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