Commit message: None
CVE: CVE-2015-6768
CWE: CWE-264
Vulnerability description: The DOM implementation in Google Chrome before 47.0.2526.73 allows remote attackers to bypass the Same Origin Policy via unspecified vectors, a different vulnerability than CVE-2015-6770.

Project: Chrome

void Document::cancelIdleCallback(int id)
{
    if (!m_scriptedIdleTaskController)
        return;
    m_scriptedIdleTaskController->cancelCallback(id);
}

Project: Chrome

static inline String canonicalizedTitle(Document* document, const String& title)
{
    unsigned length = title.length();
    unsigned builderIndex = 0;
    const CharacterType* characters = title.getCharacters<CharacterType>();

    StringBuffer<CharacterType> buffer(length);

    bool pendingWhitespace = false;
    for (unsigned i = 0; i < length; ++i) {
        UChar32 c = characters[i];
        if (c <= 0x20 || c == 0x7F || (WTF::Unicode::category(c) & (WTF::Unicode::Separator_Line | WTF::Unicode::Separator_Paragraph))) {
            if (builderIndex != 0)
                pendingWhitespace = true;
        } else {
            if (pendingWhitespace) {
                buffer[builderIndex++] = ' ';
                pendingWhitespace = false;
            }
            buffer[builderIndex++] = c;
        }
    }
    buffer.shrink(builderIndex);

    return String::adopt(buffer);
}

Project: Chrome

bool Document::childTypeAllowed(NodeType type) const
{
    switch (type) {
    case ATTRIBUTE_NODE:
    case CDATA_SECTION_NODE:
    case DOCUMENT_FRAGMENT_NODE:
    case DOCUMENT_NODE:
    case TEXT_NODE:
        return false;
    case COMMENT_NODE:
    case PROCESSING_INSTRUCTION_NODE:
        return true;
    case DOCUMENT_TYPE_NODE:
    case ELEMENT_NODE:
        for (Node& c : NodeTraversal::childrenOf(*this)) {
            if (c.nodeType() == type)
                return false;
        }
        return true;
    }
    return false;
}

Project: Chrome

void Document::cloneDataFromDocument(const Document& other)
{
    setCompatibilityMode(other.compatibilityMode());
    setEncodingData(other.m_encodingData);
    setContextFeatures(other.contextFeatures());
    setSecurityOrigin(other.securityOrigin()->isolatedCopy());
    setMimeType(other.contentType());
}

Project: Chrome

void Document::close()
{
    if (!scriptableDocumentParser() || !scriptableDocumentParser()->wasCreatedByScript() || !scriptableDocumentParser()->isParsing())
        return;

    if (RefPtrWillBeRawPtr<DocumentParser> parser = m_parser)
        parser->finish();

    if (!m_frame) {
        implicitClose();
        return;
    }

    m_frame->loader().checkCompleted();
}

Project: Chrome

AtomicString Document::contentType() const
{
    if (!m_mimeType.isEmpty())
        return m_mimeType;

    if (DocumentLoader* documentLoader = loader())
        return documentLoader->mimeType();

    String mimeType = suggestedMIMEType();
    if (!mimeType.isEmpty())
        return AtomicString(mimeType);

    return AtomicString("application/xml");
}

Project: Chrome

WeakPtrWillBeRawPtr<Document> Document::contextDocument()
{
    if (m_contextDocument)
        return m_contextDocument;
    if (m_frame) {
        return createWeakPtr();
    }
    return nullptr;
}

Project: Chrome

PassRefPtrWillBeRawPtr<Element> Document::createElement(const AtomicString& localName, const AtomicString& typeExtension, ExceptionState& exceptionState)
{
    if (!isValidName(localName)) {
        exceptionState.throwDOMException(InvalidCharacterError, "The tag name provided ('" + localName + "') is not a valid name.");
        return nullptr;
    }

    RefPtrWillBeRawPtr<Element> element;

    if (CustomElement::isValidName(localName) && registrationContext()) {
        element = registrationContext()->createCustomTagElement(*this, QualifiedName(nullAtom, convertLocalName(localName), xhtmlNamespaceURI));
    } else {
        element = createElement(localName, exceptionState);
        if (exceptionState.hadException())
            return nullptr;
    }

    if (!typeExtension.isEmpty())
        CustomElementRegistrationContext::setIsAttributeAndTypeExtension(element.get(), typeExtension);

    return element.release();
}

