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