static void DispatchSelectionStateChangedEvent(nsIPresShell* aPresShell, nsISelection* aSel, const dom::Sequence<SelectionState>& aStates) { nsIDocument* doc = aPresShell->GetDocument(); MOZ_ASSERT(doc); SelectionStateChangedEventInit init; init.mBubbles = true; if (aSel) { Selection* selection = static_cast<Selection*>(aSel); nsRect rect = GetSelectionBoundingRect(selection, doc->GetShell()); nsRefPtr<DOMRect>domRect = new DOMRect(ToSupports(doc)); domRect->SetLayoutRect(rect); init.mBoundingClientRect = domRect; selection->Stringify(init.mSelectedText); } init.mStates = aStates; nsRefPtr<SelectionStateChangedEvent> event = SelectionStateChangedEvent::Constructor(doc, NS_LITERAL_STRING("mozselectionstatechanged"), init); event->SetTrusted(true); event->GetInternalNSEvent()->mFlags.mOnlyChromeDispatch = true; bool ret; doc->DispatchEvent(event, &ret); }
void AccessibleCaretManager::DispatchCaretStateChangedEvent(CaretChangedReason aReason) const { // Holding PresShell to prevent AccessibleCaretManager to be destroyed. nsCOMPtr<nsIPresShell> presShell = mPresShell; FlushLayout(); if (presShell->IsDestroying()) { return; } Selection* sel = GetSelection(); if (!sel) { return; } nsIDocument* doc = mPresShell->GetDocument(); MOZ_ASSERT(doc); CaretStateChangedEventInit init; init.mBubbles = true; const nsRange* range = sel->GetAnchorFocusRange(); nsINode* commonAncestorNode = nullptr; if (range) { commonAncestorNode = range->GetCommonAncestor(); } if (!commonAncestorNode) { commonAncestorNode = sel->GetFrameSelection()->GetAncestorLimiter(); } RefPtr<DOMRect> domRect = new DOMRect(ToSupports(doc)); nsRect rect = nsLayoutUtils::GetSelectionBoundingRect(sel); nsIFrame* commonAncestorFrame = nullptr; nsIFrame* rootFrame = mPresShell->GetRootFrame(); if (commonAncestorNode && commonAncestorNode->IsContent()) { commonAncestorFrame = commonAncestorNode->AsContent()->GetPrimaryFrame(); } if (commonAncestorFrame && rootFrame) { nsLayoutUtils::TransformRect(rootFrame, commonAncestorFrame, rect); nsRect clampedRect = nsLayoutUtils::ClampRectToScrollFrames(commonAncestorFrame, rect); nsLayoutUtils::TransformRect(commonAncestorFrame, rootFrame, clampedRect); domRect->SetLayoutRect(clampedRect); init.mSelectionVisible = !clampedRect.IsEmpty(); } else { domRect->SetLayoutRect(rect); init.mSelectionVisible = true; } // Send isEditable info w/ event detail. This info can help determine // whether to show cut command on selection dialog or not. init.mSelectionEditable = commonAncestorFrame && GetEditingHostForFrame(commonAncestorFrame); init.mBoundingClientRect = domRect; init.mReason = aReason; init.mCollapsed = sel->IsCollapsed(); init.mCaretVisible = mFirstCaret->IsLogicallyVisible() || mSecondCaret->IsLogicallyVisible(); init.mCaretVisuallyVisible = mFirstCaret->IsVisuallyVisible() || mSecondCaret->IsVisuallyVisible(); sel->Stringify(init.mSelectedTextContent); RefPtr<CaretStateChangedEvent> event = CaretStateChangedEvent::Constructor(doc, NS_LITERAL_STRING("mozcaretstatechanged"), init); event->SetTrusted(true); event->GetInternalNSEvent()->mFlags.mOnlyChromeDispatch = true; AC_LOG("%s: reason %d, collapsed %d, caretVisible %d", __FUNCTION__, init.mReason, init.mCollapsed, init.mCaretVisible); (new AsyncEventDispatcher(doc, event))->RunDOMEventWhenSafe(); }