Project: Chrome

PassRefPtrWillBeRawPtr<Touch> Document::createTouch(DOMWindow* window, EventTarget* target, int identifier, double pageX, double pageY, double screenX, double screenY, double radiusX, double radiusY, float rotationAngle, float force) const
{
    if (!std::isfinite(pageX))
        pageX = 0;
    if (!std::isfinite(pageY))
        pageY = 0;
    if (!std::isfinite(screenX))
        screenX = 0;
    if (!std::isfinite(screenY))
        screenY = 0;
    if (!std::isfinite(radiusX))
        radiusX = 0;
    if (!std::isfinite(radiusY))
        radiusY = 0;
    if (!std::isfinite(rotationAngle))
        rotationAngle = 0;
    if (!std::isfinite(force))
        force = 0;

    LocalFrame* frame = window && window->isLocalDOMWindow() ? toLocalDOMWindow(window)->frame() : this->frame();
    return Touch::create(frame, target, identifier, FloatPoint(screenX, screenY), FloatPoint(pageX, pageY), FloatSize(radiusX, radiusY), rotationAngle, force);
}

Project: Chrome

String Document::designMode() const
{
    return inDesignMode() ? "on" : "off";
}

Project: Chrome

void Document::didMergeTextNodes(Text& oldNode, unsigned offset)
{
    if (!m_ranges.isEmpty()) {
        NodeWithIndex oldNodeWithIndex(oldNode);
        for (Range* range : m_ranges)
            range->didMergeTextNodes(oldNodeWithIndex, offset);
    }

    if (m_frame)
        m_frame->selection().didMergeTextNodes(oldNode, offset);

}

Project: Chrome

const AtomicString& Document::dir()
{
    Element* rootElement = documentElement();
    if (isHTMLHtmlElement(rootElement))
        return toHTMLHtmlElement(rootElement)->dir();
    return nullAtom;
}

Project: Chrome

bool Document::dirtyElementsForLayerUpdate()
{
    if (m_layerUpdateSVGFilterElements.isEmpty())
        return false;

    for (Element* element : m_layerUpdateSVGFilterElements)
        element->setNeedsStyleRecalc(LocalStyleChange, StyleChangeReasonForTracing::create(StyleChangeReason::SVGFilterLayerUpdate));
    m_layerUpdateSVGFilterElements.clear();
    return true;
}

Project: Chrome

bool Document::dispatchBeforeUnloadEvent(ChromeClient& chromeClient, bool isReload, bool& didAllowNavigation)
{
    if (!m_domWindow)
        return true;

    if (!body())
        return true;

    if (processingBeforeUnload())
        return false;

    RefPtrWillBeRawPtr<Document> protect(this);

    RefPtrWillBeRawPtr<BeforeUnloadEvent> beforeUnloadEvent = BeforeUnloadEvent::create();
    m_loadEventProgress = BeforeUnloadEventInProgress;
    m_domWindow->dispatchEvent(beforeUnloadEvent.get(), this);
    m_loadEventProgress = BeforeUnloadEventCompleted;
    if (!beforeUnloadEvent->defaultPrevented())
        defaultEventHandler(beforeUnloadEvent.get());
    if (!frame() || beforeUnloadEvent->returnValue().isNull())
        return true;

    if (didAllowNavigation) {
        addConsoleMessage(ConsoleMessage::create(JSMessageSource, ErrorMessageLevel, "Blocked attempt to show multiple 'beforeunload' confirmation panels for a single navigation."));
        return true;
    }

    String text = beforeUnloadEvent->returnValue();
    if (chromeClient.openBeforeUnloadConfirmPanel(text, m_frame, isReload)) {
        didAllowNavigation = true;
        return true;
    }
    return false;
}

Project: Chrome

Element* Document::elementFromPoint(int x, int y) const
{
    if (!layoutView())
        return 0;

    return TreeScope::elementFromPoint(x, y);
}

Project: Chrome

void Document::enqueueMediaQueryChangeListeners(WillBeHeapVector<RefPtrWillBeMember<MediaQueryListListener>>& listeners)
{
    ensureScriptedAnimationController().enqueueMediaQueryChangeListeners(listeners);
}

Project: Chrome

