Web Inspector: timelines should not count time elapsed while paused in the debugger
[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 #include "InspectorPageAgent.h"
33
34 #if ENABLE(INSPECTOR)
35
36 #include "CachedCSSStyleSheet.h"
37 #include "CachedFont.h"
38 #include "CachedImage.h"
39 #include "CachedResource.h"
40 #include "CachedResourceLoader.h"
41 #include "CachedScript.h"
42 #include "Cookie.h"
43 #include "CookieJar.h"
44 #include "DOMImplementation.h"
45 #include "DOMPatchSupport.h"
46 #include "DOMWrapperWorld.h"
47 #include "Document.h"
48 #include "DocumentLoader.h"
49 #include "Frame.h"
50 #include "FrameLoader.h"
51 #include "FrameSnapshotting.h"
52 #include "FrameView.h"
53 #include "HTMLFrameOwnerElement.h"
54 #include "HTMLNames.h"
55 #include "ImageBuffer.h"
56 #include "InspectorClient.h"
57 #include "InspectorDOMAgent.h"
58 #include "InspectorInstrumentation.h"
59 #include "InspectorOverlay.h"
60 #include "InspectorTimelineAgent.h"
61 #include "InspectorWebFrontendDispatchers.h"
62 #include "InstrumentingAgents.h"
63 #include "MainFrame.h"
64 #include "MemoryCache.h"
65 #include "Page.h"
66 #include "ResourceBuffer.h"
67 #include "ScriptController.h"
68 #include "SecurityOrigin.h"
69 #include "Settings.h"
70 #include "TextEncoding.h"
71 #include "TextResourceDecoder.h"
72 #include "UserGestureIndicator.h"
73 #include <bindings/ScriptValue.h>
74 #include <inspector/ContentSearchUtilities.h>
75 #include <inspector/IdentifiersFactory.h>
76 #include <inspector/InspectorValues.h>
77 #include <wtf/ListHashSet.h>
78 #include <wtf/Vector.h>
79 #include <wtf/text/Base64.h>
80 #include <wtf/text/StringBuilder.h>
81 #include <yarr/RegularExpression.h>
82
83 #if ENABLE(WEB_ARCHIVE) && USE(CF)
84 #include "LegacyWebArchive.h"
85 #endif
86
87 using namespace Inspector;
88
89 namespace WebCore {
90
91 static bool decodeBuffer(const char* buffer, unsigned size, const String& textEncodingName, String* result)
92 {
93     if (buffer) {
94         TextEncoding encoding(textEncodingName);
95         if (!encoding.isValid())
96             encoding = WindowsLatin1Encoding();
97         *result = encoding.decode(buffer, size);
98         return true;
99     }
100     return false;
101 }
102
103 static bool prepareCachedResourceBuffer(CachedResource* cachedResource, bool* hasZeroSize)
104 {
105     *hasZeroSize = false;
106     if (!cachedResource)
107         return false;
108
109     // Zero-sized resources don't have data at all -- so fake the empty buffer, instead of indicating error by returning 0.
110     if (!cachedResource->encodedSize()) {
111         *hasZeroSize = true;
112         return true;
113     }
114
115     return true;
116 }
117
118 static bool hasTextContent(CachedResource* cachedResource)
119 {
120     InspectorPageAgent::ResourceType type = InspectorPageAgent::cachedResourceType(*cachedResource);
121     return type == InspectorPageAgent::DocumentResource || type == InspectorPageAgent::StylesheetResource || type == InspectorPageAgent::ScriptResource || type == InspectorPageAgent::XHRResource;
122 }
123
124 static PassRefPtr<TextResourceDecoder> createXHRTextDecoder(const String& mimeType, const String& textEncodingName)
125 {
126     RefPtr<TextResourceDecoder> decoder;
127     if (!textEncodingName.isEmpty())
128         decoder = TextResourceDecoder::create("text/plain", textEncodingName);
129     else if (DOMImplementation::isXMLMIMEType(mimeType.lower())) {
130         decoder = TextResourceDecoder::create("application/xml");
131         decoder->useLenientXMLDecoding();
132     } else if (equalIgnoringCase(mimeType, "text/html"))
133         decoder = TextResourceDecoder::create("text/html", "UTF-8");
134     else
135         decoder = TextResourceDecoder::create("text/plain", "UTF-8");
136     return decoder;
137 }
138
139 bool InspectorPageAgent::cachedResourceContent(CachedResource* cachedResource, String* result, bool* base64Encoded)
140 {
141     bool hasZeroSize;
142     bool prepared = prepareCachedResourceBuffer(cachedResource, &hasZeroSize);
143     if (!prepared)
144         return false;
145
146     *base64Encoded = !hasTextContent(cachedResource);
147     if (*base64Encoded) {
148         RefPtr<SharedBuffer> buffer = hasZeroSize ? SharedBuffer::create() : cachedResource->resourceBuffer()->sharedBuffer();
149
150         if (!buffer)
151             return false;
152
153         *result = base64Encode(buffer->data(), buffer->size());
154         return true;
155     }
156
157     if (hasZeroSize) {
158         *result = emptyString();
159         return true;
160     }
161
162     if (cachedResource) {
163         switch (cachedResource->type()) {
164         case CachedResource::CSSStyleSheet:
165             *result = toCachedCSSStyleSheet(cachedResource)->sheetText(false);
166             return true;
167         case CachedResource::Script:
168             *result = toCachedScript(cachedResource)->script();
169             return true;
170         case CachedResource::RawResource: {
171             ResourceBuffer* buffer = cachedResource->resourceBuffer();
172             if (!buffer)
173                 return false;
174             RefPtr<TextResourceDecoder> decoder = createXHRTextDecoder(cachedResource->response().mimeType(), cachedResource->response().textEncodingName());
175             // We show content for raw resources only for certain mime types (text, html and xml). Otherwise decoder will be null.
176             if (!decoder)
177                 return false;
178             *result = decoder->decodeAndFlush(buffer->data(), buffer->size());
179             return true;
180         }
181         default:
182             ResourceBuffer* buffer = cachedResource->resourceBuffer();
183             return decodeBuffer(buffer ? buffer->data() : nullptr, buffer ? buffer->size() : 0, cachedResource->encoding(), result);
184         }
185     }
186     return false;
187 }
188
189 bool InspectorPageAgent::mainResourceContent(Frame* frame, bool withBase64Encode, String* result)
190 {
191     RefPtr<ResourceBuffer> buffer = frame->loader().documentLoader()->mainResourceData();
192     if (!buffer)
193         return false;
194     String textEncodingName = frame->document()->inputEncoding();
195
196     return InspectorPageAgent::dataContent(buffer->data(), buffer->size(), textEncodingName, withBase64Encode, result);
197 }
198
199 // static
200 bool InspectorPageAgent::sharedBufferContent(PassRefPtr<SharedBuffer> buffer, const String& textEncodingName, bool withBase64Encode, String* result)
201 {
202     return dataContent(buffer ? buffer->data() : nullptr, buffer ? buffer->size() : 0, textEncodingName, withBase64Encode, result);
203 }
204
205 bool InspectorPageAgent::dataContent(const char* data, unsigned size, const String& textEncodingName, bool withBase64Encode, String* result)
206 {
207     if (withBase64Encode) {
208         *result = base64Encode(data, size);
209         return true;
210     }
211
212     return decodeBuffer(data, size, textEncodingName, result);
213 }
214
215 // static
216 void InspectorPageAgent::resourceContent(ErrorString& errorString, Frame* frame, const URL& url, String* result, bool* base64Encoded)
217 {
218     DocumentLoader* loader = assertDocumentLoader(errorString, frame);
219     if (!loader)
220         return;
221
222     RefPtr<SharedBuffer> buffer;
223     bool success = false;
224     if (equalIgnoringFragmentIdentifier(url, loader->url())) {
225         *base64Encoded = false;
226         success = mainResourceContent(frame, *base64Encoded, result);
227     }
228
229     if (!success)
230         success = cachedResourceContent(cachedResource(frame, url), result, base64Encoded);
231
232     if (!success)
233         errorString = ASCIILiteral("No resource with given URL found");
234 }
235
236 //static
237 String InspectorPageAgent::sourceMapURLForResource(CachedResource* cachedResource)
238 {
239     DEPRECATED_DEFINE_STATIC_LOCAL(String, sourceMapHTTPHeader, (ASCIILiteral("SourceMap")));
240     DEPRECATED_DEFINE_STATIC_LOCAL(String, sourceMapHTTPHeaderDeprecated, (ASCIILiteral("X-SourceMap")));
241
242     if (!cachedResource)
243         return String();
244
245     // Scripts are handled in a separate path.
246     if (cachedResource->type() != CachedResource::CSSStyleSheet)
247         return String();
248
249     String sourceMapHeader = cachedResource->response().httpHeaderField(sourceMapHTTPHeader);
250     if (!sourceMapHeader.isEmpty())
251         return sourceMapHeader;
252
253     sourceMapHeader = cachedResource->response().httpHeaderField(sourceMapHTTPHeaderDeprecated);
254     if (!sourceMapHeader.isEmpty())
255         return sourceMapHeader;
256
257     String content;
258     bool base64Encoded;
259     if (InspectorPageAgent::cachedResourceContent(cachedResource, &content, &base64Encoded) && !base64Encoded)
260         return ContentSearchUtilities::findStylesheetSourceMapURL(content);
261
262     return String();
263 }
264
265 CachedResource* InspectorPageAgent::cachedResource(Frame* frame, const URL& url)
266 {
267     CachedResource* cachedResource = frame->document()->cachedResourceLoader()->cachedResource(url);
268     if (!cachedResource) {
269         ResourceRequest request(url);
270 #if ENABLE(CACHE_PARTITIONING)
271         request.setCachePartition(frame->document()->topOrigin()->cachePartition());
272 #endif
273         cachedResource = memoryCache()->resourceForRequest(request, frame->page()->sessionID());
274     }
275
276     return cachedResource;
277 }
278
279 Inspector::Protocol::Page::ResourceType InspectorPageAgent::resourceTypeJson(InspectorPageAgent::ResourceType resourceType)
280 {
281     switch (resourceType) {
282     case DocumentResource:
283         return Inspector::Protocol::Page::ResourceType::Document;
284     case ImageResource:
285         return Inspector::Protocol::Page::ResourceType::Image;
286     case FontResource:
287         return Inspector::Protocol::Page::ResourceType::Font;
288     case StylesheetResource:
289         return Inspector::Protocol::Page::ResourceType::Stylesheet;
290     case ScriptResource:
291         return Inspector::Protocol::Page::ResourceType::Script;
292     case XHRResource:
293         return Inspector::Protocol::Page::ResourceType::XHR;
294     case WebSocketResource:
295         return Inspector::Protocol::Page::ResourceType::WebSocket;
296     case OtherResource:
297         return Inspector::Protocol::Page::ResourceType::Other;
298     }
299     return Inspector::Protocol::Page::ResourceType::Other;
300 }
301
302 InspectorPageAgent::ResourceType InspectorPageAgent::cachedResourceType(const CachedResource& cachedResource)
303 {
304     switch (cachedResource.type()) {
305     case CachedResource::ImageResource:
306         return InspectorPageAgent::ImageResource;
307     case CachedResource::FontResource:
308         return InspectorPageAgent::FontResource;
309     case CachedResource::CSSStyleSheet:
310         // Fall through.
311 #if ENABLE(XSLT)
312     case CachedResource::XSLStyleSheet:
313 #endif
314         return InspectorPageAgent::StylesheetResource;
315     case CachedResource::Script:
316         return InspectorPageAgent::ScriptResource;
317     case CachedResource::RawResource:
318         return InspectorPageAgent::XHRResource;
319     case CachedResource::MainResource:
320         return InspectorPageAgent::DocumentResource;
321     default:
322         break;
323     }
324     return InspectorPageAgent::OtherResource;
325 }
326
327 Inspector::Protocol::Page::ResourceType InspectorPageAgent::cachedResourceTypeJson(const CachedResource& cachedResource)
328 {
329     return resourceTypeJson(cachedResourceType(cachedResource));
330 }
331
332 InspectorPageAgent::InspectorPageAgent(InstrumentingAgents* instrumentingAgents, Page* page, InspectorClient* client, InspectorOverlay* overlay)
333     : InspectorAgentBase(ASCIILiteral("Page"), instrumentingAgents)
334     , m_page(page)
335     , m_client(client)
336     , m_overlay(overlay)
337     , m_lastScriptIdentifier(0)
338     , m_enabled(false)
339     , m_isFirstLayoutAfterOnLoad(false)
340     , m_originalScriptExecutionDisabled(false)
341     , m_ignoreScriptsEnabledNotification(false)
342     , m_showPaintRects(false)
343 {
344 }
345
346 void InspectorPageAgent::didCreateFrontendAndBackend(Inspector::InspectorFrontendChannel* frontendChannel, InspectorBackendDispatcher* backendDispatcher)
347 {
348     m_frontendDispatcher = std::make_unique<InspectorPageFrontendDispatcher>(frontendChannel);
349     m_backendDispatcher = InspectorPageBackendDispatcher::create(backendDispatcher, this);
350 }
351
352 void InspectorPageAgent::willDestroyFrontendAndBackend(InspectorDisconnectReason)
353 {
354     m_frontendDispatcher = nullptr;
355     m_backendDispatcher.clear();
356
357     ErrorString unused;
358     disable(unused);
359 #if ENABLE(TOUCH_EVENTS)
360     updateTouchEventEmulationInPage(false);
361 #endif
362 }
363
364 double InspectorPageAgent::timestamp()
365 {
366     // If the timeline agent is recording now, use its stopwatch. Otherwise, just report 0.0
367     // since the timestamps are only used to accurately graph records on the timeline.
368     if (InspectorTimelineAgent* timelineAgent = m_instrumentingAgents->inspectorTimelineAgent())
369         return timelineAgent->timestamp();
370
371     return 0.0;
372 }
373
374 void InspectorPageAgent::enable(ErrorString&)
375 {
376     m_enabled = true;
377     m_instrumentingAgents->setInspectorPageAgent(this);
378
379     if (Frame* frame = mainFrame())
380         m_originalScriptExecutionDisabled = !frame->settings().isScriptEnabled();
381 }
382
383 void InspectorPageAgent::disable(ErrorString&)
384 {
385     m_enabled = false;
386     m_scriptsToEvaluateOnLoad.clear();
387     m_instrumentingAgents->setInspectorPageAgent(nullptr);
388
389     ErrorString unused;
390     setScriptExecutionDisabled(unused, m_originalScriptExecutionDisabled);
391     setShowPaintRects(unused, false);
392     setShowDebugBorders(unused, false);
393     setShowFPSCounter(unused, false);
394     setEmulatedMedia(unused, emptyString());
395     setContinuousPaintingEnabled(unused, false);
396 }
397
398 void InspectorPageAgent::addScriptToEvaluateOnLoad(ErrorString&, const String& source, String* identifier)
399 {
400     if (!m_scriptsToEvaluateOnLoad)
401         m_scriptsToEvaluateOnLoad = InspectorObject::create();
402
403     // Assure we don't override existing ids -- m_lastScriptIdentifier could get out of sync WRT actual
404     // scripts once we restored the scripts from the cookie during navigation.
405     do {
406         *identifier = String::number(++m_lastScriptIdentifier);
407     } while (m_scriptsToEvaluateOnLoad->find(*identifier) != m_scriptsToEvaluateOnLoad->end());
408
409     m_scriptsToEvaluateOnLoad->setString(*identifier, source);
410 }
411
412 void InspectorPageAgent::removeScriptToEvaluateOnLoad(ErrorString& error, const String& identifier)
413 {
414     if (!m_scriptsToEvaluateOnLoad || m_scriptsToEvaluateOnLoad->find(identifier) == m_scriptsToEvaluateOnLoad->end()) {
415         error = ASCIILiteral("Script not found");
416         return;
417     }
418
419     m_scriptsToEvaluateOnLoad->remove(identifier);
420 }
421
422 void InspectorPageAgent::reload(ErrorString&, const bool* const optionalIgnoreCache, const String* optionalScriptToEvaluateOnLoad)
423 {
424     m_pendingScriptToEvaluateOnLoadOnce = optionalScriptToEvaluateOnLoad ? *optionalScriptToEvaluateOnLoad : "";
425     m_page->mainFrame().loader().reload(optionalIgnoreCache ? *optionalIgnoreCache : false);
426 }
427
428 void InspectorPageAgent::navigate(ErrorString&, const String& url)
429 {
430     UserGestureIndicator indicator(DefinitelyProcessingUserGesture);
431     Frame& frame = m_page->mainFrame();
432     frame.loader().changeLocation(frame.document()->securityOrigin(), frame.document()->completeURL(url), "", LockHistory::No, LockBackForwardList::No);
433 }
434
435 static PassRefPtr<Inspector::Protocol::Page::Cookie> buildObjectForCookie(const Cookie& cookie)
436 {
437     return Inspector::Protocol::Page::Cookie::create()
438         .setName(cookie.name)
439         .setValue(cookie.value)
440         .setDomain(cookie.domain)
441         .setPath(cookie.path)
442         .setExpires(cookie.expires)
443         .setSize((cookie.name.length() + cookie.value.length()))
444         .setHttpOnly(cookie.httpOnly)
445         .setSecure(cookie.secure)
446         .setSession(cookie.session)
447         .release();
448 }
449
450 static PassRefPtr<Inspector::Protocol::Array<Inspector::Protocol::Page::Cookie>> buildArrayForCookies(ListHashSet<Cookie>& cookiesList)
451 {
452     RefPtr<Inspector::Protocol::Array<Inspector::Protocol::Page::Cookie>> cookies = Inspector::Protocol::Array<Inspector::Protocol::Page::Cookie>::create();
453
454     for (auto& cookie : cookiesList)
455         cookies->addItem(buildObjectForCookie(cookie));
456
457     return cookies;
458 }
459
460 static Vector<CachedResource*> cachedResourcesForFrame(Frame* frame)
461 {
462     Vector<CachedResource*> result;
463
464     for (auto& cachedResourceHandle : frame->document()->cachedResourceLoader()->allCachedResources().values()) {
465         auto* cachedResource = cachedResourceHandle.get();
466         if (cachedResource->resourceRequest().hiddenFromInspector())
467             continue;
468
469         switch (cachedResource->type()) {
470         case CachedResource::ImageResource:
471             // Skip images that were not auto loaded (images disabled in the user agent).
472         case CachedResource::FontResource:
473             // Skip fonts that were referenced in CSS but never used/downloaded.
474             if (cachedResource->stillNeedsLoad())
475                 continue;
476             break;
477         default:
478             // All other CachedResource types download immediately.
479             break;
480         }
481
482         result.append(cachedResource);
483     }
484
485     return result;
486 }
487
488 static Vector<URL> allResourcesURLsForFrame(Frame* frame)
489 {
490     Vector<URL> result;
491
492     result.append(frame->loader().documentLoader()->url());
493
494     for (auto* cachedResource : cachedResourcesForFrame(frame))
495         result.append(cachedResource->url());
496
497     return result;
498 }
499
500 void InspectorPageAgent::getCookies(ErrorString&, RefPtr<Inspector::Protocol::Array<Inspector::Protocol::Page::Cookie>>& cookies)
501 {
502     // If we can get raw cookies.
503     ListHashSet<Cookie> rawCookiesList;
504
505     // If we can't get raw cookies - fall back to String representation
506     StringBuilder stringCookiesList;
507
508     // Return value to getRawCookies should be the same for every call because
509     // the return value is platform/network backend specific, and the call will
510     // always return the same true/false value.
511     bool rawCookiesImplemented = false;
512
513     for (Frame* frame = mainFrame(); frame; frame = frame->tree().traverseNext(mainFrame())) {
514         Document* document = frame->document();
515
516         for (auto& url : allResourcesURLsForFrame(frame)) {
517             Vector<Cookie> docCookiesList;
518             rawCookiesImplemented = getRawCookies(document, URL(ParsedURLString, url), docCookiesList);
519
520             if (!rawCookiesImplemented) {
521                 // FIXME: We need duplication checking for the String representation of cookies.
522                 // Exceptions are thrown by cookie() in sandboxed frames. That won't happen here
523                 // because "document" is the document of the main frame of the page.
524                 stringCookiesList.append(document->cookie(ASSERT_NO_EXCEPTION));
525             } else {
526                 int cookiesSize = docCookiesList.size();
527                 for (int i = 0; i < cookiesSize; i++) {
528                     if (!rawCookiesList.contains(docCookiesList[i]))
529                         rawCookiesList.add(docCookiesList[i]);
530                 }
531             }
532         }
533     }
534
535     // FIXME: Do not return empty string/empty array. Make returns optional instead. https://bugs.webkit.org/show_bug.cgi?id=80855
536     if (rawCookiesImplemented)
537         cookies = buildArrayForCookies(rawCookiesList);
538     else
539         cookies = Inspector::Protocol::Array<Inspector::Protocol::Page::Cookie>::create();
540 }
541
542 void InspectorPageAgent::deleteCookie(ErrorString&, const String& cookieName, const String& url)
543 {
544     URL parsedURL(ParsedURLString, url);
545     for (Frame* frame = &m_page->mainFrame(); frame; frame = frame->tree().traverseNext(&m_page->mainFrame()))
546         WebCore::deleteCookie(frame->document(), parsedURL, cookieName);
547 }
548
549 void InspectorPageAgent::getResourceTree(ErrorString&, RefPtr<Inspector::Protocol::Page::FrameResourceTree>& object)
550 {
551     object = buildObjectForFrameTree(&m_page->mainFrame());
552 }
553
554 void InspectorPageAgent::getResourceContent(ErrorString& errorString, const String& frameId, const String& url, String* content, bool* base64Encoded)
555 {
556     Frame* frame = assertFrame(errorString, frameId);
557     if (!frame)
558         return;
559
560     resourceContent(errorString, frame, URL(ParsedURLString, url), content, base64Encoded);
561 }
562
563 static bool textContentForCachedResource(CachedResource* cachedResource, String* result)
564 {
565     if (hasTextContent(cachedResource)) {
566         String content;
567         bool base64Encoded;
568         if (InspectorPageAgent::cachedResourceContent(cachedResource, result, &base64Encoded)) {
569             ASSERT(!base64Encoded);
570             return true;
571         }
572     }
573     return false;
574 }
575
576 void InspectorPageAgent::searchInResource(ErrorString&, const String& frameId, const String& url, const String& query, const bool* const optionalCaseSensitive, const bool* const optionalIsRegex, RefPtr<Inspector::Protocol::Array<Inspector::Protocol::GenericTypes::SearchMatch>>& results)
577 {
578     results = Inspector::Protocol::Array<Inspector::Protocol::GenericTypes::SearchMatch>::create();
579
580     bool isRegex = optionalIsRegex ? *optionalIsRegex : false;
581     bool caseSensitive = optionalCaseSensitive ? *optionalCaseSensitive : false;
582
583     Frame* frame = frameForId(frameId);
584     if (!frame)
585         return;
586
587     DocumentLoader* loader = frame->loader().documentLoader();
588     if (!loader)
589         return;
590
591     URL kurl(ParsedURLString, url);
592
593     String content;
594     bool success = false;
595     if (equalIgnoringFragmentIdentifier(kurl, loader->url()))
596         success = mainResourceContent(frame, false, &content);
597
598     if (!success) {
599         CachedResource* resource = cachedResource(frame, kurl);
600         if (resource)
601             success = textContentForCachedResource(resource, &content);
602     }
603
604     if (!success)
605         return;
606
607     results = ContentSearchUtilities::searchInTextByLines(content, query, caseSensitive, isRegex);
608 }
609
610 static PassRefPtr<Inspector::Protocol::Page::SearchResult> buildObjectForSearchResult(const String& frameId, const String& url, int matchesCount)
611 {
612     return Inspector::Protocol::Page::SearchResult::create()
613         .setUrl(url)
614         .setFrameId(frameId)
615         .setMatchesCount(matchesCount)
616         .release();
617 }
618
619 void InspectorPageAgent::searchInResources(ErrorString&, const String& text, const bool* const optionalCaseSensitive, const bool* const optionalIsRegex, RefPtr<Inspector::Protocol::Array<Inspector::Protocol::Page::SearchResult>>& results)
620 {
621     RefPtr<Inspector::Protocol::Array<Inspector::Protocol::Page::SearchResult>> searchResults = Inspector::Protocol::Array<Inspector::Protocol::Page::SearchResult>::create();
622
623     bool isRegex = optionalIsRegex ? *optionalIsRegex : false;
624     bool caseSensitive = optionalCaseSensitive ? *optionalCaseSensitive : false;
625     JSC::Yarr::RegularExpression regex = ContentSearchUtilities::createSearchRegex(text, caseSensitive, isRegex);
626
627     for (Frame* frame = &m_page->mainFrame(); frame; frame = frame->tree().traverseNext(&m_page->mainFrame())) {
628         String content;
629
630         for (auto* cachedResource : cachedResourcesForFrame(frame)) {
631             if (textContentForCachedResource(cachedResource, &content)) {
632                 int matchesCount = ContentSearchUtilities::countRegularExpressionMatches(regex, content);
633                 if (matchesCount)
634                     searchResults->addItem(buildObjectForSearchResult(frameId(frame), cachedResource->url(), matchesCount));
635             }
636         }
637
638         if (mainResourceContent(frame, false, &content)) {
639             int matchesCount = ContentSearchUtilities::countRegularExpressionMatches(regex, content);
640             if (matchesCount)
641                 searchResults->addItem(buildObjectForSearchResult(frameId(frame), frame->document()->url(), matchesCount));
642         }
643     }
644
645     results = searchResults;
646 }
647
648 void InspectorPageAgent::setDocumentContent(ErrorString& errorString, const String& frameId, const String& html)
649 {
650     Frame* frame = assertFrame(errorString, frameId);
651     if (!frame)
652         return;
653
654     Document* document = frame->document();
655     if (!document) {
656         errorString = ASCIILiteral("No Document instance to set HTML for");
657         return;
658     }
659     DOMPatchSupport::patchDocument(document, html);
660 }
661
662 void InspectorPageAgent::setShowPaintRects(ErrorString&, bool show)
663 {
664     m_showPaintRects = show;
665     m_client->setShowPaintRects(show);
666
667     if (m_client->overridesShowPaintRects())
668         return;
669
670     m_overlay->setShowingPaintRects(show);
671 }
672
673 void InspectorPageAgent::canShowDebugBorders(ErrorString&, bool* outParam)
674 {
675     *outParam = m_client->canShowDebugBorders();
676 }
677
678 void InspectorPageAgent::setShowDebugBorders(ErrorString&, bool show)
679 {
680     m_client->setShowDebugBorders(show);
681     if (mainFrame() && mainFrame()->view())
682         mainFrame()->view()->invalidate();
683 }
684
685 void InspectorPageAgent::canShowFPSCounter(ErrorString&, bool* outParam)
686 {
687     *outParam = m_client->canShowFPSCounter();
688 }
689
690 void InspectorPageAgent::setShowFPSCounter(ErrorString&, bool show)
691 {
692     m_client->setShowFPSCounter(show);
693
694     if (mainFrame() && mainFrame()->view())
695         mainFrame()->view()->invalidate();
696 }
697
698 void InspectorPageAgent::canContinuouslyPaint(ErrorString&, bool* outParam)
699 {
700     *outParam = m_client->canContinuouslyPaint();
701 }
702
703 void InspectorPageAgent::setContinuousPaintingEnabled(ErrorString&, bool enabled)
704 {
705     m_client->setContinuousPaintingEnabled(enabled);
706
707     if (!enabled && mainFrame() && mainFrame()->view())
708         mainFrame()->view()->invalidate();
709 }
710
711 void InspectorPageAgent::getScriptExecutionStatus(ErrorString&, InspectorPageBackendDispatcherHandler::Result* status)
712 {
713     bool disabledByScriptController = false;
714     bool disabledInSettings = false;
715     Frame* frame = mainFrame();
716     if (frame) {
717         disabledByScriptController = !frame->script().canExecuteScripts(NotAboutToExecuteScript);
718         disabledInSettings = !frame->settings().isScriptEnabled();
719     }
720
721     if (!disabledByScriptController) {
722         *status = InspectorPageBackendDispatcherHandler::Result::Allowed;
723         return;
724     }
725
726     if (disabledInSettings)
727         *status = InspectorPageBackendDispatcherHandler::Result::Disabled;
728     else
729         *status = InspectorPageBackendDispatcherHandler::Result::Forbidden;
730 }
731
732 void InspectorPageAgent::setScriptExecutionDisabled(ErrorString&, bool value)
733 {
734     if (!mainFrame())
735         return;
736
737     m_ignoreScriptsEnabledNotification = true;
738     mainFrame()->settings().setScriptEnabled(!value);
739     m_ignoreScriptsEnabledNotification = false;
740 }
741
742 void InspectorPageAgent::didClearWindowObjectInWorld(Frame* frame, DOMWrapperWorld& world)
743 {
744     if (&world != &mainThreadNormalWorld())
745         return;
746
747     if (!m_frontendDispatcher)
748         return;
749
750     if (m_scriptsToEvaluateOnLoad) {
751         for (auto& keyValuePair : *m_scriptsToEvaluateOnLoad) {
752             String scriptText;
753             if (keyValuePair.value->asString(scriptText))
754                 frame->script().executeScript(scriptText);
755         }
756     }
757
758     if (!m_scriptToEvaluateOnLoadOnce.isEmpty())
759         frame->script().executeScript(m_scriptToEvaluateOnLoadOnce);
760 }
761
762 void InspectorPageAgent::domContentEventFired()
763 {
764     m_isFirstLayoutAfterOnLoad = true;
765     m_frontendDispatcher->domContentEventFired(timestamp());
766 }
767
768 void InspectorPageAgent::loadEventFired()
769 {
770     m_frontendDispatcher->loadEventFired(timestamp());
771 }
772
773 void InspectorPageAgent::frameNavigated(DocumentLoader* loader)
774 {
775     if (loader->frame()->isMainFrame()) {
776         m_scriptToEvaluateOnLoadOnce = m_pendingScriptToEvaluateOnLoadOnce;
777         m_pendingScriptToEvaluateOnLoadOnce = String();
778     }
779     m_frontendDispatcher->frameNavigated(buildObjectForFrame(loader->frame()));
780 }
781
782 void InspectorPageAgent::frameDetached(Frame* frame)
783 {
784     HashMap<Frame*, String>::iterator iterator = m_frameToIdentifier.find(frame);
785     if (iterator != m_frameToIdentifier.end()) {
786         m_frontendDispatcher->frameDetached(iterator->value);
787         m_identifierToFrame.remove(iterator->value);
788         m_frameToIdentifier.remove(iterator);
789     }
790 }
791
792 Frame* InspectorPageAgent::mainFrame()
793 {
794     // FIXME: This should return a Frame&
795     return &m_page->mainFrame();
796 }
797
798 Frame* InspectorPageAgent::frameForId(const String& frameId)
799 {
800     return frameId.isEmpty() ? nullptr : m_identifierToFrame.get(frameId);
801 }
802
803 String InspectorPageAgent::frameId(Frame* frame)
804 {
805     if (!frame)
806         return "";
807     String identifier = m_frameToIdentifier.get(frame);
808     if (identifier.isNull()) {
809         identifier = IdentifiersFactory::createIdentifier();
810         m_frameToIdentifier.set(frame, identifier);
811         m_identifierToFrame.set(identifier, frame);
812     }
813     return identifier;
814 }
815
816 bool InspectorPageAgent::hasIdForFrame(Frame* frame) const
817 {
818     return frame && m_frameToIdentifier.contains(frame);
819 }
820
821 String InspectorPageAgent::loaderId(DocumentLoader* loader)
822 {
823     if (!loader)
824         return "";
825     String identifier = m_loaderToIdentifier.get(loader);
826     if (identifier.isNull()) {
827         identifier = IdentifiersFactory::createIdentifier();
828         m_loaderToIdentifier.set(loader, identifier);
829     }
830     return identifier;
831 }
832
833 Frame* InspectorPageAgent::findFrameWithSecurityOrigin(const String& originRawString)
834 {
835     for (Frame* frame = &m_page->mainFrame(); frame; frame = frame->tree().traverseNext()) {
836         RefPtr<SecurityOrigin> documentOrigin = frame->document()->securityOrigin();
837         if (documentOrigin->toRawString() == originRawString)
838             return frame;
839     }
840     return nullptr;
841 }
842
843 Frame* InspectorPageAgent::assertFrame(ErrorString& errorString, const String& frameId)
844 {
845     Frame* frame = frameForId(frameId);
846     if (!frame)
847         errorString = ASCIILiteral("No frame for given id found");
848     return frame;
849 }
850
851 // static
852 DocumentLoader* InspectorPageAgent::assertDocumentLoader(ErrorString& errorString, Frame* frame)
853 {
854     FrameLoader& frameLoader = frame->loader();
855     DocumentLoader* documentLoader = frameLoader.documentLoader();
856     if (!documentLoader)
857         errorString = ASCIILiteral("No documentLoader for given frame found");
858     return documentLoader;
859 }
860
861 void InspectorPageAgent::loaderDetachedFromFrame(DocumentLoader* loader)
862 {
863     m_loaderToIdentifier.remove(loader);
864 }
865
866 void InspectorPageAgent::frameStartedLoading(Frame& frame)
867 {
868     m_frontendDispatcher->frameStartedLoading(frameId(&frame));
869 }
870
871 void InspectorPageAgent::frameStoppedLoading(Frame& frame)
872 {
873     m_frontendDispatcher->frameStoppedLoading(frameId(&frame));
874 }
875
876 void InspectorPageAgent::frameScheduledNavigation(Frame& frame, double delay)
877 {
878     m_frontendDispatcher->frameScheduledNavigation(frameId(&frame), delay);
879 }
880
881 void InspectorPageAgent::frameClearedScheduledNavigation(Frame& frame)
882 {
883     m_frontendDispatcher->frameClearedScheduledNavigation(frameId(&frame));
884 }
885
886 void InspectorPageAgent::willRunJavaScriptDialog(const String& message)
887 {
888     m_frontendDispatcher->javascriptDialogOpening(message);
889 }
890
891 void InspectorPageAgent::didRunJavaScriptDialog()
892 {
893     m_frontendDispatcher->javascriptDialogClosed();
894 }
895
896 void InspectorPageAgent::didPaint(RenderObject* renderer, const LayoutRect& rect)
897 {
898     if (!m_enabled || !m_showPaintRects)
899         return;
900
901     LayoutRect absoluteRect = LayoutRect(renderer->localToAbsoluteQuad(FloatRect(rect)).boundingBox());
902     FrameView* view = renderer->document().view();
903     
904     LayoutRect rootRect = absoluteRect;
905     if (!view->frame().isMainFrame()) {
906         IntRect rootViewRect = view->contentsToRootView(snappedIntRect(absoluteRect));
907         rootRect = view->frame().mainFrame().view()->rootViewToContents(rootViewRect);
908     }
909     
910     if (m_client->overridesShowPaintRects()) {
911         m_client->showPaintRect(rootRect);
912         return;
913     }
914
915     m_overlay->showPaintRect(rootRect);
916 }
917
918 void InspectorPageAgent::didLayout()
919 {
920     bool isFirstLayout = m_isFirstLayoutAfterOnLoad;
921     if (isFirstLayout)
922         m_isFirstLayoutAfterOnLoad = false;
923
924     if (!m_enabled)
925         return;
926
927     m_overlay->update();
928 }
929
930 void InspectorPageAgent::didScroll()
931 {
932     if (m_enabled)
933         m_overlay->update();
934 }
935
936 void InspectorPageAgent::didRecalculateStyle()
937 {
938     if (m_enabled)
939         m_overlay->update();
940 }
941
942 void InspectorPageAgent::scriptsEnabled(bool isEnabled)
943 {
944     if (m_ignoreScriptsEnabledNotification)
945         return;
946
947     m_frontendDispatcher->scriptsEnabled(isEnabled);
948 }
949
950 PassRefPtr<Inspector::Protocol::Page::Frame> InspectorPageAgent::buildObjectForFrame(Frame* frame)
951 {
952     RefPtr<Inspector::Protocol::Page::Frame> frameObject = Inspector::Protocol::Page::Frame::create()
953         .setId(frameId(frame))
954         .setLoaderId(loaderId(frame->loader().documentLoader()))
955         .setUrl(frame->document()->url().string())
956         .setMimeType(frame->loader().documentLoader()->responseMIMEType())
957         .setSecurityOrigin(frame->document()->securityOrigin()->toRawString());
958     if (frame->tree().parent())
959         frameObject->setParentId(frameId(frame->tree().parent()));
960     if (frame->ownerElement()) {
961         String name = frame->ownerElement()->getNameAttribute();
962         if (name.isEmpty())
963             name = frame->ownerElement()->getAttribute(HTMLNames::idAttr);
964         frameObject->setName(name);
965     }
966
967     return frameObject;
968 }
969
970 PassRefPtr<Inspector::Protocol::Page::FrameResourceTree> InspectorPageAgent::buildObjectForFrameTree(Frame* frame)
971 {
972     RefPtr<Inspector::Protocol::Page::Frame> frameObject = buildObjectForFrame(frame);
973     RefPtr<Inspector::Protocol::Array<Inspector::Protocol::Page::FrameResource>> subresources = Inspector::Protocol::Array<Inspector::Protocol::Page::FrameResource>::create();
974     RefPtr<Inspector::Protocol::Page::FrameResourceTree> result = Inspector::Protocol::Page::FrameResourceTree::create()
975          .setFrame(frameObject)
976          .setResources(subresources);
977
978     for (auto* cachedResource : cachedResourcesForFrame(frame)) {
979         RefPtr<Inspector::Protocol::Page::FrameResource> resourceObject = Inspector::Protocol::Page::FrameResource::create()
980             .setUrl(cachedResource->url())
981             .setType(cachedResourceTypeJson(*cachedResource))
982             .setMimeType(cachedResource->response().mimeType());
983         if (cachedResource->wasCanceled())
984             resourceObject->setCanceled(true);
985         else if (cachedResource->status() == CachedResource::LoadError)
986             resourceObject->setFailed(true);
987         String sourceMappingURL = InspectorPageAgent::sourceMapURLForResource(cachedResource);
988         if (!sourceMappingURL.isEmpty())
989             resourceObject->setSourceMapURL(sourceMappingURL);
990         subresources->addItem(resourceObject);
991     }
992
993     RefPtr<Inspector::Protocol::Array<Inspector::Protocol::Page::FrameResourceTree>> childrenArray;
994     for (Frame* child = frame->tree().firstChild(); child; child = child->tree().nextSibling()) {
995         if (!childrenArray) {
996             childrenArray = Inspector::Protocol::Array<Inspector::Protocol::Page::FrameResourceTree>::create();
997             result->setChildFrames(childrenArray);
998         }
999         childrenArray->addItem(buildObjectForFrameTree(child));
1000     }
1001     return result;
1002 }
1003
1004 #if ENABLE(TOUCH_EVENTS)
1005 void InspectorPageAgent::updateTouchEventEmulationInPage(bool enabled)
1006 {
1007     if (mainFrame())
1008         mainFrame()->settings().setTouchEventEmulationEnabled(enabled);
1009 }
1010 #endif
1011
1012 void InspectorPageAgent::setTouchEmulationEnabled(ErrorString& error, bool enabled)
1013 {
1014 #if ENABLE(TOUCH_EVENTS)
1015     UNUSED_PARAM(error);
1016     updateTouchEventEmulationInPage(enabled);
1017 #else
1018     error = ASCIILiteral("Touch events emulation not supported");
1019     UNUSED_PARAM(enabled);
1020 #endif
1021 }
1022
1023 void InspectorPageAgent::setEmulatedMedia(ErrorString&, const String& media)
1024 {
1025     if (media == m_emulatedMedia)
1026         return;
1027
1028     m_emulatedMedia = media;
1029     Document* document = m_page->mainFrame().document();
1030     if (document) {
1031         document->styleResolverChanged(RecalcStyleImmediately);
1032         document->updateLayout();
1033     }
1034 }
1035
1036 void InspectorPageAgent::applyEmulatedMedia(String* media)
1037 {
1038     if (!m_emulatedMedia.isEmpty())
1039         *media = m_emulatedMedia;
1040 }
1041
1042 void InspectorPageAgent::getCompositingBordersVisible(ErrorString&, bool* outParam)
1043 {
1044     *outParam = m_page->settings().showDebugBorders() || m_page->settings().showRepaintCounter();
1045 }
1046
1047 void InspectorPageAgent::setCompositingBordersVisible(ErrorString&, bool visible)
1048 {
1049     m_page->settings().setShowDebugBorders(visible);
1050     m_page->settings().setShowRepaintCounter(visible);
1051 }
1052
1053 void InspectorPageAgent::snapshotNode(ErrorString& errorString, int nodeId, String* outDataURL)
1054 {
1055     Frame* frame = mainFrame();
1056     ASSERT(frame);
1057
1058     InspectorDOMAgent* domAgent = m_instrumentingAgents->inspectorDOMAgent();
1059     ASSERT(domAgent);
1060     Node* node = domAgent->assertNode(errorString, nodeId);
1061     if (!node)
1062         return;
1063
1064     std::unique_ptr<ImageBuffer> snapshot = WebCore::snapshotNode(*frame, *node);
1065     if (!snapshot) {
1066         errorString = ASCIILiteral("Could not capture snapshot");
1067         return;
1068     }
1069
1070     *outDataURL = snapshot->toDataURL(ASCIILiteral("image/png"));
1071 }
1072
1073 void InspectorPageAgent::snapshotRect(ErrorString& errorString, int x, int y, int width, int height, const String& coordinateSystem, String* outDataURL)
1074 {
1075     Frame* frame = mainFrame();
1076     ASSERT(frame);
1077
1078     SnapshotOptions options = SnapshotOptionsNone;
1079     if (coordinateSystem == "Viewport")
1080         options |= SnapshotOptionsInViewCoordinates;
1081
1082     IntRect rectangle(x, y, width, height);
1083     std::unique_ptr<ImageBuffer> snapshot = snapshotFrameRect(*frame, rectangle, options);
1084
1085     if (!snapshot) {
1086         errorString = ASCIILiteral("Could not capture snapshot");
1087         return;
1088     }
1089
1090     *outDataURL = snapshot->toDataURL(ASCIILiteral("image/png"));
1091 }
1092
1093 void InspectorPageAgent::handleJavaScriptDialog(ErrorString& errorString, bool accept, const String* promptText)
1094 {
1095     if (!m_client->handleJavaScriptDialog(accept, promptText))
1096         errorString = ASCIILiteral("Could not handle JavaScript dialog");
1097 }
1098
1099 void InspectorPageAgent::archive(ErrorString& errorString, String* data)
1100 {
1101     Frame* frame = mainFrame();
1102     if (!frame) {
1103         errorString = ASCIILiteral("No main frame");
1104         return;
1105     }
1106
1107 #if ENABLE(WEB_ARCHIVE) && USE(CF)
1108     RefPtr<LegacyWebArchive> archive = LegacyWebArchive::create(frame);
1109     if (!archive) {
1110         errorString = ASCIILiteral("Could not create web archive for main frame");
1111         return;
1112     }
1113
1114     RetainPtr<CFDataRef> buffer = archive->rawDataRepresentation();
1115     *data = base64Encode(CFDataGetBytePtr(buffer.get()), CFDataGetLength(buffer.get()));
1116 #else
1117     UNUSED_PARAM(data);
1118     errorString = ASCIILiteral("No support for creating archives");
1119 #endif
1120 }
1121
1122 } // namespace WebCore
1123
1124 #endif // ENABLE(INSPECTOR)