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