1 /*
2 * Copyright (C) 2011 Google Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 *
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
14 * its contributors may be used to endorse or promote products derived
15 * from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
18 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
21 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
22 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
23 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
24 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29 #include "config.h"
30 #include "core/inspector/InspectorOverlay.h"
31
32 #include "InspectorOverlayPage.h"
33 #include "V8InspectorOverlayHost.h"
34 #include "bindings/v8/ScriptController.h"
35 #include "bindings/v8/ScriptSourceCode.h"
36 #include "core/dom/Element.h"
37 #include "core/dom/Node.h"
38 #include "core/dom/PseudoElement.h"
39 #include "core/inspector/InspectorClient.h"
40 #include "core/inspector/InspectorOverlayHost.h"
41 #include "core/loader/DocumentLoader.h"
42 #include "core/loader/EmptyClients.h"
43 #include "core/page/Chrome.h"
44 #include "core/page/EventHandler.h"
45 #include "core/frame/Frame.h"
46 #include "core/frame/FrameView.h"
47 #include "core/page/Page.h"
48 #include "core/frame/Settings.h"
49 #include "core/rendering/RenderBoxModelObject.h"
50 #include "core/rendering/RenderInline.h"
51 #include "core/rendering/RenderObject.h"
52 #include "core/rendering/style/RenderStyleConstants.h"
53 #include "platform/JSONValues.h"
54 #include "platform/PlatformMouseEvent.h"
55 #include "platform/graphics/GraphicsContextStateSaver.h"
56 #include "wtf/text/StringBuilder.h"
57
58 namespace WebCore {
59
60 namespace {
61
62 class InspectorOverlayChromeClient: public EmptyChromeClient {
63 public:
InspectorOverlayChromeClient(ChromeClient & client,InspectorOverlay * overlay)64 InspectorOverlayChromeClient(ChromeClient& client, InspectorOverlay* overlay)
65 : m_client(client)
66 , m_overlay(overlay)
67 { }
68
setCursor(const Cursor & cursor)69 virtual void setCursor(const Cursor& cursor)
70 {
71 m_client.setCursor(cursor);
72 }
73
setToolTip(const String & tooltip,TextDirection direction)74 virtual void setToolTip(const String& tooltip, TextDirection direction)
75 {
76 m_client.setToolTip(tooltip, direction);
77 }
78
invalidateRootView(const IntRect & rect)79 virtual void invalidateRootView(const IntRect& rect)
80 {
81 m_overlay->invalidate();
82 }
83
invalidateContentsAndRootView(const IntRect & rect)84 virtual void invalidateContentsAndRootView(const IntRect& rect)
85 {
86 m_overlay->invalidate();
87 }
88
invalidateContentsForSlowScroll(const IntRect & rect)89 virtual void invalidateContentsForSlowScroll(const IntRect& rect)
90 {
91 m_overlay->invalidate();
92 }
93
94 private:
95 ChromeClient& m_client;
96 InspectorOverlay* m_overlay;
97 };
98
quadToPath(const FloatQuad & quad)99 Path quadToPath(const FloatQuad& quad)
100 {
101 Path quadPath;
102 quadPath.moveTo(quad.p1());
103 quadPath.addLineTo(quad.p2());
104 quadPath.addLineTo(quad.p3());
105 quadPath.addLineTo(quad.p4());
106 quadPath.closeSubpath();
107 return quadPath;
108 }
109
drawOutlinedQuad(GraphicsContext * context,const FloatQuad & quad,const Color & fillColor,const Color & outlineColor)110 void drawOutlinedQuad(GraphicsContext* context, const FloatQuad& quad, const Color& fillColor, const Color& outlineColor)
111 {
112 static const int outlineThickness = 2;
113
114 Path quadPath = quadToPath(quad);
115
116 // Clip out the quad, then draw with a 2px stroke to get a pixel
117 // of outline (because inflating a quad is hard)
118 {
119 context->save();
120 context->clipOut(quadPath);
121
122 context->setStrokeThickness(outlineThickness);
123 context->setStrokeColor(outlineColor);
124 context->strokePath(quadPath);
125
126 context->restore();
127 }
128
129 // Now do the fill
130 context->setFillColor(fillColor);
131 context->fillPath(quadPath);
132 }
133
contentsQuadToPage(const FrameView * mainView,const FrameView * view,FloatQuad & quad)134 static void contentsQuadToPage(const FrameView* mainView, const FrameView* view, FloatQuad& quad)
135 {
136 quad.setP1(view->contentsToRootView(roundedIntPoint(quad.p1())));
137 quad.setP2(view->contentsToRootView(roundedIntPoint(quad.p2())));
138 quad.setP3(view->contentsToRootView(roundedIntPoint(quad.p3())));
139 quad.setP4(view->contentsToRootView(roundedIntPoint(quad.p4())));
140 quad += mainView->scrollOffset();
141 }
142
buildNodeQuads(Node * node,Vector<FloatQuad> & quads)143 static bool buildNodeQuads(Node* node, Vector<FloatQuad>& quads)
144 {
145 RenderObject* renderer = node->renderer();
146 Frame* containingFrame = node->document().frame();
147
148 if (!renderer || !containingFrame)
149 return false;
150
151 FrameView* containingView = containingFrame->view();
152 FrameView* mainView = containingFrame->page()->mainFrame()->view();
153 IntRect boundingBox = pixelSnappedIntRect(containingView->contentsToRootView(renderer->absoluteBoundingBoxRect()));
154 boundingBox.move(mainView->scrollOffset());
155
156 // RenderSVGRoot should be highlighted through the isBox() code path, all other SVG elements should just dump their absoluteQuads().
157 if (renderer->node() && renderer->node()->isSVGElement() && !renderer->isSVGRoot()) {
158 renderer->absoluteQuads(quads);
159 for (size_t i = 0; i < quads.size(); ++i)
160 contentsQuadToPage(mainView, containingView, quads[i]);
161 return false;
162 }
163
164 if (!renderer->isBox() && !renderer->isRenderInline())
165 return false;
166
167 LayoutRect contentBox;
168 LayoutRect paddingBox;
169 LayoutRect borderBox;
170 LayoutRect marginBox;
171
172 if (renderer->isBox()) {
173 RenderBox* renderBox = toRenderBox(renderer);
174
175 // RenderBox returns the "pure" content area box, exclusive of the scrollbars (if present), which also count towards the content area in CSS.
176 contentBox = renderBox->contentBoxRect();
177 contentBox.setWidth(contentBox.width() + renderBox->verticalScrollbarWidth());
178 contentBox.setHeight(contentBox.height() + renderBox->horizontalScrollbarHeight());
179
180 paddingBox = LayoutRect(contentBox.x() - renderBox->paddingLeft(), contentBox.y() - renderBox->paddingTop(),
181 contentBox.width() + renderBox->paddingLeft() + renderBox->paddingRight(), contentBox.height() + renderBox->paddingTop() + renderBox->paddingBottom());
182 borderBox = LayoutRect(paddingBox.x() - renderBox->borderLeft(), paddingBox.y() - renderBox->borderTop(),
183 paddingBox.width() + renderBox->borderLeft() + renderBox->borderRight(), paddingBox.height() + renderBox->borderTop() + renderBox->borderBottom());
184 marginBox = LayoutRect(borderBox.x() - renderBox->marginLeft(), borderBox.y() - renderBox->marginTop(),
185 borderBox.width() + renderBox->marginWidth(), borderBox.height() + renderBox->marginHeight());
186 } else {
187 RenderInline* renderInline = toRenderInline(renderer);
188
189 // RenderInline's bounding box includes paddings and borders, excludes margins.
190 borderBox = renderInline->linesBoundingBox();
191 paddingBox = LayoutRect(borderBox.x() + renderInline->borderLeft(), borderBox.y() + renderInline->borderTop(),
192 borderBox.width() - renderInline->borderLeft() - renderInline->borderRight(), borderBox.height() - renderInline->borderTop() - renderInline->borderBottom());
193 contentBox = LayoutRect(paddingBox.x() + renderInline->paddingLeft(), paddingBox.y() + renderInline->paddingTop(),
194 paddingBox.width() - renderInline->paddingLeft() - renderInline->paddingRight(), paddingBox.height() - renderInline->paddingTop() - renderInline->paddingBottom());
195 // Ignore marginTop and marginBottom for inlines.
196 marginBox = LayoutRect(borderBox.x() - renderInline->marginLeft(), borderBox.y(),
197 borderBox.width() + renderInline->marginWidth(), borderBox.height());
198 }
199
200 FloatQuad absContentQuad = renderer->localToAbsoluteQuad(FloatRect(contentBox));
201 FloatQuad absPaddingQuad = renderer->localToAbsoluteQuad(FloatRect(paddingBox));
202 FloatQuad absBorderQuad = renderer->localToAbsoluteQuad(FloatRect(borderBox));
203 FloatQuad absMarginQuad = renderer->localToAbsoluteQuad(FloatRect(marginBox));
204
205 contentsQuadToPage(mainView, containingView, absContentQuad);
206 contentsQuadToPage(mainView, containingView, absPaddingQuad);
207 contentsQuadToPage(mainView, containingView, absBorderQuad);
208 contentsQuadToPage(mainView, containingView, absMarginQuad);
209
210 quads.append(absMarginQuad);
211 quads.append(absBorderQuad);
212 quads.append(absPaddingQuad);
213 quads.append(absContentQuad);
214
215 return true;
216 }
217
buildNodeHighlight(Node * node,const HighlightConfig & highlightConfig,Highlight * highlight)218 static void buildNodeHighlight(Node* node, const HighlightConfig& highlightConfig, Highlight* highlight)
219 {
220 RenderObject* renderer = node->renderer();
221 Frame* containingFrame = node->document().frame();
222
223 if (!renderer || !containingFrame)
224 return;
225
226 highlight->setDataFromConfig(highlightConfig);
227
228 // RenderSVGRoot should be highlighted through the isBox() code path, all other SVG elements should just dump their absoluteQuads().
229 if (renderer->node() && renderer->node()->isSVGElement() && !renderer->isSVGRoot())
230 highlight->type = HighlightTypeRects;
231 else if (renderer->isBox() || renderer->isRenderInline())
232 highlight->type = HighlightTypeNode;
233 buildNodeQuads(node, highlight->quads);
234 }
235
buildQuadHighlight(Page * page,const FloatQuad & quad,const HighlightConfig & highlightConfig,Highlight * highlight)236 static void buildQuadHighlight(Page* page, const FloatQuad& quad, const HighlightConfig& highlightConfig, Highlight *highlight)
237 {
238 if (!page)
239 return;
240 highlight->setDataFromConfig(highlightConfig);
241 highlight->type = HighlightTypeRects;
242 highlight->quads.append(quad);
243 }
244
245 } // anonymous namespace
246
InspectorOverlay(Page * page,InspectorClient * client)247 InspectorOverlay::InspectorOverlay(Page* page, InspectorClient* client)
248 : m_page(page)
249 , m_client(client)
250 , m_inspectModeEnabled(false)
251 , m_overlayHost(InspectorOverlayHost::create())
252 , m_drawViewSize(false)
253 , m_drawViewSizeWithGrid(false)
254 , m_timer(this, &InspectorOverlay::onTimer)
255 , m_activeProfilerCount(0)
256 {
257 }
258
~InspectorOverlay()259 InspectorOverlay::~InspectorOverlay()
260 {
261 }
262
paint(GraphicsContext & context)263 void InspectorOverlay::paint(GraphicsContext& context)
264 {
265 if (isEmpty())
266 return;
267 GraphicsContextStateSaver stateSaver(context);
268 FrameView* view = overlayPage()->mainFrame()->view();
269 ASSERT(!view->needsLayout());
270 view->paint(&context, IntRect(0, 0, view->width(), view->height()));
271 }
272
invalidate()273 void InspectorOverlay::invalidate()
274 {
275 m_client->highlight();
276 }
277
handleGestureEvent(const PlatformGestureEvent & event)278 bool InspectorOverlay::handleGestureEvent(const PlatformGestureEvent& event)
279 {
280 if (isEmpty())
281 return false;
282
283 return overlayPage()->mainFrame()->eventHandler().handleGestureEvent(event);
284 }
285
handleMouseEvent(const PlatformMouseEvent & event)286 bool InspectorOverlay::handleMouseEvent(const PlatformMouseEvent& event)
287 {
288 if (isEmpty())
289 return false;
290
291 EventHandler& eventHandler = overlayPage()->mainFrame()->eventHandler();
292 bool result;
293 switch (event.type()) {
294 case PlatformEvent::MouseMoved:
295 result = eventHandler.handleMouseMoveEvent(event);
296 break;
297 case PlatformEvent::MousePressed:
298 result = eventHandler.handleMousePressEvent(event);
299 break;
300 case PlatformEvent::MouseReleased:
301 result = eventHandler.handleMouseReleaseEvent(event);
302 break;
303 default:
304 return false;
305 }
306
307 overlayPage()->mainFrame()->document()->updateLayout();
308 return result;
309 }
310
handleTouchEvent(const PlatformTouchEvent & event)311 bool InspectorOverlay::handleTouchEvent(const PlatformTouchEvent& event)
312 {
313 if (isEmpty())
314 return false;
315
316 return overlayPage()->mainFrame()->eventHandler().handleTouchEvent(event);
317 }
318
handleKeyboardEvent(const PlatformKeyboardEvent & event)319 bool InspectorOverlay::handleKeyboardEvent(const PlatformKeyboardEvent& event)
320 {
321 if (isEmpty())
322 return false;
323
324 return overlayPage()->mainFrame()->eventHandler().keyEvent(event);
325 }
326
drawOutline(GraphicsContext * context,const LayoutRect & rect,const Color & color)327 void InspectorOverlay::drawOutline(GraphicsContext* context, const LayoutRect& rect, const Color& color)
328 {
329 FloatRect outlineRect = rect;
330 drawOutlinedQuad(context, outlineRect, Color(), color);
331 }
332
getHighlight(Highlight * highlight) const333 void InspectorOverlay::getHighlight(Highlight* highlight) const
334 {
335 if (!m_highlightNode && !m_highlightQuad)
336 return;
337
338 highlight->type = HighlightTypeRects;
339 if (m_highlightNode)
340 buildNodeHighlight(m_highlightNode.get(), m_nodeHighlightConfig, highlight);
341 else
342 buildQuadHighlight(m_page, *m_highlightQuad, m_quadHighlightConfig, highlight);
343 }
344
resize(const IntSize & size)345 void InspectorOverlay::resize(const IntSize& size)
346 {
347 m_size = size;
348 update();
349 }
350
setPausedInDebuggerMessage(const String * message)351 void InspectorOverlay::setPausedInDebuggerMessage(const String* message)
352 {
353 m_pausedInDebuggerMessage = message ? *message : String();
354 update();
355 }
356
setInspectModeEnabled(bool enabled)357 void InspectorOverlay::setInspectModeEnabled(bool enabled)
358 {
359 m_inspectModeEnabled = enabled;
360 update();
361 }
362
hideHighlight()363 void InspectorOverlay::hideHighlight()
364 {
365 m_highlightNode.clear();
366 m_eventTargetNode.clear();
367 m_highlightQuad.clear();
368 update();
369 }
370
highlightNode(Node * node,Node * eventTarget,const HighlightConfig & highlightConfig)371 void InspectorOverlay::highlightNode(Node* node, Node* eventTarget, const HighlightConfig& highlightConfig)
372 {
373 m_nodeHighlightConfig = highlightConfig;
374 m_highlightNode = node;
375 m_eventTargetNode = eventTarget;
376 update();
377 }
378
highlightQuad(PassOwnPtr<FloatQuad> quad,const HighlightConfig & highlightConfig)379 void InspectorOverlay::highlightQuad(PassOwnPtr<FloatQuad> quad, const HighlightConfig& highlightConfig)
380 {
381 m_quadHighlightConfig = highlightConfig;
382 m_highlightQuad = quad;
383 update();
384 }
385
showAndHideViewSize(bool showGrid)386 void InspectorOverlay::showAndHideViewSize(bool showGrid)
387 {
388 m_drawViewSize = true;
389 m_drawViewSizeWithGrid = showGrid;
390 update();
391 m_timer.startOneShot(1);
392 }
393
highlightedNode() const394 Node* InspectorOverlay::highlightedNode() const
395 {
396 return m_highlightNode.get();
397 }
398
isEmpty()399 bool InspectorOverlay::isEmpty()
400 {
401 if (m_activeProfilerCount)
402 return true;
403 bool hasAlwaysVisibleElements = m_highlightNode || m_eventTargetNode || m_highlightQuad || !m_size.isEmpty() || m_drawViewSize;
404 bool hasInvisibleInInspectModeElements = !m_pausedInDebuggerMessage.isNull();
405 return !(hasAlwaysVisibleElements || (hasInvisibleInInspectModeElements && !m_inspectModeEnabled));
406 }
407
update()408 void InspectorOverlay::update()
409 {
410 if (isEmpty()) {
411 m_client->hideHighlight();
412 return;
413 }
414
415 FrameView* view = m_page->mainFrame()->view();
416 if (!view)
417 return;
418 IntRect viewRect = view->visibleContentRect();
419 FrameView* overlayView = overlayPage()->mainFrame()->view();
420
421 // Include scrollbars to avoid masking them by the gutter.
422 IntSize frameViewFullSize = view->visibleContentRect(ScrollableArea::IncludeScrollbars).size();
423 IntSize size = m_size.isEmpty() ? frameViewFullSize : m_size;
424 size.scale(m_page->pageScaleFactor());
425 overlayView->resize(size);
426
427 // Clear canvas and paint things.
428 reset(size, m_size.isEmpty() ? IntSize() : frameViewFullSize, viewRect.x(), viewRect.y());
429
430 drawNodeHighlight();
431 drawQuadHighlight();
432 if (!m_inspectModeEnabled)
433 drawPausedInDebuggerMessage();
434 drawViewSize();
435
436 // Position DOM elements.
437 overlayPage()->mainFrame()->document()->recalcStyle(Force);
438 if (overlayView->needsLayout())
439 overlayView->layout();
440
441 // Kick paint.
442 m_client->highlight();
443 }
444
hide()445 void InspectorOverlay::hide()
446 {
447 m_timer.stop();
448 m_highlightNode.clear();
449 m_eventTargetNode.clear();
450 m_highlightQuad.clear();
451 m_pausedInDebuggerMessage = String();
452 m_size = IntSize();
453 m_drawViewSize = false;
454 m_drawViewSizeWithGrid = false;
455 update();
456 }
457
buildObjectForPoint(const FloatPoint & point)458 static PassRefPtr<JSONObject> buildObjectForPoint(const FloatPoint& point)
459 {
460 RefPtr<JSONObject> object = JSONObject::create();
461 object->setNumber("x", point.x());
462 object->setNumber("y", point.y());
463 return object.release();
464 }
465
buildArrayForQuad(const FloatQuad & quad)466 static PassRefPtr<JSONArray> buildArrayForQuad(const FloatQuad& quad)
467 {
468 RefPtr<JSONArray> array = JSONArray::create();
469 array->pushObject(buildObjectForPoint(quad.p1()));
470 array->pushObject(buildObjectForPoint(quad.p2()));
471 array->pushObject(buildObjectForPoint(quad.p3()));
472 array->pushObject(buildObjectForPoint(quad.p4()));
473 return array.release();
474 }
475
buildObjectForHighlight(const Highlight & highlight)476 static PassRefPtr<JSONObject> buildObjectForHighlight(const Highlight& highlight)
477 {
478 RefPtr<JSONObject> object = JSONObject::create();
479 RefPtr<JSONArray> array = JSONArray::create();
480 for (size_t i = 0; i < highlight.quads.size(); ++i)
481 array->pushArray(buildArrayForQuad(highlight.quads[i]));
482 object->setArray("quads", array.release());
483 object->setBoolean("showRulers", highlight.showRulers);
484 object->setString("contentColor", highlight.contentColor.serialized());
485 object->setString("contentOutlineColor", highlight.contentOutlineColor.serialized());
486 object->setString("paddingColor", highlight.paddingColor.serialized());
487 object->setString("borderColor", highlight.borderColor.serialized());
488 object->setString("marginColor", highlight.marginColor.serialized());
489 object->setString("eventTargetColor", highlight.eventTargetColor.serialized());
490 return object.release();
491 }
492
buildObjectForSize(const IntSize & size)493 static PassRefPtr<JSONObject> buildObjectForSize(const IntSize& size)
494 {
495 RefPtr<JSONObject> result = JSONObject::create();
496 result->setNumber("width", size.width());
497 result->setNumber("height", size.height());
498 return result.release();
499 }
500
drawNodeHighlight()501 void InspectorOverlay::drawNodeHighlight()
502 {
503 if (!m_highlightNode)
504 return;
505
506 Highlight highlight;
507 buildNodeHighlight(m_highlightNode.get(), m_nodeHighlightConfig, &highlight);
508 if (m_eventTargetNode) {
509 Highlight eventTargetHighlight;
510 buildNodeHighlight(m_eventTargetNode.get(), m_nodeHighlightConfig, &eventTargetHighlight);
511 highlight.quads.append(eventTargetHighlight.quads[1]); // Add border from eventTargetNode to highlight.
512 }
513 RefPtr<JSONObject> highlightObject = buildObjectForHighlight(highlight);
514
515 Node* node = m_highlightNode.get();
516 if (node->isElementNode() && m_nodeHighlightConfig.showInfo && node->renderer() && node->document().frame()) {
517 RefPtr<JSONObject> elementInfo = JSONObject::create();
518 Element* element = toElement(node);
519 Element* realElement = element;
520 PseudoElement* pseudoElement = 0;
521 if (element->isPseudoElement()) {
522 pseudoElement = toPseudoElement(element);
523 realElement = element->parentOrShadowHostElement();
524 }
525 bool isXHTML = realElement->document().isXHTMLDocument();
526 elementInfo->setString("tagName", isXHTML ? realElement->nodeName() : realElement->nodeName().lower());
527 elementInfo->setString("idValue", realElement->getIdAttribute());
528 StringBuilder classNames;
529 if (realElement->hasClass() && realElement->isStyledElement()) {
530 HashSet<AtomicString> usedClassNames;
531 const SpaceSplitString& classNamesString = realElement->classNames();
532 size_t classNameCount = classNamesString.size();
533 for (size_t i = 0; i < classNameCount; ++i) {
534 const AtomicString& className = classNamesString[i];
535 if (!usedClassNames.add(className).isNewEntry)
536 continue;
537 classNames.append('.');
538 classNames.append(className);
539 }
540 }
541 if (pseudoElement) {
542 if (pseudoElement->pseudoId() == BEFORE)
543 classNames.append("::before");
544 else if (pseudoElement->pseudoId() == AFTER)
545 classNames.append("::after");
546 }
547 if (!classNames.isEmpty())
548 elementInfo->setString("className", classNames.toString());
549
550 RenderObject* renderer = node->renderer();
551 Frame* containingFrame = node->document().frame();
552 FrameView* containingView = containingFrame->view();
553 IntRect boundingBox = pixelSnappedIntRect(containingView->contentsToRootView(renderer->absoluteBoundingBoxRect()));
554 RenderBoxModelObject* modelObject = renderer->isBoxModelObject() ? toRenderBoxModelObject(renderer) : 0;
555 elementInfo->setString("nodeWidth", String::number(modelObject ? adjustForAbsoluteZoom(modelObject->pixelSnappedOffsetWidth(), modelObject) : boundingBox.width()));
556 elementInfo->setString("nodeHeight", String::number(modelObject ? adjustForAbsoluteZoom(modelObject->pixelSnappedOffsetHeight(), modelObject) : boundingBox.height()));
557 highlightObject->setObject("elementInfo", elementInfo.release());
558 }
559 evaluateInOverlay("drawNodeHighlight", highlightObject);
560 }
561
drawQuadHighlight()562 void InspectorOverlay::drawQuadHighlight()
563 {
564 if (!m_highlightQuad)
565 return;
566
567 Highlight highlight;
568 buildQuadHighlight(m_page, *m_highlightQuad, m_quadHighlightConfig, &highlight);
569 evaluateInOverlay("drawQuadHighlight", buildObjectForHighlight(highlight));
570 }
571
drawPausedInDebuggerMessage()572 void InspectorOverlay::drawPausedInDebuggerMessage()
573 {
574 if (!m_pausedInDebuggerMessage.isNull())
575 evaluateInOverlay("drawPausedInDebuggerMessage", m_pausedInDebuggerMessage);
576 }
577
drawViewSize()578 void InspectorOverlay::drawViewSize()
579 {
580 if (m_drawViewSize)
581 evaluateInOverlay("drawViewSize", m_drawViewSizeWithGrid ? "true" : "false");
582 }
583
overlayPage()584 Page* InspectorOverlay::overlayPage()
585 {
586 if (m_overlayPage)
587 return m_overlayPage.get();
588
589 static FrameLoaderClient* dummyFrameLoaderClient = new EmptyFrameLoaderClient;
590 Page::PageClients pageClients;
591 fillWithEmptyClients(pageClients);
592 ASSERT(!m_overlayChromeClient);
593 m_overlayChromeClient = adoptPtr(new InspectorOverlayChromeClient(m_page->chrome().client(), this));
594 pageClients.chromeClient = m_overlayChromeClient.get();
595 m_overlayPage = adoptPtr(new Page(pageClients));
596
597 Settings& settings = m_page->settings();
598 Settings& overlaySettings = m_overlayPage->settings();
599
600 overlaySettings.genericFontFamilySettings().setStandard(settings.genericFontFamilySettings().standard());
601 overlaySettings.genericFontFamilySettings().setSerif(settings.genericFontFamilySettings().serif());
602 overlaySettings.genericFontFamilySettings().setSansSerif(settings.genericFontFamilySettings().sansSerif());
603 overlaySettings.genericFontFamilySettings().setCursive(settings.genericFontFamilySettings().cursive());
604 overlaySettings.genericFontFamilySettings().setFantasy(settings.genericFontFamilySettings().fantasy());
605 overlaySettings.genericFontFamilySettings().setPictograph(settings.genericFontFamilySettings().pictograph());
606 overlaySettings.setMinimumFontSize(settings.minimumFontSize());
607 overlaySettings.setMinimumLogicalFontSize(settings.minimumLogicalFontSize());
608 overlaySettings.setMediaEnabled(false);
609 overlaySettings.setScriptEnabled(true);
610 overlaySettings.setPluginsEnabled(false);
611 overlaySettings.setLoadsImagesAutomatically(true);
612
613 RefPtr<Frame> frame = Frame::create(FrameInit::create(0, m_overlayPage.get(), dummyFrameLoaderClient));
614 frame->setView(FrameView::create(frame.get()));
615 frame->init();
616 FrameLoader& loader = frame->loader();
617 frame->view()->setCanHaveScrollbars(false);
618 frame->view()->setTransparent(true);
619 ASSERT(loader.activeDocumentLoader());
620 DocumentWriter* writer = loader.activeDocumentLoader()->beginWriting("text/html", "UTF-8");
621 writer->addData(reinterpret_cast<const char*>(InspectorOverlayPage_html), sizeof(InspectorOverlayPage_html));
622 loader.activeDocumentLoader()->endWriting(writer);
623 v8::Isolate* isolate = toIsolate(frame.get());
624 v8::HandleScope handleScope(isolate);
625 v8::Handle<v8::Context> frameContext = frame->script().currentWorldContext();
626 v8::Context::Scope contextScope(frameContext);
627 v8::Handle<v8::Value> overlayHostObj = toV8(m_overlayHost.get(), v8::Handle<v8::Object>(), isolate);
628 v8::Handle<v8::Object> global = frameContext->Global();
629 global->Set(v8::String::NewFromUtf8(isolate, "InspectorOverlayHost"), overlayHostObj);
630
631 #if OS(WIN)
632 evaluateInOverlay("setPlatform", "windows");
633 #elif OS(MACOSX)
634 evaluateInOverlay("setPlatform", "mac");
635 #elif OS(POSIX)
636 evaluateInOverlay("setPlatform", "linux");
637 #endif
638
639 return m_overlayPage.get();
640 }
641
reset(const IntSize & viewportSize,const IntSize & frameViewFullSize,int scrollX,int scrollY)642 void InspectorOverlay::reset(const IntSize& viewportSize, const IntSize& frameViewFullSize, int scrollX, int scrollY)
643 {
644 RefPtr<JSONObject> resetData = JSONObject::create();
645 resetData->setNumber("pageScaleFactor", m_page->pageScaleFactor());
646 resetData->setNumber("deviceScaleFactor", m_page->deviceScaleFactor());
647 resetData->setObject("viewportSize", buildObjectForSize(viewportSize));
648 resetData->setObject("frameViewFullSize", buildObjectForSize(frameViewFullSize));
649 resetData->setNumber("pageZoomFactor", m_page->mainFrame()->pageZoomFactor());
650 resetData->setNumber("scrollX", scrollX);
651 resetData->setNumber("scrollY", scrollY);
652 evaluateInOverlay("reset", resetData.release());
653 }
654
evaluateInOverlay(const String & method,const String & argument)655 void InspectorOverlay::evaluateInOverlay(const String& method, const String& argument)
656 {
657 RefPtr<JSONArray> command = JSONArray::create();
658 command->pushString(method);
659 command->pushString(argument);
660 overlayPage()->mainFrame()->script().executeScriptInMainWorld("dispatch(" + command->toJSONString() + ")", ScriptController::ExecuteScriptWhenScriptsDisabled);
661 }
662
evaluateInOverlay(const String & method,PassRefPtr<JSONValue> argument)663 void InspectorOverlay::evaluateInOverlay(const String& method, PassRefPtr<JSONValue> argument)
664 {
665 RefPtr<JSONArray> command = JSONArray::create();
666 command->pushString(method);
667 command->pushValue(argument);
668 overlayPage()->mainFrame()->script().executeScriptInMainWorld("dispatch(" + command->toJSONString() + ")", ScriptController::ExecuteScriptWhenScriptsDisabled);
669 }
670
onTimer(Timer<InspectorOverlay> *)671 void InspectorOverlay::onTimer(Timer<InspectorOverlay>*)
672 {
673 m_drawViewSize = false;
674 update();
675 }
676
getBoxModel(Node * node,Vector<FloatQuad> * quads)677 bool InspectorOverlay::getBoxModel(Node* node, Vector<FloatQuad>* quads)
678 {
679 return buildNodeQuads(node, *quads);
680 }
681
freePage()682 void InspectorOverlay::freePage()
683 {
684 m_overlayPage.clear();
685 m_overlayChromeClient.clear();
686 m_timer.stop();
687 }
688
startedRecordingProfile()689 void InspectorOverlay::startedRecordingProfile()
690 {
691 if (!m_activeProfilerCount++)
692 freePage();
693 }
694
695 } // namespace WebCore
696