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