blob: eb3a7dc6e39b64af6dde48a2d4e08a11001c43f9 [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 "config.h"
#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/UserAgentStyleSheets.h"
#include "core/css/StyleSheetContents.h"
#include "core/css/resolver/StyleResolver.h"
#include "core/css/resolver/ViewportStyleResolver.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/FrameView.h"
#include "core/frame/LocalFrame.h"
#include "core/frame/Settings.h"
#include "core/html/HTMLFrameOwnerElement.h"
#include "core/html/VoidCallback.h"
#include "core/html/imports/HTMLImport.h"
#include "core/html/imports/HTMLImportLoader.h"
#include "core/html/imports/HTMLImportsController.h"
#include "core/html/parser/TextResourceDecoder.h"
#include "core/inspector/ContentSearchUtils.h"
#include "core/inspector/DOMPatchSupport.h"
#include "core/inspector/IdentifiersFactory.h"
#include "core/inspector/InjectedScriptManager.h"
#include "core/inspector/InspectorClient.h"
#include "core/inspector/InspectorInstrumentation.h"
#include "core/inspector/InspectorOverlay.h"
#include "core/inspector/InspectorResourceContentLoader.h"
#include "core/inspector/InspectorState.h"
#include "core/inspector/InstrumentingAgents.h"
#include "core/loader/CookieJar.h"
#include "core/loader/DocumentLoader.h"
#include "core/loader/FrameLoadRequest.h"
#include "core/loader/FrameLoader.h"
#include "core/page/Page.h"
#include "platform/Cookie.h"
#include "platform/JSONValues.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 pageAgentScriptExecutionDisabled[] = "pageAgentScriptExecutionDisabled";
static const char pageAgentScriptsToEvaluateOnLoad[] = "pageAgentScriptsToEvaluateOnLoad";
static const char deviceMetricsOverrideEnabled[] = "deviceMetricsOverrideEnabled";
static const char pageAgentScreenWidthOverride[] = "pageAgentScreenWidthOverride";
static const char pageAgentScreenHeightOverride[] = "pageAgentScreenHeightOverride";
static const char pageAgentDeviceScaleFactorOverride[] = "pageAgentDeviceScaleFactorOverride";
static const char pageAgentEmulateMobile[] = "pageAgentEmulateMobile";
static const char pageAgentFitWindow[] = "pageAgentFitWindow";
static const char deviceScale[] = "deviceScale";
static const char deviceOffsetX[] = "deviceOffsetX";
static const char deviceOffsetY[] = "deviceOffsetY";
static const char pageAgentShowFPSCounter[] = "pageAgentShowFPSCounter";
static const char pageAgentContinuousPaintingEnabled[] = "pageAgentContinuousPaintingEnabled";
static const char pageAgentShowPaintRects[] = "pageAgentShowPaintRects";
static const char pageAgentShowDebugBorders[] = "pageAgentShowDebugBorders";
static const char pageAgentShowScrollBottleneckRects[] = "pageAgentShowScrollBottleneckRects";
static const char touchEventEmulationEnabled[] = "touchEventEmulationEnabled";
static const char pageAgentEmulatedMedia[] = "pageAgentEmulatedMedia";
static const char showSizeOnResize[] = "showSizeOnResize";
static const char showGridOnResize[] = "showGridOnResize";
}
namespace {
KURL urlWithoutFragment(const KURL& url)
{
KURL result = url;
result.removeFragmentIdentifier();
return result;
}
static float calculateFontScaleFactor(int width, int height, float deviceScaleFactor)
{
// Chromium on Android uses a device scale adjustment for fonts used in text autosizing for
// improved legibility. This function computes this adjusted value for text autosizing.
// For a description of the Android device scale adjustment algorithm, see:
// chrome/browser/chrome_content_browser_client.cc, GetDeviceScaleAdjustment(...)
if (!width || !height || !deviceScaleFactor)
return 1;
static const float kMinFSM = 1.05f;
static const int kWidthForMinFSM = 320;
static const float kMaxFSM = 1.3f;
static const int kWidthForMaxFSM = 800;
float minWidth = std::min(width, height) / deviceScaleFactor;
if (minWidth <= kWidthForMinFSM)
return kMinFSM;
if (minWidth >= kWidthForMaxFSM)
return kMaxFSM;
// The font scale multiplier varies linearly between kMinFSM and kMaxFSM.
float ratio = static_cast<float>(minWidth - kWidthForMinFSM) / (kWidthForMaxFSM - kWidthForMinFSM);
return ratio * (kMaxFSM - kMinFSM) + kMinFSM;
}
}
class InspectorPageAgent::GetResourceContentLoadListener FINAL : public VoidCallback {
public:
GetResourceContentLoadListener(InspectorPageAgent*, const String& frameId, const String& url, PassRefPtr<GetResourceContentCallback>);
virtual void handleEvent() OVERRIDE;
private:
InspectorPageAgent* m_pageAgent;
String m_frameId;
String m_url;
RefPtr<GetResourceContentCallback> m_callback;
};
InspectorPageAgent::GetResourceContentLoadListener::GetResourceContentLoadListener(InspectorPageAgent* pageAgent, const String& frameId, const String& url, PassRefPtr<GetResourceContentCallback> callback)
: m_pageAgent(pageAgent)
, m_frameId(frameId)
, m_url(url)
, m_callback(callback)
{
}
void InspectorPageAgent::GetResourceContentLoadListener::handleEvent()
{
if (!m_callback->isActive())
return;
m_pageAgent->getResourceContentAfterResourcesContentLoaded(m_frameId, m_url, m_callback);
}
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)
{
InspectorPageAgent::ResourceType type = InspectorPageAgent::cachedResourceType(*cachedResource);
return type == InspectorPageAgent::DocumentResource || type == InspectorPageAgent::StylesheetResource || type == InspectorPageAgent::ScriptResource || type == InspectorPageAgent::XHRResource;
}
static PassOwnPtr<TextResourceDecoder> createXHRTextDecoder(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");
return TextResourceDecoder::create("text/plain", "UTF-8");
}
static void resourceContent(ErrorString* errorString, LocalFrame* frame, const KURL& url, String* result, bool* base64Encoded)
{
DocumentLoader* loader = InspectorPageAgent::assertDocumentLoader(errorString, frame);
if (!loader)
return;
if (!InspectorPageAgent::cachedResourceContent(InspectorPageAgent::cachedResource(frame, url), result, base64Encoded))
*errorString = "No resource with given URL found";
}
bool InspectorPageAgent::cachedResourceContent(Resource* cachedResource, String* result, bool* base64Encoded)
{
bool hasZeroSize;
bool prepared = prepareResourceBuffer(cachedResource, &hasZeroSize);
if (!prepared)
return false;
*base64Encoded = !hasTextContent(cachedResource);
if (*base64Encoded) {
RefPtr<SharedBuffer> buffer = hasZeroSize ? SharedBuffer::create() : cachedResource->resourceBuffer();
if (!buffer)
return false;
*result = base64Encode(buffer->data(), buffer->size());
return true;
}
if (hasZeroSize) {
*result = "";
return true;
}
if (cachedResource) {
switch (cachedResource->type()) {
case Resource::CSSStyleSheet:
*result = toCSSStyleSheetResource(cachedResource)->sheetText(false);
return true;
case Resource::Script:
*result = toScriptResource(cachedResource)->script();
return true;
case Resource::Raw: {
SharedBuffer* buffer = cachedResource->resourceBuffer();
if (!buffer)
return false;
OwnPtr<TextResourceDecoder> decoder = createXHRTextDecoder(cachedResource->response().mimeType(), cachedResource->response().textEncodingName());
String content = decoder->decode(buffer->data(), buffer->size());
*result = content + decoder->flush();
return true;
}
default:
SharedBuffer* buffer = cachedResource->resourceBuffer();
return decodeBuffer(buffer ? buffer->data() : 0, 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() : 0, 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(Page* page, InjectedScriptManager* injectedScriptManager, InspectorClient* client, InspectorOverlay* overlay)
{
return adoptPtrWillBeNoop(new InspectorPageAgent(page, injectedScriptManager, client, overlay));
}
Resource* InspectorPageAgent::cachedResource(LocalFrame* frame, const KURL& url)
{
Document* document = frame->document();
if (!document)
return 0;
Resource* cachedResource = document->fetcher()->cachedResource(url);
if (!cachedResource) {
Vector<Document*> allImports = InspectorPageAgent::importsForFrame(frame);
for (Vector<Document*>::const_iterator it = allImports.begin(); it != allImports.end(); ++it) {
Document* import = *it;
cachedResource = import->fetcher()->cachedResource(url);
if (cachedResource)
break;
}
}
if (!cachedResource)
cachedResource = memoryCache()->resourceForURL(url);
return cachedResource;
}
TypeBuilder::Page::ResourceType::Enum InspectorPageAgent::resourceTypeJson(InspectorPageAgent::ResourceType resourceType)
{
switch (resourceType) {
case DocumentResource:
return TypeBuilder::Page::ResourceType::Document;
case FontResource:
return TypeBuilder::Page::ResourceType::Font;
case ImageResource:
return TypeBuilder::Page::ResourceType::Image;
case MediaResource:
return TypeBuilder::Page::ResourceType::Media;
case ScriptResource:
return TypeBuilder::Page::ResourceType::Script;
case StylesheetResource:
return TypeBuilder::Page::ResourceType::Stylesheet;
case TextTrackResource:
return TypeBuilder::Page::ResourceType::TextTrack;
case XHRResource:
return TypeBuilder::Page::ResourceType::XHR;
case WebSocketResource:
return TypeBuilder::Page::ResourceType::WebSocket;
case OtherResource:
return TypeBuilder::Page::ResourceType::Other;
}
return 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::TextTrack:
return InspectorPageAgent::TextTrackResource;
case Resource::CSSStyleSheet:
// Fall through.
case Resource::XSLStyleSheet:
return InspectorPageAgent::StylesheetResource;
case Resource::Script:
return InspectorPageAgent::ScriptResource;
case Resource::Raw:
return InspectorPageAgent::XHRResource;
case Resource::ImportResource:
// Fall through.
case Resource::MainResource:
return InspectorPageAgent::DocumentResource;
default:
break;
}
return InspectorPageAgent::OtherResource;
}
TypeBuilder::Page::ResourceType::Enum InspectorPageAgent::cachedResourceTypeJson(const Resource& cachedResource)
{
return resourceTypeJson(cachedResourceType(cachedResource));
}
InspectorPageAgent::InspectorPageAgent(Page* page, InjectedScriptManager* injectedScriptManager, InspectorClient* client, InspectorOverlay* overlay)
: InspectorBaseAgent<InspectorPageAgent>("Page")
, m_page(page)
, m_injectedScriptManager(injectedScriptManager)
, m_client(client)
, m_frontend(0)
, m_overlay(overlay)
, m_lastScriptIdentifier(0)
, m_enabled(false)
, m_ignoreScriptsEnabledNotification(false)
, m_deviceMetricsOverridden(false)
, m_emulateMobileEnabled(false)
, m_touchEmulationEnabled(false)
, m_originalTouchEnabled(false)
, m_originalDeviceSupportsMouse(false)
, m_originalDeviceSupportsTouch(false)
, m_embedderTextAutosizingEnabled(m_page->settings().textAutosizingEnabled())
, m_embedderFontScaleFactor(m_page->settings().deviceScaleAdjustment())
{
}
void InspectorPageAgent::setTextAutosizingEnabled(bool enabled)
{
m_embedderTextAutosizingEnabled = enabled;
bool emulateMobileEnabled = m_enabled && m_deviceMetricsOverridden && m_emulateMobileEnabled;
if (!emulateMobileEnabled)
m_page->settings().setTextAutosizingEnabled(enabled);
}
void InspectorPageAgent::setDeviceScaleAdjustment(float deviceScaleAdjustment)
{
m_embedderFontScaleFactor = deviceScaleAdjustment;
bool emulateMobileEnabled = m_enabled && m_deviceMetricsOverridden && m_emulateMobileEnabled;
if (!emulateMobileEnabled)
m_page->settings().setDeviceScaleAdjustment(deviceScaleAdjustment);
}
void InspectorPageAgent::setFrontend(InspectorFrontend* frontend)
{
m_frontend = frontend->page();
}
void InspectorPageAgent::clearFrontend()
{
ErrorString error;
disable(&error);
m_frontend = 0;
}
void InspectorPageAgent::restore()
{
if (m_state->getBoolean(PageAgentState::pageAgentEnabled)) {
ErrorString error;
enable(&error);
bool scriptExecutionDisabled = m_state->getBoolean(PageAgentState::pageAgentScriptExecutionDisabled);
setScriptExecutionDisabled(0, scriptExecutionDisabled);
bool showPaintRects = m_state->getBoolean(PageAgentState::pageAgentShowPaintRects);
setShowPaintRects(0, showPaintRects);
bool showDebugBorders = m_state->getBoolean(PageAgentState::pageAgentShowDebugBorders);
setShowDebugBorders(0, showDebugBorders);
bool showFPSCounter = m_state->getBoolean(PageAgentState::pageAgentShowFPSCounter);
setShowFPSCounter(0, showFPSCounter);
String emulatedMedia = m_state->getString(PageAgentState::pageAgentEmulatedMedia);
setEmulatedMedia(0, emulatedMedia);
bool continuousPaintingEnabled = m_state->getBoolean(PageAgentState::pageAgentContinuousPaintingEnabled);
setContinuousPaintingEnabled(0, continuousPaintingEnabled);
bool showScrollBottleneckRects = m_state->getBoolean(PageAgentState::pageAgentShowScrollBottleneckRects);
setShowScrollBottleneckRects(0, showScrollBottleneckRects);
updateViewMetricsFromState();
updateTouchEventEmulationInPage(m_state->getBoolean(PageAgentState::touchEventEmulationEnabled));
}
}
void InspectorPageAgent::enable(ErrorString*)
{
m_enabled = true;
m_state->setBoolean(PageAgentState::pageAgentEnabled, true);
m_instrumentingAgents->setInspectorPageAgent(this);
m_inspectorResourceContentLoader = adoptPtr(new InspectorResourceContentLoader(m_page));
}
void InspectorPageAgent::disable(ErrorString*)
{
m_enabled = false;
m_state->setBoolean(PageAgentState::pageAgentEnabled, false);
m_state->remove(PageAgentState::pageAgentScriptsToEvaluateOnLoad);
m_overlay->hide();
m_instrumentingAgents->setInspectorPageAgent(0);
m_inspectorResourceContentLoader.clear();
m_deviceMetricsOverridden = false;
setShowPaintRects(0, false);
setShowDebugBorders(0, false);
setShowFPSCounter(0, false);
setEmulatedMedia(0, String());
if (m_state->getBoolean(PageAgentState::pageAgentContinuousPaintingEnabled))
setContinuousPaintingEnabled(0, false);
setShowScrollBottleneckRects(0, false);
setShowViewportSizeOnResize(0, false, 0);
if (m_state->getBoolean(PageAgentState::touchEventEmulationEnabled)) {
updateTouchEventEmulationInPage(false);
m_state->setBoolean(PageAgentState::touchEventEmulationEnabled, false);
}
if (!deviceMetricsChanged(false, 0, 0, 0, false, false, 1, 0, 0))
return;
// When disabling the agent, reset the override values if necessary.
updateViewMetrics(false, 0, 0, 0, false, false, 1, 0, 0);
m_state->setLong(PageAgentState::pageAgentScreenWidthOverride, 0);
m_state->setLong(PageAgentState::pageAgentScreenHeightOverride, 0);
m_state->setDouble(PageAgentState::pageAgentDeviceScaleFactorOverride, 0);
m_state->setBoolean(PageAgentState::pageAgentEmulateMobile, false);
m_state->setBoolean(PageAgentState::pageAgentFitWindow, false);
m_state->setDouble(PageAgentState::deviceScale, 1);
m_state->setDouble(PageAgentState::deviceOffsetX, 0);
m_state->setDouble(PageAgentState::deviceOffsetY, 0);
}
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);
// Force cookie serialization.
m_state->setObject(PageAgentState::pageAgentScriptsToEvaluateOnLoad, scripts);
}
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::reload(ErrorString*, const bool* const optionalIgnoreCache, const String* optionalScriptToEvaluateOnLoad, const String* optionalScriptPreprocessor)
{
m_pendingScriptToEvaluateOnLoadOnce = optionalScriptToEvaluateOnLoad ? *optionalScriptToEvaluateOnLoad : "";
m_pendingScriptPreprocessor = optionalScriptPreprocessor ? *optionalScriptPreprocessor : "";
m_page->deprecatedLocalMainFrame()->loader().reload(asBool(optionalIgnoreCache) ? EndToEndReload : NormalReload);
}
void InspectorPageAgent::navigate(ErrorString*, const String& url, String* outFrameId)
{
LocalFrame* frame = m_page->deprecatedLocalMainFrame();
*outFrameId = frameId(frame);
}
static PassRefPtr<TypeBuilder::Page::Cookie> buildObjectForCookie(const Cookie& cookie)
{
return TypeBuilder::Page::Cookie::create()
.setName(cookie.name)
.setValue(cookie.value)
.setDomain(cookie.domain)
.setPath(cookie.path)
.setExpires(cookie.expires)
.setSize((cookie.name.length() + cookie.value.length()))
.setHttpOnly(cookie.httpOnly)
.setSecure(cookie.secure)
.setSession(cookie.session)
.release();
}
static PassRefPtr<TypeBuilder::Array<TypeBuilder::Page::Cookie> > buildArrayForCookies(ListHashSet<Cookie>& cookiesList)
{
RefPtr<TypeBuilder::Array<TypeBuilder::Page::Cookie> > cookies = TypeBuilder::Array<TypeBuilder::Page::Cookie>::create();
ListHashSet<Cookie>::iterator end = cookiesList.end();
ListHashSet<Cookie>::iterator it = cookiesList.begin();
for (int i = 0; it != end; ++it, i++)
cookies->addItem(buildObjectForCookie(*it));
return cookies;
}
static void cachedResourcesForDocument(Document* document, Vector<Resource*>& result, bool skipXHRs)
{
const ResourceFetcher::DocumentResourceMap& allResources = document->fetcher()->allResources();
ResourceFetcher::DocumentResourceMap::const_iterator end = allResources.end();
for (ResourceFetcher::DocumentResourceMap::const_iterator it = allResources.begin(); it != end; ++it) {
Resource* cachedResource = it->value.get();
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
Vector<Document*> InspectorPageAgent::importsForFrame(LocalFrame* frame)
{
Vector<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 Vector<Resource*> cachedResourcesForFrame(LocalFrame* frame, bool skipXHRs)
{
Vector<Resource*> result;
Document* rootDocument = frame->document();
Vector<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;
}
static Vector<KURL> allResourcesURLsForFrame(LocalFrame* frame)
{
Vector<KURL> result;
result.append(urlWithoutFragment(frame->loader().documentLoader()->url()));
Vector<Resource*> allResources = cachedResourcesForFrame(frame, false);
for (Vector<Resource*>::const_iterator it = allResources.begin(); it != allResources.end(); ++it)
result.append(urlWithoutFragment((*it)->url()));
return result;
}
void InspectorPageAgent::getCookies(ErrorString*, RefPtr<TypeBuilder::Array<TypeBuilder::Page::Cookie> >& cookies)
{
ListHashSet<Cookie> rawCookiesList;
for (Frame* frame = mainFrame(); frame; frame = frame->tree().traverseNext(mainFrame())) {
if (!frame->isLocalFrame())
continue;
Document* document = toLocalFrame(frame)->document();
Vector<KURL> allURLs = allResourcesURLsForFrame(toLocalFrame(frame));
for (Vector<KURL>::const_iterator it = allURLs.begin(); it != allURLs.end(); ++it) {
Vector<Cookie> docCookiesList;
getRawCookies(document, *it, docCookiesList);
int cookiesSize = docCookiesList.size();
for (int i = 0; i < cookiesSize; i++) {
if (!rawCookiesList.contains(docCookiesList[i]))
rawCookiesList.add(docCookiesList[i]);
}
}
}
cookies = buildArrayForCookies(rawCookiesList);
}
void InspectorPageAgent::deleteCookie(ErrorString*, const String& cookieName, const String& url)
{
KURL parsedURL(ParsedURLString, url);
for (Frame* frame = m_page->mainFrame(); frame; frame = frame->tree().traverseNext(m_page->mainFrame())) {
if (frame->isLocalFrame())
blink::deleteCookie(toLocalFrame(frame)->document(), parsedURL, cookieName);
}
}
void InspectorPageAgent::getResourceTree(ErrorString*, RefPtr<TypeBuilder::Page::FrameResourceTree>& object)
{
object = buildObjectForFrameTree(m_page->deprecatedLocalMainFrame());
}
void InspectorPageAgent::getResourceContentAfterResourcesContentLoaded(const String& frameId, const String& url, PassRefPtr<GetResourceContentCallback> callback)
{
ErrorString errorString;
LocalFrame* frame = assertFrame(&errorString, frameId);
if (!frame) {
callback->sendFailure(errorString);
return;
}
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)
{
String content;
if (getEditedResourceContent(url, &content)) {
callback->sendSuccess(content, false);
return;
}
if (!m_inspectorResourceContentLoader) {
callback->sendFailure("Agent is not enabled.");
return;
}
m_inspectorResourceContentLoader->ensureResourcesContentLoaded(adoptPtr(new GetResourceContentLoadListener(this, frameId, url, callback)));
}
static bool textContentForResource(Resource* cachedResource, String* result)
{
if (hasTextContent(cachedResource)) {
String content;
bool base64Encoded;
if (InspectorPageAgent::cachedResourceContent(cachedResource, result, &base64Encoded)) {
ASSERT(!base64Encoded);
return true;
}
}
return false;
}
void InspectorPageAgent::searchInResource(ErrorString*, const String& frameId, const String& url, const String& query, const bool* const optionalCaseSensitive, const bool* const optionalIsRegex, RefPtr<TypeBuilder::Array<TypeBuilder::Page::SearchMatch> >& results)
{
results = TypeBuilder::Array<TypeBuilder::Page::SearchMatch>::create();
LocalFrame* frame = frameForId(frameId);
KURL kurl(ParsedURLString, url);
FrameLoader* frameLoader = frame ? &frame->loader() : 0;
DocumentLoader* loader = frameLoader ? frameLoader->documentLoader() : 0;
if (!loader)
return;
String content;
bool success = false;
Resource* resource = cachedResource(frame, kurl);
if (resource)
success = textContentForResource(resource, &content);
if (!success)
return;
results = ContentSearchUtils::searchInTextByLines(content, query, asBool(optionalCaseSensitive), asBool(optionalIsRegex));
}
void InspectorPageAgent::setDocumentContent(ErrorString* errorString, const String& frameId, const String& html)
{
LocalFrame* frame = assertFrame(errorString, frameId);
if (!frame)
return;
Document* document = frame->document();
if (!document) {
*errorString = "No Document instance to set HTML for";
return;
}
DOMPatchSupport::patchDocument(*document, html);
}
void InspectorPageAgent::setDeviceMetricsOverride(ErrorString* errorString, int width, int height, double deviceScaleFactor, bool mobile, bool fitWindow, const double* optionalScale, const double* optionalOffsetX, const double* optionalOffsetY)
{
const static long maxDimension = 10000000;
const static double maxScale = 10;
double scale = optionalScale ? *optionalScale : 1;
double offsetX = optionalOffsetX ? *optionalOffsetX : 0;
double offsetY = optionalOffsetY ? *optionalOffsetY : 0;
if (width < 0 || height < 0 || width > maxDimension || height > maxDimension) {
*errorString = "Width and height values must be positive, not greater than " + String::number(maxDimension);
return;
}
if (deviceScaleFactor < 0) {
*errorString = "deviceScaleFactor must be non-negative";
return;
}
if (scale <= 0 || scale > maxScale) {
*errorString = "scale must be positive, not greater than " + String::number(maxScale);
return;
}
Settings& settings = m_page->settings();
if (!settings.acceleratedCompositingEnabled()) {
if (errorString)
*errorString = "Compositing mode is not supported";
return;
}
if (!deviceMetricsChanged(true, width, height, deviceScaleFactor, mobile, fitWindow, scale, offsetX, offsetY))
return;
m_state->setBoolean(PageAgentState::deviceMetricsOverrideEnabled, true);
m_state->setLong(PageAgentState::pageAgentScreenWidthOverride, width);
m_state->setLong(PageAgentState::pageAgentScreenHeightOverride, height);
m_state->setDouble(PageAgentState::pageAgentDeviceScaleFactorOverride, deviceScaleFactor);
m_state->setBoolean(PageAgentState::pageAgentEmulateMobile, mobile);
m_state->setBoolean(PageAgentState::pageAgentFitWindow, fitWindow);
m_state->setDouble(PageAgentState::deviceScale, scale);
m_state->setDouble(PageAgentState::deviceOffsetX, offsetX);
m_state->setDouble(PageAgentState::deviceOffsetY, offsetY);
updateViewMetricsFromState();
}
void InspectorPageAgent::clearDeviceMetricsOverride(ErrorString*)
{
if (m_state->getBoolean(PageAgentState::deviceMetricsOverrideEnabled)) {
m_state->setBoolean(PageAgentState::deviceMetricsOverrideEnabled, false);
updateViewMetricsFromState();
}
}
void InspectorPageAgent::resetScrollAndPageScaleFactor(ErrorString*)
{
m_client->resetScrollAndPageScaleFactor();
}
bool InspectorPageAgent::deviceMetricsChanged(bool enabled, int width, int height, double deviceScaleFactor, bool mobile, bool fitWindow, double scale, double offsetX, double offsetY)
{
bool currentEnabled = m_state->getBoolean(PageAgentState::deviceMetricsOverrideEnabled);
// These two always fit an int.
int currentWidth = static_cast<int>(m_state->getLong(PageAgentState::pageAgentScreenWidthOverride));
int currentHeight = static_cast<int>(m_state->getLong(PageAgentState::pageAgentScreenHeightOverride));
double currentDeviceScaleFactor = m_state->getDouble(PageAgentState::pageAgentDeviceScaleFactorOverride, 0);
bool currentMobile = m_state->getBoolean(PageAgentState::pageAgentEmulateMobile);
bool currentFitWindow = m_state->getBoolean(PageAgentState::pageAgentFitWindow);
double currentScale = m_state->getDouble(PageAgentState::deviceScale, 1);
double currentOffsetX = m_state->getDouble(PageAgentState::deviceOffsetX, 0);
double currentOffsetY = m_state->getDouble(PageAgentState::deviceOffsetY, 0);
return enabled != currentEnabled
|| width != currentWidth
|| height != currentHeight
|| deviceScaleFactor != currentDeviceScaleFactor
|| mobile != currentMobile
|| fitWindow != currentFitWindow
|| scale != currentScale
|| offsetX != currentOffsetX
|| offsetY != currentOffsetY;
}
void InspectorPageAgent::setShowPaintRects(ErrorString*, bool show)
{
m_state->setBoolean(PageAgentState::pageAgentShowPaintRects, show);
m_client->setShowPaintRects(show);
if (!show && mainFrame() && mainFrame()->view())
mainFrame()->view()->invalidate();
}
void InspectorPageAgent::setShowDebugBorders(ErrorString* errorString, bool show)
{
m_state->setBoolean(PageAgentState::pageAgentShowDebugBorders, show);
if (show && !compositingEnabled(errorString))
return;
m_client->setShowDebugBorders(show);
}
void InspectorPageAgent::setShowFPSCounter(ErrorString* errorString, bool show)
{
// FIXME: allow metrics override, fps counter and continuous painting at the same time: crbug.com/299837.
m_state->setBoolean(PageAgentState::pageAgentShowFPSCounter, show);
if (show && !compositingEnabled(errorString))
return;
m_client->setShowFPSCounter(show && !m_deviceMetricsOverridden);
}
void InspectorPageAgent::setContinuousPaintingEnabled(ErrorString* errorString, bool enabled)
{
m_state->setBoolean(PageAgentState::pageAgentContinuousPaintingEnabled, enabled);
if (enabled && !compositingEnabled(errorString))
return;
m_client->setContinuousPaintingEnabled(enabled && !m_deviceMetricsOverridden);
}
void InspectorPageAgent::setShowScrollBottleneckRects(ErrorString* errorString, bool show)
{
m_state->setBoolean(PageAgentState::pageAgentShowScrollBottleneckRects, show);
if (show && !compositingEnabled(errorString))
return;
m_client->setShowScrollBottleneckRects(show);
}
void InspectorPageAgent::getScriptExecutionStatus(ErrorString*, PageCommandHandler::Result::Enum* status)
{
bool disabledByScriptController = false;
bool disabledInSettings = false;
LocalFrame* frame = mainFrame();
if (frame) {
disabledByScriptController = !frame->script().canExecuteScripts(NotAboutToExecuteScript);
if (frame->settings())
disabledInSettings = !frame->settings()->scriptEnabled();
}
// Order is important.
if (disabledInSettings)
*status = PageCommandHandler::Result::Disabled;
else if (disabledByScriptController)
*status = PageCommandHandler::Result::Forbidden;
else
*status = PageCommandHandler::Result::Allowed;
}
void InspectorPageAgent::setScriptExecutionDisabled(ErrorString*, bool value)
{
m_state->setBoolean(PageAgentState::pageAgentScriptExecutionDisabled, value);
if (!mainFrame())
return;
Settings* settings = mainFrame()->settings();
if (settings) {
m_ignoreScriptsEnabledNotification = true;
settings->setScriptEnabled(!value);
m_ignoreScriptsEnabledNotification = false;
}
}
void InspectorPageAgent::didClearDocumentOfWindowObject(LocalFrame* frame)
{
if (frame == m_page->mainFrame())
m_injectedScriptManager->discardInjectedScripts();
if (!m_frontend)
return;
RefPtr<JSONObject> scripts = m_state->getObject(PageAgentState::pageAgentScriptsToEvaluateOnLoad);
if (scripts) {
JSONObject::const_iterator end = scripts->end();
for (JSONObject::const_iterator it = scripts->begin(); it != end; ++it) {
String scriptText;
if (it->value->asString(&scriptText))
frame->script().executeScriptInMainWorld(scriptText);
}
}
if (!m_scriptToEvaluateOnLoadOnce.isEmpty())
frame->script().executeScriptInMainWorld(m_scriptToEvaluateOnLoadOnce);
}
void InspectorPageAgent::domContentLoadedEventFired(LocalFrame* frame)
{
if (!frame->isMainFrame())
return;
m_frontend->domContentEventFired(currentTime());
}
void InspectorPageAgent::loadEventFired(LocalFrame* frame)
{
if (!frame->isMainFrame())
return;
m_frontend->loadEventFired(currentTime());
}
void InspectorPageAgent::didCommitLoad(LocalFrame*, DocumentLoader* loader)
{
// FIXME: If "frame" is always guaranteed to be in the same Page as loader->frame()
// then all we need to check here is loader->frame()->isMainFrame()
// and we don't need "frame" at all.
if (loader->frame() == m_page->mainFrame()) {
m_scriptToEvaluateOnLoadOnce = m_pendingScriptToEvaluateOnLoadOnce;
m_scriptPreprocessorSource = m_pendingScriptPreprocessor;
m_pendingScriptToEvaluateOnLoadOnce = String();
m_pendingScriptPreprocessor = String();
if (m_inspectorResourceContentLoader)
m_inspectorResourceContentLoader->stop();
}
m_frontend->frameNavigated(buildObjectForFrame(loader->frame()));
viewportChanged();
}
void InspectorPageAgent::frameAttachedToParent(LocalFrame* frame)
{
Frame* parentFrame = frame->tree().parent();
if (!parentFrame->isLocalFrame())
parentFrame = 0;
m_frontend->frameAttached(frameId(frame), frameId(toLocalFrame(parentFrame)));
}
void InspectorPageAgent::frameDetachedFromParent(LocalFrame* frame)
{
HashMap<LocalFrame*, String>::iterator iterator = m_frameToIdentifier.find(frame);
if (iterator != m_frameToIdentifier.end()) {
m_frontend->frameDetached(iterator->value);
m_identifierToFrame.remove(iterator->value);
m_frameToIdentifier.remove(iterator);
}
}
LocalFrame* InspectorPageAgent::mainFrame()
{
return m_page->deprecatedLocalMainFrame();
}
LocalFrame* InspectorPageAgent::frameForId(const String& frameId)
{
return frameId.isEmpty() ? 0 : m_identifierToFrame.get(frameId);
}
String InspectorPageAgent::frameId(LocalFrame* frame)
{
if (!frame)
return "";
String identifier = m_frameToIdentifier.get(frame);
if (identifier.isNull()) {
identifier = IdentifiersFactory::createIdentifier();
m_frameToIdentifier.set(frame, identifier);
m_identifierToFrame.set(identifier, frame);
}
return identifier;
}
bool InspectorPageAgent::hasIdForFrame(LocalFrame* frame) const
{
return frame && m_frameToIdentifier.contains(frame);
}
String InspectorPageAgent::loaderId(DocumentLoader* loader)
{
if (!loader)
return "";
String identifier = m_loaderToIdentifier.get(loader);
if (identifier.isNull()) {
identifier = IdentifiersFactory::createIdentifier();
m_loaderToIdentifier.set(loader, identifier);
}
return identifier;
}
LocalFrame* InspectorPageAgent::findFrameWithSecurityOrigin(const String& originRawString)
{
for (Frame* frame = m_page->mainFrame(); frame; frame = frame->tree().traverseNext()) {
// FIXME: RemoteFrame security origins are not yet available.
if (!frame->isLocalFrame())
continue;
RefPtr<SecurityOrigin> documentOrigin = toLocalFrame(frame)->document()->securityOrigin();
if (documentOrigin->toRawString() == originRawString)
return toLocalFrame(frame);
}
return 0;
}
LocalFrame* InspectorPageAgent::assertFrame(ErrorString* errorString, const String& frameId)
{
LocalFrame* frame = frameForId(frameId);
if (!frame)
*errorString = "No frame for given id found";
return frame;
}
const AtomicString& InspectorPageAgent::resourceSourceMapURL(const String& url)
{
DEFINE_STATIC_LOCAL(const AtomicString, sourceMapHttpHeader, ("SourceMap", AtomicString::ConstructFromLiteral));
DEFINE_STATIC_LOCAL(const AtomicString, deprecatedSourceMapHttpHeader, ("X-SourceMap", AtomicString::ConstructFromLiteral));
if (url.isEmpty())
return nullAtom;
LocalFrame* frame = mainFrame();
if (!frame)
return nullAtom;
Resource* resource = cachedResource(frame, KURL(ParsedURLString, url));
if (!resource)
return nullAtom;
const AtomicString& deprecatedHeaderSourceMapURL = resource->response().httpHeaderField(deprecatedSourceMapHttpHeader);
if (!deprecatedHeaderSourceMapURL.isEmpty()) {
// FIXME: add deprecated console message here.
return deprecatedHeaderSourceMapURL;
}
return resource->response().httpHeaderField(sourceMapHttpHeader);
}
bool InspectorPageAgent::deviceMetricsOverrideEnabled()
{
return m_enabled && m_deviceMetricsOverridden;
}
// static
DocumentLoader* InspectorPageAgent::assertDocumentLoader(ErrorString* errorString, LocalFrame* frame)
{
DocumentLoader* documentLoader = frame->loader().documentLoader();
if (!documentLoader)
*errorString = "No documentLoader for given frame found";
return documentLoader;
}
void InspectorPageAgent::loaderDetachedFromFrame(DocumentLoader* loader)
{
HashMap<DocumentLoader*, String>::iterator iterator = m_loaderToIdentifier.find(loader);
if (iterator != m_loaderToIdentifier.end())
m_loaderToIdentifier.remove(iterator);
}
void InspectorPageAgent::frameStartedLoading(LocalFrame* frame)
{
m_frontend->frameStartedLoading(frameId(frame));
}
void InspectorPageAgent::frameStoppedLoading(LocalFrame* frame)
{
m_frontend->frameStoppedLoading(frameId(frame));
}
void InspectorPageAgent::frameScheduledNavigation(LocalFrame* frame, double delay)
{
m_frontend->frameScheduledNavigation(frameId(frame), delay);
}
void InspectorPageAgent::frameClearedScheduledNavigation(LocalFrame* frame)
{
m_frontend->frameClearedScheduledNavigation(frameId(frame));
}
void InspectorPageAgent::willRunJavaScriptDialog(const String& message)
{
m_frontend->javascriptDialogOpening(message);
}
void InspectorPageAgent::didRunJavaScriptDialog()
{
m_frontend->javascriptDialogClosed();
}
void InspectorPageAgent::didPaint(RenderObject*, const GraphicsLayer*, GraphicsContext* context, const LayoutRect& rect)
{
if (!m_enabled || m_client->overridesShowPaintRects() || !m_state->getBoolean(PageAgentState::pageAgentShowPaintRects))
return;
static int colorSelector = 0;
const Color colors[] = {
Color(0, 0x5F, 0, 0x3F),
Color(0, 0xAF, 0, 0x3F),
Color(0, 0xFF, 0, 0x3F),
};
LayoutRect inflatedRect(rect);
inflatedRect.inflate(-1);
m_overlay->drawOutline(context, inflatedRect, colors[colorSelector++ % WTF_ARRAY_LENGTH(colors)]);
}
void InspectorPageAgent::didLayout(RenderObject*)
{
if (!m_enabled)
return;
m_overlay->update();
viewportChanged();
}
void InspectorPageAgent::didScroll()
{
if (m_enabled)
m_overlay->update();
viewportChanged();
}
void InspectorPageAgent::viewportChanged()
{
if (!m_enabled || !m_deviceMetricsOverridden)
return;
IntSize contentsSize = m_page->deprecatedLocalMainFrame()->view()->contentsSize();
IntRect viewRect = m_page->deprecatedLocalMainFrame()->view()->visibleContentRect();
RefPtr<TypeBuilder::Page::Viewport> viewport = TypeBuilder::Page::Viewport::create()
.setScrollX(viewRect.x())
.setScrollY(viewRect.y())
.setContentsWidth(contentsSize.width())
.setContentsHeight(contentsSize.height())
.setPageScaleFactor(m_page->pageScaleFactor());
m_frontend->viewportChanged(viewport);
}
void InspectorPageAgent::didResizeMainFrame()
{
#if !OS(ANDROID)
if (m_enabled && m_state->getBoolean(PageAgentState::showSizeOnResize))
m_overlay->showAndHideViewSize(m_state->getBoolean(PageAgentState::showGridOnResize));
#endif
m_frontend->frameResized();
viewportChanged();
}
void InspectorPageAgent::didRecalculateStyle(int)
{
if (m_enabled)
m_overlay->update();
}
void InspectorPageAgent::deviceOrPageScaleFactorChanged()
{
if (m_enabled)
m_overlay->update();
viewportChanged();
}
void InspectorPageAgent::scriptsEnabled(bool isEnabled)
{
if (m_ignoreScriptsEnabledNotification)
return;
m_frontend->scriptsEnabled(isEnabled);
}
PassRefPtr<TypeBuilder::Page::Frame> InspectorPageAgent::buildObjectForFrame(LocalFrame* frame)
{
RefPtr<TypeBuilder::Page::Frame> frameObject = TypeBuilder::Page::Frame::create()
.setId(frameId(frame))
.setLoaderId(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<TypeBuilder::Page::FrameResourceTree> InspectorPageAgent::buildObjectForFrameTree(LocalFrame* frame)
{
RefPtr<TypeBuilder::Page::Frame> frameObject = buildObjectForFrame(frame);
RefPtr<TypeBuilder::Array<TypeBuilder::Page::FrameResourceTree::Resources> > subresources = TypeBuilder::Array<TypeBuilder::Page::FrameResourceTree::Resources>::create();
RefPtr<TypeBuilder::Page::FrameResourceTree> result = TypeBuilder::Page::FrameResourceTree::create()
.setFrame(frameObject)
.setResources(subresources);
Vector<Resource*> allResources = cachedResourcesForFrame(frame, true);
for (Vector<Resource*>::const_iterator it = allResources.begin(); it != allResources.end(); ++it) {
Resource* cachedResource = *it;
RefPtr<TypeBuilder::Page::FrameResourceTree::Resources> resourceObject = 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);
}
Vector<Document*> allImports = InspectorPageAgent::importsForFrame(frame);
for (Vector<Document*>::const_iterator it = allImports.begin(); it != allImports.end(); ++it) {
Document* import = *it;
RefPtr<TypeBuilder::Page::FrameResourceTree::Resources> resourceObject = TypeBuilder::Page::FrameResourceTree::Resources::create()
.setUrl(urlWithoutFragment(import->url()).string())
.setType(resourceTypeJson(InspectorPageAgent::DocumentResource))
.setMimeType(import->suggestedMIMEType());
subresources->addItem(resourceObject);
}
RefPtr<TypeBuilder::Array<TypeBuilder::Page::FrameResourceTree> > childrenArray;
for (Frame* child = frame->tree().firstChild(); child; child = child->tree().nextSibling()) {
if (!child->isLocalFrame())
continue;
if (!childrenArray) {
childrenArray = TypeBuilder::Array<TypeBuilder::Page::FrameResourceTree>::create();
result->setChildFrames(childrenArray);
}
childrenArray->addItem(buildObjectForFrameTree(toLocalFrame(child)));
}
return result;
}
void InspectorPageAgent::updateViewMetricsFromState()
{
bool enabled = m_state->getBoolean(PageAgentState::deviceMetricsOverrideEnabled);
int width = static_cast<int>(m_state->getLong(PageAgentState::pageAgentScreenWidthOverride));
int height = static_cast<int>(m_state->getLong(PageAgentState::pageAgentScreenHeightOverride));
bool mobile = m_state->getBoolean(PageAgentState::pageAgentEmulateMobile);
double deviceScaleFactor = m_state->getDouble(PageAgentState::pageAgentDeviceScaleFactorOverride);
bool fitWindow = m_state->getBoolean(PageAgentState::pageAgentFitWindow);
double scale = m_state->getDouble(PageAgentState::deviceScale, 1);
double offsetX = m_state->getDouble(PageAgentState::deviceOffsetX, 0);
double offsetY = m_state->getDouble(PageAgentState::deviceOffsetY, 0);
updateViewMetrics(enabled, width, height, deviceScaleFactor, mobile, fitWindow, scale, offsetX, offsetY);
}
void InspectorPageAgent::updateViewMetrics(bool enabled, int width, int height, double deviceScaleFactor, bool mobile, bool fitWindow, double scale, double offsetX, double offsetY)
{
if (enabled && !m_page->settings().acceleratedCompositingEnabled())
return;
m_deviceMetricsOverridden = enabled;
m_emulateMobileEnabled = mobile;
if (enabled)
m_client->setDeviceMetricsOverride(width, height, static_cast<float>(deviceScaleFactor), mobile, fitWindow, static_cast<float>(scale), static_cast<float>(offsetX), static_cast<float>(offsetY));
else
m_client->clearDeviceMetricsOverride();
Document* document = mainFrame()->document();
if (document) {
document->styleResolverChanged();
document->mediaQueryAffectingValueChanged();
}
InspectorInstrumentation::mediaQueryResultChanged(document);
if (m_deviceMetricsOverridden) {
m_page->settings().setTextAutosizingEnabled(mobile);
m_page->settings().setDeviceScaleAdjustment(calculateFontScaleFactor(width, height, static_cast<float>(deviceScaleFactor)));
} else {
m_page->settings().setTextAutosizingEnabled(m_embedderTextAutosizingEnabled);
m_page->settings().setDeviceScaleAdjustment(m_embedderFontScaleFactor);
}
// FIXME: allow metrics override, fps counter and continuous painting at the same time: crbug.com/299837.
m_client->setShowFPSCounter(m_state->getBoolean(PageAgentState::pageAgentShowFPSCounter) && !m_deviceMetricsOverridden);
m_client->setContinuousPaintingEnabled(m_state->getBoolean(PageAgentState::pageAgentContinuousPaintingEnabled) && !m_deviceMetricsOverridden);
}
void InspectorPageAgent::updateTouchEventEmulationInPage(bool enabled)
{
if (!m_touchEmulationEnabled) {
m_originalTouchEnabled = RuntimeEnabledFeatures::touchEnabled();
m_originalDeviceSupportsMouse = m_page->settings().deviceSupportsMouse();
m_originalDeviceSupportsTouch = m_page->settings().deviceSupportsTouch();
}
RuntimeEnabledFeatures::setTouchEnabled(enabled ? true : m_originalTouchEnabled);
if (!m_originalDeviceSupportsTouch) {
m_page->settings().setDeviceSupportsMouse(enabled ? false : m_originalDeviceSupportsMouse);
m_page->settings().setDeviceSupportsTouch(enabled ? true : m_originalDeviceSupportsTouch);
}
m_touchEmulationEnabled = enabled;
m_client->setTouchEventEmulationEnabled(enabled);
m_page->deprecatedLocalMainFrame()->view()->layout();
}
void InspectorPageAgent::setTouchEmulationEnabled(ErrorString*, bool enabled)
{
if (m_state->getBoolean(PageAgentState::touchEventEmulationEnabled) == enabled)
return;
m_state->setBoolean(PageAgentState::touchEventEmulationEnabled, enabled);
updateTouchEventEmulationInPage(enabled);
}
void InspectorPageAgent::setEmulatedMedia(ErrorString*, const String& media)
{
String currentMedia = m_state->getString(PageAgentState::pageAgentEmulatedMedia);
if (media == currentMedia)
return;
m_state->setString(PageAgentState::pageAgentEmulatedMedia, media);
Document* document = 0;
if (m_page->mainFrame())
document = m_page->deprecatedLocalMainFrame()->document();
if (document) {
document->mediaQueryAffectingValueChanged();
document->styleResolverChanged();
document->updateLayout();
}
}
bool InspectorPageAgent::applyViewportStyleOverride(StyleResolver* resolver)
{
if (!m_deviceMetricsOverridden || !m_emulateMobileEnabled)
return false;
RefPtrWillBeRawPtr<StyleSheetContents> styleSheet = StyleSheetContents::create(CSSParserContext(UASheetMode, 0));
styleSheet->parseString(String(viewportAndroidCss, sizeof(viewportAndroidCss)));
OwnPtrWillBeRawPtr<RuleSet> ruleSet = RuleSet::create();
ruleSet->addRulesFromSheet(styleSheet.get(), MediaQueryEvaluator("screen"));
resolver->viewportStyleResolver()->collectViewportRules(ruleSet.get(), ViewportStyleResolver::UserAgentOrigin);
return true;
}
void InspectorPageAgent::applyEmulatedMedia(String* media)
{
String emulatedMedia = m_state->getString(PageAgentState::pageAgentEmulatedMedia);
if (!emulatedMedia.isEmpty())
*media = emulatedMedia;
}
bool InspectorPageAgent::compositingEnabled(ErrorString* errorString)
{
if (!m_page->settings().acceleratedCompositingEnabled()) {
if (errorString)
*errorString = "Compositing mode is not supported";
return false;
}
return true;
}
void InspectorPageAgent::setShowViewportSizeOnResize(ErrorString*, bool show, const bool* showGrid)
{
m_state->setBoolean(PageAgentState::showSizeOnResize, show);
m_state->setBoolean(PageAgentState::showGridOnResize, asBool(showGrid));
}
void InspectorPageAgent::clearEditedResourcesContent()
{
m_editedResourceContent.clear();
}
void InspectorPageAgent::addEditedResourceContent(const String& url, const String& content)
{
m_editedResourceContent.set(url, content);
}
bool InspectorPageAgent::getEditedResourceContent(const String& url, String* content)
{
if (!m_editedResourceContent.contains(url))
return false;
*content = m_editedResourceContent.get(url);
return true;
}
void InspectorPageAgent::trace(Visitor* visitor)
{
visitor->trace(m_page);
visitor->trace(m_injectedScriptManager);
InspectorBaseAgent::trace(visitor);
}
} // namespace blink