initial import
[vuplus_webkit] / Source / WebKit / qt / Api / qwebframe.cpp
1 /*
2     Copyright (C) 2008,2009 Nokia Corporation and/or its subsidiary(-ies)
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
21 #include "config.h"
22 #include "qwebframe.h"
23
24 #if USE(JSC)
25 #include "APICast.h"
26 #include "BridgeJSC.h"
27 #include "CallFrame.h"
28 #elif USE(V8)
29 #include "V8Binding.h"
30 #endif
31 #include "Document.h"
32 #include "DocumentLoader.h"
33 #include "DragData.h"
34 #include "Element.h"
35 #include "FocusController.h"
36 #include "Frame.h"
37 #include "FrameLoaderClientQt.h"
38 #include "FrameSelection.h"
39 #include "FrameTree.h"
40 #include "FrameView.h"
41 #if USE(JSC)
42 #include "GCController.h"
43 #elif USE(V8)
44 #include "V8GCController.h"
45 #endif
46 #include "GraphicsContext.h"
47 #include "HTMLMetaElement.h"
48 #include "HitTestResult.h"
49 #include "HTTPParsers.h"
50 #include "IconDatabase.h"
51 #include "InspectorController.h"
52 #if USE(JSC)
53 #include "JavaScript.h"
54 #include "JSDOMBinding.h"
55 #include "JSDOMWindowBase.h"
56 #include "JSLock.h"
57 #include "JSObject.h"
58 #include "JSRetainPtr.h"
59 #include "OpaqueJSString.h"
60 #elif USE(V8)
61 #include "V8DOMWrapper.h"
62 #include "V8DOMWindowShell.h"
63 #endif
64 #include "NetworkingContext.h"
65 #include "NodeList.h"
66 #include "Page.h"
67 #include "PlatformMouseEvent.h"
68 #include "PlatformWheelEvent.h"
69 #include "PrintContext.h"
70 #if USE(JSC)
71 #include "PutPropertySlot.h"
72 #endif
73 #include "RenderLayer.h"
74 #include "RenderTreeAsText.h"
75 #include "RenderView.h"
76 #include "ResourceRequest.h"
77 #include "ScriptController.h"
78 #include "ScriptSourceCode.h"
79 #include "ScriptValue.h"
80 #include "Scrollbar.h"
81 #include "Settings.h"
82 #include "SubstituteData.h"
83 #include "SVGSMILElement.h"
84 #include "TiledBackingStore.h"
85 #include "htmlediting.h"
86 #include "markup.h"
87 #if USE(JSC)
88 #include "qt_instance.h"
89 #include "qt_runtime.h"
90 #endif
91 #include "qwebelement.h"
92 #include "qwebframe_p.h"
93 #include "qwebpage.h"
94 #include "qwebpage_p.h"
95 #include "qwebsecurityorigin.h"
96 #include "qwebsecurityorigin_p.h"
97 #include "qwebscriptworld.h"
98 #include "qwebscriptworld_p.h"
99 #if USE(JSC)
100 #include "runtime_object.h"
101 #include "runtime_root.h"
102 #endif
103 #if USE(TEXTURE_MAPPER)
104 #include "texmap/TextureMapper.h"
105 #include "texmap/TextureMapperNode.h"
106 #endif
107 #include "wtf/HashMap.h"
108 #include <QMultiMap>
109 #include <qdebug.h>
110 #include <qevent.h>
111 #include <qfileinfo.h>
112 #include <qpainter.h>
113 #include <qprinter.h>
114 #include <qregion.h>
115 #include <qnetworkrequest.h>
116
117 using namespace WebCore;
118
119 // from text/qfont.cpp
120 QT_BEGIN_NAMESPACE
121 extern Q_GUI_EXPORT int qt_defaultDpi();
122 QT_END_NAMESPACE
123
124 bool QWEBKIT_EXPORT qtwebkit_webframe_scrollOverflow(QWebFrame* qFrame, int dx, int dy, const QPoint& pos)
125 {
126     WebCore::Frame* frame = QWebFramePrivate::core(qFrame);
127     if (!frame || !frame->document() || !frame->view() || !frame->eventHandler())
128         return false;
129
130     QPoint contentsPos = frame->view()->windowToContents(pos);
131     Node* node = frame->document()->elementFromPoint(contentsPos.x(), contentsPos.y());
132     if (!node)
133         return false;
134
135     RenderObject* renderer = node->renderer();
136     if (!renderer)
137         return false;
138
139     if (renderer->isListBox())
140         return false;
141
142     RenderLayer* renderLayer = renderer->enclosingLayer();
143     if (!renderLayer)
144         return false;
145
146     bool scrolledHorizontal = false;
147     bool scrolledVertical = false;
148
149     do {
150         if (dx > 0)
151             scrolledHorizontal = renderLayer->scroll(ScrollRight, ScrollByPixel, dx);
152         else if (dx < 0)
153             scrolledHorizontal = renderLayer->scroll(ScrollLeft, ScrollByPixel, qAbs(dx));
154
155         if (dy > 0)
156             scrolledVertical = renderLayer->scroll(ScrollDown, ScrollByPixel, dy);
157         else if (dy < 0)
158             scrolledVertical = renderLayer->scroll(ScrollUp, ScrollByPixel, qAbs(dy));
159
160         if (scrolledHorizontal || scrolledVertical)
161             return true;
162
163         renderLayer = renderLayer->parent();
164     } while (renderLayer);
165
166     return false;
167 }
168
169
170 /*!
171   \internal
172   Scrolls nested frames starting at this frame, \a dx pixels to the right 
173   and \a dy pixels downward. Both \a dx and \a dy may be negative. First attempts
174   to scroll elements with CSS overflow at position pos, followed by this frame. If this 
175   frame doesn't scroll, attempts to scroll the parent
176 */
177 void QWEBKIT_EXPORT qtwebkit_webframe_scrollRecursively(QWebFrame* qFrame, int dx, int dy, const QPoint& pos)
178 {
179     if (!qFrame)
180         return;
181
182     if (qtwebkit_webframe_scrollOverflow(qFrame, dx, dy, pos))
183         return;
184
185     bool scrollHorizontal = false;
186     bool scrollVertical = false;
187
188     do {
189         if (dx > 0)  // scroll right
190             scrollHorizontal = qFrame->scrollBarValue(Qt::Horizontal) < qFrame->scrollBarMaximum(Qt::Horizontal);
191         else if (dx < 0)  // scroll left
192             scrollHorizontal = qFrame->scrollBarValue(Qt::Horizontal) > qFrame->scrollBarMinimum(Qt::Horizontal);
193
194         if (dy > 0)  // scroll down
195             scrollVertical = qFrame->scrollBarValue(Qt::Vertical) < qFrame->scrollBarMaximum(Qt::Vertical);
196         else if (dy < 0) //scroll up
197             scrollVertical = qFrame->scrollBarValue(Qt::Vertical) > qFrame->scrollBarMinimum(Qt::Vertical);
198
199         if (scrollHorizontal || scrollVertical) {
200             qFrame->scroll(dx, dy);
201             return;
202         }
203
204         qFrame = qFrame->parentFrame();
205     } while (qFrame);
206 }
207
208 static inline ResourceRequestCachePolicy cacheLoadControlToCachePolicy(uint cacheLoadControl)
209 {
210     switch (cacheLoadControl) {
211     case QNetworkRequest::AlwaysNetwork:
212         return WebCore::ReloadIgnoringCacheData;
213     case QNetworkRequest::PreferCache:
214         return WebCore::ReturnCacheDataElseLoad;
215     case QNetworkRequest::AlwaysCache:
216         return WebCore::ReturnCacheDataDontLoad;
217     default:
218         break;
219     }
220     return WebCore::UseProtocolCachePolicy;
221 }
222
223 QWebFrameData::QWebFrameData(WebCore::Page* parentPage, WebCore::Frame* parentFrame,
224                              WebCore::HTMLFrameOwnerElement* ownerFrameElement,
225                              const WTF::String& frameName)
226     : name(frameName)
227     , ownerElement(ownerFrameElement)
228     , page(parentPage)
229     , allowsScrolling(true)
230     , marginWidth(0)
231     , marginHeight(0)
232 {
233     frameLoaderClient = new FrameLoaderClientQt();
234     frame = Frame::create(page, ownerElement, frameLoaderClient);
235
236     // FIXME: All of the below should probably be moved over into WebCore
237     frame->tree()->setName(name);
238     if (parentFrame)
239         parentFrame->tree()->appendChild(frame);
240 }
241
242 void QWebFramePrivate::init(QWebFrame *qframe, QWebFrameData *frameData)
243 {
244     q = qframe;
245
246     allowsScrolling = frameData->allowsScrolling;
247     marginWidth = frameData->marginWidth;
248     marginHeight = frameData->marginHeight;
249     frame = frameData->frame.get();
250     frameLoaderClient = frameData->frameLoaderClient;
251     frameLoaderClient->setFrame(qframe, frame);
252
253     frame->init();
254 }
255
256 void QWebFramePrivate::setPage(QWebPage* newPage)
257 {
258     if (page == newPage)
259         return;
260
261     // The QWebFrame is created as a child of QWebPage or a parent QWebFrame.
262     // That adds it to QObject's internal children list and ensures it will be
263     // deleted when parent QWebPage is deleted. Reparent if needed.
264     if (q->parent() == qobject_cast<QObject*>(page))
265         q->setParent(newPage);
266
267     page = newPage;
268     emit q->pageChanged();
269 }
270
271 WebCore::Scrollbar* QWebFramePrivate::horizontalScrollBar() const
272 {
273     if (!frame->view())
274         return 0;
275     return frame->view()->horizontalScrollbar();
276 }
277
278 WebCore::Scrollbar* QWebFramePrivate::verticalScrollBar() const
279 {
280     if (!frame->view())
281         return 0;
282     return frame->view()->verticalScrollbar();
283 }
284
285 #if ENABLE(TILED_BACKING_STORE)
286 void QWebFramePrivate::renderFromTiledBackingStore(GraphicsContext* context, const QRegion& clip)
287 {
288     ASSERT(frame->tiledBackingStore());
289
290     if (!frame->view() || !frame->contentRenderer())
291         return;
292
293     QVector<QRect> vector = clip.rects();
294     if (vector.isEmpty())
295         return;
296
297     QPainter* painter = context->platformContext();
298
299     WebCore::FrameView* view = frame->view();
300     
301     int scrollX = view->scrollX();
302     int scrollY = view->scrollY();
303     context->translate(-scrollX, -scrollY);
304
305     for (int i = 0; i < vector.size(); ++i) {
306         const QRect& clipRect = vector.at(i);
307
308         painter->save();
309         
310         QRect rect = clipRect.translated(scrollX, scrollY);
311         painter->setClipRect(rect, Qt::IntersectClip);
312
313         frame->tiledBackingStore()->paint(context, rect);
314
315         painter->restore();
316     }
317
318 #if USE(ACCELERATED_COMPOSITING) && USE(TEXTURE_MAPPER)
319     renderCompositedLayers(context, IntRect(clip.boundingRect()));
320     renderFrameExtras(context, QFlags<QWebFrame::RenderLayer>(QWebFrame::ScrollBarLayer) | QWebFrame::PanIconLayer, clip);
321 #endif
322 }
323 #endif
324
325 #if USE(ACCELERATED_COMPOSITING) && USE(TEXTURE_MAPPER)
326 void QWebFramePrivate::renderCompositedLayers(GraphicsContext* context, const IntRect& clip)
327 {
328     if (!rootTextureMapperNode || !textureMapper)
329         return;
330
331     textureMapper->setGraphicsContext(context);
332     textureMapper->setImageInterpolationQuality(context->imageInterpolationQuality());
333     textureMapper->setTextDrawingMode(context->textDrawingMode());
334     textureMapper->setViewportSize(frame->view()->frameRect().size());
335     QPainter* painter = context->platformContext();
336     const QTransform transform = painter->worldTransform();
337     const TransformationMatrix matrix(
338                 transform.m11(), transform.m12(), 0, transform.m13(),
339                 transform.m21(), transform.m22(), 0, transform.m23(),
340                 0, 0, 1, 0,
341                 transform.m31(), transform.m32(), 0, transform.m33()
342                 );
343     rootTextureMapperNode->setTransform(matrix);
344     rootTextureMapperNode->setOpacity(painter->opacity());
345     textureMapper->beginPainting();
346     textureMapper->beginClip(matrix, clip);
347     rootTextureMapperNode->paint();
348     textureMapper->endClip();
349     textureMapper->endPainting();
350 }
351 #endif
352
353 void QWebFramePrivate::renderRelativeCoords(GraphicsContext* context, QFlags<QWebFrame::RenderLayer> layers, const QRegion& clip)
354 {
355     if (!frame->view() || !frame->contentRenderer())
356         return;
357
358     QVector<QRect> vector = clip.rects();
359     if (vector.isEmpty())
360         return;
361
362     QPainter* painter = context->platformContext();
363
364     WebCore::FrameView* view = frame->view();
365     view->updateLayoutAndStyleIfNeededRecursive();
366
367     if (layers & QWebFrame::ContentsLayer) {
368         for (int i = 0; i < vector.size(); ++i) {
369             const QRect& clipRect = vector.at(i);
370
371             QRect rect = clipRect.intersected(view->frameRect());
372
373             context->save();
374             painter->setClipRect(clipRect, Qt::IntersectClip);
375
376             int x = view->x();
377             int y = view->y();
378
379             int scrollX = view->scrollX();
380             int scrollY = view->scrollY();
381
382             context->translate(x, y);
383             rect.translate(-x, -y);
384             context->translate(-scrollX, -scrollY);
385             rect.translate(scrollX, scrollY);
386             context->clip(view->visibleContentRect());
387
388             view->paintContents(context, rect);
389
390             context->restore();
391         }
392 #if USE(ACCELERATED_COMPOSITING) && USE(TEXTURE_MAPPER)
393         renderCompositedLayers(context, IntRect(clip.boundingRect()));
394 #endif
395     }
396     renderFrameExtras(context, layers, clip);
397 #if ENABLE(INSPECTOR)
398     if (frame->page()->inspectorController()->highlightedNode()) {
399         context->save();
400         frame->page()->inspectorController()->drawHighlight(*context);
401         context->restore();
402     }
403 #endif
404 }
405
406 void QWebFramePrivate::renderFrameExtras(GraphicsContext* context, QFlags<QWebFrame::RenderLayer> layers, const QRegion& clip)
407 {
408     if (!(layers & (QWebFrame::PanIconLayer | QWebFrame::ScrollBarLayer)))
409         return;
410     QPainter* painter = context->platformContext();
411     WebCore::FrameView* view = frame->view();
412     QVector<QRect> vector = clip.rects();
413     for (int i = 0; i < vector.size(); ++i) {
414         const QRect& clipRect = vector.at(i);
415
416         QRect intersectedRect = clipRect.intersected(view->frameRect());
417
418         painter->save();
419         painter->setClipRect(clipRect, Qt::IntersectClip);
420
421         int x = view->x();
422         int y = view->y();
423
424         if (layers & QWebFrame::ScrollBarLayer
425             && !view->scrollbarsSuppressed()
426             && (view->horizontalScrollbar() || view->verticalScrollbar())) {
427
428             QRect rect = intersectedRect;
429             context->translate(x, y);
430             rect.translate(-x, -y);
431             view->paintScrollbars(context, rect);
432             context->translate(-x, -y);
433         }
434
435 #if ENABLE(PAN_SCROLLING)
436         if (layers & QWebFrame::PanIconLayer)
437             view->paintPanScrollIcon(context);
438 #endif
439
440         painter->restore();
441     }
442 }
443
444 void QWebFramePrivate::emitUrlChanged()
445 {
446     url = frame->document()->url();
447     emit q->urlChanged(url);
448 }
449
450 void QWebFramePrivate::_q_orientationChanged()
451 {
452 #if ENABLE(ORIENTATION_EVENTS)
453     int orientation;
454     WebCore::Frame* frame = core(q);
455
456     switch (m_orientation.reading()->orientation()) {
457     case QtMobility::QOrientationReading::TopUp:
458         orientation = 0;
459         break;
460     case QtMobility::QOrientationReading::TopDown:
461         orientation = 180;
462         break;
463     case QtMobility::QOrientationReading::LeftUp:
464         orientation = -90;
465         break;
466     case QtMobility::QOrientationReading::RightUp:
467         orientation = 90;
468         break;
469     case QtMobility::QOrientationReading::FaceUp:
470     case QtMobility::QOrientationReading::FaceDown:
471         // WebCore unable to handle it
472     default:
473         return;
474     }
475     frame->sendOrientationChangeEvent(orientation);
476 #endif
477 }
478
479 void QWebFramePrivate::didClearWindowObject()
480 {
481 #if USE(JSC)
482     if (page->settings()->testAttribute(QWebSettings::JavascriptEnabled))
483         addQtSenderToGlobalObject();
484 #endif
485     emit q->javaScriptWindowObjectCleared();
486 }
487
488 #if USE(JSC)
489 static JSValueRef qtSenderCallback(JSContextRef context, JSObjectRef, JSObjectRef, size_t, const JSValueRef[], JSValueRef*)
490 {
491     QObject* sender = JSC::Bindings::QtInstance::qtSenderStack()->top();
492     if (!sender)
493         return JSValueMakeUndefined(context);
494
495     JSC::ExecState* exec = ::toJS(context);
496     RefPtr<JSC::Bindings::RootObject> rootObject = JSC::Bindings::findRootObject(exec->dynamicGlobalObject());
497     JSC::JSObject* jsSender = JSC::Bindings::QtInstance::getQtInstance(sender, rootObject, QScriptEngine::QtOwnership)->createRuntimeObject(exec);
498     return ::toRef(jsSender);
499 }
500
501 void QWebFramePrivate::addQtSenderToGlobalObject()
502 {
503     JSC::JSLock lock(JSC::SilenceAssertionsOnly);
504
505     JSDOMWindow* window = toJSDOMWindow(frame, mainThreadNormalWorld());
506     Q_ASSERT(window);
507
508     JSC::ExecState* exec = window->globalExec();
509     Q_ASSERT(exec);
510
511     JSContextRef context = ::toRef(exec);
512     JSRetainPtr<JSStringRef> propertyName(Adopt, JSStringCreateWithUTF8CString("__qt_sender__"));
513     JSObjectRef function = JSObjectMakeFunctionWithCallback(context, propertyName.get(), qtSenderCallback);
514
515     // JSC public API doesn't support setting a Getter for a property of a given object, https://bugs.webkit.org/show_bug.cgi?id=61374.
516     window->defineGetter(exec, propertyName.get()->identifier(&exec->globalData()), ::toJS(function),
517                          JSC::ReadOnly | JSC::DontEnum | JSC::DontDelete);
518 }
519 #endif
520
521 /*!
522     \class QWebFrame
523     \since 4.4
524     \brief The QWebFrame class represents a frame in a web page.
525
526     \inmodule QtWebKit
527
528     QWebFrame represents a frame inside a web page. Each QWebPage
529     object contains at least one frame, the main frame, obtained using
530     QWebPage::mainFrame(). Additional frames will be created for HTML
531     \c{<frame>} or \c{<iframe>} elements.
532
533     A frame can be loaded using load() or setUrl(). Alternatively, if you have
534     the HTML content readily available, you can use setHtml() instead.
535
536     The page() function returns a pointer to the web page object. See
537     \l{QWebView}{Elements of QWebView} for an explanation of how web
538     frames are related to a web page and web view.
539
540     The QWebFrame class also offers methods to retrieve both the URL currently
541     loaded by the frame (see url()) as well as the URL originally requested
542     to be loaded (see requestedUrl()). These methods make possible the retrieval
543     of the URL before and after a DNS resolution or a redirection occurs during
544     the load process. The requestedUrl() also matches to the URL added to the
545     frame history (\l{QWebHistory}) if load is successful.
546
547     The title of an HTML frame can be accessed with the title() property.
548     Additionally, a frame may also specify an icon, which can be accessed
549     using the icon() property. If the title or the icon changes, the
550     corresponding titleChanged() and iconChanged() signals will be emitted.
551     The zoomFactor() property can be used to change the overall size
552     of the content displayed in the frame.
553
554     QWebFrame objects are created and controlled by the web page. You
555     can connect to the web page's \l{QWebPage::}{frameCreated()} signal
556     to be notified when a new frame is created.
557
558     There are multiple ways to programmatically examine the contents of a frame.
559     The hitTestContent() function can be used to find elements by coordinate.
560     For access to the underlying DOM tree, there is documentElement(),
561     findAllElements() and findFirstElement().
562
563     A QWebFrame can be printed onto a QPrinter using the print() function.
564     This function is marked as a slot and can be conveniently connected to
565     \l{QPrintPreviewDialog}'s \l{QPrintPreviewDialog::}{paintRequested()}
566     signal.
567
568     \sa QWebPage
569 */
570
571 /*!
572     \enum QWebFrame::RenderLayer
573
574     This enum describes the layers available for rendering using \l{QWebFrame::}{render()}.
575     The layers can be OR-ed together from the following list:
576
577     \value ContentsLayer The web content of the frame
578     \value ScrollBarLayer The scrollbars of the frame
579     \value PanIconLayer The icon used when panning the frame
580
581     \value AllLayers Includes all the above layers
582 */
583
584 QWebFrame::QWebFrame(QWebPage *parent, QWebFrameData *frameData)
585     : QObject(parent)
586     , d(new QWebFramePrivate)
587 {
588     d->page = parent;
589     d->init(this, frameData);
590
591     if (!frameData->url.isEmpty()) {
592         WebCore::ResourceRequest request(frameData->url, frameData->referrer);
593         d->frame->loader()->load(request, frameData->name, false);
594     }
595 #if ENABLE(ORIENTATION_EVENTS)
596     connect(&d->m_orientation, SIGNAL(readingChanged()), this, SLOT(_q_orientationChanged()));
597     d->m_orientation.start();
598 #endif
599 }
600
601 QWebFrame::QWebFrame(QWebFrame *parent, QWebFrameData *frameData)
602     : QObject(parent)
603     , d(new QWebFramePrivate)
604 {
605     d->page = parent->d->page;
606     d->init(this, frameData);
607 #if ENABLE(ORIENTATION_EVENTS)
608     connect(&d->m_orientation, SIGNAL(readingChanged()), this, SLOT(_q_orientationChanged()));
609     d->m_orientation.start();
610 #endif
611 }
612
613 QWebFrame::~QWebFrame()
614 {
615     if (d->frame && d->frame->loader() && d->frame->loader()->client())
616         static_cast<FrameLoaderClientQt*>(d->frame->loader()->client())->m_webFrame = 0;
617
618     delete d;
619 }
620
621 /*!
622     Make \a object available under \a name from within the frame's JavaScript
623     context. The \a object will be inserted as a child of the frame's window
624     object.
625
626     Qt properties will be exposed as JavaScript properties and slots as
627     JavaScript methods.
628     The interaction between C++ and JavaScript is explained in the documentation of the \l{The QtWebKit Bridge}{QtWebKit bridge}.
629
630     If you want to ensure that your QObjects remain accessible after loading a
631     new URL, you should add them in a slot connected to the
632     javaScriptWindowObjectCleared() signal.
633
634     If Javascript is not enabled for this page, then this method does nothing.
635
636     The \a object will never be explicitly deleted by QtWebKit.
637 */
638 void QWebFrame::addToJavaScriptWindowObject(const QString &name, QObject *object)
639 {
640     addToJavaScriptWindowObject(name, object, QScriptEngine::QtOwnership);
641 }
642
643 /*!
644     \fn void QWebFrame::addToJavaScriptWindowObject(const QString &name, QObject *object, QScriptEngine::ValueOwnership own)
645     \overload
646
647     Make \a object available under \a name from within the frame's JavaScript
648     context. The \a object will be inserted as a child of the frame's window
649     object.
650
651     Qt properties will be exposed as JavaScript properties and slots as
652     JavaScript methods.
653     The interaction between C++ and JavaScript is explained in the documentation of the \l{The QtWebKit Bridge}{QtWebKit bridge}.
654
655     If you want to ensure that your QObjects remain accessible after loading a
656     new URL, you should add them in a slot connected to the
657     javaScriptWindowObjectCleared() signal.
658
659     If Javascript is not enabled for this page, then this method does nothing.
660
661     The ownership of \a object is specified using \a own.
662 */
663 void QWebFrame::addToJavaScriptWindowObject(const QString &name, QObject *object, QScriptEngine::ValueOwnership ownership)
664 {
665     if (!page()->settings()->testAttribute(QWebSettings::JavascriptEnabled))
666         return;
667 #if USE(JSC)
668     JSC::JSLock lock(JSC::SilenceAssertionsOnly);
669     JSDOMWindow* window = toJSDOMWindow(d->frame, mainThreadNormalWorld());
670     JSC::Bindings::RootObject* root;
671     if (ownership == QScriptEngine::QtOwnership)
672         root = d->frame->script()->cacheableBindingRootObject();
673     else
674         root = d->frame->script()->bindingRootObject();
675
676     if (!window) {
677         qDebug() << "Warning: couldn't get window object";
678         return;
679     }
680     if (!root) {
681         qDebug() << "Warning: couldn't get root object";
682         return;
683     }
684
685     JSC::ExecState* exec = window->globalExec();
686
687     JSC::JSObject* runtimeObject =
688             JSC::Bindings::QtInstance::getQtInstance(object, root, ownership)->createRuntimeObject(exec);
689
690     JSC::PutPropertySlot slot;
691     window->put(exec, JSC::Identifier(exec, reinterpret_cast_ptr<const UChar*>(name.constData()), name.length()), runtimeObject, slot);
692 #elif USE(V8)
693     QScriptEngine* engine = d->frame->script()->qtScriptEngine();
694     if (!engine)
695         return;
696     QScriptValue v = engine->newQObject(object, ownership);
697     engine->globalObject().property(QLatin1String("window")).setProperty(name, v);
698 #endif
699 }
700
701 /*!
702     Returns the frame's content as HTML, enclosed in HTML and BODY tags.
703
704     \sa setHtml(), toPlainText()
705 */
706 QString QWebFrame::toHtml() const
707 {
708     if (!d->frame->document())
709         return QString();
710     return createMarkup(d->frame->document());
711 }
712
713 /*!
714     Returns the content of this frame converted to plain text, completely
715     stripped of all HTML formatting.
716
717     \sa toHtml()
718 */
719 QString QWebFrame::toPlainText() const
720 {
721     if (d->frame->view() && d->frame->view()->layoutPending())
722         d->frame->view()->layout();
723
724     Element *documentElement = d->frame->document()->documentElement();
725     if (documentElement)
726         return documentElement->innerText();
727     return QString();
728 }
729
730 /*!
731     Returns a dump of the rendering tree. This is mainly useful for debugging
732     html.
733 */
734 QString QWebFrame::renderTreeDump() const
735 {
736     if (d->frame->view() && d->frame->view()->layoutPending())
737         d->frame->view()->layout();
738
739     return externalRepresentation(d->frame);
740 }
741
742 /*!
743     \property QWebFrame::title
744     \brief the title of the frame as defined by the HTML &lt;title&gt; element
745
746     \sa titleChanged()
747 */
748
749 QString QWebFrame::title() const
750 {
751     if (d->frame->document())
752         return d->frame->loader()->documentLoader()->title().string();
753     return QString();
754 }
755
756 /*!
757     \since 4.5
758     \brief Returns the meta data in this frame as a QMultiMap
759
760     The meta data consists of the name and content attributes of the
761     of the \c{<meta>} tags in the HTML document.
762
763     For example:
764
765     \code
766     <html>
767         <head>
768             <meta name="description" content="This document is a tutorial about Qt development">
769             <meta name="keywords" content="Qt, WebKit, Programming">
770         </head>
771         ...
772     </html>
773     \endcode
774
775     Given the above HTML code the metaData() function will return a map with two entries:
776     \table
777     \header \o Key
778             \o Value
779     \row    \o "description"
780             \o "This document is a tutorial about Qt development"
781     \row    \o "keywords"
782             \o "Qt, WebKit, Programming"
783     \endtable
784
785     This function returns a multi map to support multiple meta tags with the same attribute name.
786 */
787 QMultiMap<QString, QString> QWebFrame::metaData() const
788 {
789     if (!d->frame->document())
790        return QMap<QString, QString>();
791
792     QMultiMap<QString, QString> map;
793     Document* doc = d->frame->document();
794     RefPtr<NodeList> list = doc->getElementsByTagName("meta");
795     unsigned len = list->length();
796     for (unsigned i = 0; i < len; i++) {
797         HTMLMetaElement* meta = static_cast<HTMLMetaElement*>(list->item(i));
798         map.insert(meta->name(), meta->content());
799     }
800     return map;
801 }
802
803 static inline void clearCoreFrame(WebCore::Frame* frame)
804 {
805     WebCore::DocumentLoader* documentLoader = frame->loader()->activeDocumentLoader();
806     Q_ASSERT(documentLoader);
807     documentLoader->writer()->begin();
808     documentLoader->writer()->end();
809 }
810
811 static inline bool isCoreFrameClear(WebCore::Frame* frame)
812 {
813     return frame->document()->url().isEmpty();
814 }
815
816 static inline QUrl ensureAbsoluteUrl(const QUrl &url)
817 {
818     if (!url.isValid() || !url.isRelative())
819         return url;
820
821     // This contains the URL with absolute path but without 
822     // the query and the fragment part.
823     QUrl baseUrl = QUrl::fromLocalFile(QFileInfo(url.toLocalFile()).absoluteFilePath()); 
824
825     // The path is removed so the query and the fragment parts are there.
826     QString pathRemoved = url.toString(QUrl::RemovePath);
827     QUrl toResolve(pathRemoved);
828     
829     return baseUrl.resolved(toResolve);
830 }
831
832 /*!
833     \property QWebFrame::url
834     \brief the url of the frame currently viewed
835
836     Setting this property clears the view and loads the URL.
837
838     By default, this property contains an empty, invalid URL.
839
840     \sa urlChanged()
841 */
842
843 void QWebFrame::setUrl(const QUrl &url)
844 {
845     clearCoreFrame(d->frame);
846     const QUrl absolute = ensureAbsoluteUrl(url);
847     d->url = absolute;
848     load(absolute);
849 }
850
851 QUrl QWebFrame::url() const
852 {
853     return d->url;
854 }
855
856 /*!
857     \since 4.6
858     \property QWebFrame::requestedUrl
859
860     The URL requested to loaded by the frame currently viewed. The URL may differ from
861     the one returned by url() if a DNS resolution or a redirection occurs.
862
863     \sa url(), setUrl()
864 */
865 QUrl QWebFrame::requestedUrl() const
866 {
867     return d->frameLoaderClient->lastRequestedUrl();
868 }
869 /*!
870     \since 4.6
871     \property QWebFrame::baseUrl
872     \brief the base URL of the frame, can be used to resolve relative URLs
873     \since 4.6
874 */
875
876 QUrl QWebFrame::baseUrl() const
877 {
878     if (isCoreFrameClear(d->frame))
879         return QUrl(d->url).resolved(QUrl());
880     return d->frame->document()->baseURL();
881 }
882
883 /*!
884     \property QWebFrame::icon
885     \brief the icon associated with this frame
886
887     \sa iconChanged(), QWebSettings::iconForUrl()
888 */
889
890 QIcon QWebFrame::icon() const
891 {
892     return QWebSettings::iconForUrl(d->frame->document()->url());
893 }
894
895 /*!
896   The name of this frame as defined by the parent frame.
897 */
898 QString QWebFrame::frameName() const
899 {
900     return d->frame->tree()->uniqueName();
901 }
902
903 /*!
904   The web page that contains this frame.
905
906   \sa pageChanged()
907 */
908 QWebPage *QWebFrame::page() const
909 {
910     return d->page;
911 }
912
913 /*!
914   Loads \a url into this frame.
915
916   \note The view remains the same until enough data has arrived to display the new \a url.
917
918   \sa setUrl(), setHtml(), setContent()
919 */
920 void QWebFrame::load(const QUrl &url)
921 {
922     // The load() overload ensures that the url is absolute.
923     load(QNetworkRequest(url));
924 }
925
926 /*!
927   Loads a network request, \a req, into this frame, using the method specified in \a
928   operation.
929
930   \a body is optional and is only used for POST operations.
931
932   \note The view remains the same until enough data has arrived to display the new content.
933
934   \sa setUrl()
935 */
936 void QWebFrame::load(const QNetworkRequest &req,
937                      QNetworkAccessManager::Operation operation,
938                      const QByteArray &body)
939 {
940     if (d->parentFrame())
941         d->page->d->insideOpenCall = true;
942
943     QUrl url = ensureAbsoluteUrl(req.url());
944
945     WebCore::ResourceRequest request(url);
946
947     switch (operation) {
948         case QNetworkAccessManager::HeadOperation:
949             request.setHTTPMethod("HEAD");
950             break;
951         case QNetworkAccessManager::GetOperation:
952             request.setHTTPMethod("GET");
953             break;
954         case QNetworkAccessManager::PutOperation:
955             request.setHTTPMethod("PUT");
956             break;
957         case QNetworkAccessManager::PostOperation:
958             request.setHTTPMethod("POST");
959             break;
960         case QNetworkAccessManager::DeleteOperation:
961             request.setHTTPMethod("DELETE");
962             break;
963         case QNetworkAccessManager::CustomOperation:
964             request.setHTTPMethod(req.attribute(QNetworkRequest::CustomVerbAttribute).toByteArray().constData());
965             break;
966         case QNetworkAccessManager::UnknownOperation:
967             // eh?
968             break;
969     }
970
971     QVariant cacheLoad = req.attribute(QNetworkRequest::CacheLoadControlAttribute);
972     if (cacheLoad.isValid()) {
973         bool ok;
974         uint cacheLoadValue = cacheLoad.toUInt(&ok);
975         if (ok)
976             request.setCachePolicy(cacheLoadControlToCachePolicy(cacheLoadValue));
977     }
978
979     QList<QByteArray> httpHeaders = req.rawHeaderList();
980     for (int i = 0; i < httpHeaders.size(); ++i) {
981         const QByteArray &headerName = httpHeaders.at(i);
982         request.addHTTPHeaderField(QString::fromLatin1(headerName), QString::fromLatin1(req.rawHeader(headerName)));
983     }
984
985     if (!body.isEmpty())
986         request.setHTTPBody(WebCore::FormData::create(body.constData(), body.size()));
987
988     d->frame->loader()->load(request, false);
989
990     if (d->parentFrame())
991         d->page->d->insideOpenCall = false;
992 }
993
994 /*!
995   Sets the content of this frame to \a html. \a baseUrl is optional and used to resolve relative
996   URLs in the document, such as referenced images or stylesheets.
997
998   The \a html is loaded immediately; external objects are loaded asynchronously.
999
1000   If a script in the \a html runs longer than the default script timeout (currently 10 seconds),
1001   for example due to being blocked by a modal JavaScript alert dialog, this method will return
1002   as soon as possible after the timeout and any subsequent \a html will be loaded asynchronously.
1003
1004   When using this method WebKit assumes that external resources such as JavaScript programs or style
1005   sheets are encoded in UTF-8 unless otherwise specified. For example, the encoding of an external
1006   script can be specified through the charset attribute of the HTML script tag. It is also possible
1007   for the encoding to be specified by web server.
1008
1009   This is a convenience function equivalent to setContent(html, "text/html", baseUrl).
1010
1011   \note This method will not affect session or global history for the frame.
1012
1013   \warning This function works only for HTML, for other mime types (i.e. XHTML, SVG)
1014   setContent() should be used instead.
1015
1016   \sa toHtml(), setContent(), load()
1017 */
1018 void QWebFrame::setHtml(const QString &html, const QUrl &baseUrl)
1019 {
1020     KURL kurl(baseUrl);
1021     WebCore::ResourceRequest request(kurl);
1022     const QByteArray utf8 = html.toUtf8();
1023     WTF::RefPtr<WebCore::SharedBuffer> data = WebCore::SharedBuffer::create(utf8.constData(), utf8.length());
1024     WebCore::SubstituteData substituteData(data, WTF::String("text/html"), WTF::String("utf-8"), KURL());
1025     d->frame->loader()->load(request, substituteData, false);
1026 }
1027
1028 /*!
1029   Sets the content of this frame to the specified content \a data. If the \a mimeType argument
1030   is empty it is currently assumed that the content is HTML but in future versions we may introduce
1031   auto-detection.
1032
1033   External objects referenced in the content are located relative to \a baseUrl.
1034
1035   The \a data is loaded immediately; external objects are loaded asynchronously.
1036
1037   \note This method will not affect session or global history for the frame.
1038
1039   \sa toHtml(), setHtml()
1040 */
1041 void QWebFrame::setContent(const QByteArray &data, const QString &mimeType, const QUrl &baseUrl)
1042 {
1043     KURL kurl(baseUrl);
1044     WebCore::ResourceRequest request(kurl);
1045     WTF::RefPtr<WebCore::SharedBuffer> buffer = WebCore::SharedBuffer::create(data.constData(), data.length());
1046     QString actualMimeType;
1047     WTF::String encoding;
1048     if (mimeType.isEmpty())
1049         actualMimeType = QLatin1String("text/html");
1050     else {
1051         actualMimeType = extractMIMETypeFromMediaType(mimeType);
1052         encoding = extractCharsetFromMediaType(mimeType);
1053     }
1054     WebCore::SubstituteData substituteData(buffer, WTF::String(actualMimeType), encoding, KURL());
1055     d->frame->loader()->load(request, substituteData, false);
1056 }
1057
1058 /*!
1059   Returns the parent frame of this frame, or 0 if the frame is the web pages
1060   main frame.
1061
1062   This is equivalent to qobject_cast<QWebFrame*>(frame->parent()).
1063
1064   \sa childFrames()
1065 */
1066 QWebFrame *QWebFrame::parentFrame() const
1067 {
1068     return d->parentFrame();
1069 }
1070
1071 /*!
1072   Returns a list of all frames that are direct children of this frame.
1073
1074   \sa parentFrame()
1075 */
1076 QList<QWebFrame*> QWebFrame::childFrames() const
1077 {
1078     QList<QWebFrame*> rc;
1079     if (d->frame) {
1080         FrameTree *tree = d->frame->tree();
1081         for (Frame *child = tree->firstChild(); child; child = child->tree()->nextSibling()) {
1082             FrameLoader *loader = child->loader();
1083             QWebFrame* webFrame = qobject_cast<QWebFrame*>(loader->networkingContext()->originatingObject());
1084             if (webFrame)
1085                 rc.append(webFrame);
1086         }
1087
1088     }
1089     return rc;
1090 }
1091
1092 /*!
1093     Returns the scrollbar policy for the scrollbar defined by \a orientation.
1094 */
1095 Qt::ScrollBarPolicy QWebFrame::scrollBarPolicy(Qt::Orientation orientation) const
1096 {
1097     if (orientation == Qt::Horizontal)
1098         return d->horizontalScrollBarPolicy;
1099     return d->verticalScrollBarPolicy;
1100 }
1101
1102 /*!
1103     Sets the scrollbar policy for the scrollbar defined by \a orientation to \a policy.
1104 */
1105 void QWebFrame::setScrollBarPolicy(Qt::Orientation orientation, Qt::ScrollBarPolicy policy)
1106 {
1107     Q_ASSERT((int)ScrollbarAuto == (int)Qt::ScrollBarAsNeeded);
1108     Q_ASSERT((int)ScrollbarAlwaysOff == (int)Qt::ScrollBarAlwaysOff);
1109     Q_ASSERT((int)ScrollbarAlwaysOn == (int)Qt::ScrollBarAlwaysOn);
1110
1111     if (orientation == Qt::Horizontal) {
1112         d->horizontalScrollBarPolicy = policy;
1113         if (d->frame->view()) {
1114             d->frame->view()->setHorizontalScrollbarMode((ScrollbarMode)policy, policy != Qt::ScrollBarAsNeeded /* lock */);
1115             d->frame->view()->updateCanHaveScrollbars();
1116         }
1117     } else {
1118         d->verticalScrollBarPolicy = policy;
1119         if (d->frame->view()) {
1120             d->frame->view()->setVerticalScrollbarMode((ScrollbarMode)policy, policy != Qt::ScrollBarAsNeeded /* lock */);
1121             d->frame->view()->updateCanHaveScrollbars();
1122         }
1123     }
1124 }
1125
1126 /*!
1127   Sets the current \a value for the scrollbar with orientation \a orientation.
1128
1129   The scrollbar forces the \a value to be within the legal range: minimum <= value <= maximum.
1130
1131   Changing the value also updates the thumb position.
1132
1133   \sa scrollBarMinimum(), scrollBarMaximum()
1134 */
1135 void QWebFrame::setScrollBarValue(Qt::Orientation orientation, int value)
1136 {
1137     Scrollbar *sb;
1138     sb = (orientation == Qt::Horizontal) ? d->horizontalScrollBar() : d->verticalScrollBar();
1139     if (sb) {
1140         if (value < 0)
1141             value = 0;
1142         else if (value > scrollBarMaximum(orientation))
1143             value = scrollBarMaximum(orientation);
1144         sb->scrollableArea()->scrollToOffsetWithoutAnimation(orientation == Qt::Horizontal ? HorizontalScrollbar : VerticalScrollbar, value);
1145     }
1146 }
1147
1148 /*!
1149   Returns the current value for the scrollbar with orientation \a orientation, or 0
1150   if no scrollbar is found for \a orientation.
1151
1152   \sa scrollBarMinimum(), scrollBarMaximum()
1153 */
1154 int QWebFrame::scrollBarValue(Qt::Orientation orientation) const
1155 {
1156     Scrollbar *sb;
1157     sb = (orientation == Qt::Horizontal) ? d->horizontalScrollBar() : d->verticalScrollBar();
1158     if (sb)
1159         return sb->value();
1160     return 0;
1161 }
1162
1163 /*!
1164   Returns the maximum value for the scrollbar with orientation \a orientation, or 0
1165   if no scrollbar is found for \a orientation.
1166
1167   \sa scrollBarMinimum()
1168 */
1169 int QWebFrame::scrollBarMaximum(Qt::Orientation orientation) const
1170 {
1171     Scrollbar *sb;
1172     sb = (orientation == Qt::Horizontal) ? d->horizontalScrollBar() : d->verticalScrollBar();
1173     if (sb)
1174         return sb->maximum();
1175     return 0;
1176 }
1177
1178 /*!
1179   Returns the minimum value for the scrollbar with orientation \a orientation.
1180
1181   The minimum value is always 0.
1182
1183   \sa scrollBarMaximum()
1184 */
1185 int QWebFrame::scrollBarMinimum(Qt::Orientation orientation) const
1186 {
1187     Q_UNUSED(orientation)
1188     return 0;
1189 }
1190
1191 /*!
1192   \since 4.6
1193   Returns the geometry for the scrollbar with orientation \a orientation.
1194
1195   If the scrollbar does not exist an empty rect is returned.
1196 */
1197 QRect QWebFrame::scrollBarGeometry(Qt::Orientation orientation) const
1198 {
1199     Scrollbar *sb;
1200     sb = (orientation == Qt::Horizontal) ? d->horizontalScrollBar() : d->verticalScrollBar();
1201     if (sb)
1202         return sb->frameRect();
1203     return QRect();
1204 }
1205
1206 /*!
1207   \since 4.5
1208   Scrolls the frame \a dx pixels to the right and \a dy pixels downward. Both
1209   \a dx and \a dy may be negative.
1210
1211   \sa QWebFrame::scrollPosition
1212 */
1213
1214 void QWebFrame::scroll(int dx, int dy)
1215 {
1216     if (!d->frame->view())
1217         return;
1218
1219     d->frame->view()->scrollBy(IntSize(dx, dy));
1220 }
1221
1222 /*!
1223   \property QWebFrame::scrollPosition
1224   \since 4.5
1225   \brief the position the frame is currently scrolled to.
1226 */
1227
1228 QPoint QWebFrame::scrollPosition() const
1229 {
1230     if (!d->frame->view())
1231         return QPoint(0, 0);
1232
1233     IntSize ofs = d->frame->view()->scrollOffset();
1234     return QPoint(ofs.width(), ofs.height());
1235 }
1236
1237 void QWebFrame::setScrollPosition(const QPoint &pos)
1238 {
1239     QPoint current = scrollPosition();
1240     int dx = pos.x() - current.x();
1241     int dy = pos.y() - current.y();
1242     scroll(dx, dy);
1243 }
1244
1245 /*!
1246   \since 4.7
1247   Scrolls the frame to the given \a anchor name.
1248 */
1249 void QWebFrame::scrollToAnchor(const QString& anchor)
1250 {
1251     FrameView *view = d->frame->view();
1252     if (view)
1253         view->scrollToAnchor(anchor);
1254 }
1255
1256 /*!
1257   \since 4.6
1258   Render the \a layer of the frame using \a painter clipping to \a clip.
1259
1260   \sa print()
1261 */
1262
1263 void QWebFrame::render(QPainter* painter, RenderLayer layer, const QRegion& clip)
1264 {
1265     GraphicsContext context(painter);
1266     if (context.paintingDisabled() && !context.updatingControlTints())
1267         return;
1268
1269     if (!clip.isEmpty())
1270         d->renderRelativeCoords(&context, layer, clip);
1271     else if (d->frame->view())
1272         d->renderRelativeCoords(&context, layer, QRegion(d->frame->view()->frameRect()));
1273 }
1274
1275 /*!
1276   Render the frame into \a painter clipping to \a clip.
1277 */
1278 void QWebFrame::render(QPainter* painter, const QRegion& clip)
1279 {
1280     GraphicsContext context(painter);
1281     if (context.paintingDisabled() && !context.updatingControlTints())
1282         return;
1283
1284     d->renderRelativeCoords(&context, AllLayers, clip);
1285 }
1286
1287 /*!
1288   Render the frame into \a painter.
1289 */
1290 void QWebFrame::render(QPainter* painter)
1291 {
1292     if (!d->frame->view())
1293         return;
1294
1295     GraphicsContext context(painter);
1296     if (context.paintingDisabled() && !context.updatingControlTints())
1297         return;
1298
1299     d->renderRelativeCoords(&context, AllLayers, QRegion(d->frame->view()->frameRect()));
1300 }
1301
1302 /*!
1303     \property QWebFrame::textSizeMultiplier
1304     \brief the scaling factor for all text in the frame
1305     \obsolete
1306
1307     Use setZoomFactor instead, in combination with the ZoomTextOnly attribute in
1308     QWebSettings.
1309
1310     \note Setting this property also enables the ZoomTextOnly attribute in
1311     QWebSettings.
1312 */
1313
1314 /*!
1315     Sets the value of the multiplier used to scale the text in a Web frame to
1316     the \a factor specified.
1317 */
1318 void QWebFrame::setTextSizeMultiplier(qreal factor)
1319 {
1320     page()->settings()->setAttribute(QWebSettings::ZoomTextOnly, true);
1321
1322     d->frame->setPageAndTextZoomFactors(1, factor);
1323 }
1324
1325 /*!
1326     Returns the value of the multiplier used to scale the text in a Web frame.
1327 */
1328 qreal QWebFrame::textSizeMultiplier() const
1329 {
1330     return page()->settings()->testAttribute(QWebSettings::ZoomTextOnly) ? d->frame->textZoomFactor() : d->frame->pageZoomFactor();
1331 }
1332
1333 /*!
1334     \property QWebFrame::zoomFactor
1335     \since 4.5
1336     \brief the zoom factor for the frame
1337 */
1338
1339 void QWebFrame::setZoomFactor(qreal factor)
1340 {
1341     if (page()->settings()->testAttribute(QWebSettings::ZoomTextOnly))
1342         d->frame->setTextZoomFactor(factor);
1343     else
1344         d->frame->setPageZoomFactor(factor);
1345 }
1346
1347 qreal QWebFrame::zoomFactor() const
1348 {
1349     return page()->settings()->testAttribute(QWebSettings::ZoomTextOnly) ? d->frame->textZoomFactor() : d->frame->pageZoomFactor();
1350 }
1351
1352 /*!
1353     \property QWebFrame::focus
1354     \since 4.6
1355
1356     Returns true if this frame has keyboard input focus; otherwise, returns false.
1357 */
1358 bool QWebFrame::hasFocus() const
1359 {
1360     WebCore::Frame* ff = d->frame->page()->focusController()->focusedFrame();
1361     return ff && QWebFramePrivate::kit(ff) == this;
1362 }
1363
1364 /*!
1365     \since 4.6
1366
1367     Gives keyboard input focus to this frame.
1368 */
1369 void QWebFrame::setFocus()
1370 {
1371     QWebFramePrivate::core(this)->page()->focusController()->setFocusedFrame(QWebFramePrivate::core(this));
1372 }
1373
1374 /*!
1375     Returns the position of the frame relative to it's parent frame.
1376 */
1377 QPoint QWebFrame::pos() const
1378 {
1379     if (!d->frame->view())
1380         return QPoint();
1381
1382     return d->frame->view()->frameRect().location();
1383 }
1384
1385 /*!
1386     Return the geometry of the frame relative to it's parent frame.
1387 */
1388 QRect QWebFrame::geometry() const
1389 {
1390     if (!d->frame->view())
1391         return QRect();
1392     return d->frame->view()->frameRect();
1393 }
1394
1395 /*!
1396     \property QWebFrame::contentsSize
1397     \brief the size of the contents in this frame
1398
1399     \sa contentsSizeChanged()
1400 */
1401 QSize QWebFrame::contentsSize() const
1402 {
1403     FrameView *view = d->frame->view();
1404     if (!view)
1405         return QSize();
1406     return QSize(view->contentsWidth(), view->contentsHeight());
1407 }
1408
1409 /*!
1410     \since 4.6
1411
1412     Returns the document element of this frame.
1413
1414     The document element provides access to the entire structured
1415     content of the frame.
1416 */
1417 QWebElement QWebFrame::documentElement() const
1418 {
1419     WebCore::Document *doc = d->frame->document();
1420     if (!doc)
1421         return QWebElement();
1422     return QWebElement(doc->documentElement());
1423 }
1424
1425 /*!
1426     \since 4.6
1427     Returns a new list of elements matching the given CSS selector \a selectorQuery.
1428     If there are no matching elements, an empty list is returned.
1429
1430     \l{http://www.w3.org/TR/REC-CSS2/selector.html#q1}{Standard CSS2 selector} syntax is
1431     used for the query.
1432
1433     \sa QWebElement::findAll()
1434 */
1435 QWebElementCollection QWebFrame::findAllElements(const QString &selectorQuery) const
1436 {
1437     return documentElement().findAll(selectorQuery);
1438 }
1439
1440 /*!
1441     \since 4.6
1442     Returns the first element in the frame's document that matches the
1443     given CSS selector \a selectorQuery. If there is no matching element, a
1444     null element is returned.
1445
1446     \l{http://www.w3.org/TR/REC-CSS2/selector.html#q1}{Standard CSS2 selector} syntax is
1447     used for the query.
1448
1449     \sa QWebElement::findFirst()
1450 */
1451 QWebElement QWebFrame::findFirstElement(const QString &selectorQuery) const
1452 {
1453     return documentElement().findFirst(selectorQuery);
1454 }
1455
1456 /*!
1457     Performs a hit test on the frame contents at the given position \a pos and returns the hit test result.
1458 */
1459 QWebHitTestResult QWebFrame::hitTestContent(const QPoint &pos) const
1460 {
1461     if (!d->frame->view() || !d->frame->contentRenderer())
1462         return QWebHitTestResult();
1463
1464     HitTestResult result = d->frame->eventHandler()->hitTestResultAtPoint(d->frame->view()->windowToContents(pos), /*allowShadowContent*/ false, /*ignoreClipping*/ true);
1465
1466     if (result.scrollbar())
1467         return QWebHitTestResult();
1468
1469     return QWebHitTestResult(new QWebHitTestResultPrivate(result));
1470 }
1471
1472 /*! \reimp
1473 */
1474 bool QWebFrame::event(QEvent *e)
1475 {
1476     return QObject::event(e);
1477 }
1478
1479 #ifndef QT_NO_PRINTER
1480 /*!
1481     Prints the frame to the given \a printer.
1482
1483     \sa render()
1484 */
1485 void QWebFrame::print(QPrinter *printer) const
1486 {
1487     QPainter painter;
1488     if (!painter.begin(printer))
1489         return;
1490
1491     const qreal zoomFactorX = (qreal)printer->logicalDpiX() / qt_defaultDpi();
1492     const qreal zoomFactorY = (qreal)printer->logicalDpiY() / qt_defaultDpi();
1493
1494     PrintContext printContext(d->frame);
1495     float pageHeight = 0;
1496
1497     QRect qprinterRect = printer->pageRect();
1498
1499     IntRect pageRect(0, 0,
1500                      int(qprinterRect.width() / zoomFactorX),
1501                      int(qprinterRect.height() / zoomFactorY));
1502
1503     printContext.begin(pageRect.width());
1504
1505     printContext.computePageRects(pageRect, /* headerHeight */ 0, /* footerHeight */ 0, /* userScaleFactor */ 1.0, pageHeight);
1506
1507     int docCopies;
1508     int pageCopies;
1509     if (printer->collateCopies()) {
1510         docCopies = 1;
1511         pageCopies = printer->numCopies();
1512     } else {
1513         docCopies = printer->numCopies();
1514         pageCopies = 1;
1515     }
1516
1517     int fromPage = printer->fromPage();
1518     int toPage = printer->toPage();
1519     bool ascending = true;
1520
1521     if (fromPage == 0 && toPage == 0) {
1522         fromPage = 1;
1523         toPage = printContext.pageCount();
1524     }
1525     // paranoia check
1526     fromPage = qMax(1, fromPage);
1527     toPage = qMin(static_cast<int>(printContext.pageCount()), toPage);
1528     if (toPage < fromPage) {
1529         // if the user entered a page range outside the actual number
1530         // of printable pages, just return
1531         return;
1532     }
1533
1534     if (printer->pageOrder() == QPrinter::LastPageFirst) {
1535         int tmp = fromPage;
1536         fromPage = toPage;
1537         toPage = tmp;
1538         ascending = false;
1539     }
1540
1541     painter.scale(zoomFactorX, zoomFactorY);
1542     GraphicsContext ctx(&painter);
1543
1544     for (int i = 0; i < docCopies; ++i) {
1545         int page = fromPage;
1546         while (true) {
1547             for (int j = 0; j < pageCopies; ++j) {
1548                 if (printer->printerState() == QPrinter::Aborted
1549                     || printer->printerState() == QPrinter::Error) {
1550                     printContext.end();
1551                     return;
1552                 }
1553                 printContext.spoolPage(ctx, page - 1, pageRect.width());
1554                 if (j < pageCopies - 1)
1555                     printer->newPage();
1556             }
1557
1558             if (page == toPage)
1559                 break;
1560
1561             if (ascending)
1562                 ++page;
1563             else
1564                 --page;
1565
1566             printer->newPage();
1567         }
1568
1569         if ( i < docCopies - 1)
1570             printer->newPage();
1571     }
1572
1573     printContext.end();
1574 }
1575 #endif // QT_NO_PRINTER
1576
1577 /*!
1578     Evaluates the JavaScript defined by \a scriptSource using this frame as context
1579     and returns the result of the last executed statement.
1580
1581     \sa addToJavaScriptWindowObject(), javaScriptWindowObjectCleared()
1582 */
1583 QVariant QWebFrame::evaluateJavaScript(const QString& scriptSource)
1584 {
1585     ScriptController *proxy = d->frame->script();
1586     QVariant rc;
1587     if (proxy) {
1588 #if USE(JSC)
1589         int distance = 0;
1590         JSC::JSValue v = d->frame->script()->executeScript(ScriptSourceCode(scriptSource)).jsValue();
1591
1592         rc = JSC::Bindings::convertValueToQVariant(proxy->globalObject(mainThreadNormalWorld())->globalExec(), v, QMetaType::Void, &distance);
1593 #elif USE(V8)
1594         QScriptEngine* engine = d->frame->script()->qtScriptEngine();
1595         if (!engine)
1596             return rc;
1597         rc = engine->evaluate(scriptSource).toVariant();
1598 #endif
1599     }
1600     return rc;
1601 }
1602
1603 /*!
1604     \since 4.5
1605
1606     Returns the frame's security origin.
1607 */
1608 QWebSecurityOrigin QWebFrame::securityOrigin() const
1609 {
1610     QWebFrame* that = const_cast<QWebFrame*>(this);
1611     QWebSecurityOriginPrivate* priv = new QWebSecurityOriginPrivate(QWebFramePrivate::core(that)->document()->securityOrigin());
1612     return QWebSecurityOrigin(priv);
1613 }
1614
1615 WebCore::Frame* QWebFramePrivate::core(const QWebFrame* webFrame)
1616 {
1617     return webFrame->d->frame;
1618 }
1619
1620 QWebFrame* QWebFramePrivate::kit(const WebCore::Frame* coreFrame)
1621 {
1622     return qobject_cast<QWebFrame*>(coreFrame->loader()->networkingContext()->originatingObject());
1623 }
1624
1625
1626 /*!
1627     \fn void QWebFrame::javaScriptWindowObjectCleared()
1628
1629     This signal is emitted whenever the global window object of the JavaScript
1630     environment is cleared, e.g., before starting a new load.
1631
1632     If you intend to add QObjects to a QWebFrame using
1633     addToJavaScriptWindowObject(), you should add them in a slot connected
1634     to this signal. This ensures that your objects remain accessible when
1635     loading new URLs.
1636 */
1637
1638 /*!
1639     \fn void QWebFrame::provisionalLoad()
1640     \internal
1641 */
1642
1643 /*!
1644     \fn void QWebFrame::titleChanged(const QString &title)
1645
1646     This signal is emitted whenever the title of the frame changes.
1647     The \a title string specifies the new title.
1648
1649     \sa title()
1650 */
1651
1652 /*!
1653     \fn void QWebFrame::urlChanged(const QUrl &url)
1654
1655     This signal is emitted with the URL of the frame when the frame's title is
1656     received. The new URL is specified by \a url.
1657
1658     \sa url()
1659 */
1660
1661 /*!
1662     \fn void QWebFrame::initialLayoutCompleted()
1663
1664     This signal is emitted when the frame is laid out the first time.
1665     This is the first time you will see contents displayed on the frame.
1666
1667     \note A frame can be laid out multiple times.
1668 */
1669
1670 /*!
1671   \fn void QWebFrame::iconChanged()
1672
1673   This signal is emitted when the icon ("favicon") associated with the frame
1674   has been loaded.
1675
1676   \sa icon()
1677 */
1678
1679 /*!
1680   \fn void QWebFrame::contentsSizeChanged(const QSize &size)
1681   \since 4.6
1682
1683   This signal is emitted when the frame's contents size changes
1684   to \a size.
1685
1686   \sa contentsSize()
1687 */
1688
1689 /*!
1690     \fn void QWebFrame::loadStarted()
1691     \since 4.6
1692
1693     This signal is emitted when a new load of this frame is started.
1694
1695     \sa loadFinished()
1696 */
1697
1698 /*!
1699     \fn void QWebFrame::loadFinished(bool ok)
1700     \since 4.6
1701
1702     This signal is emitted when a load of this frame is finished.
1703     \a ok will indicate whether the load was successful or any error occurred.
1704
1705     \sa loadStarted()
1706 */
1707
1708 /*!
1709     \fn void QWebFrame::pageChanged()
1710     \since 4.7
1711
1712     This signal is emitted when this frame has been moved to a different QWebPage.
1713
1714     \sa page()
1715 */
1716
1717 /*!
1718     \class QWebHitTestResult
1719     \since 4.4
1720     \brief The QWebHitTestResult class provides information about the web
1721     page content after a hit test.
1722
1723     \inmodule QtWebKit
1724
1725     QWebHitTestResult is returned by QWebFrame::hitTestContent() to provide
1726     information about the content of the web page at the specified position.
1727 */
1728
1729 /*!
1730     \internal
1731 */
1732 QWebHitTestResult::QWebHitTestResult(QWebHitTestResultPrivate *priv)
1733     : d(priv)
1734 {
1735 }
1736
1737 QWebHitTestResultPrivate::QWebHitTestResultPrivate(const WebCore::HitTestResult &hitTest)
1738     : isContentEditable(false)
1739     , isContentSelected(false)
1740     , isScrollBar(false)
1741 {
1742     if (!hitTest.innerNode())
1743         return;
1744     pos = hitTest.point();
1745     WebCore::TextDirection dir;
1746     title = hitTest.title(dir);
1747     linkText = hitTest.textContent();
1748     linkUrl = hitTest.absoluteLinkURL();
1749     linkTitle = hitTest.titleDisplayString();
1750     alternateText = hitTest.altDisplayString();
1751     imageUrl = hitTest.absoluteImageURL();
1752     innerNode = hitTest.innerNode();
1753     innerNonSharedNode = hitTest.innerNonSharedNode();
1754     boundingRect = innerNonSharedNode ? innerNonSharedNode->renderer()->absoluteBoundingBoxRect(true) : IntRect();
1755     WebCore::Image *img = hitTest.image();
1756     if (img) {
1757         QPixmap *pix = img->nativeImageForCurrentFrame();
1758         if (pix)
1759             pixmap = *pix;
1760     }
1761     WebCore::Frame *wframe = hitTest.targetFrame();
1762     if (wframe)
1763         linkTargetFrame = QWebFramePrivate::kit(wframe);
1764     linkElement = QWebElement(hitTest.URLElement());
1765
1766     isContentEditable = hitTest.isContentEditable();
1767     isContentSelected = hitTest.isSelected();
1768     isScrollBar = hitTest.scrollbar();
1769
1770     if (innerNonSharedNode && innerNonSharedNode->document()
1771         && innerNonSharedNode->document()->frame())
1772         frame = QWebFramePrivate::kit(innerNonSharedNode->document()->frame());
1773
1774     enclosingBlock = QWebElement(WebCore::enclosingBlock(innerNode.get()));
1775 }
1776
1777 /*!
1778     Constructs a null hit test result.
1779 */
1780 QWebHitTestResult::QWebHitTestResult()
1781     : d(0)
1782 {
1783 }
1784
1785 /*!
1786     Constructs a hit test result from \a other.
1787 */
1788 QWebHitTestResult::QWebHitTestResult(const QWebHitTestResult &other)
1789     : d(0)
1790 {
1791     if (other.d)
1792         d = new QWebHitTestResultPrivate(*other.d);
1793 }
1794
1795 /*!
1796     Assigns the \a other hit test result to this.
1797 */
1798 QWebHitTestResult &QWebHitTestResult::operator=(const QWebHitTestResult &other)
1799 {
1800     if (this != &other) {
1801         if (other.d) {
1802             if (!d)
1803                 d = new QWebHitTestResultPrivate;
1804             *d = *other.d;
1805         } else {
1806             delete d;
1807             d = 0;
1808         }
1809     }
1810     return *this;
1811 }
1812
1813 /*!
1814     Destructor.
1815 */
1816 QWebHitTestResult::~QWebHitTestResult()
1817 {
1818     delete d;
1819 }
1820
1821 /*!
1822     Returns true if the hit test result is null; otherwise returns false.
1823 */
1824 bool QWebHitTestResult::isNull() const
1825 {
1826     return !d;
1827 }
1828
1829 /*!
1830     Returns the position where the hit test occured.
1831 */
1832 QPoint QWebHitTestResult::pos() const
1833 {
1834     if (!d)
1835         return QPoint();
1836     return d->pos;
1837 }
1838
1839 /*!
1840     \since 4.5
1841     Returns the bounding rect of the element.
1842 */
1843 QRect QWebHitTestResult::boundingRect() const
1844 {
1845     if (!d)
1846         return QRect();
1847     return d->boundingRect;
1848 }
1849
1850 /*!
1851     \since 4.6
1852     Returns the block element that encloses the element hit.
1853
1854     A block element is an element that is rendered using the
1855     CSS "block" style. This includes for example text
1856     paragraphs.
1857 */
1858 QWebElement QWebHitTestResult::enclosingBlockElement() const
1859 {
1860     if (!d)
1861         return QWebElement();
1862     return d->enclosingBlock;
1863 }
1864
1865 /*!
1866     Returns the title of the nearest enclosing HTML element.
1867 */
1868 QString QWebHitTestResult::title() const
1869 {
1870     if (!d)
1871         return QString();
1872     return d->title;
1873 }
1874
1875 /*!
1876     Returns the text of the link.
1877 */
1878 QString QWebHitTestResult::linkText() const
1879 {
1880     if (!d)
1881         return QString();
1882     return d->linkText;
1883 }
1884
1885 /*!
1886     Returns the url to which the link points to.
1887 */
1888 QUrl QWebHitTestResult::linkUrl() const
1889 {
1890     if (!d)
1891         return QUrl();
1892     return d->linkUrl;
1893 }
1894
1895 /*!
1896     Returns the title of the link.
1897 */
1898 QUrl QWebHitTestResult::linkTitle() const
1899 {
1900     if (!d)
1901         return QUrl();
1902     return d->linkTitle;
1903 }
1904
1905 /*!
1906   \since 4.6
1907   Returns the element that represents the link.
1908
1909   \sa linkTargetFrame()
1910 */
1911 QWebElement QWebHitTestResult::linkElement() const
1912 {
1913     if (!d)
1914         return QWebElement();
1915     return d->linkElement;
1916 }
1917
1918 /*!
1919     Returns the frame that will load the link if it is activated.
1920
1921     \sa linkElement()
1922 */
1923 QWebFrame *QWebHitTestResult::linkTargetFrame() const
1924 {
1925     if (!d)
1926         return 0;
1927     return d->linkTargetFrame.data();
1928 }
1929
1930 /*!
1931     Returns the alternate text of the element. This corresponds to the HTML alt attribute.
1932 */
1933 QString QWebHitTestResult::alternateText() const
1934 {
1935     if (!d)
1936         return QString();
1937     return d->alternateText;
1938 }
1939
1940 /*!
1941     Returns the url of the image.
1942 */
1943 QUrl QWebHitTestResult::imageUrl() const
1944 {
1945     if (!d)
1946         return QUrl();
1947     return d->imageUrl;
1948 }
1949
1950 /*!
1951     Returns a QPixmap containing the image. A null pixmap is returned if the
1952     element being tested is not an image.
1953 */
1954 QPixmap QWebHitTestResult::pixmap() const
1955 {
1956     if (!d)
1957         return QPixmap();
1958     return d->pixmap;
1959 }
1960
1961 /*!
1962     Returns true if the content is editable by the user; otherwise returns false.
1963 */
1964 bool QWebHitTestResult::isContentEditable() const
1965 {
1966     if (!d)
1967         return false;
1968     return d->isContentEditable;
1969 }
1970
1971 /*!
1972     Returns true if the content tested is part of the selection; otherwise returns false.
1973 */
1974 bool QWebHitTestResult::isContentSelected() const
1975 {
1976     if (!d)
1977         return false;
1978     return d->isContentSelected;
1979 }
1980
1981 /*!
1982     \since 4.6
1983     Returns the underlying DOM element as QWebElement.
1984 */
1985 QWebElement QWebHitTestResult::element() const
1986 {
1987     if (!d || !d->innerNonSharedNode || !d->innerNonSharedNode->isElementNode())
1988         return QWebElement();
1989
1990     return QWebElement(static_cast<WebCore::Element*>(d->innerNonSharedNode.get()));
1991 }
1992
1993 /*!
1994     Returns the frame the hit test was executed in.
1995 */
1996 QWebFrame *QWebHitTestResult::frame() const
1997 {
1998     if (!d)
1999         return 0;
2000     return d->frame.data();
2001 }
2002
2003 #include "moc_qwebframe.cpp"