tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

Highlight.cpp (7159B)


      1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
      2 /* vim:set ts=2 sw=2 sts=2 et cindent: */
      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 #include "Highlight.h"
      8 
      9 #include "AbstractRange.h"
     10 #include "Document.h"
     11 #include "HighlightRegistry.h"
     12 #include "PresShell.h"
     13 #include "Selection.h"
     14 #include "mozilla/AlreadyAddRefed.h"
     15 #include "mozilla/ErrorResult.h"
     16 #include "mozilla/RefPtr.h"
     17 #include "mozilla/StaticAnalysisFunctions.h"
     18 #include "mozilla/dom/HighlightBinding.h"
     19 #include "nsFrameSelection.h"
     20 #include "nsPIDOMWindow.h"
     21 
     22 namespace mozilla::dom {
     23 
     24 NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(Highlight, mRanges, mWindow)
     25 
     26 NS_IMPL_CYCLE_COLLECTING_ADDREF(Highlight)
     27 NS_IMPL_CYCLE_COLLECTING_RELEASE(Highlight)
     28 
     29 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(Highlight)
     30  NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
     31  NS_INTERFACE_MAP_ENTRY(nsISupports)
     32 NS_INTERFACE_MAP_END
     33 
     34 Highlight::Highlight(
     35    const Sequence<OwningNonNull<AbstractRange>>& aInitialRanges,
     36    nsPIDOMWindowInner* aWindow, ErrorResult& aRv)
     37    : mWindow(aWindow) {
     38  for (RefPtr<AbstractRange> range : aInitialRanges) {
     39    Add(*range, aRv);
     40    if (aRv.Failed()) {
     41      return;
     42    }
     43  }
     44 }
     45 
     46 already_AddRefed<Highlight> Highlight::Constructor(
     47    const GlobalObject& aGlobal,
     48    const Sequence<OwningNonNull<AbstractRange>>& aInitialRanges,
     49    ErrorResult& aRv) {
     50  MOZ_ASSERT(NS_IsMainThread());
     51  nsCOMPtr<nsPIDOMWindowInner> window =
     52      do_QueryInterface(aGlobal.GetAsSupports());
     53  if (!window) {
     54    aRv.ThrowUnknownError(
     55        "There is no window associated to "
     56        "this highlight object!");
     57    return nullptr;
     58  }
     59 
     60  RefPtr<Highlight> highlight = new Highlight(aInitialRanges, window, aRv);
     61  return aRv.Failed() ? nullptr : highlight.forget();
     62 }
     63 
     64 void Highlight::AddToHighlightRegistry(HighlightRegistry& aHighlightRegistry,
     65                                       nsAtom& aHighlightName) {
     66  mHighlightRegistries.LookupOrInsert(&aHighlightRegistry)
     67      .Insert(&aHighlightName);
     68 }
     69 
     70 void Highlight::RemoveFromHighlightRegistry(
     71    HighlightRegistry& aHighlightRegistry, nsAtom& aHighlightName) {
     72  if (auto entry = mHighlightRegistries.Lookup(&aHighlightRegistry)) {
     73    auto& highlightNames = entry.Data();
     74    highlightNames.Remove(&aHighlightName);
     75    if (highlightNames.IsEmpty()) {
     76      entry.Remove();
     77    }
     78  }
     79 }
     80 
     81 already_AddRefed<Selection> Highlight::CreateHighlightSelection(
     82    nsAtom* aHighlightName, nsFrameSelection* aFrameSelection) {
     83  MOZ_ASSERT(aFrameSelection);
     84  MOZ_ASSERT(aFrameSelection->GetPresShell());
     85  RefPtr<Selection> selection =
     86      MakeRefPtr<Selection>(SelectionType::eHighlight, aFrameSelection);
     87  selection->SetHighlightSelectionData({aHighlightName, this});
     88  AutoFrameSelectionBatcher selectionBatcher(__FUNCTION__);
     89  for (const RefPtr<AbstractRange>& range : mRanges) {
     90    if (range->GetComposedDocOfContainers() ==
     91        aFrameSelection->GetPresShell()->GetDocument()) {
     92      // since this is run in a context guarded by a selection batcher,
     93      // no strong reference is needed to keep `range` alive.
     94      selection->AddHighlightRangeAndSelectFramesAndNotifyListeners(
     95          MOZ_KnownLive(*range));
     96    }
     97  }
     98  return selection.forget();
     99 }
    100 
    101 void Highlight::Repaint() {
    102  for (const RefPtr<HighlightRegistry>& registry :
    103       mHighlightRegistries.Keys()) {
    104    // since this is run in a context guarded by a selection batcher,
    105    // no strong reference is needed to keep `registry` alive.
    106    registry->RepaintHighlightSelection(*this);
    107  }
    108 }
    109 
    110 void Highlight::SetPriority(int32_t aPriority) {
    111  if (mPriority == aPriority) {
    112    return;
    113  }
    114  mPriority = aPriority;
    115  Repaint();
    116 }
    117 
    118 void Highlight::SetType(HighlightType aHighlightType) {
    119  if (mHighlightType == aHighlightType) {
    120    return;
    121  }
    122  mHighlightType = aHighlightType;
    123  Repaint();
    124 }
    125 
    126 Highlight* Highlight::Add(AbstractRange& aRange, ErrorResult& aRv) {
    127  // Manually check if the range `aKey` is already present in this highlight,
    128  // because `SetlikeHelpers::Add()` doesn't indicate this.
    129  // To keep the setlike and the mirrored array in sync, the range must not
    130  // be added to `mRanges` if it was already present.
    131  // `SetlikeHelpers::Has()` is much faster in checking this than
    132  // `nsTArray<>::Contains()`.
    133  if (Highlight_Binding::SetlikeHelpers::Has(this, aRange, aRv) ||
    134      aRv.Failed()) {
    135    return this;
    136  }
    137  Highlight_Binding::SetlikeHelpers::Add(this, aRange, aRv);
    138  if (aRv.Failed()) {
    139    return this;
    140  }
    141 
    142  MOZ_ASSERT(!mRanges.Contains(&aRange),
    143             "setlike and DOM mirror are not in sync");
    144 
    145  mRanges.AppendElement(&aRange);
    146  AutoFrameSelectionBatcher selectionBatcher(__FUNCTION__,
    147                                             mHighlightRegistries.Count());
    148  for (const RefPtr<HighlightRegistry>& registry :
    149       mHighlightRegistries.Keys()) {
    150    auto frameSelection = registry->GetFrameSelection();
    151    selectionBatcher.AddFrameSelection(frameSelection);
    152    // since this is run in a context guarded by a selection batcher,
    153    // no strong reference is needed to keep `registry` alive.
    154    MOZ_KnownLive(registry)->MaybeAddRangeToHighlightSelection(aRange, *this);
    155    if (aRv.Failed()) {
    156      return this;
    157    }
    158  }
    159  return this;
    160 }
    161 
    162 void Highlight::Clear(ErrorResult& aRv) {
    163  Highlight_Binding::SetlikeHelpers::Clear(this, aRv);
    164  if (!aRv.Failed()) {
    165    mRanges.Clear();
    166    AutoFrameSelectionBatcher selectionBatcher(__FUNCTION__,
    167                                               mHighlightRegistries.Count());
    168 
    169    for (const RefPtr<HighlightRegistry>& registry :
    170         mHighlightRegistries.Keys()) {
    171      auto frameSelection = registry->GetFrameSelection();
    172      selectionBatcher.AddFrameSelection(frameSelection);
    173      // since this is run in a context guarded by a selection batcher,
    174      // no strong reference is needed to keep `registry` alive.
    175      MOZ_KnownLive(registry)->RemoveHighlightSelection(*this);
    176    }
    177  }
    178 }
    179 
    180 bool Highlight::Delete(AbstractRange& aRange, ErrorResult& aRv) {
    181  if (Highlight_Binding::SetlikeHelpers::Delete(this, aRange, aRv)) {
    182    mRanges.RemoveElement(&aRange);
    183    AutoFrameSelectionBatcher selectionBatcher(__FUNCTION__,
    184                                               mHighlightRegistries.Count());
    185 
    186    for (const RefPtr<HighlightRegistry>& registry :
    187         mHighlightRegistries.Keys()) {
    188      auto frameSelection = registry->GetFrameSelection();
    189      selectionBatcher.AddFrameSelection(frameSelection);
    190      // since this is run in a context guarded by a selection batcher,
    191      // no strong reference is needed to keep `registry` alive.
    192      MOZ_KnownLive(registry)->MaybeRemoveRangeFromHighlightSelection(aRange,
    193                                                                      *this);
    194    }
    195    return true;
    196  }
    197  return false;
    198 }
    199 
    200 JSObject* Highlight::WrapObject(JSContext* aCx,
    201                                JS::Handle<JSObject*> aGivenProto) {
    202  return Highlight_Binding::Wrap(aCx, this, aGivenProto);
    203 }
    204 
    205 }  // namespace mozilla::dom