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