Fixes QWebFrame::setScrollBarPolicy(..) to actually work. Also happens
[WebKit-https.git] / WebKit / qt / Api / qwebframe.cpp
1 /*
2     Copyright (C) 2008 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 #include "qwebpage.h"
24 #include "qwebpage_p.h"
25 #include "qwebframe_p.h"
26 #include "qwebsecurityorigin.h"
27 #include "qwebsecurityorigin_p.h"
28
29 #include "DocumentLoader.h"
30 #include "FocusController.h"
31 #include "FrameLoaderClientQt.h"
32 #include "Frame.h"
33 #include "FrameTree.h"
34 #include "FrameView.h"
35 #include "IconDatabase.h"
36 #include "InspectorController.h"
37 #include "Page.h"
38 #include "PutPropertySlot.h"
39 #include "ResourceRequest.h"
40 #include "RenderView.h"
41 #include "SelectionController.h"
42 #include "Scrollbar.h"
43 #include "PrintContext.h"
44 #include "SubstituteData.h"
45
46 #include "markup.h"
47 #include "htmlediting.h"
48 #include "RenderTreeAsText.h"
49 #include "Element.h"
50 #include "Document.h"
51 #include "DragData.h"
52 #include "RenderView.h"
53 #include "GraphicsContext.h"
54 #include "PlatformMouseEvent.h"
55 #include "PlatformWheelEvent.h"
56 #include "GraphicsContext.h"
57 #include "HitTestResult.h"
58
59 #include "CallFrame.h"
60 #include "JSDOMBinding.h"
61 #include "JSDOMWindow.h"
62 #include "JSLock.h"
63 #include "JSObject.h"
64 #include "qt_instance.h"
65 #include "qt_runtime.h"
66 #include "runtime.h"
67 #include "runtime_object.h"
68 #include "runtime_root.h"
69 #include "ScriptController.h"
70 #include "ScriptSourceCode.h"
71 #include "ScriptValue.h"
72
73 #include "wtf/HashMap.h"
74
75 #include <qdebug.h>
76 #include <qevent.h>
77 #include <qfileinfo.h>
78 #include <qpainter.h>
79 #include <QMultiMap>
80 #if QT_VERSION >= 0x040400
81 #include <qnetworkrequest.h>
82 #else
83 #include "qwebnetworkinterface.h"
84 #endif
85 #include <qregion.h>
86 #include <qprinter.h>
87 #include "HTMLMetaElement.h"
88 #include "NodeList.h"
89
90 using namespace WebCore;
91
92 // from text/qfont.cpp
93 QT_BEGIN_NAMESPACE
94 extern Q_GUI_EXPORT int qt_defaultDpi();
95 QT_END_NAMESPACE
96
97 void QWEBKIT_EXPORT qt_drt_setJavaScriptProfilingEnabled(QWebFrame* qframe, bool enabled)
98 {
99     Frame* frame = QWebFramePrivate::core(qframe);
100     InspectorController* controller = frame->page()->inspectorController();
101     if (!controller)
102         return;
103     if (enabled)
104         controller->enableProfiler();
105     else
106         controller->disableProfiler();
107 }
108
109 void QWebFramePrivate::init(QWebFrame *qframe, WebCore::Page *webcorePage, QWebFrameData *frameData)
110 {
111     q = qframe;
112
113     allowsScrolling = frameData->allowsScrolling;
114     marginWidth = frameData->marginWidth;
115     marginHeight = frameData->marginHeight;
116
117     frameLoaderClient = new FrameLoaderClientQt();
118     RefPtr<Frame> newFrame = Frame::create(webcorePage, frameData->ownerElement, frameLoaderClient);
119     frame = newFrame.get();
120     frameLoaderClient->setFrame(qframe, frame);
121
122     // FIXME: All of the below should probably be moved over into WebCore
123     frame->tree()->setName(frameData->name);
124     if (QWebFrame* _parentFrame = parentFrame())
125         QWebFramePrivate::core(_parentFrame)->tree()->appendChild(frame);
126
127     // balanced by adoptRef in FrameLoaderClientQt::createFrame
128     if (frameData->ownerElement)
129         frame->ref();
130
131     frame->init();
132 }
133
134 WebCore::Scrollbar* QWebFramePrivate::horizontalScrollBar() const
135 {
136     if (!frame->view())
137         return 0;
138     return frame->view()->horizontalScrollbar();
139 }
140
141 WebCore::Scrollbar* QWebFramePrivate::verticalScrollBar() const
142 {
143     if (!frame->view())
144         return 0;
145     return frame->view()->verticalScrollbar();
146 }
147
148 /*!
149     \class QWebFrame
150     \since 4.4
151     \brief The QWebFrame class represents a frame in a web page.
152
153     QWebFrame represents a frame inside a web page. Each QWebPage
154     object contains at least one frame, the main frame, obtained using
155     QWebPage::mainFrame(). Additional frames will be created for HTML
156     \c{<frame>} or \c{<iframe>} elements.
157
158     A frame can be loaded using load() or setUrl(). Alternatively, if you have
159     the HTML content readily available, you can use setHtml() instead.
160
161     The page() function returns a pointer to the web page object. See
162     \l{Elements of QWebView} for an explanation of how web
163     frames are related to a web page and web view.
164
165     The title of an HTML frame can be accessed with the title() property.
166     Additionally, a frame may also specify an icon, which can be accessed
167     using the icon() property. If the title or the icon changes, the
168     corresponding titleChanged() and iconChanged() signals will be emitted.
169     The zoomFactor() property can be used to change the overall size
170     of the content displayed in the frame.
171
172     QWebFrame objects are created and controlled by the web page. You
173     can connect to the web page's \l{QWebPage::}{frameCreated()} signal
174     to be notified when a new frame is created.
175
176     The hitTestContent() function can be used to programmatically examine the
177     contents of a frame.
178
179     A QWebFrame can be printed onto a QPrinter using the print() function.
180     This function is marked as a slot and can be conveniently connected to
181     \l{QPrintPreviewDialog}'s \l{QPrintPreviewDialog::}{paintRequested()}
182     signal.
183
184     \sa QWebPage
185 */
186
187 QWebFrame::QWebFrame(QWebPage *parent, QWebFrameData *frameData)
188     : QObject(parent)
189     , d(new QWebFramePrivate)
190 {
191     d->page = parent;
192     d->init(this, parent->d->page, frameData);
193
194     if (!frameData->url.isEmpty()) {
195         WebCore::ResourceRequest request(frameData->url, frameData->referrer);
196         d->frame->loader()->load(request, frameData->name);
197     }
198 }
199
200 QWebFrame::QWebFrame(QWebFrame *parent, QWebFrameData *frameData)
201     : QObject(parent)
202     , d(new QWebFramePrivate)
203 {
204     d->page = parent->d->page;
205     d->init(this, parent->d->page->d->page, frameData);
206 }
207
208 QWebFrame::~QWebFrame()
209 {
210     if (d->frame && d->frame->loader() && d->frame->loader()->client())
211         static_cast<FrameLoaderClientQt*>(d->frame->loader()->client())->m_webFrame = 0;
212
213     delete d;
214 }
215
216 /*!
217     Make \a object available under \a name from within the frame's JavaScript
218     context. The \a object will be inserted as a child of the frame's window
219     object.
220
221     Qt properties will be exposed as JavaScript properties and slots as
222     JavaScript methods.
223
224     If you want to ensure that your QObjects remain accessible after loading a
225     new URL, you should add them in a slot connected to the
226     javaScriptWindowObjectCleared() signal.
227 */
228 void QWebFrame::addToJavaScriptWindowObject(const QString &name, QObject *object)
229 {
230       JSC::JSLock lock(false);
231       JSDOMWindow *window = toJSDOMWindow(d->frame);
232       JSC::Bindings::RootObject *root = d->frame->script()->bindingRootObject();
233       if (!window) {
234           qDebug() << "Warning: couldn't get window object";
235           return;
236       }
237
238       JSC::ExecState* exec = window->globalExec();
239
240       JSC::JSObject *runtimeObject =
241         JSC::Bindings::Instance::createRuntimeObject(exec, JSC::Bindings::QtInstance::getQtInstance(object, root));
242
243       JSC::PutPropertySlot slot;
244       window->put(exec, JSC::Identifier(exec, (const UChar *) name.constData(), name.length()), runtimeObject, slot);
245 }
246
247 /*!
248     Returns the frame's content, converted to HTML.
249
250     \sa setHtml(), toPlainText()
251 */
252 QString QWebFrame::toHtml() const
253 {
254     if (!d->frame->document())
255         return QString();
256     return createMarkup(d->frame->document());
257 }
258
259 /*!
260     Returns the content of this frame converted to plain text.
261
262     \sa toHtml()
263 */
264 QString QWebFrame::toPlainText() const
265 {
266     if (d->frame->view() && d->frame->view()->layoutPending())
267         d->frame->view()->layout();
268
269     Element *documentElement = d->frame->document()->documentElement();
270     return documentElement->innerText();
271 }
272
273 /*!
274     Returns a dump of the rendering tree. This is mainly useful for debugging
275     html.
276 */
277 QString QWebFrame::renderTreeDump() const
278 {
279     if (d->frame->view() && d->frame->view()->layoutPending())
280         d->frame->view()->layout();
281
282     return externalRepresentation(d->frame->contentRenderer());
283 }
284
285 /*!
286     \property QWebFrame::title
287     \brief the title of the frame as defined by the HTML &lt;title&gt; element
288
289     \sa titleChanged()
290 */
291
292 QString QWebFrame::title() const
293 {
294     if (d->frame->document())
295         return d->frame->loader()->documentLoader()->title();
296     else return QString();
297 }
298
299 /*!
300     \since 4.5
301     \brief Returns the meta data in this frame as a QMultiMap
302
303     The meta data consists of the name and content attributes of the
304     of the \c{<meta>} tags in the HTML document.
305
306     For example:
307
308     \code
309     <html>
310         <head>
311             <meta name="description" content="This document is a tutorial about Qt development">
312             <meta name="keywords" content="Qt, WebKit, Programming">
313         </head>
314         ...
315     </html>
316     \endcode
317
318     Given the above HTML code the metaData() function will return a map with two entries:
319     \table
320     \header \o Key
321             \o Value
322     \row    \o "description"
323             \o "This document is a tutorial about Qt development"
324     \row    \o "keywords"
325             \o "Qt, WebKit, Programming"
326     \endtable
327
328     This function returns a multi map to support multiple meta tags with the same attribute name.
329 */
330 QMultiMap<QString, QString> QWebFrame::metaData() const
331 {
332     if(!d->frame->document())
333        return QMap<QString,QString>();
334
335     QMultiMap<QString,QString> map;
336     Document* doc = d->frame->document();
337     RefPtr<NodeList> list = doc->getElementsByTagName("meta");
338     unsigned len = list->length();
339     for (unsigned i = 0; i < len; i++) {
340         HTMLMetaElement* meta = static_cast<HTMLMetaElement*>(list->item(i));
341         map.insert(meta->name(), meta->content());
342     }
343     return map;
344 }
345
346 static inline QUrl ensureAbsoluteUrl(const QUrl &url)
347 {
348     if (!url.isRelative())
349         return url;
350
351     return QUrl::fromLocalFile(QFileInfo(url.toLocalFile()).absoluteFilePath());
352 }
353
354 /*!
355     \property QWebFrame::url
356     \brief the url of the frame currently viewed
357
358     \sa urlChanged()
359 */
360
361 void QWebFrame::setUrl(const QUrl &url)
362 {
363     d->frame->loader()->begin(ensureAbsoluteUrl(url));
364     d->frame->loader()->end();
365     load(ensureAbsoluteUrl(url));
366 }
367
368 QUrl QWebFrame::url() const
369 {
370     return d->frame->loader()->url();
371 }
372
373 /*!
374     \property QWebFrame::icon
375     \brief the icon associated with this frame
376
377     \sa iconChanged(), QWebSettings::iconForUrl()
378 */
379
380 QIcon QWebFrame::icon() const
381 {
382     return QWebSettings::iconForUrl(d->frame->loader()->url());
383 }
384
385 /*!
386   The name of this frame as defined by the parent frame.
387 */
388 QString QWebFrame::frameName() const
389 {
390     return d->frame->tree()->name();
391 }
392
393 /*!
394   The web page that contains this frame.
395 */
396 QWebPage *QWebFrame::page() const
397 {
398     return d->page;
399 }
400
401 /*!
402   Loads \a url into this frame.
403
404   \note The view remains the same until enough data has arrived to display the new \a url.
405
406   \sa setUrl(), setHtml(), setContent()
407 */
408 void QWebFrame::load(const QUrl &url)
409 {
410 #if QT_VERSION < 0x040400
411     load(QWebNetworkRequest(ensureAbsoluteUrl(url)));
412 #else
413     load(QNetworkRequest(ensureAbsoluteUrl(url)));
414 #endif
415 }
416
417 #if QT_VERSION < 0x040400
418 /*!
419   Loads a network request, \a req, into this frame.
420
421   \note The view remains the same until enough data has arrived to display the new url.
422 */
423 void QWebFrame::load(const QWebNetworkRequest &req)
424 {
425     if (d->parentFrame())
426         d->page->d->insideOpenCall = true;
427
428     QUrl url = ensureAbsoluteUrl(req.url());
429     QHttpRequestHeader httpHeader = req.httpHeader();
430     QByteArray postData = req.postData();
431
432     WebCore::ResourceRequest request(url);
433
434     QString method = httpHeader.method();
435     if (!method.isEmpty())
436         request.setHTTPMethod(method);
437
438     QList<QPair<QString, QString> > values = httpHeader.values();
439     for (int i = 0; i < values.size(); ++i) {
440         const QPair<QString, QString> &val = values.at(i);
441         request.addHTTPHeaderField(val.first, val.second);
442     }
443
444     if (!postData.isEmpty())
445         request.setHTTPBody(WebCore::FormData::create(postData.constData(), postData.size()));
446
447     d->frame->loader()->load(request);
448
449     if (d->parentFrame())
450         d->page->d->insideOpenCall = false;
451 }
452
453 #else
454
455 /*!
456   Loads a network request, \a req, into this frame, using the method specified in \a
457   operation.
458
459   \a body is optional and is only used for POST operations.
460
461   \note The view remains the same until enough data has arrived to display the new \a url.
462
463   \sa setUrl()
464 */
465 void QWebFrame::load(const QNetworkRequest &req,
466                      QNetworkAccessManager::Operation operation,
467                      const QByteArray &body)
468 {
469     if (d->parentFrame())
470         d->page->d->insideOpenCall = true;
471
472     QUrl url = ensureAbsoluteUrl(req.url());
473
474     WebCore::ResourceRequest request(url);
475
476     switch (operation) {
477         case QNetworkAccessManager::HeadOperation:
478             request.setHTTPMethod("HEAD");
479             break;
480         case QNetworkAccessManager::GetOperation:
481             request.setHTTPMethod("GET");
482             break;
483         case QNetworkAccessManager::PutOperation:
484             request.setHTTPMethod("PUT");
485             break;
486         case QNetworkAccessManager::PostOperation:
487             request.setHTTPMethod("POST");
488             break;
489         case QNetworkAccessManager::UnknownOperation:
490             // eh?
491             break;
492     }
493
494     QList<QByteArray> httpHeaders = req.rawHeaderList();
495     for (int i = 0; i < httpHeaders.size(); ++i) {
496         const QByteArray &headerName = httpHeaders.at(i);
497         request.addHTTPHeaderField(QString::fromLatin1(headerName), QString::fromLatin1(req.rawHeader(headerName)));
498     }
499
500     if (!body.isEmpty())
501         request.setHTTPBody(WebCore::FormData::create(body.constData(), body.size()));
502
503     d->frame->loader()->load(request);
504
505     if (d->parentFrame())
506         d->page->d->insideOpenCall = false;
507 }
508 #endif
509
510 /*!
511   Sets the content of this frame to \a html. \a baseUrl is optional and used to resolve relative
512   URLs in the document, such as referenced images or stylesheets.
513
514   When using this method WebKit assumes that external resources such as JavaScript programs or style
515   sheets are encoded in UTF-8 unless otherwise specified. For example, the encoding of an external
516   script can be specified through the charset attribute of the HTML script tag. It is also possible
517   for the encoding to be specified by web server.
518
519   \sa toHtml()
520 */
521 void QWebFrame::setHtml(const QString &html, const QUrl &baseUrl)
522 {
523     KURL kurl(baseUrl);
524     WebCore::ResourceRequest request(kurl);
525     const QByteArray utf8 = html.toUtf8();
526     WTF::RefPtr<WebCore::SharedBuffer> data = WebCore::SharedBuffer::create(utf8.constData(), utf8.length());
527     WebCore::SubstituteData substituteData(data, WebCore::String("text/html"), WebCore::String("utf-8"), kurl);
528     d->frame->loader()->load(request, substituteData);
529 }
530
531 /*!
532   Sets the content of this frame to the specified content \a data. If the \a mimeType argument
533   is empty it is currently assumed that the content is HTML but in future versions we may introduce
534   auto-detection.
535
536   External objects referenced in the content are located relative to \a baseUrl.
537
538   \sa toHtml()
539 */
540 void QWebFrame::setContent(const QByteArray &data, const QString &mimeType, const QUrl &baseUrl)
541 {
542     KURL kurl(baseUrl);
543     WebCore::ResourceRequest request(kurl);
544     WTF::RefPtr<WebCore::SharedBuffer> buffer = WebCore::SharedBuffer::create(data.constData(), data.length());
545     QString actualMimeType = mimeType;
546     if (actualMimeType.isEmpty())
547         actualMimeType = QLatin1String("text/html");
548     WebCore::SubstituteData substituteData(buffer, WebCore::String(actualMimeType), WebCore::String(), kurl);
549     d->frame->loader()->load(request, substituteData);
550 }
551
552
553 /*!
554   Returns the parent frame of this frame, or 0 if the frame is the web pages
555   main frame.
556
557   This is equivalent to qobject_cast<QWebFrame*>(frame->parent()).
558
559   \sa childFrames()
560 */
561 QWebFrame *QWebFrame::parentFrame() const
562 {
563     return d->parentFrame();
564 }
565
566 /*!
567   Returns a list of all frames that are direct children of this frame.
568
569   \sa parentFrame()
570 */
571 QList<QWebFrame*> QWebFrame::childFrames() const
572 {
573     QList<QWebFrame*> rc;
574     if (d->frame) {
575         FrameTree *tree = d->frame->tree();
576         for (Frame *child = tree->firstChild(); child; child = child->tree()->nextSibling()) {
577             FrameLoader *loader = child->loader();
578             FrameLoaderClientQt *client = static_cast<FrameLoaderClientQt*>(loader->client());
579             if (client)
580                 rc.append(client->webFrame());
581         }
582
583     }
584     return rc;
585 }
586
587 /*!
588     Returns the scrollbar policy for the scrollbar defined by \a orientation.
589 */
590 Qt::ScrollBarPolicy QWebFrame::scrollBarPolicy(Qt::Orientation orientation) const
591 {
592     if (orientation == Qt::Horizontal)
593         return d->horizontalScrollBarPolicy;
594     return d->verticalScrollBarPolicy;
595 }
596
597 /*!
598     Sets the scrollbar policy for the scrollbar defined by \a orientation to \a policy.
599 */
600 void QWebFrame::setScrollBarPolicy(Qt::Orientation orientation, Qt::ScrollBarPolicy policy)
601 {
602     Q_ASSERT((int)ScrollbarAuto == (int)Qt::ScrollBarAsNeeded);
603     Q_ASSERT((int)ScrollbarAlwaysOff == (int)Qt::ScrollBarAlwaysOff);
604     Q_ASSERT((int)ScrollbarAlwaysOn == (int)Qt::ScrollBarAlwaysOn);
605
606     if (orientation == Qt::Horizontal) {
607         d->horizontalScrollBarPolicy = policy;
608         if (d->frame->view()) {
609             d->frame->view()->setHorizontalScrollbarMode((ScrollbarMode)policy);
610             d->frame->view()->updateDefaultScrollbarState();
611         }
612     } else {
613         d->verticalScrollBarPolicy = policy;
614         if (d->frame->view()) {
615             d->frame->view()->setVerticalScrollbarMode((ScrollbarMode)policy);
616             d->frame->view()->updateDefaultScrollbarState();
617         }
618     }
619 }
620
621 /*!
622   Sets the current \a value for the scrollbar with orientation \a orientation.
623
624   The scrollbar forces the \a value to be within the legal range: minimum <= value <= maximum.
625
626   Changing the value also updates the thumb position.
627
628   \sa scrollBarMinimum(), scrollBarMaximum()
629 */
630 void QWebFrame::setScrollBarValue(Qt::Orientation orientation, int value)
631 {
632     Scrollbar *sb;
633     sb = (orientation == Qt::Horizontal) ? d->horizontalScrollBar() : d->verticalScrollBar();
634     if (sb) {
635         if (value < 0)
636             value = 0;
637         else if (value > scrollBarMaximum(orientation))
638             value = scrollBarMaximum(orientation);
639         sb->setValue(value);
640     }
641 }
642
643 /*!
644   Returns the current value for the scrollbar with orientation \a orientation, or 0
645   if no scrollbar is found for \a orientation.
646
647   \sa scrollBarMinimum(), scrollBarMaximum()
648 */
649 int QWebFrame::scrollBarValue(Qt::Orientation orientation) const
650 {
651     Scrollbar *sb;
652     sb = (orientation == Qt::Horizontal) ? d->horizontalScrollBar() : d->verticalScrollBar();
653     if (sb) {
654         return sb->value();
655     }
656     return 0;
657 }
658
659 /*!
660   Returns the maximum value for the scrollbar with orientation \a orientation, or 0
661   if no scrollbar is found for \a orientation.
662
663   \sa scrollBarMinimum()
664 */
665 int QWebFrame::scrollBarMaximum(Qt::Orientation orientation) const
666 {
667     Scrollbar *sb;
668     sb = (orientation == Qt::Horizontal) ? d->horizontalScrollBar() : d->verticalScrollBar();
669     if (sb)
670         return sb->maximum();
671     return 0;
672 }
673
674 /*!
675   Returns the minimum value for the scrollbar with orientation \a orientation.
676
677   The minimum value is always 0.
678
679   \sa scrollBarMaximum()
680 */
681 int QWebFrame::scrollBarMinimum(Qt::Orientation orientation) const
682 {
683     return 0;
684 }
685
686 /*!
687   \since 4.5
688   Scrolls the frame \a dx pixels to the right and \a dy pixels downward. Both
689   \a dx and \a dy may be negative.
690   
691   \sa QWebFrame::scrollPosition
692 */
693
694 void QWebFrame::scroll(int dx, int dy)
695 {
696     if (!d->frame->view())
697         return;
698     
699     d->frame->view()->scrollBy(IntSize(dx, dy));
700 }
701
702 /*!
703   \property QWebFrame::scrollPosition
704   \since 4.5
705   \brief the position the frame is currently scrolled to.
706 */
707
708 QPoint QWebFrame::scrollPosition() const
709 {
710     if (!d->frame->view())
711         return QPoint(0,0);
712
713     IntSize ofs = d->frame->view()->scrollOffset();
714     return QPoint(ofs.width(), ofs.height());
715 }
716
717 void QWebFrame::setScrollPosition(const QPoint &pos)
718 {
719     QPoint current = scrollPosition();
720     int dx = pos.x() - current.x();
721     int dy = pos.y() - current.y();
722     scroll(dx, dy);
723 }
724
725 /*!
726   Render the frame into \a painter clipping to \a clip.
727
728   \sa print()
729 */
730 void QWebFrame::render(QPainter *painter, const QRegion &clip)
731 {
732     if (!d->frame->view() || !d->frame->contentRenderer())
733         return;
734
735     d->frame->view()->layoutIfNeededRecursive();
736
737     GraphicsContext ctx(painter);
738     QVector<QRect> vector = clip.rects();
739     WebCore::FrameView* view = d->frame->view();
740     for (int i = 0; i < vector.size(); ++i) {
741         if (i > 0) {
742             painter->save();
743             painter->setClipRect(vector.at(i), Qt::IntersectClip);
744         }
745
746         view->paint(&ctx, vector.at(i));
747
748         if (i > 0)
749             painter->restore();
750     }
751 }
752
753 /*!
754   Render the frame into \a painter.
755 */
756 void QWebFrame::render(QPainter *painter)
757 {
758     if (!d->frame->view() || !d->frame->contentRenderer())
759         return;
760
761     d->frame->view()->layoutIfNeededRecursive();
762
763     GraphicsContext ctx(painter);
764     WebCore::FrameView* view = d->frame->view();
765     view->paint(&ctx, view->frameRect());
766 }
767
768 /*!
769     \property QWebFrame::textSizeMultiplier
770     \brief the scaling factor for all text in the frame
771     \obsolete
772
773     Use setZoomFactor instead, in combination with the ZoomTextOnly attribute in
774     QWebSettings.
775
776     \note Setting this property also enables the ZoomTextOnly attribute in
777     QWebSettings.
778 */
779
780 /*!
781     Sets the value of the multiplier used to scale the text in a Web frame to
782     the \a factor specified.
783 */
784 void QWebFrame::setTextSizeMultiplier(qreal factor)
785 {
786     d->frame->setZoomFactor(factor, /*isTextOnly*/true);
787 }
788
789 /*!
790     Returns the value of the multiplier used to scale the text in a Web frame.
791 */
792 qreal QWebFrame::textSizeMultiplier() const
793 {
794     return d->frame->zoomFactor();
795 }
796
797 /*!
798     \property QWebFrame::zoomFactor
799     \since 4.5
800     \brief the zoom factor for the frame
801 */
802
803 void QWebFrame::setZoomFactor(qreal factor)
804 {
805     d->frame->setZoomFactor(factor, d->frame->isZoomFactorTextOnly());
806 }
807
808 qreal QWebFrame::zoomFactor() const
809 {
810     return d->frame->zoomFactor();
811 }
812
813 /*!
814     Returns the position of the frame relative to it's parent frame.
815 */
816 QPoint QWebFrame::pos() const
817 {
818     if (!d->frame->view())
819         return QPoint();
820
821     return d->frame->view()->frameRect().topLeft();
822 }
823
824 /*!
825     Return the geometry of the frame relative to it's parent frame.
826 */
827 QRect QWebFrame::geometry() const
828 {
829     if (!d->frame->view())
830         return QRect();
831     return d->frame->view()->frameRect();
832 }
833
834 /*!
835     \property QWebFrame::contentsSize
836     \brief the size of the contents in this frame
837 */
838 QSize QWebFrame::contentsSize() const
839 {
840     FrameView *view = d->frame->view();
841     if (!view)
842         return QSize();
843     return QSize(view->contentsWidth(), view->contentsHeight());
844 }
845
846 /*!
847     Performs a hit test on the frame contents at the given position \a pos and returns the hit test result.
848 */
849 QWebHitTestResult QWebFrame::hitTestContent(const QPoint &pos) const
850 {
851     if (!d->frame->view() || !d->frame->contentRenderer())
852         return QWebHitTestResult();
853
854     HitTestResult result = d->frame->eventHandler()->hitTestResultAtPoint(d->frame->view()->windowToContents(pos), /*allowShadowContent*/ false);
855     return QWebHitTestResult(new QWebHitTestResultPrivate(result));
856 }
857
858 /*! \reimp
859 */
860 bool QWebFrame::event(QEvent *e)
861 {
862     return QObject::event(e);
863 }
864
865 #ifndef QT_NO_PRINTER
866 /*!
867     Prints the frame to the given \a printer.
868
869     \sa render()
870 */
871 void QWebFrame::print(QPrinter *printer) const
872 {
873     const qreal zoomFactorX = printer->logicalDpiX() / qt_defaultDpi();
874     const qreal zoomFactorY = printer->logicalDpiY() / qt_defaultDpi();
875
876     PrintContext printContext(d->frame);
877     float pageHeight = 0;
878
879     QRect qprinterRect = printer->pageRect();
880
881     IntRect pageRect(0, 0,
882                      int(qprinterRect.width() / zoomFactorX),
883                      int(qprinterRect.height() / zoomFactorY));
884
885     printContext.begin(pageRect.width());
886
887     printContext.computePageRects(pageRect, /*headerHeight*/0, /*footerHeight*/0, /*userScaleFactor*/1.0, pageHeight);
888
889     int docCopies;
890     int pageCopies;
891     if (printer->collateCopies() == true){
892         docCopies = 1;
893         pageCopies = printer->numCopies();
894     } else {
895         docCopies = printer->numCopies();
896         pageCopies = 1;
897     }
898
899     int fromPage = printer->fromPage();
900     int toPage = printer->toPage();
901     bool ascending = true;
902
903     if (fromPage == 0 && toPage == 0) {
904         fromPage = 1;
905         toPage = printContext.pageCount();
906     }
907     // paranoia check
908     fromPage = qMax(1, fromPage);
909     toPage = qMin(printContext.pageCount(), toPage);
910
911     if (printer->pageOrder() == QPrinter::LastPageFirst) {
912         int tmp = fromPage;
913         fromPage = toPage;
914         toPage = tmp;
915         ascending = false;
916     }
917
918     QPainter painter(printer);
919     painter.scale(zoomFactorX, zoomFactorY);
920     GraphicsContext ctx(&painter);
921
922     for (int i = 0; i < docCopies; ++i) {
923         int page = fromPage;
924         while (true) {
925             for (int j = 0; j < pageCopies; ++j) {
926                 if (printer->printerState() == QPrinter::Aborted
927                     || printer->printerState() == QPrinter::Error) {
928                     printContext.end();
929                     return;
930                 }
931                 printContext.spoolPage(ctx, page - 1, pageRect.width());
932                 if (j < pageCopies - 1)
933                     printer->newPage();
934             }
935
936             if (page == toPage)
937                 break;
938
939             if (ascending)
940                 ++page;
941             else
942                 --page;
943
944             printer->newPage();
945         }
946
947         if ( i < docCopies - 1)
948             printer->newPage();
949     }
950
951     printContext.end();
952 }
953 #endif // QT_NO_PRINTER
954
955 /*!
956     Evaluate JavaScript defined by \a scriptSource using this frame as context.
957
958     \sa addToJavaScriptWindowObject(), javaScriptWindowObjectCleared()
959 */
960 QVariant QWebFrame::evaluateJavaScript(const QString& scriptSource)
961 {
962     ScriptController *proxy = d->frame->script();
963     QVariant rc;
964     if (proxy) {
965         JSC::JSValue* v = proxy->evaluate(ScriptSourceCode(scriptSource)).jsValue();
966         if (v) {
967             int distance = 0;
968             rc = JSC::Bindings::convertValueToQVariant(proxy->globalObject()->globalExec(), v, QMetaType::Void, &distance);
969         }
970     }
971     return rc;
972 }
973
974 /*!
975     \since 4.5
976
977     Returns the frame's security origin.
978 */
979 QWebSecurityOrigin QWebFrame::securityOrigin() const
980 {
981     QWebFrame* that = const_cast<QWebFrame*>(this);
982     QWebSecurityOriginPrivate* priv = new QWebSecurityOriginPrivate(QWebFramePrivate::core(that)->document()->securityOrigin());
983     return QWebSecurityOrigin(priv);
984 }
985
986 WebCore::Frame* QWebFramePrivate::core(QWebFrame* webFrame)
987 {
988     return webFrame->d->frame;
989 }
990
991 QWebFrame* QWebFramePrivate::kit(WebCore::Frame* coreFrame)
992 {
993     return static_cast<FrameLoaderClientQt*>(coreFrame->loader()->client())->webFrame();
994 }
995
996
997 /*!
998     \fn void QWebFrame::javaScriptWindowObjectCleared()
999
1000     This signal is emitted whenever the global window object of the JavaScript
1001     environment is cleared, e.g., before starting a new load.
1002
1003     If you intend to add QObjects to a QWebFrame using
1004     addToJavaScriptWindowObject(), you should add them in a slot connected
1005     to this signal. This ensures that your objects remain accessible when
1006     loading new URLs.
1007 */
1008
1009 /*!
1010     \fn void QWebFrame::provisionalLoad()
1011     \internal
1012 */
1013
1014 /*!
1015     \fn void QWebFrame::titleChanged(const QString &title)
1016
1017     This signal is emitted whenever the title of the frame changes.
1018     The \a title string specifies the new title.
1019
1020     \sa title()
1021 */
1022
1023 /*!
1024     \fn void QWebFrame::urlChanged(const QUrl &url)
1025
1026     This signal is emitted with the URL of the frame when the frame's title is
1027     received. The new URL is specified by \a url.
1028
1029     \sa url()
1030 */
1031
1032 /*!
1033     \fn void QWebFrame::initialLayoutCompleted()
1034
1035     This signal is emitted when the frame is laid out the first time.
1036     This is the first time you will see contents displayed on the frame.
1037
1038     \note A frame can be laid out multiple times.
1039 */
1040
1041 /*!
1042   \fn void QWebFrame::iconChanged()
1043
1044   This signal is emitted when the icon ("favicon") associated with the frame
1045   has been loaded.
1046
1047   \sa icon()
1048 */
1049
1050 /*!
1051     \class QWebHitTestResult
1052     \since 4.4
1053     \brief The QWebHitTestResult class provides information about the web
1054     page content after a hit test.
1055
1056     QWebHitTestResult is returned by QWebFrame::hitTestContent() to provide
1057     information about the content of the web page at the specified position.
1058 */
1059
1060 /*!
1061     \internal
1062 */
1063 QWebHitTestResult::QWebHitTestResult(QWebHitTestResultPrivate *priv)
1064     : d(priv)
1065 {
1066 }
1067
1068 QWebHitTestResultPrivate::QWebHitTestResultPrivate(const WebCore::HitTestResult &hitTest)
1069     : isContentEditable(false)
1070     , isContentSelected(false)
1071 {
1072     if (!hitTest.innerNode())
1073         return;
1074     pos = hitTest.point();
1075     boundingRect = hitTest.boundingBox();
1076     title = hitTest.title();
1077     linkText = hitTest.textContent();
1078     linkUrl = hitTest.absoluteLinkURL();
1079     linkTitle = hitTest.titleDisplayString();
1080     alternateText = hitTest.altDisplayString();
1081     imageUrl = hitTest.absoluteImageURL();
1082     innerNode = hitTest.innerNode();
1083     innerNonSharedNode = hitTest.innerNonSharedNode();
1084     WebCore::Image *img = hitTest.image();
1085     if (img) {
1086         QPixmap *pix = img->nativeImageForCurrentFrame();
1087         if (pix)
1088             pixmap = *pix;
1089     }
1090     WebCore::Frame *wframe = hitTest.targetFrame();
1091     if (wframe)
1092         linkTargetFrame = QWebFramePrivate::kit(wframe);
1093
1094     isContentEditable = hitTest.isContentEditable();
1095     isContentSelected = hitTest.isSelected();
1096
1097     if (innerNonSharedNode && innerNonSharedNode->document()
1098         && innerNonSharedNode->document()->frame())
1099         frame = QWebFramePrivate::kit(innerNonSharedNode->document()->frame());
1100
1101     if (Node *block = WebCore::enclosingBlock(innerNode.get())) {
1102         RenderObject *renderBlock = block->renderer();
1103         while (renderBlock && renderBlock->isListItem())
1104             renderBlock = renderBlock->containingBlock();
1105
1106         if (renderBlock)
1107             enclosingBlock = renderBlock->absoluteClippedOverflowRect();
1108     }
1109 }
1110
1111 /*!
1112     Constructs a null hit test result.
1113 */
1114 QWebHitTestResult::QWebHitTestResult()
1115     : d(0)
1116 {
1117 }
1118
1119 /*!
1120     Constructs a hit test result from \a other.
1121 */
1122 QWebHitTestResult::QWebHitTestResult(const QWebHitTestResult &other)
1123     : d(0)
1124 {
1125     if (other.d)
1126         d = new QWebHitTestResultPrivate(*other.d);
1127 }
1128
1129 /*!
1130     Assigns the \a other hit test result to this.
1131 */
1132 QWebHitTestResult &QWebHitTestResult::operator=(const QWebHitTestResult &other)
1133 {
1134     if (this != &other) {
1135         if (other.d) {
1136             if (!d)
1137                 d = new QWebHitTestResultPrivate;
1138             *d = *other.d;
1139         } else {
1140             delete d;
1141             d = 0;
1142         }
1143     }
1144     return *this;
1145 }
1146
1147 /*!
1148     Destructor.
1149 */
1150 QWebHitTestResult::~QWebHitTestResult()
1151 {
1152     delete d;
1153 }
1154
1155 /*!
1156     Returns true if the hit test result is null; otherwise returns false.
1157 */
1158 bool QWebHitTestResult::isNull() const
1159 {
1160     return !d;
1161 }
1162
1163 /*!
1164     Returns the position where the hit test occured.
1165 */
1166 QPoint QWebHitTestResult::pos() const
1167 {
1168     if (!d)
1169         return QPoint();
1170     return d->pos;
1171 }
1172
1173 /*!
1174     \since 4.5
1175     Returns the bounding rect of the element.
1176 */
1177 QRect QWebHitTestResult::boundingRect() const
1178 {
1179     if (!d)
1180         return QRect();
1181     return d->boundingRect;
1182 }
1183
1184 /*!
1185     \since 4.5
1186     Returns the rect of the smallest enclosing block element.
1187 */
1188 QRect QWebHitTestResult::enclosingBlock() const
1189 {
1190     if (!d)
1191         return QRect();
1192     return d->enclosingBlock;
1193 }
1194
1195 /*!
1196     Returns the title of the nearest enclosing HTML element.
1197 */
1198 QString QWebHitTestResult::title() const
1199 {
1200     if (!d)
1201         return QString();
1202     return d->title;
1203 }
1204
1205 /*!
1206     Returns the text of the link.
1207 */
1208 QString QWebHitTestResult::linkText() const
1209 {
1210     if (!d)
1211         return QString();
1212     return d->linkText;
1213 }
1214
1215 /*!
1216     Returns the url to which the link points to.
1217 */
1218 QUrl QWebHitTestResult::linkUrl() const
1219 {
1220     if (!d)
1221         return QUrl();
1222     return d->linkUrl;
1223 }
1224
1225 /*!
1226     Returns the title of the link.
1227 */
1228 QUrl QWebHitTestResult::linkTitle() const
1229 {
1230     if (!d)
1231         return QUrl();
1232     return d->linkTitle;
1233 }
1234
1235 /*!
1236     Returns the frame that will load the link if it is activated.
1237 */
1238 QWebFrame *QWebHitTestResult::linkTargetFrame() const
1239 {
1240     if (!d)
1241         return 0;
1242     return d->linkTargetFrame;
1243 }
1244
1245 /*!
1246     Returns the alternate text of the element. This corresponds to the HTML alt attribute.
1247 */
1248 QString QWebHitTestResult::alternateText() const
1249 {
1250     if (!d)
1251         return QString();
1252     return d->alternateText;
1253 }
1254
1255 /*!
1256     Returns the url of the image.
1257 */
1258 QUrl QWebHitTestResult::imageUrl() const
1259 {
1260     if (!d)
1261         return QUrl();
1262     return d->imageUrl;
1263 }
1264
1265 /*!
1266     Returns a QPixmap containing the image. A null pixmap is returned if the
1267     element being tested is not an image.
1268 */
1269 QPixmap QWebHitTestResult::pixmap() const
1270 {
1271     if (!d)
1272         return QPixmap();
1273     return d->pixmap;
1274 }
1275
1276 /*!
1277     Returns true if the content is editable by the user; otherwise returns false.
1278 */
1279 bool QWebHitTestResult::isContentEditable() const
1280 {
1281     if (!d)
1282         return false;
1283     return d->isContentEditable;
1284 }
1285
1286 /*!
1287     Returns true if the content tested is part of the selection; otherwise returns false.
1288 */
1289 bool QWebHitTestResult::isContentSelected() const
1290 {
1291     if (!d)
1292         return false;
1293     return d->isContentSelected;
1294 }
1295
1296 /*!
1297     Returns the frame the hit test was executed in.
1298 */
1299 QWebFrame *QWebHitTestResult::frame() const
1300 {
1301     if (!d)
1302         return 0;
1303     return d->frame;
1304 }
1305