Web Inspector: Remove recompileAllJSFunctions timer in ScriptDebugServer
[WebKit-https.git] / Source / WebCore / inspector / InspectorPageAgent.cpp
1 /*
2  * Copyright (C) 2011 Google Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions are
6  * met:
7  *
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
13  * distribution.
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.
17  *
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.
29  */
30
31 #include "config.h"
32
33 #if ENABLE(INSPECTOR)
34
35 #include "InspectorPageAgent.h"
36
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"
44 #include "Cookie.h"
45 #include "CookieJar.h"
46 #include "DOMImplementation.h"
47 #include "DOMPatchSupport.h"
48 #include "DOMWrapperWorld.h"
49 #include "Document.h"
50 #include "DocumentLoader.h"
51 #include "Frame.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"
67 #include "Page.h"
68 #include "RegularExpression.h"
69 #include "ResourceBuffer.h"
70 #include "ScriptController.h"
71 #include "SecurityOrigin.h"
72 #include "Settings.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>
83
84 #if ENABLE(WEB_ARCHIVE) && USE(CF)
85 #include "LegacyWebArchive.h"
86 #endif
87
88 using namespace Inspector;
89
90 namespace WebCore {
91
92 static bool decodeBuffer(const char* buffer, unsigned size, const String& textEncodingName, String* result)
93 {
94     if (buffer) {
95         TextEncoding encoding(textEncodingName);
96         if (!encoding.isValid())
97             encoding = WindowsLatin1Encoding();
98         *result = encoding.decode(buffer, size);
99         return true;
100     }
101     return false;
102 }
103
104 static bool prepareCachedResourceBuffer(CachedResource* cachedResource, bool* hasZeroSize)
105 {
106     *hasZeroSize = false;
107     if (!cachedResource)
108         return false;
109
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()) {
112         *hasZeroSize = true;
113         return true;
114     }
115
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
119         // empty String.
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
122         // inspector?
123         if (!cachedResource->makePurgeable(false))
124             return false;
125     }
126
127     return true;
128 }
129
130 static bool hasTextContent(CachedResource* cachedResource)
131 {
132     InspectorPageAgent::ResourceType type = InspectorPageAgent::cachedResourceType(*cachedResource);
133     return type == InspectorPageAgent::DocumentResource || type == InspectorPageAgent::StylesheetResource || type == InspectorPageAgent::ScriptResource || type == InspectorPageAgent::XHRResource;
134 }
135
136 static PassRefPtr<TextResourceDecoder> createXHRTextDecoder(const String& mimeType, const String& textEncodingName)
137 {
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");
146     else
147         decoder = TextResourceDecoder::create("text/plain", "UTF-8");
148     return decoder;
149 }
150
151 bool InspectorPageAgent::cachedResourceContent(CachedResource* cachedResource, String* result, bool* base64Encoded)
152 {
153     bool hasZeroSize;
154     bool prepared = prepareCachedResourceBuffer(cachedResource, &hasZeroSize);
155     if (!prepared)
156         return false;
157
158     *base64Encoded = !hasTextContent(cachedResource);
159     if (*base64Encoded) {
160         RefPtr<SharedBuffer> buffer = hasZeroSize ? SharedBuffer::create() : cachedResource->resourceBuffer()->sharedBuffer();
161
162         if (!buffer)
163             return false;
164
165         *result = base64Encode(buffer->data(), buffer->size());
166         return true;
167     }
168
169     if (hasZeroSize) {
170         *result = "";
171         return true;
172     }
173
174     if (cachedResource) {
175         switch (cachedResource->type()) {
176         case CachedResource::CSSStyleSheet:
177             *result = static_cast<CachedCSSStyleSheet*>(cachedResource)->sheetText(false);
178             return true;
179         case CachedResource::Script:
180             *result = static_cast<CachedScript*>(cachedResource)->script();
181             return true;
182         case CachedResource::RawResource: {
183             ResourceBuffer* buffer = cachedResource->resourceBuffer();
184             if (!buffer)
185                 return false;
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.
188             if (!decoder)
189                 return false;
190             String content = decoder->decode(buffer->data(), buffer->size());
191             *result = content + decoder->flush();
192             return true;
193         }
194         default:
195             ResourceBuffer* buffer = cachedResource->resourceBuffer();
196             return decodeBuffer(buffer ? buffer->data() : nullptr, buffer ? buffer->size() : 0, cachedResource->encoding(), result);
197         }
198     }
199     return false;
200 }
201
202 bool InspectorPageAgent::mainResourceContent(Frame* frame, bool withBase64Encode, String* result)
203 {
204     RefPtr<ResourceBuffer> buffer = frame->loader().documentLoader()->mainResourceData();
205     if (!buffer)
206         return false;
207     String textEncodingName = frame->document()->inputEncoding();
208
209     return InspectorPageAgent::dataContent(buffer->data(), buffer->size(), textEncodingName, withBase64Encode, result);
210 }
211
212 // static
213 bool InspectorPageAgent::sharedBufferContent(PassRefPtr<SharedBuffer> buffer, const String& textEncodingName, bool withBase64Encode, String* result)
214 {
215     return dataContent(buffer ? buffer->data() : nullptr, buffer ? buffer->size() : 0, textEncodingName, withBase64Encode, result);
216 }
217
218 bool InspectorPageAgent::dataContent(const char* data, unsigned size, const String& textEncodingName, bool withBase64Encode, String* result)
219 {
220     if (withBase64Encode) {
221         *result = base64Encode(data, size);
222         return true;
223     }
224
225     return decodeBuffer(data, size, textEncodingName, result);
226 }
227
228 // static
229 void InspectorPageAgent::resourceContent(ErrorString* errorString, Frame* frame, const URL& url, String* result, bool* base64Encoded)
230 {
231     DocumentLoader* loader = assertDocumentLoader(errorString, frame);
232     if (!loader)
233         return;
234
235     RefPtr<SharedBuffer> buffer;
236     bool success = false;
237     if (equalIgnoringFragmentIdentifier(url, loader->url())) {
238         *base64Encoded = false;
239         success = mainResourceContent(frame, *base64Encoded, result);
240     }
241
242     if (!success)
243         success = cachedResourceContent(cachedResource(frame, url), result, base64Encoded);
244
245     if (!success)
246         *errorString = "No resource with given URL found";
247 }
248
249 //static
250 String InspectorPageAgent::sourceMapURLForResource(CachedResource* cachedResource)
251 {
252     DEFINE_STATIC_LOCAL(String, sourceMapHTTPHeader, (ASCIILiteral("SourceMap")));
253     DEFINE_STATIC_LOCAL(String, sourceMapHTTPHeaderDeprecated, (ASCIILiteral("X-SourceMap")));
254
255     if (!cachedResource)
256         return String();
257
258     // Scripts are handled in a separate path.
259     if (cachedResource->type() != CachedResource::CSSStyleSheet)
260         return String();
261
262     String sourceMapHeader = cachedResource->response().httpHeaderField(sourceMapHTTPHeader);
263     if (!sourceMapHeader.isEmpty())
264         return sourceMapHeader;
265
266     sourceMapHeader = cachedResource->response().httpHeaderField(sourceMapHTTPHeaderDeprecated);
267     if (!sourceMapHeader.isEmpty())
268         return sourceMapHeader;
269
270     String content;
271     bool base64Encoded;
272     if (InspectorPageAgent::cachedResourceContent(cachedResource, &content, &base64Encoded) && !base64Encoded)
273         return ContentSearchUtils::findStylesheetSourceMapURL(content);
274
275     return String();
276 }
277
278 CachedResource* InspectorPageAgent::cachedResource(Frame* frame, const URL& url)
279 {
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());
285 #endif
286         cachedResource = memoryCache()->resourceForRequest(request);
287     }
288
289     return cachedResource;
290 }
291
292 Inspector::TypeBuilder::Page::ResourceType::Enum InspectorPageAgent::resourceTypeJson(InspectorPageAgent::ResourceType resourceType)
293 {
294     switch (resourceType) {
295     case DocumentResource:
296         return Inspector::TypeBuilder::Page::ResourceType::Document;
297     case ImageResource:
298         return Inspector::TypeBuilder::Page::ResourceType::Image;
299     case FontResource:
300         return Inspector::TypeBuilder::Page::ResourceType::Font;
301     case StylesheetResource:
302         return Inspector::TypeBuilder::Page::ResourceType::Stylesheet;
303     case ScriptResource:
304         return Inspector::TypeBuilder::Page::ResourceType::Script;
305     case XHRResource:
306         return Inspector::TypeBuilder::Page::ResourceType::XHR;
307     case WebSocketResource:
308         return Inspector::TypeBuilder::Page::ResourceType::WebSocket;
309     case OtherResource:
310         return Inspector::TypeBuilder::Page::ResourceType::Other;
311     }
312     return Inspector::TypeBuilder::Page::ResourceType::Other;
313 }
314
315 InspectorPageAgent::ResourceType InspectorPageAgent::cachedResourceType(const CachedResource& cachedResource)
316 {
317     switch (cachedResource.type()) {
318     case CachedResource::ImageResource:
319         return InspectorPageAgent::ImageResource;
320     case CachedResource::FontResource:
321         return InspectorPageAgent::FontResource;
322     case CachedResource::CSSStyleSheet:
323         // Fall through.
324 #if ENABLE(XSLT)
325     case CachedResource::XSLStyleSheet:
326 #endif
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;
334     default:
335         break;
336     }
337     return InspectorPageAgent::OtherResource;
338 }
339
340 Inspector::TypeBuilder::Page::ResourceType::Enum InspectorPageAgent::cachedResourceTypeJson(const CachedResource& cachedResource)
341 {
342     return resourceTypeJson(cachedResourceType(cachedResource));
343 }
344
345 InspectorPageAgent::InspectorPageAgent(InstrumentingAgents* instrumentingAgents, Page* page, InspectorClient* client, InspectorOverlay* overlay)
346     : InspectorAgentBase(ASCIILiteral("Page"), instrumentingAgents)
347     , m_page(page)
348     , m_client(client)
349     , m_overlay(overlay)
350     , m_lastScriptIdentifier(0)
351     , m_enabled(false)
352     , m_isFirstLayoutAfterOnLoad(false)
353     , m_originalScriptExecutionDisabled(false)
354     , m_ignoreScriptsEnabledNotification(false)
355     , m_showPaintRects(false)
356 {
357 }
358
359 void InspectorPageAgent::didCreateFrontendAndBackend(Inspector::InspectorFrontendChannel* frontendChannel, InspectorBackendDispatcher* backendDispatcher)
360 {
361     m_frontendDispatcher = std::make_unique<InspectorPageFrontendDispatcher>(frontendChannel);
362     m_backendDispatcher = InspectorPageBackendDispatcher::create(backendDispatcher, this);
363 }
364
365 void InspectorPageAgent::willDestroyFrontendAndBackend(InspectorDisconnectReason)
366 {
367     m_frontendDispatcher = nullptr;
368     m_backendDispatcher.clear();
369
370     ErrorString error;
371     disable(&error);
372 #if ENABLE(TOUCH_EVENTS)
373     updateTouchEventEmulationInPage(false);
374 #endif
375 }
376
377 void InspectorPageAgent::enable(ErrorString*)
378 {
379     m_enabled = true;
380     m_instrumentingAgents->setInspectorPageAgent(this);
381
382     if (Frame* frame = mainFrame())
383         m_originalScriptExecutionDisabled = !frame->settings().isScriptEnabled();
384 }
385
386 void InspectorPageAgent::disable(ErrorString*)
387 {
388     m_enabled = false;
389     m_scriptsToEvaluateOnLoad.clear();
390     m_instrumentingAgents->setInspectorPageAgent(nullptr);
391
392     setScriptExecutionDisabled(nullptr, m_originalScriptExecutionDisabled);
393     setShowPaintRects(nullptr, false);
394     setShowDebugBorders(nullptr, false);
395     setShowFPSCounter(nullptr, false);
396     setEmulatedMedia(nullptr, "");
397     setContinuousPaintingEnabled(nullptr, false);
398 }
399
400 void InspectorPageAgent::addScriptToEvaluateOnLoad(ErrorString*, const String& source, String* identifier)
401 {
402     if (!m_scriptsToEvaluateOnLoad)
403         m_scriptsToEvaluateOnLoad = InspectorObject::create();
404
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.
407     do {
408         *identifier = String::number(++m_lastScriptIdentifier);
409     } while (m_scriptsToEvaluateOnLoad->find(*identifier) != m_scriptsToEvaluateOnLoad->end());
410
411     m_scriptsToEvaluateOnLoad->setString(*identifier, source);
412 }
413
414 void InspectorPageAgent::removeScriptToEvaluateOnLoad(ErrorString* error, const String& identifier)
415 {
416     if (!m_scriptsToEvaluateOnLoad || m_scriptsToEvaluateOnLoad->find(identifier) == m_scriptsToEvaluateOnLoad->end()) {
417         *error = "Script not found";
418         return;
419     }
420
421     m_scriptsToEvaluateOnLoad->remove(identifier);
422 }
423
424 void InspectorPageAgent::reload(ErrorString*, const bool* const optionalIgnoreCache, const String* optionalScriptToEvaluateOnLoad)
425 {
426     m_pendingScriptToEvaluateOnLoadOnce = optionalScriptToEvaluateOnLoad ? *optionalScriptToEvaluateOnLoad : "";
427     m_page->mainFrame().loader().reload(optionalIgnoreCache ? *optionalIgnoreCache : false);
428 }
429
430 void InspectorPageAgent::navigate(ErrorString*, const String& url)
431 {
432     UserGestureIndicator indicator(DefinitelyProcessingUserGesture);
433     Frame& frame = m_page->mainFrame();
434     frame.loader().changeLocation(frame.document()->securityOrigin(), frame.document()->completeURL(url), "", false, false);
435 }
436
437 static PassRefPtr<Inspector::TypeBuilder::Page::Cookie> buildObjectForCookie(const Cookie& cookie)
438 {
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)
449         .release();
450 }
451
452 static PassRefPtr<Inspector::TypeBuilder::Array<Inspector::TypeBuilder::Page::Cookie>> buildArrayForCookies(ListHashSet<Cookie>& cookiesList)
453 {
454     RefPtr<Inspector::TypeBuilder::Array<Inspector::TypeBuilder::Page::Cookie>> cookies = Inspector::TypeBuilder::Array<Inspector::TypeBuilder::Page::Cookie>::create();
455
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));
460
461     return cookies;
462 }
463
464 static Vector<CachedResource*> cachedResourcesForFrame(Frame* frame)
465 {
466     Vector<CachedResource*> result;
467
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();
472
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())
479                 continue;
480             break;
481         default:
482             // All other CachedResource types download immediately.
483             break;
484         }
485
486         result.append(cachedResource);
487     }
488
489     return result;
490 }
491
492 static Vector<URL> allResourcesURLsForFrame(Frame* frame)
493 {
494     Vector<URL> result;
495
496     result.append(frame->loader().documentLoader()->url());
497
498     Vector<CachedResource*> allResources = cachedResourcesForFrame(frame);
499     for (Vector<CachedResource*>::const_iterator it = allResources.begin(); it != allResources.end(); ++it)
500         result.append((*it)->url());
501
502     return result;
503 }
504
505 void InspectorPageAgent::getCookies(ErrorString*, RefPtr<Inspector::TypeBuilder::Array<Inspector::TypeBuilder::Page::Cookie>>& cookies)
506 {
507     // If we can get raw cookies.
508     ListHashSet<Cookie> rawCookiesList;
509
510     // If we can't get raw cookies - fall back to String representation
511     StringBuilder stringCookiesList;
512
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;
517
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.
526                 //
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));
530             } else {
531                 int cookiesSize = docCookiesList.size();
532                 for (int i = 0; i < cookiesSize; i++) {
533                     if (!rawCookiesList.contains(docCookiesList[i]))
534                         rawCookiesList.add(docCookiesList[i]);
535                 }
536             }
537         }
538     }
539
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);
543     else
544         cookies = Inspector::TypeBuilder::Array<TypeBuilder::Page::Cookie>::create();
545 }
546
547 void InspectorPageAgent::deleteCookie(ErrorString*, const String& cookieName, const String& url)
548 {
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);
552 }
553
554 void InspectorPageAgent::getResourceTree(ErrorString*, RefPtr<Inspector::TypeBuilder::Page::FrameResourceTree>& object)
555 {
556     object = buildObjectForFrameTree(&m_page->mainFrame());
557 }
558
559 void InspectorPageAgent::getResourceContent(ErrorString* errorString, const String& frameId, const String& url, String* content, bool* base64Encoded)
560 {
561     Frame* frame = assertFrame(errorString, frameId);
562     if (!frame)
563         return;
564
565     resourceContent(errorString, frame, URL(ParsedURLString, url), content, base64Encoded);
566 }
567
568 static bool textContentForCachedResource(CachedResource* cachedResource, String* result)
569 {
570     if (hasTextContent(cachedResource)) {
571         String content;
572         bool base64Encoded;
573         if (InspectorPageAgent::cachedResourceContent(cachedResource, result, &base64Encoded)) {
574             ASSERT(!base64Encoded);
575             return true;
576         }
577     }
578     return false;
579 }
580
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)
582 {
583     results = Inspector::TypeBuilder::Array<Inspector::TypeBuilder::GenericTypes::SearchMatch>::create();
584
585     bool isRegex = optionalIsRegex ? *optionalIsRegex : false;
586     bool caseSensitive = optionalCaseSensitive ? *optionalCaseSensitive : false;
587
588     Frame* frame = frameForId(frameId);
589     if (!frame)
590         return;
591
592     DocumentLoader* loader = frame->loader().documentLoader();
593     if (!loader)
594         return;
595
596     URL kurl(ParsedURLString, url);
597
598     String content;
599     bool success = false;
600     if (equalIgnoringFragmentIdentifier(kurl, loader->url()))
601         success = mainResourceContent(frame, false, &content);
602
603     if (!success) {
604         CachedResource* resource = cachedResource(frame, kurl);
605         if (resource)
606             success = textContentForCachedResource(resource, &content);
607     }
608
609     if (!success)
610         return;
611
612     results = ContentSearchUtils::searchInTextByLines(content, query, caseSensitive, isRegex);
613 }
614
615 static PassRefPtr<Inspector::TypeBuilder::Page::SearchResult> buildObjectForSearchResult(const String& frameId, const String& url, int matchesCount)
616 {
617     return Inspector::TypeBuilder::Page::SearchResult::create()
618         .setUrl(url)
619         .setFrameId(frameId)
620         .setMatchesCount(matchesCount)
621         .release();
622 }
623
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)
625 {
626     RefPtr<Inspector::TypeBuilder::Array<Inspector::TypeBuilder::Page::SearchResult>> searchResults = Inspector::TypeBuilder::Array<Inspector::TypeBuilder::Page::SearchResult>::create();
627
628     bool isRegex = optionalIsRegex ? *optionalIsRegex : false;
629     bool caseSensitive = optionalCaseSensitive ? *optionalCaseSensitive : false;
630     RegularExpression regex = ContentSearchUtils::createSearchRegex(text, caseSensitive, isRegex);
631
632     for (Frame* frame = &m_page->mainFrame(); frame; frame = frame->tree().traverseNext(&m_page->mainFrame())) {
633         String content;
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);
639                 if (matchesCount)
640                     searchResults->addItem(buildObjectForSearchResult(frameId(frame), cachedResource->url(), matchesCount));
641             }
642         }
643         if (mainResourceContent(frame, false, &content)) {
644             int matchesCount = ContentSearchUtils::countRegularExpressionMatches(regex, content);
645             if (matchesCount)
646                 searchResults->addItem(buildObjectForSearchResult(frameId(frame), frame->document()->url(), matchesCount));
647         }
648     }
649
650     results = searchResults;
651 }
652
653 void InspectorPageAgent::setDocumentContent(ErrorString* errorString, const String& frameId, const String& html)
654 {
655     Frame* frame = assertFrame(errorString, frameId);
656     if (!frame)
657         return;
658
659     Document* document = frame->document();
660     if (!document) {
661         *errorString = "No Document instance to set HTML for";
662         return;
663     }
664     DOMPatchSupport::patchDocument(document, html);
665 }
666
667 void InspectorPageAgent::setShowPaintRects(ErrorString*, bool show)
668 {
669     m_showPaintRects = show;
670     m_client->setShowPaintRects(show);
671
672     if (!show && mainFrame() && mainFrame()->view())
673         mainFrame()->view()->invalidate();
674 }
675
676 void InspectorPageAgent::canShowDebugBorders(ErrorString*, bool* outParam)
677 {
678     *outParam = m_client->canShowDebugBorders();
679 }
680
681 void InspectorPageAgent::setShowDebugBorders(ErrorString*, bool show)
682 {
683     m_client->setShowDebugBorders(show);
684     if (mainFrame() && mainFrame()->view())
685         mainFrame()->view()->invalidate();
686 }
687
688 void InspectorPageAgent::canShowFPSCounter(ErrorString*, bool* outParam)
689 {
690     *outParam = m_client->canShowFPSCounter();
691 }
692
693 void InspectorPageAgent::setShowFPSCounter(ErrorString*, bool show)
694 {
695     m_client->setShowFPSCounter(show);
696
697     if (mainFrame() && mainFrame()->view())
698         mainFrame()->view()->invalidate();
699 }
700
701 void InspectorPageAgent::canContinuouslyPaint(ErrorString*, bool* outParam)
702 {
703     *outParam = m_client->canContinuouslyPaint();
704 }
705
706 void InspectorPageAgent::setContinuousPaintingEnabled(ErrorString*, bool enabled)
707 {
708     m_client->setContinuousPaintingEnabled(enabled);
709
710     if (!enabled && mainFrame() && mainFrame()->view())
711         mainFrame()->view()->invalidate();
712 }
713
714 void InspectorPageAgent::getScriptExecutionStatus(ErrorString*, InspectorPageBackendDispatcherHandler::Result::Enum* status)
715 {
716     bool disabledByScriptController = false;
717     bool disabledInSettings = false;
718     Frame* frame = mainFrame();
719     if (frame) {
720         disabledByScriptController = !frame->script().canExecuteScripts(NotAboutToExecuteScript);
721         disabledInSettings = !frame->settings().isScriptEnabled();
722     }
723
724     if (!disabledByScriptController) {
725         *status = InspectorPageBackendDispatcherHandler::Result::Allowed;
726         return;
727     }
728
729     if (disabledInSettings)
730         *status = InspectorPageBackendDispatcherHandler::Result::Disabled;
731     else
732         *status = InspectorPageBackendDispatcherHandler::Result::Forbidden;
733 }
734
735 void InspectorPageAgent::setScriptExecutionDisabled(ErrorString*, bool value)
736 {
737     if (!mainFrame())
738         return;
739
740     m_ignoreScriptsEnabledNotification = true;
741     mainFrame()->settings().setScriptEnabled(!value);
742     m_ignoreScriptsEnabledNotification = false;
743 }
744
745 void InspectorPageAgent::didClearWindowObjectInWorld(Frame* frame, DOMWrapperWorld& world)
746 {
747     if (&world != &mainThreadNormalWorld())
748         return;
749
750     if (!m_frontendDispatcher)
751         return;
752
753     if (m_scriptsToEvaluateOnLoad) {
754         InspectorObject::const_iterator end = m_scriptsToEvaluateOnLoad->end();
755         for (InspectorObject::const_iterator it = m_scriptsToEvaluateOnLoad->begin(); it != end; ++it) {
756             String scriptText;
757             if (it->value->asString(&scriptText))
758                 frame->script().executeScript(scriptText);
759         }
760     }
761
762     if (!m_scriptToEvaluateOnLoadOnce.isEmpty())
763         frame->script().executeScript(m_scriptToEvaluateOnLoadOnce);
764 }
765
766 void InspectorPageAgent::domContentEventFired()
767 {
768     m_isFirstLayoutAfterOnLoad = true;
769     m_frontendDispatcher->domContentEventFired(currentTime());
770 }
771
772 void InspectorPageAgent::loadEventFired()
773 {
774     m_frontendDispatcher->loadEventFired(currentTime());
775 }
776
777 void InspectorPageAgent::frameNavigated(DocumentLoader* loader)
778 {
779     if (loader->frame()->isMainFrame()) {
780         m_scriptToEvaluateOnLoadOnce = m_pendingScriptToEvaluateOnLoadOnce;
781         m_pendingScriptToEvaluateOnLoadOnce = String();
782     }
783     m_frontendDispatcher->frameNavigated(buildObjectForFrame(loader->frame()));
784 }
785
786 void InspectorPageAgent::frameDetached(Frame* frame)
787 {
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);
793     }
794 }
795
796 Frame* InspectorPageAgent::mainFrame()
797 {
798     // FIXME: This should return a Frame&
799     return &m_page->mainFrame();
800 }
801
802 Frame* InspectorPageAgent::frameForId(const String& frameId)
803 {
804     return frameId.isEmpty() ? nullptr : m_identifierToFrame.get(frameId);
805 }
806
807 String InspectorPageAgent::frameId(Frame* frame)
808 {
809     if (!frame)
810         return "";
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);
816     }
817     return identifier;
818 }
819
820 bool InspectorPageAgent::hasIdForFrame(Frame* frame) const
821 {
822     return frame && m_frameToIdentifier.contains(frame);
823 }
824
825 String InspectorPageAgent::loaderId(DocumentLoader* loader)
826 {
827     if (!loader)
828         return "";
829     String identifier = m_loaderToIdentifier.get(loader);
830     if (identifier.isNull()) {
831         identifier = IdentifiersFactory::createIdentifier();
832         m_loaderToIdentifier.set(loader, identifier);
833     }
834     return identifier;
835 }
836
837 Frame* InspectorPageAgent::findFrameWithSecurityOrigin(const String& originRawString)
838 {
839     for (Frame* frame = &m_page->mainFrame(); frame; frame = frame->tree().traverseNext()) {
840         RefPtr<SecurityOrigin> documentOrigin = frame->document()->securityOrigin();
841         if (documentOrigin->toRawString() == originRawString)
842             return frame;
843     }
844     return nullptr;
845 }
846
847 Frame* InspectorPageAgent::assertFrame(ErrorString* errorString, const String& frameId)
848 {
849     Frame* frame = frameForId(frameId);
850     if (!frame)
851         *errorString = "No frame for given id found";
852     return frame;
853 }
854
855 // static
856 DocumentLoader* InspectorPageAgent::assertDocumentLoader(ErrorString* errorString, Frame* frame)
857 {
858     FrameLoader& frameLoader = frame->loader();
859     DocumentLoader* documentLoader = frameLoader.documentLoader();
860     if (!documentLoader)
861         *errorString = "No documentLoader for given frame found";
862     return documentLoader;
863 }
864
865 void InspectorPageAgent::loaderDetachedFromFrame(DocumentLoader* loader)
866 {
867     HashMap<DocumentLoader*, String>::iterator iterator = m_loaderToIdentifier.find(loader);
868     if (iterator != m_loaderToIdentifier.end())
869         m_loaderToIdentifier.remove(iterator);
870 }
871
872 void InspectorPageAgent::frameStartedLoading(Frame& frame)
873 {
874     m_frontendDispatcher->frameStartedLoading(frameId(&frame));
875 }
876
877 void InspectorPageAgent::frameStoppedLoading(Frame& frame)
878 {
879     m_frontendDispatcher->frameStoppedLoading(frameId(&frame));
880 }
881
882 void InspectorPageAgent::frameScheduledNavigation(Frame& frame, double delay)
883 {
884     m_frontendDispatcher->frameScheduledNavigation(frameId(&frame), delay);
885 }
886
887 void InspectorPageAgent::frameClearedScheduledNavigation(Frame& frame)
888 {
889     m_frontendDispatcher->frameClearedScheduledNavigation(frameId(&frame));
890 }
891
892 void InspectorPageAgent::willRunJavaScriptDialog(const String& message)
893 {
894     m_frontendDispatcher->javascriptDialogOpening(message);
895 }
896
897 void InspectorPageAgent::didRunJavaScriptDialog()
898 {
899     m_frontendDispatcher->javascriptDialogClosed();
900 }
901
902 void InspectorPageAgent::didPaint(GraphicsContext* context, const LayoutRect& rect)
903 {
904     if (!m_enabled || m_client->overridesShowPaintRects() || !m_showPaintRects)
905         return;
906
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),
912     };
913
914     LayoutRect inflatedRect(rect);
915     inflatedRect.inflate(-1);
916     m_overlay->drawOutline(context, inflatedRect, colors[colorSelector++ % WTF_ARRAY_LENGTH(colors)]);
917 }
918
919 void InspectorPageAgent::didLayout()
920 {
921     bool isFirstLayout = m_isFirstLayoutAfterOnLoad;
922     if (isFirstLayout)
923         m_isFirstLayoutAfterOnLoad = false;
924
925     if (!m_enabled)
926         return;
927
928     m_overlay->update();
929 }
930
931 void InspectorPageAgent::didScroll()
932 {
933     if (m_enabled)
934         m_overlay->update();
935 }
936
937 void InspectorPageAgent::didRecalculateStyle()
938 {
939     if (m_enabled)
940         m_overlay->update();
941 }
942
943 void InspectorPageAgent::scriptsEnabled(bool isEnabled)
944 {
945     if (m_ignoreScriptsEnabledNotification)
946         return;
947
948     m_frontendDispatcher->scriptsEnabled(isEnabled);
949 }
950
951 PassRefPtr<Inspector::TypeBuilder::Page::Frame> InspectorPageAgent::buildObjectForFrame(Frame* frame)
952 {
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();
963         if (name.isEmpty())
964             name = frame->ownerElement()->getAttribute(HTMLNames::idAttr);
965         frameObject->setName(name);
966     }
967
968     return frameObject;
969 }
970
971 PassRefPtr<Inspector::TypeBuilder::Page::FrameResourceTree> InspectorPageAgent::buildObjectForFrameTree(Frame* frame)
972 {
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);
978
979     Vector<CachedResource*> allResources = cachedResourcesForFrame(frame);
980     for (Vector<CachedResource*>::const_iterator it = allResources.begin(); it != allResources.end(); ++it) {
981         CachedResource* cachedResource = *it;
982
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);
995     }
996
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);
1002         }
1003         childrenArray->addItem(buildObjectForFrameTree(child));
1004     }
1005     return result;
1006 }
1007
1008 #if ENABLE(TOUCH_EVENTS)
1009 void InspectorPageAgent::updateTouchEventEmulationInPage(bool enabled)
1010 {
1011     if (mainFrame())
1012         mainFrame()->settings().setTouchEventEmulationEnabled(enabled);
1013 }
1014 #endif
1015
1016 void InspectorPageAgent::setTouchEmulationEnabled(ErrorString* error, bool enabled)
1017 {
1018 #if ENABLE(TOUCH_EVENTS)
1019     UNUSED_PARAM(error);
1020     updateTouchEventEmulationInPage(enabled);
1021 #else
1022     *error = "Touch events emulation not supported";
1023     UNUSED_PARAM(enabled);
1024 #endif
1025 }
1026
1027 void InspectorPageAgent::setEmulatedMedia(ErrorString*, const String& media)
1028 {
1029     if (media == m_emulatedMedia)
1030         return;
1031
1032     m_emulatedMedia = media;
1033     Document* document = m_page->mainFrame().document();
1034     if (document) {
1035         document->styleResolverChanged(RecalcStyleImmediately);
1036         document->updateLayout();
1037     }
1038 }
1039
1040 void InspectorPageAgent::applyEmulatedMedia(String* media)
1041 {
1042     if (!m_emulatedMedia.isEmpty())
1043         *media = m_emulatedMedia;
1044 }
1045
1046 void InspectorPageAgent::getCompositingBordersVisible(ErrorString*, bool* outParam)
1047 {
1048     *outParam = m_page->settings().showDebugBorders() || m_page->settings().showRepaintCounter();
1049 }
1050
1051 void InspectorPageAgent::setCompositingBordersVisible(ErrorString*, bool visible)
1052 {
1053     m_page->settings().setShowDebugBorders(visible);
1054     m_page->settings().setShowRepaintCounter(visible);
1055 }
1056
1057 void InspectorPageAgent::snapshotNode(ErrorString* errorString, int nodeId, String* outDataURL)
1058 {
1059     Frame* frame = mainFrame();
1060     ASSERT(frame);
1061
1062     InspectorDOMAgent* domAgent = m_instrumentingAgents->inspectorDOMAgent();
1063     ASSERT(domAgent);
1064     Node* node = domAgent->assertNode(errorString, nodeId);
1065     if (!node)
1066         return;
1067
1068     std::unique_ptr<ImageBuffer> snapshot = WebCore::snapshotNode(*frame, *node);
1069     if (!snapshot) {
1070         *errorString = ASCIILiteral("Could not capture snapshot");
1071         return;
1072     }
1073
1074     *outDataURL = snapshot->toDataURL(ASCIILiteral("image/png"));
1075 }
1076
1077 void InspectorPageAgent::snapshotRect(ErrorString* errorString, int x, int y, int width, int height, const String& coordinateSystem, String* outDataURL)
1078 {
1079     Frame* frame = mainFrame();
1080     ASSERT(frame);
1081
1082     SnapshotOptions options = SnapshotOptionsNone;
1083     if (coordinateSystem == "Viewport")
1084         options |= SnapshotOptionsInViewCoordinates;
1085
1086     IntRect rectangle(x, y, width, height);
1087     std::unique_ptr<ImageBuffer> snapshot = snapshotFrameRect(*frame, rectangle, options);
1088
1089     if (!snapshot) {
1090         *errorString = ASCIILiteral("Could not capture snapshot");
1091         return;
1092     }
1093
1094     *outDataURL = snapshot->toDataURL(ASCIILiteral("image/png"));
1095 }
1096
1097 void InspectorPageAgent::handleJavaScriptDialog(ErrorString* errorString, bool accept, const String* promptText)
1098 {
1099     if (!m_client->handleJavaScriptDialog(accept, promptText))
1100         *errorString = "Could not handle JavaScript dialog";
1101 }
1102
1103 void InspectorPageAgent::archive(ErrorString* errorString, String* data)
1104 {
1105     Frame* frame = mainFrame();
1106     if (!frame) {
1107         *errorString = "No main frame";
1108         return;
1109     }
1110
1111 #if ENABLE(WEB_ARCHIVE) && USE(CF)
1112     RefPtr<LegacyWebArchive> archive = LegacyWebArchive::create(frame);
1113     if (!archive) {
1114         *errorString = "Could not create web archive for main frame";
1115         return;
1116     }
1117
1118     RetainPtr<CFDataRef> buffer = archive->rawDataRepresentation();
1119     *data = base64Encode(CFDataGetBytePtr(buffer.get()), CFDataGetLength(buffer.get()));
1120 #else
1121     UNUSED_PARAM(data);
1122     *errorString = "No support for creating archives";
1123 #endif
1124 }
1125
1126 } // namespace WebCore
1127
1128 #endif // ENABLE(INSPECTOR)