void Document::enqueueUniqueAnimationFrameEvent(PassRefPtrWillBeRawPtr<Event> event)
{
    ensureScriptedAnimationController().enqueuePerFrameEvent(event);
}

Project: Chrome

bool Document::execCommand(const String& commandName, bool, const String& value, ExceptionState& exceptionState)
{
    if (!isHTMLDocument() && !isXHTMLDocument()) {
        exceptionState.throwDOMException(InvalidStateError, "execCommand is only supported on HTML documents.");
        return false;
    }
    if (focusedElement() && isHTMLTextFormControlElement(*focusedElement()))
        UseCounter::count(*this, UseCounter::ExecCommandOnInputOrTextarea);

    if (m_isRunningExecCommand) {
        String message = "We don't execute document.execCommand() this time, because it is called recursively.";
        addConsoleMessage(ConsoleMessage::create(JSMessageSource, WarningMessageLevel, message));
        return false;
    }
    TemporaryChange<bool> executeScope(m_isRunningExecCommand, true);

    EventQueueScope eventQueueScope;
    Editor::tidyUpHTMLStructure(*this);
    Editor::Command editorCommand = command(this, commandName);

    DEFINE_STATIC_LOCAL(SparseHistogram, editorCommandHistogram, ("WebCore.Document.execCommand"));
    editorCommandHistogram.sample(editorCommand.idForHistogram());
    return editorCommand.execute(value);
}

Project: Chrome

void Document::finishedParsing()
{
    ASSERT(!scriptableDocumentParser() || !m_parser->isParsing());
    ASSERT(!scriptableDocumentParser() || m_readyState != Loading);
    setParsingState(InDOMContentLoaded);

    if (!m_documentTiming.domContentLoadedEventStart())
        m_documentTiming.markDomContentLoadedEventStart();
    dispatchEvent(Event::createBubble(EventTypeNames::DOMContentLoaded));
    if (!m_documentTiming.domContentLoadedEventEnd())
        m_documentTiming.markDomContentLoadedEventEnd();
    setParsingState(FinishedParsing);

    RefPtrWillBeRawPtr<Document> protect(this);

    Microtask::performCheckpoint(V8PerIsolateData::mainThreadIsolate());

    if (RefPtrWillBeRawPtr<LocalFrame> frame = this->frame()) {
        const bool mainResourceWasAlreadyRequested = frame->loader().stateMachine()->committedFirstRealDocumentLoad();

        if (mainResourceWasAlreadyRequested)
            updateLayoutTreeIfNeeded();

        frame->loader().finishedParsing();

        TRACE_EVENT_INSTANT1("devtools.timeline", "MarkDOMContent", TRACE_EVENT_SCOPE_THREAD, "data", InspectorMarkLoadEvent::data(frame.get()));
        InspectorInstrumentation::domContentLoadedEventFired(frame.get());
    }

    m_elementDataCacheClearTimer.startOneShot(10, BLINK_FROM_HERE);

    m_fetcher->clearPreloads(ResourceFetcher::ClearSpeculativeMarkupPreloads);
}

Project: Chrome

PassRefPtrWillBeRawPtr<HTMLCollection> Document::forms()
{
    return ensureCachedCollection<HTMLCollection>(DocForms);
}

Project: Chrome

PassRefPtrWillBeRawPtr<DocumentParser> Document::implicitOpen(ParserSynchronizationPolicy parserSyncPolicy)
{
    detachParser();

    removeChildren();
    ASSERT(!m_focusedElement);

    setCompatibilityMode(NoQuirksMode);

    if (!threadedParsingEnabledForTesting())
        parserSyncPolicy = ForceSynchronousParsing;

    m_parserSyncPolicy = parserSyncPolicy;
    m_parser = createParser();
    setParsingState(Parsing);
    setReadyState(Loading);

    return m_parser;
}

Project: Chrome

PassRefPtrWillBeRawPtr<HTMLCollection> Document::links()
{
    return ensureCachedCollection<HTMLCollection>(DocLinks);
}

Project: Chrome

void Document::processReferrerPolicy(const String& policy)
{
    ReferrerPolicy referrerPolicy;
    if (!SecurityPolicy::referrerPolicyFromString(policy, &referrerPolicy)) {
        addConsoleMessage(ConsoleMessage::create(RenderingMessageSource, ErrorMessageLevel, "Failed to set referrer policy: The value '" + policy + "' is not one of 'always', 'default', 'never', 'no-referrer', 'no-referrer-when-downgrade', 'origin', 'origin-when-crossorigin', or 'unsafe-url'. This document's referrer policy has been left unchanged."));
        return;
    }

    setReferrerPolicy(referrerPolicy);
}

