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