1/*
2    Copyright (C) 2008,2009 Nokia Corporation and/or its subsidiary(-ies)
3    Copyright (C) 2007 Staikos Computing Services Inc.
4
5    This library is free software; you can redistribute it and/or
6    modify it under the terms of the GNU Library General Public
7    License as published by the Free Software Foundation; either
8    version 2 of the License, or (at your option) any later version.
9
10    This library is distributed in the hope that it will be useful,
11    but WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13    Library General Public License for more details.
14
15    You should have received a copy of the GNU Library General Public License
16    along with this library; see the file COPYING.LIB.  If not, write to
17    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18    Boston, MA 02110-1301, USA.
19*/
20
21#include "config.h"
22#include "qwebframe.h"
23
24#if USE(JSC)
25#include "BridgeJSC.h"
26#include "CallFrame.h"
27#elif USE(V8)
28#include "V8Binding.h"
29#endif
30#include "Document.h"
31#include "DocumentLoader.h"
32#include "DragData.h"
33#include "Element.h"
34#include "FocusController.h"
35#include "Frame.h"
36#include "FrameLoaderClientQt.h"
37#include "FrameTree.h"
38#include "FrameView.h"
39#if USE(JSC)
40#include "GCController.h"
41#elif USE(V8)
42#include "V8GCController.h"
43#endif
44#include "GraphicsContext.h"
45#include "HTMLMetaElement.h"
46#include "HitTestResult.h"
47#include "HTTPParsers.h"
48#include "IconDatabase.h"
49#include "InspectorController.h"
50#if USE(JSC)
51#include "JSDOMBinding.h"
52#include "JSDOMWindowBase.h"
53#include "JSLock.h"
54#include "JSObject.h"
55#elif USE(V8)
56#include "V8DOMWrapper.h"
57#include "V8DOMWindowShell.h"
58#endif
59#include "NetworkingContext.h"
60#include "NodeList.h"
61#include "Page.h"
62#include "PlatformMouseEvent.h"
63#include "PlatformWheelEvent.h"
64#include "PrintContext.h"
65#if USE(JSC)
66#include "PutPropertySlot.h"
67#endif
68#include "RenderLayer.h"
69#include "RenderTreeAsText.h"
70#include "RenderView.h"
71#include "ResourceRequest.h"
72#include "ScriptController.h"
73#include "ScriptSourceCode.h"
74#include "ScriptValue.h"
75#include "Scrollbar.h"
76#include "Settings.h"
77#include "SelectionController.h"
78#include "SubstituteData.h"
79#include "SVGSMILElement.h"
80#include "TiledBackingStore.h"
81#include "htmlediting.h"
82#include "markup.h"
83#if USE(JSC)
84#include "qt_instance.h"
85#include "qt_runtime.h"
86#endif
87#include "qwebelement.h"
88#include "qwebframe_p.h"
89#include "qwebpage.h"
90#include "qwebpage_p.h"
91#include "qwebsecurityorigin.h"
92#include "qwebsecurityorigin_p.h"
93#include "qwebscriptworld.h"
94#include "qwebscriptworld_p.h"
95#if USE(JSC)
96#include "runtime_object.h"
97#include "runtime_root.h"
98#endif
99#if USE(TEXTURE_MAPPER)
100#include "texmap/TextureMapper.h"
101#include "texmap/TextureMapperPlatformLayer.h"
102#endif
103#include "wtf/HashMap.h"
104#include <QMultiMap>
105#include <qdebug.h>
106#include <qevent.h>
107#include <qfileinfo.h>
108#include <qpainter.h>
109#include <qprinter.h>
110#include <qregion.h>
111#include <qnetworkrequest.h>
112
113using namespace WebCore;
114
115// from text/qfont.cpp
116QT_BEGIN_NAMESPACE
117extern Q_GUI_EXPORT int qt_defaultDpi();
118QT_END_NAMESPACE
119
120bool QWEBKIT_EXPORT qtwebkit_webframe_scrollOverflow(QWebFrame* qFrame, int dx, int dy, const QPoint& pos)
121{
122    WebCore::Frame* frame = QWebFramePrivate::core(qFrame);
123    if (!frame || !frame->document() || !frame->view() || !frame->eventHandler())
124        return false;
125
126    QPoint contentsPos = frame->view()->windowToContents(pos);
127    Node* node = frame->document()->elementFromPoint(contentsPos.x(), contentsPos.y());
128    if (!node)
129        return false;
130
131    RenderObject* renderer = node->renderer();
132    if (!renderer)
133        return false;
134
135    if (renderer->isListBox())
136        return false;
137
138    RenderLayer* renderLayer = renderer->enclosingLayer();
139    if (!renderLayer)
140        return false;
141
142    bool scrolledHorizontal = false;
143    bool scrolledVertical = false;
144
145    do {
146        if (dx > 0)
147            scrolledHorizontal = renderLayer->scroll(ScrollRight, ScrollByPixel, dx);
148        else if (dx < 0)
149            scrolledHorizontal = renderLayer->scroll(ScrollLeft, ScrollByPixel, qAbs(dx));
150
151        if (dy > 0)
152            scrolledVertical = renderLayer->scroll(ScrollDown, ScrollByPixel, dy);
153        else if (dy < 0)
154            scrolledVertical = renderLayer->scroll(ScrollUp, ScrollByPixel, qAbs(dy));
155
156        if (scrolledHorizontal || scrolledVertical)
157            return true;
158
159        renderLayer = renderLayer->parent();
160    } while (renderLayer);
161
162    return false;
163}
164
165
166/*!
167  \internal
168  Scrolls nested frames starting at this frame, \a dx pixels to the right
169  and \a dy pixels downward. Both \a dx and \a dy may be negative. First attempts
170  to scroll elements with CSS overflow at position pos, followed by this frame. If this
171  frame doesn't scroll, attempts to scroll the parent
172*/
173void QWEBKIT_EXPORT qtwebkit_webframe_scrollRecursively(QWebFrame* qFrame, int dx, int dy, const QPoint& pos)
174{
175    if (!qFrame)
176        return;
177
178    if (qtwebkit_webframe_scrollOverflow(qFrame, dx, dy, pos))
179        return;
180
181    bool scrollHorizontal = false;
182    bool scrollVertical = false;
183
184    do {
185        if (dx > 0)  // scroll right
186            scrollHorizontal = qFrame->scrollBarValue(Qt::Horizontal) < qFrame->scrollBarMaximum(Qt::Horizontal);
187        else if (dx < 0)  // scroll left
188            scrollHorizontal = qFrame->scrollBarValue(Qt::Horizontal) > qFrame->scrollBarMinimum(Qt::Horizontal);
189
190        if (dy > 0)  // scroll down
191            scrollVertical = qFrame->scrollBarValue(Qt::Vertical) < qFrame->scrollBarMaximum(Qt::Vertical);
192        else if (dy < 0) //scroll up
193            scrollVertical = qFrame->scrollBarValue(Qt::Vertical) > qFrame->scrollBarMinimum(Qt::Vertical);
194
195        if (scrollHorizontal || scrollVertical) {
196            qFrame->scroll(dx, dy);
197            return;
198        }
199
200        qFrame = qFrame->parentFrame();
201    } while (qFrame);
202}
203
204static inline ResourceRequestCachePolicy cacheLoadControlToCachePolicy(uint cacheLoadControl)
205{
206    switch (cacheLoadControl) {
207    case QNetworkRequest::AlwaysNetwork:
208        return WebCore::ReloadIgnoringCacheData;
209    case QNetworkRequest::PreferCache:
210        return WebCore::ReturnCacheDataElseLoad;
211    case QNetworkRequest::AlwaysCache:
212        return WebCore::ReturnCacheDataDontLoad;
213    default:
214        break;
215    }
216    return WebCore::UseProtocolCachePolicy;
217}
218
219QWebFrameData::QWebFrameData(WebCore::Page* parentPage, WebCore::Frame* parentFrame,
220                             WebCore::HTMLFrameOwnerElement* ownerFrameElement,
221                             const WTF::String& frameName)
222    : name(frameName)
223    , ownerElement(ownerFrameElement)
224    , page(parentPage)
225    , allowsScrolling(true)
226    , marginWidth(0)
227    , marginHeight(0)
228{
229    frameLoaderClient = new FrameLoaderClientQt();
230    frame = Frame::create(page, ownerElement, frameLoaderClient);
231
232    // FIXME: All of the below should probably be moved over into WebCore
233    frame->tree()->setName(name);
234    if (parentFrame)
235        parentFrame->tree()->appendChild(frame);
236}
237
238void QWebFramePrivate::init(QWebFrame *qframe, QWebFrameData *frameData)
239{
240    q = qframe;
241
242    allowsScrolling = frameData->allowsScrolling;
243    marginWidth = frameData->marginWidth;
244    marginHeight = frameData->marginHeight;
245    frame = frameData->frame.get();
246    frameLoaderClient = frameData->frameLoaderClient;
247    frameLoaderClient->setFrame(qframe, frame);
248
249    frame->init();
250}
251
252void QWebFramePrivate::setPage(QWebPage* newPage)
253{
254    if (page == newPage)
255        return;
256
257    // The QWebFrame is created as a child of QWebPage or a parent QWebFrame.
258    // That adds it to QObject's internal children list and ensures it will be
259    // deleted when parent QWebPage is deleted. Reparent if needed.
260    if (q->parent() == qobject_cast<QObject*>(page))
261        q->setParent(newPage);
262
263    page = newPage;
264    emit q->pageChanged();
265}
266
267WebCore::Scrollbar* QWebFramePrivate::horizontalScrollBar() const
268{
269    if (!frame->view())
270        return 0;
271    return frame->view()->horizontalScrollbar();
272}
273
274WebCore::Scrollbar* QWebFramePrivate::verticalScrollBar() const
275{
276    if (!frame->view())
277        return 0;
278    return frame->view()->verticalScrollbar();
279}
280
281#if ENABLE(TILED_BACKING_STORE)
282void QWebFramePrivate::renderFromTiledBackingStore(GraphicsContext* context, const QRegion& clip)
283{
284    ASSERT(frame->tiledBackingStore());
285
286    if (!frame->view() || !frame->contentRenderer())
287        return;
288
289    QVector<QRect> vector = clip.rects();
290    if (vector.isEmpty())
291        return;
292
293    QPainter* painter = context->platformContext();
294
295    WebCore::FrameView* view = frame->view();
296
297    int scrollX = view->scrollX();
298    int scrollY = view->scrollY();
299    context->translate(-scrollX, -scrollY);
300
301    for (int i = 0; i < vector.size(); ++i) {
302        const QRect& clipRect = vector.at(i);
303
304        painter->save();
305
306        QRect rect = clipRect.translated(scrollX, scrollY);
307        painter->setClipRect(rect, Qt::IntersectClip);
308
309        frame->tiledBackingStore()->paint(context, rect);
310
311        painter->restore();
312    }
313
314#if USE(ACCELERATED_COMPOSITING) && USE(TEXTURE_MAPPER)
315    renderCompositedLayers(context, IntRect(clip.boundingRect()));
316    renderFrameExtras(context, QFlags<QWebFrame::RenderLayer>(QWebFrame::ScrollBarLayer) | QWebFrame::PanIconLayer, clip);
317#endif
318}
319#endif
320
321#if USE(ACCELERATED_COMPOSITING) && USE(TEXTURE_MAPPER)
322void QWebFramePrivate::renderCompositedLayers(GraphicsContext* context, const IntRect& clip)
323{
324    if (!rootGraphicsLayer)
325        return;
326
327    textureMapper->setGraphicsContext(context);
328    textureMapper->setImageInterpolationQuality(context->imageInterpolationQuality());
329    textureMapper->setTextDrawingMode(context->textDrawingMode());
330    QPainter* painter = context->platformContext();
331    FrameView* view = frame->view();
332    painter->save();
333    painter->beginNativePainting();
334    TextureMapperContentLayer::PaintOptions options;
335    options.visibleRect = clip;
336    options.targetRect = view->frameRect();
337    options.viewportSize = view->size();
338    options.opacity = painter->opacity();
339    rootGraphicsLayer->paint(textureMapper.get(), options);
340    painter->endNativePainting();
341    painter->restore();
342}
343#endif
344
345void QWebFramePrivate::renderRelativeCoords(GraphicsContext* context, QFlags<QWebFrame::RenderLayer> layers, const QRegion& clip)
346{
347    if (!frame->view() || !frame->contentRenderer())
348        return;
349
350    QVector<QRect> vector = clip.rects();
351    if (vector.isEmpty())
352        return;
353
354    QPainter* painter = context->platformContext();
355
356    WebCore::FrameView* view = frame->view();
357    view->updateLayoutAndStyleIfNeededRecursive();
358
359    if (layers & QWebFrame::ContentsLayer) {
360        for (int i = 0; i < vector.size(); ++i) {
361            const QRect& clipRect = vector.at(i);
362
363            QRect rect = clipRect.intersected(view->frameRect());
364
365            context->save();
366            painter->setClipRect(clipRect, Qt::IntersectClip);
367
368            int x = view->x();
369            int y = view->y();
370
371            int scrollX = view->scrollX();
372            int scrollY = view->scrollY();
373
374            context->translate(x, y);
375            rect.translate(-x, -y);
376            context->translate(-scrollX, -scrollY);
377            rect.translate(scrollX, scrollY);
378            context->clip(view->visibleContentRect());
379
380            view->paintContents(context, rect);
381
382            context->restore();
383        }
384#if USE(ACCELERATED_COMPOSITING) && USE(TEXTURE_MAPPER)
385        renderCompositedLayers(context, IntRect(clip.boundingRect()));
386#endif
387    }
388    renderFrameExtras(context, layers, clip);
389#if ENABLE(INSPECTOR)
390    if (frame->page()->inspectorController()->highlightedNode()) {
391        context->save();
392        frame->page()->inspectorController()->drawNodeHighlight(*context);
393        context->restore();
394    }
395#endif
396}
397
398void QWebFramePrivate::renderFrameExtras(GraphicsContext* context, QFlags<QWebFrame::RenderLayer> layers, const QRegion& clip)
399{
400    if (!(layers & (QWebFrame::PanIconLayer | QWebFrame::ScrollBarLayer)))
401        return;
402    QPainter* painter = context->platformContext();
403    WebCore::FrameView* view = frame->view();
404    QVector<QRect> vector = clip.rects();
405    for (int i = 0; i < vector.size(); ++i) {
406        const QRect& clipRect = vector.at(i);
407
408        QRect intersectedRect = clipRect.intersected(view->frameRect());
409
410        painter->save();
411        painter->setClipRect(clipRect, Qt::IntersectClip);
412
413        int x = view->x();
414        int y = view->y();
415
416        if (layers & QWebFrame::ScrollBarLayer
417            && !view->scrollbarsSuppressed()
418            && (view->horizontalScrollbar() || view->verticalScrollbar())) {
419
420            QRect rect = intersectedRect;
421            context->translate(x, y);
422            rect.translate(-x, -y);
423            view->paintScrollbars(context, rect);
424            context->translate(-x, -y);
425        }
426
427#if ENABLE(PAN_SCROLLING)
428        if (layers & QWebFrame::PanIconLayer)
429            view->paintPanScrollIcon(context);
430#endif
431
432        painter->restore();
433    }
434}
435
436void QWebFramePrivate::emitUrlChanged()
437{
438    url = frame->document()->url();
439    emit q->urlChanged(url);
440}
441
442void QWebFramePrivate::_q_orientationChanged()
443{
444#if ENABLE(ORIENTATION_EVENTS) && ENABLE(DEVICE_ORIENTATION)
445    int orientation;
446    WebCore::Frame* frame = core(q);
447
448    switch (m_orientation.reading()->orientation()) {
449    case QtMobility::QOrientationReading::TopUp:
450        orientation = 0;
451        break;
452    case QtMobility::QOrientationReading::TopDown:
453        orientation = 180;
454        break;
455    case QtMobility::QOrientationReading::LeftUp:
456        orientation = -90;
457        break;
458    case QtMobility::QOrientationReading::RightUp:
459        orientation = 90;
460        break;
461    case QtMobility::QOrientationReading::FaceUp:
462    case QtMobility::QOrientationReading::FaceDown:
463        // WebCore unable to handle it
464    default:
465        return;
466    }
467    frame->sendOrientationChangeEvent(orientation);
468#endif
469}
470/*!
471    \class QWebFrame
472    \since 4.4
473    \brief The QWebFrame class represents a frame in a web page.
474
475    \inmodule QtWebKit
476
477    QWebFrame represents a frame inside a web page. Each QWebPage
478    object contains at least one frame, the main frame, obtained using
479    QWebPage::mainFrame(). Additional frames will be created for HTML
480    \c{<frame>} or \c{<iframe>} elements.
481
482    A frame can be loaded using load() or setUrl(). Alternatively, if you have
483    the HTML content readily available, you can use setHtml() instead.
484
485    The page() function returns a pointer to the web page object. See
486    \l{QWebView}{Elements of QWebView} for an explanation of how web
487    frames are related to a web page and web view.
488
489    The QWebFrame class also offers methods to retrieve both the URL currently
490    loaded by the frame (see url()) as well as the URL originally requested
491    to be loaded (see requestedUrl()). These methods make possible the retrieval
492    of the URL before and after a DNS resolution or a redirection occurs during
493    the load process. The requestedUrl() also matches to the URL added to the
494    frame history (\l{QWebHistory}) if load is successful.
495
496    The title of an HTML frame can be accessed with the title() property.
497    Additionally, a frame may also specify an icon, which can be accessed
498    using the icon() property. If the title or the icon changes, the
499    corresponding titleChanged() and iconChanged() signals will be emitted.
500    The zoomFactor() property can be used to change the overall size
501    of the content displayed in the frame.
502
503    QWebFrame objects are created and controlled by the web page. You
504    can connect to the web page's \l{QWebPage::}{frameCreated()} signal
505    to be notified when a new frame is created.
506
507    There are multiple ways to programmatically examine the contents of a frame.
508    The hitTestContent() function can be used to find elements by coordinate.
509    For access to the underlying DOM tree, there is documentElement(),
510    findAllElements() and findFirstElement().
511
512    A QWebFrame can be printed onto a QPrinter using the print() function.
513    This function is marked as a slot and can be conveniently connected to
514    \l{QPrintPreviewDialog}'s \l{QPrintPreviewDialog::}{paintRequested()}
515    signal.
516
517    \sa QWebPage
518*/
519
520/*!
521    \enum QWebFrame::RenderLayer
522
523    This enum describes the layers available for rendering using \l{QWebFrame::}{render()}.
524    The layers can be OR-ed together from the following list:
525
526    \value ContentsLayer The web content of the frame
527    \value ScrollBarLayer The scrollbars of the frame
528    \value PanIconLayer The icon used when panning the frame
529
530    \value AllLayers Includes all the above layers
531*/
532
533QWebFrame::QWebFrame(QWebPage *parent, QWebFrameData *frameData)
534    : QObject(parent)
535    , d(new QWebFramePrivate)
536{
537    d->page = parent;
538    d->init(this, frameData);
539
540    if (!frameData->url.isEmpty()) {
541        WebCore::ResourceRequest request(frameData->url, frameData->referrer);
542        d->frame->loader()->load(request, frameData->name, false);
543    }
544#if ENABLE(ORIENTATION_EVENTS) && ENABLE(DEVICE_ORIENTATION)
545    connect(&d->m_orientation, SIGNAL(readingChanged()), this, SLOT(_q_orientationChanged()));
546    d->m_orientation.start();
547#endif
548}
549
550QWebFrame::QWebFrame(QWebFrame *parent, QWebFrameData *frameData)
551    : QObject(parent)
552    , d(new QWebFramePrivate)
553{
554    d->page = parent->d->page;
555    d->init(this, frameData);
556#if ENABLE(ORIENTATION_EVENTS) && ENABLE(DEVICE_ORIENTATION)
557    connect(&d->m_orientation, SIGNAL(readingChanged()), this, SLOT(_q_orientationChanged()));
558    d->m_orientation.start();
559#endif
560}
561
562QWebFrame::~QWebFrame()
563{
564    if (d->frame && d->frame->loader() && d->frame->loader()->client())
565        static_cast<FrameLoaderClientQt*>(d->frame->loader()->client())->m_webFrame = 0;
566
567    delete d;
568}
569
570/*!
571    Make \a object available under \a name from within the frame's JavaScript
572    context. The \a object will be inserted as a child of the frame's window
573    object.
574
575    Qt properties will be exposed as JavaScript properties and slots as
576    JavaScript methods.
577    The interaction between C++ and JavaScript is explained in the documentation of the \l{The QtWebKit Bridge}{QtWebKit bridge}.
578
579    If you want to ensure that your QObjects remain accessible after loading a
580    new URL, you should add them in a slot connected to the
581    javaScriptWindowObjectCleared() signal.
582
583    If Javascript is not enabled for this page, then this method does nothing.
584
585    The \a object will never be explicitly deleted by QtWebKit.
586*/
587void QWebFrame::addToJavaScriptWindowObject(const QString &name, QObject *object)
588{
589    addToJavaScriptWindowObject(name, object, QScriptEngine::QtOwnership);
590}
591
592/*!
593    \fn void QWebFrame::addToJavaScriptWindowObject(const QString &name, QObject *object, QScriptEngine::ValueOwnership own)
594    \overload
595
596    Make \a object available under \a name from within the frame's JavaScript
597    context. The \a object will be inserted as a child of the frame's window
598    object.
599
600    Qt properties will be exposed as JavaScript properties and slots as
601    JavaScript methods.
602    The interaction between C++ and JavaScript is explained in the documentation of the \l{The QtWebKit Bridge}{QtWebKit bridge}.
603
604    If you want to ensure that your QObjects remain accessible after loading a
605    new URL, you should add them in a slot connected to the
606    javaScriptWindowObjectCleared() signal.
607
608    If Javascript is not enabled for this page, then this method does nothing.
609
610    The ownership of \a object is specified using \a own.
611*/
612void QWebFrame::addToJavaScriptWindowObject(const QString &name, QObject *object, QScriptEngine::ValueOwnership ownership)
613{
614    if (!page()->settings()->testAttribute(QWebSettings::JavascriptEnabled))
615        return;
616#if USE(JSC)
617    JSC::JSLock lock(JSC::SilenceAssertionsOnly);
618    JSDOMWindow* window = toJSDOMWindow(d->frame, mainThreadNormalWorld());
619    JSC::Bindings::RootObject* root;
620    if (ownership == QScriptEngine::QtOwnership)
621        root = d->frame->script()->cacheableBindingRootObject();
622    else
623        root = d->frame->script()->bindingRootObject();
624
625    if (!window) {
626        qDebug() << "Warning: couldn't get window object";
627        return;
628    }
629    if (!root) {
630        qDebug() << "Warning: couldn't get root object";
631        return;
632    }
633
634    JSC::ExecState* exec = window->globalExec();
635
636    JSC::JSObject* runtimeObject =
637            JSC::Bindings::QtInstance::getQtInstance(object, root, ownership)->createRuntimeObject(exec);
638
639    JSC::PutPropertySlot slot;
640    window->put(exec, JSC::Identifier(exec, reinterpret_cast_ptr<const UChar*>(name.constData()), name.length()), runtimeObject, slot);
641#elif USE(V8)
642    QScriptEngine* engine = d->frame->script()->qtScriptEngine();
643    if (!engine)
644        return;
645    QScriptValue v = engine->newQObject(object, ownership);
646    engine->globalObject().property("window").setProperty(name, v);
647#endif
648}
649
650/*!
651    Returns the frame's content as HTML, enclosed in HTML and BODY tags.
652
653    \sa setHtml(), toPlainText()
654*/
655QString QWebFrame::toHtml() const
656{
657    if (!d->frame->document())
658        return QString();
659    return createMarkup(d->frame->document());
660}
661
662/*!
663    Returns the content of this frame converted to plain text, completely
664    stripped of all HTML formatting.
665
666    \sa toHtml()
667*/
668QString QWebFrame::toPlainText() const
669{
670    if (d->frame->view() && d->frame->view()->layoutPending())
671        d->frame->view()->layout();
672
673    Element *documentElement = d->frame->document()->documentElement();
674    if (documentElement)
675        return documentElement->innerText();
676    return QString();
677}
678
679/*!
680    Returns a dump of the rendering tree. This is mainly useful for debugging
681    html.
682*/
683QString QWebFrame::renderTreeDump() const
684{
685    if (d->frame->view() && d->frame->view()->layoutPending())
686        d->frame->view()->layout();
687
688    return externalRepresentation(d->frame);
689}
690
691/*!
692    \property QWebFrame::title
693    \brief the title of the frame as defined by the HTML &lt;title&gt; element
694
695    \sa titleChanged()
696*/
697
698QString QWebFrame::title() const
699{
700    if (d->frame->document())
701        return d->frame->loader()->documentLoader()->title().string();
702    return QString();
703}
704
705/*!
706    \since 4.5
707    \brief Returns the meta data in this frame as a QMultiMap
708
709    The meta data consists of the name and content attributes of the
710    of the \c{<meta>} tags in the HTML document.
711
712    For example:
713
714    \code
715    <html>
716        <head>
717            <meta name="description" content="This document is a tutorial about Qt development">
718            <meta name="keywords" content="Qt, WebKit, Programming">
719        </head>
720        ...
721    </html>
722    \endcode
723
724    Given the above HTML code the metaData() function will return a map with two entries:
725    \table
726    \header \o Key
727            \o Value
728    \row    \o "description"
729            \o "This document is a tutorial about Qt development"
730    \row    \o "keywords"
731            \o "Qt, WebKit, Programming"
732    \endtable
733
734    This function returns a multi map to support multiple meta tags with the same attribute name.
735*/
736QMultiMap<QString, QString> QWebFrame::metaData() const
737{
738    if (!d->frame->document())
739       return QMap<QString, QString>();
740
741    QMultiMap<QString, QString> map;
742    Document* doc = d->frame->document();
743    RefPtr<NodeList> list = doc->getElementsByTagName("meta");
744    unsigned len = list->length();
745    for (unsigned i = 0; i < len; i++) {
746        HTMLMetaElement* meta = static_cast<HTMLMetaElement*>(list->item(i));
747        map.insert(meta->name(), meta->content());
748    }
749    return map;
750}
751
752static inline void clearCoreFrame(WebCore::Frame* frame)
753{
754    frame->loader()->activeDocumentLoader()->writer()->begin();
755    frame->loader()->activeDocumentLoader()->writer()->end();
756}
757
758static inline bool isCoreFrameClear(WebCore::Frame* frame)
759{
760    return frame->document()->url().isEmpty();
761}
762
763static inline QUrl ensureAbsoluteUrl(const QUrl &url)
764{
765    if (!url.isValid() || !url.isRelative())
766        return url;
767
768    // This contains the URL with absolute path but without
769    // the query and the fragment part.
770    QUrl baseUrl = QUrl::fromLocalFile(QFileInfo(url.toLocalFile()).absoluteFilePath());
771
772    // The path is removed so the query and the fragment parts are there.
773    QString pathRemoved = url.toString(QUrl::RemovePath);
774    QUrl toResolve(pathRemoved);
775
776    return baseUrl.resolved(toResolve);
777}
778
779/*!
780    \property QWebFrame::url
781    \brief the url of the frame currently viewed
782
783    Setting this property clears the view and loads the URL.
784
785    By default, this property contains an empty, invalid URL.
786
787    \sa urlChanged()
788*/
789
790void QWebFrame::setUrl(const QUrl &url)
791{
792    clearCoreFrame(d->frame);
793    const QUrl absolute = ensureAbsoluteUrl(url);
794    d->url = absolute;
795    load(absolute);
796}
797
798QUrl QWebFrame::url() const
799{
800    return d->url;
801}
802
803/*!
804    \since 4.6
805    \property QWebFrame::requestedUrl
806
807    The URL requested to loaded by the frame currently viewed. The URL may differ from
808    the one returned by url() if a DNS resolution or a redirection occurs.
809
810    \sa url(), setUrl()
811*/
812QUrl QWebFrame::requestedUrl() const
813{
814    return d->frameLoaderClient->lastRequestedUrl();
815}
816/*!
817    \since 4.6
818    \property QWebFrame::baseUrl
819    \brief the base URL of the frame, can be used to resolve relative URLs
820    \since 4.6
821*/
822
823QUrl QWebFrame::baseUrl() const
824{
825    if (isCoreFrameClear(d->frame))
826        return QUrl(d->url).resolved(QUrl());
827    return d->frame->document()->baseURL();
828}
829
830/*!
831    \property QWebFrame::icon
832    \brief the icon associated with this frame
833
834    \sa iconChanged(), QWebSettings::iconForUrl()
835*/
836
837QIcon QWebFrame::icon() const
838{
839    return QWebSettings::iconForUrl(d->frame->document()->url());
840}
841
842/*!
843  The name of this frame as defined by the parent frame.
844*/
845QString QWebFrame::frameName() const
846{
847    return d->frame->tree()->uniqueName();
848}
849
850/*!
851  The web page that contains this frame.
852
853  \sa pageChanged()
854*/
855QWebPage *QWebFrame::page() const
856{
857    return d->page;
858}
859
860/*!
861  Loads \a url into this frame.
862
863  \note The view remains the same until enough data has arrived to display the new \a url.
864
865  \sa setUrl(), setHtml(), setContent()
866*/
867void QWebFrame::load(const QUrl &url)
868{
869    // The load() overload ensures that the url is absolute.
870    load(QNetworkRequest(url));
871}
872
873/*!
874  Loads a network request, \a req, into this frame, using the method specified in \a
875  operation.
876
877  \a body is optional and is only used for POST operations.
878
879  \note The view remains the same until enough data has arrived to display the new content.
880
881  \sa setUrl()
882*/
883void QWebFrame::load(const QNetworkRequest &req,
884                     QNetworkAccessManager::Operation operation,
885                     const QByteArray &body)
886{
887    if (d->parentFrame())
888        d->page->d->insideOpenCall = true;
889
890    QUrl url = ensureAbsoluteUrl(req.url());
891
892    WebCore::ResourceRequest request(url);
893
894    switch (operation) {
895        case QNetworkAccessManager::HeadOperation:
896            request.setHTTPMethod("HEAD");
897            break;
898        case QNetworkAccessManager::GetOperation:
899            request.setHTTPMethod("GET");
900            break;
901        case QNetworkAccessManager::PutOperation:
902            request.setHTTPMethod("PUT");
903            break;
904        case QNetworkAccessManager::PostOperation:
905            request.setHTTPMethod("POST");
906            break;
907        case QNetworkAccessManager::DeleteOperation:
908            request.setHTTPMethod("DELETE");
909            break;
910        case QNetworkAccessManager::CustomOperation:
911            request.setHTTPMethod(req.attribute(QNetworkRequest::CustomVerbAttribute).toByteArray().constData());
912            break;
913        case QNetworkAccessManager::UnknownOperation:
914            // eh?
915            break;
916    }
917
918    QVariant cacheLoad = req.attribute(QNetworkRequest::CacheLoadControlAttribute);
919    if (cacheLoad.isValid()) {
920        bool ok;
921        uint cacheLoadValue = cacheLoad.toUInt(&ok);
922        if (ok)
923            request.setCachePolicy(cacheLoadControlToCachePolicy(cacheLoadValue));
924    }
925
926    QList<QByteArray> httpHeaders = req.rawHeaderList();
927    for (int i = 0; i < httpHeaders.size(); ++i) {
928        const QByteArray &headerName = httpHeaders.at(i);
929        request.addHTTPHeaderField(QString::fromLatin1(headerName), QString::fromLatin1(req.rawHeader(headerName)));
930    }
931
932    if (!body.isEmpty())
933        request.setHTTPBody(WebCore::FormData::create(body.constData(), body.size()));
934
935    d->frame->loader()->load(request, false);
936
937    if (d->parentFrame())
938        d->page->d->insideOpenCall = false;
939}
940
941/*!
942  Sets the content of this frame to \a html. \a baseUrl is optional and used to resolve relative
943  URLs in the document, such as referenced images or stylesheets.
944
945  The \a html is loaded immediately; external objects are loaded asynchronously.
946
947  If a script in the \a html runs longer than the default script timeout (currently 10 seconds),
948  for example due to being blocked by a modal JavaScript alert dialog, this method will return
949  as soon as possible after the timeout and any subsequent \a html will be loaded asynchronously.
950
951  When using this method WebKit assumes that external resources such as JavaScript programs or style
952  sheets are encoded in UTF-8 unless otherwise specified. For example, the encoding of an external
953  script can be specified through the charset attribute of the HTML script tag. It is also possible
954  for the encoding to be specified by web server.
955
956  This is a convenience function equivalent to setContent(html, "text/html", baseUrl).
957
958  \note This method will not affect session or global history for the frame.
959
960  \warning This function works only for HTML, for other mime types (i.e. XHTML, SVG)
961  setContent() should be used instead.
962
963  \sa toHtml(), setContent(), load()
964*/
965void QWebFrame::setHtml(const QString &html, const QUrl &baseUrl)
966{
967    KURL kurl(baseUrl);
968    WebCore::ResourceRequest request(kurl);
969    const QByteArray utf8 = html.toUtf8();
970    WTF::RefPtr<WebCore::SharedBuffer> data = WebCore::SharedBuffer::create(utf8.constData(), utf8.length());
971    WebCore::SubstituteData substituteData(data, WTF::String("text/html"), WTF::String("utf-8"), KURL());
972    d->frame->loader()->load(request, substituteData, false);
973}
974
975/*!
976  Sets the content of this frame to the specified content \a data. If the \a mimeType argument
977  is empty it is currently assumed that the content is HTML but in future versions we may introduce
978  auto-detection.
979
980  External objects referenced in the content are located relative to \a baseUrl.
981
982  The \a data is loaded immediately; external objects are loaded asynchronously.
983
984  \note This method will not affect session or global history for the frame.
985
986  \sa toHtml(), setHtml()
987*/
988void QWebFrame::setContent(const QByteArray &data, const QString &mimeType, const QUrl &baseUrl)
989{
990    KURL kurl(baseUrl);
991    WebCore::ResourceRequest request(kurl);
992    WTF::RefPtr<WebCore::SharedBuffer> buffer = WebCore::SharedBuffer::create(data.constData(), data.length());
993    QString actualMimeType;
994    WTF::String encoding;
995    if (mimeType.isEmpty())
996        actualMimeType = QLatin1String("text/html");
997    else {
998        actualMimeType = extractMIMETypeFromMediaType(mimeType);
999        encoding = extractCharsetFromMediaType(mimeType);
1000    }
1001    WebCore::SubstituteData substituteData(buffer, WTF::String(actualMimeType), encoding, KURL());
1002    d->frame->loader()->load(request, substituteData, false);
1003}
1004
1005/*!
1006  Returns the parent frame of this frame, or 0 if the frame is the web pages
1007  main frame.
1008
1009  This is equivalent to qobject_cast<QWebFrame*>(frame->parent()).
1010
1011  \sa childFrames()
1012*/
1013QWebFrame *QWebFrame::parentFrame() const
1014{
1015    return d->parentFrame();
1016}
1017
1018/*!
1019  Returns a list of all frames that are direct children of this frame.
1020
1021  \sa parentFrame()
1022*/
1023QList<QWebFrame*> QWebFrame::childFrames() const
1024{
1025    QList<QWebFrame*> rc;
1026    if (d->frame) {
1027        FrameTree *tree = d->frame->tree();
1028        for (Frame *child = tree->firstChild(); child; child = child->tree()->nextSibling()) {
1029            FrameLoader *loader = child->loader();
1030            QWebFrame* webFrame = qobject_cast<QWebFrame*>(loader->networkingContext()->originatingObject());
1031            if (webFrame)
1032                rc.append(webFrame);
1033        }
1034
1035    }
1036    return rc;
1037}
1038
1039/*!
1040    Returns the scrollbar policy for the scrollbar defined by \a orientation.
1041*/
1042Qt::ScrollBarPolicy QWebFrame::scrollBarPolicy(Qt::Orientation orientation) const
1043{
1044    if (orientation == Qt::Horizontal)
1045        return d->horizontalScrollBarPolicy;
1046    return d->verticalScrollBarPolicy;
1047}
1048
1049/*!
1050    Sets the scrollbar policy for the scrollbar defined by \a orientation to \a policy.
1051*/
1052void QWebFrame::setScrollBarPolicy(Qt::Orientation orientation, Qt::ScrollBarPolicy policy)
1053{
1054    Q_ASSERT((int)ScrollbarAuto == (int)Qt::ScrollBarAsNeeded);
1055    Q_ASSERT((int)ScrollbarAlwaysOff == (int)Qt::ScrollBarAlwaysOff);
1056    Q_ASSERT((int)ScrollbarAlwaysOn == (int)Qt::ScrollBarAlwaysOn);
1057
1058    if (orientation == Qt::Horizontal) {
1059        d->horizontalScrollBarPolicy = policy;
1060        if (d->frame->view()) {
1061            d->frame->view()->setHorizontalScrollbarMode((ScrollbarMode)policy, policy != Qt::ScrollBarAsNeeded /* lock */);
1062            d->frame->view()->updateCanHaveScrollbars();
1063        }
1064    } else {
1065        d->verticalScrollBarPolicy = policy;
1066        if (d->frame->view()) {
1067            d->frame->view()->setVerticalScrollbarMode((ScrollbarMode)policy, policy != Qt::ScrollBarAsNeeded /* lock */);
1068            d->frame->view()->updateCanHaveScrollbars();
1069        }
1070    }
1071}
1072
1073/*!
1074  Sets the current \a value for the scrollbar with orientation \a orientation.
1075
1076  The scrollbar forces the \a value to be within the legal range: minimum <= value <= maximum.
1077
1078  Changing the value also updates the thumb position.
1079
1080  \sa scrollBarMinimum(), scrollBarMaximum()
1081*/
1082void QWebFrame::setScrollBarValue(Qt::Orientation orientation, int value)
1083{
1084    Scrollbar *sb;
1085    sb = (orientation == Qt::Horizontal) ? d->horizontalScrollBar() : d->verticalScrollBar();
1086    if (sb) {
1087        if (value < 0)
1088            value = 0;
1089        else if (value > scrollBarMaximum(orientation))
1090            value = scrollBarMaximum(orientation);
1091        sb->scrollableArea()->scrollToOffsetWithoutAnimation(orientation == Qt::Horizontal ? HorizontalScrollbar : VerticalScrollbar, value);
1092    }
1093}
1094
1095/*!
1096  Returns the current value for the scrollbar with orientation \a orientation, or 0
1097  if no scrollbar is found for \a orientation.
1098
1099  \sa scrollBarMinimum(), scrollBarMaximum()
1100*/
1101int QWebFrame::scrollBarValue(Qt::Orientation orientation) const
1102{
1103    Scrollbar *sb;
1104    sb = (orientation == Qt::Horizontal) ? d->horizontalScrollBar() : d->verticalScrollBar();
1105    if (sb)
1106        return sb->value();
1107    return 0;
1108}
1109
1110/*!
1111  Returns the maximum value for the scrollbar with orientation \a orientation, or 0
1112  if no scrollbar is found for \a orientation.
1113
1114  \sa scrollBarMinimum()
1115*/
1116int QWebFrame::scrollBarMaximum(Qt::Orientation orientation) const
1117{
1118    Scrollbar *sb;
1119    sb = (orientation == Qt::Horizontal) ? d->horizontalScrollBar() : d->verticalScrollBar();
1120    if (sb)
1121        return sb->maximum();
1122    return 0;
1123}
1124
1125/*!
1126  Returns the minimum value for the scrollbar with orientation \a orientation.
1127
1128  The minimum value is always 0.
1129
1130  \sa scrollBarMaximum()
1131*/
1132int QWebFrame::scrollBarMinimum(Qt::Orientation orientation) const
1133{
1134    Q_UNUSED(orientation)
1135    return 0;
1136}
1137
1138/*!
1139  \since 4.6
1140  Returns the geometry for the scrollbar with orientation \a orientation.
1141
1142  If the scrollbar does not exist an empty rect is returned.
1143*/
1144QRect QWebFrame::scrollBarGeometry(Qt::Orientation orientation) const
1145{
1146    Scrollbar *sb;
1147    sb = (orientation == Qt::Horizontal) ? d->horizontalScrollBar() : d->verticalScrollBar();
1148    if (sb)
1149        return sb->frameRect();
1150    return QRect();
1151}
1152
1153/*!
1154  \since 4.5
1155  Scrolls the frame \a dx pixels to the right and \a dy pixels downward. Both
1156  \a dx and \a dy may be negative.
1157
1158  \sa QWebFrame::scrollPosition
1159*/
1160
1161void QWebFrame::scroll(int dx, int dy)
1162{
1163    if (!d->frame->view())
1164        return;
1165
1166    d->frame->view()->scrollBy(IntSize(dx, dy));
1167}
1168
1169/*!
1170  \property QWebFrame::scrollPosition
1171  \since 4.5
1172  \brief the position the frame is currently scrolled to.
1173*/
1174
1175QPoint QWebFrame::scrollPosition() const
1176{
1177    if (!d->frame->view())
1178        return QPoint(0, 0);
1179
1180    IntSize ofs = d->frame->view()->scrollOffset();
1181    return QPoint(ofs.width(), ofs.height());
1182}
1183
1184void QWebFrame::setScrollPosition(const QPoint &pos)
1185{
1186    QPoint current = scrollPosition();
1187    int dx = pos.x() - current.x();
1188    int dy = pos.y() - current.y();
1189    scroll(dx, dy);
1190}
1191
1192/*!
1193  \since 4.7
1194  Scrolls the frame to the given \a anchor name.
1195*/
1196void QWebFrame::scrollToAnchor(const QString& anchor)
1197{
1198    FrameView *view = d->frame->view();
1199    if (view)
1200        view->scrollToAnchor(anchor);
1201}
1202
1203/*!
1204  \since 4.6
1205  Render the \a layer of the frame using \a painter clipping to \a clip.
1206
1207  \sa print()
1208*/
1209
1210void QWebFrame::render(QPainter* painter, RenderLayer layer, const QRegion& clip)
1211{
1212    GraphicsContext context(painter);
1213    if (context.paintingDisabled() && !context.updatingControlTints())
1214        return;
1215
1216    if (!clip.isEmpty())
1217        d->renderRelativeCoords(&context, layer, clip);
1218    else if (d->frame->view())
1219        d->renderRelativeCoords(&context, layer, QRegion(d->frame->view()->frameRect()));
1220}
1221
1222/*!
1223  Render the frame into \a painter clipping to \a clip.
1224*/
1225void QWebFrame::render(QPainter* painter, const QRegion& clip)
1226{
1227    GraphicsContext context(painter);
1228    if (context.paintingDisabled() && !context.updatingControlTints())
1229        return;
1230
1231    d->renderRelativeCoords(&context, AllLayers, clip);
1232}
1233
1234/*!
1235  Render the frame into \a painter.
1236*/
1237void QWebFrame::render(QPainter* painter)
1238{
1239    if (!d->frame->view())
1240        return;
1241
1242    GraphicsContext context(painter);
1243    if (context.paintingDisabled() && !context.updatingControlTints())
1244        return;
1245
1246    d->renderRelativeCoords(&context, AllLayers, QRegion(d->frame->view()->frameRect()));
1247}
1248
1249/*!
1250    \property QWebFrame::textSizeMultiplier
1251    \brief the scaling factor for all text in the frame
1252    \obsolete
1253
1254    Use setZoomFactor instead, in combination with the ZoomTextOnly attribute in
1255    QWebSettings.
1256
1257    \note Setting this property also enables the ZoomTextOnly attribute in
1258    QWebSettings.
1259*/
1260
1261/*!
1262    Sets the value of the multiplier used to scale the text in a Web frame to
1263    the \a factor specified.
1264*/
1265void QWebFrame::setTextSizeMultiplier(qreal factor)
1266{
1267    page()->settings()->setAttribute(QWebSettings::ZoomTextOnly, true);
1268
1269    d->frame->setPageAndTextZoomFactors(1, factor);
1270}
1271
1272/*!
1273    Returns the value of the multiplier used to scale the text in a Web frame.
1274*/
1275qreal QWebFrame::textSizeMultiplier() const
1276{
1277    return page()->settings()->testAttribute(QWebSettings::ZoomTextOnly) ? d->frame->textZoomFactor() : d->frame->pageZoomFactor();
1278}
1279
1280/*!
1281    \property QWebFrame::zoomFactor
1282    \since 4.5
1283    \brief the zoom factor for the frame
1284*/
1285
1286void QWebFrame::setZoomFactor(qreal factor)
1287{
1288    if (page()->settings()->testAttribute(QWebSettings::ZoomTextOnly))
1289        d->frame->setTextZoomFactor(factor);
1290    else
1291        d->frame->setPageZoomFactor(factor);
1292}
1293
1294qreal QWebFrame::zoomFactor() const
1295{
1296    return page()->settings()->testAttribute(QWebSettings::ZoomTextOnly) ? d->frame->textZoomFactor() : d->frame->pageZoomFactor();
1297}
1298
1299/*!
1300    \property QWebFrame::focus
1301    \since 4.6
1302
1303    Returns true if this frame has keyboard input focus; otherwise, returns false.
1304*/
1305bool QWebFrame::hasFocus() const
1306{
1307    WebCore::Frame* ff = d->frame->page()->focusController()->focusedFrame();
1308    return ff && QWebFramePrivate::kit(ff) == this;
1309}
1310
1311/*!
1312    \since 4.6
1313
1314    Gives keyboard input focus to this frame.
1315*/
1316void QWebFrame::setFocus()
1317{
1318    QWebFramePrivate::core(this)->page()->focusController()->setFocusedFrame(QWebFramePrivate::core(this));
1319}
1320
1321/*!
1322    Returns the position of the frame relative to it's parent frame.
1323*/
1324QPoint QWebFrame::pos() const
1325{
1326    if (!d->frame->view())
1327        return QPoint();
1328
1329    return d->frame->view()->frameRect().location();
1330}
1331
1332/*!
1333    Return the geometry of the frame relative to it's parent frame.
1334*/
1335QRect QWebFrame::geometry() const
1336{
1337    if (!d->frame->view())
1338        return QRect();
1339    return d->frame->view()->frameRect();
1340}
1341
1342/*!
1343    \property QWebFrame::contentsSize
1344    \brief the size of the contents in this frame
1345
1346    \sa contentsSizeChanged()
1347*/
1348QSize QWebFrame::contentsSize() const
1349{
1350    FrameView *view = d->frame->view();
1351    if (!view)
1352        return QSize();
1353    return QSize(view->contentsWidth(), view->contentsHeight());
1354}
1355
1356/*!
1357    \since 4.6
1358
1359    Returns the document element of this frame.
1360
1361    The document element provides access to the entire structured
1362    content of the frame.
1363*/
1364QWebElement QWebFrame::documentElement() const
1365{
1366    WebCore::Document *doc = d->frame->document();
1367    if (!doc)
1368        return QWebElement();
1369    return QWebElement(doc->documentElement());
1370}
1371
1372/*!
1373    \since 4.6
1374    Returns a new list of elements matching the given CSS selector \a selectorQuery.
1375    If there are no matching elements, an empty list is returned.
1376
1377    \l{http://www.w3.org/TR/REC-CSS2/selector.html#q1}{Standard CSS2 selector} syntax is
1378    used for the query.
1379
1380    \sa QWebElement::findAll()
1381*/
1382QWebElementCollection QWebFrame::findAllElements(const QString &selectorQuery) const
1383{
1384    return documentElement().findAll(selectorQuery);
1385}
1386
1387/*!
1388    \since 4.6
1389    Returns the first element in the frame's document that matches the
1390    given CSS selector \a selectorQuery. If there is no matching element, a
1391    null element is returned.
1392
1393    \l{http://www.w3.org/TR/REC-CSS2/selector.html#q1}{Standard CSS2 selector} syntax is
1394    used for the query.
1395
1396    \sa QWebElement::findFirst()
1397*/
1398QWebElement QWebFrame::findFirstElement(const QString &selectorQuery) const
1399{
1400    return documentElement().findFirst(selectorQuery);
1401}
1402
1403/*!
1404    Performs a hit test on the frame contents at the given position \a pos and returns the hit test result.
1405*/
1406QWebHitTestResult QWebFrame::hitTestContent(const QPoint &pos) const
1407{
1408    if (!d->frame->view() || !d->frame->contentRenderer())
1409        return QWebHitTestResult();
1410
1411    HitTestResult result = d->frame->eventHandler()->hitTestResultAtPoint(d->frame->view()->windowToContents(pos), /*allowShadowContent*/ false, /*ignoreClipping*/ true);
1412
1413    if (result.scrollbar())
1414        return QWebHitTestResult();
1415
1416    return QWebHitTestResult(new QWebHitTestResultPrivate(result));
1417}
1418
1419/*! \reimp
1420*/
1421bool QWebFrame::event(QEvent *e)
1422{
1423    return QObject::event(e);
1424}
1425
1426#ifndef QT_NO_PRINTER
1427/*!
1428    Prints the frame to the given \a printer.
1429
1430    \sa render()
1431*/
1432void QWebFrame::print(QPrinter *printer) const
1433{
1434    QPainter painter;
1435    if (!painter.begin(printer))
1436        return;
1437
1438    const qreal zoomFactorX = (qreal)printer->logicalDpiX() / qt_defaultDpi();
1439    const qreal zoomFactorY = (qreal)printer->logicalDpiY() / qt_defaultDpi();
1440
1441    PrintContext printContext(d->frame);
1442    float pageHeight = 0;
1443
1444    QRect qprinterRect = printer->pageRect();
1445
1446    IntRect pageRect(0, 0,
1447                     int(qprinterRect.width() / zoomFactorX),
1448                     int(qprinterRect.height() / zoomFactorY));
1449
1450    printContext.begin(pageRect.width());
1451
1452    printContext.computePageRects(pageRect, /* headerHeight */ 0, /* footerHeight */ 0, /* userScaleFactor */ 1.0, pageHeight);
1453
1454    int docCopies;
1455    int pageCopies;
1456    if (printer->collateCopies()) {
1457        docCopies = 1;
1458        pageCopies = printer->numCopies();
1459    } else {
1460        docCopies = printer->numCopies();
1461        pageCopies = 1;
1462    }
1463
1464    int fromPage = printer->fromPage();
1465    int toPage = printer->toPage();
1466    bool ascending = true;
1467
1468    if (fromPage == 0 && toPage == 0) {
1469        fromPage = 1;
1470        toPage = printContext.pageCount();
1471    }
1472    // paranoia check
1473    fromPage = qMax(1, fromPage);
1474    toPage = qMin(static_cast<int>(printContext.pageCount()), toPage);
1475    if (toPage < fromPage) {
1476        // if the user entered a page range outside the actual number
1477        // of printable pages, just return
1478        return;
1479    }
1480
1481    if (printer->pageOrder() == QPrinter::LastPageFirst) {
1482        int tmp = fromPage;
1483        fromPage = toPage;
1484        toPage = tmp;
1485        ascending = false;
1486    }
1487
1488    painter.scale(zoomFactorX, zoomFactorY);
1489    GraphicsContext ctx(&painter);
1490
1491    for (int i = 0; i < docCopies; ++i) {
1492        int page = fromPage;
1493        while (true) {
1494            for (int j = 0; j < pageCopies; ++j) {
1495                if (printer->printerState() == QPrinter::Aborted
1496                    || printer->printerState() == QPrinter::Error) {
1497                    printContext.end();
1498                    return;
1499                }
1500                printContext.spoolPage(ctx, page - 1, pageRect.width());
1501                if (j < pageCopies - 1)
1502                    printer->newPage();
1503            }
1504
1505            if (page == toPage)
1506                break;
1507
1508            if (ascending)
1509                ++page;
1510            else
1511                --page;
1512
1513            printer->newPage();
1514        }
1515
1516        if ( i < docCopies - 1)
1517            printer->newPage();
1518    }
1519
1520    printContext.end();
1521}
1522#endif // QT_NO_PRINTER
1523
1524/*!
1525    Evaluates the JavaScript defined by \a scriptSource using this frame as context
1526    and returns the result of the last executed statement.
1527
1528    \sa addToJavaScriptWindowObject(), javaScriptWindowObjectCleared()
1529*/
1530QVariant QWebFrame::evaluateJavaScript(const QString& scriptSource)
1531{
1532    ScriptController *proxy = d->frame->script();
1533    QVariant rc;
1534    if (proxy) {
1535#if USE(JSC)
1536        int distance = 0;
1537        JSC::JSValue v = d->frame->script()->executeScript(ScriptSourceCode(scriptSource)).jsValue();
1538
1539        rc = JSC::Bindings::convertValueToQVariant(proxy->globalObject(mainThreadNormalWorld())->globalExec(), v, QMetaType::Void, &distance);
1540#elif USE(V8)
1541        QScriptEngine* engine = d->frame->script()->qtScriptEngine();
1542        if (!engine)
1543            return rc;
1544        rc = engine->evaluate(scriptSource).toVariant();
1545#endif
1546    }
1547    return rc;
1548}
1549
1550/*!
1551    \since 4.5
1552
1553    Returns the frame's security origin.
1554*/
1555QWebSecurityOrigin QWebFrame::securityOrigin() const
1556{
1557    QWebFrame* that = const_cast<QWebFrame*>(this);
1558    QWebSecurityOriginPrivate* priv = new QWebSecurityOriginPrivate(QWebFramePrivate::core(that)->document()->securityOrigin());
1559    return QWebSecurityOrigin(priv);
1560}
1561
1562WebCore::Frame* QWebFramePrivate::core(const QWebFrame* webFrame)
1563{
1564    return webFrame->d->frame;
1565}
1566
1567QWebFrame* QWebFramePrivate::kit(const WebCore::Frame* coreFrame)
1568{
1569    return qobject_cast<QWebFrame*>(coreFrame->loader()->networkingContext()->originatingObject());
1570}
1571
1572
1573/*!
1574    \fn void QWebFrame::javaScriptWindowObjectCleared()
1575
1576    This signal is emitted whenever the global window object of the JavaScript
1577    environment is cleared, e.g., before starting a new load.
1578
1579    If you intend to add QObjects to a QWebFrame using
1580    addToJavaScriptWindowObject(), you should add them in a slot connected
1581    to this signal. This ensures that your objects remain accessible when
1582    loading new URLs.
1583*/
1584
1585/*!
1586    \fn void QWebFrame::provisionalLoad()
1587    \internal
1588*/
1589
1590/*!
1591    \fn void QWebFrame::titleChanged(const QString &title)
1592
1593    This signal is emitted whenever the title of the frame changes.
1594    The \a title string specifies the new title.
1595
1596    \sa title()
1597*/
1598
1599/*!
1600    \fn void QWebFrame::urlChanged(const QUrl &url)
1601
1602    This signal is emitted with the URL of the frame when the frame's title is
1603    received. The new URL is specified by \a url.
1604
1605    \sa url()
1606*/
1607
1608/*!
1609    \fn void QWebFrame::initialLayoutCompleted()
1610
1611    This signal is emitted when the frame is laid out the first time.
1612    This is the first time you will see contents displayed on the frame.
1613
1614    \note A frame can be laid out multiple times.
1615*/
1616
1617/*!
1618  \fn void QWebFrame::iconChanged()
1619
1620  This signal is emitted when the icon ("favicon") associated with the frame
1621  has been loaded.
1622
1623  \sa icon()
1624*/
1625
1626/*!
1627  \fn void QWebFrame::contentsSizeChanged(const QSize &size)
1628  \since 4.6
1629
1630  This signal is emitted when the frame's contents size changes
1631  to \a size.
1632
1633  \sa contentsSize()
1634*/
1635
1636/*!
1637    \fn void QWebFrame::loadStarted()
1638    \since 4.6
1639
1640    This signal is emitted when a new load of this frame is started.
1641
1642    \sa loadFinished()
1643*/
1644
1645/*!
1646    \fn void QWebFrame::loadFinished(bool ok)
1647    \since 4.6
1648
1649    This signal is emitted when a load of this frame is finished.
1650    \a ok will indicate whether the load was successful or any error occurred.
1651
1652    \sa loadStarted()
1653*/
1654
1655/*!
1656    \fn void QWebFrame::pageChanged()
1657    \since 4.7
1658
1659    This signal is emitted when this frame has been moved to a different QWebPage.
1660
1661    \sa page()
1662*/
1663
1664/*!
1665    \class QWebHitTestResult
1666    \since 4.4
1667    \brief The QWebHitTestResult class provides information about the web
1668    page content after a hit test.
1669
1670    \inmodule QtWebKit
1671
1672    QWebHitTestResult is returned by QWebFrame::hitTestContent() to provide
1673    information about the content of the web page at the specified position.
1674*/
1675
1676/*!
1677    \internal
1678*/
1679QWebHitTestResult::QWebHitTestResult(QWebHitTestResultPrivate *priv)
1680    : d(priv)
1681{
1682}
1683
1684QWebHitTestResultPrivate::QWebHitTestResultPrivate(const WebCore::HitTestResult &hitTest)
1685    : isContentEditable(false)
1686    , isContentSelected(false)
1687    , isScrollBar(false)
1688{
1689    if (!hitTest.innerNode())
1690        return;
1691    pos = hitTest.point();
1692    WebCore::TextDirection dir;
1693    title = hitTest.title(dir);
1694    linkText = hitTest.textContent();
1695    linkUrl = hitTest.absoluteLinkURL();
1696    linkTitle = hitTest.titleDisplayString();
1697    alternateText = hitTest.altDisplayString();
1698    imageUrl = hitTest.absoluteImageURL();
1699    innerNode = hitTest.innerNode();
1700    innerNonSharedNode = hitTest.innerNonSharedNode();
1701    boundingRect = innerNonSharedNode ? innerNonSharedNode->renderer()->absoluteBoundingBoxRect(true) : IntRect();
1702    WebCore::Image *img = hitTest.image();
1703    if (img) {
1704        QPixmap *pix = img->nativeImageForCurrentFrame();
1705        if (pix)
1706            pixmap = *pix;
1707    }
1708    WebCore::Frame *wframe = hitTest.targetFrame();
1709    if (wframe)
1710        linkTargetFrame = QWebFramePrivate::kit(wframe);
1711    linkElement = QWebElement(hitTest.URLElement());
1712
1713    isContentEditable = hitTest.isContentEditable();
1714    isContentSelected = hitTest.isSelected();
1715    isScrollBar = hitTest.scrollbar();
1716
1717    if (innerNonSharedNode && innerNonSharedNode->document()
1718        && innerNonSharedNode->document()->frame())
1719        frame = QWebFramePrivate::kit(innerNonSharedNode->document()->frame());
1720
1721    enclosingBlock = QWebElement(WebCore::enclosingBlock(innerNode.get()));
1722}
1723
1724/*!
1725    Constructs a null hit test result.
1726*/
1727QWebHitTestResult::QWebHitTestResult()
1728    : d(0)
1729{
1730}
1731
1732/*!
1733    Constructs a hit test result from \a other.
1734*/
1735QWebHitTestResult::QWebHitTestResult(const QWebHitTestResult &other)
1736    : d(0)
1737{
1738    if (other.d)
1739        d = new QWebHitTestResultPrivate(*other.d);
1740}
1741
1742/*!
1743    Assigns the \a other hit test result to this.
1744*/
1745QWebHitTestResult &QWebHitTestResult::operator=(const QWebHitTestResult &other)
1746{
1747    if (this != &other) {
1748        if (other.d) {
1749            if (!d)
1750                d = new QWebHitTestResultPrivate;
1751            *d = *other.d;
1752        } else {
1753            delete d;
1754            d = 0;
1755        }
1756    }
1757    return *this;
1758}
1759
1760/*!
1761    Destructor.
1762*/
1763QWebHitTestResult::~QWebHitTestResult()
1764{
1765    delete d;
1766}
1767
1768/*!
1769    Returns true if the hit test result is null; otherwise returns false.
1770*/
1771bool QWebHitTestResult::isNull() const
1772{
1773    return !d;
1774}
1775
1776/*!
1777    Returns the position where the hit test occured.
1778*/
1779QPoint QWebHitTestResult::pos() const
1780{
1781    if (!d)
1782        return QPoint();
1783    return d->pos;
1784}
1785
1786/*!
1787    \since 4.5
1788    Returns the bounding rect of the element.
1789*/
1790QRect QWebHitTestResult::boundingRect() const
1791{
1792    if (!d)
1793        return QRect();
1794    return d->boundingRect;
1795}
1796
1797/*!
1798    \since 4.6
1799    Returns the block element that encloses the element hit.
1800
1801    A block element is an element that is rendered using the
1802    CSS "block" style. This includes for example text
1803    paragraphs.
1804*/
1805QWebElement QWebHitTestResult::enclosingBlockElement() const
1806{
1807    if (!d)
1808        return QWebElement();
1809    return d->enclosingBlock;
1810}
1811
1812/*!
1813    Returns the title of the nearest enclosing HTML element.
1814*/
1815QString QWebHitTestResult::title() const
1816{
1817    if (!d)
1818        return QString();
1819    return d->title;
1820}
1821
1822/*!
1823    Returns the text of the link.
1824*/
1825QString QWebHitTestResult::linkText() const
1826{
1827    if (!d)
1828        return QString();
1829    return d->linkText;
1830}
1831
1832/*!
1833    Returns the url to which the link points to.
1834*/
1835QUrl QWebHitTestResult::linkUrl() const
1836{
1837    if (!d)
1838        return QUrl();
1839    return d->linkUrl;
1840}
1841
1842/*!
1843    Returns the title of the link.
1844*/
1845QUrl QWebHitTestResult::linkTitle() const
1846{
1847    if (!d)
1848        return QUrl();
1849    return d->linkTitle;
1850}
1851
1852/*!
1853  \since 4.6
1854  Returns the element that represents the link.
1855
1856  \sa linkTargetFrame()
1857*/
1858QWebElement QWebHitTestResult::linkElement() const
1859{
1860    if (!d)
1861        return QWebElement();
1862    return d->linkElement;
1863}
1864
1865/*!
1866    Returns the frame that will load the link if it is activated.
1867
1868    \sa linkElement()
1869*/
1870QWebFrame *QWebHitTestResult::linkTargetFrame() const
1871{
1872    if (!d)
1873        return 0;
1874    return d->linkTargetFrame;
1875}
1876
1877/*!
1878    Returns the alternate text of the element. This corresponds to the HTML alt attribute.
1879*/
1880QString QWebHitTestResult::alternateText() const
1881{
1882    if (!d)
1883        return QString();
1884    return d->alternateText;
1885}
1886
1887/*!
1888    Returns the url of the image.
1889*/
1890QUrl QWebHitTestResult::imageUrl() const
1891{
1892    if (!d)
1893        return QUrl();
1894    return d->imageUrl;
1895}
1896
1897/*!
1898    Returns a QPixmap containing the image. A null pixmap is returned if the
1899    element being tested is not an image.
1900*/
1901QPixmap QWebHitTestResult::pixmap() const
1902{
1903    if (!d)
1904        return QPixmap();
1905    return d->pixmap;
1906}
1907
1908/*!
1909    Returns true if the content is editable by the user; otherwise returns false.
1910*/
1911bool QWebHitTestResult::isContentEditable() const
1912{
1913    if (!d)
1914        return false;
1915    return d->isContentEditable;
1916}
1917
1918/*!
1919    Returns true if the content tested is part of the selection; otherwise returns false.
1920*/
1921bool QWebHitTestResult::isContentSelected() const
1922{
1923    if (!d)
1924        return false;
1925    return d->isContentSelected;
1926}
1927
1928/*!
1929    \since 4.6
1930    Returns the underlying DOM element as QWebElement.
1931*/
1932QWebElement QWebHitTestResult::element() const
1933{
1934    if (!d || !d->innerNonSharedNode || !d->innerNonSharedNode->isElementNode())
1935        return QWebElement();
1936
1937    return QWebElement(static_cast<WebCore::Element*>(d->innerNonSharedNode.get()));
1938}
1939
1940/*!
1941    Returns the frame the hit test was executed in.
1942*/
1943QWebFrame *QWebHitTestResult::frame() const
1944{
1945    if (!d)
1946        return 0;
1947    return d->frame;
1948}
1949
1950#include "moc_qwebframe.cpp"
1951