19243bee03e4726ca0bb7a981d8b30843b9de515
[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 #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 void WebFrame::startDownload(const WebCore::ResourceRequest& request)
229 {
230     ASSERT(m_policyDownloadID);
231
232     DownloadManager::shared().startDownload(m_policyDownloadID, page(), request);
233
234     m_policyDownloadID = 0;
235 }
236
237 void WebFrame::convertHandleToDownload(ResourceHandle* handle, const ResourceRequest& request, const ResourceResponse& response)
238 {
239     ASSERT(m_policyDownloadID);
240
241     DownloadManager::shared().convertHandleToDownload(m_policyDownloadID, page(), handle, request, response);
242     m_policyDownloadID = 0;
243 }
244
245 #if ENABLE(WEB_INTENTS)
246 void WebFrame::deliverIntent(const IntentData& intentData)
247 {
248     OwnPtr<DeliveredIntentClient> dummyClient;
249     OwnPtr<MessagePortArray> dummyPorts;
250     Vector<uint8_t> dataCopy = intentData.data;
251     RefPtr<DeliveredIntent> deliveredIntent = DeliveredIntent::create(m_coreFrame, dummyClient.release(), intentData.action, intentData.type,
252                                                                       SerializedScriptValue::adopt(dataCopy), dummyPorts.release(),
253                                                                       intentData.extras);
254     WebCore::DOMWindowIntents::from(m_coreFrame->document()->domWindow())->deliver(deliveredIntent.release());
255 }
256 #endif
257
258 String WebFrame::source() const 
259 {
260     if (!m_coreFrame)
261         return String();
262     Document* document = m_coreFrame->document();
263     if (!document)
264         return String();
265     TextResourceDecoder* decoder = document->decoder();
266     if (!decoder)
267         return String();
268     DocumentLoader* documentLoader = m_coreFrame->loader()->activeDocumentLoader();
269     if (!documentLoader)
270         return String();
271     RefPtr<SharedBuffer> mainResourceData = documentLoader->mainResourceData();
272     if (!mainResourceData)
273         return String();
274     return decoder->encoding().decode(mainResourceData->data(), mainResourceData->size());
275 }
276
277 String WebFrame::contentsAsString() const 
278 {
279     if (!m_coreFrame)
280         return String();
281
282     if (isFrameSet()) {
283         StringBuilder builder;
284         for (Frame* child = m_coreFrame->tree()->firstChild(); child; child = child->tree()->nextSibling()) {
285             if (!builder.isEmpty())
286                 builder.append(' ');
287             builder.append(static_cast<WebFrameLoaderClient*>(child->loader()->client())->webFrame()->contentsAsString());
288         }
289         // FIXME: It may make sense to use toStringPreserveCapacity() here.
290         return builder.toString();
291     }
292
293     Document* document = m_coreFrame->document();
294     if (!document)
295         return String();
296
297     RefPtr<Element> documentElement = document->documentElement();
298     if (!documentElement)
299         return String();
300
301     RefPtr<Range> range = document->createRange();
302
303     ExceptionCode ec = 0;
304     range->selectNode(documentElement.get(), ec);
305     if (ec)
306         return String();
307
308     return plainText(range.get());
309 }
310
311 String WebFrame::selectionAsString() const 
312 {
313     if (!m_coreFrame)
314         return String();
315
316     return m_coreFrame->displayStringModifiedByEncoding(m_coreFrame->editor()->selectedText());
317 }
318
319 IntSize WebFrame::size() const
320 {
321     if (!m_coreFrame)
322         return IntSize();
323
324     FrameView* frameView = m_coreFrame->view();
325     if (!frameView)
326         return IntSize();
327
328     return frameView->contentsSize();
329 }
330
331 bool WebFrame::isFrameSet() const
332 {
333     if (!m_coreFrame)
334         return false;
335
336     Document* document = m_coreFrame->document();
337     if (!document)
338         return false;
339     return document->isFrameSet();
340 }
341
342 bool WebFrame::isMainFrame() const
343 {
344     if (WebPage* p = page())
345         return p->mainWebFrame() == this;
346
347     return false;
348 }
349
350 String WebFrame::name() const
351 {
352     if (!m_coreFrame)
353         return String();
354
355     return m_coreFrame->tree()->uniqueName();
356 }
357
358 String WebFrame::url() const
359 {
360     if (!m_coreFrame)
361         return String();
362
363     DocumentLoader* documentLoader = m_coreFrame->loader()->documentLoader();
364     if (!documentLoader)
365         return String();
366
367     return documentLoader->url().string();
368 }
369
370 String WebFrame::innerText() const
371 {
372     if (!m_coreFrame)
373         return String();
374
375     if (!m_coreFrame->document()->documentElement())
376         return String();
377
378     return m_coreFrame->document()->documentElement()->innerText();
379 }
380
381 WebFrame* WebFrame::parentFrame() const
382 {
383     if (!m_coreFrame || !m_coreFrame->ownerElement() || !m_coreFrame->ownerElement()->document())
384         return 0;
385
386     return static_cast<WebFrameLoaderClient*>(m_coreFrame->ownerElement()->document()->frame()->loader()->client())->webFrame();
387 }
388
389 PassRefPtr<ImmutableArray> WebFrame::childFrames()
390 {
391     if (!m_coreFrame)
392         return ImmutableArray::create();
393
394     size_t size = m_coreFrame->tree()->childCount();
395     if (!size)
396         return ImmutableArray::create();
397
398     Vector<RefPtr<APIObject> > vector;
399     vector.reserveInitialCapacity(size);
400
401     for (Frame* child = m_coreFrame->tree()->firstChild(); child; child = child->tree()->nextSibling()) {
402         WebFrame* webFrame = static_cast<WebFrameLoaderClient*>(child->loader()->client())->webFrame();
403         vector.uncheckedAppend(webFrame);
404     }
405
406     return ImmutableArray::adopt(vector);
407 }
408
409 unsigned WebFrame::numberOfActiveAnimations() const
410 {
411     if (!m_coreFrame)
412         return 0;
413
414     AnimationController* controller = m_coreFrame->animation();
415     if (!controller)
416         return 0;
417
418     return controller->numberOfActiveAnimations(m_coreFrame->document());
419 }
420
421 bool WebFrame::pauseAnimationOnElementWithId(const String& animationName, const String& elementID, double time)
422 {
423     if (!m_coreFrame)
424         return false;
425
426     AnimationController* controller = m_coreFrame->animation();
427     if (!controller)
428         return false;
429
430     if (!m_coreFrame->document())
431         return false;
432
433     Node* coreNode = m_coreFrame->document()->getElementById(elementID);
434     if (!coreNode || !coreNode->renderer())
435         return false;
436
437     return controller->pauseAnimationAtTime(coreNode->renderer(), animationName, time);
438 }
439
440 bool WebFrame::pauseTransitionOnElementWithId(const String& propertyName, const String& elementID, double time)
441 {
442     if (!m_coreFrame)
443         return false;
444
445     AnimationController* controller = m_coreFrame->animation();
446     if (!controller)
447         return false;
448
449     if (!m_coreFrame->document())
450         return false;
451
452     Node* coreNode = m_coreFrame->document()->getElementById(elementID);
453     if (!coreNode || !coreNode->renderer())
454         return false;
455
456     return controller->pauseTransitionAtTime(coreNode->renderer(), propertyName, time);
457 }
458
459 void WebFrame::suspendAnimations()
460 {
461     if (!m_coreFrame)
462         return;
463
464     AnimationController* controller = m_coreFrame->animation();
465     if (!controller)
466         return;
467
468     controller->suspendAnimations();
469 }
470
471 void WebFrame::resumeAnimations()
472 {
473     if (!m_coreFrame)
474         return;
475
476     AnimationController* controller = m_coreFrame->animation();
477     if (!controller)
478         return;
479
480     controller->resumeAnimations();
481 }
482
483 String WebFrame::layerTreeAsText() const
484 {
485     if (!m_coreFrame)
486         return "";
487
488     return m_coreFrame->layerTreeAsText();
489 }
490
491 unsigned WebFrame::pendingUnloadCount() const
492 {
493     if (!m_coreFrame)
494         return 0;
495
496     return m_coreFrame->document()->domWindow()->pendingUnloadEventListeners();
497 }
498
499 bool WebFrame::allowsFollowingLink(const WebCore::KURL& url) const
500 {
501     if (!m_coreFrame)
502         return true;
503         
504     return m_coreFrame->document()->securityOrigin()->canDisplay(url);
505 }
506
507 JSGlobalContextRef WebFrame::jsContext()
508 {
509     return toGlobalRef(m_coreFrame->script()->globalObject(mainThreadNormalWorld())->globalExec());
510 }
511
512 JSGlobalContextRef WebFrame::jsContextForWorld(InjectedBundleScriptWorld* world)
513 {
514     return toGlobalRef(m_coreFrame->script()->globalObject(world->coreWorld())->globalExec());
515 }
516
517 IntRect WebFrame::contentBounds() const
518 {    
519     if (!m_coreFrame)
520         return IntRect();
521     
522     FrameView* view = m_coreFrame->view();
523     if (!view)
524         return IntRect();
525     
526     return IntRect(0, 0, view->contentsWidth(), view->contentsHeight());
527 }
528
529 IntRect WebFrame::visibleContentBounds() const
530 {
531     if (!m_coreFrame)
532         return IntRect();
533     
534     FrameView* view = m_coreFrame->view();
535     if (!view)
536         return IntRect();
537     
538     IntRect contentRect = view->visibleContentRect(true);
539     return IntRect(0, 0, contentRect.width(), contentRect.height());
540 }
541
542 IntRect WebFrame::visibleContentBoundsExcludingScrollbars() const
543 {
544     if (!m_coreFrame)
545         return IntRect();
546     
547     FrameView* view = m_coreFrame->view();
548     if (!view)
549         return IntRect();
550     
551     IntRect contentRect = view->visibleContentRect(false);
552     return IntRect(0, 0, contentRect.width(), contentRect.height());
553 }
554
555 IntSize WebFrame::scrollOffset() const
556 {
557     if (!m_coreFrame)
558         return IntSize();
559     
560     FrameView* view = m_coreFrame->view();
561     if (!view)
562         return IntSize();
563
564     return view->scrollOffset();
565 }
566
567 bool WebFrame::hasHorizontalScrollbar() const
568 {
569     if (!m_coreFrame)
570         return false;
571
572     FrameView* view = m_coreFrame->view();
573     if (!view)
574         return false;
575
576     return view->horizontalScrollbar();
577 }
578
579 bool WebFrame::hasVerticalScrollbar() const
580 {
581     if (!m_coreFrame)
582         return false;
583
584     FrameView* view = m_coreFrame->view();
585     if (!view)
586         return false;
587
588     return view->verticalScrollbar();
589 }
590
591 bool WebFrame::getDocumentBackgroundColor(double* red, double* green, double* blue, double* alpha)
592 {
593     if (!m_coreFrame)
594         return false;
595
596     FrameView* view = m_coreFrame->view();
597     if (!view)
598         return false;
599
600     Color bgColor = view->documentBackgroundColor();
601     if (!bgColor.isValid())
602         return false;
603
604     bgColor.getRGBA(*red, *green, *blue, *alpha);
605     return true;
606 }
607
608 bool WebFrame::containsAnyFormElements() const
609 {
610     if (!m_coreFrame)
611         return false;
612     
613     Document* document = m_coreFrame->document();
614     if (!document)
615         return false;
616
617     for (Node* node = document->documentElement(); node; node = node->traverseNextNode()) {
618         if (!node->isElementNode())
619             continue;
620         if (static_cast<Element*>(node)->hasTagName(HTMLNames::formTag))
621             return true;
622     }
623     return false;
624 }
625
626 WebFrame* WebFrame::frameForContext(JSContextRef context)
627 {
628     JSObjectRef globalObjectRef = JSContextGetGlobalObject(context);
629     JSC::JSObject* globalObjectObj = toJS(globalObjectRef);
630     if (strcmp(globalObjectObj->classInfo()->className, "JSDOMWindowShell") != 0)
631         return 0;
632
633     Frame* coreFrame = static_cast<JSDOMWindowShell*>(globalObjectObj)->window()->impl()->frame();
634     return static_cast<WebFrameLoaderClient*>(coreFrame->loader()->client())->webFrame();
635 }
636
637 JSValueRef WebFrame::jsWrapperForWorld(InjectedBundleNodeHandle* nodeHandle, InjectedBundleScriptWorld* world)
638 {
639     if (!m_coreFrame)
640         return 0;
641
642     JSDOMWindow* globalObject = m_coreFrame->script()->globalObject(world->coreWorld());
643     ExecState* exec = globalObject->globalExec();
644
645     JSLockHolder lock(exec);
646     return toRef(exec, toJS(exec, globalObject, nodeHandle->coreNode()));
647 }
648
649 JSValueRef WebFrame::jsWrapperForWorld(InjectedBundleRangeHandle* rangeHandle, InjectedBundleScriptWorld* world)
650 {
651     if (!m_coreFrame)
652         return 0;
653
654     JSDOMWindow* globalObject = m_coreFrame->script()->globalObject(world->coreWorld());
655     ExecState* exec = globalObject->globalExec();
656
657     JSLockHolder lock(exec);
658     return toRef(exec, toJS(exec, globalObject, rangeHandle->coreRange()));
659 }
660
661 JSValueRef WebFrame::computedStyleIncludingVisitedInfo(JSObjectRef element)
662 {
663     if (!m_coreFrame)
664         return 0;
665
666     JSDOMWindow* globalObject = m_coreFrame->script()->globalObject(mainThreadNormalWorld());
667     ExecState* exec = globalObject->globalExec();
668
669     if (!toJS(element)->inherits(&JSElement::s_info))
670         return JSValueMakeUndefined(toRef(exec));
671
672     RefPtr<CSSComputedStyleDeclaration> style = CSSComputedStyleDeclaration::create(static_cast<JSElement*>(toJS(element))->impl(), true);
673
674     JSLockHolder lock(exec);
675     return toRef(exec, toJS(exec, globalObject, style.get()));
676 }
677
678 String WebFrame::counterValue(JSObjectRef element)
679 {
680     if (!toJS(element)->inherits(&JSElement::s_info))
681         return String();
682
683     return counterValueForElement(static_cast<JSElement*>(toJS(element))->impl());
684 }
685
686 String WebFrame::markerText(JSObjectRef element)
687 {
688     if (!toJS(element)->inherits(&JSElement::s_info))
689         return String();
690
691     return markerTextForListItem(static_cast<JSElement*>(toJS(element))->impl());
692 }
693
694 String WebFrame::provisionalURL() const
695 {
696     if (!m_coreFrame)
697         return String();
698
699     return m_coreFrame->loader()->provisionalDocumentLoader()->url().string();
700 }
701
702 String WebFrame::suggestedFilenameForResourceWithURL(const KURL& url) const
703 {
704     if (!m_coreFrame)
705         return String();
706
707     DocumentLoader* loader = m_coreFrame->loader()->documentLoader();
708     if (!loader)
709         return String();
710
711     // First, try the main resource.
712     if (loader->url() == url)
713         return loader->response().suggestedFilename();
714
715     // Next, try subresources.
716     RefPtr<ArchiveResource> resource = loader->subresource(url);
717     if (resource)
718         return resource->response().suggestedFilename();
719
720     return page()->cachedSuggestedFilenameForURL(url);
721 }
722
723 String WebFrame::mimeTypeForResourceWithURL(const KURL& url) const
724 {
725     if (!m_coreFrame)
726         return String();
727
728     DocumentLoader* loader = m_coreFrame->loader()->documentLoader();
729     if (!loader)
730         return String();
731
732     // First, try the main resource.
733     if (loader->url() == url)
734         return loader->response().mimeType();
735
736     // Next, try subresources.
737     RefPtr<ArchiveResource> resource = loader->subresource(url);
738     if (resource)
739         return resource->mimeType();
740
741     return page()->cachedResponseMIMETypeForURL(url);
742 }
743
744 void WebFrame::setTextDirection(const String& direction)
745 {
746     if (!m_coreFrame || !m_coreFrame->editor())
747         return;
748
749     if (direction == "auto")
750         m_coreFrame->editor()->setBaseWritingDirection(NaturalWritingDirection);
751     else if (direction == "ltr")
752         m_coreFrame->editor()->setBaseWritingDirection(LeftToRightWritingDirection);
753     else if (direction == "rtl")
754         m_coreFrame->editor()->setBaseWritingDirection(RightToLeftWritingDirection);
755 }
756
757 #if PLATFORM(MAC) || PLATFORM(WIN)
758
759 class WebFrameFilter : public FrameFilter {
760 public:
761     WebFrameFilter(WebFrame*, WebFrame::FrameFilterFunction, void* context);
762         
763 private:
764     virtual bool shouldIncludeSubframe(Frame*) const OVERRIDE;
765
766     WebFrame* m_topLevelWebFrame;
767     WebFrame::FrameFilterFunction m_callback;
768     void* m_context;
769 };
770
771 WebFrameFilter::WebFrameFilter(WebFrame* topLevelWebFrame, WebFrame::FrameFilterFunction callback, void* context)
772     : m_topLevelWebFrame(topLevelWebFrame)
773     , m_callback(callback)
774     , m_context(context)
775 {
776 }
777
778 bool WebFrameFilter::shouldIncludeSubframe(Frame* frame) const
779 {
780     if (!m_callback)
781         return true;
782         
783     WebFrame* webFrame = static_cast<WebFrameLoaderClient*>(frame->loader()->client())->webFrame();
784     return m_callback(toAPI(m_topLevelWebFrame), toAPI(webFrame), m_context);
785 }
786
787 RetainPtr<CFDataRef> WebFrame::webArchiveData(FrameFilterFunction callback, void* context)
788 {
789     WebFrameFilter filter(this, callback, context);
790
791     if (RefPtr<LegacyWebArchive> archive = LegacyWebArchive::create(coreFrame()->document(), &filter))
792         return archive->rawDataRepresentation();
793     
794     return 0;
795 }
796 #endif
797     
798 } // namespace WebKit