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     allowsScrolling = frameData->allowsScrolling;
83     marginWidth = frameData->marginWidth;
84     marginHeight = frameData->marginHeight;
85
86     frameLoaderClient = new FrameLoaderClientQt();
87     frame = new Frame(webcorePage, frameData->ownerElement, frameLoaderClient);
88     frameLoaderClient->setFrame(qframe, frame);
89     frame->init();
90
91     QObject::connect(q, SIGNAL(hoveringOverLink(const QString&, const QString&, const QString&)),
92                      page, SIGNAL(hoveringOverLink(const QString&, const QString&, const QString&)));
93 }
94
95 WebCore::PlatformScrollbar *QWebFramePrivate::horizontalScrollBar() const
96 {
97     if (!frame->view())
98         return 0;
99     return frame->view()->horizontalScrollBar();
100 }
101
102 WebCore::PlatformScrollbar *QWebFramePrivate::verticalScrollBar() const
103 {
104     if (!frame->view())
105         return 0;
106     return frame->view()->verticalScrollBar();
107 }
108
109 /*!
110     \class QWebFrame
111     \since 4.4
112     \brief The QWebFrame class represents a frame in a web page.
113
114     QWebFrame represents a frame inside a web page. Each QWebPage
115     object contains at least one frame, the mainFrame(). Additional
116     frames will be created for HTML &lt;frame&gt; or &lt;iframe&gt;
117     elements.
118
119     QWebFrame objects are created and controlled by the web page. You
120     can connect to the web pages frameCreated() signal to find out
121     about creation of new frames.
122
123     \sa QWebPage
124 */
125
126 QWebFrame::QWebFrame(QWebPage *parent, QWebFrameData *frameData)
127     : QObject(parent)
128     , d(new QWebFramePrivate)
129 {
130     d->page = parent;
131     d->init(this, parent->d->page, frameData);
132
133     if (!frameData->url.isEmpty()) {
134         ResourceRequest request(frameData->url, frameData->referrer);
135         d->frame->loader()->load(request, frameData->name);
136     }
137 }
138
139 QWebFrame::QWebFrame(QWebFrame *parent, QWebFrameData *frameData)
140     : QObject(parent)
141     , d(new QWebFramePrivate)
142 {
143     d->page = parent->d->page;
144     d->init(this, parent->d->page->d->page, frameData);
145 }
146
147 QWebFrame::~QWebFrame()
148 {
149     if (d->frame && d->frame->loader() && d->frame->loader()->client())
150         static_cast<FrameLoaderClientQt*>(d->frame->loader()->client())->m_webFrame = 0;
151         
152     delete d;
153 }
154
155 /*!
156   Make \a object available under \a name from within the frames
157   JavaScript context. The \a object will be inserted as a child of the
158   frames window object.
159
160   Qt properties will be exposed as JavaScript properties and slots as
161   JavaScript methods.
162 */
163 void QWebFrame::addToJSWindowObject(const QString &name, QObject *object)
164 {
165       KJS::JSLock lock;
166       JSDOMWindow *window = toJSDOMWindow(d->frame);
167       KJS::Bindings::RootObject *root = d->frame->bindingRootObject();
168       if (!window) {
169           qDebug() << "Warning: couldn't get window object";
170           return;
171       }
172
173       KJS::JSObject *runtimeObject =
174         KJS::Bindings::Instance::createRuntimeObject(KJS::Bindings::QtInstance::create(object, root));
175
176       window->put(window->globalExec(), KJS::Identifier((const UChar *) name.constData(), name.length()), runtimeObject);
177 }
178
179 /*!
180   returns the markup (HTML) contained in the current frame.
181 */
182 QString QWebFrame::markup() const
183 {
184     if (!d->frame->document())
185         return QString();
186     return createMarkup(d->frame->document());
187 }
188
189 /*!
190   returns the content of this frame as plain text.
191 */
192 QString QWebFrame::innerText() const
193 {
194     if (d->frame->view() && d->frame->view()->layoutPending())
195         d->frame->view()->layout();
196
197     Element *documentElement = d->frame->document()->documentElement();
198     return documentElement->innerText();
199 }
200
201 /*!
202   returns a dump of the rendering tree. Mainly useful for debugging html.
203 */
204 QString QWebFrame::renderTreeDump() const
205 {
206     if (d->frame->view() && d->frame->view()->layoutPending())
207         d->frame->view()->layout();
208
209     return externalRepresentation(d->frame->renderer());
210 }
211
212 /*!
213   The title of the frame as defined by the HTML &lt;title&gt;
214   element.
215 */
216 QString QWebFrame::title() const
217 {
218     if (d->frame->document())
219         return d->frame->loader()->documentLoader()->title();
220     else return QString();
221 }
222
223 /*!
224   The url of this frame.
225 */
226 QUrl QWebFrame::url() const
227 {
228     return d->frame->loader()->url();
229 }
230
231 /*!
232   The icon associated with this frame.
233 */
234 QPixmap QWebFrame::icon() const
235 {
236     String url = d->frame->loader()->url().string();
237
238     Image* image = 0;
239     if (!url.isEmpty()) {
240         image = iconDatabase()->iconForPageURL(url, IntSize(16, 16));
241     }
242
243     if (!image || image->isNull()) {
244         image = iconDatabase()->defaultIcon(IntSize(16, 16));
245     }
246
247     if (!image) {
248         return QPixmap();
249     }
250
251     QPixmap *icon = image->getPixmap();
252     if (!icon) {
253         return QPixmap();
254     }
255     return *icon;
256 }
257
258 /*!
259   The name of this frame as defined by the parent frame.
260 */
261 QString QWebFrame::name() const
262 {
263     return d->frame->tree()->name();
264 }
265
266 /*!
267   The web page that contains this frame.
268 */
269 QWebPage *QWebFrame::page() const
270 {
271     return d->page;
272 }
273
274 /*!
275   Load \a url into this frame.
276 */
277 void QWebFrame::load(const QUrl &url)
278 {
279 #if QT_VERSION < 0x040400
280     load(QWebNetworkRequest(url));
281 #else
282     load(QNetworkRequest(url));
283 #endif
284 }
285
286 #if QT_VERSION < 0x040400
287 /*!
288   Load network request \a req into this frame.
289 */
290 void QWebFrame::load(const QWebNetworkRequest &req)
291 {
292     if (d->parentFrame())
293         d->page->d->insideOpenCall = true;
294
295     QUrl url = req.url();
296     QHttpRequestHeader httpHeader = req.httpHeader();
297     QByteArray postData = req.postData();
298
299     WebCore::ResourceRequest request(url);
300
301     QString method = httpHeader.method();
302     if (!method.isEmpty())
303         request.setHTTPMethod(method);
304
305     QList<QPair<QString, QString> > values = httpHeader.values();
306     for (int i = 0; i < values.size(); ++i) {
307         const QPair<QString, QString> &val = values.at(i);
308         request.addHTTPHeaderField(val.first, val.second);
309     }
310
311     if (!postData.isEmpty())
312         request.setHTTPBody(WebCore::FormData::create(postData.constData(), postData.size()));
313
314     d->frame->loader()->load(request);
315
316     if (d->parentFrame())
317         d->page->d->insideOpenCall = false;
318 }
319
320 #else
321
322 /*!
323   Load network request \a req into this frame. Use the method specified in \a
324   operation. \a body is optional and is only used for POST operations.
325 */
326 void QWebFrame::load(const QNetworkRequest &req,
327                      QNetworkAccessManager::Operation operation,
328                      const QByteArray &body)
329 {
330     if (d->parentFrame())
331         d->page->d->insideOpenCall = true;
332
333     QUrl url = req.url();
334
335     WebCore::ResourceRequest request(url);
336
337     switch (operation) {
338         case QNetworkAccessManager::HeadOperation:
339             request.setHTTPMethod("HEAD");
340             break;
341         case QNetworkAccessManager::GetOperation:
342             request.setHTTPMethod("GET");
343             break;
344         case QNetworkAccessManager::PutOperation:
345             request.setHTTPMethod("PUT");
346             break;
347         case QNetworkAccessManager::PostOperation:
348             request.setHTTPMethod("POST");
349             break;
350         case QNetworkAccessManager::UnknownOperation:
351             // eh?
352             break;
353     }
354
355     QList<QByteArray> httpHeaders = req.rawHeaderList();
356     for (int i = 0; i < httpHeaders.size(); ++i) {
357         const QByteArray &headerName = httpHeaders.at(i);
358         request.addHTTPHeaderField(QString::fromLatin1(headerName), QString::fromLatin1(req.rawHeader(headerName)));
359     }
360
361     if (!body.isEmpty())
362         request.setHTTPBody(WebCore::FormData::create(body.constData(), body.size()));
363
364     d->frame->loader()->load(request);
365
366     if (d->parentFrame())
367         d->page->d->insideOpenCall = false;
368 }
369 #endif
370
371 /*!
372   Sets the content of this frame to \a html. \a baseUrl is optional and used to resolve relative
373   URLs in the document.
374 */
375 void QWebFrame::setHtml(const QString &html, const QUrl &baseUrl)
376 {
377     KURL kurl(baseUrl);
378     WebCore::ResourceRequest request(kurl);
379     WTF::RefPtr<WebCore::SharedBuffer> data = WebCore::SharedBuffer::create(reinterpret_cast<const uchar *>(html.unicode()), html.length() * 2);
380     WebCore::SubstituteData substituteData(data, WebCore::String("text/html"), WebCore::String("utf-16"), kurl);
381     d->frame->loader()->load(request, substituteData);
382 }
383
384 /*!
385   \overload
386 */
387 void QWebFrame::setHtml(const QByteArray &html, const QUrl &baseUrl)
388 {
389     setContent(html, QString(), baseUrl);
390 }
391
392 /*!
393   Sets the content of this frame to \a data assuming \a mimeType. If
394   \a mimeType is not specified it defaults to 'text/html'.  \a baseUrl
395   us optional and used to resolve relative URLs in the document.
396 */
397 void QWebFrame::setContent(const QByteArray &data, const QString &mimeType, const QUrl &baseUrl)
398 {
399     KURL kurl(baseUrl);
400     WebCore::ResourceRequest request(kurl);
401     WTF::RefPtr<WebCore::SharedBuffer> buffer = WebCore::SharedBuffer::create(data.constData(), data.length());
402     QString actualMimeType = mimeType;
403     if (actualMimeType.isEmpty())
404         actualMimeType = QLatin1String("text/html");
405     WebCore::SubstituteData substituteData(buffer, WebCore::String(actualMimeType), WebCore::String(), kurl);
406     d->frame->loader()->load(request, substituteData);
407 }
408
409
410 /*!
411   Returns the parent frame of this frame, or 0 if the frame is the web pages
412   main frame.
413
414   This is equivalent to qobject_cast<QWebFrame*>(frame->parent()).
415 */
416 QWebFrame *QWebFrame::parentFrame() const
417 {
418     return d->parentFrame();
419 }
420
421 /*!
422   Returns a list of all frames that are direct children of this frame.
423 */
424 QList<QWebFrame*> QWebFrame::childFrames() const
425 {
426     QList<QWebFrame*> rc;
427     if (d->frame) {
428         FrameTree *tree = d->frame->tree();
429         for (Frame *child = tree->firstChild(); child; child = child->tree()->nextSibling()) {
430             FrameLoader *loader = child->loader();
431             FrameLoaderClientQt *client = static_cast<FrameLoaderClientQt*>(loader->client());
432             if (client)
433                 rc.append(client->webFrame());
434         }
435
436     }
437     return rc;
438 }
439
440 /*!
441   \property QWebFrame::verticalScrollBarPolicy
442
443   This property defines the vertical scrollbar policy.
444
445   \sa Qt::ScrollBarPolicy
446 */
447 Qt::ScrollBarPolicy QWebFrame::verticalScrollBarPolicy() const
448 {
449     return d->verticalScrollBarPolicy;
450 }
451
452 void QWebFrame::setVerticalScrollBarPolicy(Qt::ScrollBarPolicy policy)
453 {
454     Q_ASSERT((int)ScrollbarAuto == (int)Qt::ScrollBarAsNeeded);
455     Q_ASSERT((int)ScrollbarAlwaysOff == (int)Qt::ScrollBarAlwaysOff);
456     Q_ASSERT((int)ScrollbarAlwaysOn == (int)Qt::ScrollBarAlwaysOn);
457
458     d->verticalScrollBarPolicy = policy;
459     if (d->frame->view())
460         d->frame->view()->setVScrollbarMode((ScrollbarMode)policy);
461 }
462
463 /*!
464   \property QWebFrame::horizontalScrollBarPolicy
465
466   This property defines the horizontal scrollbar policy.
467
468   \sa Qt::ScrollBarPolicy
469 */
470 Qt::ScrollBarPolicy QWebFrame::horizontalScrollBarPolicy() const
471 {
472     return d->horizontalScrollBarPolicy;
473 }
474
475 void QWebFrame::setHorizontalScrollBarPolicy(Qt::ScrollBarPolicy policy)
476 {
477     d->horizontalScrollBarPolicy = policy;
478     if (d->frame->view())
479         d->frame->view()->setHScrollbarMode((ScrollbarMode)policy);
480 }
481
482 /*!
483   Render the frame into \a painter clipping to \a clip.
484 */
485 void QWebFrame::render(QPainter *painter, const QRegion &clip)
486 {
487     if (!d->frame->view() || !d->frame->renderer())
488         return;
489
490     layout();
491
492     GraphicsContext ctx(painter);
493     QVector<QRect> vector = clip.rects();
494     WebCore::FrameView* view = d->frame->view();
495     for (int i = 0; i < vector.size(); ++i) 
496         view->paint(&ctx, vector.at(i));
497 }
498
499 /*!
500   Ensure that the content of the frame and all subframes are correctly layouted.
501 */
502 void QWebFrame::layout()
503 {
504     if (!d->frame->view())
505         return;
506
507     d->frame->view()->layoutIfNeededRecursive();
508 }
509
510 /*!
511   returns the position of the frame relative to it's parent frame.
512 */
513 QPoint QWebFrame::pos() const
514 {
515     if (!d->frame->view())
516         return QPoint();
517
518     return d->frame->view()->frameGeometry().topLeft();
519 }
520
521 /*!
522   return the geometry of the frame relative to it's parent frame.
523 */
524 QRect QWebFrame::geometry() const
525 {
526     if (!d->frame->view())
527         return QRect();
528     return d->frame->view()->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;
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 title of the frame changes.
582   The \a title string specifies the new title.
583
584   \sa title()
585 */
586
587 /*!
588   \fn void QWebFrame::urlChanged(const QUrl &url)
589
590   This signal is emitted whenever the \a url of the frame changes.
591
592   \sa url()
593 */
594
595 /*!
596   \fn void QWebFrame::hoveringOverLink(const QString &link, const QString &title, const QString &textContent)
597
598   This signal is emitted whenever the mouse cursor is hovering over a
599   link. It can be used to display information about the link in
600   e.g. the status bar. The signal arguments consist of the \a link destination, the \a title and the
601   link text as \a textContent .
602 */
603
604
605 /*!
606   \fn void QWebFrame::loadStarted()
607
608   This signal is emitted when a new load of the frame is started.
609 */
610
611 /*!
612   \fn void QWebFrame::loadFinished()
613   
614   This signal is emitted when a load of the frame is finished.
615 */
616
617 /*!
618   \fn void QWebFrame::initialLayoutComplete()
619
620   This signal is emitted when the first (initial) layout of the frame
621   has happened. This is the earliest time something can be shown on
622   the screen.
623 */
624     
625 /*!
626   \fn void QWebFrame::iconLoaded()
627
628   This signal is emitted when the icon ("favicon") associated with the frame has been loaded.
629 */