LCOV - code coverage report
Current view: top level - accessible/base - SelectionManager.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 1 102 1.0 %
Date: 2017-07-14 16:53:18 Functions: 2 14 14.3 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
       2             : /* This Source Code Form is subject to the terms of the Mozilla Public
       3             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       4             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
       5             : 
       6             : #include "mozilla/a11y/SelectionManager.h"
       7             : 
       8             : #include "DocAccessible-inl.h"
       9             : #include "HyperTextAccessible.h"
      10             : #include "HyperTextAccessible-inl.h"
      11             : #include "nsAccessibilityService.h"
      12             : #include "nsAccUtils.h"
      13             : #include "nsCoreUtils.h"
      14             : #include "nsEventShell.h"
      15             : #include "nsFrameSelection.h"
      16             : 
      17             : #include "nsIAccessibleTypes.h"
      18             : #include "nsIDOMDocument.h"
      19             : #include "nsIPresShell.h"
      20             : #include "mozilla/dom/Selection.h"
      21             : #include "mozilla/dom/Element.h"
      22             : 
      23             : using namespace mozilla;
      24             : using namespace mozilla::a11y;
      25             : using mozilla::dom::Selection;
      26             : 
      27             : struct mozilla::a11y::SelData final
      28             : {
      29           0 :   SelData(Selection* aSel, int32_t aReason) :
      30           0 :     mSel(aSel), mReason(aReason) {}
      31             : 
      32             :   RefPtr<Selection> mSel;
      33             :   int16_t mReason;
      34             : 
      35           0 :   NS_INLINE_DECL_REFCOUNTING(SelData)
      36             : 
      37             : private:
      38             :   // Private destructor, to discourage deletion outside of Release():
      39           0 :   ~SelData() {}
      40             : };
      41             : 
      42           0 : SelectionManager::SelectionManager() :
      43           0 :   mCaretOffset(-1), mAccWithCaret(nullptr)
      44             : {
      45             : 
      46           0 : }
      47             : 
      48             : void
      49           0 : SelectionManager::ClearControlSelectionListener()
      50             : {
      51           0 :   if (!mCurrCtrlFrame)
      52           0 :     return;
      53             : 
      54           0 :   const nsFrameSelection* frameSel = mCurrCtrlFrame->GetConstFrameSelection();
      55           0 :   NS_ASSERTION(frameSel, "No frame selection for the element!");
      56             : 
      57           0 :   mCurrCtrlFrame = nullptr;
      58           0 :   if (!frameSel)
      59           0 :     return;
      60             : 
      61             :   // Remove 'this' registered as selection listener for the normal selection.
      62           0 :   Selection* normalSel = frameSel->GetSelection(SelectionType::eNormal);
      63           0 :   normalSel->RemoveSelectionListener(this);
      64             : 
      65             :   // Remove 'this' registered as selection listener for the spellcheck
      66             :   // selection.
      67           0 :   Selection* spellSel = frameSel->GetSelection(SelectionType::eSpellCheck);
      68           0 :   spellSel->RemoveSelectionListener(this);
      69             : }
      70             : 
      71             : void
      72           0 : SelectionManager::SetControlSelectionListener(dom::Element* aFocusedElm)
      73             : {
      74             :   // When focus moves such that the caret is part of a new frame selection
      75             :   // this removes the old selection listener and attaches a new one for
      76             :   // the current focus.
      77           0 :   ClearControlSelectionListener();
      78             : 
      79           0 :   mCurrCtrlFrame = aFocusedElm->GetPrimaryFrame();
      80           0 :   if (!mCurrCtrlFrame)
      81           0 :     return;
      82             : 
      83           0 :   const nsFrameSelection* frameSel = mCurrCtrlFrame->GetConstFrameSelection();
      84           0 :   NS_ASSERTION(frameSel, "No frame selection for focused element!");
      85           0 :   if (!frameSel)
      86           0 :     return;
      87             : 
      88             :   // Register 'this' as selection listener for the normal selection.
      89           0 :   Selection* normalSel = frameSel->GetSelection(SelectionType::eNormal);
      90           0 :   normalSel->AddSelectionListener(this);
      91             : 
      92             :   // Register 'this' as selection listener for the spell check selection.
      93           0 :   Selection* spellSel = frameSel->GetSelection(SelectionType::eSpellCheck);
      94           0 :   spellSel->AddSelectionListener(this);
      95             : }
      96             : 
      97             : void
      98           0 : SelectionManager::AddDocSelectionListener(nsIPresShell* aPresShell)
      99             : {
     100           0 :   const nsFrameSelection* frameSel = aPresShell->ConstFrameSelection();
     101             : 
     102             :   // Register 'this' as selection listener for the normal selection.
     103           0 :   Selection* normalSel = frameSel->GetSelection(SelectionType::eNormal);
     104           0 :   normalSel->AddSelectionListener(this);
     105             : 
     106             :   // Register 'this' as selection listener for the spell check selection.
     107           0 :   Selection* spellSel = frameSel->GetSelection(SelectionType::eSpellCheck);
     108           0 :   spellSel->AddSelectionListener(this);
     109           0 : }
     110             : 
     111             : void
     112           0 : SelectionManager::RemoveDocSelectionListener(nsIPresShell* aPresShell)
     113             : {
     114           0 :   const nsFrameSelection* frameSel = aPresShell->ConstFrameSelection();
     115             : 
     116             :   // Remove 'this' registered as selection listener for the normal selection.
     117           0 :   Selection* normalSel = frameSel->GetSelection(SelectionType::eNormal);
     118           0 :   normalSel->RemoveSelectionListener(this);
     119             : 
     120             :   // Remove 'this' registered as selection listener for the spellcheck
     121             :   // selection.
     122           0 :   Selection* spellSel = frameSel->GetSelection(SelectionType::eSpellCheck);
     123           0 :   spellSel->RemoveSelectionListener(this);
     124           0 : }
     125             : 
     126             : void
     127           0 : SelectionManager::ProcessTextSelChangeEvent(AccEvent* aEvent)
     128             : {
     129             :   // Fire selection change event if it's not pure caret-move selection change,
     130             :   // i.e. the accessible has or had not collapsed selection.
     131           0 :   AccTextSelChangeEvent* event = downcast_accEvent(aEvent);
     132           0 :   if (!event->IsCaretMoveOnly())
     133           0 :     nsEventShell::FireEvent(aEvent);
     134             : 
     135             :   // Fire caret move event if there's a caret in the selection.
     136             :   nsINode* caretCntrNode =
     137           0 :     nsCoreUtils::GetDOMNodeFromDOMPoint(event->mSel->GetFocusNode(),
     138           0 :                                         event->mSel->FocusOffset());
     139           0 :   if (!caretCntrNode)
     140           0 :     return;
     141             : 
     142           0 :   HyperTextAccessible* caretCntr = nsAccUtils::GetTextContainer(caretCntrNode);
     143           0 :   NS_ASSERTION(caretCntr,
     144             :                "No text container for focus while there's one for common ancestor?!");
     145           0 :   if (!caretCntr)
     146           0 :     return;
     147             : 
     148           0 :   Selection* selection = caretCntr->DOMSelection();
     149             : 
     150             :   // XXX Sometimes we can't get a selection for caretCntr, in that case assume
     151             :   // event->mSel is correct.
     152           0 :   if (!selection)
     153           0 :     selection = event->mSel;
     154             : 
     155           0 :   mCaretOffset = caretCntr->DOMPointToOffset(selection->GetFocusNode(),
     156           0 :                                              selection->FocusOffset());
     157           0 :   mAccWithCaret = caretCntr;
     158           0 :   if (mCaretOffset != -1) {
     159             :     RefPtr<AccCaretMoveEvent> caretMoveEvent =
     160           0 :       new AccCaretMoveEvent(caretCntr, mCaretOffset, aEvent->FromUserInput());
     161           0 :     nsEventShell::FireEvent(caretMoveEvent);
     162             :   }
     163             : }
     164             : 
     165             : NS_IMETHODIMP
     166           0 : SelectionManager::NotifySelectionChanged(nsIDOMDocument* aDOMDocument,
     167             :                                          nsISelection* aSelection,
     168             :                                          int16_t aReason)
     169             : {
     170           0 :   if (NS_WARN_IF(!aDOMDocument) || NS_WARN_IF(!aSelection)) {
     171           0 :     return NS_ERROR_INVALID_ARG;
     172             :   }
     173             : 
     174           0 :   nsCOMPtr<nsIDocument> documentNode(do_QueryInterface(aDOMDocument));
     175           0 :   DocAccessible* document = GetAccService()->GetDocAccessible(documentNode);
     176             : 
     177             : #ifdef A11Y_LOG
     178           0 :   if (logging::IsEnabled(logging::eSelection))
     179           0 :     logging::SelChange(aSelection, document, aReason);
     180             : #endif
     181             : 
     182           0 :   if (document) {
     183             :     // Selection manager has longer lifetime than any document accessible,
     184             :     // so that we are guaranteed that the notification is processed before
     185             :     // the selection manager is destroyed.
     186             :     RefPtr<SelData> selData =
     187           0 :       new SelData(aSelection->AsSelection(), aReason);
     188             :     document->HandleNotification<SelectionManager, SelData>
     189           0 :       (this, &SelectionManager::ProcessSelectionChanged, selData);
     190             :   }
     191             : 
     192           0 :   return NS_OK;
     193             : }
     194             : 
     195             : void
     196           0 : SelectionManager::ProcessSelectionChanged(SelData* aSelData)
     197             : {
     198           0 :   Selection* selection = aSelData->mSel;
     199           0 :   if (!selection->GetPresShell())
     200           0 :     return;
     201             : 
     202           0 :   const nsRange* range = selection->GetAnchorFocusRange();
     203           0 :   nsINode* cntrNode = nullptr;
     204           0 :   if (range)
     205           0 :     cntrNode = range->GetCommonAncestor();
     206             : 
     207           0 :   if (!cntrNode) {
     208           0 :     cntrNode = selection->GetFrameSelection()->GetAncestorLimiter();
     209           0 :     if (!cntrNode) {
     210           0 :       cntrNode = selection->GetPresShell()->GetDocument();
     211           0 :       NS_ASSERTION(aSelData->mSel->GetPresShell()->ConstFrameSelection() == selection->GetFrameSelection(),
     212             :                    "Wrong selection container was used!");
     213             :     }
     214             :   }
     215             : 
     216           0 :   HyperTextAccessible* text = nsAccUtils::GetTextContainer(cntrNode);
     217           0 :   if (!text) {
     218           0 :     NS_NOTREACHED("We must reach document accessible implementing text interface!");
     219           0 :     return;
     220             :   }
     221             : 
     222           0 :   if (selection->GetType() == SelectionType::eNormal) {
     223             :     RefPtr<AccEvent> event =
     224           0 :       new AccTextSelChangeEvent(text, selection, aSelData->mReason);
     225           0 :     text->Document()->FireDelayedEvent(event);
     226             : 
     227           0 :   } else if (selection->GetType() == SelectionType::eSpellCheck) {
     228             :     // XXX: fire an event for container accessible of the focus/anchor range
     229             :     // of the spelcheck selection.
     230           0 :     text->Document()->FireDelayedEvent(nsIAccessibleEvent::EVENT_TEXT_ATTRIBUTE_CHANGED,
     231           0 :                                        text);
     232             :   }
     233           9 : }

Generated by: LCOV version 1.13