Bug 1803355: Basic implementation of Custom Highlight API. r=edgar,emilio

Added WebIDL interfaces as per spec, added some necessary changes to support maplike and setlike structures to be accessed from C++.

Added `::highlight(foo)` pseudo element to CSS engine.

Implemented Highlight as new kind of `Selection` using `HighlightType::eHighlight`. This implies Selections being added/removed during runtime (one `Selection` object per highlight identifier), therefore a dynamic container for highlight `Selection` objects was added to `nsFrameSelection`. Also, the painting code queries the highlight style for highlight Selections.

Implementation is currently hidden behind a pref `dom.customHighlightAPI.enabled`.

Differential Revision: https://phabricator.services.mozilla.com/D164203
This commit is contained in:
Jan-Niklas Jaeschke 2023-01-24 11:46:28 +00:00
Родитель c711b8f39b
Коммит 1b3bff372b
88 изменённых файлов: 1166 добавлений и 264 удалений

Просмотреть файл

@ -75,8 +75,11 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
// NOTE: If you need to change default value of members of AbstractRange,
// update nsRange::Create(nsINode* aNode) and ClearForReuse() too.
AbstractRange::AbstractRange(nsINode* aNode)
: mIsPositioned(false), mIsGenerated(false), mCalledByJS(false) {
AbstractRange::AbstractRange(nsINode* aNode, bool aIsDynamicRange)
: mIsPositioned(false),
mIsGenerated(false),
mCalledByJS(false),
mIsDynamicRange(aIsDynamicRange) {
Init(aNode);
}

Просмотреть файл

@ -21,15 +21,16 @@
class JSObject;
class nsIContent;
class nsINode;
class nsRange;
struct JSContext;
namespace mozilla::dom {
class StaticRange;
class Document;
class AbstractRange : public nsISupports, public nsWrapperCache {
protected:
explicit AbstractRange(nsINode* aNode);
explicit AbstractRange(nsINode* aNode, bool aIsDynamicRange);
virtual ~AbstractRange();
public:
@ -93,6 +94,12 @@ class AbstractRange : public nsISupports, public nsWrapperCache {
bool HasEqualBoundaries(const AbstractRange& aOther) const {
return (mStart == aOther.mStart) && (mEnd == aOther.mEnd);
}
bool IsDynamicRange() const { return mIsDynamicRange; }
bool IsStaticRange() const { return !mIsDynamicRange; }
inline nsRange* AsDynamicRange();
inline const nsRange* AsDynamicRange() const;
inline StaticRange* AsStaticRange();
inline const StaticRange* AsStaticRange() const;
protected:
template <typename SPT, typename SRT, typename EPT, typename ERT,
@ -122,6 +129,9 @@ class AbstractRange : public nsISupports, public nsWrapperCache {
// Used by nsRange, but this should have this for minimizing the size.
bool mCalledByJS;
// true if this is an `nsRange` object.
const bool mIsDynamicRange;
static bool sHasShutDown;
};

Просмотреть файл

@ -172,6 +172,7 @@
#include "mozilla/dom/FeaturePolicyUtils.h"
#include "mozilla/dom/FontFaceSet.h"
#include "mozilla/dom/FromParser.h"
#include "mozilla/dom/HighlightRegistry.h"
#include "mozilla/dom/HTMLAllCollection.h"
#include "mozilla/dom/HTMLBodyElement.h"
#include "mozilla/dom/HTMLCollectionBinding.h"
@ -2531,6 +2532,7 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INTERNAL(Document)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mFontFaceSet)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mReadyForIdle)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDocumentL10n)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mHighlightRegistry)
// Traverse all Document nsCOMPtrs.
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mParser)
@ -2673,6 +2675,7 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(Document)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mFontFaceSet)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mReadyForIdle)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mDocumentL10n)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mHighlightRegistry)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mParser)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mOnloadBlocker)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mDOMImplementation)
@ -6844,7 +6847,9 @@ already_AddRefed<PresShell> Document::CreatePresShell(
}
presShell->Init(aContext, aViewManager);
if (RefPtr<class HighlightRegistry> highlightRegistry = mHighlightRegistry) {
highlightRegistry->AddHighlightSelectionsToFrameSelection(IgnoreErrors());
}
// Gaining a shell causes changes in how media queries are evaluated, so
// invalidate that.
aContext->MediaFeatureValuesChanged(
@ -18104,4 +18109,11 @@ void Document::ClearOOPChildrenLoading() {
}
}
HighlightRegistry& Document::HighlightRegistry() {
if (!mHighlightRegistry) {
mHighlightRegistry = MakeRefPtr<class HighlightRegistry>(this);
}
return *mHighlightRegistry;
}
} // namespace mozilla::dom

Просмотреть файл

@ -249,6 +249,7 @@ class FeaturePolicy;
class FontFaceSet;
class FrameRequestCallback;
class ImageTracker;
class HighlightRegistry;
class HTMLAllCollection;
class HTMLBodyElement;
class HTMLInputElement;
@ -1181,8 +1182,8 @@ class Document : public nsINode,
* method is responsible for calling BeginObservingDocument() on the
* presshell if the presshell should observe document mutations.
*/
already_AddRefed<PresShell> CreatePresShell(nsPresContext* aContext,
nsViewManager* aViewManager);
MOZ_CAN_RUN_SCRIPT already_AddRefed<PresShell> CreatePresShell(
nsPresContext* aContext, nsViewManager* aViewManager);
void DeletePresShell();
PresShell* GetPresShell() const {
@ -4115,6 +4116,12 @@ class Document : public nsINode,
bool DidHitCompleteSheetCache() const { return mDidHitCompleteSheetCache; }
/**
* Get the `HighlightRegistry` which contains all highlights associated
* with this document.
*/
class HighlightRegistry& HighlightRegistry();
bool ShouldResistFingerprinting() const {
return mShouldResistFingerprinting;
}
@ -5364,6 +5371,9 @@ class Document : public nsINode,
// Not holding strong refs here since we don't actually use the BBCs.
nsTArray<const BrowserBridgeChild*> mOOPChildrenLoading;
// Registry of custom highlight definitions associated with this document.
RefPtr<class HighlightRegistry> mHighlightRegistry;
public:
// Needs to be public because the bindings code pokes at it.
JS::ExpandoAndGeneration mExpandoAndGeneration;

151
dom/base/Highlight.cpp Normal file
Просмотреть файл

@ -0,0 +1,151 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim:set ts=2 sw=2 sts=2 et cindent: */
/* 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/. */
#include "Highlight.h"
#include "HighlightRegistry.h"
#include "mozilla/dom/HighlightBinding.h"
#include "mozilla/AlreadyAddRefed.h"
#include "mozilla/ErrorResult.h"
#include "mozilla/RefPtr.h"
#include "AbstractRange.h"
#include "Document.h"
#include "PresShell.h"
#include "Selection.h"
#include "nsPIDOMWindow.h"
namespace mozilla::dom {
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(Highlight, mRanges, mWindow)
NS_IMPL_CYCLE_COLLECTING_ADDREF(Highlight)
NS_IMPL_CYCLE_COLLECTING_RELEASE(Highlight)
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(Highlight)
NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
NS_INTERFACE_MAP_ENTRY(nsISupports)
NS_INTERFACE_MAP_END
Highlight::Highlight(
const Sequence<OwningNonNull<AbstractRange>>& aInitialRanges,
nsPIDOMWindowInner* aWindow, ErrorResult& aRv)
: mWindow(aWindow) {
for (RefPtr<AbstractRange> range : aInitialRanges) {
Add(*range, aRv);
if (aRv.Failed()) {
return;
}
}
}
already_AddRefed<Highlight> Highlight::Constructor(
const GlobalObject& aGlobal,
const Sequence<OwningNonNull<AbstractRange>>& aInitialRanges,
ErrorResult& aRv) {
MOZ_ASSERT(NS_IsMainThread());
nsCOMPtr<nsPIDOMWindowInner> window =
do_QueryInterface(aGlobal.GetAsSupports());
if (!window) {
aRv.ThrowUnknownError(
"There is no window associated to "
"this highlight object!");
return nullptr;
}
RefPtr<Highlight> highlight = new Highlight(aInitialRanges, window, aRv);
return aRv.Failed() ? nullptr : highlight.forget();
}
void Highlight::AddToHighlightRegistry(HighlightRegistry& aHighlightRegistry,
const nsAtom& aHighlightName) {
mHighlightRegistries.LookupOrInsert(&aHighlightRegistry)
.Insert(&aHighlightName);
}
void Highlight::RemoveFromHighlightRegistry(
HighlightRegistry& aHighlightRegistry, const nsAtom& aHighlightName) {
if (auto entry = mHighlightRegistries.Lookup(&aHighlightRegistry)) {
auto& highlightNames = entry.Data();
highlightNames.Remove(&aHighlightName);
if (highlightNames.IsEmpty()) {
entry.Remove();
}
}
}
already_AddRefed<Selection> Highlight::CreateHighlightSelection(
const nsAtom* aHighlightName, nsFrameSelection* aFrameSelection,
ErrorResult& aRv) const {
RefPtr<Selection> selection =
MakeRefPtr<Selection>(SelectionType::eHighlight, aFrameSelection);
selection->SetHighlightName(aHighlightName);
for (auto const& range : mRanges) {
// this is safe because `Highlight::Add()` ensures all ranges are
// dynamic.
RefPtr<nsRange> dynamicRange = range->AsDynamicRange();
selection->AddRangeAndSelectFramesAndNotifyListeners(*dynamicRange, aRv);
if (aRv.Failed()) {
return nullptr;
}
}
return selection.forget();
}
void Highlight::NotifyChangesToRegistries(ErrorResult& aRv) {
for (RefPtr<HighlightRegistry> highlightRegistry :
mHighlightRegistries.Keys()) {
MOZ_ASSERT(highlightRegistry);
highlightRegistry->HighlightPropertiesChanged(*this, aRv);
if (aRv.Failed()) {
return;
}
}
}
void Highlight::Add(AbstractRange& aRange, ErrorResult& aRv) {
if (aRange.IsStaticRange()) {
// TODO (jjaschke) Selection needs to be able to deal with StaticRanges
// (Bug 1808565)
aRv.ThrowUnknownError("Support for StaticRanges is not implemented yet!");
return;
}
Highlight_Binding::SetlikeHelpers::Add(this, aRange, aRv);
if (aRv.Failed()) {
return;
}
if (!mRanges.Contains(&aRange)) {
mRanges.AppendElement(&aRange);
NotifyChangesToRegistries(aRv);
if (aRv.Failed()) {
return;
}
}
}
void Highlight::Clear(ErrorResult& aRv) {
Highlight_Binding::SetlikeHelpers::Clear(this, aRv);
if (!aRv.Failed()) {
mRanges.Clear();
NotifyChangesToRegistries(aRv);
}
}
void Highlight::Delete(AbstractRange& aRange, ErrorResult& aRv) {
if (Highlight_Binding::SetlikeHelpers::Delete(this, aRange, aRv)) {
mRanges.RemoveElement(&aRange);
NotifyChangesToRegistries(aRv);
}
}
JSObject* Highlight::WrapObject(JSContext* aCx,
JS::Handle<JSObject*> aGivenProto) {
return Highlight_Binding::Wrap(aCx, this, aGivenProto);
}
} // namespace mozilla::dom

198
dom/base/Highlight.h Normal file
Просмотреть файл

@ -0,0 +1,198 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim:set ts=2 sw=2 sts=2 et cindent: */
/* 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 "nsCycleCollectionParticipant.h"
#include "nsHashKeys.h"
#include "nsTHashSet.h"
#include "nsTArray.h"
#include "nsWrapperCache.h"
class nsFrameSelection;
class nsPIDOMWindowInner;
namespace mozilla {
class ErrorResult;
}
namespace mozilla::dom {
class AbstractRange;
class Document;
class HighlightRegistry;
class Selection;
/**
* @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
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,
const nsAtom& aHighlightName);
/**
* @brief Removes `this` from `aHighlightRegistry`.
*/
void RemoveFromHighlightRegistry(HighlightRegistry& aHighlightRegistry,
const nsAtom& aHighlightName);
/**
* @brief Creates a Highlight Selection using the given ranges.
*/
MOZ_CAN_RUN_SCRIPT already_AddRefed<Selection> CreateHighlightSelection(
const nsAtom* aHighlightName, nsFrameSelection* aFrameSelection,
ErrorResult& aRv) const;
// 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) { mPriority = 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) {
mHighlightType = aHighlightType;
}
/**
* @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 void 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.
*/
MOZ_CAN_RUN_SCRIPT void Delete(AbstractRange& aRange, ErrorResult& aRv);
private:
MOZ_CAN_RUN_SCRIPT void NotifyChangesToRegistries(ErrorResult& aRv);
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<nsRefPtrHashKey<const nsAtom>>>
mHighlightRegistries;
};
} // namespace mozilla::dom
#endif // mozilla_dom_Highlight_h