Project: Chrome

void Document::pushCurrentScript(PassRefPtrWillBeRawPtr<HTMLScriptElement> newCurrentScript)
{
    ASSERT(newCurrentScript);
    m_currentScriptStack.append(newCurrentScript);
}

Project: Chrome

void Document::registerEventFactory(PassOwnPtr<EventFactoryBase> eventFactory)
{
    ASSERT(!eventFactories().contains(eventFactory.get()));
    eventFactories().add(eventFactory);
}

Project: Chrome

void Document::setCookie(const String& value, ExceptionState& exceptionState)
{
    if (settings() && !settings()->cookieEnabled())
        return;


    if (!securityOrigin()->canAccessCookies()) {
        if (isSandboxed(SandboxOrigin))
            exceptionState.throwSecurityError("The document is sandboxed and lacks the 'allow-same-origin' flag.");
        else if (url().protocolIs("data"))
            exceptionState.throwSecurityError("Cookies are disabled inside 'data:' URLs.");
        else
            exceptionState.throwSecurityError("Access is denied for this document.");
        return;
    }

    KURL cookieURL = this->cookieURL();
    if (cookieURL.isEmpty())
        return;

    setCookies(this, cookieURL, value);
}

Project: Chrome

void Document::setDoctype(PassRefPtrWillBeRawPtr<DocumentType> docType)
{
    ASSERT(!m_docType || !docType);
    m_docType = docType;
    if (m_docType) {
        this->adoptIfNeeded(*m_docType);
        if (m_docType->publicId().startsWith("-//wapforum//dtd xhtml mobile 1.", TextCaseInsensitive))
            m_isMobileDocument = true;
    }
    styleEngine().clearResolver();
}

Project: Chrome

void Document::setViewportDescription(const ViewportDescription& viewportDescription)
{
    if (viewportDescription == m_viewportDescription)
        return;

    if (!viewportDescription.isSpecifiedByAuthor())
        m_viewportDefaultMinWidth = viewportDescription.minWidth;

    if (viewportDescription.isLegacyViewportType()) {
        m_legacyViewportDescription = viewportDescription;

        if (m_viewportDescription.type == ViewportDescription::AuthorStyleSheet)
            return;
        m_viewportDescription = viewportDescription;
    } else {
        if (!shouldOverrideLegacyDescription(viewportDescription.type))
            m_viewportDescription = m_legacyViewportDescription;
        else
            m_viewportDescription = viewportDescription;
    }

    updateViewportDescription();
}

Project: Chrome

bool shouldInvalidateNodeListCachesForAttr(const HeapHashSet<WeakMember<const LiveNodeListBase>> nodeLists[], const QualifiedName& attrName)
{
    if (!nodeLists[type].isEmpty() && LiveNodeListBase::shouldInvalidateTypeOnAttributeChange(static_cast<NodeListInvalidationType>(type), attrName))
        return true;
    return shouldInvalidateNodeListCachesForAttr<type + 1>(nodeLists, attrName);
}

Project: Chrome

bool Document::tasksNeedSuspension()
{
    Page* page = this->page();
    return page && page->defersLoading();
}

Project: Chrome

void Document::tasksWereResumed()
{
    scriptRunner()->resume();

    if (m_parser)
        m_parser->resumeScheduledTasks();
    if (m_scriptedAnimationController)
        m_scriptedAnimationController->resume();

    MutationObserver::resumeSuspendedObservers();
    if (m_domWindow)
        DOMWindowPerformance::performance(*m_domWindow)->resumeSuspendedObservers();
}

Project: Chrome

bool Document::threadedParsingEnabledForTesting()
{
    return s_threadedParsingEnabledForTesting;
}

Project: Chrome

void Document::updateFocusAppearanceSoon(SelectionBehaviorOnFocus selectionbehavioronfocus)
{
    m_updateFocusAppearanceSelectionBahavior = selectionbehavioronfocus;
    if (!m_updateFocusAppearanceTimer.isActive())
        m_updateFocusAppearanceTimer.startOneShot(0, BLINK_FROM_HERE);
}

