Use a light scrollbar for transparent web views in dark mode.
[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 "CacheStorageProvider.h"
33 #include "DocumentLoader.h"
34 #include "EditorClient.h"
35 #include "Element.h"
36 #include "EmptyClients.h"
37 #include "Frame.h"
38 #include "FrameView.h"
39 #include "GraphicsContext.h"
40 #include "InspectorClient.h"
41 #include "InspectorOverlayPage.h"
42 #include "LibWebRTCProvider.h"
43 #include "Node.h"
44 #include "Page.h"
45 #include "PageConfiguration.h"
46 #include "PolygonShape.h"
47 #include "PseudoElement.h"
48 #include "RTCController.h"
49 #include "RectangleShape.h"
50 #include "RenderBoxModelObject.h"
51 #include "RenderElement.h"
52 #include "RenderInline.h"
53 #include "RenderView.h"
54 #include "ScriptController.h"
55 #include "ScriptSourceCode.h"
56 #include "Settings.h"
57 #include "SocketProvider.h"
58 #include "StyledElement.h"
59 #include <JavaScriptCore/InspectorProtocolObjects.h>
60 #include <wtf/JSONValues.h>
61
62 #if PLATFORM(MAC)
63 #include "LocalDefaultSystemAppearance.h"
64 #endif
65
66 namespace WebCore {
67
68 using namespace Inspector;
69
70 static void contentsQuadToCoordinateSystem(const FrameView* mainView, const FrameView* view, FloatQuad& quad, InspectorOverlay::CoordinateSystem coordinateSystem)
71 {
72     quad.setP1(view->contentsToRootView(roundedIntPoint(quad.p1())));
73     quad.setP2(view->contentsToRootView(roundedIntPoint(quad.p2())));
74     quad.setP3(view->contentsToRootView(roundedIntPoint(quad.p3())));
75     quad.setP4(view->contentsToRootView(roundedIntPoint(quad.p4())));
76
77     if (coordinateSystem == InspectorOverlay::CoordinateSystem::View)
78         quad += toIntSize(mainView->scrollPosition());
79 }
80
81 static void contentsQuadToPage(const FrameView* mainView, const FrameView* view, FloatQuad& quad)
82 {
83     contentsQuadToCoordinateSystem(mainView, view, quad, InspectorOverlay::CoordinateSystem::View);
84 }
85
86 static void buildRendererHighlight(RenderObject* renderer, const HighlightConfig& highlightConfig, Highlight& highlight, InspectorOverlay::CoordinateSystem coordinateSystem)
87 {
88     Frame* containingFrame = renderer->document().frame();
89     if (!containingFrame)
90         return;
91
92     highlight.setDataFromConfig(highlightConfig);
93     FrameView* containingView = containingFrame->view();
94     FrameView* mainView = containingFrame->page()->mainFrame().view();
95
96     // RenderSVGRoot should be highlighted through the isBox() code path, all other SVG elements should just dump their absoluteQuads().
97     bool isSVGRenderer = renderer->node() && renderer->node()->isSVGElement() && !renderer->isSVGRoot();
98
99     if (isSVGRenderer) {
100         highlight.type = HighlightType::Rects;
101         renderer->absoluteQuads(highlight.quads);
102         for (auto& quad : highlight.quads)
103             contentsQuadToCoordinateSystem(mainView, containingView, quad, coordinateSystem);
104     } else if (is<RenderBox>(*renderer) || is<RenderInline>(*renderer)) {
105         LayoutRect contentBox;
106         LayoutRect paddingBox;
107         LayoutRect borderBox;
108         LayoutRect marginBox;
109
110         if (is<RenderBox>(*renderer)) {
111             auto& renderBox = downcast<RenderBox>(*renderer);
112
113             LayoutBoxExtent margins(renderBox.marginTop(), renderBox.marginRight(), renderBox.marginBottom(), renderBox.marginLeft());
114             paddingBox = renderBox.clientBoxRect();
115             contentBox = LayoutRect(paddingBox.x() + renderBox.paddingLeft(), paddingBox.y() + renderBox.paddingTop(),
116                 paddingBox.width() - renderBox.paddingLeft() - renderBox.paddingRight(), paddingBox.height() - renderBox.paddingTop() - renderBox.paddingBottom());
117             borderBox = LayoutRect(paddingBox.x() - renderBox.borderLeft(), paddingBox.y() - renderBox.borderTop(),
118                 paddingBox.width() + renderBox.borderLeft() + renderBox.borderRight(), paddingBox.height() + renderBox.borderTop() + renderBox.borderBottom());
119             marginBox = LayoutRect(borderBox.x() - margins.left(), borderBox.y() - margins.top(),
120                 borderBox.width() + margins.left() + margins.right(), borderBox.height() + margins.top() + margins.bottom());
121         } else {
122             auto& renderInline = downcast<RenderInline>(*renderer);
123
124             // RenderInline's bounding box includes paddings and borders, excludes margins.
125             borderBox = renderInline.linesBoundingBox();
126             paddingBox = LayoutRect(borderBox.x() + renderInline.borderLeft(), borderBox.y() + renderInline.borderTop(),
127                 borderBox.width() - renderInline.borderLeft() - renderInline.borderRight(), borderBox.height() - renderInline.borderTop() - renderInline.borderBottom());
128             contentBox = LayoutRect(paddingBox.x() + renderInline.paddingLeft(), paddingBox.y() + renderInline.paddingTop(),
129                 paddingBox.width() - renderInline.paddingLeft() - renderInline.paddingRight(), paddingBox.height() - renderInline.paddingTop() - renderInline.paddingBottom());
130             // Ignore marginTop and marginBottom for inlines.
131             marginBox = LayoutRect(borderBox.x() - renderInline.marginLeft(), borderBox.y(),
132                 borderBox.width() + renderInline.horizontalMarginExtent(), borderBox.height());
133         }
134
135         FloatQuad absContentQuad = renderer->localToAbsoluteQuad(FloatRect(contentBox));
136         FloatQuad absPaddingQuad = renderer->localToAbsoluteQuad(FloatRect(paddingBox));
137         FloatQuad absBorderQuad = renderer->localToAbsoluteQuad(FloatRect(borderBox));
138         FloatQuad absMarginQuad = renderer->localToAbsoluteQuad(FloatRect(marginBox));
139
140         contentsQuadToCoordinateSystem(mainView, containingView, absContentQuad, coordinateSystem);
141         contentsQuadToCoordinateSystem(mainView, containingView, absPaddingQuad, coordinateSystem);
142         contentsQuadToCoordinateSystem(mainView, containingView, absBorderQuad, coordinateSystem);
143         contentsQuadToCoordinateSystem(mainView, containingView, absMarginQuad, coordinateSystem);
144
145         highlight.type = HighlightType::Node;
146         highlight.quads.append(absMarginQuad);
147         highlight.quads.append(absBorderQuad);
148         highlight.quads.append(absPaddingQuad);
149         highlight.quads.append(absContentQuad);
150     }
151 }
152
153 static void buildNodeHighlight(Node& node, const HighlightConfig& highlightConfig, Highlight& highlight, InspectorOverlay::CoordinateSystem coordinateSystem)
154 {
155     RenderObject* renderer = node.renderer();
156     if (!renderer)
157         return;
158
159     buildRendererHighlight(renderer, highlightConfig, highlight, coordinateSystem);
160 }
161
162 static void buildQuadHighlight(const FloatQuad& quad, const HighlightConfig& highlightConfig, Highlight& highlight)
163 {
164     highlight.setDataFromConfig(highlightConfig);
165     highlight.type = HighlightType::Rects;
166     highlight.quads.append(quad);
167 }
168
169 InspectorOverlay::InspectorOverlay(Page& page, InspectorClient* client)
170     : m_page(page)
171     , m_client(client)
172     , m_paintRectUpdateTimer(*this, &InspectorOverlay::updatePaintRectsTimerFired)
173 {
174 }
175
176 InspectorOverlay::~InspectorOverlay() = default;
177
178 void InspectorOverlay::paint(GraphicsContext& context)
179 {
180     if (!shouldShowOverlay())
181         return;
182
183     GraphicsContextStateSaver stateSaver(context);
184     FrameView* view = overlayPage()->mainFrame().view();
185
186 #if PLATFORM(MAC)
187     LocalDefaultSystemAppearance localAppearance(view->useDarkAppearance());
188 #endif
189
190     view->updateLayoutAndStyleIfNeededRecursive();
191     view->paint(context, IntRect(0, 0, view->width(), view->height()));
192 }
193
194 void InspectorOverlay::getHighlight(Highlight& highlight, InspectorOverlay::CoordinateSystem coordinateSystem) const
195 {
196     if (!m_highlightNode && !m_highlightQuad && !m_highlightNodeList)
197         return;
198
199     highlight.type = HighlightType::Rects;
200     if (m_highlightNode)
201         buildNodeHighlight(*m_highlightNode, m_nodeHighlightConfig, highlight, coordinateSystem);
202     else if (m_highlightNodeList) {
203         highlight.setDataFromConfig(m_nodeHighlightConfig);
204         for (unsigned i = 0; i < m_highlightNodeList->length(); ++i) {
205             Highlight nodeHighlight;
206             buildNodeHighlight(*(m_highlightNodeList->item(i)), m_nodeHighlightConfig, nodeHighlight, coordinateSystem);
207             if (nodeHighlight.type == HighlightType::Node)
208                 highlight.quads.appendVector(nodeHighlight.quads);
209         }
210         highlight.type = HighlightType::NodeList;
211     } else
212         buildQuadHighlight(*m_highlightQuad, m_quadHighlightConfig, highlight);
213 }
214
215 void InspectorOverlay::setPausedInDebuggerMessage(const String* message)
216 {
217     m_pausedInDebuggerMessage = message ? *message : String();
218     update();
219 }
220
221 void InspectorOverlay::hideHighlight()
222 {
223     m_highlightNode = nullptr;
224     m_highlightNodeList = nullptr;
225     m_highlightQuad = nullptr;
226     update();
227 }
228
229 void InspectorOverlay::highlightNodeList(RefPtr<NodeList>&& nodes, const HighlightConfig& highlightConfig)
230 {
231     m_nodeHighlightConfig = highlightConfig;
232     m_highlightNodeList = WTFMove(nodes);
233     m_highlightNode = nullptr;
234     update();
235 }
236
237 void InspectorOverlay::highlightNode(Node* node, const HighlightConfig& highlightConfig)
238 {
239     m_nodeHighlightConfig = highlightConfig;
240     m_highlightNode = node;
241     m_highlightNodeList = nullptr;
242     update();
243 }
244
245 void InspectorOverlay::highlightQuad(std::unique_ptr<FloatQuad> quad, const HighlightConfig& highlightConfig)
246 {
247     if (highlightConfig.usePageCoordinates)
248         *quad -= toIntSize(m_page.mainFrame().view()->scrollPosition());
249
250     m_quadHighlightConfig = highlightConfig;
251     m_highlightQuad = WTFMove(quad);
252     update();
253 }
254
255 Node* InspectorOverlay::highlightedNode() const
256 {
257     return m_highlightNode.get();
258 }
259
260 void InspectorOverlay::didSetSearchingForNode(bool enabled)
261 {
262     m_client->didSetSearchingForNode(enabled);
263 }
264
265 void InspectorOverlay::setIndicating(bool indicating)
266 {
267     m_indicating = indicating;
268
269     if (m_indicating)
270         evaluateInOverlay("showPageIndication"_s);
271     else
272         evaluateInOverlay("hidePageIndication"_s);
273
274     update();
275 }
276
277 bool InspectorOverlay::shouldShowOverlay() const
278 {
279     return m_highlightNode || m_highlightNodeList || m_highlightQuad || m_indicating || m_showingPaintRects || m_showRulers || !m_pausedInDebuggerMessage.isNull();
280 }
281
282 void InspectorOverlay::update()
283 {
284     if (!shouldShowOverlay()) {
285         m_client->hideHighlight();
286         return;
287     }
288
289     FrameView* view = m_page.mainFrame().view();
290     if (!view)
291         return;
292
293     FrameView* overlayView = overlayPage()->mainFrame().view();
294     IntSize frameViewFullSize = view->sizeForVisibleContent(ScrollableArea::IncludeScrollbars);
295     overlayView->resize(frameViewFullSize);
296
297     // Clear canvas and paint things.
298     IntSize viewportSize = view->sizeForVisibleContent();
299     IntPoint scrollOffset = view->scrollPosition();
300     reset(viewportSize, scrollOffset);
301
302     // Include scrollbars to avoid masking them by the gutter.
303     drawNodeHighlight();
304     drawQuadHighlight();
305     drawPausedInDebuggerMessage();
306     drawPaintRects();
307
308     if (m_showRulers)
309         drawRulers();
310
311     // Position DOM elements.
312     overlayPage()->mainFrame().document()->resolveStyle(Document::ResolveStyleType::Rebuild);
313     if (overlayView->needsLayout())
314         overlayView->layoutContext().layout();
315
316     forcePaint();
317 }
318
319 static Ref<Inspector::Protocol::OverlayTypes::Point> buildObjectForPoint(const FloatPoint& point)
320 {
321     return Inspector::Protocol::OverlayTypes::Point::create()
322         .setX(point.x())
323         .setY(point.y())
324         .release();
325 }
326
327 static Ref<Inspector::Protocol::OverlayTypes::Rect> buildObjectForRect(const FloatRect& rect)
328 {
329     return Inspector::Protocol::OverlayTypes::Rect::create()
330         .setX(rect.x())
331         .setY(rect.y())
332         .setWidth(rect.width())
333         .setHeight(rect.height())
334         .release();
335 }
336
337 static Ref<Inspector::Protocol::OverlayTypes::Quad> buildArrayForQuad(const FloatQuad& quad)
338 {
339     auto array = Inspector::Protocol::OverlayTypes::Quad::create();
340     array->addItem(buildObjectForPoint(quad.p1()));
341     array->addItem(buildObjectForPoint(quad.p2()));
342     array->addItem(buildObjectForPoint(quad.p3()));
343     array->addItem(buildObjectForPoint(quad.p4()));
344     return array;
345 }
346
347 static Ref<Inspector::Protocol::OverlayTypes::FragmentHighlightData> buildObjectForHighlight(const Highlight& highlight)
348 {
349     auto arrayOfQuads = JSON::ArrayOf<Inspector::Protocol::OverlayTypes::Quad>::create();
350     for (auto& quad : highlight.quads)
351         arrayOfQuads->addItem(buildArrayForQuad(quad));
352
353     return Inspector::Protocol::OverlayTypes::FragmentHighlightData::create()
354         .setQuads(WTFMove(arrayOfQuads))
355         .setContentColor(highlight.contentColor.serialized())
356         .setContentOutlineColor(highlight.contentOutlineColor.serialized())
357         .setPaddingColor(highlight.paddingColor.serialized())
358         .setBorderColor(highlight.borderColor.serialized())
359         .setMarginColor(highlight.marginColor.serialized())
360         .release();
361 }
362
363 static Ref<Inspector::Protocol::OverlayTypes::Size> buildObjectForSize(const IntSize& size)
364 {
365     return Inspector::Protocol::OverlayTypes::Size::create()
366         .setWidth(size.width())
367         .setHeight(size.height())
368         .release();
369 }
370
371 void InspectorOverlay::setShowingPaintRects(bool showingPaintRects)
372 {
373     if (m_showingPaintRects == showingPaintRects)
374         return;
375
376     m_showingPaintRects = showingPaintRects;
377     if (!m_showingPaintRects) {
378         m_paintRects.clear();
379         m_paintRectUpdateTimer.stop();
380         drawPaintRects();
381         forcePaint();
382     }
383 }
384
385 void InspectorOverlay::showPaintRect(const FloatRect& rect)
386 {
387     if (!m_showingPaintRects)
388         return;
389
390     IntRect rootRect = m_page.mainFrame().view()->contentsToRootView(enclosingIntRect(rect));
391
392     const auto removeDelay = 250_ms;
393
394     MonotonicTime removeTime = MonotonicTime::now() + removeDelay;
395     m_paintRects.append(TimeRectPair(removeTime, rootRect));
396
397     if (!m_paintRectUpdateTimer.isActive()) {
398         const Seconds paintRectsUpdateInterval { 32_ms };
399         m_paintRectUpdateTimer.startRepeating(paintRectsUpdateInterval);
400     }
401
402     drawPaintRects();
403     forcePaint();
404 }
405
406 void InspectorOverlay::setShowRulers(bool showRulers)
407 {
408     if (m_showRulers == showRulers)
409         return;
410
411     m_showRulers = showRulers;
412
413     update();
414 }
415
416 void InspectorOverlay::updatePaintRectsTimerFired()
417 {
418     MonotonicTime now = MonotonicTime::now();
419     bool rectsChanged = false;
420     while (!m_paintRects.isEmpty() && m_paintRects.first().first < now) {
421         m_paintRects.removeFirst();
422         rectsChanged = true;
423     }
424
425     if (m_paintRects.isEmpty())
426         m_paintRectUpdateTimer.stop();
427
428     if (rectsChanged) {
429         drawPaintRects();
430         forcePaint();
431     }
432 }
433
434 void InspectorOverlay::drawPaintRects()
435 {
436     auto arrayOfRects = JSON::ArrayOf<Inspector::Protocol::OverlayTypes::Rect>::create();
437     for (const auto& pair : m_paintRects)
438         arrayOfRects->addItem(buildObjectForRect(pair.second));
439
440     evaluateInOverlay("updatePaintRects"_s, WTFMove(arrayOfRects));
441 }
442
443 void InspectorOverlay::drawRulers()
444 {
445     evaluateInOverlay("drawRulers"_s);
446 }
447
448 static RefPtr<JSON::ArrayOf<Inspector::Protocol::OverlayTypes::FragmentHighlightData>> buildArrayForRendererFragments(RenderObject* renderer, const HighlightConfig& config)
449 {
450     auto arrayOfFragments = JSON::ArrayOf<Inspector::Protocol::OverlayTypes::FragmentHighlightData>::create();
451
452     Highlight highlight;
453     buildRendererHighlight(renderer, config, highlight, InspectorOverlay::CoordinateSystem::View);
454     arrayOfFragments->addItem(buildObjectForHighlight(highlight));
455
456     return WTFMove(arrayOfFragments);
457 }
458
459 static FloatPoint localPointToRoot(RenderObject* renderer, const FrameView* mainView, const FrameView* view, const FloatPoint& point)
460 {
461     FloatPoint result = renderer->localToAbsolute(point);
462     result = view->contentsToRootView(roundedIntPoint(result));
463     result += toIntSize(mainView->scrollPosition());
464     return result;
465 }
466
467 struct PathApplyInfo {
468     FrameView* rootView;
469     FrameView* view;
470     Inspector::Protocol::OverlayTypes::DisplayPath* pathArray;
471     RenderObject* renderer;
472     const ShapeOutsideInfo* shapeOutsideInfo;
473 };
474
475 static void appendPathCommandAndPoints(PathApplyInfo& info, const String& command, const FloatPoint points[], unsigned length)
476 {
477     FloatPoint point;
478     info.pathArray->addItem(command);
479     for (unsigned i = 0; i < length; i++) {
480         point = info.shapeOutsideInfo->shapeToRendererPoint(points[i]);
481         point = localPointToRoot(info.renderer, info.rootView, info.view, point);
482         info.pathArray->addItem(point.x());
483         info.pathArray->addItem(point.y());
484     }
485 }
486
487 static void appendPathSegment(PathApplyInfo& pathApplyInfo, const PathElement& pathElement)
488 {
489     FloatPoint point;
490     switch (pathElement.type) {
491     // The points member will contain 1 value.
492     case PathElementMoveToPoint:
493         appendPathCommandAndPoints(pathApplyInfo, "M"_s, pathElement.points, 1);
494         break;
495     // The points member will contain 1 value.
496     case PathElementAddLineToPoint:
497         appendPathCommandAndPoints(pathApplyInfo, "L"_s, pathElement.points, 1);
498         break;
499     // The points member will contain 3 values.
500     case PathElementAddCurveToPoint:
501         appendPathCommandAndPoints(pathApplyInfo, "C"_s, pathElement.points, 3);
502         break;
503     // The points member will contain 2 values.
504     case PathElementAddQuadCurveToPoint:
505         appendPathCommandAndPoints(pathApplyInfo, "Q"_s, pathElement.points, 2);
506         break;
507     // The points member will contain no values.
508     case PathElementCloseSubpath:
509         appendPathCommandAndPoints(pathApplyInfo, "Z"_s, nullptr, 0);
510         break;
511     }
512 }
513
514 static RefPtr<Inspector::Protocol::OverlayTypes::ShapeOutsideData> buildObjectForShapeOutside(Frame* containingFrame, RenderBox* renderer)
515 {
516     const ShapeOutsideInfo* shapeOutsideInfo = renderer->shapeOutsideInfo();
517     if (!shapeOutsideInfo)
518         return nullptr;
519
520     LayoutRect shapeBounds = shapeOutsideInfo->computedShapePhysicalBoundingBox();
521     FloatQuad shapeQuad = renderer->localToAbsoluteQuad(FloatRect(shapeBounds));
522     contentsQuadToPage(containingFrame->page()->mainFrame().view(), containingFrame->view(), shapeQuad);
523
524     auto shapeObject = Inspector::Protocol::OverlayTypes::ShapeOutsideData::create()
525         .setBounds(buildArrayForQuad(shapeQuad))
526         .release();
527
528     Shape::DisplayPaths paths;
529     shapeOutsideInfo->computedShape().buildDisplayPaths(paths);
530
531     if (paths.shape.length()) {
532         auto shapePath = Inspector::Protocol::OverlayTypes::DisplayPath::create();
533         PathApplyInfo info;
534         info.rootView = containingFrame->page()->mainFrame().view();
535         info.view = containingFrame->view();
536         info.pathArray = &shapePath.get();
537         info.renderer = renderer;
538         info.shapeOutsideInfo = shapeOutsideInfo;
539
540         paths.shape.apply([&info](const PathElement& pathElement) {
541             appendPathSegment(info, pathElement);
542         });
543
544         shapeObject->setShape(shapePath.copyRef());
545
546         if (paths.marginShape.length()) {
547             auto marginShapePath = Inspector::Protocol::OverlayTypes::DisplayPath::create();
548             info.pathArray = &marginShapePath.get();
549
550             paths.marginShape.apply([&info](const PathElement& pathElement) {
551                 appendPathSegment(info, pathElement);
552             });
553
554             shapeObject->setMarginShape(marginShapePath.copyRef());
555         }
556     }
557
558     return WTFMove(shapeObject);
559 }
560
561 static RefPtr<Inspector::Protocol::OverlayTypes::ElementData> buildObjectForElementData(Node* node, HighlightType)
562 {
563     if (!is<Element>(node) || !node->document().frame())
564         return nullptr;
565
566     Element* effectiveElement = downcast<Element>(node);
567     if (node->isPseudoElement()) {
568         Element* hostElement = downcast<PseudoElement>(*node).hostElement();
569         if (!hostElement)
570             return nullptr;
571         effectiveElement = hostElement;
572     }
573
574     Element& element = *effectiveElement;
575     bool isXHTML = element.document().isXHTMLDocument();
576     auto elementData = Inspector::Protocol::OverlayTypes::ElementData::create()
577         .setTagName(isXHTML ? element.nodeName() : element.nodeName().convertToASCIILowercase())
578         .setIdValue(element.getIdAttribute())
579         .release();
580
581     if (element.hasClass() && is<StyledElement>(element)) {
582         auto classes = JSON::ArrayOf<String>::create();
583         HashSet<AtomicString> usedClassNames;
584         const SpaceSplitString& classNamesString = downcast<StyledElement>(element).classNames();
585         for (size_t i = 0; i < classNamesString.size(); ++i) {
586             const AtomicString& className = classNamesString[i];
587             if (usedClassNames.contains(className))
588                 continue;
589
590             usedClassNames.add(className);
591             classes->addItem(className);
592         }
593         elementData->setClasses(WTFMove(classes));
594     }
595
596     if (node->isPseudoElement()) {
597         if (node->pseudoId() == PseudoId::Before)
598             elementData->setPseudoElement("before");
599         else if (node->pseudoId() == PseudoId::After)
600             elementData->setPseudoElement("after");
601     }
602
603     RenderElement* renderer = element.renderer();
604     if (!renderer)
605         return nullptr;
606
607     Frame* containingFrame = node->document().frame();
608     FrameView* containingView = containingFrame->view();
609     IntRect boundingBox = snappedIntRect(containingView->contentsToRootView(renderer->absoluteBoundingBoxRect()));
610     RenderBoxModelObject* modelObject = is<RenderBoxModelObject>(*renderer) ? downcast<RenderBoxModelObject>(renderer) : nullptr;
611     auto sizeObject = Inspector::Protocol::OverlayTypes::Size::create()
612         .setWidth(modelObject ? adjustForAbsoluteZoom(roundToInt(modelObject->offsetWidth()), *modelObject) : boundingBox.width())
613         .setHeight(modelObject ? adjustForAbsoluteZoom(roundToInt(modelObject->offsetHeight()), *modelObject) : boundingBox.height())
614         .release();
615     elementData->setSize(WTFMove(sizeObject));
616
617     if (is<RenderBox>(*renderer)) {
618         auto& renderBox = downcast<RenderBox>(*renderer);
619         if (RefPtr<Inspector::Protocol::OverlayTypes::ShapeOutsideData> shapeObject = buildObjectForShapeOutside(containingFrame, &renderBox))
620             elementData->setShapeOutsideData(WTFMove(shapeObject));
621     }
622
623     // Need to enable AX to get the computed role.
624     if (!WebCore::AXObjectCache::accessibilityEnabled())
625         WebCore::AXObjectCache::enableAccessibility();
626
627     if (AXObjectCache* axObjectCache = node->document().axObjectCache()) {
628         if (AccessibilityObject* axObject = axObjectCache->getOrCreate(node))
629             elementData->setRole(axObject->computedRoleString());
630     }
631
632     return WTFMove(elementData);
633 }
634
635 RefPtr<Inspector::Protocol::OverlayTypes::NodeHighlightData> InspectorOverlay::buildHighlightObjectForNode(Node* node, HighlightType type) const
636 {
637     if (!node)
638         return nullptr;
639
640     RenderObject* renderer = node->renderer();
641     if (!renderer)
642         return nullptr;
643
644     RefPtr<JSON::ArrayOf<Inspector::Protocol::OverlayTypes::FragmentHighlightData>> arrayOfFragmentHighlights = buildArrayForRendererFragments(renderer, m_nodeHighlightConfig);
645     if (!arrayOfFragmentHighlights)
646         return nullptr;
647
648     // The main view's scroll offset is shared across all quads.
649     FrameView* mainView = m_page.mainFrame().view();
650
651     auto nodeHighlightObject = Inspector::Protocol::OverlayTypes::NodeHighlightData::create()
652         .setScrollOffset(buildObjectForPoint(!mainView->delegatesScrolling() ? mainView->visibleContentRect().location() : FloatPoint()))
653         .setFragments(WTFMove(arrayOfFragmentHighlights))
654         .release();
655
656     if (m_nodeHighlightConfig.showInfo) {
657         if (RefPtr<Inspector::Protocol::OverlayTypes::ElementData> elementData = buildObjectForElementData(node, type))
658             nodeHighlightObject->setElementData(WTFMove(elementData));
659     }
660
661     return WTFMove(nodeHighlightObject);
662 }
663
664 Ref<JSON::ArrayOf<Inspector::Protocol::OverlayTypes::NodeHighlightData>> InspectorOverlay::buildObjectForHighlightedNodes() const
665 {
666     auto highlights = JSON::ArrayOf<Inspector::Protocol::OverlayTypes::NodeHighlightData>::create();
667
668     if (m_highlightNode) {
669         if (RefPtr<Inspector::Protocol::OverlayTypes::NodeHighlightData> nodeHighlightData = buildHighlightObjectForNode(m_highlightNode.get(), HighlightType::Node))
670             highlights->addItem(WTFMove(nodeHighlightData));
671     } else if (m_highlightNodeList) {
672         for (unsigned i = 0; i < m_highlightNodeList->length(); ++i) {
673             if (RefPtr<Inspector::Protocol::OverlayTypes::NodeHighlightData> nodeHighlightData = buildHighlightObjectForNode(m_highlightNodeList->item(i), HighlightType::NodeList))
674                 highlights->addItem(WTFMove(nodeHighlightData));
675         }
676     }
677
678     return highlights;
679 }
680
681 void InspectorOverlay::drawNodeHighlight()
682 {
683     if (m_highlightNode || m_highlightNodeList)
684         evaluateInOverlay("drawNodeHighlight", buildObjectForHighlightedNodes());
685 }
686
687 void InspectorOverlay::drawQuadHighlight()
688 {
689     if (!m_highlightQuad)
690         return;
691
692     Highlight highlight;
693     buildQuadHighlight(*m_highlightQuad, m_quadHighlightConfig, highlight);
694     evaluateInOverlay("drawQuadHighlight", buildObjectForHighlight(highlight));
695 }
696
697 void InspectorOverlay::drawPausedInDebuggerMessage()
698 {
699     if (!m_pausedInDebuggerMessage.isNull())
700         evaluateInOverlay("drawPausedInDebuggerMessage", m_pausedInDebuggerMessage);
701 }
702
703 Page* InspectorOverlay::overlayPage()
704 {
705     if (m_overlayPage)
706         return m_overlayPage.get();
707
708     auto pageConfiguration = pageConfigurationWithEmptyClients();
709     m_overlayPage = std::make_unique<Page>(WTFMove(pageConfiguration));
710     m_overlayPage->setDeviceScaleFactor(m_page.deviceScaleFactor());
711
712     Settings& settings = m_page.settings();
713     Settings& overlaySettings = m_overlayPage->settings();
714
715     overlaySettings.setStandardFontFamily(settings.standardFontFamily());
716     overlaySettings.setSerifFontFamily(settings.serifFontFamily());
717     overlaySettings.setSansSerifFontFamily(settings.sansSerifFontFamily());
718     overlaySettings.setCursiveFontFamily(settings.cursiveFontFamily());
719     overlaySettings.setFantasyFontFamily(settings.fantasyFontFamily());
720     overlaySettings.setPictographFontFamily(settings.pictographFontFamily());
721     overlaySettings.setMinimumFontSize(settings.minimumFontSize());
722     overlaySettings.setMinimumLogicalFontSize(settings.minimumLogicalFontSize());
723     overlaySettings.setMediaEnabled(false);
724     overlaySettings.setScriptEnabled(true);
725     overlaySettings.setPluginsEnabled(false);
726
727     Frame& frame = m_overlayPage->mainFrame();
728     frame.setView(FrameView::create(frame));
729     frame.init();
730     FrameLoader& loader = frame.loader();
731     frame.view()->setCanHaveScrollbars(false);
732     frame.view()->setTransparent(true);
733     ASSERT(loader.activeDocumentLoader());
734     auto& writer = loader.activeDocumentLoader()->writer();
735     writer.setMIMEType("text/html");
736     writer.begin();
737     writer.insertDataSynchronously(String(reinterpret_cast<const char*>(InspectorOverlayPage_html), sizeof(InspectorOverlayPage_html)));
738     writer.end();
739
740 #if OS(WINDOWS)
741     evaluateInOverlay("setPlatform", "windows");
742 #elif OS(MAC_OS_X)
743     evaluateInOverlay("setPlatform", "mac");
744 #elif OS(UNIX)
745     evaluateInOverlay("setPlatform", "linux");
746 #endif
747
748     return m_overlayPage.get();
749 }
750
751 void InspectorOverlay::forcePaint()
752 {
753     // This overlay page is very weird and doesn't automatically paint. We have to force paints manually.
754     m_client->highlight();
755 }
756
757 void InspectorOverlay::reset(const IntSize& viewportSize, const IntPoint& scrollOffset)
758 {
759     auto configObject = Inspector::Protocol::OverlayTypes::OverlayConfiguration::create()
760         .setDeviceScaleFactor(m_page.deviceScaleFactor())
761         .setViewportSize(buildObjectForSize(viewportSize))
762         .setPageScaleFactor(m_page.pageScaleFactor())
763         .setPageZoomFactor(m_page.mainFrame().pageZoomFactor())
764         .setScrollOffset(buildObjectForPoint(scrollOffset))
765         .setContentInset(buildObjectForSize(IntSize(0, m_page.mainFrame().view()->topContentInset(ScrollView::TopContentInsetType::WebCoreOrPlatformContentInset))))
766         .setShowRulers(m_showRulers)
767         .release();
768     evaluateInOverlay("reset", WTFMove(configObject));
769 }
770
771 static void evaluateCommandInOverlay(Page* page, Ref<JSON::Array>&& command)
772 {
773     page->mainFrame().script().evaluate(ScriptSourceCode(makeString("dispatch(", command->toJSONString(), ')')));
774 }
775
776 void InspectorOverlay::evaluateInOverlay(const String& method)
777 {
778     Ref<JSON::Array> command = JSON::Array::create();
779     command->pushString(method);
780
781     evaluateCommandInOverlay(overlayPage(), WTFMove(command));
782 }
783
784 void InspectorOverlay::evaluateInOverlay(const String& method, const String& argument)
785 {
786     Ref<JSON::Array> command = JSON::Array::create();
787     command->pushString(method);
788     command->pushString(argument);
789
790     evaluateCommandInOverlay(overlayPage(), WTFMove(command));
791 }
792
793 void InspectorOverlay::evaluateInOverlay(const String& method, RefPtr<JSON::Value>&& argument)
794 {
795     Ref<JSON::Array> command = JSON::Array::create();
796     command->pushString(method);
797     command->pushValue(WTFMove(argument));
798
799     evaluateCommandInOverlay(overlayPage(), WTFMove(command));
800 }
801
802 void InspectorOverlay::freePage()
803 {
804     m_overlayPage = nullptr;
805 }
806
807 } // namespace WebCore