/* 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 "APICast.h" #include "BridgeJSC.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 "FrameSelection.h" #include "FrameTree.h" #include "FrameView.h" #include "GCController.h" #include "GraphicsContext.h" #include "HTMLFormElement.h" #include "HTMLMetaElement.h" #include "HitTestResult.h" #include "HTTPParsers.h" #include "IconDatabase.h" #include "InspectorController.h" #include "JavaScript.h" #include "JSDOMBinding.h" #include "JSDOMWindowBase.h" #include "JSLock.h" #include "JSObject.h" #include "JSRetainPtr.h" #include "OpaqueJSString.h" #include "NetworkingContext.h" #include "NodeList.h" #include "Page.h" #include "PlatformMouseEvent.h" #include "PlatformWheelEvent.h" #include "PrintContext.h" #include "PropertyDescriptor.h" #include "PutPropertySlot.h" #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 "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 "qwebscriptworld.h" #include "qwebscriptworld_p.h" #include "runtime_object.h" #include "runtime_root.h" #if USE(TEXTURE_MAPPER) #include "texmap/TextureMapper.h" #include "texmap/TextureMapperLayer.h" #endif #include "wtf/HashMap.h" #include #include #include #include #include #if HAVE(QTPRINTSUPPORT) #include #endif #include #include using namespace WebCore; // from text/qfont.cpp QT_BEGIN_NAMESPACE extern Q_GUI_EXPORT int qt_defaultDpi(); QT_END_NAMESPACE 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 USE(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) renderCompositedLayers(context, IntRect(clip.boundingRect())); renderFrameExtras(context, QFlags(QWebFrame::ScrollBarLayer) | QWebFrame::PanIconLayer, clip); #endif } #endif #if USE(ACCELERATED_COMPOSITING) void QWebFramePrivate::renderCompositedLayers(GraphicsContext* context, const IntRect& clip) { if (!rootTextureMapperLayer || !textureMapper) return; textureMapper->setGraphicsContext(context); textureMapper->setImageInterpolationQuality(context->imageInterpolationQuality()); textureMapper->setTextDrawingMode(context->textDrawingMode()); QPainter* painter = context->platformContext(); const QTransform transform = painter->worldTransform(); const TransformationMatrix matrix( transform.m11(), transform.m12(), 0, transform.m13(), transform.m21(), transform.m22(), 0, transform.m23(), 0, 0, 1, 0, transform.m31(), transform.m32(), 0, transform.m33() ); rootTextureMapperLayer->setTransform(matrix); rootTextureMapperLayer->setOpacity(painter->opacity()); textureMapper->beginPainting(); textureMapper->beginClip(matrix, clip); rootTextureMapperLayer->paint(); textureMapper->endClip(); textureMapper->endPainting(); } #endif // This code is copied from ChromeClientGtk.cpp. static void coalesceRectsIfPossible(const QRect& clipRect, QVector& rects) { const unsigned int rectThreshold = 10; const float wastedSpaceThreshold = 0.75f; bool useUnionedRect = (rects.size() <= 1) || (rects.size() > rectThreshold); if (!useUnionedRect) { // Attempt to guess whether or not we should use the unioned rect or the individual rects. // We do this by computing the percentage of "wasted space" in the union. If that wasted space // is too large, then we will do individual rect painting instead. float unionPixels = (clipRect.width() * clipRect.height()); float singlePixels = 0; for (size_t i = 0; i < rects.size(); ++i) singlePixels += rects[i].width() * rects[i].height(); float wastedSpace = 1 - (singlePixels / unionPixels); if (wastedSpace <= wastedSpaceThreshold) useUnionedRect = true; } if (!useUnionedRect) return; rects.clear(); rects.append(clipRect); } void QWebFramePrivate::renderRelativeCoords(GraphicsContext* context, QFlags layers, 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 (layers & QWebFrame::ContentsLayer) { QRect clipBoundingRect = clip.boundingRect(); coalesceRectsIfPossible(clipBoundingRect, vector); 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) renderCompositedLayers(context, IntRect(clipBoundingRect)); #endif } renderFrameExtras(context, layers, clip); #if ENABLE(INSPECTOR) if (frame->page()->inspectorController()->highlightedNode()) { context->save(); frame->page()->inspectorController()->drawHighlight(*context); context->restore(); } #endif } void QWebFramePrivate::renderFrameExtras(GraphicsContext* context, QFlags layers, const QRegion& clip) { if (!(layers & (QWebFrame::PanIconLayer | QWebFrame::ScrollBarLayer))) return; QPainter* painter = context->platformContext(); WebCore::FrameView* view = frame->view(); QVector vector = clip.rects(); 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 (layers & 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 (layers & QWebFrame::PanIconLayer) view->paintPanScrollIcon(context); #endif painter->restore(); } } void QWebFramePrivate::emitUrlChanged() { url = frame->document()->url(); emit q->urlChanged(url); } void QWebFramePrivate::_q_orientationChanged() { #if ENABLE(ORIENTATION_EVENTS) int orientation; WebCore::Frame* frame = core(q); switch (m_orientation.reading()->orientation()) { case QOrientationReading::TopUp: orientation = 0; break; case QOrientationReading::TopDown: orientation = 180; break; case QOrientationReading::LeftUp: orientation = -90; break; case QOrientationReading::RightUp: orientation = 90; break; case QOrientationReading::FaceUp: case QOrientationReading::FaceDown: // WebCore unable to handle it default: return; } frame->sendOrientationChangeEvent(orientation); #endif } void QWebFramePrivate::didClearWindowObject() { emit q->javaScriptWindowObjectCleared(); } /*! \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{