зеркало из https://github.com/mozilla/gecko-dev.git
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:
Родитель
c711b8f39b
Коммит
1b3bff372b
|
@ -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;
|
||||
|
|
|
@ -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
|
|
@ -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,
|
||||
¶ms.color, &bg);
|
||||
GetSelectionTextColors(aSelectionType, nullptr, aTextPaintStyle,
|
||||
aRangeStyle, ¶ms.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"),
|
||||
|
|
Загрузка…
Ссылка в новой задаче