diff options
Diffstat (limited to 'Source/WebKit2/UIProcess/qt')
51 files changed, 6598 insertions, 0 deletions
diff --git a/Source/WebKit2/UIProcess/qt/BackingStoreQt.cpp b/Source/WebKit2/UIProcess/qt/BackingStoreQt.cpp new file mode 100644 index 000000000..1af16d842 --- /dev/null +++ b/Source/WebKit2/UIProcess/qt/BackingStoreQt.cpp @@ -0,0 +1,75 @@ +/* + * Copyright (C) 2011 Apple Inc. All rights reserved. + * Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies) + * Copyright (C) 2011 Andreas Kling <kling@webkit.org> + * + * 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 "BackingStore.h" + +#include "UpdateInfo.h" +#include "ShareableBitmap.h" +#include <WebCore/GraphicsContext.h> +#include <WebCore/IntRect.h> + +using namespace WebCore; + +namespace WebKit { + +void BackingStore::paint(QPainter* painter, const IntRect& rect) +{ + ASSERT(!m_pixmap.isNull()); + painter->drawPixmap(rect, m_pixmap, rect); +} + +void BackingStore::incorporateUpdate(ShareableBitmap* bitmap, const UpdateInfo& updateInfo) +{ + if (m_pixmap.isNull()) + m_pixmap = QPixmap(m_size); + + scroll(updateInfo.scrollRect, updateInfo.scrollOffset); + + IntPoint updateRectLocation = updateInfo.updateRectBounds.location(); + + QPainter painter(&m_pixmap); + GraphicsContext graphicsContext(&painter); + + // Paint all update rects. + for (size_t i = 0; i < updateInfo.updateRects.size(); ++i) { + IntRect updateRect = updateInfo.updateRects[i]; + IntRect srcRect = updateRect; + srcRect.move(-updateRectLocation.x(), -updateRectLocation.y()); + bitmap->paint(graphicsContext, updateRect.location(), srcRect); + } +} + +void BackingStore::scroll(const IntRect& scrollRect, const IntSize& scrollOffset) +{ + if (scrollOffset.isZero()) + return; + + m_pixmap.scroll(scrollOffset.width(), scrollOffset.height(), scrollRect); +} + +} // namespace WebKit diff --git a/Source/WebKit2/UIProcess/qt/LayerTreeHostProxyQt.cpp b/Source/WebKit2/UIProcess/qt/LayerTreeHostProxyQt.cpp new file mode 100644 index 000000000..a1dd272a7 --- /dev/null +++ b/Source/WebKit2/UIProcess/qt/LayerTreeHostProxyQt.cpp @@ -0,0 +1,635 @@ +/* + Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#include "config.h" + +#if USE(ACCELERATED_COMPOSITING) +#include "LayerTreeHostProxy.h" + +#include "LayerTreeHostMessages.h" +#include "MainThread.h" +#include "MessageID.h" +#include "ShareableBitmap.h" +#include "TextureMapperGL.h" +#include "UpdateInfo.h" +#include "WebCoreArgumentCoders.h" +#include "WebLayerTreeInfo.h" +#include "WebPageProxy.h" +#include "WebProcessProxy.h" +#include "texmap/GraphicsLayerTextureMapper.h" +#include "texmap/TextureMapper.h" +#include "texmap/TextureMapperNode.h" +#include <QDateTime> +#include <cairo/OpenGLShims.h> + +namespace WebKit { + +class LayerTreeMessageToRenderer { +public: + enum Type { + DeleteLayer, + CreateTile, + RemoveTile, + UpdateTile, + CreateImage, + DestroyImage, + SyncLayerParameters, + FlushLayerChanges, + SetRootLayer + }; + virtual ~LayerTreeMessageToRenderer() { } + virtual Type type() const = 0; +}; + +template<class MessageData, LayerTreeMessageToRenderer::Type messageType> +class LayerTreeMessageToRendererWithData : public LayerTreeMessageToRenderer { +public: + virtual Type type() const { return messageType; } + + static PassOwnPtr<LayerTreeMessageToRenderer> create(const MessageData& data = MessageData()) + { + return adoptPtr(new LayerTreeMessageToRendererWithData(data)); + } + + const MessageData& data() const + { + return m_data; + } + +private: + LayerTreeMessageToRendererWithData(const MessageData& data) + : m_data(data) + { + } + + MessageData m_data; +}; + + +namespace { +struct CreateTileMessageData { + WebLayerID layerID; + int remoteTileID; + float scale; +}; + +struct UpdateTileMessageData { + WebLayerID layerID; + int remoteTileID; + IntRect sourceRect; + IntRect targetRect; + QImage image; +}; + +struct RemoveTileMessageData { + WebLayerID layerID; + int remoteTileID; +}; + +struct CreateImageMessageData { + int64_t imageID; + QImage image; +}; + +struct DestroyImageMessageData { + int64_t imageID; +}; + +struct SyncLayerParametersMessageData { + WebLayerInfo layerInfo; +}; + +struct EmptyMessageData { }; +struct DeleteLayerMessageData { + WebLayerID layerID; +}; +struct SetRootLayerMessageData { + WebLayerID layerID; +}; + +class CreateTileMessage + : public LayerTreeMessageToRendererWithData<CreateTileMessageData, LayerTreeMessageToRenderer::CreateTile> { }; +class UpdateTileMessage + : public LayerTreeMessageToRendererWithData<UpdateTileMessageData, LayerTreeMessageToRenderer::UpdateTile> { }; +class RemoveTileMessage + : public LayerTreeMessageToRendererWithData<RemoveTileMessageData, LayerTreeMessageToRenderer::RemoveTile> { }; +class CreateImageMessage + : public LayerTreeMessageToRendererWithData<CreateImageMessageData, LayerTreeMessageToRenderer::CreateImage> { }; +class DestroyImageMessage + : public LayerTreeMessageToRendererWithData<DestroyImageMessageData, LayerTreeMessageToRenderer::DestroyImage> { }; +class FlushLayerChangesMessage + : public LayerTreeMessageToRendererWithData<EmptyMessageData, LayerTreeMessageToRenderer::FlushLayerChanges> { }; +class SyncLayerParametersMessage + : public LayerTreeMessageToRendererWithData<SyncLayerParametersMessageData, LayerTreeMessageToRenderer::SyncLayerParameters> { }; +class DeleteLayerMessage + : public LayerTreeMessageToRendererWithData<DeleteLayerMessageData, LayerTreeMessageToRenderer::DeleteLayer> { }; +class SetRootLayerMessage + : public LayerTreeMessageToRendererWithData<SetRootLayerMessageData, LayerTreeMessageToRenderer::SetRootLayer> { }; +} + +PassOwnPtr<GraphicsLayer> LayerTreeHostProxy::createLayer(WebLayerID layerID) +{ + GraphicsLayer* newLayer = new GraphicsLayerTextureMapper(this); + TextureMapperNode* node = toTextureMapperNode(newLayer); + node->setID(layerID); + node->setTileOwnership(TextureMapperNode::ExternallyManagedTiles); + return adoptPtr(newLayer); +} + +LayerTreeHostProxy::LayerTreeHostProxy(DrawingAreaProxy* drawingAreaProxy) + : m_animationTimer(RunLoop::main(), this, &LayerTreeHostProxy::updateViewport) + , m_drawingAreaProxy(drawingAreaProxy) + , m_viewportUpdateTimer(this, &LayerTreeHostProxy::didFireViewportUpdateTimer) + , m_rootLayerID(0) +{ +} + +LayerTreeHostProxy::~LayerTreeHostProxy() +{ +} + +// This function needs to be reentrant. +void LayerTreeHostProxy::paintToCurrentGLContext(const TransformationMatrix& matrix, float opacity) +{ + if (!m_textureMapper) + m_textureMapper = TextureMapperGL::create(); + + syncRemoteContent(); + GraphicsLayer* currentRootLayer = rootLayer(); + if (!currentRootLayer) + return; + + TextureMapperNode* node = toTextureMapperNode(currentRootLayer); + + if (!node) + return; + + GLint viewport[4]; + glGetIntegerv(GL_VIEWPORT, viewport); + IntRect viewportRect(viewport[0], viewport[1], viewport[2], viewport[3]); + m_textureMapper->setViewportSize(IntSize(viewport[2], viewport[3])); + node->setTextureMapper(m_textureMapper.get()); + m_textureMapper->beginPainting(); + m_textureMapper->bindSurface(0); + + if (currentRootLayer->opacity() != opacity || currentRootLayer->transform() != matrix) { + currentRootLayer->setOpacity(opacity); + currentRootLayer->setTransform(matrix); + currentRootLayer->syncCompositingStateForThisLayerOnly(); + } + + TextureMapperNode::NodeRectMap nodeVisualContentsRectMap; + if (node->collectVisibleContentsRects(nodeVisualContentsRectMap, viewportRect)) { + TextureMapperNode::NodeRectMap::iterator endIterator = nodeVisualContentsRectMap.end(); + for (TextureMapperNode::NodeRectMap::iterator it = nodeVisualContentsRectMap.begin(); it != endIterator; ++it) { + WebLayerID layerID = it->first->id(); + // avoid updating non-synced root layer + if (!layerID) + continue; + IntRect visibleRect = IntRect(it->second); + setVisibleContentsRectForLayer(layerID, visibleRect); + } + } + node->paint(); + + m_textureMapper->endPainting(); + + if (node->descendantsOrSelfHaveRunningAnimations()) { + node->syncAnimationsRecursively(); + m_viewportUpdateTimer.startOneShot(0); + } +} + +void LayerTreeHostProxy::didFireViewportUpdateTimer(Timer<LayerTreeHostProxy>*) +{ + updateViewport(); +} + +void LayerTreeHostProxy::updateViewport() +{ + m_drawingAreaProxy->updateViewport(); +} + +void LayerTreeHostProxy::setVisibleContentsRectForLayer(WebLayerID layerID, const IntRect& rect) +{ + m_drawingAreaProxy->page()->process()->send(Messages::LayerTreeHost::SetVisibleContentRectForLayer(layerID, rect), m_drawingAreaProxy->page()->pageID()); +} + +int LayerTreeHostProxy::remoteTileIDToNodeTileID(int tileID) const +{ + HashMap<int, int>::const_iterator it = m_tileToNodeTile.find(tileID); + if (it == m_tileToNodeTile.end()) + return 0; + return it->second; +} + +void LayerTreeHostProxy::syncLayerParameters(const WebLayerInfo& layerInfo) +{ + WebLayerID id = layerInfo.id; + ensureLayer(id); + LayerMap::iterator it = m_layers.find(id); + GraphicsLayer* layer = it->second; + + layer->setName(layerInfo.name); + + layer->setReplicatedByLayer(layerByID(layerInfo.replica)); + layer->setMaskLayer(layerByID(layerInfo.mask)); + + layer->setPosition(layerInfo.pos); + layer->setSize(layerInfo.size); + layer->setTransform(layerInfo.transform); + layer->setAnchorPoint(layerInfo.anchorPoint); + layer->setChildrenTransform(layerInfo.childrenTransform); + layer->setBackfaceVisibility(layerInfo.backfaceVisible); + layer->setContentsOpaque(layerInfo.contentsOpaque); + layer->setContentsRect(layerInfo.contentsRect); + layer->setDrawsContent(layerInfo.drawsContent); + + if (layerInfo.imageIsUpdated) + assignImageToLayer(layer, layerInfo.imageBackingStoreID); + + // Never make the root layer clip. + layer->setMasksToBounds(layerInfo.isRootLayer ? false : layerInfo.masksToBounds); + layer->setOpacity(layerInfo.opacity); + layer->setPreserves3D(layerInfo.preserves3D); + Vector<GraphicsLayer*> children; + + for (size_t i = 0; i < layerInfo.children.size(); ++i) { + WebLayerID childID = layerInfo.children[i]; + GraphicsLayer* child = layerByID(childID); + if (!child) { + child = createLayer(childID).leakPtr(); + m_layers.add(childID, child); + } + children.append(child); + } + layer->setChildren(children); + + for (size_t i = 0; i < layerInfo.animations.size(); ++i) { + const WebKit::WebLayerAnimation anim = layerInfo.animations[i]; + + switch (anim.operation) { + case WebKit::WebLayerAnimation::AddAnimation: { + const IntSize boxSize = anim.boxSize; + layer->addAnimation(anim.keyframeList, boxSize, anim.animation.get(), anim.name, anim.startTime); + break; + } + case WebKit::WebLayerAnimation::RemoveAnimation: + layer->removeAnimation(anim.name); + break; + case WebKit::WebLayerAnimation::PauseAnimation: + double offset = WTF::currentTime() - anim.startTime; + layer->pauseAnimation(anim.name, offset); + break; + } + } + + if (layerInfo.isRootLayer && m_rootLayerID != id) + setRootLayerID(id); +} + +void LayerTreeHostProxy::deleteLayer(WebLayerID layerID) +{ + GraphicsLayer* layer = layerByID(layerID); + if (!layer) + return; + + layer->removeFromParent(); + m_layers.remove(layerID); + delete layer; +} + + +void LayerTreeHostProxy::ensureLayer(WebLayerID id) +{ + // We have to leak the new layer's pointer and manage it ourselves, + // because OwnPtr is not copyable. + if (m_layers.find(id) == m_layers.end()) + m_layers.add(id, createLayer(id).leakPtr()); +} + +void LayerTreeHostProxy::setRootLayerID(WebLayerID layerID) +{ + if (layerID == m_rootLayerID) + return; + + m_rootLayerID = layerID; + + m_rootLayer->removeAllChildren(); + + if (!layerID) + return; + + GraphicsLayer* layer = layerByID(layerID); + if (!layer) + return; + + m_rootLayer->addChild(layer); +} + +void LayerTreeHostProxy::createTile(WebLayerID layerID, int tileID, float scale) +{ + ensureLayer(layerID); + TextureMapperNode* node = toTextureMapperNode(layerByID(layerID)); + + int nodeTileID = node->createContentsTile(scale); + m_tileToNodeTile.add(tileID, nodeTileID); +} + +void LayerTreeHostProxy::removeTile(WebLayerID layerID, int tileID) +{ + TextureMapperNode* node = toTextureMapperNode(layerByID(layerID)); + if (!node) + return; + + int nodeTileID = remoteTileIDToNodeTileID(tileID); + if (!nodeTileID) + return; + + node->removeContentsTile(nodeTileID); + m_tileToNodeTile.remove(tileID); +} + +void LayerTreeHostProxy::updateTile(WebLayerID layerID, int tileID, const IntRect& sourceRect, const IntRect& targetRect, const QImage& image) +{ + ensureLayer(layerID); + TextureMapperNode* node = toTextureMapperNode(layerByID(layerID)); + if (!node) + return; + + int nodeTileID = remoteTileIDToNodeTileID(tileID); + if (!nodeTileID) + return; + + QImage imageRef(image); + node->setTextureMapper(m_textureMapper.get()); + node->setContentsTileBackBuffer(nodeTileID, sourceRect, targetRect, imageRef.bits(), BitmapTexture::BGRAFormat); +} + +void LayerTreeHostProxy::createImage(int64_t imageID, const QImage& image) +{ + TiledImage tiledImage; + static const int TileDimension = 1024; + bool imageHasAlpha = image.hasAlphaChannel(); + IntRect imageRect(0, 0, image.width(), image.height()); + for (int y = 0; y < image.height(); y += TileDimension) { + for (int x = 0; x < image.width(); x += TileDimension) { + QImage subImage; + IntRect rect(x, y, TileDimension, TileDimension); + rect.intersect(imageRect); + if (QSize(rect.size()) == image.size()) + subImage = image; + else + subImage = image.copy(rect); + RefPtr<BitmapTexture> texture = m_textureMapper->createTexture(); + texture->reset(rect.size(), !imageHasAlpha); + texture->updateContents(imageHasAlpha ? BitmapTexture::BGRAFormat : BitmapTexture::BGRFormat, IntRect(IntPoint::zero(), rect.size()), subImage.bits()); + tiledImage.add(rect.location(), texture); + } + } + + m_directlyCompositedImages.remove(imageID); + m_directlyCompositedImages.add(imageID, tiledImage); +} + +void LayerTreeHostProxy::destroyImage(int64_t imageID) +{ + m_directlyCompositedImages.remove(imageID); +} + +void LayerTreeHostProxy::assignImageToLayer(GraphicsLayer* layer, int64_t imageID) +{ + TextureMapperNode* node = toTextureMapperNode(layer); + if (!node) + return; + + if (!imageID) { + node->clearAllDirectlyCompositedImageTiles(); + return; + } + + FloatSize size(layer->size()); + FloatRect contentsRect(layer->contentsRect()); + float horizontalFactor = contentsRect.width() / size.width(); + float verticalFactor = contentsRect.height() / size.height(); + HashMap<int64_t, TiledImage>::iterator it = m_directlyCompositedImages.find(imageID); + if (it == m_directlyCompositedImages.end()) + return; + + TiledImage::iterator endTileIterator = it->second.end(); + for (TiledImage::iterator tileIt = it->second.begin(); tileIt != endTileIterator; ++tileIt) { + FloatRect sourceRect(FloatPoint(tileIt->first), FloatSize(tileIt->second->size())); + FloatRect targetRect(sourceRect.x() * horizontalFactor + contentsRect.x(), + sourceRect.y() * verticalFactor + contentsRect.y(), + sourceRect.width() * horizontalFactor, + sourceRect.height() * verticalFactor); + int newTileID = node->createContentsTile(1.0); + node->setTileBackBufferTextureForDirectlyCompositedImage(newTileID, IntRect(sourceRect), targetRect, tileIt->second.get()); + } +} + +void LayerTreeHostProxy::flushLayerChanges() +{ + m_rootLayer->syncCompositingState(FloatRect()); +} + +void LayerTreeHostProxy::ensureRootLayer() +{ + if (m_rootLayer) + return; + m_rootLayer = createLayer(InvalidWebLayerID); + m_rootLayer->setMasksToBounds(false); + m_rootLayer->setDrawsContent(false); + m_rootLayer->setAnchorPoint(FloatPoint3D(0, 0, 0)); + + // The root layer should not have zero size, or it would be optimized out. + m_rootLayer->setSize(FloatSize(1.0, 1.0)); + m_textureMapper = TextureMapperGL::create(); + toTextureMapperNode(m_rootLayer.get())->setTextureMapper(m_textureMapper.get()); +} + +void LayerTreeHostProxy::syncRemoteContent() +{ + // We enqueue messages and execute them during paint, as they require an active GL context. + ensureRootLayer(); + + while (OwnPtr<LayerTreeMessageToRenderer> nextMessage = m_messagesToRenderer.tryGetMessage()) { + switch (nextMessage->type()) { + case LayerTreeMessageToRenderer::SetRootLayer: { + const SetRootLayerMessageData& data = static_cast<SetRootLayerMessage*>(nextMessage.get())->data(); + setRootLayerID(data.layerID); + break; + } + + case LayerTreeMessageToRenderer::DeleteLayer: { + const DeleteLayerMessageData& data = static_cast<DeleteLayerMessage*>(nextMessage.get())->data(); + deleteLayer(data.layerID); + break; + } + + case LayerTreeMessageToRenderer::SyncLayerParameters: { + const SyncLayerParametersMessageData& data = static_cast<SyncLayerParametersMessage*>(nextMessage.get())->data(); + syncLayerParameters(data.layerInfo); + break; + } + + case LayerTreeMessageToRenderer::CreateTile: { + const CreateTileMessageData& data = static_cast<CreateTileMessage*>(nextMessage.get())->data(); + createTile(data.layerID, data.remoteTileID, data.scale); + break; + } + + case LayerTreeMessageToRenderer::RemoveTile: { + const RemoveTileMessageData& data = static_cast<RemoveTileMessage*>(nextMessage.get())->data(); + removeTile(data.layerID, data.remoteTileID); + break; + } + + case LayerTreeMessageToRenderer::UpdateTile: { + const UpdateTileMessageData& data = static_cast<UpdateTileMessage*>(nextMessage.get())->data(); + updateTile(data.layerID, data.remoteTileID, data.sourceRect, data.targetRect, data.image); + break; + } + + case LayerTreeMessageToRenderer::CreateImage: { + const CreateImageMessageData& data = static_cast<CreateImageMessage*>(nextMessage.get())->data(); + createImage(data.imageID, data.image); + break; + } + + case LayerTreeMessageToRenderer::DestroyImage: { + const CreateImageMessageData& data = static_cast<CreateImageMessage*>(nextMessage.get())->data(); + destroyImage(data.imageID); + break; + } + + case LayerTreeMessageToRenderer::FlushLayerChanges: + flushLayerChanges(); + break; + } + } +} + +void LayerTreeHostProxy::pushUpdateToQueue(PassOwnPtr<LayerTreeMessageToRenderer> message) +{ + m_messagesToRenderer.append(message); + updateViewport(); +} + +void LayerTreeHostProxy::createTileForLayer(int layerID, int tileID, const WebKit::UpdateInfo& updateInfo) +{ + CreateTileMessageData data; + data.layerID = layerID; + data.remoteTileID = tileID; + data.scale = updateInfo.updateScaleFactor; + pushUpdateToQueue(CreateTileMessage::create(data)); + updateTileForLayer(layerID, tileID, updateInfo); +} + +void LayerTreeHostProxy::updateTileForLayer(int layerID, int tileID, const WebKit::UpdateInfo& updateInfo) +{ + UpdateTileMessageData data; + data.layerID = layerID; + data.remoteTileID = tileID; + RefPtr<ShareableBitmap> bitmap = ShareableBitmap::create(updateInfo.bitmapHandle); + data.image = bitmap->createQImage().copy(); + data.sourceRect = IntRect(IntPoint::zero(), updateInfo.updateRectBounds.size()); + data.targetRect = updateInfo.updateRectBounds; + pushUpdateToQueue(UpdateTileMessage::create(data)); +} + +void LayerTreeHostProxy::removeTileForLayer(int layerID, int tileID) +{ + RemoveTileMessageData data; + data.layerID = layerID; + data.remoteTileID = tileID; + pushUpdateToQueue(RemoveTileMessage::create(data)); +} + + +void LayerTreeHostProxy::deleteCompositingLayer(WebLayerID id) +{ + DeleteLayerMessageData data; + data.layerID = id; + pushUpdateToQueue(DeleteLayerMessage::create(data)); +} + +void LayerTreeHostProxy::setRootCompositingLayer(WebLayerID id) +{ + SetRootLayerMessageData data; + data.layerID = id; + pushUpdateToQueue(SetRootLayerMessage::create(data)); +} + +void LayerTreeHostProxy::syncCompositingLayerState(const WebLayerInfo& info) +{ + SyncLayerParametersMessageData data; + data.layerInfo = info; + pushUpdateToQueue(SyncLayerParametersMessage::create(data)); +} + +void LayerTreeHostProxy::didRenderFrame() +{ + m_drawingAreaProxy->page()->process()->send(Messages::LayerTreeHost::RenderNextFrame(), m_drawingAreaProxy->page()->pageID()); + pushUpdateToQueue(FlushLayerChangesMessage::create()); + updateViewport(); +} + +void LayerTreeHostProxy::createDirectlyCompositedImage(int64_t key, const WebKit::ShareableBitmap::Handle& handle) +{ + CreateImageMessageData data; + RefPtr<ShareableBitmap> bitmap = ShareableBitmap::create(handle); + data.imageID = key; + data.image = bitmap->createQImage().copy(); + pushUpdateToQueue(CreateImageMessage::create(data)); +} + +void LayerTreeHostProxy::destroyDirectlyCompositedImage(int64_t key) +{ + DestroyImageMessageData data; + data.imageID = key; + pushUpdateToQueue(DestroyImageMessage::create(data)); +} + +void LayerTreeHostProxy::setVisibleContentRectTrajectoryVector(const FloatPoint& trajectoryVector) +{ + m_drawingAreaProxy->page()->process()->send(Messages::LayerTreeHost::SetVisibleContentRectTrajectoryVector(trajectoryVector), m_drawingAreaProxy->page()->pageID()); +} + +void LayerTreeHostProxy::setVisibleContentsRectAndScale(const IntRect& rect, float scale) +{ + m_visibleContentsRect = rect; + m_contentsScale = scale; + m_drawingAreaProxy->page()->process()->send(Messages::LayerTreeHost::SetVisibleContentRectAndScale(rect, scale), m_drawingAreaProxy->page()->pageID()); +} + +void LayerTreeHostProxy::purgeGLResources() +{ + TextureMapperNode* node = toTextureMapperNode(rootLayer()); + + node->purgeNodeTexturesRecursive(); + m_directlyCompositedImages.clear(); + + m_textureMapper.clear(); + + m_drawingAreaProxy->page()->process()->send(Messages::LayerTreeHost::PurgeBackingStores(), m_drawingAreaProxy->page()->pageID()); +} + +} +#endif diff --git a/Source/WebKit2/UIProcess/qt/QtDialogRunner.cpp b/Source/WebKit2/UIProcess/qt/QtDialogRunner.cpp new file mode 100644 index 000000000..32de21af7 --- /dev/null +++ b/Source/WebKit2/UIProcess/qt/QtDialogRunner.cpp @@ -0,0 +1,136 @@ +/* + * Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this program; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + */ + +#include "config.h" +#include "QtDialogRunner.h" + +#include <QtDeclarative/QDeclarativeComponent> +#include <QtDeclarative/QDeclarativeContext> +#include <QtDeclarative/QDeclarativeEngine> +#include <QtQuick/QQuickItem> +#include <wtf/PassOwnPtr.h> + +QtDialogRunner::QtDialogRunner() + : QEventLoop() + , m_wasAccepted(false) +{ +} + +QtDialogRunner::~QtDialogRunner() +{ +} + +class DialogContextObject : public QObject { + Q_OBJECT + Q_PROPERTY(QString message READ message CONSTANT) + Q_PROPERTY(QString defaultValue READ defaultValue CONSTANT) + +public: + DialogContextObject(const QString& message, const QString& defaultValue = QString()) + : QObject() + , m_message(message) + , m_defaultValue(defaultValue) + { + } + QString message() const { return m_message; } + QString defaultValue() const { return m_defaultValue; } + +public slots: + void dismiss() { emit dismissed(); } + void accept() { emit accepted(); } + void accept(const QString& result) { emit accepted(result); } + void reject() { emit rejected(); } + +signals: + void dismissed(); + void accepted(); + void accepted(const QString& result); + void rejected(); + +private: + QString m_message; + QString m_defaultValue; +}; + +bool QtDialogRunner::initForAlert(QDeclarativeComponent* component, QQuickItem* dialogParent, const QString& message) +{ + DialogContextObject* contextObject = new DialogContextObject(message); + if (!createDialog(component, dialogParent, contextObject)) + return false; + + connect(contextObject, SIGNAL(dismissed()), SLOT(quit())); + return true; +} + +bool QtDialogRunner::initForConfirm(QDeclarativeComponent* component, QQuickItem* dialogParent, const QString& message) +{ + DialogContextObject* contextObject = new DialogContextObject(message); + if (!createDialog(component, dialogParent, contextObject)) + return false; + + connect(contextObject, SIGNAL(accepted()), SLOT(onAccepted())); + connect(contextObject, SIGNAL(accepted()), SLOT(quit())); + connect(contextObject, SIGNAL(rejected()), SLOT(quit())); + return true; +} + +bool QtDialogRunner::initForPrompt(QDeclarativeComponent* component, QQuickItem* dialogParent, const QString& message, const QString& defaultValue) +{ + DialogContextObject* contextObject = new DialogContextObject(message, defaultValue); + if (!createDialog(component, dialogParent, contextObject)) + return false; + + connect(contextObject, SIGNAL(accepted(QString)), SLOT(onAccepted(QString))); + connect(contextObject, SIGNAL(accepted(QString)), SLOT(quit())); + connect(contextObject, SIGNAL(rejected()), SLOT(quit())); + return true; +} + +bool QtDialogRunner::createDialog(QDeclarativeComponent* component, QQuickItem* dialogParent, QObject* contextObject) +{ + QDeclarativeContext* baseContext = component->creationContext(); + if (!baseContext) + baseContext = QDeclarativeEngine::contextForObject(dialogParent); + m_dialogContext = adoptPtr(new QDeclarativeContext(baseContext)); + + // This makes both "message" and "model.message" work for the dialog, just like QtQuick's ListView delegates. + contextObject->setParent(m_dialogContext.get()); + m_dialogContext->setContextProperty(QLatin1String("model"), contextObject); + m_dialogContext->setContextObject(contextObject); + + QObject* object = component->create(m_dialogContext.get()); + if (!object) { + m_dialogContext.clear(); + return false; + } + + m_dialog = adoptPtr(qobject_cast<QQuickItem*>(object)); + if (!m_dialog) { + m_dialogContext.clear(); + m_dialog.clear(); + return false; + } + + m_dialog->setParentItem(dialogParent); + return true; +} + +#include "QtDialogRunner.moc" +#include "moc_QtDialogRunner.cpp" diff --git a/Source/WebKit2/UIProcess/qt/QtDialogRunner.h b/Source/WebKit2/UIProcess/qt/QtDialogRunner.h new file mode 100644 index 000000000..bfa530264 --- /dev/null +++ b/Source/WebKit2/UIProcess/qt/QtDialogRunner.h @@ -0,0 +1,63 @@ +/* + * Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this program; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + */ + +#ifndef QtDialogRunner_h +#define QtDialogRunner_h + +#include <QtCore/QEventLoop> +#include <wtf/OwnPtr.h> + +class QDeclarativeComponent; +class QDeclarativeContext; +class QQuickItem; + +class QtDialogRunner : public QEventLoop { + Q_OBJECT + +public: + QtDialogRunner(); + virtual ~QtDialogRunner(); + + bool initForAlert(QDeclarativeComponent*, QQuickItem* dialogParent, const QString& message); + bool initForConfirm(QDeclarativeComponent*, QQuickItem* dialogParent, const QString& message); + bool initForPrompt(QDeclarativeComponent*, QQuickItem* dialogParent, const QString& message, const QString& defaultValue); + + QQuickItem* dialog() const { return m_dialog.get(); } + + bool wasAccepted() const { return m_wasAccepted; } + QString result() const { return m_result; } + +public slots: + void onAccepted(const QString& result = QString()) + { + m_wasAccepted = true; + m_result = result; + } + +private: + bool createDialog(QDeclarativeComponent*, QQuickItem* dialogParent, QObject* contextObject); + + OwnPtr<QDeclarativeContext> m_dialogContext; + OwnPtr<QQuickItem> m_dialog; + QString m_result; + bool m_wasAccepted; +}; + +#endif // QtDialogRunner_h diff --git a/Source/WebKit2/UIProcess/qt/QtDownloadManager.cpp b/Source/WebKit2/UIProcess/qt/QtDownloadManager.cpp new file mode 100644 index 000000000..99c4dc58e --- /dev/null +++ b/Source/WebKit2/UIProcess/qt/QtDownloadManager.cpp @@ -0,0 +1,145 @@ +/* + * Copyright (C) 2010, 2011 Nokia Corporation and/or its subsidiary(-ies) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this program; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + */ + +#include "config.h" +#include "QtDownloadManager.h" + +#include "DownloadProxy.h" +#include "QtWebError.h" +#include "WKStringQt.h" +#include "WKURLQt.h" +#include "WebContext.h" +#include "qwebdownloaditem_p.h" +#include "qwebdownloaditem_p_p.h" + +namespace WebKit { + +QtDownloadManager::QtDownloadManager(WebContext* context) +{ + WKContextDownloadClient downloadClient; + memset(&downloadClient, 0, sizeof(WKContextDownloadClient)); + downloadClient.version = kWKContextDownloadClientCurrentVersion; + downloadClient.clientInfo = this; + downloadClient.didReceiveResponse = didReceiveResponse; + downloadClient.didReceiveData = didReceiveDataForDownload; + downloadClient.didCreateDestination = didCreateDestination; + downloadClient.didFinish = didFinishDownload; + downloadClient.didFail = didFailDownload; + WKContextSetDownloadClient(toAPI(context), &downloadClient); +} + +QtDownloadManager::~QtDownloadManager() +{ +} + +void QtDownloadManager::addDownload(DownloadProxy* download, QWebDownloadItem* downloadItem) +{ + m_downloads[download->downloadID()] = downloadItem; +} + +void QtDownloadManager::downloadReceivedResponse(DownloadProxy* download, const WebCore::ResourceResponse& response) +{ + // Will be called when the headers are read by WebProcess. + QWebDownloadItem* downloadItem = m_downloads.value(download->downloadID()); + ASSERT(downloadItem); + + downloadItem->d->sourceUrl = response.url(); + downloadItem->d->mimeType = response.mimeType(); + downloadItem->d->expectedContentLength = response.expectedContentLength(); + downloadItem->d->suggestedFilename = response.suggestedFilename(); + + downloadItem->d->didReceiveResponse(downloadItem); +} + +void QtDownloadManager::downloadCreatedDestination(DownloadProxy* download, const QString& path) +{ + QWebDownloadItem* downloadItem = m_downloads.value(download->downloadID()); + ASSERT(downloadItem); + downloadItem->d->destinationPath = path; + emit downloadItem->destinationFileCreated(downloadItem->d->destinationPath); +} + +void QtDownloadManager::downloadFinished(DownloadProxy* download) +{ + // Will be called when download finishes with success. + QWebDownloadItem* downloadItem = m_downloads.take(download->downloadID()); + ASSERT(downloadItem); + emit downloadItem->succeeded(); +} + +void QtDownloadManager::downloadFailed(DownloadProxy* download, const QtWebError& error) +{ + // Will be called when download fails or is aborted. + QWebDownloadItem* downloadItem = m_downloads.take(download->downloadID()); + ASSERT(downloadItem); + + // If the parent is null at this point, the download failed before it + // received a response and downloadRequested was emitted. + // Due to this the item will never be parented and we have to delete it + // manually at this point. + if (!downloadItem->parent()) { + delete downloadItem; + return; + } + + emit downloadItem->failed(error.errorCodeAsDownloadError(), error.url(), error.description()); +} + +void QtDownloadManager::downloadDataReceived(DownloadProxy* download, uint64_t length) +{ + // Will be called everytime bytes were written to destination file by WebProcess. + QWebDownloadItem* downloadItem = m_downloads.value(download->downloadID()); + ASSERT(downloadItem); + downloadItem->d->totalBytesReceived += length; + emit downloadItem->totalBytesReceivedChanged(length); +} + +static inline QtDownloadManager* toQtDownloadManager(const void* clientInfo) +{ + ASSERT(clientInfo); + return reinterpret_cast<QtDownloadManager*>(const_cast<void*>(clientInfo)); +} + +void QtDownloadManager::didReceiveResponse(WKContextRef, WKDownloadRef download, WKURLResponseRef response, const void *clientInfo) +{ + toQtDownloadManager(clientInfo)->downloadReceivedResponse(toImpl(download), toImpl(response)->resourceResponse()); +} + +void QtDownloadManager::didCreateDestination(WKContextRef, WKDownloadRef download, WKStringRef path, const void *clientInfo) +{ + toQtDownloadManager(clientInfo)->downloadCreatedDestination(toImpl(download), WKStringCopyQString(path)); +} + +void QtDownloadManager::didFinishDownload(WKContextRef, WKDownloadRef download, const void *clientInfo) +{ + toQtDownloadManager(clientInfo)->downloadFinished(toImpl(download)); +} + +void QtDownloadManager::didFailDownload(WKContextRef, WKDownloadRef download, WKErrorRef error, const void *clientInfo) +{ + toQtDownloadManager(clientInfo)->downloadFailed(toImpl(download), QtWebError(error)); +} + +void QtDownloadManager::didReceiveDataForDownload(WKContextRef, WKDownloadRef download, uint64_t length, const void *clientInfo) +{ + toQtDownloadManager(clientInfo)->downloadDataReceived(toImpl(download), length); +} + +} diff --git a/Source/WebKit2/UIProcess/qt/QtDownloadManager.h b/Source/WebKit2/UIProcess/qt/QtDownloadManager.h new file mode 100644 index 000000000..5e8d5ee43 --- /dev/null +++ b/Source/WebKit2/UIProcess/qt/QtDownloadManager.h @@ -0,0 +1,64 @@ +/* + * Copyright (C) 2010, 2011 Nokia Corporation and/or its subsidiary(-ies) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this program; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + */ + +#ifndef QtDownloadManager_h +#define QtDownloadManager_h + +#include <QMap> +#include <WKContext.h> + +class QtWebError; +class QWebDownloadItem; + +namespace WebCore { +class ResourceResponse; +} + +namespace WebKit { + +class DownloadProxy; +class WebContext; + +class QtDownloadManager { +public: + QtDownloadManager(WebContext*); + ~QtDownloadManager(); + + void addDownload(DownloadProxy*, QWebDownloadItem*); + +private: + void downloadReceivedResponse(DownloadProxy*, const WebCore::ResourceResponse&); + void downloadCreatedDestination(DownloadProxy*, const QString& path); + void downloadFinished(DownloadProxy*); + void downloadFailed(DownloadProxy*, const QtWebError&); + void downloadDataReceived(DownloadProxy*, uint64_t length); + + // WKContextDownloadClient callbacks. + static void didReceiveResponse(WKContextRef, WKDownloadRef, WKURLResponseRef, const void* clientInfo); + static void didCreateDestination(WKContextRef, WKDownloadRef, WKStringRef path, const void* clientInfo); + static void didFinishDownload(WKContextRef, WKDownloadRef, const void* clientInfo); + static void didFailDownload(WKContextRef, WKDownloadRef, WKErrorRef, const void* clientInfo); + static void didReceiveDataForDownload(WKContextRef, WKDownloadRef, uint64_t length, const void* clientInfo); + + QMap<uint64_t, QWebDownloadItem*> m_downloads; +}; + +} +#endif /* QtDownloadManager_h */ diff --git a/Source/WebKit2/UIProcess/qt/QtGestureRecognizer.cpp b/Source/WebKit2/UIProcess/qt/QtGestureRecognizer.cpp new file mode 100644 index 000000000..0c62452c6 --- /dev/null +++ b/Source/WebKit2/UIProcess/qt/QtGestureRecognizer.cpp @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2011 Benjamin Poulain <benjamin@webkit.org> + * + * 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 "QtGestureRecognizer.h" + +#include "QtWebPageEventHandler.h" + +namespace WebKit { + +QtGestureRecognizer::QtGestureRecognizer(QtWebPageEventHandler* eventHandler) + : m_eventHandler(eventHandler) + , m_state(NoGesture) +{ +} + +void QtGestureRecognizer::reset() +{ + m_state = NoGesture; +} + +QtViewportInteractionEngine* QtGestureRecognizer::interactionEngine() +{ + return m_eventHandler->interactionEngine(); +} + +} diff --git a/Source/WebKit2/UIProcess/qt/QtGestureRecognizer.h b/Source/WebKit2/UIProcess/qt/QtGestureRecognizer.h new file mode 100644 index 000000000..4c191f6e2 --- /dev/null +++ b/Source/WebKit2/UIProcess/qt/QtGestureRecognizer.h @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2011 Benjamin Poulain <benjamin@webkit.org> + * + * 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 QtGestureRecognizer_h +#define QtGestureRecognizer_h + +class QtWebPageEventHandler; + +namespace WebKit { + +class QtViewportInteractionEngine; + +class QtGestureRecognizer { +public: + bool isRecognized() const { return m_state == GestureRecognized; } + +protected: + QtGestureRecognizer(QtWebPageEventHandler*); + void reset(); + + QtWebPageEventHandler* m_eventHandler; + enum State { + NoGesture, + GestureRecognitionStarted, + GestureRecognized + } m_state; + + QtViewportInteractionEngine* interactionEngine(); +}; + +} + +#endif /* QtGestureRecognizer_h */ diff --git a/Source/WebKit2/UIProcess/qt/QtPageClient.cpp b/Source/WebKit2/UIProcess/qt/QtPageClient.cpp new file mode 100644 index 000000000..b173776d8 --- /dev/null +++ b/Source/WebKit2/UIProcess/qt/QtPageClient.cpp @@ -0,0 +1,256 @@ +/* + * Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this program; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + */ + +#include "config.h" +#include "QtPageClient.h" + +#include "QtWebPageEventHandler.h" +#include "QtWebUndoController.h" +#include "WebContextMenuProxyQt.h" +#include "WebEditCommandProxy.h" +#include "WebPopupMenuProxyQt.h" +#include "qquickwebview_p.h" +#include "qquickwebview_p_p.h" +#include <QGuiApplication> +#include <WebCore/Cursor.h> +#include <WebCore/DragData.h> +#include <WebCore/FloatRect.h> +#include <WebCore/NotImplemented.h> + +using namespace WebKit; +using namespace WebCore; + +QtPageClient::QtPageClient() + : m_webView(0) + , m_eventHandler(0) + , m_undoController(0) +{ +} + +QtPageClient::~QtPageClient() +{ +} + +void QtPageClient::initialize(QQuickWebView* webView, QtWebPageEventHandler* eventHandler, QtWebUndoController* undoController) +{ + m_webView = webView; + m_eventHandler = eventHandler; + m_undoController = undoController; +} + +PassOwnPtr<DrawingAreaProxy> QtPageClient::createDrawingAreaProxy() +{ + return QQuickWebViewPrivate::get(m_webView)->createDrawingAreaProxy(); +} + +void QtPageClient::setViewNeedsDisplay(const WebCore::IntRect& rect) +{ + m_webView->page()->update(); +} + +void QtPageClient::pageDidRequestScroll(const IntPoint& pos) +{ + QQuickWebViewPrivate::get(m_webView)->pageDidRequestScroll(pos); +} + +void QtPageClient::processDidCrash() +{ + QQuickWebViewPrivate::get(m_webView)->processDidCrash(); +} + +void QtPageClient::didRelaunchProcess() +{ + QQuickWebViewPrivate::get(m_webView)->didRelaunchProcess(); +} + +void QtPageClient::didChangeContentsSize(const IntSize& newSize) +{ + QQuickWebViewPrivate::get(m_webView)->didChangeContentsSize(newSize); +} + +void QtPageClient::didChangeViewportProperties(const WebCore::ViewportArguments& args) +{ + QQuickWebViewPrivate::get(m_webView)->didChangeViewportProperties(args); +} + +void QtPageClient::startDrag(const WebCore::DragData& dragData, PassRefPtr<ShareableBitmap> dragImage) +{ + m_eventHandler->startDrag(dragData, dragImage); +} + +void QtPageClient::handleDownloadRequest(DownloadProxy* download) +{ + QQuickWebViewPrivate::get(m_webView)->handleDownloadRequest(download); +} + +void QtPageClient::handleApplicationSchemeRequest(PassRefPtr<QtNetworkRequestData> requestData) +{ + if (!m_webView || !m_webView->experimental()) + return; + m_webView->experimental()->invokeApplicationSchemeHandler(requestData.get()); +} + +void QtPageClient::setCursor(const WebCore::Cursor& cursor) +{ + // FIXME: This is a temporary fix until we get cursor support in QML items. + QGuiApplication::setOverrideCursor(*cursor.platformCursor()); +} + +void QtPageClient::setCursorHiddenUntilMouseMoves(bool hiddenUntilMouseMoves) +{ + notImplemented(); +} + +void QtPageClient::toolTipChanged(const String&, const String& newTooltip) +{ + // There is not yet any UI defined for the tooltips for mobile so we ignore the change. +} + +void QtPageClient::registerEditCommand(PassRefPtr<WebEditCommandProxy> command, WebPageProxy::UndoOrRedo undoOrRedo) +{ + m_undoController->registerEditCommand(command, undoOrRedo); +} + +void QtPageClient::clearAllEditCommands() +{ + m_undoController->clearAllEditCommands(); +} + +bool QtPageClient::canUndoRedo(WebPageProxy::UndoOrRedo undoOrRedo) +{ + return m_undoController->canUndoRedo(undoOrRedo); +} + +void QtPageClient::executeUndoRedo(WebPageProxy::UndoOrRedo undoOrRedo) +{ + m_undoController->executeUndoRedo(undoOrRedo); +} + +FloatRect QtPageClient::convertToDeviceSpace(const FloatRect& rect) +{ + return rect; +} + +FloatRect QtPageClient::convertToUserSpace(const FloatRect& rect) +{ + return rect; +} + +IntPoint QtPageClient::screenToWindow(const IntPoint& point) +{ + return point; +} + +IntRect QtPageClient::windowToScreen(const IntRect& rect) +{ + return rect; +} + +PassRefPtr<WebPopupMenuProxy> QtPageClient::createPopupMenuProxy(WebPageProxy* webPageProxy) +{ + return WebPopupMenuProxyQt::create(webPageProxy, m_webView); +} + +PassRefPtr<WebContextMenuProxy> QtPageClient::createContextMenuProxy(WebPageProxy* webPageProxy) +{ + return WebContextMenuProxyQt::create(webPageProxy); +} + +void QtPageClient::flashBackingStoreUpdates(const Vector<IntRect>&) +{ + notImplemented(); +} + +void QtPageClient::didFindZoomableArea(const IntPoint& target, const IntRect& area) +{ + ASSERT(m_eventHandler); + m_eventHandler->didFindZoomableArea(target, area); +} + +void QtPageClient::focusEditableArea(const IntRect& caret, const IntRect& area) +{ + ASSERT(m_eventHandler); + m_eventHandler->focusEditableArea(caret, area); +} + +void QtPageClient::didReceiveMessageFromNavigatorQtObject(const String& message) +{ + QQuickWebViewPrivate::get(m_webView)->didReceiveMessageFromNavigatorQtObject(message); +} + +#if ENABLE(TOUCH_EVENTS) +void QtPageClient::doneWithTouchEvent(const NativeWebTouchEvent& event, bool wasEventHandled) +{ + ASSERT(m_eventHandler); + m_eventHandler->doneWithTouchEvent(event, wasEventHandled); +} +#endif + +void QtPageClient::displayView() +{ + // FIXME: Implement. +} + +void QtPageClient::scrollView(const WebCore::IntRect& scrollRect, const WebCore::IntSize& scrollOffset) +{ + // FIXME: Implement. +} + +WebCore::IntSize QtPageClient::viewSize() +{ + return QQuickWebViewPrivate::get(m_webView)->viewSize(); +} + +bool QtPageClient::isViewWindowActive() +{ + // FIXME: The scene graph does not have the concept of being active or not when this was written. + return true; +} + +bool QtPageClient::isViewFocused() +{ + if (!m_webView) + return false; + return m_webView->hasFocus(); +} + +bool QtPageClient::isViewVisible() +{ + if (!m_webView) + return false; + return m_webView->isVisible() && m_webView->page()->isVisible(); +} + +bool QtPageClient::isViewInWindow() +{ + // FIXME: Implement. + return true; +} + +void QtPageClient::enterAcceleratedCompositingMode(const LayerTreeContext&) +{ + // FIXME: Implement. +} + +void QtPageClient::exitAcceleratedCompositingMode() +{ + // FIXME: Implement. +} + diff --git a/Source/WebKit2/UIProcess/qt/QtPageClient.h b/Source/WebKit2/UIProcess/qt/QtPageClient.h new file mode 100644 index 000000000..a3149b631 --- /dev/null +++ b/Source/WebKit2/UIProcess/qt/QtPageClient.h @@ -0,0 +1,107 @@ +/* + * Copyright (C) 2010, 2011 Nokia Corporation and/or its subsidiary(-ies) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this program; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + */ + +#ifndef QtPageClient_h +#define QtPageClient_h + +#include "DrawingAreaProxy.h" +#include "LayerTreeContext.h" +#include "PageClient.h" +#include "ShareableBitmap.h" +#include "ViewportArguments.h" + +class QtWebPageEventHandler; +class QtWebUndoController; +class QQuickWebView; + +using namespace WebKit; + +class QtPageClient : public WebKit::PageClient { +public: + QtPageClient(); + ~QtPageClient(); + + void initialize(QQuickWebView*, QtWebPageEventHandler*, QtWebUndoController*); + + // QQuickWebView. + virtual void setViewNeedsDisplay(const WebCore::IntRect&); + virtual WebCore::IntSize viewSize(); + virtual bool isViewFocused(); + virtual bool isViewVisible(); + virtual void didReceiveMessageFromNavigatorQtObject(const String&); + virtual void pageDidRequestScroll(const WebCore::IntPoint&); + virtual void didChangeContentsSize(const WebCore::IntSize&); + virtual void didChangeViewportProperties(const WebCore::ViewportArguments&); + virtual void processDidCrash(); + virtual void didRelaunchProcess(); + virtual PassOwnPtr<DrawingAreaProxy> createDrawingAreaProxy(); + virtual void handleDownloadRequest(DownloadProxy*); + virtual void handleApplicationSchemeRequest(PassRefPtr<QtNetworkRequestData>); + + virtual void displayView(); + virtual void scrollView(const WebCore::IntRect& scrollRect, const WebCore::IntSize& scrollOffset); + virtual bool isViewWindowActive(); + virtual bool isViewInWindow(); +#if USE(ACCELERATED_COMPOSITING) + virtual void enterAcceleratedCompositingMode(const LayerTreeContext&); + virtual void exitAcceleratedCompositingMode(); +#endif // USE(ACCELERATED_COMPOSITING) + virtual void pageClosed() { } + virtual void startDrag(const WebCore::DragData&, PassRefPtr<ShareableBitmap> dragImage); + virtual void setCursor(const WebCore::Cursor&); + virtual void setCursorHiddenUntilMouseMoves(bool); + virtual void toolTipChanged(const String&, const String&); + + // QtWebUndoController + virtual void registerEditCommand(PassRefPtr<WebEditCommandProxy>, WebPageProxy::UndoOrRedo); + virtual void clearAllEditCommands(); + virtual bool canUndoRedo(WebPageProxy::UndoOrRedo); + virtual void executeUndoRedo(WebPageProxy::UndoOrRedo); + + virtual WebCore::FloatRect convertToDeviceSpace(const WebCore::FloatRect&); + virtual WebCore::FloatRect convertToUserSpace(const WebCore::FloatRect&); + virtual WebCore::IntPoint screenToWindow(const WebCore::IntPoint&); + virtual WebCore::IntRect windowToScreen(const WebCore::IntRect&); + virtual void doneWithKeyEvent(const NativeWebKeyboardEvent&, bool wasEventHandled) { } + virtual PassRefPtr<WebPopupMenuProxy> createPopupMenuProxy(WebPageProxy*); + virtual PassRefPtr<WebContextMenuProxy> createContextMenuProxy(WebPageProxy*); + virtual void setFindIndicator(PassRefPtr<FindIndicator>, bool fadeOut, bool animate) { } + virtual void didCommitLoadForMainFrame(bool useCustomRepresentation) { } + virtual void didFinishLoadingDataForCustomRepresentation(const String& suggestedFilename, const CoreIPC::DataReference&) { } + virtual double customRepresentationZoomFactor() { return 1; } + virtual void setCustomRepresentationZoomFactor(double) { } + virtual void didChangeScrollbarsForMainFrame() const { } + virtual void flashBackingStoreUpdates(const Vector<WebCore::IntRect>& updateRects); + virtual void findStringInCustomRepresentation(const String&, WebKit::FindOptions, unsigned maxMatchCount) { } + virtual void countStringMatchesInCustomRepresentation(const String&, WebKit::FindOptions, unsigned maxMatchCount) { } + virtual void didFindZoomableArea(const WebCore::IntPoint&, const WebCore::IntRect&); + virtual void focusEditableArea(const WebCore::IntRect&, const WebCore::IntRect&); + +#if ENABLE(TOUCH_EVENTS) + virtual void doneWithTouchEvent(const NativeWebTouchEvent&, bool wasEventHandled); +#endif + +private: + QQuickWebView* m_webView; + QtWebPageEventHandler* m_eventHandler; + QtWebUndoController* m_undoController; +}; + +#endif /* QtPageClient_h */ diff --git a/Source/WebKit2/UIProcess/qt/QtPanGestureRecognizer.cpp b/Source/WebKit2/UIProcess/qt/QtPanGestureRecognizer.cpp new file mode 100644 index 000000000..6f93c9391 --- /dev/null +++ b/Source/WebKit2/UIProcess/qt/QtPanGestureRecognizer.cpp @@ -0,0 +1,104 @@ +/* + * Copyright (C) 2011 Benjamin Poulain <benjamin@webkit.org> + * + * 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 "QtPanGestureRecognizer.h" + +#include "QtWebPageEventHandler.h" +#include <QTouchEvent> + +namespace WebKit { + +QtPanGestureRecognizer::QtPanGestureRecognizer(QtWebPageEventHandler* eventHandler) + : QtGestureRecognizer(eventHandler) +{ + reset(); +} + +bool QtPanGestureRecognizer::recognize(const QTouchEvent* event, qint64 eventTimestampMillis) +{ + if (!interactionEngine()) + return false; + + // Pan gesture always starts on TouchBegin unless the engine is suspended, or + // we ignored the event. + if (m_state == NoGesture && event->type() != QEvent::TouchBegin) + return false; + + // Having multiple touch points cancel the panning gesture. + if (event->touchPoints().size() > 1) { + if (m_state == GestureRecognized) + interactionEngine()->panGestureCancelled(); + reset(); + return false; + } + + const QTouchEvent::TouchPoint& touchPoint = event->touchPoints().first(); + + switch (event->type()) { + case QEvent::TouchBegin: + ASSERT(m_state == NoGesture); + m_state = GestureRecognitionStarted; + m_firstPosition = touchPoint.screenPos(); + return false; + case QEvent::TouchUpdate: { + ASSERT(m_state != NoGesture); + if (m_state == GestureRecognitionStarted) { + // To start the gesture, the delta from start in screen coordinates + // must be bigger than the trigger threshold. + QPointF totalOffsetFromStart(touchPoint.screenPos() - m_firstPosition); + if (qAbs(totalOffsetFromStart.x()) < panningInitialTriggerDistanceThreshold && qAbs(totalOffsetFromStart.y()) < panningInitialTriggerDistanceThreshold) + return false; + + m_state = GestureRecognized; + interactionEngine()->panGestureStarted(touchPoint.pos(), eventTimestampMillis); + } + + ASSERT(m_state == GestureRecognized); + interactionEngine()->panGestureRequestUpdate(touchPoint.pos(), eventTimestampMillis); + return true; + } + case QEvent::TouchEnd: + if (m_state == GestureRecognized) { + interactionEngine()->panGestureEnded(touchPoint.pos(), eventTimestampMillis); + reset(); + return true; + } + ASSERT(m_state == GestureRecognitionStarted); + reset(); + return false; + default: + ASSERT_NOT_REACHED(); + } + return false; +} + +void QtPanGestureRecognizer::reset() +{ + QtGestureRecognizer::reset(); + m_firstPosition = QPointF(); +} + +} // namespace WebKit diff --git a/Source/WebKit2/UIProcess/qt/QtPanGestureRecognizer.h b/Source/WebKit2/UIProcess/qt/QtPanGestureRecognizer.h new file mode 100644 index 000000000..532507e09 --- /dev/null +++ b/Source/WebKit2/UIProcess/qt/QtPanGestureRecognizer.h @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2011 Benjamin Poulain <benjamin@webkit.org> + * + * 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 QtPanGestureRecognizer_h +#define QtPanGestureRecognizer_h + +#include "QtGestureRecognizer.h" + +#include <QPointF> +#include <QtCore/QtGlobal> + +QT_BEGIN_NAMESPACE +class QTouchEvent; +QT_END_NAMESPACE + +namespace WebKit { + +const qreal panningInitialTriggerDistanceThreshold = 5.; + +class QtPanGestureRecognizer : public QtGestureRecognizer { +public: + QtPanGestureRecognizer(QtWebPageEventHandler*); + bool recognize(const QTouchEvent*, qint64 eventTimestampMillis); + void reset(); + +private: + QPointF m_firstPosition; +}; + +} // namespace WebKit + +#endif /* QtPanGestureRecognizer_h */ diff --git a/Source/WebKit2/UIProcess/qt/QtPinchGestureRecognizer.cpp b/Source/WebKit2/UIProcess/qt/QtPinchGestureRecognizer.cpp new file mode 100644 index 000000000..9167792c4 --- /dev/null +++ b/Source/WebKit2/UIProcess/qt/QtPinchGestureRecognizer.cpp @@ -0,0 +1,157 @@ +/* + * Copyright (C) 2011 Benjamin Poulain <benjamin@webkit.org> + * + * 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 "QtPinchGestureRecognizer.h" + +#include "QtWebPageEventHandler.h" +#include <QtCore/QLineF> + +namespace WebKit { + +const qreal pinchInitialTriggerDistanceThreshold = 5.; + +static inline int findTouchPointIndex(const QList<QTouchEvent::TouchPoint>& touchPoints, const QtPinchGestureRecognizer::TouchPointInformation& pointInformation) +{ + const int touchCount = touchPoints.size(); + for (int i = 0; i < touchCount; ++i) { + const QTouchEvent::TouchPoint& touchPoint = touchPoints.at(i); + if (touchPoint.id() == pointInformation.id) + return i; + } + return -1; +} + +static inline QPointF computePinchCenter(const QTouchEvent::TouchPoint& point1, const QTouchEvent::TouchPoint& point2) +{ + return (point1.pos() + point2.pos()) / 2.0f; +} + +QtPinchGestureRecognizer::QtPinchGestureRecognizer(QtWebPageEventHandler* eventHandler) + : QtGestureRecognizer(eventHandler) +{ + reset(); +} + +bool QtPinchGestureRecognizer::recognize(const QTouchEvent* event) +{ + if (!interactionEngine()) + return false; + + const QList<QTouchEvent::TouchPoint>& touchPoints = event->touchPoints(); + if (touchPoints.size() < 2) { + if (m_state == GestureRecognized) + interactionEngine()->pinchGestureEnded(); + reset(); + return false; + } + + switch (event->type()) { + case QEvent::TouchBegin: + case QEvent::TouchUpdate: + switch (m_state) { + case NoGesture: + initializeGesture(touchPoints); + return false; + case GestureRecognitionStarted: + case GestureRecognized: + ASSERT(m_point1.isValid()); + ASSERT(m_point2.isValid()); + + const int point1Index = findTouchPointIndex(touchPoints, m_point1); + if (point1Index < 0) { + reset(); + return false; + } + const int point2Index = findTouchPointIndex(touchPoints, m_point2); + if (point2Index < 0) { + reset(); + return false; + } + + const QTouchEvent::TouchPoint& point1 = touchPoints.at(point1Index); + const QTouchEvent::TouchPoint& point2 = touchPoints.at(point2Index); + if (m_state == GestureRecognitionStarted) { + // FIXME: The gesture should only start if the touch events were not accepted at the start of the touch sequence. + const qreal pinchDistance = qAbs(QLineF(point1.screenPos(), point2.screenPos()).length() - QLineF(m_point1.initialScreenPosition, m_point2.initialScreenPosition).length()); + if (pinchDistance < pinchInitialTriggerDistanceThreshold) + return false; + m_state = GestureRecognized; + interactionEngine()->pinchGestureStarted(computePinchCenter(point1, point2)); + + // We reset the initial position to the previous position in order to avoid the jump caused + // by skipping all the events between the beginning and when the threshold is hit. + m_point1.initialPosition = point1.lastPos(); + m_point1.initialScreenPosition = point1.lastScreenPos(); + m_point2.initialPosition = point2.lastPos(); + m_point2.initialScreenPosition = point2.lastScreenPos(); + } + ASSERT(m_state == GestureRecognized); + const qreal currentSpanDistance = QLineF(point1.screenPos(), point2.screenPos()).length(); + const qreal initialSpanDistance = QLineF(m_point1.initialScreenPosition, m_point2.initialScreenPosition).length(); + const qreal totalScaleFactor = currentSpanDistance / initialSpanDistance; + const QPointF touchCenterInPageViewCoordinates = computePinchCenter(point1, point2); + interactionEngine()->pinchGestureRequestUpdate(touchCenterInPageViewCoordinates, totalScaleFactor); + return true; + break; + } + break; + case QEvent::TouchEnd: + if (m_state == GestureRecognized) { + interactionEngine()->pinchGestureEnded(); + reset(); + return true; + } + reset(); + break; + default: + ASSERT_NOT_REACHED(); + } + + return false; +} + +void QtPinchGestureRecognizer::reset() +{ + QtGestureRecognizer::reset(); + m_point1 = TouchPointInformation(); + m_point2 = TouchPointInformation(); +} + +void QtPinchGestureRecognizer::initializeGesture(const QList<QTouchEvent::TouchPoint>& touchPoints) +{ + ASSERT(!m_point1.isValid()); + ASSERT(!m_point2.isValid()); + + m_state = GestureRecognitionStarted; + + m_point1 = TouchPointInformation(touchPoints.at(0)); + m_point2 = TouchPointInformation(touchPoints.at(1)); + + ASSERT(m_point1.isValid()); + ASSERT(m_point2.isValid()); +} + +} diff --git a/Source/WebKit2/UIProcess/qt/QtPinchGestureRecognizer.h b/Source/WebKit2/UIProcess/qt/QtPinchGestureRecognizer.h new file mode 100644 index 000000000..7dd3d911b --- /dev/null +++ b/Source/WebKit2/UIProcess/qt/QtPinchGestureRecognizer.h @@ -0,0 +1,83 @@ +/* + * Copyright (C) 2011 Benjamin Poulain <benjamin@webkit.org> + * + * 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 QtPinchGestureRecognizer_h +#define QtPinchGestureRecognizer_h + +#include "QtGestureRecognizer.h" + +#include <QTouchEvent> +#include <QtCore/QList> +#include <QtCore/QPointF> + +QT_BEGIN_NAMESPACE +class QTouchEvent; +QT_END_NAMESPACE + +namespace WebKit { + +class QtPinchGestureRecognizer : public QtGestureRecognizer { +public: + struct TouchPointInformation { + inline TouchPointInformation(); + inline TouchPointInformation(const QTouchEvent::TouchPoint&); + inline bool isValid() const; + + int id; + QPointF initialScreenPosition; + QPointF initialPosition; + }; + + QtPinchGestureRecognizer(QtWebPageEventHandler*); + bool recognize(const QTouchEvent*); + void reset(); + +private: + void initializeGesture(const QList<QTouchEvent::TouchPoint>& touchPoints); + + TouchPointInformation m_point1; + TouchPointInformation m_point2; +}; + +inline QtPinchGestureRecognizer::TouchPointInformation::TouchPointInformation() + : id(-1) +{ +} + +inline QtPinchGestureRecognizer::TouchPointInformation::TouchPointInformation(const QTouchEvent::TouchPoint& touchPoint) + : id(touchPoint.id()) + , initialScreenPosition(touchPoint.screenPos()) + , initialPosition(touchPoint.pos()) +{ +} + +inline bool QtPinchGestureRecognizer::TouchPointInformation::isValid() const +{ + return id >= 0; +} + +} + +#endif /* QtPinchGestureRecognizer_h */ diff --git a/Source/WebKit2/UIProcess/qt/QtSGTileNode.cpp b/Source/WebKit2/UIProcess/qt/QtSGTileNode.cpp new file mode 100644 index 000000000..229bafc7c --- /dev/null +++ b/Source/WebKit2/UIProcess/qt/QtSGTileNode.cpp @@ -0,0 +1,73 @@ +/* + * Copyright (C) 2010, 2011 Nokia Corporation and/or its subsidiary(-ies) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this program; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + */ + +#include "config.h" +#include "QtSGTileNode.h" + +#include <QtQuick/QSGEngine> +#include <QtQuick/QSGFlatColorMaterial> +#include <QtQuick/QSGTexture> + +namespace WebKit { + +QtSGTileNode::QtSGTileNode(QSGEngine* engine) + : m_engine(engine) + , m_geometry(QSGGeometry::defaultAttributes_TexturedPoint2D(), 4) + , m_textureMaterialsCreated(false) +{ + setFlags(OwnsMaterial | OwnsOpaqueMaterial); + setGeometry(&m_geometry); + setMaterial(new QSGFlatColorMaterial); + setOpaqueMaterial(new QSGFlatColorMaterial); +} + +void QtSGTileNode::setBackBuffer(const QImage& backBuffer, const QRectF& sourceRect, const QRectF& targetRect) +{ + m_backBufferTexture.reset(m_engine->createTextureFromImage(backBuffer)); + m_backBufferTargetRect = targetRect; + m_backBufferSourceRect = m_backBufferTexture->convertToNormalizedSourceRect(sourceRect); + + // Force the texture upload. + m_backBufferTexture->bind(); +} + +void QtSGTileNode::swapBuffersIfNeeded() +{ + if (!m_backBufferTexture) + return; + + if (!m_textureMaterialsCreated) { + setMaterial(new QSGTextureMaterial); + setOpaqueMaterial(new QSGOpaqueTextureMaterial); + m_textureMaterialsCreated = true; + } + + static_cast<QSGTextureMaterial*>(material())->setTexture(m_backBufferTexture.data()); + static_cast<QSGOpaqueTextureMaterial*>(opaqueMaterial())->setTexture(m_backBufferTexture.data()); + markDirty(DirtyMaterial); + + QSGGeometry::updateTexturedRectGeometry(&m_geometry, m_backBufferTargetRect, m_backBufferSourceRect); + markDirty(DirtyGeometry); + + m_frontBufferTexture.swap(m_backBufferTexture); + m_backBufferTexture.reset(); +} + +} diff --git a/Source/WebKit2/UIProcess/qt/QtSGTileNode.h b/Source/WebKit2/UIProcess/qt/QtSGTileNode.h new file mode 100644 index 000000000..11aaecad8 --- /dev/null +++ b/Source/WebKit2/UIProcess/qt/QtSGTileNode.h @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this program; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + */ + +#ifndef QtSGTileNode_h +#define QtSGTileNode_h + +#include <QtQuick/QSGGeometryNode> +#include <QtQuick/QSGOpaqueTextureMaterial> +#include <QtQuick/QSGTextureMaterial> + +QT_BEGIN_NAMESPACE +class QSGEngine; +class QSGTexture; +QT_END_NAMESPACE + +namespace WebKit { + +class QtSGTileNode : public QSGGeometryNode { +public: + QtSGTileNode(QSGEngine*); + void setBackBuffer(const QImage&, const QRectF& sourceRect, const QRectF& targetRect); + void swapBuffersIfNeeded(); + +private: + QSGEngine* m_engine; + QSGGeometry m_geometry; + QScopedPointer<QSGTexture> m_frontBufferTexture; + QScopedPointer<QSGTexture> m_backBufferTexture; + bool m_textureMaterialsCreated; + + QRectF m_backBufferTargetRect; + QRectF m_backBufferSourceRect; +}; + +} + +#endif // QtSGTileNode_h diff --git a/Source/WebKit2/UIProcess/qt/QtSGUpdateQueue.cpp b/Source/WebKit2/UIProcess/qt/QtSGUpdateQueue.cpp new file mode 100644 index 000000000..7b1675dfe --- /dev/null +++ b/Source/WebKit2/UIProcess/qt/QtSGUpdateQueue.cpp @@ -0,0 +1,170 @@ +/* + * Copyright (C) 2010, 2011 Nokia Corporation and/or its subsidiary(-ies) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this program; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + */ + +#include "config.h" +#include "QtSGUpdateQueue.h" + +#include "PassOwnPtr.h" +#include "QtSGTileNode.h" +#include <QtQuick/QQuickItem> + +namespace WebKit { + +struct NodeUpdateCreateTile : public NodeUpdate { + NodeUpdateCreateTile(int nodeID, float scale) + : NodeUpdate(CreateTile) + , nodeID(nodeID) + , scale(scale) + { } + int nodeID; + float scale; +}; + +struct NodeUpdateRemoveTile : public NodeUpdate { + NodeUpdateRemoveTile(int nodeID) + : NodeUpdate(RemoveTile) + , nodeID(nodeID) + { } + int nodeID; +}; + +struct NodeUpdateSetBackBuffer : public NodeUpdate { + NodeUpdateSetBackBuffer(int nodeID, const QImage& backBuffer, const QRect& sourceRect, const QRect& targetRect) + : NodeUpdate(SetBackBuffer) + , nodeID(nodeID) + , backBuffer(backBuffer) + , sourceRect(sourceRect) + , targetRect(targetRect) + { } + int nodeID; + QImage backBuffer; + QRect sourceRect; + QRect targetRect; +}; + +struct NodeUpdateSwapTileBuffers : public NodeUpdate { + NodeUpdateSwapTileBuffers() + : NodeUpdate(SwapTileBuffers) + { } +}; + +QtSGUpdateQueue::QtSGUpdateQueue(QQuickItem *item) + : item(item) + , lastScale(0) + , lastScaleNode(0) + , nextNodeID(1) + , m_isSwapPending(false) +{ +} + +int QtSGUpdateQueue::createTileNode(float scale) +{ + int nodeID = nextNodeID++; + nodeUpdateQueue.append(adoptPtr(new NodeUpdateCreateTile(nodeID, scale))); + item->update(); + return nodeID; +} + +void QtSGUpdateQueue::removeTileNode(int nodeID) +{ + nodeUpdateQueue.append(adoptPtr(new NodeUpdateRemoveTile(nodeID))); + item->update(); +} + +void QtSGUpdateQueue::setNodeBackBuffer(int nodeID, const QImage& backBuffer, const QRect& sourceRect, const QRect& targetRect) +{ + nodeUpdateQueue.append(adoptPtr(new NodeUpdateSetBackBuffer(nodeID, backBuffer, sourceRect, targetRect))); + item->update(); +} + +void QtSGUpdateQueue::swapTileBuffers() +{ + nodeUpdateQueue.append(adoptPtr(new NodeUpdateSwapTileBuffers())); + m_isSwapPending = true; + item->update(); +} + +void QtSGUpdateQueue::applyUpdates(QSGNode* itemNode) +{ + while (!nodeUpdateQueue.isEmpty()) { + OwnPtr<NodeUpdate> nodeUpdate(nodeUpdateQueue.takeFirst()); + switch (nodeUpdate->type) { + case NodeUpdate::CreateTile: { + NodeUpdateCreateTile* createTileUpdate = static_cast<NodeUpdateCreateTile*>(nodeUpdate.get()); + QtSGTileNode* tileNode = new QtSGTileNode(item->sceneGraphEngine()); + getScaleNode(createTileUpdate->scale, itemNode)->prependChildNode(tileNode); + nodes.set(createTileUpdate->nodeID, tileNode); + break; + } + case NodeUpdate::RemoveTile: { + NodeUpdateRemoveTile* removeUpdate = static_cast<NodeUpdateRemoveTile*>(nodeUpdate.get()); + QSGNode* node = nodes.take(removeUpdate->nodeID); + QSGNode* scaleNode = node->parent(); + + scaleNode->removeChildNode(node); + if (!scaleNode->childCount()) { + if (scaleNode == lastScaleNode) { + lastScale = 0; + lastScaleNode = 0; + } + delete scaleNode; + } + delete node; + break; + } + case NodeUpdate::SetBackBuffer: { + NodeUpdateSetBackBuffer* setBackBufferUpdate = static_cast<NodeUpdateSetBackBuffer*>(nodeUpdate.get()); + QtSGTileNode* tileNode = nodes.get(setBackBufferUpdate->nodeID); + tileNode->setBackBuffer(setBackBufferUpdate->backBuffer, setBackBufferUpdate->sourceRect, setBackBufferUpdate->targetRect); + break; + } + case NodeUpdate::SwapTileBuffers: { + HashMap<int, QtSGTileNode*>::iterator end = nodes.end(); + for (HashMap<int, QtSGTileNode*>::iterator it = nodes.begin(); it != end; ++it) + it->second->swapBuffersIfNeeded(); + m_isSwapPending = false; + break; + } + default: + ASSERT_NOT_REACHED(); + } + } +} + +QSGNode* QtSGUpdateQueue::getScaleNode(float scale, QSGNode* itemNode) +{ + if (scale == lastScale) + return lastScaleNode; + + QSGTransformNode* scaleNode = new QSGTransformNode; + QMatrix4x4 scaleMatrix; + // Use scale(float,float) to prevent scaling the Z component. + // Reverse the item's transform scale since our tiles were generated for this specific scale. + scaleMatrix.scale(1 / scale, 1 / scale); + scaleNode->setMatrix(scaleMatrix); + // Prepend instead of append to paint the new, incomplete, scale before/behind the previous one. + itemNode->prependChildNode(scaleNode); + + lastScale = scale; + lastScaleNode = scaleNode; + return lastScaleNode; +} + +} diff --git a/Source/WebKit2/UIProcess/qt/QtSGUpdateQueue.h b/Source/WebKit2/UIProcess/qt/QtSGUpdateQueue.h new file mode 100644 index 000000000..f70c50668 --- /dev/null +++ b/Source/WebKit2/UIProcess/qt/QtSGUpdateQueue.h @@ -0,0 +1,82 @@ +/* + * Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this program; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + */ + +#ifndef QtSGUpdateQueue_h +#define QtSGUpdateQueue_h + +#include "Deque.h" +#include "HashMap.h" +#include "OwnPtr.h" + +class QImage; +class QRect; +class QQuickItem; +class QSGNode; +class QSize; + +namespace WebKit { + +class NodeUpdate; +class PageNode; +class QtSGTileNode; + +// Takes care of taking update requests then fulfilling them asynchronously on the scene graph thread. +class QtSGUpdateQueue { +public: + QtSGUpdateQueue(QQuickItem*); + + int createTileNode(float scale); + void removeTileNode(int nodeID); + void setNodeBackBuffer(int nodeID, const QImage& texture, const QRect& sourceRect, const QRect& targetRect); + void swapTileBuffers(); + + // Called by the QQuickItem. + void applyUpdates(QSGNode* itemNode); + bool isSwapPending() const { return m_isSwapPending; } + +private: + QSGNode* getScaleNode(float scale, QSGNode* itemNode); + + QQuickItem* item; + Deque<OwnPtr<NodeUpdate> > nodeUpdateQueue; + HashMap<int, QtSGTileNode*> nodes; + float lastScale; + QSGNode* lastScaleNode; + int nextNodeID; + bool m_isSwapPending; +}; + +struct NodeUpdate { + enum Type { + CreateTile, + RemoveTile, + SetBackBuffer, + SwapTileBuffers + }; + NodeUpdate(Type type) + : type(type) + { } + virtual ~NodeUpdate() { } + Type type; +}; + +} + +#endif // QtSGUpdateQueue_h diff --git a/Source/WebKit2/UIProcess/qt/QtTapGestureRecognizer.cpp b/Source/WebKit2/UIProcess/qt/QtTapGestureRecognizer.cpp new file mode 100644 index 000000000..2ed773c11 --- /dev/null +++ b/Source/WebKit2/UIProcess/qt/QtTapGestureRecognizer.cpp @@ -0,0 +1,161 @@ +/* + * Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies) + * + * 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 "QtTapGestureRecognizer.h" + +#include "QtWebPageEventHandler.h" +#include <QLineF> +#include <QTouchEvent> + +namespace WebKit { + +QtTapGestureRecognizer::QtTapGestureRecognizer(QtWebPageEventHandler* eventHandler) + : QtGestureRecognizer(eventHandler) + , m_tapState(NoTap) +{ + reset(); +} + +bool QtTapGestureRecognizer::recognize(const QTouchEvent* event, qint64 eventTimestampMillis) +{ + if (event->touchPoints().size() != 1) { + reset(); + return false; + } + + switch (event->type()) { + case QEvent::TouchBegin: + ASSERT(m_tapState == NoTap); + ASSERT(!m_tapAndHoldTimer.isActive()); + + m_tapAndHoldTimer.start(tapAndHoldTime, this); + + if (m_doubleTapTimer.isActive()) { + // Might be double tap. + ASSERT(m_touchBeginEventForTap); + m_doubleTapTimer.stop(); + QPointF lastPosition = m_touchBeginEventForTap->touchPoints().first().screenPos(); + QPointF newPosition = event->touchPoints().first().screenPos(); + if (QLineF(lastPosition, newPosition).length() < maxDoubleTapDistance) + m_tapState = DoubleTapCandidate; + else { + // Received a new tap, that is unrelated to the previous one. + tapTimeout(); + m_tapState = SingleTapStarted; + } + } else + m_tapState = SingleTapStarted; + m_touchBeginEventForTap = adoptPtr(new QTouchEvent(*event)); + break; + case QEvent::TouchUpdate: + // If the touch point moves further than the threshold, we cancel the tap gesture. + if (m_tapState == SingleTapStarted) { + const QTouchEvent::TouchPoint& touchPoint = event->touchPoints().first(); + QPointF offset(touchPoint.scenePos() - m_touchBeginEventForTap->touchPoints().first().scenePos()); + const qreal distX = qAbs(offset.x()); + const qreal distY = qAbs(offset.y()); + if (distX > initialTriggerDistanceThreshold || distY > initialTriggerDistanceThreshold) + reset(); + } + break; + case QEvent::TouchEnd: + m_tapAndHoldTimer.stop(); + + switch (m_tapState) { + case DoubleTapCandidate: + { + ASSERT(!m_doubleTapTimer.isActive()); + m_tapState = NoTap; + + const QTouchEvent::TouchPoint& touchPoint = event->touchPoints().first(); + QPointF startPosition = touchPoint.startScreenPos(); + QPointF endPosition = touchPoint.screenPos(); + if (QLineF(endPosition, startPosition).length() < maxDoubleTapDistance && m_eventHandler) + m_eventHandler->handleDoubleTapEvent(touchPoint); + break; + } + case SingleTapStarted: + ASSERT(!m_doubleTapTimer.isActive()); + m_doubleTapTimer.start(doubleClickInterval, this); + m_tapState = NoTap; + break; + case TapAndHold: + m_tapState = NoTap; + break; + default: + break; + } + break; + default: + break; + } + return false; +} + +void QtTapGestureRecognizer::tapTimeout() +{ + m_doubleTapTimer.stop(); + m_eventHandler->handleSingleTapEvent(m_touchBeginEventForTap->touchPoints().at(0)); + m_touchBeginEventForTap.clear(); +} + +void QtTapGestureRecognizer::tapAndHoldTimeout() +{ + ASSERT(m_touchBeginEventForTap); + m_tapAndHoldTimer.stop(); +#if 0 // No support for synthetic context menus in WK2 yet. + QTouchEvent::TouchPoint tapPoint = m_touchBeginEventForTap->touchPoints().at(0); + WebGestureEvent gesture(WebEvent::GestureTapAndHold, tapPoint.pos().toPoint(), tapPoint.screenPos().toPoint(), WebEvent::Modifiers(0), 0); + if (m_webPageProxy) + m_webPageProxy->handleGestureEvent(gesture); +#endif + m_touchBeginEventForTap.clear(); + m_tapState = TapAndHold; + + ASSERT(!m_doubleTapTimer.isActive()); + m_doubleTapTimer.stop(); +} + +void QtTapGestureRecognizer::reset() +{ + m_tapState = NoTap; + m_touchBeginEventForTap.clear(); + m_tapAndHoldTimer.stop(); + + QtGestureRecognizer::reset(); +} + +void QtTapGestureRecognizer::timerEvent(QTimerEvent* ev) +{ + int timerId = ev->timerId(); + if (timerId == m_doubleTapTimer.timerId()) + tapTimeout(); + else if (timerId == m_tapAndHoldTimer.timerId()) + tapAndHoldTimeout(); + else + QObject::timerEvent(ev); +} + +} // namespace WebKit diff --git a/Source/WebKit2/UIProcess/qt/QtTapGestureRecognizer.h b/Source/WebKit2/UIProcess/qt/QtTapGestureRecognizer.h new file mode 100644 index 000000000..a4ec41eff --- /dev/null +++ b/Source/WebKit2/UIProcess/qt/QtTapGestureRecognizer.h @@ -0,0 +1,76 @@ +/* + * Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies) + * + * 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 QtTapGestureRecognizer_h +#define QtTapGestureRecognizer_h + +#include "QtGestureRecognizer.h" + +#include <QtCore/QBasicTimer> +#include <QtCore/QObject> +#include <QtCore/QtGlobal> +#include <wtf/OwnPtr.h> + +QT_BEGIN_NAMESPACE +class QTouchEvent; +QT_END_NAMESPACE + +// FIXME: These constants should possibly depend on DPI. +const qreal initialTriggerDistanceThreshold = 5; +const qreal maxDoubleTapDistance = 120; +const int tapAndHoldTime = 800; +const int doubleClickInterval = 400; + +class QtWebPageEventHandler; + +namespace WebKit { + +class QtTapGestureRecognizer : public QObject, private QtGestureRecognizer { +public: + QtTapGestureRecognizer(QtWebPageEventHandler*); + bool recognize(const QTouchEvent*, qint64 eventTimestampMillis); + void reset(); + +protected: + void timerEvent(QTimerEvent*); + void tapTimeout(); + void tapAndHoldTimeout(); + +private: + QBasicTimer m_doubleTapTimer; + QBasicTimer m_tapAndHoldTimer; + OwnPtr<QTouchEvent> m_touchBeginEventForTap; + + enum { + NoTap, + SingleTapStarted, + DoubleTapCandidate, + TapAndHold + } m_tapState; +}; + +} // namespace WebKit + +#endif /* QtTapGestureRecognizer_h */ diff --git a/Source/WebKit2/UIProcess/qt/QtViewportInteractionEngine.cpp b/Source/WebKit2/UIProcess/qt/QtViewportInteractionEngine.cpp new file mode 100644 index 000000000..788349ae0 --- /dev/null +++ b/Source/WebKit2/UIProcess/qt/QtViewportInteractionEngine.cpp @@ -0,0 +1,589 @@ +/* + * Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies) + * Copyright (C) 2011 Benjamin Poulain <benjamin@webkit.org> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this program; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + */ + +#include "config.h" +#include "QtViewportInteractionEngine.h" + +#include "PassOwnPtr.h" +#include <QPointF> +#include <QScrollEvent> +#include <QScrollPrepareEvent> +#include <QScrollerProperties> +#include <QWheelEvent> +#include <QtQuick/qquickitem.h> + +namespace WebKit { + +static const int kScaleAnimationDurationMillis = 250; + +// UPDATE DEFERRING (SUSPEND/RESUME) +// ================================= +// +// When interaction with the content, either by animating or by the hand of the user, +// it is important to ensure smooth animations of at least 60fps in order to give a +// good user experience. +// +// In order to do this we need to get rid of unknown factors. These include device +// sensors (geolocation, orientation updates etc), CSS3 animations, JavaScript +// exectution, sub resource loads etc. We do this by emitting suspend and resume +// signals, which are then handled by the viewport and propagates to the right place. +// +// For this reason the ViewportUpdateDeferrer guard must be used when we interact +// or animate the content. +// +// It should be noted that when we update content properties, we might receive notify +// signals send my the content item itself, and care should be taken to not act on +// these unconditionally. An example of this is the pinch zoom, which changes the +// position and will thus result in a QQuickWebPage::geometryChanged() signal getting +// emitted. +// +// If something should only be executed during update deferring, it is possible to +// check for that using ASSERT(m_suspendCount). + +class ViewportUpdateDeferrer { +public: + ViewportUpdateDeferrer(QtViewportInteractionEngine* engine) + : engine(engine) + { + if (engine->m_suspendCount++) + return; + + emit engine->contentSuspendRequested(); + } + + ~ViewportUpdateDeferrer() + { + if (--(engine->m_suspendCount)) + return; + + emit engine->contentResumeRequested(); + + // Make sure that tiles all around the viewport will be requested. + emit engine->viewportTrajectoryVectorChanged(QPointF()); + } + +private: + QtViewportInteractionEngine* const engine; +}; + +inline qreal QtViewportInteractionEngine::cssScaleFromItem(qreal itemScale) +{ + return itemScale / m_constraints.devicePixelRatio; +} + +inline qreal QtViewportInteractionEngine::itemScaleFromCSS(qreal cssScale) +{ + return cssScale * m_constraints.devicePixelRatio; +} + +inline qreal QtViewportInteractionEngine::itemCoordFromCSS(qreal value) +{ + return value * m_constraints.devicePixelRatio; +} + +inline QRectF QtViewportInteractionEngine::itemRectFromCSS(const QRectF& cssRect) +{ + QRectF itemRect; + + itemRect.setX(itemCoordFromCSS(cssRect.x())); + itemRect.setY(itemCoordFromCSS(cssRect.y())); + itemRect.setWidth(itemCoordFromCSS(cssRect.width())); + itemRect.setHeight(itemCoordFromCSS(cssRect.height())); + + return itemRect; +} + +QtViewportInteractionEngine::QtViewportInteractionEngine(const QQuickItem* viewport, QQuickItem* content) + : m_viewport(viewport) + , m_content(content) + , m_suspendCount(0) + , m_scaleAnimation(new ScaleAnimation(this)) + , m_pinchStartScale(-1) +{ + reset(); + + QScrollerProperties properties = scroller()->scrollerProperties(); + + // The QtPanGestureRecognizer is responsible for recognizing the gesture + // thus we need to disable the drag start distance. + properties.setScrollMetric(QScrollerProperties::DragStartDistance, 0.0); + + // Set some default QScroller constrains to mimic the physics engine of the N9 browser. + properties.setScrollMetric(QScrollerProperties::AxisLockThreshold, 0.66); + properties.setScrollMetric(QScrollerProperties::ScrollingCurve, QEasingCurve(QEasingCurve::OutExpo)); + properties.setScrollMetric(QScrollerProperties::DecelerationFactor, 0.05); + properties.setScrollMetric(QScrollerProperties::MaximumVelocity, 0.635); + properties.setScrollMetric(QScrollerProperties::OvershootDragResistanceFactor, 0.33); + properties.setScrollMetric(QScrollerProperties::OvershootScrollDistanceFactor, 0.33); + + scroller()->setScrollerProperties(properties); + + connect(m_content, SIGNAL(widthChanged()), this, SLOT(itemSizeChanged()), Qt::DirectConnection); + connect(m_content, SIGNAL(heightChanged()), this, SLOT(itemSizeChanged()), Qt::DirectConnection); + + connect(m_scaleAnimation, SIGNAL(valueChanged(QVariant)), + SLOT(scaleAnimationValueChanged(QVariant)), Qt::DirectConnection); + connect(m_scaleAnimation, SIGNAL(stateChanged(QAbstractAnimation::State, QAbstractAnimation::State)), + SLOT(scaleAnimationStateChanged(QAbstractAnimation::State, QAbstractAnimation::State)), Qt::DirectConnection); + + connect(scroller(), SIGNAL(stateChanged(QScroller::State)), + SLOT(scrollStateChanged(QScroller::State)), Qt::DirectConnection); +} + +QtViewportInteractionEngine::~QtViewportInteractionEngine() +{ +} + +qreal QtViewportInteractionEngine::innerBoundedCSSScale(qreal cssScale) +{ + return qBound(m_constraints.minimumScale, cssScale, m_constraints.maximumScale); +} + +qreal QtViewportInteractionEngine::outerBoundedCSSScale(qreal cssScale) +{ + if (m_constraints.isUserScalable) { + // Bounded by [0.1, 10.0] like the viewport meta code in WebCore. + qreal hardMin = qMax<qreal>(0.1, qreal(0.5) * m_constraints.minimumScale); + qreal hardMax = qMin<qreal>(10, qreal(2.0) * m_constraints.maximumScale); + return qBound(hardMin, cssScale, hardMax); + } + return innerBoundedCSSScale(cssScale); +} + +void QtViewportInteractionEngine::setItemRectVisible(const QRectF& itemRect) +{ + ViewportUpdateDeferrer guard(this); + + qreal itemScale = m_viewport->width() / itemRect.width(); + + m_content->setScale(itemScale); + + // We need to animate the content but the position represents the viewport hence we need to invert the position here. + // To animate the position together with the scale we multiply the position with the current scale; + m_content->setPos(- itemRect.topLeft() * itemScale); +} + +bool QtViewportInteractionEngine::animateItemRectVisible(const QRectF& itemRect) +{ + QRectF currentItemRectVisible = m_content->mapRectFromItem(m_viewport, m_viewport->boundingRect()); + if (itemRect == currentItemRectVisible) + return false; + + m_scaleAnimation->setDuration(kScaleAnimationDurationMillis); + m_scaleAnimation->setEasingCurve(QEasingCurve::OutCubic); + + m_scaleAnimation->setStartValue(currentItemRectVisible); + m_scaleAnimation->setEndValue(itemRect); + + m_scaleAnimation->start(); + return true; +} + +void QtViewportInteractionEngine::scaleAnimationStateChanged(QAbstractAnimation::State newState, QAbstractAnimation::State /*oldState*/) +{ + switch (newState) { + case QAbstractAnimation::Running: + if (!m_scaleUpdateDeferrer) + m_scaleUpdateDeferrer = adoptPtr(new ViewportUpdateDeferrer(this)); + break; + case QAbstractAnimation::Stopped: + m_scaleUpdateDeferrer.clear(); + break; + default: + break; + } +} + +void QtViewportInteractionEngine::scrollStateChanged(QScroller::State newState) +{ + switch (newState) { + case QScroller::Inactive: + // FIXME: QScroller gets when even when tapping while it is scrolling. + m_scrollUpdateDeferrer.clear(); + break; + case QScroller::Pressed: + case QScroller::Dragging: + case QScroller::Scrolling: + if (m_scrollUpdateDeferrer) + break; + m_scrollUpdateDeferrer = adoptPtr(new ViewportUpdateDeferrer(this)); + break; + default: + break; + } +} + +bool QtViewportInteractionEngine::event(QEvent* event) +{ + switch (event->type()) { + case QEvent::ScrollPrepare: { + QScrollPrepareEvent* prepareEvent = static_cast<QScrollPrepareEvent*>(event); + const QRectF viewportRect = m_viewport->boundingRect(); + const QRectF contentRect = m_viewport->mapRectFromItem(m_content, m_content->boundingRect()); + const QRectF posRange = computePosRangeForItemAtScale(m_content->scale()); + prepareEvent->setContentPosRange(posRange); + prepareEvent->setViewportSize(viewportRect.size()); + + // As we want to push the contents and not actually scroll it, we need to invert the positions here. + prepareEvent->setContentPos(-contentRect.topLeft()); + prepareEvent->accept(); + return true; + } + case QEvent::Scroll: { + QScrollEvent* scrollEvent = static_cast<QScrollEvent*>(event); + QPointF newPos = -scrollEvent->contentPos() - scrollEvent->overshootDistance(); + if (m_content->pos() != newPos) { + QPointF currentPosInContentCoordinates = m_content->mapToItem(m_content->parentItem(), m_content->pos()); + QPointF newPosInContentCoordinates = m_content->mapToItem(m_content->parentItem(), newPos); + + // This must be emitted before viewportUpdateRequested so that the web process knows where to look for tiles. + emit viewportTrajectoryVectorChanged(currentPosInContentCoordinates- newPosInContentCoordinates); + m_content->setPos(newPos); + } + return true; + } + default: + break; + } + return QObject::event(event); +} + +static inline QPointF boundPosition(const QPointF minPosition, const QPointF& position, const QPointF& maxPosition) +{ + return QPointF(qBound(minPosition.x(), position.x(), maxPosition.x()), + qBound(minPosition.y(), position.y(), maxPosition.y())); +} + +void QtViewportInteractionEngine::wheelEvent(QWheelEvent* ev) +{ + if (scrollAnimationActive() || scaleAnimationActive() || pinchGestureActive()) + return; // Ignore. + + int delta = ev->delta(); + QPointF newPos = -m_content->pos(); + + // A delta that is not mod 120 indicates a device that is sending + // fine-resolution scroll events, so use the delta as number of wheel ticks + // and number of pixels to scroll. See also webkit.org/b/29601 + bool fullTick = !(delta % 120); + + static const int cDefaultQtScrollStep = 20; + static const int wheelScrollLines = 3; + int scrollLines = (fullTick) ? wheelScrollLines * cDefaultQtScrollStep : 1; + + delta = (fullTick) ? delta / 120.0f : delta; + delta *= scrollLines; + + if (ev->orientation() == Qt::Horizontal) + newPos.rx() += delta; + else + newPos.ry() += delta; + + QRectF endPosRange = computePosRangeForItemAtScale(m_content->scale()); + m_content->setPos(-boundPosition(endPosRange.topLeft(), newPos, endPosRange.bottomRight())); +} + +void QtViewportInteractionEngine::pagePositionRequest(const QPoint& pagePosition) +{ + // Ignore the request if suspended. Can only happen due to delay in event delivery. + if (m_suspendCount) + return; + + qreal endItemScale = m_content->scale(); // Stay at same scale. + + QRectF endPosRange = computePosRangeForItemAtScale(endItemScale); + QPointF endPosition = boundPosition(endPosRange.topLeft(), pagePosition * endItemScale, endPosRange.bottomRight()); + + QRectF endVisibleContentRect(endPosition / endItemScale, m_viewport->boundingRect().size() / endItemScale); + + setItemRectVisible(endVisibleContentRect); +} + +QRectF QtViewportInteractionEngine::computePosRangeForItemAtScale(qreal itemScale) const +{ + const QSizeF contentItemSize = m_content->boundingRect().size() * itemScale; + const QSizeF viewportItemSize = m_viewport->boundingRect().size(); + + const qreal horizontalRange = contentItemSize.width() - viewportItemSize.width(); + const qreal verticalRange = contentItemSize.height() - viewportItemSize.height(); + + return QRectF(QPointF(0, 0), QSizeF(horizontalRange, verticalRange)); +} + +void QtViewportInteractionEngine::focusEditableArea(const QRectF& caretArea, const QRectF& targetArea) +{ + QRectF endArea = itemRectFromCSS(targetArea); + + qreal endItemScale = itemScaleFromCSS(innerBoundedCSSScale(2.0)); + const QRectF viewportRect = m_viewport->boundingRect(); + + qreal x; + const qreal borderOffset = 10; + if ((endArea.width() + borderOffset) * endItemScale <= viewportRect.width()) { + // Center the input field in the middle of the view, if it is smaller than + // the view at the scale target. + x = viewportRect.center().x() - endArea.width() * endItemScale / 2.0; + } else { + // Ensure that the caret always has borderOffset contents pixels to the right + // of it, and secondarily (if possible), that the area has borderOffset + // contents pixels to the left of it. + qreal caretOffset = itemCoordFromCSS(caretArea.x()) - endArea.x(); + x = qMin(viewportRect.width() - (caretOffset + borderOffset) * endItemScale, borderOffset * endItemScale); + } + + const QPointF hotspot = QPointF(endArea.x(), endArea.center().y()); + const QPointF viewportHotspot = QPointF(x, /* FIXME: visibleCenter */ viewportRect.center().y()); + + QPointF endPosition = hotspot * endItemScale - viewportHotspot; + QRectF endPosRange = computePosRangeForItemAtScale(endItemScale); + + endPosition = boundPosition(endPosRange.topLeft(), endPosition, endPosRange.bottomRight()); + + QRectF endVisibleContentRect(endPosition / endItemScale, viewportRect.size() / endItemScale); + + animateItemRectVisible(endVisibleContentRect); +} + +void QtViewportInteractionEngine::zoomToAreaGestureEnded(const QPointF& touchPoint, const QRectF& targetArea) +{ + if (!targetArea.isValid()) + return; + + if (scrollAnimationActive() || scaleAnimationActive()) + return; + + const int margin = 10; // We want at least a little bit or margin. + QRectF endArea = itemRectFromCSS(targetArea.adjusted(-margin, -margin, margin, margin)); + + const QRectF viewportRect = m_viewport->boundingRect(); + + qreal targetCSSScale = cssScaleFromItem(viewportRect.size().width() / endArea.size().width()); + qreal endItemScale = itemScaleFromCSS(innerBoundedCSSScale(qMin(targetCSSScale, qreal(2.5)))); + + // We want to end up with the target area filling the whole width of the viewport (if possible), + // and centralized vertically where the user requested zoom. Thus our hotspot is the center of + // the targetArea x-wise and the requested zoom position, y-wise. + const QPointF hotspot = QPointF(endArea.center().x(), touchPoint.y() * m_constraints.devicePixelRatio); + const QPointF viewportHotspot = viewportRect.center(); + + QPointF endPosition = hotspot * endItemScale - viewportHotspot; + + QRectF endPosRange = computePosRangeForItemAtScale(endItemScale); + endPosition = boundPosition(endPosRange.topLeft(), endPosition, endPosRange.bottomRight()); + + QRectF endVisibleContentRect(endPosition / endItemScale, viewportRect.size() / endItemScale); + + animateItemRectVisible(endVisibleContentRect); +} + +bool QtViewportInteractionEngine::ensureContentWithinViewportBoundary(bool immediate) +{ + ASSERT(m_suspendCount); + + if (scrollAnimationActive() || scaleAnimationActive()) + return false; + + qreal endItemScale = itemScaleFromCSS(innerBoundedCSSScale(currentCSSScale())); + + const QRectF viewportRect = m_viewport->boundingRect(); + QPointF viewportHotspot = viewportRect.center(); + + QPointF endPosition = m_content->mapFromItem(m_viewport, viewportHotspot) * endItemScale - viewportHotspot; + + QRectF endPosRange = computePosRangeForItemAtScale(endItemScale); + endPosition = boundPosition(endPosRange.topLeft(), endPosition, endPosRange.bottomRight()); + + QRectF endVisibleContentRect(endPosition / endItemScale, viewportRect.size() / endItemScale); + + if (immediate) { + setItemRectVisible(endVisibleContentRect); + return true; + } + return !animateItemRectVisible(endVisibleContentRect); +} + +void QtViewportInteractionEngine::reset() +{ + ASSERT(!m_suspendCount); + + m_hadUserInteraction = false; + + scroller()->stop(); + m_scaleAnimation->stop(); +} + +void QtViewportInteractionEngine::applyConstraints(const Constraints& constraints) +{ + // We always have to apply the constrains even if they didn't change, as + // the initial scale might need to be applied. + + ViewportUpdateDeferrer guard(this); + + m_constraints = constraints; + + if (!m_hadUserInteraction) { + qreal initialScale = innerBoundedCSSScale(m_constraints.initialScale); + m_content->setScale(itemScaleFromCSS(initialScale)); + } + + // If the web app changes successively changes the viewport on purpose + // it wants to be in control and we should disable animations. + ensureContentWithinViewportBoundary(/* immediate */ true); +} + +qreal QtViewportInteractionEngine::currentCSSScale() +{ + return cssScaleFromItem(m_content->scale()); +} + +bool QtViewportInteractionEngine::scrollAnimationActive() const +{ + QScroller* scroller = const_cast<QtViewportInteractionEngine*>(this)->scroller(); + return scroller->state() == QScroller::Scrolling; +} + +void QtViewportInteractionEngine::interruptScrollAnimation() +{ + // Stopping the scroller immediately stops kinetic scrolling and if the view is out of bounds it + // is moved inside valid bounds immediately as well. This is the behavior that we want. + scroller()->stop(); +} + +bool QtViewportInteractionEngine::panGestureActive() const +{ + QScroller* scroller = const_cast<QtViewportInteractionEngine*>(this)->scroller(); + return scroller->state() == QScroller::Pressed || scroller->state() == QScroller::Dragging; +} + +void QtViewportInteractionEngine::panGestureStarted(const QPointF& touchPoint, qint64 eventTimestampMillis) +{ + m_hadUserInteraction = true; + scroller()->handleInput(QScroller::InputPress, m_viewport->mapFromItem(m_content, touchPoint), eventTimestampMillis); +} + +void QtViewportInteractionEngine::panGestureRequestUpdate(const QPointF& touchPoint, qint64 eventTimestampMillis) +{ + scroller()->handleInput(QScroller::InputMove, m_viewport->mapFromItem(m_content, touchPoint), eventTimestampMillis); +} + +void QtViewportInteractionEngine::panGestureCancelled() +{ + // Stopping the scroller immediately stops kinetic scrolling and if the view is out of bounds it + // is moved inside valid bounds immediately as well. This is the behavior that we want. + scroller()->stop(); +} + +void QtViewportInteractionEngine::panGestureEnded(const QPointF& touchPoint, qint64 eventTimestampMillis) +{ + scroller()->handleInput(QScroller::InputRelease, m_viewport->mapFromItem(m_content, touchPoint), eventTimestampMillis); +} + +bool QtViewportInteractionEngine::scaleAnimationActive() const +{ + return m_scaleAnimation->state() == QAbstractAnimation::Running; +} + +void QtViewportInteractionEngine::interruptScaleAnimation() +{ + // This interrupts the scale animation exactly where it is, even if it is out of bounds. + m_scaleAnimation->stop(); +} + +bool QtViewportInteractionEngine::pinchGestureActive() const +{ + return m_pinchStartScale > 0; +} + +void QtViewportInteractionEngine::pinchGestureStarted(const QPointF& pinchCenterInContentCoordinates) +{ + ASSERT(!m_suspendCount); + + if (!m_constraints.isUserScalable) + return; + + m_hadUserInteraction = true; + + m_scaleUpdateDeferrer = adoptPtr(new ViewportUpdateDeferrer(this)); + + m_lastPinchCenterInViewportCoordinates = m_viewport->mapFromItem(m_content, pinchCenterInContentCoordinates); + m_pinchStartScale = m_content->scale(); + + // Reset the tiling look-ahead vector so that tiles all around the viewport will be requested on pinch-end. + emit viewportTrajectoryVectorChanged(QPointF()); +} + +void QtViewportInteractionEngine::pinchGestureRequestUpdate(const QPointF& pinchCenterInContentCoordinates, qreal totalScaleFactor) +{ + ASSERT(m_suspendCount); + + if (!m_constraints.isUserScalable) + return; + + // Changes of the center position should move the page even if the zoom factor + // does not change. + const qreal cssScale = cssScaleFromItem(m_pinchStartScale * totalScaleFactor); + + // Allow zooming out beyond mimimum scale on pages that do not explicitly disallow it. + const qreal targetCSSScale = outerBoundedCSSScale(cssScale); + + QPointF pinchCenterInViewportCoordinates = m_viewport->mapFromItem(m_content, pinchCenterInContentCoordinates); + + scaleContent(pinchCenterInContentCoordinates, targetCSSScale); + + const QPointF positionDiff = pinchCenterInViewportCoordinates - m_lastPinchCenterInViewportCoordinates; + m_lastPinchCenterInViewportCoordinates = pinchCenterInViewportCoordinates; + m_content->setPos(m_content->pos() + positionDiff); +} + +void QtViewportInteractionEngine::pinchGestureEnded() +{ + ASSERT(m_suspendCount); + + if (!m_constraints.isUserScalable) + return; + + m_pinchStartScale = -1; + // Clear the update deferrer now if we're in our final position and there won't be any animation to clear it later. + if (ensureContentWithinViewportBoundary()) + m_scaleUpdateDeferrer.clear(); +} + +void QtViewportInteractionEngine::itemSizeChanged() +{ + // FIXME: This needs to be done smarter. What happens if it resizes when we were interacting? + if (m_suspendCount) + return; + + ViewportUpdateDeferrer guard(this); + ensureContentWithinViewportBoundary(); +} + +void QtViewportInteractionEngine::scaleContent(const QPointF& centerInContentCoordinates, qreal cssScale) +{ + QPointF oldPinchCenterOnParent = m_content->mapToItem(m_content->parentItem(), centerInContentCoordinates); + m_content->setScale(itemScaleFromCSS(cssScale)); + QPointF newPinchCenterOnParent = m_content->mapToItem(m_content->parentItem(), centerInContentCoordinates); + m_content->setPos(m_content->pos() - (newPinchCenterOnParent - oldPinchCenterOnParent)); +} + +#include "moc_QtViewportInteractionEngine.cpp" + +} diff --git a/Source/WebKit2/UIProcess/qt/QtViewportInteractionEngine.h b/Source/WebKit2/UIProcess/qt/QtViewportInteractionEngine.h new file mode 100644 index 000000000..68377a41c --- /dev/null +++ b/Source/WebKit2/UIProcess/qt/QtViewportInteractionEngine.h @@ -0,0 +1,171 @@ +/* + * Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies) + * Copyright (C) 2011 Benjamin Poulain <benjamin@webkit.org> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this program; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + */ + +#ifndef QtViewportInteractionEngine_h +#define QtViewportInteractionEngine_h + +#include "OwnPtr.h" +#include <QScroller> +#include "qwebkitglobal.h" +#include <QtCore/QObject> +#include <QtCore/QRectF> +#include <QtCore/QVariant> +#include <QtCore/QVariantAnimation> + +QT_BEGIN_NAMESPACE +class QPointF; +class QQuickItem; +class QWheelEvent; +QT_END_NAMESPACE + +namespace WebKit { + +class ViewportUpdateDeferrer; + +class QtViewportInteractionEngine : public QObject { + Q_OBJECT + +public: + QtViewportInteractionEngine(const QQuickItem*, QQuickItem*); + ~QtViewportInteractionEngine(); + + struct Constraints { + Constraints() + : initialScale(1.0) + , minimumScale(0.25) + , maximumScale(1.8) + , devicePixelRatio(1.0) + , isUserScalable(true) + , layoutSize(QSize()) + { } + + qreal initialScale; + qreal minimumScale; + qreal maximumScale; + qreal devicePixelRatio; + bool isUserScalable; + QSize layoutSize; + }; + + bool event(QEvent*); + + void reset(); + void applyConstraints(const Constraints&); + + void setItemRectVisible(const QRectF&); + bool animateItemRectVisible(const QRectF&); + + void wheelEvent(QWheelEvent*); + void pagePositionRequest(const QPoint& pos); + + bool scrollAnimationActive() const; + void interruptScrollAnimation(); + + bool panGestureActive() const; + void panGestureStarted(const QPointF& touchPoint, qint64 eventTimestampMillis); + void panGestureRequestUpdate(const QPointF& touchPoint, qint64 eventTimestampMillis); + void panGestureCancelled(); + void panGestureEnded(const QPointF& touchPoint, qint64 eventTimestampMillis); + + bool scaleAnimationActive() const; + void interruptScaleAnimation(); + + bool pinchGestureActive() const; + void pinchGestureStarted(const QPointF& pinchCenterInContentCoordinates); + void pinchGestureRequestUpdate(const QPointF& pinchCenterInContentCoordinates, qreal totalScaleFactor); + void pinchGestureEnded(); + + void zoomToAreaGestureEnded(const QPointF& touchPoint, const QRectF& targetArea); + void focusEditableArea(const QRectF& caretArea, const QRectF& targetArea); + + const Constraints& constraints() const { return m_constraints; } + qreal currentCSSScale(); + +Q_SIGNALS: + void contentSuspendRequested(); + void contentResumeRequested(); + + void viewportTrajectoryVectorChanged(const QPointF&); + +private Q_SLOTS: + // Respond to changes of content that are not driven by us, like the page resizing itself. + void itemSizeChanged(); + + void scrollStateChanged(QScroller::State); + void scaleAnimationStateChanged(QAbstractAnimation::State, QAbstractAnimation::State); + void scaleAnimationValueChanged(QVariant value) { setItemRectVisible(value.toRectF()); } + +private: + friend class ViewportUpdateDeferrer; + + qreal cssScaleFromItem(qreal); + qreal itemScaleFromCSS(qreal); + qreal itemCoordFromCSS(qreal); + QRectF itemRectFromCSS(const QRectF&); + + qreal innerBoundedCSSScale(qreal); + qreal outerBoundedCSSScale(qreal); + + QRectF computePosRangeForItemAtScale(qreal itemScale) const; + bool ensureContentWithinViewportBoundary(bool immediate = false); + + void scaleContent(const QPointF& centerInContentCoordinates, qreal scale); + + // As long as the object exists this function will always return the same QScroller instance. + QScroller* scroller() { return QScroller::scroller(this); } + + + const QQuickItem* const m_viewport; + QQuickItem* const m_content; + + Constraints m_constraints; + + int m_suspendCount; + OwnPtr<ViewportUpdateDeferrer> m_scaleUpdateDeferrer; + OwnPtr<ViewportUpdateDeferrer> m_scrollUpdateDeferrer; + + bool m_hadUserInteraction; + + class ScaleAnimation : public QVariantAnimation { + public: + ScaleAnimation(QObject* parent = 0) + : QVariantAnimation(parent) + { } + + virtual void updateCurrentValue(const QVariant&) { } + }; + + ScaleAnimation* m_scaleAnimation; + QPointF m_lastPinchCenterInViewportCoordinates; + qreal m_pinchStartScale; +}; + +inline bool operator==(const QtViewportInteractionEngine::Constraints& a, const QtViewportInteractionEngine::Constraints& b) +{ + return a.initialScale == b.initialScale + && a.minimumScale == b.minimumScale + && a.maximumScale == b.maximumScale + && a.isUserScalable == b.isUserScalable; +} + +} + +#endif // QtViewportInteractionEngine_h diff --git a/Source/WebKit2/UIProcess/qt/QtWebContext.cpp b/Source/WebKit2/UIProcess/qt/QtWebContext.cpp new file mode 100644 index 000000000..29a547ba9 --- /dev/null +++ b/Source/WebKit2/UIProcess/qt/QtWebContext.cpp @@ -0,0 +1,157 @@ +/* + * Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this program; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + */ + +#include "config.h" +#include "QtWebContext.h" + +#include "MutableArray.h" +#include "QtDownloadManager.h" +#include "QtWebIconDatabaseClient.h" +#include "WKAPICast.h" +#include "WebContext.h" +#include "WebPageProxy.h" +#include <WKArray.h> +#include <WKPage.h> +#include <WKString.h> +#include <WKType.h> + +namespace WebKit { + +static uint64_t generateContextID() +{ + static uint64_t uniqueContextID = 1; + return uniqueContextID++; +} + +static HashMap<uint64_t, QtWebContext*> contextMap; + +QtWebContext* QtWebContext::s_defaultContext = 0; + +QtWebContext::QtWebContext(WebContext* context) + : m_context(context) +{ + m_contextID = generateContextID(); + contextMap.set(m_contextID, this); +} + +QtWebContext::~QtWebContext() +{ + if (s_defaultContext == this) + s_defaultContext = 0; + contextMap.remove(m_contextID); +} + +// Used only by WebKitTestRunner. It avoids calling initialize(), so that we don't register any clients. +PassRefPtr<QtWebContext> QtWebContext::create(WebContext* context) +{ + return adoptRef(new QtWebContext(context)); +} + +PassRefPtr<QtWebContext> QtWebContext::defaultContext() +{ + if (s_defaultContext) + return PassRefPtr<QtWebContext>(s_defaultContext); + + RefPtr<WebContext> context = WebContext::create(String()); + RefPtr<QtWebContext> defaultContext = QtWebContext::create(context.get()); + s_defaultContext = defaultContext.get(); + defaultContext->initialize(); + + return defaultContext.release(); +} + +PassRefPtr<WebPageProxy> QtWebContext::createWebPage(PageClient* client, WebPageGroup* pageGroup) +{ + return m_context->createWebPage(client, pageGroup); +} + +void QtWebContext::setNavigatorQtObjectEnabled(WebPageProxy* webPageProxy, bool enabled) +{ + static String messageName("SetNavigatorQtObjectEnabled"); + RefPtr<MutableArray> body = MutableArray::create(); + body->append(webPageProxy); + RefPtr<WebBoolean> webEnabled = WebBoolean::create(enabled); + body->append(webEnabled.get()); + m_context->postMessageToInjectedBundle(messageName, body.get()); +} + +void QtWebContext::postMessageToNavigatorQtObject(WebPageProxy* webPageProxy, const QString& message) +{ + static String messageName("MessageToNavigatorQtObject"); + RefPtr<MutableArray> body = MutableArray::create(); + body->append(webPageProxy); + RefPtr<WebString> contents = WebString::create(String(message)); + body->append(contents.get()); + m_context->postMessageToInjectedBundle(messageName, body.get()); +} + +QtWebContext* QtWebContext::contextByID(uint64_t id) +{ + return contextMap.get(id); +} + +void QtWebContext::initialize() +{ + m_downloadManager = adoptPtr(new QtDownloadManager(m_context.get())); + m_iconDatabase = adoptPtr(new QtWebIconDatabaseClient(this)); + initializeContextInjectedBundleClient(); +} + +void QtWebContext::initializeContextInjectedBundleClient() +{ + WKContextInjectedBundleClient injectedBundleClient; + memset(&injectedBundleClient, 0, sizeof(WKContextInjectedBundleClient)); + injectedBundleClient.version = kWKContextInjectedBundleClientCurrentVersion; + injectedBundleClient.clientInfo = this; + injectedBundleClient.didReceiveMessageFromInjectedBundle = didReceiveMessageFromInjectedBundle; + WKContextSetInjectedBundleClient(toAPI(m_context.get()), &injectedBundleClient); +} + +static QtWebContext* toQtWebContext(const void* clientInfo) +{ + ASSERT(clientInfo); + return reinterpret_cast<QtWebContext*>(const_cast<void*>(clientInfo)); +} + +void QtWebContext::didReceiveMessageFromInjectedBundle(WKContextRef, WKStringRef messageName, WKTypeRef messageBody, const void* clientInfo) +{ + toQtWebContext(clientInfo)->didReceiveMessageFromInjectedBundle(messageName, messageBody); +} + +void QtWebContext::didReceiveMessageFromInjectedBundle(WKStringRef messageName, WKTypeRef messageBody) +{ + if (!WKStringIsEqualToUTF8CString(messageName, "MessageFromNavigatorQtObject")) + return; + + ASSERT(messageBody); + ASSERT(WKGetTypeID(messageBody) == WKArrayGetTypeID()); + + WKArrayRef body = static_cast<WKArrayRef>(messageBody); + ASSERT(WKArrayGetSize(body) == 2); + ASSERT(WKGetTypeID(WKArrayGetItemAtIndex(body, 0)) == WKPageGetTypeID()); + ASSERT(WKGetTypeID(WKArrayGetItemAtIndex(body, 1)) == WKStringGetTypeID()); + + WKPageRef page = static_cast<WKPageRef>(WKArrayGetItemAtIndex(body, 0)); + WKStringRef str = static_cast<WKStringRef>(WKArrayGetItemAtIndex(body, 1)); + + toImpl(page)->didReceiveMessageFromNavigatorQtObject(toImpl(str)->string()); +} + +} diff --git a/Source/WebKit2/UIProcess/qt/QtWebContext.h b/Source/WebKit2/UIProcess/qt/QtWebContext.h new file mode 100644 index 000000000..202db2242 --- /dev/null +++ b/Source/WebKit2/UIProcess/qt/QtWebContext.h @@ -0,0 +1,82 @@ +/* + * Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this program; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + */ + +#ifndef QtWebContext_h +#define QtWebContext_h + +#include <WKContext.h> +#include <wtf/OwnPtr.h> +#include <wtf/RefCounted.h> +#include <wtf/RefPtr.h> +#include <qglobal.h> + +QT_BEGIN_NAMESPACE +class QString; +QT_END_NAMESPACE + +namespace WebKit { + +class PageClient; +class QtDownloadManager; +class QtWebIconDatabaseClient; +class WebContext; +class WebPageGroup; +class WebPageProxy; + +class QtWebContext : public RefCounted<QtWebContext> { +public: + ~QtWebContext(); + + static PassRefPtr<QtWebContext> create(WebContext*); + static PassRefPtr<QtWebContext> defaultContext(); + + PassRefPtr<WebPageProxy> createWebPage(PageClient*, WebPageGroup*); + + WebContext* context() { return m_context.get(); } + QtDownloadManager* downloadManager() { return m_downloadManager.get(); } + QtWebIconDatabaseClient* iconDatabase() { return m_iconDatabase.get(); } + + void setNavigatorQtObjectEnabled(WebPageProxy*, bool); + void postMessageToNavigatorQtObject(WebPageProxy*, const QString&); + + uint64_t contextID() const { return m_contextID; } + + static QtWebContext* contextByID(uint64_t id); + +private: + explicit QtWebContext(WebContext*); + + void initialize(); + void initializeContextInjectedBundleClient(); + + static void didReceiveMessageFromInjectedBundle(WKContextRef, WKStringRef messageName, WKTypeRef messageBody, const void*); + void didReceiveMessageFromInjectedBundle(WKStringRef messageName, WKTypeRef messageBody); + + static QtWebContext* s_defaultContext; + + uint64_t m_contextID; + RefPtr<WebContext> m_context; + OwnPtr<QtDownloadManager> m_downloadManager; + OwnPtr<QtWebIconDatabaseClient> m_iconDatabase; +}; + +} + +#endif // QtWebContext_h diff --git a/Source/WebKit2/UIProcess/qt/QtWebError.cpp b/Source/WebKit2/UIProcess/qt/QtWebError.cpp new file mode 100644 index 000000000..d5b1cbd1b --- /dev/null +++ b/Source/WebKit2/UIProcess/qt/QtWebError.cpp @@ -0,0 +1,67 @@ +/* + * Copyright (C) 2011 Andreas Kling <kling@webkit.org> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this program; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + */ + +#include "config.h" +#include "QtWebError.h" + +#include <QtCore/QUrl> +#include <WKSharedAPICast.h> +#include <WKString.h> +#include <WKStringQt.h> +#include <WKType.h> +#include <WKURL.h> +#include <WKURLQt.h> + +using namespace WebKit; + +QtWebError::QtWebError(WKErrorRef errorRef) + : error(errorRef) +{ +} + +QtWebError::Type QtWebError::type() const +{ + WKRetainPtr<WKStringRef> errorDomainPtr = adoptWK(WKErrorCopyDomain(error.get())); + WTF::String errorDomain = toWTFString(errorDomainPtr.get()); + + if (errorDomain == "QtNetwork") + return QtWebError::NetworkError; + if (errorDomain == "HTTP") + return QtWebError::HttpError; + if (errorDomain == "Download") + return QtWebError::DownloadError; + return QtWebError::InternalError; +} + +int QtWebError::errorCode() const +{ + return WKErrorGetErrorCode(error.get()); +} + +QUrl QtWebError::url() const +{ + WKRetainPtr<WKURLRef> failingURL = adoptWK(WKErrorCopyFailingURL(error.get())); + return WKURLCopyQUrl(failingURL.get()); +} + +QString QtWebError::description() const +{ + return WKStringCopyQString(WKErrorCopyLocalizedDescription(error.get())); +} diff --git a/Source/WebKit2/UIProcess/qt/QtWebError.h b/Source/WebKit2/UIProcess/qt/QtWebError.h new file mode 100644 index 000000000..3bd7bd508 --- /dev/null +++ b/Source/WebKit2/UIProcess/qt/QtWebError.h @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2011 Andreas Kling <kling@webkit.org> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this program; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + */ + +#ifndef QtWebError_h +#define QtWebError_h + +#include "qwebdownloaditem_p.h" +#include "qwebkitglobal.h" +#include <QtNetwork/QNetworkReply> +#include <WKError.h> +#include <WKRetainPtr.h> + +QT_BEGIN_NAMESPACE +class QUrl; +QT_END_NAMESPACE + +class QtWebError { +public: + enum Type { + InternalError, + NetworkError, + HttpError, + DownloadError + }; + + Type type() const; + QUrl url() const; + int errorCode() const; + QString description() const; + + int errorCodeAsHttpStatusCode() const { return errorCode(); } + QNetworkReply::NetworkError errorCodeAsNetworkError() const { return static_cast<QNetworkReply::NetworkError>(errorCode()); } + QWebDownloadItem::DownloadError errorCodeAsDownloadError() const { return static_cast<QWebDownloadItem::DownloadError>(errorCode()); } + + QtWebError(const QtWebError&); + + QtWebError(WKErrorRef); + +private: + WKRetainPtr<WKErrorRef> error; +}; + +#endif /* QtWebError_h */ diff --git a/Source/WebKit2/UIProcess/qt/QtWebIconDatabaseClient.cpp b/Source/WebKit2/UIProcess/qt/QtWebIconDatabaseClient.cpp new file mode 100644 index 000000000..8b09b20f3 --- /dev/null +++ b/Source/WebKit2/UIProcess/qt/QtWebIconDatabaseClient.cpp @@ -0,0 +1,122 @@ +/* + Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#include "config.h" +#include "QtWebIconDatabaseClient.h" + +#include "Image.h" +#include "KURL.h" +#include "QtWebContext.h" +#include "SharedBuffer.h" +#include "WKURLQt.h" +#include "WebContext.h" +#include "WebIconDatabase.h" +#include <QtCore/QHash> +#include <QtCore/QObject> +#include <QtCore/QUrl> +#include <QtGui/QImage> + +using namespace WebKit; + +static inline QtWebIconDatabaseClient* toQtWebIconDatabaseClient(const void* clientInfo) +{ + ASSERT(clientInfo); + return reinterpret_cast<QtWebIconDatabaseClient*>(const_cast<void*>(clientInfo)); +} + +QtWebIconDatabaseClient::QtWebIconDatabaseClient(QtWebContext *qtWebContext) +{ + m_contextId = qtWebContext->contextID(); + // The setter calls the getter here as it triggers the startup of the icon database. + WebContext* context = qtWebContext->context(); + context->setIconDatabasePath(context->iconDatabasePath()); + m_iconDatabase = context->iconDatabase(); + + WKIconDatabaseClient iconDatabaseClient; + memset(&iconDatabaseClient, 0, sizeof(WKIconDatabaseClient)); + iconDatabaseClient.version = kWKIconDatabaseClientCurrentVersion; + iconDatabaseClient.clientInfo = this; + iconDatabaseClient.didChangeIconForPageURL = didChangeIconForPageURL; + WKIconDatabaseSetIconDatabaseClient(toAPI(m_iconDatabase), &iconDatabaseClient); +} + +QtWebIconDatabaseClient::~QtWebIconDatabaseClient() +{ +} + +void QtWebIconDatabaseClient::didChangeIconForPageURL(WKIconDatabaseRef iconDatabase, WKURLRef pageURL, const void* clientInfo) +{ + QUrl qUrl = WKURLCopyQUrl(pageURL); + toQtWebIconDatabaseClient(clientInfo)->requestIconForPageURL(qUrl); +} + +QImage QtWebIconDatabaseClient::iconImageForPageURL(const String& pageURL, const QSize& iconSize) +{ + MutexLocker locker(m_imageLock); + + WebCore::IntSize size(iconSize.width(), iconSize.height()); + RefPtr<WebCore::Image> image = m_iconDatabase->imageForPageURL(pageURL, size); + if (!image) + return QImage(); + + QPixmap* nativeImage = image->nativeImageForCurrentFrame(); + if (!nativeImage) + return QImage(); + + return nativeImage->toImage(); +} + +unsigned QtWebIconDatabaseClient::iconURLHashForPageURL(const String& pageURL) +{ + String iconURL; + m_iconDatabase->synchronousIconURLForPageURL(pageURL, iconURL); + return StringHash::hash(iconURL); +} + +void QtWebIconDatabaseClient::requestIconForPageURL(const QUrl& pageURL) +{ + String pageURLString = WebCore::KURL(pageURL).string(); + if (iconImageForPageURL(pageURLString).isNull()) + return; + + unsigned iconID = iconURLHashForPageURL(pageURLString); + QUrl url; + url.setScheme(QStringLiteral("image")); + url.setHost(QStringLiteral("webicon")); + QString path; + path.append(QLatin1Char('/')); + path.append(QString::number(m_contextId)); + path.append(QLatin1Char('/')); + path.append(QString::number(iconID)); + url.setPath(path); + url.setEncodedFragment(pageURL.toEncoded()); + emit iconChangedForPageURL(pageURL, url); +} + +void QtWebIconDatabaseClient::retainIconForPageURL(const String& pageURL) +{ + m_iconDatabase->retainIconForPageURL(pageURL); +} + +void QtWebIconDatabaseClient::releaseIconForPageURL(const String& pageURL) +{ + m_iconDatabase->releaseIconForPageURL(pageURL); +} + +#include "moc_QtWebIconDatabaseClient.cpp" diff --git a/Source/WebKit2/UIProcess/qt/QtWebIconDatabaseClient.h b/Source/WebKit2/UIProcess/qt/QtWebIconDatabaseClient.h new file mode 100644 index 000000000..e8d056248 --- /dev/null +++ b/Source/WebKit2/UIProcess/qt/QtWebIconDatabaseClient.h @@ -0,0 +1,67 @@ +/* + Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + + +#ifndef QtWebIconDatabaseClient_h +#define QtWebIconDatabaseClient_h + +#include "WKIconDatabase.h" +#include "qwebkitglobal.h" +#include <QtCore/QObject> +#include <QtCore/QSize> +#include <wtf/Threading.h> +#include <wtf/text/WTFString.h> + +QT_BEGIN_NAMESPACE +class QImage; +class QUrl; +QT_END_NAMESPACE + +namespace WebKit { +class QtWebContext; +class WebIconDatabase; + +class QtWebIconDatabaseClient : public QObject { + Q_OBJECT + +public: + QtWebIconDatabaseClient(QtWebContext*); + ~QtWebIconDatabaseClient(); + + QImage iconImageForPageURL(const String& pageURL, const QSize& iconSize = QSize(32, 32)); + void retainIconForPageURL(const String&); + void releaseIconForPageURL(const String&); + +public Q_SLOTS: + void requestIconForPageURL(const QUrl&); + +public: + Q_SIGNAL void iconChangedForPageURL(const QUrl& pageURL, const QUrl& iconURL); + +private: + unsigned iconURLHashForPageURL(const String&); + static void didChangeIconForPageURL(WKIconDatabaseRef, WKURLRef pageURL, const void* clientInfo); + uint64_t m_contextId; + WebKit::WebIconDatabase* m_iconDatabase; + Mutex m_imageLock; +}; + +} + +#endif diff --git a/Source/WebKit2/UIProcess/qt/QtWebPageEventHandler.cpp b/Source/WebKit2/UIProcess/qt/QtWebPageEventHandler.cpp new file mode 100644 index 000000000..d0196880d --- /dev/null +++ b/Source/WebKit2/UIProcess/qt/QtWebPageEventHandler.cpp @@ -0,0 +1,500 @@ +/* + * Copyright (C) 2010, 2011 Nokia Corporation and/or its subsidiary(-ies) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this program; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + */ + +#include "config.h" +#include "QtWebPageEventHandler.h" + +#include "NativeWebKeyboardEvent.h" +#include "NativeWebMouseEvent.h" +#include "NativeWebWheelEvent.h" +#include "QtViewportInteractionEngine.h" +#include "qquickwebpage_p.h" +#include <QDrag> +#include <QGraphicsSceneMouseEvent> +#include <QGuiApplication> +#include <QMimeData> +#include <QtQuick/QQuickCanvas> +#include <QStyleHints> +#include <QTextFormat> +#include <QTouchEvent> +#include <WebCore/DragData.h> +#include <WebCore/Editor.h> + +using namespace WebKit; +using namespace WebCore; + +static inline Qt::DropAction dragOperationToDropAction(unsigned dragOperation) +{ + Qt::DropAction result = Qt::IgnoreAction; + if (dragOperation & DragOperationCopy) + result = Qt::CopyAction; + else if (dragOperation & DragOperationMove) + result = Qt::MoveAction; + else if (dragOperation & DragOperationGeneric) + result = Qt::MoveAction; + else if (dragOperation & DragOperationLink) + result = Qt::LinkAction; + return result; +} + +static inline Qt::DropActions dragOperationToDropActions(unsigned dragOperations) +{ + Qt::DropActions result = Qt::IgnoreAction; + if (dragOperations & DragOperationCopy) + result |= Qt::CopyAction; + if (dragOperations & DragOperationMove) + result |= Qt::MoveAction; + if (dragOperations & DragOperationGeneric) + result |= Qt::MoveAction; + if (dragOperations & DragOperationLink) + result |= Qt::LinkAction; + return result; +} + +static inline WebCore::DragOperation dropActionToDragOperation(Qt::DropActions actions) +{ + unsigned result = 0; + if (actions & Qt::CopyAction) + result |= DragOperationCopy; + if (actions & Qt::MoveAction) + result |= (DragOperationMove | DragOperationGeneric); + if (actions & Qt::LinkAction) + result |= DragOperationLink; + if (result == (DragOperationCopy | DragOperationMove | DragOperationGeneric | DragOperationLink)) + result = DragOperationEvery; + return (DragOperation)result; +} + +QtWebPageEventHandler::QtWebPageEventHandler(WKPageRef pageRef, QQuickWebPage* qmlWebPage) + : m_webPageProxy(toImpl(pageRef)) + , m_panGestureRecognizer(this) + , m_pinchGestureRecognizer(this) + , m_tapGestureRecognizer(this) + , m_webPage(qmlWebPage) + , m_previousClickButton(Qt::NoButton) + , m_clickCount(0) +{ +} + +QtWebPageEventHandler::~QtWebPageEventHandler() +{ +} + +bool QtWebPageEventHandler::handleEvent(QEvent* ev) +{ + switch (ev->type()) { + case QEvent::MouseMove: + return handleMouseMoveEvent(static_cast<QMouseEvent*>(ev)); + case QEvent::MouseButtonPress: + case QEvent::MouseButtonDblClick: + // If a MouseButtonDblClick was received then we got a MouseButtonPress before + // handleMousePressEvent will take care of double clicks. + return handleMousePressEvent(static_cast<QMouseEvent*>(ev)); + case QEvent::MouseButtonRelease: + return handleMouseReleaseEvent(static_cast<QMouseEvent*>(ev)); + case QEvent::Wheel: + return handleWheelEvent(static_cast<QWheelEvent*>(ev)); + case QEvent::HoverLeave: + return handleHoverLeaveEvent(static_cast<QHoverEvent*>(ev)); + case QEvent::HoverEnter: // Fall-through, for WebKit the distinction doesn't matter. + case QEvent::HoverMove: + return handleHoverMoveEvent(static_cast<QHoverEvent*>(ev)); + case QEvent::DragEnter: + return handleDragEnterEvent(static_cast<QDragEnterEvent*>(ev)); + case QEvent::DragLeave: + return handleDragLeaveEvent(static_cast<QDragLeaveEvent*>(ev)); + case QEvent::DragMove: + return handleDragMoveEvent(static_cast<QDragMoveEvent*>(ev)); + case QEvent::Drop: + return handleDropEvent(static_cast<QDropEvent*>(ev)); + case QEvent::KeyPress: + return handleKeyPressEvent(static_cast<QKeyEvent*>(ev)); + case QEvent::KeyRelease: + return handleKeyReleaseEvent(static_cast<QKeyEvent*>(ev)); + case QEvent::FocusIn: + return handleFocusInEvent(static_cast<QFocusEvent*>(ev)); + case QEvent::FocusOut: + return handleFocusOutEvent(static_cast<QFocusEvent*>(ev)); + case QEvent::TouchBegin: + case QEvent::TouchEnd: + case QEvent::TouchUpdate: + touchEvent(static_cast<QTouchEvent*>(ev)); + return true; + case QEvent::InputMethod: + inputMethodEvent(static_cast<QInputMethodEvent*>(ev)); + return false; // Look at comment in qquickwebpage.cpp + } + + // FIXME: Move all common event handling here. + return false; +} + +bool QtWebPageEventHandler::handleMouseMoveEvent(QMouseEvent* ev) +{ + // For some reason mouse press results in mouse hover (which is + // converted to mouse move for WebKit). We ignore these hover + // events by comparing lastPos with newPos. + // NOTE: lastPos from the event always comes empty, so we work + // around that here. + static QPointF lastPos = QPointF(); + if (lastPos == ev->pos()) + return ev->isAccepted(); + lastPos = ev->pos(); + + m_webPageProxy->handleMouseEvent(NativeWebMouseEvent(ev, /*eventClickCount*/ 0)); + + return ev->isAccepted(); +} + +bool QtWebPageEventHandler::handleMousePressEvent(QMouseEvent* ev) +{ + if (m_clickTimer.isActive() + && m_previousClickButton == ev->button() + && (ev->pos() - m_lastClick).manhattanLength() < qApp->styleHints()->startDragDistance()) { + m_clickCount++; + } else { + m_clickCount = 1; + m_previousClickButton = ev->button(); + } + + m_webPageProxy->handleMouseEvent(NativeWebMouseEvent(ev, m_clickCount)); + + m_lastClick = ev->pos(); + m_clickTimer.start(qApp->styleHints()->mouseDoubleClickInterval(), this); + return ev->isAccepted(); +} + +bool QtWebPageEventHandler::handleMouseReleaseEvent(QMouseEvent* ev) +{ + m_webPageProxy->handleMouseEvent(NativeWebMouseEvent(ev, /*eventClickCount*/ 0)); + return ev->isAccepted(); +} + +bool QtWebPageEventHandler::handleWheelEvent(QWheelEvent* ev) +{ + m_webPageProxy->handleWheelEvent(NativeWebWheelEvent(ev)); + // FIXME: Handle whether the page used the wheel event or not. + if (m_interactionEngine) + m_interactionEngine->wheelEvent(ev); + return ev->isAccepted(); +} + +bool QtWebPageEventHandler::handleHoverLeaveEvent(QHoverEvent* ev) +{ + // To get the correct behavior of mouseout, we need to turn the Leave event of our webview into a mouse move + // to a very far region. + QHoverEvent fakeEvent(QEvent::HoverMove, QPoint(INT_MIN, INT_MIN), ev->oldPos()); + fakeEvent.setTimestamp(ev->timestamp()); + return handleHoverMoveEvent(&fakeEvent); +} + +bool QtWebPageEventHandler::handleHoverMoveEvent(QHoverEvent* ev) +{ + QMouseEvent me(QEvent::MouseMove, ev->pos(), Qt::NoButton, Qt::NoButton, Qt::NoModifier); + me.setAccepted(ev->isAccepted()); + me.setTimestamp(ev->timestamp()); + + return handleMouseMoveEvent(&me); +} + +bool QtWebPageEventHandler::handleDragEnterEvent(QDragEnterEvent* ev) +{ + m_webPageProxy->resetDragOperation(); + // FIXME: Should not use QCursor::pos() + DragData dragData(ev->mimeData(), ev->pos(), QCursor::pos(), dropActionToDragOperation(ev->possibleActions())); + m_webPageProxy->dragEntered(&dragData); + ev->acceptProposedAction(); + return true; +} + +bool QtWebPageEventHandler::handleDragLeaveEvent(QDragLeaveEvent* ev) +{ + bool accepted = ev->isAccepted(); + + // FIXME: Should not use QCursor::pos() + DragData dragData(0, IntPoint(), QCursor::pos(), DragOperationNone); + m_webPageProxy->dragExited(&dragData); + m_webPageProxy->resetDragOperation(); + + ev->setAccepted(accepted); + return accepted; +} + +bool QtWebPageEventHandler::handleDragMoveEvent(QDragMoveEvent* ev) +{ + bool accepted = ev->isAccepted(); + + // FIXME: Should not use QCursor::pos() + DragData dragData(ev->mimeData(), ev->pos(), QCursor::pos(), dropActionToDragOperation(ev->possibleActions())); + m_webPageProxy->dragUpdated(&dragData); + ev->setDropAction(dragOperationToDropAction(m_webPageProxy->dragSession().operation)); + if (m_webPageProxy->dragSession().operation != DragOperationNone) + ev->accept(); + + ev->setAccepted(accepted); + return accepted; +} + +bool QtWebPageEventHandler::handleDropEvent(QDropEvent* ev) +{ + bool accepted = ev->isAccepted(); + + // FIXME: Should not use QCursor::pos() + DragData dragData(ev->mimeData(), ev->pos(), QCursor::pos(), dropActionToDragOperation(ev->possibleActions())); + SandboxExtension::Handle handle; + m_webPageProxy->performDrag(&dragData, String(), handle); + ev->setDropAction(dragOperationToDropAction(m_webPageProxy->dragSession().operation)); + ev->accept(); + + ev->setAccepted(accepted); + return accepted; +} + +void QtWebPageEventHandler::handleSingleTapEvent(const QTouchEvent::TouchPoint& point) +{ + WebGestureEvent gesture(WebEvent::GestureSingleTap, point.pos().toPoint(), point.screenPos().toPoint(), WebEvent::Modifiers(0), 0); + m_webPageProxy->handleGestureEvent(gesture); +} + +void QtWebPageEventHandler::handleDoubleTapEvent(const QTouchEvent::TouchPoint& point) +{ + m_webPageProxy->findZoomableAreaForPoint(point.pos().toPoint()); +} + +void QtWebPageEventHandler::timerEvent(QTimerEvent* ev) +{ + int timerId = ev->timerId(); + if (timerId == m_clickTimer.timerId()) + m_clickTimer.stop(); + else + QObject::timerEvent(ev); +} + +bool QtWebPageEventHandler::handleKeyPressEvent(QKeyEvent* ev) +{ + m_webPageProxy->handleKeyboardEvent(NativeWebKeyboardEvent(ev)); + return true; +} + +bool QtWebPageEventHandler::handleKeyReleaseEvent(QKeyEvent* ev) +{ + m_webPageProxy->handleKeyboardEvent(NativeWebKeyboardEvent(ev)); + return true; +} + +bool QtWebPageEventHandler::handleFocusInEvent(QFocusEvent*) +{ + m_webPageProxy->viewStateDidChange(WebPageProxy::ViewIsFocused | WebPageProxy::ViewWindowIsActive); + return true; +} + +bool QtWebPageEventHandler::handleFocusOutEvent(QFocusEvent*) +{ + m_webPageProxy->viewStateDidChange(WebPageProxy::ViewIsFocused | WebPageProxy::ViewWindowIsActive); + return true; +} + +void QtWebPageEventHandler::setViewportInteractionEngine(QtViewportInteractionEngine* engine) +{ + m_interactionEngine = engine; +} + +void QtWebPageEventHandler::inputMethodEvent(QInputMethodEvent* ev) +{ + QString commit = ev->commitString(); + QString composition = ev->preeditString(); + + int replacementStart = ev->replacementStart(); + int replacementLength = ev->replacementLength(); + + // NOTE: We might want to handle events of one char as special + // and resend them as key events to make web site completion work. + + int cursorPositionWithinComposition = 0; + + Vector<CompositionUnderline> underlines; + + for (int i = 0; i < ev->attributes().size(); ++i) { + const QInputMethodEvent::Attribute& attr = ev->attributes().at(i); + switch (attr.type) { + case QInputMethodEvent::TextFormat: { + if (composition.isEmpty()) + break; + + QTextCharFormat textCharFormat = attr.value.value<QTextFormat>().toCharFormat(); + QColor qcolor = textCharFormat.underlineColor(); + Color color = makeRGBA(qcolor.red(), qcolor.green(), qcolor.blue(), qcolor.alpha()); + int start = qMin(attr.start, (attr.start + attr.length)); + int end = qMax(attr.start, (attr.start + attr.length)); + underlines.append(CompositionUnderline(start, end, color, false)); + break; + } + case QInputMethodEvent::Cursor: + if (attr.length) + cursorPositionWithinComposition = attr.start; + break; + // Selection is handled further down. + default: break; + } + } + + if (composition.isEmpty()) { + int selectionStart = -1; + int selectionLength = 0; + for (int i = 0; i < ev->attributes().size(); ++i) { + const QInputMethodEvent::Attribute& attr = ev->attributes().at(i); + if (attr.type == QInputMethodEvent::Selection) { + selectionStart = attr.start; + selectionLength = attr.length; + + ASSERT(selectionStart >= 0); + ASSERT(selectionLength >= 0); + break; + } + } + + m_webPageProxy->confirmComposition(commit, selectionStart, selectionLength); + } else { + ASSERT(cursorPositionWithinComposition >= 0); + ASSERT(replacementStart >= 0); + + m_webPageProxy->setComposition(composition, underlines, + cursorPositionWithinComposition, cursorPositionWithinComposition, + replacementStart, replacementLength); + } + + ev->accept(); +} + +void QtWebPageEventHandler::touchEvent(QTouchEvent* event) +{ +#if ENABLE(TOUCH_EVENTS) + m_webPageProxy->handleTouchEvent(NativeWebTouchEvent(event)); + event->accept(); +#else + ASSERT_NOT_REACHED(); + ev->ignore(); +#endif +} + +void QtWebPageEventHandler::resetGestureRecognizers() +{ + m_panGestureRecognizer.reset(); + m_pinchGestureRecognizer.reset(); + m_tapGestureRecognizer.reset(); +} + +void QtWebPageEventHandler::doneWithTouchEvent(const NativeWebTouchEvent& event, bool wasEventHandled) +{ + if (!m_interactionEngine) + return; + + if (wasEventHandled || event.type() == WebEvent::TouchCancel) { + resetGestureRecognizers(); + return; + } + + const QTouchEvent* ev = event.nativeEvent(); + + switch (ev->type()) { + case QEvent::TouchBegin: + ASSERT(!m_interactionEngine->panGestureActive()); + ASSERT(!m_interactionEngine->pinchGestureActive()); + + // The interaction engine might still be animating kinetic scrolling or a scale animation + // such as double-tap to zoom or the bounce back effect. A touch stops the kinetic scrolling + // where as it does not stop the scale animation. + if (m_interactionEngine->scrollAnimationActive()) + m_interactionEngine->interruptScrollAnimation(); + break; + case QEvent::TouchUpdate: + // The scale animation can only be interrupted by a pinch gesture, which will then take over. + if (m_interactionEngine->scaleAnimationActive() && m_pinchGestureRecognizer.isRecognized()) + m_interactionEngine->interruptScaleAnimation(); + break; + default: + break; + } + + // If the scale animation is active we don't pass the event to the recognizers. In the future + // we would want to queue the event here and repost then when the animation ends. + if (m_interactionEngine->scaleAnimationActive()) + return; + + // Convert the event timestamp from second to millisecond. + qint64 eventTimestampMillis = static_cast<qint64>(event.timestamp() * 1000); + m_panGestureRecognizer.recognize(ev, eventTimestampMillis); + m_pinchGestureRecognizer.recognize(ev); + + if (m_panGestureRecognizer.isRecognized() || m_pinchGestureRecognizer.isRecognized()) + m_tapGestureRecognizer.reset(); + else { + const QTouchEvent* ev = event.nativeEvent(); + m_tapGestureRecognizer.recognize(ev, eventTimestampMillis); + } +} + +void QtWebPageEventHandler::didFindZoomableArea(const IntPoint& target, const IntRect& area) +{ + if (!m_interactionEngine) + return; + + // FIXME: As the find method might not respond immediately during load etc, + // we should ignore all but the latest request. + m_interactionEngine->zoomToAreaGestureEnded(QPointF(target), QRectF(area)); +} + +void QtWebPageEventHandler::focusEditableArea(const IntRect& caret, const IntRect& area) +{ + if (!m_interactionEngine) + return; + + m_interactionEngine->focusEditableArea(QRectF(caret), QRectF(area)); +} + +void QtWebPageEventHandler::startDrag(const WebCore::DragData& dragData, PassRefPtr<ShareableBitmap> dragImage) +{ + QImage dragQImage; + if (dragImage) + dragQImage = dragImage->createQImage(); + else if (dragData.platformData() && dragData.platformData()->hasImage()) + dragQImage = qvariant_cast<QImage>(dragData.platformData()->imageData()); + + DragOperation dragOperationMask = dragData.draggingSourceOperationMask(); + QMimeData* mimeData = const_cast<QMimeData*>(dragData.platformData()); + Qt::DropActions supportedDropActions = dragOperationToDropActions(dragOperationMask); + + QPoint clientPosition; + QPoint globalPosition; + Qt::DropAction actualDropAction = Qt::IgnoreAction; + + if (QWindow* window = m_webPage->canvas()) { + QDrag* drag = new QDrag(window); + drag->setPixmap(QPixmap::fromImage(dragQImage)); + drag->setMimeData(mimeData); + actualDropAction = drag->exec(supportedDropActions); + globalPosition = QCursor::pos(); + clientPosition = window->mapFromGlobal(globalPosition); + } + + m_webPageProxy->dragEnded(clientPosition, globalPosition, dropActionToDragOperation(actualDropAction)); +} + +#include "moc_QtWebPageEventHandler.cpp" diff --git a/Source/WebKit2/UIProcess/qt/QtWebPageEventHandler.h b/Source/WebKit2/UIProcess/qt/QtWebPageEventHandler.h new file mode 100644 index 000000000..dfab4c8b9 --- /dev/null +++ b/Source/WebKit2/UIProcess/qt/QtWebPageEventHandler.h @@ -0,0 +1,97 @@ +/* + * Copyright (C) 2010, 2011 Nokia Corporation and/or its subsidiary(-ies) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this program; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + */ + +#ifndef QtWebPageEventHandler_h +#define QtWebPageEventHandler_h + +#include "QtPanGestureRecognizer.h" +#include "QtPinchGestureRecognizer.h" +#include "QtTapGestureRecognizer.h" +#include "QtViewportInteractionEngine.h" +#include "WebPageProxy.h" +#include <QBasicTimer> +#include <QKeyEvent> +#include <QInputMethodEvent> +#include <QTouchEvent> +#include <WKPage.h> + +class QQuickWebPage; + +using namespace WebKit; + +class QtWebPageEventHandler : public QObject { + Q_OBJECT + +public: + QtWebPageEventHandler(WKPageRef, QQuickWebPage*); + ~QtWebPageEventHandler(); + + bool handleEvent(QEvent*); + + void setViewportInteractionEngine(QtViewportInteractionEngine*); + + void handleSingleTapEvent(const QTouchEvent::TouchPoint&); + void handleDoubleTapEvent(const QTouchEvent::TouchPoint&); + + void didFindZoomableArea(const WebCore::IntPoint& target, const WebCore::IntRect& area); + void focusEditableArea(const WebCore::IntRect& caret, const WebCore::IntRect& area); + void doneWithTouchEvent(const NativeWebTouchEvent&, bool wasEventHandled); + void resetGestureRecognizers(); + + QtViewportInteractionEngine* interactionEngine() { return m_interactionEngine; } + + void startDrag(const WebCore::DragData&, PassRefPtr<ShareableBitmap> dragImage); + +protected: + WebPageProxy* m_webPageProxy; + QtViewportInteractionEngine* m_interactionEngine; + QtPanGestureRecognizer m_panGestureRecognizer; + QtPinchGestureRecognizer m_pinchGestureRecognizer; + QtTapGestureRecognizer m_tapGestureRecognizer; + QQuickWebPage* m_webPage; + +private: + bool handleKeyPressEvent(QKeyEvent*); + bool handleKeyReleaseEvent(QKeyEvent*); + bool handleFocusInEvent(QFocusEvent*); + bool handleFocusOutEvent(QFocusEvent*); + bool handleMouseMoveEvent(QMouseEvent*); + bool handleMousePressEvent(QMouseEvent*); + bool handleMouseReleaseEvent(QMouseEvent*); + bool handleWheelEvent(QWheelEvent*); + bool handleHoverLeaveEvent(QHoverEvent*); + bool handleHoverMoveEvent(QHoverEvent*); + bool handleDragEnterEvent(QDragEnterEvent*); + bool handleDragLeaveEvent(QDragLeaveEvent*); + bool handleDragMoveEvent(QDragMoveEvent*); + bool handleDropEvent(QDropEvent*); + + void timerEvent(QTimerEvent*); + + void touchEvent(QTouchEvent*); + void inputMethodEvent(QInputMethodEvent*); + + QPoint m_lastClick; + QBasicTimer m_clickTimer; + Qt::MouseButton m_previousClickButton; + int m_clickCount; +}; + +#endif /* QtWebPageEventHandler_h */ diff --git a/Source/WebKit2/UIProcess/qt/QtWebPageLoadClient.cpp b/Source/WebKit2/UIProcess/qt/QtWebPageLoadClient.cpp new file mode 100644 index 000000000..3ba8c74f6 --- /dev/null +++ b/Source/WebKit2/UIProcess/qt/QtWebPageLoadClient.cpp @@ -0,0 +1,197 @@ +/* + * Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this program; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + */ + +#include "config.h" +#include "QtWebPageLoadClient.h" + +#include "WKStringQt.h" +#include "qquickwebview_p.h" +#include "qquickwebview_p_p.h" +#include <WKFrame.h> + +QtWebPageLoadClient::QtWebPageLoadClient(WKPageRef pageRef, QQuickWebView* webView) + : m_webView(webView) + , m_loadProgress(0) +{ + WKPageLoaderClient loadClient; + memset(&loadClient, 0, sizeof(WKPageLoaderClient)); + loadClient.version = kWKPageLoaderClientCurrentVersion; + loadClient.clientInfo = this; + loadClient.didStartProvisionalLoadForFrame = didStartProvisionalLoadForFrame; + loadClient.didFailProvisionalLoadWithErrorForFrame = didFailProvisionalLoadWithErrorForFrame; + loadClient.didCommitLoadForFrame = didCommitLoadForFrame; + loadClient.didFinishLoadForFrame = didFinishLoadForFrame; + loadClient.didFailLoadWithErrorForFrame = didFailLoadWithErrorForFrame; + loadClient.didSameDocumentNavigationForFrame = didSameDocumentNavigationForFrame; + loadClient.didReceiveTitleForFrame = didReceiveTitleForFrame; + loadClient.didStartProgress = didStartProgress; + loadClient.didChangeProgress = didChangeProgress; + loadClient.didFinishProgress = didFinishProgress; + loadClient.didFirstVisuallyNonEmptyLayoutForFrame = didFirstVisuallyNonEmptyLayoutForFrame; + loadClient.didChangeBackForwardList = didChangeBackForwardList; + WKPageSetPageLoaderClient(pageRef, &loadClient); +} + +void QtWebPageLoadClient::didStartProvisionalLoadForFrame() +{ + emit m_webView->navigationStateChanged(); + emit m_webView->loadStarted(); +} + +void QtWebPageLoadClient::didCommitLoadForFrame(const QUrl& url) +{ + emit m_webView->navigationStateChanged(); + emit m_webView->urlChanged(url); + m_webView->d_func()->loadDidCommit(); +} + +void QtWebPageLoadClient::didSameDocumentNavigationForFrame(const QUrl& url) +{ + emit m_webView->navigationStateChanged(); + emit m_webView->urlChanged(url); +} + +void QtWebPageLoadClient::didReceiveTitleForFrame(const QString& title) +{ + emit m_webView->titleChanged(title); +} + +void QtWebPageLoadClient::didFirstVisuallyNonEmptyLayoutForFrame() +{ + m_webView->d_func()->didFinishFirstNonEmptyLayout(); +} + +void QtWebPageLoadClient::didChangeBackForwardList() +{ + m_webView->d_func()->didChangeBackForwardList(); +} + +void QtWebPageLoadClient::dispatchLoadSucceeded() +{ + emit m_webView->navigationStateChanged(); + emit m_webView->loadSucceeded(); +} + +void QtWebPageLoadClient::dispatchLoadFailed(WKErrorRef error) +{ + emit m_webView->navigationStateChanged(); + + int errorCode = WKErrorGetErrorCode(error); + if (toImpl(error)->platformError().isCancellation() || errorCode == kWKErrorCodeFrameLoadInterruptedByPolicyChange || errorCode == kWKErrorCodePlugInWillHandleLoad) + return; + + QtWebError qtError(error); + emit m_webView->loadFailed(static_cast<QQuickWebView::ErrorDomain>(qtError.type()), qtError.errorCode(), qtError.url(), qtError.description()); +} + +void QtWebPageLoadClient::setLoadProgress(int loadProgress) +{ + m_loadProgress = loadProgress; + emit m_webView->loadProgressChanged(m_loadProgress); +} + +static QtWebPageLoadClient* toQtWebPageLoadClient(const void* clientInfo) +{ + ASSERT(clientInfo); + return reinterpret_cast<QtWebPageLoadClient*>(const_cast<void*>(clientInfo)); +} + +void QtWebPageLoadClient::didStartProvisionalLoadForFrame(WKPageRef, WKFrameRef frame, WKTypeRef, const void* clientInfo) +{ + if (!WKFrameIsMainFrame(frame)) + return; + toQtWebPageLoadClient(clientInfo)->didStartProvisionalLoadForFrame(); +} + +void QtWebPageLoadClient::didFailProvisionalLoadWithErrorForFrame(WKPageRef, WKFrameRef frame, WKErrorRef error, WKTypeRef, const void* clientInfo) +{ + if (!WKFrameIsMainFrame(frame)) + return; + toQtWebPageLoadClient(clientInfo)->dispatchLoadFailed(error); +} + +void QtWebPageLoadClient::didCommitLoadForFrame(WKPageRef, WKFrameRef frame, WKTypeRef, const void* clientInfo) +{ + if (!WKFrameIsMainFrame(frame)) + return; + WebFrameProxy* wkframe = toImpl(frame); + QString urlStr(wkframe->url()); + QUrl qUrl = urlStr; + toQtWebPageLoadClient(clientInfo)->didCommitLoadForFrame(qUrl); +} + +void QtWebPageLoadClient::didFinishLoadForFrame(WKPageRef, WKFrameRef frame, WKTypeRef, const void* clientInfo) +{ + if (!WKFrameIsMainFrame(frame)) + return; + toQtWebPageLoadClient(clientInfo)->dispatchLoadSucceeded(); +} + +void QtWebPageLoadClient::didFailLoadWithErrorForFrame(WKPageRef, WKFrameRef frame, WKErrorRef error, WKTypeRef, const void* clientInfo) +{ + if (!WKFrameIsMainFrame(frame)) + return; + toQtWebPageLoadClient(clientInfo)->dispatchLoadFailed(error); +} + +void QtWebPageLoadClient::didSameDocumentNavigationForFrame(WKPageRef page, WKFrameRef frame, WKSameDocumentNavigationType type, WKTypeRef userData, const void* clientInfo) +{ + WebFrameProxy* wkframe = toImpl(frame); + QString urlStr(wkframe->url()); + QUrl qUrl = urlStr; + toQtWebPageLoadClient(clientInfo)->didSameDocumentNavigationForFrame(qUrl); +} + +void QtWebPageLoadClient::didReceiveTitleForFrame(WKPageRef, WKStringRef title, WKFrameRef frame, WKTypeRef, const void* clientInfo) +{ + if (!WKFrameIsMainFrame(frame)) + return; + QString qTitle = WKStringCopyQString(title); + toQtWebPageLoadClient(clientInfo)->didReceiveTitleForFrame(qTitle); +} + +void QtWebPageLoadClient::didStartProgress(WKPageRef, const void* clientInfo) +{ + QtWebPageLoadClient* client = toQtWebPageLoadClient(clientInfo); + client->setLoadProgress(0); + client->m_webView->d_func()->setIcon(QUrl()); +} + +void QtWebPageLoadClient::didChangeProgress(WKPageRef page, const void* clientInfo) +{ + toQtWebPageLoadClient(clientInfo)->setLoadProgress(WKPageGetEstimatedProgress(page) * 100); +} + +void QtWebPageLoadClient::didFinishProgress(WKPageRef, const void* clientInfo) +{ + toQtWebPageLoadClient(clientInfo)->setLoadProgress(100); +} + +void QtWebPageLoadClient::didFirstVisuallyNonEmptyLayoutForFrame(WKPageRef, WKFrameRef frame, WKTypeRef, const void *clientInfo) +{ + if (!WKFrameIsMainFrame(frame)) + return; + toQtWebPageLoadClient(clientInfo)->didFirstVisuallyNonEmptyLayoutForFrame(); +} + +void QtWebPageLoadClient::didChangeBackForwardList(WKPageRef, WKBackForwardListItemRef, WKArrayRef, const void *clientInfo) +{ + toQtWebPageLoadClient(clientInfo)->didChangeBackForwardList(); +} diff --git a/Source/WebKit2/UIProcess/qt/QtWebPageLoadClient.h b/Source/WebKit2/UIProcess/qt/QtWebPageLoadClient.h new file mode 100644 index 000000000..fbdb92e7b --- /dev/null +++ b/Source/WebKit2/UIProcess/qt/QtWebPageLoadClient.h @@ -0,0 +1,67 @@ +/* + * Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this program; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + */ + +#ifndef QtWebPageLoadClient_h +#define QtWebPageLoadClient_h + +#include "QtWebError.h" +#include <QtCore/QString> +#include <QtCore/QUrl> +#include <WKPage.h> + +class QQuickWebView; + +class QtWebPageLoadClient { +public: + QtWebPageLoadClient(WKPageRef, QQuickWebView*); + + int loadProgress() const { return m_loadProgress; } + +private: + void didStartProvisionalLoadForFrame(); + void didCommitLoadForFrame(const QUrl&); + void didSameDocumentNavigationForFrame(const QUrl&); + void didReceiveTitleForFrame(const QString&); + void didFirstVisuallyNonEmptyLayoutForFrame(); + void didChangeBackForwardList(); + + void dispatchLoadSucceeded(); + void dispatchLoadFailed(WKErrorRef); + void setLoadProgress(int); + + // WKPageLoadClient callbacks. + static void didStartProvisionalLoadForFrame(WKPageRef, WKFrameRef, WKTypeRef userData, const void* clientInfo); + static void didFailProvisionalLoadWithErrorForFrame(WKPageRef, WKFrameRef, WKErrorRef, WKTypeRef userData, const void* clientInfo); + static void didCommitLoadForFrame(WKPageRef, WKFrameRef, WKTypeRef userData, const void* clientInfo); + static void didFinishLoadForFrame(WKPageRef, WKFrameRef, WKTypeRef userData, const void* clientInfo); + static void didFailLoadWithErrorForFrame(WKPageRef, WKFrameRef, WKErrorRef, WKTypeRef userData, const void* clientInfo); + static void didSameDocumentNavigationForFrame(WKPageRef, WKFrameRef, WKSameDocumentNavigationType, WKTypeRef userData, const void* clientInfo); + static void didReceiveTitleForFrame(WKPageRef, WKStringRef, WKFrameRef, WKTypeRef userData, const void* clientInfo); + static void didStartProgress(WKPageRef, const void* clientInfo); + static void didChangeProgress(WKPageRef, const void* clientInfo); + static void didFinishProgress(WKPageRef, const void* clientInfo); + static void didFirstVisuallyNonEmptyLayoutForFrame(WKPageRef, WKFrameRef, WKTypeRef userData, const void* clientInfo); + static void didChangeBackForwardList(WKPageRef, WKBackForwardListItemRef, WKArrayRef, const void *clientInfo); + + QQuickWebView* m_webView; + int m_loadProgress; +}; + +#endif // QtWebPageLoadClient_h diff --git a/Source/WebKit2/UIProcess/qt/QtWebPagePolicyClient.cpp b/Source/WebKit2/UIProcess/qt/QtWebPagePolicyClient.cpp new file mode 100644 index 000000000..e77fb1463 --- /dev/null +++ b/Source/WebKit2/UIProcess/qt/QtWebPagePolicyClient.cpp @@ -0,0 +1,136 @@ +/* + * Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this program; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + */ + +#include "config.h" +#include "QtWebPagePolicyClient.h" + +#include "WKFrame.h" +#include "WKURLQt.h" +#include "qquickwebview_p.h" +#include "qquickwebview_p_p.h" +#include "qwebnavigationrequest_p.h" +#include <QtCore/QObject> +#include <WKFramePolicyListener.h> +#include <WKURLRequest.h> + +QtWebPagePolicyClient::QtWebPagePolicyClient(WKPageRef pageRef, QQuickWebView* webView) + : m_webView(webView) +{ + WKPagePolicyClient policyClient; + memset(&policyClient, 0, sizeof(WKPagePolicyClient)); + policyClient.version = kWKPagePolicyClientCurrentVersion; + policyClient.clientInfo = this; + policyClient.decidePolicyForNavigationAction = decidePolicyForNavigationAction; + policyClient.decidePolicyForResponse = decidePolicyForResponse; + WKPageSetPagePolicyClient(pageRef, &policyClient); +} + +void QtWebPagePolicyClient::decidePolicyForNavigationAction(const QUrl& url, const QUrl& originatingUrl, Qt::MouseButton mouseButton, Qt::KeyboardModifiers keyboardModifiers, WKFramePolicyListenerRef listener) +{ + // NOTE: even though the C API (and the WebKit2 IPC) supports an asynchronous answer, this is not currently working. + // We are expected to call the listener immediately. See the patch for https://bugs.webkit.org/show_bug.cgi?id=53785. + QWebNavigationRequest navigationRequest(url, originatingUrl, mouseButton, keyboardModifiers); + emit m_webView->navigationRequested(&navigationRequest); + + switch (navigationRequest.action()) { + case QQuickWebView::IgnoreRequest: + WKFramePolicyListenerIgnore(listener); + return; + case QQuickWebViewExperimental::DownloadRequest: + WKFramePolicyListenerDownload(listener); + return; + case QQuickWebView::AcceptRequest: + WKFramePolicyListenerUse(listener); + return; + } + ASSERT_NOT_REACHED(); +} + +static inline QtWebPagePolicyClient* toQtWebPagePolicyClient(const void* clientInfo) +{ + ASSERT(clientInfo); + return reinterpret_cast<QtWebPagePolicyClient*>(const_cast<void*>(clientInfo)); +} + +static Qt::MouseButton toQtMouseButton(WKEventMouseButton button) +{ + switch (button) { + case kWKEventMouseButtonLeftButton: + return Qt::LeftButton; + case kWKEventMouseButtonMiddleButton: + return Qt::MiddleButton; + case kWKEventMouseButtonRightButton: + return Qt::RightButton; + case kWKEventMouseButtonNoButton: + return Qt::NoButton; + } + ASSERT_NOT_REACHED(); + return Qt::NoButton; +} + +static Qt::KeyboardModifiers toQtKeyboardModifiers(WKEventModifiers modifiers) +{ + Qt::KeyboardModifiers qtModifiers = Qt::NoModifier; + if (modifiers & kWKEventModifiersShiftKey) + qtModifiers |= Qt::ShiftModifier; + if (modifiers & kWKEventModifiersControlKey) + qtModifiers |= Qt::ControlModifier; + if (modifiers & kWKEventModifiersAltKey) + qtModifiers |= Qt::AltModifier; + if (modifiers & kWKEventModifiersMetaKey) + qtModifiers |= Qt::MetaModifier; + return qtModifiers; +} + +void QtWebPagePolicyClient::decidePolicyForNavigationAction(WKPageRef, WKFrameRef frame, WKFrameNavigationType, WKEventModifiers modifiers, WKEventMouseButton mouseButton, WKURLRequestRef request, WKFramePolicyListenerRef listener, WKTypeRef, const void* clientInfo) +{ + WKRetainPtr<WKURLRef> frameURL(AdoptWK, WKFrameCopyURL(frame)); + WKRetainPtr<WKURLRef> requestURL(AdoptWK, WKURLRequestCopyURL(request)); + QUrl qUrlFrame = WKURLCopyQUrl(frameURL.get()); + QUrl qUrl = WKURLCopyQUrl(requestURL.get()); + toQtWebPagePolicyClient(clientInfo)->decidePolicyForNavigationAction(qUrl, qUrlFrame, toQtMouseButton(mouseButton), toQtKeyboardModifiers(modifiers), listener); +} + +void QtWebPagePolicyClient::decidePolicyForResponse(WKPageRef page, WKFrameRef frame, WKURLResponseRef response, WKURLRequestRef, WKFramePolicyListenerRef listener, WKTypeRef, const void*) +{ + String type = toImpl(response)->resourceResponse().mimeType(); + type.makeLower(); + bool canShowMIMEType = toImpl(frame)->canShowMIMEType(type); + + if (WKPageGetMainFrame(page) == frame) { + if (canShowMIMEType) { + WKFramePolicyListenerUse(listener); + return; + } + + // If we can't use (show) it then we should download it. + WKFramePolicyListenerDownload(listener); + return; + } + + // We should ignore downloadable top-level content for subframes, with an exception for text/xml and application/xml so we can still support Acid3 test. + // It makes the browser intentionally behave differently when it comes to text(application)/xml content in subframes vs. mainframe. + if (!canShowMIMEType && !(type == "text/xml" || type == "application/xml")) { + WKFramePolicyListenerIgnore(listener); + return; + } + + WKFramePolicyListenerUse(listener); +} diff --git a/Source/WebKit2/UIProcess/qt/QtWebPagePolicyClient.h b/Source/WebKit2/UIProcess/qt/QtWebPagePolicyClient.h new file mode 100644 index 000000000..8c6021398 --- /dev/null +++ b/Source/WebKit2/UIProcess/qt/QtWebPagePolicyClient.h @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this program; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + */ + +#ifndef QtWebPagePolicyClient_h +#define QtWebPagePolicyClient_h + +#include <QtCore/QUrl> +#include <WKPage.h> + +class QQuickWebView; + +class QtWebPagePolicyClient { +public: + QtWebPagePolicyClient(WKPageRef, QQuickWebView*); + +private: + void decidePolicyForNavigationAction(const QUrl&, const QUrl&, Qt::MouseButton, Qt::KeyboardModifiers, WKFramePolicyListenerRef); + + // WKPagePolicyClient callbacks. + static void decidePolicyForNavigationAction(WKPageRef, WKFrameRef, WKFrameNavigationType, WKEventModifiers, WKEventMouseButton, WKURLRequestRef, WKFramePolicyListenerRef, WKTypeRef userData, const void* clientInfo); + static void decidePolicyForResponse(WKPageRef, WKFrameRef, WKURLResponseRef, WKURLRequestRef, WKFramePolicyListenerRef, WKTypeRef userData, const void* clientInfo); + + QQuickWebView* m_webView; +}; + +#endif // QtWebPagePolicyClient_h diff --git a/Source/WebKit2/UIProcess/qt/QtWebPageUIClient.cpp b/Source/WebKit2/UIProcess/qt/QtWebPageUIClient.cpp new file mode 100644 index 000000000..ef764c5c9 --- /dev/null +++ b/Source/WebKit2/UIProcess/qt/QtWebPageUIClient.cpp @@ -0,0 +1,147 @@ +/* + * Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this program; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + */ + +#include "config.h" +#include "QtWebPageUIClient.h" + +#include "WKStringQt.h" +#include "WKURLQt.h" +#include "qquickwebview_p.h" +#include "qquickwebview_p_p.h" +#include "qwebpermissionrequest_p.h" +#include <WKAPICast.h> +#include <WKHitTestResult.h> +#include <WKOpenPanelParameters.h> +#include <WKOpenPanelResultListener.h> + +QtWebPageUIClient::QtWebPageUIClient(WKPageRef pageRef, QQuickWebView* webView) + : m_webView(webView) +{ + WKPageUIClient uiClient; + memset(&uiClient, 0, sizeof(WKPageUIClient)); + uiClient.version = kWKPageUIClientCurrentVersion; + uiClient.clientInfo = this; + uiClient.runJavaScriptAlert = runJavaScriptAlert; + uiClient.runJavaScriptConfirm = runJavaScriptConfirm; + uiClient.runJavaScriptPrompt = runJavaScriptPrompt; + uiClient.runOpenPanel = runOpenPanel; + uiClient.mouseDidMoveOverElement = mouseDidMoveOverElement; + uiClient.decidePolicyForGeolocationPermissionRequest = policyForGeolocationPermissionRequest; + WKPageSetPageUIClient(pageRef, &uiClient); +} + +void QtWebPageUIClient::runJavaScriptAlert(const QString& message) +{ + m_webView->d_func()->runJavaScriptAlert(message); +} + +bool QtWebPageUIClient::runJavaScriptConfirm(const QString& message) +{ + return m_webView->d_func()->runJavaScriptConfirm(message); +} + +QString QtWebPageUIClient::runJavaScriptPrompt(const QString& message, const QString& defaultValue, bool& ok) +{ + return m_webView->d_func()->runJavaScriptPrompt(message, defaultValue, ok); +} + +void QtWebPageUIClient::runOpenPanel(WKOpenPanelResultListenerRef listenerRef, const QStringList& selectedFileNames, FileChooserType type) +{ + m_webView->d_func()->chooseFiles(listenerRef, selectedFileNames, type); +} + +void QtWebPageUIClient::mouseDidMoveOverElement(const QUrl& linkURL, const QString& linkTitle) +{ + if (linkURL == m_lastHoveredURL && linkTitle == m_lastHoveredTitle) + return; + m_lastHoveredURL = linkURL; + m_lastHoveredTitle = linkTitle; + emit m_webView->linkHovered(m_lastHoveredURL, m_lastHoveredTitle); +} + +void QtWebPageUIClient::permissionRequest(QWebPermissionRequest* request) +{ + request->setParent(m_webView); + emit m_webView->experimental()->permissionRequested(request); +} + +static QtWebPageUIClient* toQtWebPageUIClient(const void* clientInfo) +{ + ASSERT(clientInfo); + return reinterpret_cast<QtWebPageUIClient*>(const_cast<void*>(clientInfo)); +} + +void QtWebPageUIClient::runJavaScriptAlert(WKPageRef, WKStringRef alertText, WKFrameRef, const void* clientInfo) +{ + QString qAlertText = WKStringCopyQString(alertText); + toQtWebPageUIClient(clientInfo)->runJavaScriptAlert(qAlertText); +} + +bool QtWebPageUIClient::runJavaScriptConfirm(WKPageRef, WKStringRef message, WKFrameRef, const void* clientInfo) +{ + QString qMessage = WKStringCopyQString(message); + return toQtWebPageUIClient(clientInfo)->runJavaScriptConfirm(qMessage); +} + +static inline WKStringRef createNullWKString() +{ + RefPtr<WebString> webString = WebString::createNull(); + return toAPI(webString.release().leakRef()); +} + +WKStringRef QtWebPageUIClient::runJavaScriptPrompt(WKPageRef, WKStringRef message, WKStringRef defaultValue, WKFrameRef, const void* clientInfo) +{ + QString qMessage = WKStringCopyQString(message); + QString qDefaultValue = WKStringCopyQString(defaultValue); + bool ok = false; + QString result = toQtWebPageUIClient(clientInfo)->runJavaScriptPrompt(qMessage, qDefaultValue, ok); + if (!ok) + return createNullWKString(); + return WKStringCreateWithQString(result); +} + +void QtWebPageUIClient::runOpenPanel(WKPageRef, WKFrameRef, WKOpenPanelParametersRef parameters, WKOpenPanelResultListenerRef listener, const void* clientInfo) +{ + Vector<String> wkSelectedFileNames = toImpl(parameters)->selectedFileNames(); + + QStringList selectedFileNames; + for (size_t i = 0; i < wkSelectedFileNames.size(); ++i) + selectedFileNames += wkSelectedFileNames.at(i); + + FileChooserType allowMultipleFiles = WKOpenPanelParametersGetAllowsMultipleFiles(parameters) ? MultipleFilesSelection : SingleFileSelection; + toQtWebPageUIClient(clientInfo)->runOpenPanel(listener, selectedFileNames, allowMultipleFiles); +} + +void QtWebPageUIClient::mouseDidMoveOverElement(WKPageRef page, WKHitTestResultRef hitTestResult, WKEventModifiers modifiers, WKTypeRef userData, const void* clientInfo) +{ + const QUrl absoluteLinkUrl = WKURLCopyQUrl(adoptWK(WKHitTestResultCopyAbsoluteLinkURL(hitTestResult)).get()); + const QString linkTitle = WKStringCopyQString(adoptWK(WKHitTestResultCopyLinkTitle(hitTestResult)).get()); + toQtWebPageUIClient(clientInfo)->mouseDidMoveOverElement(absoluteLinkUrl, linkTitle); +} + +void QtWebPageUIClient::policyForGeolocationPermissionRequest(WKPageRef page, WKFrameRef frame, WKSecurityOriginRef origin, WKGeolocationPermissionRequestRef request, const void* clientInfo) +{ + if (!request) + return; + + QWebPermissionRequest* req = QWebPermissionRequest::create(origin, request); + toQtWebPageUIClient(clientInfo)->permissionRequest(req); +} + diff --git a/Source/WebKit2/UIProcess/qt/QtWebPageUIClient.h b/Source/WebKit2/UIProcess/qt/QtWebPageUIClient.h new file mode 100644 index 000000000..8cfe13c21 --- /dev/null +++ b/Source/WebKit2/UIProcess/qt/QtWebPageUIClient.h @@ -0,0 +1,64 @@ +/* + * Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this program; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + */ + +#ifndef QtWebPageUIClient_h +#define QtWebPageUIClient_h + +#include <QtCore/QString> +#include <QtCore/QUrl> +#include <WKFrame.h> +#include <WKGeolocationPermissionRequest.h> +#include <WKPage.h> +#include <WKSecurityOrigin.h> + +class QQuickWebView; +class QWebPermissionRequest; + +class QtWebPageUIClient { +public: + enum FileChooserType { + SingleFileSelection, + MultipleFilesSelection + }; + + QtWebPageUIClient(WKPageRef, QQuickWebView*); + +private: + void runJavaScriptAlert(const QString& message); + bool runJavaScriptConfirm(const QString& message); + QString runJavaScriptPrompt(const QString& message, const QString& defaultValue, bool& ok); + void runOpenPanel(WKOpenPanelResultListenerRef, const QStringList& selectedFileNames, FileChooserType); + void mouseDidMoveOverElement(const QUrl& linkURL, const QString& linkTitle); + void permissionRequest(QWebPermissionRequest*); + + // WKPageUIClient callbacks. + static void runJavaScriptAlert(WKPageRef, WKStringRef alertText, WKFrameRef, const void* clientInfo); + static bool runJavaScriptConfirm(WKPageRef, WKStringRef message, WKFrameRef, const void* clientInfo); + static WKStringRef runJavaScriptPrompt(WKPageRef, WKStringRef message, WKStringRef defaultValue, WKFrameRef, const void* clientInfo); + static void runOpenPanel(WKPageRef, WKFrameRef, WKOpenPanelParametersRef, WKOpenPanelResultListenerRef, const void* clientInfo); + static void mouseDidMoveOverElement(WKPageRef, WKHitTestResultRef, WKEventModifiers, WKTypeRef userData, const void* clientInfo); + static void policyForGeolocationPermissionRequest(WKPageRef, WKFrameRef, WKSecurityOriginRef, WKGeolocationPermissionRequestRef, const void*); + + QQuickWebView* m_webView; + QUrl m_lastHoveredURL; + QString m_lastHoveredTitle; +}; + +#endif // QtWebPageUIClient_h diff --git a/Source/WebKit2/UIProcess/qt/QtWebUndoController.cpp b/Source/WebKit2/UIProcess/qt/QtWebUndoController.cpp new file mode 100644 index 000000000..62d31e8ab --- /dev/null +++ b/Source/WebKit2/UIProcess/qt/QtWebUndoController.cpp @@ -0,0 +1,63 @@ +/* + Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies) + Copyright (C) 2007 Staikos Computing Services Inc. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#include "config.h" +#include "QtWebUndoController.h" + +#include <qglobal.h> +#include <wtf/RefPtr.h> + +using namespace WebKit; + +void QtWebUndoController::registerEditCommand(PassRefPtr<WebEditCommandProxy> command, WebPageProxy::UndoOrRedo undoOrRedo) +{ + if (undoOrRedo == WebPageProxy::Undo) + m_undoStack.append(command); + else + m_redoStack.append(command); +} + +void QtWebUndoController::clearAllEditCommands() +{ + m_undoStack.clear(); + m_redoStack.clear(); +} + +bool QtWebUndoController::canUndoRedo(WebPageProxy::UndoOrRedo undoOrRedo) +{ + if (undoOrRedo == WebPageProxy::Undo) + return !m_undoStack.isEmpty(); + else + return !m_redoStack.isEmpty(); +} + +void QtWebUndoController::executeUndoRedo(WebPageProxy::UndoOrRedo undoOrRedo) +{ + RefPtr<WebEditCommandProxy> command; + if (undoOrRedo == WebPageProxy::Undo) { + command = m_undoStack.last(); + m_undoStack.removeLast(); + command->unapply(); + } else { + command = m_redoStack.last(); + m_redoStack.removeLast(); + command->reapply(); + } +} diff --git a/Source/WebKit2/UIProcess/qt/QtWebUndoController.h b/Source/WebKit2/UIProcess/qt/QtWebUndoController.h new file mode 100644 index 000000000..a260ca2fd --- /dev/null +++ b/Source/WebKit2/UIProcess/qt/QtWebUndoController.h @@ -0,0 +1,41 @@ +/* + Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies) + Copyright (C) 2007 Staikos Computing Services Inc. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#ifndef QtWebUndoController_h +#define QtWebUndoController_h + +#include "PageClient.h" +#include "WebEditCommandProxy.h" +#include "WebPageProxy.h" + +class QtWebUndoController { +public: + // Page Client. + void registerEditCommand(PassRefPtr<WebKit::WebEditCommandProxy>, WebKit::WebPageProxy::UndoOrRedo); + void clearAllEditCommands(); + bool canUndoRedo(WebKit::WebPageProxy::UndoOrRedo); + void executeUndoRedo(WebKit::WebPageProxy::UndoOrRedo); + + typedef Vector<RefPtr<WebKit::WebEditCommandProxy> > CommandVector; + CommandVector m_undoStack; + CommandVector m_redoStack; +}; + +#endif // QtWebUndoController_h diff --git a/Source/WebKit2/UIProcess/qt/TextCheckerQt.cpp b/Source/WebKit2/UIProcess/qt/TextCheckerQt.cpp new file mode 100644 index 000000000..4a3318405 --- /dev/null +++ b/Source/WebKit2/UIProcess/qt/TextCheckerQt.cpp @@ -0,0 +1,129 @@ +/* + * Copyright (C) 2010 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 "TextChecker.h" + +#include "TextCheckerState.h" +#include <WebCore/NotImplemented.h> + +using namespace WebCore; + +namespace WebKit { + +static TextCheckerState textCheckerState; + +const TextCheckerState& TextChecker::state() +{ + notImplemented(); + + return textCheckerState; +} + +bool TextChecker::isContinuousSpellCheckingAllowed() +{ + notImplemented(); + + return false; +} + +void TextChecker::setContinuousSpellCheckingEnabled(bool isContinuousSpellCheckingEnabled) +{ + notImplemented(); +} + +void TextChecker::setGrammarCheckingEnabled(bool isGrammarCheckingEnabled) +{ + notImplemented(); +} + +void TextChecker::continuousSpellCheckingEnabledStateChanged(bool enabled) +{ + notImplemented(); +} + +void TextChecker::grammarCheckingEnabledStateChanged(bool enabled) +{ + notImplemented(); +} + +int64_t TextChecker::uniqueSpellDocumentTag(WebPageProxy*) +{ + notImplemented(); + return 0; +} + +void TextChecker::closeSpellDocumentWithTag(int64_t) +{ + notImplemented(); +} + +void TextChecker::checkSpellingOfString(int64_t, const UChar*, uint32_t, int32_t&, int32_t&) +{ + notImplemented(); +} + +void TextChecker::checkGrammarOfString(int64_t, const UChar*, uint32_t, Vector<WebCore::GrammarDetail>&, int32_t&, int32_t&) +{ + notImplemented(); +} + +bool TextChecker::spellingUIIsShowing() +{ + notImplemented(); + return false; +} + +void TextChecker::toggleSpellingUIIsShowing() +{ + notImplemented(); +} + +void TextChecker::updateSpellingUIWithMisspelledWord(int64_t, const String&) +{ + notImplemented(); +} + +void TextChecker::updateSpellingUIWithGrammarString(int64_t, const String&, const GrammarDetail&) +{ + notImplemented(); +} + +void TextChecker::getGuessesForWord(int64_t spellDocumentTag, const String& word, const String& context, Vector<String>& guesses) +{ + notImplemented(); +} + +void TextChecker::learnWord(int64_t, const String&) +{ + notImplemented(); +} + +void TextChecker::ignoreWord(int64_t spellDocumentTag, const String& word) +{ + notImplemented(); +} + +} // namespace WebKit diff --git a/Source/WebKit2/UIProcess/qt/TiledDrawingAreaProxyQt.cpp b/Source/WebKit2/UIProcess/qt/TiledDrawingAreaProxyQt.cpp new file mode 100644 index 000000000..2c76062f5 --- /dev/null +++ b/Source/WebKit2/UIProcess/qt/TiledDrawingAreaProxyQt.cpp @@ -0,0 +1,83 @@ +/* + * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies) + * + * 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 "TiledDrawingAreaProxy.h" + +#include "QtSGUpdateQueue.h" +#include "qquickwebpage_p.h" +#include "ShareableBitmap.h" +#include "UpdateInfo.h" +#include "WKAPICast.h" +#include "WebPageProxy.h" + +using namespace WebCore; + +#define TILE_DEBUG_LOG + +namespace WebKit { + +void TiledDrawingAreaProxy::updateWebView(const Vector<IntRect>& paintedArea) +{ + // SG updates are triggered through QtSGUpdateQueue. +} + +WebPageProxy* TiledDrawingAreaProxy::page() +{ + return m_webPageProxy; +} + +void TiledDrawingAreaProxy::createTile(int tileID, const UpdateInfo& updateInfo) +{ + int nodeID = m_webView->sceneGraphUpdateQueue()->createTileNode(updateInfo.updateScaleFactor); + m_tileNodeMap.set(tileID, nodeID); + updateTile(tileID, updateInfo); +} + +void TiledDrawingAreaProxy::updateTile(int tileID, const UpdateInfo& updateInfo) +{ + int nodeID = m_tileNodeMap.get(tileID); + ASSERT(nodeID); + + RefPtr<ShareableBitmap> bitmap = ShareableBitmap::create(updateInfo.bitmapHandle); + // FIXME: We could avoid this copy by carying the ShareableBitmap all the way up to texture uploading. + // Currently won't work since the SharedMemory handle is owned by updateInfo. + QImage image(bitmap->createQImage().copy()); + QRect sourceRect(0, 0, updateInfo.updateRectBounds.width(), updateInfo.updateRectBounds.height()); + m_webView->sceneGraphUpdateQueue()->setNodeBackBuffer(nodeID, image, sourceRect, updateInfo.updateRectBounds); +} + +void TiledDrawingAreaProxy::didRenderFrame() +{ + m_webView->sceneGraphUpdateQueue()->swapTileBuffers(); +} + +void TiledDrawingAreaProxy::removeTile(int tileID) +{ + int nodeID = m_tileNodeMap.take(tileID); + m_webView->sceneGraphUpdateQueue()->removeTileNode(nodeID); +} + +} // namespace WebKit diff --git a/Source/WebKit2/UIProcess/qt/WebContextMenuProxyQt.cpp b/Source/WebKit2/UIProcess/qt/WebContextMenuProxyQt.cpp new file mode 100644 index 000000000..b00951014 --- /dev/null +++ b/Source/WebKit2/UIProcess/qt/WebContextMenuProxyQt.cpp @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2010 Apple Inc. All rights reserved. + * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies) + * + * 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 "WebContextMenuProxyQt.h" + +using namespace WebCore; + +namespace WebKit { + +WebContextMenuProxyQt::WebContextMenuProxyQt(WebPageProxy*) +{ +} + +PassRefPtr<WebContextMenuProxyQt> WebContextMenuProxyQt::create(WebPageProxy* webPageProxy) +{ + return adoptRef(new WebContextMenuProxyQt(webPageProxy)); +} + +void WebContextMenuProxyQt::showContextMenu(const IntPoint& position, const Vector<WebContextMenuItemData>& items) +{ +} + +void WebContextMenuProxyQt::hideContextMenu() +{ +} + +#include "moc_WebContextMenuProxyQt.cpp" + +} // namespace WebKit diff --git a/Source/WebKit2/UIProcess/qt/WebContextMenuProxyQt.h b/Source/WebKit2/UIProcess/qt/WebContextMenuProxyQt.h new file mode 100644 index 000000000..bd7aebd6f --- /dev/null +++ b/Source/WebKit2/UIProcess/qt/WebContextMenuProxyQt.h @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2010 Apple Inc. All rights reserved. + * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies) + * + * 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 WebContextMenuProxyQt_h +#define WebContextMenuProxyQt_h + +#include "WebContextMenuProxy.h" +#include <QtCore/QObject> + +namespace WebKit { + +class WebPageProxy; + +class WebContextMenuProxyQt : public QObject, public WebContextMenuProxy { + Q_OBJECT +public: + static PassRefPtr<WebContextMenuProxyQt> create(WebPageProxy*); + +private: + WebContextMenuProxyQt(WebPageProxy*); + + virtual void showContextMenu(const WebCore::IntPoint&, const Vector<WebContextMenuItemData>&); + virtual void hideContextMenu(); +}; + +} // namespace WebKit + +#endif // WebContextMenuProxyQt_h diff --git a/Source/WebKit2/UIProcess/qt/WebContextQt.cpp b/Source/WebKit2/UIProcess/qt/WebContextQt.cpp new file mode 100644 index 000000000..b0d5ac4ba --- /dev/null +++ b/Source/WebKit2/UIProcess/qt/WebContextQt.cpp @@ -0,0 +1,107 @@ +/* + * Copyright (C) 2010 Apple Inc. All rights reserved. + * Copyright (C) 2010 University of Szeged + * + * 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 "WebContext.h" + +#include "ApplicationCacheStorage.h" +#include "FileSystem.h" +#include "WKSharedAPICast.h" +#if ENABLE(GEOLOCATION) +#include "WebGeolocationProviderQt.h" +#endif +#include "WebProcessCreationParameters.h" + +#include <QCoreApplication> +#include <QStandardPaths> +#include <QDir> +#include <QProcess> + +namespace WebKit { + +static QString defaultDataLocation() +{ + static QString s_dataLocation; + + if (!s_dataLocation.isEmpty()) + return s_dataLocation; + + QString dataLocation = QStandardPaths::writableLocation(QStandardPaths::DataLocation); + if (dataLocation.isEmpty()) + dataLocation = WebCore::pathByAppendingComponent(QDir::homePath(), QCoreApplication::applicationName()); + s_dataLocation = WebCore::pathByAppendingComponent(dataLocation, ".QtWebKit/"); + WebCore::makeAllDirectories(s_dataLocation); + return s_dataLocation; +} + +static QString s_defaultDatabaseDirectory; +static QString s_defaultLocalStorageDirectory; + +String WebContext::applicationCacheDirectory() +{ + return WebCore::cacheStorage().cacheDirectory(); +} + +void WebContext::platformInitializeWebProcess(WebProcessCreationParameters& parameters) +{ + qRegisterMetaType<QProcess::ExitStatus>("QProcess::ExitStatus"); + parameters.cookieStorageDirectory = defaultDataLocation(); +#if ENABLE(GEOLOCATION) + static WebGeolocationProviderQt* location = WebGeolocationProviderQt::create(toAPI(geolocationManagerProxy())); + WKGeolocationManagerSetProvider(toAPI(geolocationManagerProxy()), WebGeolocationProviderQt::provider(location)); +#endif +} + +void WebContext::platformInvalidateContext() +{ +} + +String WebContext::platformDefaultDatabaseDirectory() const +{ + if (!s_defaultDatabaseDirectory.isEmpty()) + return s_defaultDatabaseDirectory; + + s_defaultDatabaseDirectory = defaultDataLocation() + QLatin1String("Databases"); + QDir().mkpath(s_defaultDatabaseDirectory); + return s_defaultDatabaseDirectory; +} + +String WebContext::platformDefaultIconDatabasePath() const +{ + return defaultDataLocation() + QLatin1String("WebpageIcons.db"); +} + +String WebContext::platformDefaultLocalStorageDirectory() const +{ + if (!s_defaultLocalStorageDirectory.isEmpty()) + return s_defaultLocalStorageDirectory; + + s_defaultLocalStorageDirectory = defaultDataLocation() + QLatin1String("LocalStorage"); + QDir().mkpath(s_defaultLocalStorageDirectory); + return s_defaultLocalStorageDirectory; +} + +} // namespace WebKit diff --git a/Source/WebKit2/UIProcess/qt/WebFullScreenManagerProxyQt.cpp b/Source/WebKit2/UIProcess/qt/WebFullScreenManagerProxyQt.cpp new file mode 100644 index 000000000..c4a13fad8 --- /dev/null +++ b/Source/WebKit2/UIProcess/qt/WebFullScreenManagerProxyQt.cpp @@ -0,0 +1,86 @@ +/* + * Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include "config.h" +#include "WebFullScreenManagerProxy.h" + +#if ENABLE(FULLSCREEN_API) + +#include "WebContext.h" +#include "WebFullScreenManagerMessages.h" +#include "WebFullScreenManagerProxyMessages.h" +#include "WebProcess.h" + +#include <WebCore/NotImplemented.h> + +namespace WebKit { + +void WebFullScreenManagerProxy::invalidate() +{ + m_webView = 0; +} + +void WebFullScreenManagerProxy::enterFullScreen() +{ + notImplemented(); +} + +void WebFullScreenManagerProxy::exitFullScreen() +{ + notImplemented(); +} + +void WebFullScreenManagerProxy::beganEnterFullScreenAnimation() +{ + notImplemented(); +} + +void WebFullScreenManagerProxy::finishedEnterFullScreenAnimation(bool completed) +{ + notImplemented(); +} + +void WebFullScreenManagerProxy::beganExitFullScreenAnimation() +{ + notImplemented(); +} + +void WebFullScreenManagerProxy::finishedExitFullScreenAnimation(bool completed) +{ + notImplemented(); +} + +void WebFullScreenManagerProxy::enterAcceleratedCompositingMode(const LayerTreeContext& context) +{ + notImplemented(); +} + +void WebFullScreenManagerProxy::exitAcceleratedCompositingMode() +{ + notImplemented(); +} + +void WebFullScreenManagerProxy::getFullScreenRect(WebCore::IntRect& rect) +{ + notImplemented(); +} + +} // namespace WebKit + +#endif // ENABLE(FULLSCREEN_API) diff --git a/Source/WebKit2/UIProcess/qt/WebGeolocationProviderQt.cpp b/Source/WebKit2/UIProcess/qt/WebGeolocationProviderQt.cpp new file mode 100644 index 000000000..70d7b5733 --- /dev/null +++ b/Source/WebKit2/UIProcess/qt/WebGeolocationProviderQt.cpp @@ -0,0 +1,119 @@ +/* + * Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this program; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + */ + +#include "config.h" +#include "WebGeolocationProviderQt.h" + +#if ENABLE(GEOLOCATION) + +#include <QtLocation/QGeoPositionInfoSource> + +using namespace WebKit; + +static inline const WebGeolocationProviderQt* toLocationProvider(const void* clientInfo) +{ + return static_cast<const WebGeolocationProviderQt*>(clientInfo); +} + +static void locationStartUpdating(WKGeolocationManagerRef geolocationManager, const void* clientInfo) +{ + toLocationProvider(clientInfo)->startUpdating(); +} + +static void locationStopUpdating(WKGeolocationManagerRef geolocationManager, const void* clientInfo) +{ + toLocationProvider(clientInfo)->stopUpdating(); +} + +WebGeolocationProviderQt* WebGeolocationProviderQt::create(WKGeolocationManagerRef manager) +{ + return new WebGeolocationProviderQt(manager); +} + +WKGeolocationProvider* WebGeolocationProviderQt::provider(const WebGeolocationProviderQt* location) +{ + static WKGeolocationProvider provider = { + 0, // This features the version. + location, // This points to the object implementer. + locationStartUpdating, // The callbacks are next. + locationStopUpdating + }; + + return &provider; +} + +WebGeolocationProviderQt::WebGeolocationProviderQt(WKGeolocationManagerRef manager) + : m_manager(manager) + , m_source(0) +{ +} + +WebGeolocationProviderQt::~WebGeolocationProviderQt() +{ +} + +void WebGeolocationProviderQt::updateTimeout() +{ + WKGeolocationManagerProviderDidFailToDeterminePosition(m_manager); +} + +void WebGeolocationProviderQt::positionUpdated(const QGeoPositionInfo& geoPosition) +{ + if (!geoPosition.isValid()) + return; + + QGeoCoordinate coord = geoPosition.coordinate(); + double latitude = coord.latitude(); + double longitude = coord.longitude(); + double accuracy = geoPosition.attribute(QGeoPositionInfo::HorizontalAccuracy); + double timeStampInSeconds = geoPosition.timestamp().toMSecsSinceEpoch() / 1000; + + m_lastPosition.adopt(WKGeolocationPositionCreate(timeStampInSeconds, latitude, longitude, accuracy)); + + WKGeolocationManagerProviderDidChangePosition(m_manager, m_lastPosition.get()); +} + +void WebGeolocationProviderQt::startUpdating() const +{ + if (!m_source) { + if (!(m_source = QGeoPositionInfoSource::createDefaultSource(const_cast<WebGeolocationProviderQt*>(this)))) { + // Let the manager known that the provider is not available. + WKGeolocationManagerSetProvider(m_manager, 0); + // Notify failure at retrieving the position. + WKGeolocationManagerProviderDidFailToDeterminePosition(m_manager); + return; + } + + connect(m_source, SIGNAL(positionUpdated(QGeoPositionInfo)), this, SLOT(positionUpdated(QGeoPositionInfo))); + connect(m_source, SIGNAL(updateTimeout()), this, SLOT(updateTimeout())); + } + + m_source->startUpdates(); +} + +void WebGeolocationProviderQt::stopUpdating() const +{ + if (m_source) + m_source->stopUpdates(); +} + +#include "moc_WebGeolocationProviderQt.cpp" + +#endif // ENABLE(GEOLOCATION) diff --git a/Source/WebKit2/UIProcess/qt/WebGeolocationProviderQt.h b/Source/WebKit2/UIProcess/qt/WebGeolocationProviderQt.h new file mode 100644 index 000000000..e59e3d75b --- /dev/null +++ b/Source/WebKit2/UIProcess/qt/WebGeolocationProviderQt.h @@ -0,0 +1,56 @@ +/* + Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + + +#ifndef WebGeolocationProviderQt_h +#define WebGeolocationProviderQt_h + +#include <QObject> +#include <WebKit2/WKGeolocationManager.h> +#include <WebKit2/WKGeolocationPosition.h> +#include <WebKit2/WKRetainPtr.h> + +class QGeoPositionInfoSource; +class QGeoPositionInfo; + +class WebGeolocationProviderQt : public QObject { + Q_OBJECT +public: + static WebGeolocationProviderQt* create(WKGeolocationManagerRef); + static WKGeolocationProvider* provider(const WebGeolocationProviderQt*); + + virtual ~WebGeolocationProviderQt(); + + void startUpdating() const; + void stopUpdating() const; + +public Q_SLOTS: + void updateTimeout(); + void positionUpdated(const QGeoPositionInfo&); + +private: + Q_DISABLE_COPY(WebGeolocationProviderQt); + WebGeolocationProviderQt(WKGeolocationManagerRef); + + WKGeolocationManagerRef m_manager; + WKRetainPtr<WKGeolocationPositionRef> m_lastPosition; + mutable QGeoPositionInfoSource* m_source; +}; + +#endif /* WebGeolocationProviderQt_h */ diff --git a/Source/WebKit2/UIProcess/qt/WebInspectorProxyQt.cpp b/Source/WebKit2/UIProcess/qt/WebInspectorProxyQt.cpp new file mode 100644 index 000000000..6b69e9975 --- /dev/null +++ b/Source/WebKit2/UIProcess/qt/WebInspectorProxyQt.cpp @@ -0,0 +1,97 @@ +/* + * Copyright (C) 2010 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 "WebInspectorProxy.h" + +#if ENABLE(INSPECTOR) + +#include <WebCore/NotImplemented.h> +#include <wtf/text/WTFString.h> + +namespace WebKit { + +WebPageProxy* WebInspectorProxy::platformCreateInspectorPage() +{ + notImplemented(); + return 0; +} + +void WebInspectorProxy::platformOpen() +{ + notImplemented(); +} + +void WebInspectorProxy::platformDidClose() +{ + notImplemented(); +} + +void WebInspectorProxy::platformBringToFront() +{ + notImplemented(); +} + +void WebInspectorProxy::platformInspectedURLChanged(const String&) +{ + notImplemented(); +} + +unsigned WebInspectorProxy::platformInspectedWindowHeight() +{ + notImplemented(); + return 0; +} + +void WebInspectorProxy::platformAttach() +{ + notImplemented(); +} + +void WebInspectorProxy::platformDetach() +{ + notImplemented(); +} + +void WebInspectorProxy::platformSetAttachedWindowHeight(unsigned) +{ + notImplemented(); +} + +String WebInspectorProxy::inspectorPageURL() const +{ + notImplemented(); + return String(); +} + +String WebInspectorProxy::inspectorBaseURL() const +{ + notImplemented(); + return String(); +} + +} // namespace WebKit + +#endif // ENABLE(INSPECTOR) diff --git a/Source/WebKit2/UIProcess/qt/WebPageProxyQt.cpp b/Source/WebKit2/UIProcess/qt/WebPageProxyQt.cpp new file mode 100644 index 000000000..ac9fde418 --- /dev/null +++ b/Source/WebKit2/UIProcess/qt/WebPageProxyQt.cpp @@ -0,0 +1,105 @@ +/* + * Copyright (C) 2010 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 "WebPageProxy.h" + +#include "PageClient.h" +#include "QtNetworkReplyData.h" +#include "QtPageClient.h" +#include "qquicknetworkreply_p.h" +#include "WebPageMessages.h" +#include "WebProcessProxy.h" +#include <WebCore/Editor.h> +#include <WebCore/NotImplemented.h> + +using namespace WebCore; + +namespace WebKit { + +String WebPageProxy::standardUserAgent(const String& applicationNameForUserAgent) +{ + // FIXME: This should not be hard coded. + return "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_6) AppleWebKit/531.4 (KHTML, like Gecko) Version/4.0.3 Safari/531.4"; +} + +void WebPageProxy::saveRecentSearches(const String&, const Vector<String>&) +{ + notImplemented(); +} + +void WebPageProxy::loadRecentSearches(const String&, Vector<String>&) +{ + notImplemented(); +} + +void WebPageProxy::setComposition(const String& text, Vector<CompositionUnderline> underlines, uint64_t selectionStart, uint64_t selectionEnd, uint64_t replacementRangeStart, uint64_t replacementRangeEnd) +{ + // FIXME: We need to find out how to proper handle the crashes case. + if (!isValid()) + return; + + process()->send(Messages::WebPage::SetComposition(text, underlines, selectionStart, selectionEnd, replacementRangeStart, replacementRangeEnd), m_pageID); +} + +void WebPageProxy::confirmComposition(const String& compositionString, int64_t selectionStart, int64_t selectionLength) +{ + if (!isValid()) + return; + + process()->send(Messages::WebPage::ConfirmComposition(compositionString, selectionStart, selectionLength), m_pageID); +} + +void WebPageProxy::cancelComposition() +{ + if (!isValid()) + return; + + process()->send(Messages::WebPage::CancelComposition(), m_pageID); +} + +void WebPageProxy::registerApplicationScheme(const String& scheme) +{ + process()->send(Messages::WebPage::RegisterApplicationScheme(scheme), m_pageID); +} + +void WebPageProxy::resolveApplicationSchemeRequest(QtNetworkRequestData request) +{ + RefPtr<QtNetworkRequestData> requestData = adoptRef(new QtNetworkRequestData(request)); + m_applicationSchemeRequests.add(requestData); + static_cast<QtPageClient*>(m_pageClient)->handleApplicationSchemeRequest(requestData); +} + +void WebPageProxy::sendApplicationSchemeReply(const QQuickNetworkReply* reply) +{ + RefPtr<QtNetworkRequestData> requestData = reply->networkRequestData(); + if (m_applicationSchemeRequests.contains(requestData)) { + RefPtr<QtNetworkReplyData> replyData = reply->networkReplyData(); + process()->send(Messages::WebPage::ApplicationSchemeReply(*replyData), pageID()); + m_applicationSchemeRequests.remove(requestData); + } +} + +} // namespace WebKit diff --git a/Source/WebKit2/UIProcess/qt/WebPopupMenuProxyQt.cpp b/Source/WebKit2/UIProcess/qt/WebPopupMenuProxyQt.cpp new file mode 100644 index 000000000..4c0deadc2 --- /dev/null +++ b/Source/WebKit2/UIProcess/qt/WebPopupMenuProxyQt.cpp @@ -0,0 +1,316 @@ +/* + * Copyright (C) 2010 Apple Inc. All rights reserved. + * Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies) + * + * 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 "WebPopupMenuProxyQt.h" + +#include "PlatformPopupMenuData.h" +#include "WebPopupItem.h" +#include "qquickwebview_p.h" +#include "qquickwebview_p_p.h" +#include <QtCore/QAbstractListModel> +#include <QtDeclarative/QDeclarativeContext> +#include <QtDeclarative/QDeclarativeEngine> + +using namespace WebCore; + +namespace WebKit { + +static QHash<int, QByteArray> createRoleNamesHash(); + +class PopupMenuItemModel : public QAbstractListModel { + Q_OBJECT + +public: + enum Roles { + GroupRole = Qt::UserRole, + EnabledRole = Qt::UserRole + 1, + SelectedRole = Qt::UserRole + 2, + IsSeparatorRole = Qt::UserRole + 3 + }; + + PopupMenuItemModel(const Vector<WebPopupItem>&, int selectedOriginalIndex); + virtual int rowCount(const QModelIndex& parent = QModelIndex()) const { return m_items.size(); } + virtual QVariant data(const QModelIndex&, int role = Qt::DisplayRole) const; + + Q_INVOKABLE void select(int); + + int selectedOriginalIndex() const; + +private: + struct Item { + Item(const WebPopupItem& webPopupItem, const QString& group, int originalIndex, bool selected) + : text(webPopupItem.m_text) + , toolTip(webPopupItem.m_toolTip) + , group(group) + , originalIndex(originalIndex) + , enabled(webPopupItem.m_isEnabled) + , selected(selected) + , isSeparator(webPopupItem.m_type == WebPopupItem::Separator) + { } + + QString text; + QString toolTip; + QString group; + // Keep track of originalIndex because we don't add the label (group) items to our vector. + int originalIndex; + bool enabled; + bool selected; + bool isSeparator; + }; + + void buildItems(const Vector<WebPopupItem>& webPopupItems, int selectedOriginalIndex); + + Vector<Item> m_items; + int m_selectedModelIndex; +}; + +class ItemSelectorContextObject : public QObject { + Q_OBJECT + Q_PROPERTY(QRect elementRect READ elementRect CONSTANT FINAL) + Q_PROPERTY(QObject* items READ items CONSTANT FINAL) + +public: + ItemSelectorContextObject(const IntRect& elementRect, const Vector<WebPopupItem>&, int selectedIndex); + + QRect elementRect() const { return m_elementRect; } + PopupMenuItemModel* items() { return &m_items; } + + Q_INVOKABLE void accept(int index = -1); + Q_INVOKABLE void reject() { emit rejected(); } + +Q_SIGNALS: + void acceptedWithOriginalIndex(int); + void rejected(); + +private: + QRect m_elementRect; + PopupMenuItemModel m_items; +}; + +ItemSelectorContextObject::ItemSelectorContextObject(const IntRect& elementRect, const Vector<WebPopupItem>& webPopupItems, int selectedIndex) + : m_elementRect(elementRect) + , m_items(webPopupItems, selectedIndex) +{ +} + +void ItemSelectorContextObject::accept(int index) +{ + if (index != -1) + m_items.select(index); + int originalIndex = m_items.selectedOriginalIndex(); + emit acceptedWithOriginalIndex(originalIndex); +} + +static QHash<int, QByteArray> createRoleNamesHash() +{ + QHash<int, QByteArray> roles; + roles[Qt::DisplayRole] = "text"; + roles[Qt::ToolTipRole] = "tooltip"; + roles[PopupMenuItemModel::GroupRole] = "group"; + roles[PopupMenuItemModel::EnabledRole] = "enabled"; + roles[PopupMenuItemModel::SelectedRole] = "selected"; + roles[PopupMenuItemModel::IsSeparatorRole] = "isSeparator"; + return roles; +} + +PopupMenuItemModel::PopupMenuItemModel(const Vector<WebPopupItem>& webPopupItems, int selectedOriginalIndex) + : m_selectedModelIndex(-1) +{ + static QHash<int, QByteArray> roles = createRoleNamesHash(); + setRoleNames(roles); + buildItems(webPopupItems, selectedOriginalIndex); +} + +QVariant PopupMenuItemModel::data(const QModelIndex& index, int role) const +{ + if (!index.isValid() || index.row() < 0 || index.row() >= m_items.size()) + return QVariant(); + + const Item& item = m_items[index.row()]; + if (item.isSeparator) { + if (role == IsSeparatorRole) + return true; + return QVariant(); + } + + switch (role) { + case Qt::DisplayRole: + return item.text; + case Qt::ToolTipRole: + return item.toolTip; + case GroupRole: + return item.group; + case EnabledRole: + return item.enabled; + case SelectedRole: + return item.selected; + case IsSeparatorRole: + return false; + } + + return QVariant(); +} + +void PopupMenuItemModel::select(int index) +{ + int oldIndex = m_selectedModelIndex; + if (index == oldIndex) + return; + if (index < 0 || index >= m_items.size()) + return; + Item& item = m_items[index]; + if (!item.enabled) + return; + + Item& oldItem = m_items[oldIndex]; + oldItem.selected = false; + item.selected = true; + m_selectedModelIndex = index; + + emit dataChanged(this->index(oldIndex), this->index(oldIndex)); + emit dataChanged(this->index(index), this->index(index)); +} + +int PopupMenuItemModel::selectedOriginalIndex() const +{ + if (m_selectedModelIndex == -1) + return -1; + return m_items[m_selectedModelIndex].originalIndex; +} + +void PopupMenuItemModel::buildItems(const Vector<WebPopupItem>& webPopupItems, int selectedOriginalIndex) +{ + QString currentGroup; + m_items.reserveInitialCapacity(webPopupItems.size()); + for (int i = 0; i < webPopupItems.size(); i++) { + const WebPopupItem& webPopupItem = webPopupItems[i]; + if (webPopupItem.m_isLabel) { + currentGroup = webPopupItem.m_text; + continue; + } + const bool selected = i == selectedOriginalIndex; + if (selected) + m_selectedModelIndex = m_items.size(); + m_items.append(Item(webPopupItem, currentGroup, i, selected)); + } +} + +WebPopupMenuProxyQt::WebPopupMenuProxyQt(WebPopupMenuProxy::Client* client, QQuickWebView* webView) + : WebPopupMenuProxy(client) + , m_webView(webView) +{ +} + +WebPopupMenuProxyQt::~WebPopupMenuProxyQt() +{ +} + +void WebPopupMenuProxyQt::showPopupMenu(const IntRect& rect, WebCore::TextDirection, double, const Vector<WebPopupItem>& items, const PlatformPopupMenuData&, int32_t selectedIndex) +{ + m_selectedIndex = selectedIndex; + + ItemSelectorContextObject* contextObject = new ItemSelectorContextObject(rect, items, m_selectedIndex); + createItem(contextObject); + if (!m_itemSelector) { + notifyValueChanged(); + return; + } +} + +void WebPopupMenuProxyQt::hidePopupMenu() +{ + m_itemSelector.clear(); + m_context.clear(); + notifyValueChanged(); +} + +void WebPopupMenuProxyQt::selectIndex(int index) +{ + m_selectedIndex = index; +} + +void WebPopupMenuProxyQt::createItem(QObject* contextObject) +{ + QDeclarativeComponent* component = m_webView->experimental()->itemSelector(); + if (!component) { + delete contextObject; + return; + } + + createContext(component, contextObject); + QObject* object = component->beginCreate(m_context.get()); + if (!object) { + m_context.clear(); + return; + } + + m_itemSelector = adoptPtr(qobject_cast<QQuickItem*>(object)); + if (!m_itemSelector) { + m_context.clear(); + m_itemSelector.clear(); + return; + } + + connect(contextObject, SIGNAL(acceptedWithOriginalIndex(int)), SLOT(selectIndex(int))); + + // We enqueue these because they are triggered by m_itemSelector and will lead to its destruction. + connect(contextObject, SIGNAL(acceptedWithOriginalIndex(int)), SLOT(hidePopupMenu()), Qt::QueuedConnection); + connect(contextObject, SIGNAL(rejected()), SLOT(hidePopupMenu()), Qt::QueuedConnection); + + QQuickWebViewPrivate::get(m_webView)->setViewInAttachedProperties(m_itemSelector.get()); + component->completeCreate(); + + m_itemSelector->setParentItem(m_webView); +} + +void WebPopupMenuProxyQt::createContext(QDeclarativeComponent* component, QObject* contextObject) +{ + QDeclarativeContext* baseContext = component->creationContext(); + if (!baseContext) + baseContext = QDeclarativeEngine::contextForObject(m_webView); + m_context = adoptPtr(new QDeclarativeContext(baseContext)); + + contextObject->setParent(m_context.get()); + m_context->setContextProperty(QLatin1String("model"), contextObject); + m_context->setContextObject(contextObject); +} + +void WebPopupMenuProxyQt::notifyValueChanged() +{ + if (m_client) { + m_client->valueChangedForPopupMenu(this, m_selectedIndex); + invalidate(); + } +} + +} // namespace WebKit + +// Since we define QObjects in WebPopupMenuProxyQt.cpp, this will trigger moc to run on .cpp. +#include "WebPopupMenuProxyQt.moc" + +// And we can't compile the moc for WebPopupMenuProxyQt.h by itself, since it doesn't include "config.h" +#include "moc_WebPopupMenuProxyQt.cpp" diff --git a/Source/WebKit2/UIProcess/qt/WebPopupMenuProxyQt.h b/Source/WebKit2/UIProcess/qt/WebPopupMenuProxyQt.h new file mode 100644 index 000000000..ea22bbdd6 --- /dev/null +++ b/Source/WebKit2/UIProcess/qt/WebPopupMenuProxyQt.h @@ -0,0 +1,76 @@ +/* + * Copyright (C) 2010 Apple Inc. All rights reserved. + * Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies) + * + * 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 WebPopupMenuProxyQt_h +#define WebPopupMenuProxyQt_h + +#include "WebPopupMenuProxy.h" + +#include <QtCore/QObject> +#include <wtf/OwnPtr.h> + +class QDeclarativeComponent; +class QDeclarativeContext; +class QQuickWebView; +class QQuickItem; + +namespace WebKit { + +class WebPopupMenuProxyQt : public QObject, public WebPopupMenuProxy { + Q_OBJECT + +public: + static PassRefPtr<WebPopupMenuProxyQt> create(WebPopupMenuProxy::Client* client, QQuickWebView* webView) + { + return adoptRef(new WebPopupMenuProxyQt(client, webView)); + } + ~WebPopupMenuProxyQt(); + + virtual void showPopupMenu(const WebCore::IntRect&, WebCore::TextDirection, double pageScaleFactor, const Vector<WebPopupItem>&, const PlatformPopupMenuData&, int32_t selectedIndex); + +public Q_SLOTS: + virtual void hidePopupMenu(); + +private Q_SLOTS: + void selectIndex(int); + +private: + WebPopupMenuProxyQt(WebPopupMenuProxy::Client*, QQuickWebView*); + void createItem(QObject*); + void createContext(QDeclarativeComponent*, QObject*); + + void notifyValueChanged(); + + OwnPtr<QDeclarativeContext> m_context; + OwnPtr<QQuickItem> m_itemSelector; + + QQuickWebView* m_webView; + int32_t m_selectedIndex; +}; + +} // namespace WebKit + +#endif // WebPopupMenuProxyQt_h diff --git a/Source/WebKit2/UIProcess/qt/WebPreferencesQt.cpp b/Source/WebKit2/UIProcess/qt/WebPreferencesQt.cpp new file mode 100644 index 000000000..fae4a2d76 --- /dev/null +++ b/Source/WebKit2/UIProcess/qt/WebPreferencesQt.cpp @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2010 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 "WebPreferences.h" + +namespace WebKit { + +void WebPreferences::platformInitializeStore() +{ +} + +void WebPreferences::platformUpdateStringValueForKey(const String&, const String&) +{ +} + +void WebPreferences::platformUpdateBoolValueForKey(const String&, bool) +{ +} + +void WebPreferences::platformUpdateUInt32ValueForKey(const String&, uint32_t) +{ +} + +void WebPreferences::platformUpdateDoubleValueForKey(const String&, double) +{ +} + +} // namespace WebKit |
