Web Inspector: Push More Inspector Required Classes Down into JavaScriptCore
[WebKit-https.git] / Source / WebCore / 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
31 #if ENABLE(INSPECTOR)
32
33 #include "InspectorOverlay.h"
34
35 #include "DocumentLoader.h"
36 #include "Element.h"
37 #include "EmptyClients.h"
38 #include "FrameView.h"
39 #include "GraphicsContext.h"
40 #include "InspectorClient.h"
41 #include "InspectorOverlayPage.h"
42 #include "MainFrame.h"
43 #include "Node.h"
44 #include "Page.h"
45 #include "PolygonShape.h"
46 #include "RectangleShape.h"
47 #include "RenderBoxModelObject.h"
48 #include "RenderElement.h"
49 #include "RenderFlowThread.h"
50 #include "RenderInline.h"
51 #include "RenderNamedFlowFragment.h"
52 #include "RenderNamedFlowThread.h"
53 #include "RenderRegion.h"
54 #include "RenderView.h"
55 #include "ScriptController.h"
56 #include "ScriptSourceCode.h"
57 #include "Settings.h"
58 #include "StyledElement.h"
59 #include <bindings/ScriptValue.h>
60 #include <inspector/InspectorValues.h>
61 #include <wtf/text/StringBuilder.h>
62
63 using namespace Inspector;
64
65 namespace WebCore {
66
67 namespace {
68
69 Path quadToPath(const FloatQuad& quad)
70 {
71     Path quadPath;
72     quadPath.moveTo(quad.p1());
73     quadPath.addLineTo(quad.p2());
74     quadPath.addLineTo(quad.p3());
75     quadPath.addLineTo(quad.p4());
76     quadPath.closeSubpath();
77     return quadPath;
78 }
79
80 void drawOutlinedQuad(GraphicsContext* context, const FloatQuad& quad, const Color& fillColor, const Color& outlineColor)
81 {
82     static const int outlineThickness = 2;
83
84     Path quadPath = quadToPath(quad);
85
86     // Clip out the quad, then draw with a 2px stroke to get a pixel
87     // of outline (because inflating a quad is hard)
88     {
89         context->save();
90         context->clipOut(quadPath);
91
92         context->setStrokeThickness(outlineThickness);
93         context->setStrokeColor(outlineColor, ColorSpaceDeviceRGB);
94         context->strokePath(quadPath);
95
96         context->restore();
97     }
98
99     // Now do the fill
100     context->setFillColor(fillColor, ColorSpaceDeviceRGB);
101     context->fillPath(quadPath);
102 }
103
104 static void contentsQuadToPage(const FrameView* mainView, const FrameView* view, FloatQuad& quad)
105 {
106     quad.setP1(view->contentsToRootView(roundedIntPoint(quad.p1())));
107     quad.setP2(view->contentsToRootView(roundedIntPoint(quad.p2())));
108     quad.setP3(view->contentsToRootView(roundedIntPoint(quad.p3())));
109     quad.setP4(view->contentsToRootView(roundedIntPoint(quad.p4())));
110     quad += mainView->scrollOffset();
111 }
112
113 static void buildRendererHighlight(RenderObject* renderer, RenderRegion* region, const HighlightConfig& highlightConfig, Highlight* highlight)
114 {
115     Frame* containingFrame = renderer->document().frame();
116     if (!containingFrame)
117         return;
118
119     highlight->setDataFromConfig(highlightConfig);
120     FrameView* containingView = containingFrame->view();
121     FrameView* mainView = containingFrame->page()->mainFrame().view();
122
123     // RenderSVGRoot should be highlighted through the isBox() code path, all other SVG elements should just dump their absoluteQuads().
124 #if ENABLE(SVG)
125     bool isSVGRenderer = renderer->node() && renderer->node()->isSVGElement() && !renderer->isSVGRoot();
126 #else
127     bool isSVGRenderer = false;
128 #endif
129
130     if (isSVGRenderer) {
131         highlight->type = HighlightTypeRects;
132         renderer->absoluteQuads(highlight->quads);
133         for (size_t i = 0; i < highlight->quads.size(); ++i)
134             contentsQuadToPage(mainView, containingView, highlight->quads[i]);
135     } else if (renderer->isBox() || renderer->isRenderInline()) {
136         LayoutRect contentBox;
137         LayoutRect paddingBox;
138         LayoutRect borderBox;
139         LayoutRect marginBox;
140
141         if (renderer->isBox()) {
142             RenderBox* renderBox = toRenderBox(renderer);
143
144             LayoutBoxExtent margins(renderBox->marginTop(), renderBox->marginRight(), renderBox->marginBottom(), renderBox->marginLeft());
145
146             if (!renderBox->isOutOfFlowPositioned() && region) {
147                 RenderBox::LogicalExtentComputedValues computedValues;
148                 renderBox->computeLogicalWidthInRegion(computedValues, region);
149                 margins.mutableLogicalLeft(renderBox->style().writingMode()) = computedValues.m_margins.m_start;
150                 margins.mutableLogicalRight(renderBox->style().writingMode()) = computedValues.m_margins.m_end;
151             }
152
153             paddingBox = renderBox->clientBoxRectInRegion(region);
154             contentBox = LayoutRect(paddingBox.x() + renderBox->paddingLeft(), paddingBox.y() + renderBox->paddingTop(),
155                 paddingBox.width() - renderBox->paddingLeft() - renderBox->paddingRight(), paddingBox.height() - renderBox->paddingTop() - renderBox->paddingBottom());
156             borderBox = LayoutRect(paddingBox.x() - renderBox->borderLeft(), paddingBox.y() - renderBox->borderTop(),
157                 paddingBox.width() + renderBox->borderLeft() + renderBox->borderRight(), paddingBox.height() + renderBox->borderTop() + renderBox->borderBottom());
158             marginBox = LayoutRect(borderBox.x() - margins.left(), borderBox.y() - margins.top(),
159                 borderBox.width() + margins.left() + margins.right(), borderBox.height() + margins.top() + margins.bottom());
160         } else {
161             RenderInline* renderInline = toRenderInline(renderer);
162
163             // RenderInline's bounding box includes paddings and borders, excludes margins.
164             borderBox = renderInline->linesBoundingBox();
165             paddingBox = LayoutRect(borderBox.x() + renderInline->borderLeft(), borderBox.y() + renderInline->borderTop(),
166                 borderBox.width() - renderInline->borderLeft() - renderInline->borderRight(), borderBox.height() - renderInline->borderTop() - renderInline->borderBottom());
167             contentBox = LayoutRect(paddingBox.x() + renderInline->paddingLeft(), paddingBox.y() + renderInline->paddingTop(),
168                 paddingBox.width() - renderInline->paddingLeft() - renderInline->paddingRight(), paddingBox.height() - renderInline->paddingTop() - renderInline->paddingBottom());
169             // Ignore marginTop and marginBottom for inlines.
170             marginBox = LayoutRect(borderBox.x() - renderInline->marginLeft(), borderBox.y(),
171                 borderBox.width() + renderInline->marginWidth(), borderBox.height());
172         }
173
174         FloatQuad absContentQuad;
175         FloatQuad absPaddingQuad;
176         FloatQuad absBorderQuad;
177         FloatQuad absMarginQuad;
178
179         if (region) {
180             RenderFlowThread* flowThread = region->flowThread();
181
182             // Figure out the quads in the space of the RenderFlowThread.
183             absContentQuad = renderer->localToContainerQuad(FloatRect(contentBox), flowThread);
184             absPaddingQuad = renderer->localToContainerQuad(FloatRect(paddingBox), flowThread);
185             absBorderQuad = renderer->localToContainerQuad(FloatRect(borderBox), flowThread);
186             absMarginQuad = renderer->localToContainerQuad(FloatRect(marginBox), flowThread);
187
188             // Move the quad relative to the space of the current region.
189             LayoutRect flippedRegionRect(region->flowThreadPortionRect());
190             flowThread->flipForWritingMode(flippedRegionRect);
191
192             FloatSize delta = region->contentBoxRect().location() - flippedRegionRect.location();
193             absContentQuad.move(delta);
194             absPaddingQuad.move(delta);
195             absBorderQuad.move(delta);
196             absMarginQuad.move(delta);
197
198             // Resolve the absolute quads starting from the current region.
199             absContentQuad = region->localToAbsoluteQuad(absContentQuad);
200             absPaddingQuad = region->localToAbsoluteQuad(absPaddingQuad);
201             absBorderQuad = region->localToAbsoluteQuad(absBorderQuad);
202             absMarginQuad = region->localToAbsoluteQuad(absMarginQuad);
203         } else {
204             absContentQuad = renderer->localToAbsoluteQuad(FloatRect(contentBox));
205             absPaddingQuad = renderer->localToAbsoluteQuad(FloatRect(paddingBox));
206             absBorderQuad = renderer->localToAbsoluteQuad(FloatRect(borderBox));
207             absMarginQuad = renderer->localToAbsoluteQuad(FloatRect(marginBox));
208         }
209
210         contentsQuadToPage(mainView, containingView, absContentQuad);
211         contentsQuadToPage(mainView, containingView, absPaddingQuad);
212         contentsQuadToPage(mainView, containingView, absBorderQuad);
213         contentsQuadToPage(mainView, containingView, absMarginQuad);
214
215         highlight->type = HighlightTypeNode;
216         highlight->quads.append(absMarginQuad);
217         highlight->quads.append(absBorderQuad);
218         highlight->quads.append(absPaddingQuad);
219         highlight->quads.append(absContentQuad);
220     }
221 }
222
223 static void buildNodeHighlight(Node* node, RenderRegion* region, const HighlightConfig& highlightConfig, Highlight* highlight)
224 {
225     RenderObject* renderer = node->renderer();
226     if (!renderer)
227         return;
228     buildRendererHighlight(renderer, region, highlightConfig, highlight);
229 }
230
231 static void buildQuadHighlight(Page* page, const FloatQuad& quad, const HighlightConfig& highlightConfig, Highlight *highlight)
232 {
233     if (!page)
234         return;
235     highlight->setDataFromConfig(highlightConfig);
236     highlight->type = HighlightTypeRects;
237     highlight->quads.append(quad);
238 }
239
240 } // anonymous namespace
241
242 InspectorOverlay::InspectorOverlay(Page* page, InspectorClient* client)
243     : m_page(page)
244     , m_client(client)
245 {
246 }
247
248 InspectorOverlay::~InspectorOverlay()
249 {
250 }
251
252 void InspectorOverlay::paint(GraphicsContext& context)
253 {
254     if (m_pausedInDebuggerMessage.isNull() && !m_highlightNode && !m_highlightQuad && m_size.isEmpty())
255         return;
256     GraphicsContextStateSaver stateSaver(context);
257     FrameView* view = overlayPage()->mainFrame().view();
258     view->updateLayoutAndStyleIfNeededRecursive();
259     view->paint(&context, IntRect(0, 0, view->width(), view->height()));
260 }
261
262 void InspectorOverlay::drawOutline(GraphicsContext* context, const LayoutRect& rect, const Color& color)
263 {
264     FloatRect outlineRect = rect;
265     drawOutlinedQuad(context, outlineRect, Color(), color);
266 }
267
268 void InspectorOverlay::getHighlight(Highlight* highlight) const
269 {
270     if (!m_highlightNode && !m_highlightQuad)
271         return;
272
273     highlight->type = HighlightTypeRects;
274     if (m_highlightNode)
275         buildNodeHighlight(m_highlightNode.get(), nullptr, m_nodeHighlightConfig, highlight);
276     else
277         buildQuadHighlight(m_page, *m_highlightQuad, m_quadHighlightConfig, highlight);
278 }
279
280 void InspectorOverlay::setPausedInDebuggerMessage(const String* message)
281 {
282     m_pausedInDebuggerMessage = message ? *message : String();
283     update();
284 }
285
286 void InspectorOverlay::hideHighlight()
287 {
288     m_highlightNode.clear();
289     m_highlightQuad.clear();
290     update();
291 }
292
293 void InspectorOverlay::highlightNode(Node* node, const HighlightConfig& highlightConfig)
294 {
295     m_nodeHighlightConfig = highlightConfig;
296     m_highlightNode = node;
297     update();
298 }
299
300 void InspectorOverlay::highlightQuad(PassOwnPtr<FloatQuad> quad, const HighlightConfig& highlightConfig)
301 {
302     if (m_quadHighlightConfig.usePageCoordinates)
303         *quad -= m_page->mainFrame().view()->scrollOffset();
304
305     m_quadHighlightConfig = highlightConfig;
306     m_highlightQuad = quad;
307     update();
308 }
309
310 Node* InspectorOverlay::highlightedNode() const
311 {
312     return m_highlightNode.get();
313 }
314
315 void InspectorOverlay::didSetSearchingForNode(bool enabled)
316 {
317     m_client->didSetSearchingForNode(enabled);
318 }
319
320 void InspectorOverlay::update()
321 {
322     if (!m_highlightNode && !m_highlightQuad && m_pausedInDebuggerMessage.isNull() && m_size.isEmpty()) {
323         m_client->hideHighlight();
324         return;
325     }
326
327     FrameView* view = m_page->mainFrame().view();
328     if (!view)
329         return;
330
331     FrameView* overlayView = overlayPage()->mainFrame().view();
332     IntSize viewportSize = view->visibleContentRect().size();
333     IntSize frameViewFullSize = view->visibleContentRect(ScrollableArea::IncludeScrollbars).size();
334     IntSize size = m_size.isEmpty() ? frameViewFullSize : m_size;
335     overlayPage()->setPageScaleFactor(m_page->pageScaleFactor(), IntPoint());
336     size.scale(m_page->pageScaleFactor());
337     overlayView->resize(size);
338
339     // Clear canvas and paint things.
340     reset(viewportSize, m_size.isEmpty() ? IntSize() : frameViewFullSize);
341
342     // Include scrollbars to avoid masking them by the gutter.
343     drawGutter();
344     drawNodeHighlight();
345     drawQuadHighlight();
346     drawPausedInDebuggerMessage();
347
348     // Position DOM elements.
349     overlayPage()->mainFrame().document()->recalcStyle(Style::Force);
350     if (overlayView->needsLayout())
351         overlayView->layout();
352
353     // Kick paint.
354     m_client->highlight();
355 }
356
357 static PassRefPtr<InspectorObject> buildObjectForPoint(const FloatPoint& point)
358 {
359     RefPtr<InspectorObject> object = InspectorObject::create();
360     object->setNumber("x", point.x());
361     object->setNumber("y", point.y());
362     return object.release();
363 }
364
365 static PassRefPtr<InspectorArray> buildArrayForQuad(const FloatQuad& quad)
366 {
367     RefPtr<InspectorArray> array = InspectorArray::create();
368     array->pushObject(buildObjectForPoint(quad.p1()));
369     array->pushObject(buildObjectForPoint(quad.p2()));
370     array->pushObject(buildObjectForPoint(quad.p3()));
371     array->pushObject(buildObjectForPoint(quad.p4()));
372     return array.release();
373 }
374
375 static PassRefPtr<InspectorObject> buildObjectForHighlight(const Highlight& highlight)
376 {
377     RefPtr<InspectorObject> object = InspectorObject::create();
378     RefPtr<InspectorArray> array = InspectorArray::create();
379     for (size_t i = 0; i < highlight.quads.size(); ++i)
380         array->pushArray(buildArrayForQuad(highlight.quads[i]));
381     object->setArray("quads", array.release());
382     object->setBoolean("showRulers", highlight.showRulers);
383     object->setString("contentColor", highlight.contentColor.serialized());
384     object->setString("contentOutlineColor", highlight.contentOutlineColor.serialized());
385     object->setString("paddingColor", highlight.paddingColor.serialized());
386     object->setString("borderColor", highlight.borderColor.serialized());
387     object->setString("marginColor", highlight.marginColor.serialized());
388     return object.release();
389 }
390
391 static PassRefPtr<InspectorObject> buildObjectForRegionHighlight(FrameView* mainView, RenderRegion* region)
392 {
393     FrameView* containingView = region->frame().view();
394     if (!containingView)
395         return nullptr;
396
397     RenderBlockFlow* regionContainer = toRenderBlockFlow(region->parent());
398     LayoutRect borderBox = regionContainer->borderBoxRect();
399     borderBox.setWidth(borderBox.width() + regionContainer->verticalScrollbarWidth());
400     borderBox.setHeight(borderBox.height() + regionContainer->horizontalScrollbarHeight());
401
402     // Create incoming and outgoing boxes that we use to chain the regions toghether.
403     const LayoutSize linkBoxSize(10, 10);
404     const LayoutSize linkBoxMidpoint(linkBoxSize.width() / 2, linkBoxSize.height() / 2);
405     
406     LayoutRect incomingRectBox = LayoutRect(borderBox.location() - linkBoxMidpoint, linkBoxSize);
407     LayoutRect outgoingRectBox = LayoutRect(borderBox.location() - linkBoxMidpoint + borderBox.size(), linkBoxSize);
408
409     // Move the link boxes slightly inside the region border box.
410     LayoutUnit maxUsableHeight = std::max(LayoutUnit(), borderBox.height() - linkBoxMidpoint.height());
411     LayoutUnit linkBoxVerticalOffset = std::min(LayoutUnit(15), maxUsableHeight);
412     incomingRectBox.move(0, linkBoxVerticalOffset);
413     outgoingRectBox.move(0, -linkBoxVerticalOffset);
414
415     FloatQuad borderRectQuad = regionContainer->localToAbsoluteQuad(FloatRect(borderBox));
416     FloatQuad incomingRectQuad = regionContainer->localToAbsoluteQuad(FloatRect(incomingRectBox));
417     FloatQuad outgoingRectQuad = regionContainer->localToAbsoluteQuad(FloatRect(outgoingRectBox));
418
419     contentsQuadToPage(mainView, containingView, borderRectQuad);
420     contentsQuadToPage(mainView, containingView, incomingRectQuad);
421     contentsQuadToPage(mainView, containingView, outgoingRectQuad);
422
423     RefPtr<InspectorObject> regionObject = InspectorObject::create();
424
425     regionObject->setArray("borderQuad", buildArrayForQuad(borderRectQuad));
426     regionObject->setArray("incomingQuad", buildArrayForQuad(incomingRectQuad));
427     regionObject->setArray("outgoingQuad", buildArrayForQuad(outgoingRectQuad));
428
429     return regionObject.release();
430 }
431
432 static PassRefPtr<InspectorArray> buildObjectForCSSRegionsHighlight(RenderRegion* region, RenderFlowThread* flowThread)
433 {
434     FrameView* mainFrameView = region->document().page()->mainFrame().view();
435
436     RefPtr<InspectorArray> array = InspectorArray::create();
437
438     const RenderRegionList& regionList = flowThread->renderRegionList();
439     for (RenderRegionList::const_iterator iter = regionList.begin(); iter != regionList.end(); ++iter) {
440         RenderRegion* iterRegion = *iter;
441         if (!iterRegion->isValid())
442             continue;
443         RefPtr<InspectorObject> regionHighlightObject = buildObjectForRegionHighlight(mainFrameView, iterRegion);
444         if (!regionHighlightObject)
445             continue;
446         if (region == iterRegion) {
447             // Let the script know that this is the currently highlighted node.
448             regionHighlightObject->setBoolean("isHighlighted", true);
449         }
450         array->pushObject(regionHighlightObject.release());
451     }
452
453     return array.release();
454 }
455
456 static PassRefPtr<InspectorObject> buildObjectForSize(const IntSize& size)
457 {
458     RefPtr<InspectorObject> result = InspectorObject::create();
459     result->setNumber("width", size.width());
460     result->setNumber("height", size.height());
461     return result.release();
462 }
463
464 static PassRefPtr<InspectorObject> buildObjectForCSSRegionContentClip(RenderRegion* region)
465 {
466     Frame* containingFrame = region->document().frame();
467     if (!containingFrame)
468         return nullptr;
469
470     FrameView* containingView = containingFrame->view();
471     FrameView* mainView = containingFrame->page()->mainFrame().view();
472     RenderFlowThread* flowThread = region->flowThread();
473
474     // Get the clip box of the current region and covert it into an absolute quad.
475     LayoutRect flippedRegionRect(region->flowThreadPortionOverflowRect());
476     flowThread->flipForWritingMode(flippedRegionRect);
477
478     // Apply any border or padding of the region.
479     flippedRegionRect.setLocation(region->contentBoxRect().location());
480     
481     FloatQuad clipQuad = region->localToAbsoluteQuad(FloatRect(flippedRegionRect));
482     contentsQuadToPage(mainView, containingView, clipQuad);
483
484     RefPtr<InspectorObject> regionObject = InspectorObject::create();
485     regionObject->setArray("quad", buildArrayForQuad(clipQuad));
486     return regionObject.release();
487 }
488
489 void InspectorOverlay::drawGutter()
490 {
491     evaluateInOverlay("drawGutter", "");
492 }
493
494 static PassRefPtr<InspectorArray> buildObjectForRendererFragments(RenderObject* renderer, const HighlightConfig& config)
495 {
496     RefPtr<InspectorArray> fragmentsArray = InspectorArray::create();
497
498     RenderFlowThread* containingFlowThread = renderer->flowThreadContainingBlock();
499     if (!containingFlowThread) {
500         Highlight highlight;
501         buildRendererHighlight(renderer, nullptr, config, &highlight);
502         fragmentsArray->pushObject(buildObjectForHighlight(highlight));
503     } else {
504         RenderBox* enclosingBox = renderer->enclosingBox();
505         RenderRegion* startRegion = nullptr;
506         RenderRegion* endRegion = nullptr;
507         containingFlowThread->getRegionRangeForBox(enclosingBox, startRegion, endRegion);
508         if (!startRegion) {
509             // The flow has no visible regions. The renderer is not visible on screen.
510             return nullptr;
511         }
512         const RenderRegionList& regionList = containingFlowThread->renderRegionList();
513         for (RenderRegionList::const_iterator iter = regionList.find(startRegion); iter != regionList.end(); ++iter) {
514             RenderRegion* region = *iter;
515             if (region->isValid()) {
516                 // Compute the highlight of the fragment inside the current region.
517                 Highlight highlight;
518                 buildRendererHighlight(renderer, region, config, &highlight);
519                 RefPtr<InspectorObject> fragmentObject = buildObjectForHighlight(highlight);
520
521                 // Compute the clipping area of the region.
522                 fragmentObject->setObject("region", buildObjectForCSSRegionContentClip(region));
523                 fragmentsArray->pushObject(fragmentObject.release());
524             }
525             if (region == endRegion)
526                 break;
527         }
528     }
529
530     return fragmentsArray.release();
531 }
532
533 #if ENABLE(CSS_SHAPES)
534 static FloatPoint localPointToRoot(RenderObject* renderer, const FrameView* mainView, const FrameView* view, const FloatPoint& point)
535 {
536     FloatPoint result = renderer->localToAbsolute(point);
537     result = view->contentsToRootView(roundedIntPoint(result));
538     result += mainView->scrollOffset();
539     return result;
540 }
541
542 struct PathApplyInfo {
543     FrameView* rootView;
544     FrameView* view;
545     InspectorArray* array;
546     RenderObject* renderer;
547     const ShapeOutsideInfo* shapeOutsideInfo;
548 };
549
550 static void appendPathCommandAndPoints(PathApplyInfo* info, const String& command, const FloatPoint points[], unsigned length)
551 {
552     FloatPoint point;
553     info->array->pushString(command);
554     for (unsigned i = 0; i < length; i++) {
555         point = info->shapeOutsideInfo->shapeToRendererPoint(points[i]);
556         point = localPointToRoot(info->renderer, info->rootView, info->view, point);
557         info->array->pushNumber(point.x());
558         info->array->pushNumber(point.y());
559     }
560 }
561
562 static void appendPathSegment(void* info, const PathElement* pathElement)
563 {
564     PathApplyInfo* pathApplyInfo = static_cast<PathApplyInfo*>(info);
565     FloatPoint point;
566     switch (pathElement->type) {
567     // The points member will contain 1 value.
568     case PathElementMoveToPoint:
569         appendPathCommandAndPoints(pathApplyInfo, ASCIILiteral("M"), pathElement->points, 1);
570         break;
571     // The points member will contain 1 value.
572     case PathElementAddLineToPoint:
573         appendPathCommandAndPoints(pathApplyInfo, ASCIILiteral("L"), pathElement->points, 1);
574         break;
575     // The points member will contain 3 values.
576     case PathElementAddCurveToPoint:
577         appendPathCommandAndPoints(pathApplyInfo, ASCIILiteral("C"), pathElement->points, 3);
578         break;
579     // The points member will contain 2 values.
580     case PathElementAddQuadCurveToPoint:
581         appendPathCommandAndPoints(pathApplyInfo, ASCIILiteral("Q"), pathElement->points, 2);
582         break;
583     // The points member will contain no values.
584     case PathElementCloseSubpath:
585         appendPathCommandAndPoints(pathApplyInfo, ASCIILiteral("Z"), nullptr, 0);
586         break;
587     }
588 }
589
590 static PassRefPtr<InspectorObject> buildObjectForShapeOutside(Frame* containingFrame, RenderBox* renderer)
591 {
592     const ShapeOutsideInfo* shapeOutsideInfo = renderer->shapeOutsideInfo();
593     if (!shapeOutsideInfo)
594         return nullptr;
595
596     RefPtr<InspectorObject> shapeObject = InspectorObject::create();
597     LayoutRect shapeBounds = shapeOutsideInfo->computedShapePhysicalBoundingBox();
598     FloatQuad shapeQuad = renderer->localToAbsoluteQuad(FloatRect(shapeBounds));
599     contentsQuadToPage(containingFrame->page()->mainFrame().view(), containingFrame->view(), shapeQuad);
600     shapeObject->setArray(ASCIILiteral("bounds"), buildArrayForQuad(shapeQuad));
601
602     Shape::DisplayPaths paths;
603     shapeOutsideInfo->computedShape().buildDisplayPaths(paths);
604
605     if (paths.shape.length()) {
606         RefPtr<InspectorArray> shapePath = InspectorArray::create();
607         PathApplyInfo info;
608         info.rootView = containingFrame->page()->mainFrame().view();
609         info.view = containingFrame->view();
610         info.array = shapePath.get();
611         info.renderer = renderer;
612         info.shapeOutsideInfo = shapeOutsideInfo;
613
614         paths.shape.apply(&info, &appendPathSegment);
615
616         shapeObject->setArray(ASCIILiteral("shape"), shapePath.release());
617
618         if (paths.marginShape.length()) {
619             shapePath = InspectorArray::create();
620             info.array = shapePath.get();
621
622             paths.marginShape.apply(&info, &appendPathSegment);
623
624             shapeObject->setArray(ASCIILiteral("marginShape"), shapePath.release());
625         }
626     }
627
628     return shapeObject.release();
629 }
630 #endif
631
632 static PassRefPtr<InspectorObject> buildObjectForElementInfo(Node* node)
633 {
634     if (!node->isElementNode() || !node->document().frame())
635         return nullptr;
636
637     RefPtr<InspectorObject> elementInfo = InspectorObject::create();
638
639     Element* element = toElement(node);
640     bool isXHTML = element->document().isXHTMLDocument();
641     elementInfo->setString("tagName", isXHTML ? element->nodeName() : element->nodeName().lower());
642     elementInfo->setString("idValue", element->getIdAttribute());
643     HashSet<AtomicString> usedClassNames;
644     if (element->hasClass() && element->isStyledElement()) {
645         StringBuilder classNames;
646         const SpaceSplitString& classNamesString = toStyledElement(element)->classNames();
647         size_t classNameCount = classNamesString.size();
648         for (size_t i = 0; i < classNameCount; ++i) {
649             const AtomicString& className = classNamesString[i];
650             if (usedClassNames.contains(className))
651                 continue;
652             usedClassNames.add(className);
653             classNames.append('.');
654             classNames.append(className);
655         }
656         elementInfo->setString("className", classNames.toString());
657     }
658
659     RenderElement* renderer = element->renderer();
660     Frame* containingFrame = node->document().frame();
661     FrameView* containingView = containingFrame->view();
662     IntRect boundingBox = pixelSnappedIntRect(containingView->contentsToRootView(renderer->absoluteBoundingBoxRect()));
663     RenderBoxModelObject* modelObject = renderer->isBoxModelObject() ? toRenderBoxModelObject(renderer) : 0;
664     elementInfo->setString("nodeWidth", String::number(modelObject ? adjustForAbsoluteZoom(modelObject->pixelSnappedOffsetWidth(), modelObject) : boundingBox.width()));
665     elementInfo->setString("nodeHeight", String::number(modelObject ? adjustForAbsoluteZoom(modelObject->pixelSnappedOffsetHeight(), modelObject) : boundingBox.height()));
666     
667     if (renderer->isRenderNamedFlowFragmentContainer()) {
668         RenderNamedFlowFragment* region = toRenderBlockFlow(renderer)->renderNamedFlowFragment();
669         RenderFlowThread* flowThread = region->flowThread();
670         if (flowThread && flowThread->isRenderNamedFlowThread()) {
671             RefPtr<InspectorObject> regionFlowInfo = InspectorObject::create();
672             regionFlowInfo->setString("name", toRenderNamedFlowThread(flowThread)->flowThreadName());
673             regionFlowInfo->setArray("regions", buildObjectForCSSRegionsHighlight(region, flowThread));
674             elementInfo->setObject("regionFlowInfo", regionFlowInfo.release());
675         }
676     }
677
678     RenderFlowThread* containingFlowThread = renderer->flowThreadContainingBlock();
679     if (containingFlowThread && containingFlowThread->isRenderNamedFlowThread()) {
680         RefPtr<InspectorObject> contentFlowInfo = InspectorObject::create();
681         contentFlowInfo->setString("name", toRenderNamedFlowThread(containingFlowThread)->flowThreadName());
682         elementInfo->setObject("contentFlowInfo", contentFlowInfo.release());
683     }
684
685 #if ENABLE(CSS_SHAPES)
686     if (renderer->isBox()) {
687         RenderBox* renderBox = toRenderBox(renderer);
688         if (RefPtr<InspectorObject> shapeObject = buildObjectForShapeOutside(containingFrame, renderBox))
689             elementInfo->setObject("shapeOutsideInfo", shapeObject.release());
690     }
691 #endif
692
693     return elementInfo.release();
694 }
695
696 PassRefPtr<InspectorObject> InspectorOverlay::buildObjectForHighlightedNode() const
697 {
698     if (!m_highlightNode)
699         return nullptr;
700
701     Node* node = m_highlightNode.get();
702     RenderObject* renderer = node->renderer();
703     if (!renderer)
704         return nullptr;
705
706     RefPtr<InspectorArray> highlightFragments = buildObjectForRendererFragments(renderer, m_nodeHighlightConfig);
707     if (!highlightFragments)
708         return nullptr;
709
710     RefPtr<InspectorObject> highlightObject = InspectorObject::create();
711
712     // The main view's scroll offset is shared across all quads.
713     FrameView* mainView = m_page->mainFrame().view();
714     highlightObject->setObject("scroll", buildObjectForPoint(!mainView->delegatesScrolling() ? mainView->visibleContentRect().location() : FloatPoint()));
715
716     highlightObject->setArray("fragments", highlightFragments.release());
717
718     if (m_nodeHighlightConfig.showInfo) {
719         RefPtr<InspectorObject> elementInfo = buildObjectForElementInfo(node);
720         if (elementInfo)
721             highlightObject->setObject("elementInfo", elementInfo.release());
722     }
723         
724     return highlightObject.release();
725 }
726
727 void InspectorOverlay::drawNodeHighlight()
728 {
729     RefPtr<InspectorObject> highlightObject = buildObjectForHighlightedNode();
730     if (!highlightObject)
731         return;
732     evaluateInOverlay("drawNodeHighlight", highlightObject);
733 }
734
735 void InspectorOverlay::drawQuadHighlight()
736 {
737     if (!m_highlightQuad)
738         return;
739
740     Highlight highlight;
741     buildQuadHighlight(m_page, *m_highlightQuad, m_quadHighlightConfig, &highlight);
742     evaluateInOverlay("drawQuadHighlight", buildObjectForHighlight(highlight));
743 }
744
745 void InspectorOverlay::drawPausedInDebuggerMessage()
746 {
747     if (!m_pausedInDebuggerMessage.isNull())
748         evaluateInOverlay("drawPausedInDebuggerMessage", m_pausedInDebuggerMessage);
749 }
750
751 Page* InspectorOverlay::overlayPage()
752 {
753     if (m_overlayPage)
754         return m_overlayPage.get();
755
756     Page::PageClients pageClients;
757     fillWithEmptyClients(pageClients);
758     m_overlayPage = adoptPtr(new Page(pageClients));
759
760     Settings& settings = m_page->settings();
761     Settings& overlaySettings = m_overlayPage->settings();
762
763     overlaySettings.setStandardFontFamily(settings.standardFontFamily());
764     overlaySettings.setSerifFontFamily(settings.serifFontFamily());
765     overlaySettings.setSansSerifFontFamily(settings.sansSerifFontFamily());
766     overlaySettings.setCursiveFontFamily(settings.cursiveFontFamily());
767     overlaySettings.setFantasyFontFamily(settings.fantasyFontFamily());
768     overlaySettings.setPictographFontFamily(settings.pictographFontFamily());
769     overlaySettings.setMinimumFontSize(settings.minimumFontSize());
770     overlaySettings.setMinimumLogicalFontSize(settings.minimumLogicalFontSize());
771     overlaySettings.setMediaEnabled(false);
772     overlaySettings.setScriptEnabled(true);
773     overlaySettings.setPluginsEnabled(false);
774
775     Frame& frame = m_overlayPage->mainFrame();
776     frame.setView(FrameView::create(frame));
777     frame.init();
778     FrameLoader& loader = frame.loader();
779     frame.view()->setCanHaveScrollbars(false);
780     frame.view()->setTransparent(true);
781     ASSERT(loader.activeDocumentLoader());
782     loader.activeDocumentLoader()->writer().setMIMEType("text/html");
783     loader.activeDocumentLoader()->writer().begin();
784     loader.activeDocumentLoader()->writer().addData(reinterpret_cast<const char*>(InspectorOverlayPage_html), sizeof(InspectorOverlayPage_html));
785     loader.activeDocumentLoader()->writer().end();
786
787 #if OS(WINDOWS)
788     evaluateInOverlay("setPlatform", "windows");
789 #elif OS(MAC_OS_X)
790     evaluateInOverlay("setPlatform", "mac");
791 #elif OS(UNIX)
792     evaluateInOverlay("setPlatform", "linux");
793 #endif
794
795     return m_overlayPage.get();
796 }
797
798 void InspectorOverlay::reset(const IntSize& viewportSize, const IntSize& frameViewFullSize)
799 {
800     RefPtr<InspectorObject> resetData = InspectorObject::create();
801     resetData->setNumber("deviceScaleFactor", m_page->deviceScaleFactor());
802     resetData->setObject("viewportSize", buildObjectForSize(viewportSize));
803     resetData->setObject("frameViewFullSize", buildObjectForSize(frameViewFullSize));
804     evaluateInOverlay("reset", resetData.release());
805 }
806
807 void InspectorOverlay::evaluateInOverlay(const String& method, const String& argument)
808 {
809     RefPtr<InspectorArray> command = InspectorArray::create();
810     command->pushString(method);
811     command->pushString(argument);
812     overlayPage()->mainFrame().script().evaluate(ScriptSourceCode(makeString("dispatch(", command->toJSONString(), ")")));
813 }
814
815 void InspectorOverlay::evaluateInOverlay(const String& method, PassRefPtr<InspectorValue> argument)
816 {
817     RefPtr<InspectorArray> command = InspectorArray::create();
818     command->pushString(method);
819     command->pushValue(argument);
820     overlayPage()->mainFrame().script().evaluate(ScriptSourceCode(makeString("dispatch(", command->toJSONString(), ")")));
821 }
822
823 void InspectorOverlay::freePage()
824 {
825     m_overlayPage.clear();
826 }
827
828 } // namespace WebCore
829
830 #endif // ENABLE(INSPECTOR)