2008-04-01 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 "runtime.h"
56 #include "runtime_root.h"
57 #include "JSDOMWindow.h"
58 #include "qt_instance.h"
59 #include "kjs_proxy.h"
60 #include "kjs_binding.h"
61 #include "ExecState.h"
62 #include "object.h"
63
64 #include "wtf/HashMap.h"
65
66 #include <qdebug.h>
67 #include <qevent.h>
68 #include <qpainter.h>
69 #if QT_VERSION >= 0x040400
70 #include <qnetworkrequest.h>
71 #else
72 #include "qwebnetworkinterface.h"
73 #endif
74 #include <qregion.h>
75
76 using namespace WebCore;
77
78 void QWebFramePrivate::init(QWebFrame *qframe, WebCore::Page *webcorePage, QWebFrameData *frameData)
79 {
80     q = qframe;
81
82     frameLoaderClient = new FrameLoaderClientQt();
83     frame = new Frame(webcorePage, frameData->ownerElement, frameLoaderClient);
84     frameLoaderClient->setFrame(qframe, frame.get());
85
86     FrameView* frameView = new FrameView(frame.get());
87     if (!frameData->allowsScrolling)
88         frameView->setScrollbarsMode(ScrollbarAlwaysOff);
89     if (frameData->marginWidth != -1)
90         frameView->setMarginWidth(frameData->marginWidth);
91     if (frameData->marginHeight != -1)
92         frameView->setMarginHeight(frameData->marginHeight);
93
94     frame->setView(frameView.get());
95     frame->init();
96     frameView->deref();
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     if (!frame->view())
105         return 0;
106     return frame->view()->horizontalScrollBar();
107 }
108
109 WebCore::PlatformScrollbar *QWebFramePrivate::verticalScrollBar() const
110 {
111     if (!frame->view())
112         return 0;
113     return frame->view()->verticalScrollBar();
114 }
115
116 /*!
117     \class QWebFrame
118     \since 4.4
119     \brief The QWebFrame class represents a frame in a web page.
120
121     QWebFrame represents a frame inside a web page. Each QWebPage
122     object contains at least one frame, the mainFrame(). Additional
123     frames will be created for HTML &lt;frame&gt; or &lt;iframe&gt;
124     elements.
125
126     QWebFrame objects are created and controlled by the web page. You
127     can connect to the web pages frameCreated() signal to find out
128     about creation of new frames.
129
130     \sa QWebPage
131 */
132
133 QWebFrame::QWebFrame(QWebPage *parent, QWebFrameData *frameData)
134     : QObject(parent)
135     , d(new QWebFramePrivate)
136 {
137     d->page = parent;
138     d->init(this, parent->d->page, frameData);
139
140     if (!frameData->url.isEmpty()) {
141         ResourceRequest request(frameData->url, frameData->referrer);
142         d->frame->loader()->load(request, frameData->name);
143     }
144 }
145
146 QWebFrame::QWebFrame(QWebFrame *parent, QWebFrameData *frameData)
147     : QObject(parent)
148     , d(new QWebFramePrivate)
149 {
150     d->page = parent->d->page;
151     d->init(this, parent->d->page->d->page, frameData);
152 }
153
154 QWebFrame::~QWebFrame()
155 {
156     Q_ASSERT(d->frame == 0);
157     delete d;
158 }
159
160 /*!
161   Make \a object available under \a name from within the frames
162   JavaScript context. The \a object will be inserted as a child of the
163   frames window object.
164
165   Qt properties will be exposed as JavaScript properties and slots as
166   JavaScript methods.
167 */
168 void QWebFrame::addToJSWindowObject(const QString &name, QObject *object)
169 {
170       KJS::JSLock lock;
171       JSDOMWindow *window = toJSDOMWindow(d->frame.get());
172       KJS::Bindings::RootObject *root = d->frame->bindingRootObject();
173       if (!window) {
174           qDebug() << "Warning: couldn't get window object";
175           return;
176       }
177
178       KJS::JSObject *runtimeObject =
179         KJS::Bindings::Instance::createRuntimeObject(KJS::Bindings::QtInstance::create(object, root));
180
181       window->put(window->globalExec(), KJS::Identifier((const 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->frame->view() && d->frame->view()->layoutPending())
200         d->frame->view()->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->frame->view() && d->frame->view()->layoutPending())
212         d->frame->view()->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 d->frame->loader()->url();
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         request.setHTTPBody(WebCore::FormData::create(postData.constData(), postData.size()));
318
319     d->frame->loader()->load(request);
320
321     if (d->parentFrame())
322         d->page->d->insideOpenCall = false;
323 }
324
325 #else
326
327 /*!
328   Load network request \a req into this frame. Use the method specified in \a
329   operation. \a body is optional and is only used for POST operations.
330 */
331 void QWebFrame::load(const QNetworkRequest &req,
332                      QNetworkAccessManager::Operation operation,
333                      const QByteArray &body)
334 {
335     if (d->parentFrame())
336         d->page->d->insideOpenCall = true;
337
338     QUrl url = req.url();
339
340     WebCore::ResourceRequest request(url);
341
342     switch (operation) {
343         case QNetworkAccessManager::HeadOperation:
344             request.setHTTPMethod("HEAD");
345             break;
346         case QNetworkAccessManager::GetOperation:
347             request.setHTTPMethod("GET");
348             break;
349         case QNetworkAccessManager::PutOperation:
350             request.setHTTPMethod("PUT");
351             break;
352         case QNetworkAccessManager::PostOperation:
353             request.setHTTPMethod("POST");
354             break;
355         case QNetworkAccessManager::UnknownOperation:
356             // eh?
357             break;
358     }
359
360     QList<QByteArray> httpHeaders = req.rawHeaderList();
361     for (int i = 0; i < httpHeaders.size(); ++i) {
362         const QByteArray &headerName = httpHeaders.at(i);
363         request.addHTTPHeaderField(QString::fromLatin1(headerName), QString::fromLatin1(req.rawHeader(headerName)));
364     }
365
366     if (!body.isEmpty())
367         request.setHTTPBody(WebCore::FormData::create(body.constData(), body.size()));
368
369     d->frame->loader()->load(request);
370
371     if (d->parentFrame())
372         d->page->d->insideOpenCall = false;
373 }
374 #endif
375
376 /*!
377   Sets the content of this frame to \a html. \a baseUrl is optional and used to resolve relative
378   URLs in the document.
379 */
380 void QWebFrame::setHtml(const QString &html, const QUrl &baseUrl)
381 {
382     KURL kurl(baseUrl);
383     WebCore::ResourceRequest request(kurl);
384     WTF::RefPtr<WebCore::SharedBuffer> data = WebCore::SharedBuffer::create(reinterpret_cast<const uchar *>(html.unicode()), html.length() * 2);
385     WebCore::SubstituteData substituteData(data, WebCore::String("text/html"), WebCore::String("utf-16"), kurl);
386     d->frame->loader()->load(request, substituteData);
387 }
388
389 /*!
390   \overload
391 */
392 void QWebFrame::setHtml(const QByteArray &html, const QUrl &baseUrl)
393 {
394     setContent(html, QString(), baseUrl);
395 }
396
397 /*!
398   Sets the content of this frame to \a data assuming \a mimeType. If
399   \a mimeType is not specified it defaults to 'text/html'.  \a baseUrl
400   us optional and used to resolve relative URLs in the document.
401 */
402 void QWebFrame::setContent(const QByteArray &data, const QString &mimeType, const QUrl &baseUrl)
403 {
404     KURL kurl(baseUrl);
405     WebCore::ResourceRequest request(kurl);
406     WTF::RefPtr<WebCore::SharedBuffer> buffer = WebCore::SharedBuffer::create(data.constData(), data.length());
407     QString actualMimeType = mimeType;
408     if (actualMimeType.isEmpty())
409         actualMimeType = QLatin1String("text/html");
410     WebCore::SubstituteData substituteData(buffer, WebCore::String(actualMimeType), WebCore::String(), kurl);
411     d->frame->loader()->load(request, substituteData);
412 }
413
414
415 /*!
416   Returns the parent frame of this frame, or 0 if the frame is the web pages
417   main frame.
418
419   This is equivalent to qobject_cast<QWebFrame*>(frame->parent()).
420 */
421 QWebFrame *QWebFrame::parentFrame() const
422 {
423     return d->parentFrame();
424 }
425
426 /*!
427   Returns a list of all frames that are direct children of this frame.
428 */
429 QList<QWebFrame*> QWebFrame::childFrames() const
430 {
431     QList<QWebFrame*> rc;
432     if (d->frame) {
433         FrameTree *tree = d->frame->tree();
434         for (Frame *child = tree->firstChild(); child; child = child->tree()->nextSibling()) {
435             FrameLoader *loader = child->loader();
436             FrameLoaderClientQt *client = static_cast<FrameLoaderClientQt*>(loader->client());
437             if (client)
438                 rc.append(client->webFrame());
439         }
440
441     }
442     return rc;
443 }
444
445 /*!
446   \property QWebFrame::verticalScrollBarPolicy
447
448   This property defines the vertical scrollbar policy.
449
450   \sa Qt::ScrollBarPolicy
451 */
452 Qt::ScrollBarPolicy QWebFrame::verticalScrollBarPolicy() const
453 {
454     return d->verticalScrollBarPolicy;
455 }
456
457 void QWebFrame::setVerticalScrollBarPolicy(Qt::ScrollBarPolicy policy)
458 {
459     Q_ASSERT((int)ScrollbarAuto == (int)Qt::ScrollBarAsNeeded);
460     Q_ASSERT((int)ScrollbarAlwaysOff == (int)Qt::ScrollBarAlwaysOff);
461     Q_ASSERT((int)ScrollbarAlwaysOn == (int)Qt::ScrollBarAlwaysOn);
462
463     d->verticalScrollBarPolicy = policy;
464     if (d->frame->view())
465         d->frame->view()->setVScrollbarMode((ScrollbarMode)policy);
466 }
467
468 /*!
469   \property QWebFrame::horizontalScrollBarPolicy
470
471   This property defines the horizontal scrollbar policy.
472
473   \sa Qt::ScrollBarPolicy
474 */
475 Qt::ScrollBarPolicy QWebFrame::horizontalScrollBarPolicy() const
476 {
477     return d->horizontalScrollBarPolicy;
478 }
479
480 void QWebFrame::setHorizontalScrollBarPolicy(Qt::ScrollBarPolicy policy)
481 {
482     d->horizontalScrollBarPolicy = policy;
483     if (d->frame->view())
484         d->frame->view()->setHScrollbarMode((ScrollbarMode)policy);
485 }
486
487 /*!
488   Render the frame into \a painter clipping to \a clip.
489 */
490 void QWebFrame::render(QPainter *painter, const QRegion &clip)
491 {
492     if (!d->frame->view() || !d->frame->renderer())
493         return;
494
495     layout();
496
497     GraphicsContext ctx(painter);
498     QVector<QRect> vector = clip.rects();
499     WebCore::FrameView* view = d->frame->view();
500     for (int i = 0; i < vector.size(); ++i) 
501         view->paint(&ctx, vector.at(i));
502 }
503
504 /*!
505   Ensure that the content of the frame and all subframes are correctly layouted.
506 */
507 void QWebFrame::layout()
508 {
509     if (!d->frame->view())
510         return;
511
512     d->frame->view()->layoutIfNeededRecursive();
513 }
514
515 /*!
516   returns the position of the frame relative to it's parent frame.
517 */
518 QPoint QWebFrame::pos() const
519 {
520     if (!d->frame->view())
521         return QPoint();
522
523     return d->frame->view()->frameGeometry().topLeft();
524 }
525
526 /*!
527   return the geometry of the frame relative to it's parent frame.
528 */
529 QRect QWebFrame::geometry() const
530 {
531     if (!d->frame->view())
532         return QRect();
533     return d->frame->view()->frameGeometry();
534 }
535
536 /*!
537   Evaluate JavaScript defined by \a scriptSource using this frame as context.
538 */
539 QString QWebFrame::evaluateJavaScript(const QString& scriptSource)
540 {
541     KJSProxy *proxy = d->frame->scriptProxy();
542     QString rc;
543     if (proxy) {
544         KJS::JSValue *v = proxy->evaluate(String(), 0, scriptSource);
545         if (v) {
546             rc = String(v->toString(proxy->globalObject()->globalExec()));
547         }
548     }
549     return rc;
550 }
551
552 WebCore::Frame* QWebFramePrivate::core(QWebFrame* webFrame)
553 {
554     return webFrame->d->frame.get();
555 }
556
557 QWebFrame* QWebFramePrivate::kit(WebCore::Frame* coreFrame)
558 {
559     return static_cast<FrameLoaderClientQt*>(coreFrame->loader()->client())->webFrame();
560 }
561
562
563 /*!
564   \fn void QWebFrame::cleared()
565
566   This signal is emitted whenever the content of the frame is cleared
567   (e.g. before starting a new load).
568 */
569
570 /*!
571   \fn void QWebFrame::loadDone(bool ok)
572
573   This signal is emitted when the frame is completely loaded. \a ok will indicate whether the load
574   was successful or any error occurred.
575 */
576
577 /*!
578   \fn void QWebFrame::provisionalLoad()
579
580   \internal
581 */
582
583 /*!
584   \fn void QWebFrame::titleChanged(const QString &title)
585
586   This signal is emitted whenever the title of the frame changes.
587   The \a title string specifies the new title.
588
589   \sa title()
590 */
591
592 /*!
593   \fn void QWebFrame::urlChanged(const QUrl &url)
594
595   This signal is emitted whenever the \a url of the frame changes.
596
597   \sa url()
598 */
599
600 /*!
601   \fn void QWebFrame::hoveringOverLink(const QString &link, const QString &title, const QString &textContent)
602
603   This signal is emitted whenever the mouse cursor is hovering over a
604   link. It can be used to display information about the link in
605   e.g. the status bar. The signal arguments consist of the \a link destination, the \a title and the
606   link text as \a textContent .
607 */
608
609
610 /*!
611   \fn void QWebFrame::loadStarted()
612
613   This signal is emitted when a new load of the frame is started.
614 */
615
616 /*!
617   \fn void QWebFrame::loadFinished()
618   
619   This signal is emitted when a load of the frame is finished.
620 */
621
622 /*!
623   \fn void QWebFrame::initialLayoutComplete()
624
625   This signal is emitted when the first (initial) layout of the frame
626   has happened. This is the earliest time something can be shown on
627   the screen.
628 */
629     
630 /*!
631   \fn void QWebFrame::iconLoaded()
632
633   This signal is emitted when the icon ("favicon") associated with the frame has been loaded.
634 */