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#include "QtPrintContext.h"
25#include "qwebelement.h"
26#include "qwebframe_p.h"
27#include "qwebpage.h"
28#include "qwebpage_p.h"
29#include "qwebscriptworld.h"
30#include "qwebscriptworld_p.h"
31#include "qwebsecurityorigin.h"
32#include "DOMWrapperWorld.h"
33#include <QMultiMap>
34#include <qdebug.h>
35#include <qevent.h>
36#include <qfileinfo.h>
37#include <qpainter.h>
38#if HAVE(QTPRINTSUPPORT)
39#include <qprinter.h>
40#endif
41#include <qnetworkrequest.h>
42#include <qregion.h>
43
44using namespace WebCore;
45
46// from text/qfont.cpp
47QT_BEGIN_NAMESPACE
48extern Q_GUI_EXPORT int qt_defaultDpi();
49QT_END_NAMESPACE
50
51void QWebFramePrivate::setPage(QWebPage* newPage)
52{
53    if (page == newPage)
54        return;
55
56    // The QWebFrame is created as a child of QWebPage or a parent QWebFrame.
57    // That adds it to QObject's internal children list and ensures it will be
58    // deleted when parent QWebPage is deleted. Reparent if needed.
59    if (q->parent() == qobject_cast<QObject*>(page))
60        q->setParent(newPage);
61
62    page = newPage;
63    pageAdapter = newPage->handle();
64    emit q->pageChanged();
65}
66
67void QWebFramePrivate::emitUrlChanged()
68{
69    url = coreFrameUrl();
70    emit q->urlChanged(url);
71}
72
73void QWebFramePrivate::didStartProvisionalLoad()
74{
75    emit q->provisionalLoad();
76}
77
78void QWebFramePrivate::didClearWindowObject()
79{
80    emit q->javaScriptWindowObjectCleared();
81}
82
83bool QWebFramePrivate::handleProgressFinished(QPoint *localPos)
84{
85    QWidget *view = q->page()->view();
86    if (!view || !localPos)
87        return false;
88    *localPos = view->mapFromGlobal(QCursor::pos());
89    return view->hasFocus() && view->rect().contains(*localPos);
90}
91
92void QWebFramePrivate::emitInitialLayoutCompleted()
93{
94    emit q->initialLayoutCompleted();
95}
96
97void QWebFramePrivate::emitIconChanged()
98{
99    emit q->iconChanged();
100}
101
102void QWebFramePrivate::emitLoadStarted(bool originatingLoad)
103{
104    if (page && originatingLoad)
105        emit page->loadStarted();
106    emit q->loadStarted();
107}
108
109void QWebFramePrivate::emitLoadFinished(bool originatingLoad, bool ok)
110{
111    if (page && originatingLoad)
112        emit page->loadFinished(ok);
113    emit q->loadFinished(ok);
114}
115
116QWebFrameAdapter* QWebFramePrivate::createChildFrame(QWebFrameData* frameData)
117{
118    QWebFrame* newFrame = new QWebFrame(/*parent frame*/q, frameData);
119    return newFrame->d;
120}
121
122QWebFrame *QWebFramePrivate::apiHandle()
123{
124    return q;
125}
126
127QObject *QWebFramePrivate::handle()
128{
129    return q;
130}
131
132void QWebFramePrivate::contentsSizeDidChange(const QSize &size)
133{
134    emit q->contentsSizeChanged(size);
135}
136
137int QWebFramePrivate::scrollBarPolicy(Qt::Orientation orientation) const
138{
139    return (int) q->scrollBarPolicy(orientation);
140}
141
142/*!
143    \class QWebFrame
144    \since 4.4
145    \brief The QWebFrame class represents a frame in a web page.
146
147    \inmodule QtWebKit
148
149    QWebFrame represents a frame inside a web page. Each QWebPage
150    object contains at least one frame, the main frame, obtained using
151    QWebPage::mainFrame(). Additional frames will be created for HTML
152    \c{<frame>} or \c{<iframe>} elements.
153
154    A frame can be loaded using load() or setUrl(). Alternatively, if you have
155    the HTML content readily available, you can use setHtml() instead.
156
157    The page() function returns a pointer to the web page object. See
158    \l{QWebView}{Elements of QWebView} for an explanation of how web
159    frames are related to a web page and web view.
160
161    The QWebFrame class also offers methods to retrieve both the URL currently
162    loaded by the frame (see url()) as well as the URL originally requested
163    to be loaded (see requestedUrl()). These methods make possible the retrieval
164    of the URL before and after a DNS resolution or a redirection occurs during
165    the load process. The requestedUrl() also matches to the URL added to the
166    frame history (\l{QWebHistory}) if load is successful.
167
168    The title of an HTML frame can be accessed with the title() property.
169    Additionally, a frame may also specify an icon, which can be accessed
170    using the icon() property. If the title or the icon changes, the
171    corresponding titleChanged() and iconChanged() signals will be emitted.
172    The zoomFactor() property can be used to change the overall size
173    of the content displayed in the frame.
174
175    QWebFrame objects are created and controlled by the web page. You
176    can connect to the web page's \l{QWebPage::}{frameCreated()} signal
177    to be notified when a new frame is created.
178
179    There are multiple ways to programmatically examine the contents of a frame.
180    The hitTestContent() function can be used to find elements by coordinate.
181    For access to the underlying DOM tree, there is documentElement(),
182    findAllElements() and findFirstElement().
183
184    A QWebFrame can be printed onto a QPrinter using the print() function.
185    This function is marked as a slot and can be conveniently connected to
186    \l{QPrintPreviewDialog}'s \l{QPrintPreviewDialog::}{paintRequested()}
187    signal.
188
189    \sa QWebPage
190*/
191
192/*!
193    \enum QWebFrame::RenderLayer
194
195    This enum describes the layers available for rendering using \l{QWebFrame::}{render()}.
196    The layers can be OR-ed together from the following list:
197
198    \value ContentsLayer The web content of the frame
199    \value ScrollBarLayer The scrollbars of the frame
200    \value PanIconLayer The icon used when panning the frame
201
202    \value AllLayers Includes all the above layers
203*/
204
205QWebFrame::QWebFrame(QWebPage *parentPage)
206    : QObject(parentPage)
207    , d(new QWebFramePrivate)
208{
209    d->page = parentPage;
210    d->q = this;
211    d->init(/*page adapter*/ parentPage->handle());
212
213#if ENABLE(ORIENTATION_EVENTS) && HAVE(QTSENSORS)
214    connect(&d->m_orientation, SIGNAL(readingChanged()), this, SLOT(_q_orientationChanged()));
215    d->m_orientation.start();
216#endif
217}
218
219QWebFrame::QWebFrame(QWebFrame* parent, QWebFrameData* frameData)
220    : QObject(parent)
221    , d(new QWebFramePrivate)
222{
223    d->page = parent->d->page;
224    d->q = this;
225    d->init(parent->d->pageAdapter, frameData);
226#if ENABLE(ORIENTATION_EVENTS) && HAVE(QTSENSORS)
227    connect(&d->m_orientation, SIGNAL(readingChanged()), this, SLOT(_q_orientationChanged()));
228    d->m_orientation.start();
229#endif
230}
231
232QWebFrame::~QWebFrame()
233{
234    delete d;
235}
236
237/*!
238    \fn void QWebFrame::addToJavaScriptWindowObject(const QString &name, QObject *object, ValueOwnership own)
239
240    Make \a object available under \a name from within the frame's JavaScript
241    context. The \a object will be inserted as a child of the frame's window
242    object.
243
244    Qt properties will be exposed as JavaScript properties and slots as
245    JavaScript methods.
246    The interaction between C++ and JavaScript is explained in the documentation of the \l{The Qt WebKit Bridge}{Qt WebKit bridge}.
247
248    If you want to ensure that your QObjects remain accessible after loading a
249    new URL, you should add them in a slot connected to the
250    javaScriptWindowObjectCleared() signal.
251
252    If Javascript is not enabled for this page, then this method does nothing.
253
254    The ownership of \a object is specified using \a own.
255*/
256void QWebFrame::addToJavaScriptWindowObject(const QString &name, QObject *object, ValueOwnership ownership)
257{
258    d->addToJavaScriptWindowObject(name, object, static_cast<QWebFrameAdapter::ValueOwnership>(ownership));
259}
260
261/*!
262    Returns the frame's content as HTML, enclosed in HTML and BODY tags.
263
264    \sa setHtml(), toPlainText()
265*/
266QString QWebFrame::toHtml() const
267{
268    return d->toHtml();
269}
270
271/*!
272    Returns the content of this frame converted to plain text, completely
273    stripped of all HTML formatting.
274
275    \sa toHtml()
276*/
277QString QWebFrame::toPlainText() const
278{
279    return d->toPlainText();
280}
281
282/*!
283    \property QWebFrame::title
284    \brief the title of the frame as defined by the HTML &lt;title&gt; element
285
286    \sa titleChanged()
287*/
288
289QString QWebFrame::title() const
290{
291    return d->title();
292}
293
294/*!
295    \since 4.5
296    \brief Returns the meta data in this frame as a QMultiMap
297
298    The meta data consists of the name and content attributes of the
299    of the \c{<meta>} tags in the HTML document.
300
301    For example:
302
303    \code
304    <html>
305        <head>
306            <meta name="description" content="This document is a tutorial about Qt development">
307            <meta name="keywords" content="Qt, WebKit, Programming">
308        </head>
309        ...
310    </html>
311    \endcode
312
313    Given the above HTML code the metaData() function will return a map with two entries:
314    \table
315    \header \li Key
316            \li Value
317    \row    \li "description"
318            \li "This document is a tutorial about Qt development"
319    \row    \li "keywords"
320            \li "Qt, WebKit, Programming"
321    \endtable
322
323    This function returns a multi map to support multiple meta tags with the same attribute name.
324*/
325QMultiMap<QString, QString> QWebFrame::metaData() const
326{
327    return d->metaData();
328}
329
330/*!
331    \property QWebFrame::url
332    \brief the url of the frame currently viewed
333
334    Setting this property clears the view and loads the URL.
335
336    By default, this property contains an empty, invalid URL.
337
338    \sa urlChanged()
339*/
340
341void QWebFrame::setUrl(const QUrl &url)
342{
343    d->clearCoreFrame();
344    const QUrl absolute = QWebFrameAdapter::ensureAbsoluteUrl(url);
345    d->url = absolute;
346    load(absolute);
347}
348
349QUrl QWebFrame::url() const
350{
351    return d->url;
352}
353
354/*!
355    \since 4.6
356    \property QWebFrame::requestedUrl
357
358    The URL requested to loaded by the frame currently viewed. The URL may differ from
359    the one returned by url() if a DNS resolution or a redirection occurs.
360
361    \sa url(), setUrl()
362*/
363QUrl QWebFrame::requestedUrl() const
364{
365    return d->lastRequestedUrl();
366}
367/*!
368    \since 4.6
369    \property QWebFrame::baseUrl
370    \brief the base URL of the frame, can be used to resolve relative URLs
371    \since 4.6
372*/
373
374QUrl QWebFrame::baseUrl() const
375{
376    return d->baseUrl();
377}
378
379/*!
380    \property QWebFrame::icon
381    \brief the icon associated with this frame
382
383    \sa iconChanged(), QWebSettings::iconForUrl()
384*/
385
386QIcon QWebFrame::icon() const
387{
388    return QWebSettings::iconForUrl(d->coreFrameUrl());
389}
390
391/*!
392  The name of this frame as defined by the parent frame.
393*/
394QString QWebFrame::frameName() const
395{
396    return d->uniqueName();
397}
398
399/*!
400  The web page that contains this frame.
401
402  \sa pageChanged()
403*/
404QWebPage *QWebFrame::page() const
405{
406    return d->page;
407}
408
409/*!
410  Loads \a url into this frame.
411
412  \note The view remains the same until enough data has arrived to display the new \a url.
413
414  \sa setUrl(), setHtml(), setContent()
415*/
416void QWebFrame::load(const QUrl &url)
417{
418    // The load() overload ensures that the url is absolute.
419    load(QNetworkRequest(url));
420}
421
422/*!
423  Loads a network request, \a req, into this frame, using the method specified in \a
424  operation.
425
426  \a body is optional and is only used for POST operations.
427
428  \note The view remains the same until enough data has arrived to display the new content.
429
430  \sa setUrl()
431*/
432void QWebFrame::load(const QNetworkRequest &req, QNetworkAccessManager::Operation operation, const QByteArray &body)
433{
434    d->load(req, operation, body);
435}
436
437/*!
438  Sets the content of this frame to \a html. \a baseUrl is optional and used to resolve relative
439  URLs in the document, such as referenced images or stylesheets.
440
441  The \a html is loaded immediately; external objects are loaded asynchronously.
442
443  If a script in the \a html runs longer than the default script timeout (currently 10 seconds),
444  for example due to being blocked by a modal JavaScript alert dialog, this method will return
445  as soon as possible after the timeout and any subsequent \a html will be loaded asynchronously.
446
447  When using this method WebKit assumes that external resources such as JavaScript programs or style
448  sheets are encoded in UTF-8 unless otherwise specified. For example, the encoding of an external
449  script can be specified through the charset attribute of the HTML script tag. It is also possible
450  for the encoding to be specified by web server.
451
452  This is a convenience function equivalent to setContent(html, "text/html", baseUrl).
453
454  \note This method will not affect session or global history for the frame.
455
456  \warning This function works only for HTML, for other mime types (i.e. XHTML, SVG)
457  setContent() should be used instead.
458
459  \sa toHtml(), setContent(), load()
460*/
461void QWebFrame::setHtml(const QString &html, const QUrl &baseUrl)
462{
463    d->setHtml(html, baseUrl);
464}
465
466/*!
467  Sets the content of this frame to the specified content \a data. If the \a mimeType argument
468  is empty it is currently assumed that the content is HTML but in future versions we may introduce
469  auto-detection.
470
471  External objects referenced in the content are located relative to \a baseUrl.
472
473  The \a data is loaded immediately; external objects are loaded asynchronously.
474
475  \note This method will not affect session or global history for the frame.
476
477  \sa toHtml(), setHtml()
478*/
479void QWebFrame::setContent(const QByteArray &data, const QString &mimeType, const QUrl &baseUrl)
480{
481    d->setContent(data, mimeType, baseUrl);
482}
483
484/*!
485  Returns the parent frame of this frame, or 0 if the frame is the web pages
486  main frame.
487
488  This is equivalent to qobject_cast<QWebFrame*>(frame->parent()).
489
490  \sa childFrames()
491*/
492QWebFrame *QWebFrame::parentFrame() const
493{
494    return d->parentFrame();
495}
496
497/*!
498  Returns a list of all frames that are direct children of this frame.
499
500  \sa parentFrame()
501*/
502QList<QWebFrame*> QWebFrame::childFrames() const
503{
504    QList<QObject*> objects = d->childFrames();
505    QList<QWebFrame*> rc;
506    rc.reserve(objects.size());
507    Q_FOREACH(QObject* object, objects) {
508        if (QWebFrame* frame = qobject_cast<QWebFrame*>(object))
509            rc.append(frame);
510    }
511
512    return rc;
513}
514
515/*!
516    Returns the scrollbar policy for the scrollbar defined by \a orientation.
517*/
518Qt::ScrollBarPolicy QWebFrame::scrollBarPolicy(Qt::Orientation orientation) const
519{
520    if (orientation == Qt::Horizontal)
521        return d->horizontalScrollBarPolicy;
522    return d->verticalScrollBarPolicy;
523}
524
525/*!
526    Sets the scrollbar policy for the scrollbar defined by \a orientation to \a policy.
527*/
528void QWebFrame::setScrollBarPolicy(Qt::Orientation orientation, Qt::ScrollBarPolicy policy)
529{
530    d->setScrollBarPolicy(orientation, policy);
531}
532
533/*!
534  Sets the current \a value for the scrollbar with orientation \a orientation.
535
536  The scrollbar forces the \a value to be within the legal range: minimum <= value <= maximum.
537
538  Changing the value also updates the thumb position.
539
540  \sa scrollBarMinimum(), scrollBarMaximum()
541*/
542void QWebFrame::setScrollBarValue(Qt::Orientation orientation, int value)
543{
544    d->setScrollBarValue(orientation, value);
545}
546
547/*!
548  Returns the current value for the scrollbar with orientation \a orientation, or 0
549  if no scrollbar is found for \a orientation.
550
551  \sa scrollBarMinimum(), scrollBarMaximum()
552*/
553int QWebFrame::scrollBarValue(Qt::Orientation orientation) const
554{
555    return d->scrollBarValue(orientation);
556}
557
558/*!
559  Returns the maximum value for the scrollbar with orientation \a orientation, or 0
560  if no scrollbar is found for \a orientation.
561
562  \sa scrollBarMinimum()
563*/
564int QWebFrame::scrollBarMaximum(Qt::Orientation orientation) const
565{
566    return d->scrollBarMaximum(orientation);
567}
568
569/*!
570  Returns the minimum value for the scrollbar with orientation \a orientation.
571
572  The minimum value is always 0.
573
574  \sa scrollBarMaximum()
575*/
576int QWebFrame::scrollBarMinimum(Qt::Orientation orientation) const
577{
578    Q_UNUSED(orientation);
579    return 0;
580}
581
582/*!
583  \since 4.6
584  Returns the geometry for the scrollbar with orientation \a orientation.
585
586  If the scrollbar does not exist an empty rect is returned.
587*/
588QRect QWebFrame::scrollBarGeometry(Qt::Orientation orientation) const
589{
590    return d->scrollBarGeometry(orientation);
591}
592
593/*!
594  \since 4.5
595  Scrolls the frame \a dx pixels to the right and \a dy pixels downward. Both
596  \a dx and \a dy may be negative.
597
598  \sa QWebFrame::scrollPosition
599*/
600
601void QWebFrame::scroll(int dx, int dy)
602{
603    d->scrollBy(dx, dy);
604}
605
606/*!
607  \property QWebFrame::scrollPosition
608  \since 4.5
609  \brief the position the frame is currently scrolled to.
610*/
611
612QPoint QWebFrame::scrollPosition() const
613{
614    return d->scrollPosition();
615}
616
617void QWebFrame::setScrollPosition(const QPoint &pos)
618{
619    QPoint current = scrollPosition();
620    int dx = pos.x() - current.x();
621    int dy = pos.y() - current.y();
622    scroll(dx, dy);
623}
624
625/*!
626  \since 4.7
627  Scrolls the frame to the given \a anchor name.
628*/
629void QWebFrame::scrollToAnchor(const QString& anchor)
630{
631    d->scrollToAnchor(anchor);
632}
633
634/*!
635  \since 4.6
636  Render the \a layer of the frame using \a painter clipping to \a clip.
637
638  \sa print()
639*/
640
641void QWebFrame::render(QPainter* painter, RenderLayers layer, const QRegion& clip)
642{
643    if (!clip.isEmpty())
644        d->renderRelativeCoords(painter, layer, clip);
645    else if (d->hasView())
646        d->renderRelativeCoords(painter, layer, QRegion(d->frameRect()));
647}
648
649/*!
650  Render the frame into \a painter clipping to \a clip.
651*/
652void QWebFrame::render(QPainter* painter, const QRegion& clip)
653{
654    render(painter, AllLayers, clip);
655}
656
657/*!
658    \property QWebFrame::textSizeMultiplier
659    \brief the scaling factor for all text in the frame
660    \obsolete
661
662    Use setZoomFactor instead, in combination with the ZoomTextOnly attribute in
663    QWebSettings.
664
665    \note Setting this property also enables the ZoomTextOnly attribute in
666    QWebSettings.
667*/
668
669/*!
670    Sets the value of the multiplier used to scale the text in a Web frame to
671    the \a factor specified.
672*/
673void QWebFrame::setTextSizeMultiplier(qreal factor)
674{
675    d->setTextSizeMultiplier(factor);
676}
677
678/*!
679    Returns the value of the multiplier used to scale the text in a Web frame.
680*/
681qreal QWebFrame::textSizeMultiplier() const
682{
683    return d->zoomFactor();
684}
685
686/*!
687    \property QWebFrame::zoomFactor
688    \since 4.5
689    \brief the zoom factor for the frame
690*/
691
692void QWebFrame::setZoomFactor(qreal factor)
693{
694    d->setZoomFactor(factor);
695}
696
697qreal QWebFrame::zoomFactor() const
698{
699    return d->zoomFactor();
700}
701
702/*!
703    \property QWebFrame::focus
704    \since 4.6
705
706    Returns true if this frame has keyboard input focus; otherwise, returns false.
707*/
708bool QWebFrame::hasFocus() const
709{
710    return d->hasFocus();
711}
712
713/*!
714    \since 4.6
715
716    Gives keyboard input focus to this frame.
717*/
718void QWebFrame::setFocus()
719{
720    d->setFocus();
721}
722
723/*!
724    Returns the position of the frame relative to it's parent frame.
725*/
726QPoint QWebFrame::pos() const
727{
728    if (!d->hasView())
729        return QPoint();
730
731    return d->frameRect().topLeft();
732}
733
734/*!
735    Return the geometry of the frame relative to it's parent frame.
736*/
737QRect QWebFrame::geometry() const
738{
739    return d->frameRect();
740}
741
742/*!
743    \property QWebFrame::contentsSize
744    \brief the size of the contents in this frame
745
746    \sa contentsSizeChanged()
747*/
748QSize QWebFrame::contentsSize() const
749{
750    return d->contentsSize();
751}
752
753/*!
754    \since 4.6
755
756    Returns the document element of this frame.
757
758    The document element provides access to the entire structured
759    content of the frame.
760*/
761QWebElement QWebFrame::documentElement() const
762{
763    return d->documentElement();
764}
765
766/*!
767    \since 4.6
768    Returns a new list of elements matching the given CSS selector \a selectorQuery.
769    If there are no matching elements, an empty list is returned.
770
771    \l{http://www.w3.org/TR/REC-CSS2/selector.html#q1}{Standard CSS2 selector} syntax is
772    used for the query.
773
774    \sa QWebElement::findAll()
775*/
776QWebElementCollection QWebFrame::findAllElements(const QString &selectorQuery) const
777{
778    return documentElement().findAll(selectorQuery);
779}
780
781/*!
782    \since 4.6
783    Returns the first element in the frame's document that matches the
784    given CSS selector \a selectorQuery. If there is no matching element, a
785    null element is returned.
786
787    \l{http://www.w3.org/TR/REC-CSS2/selector.html#q1}{Standard CSS2 selector} syntax is
788    used for the query.
789
790    \sa QWebElement::findFirst()
791*/
792QWebElement QWebFrame::findFirstElement(const QString &selectorQuery) const
793{
794    return documentElement().findFirst(selectorQuery);
795}
796
797/*!
798    Performs a hit test on the frame contents at the given position \a pos and returns the hit test result.
799*/
800QWebHitTestResult QWebFrame::hitTestContent(const QPoint &pos) const
801{
802    QWebHitTestResultPrivate* result = d->hitTestContent(pos);
803
804    if (!result)
805        return QWebHitTestResult();
806
807    return QWebHitTestResult(result);
808}
809
810/*! \reimp
811*/
812bool QWebFrame::event(QEvent *e)
813{
814    return QObject::event(e);
815}
816
817#ifndef QT_NO_PRINTER
818/*!
819    Prints the frame to the given \a printer.
820
821    \sa render()
822*/
823void QWebFrame::print(QPrinter *printer) const
824{
825#if HAVE(QTPRINTSUPPORT)
826    QPainter painter;
827    if (!painter.begin(printer))
828        return;
829
830    const qreal zoomFactorX = (qreal)printer->logicalDpiX() / qt_defaultDpi();
831    const qreal zoomFactorY = (qreal)printer->logicalDpiY() / qt_defaultDpi();
832
833    QRect qprinterRect = printer->pageRect();
834
835    QRect pageRect(0, 0, int(qprinterRect.width() / zoomFactorX), int(qprinterRect.height() / zoomFactorY));
836
837    QtPrintContext printContext(&painter, pageRect, d);
838
839    int docCopies;
840    int pageCopies;
841    if (printer->collateCopies()) {
842        docCopies = 1;
843        pageCopies = printer->numCopies();
844    } else {
845        docCopies = printer->numCopies();
846        pageCopies = 1;
847    }
848
849    int fromPage = printer->fromPage();
850    int toPage = printer->toPage();
851    bool ascending = true;
852
853    if (!fromPage && !toPage) {
854        fromPage = 1;
855        toPage = printContext.pageCount();
856    }
857    // paranoia check
858    fromPage = qMax(1, fromPage);
859    toPage = qMin(static_cast<int>(printContext.pageCount()), toPage);
860    if (toPage < fromPage) {
861        // if the user entered a page range outside the actual number
862        // of printable pages, just return
863        return;
864    }
865
866    if (printer->pageOrder() == QPrinter::LastPageFirst) {
867        int tmp = fromPage;
868        fromPage = toPage;
869        toPage = tmp;
870        ascending = false;
871    }
872
873    painter.scale(zoomFactorX, zoomFactorY);
874
875    for (int i = 0; i < docCopies; ++i) {
876        int page = fromPage;
877        while (true) {
878            for (int j = 0; j < pageCopies; ++j) {
879                if (printer->printerState() == QPrinter::Aborted
880                    || printer->printerState() == QPrinter::Error) {
881                    return;
882                }
883                printContext.spoolPage(page - 1, pageRect.width());
884                if (j < pageCopies - 1)
885                    printer->newPage();
886            }
887
888            if (page == toPage)
889                break;
890
891            if (ascending)
892                ++page;
893            else
894                --page;
895
896            printer->newPage();
897        }
898
899        if (i < docCopies - 1)
900            printer->newPage();
901    }
902#endif // HAVE(PRINTSUPPORT)
903}
904#endif // QT_NO_PRINTER
905
906/*!
907    Evaluates the JavaScript defined by \a scriptSource using this frame as context
908    and returns the result of the last executed statement.
909
910    \sa addToJavaScriptWindowObject(), javaScriptWindowObjectCleared()
911*/
912QVariant QWebFrame::evaluateJavaScript(const QString& scriptSource)
913{
914    return d->evaluateJavaScript(scriptSource);
915}
916
917/*!
918    \since 4.5
919
920    Returns the frame's security origin.
921*/
922QWebSecurityOrigin QWebFrame::securityOrigin() const
923{
924    return d->securityOrigin();
925}
926
927QWebFrame *QWebFramePrivate::kit(const QWebFrameAdapter* frameAdapter)
928{
929    return static_cast<const QWebFramePrivate*>(frameAdapter)->q;
930}
931
932
933/*!
934    \fn void QWebFrame::javaScriptWindowObjectCleared()
935
936    This signal is emitted whenever the global window object of the JavaScript
937    environment is cleared, e.g., before starting a new load.
938
939    If you intend to add QObjects to a QWebFrame using
940    addToJavaScriptWindowObject(), you should add them in a slot connected
941    to this signal. This ensures that your objects remain accessible when
942    loading new URLs.
943*/
944
945/*!
946    \fn void QWebFrame::provisionalLoad()
947    \internal
948*/
949
950/*!
951    \fn void QWebFrame::titleChanged(const QString &title)
952
953    This signal is emitted whenever the title of the frame changes.
954    The \a title string specifies the new title.
955
956    \sa title()
957*/
958
959/*!
960    \fn void QWebFrame::urlChanged(const QUrl &url)
961
962    This signal is emitted with the URL of the frame when the frame's title is
963    received. The new URL is specified by \a url.
964
965    \sa url()
966*/
967
968/*!
969    \fn void QWebFrame::initialLayoutCompleted()
970
971    This signal is emitted when the frame is laid out the first time.
972    This is the first time you will see contents displayed on the frame.
973
974    \note A frame can be laid out multiple times.
975*/
976
977/*!
978  \fn void QWebFrame::iconChanged()
979
980  This signal is emitted when the icon ("favicon") associated with the frame
981  has been loaded.
982
983  \sa icon()
984*/
985
986/*!
987  \fn void QWebFrame::contentsSizeChanged(const QSize &size)
988  \since 4.6
989
990  This signal is emitted when the frame's contents size changes
991  to \a size.
992
993  \sa contentsSize()
994*/
995
996/*!
997    \fn void QWebFrame::loadStarted()
998    \since 4.6
999
1000    This signal is emitted when a new load of this frame is started.
1001
1002    \sa loadFinished()
1003*/
1004
1005/*!
1006    \fn void QWebFrame::loadFinished(bool ok)
1007    \since 4.6
1008
1009    This signal is emitted when a load of this frame is finished.
1010    \a ok will indicate whether the load was successful or any error occurred.
1011
1012    \sa loadStarted()
1013*/
1014
1015/*!
1016    \fn void QWebFrame::pageChanged()
1017    \since 4.7
1018
1019    This signal is emitted when this frame has been moved to a different QWebPage.
1020
1021    \sa page()
1022*/
1023
1024/*!
1025    \class QWebHitTestResult
1026    \since 4.4
1027    \brief The QWebHitTestResult class provides information about the web
1028    page content after a hit test.
1029
1030    \inmodule QtWebKit
1031
1032    QWebHitTestResult is returned by QWebFrame::hitTestContent() to provide
1033    information about the content of the web page at the specified position.
1034*/
1035
1036/*!
1037    \internal
1038*/
1039QWebHitTestResult::QWebHitTestResult(QWebHitTestResultPrivate *priv)
1040    : d(priv)
1041{
1042}
1043
1044/*!
1045    Constructs a null hit test result.
1046*/
1047QWebHitTestResult::QWebHitTestResult()
1048    : d(0)
1049{
1050}
1051
1052/*!
1053    Constructs a hit test result from \a other.
1054*/
1055QWebHitTestResult::QWebHitTestResult(const QWebHitTestResult &other)
1056    : d(0)
1057{
1058    if (other.d)
1059        d = new QWebHitTestResultPrivate(*other.d);
1060}
1061
1062/*!
1063    Assigns the \a other hit test result to this.
1064*/
1065QWebHitTestResult &QWebHitTestResult::operator=(const QWebHitTestResult &other)
1066{
1067    if (this != &other) {
1068        if (other.d) {
1069            if (!d)
1070                d = new QWebHitTestResultPrivate;
1071            *d = *other.d;
1072        } else {
1073            delete d;
1074            d = 0;
1075        }
1076    }
1077    return *this;
1078}
1079
1080/*!
1081    Destructor.
1082*/
1083QWebHitTestResult::~QWebHitTestResult()
1084{
1085    delete d;
1086}
1087
1088/*!
1089    Returns true if the hit test result is null; otherwise returns false.
1090*/
1091bool QWebHitTestResult::isNull() const
1092{
1093    return !d;
1094}
1095
1096/*!
1097    Returns the position where the hit test occured in the coordinates of frame containing the element hit.
1098
1099    \sa frame()
1100*/
1101QPoint QWebHitTestResult::pos() const
1102{
1103    if (!d)
1104        return QPoint();
1105    return d->pos;
1106}
1107
1108/*!
1109    \since 4.5
1110    Returns the bounding rect of the element.
1111*/
1112QRect QWebHitTestResult::boundingRect() const
1113{
1114    if (!d)
1115        return QRect();
1116    return d->boundingRect;
1117}
1118
1119/*!
1120    \since 4.6
1121    Returns the block element that encloses the element hit.
1122
1123    A block element is an element that is rendered using the
1124    CSS "block" style. This includes for example text
1125    paragraphs.
1126*/
1127QWebElement QWebHitTestResult::enclosingBlockElement() const
1128{
1129    if (!d)
1130        return QWebElement();
1131    return d->enclosingBlock;
1132}
1133
1134/*!
1135    Returns the title of the nearest enclosing HTML element.
1136*/
1137QString QWebHitTestResult::title() const
1138{
1139    if (!d)
1140        return QString();
1141    return d->title;
1142}
1143
1144/*!
1145    Returns the text of the link.
1146*/
1147QString QWebHitTestResult::linkText() const
1148{
1149    if (!d)
1150        return QString();
1151    return d->linkText;
1152}
1153
1154/*!
1155    Returns the url to which the link points to.
1156*/
1157QUrl QWebHitTestResult::linkUrl() const
1158{
1159    if (!d)
1160        return QUrl();
1161    return d->linkUrl;
1162}
1163
1164/*!
1165    Returns the title of the link.
1166*/
1167QUrl QWebHitTestResult::linkTitle() const
1168{
1169    if (!d)
1170        return QUrl();
1171    return d->linkTitle;
1172}
1173
1174/*!
1175  \since 4.6
1176  Returns the element that represents the link.
1177
1178  \sa linkTargetFrame()
1179*/
1180QWebElement QWebHitTestResult::linkElement() const
1181{
1182    if (!d)
1183        return QWebElement();
1184    return d->linkElement;
1185}
1186
1187/*!
1188    Returns the frame that will load the link if it is activated.
1189
1190    \sa linkElement()
1191*/
1192QWebFrame *QWebHitTestResult::linkTargetFrame() const
1193{
1194    if (!d)
1195        return 0;
1196    return qobject_cast<QWebFrame*>(d->linkTargetFrame.data());
1197}
1198
1199/*!
1200    Returns the alternate text of the element. This corresponds to the HTML alt attribute.
1201*/
1202QString QWebHitTestResult::alternateText() const
1203{
1204    if (!d)
1205        return QString();
1206    return d->alternateText;
1207}
1208
1209/*!
1210    Returns the url of the image.
1211*/
1212QUrl QWebHitTestResult::imageUrl() const
1213{
1214    if (!d)
1215        return QUrl();
1216    return d->imageUrl;
1217}
1218
1219/*!
1220    Returns a QPixmap containing the image. A null pixmap is returned if the
1221    element being tested is not an image.
1222*/
1223QPixmap QWebHitTestResult::pixmap() const
1224{
1225    if (!d)
1226        return QPixmap();
1227    return d->pixmap;
1228}
1229
1230/*!
1231    Returns true if the content is editable by the user; otherwise returns false.
1232*/
1233bool QWebHitTestResult::isContentEditable() const
1234{
1235    if (!d)
1236        return false;
1237    return d->isContentEditable;
1238}
1239
1240/*!
1241    Returns true if the content tested is part of the selection; otherwise returns false.
1242*/
1243bool QWebHitTestResult::isContentSelected() const
1244{
1245    if (!d)
1246        return false;
1247    return d->isContentSelected;
1248}
1249
1250/*!
1251    \since 4.6
1252    Returns the underlying DOM element as QWebElement.
1253*/
1254QWebElement QWebHitTestResult::element() const
1255{
1256    if (!d)
1257        return QWebElement();
1258
1259    return d->elementForInnerNode();
1260}
1261
1262/*!
1263    Returns the frame of the element hit.
1264*/
1265QWebFrame *QWebHitTestResult::frame() const
1266{
1267    if (!d)
1268        return 0;
1269    return qobject_cast<QWebFrame*>(d->frame.data());
1270}
1271
1272/*!
1273 * \internal
1274 */
1275QWebFrameAdapter *QWebFrame::handle() const
1276{
1277    return d;
1278}
1279
1280#include "moc_qwebframe.cpp"
1281