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