Project: Chrome

void Document::updateHoverActiveState(const HitTestRequest& request, Element* innerElement)
{
    ASSERT(!request.readOnly());

    if (request.active() && m_frame)
        m_frame->eventHandler().notifyElementActivated();

    Element* innerElementInDocument = innerElement;
    while (innerElementInDocument && innerElementInDocument->document() != this) {
        innerElementInDocument->document().updateHoverActiveState(request, innerElementInDocument);
        innerElementInDocument = innerElementInDocument->document().ownerElement();
    }

    updateDistribution();
    Element* oldActiveElement = activeHoverElement();
    if (oldActiveElement && !request.active()) {
        for (RefPtrWillBeRawPtr<Node> node = oldActiveElement; node; node = ComposedTreeTraversal::parent(*node)) {
            ASSERT(!node->isTextNode());
            node->setActive(false);
            m_userActionElements.setInActiveChain(node.get(), false);
        }
        setActiveHoverElement(nullptr);
    } else {
        Element* newActiveElement = innerElementInDocument;
        if (!oldActiveElement && newActiveElement && !newActiveElement->isDisabledFormControl() && request.active() && !request.touchMove()) {
            for (Node* node = newActiveElement; node; node = ComposedTreeTraversal::parent(*node)) {
                ASSERT(!node->isTextNode());
                m_userActionElements.setInActiveChain(node, true);
            }
            setActiveHoverElement(newActiveElement);
        }
    }
    bool allowActiveChanges = !oldActiveElement && activeHoverElement();

    bool mustBeInActiveChain = request.active() && request.move();

    RefPtrWillBeRawPtr<Node> oldHoverNode = hoverNode();

    Node* newHoverNode = innerElementInDocument;
    while (newHoverNode && !newHoverNode->layoutObject())
        newHoverNode = newHoverNode->parentOrShadowHostNode();

    setHoverNode(newHoverNode);

    LayoutObject* oldHoverObj = oldHoverNode ? oldHoverNode->layoutObject() : 0;
    LayoutObject* newHoverObj = newHoverNode ? newHoverNode->layoutObject() : 0;

    LayoutObject* ancestor = nearestCommonHoverAncestor(oldHoverObj, newHoverObj);
    RefPtrWillBeRawPtr<Node> ancestorNode(ancestor ? ancestor->node() : 0);

    WillBeHeapVector<RefPtrWillBeMember<Node>, 32> nodesToRemoveFromChain;
    WillBeHeapVector<RefPtrWillBeMember<Node>, 32> nodesToAddToChain;

    if (oldHoverObj != newHoverObj) {
        if (oldHoverNode && !oldHoverObj) {
            for (Node* node = oldHoverNode.get(); node; node = node->parentNode()) {
                if (!mustBeInActiveChain || (node->isElementNode() && toElement(node)->inActiveChain()))
                    nodesToRemoveFromChain.append(node);
            }

        }

        for (LayoutObject* curr = oldHoverObj; curr && curr != ancestor; curr = curr->hoverAncestor()) {
            if (curr->node() && !curr->isText() && (!mustBeInActiveChain || curr->node()->inActiveChain()))
                nodesToRemoveFromChain.append(curr->node());
        }

    }

    for (LayoutObject* curr = newHoverObj; curr; curr = curr->hoverAncestor()) {
        if (curr->node() && !curr->isText() && (!mustBeInActiveChain || curr->node()->inActiveChain()))
            nodesToAddToChain.append(curr->node());
    }

    size_t removeCount = nodesToRemoveFromChain.size();
    for (size_t i = 0; i < removeCount; ++i) {
        nodesToRemoveFromChain[i]->setHovered(false);
    }

    bool sawCommonAncestor = false;
    size_t addCount = nodesToAddToChain.size();
    for (size_t i = 0; i < addCount; ++i) {
        if (ancestorNode && nodesToAddToChain[i] == ancestorNode)
            sawCommonAncestor = true;
        if (allowActiveChanges)
            nodesToAddToChain[i]->setActive(true);
        if (!sawCommonAncestor || nodesToAddToChain[i] == m_hoverNode) {
            nodesToAddToChain[i]->setHovered(true);
        }
    }
}

Project: Chrome

