LCOV - code coverage report
Current view: top level - dom/base - SelectionChangeListener.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 59 85 69.4 %
Date: 2017-07-14 16:53:18 Functions: 6 10 60.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
       2             : /* vim: set ts=2 sw=2 et tw=78: */
       3             : /* This Source Code Form is subject to the terms of the Mozilla Public
       4             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       5             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
       6             : 
       7             : /*
       8             :  * Implementation of mozilla::dom::SelectionChangeListener
       9             :  */
      10             : 
      11             : #include "SelectionChangeListener.h"
      12             : 
      13             : #include "nsContentUtils.h"
      14             : #include "nsFrameSelection.h"
      15             : #include "nsRange.h"
      16             : #include "Selection.h"
      17             : 
      18             : using namespace mozilla;
      19             : using namespace mozilla::dom;
      20             : 
      21          15 : SelectionChangeListener::RawRangeData::RawRangeData(const nsRange* aRange)
      22             : {
      23          30 :   mozilla::ErrorResult rv;
      24          15 :   mStartContainer = aRange->GetStartContainer(rv);
      25          15 :   rv.SuppressException();
      26          15 :   mEndContainer = aRange->GetEndContainer(rv);
      27          15 :   rv.SuppressException();
      28          15 :   mStartOffset = aRange->GetStartOffset(rv);
      29          15 :   rv.SuppressException();
      30          15 :   mEndOffset = aRange->GetEndOffset(rv);
      31          15 :   rv.SuppressException();
      32          15 : }
      33             : 
      34             : bool
      35           3 : SelectionChangeListener::RawRangeData::Equals(const nsRange* aRange)
      36             : {
      37           6 :   mozilla::ErrorResult rv;
      38           3 :   bool eq = mStartContainer == aRange->GetStartContainer(rv);
      39           3 :   rv.SuppressException();
      40           3 :   eq = eq && mEndContainer == aRange->GetEndContainer(rv);
      41           3 :   rv.SuppressException();
      42           3 :   eq = eq && mStartOffset == aRange->GetStartOffset(rv);
      43           3 :   rv.SuppressException();
      44           3 :   eq = eq && mEndOffset == aRange->GetEndOffset(rv);
      45           3 :   rv.SuppressException();
      46           6 :   return eq;
      47             : }
      48             : 
      49             : inline void
      50           0 : ImplCycleCollectionTraverse(nsCycleCollectionTraversalCallback& aCallback,
      51             :                             SelectionChangeListener::RawRangeData& aField,
      52             :                             const char* aName,
      53             :                             uint32_t aFlags = 0)
      54             : {
      55           0 :   ImplCycleCollectionTraverse(aCallback, aField.mStartContainer,
      56           0 :                               "mStartContainer", aFlags);
      57           0 :   ImplCycleCollectionTraverse(aCallback, aField.mEndContainer,
      58           0 :                               "mEndContainer", aFlags);
      59           0 : }
      60             : 
      61             : NS_IMPL_CYCLE_COLLECTION_CLASS(SelectionChangeListener)
      62             : 
      63           0 : NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(SelectionChangeListener)
      64           0 :   tmp->mOldRanges.Clear();
      65           0 : NS_IMPL_CYCLE_COLLECTION_UNLINK_END
      66             : 
      67           0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(SelectionChangeListener)
      68           0 :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mOldRanges);
      69           0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
      70             : 
      71          64 : NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(SelectionChangeListener)
      72          32 :   NS_INTERFACE_MAP_ENTRY(nsISupports)
      73          32 :   NS_INTERFACE_MAP_ENTRY(nsISelectionListener)
      74           0 : NS_INTERFACE_MAP_END
      75             : 
      76         119 : NS_IMPL_CYCLE_COLLECTING_ADDREF(SelectionChangeListener)
      77          87 : NS_IMPL_CYCLE_COLLECTING_RELEASE(SelectionChangeListener)
      78             : 
      79             : NS_IMETHODIMP
      80          23 : SelectionChangeListener::NotifySelectionChanged(nsIDOMDocument* aDoc,
      81             :                                                 nsISelection* aSel, int16_t aReason)
      82             : {
      83          46 :   RefPtr<Selection> sel = aSel->AsSelection();
      84             : 
      85          23 :   nsIDocument* doc = sel->GetParentObject();
      86          29 :   if (!(doc && nsContentUtils::IsSystemPrincipal(doc->NodePrincipal())) &&
      87           6 :       !nsFrameSelection::sSelectionEventsEnabled) {
      88           0 :     return NS_OK;
      89             :   }
      90             : 
      91             :   // Check if the ranges have actually changed
      92             :   // Don't bother checking this if we are hiding changes.
      93          23 :   if (mOldRanges.Length() == sel->RangeCount() && !sel->IsBlockingSelectionChangeEvents()) {
      94           5 :     bool changed = false;
      95             : 
      96           5 :     for (size_t i = 0; i < mOldRanges.Length(); i++) {
      97           3 :       if (!mOldRanges[i].Equals(sel->GetRangeAt(i))) {
      98           3 :         changed = true;
      99           3 :         break;
     100             :       }
     101             :     }
     102             : 
     103           5 :     if (!changed) {
     104           2 :       return NS_OK;
     105             :     }
     106             :   }
     107             : 
     108             :   // The ranges have actually changed, update the mOldRanges array
     109          21 :   mOldRanges.ClearAndRetainStorage();
     110          36 :   for (size_t i = 0; i < sel->RangeCount(); i++) {
     111          15 :     mOldRanges.AppendElement(RawRangeData(sel->GetRangeAt(i)));
     112             :   }
     113             : 
     114          21 :   if (doc) {
     115          21 :     nsPIDOMWindowInner* inner = doc->GetInnerWindow();
     116          21 :     if (inner && !inner->HasSelectionChangeEventListeners()) {
     117          17 :       return NS_OK;
     118             :     }
     119             :   }
     120             : 
     121             :   // If we are hiding changes, then don't do anything else. We do this after we
     122             :   // update mOldRanges so that changes after the changes stop being hidden don't
     123             :   // incorrectly trigger a change, even though they didn't change anything
     124           4 :   if (sel->IsBlockingSelectionChangeEvents()) {
     125           0 :     return NS_OK;
     126             :   }
     127             : 
     128             :   // The spec currently doesn't say that we should dispatch this event on text
     129             :   // controls, so for now we only support doing that under a pref, disabled by
     130             :   // default.
     131             :   // See https://github.com/w3c/selection-api/issues/53.
     132           4 :   if (nsFrameSelection::sSelectionEventsOnTextControlsEnabled) {
     133           8 :     nsCOMPtr<nsINode> target;
     134             : 
     135             :     // Check if we should be firing this event to a different node than the
     136             :     // document. The limiter of the nsFrameSelection will be within the native
     137             :     // anonymous subtree of the node we want to fire the event on. We need to
     138             :     // climb up the parent chain to escape the native anonymous subtree, and then
     139             :     // fire the event.
     140           4 :     if (const nsFrameSelection* fs = sel->GetFrameSelection()) {
     141           8 :       if (nsCOMPtr<nsIContent> root = fs->GetLimiter()) {
     142           0 :         while (root && root->IsInNativeAnonymousSubtree()) {
     143           0 :           root = root->GetParent();
     144             :         }
     145             : 
     146           0 :         target = root.forget();
     147             :       }
     148             :     }
     149             : 
     150             :     // If we didn't get a target before, we can instead fire the event at the document.
     151           4 :     if (!target) {
     152           8 :       nsCOMPtr<nsIDocument> doc = do_QueryInterface(aDoc);
     153           4 :       target = doc.forget();
     154             :     }
     155             : 
     156           4 :     if (target) {
     157             :       RefPtr<AsyncEventDispatcher> asyncDispatcher =
     158          12 :         new AsyncEventDispatcher(target, eSelectionChange, false);
     159           4 :       asyncDispatcher->PostDOMEvent();
     160             :     }
     161             :   } else {
     162           0 :     if (const nsFrameSelection* fs = sel->GetFrameSelection()) {
     163           0 :       if (nsCOMPtr<nsIContent> root = fs->GetLimiter()) {
     164           0 :         if (root->IsInNativeAnonymousSubtree()) {
     165           0 :           return NS_OK;
     166             :         }
     167             :       }
     168             :     }
     169             : 
     170           0 :     nsCOMPtr<nsIDocument> doc = do_QueryInterface(aDoc);
     171           0 :     if (doc) {
     172             :       RefPtr<AsyncEventDispatcher> asyncDispatcher =
     173           0 :         new AsyncEventDispatcher(doc, eSelectionChange, false);
     174           0 :       asyncDispatcher->PostDOMEvent();
     175             :     }
     176             :   }
     177             : 
     178           4 :   return NS_OK;
     179             : }

Generated by: LCOV version 1.13