/* 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" #include "Bridge.h" #include "CallFrame.h" #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" #include "GCController.h" #include "GraphicsContext.h" #include "HTMLMetaElement.h" #include "HitTestResult.h" #include "IconDatabase.h" #include "InspectorController.h" #include "JSDOMBinding.h" #include "JSDOMWindowBase.h" #include "JSLock.h" #include "JSObject.h" #include "NodeList.h" #include "Page.h" #include "PlatformMouseEvent.h" #include "PlatformWheelEvent.h" #include "PrintContext.h" #include "PutPropertySlot.h" #include "RenderTreeAsText.h" #include "RenderView.h" #include "ResourceRequest.h" #include "ScriptController.h" #include "ScriptSourceCode.h" #include "ScriptValue.h" #include "Scrollbar.h" #include "SelectionController.h" #include "SubstituteData.h" #include "SVGSMILElement.h" #include "TiledBackingStore.h" #include "htmlediting.h" #include "markup.h" #include "qt_instance.h" #include "qt_runtime.h" #include "qwebelement.h" #include "qwebframe_p.h" #include "qwebpage.h" #include "qwebpage_p.h" #include "qwebsecurityorigin.h" #include "qwebsecurityorigin_p.h" #include "runtime_object.h" #include "runtime_root.h" #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 void QWEBKIT_EXPORT qt_drt_setMediaType(QWebFrame* qframe, const QString& type) { WebCore::Frame* frame = QWebFramePrivate::core(qframe); WebCore::FrameView* view = frame->view(); view->setMediaType(type); frame->document()->updateStyleSelector(); view->forceLayout(); } bool QWEBKIT_EXPORT qt_drt_hasDocumentElement(QWebFrame* qframe) { return QWebFramePrivate::core(qframe)->document()->documentElement(); } void QWEBKIT_EXPORT qt_drt_setJavaScriptProfilingEnabled(QWebFrame* qframe, bool enabled) { #if ENABLE(JAVASCRIPT_DEBUGGER) Frame* frame = QWebFramePrivate::core(qframe); InspectorController* controller = frame->page()->inspectorController(); if (!controller) return; if (enabled) controller->enableProfiler(); else controller->disableProfiler(); #endif } // Pause a given CSS animation or transition on the target node at a specific time. // If the animation or transition is already paused, it will update its pause time. // This method is only intended to be used for testing the CSS animation and transition system. bool QWEBKIT_EXPORT qt_drt_pauseAnimation(QWebFrame *qframe, const QString &animationName, double time, const QString &elementId) { Frame* frame = QWebFramePrivate::core(qframe); if (!frame) return false; AnimationController* controller = frame->animation(); if (!controller) return false; Document* doc = frame->document(); Q_ASSERT(doc); Node* coreNode = doc->getElementById(elementId); if (!coreNode || !coreNode->renderer()) return false; return controller->pauseAnimationAtTime(coreNode->renderer(), animationName, time); } bool QWEBKIT_EXPORT qt_drt_pauseTransitionOfProperty(QWebFrame *qframe, const QString &propertyName, double time, const QString &elementId) { Frame* frame = QWebFramePrivate::core(qframe); if (!frame) return false; AnimationController* controller = frame->animation(); if (!controller) return false; Document* doc = frame->document(); Q_ASSERT(doc); Node* coreNode = doc->getElementById(elementId); if (!coreNode || !coreNode->renderer()) return false; return controller->pauseTransitionAtTime(coreNode->renderer(), propertyName, time); } // Pause a given SVG animation on the target node at a specific time. // This method is only intended to be used for testing the SVG animation system. bool QWEBKIT_EXPORT qt_drt_pauseSVGAnimation(QWebFrame *qframe, const QString &animationId, double time, const QString &elementId) { #if !ENABLE(SVG) return false; #else Frame* frame = QWebFramePrivate::core(qframe); if (!frame) return false; Document* doc = frame->document(); Q_ASSERT(doc); if (!doc->svgExtensions()) return false; Node* coreNode = doc->getElementById(animationId); if (!coreNode || !SVGSMILElement::isSMILElement(coreNode)) return false; return doc->accessSVGExtensions()->sampleAnimationAtTime(elementId, static_cast(coreNode), time); #endif } // Returns the total number of currently running animations (includes both CSS transitions and CSS animations). int QWEBKIT_EXPORT qt_drt_numberOfActiveAnimations(QWebFrame *qframe) { Frame* frame = QWebFramePrivate::core(qframe); if (!frame) return false; AnimationController* controller = frame->animation(); if (!controller) return false; return controller->numberOfActiveAnimations(); } void QWEBKIT_EXPORT qt_drt_clearFrameName(QWebFrame* qFrame) { Frame* frame = QWebFramePrivate::core(qFrame); frame->tree()->clearName(); } int QWEBKIT_EXPORT qt_drt_javaScriptObjectsCount() { return JSDOMWindowBase::commonJSGlobalData()->heap.globalObjectCount(); } void QWEBKIT_EXPORT qt_drt_garbageCollector_collect() { gcController().garbageCollectNow(); } void QWEBKIT_EXPORT qt_drt_garbageCollector_collectOnAlternateThread(bool waitUntilDone) { gcController().garbageCollectOnAlternateThreadForDebugging(waitUntilDone); } // Returns the value of counter in the element specified by \a id. QString QWEBKIT_EXPORT qt_drt_counterValueForElementById(QWebFrame* qFrame, const QString& id) { Frame* frame = QWebFramePrivate::core(qFrame); if (Document* document = frame->document()) { Element* element = document->getElementById(id); return WebCore::counterValueForElement(element); } return QString(); } int QWEBKIT_EXPORT qt_drt_pageNumberForElementById(QWebFrame* qFrame, const QString& id, float width, float height) { Frame* frame = QWebFramePrivate::core(qFrame); if (!frame) return -1; Element* element = frame->document()->getElementById(AtomicString(id)); if (!element) return -1; return PrintContext::pageNumberForElement(element, FloatSize(width, height)); } int QWEBKIT_EXPORT qt_drt_numberOfPages(QWebFrame* qFrame, float width, float height) { Frame* frame = QWebFramePrivate::core(qFrame); if (!frame) return -1; return PrintContext::numberOfPages(frame, FloatSize(width, height)); } // Suspend active DOM objects in this frame. void QWEBKIT_EXPORT qt_suspendActiveDOMObjects(QWebFrame* qFrame) { Frame* frame = QWebFramePrivate::core(qFrame); if (frame->document()) frame->document()->suspendActiveDOMObjects(); } // Resume active DOM objects in this frame. void QWEBKIT_EXPORT qt_resumeActiveDOMObjects(QWebFrame* qFrame) { Frame* frame = QWebFramePrivate::core(qFrame); if (frame->document()) frame->document()->resumeActiveDOMObjects(); } void QWEBKIT_EXPORT qt_drt_evaluateScriptInIsolatedWorld(QWebFrame* qFrame, int worldId, const QString& script) { Frame* frame = QWebFramePrivate::core(qFrame); if (frame) JSC::JSValue result = frame->script()->executeScriptInWorld(mainThreadNormalWorld(), script, true).jsValue(); } 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); } QWebFrameData::QWebFrameData(WebCore::Page* parentPage, WebCore::Frame* parentFrame, WebCore::HTMLFrameOwnerElement* ownerFrameElement, const WebCore::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(); } } #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->layoutIfNeededRecursive(); 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::ContentsLayer) { context->save(); int scrollX = view->scrollX(); int scrollY = view->scrollY(); QRect rect = intersectedRect; 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 (layer & QWebFrame::ScrollBarLayer && !view->scrollbarsSuppressed() && (view->horizontalScrollbar() || view->verticalScrollbar())) { context->save(); QRect rect = intersectedRect; context->translate(x, y); rect.translate(-x, -y); view->paintScrollbars(context, rect); context->restore(); } #if ENABLE(PAN_SCROLLING) if (layer & QWebFrame::PanIconLayer) view->paintPanScrollIcon(context); #endif painter->restore(); } } /*! \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{