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