void mozilla::dom::TraceBlackJS(JSTracer* aTrc, uint32_t aGCNumber, bool aIsShutdownGC) { #ifdef MOZ_XUL // Mark the scripts held in the XULPrototypeCache. This is required to keep // the JS script in the cache live across GC. nsXULPrototypeCache* cache = nsXULPrototypeCache::MaybeGetInstance(); if (cache) { if (aIsShutdownGC) { cache->FlushScripts(); } else { cache->MarkInGC(aTrc); } } #endif if (!nsCCUncollectableMarker::sGeneration) { return; } if (nsFrameMessageManager::GetChildProcessManager()) { nsIContentProcessMessageManager* pg = ProcessGlobal::Get(); if (pg) { mozilla::TraceScriptHolder(pg, aTrc); } } // Mark globals of active windows black. nsGlobalWindow::WindowByIdTable* windowsById = nsGlobalWindow::GetWindowsTable(); if (windowsById) { for (auto iter = windowsById->Iter(); !iter.Done(); iter.Next()) { nsGlobalWindow* window = iter.Data(); if (window->GetDocShell() && window->IsOuterWindow()) { window->TraceGlobalJSObject(aTrc); EventListenerManager* elm = window->GetExistingListenerManager(); if (elm) { elm->TraceListeners(aTrc); } if (window->IsRootOuterWindow()) { // In child process trace all the TabChildGlobals. // Since there is one root outer window per TabChildGlobal, we need // to look for only those windows, not all. nsIDocShell* ds = window->GetDocShell(); if (ds) { nsCOMPtr<nsITabChild> tabChild = ds->GetTabChild(); if (tabChild) { nsCOMPtr<nsIContentFrameMessageManager> mm; tabChild->GetMessageManager(getter_AddRefs(mm)); nsCOMPtr<EventTarget> et = do_QueryInterface(mm); if (et) { nsCOMPtr<nsISupports> tabChildAsSupports = do_QueryInterface(tabChild); mozilla::TraceScriptHolder(tabChildAsSupports, aTrc); EventListenerManager* elm = et->GetExistingListenerManager(); if (elm) { elm->TraceListeners(aTrc); } // As of now there isn't an easy way to trace message listeners. } } } } #ifdef MOZ_XUL nsIDocument* doc = window->GetExtantDoc(); if (doc && doc->IsXULDocument()) { XULDocument* xulDoc = static_cast<XULDocument*>(doc); xulDoc->TraceProtos(aTrc, aGCNumber); } #endif } } } }
EventHandlerNonNull* EventTarget::GetEventHandler(nsIAtom* aType, const nsAString& aTypeString) { EventListenerManager* elm = GetExistingListenerManager(); return elm ? elm->GetEventHandler(aType, aTypeString) : nullptr; }
bool EventTarget::HasApzAwareListeners() const { EventListenerManager* elm = GetExistingListenerManager(); return elm && elm->HasApzAwareListeners(); }
OnErrorEventHandlerNonNull* WorkerGlobalScope::GetOnerror() { mWorkerPrivate->AssertIsOnWorkerThread(); EventListenerManager* elm = GetExistingListenerManager(); return elm ? elm->GetOnErrorEventHandler() : nullptr; }
/* static */ nsresult nsNodeUtils::CloneAndAdopt(nsINode *aNode, bool aClone, bool aDeep, nsNodeInfoManager *aNewNodeInfoManager, JS::Handle<JSObject*> aReparentScope, nsCOMArray<nsINode> &aNodesWithProperties, nsINode *aParent, nsINode **aResult) { NS_PRECONDITION((!aClone && aNewNodeInfoManager) || !aReparentScope, "If cloning or not getting a new nodeinfo we shouldn't " "rewrap"); NS_PRECONDITION(!aParent || aNode->IsNodeOfType(nsINode::eCONTENT), "Can't insert document or attribute nodes into a parent"); *aResult = nullptr; // First deal with aNode and walk its attributes (and their children). Then, // if aDeep is true, deal with aNode's children (and recurse into their // attributes and children). nsAutoScriptBlocker scriptBlocker; AutoJSContext cx; nsresult rv; nsNodeInfoManager *nodeInfoManager = aNewNodeInfoManager; // aNode. NodeInfo *nodeInfo = aNode->mNodeInfo; RefPtr<NodeInfo> newNodeInfo; if (nodeInfoManager) { // Don't allow importing/adopting nodes from non-privileged "scriptable" // documents to "non-scriptable" documents. nsIDocument* newDoc = nodeInfoManager->GetDocument(); NS_ENSURE_STATE(newDoc); bool hasHadScriptHandlingObject = false; if (!newDoc->GetScriptHandlingObject(hasHadScriptHandlingObject) && !hasHadScriptHandlingObject) { nsIDocument* currentDoc = aNode->OwnerDoc(); NS_ENSURE_STATE((nsContentUtils::IsChromeDoc(currentDoc) || (!currentDoc->GetScriptHandlingObject(hasHadScriptHandlingObject) && !hasHadScriptHandlingObject))); } newNodeInfo = nodeInfoManager->GetNodeInfo(nodeInfo->NameAtom(), nodeInfo->GetPrefixAtom(), nodeInfo->NamespaceID(), nodeInfo->NodeType(), nodeInfo->GetExtraName()); nodeInfo = newNodeInfo; } Element *elem = aNode->IsElement() ? aNode->AsElement() : nullptr; nsCOMPtr<nsINode> clone; if (aClone) { rv = aNode->Clone(nodeInfo, getter_AddRefs(clone)); NS_ENSURE_SUCCESS(rv, rv); if (clone->IsElement()) { // The cloned node may be a custom element that may require // enqueing created callback and prototype swizzling. Element* elem = clone->AsElement(); if (nsContentUtils::IsCustomElementName(nodeInfo->NameAtom())) { elem->OwnerDoc()->SetupCustomElement(elem, nodeInfo->NamespaceID()); } else { // Check if node may be custom element by type extension. // ex. <button is="x-button"> nsAutoString extension; if (elem->GetAttr(kNameSpaceID_None, nsGkAtoms::is, extension) && !extension.IsEmpty()) { elem->OwnerDoc()->SetupCustomElement(elem, nodeInfo->NamespaceID(), &extension); } } } if (aParent) { // If we're cloning we need to insert the cloned children into the cloned // parent. rv = aParent->AppendChildTo(static_cast<nsIContent*>(clone.get()), false); NS_ENSURE_SUCCESS(rv, rv); } else if (aDeep && clone->IsNodeOfType(nsINode::eDOCUMENT)) { // After cloning the document itself, we want to clone the children into // the cloned document (somewhat like cloning and importing them into the // cloned document). nodeInfoManager = clone->mNodeInfo->NodeInfoManager(); } } else if (nodeInfoManager) { nsIDocument* oldDoc = aNode->OwnerDoc(); bool wasRegistered = false; if (aNode->IsElement()) { Element* element = aNode->AsElement(); oldDoc->ClearBoxObjectFor(element); wasRegistered = oldDoc->UnregisterActivityObserver(element); } aNode->mNodeInfo.swap(newNodeInfo); if (elem) { elem->NodeInfoChanged(newNodeInfo); } nsIDocument* newDoc = aNode->OwnerDoc(); if (newDoc) { // XXX what if oldDoc is null, we don't know if this should be // registered or not! Can that really happen? if (wasRegistered) { newDoc->RegisterActivityObserver(aNode->AsElement()); } if (nsPIDOMWindowInner* window = newDoc->GetInnerWindow()) { EventListenerManager* elm = aNode->GetExistingListenerManager(); if (elm) { window->SetMutationListeners(elm->MutationListenerBits()); if (elm->MayHavePaintEventListener()) { window->SetHasPaintEventListeners(); } if (elm->MayHaveTouchEventListener()) { window->SetHasTouchEventListeners(); } if (elm->MayHaveMouseEnterLeaveEventListener()) { window->SetHasMouseEnterLeaveEventListeners(); } if (elm->MayHavePointerEnterLeaveEventListener()) { window->SetHasPointerEnterLeaveEventListeners(); } } } } if (wasRegistered && oldDoc != newDoc) { nsCOMPtr<nsIDOMHTMLMediaElement> domMediaElem(do_QueryInterface(aNode)); if (domMediaElem) { HTMLMediaElement* mediaElem = static_cast<HTMLMediaElement*>(aNode); mediaElem->NotifyOwnerDocumentActivityChanged(); } nsCOMPtr<nsIObjectLoadingContent> objectLoadingContent(do_QueryInterface(aNode)); if (objectLoadingContent) { nsObjectLoadingContent* olc = static_cast<nsObjectLoadingContent*>(objectLoadingContent.get()); olc->NotifyOwnerDocumentActivityChanged(); } } if (oldDoc != newDoc && oldDoc->MayHaveDOMMutationObservers()) { newDoc->SetMayHaveDOMMutationObservers(); } if (oldDoc != newDoc && oldDoc->MayHaveAnimationObservers()) { newDoc->SetMayHaveAnimationObservers(); } if (elem) { elem->RecompileScriptEventListeners(); } if (aReparentScope) { JS::Rooted<JSObject*> wrapper(cx); if ((wrapper = aNode->GetWrapper())) { MOZ_ASSERT(IsDOMObject(wrapper)); JSAutoCompartment ac(cx, wrapper); rv = ReparentWrapper(cx, wrapper); if (NS_FAILED(rv)) { aNode->mNodeInfo.swap(nodeInfo); return rv; } } } } if (aDeep && (!aClone || !aNode->IsNodeOfType(nsINode::eATTRIBUTE))) { // aNode's children. for (nsIContent* cloneChild = aNode->GetFirstChild(); cloneChild; cloneChild = cloneChild->GetNextSibling()) { nsCOMPtr<nsINode> child; rv = CloneAndAdopt(cloneChild, aClone, true, nodeInfoManager, aReparentScope, aNodesWithProperties, clone, getter_AddRefs(child)); NS_ENSURE_SUCCESS(rv, rv); } } // Cloning template element. if (aDeep && aClone && IsTemplateElement(aNode)) { DocumentFragment* origContent = static_cast<HTMLTemplateElement*>(aNode)->Content(); DocumentFragment* cloneContent = static_cast<HTMLTemplateElement*>(clone.get())->Content(); // Clone the children into the clone's template content owner // document's nodeinfo manager. nsNodeInfoManager* ownerNodeInfoManager = cloneContent->mNodeInfo->NodeInfoManager(); for (nsIContent* cloneChild = origContent->GetFirstChild(); cloneChild; cloneChild = cloneChild->GetNextSibling()) { nsCOMPtr<nsINode> child; rv = CloneAndAdopt(cloneChild, aClone, aDeep, ownerNodeInfoManager, aReparentScope, aNodesWithProperties, cloneContent, getter_AddRefs(child)); NS_ENSURE_SUCCESS(rv, rv); } } // XXX setting document on some nodes not in a document so XBL will bind // and chrome won't break. Make XBL bind to document-less nodes! // XXXbz Once this is fixed, fix up the asserts in all implementations of // BindToTree to assert what they would like to assert, and fix the // ChangeDocumentFor() call in nsXULElement::BindToTree as well. Also, // remove the UnbindFromTree call in ~nsXULElement, and add back in the // precondition in nsXULElement::UnbindFromTree and remove the line in // nsXULElement.h that makes nsNodeUtils a friend of nsXULElement. // Note: Make sure to do this witchery _after_ we've done any deep // cloning, so kids of the new node aren't confused about whether they're // in a document. #ifdef MOZ_XUL if (aClone && !aParent && aNode->IsXULElement()) { if (!aNode->OwnerDoc()->IsLoadedAsInteractiveData()) { clone->SetFlags(NODE_FORCE_XBL_BINDINGS); } } #endif if (aNode->HasProperties()) { bool ok = aNodesWithProperties.AppendObject(aNode); if (aClone) { ok = ok && aNodesWithProperties.AppendObject(clone); } NS_ENSURE_TRUE(ok, NS_ERROR_OUT_OF_MEMORY); } clone.forget(aResult); return NS_OK; }
void mozilla::dom::TraceBlackJS(JSTracer* aTrc, bool aIsShutdownGC) { #ifdef MOZ_XUL // Mark the scripts held in the XULPrototypeCache. This is required to keep // the JS script in the cache live across GC. nsXULPrototypeCache* cache = nsXULPrototypeCache::MaybeGetInstance(); if (cache) { if (aIsShutdownGC) { cache->FlushScripts(); } else { cache->MarkInGC(aTrc); } } #endif if (!nsCCUncollectableMarker::sGeneration) { return; } if (ContentProcessMessageManager::WasCreated() && nsFrameMessageManager::GetChildProcessManager()) { auto* pg = ContentProcessMessageManager::Get(); if (pg) { mozilla::TraceScriptHolder(ToSupports(pg), aTrc); } } // Mark globals of active windows black. nsGlobalWindowOuter::OuterWindowByIdTable* windowsById = nsGlobalWindowOuter::GetWindowsTable(); if (windowsById) { for (auto iter = windowsById->Iter(); !iter.Done(); iter.Next()) { nsGlobalWindowOuter* window = iter.Data(); if (!window->IsCleanedUp()) { nsGlobalWindowInner* inner = nullptr; for (PRCList* win = PR_LIST_HEAD(window); win != window; win = PR_NEXT_LINK(inner)) { inner = static_cast<nsGlobalWindowInner*>(win); if (inner->IsCurrentInnerWindow() || (inner->GetExtantDoc() && inner->GetExtantDoc()->GetBFCacheEntry())) { inner->TraceGlobalJSObject(aTrc); EventListenerManager* elm = inner->GetExistingListenerManager(); if (elm) { elm->TraceListeners(aTrc); } } } if (window->IsRootOuterWindow()) { // In child process trace all the TabChildMessageManagers. // Since there is one root outer window per TabChildMessageManager, we // need to look for only those windows, not all. nsIDocShell* ds = window->GetDocShell(); if (ds) { nsCOMPtr<nsITabChild> tabChild = ds->GetTabChild(); if (tabChild) { RefPtr<ContentFrameMessageManager> mm; tabChild->GetMessageManager(getter_AddRefs(mm)); if (mm) { nsCOMPtr<nsISupports> tabChildAsSupports = do_QueryInterface(tabChild); mozilla::TraceScriptHolder(tabChildAsSupports, aTrc); EventListenerManager* elm = mm->GetExistingListenerManager(); if (elm) { elm->TraceListeners(aTrc); } // As of now there isn't an easy way to trace message listeners. } } } } #ifdef MOZ_XUL Document* doc = window->GetExtantDoc(); if (doc) { doc->TraceProtos(aTrc); } #endif } } } }
void nsEditorEventListener::UninstallFromEditor() { nsCOMPtr<EventTarget> piTarget = mEditor->GetDOMEventTarget(); if (!piTarget) { return; } EventListenerManager* elmP = piTarget->GetOrCreateListenerManager(); if (!elmP) { return; } #ifdef HANDLE_NATIVE_TEXT_DIRECTION_SWITCH elmP->RemoveEventListenerByType(this, NS_LITERAL_STRING("keydown"), TrustedEventsAtSystemGroupBubble()); elmP->RemoveEventListenerByType(this, NS_LITERAL_STRING("keyup"), TrustedEventsAtSystemGroupBubble()); #endif elmP->RemoveEventListenerByType(this, NS_LITERAL_STRING("keypress"), TrustedEventsAtSystemGroupBubble()); elmP->RemoveEventListenerByType(this, NS_LITERAL_STRING("dragenter"), TrustedEventsAtSystemGroupBubble()); elmP->RemoveEventListenerByType(this, NS_LITERAL_STRING("dragover"), TrustedEventsAtSystemGroupBubble()); elmP->RemoveEventListenerByType(this, NS_LITERAL_STRING("dragexit"), TrustedEventsAtSystemGroupBubble()); elmP->RemoveEventListenerByType(this, NS_LITERAL_STRING("drop"), TrustedEventsAtSystemGroupBubble()); elmP->RemoveEventListenerByType(this, NS_LITERAL_STRING("mousedown"), TrustedEventsAtCapture()); elmP->RemoveEventListenerByType(this, NS_LITERAL_STRING("mouseup"), TrustedEventsAtCapture()); elmP->RemoveEventListenerByType(this, NS_LITERAL_STRING("click"), TrustedEventsAtCapture()); elmP->RemoveEventListenerByType(this, NS_LITERAL_STRING("blur"), TrustedEventsAtCapture()); elmP->RemoveEventListenerByType(this, NS_LITERAL_STRING("focus"), TrustedEventsAtCapture()); elmP->RemoveEventListenerByType(this, NS_LITERAL_STRING("text"), TrustedEventsAtSystemGroupBubble()); elmP->RemoveEventListenerByType(this, NS_LITERAL_STRING("compositionstart"), TrustedEventsAtSystemGroupBubble()); elmP->RemoveEventListenerByType(this, NS_LITERAL_STRING("compositionend"), TrustedEventsAtSystemGroupBubble()); }
nsresult nsEditorEventListener::InstallToEditor() { NS_PRECONDITION(mEditor, "The caller must set mEditor"); nsCOMPtr<EventTarget> piTarget = mEditor->GetDOMEventTarget(); NS_ENSURE_TRUE(piTarget, NS_ERROR_FAILURE); // register the event listeners with the listener manager EventListenerManager* elmP = piTarget->GetOrCreateListenerManager(); NS_ENSURE_STATE(elmP); #ifdef HANDLE_NATIVE_TEXT_DIRECTION_SWITCH elmP->AddEventListenerByType(this, NS_LITERAL_STRING("keydown"), TrustedEventsAtSystemGroupBubble()); elmP->AddEventListenerByType(this, NS_LITERAL_STRING("keyup"), TrustedEventsAtSystemGroupBubble()); #endif elmP->AddEventListenerByType(this, NS_LITERAL_STRING("keypress"), TrustedEventsAtSystemGroupBubble()); elmP->AddEventListenerByType(this, NS_LITERAL_STRING("dragenter"), TrustedEventsAtSystemGroupBubble()); elmP->AddEventListenerByType(this, NS_LITERAL_STRING("dragover"), TrustedEventsAtSystemGroupBubble()); elmP->AddEventListenerByType(this, NS_LITERAL_STRING("dragexit"), TrustedEventsAtSystemGroupBubble()); elmP->AddEventListenerByType(this, NS_LITERAL_STRING("drop"), TrustedEventsAtSystemGroupBubble()); // XXX We should add the mouse event listeners as system event group. // E.g., web applications cannot prevent middle mouse paste by // preventDefault() of click event at bubble phase. // However, if we do so, all click handlers in any frames and frontend // code need to check if it's editable. It makes easier create new bugs. elmP->AddEventListenerByType(this, NS_LITERAL_STRING("mousedown"), TrustedEventsAtCapture()); elmP->AddEventListenerByType(this, NS_LITERAL_STRING("mouseup"), TrustedEventsAtCapture()); elmP->AddEventListenerByType(this, NS_LITERAL_STRING("click"), TrustedEventsAtCapture()); // Focus event doesn't bubble so adding the listener to capturing phase. // Make sure this works after bug 235441 gets fixed. elmP->AddEventListenerByType(this, NS_LITERAL_STRING("blur"), TrustedEventsAtCapture()); elmP->AddEventListenerByType(this, NS_LITERAL_STRING("focus"), TrustedEventsAtCapture()); elmP->AddEventListenerByType(this, NS_LITERAL_STRING("text"), TrustedEventsAtSystemGroupBubble()); elmP->AddEventListenerByType(this, NS_LITERAL_STRING("compositionstart"), TrustedEventsAtSystemGroupBubble()); elmP->AddEventListenerByType(this, NS_LITERAL_STRING("compositionend"), TrustedEventsAtSystemGroupBubble()); return NS_OK; }