1// Copyright 2014 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "config.h"
6#include "web/WebRemoteFrameImpl.h"
7
8#include "core/frame/FrameOwner.h"
9#include "core/frame/RemoteFrame.h"
10#include "public/platform/WebFloatRect.h"
11#include "public/platform/WebRect.h"
12#include "public/web/WebDocument.h"
13#include "public/web/WebPerformance.h"
14#include "public/web/WebRange.h"
15#include "web/WebLocalFrameImpl.h"
16#include "web/WebViewImpl.h"
17#include <v8/include/v8.h>
18
19using namespace WebCore;
20
21namespace blink {
22
23namespace {
24
25// Helper class to bridge communication for a local frame with a remote parent.
26// Currently, it serves two purposes:
27// 1. Allows the local frame's loader to retrieve sandbox flags associated with
28//    its owner element in another process.
29// 2. Trigger a load event on its owner element once it finishes a load.
30class RemoteBridgeFrameOwner : public FrameOwner {
31public:
32    explicit RemoteBridgeFrameOwner(PassRefPtr<WebLocalFrameImpl>);
33
34    virtual bool isLocal() const OVERRIDE;
35    virtual SandboxFlags sandboxFlags() const OVERRIDE;
36    virtual void dispatchLoad() OVERRIDE;
37
38private:
39    RefPtr<WebLocalFrameImpl> m_frame;
40};
41
42RemoteBridgeFrameOwner::RemoteBridgeFrameOwner(PassRefPtr<WebLocalFrameImpl> frame)
43    : m_frame(frame)
44{
45}
46
47bool RemoteBridgeFrameOwner::isLocal() const
48{
49    return false;
50}
51
52SandboxFlags RemoteBridgeFrameOwner::sandboxFlags() const
53{
54    // FIXME: Implement. Most likely grab it from m_frame.
55    return 0;
56}
57
58void RemoteBridgeFrameOwner::dispatchLoad()
59{
60    // FIXME: Implement. Most likely goes through m_frame->client().
61}
62
63// FIXME: This is just a placeholder frame owner to supply to RemoteFrame when
64// the parent is also a remote frame. Strictly speaking, this shouldn't be
65// necessary, since a remote frame shouldn't ever need to communicate with a
66// remote parent (there are no sandbox flags to retrieve in this case, nor can
67// the RemoteFrame itself load a document). In most circumstances, the check for
68// frame->owner() can be replaced with a check for frame->tree().parent(). Once
69// that's done, this class can be removed.
70class PlaceholderFrameOwner : public FrameOwner {
71public:
72    virtual bool isLocal() const OVERRIDE;
73    virtual SandboxFlags sandboxFlags() const OVERRIDE;
74    virtual void dispatchLoad() OVERRIDE;
75};
76
77bool PlaceholderFrameOwner::isLocal() const
78{
79    return false;
80}
81
82SandboxFlags PlaceholderFrameOwner::sandboxFlags() const
83{
84    ASSERT_NOT_REACHED();
85    return 0;
86}
87
88void PlaceholderFrameOwner::dispatchLoad()
89{
90    ASSERT_NOT_REACHED();
91}
92
93} // namespace
94
95WebRemoteFrame* WebRemoteFrame::create(WebFrameClient*)
96{
97    return adoptRef(new WebRemoteFrameImpl()).leakRef();
98}
99
100WebRemoteFrameImpl::WebRemoteFrameImpl()
101    : m_frameClient(this)
102{
103}
104
105WebRemoteFrameImpl::~WebRemoteFrameImpl()
106{
107}
108
109bool WebRemoteFrameImpl::isWebLocalFrame() const
110{
111    return false;
112}
113
114WebLocalFrame* WebRemoteFrameImpl::toWebLocalFrame()
115{
116    ASSERT_NOT_REACHED();
117    return 0;
118}
119
120bool WebRemoteFrameImpl::isWebRemoteFrame() const
121{
122    return true;
123}
124
125WebRemoteFrame* WebRemoteFrameImpl::toWebRemoteFrame()
126{
127    return this;
128}
129
130void WebRemoteFrameImpl::close()
131{
132    ASSERT_NOT_REACHED();
133}
134
135WebString WebRemoteFrameImpl::uniqueName() const
136{
137    ASSERT_NOT_REACHED();
138    return WebString();
139}
140
141WebString WebRemoteFrameImpl::assignedName() const
142{
143    ASSERT_NOT_REACHED();
144    return WebString();
145}
146
147void WebRemoteFrameImpl::setName(const WebString&)
148{
149    ASSERT_NOT_REACHED();
150}
151
152WebVector<WebIconURL> WebRemoteFrameImpl::iconURLs(int iconTypesMask) const
153{
154    ASSERT_NOT_REACHED();
155    return WebVector<WebIconURL>();
156}
157
158void WebRemoteFrameImpl::setIsRemote(bool)
159{
160    ASSERT_NOT_REACHED();
161}
162
163void WebRemoteFrameImpl::setRemoteWebLayer(WebLayer*)
164{
165    ASSERT_NOT_REACHED();
166}
167
168void WebRemoteFrameImpl::setPermissionClient(WebPermissionClient*)
169{
170    ASSERT_NOT_REACHED();
171}
172
173void WebRemoteFrameImpl::setSharedWorkerRepositoryClient(WebSharedWorkerRepositoryClient*)
174{
175    ASSERT_NOT_REACHED();
176}
177
178void WebRemoteFrameImpl::setCanHaveScrollbars(bool)
179{
180    ASSERT_NOT_REACHED();
181}
182
183WebSize WebRemoteFrameImpl::scrollOffset() const
184{
185    ASSERT_NOT_REACHED();
186    return WebSize();
187}
188
189void WebRemoteFrameImpl::setScrollOffset(const WebSize&)
190{
191    ASSERT_NOT_REACHED();
192}
193
194WebSize WebRemoteFrameImpl::minimumScrollOffset() const
195{
196    ASSERT_NOT_REACHED();
197    return WebSize();
198}
199
200WebSize WebRemoteFrameImpl::maximumScrollOffset() const
201{
202    ASSERT_NOT_REACHED();
203    return WebSize();
204}
205
206WebSize WebRemoteFrameImpl::contentsSize() const
207{
208    ASSERT_NOT_REACHED();
209    return WebSize();
210}
211
212bool WebRemoteFrameImpl::hasVisibleContent() const
213{
214    ASSERT_NOT_REACHED();
215    return false;
216}
217
218WebRect WebRemoteFrameImpl::visibleContentRect() const
219{
220    ASSERT_NOT_REACHED();
221    return WebRect();
222}
223
224bool WebRemoteFrameImpl::hasHorizontalScrollbar() const
225{
226    ASSERT_NOT_REACHED();
227    return false;
228}
229
230bool WebRemoteFrameImpl::hasVerticalScrollbar() const
231{
232    ASSERT_NOT_REACHED();
233    return false;
234}
235
236WebView* WebRemoteFrameImpl::view() const
237{
238    ASSERT_NOT_REACHED();
239    return 0;
240}
241
242void WebRemoteFrameImpl::removeChild(WebFrame* frame)
243{
244    WebFrame::removeChild(frame);
245    m_ownersForChildren.remove(frame);
246}
247
248WebDocument WebRemoteFrameImpl::document() const
249{
250    ASSERT_NOT_REACHED();
251    return WebDocument();
252}
253
254WebPerformance WebRemoteFrameImpl::performance() const
255{
256    ASSERT_NOT_REACHED();
257    return WebPerformance();
258}
259
260bool WebRemoteFrameImpl::dispatchBeforeUnloadEvent()
261{
262    ASSERT_NOT_REACHED();
263    return false;
264}
265
266void WebRemoteFrameImpl::dispatchUnloadEvent()
267{
268    ASSERT_NOT_REACHED();
269}
270
271NPObject* WebRemoteFrameImpl::windowObject() const
272{
273    ASSERT_NOT_REACHED();
274    return 0;
275}
276
277void WebRemoteFrameImpl::bindToWindowObject(const WebString& name, NPObject*)
278{
279    ASSERT_NOT_REACHED();
280}
281
282void WebRemoteFrameImpl::bindToWindowObject(const WebString& name, NPObject*, void*)
283{
284    ASSERT_NOT_REACHED();
285}
286
287void WebRemoteFrameImpl::executeScript(const WebScriptSource&)
288{
289    ASSERT_NOT_REACHED();
290}
291
292void WebRemoteFrameImpl::executeScriptInIsolatedWorld(
293    int worldID, const WebScriptSource* sources, unsigned numSources,
294    int extensionGroup)
295{
296    ASSERT_NOT_REACHED();
297}
298
299void WebRemoteFrameImpl::setIsolatedWorldSecurityOrigin(int worldID, const WebSecurityOrigin&)
300{
301    ASSERT_NOT_REACHED();
302}
303
304void WebRemoteFrameImpl::setIsolatedWorldContentSecurityPolicy(int worldID, const WebString&)
305{
306    ASSERT_NOT_REACHED();
307}
308
309void WebRemoteFrameImpl::addMessageToConsole(const WebConsoleMessage&)
310{
311    ASSERT_NOT_REACHED();
312}
313
314void WebRemoteFrameImpl::collectGarbage()
315{
316    ASSERT_NOT_REACHED();
317}
318
319bool WebRemoteFrameImpl::checkIfRunInsecureContent(const WebURL&) const
320{
321    ASSERT_NOT_REACHED();
322    return false;
323}
324
325v8::Handle<v8::Value> WebRemoteFrameImpl::executeScriptAndReturnValue(
326    const WebScriptSource&)
327{
328    ASSERT_NOT_REACHED();
329    return v8::Handle<v8::Value>();
330}
331
332void WebRemoteFrameImpl::executeScriptInIsolatedWorld(
333    int worldID, const WebScriptSource* sourcesIn, unsigned numSources,
334    int extensionGroup, WebVector<v8::Local<v8::Value> >* results)
335{
336    ASSERT_NOT_REACHED();
337}
338
339v8::Handle<v8::Value> WebRemoteFrameImpl::callFunctionEvenIfScriptDisabled(
340    v8::Handle<v8::Function>,
341    v8::Handle<v8::Value>,
342    int argc,
343    v8::Handle<v8::Value> argv[])
344{
345    ASSERT_NOT_REACHED();
346    return v8::Handle<v8::Value>();
347}
348
349v8::Local<v8::Context> WebRemoteFrameImpl::mainWorldScriptContext() const
350{
351    ASSERT_NOT_REACHED();
352    return v8::Local<v8::Context>();
353}
354
355void WebRemoteFrameImpl::reload(bool ignoreCache)
356{
357    ASSERT_NOT_REACHED();
358}
359
360void WebRemoteFrameImpl::reloadWithOverrideURL(const WebURL& overrideUrl, bool ignoreCache)
361{
362    ASSERT_NOT_REACHED();
363}
364
365void WebRemoteFrameImpl::loadRequest(const WebURLRequest&)
366{
367    ASSERT_NOT_REACHED();
368}
369
370void WebRemoteFrameImpl::loadHistoryItem(const WebHistoryItem&, WebHistoryLoadType, WebURLRequest::CachePolicy)
371{
372    ASSERT_NOT_REACHED();
373}
374
375void WebRemoteFrameImpl::loadData(
376    const WebData&, const WebString& mimeType, const WebString& textEncoding,
377    const WebURL& baseURL, const WebURL& unreachableURL, bool replace)
378{
379    ASSERT_NOT_REACHED();
380}
381
382void WebRemoteFrameImpl::loadHTMLString(
383    const WebData& html, const WebURL& baseURL, const WebURL& unreachableURL,
384    bool replace)
385{
386    ASSERT_NOT_REACHED();
387}
388
389bool WebRemoteFrameImpl::isLoading() const
390{
391    ASSERT_NOT_REACHED();
392    return false;
393}
394
395void WebRemoteFrameImpl::stopLoading()
396{
397    ASSERT_NOT_REACHED();
398}
399
400WebDataSource* WebRemoteFrameImpl::provisionalDataSource() const
401{
402    ASSERT_NOT_REACHED();
403    return 0;
404}
405
406WebDataSource* WebRemoteFrameImpl::dataSource() const
407{
408    ASSERT_NOT_REACHED();
409    return 0;
410}
411
412void WebRemoteFrameImpl::enableViewSourceMode(bool enable)
413{
414    ASSERT_NOT_REACHED();
415}
416
417bool WebRemoteFrameImpl::isViewSourceModeEnabled() const
418{
419    ASSERT_NOT_REACHED();
420    return false;
421}
422
423void WebRemoteFrameImpl::setReferrerForRequest(WebURLRequest&, const WebURL& referrer)
424{
425    ASSERT_NOT_REACHED();
426}
427
428void WebRemoteFrameImpl::dispatchWillSendRequest(WebURLRequest&)
429{
430    ASSERT_NOT_REACHED();
431}
432
433WebURLLoader* WebRemoteFrameImpl::createAssociatedURLLoader(const WebURLLoaderOptions&)
434{
435    ASSERT_NOT_REACHED();
436    return 0;
437}
438
439unsigned WebRemoteFrameImpl::unloadListenerCount() const
440{
441    ASSERT_NOT_REACHED();
442    return 0;
443}
444
445void WebRemoteFrameImpl::replaceSelection(const WebString&)
446{
447    ASSERT_NOT_REACHED();
448}
449
450void WebRemoteFrameImpl::insertText(const WebString&)
451{
452    ASSERT_NOT_REACHED();
453}
454
455void WebRemoteFrameImpl::setMarkedText(const WebString&, unsigned location, unsigned length)
456{
457    ASSERT_NOT_REACHED();
458}
459
460void WebRemoteFrameImpl::unmarkText()
461{
462    ASSERT_NOT_REACHED();
463}
464
465bool WebRemoteFrameImpl::hasMarkedText() const
466{
467    ASSERT_NOT_REACHED();
468    return false;
469}
470
471WebRange WebRemoteFrameImpl::markedRange() const
472{
473    ASSERT_NOT_REACHED();
474    return WebRange();
475}
476
477bool WebRemoteFrameImpl::firstRectForCharacterRange(unsigned location, unsigned length, WebRect&) const
478{
479    ASSERT_NOT_REACHED();
480    return false;
481}
482
483size_t WebRemoteFrameImpl::characterIndexForPoint(const WebPoint&) const
484{
485    ASSERT_NOT_REACHED();
486    return 0;
487}
488
489bool WebRemoteFrameImpl::executeCommand(const WebString&, const WebNode&)
490{
491    ASSERT_NOT_REACHED();
492    return false;
493}
494
495bool WebRemoteFrameImpl::executeCommand(const WebString&, const WebString& value, const WebNode&)
496{
497    ASSERT_NOT_REACHED();
498    return false;
499}
500
501bool WebRemoteFrameImpl::isCommandEnabled(const WebString&) const
502{
503    ASSERT_NOT_REACHED();
504    return false;
505}
506
507void WebRemoteFrameImpl::enableContinuousSpellChecking(bool)
508{
509    ASSERT_NOT_REACHED();
510}
511
512bool WebRemoteFrameImpl::isContinuousSpellCheckingEnabled() const
513{
514    ASSERT_NOT_REACHED();
515    return false;
516}
517
518void WebRemoteFrameImpl::requestTextChecking(const WebElement&)
519{
520    ASSERT_NOT_REACHED();
521}
522
523void WebRemoteFrameImpl::replaceMisspelledRange(const WebString&)
524{
525    ASSERT_NOT_REACHED();
526}
527
528void WebRemoteFrameImpl::removeSpellingMarkers()
529{
530    ASSERT_NOT_REACHED();
531}
532
533bool WebRemoteFrameImpl::hasSelection() const
534{
535    ASSERT_NOT_REACHED();
536    return false;
537}
538
539WebRange WebRemoteFrameImpl::selectionRange() const
540{
541    ASSERT_NOT_REACHED();
542    return WebRange();
543}
544
545WebString WebRemoteFrameImpl::selectionAsText() const
546{
547    ASSERT_NOT_REACHED();
548    return WebString();
549}
550
551WebString WebRemoteFrameImpl::selectionAsMarkup() const
552{
553    ASSERT_NOT_REACHED();
554    return WebString();
555}
556
557bool WebRemoteFrameImpl::selectWordAroundCaret()
558{
559    ASSERT_NOT_REACHED();
560    return false;
561}
562
563void WebRemoteFrameImpl::selectRange(const WebPoint& base, const WebPoint& extent)
564{
565    ASSERT_NOT_REACHED();
566}
567
568void WebRemoteFrameImpl::selectRange(const WebRange&)
569{
570    ASSERT_NOT_REACHED();
571}
572
573void WebRemoteFrameImpl::moveRangeSelection(const WebPoint& base, const WebPoint& extent)
574{
575    ASSERT_NOT_REACHED();
576}
577
578void WebRemoteFrameImpl::moveCaretSelection(const WebPoint&)
579{
580    ASSERT_NOT_REACHED();
581}
582
583bool WebRemoteFrameImpl::setEditableSelectionOffsets(int start, int end)
584{
585    ASSERT_NOT_REACHED();
586    return false;
587}
588
589bool WebRemoteFrameImpl::setCompositionFromExistingText(int compositionStart, int compositionEnd, const WebVector<WebCompositionUnderline>& underlines)
590{
591    ASSERT_NOT_REACHED();
592    return false;
593}
594
595void WebRemoteFrameImpl::extendSelectionAndDelete(int before, int after)
596{
597    ASSERT_NOT_REACHED();
598}
599
600void WebRemoteFrameImpl::setCaretVisible(bool)
601{
602    ASSERT_NOT_REACHED();
603}
604
605int WebRemoteFrameImpl::printBegin(const WebPrintParams&, const WebNode& constrainToNode)
606{
607    ASSERT_NOT_REACHED();
608    return 0;
609}
610
611float WebRemoteFrameImpl::printPage(int pageToPrint, WebCanvas*)
612{
613    ASSERT_NOT_REACHED();
614    return 0.0;
615}
616
617float WebRemoteFrameImpl::getPrintPageShrink(int page)
618{
619    ASSERT_NOT_REACHED();
620    return 0.0;
621}
622
623void WebRemoteFrameImpl::printEnd()
624{
625    ASSERT_NOT_REACHED();
626}
627
628bool WebRemoteFrameImpl::isPrintScalingDisabledForPlugin(const WebNode&)
629{
630    ASSERT_NOT_REACHED();
631    return false;
632}
633
634bool WebRemoteFrameImpl::hasCustomPageSizeStyle(int pageIndex)
635{
636    ASSERT_NOT_REACHED();
637    return false;
638}
639
640bool WebRemoteFrameImpl::isPageBoxVisible(int pageIndex)
641{
642    ASSERT_NOT_REACHED();
643    return false;
644}
645
646void WebRemoteFrameImpl::pageSizeAndMarginsInPixels(
647    int pageIndex,
648    WebSize& pageSize,
649    int& marginTop,
650    int& marginRight,
651    int& marginBottom,
652    int& marginLeft)
653{
654    ASSERT_NOT_REACHED();
655}
656
657WebString WebRemoteFrameImpl::pageProperty(const WebString& propertyName, int pageIndex)
658{
659    ASSERT_NOT_REACHED();
660    return WebString();
661}
662
663void WebRemoteFrameImpl::printPagesWithBoundaries(WebCanvas*, const WebSize&)
664{
665    ASSERT_NOT_REACHED();
666}
667
668bool WebRemoteFrameImpl::find(
669    int identifier, const WebString& searchText, const WebFindOptions&,
670    bool wrapWithinFrame, WebRect* selectionRect)
671{
672    ASSERT_NOT_REACHED();
673    return false;
674}
675
676void WebRemoteFrameImpl::stopFinding(bool clearSelection)
677{
678    ASSERT_NOT_REACHED();
679}
680
681void WebRemoteFrameImpl::scopeStringMatches(
682    int identifier, const WebString& searchText, const WebFindOptions&,
683    bool reset)
684{
685    ASSERT_NOT_REACHED();
686}
687
688void WebRemoteFrameImpl::cancelPendingScopingEffort()
689{
690    ASSERT_NOT_REACHED();
691}
692
693void WebRemoteFrameImpl::increaseMatchCount(int count, int identifier)
694{
695    ASSERT_NOT_REACHED();
696}
697
698void WebRemoteFrameImpl::resetMatchCount()
699{
700    ASSERT_NOT_REACHED();
701}
702
703int WebRemoteFrameImpl::findMatchMarkersVersion() const
704{
705    ASSERT_NOT_REACHED();
706    return 0;
707}
708
709WebFloatRect WebRemoteFrameImpl::activeFindMatchRect()
710{
711    ASSERT_NOT_REACHED();
712    return WebFloatRect();
713}
714
715void WebRemoteFrameImpl::findMatchRects(WebVector<WebFloatRect>&)
716{
717    ASSERT_NOT_REACHED();
718}
719
720int WebRemoteFrameImpl::selectNearestFindMatch(const WebFloatPoint&, WebRect* selectionRect)
721{
722    ASSERT_NOT_REACHED();
723    return 0;
724}
725
726void WebRemoteFrameImpl::setTickmarks(const WebVector<WebRect>&)
727{
728    ASSERT_NOT_REACHED();
729}
730
731void WebRemoteFrameImpl::sendOrientationChangeEvent()
732{
733    ASSERT_NOT_REACHED();
734}
735
736void WebRemoteFrameImpl::dispatchMessageEventWithOriginCheck(
737    const WebSecurityOrigin& intendedTargetOrigin,
738    const WebDOMEvent&)
739{
740    ASSERT_NOT_REACHED();
741}
742
743WebString WebRemoteFrameImpl::contentAsText(size_t maxChars) const
744{
745    ASSERT_NOT_REACHED();
746    return WebString();
747}
748
749WebString WebRemoteFrameImpl::contentAsMarkup() const
750{
751    ASSERT_NOT_REACHED();
752    return WebString();
753}
754
755WebString WebRemoteFrameImpl::renderTreeAsText(RenderAsTextControls toShow) const
756{
757    ASSERT_NOT_REACHED();
758    return WebString();
759}
760
761WebString WebRemoteFrameImpl::markerTextForListItem(const WebElement&) const
762{
763    ASSERT_NOT_REACHED();
764    return WebString();
765}
766
767WebRect WebRemoteFrameImpl::selectionBoundsRect() const
768{
769    ASSERT_NOT_REACHED();
770    return WebRect();
771}
772
773bool WebRemoteFrameImpl::selectionStartHasSpellingMarkerFor(int from, int length) const
774{
775    ASSERT_NOT_REACHED();
776    return false;
777}
778
779WebString WebRemoteFrameImpl::layerTreeAsText(bool showDebugInfo) const
780{
781    ASSERT_NOT_REACHED();
782    return WebString();
783}
784
785WebLocalFrame* WebRemoteFrameImpl::createLocalChild(const WebString& name, WebFrameClient* client)
786{
787    WebLocalFrameImpl* child = toWebLocalFrameImpl(WebLocalFrame::create(client));
788    HashMap<WebFrame*, OwnPtr<FrameOwner> >::AddResult result =
789        m_ownersForChildren.add(child, adoptPtr(new RemoteBridgeFrameOwner(child)));
790    appendChild(child);
791    // FIXME: currently this calls LocalFrame::init() on the created LocalFrame, which may
792    // result in the browser observing two navigations to about:blank (one from the initial
793    // frame creation, and one from swapping it into the remote process). FrameLoader might
794    // need a special initialization function for this case to avoid that duplicate navigation.
795    child->initializeAsChildFrame(frame()->host(), result.storedValue->value.get(), name, AtomicString());
796    // Partially related with the above FIXME--the init() call may trigger JS dispatch. However,
797    // if the parent is remote, it should never be detached synchronously...
798    ASSERT(child->frame());
799    return child;
800}
801
802void WebRemoteFrameImpl::initializeAsMainFrame(Page* page)
803{
804    setWebCoreFrame(RemoteFrame::create(&m_frameClient, &page->frameHost(), 0));
805}
806
807WebRemoteFrame* WebRemoteFrameImpl::createRemoteChild(const WebString& name, WebFrameClient* client)
808{
809    WebRemoteFrameImpl* child = toWebRemoteFrameImpl(WebRemoteFrame::create(client));
810    HashMap<WebFrame*, OwnPtr<FrameOwner> >::AddResult result =
811        m_ownersForChildren.add(child, adoptPtr(new PlaceholderFrameOwner));
812    appendChild(child);
813    RefPtr<RemoteFrame> childFrame = RemoteFrame::create(&child->m_frameClient, frame()->host(), result.storedValue->value.get());
814    child->setWebCoreFrame(childFrame);
815    childFrame->tree().setName(name, AtomicString());
816    return child;
817}
818
819void WebRemoteFrameImpl::setWebCoreFrame(PassRefPtr<RemoteFrame> frame)
820{
821    m_frame = frame;
822}
823
824WebRemoteFrameImpl* WebRemoteFrameImpl::fromFrame(RemoteFrame& frame)
825{
826    if (!frame.client())
827        return 0;
828    return static_cast<RemoteFrameClient*>(frame.client())->webFrame();
829}
830
831} // namespace blink
832
833