void Document::updateLayout()
{
    ASSERT(isMainThread());

    ScriptForbiddenScope forbidScript;

    RefPtrWillBeRawPtr<FrameView> frameView = view();
    if (frameView && frameView->isInPerformLayout()) {
        ASSERT_NOT_REACHED();
        return;
    }

    if (HTMLFrameOwnerElement* owner = ownerElement())
        owner->document().updateLayout();

    updateLayoutTreeIfNeeded();

    if (!isActive())
        return;

    if (frameView->needsLayout())
        frameView->layout();

    if (lifecycle().state() < DocumentLifecycle::LayoutClean)
        lifecycle().advanceTo(DocumentLifecycle::LayoutClean);
}

Project: Chrome

void Document::updateStyle(StyleRecalcChange change)
{
    if (view()->shouldThrottleRendering())
        return;

    TRACE_EVENT_BEGIN0("blink,blink_style", "Document::updateStyle");
    unsigned initialElementCount = styleEngine().styleForElementCount();

    HTMLFrameOwnerElement::UpdateSuspendScope suspendWidgetHierarchyUpdates;
    m_lifecycle.advanceTo(DocumentLifecycle::InStyleRecalc);

    NthIndexCache nthIndexCache(*this);

    if (styleChangeType() >= SubtreeStyleChange)
        change = Force;


    if (change == Force) {
        m_hasNodesWithPlaceholderStyle = false;
        RefPtr<ComputedStyle> documentStyle = StyleResolver::styleForDocument(*this);
        StyleRecalcChange localChange = ComputedStyle::stylePropagationDiff(documentStyle.get(), layoutView()->style());
        if (localChange != NoChange)
            layoutView()->setStyle(documentStyle.release());
    }

    clearNeedsStyleRecalc();

    StyleResolver& resolver = ensureStyleResolver();

    bool shouldRecordStats;
    TRACE_EVENT_CATEGORY_GROUP_ENABLED("blink,blink_style", &shouldRecordStats);
    styleEngine().setStatsEnabled(shouldRecordStats);

    if (Element* documentElement = this->documentElement()) {
        inheritHtmlAndBodyElementStyles(change);
        dirtyElementsForLayerUpdate();
        if (documentElement->shouldCallRecalcStyle(change))
            documentElement->recalcStyle(change);
        while (dirtyElementsForLayerUpdate())
            documentElement->recalcStyle(NoChange);
    }

    view()->recalcOverflowAfterStyleChange();
    view()->setFrameTimingRequestsDirty(true);

    clearChildNeedsStyleRecalc();

    styleEngine().resetCSSFeatureFlags(resolver.ensureUpdatedRuleFeatureSet());
    resolver.clearStyleSharingList();

    m_wasPrinting = m_printing;

    ASSERT(!needsStyleRecalc());
    ASSERT(!childNeedsStyleRecalc());
    ASSERT(inStyleRecalc());
    ASSERT(styleResolver() == &resolver);
    m_lifecycle.advanceTo(DocumentLifecycle::StyleClean);
    if (shouldRecordStats) {
        TRACE_EVENT_END2("blink,blink_style", "Document::updateStyle",
            "resolverAccessCount", styleEngine().styleForElementCount() - initialElementCount,
            "counters", styleEngine().stats()->toTracedValue());
    } else {
        TRACE_EVENT_END1("blink,blink_style", "Document::updateStyle",
            "resolverAccessCount", styleEngine().styleForElementCount() - initialElementCount);
    }
}

Project: Chrome

v8::Local<v8::Object> Document::wrap(v8::Isolate* isolate, v8::Local<v8::Object> creationContext)
{
    RefPtrWillBeRawPtr<Document> protect(this);

    ASSERT(!DOMDataStore::containsWrapper(this, isolate));

    const WrapperTypeInfo* wrapperType = wrapperTypeInfo();

    if (frame() && frame()->script().initializeMainWorld()) {
        v8::Local<v8::Object> wrapper = DOMDataStore::getWrapper(this, isolate);
        if (!wrapper.IsEmpty())
            return wrapper;
    }

    v8::Local<v8::Object> wrapper = V8DOMWrapper::createWrapper(isolate, creationContext, wrapperType, this);
    if (UNLIKELY(wrapper.IsEmpty()))
        return wrapper;

    wrapperType->installConditionallyEnabledProperties(wrapper, isolate);
    return associateWithWrapper(isolate, wrapperType, wrapper);
}