blob: 7c3d3c8fdbab02ea6d53147203d2a73ede7daee6 [file] [log] [blame]
/*
* Copyright (C) 1998, 1999 Torben Weis <weis@kde.org>
* 1999 Lars Knoll <knoll@kde.org>
* 1999 Antti Koivisto <koivisto@kde.org>
* 2000 Simon Hausmann <hausmann@kde.org>
* 2000 Stefan Schimanski <1Stein@gmx.de>
* 2001 George Staikos <staikos@kde.org>
* Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 Apple Inc. All rights reserved.
* Copyright (C) 2005 Alexey Proskuryakov <ap@nypop.com>
* Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies)
* Copyright (C) 2008 Eric Seidel <eric@webkit.org>
* Copyright (C) 2008 Google Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public License
* along with this library; see the file COPYING.LIB. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#include "core/frame/LocalFrame.h"
#include "bindings/core/v8/ScriptController.h"
#include "core/InstrumentingAgents.h"
#include "core/dom/DocumentType.h"
#include "core/dom/StyleChangeReason.h"
#include "core/editing/EditingUtilities.h"
#include "core/editing/Editor.h"
#include "core/editing/FrameSelection.h"
#include "core/editing/InputMethodController.h"
#include "core/editing/serializers/Serialization.h"
#include "core/editing/spellcheck/SpellChecker.h"
#include "core/events/Event.h"
#include "core/fetch/ResourceFetcher.h"
#include "core/frame/EventHandlerRegistry.h"
#include "core/frame/FrameConsole.h"
#include "core/frame/FrameHost.h"
#include "core/frame/FrameView.h"
#include "core/frame/LocalDOMWindow.h"
#include "core/frame/Settings.h"
#include "core/html/HTMLFrameElementBase.h"
#include "core/html/HTMLPlugInElement.h"
#include "core/input/EventHandler.h"
#include "core/inspector/ConsoleMessageStorage.h"
#include "core/inspector/InspectorInstrumentation.h"
#include "core/layout/HitTestResult.h"
#include "core/layout/LayoutView.h"
#include "core/layout/api/LayoutViewItem.h"
#include "core/layout/compositing/PaintLayerCompositor.h"
#include "core/loader/FrameLoadRequest.h"
#include "core/loader/FrameLoaderClient.h"
#include "core/loader/NavigationScheduler.h"
#include "core/page/ChromeClient.h"
#include "core/page/FocusController.h"
#include "core/page/Page.h"
#include "core/page/scrolling/ScrollingCoordinator.h"
#include "core/paint/ObjectPainter.h"
#include "core/paint/PaintInfo.h"
#include "core/paint/PaintLayer.h"
#include "core/paint/TransformRecorder.h"
#include "core/svg/SVGDocumentExtensions.h"
#include "platform/DragImage.h"
#include "platform/PluginScriptForbiddenScope.h"
#include "platform/RuntimeEnabledFeatures.h"
#include "platform/ScriptForbiddenScope.h"
#include "platform/graphics/GraphicsContext.h"
#include "platform/graphics/StaticBitmapImage.h"
#include "platform/graphics/paint/ClipRecorder.h"
#include "platform/graphics/paint/PaintController.h"
#include "platform/graphics/paint/SkPictureBuilder.h"
#include "platform/graphics/paint/TransformDisplayItem.h"
#include "platform/plugins/PluginData.h"
#include "platform/text/TextStream.h"
#include "public/platform/ServiceRegistry.h"
#include "public/platform/WebFrameScheduler.h"
#include "public/platform/WebScreenInfo.h"
#include "public/platform/WebViewScheduler.h"
#include "third_party/skia/include/core/SkImage.h"
#include "wtf/PassOwnPtr.h"
#include "wtf/StdLibExtras.h"
namespace blink {
using namespace HTMLNames;
namespace {
// Convenience class for initializing a GraphicsContext to build a DragImage from a specific
// region specified by |bounds|. After painting the using context(), the DragImage returned from
// createImage() will only contain the content in |bounds| with the appropriate device scale
// factor included.
class DragImageBuilder {
STACK_ALLOCATED();
public:
DragImageBuilder(const LocalFrame* localFrame, const FloatRect& bounds, Node* draggedNode, float opacity = 1)
: m_localFrame(localFrame)
, m_draggedNode(draggedNode)
, m_bounds(bounds)
, m_opacity(opacity)
{
if (m_draggedNode && m_draggedNode->layoutObject())
m_draggedNode->layoutObject()->updateDragState(true);
float deviceScaleFactor = m_localFrame->host()->chromeClient().screenInfo().deviceScaleFactor;
m_bounds.setWidth(m_bounds.width() * deviceScaleFactor);
m_bounds.setHeight(m_bounds.height() * deviceScaleFactor);
m_pictureBuilder = adoptPtr(new SkPictureBuilder(SkRect::MakeIWH(m_bounds.width(), m_bounds.height())));
AffineTransform transform;
transform.scale(deviceScaleFactor, deviceScaleFactor);
transform.translate(-m_bounds.x(), -m_bounds.y());
context().getPaintController().createAndAppend<BeginTransformDisplayItem>(*m_pictureBuilder, transform);
}
GraphicsContext& context() { return m_pictureBuilder->context(); }
PassOwnPtr<DragImage> createImage()
{
if (m_draggedNode && m_draggedNode->layoutObject())
m_draggedNode->layoutObject()->updateDragState(false);
context().getPaintController().endItem<EndTransformDisplayItem>(*m_pictureBuilder);
RefPtr<const SkPicture> recording = m_pictureBuilder->endRecording();
RefPtr<SkImage> skImage = adoptRef(SkImage::NewFromPicture(recording.get(),
SkISize::Make(m_bounds.width(), m_bounds.height()), nullptr, nullptr));
RefPtr<Image> image = StaticBitmapImage::create(skImage.release());
RespectImageOrientationEnum imageOrientation = DoNotRespectImageOrientation;
if (m_draggedNode && m_draggedNode->layoutObject())
imageOrientation = LayoutObject::shouldRespectImageOrientation(m_draggedNode->layoutObject());
float screenDeviceScaleFactor = m_localFrame->page()->chromeClient().screenInfo().deviceScaleFactor;
return DragImage::create(image.get(), imageOrientation, screenDeviceScaleFactor, InterpolationHigh, m_opacity);
}
private:
Member<const LocalFrame> m_localFrame;
Member<Node> m_draggedNode;
FloatRect m_bounds;
float m_opacity;
OwnPtr<SkPictureBuilder> m_pictureBuilder;
};
inline float parentPageZoomFactor(LocalFrame* frame)
{
Frame* parent = frame->tree().parent();
if (!parent || !parent->isLocalFrame())
return 1;
return toLocalFrame(parent)->pageZoomFactor();
}
inline float parentTextZoomFactor(LocalFrame* frame)
{
Frame* parent = frame->tree().parent();
if (!parent || !parent->isLocalFrame())
return 1;
return toLocalFrame(parent)->textZoomFactor();
}
} // namespace
LocalFrame* LocalFrame::create(FrameLoaderClient* client, FrameHost* host, FrameOwner* owner, ServiceRegistry* serviceRegistry)
{
LocalFrame* frame = new LocalFrame(client, host, owner, serviceRegistry ? serviceRegistry : ServiceRegistry::getEmptyServiceRegistry());
InspectorInstrumentation::frameAttachedToParent(frame);
return frame;
}
void LocalFrame::setView(FrameView* view)
{
ASSERT(!m_view || m_view != view);
ASSERT(!document() || !document()->isActive());
eventHandler().clear();
m_view = view;
}
void LocalFrame::createView(const IntSize& viewportSize, const Color& backgroundColor, bool transparent,
ScrollbarMode horizontalScrollbarMode, bool horizontalLock,
ScrollbarMode verticalScrollbarMode, bool verticalLock)
{
ASSERT(this);
ASSERT(page());
bool isLocalRoot = this->isLocalRoot();
if (isLocalRoot && view())
view()->setParentVisible(false);
setView(nullptr);
FrameView* frameView = nullptr;
if (isLocalRoot) {
frameView = FrameView::create(this, viewportSize);
// The layout size is set by WebViewImpl to support @viewport
frameView->setLayoutSizeFixedToFrameSize(false);
} else {
frameView = FrameView::create(this);
}
frameView->setScrollbarModes(horizontalScrollbarMode, verticalScrollbarMode, horizontalLock, verticalLock);
setView(frameView);
frameView->updateBackgroundRecursively(backgroundColor, transparent);
if (isLocalRoot)
frameView->setParentVisible(true);
// FIXME: Not clear what the right thing for OOPI is here.
if (ownerLayoutObject()) {
HTMLFrameOwnerElement* owner = deprecatedLocalOwner();
ASSERT(owner);
// FIXME: OOPI might lead to us temporarily lying to a frame and telling it
// that it's owned by a FrameOwner that knows nothing about it. If we're
// lying to this frame, don't let it clobber the existing widget.
if (owner->contentFrame() == this)
owner->setWidget(frameView);
}
if (owner())
view()->setCanHaveScrollbars(owner()->scrollingMode() != ScrollbarAlwaysOff);
}
LocalFrame::~LocalFrame()
{
// Verify that the FrameView has been cleared as part of detaching
// the frame owner.
ASSERT(!m_view);
}
DEFINE_TRACE(LocalFrame)
{
visitor->trace(m_instrumentingAgents);
visitor->trace(m_loader);
visitor->trace(m_navigationScheduler);
visitor->trace(m_view);
visitor->trace(m_domWindow);
visitor->trace(m_pagePopupOwner);
visitor->trace(m_script);
visitor->trace(m_editor);
visitor->trace(m_spellChecker);
visitor->trace(m_selection);
visitor->trace(m_eventHandler);
visitor->trace(m_console);
visitor->trace(m_inputMethodController);
Frame::trace(visitor);
LocalFrameLifecycleNotifier::trace(visitor);
Supplementable<LocalFrame>::trace(visitor);
}
DOMWindow* LocalFrame::domWindow() const
{
return m_domWindow.get();
}
WindowProxy* LocalFrame::windowProxy(DOMWrapperWorld& world)
{
return m_script->windowProxy(world);
}
void LocalFrame::navigate(Document& originDocument, const KURL& url, bool replaceCurrentItem, UserGestureStatus userGestureStatus)
{
// TODO(dcheng): Special case for window.open("about:blank") to ensure it loads synchronously into
// a new window. This is our historical behavior, and it's consistent with the creation of
// a new iframe with src="about:blank". Perhaps we could get rid of this if we started reporting
// the initial empty document's url as about:blank? See crbug.com/471239.
// TODO(japhet): This special case is also necessary for behavior asserted by some extensions tests.
// Using NavigationScheduler::scheduleNavigationChange causes the navigation to be flagged as a
// client redirect, which is observable via the webNavigation extension api.
if (isMainFrame() && !m_loader.stateMachine()->committedFirstRealDocumentLoad()) {
FrameLoadRequest request(&originDocument, url);
request.resourceRequest().setHasUserGesture(userGestureStatus == UserGestureStatus::Active);
navigate(request);
} else {
m_navigationScheduler->scheduleLocationChange(&originDocument, url.getString(), replaceCurrentItem);
}
}
void LocalFrame::navigate(const FrameLoadRequest& request)
{
m_loader.load(request);
}
void LocalFrame::reload(FrameLoadType loadType, ClientRedirectPolicy clientRedirectPolicy)
{
ASSERT(loadType == FrameLoadTypeReload || loadType == FrameLoadTypeReloadBypassingCache);
ASSERT(clientRedirectPolicy == ClientRedirectPolicy::NotClientRedirect || loadType == FrameLoadTypeReload);
if (clientRedirectPolicy == ClientRedirectPolicy::NotClientRedirect) {
if (!m_loader.currentItem())
return;
FrameLoadRequest request = FrameLoadRequest(
nullptr, m_loader.resourceRequestForReload(loadType, KURL(), clientRedirectPolicy));
request.setClientRedirect(clientRedirectPolicy);
m_loader.load(request, loadType);
} else {
m_navigationScheduler->scheduleReload();
}
}
void LocalFrame::detach(FrameDetachType type)
{
PluginScriptForbiddenScope forbidPluginDestructorScripting;
m_loader.stopAllLoaders();
// Don't allow any new child frames to load in this frame: attaching a new
// child frame during or after detaching children results in an attached
// frame on a detached DOM tree, which is bad.
SubframeLoadingDisabler disabler(*document());
m_loader.dispatchUnloadEvent();
detachChildren();
m_frameScheduler.clear();
// All done if detaching the subframes brought about a detach of this frame also.
if (!client())
return;
// stopAllLoaders() needs to be called after detachChildren(), because detachChildren()
// will trigger the unload event handlers of any child frames, and those event
// handlers might start a new subresource load in this frame.
m_loader.stopAllLoaders();
m_loader.detach();
document()->detach();
// This is the earliest that scripting can be disabled:
// - FrameLoader::detach() can fire XHR abort events
// - Document::detach()'s deferred widget updates can run script.
ScriptForbiddenScope forbidScript;
m_loader.clear();
if (!client())
return;
client()->willBeDetached();
// Notify ScriptController that the frame is closing, since its cleanup ends up calling
// back to FrameLoaderClient via WindowProxy.
script().clearForClose();
setView(nullptr);
willDetachFrameHost();
InspectorInstrumentation::frameDetachedFromParent(this);
Frame::detach(type);
// Signal frame destruction here rather than in the destructor.
// Main motivation is to avoid being dependent on its exact timing (Oilpan.)
LocalFrameLifecycleNotifier::notifyContextDestroyed();
m_supplements.clear();
WeakIdentifierMap<LocalFrame>::notifyObjectDestroyed(this);
}
bool LocalFrame::prepareForCommit()
{
return loader().prepareForCommit();
}
SecurityContext* LocalFrame::securityContext() const
{
return document();
}
void LocalFrame::printNavigationErrorMessage(const Frame& targetFrame, const char* reason)
{
// URLs aren't available for RemoteFrames, so the error message uses their
// origin instead.
String targetFrameDescription = targetFrame.isLocalFrame() ? "with URL '" + toLocalFrame(targetFrame).document()->url().getString() + "'" : "with origin '" + targetFrame.securityContext()->getSecurityOrigin()->toString() + "'";
String message = "Unsafe JavaScript attempt to initiate navigation for frame " + targetFrameDescription + " from frame with URL '" + document()->url().getString() + "'. " + reason + "\n";
localDOMWindow()->printErrorMessage(message);
}
WindowProxyManager* LocalFrame::getWindowProxyManager() const
{
return m_script->getWindowProxyManager();
}
bool LocalFrame::shouldClose()
{
// TODO(dcheng): This should be fixed to dispatch beforeunload events to
// both local and remote frames.
return m_loader.shouldClose();
}
void LocalFrame::willDetachFrameHost()
{
LocalFrameLifecycleNotifier::notifyWillDetachFrameHost();
// FIXME: Page should take care of updating focus/scrolling instead of Frame.
// FIXME: It's unclear as to why this is called more than once, but it is,
// so page() could be null.
if (page() && page()->focusController().focusedFrame() == this)
page()->focusController().setFocusedFrame(nullptr);
if (page() && page()->scrollingCoordinator() && m_view)
page()->scrollingCoordinator()->willDestroyScrollableArea(m_view.get());
}
void LocalFrame::setDOMWindow(LocalDOMWindow* domWindow)
{
// Oilpan: setDOMWindow() cannot be used when finalizing. Which
// is acceptable as its actions are either not needed or handled
// by other means --
//
// - LocalFrameLifecycleObserver::willDetachFrameHost() will have
// signalled the Inspector frameWindowDiscarded() notifications.
// We assume that all LocalFrames are detached, where that notification
// will have been done.
//
// - Calling LocalDOMWindow::reset() is not needed (called from
// Frame::setDOMWindow().) The Member references it clears will now
// die with the window. And the registered DOMWindowProperty instances that don't,
// only keep a weak reference to this frame, so there's no need to be
// explicitly notified that this frame is going away.
if (m_domWindow && host())
host()->consoleMessageStorage().frameWindowDiscarded(m_domWindow.get());
if (domWindow)
script().clearWindowProxy();
if (m_domWindow)
m_domWindow->reset();
m_domWindow = domWindow;
}
Document* LocalFrame::document() const
{
return m_domWindow ? m_domWindow->document() : nullptr;
}
void LocalFrame::setPagePopupOwner(Element& owner)
{
m_pagePopupOwner = &owner;
}
LayoutView* LocalFrame::contentLayoutObject() const
{
return document() ? document()->layoutView() : nullptr;
}
LayoutViewItem LocalFrame::contentLayoutItem() const
{
return LayoutViewItem(contentLayoutObject());
}
void LocalFrame::didChangeVisibilityState()
{
if (document())
document()->didChangeVisibilityState();
Frame::didChangeVisibilityState();
}
LocalFrame* LocalFrame::localFrameRoot()
{
LocalFrame* curFrame = this;
while (curFrame && curFrame->tree().parent() && curFrame->tree().parent()->isLocalFrame())
curFrame = toLocalFrame(curFrame->tree().parent());
return curFrame;
}
String LocalFrame::layerTreeAsText(LayerTreeFlags flags) const
{
TextStream textStream;
textStream << localLayerTreeAsText(flags);
for (Frame* child = tree().firstChild(); child; child = child->tree().traverseNext(this)) {
if (!child->isLocalFrame())
continue;
String childLayerTree = toLocalFrame(child)->localLayerTreeAsText(flags);
if (!childLayerTree.length())
continue;
textStream << "\n\n--------\nFrame: '";
textStream << child->tree().uniqueName();
textStream << "'\n--------\n";
textStream << childLayerTree;
}
return textStream.release();
}
void LocalFrame::setPrinting(bool printing, const FloatSize& pageSize, const FloatSize& originalPageSize, float maximumShrinkRatio)
{
// In setting printing, we should not validate resources already cached for the document.
// See https://bugs.webkit.org/show_bug.cgi?id=43704
ResourceCacheValidationSuppressor validationSuppressor(document()->fetcher());
document()->setPrinting(printing);
view()->adjustMediaTypeForPrinting(printing);
if (shouldUsePrintingLayout()) {
view()->forceLayoutForPagination(pageSize, originalPageSize, maximumShrinkRatio);
} else {
if (LayoutView* layoutView = view()->layoutView()) {
layoutView->setPreferredLogicalWidthsDirty();
layoutView->setNeedsLayout(LayoutInvalidationReason::PrintingChanged);
layoutView->setShouldDoFullPaintInvalidationForViewAndAllDescendants();
}
view()->layout();
view()->adjustViewSize();
}
// Subframes of the one we're printing don't lay out to the page size.
for (Frame* child = tree().firstChild(); child; child = child->tree().nextSibling()) {
if (child->isLocalFrame())
toLocalFrame(child)->setPrinting(printing, FloatSize(), FloatSize(), 0);
}
}
bool LocalFrame::shouldUsePrintingLayout() const
{
// Only top frame being printed should be fit to page size.
// Subframes should be constrained by parents only.
return document()->printing() && (!tree().parent() || !tree().parent()->isLocalFrame() || !toLocalFrame(tree().parent())->document()->printing());
}
FloatSize LocalFrame::resizePageRectsKeepingRatio(const FloatSize& originalSize, const FloatSize& expectedSize)
{
FloatSize resultSize;
if (!contentLayoutObject())
return FloatSize();
if (contentLayoutObject()->style()->isHorizontalWritingMode()) {
ASSERT(fabs(originalSize.width()) > std::numeric_limits<float>::epsilon());
float ratio = originalSize.height() / originalSize.width();
resultSize.setWidth(floorf(expectedSize.width()));
resultSize.setHeight(floorf(resultSize.width() * ratio));
} else {
ASSERT(fabs(originalSize.height()) > std::numeric_limits<float>::epsilon());
float ratio = originalSize.width() / originalSize.height();
resultSize.setHeight(floorf(expectedSize.height()));
resultSize.setWidth(floorf(resultSize.height() * ratio));
}
return resultSize;
}
void LocalFrame::setPageZoomFactor(float factor)
{
setPageAndTextZoomFactors(factor, m_textZoomFactor);
}
void LocalFrame::setTextZoomFactor(float factor)
{
setPageAndTextZoomFactors(m_pageZoomFactor, factor);
}
void LocalFrame::setPageAndTextZoomFactors(float pageZoomFactor, float textZoomFactor)
{
if (m_pageZoomFactor == pageZoomFactor && m_textZoomFactor == textZoomFactor)
return;
Page* page = this->page();
if (!page)
return;
Document* document = this->document();
if (!document)
return;
// Respect SVGs zoomAndPan="disabled" property in standalone SVG documents.
// FIXME: How to handle compound documents + zoomAndPan="disabled"? Needs SVG WG clarification.
if (document->isSVGDocument()) {
if (!document->accessSVGExtensions().zoomAndPanEnabled())
return;
}
if (m_pageZoomFactor != pageZoomFactor) {
if (FrameView* view = this->view()) {
// Update the scroll position when doing a full page zoom, so the content stays in relatively the same position.
LayoutPoint scrollPosition = view->scrollPosition();
float percentDifference = (pageZoomFactor / m_pageZoomFactor);
view->setScrollPosition(
DoublePoint(scrollPosition.x() * percentDifference, scrollPosition.y() * percentDifference),
ProgrammaticScroll);
}
}
m_pageZoomFactor = pageZoomFactor;
m_textZoomFactor = textZoomFactor;
for (Frame* child = tree().firstChild(); child; child = child->tree().nextSibling()) {
if (child->isLocalFrame())
toLocalFrame(child)->setPageAndTextZoomFactors(m_pageZoomFactor, m_textZoomFactor);
}
document->setNeedsStyleRecalc(SubtreeStyleChange, StyleChangeReasonForTracing::create(StyleChangeReason::Zoom));
document->updateStyleAndLayoutIgnorePendingStylesheets();
}
void LocalFrame::deviceScaleFactorChanged()
{
document()->mediaQueryAffectingValueChanged();
for (Frame* child = tree().firstChild(); child; child = child->tree().nextSibling()) {
if (child->isLocalFrame())
toLocalFrame(child)->deviceScaleFactorChanged();
}
}
double LocalFrame::devicePixelRatio() const
{
if (!m_host)
return 0;
double ratio = m_host->deviceScaleFactorDeprecated();
ratio *= pageZoomFactor();
return ratio;
}
PassOwnPtr<DragImage> LocalFrame::nodeImage(Node& node)
{
m_view->updateAllLifecyclePhasesExceptPaint();
LayoutObject* layoutObject = node.layoutObject();
if (!layoutObject)
return nullptr;
// Paint starting at the nearest self painting layer, clipped to the object itself.
// TODO(pdr): This will also paint the content behind the object if the object contains
// transparency but the layer is opaque. We could directly call layoutObject->paint(...)
// (see ObjectPainter::paintAllPhasesAtomically) but this would skip self-painting children.
PaintLayer* layer = layoutObject->enclosingLayer()->enclosingSelfPaintingLayer();
IntRect absoluteBoundingBox = layoutObject->absoluteBoundingBoxRectIncludingDescendants();
FloatRect boundingBox = layer->layoutObject()->absoluteToLocalQuad(FloatQuad(absoluteBoundingBox), UseTransforms).boundingBox();
DragImageBuilder dragImageBuilder(this, boundingBox, &node);
{
PaintLayerPaintingInfo paintingInfo(layer, LayoutRect(boundingBox), GlobalPaintFlattenCompositingLayers, LayoutSize(), 0);
PaintLayerFlags flags = PaintLayerHaveTransparency | PaintLayerAppliedTransform | PaintLayerUncachedClipRects;
PaintLayerPainter(*layer).paintLayer(dragImageBuilder.context(), paintingInfo, flags);
}
return dragImageBuilder.createImage();
}
PassOwnPtr<DragImage> LocalFrame::dragImageForSelection(float opacity)
{
if (!selection().isRange())
return nullptr;
m_view->updateAllLifecyclePhasesExceptPaint();
ASSERT(document()->isActive());
FloatRect paintingRect = FloatRect(selection().bounds());
DragImageBuilder dragImageBuilder(this, paintingRect, nullptr, opacity);
GlobalPaintFlags paintFlags = GlobalPaintSelectionOnly | GlobalPaintFlattenCompositingLayers;
m_view->paintContents(dragImageBuilder.context(), paintFlags, enclosingIntRect(paintingRect));
return dragImageBuilder.createImage();
}
String LocalFrame::selectedText() const
{
return selection().selectedText();
}
String LocalFrame::selectedTextForClipboard() const
{
return selection().selectedTextForClipboard();
}
PositionWithAffinity LocalFrame::positionForPoint(const IntPoint& framePoint)
{
HitTestResult result = eventHandler().hitTestResultAtPoint(framePoint);
Node* node = result.innerNodeOrImageMapImage();
if (!node)
return PositionWithAffinity();
LayoutObject* layoutObject = node->layoutObject();
if (!layoutObject)
return PositionWithAffinity();
const PositionWithAffinity position = layoutObject->positionForPoint(result.localPoint());
if (position.isNull())
return PositionWithAffinity(firstPositionInOrBeforeNode(node));
return position;
}
Document* LocalFrame::documentAtPoint(const IntPoint& pointInRootFrame)
{
if (!view())
return nullptr;
IntPoint pt = view()->rootFrameToContents(pointInRootFrame);
if (!contentLayoutObject())
return nullptr;
HitTestResult result = eventHandler().hitTestResultAtPoint(pt, HitTestRequest::ReadOnly | HitTestRequest::Active);
return result.innerNode() ? &result.innerNode()->document() : nullptr;
}
EphemeralRange LocalFrame::rangeForPoint(const IntPoint& framePoint)
{
const PositionWithAffinity positionWithAffinity = positionForPoint(framePoint);
if (positionWithAffinity.isNull())
return EphemeralRange();
VisiblePosition position = createVisiblePosition(positionWithAffinity);
VisiblePosition previous = previousPositionOf(position);
if (previous.isNotNull()) {
const EphemeralRange previousCharacterRange = makeRange(previous, position);
IntRect rect = editor().firstRectForRange(previousCharacterRange);
if (rect.contains(framePoint))
return EphemeralRange(previousCharacterRange);
}
VisiblePosition next = nextPositionOf(position);
const EphemeralRange nextCharacterRange = makeRange(position, next);
if (nextCharacterRange.isNotNull()) {
IntRect rect = editor().firstRectForRange(nextCharacterRange);
if (rect.contains(framePoint))
return EphemeralRange(nextCharacterRange);
}
return EphemeralRange();
}
bool LocalFrame::isURLAllowed(const KURL& url) const
{
// Exempt about: URLs from self-reference check.
if (url.protocolIsAbout())
return true;
// We allow one level of self-reference because some sites depend on that,
// but we don't allow more than one.
bool foundSelfReference = false;
for (const Frame* frame = this; frame; frame = frame->tree().parent()) {
if (!frame->isLocalFrame())
continue;
if (equalIgnoringFragmentIdentifier(toLocalFrame(frame)->document()->url(), url)) {
if (foundSelfReference)
return false;
foundSelfReference = true;
}
}
return true;
}
bool LocalFrame::shouldReuseDefaultView(const KURL& url) const
{
// Secure transitions can only happen when navigating from the initial empty
// document.
if (!loader().stateMachine()->isDisplayingInitialEmptyDocument())
return false;
return document()->isSecureTransitionTo(url);
}
void LocalFrame::removeSpellingMarkersUnderWords(const Vector<String>& words)
{
spellChecker().removeSpellingMarkersUnderWords(words);
}
String LocalFrame::localLayerTreeAsText(unsigned flags) const
{
if (!contentLayoutObject())
return String();
return contentLayoutObject()->compositor()->layerTreeAsText(static_cast<LayerTreeFlags>(flags));
}
bool LocalFrame::shouldThrottleRendering() const
{
return view() && view()->shouldThrottleRendering();
}
inline LocalFrame::LocalFrame(FrameLoaderClient* client, FrameHost* host, FrameOwner* owner, ServiceRegistry* serviceRegistry)
: Frame(client, host, owner)
, m_loader(this)
, m_navigationScheduler(NavigationScheduler::create(this))
, m_script(ScriptController::create(this))
, m_editor(Editor::create(*this))
, m_spellChecker(SpellChecker::create(*this))
, m_selection(FrameSelection::create(this))
, m_eventHandler(new EventHandler(this))
, m_console(FrameConsole::create(*this))
, m_inputMethodController(InputMethodController::create(*this))
, m_navigationDisableCount(0)
, m_pageZoomFactor(parentPageZoomFactor(this))
, m_textZoomFactor(parentTextZoomFactor(this))
, m_inViewSourceMode(false)
, m_serviceRegistry(serviceRegistry)
{
if (isLocalRoot())
m_instrumentingAgents = new InstrumentingAgents();
else
m_instrumentingAgents = localFrameRoot()->m_instrumentingAgents;
}
WebFrameScheduler* LocalFrame::frameScheduler()
{
if (!m_frameScheduler.get())
m_frameScheduler = page()->chromeClient().createFrameScheduler(client()->frameBlameContext());
ASSERT(m_frameScheduler.get());
return m_frameScheduler.get();
}
void LocalFrame::scheduleVisualUpdateUnlessThrottled()
{
if (shouldThrottleRendering())
return;
page()->animator().scheduleVisualUpdate(this);
}
FrameLoaderClient* LocalFrame::client() const
{
return static_cast<FrameLoaderClient*>(Frame::client());
}
PluginData* LocalFrame::pluginData() const
{
if (!loader().allowPlugins(NotAboutToInstantiatePlugin))
return nullptr;
return page()->pluginData();
}
DEFINE_WEAK_IDENTIFIER_MAP(LocalFrame);
FrameNavigationDisabler::FrameNavigationDisabler(LocalFrame& frame)
: m_frame(&frame)
{
m_frame->disableNavigation();
}
FrameNavigationDisabler::~FrameNavigationDisabler()
{
m_frame->enableNavigation();
}
} // namespace blink