Holger Hans Peter Freyther <holger.freyther@trolltech.com>
[WebKit-https.git] / WebKit / qt / Api / qwebframe.cpp
1 /*
2     Copyright (C) 2007 Trolltech ASA
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     This class provides all functionality needed for loading images, style sheets and html
21     pages from the web. It has a memory cache for these objects.
22 */
23 #include "config.h"
24 #include "qwebframe.h"
25 #include "qwebpage.h"
26 #include "qwebpage_p.h"
27 #include "qwebframe_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 "Page.h"
37 #include "ResourceRequest.h"
38 #include "SelectionController.h"
39 #include "PlatformScrollBar.h"
40 #include "SubstituteData.h"
41
42 #include "markup.h"
43 #include "RenderTreeAsText.h"
44 #include "Element.h"
45 #include "Document.h"
46 #include "DragData.h"
47 #include "RenderObject.h"
48 #include "GraphicsContext.h"
49 #include "PlatformScrollBar.h"
50 #include "PlatformMouseEvent.h"
51 #include "PlatformWheelEvent.h"
52 #include "GraphicsContext.h"
53 #include "HitTestResult.h"
54
55 #include "bindings/runtime.h"
56 #include "bindings/runtime_root.h"
57 #include "kjs_proxy.h"
58 #include "kjs_window.h"
59 #include "kjs_binding.h"
60 #include "ExecState.h"
61 #include "object.h"
62
63 #include "wtf/HashMap.h"
64
65 #include <qdebug.h>
66 #include <qevent.h>
67 #include <qpainter.h>
68 #if QT_VERSION >= 0x040400
69 #include <qnetworkrequest.h>
70 #else
71 #include "qwebnetworkinterface.h"
72 #endif
73 #include <qregion.h>
74
75 using namespace WebCore;
76
77 void QWebFramePrivate::init(QWebFrame *qframe, WebCore::Page *webcorePage, QWebFrameData *frameData)
78 {
79     q = qframe;
80
81     frameLoaderClient = new FrameLoaderClientQt();
82     frame = new Frame(webcorePage, frameData->ownerElement, frameLoaderClient);
83     frameLoaderClient->setFrame(qframe, frame.get());
84
85     frameView = new FrameView(frame.get());
86     frameView->deref();
87     frameView->setQWebFrame(qframe);
88     if (!frameData->allowsScrolling)
89         frameView->setScrollbarsMode(ScrollbarAlwaysOff);
90     if (frameData->marginWidth != -1)
91         frameView->setMarginWidth(frameData->marginWidth);
92     if (frameData->marginHeight != -1)
93         frameView->setMarginHeight(frameData->marginHeight);
94
95     frame->setView(frameView.get());
96     frame->init();
97
98     QObject::connect(q, SIGNAL(hoveringOverLink(const QString&, const QString&, const QString&)),
99                      page, SIGNAL(hoveringOverLink(const QString&, const QString&, const QString&)));
100 }
101
102 WebCore::PlatformScrollbar *QWebFramePrivate::horizontalScrollBar() const
103 {
104     Q_ASSERT(frameView);
105     return frameView->horizontalScrollBar();
106 }
107
108 WebCore::PlatformScrollbar *QWebFramePrivate::verticalScrollBar() const
109 {
110     Q_ASSERT(frameView);
111     return frameView->verticalScrollBar();
112 }
113
114 /*!
115     \class QWebFrame
116     \since 4.4
117     \brief The QWebFrame class represents a frame in a web page.
118
119     QWebFrame represents a frame inside a web page. Each QWebPage
120     object contains at least one frame, the mainFrame(). Additional
121     frames will be created for HTML &lt;frame&gt; or &lt;iframe&gt;
122     elements.
123
124     QWebFrame objects are created and controlled by the web page. You
125     can connect to the web pages frameCreated() signal to find out
126     about creation of new frames.
127
128     \sa QWebPage
129 */
130
131 QWebFrame::QWebFrame(QWebPage *parent, QWebFrameData *frameData)
132     : QObject(parent)
133     , d(new QWebFramePrivate)
134 {
135     d->page = parent;
136     d->init(this, parent->d->page, frameData);
137
138     if (!frameData->url.isEmpty()) {
139         ResourceRequest request(frameData->url, frameData->referrer);
140         d->frame->loader()->load(request, frameData->name);
141     }
142 }
143
144 QWebFrame::QWebFrame(QWebFrame *parent, QWebFrameData *frameData)
145     : QObject(parent)
146     , d(new QWebFramePrivate)
147 {
148     d->page = parent->d->page;
149     d->init(this, parent->d->page->d->page, frameData);
150 }
151
152 QWebFrame::~QWebFrame()
153 {
154     Q_ASSERT(d->frame == 0);
155     Q_ASSERT(d->frameView == 0);
156     delete d;
157 }
158
159 /*!
160   Make \a object available under \a name from within the frames
161   JavaScript context. The \a object will be inserted as a child of the
162   frames window object.
163
164   Qt properties will be exposed as JavaScript properties and slots as
165   JavaScript methods.
166 */
167 void QWebFrame::addToJSWindowObject(const QString &name, QObject *object)
168 {
169       KJS::JSLock lock;
170       KJS::Window *window = KJS::Window::retrieveWindow(d->frame.get());
171       KJS::Bindings::RootObject *root = d->frame->bindingRootObject();
172       if (!window) {
173           qDebug() << "Warning: couldn't get window object";
174           return;
175       }
176
177       KJS::JSObject *runtimeObject =
178         KJS::Bindings::Instance::createRuntimeObject(KJS::Bindings::Instance::QtLanguage,
179                                                      object, root);
180
181       window->put(window->globalExec(), KJS::Identifier((const KJS::UChar *) name.constData(), name.length()), runtimeObject);
182 }
183
184 /*!
185   returns the markup (HTML) contained in the current frame.
186 */
187 QString QWebFrame::markup() const
188 {
189     if (!d->frame->document())
190         return QString();
191     return createMarkup(d->frame->document());
192 }
193
194 /*!
195   returns the content of this frame as plain text.
196 */
197 QString QWebFrame::innerText() const
198 {
199     if (d->frameView->layoutPending())
200         d->frameView->layout();
201
202     Element *documentElement = d->frame->document()->documentElement();
203     return documentElement->innerText();
204 }
205
206 /*!
207   returns a dump of the rendering tree. Mainly useful for debugging html.
208 */
209 QString QWebFrame::renderTreeDump() const
210 {
211     if (d->frameView->layoutPending())
212         d->frameView->layout();
213
214     return externalRepresentation(d->frame->renderer());
215 }
216
217 /*!
218   The title of the frame as defined by the HTML &lt;title&gt;
219   element.
220 */
221 QString QWebFrame::title() const
222 {
223     if (d->frame->document())
224         return d->frame->loader()->documentLoader()->title();
225     else return QString();
226 }
227
228 /*!
229   The url of this frame.
230 */
231 QUrl QWebFrame::url() const
232 {
233     return QUrl((QString)d->frame->loader()->url().string());
234 }
235
236 /*!
237   The icon associated with this frame.
238 */
239 QPixmap QWebFrame::icon() const
240 {
241     String url = d->frame->loader()->url().string();
242
243     Image* image = 0;
244     if (!url.isEmpty()) {
245         image = iconDatabase()->iconForPageURL(url, IntSize(16, 16));
246     }
247
248     if (!image || image->isNull()) {
249         image = iconDatabase()->defaultIcon(IntSize(16, 16));
250     }
251
252     if (!image) {
253         return QPixmap();
254     }
255
256     QPixmap *icon = image->getPixmap();
257     if (!icon) {
258         return QPixmap();
259     }
260     return *icon;
261 }
262
263 /*!
264   The name of this frame as defined by the parent frame.
265 */
266 QString QWebFrame::name() const
267 {
268     return d->frame->tree()->name();
269 }
270
271 /*!
272   The web page that contains this frame.
273 */
274 QWebPage *QWebFrame::page() const
275 {
276     return d->page;
277 }
278
279 /*!
280   Load \a url into this frame.
281 */
282 void QWebFrame::load(const QUrl &url)
283 {
284 #if QT_VERSION < 0x040400
285     load(QWebNetworkRequest(url));
286 #else
287     load(QNetworkRequest(url));
288 #endif
289 }
290
291 #if QT_VERSION < 0x040400
292 /*!
293   Load network request \a req into this frame.
294 */
295 void QWebFrame::load(const QWebNetworkRequest &req)
296 {
297     if (d->parentFrame())
298         d->page->d->insideOpenCall = true;
299
300     QUrl url = req.url();
301     QHttpRequestHeader httpHeader = req.httpHeader();
302     QByteArray postData = req.postData();
303
304     WebCore::ResourceRequest request(url);
305
306     QString method = httpHeader.method();
307     if (!method.isEmpty())
308         request.setHTTPMethod(method);
309
310     QList<QPair<QString, QString> > values = httpHeader.values();
311     for (int i = 0; i < values.size(); ++i) {
312         const QPair<QString, QString> &val = values.at(i);
313         request.addHTTPHeaderField(val.first, val.second);
314     }
315
316     if (!postData.isEmpty()) {
317         WTF::RefPtr<WebCore::FormData> formData = new WebCore::FormData(postData.constData(), postData.size());
318         request.setHTTPBody(formData);
319     }
320
321     d->frame->loader()->load(request);
322
323     if (d->parentFrame())
324         d->page->d->insideOpenCall = false;
325 }
326
327 #else
328
329 /*!
330   Load network request \a req into this frame. Use the method specified in \a
331   operation. \a body is optional and is only used for POST operations.
332 */
333 void QWebFrame::load(const QNetworkRequest &req,
334                      QNetworkAccessManager::Operation operation,
335                      const QByteArray &body)
336 {
337     if (d->parentFrame())
338         d->page->d->insideOpenCall = true;
339
340     QUrl url = req.url();
341
342     WebCore::ResourceRequest request(url);
343
344     switch (operation) {
345         case QNetworkAccessManager::HeadOperation:
346             request.setHTTPMethod("HEAD");
347             break;
348         case QNetworkAccessManager::GetOperation:
349             request.setHTTPMethod("GET");
350             break;
351         case QNetworkAccessManager::PutOperation:
352             request.setHTTPMethod("PUT");
353             break;
354         case QNetworkAccessManager::PostOperation:
355             request.setHTTPMethod("POST");
356             break;
357         case QNetworkAccessManager::UnknownOperation:
358             // eh?
359             break;
360     }
361
362     QList<QByteArray> httpHeaders = req.rawHeaderList();
363     for (int i = 0; i < httpHeaders.size(); ++i) {
364         const QByteArray &headerName = httpHeaders.at(i);
365         request.addHTTPHeaderField(QString::fromLatin1(headerName), QString::fromLatin1(req.rawHeader(headerName)));
366     }
367
368     if (!body.isEmpty()) {
369         WTF::RefPtr<WebCore::FormData> formData = new WebCore::FormData(body.constData(), body.size());
370         request.setHTTPBody(formData);
371     }
372
373     d->frame->loader()->load(request);
374
375     if (d->parentFrame())
376         d->page->d->insideOpenCall = false;
377 }
378 #endif
379
380 /*!
381   Sets the content of this frame to \a html. \a baseUrl is optional and used to resolve relative
382   URLs in the document.
383 */
384 void QWebFrame::setHtml(const QString &html, const QUrl &baseUrl)
385 {
386     KURL kurl(baseUrl);
387     WebCore::ResourceRequest request(kurl);
388     WTF::RefPtr<WebCore::SharedBuffer> data = new WebCore::SharedBuffer(reinterpret_cast<const uchar *>(html.unicode()), html.length() * 2);
389     WebCore::SubstituteData substituteData(data, WebCore::String("text/html"), WebCore::String("utf-16"), kurl);
390     d->frame->loader()->load(request, substituteData);
391 }
392
393 /*!
394   \overload
395 */
396 void QWebFrame::setHtml(const QByteArray &html, const QUrl &baseUrl)
397 {
398     setContent(html, QString(), baseUrl);
399 }
400
401 /*!
402   Sets the content of this frame to \a data assuming \a mimeType. If
403   \a mimeType is not specified it defaults to 'text/html'.  \a baseUrl
404   us optional and used to resolve relative URLs in the document.
405 */
406 void QWebFrame::setContent(const QByteArray &data, const QString &mimeType, const QUrl &baseUrl)
407 {
408     KURL kurl(baseUrl);
409     WebCore::ResourceRequest request(kurl);
410     WTF::RefPtr<WebCore::SharedBuffer> buffer = new WebCore::SharedBuffer(data.constData(), data.length());
411     QString actualMimeType = mimeType;
412     if (actualMimeType.isEmpty())
413         actualMimeType = QLatin1String("text/html");
414     WebCore::SubstituteData substituteData(buffer, WebCore::String(actualMimeType), WebCore::String(), kurl);
415     d->frame->loader()->load(request, substituteData);
416 }
417
418
419 /*!
420   Returns the parent frame of this frame, or 0 if the frame is the web pages
421   main frame.
422
423   This is equivalent to qobject_cast<QWebFrame*>(frame->parent()).
424 */
425 QWebFrame *QWebFrame::parentFrame() const
426 {
427     return d->parentFrame();
428 }
429
430 /*!
431   Returns a list of all frames that are direct children of this frame.
432 */
433 QList<QWebFrame*> QWebFrame::childFrames() const
434 {
435     QList<QWebFrame*> rc;
436     if (d->frame) {
437         FrameTree *tree = d->frame->tree();
438         for (Frame *child = tree->firstChild(); child; child = child->tree()->nextSibling()) {
439             FrameLoader *loader = child->loader();
440             FrameLoaderClientQt *client = static_cast<FrameLoaderClientQt*>(loader->client());
441             if (client)
442                 rc.append(client->webFrame());
443         }
444
445     }
446     return rc;
447 }
448
449 /*!
450   \property QWebFrame::verticalScrollBarPolicy
451
452   This property defines the vertical scrollbar policy.
453
454   \sa Qt::ScrollBarPolicy
455 */
456 Qt::ScrollBarPolicy QWebFrame::verticalScrollBarPolicy() const
457 {
458     return (Qt::ScrollBarPolicy) d->frameView->vScrollbarMode();
459 }
460
461 void QWebFrame::setVerticalScrollBarPolicy(Qt::ScrollBarPolicy policy)
462 {
463     Q_ASSERT((int)ScrollbarAuto == (int)Qt::ScrollBarAsNeeded);
464     Q_ASSERT((int)ScrollbarAlwaysOff == (int)Qt::ScrollBarAlwaysOff);
465     Q_ASSERT((int)ScrollbarAlwaysOn == (int)Qt::ScrollBarAlwaysOn);
466     d->frameView->setVScrollbarMode((ScrollbarMode)policy);
467 }
468
469 /*!
470   \property QWebFrame::horizontalScrollBarPolicy
471
472   This property defines the horizontal scrollbar policy.
473
474   \sa Qt::ScrollBarPolicy
475 */
476 Qt::ScrollBarPolicy QWebFrame::horizontalScrollBarPolicy() const
477 {
478     return (Qt::ScrollBarPolicy) d->frameView->hScrollbarMode();
479 }
480
481 void QWebFrame::setHorizontalScrollBarPolicy(Qt::ScrollBarPolicy policy)
482 {
483     d->frameView->setHScrollbarMode((ScrollbarMode)policy);
484 }
485
486 /*!
487   Render the frame into \a painter clipping to \a clip.
488 */
489 void QWebFrame::render(QPainter *painter, const QRegion &clip)
490 {
491     if (!d->frameView || !d->frame->renderer())
492         return;
493
494     layout();
495
496     GraphicsContext ctx(painter);
497     QVector<QRect> vector = clip.rects();
498     for (int i = 0; i < vector.size(); ++i) 
499         d->frameView->paint(&ctx, vector.at(i));
500 }
501
502 /*!
503   Ensure that the content of the frame and all subframes are correctly layouted.
504 */
505 void QWebFrame::layout()
506 {
507     if (!d->frameView)
508         return;
509
510     d->frameView->layoutIfNeededRecursive();
511 }
512
513 /*!
514   returns the position of the frame relative to it's parent frame.
515 */
516 QPoint QWebFrame::pos() const
517 {
518     Q_ASSERT(d->frameView);
519     return d->pos();
520 }
521
522 /*!
523   return the geometry of the frame relative to it's parent frame.
524 */
525 QRect QWebFrame::geometry() const
526 {
527     Q_ASSERT(d->frameView);
528     return d->frameView->frameGeometry();
529 }
530
531 /*!
532   Evaluate JavaScript defined by \a scriptSource using this frame as context.
533 */
534 QString QWebFrame::evaluateJavaScript(const QString& scriptSource)
535 {
536     KJSProxy *proxy = d->frame->scriptProxy();
537     QString rc;
538     if (proxy) {
539         KJS::JSValue *v = proxy->evaluate(String(), 0, scriptSource);
540         if (v) {
541             rc = String(v->toString(proxy->globalObject()->globalExec()));
542         }
543     }
544     return rc;
545 }
546
547 WebCore::Frame* QWebFramePrivate::core(QWebFrame* webFrame)
548 {
549     return webFrame->d->frame.get();
550 }
551
552 QWebFrame* QWebFramePrivate::kit(WebCore::Frame* coreFrame)
553 {
554     return static_cast<FrameLoaderClientQt*>(coreFrame->loader()->client())->webFrame();
555 }
556
557
558 /*!
559   \fn void QWebFrame::cleared()
560
561   This signal is emitted whenever the content of the frame is cleared
562   (e.g. before starting a new load).
563 */
564
565 /*!
566   \fn void QWebFrame::loadDone(bool ok)
567
568   This signal is emitted when the frame is completely loaded. \a ok will indicate whether the load
569   was successful or any error occurred.
570 */
571
572 /*!
573   \fn void QWebFrame::provisionalLoad()
574
575   \internal
576 */
577
578 /*!
579   \fn void QWebFrame::titleChanged(const QString &title)
580
581   This signal is emitted whenever the \a title of the frame changes.
582
583   \sa title()
584 */
585
586 /*!
587   \fn void QWebFrame::urlChanged(const QUrl &url)
588
589   This signal is emitted whenever the \a url of the frame changes.
590
591   \sa url()
592 */
593
594 /*!
595   \fn void QWebFrame::hoveringOverLink(const QString &link, const QString &title, const QString &textContent)
596
597   This signal is emitted whenever the mouse cursor is hovering over a
598   link. It can be used to display information about the link in
599   e.g. the status bar. The signal arguments consist of the \a link destination, the \a title and the
600   link text as \a textContent .
601 */
602
603
604 /*!
605   \fn void QWebFrame::loadStarted()
606
607   This signal is emitted when a new load of the frame is started.
608 */
609
610 /*!
611   \fn void QWebFrame::loadFinished()
612   
613   This signal is emitted when a load of the frame is finished.
614 */
615
616 /*!
617   \fn void QWebFrame::initialLayoutComplete()
618
619   This signal is emitted when the first (initial) layout of the frame
620   has happened. This is the earliest time something can be shown on
621   the screen.
622 */
623     
624 /*!
625   \fn void QWebFrame::iconLoaded()
626
627   This signal is emitted when the icon ("favicon") associated with the frame has been loaded.
628 */