Home | History | Annotate | Download | only in inspector
      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