Просмотреть файл

@ -0,0 +1,176 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim:set ts=2 sw=2 sts=2 et cindent: */
/* 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/. */
#include "HighlightRegistry.h"
#include "mozilla/ErrorResult.h"
#include "mozilla/CompactPair.h"
#include "Document.h"
#include "Highlight.h"
#include "mozilla/dom/HighlightBinding.h"
#include "PresShell.h"
#include "nsAtom.h"
#include "nsCycleCollectionParticipant.h"
#include "nsFrameSelection.h"
namespace mozilla::dom {
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_CLASS(HighlightRegistry)
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(HighlightRegistry)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mDocument)
for (auto const& iter : tmp->mHighlightsOrdered) {
iter.second()->RemoveFromHighlightRegistry(*tmp, *iter.first());
}
NS_IMPL_CYCLE_COLLECTION_UNLINK(mHighlightsOrdered)
NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(HighlightRegistry)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDocument)
for (size_t i = 0; i < tmp->mHighlightsOrdered.Length(); ++i) {
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mHighlightsOrdered[i].second())
}
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
NS_IMPL_CYCLE_COLLECTING_ADDREF(HighlightRegistry)
NS_IMPL_CYCLE_COLLECTING_RELEASE(HighlightRegistry)
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(HighlightRegistry)
NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
NS_INTERFACE_MAP_ENTRY(nsISupports)
NS_INTERFACE_MAP_END
HighlightRegistry::HighlightRegistry(Document* aDocument)
: mDocument(aDocument) {}
HighlightRegistry::~HighlightRegistry() {
for (auto const& iter : mHighlightsOrdered) {
iter.second()->RemoveFromHighlightRegistry(*this, *iter.first());
}
}
JSObject* HighlightRegistry::WrapObject(JSContext* aCx,
JS::Handle<JSObject*> aGivenProto) {
return HighlightRegistry_Binding::Wrap(aCx, this, aGivenProto);
}
void HighlightRegistry::HighlightPropertiesChanged(Highlight& aHighlight,
ErrorResult& aRv) {
RefPtr<nsFrameSelection> frameSelection = GetFrameSelection();
if (!frameSelection) {
return;
}
for (auto const& iter : mHighlightsOrdered) {
if (iter.second() != &aHighlight) {
continue;
}
RefPtr<const nsAtom> highlightName = iter.first();
frameSelection->RemoveHighlightSelection(highlightName);
frameSelection->AddHighlightSelection(highlightName, aHighlight, aRv);
if (aRv.Failed()) {
return;
}
}
}
void HighlightRegistry::AddHighlightSelectionsToFrameSelection(
ErrorResult& aRv) {
if (mHighlightsOrdered.IsEmpty()) {
return;
}
RefPtr<nsFrameSelection> frameSelection = GetFrameSelection();
if (!frameSelection) {
return;
}
for (auto const& iter : mHighlightsOrdered) {
RefPtr<const nsAtom> highlightName = iter.first();
RefPtr<Highlight> highlight = iter.second();
frameSelection->AddHighlightSelection(highlightName, *highlight, aRv);
if (aRv.Failed()) {
return;
}
}
}
void HighlightRegistry::Set(const nsAString& aKey, Highlight& aValue,
ErrorResult& aRv) {
HighlightRegistry_Binding::MaplikeHelpers::Set(this, aKey, aValue, aRv);
if (aRv.Failed()) {
return;
}
RefPtr<nsFrameSelection> frameSelection = GetFrameSelection();
RefPtr<nsAtom> highlightNameAtom = NS_AtomizeMainThread(aKey);
auto foundIter =
std::find_if(mHighlightsOrdered.begin(), mHighlightsOrdered.end(),
[&highlightNameAtom](auto const& aElm) {
return aElm.first() == highlightNameAtom;
});
if (foundIter != mHighlightsOrdered.end()) {
foundIter->second()->RemoveFromHighlightRegistry(*this, *highlightNameAtom);
if (frameSelection) {
frameSelection->RemoveHighlightSelection(highlightNameAtom);
}
foundIter->second() = &aValue;
} else {
mHighlightsOrdered.AppendElement(
CompactPair<RefPtr<const nsAtom>, RefPtr<Highlight>>(highlightNameAtom,
&aValue));
}
aValue.AddToHighlightRegistry(*this, *highlightNameAtom);
if (frameSelection) {
frameSelection->AddHighlightSelection(highlightNameAtom, aValue, aRv);
}
}
void HighlightRegistry::Clear(ErrorResult& aRv) {
HighlightRegistry_Binding::MaplikeHelpers::Clear(this, aRv);
if (aRv.Failed()) {
return;
}
auto frameSelection = GetFrameSelection();
for (auto const& iter : mHighlightsOrdered) {
const auto& highlightName = iter.first();
const auto& highlight = iter.second();
highlight->RemoveFromHighlightRegistry(*this, *highlightName);
if (frameSelection) {
frameSelection->RemoveHighlightSelection(highlightName);
}
}
mHighlightsOrdered.Clear();
}
void HighlightRegistry::Delete(const nsAString& aKey, ErrorResult& aRv) {
if (!HighlightRegistry_Binding::MaplikeHelpers::Delete(this, aKey, aRv)) {
return;
}
RefPtr<nsAtom> highlightNameAtom = NS_AtomizeMainThread(aKey);
auto foundIter =
std::find_if(mHighlightsOrdered.cbegin(), mHighlightsOrdered.cend(),
[&highlightNameAtom](auto const& aElm) {
return aElm.first() == highlightNameAtom;
});
if (foundIter == mHighlightsOrdered.cend()) {
return;
}
RefPtr<Highlight> highlight = foundIter->second();
mHighlightsOrdered.RemoveElementAt(foundIter);
if (auto frameSelection = GetFrameSelection()) {
frameSelection->RemoveHighlightSelection(highlightNameAtom);
}
highlight->RemoveFromHighlightRegistry(*this, *highlightNameAtom);
}
RefPtr<nsFrameSelection> HighlightRegistry::GetFrameSelection() {
return RefPtr<nsFrameSelection>(
mDocument->GetPresShell() ? mDocument->GetPresShell()->FrameSelection()
: nullptr);
}
} // namespace mozilla::dom

Просмотреть файл

