blob: 1943a85561a0a1532dd6762f7aa613ffa32afffd [file] [log] [blame]
/*
* Copyright (C) 2009 Google Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
// How ownership works
// -------------------
//
// Big oh represents a refcounted relationship: owner O--- ownee
//
// WebView (for the toplevel frame only)
// O
// | WebFrame
// | O
// | |
// Page O------- LocalFrame (m_mainFrame) O-------O FrameView
// ||
// ||
// FrameLoader
//
// FrameLoader and LocalFrame are formerly one object that was split apart
// because it got too big. They basically have the same lifetime, hence the
// double line.
//
// From the perspective of the embedder, WebFrame is simply an object that it
// allocates by calling WebFrame::create() and must be freed by calling close().
// Internally, WebFrame is actually refcounted and it holds a reference to its
// corresponding LocalFrame in blink.
//
// Oilpan: the middle objects + Page in the above diagram are Oilpan heap
// allocated, WebView and FrameView are currently not. In terms of ownership
// and control, the relationships stays the same, but the references from the
// off-heap WebView to the on-heap Page is handled by a Persistent<>, not a
// RefPtr<>. Similarly, the mutual strong references between the on-heap
// LocalFrame and the off-heap FrameView is through a RefPtr (from LocalFrame
// to FrameView), and a Persistent refers to the LocalFrame in the other
// direction.
//
// From the embedder's point of view, the use of Oilpan brings no changes.
// close() must still be used to signal that the embedder is through with the
// WebFrame. Calling it will bring about the release and finalization of the
// frame object, and everything underneath.
//
// How frames are destroyed
// ------------------------
//
// The main frame is never destroyed and is re-used. The FrameLoader is re-used
// and a reference to the main frame is kept by the Page.
//
// When frame content is replaced, all subframes are destroyed. This happens
// in Frame::detachChildren for each subframe in a pre-order depth-first
// traversal. Note that child node order may not match DOM node order!
// detachChildren() (virtually) calls Frame::detach(), which again calls
// LocalFrameClient::detached(). This triggers WebFrame to clear its reference
// to LocalFrame. LocalFrameClient::detached() also notifies the embedder via
// WebFrameClient that the frame is detached. Most embedders will invoke
// close() on the WebFrame at this point, triggering its deletion unless
// something else is still retaining a reference.
//
// The client is expected to be set whenever the WebLocalFrameImpl is attached
// to the DOM.
#include "web/WebLocalFrameImpl.h"
#include <algorithm>
#include <memory>
#include <utility>
#include "bindings/core/v8/BindingSecurity.h"
#include "bindings/core/v8/DOMWrapperWorld.h"
#include "bindings/core/v8/ExceptionState.h"
#include "bindings/core/v8/ScriptController.h"
#include "bindings/core/v8/ScriptSourceCode.h"
#include "bindings/core/v8/ScriptValue.h"
#include "bindings/core/v8/SourceLocation.h"
#include "bindings/core/v8/V8Binding.h"
#include "bindings/core/v8/V8GCController.h"
#include "bindings/core/v8/V8PerIsolateData.h"
#include "core/HTMLNames.h"
#include "core/dom/Document.h"
#include "core/dom/DocumentUserGestureToken.h"
#include "core/dom/IconURL.h"
#include "core/dom/MessagePort.h"
#include "core/dom/Node.h"
#include "core/dom/NodeTraversal.h"
#include "core/dom/shadow/ShadowRoot.h"
#include "core/editing/EditingUtilities.h"
#include "core/editing/Editor.h"
#include "core/editing/FrameSelection.h"
#include "core/editing/InputMethodController.h"
#include "core/editing/PlainTextRange.h"
#include "core/editing/TextAffinity.h"
#include "core/editing/iterators/TextIterator.h"
#include "core/editing/serializers/Serialization.h"
#include "core/editing/spellcheck/SpellChecker.h"
#include "core/frame/FrameView.h"
#include "core/frame/LocalDOMWindow.h"
#include "core/frame/PageScaleConstraintsSet.h"
#include "core/frame/RemoteFrame.h"
#include "core/frame/ScreenOrientationController.h"
#include "core/frame/Settings.h"
#include "core/frame/SmartClip.h"
#include "core/frame/UseCounter.h"
#include "core/frame/VisualViewport.h"
#include "core/html/HTMLAnchorElement.h"
#include "core/html/HTMLCollection.h"
#include "core/html/HTMLFormElement.h"
#include "core/html/HTMLFrameElementBase.h"
#include "core/html/HTMLFrameOwnerElement.h"
#include "core/html/HTMLHeadElement.h"
#include "core/html/HTMLImageElement.h"
#include "core/html/HTMLInputElement.h"
#include "core/html/HTMLLinkElement.h"
#include "core/html/PluginDocument.h"
#include "core/input/EventHandler.h"
#include "core/inspector/ConsoleMessage.h"
#include "core/layout/HitTestResult.h"
#include "core/layout/LayoutObject.h"
#include "core/layout/api/LayoutPartItem.h"
#include "core/layout/api/LayoutViewItem.h"
#include "core/loader/DocumentLoader.h"
#include "core/loader/FrameLoadRequest.h"
#include "core/loader/FrameLoader.h"
#include "core/loader/HistoryItem.h"
#include "core/loader/MixedContentChecker.h"
#include "core/loader/NavigationScheduler.h"
#include "core/page/FocusController.h"
#include "core/page/FrameTree.h"
#include "core/page/Page.h"
#include "core/page/PrintContext.h"
#include "core/paint/PaintLayer.h"
#include "core/paint/TransformRecorder.h"
#include "core/style/StyleInheritedData.h"
#include "core/timing/DOMWindowPerformance.h"
#include "core/timing/Performance.h"
#include "platform/ScriptForbiddenScope.h"
#include "platform/UserGestureIndicator.h"
#include "platform/WebFrameScheduler.h"
#include "platform/clipboard/ClipboardUtilities.h"
#include "platform/fonts/FontCache.h"
#include "platform/graphics/GraphicsContext.h"
#include "platform/graphics/GraphicsLayerClient.h"
#include "platform/graphics/paint/ClipRecorder.h"
#include "platform/graphics/paint/DisplayItemCacheSkipper.h"
#include "platform/graphics/paint/DrawingRecorder.h"
#include "platform/graphics/paint/PaintRecordBuilder.h"
#include "platform/graphics/skia/SkiaUtils.h"
#include "platform/heap/Handle.h"
#include "platform/instrumentation/tracing/TraceEvent.h"
#include "platform/loader/fetch/ResourceFetcher.h"
#include "platform/loader/fetch/ResourceRequest.h"
#include "platform/loader/fetch/SubstituteData.h"
#include "platform/scroll/ScrollTypes.h"
#include "platform/scroll/ScrollbarTheme.h"
#include "platform/weborigin/KURL.h"
#include "platform/weborigin/SchemeRegistry.h"
#include "platform/weborigin/SecurityPolicy.h"
#include "public/platform/WebDoubleSize.h"
#include "public/platform/WebFloatPoint.h"
#include "public/platform/WebFloatRect.h"
#include "public/platform/WebLayer.h"
#include "public/platform/WebPoint.h"
#include "public/platform/WebRect.h"
#include "public/platform/WebSecurityOrigin.h"
#include "public/platform/WebSize.h"
#include "public/platform/WebURLError.h"
#include "public/platform/WebVector.h"
#include "public/web/WebAssociatedURLLoaderOptions.h"
#include "public/web/WebAutofillClient.h"
#include "public/web/WebConsoleMessage.h"
#include "public/web/WebDOMEvent.h"
#include "public/web/WebDocument.h"
#include "public/web/WebFindOptions.h"
#include "public/web/WebFormElement.h"
#include "public/web/WebFrameClient.h"
#include "public/web/WebFrameOwnerProperties.h"
#include "public/web/WebHistoryItem.h"
#include "public/web/WebIconURL.h"
#include "public/web/WebInputElement.h"
#include "public/web/WebKit.h"
#include "public/web/WebNode.h"
#include "public/web/WebPerformance.h"
#include "public/web/WebPlugin.h"
#include "public/web/WebPrintParams.h"
#include "public/web/WebPrintPresetOptions.h"
#include "public/web/WebRange.h"
#include "public/web/WebScriptSource.h"
#include "public/web/WebSerializedScriptValue.h"
#include "public/web/WebTreeScopeType.h"
#include "skia/ext/platform_canvas.h"
#include "web/CompositionUnderlineVectorBuilder.h"
#include "web/FindInPageCoordinates.h"
#include "web/RemoteFrameOwner.h"
#include "web/SharedWorkerRepositoryClientImpl.h"
#include "web/SuspendableScriptExecutor.h"
#include "web/TextFinder.h"
#include "web/WebAssociatedURLLoaderImpl.h"
#include "web/WebDataSourceImpl.h"
#include "web/WebDevToolsAgentImpl.h"
#include "web/WebFrameWidgetImpl.h"
#include "web/WebPluginContainerImpl.h"
#include "web/WebRemoteFrameImpl.h"
#include "web/WebViewImpl.h"
#include "wtf/CurrentTime.h"
#include "wtf/HashMap.h"
#include "wtf/PtrUtil.h"
namespace blink {
static int frameCount = 0;
static HeapVector<ScriptSourceCode> createSourcesVector(
const WebScriptSource* sourcesIn,
unsigned numSources) {
HeapVector<ScriptSourceCode> sources;
sources.append(sourcesIn, numSources);
return sources;
}
WebPluginContainerImpl* WebLocalFrameImpl::pluginContainerFromFrame(
LocalFrame* frame) {
if (!frame)
return 0;
if (!frame->document() || !frame->document()->isPluginDocument())
return 0;
PluginDocument* pluginDocument = toPluginDocument(frame->document());
return toWebPluginContainerImpl(pluginDocument->pluginView());
}
WebPluginContainerImpl* WebLocalFrameImpl::currentPluginContainer(
LocalFrame* frame,
Node* node) {
WebPluginContainerImpl* pluginContainer = pluginContainerFromFrame(frame);
if (pluginContainer)
return pluginContainer;
if (!node) {
DCHECK(frame->document());
node = frame->document()->focusedElement();
}
return toWebPluginContainerImpl(WebNode::pluginContainerFromNode(node));
}
// Simple class to override some of PrintContext behavior. Some of the methods
// made virtual so that they can be overridden by ChromePluginPrintContext.
class ChromePrintContext : public PrintContext {
WTF_MAKE_NONCOPYABLE(ChromePrintContext);
public:
ChromePrintContext(LocalFrame* frame)
: PrintContext(frame), m_printedPageWidth(0) {}
~ChromePrintContext() override {}
virtual void begin(float width, float height) {
DCHECK(!m_printedPageWidth);
m_printedPageWidth = width;
m_printedPageHeight = height;
PrintContext::begin(m_printedPageWidth, height);
}
virtual float getPageShrink(int pageNumber) const {
IntRect pageRect = m_pageRects[pageNumber];
return m_printedPageWidth / pageRect.width();
}
float spoolSinglePage(WebCanvas* canvas, int pageNumber) {
dispatchEventsForPrintingOnAllFrames();
if (!frame()->document() || frame()->document()->layoutViewItem().isNull())
return 0;
frame()->view()->updateAllLifecyclePhasesExceptPaint();
if (!frame()->document() || frame()->document()->layoutViewItem().isNull())
return 0;
// The page rect gets scaled and translated, so specify the entire
// print content area here as the recording rect.
IntRect bounds(0, 0, m_printedPageHeight, m_printedPageWidth);
PaintRecordBuilder builder(bounds, &canvas->getMetaData());
builder.context().setPrinting(true);
builder.context().beginRecording(bounds);
float scale = spoolPage(builder.context(), pageNumber, bounds);
canvas->PlaybackPaintRecord(builder.context().endRecording());
return scale;
}
void spoolAllPagesWithBoundaries(WebCanvas* canvas,
const FloatSize& pageSizeInPixels) {
dispatchEventsForPrintingOnAllFrames();
if (!frame()->document() || frame()->document()->layoutViewItem().isNull())
return;
frame()->view()->updateAllLifecyclePhasesExceptPaint();
if (!frame()->document() || frame()->document()->layoutViewItem().isNull())
return;
float pageHeight;
computePageRects(FloatRect(FloatPoint(0, 0), pageSizeInPixels), 0, 0, 1,
pageHeight);
const float pageWidth = pageSizeInPixels.width();
size_t numPages = pageRects().size();
int totalHeight = numPages * (pageSizeInPixels.height() + 1) - 1;
IntRect allPagesRect(0, 0, pageWidth, totalHeight);
PaintRecordBuilder builder(allPagesRect, &canvas->getMetaData());
{
GraphicsContext& context = builder.context();
context.setPrinting(true);
context.beginRecording(allPagesRect);
// Fill the whole background by white.
context.fillRect(FloatRect(0, 0, pageWidth, totalHeight), Color::white);
int currentHeight = 0;
for (size_t pageIndex = 0; pageIndex < numPages; pageIndex++) {
// Draw a line for a page boundary if this isn't the first page.
if (pageIndex > 0) {
context.save();
context.setStrokeColor(Color(0, 0, 255));
context.setFillColor(Color(0, 0, 255));
context.drawLine(IntPoint(0, currentHeight),
IntPoint(pageWidth, currentHeight));
context.restore();
}
AffineTransform transform;
transform.translate(0, currentHeight);
#if OS(WIN) || OS(MACOSX)
// Account for the disabling of scaling in spoolPage. In the context
// of spoolAllPagesWithBoundaries the scale HAS NOT been pre-applied.
float scale = getPageShrink(pageIndex);
transform.scale(scale, scale);
#endif
context.save();
context.concatCTM(transform);
spoolPage(context, pageIndex, allPagesRect);
context.restore();
currentHeight += pageSizeInPixels.height() + 1;
}
canvas->PlaybackPaintRecord(context.endRecording());
}
}
protected:
// Spools the printed page, a subrect of frame(). Skip the scale step.
// NativeTheme doesn't play well with scaling. Scaling is done browser side
// instead. Returns the scale to be applied.
// On Linux, we don't have the problem with NativeTheme, hence we let WebKit
// do the scaling and ignore the return value.
virtual float spoolPage(GraphicsContext& context,
int pageNumber,
const IntRect& bounds) {
IntRect pageRect = m_pageRects[pageNumber];
float scale = m_printedPageWidth / pageRect.width();
AffineTransform transform;
#if OS(POSIX) && !OS(MACOSX)
transform.scale(scale);
#endif
transform.translate(static_cast<float>(-pageRect.x()),
static_cast<float>(-pageRect.y()));
context.save();
context.concatCTM(transform);
context.clipRect(pageRect);
PaintRecordBuilder builder(bounds, &context.canvas()->getMetaData());
// The local scope is so that the cache skipper is destroyed before
// we call endRecording().
{
DisplayItemCacheSkipper skipper(builder.context());
frame()->view()->paintContents(builder.context(), GlobalPaintNormalPhase,
pageRect);
DrawingRecorder lineBoundaryRecorder(
builder.context(), builder,
DisplayItem::kPrintedContentDestinationLocations, pageRect);
outputLinkedDestinations(builder.context(), pageRect);
}
context.drawRecord(builder.endRecording());
context.restore();
return scale;
}
private:
void dispatchEventsForPrintingOnAllFrames() {
HeapVector<Member<Document>> documents;
for (Frame* currentFrame = frame(); currentFrame;
currentFrame = currentFrame->tree().traverseNext(frame())) {
if (currentFrame->isLocalFrame())
documents.push_back(toLocalFrame(currentFrame)->document());
}
for (auto& doc : documents)
doc->dispatchEventsForPrinting();
}
// Set when printing.
float m_printedPageWidth;
float m_printedPageHeight;
};
// Simple class to override some of PrintContext behavior. This is used when
// the frame hosts a plugin that supports custom printing. In this case, we
// want to delegate all printing related calls to the plugin.
class ChromePluginPrintContext final : public ChromePrintContext {
public:
ChromePluginPrintContext(LocalFrame* frame,
WebPluginContainerImpl* plugin,
const WebPrintParams& printParams)
: ChromePrintContext(frame),
m_plugin(plugin),
m_printParams(printParams) {}
~ChromePluginPrintContext() override {}
DEFINE_INLINE_VIRTUAL_TRACE() {
visitor->trace(m_plugin);
ChromePrintContext::trace(visitor);
}
void begin(float width, float height) override {}
void end() override { m_plugin->printEnd(); }
float getPageShrink(int pageNumber) const override {
// We don't shrink the page (maybe we should ask the widget ??)
return 1.0;
}
void computePageRects(const FloatRect& printRect,
float headerHeight,
float footerHeight,
float userScaleFactor,
float& outPageHeight) override {
m_printParams.printContentArea = IntRect(printRect);
m_pageRects.fill(IntRect(printRect), m_plugin->printBegin(m_printParams));
}
void computePageRectsWithPageSize(
const FloatSize& pageSizeInPixels) override {
NOTREACHED();
}
protected:
// Spools the printed page, a subrect of frame(). Skip the scale step.
// NativeTheme doesn't play well with scaling. Scaling is done browser side
// instead. Returns the scale to be applied.
float spoolPage(GraphicsContext& context,
int pageNumber,
const IntRect& bounds) override {
IntRect pageRect = m_pageRects[pageNumber];
PaintRecordBuilder builder(bounds, &context.canvas()->getMetaData());
// The local scope is so that the cache skipper is destroyed before
// we call endRecording().
{
DisplayItemCacheSkipper skipper(builder.context());
m_plugin->printPage(pageNumber, builder.context(), pageRect);
}
context.drawRecord(builder.endRecording());
return 1.0;
}
private:
// Set when printing.
Member<WebPluginContainerImpl> m_plugin;
WebPrintParams m_printParams;
};
static WebDataSource* DataSourceForDocLoader(DocumentLoader* loader) {
return loader ? WebDataSourceImpl::fromDocumentLoader(loader) : 0;
}
// WebFrame -------------------------------------------------------------------
int WebFrame::instanceCount() {
return frameCount;
}
WebLocalFrame* WebLocalFrame::frameForCurrentContext() {
v8::Local<v8::Context> context =
v8::Isolate::GetCurrent()->GetCurrentContext();
if (context.IsEmpty())
return 0;
return frameForContext(context);
}
WebLocalFrame* WebLocalFrame::frameForContext(v8::Local<v8::Context> context) {
return WebLocalFrameImpl::fromFrame(toLocalFrameIfNotDetached(context));
}
WebLocalFrame* WebLocalFrame::fromFrameOwnerElement(const WebElement& element) {
return WebLocalFrameImpl::fromFrameOwnerElement(element);
}
bool WebLocalFrameImpl::isWebLocalFrame() const {
return true;
}
WebLocalFrame* WebLocalFrameImpl::toWebLocalFrame() {
return this;
}
bool WebLocalFrameImpl::isWebRemoteFrame() const {
return false;
}
WebRemoteFrame* WebLocalFrameImpl::toWebRemoteFrame() {
NOTREACHED();
return 0;
}
void WebLocalFrameImpl::close() {
WebLocalFrame::close();
m_client = nullptr;
if (m_devToolsAgent)
m_devToolsAgent.clear();
m_selfKeepAlive.clear();
}
WebString WebLocalFrameImpl::assignedName() const {
return frame()->tree().name();
}
void WebLocalFrameImpl::setName(const WebString& name) {
frame()->tree().setName(name);
}
WebVector<WebIconURL> WebLocalFrameImpl::iconURLs(int iconTypesMask) const {
// The URL to the icon may be in the header. As such, only
// ask the loader for the icon if it's finished loading.
if (frame()->document()->loadEventFinished())
return frame()->document()->iconURLs(iconTypesMask);
return WebVector<WebIconURL>();
}
void WebLocalFrameImpl::setContentSettingsClient(
WebContentSettingsClient* contentSettingsClient) {
m_contentSettingsClient = contentSettingsClient;
}
void WebLocalFrameImpl::setSharedWorkerRepositoryClient(
WebSharedWorkerRepositoryClient* client) {
m_sharedWorkerRepositoryClient =
SharedWorkerRepositoryClientImpl::create(client);
}
ScrollableArea* WebLocalFrameImpl::layoutViewportScrollableArea() const {
if (FrameView* view = frameView())
return view->layoutViewportScrollableArea();
return nullptr;
}
bool WebLocalFrameImpl::isFocused() const {
if (!viewImpl() || !viewImpl()->page())
return false;
return this == WebFrame::fromFrame(
viewImpl()->page()->focusController().focusedFrame());
}
WebSize WebLocalFrameImpl::getScrollOffset() const {
if (ScrollableArea* scrollableArea = layoutViewportScrollableArea())
return scrollableArea->scrollOffsetInt();
return WebSize();
}
void WebLocalFrameImpl::setScrollOffset(const WebSize& offset) {
if (ScrollableArea* scrollableArea = layoutViewportScrollableArea()) {
scrollableArea->setScrollOffset(ScrollOffset(offset.width, offset.height),
ProgrammaticScroll);
}
}
WebSize WebLocalFrameImpl::contentsSize() const {
if (FrameView* view = frameView())
return view->contentsSize();
return WebSize();
}
bool WebLocalFrameImpl::hasVisibleContent() const {
LayoutPartItem layoutItem = frame()->ownerLayoutItem();
if (!layoutItem.isNull() &&
layoutItem.style()->visibility() != EVisibility::kVisible) {
return false;
}
if (FrameView* view = frameView())
return view->visibleWidth() > 0 && view->visibleHeight() > 0;
return false;
}
WebRect WebLocalFrameImpl::visibleContentRect() const {
if (FrameView* view = frameView())
return view->visibleContentRect();
return WebRect();
}
bool WebLocalFrameImpl::hasHorizontalScrollbar() const {
return frame() && frame()->view() && frame()->view()->horizontalScrollbar();
}
bool WebLocalFrameImpl::hasVerticalScrollbar() const {
return frame() && frame()->view() && frame()->view()->verticalScrollbar();
}
WebView* WebLocalFrameImpl::view() const {
return viewImpl();
}
WebDocument WebLocalFrameImpl::document() const {
if (!frame() || !frame()->document())
return WebDocument();
return WebDocument(frame()->document());
}
WebPerformance WebLocalFrameImpl::performance() const {
if (!frame())
return WebPerformance();
return WebPerformance(
DOMWindowPerformance::performance(*(frame()->domWindow())));
}
void WebLocalFrameImpl::dispatchUnloadEvent() {
if (!frame())
return;
SubframeLoadingDisabler disabler(frame()->document());
frame()->loader().dispatchUnloadEvent();
}
void WebLocalFrameImpl::executeScript(const WebScriptSource& source) {
DCHECK(frame());
TextPosition position(OrdinalNumber::fromOneBasedInt(source.startLine),
OrdinalNumber::first());
v8::HandleScope handleScope(toIsolate(frame()));
frame()->script().executeScriptInMainWorld(
ScriptSourceCode(source.code, source.url, position));
}
void WebLocalFrameImpl::executeScriptInIsolatedWorld(
int worldID,
const WebScriptSource* sourcesIn,
unsigned numSources) {
DCHECK(frame());
CHECK_GT(worldID, 0);
CHECK_LT(worldID, DOMWrapperWorld::EmbedderWorldIdLimit);
HeapVector<ScriptSourceCode> sources =
createSourcesVector(sourcesIn, numSources);
v8::HandleScope handleScope(toIsolate(frame()));
frame()->script().executeScriptInIsolatedWorld(worldID, sources, 0);
}
void WebLocalFrameImpl::setIsolatedWorldSecurityOrigin(
int worldID,
const WebSecurityOrigin& securityOrigin) {
DCHECK(frame());
DOMWrapperWorld::setIsolatedWorldSecurityOrigin(worldID,
securityOrigin.get());
}
void WebLocalFrameImpl::setIsolatedWorldContentSecurityPolicy(
int worldID,
const WebString& policy) {
DCHECK(frame());
DOMWrapperWorld::setIsolatedWorldContentSecurityPolicy(worldID, policy);
}
void WebLocalFrameImpl::setIsolatedWorldHumanReadableName(
int worldID,
const WebString& humanReadableName) {
DCHECK(frame());
DOMWrapperWorld::setIsolatedWorldHumanReadableName(worldID,
humanReadableName);
}
void WebLocalFrameImpl::addMessageToConsole(const WebConsoleMessage& message) {
DCHECK(frame());
MessageLevel webCoreMessageLevel = InfoMessageLevel;
switch (message.level) {
case WebConsoleMessage::LevelVerbose:
webCoreMessageLevel = VerboseMessageLevel;
break;
case WebConsoleMessage::LevelInfo:
webCoreMessageLevel = InfoMessageLevel;
break;
case WebConsoleMessage::LevelWarning:
webCoreMessageLevel = WarningMessageLevel;
break;
case WebConsoleMessage::LevelError:
webCoreMessageLevel = ErrorMessageLevel;
break;
}
frame()->document()->addConsoleMessage(ConsoleMessage::create(
OtherMessageSource, webCoreMessageLevel, message.text,
SourceLocation::create(message.url, message.lineNumber,
message.columnNumber, nullptr)));
}
void WebLocalFrameImpl::collectGarbage() {
if (!frame())
return;
if (!frame()->settings()->getScriptEnabled())
return;
V8GCController::collectGarbage(v8::Isolate::GetCurrent());
}
v8::Local<v8::Value> WebLocalFrameImpl::executeScriptAndReturnValue(
const WebScriptSource& source) {
DCHECK(frame());
TextPosition position(OrdinalNumber::fromOneBasedInt(source.startLine),
OrdinalNumber::first());
return frame()->script().executeScriptInMainWorldAndReturnValue(
ScriptSourceCode(source.code, source.url, position));
}
void WebLocalFrameImpl::requestExecuteScriptAndReturnValue(
const WebScriptSource& source,
bool userGesture,
WebScriptExecutionCallback* callback) {
DCHECK(frame());
RefPtr<DOMWrapperWorld> mainWorld = &DOMWrapperWorld::mainWorld();
SuspendableScriptExecutor* executor = SuspendableScriptExecutor::create(
frame(), std::move(mainWorld), createSourcesVector(&source, 1),
userGesture, callback);
executor->run();
}
void WebLocalFrameImpl::requestExecuteV8Function(
v8::Local<v8::Context> context,
v8::Local<v8::Function> function,
v8::Local<v8::Value> receiver,
int argc,
v8::Local<v8::Value> argv[],
WebScriptExecutionCallback* callback) {
DCHECK(frame());
SuspendableScriptExecutor::createAndRun(frame(), toIsolate(frame()), context,
function, receiver, argc, argv,
callback);
}
void WebLocalFrameImpl::executeScriptInIsolatedWorld(
int worldID,
const WebScriptSource* sourcesIn,
unsigned numSources,
WebVector<v8::Local<v8::Value>>* results) {
DCHECK(frame());
CHECK_GT(worldID, 0);
CHECK_LT(worldID, DOMWrapperWorld::EmbedderWorldIdLimit);
HeapVector<ScriptSourceCode> sources =
createSourcesVector(sourcesIn, numSources);
if (results) {
Vector<v8::Local<v8::Value>> scriptResults;
frame()->script().executeScriptInIsolatedWorld(worldID, sources,
&scriptResults);
WebVector<v8::Local<v8::Value>> v8Results(scriptResults.size());
for (unsigned i = 0; i < scriptResults.size(); i++)
v8Results[i] =
v8::Local<v8::Value>::New(toIsolate(frame()), scriptResults[i]);
results->swap(v8Results);
} else {
v8::HandleScope handleScope(toIsolate(frame()));
frame()->script().executeScriptInIsolatedWorld(worldID, sources, 0);
}
}
void WebLocalFrameImpl::requestExecuteScriptInIsolatedWorld(
int worldID,
const WebScriptSource* sourcesIn,
unsigned numSources,
bool userGesture,
ScriptExecutionType option,
WebScriptExecutionCallback* callback) {
DCHECK(frame());
CHECK_GT(worldID, 0);
CHECK_LT(worldID, DOMWrapperWorld::EmbedderWorldIdLimit);
RefPtr<DOMWrapperWorld> isolatedWorld =
DOMWrapperWorld::ensureIsolatedWorld(toIsolate(frame()), worldID);
SuspendableScriptExecutor* executor = SuspendableScriptExecutor::create(
frame(), std::move(isolatedWorld),
createSourcesVector(sourcesIn, numSources), userGesture, callback);
switch (option) {
case AsynchronousBlockingOnload:
executor->runAsync(SuspendableScriptExecutor::OnloadBlocking);
break;
case Asynchronous:
executor->runAsync(SuspendableScriptExecutor::NonBlocking);
break;
case Synchronous:
executor->run();
break;
}
}
// TODO(bashi): Consider returning MaybeLocal.
v8::Local<v8::Value> WebLocalFrameImpl::callFunctionEvenIfScriptDisabled(
v8::Local<v8::Function> function,
v8::Local<v8::Value> receiver,
int argc,
v8::Local<v8::Value> argv[]) {
DCHECK(frame());
v8::Local<v8::Value> result;
if (!V8ScriptRunner::callFunction(
function, frame()->document(), receiver, argc,
static_cast<v8::Local<v8::Value>*>(argv), toIsolate(frame()))
.ToLocal(&result))
return v8::Local<v8::Value>();
return result;
}
v8::Local<v8::Context> WebLocalFrameImpl::mainWorldScriptContext() const {
ScriptState* scriptState = ScriptState::forMainWorld(frame());
DCHECK(scriptState);
return scriptState->context();
}
bool WebFrame::scriptCanAccess(WebFrame* target) {
return BindingSecurity::shouldAllowAccessToFrame(
currentDOMWindow(mainThreadIsolate()), target->toImplBase()->frame(),
BindingSecurity::ErrorReportOption::DoNotReport);
}
void WebLocalFrameImpl::reload(WebFrameLoadType loadType) {
// TODO(clamy): Remove this function once RenderFrame calls load for all
// requests.
reloadWithOverrideURL(KURL(), loadType);
}
void WebLocalFrameImpl::reloadWithOverrideURL(const WebURL& overrideUrl,
WebFrameLoadType loadType) {
// TODO(clamy): Remove this function once RenderFrame calls load for all
// requests.
DCHECK(frame());
DCHECK(isReloadLoadType(static_cast<FrameLoadType>(loadType)));
WebURLRequest request = requestForReload(loadType, overrideUrl);
if (request.isNull())
return;
load(request, loadType, WebHistoryItem(), WebHistoryDifferentDocumentLoad,
false);
}
void WebLocalFrameImpl::reloadImage(const WebNode& webNode) {
const Node* node = webNode.constUnwrap<Node>();
if (isHTMLImageElement(*node)) {
const HTMLImageElement& imageElement = toHTMLImageElement(*node);
imageElement.forceReload();
}
}
void WebLocalFrameImpl::reloadLoFiImages() {
frame()->document()->fetcher()->reloadLoFiImages();
}
void WebLocalFrameImpl::loadRequest(const WebURLRequest& request) {
// TODO(clamy): Remove this function once RenderFrame calls load for all
// requests.
load(request, WebFrameLoadType::Standard, WebHistoryItem(),
WebHistoryDifferentDocumentLoad, false);
}
void WebLocalFrameImpl::loadHTMLString(const WebData& data,
const WebURL& baseURL,
const WebURL& unreachableURL,
bool replace) {
DCHECK(frame());
loadData(data, WebString::fromUTF8("text/html"), WebString::fromUTF8("UTF-8"),
baseURL, unreachableURL, replace, WebFrameLoadType::Standard,
WebHistoryItem(), WebHistoryDifferentDocumentLoad, false);
}
void WebLocalFrameImpl::stopLoading() {
if (!frame())
return;
// FIXME: Figure out what we should really do here. It seems like a bug
// that FrameLoader::stopLoading doesn't call stopAllLoaders.
frame()->loader().stopAllLoaders();
}
WebDataSource* WebLocalFrameImpl::provisionalDataSource() const {
DCHECK(frame());
return DataSourceForDocLoader(frame()->loader().provisionalDocumentLoader());
}
WebDataSource* WebLocalFrameImpl::dataSource() const {
DCHECK(frame());
return DataSourceForDocLoader(frame()->loader().documentLoader());
}
void WebLocalFrameImpl::enableViewSourceMode(bool enable) {
if (frame())
frame()->setInViewSourceMode(enable);
}
bool WebLocalFrameImpl::isViewSourceModeEnabled() const {
if (!frame())
return false;
return frame()->inViewSourceMode();
}
void WebLocalFrameImpl::setReferrerForRequest(WebURLRequest& request,
const WebURL& referrerURL) {
String referrer = referrerURL.isEmpty()
? frame()->document()->outgoingReferrer()
: String(referrerURL.string());
request.toMutableResourceRequest().setHTTPReferrer(
SecurityPolicy::generateReferrer(frame()->document()->getReferrerPolicy(),
request.url(), referrer));
}
WebAssociatedURLLoader* WebLocalFrameImpl::createAssociatedURLLoader(
const WebAssociatedURLLoaderOptions& options) {
return new WebAssociatedURLLoaderImpl(this, options);
}
unsigned WebLocalFrameImpl::unloadListenerCount() const {
return frame()->domWindow()->pendingUnloadEventListeners();
}
void WebLocalFrameImpl::replaceSelection(const WebString& text) {
// TODO(xiaochengh): The use of updateStyleAndLayoutIgnorePendingStylesheets
// needs to be audited. See http://crbug.com/590369 for more details.
frame()->document()->updateStyleAndLayoutIgnorePendingStylesheets();
frame()->editor().replaceSelection(text);
}
void WebLocalFrameImpl::setMarkedText(const WebString& text,
unsigned location,
unsigned length) {
Vector<CompositionUnderline> decorations;
frame()->inputMethodController().setComposition(text, decorations, location,
length);
}
void WebLocalFrameImpl::unmarkText() {
frame()->inputMethodController().cancelComposition();
}
bool WebLocalFrameImpl::hasMarkedText() const {
return frame()->inputMethodController().hasComposition();
}
WebRange WebLocalFrameImpl::markedRange() const {
return frame()->inputMethodController().compositionEphemeralRange();
}
bool WebLocalFrameImpl::firstRectForCharacterRange(
unsigned location,
unsigned length,
WebRect& rectInViewport) const {
if ((location + length < location) && (location + length))
length = 0;
Element* editable =
frame()->selection().rootEditableElementOrDocumentElement();
if (!editable)
return false;
// TODO(dglazkov): The use of updateStyleAndLayoutIgnorePendingStylesheets
// needs to be audited. see http://crbug.com/590369 for more details.
editable->document().updateStyleAndLayoutIgnorePendingStylesheets();
const EphemeralRange range =
PlainTextRange(location, location + length).createRange(*editable);
if (range.isNull())
return false;
IntRect intRect = frame()->editor().firstRectForRange(range);
rectInViewport = WebRect(intRect);
rectInViewport = frame()->view()->contentsToViewport(rectInViewport);
return true;
}
size_t WebLocalFrameImpl::characterIndexForPoint(
const WebPoint& pointInViewport) const {
if (!frame())
return kNotFound;
IntPoint point = frame()->view()->viewportToContents(pointInViewport);
HitTestResult result = frame()->eventHandler().hitTestResultAtPoint(
point, HitTestRequest::ReadOnly | HitTestRequest::Active);
const EphemeralRange range =
frame()->rangeForPoint(result.roundedPointInInnerNodeFrame());
if (range.isNull())
return kNotFound;
Element* editable =
frame()->selection().rootEditableElementOrDocumentElement();
DCHECK(editable);
return PlainTextRange::create(*editable, range).start();
}
bool WebLocalFrameImpl::executeCommand(const WebString& name) {
DCHECK(frame());
if (name.length() <= 2)
return false;
// Since we don't have NSControl, we will convert the format of command
// string and call the function on Editor directly.
String command = name;
// Make sure the first letter is upper case.
command.replace(0, 1, command.substring(0, 1).upper());
// Remove the trailing ':' if existing.
if (command[command.length() - 1] == UChar(':'))
command = command.substring(0, command.length() - 1);
Node* pluginLookupContextNode =
m_contextMenuNode && name == "Copy" ? m_contextMenuNode : nullptr;
WebPluginContainerImpl* pluginContainer =
currentPluginContainer(frame(), pluginLookupContextNode);
if (pluginContainer && pluginContainer->executeEditCommand(name))
return true;
return frame()->editor().executeCommand(command);
}
bool WebLocalFrameImpl::executeCommand(const WebString& name,
const WebString& value) {
DCHECK(frame());
WebPluginContainerImpl* pluginContainer = currentPluginContainer(frame());
if (pluginContainer && pluginContainer->executeEditCommand(name, value))
return true;
return frame()->editor().executeCommand(name, value);
}
bool WebLocalFrameImpl::isCommandEnabled(const WebString& name) const {
DCHECK(frame());
return frame()->editor().createCommand(name).isEnabled();
}
void WebLocalFrameImpl::enableSpellChecking(bool enable) {
if (enable == isSpellCheckingEnabled())
return;
frame()->spellChecker().toggleSpellCheckingEnabled();
}
bool WebLocalFrameImpl::isSpellCheckingEnabled() const {
return frame()->spellChecker().isSpellCheckingEnabled();
}
void WebLocalFrameImpl::replaceMisspelledRange(const WebString& text) {
// If this caret selection has two or more markers, this function replace the
// range covered by the first marker with the specified word as Microsoft Word
// does.
if (pluginContainerFromFrame(frame()))
return;
// TODO(xiaochengh): The use of updateStyleAndLayoutIgnorePendingStylesheets
// needs to be audited. see http://crbug.com/590369 for more details.
frame()->document()->updateStyleAndLayoutIgnorePendingStylesheets();
frame()->spellChecker().replaceMisspelledRange(text);
}
void WebLocalFrameImpl::removeSpellingMarkers() {
frame()->spellChecker().removeSpellingMarkers();
}
bool WebLocalFrameImpl::hasSelection() const {
WebPluginContainerImpl* pluginContainer = pluginContainerFromFrame(frame());
if (pluginContainer)
return pluginContainer->plugin()->hasSelection();
// frame()->selection()->isNone() never returns true.
return frame()
->selection()
.computeVisibleSelectionInDOMTreeDeprecated()
.start() !=
frame()
->selection()
.computeVisibleSelectionInDOMTreeDeprecated()
.end();
}
WebRange WebLocalFrameImpl::selectionRange() const {
// TODO(xiaochengh): The use of updateStyleAndLayoutIgnorePendingStylesheets
// needs to be audited. See http://crbug.com/590369 for more details.
frame()->document()->updateStyleAndLayoutIgnorePendingStylesheets();
return frame()
->selection()
.computeVisibleSelectionInDOMTreeDeprecated()
.toNormalizedEphemeralRange();
}
WebString WebLocalFrameImpl::selectionAsText() const {
WebPluginContainerImpl* pluginContainer = pluginContainerFromFrame(frame());
if (pluginContainer)
return pluginContainer->plugin()->selectionAsText();
// TODO(xiaochengh): The use of updateStyleAndLayoutIgnorePendingStylesheets
// needs to be audited. See http://crbug.com/590369 for more details.
frame()->document()->updateStyleAndLayoutIgnorePendingStylesheets();
String text = frame()->selection().selectedText(
TextIteratorBehavior::emitsObjectReplacementCharacterBehavior());
#if OS(WIN)
replaceNewlinesWithWindowsStyleNewlines(text);
#endif
replaceNBSPWithSpace(text);
return text;
}
WebString WebLocalFrameImpl::selectionAsMarkup() const {
WebPluginContainerImpl* pluginContainer = pluginContainerFromFrame(frame());
if (pluginContainer)
return pluginContainer->plugin()->selectionAsMarkup();
// TODO(xiaochengh): The use of updateStyleAndLayoutIgnorePendingStylesheets
// needs to be audited. See http://crbug.com/590369 for more details.
// Selection normalization and markup generation require clean layout.
frame()->document()->updateStyleAndLayoutIgnorePendingStylesheets();
return frame()->selection().selectedHTMLForClipboard();
}
void WebLocalFrameImpl::selectWordAroundPosition(LocalFrame* frame,
VisiblePosition position) {
TRACE_EVENT0("blink", "WebLocalFrameImpl::selectWordAroundPosition");
// TODO(xiaochengh): The use of updateStyleAndLayoutIgnorePendingStylesheets
// needs to be audited. see http://crbug.com/590369 for more details.
frame->document()->updateStyleAndLayoutIgnorePendingStylesheets();
frame->selection().selectWordAroundPosition(position);
}
bool WebLocalFrameImpl::selectWordAroundCaret() {
TRACE_EVENT0("blink", "WebLocalFrameImpl::selectWordAroundCaret");
FrameSelection& selection = frame()->selection();
if (selection.computeVisibleSelectionInDOMTreeDeprecated().isNone() ||
selection.computeVisibleSelectionInDOMTreeDeprecated().isRange())
return false;
// TODO(xiaochengh): The use of updateStyleAndLayoutIgnorePendingStylesheets
// needs to be audited. see http://crbug.com/590369 for more details.
frame()->document()->updateStyleAndLayoutIgnorePendingStylesheets();
return frame()->selection().selectWordAroundPosition(
selection.computeVisibleSelectionInDOMTreeDeprecated().visibleStart());
}
void WebLocalFrameImpl::selectRange(const WebPoint& baseInViewport,
const WebPoint& extentInViewport) {
moveRangeSelection(baseInViewport, extentInViewport);
}
void WebLocalFrameImpl::selectRange(const WebRange& webRange) {
TRACE_EVENT0("blink", "WebLocalFrameImpl::selectRange");
// TODO(dglazkov): The use of updateStyleAndLayoutIgnorePendingStylesheets
// needs to be audited. see http://crbug.com/590369 for more details.
frame()->document()->updateStyleAndLayoutIgnorePendingStylesheets();
frame()->selection().setSelectedRange(
webRange.createEphemeralRange(frame()), VP_DEFAULT_AFFINITY,
SelectionDirectionalMode::NonDirectional, NotUserTriggered);
}
WebString WebLocalFrameImpl::rangeAsText(const WebRange& webRange) {
// TODO(dglazkov): The use of updateStyleAndLayoutIgnorePendingStylesheets
// needs to be audited. see http://crbug.com/590369 for more details.
frame()->document()->updateStyleAndLayoutIgnorePendingStylesheets();
DocumentLifecycle::DisallowTransitionScope disallowTransition(
frame()->document()->lifecycle());
return plainText(
webRange.createEphemeralRange(frame()),
TextIteratorBehavior::emitsObjectReplacementCharacterBehavior());
}
void WebLocalFrameImpl::moveRangeSelectionExtent(const WebPoint& point) {
TRACE_EVENT0("blink", "WebLocalFrameImpl::moveRangeSelectionExtent");
// TODO(xiaochengh): The use of updateStyleAndLayoutIgnorePendingStylesheets
// needs to be audited. See http://crbug.com/590369 for more details.
frame()->document()->updateStyleAndLayoutIgnorePendingStylesheets();
frame()->selection().moveRangeSelectionExtent(
frame()->view()->viewportToContents(point));
}
void WebLocalFrameImpl::moveRangeSelection(
const WebPoint& baseInViewport,
const WebPoint& extentInViewport,
WebFrame::TextGranularity granularity) {
TRACE_EVENT0("blink", "WebLocalFrameImpl::moveRangeSelection");
// TODO(xiaochengh): The use of updateStyleAndLayoutIgnorePendingStylesheets
// needs to be audited. See http://crbug.com/590369 for more details.
frame()->document()->updateStyleAndLayoutIgnorePendingStylesheets();
blink::TextGranularity blinkGranularity = blink::CharacterGranularity;
if (granularity == WebFrame::WordGranularity)
blinkGranularity = blink::WordGranularity;
frame()->selection().moveRangeSelection(
visiblePositionForViewportPoint(baseInViewport),
visiblePositionForViewportPoint(extentInViewport), blinkGranularity);
}
void WebLocalFrameImpl::moveCaretSelection(const WebPoint& pointInViewport) {
TRACE_EVENT0("blink", "WebLocalFrameImpl::moveCaretSelection");
// TODO(editing-dev): The use of updateStyleAndLayoutIgnorePendingStylesheets
// needs to be audited. see http://crbug.com/590369 for more details.
frame()->document()->updateStyleAndLayoutIgnorePendingStylesheets();
const IntPoint pointInContents =
frame()->view()->viewportToContents(pointInViewport);
frame()->selection().moveCaretSelection(pointInContents);
}
bool WebLocalFrameImpl::setEditableSelectionOffsets(int start, int end) {
TRACE_EVENT0("blink", "WebLocalFrameImpl::setEditableSelectionOffsets");
// TODO(xiaochengh): The use of updateStyleAndLayoutIgnorePendingStylesheets
// needs to be audited. See http://crbug.com/590369 for more details.
frame()->document()->updateStyleAndLayoutIgnorePendingStylesheets();
return frame()->inputMethodController().setEditableSelectionOffsets(
PlainTextRange(start, end));
}
bool WebLocalFrameImpl::setCompositionFromExistingText(
int compositionStart,
int compositionEnd,
const WebVector<WebCompositionUnderline>& underlines) {
TRACE_EVENT0("blink", "WebLocalFrameImpl::setCompositionFromExistingText");
if (!frame()->editor().canEdit())
return false;
InputMethodController& inputMethodController =
frame()->inputMethodController();
inputMethodController.cancelComposition();
if (compositionStart == compositionEnd)
return true;
// TODO(xiaochengh): The use of updateStyleAndLayoutIgnorePendingStylesheets
// needs to be audited. See http://crbug.com/590369 for more details.
frame()->document()->updateStyleAndLayoutIgnorePendingStylesheets();
inputMethodController.setCompositionFromExistingText(
CompositionUnderlineVectorBuilder(underlines), compositionStart,
compositionEnd);
return true;
}
void WebLocalFrameImpl::extendSelectionAndDelete(int before, int after) {
TRACE_EVENT0("blink", "WebLocalFrameImpl::extendSelectionAndDelete");
if (WebPlugin* plugin = focusedPluginIfInputMethodSupported()) {
plugin->extendSelectionAndDelete(before, after);
return;
}
// TODO(xiaochengh): The use of updateStyleAndLayoutIgnorePendingStylesheets
// needs to be audited. See http://crbug.com/590369 for more details.
frame()->document()->updateStyleAndLayoutIgnorePendingStylesheets();
frame()->inputMethodController().extendSelectionAndDelete(before, after);
}
void WebLocalFrameImpl::deleteSurroundingText(int before, int after) {
TRACE_EVENT0("blink", "WebLocalFrameImpl::deleteSurroundingText");
if (WebPlugin* plugin = focusedPluginIfInputMethodSupported()) {
plugin->deleteSurroundingText(before, after);
return;
}
// TODO(editing-dev): The use of updateStyleAndLayoutIgnorePendingStylesheets
// needs to be audited. See http://crbug.com/590369 for more details.
frame()->document()->updateStyleAndLayoutIgnorePendingStylesheets();
frame()->inputMethodController().deleteSurroundingText(before, after);
}
void WebLocalFrameImpl::deleteSurroundingTextInCodePoints(int before,
int after) {
TRACE_EVENT0("blink", "WebLocalFrameImpl::deleteSurroundingTextInCodePoints");
if (WebPlugin* plugin = focusedPluginIfInputMethodSupported()) {
plugin->deleteSurroundingTextInCodePoints(before, after);
return;
}
// TODO(editing-dev): The use of updateStyleAndLayoutIgnorePendingStylesheets
// needs to be audited. See http://crbug.com/590369 for more details.
frame()->document()->updateStyleAndLayoutIgnorePendingStylesheets();
frame()->inputMethodController().deleteSurroundingTextInCodePoints(before,
after);
}
void WebLocalFrameImpl::setCaretVisible(bool visible) {
frame()->selection().setCaretVisible(visible);
}
VisiblePosition WebLocalFrameImpl::visiblePositionForViewportPoint(
const WebPoint& pointInViewport) {
return visiblePositionForContentsPoint(
frame()->view()->viewportToContents(pointInViewport), frame());
}
WebPlugin* WebLocalFrameImpl::focusedPluginIfInputMethodSupported() {
WebPluginContainerImpl* container =
WebLocalFrameImpl::currentPluginContainer(frame());
if (container && container->supportsInputMethod())
return container->plugin();
return 0;
}
int WebLocalFrameImpl::printBegin(const WebPrintParams& printParams,
const WebNode& constrainToNode) {
DCHECK(!frame()->document()->isFrameSet());
WebPluginContainerImpl* pluginContainer = nullptr;
if (constrainToNode.isNull()) {
// If this is a plugin document, check if the plugin supports its own
// printing. If it does, we will delegate all printing to that.
pluginContainer = pluginContainerFromFrame(frame());
} else {
// We only support printing plugin nodes for now.
pluginContainer =
toWebPluginContainerImpl(constrainToNode.pluginContainer());
}
if (pluginContainer && pluginContainer->supportsPaginatedPrint())
m_printContext =
new ChromePluginPrintContext(frame(), pluginContainer, printParams);
else
m_printContext = new ChromePrintContext(frame());
FloatRect rect(0, 0, static_cast<float>(printParams.printContentArea.width),
static_cast<float>(printParams.printContentArea.height));
m_printContext->begin(rect.width(), rect.height());
float pageHeight;
// We ignore the overlays calculation for now since they are generated in the
// browser. pageHeight is actually an output parameter.
m_printContext->computePageRects(rect, 0, 0, 1.0, pageHeight);
return static_cast<int>(m_printContext->pageCount());
}
float WebLocalFrameImpl::getPrintPageShrink(int page) {
DCHECK(m_printContext);
DCHECK_GE(page, 0);
return m_printContext->getPageShrink(page);
}
float WebLocalFrameImpl::printPage(int page, WebCanvas* canvas) {
DCHECK(m_printContext);
DCHECK_GE(page, 0);
DCHECK(frame());
DCHECK(frame()->document());
return m_printContext->spoolSinglePage(canvas, page);
}
void WebLocalFrameImpl::printEnd() {
DCHECK(m_printContext);
m_printContext->end();
m_printContext.clear();
}
bool WebLocalFrameImpl::isPrintScalingDisabledForPlugin(const WebNode& node) {
WebPluginContainerImpl* pluginContainer =
node.isNull() ? pluginContainerFromFrame(frame())
: toWebPluginContainerImpl(node.pluginContainer());
if (!pluginContainer || !pluginContainer->supportsPaginatedPrint())
return false;
return pluginContainer->isPrintScalingDisabled();
}
bool WebLocalFrameImpl::getPrintPresetOptionsForPlugin(
const WebNode& node,
WebPrintPresetOptions* presetOptions) {
WebPluginContainerImpl* pluginContainer =
node.isNull() ? pluginContainerFromFrame(frame())
: toWebPluginContainerImpl(node.pluginContainer());
if (!pluginContainer || !pluginContainer->supportsPaginatedPrint())
return false;
return pluginContainer->getPrintPresetOptionsFromDocument(presetOptions);
}
bool WebLocalFrameImpl::hasCustomPageSizeStyle(int pageIndex) {
return frame()->document()->styleForPage(pageIndex)->getPageSizeType() !=
PAGE_SIZE_AUTO;
}
bool WebLocalFrameImpl::isPageBoxVisible(int pageIndex) {
return frame()->document()->isPageBoxVisible(pageIndex);
}
void WebLocalFrameImpl::pageSizeAndMarginsInPixels(int pageIndex,
WebDoubleSize& pageSize,
int& marginTop,
int& marginRight,
int& marginBottom,
int& marginLeft) {
DoubleSize size = pageSize;
frame()->document()->pageSizeAndMarginsInPixels(
pageIndex, size, marginTop, marginRight, marginBottom, marginLeft);
pageSize = size;
}
WebString WebLocalFrameImpl::pageProperty(const WebString& propertyName,
int pageIndex) {
DCHECK(m_printContext);
return m_printContext->pageProperty(frame(), propertyName.utf8().data(),
pageIndex);
}
void WebLocalFrameImpl::printPagesWithBoundaries(
WebCanvas* canvas,
const WebSize& pageSizeInPixels) {
DCHECK(m_printContext);
m_printContext->spoolAllPagesWithBoundaries(
canvas, FloatSize(pageSizeInPixels.width, pageSizeInPixels.height));
}
WebRect WebLocalFrameImpl::selectionBoundsRect() const {
return hasSelection() ? WebRect(IntRect(frame()->selection().bounds()))
: WebRect();
}
WebString WebLocalFrameImpl::layerTreeAsText(bool showDebugInfo) const {
if (!frame())
return WebString();
return WebString(frame()->layerTreeAsText(
showDebugInfo ? LayerTreeIncludesDebugInfo : LayerTreeNormal));
}
// WebLocalFrameImpl public --------------------------------------------------
WebLocalFrame* WebLocalFrame::create(
WebTreeScopeType scope,
WebFrameClient* client,
blink::InterfaceProvider* interfaceProvider,
blink::InterfaceRegistry* interfaceRegistry,
WebFrame* opener) {
return WebLocalFrameImpl::create(scope, client, interfaceProvider,
interfaceRegistry, opener);
}
WebLocalFrame* WebLocalFrame::createProvisional(
WebFrameClient* client,
blink::InterfaceProvider* interfaceProvider,
blink::InterfaceRegistry* interfaceRegistry,
WebRemoteFrame* oldWebFrame,
WebSandboxFlags flags) {
return WebLocalFrameImpl::createProvisional(
client, interfaceProvider, interfaceRegistry, oldWebFrame, flags);
}
WebLocalFrameImpl* WebLocalFrameImpl::create(
WebTreeScopeType scope,
WebFrameClient* client,
blink::InterfaceProvider* interfaceProvider,
blink::InterfaceRegistry* interfaceRegistry,
WebFrame* opener) {
WebLocalFrameImpl* frame = new WebLocalFrameImpl(
scope, client, interfaceProvider, interfaceRegistry);
frame->setOpener(opener);
return frame;
}
WebLocalFrameImpl* WebLocalFrameImpl::createProvisional(
WebFrameClient* client,
blink::InterfaceProvider* interfaceProvider,
blink::InterfaceRegistry* interfaceRegistry,
WebRemoteFrame* oldWebFrame,
WebSandboxFlags flags) {
DCHECK(client);
WebLocalFrameImpl* webFrame = new WebLocalFrameImpl(
oldWebFrame, client, interfaceProvider, interfaceRegistry);
Frame* oldFrame = oldWebFrame->toImplBase()->frame();
webFrame->setParent(oldWebFrame->parent());
webFrame->setOpener(oldWebFrame->opener());
// Note: this *always* temporarily sets a frame owner, even for main frames!
// When a core Frame is created with no owner, it attempts to set itself as
// the main frame of the Page. However, this is a provisional frame, and may
// disappear, so Page::m_mainFrame can't be updated just yet.
FrameOwner* tempOwner = DummyFrameOwner::create();
// TODO(dcheng): This block is very similar to initializeCoreFrame. Try to
// reuse it here.
LocalFrame* frame = LocalFrame::create(webFrame->m_localFrameClientImpl.get(),
*oldFrame->page(), tempOwner,
interfaceProvider, interfaceRegistry);
frame->tree().setName(
toWebRemoteFrameImpl(oldWebFrame)->frame()->tree().name());
webFrame->setCoreFrame(frame);
frame->setOwner(oldFrame->owner());
if (frame->owner() && frame->owner()->isRemote())
toRemoteFrameOwner(frame->owner())
->setSandboxFlags(static_cast<SandboxFlags>(flags));
// We must call init() after m_frame is assigned because it is referenced
// during init(). Note that this may dispatch JS events; the frame may be
// detached after init() returns.
frame->init();
return webFrame;
}
WebLocalFrameImpl::WebLocalFrameImpl(
WebTreeScopeType scope,
WebFrameClient* client,
blink::InterfaceProvider* interfaceProvider,
blink::InterfaceRegistry* interfaceRegistry)
: WebLocalFrame(scope),
m_localFrameClientImpl(LocalFrameClientImpl::create(this)),
m_frameWidget(0),
m_client(client),
m_autofillClient(0),
m_contentSettingsClient(0),
m_inputEventsScaleFactorForEmulation(1),
m_interfaceProvider(interfaceProvider),
m_interfaceRegistry(interfaceRegistry),
m_webDevToolsFrontend(0),
m_inputMethodController(new WebInputMethodControllerImpl(this)),
m_selfKeepAlive(this) {
DCHECK(m_client);
frameCount++;
}
WebLocalFrameImpl::WebLocalFrameImpl(
WebRemoteFrame* oldWebFrame,
WebFrameClient* client,
blink::InterfaceProvider* interfaceProvider,
blink::InterfaceRegistry* interfaceRegistry)
: WebLocalFrameImpl(oldWebFrame->inShadowTree()
? WebTreeScopeType::Shadow
: WebTreeScopeType::Document,
client,
interfaceProvider,
interfaceRegistry) {}
WebLocalFrameImpl::~WebLocalFrameImpl() {
// The widget for the frame, if any, must have already been closed.
DCHECK(!m_frameWidget);
frameCount--;
}
DEFINE_TRACE(WebLocalFrameImpl) {
visitor->trace(m_localFrameClientImpl);
visitor->trace(m_frame);
visitor->trace(m_devToolsAgent);
visitor->trace(m_textFinder);
visitor->trace(m_printContext);
visitor->trace(m_contextMenuNode);
WebFrame::traceFrames(visitor, this);
WebFrameImplBase::trace(visitor);
}
void WebLocalFrameImpl::setCoreFrame(LocalFrame* frame) {
m_frame = frame;
}
void WebLocalFrameImpl::initializeCoreFrame(Page& page,
FrameOwner* owner,
const AtomicString& name) {
setCoreFrame(LocalFrame::create(m_localFrameClientImpl.get(), page, owner,
m_interfaceProvider, m_interfaceRegistry));
frame()->tree().setName(name);
// We must call init() after m_frame is assigned because it is referenced
// during init(). Note that this may dispatch JS events; the frame may be
// detached after init() returns.
frame()->init();
if (frame()) {
if (frame()->loader().stateMachine()->isDisplayingInitialEmptyDocument() &&
!parent() && !opener() &&
frame()->settings()->getShouldReuseGlobalForUnownedMainFrame()) {
frame()->document()->getSecurityOrigin()->grantUniversalAccess();
}
if (!owner) {
// This trace event is needed to detect the main frame of the
// renderer in telemetry metrics. See crbug.com/692112#c11.
TRACE_EVENT_INSTANT1("loading", "markAsMainFrame",
TRACE_EVENT_SCOPE_THREAD, "frame", frame());
}
}
}
LocalFrame* WebLocalFrameImpl::createChildFrame(
const FrameLoadRequest& request,
const AtomicString& name,
HTMLFrameOwnerElement* ownerElement) {
DCHECK(m_client);
TRACE_EVENT0("blink", "WebLocalFrameImpl::createChildframe");
WebTreeScopeType scope = frame()->document() == ownerElement->treeScope()
? WebTreeScopeType::Document
: WebTreeScopeType::Shadow;
WebFrameOwnerProperties ownerProperties(
ownerElement->browsingContextContainerName(),
ownerElement->scrollingMode(), ownerElement->marginWidth(),
ownerElement->marginHeight(), ownerElement->allowFullscreen(),
ownerElement->allowPaymentRequest(), ownerElement->isDisplayNone(),
ownerElement->csp(), ownerElement->allowedFeatures());
// FIXME: Using subResourceAttributeName as fallback is not a perfect
// solution. subResourceAttributeName returns just one attribute name. The
// element might not have the attribute, and there might be other attributes
// which can identify the element.
WebLocalFrameImpl* webframeChild =
toWebLocalFrameImpl(m_client->createChildFrame(
this, scope, name,
ownerElement->getAttribute(ownerElement->subResourceAttributeName()),
static_cast<WebSandboxFlags>(ownerElement->getSandboxFlags()),
ownerProperties));
if (!webframeChild)
return nullptr;
webframeChild->initializeCoreFrame(*frame()->page(), ownerElement, name);
// Initializing the core frame may cause the new child to be detached, since
// it may dispatch a load event in the parent.
if (!webframeChild->parent())
return nullptr;
// If we're moving in the back/forward list, we might want to replace the
// content of this child frame with whatever was there at that point.
HistoryItem* childItem = nullptr;
if (isBackForwardLoadType(frame()->loader().documentLoader()->loadType()) &&
!frame()->document()->loadEventFinished())
childItem = webframeChild->client()->historyItemForNewChildFrame();
FrameLoadRequest newRequest = request;
FrameLoadType loadType = FrameLoadTypeStandard;
if (childItem) {
newRequest = FrameLoadRequest(
request.originDocument(),
FrameLoader::resourceRequestFromHistoryItem(
childItem, WebCachePolicy::UseProtocolCachePolicy));
loadType = FrameLoadTypeInitialHistoryLoad;
}
webframeChild->frame()->loader().load(newRequest, loadType, childItem);
// Note a synchronous navigation (about:blank) would have already processed
// onload, so it is possible for the child frame to have already been
// detached by script in the page.
if (!webframeChild->parent())
return nullptr;
return webframeChild->frame();
}
void WebLocalFrameImpl::didChangeContentsSize(const IntSize& size) {
if (m_textFinder && m_textFinder->totalMatchCount() > 0)
m_textFinder->increaseMarkerVersion();
}
void WebLocalFrameImpl::createFrameView() {
TRACE_EVENT0("blink", "WebLocalFrameImpl::createFrameView");
DCHECK(
frame()); // If frame() doesn't exist, we probably didn't init properly.
WebViewImpl* webView = viewImpl();
// Check if we're shutting down.
if (!webView->page())
return;
bool isMainFrame = !parent();
IntSize initialSize = (isMainFrame || !frameWidget())
? webView->mainFrameSize()
: (IntSize)frameWidget()->size();
bool isTransparent = !isMainFrame && parent()->isWebRemoteFrame()
? true
: webView->isTransparent();
frame()->createView(initialSize, webView->baseBackgroundColor(),
isTransparent);
if (isMainFrame) {
frame()->view()->setInitialViewportSize(
webView->pageScaleConstraintsSet().initialViewportSize());
}
if (webView->shouldAutoResize() && frame()->isLocalRoot())
frame()->view()->enableAutoSizeMode(webView->minAutoSize(),
webView->maxAutoSize());
frame()->view()->setInputEventsTransformForEmulation(
m_inputEventsOffsetForEmulation, m_inputEventsScaleFactorForEmulation);
frame()->view()->setDisplayMode(webView->displayMode());
}
WebLocalFrameImpl* WebLocalFrameImpl::fromFrame(LocalFrame* frame) {
if (!frame)
return nullptr;
return fromFrame(*frame);
}
WebLocalFrameImpl* WebLocalFrameImpl::fromFrame(LocalFrame& frame) {
LocalFrameClient* client = frame.loader().client();
if (!client || !client->isLocalFrameClientImpl())
return nullptr;
return toLocalFrameClientImpl(client)->webFrame();
}
WebLocalFrameImpl* WebLocalFrameImpl::fromFrameOwnerElement(Element* element) {
if (!element->isFrameOwnerElement())
return nullptr;
return fromFrame(
toLocalFrame(toHTMLFrameOwnerElement(element)->contentFrame()));
}
WebViewImpl* WebLocalFrameImpl::viewImpl() const {
if (!frame())
return nullptr;
return WebViewImpl::fromPage(frame()->page());
}
WebDataSourceImpl* WebLocalFrameImpl::dataSourceImpl() const {
return static_cast<WebDataSourceImpl*>(dataSource());
}
WebDataSourceImpl* WebLocalFrameImpl::provisionalDataSourceImpl() const {
return static_cast<WebDataSourceImpl*>(provisionalDataSource());
}
void WebLocalFrameImpl::setFindEndstateFocusAndSelection() {
if (!m_textFinder || !m_textFinder->activeMatchFrame())
return;
if (Range* activeMatch = m_textFinder->activeMatch()) {
// If the user has set the selection since the match was found, we
// don't focus anything.
VisibleSelection selection(
frame()->selection().computeVisibleSelectionInDOMTreeDeprecated());
if (!selection.isNone())
return;
// Need to clean out style and layout state before querying
// Element::isFocusable().
frame()->document()->updateStyleAndLayoutIgnorePendingStylesheets();
// Try to find the first focusable node up the chain, which will, for
// example, focus links if we have found text within the link.
Node* node = activeMatch->firstNode();
if (node && node->isInShadowTree()) {
if (Node* host = node->ownerShadowHost()) {
if (isHTMLInputElement(*host) || isHTMLTextAreaElement(*host))
node = host;
}
}
const EphemeralRange activeMatchRange(activeMatch);
if (node) {
for (Node& runner : NodeTraversal::inclusiveAncestorsOf(*node)) {
if (!runner.isElementNode())
continue;
Element& element = toElement(runner);
if (element.isFocusable()) {
// Found a focusable parent node. Set the active match as the
// selection and focus to the focusable node.
frame()->selection().setSelection(
SelectionInDOMTree::Builder()
.setBaseAndExtent(activeMatchRange)
.build());
frame()->document()->setFocusedElement(
&element, FocusParams(SelectionBehaviorOnFocus::None,
WebFocusTypeNone, nullptr));
return;
}
}
}
// Iterate over all the nodes in the range until we find a focusable node.
// This, for example, sets focus to the first link if you search for
// text and text that is within one or more links.
for (Node& runner : activeMatchRange.nodes()) {
if (!runner.isElementNode())
continue;
Element& element = toElement(runner);
if (element.isFocusable()) {
frame()->document()->setFocusedElement(
&element, FocusParams(SelectionBehaviorOnFocus::None,
WebFocusTypeNone, nullptr));
return;
}
}
// No node related to the active match was focusable, so set the
// active match as the selection (so that when you end the Find session,
// you'll have the last thing you found highlighted) and make sure that
// we have nothing focused (otherwise you might have text selected but
// a link focused, which is weird).
frame()->selection().setSelection(SelectionInDOMTree::Builder()
.setBaseAndExtent(activeMatchRange)
.build());
frame()->document()->clearFocusedElement();
// Finally clear the active match, for two reasons:
// We just finished the find 'session' and we don't want future (potentially
// unrelated) find 'sessions' operations to start at the same place.
// The WebLocalFrameImpl could get reused and the activeMatch could end up
// pointing to a document that is no longer valid. Keeping an invalid
// reference around is just asking for trouble.
m_textFinder->resetActiveMatch();
}
}
void WebLocalFrameImpl::didFail(const ResourceError& error,
bool wasProvisional,
HistoryCommitType commitType) {
if (!client())
return;
WebURLError webError = error;
WebHistoryCommitType webCommitType =
static_cast<WebHistoryCommitType>(commitType);
if (WebPluginContainerImpl* plugin = pluginContainerFromFrame(frame()))
plugin->didFailLoading(error);
if (wasProvisional)
client()->didFailProvisionalLoad(this, webError, webCommitType);
else
client()->didFailLoad(this, webError, webCommitType);
}
void WebLocalFrameImpl::didFinish() {
if (!client())
return;
if (WebPluginContainerImpl* plugin = pluginContainerFromFrame(frame()))
plugin->didFinishLoading();
client()->didFinishLoad(this);
}
void WebLocalFrameImpl::setCanHaveScrollbars(bool canHaveScrollbars) {
frame()->view()->setCanHaveScrollbars(canHaveScrollbars);
}
void WebLocalFrameImpl::setInputEventsTransformForEmulation(
const IntSize& offset,
float contentScaleFactor) {
m_inputEventsOffsetForEmulation = offset;
m_inputEventsScaleFactorForEmulation = contentScaleFactor;
if (frame()->view())
frame()->view()->setInputEventsTransformForEmulation(
m_inputEventsOffsetForEmulation, m_inputEventsScaleFactorForEmulation);
}
void WebLocalFrameImpl::loadJavaScriptURL(const KURL& url) {
// This is copied from ScriptController::executeScriptIfJavaScriptURL.
// Unfortunately, we cannot just use that method since it is private, and
// it also doesn't quite behave as we require it to for bookmarklets. The
// key difference is that we need to suppress loading the string result
// from evaluating the JS URL if executing the JS URL resulted in a
// location change. We also allow a JS URL to be loaded even if scripts on
// the page are otherwise disabled.
if (!frame()->document() || !frame()->page())
return;
Document* ownerDocument(frame()->document());
// Protect privileged pages against bookmarklets and other javascript
// manipulations.
if (SchemeRegistry::shouldTreatURLSchemeAsNotAllowingJavascriptURLs(
frame()->document()->url().protocol()))
return;
String script = decodeURLEscapeSequences(
url.getString().substring(strlen("javascript:")));
UserGestureIndicator gestureIndicator(DocumentUserGestureToken::create(
frame()->document(), UserGestureToken::NewGesture));
v8::HandleScope handleScope(toIsolate(frame()));
v8::Local<v8::Value> result =
frame()->script().executeScriptInMainWorldAndReturnValue(
ScriptSourceCode(script));
if (result.IsEmpty() || !result->IsString())
return;
String scriptResult = toCoreString(v8::Local<v8::String>::Cast(result));
if (!frame()->navigationScheduler().locationChangePending())
frame()->loader().replaceDocumentWhileExecutingJavaScriptURL(scriptResult,
ownerDocument);
}
HitTestResult WebLocalFrameImpl::hitTestResultForVisualViewportPos(
const IntPoint& posInViewport) {
IntPoint rootFramePoint(
frame()->page()->visualViewport().viewportToRootFrame(posInViewport));
IntPoint docPoint(frame()->view()->rootFrameToContents(rootFramePoint));
HitTestResult result = frame()->eventHandler().hitTestResultAtPoint(
docPoint, HitTestRequest::ReadOnly | HitTestRequest::Active);
result.setToShadowHostIfInRestrictedShadowRoot();
return result;
}
static void ensureFrameLoaderHasCommitted(FrameLoader& frameLoader) {
// Internally, Blink uses CommittedMultipleRealLoads to track whether the
// next commit should create a new history item or not. Ensure we have
// reached that state.
if (frameLoader.stateMachine()->committedMultipleRealLoads())
return;
frameLoader.stateMachine()->advanceTo(
FrameLoaderStateMachine::CommittedMultipleRealLoads);
}
void WebLocalFrameImpl::setAutofillClient(WebAutofillClient* autofillClient) {
m_autofillClient = autofillClient;
}
WebAutofillClient* WebLocalFrameImpl::autofillClient() {
return m_autofillClient;
}
void WebLocalFrameImpl::setDevToolsAgentClient(
WebDevToolsAgentClient* devToolsClient) {
DCHECK(devToolsClient);
m_devToolsAgent = WebDevToolsAgentImpl::create(this, devToolsClient);
}
WebDevToolsAgent* WebLocalFrameImpl::devToolsAgent() {
return m_devToolsAgent.get();
}
WebLocalFrameImpl* WebLocalFrameImpl::localRoot() {
// This can't use the LocalFrame::localFrameRoot, since it may be called
// when the WebLocalFrame exists but the core LocalFrame does not.
// TODO(alexmos, dcheng): Clean this up to only calculate this in one place.
WebLocalFrameImpl* localRoot = this;
while (localRoot->parent() && localRoot->parent()->isWebLocalFrame())
localRoot = toWebLocalFrameImpl(localRoot->parent());
return localRoot;
}
void WebLocalFrameImpl::sendPings(const WebURL& destinationURL) {
DCHECK(frame());
DCHECK(m_contextMenuNode.get());
Element* anchor = m_contextMenuNode->enclosingLinkEventParentOrSelf();
if (isHTMLAnchorElement(anchor))
toHTMLAnchorElement(anchor)->sendPings(destinationURL);
}
bool WebLocalFrameImpl::dispatchBeforeUnloadEvent(bool isReload) {
if (!frame())
return true;
return frame()->loader().shouldClose(isReload);
}
WebURLRequest WebLocalFrameImpl::requestFromHistoryItem(
const WebHistoryItem& item,
WebCachePolicy cachePolicy) const {
HistoryItem* historyItem = item;
ResourceRequest request =
FrameLoader::resourceRequestFromHistoryItem(historyItem, cachePolicy);
return WrappedResourceRequest(request);
}
WebURLRequest WebLocalFrameImpl::requestForReload(
WebFrameLoadType loadType,
const WebURL& overrideUrl) const {
DCHECK(frame());
ResourceRequest request = frame()->loader().resourceRequestForReload(
static_cast<FrameLoadType>(loadType), overrideUrl);
return WrappedResourceRequest(request);
}
void WebLocalFrameImpl::load(const WebURLRequest& request,
WebFrameLoadType webFrameLoadType,
const WebHistoryItem& item,
WebHistoryLoadType webHistoryLoadType,
bool isClientRedirect) {
DCHECK(frame());
DCHECK(!request.isNull());
const ResourceRequest& resourceRequest = request.toResourceRequest();
if (resourceRequest.url().protocolIs("javascript") &&
webFrameLoadType == WebFrameLoadType::Standard) {
loadJavaScriptURL(resourceRequest.url());
return;
}
FrameLoadRequest frameRequest = FrameLoadRequest(nullptr, resourceRequest);
if (isClientRedirect)
frameRequest.setClientRedirect(ClientRedirectPolicy::ClientRedirect);
HistoryItem* historyItem = item;
frame()->loader().load(
frameRequest, static_cast<FrameLoadType>(webFrameLoadType), historyItem,
static_cast<HistoryLoadType>(webHistoryLoadType));
}
void WebLocalFrameImpl::loadData(const WebData& data,
const WebString& mimeType,
const WebString& textEncoding,
const WebURL& baseURL,
const WebURL& unreachableURL,
bool replace,
WebFrameLoadType webFrameLoadType,
const WebHistoryItem& item,
WebHistoryLoadType webHistoryLoadType,
bool isClientRedirect) {
DCHECK(frame());
// If we are loading substitute data to replace an existing load, then
// inherit all of the properties of that original request. This way,
// reload will re-attempt the original request. It is essential that
// we only do this when there is an unreachableURL since a non-empty
// unreachableURL informs FrameLoader::reload to load unreachableURL
// instead of the currently loaded URL.
ResourceRequest request;
if (replace && !unreachableURL.isEmpty() &&
frame()->loader().provisionalDocumentLoader())
request = frame()->loader().provisionalDocumentLoader()->originalRequest();
request.setURL(baseURL);
request.setCheckForBrowserSideNavigation(false);
FrameLoadRequest frameRequest(
0, request, SubstituteData(data, mimeType, textEncoding, unreachableURL));
DCHECK(frameRequest.substituteData().isValid());
frameRequest.setReplacesCurrentItem(replace);
if (isClientRedirect)
frameRequest.setClientRedirect(ClientRedirectPolicy::ClientRedirect);
HistoryItem* historyItem = item;
frame()->loader().load(
frameRequest, static_cast<FrameLoadType>(webFrameLoadType), historyItem,
static_cast<HistoryLoadType>(webHistoryLoadType));
}
bool WebLocalFrameImpl::maybeRenderFallbackContent(
const WebURLError& error) const {
DCHECK(frame());
if (!frame()->owner() || !frame()->owner()->canRenderFallbackContent())
return false;
FrameLoader& frameloader = frame()->loader();
DCHECK(frameloader.provisionalDocumentLoader());
frameloader.loadFailed(frameloader.provisionalDocumentLoader(), error);
return true;
}
// Called when a navigation is blocked because a Content Security Policy (CSP)
// is infringed.
void WebLocalFrameImpl::reportContentSecurityPolicyViolation(
const blink::WebContentSecurityPolicyViolation& violation) {
addMessageToConsole(blink::WebConsoleMessage(
WebConsoleMessage::LevelError, violation.consoleMessage,
violation.sourceLocation.url, violation.sourceLocation.lineNumber,
violation.sourceLocation.columnNumber));
std::unique_ptr<SourceLocation> sourceLocation = SourceLocation::create(
violation.sourceLocation.url, violation.sourceLocation.lineNumber,
violation.sourceLocation.columnNumber, nullptr);
DCHECK(frame() && frame()->document());
Document* document = frame()->document();
Vector<String> reportEndpoints;
for (const WebString& endPoint : violation.reportEndpoints)
reportEndpoints.push_back(endPoint);
document->contentSecurityPolicy()->reportViolation(
violation.directive, /* directiveText */
ContentSecurityPolicy::getDirectiveType(
violation.effectiveDirective), /* effectiveType */
violation.consoleMessage, /* consoleMessage */
violation.blockedUrl, /* blockedUrl */
reportEndpoints, /* reportEndpoints */
violation.header, /* header */
static_cast<ContentSecurityPolicyHeaderType>(violation.disposition),
ContentSecurityPolicy::ViolationType::URLViolation, /* ViolationType */
std::move(sourceLocation), nullptr, /* LocalFrame */
violation.afterRedirect ? RedirectStatus::FollowedRedirect
: RedirectStatus::NoRedirect,
nullptr); /* Element */
}
bool WebLocalFrameImpl::isLoading() const {
if (!frame() || !frame()->document())
return false;
return frame()->loader().stateMachine()->isDisplayingInitialEmptyDocument() ||
frame()->loader().hasProvisionalNavigation() ||
!frame()->document()->loadEventFinished();
}
bool WebLocalFrameImpl::isNavigationScheduledWithin(
double intervalInSeconds) const {
return frame() &&
frame()->navigationScheduler().isNavigationScheduledWithin(
intervalInSeconds);
}
void WebLocalFrameImpl::setCommittedFirstRealLoad() {
DCHECK(frame());
ensureFrameLoaderHasCommitted(frame()->loader());
}
void WebLocalFrameImpl::setHasReceivedUserGesture() {
if (frame())
frame()->setDocumentHasReceivedUserGesture();
}
void WebLocalFrameImpl::blinkFeatureUsageReport(const std::set<int>& features) {
DCHECK(!features.empty());
// Assimilate all features used/performed by the browser into UseCounter.
for (int feature : features) {
UseCounter::count(frame(), static_cast<UseCounter::Feature>(feature));
}
}
void WebLocalFrameImpl::mixedContentFound(
const WebURL& mainResourceUrl,
const WebURL& mixedContentUrl,
WebURLRequest::RequestContext requestContext,
bool wasAllowed,
bool hadRedirect,
const WebSourceLocation& sourceLocation) {
DCHECK(frame());
std::unique_ptr<SourceLocation> source;
if (!sourceLocation.url.isNull()) {
source =
SourceLocation::create(sourceLocation.url, sourceLocation.lineNumber,
sourceLocation.columnNumber, nullptr);
}
MixedContentChecker::mixedContentFound(
frame(), mainResourceUrl, mixedContentUrl, requestContext, wasAllowed,
hadRedirect, std::move(source));
}
void WebLocalFrameImpl::sendOrientationChangeEvent() {
if (!frame())
return;
// Screen Orientation API
if (ScreenOrientationController::from(*frame()))
ScreenOrientationController::from(*frame())->notifyOrientationChanged();
// Legacy window.orientation API
if (RuntimeEnabledFeatures::orientationEventEnabled() && frame()->domWindow())
frame()->domWindow()->sendOrientationChangeEvent();
}
void WebLocalFrameImpl::didCallAddSearchProvider() {
UseCounter::count(frame(), UseCounter::ExternalAddSearchProvider);
}
void WebLocalFrameImpl::didCallIsSearchProviderInstalled() {
UseCounter::count(frame(), UseCounter::ExternalIsSearchProviderInstalled);
}
void WebLocalFrameImpl::requestFind(int identifier,
const WebString& searchText,
const WebFindOptions& options) {
// Send "no results" if this frame has no visible content.
if (!hasVisibleContent() && !options.force) {
client()->reportFindInPageMatchCount(identifier, 0 /* count */,
true /* finalUpdate */);
return;
}
WebRange currentSelection = selectionRange();
bool result = false;
bool activeNow = false;
// Search for an active match only if this frame is focused or if this is a
// find next request.
if (isFocused() || options.findNext) {
result = find(identifier, searchText, options, false /* wrapWithinFrame */,
&activeNow);
}
if (result && !options.findNext) {
// Indicate that at least one match has been found. 1 here means
// possibly more matches could be coming.
client()->reportFindInPageMatchCount(identifier, 1 /* count */,
false /* finalUpdate */);
}
// There are three cases in which scoping is needed:
//
// (1) This is an initial find request (|options.findNext| is false). This
// will be the first scoping effort for this find session.
//
// (2) Something has been selected since the last search. This means that we
// cannot just increment the current match ordinal; we need to re-generate
// it.
//
// (3) TextFinder::Find() found what should be the next match (|result| is
// true), but was unable to activate it (|activeNow| is false). This means
// that the text containing this match was dynamically added since the last
// scope of the frame. The frame needs to be re-scoped so that any matches
// in the new text can be highlighted and included in the reported number of
// matches.
//
// If none of these cases are true, then we just report the current match
// count without scoping.
if (/* (1) */ options.findNext && /* (2) */ currentSelection.isNull() &&
/* (3) */ !(result && !activeNow)) {
// Force report of the actual count.
increaseMatchCount(0, identifier);
return;
}
// Start a new scoping request. If the scoping function determines that it
// needs to scope, it will defer until later.
ensureTextFinder().startScopingStringMatches(identifier, searchText, options);
}
bool WebLocalFrameImpl::find(int identifier,
const WebString& searchText,
const WebFindOptions& options,
bool wrapWithinFrame,
bool* activeNow) {
if (!frame())
return false;
// Unlikely, but just in case we try to find-in-page on a detached frame.
DCHECK(frame()->page());
// Up-to-date, clean tree is required for finding text in page, since it
// relies on TextIterator to look over the text.
frame()->document()->updateStyleAndLayoutIgnorePendingStylesheets();
return ensureTextFinder().find(identifier, searchText, options,
wrapWithinFrame, activeNow);
}
void WebLocalFrameImpl::stopFinding(StopFindAction action) {
bool clearSelection = action == StopFindActionClearSelection;
if (clearSelection)
executeCommand(WebString::fromUTF8("Unselect"));
if (m_textFinder) {
if (!clearSelection)
setFindEndstateFocusAndSelection();
m_textFinder->stopFindingAndClearSelection();
}
if (action == StopFindActionActivateSelection && isFocused()) {
WebDocument doc = document();
if (!doc.isNull()) {
WebElement element = doc.focusedElement();
if (!element.isNull())
element.simulateClick();
}
}
}
void WebLocalFrameImpl::increaseMatchCount(int count, int identifier) {
ensureTextFinder().increaseMatchCount(identifier, count);
}
void WebLocalFrameImpl::dispatchMessageEventWithOriginCheck(
const WebSecurityOrigin& intendedTargetOrigin,
const WebDOMEvent& event) {
DCHECK(!event.isNull());
frame()->domWindow()->dispatchMessageEventWithOriginCheck(
intendedTargetOrigin.get(), event,
SourceLocation::create(String(), 0, 0, nullptr));
}
int WebLocalFrameImpl::findMatchMarkersVersion() const {
if (m_textFinder)
return m_textFinder->findMatchMarkersVersion();
return 0;
}
int WebLocalFrameImpl::selectNearestFindMatch(const WebFloatPoint& point,
WebRect* selectionRect) {
return ensureTextFinder().selectNearestFindMatch(point, selectionRect);
}
float WebLocalFrameImpl::distanceToNearestFindMatch(
const WebFloatPoint& point) {
float nearestDistance;
ensureTextFinder().nearestFindMatch(point, &nearestDistance);
return nearestDistance;
}
WebFloatRect WebLocalFrameImpl::activeFindMatchRect() {
if (m_textFinder)
return m_textFinder->activeFindMatchRect();
return WebFloatRect();
}
void WebLocalFrameImpl::findMatchRects(WebVector<WebFloatRect>& outputRects) {
ensureTextFinder().findMatchRects(outputRects);
}
void WebLocalFrameImpl::setTickmarks(const WebVector<WebRect>& tickmarks) {
if (frameView()) {
Vector<IntRect> tickmarksConverted(tickmarks.size());
for (size_t i = 0; i < tickmarks.size(); ++i)
tickmarksConverted[i] = tickmarks[i];
frameView()->setTickmarks(tickmarksConverted);
}
}
void WebLocalFrameImpl::willBeDetached() {
if (m_devToolsAgent)
m_devToolsAgent->willBeDestroyed();
}
void WebLocalFrameImpl::willDetachParent() {
// Do not expect string scoping results from any frames that got detached
// in the middle of the operation.
if (m_textFinder && m_textFinder->scopingInProgress()) {
// There is a possibility that the frame being detached was the only
// pending one. We need to make sure final replies can be sent.
m_textFinder->flushCurrentScoping();
m_textFinder->cancelPendingScopingEffort();
}
}
TextFinder* WebLocalFrameImpl::textFinder() const {
return m_textFinder;
}
TextFinder& WebLocalFrameImpl::ensureTextFinder() {
if (!m_textFinder)
m_textFinder = TextFinder::create(*this);
return *m_textFinder;
}
void WebLocalFrameImpl::setFrameWidget(WebFrameWidgetBase* frameWidget) {
m_frameWidget = frameWidget;
}
WebFrameWidgetBase* WebLocalFrameImpl::frameWidget() const {
return m_frameWidget;
}
void WebLocalFrameImpl::copyImageAt(const WebPoint& posInViewport) {
HitTestResult result = hitTestResultForVisualViewportPos(posInViewport);
if (!isHTMLCanvasElement(result.innerNodeOrImageMapImage()) &&
result.absoluteImageURL().isEmpty()) {
// There isn't actually an image at these coordinates. Might be because
// the window scrolled while the context menu was open or because the page
// changed itself between when we thought there was an image here and when
// we actually tried to retreive the image.
//
// FIXME: implement a cache of the most recent HitTestResult to avoid having
// to do two hit tests.
return;
}
// TODO(xiaochengh): The use of updateStyleAndLayoutIgnorePendingStylesheets
// needs to be audited. See http://crbug.com/590369 for more details.
frame()->document()->updateStyleAndLayoutIgnorePendingStylesheets();
frame()->editor().copyImage(result);
}
void WebLocalFrameImpl::saveImageAt(const WebPoint& posInViewport) {
Node* node = hitTestResultForVisualViewportPos(posInViewport)
.innerNodeOrImageMapImage();
if (!node || !(isHTMLCanvasElement(*node) || isHTMLImageElement(*node)))
return;
String url = toElement(*node).imageSourceURL();
if (!KURL(KURL(), url).protocolIsData())
return;
m_client->saveImageFromDataURL(url);
}
void WebLocalFrameImpl::setEngagementLevel(mojom::EngagementLevel level) {
frame()->document()->setEngagementLevel(level);
}
WebSandboxFlags WebLocalFrameImpl::effectiveSandboxFlags() const {
if (!frame())
return WebSandboxFlags::None;
return static_cast<WebSandboxFlags>(
frame()->loader().effectiveSandboxFlags());
}
void WebLocalFrameImpl::forceSandboxFlags(WebSandboxFlags flags) {
frame()->loader().forceSandboxFlags(static_cast<SandboxFlags>(flags));
}
void WebLocalFrameImpl::clearActiveFindMatch() {
ensureTextFinder().clearActiveFindMatch();
}
void WebLocalFrameImpl::usageCountChromeLoadTimes(const WebString& metric) {
UseCounter::Feature feature = UseCounter::ChromeLoadTimesUnknown;
if (metric == "requestTime") {
feature = UseCounter::ChromeLoadTimesRequestTime;
} else if (metric == "startLoadTime") {
feature = UseCounter::ChromeLoadTimesStartLoadTime;
} else if (metric == "commitLoadTime") {
feature = UseCounter::ChromeLoadTimesCommitLoadTime;
} else if (metric == "finishDocumentLoadTime") {
feature = UseCounter::ChromeLoadTimesFinishDocumentLoadTime;
} else if (metric == "finishLoadTime") {
feature = UseCounter::ChromeLoadTimesFinishLoadTime;
} else if (metric == "firstPaintTime") {
feature = UseCounter::ChromeLoadTimesFirstPaintTime;
} else if (metric == "firstPaintAfterLoadTime") {
feature = UseCounter::ChromeLoadTimesFirstPaintAfterLoadTime;
} else if (metric == "navigationType") {
feature = UseCounter::ChromeLoadTimesNavigationType;
} else if (metric == "wasFetchedViaSpdy") {
feature = UseCounter::ChromeLoadTimesWasFetchedViaSpdy;
} else if (metric == "wasNpnNegotiated") {
feature = UseCounter::ChromeLoadTimesWasNpnNegotiated;
} else if (metric == "npnNegotiatedProtocol") {
feature = UseCounter::ChromeLoadTimesNpnNegotiatedProtocol;
} else if (metric == "wasAlternateProtocolAvailable") {
feature = UseCounter::ChromeLoadTimesWasAlternateProtocolAvailable;
} else if (metric == "connectionInfo") {
feature = UseCounter::ChromeLoadTimesConnectionInfo;
}
UseCounter::count(frame(), feature);
}
base::SingleThreadTaskRunner* WebLocalFrameImpl::timerTaskRunner() {
return frame()
->frameScheduler()
->timerTaskRunner()
->toSingleThreadTaskRunner();
}
base::SingleThreadTaskRunner* WebLocalFrameImpl::loadingTaskRunner() {
return frame()
->frameScheduler()
->loadingTaskRunner()
->toSingleThreadTaskRunner();
}
base::SingleThreadTaskRunner* WebLocalFrameImpl::unthrottledTaskRunner() {
return frame()
->frameScheduler()
->unthrottledTaskRunner()
->toSingleThreadTaskRunner();
}
WebInputMethodControllerImpl* WebLocalFrameImpl::inputMethodController() const {
return m_inputMethodController.get();
}
void WebLocalFrameImpl::extractSmartClipData(WebRect rectInViewport,
WebString& clipText,
WebString& clipHtml) {
SmartClipData clipData = SmartClip(frame()).dataForRect(rectInViewport);
clipText = clipData.clipData();
WebPoint startPoint(rectInViewport.x, rectInViewport.y);
WebPoint endPoint(rectInViewport.x + rectInViewport.width,
rectInViewport.y + rectInViewport.height);
VisiblePosition startVisiblePosition =
visiblePositionForViewportPoint(startPoint);
VisiblePosition endVisiblePosition =
visiblePositionForViewportPoint(endPoint);
Position startPosition = startVisiblePosition.deepEquivalent();
Position endPosition = endVisiblePosition.deepEquivalent();
// document() will return null if -webkit-user-select is set to none.
if (!startPosition.document() || !endPosition.document())
return;
if (startPosition.compareTo(endPosition) <= 0) {
clipHtml =
createMarkup(startPosition, endPosition, AnnotateForInterchange,
ConvertBlocksToInlines::NotConvert, ResolveNonLocalURLs);
} else {
clipHtml =
createMarkup(endPosition, startPosition, AnnotateForInterchange,
ConvertBlocksToInlines::NotConvert, ResolveNonLocalURLs);
}
}
} // namespace blink