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