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#include "core/inspector/InspectorOverlay.h"
31
32#include "InspectorOverlayPage.h"
33#include "V8InspectorOverlayHost.h"
34#include "bindings/v8/ScriptController.h"
35#include "bindings/v8/ScriptSourceCode.h"
36#include "core/dom/Element.h"
37#include "core/dom/Node.h"
38#include "core/dom/PseudoElement.h"
39#include "core/inspector/InspectorClient.h"
40#include "core/inspector/InspectorOverlayHost.h"
41#include "core/loader/DocumentLoader.h"
42#include "core/loader/EmptyClients.h"
43#include "core/page/Chrome.h"
44#include "core/page/EventHandler.h"
45#include "core/frame/Frame.h"
46#include "core/frame/FrameView.h"
47#include "core/page/Page.h"
48#include "core/frame/Settings.h"
49#include "core/rendering/RenderBoxModelObject.h"
50#include "core/rendering/RenderInline.h"
51#include "core/rendering/RenderObject.h"
52#include "core/rendering/style/RenderStyleConstants.h"
53#include "platform/JSONValues.h"
54#include "platform/PlatformMouseEvent.h"
55#include "platform/graphics/GraphicsContextStateSaver.h"
56#include "wtf/text/StringBuilder.h"
57
58namespace WebCore {
59
60namespace {
61
62class InspectorOverlayChromeClient: public EmptyChromeClient {
63public:
64    InspectorOverlayChromeClient(ChromeClient& client, InspectorOverlay* overlay)
65        : m_client(client)
66        , m_overlay(overlay)
67    { }
68
69    virtual void setCursor(const Cursor& cursor)
70    {
71        m_client.setCursor(cursor);
72    }
73
74    virtual void setToolTip(const String& tooltip, TextDirection direction)
75    {
76        m_client.setToolTip(tooltip, direction);
77    }
78
79    virtual void invalidateRootView(const IntRect& rect)
80    {
81        m_overlay->invalidate();
82    }
83
84    virtual void invalidateContentsAndRootView(const IntRect& rect)
85    {
86        m_overlay->invalidate();
87    }
88
89    virtual void invalidateContentsForSlowScroll(const IntRect& rect)
90    {
91        m_overlay->invalidate();
92    }
93
94private:
95    ChromeClient& m_client;
96    InspectorOverlay* m_overlay;
97};
98
99Path quadToPath(const FloatQuad& quad)
100{
101    Path quadPath;
102    quadPath.moveTo(quad.p1());
103    quadPath.addLineTo(quad.p2());
104    quadPath.addLineTo(quad.p3());
105    quadPath.addLineTo(quad.p4());
106    quadPath.closeSubpath();
107    return quadPath;
108}
109
110void drawOutlinedQuad(GraphicsContext* context, const FloatQuad& quad, const Color& fillColor, const Color& outlineColor)
111{
112    static const int outlineThickness = 2;
113
114    Path quadPath = quadToPath(quad);
115
116    // Clip out the quad, then draw with a 2px stroke to get a pixel
117    // of outline (because inflating a quad is hard)
118    {
119        context->save();
120        context->clipOut(quadPath);
121
122        context->setStrokeThickness(outlineThickness);
123        context->setStrokeColor(outlineColor);
124        context->strokePath(quadPath);
125
126        context->restore();
127    }
128
129    // Now do the fill
130    context->setFillColor(fillColor);
131    context->fillPath(quadPath);
132}
133
134static void contentsQuadToPage(const FrameView* mainView, const FrameView* view, FloatQuad& quad)
135{
136    quad.setP1(view->contentsToRootView(roundedIntPoint(quad.p1())));
137    quad.setP2(view->contentsToRootView(roundedIntPoint(quad.p2())));
138    quad.setP3(view->contentsToRootView(roundedIntPoint(quad.p3())));
139    quad.setP4(view->contentsToRootView(roundedIntPoint(quad.p4())));
140    quad += mainView->scrollOffset();
141}
142
143static bool buildNodeQuads(Node* node, Vector<FloatQuad>& quads)
144{
145    RenderObject* renderer = node->renderer();
146    Frame* containingFrame = node->document().frame();
147
148    if (!renderer || !containingFrame)
149        return false;
150
151    FrameView* containingView = containingFrame->view();
152    FrameView* mainView = containingFrame->page()->mainFrame()->view();
153    IntRect boundingBox = pixelSnappedIntRect(containingView->contentsToRootView(renderer->absoluteBoundingBoxRect()));
154    boundingBox.move(mainView->scrollOffset());
155
156    // RenderSVGRoot should be highlighted through the isBox() code path, all other SVG elements should just dump their absoluteQuads().
157    if (renderer->node() && renderer->node()->isSVGElement() && !renderer->isSVGRoot()) {
158        renderer->absoluteQuads(quads);
159        for (size_t i = 0; i < quads.size(); ++i)
160            contentsQuadToPage(mainView, containingView, quads[i]);
161        return false;
162    }
163
164    if (!renderer->isBox() && !renderer->isRenderInline())
165        return false;
166
167    LayoutRect contentBox;
168    LayoutRect paddingBox;
169    LayoutRect borderBox;
170    LayoutRect marginBox;
171
172    if (renderer->isBox()) {
173        RenderBox* renderBox = toRenderBox(renderer);
174
175        // RenderBox returns the "pure" content area box, exclusive of the scrollbars (if present), which also count towards the content area in CSS.
176        contentBox = renderBox->contentBoxRect();
177        contentBox.setWidth(contentBox.width() + renderBox->verticalScrollbarWidth());
178        contentBox.setHeight(contentBox.height() + renderBox->horizontalScrollbarHeight());
179
180        paddingBox = LayoutRect(contentBox.x() - renderBox->paddingLeft(), contentBox.y() - renderBox->paddingTop(),
181            contentBox.width() + renderBox->paddingLeft() + renderBox->paddingRight(), contentBox.height() + renderBox->paddingTop() + renderBox->paddingBottom());
182        borderBox = LayoutRect(paddingBox.x() - renderBox->borderLeft(), paddingBox.y() - renderBox->borderTop(),
183            paddingBox.width() + renderBox->borderLeft() + renderBox->borderRight(), paddingBox.height() + renderBox->borderTop() + renderBox->borderBottom());
184        marginBox = LayoutRect(borderBox.x() - renderBox->marginLeft(), borderBox.y() - renderBox->marginTop(),
185            borderBox.width() + renderBox->marginWidth(), borderBox.height() + renderBox->marginHeight());
186    } else {
187        RenderInline* renderInline = toRenderInline(renderer);
188
189        // RenderInline's bounding box includes paddings and borders, excludes margins.
190        borderBox = renderInline->linesBoundingBox();
191        paddingBox = LayoutRect(borderBox.x() + renderInline->borderLeft(), borderBox.y() + renderInline->borderTop(),
192            borderBox.width() - renderInline->borderLeft() - renderInline->borderRight(), borderBox.height() - renderInline->borderTop() - renderInline->borderBottom());
193        contentBox = LayoutRect(paddingBox.x() + renderInline->paddingLeft(), paddingBox.y() + renderInline->paddingTop(),
194            paddingBox.width() - renderInline->paddingLeft() - renderInline->paddingRight(), paddingBox.height() - renderInline->paddingTop() - renderInline->paddingBottom());
195        // Ignore marginTop and marginBottom for inlines.
196        marginBox = LayoutRect(borderBox.x() - renderInline->marginLeft(), borderBox.y(),
197            borderBox.width() + renderInline->marginWidth(), borderBox.height());
198    }
199
200    FloatQuad absContentQuad = renderer->localToAbsoluteQuad(FloatRect(contentBox));
201    FloatQuad absPaddingQuad = renderer->localToAbsoluteQuad(FloatRect(paddingBox));
202    FloatQuad absBorderQuad = renderer->localToAbsoluteQuad(FloatRect(borderBox));
203    FloatQuad absMarginQuad = renderer->localToAbsoluteQuad(FloatRect(marginBox));
204
205    contentsQuadToPage(mainView, containingView, absContentQuad);
206    contentsQuadToPage(mainView, containingView, absPaddingQuad);
207    contentsQuadToPage(mainView, containingView, absBorderQuad);
208    contentsQuadToPage(mainView, containingView, absMarginQuad);
209
210    quads.append(absMarginQuad);
211    quads.append(absBorderQuad);
212    quads.append(absPaddingQuad);
213    quads.append(absContentQuad);
214
215    return true;
216}
217
218static void buildNodeHighlight(Node* node, const HighlightConfig& highlightConfig, Highlight* highlight)
219{
220    RenderObject* renderer = node->renderer();
221    Frame* containingFrame = node->document().frame();
222
223    if (!renderer || !containingFrame)
224        return;
225
226    highlight->setDataFromConfig(highlightConfig);
227
228    // RenderSVGRoot should be highlighted through the isBox() code path, all other SVG elements should just dump their absoluteQuads().
229    if (renderer->node() && renderer->node()->isSVGElement() && !renderer->isSVGRoot())
230        highlight->type = HighlightTypeRects;
231    else if (renderer->isBox() || renderer->isRenderInline())
232        highlight->type = HighlightTypeNode;
233    buildNodeQuads(node, highlight->quads);
234}
235
236static void buildQuadHighlight(Page* page, const FloatQuad& quad, const HighlightConfig& highlightConfig, Highlight *highlight)
237{
238    if (!page)
239        return;
240    highlight->setDataFromConfig(highlightConfig);
241    highlight->type = HighlightTypeRects;
242    highlight->quads.append(quad);
243}
244
245} // anonymous namespace
246
247InspectorOverlay::InspectorOverlay(Page* page, InspectorClient* client)
248    : m_page(page)
249    , m_client(client)
250    , m_inspectModeEnabled(false)
251    , m_overlayHost(InspectorOverlayHost::create())
252    , m_drawViewSize(false)
253    , m_drawViewSizeWithGrid(false)
254    , m_timer(this, &InspectorOverlay::onTimer)
255    , m_activeProfilerCount(0)
256{
257}
258
259InspectorOverlay::~InspectorOverlay()
260{
261}
262
263void InspectorOverlay::paint(GraphicsContext& context)
264{
265    if (isEmpty())
266        return;
267    GraphicsContextStateSaver stateSaver(context);
268    FrameView* view = overlayPage()->mainFrame()->view();
269    ASSERT(!view->needsLayout());
270    view->paint(&context, IntRect(0, 0, view->width(), view->height()));
271}
272
273void InspectorOverlay::invalidate()
274{
275    m_client->highlight();
276}
277
278bool InspectorOverlay::handleGestureEvent(const PlatformGestureEvent& event)
279{
280    if (isEmpty())
281        return false;
282
283    return overlayPage()->mainFrame()->eventHandler().handleGestureEvent(event);
284}
285
286bool InspectorOverlay::handleMouseEvent(const PlatformMouseEvent& event)
287{
288    if (isEmpty())
289        return false;
290
291    EventHandler& eventHandler = overlayPage()->mainFrame()->eventHandler();
292    bool result;
293    switch (event.type()) {
294    case PlatformEvent::MouseMoved:
295        result = eventHandler.handleMouseMoveEvent(event);
296        break;
297    case PlatformEvent::MousePressed:
298        result = eventHandler.handleMousePressEvent(event);
299        break;
300    case PlatformEvent::MouseReleased:
301        result = eventHandler.handleMouseReleaseEvent(event);
302        break;
303    default:
304        return false;
305    }
306
307    overlayPage()->mainFrame()->document()->updateLayout();
308    return result;
309}
310
311bool InspectorOverlay::handleTouchEvent(const PlatformTouchEvent& event)
312{
313    if (isEmpty())
314        return false;
315
316    return overlayPage()->mainFrame()->eventHandler().handleTouchEvent(event);
317}
318
319bool InspectorOverlay::handleKeyboardEvent(const PlatformKeyboardEvent& event)
320{
321    if (isEmpty())
322        return false;
323
324    return overlayPage()->mainFrame()->eventHandler().keyEvent(event);
325}
326
327void InspectorOverlay::drawOutline(GraphicsContext* context, const LayoutRect& rect, const Color& color)
328{
329    FloatRect outlineRect = rect;
330    drawOutlinedQuad(context, outlineRect, Color(), color);
331}
332
333void InspectorOverlay::getHighlight(Highlight* highlight) const
334{
335    if (!m_highlightNode && !m_highlightQuad)
336        return;
337
338    highlight->type = HighlightTypeRects;
339    if (m_highlightNode)
340        buildNodeHighlight(m_highlightNode.get(), m_nodeHighlightConfig, highlight);
341    else
342        buildQuadHighlight(m_page, *m_highlightQuad, m_quadHighlightConfig, highlight);
343}
344
345void InspectorOverlay::resize(const IntSize& size)
346{
347    m_size = size;
348    update();
349}
350
351void InspectorOverlay::setPausedInDebuggerMessage(const String* message)
352{
353    m_pausedInDebuggerMessage = message ? *message : String();
354    update();
355}
356
357void InspectorOverlay::setInspectModeEnabled(bool enabled)
358{
359    m_inspectModeEnabled = enabled;
360    update();
361}
362
363void InspectorOverlay::hideHighlight()
364{
365    m_highlightNode.clear();
366    m_eventTargetNode.clear();
367    m_highlightQuad.clear();
368    update();
369}
370
371void InspectorOverlay::highlightNode(Node* node, Node* eventTarget, const HighlightConfig& highlightConfig)
372{
373    m_nodeHighlightConfig = highlightConfig;
374    m_highlightNode = node;
375    m_eventTargetNode = eventTarget;
376    update();
377}
378
379void InspectorOverlay::highlightQuad(PassOwnPtr<FloatQuad> quad, const HighlightConfig& highlightConfig)
380{
381    m_quadHighlightConfig = highlightConfig;
382    m_highlightQuad = quad;
383    update();
384}
385
386void InspectorOverlay::showAndHideViewSize(bool showGrid)
387{
388    m_drawViewSize = true;
389    m_drawViewSizeWithGrid = showGrid;
390    update();
391    m_timer.startOneShot(1);
392}
393
394Node* InspectorOverlay::highlightedNode() const
395{
396    return m_highlightNode.get();
397}
398
399bool InspectorOverlay::isEmpty()
400{
401    if (m_activeProfilerCount)
402        return true;
403    bool hasAlwaysVisibleElements = m_highlightNode || m_eventTargetNode || m_highlightQuad || !m_size.isEmpty() || m_drawViewSize;
404    bool hasInvisibleInInspectModeElements = !m_pausedInDebuggerMessage.isNull();
405    return !(hasAlwaysVisibleElements || (hasInvisibleInInspectModeElements && !m_inspectModeEnabled));
406}
407
408void InspectorOverlay::update()
409{
410    if (isEmpty()) {
411        m_client->hideHighlight();
412        return;
413    }
414
415    FrameView* view = m_page->mainFrame()->view();
416    if (!view)
417        return;
418    IntRect viewRect = view->visibleContentRect();
419    FrameView* overlayView = overlayPage()->mainFrame()->view();
420
421    // Include scrollbars to avoid masking them by the gutter.
422    IntSize frameViewFullSize = view->visibleContentRect(ScrollableArea::IncludeScrollbars).size();
423    IntSize size = m_size.isEmpty() ? frameViewFullSize : m_size;
424    size.scale(m_page->pageScaleFactor());
425    overlayView->resize(size);
426
427    // Clear canvas and paint things.
428    reset(size, m_size.isEmpty() ? IntSize() : frameViewFullSize, viewRect.x(), viewRect.y());
429
430    drawNodeHighlight();
431    drawQuadHighlight();
432    if (!m_inspectModeEnabled)
433        drawPausedInDebuggerMessage();
434    drawViewSize();
435
436    // Position DOM elements.
437    overlayPage()->mainFrame()->document()->recalcStyle(Force);
438    if (overlayView->needsLayout())
439        overlayView->layout();
440
441    // Kick paint.
442    m_client->highlight();
443}
444
445void InspectorOverlay::hide()
446{
447    m_timer.stop();
448    m_highlightNode.clear();
449    m_eventTargetNode.clear();
450    m_highlightQuad.clear();
451    m_pausedInDebuggerMessage = String();
452    m_size = IntSize();
453    m_drawViewSize = false;
454    m_drawViewSizeWithGrid = false;
455    update();
456}
457
458static PassRefPtr<JSONObject> buildObjectForPoint(const FloatPoint& point)
459{
460    RefPtr<JSONObject> object = JSONObject::create();
461    object->setNumber("x", point.x());
462    object->setNumber("y", point.y());
463    return object.release();
464}
465
466static PassRefPtr<JSONArray> buildArrayForQuad(const FloatQuad& quad)
467{
468    RefPtr<JSONArray> array = JSONArray::create();
469    array->pushObject(buildObjectForPoint(quad.p1()));
470    array->pushObject(buildObjectForPoint(quad.p2()));
471    array->pushObject(buildObjectForPoint(quad.p3()));
472    array->pushObject(buildObjectForPoint(quad.p4()));
473    return array.release();
474}
475
476static PassRefPtr<JSONObject> buildObjectForHighlight(const Highlight& highlight)
477{
478    RefPtr<JSONObject> object = JSONObject::create();
479    RefPtr<JSONArray> array = JSONArray::create();
480    for (size_t i = 0; i < highlight.quads.size(); ++i)
481        array->pushArray(buildArrayForQuad(highlight.quads[i]));
482    object->setArray("quads", array.release());
483    object->setBoolean("showRulers", highlight.showRulers);
484    object->setString("contentColor", highlight.contentColor.serialized());
485    object->setString("contentOutlineColor", highlight.contentOutlineColor.serialized());
486    object->setString("paddingColor", highlight.paddingColor.serialized());
487    object->setString("borderColor", highlight.borderColor.serialized());
488    object->setString("marginColor", highlight.marginColor.serialized());
489    object->setString("eventTargetColor", highlight.eventTargetColor.serialized());
490    return object.release();
491}
492
493static PassRefPtr<JSONObject> buildObjectForSize(const IntSize& size)
494{
495    RefPtr<JSONObject> result = JSONObject::create();
496    result->setNumber("width", size.width());
497    result->setNumber("height", size.height());
498    return result.release();
499}
500
501void InspectorOverlay::drawNodeHighlight()
502{
503    if (!m_highlightNode)
504        return;
505
506    Highlight highlight;
507    buildNodeHighlight(m_highlightNode.get(), m_nodeHighlightConfig, &highlight);
508    if (m_eventTargetNode) {
509        Highlight eventTargetHighlight;
510        buildNodeHighlight(m_eventTargetNode.get(), m_nodeHighlightConfig, &eventTargetHighlight);
511        highlight.quads.append(eventTargetHighlight.quads[1]); // Add border from eventTargetNode to highlight.
512    }
513    RefPtr<JSONObject> highlightObject = buildObjectForHighlight(highlight);
514
515    Node* node = m_highlightNode.get();
516    if (node->isElementNode() && m_nodeHighlightConfig.showInfo && node->renderer() && node->document().frame()) {
517        RefPtr<JSONObject> elementInfo = JSONObject::create();
518        Element* element = toElement(node);
519        Element* realElement = element;
520        PseudoElement* pseudoElement = 0;
521        if (element->isPseudoElement()) {
522            pseudoElement = toPseudoElement(element);
523            realElement = element->parentOrShadowHostElement();
524        }
525        bool isXHTML = realElement->document().isXHTMLDocument();
526        elementInfo->setString("tagName", isXHTML ? realElement->nodeName() : realElement->nodeName().lower());
527        elementInfo->setString("idValue", realElement->getIdAttribute());
528        StringBuilder classNames;
529        if (realElement->hasClass() && realElement->isStyledElement()) {
530            HashSet<AtomicString> usedClassNames;
531            const SpaceSplitString& classNamesString = realElement->classNames();
532            size_t classNameCount = classNamesString.size();
533            for (size_t i = 0; i < classNameCount; ++i) {
534                const AtomicString& className = classNamesString[i];
535                if (!usedClassNames.add(className).isNewEntry)
536                    continue;
537                classNames.append('.');
538                classNames.append(className);
539            }
540        }
541        if (pseudoElement) {
542            if (pseudoElement->pseudoId() == BEFORE)
543                classNames.append("::before");
544            else if (pseudoElement->pseudoId() == AFTER)
545                classNames.append("::after");
546        }
547        if (!classNames.isEmpty())
548            elementInfo->setString("className", classNames.toString());
549
550        RenderObject* renderer = node->renderer();
551        Frame* containingFrame = node->document().frame();
552        FrameView* containingView = containingFrame->view();
553        IntRect boundingBox = pixelSnappedIntRect(containingView->contentsToRootView(renderer->absoluteBoundingBoxRect()));
554        RenderBoxModelObject* modelObject = renderer->isBoxModelObject() ? toRenderBoxModelObject(renderer) : 0;
555        elementInfo->setString("nodeWidth", String::number(modelObject ? adjustForAbsoluteZoom(modelObject->pixelSnappedOffsetWidth(), modelObject) : boundingBox.width()));
556        elementInfo->setString("nodeHeight", String::number(modelObject ? adjustForAbsoluteZoom(modelObject->pixelSnappedOffsetHeight(), modelObject) : boundingBox.height()));
557        highlightObject->setObject("elementInfo", elementInfo.release());
558    }
559    evaluateInOverlay("drawNodeHighlight", highlightObject);
560}
561
562void InspectorOverlay::drawQuadHighlight()
563{
564    if (!m_highlightQuad)
565        return;
566
567    Highlight highlight;
568    buildQuadHighlight(m_page, *m_highlightQuad, m_quadHighlightConfig, &highlight);
569    evaluateInOverlay("drawQuadHighlight", buildObjectForHighlight(highlight));
570}
571
572void InspectorOverlay::drawPausedInDebuggerMessage()
573{
574    if (!m_pausedInDebuggerMessage.isNull())
575        evaluateInOverlay("drawPausedInDebuggerMessage", m_pausedInDebuggerMessage);
576}
577
578void InspectorOverlay::drawViewSize()
579{
580    if (m_drawViewSize)
581        evaluateInOverlay("drawViewSize", m_drawViewSizeWithGrid ? "true" : "false");
582}
583
584Page* InspectorOverlay::overlayPage()
585{
586    if (m_overlayPage)
587        return m_overlayPage.get();
588
589    static FrameLoaderClient* dummyFrameLoaderClient =  new EmptyFrameLoaderClient;
590    Page::PageClients pageClients;
591    fillWithEmptyClients(pageClients);
592    ASSERT(!m_overlayChromeClient);
593    m_overlayChromeClient = adoptPtr(new InspectorOverlayChromeClient(m_page->chrome().client(), this));
594    pageClients.chromeClient = m_overlayChromeClient.get();
595    m_overlayPage = adoptPtr(new Page(pageClients));
596
597    Settings& settings = m_page->settings();
598    Settings& overlaySettings = m_overlayPage->settings();
599
600    overlaySettings.genericFontFamilySettings().setStandard(settings.genericFontFamilySettings().standard());
601    overlaySettings.genericFontFamilySettings().setSerif(settings.genericFontFamilySettings().serif());
602    overlaySettings.genericFontFamilySettings().setSansSerif(settings.genericFontFamilySettings().sansSerif());
603    overlaySettings.genericFontFamilySettings().setCursive(settings.genericFontFamilySettings().cursive());
604    overlaySettings.genericFontFamilySettings().setFantasy(settings.genericFontFamilySettings().fantasy());
605    overlaySettings.genericFontFamilySettings().setPictograph(settings.genericFontFamilySettings().pictograph());
606    overlaySettings.setMinimumFontSize(settings.minimumFontSize());
607    overlaySettings.setMinimumLogicalFontSize(settings.minimumLogicalFontSize());
608    overlaySettings.setMediaEnabled(false);
609    overlaySettings.setScriptEnabled(true);
610    overlaySettings.setPluginsEnabled(false);
611    overlaySettings.setLoadsImagesAutomatically(true);
612
613    RefPtr<Frame> frame = Frame::create(FrameInit::create(0, m_overlayPage.get(), dummyFrameLoaderClient));
614    frame->setView(FrameView::create(frame.get()));
615    frame->init();
616    FrameLoader& loader = frame->loader();
617    frame->view()->setCanHaveScrollbars(false);
618    frame->view()->setTransparent(true);
619    ASSERT(loader.activeDocumentLoader());
620    DocumentWriter* writer = loader.activeDocumentLoader()->beginWriting("text/html", "UTF-8");
621    writer->addData(reinterpret_cast<const char*>(InspectorOverlayPage_html), sizeof(InspectorOverlayPage_html));
622    loader.activeDocumentLoader()->endWriting(writer);
623    v8::Isolate* isolate = toIsolate(frame.get());
624    v8::HandleScope handleScope(isolate);
625    v8::Handle<v8::Context> frameContext = frame->script().currentWorldContext();
626    v8::Context::Scope contextScope(frameContext);
627    v8::Handle<v8::Value> overlayHostObj = toV8(m_overlayHost.get(), v8::Handle<v8::Object>(), isolate);
628    v8::Handle<v8::Object> global = frameContext->Global();
629    global->Set(v8::String::NewFromUtf8(isolate, "InspectorOverlayHost"), overlayHostObj);
630
631#if OS(WIN)
632    evaluateInOverlay("setPlatform", "windows");
633#elif OS(MACOSX)
634    evaluateInOverlay("setPlatform", "mac");
635#elif OS(POSIX)
636    evaluateInOverlay("setPlatform", "linux");
637#endif
638
639    return m_overlayPage.get();
640}
641
642void InspectorOverlay::reset(const IntSize& viewportSize, const IntSize& frameViewFullSize, int scrollX, int scrollY)
643{
644    RefPtr<JSONObject> resetData = JSONObject::create();
645    resetData->setNumber("pageScaleFactor", m_page->pageScaleFactor());
646    resetData->setNumber("deviceScaleFactor", m_page->deviceScaleFactor());
647    resetData->setObject("viewportSize", buildObjectForSize(viewportSize));
648    resetData->setObject("frameViewFullSize", buildObjectForSize(frameViewFullSize));
649    resetData->setNumber("pageZoomFactor", m_page->mainFrame()->pageZoomFactor());
650    resetData->setNumber("scrollX", scrollX);
651    resetData->setNumber("scrollY", scrollY);
652    evaluateInOverlay("reset", resetData.release());
653}
654
655void InspectorOverlay::evaluateInOverlay(const String& method, const String& argument)
656{
657    RefPtr<JSONArray> command = JSONArray::create();
658    command->pushString(method);
659    command->pushString(argument);
660    overlayPage()->mainFrame()->script().executeScriptInMainWorld("dispatch(" + command->toJSONString() + ")", ScriptController::ExecuteScriptWhenScriptsDisabled);
661}
662
663void InspectorOverlay::evaluateInOverlay(const String& method, PassRefPtr<JSONValue> argument)
664{
665    RefPtr<JSONArray> command = JSONArray::create();
666    command->pushString(method);
667    command->pushValue(argument);
668    overlayPage()->mainFrame()->script().executeScriptInMainWorld("dispatch(" + command->toJSONString() + ")", ScriptController::ExecuteScriptWhenScriptsDisabled);
669}
670
671void InspectorOverlay::onTimer(Timer<InspectorOverlay>*)
672{
673    m_drawViewSize = false;
674    update();
675}
676
677bool InspectorOverlay::getBoxModel(Node* node, Vector<FloatQuad>* quads)
678{
679    return buildNodeQuads(node, *quads);
680}
681
682void InspectorOverlay::freePage()
683{
684    m_overlayPage.clear();
685    m_overlayChromeClient.clear();
686    m_timer.stop();
687}
688
689void InspectorOverlay::startedRecordingProfile()
690{
691    if (!m_activeProfilerCount++)
692        freePage();
693}
694
695} // namespace WebCore
696