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 "bindings/core/v8/V8InspectorOverlayHost.h"
     33 #include "bindings/v8/ScriptController.h"
     34 #include "bindings/v8/ScriptSourceCode.h"
     35 #include "core/InspectorOverlayPage.h"
     36 #include "core/dom/Element.h"
     37 #include "core/dom/Node.h"
     38 #include "core/dom/PseudoElement.h"
     39 #include "core/frame/FrameView.h"
     40 #include "core/frame/LocalFrame.h"
     41 #include "core/inspector/InspectorClient.h"
     42 #include "core/inspector/InspectorOverlayHost.h"
     43 #include "core/loader/EmptyClients.h"
     44 #include "core/loader/FrameLoadRequest.h"
     45 #include "core/page/Chrome.h"
     46 #include "core/page/EventHandler.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 #include <v8.h>
     58 
     59 namespace WebCore {
     60 
     61 namespace {
     62 
     63 struct PathApplyInfo {
     64     FrameView* rootView;
     65     FrameView* view;
     66     TypeBuilder::Array<JSONValue>* array;
     67     RenderObject* renderer;
     68     const ShapeOutsideInfo* shapeOutsideInfo;
     69 };
     70 
     71 class InspectorOverlayChromeClient FINAL: public EmptyChromeClient {
     72 public:
     73     InspectorOverlayChromeClient(ChromeClient& client, InspectorOverlay* overlay)
     74         : m_client(client)
     75         , m_overlay(overlay)
     76     { }
     77 
     78     virtual void setCursor(const Cursor& cursor) OVERRIDE
     79     {
     80         m_client.setCursor(cursor);
     81     }
     82 
     83     virtual void setToolTip(const String& tooltip, TextDirection direction) OVERRIDE
     84     {
     85         m_client.setToolTip(tooltip, direction);
     86     }
     87 
     88     virtual void invalidateContentsAndRootView(const IntRect&) OVERRIDE
     89     {
     90         m_overlay->invalidate();
     91     }
     92 
     93     virtual void invalidateContentsForSlowScroll(const IntRect&) OVERRIDE
     94     {
     95         m_overlay->invalidate();
     96     }
     97 
     98 private:
     99     ChromeClient& m_client;
    100     InspectorOverlay* m_overlay;
    101 };
    102 
    103 Path quadToPath(const FloatQuad& quad)
    104 {
    105     Path quadPath;
    106     quadPath.moveTo(quad.p1());
    107     quadPath.addLineTo(quad.p2());
    108     quadPath.addLineTo(quad.p3());
    109     quadPath.addLineTo(quad.p4());
    110     quadPath.closeSubpath();
    111     return quadPath;
    112 }
    113 
    114 void drawOutlinedQuad(GraphicsContext* context, const FloatQuad& quad, const Color& fillColor, const Color& outlineColor)
    115 {
    116     static const int outlineThickness = 2;
    117 
    118     Path quadPath = quadToPath(quad);
    119 
    120     // Clip out the quad, then draw with a 2px stroke to get a pixel
    121     // of outline (because inflating a quad is hard)
    122     {
    123         context->save();
    124         context->clipOut(quadPath);
    125 
    126         context->setStrokeThickness(outlineThickness);
    127         context->setStrokeColor(outlineColor);
    128         context->strokePath(quadPath);
    129 
    130         context->restore();
    131     }
    132 
    133     // Now do the fill
    134     context->setFillColor(fillColor);
    135     context->fillPath(quadPath);
    136 }
    137 
    138 static void contentsQuadToPage(const FrameView* mainView, const FrameView* view, FloatQuad& quad)
    139 {
    140     quad.setP1(view->contentsToRootView(roundedIntPoint(quad.p1())));
    141     quad.setP2(view->contentsToRootView(roundedIntPoint(quad.p2())));
    142     quad.setP3(view->contentsToRootView(roundedIntPoint(quad.p3())));
    143     quad.setP4(view->contentsToRootView(roundedIntPoint(quad.p4())));
    144     quad += mainView->scrollOffset();
    145 }
    146 
    147 static bool buildNodeQuads(Node* node, Vector<FloatQuad>& quads)
    148 {
    149     RenderObject* renderer = node->renderer();
    150     LocalFrame* containingFrame = node->document().frame();
    151 
    152     if (!renderer || !containingFrame)
    153         return false;
    154 
    155     FrameView* containingView = containingFrame->view();
    156     FrameView* mainView = containingFrame->page()->deprecatedLocalMainFrame()->view();
    157     IntRect boundingBox = pixelSnappedIntRect(containingView->contentsToRootView(renderer->absoluteBoundingBoxRect()));
    158     boundingBox.move(mainView->scrollOffset());
    159 
    160     // RenderSVGRoot should be highlighted through the isBox() code path, all other SVG elements should just dump their absoluteQuads().
    161     if (renderer->node() && renderer->node()->isSVGElement() && !renderer->isSVGRoot()) {
    162         renderer->absoluteQuads(quads);
    163         for (size_t i = 0; i < quads.size(); ++i)
    164             contentsQuadToPage(mainView, containingView, quads[i]);
    165         return false;
    166     }
    167 
    168     if (!renderer->isBox() && !renderer->isRenderInline())
    169         return false;
    170 
    171     LayoutRect contentBox;
    172     LayoutRect paddingBox;
    173     LayoutRect borderBox;
    174     LayoutRect marginBox;
    175 
    176     if (renderer->isBox()) {
    177         RenderBox* renderBox = toRenderBox(renderer);
    178 
    179         // RenderBox returns the "pure" content area box, exclusive of the scrollbars (if present), which also count towards the content area in CSS.
    180         contentBox = renderBox->contentBoxRect();
    181         contentBox.setWidth(contentBox.width() + renderBox->verticalScrollbarWidth());
    182         contentBox.setHeight(contentBox.height() + renderBox->horizontalScrollbarHeight());
    183 
    184         paddingBox = LayoutRect(contentBox.x() - renderBox->paddingLeft(), contentBox.y() - renderBox->paddingTop(),
    185             contentBox.width() + renderBox->paddingLeft() + renderBox->paddingRight(), contentBox.height() + renderBox->paddingTop() + renderBox->paddingBottom());
    186         borderBox = LayoutRect(paddingBox.x() - renderBox->borderLeft(), paddingBox.y() - renderBox->borderTop(),
    187             paddingBox.width() + renderBox->borderLeft() + renderBox->borderRight(), paddingBox.height() + renderBox->borderTop() + renderBox->borderBottom());
    188         marginBox = LayoutRect(borderBox.x() - renderBox->marginLeft(), borderBox.y() - renderBox->marginTop(),
    189             borderBox.width() + renderBox->marginWidth(), borderBox.height() + renderBox->marginHeight());
    190     } else {
    191         RenderInline* renderInline = toRenderInline(renderer);
    192 
    193         // RenderInline's bounding box includes paddings and borders, excludes margins.
    194         borderBox = renderInline->linesBoundingBox();
    195         paddingBox = LayoutRect(borderBox.x() + renderInline->borderLeft(), borderBox.y() + renderInline->borderTop(),
    196             borderBox.width() - renderInline->borderLeft() - renderInline->borderRight(), borderBox.height() - renderInline->borderTop() - renderInline->borderBottom());
    197         contentBox = LayoutRect(paddingBox.x() + renderInline->paddingLeft(), paddingBox.y() + renderInline->paddingTop(),
    198             paddingBox.width() - renderInline->paddingLeft() - renderInline->paddingRight(), paddingBox.height() - renderInline->paddingTop() - renderInline->paddingBottom());
    199         // Ignore marginTop and marginBottom for inlines.
    200         marginBox = LayoutRect(borderBox.x() - renderInline->marginLeft(), borderBox.y(),
    201             borderBox.width() + renderInline->marginWidth(), borderBox.height());
    202     }
    203 
    204     FloatQuad absContentQuad = renderer->localToAbsoluteQuad(FloatRect(contentBox));
    205     FloatQuad absPaddingQuad = renderer->localToAbsoluteQuad(FloatRect(paddingBox));
    206     FloatQuad absBorderQuad = renderer->localToAbsoluteQuad(FloatRect(borderBox));
    207     FloatQuad absMarginQuad = renderer->localToAbsoluteQuad(FloatRect(marginBox));
    208 
    209     contentsQuadToPage(mainView, containingView, absContentQuad);
    210     contentsQuadToPage(mainView, containingView, absPaddingQuad);
    211     contentsQuadToPage(mainView, containingView, absBorderQuad);
    212     contentsQuadToPage(mainView, containingView, absMarginQuad);
    213 
    214     quads.append(absMarginQuad);
    215     quads.append(absBorderQuad);
    216     quads.append(absPaddingQuad);
    217     quads.append(absContentQuad);
    218 
    219     return true;
    220 }
    221 
    222 static void buildNodeHighlight(Node* node, const HighlightConfig& highlightConfig, Highlight* highlight)
    223 {
    224     RenderObject* renderer = node->renderer();
    225     LocalFrame* containingFrame = node->document().frame();
    226 
    227     if (!renderer || !containingFrame)
    228         return;
    229 
    230     highlight->setDataFromConfig(highlightConfig);
    231 
    232     // RenderSVGRoot should be highlighted through the isBox() code path, all other SVG elements should just dump their absoluteQuads().
    233     if (renderer->node() && renderer->node()->isSVGElement() && !renderer->isSVGRoot())
    234         highlight->type = HighlightTypeRects;
    235     else if (renderer->isBox() || renderer->isRenderInline())
    236         highlight->type = HighlightTypeNode;
    237     buildNodeQuads(node, highlight->quads);
    238 }
    239 
    240 static void buildQuadHighlight(Page* page, const FloatQuad& quad, const HighlightConfig& highlightConfig, Highlight *highlight)
    241 {
    242     if (!page)
    243         return;
    244     highlight->setDataFromConfig(highlightConfig);
    245     highlight->type = HighlightTypeRects;
    246     highlight->quads.append(quad);
    247 }
    248 
    249 } // anonymous namespace
    250 
    251 InspectorOverlay::InspectorOverlay(Page* page, InspectorClient* client)
    252     : m_page(page)
    253     , m_client(client)
    254     , m_inspectModeEnabled(false)
    255     , m_overlayHost(InspectorOverlayHost::create())
    256     , m_drawViewSize(false)
    257     , m_drawViewSizeWithGrid(false)
    258     , m_omitTooltip(false)
    259     , m_timer(this, &InspectorOverlay::onTimer)
    260     , m_activeProfilerCount(0)
    261 {
    262 }
    263 
    264 InspectorOverlay::~InspectorOverlay()
    265 {
    266     ASSERT(!m_overlayPage);
    267 }
    268 
    269 void InspectorOverlay::paint(GraphicsContext& context)
    270 {
    271     if (isEmpty())
    272         return;
    273     GraphicsContextStateSaver stateSaver(context);
    274     FrameView* view = toLocalFrame(overlayPage()->mainFrame())->view();
    275     ASSERT(!view->needsLayout());
    276     view->paint(&context, IntRect(0, 0, view->width(), view->height()));
    277 }
    278 
    279 void InspectorOverlay::invalidate()
    280 {
    281     m_client->highlight();
    282 }
    283 
    284 bool InspectorOverlay::handleGestureEvent(const PlatformGestureEvent& event)
    285 {
    286     if (isEmpty())
    287         return false;
    288 
    289     return toLocalFrame(overlayPage()->mainFrame())->eventHandler().handleGestureEvent(event);
    290 }
    291 
    292 bool InspectorOverlay::handleMouseEvent(const PlatformMouseEvent& event)
    293 {
    294     if (isEmpty())
    295         return false;
    296 
    297     EventHandler& eventHandler = toLocalFrame(overlayPage()->mainFrame())->eventHandler();
    298     bool result;
    299     switch (event.type()) {
    300     case PlatformEvent::MouseMoved:
    301         result = eventHandler.handleMouseMoveEvent(event);
    302         break;
    303     case PlatformEvent::MousePressed:
    304         result = eventHandler.handleMousePressEvent(event);
    305         break;
    306     case PlatformEvent::MouseReleased:
    307         result = eventHandler.handleMouseReleaseEvent(event);
    308         break;
    309     default:
    310         return false;
    311     }
    312 
    313     toLocalFrame(overlayPage()->mainFrame())->document()->updateLayout();
    314     return result;
    315 }
    316 
    317 bool InspectorOverlay::handleTouchEvent(const PlatformTouchEvent& event)
    318 {
    319     if (isEmpty())
    320         return false;
    321 
    322     return toLocalFrame(overlayPage()->mainFrame())->eventHandler().handleTouchEvent(event);
    323 }
    324 
    325 bool InspectorOverlay::handleKeyboardEvent(const PlatformKeyboardEvent& event)
    326 {
    327     if (isEmpty())
    328         return false;
    329 
    330     return toLocalFrame(overlayPage()->mainFrame())->eventHandler().keyEvent(event);
    331 }
    332 
    333 void InspectorOverlay::drawOutline(GraphicsContext* context, const LayoutRect& rect, const Color& color)
    334 {
    335     FloatRect outlineRect = rect;
    336     drawOutlinedQuad(context, outlineRect, Color(), color);
    337 }
    338 
    339 void InspectorOverlay::setPausedInDebuggerMessage(const String* message)
    340 {
    341     m_pausedInDebuggerMessage = message ? *message : String();
    342     update();
    343 }
    344 
    345 void InspectorOverlay::setInspectModeEnabled(bool enabled)
    346 {
    347     m_inspectModeEnabled = enabled;
    348     update();
    349 }
    350 
    351 void InspectorOverlay::hideHighlight()
    352 {
    353     m_highlightNode.clear();
    354     m_eventTargetNode.clear();
    355     m_highlightQuad.clear();
    356     update();
    357 }
    358 
    359 void InspectorOverlay::highlightNode(Node* node, Node* eventTarget, const HighlightConfig& highlightConfig, bool omitTooltip)
    360 {
    361     m_nodeHighlightConfig = highlightConfig;
    362     m_highlightNode = node;
    363     m_eventTargetNode = eventTarget;
    364     m_omitTooltip = omitTooltip;
    365     update();
    366 }
    367 
    368 void InspectorOverlay::highlightQuad(PassOwnPtr<FloatQuad> quad, const HighlightConfig& highlightConfig)
    369 {
    370     m_quadHighlightConfig = highlightConfig;
    371     m_highlightQuad = quad;
    372     m_omitTooltip = false;
    373     update();
    374 }
    375 
    376 void InspectorOverlay::showAndHideViewSize(bool showGrid)
    377 {
    378     m_drawViewSize = true;
    379     m_drawViewSizeWithGrid = showGrid;
    380     update();
    381     m_timer.startOneShot(1, FROM_HERE);
    382 }
    383 
    384 Node* InspectorOverlay::highlightedNode() const
    385 {
    386     return m_highlightNode.get();
    387 }
    388 
    389 bool InspectorOverlay::isEmpty()
    390 {
    391     if (m_activeProfilerCount)
    392         return true;
    393     bool hasAlwaysVisibleElements = m_highlightNode || m_eventTargetNode || m_highlightQuad  || m_drawViewSize;
    394     bool hasInvisibleInInspectModeElements = !m_pausedInDebuggerMessage.isNull();
    395     return !(hasAlwaysVisibleElements || (hasInvisibleInInspectModeElements && !m_inspectModeEnabled));
    396 }
    397 
    398 void InspectorOverlay::update()
    399 {
    400     if (isEmpty()) {
    401         m_client->hideHighlight();
    402         return;
    403     }
    404 
    405     FrameView* view = m_page->deprecatedLocalMainFrame()->view();
    406     if (!view)
    407         return;
    408 
    409     // Include scrollbars to avoid masking them by the gutter.
    410     IntSize size = view->unscaledVisibleContentSize(IncludeScrollbars);
    411     toLocalFrame(overlayPage()->mainFrame())->view()->resize(size);
    412 
    413     // Clear canvas and paint things.
    414     IntRect viewRect = view->visibleContentRect();
    415     reset(size, viewRect.x(), viewRect.y());
    416 
    417     drawNodeHighlight();
    418     drawQuadHighlight();
    419     if (!m_inspectModeEnabled)
    420         drawPausedInDebuggerMessage();
    421     drawViewSize();
    422 
    423     // Position DOM elements.
    424     toLocalFrame(overlayPage()->mainFrame())->document()->setNeedsStyleRecalc(SubtreeStyleChange);
    425     toLocalFrame(overlayPage()->mainFrame())->document()->updateLayout();
    426 
    427     // Kick paint.
    428     m_client->highlight();
    429 }
    430 
    431 void InspectorOverlay::hide()
    432 {
    433     m_timer.stop();
    434     m_highlightNode.clear();
    435     m_eventTargetNode.clear();
    436     m_highlightQuad.clear();
    437     m_pausedInDebuggerMessage = String();
    438     m_drawViewSize = false;
    439     m_drawViewSizeWithGrid = false;
    440     update();
    441 }
    442 
    443 static PassRefPtr<JSONObject> buildObjectForPoint(const FloatPoint& point)
    444 {
    445     RefPtr<JSONObject> object = JSONObject::create();
    446     object->setNumber("x", point.x());
    447     object->setNumber("y", point.y());
    448     return object.release();
    449 }
    450 
    451 static PassRefPtr<JSONArray> buildArrayForQuad(const FloatQuad& quad)
    452 {
    453     RefPtr<JSONArray> array = JSONArray::create();
    454     array->pushObject(buildObjectForPoint(quad.p1()));
    455     array->pushObject(buildObjectForPoint(quad.p2()));
    456     array->pushObject(buildObjectForPoint(quad.p3()));
    457     array->pushObject(buildObjectForPoint(quad.p4()));
    458     return array.release();
    459 }
    460 
    461 static PassRefPtr<JSONObject> buildObjectForHighlight(const Highlight& highlight)
    462 {
    463     RefPtr<JSONObject> object = JSONObject::create();
    464     RefPtr<JSONArray> array = JSONArray::create();
    465     for (size_t i = 0; i < highlight.quads.size(); ++i)
    466         array->pushArray(buildArrayForQuad(highlight.quads[i]));
    467     object->setArray("quads", array.release());
    468     object->setBoolean("showRulers", highlight.showRulers);
    469     object->setString("contentColor", highlight.contentColor.serialized());
    470     object->setString("contentOutlineColor", highlight.contentOutlineColor.serialized());
    471     object->setString("paddingColor", highlight.paddingColor.serialized());
    472     object->setString("borderColor", highlight.borderColor.serialized());
    473     object->setString("marginColor", highlight.marginColor.serialized());
    474     object->setString("eventTargetColor", highlight.eventTargetColor.serialized());
    475     return object.release();
    476 }
    477 
    478 static PassRefPtr<JSONObject> buildObjectForSize(const IntSize& size)
    479 {
    480     RefPtr<JSONObject> result = JSONObject::create();
    481     result->setNumber("width", size.width());
    482     result->setNumber("height", size.height());
    483     return result.release();
    484 }
    485 
    486 // CSS shapes
    487 static void appendPathCommandAndPoints(PathApplyInfo* info, const String& command, const FloatPoint points[], unsigned length)
    488 {
    489     FloatPoint point;
    490     info->array->addItem(JSONString::create(command));
    491     for (unsigned i = 0; i < length; i++) {
    492         point = info->shapeOutsideInfo->shapeToRendererPoint(points[i]);
    493         point = info->view->contentsToRootView(roundedIntPoint(info->renderer->localToAbsolute(point))) + info->rootView->scrollOffset();
    494         info->array->addItem(JSONBasicValue::create(point.x()));
    495         info->array->addItem(JSONBasicValue::create(point.y()));
    496     }
    497 }
    498 
    499 static void appendPathSegment(void* info, const PathElement* pathElement)
    500 {
    501     PathApplyInfo* pathApplyInfo = static_cast<PathApplyInfo*>(info);
    502     FloatPoint point;
    503     switch (pathElement->type) {
    504     // The points member will contain 1 value.
    505     case PathElementMoveToPoint:
    506         appendPathCommandAndPoints(pathApplyInfo, "M", pathElement->points, 1);
    507         break;
    508     // The points member will contain 1 value.
    509     case PathElementAddLineToPoint:
    510         appendPathCommandAndPoints(pathApplyInfo, "L", pathElement->points, 1);
    511         break;
    512     // The points member will contain 3 values.
    513     case PathElementAddCurveToPoint:
    514         appendPathCommandAndPoints(pathApplyInfo, "C", pathElement->points, 3);
    515         break;
    516     // The points member will contain 2 values.
    517     case PathElementAddQuadCurveToPoint:
    518         appendPathCommandAndPoints(pathApplyInfo, "Q", pathElement->points, 2);
    519         break;
    520     // The points member will contain no values.
    521     case PathElementCloseSubpath:
    522         appendPathCommandAndPoints(pathApplyInfo, "Z", 0, 0);
    523         break;
    524     }
    525 }
    526 
    527 static RefPtr<TypeBuilder::Array<double> > buildArrayForQuadTypeBuilder(const FloatQuad& quad)
    528 {
    529     RefPtr<TypeBuilder::Array<double> > array = TypeBuilder::Array<double>::create();
    530     array->addItem(quad.p1().x());
    531     array->addItem(quad.p1().y());
    532     array->addItem(quad.p2().x());
    533     array->addItem(quad.p2().y());
    534     array->addItem(quad.p3().x());
    535     array->addItem(quad.p3().y());
    536     array->addItem(quad.p4().x());
    537     array->addItem(quad.p4().y());
    538     return array.release();
    539 }
    540 
    541 PassRefPtr<TypeBuilder::DOM::ShapeOutsideInfo> InspectorOverlay::buildObjectForShapeOutside(Node* node)
    542 {
    543     RenderObject* renderer = node->renderer();
    544     if (!renderer || !renderer->isBox() || !toRenderBox(renderer)->shapeOutsideInfo())
    545         return nullptr;
    546 
    547     LocalFrame* containingFrame = node->document().frame();
    548     RenderBox* renderBox = toRenderBox(renderer);
    549     const ShapeOutsideInfo* shapeOutsideInfo = renderBox->shapeOutsideInfo();
    550 
    551     LayoutRect shapeBounds = shapeOutsideInfo->computedShapePhysicalBoundingBox();
    552     FloatQuad shapeQuad = renderBox->localToAbsoluteQuad(FloatRect(shapeBounds));
    553     FrameView* mainView = containingFrame->page()->deprecatedLocalMainFrame()->view();
    554     FrameView* containingView = containingFrame->view();
    555     contentsQuadToPage(mainView, containingView, shapeQuad);
    556 
    557     Shape::DisplayPaths paths;
    558     shapeOutsideInfo->computedShape().buildDisplayPaths(paths);
    559     RefPtr<TypeBuilder::Array<JSONValue> > shapePath = TypeBuilder::Array<JSONValue>::create();
    560     RefPtr<TypeBuilder::Array<JSONValue> > marginShapePath = TypeBuilder::Array<JSONValue>::create();
    561 
    562     if (paths.shape.length()) {
    563         PathApplyInfo info;
    564         info.rootView = mainView;
    565         info.view = containingView;
    566         info.array = shapePath.get();
    567         info.renderer = renderBox;
    568         info.shapeOutsideInfo = shapeOutsideInfo;
    569         paths.shape.apply(&info, &appendPathSegment);
    570 
    571         if (paths.marginShape.length()) {
    572             info.array = marginShapePath.get();
    573             paths.marginShape.apply(&info, &appendPathSegment);
    574         }
    575     }
    576     RefPtr<TypeBuilder::DOM::ShapeOutsideInfo> shapeTypeBuilder = TypeBuilder::DOM::ShapeOutsideInfo::create()
    577         .setBounds(buildArrayForQuadTypeBuilder(shapeQuad))
    578         .setShape(shapePath)
    579         .setMarginShape(marginShapePath);
    580 
    581     return shapeTypeBuilder.release();
    582 }
    583 
    584 static void setElementInfo(RefPtr<JSONObject>& highlightObject, RefPtr<JSONObject>& shapeObject, Node* node)
    585 {
    586     RefPtr<JSONObject> elementInfo = JSONObject::create();
    587     Element* element = toElement(node);
    588     Element* realElement = element;
    589     PseudoElement* pseudoElement = 0;
    590     if (element->isPseudoElement()) {
    591         pseudoElement = toPseudoElement(element);
    592         realElement = element->parentOrShadowHostElement();
    593     }
    594     bool isXHTML = realElement->document().isXHTMLDocument();
    595     elementInfo->setString("tagName", isXHTML ? realElement->nodeName() : realElement->nodeName().lower());
    596     elementInfo->setString("idValue", realElement->getIdAttribute());
    597     StringBuilder classNames;
    598     if (realElement->hasClass() && realElement->isStyledElement()) {
    599         HashSet<AtomicString> usedClassNames;
    600         const SpaceSplitString& classNamesString = realElement->classNames();
    601         size_t classNameCount = classNamesString.size();
    602         for (size_t i = 0; i < classNameCount; ++i) {
    603             const AtomicString& className = classNamesString[i];
    604             if (!usedClassNames.add(className).isNewEntry)
    605                 continue;
    606             classNames.append('.');
    607             classNames.append(className);
    608         }
    609     }
    610     if (pseudoElement) {
    611         if (pseudoElement->pseudoId() == BEFORE)
    612             classNames.append("::before");
    613         else if (pseudoElement->pseudoId() == AFTER)
    614             classNames.append("::after");
    615     }
    616     if (!classNames.isEmpty())
    617         elementInfo->setString("className", classNames.toString());
    618 
    619     RenderObject* renderer = node->renderer();
    620     LocalFrame* containingFrame = node->document().frame();
    621     FrameView* containingView = containingFrame->view();
    622     IntRect boundingBox = pixelSnappedIntRect(containingView->contentsToRootView(renderer->absoluteBoundingBoxRect()));
    623     RenderBoxModelObject* modelObject = renderer->isBoxModelObject() ? toRenderBoxModelObject(renderer) : 0;
    624     elementInfo->setString("nodeWidth", String::number(modelObject ? adjustForAbsoluteZoom(modelObject->pixelSnappedOffsetWidth(), modelObject) : boundingBox.width()));
    625     elementInfo->setString("nodeHeight", String::number(modelObject ? adjustForAbsoluteZoom(modelObject->pixelSnappedOffsetHeight(), modelObject) : boundingBox.height()));
    626     if (renderer->isBox() && shapeObject)
    627         elementInfo->setObject("shapeOutsideInfo", shapeObject.release());
    628     highlightObject->setObject("elementInfo", elementInfo.release());
    629 }
    630 
    631 void InspectorOverlay::drawNodeHighlight()
    632 {
    633     if (!m_highlightNode)
    634         return;
    635 
    636     Highlight highlight;
    637     buildNodeHighlight(m_highlightNode.get(), m_nodeHighlightConfig, &highlight);
    638     if (m_eventTargetNode) {
    639         Highlight eventTargetHighlight;
    640         buildNodeHighlight(m_eventTargetNode.get(), m_nodeHighlightConfig, &eventTargetHighlight);
    641         highlight.quads.append(eventTargetHighlight.quads[1]); // Add border from eventTargetNode to highlight.
    642     }
    643     RefPtr<JSONObject> highlightObject = buildObjectForHighlight(highlight);
    644 
    645     Node* node = m_highlightNode.get();
    646     RefPtr<TypeBuilder::DOM::ShapeOutsideInfo> shapeObject = buildObjectForShapeOutside(node);
    647     RefPtr<JSONObject> shapeObjectJSON = shapeObject ? shapeObject->asObject() : nullptr;
    648     if (node->isElementNode() && !m_omitTooltip && m_nodeHighlightConfig.showInfo && node->renderer() && node->document().frame())
    649         setElementInfo(highlightObject, shapeObjectJSON, node);
    650     evaluateInOverlay("drawNodeHighlight", highlightObject);
    651 }
    652 
    653 void InspectorOverlay::drawQuadHighlight()
    654 {
    655     if (!m_highlightQuad)
    656         return;
    657 
    658     Highlight highlight;
    659     buildQuadHighlight(m_page, *m_highlightQuad, m_quadHighlightConfig, &highlight);
    660     evaluateInOverlay("drawQuadHighlight", buildObjectForHighlight(highlight));
    661 }
    662 
    663 void InspectorOverlay::drawPausedInDebuggerMessage()
    664 {
    665     if (!m_pausedInDebuggerMessage.isNull())
    666         evaluateInOverlay("drawPausedInDebuggerMessage", m_pausedInDebuggerMessage);
    667 }
    668 
    669 void InspectorOverlay::drawViewSize()
    670 {
    671     if (m_drawViewSize)
    672         evaluateInOverlay("drawViewSize", m_drawViewSizeWithGrid ? "true" : "false");
    673 }
    674 
    675 Page* InspectorOverlay::overlayPage()
    676 {
    677     if (m_overlayPage)
    678         return m_overlayPage.get();
    679 
    680     static FrameLoaderClient* dummyFrameLoaderClient =  new EmptyFrameLoaderClient;
    681     Page::PageClients pageClients;
    682     fillWithEmptyClients(pageClients);
    683     ASSERT(!m_overlayChromeClient);
    684     m_overlayChromeClient = adoptPtr(new InspectorOverlayChromeClient(m_page->chrome().client(), this));
    685     pageClients.chromeClient = m_overlayChromeClient.get();
    686     m_overlayPage = adoptPtrWillBeNoop(new Page(pageClients));
    687 
    688     Settings& settings = m_page->settings();
    689     Settings& overlaySettings = m_overlayPage->settings();
    690 
    691     overlaySettings.genericFontFamilySettings().setStandard(settings.genericFontFamilySettings().standard());
    692     overlaySettings.genericFontFamilySettings().setSerif(settings.genericFontFamilySettings().serif());
    693     overlaySettings.genericFontFamilySettings().setSansSerif(settings.genericFontFamilySettings().sansSerif());
    694     overlaySettings.genericFontFamilySettings().setCursive(settings.genericFontFamilySettings().cursive());
    695     overlaySettings.genericFontFamilySettings().setFantasy(settings.genericFontFamilySettings().fantasy());
    696     overlaySettings.genericFontFamilySettings().setPictograph(settings.genericFontFamilySettings().pictograph());
    697     overlaySettings.setMinimumFontSize(settings.minimumFontSize());
    698     overlaySettings.setMinimumLogicalFontSize(settings.minimumLogicalFontSize());
    699     overlaySettings.setScriptEnabled(true);
    700     overlaySettings.setPluginsEnabled(false);
    701     overlaySettings.setLoadsImagesAutomatically(true);
    702     // FIXME: http://crbug.com/363843. Inspector should probably create its
    703     // own graphics layers and attach them to the tree rather than going
    704     // through some non-composited paint function.
    705     overlaySettings.setAcceleratedCompositingEnabled(false);
    706 
    707     RefPtr<LocalFrame> frame = LocalFrame::create(dummyFrameLoaderClient, &m_overlayPage->frameHost(), 0);
    708     frame->setView(FrameView::create(frame.get()));
    709     frame->init();
    710     FrameLoader& loader = frame->loader();
    711     frame->view()->setCanHaveScrollbars(false);
    712     frame->view()->setTransparent(true);
    713 
    714     RefPtr<SharedBuffer> data = SharedBuffer::create(reinterpret_cast<const char*>(InspectorOverlayPage_html), sizeof(InspectorOverlayPage_html));
    715     loader.load(FrameLoadRequest(0, blankURL(), SubstituteData(data, "text/html", "UTF-8", KURL(), ForceSynchronousLoad)));
    716     v8::Isolate* isolate = toIsolate(frame.get());
    717     ScriptState* scriptState = ScriptState::forMainWorld(frame.get());
    718     ASSERT(!scriptState->contextIsEmpty());
    719     ScriptState::Scope scope(scriptState);
    720     v8::Handle<v8::Object> global = scriptState->context()->Global();
    721     v8::Handle<v8::Value> overlayHostObj = toV8(m_overlayHost.get(), global, isolate);
    722     global->Set(v8::String::NewFromUtf8(isolate, "InspectorOverlayHost"), overlayHostObj);
    723 
    724 #if OS(WIN)
    725     evaluateInOverlay("setPlatform", "windows");
    726 #elif OS(MACOSX)
    727     evaluateInOverlay("setPlatform", "mac");
    728 #elif OS(POSIX)
    729     evaluateInOverlay("setPlatform", "linux");
    730 #endif
    731 
    732     return m_overlayPage.get();
    733 }
    734 
    735 void InspectorOverlay::reset(const IntSize& viewportSize, int scrollX, int scrollY)
    736 {
    737     RefPtr<JSONObject> resetData = JSONObject::create();
    738     resetData->setNumber("pageScaleFactor", m_page->settings().pinchVirtualViewportEnabled() ? 1 : m_page->pageScaleFactor());
    739     resetData->setNumber("deviceScaleFactor", m_page->deviceScaleFactor());
    740     resetData->setObject("viewportSize", buildObjectForSize(viewportSize));
    741     resetData->setNumber("pageZoomFactor", m_page->deprecatedLocalMainFrame()->pageZoomFactor());
    742     resetData->setNumber("scrollX", scrollX);
    743     resetData->setNumber("scrollY", scrollY);
    744     evaluateInOverlay("reset", resetData.release());
    745 }
    746 
    747 void InspectorOverlay::evaluateInOverlay(const String& method, const String& argument)
    748 {
    749     RefPtr<JSONArray> command = JSONArray::create();
    750     command->pushString(method);
    751     command->pushString(argument);
    752     toLocalFrame(overlayPage()->mainFrame())->script().executeScriptInMainWorld("dispatch(" + command->toJSONString() + ")", ScriptController::ExecuteScriptWhenScriptsDisabled);
    753 }
    754 
    755 void InspectorOverlay::evaluateInOverlay(const String& method, PassRefPtr<JSONValue> argument)
    756 {
    757     RefPtr<JSONArray> command = JSONArray::create();
    758     command->pushString(method);
    759     command->pushValue(argument);
    760     toLocalFrame(overlayPage()->mainFrame())->script().executeScriptInMainWorld("dispatch(" + command->toJSONString() + ")", ScriptController::ExecuteScriptWhenScriptsDisabled);
    761 }
    762 
    763 void InspectorOverlay::onTimer(Timer<InspectorOverlay>*)
    764 {
    765     m_drawViewSize = false;
    766     update();
    767 }
    768 
    769 bool InspectorOverlay::getBoxModel(Node* node, Vector<FloatQuad>* quads)
    770 {
    771     return buildNodeQuads(node, *quads);
    772 }
    773 
    774 void InspectorOverlay::freePage()
    775 {
    776     if (m_overlayPage) {
    777         m_overlayPage->willBeDestroyed();
    778         m_overlayPage.clear();
    779     }
    780     m_overlayChromeClient.clear();
    781     m_timer.stop();
    782 
    783     // This will clear internal structures and issue update to the client. Safe to call last.
    784     hideHighlight();
    785 }
    786 
    787 void InspectorOverlay::startedRecordingProfile()
    788 {
    789     if (!m_activeProfilerCount++)
    790         freePage();
    791 }
    792 
    793 } // namespace WebCore
    794