Fixing `ContentSubtreeIterator` bugs makes stop failing in some cases. Then, `AbstractRange::CollectClientRectsAndText()` is changed and `Highlight::RangesAtPoint()` starts appending ranges in a shadow which is covered by an assigned node of a `<slot>` in the shadow since selecting a `<slot>` succeeds the hit-testing in its assigned nodes. The failing test is: https://searchfox.org/firefox-main/rev/eec2f8dc61cc9f851fe5303cc05fc015d3128e6f/testing/web-platform/tests/shadow-dom/HighlightRegistry-highlightsFromPoint.html#170-174,176-181,185-187,197-201 Differential Revision: https://phabricator.services.mozilla.com/D307951
231 lines
7.0 KiB
C++
231 lines
7.0 KiB
C++
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
|
|
#ifndef mozilla_dom_Highlight_h
|
|
#define mozilla_dom_Highlight_h
|
|
|
|
#include "mozilla/Attributes.h"
|
|
#include "mozilla/dom/BindingDeclarations.h"
|
|
#include "mozilla/dom/HighlightBinding.h"
|
|
#include "nsAtomHashKeys.h"
|
|
#include "nsCycleCollectionParticipant.h"
|
|
#include "nsTArray.h"
|
|
#include "nsTHashSet.h"
|
|
#include "nsWrapperCache.h"
|
|
|
|
class nsFrameSelection;
|
|
class nsPIDOMWindowInner;
|
|
namespace mozilla {
|
|
class ErrorResult;
|
|
}
|
|
|
|
namespace mozilla::dom {
|
|
class AbstractRange;
|
|
class Document;
|
|
class Element;
|
|
class HighlightRegistry;
|
|
class Selection;
|
|
class ShadowRoot;
|
|
|
|
/**
|
|
* @brief Collection of all data of a highlight instance.
|
|
*
|
|
* This struct is intended to be allocated on the stack and passed on
|
|
* to the `nsFrameSelection` and layout code.
|
|
*/
|
|
struct HighlightSelectionData {
|
|
RefPtr<nsAtom> mHighlightName;
|
|
RefPtr<Highlight> mHighlight;
|
|
};
|
|
|
|
/**
|
|
* @brief Representation of a custom `Highlight`.
|
|
*
|
|
* A `Highlight` is defined in JS as a collection of `AbstractRange`s.
|
|
* Furthermore, a custom highlight contains the highlight type and priority.
|
|
*
|
|
* A highlight is added to a document using the `HighlightRegistry` interface.
|
|
* A highlight can be added to a document using different names as well as to
|
|
* multiple `HighlightRegistries`.
|
|
* To propagate runtime changes of the highlight to its registries, an
|
|
* observer pattern is implemented.
|
|
*
|
|
* The spec defines this class as a `setlike`. To allow access and iteration
|
|
* of the setlike contents from C++, the insertion and deletion operations are
|
|
* overridden and the Ranges are also stored internally in an Array.
|
|
*
|
|
* @see https://drafts.csswg.org/css-highlight-api-1/#creation
|
|
*/
|
|
class Highlight final : public nsISupports, public nsWrapperCache {
|
|
public:
|
|
NS_DECL_CYCLE_COLLECTING_ISUPPORTS_FINAL
|
|
NS_DECL_CYCLE_COLLECTION_WRAPPERCACHE_CLASS(Highlight)
|
|
|
|
protected:
|
|
MOZ_CAN_RUN_SCRIPT Highlight(
|
|
const Sequence<OwningNonNull<AbstractRange>>& aInitialRanges,
|
|
nsPIDOMWindowInner* aWindow, ErrorResult& aRv);
|
|
~Highlight() = default;
|
|
|
|
public:
|
|
/**
|
|
* @brief Adds `this` to `aHighlightRegistry`.
|
|
*
|
|
* Highlights must know of all registry objects which contain them, so that
|
|
* the registries can be notified when a property of the Highlight changes.
|
|
*
|
|
* Since a Highlight can be part of a registry using different names,
|
|
* the name has to be provided as well.
|
|
*/
|
|
void AddToHighlightRegistry(HighlightRegistry& aHighlightRegistry,
|
|
nsAtom& aHighlightName);
|
|
|
|
/**
|
|
* @brief Removes `this` from `aHighlightRegistry`.
|
|
*/
|
|
void RemoveFromHighlightRegistry(HighlightRegistry& aHighlightRegistry,
|
|
nsAtom& aHighlightName);
|
|
|
|
// WebIDL interface
|
|
nsPIDOMWindowInner* GetParentObject() const { return mWindow; }
|
|
|
|
JSObject* WrapObject(JSContext* aCx,
|
|
JS::Handle<JSObject*> aGivenProto) override;
|
|
|
|
static MOZ_CAN_RUN_SCRIPT_BOUNDARY already_AddRefed<Highlight> Constructor(
|
|
const GlobalObject& aGlobal,
|
|
const Sequence<OwningNonNull<AbstractRange>>& aInitialRanges,
|
|
ErrorResult& aRv);
|
|
|
|
/**
|
|
* @brief Priority of this highlight.
|
|
*
|
|
* Priority is used to stack overlapping highlights.
|
|
*/
|
|
int32_t Priority() const { return mPriority; }
|
|
|
|
/**
|
|
* @brief Set the priority of this Highlight.
|
|
*
|
|
* Priority is used to stack overlapping highlights.
|
|
*/
|
|
void SetPriority(int32_t aPriority);
|
|
|
|
/**
|
|
* @brief The HighlightType of this Highlight (Highlight, Spelling Error,
|
|
* Grammar Error)
|
|
*/
|
|
HighlightType Type() const { return mHighlightType; }
|
|
|
|
/**
|
|
* @brief Sets the HighlightType (Highlight, Spelling Error, Grammar Error)
|
|
*/
|
|
void SetType(HighlightType aHighlightType);
|
|
|
|
/**
|
|
* @brief This mirrors the `size` property in JS world (_not_ exposed via
|
|
* webIDL)
|
|
*/
|
|
uint32_t Size() const { return mRanges.Length(); }
|
|
|
|
/**
|
|
* @brief Access to the ranges for frame selection population.
|
|
*/
|
|
const nsTArray<RefPtr<AbstractRange>>& Ranges() const { return mRanges; }
|
|
|
|
/**
|
|
* @brief Adds a `Range` to this highlight.
|
|
*
|
|
* This adds `aRange` both to the setlike data storage and the internal one
|
|
* needed for iteration, if it is not yet present.
|
|
*
|
|
* Also notifies all `HighlightRegistry` instances.
|
|
*/
|
|
MOZ_CAN_RUN_SCRIPT Highlight* Add(AbstractRange& aRange, ErrorResult& aRv);
|
|
|
|
/**
|
|
* @brief Removes all ranges from this highlight.
|
|
*
|
|
* This removes all highlights from the setlike data structure as well as from
|
|
* the internal one.
|
|
*
|
|
* Also notifies all `HighlightRegistry` instances.
|
|
*/
|
|
MOZ_CAN_RUN_SCRIPT void Clear(ErrorResult& aRv);
|
|
|
|
/**
|
|
* @brief Removes `aRange` from this highlight.
|
|
*
|
|
* This removes `aRange` from the setlike data structure as well as from the
|
|
* internal one.
|
|
*
|
|
* Also notifies all `HighlightRegistry` instances.
|
|
*
|
|
* @return As per spec, returns true if the range was deleted.
|
|
*/
|
|
MOZ_CAN_RUN_SCRIPT bool Delete(AbstractRange& aRange, ErrorResult& aRv);
|
|
|
|
/**
|
|
* @brief Returns ranges of this highlight present at the given point.
|
|
*
|
|
* This method uses `range.getClientRects()` to determine if a range is
|
|
* present at the given point.
|
|
* Ranges in a shadow tree are only considered if the shadow root is in
|
|
* `aShadowRoots`. If `aPointShadowRoot` is non-null, only ranges in that
|
|
* shadow tree are considered (the point itself is inside it).
|
|
*
|
|
* @param aX x coordinate
|
|
* @param aY y coordinate
|
|
* @param aShadowRoots List of shadow roots to consider
|
|
* @param aElementAtPoint The element at the hit-tested point.
|
|
*/
|
|
nsTArray<RefPtr<AbstractRange>> RangesAtPoint(
|
|
float aX, float aY,
|
|
const Sequence<OwningNonNull<mozilla::dom::ShadowRoot>>& aShadowRoots,
|
|
mozilla::dom::Element* aElementAtPoint) const;
|
|
|
|
private:
|
|
void Repaint();
|
|
|
|
RefPtr<nsPIDOMWindowInner> mWindow;
|
|
|
|
/**
|
|
* All Range objects contained in this highlight.
|
|
*/
|
|
nsTArray<RefPtr<AbstractRange>> mRanges;
|
|
|
|
/**
|
|
* Type of this highlight.
|
|
* @see HighlightType
|
|
*/
|
|
HighlightType mHighlightType{HighlightType::Highlight};
|
|
|
|
/**
|
|
* Priority of this highlight.
|
|
*
|
|
* If highlights are overlapping, the priority can
|
|
* be used to prioritize. If the priorities of all
|
|
* Highlights involved are equal, the highlights are
|
|
* stacked in order of ther insertion into the
|
|
* `HighlightRegistry`.
|
|
*/
|
|
int32_t mPriority{0};
|
|
|
|
/**
|
|
* All highlight registries that contain this Highlight.
|
|
*
|
|
* A highlight can be included in several registries
|
|
* using several names.
|
|
*
|
|
* Note: Storing `HighlightRegistry` as raw pointer is safe here
|
|
* because it unregisters itself from `this` when it is destroyed/CC'd
|
|
*/
|
|
nsTHashMap<nsPtrHashKey<HighlightRegistry>, nsTHashSet<RefPtr<nsAtom>>>
|
|
mHighlightRegistries;
|
|
};
|
|
|
|
} // namespace mozilla::dom
|
|
|
|
#endif // mozilla_dom_Highlight_h
|