1/*
2 * Copyright (C) 2012 Google Inc. All rights reserved.
3 * Copyright (C) 2013 Apple Inc. All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * 1.  Redistributions of source code must retain the above copyright
10 *     notice, this list of conditions and the following disclaimer.
11 * 2.  Redistributions in binary form must reproduce the above copyright
12 *     notice, this list of conditions and the following disclaimer in the
13 *     documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
16 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
17 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
18 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
19 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
20 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
21 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 */
26
27#include "config.h"
28#include "Internals.h"
29
30#include "HTMLNames.h"
31#include "InspectorFrontendClientLocal.h"
32#include "InternalProfilers.h"
33#include "InternalRuntimeFlags.h"
34#include "InternalSettings.h"
35#include "LayerRect.h"
36#include "LayerRectList.h"
37#include "MallocStatistics.h"
38#include "MockPagePopupDriver.h"
39#include "RuntimeEnabledFeatures.h"
40#include "TypeConversions.h"
41#include "bindings/v8/ExceptionState.h"
42#include "bindings/v8/SerializedScriptValue.h"
43#include "bindings/v8/V8ThrowException.h"
44#include "core/css/StyleSheetContents.h"
45#include "core/css/resolver/StyleResolver.h"
46#include "core/css/resolver/ViewportStyleResolver.h"
47#include "core/dom/ClientRect.h"
48#include "core/dom/ClientRectList.h"
49#include "core/dom/DOMStringList.h"
50#include "core/dom/Document.h"
51#include "core/dom/DocumentMarker.h"
52#include "core/dom/DocumentMarkerController.h"
53#include "core/dom/Element.h"
54#include "core/dom/ExceptionCode.h"
55#include "core/dom/FullscreenElementStack.h"
56#include "core/dom/NodeRenderingContext.h"
57#include "core/dom/PseudoElement.h"
58#include "core/dom/Range.h"
59#include "core/dom/StaticNodeList.h"
60#include "core/dom/TreeScope.h"
61#include "core/dom/ViewportArguments.h"
62#include "core/dom/shadow/ComposedShadowTreeWalker.h"
63#include "core/dom/shadow/ContentDistributor.h"
64#include "core/dom/shadow/ElementShadow.h"
65#include "core/dom/shadow/SelectRuleFeatureSet.h"
66#include "core/dom/shadow/ShadowRoot.h"
67#include "core/editing/Editor.h"
68#include "core/editing/SpellChecker.h"
69#include "core/editing/TextIterator.h"
70#include "core/history/BackForwardController.h"
71#include "core/history/HistoryItem.h"
72#include "core/html/FormController.h"
73#include "core/html/HTMLInputElement.h"
74#include "core/html/HTMLMediaElement.h"
75#include "core/html/HTMLSelectElement.h"
76#include "core/html/HTMLTextAreaElement.h"
77#include "core/html/shadow/HTMLContentElement.h"
78#include "core/inspector/InspectorClient.h"
79#include "core/inspector/InspectorConsoleAgent.h"
80#include "core/inspector/InspectorController.h"
81#include "core/inspector/InspectorCounters.h"
82#include "core/inspector/InspectorFrontendChannel.h"
83#include "core/inspector/InspectorInstrumentation.h"
84#include "core/inspector/InspectorOverlay.h"
85#include "core/inspector/InstrumentingAgents.h"
86#include "core/loader/FrameLoader.h"
87#include "core/loader/cache/MemoryCache.h"
88#include "core/loader/cache/ResourceFetcher.h"
89#include "core/page/Chrome.h"
90#include "core/page/ChromeClient.h"
91#include "core/page/DOMPoint.h"
92#include "core/page/DOMWindow.h"
93#include "core/page/EventHandler.h"
94#include "core/page/Frame.h"
95#include "core/page/FrameView.h"
96#include "core/page/Page.h"
97#include "core/page/PagePopupController.h"
98#include "core/page/PrintContext.h"
99#include "core/page/Settings.h"
100#include "core/page/animation/AnimationController.h"
101#include "core/page/scrolling/ScrollingCoordinator.h"
102#include "core/platform/ColorChooser.h"
103#include "core/platform/Cursor.h"
104#include "core/platform/Language.h"
105#include "core/platform/chromium/TraceEvent.h"
106#include "core/platform/graphics/GraphicsLayer.h"
107#include "core/platform/graphics/IntRect.h"
108#include "core/platform/graphics/filters/FilterOperation.h"
109#include "core/platform/graphics/filters/FilterOperations.h"
110#include "core/platform/graphics/gpu/SharedGraphicsContext3D.h"
111#include "core/platform/mock/PlatformSpeechSynthesizerMock.h"
112#include "core/rendering/RenderLayerBacking.h"
113#include "core/rendering/RenderMenuList.h"
114#include "core/rendering/RenderObject.h"
115#include "core/rendering/RenderTreeAsText.h"
116#include "core/rendering/RenderView.h"
117#include "core/testing/GCObservation.h"
118#include "core/workers/WorkerThread.h"
119#include "modules/speech/DOMWindowSpeechSynthesis.h"
120#include "modules/speech/SpeechSynthesis.h"
121#include "weborigin/SchemeRegistry.h"
122#include "wtf/dtoa.h"
123#include "wtf/text/StringBuffer.h"
124#include <v8.h>
125
126namespace WebCore {
127
128static MockPagePopupDriver* s_pagePopupDriver = 0;
129
130using namespace HTMLNames;
131
132class InspectorFrontendChannelDummy : public InspectorFrontendChannel {
133public:
134    explicit InspectorFrontendChannelDummy(Page*);
135    virtual ~InspectorFrontendChannelDummy() { }
136    virtual bool sendMessageToFrontend(const String& message) OVERRIDE;
137
138private:
139    Page* m_frontendPage;
140};
141
142InspectorFrontendChannelDummy::InspectorFrontendChannelDummy(Page* page)
143    : m_frontendPage(page)
144{
145}
146
147bool InspectorFrontendChannelDummy::sendMessageToFrontend(const String& message)
148{
149    return InspectorClient::doDispatchMessageOnFrontendPage(m_frontendPage, message);
150}
151
152static bool markerTypesFrom(const String& markerType, DocumentMarker::MarkerTypes& result)
153{
154    if (markerType.isEmpty() || equalIgnoringCase(markerType, "all"))
155        result = DocumentMarker::AllMarkers();
156    else if (equalIgnoringCase(markerType, "Spelling"))
157        result =  DocumentMarker::Spelling;
158    else if (equalIgnoringCase(markerType, "Grammar"))
159        result =  DocumentMarker::Grammar;
160    else if (equalIgnoringCase(markerType, "TextMatch"))
161        result =  DocumentMarker::TextMatch;
162    else
163        return false;
164
165    return true;
166}
167
168static SpellChecker* spellchecker(Document* document)
169{
170    if (!document || !document->frame() || !document->frame()->editor())
171        return 0;
172
173    return document->frame()->editor()->spellChecker();
174}
175
176const char* Internals::internalsId = "internals";
177
178PassRefPtr<Internals> Internals::create(Document* document)
179{
180    return adoptRef(new Internals(document));
181}
182
183Internals::~Internals()
184{
185    if (m_scrollingCoordinator) {
186        m_scrollingCoordinator->removeTouchEventTargetRectsObserver(this);
187    }
188}
189
190void Internals::resetToConsistentState(Page* page)
191{
192    ASSERT(page);
193
194    page->setDeviceScaleFactor(1);
195    page->setPageScaleFactor(1, IntPoint(0, 0));
196    page->setPagination(Pagination());
197    TextRun::setAllowsRoundingHacks(false);
198    WebCore::overrideUserPreferredLanguages(Vector<String>());
199    WebCore::Settings::setUsesOverlayScrollbars(false);
200    delete s_pagePopupDriver;
201    s_pagePopupDriver = 0;
202    page->chrome().client()->resetPagePopupDriver();
203    if (!page->mainFrame()->editor()->isContinuousSpellCheckingEnabled())
204        page->mainFrame()->editor()->toggleContinuousSpellChecking();
205    if (page->mainFrame()->editor()->isOverwriteModeEnabled())
206        page->mainFrame()->editor()->toggleOverwriteModeEnabled();
207}
208
209Internals::Internals(Document* document)
210    : ContextLifecycleObserver(document)
211    , m_runtimeFlags(InternalRuntimeFlags::create())
212    , m_scrollingCoordinator(document->page() ? document->page()->scrollingCoordinator() : 0)
213    , m_touchEventTargetRectUpdateCount(0)
214{
215    if (m_scrollingCoordinator) {
216        m_scrollingCoordinator->addTouchEventTargetRectsObserver(this);
217    }
218}
219
220Document* Internals::contextDocument() const
221{
222    return toDocument(scriptExecutionContext());
223}
224
225Frame* Internals::frame() const
226{
227    if (!contextDocument())
228        return 0;
229    return contextDocument()->frame();
230}
231
232InternalSettings* Internals::settings() const
233{
234    Document* document = contextDocument();
235    if (!document)
236        return 0;
237    Page* page = document->page();
238    if (!page)
239        return 0;
240    return InternalSettings::from(page);
241}
242
243InternalRuntimeFlags* Internals::runtimeFlags() const
244{
245    return m_runtimeFlags.get();
246}
247
248InternalProfilers* Internals::profilers()
249{
250    if (!m_profilers)
251        m_profilers = InternalProfilers::create();
252    return m_profilers.get();
253}
254
255unsigned Internals::workerThreadCount() const
256{
257    return WorkerThread::workerThreadCount();
258}
259
260String Internals::address(Node* node)
261{
262    char buf[32];
263    sprintf(buf, "%p", node);
264
265    return String(buf);
266}
267
268PassRefPtr<GCObservation> Internals::observeGC(ScriptValue scriptValue)
269{
270    v8::Handle<v8::Value> observedValue = scriptValue.v8Value();
271    ASSERT(!observedValue.IsEmpty());
272    if (observedValue->IsNull() || observedValue->IsUndefined()) {
273        V8ThrowException::throwTypeError("value to observe is null or undefined", v8::Isolate::GetCurrent());
274        return 0;
275    }
276
277    return GCObservation::create(observedValue);
278}
279
280bool Internals::isPreloaded(const String& url)
281{
282    Document* document = contextDocument();
283    return document->fetcher()->isPreloaded(url);
284}
285
286bool Internals::isLoadingFromMemoryCache(const String& url)
287{
288    if (!contextDocument())
289        return false;
290    Resource* resource = memoryCache()->resourceForURL(contextDocument()->completeURL(url));
291    return resource && resource->status() == Resource::Cached;
292}
293
294void Internals::crash()
295{
296    CRASH();
297}
298
299PassRefPtr<Element> Internals::createContentElement(ExceptionState& es)
300{
301    Document* document = contextDocument();
302    if (!document) {
303        es.throwDOMException(InvalidAccessError);
304        return 0;
305    }
306
307    return HTMLContentElement::create(document);
308}
309
310bool Internals::isValidContentSelect(Element* insertionPoint, ExceptionState& es)
311{
312    if (!insertionPoint || !insertionPoint->isInsertionPoint()) {
313        es.throwDOMException(InvalidAccessError);
314        return false;
315    }
316
317    return isHTMLContentElement(insertionPoint) && toHTMLContentElement(insertionPoint)->isSelectValid();
318}
319
320Node* Internals::treeScopeRootNode(Node* node, ExceptionState& es)
321{
322    if (!node) {
323        es.throwDOMException(InvalidAccessError);
324        return 0;
325    }
326
327    return node->treeScope()->rootNode();
328}
329
330Node* Internals::parentTreeScope(Node* node, ExceptionState& es)
331{
332    if (!node) {
333        es.throwDOMException(InvalidAccessError);
334        return 0;
335    }
336    const TreeScope* parentTreeScope = node->treeScope()->parentTreeScope();
337    return parentTreeScope ? parentTreeScope->rootNode() : 0;
338}
339
340bool Internals::hasSelectorForIdInShadow(Element* host, const String& idValue, ExceptionState& es)
341{
342    if (!host || !host->shadow()) {
343        es.throwDOMException(InvalidAccessError);
344        return 0;
345    }
346
347    return host->shadow()->distributor().ensureSelectFeatureSet(host->shadow()).hasSelectorForId(idValue);
348}
349
350bool Internals::hasSelectorForClassInShadow(Element* host, const String& className, ExceptionState& es)
351{
352    if (!host || !host->shadow()) {
353        es.throwDOMException(InvalidAccessError);
354        return 0;
355    }
356
357    return host->shadow()->distributor().ensureSelectFeatureSet(host->shadow()).hasSelectorForClass(className);
358}
359
360bool Internals::hasSelectorForAttributeInShadow(Element* host, const String& attributeName, ExceptionState& es)
361{
362    if (!host || !host->shadow()) {
363        es.throwDOMException(InvalidAccessError);
364        return 0;
365    }
366
367    return host->shadow()->distributor().ensureSelectFeatureSet(host->shadow()).hasSelectorForAttribute(attributeName);
368}
369
370bool Internals::hasSelectorForPseudoClassInShadow(Element* host, const String& pseudoClass, ExceptionState& es)
371{
372    if (!host || !host->shadow()) {
373        es.throwDOMException(InvalidAccessError);
374        return 0;
375    }
376
377    const SelectRuleFeatureSet& featureSet = host->shadow()->distributor().ensureSelectFeatureSet(host->shadow());
378    if (pseudoClass == "checked")
379        return featureSet.hasSelectorForChecked();
380    if (pseudoClass == "enabled")
381        return featureSet.hasSelectorForEnabled();
382    if (pseudoClass == "disabled")
383        return featureSet.hasSelectorForDisabled();
384    if (pseudoClass == "indeterminate")
385        return featureSet.hasSelectorForIndeterminate();
386    if (pseudoClass == "link")
387        return featureSet.hasSelectorForLink();
388    if (pseudoClass == "target")
389        return featureSet.hasSelectorForTarget();
390    if (pseudoClass == "visited")
391        return featureSet.hasSelectorForVisited();
392
393    ASSERT_NOT_REACHED();
394    return false;
395}
396
397unsigned short Internals::compareTreeScopePosition(const Node* node1, const Node* node2, ExceptionState& es) const
398{
399    if (!node1 || !node2) {
400        es.throwDOMException(InvalidAccessError);
401        return 0;
402    }
403    const TreeScope* treeScope1 = node1->isDocumentNode() ? static_cast<const TreeScope*>(toDocument(node1)) :
404        node1->isShadowRoot() ? static_cast<const TreeScope*>(toShadowRoot(node1)) : 0;
405    const TreeScope* treeScope2 = node2->isDocumentNode() ? static_cast<const TreeScope*>(toDocument(node2)) :
406        node2->isShadowRoot() ? static_cast<const TreeScope*>(toShadowRoot(node2)) : 0;
407    if (!treeScope1 || !treeScope2) {
408        es.throwDOMException(InvalidAccessError);
409        return 0;
410    }
411    return treeScope1->comparePosition(treeScope2);
412}
413
414unsigned Internals::numberOfActiveAnimations() const
415{
416    Frame* contextFrame = frame();
417    if (!RuntimeEnabledFeatures::webAnimationsCSSEnabled()) {
418        if (AnimationController* controller = contextFrame->animation())
419            return controller->numberOfActiveAnimations(contextFrame->document());
420    }
421    return 0;
422}
423
424void Internals::suspendAnimations(Document* document, ExceptionState& es) const
425{
426    if (!document || !document->frame()) {
427        es.throwDOMException(InvalidAccessError);
428        return;
429    }
430
431    if (!RuntimeEnabledFeatures::webAnimationsCSSEnabled()) {
432        AnimationController* controller = document->frame()->animation();
433        if (!controller)
434            return;
435
436        controller->suspendAnimations();
437    }
438}
439
440void Internals::resumeAnimations(Document* document, ExceptionState& es) const
441{
442    if (!document || !document->frame()) {
443        es.throwDOMException(InvalidAccessError);
444        return;
445    }
446
447    if (!RuntimeEnabledFeatures::webAnimationsCSSEnabled()) {
448        AnimationController* controller = document->frame()->animation();
449        if (!controller)
450            return;
451
452        controller->resumeAnimations();
453    }
454}
455
456void Internals::pauseAnimations(double pauseTime, ExceptionState& es)
457{
458    if (pauseTime < 0) {
459        es.throwDOMException(InvalidAccessError);
460        return;
461    }
462
463    if (!RuntimeEnabledFeatures::webAnimationsCSSEnabled())
464        frame()->animation()->pauseAnimationsForTesting(pauseTime);
465}
466
467bool Internals::hasShadowInsertionPoint(const Node* root, ExceptionState& es) const
468{
469    if (root && root->isShadowRoot())
470        return toShadowRoot(root)->containsShadowElements();
471
472    es.throwDOMException(InvalidAccessError);
473    return 0;
474}
475
476bool Internals::hasContentElement(const Node* root, ExceptionState& es) const
477{
478    if (root && root->isShadowRoot())
479        return toShadowRoot(root)->containsContentElements();
480
481    es.throwDOMException(InvalidAccessError);
482    return 0;
483}
484
485size_t Internals::countElementShadow(const Node* root, ExceptionState& es) const
486{
487    if (!root || !root->isShadowRoot()) {
488        es.throwDOMException(InvalidAccessError);
489        return 0;
490    }
491    if (const ScopeContentDistribution* distribution = toShadowRoot(root)->scopeDistribution())
492        return distribution->numberOfElementShadowChildren();
493    return 0;
494}
495
496bool Internals::attached(Node* node, ExceptionState& es)
497{
498    if (!node) {
499        es.throwDOMException(InvalidAccessError);
500        return false;
501    }
502
503    return node->attached();
504}
505
506Node* Internals::nextSiblingByWalker(Node* node, ExceptionState& es)
507{
508    if (!node) {
509        es.throwDOMException(InvalidAccessError);
510        return 0;
511    }
512    ComposedShadowTreeWalker walker(node);
513    walker.nextSibling();
514    return walker.get();
515}
516
517Node* Internals::firstChildByWalker(Node* node, ExceptionState& es)
518{
519    if (!node) {
520        es.throwDOMException(InvalidAccessError);
521        return 0;
522    }
523    ComposedShadowTreeWalker walker(node);
524    walker.firstChild();
525    return walker.get();
526}
527
528Node* Internals::lastChildByWalker(Node* node, ExceptionState& es)
529{
530    if (!node) {
531        es.throwDOMException(InvalidAccessError);
532        return 0;
533    }
534    ComposedShadowTreeWalker walker(node);
535    walker.lastChild();
536    return walker.get();
537}
538
539Node* Internals::nextNodeByWalker(Node* node, ExceptionState& es)
540{
541    if (!node) {
542        es.throwDOMException(InvalidAccessError);
543        return 0;
544    }
545    ComposedShadowTreeWalker walker(node);
546    walker.next();
547    return walker.get();
548}
549
550Node* Internals::previousNodeByWalker(Node* node, ExceptionState& es)
551{
552    if (!node) {
553        es.throwDOMException(InvalidAccessError);
554        return 0;
555    }
556    ComposedShadowTreeWalker walker(node);
557    walker.previous();
558    return walker.get();
559}
560
561String Internals::elementRenderTreeAsText(Element* element, ExceptionState& es)
562{
563    if (!element) {
564        es.throwDOMException(InvalidAccessError);
565        return String();
566    }
567
568    String representation = externalRepresentation(element);
569    if (representation.isEmpty()) {
570        es.throwDOMException(InvalidAccessError);
571        return String();
572    }
573
574    return representation;
575}
576
577size_t Internals::numberOfScopedHTMLStyleChildren(const Node* scope, ExceptionState& es) const
578{
579    if (scope && (scope->isElementNode() || scope->isShadowRoot()))
580        return scope->numberOfScopedHTMLStyleChildren();
581
582    es.throwDOMException(InvalidAccessError);
583    return 0;
584}
585
586PassRefPtr<CSSComputedStyleDeclaration> Internals::computedStyleIncludingVisitedInfo(Node* node, ExceptionState& es) const
587{
588    if (!node) {
589        es.throwDOMException(InvalidAccessError);
590        return 0;
591    }
592
593    bool allowVisitedStyle = true;
594    return CSSComputedStyleDeclaration::create(node, allowVisitedStyle);
595}
596
597ShadowRoot* Internals::ensureShadowRoot(Element* host, ExceptionState& es)
598{
599    if (!host) {
600        es.throwDOMException(InvalidAccessError);
601        return 0;
602    }
603
604    if (ElementShadow* shadow = host->shadow())
605        return shadow->youngestShadowRoot();
606
607    return host->createShadowRoot(es).get();
608}
609
610ShadowRoot* Internals::shadowRoot(Element* host, ExceptionState& es)
611{
612    // FIXME: Internals::shadowRoot() in tests should be converted to youngestShadowRoot() or oldestShadowRoot().
613    // https://bugs.webkit.org/show_bug.cgi?id=78465
614    return youngestShadowRoot(host, es);
615}
616
617ShadowRoot* Internals::youngestShadowRoot(Element* host, ExceptionState& es)
618{
619    if (!host) {
620        es.throwDOMException(InvalidAccessError);
621        return 0;
622    }
623
624    if (ElementShadow* shadow = host->shadow())
625        return shadow->youngestShadowRoot();
626    return 0;
627}
628
629ShadowRoot* Internals::oldestShadowRoot(Element* host, ExceptionState& es)
630{
631    if (!host) {
632        es.throwDOMException(InvalidAccessError);
633        return 0;
634    }
635
636    if (ElementShadow* shadow = host->shadow())
637        return shadow->oldestShadowRoot();
638    return 0;
639}
640
641ShadowRoot* Internals::youngerShadowRoot(Node* shadow, ExceptionState& es)
642{
643    if (!shadow || !shadow->isShadowRoot()) {
644        es.throwDOMException(InvalidAccessError);
645        return 0;
646    }
647
648    return toShadowRoot(shadow)->youngerShadowRoot();
649}
650
651ShadowRoot* Internals::olderShadowRoot(Node* shadow, ExceptionState& es)
652{
653    if (!shadow || !shadow->isShadowRoot()) {
654        es.throwDOMException(InvalidAccessError);
655        return 0;
656    }
657
658    return toShadowRoot(shadow)->olderShadowRoot();
659}
660
661String Internals::shadowRootType(const Node* root, ExceptionState& es) const
662{
663    if (!root || !root->isShadowRoot()) {
664        es.throwDOMException(InvalidAccessError);
665        return String();
666    }
667
668    switch (toShadowRoot(root)->type()) {
669    case ShadowRoot::UserAgentShadowRoot:
670        return String("UserAgentShadowRoot");
671    case ShadowRoot::AuthorShadowRoot:
672        return String("AuthorShadowRoot");
673    default:
674        ASSERT_NOT_REACHED();
675        return String("Unknown");
676    }
677}
678
679Element* Internals::includerFor(Node* node, ExceptionState& es)
680{
681    if (!node) {
682        es.throwDOMException(InvalidAccessError);
683        return 0;
684    }
685
686    NodeRenderingTraversal::ParentDetails parentDetails;
687    NodeRenderingTraversal::parent(node, &parentDetails);
688    return parentDetails.insertionPoint();
689}
690
691String Internals::shadowPseudoId(Element* element, ExceptionState& es)
692{
693    if (!element) {
694        es.throwDOMException(InvalidAccessError);
695        return String();
696    }
697
698    return element->shadowPseudoId().string();
699}
700
701void Internals::setShadowPseudoId(Element* element, const String& id, ExceptionState& es)
702{
703    if (!element) {
704        es.throwDOMException(InvalidAccessError);
705        return;
706    }
707
708    return element->setPart(id);
709}
710
711String Internals::visiblePlaceholder(Element* element)
712{
713    if (element && isHTMLTextFormControlElement(element)) {
714        if (toHTMLTextFormControlElement(element)->placeholderShouldBeVisible())
715            return toHTMLTextFormControlElement(element)->placeholderElement()->textContent();
716    }
717
718    return String();
719}
720
721void Internals::selectColorInColorChooser(Element* element, const String& colorValue)
722{
723    if (!element->hasTagName(inputTag))
724        return;
725    toHTMLInputElement(element)->selectColorInColorChooser(StyleColor(colorValue).color());
726}
727
728Vector<String> Internals::formControlStateOfPreviousHistoryItem(ExceptionState& es)
729{
730    HistoryItem* mainItem = frame()->loader()->history()->previousItem();
731    if (!mainItem) {
732        es.throwDOMException(InvalidAccessError);
733        return Vector<String>();
734    }
735    String uniqueName = frame()->tree()->uniqueName();
736    if (mainItem->target() != uniqueName && !mainItem->childItemWithTarget(uniqueName)) {
737        es.throwDOMException(InvalidAccessError);
738        return Vector<String>();
739    }
740    return mainItem->target() == uniqueName ? mainItem->documentState() : mainItem->childItemWithTarget(uniqueName)->documentState();
741}
742
743void Internals::setFormControlStateOfPreviousHistoryItem(const Vector<String>& state, ExceptionState& es)
744{
745    HistoryItem* mainItem = frame()->loader()->history()->previousItem();
746    if (!mainItem) {
747        es.throwDOMException(InvalidAccessError);
748        return;
749    }
750    String uniqueName = frame()->tree()->uniqueName();
751    if (mainItem->target() == uniqueName)
752        mainItem->setDocumentState(state);
753    else if (HistoryItem* subItem = mainItem->childItemWithTarget(uniqueName))
754        subItem->setDocumentState(state);
755    else
756        es.throwDOMException(InvalidAccessError);
757}
758
759void Internals::enableMockSpeechSynthesizer()
760{
761    Document* document = contextDocument();
762    if (!document || !document->domWindow())
763        return;
764    SpeechSynthesis* synthesis = DOMWindowSpeechSynthesis::speechSynthesis(document->domWindow());
765    if (!synthesis)
766        return;
767
768    synthesis->setPlatformSynthesizer(PlatformSpeechSynthesizerMock::create(synthesis));
769}
770
771void Internals::setEnableMockPagePopup(bool enabled, ExceptionState& es)
772{
773    Document* document = contextDocument();
774    if (!document || !document->page())
775        return;
776    Page* page = document->page();
777    if (!enabled) {
778        page->chrome().client()->resetPagePopupDriver();
779        return;
780    }
781    if (!s_pagePopupDriver)
782        s_pagePopupDriver = MockPagePopupDriver::create(page->mainFrame()).leakPtr();
783    page->chrome().client()->setPagePopupDriver(s_pagePopupDriver);
784}
785
786PassRefPtr<PagePopupController> Internals::pagePopupController()
787{
788    return s_pagePopupDriver ? s_pagePopupDriver->pagePopupController() : 0;
789}
790
791PassRefPtr<ClientRect> Internals::absoluteCaretBounds(ExceptionState& es)
792{
793    Document* document = contextDocument();
794    if (!document || !document->frame() || !document->frame()->selection()) {
795        es.throwDOMException(InvalidAccessError);
796        return ClientRect::create();
797    }
798
799    return ClientRect::create(document->frame()->selection()->absoluteCaretBounds());
800}
801
802PassRefPtr<ClientRect> Internals::boundingBox(Element* element, ExceptionState& es)
803{
804    if (!element) {
805        es.throwDOMException(InvalidAccessError);
806        return ClientRect::create();
807    }
808
809    element->document()->updateLayoutIgnorePendingStylesheets();
810    RenderObject* renderer = element->renderer();
811    if (!renderer)
812        return ClientRect::create();
813    return ClientRect::create(renderer->absoluteBoundingBoxRectIgnoringTransforms());
814}
815
816PassRefPtr<ClientRectList> Internals::inspectorHighlightRects(Document* document, ExceptionState& es)
817{
818    if (!document || !document->page() || !document->page()->inspectorController()) {
819        es.throwDOMException(InvalidAccessError);
820        return ClientRectList::create();
821    }
822
823    Highlight highlight;
824    document->page()->inspectorController()->getHighlight(&highlight);
825    return ClientRectList::create(highlight.quads);
826}
827
828unsigned Internals::markerCountForNode(Node* node, const String& markerType, ExceptionState& es)
829{
830    if (!node) {
831        es.throwDOMException(InvalidAccessError);
832        return 0;
833    }
834
835    DocumentMarker::MarkerTypes markerTypes = 0;
836    if (!markerTypesFrom(markerType, markerTypes)) {
837        es.throwDOMException(SyntaxError);
838        return 0;
839    }
840
841    return node->document()->markers()->markersFor(node, markerTypes).size();
842}
843
844DocumentMarker* Internals::markerAt(Node* node, const String& markerType, unsigned index, ExceptionState& es)
845{
846    if (!node) {
847        es.throwDOMException(InvalidAccessError);
848        return 0;
849    }
850
851    DocumentMarker::MarkerTypes markerTypes = 0;
852    if (!markerTypesFrom(markerType, markerTypes)) {
853        es.throwDOMException(SyntaxError);
854        return 0;
855    }
856
857    Vector<DocumentMarker*> markers = node->document()->markers()->markersFor(node, markerTypes);
858    if (markers.size() <= index)
859        return 0;
860    return markers[index];
861}
862
863PassRefPtr<Range> Internals::markerRangeForNode(Node* node, const String& markerType, unsigned index, ExceptionState& es)
864{
865    DocumentMarker* marker = markerAt(node, markerType, index, es);
866    if (!marker)
867        return 0;
868    return Range::create(node->document(), node, marker->startOffset(), node, marker->endOffset());
869}
870
871String Internals::markerDescriptionForNode(Node* node, const String& markerType, unsigned index, ExceptionState& es)
872{
873    DocumentMarker* marker = markerAt(node, markerType, index, es);
874    if (!marker)
875        return String();
876    return marker->description();
877}
878
879void Internals::addTextMatchMarker(const Range* range, bool isActive)
880{
881    range->ownerDocument()->updateLayoutIgnorePendingStylesheets();
882    range->ownerDocument()->markers()->addTextMatchMarker(range, isActive);
883}
884
885void Internals::setScrollViewPosition(Document* document, long x, long y, ExceptionState& es)
886{
887    if (!document || !document->view()) {
888        es.throwDOMException(InvalidAccessError);
889        return;
890    }
891
892    FrameView* frameView = document->view();
893    bool constrainsScrollingToContentEdgeOldValue = frameView->constrainsScrollingToContentEdge();
894    bool scrollbarsSuppressedOldValue = frameView->scrollbarsSuppressed();
895
896    frameView->setConstrainsScrollingToContentEdge(false);
897    frameView->setScrollbarsSuppressed(false);
898    frameView->setScrollOffsetFromInternals(IntPoint(x, y));
899    frameView->setScrollbarsSuppressed(scrollbarsSuppressedOldValue);
900    frameView->setConstrainsScrollingToContentEdge(constrainsScrollingToContentEdgeOldValue);
901}
902
903void Internals::setPagination(Document* document, const String& mode, int gap, int pageLength, ExceptionState& es)
904{
905    if (!document || !document->page()) {
906        es.throwDOMException(InvalidAccessError);
907        return;
908    }
909    Page* page = document->page();
910
911    Pagination pagination;
912    if (mode == "Unpaginated")
913        pagination.mode = Pagination::Unpaginated;
914    else if (mode == "LeftToRightPaginated")
915        pagination.mode = Pagination::LeftToRightPaginated;
916    else if (mode == "RightToLeftPaginated")
917        pagination.mode = Pagination::RightToLeftPaginated;
918    else if (mode == "TopToBottomPaginated")
919        pagination.mode = Pagination::TopToBottomPaginated;
920    else if (mode == "BottomToTopPaginated")
921        pagination.mode = Pagination::BottomToTopPaginated;
922    else {
923        es.throwDOMException(SyntaxError);
924        return;
925    }
926
927    pagination.gap = gap;
928    pagination.pageLength = pageLength;
929    page->setPagination(pagination);
930}
931
932String Internals::configurationForViewport(Document* document, float, int deviceWidth, int deviceHeight, int availableWidth, int availableHeight, ExceptionState& es)
933{
934    if (!document || !document->page()) {
935        es.throwDOMException(InvalidAccessError);
936        return String();
937    }
938    Page* page = document->page();
939
940    // Update initial viewport size.
941    IntSize initialViewportSize(availableWidth, availableHeight);
942    document->page()->mainFrame()->view()->setFrameRect(IntRect(IntPoint::zero(), initialViewportSize));
943    document->styleResolver()->viewportStyleResolver()->resolve();
944
945    ViewportArguments arguments = page->viewportArguments();
946    PageScaleConstraints constraints = arguments.resolve(initialViewportSize, FloatSize(deviceWidth, deviceHeight), 980 /* defaultLayoutWidthForNonMobilePages */);
947
948    constraints.fitToContentsWidth(constraints.layoutSize.width(), availableWidth);
949
950    StringBuilder builder;
951
952    builder.appendLiteral("viewport size ");
953    builder.append(String::number(constraints.layoutSize.width()));
954    builder.append('x');
955    builder.append(String::number(constraints.layoutSize.height()));
956
957    builder.appendLiteral(" scale ");
958    builder.append(String::number(constraints.initialScale));
959    builder.appendLiteral(" with limits [");
960    builder.append(String::number(constraints.minimumScale));
961    builder.appendLiteral(", ");
962    builder.append(String::number(constraints.maximumScale));
963
964    builder.appendLiteral("] and userScalable ");
965    builder.append(arguments.userZoom ? "true" : "false");
966
967    return builder.toString();
968}
969
970bool Internals::wasLastChangeUserEdit(Element* textField, ExceptionState& es)
971{
972    if (!textField) {
973        es.throwDOMException(InvalidAccessError);
974        return false;
975    }
976
977    if (textField->hasTagName(inputTag))
978        return toHTMLInputElement(textField)->lastChangeWasUserEdit();
979
980    // FIXME: We should be using hasTagName instead but Windows port doesn't link QualifiedNames properly.
981    if (textField->tagName() == "TEXTAREA")
982        return toHTMLTextAreaElement(textField)->lastChangeWasUserEdit();
983
984    es.throwDOMException(InvalidNodeTypeError);
985    return false;
986}
987
988bool Internals::elementShouldAutoComplete(Element* element, ExceptionState& es)
989{
990    if (!element) {
991        es.throwDOMException(InvalidAccessError);
992        return false;
993    }
994
995    if (element->hasTagName(inputTag))
996        return toHTMLInputElement(element)->shouldAutocomplete();
997
998    es.throwDOMException(InvalidNodeTypeError);
999    return false;
1000}
1001
1002String Internals::suggestedValue(Element* element, ExceptionState& es)
1003{
1004    if (!element) {
1005        es.throwDOMException(InvalidAccessError);
1006        return String();
1007    }
1008
1009    if (!element->hasTagName(inputTag)) {
1010        es.throwDOMException(InvalidNodeTypeError);
1011        return String();
1012    }
1013
1014    return toHTMLInputElement(element)->suggestedValue();
1015}
1016
1017void Internals::setSuggestedValue(Element* element, const String& value, ExceptionState& es)
1018{
1019    if (!element) {
1020        es.throwDOMException(InvalidAccessError);
1021        return;
1022    }
1023
1024    if (!element->hasTagName(inputTag)) {
1025        es.throwDOMException(InvalidNodeTypeError);
1026        return;
1027    }
1028
1029    toHTMLInputElement(element)->setSuggestedValue(value);
1030}
1031
1032void Internals::setEditingValue(Element* element, const String& value, ExceptionState& es)
1033{
1034    if (!element) {
1035        es.throwDOMException(InvalidAccessError);
1036        return;
1037    }
1038
1039    if (!element->hasTagName(inputTag)) {
1040        es.throwDOMException(InvalidNodeTypeError);
1041        return;
1042    }
1043
1044    toHTMLInputElement(element)->setEditingValue(value);
1045}
1046
1047void Internals::setAutofilled(Element* element, bool enabled, ExceptionState& es)
1048{
1049    if (!element->hasTagName(inputTag)) {
1050        es.throwDOMException(InvalidAccessError);
1051        return;
1052    }
1053    toHTMLInputElement(element)->setAutofilled(enabled);
1054}
1055
1056void Internals::scrollElementToRect(Element* element, long x, long y, long w, long h, ExceptionState& es)
1057{
1058    if (!element || !element->document() || !element->document()->view()) {
1059        es.throwDOMException(InvalidAccessError);
1060        return;
1061    }
1062    FrameView* frameView = element->document()->view();
1063    frameView->scrollElementToRect(element, IntRect(x, y, w, h));
1064}
1065
1066void Internals::paintControlTints(Document* document, ExceptionState& es)
1067{
1068    if (!document || !document->view()) {
1069        es.throwDOMException(InvalidAccessError);
1070        return;
1071    }
1072
1073    FrameView* frameView = document->view();
1074    frameView->paintControlTints();
1075}
1076
1077PassRefPtr<Range> Internals::rangeFromLocationAndLength(Element* scope, int rangeLocation, int rangeLength, ExceptionState& es)
1078{
1079    if (!scope) {
1080        es.throwDOMException(InvalidAccessError);
1081        return 0;
1082    }
1083
1084    return TextIterator::rangeFromLocationAndLength(scope, rangeLocation, rangeLength);
1085}
1086
1087unsigned Internals::locationFromRange(Element* scope, const Range* range, ExceptionState& es)
1088{
1089    if (!scope || !range) {
1090        es.throwDOMException(InvalidAccessError);
1091        return 0;
1092    }
1093
1094    size_t location = 0;
1095    size_t unusedLength = 0;
1096    TextIterator::getLocationAndLengthFromRange(scope, range, location, unusedLength);
1097    return location;
1098}
1099
1100unsigned Internals::lengthFromRange(Element* scope, const Range* range, ExceptionState& es)
1101{
1102    if (!scope || !range) {
1103        es.throwDOMException(InvalidAccessError);
1104        return 0;
1105    }
1106
1107    size_t unusedLocation = 0;
1108    size_t length = 0;
1109    TextIterator::getLocationAndLengthFromRange(scope, range, unusedLocation, length);
1110    return length;
1111}
1112
1113String Internals::rangeAsText(const Range* range, ExceptionState& es)
1114{
1115    if (!range) {
1116        es.throwDOMException(InvalidAccessError);
1117        return String();
1118    }
1119
1120    return range->text();
1121}
1122
1123PassRefPtr<DOMPoint> Internals::touchPositionAdjustedToBestClickableNode(long x, long y, long width, long height, Document* document, ExceptionState& es)
1124{
1125    if (!document || !document->frame()) {
1126        es.throwDOMException(InvalidAccessError);
1127        return 0;
1128    }
1129
1130    document->updateLayout();
1131
1132    IntSize radius(width / 2, height / 2);
1133    IntPoint point(x + radius.width(), y + radius.height());
1134
1135    Node* targetNode;
1136    IntPoint adjustedPoint;
1137
1138    bool foundNode = document->frame()->eventHandler()->bestClickableNodeForTouchPoint(point, radius, adjustedPoint, targetNode);
1139    if (foundNode)
1140        return DOMPoint::create(adjustedPoint.x(), adjustedPoint.y());
1141
1142    return 0;
1143}
1144
1145Node* Internals::touchNodeAdjustedToBestClickableNode(long x, long y, long width, long height, Document* document, ExceptionState& es)
1146{
1147    if (!document || !document->frame()) {
1148        es.throwDOMException(InvalidAccessError);
1149        return 0;
1150    }
1151
1152    document->updateLayout();
1153
1154    IntSize radius(width / 2, height / 2);
1155    IntPoint point(x + radius.width(), y + radius.height());
1156
1157    Node* targetNode;
1158    IntPoint adjustedPoint;
1159    document->frame()->eventHandler()->bestClickableNodeForTouchPoint(point, radius, adjustedPoint, targetNode);
1160    return targetNode;
1161}
1162
1163PassRefPtr<DOMPoint> Internals::touchPositionAdjustedToBestContextMenuNode(long x, long y, long width, long height, Document* document, ExceptionState& es)
1164{
1165    if (!document || !document->frame()) {
1166        es.throwDOMException(InvalidAccessError);
1167        return 0;
1168    }
1169
1170    document->updateLayout();
1171
1172    IntSize radius(width / 2, height / 2);
1173    IntPoint point(x + radius.width(), y + radius.height());
1174
1175    Node* targetNode = 0;
1176    IntPoint adjustedPoint;
1177
1178    bool foundNode = document->frame()->eventHandler()->bestContextMenuNodeForTouchPoint(point, radius, adjustedPoint, targetNode);
1179    if (foundNode)
1180        return DOMPoint::create(adjustedPoint.x(), adjustedPoint.y());
1181
1182    return DOMPoint::create(x, y);
1183}
1184
1185Node* Internals::touchNodeAdjustedToBestContextMenuNode(long x, long y, long width, long height, Document* document, ExceptionState& es)
1186{
1187    if (!document || !document->frame()) {
1188        es.throwDOMException(InvalidAccessError);
1189        return 0;
1190    }
1191
1192    document->updateLayout();
1193
1194    IntSize radius(width / 2, height / 2);
1195    IntPoint point(x + radius.width(), y + radius.height());
1196
1197    Node* targetNode = 0;
1198    IntPoint adjustedPoint;
1199    document->frame()->eventHandler()->bestContextMenuNodeForTouchPoint(point, radius, adjustedPoint, targetNode);
1200    return targetNode;
1201}
1202
1203PassRefPtr<ClientRect> Internals::bestZoomableAreaForTouchPoint(long x, long y, long width, long height, Document* document, ExceptionState& es)
1204{
1205    if (!document || !document->frame()) {
1206        es.throwDOMException(InvalidAccessError);
1207        return 0;
1208    }
1209
1210    document->updateLayout();
1211
1212    IntSize radius(width / 2, height / 2);
1213    IntPoint point(x + radius.width(), y + radius.height());
1214
1215    Node* targetNode;
1216    IntRect zoomableArea;
1217    bool foundNode = document->frame()->eventHandler()->bestZoomableAreaForTouchPoint(point, radius, zoomableArea, targetNode);
1218    if (foundNode)
1219        return ClientRect::create(zoomableArea);
1220
1221    return 0;
1222}
1223
1224
1225int Internals::lastSpellCheckRequestSequence(Document* document, ExceptionState& es)
1226{
1227    SpellChecker* checker = spellchecker(document);
1228
1229    if (!checker) {
1230        es.throwDOMException(InvalidAccessError);
1231        return -1;
1232    }
1233
1234    return checker->lastRequestSequence();
1235}
1236
1237int Internals::lastSpellCheckProcessedSequence(Document* document, ExceptionState& es)
1238{
1239    SpellChecker* checker = spellchecker(document);
1240
1241    if (!checker) {
1242        es.throwDOMException(InvalidAccessError);
1243        return -1;
1244    }
1245
1246    return checker->lastProcessedSequence();
1247}
1248
1249Vector<String> Internals::userPreferredLanguages() const
1250{
1251    return WebCore::userPreferredLanguages();
1252}
1253
1254void Internals::setUserPreferredLanguages(const Vector<String>& languages)
1255{
1256    WebCore::overrideUserPreferredLanguages(languages);
1257}
1258
1259unsigned Internals::wheelEventHandlerCount(Document* document, ExceptionState& es)
1260{
1261    if (!document) {
1262        es.throwDOMException(InvalidAccessError);
1263        return 0;
1264    }
1265
1266    return document->wheelEventHandlerCount();
1267}
1268
1269unsigned Internals::touchEventHandlerCount(Document* document, ExceptionState& es)
1270{
1271    if (!document) {
1272        es.throwDOMException(InvalidAccessError);
1273        return 0;
1274    }
1275
1276    const TouchEventTargetSet* touchHandlers = document->touchEventTargets();
1277    if (!touchHandlers)
1278        return 0;
1279
1280    unsigned count = 0;
1281    for (TouchEventTargetSet::const_iterator iter = touchHandlers->begin(); iter != touchHandlers->end(); ++iter)
1282        count += iter->value;
1283    return count;
1284}
1285
1286LayerRectList* Internals::touchEventTargetLayerRects(Document* document, ExceptionState& es)
1287{
1288    if (!document || !document->view() || !document->page() || document != contextDocument()) {
1289        es.throwDOMException(InvalidAccessError);
1290        return 0;
1291    }
1292
1293    // Do any pending layouts (which may call touchEventTargetRectsChange) to ensure this
1294    // really takes any previous changes into account.
1295    document->updateLayout();
1296    return m_currentTouchEventRects.get();
1297}
1298
1299unsigned Internals::touchEventTargetLayerRectsUpdateCount(Document* document, ExceptionState& es)
1300{
1301    if (!document || !document->view() || !document->page() || document != contextDocument()) {
1302        es.throwDOMException(InvalidAccessError);
1303        return 0;
1304    }
1305
1306    // Do any pending layouts to ensure this really takes any previous changes into account.
1307    document->updateLayout();
1308
1309    return m_touchEventTargetRectUpdateCount;
1310}
1311
1312void Internals::touchEventTargetRectsChanged(const LayerHitTestRects& rects)
1313{
1314    // When profiling content_shell, it can be handy to exclude this time (since it's only
1315    // present for testing / debugging).
1316    TRACE_EVENT0("input", "Internals::touchEventTargetRectsChanged");
1317
1318    m_touchEventTargetRectUpdateCount++;
1319
1320    // Since it's not safe to hang onto the pointers in a LayerHitTestRects, we immediately
1321    // copy into a LayerRectList.
1322    m_currentTouchEventRects = LayerRectList::create();
1323    for (LayerHitTestRects::const_iterator iter = rects.begin(); iter != rects.end(); ++iter) {
1324        for (size_t i = 0; i < iter->value.size(); ++i) {
1325            m_currentTouchEventRects->append(iter->key->renderer()->node(), ClientRect::create(enclosingIntRect(iter->value[i])));
1326        }
1327    }
1328}
1329
1330PassRefPtr<NodeList> Internals::nodesFromRect(Document* document, int centerX, int centerY, unsigned topPadding, unsigned rightPadding,
1331    unsigned bottomPadding, unsigned leftPadding, bool ignoreClipping, bool allowShadowContent, bool allowChildFrameContent, ExceptionState& es) const
1332{
1333    if (!document || !document->frame() || !document->frame()->view()) {
1334        es.throwDOMException(InvalidAccessError);
1335        return 0;
1336    }
1337
1338    Frame* frame = document->frame();
1339    FrameView* frameView = document->view();
1340    RenderView* renderView = document->renderView();
1341
1342    if (!renderView)
1343        return 0;
1344
1345    float zoomFactor = frame->pageZoomFactor();
1346    LayoutPoint point = roundedLayoutPoint(FloatPoint(centerX * zoomFactor + frameView->scrollX(), centerY * zoomFactor + frameView->scrollY()));
1347
1348    HitTestRequest::HitTestRequestType hitType = HitTestRequest::ReadOnly | HitTestRequest::Active;
1349    if (ignoreClipping)
1350        hitType |= HitTestRequest::IgnoreClipping;
1351    if (!allowShadowContent)
1352        hitType |= HitTestRequest::DisallowShadowContent;
1353    if (allowChildFrameContent)
1354        hitType |= HitTestRequest::AllowChildFrameContent;
1355
1356    HitTestRequest request(hitType);
1357
1358    // When ignoreClipping is false, this method returns null for coordinates outside of the viewport.
1359    if (!request.ignoreClipping() && !frameView->visibleContentRect().intersects(HitTestLocation::rectForPoint(point, topPadding, rightPadding, bottomPadding, leftPadding)))
1360        return 0;
1361
1362    Vector<RefPtr<Node> > matches;
1363
1364    // Need padding to trigger a rect based hit test, but we want to return a NodeList
1365    // so we special case this.
1366    if (!topPadding && !rightPadding && !bottomPadding && !leftPadding) {
1367        HitTestResult result(point);
1368        renderView->hitTest(request, result);
1369        if (result.innerNode())
1370            matches.append(result.innerNode()->deprecatedShadowAncestorNode());
1371    } else {
1372        HitTestResult result(point, topPadding, rightPadding, bottomPadding, leftPadding);
1373        renderView->hitTest(request, result);
1374        copyToVector(result.rectBasedTestResult(), matches);
1375    }
1376
1377    return StaticNodeList::adopt(matches);
1378}
1379
1380void Internals::emitInspectorDidBeginFrame()
1381{
1382    InspectorController* inspectorController = contextDocument()->frame()->page()->inspectorController();
1383    inspectorController->didBeginFrame();
1384}
1385
1386void Internals::emitInspectorDidCancelFrame()
1387{
1388    InspectorController* inspectorController = contextDocument()->frame()->page()->inspectorController();
1389    inspectorController->didCancelFrame();
1390}
1391
1392bool Internals::hasSpellingMarker(Document* document, int from, int length, ExceptionState&)
1393{
1394    if (!document || !document->frame())
1395        return 0;
1396
1397    return document->frame()->editor()->selectionStartHasMarkerFor(DocumentMarker::Spelling, from, length);
1398}
1399
1400void Internals::setContinuousSpellCheckingEnabled(bool enabled, ExceptionState&)
1401{
1402    if (!contextDocument() || !contextDocument()->frame() || !contextDocument()->frame()->editor())
1403        return;
1404
1405    if (enabled != contextDocument()->frame()->editor()->isContinuousSpellCheckingEnabled())
1406        contextDocument()->frame()->editor()->toggleContinuousSpellChecking();
1407}
1408
1409bool Internals::isOverwriteModeEnabled(Document* document, ExceptionState&)
1410{
1411    if (!document || !document->frame())
1412        return 0;
1413
1414    return document->frame()->editor()->isOverwriteModeEnabled();
1415}
1416
1417void Internals::toggleOverwriteModeEnabled(Document* document, ExceptionState&)
1418{
1419    if (!document || !document->frame())
1420        return;
1421
1422    document->frame()->editor()->toggleOverwriteModeEnabled();
1423}
1424
1425unsigned Internals::numberOfLiveNodes() const
1426{
1427    return InspectorCounters::counterValue(InspectorCounters::NodeCounter);
1428}
1429
1430unsigned Internals::numberOfLiveDocuments() const
1431{
1432    return InspectorCounters::counterValue(InspectorCounters::DocumentCounter);
1433}
1434
1435Vector<String> Internals::consoleMessageArgumentCounts(Document* document) const
1436{
1437    InstrumentingAgents* instrumentingAgents = instrumentationForPage(document->page());
1438    if (!instrumentingAgents)
1439        return Vector<String>();
1440    InspectorConsoleAgent* consoleAgent = instrumentingAgents->inspectorConsoleAgent();
1441    if (!consoleAgent)
1442        return Vector<String>();
1443    Vector<unsigned> counts = consoleAgent->consoleMessageArgumentCounts();
1444    Vector<String> result(counts.size());
1445    for (size_t i = 0; i < counts.size(); i++)
1446        result[i] = String::number(counts[i]);
1447    return result;
1448}
1449
1450PassRefPtr<DOMWindow> Internals::openDummyInspectorFrontend(const String& url)
1451{
1452    Page* page = contextDocument()->frame()->page();
1453    ASSERT(page);
1454
1455    DOMWindow* window = page->mainFrame()->domWindow();
1456    ASSERT(window);
1457
1458    m_frontendWindow = window->open(url, "", "", window, window);
1459    ASSERT(m_frontendWindow);
1460
1461    Page* frontendPage = m_frontendWindow->document()->page();
1462    ASSERT(frontendPage);
1463
1464    OwnPtr<InspectorFrontendClientLocal> frontendClient = adoptPtr(new InspectorFrontendClientLocal(page->inspectorController(), frontendPage));
1465
1466    frontendPage->inspectorController()->setInspectorFrontendClient(frontendClient.release());
1467
1468    m_frontendChannel = adoptPtr(new InspectorFrontendChannelDummy(frontendPage));
1469
1470    page->inspectorController()->connectFrontend(m_frontendChannel.get());
1471
1472    return m_frontendWindow;
1473}
1474
1475void Internals::closeDummyInspectorFrontend()
1476{
1477    Page* page = contextDocument()->frame()->page();
1478    ASSERT(page);
1479    ASSERT(m_frontendWindow);
1480
1481    page->inspectorController()->disconnectFrontend();
1482
1483    m_frontendChannel.release();
1484
1485    m_frontendWindow->close(m_frontendWindow->scriptExecutionContext());
1486    m_frontendWindow.release();
1487}
1488
1489Vector<unsigned long> Internals::setMemoryCacheCapacities(unsigned long minDeadBytes, unsigned long maxDeadBytes, unsigned long totalBytes)
1490{
1491    Vector<unsigned long> result;
1492    result.append(memoryCache()->minDeadCapacity());
1493    result.append(memoryCache()->maxDeadCapacity());
1494    result.append(memoryCache()->capacity());
1495    memoryCache()->setCapacities(minDeadBytes, maxDeadBytes, totalBytes);
1496    return result;
1497}
1498
1499void Internals::setInspectorResourcesDataSizeLimits(int maximumResourcesContentSize, int maximumSingleResourceContentSize, ExceptionState& es)
1500{
1501    Page* page = contextDocument()->frame()->page();
1502    if (!page || !page->inspectorController()) {
1503        es.throwDOMException(InvalidAccessError);
1504        return;
1505    }
1506    page->inspectorController()->setResourcesDataSizeLimitsFromInternals(maximumResourcesContentSize, maximumSingleResourceContentSize);
1507}
1508
1509bool Internals::hasGrammarMarker(Document* document, int from, int length, ExceptionState&)
1510{
1511    if (!document || !document->frame())
1512        return 0;
1513
1514    return document->frame()->editor()->selectionStartHasMarkerFor(DocumentMarker::Grammar, from, length);
1515}
1516
1517unsigned Internals::numberOfScrollableAreas(Document* document, ExceptionState&)
1518{
1519    unsigned count = 0;
1520    Frame* frame = document->frame();
1521    if (frame->view()->scrollableAreas())
1522        count += frame->view()->scrollableAreas()->size();
1523
1524    for (Frame* child = frame->tree()->firstChild(); child; child = child->tree()->nextSibling()) {
1525        if (child->view() && child->view()->scrollableAreas())
1526            count += child->view()->scrollableAreas()->size();
1527    }
1528
1529    return count;
1530}
1531
1532bool Internals::isPageBoxVisible(Document* document, int pageNumber, ExceptionState& es)
1533{
1534    if (!document) {
1535        es.throwDOMException(InvalidAccessError);
1536        return false;
1537    }
1538
1539    return document->isPageBoxVisible(pageNumber);
1540}
1541
1542String Internals::layerTreeAsText(Document* document, ExceptionState& es) const
1543{
1544    return layerTreeAsText(document, 0, es);
1545}
1546
1547String Internals::elementLayerTreeAsText(Element* element, ExceptionState& es) const
1548{
1549    return elementLayerTreeAsText(element, 0, es);
1550}
1551
1552static PassRefPtr<NodeList> paintOrderList(Element* element, ExceptionState& es, RenderLayer::PaintOrderListType type)
1553{
1554    if (!element) {
1555        es.throwDOMException(InvalidAccessError);
1556        return 0;
1557    }
1558
1559    element->document()->updateLayout();
1560
1561    RenderObject* renderer = element->renderer();
1562    if (!renderer || !renderer->isBox()) {
1563        es.throwDOMException(InvalidAccessError);
1564        return 0;
1565    }
1566
1567    RenderLayer* layer = toRenderBox(renderer)->layer();
1568    if (!layer) {
1569        es.throwDOMException(InvalidAccessError);
1570        return 0;
1571    }
1572
1573    Vector<RefPtr<Node> > nodes;
1574    layer->computePaintOrderList(type, nodes);
1575    return StaticNodeList::adopt(nodes);
1576}
1577
1578PassRefPtr<NodeList> Internals::paintOrderListBeforePromote(Element* element, ExceptionState& es)
1579{
1580    return paintOrderList(element, es, RenderLayer::BeforePromote);
1581}
1582
1583PassRefPtr<NodeList> Internals::paintOrderListAfterPromote(Element* element, ExceptionState& es)
1584{
1585    return paintOrderList(element, es, RenderLayer::AfterPromote);
1586}
1587
1588String Internals::layerTreeAsText(Document* document, unsigned flags, ExceptionState& es) const
1589{
1590    if (!document || !document->frame()) {
1591        es.throwDOMException(InvalidAccessError);
1592        return String();
1593    }
1594
1595    return document->frame()->layerTreeAsText(flags);
1596}
1597
1598String Internals::elementLayerTreeAsText(Element* element, unsigned flags, ExceptionState& es) const
1599{
1600    if (!element) {
1601        es.throwDOMException(InvalidAccessError);
1602        return String();
1603    }
1604
1605    element->document()->updateLayout();
1606
1607    RenderObject* renderer = element->renderer();
1608    if (!renderer || !renderer->isBox()) {
1609        es.throwDOMException(InvalidAccessError);
1610        return String();
1611    }
1612
1613    RenderLayer* layer = toRenderBox(renderer)->layer();
1614    if (!layer
1615        || !layer->backing()
1616        || !layer->backing()->graphicsLayer()) {
1617        // Don't raise exception in these cases which may be normally used in tests.
1618        return String();
1619    }
1620
1621    return layer->backing()->graphicsLayer()->layerTreeAsText(flags);
1622}
1623
1624void Internals::setNeedsCompositedScrolling(Element* element, unsigned needsCompositedScrolling, ExceptionState& es)
1625{
1626    if (!element) {
1627        es.throwDOMException(InvalidAccessError);
1628        return;
1629    }
1630
1631    element->document()->updateLayout();
1632
1633    RenderObject* renderer = element->renderer();
1634    if (!renderer || !renderer->isBox()) {
1635        es.throwDOMException(InvalidAccessError);
1636        return;
1637    }
1638
1639    RenderLayer* layer = toRenderBox(renderer)->layer();
1640    if (!layer) {
1641        es.throwDOMException(InvalidAccessError);
1642        return;
1643    }
1644
1645    layer->setForceNeedsCompositedScrolling(static_cast<RenderLayer::ForceNeedsCompositedScrollingMode>(needsCompositedScrolling));
1646}
1647
1648String Internals::repaintRectsAsText(Document* document, ExceptionState& es) const
1649{
1650    if (!document || !document->frame()) {
1651        es.throwDOMException(InvalidAccessError);
1652        return String();
1653    }
1654
1655    return document->frame()->trackedRepaintRectsAsText();
1656}
1657
1658String Internals::scrollingStateTreeAsText(Document* document, ExceptionState& es) const
1659{
1660    return String();
1661}
1662
1663String Internals::mainThreadScrollingReasons(Document* document, ExceptionState& es) const
1664{
1665    if (!document || !document->frame()) {
1666        es.throwDOMException(InvalidAccessError);
1667        return String();
1668    }
1669
1670    Page* page = document->page();
1671    if (!page)
1672        return String();
1673
1674    return page->mainThreadScrollingReasonsAsText();
1675}
1676
1677PassRefPtr<ClientRectList> Internals::nonFastScrollableRects(Document* document, ExceptionState& es) const
1678{
1679    if (!document || !document->frame()) {
1680        es.throwDOMException(InvalidAccessError);
1681        return 0;
1682    }
1683
1684    Page* page = document->page();
1685    if (!page)
1686        return 0;
1687
1688    return page->nonFastScrollableRects(document->frame());
1689}
1690
1691void Internals::garbageCollectDocumentResources(Document* document, ExceptionState& es) const
1692{
1693    if (!document) {
1694        es.throwDOMException(InvalidAccessError);
1695        return;
1696    }
1697
1698    ResourceFetcher* fetcher = document->fetcher();
1699    if (!fetcher)
1700        return;
1701    fetcher->garbageCollectDocumentResources();
1702}
1703
1704void Internals::evictAllResources() const
1705{
1706    memoryCache()->evictResources();
1707}
1708
1709void Internals::allowRoundingHacks() const
1710{
1711    TextRun::setAllowsRoundingHacks(true);
1712}
1713
1714void Internals::insertAuthorCSS(Document* document, const String& css) const
1715{
1716    RefPtr<StyleSheetContents> parsedSheet = StyleSheetContents::create(document);
1717    parsedSheet->setIsUserStyleSheet(false);
1718    parsedSheet->parseString(css);
1719    document->styleSheetCollection()->addAuthorSheet(parsedSheet);
1720}
1721
1722void Internals::insertUserCSS(Document* document, const String& css) const
1723{
1724    RefPtr<StyleSheetContents> parsedSheet = StyleSheetContents::create(document);
1725    parsedSheet->setIsUserStyleSheet(true);
1726    parsedSheet->parseString(css);
1727    document->styleSheetCollection()->addUserSheet(parsedSheet);
1728}
1729
1730String Internals::counterValue(Element* element)
1731{
1732    if (!element)
1733        return String();
1734
1735    return counterValueForElement(element);
1736}
1737
1738int Internals::pageNumber(Element* element, float pageWidth, float pageHeight)
1739{
1740    if (!element)
1741        return 0;
1742
1743    return PrintContext::pageNumberForElement(element, FloatSize(pageWidth, pageHeight));
1744}
1745
1746Vector<String> Internals::iconURLs(Document* document, int iconTypesMask) const
1747{
1748    Vector<IconURL> iconURLs = document->iconURLs(iconTypesMask);
1749    Vector<String> array;
1750
1751    Vector<IconURL>::const_iterator iter(iconURLs.begin());
1752    for (; iter != iconURLs.end(); ++iter)
1753        array.append(iter->m_iconURL.string());
1754
1755    return array;
1756}
1757
1758Vector<String> Internals::shortcutIconURLs(Document* document) const
1759{
1760    return iconURLs(document, Favicon);
1761}
1762
1763Vector<String> Internals::allIconURLs(Document* document) const
1764{
1765    return iconURLs(document, Favicon | TouchIcon | TouchPrecomposedIcon);
1766}
1767
1768int Internals::numberOfPages(float pageWidth, float pageHeight)
1769{
1770    if (!frame())
1771        return -1;
1772
1773    return PrintContext::numberOfPages(frame(), FloatSize(pageWidth, pageHeight));
1774}
1775
1776String Internals::pageProperty(String propertyName, int pageNumber, ExceptionState& es) const
1777{
1778    if (!frame()) {
1779        es.throwDOMException(InvalidAccessError);
1780        return String();
1781    }
1782
1783    return PrintContext::pageProperty(frame(), propertyName.utf8().data(), pageNumber);
1784}
1785
1786String Internals::pageSizeAndMarginsInPixels(int pageNumber, int width, int height, int marginTop, int marginRight, int marginBottom, int marginLeft, ExceptionState& es) const
1787{
1788    if (!frame()) {
1789        es.throwDOMException(InvalidAccessError);
1790        return String();
1791    }
1792
1793    return PrintContext::pageSizeAndMarginsInPixels(frame(), pageNumber, width, height, marginTop, marginRight, marginBottom, marginLeft);
1794}
1795
1796void Internals::setDeviceScaleFactor(float scaleFactor, ExceptionState& es)
1797{
1798    Document* document = contextDocument();
1799    if (!document || !document->page()) {
1800        es.throwDOMException(InvalidAccessError);
1801        return;
1802    }
1803    Page* page = document->page();
1804    page->setDeviceScaleFactor(scaleFactor);
1805}
1806
1807void Internals::setIsCursorVisible(Document* document, bool isVisible, ExceptionState& es)
1808{
1809    if (!document || !document->page()) {
1810        es.throwDOMException(InvalidAccessError);
1811        return;
1812    }
1813    document->page()->setIsCursorVisible(isVisible);
1814}
1815
1816void Internals::webkitWillEnterFullScreenForElement(Document* document, Element* element)
1817{
1818    if (!document)
1819        return;
1820    FullscreenElementStack::from(document)->webkitWillEnterFullScreenForElement(element);
1821}
1822
1823void Internals::webkitDidEnterFullScreenForElement(Document* document, Element* element)
1824{
1825    if (!document)
1826        return;
1827    FullscreenElementStack::from(document)->webkitDidEnterFullScreenForElement(element);
1828}
1829
1830void Internals::webkitWillExitFullScreenForElement(Document* document, Element* element)
1831{
1832    if (!document)
1833        return;
1834    FullscreenElementStack::from(document)->webkitWillExitFullScreenForElement(element);
1835}
1836
1837void Internals::webkitDidExitFullScreenForElement(Document* document, Element* element)
1838{
1839    if (!document)
1840        return;
1841    FullscreenElementStack::from(document)->webkitDidExitFullScreenForElement(element);
1842}
1843
1844void Internals::registerURLSchemeAsBypassingContentSecurityPolicy(const String& scheme)
1845{
1846    SchemeRegistry::registerURLSchemeAsBypassingContentSecurityPolicy(scheme);
1847}
1848
1849void Internals::removeURLSchemeRegisteredAsBypassingContentSecurityPolicy(const String& scheme)
1850{
1851    SchemeRegistry::removeURLSchemeRegisteredAsBypassingContentSecurityPolicy(scheme);
1852}
1853
1854PassRefPtr<MallocStatistics> Internals::mallocStatistics() const
1855{
1856    return MallocStatistics::create();
1857}
1858
1859PassRefPtr<TypeConversions> Internals::typeConversions() const
1860{
1861    return TypeConversions::create();
1862}
1863
1864Vector<String> Internals::getReferencedFilePaths() const
1865{
1866    frame()->loader()->history()->saveDocumentAndScrollState();
1867    return FormController::getReferencedFilePaths(frame()->loader()->history()->currentItem()->documentState());
1868}
1869
1870void Internals::startTrackingRepaints(Document* document, ExceptionState& es)
1871{
1872    if (!document || !document->view()) {
1873        es.throwDOMException(InvalidAccessError);
1874        return;
1875    }
1876
1877    FrameView* frameView = document->view();
1878    frameView->setTracksRepaints(true);
1879}
1880
1881void Internals::stopTrackingRepaints(Document* document, ExceptionState& es)
1882{
1883    if (!document || !document->view()) {
1884        es.throwDOMException(InvalidAccessError);
1885        return;
1886    }
1887
1888    FrameView* frameView = document->view();
1889    frameView->setTracksRepaints(false);
1890}
1891
1892static const char* cursorTypeToString(Cursor::Type cursorType)
1893{
1894    switch (cursorType) {
1895    case Cursor::Pointer: return "Pointer";
1896    case Cursor::Cross: return "Cross";
1897    case Cursor::Hand: return "Hand";
1898    case Cursor::IBeam: return "IBeam";
1899    case Cursor::Wait: return "Wait";
1900    case Cursor::Help: return "Help";
1901    case Cursor::EastResize: return "EastResize";
1902    case Cursor::NorthResize: return "NorthResize";
1903    case Cursor::NorthEastResize: return "NorthEastResize";
1904    case Cursor::NorthWestResize: return "NorthWestResize";
1905    case Cursor::SouthResize: return "SouthResize";
1906    case Cursor::SouthEastResize: return "SouthEastResize";
1907    case Cursor::SouthWestResize: return "SouthWestResize";
1908    case Cursor::WestResize: return "WestResize";
1909    case Cursor::NorthSouthResize: return "NorthSouthResize";
1910    case Cursor::EastWestResize: return "EastWestResize";
1911    case Cursor::NorthEastSouthWestResize: return "NorthEastSouthWestResize";
1912    case Cursor::NorthWestSouthEastResize: return "NorthWestSouthEastResize";
1913    case Cursor::ColumnResize: return "ColumnResize";
1914    case Cursor::RowResize: return "RowResize";
1915    case Cursor::MiddlePanning: return "MiddlePanning";
1916    case Cursor::EastPanning: return "EastPanning";
1917    case Cursor::NorthPanning: return "NorthPanning";
1918    case Cursor::NorthEastPanning: return "NorthEastPanning";
1919    case Cursor::NorthWestPanning: return "NorthWestPanning";
1920    case Cursor::SouthPanning: return "SouthPanning";
1921    case Cursor::SouthEastPanning: return "SouthEastPanning";
1922    case Cursor::SouthWestPanning: return "SouthWestPanning";
1923    case Cursor::WestPanning: return "WestPanning";
1924    case Cursor::Move: return "Move";
1925    case Cursor::VerticalText: return "VerticalText";
1926    case Cursor::Cell: return "Cell";
1927    case Cursor::ContextMenu: return "ContextMenu";
1928    case Cursor::Alias: return "Alias";
1929    case Cursor::Progress: return "Progress";
1930    case Cursor::NoDrop: return "NoDrop";
1931    case Cursor::Copy: return "Copy";
1932    case Cursor::None: return "None";
1933    case Cursor::NotAllowed: return "NotAllowed";
1934    case Cursor::ZoomIn: return "ZoomIn";
1935    case Cursor::ZoomOut: return "ZoomOut";
1936    case Cursor::Grab: return "Grab";
1937    case Cursor::Grabbing: return "Grabbing";
1938    case Cursor::Custom: return "Custom";
1939    }
1940
1941    ASSERT_NOT_REACHED();
1942    return "UNKNOWN";
1943}
1944
1945String Internals::getCurrentCursorInfo(Document* document, ExceptionState& es)
1946{
1947    if (!document || !document->frame()) {
1948        es.throwDOMException(InvalidAccessError);
1949        return String();
1950    }
1951
1952    Cursor cursor = document->frame()->eventHandler()->currentMouseCursor();
1953
1954    StringBuilder result;
1955    result.append("type=");
1956    result.append(cursorTypeToString(cursor.type()));
1957    result.append(" hotSpot=");
1958    result.appendNumber(cursor.hotSpot().x());
1959    result.append(",");
1960    result.appendNumber(cursor.hotSpot().y());
1961    if (cursor.image()) {
1962        IntSize size = cursor.image()->size();
1963        result.append(" image=");
1964        result.appendNumber(size.width());
1965        result.append("x");
1966        result.appendNumber(size.height());
1967    }
1968    if (cursor.imageScaleFactor() != 1) {
1969        result.append(" scale=");
1970        NumberToStringBuffer buffer;
1971        result.append(numberToFixedPrecisionString(cursor.imageScaleFactor(), 8, buffer, true));
1972    }
1973
1974    return result.toString();
1975}
1976
1977PassRefPtr<ArrayBuffer> Internals::serializeObject(PassRefPtr<SerializedScriptValue> value) const
1978{
1979    String stringValue = value->toWireString();
1980    RefPtr<ArrayBuffer> buffer = ArrayBuffer::createUninitialized(stringValue.length(), sizeof(UChar));
1981    stringValue.copyTo(static_cast<UChar*>(buffer->data()), 0, stringValue.length());
1982    return buffer.release();
1983}
1984
1985PassRefPtr<SerializedScriptValue> Internals::deserializeBuffer(PassRefPtr<ArrayBuffer> buffer) const
1986{
1987    String value(static_cast<const UChar*>(buffer->data()), buffer->byteLength() / sizeof(UChar));
1988    return SerializedScriptValue::createFromWire(value);
1989}
1990
1991void Internals::setUsesOverlayScrollbars(bool enabled)
1992{
1993    WebCore::Settings::setUsesOverlayScrollbars(enabled);
1994}
1995
1996void Internals::forceReload(bool endToEnd)
1997{
1998    frame()->loader()->reload(endToEnd ? EndToEndReload : NormalReload);
1999}
2000
2001PassRefPtr<ClientRect> Internals::selectionBounds(ExceptionState& es)
2002{
2003    Document* document = contextDocument();
2004    if (!document || !document->frame() || !document->frame()->selection()) {
2005        es.throwDOMException(InvalidAccessError);
2006        return 0;
2007    }
2008
2009    return ClientRect::create(document->frame()->selection()->bounds());
2010}
2011
2012String Internals::markerTextForListItem(Element* element, ExceptionState& es)
2013{
2014    if (!element) {
2015        es.throwDOMException(InvalidAccessError);
2016        return String();
2017    }
2018    return WebCore::markerTextForListItem(element);
2019}
2020
2021String Internals::getImageSourceURL(Element* element, ExceptionState& es)
2022{
2023    if (!element) {
2024        es.throwDOMException(InvalidAccessError);
2025        return String();
2026    }
2027    return element->imageSourceURL();
2028}
2029
2030String Internals::baseURL(Document* document, ExceptionState& es)
2031{
2032    if (!document) {
2033        es.throwDOMException(InvalidAccessError);
2034        return String();
2035    }
2036
2037    return document->baseURL().string();
2038}
2039
2040bool Internals::isSelectPopupVisible(Node* node)
2041{
2042    if (!node->hasTagName(HTMLNames::selectTag))
2043        return false;
2044
2045    HTMLSelectElement* select = toHTMLSelectElement(node);
2046
2047    RenderObject* renderer = select->renderer();
2048    if (!renderer->isMenuList())
2049        return false;
2050
2051    RenderMenuList* menuList = toRenderMenuList(renderer);
2052    return menuList->popupIsVisible();
2053}
2054
2055bool Internals::loseSharedGraphicsContext3D()
2056{
2057    RefPtr<GraphicsContext3D> sharedContext = SharedGraphicsContext3D::get();
2058    if (!sharedContext)
2059        return false;
2060    sharedContext->getExtensions()->loseContextCHROMIUM(Extensions3D::GUILTY_CONTEXT_RESET_ARB, Extensions3D::INNOCENT_CONTEXT_RESET_ARB);
2061    // To prevent tests that call loseSharedGraphicsContext3D from being
2062    // flaky, we call finish so that the context is guaranteed to be lost
2063    // synchronously (i.e. before returning).
2064    sharedContext->finish();
2065    return true;
2066}
2067
2068}
2069