blob: 18d1b8857740f439ad4c5664fe8efe71c13dbee3 [file] [log] [blame]
/*
* Copyright (C) 2011 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.
*/
#include "core/inspector/InspectorPageAgent.h"
#include "bindings/core/v8/DOMWrapperWorld.h"
#include "bindings/core/v8/ScriptController.h"
#include "bindings/core/v8/ScriptRegexp.h"
#include "core/HTMLNames.h"
#include "core/dom/DOMImplementation.h"
#include "core/dom/Document.h"
#include "core/fetch/CSSStyleSheetResource.h"
#include "core/fetch/FontResource.h"
#include "core/fetch/ImageResource.h"
#include "core/fetch/MemoryCache.h"
#include "core/fetch/Resource.h"
#include "core/fetch/ResourceFetcher.h"
#include "core/fetch/ScriptResource.h"
#include "core/frame/LocalFrame.h"
#include "core/html/HTMLFrameOwnerElement.h"
#include "core/html/VoidCallback.h"
#include "core/html/imports/HTMLImportLoader.h"
#include "core/html/imports/HTMLImportsController.h"
#include "core/html/parser/TextResourceDecoder.h"
#include "core/inspector/DOMPatchSupport.h"
#include "core/inspector/IdentifiersFactory.h"
#include "core/inspector/InspectedFrames.h"
#include "core/inspector/InspectorCSSAgent.h"
#include "core/inspector/InspectorDebuggerAgent.h"
#include "core/inspector/InspectorInstrumentation.h"
#include "core/inspector/InspectorResourceContentLoader.h"
#include "core/inspector/InstrumentingAgents.h"
#include "core/inspector/v8/public/V8ContentSearchUtil.h"
#include "core/loader/DocumentLoader.h"
#include "core/loader/FrameLoader.h"
#include "platform/JSONValues.h"
#include "platform/MIMETypeRegistry.h"
#include "platform/PlatformResourceLoader.h"
#include "platform/UserGestureIndicator.h"
#include "platform/weborigin/SecurityOrigin.h"
#include "wtf/CurrentTime.h"
#include "wtf/ListHashSet.h"
#include "wtf/Vector.h"
#include "wtf/text/Base64.h"
#include "wtf/text/TextEncoding.h"
namespace blink {
namespace PageAgentState {
static const char pageAgentEnabled[] = "pageAgentEnabled";
static const char pageAgentScriptsToEvaluateOnLoad[] = "pageAgentScriptsToEvaluateOnLoad";
static const char screencastEnabled[] = "screencastEnabled";
static const char autoAttachToCreatedPages[] = "autoAttachToCreatedPages";
}
namespace {
KURL urlWithoutFragment(const KURL& url)
{
KURL result = url;
result.removeFragmentIdentifier();
return result;
}
String frameId(LocalFrame* frame)
{
return frame ? IdentifiersFactory::frameId(frame) : "";
}
protocol::TypeBuilder::Page::DialogType::Enum dialogTypeToProtocol(ChromeClient::DialogType dialogType)
{
switch (dialogType) {
case ChromeClient::AlertDialog:
return protocol::TypeBuilder::Page::DialogType::Alert;
case ChromeClient::ConfirmDialog:
return protocol::TypeBuilder::Page::DialogType::Confirm;
case ChromeClient::PromptDialog:
return protocol::TypeBuilder::Page::DialogType::Prompt;
case ChromeClient::HTMLDialog:
return protocol::TypeBuilder::Page::DialogType::Beforeunload;
}
return protocol::TypeBuilder::Page::DialogType::Alert;
}
} // namespace
static bool decodeBuffer(const char* buffer, unsigned size, const String& textEncodingName, String* result)
{
if (buffer) {
WTF::TextEncoding encoding(textEncodingName);
if (!encoding.isValid())
encoding = WindowsLatin1Encoding();
*result = encoding.decode(buffer, size);
return true;
}
return false;
}
static bool prepareResourceBuffer(Resource* cachedResource, bool* hasZeroSize)
{
*hasZeroSize = false;
if (!cachedResource)
return false;
if (cachedResource->dataBufferingPolicy() == DoNotBufferData)
return false;
// Zero-sized resources don't have data at all -- so fake the empty buffer, instead of indicating error by returning 0.
if (!cachedResource->encodedSize()) {
*hasZeroSize = true;
return true;
}
if (cachedResource->isPurgeable()) {
// If the resource is purgeable then make it unpurgeable to get
// get its data. This might fail, in which case we return an
// empty String.
// FIXME: should we do something else in the case of a purged
// resource that informs the user why there is no data in the
// inspector?
if (!cachedResource->lock())
return false;
}
return true;
}
static bool hasTextContent(Resource* cachedResource)
{
Resource::Type type = cachedResource->type();
return type == Resource::CSSStyleSheet || type == Resource::XSLStyleSheet || type == Resource::Script || type == Resource::Raw || type == Resource::ImportResource || type == Resource::MainResource;
}
PassOwnPtr<TextResourceDecoder> InspectorPageAgent::createResourceTextDecoder(const String& mimeType, const String& textEncodingName)
{
if (!textEncodingName.isEmpty())
return TextResourceDecoder::create("text/plain", textEncodingName);
if (DOMImplementation::isXMLMIMEType(mimeType)) {
OwnPtr<TextResourceDecoder> decoder = TextResourceDecoder::create("application/xml");
decoder->useLenientXMLDecoding();
return decoder.release();
}
if (equalIgnoringCase(mimeType, "text/html"))
return TextResourceDecoder::create("text/html", "UTF-8");
if (MIMETypeRegistry::isSupportedJavaScriptMIMEType(mimeType) || DOMImplementation::isJSONMIMEType(mimeType))
return TextResourceDecoder::create("text/plain", "UTF-8");
if (DOMImplementation::isTextMIMEType(mimeType))
return TextResourceDecoder::create("text/plain", "ISO-8859-1");
return PassOwnPtr<TextResourceDecoder>();
}
static void resourceContent(ErrorString* errorString, LocalFrame* frame, const KURL& url, String* result, bool* base64Encoded)
{
if (!InspectorPageAgent::cachedResourceContent(InspectorPageAgent::cachedResource(frame, url), result, base64Encoded))
*errorString = "No resource with given URL found";
}
static bool encodeCachedResourceContent(Resource* cachedResource, bool hasZeroSize, String* result, bool* base64Encoded)
{
*base64Encoded = true;
RefPtr<SharedBuffer> buffer = hasZeroSize ? SharedBuffer::create() : cachedResource->resourceBuffer();
if (!buffer)
return false;
*result = base64Encode(buffer->data(), buffer->size());
return true;
}
bool InspectorPageAgent::cachedResourceContent(Resource* cachedResource, String* result, bool* base64Encoded)
{
bool hasZeroSize;
bool prepared = prepareResourceBuffer(cachedResource, &hasZeroSize);
if (!prepared)
return false;
if (!hasTextContent(cachedResource))
return encodeCachedResourceContent(cachedResource, hasZeroSize, result, base64Encoded);
*base64Encoded = false;
if (hasZeroSize) {
*result = "";
return true;
}
if (cachedResource) {
switch (cachedResource->type()) {
case Resource::CSSStyleSheet:
*result = toCSSStyleSheetResource(cachedResource)->sheetText();
return true;
case Resource::Script:
*result = cachedResource->resourceBuffer() ? toScriptResource(cachedResource)->decodedText() : toScriptResource(cachedResource)->script().toString();
return true;
case Resource::ImportResource: // Fall through.
case Resource::Raw: {
SharedBuffer* buffer = cachedResource->resourceBuffer();
if (!buffer)
return false;
OwnPtr<TextResourceDecoder> decoder = InspectorPageAgent::createResourceTextDecoder(cachedResource->response().mimeType(), cachedResource->response().textEncodingName());
if (!decoder)
return encodeCachedResourceContent(cachedResource, hasZeroSize, result, base64Encoded);
String content = decoder->decode(buffer->data(), buffer->size());
*result = content + decoder->flush();
return true;
}
default:
SharedBuffer* buffer = cachedResource->resourceBuffer();
return decodeBuffer(buffer ? buffer->data() : nullptr, buffer ? buffer->size() : 0, cachedResource->response().textEncodingName(), result);
}
}
return false;
}
// static
bool InspectorPageAgent::sharedBufferContent(PassRefPtr<SharedBuffer> buffer, const String& textEncodingName, bool withBase64Encode, String* result)
{
return dataContent(buffer ? buffer->data() : nullptr, buffer ? buffer->size() : 0, textEncodingName, withBase64Encode, result);
}
bool InspectorPageAgent::dataContent(const char* data, unsigned size, const String& textEncodingName, bool withBase64Encode, String* result)
{
if (withBase64Encode) {
*result = base64Encode(data, size);
return true;
}
return decodeBuffer(data, size, textEncodingName, result);
}
PassOwnPtrWillBeRawPtr<InspectorPageAgent> InspectorPageAgent::create(InspectedFrames* inspectedFrames, Client* client, InspectorResourceContentLoader* resourceContentLoader, InspectorDebuggerAgent* debuggerAgent)
{
return adoptPtrWillBeNoop(new InspectorPageAgent(inspectedFrames, client, resourceContentLoader, debuggerAgent));
}
Resource* InspectorPageAgent::cachedResource(LocalFrame* frame, const KURL& url)
{
Document* document = frame->document();
if (!document)
return nullptr;
Resource* cachedResource = document->fetcher()->cachedResource(url);
if (!cachedResource) {
WillBeHeapVector<RawPtrWillBeMember<Document>> allImports = InspectorPageAgent::importsForFrame(frame);
for (Document* import : allImports) {
cachedResource = import->fetcher()->cachedResource(url);
if (cachedResource)
break;
}
}
if (!cachedResource)
cachedResource = memoryCache()->resourceForURL(url, document->fetcher()->getCacheIdentifier());
return cachedResource;
}
protocol::TypeBuilder::Page::ResourceType::Enum InspectorPageAgent::resourceTypeJson(InspectorPageAgent::ResourceType resourceType)
{
switch (resourceType) {
case DocumentResource:
return protocol::TypeBuilder::Page::ResourceType::Document;
case FontResource:
return protocol::TypeBuilder::Page::ResourceType::Font;
case ImageResource:
return protocol::TypeBuilder::Page::ResourceType::Image;
case MediaResource:
return protocol::TypeBuilder::Page::ResourceType::Media;
case ScriptResource:
return protocol::TypeBuilder::Page::ResourceType::Script;
case StylesheetResource:
return protocol::TypeBuilder::Page::ResourceType::Stylesheet;
case TextTrackResource:
return protocol::TypeBuilder::Page::ResourceType::TextTrack;
case XHRResource:
return protocol::TypeBuilder::Page::ResourceType::XHR;
case FetchResource:
return protocol::TypeBuilder::Page::ResourceType::Fetch;
case EventSourceResource:
return protocol::TypeBuilder::Page::ResourceType::EventSource;
case WebSocketResource:
return protocol::TypeBuilder::Page::ResourceType::WebSocket;
case ManifestResource:
return protocol::TypeBuilder::Page::ResourceType::Manifest;
case OtherResource:
return protocol::TypeBuilder::Page::ResourceType::Other;
}
return protocol::TypeBuilder::Page::ResourceType::Other;
}
InspectorPageAgent::ResourceType InspectorPageAgent::cachedResourceType(const Resource& cachedResource)
{
switch (cachedResource.type()) {
case Resource::Image:
return InspectorPageAgent::ImageResource;
case Resource::Font:
return InspectorPageAgent::FontResource;
case Resource::Media:
return InspectorPageAgent::MediaResource;
case Resource::Manifest:
return InspectorPageAgent::ManifestResource;
case Resource::TextTrack:
return InspectorPageAgent::TextTrackResource;
case Resource::CSSStyleSheet:
// Fall through.
case Resource::XSLStyleSheet:
return InspectorPageAgent::StylesheetResource;
case Resource::Script:
return InspectorPageAgent::ScriptResource;
case Resource::ImportResource:
// Fall through.
case Resource::MainResource:
return InspectorPageAgent::DocumentResource;
default:
break;
}
return InspectorPageAgent::OtherResource;
}
protocol::TypeBuilder::Page::ResourceType::Enum InspectorPageAgent::cachedResourceTypeJson(const Resource& cachedResource)
{
return resourceTypeJson(cachedResourceType(cachedResource));
}
InspectorPageAgent::InspectorPageAgent(InspectedFrames* inspectedFrames, Client* client, InspectorResourceContentLoader* resourceContentLoader, InspectorDebuggerAgent* debuggerAgent)
: InspectorBaseAgent<InspectorPageAgent, protocol::Frontend::Page>("Page")
, m_inspectedFrames(inspectedFrames)
, m_debuggerAgent(debuggerAgent)
, m_client(client)
, m_lastScriptIdentifier(0)
, m_enabled(false)
, m_reloading(false)
, m_inspectorResourceContentLoader(resourceContentLoader)
{
}
void InspectorPageAgent::restore()
{
if (m_state->booleanProperty(PageAgentState::pageAgentEnabled, false)) {
ErrorString error;
enable(&error);
}
}
void InspectorPageAgent::enable(ErrorString*)
{
m_enabled = true;
m_state->setBoolean(PageAgentState::pageAgentEnabled, true);
m_instrumentingAgents->setInspectorPageAgent(this);
}
void InspectorPageAgent::disable(ErrorString*)
{
m_enabled = false;
m_state->setBoolean(PageAgentState::pageAgentEnabled, false);
m_state->remove(PageAgentState::pageAgentScriptsToEvaluateOnLoad);
m_scriptToEvaluateOnLoadOnce = String();
m_pendingScriptToEvaluateOnLoadOnce = String();
m_instrumentingAgents->setInspectorPageAgent(0);
stopScreencast(0);
finishReload();
}
void InspectorPageAgent::addScriptToEvaluateOnLoad(ErrorString*, const String& source, String* identifier)
{
RefPtr<JSONObject> scripts = m_state->getObject(PageAgentState::pageAgentScriptsToEvaluateOnLoad);
if (!scripts) {
scripts = JSONObject::create();
m_state->setObject(PageAgentState::pageAgentScriptsToEvaluateOnLoad, scripts);
}
// Assure we don't override existing ids -- m_lastScriptIdentifier could get out of sync WRT actual
// scripts once we restored the scripts from the cookie during navigation.
do {
*identifier = String::number(++m_lastScriptIdentifier);
} while (scripts->find(*identifier) != scripts->end());
scripts->setString(*identifier, source);
}
void InspectorPageAgent::removeScriptToEvaluateOnLoad(ErrorString* error, const String& identifier)
{
RefPtr<JSONObject> scripts = m_state->getObject(PageAgentState::pageAgentScriptsToEvaluateOnLoad);
if (!scripts || scripts->find(identifier) == scripts->end()) {
*error = "Script not found";
return;
}
scripts->remove(identifier);
}
void InspectorPageAgent::setAutoAttachToCreatedPages(ErrorString*, bool autoAttach)
{
m_state->setBoolean(PageAgentState::autoAttachToCreatedPages, autoAttach);
}
void InspectorPageAgent::reload(ErrorString*, const bool* const optionalIgnoreCache, const String* optionalScriptToEvaluateOnLoad)
{
m_pendingScriptToEvaluateOnLoadOnce = optionalScriptToEvaluateOnLoad ? *optionalScriptToEvaluateOnLoad : "";
ErrorString unused;
m_debuggerAgent->setSkipAllPauses(&unused, true);
m_reloading = true;
m_inspectedFrames->root()->reload(asBool(optionalIgnoreCache) ? FrameLoadTypeReloadFromOrigin : FrameLoadTypeReload, NotClientRedirect);
}
void InspectorPageAgent::navigate(ErrorString*, const String& url, String* outFrameId)
{
*outFrameId = frameId(m_inspectedFrames->root());
}
static void cachedResourcesForDocument(Document* document, WillBeHeapVector<RawPtrWillBeMember<Resource>>& result, bool skipXHRs)
{
const ResourceFetcher::DocumentResourceMap& allResources = document->fetcher()->allResources();
for (const auto& resource : allResources) {
Resource* cachedResource = resource.value.get();
if (!cachedResource)
continue;
switch (cachedResource->type()) {
case Resource::Image:
// Skip images that were not auto loaded (images disabled in the user agent).
if (toImageResource(cachedResource)->stillNeedsLoad())
continue;
break;
case Resource::Font:
// Skip fonts that were referenced in CSS but never used/downloaded.
if (toFontResource(cachedResource)->stillNeedsLoad())
continue;
break;
case Resource::Raw:
if (skipXHRs)
continue;
break;
default:
// All other Resource types download immediately.
break;
}
result.append(cachedResource);
}
}
// static
WillBeHeapVector<RawPtrWillBeMember<Document>> InspectorPageAgent::importsForFrame(LocalFrame* frame)
{
WillBeHeapVector<RawPtrWillBeMember<Document>> result;
Document* rootDocument = frame->document();
if (HTMLImportsController* controller = rootDocument->importsController()) {
for (size_t i = 0; i < controller->loaderCount(); ++i) {
if (Document* document = controller->loaderAt(i)->document())
result.append(document);
}
}
return result;
}
static WillBeHeapVector<RawPtrWillBeMember<Resource>> cachedResourcesForFrame(LocalFrame* frame, bool skipXHRs)
{
WillBeHeapVector<RawPtrWillBeMember<Resource>> result;
Document* rootDocument = frame->document();
WillBeHeapVector<RawPtrWillBeMember<Document>> loaders = InspectorPageAgent::importsForFrame(frame);
cachedResourcesForDocument(rootDocument, result, skipXHRs);
for (size_t i = 0; i < loaders.size(); ++i)
cachedResourcesForDocument(loaders[i], result, skipXHRs);
return result;
}
void InspectorPageAgent::getResourceTree(ErrorString*, RefPtr<protocol::TypeBuilder::Page::FrameResourceTree>& object)
{
object = buildObjectForFrameTree(m_inspectedFrames->root());
}
void InspectorPageAgent::finishReload()
{
if (!m_reloading)
return;
m_reloading = false;
ErrorString unused;
m_debuggerAgent->setSkipAllPauses(&unused, false);
}
void InspectorPageAgent::getResourceContentAfterResourcesContentLoaded(const String& frameId, const String& url, PassRefPtr<GetResourceContentCallback> callback)
{
if (!callback->isActive())
return;
LocalFrame* frame = IdentifiersFactory::frameById(m_inspectedFrames, frameId);
if (!frame) {
callback->sendFailure("No frame for given id found");
return;
}
ErrorString errorString;
String content;
bool base64Encoded;
resourceContent(&errorString, frame, KURL(ParsedURLString, url), &content, &base64Encoded);
if (!errorString.isEmpty()) {
callback->sendFailure(errorString);
return;
}
callback->sendSuccess(content, base64Encoded);
}
void InspectorPageAgent::getResourceContent(ErrorString* errorString, const String& frameId, const String& url, PassRefPtr<GetResourceContentCallback> callback)
{
if (!m_enabled) {
callback->sendFailure("Agent is not enabled.");
return;
}
m_inspectorResourceContentLoader->ensureResourcesContentLoaded(bind(&InspectorPageAgent::getResourceContentAfterResourcesContentLoaded, this, frameId, url, callback));
}
void InspectorPageAgent::searchContentAfterResourcesContentLoaded(const String& frameId, const String& url, const String& query, bool caseSensitive, bool isRegex, PassRefPtr<SearchInResourceCallback> callback)
{
if (!callback->isActive())
return;
LocalFrame* frame = IdentifiersFactory::frameById(m_inspectedFrames, frameId);
if (!frame) {
callback->sendFailure("No frame for given id found");
return;
}
ErrorString errorString;
String content;
bool base64Encoded;
resourceContent(&errorString, frame, KURL(ParsedURLString, url), &content, &base64Encoded);
if (!errorString.isEmpty()) {
callback->sendFailure(errorString);
return;
}
RefPtr<protocol::TypeBuilder::Array<protocol::TypeBuilder::Debugger::SearchMatch>> results;
results = V8ContentSearchUtil::searchInTextByLines(m_debuggerAgent->debugger(), content, query, caseSensitive, isRegex);
callback->sendSuccess(results);
}
void InspectorPageAgent::searchInResource(ErrorString*, const String& frameId, const String& url, const String& query, const bool* optionalCaseSensitive, const bool* optionalIsRegex, PassRefPtr<SearchInResourceCallback> callback)
{
if (!m_enabled) {
callback->sendFailure("Agent is not enabled.");
return;
}
m_inspectorResourceContentLoader->ensureResourcesContentLoaded(bind(&InspectorPageAgent::searchContentAfterResourcesContentLoaded, this, frameId, url, query, asBool(optionalCaseSensitive), asBool(optionalIsRegex), callback));
}
void InspectorPageAgent::setDocumentContent(ErrorString* errorString, const String& frameId, const String& html)
{
LocalFrame* frame = IdentifiersFactory::frameById(m_inspectedFrames, frameId);
if (!frame) {
*errorString = "No frame for given id found";
return;
}
Document* document = frame->document();
if (!document) {
*errorString = "No Document instance to set HTML for";
return;
}
DOMPatchSupport::patchDocument(*document, html);
}
void InspectorPageAgent::didClearDocumentOfWindowObject(LocalFrame* frame)
{
if (!frontend())
return;
RefPtr<JSONObject> scripts = m_state->getObject(PageAgentState::pageAgentScriptsToEvaluateOnLoad);
if (scripts) {
for (const auto& script : *scripts) {
String scriptText;
if (script.value->asString(&scriptText))
frame->script().executeScriptInMainWorld(scriptText);
}
}
if (!m_scriptToEvaluateOnLoadOnce.isEmpty())
frame->script().executeScriptInMainWorld(m_scriptToEvaluateOnLoadOnce);
}
void InspectorPageAgent::domContentLoadedEventFired(LocalFrame* frame)
{
if (frame != m_inspectedFrames->root())
return;
frontend()->domContentEventFired(monotonicallyIncreasingTime());
}
void InspectorPageAgent::loadEventFired(LocalFrame* frame)
{
if (frame != m_inspectedFrames->root())
return;
frontend()->loadEventFired(monotonicallyIncreasingTime());
}
void InspectorPageAgent::didCommitLoad(LocalFrame*, DocumentLoader* loader)
{
if (loader->frame() == m_inspectedFrames->root()) {
finishReload();
m_scriptToEvaluateOnLoadOnce = m_pendingScriptToEvaluateOnLoadOnce;
m_pendingScriptToEvaluateOnLoadOnce = String();
}
frontend()->frameNavigated(buildObjectForFrame(loader->frame()));
}
void InspectorPageAgent::frameAttachedToParent(LocalFrame* frame)
{
Frame* parentFrame = frame->tree().parent();
if (!parentFrame->isLocalFrame())
parentFrame = 0;
frontend()->frameAttached(frameId(frame), frameId(toLocalFrame(parentFrame)));
}
void InspectorPageAgent::frameDetachedFromParent(LocalFrame* frame)
{
frontend()->frameDetached(frameId(frame));
}
bool InspectorPageAgent::screencastEnabled()
{
return m_enabled && m_state->booleanProperty(PageAgentState::screencastEnabled, false);
}
void InspectorPageAgent::frameStartedLoading(LocalFrame* frame)
{
frontend()->frameStartedLoading(frameId(frame));
}
void InspectorPageAgent::frameStoppedLoading(LocalFrame* frame)
{
frontend()->frameStoppedLoading(frameId(frame));
}
void InspectorPageAgent::frameScheduledNavigation(LocalFrame* frame, double delay)
{
frontend()->frameScheduledNavigation(frameId(frame), delay);
}
void InspectorPageAgent::frameClearedScheduledNavigation(LocalFrame* frame)
{
frontend()->frameClearedScheduledNavigation(frameId(frame));
}
void InspectorPageAgent::willRunJavaScriptDialog(const String& message, ChromeClient::DialogType dialogType)
{
frontend()->javascriptDialogOpening(message, dialogTypeToProtocol(dialogType));
}
void InspectorPageAgent::didRunJavaScriptDialog(bool result)
{
frontend()->javascriptDialogClosed(result);
}
void InspectorPageAgent::didUpdateLayout()
{
if (m_enabled && m_client)
m_client->pageLayoutInvalidated();
}
void InspectorPageAgent::didResizeMainFrame()
{
if (!m_inspectedFrames->root()->isMainFrame())
return;
#if !OS(ANDROID)
if (m_enabled && m_client)
m_client->pageLayoutInvalidated();
#endif
frontend()->frameResized();
}
void InspectorPageAgent::didRecalculateStyle(int)
{
if (m_enabled && m_client)
m_client->pageLayoutInvalidated();
}
void InspectorPageAgent::windowCreated(LocalFrame* created)
{
if (m_enabled && m_state->booleanProperty(PageAgentState::autoAttachToCreatedPages, false))
m_client->waitForCreateWindow(created);
}
PassRefPtr<protocol::TypeBuilder::Page::Frame> InspectorPageAgent::buildObjectForFrame(LocalFrame* frame)
{
RefPtr<protocol::TypeBuilder::Page::Frame> frameObject = protocol::TypeBuilder::Page::Frame::create()
.setId(frameId(frame))
.setLoaderId(IdentifiersFactory::loaderId(frame->loader().documentLoader()))
.setUrl(urlWithoutFragment(frame->document()->url()).string())
.setMimeType(frame->loader().documentLoader()->responseMIMEType())
.setSecurityOrigin(frame->document()->securityOrigin()->toRawString());
// FIXME: This doesn't work for OOPI.
Frame* parentFrame = frame->tree().parent();
if (parentFrame && parentFrame->isLocalFrame())
frameObject->setParentId(frameId(toLocalFrame(parentFrame)));
if (frame->deprecatedLocalOwner()) {
AtomicString name = frame->deprecatedLocalOwner()->getNameAttribute();
if (name.isEmpty())
name = frame->deprecatedLocalOwner()->getAttribute(HTMLNames::idAttr);
frameObject->setName(name);
}
return frameObject;
}
PassRefPtr<protocol::TypeBuilder::Page::FrameResourceTree> InspectorPageAgent::buildObjectForFrameTree(LocalFrame* frame)
{
RefPtr<protocol::TypeBuilder::Page::Frame> frameObject = buildObjectForFrame(frame);
RefPtr<protocol::TypeBuilder::Array<protocol::TypeBuilder::Page::FrameResourceTree::Resources>> subresources = protocol::TypeBuilder::Array<protocol::TypeBuilder::Page::FrameResourceTree::Resources>::create();
RefPtr<protocol::TypeBuilder::Page::FrameResourceTree> result = protocol::TypeBuilder::Page::FrameResourceTree::create()
.setFrame(frameObject)
.setResources(subresources);
WillBeHeapVector<RawPtrWillBeMember<Resource>> allResources = cachedResourcesForFrame(frame, true);
for (Resource* cachedResource : allResources) {
RefPtr<protocol::TypeBuilder::Page::FrameResourceTree::Resources> resourceObject = protocol::TypeBuilder::Page::FrameResourceTree::Resources::create()
.setUrl(urlWithoutFragment(cachedResource->url()).string())
.setType(cachedResourceTypeJson(*cachedResource))
.setMimeType(cachedResource->response().mimeType());
if (cachedResource->wasCanceled())
resourceObject->setCanceled(true);
else if (cachedResource->status() == Resource::LoadError)
resourceObject->setFailed(true);
subresources->addItem(resourceObject);
}
WillBeHeapVector<RawPtrWillBeMember<Document>> allImports = InspectorPageAgent::importsForFrame(frame);
for (Document* import : allImports) {
RefPtr<protocol::TypeBuilder::Page::FrameResourceTree::Resources> resourceObject = protocol::TypeBuilder::Page::FrameResourceTree::Resources::create()
.setUrl(urlWithoutFragment(import->url()).string())
.setType(resourceTypeJson(InspectorPageAgent::DocumentResource))
.setMimeType(import->suggestedMIMEType());
subresources->addItem(resourceObject);
}
RefPtr<protocol::TypeBuilder::Array<protocol::TypeBuilder::Page::FrameResourceTree>> childrenArray;
for (Frame* child = frame->tree().firstChild(); child; child = child->tree().nextSibling()) {
if (!child->isLocalFrame())
continue;
if (!childrenArray) {
childrenArray = protocol::TypeBuilder::Array<protocol::TypeBuilder::Page::FrameResourceTree>::create();
result->setChildFrames(childrenArray);
}
childrenArray->addItem(buildObjectForFrameTree(toLocalFrame(child)));
}
return result;
}
void InspectorPageAgent::startScreencast(ErrorString*, const String* format, const int* quality, const int* maxWidth, const int* maxHeight, const int* everyNthFrame)
{
m_state->setBoolean(PageAgentState::screencastEnabled, true);
}
void InspectorPageAgent::stopScreencast(ErrorString*)
{
m_state->setBoolean(PageAgentState::screencastEnabled, false);
}
void InspectorPageAgent::setOverlayMessage(ErrorString*, const String* message)
{
if (m_client)
m_client->setPausedInDebuggerMessage(message);
}
DEFINE_TRACE(InspectorPageAgent)
{
visitor->trace(m_inspectedFrames);
visitor->trace(m_debuggerAgent);
visitor->trace(m_inspectorResourceContentLoader);
InspectorBaseAgent::trace(visitor);
}
} // namespace blink