RenderElement::style() should return a reference.
[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 Computer, 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
31 #if ENABLE(INSPECTOR)
32
33 #include "InspectorOverlay.h"
34
35 #include "DocumentLoader.h"
36 #include "Element.h"
37 #include "EmptyClients.h"
38 #include "FrameView.h"
39 #include "GraphicsContext.h"
40 #include "InspectorClient.h"
41 #include "InspectorOverlayPage.h"
42 #include "InspectorValues.h"
43 #include "MainFrame.h"
44 #include "Node.h"
45 #include "Page.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 "ScriptValue.h"
57 #include "Settings.h"
58 #include "StyledElement.h"
59 #include <wtf/text/StringBuilder.h>
60
61 namespace WebCore {
62
63 namespace {
64
65 Path quadToPath(const FloatQuad& quad)
66 {
67     Path quadPath;
68     quadPath.moveTo(quad.p1());
69     quadPath.addLineTo(quad.p2());
70     quadPath.addLineTo(quad.p3());
71     quadPath.addLineTo(quad.p4());
72     quadPath.closeSubpath();
73     return quadPath;
74 }
75
76 void drawOutlinedQuad(GraphicsContext* context, const FloatQuad& quad, const Color& fillColor, const Color& outlineColor)
77 {
78     static const int outlineThickness = 2;
79
80     Path quadPath = quadToPath(quad);
81
82     // Clip out the quad, then draw with a 2px stroke to get a pixel
83     // of outline (because inflating a quad is hard)
84     {
85         context->save();
86         context->clipOut(quadPath);
87
88         context->setStrokeThickness(outlineThickness);
89         context->setStrokeColor(outlineColor, ColorSpaceDeviceRGB);
90         context->strokePath(quadPath);
91
92         context->restore();
93     }
94
95     // Now do the fill
96     context->setFillColor(fillColor, ColorSpaceDeviceRGB);
97     context->fillPath(quadPath);
98 }
99
100 static void contentsQuadToPage(const FrameView* mainView, const FrameView* view, FloatQuad& quad)
101 {
102     quad.setP1(view->contentsToRootView(roundedIntPoint(quad.p1())));
103     quad.setP2(view->contentsToRootView(roundedIntPoint(quad.p2())));
104     quad.setP3(view->contentsToRootView(roundedIntPoint(quad.p3())));
105     quad.setP4(view->contentsToRootView(roundedIntPoint(quad.p4())));
106     quad += mainView->scrollOffset();
107 }
108
109 static void buildRendererHighlight(RenderObject* renderer, RenderRegion* region, const HighlightConfig& highlightConfig, Highlight* highlight)
110 {
111     Frame* containingFrame = renderer->document().frame();
112     if (!containingFrame)
113         return;
114
115     highlight->setDataFromConfig(highlightConfig);
116     FrameView* containingView = containingFrame->view();
117     FrameView* mainView = containingFrame->page()->mainFrame().view();
118
119     // RenderSVGRoot should be highlighted through the isBox() code path, all other SVG elements should just dump their absoluteQuads().
120 #if ENABLE(SVG)
121     bool isSVGRenderer = renderer->node() && renderer->node()->isSVGElement() && !renderer->isSVGRoot();
122 #else
123     bool isSVGRenderer = false;
124 #endif
125
126     if (isSVGRenderer) {
127         highlight->type = HighlightTypeRects;
128         renderer->absoluteQuads(highlight->quads);
129         for (size_t i = 0; i < highlight->quads.size(); ++i)
130             contentsQuadToPage(mainView, containingView, highlight->quads[i]);
131     } else if (renderer->isBox() || renderer->isRenderInline()) {
132         LayoutRect contentBox;
133         LayoutRect paddingBox;
134         LayoutRect borderBox;
135         LayoutRect marginBox;
136
137         if (renderer->isBox()) {
138             RenderBox* renderBox = toRenderBox(renderer);
139
140             LayoutBoxExtent margins(renderBox->marginTop(), renderBox->marginRight(), renderBox->marginBottom(), renderBox->marginLeft());
141
142             if (!renderBox->isOutOfFlowPositioned() && region) {
143                 RenderBox::LogicalExtentComputedValues computedValues;
144                 renderBox->computeLogicalWidthInRegion(computedValues, region);
145                 margins.mutableLogicalLeft(renderBox->style().writingMode()) = computedValues.m_margins.m_start;
146                 margins.mutableLogicalRight(renderBox->style().writingMode()) = computedValues.m_margins.m_end;
147             }
148
149             paddingBox = renderBox->clientBoxRectInRegion(region);
150             contentBox = LayoutRect(paddingBox.x() + renderBox->paddingLeft(), paddingBox.y() + renderBox->paddingTop(),
151                 paddingBox.width() - renderBox->paddingLeft() - renderBox->paddingRight(), paddingBox.height() - renderBox->paddingTop() - renderBox->paddingBottom());
152             borderBox = LayoutRect(paddingBox.x() - renderBox->borderLeft(), paddingBox.y() - renderBox->borderTop(),
153                 paddingBox.width() + renderBox->borderLeft() + renderBox->borderRight(), paddingBox.height() + renderBox->borderTop() + renderBox->borderBottom());
154             marginBox = LayoutRect(borderBox.x() - margins.left(), borderBox.y() - margins.top(),
155                 borderBox.width() + margins.left() + margins.right(), borderBox.height() + margins.top() + margins.bottom());
156         } else {
157             RenderInline* renderInline = toRenderInline(renderer);
158
159             // RenderInline's bounding box includes paddings and borders, excludes margins.
160             borderBox = renderInline->linesBoundingBox();
161             paddingBox = LayoutRect(borderBox.x() + renderInline->borderLeft(), borderBox.y() + renderInline->borderTop(),
162                 borderBox.width() - renderInline->borderLeft() - renderInline->borderRight(), borderBox.height() - renderInline->borderTop() - renderInline->borderBottom());
163             contentBox = LayoutRect(paddingBox.x() + renderInline->paddingLeft(), paddingBox.y() + renderInline->paddingTop(),
164                 paddingBox.width() - renderInline->paddingLeft() - renderInline->paddingRight(), paddingBox.height() - renderInline->paddingTop() - renderInline->paddingBottom());
165             // Ignore marginTop and marginBottom for inlines.
166             marginBox = LayoutRect(borderBox.x() - renderInline->marginLeft(), borderBox.y(),
167                 borderBox.width() + renderInline->marginWidth(), borderBox.height());
168         }
169
170         FloatQuad absContentQuad;
171         FloatQuad absPaddingQuad;
172         FloatQuad absBorderQuad;
173         FloatQuad absMarginQuad;
174
175         if (region) {
176             RenderFlowThread* flowThread = region->flowThread();
177
178             // Figure out the quads in the space of the RenderFlowThread.
179             absContentQuad = renderer->localToContainerQuad(FloatRect(contentBox), flowThread);
180             absPaddingQuad = renderer->localToContainerQuad(FloatRect(paddingBox), flowThread);
181             absBorderQuad = renderer->localToContainerQuad(FloatRect(borderBox), flowThread);
182             absMarginQuad = renderer->localToContainerQuad(FloatRect(marginBox), flowThread);
183
184             // Move the quad relative to the space of the current region.
185             LayoutRect flippedRegionRect(region->flowThreadPortionRect());
186             flowThread->flipForWritingMode(flippedRegionRect);
187
188             FloatSize delta = region->contentBoxRect().location() - flippedRegionRect.location();
189             absContentQuad.move(delta);
190             absPaddingQuad.move(delta);
191             absBorderQuad.move(delta);
192             absMarginQuad.move(delta);
193
194             // Resolve the absolute quads starting from the current region.
195             absContentQuad = region->localToAbsoluteQuad(absContentQuad);
196             absPaddingQuad = region->localToAbsoluteQuad(absPaddingQuad);
197             absBorderQuad = region->localToAbsoluteQuad(absBorderQuad);
198             absMarginQuad = region->localToAbsoluteQuad(absMarginQuad);
199         } else {
200             absContentQuad = renderer->localToAbsoluteQuad(FloatRect(contentBox));
201             absPaddingQuad = renderer->localToAbsoluteQuad(FloatRect(paddingBox));
202             absBorderQuad = renderer->localToAbsoluteQuad(FloatRect(borderBox));
203             absMarginQuad = renderer->localToAbsoluteQuad(FloatRect(marginBox));
204         }
205
206         contentsQuadToPage(mainView, containingView, absContentQuad);
207         contentsQuadToPage(mainView, containingView, absPaddingQuad);
208         contentsQuadToPage(mainView, containingView, absBorderQuad);
209         contentsQuadToPage(mainView, containingView, absMarginQuad);
210
211         highlight->type = HighlightTypeNode;
212         highlight->quads.append(absMarginQuad);
213         highlight->quads.append(absBorderQuad);
214         highlight->quads.append(absPaddingQuad);
215         highlight->quads.append(absContentQuad);
216     }
217 }
218
219 static void buildNodeHighlight(Node* node, RenderRegion* region, const HighlightConfig& highlightConfig, Highlight* highlight)
220 {
221     RenderObject* renderer = node->renderer();
222     if (!renderer)
223         return;
224     buildRendererHighlight(renderer, region, highlightConfig, highlight);
225 }
226
227 static void buildQuadHighlight(Page* page, const FloatQuad& quad, const HighlightConfig& highlightConfig, Highlight *highlight)
228 {
229     if (!page)
230         return;
231     highlight->setDataFromConfig(highlightConfig);
232     highlight->type = HighlightTypeRects;
233     highlight->quads.append(quad);
234 }
235
236 } // anonymous namespace
237
238 InspectorOverlay::InspectorOverlay(Page* page, InspectorClient* client)
239     : m_page(page)
240     , m_client(client)
241 {
242 }
243
244 InspectorOverlay::~InspectorOverlay()
245 {
246 }
247
248 void InspectorOverlay::paint(GraphicsContext& context)
249 {
250     if (m_pausedInDebuggerMessage.isNull() && !m_highlightNode && !m_highlightQuad && m_size.isEmpty())
251         return;
252     GraphicsContextStateSaver stateSaver(context);
253     FrameView* view = overlayPage()->mainFrame().view();
254     view->updateLayoutAndStyleIfNeededRecursive();
255     view->paint(&context, IntRect(0, 0, view->width(), view->height()));
256 }
257
258 void InspectorOverlay::drawOutline(GraphicsContext* context, const LayoutRect& rect, const Color& color)
259 {
260     FloatRect outlineRect = rect;
261     drawOutlinedQuad(context, outlineRect, Color(), color);
262 }
263
264 void InspectorOverlay::getHighlight(Highlight* highlight) const
265 {
266     if (!m_highlightNode && !m_highlightQuad)
267         return;
268
269     highlight->type = HighlightTypeRects;
270     if (m_highlightNode)
271         buildNodeHighlight(m_highlightNode.get(), nullptr, m_nodeHighlightConfig, highlight);
272     else
273         buildQuadHighlight(m_page, *m_highlightQuad, m_quadHighlightConfig, highlight);
274 }
275
276 void InspectorOverlay::resize(const IntSize& size)
277 {
278     m_size = size;
279     update();
280 }
281
282 void InspectorOverlay::setPausedInDebuggerMessage(const String* message)
283 {
284     m_pausedInDebuggerMessage = message ? *message : String();
285     update();
286 }
287
288 void InspectorOverlay::hideHighlight()
289 {
290     m_highlightNode.clear();
291     m_highlightQuad.clear();
292     update();
293 }
294
295 void InspectorOverlay::highlightNode(Node* node, const HighlightConfig& highlightConfig)
296 {
297     m_nodeHighlightConfig = highlightConfig;
298     m_highlightNode = node;
299     update();
300 }
301
302 void InspectorOverlay::highlightQuad(PassOwnPtr<FloatQuad> quad, const HighlightConfig& highlightConfig)
303 {
304     if (m_quadHighlightConfig.usePageCoordinates)
305         *quad -= m_page->mainFrame().view()->scrollOffset();
306
307     m_quadHighlightConfig = highlightConfig;
308     m_highlightQuad = quad;
309     update();
310 }
311
312 Node* InspectorOverlay::highlightedNode() const
313 {
314     return m_highlightNode.get();
315 }
316
317 void InspectorOverlay::didSetSearchingForNode(bool enabled)
318 {
319     m_client->didSetSearchingForNode(enabled);
320 }
321
322 void InspectorOverlay::update()
323 {
324     if (!m_highlightNode && !m_highlightQuad && m_pausedInDebuggerMessage.isNull() && m_size.isEmpty()) {
325         m_client->hideHighlight();
326         return;
327     }
328
329     FrameView* view = m_page->mainFrame().view();
330     if (!view)
331         return;
332
333     FrameView* overlayView = overlayPage()->mainFrame().view();
334     IntSize viewportSize = view->visibleContentRect().size();
335     IntSize frameViewFullSize = view->visibleContentRect(ScrollableArea::IncludeScrollbars).size();
336     IntSize size = m_size.isEmpty() ? frameViewFullSize : m_size;
337     overlayPage()->setPageScaleFactor(m_page->pageScaleFactor(), IntPoint());
338     size.scale(m_page->pageScaleFactor());
339     overlayView->resize(size);
340
341     // Clear canvas and paint things.
342     reset(viewportSize, m_size.isEmpty() ? IntSize() : frameViewFullSize);
343
344     // Include scrollbars to avoid masking them by the gutter.
345     drawGutter();
346     drawNodeHighlight();
347     drawQuadHighlight();
348     drawPausedInDebuggerMessage();
349
350     // Position DOM elements.
351     overlayPage()->mainFrame().document()->recalcStyle(Style::Force);
352     if (overlayView->needsLayout())
353         overlayView->layout();
354
355     // Kick paint.
356     m_client->highlight();
357 }
358
359 static PassRefPtr<InspectorObject> buildObjectForPoint(const FloatPoint& point)
360 {
361     RefPtr<InspectorObject> object = InspectorObject::create();
362     object->setNumber("x", point.x());
363     object->setNumber("y", point.y());
364     return object.release();
365 }
366
367 static PassRefPtr<InspectorArray> buildArrayForQuad(const FloatQuad& quad)
368 {
369     RefPtr<InspectorArray> array = InspectorArray::create();
370     array->pushObject(buildObjectForPoint(quad.p1()));
371     array->pushObject(buildObjectForPoint(quad.p2()));
372     array->pushObject(buildObjectForPoint(quad.p3()));
373     array->pushObject(buildObjectForPoint(quad.p4()));
374     return array.release();
375 }
376
377 static PassRefPtr<InspectorObject> buildObjectForHighlight(const Highlight& highlight)
378 {
379     RefPtr<InspectorObject> object = InspectorObject::create();
380     RefPtr<InspectorArray> array = InspectorArray::create();
381     for (size_t i = 0; i < highlight.quads.size(); ++i)
382         array->pushArray(buildArrayForQuad(highlight.quads[i]));
383     object->setArray("quads", array.release());
384     object->setBoolean("showRulers", highlight.showRulers);
385     object->setString("contentColor", highlight.contentColor.serialized());
386     object->setString("contentOutlineColor", highlight.contentOutlineColor.serialized());
387     object->setString("paddingColor", highlight.paddingColor.serialized());
388     object->setString("borderColor", highlight.borderColor.serialized());
389     object->setString("marginColor", highlight.marginColor.serialized());
390     return object.release();
391 }
392
393 static PassRefPtr<InspectorObject> buildObjectForRegionHighlight(FrameView* mainView, RenderRegion* region)
394 {
395     FrameView* containingView = region->frame().view();
396     if (!containingView)
397         return nullptr;
398
399     RenderBlockFlow* regionContainer = toRenderBlockFlow(region->parent());
400     LayoutRect borderBox = regionContainer->borderBoxRect();
401     borderBox.setWidth(borderBox.width() + regionContainer->verticalScrollbarWidth());
402     borderBox.setHeight(borderBox.height() + regionContainer->horizontalScrollbarHeight());
403
404     // Create incoming and outgoing boxes that we use to chain the regions toghether.
405     const LayoutSize linkBoxSize(10, 10);
406     const LayoutSize linkBoxMidpoint(linkBoxSize.width() / 2, linkBoxSize.height() / 2);
407     
408     LayoutRect incomingRectBox = LayoutRect(borderBox.location() - linkBoxMidpoint, linkBoxSize);
409     LayoutRect outgoingRectBox = LayoutRect(borderBox.location() - linkBoxMidpoint + borderBox.size(), linkBoxSize);
410
411     // Move the link boxes slightly inside the region border box.
412     LayoutUnit maxUsableHeight = std::max(LayoutUnit(), borderBox.height() - linkBoxMidpoint.height());
413     LayoutUnit linkBoxVerticalOffset = std::min(LayoutUnit(15), maxUsableHeight);
414     incomingRectBox.move(0, linkBoxVerticalOffset);
415     outgoingRectBox.move(0, -linkBoxVerticalOffset);
416
417     FloatQuad borderRectQuad = regionContainer->localToAbsoluteQuad(FloatRect(borderBox));
418     FloatQuad incomingRectQuad = regionContainer->localToAbsoluteQuad(FloatRect(incomingRectBox));
419     FloatQuad outgoingRectQuad = regionContainer->localToAbsoluteQuad(FloatRect(outgoingRectBox));
420
421     contentsQuadToPage(mainView, containingView, borderRectQuad);
422     contentsQuadToPage(mainView, containingView, incomingRectQuad);
423     contentsQuadToPage(mainView, containingView, outgoingRectQuad);
424
425     RefPtr<InspectorObject> regionObject = InspectorObject::create();
426
427     regionObject->setArray("borderQuad", buildArrayForQuad(borderRectQuad));
428     regionObject->setArray("incomingQuad", buildArrayForQuad(incomingRectQuad));
429     regionObject->setArray("outgoingQuad", buildArrayForQuad(outgoingRectQuad));
430
431     return regionObject.release();
432 }
433
434 static PassRefPtr<InspectorArray> buildObjectForCSSRegionsHighlight(RenderRegion* region, RenderFlowThread* flowThread)
435 {
436     FrameView* mainFrameView = region->document().page()->mainFrame().view();
437
438     RefPtr<InspectorArray> array = InspectorArray::create();
439
440     const RenderRegionList& regionList = flowThread->renderRegionList();
441     for (RenderRegionList::const_iterator iter = regionList.begin(); iter != regionList.end(); ++iter) {
442         RenderRegion* iterRegion = *iter;
443         if (!iterRegion->isValid())
444             continue;
445         RefPtr<InspectorObject> regionHighlightObject = buildObjectForRegionHighlight(mainFrameView, iterRegion);
446         if (!regionHighlightObject)
447             continue;
448         if (region == iterRegion) {
449             // Let the script know that this is the currently highlighted node.
450             regionHighlightObject->setBoolean("isHighlighted", true);
451         }
452         array->pushObject(regionHighlightObject.release());
453     }
454
455     return array.release();
456 }
457
458 static PassRefPtr<InspectorObject> buildObjectForSize(const IntSize& size)
459 {
460     RefPtr<InspectorObject> result = InspectorObject::create();
461     result->setNumber("width", size.width());
462     result->setNumber("height", size.height());
463     return result.release();
464 }
465
466 static PassRefPtr<InspectorObject> buildObjectForCSSRegionContentClip(RenderRegion* region)
467 {
468     Frame* containingFrame = region->document().frame();
469     if (!containingFrame)
470         return nullptr;
471
472     FrameView* containingView = containingFrame->view();
473     FrameView* mainView = containingFrame->page()->mainFrame().view();
474     RenderFlowThread* flowThread = region->flowThread();
475
476     // Get the clip box of the current region and covert it into an absolute quad.
477     LayoutRect flippedRegionRect(region->flowThreadPortionOverflowRect());
478     flowThread->flipForWritingMode(flippedRegionRect);
479
480     // Apply any border or padding of the region.
481     flippedRegionRect.setLocation(region->contentBoxRect().location());
482     
483     FloatQuad clipQuad = region->localToAbsoluteQuad(FloatRect(flippedRegionRect));
484     contentsQuadToPage(mainView, containingView, clipQuad);
485
486     RefPtr<InspectorObject> regionObject = InspectorObject::create();
487     regionObject->setArray("quad", buildArrayForQuad(clipQuad));
488     return regionObject.release();
489 }
490
491 void InspectorOverlay::drawGutter()
492 {
493     evaluateInOverlay("drawGutter", "");
494 }
495
496 static PassRefPtr<InspectorArray> buildObjectForRendererFragments(RenderObject* renderer, const HighlightConfig& config)
497 {
498     RefPtr<InspectorArray> fragmentsArray = InspectorArray::create();
499
500     RenderFlowThread* containingFlowThread = renderer->flowThreadContainingBlock();
501     if (!containingFlowThread) {
502         Highlight highlight;
503         buildRendererHighlight(renderer, nullptr, config, &highlight);
504         fragmentsArray->pushObject(buildObjectForHighlight(highlight));
505     } else {
506         RenderBox* enclosingBox = renderer->enclosingBox();
507         RenderRegion* startRegion = nullptr;
508         RenderRegion* endRegion = nullptr;
509         containingFlowThread->getRegionRangeForBox(enclosingBox, startRegion, endRegion);
510         if (!startRegion) {
511             // The flow has no visible regions. The renderer is not visible on screen.
512             return nullptr;
513         }
514         const RenderRegionList& regionList = containingFlowThread->renderRegionList();
515         for (RenderRegionList::const_iterator iter = regionList.find(startRegion); iter != regionList.end(); ++iter) {
516             RenderRegion* region = *iter;
517             if (region->isValid()) {
518                 // Compute the highlight of the fragment inside the current region.
519                 Highlight highlight;
520                 buildRendererHighlight(renderer, region, config, &highlight);
521                 RefPtr<InspectorObject> fragmentObject = buildObjectForHighlight(highlight);
522
523                 // Compute the clipping area of the region.
524                 fragmentObject->setObject("region", buildObjectForCSSRegionContentClip(region));
525                 fragmentsArray->pushObject(fragmentObject.release());
526             }
527             if (region == endRegion)
528                 break;
529         }
530     }
531
532     return fragmentsArray.release();
533 }
534
535 static PassRefPtr<InspectorObject> buildObjectForElementInfo(Node* node)
536 {
537     if (!node->isElementNode() || !node->document().frame())
538         return nullptr;
539
540     RefPtr<InspectorObject> elementInfo = InspectorObject::create();
541
542     Element* element = toElement(node);
543     bool isXHTML = element->document().isXHTMLDocument();
544     elementInfo->setString("tagName", isXHTML ? element->nodeName() : element->nodeName().lower());
545     elementInfo->setString("idValue", element->getIdAttribute());
546     HashSet<AtomicString> usedClassNames;
547     if (element->hasClass() && element->isStyledElement()) {
548         StringBuilder classNames;
549         const SpaceSplitString& classNamesString = static_cast<StyledElement*>(element)->classNames();
550         size_t classNameCount = classNamesString.size();
551         for (size_t i = 0; i < classNameCount; ++i) {
552             const AtomicString& className = classNamesString[i];
553             if (usedClassNames.contains(className))
554                 continue;
555             usedClassNames.add(className);
556             classNames.append('.');
557             classNames.append(className);
558         }
559         elementInfo->setString("className", classNames.toString());
560     }
561
562     RenderElement* renderer = element->renderer();
563     Frame* containingFrame = node->document().frame();
564     FrameView* containingView = containingFrame->view();
565     IntRect boundingBox = pixelSnappedIntRect(containingView->contentsToRootView(renderer->absoluteBoundingBoxRect()));
566     RenderBoxModelObject* modelObject = renderer->isBoxModelObject() ? toRenderBoxModelObject(renderer) : 0;
567     elementInfo->setString("nodeWidth", String::number(modelObject ? adjustForAbsoluteZoom(modelObject->pixelSnappedOffsetWidth(), modelObject) : boundingBox.width()));
568     elementInfo->setString("nodeHeight", String::number(modelObject ? adjustForAbsoluteZoom(modelObject->pixelSnappedOffsetHeight(), modelObject) : boundingBox.height()));
569     
570     if (renderer->isRenderNamedFlowFragmentContainer()) {
571         RenderNamedFlowFragment* region = toRenderBlockFlow(renderer)->renderNamedFlowFragment();
572         RenderFlowThread* flowThread = region->flowThread();
573         if (flowThread && flowThread->isRenderNamedFlowThread()) {
574             RefPtr<InspectorObject> regionFlowInfo = InspectorObject::create();
575             regionFlowInfo->setString("name", toRenderNamedFlowThread(flowThread)->flowThreadName());
576             regionFlowInfo->setArray("regions", buildObjectForCSSRegionsHighlight(region, flowThread));
577             elementInfo->setObject("regionFlowInfo", regionFlowInfo.release());
578         }
579     }
580
581     RenderFlowThread* containingFlowThread = renderer->flowThreadContainingBlock();
582     if (containingFlowThread && containingFlowThread->isRenderNamedFlowThread()) {
583         RefPtr<InspectorObject> contentFlowInfo = InspectorObject::create();
584         contentFlowInfo->setString("name", toRenderNamedFlowThread(containingFlowThread)->flowThreadName());
585         elementInfo->setObject("contentFlowInfo", contentFlowInfo.release());
586     }
587
588     return elementInfo.release();
589 }
590
591 PassRefPtr<InspectorObject> InspectorOverlay::buildObjectForHighlightedNode() const
592 {
593     if (!m_highlightNode)
594         return nullptr;
595
596     Node* node = m_highlightNode.get();
597     RenderObject* renderer = node->renderer();
598     if (!renderer)
599         return nullptr;
600
601     RefPtr<InspectorArray> highlightFragments = buildObjectForRendererFragments(renderer, m_nodeHighlightConfig);
602     if (!highlightFragments)
603         return nullptr;
604
605     RefPtr<InspectorObject> highlightObject = InspectorObject::create();
606
607     // The main view's scroll offset is shared across all quads.
608     FrameView* mainView = m_page->mainFrame().view();
609     highlightObject->setObject("scroll", buildObjectForPoint(!mainView->delegatesScrolling() ? mainView->visibleContentRect().location() : FloatPoint()));
610
611     highlightObject->setArray("fragments", highlightFragments.release());
612
613     if (m_nodeHighlightConfig.showInfo) {
614         RefPtr<InspectorObject> elementInfo = buildObjectForElementInfo(node);
615         if (elementInfo)
616             highlightObject->setObject("elementInfo", elementInfo.release());
617     }
618         
619     return highlightObject.release();
620 }
621
622 void InspectorOverlay::drawNodeHighlight()
623 {
624     RefPtr<InspectorObject> highlightObject = buildObjectForHighlightedNode();
625     if (!highlightObject)
626         return;
627     evaluateInOverlay("drawNodeHighlight", highlightObject);
628 }
629
630 void InspectorOverlay::drawQuadHighlight()
631 {
632     if (!m_highlightQuad)
633         return;
634
635     Highlight highlight;
636     buildQuadHighlight(m_page, *m_highlightQuad, m_quadHighlightConfig, &highlight);
637     evaluateInOverlay("drawQuadHighlight", buildObjectForHighlight(highlight));
638 }
639
640 void InspectorOverlay::drawPausedInDebuggerMessage()
641 {
642     if (!m_pausedInDebuggerMessage.isNull())
643         evaluateInOverlay("drawPausedInDebuggerMessage", m_pausedInDebuggerMessage);
644 }
645
646 Page* InspectorOverlay::overlayPage()
647 {
648     if (m_overlayPage)
649         return m_overlayPage.get();
650
651     Page::PageClients pageClients;
652     fillWithEmptyClients(pageClients);
653     m_overlayPage = adoptPtr(new Page(pageClients));
654
655     Settings& settings = m_page->settings();
656     Settings& overlaySettings = m_overlayPage->settings();
657
658     overlaySettings.setStandardFontFamily(settings.standardFontFamily());
659     overlaySettings.setSerifFontFamily(settings.serifFontFamily());
660     overlaySettings.setSansSerifFontFamily(settings.sansSerifFontFamily());
661     overlaySettings.setCursiveFontFamily(settings.cursiveFontFamily());
662     overlaySettings.setFantasyFontFamily(settings.fantasyFontFamily());
663     overlaySettings.setPictographFontFamily(settings.pictographFontFamily());
664     overlaySettings.setMinimumFontSize(settings.minimumFontSize());
665     overlaySettings.setMinimumLogicalFontSize(settings.minimumLogicalFontSize());
666     overlaySettings.setMediaEnabled(false);
667     overlaySettings.setScriptEnabled(true);
668     overlaySettings.setPluginsEnabled(false);
669
670     Frame& frame = m_overlayPage->mainFrame();
671     frame.setView(FrameView::create(frame));
672     frame.init();
673     FrameLoader& loader = frame.loader();
674     frame.view()->setCanHaveScrollbars(false);
675     frame.view()->setTransparent(true);
676     ASSERT(loader.activeDocumentLoader());
677     loader.activeDocumentLoader()->writer().setMIMEType("text/html");
678     loader.activeDocumentLoader()->writer().begin();
679     loader.activeDocumentLoader()->writer().addData(reinterpret_cast<const char*>(InspectorOverlayPage_html), sizeof(InspectorOverlayPage_html));
680     loader.activeDocumentLoader()->writer().end();
681
682 #if OS(WINDOWS)
683     evaluateInOverlay("setPlatform", "windows");
684 #elif OS(MAC_OS_X)
685     evaluateInOverlay("setPlatform", "mac");
686 #elif OS(UNIX)
687     evaluateInOverlay("setPlatform", "linux");
688 #endif
689
690     return m_overlayPage.get();
691 }
692
693 void InspectorOverlay::reset(const IntSize& viewportSize, const IntSize& frameViewFullSize)
694 {
695     RefPtr<InspectorObject> resetData = InspectorObject::create();
696     resetData->setNumber("deviceScaleFactor", m_page->deviceScaleFactor());
697     resetData->setObject("viewportSize", buildObjectForSize(viewportSize));
698     resetData->setObject("frameViewFullSize", buildObjectForSize(frameViewFullSize));
699     evaluateInOverlay("reset", resetData.release());
700 }
701
702 void InspectorOverlay::evaluateInOverlay(const String& method, const String& argument)
703 {
704     RefPtr<InspectorArray> command = InspectorArray::create();
705     command->pushString(method);
706     command->pushString(argument);
707     overlayPage()->mainFrame().script().evaluate(ScriptSourceCode(makeString("dispatch(", command->toJSONString(), ")")));
708 }
709
710 void InspectorOverlay::evaluateInOverlay(const String& method, PassRefPtr<InspectorValue> argument)
711 {
712     RefPtr<InspectorArray> command = InspectorArray::create();
713     command->pushString(method);
714     command->pushValue(argument);
715     overlayPage()->mainFrame().script().evaluate(ScriptSourceCode(makeString("dispatch(", command->toJSONString(), ")")));
716 }
717
718 void InspectorOverlay::freePage()
719 {
720     m_overlayPage.clear();
721 }
722
723 } // namespace WebCore
724
725 #endif // ENABLE(INSPECTOR)