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