2 * Copyright (C) 2011 Google Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above
11 * copyright notice, this list of conditions and the following disclaimer
12 * in the documentation and/or other materials provided with the
14 * * Neither the name of Google Inc. nor the names of its
15 * contributors may be used to endorse or promote products derived from
16 * this software without specific prior written permission.
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
35 #include "InspectorPageAgent.h"
37 #include "CachedCSSStyleSheet.h"
38 #include "CachedFont.h"
39 #include "CachedImage.h"
40 #include "CachedResource.h"
41 #include "CachedResourceLoader.h"
42 #include "CachedScript.h"
43 #include "ContentSearchUtils.h"
45 #include "CookieJar.h"
46 #include "DOMImplementation.h"
47 #include "DOMPatchSupport.h"
48 #include "DOMWrapperWorld.h"
50 #include "DocumentLoader.h"
52 #include "FrameLoader.h"
53 #include "FrameSnapshotting.h"
54 #include "FrameView.h"
55 #include "HTMLFrameOwnerElement.h"
56 #include "HTMLNames.h"
57 #include "IdentifiersFactory.h"
58 #include "ImageBuffer.h"
59 #include "InspectorClient.h"
60 #include "InspectorDOMAgent.h"
61 #include "InspectorInstrumentation.h"
62 #include "InspectorOverlay.h"
63 #include "InspectorWebFrontendDispatchers.h"
64 #include "InstrumentingAgents.h"
65 #include "MainFrame.h"
66 #include "MemoryCache.h"
68 #include "RegularExpression.h"
69 #include "ResourceBuffer.h"
70 #include "ScriptController.h"
71 #include "SecurityOrigin.h"
73 #include "TextEncoding.h"
74 #include "TextResourceDecoder.h"
75 #include "UserGestureIndicator.h"
76 #include <bindings/ScriptValue.h>
77 #include <inspector/InspectorValues.h>
78 #include <wtf/CurrentTime.h>
79 #include <wtf/ListHashSet.h>
80 #include <wtf/Vector.h>
81 #include <wtf/text/Base64.h>
82 #include <wtf/text/StringBuilder.h>
84 #if ENABLE(WEB_ARCHIVE) && USE(CF)
85 #include "LegacyWebArchive.h"
88 using namespace Inspector;
92 static bool decodeBuffer(const char* buffer, unsigned size, const String& textEncodingName, String* result)
95 TextEncoding encoding(textEncodingName);
96 if (!encoding.isValid())
97 encoding = WindowsLatin1Encoding();
98 *result = encoding.decode(buffer, size);
104 static bool prepareCachedResourceBuffer(CachedResource* cachedResource, bool* hasZeroSize)
106 *hasZeroSize = false;
110 // Zero-sized resources don't have data at all -- so fake the empty buffer, instead of indicating error by returning 0.
111 if (!cachedResource->encodedSize()) {
116 if (cachedResource->isPurgeable()) {
117 // If the resource is purgeable then make it unpurgeable to get
118 // get its data. This might fail, in which case we return an
120 // FIXME: should we do something else in the case of a purged
121 // resource that informs the user why there is no data in the
123 if (!cachedResource->makePurgeable(false))
130 static bool hasTextContent(CachedResource* cachedResource)
132 InspectorPageAgent::ResourceType type = InspectorPageAgent::cachedResourceType(*cachedResource);
133 return type == InspectorPageAgent::DocumentResource || type == InspectorPageAgent::StylesheetResource || type == InspectorPageAgent::ScriptResource || type == InspectorPageAgent::XHRResource;
136 static PassRefPtr<TextResourceDecoder> createXHRTextDecoder(const String& mimeType, const String& textEncodingName)
138 RefPtr<TextResourceDecoder> decoder;
139 if (!textEncodingName.isEmpty())
140 decoder = TextResourceDecoder::create("text/plain", textEncodingName);
141 else if (DOMImplementation::isXMLMIMEType(mimeType.lower())) {
142 decoder = TextResourceDecoder::create("application/xml");
143 decoder->useLenientXMLDecoding();
144 } else if (equalIgnoringCase(mimeType, "text/html"))
145 decoder = TextResourceDecoder::create("text/html", "UTF-8");
147 decoder = TextResourceDecoder::create("text/plain", "UTF-8");
151 bool InspectorPageAgent::cachedResourceContent(CachedResource* cachedResource, String* result, bool* base64Encoded)
154 bool prepared = prepareCachedResourceBuffer(cachedResource, &hasZeroSize);
158 *base64Encoded = !hasTextContent(cachedResource);
159 if (*base64Encoded) {
160 RefPtr<SharedBuffer> buffer = hasZeroSize ? SharedBuffer::create() : cachedResource->resourceBuffer()->sharedBuffer();
165 *result = base64Encode(buffer->data(), buffer->size());
174 if (cachedResource) {
175 switch (cachedResource->type()) {
176 case CachedResource::CSSStyleSheet:
177 *result = static_cast<CachedCSSStyleSheet*>(cachedResource)->sheetText(false);
179 case CachedResource::Script:
180 *result = static_cast<CachedScript*>(cachedResource)->script();
182 case CachedResource::RawResource: {
183 ResourceBuffer* buffer = cachedResource->resourceBuffer();
186 RefPtr<TextResourceDecoder> decoder = createXHRTextDecoder(cachedResource->response().mimeType(), cachedResource->response().textEncodingName());
187 // We show content for raw resources only for certain mime types (text, html and xml). Otherwise decoder will be null.
190 String content = decoder->decode(buffer->data(), buffer->size());
191 *result = content + decoder->flush();
195 ResourceBuffer* buffer = cachedResource->resourceBuffer();
196 return decodeBuffer(buffer ? buffer->data() : nullptr, buffer ? buffer->size() : 0, cachedResource->encoding(), result);
202 bool InspectorPageAgent::mainResourceContent(Frame* frame, bool withBase64Encode, String* result)
204 RefPtr<ResourceBuffer> buffer = frame->loader().documentLoader()->mainResourceData();
207 String textEncodingName = frame->document()->inputEncoding();
209 return InspectorPageAgent::dataContent(buffer->data(), buffer->size(), textEncodingName, withBase64Encode, result);
213 bool InspectorPageAgent::sharedBufferContent(PassRefPtr<SharedBuffer> buffer, const String& textEncodingName, bool withBase64Encode, String* result)
215 return dataContent(buffer ? buffer->data() : nullptr, buffer ? buffer->size() : 0, textEncodingName, withBase64Encode, result);
218 bool InspectorPageAgent::dataContent(const char* data, unsigned size, const String& textEncodingName, bool withBase64Encode, String* result)
220 if (withBase64Encode) {
221 *result = base64Encode(data, size);
225 return decodeBuffer(data, size, textEncodingName, result);
229 void InspectorPageAgent::resourceContent(ErrorString* errorString, Frame* frame, const URL& url, String* result, bool* base64Encoded)
231 DocumentLoader* loader = assertDocumentLoader(errorString, frame);
235 RefPtr<SharedBuffer> buffer;
236 bool success = false;
237 if (equalIgnoringFragmentIdentifier(url, loader->url())) {
238 *base64Encoded = false;
239 success = mainResourceContent(frame, *base64Encoded, result);
243 success = cachedResourceContent(cachedResource(frame, url), result, base64Encoded);
246 *errorString = "No resource with given URL found";
250 String InspectorPageAgent::sourceMapURLForResource(CachedResource* cachedResource)
252 DEFINE_STATIC_LOCAL(String, sourceMapHTTPHeader, (ASCIILiteral("SourceMap")));
253 DEFINE_STATIC_LOCAL(String, sourceMapHTTPHeaderDeprecated, (ASCIILiteral("X-SourceMap")));
258 // Scripts are handled in a separate path.
259 if (cachedResource->type() != CachedResource::CSSStyleSheet)
262 String sourceMapHeader = cachedResource->response().httpHeaderField(sourceMapHTTPHeader);
263 if (!sourceMapHeader.isEmpty())
264 return sourceMapHeader;
266 sourceMapHeader = cachedResource->response().httpHeaderField(sourceMapHTTPHeaderDeprecated);
267 if (!sourceMapHeader.isEmpty())
268 return sourceMapHeader;
272 if (InspectorPageAgent::cachedResourceContent(cachedResource, &content, &base64Encoded) && !base64Encoded)
273 return ContentSearchUtils::findStylesheetSourceMapURL(content);
278 CachedResource* InspectorPageAgent::cachedResource(Frame* frame, const URL& url)
280 CachedResource* cachedResource = frame->document()->cachedResourceLoader()->cachedResource(url);
281 if (!cachedResource) {
282 ResourceRequest request(url);
283 #if ENABLE(CACHE_PARTITIONING)
284 request.setCachePartition(frame->document()->topOrigin()->cachePartition());
286 cachedResource = memoryCache()->resourceForRequest(request);
289 return cachedResource;
292 Inspector::TypeBuilder::Page::ResourceType::Enum InspectorPageAgent::resourceTypeJson(InspectorPageAgent::ResourceType resourceType)
294 switch (resourceType) {
295 case DocumentResource:
296 return Inspector::TypeBuilder::Page::ResourceType::Document;
298 return Inspector::TypeBuilder::Page::ResourceType::Image;
300 return Inspector::TypeBuilder::Page::ResourceType::Font;
301 case StylesheetResource:
302 return Inspector::TypeBuilder::Page::ResourceType::Stylesheet;
304 return Inspector::TypeBuilder::Page::ResourceType::Script;
306 return Inspector::TypeBuilder::Page::ResourceType::XHR;
307 case WebSocketResource:
308 return Inspector::TypeBuilder::Page::ResourceType::WebSocket;
310 return Inspector::TypeBuilder::Page::ResourceType::Other;
312 return Inspector::TypeBuilder::Page::ResourceType::Other;
315 InspectorPageAgent::ResourceType InspectorPageAgent::cachedResourceType(const CachedResource& cachedResource)
317 switch (cachedResource.type()) {
318 case CachedResource::ImageResource:
319 return InspectorPageAgent::ImageResource;
320 case CachedResource::FontResource:
321 return InspectorPageAgent::FontResource;
322 case CachedResource::CSSStyleSheet:
325 case CachedResource::XSLStyleSheet:
327 return InspectorPageAgent::StylesheetResource;
328 case CachedResource::Script:
329 return InspectorPageAgent::ScriptResource;
330 case CachedResource::RawResource:
331 return InspectorPageAgent::XHRResource;
332 case CachedResource::MainResource:
333 return InspectorPageAgent::DocumentResource;
337 return InspectorPageAgent::OtherResource;
340 Inspector::TypeBuilder::Page::ResourceType::Enum InspectorPageAgent::cachedResourceTypeJson(const CachedResource& cachedResource)
342 return resourceTypeJson(cachedResourceType(cachedResource));
345 InspectorPageAgent::InspectorPageAgent(InstrumentingAgents* instrumentingAgents, Page* page, InspectorClient* client, InspectorOverlay* overlay)
346 : InspectorAgentBase(ASCIILiteral("Page"), instrumentingAgents)
350 , m_lastScriptIdentifier(0)
352 , m_isFirstLayoutAfterOnLoad(false)
353 , m_originalScriptExecutionDisabled(false)
354 , m_ignoreScriptsEnabledNotification(false)
355 , m_showPaintRects(false)
359 void InspectorPageAgent::didCreateFrontendAndBackend(Inspector::InspectorFrontendChannel* frontendChannel, InspectorBackendDispatcher* backendDispatcher)
361 m_frontendDispatcher = std::make_unique<InspectorPageFrontendDispatcher>(frontendChannel);
362 m_backendDispatcher = InspectorPageBackendDispatcher::create(backendDispatcher, this);
365 void InspectorPageAgent::willDestroyFrontendAndBackend(InspectorDisconnectReason)
367 m_frontendDispatcher = nullptr;
368 m_backendDispatcher.clear();
372 #if ENABLE(TOUCH_EVENTS)
373 updateTouchEventEmulationInPage(false);
377 void InspectorPageAgent::enable(ErrorString*)
380 m_instrumentingAgents->setInspectorPageAgent(this);
382 if (Frame* frame = mainFrame())
383 m_originalScriptExecutionDisabled = !frame->settings().isScriptEnabled();
386 void InspectorPageAgent::disable(ErrorString*)
389 m_scriptsToEvaluateOnLoad.clear();
390 m_instrumentingAgents->setInspectorPageAgent(nullptr);
392 setScriptExecutionDisabled(nullptr, m_originalScriptExecutionDisabled);
393 setShowPaintRects(nullptr, false);
394 setShowDebugBorders(nullptr, false);
395 setShowFPSCounter(nullptr, false);
396 setEmulatedMedia(nullptr, "");
397 setContinuousPaintingEnabled(nullptr, false);
400 void InspectorPageAgent::addScriptToEvaluateOnLoad(ErrorString*, const String& source, String* identifier)
402 if (!m_scriptsToEvaluateOnLoad)
403 m_scriptsToEvaluateOnLoad = InspectorObject::create();
405 // Assure we don't override existing ids -- m_lastScriptIdentifier could get out of sync WRT actual
406 // scripts once we restored the scripts from the cookie during navigation.
408 *identifier = String::number(++m_lastScriptIdentifier);
409 } while (m_scriptsToEvaluateOnLoad->find(*identifier) != m_scriptsToEvaluateOnLoad->end());
411 m_scriptsToEvaluateOnLoad->setString(*identifier, source);
414 void InspectorPageAgent::removeScriptToEvaluateOnLoad(ErrorString* error, const String& identifier)
416 if (!m_scriptsToEvaluateOnLoad || m_scriptsToEvaluateOnLoad->find(identifier) == m_scriptsToEvaluateOnLoad->end()) {
417 *error = "Script not found";
421 m_scriptsToEvaluateOnLoad->remove(identifier);
424 void InspectorPageAgent::reload(ErrorString*, const bool* const optionalIgnoreCache, const String* optionalScriptToEvaluateOnLoad)
426 m_pendingScriptToEvaluateOnLoadOnce = optionalScriptToEvaluateOnLoad ? *optionalScriptToEvaluateOnLoad : "";
427 m_page->mainFrame().loader().reload(optionalIgnoreCache ? *optionalIgnoreCache : false);
430 void InspectorPageAgent::navigate(ErrorString*, const String& url)
432 UserGestureIndicator indicator(DefinitelyProcessingUserGesture);
433 Frame& frame = m_page->mainFrame();
434 frame.loader().changeLocation(frame.document()->securityOrigin(), frame.document()->completeURL(url), "", false, false);
437 static PassRefPtr<Inspector::TypeBuilder::Page::Cookie> buildObjectForCookie(const Cookie& cookie)
439 return Inspector::TypeBuilder::Page::Cookie::create()
440 .setName(cookie.name)
441 .setValue(cookie.value)
442 .setDomain(cookie.domain)
443 .setPath(cookie.path)
444 .setExpires(cookie.expires)
445 .setSize((cookie.name.length() + cookie.value.length()))
446 .setHttpOnly(cookie.httpOnly)
447 .setSecure(cookie.secure)
448 .setSession(cookie.session)
452 static PassRefPtr<Inspector::TypeBuilder::Array<Inspector::TypeBuilder::Page::Cookie>> buildArrayForCookies(ListHashSet<Cookie>& cookiesList)
454 RefPtr<Inspector::TypeBuilder::Array<Inspector::TypeBuilder::Page::Cookie>> cookies = Inspector::TypeBuilder::Array<Inspector::TypeBuilder::Page::Cookie>::create();
456 ListHashSet<Cookie>::iterator end = cookiesList.end();
457 ListHashSet<Cookie>::iterator it = cookiesList.begin();
458 for (int i = 0; it != end; ++it, i++)
459 cookies->addItem(buildObjectForCookie(*it));
464 static Vector<CachedResource*> cachedResourcesForFrame(Frame* frame)
466 Vector<CachedResource*> result;
468 const CachedResourceLoader::DocumentResourceMap& allResources = frame->document()->cachedResourceLoader()->allCachedResources();
469 CachedResourceLoader::DocumentResourceMap::const_iterator end = allResources.end();
470 for (CachedResourceLoader::DocumentResourceMap::const_iterator it = allResources.begin(); it != end; ++it) {
471 CachedResource* cachedResource = it->value.get();
473 switch (cachedResource->type()) {
474 case CachedResource::ImageResource:
475 // Skip images that were not auto loaded (images disabled in the user agent).
476 case CachedResource::FontResource:
477 // Skip fonts that were referenced in CSS but never used/downloaded.
478 if (cachedResource->stillNeedsLoad())
482 // All other CachedResource types download immediately.
486 result.append(cachedResource);
492 static Vector<URL> allResourcesURLsForFrame(Frame* frame)
496 result.append(frame->loader().documentLoader()->url());
498 Vector<CachedResource*> allResources = cachedResourcesForFrame(frame);
499 for (Vector<CachedResource*>::const_iterator it = allResources.begin(); it != allResources.end(); ++it)
500 result.append((*it)->url());
505 void InspectorPageAgent::getCookies(ErrorString*, RefPtr<Inspector::TypeBuilder::Array<Inspector::TypeBuilder::Page::Cookie>>& cookies)
507 // If we can get raw cookies.
508 ListHashSet<Cookie> rawCookiesList;
510 // If we can't get raw cookies - fall back to String representation
511 StringBuilder stringCookiesList;
513 // Return value to getRawCookies should be the same for every call because
514 // the return value is platform/network backend specific, and the call will
515 // always return the same true/false value.
516 bool rawCookiesImplemented = false;
518 for (Frame* frame = mainFrame(); frame; frame = frame->tree().traverseNext(mainFrame())) {
519 Document* document = frame->document();
520 Vector<URL> allURLs = allResourcesURLsForFrame(frame);
521 for (Vector<URL>::const_iterator it = allURLs.begin(); it != allURLs.end(); ++it) {
522 Vector<Cookie> docCookiesList;
523 rawCookiesImplemented = getRawCookies(document, URL(ParsedURLString, *it), docCookiesList);
524 if (!rawCookiesImplemented) {
525 // FIXME: We need duplication checking for the String representation of cookies.
527 // Exceptions are thrown by cookie() in sandboxed frames. That won't happen here
528 // because "document" is the document of the main frame of the page.
529 stringCookiesList.append(document->cookie(ASSERT_NO_EXCEPTION));
531 int cookiesSize = docCookiesList.size();
532 for (int i = 0; i < cookiesSize; i++) {
533 if (!rawCookiesList.contains(docCookiesList[i]))
534 rawCookiesList.add(docCookiesList[i]);
540 // FIXME: Do not return empty string/empty array. Make returns optional instead. https://bugs.webkit.org/show_bug.cgi?id=80855
541 if (rawCookiesImplemented)
542 cookies = buildArrayForCookies(rawCookiesList);
544 cookies = Inspector::TypeBuilder::Array<TypeBuilder::Page::Cookie>::create();
547 void InspectorPageAgent::deleteCookie(ErrorString*, const String& cookieName, const String& url)
549 URL parsedURL(ParsedURLString, url);
550 for (Frame* frame = &m_page->mainFrame(); frame; frame = frame->tree().traverseNext(&m_page->mainFrame()))
551 WebCore::deleteCookie(frame->document(), parsedURL, cookieName);
554 void InspectorPageAgent::getResourceTree(ErrorString*, RefPtr<Inspector::TypeBuilder::Page::FrameResourceTree>& object)
556 object = buildObjectForFrameTree(&m_page->mainFrame());
559 void InspectorPageAgent::getResourceContent(ErrorString* errorString, const String& frameId, const String& url, String* content, bool* base64Encoded)
561 Frame* frame = assertFrame(errorString, frameId);
565 resourceContent(errorString, frame, URL(ParsedURLString, url), content, base64Encoded);
568 static bool textContentForCachedResource(CachedResource* cachedResource, String* result)
570 if (hasTextContent(cachedResource)) {
573 if (InspectorPageAgent::cachedResourceContent(cachedResource, result, &base64Encoded)) {
574 ASSERT(!base64Encoded);
581 void InspectorPageAgent::searchInResource(ErrorString*, const String& frameId, const String& url, const String& query, const bool* const optionalCaseSensitive, const bool* const optionalIsRegex, RefPtr<Inspector::TypeBuilder::Array<Inspector::TypeBuilder::GenericTypes::SearchMatch>>& results)
583 results = Inspector::TypeBuilder::Array<Inspector::TypeBuilder::GenericTypes::SearchMatch>::create();
585 bool isRegex = optionalIsRegex ? *optionalIsRegex : false;
586 bool caseSensitive = optionalCaseSensitive ? *optionalCaseSensitive : false;
588 Frame* frame = frameForId(frameId);
592 DocumentLoader* loader = frame->loader().documentLoader();
596 URL kurl(ParsedURLString, url);
599 bool success = false;
600 if (equalIgnoringFragmentIdentifier(kurl, loader->url()))
601 success = mainResourceContent(frame, false, &content);
604 CachedResource* resource = cachedResource(frame, kurl);
606 success = textContentForCachedResource(resource, &content);
612 results = ContentSearchUtils::searchInTextByLines(content, query, caseSensitive, isRegex);
615 static PassRefPtr<Inspector::TypeBuilder::Page::SearchResult> buildObjectForSearchResult(const String& frameId, const String& url, int matchesCount)
617 return Inspector::TypeBuilder::Page::SearchResult::create()
620 .setMatchesCount(matchesCount)
624 void InspectorPageAgent::searchInResources(ErrorString*, const String& text, const bool* const optionalCaseSensitive, const bool* const optionalIsRegex, RefPtr<Inspector::TypeBuilder::Array<Inspector::TypeBuilder::Page::SearchResult>>& results)
626 RefPtr<Inspector::TypeBuilder::Array<Inspector::TypeBuilder::Page::SearchResult>> searchResults = Inspector::TypeBuilder::Array<Inspector::TypeBuilder::Page::SearchResult>::create();
628 bool isRegex = optionalIsRegex ? *optionalIsRegex : false;
629 bool caseSensitive = optionalCaseSensitive ? *optionalCaseSensitive : false;
630 RegularExpression regex = ContentSearchUtils::createSearchRegex(text, caseSensitive, isRegex);
632 for (Frame* frame = &m_page->mainFrame(); frame; frame = frame->tree().traverseNext(&m_page->mainFrame())) {
634 Vector<CachedResource*> allResources = cachedResourcesForFrame(frame);
635 for (Vector<CachedResource*>::const_iterator it = allResources.begin(); it != allResources.end(); ++it) {
636 CachedResource* cachedResource = *it;
637 if (textContentForCachedResource(cachedResource, &content)) {
638 int matchesCount = ContentSearchUtils::countRegularExpressionMatches(regex, content);
640 searchResults->addItem(buildObjectForSearchResult(frameId(frame), cachedResource->url(), matchesCount));
643 if (mainResourceContent(frame, false, &content)) {
644 int matchesCount = ContentSearchUtils::countRegularExpressionMatches(regex, content);
646 searchResults->addItem(buildObjectForSearchResult(frameId(frame), frame->document()->url(), matchesCount));
650 results = searchResults;
653 void InspectorPageAgent::setDocumentContent(ErrorString* errorString, const String& frameId, const String& html)
655 Frame* frame = assertFrame(errorString, frameId);
659 Document* document = frame->document();
661 *errorString = "No Document instance to set HTML for";
664 DOMPatchSupport::patchDocument(document, html);
667 void InspectorPageAgent::setShowPaintRects(ErrorString*, bool show)
669 m_showPaintRects = show;
670 m_client->setShowPaintRects(show);
672 if (!show && mainFrame() && mainFrame()->view())
673 mainFrame()->view()->invalidate();
676 void InspectorPageAgent::canShowDebugBorders(ErrorString*, bool* outParam)
678 *outParam = m_client->canShowDebugBorders();
681 void InspectorPageAgent::setShowDebugBorders(ErrorString*, bool show)
683 m_client->setShowDebugBorders(show);
684 if (mainFrame() && mainFrame()->view())
685 mainFrame()->view()->invalidate();
688 void InspectorPageAgent::canShowFPSCounter(ErrorString*, bool* outParam)
690 *outParam = m_client->canShowFPSCounter();
693 void InspectorPageAgent::setShowFPSCounter(ErrorString*, bool show)
695 m_client->setShowFPSCounter(show);
697 if (mainFrame() && mainFrame()->view())
698 mainFrame()->view()->invalidate();
701 void InspectorPageAgent::canContinuouslyPaint(ErrorString*, bool* outParam)
703 *outParam = m_client->canContinuouslyPaint();
706 void InspectorPageAgent::setContinuousPaintingEnabled(ErrorString*, bool enabled)
708 m_client->setContinuousPaintingEnabled(enabled);
710 if (!enabled && mainFrame() && mainFrame()->view())
711 mainFrame()->view()->invalidate();
714 void InspectorPageAgent::getScriptExecutionStatus(ErrorString*, InspectorPageBackendDispatcherHandler::Result::Enum* status)
716 bool disabledByScriptController = false;
717 bool disabledInSettings = false;
718 Frame* frame = mainFrame();
720 disabledByScriptController = !frame->script().canExecuteScripts(NotAboutToExecuteScript);
721 disabledInSettings = !frame->settings().isScriptEnabled();
724 if (!disabledByScriptController) {
725 *status = InspectorPageBackendDispatcherHandler::Result::Allowed;
729 if (disabledInSettings)
730 *status = InspectorPageBackendDispatcherHandler::Result::Disabled;
732 *status = InspectorPageBackendDispatcherHandler::Result::Forbidden;
735 void InspectorPageAgent::setScriptExecutionDisabled(ErrorString*, bool value)
740 m_ignoreScriptsEnabledNotification = true;
741 mainFrame()->settings().setScriptEnabled(!value);
742 m_ignoreScriptsEnabledNotification = false;
745 void InspectorPageAgent::didClearWindowObjectInWorld(Frame* frame, DOMWrapperWorld& world)
747 if (&world != &mainThreadNormalWorld())
750 if (!m_frontendDispatcher)
753 if (m_scriptsToEvaluateOnLoad) {
754 InspectorObject::const_iterator end = m_scriptsToEvaluateOnLoad->end();
755 for (InspectorObject::const_iterator it = m_scriptsToEvaluateOnLoad->begin(); it != end; ++it) {
757 if (it->value->asString(&scriptText))
758 frame->script().executeScript(scriptText);
762 if (!m_scriptToEvaluateOnLoadOnce.isEmpty())
763 frame->script().executeScript(m_scriptToEvaluateOnLoadOnce);
766 void InspectorPageAgent::domContentEventFired()
768 m_isFirstLayoutAfterOnLoad = true;
769 m_frontendDispatcher->domContentEventFired(currentTime());
772 void InspectorPageAgent::loadEventFired()
774 m_frontendDispatcher->loadEventFired(currentTime());
777 void InspectorPageAgent::frameNavigated(DocumentLoader* loader)
779 if (loader->frame()->isMainFrame()) {
780 m_scriptToEvaluateOnLoadOnce = m_pendingScriptToEvaluateOnLoadOnce;
781 m_pendingScriptToEvaluateOnLoadOnce = String();
783 m_frontendDispatcher->frameNavigated(buildObjectForFrame(loader->frame()));
786 void InspectorPageAgent::frameDetached(Frame* frame)
788 HashMap<Frame*, String>::iterator iterator = m_frameToIdentifier.find(frame);
789 if (iterator != m_frameToIdentifier.end()) {
790 m_frontendDispatcher->frameDetached(iterator->value);
791 m_identifierToFrame.remove(iterator->value);
792 m_frameToIdentifier.remove(iterator);
796 Frame* InspectorPageAgent::mainFrame()
798 // FIXME: This should return a Frame&
799 return &m_page->mainFrame();
802 Frame* InspectorPageAgent::frameForId(const String& frameId)
804 return frameId.isEmpty() ? nullptr : m_identifierToFrame.get(frameId);
807 String InspectorPageAgent::frameId(Frame* frame)
811 String identifier = m_frameToIdentifier.get(frame);
812 if (identifier.isNull()) {
813 identifier = IdentifiersFactory::createIdentifier();
814 m_frameToIdentifier.set(frame, identifier);
815 m_identifierToFrame.set(identifier, frame);
820 bool InspectorPageAgent::hasIdForFrame(Frame* frame) const
822 return frame && m_frameToIdentifier.contains(frame);
825 String InspectorPageAgent::loaderId(DocumentLoader* loader)
829 String identifier = m_loaderToIdentifier.get(loader);
830 if (identifier.isNull()) {
831 identifier = IdentifiersFactory::createIdentifier();
832 m_loaderToIdentifier.set(loader, identifier);
837 Frame* InspectorPageAgent::findFrameWithSecurityOrigin(const String& originRawString)
839 for (Frame* frame = &m_page->mainFrame(); frame; frame = frame->tree().traverseNext()) {
840 RefPtr<SecurityOrigin> documentOrigin = frame->document()->securityOrigin();
841 if (documentOrigin->toRawString() == originRawString)
847 Frame* InspectorPageAgent::assertFrame(ErrorString* errorString, const String& frameId)
849 Frame* frame = frameForId(frameId);
851 *errorString = "No frame for given id found";
856 DocumentLoader* InspectorPageAgent::assertDocumentLoader(ErrorString* errorString, Frame* frame)
858 FrameLoader& frameLoader = frame->loader();
859 DocumentLoader* documentLoader = frameLoader.documentLoader();
861 *errorString = "No documentLoader for given frame found";
862 return documentLoader;
865 void InspectorPageAgent::loaderDetachedFromFrame(DocumentLoader* loader)
867 HashMap<DocumentLoader*, String>::iterator iterator = m_loaderToIdentifier.find(loader);
868 if (iterator != m_loaderToIdentifier.end())
869 m_loaderToIdentifier.remove(iterator);
872 void InspectorPageAgent::frameStartedLoading(Frame& frame)
874 m_frontendDispatcher->frameStartedLoading(frameId(&frame));
877 void InspectorPageAgent::frameStoppedLoading(Frame& frame)
879 m_frontendDispatcher->frameStoppedLoading(frameId(&frame));
882 void InspectorPageAgent::frameScheduledNavigation(Frame& frame, double delay)
884 m_frontendDispatcher->frameScheduledNavigation(frameId(&frame), delay);
887 void InspectorPageAgent::frameClearedScheduledNavigation(Frame& frame)
889 m_frontendDispatcher->frameClearedScheduledNavigation(frameId(&frame));
892 void InspectorPageAgent::willRunJavaScriptDialog(const String& message)
894 m_frontendDispatcher->javascriptDialogOpening(message);
897 void InspectorPageAgent::didRunJavaScriptDialog()
899 m_frontendDispatcher->javascriptDialogClosed();
902 void InspectorPageAgent::didPaint(GraphicsContext* context, const LayoutRect& rect)
904 if (!m_enabled || m_client->overridesShowPaintRects() || !m_showPaintRects)
907 static int colorSelector = 0;
908 const Color colors[] = {
909 Color(0xFF, 0, 0, 0x3F),
910 Color(0xFF, 0, 0xFF, 0x3F),
911 Color(0, 0, 0xFF, 0x3F),
914 LayoutRect inflatedRect(rect);
915 inflatedRect.inflate(-1);
916 m_overlay->drawOutline(context, inflatedRect, colors[colorSelector++ % WTF_ARRAY_LENGTH(colors)]);
919 void InspectorPageAgent::didLayout()
921 bool isFirstLayout = m_isFirstLayoutAfterOnLoad;
923 m_isFirstLayoutAfterOnLoad = false;
931 void InspectorPageAgent::didScroll()
937 void InspectorPageAgent::didRecalculateStyle()
943 void InspectorPageAgent::scriptsEnabled(bool isEnabled)
945 if (m_ignoreScriptsEnabledNotification)
948 m_frontendDispatcher->scriptsEnabled(isEnabled);
951 PassRefPtr<Inspector::TypeBuilder::Page::Frame> InspectorPageAgent::buildObjectForFrame(Frame* frame)
953 RefPtr<Inspector::TypeBuilder::Page::Frame> frameObject = Inspector::TypeBuilder::Page::Frame::create()
954 .setId(frameId(frame))
955 .setLoaderId(loaderId(frame->loader().documentLoader()))
956 .setUrl(frame->document()->url().string())
957 .setMimeType(frame->loader().documentLoader()->responseMIMEType())
958 .setSecurityOrigin(frame->document()->securityOrigin()->toRawString());
959 if (frame->tree().parent())
960 frameObject->setParentId(frameId(frame->tree().parent()));
961 if (frame->ownerElement()) {
962 String name = frame->ownerElement()->getNameAttribute();
964 name = frame->ownerElement()->getAttribute(HTMLNames::idAttr);
965 frameObject->setName(name);
971 PassRefPtr<Inspector::TypeBuilder::Page::FrameResourceTree> InspectorPageAgent::buildObjectForFrameTree(Frame* frame)
973 RefPtr<Inspector::TypeBuilder::Page::Frame> frameObject = buildObjectForFrame(frame);
974 RefPtr<Inspector::TypeBuilder::Array<Inspector::TypeBuilder::Page::FrameResourceTree::Resources>> subresources = Inspector::TypeBuilder::Array<Inspector::TypeBuilder::Page::FrameResourceTree::Resources>::create();
975 RefPtr<Inspector::TypeBuilder::Page::FrameResourceTree> result = Inspector::TypeBuilder::Page::FrameResourceTree::create()
976 .setFrame(frameObject)
977 .setResources(subresources);
979 Vector<CachedResource*> allResources = cachedResourcesForFrame(frame);
980 for (Vector<CachedResource*>::const_iterator it = allResources.begin(); it != allResources.end(); ++it) {
981 CachedResource* cachedResource = *it;
983 RefPtr<Inspector::TypeBuilder::Page::FrameResourceTree::Resources> resourceObject = Inspector::TypeBuilder::Page::FrameResourceTree::Resources::create()
984 .setUrl(cachedResource->url())
985 .setType(cachedResourceTypeJson(*cachedResource))
986 .setMimeType(cachedResource->response().mimeType());
987 if (cachedResource->wasCanceled())
988 resourceObject->setCanceled(true);
989 else if (cachedResource->status() == CachedResource::LoadError)
990 resourceObject->setFailed(true);
991 String sourceMappingURL = InspectorPageAgent::sourceMapURLForResource(cachedResource);
992 if (!sourceMappingURL.isEmpty())
993 resourceObject->setSourceMapURL(sourceMappingURL);
994 subresources->addItem(resourceObject);
997 RefPtr<Inspector::TypeBuilder::Array<Inspector::TypeBuilder::Page::FrameResourceTree>> childrenArray;
998 for (Frame* child = frame->tree().firstChild(); child; child = child->tree().nextSibling()) {
999 if (!childrenArray) {
1000 childrenArray = Inspector::TypeBuilder::Array<Inspector::TypeBuilder::Page::FrameResourceTree>::create();
1001 result->setChildFrames(childrenArray);
1003 childrenArray->addItem(buildObjectForFrameTree(child));
1008 #if ENABLE(TOUCH_EVENTS)
1009 void InspectorPageAgent::updateTouchEventEmulationInPage(bool enabled)
1012 mainFrame()->settings().setTouchEventEmulationEnabled(enabled);
1016 void InspectorPageAgent::setTouchEmulationEnabled(ErrorString* error, bool enabled)
1018 #if ENABLE(TOUCH_EVENTS)
1019 UNUSED_PARAM(error);
1020 updateTouchEventEmulationInPage(enabled);
1022 *error = "Touch events emulation not supported";
1023 UNUSED_PARAM(enabled);
1027 void InspectorPageAgent::setEmulatedMedia(ErrorString*, const String& media)
1029 if (media == m_emulatedMedia)
1032 m_emulatedMedia = media;
1033 Document* document = m_page->mainFrame().document();
1035 document->styleResolverChanged(RecalcStyleImmediately);
1036 document->updateLayout();
1040 void InspectorPageAgent::applyEmulatedMedia(String* media)
1042 if (!m_emulatedMedia.isEmpty())
1043 *media = m_emulatedMedia;
1046 void InspectorPageAgent::getCompositingBordersVisible(ErrorString*, bool* outParam)
1048 *outParam = m_page->settings().showDebugBorders() || m_page->settings().showRepaintCounter();
1051 void InspectorPageAgent::setCompositingBordersVisible(ErrorString*, bool visible)
1053 m_page->settings().setShowDebugBorders(visible);
1054 m_page->settings().setShowRepaintCounter(visible);
1057 void InspectorPageAgent::snapshotNode(ErrorString* errorString, int nodeId, String* outDataURL)
1059 Frame* frame = mainFrame();
1062 InspectorDOMAgent* domAgent = m_instrumentingAgents->inspectorDOMAgent();
1064 Node* node = domAgent->assertNode(errorString, nodeId);
1068 std::unique_ptr<ImageBuffer> snapshot = WebCore::snapshotNode(*frame, *node);
1070 *errorString = ASCIILiteral("Could not capture snapshot");
1074 *outDataURL = snapshot->toDataURL(ASCIILiteral("image/png"));
1077 void InspectorPageAgent::snapshotRect(ErrorString* errorString, int x, int y, int width, int height, const String& coordinateSystem, String* outDataURL)
1079 Frame* frame = mainFrame();
1082 SnapshotOptions options = SnapshotOptionsNone;
1083 if (coordinateSystem == "Viewport")
1084 options |= SnapshotOptionsInViewCoordinates;
1086 IntRect rectangle(x, y, width, height);
1087 std::unique_ptr<ImageBuffer> snapshot = snapshotFrameRect(*frame, rectangle, options);
1090 *errorString = ASCIILiteral("Could not capture snapshot");
1094 *outDataURL = snapshot->toDataURL(ASCIILiteral("image/png"));
1097 void InspectorPageAgent::handleJavaScriptDialog(ErrorString* errorString, bool accept, const String* promptText)
1099 if (!m_client->handleJavaScriptDialog(accept, promptText))
1100 *errorString = "Could not handle JavaScript dialog";
1103 void InspectorPageAgent::archive(ErrorString* errorString, String* data)
1105 Frame* frame = mainFrame();
1107 *errorString = "No main frame";
1111 #if ENABLE(WEB_ARCHIVE) && USE(CF)
1112 RefPtr<LegacyWebArchive> archive = LegacyWebArchive::create(frame);
1114 *errorString = "Could not create web archive for main frame";
1118 RetainPtr<CFDataRef> buffer = archive->rawDataRepresentation();
1119 *data = base64Encode(CFDataGetBytePtr(buffer.get()), CFDataGetLength(buffer.get()));
1122 *errorString = "No support for creating archives";
1126 } // namespace WebCore
1128 #endif // ENABLE(INSPECTOR)