[WK2] Add support for Web Intents MessagePorts
[WebKit-https.git] / Source / WebKit2 / WebProcess / WebPage / WebFrame.cpp
1 /*
2  * Copyright (C) 2010 Apple Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
14  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23  * THE POSSIBILITY OF SUCH DAMAGE.
24  */
25
26 #include "config.h"
27 #include "WebFrame.h"
28
29 #include "DownloadManager.h"
30 #include "InjectedBundleNodeHandle.h"
31 #include "InjectedBundleRangeHandle.h"
32 #include "InjectedBundleScriptWorld.h"
33 #include "WKAPICast.h"
34 #include "WKBundleAPICast.h"
35 #include "WebChromeClient.h"
36 #include "WebPage.h"
37 #include "WebPageProxyMessages.h"
38 #include "WebProcess.h"
39 #include <JavaScriptCore/APICast.h>
40 #include <JavaScriptCore/JSContextRef.h>
41 #include <JavaScriptCore/JSLock.h>
42 #include <JavaScriptCore/JSValueRef.h>
43 #include <WebCore/AnimationController.h>
44 #include <WebCore/ArchiveResource.h>
45 #include <WebCore/CSSComputedStyleDeclaration.h>
46 #include <WebCore/Chrome.h>
47 #include <WebCore/DocumentLoader.h>
48 #include <WebCore/Frame.h>
49 #include <WebCore/FrameView.h>
50 #include <WebCore/HTMLFrameOwnerElement.h>
51 #include <WebCore/HTMLNames.h>
52 #include <WebCore/JSCSSStyleDeclaration.h>
53 #include <WebCore/JSElement.h>
54 #include <WebCore/JSRange.h>
55 #include <WebCore/Page.h>
56 #include <WebCore/RenderTreeAsText.h>
57 #include <WebCore/SecurityOrigin.h>
58 #include <WebCore/TextIterator.h>
59 #include <WebCore/TextResourceDecoder.h>
60 #include <wtf/text/StringBuilder.h>
61
62 #if ENABLE(WEB_INTENTS)
63 #include "IntentData.h"
64 #include <WebCore/DOMWindowIntents.h>
65 #include <WebCore/DeliveredIntent.h>
66 #include <WebCore/Intent.h>
67 #include <WebCore/PlatformMessagePortChannel.h>
68 #endif
69
70 #if PLATFORM(MAC) || PLATFORM(WIN)
71 #include <WebCore/LegacyWebArchive.h>
72 #endif
73
74 #ifndef NDEBUG
75 #include <wtf/RefCountedLeakCounter.h>
76 #endif
77
78 using namespace JSC;
79 using namespace WebCore;
80
81 namespace WebKit {
82
83 DEFINE_DEBUG_ONLY_GLOBAL(WTF::RefCountedLeakCounter, webFrameCounter, ("WebFrame"));
84
85 static uint64_t generateFrameID()
86 {
87     static uint64_t uniqueFrameID = 1;
88     return uniqueFrameID++;
89 }
90
91 static uint64_t generateListenerID()
92 {
93     static uint64_t uniqueListenerID = 1;
94     return uniqueListenerID++;
95 }
96
97 PassRefPtr<WebFrame> WebFrame::createMainFrame(WebPage* page)
98 {
99     RefPtr<WebFrame> frame = create();
100
101     page->send(Messages::WebPageProxy::DidCreateMainFrame(frame->frameID()));
102
103     frame->init(page, String(), 0);
104
105     return frame.release();
106 }
107
108 PassRefPtr<WebFrame> WebFrame::createSubframe(WebPage* page, const String& frameName, HTMLFrameOwnerElement* ownerElement)
109 {
110     RefPtr<WebFrame> frame = create();
111
112     WebFrame* parentFrame = static_cast<WebFrameLoaderClient*>(ownerElement->document()->frame()->loader()->client())->webFrame();
113     page->send(Messages::WebPageProxy::DidCreateSubframe(frame->frameID(), parentFrame->frameID()));
114
115     frame->init(page, frameName, ownerElement);
116
117     return frame.release();
118 }
119
120 PassRefPtr<WebFrame> WebFrame::create()
121 {
122     RefPtr<WebFrame> frame = adoptRef(new WebFrame);
123
124     // Add explict ref() that will be balanced in WebFrameLoaderClient::frameLoaderDestroyed().
125     frame->ref();
126
127     return frame.release();
128 }
129
130 WebFrame::WebFrame()
131     : m_coreFrame(0)
132     , m_policyListenerID(0)
133     , m_policyFunction(0)
134     , m_policyDownloadID(0)
135     , m_frameLoaderClient(this)
136     , m_loadListener(0)
137     , m_frameID(generateFrameID())
138 {
139     WebProcess::shared().addWebFrame(m_frameID, this);
140
141 #ifndef NDEBUG
142     webFrameCounter.increment();
143 #endif
144 }
145
146 WebFrame::~WebFrame()
147 {
148     ASSERT(!m_coreFrame);
149
150 #ifndef NDEBUG
151     webFrameCounter.decrement();
152 #endif
153 }
154
155 void WebFrame::init(WebPage* page, const String& frameName, HTMLFrameOwnerElement* ownerElement)
156 {
157     RefPtr<Frame> frame = Frame::create(page->corePage(), ownerElement, &m_frameLoaderClient);
158     m_coreFrame = frame.get();
159
160     frame->tree()->setName(frameName);
161
162     if (ownerElement) {
163         ASSERT(ownerElement->document()->frame());
164         ownerElement->document()->frame()->tree()->appendChild(frame);
165     }
166
167     frame->init();
168 }
169
170 WebPage* WebFrame::page() const
171
172     if (!m_coreFrame)
173         return 0;
174     
175     if (WebCore::Page* page = m_coreFrame->page())
176         return static_cast<WebChromeClient*>(page->chrome()->client())->page();
177
178     return 0;
179 }
180
181 void WebFrame::invalidate()
182 {
183     WebProcess::shared().removeWebFrame(m_frameID);
184     m_coreFrame = 0;
185 }
186
187 uint64_t WebFrame::setUpPolicyListener(WebCore::FramePolicyFunction policyFunction)
188 {
189     // FIXME: <rdar://5634381> We need to support multiple active policy listeners.
190
191     invalidatePolicyListener();
192
193     m_policyListenerID = generateListenerID();
194     m_policyFunction = policyFunction;
195     return m_policyListenerID;
196 }
197
198 void WebFrame::invalidatePolicyListener()
199 {
200     if (!m_policyListenerID)
201         return;
202
203     m_policyDownloadID = 0;
204     m_policyListenerID = 0;
205     m_policyFunction = 0;
206 }
207
208 void WebFrame::didReceivePolicyDecision(uint64_t listenerID, PolicyAction action, uint64_t downloadID)
209 {
210     if (!m_coreFrame)
211         return;
212
213     if (!m_policyListenerID)
214         return;
215
216     if (listenerID != m_policyListenerID)
217         return;
218
219     ASSERT(m_policyFunction);
220
221     FramePolicyFunction function = m_policyFunction;
222
223     invalidatePolicyListener();
224
225     m_policyDownloadID = downloadID;
226
227     (m_coreFrame->loader()->policyChecker()->*function)(action);
228 }
229
230 void WebFrame::startDownload(const WebCore::ResourceRequest& request)
231 {
232     ASSERT(m_policyDownloadID);
233
234     DownloadManager::shared().startDownload(m_policyDownloadID, page(), request);
235
236     m_policyDownloadID = 0;
237 }
238
239 void WebFrame::convertHandleToDownload(ResourceHandle* handle, const ResourceRequest& request, const ResourceResponse& response)
240 {
241     ASSERT(m_policyDownloadID);
242
243     DownloadManager::shared().convertHandleToDownload(m_policyDownloadID, page(), handle, request, response);
244     m_policyDownloadID = 0;
245 }
246
247 #if ENABLE(WEB_INTENTS)
248 void WebFrame::deliverIntent(const IntentData& intentData)
249 {
250     OwnPtr<DeliveredIntentClient> dummyClient;
251     Vector<uint8_t> dataCopy = intentData.data;
252
253     OwnPtr<WebCore::MessagePortChannelArray> channels;
254     if (!intentData.messagePorts.isEmpty()) {
255         channels = adoptPtr(new WebCore::MessagePortChannelArray(intentData.messagePorts.size()));
256         for (size_t i = 0; i < intentData.messagePorts.size(); ++i)
257             (*channels)[i] = MessagePortChannel::create(WebProcess::shared().messagePortChannel(intentData.messagePorts.at(i)));
258     }
259     OwnPtr<WebCore::MessagePortArray> messagePorts = WebCore::MessagePort::entanglePorts(*m_coreFrame->document()->domWindow()->scriptExecutionContext(), channels.release());
260
261     RefPtr<DeliveredIntent> deliveredIntent = DeliveredIntent::create(m_coreFrame, dummyClient.release(), intentData.action, intentData.type,
262                                                                       SerializedScriptValue::adopt(dataCopy), messagePorts.release(),
263                                                                       intentData.extras);
264     WebCore::DOMWindowIntents::from(m_coreFrame->document()->domWindow())->deliver(deliveredIntent.release());
265 }
266
267 void WebFrame::deliverIntent(WebCore::Intent* intent)
268 {
269     OwnPtr<DeliveredIntentClient> dummyClient;
270
271     OwnPtr<WebCore::MessagePortChannelArray> channels;
272     WebCore::MessagePortChannelArray* origChannels = intent->messagePorts();
273     if (origChannels && origChannels->size()) {
274         channels = adoptPtr(new WebCore::MessagePortChannelArray(origChannels->size()));
275         for (size_t i = 0; i < origChannels->size(); ++i)
276             (*channels)[i] = origChannels->at(i).release();
277     }
278     OwnPtr<WebCore::MessagePortArray> messagePorts = WebCore::MessagePort::entanglePorts(*m_coreFrame->document()->domWindow()->scriptExecutionContext(), channels.release());
279
280     RefPtr<DeliveredIntent> deliveredIntent = DeliveredIntent::create(m_coreFrame, dummyClient.release(), intent->action(), intent->type(),
281                                                                       intent->data(), messagePorts.release(), intent->extras());
282     WebCore::DOMWindowIntents::from(m_coreFrame->document()->domWindow())->deliver(deliveredIntent.release());
283 }
284 #endif
285
286 String WebFrame::source() const 
287 {
288     if (!m_coreFrame)
289         return String();
290     Document* document = m_coreFrame->document();
291     if (!document)
292         return String();
293     TextResourceDecoder* decoder = document->decoder();
294     if (!decoder)
295         return String();
296     DocumentLoader* documentLoader = m_coreFrame->loader()->activeDocumentLoader();
297     if (!documentLoader)
298         return String();
299     RefPtr<SharedBuffer> mainResourceData = documentLoader->mainResourceData();
300     if (!mainResourceData)
301         return String();
302     return decoder->encoding().decode(mainResourceData->data(), mainResourceData->size());
303 }
304
305 String WebFrame::contentsAsString() const 
306 {
307     if (!m_coreFrame)
308         return String();
309
310     if (isFrameSet()) {
311         StringBuilder builder;
312         for (Frame* child = m_coreFrame->tree()->firstChild(); child; child = child->tree()->nextSibling()) {
313             if (!builder.isEmpty())
314                 builder.append(' ');
315             builder.append(static_cast<WebFrameLoaderClient*>(child->loader()->client())->webFrame()->contentsAsString());
316         }
317         // FIXME: It may make sense to use toStringPreserveCapacity() here.
318         return builder.toString();
319     }
320
321     Document* document = m_coreFrame->document();
322     if (!document)
323         return String();
324
325     RefPtr<Element> documentElement = document->documentElement();
326     if (!documentElement)
327         return String();
328
329     RefPtr<Range> range = document->createRange();
330
331     ExceptionCode ec = 0;
332     range->selectNode(documentElement.get(), ec);
333     if (ec)
334         return String();
335
336     return plainText(range.get());
337 }
338
339 String WebFrame::selectionAsString() const 
340 {
341     if (!m_coreFrame)
342         return String();
343
344     return m_coreFrame->displayStringModifiedByEncoding(m_coreFrame->editor()->selectedText());
345 }
346
347 IntSize WebFrame::size() const
348 {
349     if (!m_coreFrame)
350         return IntSize();
351
352     FrameView* frameView = m_coreFrame->view();
353     if (!frameView)
354         return IntSize();
355
356     return frameView->contentsSize();
357 }
358
359 bool WebFrame::isFrameSet() const
360 {
361     if (!m_coreFrame)
362         return false;
363
364     Document* document = m_coreFrame->document();
365     if (!document)
366         return false;
367     return document->isFrameSet();
368 }
369
370 bool WebFrame::isMainFrame() const
371 {
372     if (WebPage* p = page())
373         return p->mainWebFrame() == this;
374
375     return false;
376 }
377
378 String WebFrame::name() const
379 {
380     if (!m_coreFrame)
381         return String();
382
383     return m_coreFrame->tree()->uniqueName();
384 }
385
386 String WebFrame::url() const
387 {
388     if (!m_coreFrame)
389         return String();
390
391     DocumentLoader* documentLoader = m_coreFrame->loader()->documentLoader();
392     if (!documentLoader)
393         return String();
394
395     return documentLoader->url().string();
396 }
397
398 String WebFrame::innerText() const
399 {
400     if (!m_coreFrame)
401         return String();
402
403     if (!m_coreFrame->document()->documentElement())
404         return String();
405
406     return m_coreFrame->document()->documentElement()->innerText();
407 }
408
409 WebFrame* WebFrame::parentFrame() const
410 {
411     if (!m_coreFrame || !m_coreFrame->ownerElement() || !m_coreFrame->ownerElement()->document())
412         return 0;
413
414     return static_cast<WebFrameLoaderClient*>(m_coreFrame->ownerElement()->document()->frame()->loader()->client())->webFrame();
415 }
416
417 PassRefPtr<ImmutableArray> WebFrame::childFrames()
418 {
419     if (!m_coreFrame)
420         return ImmutableArray::create();
421
422     size_t size = m_coreFrame->tree()->childCount();
423     if (!size)
424         return ImmutableArray::create();
425
426     Vector<RefPtr<APIObject> > vector;
427     vector.reserveInitialCapacity(size);
428
429     for (Frame* child = m_coreFrame->tree()->firstChild(); child; child = child->tree()->nextSibling()) {
430         WebFrame* webFrame = static_cast<WebFrameLoaderClient*>(child->loader()->client())->webFrame();
431         vector.uncheckedAppend(webFrame);
432     }
433
434     return ImmutableArray::adopt(vector);
435 }
436
437 unsigned WebFrame::numberOfActiveAnimations() const
438 {
439     if (!m_coreFrame)
440         return 0;
441
442     AnimationController* controller = m_coreFrame->animation();
443     if (!controller)
444         return 0;
445
446     return controller->numberOfActiveAnimations(m_coreFrame->document());
447 }
448
449 bool WebFrame::pauseAnimationOnElementWithId(const String& animationName, const String& elementID, double time)
450 {
451     if (!m_coreFrame)
452         return false;
453
454     AnimationController* controller = m_coreFrame->animation();
455     if (!controller)
456         return false;
457
458     if (!m_coreFrame->document())
459         return false;
460
461     Node* coreNode = m_coreFrame->document()->getElementById(elementID);
462     if (!coreNode || !coreNode->renderer())
463         return false;
464
465     return controller->pauseAnimationAtTime(coreNode->renderer(), animationName, time);
466 }
467
468 bool WebFrame::pauseTransitionOnElementWithId(const String& propertyName, const String& elementID, double time)
469 {
470     if (!m_coreFrame)
471         return false;
472
473     AnimationController* controller = m_coreFrame->animation();
474     if (!controller)
475         return false;
476
477     if (!m_coreFrame->document())
478         return false;
479
480     Node* coreNode = m_coreFrame->document()->getElementById(elementID);
481     if (!coreNode || !coreNode->renderer())
482         return false;
483
484     return controller->pauseTransitionAtTime(coreNode->renderer(), propertyName, time);
485 }
486
487 void WebFrame::suspendAnimations()
488 {
489     if (!m_coreFrame)
490         return;
491
492     AnimationController* controller = m_coreFrame->animation();
493     if (!controller)
494         return;
495
496     controller->suspendAnimations();
497 }
498
499 void WebFrame::resumeAnimations()
500 {
501     if (!m_coreFrame)
502         return;
503
504     AnimationController* controller = m_coreFrame->animation();
505     if (!controller)
506         return;
507
508     controller->resumeAnimations();
509 }
510
511 String WebFrame::layerTreeAsText() const
512 {
513     if (!m_coreFrame)
514         return "";
515
516     return m_coreFrame->layerTreeAsText();
517 }
518
519 unsigned WebFrame::pendingUnloadCount() const
520 {
521     if (!m_coreFrame)
522         return 0;
523
524     return m_coreFrame->document()->domWindow()->pendingUnloadEventListeners();
525 }
526
527 bool WebFrame::allowsFollowingLink(const WebCore::KURL& url) const
528 {
529     if (!m_coreFrame)
530         return true;
531         
532     return m_coreFrame->document()->securityOrigin()->canDisplay(url);
533 }
534
535 JSGlobalContextRef WebFrame::jsContext()
536 {
537     return toGlobalRef(m_coreFrame->script()->globalObject(mainThreadNormalWorld())->globalExec());
538 }
539
540 JSGlobalContextRef WebFrame::jsContextForWorld(InjectedBundleScriptWorld* world)
541 {
542     return toGlobalRef(m_coreFrame->script()->globalObject(world->coreWorld())->globalExec());
543 }
544
545 IntRect WebFrame::contentBounds() const
546 {    
547     if (!m_coreFrame)
548         return IntRect();
549     
550     FrameView* view = m_coreFrame->view();
551     if (!view)
552         return IntRect();
553     
554     return IntRect(0, 0, view->contentsWidth(), view->contentsHeight());
555 }
556
557 IntRect WebFrame::visibleContentBounds() const
558 {
559     if (!m_coreFrame)
560         return IntRect();
561     
562     FrameView* view = m_coreFrame->view();
563     if (!view)
564         return IntRect();
565     
566     IntRect contentRect = view->visibleContentRect(true);
567     return IntRect(0, 0, contentRect.width(), contentRect.height());
568 }
569
570 IntRect WebFrame::visibleContentBoundsExcludingScrollbars() const
571 {
572     if (!m_coreFrame)
573         return IntRect();
574     
575     FrameView* view = m_coreFrame->view();
576     if (!view)
577         return IntRect();
578     
579     IntRect contentRect = view->visibleContentRect(false);
580     return IntRect(0, 0, contentRect.width(), contentRect.height());
581 }
582
583 IntSize WebFrame::scrollOffset() const
584 {
585     if (!m_coreFrame)
586         return IntSize();
587     
588     FrameView* view = m_coreFrame->view();
589     if (!view)
590         return IntSize();
591
592     return view->scrollOffset();
593 }
594
595 bool WebFrame::hasHorizontalScrollbar() const
596 {
597     if (!m_coreFrame)
598         return false;
599
600     FrameView* view = m_coreFrame->view();
601     if (!view)
602         return false;
603
604     return view->horizontalScrollbar();
605 }
606
607 bool WebFrame::hasVerticalScrollbar() const
608 {
609     if (!m_coreFrame)
610         return false;
611
612     FrameView* view = m_coreFrame->view();
613     if (!view)
614         return false;
615
616     return view->verticalScrollbar();
617 }
618
619 bool WebFrame::getDocumentBackgroundColor(double* red, double* green, double* blue, double* alpha)
620 {
621     if (!m_coreFrame)
622         return false;
623
624     FrameView* view = m_coreFrame->view();
625     if (!view)
626         return false;
627
628     Color bgColor = view->documentBackgroundColor();
629     if (!bgColor.isValid())
630         return false;
631
632     bgColor.getRGBA(*red, *green, *blue, *alpha);
633     return true;
634 }
635
636 bool WebFrame::containsAnyFormElements() const
637 {
638     if (!m_coreFrame)
639         return false;
640     
641     Document* document = m_coreFrame->document();
642     if (!document)
643         return false;
644
645     for (Node* node = document->documentElement(); node; node = node->traverseNextNode()) {
646         if (!node->isElementNode())
647             continue;
648         if (static_cast<Element*>(node)->hasTagName(HTMLNames::formTag))
649             return true;
650     }
651     return false;
652 }
653
654 WebFrame* WebFrame::frameForContext(JSContextRef context)
655 {
656     JSObjectRef globalObjectRef = JSContextGetGlobalObject(context);
657     JSC::JSObject* globalObjectObj = toJS(globalObjectRef);
658     if (strcmp(globalObjectObj->classInfo()->className, "JSDOMWindowShell") != 0)
659         return 0;
660
661     Frame* coreFrame = static_cast<JSDOMWindowShell*>(globalObjectObj)->window()->impl()->frame();
662     return static_cast<WebFrameLoaderClient*>(coreFrame->loader()->client())->webFrame();
663 }
664
665 JSValueRef WebFrame::jsWrapperForWorld(InjectedBundleNodeHandle* nodeHandle, InjectedBundleScriptWorld* world)
666 {
667     if (!m_coreFrame)
668         return 0;
669
670     JSDOMWindow* globalObject = m_coreFrame->script()->globalObject(world->coreWorld());
671     ExecState* exec = globalObject->globalExec();
672
673     JSLockHolder lock(exec);
674     return toRef(exec, toJS(exec, globalObject, nodeHandle->coreNode()));
675 }
676
677 JSValueRef WebFrame::jsWrapperForWorld(InjectedBundleRangeHandle* rangeHandle, InjectedBundleScriptWorld* world)
678 {
679     if (!m_coreFrame)
680         return 0;
681
682     JSDOMWindow* globalObject = m_coreFrame->script()->globalObject(world->coreWorld());
683     ExecState* exec = globalObject->globalExec();
684
685     JSLockHolder lock(exec);
686     return toRef(exec, toJS(exec, globalObject, rangeHandle->coreRange()));
687 }
688
689 JSValueRef WebFrame::computedStyleIncludingVisitedInfo(JSObjectRef element)
690 {
691     if (!m_coreFrame)
692         return 0;
693
694     JSDOMWindow* globalObject = m_coreFrame->script()->globalObject(mainThreadNormalWorld());
695     ExecState* exec = globalObject->globalExec();
696
697     if (!toJS(element)->inherits(&JSElement::s_info))
698         return JSValueMakeUndefined(toRef(exec));
699
700     RefPtr<CSSComputedStyleDeclaration> style = CSSComputedStyleDeclaration::create(static_cast<JSElement*>(toJS(element))->impl(), true);
701
702     JSLockHolder lock(exec);
703     return toRef(exec, toJS(exec, globalObject, style.get()));
704 }
705
706 String WebFrame::counterValue(JSObjectRef element)
707 {
708     if (!toJS(element)->inherits(&JSElement::s_info))
709         return String();
710
711     return counterValueForElement(static_cast<JSElement*>(toJS(element))->impl());
712 }
713
714 String WebFrame::markerText(JSObjectRef element)
715 {
716     if (!toJS(element)->inherits(&JSElement::s_info))
717         return String();
718
719     return markerTextForListItem(static_cast<JSElement*>(toJS(element))->impl());
720 }
721
722 String WebFrame::provisionalURL() const
723 {
724     if (!m_coreFrame)
725         return String();
726
727     return m_coreFrame->loader()->provisionalDocumentLoader()->url().string();
728 }
729
730 String WebFrame::suggestedFilenameForResourceWithURL(const KURL& url) const
731 {
732     if (!m_coreFrame)
733         return String();
734
735     DocumentLoader* loader = m_coreFrame->loader()->documentLoader();
736     if (!loader)
737         return String();
738
739     // First, try the main resource.
740     if (loader->url() == url)
741         return loader->response().suggestedFilename();
742
743     // Next, try subresources.
744     RefPtr<ArchiveResource> resource = loader->subresource(url);
745     if (resource)
746         return resource->response().suggestedFilename();
747
748     return page()->cachedSuggestedFilenameForURL(url);
749 }
750
751 String WebFrame::mimeTypeForResourceWithURL(const KURL& url) const
752 {
753     if (!m_coreFrame)
754         return String();
755
756     DocumentLoader* loader = m_coreFrame->loader()->documentLoader();
757     if (!loader)
758         return String();
759
760     // First, try the main resource.
761     if (loader->url() == url)
762         return loader->response().mimeType();
763
764     // Next, try subresources.
765     RefPtr<ArchiveResource> resource = loader->subresource(url);
766     if (resource)
767         return resource->mimeType();
768
769     return page()->cachedResponseMIMETypeForURL(url);
770 }
771
772 void WebFrame::setTextDirection(const String& direction)
773 {
774     if (!m_coreFrame || !m_coreFrame->editor())
775         return;
776
777     if (direction == "auto")
778         m_coreFrame->editor()->setBaseWritingDirection(NaturalWritingDirection);
779     else if (direction == "ltr")
780         m_coreFrame->editor()->setBaseWritingDirection(LeftToRightWritingDirection);
781     else if (direction == "rtl")
782         m_coreFrame->editor()->setBaseWritingDirection(RightToLeftWritingDirection);
783 }
784
785 #if PLATFORM(MAC) || PLATFORM(WIN)
786
787 class WebFrameFilter : public FrameFilter {
788 public:
789     WebFrameFilter(WebFrame*, WebFrame::FrameFilterFunction, void* context);
790         
791 private:
792     virtual bool shouldIncludeSubframe(Frame*) const OVERRIDE;
793
794     WebFrame* m_topLevelWebFrame;
795     WebFrame::FrameFilterFunction m_callback;
796     void* m_context;
797 };
798
799 WebFrameFilter::WebFrameFilter(WebFrame* topLevelWebFrame, WebFrame::FrameFilterFunction callback, void* context)
800     : m_topLevelWebFrame(topLevelWebFrame)
801     , m_callback(callback)
802     , m_context(context)
803 {
804 }
805
806 bool WebFrameFilter::shouldIncludeSubframe(Frame* frame) const
807 {
808     if (!m_callback)
809         return true;
810         
811     WebFrame* webFrame = static_cast<WebFrameLoaderClient*>(frame->loader()->client())->webFrame();
812     return m_callback(toAPI(m_topLevelWebFrame), toAPI(webFrame), m_context);
813 }
814
815 RetainPtr<CFDataRef> WebFrame::webArchiveData(FrameFilterFunction callback, void* context)
816 {
817     WebFrameFilter filter(this, callback, context);
818
819     if (RefPtr<LegacyWebArchive> archive = LegacyWebArchive::create(coreFrame()->document(), &filter))
820         return archive->rawDataRepresentation();
821     
822     return 0;
823 }
824 #endif
825     
826 } // namespace WebKit