@ -0,0 +1,132 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim:set ts=2 sw=2 sts=2 et cindent: */
/* 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_HighlightRegistry_h
#define mozilla_dom_HighlightRegistry_h
#include "mozilla/Attributes.h"
#include "mozilla/CompactPair.h"
#include "mozilla/dom/BindingDeclarations.h"
#include "nsCycleCollectionParticipant.h"
#include "nsHashKeys.h"
#include "nsTHashMap.h"
#include "nsHashtablesFwd.h"
#include "nsWrapperCache.h"
class nsFrameSelection;
namespace mozilla {
class ErrorResult;
}
namespace mozilla::dom {
class Document;
class Highlight;
/**
* @brief HighlightRegistry manages all `Highlight`s available to a `Document`.
*
* This class is exposed via `HighlightRegistry.webidl` and used to
* add or remove `Highlight` instances to a document and binding it
* to a highlight name.
*
* The HighlightRegistry idl interface defines this class to be a `maplike`.
* To be able to access the members of the maplike without proper support
* for iteration from C++, the insertion and deletion operations are
* overridden and the data is also held inside of this class.
*
* @see https://drafts.csswg.org/css-highlight-api-1/#registration
*/
class HighlightRegistry final : public nsISupports, public nsWrapperCache {
public:
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
NS_DECL_CYCLE_COLLECTION_WRAPPERCACHE_CLASS(HighlightRegistry)
public:
explicit HighlightRegistry(Document* aDocument);
protected:
~HighlightRegistry();
public:
/**
* @brief Adds selections for all highlights to the `FrameSelection`.
*
* This method is called if highlights are added to the registry before
* a `FrameSelection` is available.
*/
MOZ_CAN_RUN_SCRIPT void AddHighlightSelectionsToFrameSelection(
ErrorResult& aRv);
/**
* @brief Propagates changes to a highlight to the `FrameSelection`.
*/
MOZ_CAN_RUN_SCRIPT void HighlightPropertiesChanged(Highlight& aHighlight,
ErrorResult& aRv);
// WebIDL interface
Document* GetParentObject() const { return mDocument; };
JSObject* WrapObject(JSContext* aCx,
JS::Handle<JSObject*> aGivenProto) override;
/**
* @brief Adds a new `Highlight` to `this` using `aKey` as highlight name.
*
* Highlight instances are ordered by insertion.
*
* This call registers `this` and `aHighlightName` in the highlight given in
* `aValue`.
*
* If a `FrameSelection` is present, a highlight selection is created.
*/
MOZ_CAN_RUN_SCRIPT void Set(const nsAString& aKey, Highlight& aValue,
ErrorResult& aRv);
/**
* @brief Removes all highlights from this registry.
*
* If a `FrameSelection` is present, all highlight selections are removed.
*/
void Clear(ErrorResult& aRv);
/**
* @brief Removes the highlight named `aKey` from the registry.
*
* This call removes the combination of `this` and `aKey` from the highlight.
* If a `FrameSelection` is present, the highlight selection is removed.
*/
void Delete(const nsAString& aKey, ErrorResult& aRv);
private:
/**
* @brief Get the `FrameSelection` object if available. Can return nullptr.
*/
RefPtr<nsFrameSelection> GetFrameSelection();
/**
* Parent document.
*/
RefPtr<Document> mDocument;
/**
* Highlight instances are stored as array of name-value tuples
* instead of a hashmap in order to preserve the insertion order.
*
* This is done
* a) to keep the order in sync with the underlying
* data structure of the `maplike` interface and
* b) because the insertion order defines the stacking order of
* of highlights that have the same priority.
*/
nsTArray<CompactPair<RefPtr<const nsAtom>, RefPtr<Highlight>>>
mHighlightsOrdered;
};
} // namespace mozilla::dom
#endif // mozilla_dom_HighlightRegistry_h

Просмотреть файл

@ -1697,6 +1697,7 @@ UniquePtr<SelectionDetails> Selection::LookUpSelection(
newHead->mStart = AssertedCast<int32_t>(*start);
newHead->mEnd = AssertedCast<int32_t>(*end);
newHead->mSelectionType = aSelectionType;
newHead->mHighlightName = mHighlightName;
StyledRange* rd = mStyledRanges.FindRangeData(range);
if (rd) {
newHead->mTextRangeStyle = rd->mTextRangeStyle;
@ -3701,6 +3702,11 @@ void Selection::SetColors(const nsAString& aForegroundColor,
void Selection::ResetColors(ErrorResult& aRv) { mCustomColors = nullptr; }
void Selection::SetHighlightName(const nsAtom* aHighlightName) {
MOZ_ASSERT(mSelectionType == SelectionType::eHighlight);
mHighlightName = aHighlightName;
}
JSObject* Selection::WrapObject(JSContext* aCx,
JS::Handle<JSObject*> aGivenProto) {
return mozilla::dom::Selection_Binding::Wrap(aCx, this, aGivenProto);

Просмотреть файл

@ -456,6 +456,11 @@ class Selection final : public nsSupportsWeakReference,
}
SelectionType Type() const { return mSelectionType; }
/**
* @brief Set a highlight name, if this is a highlight selection.
*/
void SetHighlightName(const nsAtom* aHighlightName);
/**
* See documentation of `GetRangesForInterval` in Selection.webidl.
*
@ -938,6 +943,7 @@ class Selection final : public nsSupportsWeakReference,
CachedOffsetForFrame* mCachedOffsetForFrame;
nsDirection mDirection;
const SelectionType mSelectionType;
RefPtr<const nsAtom> mHighlightName;
UniquePtr<SelectionCustomColors> mCustomColors;
// Non-zero if we don't want any changes we make to the selection to be

Просмотреть файл

@ -61,7 +61,8 @@ class StaticRange final : public AbstractRange {
const RangeBoundaryBase<EPT, ERT>& aEndBoundary, ErrorResult& aRv);
protected:
explicit StaticRange(nsINode* aNode) : AbstractRange(aNode) {}
explicit StaticRange(nsINode* aNode)
: AbstractRange(aNode, /* aIsDynamicRange = */ false) {}
virtual ~StaticRange() = default;
public:
@ -112,6 +113,15 @@ class StaticRange final : public AbstractRange {
friend class AbstractRange;
};
inline StaticRange* AbstractRange::AsStaticRange() {
MOZ_ASSERT(IsStaticRange());
return static_cast<StaticRange*>(this);
}
inline const StaticRange* AbstractRange::AsStaticRange() const {
MOZ_ASSERT(IsStaticRange());
return static_cast<const StaticRange*>(this);
}
} // namespace dom
} // namespace mozilla

Просмотреть файл

