72509566496970c7328a51ab22407d03f49313c0
[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 #include "qwebnetworkinterface.h"
29
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 #endif
71 #include <qregion.h>
72
73 using namespace WebCore;
74
75 void QWebFramePrivate::init(QWebFrame *qframe, WebCore::Page *webcorePage, QWebFrameData *frameData)
76 {
77     q = qframe;
78
79     frameLoaderClient = new FrameLoaderClientQt();
80     frame = new Frame(webcorePage, frameData->ownerElement, frameLoaderClient);
81     frameLoaderClient->setFrame(qframe, frame.get());
82
83     frameView = new FrameView(frame.get());
84     frameView->deref();
85     frameView->setQWebFrame(qframe);
86     if (!frameData->allowsScrolling)
87         frameView->setScrollbarsMode(ScrollbarAlwaysOff);
88     if (frameData->marginWidth != -1)
89         frameView->setMarginWidth(frameData->marginWidth);
90     if (frameData->marginHeight != -1)
91         frameView->setMarginHeight(frameData->marginHeight);
92
93     frame->setView(frameView.get());
94     frame->init();
95     eventHandler = frame->eventHandler();
96
97     QObject::connect(q, SIGNAL(hoveringOverLink(const QString&, const QString&, const QString&)),
98                      page, SIGNAL(hoveringOverLink(const QString&, const QString&, const QString&)));
99 }
100
101 WebCore::PlatformScrollbar *QWebFramePrivate::horizontalScrollBar() const
102 {
103     Q_ASSERT(frameView);
104     return frameView->horizontalScrollBar();
105 }
106
107 WebCore::PlatformScrollbar *QWebFramePrivate::verticalScrollBar() const
108 {
109     Q_ASSERT(frameView);
110     return frameView->verticalScrollBar();
111 }
112
113 /*!
114     \class QWebFrame
115     \since 4.4
116     \brief The QWebFrame class represents a frame in a web page.
117
118     QWebFrame represents a frame inside a web page. Each QWebPage
119     object contains at least one frame, the mainFrame(). Additional
120     frames will be created for HTML &lt;frame&gt; or &lt;iframe&gt;
121     elements.
122
123     QWebFrame objects are created and controlled by the web page. You
124     can connect to the web pages frameCreated() signal to find out
125     about creation of new frames.
126
127     \sa QWebPage
128 */
129
130 QWebFrame::QWebFrame(QWebPage *parent, QWebFrameData *frameData)
131     : QObject(parent)
132     , d(new QWebFramePrivate)
133 {
134     d->page = parent;
135     d->init(this, parent->d->page, frameData);
136
137     if (!frameData->url.isEmpty()) {
138         ResourceRequest request(frameData->url, frameData->referrer);
139         d->frame->loader()->load(request, frameData->name);
140     }
141 }
142
143 QWebFrame::QWebFrame(QWebFrame *parent, QWebFrameData *frameData)
144     : QObject(parent)
145     , d(new QWebFramePrivate)
146 {
147     d->page = parent->d->page;
148     d->init(this, parent->d->page->d->page, frameData);
149 }
150
151 QWebFrame::~QWebFrame()
152 {
153     Q_ASSERT(d->frame == 0);
154     Q_ASSERT(d->frameView == 0);
155     delete d;
156 }
157
158 /*!
159   Make \a object available under \a name from within the frames
160   JavaScript context. The \a object will be inserted as a child of the
161   frames window object.
162
163   Qt properties will be exposed as JavaScript properties and slots as
164   JavaScript methods.
165 */
166 void QWebFrame::addToJSWindowObject(const QString &name, QObject *object)
167 {
168       KJS::JSLock lock;
169       KJS::Window *window = KJS::Window::retrieveWindow(d->frame.get());
170       KJS::Bindings::RootObject *root = d->frame->bindingRootObject();
171       if (!window) {
172           qDebug() << "Warning: couldn't get window object";
173           return;
174       }
175
176       KJS::JSObject *runtimeObject =
177         KJS::Bindings::Instance::createRuntimeObject(KJS::Bindings::Instance::QtLanguage,
178                                                      object, root);
179
180       window->put(window->globalExec(), KJS::Identifier((const KJS::UChar *) name.constData(), name.length()), runtimeObject);
181 }
182
183 /*!
184   returns the markup (HTML) contained in the current frame.
185 */
186 QString QWebFrame::markup() const
187 {
188     if (!d->frame->document())
189         return QString();
190     return createMarkup(d->frame->document());
191 }
192
193 /*!
194   returns the content of this frame as plain text.
195 */
196 QString QWebFrame::innerText() const
197 {
198     if (d->frameView->layoutPending())
199         d->frameView->layout();
200
201     Element *documentElement = d->frame->document()->documentElement();
202     return documentElement->innerText();
203 }
204
205 /*!
206   returns a dump of the rendering tree. Mainly useful for debugging html.
207 */
208 QString QWebFrame::renderTreeDump() const
209 {
210     if (d->frameView->layoutPending())
211         d->frameView->layout();
212
213     return externalRepresentation(d->frame->renderer());
214 }
215
216 /*!
217   The title of the frame as defined by the HTML &lt;title&gt;
218   element.
219 */
220 QString QWebFrame::title() const
221 {
222     if (d->frame->document())
223         return d->frame->document()->title();
224     else return QString();
225 }
226
227 /*!
228   The url of this frame.
229 */
230 QUrl QWebFrame::url() const
231 {
232     return QUrl((QString)d->frame->loader()->url().string());
233 }
234
235 /*!
236   The icon associated with this frame.
237 */
238 QPixmap QWebFrame::icon() const
239 {
240     String url = d->frame->loader()->url().string();
241     Image* image = iconDatabase()->iconForPageURL(url, IntSize(16, 16));
242     if (!image || image->isNull()) {
243         image = iconDatabase()->defaultIcon(IntSize(16, 16));
244     }
245
246     if (!image) {
247         return QPixmap();
248     }
249
250     QPixmap *icon = image->getPixmap();
251     if (!icon) {
252         return QPixmap();
253     }
254     return *icon;
255 }
256
257 /*!
258   The name of this frame as defined by the parent frame.
259 */
260 QString QWebFrame::name() const
261 {
262     return d->frame->tree()->name();
263 }
264
265 /*!
266   The web page that contains this frame.
267 */
268 QWebPage *QWebFrame::page() const
269 {
270     return d->page;
271 }
272
273 /*!
274   Load \a url into this frame.
275 */
276 void QWebFrame::load(const QUrl &url)
277 {
278 #if QT_VERSION < 0x040400
279     load(QWebNetworkRequest(url));
280 #else
281     load(QNetworkRequest(url));
282 #endif
283 }
284
285 #if QT_VERSION < 0x040400
286 void QWebFrame::load(const QWebNetworkRequest &req)
287 {
288     if (d->parentFrame())
289         d->page->d->insideOpenCall = true;
290
291     QUrl url = req.url();
292     QHttpRequestHeader httpHeader = req.httpHeader();
293     QByteArray postData = req.postData();
294
295     WebCore::ResourceRequest request(url);
296
297     QString method = httpHeader.method();
298     if (!method.isEmpty())
299         request.setHTTPMethod(method);
300
301     QList<QPair<QString, QString> > values = httpHeader.values();
302     for (int i = 0; i < values.size(); ++i) {
303         const QPair<QString, QString> &val = values.at(i);
304         request.addHTTPHeaderField(val.first, val.second);
305     }
306
307     if (!postData.isEmpty()) {
308         WTF::RefPtr<WebCore::FormData> formData = new WebCore::FormData(postData.constData(), postData.size());
309         request.setHTTPBody(formData);
310     }
311
312     d->frame->loader()->load(request);
313
314     if (d->parentFrame())
315         d->page->d->insideOpenCall = false;
316 }
317
318 #else
319
320 /*!
321   Load \a request into this frame. Use the method specified in \a
322   operation. \a body is optional and is only used for POST operations.
323 */
324 void QWebFrame::load(const QNetworkRequest &req,
325                      QNetworkAccessManager::Operation operation,
326                      const QByteArray &body)
327 {
328     if (d->parentFrame())
329         d->page->d->insideOpenCall = true;
330
331     QUrl url = req.url();
332
333     WebCore::ResourceRequest request(url);
334
335     switch (operation) {
336         case QNetworkAccessManager::HeadOperation:
337             request.setHTTPMethod("HEAD");
338             break;
339         case QNetworkAccessManager::GetOperation:
340             request.setHTTPMethod("GET");
341             break;
342         case QNetworkAccessManager::PutOperation:
343             request.setHTTPMethod("PUT");
344             break;
345         case QNetworkAccessManager::PostOperation:
346             request.setHTTPMethod("POST");
347             break;
348         case QNetworkAccessManager::UnknownOperation:
349             // eh?
350             break;
351     }
352
353     QList<QByteArray> httpHeaders = req.rawHeaderList();
354     for (int i = 0; i < httpHeaders.size(); ++i) {
355         const QByteArray &headerName = httpHeaders.at(i);
356         request.addHTTPHeaderField(QString::fromLatin1(headerName), QString::fromLatin1(req.rawHeader(headerName)));
357     }
358
359     if (!body.isEmpty()) {
360         WTF::RefPtr<WebCore::FormData> formData = new WebCore::FormData(body.constData(), body.size());
361         request.setHTTPBody(formData);
362     }
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 = new WebCore::SharedBuffer(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 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 = new WebCore::SharedBuffer(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 (Qt::ScrollBarPolicy) d->frameView->vScrollbarMode();
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     d->frameView->setVScrollbarMode((ScrollbarMode)policy);
458 }
459
460 /*!
461   \property QWebFrame::horizontalScrollBarPolicy
462
463   This property defines the horizontal scrollbar policy.
464
465   \sa Qt::ScrollBarPolicy
466 */
467 Qt::ScrollBarPolicy QWebFrame::horizontalScrollBarPolicy() const
468 {
469     return (Qt::ScrollBarPolicy) d->frameView->hScrollbarMode();
470 }
471
472 void QWebFrame::setHorizontalScrollBarPolicy(Qt::ScrollBarPolicy policy)
473 {
474     d->frameView->setHScrollbarMode((ScrollbarMode)policy);
475 }
476
477 /*!
478   Render the frame into \a painter clipping to \a clip.
479 */
480 void QWebFrame::render(QPainter *painter, const QRegion &clip)
481 {
482     if (!d->frameView || !d->frame->renderer())
483         return;
484
485     layout();
486
487     GraphicsContext ctx(painter);
488     QVector<QRect> vector = clip.rects();
489     for (int i = 0; i < vector.size(); ++i) 
490         d->frameView->paint(&ctx, vector.at(i));
491 }
492
493 /*!
494   Ensure that the content of the frame and all subframes are correctly layouted.
495 */
496 void QWebFrame::layout()
497 {
498     if (!d->frameView)
499         return;
500
501     d->frameView->layoutIfNeededRecursive();
502 }
503
504 /*!
505   returns the position of the frame relative to it's parent frame.
506 */
507 QPoint QWebFrame::pos() const
508 {
509     Q_ASSERT(d->frameView);
510     return d->pos();
511 }
512
513 /*!
514   return the geometry of the frame relative to it's parent frame.
515 */
516 QRect QWebFrame::geometry() const
517 {
518     Q_ASSERT(d->frameView);
519     return d->frameView->frameGeometry();
520 }
521
522 /*!
523   Evaluate JavaScript defined by \a scriptSource using this frame as context.
524 */
525 QString QWebFrame::evaluateJavaScript(const QString& scriptSource)
526 {
527     KJSProxy *proxy = d->frame->scriptProxy();
528     QString rc;
529     if (proxy) {
530         KJS::JSValue *v = proxy->evaluate(String(), 0, scriptSource);
531         if (v) {
532             rc = String(v->toString(proxy->globalObject()->globalExec()));
533         }
534     }
535     return rc;
536 }
537
538 WebCore::Frame* QWebFramePrivate::core(QWebFrame* webFrame)
539 {
540     return webFrame->d->frame.get();
541 }
542
543 QWebFrame* QWebFramePrivate::kit(WebCore::Frame* coreFrame)
544 {
545     return static_cast<FrameLoaderClientQt*>(coreFrame->loader()->client())->webFrame();
546 }
547
548
549 /*!
550   \fn void QWebFrame::cleared()
551
552   This signal is emitted whenever the content of the frame is cleared
553   (e.g. before starting a new load).
554 */
555
556 /*!
557   \fn void QWebFrame::loadDone(bool ok)
558
559   This signal is emitted when the frame is completely loaded. \a ok will indicate whether the load
560   was successful or any error occurred.
561 */
562
563 /*!
564   \fn void QWebFrame::provisionalLoad()
565
566   \internal
567 */
568
569 /*!
570   \fn void QWebFrame::titleChanged(const QString &title)
571
572   This signal is emitted whenever the title of the frame changes.
573
574   \sa title()
575 */
576
577 /*!
578   \fn void QWebFrame::hoveringOverLink(const QString &link, const QString &title, const QString &textContent)
579
580   This signal is emitted whenever the mouse cursor is hovering over a
581   link. It can be used to display information about the link in
582   e.g. the status bar.
583 */
584
585
586 /*!
587   \fn void QWebFrame::loadStarted()
588
589   This signal is emitted when a new load of the frame is started.
590 */
591
592 /*!
593   \fn void QWebFrame::loadFinished()
594   
595   This signal is emitted when a load of the frame is finished.
596 */
597
598     /**
599       * Signal is emitted when the mainframe()'s initial layout is completed.
600      */
601 /*!
602   \fn void QWebFrame::initialLayoutComplete()
603
604   This signal is emitted when the first (initial) layout of the frame
605   has happened. This is the earliest time something can be shown on
606   the screen.
607 */
608     
609 /*!
610   \fn void QWebFrame::iconLoaded()
611
612   This signal is emitted when the icon ("favicon") associated with the frame has been loaded.
613 */