Adopt is/toHTMLFormElement for code cleanup
[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 "InjectedBundleHitTestResult.h"
31 #include "InjectedBundleNodeHandle.h"
32 #include "InjectedBundleRangeHandle.h"
33 #include "InjectedBundleScriptWorld.h"
34 #include "PluginView.h"
35 #include "WKAPICast.h"
36 #include "WKBundleAPICast.h"
37 #include "WebChromeClient.h"
38 #include "WebPage.h"
39 #include "WebPageProxyMessages.h"
40 #include "WebProcess.h"
41 #include <JavaScriptCore/APICast.h>
42 #include <JavaScriptCore/JSContextRef.h>
43 #include <JavaScriptCore/JSLock.h>
44 #include <JavaScriptCore/JSValueRef.h>
45 #include <WebCore/ArchiveResource.h>
46 #include <WebCore/Chrome.h>
47 #include <WebCore/DocumentLoader.h>
48 #include <WebCore/EventHandler.h>
49 #include <WebCore/Frame.h>
50 #include <WebCore/FrameView.h>
51 #include <WebCore/HTMLFormElement.h>
52 #include <WebCore/HTMLFrameOwnerElement.h>
53 #include <WebCore/HTMLNames.h>
54 #include <WebCore/JSCSSStyleDeclaration.h>
55 #include <WebCore/JSElement.h>
56 #include <WebCore/JSRange.h>
57 #include <WebCore/NetworkingContext.h>
58 #include <WebCore/NodeTraversal.h>
59 #include <WebCore/Page.h>
60 #include <WebCore/PluginDocument.h>
61 #include <WebCore/RenderTreeAsText.h>
62 #include <WebCore/ResourceBuffer.h>
63 #include <WebCore/ResourceLoader.h>
64 #include <WebCore/ScriptController.h>
65 #include <WebCore/SecurityOrigin.h>
66 #include <WebCore/TextIterator.h>
67 #include <WebCore/TextResourceDecoder.h>
68 #include <wtf/text/StringBuilder.h>
69
70 #if PLATFORM(MAC)
71 #include <WebCore/LegacyWebArchive.h>
72 #endif
73
74 #if ENABLE(NETWORK_PROCESS)
75 #include "NetworkConnectionToWebProcessMessages.h"
76 #include "NetworkProcessConnection.h"
77 #include "WebCoreArgumentCoders.h"
78 #endif
79
80 #ifndef NDEBUG
81 #include <wtf/RefCountedLeakCounter.h>
82 #endif
83
84 using namespace JSC;
85 using namespace WebCore;
86
87 namespace WebKit {
88
89 DEFINE_DEBUG_ONLY_GLOBAL(WTF::RefCountedLeakCounter, webFrameCounter, ("WebFrame"));
90
91 static uint64_t generateFrameID()
92 {
93     static uint64_t uniqueFrameID = 1;
94     return uniqueFrameID++;
95 }
96
97 static uint64_t generateListenerID()
98 {
99     static uint64_t uniqueListenerID = 1;
100     return uniqueListenerID++;
101 }
102
103 PassRefPtr<WebFrame> WebFrame::createMainFrame(WebPage* page)
104 {
105     RefPtr<WebFrame> frame = create();
106
107     page->send(Messages::WebPageProxy::DidCreateMainFrame(frame->frameID()));
108
109     frame->init(page, String(), 0);
110
111     return frame.release();
112 }
113
114 PassRefPtr<WebFrame> WebFrame::createSubframe(WebPage* page, const String& frameName, HTMLFrameOwnerElement* ownerElement)
115 {
116     RefPtr<WebFrame> frame = create();
117
118     page->send(Messages::WebPageProxy::DidCreateSubframe(frame->frameID()));
119
120     frame->init(page, frameName, ownerElement);
121
122     return frame.release();
123 }
124
125 PassRefPtr<WebFrame> WebFrame::create()
126 {
127     RefPtr<WebFrame> frame = adoptRef(new WebFrame);
128
129     // Add explict ref() that will be balanced in WebFrameLoaderClient::frameLoaderDestroyed().
130     frame->ref();
131
132     return frame.release();
133 }
134
135 WebFrame::WebFrame()
136     : m_coreFrame(0)
137     , m_policyListenerID(0)
138     , m_policyFunction(0)
139     , m_policyDownloadID(0)
140     , m_frameLoaderClient(this)
141     , m_loadListener(0)
142     , m_frameID(generateFrameID())
143 {
144     WebProcess::shared().addWebFrame(m_frameID, this);
145
146 #ifndef NDEBUG
147     webFrameCounter.increment();
148 #endif
149 }
150
151 WebFrame::~WebFrame()
152 {
153     ASSERT(!m_coreFrame);
154
155 #ifndef NDEBUG
156     webFrameCounter.decrement();
157 #endif
158 }
159
160 void WebFrame::init(WebPage* page, const String& frameName, HTMLFrameOwnerElement* ownerElement)
161 {
162     RefPtr<Frame> frame = Frame::create(page->corePage(), ownerElement, &m_frameLoaderClient);
163     m_coreFrame = frame.get();
164
165     frame->tree()->setName(frameName);
166
167     if (ownerElement) {
168         ASSERT(ownerElement->document()->frame());
169         ownerElement->document()->frame()->tree()->appendChild(frame);
170     }
171
172     frame->init();
173 }
174
175 WebPage* WebFrame::page() const
176
177     if (!m_coreFrame)
178         return 0;
179     
180     if (Page* page = m_coreFrame->page())
181         return WebPage::fromCorePage(page);
182
183     return 0;
184 }
185
186 void WebFrame::invalidate()
187 {
188     WebProcess::shared().removeWebFrame(m_frameID);
189     m_coreFrame = 0;
190 }
191
192 uint64_t WebFrame::setUpPolicyListener(WebCore::FramePolicyFunction policyFunction)
193 {
194     // FIXME: <rdar://5634381> We need to support multiple active policy listeners.
195
196     invalidatePolicyListener();
197
198     m_policyListenerID = generateListenerID();
199     m_policyFunction = policyFunction;
200     return m_policyListenerID;
201 }
202
203 void WebFrame::invalidatePolicyListener()
204 {
205     if (!m_policyListenerID)
206         return;
207
208     m_policyDownloadID = 0;
209     m_policyListenerID = 0;
210     m_policyFunction = 0;
211 }
212
213 void WebFrame::didReceivePolicyDecision(uint64_t listenerID, PolicyAction action, uint64_t downloadID)
214 {
215     if (!m_coreFrame)
216         return;
217
218     if (!m_policyListenerID)
219         return;
220
221     if (listenerID != m_policyListenerID)
222         return;
223
224     ASSERT(m_policyFunction);
225
226     FramePolicyFunction function = m_policyFunction;
227
228     invalidatePolicyListener();
229
230     m_policyDownloadID = downloadID;
231
232     (m_coreFrame->loader()->policyChecker()->*function)(action);
233 }
234
235 void WebFrame::startDownload(const WebCore::ResourceRequest& request)
236 {
237     ASSERT(m_policyDownloadID);
238
239     uint64_t policyDownloadID = m_policyDownloadID;
240     m_policyDownloadID = 0;
241
242 #if ENABLE(NETWORK_PROCESS)
243     if (WebProcess::shared().usesNetworkProcess()) {
244         bool privateBrowsingEnabled = m_coreFrame->loader()->networkingContext()->storageSession().isPrivateBrowsingSession();
245         WebProcess::shared().networkConnection()->connection()->send(Messages::NetworkConnectionToWebProcess::StartDownload(privateBrowsingEnabled, policyDownloadID, request), 0);
246         return;
247     }
248 #endif
249
250     WebProcess::shared().downloadManager().startDownload(policyDownloadID, request);
251 }
252
253 void WebFrame::convertMainResourceLoadToDownload(DocumentLoader* documentLoader, const ResourceRequest& request, const ResourceResponse& response)
254 {
255     ASSERT(m_policyDownloadID);
256
257     uint64_t policyDownloadID = m_policyDownloadID;
258     m_policyDownloadID = 0;
259
260     ResourceLoader* mainResourceLoader = documentLoader->mainResourceLoader();
261
262 #if ENABLE(NETWORK_PROCESS)
263     if (WebProcess::shared().usesNetworkProcess()) {
264         // Use 0 to indicate that there is no main resource loader.
265         // This can happen if the main resource is in the WebCore memory cache.
266         uint64_t mainResourceLoadIdentifier;
267         if (mainResourceLoader)
268             mainResourceLoadIdentifier = mainResourceLoader->identifier();
269         else
270             mainResourceLoadIdentifier = 0;
271
272         WebProcess::shared().networkConnection()->connection()->send(Messages::NetworkConnectionToWebProcess::ConvertMainResourceLoadToDownload(mainResourceLoadIdentifier, policyDownloadID, request, response), 0);
273         return;
274     }
275 #endif
276
277     if (!mainResourceLoader) {
278         // The main resource has already been loaded. Start a new download instead.
279         WebProcess::shared().downloadManager().startDownload(policyDownloadID, request);
280         return;
281     }
282
283     WebProcess::shared().downloadManager().convertHandleToDownload(policyDownloadID, documentLoader->mainResourceLoader()->handle(), request, response);
284 }
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<ResourceBuffer> 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
316             WebFrameLoaderClient* webFrameLoaderClient = toWebFrameLoaderClient(child->loader()->client());
317             WebFrame* webFrame = webFrameLoaderClient ? webFrameLoaderClient->webFrame() : 0;
318             ASSERT(webFrame);
319
320             builder.append(webFrame->contentsAsString());
321         }
322         // FIXME: It may make sense to use toStringPreserveCapacity() here.
323         return builder.toString();
324     }
325
326     Document* document = m_coreFrame->document();
327     if (!document)
328         return String();
329
330     RefPtr<Element> documentElement = document->documentElement();
331     if (!documentElement)
332         return String();
333
334     RefPtr<Range> range = document->createRange();
335
336     ExceptionCode ec = 0;
337     range->selectNode(documentElement.get(), ec);
338     if (ec)
339         return String();
340
341     return plainText(range.get());
342 }
343
344 String WebFrame::selectionAsString() const 
345 {
346     if (!m_coreFrame)
347         return String();
348
349     return m_coreFrame->displayStringModifiedByEncoding(m_coreFrame->editor().selectedText());
350 }
351
352 IntSize WebFrame::size() const
353 {
354     if (!m_coreFrame)
355         return IntSize();
356
357     FrameView* frameView = m_coreFrame->view();
358     if (!frameView)
359         return IntSize();
360
361     return frameView->contentsSize();
362 }
363
364 bool WebFrame::isFrameSet() const
365 {
366     if (!m_coreFrame)
367         return false;
368
369     Document* document = m_coreFrame->document();
370     if (!document)
371         return false;
372     return document->isFrameSet();
373 }
374
375 bool WebFrame::isMainFrame() const
376 {
377     if (WebPage* p = page())
378         return p->mainWebFrame() == this;
379
380     return false;
381 }
382
383 String WebFrame::name() const
384 {
385     if (!m_coreFrame)
386         return String();
387
388     return m_coreFrame->tree()->uniqueName();
389 }
390
391 String WebFrame::url() const
392 {
393     if (!m_coreFrame)
394         return String();
395
396     DocumentLoader* documentLoader = m_coreFrame->loader()->documentLoader();
397     if (!documentLoader)
398         return String();
399
400     return documentLoader->url().string();
401 }
402
403 String WebFrame::innerText() const
404 {
405     if (!m_coreFrame)
406         return String();
407
408     if (!m_coreFrame->document()->documentElement())
409         return String();
410
411     return m_coreFrame->document()->documentElement()->innerText();
412 }
413
414 WebFrame* WebFrame::parentFrame() const
415 {
416     if (!m_coreFrame || !m_coreFrame->ownerElement() || !m_coreFrame->ownerElement()->document())
417         return 0;
418
419     WebFrameLoaderClient* webFrameLoaderClient = toWebFrameLoaderClient(m_coreFrame->ownerElement()->document()->frame()->loader()->client());
420     return webFrameLoaderClient ? webFrameLoaderClient->webFrame() : 0;
421 }
422
423 PassRefPtr<ImmutableArray> WebFrame::childFrames()
424 {
425     if (!m_coreFrame)
426         return ImmutableArray::create();
427
428     size_t size = m_coreFrame->tree()->childCount();
429     if (!size)
430         return ImmutableArray::create();
431
432     Vector<RefPtr<APIObject>> vector;
433     vector.reserveInitialCapacity(size);
434
435     for (Frame* child = m_coreFrame->tree()->firstChild(); child; child = child->tree()->nextSibling()) {
436         WebFrameLoaderClient* webFrameLoaderClient = toWebFrameLoaderClient(child->loader()->client());
437         WebFrame* webFrame = webFrameLoaderClient ? webFrameLoaderClient->webFrame() : 0;
438         ASSERT(webFrame);
439         vector.uncheckedAppend(webFrame);
440     }
441
442     return ImmutableArray::adopt(vector);
443 }
444
445 String WebFrame::layerTreeAsText() const
446 {
447     if (!m_coreFrame)
448         return "";
449
450     return m_coreFrame->layerTreeAsText(0);
451 }
452
453 unsigned WebFrame::pendingUnloadCount() const
454 {
455     if (!m_coreFrame)
456         return 0;
457
458     return m_coreFrame->document()->domWindow()->pendingUnloadEventListeners();
459 }
460
461 bool WebFrame::allowsFollowingLink(const WebCore::KURL& url) const
462 {
463     if (!m_coreFrame)
464         return true;
465         
466     return m_coreFrame->document()->securityOrigin()->canDisplay(url);
467 }
468
469 JSGlobalContextRef WebFrame::jsContext()
470 {
471     return toGlobalRef(m_coreFrame->script()->globalObject(mainThreadNormalWorld())->globalExec());
472 }
473
474 JSGlobalContextRef WebFrame::jsContextForWorld(InjectedBundleScriptWorld* world)
475 {
476     return toGlobalRef(m_coreFrame->script()->globalObject(world->coreWorld())->globalExec());
477 }
478
479 bool WebFrame::handlesPageScaleGesture() const
480 {
481     if (!m_coreFrame->document()->isPluginDocument())
482         return 0;
483
484     PluginDocument* pluginDocument = static_cast<PluginDocument*>(m_coreFrame->document());
485     PluginView* pluginView = static_cast<PluginView*>(pluginDocument->pluginWidget());
486
487     return pluginView->handlesPageScaleFactor();
488 }
489
490 IntRect WebFrame::contentBounds() const
491 {    
492     if (!m_coreFrame)
493         return IntRect();
494     
495     FrameView* view = m_coreFrame->view();
496     if (!view)
497         return IntRect();
498     
499     return IntRect(0, 0, view->contentsWidth(), view->contentsHeight());
500 }
501
502 IntRect WebFrame::visibleContentBounds() const
503 {
504     if (!m_coreFrame)
505         return IntRect();
506     
507     FrameView* view = m_coreFrame->view();
508     if (!view)
509         return IntRect();
510     
511     IntRect contentRect = view->visibleContentRect(ScrollableArea::IncludeScrollbars);
512     return IntRect(0, 0, contentRect.width(), contentRect.height());
513 }
514
515 IntRect WebFrame::visibleContentBoundsExcludingScrollbars() const
516 {
517     if (!m_coreFrame)
518         return IntRect();
519     
520     FrameView* view = m_coreFrame->view();
521     if (!view)
522         return IntRect();
523     
524     IntRect contentRect = view->visibleContentRect();
525     return IntRect(0, 0, contentRect.width(), contentRect.height());
526 }
527
528 IntSize WebFrame::scrollOffset() const
529 {
530     if (!m_coreFrame)
531         return IntSize();
532     
533     FrameView* view = m_coreFrame->view();
534     if (!view)
535         return IntSize();
536
537     return view->scrollOffset();
538 }
539
540 bool WebFrame::hasHorizontalScrollbar() const
541 {
542     if (!m_coreFrame)
543         return false;
544
545     FrameView* view = m_coreFrame->view();
546     if (!view)
547         return false;
548
549     return view->horizontalScrollbar();
550 }
551
552 bool WebFrame::hasVerticalScrollbar() const
553 {
554     if (!m_coreFrame)
555         return false;
556
557     FrameView* view = m_coreFrame->view();
558     if (!view)
559         return false;
560
561     return view->verticalScrollbar();
562 }
563
564 PassRefPtr<InjectedBundleHitTestResult> WebFrame::hitTest(const IntPoint point) const
565 {
566     if (!m_coreFrame)
567         return 0;
568
569     return InjectedBundleHitTestResult::create(m_coreFrame->eventHandler()->hitTestResultAtPoint(point, HitTestRequest::ReadOnly | HitTestRequest::Active | HitTestRequest::IgnoreClipping | HitTestRequest::DisallowShadowContent));
570 }
571
572 bool WebFrame::getDocumentBackgroundColor(double* red, double* green, double* blue, double* alpha)
573 {
574     if (!m_coreFrame)
575         return false;
576
577     FrameView* view = m_coreFrame->view();
578     if (!view)
579         return false;
580
581     Color bgColor = view->documentBackgroundColor();
582     if (!bgColor.isValid())
583         return false;
584
585     bgColor.getRGBA(*red, *green, *blue, *alpha);
586     return true;
587 }
588
589 bool WebFrame::containsAnyFormElements() const
590 {
591     if (!m_coreFrame)
592         return false;
593     
594     Document* document = m_coreFrame->document();
595     if (!document)
596         return false;
597
598     for (Node* node = document->documentElement(); node; node = NodeTraversal::next(node)) {
599         if (!node->isElementNode())
600             continue;
601         if (isHTMLFormElement(node))
602             return true;
603     }
604     return false;
605 }
606
607 bool WebFrame::containsAnyFormControls() const
608 {
609     if (!m_coreFrame)
610         return false;
611     
612     Document* document = m_coreFrame->document();
613     if (!document)
614         return false;
615
616     for (Node* node = document->documentElement(); node; node = NodeTraversal::next(node)) {
617         if (!node->isElementNode())
618             continue;
619         if (toElement(node)->hasTagName(HTMLNames::inputTag) || toElement(node)->hasTagName(HTMLNames::selectTag) || toElement(node)->hasTagName(HTMLNames::textareaTag))
620             return true;
621     }
622     return false;
623 }
624
625 void WebFrame::stopLoading()
626 {
627     if (!m_coreFrame)
628         return;
629
630     m_coreFrame->loader()->stopForUserCancel();
631 }
632
633 WebFrame* WebFrame::frameForContext(JSContextRef context)
634 {
635     JSObjectRef globalObjectRef = JSContextGetGlobalObject(context);
636     JSC::JSObject* globalObjectObj = toJS(globalObjectRef);
637     if (strcmp(globalObjectObj->classInfo()->className, "JSDOMWindowShell") != 0)
638         return 0;
639
640     Frame* coreFrame = static_cast<JSDOMWindowShell*>(globalObjectObj)->window()->impl()->frame();
641
642     WebFrameLoaderClient* webFrameLoaderClient = toWebFrameLoaderClient(coreFrame->loader()->client());
643     return webFrameLoaderClient ? webFrameLoaderClient->webFrame() : 0;
644 }
645
646 JSValueRef WebFrame::jsWrapperForWorld(InjectedBundleNodeHandle* nodeHandle, InjectedBundleScriptWorld* world)
647 {
648     if (!m_coreFrame)
649         return 0;
650
651     JSDOMWindow* globalObject = m_coreFrame->script()->globalObject(world->coreWorld());
652     ExecState* exec = globalObject->globalExec();
653
654     JSLockHolder lock(exec);
655     return toRef(exec, toJS(exec, globalObject, nodeHandle->coreNode()));
656 }
657
658 JSValueRef WebFrame::jsWrapperForWorld(InjectedBundleRangeHandle* rangeHandle, InjectedBundleScriptWorld* world)
659 {
660     if (!m_coreFrame)
661         return 0;
662
663     JSDOMWindow* globalObject = m_coreFrame->script()->globalObject(world->coreWorld());
664     ExecState* exec = globalObject->globalExec();
665
666     JSLockHolder lock(exec);
667     return toRef(exec, toJS(exec, globalObject, rangeHandle->coreRange()));
668 }
669
670 String WebFrame::counterValue(JSObjectRef element)
671 {
672     if (!toJS(element)->inherits(&JSElement::s_info))
673         return String();
674
675     return counterValueForElement(static_cast<JSElement*>(toJS(element))->impl());
676 }
677
678 String WebFrame::provisionalURL() const
679 {
680     if (!m_coreFrame)
681         return String();
682
683     return m_coreFrame->loader()->provisionalDocumentLoader()->url().string();
684 }
685
686 String WebFrame::suggestedFilenameForResourceWithURL(const KURL& url) const
687 {
688     if (!m_coreFrame)
689         return String();
690
691     DocumentLoader* loader = m_coreFrame->loader()->documentLoader();
692     if (!loader)
693         return String();
694
695     // First, try the main resource.
696     if (loader->url() == url)
697         return loader->response().suggestedFilename();
698
699     // Next, try subresources.
700     RefPtr<ArchiveResource> resource = loader->subresource(url);
701     if (resource)
702         return resource->response().suggestedFilename();
703
704     return page()->cachedSuggestedFilenameForURL(url);
705 }
706
707 String WebFrame::mimeTypeForResourceWithURL(const KURL& url) const
708 {
709     if (!m_coreFrame)
710         return String();
711
712     DocumentLoader* loader = m_coreFrame->loader()->documentLoader();
713     if (!loader)
714         return String();
715
716     // First, try the main resource.
717     if (loader->url() == url)
718         return loader->response().mimeType();
719
720     // Next, try subresources.
721     RefPtr<ArchiveResource> resource = loader->subresource(url);
722     if (resource)
723         return resource->mimeType();
724
725     return page()->cachedResponseMIMETypeForURL(url);
726 }
727
728 void WebFrame::setTextDirection(const String& direction)
729 {
730     if (!m_coreFrame)
731         return;
732
733     if (direction == "auto")
734         m_coreFrame->editor().setBaseWritingDirection(NaturalWritingDirection);
735     else if (direction == "ltr")
736         m_coreFrame->editor().setBaseWritingDirection(LeftToRightWritingDirection);
737     else if (direction == "rtl")
738         m_coreFrame->editor().setBaseWritingDirection(RightToLeftWritingDirection);
739 }
740
741 #if PLATFORM(MAC)
742
743 class WebFrameFilter : public FrameFilter {
744 public:
745     WebFrameFilter(WebFrame*, WebFrame::FrameFilterFunction, void* context);
746         
747 private:
748     virtual bool shouldIncludeSubframe(Frame*) const OVERRIDE;
749
750     WebFrame* m_topLevelWebFrame;
751     WebFrame::FrameFilterFunction m_callback;
752     void* m_context;
753 };
754
755 WebFrameFilter::WebFrameFilter(WebFrame* topLevelWebFrame, WebFrame::FrameFilterFunction callback, void* context)
756     : m_topLevelWebFrame(topLevelWebFrame)
757     , m_callback(callback)
758     , m_context(context)
759 {
760 }
761
762 bool WebFrameFilter::shouldIncludeSubframe(Frame* frame) const
763 {
764     if (!m_callback)
765         return true;
766
767     WebFrameLoaderClient* webFrameLoaderClient = toWebFrameLoaderClient(frame->loader()->client());
768     WebFrame* webFrame = webFrameLoaderClient ? webFrameLoaderClient->webFrame() : 0;
769     ASSERT(webFrame);
770
771     return m_callback(toAPI(m_topLevelWebFrame), toAPI(webFrame), m_context);
772 }
773
774 RetainPtr<CFDataRef> WebFrame::webArchiveData(FrameFilterFunction callback, void* context)
775 {
776     WebFrameFilter filter(this, callback, context);
777
778     if (RefPtr<LegacyWebArchive> archive = LegacyWebArchive::create(coreFrame()->document(), &filter))
779         return archive->rawDataRepresentation();
780     
781     return 0;
782 }
783 #endif
784     
785 } // namespace WebKit