/* Copyright (C) 2008,2009 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 "qwebframe.h" #if USE(JSC) #include "BridgeJSC.h" #include "CallFrame.h" #elif USE(V8) #include "V8Binding.h" #endif #include "Document.h" #include "DocumentLoader.h" #include "DragData.h" #include "Element.h" #include "FocusController.h" #include "Frame.h" #include "FrameLoaderClientQt.h" #include "FrameTree.h" #include "FrameView.h" #if USE(JSC) #include "GCController.h" #elif USE(V8) #include "V8GCController.h" #endif #include "GraphicsContext.h" #include "HTMLMetaElement.h" #include "HitTestResult.h" #include "HTTPParsers.h" #include "IconDatabase.h" #include "InspectorController.h" #if USE(JSC) #include "JSDOMBinding.h" #include "JSDOMWindowBase.h" #include "JSLock.h" #include "JSObject.h" #elif USE(V8) #include "V8DOMWrapper.h" #include "V8DOMWindowShell.h" #endif #include "NetworkingContext.h" #include "NodeList.h" #include "Page.h" #include "PlatformMouseEvent.h" #include "PlatformWheelEvent.h" #include "PrintContext.h" #if USE(JSC) #include "PutPropertySlot.h" #endif #include "RenderLayer.h" #include "RenderTreeAsText.h" #include "RenderView.h" #include "ResourceRequest.h" #include "ScriptController.h" #include "ScriptSourceCode.h" #include "ScriptValue.h" #include "Scrollbar.h" #include "Settings.h" #include "SelectionController.h" #include "SubstituteData.h" #include "SVGSMILElement.h" #include "TiledBackingStore.h" #include "htmlediting.h" #include "markup.h" #if USE(JSC) #include "qt_instance.h" #include "qt_runtime.h" #endif #include "qwebelement.h" #include "qwebframe_p.h" #include "qwebpage.h" #include "qwebpage_p.h" #include "qwebsecurityorigin.h" #include "qwebsecurityorigin_p.h" #include "qwebscriptworld.h" #include "qwebscriptworld_p.h" #if USE(JSC) #include "runtime_object.h" #include "runtime_root.h" #endif #if USE(TEXTURE_MAPPER) #include "texmap/TextureMapper.h" #include "texmap/TextureMapperPlatformLayer.h" #endif #include "wtf/HashMap.h" #include #include #include #include #include #include #include #include using namespace WebCore; // from text/qfont.cpp QT_BEGIN_NAMESPACE extern Q_GUI_EXPORT int qt_defaultDpi(); QT_END_NAMESPACE bool QWEBKIT_EXPORT qtwebkit_webframe_scrollOverflow(QWebFrame* qFrame, int dx, int dy, const QPoint& pos) { WebCore::Frame* frame = QWebFramePrivate::core(qFrame); if (!frame || !frame->document() || !frame->view() || !frame->eventHandler()) return false; QPoint contentsPos = frame->view()->windowToContents(pos); Node* node = frame->document()->elementFromPoint(contentsPos.x(), contentsPos.y()); if (!node) return false; RenderObject* renderer = node->renderer(); if (!renderer) return false; if (renderer->isListBox()) return false; RenderLayer* renderLayer = renderer->enclosingLayer(); if (!renderLayer) return false; bool scrolledHorizontal = false; bool scrolledVertical = false; do { if (dx > 0) scrolledHorizontal = renderLayer->scroll(ScrollRight, ScrollByPixel, dx); else if (dx < 0) scrolledHorizontal = renderLayer->scroll(ScrollLeft, ScrollByPixel, qAbs(dx)); if (dy > 0) scrolledVertical = renderLayer->scroll(ScrollDown, ScrollByPixel, dy); else if (dy < 0) scrolledVertical = renderLayer->scroll(ScrollUp, ScrollByPixel, qAbs(dy)); if (scrolledHorizontal || scrolledVertical) return true; renderLayer = renderLayer->parent(); } while (renderLayer); return false; } /*! \internal Scrolls nested frames starting at this frame, \a dx pixels to the right and \a dy pixels downward. Both \a dx and \a dy may be negative. First attempts to scroll elements with CSS overflow at position pos, followed by this frame. If this frame doesn't scroll, attempts to scroll the parent */ void QWEBKIT_EXPORT qtwebkit_webframe_scrollRecursively(QWebFrame* qFrame, int dx, int dy, const QPoint& pos) { if (!qFrame) return; if (qtwebkit_webframe_scrollOverflow(qFrame, dx, dy, pos)) return; bool scrollHorizontal = false; bool scrollVertical = false; do { if (dx > 0) // scroll right scrollHorizontal = qFrame->scrollBarValue(Qt::Horizontal) < qFrame->scrollBarMaximum(Qt::Horizontal); else if (dx < 0) // scroll left scrollHorizontal = qFrame->scrollBarValue(Qt::Horizontal) > qFrame->scrollBarMinimum(Qt::Horizontal); if (dy > 0) // scroll down scrollVertical = qFrame->scrollBarValue(Qt::Vertical) < qFrame->scrollBarMaximum(Qt::Vertical); else if (dy < 0) //scroll up scrollVertical = qFrame->scrollBarValue(Qt::Vertical) > qFrame->scrollBarMinimum(Qt::Vertical); if (scrollHorizontal || scrollVertical) { qFrame->scroll(dx, dy); return; } qFrame = qFrame->parentFrame(); } while (qFrame); } static inline ResourceRequestCachePolicy cacheLoadControlToCachePolicy(uint cacheLoadControl) { switch (cacheLoadControl) { case QNetworkRequest::AlwaysNetwork: return WebCore::ReloadIgnoringCacheData; case QNetworkRequest::PreferCache: return WebCore::ReturnCacheDataElseLoad; case QNetworkRequest::AlwaysCache: return WebCore::ReturnCacheDataDontLoad; default: break; } return WebCore::UseProtocolCachePolicy; } QWebFrameData::QWebFrameData(WebCore::Page* parentPage, WebCore::Frame* parentFrame, WebCore::HTMLFrameOwnerElement* ownerFrameElement, const WTF::String& frameName) : name(frameName) , ownerElement(ownerFrameElement) , page(parentPage) , allowsScrolling(true) , marginWidth(0) , marginHeight(0) { frameLoaderClient = new FrameLoaderClientQt(); frame = Frame::create(page, ownerElement, frameLoaderClient); // FIXME: All of the below should probably be moved over into WebCore frame->tree()->setName(name); if (parentFrame) parentFrame->tree()->appendChild(frame); } void QWebFramePrivate::init(QWebFrame *qframe, QWebFrameData *frameData) { q = qframe; allowsScrolling = frameData->allowsScrolling; marginWidth = frameData->marginWidth; marginHeight = frameData->marginHeight; frame = frameData->frame.get(); frameLoaderClient = frameData->frameLoaderClient; frameLoaderClient->setFrame(qframe, frame); frame->init(); } void QWebFramePrivate::setPage(QWebPage* newPage) { if (page == newPage) return; // The QWebFrame is created as a child of QWebPage or a parent QWebFrame. // That adds it to QObject's internal children list and ensures it will be // deleted when parent QWebPage is deleted. Reparent if needed. if (q->parent() == qobject_cast(page)) q->setParent(newPage); page = newPage; emit q->pageChanged(); } WebCore::Scrollbar* QWebFramePrivate::horizontalScrollBar() const { if (!frame->view()) return 0; return frame->view()->horizontalScrollbar(); } WebCore::Scrollbar* QWebFramePrivate::verticalScrollBar() const { if (!frame->view()) return 0; return frame->view()->verticalScrollbar(); } #if ENABLE(TILED_BACKING_STORE) void QWebFramePrivate::renderFromTiledBackingStore(GraphicsContext* context, const QRegion& clip) { ASSERT(frame->tiledBackingStore()); if (!frame->view() || !frame->contentRenderer()) return; QVector vector = clip.rects(); if (vector.isEmpty()) return; QPainter* painter = context->platformContext(); WebCore::FrameView* view = frame->view(); int scrollX = view->scrollX(); int scrollY = view->scrollY(); context->translate(-scrollX, -scrollY); for (int i = 0; i < vector.size(); ++i) { const QRect& clipRect = vector.at(i); painter->save(); QRect rect = clipRect.translated(scrollX, scrollY); painter->setClipRect(rect, Qt::IntersectClip); frame->tiledBackingStore()->paint(context, rect); painter->restore(); } #if USE(ACCELERATED_COMPOSITING) && USE(TEXTURE_MAPPER) renderCompositedLayers(context, IntRect(clip.boundingRect())); renderRelativeCoords(context, (QWebFrame::RenderLayer)(QWebFrame::ScrollBarLayer | QWebFrame::PanIconLayer), clip); #endif } #endif #if USE(ACCELERATED_COMPOSITING) && USE(TEXTURE_MAPPER) void QWebFramePrivate::renderCompositedLayers(GraphicsContext* context, const IntRect& clip) { if (!rootGraphicsLayer) return; textureMapper->setGraphicsContext(context); textureMapper->setImageInterpolationQuality(context->imageInterpolationQuality()); textureMapper->setTextDrawingMode(context->textDrawingMode()); QPainter* painter = context->platformContext(); FrameView* view = frame->view(); painter->save(); painter->beginNativePainting(); TextureMapperContentLayer::PaintOptions options; options.visibleRect = clip; options.targetRect = view->frameRect(); options.viewportSize = view->size(); options.opacity = painter->opacity(); rootGraphicsLayer->paint(textureMapper.get(), options); painter->endNativePainting(); painter->restore(); } #endif void QWebFramePrivate::renderRelativeCoords(GraphicsContext* context, QWebFrame::RenderLayer layer, const QRegion& clip) { if (!frame->view() || !frame->contentRenderer()) return; QVector vector = clip.rects(); if (vector.isEmpty()) return; QPainter* painter = context->platformContext(); WebCore::FrameView* view = frame->view(); view->updateLayoutAndStyleIfNeededRecursive(); if (layer & QWebFrame::ContentsLayer) { for (int i = 0; i < vector.size(); ++i) { const QRect& clipRect = vector.at(i); QRect rect = clipRect.intersected(view->frameRect()); context->save(); painter->setClipRect(clipRect, Qt::IntersectClip); int x = view->x(); int y = view->y(); int scrollX = view->scrollX(); int scrollY = view->scrollY(); context->translate(x, y); rect.translate(-x, -y); context->translate(-scrollX, -scrollY); rect.translate(scrollX, scrollY); context->clip(view->visibleContentRect()); view->paintContents(context, rect); context->restore(); } #if USE(ACCELERATED_COMPOSITING) && USE(TEXTURE_MAPPER) renderCompositedLayers(context, IntRect(clip.boundingRect())); #endif } if (layer & (QWebFrame::PanIconLayer | QWebFrame::ScrollBarLayer)) { for (int i = 0; i < vector.size(); ++i) { const QRect& clipRect = vector.at(i); QRect intersectedRect = clipRect.intersected(view->frameRect()); painter->save(); painter->setClipRect(clipRect, Qt::IntersectClip); int x = view->x(); int y = view->y(); if (layer & QWebFrame::ScrollBarLayer && !view->scrollbarsSuppressed() && (view->horizontalScrollbar() || view->verticalScrollbar())) { QRect rect = intersectedRect; context->translate(x, y); rect.translate(-x, -y); view->paintScrollbars(context, rect); context->translate(-x, -y); } #if ENABLE(PAN_SCROLLING) if (layer & QWebFrame::PanIconLayer) view->paintPanScrollIcon(context); #endif painter->restore(); } } } void QWebFrame::orientationChanged() { #if ENABLE(ORIENTATION_EVENTS) && ENABLE(DEVICE_ORIENTATION) int orientation; WebCore::Frame* frame = QWebFramePrivate::core(this); switch (d->m_orientation.reading()->orientation()) { case QtMobility::QOrientationReading::TopUp: orientation = 0; break; case QtMobility::QOrientationReading::TopDown: orientation = 180; break; case QtMobility::QOrientationReading::LeftUp: orientation = -90; break; case QtMobility::QOrientationReading::RightUp: orientation = 90; break; case QtMobility::QOrientationReading::FaceUp: case QtMobility::QOrientationReading::FaceDown: // WebCore unable to handle it default: return; } frame->sendOrientationChangeEvent(orientation); #endif } /*! \class QWebFrame \since 4.4 \brief The QWebFrame class represents a frame in a web page. \inmodule QtWebKit QWebFrame represents a frame inside a web page. Each QWebPage object contains at least one frame, the main frame, obtained using QWebPage::mainFrame(). Additional frames will be created for HTML \c{} or \c{