@ -203,6 +203,8 @@ EXPORTS.mozilla.dom += [
"FragmentOrElement.h",
"FromParser.h",
"GeneratedImageContent.h",
"Highlight.h",
"HighlightRegistry.h",
"IdleDeadline.h",
"IdleRequest.h",
"IDTracker.h",
@ -355,6 +357,8 @@ UNIFIED_SOURCES += [
"FormData.cpp",
"FragmentOrElement.cpp",
"GeneratedImageContent.cpp",
"Highlight.cpp",
"HighlightRegistry.cpp",
"IdleDeadline.cpp",
"IdleRequest.cpp",
"IDTracker.cpp",

Просмотреть файл

@ -41,8 +41,11 @@ interface nsISelectionController : nsISelectionDisplay
const short SELECTION_FIND = 8;
const short SELECTION_URLSECONDARY = 9;
const short SELECTION_URLSTRIKEOUT = 10;
// Custom Highlight API
// (see https://drafts.csswg.org/css-highlight-api-1/#enumdef-highlighttype)
const short SELECTION_HIGHLIGHT = 11;
// End of RawSelectionType values.
const short NUM_SELECTIONTYPES = 11;
const short NUM_SELECTIONTYPES = 12;
// SelectionRegion values:
const short SELECTION_ANCHOR_REGION = 0;
@ -308,6 +311,7 @@ enum class SelectionType : RawSelectionType
eFind = nsISelectionController::SELECTION_FIND,
eURLSecondary = nsISelectionController::SELECTION_URLSECONDARY,
eURLStrikeout = nsISelectionController::SELECTION_URLSTRIKEOUT,
eHighlight = nsISelectionController::SELECTION_HIGHLIGHT,
};
// Using anonymous enum to define constants because these constants may be
@ -334,6 +338,7 @@ static const SelectionType kPresentSelectionTypes[] = {
SelectionType::eFind,
SelectionType::eURLSecondary,
SelectionType::eURLStrikeout,
SelectionType::eHighlight,
};
// Please include mozilla/dom/Selection.h for the following APIs.

Просмотреть файл

@ -136,7 +136,7 @@ nsRange::~nsRange() {
}
nsRange::nsRange(nsINode* aNode)
: AbstractRange(aNode),
: AbstractRange(aNode, /* aIsDynamicRange = */ true),
mRegisteredClosestCommonInclusiveAncestor(nullptr),
mNextStartRef(nullptr),
mNextEndRef(nullptr) {

Просмотреть файл

@ -455,5 +455,14 @@ class nsRange final : public mozilla::dom::AbstractRange,
friend class mozilla::dom::AbstractRange;
};
namespace mozilla::dom {
inline nsRange* AbstractRange::AsDynamicRange() {
MOZ_ASSERT(IsDynamicRange());
return static_cast<nsRange*>(this);
}
inline const nsRange* AbstractRange::AsDynamicRange() const {
MOZ_ASSERT(IsDynamicRange());
return static_cast<const nsRange*>(this);
}
} // namespace mozilla::dom
#endif /* nsRange_h___ */

Просмотреть файл

@ -6,6 +6,7 @@
* The origin of this IDL file is
* http://dev.w3.org/csswg/css3-conditional/
* http://dev.w3.org/csswg/cssom/#the-css.escape%28%29-method
* https://www.w3.org/TR/css-highlight-api-1/#registration
*
* Copyright © 2012 W3C® (MIT, ERCIM, Keio), All Rights Reserved. W3C
* liability, trademark and document use rules apply.
@ -21,3 +22,9 @@ namespace CSS {
partial namespace CSS {
DOMString escape(DOMString ident);
};
// https://www.w3.org/TR/css-highlight-api-1/#registration
partial namespace CSS {
[Pref="dom.customHighlightAPI.enabled", GetterThrows]
readonly attribute HighlightRegistry highlights;
};

Просмотреть файл

@ -0,0 +1,71 @@
/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* 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/.
*
* The origin of this IDL file is
* https://www.w3.org/TR/css-highlight-api-1/
*
* Copyright © 2021 W3C® (MIT, ERCIM, Keio), All Rights Reserved. W3C
* liability, trademark and document use rules apply.
*/
/**
* Enum defining the available highlight types.
* See https://www.w3.org/TR/css-highlight-api-1/#enumdef-highlighttype
*/
enum HighlightType {
"highlight",
"spelling-error",
"grammar-error"
};
/**
* Definition of a highlight object, consisting of a set of ranges,
* a priority and a highlight type.
*
* See https://www.w3.org/TR/css-highlight-api-1/#highlight
*/
[Pref="dom.customHighlightAPI.enabled", Exposed=Window]
interface Highlight {
[Throws]
constructor(AbstractRange... initialRanges);
setlike<AbstractRange>;
attribute long priority;
attribute HighlightType type;
};
partial interface Highlight {
// Setlike methods need to be overridden.
// Iterating a setlike is not possible from C++ yet.
// Therefore a separate data structure must be held and kept in sync.
[Throws]
undefined add(AbstractRange range);
[Throws]
undefined clear();
[Throws]
undefined delete(AbstractRange range);
};
/**
* Registry object that contains all Highlights associated with a Document.
*
* See https://www.w3.org/TR/css-highlight-api-1/#highlightregistry
*/
[Pref="dom.customHighlightAPI.enabled", Exposed=Window]
interface HighlightRegistry {
maplike<DOMString, Highlight>;
};
partial interface HighlightRegistry {
// Maplike interface methods need to be overridden.
// Iterating a maplike is not possible from C++ yet.
// Therefore, a separate data structure must be held and kept in sync.
[Throws]
undefined set(DOMString key, Highlight value);
[Throws]
undefined clear();
[Throws]
undefined delete(DOMString key);
};

Просмотреть файл

@ -586,6 +586,7 @@ WEBIDL_FILES = [
"GetUserMediaRequest.webidl",
"Grid.webidl",
"Headers.webidl",
"Highlight.webidl",
"History.webidl",
"HTMLAllCollection.webidl",
"HTMLAnchorElement.webidl",

Просмотреть файл

@ -696,7 +696,10 @@ nsresult nsDocumentViewer::InitPresentationStuff(bool aDoInitialReflow) {
NS_ASSERTION(!mPresShell, "Someone should have destroyed the presshell!");
// Now make the shell for the document
mPresShell = mDocument->CreatePresShell(mPresContext, mViewManager);
nsCOMPtr<Document> doc = mDocument;
RefPtr<nsPresContext> presContext = mPresContext;
RefPtr<nsViewManager> viewManager = mViewManager;
mPresShell = doc->CreatePresShell(presContext, viewManager);
if (!mPresShell) {
return NS_ERROR_FAILURE;
}

Просмотреть файл

@ -73,6 +73,7 @@ static NS_DEFINE_CID(kFrameTraversalCID, NS_FRAMETRAVERSAL_CID);
#include "nsError.h"
#include "mozilla/AutoCopyListener.h"
#include "mozilla/dom/Element.h"
#include "mozilla/dom/Highlight.h"
#include "mozilla/dom/Selection.h"
#include "mozilla/dom/ShadowRoot.h"
#include "mozilla/dom/StaticRange.h"
@ -175,6 +176,7 @@ static const int8_t kIndexOfSelections[] = {
7, // SelectionType::eFind
8, // SelectionType::eURLSecondary
9, // SelectionType::eURLStrikeout
-1, // SelectionType::eHighlight
};
inline int8_t GetIndexFromSelectionType(SelectionType aSelectionType) {
@ -391,6 +393,7 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsFrameSelection)
for (size_t i = 0; i < ArrayLength(tmp->mDomSelections); ++i) {
tmp->mDomSelections[i] = nullptr;
}
tmp->mHighlightSelections.Clear();
NS_IMPL_CYCLE_COLLECTION_UNLINK(
mTableSelection.mClosestInclusiveTableCellAncestor)
@ -414,6 +417,10 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsFrameSelection)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDomSelections[i])
}
for (const auto& value : tmp->mHighlightSelections.Values()) {
CycleCollectionNoteChild(cb, value.get(), "mHighlightSelections[]");
}
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(
mTableSelection.mClosestInclusiveTableCellAncestor)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mTableSelection.mStartSelectedCell)
@ -1533,6 +1540,12 @@ UniquePtr<SelectionDetails> nsFrameSelection::LookUpSelection(
kPresentSelectionTypes[j], aSlowCheck);
}
}
for (auto const& highlightSelection : mHighlightSelections.Values()) {
details = highlightSelection->LookUpSelection(
aContent, static_cast<uint32_t>(aContentOffset),
static_cast<uint32_t>(aContentLength), std::move(details),
SelectionType::eHighlight, aSlowCheck);
}
return details;
}
@ -1564,6 +1577,21 @@ Selection* nsFrameSelection::GetSelection(SelectionType aSelectionType) const {
return mDomSelections[index];
}
void nsFrameSelection::AddHighlightSelection(
const nsAtom* aHighlightName, const mozilla::dom::Highlight& aHighlight,
ErrorResult& aRv) {
RefPtr<Selection> selection =
aHighlight.CreateHighlightSelection(aHighlightName, this, aRv);
if (aRv.Failed()) {
return;
}
mHighlightSelections.InsertOrUpdate(aHighlightName, std::move(selection));
}
void nsFrameSelection::RemoveHighlightSelection(const nsAtom* aHighlightName) {
mHighlightSelections.Remove(aHighlightName);
}
nsresult nsFrameSelection::ScrollSelectionIntoView(SelectionType aSelectionType,
SelectionRegion aRegion,
int16_t aFlags) const {

Просмотреть файл

@ -42,6 +42,7 @@ struct SelectionDetails {
int32_t mStart;
int32_t mEnd;
mozilla::SelectionType mSelectionType;
RefPtr<const nsAtom> mHighlightName;
mozilla::TextRangeStyle mTextRangeStyle;
mozilla::UniquePtr<SelectionDetails> mNext;
};
@ -189,6 +190,7 @@ struct nsPrevNextBidiLevels {
namespace mozilla {
class SelectionChangeEventDispatcher;
namespace dom {
class Highlight;
class Selection;
} // namespace dom
@ -420,6 +422,17 @@ class nsFrameSelection final {
mozilla::dom::Selection* GetSelection(
mozilla::SelectionType aSelectionType) const;
/**
* @brief Adds a highlight selection for `aHighlight`.
*/
MOZ_CAN_RUN_SCRIPT void AddHighlightSelection(
const nsAtom* aHighlightName, const mozilla::dom::Highlight& aHighlight,
mozilla::ErrorResult& aRv);
/**
* @brief Removes the Highlight selection identified by `aHighlightName`.
*/
void RemoveHighlightSelection(const nsAtom* aHighlightName);
/**
* ScrollSelectionIntoView scrolls a region of the selection,
* so that it is visible in the scrolled view.
@ -948,6 +961,9 @@ class nsFrameSelection final {
mDomSelections[sizeof(mozilla::kPresentSelectionTypes) /
sizeof(mozilla::SelectionType)];
nsTHashMap<RefPtr<const nsAtom>, RefPtr<mozilla::dom::Selection>>
mHighlightSelections;
struct TableSelection {
// Get our first range, if its first selected node is a cell. If this does
// not return null, then the first node in the returned range is a cell

Просмотреть файл

@ -2409,6 +2409,16 @@ already_AddRefed<ComputedStyle> nsIFrame::ComputeSelectionStyle(
*element, PseudoStyleType::selection, Style());
}
already_AddRefed<ComputedStyle> nsIFrame::ComputeHighlightSelectionStyle(
const nsAtom* aHighlightName) {
Element* element = FindElementAncestorForMozSelection(GetContent());
if (!element) {
return nullptr;
}
return PresContext()->StyleSet()->ProbeHighlightPseudoElementStyle(
*element, aHighlightName, Style());
}
template <typename SizeOrMaxSize>
static inline bool IsIntrinsicKeyword(const SizeOrMaxSize& aSize) {
// All keywords other than auto/none/-moz-available depend on intrinsic sizes.
@ -4814,6 +4824,7 @@ nsresult nsIFrame::MoveCaretToEventPoint(nsPresContext* aPresContext,
curDetail->mSelectionType != SelectionType::eFind &&
curDetail->mSelectionType != SelectionType::eURLSecondary &&
curDetail->mSelectionType != SelectionType::eURLStrikeout &&
curDetail->mSelectionType != SelectionType::eHighlight &&
curDetail->mStart <= offsets.StartOffset() &&
offsets.EndOffset() <= curDetail->mEnd) {
inSelection = true;

Просмотреть файл

@ -889,6 +889,9 @@ class nsIFrame : public nsQueryFrame {
already_AddRefed<ComputedStyle> ComputeSelectionStyle(
int16_t aSelectionStatus) const;
already_AddRefed<ComputedStyle> ComputeHighlightSelectionStyle(
const nsAtom* aHighlightName);
/**
* Accessor functions for geometric parent.
*/

Просмотреть файл

@ -437,6 +437,10 @@ class nsTextPaintStyle {
*/
bool GetSelectionColors(nscolor* aForeColor, nscolor* aBackColor);
void GetHighlightColors(nscolor* aForeColor, nscolor* aBackColor);
// Computes colors for custom highlights.
// Returns false if there are no rules associated with `aHighlightName`.
bool GetCustomHighlightColors(const nsAtom* aHighlightName,
nscolor* aForeColor, nscolor* aBackColor);
void GetURLSecondaryColor(nscolor* aForeColor);
void GetIMESelectionColors(int32_t aIndex, nscolor* aForeColor,
nscolor* aBackColor);
@ -498,6 +502,8 @@ class nsTextPaintStyle {
nscolor mSelectionTextColor;
nscolor mSelectionBGColor;
RefPtr<ComputedStyle> mSelectionPseudoStyle;
nsTHashMap<RefPtr<const nsAtom>, RefPtr<ComputedStyle>>
mCustomHighlightPseudoStyles;
// Common data
@ -4145,6 +4151,33 @@ void nsTextPaintStyle::GetHighlightColors(nscolor* aForeColor,
*aBackColor = NS_TRANSPARENT;
}
bool nsTextPaintStyle::GetCustomHighlightColors(const nsAtom* aHighlightName,
nscolor* aForeColor,
nscolor* aBackColor) {
NS_ASSERTION(aForeColor, "aForeColor is null");
NS_ASSERTION(aBackColor, "aBackColor is null");
// non-existing highlights will be stored as `aHighlightName->nullptr`,
// so subsequent calls only need a hashtable lookup and don't have
// to enter the style engine.
RefPtr<ComputedStyle> highlightStyle =
mCustomHighlightPseudoStyles.LookupOrInsertWith(
aHighlightName, [this, &aHighlightName] {
return mFrame->ComputeHighlightSelectionStyle(aHighlightName);
});
if (!highlightStyle) {
// highlight `aHighlightName` doesn't exist or has no style rules.
return false;
}
// this is just copied from here:
// `InitSelectionColorsAndShadow()`.
*aBackColor = highlightStyle->GetVisitedDependentColor(
&nsStyleBackground::mBackgroundColor);
*aForeColor = highlightStyle->GetVisitedDependentColor(
&nsStyleText::mWebkitTextFillColor);
return true;
}
void nsTextPaintStyle::GetURLSecondaryColor(nscolor* aForeColor) {
NS_ASSERTION(aForeColor, "aForeColor is null");
@ -6016,7 +6049,8 @@ void nsTextFrame::DrawSelectionDecorations(
case SelectionType::eIMESelectedRawClause:
case SelectionType::eIMEConvertedClause:
case SelectionType::eIMESelectedClause:
case SelectionType::eSpellCheck: {
case SelectionType::eSpellCheck:
case SelectionType::eHighlight: {
int32_t index = nsTextPaintStyle::GetUnderlineStyleIndexForSelectionType(
aSelectionType);
bool weDefineSelectionUnderline =
@ -6035,7 +6069,8 @@ void nsTextFrame::DrawSelectionDecorations(
styleText->mTextUnderlineOffset, aFontMetrics, appUnitsPerDevPixel,
this, wm.IsCentralBaseline(), swapUnderline);
bool isIMEType = aSelectionType != SelectionType::eSpellCheck;
bool isIMEType = aSelectionType != SelectionType::eSpellCheck &&
aSelectionType != SelectionType::eHighlight;
if (isIMEType) {
// IME decoration lines should not be drawn on the both ends, i.e., we
@ -6080,8 +6115,8 @@ void nsTextFrame::DrawSelectionDecorations(
else if (aRangeStyle.IsForegroundColorDefined() ||
aRangeStyle.IsBackgroundColorDefined()) {
nscolor bg;
GetSelectionTextColors(aSelectionType, aTextPaintStyle, aRangeStyle,
&params.color, &bg);
GetSelectionTextColors(aSelectionType, nullptr, aTextPaintStyle,
aRangeStyle, &params.color, &bg);
}
// Otherwise, use the foreground color of the frame.
else {
@ -6127,6 +6162,7 @@ void nsTextFrame::DrawSelectionDecorations(
/* static */
bool nsTextFrame::GetSelectionTextColors(SelectionType aSelectionType,
const nsAtom* aHighlightName,
nsTextPaintStyle& aTextPaintStyle,
const TextRangeStyle& aRangeStyle,
nscolor* aForeground,
@ -6137,6 +6173,9 @@ bool nsTextFrame::GetSelectionTextColors(SelectionType aSelectionType,
case SelectionType::eFind:
aTextPaintStyle.GetHighlightColors(aForeground, aBackground);
return true;
case SelectionType::eHighlight:
return aTextPaintStyle.GetCustomHighlightColors(aHighlightName,
aForeground, aBackground);
case SelectionType::eURLSecondary:
aTextPaintStyle.GetURLSecondaryColor(aForeground);
*aBackground = NS_RGBA(0, 0, 0, 0);
@ -6229,11 +6268,14 @@ class SelectionIterator {
* @param aHyphenWidth if a hyphen is to be rendered after the text, the
* width of the hyphen, otherwise zero
* @param aSelectionType the selection type for this segment
* @param aHighlightName name of the custom highlight if
* `aSelectionType == SelectionType::eHighlight`.
* @param aStyle the selection style for this segment
* @return false if there are no more segments
*/
bool GetNextSegment(gfxFloat* aXOffset, gfxTextRun::Range* aRange,
gfxFloat* aHyphenWidth, SelectionType* aSelectionType,
RefPtr<const nsAtom>* aHighlightName,
TextRangeStyle* aStyle);
void UpdateWithAdvance(gfxFloat aAdvance) {
mXOffset += aAdvance * mTextRun->GetDirection();
@ -6265,6 +6307,7 @@ bool SelectionIterator::GetNextSegment(gfxFloat* aXOffset,
gfxTextRun::Range* aRange,
gfxFloat* aHyphenWidth,
SelectionType* aSelectionType,
RefPtr<const nsAtom>* aHighlightName,
TextRangeStyle* aStyle) {
if (mIterator.GetOriginalOffset() >= int32_t(mOriginalRange.end))
return false;
@ -6305,6 +6348,7 @@ bool SelectionIterator::GetNextSegment(gfxFloat* aXOffset,
*aHyphenWidth = mProvider.GetHyphenWidth();
}
*aSelectionType = selectionType;
*aHighlightName = sdptr ? sdptr->mHighlightName : nullptr;
*aStyle = style;
return true;
}
@ -6456,9 +6500,9 @@ bool nsTextFrame::PaintTextWithSelectionColors(
allSelectionTypeMask |= ToSelectionTypeMask(selectionType);
// Ignore selections that don't set colors
nscolor foreground, background;
if (GetSelectionTextColors(selectionType, *aParams.textPaintStyle,
sdptr->mTextRangeStyle, &foreground,
&background)) {
if (GetSelectionTextColors(
selectionType, sdptr->mHighlightName, *aParams.textPaintStyle,
sdptr->mTextRangeStyle, &foreground, &background)) {
if (NS_GET_A(background) > 0) {
anyBackgrounds = true;
}
@ -6466,6 +6510,7 @@ bool nsTextFrame::PaintTextWithSelectionColors(
// Favour normal selection over IME selections
if (!prevailingSelections[i] ||
selectionType < prevailingSelections[i]->mSelectionType) {
// TODO ordering of highlight selections!
prevailingSelections[i] = sdptr;
}
}
@ -6496,11 +6541,14 @@ bool nsTextFrame::PaintTextWithSelectionColors(
SelectionIterator iterator(prevailingSelections, contentRange,
*aParams.provider, mTextRun, startIOffset);
SelectionType selectionType;
RefPtr<const nsAtom> highlightName;
while (iterator.GetNextSegment(&iOffset, &range, &hyphenWidth,
&selectionType, &rangeStyle)) {
&selectionType, &highlightName,
&rangeStyle)) {
nscolor foreground, background;
GetSelectionTextColors(selectionType, *aParams.textPaintStyle, rangeStyle,
&foreground, &background);
GetSelectionTextColors(selectionType, highlightName,
*aParams.textPaintStyle, rangeStyle, &foreground,
&background);
// Draw background color
gfxFloat advance =
hyphenWidth + mTextRun->GetAdvanceWidth(range, aParams.provider);
@ -6553,14 +6601,16 @@ bool nsTextFrame::PaintTextWithSelectionColors(
SelectionIterator iterator(prevailingSelections, contentRange,
*aParams.provider, mTextRun, startIOffset);
SelectionType selectionType;
RefPtr<const nsAtom> highlightName;
while (iterator.GetNextSegment(&iOffset, &range, &hyphenWidth, &selectionType,
&rangeStyle)) {
&highlightName, &rangeStyle)) {
nscolor foreground, background;
if (aParams.IsGenerateTextMask()) {
foreground = NS_RGBA(0, 0, 0, 255);
} else {
GetSelectionTextColors(selectionType, *aParams.textPaintStyle, rangeStyle,
&foreground, &background);
GetSelectionTextColors(selectionType, highlightName,
*aParams.textPaintStyle, rangeStyle, &foreground,
&background);
}
gfx::Point textBaselinePt =
@ -6662,10 +6712,12 @@ void nsTextFrame::PaintTextSelectionDecorations(
pt.y = (aParams.textBaselinePt.y - mAscent) / app;
}
SelectionType nextSelectionType;
RefPtr<const nsAtom> highlightName;
TextRangeStyle selectedStyle;
while (iterator.GetNextSegment(&iOffset, &range, &hyphenWidth,
&nextSelectionType, &selectedStyle)) {
&nextSelectionType, &highlightName,
&selectedStyle)) {
gfxFloat advance =
hyphenWidth + mTextRun->GetAdvanceWidth(range, aParams.provider);
if (nextSelectionType == aSelectionType) {
@ -6820,9 +6872,9 @@ nscolor nsTextFrame::GetCaretColorAt(int32_t aOffset) {
(selectionType == SelectionType::eNone ||
sdptr->mSelectionType < selectionType)) {
nscolor foreground, background;
if (GetSelectionTextColors(sdptr->mSelectionType, textPaintStyle,
sdptr->mTextRangeStyle, &foreground,
&background)) {
if (GetSelectionTextColors(sdptr->mSelectionType, sdptr->mHighlightName,
textPaintStyle, sdptr->mTextRangeStyle,
&foreground, &background)) {
if (!isSolidTextColor && NS_IS_SELECTION_SPECIAL_COLOR(foreground)) {
result = NS_RGBA(0, 0, 0, 255);
} else {

Просмотреть файл

@ -941,6 +941,7 @@ class nsTextFrame : public nsIFrame {
* @return true if the selection affects colors, false otherwise
*/
static bool GetSelectionTextColors(SelectionType aSelectionType,
const nsAtom* aHighlightName,
nsTextPaintStyle& aTextPaintStyle,
const TextRangeStyle& aRangeStyle,
nscolor* aForeground,

Просмотреть файл

@ -1333,8 +1333,11 @@ nsresult nsPrintJob::ReflowPrintObject(const UniquePtr<nsPrintObject>& aPO) {
// correct viewport size for the print preview page when notifying the media
// feature values changed. See au_viewport_size_for_viewport_unit_resolution()
// in media_queries.rs for more details.
aPO->mPresShell =
aPO->mDocument->CreatePresShell(aPO->mPresContext, aPO->mViewManager);
RefPtr<Document> doc = aPO->mDocument;
RefPtr<nsPresContext> presContext = aPO->mPresContext;
RefPtr<nsViewManager> viewManager = aPO->mViewManager;
aPO->mPresShell = doc->CreatePresShell(presContext, viewManager);
if (!aPO->mPresShell) {
return NS_ERROR_FAILURE;
}

Просмотреть файл

@ -9,6 +9,7 @@
#include "CSS.h"
#include "mozilla/dom/BindingDeclarations.h"
#include "mozilla/dom/HighlightRegistry.h"
#include "mozilla/ServoBindings.h"
#include "nsGlobalWindow.h"
#include "mozilla/dom/Document.h"
@ -36,5 +37,27 @@ void CSS::Escape(const GlobalObject&, const nsAString& aIdent,
nsStyleUtil::AppendEscapedCSSIdent(aIdent, aReturn);
}
/* static */
HighlightRegistry* CSS::GetHighlights(const GlobalObject& aGlobal,
ErrorResult& aRv) {
nsCOMPtr<nsPIDOMWindowInner> window =
do_QueryInterface(aGlobal.GetAsSupports());
if (!window) {
aRv.ThrowUnknownError(
"There is no window associated to "
"this highlight registry object!");
return nullptr;
}
Document* doc = window->GetExtantDoc();
if (!doc) {
aRv.ThrowUnknownError(
"There is no document associated to "
"this highlight registry object!");
return nullptr;
}
return &doc->HighlightRegistry();
}
} // namespace dom
} // namespace mozilla

Просмотреть файл

@ -19,6 +19,7 @@ class ErrorResult;
namespace dom {
class GlobalObject;
class HighlightRegistry;
class CSS {
private:
@ -32,6 +33,9 @@ class CSS {
static void Escape(const GlobalObject&, const nsAString& aIdent,
nsAString& aReturn);
static HighlightRegistry* GetHighlights(const GlobalObject& aGlobal,
ErrorResult& aRv);
};
} // namespace dom

Просмотреть файл

@ -499,6 +499,20 @@ already_AddRefed<ComputedStyle> ServoStyleSet::ResolvePseudoElementStyle(
return style.forget();
}
already_AddRefed<ComputedStyle> ServoStyleSet::ProbeHighlightPseudoElementStyle(
const dom::Element& aOriginatingElement, const nsAtom* aHighlightName,
ComputedStyle* aParentStyle) {
MOZ_ASSERT(!StylistNeedsUpdate());
MOZ_ASSERT(aHighlightName);
RefPtr<ComputedStyle> style =
Servo_ComputedValues_ResolveHighlightPseudoStyle(
&aOriginatingElement, aHighlightName, mRawSet.get())
.Consume();
return style ? style.forget() : nullptr;
}
already_AddRefed<ComputedStyle>
ServoStyleSet::ResolveInheritingAnonymousBoxStyle(PseudoStyleType aType,
ComputedStyle* aParentStyle) {

Просмотреть файл

@ -7,6 +7,7 @@
#ifndef mozilla_ServoStyleSet_h
#define mozilla_ServoStyleSet_h
#include "mozilla/AlreadyAddRefed.h"
#include "mozilla/AnonymousContentKey.h"
#include "mozilla/AtomArray.h"
#include "mozilla/EnumeratedArray.h"
@ -220,6 +221,18 @@ class ServoStyleSet {
IsProbe::Yes);
}
/**
* @brief Get a style for a highlight pseudo element.
*
* The highlight is identified by its name `aHighlightName`.
*
* Returns null if there are no rules matching for the highlight pseudo
* element.
*/
already_AddRefed<ComputedStyle> ProbeHighlightPseudoElementStyle(
const dom::Element& aOriginatingElement, const nsAtom* aHighlightName,
ComputedStyle* aParentStyle);
// Resolves style for a (possibly-pseudo) Element without assuming that the
// style has been resolved. If the element was unstyled and a new style
// was resolved, it is not stored in the DOM. (That is, the element remains

Просмотреть файл

@ -46,6 +46,7 @@ CSS_PSEUDO_ELEMENT(firstLetter, ":first-letter",
CSS_PSEUDO_ELEMENT(firstLine, ":first-line",
CSS_PSEUDO_ELEMENT_IS_CSS2 |
CSS_PSEUDO_ELEMENT_CONTAINS_ELEMENTS)
CSS_PSEUDO_ELEMENT(highlight, ":highlight", 0)
CSS_PSEUDO_ELEMENT(selection, ":selection",
CSS_PSEUDO_ELEMENT_CONTAINS_ELEMENTS)

Просмотреть файл

@ -13,6 +13,7 @@
#include "mozilla/CSSEnabledState.h"
#include "mozilla/Compiler.h"
#include "mozilla/PseudoStyleType.h"
#include "mozilla/StaticPrefs_dom.h"
// Is this pseudo-element a CSS2 pseudo-element that can be specified
// with the single colon syntax (in addition to the double-colon syntax,
@ -118,6 +119,10 @@ class nsCSSPseudoElements {
}
static bool EnabledInContent(Type aType) {
if (aType == Type::highlight &&
!mozilla::StaticPrefs::dom_customHighlightAPI_enabled()) {
return false;
}
return !PseudoElementHasAnyFlag(
aType, CSS_PSEUDO_ELEMENT_ENABLED_IN_UA_SHEETS_AND_CHROME);
}

Просмотреть файл

@ -2260,6 +2260,13 @@
value: false
mirror: always
# Disable custom highlight API; implementation pending.
- name: dom.customHighlightAPI.enabled
type: RelaxedAtomicBool
value: false
mirror: always
rust: true
# Allow control characters appear in composition string.
# When this is false, control characters except
# CHARACTER TABULATION (horizontal tab) are removed from

Просмотреть файл

@ -2903,6 +2903,7 @@ pub mod tests {
pub enum PseudoElement {
Before,
After,
Highlight(String),
}
impl parser::PseudoElement for PseudoElement {
@ -2956,6 +2957,11 @@ pub mod tests {
match *self {
PseudoElement::Before => dest.write_str("::before"),
PseudoElement::After => dest.write_str("::after"),
PseudoElement::Highlight(ref name) => {
dest.write_str("::highlight(")?;
serialize_identifier(&name, dest)?;
dest.write_char(')')
},
}
}
}
@ -3116,6 +3122,23 @@ pub mod tests {
)
}
fn parse_functional_pseudo_element<'t>(
&self,
name: CowRcStr<'i>,
parser: &mut CssParser<'i, 't>,
) -> Result<PseudoElement, SelectorParseError<'i>> {
match_ignore_ascii_case! {&name,
"highlight" => return Ok(PseudoElement::Highlight(parser.expect_ident()?.as_ref().to_owned())),
_ => {}
}
Err(
parser.new_custom_error(SelectorParseErrorKind::UnsupportedPseudoClassOrElement(
name,
)),
)
}
fn default_namespace(&self) -> Option<DummyAtom> {
self.default_ns.clone()
}
@ -3643,6 +3666,8 @@ pub mod tests {
)]))
);
assert!(parse("::highlight(foo)").is_ok());
assert!(parse("::slotted()").is_err());
assert!(parse("::slotted(div)").is_ok());
assert!(parse("::slotted(div).foo").is_err());

Просмотреть файл

@ -14,8 +14,10 @@ use crate::properties::{ComputedValues, PropertyFlags};
use crate::selector_parser::{PseudoElementCascadeType, SelectorImpl};
use crate::str::{starts_with_ignore_ascii_case, string_as_ascii_lowercase};
use crate::string_cache::Atom;
use crate::values::AtomIdent;
use crate::values::serialize_atom_identifier;
use cssparser::ToCss;
use static_prefs::pref;
use std::fmt;
include!(concat!(
@ -153,6 +155,19 @@ impl PseudoElement {
!self.is_eager() && !self.is_precomputed()
}
/// The identifier of the highlight this pseudo-element represents.
pub fn highlight_name(&self) -> Option<&AtomIdent> {
match &*self {
PseudoElement::Highlight(name) => Some(&name),
_ => None
}
}
/// Whether this pseudo-element is the ::highlight pseudo.
pub fn is_highlight(&self) -> bool {
matches!(*self, PseudoElement::Highlight(_))
}
/// Whether this pseudo-element supports user action selectors.
pub fn supports_user_action_state(&self) -> bool {
(self.flags() & structs::CSS_PSEUDO_ELEMENT_SUPPORTS_USER_ACTION_STATE) != 0
@ -160,7 +175,10 @@ impl PseudoElement {
/// Whether this pseudo-element is enabled for all content.
pub fn enabled_in_content(&self) -> bool {
self.flags() & structs::CSS_PSEUDO_ELEMENT_ENABLED_IN_UA_SHEETS_AND_CHROME == 0
if self.is_highlight() && !pref!("dom.customHighlightAPI.enabled") {
return false;
}
return self.flags() & structs::CSS_PSEUDO_ELEMENT_ENABLED_IN_UA_SHEETS_AND_CHROME == 0
}
/// Whether this pseudo is enabled explicitly in UA sheets.

Просмотреть файл

@ -12,6 +12,8 @@ pub enum PseudoElement {
/// ${pseudo.value}
% if pseudo.is_tree_pseudo_element():
${pseudo.capitalized_pseudo()}(Box<Box<[Atom]>>),
% elif pseudo.pseudo_ident == "highlight":
${pseudo.capitalized_pseudo()}(AtomIdent),
% else:
${pseudo.capitalized_pseudo()},
% endif
@ -25,7 +27,7 @@ pub enum PseudoElement {
/// nsCSSPseudoElements::IsEagerlyCascadedInServo.
<% EAGER_PSEUDOS = ["Before", "After", "FirstLine", "FirstLetter"] %>
<% TREE_PSEUDOS = [pseudo for pseudo in PSEUDOS if pseudo.is_tree_pseudo_element()] %>
<% SIMPLE_PSEUDOS = [pseudo for pseudo in PSEUDOS if not pseudo.is_tree_pseudo_element()] %>
<% SIMPLE_PSEUDOS = [pseudo for pseudo in PSEUDOS if pseudo.is_simple_pseudo_element()] %>
/// The number of eager pseudo-elements.
pub const EAGER_PSEUDO_COUNT: usize = ${len(EAGER_PSEUDOS)};
@ -47,7 +49,7 @@ pub const EAGER_PSEUDOS: [PseudoElement; EAGER_PSEUDO_COUNT] = [
];
<%def name="pseudo_element_variant(pseudo, tree_arg='..')">\
PseudoElement::${pseudo.capitalized_pseudo()}${"({})".format(tree_arg) if pseudo.is_tree_pseudo_element() else ""}\
PseudoElement::${pseudo.capitalized_pseudo()}${"({})".format(tree_arg) if not pseudo.is_simple_pseudo_element() else ""}\
</%def>
impl PseudoElement {
@ -131,7 +133,7 @@ impl PseudoElement {
pub fn from_pseudo_type(type_: PseudoStyleType) -> Option<Self> {
match type_ {
% for pseudo in PSEUDOS:
% if not pseudo.is_tree_pseudo_element():
% if pseudo.is_simple_pseudo_element():
PseudoStyleType::${pseudo.pseudo_ident} => {
Some(${pseudo_element_variant(pseudo)})
},
@ -148,6 +150,8 @@ impl PseudoElement {
% for pseudo in PSEUDOS:
% if pseudo.is_tree_pseudo_element():
PseudoElement::${pseudo.capitalized_pseudo()}(..) => PseudoStyleType::XULTree,
% elif pseudo.pseudo_ident == "highlight":
PseudoElement::${pseudo.capitalized_pseudo()}(..) => PseudoStyleType::${pseudo.pseudo_ident},
% else:
PseudoElement::${pseudo.capitalized_pseudo()} => PseudoStyleType::${pseudo.pseudo_ident},
% endif
@ -240,9 +244,14 @@ impl ToCss for PseudoElement {
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
dest.write_char(':')?;
match *self {
% for pseudo in PSEUDOS:
% for pseudo in (p for p in PSEUDOS if p.pseudo_ident != "highlight"):
${pseudo_element_variant(pseudo)} => dest.write_str("${pseudo.value}")?,
% endfor
PseudoElement::Highlight(ref name) => {
dest.write_str(":highlight(")?;
serialize_atom_identifier(name, dest)?;
dest.write_char(')')?;
}
PseudoElement::UnknownWebkit(ref atom) => {
dest.write_str(":-webkit-")?;
serialize_atom_identifier(atom, dest)?;

Просмотреть файл

@ -90,6 +90,9 @@ class Atom:
def is_tree_pseudo_element(self):
return self.value.startswith(":-moz-tree-")
def is_simple_pseudo_element(self) -> bool:
return not (self.is_tree_pseudo_element() or self.pseudo_ident == "highlight")
def collect_atoms(objdir):
atoms = []

Просмотреть файл

@ -443,6 +443,11 @@ impl<'a, 'i> ::selectors::Parser<'i> for SelectorParser<'a> {
return Ok(pseudo);
}
}
} else if name.eq_ignore_ascii_case("highlight") {
let pseudo = PseudoElement::Highlight(AtomIdent::from(parser.expect_ident()?.as_ref()));
if self.is_pseudo_element_enabled(&pseudo) {
return Ok(pseudo);
}
}
Err(
parser.new_custom_error(SelectorParseErrorKind::UnsupportedPseudoClassOrElement(

Просмотреть файл

@ -4040,6 +4040,45 @@ fn debug_atom_array(atoms: &nsTArray<structs::RefPtr<nsAtom>>) -> String {
result
}
#[no_mangle]
pub extern "C" fn Servo_ComputedValues_ResolveHighlightPseudoStyle(
element: &RawGeckoElement,
highlight_name: *const nsAtom,
raw_data: &RawServoStyleSet,
) -> Strong<ComputedValues> {
let element = GeckoElement(element);
let data = element
.borrow_data()
.expect("Calling ResolveHighlightPseudoStyle on unstyled element?");
let pseudo_element = unsafe {
AtomIdent::with(highlight_name, |atom| {
PseudoElement::Highlight(atom.to_owned())
})
};
let doc_data = PerDocumentStyleData::from_ffi(raw_data).borrow();
let matching_fn = |pseudo: &PseudoElement| *pseudo == pseudo_element;
let global_style_data = &*GLOBAL_STYLE_DATA;
let guard = global_style_data.shared_lock.read();
let style = get_pseudo_style(
&guard,
element,
&pseudo_element,
RuleInclusion::All,
&data.styles,
None,
&doc_data.stylist,
/* is_probe = */true,
Some(&matching_fn),
);
match style {
Some(s) => s.into(),
None => Strong::null(),
}
}
#[no_mangle]
pub extern "C" fn Servo_ComputedValues_ResolveXULTreePseudoStyle(
element: &RawGeckoElement,

Просмотреть файл

@ -11,9 +11,8 @@
[Highlight iteration is not modified when the range that was immediately after the one pointed to by the iterator was deleted after starting the iteration]
expected: FAIL
[Highlight iteration is not modified when a range that was already visited is deleted and there are still ranges to visit]
expected: FAIL
[Highlight iteration is not modified when the range that was pointed to by the iterator was deleted using .clear() after starting the iteration]
expected: FAIL
[Highlight iteration is not modified when a range that was already visited is deleted and there are still ranges to visit]
expected: FAIL

Просмотреть файл

@ -1,76 +1,30 @@
[Highlight-iteration.html]
[Highlight can be iterated when it's empty initializing the iterator with customHighlight[Symbol.iterator\]()]
expected: FAIL
[Highlight can be iterated when it's empty initializing the iterator with customHighlight.values()]
expected: FAIL
[Highlight can be iterated when it's empty initializing the iterator with customHighlight.keys()]
expected: FAIL
[Highlight can be iterated over all of its ranges initializing the iterator with customHighlight[Symbol.iterator\]() and adding a range by passing it to the constructor]
expected: FAIL
[Highlight can be iterated over all of its ranges initializing the iterator with customHighlight[Symbol.iterator\]() and adding two ranges by passing them to the constructor]
expected: FAIL
[Highlight can be iterated over all of its ranges initializing the iterator with customHighlight.values() and adding a range by passing it to the constructor]
expected: FAIL
[Highlight can be iterated over all of its ranges initializing the iterator with customHighlight.values() and adding two ranges by passing them to the constructor]
expected: FAIL
[Highlight can be iterated over all of its ranges initializing the iterator with customHighlight.keys() and adding a range by passing it to the constructor]
expected: FAIL
[Highlight can be iterated over all of its ranges initializing the iterator with customHighlight.keys() and adding two ranges by passing them to the constructor]
expected: FAIL
[Highlight can be iterated over all of its ranges initializing the iterator with customHighlight[Symbol.iterator\]() and adding a range by passing it to the add function]
expected: FAIL
[Highlight can be iterated over all of its ranges initializing the iterator with customHighlight[Symbol.iterator\]() and adding two ranges by passing them to the add function]
expected: FAIL
[Highlight can be iterated over all of its ranges initializing the iterator with customHighlight.values() and adding a range by passing it to the add function]
expected: FAIL
[Highlight can be iterated over all of its ranges initializing the iterator with customHighlight.values() and adding two ranges by passing them to the add function]
expected: FAIL
[Highlight can be iterated over all of its ranges initializing the iterator with customHighlight.keys() and adding a range by passing it to the add function]
expected: FAIL
[Highlight can be iterated over all of its ranges initializing the iterator with customHighlight.keys() and adding two ranges by passing them to the add function]
expected: FAIL
[Highlight can be iterated when it's empty initializing the iterator with .entries()]
expected: FAIL
[Highlight can be iterated over all of its ranges initializing the iterator with .entries() and adding a range by passing it to the constructor]
expected: FAIL
[Highlight can be iterated over all of its ranges initializing the iterator with .entries() and adding two ranges by passing them to the constructor]
expected: FAIL
[Highlight can be iterated over all of its ranges initializing the iterator with .entries() and adding a range by passing it to the add function]
expected: FAIL
[Highlight can be iterated over all of its ranges initializing the iterator with .entries() and adding two ranges by passing them to the add function]
expected: FAIL
[Highlight can be iterated through when it's empty using forEach.]
expected: FAIL
[Highlight can be iterated through using forEach when it has one range that was added by passing it to the constructor]
expected: FAIL
[Highlight can be iterated through using forEach when it has two ranges that were added by passing them to the constructor]
expected: FAIL
[Highlight can be iterated through using forEach when it has one range that was added by passing it to the add function]
expected: FAIL
[Highlight can be iterated through using forEach when it has two ranges that were added by passing them to the add function]
expected: FAIL

Просмотреть файл

@ -1,31 +1,19 @@
[Highlight-setlike.html]
[Highlight initializes empty (if no ranges are provided) and with priority 0.]
expected: FAIL
[Highlight add and has methods work as expected (using the following combination of ranges [[object Range\], [object Range\], [object Range\]\])]
expected: FAIL
[Highlight delete method works as expected (using the following combination of ranges [[object Range\], [object Range\], [object Range\]\])]
expected: FAIL
[Highlight constructor behaves like a set when using equal ranges (using the following combination of ranges [[object Range\], [object Range\], [object Range\]\])]
[Highlight delete method works as expected (using the following combination of ranges [[object StaticRange\], [object StaticRange\], [object StaticRange\]\])]
expected: FAIL
[Highlight constructor works as expected when called with one range (using the following combination of ranges [[object Range\], [object Range\], [object Range\]\])]
[Highlight delete method works as expected (using the following combination of ranges [[object Range\], [object StaticRange\], [object Range\]\])]
expected: FAIL
[Highlight constructor works as expected when called with two ranges (using the following combination of ranges [[object Range\], [object Range\], [object Range\]\])]
expected: FAIL
[Highlight clear method works as expected (using the following combination of ranges [[object Range\], [object Range\], [object Range\]\])]
[Highlight delete method works as expected (using the following combination of ranges [[object StaticRange\], [object Range\], [object StaticRange\]\])]
expected: FAIL
[Highlight add and has methods work as expected (using the following combination of ranges [[object StaticRange\], [object StaticRange\], [object StaticRange\]\])]
expected: FAIL
[Highlight delete method works as expected (using the following combination of ranges [[object StaticRange\], [object StaticRange\], [object StaticRange\]\])]
expected: FAIL
[Highlight constructor behaves like a set when using equal ranges (using the following combination of ranges [[object StaticRange\], [object StaticRange\], [object StaticRange\]\])]
expected: FAIL
@ -41,15 +29,9 @@
[Highlight add and has methods work as expected (using the following combination of ranges [[object Range\], [object StaticRange\], [object Range\]\])]
expected: FAIL
[Highlight delete method works as expected (using the following combination of ranges [[object Range\], [object StaticRange\], [object Range\]\])]
expected: FAIL
[Highlight constructor behaves like a set when using equal ranges (using the following combination of ranges [[object Range\], [object StaticRange\], [object Range\]\])]
expected: FAIL
[Highlight constructor works as expected when called with one range (using the following combination of ranges [[object Range\], [object StaticRange\], [object Range\]\])]
expected: FAIL
[Highlight constructor works as expected when called with two ranges (using the following combination of ranges [[object Range\], [object StaticRange\], [object Range\]\])]
expected: FAIL
@ -59,9 +41,6 @@
[Highlight add and has methods work as expected (using the following combination of ranges [[object StaticRange\], [object Range\], [object StaticRange\]\])]
expected: FAIL
[Highlight delete method works as expected (using the following combination of ranges [[object StaticRange\], [object Range\], [object StaticRange\]\])]
expected: FAIL
[Highlight constructor behaves like a set when using equal ranges (using the following combination of ranges [[object StaticRange\], [object Range\], [object StaticRange\]\])]
expected: FAIL

Просмотреть файл

@ -1,3 +0,0 @@
[Highlight-type-attribute.tentative.html]
[Highlight has a mutable 'type' attribute that is a HighlightType enum.]
expected: FAIL

Просмотреть файл

@ -1,4 +1,17 @@
[HighlightRegistry-iteration-with-modifications.html]
expected:
if (os == "android") and fission: [ERROR, TIMEOUT]
ERROR
[HighlightRegistry iteration is not modified when a new Highlight is added after starting the iteration]
expected: FAIL
[HighlightRegistry iteration is not modified when a new Highlight is added after starting the iteration with one Highlight in the HighlightRegistry]
expected: FAIL
[HighlightRegistry iteration is not modified when the Highlight that was pointed to by the iterator was deleted after starting the iteration]
expected: FAIL
[HighlightRegistry iteration is not modified when the Highlight that was immediately after the one pointed to by the iterator was deleted after starting the iteration]
expected: FAIL
[HighlightRegistry iteration is not modified when the Highlight that was pointed to by the iterator was deleted using .clear() after starting the iteration]
expected: FAIL

Просмотреть файл

@ -1,4 +1,3 @@
[HighlightRegistry-iteration.html]
expected:
if (os == "android") and fission: [ERROR, TIMEOUT]
ERROR

Просмотреть файл

@ -1,8 +1,5 @@
[HighlightRegistry-maplike.html]
expected:
if (os == "android") and fission: [OK, TIMEOUT]
[HighlightRegistry initializes as it should.]
expected: FAIL
[HighlightRegistry has a maplike interface.]
expected: FAIL

Просмотреть файл

@ -0,0 +1 @@
prefs: [dom.customHighlightAPI.enabled:true]

Просмотреть файл

@ -14,9 +14,6 @@
[getComputedStyle() for ::highlight(foo)( should be element's default]
expected: FAIL
[getComputedStyle() for ::highlight should be element's default]
expected: FAIL
[getComputedStyle() for ::highlight(foo)(foo) should be element's default]
expected: FAIL
@ -31,4 +28,3 @@
[getComputedStyle() for ::highlight(foo,bar) should be element's default]
expected: FAIL

Просмотреть файл

@ -1,14 +1,3 @@
[highlight-pseudo-parsing.html]
expected:
if (os == "android") and fission: [OK, TIMEOUT]
["::highlight(foo)" should be a valid selector]
expected: FAIL
[".a::highlight(foo)" should be a valid selector]
expected: FAIL
["div ::highlight(foo)" should be a valid selector]
expected: FAIL
["::part(my-part)::highlight(foo)" should be a valid selector]
expected: FAIL

Просмотреть файл

@ -1,71 +1,3 @@
[idlharness.window.html]
expected:
if (os == "android") and fission: [OK, TIMEOUT]
[Highlight interface: existence and properties of interface object]
expected: FAIL
[Highlight interface object length]
expected: FAIL
[Highlight interface object name]
expected: FAIL
[Highlight interface: existence and properties of interface prototype object]
expected: FAIL
[Highlight interface: existence and properties of interface prototype object's "constructor" property]
expected: FAIL
[Highlight interface: existence and properties of interface prototype object's @@unscopables property]
expected: FAIL
[Highlight interface: attribute priority]
expected: FAIL
[Highlight must be primary interface of new Highlight(new Range())]
expected: FAIL
[Stringification of new Highlight(new Range())]
expected: FAIL
[Highlight interface: new Highlight(new Range()) must inherit property "priority" with the proper type]
expected: FAIL
[HighlightRegistry interface: existence and properties of interface object]
expected: FAIL
[HighlightRegistry interface object length]
expected: FAIL
[HighlightRegistry interface object name]
expected: FAIL
[HighlightRegistry interface: existence and properties of interface prototype object]
expected: FAIL
[HighlightRegistry interface: existence and properties of interface prototype object's "constructor" property]
expected: FAIL
[HighlightRegistry interface: existence and properties of interface prototype object's @@unscopables property]
expected: FAIL
[HighlightRegistry must be primary interface of CSS.highlights]
expected: FAIL
[Stringification of CSS.highlights]
expected: FAIL
[CSS namespace: attribute highlights]
expected: FAIL
[Highlight interface: attribute type]
expected: FAIL
[Highlight interface: new Highlight(new Range()) must inherit property "type" with the proper type]
expected: FAIL
[Highlight interface: setlike<AbstractRange>]
expected: FAIL
[HighlightRegistry interface: maplike<DOMString, Highlight>]
expected: FAIL

Просмотреть файл

@ -1,2 +0,0 @@
[custom-highlight-painting-001.html]
expected: FAIL

Просмотреть файл

@ -1,2 +1,3 @@
[custom-highlight-painting-002.html]
expected: FAIL
;https://bugzilla.mozilla.org/show_bug.cgi?id=1811823
expected: [FAIL, PASS]

Просмотреть файл

@ -1,2 +0,0 @@
[custom-highlight-painting-003.html]
expected: FAIL

Просмотреть файл

@ -1,2 +0,0 @@
[custom-highlight-painting-005.html]
expected: FAIL

Просмотреть файл

@ -1,2 +0,0 @@
[custom-highlight-painting-006.html]
expected: FAIL

Просмотреть файл

@ -1,2 +0,0 @@
[custom-highlight-painting-007.html]
expected: FAIL

Просмотреть файл

@ -1,2 +0,0 @@
[custom-highlight-painting-008.html]
expected: FAIL

Просмотреть файл

@ -1,2 +0,0 @@
[custom-highlight-painting-009.html]
expected: FAIL

Просмотреть файл

@ -1,2 +0,0 @@
[custom-highlight-painting-010.html]
expected: FAIL

Просмотреть файл

@ -1,2 +0,0 @@
[custom-highlight-painting-011.html]
expected: FAIL

Просмотреть файл

@ -1,2 +0,0 @@
[custom-highlight-painting-012.html]
expected: FAIL

Просмотреть файл

@ -1,2 +0,0 @@
[custom-highlight-painting-013.html]
expected: FAIL

Просмотреть файл

@ -1,2 +0,0 @@
[custom-highlight-painting-015.html]
expected: FAIL

Просмотреть файл

@ -1,2 +0,0 @@
[custom-highlight-painting-016.html]
expected: FAIL

Просмотреть файл

@ -1,2 +0,0 @@
[custom-highlight-painting-017.html]
expected: FAIL

Просмотреть файл

@ -1,2 +0,0 @@
[custom-highlight-painting-018.html]
expected: FAIL

Просмотреть файл

@ -0,0 +1,2 @@
[custom-highlight-painting-below-grammar.html]
expected: FAIL

Просмотреть файл

@ -1,2 +1,2 @@
[custom-highlight-painting-below-target-text.html]
expected: FAIL
expected: TIMEOUT

Просмотреть файл

@ -1,2 +0,0 @@
[custom-highlight-painting-iframe-001.html]
expected: FAIL

Просмотреть файл

@ -1,2 +0,0 @@
[custom-highlight-painting-iframe-002.html]
expected: FAIL

Просмотреть файл

@ -1,2 +0,0 @@
[custom-highlight-painting-iframe-003.html]
expected: FAIL

Просмотреть файл

@ -1,2 +0,0 @@
[custom-highlight-painting-iframe-004.html]
expected: FAIL

Просмотреть файл

@ -1,2 +0,0 @@
[custom-highlight-painting-iframe-005.html]
expected: FAIL

Просмотреть файл

@ -1,2 +0,0 @@
[custom-highlight-painting-iframe-006.html]
expected: TIMEOUT

Просмотреть файл

@ -1,2 +0,0 @@
[custom-highlight-painting-invalidation-001.html]
expected: TIMEOUT

Просмотреть файл

@ -1,2 +1,2 @@
[custom-highlight-painting-invalidation-002.html]
expected: TIMEOUT
expected: FAIL

Просмотреть файл

@ -1,2 +0,0 @@
[custom-highlight-painting-invalidation-003.html]
expected: TIMEOUT

Просмотреть файл

@ -1,2 +0,0 @@
[custom-highlight-painting-invalidation-004.html]
expected: TIMEOUT

Просмотреть файл

@ -1,2 +1,3 @@
[custom-highlight-painting-invalidation-005.html]
expected: TIMEOUT
;https://bugzilla.mozilla.org/show_bug.cgi?id=1811823
expected: [FAIL, PASS]

Просмотреть файл

@ -1,2 +0,0 @@
[custom-highlight-painting-invalidation-006.html]
expected: TIMEOUT

Просмотреть файл

@ -1,2 +1,2 @@
[custom-highlight-painting-invalidation-007.html]
expected: TIMEOUT
expected: FAIL

Просмотреть файл

@ -1,2 +0,0 @@
[custom-highlight-painting-overlapping-highlights-001.html]
expected: FAIL

Просмотреть файл

@ -1,2 +1,3 @@
[custom-highlight-painting-overlapping-highlights-002.html]
expected: FAIL
;https://bugzilla.mozilla.org/show_bug.cgi?id=1811823
expected: [FAIL, PASS]

Просмотреть файл

@ -1,2 +1,3 @@
[custom-highlight-painting-prioritization-001.html]
expected: FAIL
;https://bugzilla.mozilla.org/show_bug.cgi?id=1811823
expected: [FAIL, PASS]

Просмотреть файл

@ -1,2 +1,3 @@
[custom-highlight-painting-prioritization-002.html]
expected: FAIL
;https://bugzilla.mozilla.org/show_bug.cgi?id=1811823
expected: [FAIL, PASS]

Просмотреть файл

@ -1,2 +0,0 @@
[custom-highlight-painting-text-decoration-dynamic-001.html]
expected: TIMEOUT

Просмотреть файл

@ -1,2 +0,0 @@
[custom-highlight-painting-text-shadow.tentative.html]
expected: FAIL

Просмотреть файл

@ -2484,6 +2484,7 @@ STATIC_ATOMS = [
PseudoElementAtom("PseudoElement_cue", ":cue"),
PseudoElementAtom("PseudoElement_firstLetter", ":first-letter"),
PseudoElementAtom("PseudoElement_firstLine", ":first-line"),
PseudoElementAtom("PseudoElement_highlight", ":highlight"),
PseudoElementAtom("PseudoElement_selection", ":selection"),
PseudoElementAtom("PseudoElement_mozFocusInner", ":-moz-focus-inner"),
PseudoElementAtom("PseudoElement_mozNumberSpinBox", ":-moz-number-spin-box"),