2 * Copyright (C) 2011 Google Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
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.
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.
30 #include "core/inspector/InspectorOverlay.h"
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"
69 WTF_MAKE_NONCOPYABLE(PathBuilder);
71 PathBuilder() : m_path(TypeBuilder::Array<JSONValue>::create()) { }
72 virtual ~PathBuilder() { }
74 PassRefPtr<TypeBuilder::Array<JSONValue> > path() const { return m_path; }
75 void appendPath(const Path& path)
77 path.apply(this, &PathBuilder::appendPathElement);
81 virtual FloatPoint translatePoint(const FloatPoint& point) { return point; }
84 static void appendPathElement(void* pathBuilder, const PathElement* pathElement)
86 static_cast<PathBuilder*>(pathBuilder)->appendPathElement(pathElement);
89 void appendPathElement(const PathElement*);
90 void appendPathCommandAndPoints(const char* command, const FloatPoint points[], size_t length);
92 RefPtr<TypeBuilder::Array<JSONValue> > m_path;
95 class ShapePathBuilder : public PathBuilder {
97 ShapePathBuilder(FrameView& view, RenderObject& renderer, const ShapeOutsideInfo& shapeOutsideInfo)
99 , m_renderer(renderer)
100 , m_shapeOutsideInfo(shapeOutsideInfo) { }
102 static PassRefPtr<TypeBuilder::Array<JSONValue> > buildPath(FrameView& view, RenderObject& renderer, const ShapeOutsideInfo& shapeOutsideInfo, const Path& path)
104 ShapePathBuilder builder(view, renderer, shapeOutsideInfo);
105 builder.appendPath(path);
106 return builder.path();
110 virtual FloatPoint translatePoint(const FloatPoint& point)
112 FloatPoint rendererPoint = m_shapeOutsideInfo.shapeToRendererPoint(point);
113 return m_view.contentsToRootView(roundedIntPoint(m_renderer.localToAbsolute(rendererPoint)));
118 RenderObject& m_renderer;
119 const ShapeOutsideInfo& m_shapeOutsideInfo;
122 class InspectorOverlayChromeClient FINAL: public EmptyChromeClient {
124 InspectorOverlayChromeClient(ChromeClient& client, InspectorOverlay* overlay)
129 virtual void setCursor(const Cursor& cursor) OVERRIDE
131 m_client.setCursor(cursor);
134 virtual void setToolTip(const String& tooltip, TextDirection direction) OVERRIDE
136 m_client.setToolTip(tooltip, direction);
139 virtual void invalidateContentsAndRootView(const IntRect&) OVERRIDE
141 m_overlay->invalidate();
144 virtual void invalidateContentsForSlowScroll(const IntRect&) OVERRIDE
146 m_overlay->invalidate();
150 ChromeClient& m_client;
151 InspectorOverlay* m_overlay;
154 static Path quadToPath(const FloatQuad& quad)
157 quadPath.moveTo(quad.p1());
158 quadPath.addLineTo(quad.p2());
159 quadPath.addLineTo(quad.p3());
160 quadPath.addLineTo(quad.p4());
161 quadPath.closeSubpath();
165 void drawOutlinedQuad(GraphicsContext* context, const FloatQuad& quad, const Color& fillColor, const Color& outlineColor)
167 static const int outlineThickness = 2;
169 Path quadPath = quadToPath(quad);
171 // Clip out the quad, then draw with a 2px stroke to get a pixel
172 // of outline (because inflating a quad is hard)
175 context->clipOut(quadPath);
177 context->setStrokeThickness(outlineThickness);
178 context->setStrokeColor(outlineColor);
179 context->strokePath(quadPath);
185 context->setFillColor(fillColor);
186 context->fillPath(quadPath);
192 : m_showRulers(false)
193 , m_showExtensionLines(false)
194 , m_highlightPaths(JSONArray::create())
197 void setDataFromConfig(const HighlightConfig& highlightConfig)
199 m_showRulers = highlightConfig.showRulers;
200 m_showExtensionLines = highlightConfig.showExtensionLines;
203 void setElementInfo(PassRefPtr<JSONObject> elementInfo)
205 m_elementInfo = elementInfo;
208 void appendQuad(const FloatQuad& quad, const Color& fillColor, const Color& outlineColor = Color::transparent)
210 Path path = quadToPath(quad);
212 builder.appendPath(path);
213 appendPath(builder.path(), fillColor, outlineColor);
216 void appendPath(PassRefPtr<JSONArrayBase> path, const Color& fillColor, const Color& outlineColor)
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());
226 PassRefPtr<JSONObject> asJSONObject() const
228 RefPtr<JSONObject> object = JSONObject::create();
229 object->setArray("paths", m_highlightPaths);
230 object->setBoolean("showRulers", m_showRulers);
231 object->setBoolean("showExtensionLines", m_showExtensionLines);
233 object->setObject("elementInfo", m_elementInfo);
234 return object.release();
239 bool m_showExtensionLines;
240 RefPtr<JSONObject> m_elementInfo;
241 RefPtr<JSONArray> m_highlightPaths;
244 static void contentsQuadToScreen(const FrameView* view, FloatQuad& quad)
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())));
252 static bool buildNodeQuads(RenderObject* renderer, FloatQuad* content, FloatQuad* padding, FloatQuad* border, FloatQuad* margin)
254 FrameView* containingView = renderer->frameView();
257 if (!renderer->isBox() && !renderer->isRenderInline())
260 LayoutRect contentBox;
261 LayoutRect paddingBox;
262 LayoutRect borderBox;
263 LayoutRect marginBox;
265 if (renderer->isBox()) {
266 RenderBox* renderBox = toRenderBox(renderer);
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());
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());
280 RenderInline* renderInline = toRenderInline(renderer);
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());
293 *content = renderer->localToAbsoluteQuad(FloatRect(contentBox));
294 *padding = renderer->localToAbsoluteQuad(FloatRect(paddingBox));
295 *border = renderer->localToAbsoluteQuad(FloatRect(borderBox));
296 *margin = renderer->localToAbsoluteQuad(FloatRect(marginBox));
298 contentsQuadToScreen(containingView, *content);
299 contentsQuadToScreen(containingView, *padding);
300 contentsQuadToScreen(containingView, *border);
301 contentsQuadToScreen(containingView, *margin);
306 static void buildNodeHighlight(Node& node, const HighlightConfig& highlightConfig, Highlight* highlight)
308 RenderObject* renderer = node.renderer();
312 highlight->setDataFromConfig(highlightConfig);
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);
323 FloatQuad content, padding, border, margin;
324 if (!buildNodeQuads(renderer, &content, &padding, &border, &margin))
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);
332 } // anonymous namespace
334 InspectorOverlay::InspectorOverlay(Page* page, InspectorClient* 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)
347 InspectorOverlay::~InspectorOverlay()
349 ASSERT(!m_overlayPage);
352 void InspectorOverlay::paint(GraphicsContext& context)
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()));
362 void InspectorOverlay::invalidate()
364 m_client->highlight();
367 bool InspectorOverlay::handleGestureEvent(const PlatformGestureEvent& event)
372 return toLocalFrame(overlayPage()->mainFrame())->eventHandler().handleGestureEvent(event);
375 bool InspectorOverlay::handleMouseEvent(const PlatformMouseEvent& event)
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);
393 bool InspectorOverlay::handleTouchEvent(const PlatformTouchEvent& event)
398 return toLocalFrame(overlayPage()->mainFrame())->eventHandler().handleTouchEvent(event);
401 bool InspectorOverlay::handleKeyboardEvent(const PlatformKeyboardEvent& event)
406 return toLocalFrame(overlayPage()->mainFrame())->eventHandler().keyEvent(event);
409 void InspectorOverlay::drawOutline(GraphicsContext* context, const LayoutRect& rect, const Color& color)
411 FloatRect outlineRect = rect;
412 drawOutlinedQuad(context, outlineRect, Color(), color);
415 void InspectorOverlay::setPausedInDebuggerMessage(const String* message)
417 m_pausedInDebuggerMessage = message ? *message : String();
421 void InspectorOverlay::setInspectModeEnabled(bool enabled)
423 m_inspectModeEnabled = enabled;
427 void InspectorOverlay::hideHighlight()
429 m_highlightNode.clear();
430 m_eventTargetNode.clear();
431 m_highlightQuad.clear();
435 void InspectorOverlay::highlightNode(Node* node, Node* eventTarget, const HighlightConfig& highlightConfig, bool omitTooltip)
437 m_nodeHighlightConfig = highlightConfig;
438 m_highlightNode = node;
439 m_eventTargetNode = eventTarget;
440 m_omitTooltip = omitTooltip;
444 void InspectorOverlay::highlightQuad(PassOwnPtr<FloatQuad> quad, const HighlightConfig& highlightConfig)
446 m_quadHighlightConfig = highlightConfig;
447 m_highlightQuad = quad;
448 m_omitTooltip = false;
452 void InspectorOverlay::showAndHideViewSize(bool showGrid)
454 m_drawViewSize = true;
455 m_drawViewSizeWithGrid = showGrid;
457 m_timer.startOneShot(1, FROM_HERE);
460 Node* InspectorOverlay::highlightedNode() const
462 return m_highlightNode.get();
465 bool InspectorOverlay::isEmpty()
467 if (m_activeProfilerCount)
469 bool hasAlwaysVisibleElements = m_highlightNode || m_eventTargetNode || m_highlightQuad || m_drawViewSize;
470 bool hasInvisibleInInspectModeElements = !m_pausedInDebuggerMessage.isNull();
471 return !(hasAlwaysVisibleElements || (hasInvisibleInInspectModeElements && !m_inspectModeEnabled));
474 void InspectorOverlay::update()
477 m_client->hideHighlight();
481 FrameView* view = m_page->deprecatedLocalMainFrame()->view();
485 // Include scrollbars to avoid masking them by the gutter.
486 IntSize size = view->unscaledVisibleContentSize(IncludeScrollbars);
487 toLocalFrame(overlayPage()->mainFrame())->view()->resize(size);
489 // Clear canvas and paint things.
490 IntRect viewRect = view->visibleContentRect();
491 reset(size, viewRect.x(), viewRect.y());
495 if (!m_inspectModeEnabled)
496 drawPausedInDebuggerMessage();
499 toLocalFrame(overlayPage()->mainFrame())->view()->updateLayoutAndStyleForPainting();
501 m_client->highlight();
504 void InspectorOverlay::hide()
507 m_highlightNode.clear();
508 m_eventTargetNode.clear();
509 m_highlightQuad.clear();
510 m_pausedInDebuggerMessage = String();
511 m_drawViewSize = false;
512 m_drawViewSizeWithGrid = false;
516 static PassRefPtr<JSONObject> buildObjectForSize(const IntSize& size)
518 RefPtr<JSONObject> result = JSONObject::create();
519 result->setNumber("width", size.width());
520 result->setNumber("height", size.height());
521 return result.release();
524 void PathBuilder::appendPathCommandAndPoints(const char* command, const FloatPoint points[], size_t length)
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()));
534 void PathBuilder::appendPathElement(const PathElement* pathElement)
536 switch (pathElement->type) {
537 // The points member will contain 1 value.
538 case PathElementMoveToPoint:
539 appendPathCommandAndPoints("M", pathElement->points, 1);
541 // The points member will contain 1 value.
542 case PathElementAddLineToPoint:
543 appendPathCommandAndPoints("L", pathElement->points, 1);
545 // The points member will contain 3 values.
546 case PathElementAddCurveToPoint:
547 appendPathCommandAndPoints("C", pathElement->points, 3);
549 // The points member will contain 2 values.
550 case PathElementAddQuadCurveToPoint:
551 appendPathCommandAndPoints("Q", pathElement->points, 2);
553 // The points member will contain no values.
554 case PathElementCloseSubpath:
555 appendPathCommandAndPoints("Z", 0, 0);
560 static RefPtr<TypeBuilder::Array<double> > buildArrayForQuad(const FloatQuad& quad)
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();
574 static const ShapeOutsideInfo* shapeOutsideInfoForNode(Node* node, Shape::DisplayPaths* paths, FloatQuad* bounds)
576 RenderObject* renderer = node->renderer();
577 if (!renderer || !renderer->isBox() || !toRenderBox(renderer)->shapeOutsideInfo())
580 FrameView* containingView = node->document().view();
581 RenderBox* renderBox = toRenderBox(renderer);
582 const ShapeOutsideInfo* shapeOutsideInfo = renderBox->shapeOutsideInfo();
584 shapeOutsideInfo->computedShape().buildDisplayPaths(*paths);
586 LayoutRect shapeBounds = shapeOutsideInfo->computedShapePhysicalBoundingBox();
587 *bounds = renderBox->localToAbsoluteQuad(FloatRect(shapeBounds));
588 contentsQuadToScreen(containingView, *bounds);
590 return shapeOutsideInfo;
593 static void appendPathsForShapeOutside(Highlight& highlight, const HighlightConfig& config, Node* node)
595 Shape::DisplayPaths paths;
596 FloatQuad boundsQuad;
598 const ShapeOutsideInfo* shapeOutsideInfo = shapeOutsideInfoForNode(node, &paths, &boundsQuad);
599 if (!shapeOutsideInfo)
602 if (!paths.shape.length()) {
603 highlight.appendQuad(boundsQuad, config.shape);
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);
612 PassRefPtr<JSONObject> buildElementInfo(Element* element)
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();
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)
633 classNames.append('.');
634 classNames.append(className);
638 if (pseudoElement->pseudoId() == BEFORE)
639 classNames.append("::before");
640 else if (pseudoElement->pseudoId() == AFTER)
641 classNames.append("::after");
643 if (!classNames.isEmpty())
644 elementInfo->setString("className", classNames.toString());
646 RenderObject* renderer = element->renderer();
647 FrameView* containingView = element->document().view();
648 if (!renderer || !containingView)
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()));
659 void InspectorOverlay::drawNodeHighlight()
661 if (!m_highlightNode)
665 appendPathsForShapeOutside(highlight, m_nodeHighlightConfig, m_highlightNode.get());
666 buildNodeHighlight(*m_highlightNode, m_nodeHighlightConfig, &highlight);
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);
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())));
677 evaluateInOverlay("drawHighlight", highlight.asJSONObject());
680 void InspectorOverlay::drawQuadHighlight()
682 if (!m_highlightQuad)
686 highlight.appendQuad(*m_highlightQuad, m_quadHighlightConfig.content, m_quadHighlightConfig.contentOutline);
687 evaluateInOverlay("drawHighlight", highlight.asJSONObject());
690 void InspectorOverlay::drawPausedInDebuggerMessage()
692 if (!m_pausedInDebuggerMessage.isNull())
693 evaluateInOverlay("drawPausedInDebuggerMessage", m_pausedInDebuggerMessage);
696 void InspectorOverlay::drawViewSize()
699 evaluateInOverlay("drawViewSize", m_drawViewSizeWithGrid ? "true" : "false");
702 Page* InspectorOverlay::overlayPage()
705 return m_overlayPage.get();
707 ScriptForbiddenScope::AllowUserAgentScript allowScript;
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));
717 Settings& settings = m_page->settings();
718 Settings& overlaySettings = m_overlayPage->settings();
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);
736 RefPtr<LocalFrame> frame = LocalFrame::create(dummyFrameLoaderClient, &m_overlayPage->frameHost(), 0);
737 frame->setView(FrameView::create(frame.get()));
739 FrameLoader& loader = frame->loader();
740 frame->view()->setCanHaveScrollbars(false);
741 frame->view()->setTransparent(true);
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);
755 evaluateInOverlay("setPlatform", "windows");
757 evaluateInOverlay("setPlatform", "mac");
759 evaluateInOverlay("setPlatform", "linux");
762 return m_overlayPage.get();
765 void InspectorOverlay::reset(const IntSize& viewportSize, int scrollX, int scrollY)
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());
777 void InspectorOverlay::evaluateInOverlay(const String& method, const String& argument)
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);
786 void InspectorOverlay::evaluateInOverlay(const String& method, PassRefPtr<JSONValue> argument)
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);
795 void InspectorOverlay::onTimer(Timer<InspectorOverlay>*)
797 m_drawViewSize = false;
801 bool InspectorOverlay::getBoxModel(Node* node, RefPtr<TypeBuilder::DOM::BoxModel>& model)
803 RenderObject* renderer = node->renderer();
804 FrameView* view = node->document().view();
805 if (!renderer || !view)
808 FloatQuad content, padding, border, margin;
809 if (!buildNodeQuads(node->renderer(), &content, &padding, &border, &margin))
812 IntRect boundingBox = pixelSnappedIntRect(view->contentsToRootView(renderer->absoluteBoundingBoxRect()));
813 RenderBoxModelObject* modelObject = renderer->isBoxModelObject() ? toRenderBoxModelObject(renderer) : 0;
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());
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);
836 void InspectorOverlay::freePage()
839 m_overlayPage->willBeDestroyed();
840 m_overlayPage.clear();
842 m_overlayChromeClient.clear();
845 // This will clear internal structures and issue update to the client. Safe to call last.
849 void InspectorOverlay::startedRecordingProfile()
851 if (!m_activeProfilerCount++)