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