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