1 /* 2 * Copyright (C) 2011 Google Inc. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions are 6 * met: 7 * 8 * * Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * * Redistributions in binary form must reproduce the above 11 * copyright notice, this list of conditions and the following disclaimer 12 * in the documentation and/or other materials provided with the 13 * distribution. 14 * * Neither the name of Google Inc. nor the names of its 15 * contributors may be used to endorse or promote products derived from 16 * this software without specific prior written permission. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 */ 30 31 #include "config.h" 32 #include "core/inspector/InspectorPageAgent.h" 33 34 #include "bindings/v8/DOMWrapperWorld.h" 35 #include "bindings/v8/ScriptController.h" 36 #include "bindings/v8/ScriptRegexp.h" 37 #include "core/HTMLNames.h" 38 #include "core/UserAgentStyleSheets.h" 39 #include "core/css/StyleSheetContents.h" 40 #include "core/css/resolver/ViewportStyleResolver.h" 41 #include "core/dom/DOMImplementation.h" 42 #include "core/dom/Document.h" 43 #include "core/fetch/CSSStyleSheetResource.h" 44 #include "core/fetch/FontResource.h" 45 #include "core/fetch/ImageResource.h" 46 #include "core/fetch/MemoryCache.h" 47 #include "core/fetch/Resource.h" 48 #include "core/fetch/ResourceFetcher.h" 49 #include "core/fetch/ScriptResource.h" 50 #include "core/frame/FrameView.h" 51 #include "core/frame/LocalFrame.h" 52 #include "core/frame/Settings.h" 53 #include "core/html/HTMLFrameOwnerElement.h" 54 #include "core/html/imports/HTMLImport.h" 55 #include "core/html/imports/HTMLImportLoader.h" 56 #include "core/html/imports/HTMLImportsController.h" 57 #include "core/html/parser/TextResourceDecoder.h" 58 #include "core/inspector/ContentSearchUtils.h" 59 #include "core/inspector/DOMPatchSupport.h" 60 #include "core/inspector/IdentifiersFactory.h" 61 #include "core/inspector/InjectedScriptManager.h" 62 #include "core/inspector/InspectorClient.h" 63 #include "core/inspector/InspectorInstrumentation.h" 64 #include "core/inspector/InspectorOverlay.h" 65 #include "core/inspector/InspectorResourceContentLoader.h" 66 #include "core/inspector/InspectorState.h" 67 #include "core/inspector/InstrumentingAgents.h" 68 #include "core/loader/CookieJar.h" 69 #include "core/loader/DocumentLoader.h" 70 #include "core/loader/FrameLoadRequest.h" 71 #include "core/loader/FrameLoader.h" 72 #include "core/page/Page.h" 73 #include "platform/Cookie.h" 74 #include "platform/JSONValues.h" 75 #include "platform/UserGestureIndicator.h" 76 #include "platform/weborigin/SecurityOrigin.h" 77 #include "wtf/CurrentTime.h" 78 #include "wtf/ListHashSet.h" 79 #include "wtf/Vector.h" 80 #include "wtf/text/Base64.h" 81 #include "wtf/text/TextEncoding.h" 82 83 namespace WebCore { 84 85 namespace PageAgentState { 86 static const char pageAgentEnabled[] = "pageAgentEnabled"; 87 static const char pageAgentScriptExecutionDisabled[] = "pageAgentScriptExecutionDisabled"; 88 static const char pageAgentScriptsToEvaluateOnLoad[] = "pageAgentScriptsToEvaluateOnLoad"; 89 static const char deviceMetricsOverrideEnabled[] = "deviceMetricsOverrideEnabled"; 90 static const char pageAgentScreenWidthOverride[] = "pageAgentScreenWidthOverride"; 91 static const char pageAgentScreenHeightOverride[] = "pageAgentScreenHeightOverride"; 92 static const char pageAgentDeviceScaleFactorOverride[] = "pageAgentDeviceScaleFactorOverride"; 93 static const char pageAgentEmulateViewport[] = "pageAgentEmulateViewport"; 94 static const char pageAgentFitWindow[] = "pageAgentFitWindow"; 95 static const char fontScaleFactor[] = "fontScaleFactor"; 96 static const char pageAgentShowFPSCounter[] = "pageAgentShowFPSCounter"; 97 static const char pageAgentTextAutosizingOverride[] = "pageAgentTextAutosizingOverride"; 98 static const char pageAgentContinuousPaintingEnabled[] = "pageAgentContinuousPaintingEnabled"; 99 static const char pageAgentShowPaintRects[] = "pageAgentShowPaintRects"; 100 static const char pageAgentShowDebugBorders[] = "pageAgentShowDebugBorders"; 101 static const char pageAgentShowScrollBottleneckRects[] = "pageAgentShowScrollBottleneckRects"; 102 static const char touchEventEmulationEnabled[] = "touchEventEmulationEnabled"; 103 static const char pageAgentEmulatedMedia[] = "pageAgentEmulatedMedia"; 104 static const char showSizeOnResize[] = "showSizeOnResize"; 105 static const char showGridOnResize[] = "showGridOnResize"; 106 } 107 108 namespace { 109 110 KURL urlWithoutFragment(const KURL& url) 111 { 112 KURL result = url; 113 result.removeFragmentIdentifier(); 114 return result; 115 } 116 117 } 118 119 static bool decodeBuffer(const char* buffer, unsigned size, const String& textEncodingName, String* result) 120 { 121 if (buffer) { 122 WTF::TextEncoding encoding(textEncodingName); 123 if (!encoding.isValid()) 124 encoding = WindowsLatin1Encoding(); 125 *result = encoding.decode(buffer, size); 126 return true; 127 } 128 return false; 129 } 130 131 static bool prepareResourceBuffer(Resource* cachedResource, bool* hasZeroSize) 132 { 133 *hasZeroSize = false; 134 if (!cachedResource) 135 return false; 136 137 if (cachedResource->dataBufferingPolicy() == DoNotBufferData) 138 return false; 139 140 // Zero-sized resources don't have data at all -- so fake the empty buffer, instead of indicating error by returning 0. 141 if (!cachedResource->encodedSize()) { 142 *hasZeroSize = true; 143 return true; 144 } 145 146 if (cachedResource->isPurgeable()) { 147 // If the resource is purgeable then make it unpurgeable to get 148 // get its data. This might fail, in which case we return an 149 // empty String. 150 // FIXME: should we do something else in the case of a purged 151 // resource that informs the user why there is no data in the 152 // inspector? 153 if (!cachedResource->lock()) 154 return false; 155 } 156 157 return true; 158 } 159 160 static bool hasTextContent(Resource* cachedResource) 161 { 162 InspectorPageAgent::ResourceType type = InspectorPageAgent::cachedResourceType(*cachedResource); 163 return type == InspectorPageAgent::DocumentResource || type == InspectorPageAgent::StylesheetResource || type == InspectorPageAgent::ScriptResource || type == InspectorPageAgent::XHRResource; 164 } 165 166 static PassOwnPtr<TextResourceDecoder> createXHRTextDecoder(const String& mimeType, const String& textEncodingName) 167 { 168 if (!textEncodingName.isEmpty()) 169 return TextResourceDecoder::create("text/plain", textEncodingName); 170 if (DOMImplementation::isXMLMIMEType(mimeType)) { 171 OwnPtr<TextResourceDecoder> decoder = TextResourceDecoder::create("application/xml"); 172 decoder->useLenientXMLDecoding(); 173 return decoder.release(); 174 } 175 if (equalIgnoringCase(mimeType, "text/html")) 176 return TextResourceDecoder::create("text/html", "UTF-8"); 177 return TextResourceDecoder::create("text/plain", "UTF-8"); 178 } 179 180 bool InspectorPageAgent::cachedResourceContent(Resource* cachedResource, String* result, bool* base64Encoded) 181 { 182 bool hasZeroSize; 183 bool prepared = prepareResourceBuffer(cachedResource, &hasZeroSize); 184 if (!prepared) 185 return false; 186 187 *base64Encoded = !hasTextContent(cachedResource); 188 if (*base64Encoded) { 189 RefPtr<SharedBuffer> buffer = hasZeroSize ? SharedBuffer::create() : cachedResource->resourceBuffer(); 190 191 if (!buffer) 192 return false; 193 194 *result = base64Encode(buffer->data(), buffer->size()); 195 return true; 196 } 197 198 if (hasZeroSize) { 199 *result = ""; 200 return true; 201 } 202 203 if (cachedResource) { 204 switch (cachedResource->type()) { 205 case Resource::CSSStyleSheet: 206 *result = toCSSStyleSheetResource(cachedResource)->sheetText(false); 207 return true; 208 case Resource::Script: 209 *result = toScriptResource(cachedResource)->script(); 210 return true; 211 case Resource::MainResource: 212 return false; 213 case Resource::Raw: { 214 SharedBuffer* buffer = cachedResource->resourceBuffer(); 215 if (!buffer) 216 return false; 217 OwnPtr<TextResourceDecoder> decoder = createXHRTextDecoder(cachedResource->response().mimeType(), cachedResource->response().textEncodingName()); 218 String content = decoder->decode(buffer->data(), buffer->size()); 219 *result = content + decoder->flush(); 220 return true; 221 } 222 default: 223 SharedBuffer* buffer = cachedResource->resourceBuffer(); 224 return decodeBuffer(buffer ? buffer->data() : 0, buffer ? buffer->size() : 0, cachedResource->response().textEncodingName(), result); 225 } 226 } 227 return false; 228 } 229 230 // static 231 bool InspectorPageAgent::sharedBufferContent(PassRefPtr<SharedBuffer> buffer, const String& textEncodingName, bool withBase64Encode, String* result) 232 { 233 return dataContent(buffer ? buffer->data() : 0, buffer ? buffer->size() : 0, textEncodingName, withBase64Encode, result); 234 } 235 236 bool InspectorPageAgent::dataContent(const char* data, unsigned size, const String& textEncodingName, bool withBase64Encode, String* result) 237 { 238 if (withBase64Encode) { 239 *result = base64Encode(data, size); 240 return true; 241 } 242 243 return decodeBuffer(data, size, textEncodingName, result); 244 } 245 246 PassOwnPtr<InspectorPageAgent> InspectorPageAgent::create(Page* page, InjectedScriptManager* injectedScriptManager, InspectorClient* client, InspectorOverlay* overlay) 247 { 248 return adoptPtr(new InspectorPageAgent(page, injectedScriptManager, client, overlay)); 249 } 250 251 // static 252 void InspectorPageAgent::resourceContent(ErrorString* errorString, LocalFrame* frame, const KURL& url, String* result, bool* base64Encoded) 253 { 254 DocumentLoader* loader = assertDocumentLoader(errorString, frame); 255 if (!loader) 256 return; 257 if (!cachedResourceContent(cachedResource(frame, url), result, base64Encoded)) 258 *errorString = "No resource with given URL found"; 259 } 260 261 Resource* InspectorPageAgent::cachedResource(LocalFrame* frame, const KURL& url) 262 { 263 Resource* cachedResource = frame->document()->fetcher()->cachedResource(url); 264 if (!cachedResource) 265 cachedResource = memoryCache()->resourceForURL(url); 266 return cachedResource; 267 } 268 269 TypeBuilder::Page::ResourceType::Enum InspectorPageAgent::resourceTypeJson(InspectorPageAgent::ResourceType resourceType) 270 { 271 switch (resourceType) { 272 case DocumentResource: 273 return TypeBuilder::Page::ResourceType::Document; 274 case FontResource: 275 return TypeBuilder::Page::ResourceType::Font; 276 case ImageResource: 277 return TypeBuilder::Page::ResourceType::Image; 278 case MediaResource: 279 return TypeBuilder::Page::ResourceType::Media; 280 case ScriptResource: 281 return TypeBuilder::Page::ResourceType::Script; 282 case StylesheetResource: 283 return TypeBuilder::Page::ResourceType::Stylesheet; 284 case TextTrackResource: 285 return TypeBuilder::Page::ResourceType::TextTrack; 286 case XHRResource: 287 return TypeBuilder::Page::ResourceType::XHR; 288 case WebSocketResource: 289 return TypeBuilder::Page::ResourceType::WebSocket; 290 case OtherResource: 291 return TypeBuilder::Page::ResourceType::Other; 292 } 293 return TypeBuilder::Page::ResourceType::Other; 294 } 295 296 InspectorPageAgent::ResourceType InspectorPageAgent::cachedResourceType(const Resource& cachedResource) 297 { 298 switch (cachedResource.type()) { 299 case Resource::Image: 300 return InspectorPageAgent::ImageResource; 301 case Resource::Font: 302 return InspectorPageAgent::FontResource; 303 case Resource::Media: 304 return InspectorPageAgent::MediaResource; 305 case Resource::TextTrack: 306 return InspectorPageAgent::TextTrackResource; 307 case Resource::CSSStyleSheet: 308 // Fall through. 309 case Resource::XSLStyleSheet: 310 return InspectorPageAgent::StylesheetResource; 311 case Resource::Script: 312 return InspectorPageAgent::ScriptResource; 313 case Resource::Raw: 314 return InspectorPageAgent::XHRResource; 315 case Resource::ImportResource: 316 // Fall through. 317 case Resource::MainResource: 318 return InspectorPageAgent::DocumentResource; 319 default: 320 break; 321 } 322 return InspectorPageAgent::OtherResource; 323 } 324 325 TypeBuilder::Page::ResourceType::Enum InspectorPageAgent::cachedResourceTypeJson(const Resource& cachedResource) 326 { 327 return resourceTypeJson(cachedResourceType(cachedResource)); 328 } 329 330 InspectorPageAgent::InspectorPageAgent(Page* page, InjectedScriptManager* injectedScriptManager, InspectorClient* client, InspectorOverlay* overlay) 331 : InspectorBaseAgent<InspectorPageAgent>("Page") 332 , m_page(page) 333 , m_injectedScriptManager(injectedScriptManager) 334 , m_client(client) 335 , m_frontend(0) 336 , m_overlay(overlay) 337 , m_lastScriptIdentifier(0) 338 , m_enabled(false) 339 , m_ignoreScriptsEnabledNotification(false) 340 , m_deviceMetricsOverridden(false) 341 , m_emulateViewportEnabled(false) 342 , m_touchEmulationEnabled(false) 343 , m_originalTouchEnabled(false) 344 , m_originalDeviceSupportsMouse(false) 345 , m_originalDeviceSupportsTouch(false) 346 , m_embedderTextAutosizingEnabled(m_page->settings().textAutosizingEnabled()) 347 , m_embedderFontScaleFactor(m_page->settings().deviceScaleAdjustment()) 348 { 349 } 350 351 void InspectorPageAgent::setTextAutosizingEnabled(bool enabled) 352 { 353 m_embedderTextAutosizingEnabled = enabled; 354 if (!m_deviceMetricsOverridden) 355 m_page->settings().setTextAutosizingEnabled(enabled); 356 } 357 358 void InspectorPageAgent::setDeviceScaleAdjustment(float deviceScaleAdjustment) 359 { 360 m_embedderFontScaleFactor = deviceScaleAdjustment; 361 if (!m_deviceMetricsOverridden) 362 m_page->settings().setDeviceScaleAdjustment(deviceScaleAdjustment); 363 } 364 365 void InspectorPageAgent::setFrontend(InspectorFrontend* frontend) 366 { 367 m_frontend = frontend->page(); 368 } 369 370 void InspectorPageAgent::clearFrontend() 371 { 372 ErrorString error; 373 disable(&error); 374 m_frontend = 0; 375 } 376 377 void InspectorPageAgent::restore() 378 { 379 if (m_state->getBoolean(PageAgentState::pageAgentEnabled)) { 380 ErrorString error; 381 enable(&error); 382 bool scriptExecutionDisabled = m_state->getBoolean(PageAgentState::pageAgentScriptExecutionDisabled); 383 setScriptExecutionDisabled(0, scriptExecutionDisabled); 384 bool showPaintRects = m_state->getBoolean(PageAgentState::pageAgentShowPaintRects); 385 setShowPaintRects(0, showPaintRects); 386 bool showDebugBorders = m_state->getBoolean(PageAgentState::pageAgentShowDebugBorders); 387 setShowDebugBorders(0, showDebugBorders); 388 bool showFPSCounter = m_state->getBoolean(PageAgentState::pageAgentShowFPSCounter); 389 setShowFPSCounter(0, showFPSCounter); 390 String emulatedMedia = m_state->getString(PageAgentState::pageAgentEmulatedMedia); 391 setEmulatedMedia(0, emulatedMedia); 392 bool continuousPaintingEnabled = m_state->getBoolean(PageAgentState::pageAgentContinuousPaintingEnabled); 393 setContinuousPaintingEnabled(0, continuousPaintingEnabled); 394 bool showScrollBottleneckRects = m_state->getBoolean(PageAgentState::pageAgentShowScrollBottleneckRects); 395 setShowScrollBottleneckRects(0, showScrollBottleneckRects); 396 397 updateViewMetricsFromState(); 398 updateTouchEventEmulationInPage(m_state->getBoolean(PageAgentState::touchEventEmulationEnabled)); 399 } 400 } 401 402 void InspectorPageAgent::enable(ErrorString*) 403 { 404 m_enabled = true; 405 m_state->setBoolean(PageAgentState::pageAgentEnabled, true); 406 m_instrumentingAgents->setInspectorPageAgent(this); 407 m_inspectorResourceContentLoader = adoptPtr(new InspectorResourceContentLoader(m_page)); 408 } 409 410 void InspectorPageAgent::disable(ErrorString*) 411 { 412 m_enabled = false; 413 m_state->setBoolean(PageAgentState::pageAgentEnabled, false); 414 m_state->remove(PageAgentState::pageAgentScriptsToEvaluateOnLoad); 415 m_overlay->hide(); 416 m_instrumentingAgents->setInspectorPageAgent(0); 417 m_inspectorResourceContentLoader.clear(); 418 m_deviceMetricsOverridden = false; 419 420 setShowPaintRects(0, false); 421 setShowDebugBorders(0, false); 422 setShowFPSCounter(0, false); 423 setEmulatedMedia(0, String()); 424 if (m_state->getBoolean(PageAgentState::pageAgentContinuousPaintingEnabled)) 425 setContinuousPaintingEnabled(0, false); 426 setShowScrollBottleneckRects(0, false); 427 setShowViewportSizeOnResize(0, false, 0); 428 429 if (m_state->getBoolean(PageAgentState::touchEventEmulationEnabled)) { 430 updateTouchEventEmulationInPage(false); 431 m_state->setBoolean(PageAgentState::touchEventEmulationEnabled, false); 432 } 433 434 if (!deviceMetricsChanged(false, 0, 0, 0, false, false, 1, false)) 435 return; 436 437 // When disabling the agent, reset the override values if necessary. 438 updateViewMetrics(false, 0, 0, 0, false, false, m_embedderFontScaleFactor, m_embedderTextAutosizingEnabled); 439 m_state->setLong(PageAgentState::pageAgentScreenWidthOverride, 0); 440 m_state->setLong(PageAgentState::pageAgentScreenHeightOverride, 0); 441 m_state->setDouble(PageAgentState::pageAgentDeviceScaleFactorOverride, 0); 442 m_state->setBoolean(PageAgentState::pageAgentEmulateViewport, false); 443 m_state->setBoolean(PageAgentState::pageAgentFitWindow, false); 444 m_state->setDouble(PageAgentState::fontScaleFactor, 1); 445 m_state->setBoolean(PageAgentState::pageAgentTextAutosizingOverride, false); 446 } 447 448 void InspectorPageAgent::addScriptToEvaluateOnLoad(ErrorString*, const String& source, String* identifier) 449 { 450 RefPtr<JSONObject> scripts = m_state->getObject(PageAgentState::pageAgentScriptsToEvaluateOnLoad); 451 if (!scripts) { 452 scripts = JSONObject::create(); 453 m_state->setObject(PageAgentState::pageAgentScriptsToEvaluateOnLoad, scripts); 454 } 455 // Assure we don't override existing ids -- m_lastScriptIdentifier could get out of sync WRT actual 456 // scripts once we restored the scripts from the cookie during navigation. 457 do { 458 *identifier = String::number(++m_lastScriptIdentifier); 459 } while (scripts->find(*identifier) != scripts->end()); 460 scripts->setString(*identifier, source); 461 462 // Force cookie serialization. 463 m_state->setObject(PageAgentState::pageAgentScriptsToEvaluateOnLoad, scripts); 464 } 465 466 void InspectorPageAgent::removeScriptToEvaluateOnLoad(ErrorString* error, const String& identifier) 467 { 468 RefPtr<JSONObject> scripts = m_state->getObject(PageAgentState::pageAgentScriptsToEvaluateOnLoad); 469 if (!scripts || scripts->find(identifier) == scripts->end()) { 470 *error = "Script not found"; 471 return; 472 } 473 scripts->remove(identifier); 474 } 475 476 void InspectorPageAgent::reload(ErrorString*, const bool* const optionalIgnoreCache, const String* optionalScriptToEvaluateOnLoad, const String* optionalScriptPreprocessor) 477 { 478 m_pendingScriptToEvaluateOnLoadOnce = optionalScriptToEvaluateOnLoad ? *optionalScriptToEvaluateOnLoad : ""; 479 m_pendingScriptPreprocessor = optionalScriptPreprocessor ? *optionalScriptPreprocessor : ""; 480 m_page->deprecatedLocalMainFrame()->loader().reload(optionalIgnoreCache && *optionalIgnoreCache ? EndToEndReload : NormalReload); 481 } 482 483 void InspectorPageAgent::navigate(ErrorString*, const String& url) 484 { 485 UserGestureIndicator indicator(DefinitelyProcessingNewUserGesture); 486 LocalFrame* frame = m_page->deprecatedLocalMainFrame(); 487 FrameLoadRequest request(frame->document(), ResourceRequest(frame->document()->completeURL(url))); 488 frame->loader().load(request); 489 } 490 491 static PassRefPtr<TypeBuilder::Page::Cookie> buildObjectForCookie(const Cookie& cookie) 492 { 493 return TypeBuilder::Page::Cookie::create() 494 .setName(cookie.name) 495 .setValue(cookie.value) 496 .setDomain(cookie.domain) 497 .setPath(cookie.path) 498 .setExpires(cookie.expires) 499 .setSize((cookie.name.length() + cookie.value.length())) 500 .setHttpOnly(cookie.httpOnly) 501 .setSecure(cookie.secure) 502 .setSession(cookie.session) 503 .release(); 504 } 505 506 static PassRefPtr<TypeBuilder::Array<TypeBuilder::Page::Cookie> > buildArrayForCookies(ListHashSet<Cookie>& cookiesList) 507 { 508 RefPtr<TypeBuilder::Array<TypeBuilder::Page::Cookie> > cookies = TypeBuilder::Array<TypeBuilder::Page::Cookie>::create(); 509 510 ListHashSet<Cookie>::iterator end = cookiesList.end(); 511 ListHashSet<Cookie>::iterator it = cookiesList.begin(); 512 for (int i = 0; it != end; ++it, i++) 513 cookies->addItem(buildObjectForCookie(*it)); 514 515 return cookies; 516 } 517 518 static void cachedResourcesForDocument(Document* document, Vector<Resource*>& result) 519 { 520 const ResourceFetcher::DocumentResourceMap& allResources = document->fetcher()->allResources(); 521 ResourceFetcher::DocumentResourceMap::const_iterator end = allResources.end(); 522 for (ResourceFetcher::DocumentResourceMap::const_iterator it = allResources.begin(); it != end; ++it) { 523 Resource* cachedResource = it->value.get(); 524 525 switch (cachedResource->type()) { 526 case Resource::Image: 527 // Skip images that were not auto loaded (images disabled in the user agent). 528 if (toImageResource(cachedResource)->stillNeedsLoad()) 529 continue; 530 break; 531 case Resource::Font: 532 // Skip fonts that were referenced in CSS but never used/downloaded. 533 if (toFontResource(cachedResource)->stillNeedsLoad()) 534 continue; 535 break; 536 default: 537 // All other Resource types download immediately. 538 break; 539 } 540 541 result.append(cachedResource); 542 } 543 } 544 545 // static 546 Vector<Document*> InspectorPageAgent::importsForFrame(LocalFrame* frame) 547 { 548 Vector<Document*> result; 549 Document* rootDocument = frame->document(); 550 551 if (HTMLImportsController* controller = rootDocument->importsController()) { 552 for (size_t i = 0; i < controller->loaderCount(); ++i) { 553 if (Document* document = controller->loaderAt(i)->document()) 554 result.append(document); 555 } 556 } 557 558 return result; 559 } 560 561 static Vector<Resource*> cachedResourcesForFrame(LocalFrame* frame) 562 { 563 Vector<Resource*> result; 564 Document* rootDocument = frame->document(); 565 Vector<Document*> loaders = InspectorPageAgent::importsForFrame(frame); 566 567 cachedResourcesForDocument(rootDocument, result); 568 for (size_t i = 0; i < loaders.size(); ++i) 569 cachedResourcesForDocument(loaders[i], result); 570 571 return result; 572 } 573 574 static Vector<KURL> allResourcesURLsForFrame(LocalFrame* frame) 575 { 576 Vector<KURL> result; 577 578 result.append(urlWithoutFragment(frame->loader().documentLoader()->url())); 579 580 Vector<Resource*> allResources = cachedResourcesForFrame(frame); 581 for (Vector<Resource*>::const_iterator it = allResources.begin(); it != allResources.end(); ++it) 582 result.append(urlWithoutFragment((*it)->url())); 583 584 return result; 585 } 586 587 void InspectorPageAgent::getCookies(ErrorString*, RefPtr<TypeBuilder::Array<TypeBuilder::Page::Cookie> >& cookies) 588 { 589 ListHashSet<Cookie> rawCookiesList; 590 591 for (Frame* frame = mainFrame(); frame; frame = frame->tree().traverseNext(mainFrame())) { 592 if (!frame->isLocalFrame()) 593 continue; 594 Document* document = toLocalFrame(frame)->document(); 595 Vector<KURL> allURLs = allResourcesURLsForFrame(toLocalFrame(frame)); 596 for (Vector<KURL>::const_iterator it = allURLs.begin(); it != allURLs.end(); ++it) { 597 Vector<Cookie> docCookiesList; 598 getRawCookies(document, *it, docCookiesList); 599 int cookiesSize = docCookiesList.size(); 600 for (int i = 0; i < cookiesSize; i++) { 601 if (!rawCookiesList.contains(docCookiesList[i])) 602 rawCookiesList.add(docCookiesList[i]); 603 } 604 } 605 } 606 607 cookies = buildArrayForCookies(rawCookiesList); 608 } 609 610 void InspectorPageAgent::deleteCookie(ErrorString*, const String& cookieName, const String& url) 611 { 612 KURL parsedURL(ParsedURLString, url); 613 for (Frame* frame = m_page->mainFrame(); frame; frame = frame->tree().traverseNext(m_page->mainFrame())) { 614 if (frame->isLocalFrame()) 615 WebCore::deleteCookie(toLocalFrame(frame)->document(), parsedURL, cookieName); 616 } 617 } 618 619 void InspectorPageAgent::getResourceTree(ErrorString*, RefPtr<TypeBuilder::Page::FrameResourceTree>& object) 620 { 621 object = buildObjectForFrameTree(m_page->deprecatedLocalMainFrame()); 622 } 623 624 void InspectorPageAgent::getResourceContent(ErrorString* errorString, const String& frameId, const String& url, String* content, bool* base64Encoded) 625 { 626 LocalFrame* frame = assertFrame(errorString, frameId); 627 if (!frame) 628 return; 629 resourceContent(errorString, frame, KURL(ParsedURLString, url), content, base64Encoded); 630 } 631 632 static bool textContentForResource(Resource* cachedResource, String* result) 633 { 634 if (hasTextContent(cachedResource)) { 635 String content; 636 bool base64Encoded; 637 if (InspectorPageAgent::cachedResourceContent(cachedResource, result, &base64Encoded)) { 638 ASSERT(!base64Encoded); 639 return true; 640 } 641 } 642 return false; 643 } 644 645 void 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) 646 { 647 results = TypeBuilder::Array<TypeBuilder::Page::SearchMatch>::create(); 648 649 bool isRegex = optionalIsRegex ? *optionalIsRegex : false; 650 bool caseSensitive = optionalCaseSensitive ? *optionalCaseSensitive : false; 651 652 LocalFrame* frame = frameForId(frameId); 653 KURL kurl(ParsedURLString, url); 654 655 FrameLoader* frameLoader = frame ? &frame->loader() : 0; 656 DocumentLoader* loader = frameLoader ? frameLoader->documentLoader() : 0; 657 if (!loader) 658 return; 659 660 String content; 661 bool success = false; 662 Resource* resource = cachedResource(frame, kurl); 663 if (resource) 664 success = textContentForResource(resource, &content); 665 666 if (!success) 667 return; 668 669 results = ContentSearchUtils::searchInTextByLines(content, query, caseSensitive, isRegex); 670 } 671 672 void InspectorPageAgent::setDocumentContent(ErrorString* errorString, const String& frameId, const String& html) 673 { 674 LocalFrame* frame = assertFrame(errorString, frameId); 675 if (!frame) 676 return; 677 678 Document* document = frame->document(); 679 if (!document) { 680 *errorString = "No Document instance to set HTML for"; 681 return; 682 } 683 DOMPatchSupport::patchDocument(*document, html); 684 } 685 686 void InspectorPageAgent::setDeviceMetricsOverride(ErrorString* errorString, int width, int height, double deviceScaleFactor, bool emulateViewport, bool fitWindow, const bool* optionalTextAutosizing, const double* optionalFontScaleFactor) 687 { 688 const static long maxDimension = 10000000; 689 690 bool textAutosizing = optionalTextAutosizing ? *optionalTextAutosizing : false; 691 double fontScaleFactor = optionalFontScaleFactor ? *optionalFontScaleFactor : 1; 692 693 if (width < 0 || height < 0 || width > maxDimension || height > maxDimension) { 694 *errorString = "Width and height values must be positive, not greater than " + String::number(maxDimension); 695 return; 696 } 697 698 if (deviceScaleFactor < 0) { 699 *errorString = "deviceScaleFactor must be non-negative"; 700 return; 701 } 702 703 if (fontScaleFactor <= 0) { 704 *errorString = "fontScaleFactor must be positive"; 705 return; 706 } 707 708 Settings& settings = m_page->settings(); 709 if (!settings.acceleratedCompositingEnabled()) { 710 if (errorString) 711 *errorString = "Compositing mode is not supported"; 712 return; 713 } 714 715 if (!deviceMetricsChanged(true, width, height, deviceScaleFactor, emulateViewport, fitWindow, fontScaleFactor, textAutosizing)) 716 return; 717 718 m_state->setBoolean(PageAgentState::deviceMetricsOverrideEnabled, true); 719 m_state->setLong(PageAgentState::pageAgentScreenWidthOverride, width); 720 m_state->setLong(PageAgentState::pageAgentScreenHeightOverride, height); 721 m_state->setDouble(PageAgentState::pageAgentDeviceScaleFactorOverride, deviceScaleFactor); 722 m_state->setBoolean(PageAgentState::pageAgentEmulateViewport, emulateViewport); 723 m_state->setBoolean(PageAgentState::pageAgentFitWindow, fitWindow); 724 m_state->setDouble(PageAgentState::fontScaleFactor, fontScaleFactor); 725 m_state->setBoolean(PageAgentState::pageAgentTextAutosizingOverride, textAutosizing); 726 updateViewMetricsFromState(); 727 } 728 729 void InspectorPageAgent::clearDeviceMetricsOverride(ErrorString*) 730 { 731 if (m_state->getBoolean(PageAgentState::deviceMetricsOverrideEnabled)) { 732 m_state->setBoolean(PageAgentState::deviceMetricsOverrideEnabled, false); 733 updateViewMetricsFromState(); 734 } 735 } 736 737 bool InspectorPageAgent::deviceMetricsChanged(bool enabled, int width, int height, double deviceScaleFactor, bool emulateViewport, bool fitWindow, double fontScaleFactor, bool textAutosizing) 738 { 739 bool currentEnabled = m_state->getBoolean(PageAgentState::deviceMetricsOverrideEnabled); 740 // These two always fit an int. 741 int currentWidth = static_cast<int>(m_state->getLong(PageAgentState::pageAgentScreenWidthOverride)); 742 int currentHeight = static_cast<int>(m_state->getLong(PageAgentState::pageAgentScreenHeightOverride)); 743 double currentDeviceScaleFactor = m_state->getDouble(PageAgentState::pageAgentDeviceScaleFactorOverride, 0); 744 bool currentEmulateViewport = m_state->getBoolean(PageAgentState::pageAgentEmulateViewport); 745 bool currentFitWindow = m_state->getBoolean(PageAgentState::pageAgentFitWindow); 746 double currentFontScaleFactor = m_state->getDouble(PageAgentState::fontScaleFactor, 1); 747 bool currentTextAutosizing = m_state->getBoolean(PageAgentState::pageAgentTextAutosizingOverride); 748 749 return enabled != currentEnabled 750 || width != currentWidth 751 || height != currentHeight 752 || deviceScaleFactor != currentDeviceScaleFactor 753 || emulateViewport != currentEmulateViewport 754 || fitWindow != currentFitWindow 755 || fontScaleFactor != currentFontScaleFactor 756 || textAutosizing != currentTextAutosizing; 757 } 758 759 void InspectorPageAgent::setShowPaintRects(ErrorString*, bool show) 760 { 761 m_state->setBoolean(PageAgentState::pageAgentShowPaintRects, show); 762 m_client->setShowPaintRects(show); 763 764 if (!show && mainFrame() && mainFrame()->view()) 765 mainFrame()->view()->invalidate(); 766 } 767 768 void InspectorPageAgent::setShowDebugBorders(ErrorString* errorString, bool show) 769 { 770 m_state->setBoolean(PageAgentState::pageAgentShowDebugBorders, show); 771 if (show && !compositingEnabled(errorString)) 772 return; 773 m_client->setShowDebugBorders(show); 774 } 775 776 void InspectorPageAgent::setShowFPSCounter(ErrorString* errorString, bool show) 777 { 778 // FIXME: allow metrics override, fps counter and continuous painting at the same time: crbug.com/299837. 779 m_state->setBoolean(PageAgentState::pageAgentShowFPSCounter, show); 780 if (show && !compositingEnabled(errorString)) 781 return; 782 m_client->setShowFPSCounter(show && !m_deviceMetricsOverridden); 783 } 784 785 void InspectorPageAgent::setContinuousPaintingEnabled(ErrorString* errorString, bool enabled) 786 { 787 m_state->setBoolean(PageAgentState::pageAgentContinuousPaintingEnabled, enabled); 788 if (enabled && !compositingEnabled(errorString)) 789 return; 790 m_client->setContinuousPaintingEnabled(enabled && !m_deviceMetricsOverridden); 791 } 792 793 void InspectorPageAgent::setShowScrollBottleneckRects(ErrorString* errorString, bool show) 794 { 795 m_state->setBoolean(PageAgentState::pageAgentShowScrollBottleneckRects, show); 796 if (show && !compositingEnabled(errorString)) 797 return; 798 m_client->setShowScrollBottleneckRects(show); 799 } 800 801 void InspectorPageAgent::getScriptExecutionStatus(ErrorString*, PageCommandHandler::Result::Enum* status) 802 { 803 bool disabledByScriptController = false; 804 bool disabledInSettings = false; 805 LocalFrame* frame = mainFrame(); 806 if (frame) { 807 disabledByScriptController = !frame->script().canExecuteScripts(NotAboutToExecuteScript); 808 if (frame->settings()) 809 disabledInSettings = !frame->settings()->scriptEnabled(); 810 } 811 812 // Order is important. 813 if (disabledInSettings) 814 *status = PageCommandHandler::Result::Disabled; 815 else if (disabledByScriptController) 816 *status = PageCommandHandler::Result::Forbidden; 817 else 818 *status = PageCommandHandler::Result::Allowed; 819 } 820 821 void InspectorPageAgent::setScriptExecutionDisabled(ErrorString*, bool value) 822 { 823 m_state->setBoolean(PageAgentState::pageAgentScriptExecutionDisabled, value); 824 if (!mainFrame()) 825 return; 826 827 Settings* settings = mainFrame()->settings(); 828 if (settings) { 829 m_ignoreScriptsEnabledNotification = true; 830 settings->setScriptEnabled(!value); 831 m_ignoreScriptsEnabledNotification = false; 832 } 833 } 834 835 void InspectorPageAgent::didClearDocumentOfWindowObject(LocalFrame* frame) 836 { 837 if (frame == m_page->mainFrame()) 838 m_injectedScriptManager->discardInjectedScripts(); 839 840 if (!m_frontend) 841 return; 842 843 RefPtr<JSONObject> scripts = m_state->getObject(PageAgentState::pageAgentScriptsToEvaluateOnLoad); 844 if (scripts) { 845 JSONObject::const_iterator end = scripts->end(); 846 for (JSONObject::const_iterator it = scripts->begin(); it != end; ++it) { 847 String scriptText; 848 if (it->value->asString(&scriptText)) 849 frame->script().executeScriptInMainWorld(scriptText); 850 } 851 } 852 if (!m_scriptToEvaluateOnLoadOnce.isEmpty()) 853 frame->script().executeScriptInMainWorld(m_scriptToEvaluateOnLoadOnce); 854 } 855 856 void InspectorPageAgent::domContentLoadedEventFired(LocalFrame* frame) 857 { 858 if (!frame->isMainFrame()) 859 return; 860 m_frontend->domContentEventFired(currentTime()); 861 } 862 863 void InspectorPageAgent::loadEventFired(LocalFrame* frame) 864 { 865 if (!frame->isMainFrame()) 866 return; 867 m_frontend->loadEventFired(currentTime()); 868 } 869 870 void InspectorPageAgent::didCommitLoad(LocalFrame*, DocumentLoader* loader) 871 { 872 // FIXME: If "frame" is always guaranteed to be in the same Page as loader->frame() 873 // then all we need to check here is loader->frame()->isMainFrame() 874 // and we don't need "frame" at all. 875 if (loader->frame() == m_page->mainFrame()) { 876 m_scriptToEvaluateOnLoadOnce = m_pendingScriptToEvaluateOnLoadOnce; 877 m_scriptPreprocessorSource = m_pendingScriptPreprocessor; 878 m_pendingScriptToEvaluateOnLoadOnce = String(); 879 m_pendingScriptPreprocessor = String(); 880 if (m_inspectorResourceContentLoader) 881 m_inspectorResourceContentLoader->stop(); 882 } 883 m_frontend->frameNavigated(buildObjectForFrame(loader->frame())); 884 } 885 886 void InspectorPageAgent::frameAttachedToParent(LocalFrame* frame) 887 { 888 Frame* parentFrame = frame->tree().parent(); 889 if (!parentFrame->isLocalFrame()) 890 parentFrame = 0; 891 m_frontend->frameAttached(frameId(frame), frameId(toLocalFrame(parentFrame))); 892 } 893 894 void InspectorPageAgent::frameDetachedFromParent(LocalFrame* frame) 895 { 896 HashMap<LocalFrame*, String>::iterator iterator = m_frameToIdentifier.find(frame); 897 if (iterator != m_frameToIdentifier.end()) { 898 m_frontend->frameDetached(iterator->value); 899 m_identifierToFrame.remove(iterator->value); 900 m_frameToIdentifier.remove(iterator); 901 } 902 } 903 904 LocalFrame* InspectorPageAgent::mainFrame() 905 { 906 return m_page->deprecatedLocalMainFrame(); 907 } 908 909 LocalFrame* InspectorPageAgent::frameForId(const String& frameId) 910 { 911 return frameId.isEmpty() ? 0 : m_identifierToFrame.get(frameId); 912 } 913 914 String InspectorPageAgent::frameId(LocalFrame* frame) 915 { 916 if (!frame) 917 return ""; 918 String identifier = m_frameToIdentifier.get(frame); 919 if (identifier.isNull()) { 920 identifier = IdentifiersFactory::createIdentifier(); 921 m_frameToIdentifier.set(frame, identifier); 922 m_identifierToFrame.set(identifier, frame); 923 } 924 return identifier; 925 } 926 927 bool InspectorPageAgent::hasIdForFrame(LocalFrame* frame) const 928 { 929 return frame && m_frameToIdentifier.contains(frame); 930 } 931 932 String InspectorPageAgent::loaderId(DocumentLoader* loader) 933 { 934 if (!loader) 935 return ""; 936 String identifier = m_loaderToIdentifier.get(loader); 937 if (identifier.isNull()) { 938 identifier = IdentifiersFactory::createIdentifier(); 939 m_loaderToIdentifier.set(loader, identifier); 940 } 941 return identifier; 942 } 943 944 LocalFrame* InspectorPageAgent::findFrameWithSecurityOrigin(const String& originRawString) 945 { 946 for (Frame* frame = m_page->mainFrame(); frame; frame = frame->tree().traverseNext()) { 947 // FIXME: RemoteFrame security origins are not yet available. 948 if (!frame->isLocalFrame()) 949 continue; 950 RefPtr<SecurityOrigin> documentOrigin = toLocalFrame(frame)->document()->securityOrigin(); 951 if (documentOrigin->toRawString() == originRawString) 952 return toLocalFrame(frame); 953 } 954 return 0; 955 } 956 957 LocalFrame* InspectorPageAgent::assertFrame(ErrorString* errorString, const String& frameId) 958 { 959 LocalFrame* frame = frameForId(frameId); 960 if (!frame) 961 *errorString = "No frame for given id found"; 962 return frame; 963 } 964 965 const AtomicString& InspectorPageAgent::resourceSourceMapURL(const String& url) 966 { 967 DEFINE_STATIC_LOCAL(const AtomicString, sourceMapHttpHeader, ("SourceMap", AtomicString::ConstructFromLiteral)); 968 DEFINE_STATIC_LOCAL(const AtomicString, deprecatedSourceMapHttpHeader, ("X-SourceMap", AtomicString::ConstructFromLiteral)); 969 if (url.isEmpty()) 970 return nullAtom; 971 LocalFrame* frame = mainFrame(); 972 if (!frame) 973 return nullAtom; 974 Resource* resource = cachedResource(frame, KURL(ParsedURLString, url)); 975 if (!resource) 976 return nullAtom; 977 const AtomicString& deprecatedHeaderSourceMapURL = resource->response().httpHeaderField(deprecatedSourceMapHttpHeader); 978 if (!deprecatedHeaderSourceMapURL.isEmpty()) { 979 // FIXME: add deprecated console message here. 980 return deprecatedHeaderSourceMapURL; 981 } 982 return resource->response().httpHeaderField(sourceMapHttpHeader); 983 } 984 985 bool InspectorPageAgent::deviceMetricsOverrideEnabled() 986 { 987 return m_enabled && m_deviceMetricsOverridden; 988 } 989 990 // static 991 DocumentLoader* InspectorPageAgent::assertDocumentLoader(ErrorString* errorString, LocalFrame* frame) 992 { 993 DocumentLoader* documentLoader = frame->loader().documentLoader(); 994 if (!documentLoader) 995 *errorString = "No documentLoader for given frame found"; 996 return documentLoader; 997 } 998 999 void InspectorPageAgent::loaderDetachedFromFrame(DocumentLoader* loader) 1000 { 1001 HashMap<DocumentLoader*, String>::iterator iterator = m_loaderToIdentifier.find(loader); 1002 if (iterator != m_loaderToIdentifier.end()) 1003 m_loaderToIdentifier.remove(iterator); 1004 } 1005 1006 void InspectorPageAgent::frameStartedLoading(LocalFrame* frame) 1007 { 1008 m_frontend->frameStartedLoading(frameId(frame)); 1009 } 1010 1011 void InspectorPageAgent::frameStoppedLoading(LocalFrame* frame) 1012 { 1013 m_frontend->frameStoppedLoading(frameId(frame)); 1014 } 1015 1016 void InspectorPageAgent::frameScheduledNavigation(LocalFrame* frame, double delay) 1017 { 1018 m_frontend->frameScheduledNavigation(frameId(frame), delay); 1019 } 1020 1021 void InspectorPageAgent::frameClearedScheduledNavigation(LocalFrame* frame) 1022 { 1023 m_frontend->frameClearedScheduledNavigation(frameId(frame)); 1024 } 1025 1026 void InspectorPageAgent::willRunJavaScriptDialog(const String& message) 1027 { 1028 m_frontend->javascriptDialogOpening(message); 1029 } 1030 1031 void InspectorPageAgent::didRunJavaScriptDialog() 1032 { 1033 m_frontend->javascriptDialogClosed(); 1034 } 1035 1036 void InspectorPageAgent::didPaint(RenderObject*, const GraphicsLayer*, GraphicsContext* context, const LayoutRect& rect) 1037 { 1038 if (!m_enabled || m_client->overridesShowPaintRects() || !m_state->getBoolean(PageAgentState::pageAgentShowPaintRects)) 1039 return; 1040 1041 static int colorSelector = 0; 1042 const Color colors[] = { 1043 Color(0, 0x5F, 0, 0x3F), 1044 Color(0, 0xAF, 0, 0x3F), 1045 Color(0, 0xFF, 0, 0x3F), 1046 }; 1047 1048 LayoutRect inflatedRect(rect); 1049 inflatedRect.inflate(-1); 1050 m_overlay->drawOutline(context, inflatedRect, colors[colorSelector++ % WTF_ARRAY_LENGTH(colors)]); 1051 } 1052 1053 void InspectorPageAgent::didLayout(RenderObject*) 1054 { 1055 if (!m_enabled) 1056 return; 1057 m_overlay->update(); 1058 } 1059 1060 void InspectorPageAgent::didScroll() 1061 { 1062 if (m_enabled) 1063 m_overlay->update(); 1064 } 1065 1066 void InspectorPageAgent::didResizeMainFrame() 1067 { 1068 #if !OS(ANDROID) 1069 if (m_enabled && m_state->getBoolean(PageAgentState::showSizeOnResize)) 1070 m_overlay->showAndHideViewSize(m_state->getBoolean(PageAgentState::showGridOnResize)); 1071 #endif 1072 m_frontend->frameResized(); 1073 } 1074 1075 void InspectorPageAgent::didRecalculateStyle(int) 1076 { 1077 if (m_enabled) 1078 m_overlay->update(); 1079 } 1080 1081 void InspectorPageAgent::scriptsEnabled(bool isEnabled) 1082 { 1083 if (m_ignoreScriptsEnabledNotification) 1084 return; 1085 1086 m_frontend->scriptsEnabled(isEnabled); 1087 } 1088 1089 PassRefPtr<TypeBuilder::Page::Frame> InspectorPageAgent::buildObjectForFrame(LocalFrame* frame) 1090 { 1091 RefPtr<TypeBuilder::Page::Frame> frameObject = TypeBuilder::Page::Frame::create() 1092 .setId(frameId(frame)) 1093 .setLoaderId(loaderId(frame->loader().documentLoader())) 1094 .setUrl(urlWithoutFragment(frame->document()->url()).string()) 1095 .setMimeType(frame->loader().documentLoader()->responseMIMEType()) 1096 .setSecurityOrigin(frame->document()->securityOrigin()->toRawString()); 1097 // FIXME: This doesn't work for OOPI. 1098 Frame* parentFrame = frame->tree().parent(); 1099 if (parentFrame && parentFrame->isLocalFrame()) 1100 frameObject->setParentId(frameId(toLocalFrame(parentFrame))); 1101 if (frame->deprecatedLocalOwner()) { 1102 AtomicString name = frame->deprecatedLocalOwner()->getNameAttribute(); 1103 if (name.isEmpty()) 1104 name = frame->deprecatedLocalOwner()->getAttribute(HTMLNames::idAttr); 1105 frameObject->setName(name); 1106 } 1107 1108 return frameObject; 1109 } 1110 1111 PassRefPtr<TypeBuilder::Page::FrameResourceTree> InspectorPageAgent::buildObjectForFrameTree(LocalFrame* frame) 1112 { 1113 RefPtr<TypeBuilder::Page::Frame> frameObject = buildObjectForFrame(frame); 1114 RefPtr<TypeBuilder::Array<TypeBuilder::Page::FrameResourceTree::Resources> > subresources = TypeBuilder::Array<TypeBuilder::Page::FrameResourceTree::Resources>::create(); 1115 RefPtr<TypeBuilder::Page::FrameResourceTree> result = TypeBuilder::Page::FrameResourceTree::create() 1116 .setFrame(frameObject) 1117 .setResources(subresources); 1118 1119 Vector<Resource*> allResources = cachedResourcesForFrame(frame); 1120 for (Vector<Resource*>::const_iterator it = allResources.begin(); it != allResources.end(); ++it) { 1121 Resource* cachedResource = *it; 1122 1123 RefPtr<TypeBuilder::Page::FrameResourceTree::Resources> resourceObject = TypeBuilder::Page::FrameResourceTree::Resources::create() 1124 .setUrl(urlWithoutFragment(cachedResource->url()).string()) 1125 .setType(cachedResourceTypeJson(*cachedResource)) 1126 .setMimeType(cachedResource->response().mimeType()); 1127 if (cachedResource->wasCanceled()) 1128 resourceObject->setCanceled(true); 1129 else if (cachedResource->status() == Resource::LoadError) 1130 resourceObject->setFailed(true); 1131 subresources->addItem(resourceObject); 1132 } 1133 1134 Vector<Document*> allImports = InspectorPageAgent::importsForFrame(frame); 1135 for (Vector<Document*>::const_iterator it = allImports.begin(); it != allImports.end(); ++it) { 1136 Document* import = *it; 1137 RefPtr<TypeBuilder::Page::FrameResourceTree::Resources> resourceObject = TypeBuilder::Page::FrameResourceTree::Resources::create() 1138 .setUrl(urlWithoutFragment(import->url()).string()) 1139 .setType(resourceTypeJson(InspectorPageAgent::DocumentResource)) 1140 .setMimeType(import->suggestedMIMEType()); 1141 subresources->addItem(resourceObject); 1142 } 1143 1144 RefPtr<TypeBuilder::Array<TypeBuilder::Page::FrameResourceTree> > childrenArray; 1145 for (Frame* child = frame->tree().firstChild(); child; child = child->tree().nextSibling()) { 1146 if (!child->isLocalFrame()) 1147 continue; 1148 if (!childrenArray) { 1149 childrenArray = TypeBuilder::Array<TypeBuilder::Page::FrameResourceTree>::create(); 1150 result->setChildFrames(childrenArray); 1151 } 1152 childrenArray->addItem(buildObjectForFrameTree(toLocalFrame(child))); 1153 } 1154 return result; 1155 } 1156 1157 void InspectorPageAgent::updateViewMetricsFromState() 1158 { 1159 bool enabled = m_state->getBoolean(PageAgentState::deviceMetricsOverrideEnabled); 1160 int width = static_cast<int>(m_state->getLong(PageAgentState::pageAgentScreenWidthOverride)); 1161 int height = static_cast<int>(m_state->getLong(PageAgentState::pageAgentScreenHeightOverride)); 1162 bool emulateViewport = m_state->getBoolean(PageAgentState::pageAgentEmulateViewport); 1163 double deviceScaleFactor = m_state->getDouble(PageAgentState::pageAgentDeviceScaleFactorOverride); 1164 bool fitWindow = m_state->getBoolean(PageAgentState::pageAgentFitWindow); 1165 double fontScaleFactor = m_state->getDouble(PageAgentState::fontScaleFactor); 1166 bool textAutosizingEnabled = m_state->getBoolean(PageAgentState::pageAgentTextAutosizingOverride); 1167 updateViewMetrics(enabled, width, height, deviceScaleFactor, emulateViewport, fitWindow, fontScaleFactor, textAutosizingEnabled); 1168 } 1169 1170 void InspectorPageAgent::updateViewMetrics(bool enabled, int width, int height, double deviceScaleFactor, bool emulateViewport, bool fitWindow, double fontScaleFactor, bool textAutosizingEnabled) 1171 { 1172 if (enabled && !m_page->settings().acceleratedCompositingEnabled()) 1173 return; 1174 1175 m_deviceMetricsOverridden = enabled; 1176 m_emulateViewportEnabled = emulateViewport; 1177 if (enabled) 1178 m_client->setDeviceMetricsOverride(width, height, static_cast<float>(deviceScaleFactor), emulateViewport, fitWindow); 1179 else 1180 m_client->clearDeviceMetricsOverride(); 1181 1182 Document* document = mainFrame()->document(); 1183 if (document) { 1184 document->styleResolverChanged(); 1185 document->mediaQueryAffectingValueChanged(); 1186 } 1187 InspectorInstrumentation::mediaQueryResultChanged(document); 1188 1189 if (m_deviceMetricsOverridden) { 1190 m_page->settings().setTextAutosizingEnabled(textAutosizingEnabled); 1191 m_page->settings().setDeviceScaleAdjustment(fontScaleFactor); 1192 } else { 1193 m_page->settings().setTextAutosizingEnabled(m_embedderTextAutosizingEnabled); 1194 m_page->settings().setDeviceScaleAdjustment(m_embedderFontScaleFactor); 1195 } 1196 1197 // FIXME: allow metrics override, fps counter and continuous painting at the same time: crbug.com/299837. 1198 m_client->setShowFPSCounter(m_state->getBoolean(PageAgentState::pageAgentShowFPSCounter) && !m_deviceMetricsOverridden); 1199 m_client->setContinuousPaintingEnabled(m_state->getBoolean(PageAgentState::pageAgentContinuousPaintingEnabled) && !m_deviceMetricsOverridden); 1200 } 1201 1202 void InspectorPageAgent::updateTouchEventEmulationInPage(bool enabled) 1203 { 1204 if (!m_touchEmulationEnabled) { 1205 m_originalTouchEnabled = RuntimeEnabledFeatures::touchEnabled(); 1206 m_originalDeviceSupportsMouse = m_page->settings().deviceSupportsMouse(); 1207 m_originalDeviceSupportsTouch = m_page->settings().deviceSupportsTouch(); 1208 } 1209 RuntimeEnabledFeatures::setTouchEnabled(enabled ? true : m_originalTouchEnabled); 1210 m_page->settings().setDeviceSupportsMouse(enabled ? false : m_originalDeviceSupportsMouse); 1211 m_page->settings().setDeviceSupportsTouch(enabled ? true : m_originalDeviceSupportsTouch); 1212 m_touchEmulationEnabled = enabled; 1213 m_client->setTouchEventEmulationEnabled(enabled); 1214 m_page->deprecatedLocalMainFrame()->view()->layout(); 1215 } 1216 1217 void InspectorPageAgent::hasTouchInputs(ErrorString*, bool* result) 1218 { 1219 *result = m_touchEmulationEnabled ? m_originalDeviceSupportsTouch : m_page->settings().deviceSupportsTouch(); 1220 } 1221 1222 void InspectorPageAgent::setTouchEmulationEnabled(ErrorString* error, bool enabled) 1223 { 1224 if (m_state->getBoolean(PageAgentState::touchEventEmulationEnabled) == enabled) 1225 return; 1226 1227 bool hasTouch = false; 1228 hasTouchInputs(error, &hasTouch); 1229 if (enabled && hasTouch) { 1230 if (error) 1231 *error = "Device already supports touch input"; 1232 return; 1233 } 1234 1235 m_state->setBoolean(PageAgentState::touchEventEmulationEnabled, enabled); 1236 updateTouchEventEmulationInPage(enabled); 1237 } 1238 1239 void InspectorPageAgent::setEmulatedMedia(ErrorString*, const String& media) 1240 { 1241 String currentMedia = m_state->getString(PageAgentState::pageAgentEmulatedMedia); 1242 if (media == currentMedia) 1243 return; 1244 1245 m_state->setString(PageAgentState::pageAgentEmulatedMedia, media); 1246 Document* document = 0; 1247 if (m_page->mainFrame()) 1248 document = m_page->deprecatedLocalMainFrame()->document(); 1249 if (document) { 1250 document->mediaQueryAffectingValueChanged(); 1251 document->styleResolverChanged(); 1252 document->updateLayout(); 1253 } 1254 } 1255 1256 bool InspectorPageAgent::applyViewportStyleOverride(StyleResolver* resolver) 1257 { 1258 if (!m_deviceMetricsOverridden || !m_emulateViewportEnabled) 1259 return false; 1260 1261 RefPtrWillBeRawPtr<StyleSheetContents> styleSheet = StyleSheetContents::create(CSSParserContext(UASheetMode, 0)); 1262 styleSheet->parseString(String(viewportAndroidUserAgentStyleSheet, sizeof(viewportAndroidUserAgentStyleSheet))); 1263 OwnPtrWillBeRawPtr<RuleSet> ruleSet = RuleSet::create(); 1264 ruleSet->addRulesFromSheet(styleSheet.get(), MediaQueryEvaluator("screen")); 1265 resolver->viewportStyleResolver()->collectViewportRules(ruleSet.get(), ViewportStyleResolver::UserAgentOrigin); 1266 return true; 1267 } 1268 1269 void InspectorPageAgent::applyEmulatedMedia(String* media) 1270 { 1271 String emulatedMedia = m_state->getString(PageAgentState::pageAgentEmulatedMedia); 1272 if (!emulatedMedia.isEmpty()) 1273 *media = emulatedMedia; 1274 } 1275 1276 bool InspectorPageAgent::compositingEnabled(ErrorString* errorString) 1277 { 1278 if (!m_page->settings().acceleratedCompositingEnabled()) { 1279 if (errorString) 1280 *errorString = "Compositing mode is not supported"; 1281 return false; 1282 } 1283 return true; 1284 } 1285 1286 void InspectorPageAgent::setShowViewportSizeOnResize(ErrorString*, bool show, const bool* showGrid) 1287 { 1288 m_state->setBoolean(PageAgentState::showSizeOnResize, show); 1289 m_state->setBoolean(PageAgentState::showGridOnResize, showGrid && *showGrid); 1290 } 1291 1292 } // namespace WebCore 1293 1294