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