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 6 * are met: 7 * 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of 14 * its contributors may be used to endorse or promote products derived 15 * from this software without specific prior written permission. 16 * 17 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY 18 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 19 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 20 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY 21 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 22 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 23 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 24 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29 #include "config.h" 30 #include "core/inspector/InspectorOverlay.h" 31 32 #include "InspectorOverlayPage.h" 33 #include "V8InspectorOverlayHost.h" 34 #include "bindings/v8/ScriptController.h" 35 #include "bindings/v8/ScriptSourceCode.h" 36 #include "core/dom/Element.h" 37 #include "core/dom/Node.h" 38 #include "core/dom/PseudoElement.h" 39 #include "core/inspector/InspectorClient.h" 40 #include "core/inspector/InspectorOverlayHost.h" 41 #include "core/loader/DocumentLoader.h" 42 #include "core/loader/EmptyClients.h" 43 #include "core/page/Chrome.h" 44 #include "core/page/EventHandler.h" 45 #include "core/frame/Frame.h" 46 #include "core/frame/FrameView.h" 47 #include "core/page/Page.h" 48 #include "core/frame/Settings.h" 49 #include "core/rendering/RenderBoxModelObject.h" 50 #include "core/rendering/RenderInline.h" 51 #include "core/rendering/RenderObject.h" 52 #include "core/rendering/style/RenderStyleConstants.h" 53 #include "platform/JSONValues.h" 54 #include "platform/PlatformMouseEvent.h" 55 #include "platform/graphics/GraphicsContextStateSaver.h" 56 #include "wtf/text/StringBuilder.h" 57 58 namespace WebCore { 59 60 namespace { 61 62 class InspectorOverlayChromeClient: public EmptyChromeClient { 63 public: 64 InspectorOverlayChromeClient(ChromeClient& client, InspectorOverlay* overlay) 65 : m_client(client) 66 , m_overlay(overlay) 67 { } 68 69 virtual void setCursor(const Cursor& cursor) 70 { 71 m_client.setCursor(cursor); 72 } 73 74 virtual void setToolTip(const String& tooltip, TextDirection direction) 75 { 76 m_client.setToolTip(tooltip, direction); 77 } 78 79 virtual void invalidateRootView(const IntRect& rect) 80 { 81 m_overlay->invalidate(); 82 } 83 84 virtual void invalidateContentsAndRootView(const IntRect& rect) 85 { 86 m_overlay->invalidate(); 87 } 88 89 virtual void invalidateContentsForSlowScroll(const IntRect& rect) 90 { 91 m_overlay->invalidate(); 92 } 93 94 private: 95 ChromeClient& m_client; 96 InspectorOverlay* m_overlay; 97 }; 98 99 Path quadToPath(const FloatQuad& quad) 100 { 101 Path quadPath; 102 quadPath.moveTo(quad.p1()); 103 quadPath.addLineTo(quad.p2()); 104 quadPath.addLineTo(quad.p3()); 105 quadPath.addLineTo(quad.p4()); 106 quadPath.closeSubpath(); 107 return quadPath; 108 } 109 110 void drawOutlinedQuad(GraphicsContext* context, const FloatQuad& quad, const Color& fillColor, const Color& outlineColor) 111 { 112 static const int outlineThickness = 2; 113 114 Path quadPath = quadToPath(quad); 115 116 // Clip out the quad, then draw with a 2px stroke to get a pixel 117 // of outline (because inflating a quad is hard) 118 { 119 context->save(); 120 context->clipOut(quadPath); 121 122 context->setStrokeThickness(outlineThickness); 123 context->setStrokeColor(outlineColor); 124 context->strokePath(quadPath); 125 126 context->restore(); 127 } 128 129 // Now do the fill 130 context->setFillColor(fillColor); 131 context->fillPath(quadPath); 132 } 133 134 static void contentsQuadToPage(const FrameView* mainView, const FrameView* view, FloatQuad& quad) 135 { 136 quad.setP1(view->contentsToRootView(roundedIntPoint(quad.p1()))); 137 quad.setP2(view->contentsToRootView(roundedIntPoint(quad.p2()))); 138 quad.setP3(view->contentsToRootView(roundedIntPoint(quad.p3()))); 139 quad.setP4(view->contentsToRootView(roundedIntPoint(quad.p4()))); 140 quad += mainView->scrollOffset(); 141 } 142 143 static bool buildNodeQuads(Node* node, Vector<FloatQuad>& quads) 144 { 145 RenderObject* renderer = node->renderer(); 146 Frame* containingFrame = node->document().frame(); 147 148 if (!renderer || !containingFrame) 149 return false; 150 151 FrameView* containingView = containingFrame->view(); 152 FrameView* mainView = containingFrame->page()->mainFrame()->view(); 153 IntRect boundingBox = pixelSnappedIntRect(containingView->contentsToRootView(renderer->absoluteBoundingBoxRect())); 154 boundingBox.move(mainView->scrollOffset()); 155 156 // RenderSVGRoot should be highlighted through the isBox() code path, all other SVG elements should just dump their absoluteQuads(). 157 if (renderer->node() && renderer->node()->isSVGElement() && !renderer->isSVGRoot()) { 158 renderer->absoluteQuads(quads); 159 for (size_t i = 0; i < quads.size(); ++i) 160 contentsQuadToPage(mainView, containingView, quads[i]); 161 return false; 162 } 163 164 if (!renderer->isBox() && !renderer->isRenderInline()) 165 return false; 166 167 LayoutRect contentBox; 168 LayoutRect paddingBox; 169 LayoutRect borderBox; 170 LayoutRect marginBox; 171 172 if (renderer->isBox()) { 173 RenderBox* renderBox = toRenderBox(renderer); 174 175 // RenderBox returns the "pure" content area box, exclusive of the scrollbars (if present), which also count towards the content area in CSS. 176 contentBox = renderBox->contentBoxRect(); 177 contentBox.setWidth(contentBox.width() + renderBox->verticalScrollbarWidth()); 178 contentBox.setHeight(contentBox.height() + renderBox->horizontalScrollbarHeight()); 179 180 paddingBox = LayoutRect(contentBox.x() - renderBox->paddingLeft(), contentBox.y() - renderBox->paddingTop(), 181 contentBox.width() + renderBox->paddingLeft() + renderBox->paddingRight(), contentBox.height() + renderBox->paddingTop() + renderBox->paddingBottom()); 182 borderBox = LayoutRect(paddingBox.x() - renderBox->borderLeft(), paddingBox.y() - renderBox->borderTop(), 183 paddingBox.width() + renderBox->borderLeft() + renderBox->borderRight(), paddingBox.height() + renderBox->borderTop() + renderBox->borderBottom()); 184 marginBox = LayoutRect(borderBox.x() - renderBox->marginLeft(), borderBox.y() - renderBox->marginTop(), 185 borderBox.width() + renderBox->marginWidth(), borderBox.height() + renderBox->marginHeight()); 186 } else { 187 RenderInline* renderInline = toRenderInline(renderer); 188 189 // RenderInline's bounding box includes paddings and borders, excludes margins. 190 borderBox = renderInline->linesBoundingBox(); 191 paddingBox = LayoutRect(borderBox.x() + renderInline->borderLeft(), borderBox.y() + renderInline->borderTop(), 192 borderBox.width() - renderInline->borderLeft() - renderInline->borderRight(), borderBox.height() - renderInline->borderTop() - renderInline->borderBottom()); 193 contentBox = LayoutRect(paddingBox.x() + renderInline->paddingLeft(), paddingBox.y() + renderInline->paddingTop(), 194 paddingBox.width() - renderInline->paddingLeft() - renderInline->paddingRight(), paddingBox.height() - renderInline->paddingTop() - renderInline->paddingBottom()); 195 // Ignore marginTop and marginBottom for inlines. 196 marginBox = LayoutRect(borderBox.x() - renderInline->marginLeft(), borderBox.y(), 197 borderBox.width() + renderInline->marginWidth(), borderBox.height()); 198 } 199 200 FloatQuad absContentQuad = renderer->localToAbsoluteQuad(FloatRect(contentBox)); 201 FloatQuad absPaddingQuad = renderer->localToAbsoluteQuad(FloatRect(paddingBox)); 202 FloatQuad absBorderQuad = renderer->localToAbsoluteQuad(FloatRect(borderBox)); 203 FloatQuad absMarginQuad = renderer->localToAbsoluteQuad(FloatRect(marginBox)); 204 205 contentsQuadToPage(mainView, containingView, absContentQuad); 206 contentsQuadToPage(mainView, containingView, absPaddingQuad); 207 contentsQuadToPage(mainView, containingView, absBorderQuad); 208 contentsQuadToPage(mainView, containingView, absMarginQuad); 209 210 quads.append(absMarginQuad); 211 quads.append(absBorderQuad); 212 quads.append(absPaddingQuad); 213 quads.append(absContentQuad); 214 215 return true; 216 } 217 218 static void buildNodeHighlight(Node* node, const HighlightConfig& highlightConfig, Highlight* highlight) 219 { 220 RenderObject* renderer = node->renderer(); 221 Frame* containingFrame = node->document().frame(); 222 223 if (!renderer || !containingFrame) 224 return; 225 226 highlight->setDataFromConfig(highlightConfig); 227 228 // RenderSVGRoot should be highlighted through the isBox() code path, all other SVG elements should just dump their absoluteQuads(). 229 if (renderer->node() && renderer->node()->isSVGElement() && !renderer->isSVGRoot()) 230 highlight->type = HighlightTypeRects; 231 else if (renderer->isBox() || renderer->isRenderInline()) 232 highlight->type = HighlightTypeNode; 233 buildNodeQuads(node, highlight->quads); 234 } 235 236 static void buildQuadHighlight(Page* page, const FloatQuad& quad, const HighlightConfig& highlightConfig, Highlight *highlight) 237 { 238 if (!page) 239 return; 240 highlight->setDataFromConfig(highlightConfig); 241 highlight->type = HighlightTypeRects; 242 highlight->quads.append(quad); 243 } 244 245 } // anonymous namespace 246 247 InspectorOverlay::InspectorOverlay(Page* page, InspectorClient* client) 248 : m_page(page) 249 , m_client(client) 250 , m_inspectModeEnabled(false) 251 , m_overlayHost(InspectorOverlayHost::create()) 252 , m_drawViewSize(false) 253 , m_drawViewSizeWithGrid(false) 254 , m_timer(this, &InspectorOverlay::onTimer) 255 , m_activeProfilerCount(0) 256 { 257 } 258 259 InspectorOverlay::~InspectorOverlay() 260 { 261 } 262 263 void InspectorOverlay::paint(GraphicsContext& context) 264 { 265 if (isEmpty()) 266 return; 267 GraphicsContextStateSaver stateSaver(context); 268 FrameView* view = overlayPage()->mainFrame()->view(); 269 ASSERT(!view->needsLayout()); 270 view->paint(&context, IntRect(0, 0, view->width(), view->height())); 271 } 272 273 void InspectorOverlay::invalidate() 274 { 275 m_client->highlight(); 276 } 277 278 bool InspectorOverlay::handleGestureEvent(const PlatformGestureEvent& event) 279 { 280 if (isEmpty()) 281 return false; 282 283 return overlayPage()->mainFrame()->eventHandler().handleGestureEvent(event); 284 } 285 286 bool InspectorOverlay::handleMouseEvent(const PlatformMouseEvent& event) 287 { 288 if (isEmpty()) 289 return false; 290 291 EventHandler& eventHandler = overlayPage()->mainFrame()->eventHandler(); 292 bool result; 293 switch (event.type()) { 294 case PlatformEvent::MouseMoved: 295 result = eventHandler.handleMouseMoveEvent(event); 296 break; 297 case PlatformEvent::MousePressed: 298 result = eventHandler.handleMousePressEvent(event); 299 break; 300 case PlatformEvent::MouseReleased: 301 result = eventHandler.handleMouseReleaseEvent(event); 302 break; 303 default: 304 return false; 305 } 306 307 overlayPage()->mainFrame()->document()->updateLayout(); 308 return result; 309 } 310 311 bool InspectorOverlay::handleTouchEvent(const PlatformTouchEvent& event) 312 { 313 if (isEmpty()) 314 return false; 315 316 return overlayPage()->mainFrame()->eventHandler().handleTouchEvent(event); 317 } 318 319 bool InspectorOverlay::handleKeyboardEvent(const PlatformKeyboardEvent& event) 320 { 321 if (isEmpty()) 322 return false; 323 324 return overlayPage()->mainFrame()->eventHandler().keyEvent(event); 325 } 326 327 void InspectorOverlay::drawOutline(GraphicsContext* context, const LayoutRect& rect, const Color& color) 328 { 329 FloatRect outlineRect = rect; 330 drawOutlinedQuad(context, outlineRect, Color(), color); 331 } 332 333 void InspectorOverlay::getHighlight(Highlight* highlight) const 334 { 335 if (!m_highlightNode && !m_highlightQuad) 336 return; 337 338 highlight->type = HighlightTypeRects; 339 if (m_highlightNode) 340 buildNodeHighlight(m_highlightNode.get(), m_nodeHighlightConfig, highlight); 341 else 342 buildQuadHighlight(m_page, *m_highlightQuad, m_quadHighlightConfig, highlight); 343 } 344 345 void InspectorOverlay::resize(const IntSize& size) 346 { 347 m_size = size; 348 update(); 349 } 350 351 void InspectorOverlay::setPausedInDebuggerMessage(const String* message) 352 { 353 m_pausedInDebuggerMessage = message ? *message : String(); 354 update(); 355 } 356 357 void InspectorOverlay::setInspectModeEnabled(bool enabled) 358 { 359 m_inspectModeEnabled = enabled; 360 update(); 361 } 362 363 void InspectorOverlay::hideHighlight() 364 { 365 m_highlightNode.clear(); 366 m_eventTargetNode.clear(); 367 m_highlightQuad.clear(); 368 update(); 369 } 370 371 void InspectorOverlay::highlightNode(Node* node, Node* eventTarget, const HighlightConfig& highlightConfig) 372 { 373 m_nodeHighlightConfig = highlightConfig; 374 m_highlightNode = node; 375 m_eventTargetNode = eventTarget; 376 update(); 377 } 378 379 void InspectorOverlay::highlightQuad(PassOwnPtr<FloatQuad> quad, const HighlightConfig& highlightConfig) 380 { 381 m_quadHighlightConfig = highlightConfig; 382 m_highlightQuad = quad; 383 update(); 384 } 385 386 void InspectorOverlay::showAndHideViewSize(bool showGrid) 387 { 388 m_drawViewSize = true; 389 m_drawViewSizeWithGrid = showGrid; 390 update(); 391 m_timer.startOneShot(1); 392 } 393 394 Node* InspectorOverlay::highlightedNode() const 395 { 396 return m_highlightNode.get(); 397 } 398 399 bool InspectorOverlay::isEmpty() 400 { 401 if (m_activeProfilerCount) 402 return true; 403 bool hasAlwaysVisibleElements = m_highlightNode || m_eventTargetNode || m_highlightQuad || !m_size.isEmpty() || m_drawViewSize; 404 bool hasInvisibleInInspectModeElements = !m_pausedInDebuggerMessage.isNull(); 405 return !(hasAlwaysVisibleElements || (hasInvisibleInInspectModeElements && !m_inspectModeEnabled)); 406 } 407 408 void InspectorOverlay::update() 409 { 410 if (isEmpty()) { 411 m_client->hideHighlight(); 412 return; 413 } 414 415 FrameView* view = m_page->mainFrame()->view(); 416 if (!view) 417 return; 418 IntRect viewRect = view->visibleContentRect(); 419 FrameView* overlayView = overlayPage()->mainFrame()->view(); 420 421 // Include scrollbars to avoid masking them by the gutter. 422 IntSize frameViewFullSize = view->visibleContentRect(ScrollableArea::IncludeScrollbars).size(); 423 IntSize size = m_size.isEmpty() ? frameViewFullSize : m_size; 424 size.scale(m_page->pageScaleFactor()); 425 overlayView->resize(size); 426 427 // Clear canvas and paint things. 428 reset(size, m_size.isEmpty() ? IntSize() : frameViewFullSize, viewRect.x(), viewRect.y()); 429 430 drawNodeHighlight(); 431 drawQuadHighlight(); 432 if (!m_inspectModeEnabled) 433 drawPausedInDebuggerMessage(); 434 drawViewSize(); 435 436 // Position DOM elements. 437 overlayPage()->mainFrame()->document()->recalcStyle(Force); 438 if (overlayView->needsLayout()) 439 overlayView->layout(); 440 441 // Kick paint. 442 m_client->highlight(); 443 } 444 445 void InspectorOverlay::hide() 446 { 447 m_timer.stop(); 448 m_highlightNode.clear(); 449 m_eventTargetNode.clear(); 450 m_highlightQuad.clear(); 451 m_pausedInDebuggerMessage = String(); 452 m_size = IntSize(); 453 m_drawViewSize = false; 454 m_drawViewSizeWithGrid = false; 455 update(); 456 } 457 458 static PassRefPtr<JSONObject> buildObjectForPoint(const FloatPoint& point) 459 { 460 RefPtr<JSONObject> object = JSONObject::create(); 461 object->setNumber("x", point.x()); 462 object->setNumber("y", point.y()); 463 return object.release(); 464 } 465 466 static PassRefPtr<JSONArray> buildArrayForQuad(const FloatQuad& quad) 467 { 468 RefPtr<JSONArray> array = JSONArray::create(); 469 array->pushObject(buildObjectForPoint(quad.p1())); 470 array->pushObject(buildObjectForPoint(quad.p2())); 471 array->pushObject(buildObjectForPoint(quad.p3())); 472 array->pushObject(buildObjectForPoint(quad.p4())); 473 return array.release(); 474 } 475 476 static PassRefPtr<JSONObject> buildObjectForHighlight(const Highlight& highlight) 477 { 478 RefPtr<JSONObject> object = JSONObject::create(); 479 RefPtr<JSONArray> array = JSONArray::create(); 480 for (size_t i = 0; i < highlight.quads.size(); ++i) 481 array->pushArray(buildArrayForQuad(highlight.quads[i])); 482 object->setArray("quads", array.release()); 483 object->setBoolean("showRulers", highlight.showRulers); 484 object->setString("contentColor", highlight.contentColor.serialized()); 485 object->setString("contentOutlineColor", highlight.contentOutlineColor.serialized()); 486 object->setString("paddingColor", highlight.paddingColor.serialized()); 487 object->setString("borderColor", highlight.borderColor.serialized()); 488 object->setString("marginColor", highlight.marginColor.serialized()); 489 object->setString("eventTargetColor", highlight.eventTargetColor.serialized()); 490 return object.release(); 491 } 492 493 static PassRefPtr<JSONObject> buildObjectForSize(const IntSize& size) 494 { 495 RefPtr<JSONObject> result = JSONObject::create(); 496 result->setNumber("width", size.width()); 497 result->setNumber("height", size.height()); 498 return result.release(); 499 } 500 501 void InspectorOverlay::drawNodeHighlight() 502 { 503 if (!m_highlightNode) 504 return; 505 506 Highlight highlight; 507 buildNodeHighlight(m_highlightNode.get(), m_nodeHighlightConfig, &highlight); 508 if (m_eventTargetNode) { 509 Highlight eventTargetHighlight; 510 buildNodeHighlight(m_eventTargetNode.get(), m_nodeHighlightConfig, &eventTargetHighlight); 511 highlight.quads.append(eventTargetHighlight.quads[1]); // Add border from eventTargetNode to highlight. 512 } 513 RefPtr<JSONObject> highlightObject = buildObjectForHighlight(highlight); 514 515 Node* node = m_highlightNode.get(); 516 if (node->isElementNode() && m_nodeHighlightConfig.showInfo && node->renderer() && node->document().frame()) { 517 RefPtr<JSONObject> elementInfo = JSONObject::create(); 518 Element* element = toElement(node); 519 Element* realElement = element; 520 PseudoElement* pseudoElement = 0; 521 if (element->isPseudoElement()) { 522 pseudoElement = toPseudoElement(element); 523 realElement = element->parentOrShadowHostElement(); 524 } 525 bool isXHTML = realElement->document().isXHTMLDocument(); 526 elementInfo->setString("tagName", isXHTML ? realElement->nodeName() : realElement->nodeName().lower()); 527 elementInfo->setString("idValue", realElement->getIdAttribute()); 528 StringBuilder classNames; 529 if (realElement->hasClass() && realElement->isStyledElement()) { 530 HashSet<AtomicString> usedClassNames; 531 const SpaceSplitString& classNamesString = realElement->classNames(); 532 size_t classNameCount = classNamesString.size(); 533 for (size_t i = 0; i < classNameCount; ++i) { 534 const AtomicString& className = classNamesString[i]; 535 if (!usedClassNames.add(className).isNewEntry) 536 continue; 537 classNames.append('.'); 538 classNames.append(className); 539 } 540 } 541 if (pseudoElement) { 542 if (pseudoElement->pseudoId() == BEFORE) 543 classNames.append("::before"); 544 else if (pseudoElement->pseudoId() == AFTER) 545 classNames.append("::after"); 546 } 547 if (!classNames.isEmpty()) 548 elementInfo->setString("className", classNames.toString()); 549 550 RenderObject* renderer = node->renderer(); 551 Frame* containingFrame = node->document().frame(); 552 FrameView* containingView = containingFrame->view(); 553 IntRect boundingBox = pixelSnappedIntRect(containingView->contentsToRootView(renderer->absoluteBoundingBoxRect())); 554 RenderBoxModelObject* modelObject = renderer->isBoxModelObject() ? toRenderBoxModelObject(renderer) : 0; 555 elementInfo->setString("nodeWidth", String::number(modelObject ? adjustForAbsoluteZoom(modelObject->pixelSnappedOffsetWidth(), modelObject) : boundingBox.width())); 556 elementInfo->setString("nodeHeight", String::number(modelObject ? adjustForAbsoluteZoom(modelObject->pixelSnappedOffsetHeight(), modelObject) : boundingBox.height())); 557 highlightObject->setObject("elementInfo", elementInfo.release()); 558 } 559 evaluateInOverlay("drawNodeHighlight", highlightObject); 560 } 561 562 void InspectorOverlay::drawQuadHighlight() 563 { 564 if (!m_highlightQuad) 565 return; 566 567 Highlight highlight; 568 buildQuadHighlight(m_page, *m_highlightQuad, m_quadHighlightConfig, &highlight); 569 evaluateInOverlay("drawQuadHighlight", buildObjectForHighlight(highlight)); 570 } 571 572 void InspectorOverlay::drawPausedInDebuggerMessage() 573 { 574 if (!m_pausedInDebuggerMessage.isNull()) 575 evaluateInOverlay("drawPausedInDebuggerMessage", m_pausedInDebuggerMessage); 576 } 577 578 void InspectorOverlay::drawViewSize() 579 { 580 if (m_drawViewSize) 581 evaluateInOverlay("drawViewSize", m_drawViewSizeWithGrid ? "true" : "false"); 582 } 583 584 Page* InspectorOverlay::overlayPage() 585 { 586 if (m_overlayPage) 587 return m_overlayPage.get(); 588 589 static FrameLoaderClient* dummyFrameLoaderClient = new EmptyFrameLoaderClient; 590 Page::PageClients pageClients; 591 fillWithEmptyClients(pageClients); 592 ASSERT(!m_overlayChromeClient); 593 m_overlayChromeClient = adoptPtr(new InspectorOverlayChromeClient(m_page->chrome().client(), this)); 594 pageClients.chromeClient = m_overlayChromeClient.get(); 595 m_overlayPage = adoptPtr(new Page(pageClients)); 596 597 Settings& settings = m_page->settings(); 598 Settings& overlaySettings = m_overlayPage->settings(); 599 600 overlaySettings.genericFontFamilySettings().setStandard(settings.genericFontFamilySettings().standard()); 601 overlaySettings.genericFontFamilySettings().setSerif(settings.genericFontFamilySettings().serif()); 602 overlaySettings.genericFontFamilySettings().setSansSerif(settings.genericFontFamilySettings().sansSerif()); 603 overlaySettings.genericFontFamilySettings().setCursive(settings.genericFontFamilySettings().cursive()); 604 overlaySettings.genericFontFamilySettings().setFantasy(settings.genericFontFamilySettings().fantasy()); 605 overlaySettings.genericFontFamilySettings().setPictograph(settings.genericFontFamilySettings().pictograph()); 606 overlaySettings.setMinimumFontSize(settings.minimumFontSize()); 607 overlaySettings.setMinimumLogicalFontSize(settings.minimumLogicalFontSize()); 608 overlaySettings.setMediaEnabled(false); 609 overlaySettings.setScriptEnabled(true); 610 overlaySettings.setPluginsEnabled(false); 611 overlaySettings.setLoadsImagesAutomatically(true); 612 613 RefPtr<Frame> frame = Frame::create(FrameInit::create(0, m_overlayPage.get(), dummyFrameLoaderClient)); 614 frame->setView(FrameView::create(frame.get())); 615 frame->init(); 616 FrameLoader& loader = frame->loader(); 617 frame->view()->setCanHaveScrollbars(false); 618 frame->view()->setTransparent(true); 619 ASSERT(loader.activeDocumentLoader()); 620 DocumentWriter* writer = loader.activeDocumentLoader()->beginWriting("text/html", "UTF-8"); 621 writer->addData(reinterpret_cast<const char*>(InspectorOverlayPage_html), sizeof(InspectorOverlayPage_html)); 622 loader.activeDocumentLoader()->endWriting(writer); 623 v8::Isolate* isolate = toIsolate(frame.get()); 624 v8::HandleScope handleScope(isolate); 625 v8::Handle<v8::Context> frameContext = frame->script().currentWorldContext(); 626 v8::Context::Scope contextScope(frameContext); 627 v8::Handle<v8::Value> overlayHostObj = toV8(m_overlayHost.get(), v8::Handle<v8::Object>(), isolate); 628 v8::Handle<v8::Object> global = frameContext->Global(); 629 global->Set(v8::String::NewFromUtf8(isolate, "InspectorOverlayHost"), overlayHostObj); 630 631 #if OS(WIN) 632 evaluateInOverlay("setPlatform", "windows"); 633 #elif OS(MACOSX) 634 evaluateInOverlay("setPlatform", "mac"); 635 #elif OS(POSIX) 636 evaluateInOverlay("setPlatform", "linux"); 637 #endif 638 639 return m_overlayPage.get(); 640 } 641 642 void InspectorOverlay::reset(const IntSize& viewportSize, const IntSize& frameViewFullSize, int scrollX, int scrollY) 643 { 644 RefPtr<JSONObject> resetData = JSONObject::create(); 645 resetData->setNumber("pageScaleFactor", m_page->pageScaleFactor()); 646 resetData->setNumber("deviceScaleFactor", m_page->deviceScaleFactor()); 647 resetData->setObject("viewportSize", buildObjectForSize(viewportSize)); 648 resetData->setObject("frameViewFullSize", buildObjectForSize(frameViewFullSize)); 649 resetData->setNumber("pageZoomFactor", m_page->mainFrame()->pageZoomFactor()); 650 resetData->setNumber("scrollX", scrollX); 651 resetData->setNumber("scrollY", scrollY); 652 evaluateInOverlay("reset", resetData.release()); 653 } 654 655 void InspectorOverlay::evaluateInOverlay(const String& method, const String& argument) 656 { 657 RefPtr<JSONArray> command = JSONArray::create(); 658 command->pushString(method); 659 command->pushString(argument); 660 overlayPage()->mainFrame()->script().executeScriptInMainWorld("dispatch(" + command->toJSONString() + ")", ScriptController::ExecuteScriptWhenScriptsDisabled); 661 } 662 663 void InspectorOverlay::evaluateInOverlay(const String& method, PassRefPtr<JSONValue> argument) 664 { 665 RefPtr<JSONArray> command = JSONArray::create(); 666 command->pushString(method); 667 command->pushValue(argument); 668 overlayPage()->mainFrame()->script().executeScriptInMainWorld("dispatch(" + command->toJSONString() + ")", ScriptController::ExecuteScriptWhenScriptsDisabled); 669 } 670 671 void InspectorOverlay::onTimer(Timer<InspectorOverlay>*) 672 { 673 m_drawViewSize = false; 674 update(); 675 } 676 677 bool InspectorOverlay::getBoxModel(Node* node, Vector<FloatQuad>* quads) 678 { 679 return buildNodeQuads(node, *quads); 680 } 681 682 void InspectorOverlay::freePage() 683 { 684 m_overlayPage.clear(); 685 m_overlayChromeClient.clear(); 686 m_timer.stop(); 687 } 688 689 void InspectorOverlay::startedRecordingProfile() 690 { 691 if (!m_activeProfilerCount++) 692 freePage(); 693 } 694 695 } // namespace WebCore 696