333d53bf5986c8b3c6ae666bd2194563b1640b31
[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);
85
86     FrameView* frameView = new FrameView(frame);
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);
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     if (d->frame && d->frame->loader() && d->frame->loader()->client())
157         static_cast<FrameLoaderClientQt*>(d->frame->loader()->client())->m_webFrame = 0;
158         
159     delete d;
160 }
161
162 /*!
163   Make \a object available under \a name from within the frames
164   JavaScript context. The \a object will be inserted as a child of the
165   frames window object.
166
167   Qt properties will be exposed as JavaScript properties and slots as
168   JavaScript methods.
169 */
170 void QWebFrame::addToJSWindowObject(const QString &name, QObject *object)
171 {
172       KJS::JSLock lock;
173       JSDOMWindow *window = toJSDOMWindow(d->frame);
174       KJS::Bindings::RootObject *root = d->frame->bindingRootObject();
175       if (!window) {
176           qDebug() << "Warning: couldn't get window object";
177           return;
178       }
179
180       KJS::JSObject *runtimeObject =
181         KJS::Bindings::Instance::createRuntimeObject(KJS::Bindings::QtInstance::create(object, root));
182
183       window->put(window->globalExec(), KJS::Identifier((const UChar *) name.constData(), name.length()), runtimeObject);
184 }
185
186 /*!
187   returns the markup (HTML) contained in the current frame.
188 */
189 QString QWebFrame::markup() const
190 {
191     if (!d->frame->document())
192         return QString();
193     return createMarkup(d->frame->document());
194 }
195
196 /*!
197   returns the content of this frame as plain text.
198 */
199 QString QWebFrame::innerText() const
200 {
201     if (d->frame->view() && d->frame->view()->layoutPending())
202         d->frame->view()->layout();
203
204     Element *documentElement = d->frame->document()->documentElement();
205     return documentElement->innerText();
206 }
207
208 /*!
209   returns a dump of the rendering tree. Mainly useful for debugging html.
210 */
211 QString QWebFrame::renderTreeDump() const
212 {
213     if (d->frame->view() && d->frame->view()->layoutPending())
214         d->frame->view()->layout();
215
216     return externalRepresentation(d->frame->renderer());
217 }
218
219 /*!
220   The title of the frame as defined by the HTML &lt;title&gt;
221   element.
222 */
223 QString QWebFrame::title() const
224 {
225     if (d->frame->document())
226         return d->frame->loader()->documentLoader()->title();
227     else return QString();
228 }
229
230 /*!
231   The url of this frame.
232 */
233 QUrl QWebFrame::url() const
234 {
235     return d->frame->loader()->url();
236 }
237
238 /*!
239   The icon associated with this frame.
240 */
241 QPixmap QWebFrame::icon() const
242 {
243     String url = d->frame->loader()->url().string();
244
245     Image* image = 0;
246     if (!url.isEmpty()) {
247         image = iconDatabase()->iconForPageURL(url, IntSize(16, 16));
248     }
249
250     if (!image || image->isNull()) {
251         image = iconDatabase()->defaultIcon(IntSize(16, 16));
252     }
253
254     if (!image) {
255         return QPixmap();
256     }
257
258     QPixmap *icon = image->getPixmap();
259     if (!icon) {
260         return QPixmap();
261     }
262     return *icon;
263 }
264
265 /*!
266   The name of this frame as defined by the parent frame.
267 */
268 QString QWebFrame::name() const
269 {
270     return d->frame->tree()->name();
271 }
272
273 /*!
274   The web page that contains this frame.
275 */
276 QWebPage *QWebFrame::page() const
277 {
278     return d->page;
279 }
280
281 /*!
282   Load \a url into this frame.
283 */
284 void QWebFrame::load(const QUrl &url)
285 {
286 #if QT_VERSION < 0x040400
287     load(QWebNetworkRequest(url));
288 #else
289     load(QNetworkRequest(url));
290 #endif
291 }
292
293 #if QT_VERSION < 0x040400
294 /*!
295   Load network request \a req into this frame.
296 */
297 void QWebFrame::load(const QWebNetworkRequest &req)
298 {
299     if (d->parentFrame())
300         d->page->d->insideOpenCall = true;
301
302     QUrl url = req.url();
303     QHttpRequestHeader httpHeader = req.httpHeader();
304     QByteArray postData = req.postData();
305
306     WebCore::ResourceRequest request(url);
307
308     QString method = httpHeader.method();
309     if (!method.isEmpty())
310         request.setHTTPMethod(method);
311
312     QList<QPair<QString, QString> > values = httpHeader.values();
313     for (int i = 0; i < values.size(); ++i) {
314         const QPair<QString, QString> &val = values.at(i);
315         request.addHTTPHeaderField(val.first, val.second);
316     }
317
318     if (!postData.isEmpty())
319         request.setHTTPBody(WebCore::FormData::create(postData.constData(), postData.size()));
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         request.setHTTPBody(WebCore::FormData::create(body.constData(), body.size()));
370
371     d->frame->loader()->load(request);
372
373     if (d->parentFrame())
374         d->page->d->insideOpenCall = false;
375 }
376 #endif
377
378 /*!
379   Sets the content of this frame to \a html. \a baseUrl is optional and used to resolve relative
380   URLs in the document.
381 */
382 void QWebFrame::setHtml(const QString &html, const QUrl &baseUrl)
383 {
384     KURL kurl(baseUrl);
385     WebCore::ResourceRequest request(kurl);
386     WTF::RefPtr<WebCore::SharedBuffer> data = WebCore::SharedBuffer::create(reinterpret_cast<const uchar *>(html.unicode()), html.length() * 2);
387     WebCore::SubstituteData substituteData(data, WebCore::String("text/html"), WebCore::String("utf-16"), kurl);
388     d->frame->loader()->load(request, substituteData);
389 }
390
391 /*!
392   \overload
393 */
394 void QWebFrame::setHtml(const QByteArray &html, const QUrl &baseUrl)
395 {
396     setContent(html, QString(), baseUrl);
397 }
398
399 /*!
400   Sets the content of this frame to \a data assuming \a mimeType. If
401   \a mimeType is not specified it defaults to 'text/html'.  \a baseUrl
402   us optional and used to resolve relative URLs in the document.
403 */
404 void QWebFrame::setContent(const QByteArray &data, const QString &mimeType, const QUrl &baseUrl)
405 {
406     KURL kurl(baseUrl);
407     WebCore::ResourceRequest request(kurl);
408     WTF::RefPtr<WebCore::SharedBuffer> buffer = WebCore::SharedBuffer::create(data.constData(), data.length());
409     QString actualMimeType = mimeType;
410     if (actualMimeType.isEmpty())
411         actualMimeType = QLatin1String("text/html");
412     WebCore::SubstituteData substituteData(buffer, WebCore::String(actualMimeType), WebCore::String(), kurl);
413     d->frame->loader()->load(request, substituteData);
414 }
415
416
417 /*!
418   Returns the parent frame of this frame, or 0 if the frame is the web pages
419   main frame.
420
421   This is equivalent to qobject_cast<QWebFrame*>(frame->parent()).
422 */
423 QWebFrame *QWebFrame::parentFrame() const
424 {
425     return d->parentFrame();
426 }
427
428 /*!
429   Returns a list of all frames that are direct children of this frame.
430 */
431 QList<QWebFrame*> QWebFrame::childFrames() const
432 {
433     QList<QWebFrame*> rc;
434     if (d->frame) {
435         FrameTree *tree = d->frame->tree();
436         for (Frame *child = tree->firstChild(); child; child = child->tree()->nextSibling()) {
437             FrameLoader *loader = child->loader();
438             FrameLoaderClientQt *client = static_cast<FrameLoaderClientQt*>(loader->client());
439             if (client)
440                 rc.append(client->webFrame());
441         }
442
443     }
444     return rc;
445 }
446
447 /*!
448   \property QWebFrame::verticalScrollBarPolicy
449
450   This property defines the vertical scrollbar policy.
451
452   \sa Qt::ScrollBarPolicy
453 */
454 Qt::ScrollBarPolicy QWebFrame::verticalScrollBarPolicy() const
455 {
456     return d->verticalScrollBarPolicy;
457 }
458
459 void QWebFrame::setVerticalScrollBarPolicy(Qt::ScrollBarPolicy policy)
460 {
461     Q_ASSERT((int)ScrollbarAuto == (int)Qt::ScrollBarAsNeeded);
462     Q_ASSERT((int)ScrollbarAlwaysOff == (int)Qt::ScrollBarAlwaysOff);
463     Q_ASSERT((int)ScrollbarAlwaysOn == (int)Qt::ScrollBarAlwaysOn);
464
465     d->verticalScrollBarPolicy = policy;
466     if (d->frame->view())
467         d->frame->view()->setVScrollbarMode((ScrollbarMode)policy);
468 }
469
470 /*!
471   \property QWebFrame::horizontalScrollBarPolicy
472
473   This property defines the horizontal scrollbar policy.
474
475   \sa Qt::ScrollBarPolicy
476 */
477 Qt::ScrollBarPolicy QWebFrame::horizontalScrollBarPolicy() const
478 {
479     return d->horizontalScrollBarPolicy;
480 }
481
482 void QWebFrame::setHorizontalScrollBarPolicy(Qt::ScrollBarPolicy policy)
483 {
484     d->horizontalScrollBarPolicy = policy;
485     if (d->frame->view())
486         d->frame->view()->setHScrollbarMode((ScrollbarMode)policy);
487 }
488
489 /*!
490   Render the frame into \a painter clipping to \a clip.
491 */
492 void QWebFrame::render(QPainter *painter, const QRegion &clip)
493 {
494     if (!d->frame->view() || !d->frame->renderer())
495         return;
496
497     layout();
498
499     GraphicsContext ctx(painter);
500     QVector<QRect> vector = clip.rects();
501     WebCore::FrameView* view = d->frame->view();
502     for (int i = 0; i < vector.size(); ++i) 
503         view->paint(&ctx, vector.at(i));
504 }
505
506 /*!
507   Ensure that the content of the frame and all subframes are correctly layouted.
508 */
509 void QWebFrame::layout()
510 {
511     if (!d->frame->view())
512         return;
513
514     d->frame->view()->layoutIfNeededRecursive();
515 }
516
517 /*!
518   returns the position of the frame relative to it's parent frame.
519 */
520 QPoint QWebFrame::pos() const
521 {
522     if (!d->frame->view())
523         return QPoint();
524
525     return d->frame->view()->frameGeometry().topLeft();
526 }
527
528 /*!
529   return the geometry of the frame relative to it's parent frame.
530 */
531 QRect QWebFrame::geometry() const
532 {
533     if (!d->frame->view())
534         return QRect();
535     return d->frame->view()->frameGeometry();
536 }
537
538 /*!
539   Evaluate JavaScript defined by \a scriptSource using this frame as context.
540 */
541 QString QWebFrame::evaluateJavaScript(const QString& scriptSource)
542 {
543     KJSProxy *proxy = d->frame->scriptProxy();
544     QString rc;
545     if (proxy) {
546         KJS::JSValue *v = proxy->evaluate(String(), 0, scriptSource);
547         if (v) {
548             rc = String(v->toString(proxy->globalObject()->globalExec()));
549         }
550     }
551     return rc;
552 }
553
554 WebCore::Frame* QWebFramePrivate::core(QWebFrame* webFrame)
555 {
556     return webFrame->d->frame;
557 }
558
559 QWebFrame* QWebFramePrivate::kit(WebCore::Frame* coreFrame)
560 {
561     return static_cast<FrameLoaderClientQt*>(coreFrame->loader()->client())->webFrame();
562 }
563
564
565 /*!
566   \fn void QWebFrame::cleared()
567
568   This signal is emitted whenever the content of the frame is cleared
569   (e.g. before starting a new load).
570 */
571
572 /*!
573   \fn void QWebFrame::loadDone(bool ok)
574
575   This signal is emitted when the frame is completely loaded. \a ok will indicate whether the load
576   was successful or any error occurred.
577 */
578
579 /*!
580   \fn void QWebFrame::provisionalLoad()
581
582   \internal
583 */
584
585 /*!
586   \fn void QWebFrame::titleChanged(const QString &title)
587
588   This signal is emitted whenever the title of the frame changes.
589   The \a title string specifies the new title.
590
591   \sa title()
592 */
593
594 /*!
595   \fn void QWebFrame::urlChanged(const QUrl &url)
596
597   This signal is emitted whenever the \a url of the frame changes.
598
599   \sa url()
600 */
601
602 /*!
603   \fn void QWebFrame::hoveringOverLink(const QString &link, const QString &title, const QString &textContent)
604
605   This signal is emitted whenever the mouse cursor is hovering over a
606   link. It can be used to display information about the link in
607   e.g. the status bar. The signal arguments consist of the \a link destination, the \a title and the
608   link text as \a textContent .
609 */
610
611
612 /*!
613   \fn void QWebFrame::loadStarted()
614
615   This signal is emitted when a new load of the frame is started.
616 */
617
618 /*!
619   \fn void QWebFrame::loadFinished()
620   
621   This signal is emitted when a load of the frame is finished.
622 */
623
624 /*!
625   \fn void QWebFrame::initialLayoutComplete()
626
627   This signal is emitted when the first (initial) layout of the frame
628   has happened. This is the earliest time something can be shown on
629   the screen.
630 */
631     
632 /*!
633   \fn void QWebFrame::iconLoaded()
634
635   This signal is emitted when the icon ("favicon") associated with the frame has been loaded.
636 */