c2a85e5a6d3999113dff1d746cde2b059ef78d8b
[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     } else {
611         d->verticalScrollBarPolicy = policy;
612         if (d->frame->view())
613             d->frame->view()->setVerticalScrollbarMode((ScrollbarMode)policy);
614     }
615 }
616
617 /*!
618   Sets the current \a value for the scrollbar with orientation \a orientation.
619
620   The scrollbar forces the \a value to be within the legal range: minimum <= value <= maximum.
621
622   Changing the value also updates the thumb position.
623
624   \sa scrollBarMinimum(), scrollBarMaximum()
625 */
626 void QWebFrame::setScrollBarValue(Qt::Orientation orientation, int value)
627 {
628     Scrollbar *sb;
629     sb = (orientation == Qt::Horizontal) ? d->horizontalScrollBar() : d->verticalScrollBar();
630     if (sb) {
631         if (value < 0)
632             value = 0;
633         else if (value > scrollBarMaximum(orientation))
634             value = scrollBarMaximum(orientation);
635         sb->setValue(value);
636     }
637 }
638
639 /*!
640   Returns the current value for the scrollbar with orientation \a orientation, or 0
641   if no scrollbar is found for \a orientation.
642
643   \sa scrollBarMinimum(), scrollBarMaximum()
644 */
645 int QWebFrame::scrollBarValue(Qt::Orientation orientation) const
646 {
647     Scrollbar *sb;
648     sb = (orientation == Qt::Horizontal) ? d->horizontalScrollBar() : d->verticalScrollBar();
649     if (sb) {
650         return sb->value();
651     }
652     return 0;
653 }
654
655 /*!
656   Returns the maximum value for the scrollbar with orientation \a orientation, or 0
657   if no scrollbar is found for \a orientation.
658
659   \sa scrollBarMinimum()
660 */
661 int QWebFrame::scrollBarMaximum(Qt::Orientation orientation) const
662 {
663     Scrollbar *sb;
664     sb = (orientation == Qt::Horizontal) ? d->horizontalScrollBar() : d->verticalScrollBar();
665     if (sb)
666         return sb->maximum();
667     return 0;
668 }
669
670 /*!
671   Returns the minimum value for the scrollbar with orientation \a orientation.
672
673   The minimum value is always 0.
674
675   \sa scrollBarMaximum()
676 */
677 int QWebFrame::scrollBarMinimum(Qt::Orientation orientation) const
678 {
679     return 0;
680 }
681
682 /*!
683   \since 4.5
684   Scrolls the frame \a dx pixels to the right and \a dy pixels downward. Both
685   \a dx and \a dy may be negative.
686   
687   \sa QWebFrame::scrollPosition
688 */
689
690 void QWebFrame::scroll(int dx, int dy)
691 {
692     if (!d->frame->view())
693         return;
694     
695     d->frame->view()->scrollBy(IntSize(dx, dy));
696 }
697
698 /*!
699   \property QWebFrame::scrollPosition
700   \since 4.5
701   \brief the position the frame is currently scrolled to.
702 */
703
704 QPoint QWebFrame::scrollPosition() const
705 {
706     if (!d->frame->view())
707         return QPoint(0,0);
708
709     IntSize ofs = d->frame->view()->scrollOffset();
710     return QPoint(ofs.width(), ofs.height());
711 }
712
713 void QWebFrame::setScrollPosition(const QPoint &pos)
714 {
715     QPoint current = scrollPosition();
716     int dx = pos.x() - current.x();
717     int dy = pos.y() - current.y();
718     scroll(dx, dy);
719 }
720
721 /*!
722   Render the frame into \a painter clipping to \a clip.
723
724   \sa print()
725 */
726 void QWebFrame::render(QPainter *painter, const QRegion &clip)
727 {
728     if (!d->frame->view() || !d->frame->contentRenderer())
729         return;
730
731     d->frame->view()->layoutIfNeededRecursive();
732
733     GraphicsContext ctx(painter);
734     QVector<QRect> vector = clip.rects();
735     WebCore::FrameView* view = d->frame->view();
736     for (int i = 0; i < vector.size(); ++i) {
737         if (i > 0) {
738             painter->save();
739             painter->setClipRect(vector.at(i), Qt::IntersectClip);
740         }
741
742         view->paint(&ctx, vector.at(i));
743
744         if (i > 0)
745             painter->restore();
746     }
747 }
748
749 /*!
750   Render the frame into \a painter.
751 */
752 void QWebFrame::render(QPainter *painter)
753 {
754     if (!d->frame->view() || !d->frame->contentRenderer())
755         return;
756
757     d->frame->view()->layoutIfNeededRecursive();
758
759     GraphicsContext ctx(painter);
760     WebCore::FrameView* view = d->frame->view();
761     view->paint(&ctx, view->frameRect());
762 }
763
764 /*!
765     \property QWebFrame::textSizeMultiplier
766     \brief the scaling factor for all text in the frame
767     \obsolete
768
769     Use setZoomFactor instead, in combination with the ZoomTextOnly attribute in
770     QWebSettings.
771
772     \note Setting this property also enables the ZoomTextOnly attribute in
773     QWebSettings.
774 */
775
776 /*!
777     Sets the value of the multiplier used to scale the text in a Web frame to
778     the \a factor specified.
779 */
780 void QWebFrame::setTextSizeMultiplier(qreal factor)
781 {
782     d->frame->setZoomFactor(factor, /*isTextOnly*/true);
783 }
784
785 /*!
786     Returns the value of the multiplier used to scale the text in a Web frame.
787 */
788 qreal QWebFrame::textSizeMultiplier() const
789 {
790     return d->frame->zoomFactor();
791 }
792
793 /*!
794     \property QWebFrame::zoomFactor
795     \since 4.5
796     \brief the zoom factor for the frame
797 */
798
799 void QWebFrame::setZoomFactor(qreal factor)
800 {
801     d->frame->setZoomFactor(factor, d->frame->isZoomFactorTextOnly());
802 }
803
804 qreal QWebFrame::zoomFactor() const
805 {
806     return d->frame->zoomFactor();
807 }
808
809 /*!
810     Returns the position of the frame relative to it's parent frame.
811 */
812 QPoint QWebFrame::pos() const
813 {
814     if (!d->frame->view())
815         return QPoint();
816
817     return d->frame->view()->frameRect().topLeft();
818 }
819
820 /*!
821     Return the geometry of the frame relative to it's parent frame.
822 */
823 QRect QWebFrame::geometry() const
824 {
825     if (!d->frame->view())
826         return QRect();
827     return d->frame->view()->frameRect();
828 }
829
830 /*!
831     \property QWebFrame::contentsSize
832     \brief the size of the contents in this frame
833 */
834 QSize QWebFrame::contentsSize() const
835 {
836     FrameView *view = d->frame->view();
837     if (!view)
838         return QSize();
839     return QSize(view->contentsWidth(), view->contentsHeight());
840 }
841
842 /*!
843     Performs a hit test on the frame contents at the given position \a pos and returns the hit test result.
844 */
845 QWebHitTestResult QWebFrame::hitTestContent(const QPoint &pos) const
846 {
847     if (!d->frame->view() || !d->frame->contentRenderer())
848         return QWebHitTestResult();
849
850     HitTestResult result = d->frame->eventHandler()->hitTestResultAtPoint(d->frame->view()->windowToContents(pos), /*allowShadowContent*/ false);
851     return QWebHitTestResult(new QWebHitTestResultPrivate(result));
852 }
853
854 /*! \reimp
855 */
856 bool QWebFrame::event(QEvent *e)
857 {
858     return QObject::event(e);
859 }
860
861 #ifndef QT_NO_PRINTER
862 /*!
863     Prints the frame to the given \a printer.
864
865     \sa render()
866 */
867 void QWebFrame::print(QPrinter *printer) const
868 {
869     const qreal zoomFactorX = printer->logicalDpiX() / qt_defaultDpi();
870     const qreal zoomFactorY = printer->logicalDpiY() / qt_defaultDpi();
871
872     PrintContext printContext(d->frame);
873     float pageHeight = 0;
874
875     QRect qprinterRect = printer->pageRect();
876
877     IntRect pageRect(0, 0,
878                      int(qprinterRect.width() / zoomFactorX),
879                      int(qprinterRect.height() / zoomFactorY));
880
881     printContext.begin(pageRect.width());
882
883     printContext.computePageRects(pageRect, /*headerHeight*/0, /*footerHeight*/0, /*userScaleFactor*/1.0, pageHeight);
884
885     int docCopies;
886     int pageCopies;
887     if (printer->collateCopies() == true){
888         docCopies = 1;
889         pageCopies = printer->numCopies();
890     } else {
891         docCopies = printer->numCopies();
892         pageCopies = 1;
893     }
894
895     int fromPage = printer->fromPage();
896     int toPage = printer->toPage();
897     bool ascending = true;
898
899     if (fromPage == 0 && toPage == 0) {
900         fromPage = 1;
901         toPage = printContext.pageCount();
902     }
903     // paranoia check
904     fromPage = qMax(1, fromPage);
905     toPage = qMin(printContext.pageCount(), toPage);
906
907     if (printer->pageOrder() == QPrinter::LastPageFirst) {
908         int tmp = fromPage;
909         fromPage = toPage;
910         toPage = tmp;
911         ascending = false;
912     }
913
914     QPainter painter(printer);
915     painter.scale(zoomFactorX, zoomFactorY);
916     GraphicsContext ctx(&painter);
917
918     for (int i = 0; i < docCopies; ++i) {
919         int page = fromPage;
920         while (true) {
921             for (int j = 0; j < pageCopies; ++j) {
922                 if (printer->printerState() == QPrinter::Aborted
923                     || printer->printerState() == QPrinter::Error) {
924                     printContext.end();
925                     return;
926                 }
927                 printContext.spoolPage(ctx, page - 1, pageRect.width());
928                 if (j < pageCopies - 1)
929                     printer->newPage();
930             }
931
932             if (page == toPage)
933                 break;
934
935             if (ascending)
936                 ++page;
937             else
938                 --page;
939
940             printer->newPage();
941         }
942
943         if ( i < docCopies - 1)
944             printer->newPage();
945     }
946
947     printContext.end();
948 }
949 #endif // QT_NO_PRINTER
950
951 /*!
952     Evaluate JavaScript defined by \a scriptSource using this frame as context.
953
954     \sa addToJavaScriptWindowObject(), javaScriptWindowObjectCleared()
955 */
956 QVariant QWebFrame::evaluateJavaScript(const QString& scriptSource)
957 {
958     ScriptController *proxy = d->frame->script();
959     QVariant rc;
960     if (proxy) {
961         JSC::JSValue* v = proxy->evaluate(ScriptSourceCode(scriptSource)).jsValue();
962         if (v) {
963             int distance = 0;
964             rc = JSC::Bindings::convertValueToQVariant(proxy->globalObject()->globalExec(), v, QMetaType::Void, &distance);
965         }
966     }
967     return rc;
968 }
969
970 /*!
971     \since 4.5
972
973     Returns the frame's security origin.
974 */
975 QWebSecurityOrigin QWebFrame::securityOrigin() const
976 {
977     QWebFrame* that = const_cast<QWebFrame*>(this);
978     QWebSecurityOriginPrivate* priv = new QWebSecurityOriginPrivate(QWebFramePrivate::core(that)->document()->securityOrigin());
979     return QWebSecurityOrigin(priv);
980 }
981
982 WebCore::Frame* QWebFramePrivate::core(QWebFrame* webFrame)
983 {
984     return webFrame->d->frame;
985 }
986
987 QWebFrame* QWebFramePrivate::kit(WebCore::Frame* coreFrame)
988 {
989     return static_cast<FrameLoaderClientQt*>(coreFrame->loader()->client())->webFrame();
990 }
991
992
993 /*!
994     \fn void QWebFrame::javaScriptWindowObjectCleared()
995
996     This signal is emitted whenever the global window object of the JavaScript
997     environment is cleared, e.g., before starting a new load.
998
999     If you intend to add QObjects to a QWebFrame using
1000     addToJavaScriptWindowObject(), you should add them in a slot connected
1001     to this signal. This ensures that your objects remain accessible when
1002     loading new URLs.
1003 */
1004
1005 /*!
1006     \fn void QWebFrame::provisionalLoad()
1007     \internal
1008 */
1009
1010 /*!
1011     \fn void QWebFrame::titleChanged(const QString &title)
1012
1013     This signal is emitted whenever the title of the frame changes.
1014     The \a title string specifies the new title.
1015
1016     \sa title()
1017 */
1018
1019 /*!
1020     \fn void QWebFrame::urlChanged(const QUrl &url)
1021
1022     This signal is emitted with the URL of the frame when the frame's title is
1023     received. The new URL is specified by \a url.
1024
1025     \sa url()
1026 */
1027
1028 /*!
1029     \fn void QWebFrame::initialLayoutCompleted()
1030
1031     This signal is emitted when the frame is laid out the first time.
1032     This is the first time you will see contents displayed on the frame.
1033
1034     \note A frame can be laid out multiple times.
1035 */
1036
1037 /*!
1038   \fn void QWebFrame::iconChanged()
1039
1040   This signal is emitted when the icon ("favicon") associated with the frame
1041   has been loaded.
1042
1043   \sa icon()
1044 */
1045
1046 /*!
1047     \class QWebHitTestResult
1048     \since 4.4
1049     \brief The QWebHitTestResult class provides information about the web
1050     page content after a hit test.
1051
1052     QWebHitTestResult is returned by QWebFrame::hitTestContent() to provide
1053     information about the content of the web page at the specified position.
1054 */
1055
1056 /*!
1057     \internal
1058 */
1059 QWebHitTestResult::QWebHitTestResult(QWebHitTestResultPrivate *priv)
1060     : d(priv)
1061 {
1062 }
1063
1064 QWebHitTestResultPrivate::QWebHitTestResultPrivate(const WebCore::HitTestResult &hitTest)
1065     : isContentEditable(false)
1066     , isContentSelected(false)
1067 {
1068     if (!hitTest.innerNode())
1069         return;
1070     pos = hitTest.point();
1071     boundingRect = hitTest.boundingBox();
1072     title = hitTest.title();
1073     linkText = hitTest.textContent();
1074     linkUrl = hitTest.absoluteLinkURL();
1075     linkTitle = hitTest.titleDisplayString();
1076     alternateText = hitTest.altDisplayString();
1077     imageUrl = hitTest.absoluteImageURL();
1078     innerNode = hitTest.innerNode();
1079     innerNonSharedNode = hitTest.innerNonSharedNode();
1080     WebCore::Image *img = hitTest.image();
1081     if (img) {
1082         QPixmap *pix = img->nativeImageForCurrentFrame();
1083         if (pix)
1084             pixmap = *pix;
1085     }
1086     WebCore::Frame *wframe = hitTest.targetFrame();
1087     if (wframe)
1088         linkTargetFrame = QWebFramePrivate::kit(wframe);
1089
1090     isContentEditable = hitTest.isContentEditable();
1091     isContentSelected = hitTest.isSelected();
1092
1093     if (innerNonSharedNode && innerNonSharedNode->document()
1094         && innerNonSharedNode->document()->frame())
1095         frame = QWebFramePrivate::kit(innerNonSharedNode->document()->frame());
1096
1097     if (Node *block = WebCore::enclosingBlock(innerNode.get())) {
1098         RenderObject *renderBlock = block->renderer();
1099         while (renderBlock && renderBlock->isListItem())
1100             renderBlock = renderBlock->containingBlock();
1101
1102         if (renderBlock)
1103             enclosingBlock = renderBlock->absoluteClippedOverflowRect();
1104     }
1105 }
1106
1107 /*!
1108     Constructs a null hit test result.
1109 */
1110 QWebHitTestResult::QWebHitTestResult()
1111     : d(0)
1112 {
1113 }
1114
1115 /*!
1116     Constructs a hit test result from \a other.
1117 */
1118 QWebHitTestResult::QWebHitTestResult(const QWebHitTestResult &other)
1119     : d(0)
1120 {
1121     if (other.d)
1122         d = new QWebHitTestResultPrivate(*other.d);
1123 }
1124
1125 /*!
1126     Assigns the \a other hit test result to this.
1127 */
1128 QWebHitTestResult &QWebHitTestResult::operator=(const QWebHitTestResult &other)
1129 {
1130     if (this != &other) {
1131         if (other.d) {
1132             if (!d)
1133                 d = new QWebHitTestResultPrivate;
1134             *d = *other.d;
1135         } else {
1136             delete d;
1137             d = 0;
1138         }
1139     }
1140     return *this;
1141 }
1142
1143 /*!
1144     Destructor.
1145 */
1146 QWebHitTestResult::~QWebHitTestResult()
1147 {
1148     delete d;
1149 }
1150
1151 /*!
1152     Returns true if the hit test result is null; otherwise returns false.
1153 */
1154 bool QWebHitTestResult::isNull() const
1155 {
1156     return !d;
1157 }
1158
1159 /*!
1160     Returns the position where the hit test occured.
1161 */
1162 QPoint QWebHitTestResult::pos() const
1163 {
1164     if (!d)
1165         return QPoint();
1166     return d->pos;
1167 }
1168
1169 /*!
1170     \since 4.5
1171     Returns the bounding rect of the element.
1172 */
1173 QRect QWebHitTestResult::boundingRect() const
1174 {
1175     if (!d)
1176         return QRect();
1177     return d->boundingRect;
1178 }
1179
1180 /*!
1181     \since 4.5
1182     Returns the rect of the smallest enclosing block element.
1183 */
1184 QRect QWebHitTestResult::enclosingBlock() const
1185 {
1186     if (!d)
1187         return QRect();
1188     return d->enclosingBlock;
1189 }
1190
1191 /*!
1192     Returns the title of the nearest enclosing HTML element.
1193 */
1194 QString QWebHitTestResult::title() const
1195 {
1196     if (!d)
1197         return QString();
1198     return d->title;
1199 }
1200
1201 /*!
1202     Returns the text of the link.
1203 */
1204 QString QWebHitTestResult::linkText() const
1205 {
1206     if (!d)
1207         return QString();
1208     return d->linkText;
1209 }
1210
1211 /*!
1212     Returns the url to which the link points to.
1213 */
1214 QUrl QWebHitTestResult::linkUrl() const
1215 {
1216     if (!d)
1217         return QUrl();
1218     return d->linkUrl;
1219 }
1220
1221 /*!
1222     Returns the title of the link.
1223 */
1224 QUrl QWebHitTestResult::linkTitle() const
1225 {
1226     if (!d)
1227         return QUrl();
1228     return d->linkTitle;
1229 }
1230
1231 /*!
1232     Returns the frame that will load the link if it is activated.
1233 */
1234 QWebFrame *QWebHitTestResult::linkTargetFrame() const
1235 {
1236     if (!d)
1237         return 0;
1238     return d->linkTargetFrame;
1239 }
1240
1241 /*!
1242     Returns the alternate text of the element. This corresponds to the HTML alt attribute.
1243 */
1244 QString QWebHitTestResult::alternateText() const
1245 {
1246     if (!d)
1247         return QString();
1248     return d->alternateText;
1249 }
1250
1251 /*!
1252     Returns the url of the image.
1253 */
1254 QUrl QWebHitTestResult::imageUrl() const
1255 {
1256     if (!d)
1257         return QUrl();
1258     return d->imageUrl;
1259 }
1260
1261 /*!
1262     Returns a QPixmap containing the image. A null pixmap is returned if the
1263     element being tested is not an image.
1264 */
1265 QPixmap QWebHitTestResult::pixmap() const
1266 {
1267     if (!d)
1268         return QPixmap();
1269     return d->pixmap;
1270 }
1271
1272 /*!
1273     Returns true if the content is editable by the user; otherwise returns false.
1274 */
1275 bool QWebHitTestResult::isContentEditable() const
1276 {
1277     if (!d)
1278         return false;
1279     return d->isContentEditable;
1280 }
1281
1282 /*!
1283     Returns true if the content tested is part of the selection; otherwise returns false.
1284 */
1285 bool QWebHitTestResult::isContentSelected() const
1286 {
1287     if (!d)
1288         return false;
1289     return d->isContentSelected;
1290 }
1291
1292 /*!
1293     Returns the frame the hit test was executed in.
1294 */
1295 QWebFrame *QWebHitTestResult::frame() const
1296 {
1297     if (!d)
1298         return 0;
1299     return d->frame;
1300 }
1301