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