240e7274db1b7694cd72b6fb15dd16c0ef4e8b03
[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 "kjs_proxy.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 #else
71 #include "qwebnetworkinterface.h"
72 #endif
73 #include <qregion.h>
74
75 using namespace WebCore;
76
77 void QWebFramePrivate::init(QWebFrame *qframe, WebCore::Page *webcorePage, QWebFrameData *frameData)
78 {
79     q = qframe;
80
81     frameLoaderClient = new FrameLoaderClientQt();
82     frame = new Frame(webcorePage, frameData->ownerElement, frameLoaderClient);
83     frameLoaderClient->setFrame(qframe, frame.get());
84
85     frameView = new FrameView(frame.get());
86     frameView->deref();
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
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     Q_ASSERT(frameView);
105     return frameView->horizontalScrollBar();
106 }
107
108 WebCore::PlatformScrollbar *QWebFramePrivate::verticalScrollBar() const
109 {
110     Q_ASSERT(frameView);
111     return frameView->verticalScrollBar();
112 }
113
114 /*!
115     \class QWebFrame
116     \since 4.4
117     \brief The QWebFrame class represents a frame in a web page.
118
119     QWebFrame represents a frame inside a web page. Each QWebPage
120     object contains at least one frame, the mainFrame(). Additional
121     frames will be created for HTML &lt;frame&gt; or &lt;iframe&gt;
122     elements.
123
124     QWebFrame objects are created and controlled by the web page. You
125     can connect to the web pages frameCreated() signal to find out
126     about creation of new frames.
127
128     \sa QWebPage
129 */
130
131 QWebFrame::QWebFrame(QWebPage *parent, QWebFrameData *frameData)
132     : QObject(parent)
133     , d(new QWebFramePrivate)
134 {
135     d->page = parent;
136     d->init(this, parent->d->page, frameData);
137
138     if (!frameData->url.isEmpty()) {
139         ResourceRequest request(frameData->url, frameData->referrer);
140         d->frame->loader()->load(request, frameData->name);
141     }
142 }
143
144 QWebFrame::QWebFrame(QWebFrame *parent, QWebFrameData *frameData)
145     : QObject(parent)
146     , d(new QWebFramePrivate)
147 {
148     d->page = parent->d->page;
149     d->init(this, parent->d->page->d->page, frameData);
150 }
151
152 QWebFrame::~QWebFrame()
153 {
154     Q_ASSERT(d->frame == 0);
155     Q_ASSERT(d->frameView == 0);
156     delete d;
157 }
158
159 /*!
160   Make \a object available under \a name from within the frames
161   JavaScript context. The \a object will be inserted as a child of the
162   frames window object.
163
164   Qt properties will be exposed as JavaScript properties and slots as
165   JavaScript methods.
166 */
167 void QWebFrame::addToJSWindowObject(const QString &name, QObject *object)
168 {
169       KJS::JSLock lock;
170       JSDOMWindow *window = toJSDOMWindow(d->frame.get());
171       KJS::Bindings::RootObject *root = d->frame->bindingRootObject();
172       if (!window) {
173           qDebug() << "Warning: couldn't get window object";
174           return;
175       }
176
177       KJS::JSObject *runtimeObject =
178         KJS::Bindings::Instance::createRuntimeObject(KJS::Bindings::Instance::QtLanguage,
179                                                      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->frameView->layoutPending())
200         d->frameView->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->frameView->layoutPending())
212         d->frameView->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 = new WebCore::SharedBuffer(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 = new WebCore::SharedBuffer(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 (Qt::ScrollBarPolicy) d->frameView->vScrollbarMode();
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     d->frameView->setVScrollbarMode((ScrollbarMode)policy);
463 }
464
465 /*!
466   \property QWebFrame::horizontalScrollBarPolicy
467
468   This property defines the horizontal scrollbar policy.
469
470   \sa Qt::ScrollBarPolicy
471 */
472 Qt::ScrollBarPolicy QWebFrame::horizontalScrollBarPolicy() const
473 {
474     return (Qt::ScrollBarPolicy) d->frameView->hScrollbarMode();
475 }
476
477 void QWebFrame::setHorizontalScrollBarPolicy(Qt::ScrollBarPolicy policy)
478 {
479     d->frameView->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->frameView || !d->frame->renderer())
488         return;
489
490     layout();
491
492     GraphicsContext ctx(painter);
493     QVector<QRect> vector = clip.rects();
494     for (int i = 0; i < vector.size(); ++i) 
495         d->frameView->paint(&ctx, vector.at(i));
496 }
497
498 /*!
499   Ensure that the content of the frame and all subframes are correctly layouted.
500 */
501 void QWebFrame::layout()
502 {
503     if (!d->frameView)
504         return;
505
506     d->frameView->layoutIfNeededRecursive();
507 }
508
509 /*!
510   returns the position of the frame relative to it's parent frame.
511 */
512 QPoint QWebFrame::pos() const
513 {
514     Q_ASSERT(d->frameView);
515     return d->pos();
516 }
517
518 /*!
519   return the geometry of the frame relative to it's parent frame.
520 */
521 QRect QWebFrame::geometry() const
522 {
523     Q_ASSERT(d->frameView);
524     return d->frameView->frameGeometry();
525 }
526
527 /*!
528   Evaluate JavaScript defined by \a scriptSource using this frame as context.
529 */
530 QString QWebFrame::evaluateJavaScript(const QString& scriptSource)
531 {
532     KJSProxy *proxy = d->frame->scriptProxy();
533     QString rc;
534     if (proxy) {
535         KJS::JSValue *v = proxy->evaluate(String(), 0, scriptSource);
536         if (v) {
537             rc = String(v->toString(proxy->globalObject()->globalExec()));
538         }
539     }
540     return rc;
541 }
542
543 WebCore::Frame* QWebFramePrivate::core(QWebFrame* webFrame)
544 {
545     return webFrame->d->frame.get();
546 }
547
548 QWebFrame* QWebFramePrivate::kit(WebCore::Frame* coreFrame)
549 {
550     return static_cast<FrameLoaderClientQt*>(coreFrame->loader()->client())->webFrame();
551 }
552
553
554 /*!
555   \fn void QWebFrame::cleared()
556
557   This signal is emitted whenever the content of the frame is cleared
558   (e.g. before starting a new load).
559 */
560
561 /*!
562   \fn void QWebFrame::loadDone(bool ok)
563
564   This signal is emitted when the frame is completely loaded. \a ok will indicate whether the load
565   was successful or any error occurred.
566 */
567
568 /*!
569   \fn void QWebFrame::provisionalLoad()
570
571   \internal
572 */
573
574 /*!
575   \fn void QWebFrame::titleChanged(const QString &title)
576
577   This signal is emitted whenever the title of the frame changes.
578   The \a title string specifies the new title.
579
580   \sa title()
581 */
582
583 /*!
584   \fn void QWebFrame::urlChanged(const QUrl &url)
585
586   This signal is emitted whenever the \a url of the frame changes.
587
588   \sa url()
589 */
590
591 /*!
592   \fn void QWebFrame::hoveringOverLink(const QString &link, const QString &title, const QString &textContent)
593
594   This signal is emitted whenever the mouse cursor is hovering over a
595   link. It can be used to display information about the link in
596   e.g. the status bar. The signal arguments consist of the \a link destination, the \a title and the
597   link text as \a textContent .
598 */
599
600
601 /*!
602   \fn void QWebFrame::loadStarted()
603
604   This signal is emitted when a new load of the frame is started.
605 */
606
607 /*!
608   \fn void QWebFrame::loadFinished()
609   
610   This signal is emitted when a load of the frame is finished.
611 */
612
613 /*!
614   \fn void QWebFrame::initialLayoutComplete()
615
616   This signal is emitted when the first (initial) layout of the frame
617   has happened. This is the earliest time something can be shown on
618   the screen.
619 */
620     
621 /*!
622   \fn void QWebFrame::iconLoaded()
623
624   This signal is emitted when the icon ("favicon") associated with the frame has been loaded.
625 */