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