9c502b01e1512df1bee69b91ddecdca873e9bccd
[platform/framework/web/crosswalk.git] / src / third_party / WebKit / Source / core / inspector / InspectorOverlay.cpp
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