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