mirror of
https://repo.dactyloidae.xyz/Dactyloidae/UXP.git
synced 2026-10-01 21:07:30 +09:00
import FIREFOX_52_6_0esr_RELEASE from mozilla-esr52 hg repo
This commit is contained in:
commit
dcd9973243
150858 changed files with 23884658 additions and 0 deletions
172
layout/style/AnimationCollection.cpp
Normal file
172
layout/style/AnimationCollection.cpp
Normal file
|
|
@ -0,0 +1,172 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* 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 "mozilla/AnimationCollection.h"
|
||||
|
||||
#include "mozilla/RestyleManagerHandle.h"
|
||||
#include "mozilla/RestyleManagerHandleInlines.h"
|
||||
#include "nsAnimationManager.h" // For dom::CSSAnimation
|
||||
#include "nsPresContext.h"
|
||||
#include "nsTransitionManager.h" // For dom::CSSTransition
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
template <class AnimationType>
|
||||
/* static */ void
|
||||
AnimationCollection<AnimationType>::PropertyDtor(void* aObject,
|
||||
nsIAtom* aPropertyName,
|
||||
void* aPropertyValue,
|
||||
void* aData)
|
||||
{
|
||||
AnimationCollection* collection =
|
||||
static_cast<AnimationCollection*>(aPropertyValue);
|
||||
#ifdef DEBUG
|
||||
MOZ_ASSERT(!collection->mCalledPropertyDtor, "can't call dtor twice");
|
||||
collection->mCalledPropertyDtor = true;
|
||||
#endif
|
||||
{
|
||||
nsAutoAnimationMutationBatch mb(collection->mElement->OwnerDoc());
|
||||
|
||||
for (size_t animIdx = collection->mAnimations.Length(); animIdx-- != 0; ) {
|
||||
collection->mAnimations[animIdx]->CancelFromStyle();
|
||||
}
|
||||
}
|
||||
delete collection;
|
||||
}
|
||||
|
||||
template <class AnimationType>
|
||||
/* static */ AnimationCollection<AnimationType>*
|
||||
AnimationCollection<AnimationType>::GetAnimationCollection(
|
||||
dom::Element *aElement,
|
||||
CSSPseudoElementType aPseudoType)
|
||||
{
|
||||
if (!aElement->MayHaveAnimations()) {
|
||||
// Early return for the most common case.
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
nsIAtom* propName = GetPropertyAtomForPseudoType(aPseudoType);
|
||||
if (!propName) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return
|
||||
static_cast<AnimationCollection<AnimationType>*>(aElement->
|
||||
GetProperty(propName));
|
||||
}
|
||||
|
||||
template <class AnimationType>
|
||||
/* static */ AnimationCollection<AnimationType>*
|
||||
AnimationCollection<AnimationType>::GetAnimationCollection(
|
||||
const nsIFrame* aFrame)
|
||||
{
|
||||
Maybe<NonOwningAnimationTarget> pseudoElement =
|
||||
EffectCompositor::GetAnimationElementAndPseudoForFrame(aFrame);
|
||||
if (!pseudoElement) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (!pseudoElement->mElement->MayHaveAnimations()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return GetAnimationCollection(pseudoElement->mElement,
|
||||
pseudoElement->mPseudoType);
|
||||
}
|
||||
|
||||
template <class AnimationType>
|
||||
/* static */ AnimationCollection<AnimationType>*
|
||||
AnimationCollection<AnimationType>::GetOrCreateAnimationCollection(
|
||||
dom::Element* aElement,
|
||||
CSSPseudoElementType aPseudoType,
|
||||
bool* aCreatedCollection)
|
||||
{
|
||||
MOZ_ASSERT(aCreatedCollection);
|
||||
*aCreatedCollection = false;
|
||||
|
||||
nsIAtom* propName = GetPropertyAtomForPseudoType(aPseudoType);
|
||||
MOZ_ASSERT(propName, "Should only try to create animations for one of the"
|
||||
" recognized pseudo types");
|
||||
|
||||
auto collection = static_cast<AnimationCollection<AnimationType>*>(
|
||||
aElement->GetProperty(propName));
|
||||
if (!collection) {
|
||||
// FIXME: Consider arena-allocating?
|
||||
collection = new AnimationCollection<AnimationType>(aElement, propName);
|
||||
nsresult rv =
|
||||
aElement->SetProperty(propName, collection,
|
||||
&AnimationCollection<AnimationType>::PropertyDtor,
|
||||
false);
|
||||
if (NS_FAILED(rv)) {
|
||||
NS_WARNING("SetProperty failed");
|
||||
// The collection must be destroyed via PropertyDtor, otherwise
|
||||
// mCalledPropertyDtor assertion is triggered in destructor.
|
||||
AnimationCollection<AnimationType>::PropertyDtor(aElement, propName,
|
||||
collection, nullptr);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
*aCreatedCollection = true;
|
||||
aElement->SetMayHaveAnimations();
|
||||
}
|
||||
|
||||
return collection;
|
||||
}
|
||||
|
||||
template <class AnimationType>
|
||||
/* static */ nsString
|
||||
AnimationCollection<AnimationType>::PseudoTypeAsString(
|
||||
CSSPseudoElementType aPseudoType)
|
||||
{
|
||||
switch (aPseudoType) {
|
||||
case CSSPseudoElementType::before:
|
||||
return NS_LITERAL_STRING("::before");
|
||||
case CSSPseudoElementType::after:
|
||||
return NS_LITERAL_STRING("::after");
|
||||
default:
|
||||
MOZ_ASSERT(aPseudoType == CSSPseudoElementType::NotPseudo,
|
||||
"Unexpected pseudo type");
|
||||
return EmptyString();
|
||||
}
|
||||
}
|
||||
|
||||
template <class AnimationType>
|
||||
void
|
||||
AnimationCollection<AnimationType>::UpdateCheckGeneration(
|
||||
nsPresContext* aPresContext)
|
||||
{
|
||||
if (aPresContext->RestyleManager()->IsServo()) {
|
||||
// stylo: ServoRestyleManager does not support animations yet.
|
||||
return;
|
||||
}
|
||||
mCheckGeneration =
|
||||
aPresContext->RestyleManager()->AsGecko()->GetAnimationGeneration();
|
||||
}
|
||||
|
||||
template<class AnimationType>
|
||||
/*static*/ nsIAtom*
|
||||
AnimationCollection<AnimationType>::GetPropertyAtomForPseudoType(
|
||||
CSSPseudoElementType aPseudoType)
|
||||
{
|
||||
nsIAtom* propName = nullptr;
|
||||
|
||||
if (aPseudoType == CSSPseudoElementType::NotPseudo) {
|
||||
propName = TraitsType::ElementPropertyAtom();
|
||||
} else if (aPseudoType == CSSPseudoElementType::before) {
|
||||
propName = TraitsType::BeforePropertyAtom();
|
||||
} else if (aPseudoType == CSSPseudoElementType::after) {
|
||||
propName = TraitsType::AfterPropertyAtom();
|
||||
}
|
||||
|
||||
return propName;
|
||||
}
|
||||
|
||||
// Explicit class instantiations
|
||||
|
||||
template class AnimationCollection<dom::CSSAnimation>;
|
||||
template class AnimationCollection<dom::CSSTransition>;
|
||||
|
||||
} // namespace mozilla
|
||||
147
layout/style/AnimationCollection.h
Normal file
147
layout/style/AnimationCollection.h
Normal file
|
|
@ -0,0 +1,147 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* 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_AnimationCollection_h
|
||||
#define mozilla_AnimationCollection_h
|
||||
|
||||
#include "mozilla/dom/Animation.h"
|
||||
#include "mozilla/dom/Element.h"
|
||||
#include "mozilla/Assertions.h"
|
||||
#include "mozilla/LinkedList.h"
|
||||
#include "mozilla/RefPtr.h"
|
||||
#include "nsCSSPseudoElements.h"
|
||||
#include "nsDOMMutationObserver.h"
|
||||
#include "nsTArray.h"
|
||||
|
||||
class nsIAtom;
|
||||
class nsPresContext;
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
// Traits class to define the specific atoms used when storing specializations
|
||||
// of AnimationCollection as a property on an Element (e.g. which atom
|
||||
// to use when storing an AnimationCollection<CSSAnimation> for a ::before
|
||||
// pseudo-element).
|
||||
template <class AnimationType>
|
||||
struct AnimationTypeTraits { };
|
||||
|
||||
template <class AnimationType>
|
||||
class AnimationCollection
|
||||
: public LinkedListElement<AnimationCollection<AnimationType>>
|
||||
{
|
||||
typedef AnimationCollection<AnimationType> SelfType;
|
||||
typedef AnimationTypeTraits<AnimationType> TraitsType;
|
||||
|
||||
AnimationCollection(dom::Element* aElement, nsIAtom* aElementProperty)
|
||||
: mElement(aElement)
|
||||
, mElementProperty(aElementProperty)
|
||||
, mCheckGeneration(0)
|
||||
#ifdef DEBUG
|
||||
, mCalledPropertyDtor(false)
|
||||
#endif
|
||||
{
|
||||
MOZ_COUNT_CTOR(AnimationCollection);
|
||||
}
|
||||
|
||||
public:
|
||||
~AnimationCollection()
|
||||
{
|
||||
MOZ_ASSERT(mCalledPropertyDtor,
|
||||
"must call destructor through element property dtor");
|
||||
MOZ_COUNT_DTOR(AnimationCollection);
|
||||
LinkedListElement<SelfType>::remove();
|
||||
}
|
||||
|
||||
void Destroy()
|
||||
{
|
||||
// This will call our destructor.
|
||||
mElement->DeleteProperty(mElementProperty);
|
||||
}
|
||||
|
||||
static void PropertyDtor(void *aObject, nsIAtom *aPropertyName,
|
||||
void *aPropertyValue, void *aData);
|
||||
|
||||
// Get the collection of animations for the given |aElement| and
|
||||
// |aPseudoType|.
|
||||
static AnimationCollection<AnimationType>*
|
||||
GetAnimationCollection(dom::Element* aElement,
|
||||
CSSPseudoElementType aPseudoType);
|
||||
|
||||
// Given the frame |aFrame| with possibly animated content, finds its
|
||||
// associated collection of animations. If |aFrame| is a generated content
|
||||
// frame, this function may examine the parent frame to search for such
|
||||
// animations.
|
||||
static AnimationCollection<AnimationType>* GetAnimationCollection(
|
||||
const nsIFrame* aFrame);
|
||||
|
||||
// Get the collection of animations for the given |aElement| and
|
||||
// |aPseudoType| or create it if it does not already exist.
|
||||
//
|
||||
// We'll set the outparam |aCreatedCollection| to true if we have
|
||||
// to create the collection and we successfully do so. Otherwise,
|
||||
// we'll set it to false.
|
||||
static AnimationCollection<AnimationType>*
|
||||
GetOrCreateAnimationCollection(dom::Element* aElement,
|
||||
CSSPseudoElementType aPseudoType,
|
||||
bool* aCreatedCollection);
|
||||
|
||||
bool IsForElement() const { // rather than for a pseudo-element
|
||||
return mElementProperty == TraitsType::ElementPropertyAtom();
|
||||
}
|
||||
|
||||
bool IsForBeforePseudo() const {
|
||||
return mElementProperty == TraitsType::BeforePropertyAtom();
|
||||
}
|
||||
|
||||
bool IsForAfterPseudo() const {
|
||||
return mElementProperty == TraitsType::AfterPropertyAtom();
|
||||
}
|
||||
|
||||
CSSPseudoElementType PseudoElementType() const
|
||||
{
|
||||
if (IsForElement()) {
|
||||
return CSSPseudoElementType::NotPseudo;
|
||||
}
|
||||
if (IsForBeforePseudo()) {
|
||||
return CSSPseudoElementType::before;
|
||||
}
|
||||
MOZ_ASSERT(IsForAfterPseudo(),
|
||||
"::before & ::after should be the only pseudo-elements here");
|
||||
return CSSPseudoElementType::after;
|
||||
}
|
||||
|
||||
static nsString PseudoTypeAsString(CSSPseudoElementType aPseudoType);
|
||||
|
||||
dom::Element *mElement;
|
||||
|
||||
// the atom we use in mElement's prop table (must be a static atom,
|
||||
// i.e., in an atom list)
|
||||
nsIAtom *mElementProperty;
|
||||
|
||||
InfallibleTArray<RefPtr<AnimationType>> mAnimations;
|
||||
|
||||
// For CSS transitions only, we record the most recent generation
|
||||
// for which we've done the transition update, so that we avoid doing
|
||||
// it more than once per style change.
|
||||
// (Note that we also store an animation generation on each EffectSet in
|
||||
// order to track when we need to update animations on layers.)
|
||||
uint64_t mCheckGeneration;
|
||||
|
||||
// Update mCheckGeneration to RestyleManager's count
|
||||
void UpdateCheckGeneration(nsPresContext* aPresContext);
|
||||
|
||||
private:
|
||||
static nsIAtom* GetPropertyAtomForPseudoType(
|
||||
CSSPseudoElementType aPseudoType);
|
||||
|
||||
#ifdef DEBUG
|
||||
bool mCalledPropertyDtor;
|
||||
#endif
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // mozilla_AnimationCollection_h
|
||||
54
layout/style/AnimationCommon.cpp
Normal file
54
layout/style/AnimationCommon.cpp
Normal file
|
|
@ -0,0 +1,54 @@
|
|||
/* vim: set shiftwidth=2 tabstop=8 autoindent cindent expandtab: */
|
||||
/* 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 "AnimationCommon.h"
|
||||
#include "nsTransitionManager.h"
|
||||
#include "nsAnimationManager.h"
|
||||
|
||||
#include "ActiveLayerTracker.h"
|
||||
#include "gfxPlatform.h"
|
||||
#include "nsCSSPropertyIDSet.h"
|
||||
#include "nsCSSValue.h"
|
||||
#include "nsCycleCollectionParticipant.h"
|
||||
#include "nsStyleContext.h"
|
||||
#include "nsIFrame.h"
|
||||
#include "nsLayoutUtils.h"
|
||||
#include "FrameLayerBuilder.h"
|
||||
#include "nsDisplayList.h"
|
||||
#include "mozilla/AnimationUtils.h"
|
||||
#include "mozilla/EffectCompositor.h"
|
||||
#include "mozilla/EffectSet.h"
|
||||
#include "mozilla/MemoryReporting.h"
|
||||
#include "mozilla/dom/KeyframeEffectReadOnly.h"
|
||||
#include "nsRuleProcessorData.h"
|
||||
#include "nsStyleSet.h"
|
||||
#include "nsStyleChangeList.h"
|
||||
|
||||
using mozilla::dom::Animation;
|
||||
using mozilla::dom::KeyframeEffectReadOnly;
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
nsPresContext*
|
||||
OwningElementRef::GetRenderedPresContext() const
|
||||
{
|
||||
if (!mElement) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
nsIDocument* doc = mElement->GetComposedDoc();
|
||||
if (!doc) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
nsIPresShell* shell = doc->GetShell();
|
||||
if (!shell) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return shell->GetPresContext();
|
||||
}
|
||||
|
||||
} // namespace mozilla
|
||||
256
layout/style/AnimationCommon.h
Normal file
256
layout/style/AnimationCommon.h
Normal file
|
|
@ -0,0 +1,256 @@
|
|||
/* vim: set shiftwidth=2 tabstop=8 autoindent cindent expandtab: */
|
||||
/* 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_css_AnimationCommon_h
|
||||
#define mozilla_css_AnimationCommon_h
|
||||
|
||||
#include <algorithm> // For <std::stable_sort>
|
||||
#include "mozilla/AnimationCollection.h"
|
||||
#include "mozilla/AnimationComparator.h"
|
||||
#include "mozilla/EventDispatcher.h"
|
||||
#include "mozilla/LinkedList.h"
|
||||
#include "mozilla/MemoryReporting.h"
|
||||
#include "mozilla/dom/Animation.h"
|
||||
#include "mozilla/Attributes.h" // For MOZ_NON_OWNING_REF
|
||||
#include "mozilla/Assertions.h"
|
||||
#include "nsContentUtils.h"
|
||||
#include "nsCSSPseudoElements.h"
|
||||
#include "nsCycleCollectionParticipant.h"
|
||||
|
||||
class nsIFrame;
|
||||
class nsPresContext;
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
namespace dom {
|
||||
class Element;
|
||||
}
|
||||
|
||||
template <class AnimationType>
|
||||
class CommonAnimationManager {
|
||||
public:
|
||||
explicit CommonAnimationManager(nsPresContext *aPresContext)
|
||||
: mPresContext(aPresContext)
|
||||
{
|
||||
}
|
||||
|
||||
// NOTE: This can return null after Disconnect().
|
||||
nsPresContext* PresContext() const { return mPresContext; }
|
||||
|
||||
/**
|
||||
* Notify the manager that the pres context is going away.
|
||||
*/
|
||||
void Disconnect()
|
||||
{
|
||||
// Content nodes might outlive the transition or animation manager.
|
||||
RemoveAllElementCollections();
|
||||
|
||||
mPresContext = nullptr;
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual ~CommonAnimationManager()
|
||||
{
|
||||
MOZ_ASSERT(!mPresContext, "Disconnect should have been called");
|
||||
}
|
||||
|
||||
void AddElementCollection(AnimationCollection<AnimationType>* aCollection)
|
||||
{
|
||||
mElementCollections.insertBack(aCollection);
|
||||
}
|
||||
void RemoveAllElementCollections()
|
||||
{
|
||||
while (AnimationCollection<AnimationType>* head =
|
||||
mElementCollections.getFirst()) {
|
||||
head->Destroy(); // Note: this removes 'head' from mElementCollections.
|
||||
}
|
||||
}
|
||||
|
||||
LinkedList<AnimationCollection<AnimationType>> mElementCollections;
|
||||
nsPresContext *mPresContext; // weak (non-null from ctor to Disconnect)
|
||||
};
|
||||
|
||||
/**
|
||||
* Utility class for referencing the element that created a CSS animation or
|
||||
* transition. It is non-owning (i.e. it uses a raw pointer) since it is only
|
||||
* expected to be set by the owned animation while it actually being managed
|
||||
* by the owning element.
|
||||
*
|
||||
* This class also abstracts the comparison of an element/pseudo-class pair
|
||||
* for the sake of composite ordering since this logic is common to both CSS
|
||||
* animations and transitions.
|
||||
*
|
||||
* (We call this OwningElementRef instead of just OwningElement so that we can
|
||||
* call the getter on CSSAnimation/CSSTransition OwningElement() without
|
||||
* clashing with this object's contructor.)
|
||||
*/
|
||||
class OwningElementRef final
|
||||
{
|
||||
public:
|
||||
OwningElementRef()
|
||||
: mElement(nullptr)
|
||||
, mPseudoType(CSSPseudoElementType::NotPseudo)
|
||||
{ }
|
||||
|
||||
OwningElementRef(dom::Element& aElement,
|
||||
CSSPseudoElementType aPseudoType)
|
||||
: mElement(&aElement)
|
||||
, mPseudoType(aPseudoType)
|
||||
{ }
|
||||
|
||||
bool Equals(const OwningElementRef& aOther) const
|
||||
{
|
||||
return mElement == aOther.mElement &&
|
||||
mPseudoType == aOther.mPseudoType;
|
||||
}
|
||||
|
||||
bool LessThan(const OwningElementRef& aOther) const
|
||||
{
|
||||
MOZ_ASSERT(mElement && aOther.mElement,
|
||||
"Elements to compare should not be null");
|
||||
|
||||
if (mElement != aOther.mElement) {
|
||||
return nsContentUtils::PositionIsBefore(mElement, aOther.mElement);
|
||||
}
|
||||
|
||||
return mPseudoType == CSSPseudoElementType::NotPseudo ||
|
||||
(mPseudoType == CSSPseudoElementType::before &&
|
||||
aOther.mPseudoType == CSSPseudoElementType::after);
|
||||
}
|
||||
|
||||
bool IsSet() const { return !!mElement; }
|
||||
|
||||
void GetElement(dom::Element*& aElement,
|
||||
CSSPseudoElementType& aPseudoType) const {
|
||||
aElement = mElement;
|
||||
aPseudoType = mPseudoType;
|
||||
}
|
||||
|
||||
nsPresContext* GetRenderedPresContext() const;
|
||||
|
||||
private:
|
||||
dom::Element* MOZ_NON_OWNING_REF mElement;
|
||||
CSSPseudoElementType mPseudoType;
|
||||
};
|
||||
|
||||
template <class EventInfo>
|
||||
class DelayedEventDispatcher
|
||||
{
|
||||
public:
|
||||
DelayedEventDispatcher() : mIsSorted(true) { }
|
||||
|
||||
void QueueEvent(EventInfo&& aEventInfo)
|
||||
{
|
||||
mPendingEvents.AppendElement(Forward<EventInfo>(aEventInfo));
|
||||
mIsSorted = false;
|
||||
}
|
||||
|
||||
// This is exposed as a separate method so that when we are dispatching
|
||||
// *both* transition events and animation events we can sort both lists
|
||||
// once using the current state of the document before beginning any
|
||||
// dispatch.
|
||||
void SortEvents()
|
||||
{
|
||||
if (mIsSorted) {
|
||||
return;
|
||||
}
|
||||
|
||||
// FIXME: Replace with mPendingEvents.StableSort when bug 1147091 is
|
||||
// fixed.
|
||||
std::stable_sort(mPendingEvents.begin(), mPendingEvents.end(),
|
||||
EventInfoLessThan());
|
||||
mIsSorted = true;
|
||||
}
|
||||
|
||||
// Takes a reference to the owning manager's pres context so it can
|
||||
// detect if the pres context is destroyed while dispatching one of
|
||||
// the events.
|
||||
//
|
||||
// This will call SortEvents automatically if it has not already been
|
||||
// called.
|
||||
void DispatchEvents(nsPresContext* const & aPresContext)
|
||||
{
|
||||
if (!aPresContext || mPendingEvents.IsEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
SortEvents();
|
||||
|
||||
EventArray events;
|
||||
mPendingEvents.SwapElements(events);
|
||||
// mIsSorted will be set to true by SortEvents above, and we leave it
|
||||
// that way since mPendingEvents is now empty
|
||||
for (EventInfo& info : events) {
|
||||
EventDispatcher::Dispatch(info.mElement, aPresContext, &info.mEvent);
|
||||
|
||||
if (!aPresContext) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ClearEventQueue()
|
||||
{
|
||||
mPendingEvents.Clear();
|
||||
mIsSorted = true;
|
||||
}
|
||||
bool HasQueuedEvents() const { return !mPendingEvents.IsEmpty(); }
|
||||
|
||||
// Methods for supporting cycle-collection
|
||||
void Traverse(nsCycleCollectionTraversalCallback* aCallback,
|
||||
const char* aName)
|
||||
{
|
||||
for (EventInfo& info : mPendingEvents) {
|
||||
ImplCycleCollectionTraverse(*aCallback, info.mElement, aName);
|
||||
ImplCycleCollectionTraverse(*aCallback, info.mAnimation, aName);
|
||||
}
|
||||
}
|
||||
void Unlink() { ClearEventQueue(); }
|
||||
|
||||
protected:
|
||||
class EventInfoLessThan
|
||||
{
|
||||
public:
|
||||
bool operator()(const EventInfo& a, const EventInfo& b) const
|
||||
{
|
||||
if (a.mTimeStamp != b.mTimeStamp) {
|
||||
// Null timestamps sort first
|
||||
if (a.mTimeStamp.IsNull() || b.mTimeStamp.IsNull()) {
|
||||
return a.mTimeStamp.IsNull();
|
||||
} else {
|
||||
return a.mTimeStamp < b.mTimeStamp;
|
||||
}
|
||||
}
|
||||
|
||||
AnimationPtrComparator<RefPtr<dom::Animation>> comparator;
|
||||
return comparator.LessThan(a.mAnimation, b.mAnimation);
|
||||
}
|
||||
};
|
||||
|
||||
typedef nsTArray<EventInfo> EventArray;
|
||||
EventArray mPendingEvents;
|
||||
bool mIsSorted;
|
||||
};
|
||||
|
||||
template <class EventInfo>
|
||||
inline void
|
||||
ImplCycleCollectionUnlink(DelayedEventDispatcher<EventInfo>& aField)
|
||||
{
|
||||
aField.Unlink();
|
||||
}
|
||||
|
||||
template <class EventInfo>
|
||||
inline void
|
||||
ImplCycleCollectionTraverse(nsCycleCollectionTraversalCallback& aCallback,
|
||||
DelayedEventDispatcher<EventInfo>& aField,
|
||||
const char* aName,
|
||||
uint32_t aFlags = 0)
|
||||
{
|
||||
aField.Traverse(&aCallback, aName);
|
||||
}
|
||||
|
||||
} // namespace mozilla
|
||||
|
||||
#endif /* !defined(mozilla_css_AnimationCommon_h) */
|
||||
107
layout/style/CSS.cpp
Normal file
107
layout/style/CSS.cpp
Normal file
|
|
@ -0,0 +1,107 @@
|
|||
/* -*- Mode: C++; 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/. */
|
||||
|
||||
/* DOM object holding utility CSS functions */
|
||||
|
||||
#include "CSS.h"
|
||||
|
||||
#include "mozilla/dom/BindingDeclarations.h"
|
||||
#include "mozilla/ServoBindings.h"
|
||||
#include "nsCSSParser.h"
|
||||
#include "nsGlobalWindow.h"
|
||||
#include "nsIDocument.h"
|
||||
#include "nsIURI.h"
|
||||
#include "nsStyleUtil.h"
|
||||
#include "xpcpublic.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
struct SupportsParsingInfo
|
||||
{
|
||||
nsIURI* mDocURI;
|
||||
nsIURI* mBaseURI;
|
||||
nsIPrincipal* mPrincipal;
|
||||
StyleBackendType mStyleBackendType;
|
||||
};
|
||||
|
||||
static nsresult
|
||||
GetParsingInfo(const GlobalObject& aGlobal,
|
||||
SupportsParsingInfo& aInfo)
|
||||
{
|
||||
nsGlobalWindow* win = xpc::WindowOrNull(aGlobal.Get());
|
||||
if (!win) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIDocument> doc = win->GetDoc();
|
||||
if (!doc) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
aInfo.mDocURI = nsCOMPtr<nsIURI>(doc->GetDocumentURI()).get();
|
||||
aInfo.mBaseURI = nsCOMPtr<nsIURI>(doc->GetBaseURI()).get();
|
||||
aInfo.mPrincipal = win->GetPrincipal();
|
||||
aInfo.mStyleBackendType = doc->GetStyleBackendType();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
/* static */ bool
|
||||
CSS::Supports(const GlobalObject& aGlobal,
|
||||
const nsAString& aProperty,
|
||||
const nsAString& aValue,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
SupportsParsingInfo info;
|
||||
|
||||
nsresult rv = GetParsingInfo(aGlobal, info);
|
||||
if (NS_FAILED(rv)) {
|
||||
aRv.Throw(rv);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (info.mStyleBackendType == StyleBackendType::Servo) {
|
||||
NS_ConvertUTF16toUTF8 property(aProperty);
|
||||
NS_ConvertUTF16toUTF8 value(aValue);
|
||||
return Servo_CSSSupports(&property, &value);
|
||||
}
|
||||
|
||||
nsCSSParser parser;
|
||||
return parser.EvaluateSupportsDeclaration(aProperty, aValue, info.mDocURI,
|
||||
info.mBaseURI, info.mPrincipal);
|
||||
}
|
||||
|
||||
/* static */ bool
|
||||
CSS::Supports(const GlobalObject& aGlobal,
|
||||
const nsAString& aCondition,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
SupportsParsingInfo info;
|
||||
|
||||
nsresult rv = GetParsingInfo(aGlobal, info);
|
||||
if (NS_FAILED(rv)) {
|
||||
aRv.Throw(rv);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (info.mStyleBackendType == StyleBackendType::Servo) {
|
||||
MOZ_CRASH("stylo: CSS.supports() with arguments is not yet implemented");
|
||||
}
|
||||
|
||||
nsCSSParser parser;
|
||||
return parser.EvaluateSupportsCondition(aCondition, info.mDocURI,
|
||||
info.mBaseURI, info.mPrincipal);
|
||||
}
|
||||
|
||||
/* static */ void
|
||||
CSS::Escape(const GlobalObject& aGlobal,
|
||||
const nsAString& aIdent,
|
||||
nsAString& aReturn)
|
||||
{
|
||||
nsStyleUtil::AppendEscapedCSSIdent(aIdent, aReturn);
|
||||
}
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
44
layout/style/CSS.h
Normal file
44
layout/style/CSS.h
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
/* -*- Mode: C++; 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/. */
|
||||
|
||||
/* DOM object holding utility CSS functions */
|
||||
|
||||
#ifndef mozilla_dom_CSS_h_
|
||||
#define mozilla_dom_CSS_h_
|
||||
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "mozilla/Preferences.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
class ErrorResult;
|
||||
|
||||
namespace dom {
|
||||
|
||||
class GlobalObject;
|
||||
|
||||
class CSS {
|
||||
private:
|
||||
CSS() = delete;
|
||||
|
||||
public:
|
||||
static bool Supports(const GlobalObject& aGlobal,
|
||||
const nsAString& aProperty,
|
||||
const nsAString& aValue,
|
||||
ErrorResult& aRv);
|
||||
|
||||
static bool Supports(const GlobalObject& aGlobal,
|
||||
const nsAString& aDeclaration,
|
||||
ErrorResult& aRv);
|
||||
|
||||
static void Escape(const GlobalObject& aGlobal,
|
||||
const nsAString& aIdent,
|
||||
nsAString& aReturn);
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // mozilla_dom_CSS_h_
|
||||
361
layout/style/CSSCalc.h
Normal file
361
layout/style/CSSCalc.h
Normal file
|
|
@ -0,0 +1,361 @@
|
|||
/* vim: set shiftwidth=2 tabstop=8 autoindent cindent expandtab: */
|
||||
/* 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 CSSCalc_h_
|
||||
#define CSSCalc_h_
|
||||
|
||||
#include "nsCSSValue.h"
|
||||
#include "nsStyleCoord.h"
|
||||
#include <math.h>
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
namespace css {
|
||||
|
||||
/**
|
||||
* ComputeCalc computes the result of a calc() expression tree.
|
||||
*
|
||||
* It is templatized over a CalcOps class that is expected to provide:
|
||||
*
|
||||
* // input_type and input_array_type have a bunch of very specific
|
||||
* // expectations (which happen to be met by two classes (nsCSSValue
|
||||
* // and nsStyleCoord). There must be methods (roughly):
|
||||
* // input_array_type* input_type::GetArrayValue();
|
||||
* // uint32_t input_array_type::Count() const;
|
||||
* // input_type& input_array_type::Item(uint32_t);
|
||||
* typedef ... input_type;
|
||||
* typedef ... input_array_type;
|
||||
*
|
||||
* typedef ... result_type;
|
||||
*
|
||||
* // GetUnit(avalue) must return the correct nsCSSUnit for any
|
||||
* // value that represents a calc tree node (eCSSUnit_Calc*). For
|
||||
* // other nodes, it may return any non eCSSUnit_Calc* unit.
|
||||
* static nsCSSUnit GetUnit(const input_type& aValue);
|
||||
*
|
||||
* result_type
|
||||
* MergeAdditive(nsCSSUnit aCalcFunction,
|
||||
* result_type aValue1, result_type aValue2);
|
||||
*
|
||||
* result_type
|
||||
* MergeMultiplicativeL(nsCSSUnit aCalcFunction,
|
||||
* float aValue1, result_type aValue2);
|
||||
*
|
||||
* result_type
|
||||
* MergeMultiplicativeR(nsCSSUnit aCalcFunction,
|
||||
* result_type aValue1, float aValue2);
|
||||
*
|
||||
* result_type
|
||||
* ComputeLeafValue(const input_type& aValue);
|
||||
*
|
||||
* float
|
||||
* ComputeNumber(const input_type& aValue);
|
||||
*
|
||||
* The CalcOps methods might compute the calc() expression down to a
|
||||
* number, reduce some parts of it to a number but replicate other
|
||||
* parts, or produce a tree with a different data structure (for
|
||||
* example, nsCSS* for specified values vs nsStyle* for computed
|
||||
* values).
|
||||
*
|
||||
* For each leaf in the calc() expression, ComputeCalc will call either
|
||||
* ComputeNumber (when the leaf is the left side of a Times_L or the
|
||||
* right side of a Times_R or Divided) or ComputeLeafValue (otherwise).
|
||||
* (The CalcOps in the CSS parser that reduces purely numeric
|
||||
* expressions in turn calls ComputeCalc on numbers; other ops can
|
||||
* presume that expressions in the number positions have already been
|
||||
* normalized to a single numeric value and derive from
|
||||
* NumbersAlreadyNormalizedCalcOps.)
|
||||
*
|
||||
* For non-leaves, one of the Merge functions will be called:
|
||||
* MergeAdditive for Plus and Minus
|
||||
* MergeMultiplicativeL for Times_L (number * value)
|
||||
* MergeMultiplicativeR for Times_R (value * number) and Divided
|
||||
*/
|
||||
template <class CalcOps>
|
||||
static typename CalcOps::result_type
|
||||
ComputeCalc(const typename CalcOps::input_type& aValue, CalcOps &aOps)
|
||||
{
|
||||
switch (CalcOps::GetUnit(aValue)) {
|
||||
case eCSSUnit_Calc: {
|
||||
typename CalcOps::input_array_type *arr = aValue.GetArrayValue();
|
||||
MOZ_ASSERT(arr->Count() == 1, "unexpected length");
|
||||
return ComputeCalc(arr->Item(0), aOps);
|
||||
}
|
||||
case eCSSUnit_Calc_Plus:
|
||||
case eCSSUnit_Calc_Minus: {
|
||||
typename CalcOps::input_array_type *arr = aValue.GetArrayValue();
|
||||
MOZ_ASSERT(arr->Count() == 2, "unexpected length");
|
||||
typename CalcOps::result_type lhs = ComputeCalc(arr->Item(0), aOps),
|
||||
rhs = ComputeCalc(arr->Item(1), aOps);
|
||||
return aOps.MergeAdditive(CalcOps::GetUnit(aValue), lhs, rhs);
|
||||
}
|
||||
case eCSSUnit_Calc_Times_L: {
|
||||
typename CalcOps::input_array_type *arr = aValue.GetArrayValue();
|
||||
MOZ_ASSERT(arr->Count() == 2, "unexpected length");
|
||||
float lhs = aOps.ComputeNumber(arr->Item(0));
|
||||
typename CalcOps::result_type rhs = ComputeCalc(arr->Item(1), aOps);
|
||||
return aOps.MergeMultiplicativeL(CalcOps::GetUnit(aValue), lhs, rhs);
|
||||
}
|
||||
case eCSSUnit_Calc_Times_R:
|
||||
case eCSSUnit_Calc_Divided: {
|
||||
typename CalcOps::input_array_type *arr = aValue.GetArrayValue();
|
||||
MOZ_ASSERT(arr->Count() == 2, "unexpected length");
|
||||
typename CalcOps::result_type lhs = ComputeCalc(arr->Item(0), aOps);
|
||||
float rhs = aOps.ComputeNumber(arr->Item(1));
|
||||
return aOps.MergeMultiplicativeR(CalcOps::GetUnit(aValue), lhs, rhs);
|
||||
}
|
||||
default: {
|
||||
return aOps.ComputeLeafValue(aValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The input unit operation for input_type being nsCSSValue.
|
||||
*/
|
||||
struct CSSValueInputCalcOps
|
||||
{
|
||||
typedef nsCSSValue input_type;
|
||||
typedef nsCSSValue::Array input_array_type;
|
||||
|
||||
static nsCSSUnit GetUnit(const nsCSSValue& aValue)
|
||||
{
|
||||
return aValue.GetUnit();
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* Basic*CalcOps provide a partial implementation of the CalcOps
|
||||
* template parameter to ComputeCalc, for those callers whose merging
|
||||
* just consists of mathematics (rather than tree construction).
|
||||
*/
|
||||
|
||||
struct BasicCoordCalcOps
|
||||
{
|
||||
typedef nscoord result_type;
|
||||
|
||||
result_type
|
||||
MergeAdditive(nsCSSUnit aCalcFunction,
|
||||
result_type aValue1, result_type aValue2)
|
||||
{
|
||||
if (aCalcFunction == eCSSUnit_Calc_Plus) {
|
||||
return NSCoordSaturatingAdd(aValue1, aValue2);
|
||||
}
|
||||
MOZ_ASSERT(aCalcFunction == eCSSUnit_Calc_Minus,
|
||||
"unexpected unit");
|
||||
return NSCoordSaturatingSubtract(aValue1, aValue2, 0);
|
||||
}
|
||||
|
||||
result_type
|
||||
MergeMultiplicativeL(nsCSSUnit aCalcFunction,
|
||||
float aValue1, result_type aValue2)
|
||||
{
|
||||
MOZ_ASSERT(aCalcFunction == eCSSUnit_Calc_Times_L,
|
||||
"unexpected unit");
|
||||
return NSCoordSaturatingMultiply(aValue2, aValue1);
|
||||
}
|
||||
|
||||
result_type
|
||||
MergeMultiplicativeR(nsCSSUnit aCalcFunction,
|
||||
result_type aValue1, float aValue2)
|
||||
{
|
||||
MOZ_ASSERT(aCalcFunction == eCSSUnit_Calc_Times_R ||
|
||||
aCalcFunction == eCSSUnit_Calc_Divided,
|
||||
"unexpected unit");
|
||||
if (aCalcFunction == eCSSUnit_Calc_Divided) {
|
||||
aValue2 = 1.0f / aValue2;
|
||||
}
|
||||
return NSCoordSaturatingMultiply(aValue1, aValue2);
|
||||
}
|
||||
};
|
||||
|
||||
struct BasicFloatCalcOps
|
||||
{
|
||||
typedef float result_type;
|
||||
|
||||
result_type
|
||||
MergeAdditive(nsCSSUnit aCalcFunction,
|
||||
result_type aValue1, result_type aValue2)
|
||||
{
|
||||
if (aCalcFunction == eCSSUnit_Calc_Plus) {
|
||||
return aValue1 + aValue2;
|
||||
}
|
||||
MOZ_ASSERT(aCalcFunction == eCSSUnit_Calc_Minus,
|
||||
"unexpected unit");
|
||||
return aValue1 - aValue2;
|
||||
}
|
||||
|
||||
result_type
|
||||
MergeMultiplicativeL(nsCSSUnit aCalcFunction,
|
||||
float aValue1, result_type aValue2)
|
||||
{
|
||||
MOZ_ASSERT(aCalcFunction == eCSSUnit_Calc_Times_L,
|
||||
"unexpected unit");
|
||||
return aValue1 * aValue2;
|
||||
}
|
||||
|
||||
result_type
|
||||
MergeMultiplicativeR(nsCSSUnit aCalcFunction,
|
||||
result_type aValue1, float aValue2)
|
||||
{
|
||||
if (aCalcFunction == eCSSUnit_Calc_Times_R) {
|
||||
return aValue1 * aValue2;
|
||||
}
|
||||
MOZ_ASSERT(aCalcFunction == eCSSUnit_Calc_Divided,
|
||||
"unexpected unit");
|
||||
return aValue1 / aValue2;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* A ComputeNumber implementation for callers that can assume numbers
|
||||
* are already normalized (i.e., anything past the parser).
|
||||
*/
|
||||
struct NumbersAlreadyNormalizedOps : public CSSValueInputCalcOps
|
||||
{
|
||||
float ComputeNumber(const nsCSSValue& aValue)
|
||||
{
|
||||
MOZ_ASSERT(aValue.GetUnit() == eCSSUnit_Number, "unexpected unit");
|
||||
return aValue.GetFloatValue();
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* SerializeCalc appends the serialization of aValue to a string.
|
||||
*
|
||||
* It is templatized over a CalcOps class that is expected to provide:
|
||||
*
|
||||
* // input_type and input_array_type have a bunch of very specific
|
||||
* // expectations (which happen to be met by two classes (nsCSSValue
|
||||
* // and nsStyleCoord). There must be methods (roughly):
|
||||
* // input_array_type* input_type::GetArrayValue();
|
||||
* // uint32_t input_array_type::Count() const;
|
||||
* // input_type& input_array_type::Item(uint32_t);
|
||||
* typedef ... input_type;
|
||||
* typedef ... input_array_type;
|
||||
*
|
||||
* static nsCSSUnit GetUnit(const input_type& aValue);
|
||||
*
|
||||
* void Append(const char* aString);
|
||||
* void AppendLeafValue(const input_type& aValue);
|
||||
* void AppendNumber(const input_type& aValue);
|
||||
*
|
||||
* Data structures given may or may not have a toplevel eCSSUnit_Calc
|
||||
* node representing a calc whose toplevel is not min() or max().
|
||||
*/
|
||||
|
||||
template <class CalcOps>
|
||||
static void
|
||||
SerializeCalcInternal(const typename CalcOps::input_type& aValue, CalcOps &aOps);
|
||||
|
||||
// Serialize the toplevel value in a calc() tree. See big comment
|
||||
// above.
|
||||
template <class CalcOps>
|
||||
static void
|
||||
SerializeCalc(const typename CalcOps::input_type& aValue, CalcOps &aOps)
|
||||
{
|
||||
aOps.Append("calc(");
|
||||
nsCSSUnit unit = CalcOps::GetUnit(aValue);
|
||||
if (unit == eCSSUnit_Calc) {
|
||||
const typename CalcOps::input_array_type *array = aValue.GetArrayValue();
|
||||
MOZ_ASSERT(array->Count() == 1, "unexpected length");
|
||||
SerializeCalcInternal(array->Item(0), aOps);
|
||||
} else {
|
||||
SerializeCalcInternal(aValue, aOps);
|
||||
}
|
||||
aOps.Append(")");
|
||||
}
|
||||
|
||||
static inline bool
|
||||
IsCalcAdditiveUnit(nsCSSUnit aUnit)
|
||||
{
|
||||
return aUnit == eCSSUnit_Calc_Plus ||
|
||||
aUnit == eCSSUnit_Calc_Minus;
|
||||
}
|
||||
|
||||
static inline bool
|
||||
IsCalcMultiplicativeUnit(nsCSSUnit aUnit)
|
||||
{
|
||||
return aUnit == eCSSUnit_Calc_Times_L ||
|
||||
aUnit == eCSSUnit_Calc_Times_R ||
|
||||
aUnit == eCSSUnit_Calc_Divided;
|
||||
}
|
||||
|
||||
// Serialize a non-toplevel value in a calc() tree. See big comment
|
||||
// above.
|
||||
template <class CalcOps>
|
||||
/* static */ void
|
||||
SerializeCalcInternal(const typename CalcOps::input_type& aValue, CalcOps &aOps)
|
||||
{
|
||||
nsCSSUnit unit = CalcOps::GetUnit(aValue);
|
||||
if (IsCalcAdditiveUnit(unit)) {
|
||||
const typename CalcOps::input_array_type *array = aValue.GetArrayValue();
|
||||
MOZ_ASSERT(array->Count() == 2, "unexpected length");
|
||||
|
||||
SerializeCalcInternal(array->Item(0), aOps);
|
||||
|
||||
if (eCSSUnit_Calc_Plus == unit) {
|
||||
aOps.Append(" + ");
|
||||
} else {
|
||||
MOZ_ASSERT(eCSSUnit_Calc_Minus == unit, "unexpected unit");
|
||||
aOps.Append(" - ");
|
||||
}
|
||||
|
||||
bool needParens = IsCalcAdditiveUnit(CalcOps::GetUnit(array->Item(1)));
|
||||
if (needParens) {
|
||||
aOps.Append("(");
|
||||
}
|
||||
SerializeCalcInternal(array->Item(1), aOps);
|
||||
if (needParens) {
|
||||
aOps.Append(")");
|
||||
}
|
||||
} else if (IsCalcMultiplicativeUnit(unit)) {
|
||||
const typename CalcOps::input_array_type *array = aValue.GetArrayValue();
|
||||
MOZ_ASSERT(array->Count() == 2, "unexpected length");
|
||||
|
||||
bool needParens = IsCalcAdditiveUnit(CalcOps::GetUnit(array->Item(0)));
|
||||
if (needParens) {
|
||||
aOps.Append("(");
|
||||
}
|
||||
if (unit == eCSSUnit_Calc_Times_L) {
|
||||
aOps.AppendNumber(array->Item(0));
|
||||
} else {
|
||||
SerializeCalcInternal(array->Item(0), aOps);
|
||||
}
|
||||
if (needParens) {
|
||||
aOps.Append(")");
|
||||
}
|
||||
|
||||
if (eCSSUnit_Calc_Times_L == unit || eCSSUnit_Calc_Times_R == unit) {
|
||||
aOps.Append(" * ");
|
||||
} else {
|
||||
MOZ_ASSERT(eCSSUnit_Calc_Divided == unit, "unexpected unit");
|
||||
aOps.Append(" / ");
|
||||
}
|
||||
|
||||
nsCSSUnit subUnit = CalcOps::GetUnit(array->Item(1));
|
||||
needParens = IsCalcAdditiveUnit(subUnit) ||
|
||||
IsCalcMultiplicativeUnit(subUnit);
|
||||
if (needParens) {
|
||||
aOps.Append("(");
|
||||
}
|
||||
if (unit == eCSSUnit_Calc_Times_L) {
|
||||
SerializeCalcInternal(array->Item(1), aOps);
|
||||
} else {
|
||||
aOps.AppendNumber(array->Item(1));
|
||||
}
|
||||
if (needParens) {
|
||||
aOps.Append(")");
|
||||
}
|
||||
} else {
|
||||
aOps.AppendLeafValue(aValue);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace css
|
||||
|
||||
} // namespace mozilla
|
||||
|
||||
#endif /* !defined(CSSCalc_h_) */
|
||||
39
layout/style/CSSEnabledState.h
Normal file
39
layout/style/CSSEnabledState.h
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* 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/. */
|
||||
|
||||
/*
|
||||
* enum for whether a CSS feature (property, pseudo-class, etc.) is
|
||||
* enabled in a specific context
|
||||
*/
|
||||
|
||||
#ifndef mozilla_CSSEnabledState_h
|
||||
#define mozilla_CSSEnabledState_h
|
||||
|
||||
#include "mozilla/TypedEnumBits.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
enum class CSSEnabledState
|
||||
{
|
||||
// The default CSSEnabledState: only enable what's enabled for all
|
||||
// content, given the current values of preferences.
|
||||
eForAllContent = 0,
|
||||
// Enable features available in UA sheets.
|
||||
eInUASheets = 0x01,
|
||||
// Enable features available in chrome code.
|
||||
eInChrome = 0x02,
|
||||
// Special value to unconditionally enable everything. This implies
|
||||
// all the bits above, but is strictly more than just their OR-ed
|
||||
// union. This just skips any test so a feature will be enabled even
|
||||
// if it would have been disabled with all the bits above set.
|
||||
eIgnoreEnabledState = 0xff
|
||||
};
|
||||
|
||||
MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(CSSEnabledState)
|
||||
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // mozilla_CSSEnabledState_h
|
||||
166
layout/style/CSSLexer.cpp
Normal file
166
layout/style/CSSLexer.cpp
Normal file
|
|
@ -0,0 +1,166 @@
|
|||
/* -*- Mode: C++; 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/. */
|
||||
|
||||
#include "mozilla/dom/CSSLexer.h"
|
||||
#include "js/Value.h"
|
||||
#include "mozilla/dom/CSSLexerBinding.h"
|
||||
#include "mozilla/dom/ToJSValue.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
// Ensure that constants are consistent.
|
||||
|
||||
#define CHECK(X, Y) \
|
||||
static_assert(static_cast<int>(X) == static_cast<int>(Y), \
|
||||
"nsCSSToken and CSSTokenType should have identical values")
|
||||
|
||||
CHECK(eCSSToken_Whitespace, CSSTokenType::Whitespace);
|
||||
CHECK(eCSSToken_Comment, CSSTokenType::Comment);
|
||||
CHECK(eCSSToken_Ident, CSSTokenType::Ident);
|
||||
CHECK(eCSSToken_Function, CSSTokenType::Function);
|
||||
CHECK(eCSSToken_AtKeyword, CSSTokenType::At);
|
||||
CHECK(eCSSToken_ID, CSSTokenType::Id);
|
||||
CHECK(eCSSToken_Hash, CSSTokenType::Hash);
|
||||
CHECK(eCSSToken_Number, CSSTokenType::Number);
|
||||
CHECK(eCSSToken_Dimension, CSSTokenType::Dimension);
|
||||
CHECK(eCSSToken_Percentage, CSSTokenType::Percentage);
|
||||
CHECK(eCSSToken_String, CSSTokenType::String);
|
||||
CHECK(eCSSToken_Bad_String, CSSTokenType::Bad_string);
|
||||
CHECK(eCSSToken_URL, CSSTokenType::Url);
|
||||
CHECK(eCSSToken_Bad_URL, CSSTokenType::Bad_url);
|
||||
CHECK(eCSSToken_Symbol, CSSTokenType::Symbol);
|
||||
CHECK(eCSSToken_Includes, CSSTokenType::Includes);
|
||||
CHECK(eCSSToken_Dashmatch, CSSTokenType::Dashmatch);
|
||||
CHECK(eCSSToken_Beginsmatch, CSSTokenType::Beginsmatch);
|
||||
CHECK(eCSSToken_Endsmatch, CSSTokenType::Endsmatch);
|
||||
CHECK(eCSSToken_Containsmatch, CSSTokenType::Containsmatch);
|
||||
CHECK(eCSSToken_URange, CSSTokenType::Urange);
|
||||
CHECK(eCSSToken_HTMLComment, CSSTokenType::Htmlcomment);
|
||||
|
||||
#undef CHECK
|
||||
|
||||
CSSLexer::CSSLexer(const nsAString& aText)
|
||||
: mInput(aText)
|
||||
, mScanner(mInput, 1)
|
||||
{
|
||||
}
|
||||
|
||||
CSSLexer::~CSSLexer()
|
||||
{
|
||||
}
|
||||
|
||||
bool
|
||||
CSSLexer::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto,
|
||||
JS::MutableHandle<JSObject*> aReflector)
|
||||
{
|
||||
return CSSLexerBinding::Wrap(aCx, this, aGivenProto, aReflector);
|
||||
}
|
||||
|
||||
uint32_t
|
||||
CSSLexer::LineNumber()
|
||||
{
|
||||
// The scanner uses 1-based line numbers, but our callers expect
|
||||
// 0-based.
|
||||
return mScanner.GetLineNumber() - 1;
|
||||
}
|
||||
|
||||
uint32_t
|
||||
CSSLexer::ColumnNumber()
|
||||
{
|
||||
return mScanner.GetColumnNumber();
|
||||
}
|
||||
|
||||
void
|
||||
CSSLexer::PerformEOFFixup(const nsAString& aInputString, bool aPreserveBackslash,
|
||||
nsAString& aResult)
|
||||
{
|
||||
aResult.Append(aInputString);
|
||||
uint32_t eofChars = mScanner.GetEOFCharacters();
|
||||
|
||||
if (aPreserveBackslash &&
|
||||
(eofChars & (nsCSSScanner::eEOFCharacters_DropBackslash |
|
||||
nsCSSScanner::eEOFCharacters_ReplacementChar)) != 0) {
|
||||
eofChars &= ~(nsCSSScanner::eEOFCharacters_DropBackslash |
|
||||
nsCSSScanner::eEOFCharacters_ReplacementChar);
|
||||
aResult.Append('\\');
|
||||
}
|
||||
|
||||
if ((eofChars & nsCSSScanner::eEOFCharacters_DropBackslash) != 0 &&
|
||||
aResult.Length() > 0 && aResult.Last() == '\\') {
|
||||
aResult.Truncate(aResult.Length() - 1);
|
||||
}
|
||||
|
||||
nsCSSScanner::AppendImpliedEOFCharacters(nsCSSScanner::EOFCharacters(eofChars),
|
||||
aResult);
|
||||
}
|
||||
|
||||
void
|
||||
CSSLexer::NextToken(Nullable<CSSToken>& aResult)
|
||||
{
|
||||
nsCSSToken token;
|
||||
if (!mScanner.Next(token, eCSSScannerExclude_None)) {
|
||||
return;
|
||||
}
|
||||
|
||||
CSSToken& resultToken(aResult.SetValue());
|
||||
|
||||
resultToken.mTokenType = static_cast<CSSTokenType>(token.mType);
|
||||
resultToken.mStartOffset = mScanner.GetTokenOffset();
|
||||
resultToken.mEndOffset = mScanner.GetTokenEndOffset();
|
||||
|
||||
switch (token.mType) {
|
||||
case eCSSToken_Whitespace:
|
||||
break;
|
||||
|
||||
case eCSSToken_Ident:
|
||||
case eCSSToken_Function:
|
||||
case eCSSToken_AtKeyword:
|
||||
case eCSSToken_ID:
|
||||
case eCSSToken_Hash:
|
||||
resultToken.mText.Construct(token.mIdent);
|
||||
break;
|
||||
|
||||
case eCSSToken_Dimension:
|
||||
resultToken.mText.Construct(token.mIdent);
|
||||
MOZ_FALLTHROUGH;
|
||||
case eCSSToken_Number:
|
||||
case eCSSToken_Percentage:
|
||||
resultToken.mNumber.Construct(token.mNumber);
|
||||
resultToken.mHasSign.Construct(token.mHasSign);
|
||||
resultToken.mIsInteger.Construct(token.mIntegerValid);
|
||||
break;
|
||||
|
||||
case eCSSToken_String:
|
||||
case eCSSToken_Bad_String:
|
||||
case eCSSToken_URL:
|
||||
case eCSSToken_Bad_URL:
|
||||
resultToken.mText.Construct(token.mIdent);
|
||||
/* Don't bother emitting the delimiter, as it is readily extracted
|
||||
from the source string when needed. */
|
||||
break;
|
||||
|
||||
case eCSSToken_Symbol:
|
||||
resultToken.mText.Construct(nsString(&token.mSymbol, 1));
|
||||
break;
|
||||
|
||||
case eCSSToken_Includes:
|
||||
case eCSSToken_Dashmatch:
|
||||
case eCSSToken_Beginsmatch:
|
||||
case eCSSToken_Endsmatch:
|
||||
case eCSSToken_Containsmatch:
|
||||
case eCSSToken_URange:
|
||||
break;
|
||||
|
||||
case eCSSToken_Comment:
|
||||
case eCSSToken_HTMLComment:
|
||||
/* The comment text is easily extracted from the source string,
|
||||
and is rarely useful. */
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
39
layout/style/CSSLexer.h
Normal file
39
layout/style/CSSLexer.h
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
/* -*- Mode: C++; 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/. */
|
||||
|
||||
#ifndef CSSLexer_h___
|
||||
#define CSSLexer_h___
|
||||
|
||||
#include "mozilla/UniquePtr.h"
|
||||
#include "nsCSSScanner.h"
|
||||
#include "mozilla/dom/CSSLexerBinding.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
class CSSLexer : public NonRefcountedDOMObject
|
||||
{
|
||||
public:
|
||||
explicit CSSLexer(const nsAString&);
|
||||
~CSSLexer();
|
||||
|
||||
bool WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto,
|
||||
JS::MutableHandle<JSObject*> aReflector);
|
||||
|
||||
uint32_t LineNumber();
|
||||
uint32_t ColumnNumber();
|
||||
void PerformEOFFixup(const nsAString& aInputString, bool aPreserveBackslash,
|
||||
nsAString& aResult);
|
||||
void NextToken(Nullable<CSSToken>& aResult);
|
||||
|
||||
private:
|
||||
nsString mInput;
|
||||
nsCSSScanner mScanner;
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
#endif /* CSSLexer_h___ */
|
||||
34
layout/style/CSSRuleList.cpp
Normal file
34
layout/style/CSSRuleList.cpp
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* 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 "mozilla/dom/CSSRuleList.h"
|
||||
|
||||
#include "mozilla/dom/CSSRuleListBinding.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_0(CSSRuleList)
|
||||
|
||||
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(CSSRuleList)
|
||||
NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
|
||||
NS_INTERFACE_MAP_ENTRY(CSSRuleList)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIDOMCSSRuleList)
|
||||
NS_INTERFACE_MAP_ENTRY(nsISupports)
|
||||
NS_INTERFACE_MAP_END
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTING_ADDREF(CSSRuleList)
|
||||
NS_IMPL_CYCLE_COLLECTING_RELEASE(CSSRuleList)
|
||||
|
||||
/* virtual */ JSObject*
|
||||
CSSRuleList::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
|
||||
{
|
||||
return CSSRuleListBinding::Wrap(aCx, this, aGivenProto);
|
||||
}
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
66
layout/style/CSSRuleList.h
Normal file
66
layout/style/CSSRuleList.h
Normal file
|
|
@ -0,0 +1,66 @@
|
|||
/* -*- Mode: C++; 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/. */
|
||||
|
||||
#ifndef mozilla_dom_CSSRuleList_h
|
||||
#define mozilla_dom_CSSRuleList_h
|
||||
|
||||
#include "mozilla/StyleSheetInlines.h"
|
||||
#include "nsIDOMCSSRule.h"
|
||||
#include "nsIDOMCSSRuleList.h"
|
||||
#include "nsWrapperCache.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
// IID for the CSSRuleList interface
|
||||
#define NS_ICSSRULELIST_IID \
|
||||
{ 0x56ac8d1c, 0xc1ed, 0x45fe, \
|
||||
{ 0x9a, 0x4d, 0x3a, 0xdc, 0xf9, 0xd1, 0xb9, 0x3f } }
|
||||
|
||||
class CSSRuleList : public nsIDOMCSSRuleList
|
||||
, public nsWrapperCache
|
||||
{
|
||||
public:
|
||||
NS_DECLARE_STATIC_IID_ACCESSOR(NS_ICSSRULELIST_IID)
|
||||
|
||||
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
|
||||
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(CSSRuleList)
|
||||
|
||||
virtual CSSStyleSheet* GetParentObject() = 0;
|
||||
virtual JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override final;
|
||||
|
||||
NS_IMETHOD
|
||||
GetLength(uint32_t* aLength) override final
|
||||
{
|
||||
*aLength = Length();
|
||||
return NS_OK;
|
||||
}
|
||||
NS_IMETHOD
|
||||
Item(uint32_t aIndex, nsIDOMCSSRule** aReturn) override final
|
||||
{
|
||||
NS_IF_ADDREF(*aReturn = Item(aIndex));
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// WebIDL API
|
||||
nsIDOMCSSRule* Item(uint32_t aIndex)
|
||||
{
|
||||
bool unused;
|
||||
return IndexedGetter(aIndex, unused);
|
||||
}
|
||||
|
||||
virtual nsIDOMCSSRule* IndexedGetter(uint32_t aIndex, bool& aFound) = 0;
|
||||
virtual uint32_t Length() = 0;
|
||||
|
||||
protected:
|
||||
virtual ~CSSRuleList() {}
|
||||
};
|
||||
|
||||
NS_DEFINE_STATIC_IID_ACCESSOR(CSSRuleList, NS_ICSSRULELIST_IID)
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
#endif /* mozilla_dom_CSSRuleList_h */
|
||||
2026
layout/style/CSSStyleSheet.cpp
Normal file
2026
layout/style/CSSStyleSheet.cpp
Normal file
File diff suppressed because it is too large
Load diff
281
layout/style/CSSStyleSheet.h
Normal file
281
layout/style/CSSStyleSheet.h
Normal file
|
|
@ -0,0 +1,281 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
// vim:cindent:tabstop=2:expandtab:shiftwidth=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/. */
|
||||
|
||||
/* representation of a CSS style sheet */
|
||||
|
||||
#ifndef mozilla_CSSStyleSheet_h
|
||||
#define mozilla_CSSStyleSheet_h
|
||||
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "mozilla/IncrementalClearCOMRuleArray.h"
|
||||
#include "mozilla/MemoryReporting.h"
|
||||
#include "mozilla/StyleSheet.h"
|
||||
#include "mozilla/StyleSheetInfo.h"
|
||||
#include "mozilla/css/SheetParsingMode.h"
|
||||
#include "mozilla/dom/Element.h"
|
||||
|
||||
#include "nscore.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsAutoPtr.h"
|
||||
#include "nsICSSLoaderObserver.h"
|
||||
#include "nsTArrayForwardDeclare.h"
|
||||
#include "nsString.h"
|
||||
#include "mozilla/CORSMode.h"
|
||||
#include "nsCycleCollectionParticipant.h"
|
||||
#include "mozilla/net/ReferrerPolicy.h"
|
||||
#include "mozilla/dom/SRIMetadata.h"
|
||||
|
||||
class CSSRuleListImpl;
|
||||
class nsCSSRuleProcessor;
|
||||
class nsIURI;
|
||||
class nsMediaList;
|
||||
class nsMediaQueryResultCacheKey;
|
||||
class nsStyleSet;
|
||||
class nsPresContext;
|
||||
class nsXMLNameSpaceMap;
|
||||
|
||||
namespace mozilla {
|
||||
struct ChildSheetListBuilder;
|
||||
class CSSStyleSheet;
|
||||
|
||||
namespace css {
|
||||
class Rule;
|
||||
class GroupRule;
|
||||
class ImportRule;
|
||||
} // namespace css
|
||||
namespace dom {
|
||||
class CSSRuleList;
|
||||
} // namespace dom
|
||||
|
||||
// -------------------------------
|
||||
// CSS Style Sheet Inner Data Container
|
||||
//
|
||||
|
||||
struct CSSStyleSheetInner : public StyleSheetInfo
|
||||
{
|
||||
CSSStyleSheetInner(CSSStyleSheet* aPrimarySheet,
|
||||
CORSMode aCORSMode,
|
||||
ReferrerPolicy aReferrerPolicy,
|
||||
const dom::SRIMetadata& aIntegrity);
|
||||
CSSStyleSheetInner(CSSStyleSheetInner& aCopy,
|
||||
CSSStyleSheet* aPrimarySheet);
|
||||
~CSSStyleSheetInner();
|
||||
|
||||
CSSStyleSheetInner* CloneFor(CSSStyleSheet* aPrimarySheet);
|
||||
void AddSheet(CSSStyleSheet* aSheet);
|
||||
void RemoveSheet(CSSStyleSheet* aSheet);
|
||||
|
||||
void RebuildNameSpaces();
|
||||
|
||||
// Create a new namespace map
|
||||
nsresult CreateNamespaceMap();
|
||||
|
||||
size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const;
|
||||
|
||||
AutoTArray<CSSStyleSheet*, 8> mSheets;
|
||||
IncrementalClearCOMRuleArray mOrderedRules;
|
||||
nsAutoPtr<nsXMLNameSpaceMap> mNameSpaceMap;
|
||||
// Linked list of child sheets. This is al fundamentally broken, because
|
||||
// each of the child sheets has a unique parent... We can only hope (and
|
||||
// currently this is the case) that any time page JS can get ts hands on a
|
||||
// child sheet that means we've already ensured unique inners throughout its
|
||||
// parent chain and things are good.
|
||||
RefPtr<CSSStyleSheet> mFirstChild;
|
||||
};
|
||||
|
||||
|
||||
// -------------------------------
|
||||
// CSS Style Sheet
|
||||
//
|
||||
|
||||
// CID for the CSSStyleSheet class
|
||||
// 7985c7ac-9ddc-444d-9899-0c86ec122f54
|
||||
#define NS_CSS_STYLE_SHEET_IMPL_CID \
|
||||
{ 0x7985c7ac, 0x9ddc, 0x444d, \
|
||||
{ 0x98, 0x99, 0x0c, 0x86, 0xec, 0x12, 0x2f, 0x54 } }
|
||||
|
||||
|
||||
class CSSStyleSheet final : public StyleSheet
|
||||
, public nsICSSLoaderObserver
|
||||
{
|
||||
public:
|
||||
typedef net::ReferrerPolicy ReferrerPolicy;
|
||||
CSSStyleSheet(css::SheetParsingMode aParsingMode,
|
||||
CORSMode aCORSMode, ReferrerPolicy aReferrerPolicy);
|
||||
CSSStyleSheet(css::SheetParsingMode aParsingMode,
|
||||
CORSMode aCORSMode, ReferrerPolicy aReferrerPolicy,
|
||||
const dom::SRIMetadata& aIntegrity);
|
||||
|
||||
NS_DECL_ISUPPORTS_INHERITED
|
||||
NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(CSSStyleSheet, StyleSheet)
|
||||
|
||||
NS_DECLARE_STATIC_IID_ACCESSOR(NS_CSS_STYLE_SHEET_IMPL_CID)
|
||||
|
||||
bool HasRules() const;
|
||||
|
||||
/**
|
||||
* Set the stylesheet to be enabled. This may or may not make it
|
||||
* applicable. Note that this WILL inform the sheet's document of
|
||||
* its new applicable state if the state changes but WILL NOT call
|
||||
* BeginUpdate() or EndUpdate() on the document -- calling those is
|
||||
* the caller's responsibility. This allows use of SetEnabled when
|
||||
* batched updates are desired. If you want updates handled for
|
||||
* you, see nsIDOMStyleSheet::SetDisabled().
|
||||
*/
|
||||
void SetEnabled(bool aEnabled);
|
||||
|
||||
// style sheet owner info
|
||||
CSSStyleSheet* GetParentSheet() const; // may be null
|
||||
void SetOwningDocument(nsIDocument* aDocument);
|
||||
|
||||
// Find the ID of the owner inner window.
|
||||
uint64_t FindOwningWindowInnerID() const;
|
||||
#ifdef DEBUG
|
||||
void List(FILE* out = stdout, int32_t aIndent = 0) const;
|
||||
#endif
|
||||
|
||||
void AppendStyleSheet(CSSStyleSheet* aSheet);
|
||||
|
||||
// XXX do these belong here or are they generic?
|
||||
void AppendStyleRule(css::Rule* aRule);
|
||||
|
||||
int32_t StyleRuleCount() const;
|
||||
css::Rule* GetStyleRuleAt(int32_t aIndex) const;
|
||||
|
||||
nsresult DeleteRuleFromGroup(css::GroupRule* aGroup, uint32_t aIndex);
|
||||
nsresult InsertRuleIntoGroup(const nsAString& aRule, css::GroupRule* aGroup, uint32_t aIndex, uint32_t* _retval);
|
||||
|
||||
void SetTitle(const nsAString& aTitle) { mTitle = aTitle; }
|
||||
void SetMedia(nsMediaList* aMedia);
|
||||
|
||||
void SetOwnerRule(css::ImportRule* aOwnerRule) { mOwnerRule = aOwnerRule; /* Not ref counted */ }
|
||||
css::ImportRule* GetOwnerRule() const { return mOwnerRule; }
|
||||
// Workaround overloaded-virtual warning in GCC.
|
||||
using StyleSheet::GetOwnerRule;
|
||||
|
||||
nsXMLNameSpaceMap* GetNameSpaceMap() const { return mInner->mNameSpaceMap; }
|
||||
|
||||
already_AddRefed<CSSStyleSheet> Clone(CSSStyleSheet* aCloneParent,
|
||||
css::ImportRule* aCloneOwnerRule,
|
||||
nsIDocument* aCloneDocument,
|
||||
nsINode* aCloneOwningNode) const;
|
||||
|
||||
bool IsModified() const { return mDirty; }
|
||||
|
||||
void SetModifiedByChildRule() {
|
||||
NS_ASSERTION(mDirty,
|
||||
"sheet must be marked dirty before handing out child rules");
|
||||
DidDirty();
|
||||
}
|
||||
|
||||
nsresult AddRuleProcessor(nsCSSRuleProcessor* aProcessor);
|
||||
nsresult DropRuleProcessor(nsCSSRuleProcessor* aProcessor);
|
||||
|
||||
void AddStyleSet(nsStyleSet* aStyleSet);
|
||||
void DropStyleSet(nsStyleSet* aStyleSet);
|
||||
|
||||
// nsICSSLoaderObserver interface
|
||||
NS_IMETHOD StyleSheetLoaded(StyleSheet* aSheet, bool aWasAlternate,
|
||||
nsresult aStatus) override;
|
||||
|
||||
void EnsureUniqueInner();
|
||||
|
||||
// Append all of this sheet's child sheets to aArray.
|
||||
void AppendAllChildSheets(nsTArray<CSSStyleSheet*>& aArray);
|
||||
|
||||
bool UseForPresentation(nsPresContext* aPresContext,
|
||||
nsMediaQueryResultCacheKey& aKey) const;
|
||||
|
||||
nsresult ReparseSheet(const nsAString& aInput);
|
||||
|
||||
void SetInRuleProcessorCache() { mInRuleProcessorCache = true; }
|
||||
|
||||
// Function used as a callback to rebuild our inner's child sheet
|
||||
// list after we clone a unique inner for ourselves.
|
||||
static bool RebuildChildList(css::Rule* aRule, void* aBuilder);
|
||||
|
||||
size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const;
|
||||
|
||||
dom::Element* GetScopeElement() const { return mScopeElement; }
|
||||
void SetScopeElement(dom::Element* aScopeElement)
|
||||
{
|
||||
mScopeElement = aScopeElement;
|
||||
}
|
||||
|
||||
// WebIDL StyleSheet API
|
||||
nsMediaList* Media() final;
|
||||
|
||||
// WebIDL CSSStyleSheet API
|
||||
// Can't be inline because we can't include ImportRule here. And can't be
|
||||
// called GetOwnerRule because that would be ambiguous with the ImportRule
|
||||
// version.
|
||||
nsIDOMCSSRule* GetDOMOwnerRule() const final;
|
||||
|
||||
void WillDirty();
|
||||
void DidDirty();
|
||||
|
||||
private:
|
||||
CSSStyleSheet(const CSSStyleSheet& aCopy,
|
||||
CSSStyleSheet* aParentToUse,
|
||||
css::ImportRule* aOwnerRuleToUse,
|
||||
nsIDocument* aDocumentToUse,
|
||||
nsINode* aOwningNodeToUse);
|
||||
|
||||
CSSStyleSheet(const CSSStyleSheet& aCopy) = delete;
|
||||
CSSStyleSheet& operator=(const CSSStyleSheet& aCopy) = delete;
|
||||
|
||||
protected:
|
||||
virtual ~CSSStyleSheet();
|
||||
|
||||
void ClearRuleCascades();
|
||||
|
||||
// Add the namespace mapping from this @namespace rule to our namespace map
|
||||
nsresult RegisterNamespaceRule(css::Rule* aRule);
|
||||
|
||||
// Drop our reference to mRuleCollection
|
||||
void DropRuleCollection();
|
||||
|
||||
// Drop our reference to mMedia
|
||||
void DropMedia();
|
||||
|
||||
// Unlink our inner, if needed, for cycle collection
|
||||
void UnlinkInner();
|
||||
// Traverse our inner, if needed, for cycle collection
|
||||
void TraverseInner(nsCycleCollectionTraversalCallback &);
|
||||
|
||||
protected:
|
||||
// Internal methods which do not have security check and completeness check.
|
||||
dom::CSSRuleList* GetCssRulesInternal(ErrorResult& aRv);
|
||||
uint32_t InsertRuleInternal(const nsAString& aRule,
|
||||
uint32_t aIndex, ErrorResult& aRv);
|
||||
void DeleteRuleInternal(uint32_t aIndex, ErrorResult& aRv);
|
||||
|
||||
RefPtr<nsMediaList> mMedia;
|
||||
RefPtr<CSSStyleSheet> mNext;
|
||||
CSSStyleSheet* mParent; // weak ref
|
||||
css::ImportRule* mOwnerRule; // weak ref
|
||||
|
||||
RefPtr<CSSRuleListImpl> mRuleCollection;
|
||||
bool mDirty; // has been modified
|
||||
bool mInRuleProcessorCache;
|
||||
RefPtr<dom::Element> mScopeElement;
|
||||
|
||||
CSSStyleSheetInner* mInner;
|
||||
|
||||
AutoTArray<nsCSSRuleProcessor*, 8>* mRuleProcessors;
|
||||
nsTArray<nsStyleSet*> mStyleSets;
|
||||
|
||||
friend class ::nsMediaList;
|
||||
friend class ::nsCSSRuleProcessor;
|
||||
friend class mozilla::StyleSheet;
|
||||
friend struct mozilla::ChildSheetListBuilder;
|
||||
};
|
||||
|
||||
NS_DEFINE_STATIC_IID_ACCESSOR(CSSStyleSheet, NS_CSS_STYLE_SHEET_IMPL_CID)
|
||||
|
||||
} // namespace mozilla
|
||||
|
||||
#endif /* !defined(mozilla_CSSStyleSheet_h) */
|
||||
342
layout/style/CSSUnprefixingService.js
Normal file
342
layout/style/CSSUnprefixingService.js
Normal file
|
|
@ -0,0 +1,342 @@
|
|||
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- /
|
||||
/* vim: set shiftwidth=2 tabstop=8 autoindent cindent expandtab: */
|
||||
/* 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/. */
|
||||
|
||||
/* Implementation of a service that converts certain vendor-prefixed CSS
|
||||
properties to their unprefixed equivalents, for sites on a whitelist. */
|
||||
|
||||
"use strict";
|
||||
|
||||
const Cc = Components.classes;
|
||||
const Ci = Components.interfaces;
|
||||
const Cu = Components.utils;
|
||||
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
|
||||
function CSSUnprefixingService() {
|
||||
}
|
||||
|
||||
CSSUnprefixingService.prototype = {
|
||||
// Boilerplate:
|
||||
classID: Components.ID("{f0729490-e15c-4a2f-a3fb-99e1cc946b42}"),
|
||||
_xpcom_factory: XPCOMUtils.generateSingletonFactory(CSSUnprefixingService),
|
||||
QueryInterface: XPCOMUtils.generateQI([Ci.nsICSSUnprefixingService]),
|
||||
|
||||
// See documentation in nsICSSUnprefixingService.idl
|
||||
generateUnprefixedDeclaration: function(aPropName, aRightHalfOfDecl,
|
||||
aUnprefixedDecl /*out*/) {
|
||||
|
||||
// Convert our input strings to lower-case, for easier string-matching.
|
||||
// (NOTE: If we ever need to add support for unprefixing properties that
|
||||
// have case-sensitive parts, then we should do these toLowerCase()
|
||||
// conversions in a more targeted way, to avoid breaking those properties.)
|
||||
aPropName = aPropName.toLowerCase();
|
||||
aRightHalfOfDecl = aRightHalfOfDecl.toLowerCase();
|
||||
|
||||
// We have several groups of supported properties:
|
||||
// FIRST GROUP: Properties that can just be handled as aliases:
|
||||
// ============================================================
|
||||
const propertiesThatAreJustAliases = {
|
||||
"-webkit-background-size": "background-size",
|
||||
"-webkit-box-flex": "flex-grow",
|
||||
"-webkit-box-ordinal-group": "order",
|
||||
"-webkit-box-sizing": "box-sizing",
|
||||
"-webkit-transform": "transform",
|
||||
"-webkit-transform-origin": "transform-origin",
|
||||
};
|
||||
|
||||
let unprefixedPropName = propertiesThatAreJustAliases[aPropName];
|
||||
if (unprefixedPropName !== undefined) {
|
||||
aUnprefixedDecl.value = unprefixedPropName + ":" + aRightHalfOfDecl;
|
||||
return true;
|
||||
}
|
||||
|
||||
// SECOND GROUP: Properties that take a single keyword, where the
|
||||
// unprefixed version takes a different (but analogous) set of keywords:
|
||||
// =====================================================================
|
||||
const propertiesThatNeedKeywordMapping = {
|
||||
"-webkit-box-align" : {
|
||||
unprefixedPropName : "align-items",
|
||||
valueMap : {
|
||||
"start" : "flex-start",
|
||||
"center" : "center",
|
||||
"end" : "flex-end",
|
||||
"baseline" : "baseline",
|
||||
"stretch" : "stretch"
|
||||
}
|
||||
},
|
||||
"-webkit-box-orient" : {
|
||||
unprefixedPropName : "flex-direction",
|
||||
valueMap : {
|
||||
"horizontal" : "row",
|
||||
"inline-axis" : "row",
|
||||
"vertical" : "column",
|
||||
"block-axis" : "column"
|
||||
}
|
||||
},
|
||||
"-webkit-box-pack" : {
|
||||
unprefixedPropName : "justify-content",
|
||||
valueMap : {
|
||||
"start" : "flex-start",
|
||||
"center" : "center",
|
||||
"end" : "flex-end",
|
||||
"justify" : "space-between"
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
let propInfo = propertiesThatNeedKeywordMapping[aPropName];
|
||||
if (typeof(propInfo) != "undefined") {
|
||||
// Regexp for parsing the right half of a declaration, for keyword-valued
|
||||
// properties. Divides the right half of the declaration into:
|
||||
// 1) any leading whitespace
|
||||
// 2) the property value (one or more alphabetical character or hyphen)
|
||||
// 3) anything after that (e.g. "!important", ";")
|
||||
// Then we can look up the appropriate unprefixed-property value for the
|
||||
// value (part 2), and splice that together with the other parts and with
|
||||
// the unprefixed property-name to make the final declaration.
|
||||
const keywordValuedPropertyRegexp = /^(\s*)([a-z\-]+)(.*)/;
|
||||
let parts = keywordValuedPropertyRegexp.exec(aRightHalfOfDecl);
|
||||
if (!parts) {
|
||||
// Failed to parse a keyword out of aRightHalfOfDecl. (It probably has
|
||||
// no alphabetical characters.)
|
||||
return false;
|
||||
}
|
||||
|
||||
let mappedKeyword = propInfo.valueMap[parts[2]];
|
||||
if (mappedKeyword === undefined) {
|
||||
// We found a keyword in aRightHalfOfDecl, but we don't have a mapping
|
||||
// to an equivalent keyword for the unprefixed version of the property.
|
||||
return false;
|
||||
}
|
||||
|
||||
aUnprefixedDecl.value = propInfo.unprefixedPropName + ":" +
|
||||
parts[1] + // any leading whitespace
|
||||
mappedKeyword +
|
||||
parts[3]; // any trailing text (e.g. !important, semicolon, etc)
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// THIRD GROUP: Properties that may need arbitrary string-replacement:
|
||||
// ===================================================================
|
||||
const propertiesThatNeedStringReplacement = {
|
||||
// "-webkit-transition" takes a multi-part value. If "-webkit-transform"
|
||||
// appears as part of that value, replace it w/ "transform".
|
||||
// And regardless, we unprefix the "-webkit-transition" property-name.
|
||||
// (We could handle other prefixed properties in addition to 'transform'
|
||||
// here, but in practice "-webkit-transform" is the main one that's
|
||||
// likely to be transitioned & that we're concerned about supporting.)
|
||||
"-webkit-transition": {
|
||||
unprefixedPropName : "transition",
|
||||
stringMap : {
|
||||
"-webkit-transform" : "transform",
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
propInfo = propertiesThatNeedStringReplacement[aPropName];
|
||||
if (typeof(propInfo) != "undefined") {
|
||||
let newRightHalf = aRightHalfOfDecl;
|
||||
for (let strToReplace in propInfo.stringMap) {
|
||||
let replacement = propInfo.stringMap[strToReplace];
|
||||
newRightHalf = newRightHalf.split(strToReplace).join(replacement);
|
||||
}
|
||||
aUnprefixedDecl.value = propInfo.unprefixedPropName + ":" + newRightHalf;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// No known mapping for property aPropName.
|
||||
return false;
|
||||
},
|
||||
|
||||
// See documentation in nsICSSUnprefixingService.idl
|
||||
generateUnprefixedGradientValue: function(aPrefixedFuncName,
|
||||
aPrefixedFuncBody,
|
||||
aUnprefixedFuncName, /*[out]*/
|
||||
aUnprefixedFuncBody /*[out]*/) {
|
||||
var unprefixedFuncName, newValue;
|
||||
if (aPrefixedFuncName == "-webkit-gradient") {
|
||||
// Create expression for oldGradientParser:
|
||||
var parts = this.oldGradientParser(aPrefixedFuncBody);
|
||||
var type = parts[0].name;
|
||||
newValue = this.standardizeOldGradientArgs(type, parts.slice(1));
|
||||
unprefixedFuncName = type + "-gradient";
|
||||
}else{ // we're dealing with more modern syntax - should be somewhat easier, at least for linear gradients.
|
||||
// Fix three things: remove -webkit-, add 'to ' before reversed top/bottom keywords (linear) or 'at ' before position keywords (radial), recalculate deg-values
|
||||
// -webkit-linear-gradient( [ [ <angle> | [top | bottom] || [left | right] ],]? <color-stop>[, <color-stop>]+);
|
||||
if (aPrefixedFuncName != "-webkit-linear-gradient" &&
|
||||
aPrefixedFuncName != "-webkit-radial-gradient") {
|
||||
// Unrecognized prefixed gradient type
|
||||
return false;
|
||||
}
|
||||
unprefixedFuncName = aPrefixedFuncName.replace(/-webkit-/, '');
|
||||
|
||||
// Keywords top, bottom, left, right: can be stand-alone or combined pairwise but in any order ('top left' or 'left top')
|
||||
// These give the starting edge or corner in the -webkit syntax. The standardised equivalent is 'to ' plus opposite values for linear gradients, 'at ' plus same values for radial gradients
|
||||
if(unprefixedFuncName.indexOf('linear') > -1){
|
||||
newValue = aPrefixedFuncBody.replace(/(top|bottom|left|right)+\s*(top|bottom|left|right)*/, function(str){
|
||||
var words = str.split(/\s+/);
|
||||
for(var i=0; i<words.length; i++){
|
||||
switch(words[i].toLowerCase()){
|
||||
case 'top':
|
||||
words[i] = 'bottom';
|
||||
break;
|
||||
case 'bottom':
|
||||
words[i] = 'top';
|
||||
break;
|
||||
case 'left':
|
||||
words[i] = 'right';
|
||||
break;
|
||||
case 'right':
|
||||
words[i] = 'left';
|
||||
}
|
||||
}
|
||||
str = words.join(' ');
|
||||
return ( 'to ' + str);
|
||||
});
|
||||
}else{
|
||||
newValue = aPrefixedFuncBody.replace(/(top|bottom|left|right)+\s/, 'at $1 ');
|
||||
}
|
||||
|
||||
newValue = newValue.replace(/\d+deg/, function (val) {
|
||||
return (360 - (parseInt(val)-90))+'deg';
|
||||
});
|
||||
|
||||
}
|
||||
aUnprefixedFuncName.value = unprefixedFuncName;
|
||||
aUnprefixedFuncBody.value = newValue;
|
||||
return true;
|
||||
},
|
||||
|
||||
// Helpers for generateUnprefixedGradientValue():
|
||||
// ----------------------------------------------
|
||||
oldGradientParser : function(str){
|
||||
/** This method takes a legacy -webkit-gradient() method call and parses it
|
||||
to pull out the values, function names and their arguments.
|
||||
It returns something like [{name:'-webkit-gradient',args:[{name:'linear'}, {name:'top left'} ... ]}]
|
||||
*/
|
||||
var objs = [{}], path=[], current, word='', separator_chars = [',', '(', ')'];
|
||||
current = objs[0], path[0] = objs;
|
||||
//str = str.replace(/\s*\(/g, '('); // sorry, ws in front of ( would make parsing a lot harder
|
||||
for(var i = 0; i < str.length; i++){
|
||||
if(separator_chars.indexOf(str[i]) === -1){
|
||||
word += str[i];
|
||||
}else{ // now we have a "separator" - presumably we've also got a "word" or value
|
||||
current.name = word.trim();
|
||||
//GM_log(word+' '+path.length+' '+str[i])
|
||||
word = '';
|
||||
if(str[i] === '('){ // we assume the 'word' is a function, for example -webkit-gradient() or rgb(), so we create a place to record the arguments
|
||||
if(!('args' in current)){
|
||||
current.args = [];
|
||||
}
|
||||
current.args.push({});
|
||||
path.push(current.args);
|
||||
current = current.args[current.args.length - 1];
|
||||
path.push(current);
|
||||
}else if(str[i] === ')'){ // function is ended, no more arguments - go back to appending details to the previous branch of the tree
|
||||
current = path.pop(); // drop 'current'
|
||||
current = path.pop(); // drop 'args' reference
|
||||
}else{
|
||||
path.pop(); // remove 'current' object from path, we have no arguments to add
|
||||
var current_parent = path[path.length - 1] || objs; // last object on current path refers to array that contained the previous "current"
|
||||
current_parent.push({}); // we need a new object to hold this "word" or value
|
||||
current = current_parent[current_parent.length - 1]; // that object is now the 'current'
|
||||
path.push(current);
|
||||
//GM_log(path.length)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return objs;
|
||||
},
|
||||
|
||||
/* Given an array of args for "-webkit-gradient(...)" returned by
|
||||
* oldGradientParser(), this function constructs a string representing the
|
||||
* equivalent arguments for a standard "linear-gradient(...)" or
|
||||
* "radial-gradient(...)" expression.
|
||||
*
|
||||
* @param type Either 'linear' or 'radial'.
|
||||
* @param args An array of args for a "-webkit-gradient(...)" expression,
|
||||
* provided by oldGradientParser() (not including gradient type).
|
||||
*/
|
||||
standardizeOldGradientArgs : function(type, args){
|
||||
var stdArgStr = "";
|
||||
var stops = [];
|
||||
if(/^linear/.test(type)){
|
||||
// linear gradient, args 1 and 2 tend to be start/end keywords
|
||||
var points = [].concat(args[0].name.split(/\s+/), args[1].name.split(/\s+/)); // example: [left, top, right, top]
|
||||
// Old webkit syntax "uses a two-point syntax that lets you explicitly state where a linear gradient starts and ends"
|
||||
// if start/end keywords are percentages, let's massage the values a little more..
|
||||
var rxPercTest = /\d+\%/;
|
||||
if(rxPercTest.test(points[0]) || points[0] == 0){
|
||||
var startX = parseInt(points[0]), startY = parseInt(points[1]), endX = parseInt(points[2]), endY = parseInt(points[3]);
|
||||
stdArgStr += ((Math.atan2(endY- startY, endX - startX)) * (180 / Math.PI)+90) + 'deg';
|
||||
}else{
|
||||
if(points[1] === points[3]){ // both 'top' or 'bottom, this linear gradient goes left-right
|
||||
stdArgStr += 'to ' + points[2];
|
||||
}else if(points[0] === points[2]){ // both 'left' or 'right', this linear gradient goes top-bottom
|
||||
stdArgStr += 'to ' + points[3];
|
||||
}else if(points[1] === 'top'){ // diagonal gradient - from top left to opposite corner is 135deg
|
||||
stdArgStr += '135deg';
|
||||
}else{
|
||||
stdArgStr += '45deg';
|
||||
}
|
||||
}
|
||||
|
||||
}else if(/^radial/i.test(type)){ // oooh, radial gradients..
|
||||
stdArgStr += 'circle ' + args[3].name.replace(/(\d+)$/, '$1px') + ' at ' + args[0].name.replace(/(\d+) /, '$1px ').replace(/(\d+)$/, '$1px');
|
||||
}
|
||||
|
||||
var toColor;
|
||||
for(var j = type === 'linear' ? 2 : 4; j < args.length; j++){
|
||||
var position, color, colorIndex;
|
||||
if(args[j].name === 'color-stop'){
|
||||
position = args[j].args[0].name;
|
||||
colorIndex = 1;
|
||||
}else if (args[j].name === 'to') {
|
||||
position = '100%';
|
||||
colorIndex = 0;
|
||||
}else if (args[j].name === 'from') {
|
||||
position = '0%';
|
||||
colorIndex = 0;
|
||||
};
|
||||
if (position.indexOf('%') === -1) { // original Safari syntax had 0.5 equivalent to 50%
|
||||
position = (parseFloat(position) * 100) +'%';
|
||||
};
|
||||
color = args[j].args[colorIndex].name;
|
||||
if (args[j].args[colorIndex].args) { // the color is itself a function call, like rgb()
|
||||
color += '(' + this.colorValue(args[j].args[colorIndex].args) + ')';
|
||||
};
|
||||
if (args[j].name === 'from'){
|
||||
stops.unshift(color + ' ' + position);
|
||||
}else if(args[j].name === 'to'){
|
||||
toColor = color;
|
||||
}else{
|
||||
stops.push(color + ' ' + position);
|
||||
}
|
||||
}
|
||||
|
||||
// translating values to right syntax
|
||||
for(var j = 0; j < stops.length; j++){
|
||||
stdArgStr += ', ' + stops[j];
|
||||
}
|
||||
if(toColor){
|
||||
stdArgStr += ', ' + toColor + ' 100%';
|
||||
}
|
||||
return stdArgStr;
|
||||
},
|
||||
|
||||
colorValue: function(obj){
|
||||
var ar = [];
|
||||
for (var i = 0; i < obj.length; i++) {
|
||||
ar.push(obj[i].name);
|
||||
};
|
||||
return ar.join(', ');
|
||||
},
|
||||
};
|
||||
|
||||
this.NSGetFactory = XPCOMUtils.generateNSGetFactory([CSSUnprefixingService]);
|
||||
2
layout/style/CSSUnprefixingService.manifest
Normal file
2
layout/style/CSSUnprefixingService.manifest
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
component {f0729490-e15c-4a2f-a3fb-99e1cc946b42} CSSUnprefixingService.js
|
||||
contract @mozilla.org/css-unprefixing-service;1 {f0729490-e15c-4a2f-a3fb-99e1cc946b42}
|
||||
47
layout/style/CSSValue.h
Normal file
47
layout/style/CSSValue.h
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=2 et sw=2 tw=80: */
|
||||
/* 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/. */
|
||||
|
||||
/* DOM object representing values in DOM computed style */
|
||||
|
||||
#ifndef mozilla_dom_CSSValue_h_
|
||||
#define mozilla_dom_CSSValue_h_
|
||||
|
||||
#include "nsWrapperCache.h"
|
||||
#include "nsStringFwd.h"
|
||||
|
||||
class nsROCSSPrimitiveValue;
|
||||
namespace mozilla {
|
||||
class ErrorResult;
|
||||
} // namespace mozilla
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
/**
|
||||
* CSSValue - a DOM object representing values in DOM computed style.
|
||||
*/
|
||||
class CSSValue : public nsISupports,
|
||||
public nsWrapperCache
|
||||
{
|
||||
public:
|
||||
// CSSValue
|
||||
virtual void GetCssText(nsString& aText, mozilla::ErrorResult& aRv) = 0;
|
||||
virtual void SetCssText(const nsAString& aText, mozilla::ErrorResult& aRv) = 0;
|
||||
virtual uint16_t CssValueType() const = 0;
|
||||
|
||||
// Downcasting
|
||||
|
||||
/**
|
||||
* Return this as a nsROCSSPrimitiveValue* if its a primitive value, and null
|
||||
* otherwise.
|
||||
*/
|
||||
nsROCSSPrimitiveValue *AsPrimitiveValue();
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
#endif
|
||||
195
layout/style/CSSVariableDeclarations.cpp
Normal file
195
layout/style/CSSVariableDeclarations.cpp
Normal file
|
|
@ -0,0 +1,195 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* 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/. */
|
||||
|
||||
/* CSS Custom Property assignments for a Declaration at a given priority */
|
||||
|
||||
#include "CSSVariableDeclarations.h"
|
||||
|
||||
#include "CSSVariableResolver.h"
|
||||
#include "nsCSSScanner.h"
|
||||
#include "nsRuleData.h"
|
||||
|
||||
// These three special string values are used to represent specified values of
|
||||
// 'initial', 'inherit' and 'unset'. (Note that none of these are valid
|
||||
// variable values.)
|
||||
#define INITIAL_VALUE "!"
|
||||
#define INHERIT_VALUE ";"
|
||||
#define UNSET_VALUE ")"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
CSSVariableDeclarations::CSSVariableDeclarations()
|
||||
{
|
||||
MOZ_COUNT_CTOR(CSSVariableDeclarations);
|
||||
}
|
||||
|
||||
CSSVariableDeclarations::CSSVariableDeclarations(const CSSVariableDeclarations& aOther)
|
||||
{
|
||||
MOZ_COUNT_CTOR(CSSVariableDeclarations);
|
||||
CopyVariablesFrom(aOther);
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
CSSVariableDeclarations::~CSSVariableDeclarations()
|
||||
{
|
||||
MOZ_COUNT_DTOR(CSSVariableDeclarations);
|
||||
}
|
||||
#endif
|
||||
|
||||
CSSVariableDeclarations&
|
||||
CSSVariableDeclarations::operator=(const CSSVariableDeclarations& aOther)
|
||||
{
|
||||
if (this == &aOther) {
|
||||
return *this;
|
||||
}
|
||||
|
||||
mVariables.Clear();
|
||||
CopyVariablesFrom(aOther);
|
||||
return *this;
|
||||
}
|
||||
|
||||
void
|
||||
CSSVariableDeclarations::CopyVariablesFrom(const CSSVariableDeclarations& aOther)
|
||||
{
|
||||
for (auto iter = aOther.mVariables.ConstIter(); !iter.Done(); iter.Next()) {
|
||||
mVariables.Put(iter.Key(), iter.UserData());
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
CSSVariableDeclarations::Has(const nsAString& aName) const
|
||||
{
|
||||
nsString value;
|
||||
return mVariables.Get(aName, &value);
|
||||
}
|
||||
|
||||
bool
|
||||
CSSVariableDeclarations::Get(const nsAString& aName,
|
||||
Type& aType,
|
||||
nsString& aTokenStream) const
|
||||
{
|
||||
nsString value;
|
||||
if (!mVariables.Get(aName, &value)) {
|
||||
return false;
|
||||
}
|
||||
if (value.EqualsLiteral(INITIAL_VALUE)) {
|
||||
aType = eInitial;
|
||||
aTokenStream.Truncate();
|
||||
} else if (value.EqualsLiteral(INHERIT_VALUE)) {
|
||||
aType = eInitial;
|
||||
aTokenStream.Truncate();
|
||||
} else if (value.EqualsLiteral(UNSET_VALUE)) {
|
||||
aType = eUnset;
|
||||
aTokenStream.Truncate();
|
||||
} else {
|
||||
aType = eTokenStream;
|
||||
aTokenStream = value;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
CSSVariableDeclarations::PutTokenStream(const nsAString& aName,
|
||||
const nsString& aTokenStream)
|
||||
{
|
||||
MOZ_ASSERT(!aTokenStream.EqualsLiteral(INITIAL_VALUE) &&
|
||||
!aTokenStream.EqualsLiteral(INHERIT_VALUE) &&
|
||||
!aTokenStream.EqualsLiteral(UNSET_VALUE));
|
||||
mVariables.Put(aName, aTokenStream);
|
||||
}
|
||||
|
||||
void
|
||||
CSSVariableDeclarations::PutInitial(const nsAString& aName)
|
||||
{
|
||||
mVariables.Put(aName, NS_LITERAL_STRING(INITIAL_VALUE));
|
||||
}
|
||||
|
||||
void
|
||||
CSSVariableDeclarations::PutInherit(const nsAString& aName)
|
||||
{
|
||||
mVariables.Put(aName, NS_LITERAL_STRING(INHERIT_VALUE));
|
||||
}
|
||||
|
||||
void
|
||||
CSSVariableDeclarations::PutUnset(const nsAString& aName)
|
||||
{
|
||||
mVariables.Put(aName, NS_LITERAL_STRING(UNSET_VALUE));
|
||||
}
|
||||
|
||||
void
|
||||
CSSVariableDeclarations::Remove(const nsAString& aName)
|
||||
{
|
||||
mVariables.Remove(aName);
|
||||
}
|
||||
|
||||
void
|
||||
CSSVariableDeclarations::MapRuleInfoInto(nsRuleData* aRuleData)
|
||||
{
|
||||
if (!(aRuleData->mSIDs & NS_STYLE_INHERIT_BIT(Variables))) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!aRuleData->mVariables) {
|
||||
aRuleData->mVariables = new CSSVariableDeclarations(*this);
|
||||
} else {
|
||||
for (auto iter = mVariables.Iter(); !iter.Done(); iter.Next()) {
|
||||
nsDataHashtable<nsStringHashKey, nsString>& variables =
|
||||
aRuleData->mVariables->mVariables;
|
||||
const nsAString& aName = iter.Key();
|
||||
if (!variables.Contains(aName)) {
|
||||
variables.Put(aName, iter.UserData());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
CSSVariableDeclarations::AddVariablesToResolver(
|
||||
CSSVariableResolver* aResolver) const
|
||||
{
|
||||
for (auto iter = mVariables.ConstIter(); !iter.Done(); iter.Next()) {
|
||||
const nsAString& name = iter.Key();
|
||||
nsString value = iter.UserData();
|
||||
if (value.EqualsLiteral(INITIAL_VALUE)) {
|
||||
// Values of 'initial' are treated the same as an invalid value in the
|
||||
// variable resolver.
|
||||
aResolver->Put(name, EmptyString(),
|
||||
eCSSTokenSerialization_Nothing,
|
||||
eCSSTokenSerialization_Nothing,
|
||||
false);
|
||||
} else if (value.EqualsLiteral(INHERIT_VALUE) ||
|
||||
value.EqualsLiteral(UNSET_VALUE)) {
|
||||
// Values of 'inherit' and 'unset' don't need any handling, since it means
|
||||
// we just need to keep whatever value is currently in the resolver. This
|
||||
// is because the specified variable declarations already have only the
|
||||
// winning declaration for the variable and no longer have any of the
|
||||
// others.
|
||||
} else {
|
||||
// At this point, we don't know what token types are at the start and end
|
||||
// of the specified variable value. These will be determined later during
|
||||
// the resolving process.
|
||||
aResolver->Put(name, value,
|
||||
eCSSTokenSerialization_Nothing,
|
||||
eCSSTokenSerialization_Nothing,
|
||||
false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
size_t
|
||||
CSSVariableDeclarations::SizeOfIncludingThis(
|
||||
mozilla::MallocSizeOf aMallocSizeOf) const
|
||||
{
|
||||
size_t n = aMallocSizeOf(this);
|
||||
n += mVariables.ShallowSizeOfExcludingThis(aMallocSizeOf);
|
||||
for (auto iter = mVariables.ConstIter(); !iter.Done(); iter.Next()) {
|
||||
n += iter.Key().SizeOfExcludingThisIfUnshared(aMallocSizeOf);
|
||||
n += iter.Data().SizeOfExcludingThisIfUnshared(aMallocSizeOf);
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
} // namespace mozilla
|
||||
139
layout/style/CSSVariableDeclarations.h
Normal file
139
layout/style/CSSVariableDeclarations.h
Normal file
|
|
@ -0,0 +1,139 @@
|
|||
/* vim: set shiftwidth=2 tabstop=8 autoindent cindent expandtab: */
|
||||
/* 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/. */
|
||||
|
||||
/* CSS Custom Property assignments for a Declaration at a given priority */
|
||||
|
||||
#ifndef mozilla_CSSVariableDeclarations_h
|
||||
#define mozilla_CSSVariableDeclarations_h
|
||||
|
||||
#include "nsDataHashtable.h"
|
||||
|
||||
namespace mozilla {
|
||||
class CSSVariableResolver;
|
||||
} // namespace mozilla
|
||||
struct nsRuleData;
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
class CSSVariableDeclarations
|
||||
{
|
||||
public:
|
||||
CSSVariableDeclarations();
|
||||
CSSVariableDeclarations(const CSSVariableDeclarations& aOther);
|
||||
#ifdef DEBUG
|
||||
~CSSVariableDeclarations();
|
||||
#endif
|
||||
CSSVariableDeclarations& operator=(const CSSVariableDeclarations& aOther);
|
||||
|
||||
/**
|
||||
* Returns whether this set of variable declarations includes a variable
|
||||
* with a given name.
|
||||
*
|
||||
* @param aName The variable name (not including any "--" prefix that would
|
||||
* be part of the custom property name).
|
||||
*/
|
||||
bool Has(const nsAString& aName) const;
|
||||
|
||||
/**
|
||||
* Represents the type of a variable value.
|
||||
*/
|
||||
enum Type {
|
||||
eTokenStream, // a stream of CSS tokens (the usual type for variables)
|
||||
eInitial, // 'initial'
|
||||
eInherit, // 'inherit'
|
||||
eUnset // 'unset'
|
||||
};
|
||||
|
||||
/**
|
||||
* Gets the value of a variable in this set of variable declarations.
|
||||
*
|
||||
* @param aName The variable name (not including any "--" prefix that would
|
||||
* be part of the custom property name).
|
||||
* @param aType Out parameter into which the type of the variable value will
|
||||
* be stored.
|
||||
* @param aValue Out parameter into which the value of the variable will
|
||||
* be stored. If the variable is 'initial', 'inherit' or 'unset', this will
|
||||
* be the empty string.
|
||||
* @return Whether a variable with the given name was found. When false
|
||||
* is returned, aType and aValue will not be modified.
|
||||
*/
|
||||
bool Get(const nsAString& aName, Type& aType, nsString& aValue) const;
|
||||
|
||||
/**
|
||||
* Adds or modifies an existing entry in this set of variable declarations
|
||||
* to have the value 'initial'.
|
||||
*
|
||||
* @param aName The variable name (not including any "--" prefix that would
|
||||
* be part of the custom property name) whose value is to be set.
|
||||
*/
|
||||
void PutInitial(const nsAString& aName);
|
||||
|
||||
/**
|
||||
* Adds or modifies an existing entry in this set of variable declarations
|
||||
* to have the value 'inherit'.
|
||||
*
|
||||
* @param aName The variable name (not including any "--" prefix that would
|
||||
* be part of the custom property name) whose value is to be set.
|
||||
*/
|
||||
void PutInherit(const nsAString& aName);
|
||||
|
||||
/**
|
||||
* Adds or modifies an existing entry in this set of variable declarations
|
||||
* to have the value 'unset'.
|
||||
*
|
||||
* @param aName The variable name (not including any "--" prefix that would
|
||||
* be part of the custom property name) whose value is to be set.
|
||||
*/
|
||||
void PutUnset(const nsAString& aName);
|
||||
|
||||
/**
|
||||
* Adds or modifies an existing entry in this set of variable declarations
|
||||
* to have a token stream value.
|
||||
*
|
||||
* @param aName The variable name (not including any "--" prefix that would
|
||||
* be part of the custom property name) whose value is to be set.
|
||||
* @param aTokenStream The CSS token stream.
|
||||
*/
|
||||
void PutTokenStream(const nsAString& aName, const nsString& aTokenStream);
|
||||
|
||||
/**
|
||||
* Removes an entry in this set of variable declarations.
|
||||
*
|
||||
* @param aName The variable name (not including any "--" prefix that would
|
||||
* be part of the custom property name) whose entry is to be removed.
|
||||
*/
|
||||
void Remove(const nsAString& aName);
|
||||
|
||||
/**
|
||||
* Returns the number of entries in this set of variable declarations.
|
||||
*/
|
||||
uint32_t Count() const { return mVariables.Count(); }
|
||||
|
||||
/**
|
||||
* Copies each variable value from this object into aRuleData, unless that
|
||||
* variable already exists on aRuleData.
|
||||
*/
|
||||
void MapRuleInfoInto(nsRuleData* aRuleData);
|
||||
|
||||
/**
|
||||
* Copies the variables from this object into aResolver, marking them as
|
||||
* specified values.
|
||||
*/
|
||||
void AddVariablesToResolver(CSSVariableResolver* aResolver) const;
|
||||
|
||||
size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const;
|
||||
|
||||
private:
|
||||
/**
|
||||
* Adds all the variable declarations from aOther into this object.
|
||||
*/
|
||||
void CopyVariablesFrom(const CSSVariableDeclarations& aOther);
|
||||
|
||||
nsDataHashtable<nsStringHashKey, nsString> mVariables;
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
|
||||
#endif
|
||||
190
layout/style/CSSVariableImageTable.h
Normal file
190
layout/style/CSSVariableImageTable.h
Normal file
|
|
@ -0,0 +1,190 @@
|
|||
/* -*- Mode: C++; 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/. */
|
||||
|
||||
/* A global table that tracks images referenced by CSS variables. */
|
||||
|
||||
#ifndef mozilla_CSSVariableImageTable_h
|
||||
#define mozilla_CSSVariableImageTable_h
|
||||
|
||||
#include "nsClassHashtable.h"
|
||||
#include "nsCSSPropertyID.h"
|
||||
#include "nsCSSValue.h"
|
||||
#include "nsStyleContext.h"
|
||||
#include "nsTArray.h"
|
||||
|
||||
/**
|
||||
* CSSVariableImageTable maintains a global mapping
|
||||
* (nsStyleContext, nsCSSPropertyID) -> nsTArray<ImageValue>
|
||||
* which allows us to track the relationship between CSS property values
|
||||
* involving variables and any images they may reference.
|
||||
*
|
||||
* When properties like background-image contain a normal url(), the
|
||||
* Declaration's data block will hold a reference to the ImageValue. When a
|
||||
* token stream is used, the Declaration only holds on to an
|
||||
* nsCSSValueTokenStream object, and the ImageValue would only exist for the
|
||||
* duration of nsRuleNode::WalkRuleTree, in the AutoCSSValueArray. So instead
|
||||
* when we re-parse a token stream and get an ImageValue, we record it in the
|
||||
* CSSVariableImageTable to keep the ImageValue alive. Such ImageValues are
|
||||
* eventually freed the next time the token stream is re-parsed, or when the
|
||||
* associated style context is destroyed.
|
||||
*
|
||||
* To add ImageValues to the CSSVariableImageTable, callers should pass a lambda
|
||||
* to CSSVariableImageTable::ReplaceAll() that calls
|
||||
* CSSVariableImageTable::Add() for each ImageValue that needs to be added to
|
||||
* the table. When callers are sure that the ImageValues for a given
|
||||
* nsStyleContext won't be needed anymore, they can call
|
||||
* CSSVariableImageTable::RemoveAll() to release them.
|
||||
*/
|
||||
|
||||
namespace mozilla {
|
||||
namespace CSSVariableImageTable {
|
||||
|
||||
namespace detail {
|
||||
|
||||
typedef nsTArray<RefPtr<css::ImageValue>> ImageValueArray;
|
||||
typedef nsClassHashtable<nsGenericHashKey<nsCSSPropertyID>, ImageValueArray>
|
||||
PerPropertyImageHashtable;
|
||||
typedef nsClassHashtable<nsPtrHashKey<nsStyleContext>, PerPropertyImageHashtable>
|
||||
CSSVariableImageHashtable;
|
||||
|
||||
inline CSSVariableImageHashtable& GetTable()
|
||||
{
|
||||
static CSSVariableImageHashtable imageTable;
|
||||
return imageTable;
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
inline bool& IsReplacing()
|
||||
{
|
||||
static bool isReplacing = false;
|
||||
return isReplacing;
|
||||
}
|
||||
#endif
|
||||
|
||||
} // namespace detail
|
||||
|
||||
/**
|
||||
* ReplaceAll() allows callers to replace the ImageValues associated with a
|
||||
* (nsStyleContext, nsCSSPropertyID) pair. The memory used by the previous list of
|
||||
* ImageValues is automatically released.
|
||||
*
|
||||
* @param aContext The style context the ImageValues are associated with.
|
||||
* @param aProp The CSS property the ImageValues are associated with.
|
||||
* @param aFunc A lambda that calls CSSVariableImageTable::Add() to add new
|
||||
* ImageValues which will replace the old ones.
|
||||
*/
|
||||
template <typename Lambda>
|
||||
inline void ReplaceAll(nsStyleContext* aContext,
|
||||
nsCSSPropertyID aProp,
|
||||
Lambda aFunc)
|
||||
{
|
||||
MOZ_ASSERT(aContext);
|
||||
|
||||
auto& imageTable = detail::GetTable();
|
||||
|
||||
// Clear the existing image array, if any, for this property.
|
||||
{
|
||||
auto* perPropertyImageTable = imageTable.Get(aContext);
|
||||
auto* imageList = perPropertyImageTable ? perPropertyImageTable->Get(aProp)
|
||||
: nullptr;
|
||||
if (imageList) {
|
||||
imageList->ClearAndRetainStorage();
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
MOZ_ASSERT(!detail::IsReplacing());
|
||||
detail::IsReplacing() = true;
|
||||
#endif
|
||||
|
||||
aFunc();
|
||||
|
||||
#ifdef DEBUG
|
||||
detail::IsReplacing() = false;
|
||||
#endif
|
||||
|
||||
// Clean up.
|
||||
auto* perPropertyImageTable = imageTable.Get(aContext);
|
||||
auto* imageList = perPropertyImageTable ? perPropertyImageTable->Get(aProp)
|
||||
: nullptr;
|
||||
if (imageList) {
|
||||
if (imageList->IsEmpty()) {
|
||||
// We used to have an image array for this property, but now we don't.
|
||||
// Remove the entry in the per-property image table for this property.
|
||||
// That may then allow us to remove the entire per-property image table.
|
||||
perPropertyImageTable->Remove(aProp);
|
||||
if (perPropertyImageTable->Count() == 0) {
|
||||
imageTable.Remove(aContext);
|
||||
}
|
||||
} else {
|
||||
// We still have a non-empty image array for this property. Compact the
|
||||
// storage it's using if possible.
|
||||
imageList->Compact();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a new ImageValue @aValue to the CSSVariableImageTable, which will be
|
||||
* associated with @aContext and @aProp.
|
||||
*
|
||||
* It's illegal to call this function outside of a lambda passed to
|
||||
* CSSVariableImageTable::ReplaceAll().
|
||||
*/
|
||||
inline void
|
||||
Add(nsStyleContext* aContext, nsCSSPropertyID aProp, css::ImageValue* aValue)
|
||||
{
|
||||
MOZ_ASSERT(aValue);
|
||||
MOZ_ASSERT(aContext);
|
||||
MOZ_ASSERT(detail::IsReplacing());
|
||||
|
||||
auto& imageTable = detail::GetTable();
|
||||
|
||||
// Ensure there's a per-property image table for this style context.
|
||||
auto* perPropertyImageTable = imageTable.Get(aContext);
|
||||
if (!perPropertyImageTable) {
|
||||
perPropertyImageTable = new detail::PerPropertyImageHashtable();
|
||||
imageTable.Put(aContext, perPropertyImageTable);
|
||||
}
|
||||
|
||||
// Ensure there's an image array for this property.
|
||||
auto* imageList = perPropertyImageTable->Get(aProp);
|
||||
if (!imageList) {
|
||||
imageList = new detail::ImageValueArray();
|
||||
perPropertyImageTable->Put(aProp, imageList);
|
||||
}
|
||||
|
||||
// Append the provided ImageValue to the list.
|
||||
imageList->AppendElement(aValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes all ImageValues stored in the CSSVariableImageTable for the provided
|
||||
* @aContext.
|
||||
*/
|
||||
inline void
|
||||
RemoveAll(nsStyleContext* aContext)
|
||||
{
|
||||
// Move all ImageValue references into removedImageList so that we can
|
||||
// release them outside of any hashtable methods. (If we just call
|
||||
// Remove(aContext) on the table then we can end up calling back
|
||||
// re-entrantly into hashtable methods, as other style contexts
|
||||
// are released.)
|
||||
detail::ImageValueArray removedImages;
|
||||
auto& imageTable = detail::GetTable();
|
||||
auto* perPropertyImageTable = imageTable.Get(aContext);
|
||||
if (perPropertyImageTable) {
|
||||
for (auto it = perPropertyImageTable->Iter(); !it.Done(); it.Next()) {
|
||||
auto* imageList = it.UserData();
|
||||
removedImages.AppendElements(Move(*imageList));
|
||||
}
|
||||
}
|
||||
imageTable.Remove(aContext);
|
||||
}
|
||||
|
||||
} // namespace CSSVariableImageTable
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // mozilla_CSSVariableImageTable_h
|
||||
266
layout/style/CSSVariableResolver.cpp
Normal file
266
layout/style/CSSVariableResolver.cpp
Normal file
|
|
@ -0,0 +1,266 @@
|
|||
/* vim: set shiftwidth=2 tabstop=8 autoindent cindent expandtab: */
|
||||
/* 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/. */
|
||||
|
||||
/* object that resolves CSS variables using specified and inherited variable
|
||||
* values
|
||||
*/
|
||||
|
||||
#include "CSSVariableResolver.h"
|
||||
|
||||
#include "CSSVariableDeclarations.h"
|
||||
#include "CSSVariableValues.h"
|
||||
#include "mozilla/PodOperations.h"
|
||||
#include "mozilla/UniquePtr.h"
|
||||
#include <algorithm>
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
/**
|
||||
* Data used by the EnumerateVariableReferences callback. Reset must be called
|
||||
* on it before it is used.
|
||||
*/
|
||||
class EnumerateVariableReferencesData
|
||||
{
|
||||
public:
|
||||
explicit EnumerateVariableReferencesData(CSSVariableResolver& aResolver)
|
||||
: mResolver(aResolver)
|
||||
, mReferences(MakeUnique<bool[]>(aResolver.mVariables.Length()))
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets the data so that it can be passed to another call of
|
||||
* EnumerateVariableReferences for a different variable.
|
||||
*/
|
||||
void Reset()
|
||||
{
|
||||
PodZero(mReferences.get(), mResolver.mVariables.Length());
|
||||
mReferencesNonExistentVariable = false;
|
||||
}
|
||||
|
||||
void RecordVariableReference(const nsAString& aVariableName)
|
||||
{
|
||||
size_t id;
|
||||
if (mResolver.mVariableIDs.Get(aVariableName, &id)) {
|
||||
mReferences[id] = true;
|
||||
} else {
|
||||
mReferencesNonExistentVariable = true;
|
||||
}
|
||||
}
|
||||
|
||||
bool HasReferenceToVariable(size_t aID) const
|
||||
{
|
||||
return mReferences[aID];
|
||||
}
|
||||
|
||||
bool ReferencesNonExistentVariable() const
|
||||
{
|
||||
return mReferencesNonExistentVariable;
|
||||
}
|
||||
|
||||
private:
|
||||
CSSVariableResolver& mResolver;
|
||||
|
||||
// Array of booleans, where each index is a variable ID. If an element is
|
||||
// true, it indicates that the variable we have called
|
||||
// EnumerateVariableReferences for has a reference to the variable with
|
||||
// that ID.
|
||||
const UniquePtr<bool[]> mReferences;
|
||||
|
||||
// Whether the variable we have called EnumerateVariableReferences for
|
||||
// references a variable that does not exist in the resolver.
|
||||
bool mReferencesNonExistentVariable;
|
||||
};
|
||||
|
||||
static void
|
||||
RecordVariableReference(const nsAString& aVariableName,
|
||||
void* aData)
|
||||
{
|
||||
static_cast<EnumerateVariableReferencesData*>(aData)->
|
||||
RecordVariableReference(aVariableName);
|
||||
}
|
||||
|
||||
void
|
||||
CSSVariableResolver::RemoveCycles(size_t v)
|
||||
{
|
||||
mVariables[v].mIndex = mNextIndex;
|
||||
mVariables[v].mLowLink = mNextIndex;
|
||||
mVariables[v].mInStack = true;
|
||||
mStack.AppendElement(v);
|
||||
mNextIndex++;
|
||||
|
||||
for (size_t i = 0, n = mReferences[v].Length(); i < n; i++) {
|
||||
size_t w = mReferences[v][i];
|
||||
if (!mVariables[w].mIndex) {
|
||||
RemoveCycles(w);
|
||||
mVariables[v].mLowLink = std::min(mVariables[v].mLowLink,
|
||||
mVariables[w].mLowLink);
|
||||
} else if (mVariables[w].mInStack) {
|
||||
mVariables[v].mLowLink = std::min(mVariables[v].mLowLink,
|
||||
mVariables[w].mIndex);
|
||||
}
|
||||
}
|
||||
|
||||
if (mVariables[v].mLowLink == mVariables[v].mIndex) {
|
||||
if (mStack.LastElement() == v) {
|
||||
// A strongly connected component consisting of a single variable is not
|
||||
// necessarily invalid. We handle variables that reference themselves
|
||||
// earlier, in CSSVariableResolver::Resolve.
|
||||
mVariables[mStack.LastElement()].mInStack = false;
|
||||
mStack.TruncateLength(mStack.Length() - 1);
|
||||
} else {
|
||||
size_t w;
|
||||
do {
|
||||
w = mStack.LastElement();
|
||||
mVariables[w].mValue.Truncate(0);
|
||||
mVariables[w].mInStack = false;
|
||||
mStack.TruncateLength(mStack.Length() - 1);
|
||||
} while (w != v);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
CSSVariableResolver::ResolveVariable(size_t aID)
|
||||
{
|
||||
if (mVariables[aID].mValue.IsEmpty() || mVariables[aID].mWasInherited) {
|
||||
// The variable is invalid or was inherited. We can just copy the value
|
||||
// and its first/last token information across.
|
||||
mOutput->Put(mVariables[aID].mVariableName,
|
||||
mVariables[aID].mValue,
|
||||
mVariables[aID].mFirstToken,
|
||||
mVariables[aID].mLastToken);
|
||||
} else {
|
||||
// Otherwise we need to resolve the variable references, after resolving
|
||||
// all of our dependencies first. We do this even for variables that we
|
||||
// know do not reference other variables so that we can find their
|
||||
// first/last token.
|
||||
//
|
||||
// XXX We might want to do this first/last token finding during
|
||||
// EnumerateVariableReferences, so that we can avoid calling
|
||||
// ResolveVariableValue and parsing the value again.
|
||||
for (size_t i = 0, n = mReferences[aID].Length(); i < n; i++) {
|
||||
size_t j = mReferences[aID][i];
|
||||
if (aID != j && !mVariables[j].mResolved) {
|
||||
ResolveVariable(j);
|
||||
}
|
||||
}
|
||||
nsString resolvedValue;
|
||||
nsCSSTokenSerializationType firstToken, lastToken;
|
||||
if (!mParser.ResolveVariableValue(mVariables[aID].mValue, mOutput,
|
||||
resolvedValue, firstToken, lastToken)) {
|
||||
resolvedValue.Truncate(0);
|
||||
}
|
||||
mOutput->Put(mVariables[aID].mVariableName, resolvedValue,
|
||||
firstToken, lastToken);
|
||||
}
|
||||
mVariables[aID].mResolved = true;
|
||||
}
|
||||
|
||||
void
|
||||
CSSVariableResolver::Resolve(const CSSVariableValues* aInherited,
|
||||
const CSSVariableDeclarations* aSpecified)
|
||||
{
|
||||
MOZ_ASSERT(!mResolved);
|
||||
|
||||
// The only time we would be worried about having a null aInherited is
|
||||
// for the root, but in that case nsRuleNode::ComputeVariablesData will
|
||||
// happen to pass in whatever we're using as mOutput for aInherited,
|
||||
// which will initially be empty.
|
||||
MOZ_ASSERT(aInherited);
|
||||
MOZ_ASSERT(aSpecified);
|
||||
|
||||
aInherited->AddVariablesToResolver(this);
|
||||
aSpecified->AddVariablesToResolver(this);
|
||||
|
||||
// First we look at each variable's value and record which other variables
|
||||
// it references.
|
||||
size_t n = mVariables.Length();
|
||||
mReferences.SetLength(n);
|
||||
EnumerateVariableReferencesData data(*this);
|
||||
for (size_t id = 0; id < n; id++) {
|
||||
data.Reset();
|
||||
if (!mVariables[id].mWasInherited &&
|
||||
!mVariables[id].mValue.IsEmpty()) {
|
||||
if (mParser.EnumerateVariableReferences(mVariables[id].mValue,
|
||||
RecordVariableReference,
|
||||
&data)) {
|
||||
// Convert the boolean array of dependencies in |data| to a list
|
||||
// of dependencies.
|
||||
for (size_t i = 0; i < n; i++) {
|
||||
if (data.HasReferenceToVariable(i)) {
|
||||
mReferences[id].AppendElement(i);
|
||||
}
|
||||
}
|
||||
// If a variable references itself, it is invalid. (RemoveCycles
|
||||
// does not check for cycles consisting of a single variable, so we
|
||||
// check here.)
|
||||
if (data.HasReferenceToVariable(id)) {
|
||||
mVariables[id].mValue.Truncate();
|
||||
}
|
||||
// Also record whether it referenced any variables that don't exist
|
||||
// in the resolver, so that we can ensure we still resolve its value
|
||||
// in ResolveVariable, even though its mReferences list is empty.
|
||||
mVariables[id].mReferencesNonExistentVariable =
|
||||
data.ReferencesNonExistentVariable();
|
||||
} else {
|
||||
MOZ_ASSERT(false, "EnumerateVariableReferences should not have failed "
|
||||
"if we previously parsed the specified value");
|
||||
mVariables[id].mValue.Truncate(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Next we remove any cycles in variable references using Tarjan's strongly
|
||||
// connected components finding algorithm, setting variables in cycles to
|
||||
// have an invalid value.
|
||||
mNextIndex = 1;
|
||||
for (size_t id = 0; id < n; id++) {
|
||||
if (!mVariables[id].mIndex) {
|
||||
RemoveCycles(id);
|
||||
MOZ_ASSERT(mStack.IsEmpty());
|
||||
}
|
||||
}
|
||||
|
||||
// Finally we construct the computed value for the variable by substituting
|
||||
// any variable references.
|
||||
for (size_t id = 0; id < n; id++) {
|
||||
if (!mVariables[id].mResolved) {
|
||||
ResolveVariable(id);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
mResolved = true;
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
CSSVariableResolver::Put(const nsAString& aVariableName,
|
||||
nsString aValue,
|
||||
nsCSSTokenSerializationType aFirstToken,
|
||||
nsCSSTokenSerializationType aLastToken,
|
||||
bool aWasInherited)
|
||||
{
|
||||
MOZ_ASSERT(!mResolved);
|
||||
|
||||
size_t id;
|
||||
if (mVariableIDs.Get(aVariableName, &id)) {
|
||||
MOZ_ASSERT(mVariables[id].mWasInherited && !aWasInherited,
|
||||
"should only overwrite inherited variables with specified "
|
||||
"variables");
|
||||
mVariables[id].mValue = aValue;
|
||||
mVariables[id].mFirstToken = aFirstToken;
|
||||
mVariables[id].mLastToken = aLastToken;
|
||||
mVariables[id].mWasInherited = aWasInherited;
|
||||
} else {
|
||||
id = mVariables.Length();
|
||||
mVariableIDs.Put(aVariableName, id);
|
||||
mVariables.AppendElement(Variable(aVariableName, aValue,
|
||||
aFirstToken, aLastToken, aWasInherited));
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace mozilla
|
||||
148
layout/style/CSSVariableResolver.h
Normal file
148
layout/style/CSSVariableResolver.h
Normal file
|
|
@ -0,0 +1,148 @@
|
|||
/* vim: set shiftwidth=2 tabstop=8 autoindent cindent expandtab: */
|
||||
/* 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/. */
|
||||
|
||||
/* object that resolves CSS variables using specified and inherited variable
|
||||
* values
|
||||
*/
|
||||
|
||||
#ifndef mozilla_CSSVariableResolver_h
|
||||
#define mozilla_CSSVariableResolver_h
|
||||
|
||||
#include "mozilla/DebugOnly.h"
|
||||
#include "nsCSSParser.h"
|
||||
#include "nsCSSScanner.h"
|
||||
#include "nsDataHashtable.h"
|
||||
#include "nsTArray.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
class CSSVariableDeclarations;
|
||||
class CSSVariableValues;
|
||||
class EnumerateVariableReferencesData;
|
||||
|
||||
class CSSVariableResolver
|
||||
{
|
||||
friend class CSSVariableDeclarations;
|
||||
friend class CSSVariableValues;
|
||||
friend class EnumerateVariableReferencesData;
|
||||
public:
|
||||
/**
|
||||
* Creates a new CSSVariableResolver that will output a set of resolved,
|
||||
* computed variables into aOutput.
|
||||
*/
|
||||
explicit CSSVariableResolver(CSSVariableValues* aOutput)
|
||||
: mOutput(aOutput)
|
||||
#ifdef DEBUG
|
||||
, mResolved(false)
|
||||
#endif
|
||||
{
|
||||
MOZ_ASSERT(aOutput);
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolves the set of inherited variables from aInherited and the
|
||||
* set of specified variables from aSpecified. The resolved variables
|
||||
* are written into mOutput.
|
||||
*/
|
||||
void Resolve(const CSSVariableValues* aInherited,
|
||||
const CSSVariableDeclarations* aSpecified);
|
||||
|
||||
private:
|
||||
struct Variable
|
||||
{
|
||||
Variable(const nsAString& aVariableName,
|
||||
nsString aValue,
|
||||
nsCSSTokenSerializationType aFirstToken,
|
||||
nsCSSTokenSerializationType aLastToken,
|
||||
bool aWasInherited)
|
||||
: mVariableName(aVariableName)
|
||||
, mValue(aValue)
|
||||
, mFirstToken(aFirstToken)
|
||||
, mLastToken(aLastToken)
|
||||
, mWasInherited(aWasInherited)
|
||||
, mResolved(false)
|
||||
, mReferencesNonExistentVariable(false)
|
||||
, mInStack(false)
|
||||
, mIndex(0)
|
||||
, mLowLink(0) { }
|
||||
|
||||
nsString mVariableName;
|
||||
nsString mValue;
|
||||
nsCSSTokenSerializationType mFirstToken;
|
||||
nsCSSTokenSerializationType mLastToken;
|
||||
|
||||
// Whether this variable came from the set of inherited variables.
|
||||
bool mWasInherited;
|
||||
|
||||
// Whether this variable has been resolved yet.
|
||||
bool mResolved;
|
||||
|
||||
// Whether this variables includes any references to non-existent variables.
|
||||
bool mReferencesNonExistentVariable;
|
||||
|
||||
// Bookkeeping for the cycle remover algorithm.
|
||||
bool mInStack;
|
||||
size_t mIndex;
|
||||
size_t mLowLink;
|
||||
};
|
||||
|
||||
/**
|
||||
* Adds or modifies an existing entry in the set of variables to be resolved.
|
||||
* This is intended to be called by the AddVariablesToResolver functions on
|
||||
* the CSSVariableDeclarations and CSSVariableValues objects passed in to
|
||||
* Resolve.
|
||||
*
|
||||
* @param aName The variable name (not including any "--" prefix that would
|
||||
* be part of the custom property name) whose value is to be set.
|
||||
* @param aValue The variable value.
|
||||
* @param aFirstToken The type of token at the start of the variable value.
|
||||
* @param aLastToken The type of token at the en of the variable value.
|
||||
* @param aWasInherited Whether this variable came from the set of inherited
|
||||
* variables.
|
||||
*/
|
||||
void Put(const nsAString& aVariableName,
|
||||
nsString aValue,
|
||||
nsCSSTokenSerializationType aFirstToken,
|
||||
nsCSSTokenSerializationType aLastToken,
|
||||
bool aWasInherited);
|
||||
|
||||
// Helper functions for Resolve.
|
||||
void RemoveCycles(size_t aID);
|
||||
void ResolveVariable(size_t aID);
|
||||
|
||||
// A mapping of variable names to an ID that indexes into mVariables
|
||||
// and mReferences.
|
||||
nsDataHashtable<nsStringHashKey, size_t> mVariableIDs;
|
||||
|
||||
// The set of variables.
|
||||
nsTArray<Variable> mVariables;
|
||||
|
||||
// The list of variables that each variable references.
|
||||
nsTArray<nsTArray<size_t> > mReferences;
|
||||
|
||||
// The next index to assign to a variable found during the cycle removing
|
||||
// algorithm's traversal of the variable reference graph.
|
||||
size_t mNextIndex;
|
||||
|
||||
// Stack of variable IDs that we push to as we traverse the variable reference
|
||||
// graph while looking for cycles. Variable::mInStack reflects whether a
|
||||
// given variable has its ID in mStack.
|
||||
nsTArray<size_t> mStack;
|
||||
|
||||
// CSS parser to use for parsing property values with variable references.
|
||||
nsCSSParser mParser;
|
||||
|
||||
// The object to output the resolved variables into.
|
||||
CSSVariableValues* mOutput;
|
||||
|
||||
#ifdef DEBUG
|
||||
// Whether Resolve has been called.
|
||||
bool mResolved;
|
||||
#endif
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
|
||||
#endif
|
||||
147
layout/style/CSSVariableValues.cpp
Normal file
147
layout/style/CSSVariableValues.cpp
Normal file
|
|
@ -0,0 +1,147 @@
|
|||
/* -*- Mode: C++; 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/. */
|
||||
|
||||
/* computed CSS Variable values */
|
||||
|
||||
#include "CSSVariableValues.h"
|
||||
|
||||
#include "CSSVariableResolver.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
CSSVariableValues::CSSVariableValues()
|
||||
{
|
||||
MOZ_COUNT_CTOR(CSSVariableValues);
|
||||
}
|
||||
|
||||
CSSVariableValues::CSSVariableValues(const CSSVariableValues& aOther)
|
||||
{
|
||||
MOZ_COUNT_CTOR(CSSVariableValues);
|
||||
CopyVariablesFrom(aOther);
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
CSSVariableValues::~CSSVariableValues()
|
||||
{
|
||||
MOZ_COUNT_DTOR(CSSVariableValues);
|
||||
}
|
||||
#endif
|
||||
|
||||
CSSVariableValues&
|
||||
CSSVariableValues::operator=(const CSSVariableValues& aOther)
|
||||
{
|
||||
if (this == &aOther) {
|
||||
return *this;
|
||||
}
|
||||
|
||||
mVariableIDs.Clear();
|
||||
mVariables.Clear();
|
||||
CopyVariablesFrom(aOther);
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool
|
||||
CSSVariableValues::operator==(const CSSVariableValues& aOther) const
|
||||
{
|
||||
if (mVariables.Length() != aOther.mVariables.Length()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (size_t thisIndex = 0; thisIndex < mVariables.Length(); ++thisIndex) {
|
||||
size_t otherIndex;
|
||||
if (!aOther.mVariableIDs.Get(mVariables[thisIndex].mVariableName,
|
||||
&otherIndex)) {
|
||||
return false;
|
||||
}
|
||||
const nsString& otherValue = aOther.mVariables[otherIndex].mValue;
|
||||
if (!mVariables[thisIndex].mValue.Equals(otherValue)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
size_t
|
||||
CSSVariableValues::Count() const
|
||||
{
|
||||
return mVariables.Length();
|
||||
}
|
||||
|
||||
bool
|
||||
CSSVariableValues::Get(const nsAString& aName, nsString& aValue) const
|
||||
{
|
||||
size_t id;
|
||||
if (!mVariableIDs.Get(aName, &id)) {
|
||||
return false;
|
||||
}
|
||||
aValue = mVariables[id].mValue;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
CSSVariableValues::Get(const nsAString& aName,
|
||||
nsString& aValue,
|
||||
nsCSSTokenSerializationType& aFirstToken,
|
||||
nsCSSTokenSerializationType& aLastToken) const
|
||||
{
|
||||
size_t id;
|
||||
if (!mVariableIDs.Get(aName, &id)) {
|
||||
return false;
|
||||
}
|
||||
aValue = mVariables[id].mValue;
|
||||
aFirstToken = mVariables[id].mFirstToken;
|
||||
aLastToken = mVariables[id].mLastToken;
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
CSSVariableValues::GetVariableAt(size_t aIndex, nsAString& aName) const
|
||||
{
|
||||
aName = mVariables[aIndex].mVariableName;
|
||||
}
|
||||
|
||||
void
|
||||
CSSVariableValues::Put(const nsAString& aName,
|
||||
nsString aValue,
|
||||
nsCSSTokenSerializationType aFirstToken,
|
||||
nsCSSTokenSerializationType aLastToken)
|
||||
{
|
||||
size_t id;
|
||||
if (mVariableIDs.Get(aName, &id)) {
|
||||
mVariables[id].mValue = aValue;
|
||||
mVariables[id].mFirstToken = aFirstToken;
|
||||
mVariables[id].mLastToken = aLastToken;
|
||||
} else {
|
||||
id = mVariables.Length();
|
||||
mVariableIDs.Put(aName, id);
|
||||
mVariables.AppendElement(Variable(aName, aValue, aFirstToken, aLastToken));
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
CSSVariableValues::CopyVariablesFrom(const CSSVariableValues& aOther)
|
||||
{
|
||||
for (size_t i = 0, n = aOther.mVariables.Length(); i < n; i++) {
|
||||
Put(aOther.mVariables[i].mVariableName,
|
||||
aOther.mVariables[i].mValue,
|
||||
aOther.mVariables[i].mFirstToken,
|
||||
aOther.mVariables[i].mLastToken);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
CSSVariableValues::AddVariablesToResolver(CSSVariableResolver* aResolver) const
|
||||
{
|
||||
for (size_t i = 0, n = mVariables.Length(); i < n; i++) {
|
||||
aResolver->Put(mVariables[i].mVariableName,
|
||||
mVariables[i].mValue,
|
||||
mVariables[i].mFirstToken,
|
||||
mVariables[i].mLastToken,
|
||||
true);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace mozilla
|
||||
147
layout/style/CSSVariableValues.h
Normal file
147
layout/style/CSSVariableValues.h
Normal file
|
|
@ -0,0 +1,147 @@
|
|||
/* vim: set shiftwidth=2 tabstop=8 autoindent cindent expandtab: */
|
||||
/* 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/. */
|
||||
|
||||
/* computed CSS Variable values */
|
||||
|
||||
#ifndef mozilla_CSSVariableValues_h
|
||||
#define mozilla_CSSVariableValues_h
|
||||
|
||||
#include "nsCSSScanner.h"
|
||||
#include "nsDataHashtable.h"
|
||||
#include "nsTArray.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
class CSSVariableResolver;
|
||||
|
||||
class CSSVariableValues
|
||||
{
|
||||
public:
|
||||
CSSVariableValues();
|
||||
CSSVariableValues(const CSSVariableValues& aOther);
|
||||
#ifdef DEBUG
|
||||
~CSSVariableValues();
|
||||
#endif
|
||||
CSSVariableValues& operator=(const CSSVariableValues& aOther);
|
||||
|
||||
bool operator==(const CSSVariableValues& aOther) const;
|
||||
bool operator!=(const CSSVariableValues& aOther) const
|
||||
{ return !(*this == aOther); }
|
||||
|
||||
/**
|
||||
* Gets the value of a variable in this set of computed variables.
|
||||
*
|
||||
* @param aName The variable name (not including any "--" prefix that would
|
||||
* be part of the custom property name).
|
||||
* @param aValue Out parameter into which the value of the variable will
|
||||
* be stored.
|
||||
* @return Whether a variable with the given name was found. When false
|
||||
* is returned, aValue will not be modified.
|
||||
*/
|
||||
bool Get(const nsAString& aName, nsString& aValue) const;
|
||||
|
||||
/**
|
||||
* Gets the value of a variable in this set of computed variables, along
|
||||
* with information on the types of tokens that appear at the start and
|
||||
* end of the token stream.
|
||||
*
|
||||
* @param aName The variable name (not including any "--" prefix that would
|
||||
* be part of the custom property name).
|
||||
* @param aValue Out parameter into which the value of the variable will
|
||||
* be stored.
|
||||
* @param aFirstToken The type of token at the start of the variable value.
|
||||
* @param aLastToken The type of token at the en of the variable value.
|
||||
* @return Whether a variable with the given name was found. When false
|
||||
* is returned, aValue, aFirstToken and aLastToken will not be modified.
|
||||
*/
|
||||
bool Get(const nsAString& aName,
|
||||
nsString& aValue,
|
||||
nsCSSTokenSerializationType& aFirstToken,
|
||||
nsCSSTokenSerializationType& aLastToken) const;
|
||||
|
||||
/**
|
||||
* Gets the name of the variable at the given index.
|
||||
*
|
||||
* Variables on this object are ordered, and that order is just determined
|
||||
* based on the order that they are added to the object. A consistent
|
||||
* ordering is required for CSSDeclaration objects in the DOM.
|
||||
* CSSDeclarations expose property names as indexed properties, which need to
|
||||
* be stable.
|
||||
*
|
||||
* @param aIndex The index of the variable to get.
|
||||
* @param aName Out parameter into which the name of the variable will be
|
||||
* stored.
|
||||
*/
|
||||
void GetVariableAt(size_t aIndex, nsAString& aName) const;
|
||||
|
||||
/**
|
||||
* Gets the number of variables stored on this object.
|
||||
*/
|
||||
size_t Count() const;
|
||||
|
||||
/**
|
||||
* Adds or modifies an existing entry in this set of variable values.
|
||||
*
|
||||
* @param aName The variable name (not including any "--" prefix that would
|
||||
* be part of the custom property name) whose value is to be set.
|
||||
* @param aValue The variable value.
|
||||
* @param aFirstToken The type of token at the start of the variable value.
|
||||
* @param aLastToken The type of token at the en of the variable value.
|
||||
*/
|
||||
void Put(const nsAString& aName,
|
||||
nsString aValue,
|
||||
nsCSSTokenSerializationType aFirstToken,
|
||||
nsCSSTokenSerializationType aLastToken);
|
||||
|
||||
/**
|
||||
* Copies the variables from this object into aResolver, marking them as
|
||||
* computed, inherited values.
|
||||
*/
|
||||
void AddVariablesToResolver(CSSVariableResolver* aResolver) const;
|
||||
|
||||
private:
|
||||
struct Variable
|
||||
{
|
||||
Variable()
|
||||
: mFirstToken(eCSSTokenSerialization_Nothing)
|
||||
, mLastToken(eCSSTokenSerialization_Nothing)
|
||||
{}
|
||||
|
||||
Variable(const nsAString& aVariableName,
|
||||
nsString aValue,
|
||||
nsCSSTokenSerializationType aFirstToken,
|
||||
nsCSSTokenSerializationType aLastToken)
|
||||
: mVariableName(aVariableName)
|
||||
, mValue(aValue)
|
||||
, mFirstToken(aFirstToken)
|
||||
, mLastToken(aLastToken)
|
||||
{}
|
||||
|
||||
nsString mVariableName;
|
||||
nsString mValue;
|
||||
nsCSSTokenSerializationType mFirstToken;
|
||||
nsCSSTokenSerializationType mLastToken;
|
||||
};
|
||||
|
||||
/**
|
||||
* Adds all the variables from aOther into this object.
|
||||
*/
|
||||
void CopyVariablesFrom(const CSSVariableValues& aOther);
|
||||
|
||||
/**
|
||||
* Map of variable names to IDs. Variable IDs are indexes into
|
||||
* mVariables.
|
||||
*/
|
||||
nsDataHashtable<nsStringHashKey, size_t> mVariableIDs;
|
||||
|
||||
/**
|
||||
* Array of variables, indexed by variable ID.
|
||||
*/
|
||||
nsTArray<Variable> mVariables;
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
|
||||
#endif
|
||||
2135
layout/style/CounterStyleManager.cpp
Normal file
2135
layout/style/CounterStyleManager.cpp
Normal file
File diff suppressed because it is too large
Load diff
192
layout/style/CounterStyleManager.h
Normal file
192
layout/style/CounterStyleManager.h
Normal file
|
|
@ -0,0 +1,192 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* 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_CounterStyleManager_h_
|
||||
#define mozilla_CounterStyleManager_h_
|
||||
|
||||
#include "nsStringFwd.h"
|
||||
#include "nsRefPtrHashtable.h"
|
||||
#include "nsHashKeys.h"
|
||||
|
||||
#include "nsStyleConsts.h"
|
||||
|
||||
#include "mozilla/Attributes.h"
|
||||
|
||||
#include "nsCSSValue.h"
|
||||
|
||||
class nsPresContext;
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
class WritingMode;
|
||||
|
||||
typedef int32_t CounterValue;
|
||||
|
||||
class CounterStyleManager;
|
||||
class AnonymousCounterStyle;
|
||||
|
||||
struct NegativeType;
|
||||
struct PadType;
|
||||
|
||||
class CounterStyle
|
||||
{
|
||||
protected:
|
||||
explicit constexpr CounterStyle(int32_t aStyle)
|
||||
: mStyle(aStyle)
|
||||
{
|
||||
}
|
||||
|
||||
private:
|
||||
CounterStyle(const CounterStyle& aOther) = delete;
|
||||
void operator=(const CounterStyle& other) = delete;
|
||||
|
||||
public:
|
||||
int32_t GetStyle() const { return mStyle; }
|
||||
bool IsNone() const { return mStyle == NS_STYLE_LIST_STYLE_NONE; }
|
||||
bool IsCustomStyle() const { return mStyle == NS_STYLE_LIST_STYLE_CUSTOM; }
|
||||
// A style is dependent if it depends on the counter style manager.
|
||||
// Custom styles are certainly dependent. In addition, some builtin
|
||||
// styles are dependent for fallback.
|
||||
bool IsDependentStyle() const;
|
||||
|
||||
virtual void GetStyleName(nsSubstring& aResult) = 0;
|
||||
virtual void GetPrefix(nsSubstring& aResult) = 0;
|
||||
virtual void GetSuffix(nsSubstring& aResult) = 0;
|
||||
void GetCounterText(CounterValue aOrdinal,
|
||||
WritingMode aWritingMode,
|
||||
nsSubstring& aResult,
|
||||
bool& aIsRTL);
|
||||
virtual void GetSpokenCounterText(CounterValue aOrdinal,
|
||||
WritingMode aWritingMode,
|
||||
nsSubstring& aResult,
|
||||
bool& aIsBullet);
|
||||
|
||||
// XXX This method could be removed once ::-moz-list-bullet and
|
||||
// ::-moz-list-number are completely merged into ::marker.
|
||||
virtual bool IsBullet() = 0;
|
||||
|
||||
virtual void GetNegative(NegativeType& aResult) = 0;
|
||||
/**
|
||||
* This method returns whether an ordinal is in the range of this
|
||||
* counter style. Note that, it is possible that an ordinal in range
|
||||
* is rejected by the generating algorithm.
|
||||
*/
|
||||
virtual bool IsOrdinalInRange(CounterValue aOrdinal) = 0;
|
||||
/**
|
||||
* This method returns whether an ordinal is in the default range of
|
||||
* this counter style. This is the effective range when no 'range'
|
||||
* descriptor is specified.
|
||||
*/
|
||||
virtual bool IsOrdinalInAutoRange(CounterValue aOrdinal) = 0;
|
||||
virtual void GetPad(PadType& aResult) = 0;
|
||||
virtual CounterStyle* GetFallback() = 0;
|
||||
virtual uint8_t GetSpeakAs() = 0;
|
||||
virtual bool UseNegativeSign() = 0;
|
||||
|
||||
virtual void CallFallbackStyle(CounterValue aOrdinal,
|
||||
WritingMode aWritingMode,
|
||||
nsSubstring& aResult,
|
||||
bool& aIsRTL);
|
||||
virtual bool GetInitialCounterText(CounterValue aOrdinal,
|
||||
WritingMode aWritingMode,
|
||||
nsSubstring& aResult,
|
||||
bool& aIsRTL) = 0;
|
||||
|
||||
virtual AnonymousCounterStyle* AsAnonymous() { return nullptr; }
|
||||
|
||||
NS_IMETHOD_(MozExternalRefCountType) AddRef() = 0;
|
||||
NS_IMETHOD_(MozExternalRefCountType) Release() = 0;
|
||||
|
||||
protected:
|
||||
int32_t mStyle;
|
||||
};
|
||||
|
||||
class AnonymousCounterStyle final : public CounterStyle
|
||||
{
|
||||
public:
|
||||
explicit AnonymousCounterStyle(const nsSubstring& aContent);
|
||||
explicit AnonymousCounterStyle(const nsCSSValue::Array* aValue);
|
||||
|
||||
virtual void GetStyleName(nsAString& aResult) override;
|
||||
virtual void GetPrefix(nsAString& aResult) override;
|
||||
virtual void GetSuffix(nsAString& aResult) override;
|
||||
virtual bool IsBullet() override;
|
||||
|
||||
virtual void GetNegative(NegativeType& aResult) override;
|
||||
virtual bool IsOrdinalInRange(CounterValue aOrdinal) override;
|
||||
virtual bool IsOrdinalInAutoRange(CounterValue aOrdinal) override;
|
||||
virtual void GetPad(PadType& aResult) override;
|
||||
virtual CounterStyle* GetFallback() override;
|
||||
virtual uint8_t GetSpeakAs() override;
|
||||
virtual bool UseNegativeSign() override;
|
||||
|
||||
virtual bool GetInitialCounterText(CounterValue aOrdinal,
|
||||
WritingMode aWritingMode,
|
||||
nsSubstring& aResult,
|
||||
bool& aIsRTL) override;
|
||||
|
||||
virtual AnonymousCounterStyle* AsAnonymous() override { return this; }
|
||||
|
||||
bool IsSingleString() const { return mSingleString; }
|
||||
uint8_t GetSystem() const { return mSystem; }
|
||||
const nsTArray<nsString>& GetSymbols() const { return mSymbols; }
|
||||
|
||||
NS_INLINE_DECL_REFCOUNTING(AnonymousCounterStyle, override)
|
||||
|
||||
private:
|
||||
~AnonymousCounterStyle() {}
|
||||
|
||||
bool mSingleString;
|
||||
uint8_t mSystem;
|
||||
nsTArray<nsString> mSymbols;
|
||||
};
|
||||
|
||||
class CounterStyleManager final
|
||||
{
|
||||
private:
|
||||
~CounterStyleManager();
|
||||
public:
|
||||
explicit CounterStyleManager(nsPresContext* aPresContext);
|
||||
|
||||
static void InitializeBuiltinCounterStyles();
|
||||
|
||||
void Disconnect();
|
||||
|
||||
bool IsInitial() const
|
||||
{
|
||||
// only 'none' and 'decimal'
|
||||
return mCacheTable.Count() == 2;
|
||||
}
|
||||
|
||||
CounterStyle* BuildCounterStyle(const nsSubstring& aName);
|
||||
|
||||
static CounterStyle* GetBuiltinStyle(int32_t aStyle);
|
||||
static CounterStyle* GetNoneStyle()
|
||||
{
|
||||
return GetBuiltinStyle(NS_STYLE_LIST_STYLE_NONE);
|
||||
}
|
||||
static CounterStyle* GetDecimalStyle()
|
||||
{
|
||||
return GetBuiltinStyle(NS_STYLE_LIST_STYLE_DECIMAL);
|
||||
}
|
||||
|
||||
// This method will scan all existing counter styles generated by this
|
||||
// manager, and remove or mark data dirty accordingly. It returns true
|
||||
// if any counter style is changed, false elsewise. This method should
|
||||
// be called when any counter style may be affected.
|
||||
bool NotifyRuleChanged();
|
||||
|
||||
nsPresContext* PresContext() const { return mPresContext; }
|
||||
|
||||
NS_INLINE_DECL_REFCOUNTING(CounterStyleManager)
|
||||
|
||||
private:
|
||||
nsPresContext* mPresContext;
|
||||
nsRefPtrHashtable<nsStringHashKey, CounterStyle> mCacheTable;
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
|
||||
#endif /* !defined(mozilla_CounterStyleManager_h_) */
|
||||
1988
layout/style/Declaration.cpp
Normal file
1988
layout/style/Declaration.cpp
Normal file
File diff suppressed because it is too large
Load diff
417
layout/style/Declaration.h
Normal file
417
layout/style/Declaration.h
Normal file
|
|
@ -0,0 +1,417 @@
|
|||
/* -*- Mode: C++; 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/. */
|
||||
|
||||
/*
|
||||
* representation of a declaration block (or style attribute) in a CSS
|
||||
* stylesheet
|
||||
*/
|
||||
|
||||
#ifndef mozilla_css_Declaration_h
|
||||
#define mozilla_css_Declaration_h
|
||||
|
||||
// This header is in EXPORTS because it's used in several places in content/,
|
||||
// but it's not really a public interface.
|
||||
#ifndef MOZILLA_INTERNAL_API
|
||||
#error "This file should only be included within libxul"
|
||||
#endif
|
||||
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "mozilla/DeclarationBlock.h"
|
||||
#include "mozilla/MemoryReporting.h"
|
||||
#include "CSSVariableDeclarations.h"
|
||||
#include "nsCSSDataBlock.h"
|
||||
#include "nsCSSPropertyID.h"
|
||||
#include "nsCSSProps.h"
|
||||
#include "nsIStyleRule.h"
|
||||
#include "nsStringFwd.h"
|
||||
#include "nsTArray.h"
|
||||
#include <stdio.h>
|
||||
|
||||
// feec07b8-3fe6-491e-90d5-cc93f853e048
|
||||
#define NS_CSS_DECLARATION_IMPL_CID \
|
||||
{ 0xfeec07b8, 0x3fe6, 0x491e, \
|
||||
{ 0x90, 0xd5, 0xcc, 0x93, 0xf8, 0x53, 0xe0, 0x48 } }
|
||||
|
||||
class nsHTMLCSSStyleSheet;
|
||||
|
||||
namespace mozilla {
|
||||
namespace css {
|
||||
|
||||
class Rule;
|
||||
class Declaration;
|
||||
|
||||
/**
|
||||
* ImportantStyleData is the implementation of nsIStyleRule (a source of
|
||||
* style data) representing the style data coming from !important rules;
|
||||
* the !important declarations need a separate nsIStyleRule object since
|
||||
* they fit at a different point in the cascade.
|
||||
*
|
||||
* ImportantStyleData is allocated only as part of a Declaration object.
|
||||
*/
|
||||
class ImportantStyleData final : public nsIStyleRule
|
||||
{
|
||||
public:
|
||||
|
||||
NS_DECL_ISUPPORTS
|
||||
|
||||
inline ::mozilla::css::Declaration* Declaration();
|
||||
|
||||
// nsIStyleRule interface
|
||||
virtual void MapRuleInfoInto(nsRuleData* aRuleData) override;
|
||||
virtual bool MightMapInheritedStyleData() override;
|
||||
virtual bool GetDiscretelyAnimatedCSSValue(nsCSSPropertyID aProperty,
|
||||
nsCSSValue* aValue) override;
|
||||
#ifdef DEBUG
|
||||
virtual void List(FILE* out = stdout, int32_t aIndent = 0) const override;
|
||||
#endif
|
||||
|
||||
private:
|
||||
ImportantStyleData() {}
|
||||
~ImportantStyleData() {}
|
||||
|
||||
friend class ::mozilla::css::Declaration;
|
||||
};
|
||||
|
||||
// Declaration objects have unusual lifetime rules. Every declaration
|
||||
// begins life in an invalid state which ends when InitializeEmpty or
|
||||
// CompressFrom is called upon it. After that, it can be attached to
|
||||
// exactly one style rule, and will be destroyed when that style rule
|
||||
// is destroyed. A declaration becomes immutable (via a SetImmutable
|
||||
// call) when it is matched (put in the rule tree); after that, it must
|
||||
// be copied before it can be modified, which is taken care of by
|
||||
// |EnsureMutable|.
|
||||
|
||||
class Declaration final : public DeclarationBlock
|
||||
, public nsIStyleRule
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Construct an |Declaration| that is in an invalid state (null
|
||||
* |mData|) and cannot be used until its |CompressFrom| method or
|
||||
* |InitializeEmpty| method is called.
|
||||
*/
|
||||
Declaration() : DeclarationBlock(StyleBackendType::Gecko) {}
|
||||
|
||||
Declaration(const Declaration& aCopy);
|
||||
|
||||
NS_DECLARE_STATIC_IID_ACCESSOR(NS_CSS_DECLARATION_IMPL_CID)
|
||||
|
||||
NS_DECL_ISUPPORTS
|
||||
|
||||
private:
|
||||
~Declaration();
|
||||
|
||||
public:
|
||||
|
||||
// nsIStyleRule implementation
|
||||
virtual void MapRuleInfoInto(nsRuleData *aRuleData) override;
|
||||
virtual bool MightMapInheritedStyleData() override;
|
||||
virtual bool GetDiscretelyAnimatedCSSValue(nsCSSPropertyID aProperty,
|
||||
nsCSSValue* aValue) override;
|
||||
#ifdef DEBUG
|
||||
virtual void List(FILE* out = stdout, int32_t aIndent = 0) const override;
|
||||
#endif
|
||||
|
||||
/**
|
||||
* |ValueAppended| must be called to maintain this declaration's
|
||||
* |mOrder| whenever a property is parsed into an expanded data block
|
||||
* for this declaration. aProperty must not be a shorthand.
|
||||
*/
|
||||
void ValueAppended(nsCSSPropertyID aProperty);
|
||||
|
||||
void GetPropertyValue(const nsAString& aProperty, nsAString& aValue) const;
|
||||
void GetPropertyValueByID(nsCSSPropertyID aPropID, nsAString& aValue) const;
|
||||
void GetAuthoredPropertyValue(const nsAString& aProperty,
|
||||
nsAString& aValue) const;
|
||||
bool GetPropertyIsImportant(const nsAString& aProperty) const;
|
||||
void RemoveProperty(const nsAString& aProperty);
|
||||
void RemovePropertyByID(nsCSSPropertyID aProperty);
|
||||
|
||||
bool HasProperty(nsCSSPropertyID aProperty) const;
|
||||
|
||||
bool HasImportantData() const {
|
||||
return mImportantData || mImportantVariables;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a custom property declaration to this object.
|
||||
*
|
||||
* @param aName The variable name (i.e., without the "--" prefix).
|
||||
* @param aType The type of value the variable has.
|
||||
* @param aValue The value of the variable, if aType is
|
||||
* CSSVariableDeclarations::eTokenStream.
|
||||
* @param aIsImportant Whether the declaration is !important.
|
||||
* @param aOverrideImportant When aIsImportant is false, whether an
|
||||
* existing !important declaration will be overridden.
|
||||
*/
|
||||
void AddVariable(const nsAString& aName,
|
||||
CSSVariableDeclarations::Type aType,
|
||||
const nsString& aValue,
|
||||
bool aIsImportant,
|
||||
bool aOverrideImportant);
|
||||
|
||||
/**
|
||||
* Removes a custom property declaration from this object.
|
||||
*
|
||||
* @param aName The variable name (i.e., without the "--" prefix).
|
||||
*/
|
||||
void RemoveVariable(const nsAString& aName);
|
||||
|
||||
/**
|
||||
* Gets the string value for a custom property declaration of a variable
|
||||
* with a given name.
|
||||
*
|
||||
* @param aName The variable name (i.e., without the "--" prefix).
|
||||
* @param aValue Out parameter into which the variable's value will be
|
||||
* stored. If the value is 'initial' or 'inherit', that exact string
|
||||
* will be stored in aValue.
|
||||
*/
|
||||
void GetVariableValue(const nsAString& aName, nsAString& aValue) const;
|
||||
|
||||
/**
|
||||
* Returns whether the custom property declaration for a variable with
|
||||
* the given name was !important.
|
||||
*/
|
||||
bool GetVariableIsImportant(const nsAString& aName) const;
|
||||
|
||||
uint32_t Count() const {
|
||||
return mOrder.Length();
|
||||
}
|
||||
|
||||
// Returns whether we actually had a property at aIndex
|
||||
bool GetNthProperty(uint32_t aIndex, nsAString& aReturn) const;
|
||||
|
||||
void ToString(nsAString& aString) const;
|
||||
|
||||
nsCSSCompressedDataBlock* GetNormalBlock() const { return mData; }
|
||||
nsCSSCompressedDataBlock* GetImportantBlock() const { return mImportantData; }
|
||||
|
||||
void AssertNotExpanded() const {
|
||||
MOZ_ASSERT(mData, "should only be called when not expanded");
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize this declaration as holding no data. Cannot fail.
|
||||
*/
|
||||
void InitializeEmpty();
|
||||
|
||||
/**
|
||||
* Transfer all of the state from |aExpandedData| into this declaration.
|
||||
* After calling, |aExpandedData| should be in its initial state.
|
||||
* Callers must make sure mOrder is updated as necessary.
|
||||
*/
|
||||
void CompressFrom(nsCSSExpandedDataBlock *aExpandedData) {
|
||||
MOZ_ASSERT(!mData, "oops");
|
||||
MOZ_ASSERT(!mImportantData, "oops");
|
||||
aExpandedData->Compress(getter_Transfers(mData),
|
||||
getter_Transfers(mImportantData),
|
||||
mOrder);
|
||||
aExpandedData->AssertInitialState();
|
||||
}
|
||||
|
||||
/**
|
||||
* Transfer all of the state from this declaration into
|
||||
* |aExpandedData| and put this declaration temporarily into an
|
||||
* invalid state (ended by |CompressFrom| or |InitializeEmpty|) that
|
||||
* should last only during parsing. During this time only
|
||||
* |ValueAppended| should be called.
|
||||
*/
|
||||
void ExpandTo(nsCSSExpandedDataBlock *aExpandedData) {
|
||||
AssertMutable();
|
||||
aExpandedData->AssertInitialState();
|
||||
|
||||
MOZ_ASSERT(mData, "oops");
|
||||
aExpandedData->Expand(mData.forget(), mImportantData.forget());
|
||||
}
|
||||
|
||||
void MapImportantRuleInfoInto(nsRuleData *aRuleData) const {
|
||||
AssertNotExpanded();
|
||||
MOZ_ASSERT(mImportantData || mImportantVariables,
|
||||
"must have important data or variables");
|
||||
if (mImportantData) {
|
||||
mImportantData->MapRuleInfoInto(aRuleData);
|
||||
}
|
||||
if (mImportantVariables) {
|
||||
mImportantVariables->MapRuleInfoInto(aRuleData);
|
||||
}
|
||||
}
|
||||
|
||||
bool MapsImportantInheritedStyleData() const;
|
||||
|
||||
/**
|
||||
* Attempt to replace the value for |aProperty| stored in this
|
||||
* declaration with the matching value from |aFromBlock|.
|
||||
* This method may only be called on a mutable declaration.
|
||||
* It will fail (returning false) if |aProperty| is shorthand,
|
||||
* is not already in this declaration, or does not have the indicated
|
||||
* importance level. If it returns true, it erases the value in
|
||||
* |aFromBlock|. |aChanged| is set to true if the declaration
|
||||
* changed as a result of the call, and to false otherwise.
|
||||
*/
|
||||
bool TryReplaceValue(nsCSSPropertyID aProperty, bool aIsImportant,
|
||||
nsCSSExpandedDataBlock& aFromBlock,
|
||||
bool* aChanged)
|
||||
{
|
||||
AssertMutable();
|
||||
AssertNotExpanded();
|
||||
|
||||
if (nsCSSProps::IsShorthand(aProperty)) {
|
||||
*aChanged = false;
|
||||
return false;
|
||||
}
|
||||
nsCSSCompressedDataBlock *block = aIsImportant ? mImportantData : mData;
|
||||
// mImportantData might be null
|
||||
if (!block) {
|
||||
*aChanged = false;
|
||||
return false;
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
{
|
||||
nsCSSCompressedDataBlock *other = aIsImportant ? mData : mImportantData;
|
||||
MOZ_ASSERT(!other || !other->ValueFor(aProperty) ||
|
||||
!block->ValueFor(aProperty),
|
||||
"Property both important and not?");
|
||||
}
|
||||
#endif
|
||||
return block->TryReplaceValue(aProperty, aFromBlock, aChanged);
|
||||
}
|
||||
|
||||
bool HasNonImportantValueFor(nsCSSPropertyID aProperty) const {
|
||||
MOZ_ASSERT(!nsCSSProps::IsShorthand(aProperty), "must be longhand");
|
||||
return !!mData->ValueFor(aProperty);
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear the data, in preparation for its replacement with entirely
|
||||
* new data by a call to |CompressFrom|.
|
||||
*/
|
||||
void ClearData() {
|
||||
AssertMutable();
|
||||
mData = nullptr;
|
||||
mImportantData = nullptr;
|
||||
mVariables = nullptr;
|
||||
mImportantVariables = nullptr;
|
||||
mOrder.Clear();
|
||||
mVariableOrder.Clear();
|
||||
}
|
||||
|
||||
ImportantStyleData* GetImportantStyleData() {
|
||||
if (HasImportantData()) {
|
||||
return &mImportantStyleData;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
private:
|
||||
Declaration& operator=(const Declaration& aCopy) = delete;
|
||||
bool operator==(const Declaration& aCopy) const = delete;
|
||||
|
||||
void GetPropertyValueInternal(nsCSSPropertyID aProperty, nsAString& aValue,
|
||||
nsCSSValue::Serialization aValueSerialization)
|
||||
const;
|
||||
bool GetPropertyIsImportantByID(nsCSSPropertyID aProperty) const;
|
||||
|
||||
static void AppendImportanceToString(bool aIsImportant, nsAString& aString);
|
||||
// return whether there was a value in |aValue| (i.e., it had a non-null unit)
|
||||
bool AppendValueToString(nsCSSPropertyID aProperty, nsAString& aResult) const;
|
||||
bool AppendValueToString(nsCSSPropertyID aProperty, nsAString& aResult,
|
||||
nsCSSValue::Serialization aValueSerialization) const;
|
||||
// Helper for ToString with strange semantics regarding aValue.
|
||||
void AppendPropertyAndValueToString(nsCSSPropertyID aProperty,
|
||||
nsAutoString& aValue,
|
||||
nsAString& aResult) const;
|
||||
// helper for ToString that serializes a custom property declaration for
|
||||
// a variable with the specified name
|
||||
void AppendVariableAndValueToString(const nsAString& aName,
|
||||
nsAString& aResult) const;
|
||||
|
||||
void GetImageLayerValue(nsCSSCompressedDataBlock *data,
|
||||
nsAString& aValue,
|
||||
nsCSSValue::Serialization aSerialization,
|
||||
const nsCSSPropertyID aTable[]) const;
|
||||
|
||||
void GetImageLayerPositionValue(nsCSSCompressedDataBlock *data,
|
||||
nsAString& aValue,
|
||||
nsCSSValue::Serialization aSerialization,
|
||||
const nsCSSPropertyID aTable[]) const;
|
||||
|
||||
public:
|
||||
/**
|
||||
* Returns the property at the given index in the ordered list of
|
||||
* declarations. For custom properties, eCSSPropertyExtra_variable
|
||||
* is returned.
|
||||
*/
|
||||
nsCSSPropertyID GetPropertyAt(uint32_t aIndex) const {
|
||||
uint32_t value = mOrder[aIndex];
|
||||
if (value >= eCSSProperty_COUNT) {
|
||||
return eCSSPropertyExtra_variable;
|
||||
}
|
||||
return nsCSSPropertyID(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the name of the custom property at the given index in the ordered
|
||||
* list of declarations.
|
||||
*/
|
||||
void GetCustomPropertyNameAt(uint32_t aIndex, nsAString& aResult) const {
|
||||
MOZ_ASSERT(mOrder[aIndex] >= eCSSProperty_COUNT);
|
||||
uint32_t variableIndex = mOrder[aIndex] - eCSSProperty_COUNT;
|
||||
aResult.Truncate();
|
||||
aResult.AppendLiteral("--");
|
||||
aResult.Append(mVariableOrder[variableIndex]);
|
||||
}
|
||||
|
||||
size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const;
|
||||
|
||||
private:
|
||||
// The order of properties in this declaration. Longhand properties are
|
||||
// represented by their nsCSSPropertyID value, and each custom property (--*)
|
||||
// is represented by a value that begins at eCSSProperty_COUNT.
|
||||
//
|
||||
// Subtracting eCSSProperty_COUNT from those values that represent custom
|
||||
// properties results in an index into mVariableOrder, which identifies the
|
||||
// specific variable the custom property declaration is for.
|
||||
AutoTArray<uint32_t, 8> mOrder;
|
||||
|
||||
// variable names of custom properties found in mOrder
|
||||
nsTArray<nsString> mVariableOrder;
|
||||
|
||||
// never null, except while expanded, or before the first call to
|
||||
// InitializeEmpty or CompressFrom.
|
||||
nsAutoPtr<nsCSSCompressedDataBlock> mData;
|
||||
|
||||
// may be null
|
||||
nsAutoPtr<nsCSSCompressedDataBlock> mImportantData;
|
||||
|
||||
// may be null
|
||||
nsAutoPtr<CSSVariableDeclarations> mVariables;
|
||||
|
||||
// may be null
|
||||
nsAutoPtr<CSSVariableDeclarations> mImportantVariables;
|
||||
|
||||
friend class ImportantStyleData;
|
||||
ImportantStyleData mImportantStyleData;
|
||||
};
|
||||
|
||||
inline ::mozilla::css::Declaration*
|
||||
ImportantStyleData::Declaration()
|
||||
{
|
||||
union {
|
||||
char* ch; /* for pointer arithmetic */
|
||||
::mozilla::css::Declaration* declaration;
|
||||
ImportantStyleData* importantData;
|
||||
} u;
|
||||
u.importantData = this;
|
||||
u.ch -= offsetof(::mozilla::css::Declaration, mImportantStyleData);
|
||||
return u.declaration;
|
||||
}
|
||||
|
||||
NS_DEFINE_STATIC_IID_ACCESSOR(Declaration, NS_CSS_DECLARATION_IMPL_CID)
|
||||
|
||||
} // namespace css
|
||||
} // namespace mozilla
|
||||
|
||||
#endif /* mozilla_css_Declaration_h */
|
||||
146
layout/style/DeclarationBlock.h
Normal file
146
layout/style/DeclarationBlock.h
Normal file
|
|
@ -0,0 +1,146 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* 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/. */
|
||||
|
||||
/*
|
||||
* representation of a declaration block in a CSS stylesheet, or of
|
||||
* a style attribute
|
||||
*/
|
||||
|
||||
#ifndef mozilla_DeclarationBlock_h
|
||||
#define mozilla_DeclarationBlock_h
|
||||
|
||||
#include "mozilla/ServoUtils.h"
|
||||
#include "mozilla/StyleBackendType.h"
|
||||
|
||||
#include "nsCSSPropertyID.h"
|
||||
|
||||
class nsHTMLCSSStyleSheet;
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
class ServoDeclarationBlock;
|
||||
|
||||
namespace css {
|
||||
class Declaration;
|
||||
class Rule;
|
||||
} // namespace css
|
||||
|
||||
class DeclarationBlock
|
||||
{
|
||||
protected:
|
||||
explicit DeclarationBlock(StyleBackendType aType)
|
||||
: mImmutable(false), mType(aType) { mContainer.mRaw = 0; }
|
||||
|
||||
DeclarationBlock(const DeclarationBlock& aCopy)
|
||||
: DeclarationBlock(aCopy.mType) {}
|
||||
|
||||
public:
|
||||
MOZ_DECL_STYLO_METHODS(css::Declaration, ServoDeclarationBlock)
|
||||
|
||||
inline MozExternalRefCountType AddRef();
|
||||
inline MozExternalRefCountType Release();
|
||||
|
||||
inline already_AddRefed<DeclarationBlock> Clone() const;
|
||||
|
||||
/**
|
||||
* Return whether |this| may be modified.
|
||||
*/
|
||||
bool IsMutable() const {
|
||||
return !mImmutable;
|
||||
}
|
||||
|
||||
/**
|
||||
* Crash if |this| cannot be modified.
|
||||
*/
|
||||
void AssertMutable() const {
|
||||
MOZ_ASSERT(IsMutable(), "someone forgot to call EnsureMutable");
|
||||
}
|
||||
|
||||
/**
|
||||
* Mark this declaration as unmodifiable. It's 'const' so it can
|
||||
* be called from ToString.
|
||||
*/
|
||||
void SetImmutable() const { mImmutable = true; }
|
||||
|
||||
/**
|
||||
* Copy |this|, if necessary to ensure that it can be modified.
|
||||
*/
|
||||
inline already_AddRefed<DeclarationBlock> EnsureMutable();
|
||||
|
||||
void SetOwningRule(css::Rule* aRule) {
|
||||
MOZ_ASSERT(!mContainer.mOwningRule || !aRule,
|
||||
"should never overwrite one rule with another");
|
||||
mContainer.mOwningRule = aRule;
|
||||
}
|
||||
|
||||
css::Rule* GetOwningRule() const {
|
||||
if (mContainer.mRaw & 0x1) {
|
||||
return nullptr;
|
||||
}
|
||||
return mContainer.mOwningRule;
|
||||
}
|
||||
|
||||
void SetHTMLCSSStyleSheet(nsHTMLCSSStyleSheet* aHTMLCSSStyleSheet) {
|
||||
MOZ_ASSERT(!mContainer.mHTMLCSSStyleSheet || !aHTMLCSSStyleSheet,
|
||||
"should never overwrite one sheet with another");
|
||||
mContainer.mHTMLCSSStyleSheet = aHTMLCSSStyleSheet;
|
||||
if (aHTMLCSSStyleSheet) {
|
||||
mContainer.mRaw |= uintptr_t(1);
|
||||
}
|
||||
}
|
||||
|
||||
nsHTMLCSSStyleSheet* GetHTMLCSSStyleSheet() const {
|
||||
if (!(mContainer.mRaw & 0x1)) {
|
||||
return nullptr;
|
||||
}
|
||||
auto c = mContainer;
|
||||
c.mRaw &= ~uintptr_t(1);
|
||||
return c.mHTMLCSSStyleSheet;
|
||||
}
|
||||
|
||||
inline void ToString(nsAString& aString) const;
|
||||
|
||||
inline uint32_t Count() const;
|
||||
inline bool GetNthProperty(uint32_t aIndex, nsAString& aReturn) const;
|
||||
|
||||
inline void GetPropertyValue(const nsAString& aProperty,
|
||||
nsAString& aValue) const;
|
||||
inline void GetPropertyValueByID(nsCSSPropertyID aPropID,
|
||||
nsAString& aValue) const;
|
||||
inline void GetAuthoredPropertyValue(const nsAString& aProperty,
|
||||
nsAString& aValue) const;
|
||||
inline bool GetPropertyIsImportant(const nsAString& aProperty) const;
|
||||
inline void RemoveProperty(const nsAString& aProperty);
|
||||
inline void RemovePropertyByID(nsCSSPropertyID aProperty);
|
||||
|
||||
private:
|
||||
union {
|
||||
// We only ever have one of these since we have an
|
||||
// nsHTMLCSSStyleSheet only for style attributes, and style
|
||||
// attributes never have an owning rule.
|
||||
|
||||
// It's an nsHTMLCSSStyleSheet if the low bit is set.
|
||||
|
||||
uintptr_t mRaw;
|
||||
|
||||
// The style rule that owns this declaration. May be null.
|
||||
css::Rule* mOwningRule;
|
||||
|
||||
// The nsHTMLCSSStyleSheet that is responsible for this declaration.
|
||||
// Only non-null for style attributes.
|
||||
nsHTMLCSSStyleSheet* mHTMLCSSStyleSheet;
|
||||
} mContainer;
|
||||
|
||||
// set when declaration put in the rule tree;
|
||||
// also by ToString (hence the 'mutable').
|
||||
mutable bool mImmutable;
|
||||
|
||||
const StyleBackendType mType;
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // mozilla_DeclarationBlock_h
|
||||
114
layout/style/DeclarationBlockInlines.h
Normal file
114
layout/style/DeclarationBlockInlines.h
Normal file
|
|
@ -0,0 +1,114 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* 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_DeclarationBlockInlines_h
|
||||
#define mozilla_DeclarationBlockInlines_h
|
||||
|
||||
#include "mozilla/css/Declaration.h"
|
||||
#include "mozilla/ServoDeclarationBlock.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
MOZ_DEFINE_STYLO_METHODS(DeclarationBlock, css::Declaration, ServoDeclarationBlock)
|
||||
|
||||
MozExternalRefCountType
|
||||
DeclarationBlock::AddRef()
|
||||
{
|
||||
MOZ_STYLO_FORWARD(AddRef, ())
|
||||
}
|
||||
|
||||
MozExternalRefCountType
|
||||
DeclarationBlock::Release()
|
||||
{
|
||||
MOZ_STYLO_FORWARD(Release, ())
|
||||
}
|
||||
|
||||
already_AddRefed<DeclarationBlock>
|
||||
DeclarationBlock::Clone() const
|
||||
{
|
||||
RefPtr<DeclarationBlock> result;
|
||||
if (IsGecko()) {
|
||||
result = new css::Declaration(*AsGecko());
|
||||
} else {
|
||||
result = new ServoDeclarationBlock(*AsServo());
|
||||
}
|
||||
return result.forget();
|
||||
}
|
||||
|
||||
already_AddRefed<DeclarationBlock>
|
||||
DeclarationBlock::EnsureMutable()
|
||||
{
|
||||
#ifdef DEBUG
|
||||
if (IsGecko()) {
|
||||
AsGecko()->AssertNotExpanded();
|
||||
}
|
||||
#endif
|
||||
if (!IsMutable()) {
|
||||
return Clone();
|
||||
}
|
||||
return do_AddRef(this);
|
||||
}
|
||||
|
||||
void
|
||||
DeclarationBlock::ToString(nsAString& aString) const
|
||||
{
|
||||
MOZ_STYLO_FORWARD(ToString, (aString))
|
||||
}
|
||||
|
||||
uint32_t
|
||||
DeclarationBlock::Count() const
|
||||
{
|
||||
MOZ_STYLO_FORWARD(Count, ())
|
||||
}
|
||||
|
||||
bool
|
||||
DeclarationBlock::GetNthProperty(uint32_t aIndex, nsAString& aReturn) const
|
||||
{
|
||||
MOZ_STYLO_FORWARD(GetNthProperty, (aIndex, aReturn))
|
||||
}
|
||||
|
||||
void
|
||||
DeclarationBlock::GetPropertyValue(const nsAString& aProperty,
|
||||
nsAString& aValue) const
|
||||
{
|
||||
MOZ_STYLO_FORWARD(GetPropertyValue, (aProperty, aValue))
|
||||
}
|
||||
|
||||
void
|
||||
DeclarationBlock::GetPropertyValueByID(nsCSSPropertyID aPropID,
|
||||
nsAString& aValue) const
|
||||
{
|
||||
MOZ_STYLO_FORWARD(GetPropertyValueByID, (aPropID, aValue))
|
||||
}
|
||||
|
||||
void
|
||||
DeclarationBlock::GetAuthoredPropertyValue(const nsAString& aProperty,
|
||||
nsAString& aValue) const
|
||||
{
|
||||
MOZ_STYLO_FORWARD(GetAuthoredPropertyValue, (aProperty, aValue))
|
||||
}
|
||||
|
||||
bool
|
||||
DeclarationBlock::GetPropertyIsImportant(const nsAString& aProperty) const
|
||||
{
|
||||
MOZ_STYLO_FORWARD(GetPropertyIsImportant, (aProperty))
|
||||
}
|
||||
|
||||
void
|
||||
DeclarationBlock::RemoveProperty(const nsAString& aProperty)
|
||||
{
|
||||
MOZ_STYLO_FORWARD(RemoveProperty, (aProperty))
|
||||
}
|
||||
|
||||
void
|
||||
DeclarationBlock::RemovePropertyByID(nsCSSPropertyID aProperty)
|
||||
{
|
||||
MOZ_STYLO_FORWARD(RemovePropertyByID, (aProperty))
|
||||
}
|
||||
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // mozilla_DeclarationBlockInlines_h
|
||||
382
layout/style/ErrorReporter.cpp
Normal file
382
layout/style/ErrorReporter.cpp
Normal file
|
|
@ -0,0 +1,382 @@
|
|||
/* -*- Mode: C++; 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/. */
|
||||
|
||||
/* diagnostic reporting for CSS style sheet parser */
|
||||
|
||||
#include "mozilla/css/ErrorReporter.h"
|
||||
|
||||
#include "mozilla/StyleSheetInlines.h"
|
||||
#include "mozilla/css/Loader.h"
|
||||
#include "mozilla/Preferences.h"
|
||||
#include "mozilla/Services.h"
|
||||
#include "nsCSSScanner.h"
|
||||
#include "nsIConsoleService.h"
|
||||
#include "nsIDocument.h"
|
||||
#include "nsIFactory.h"
|
||||
#include "nsIScriptError.h"
|
||||
#include "nsIStringBundle.h"
|
||||
#include "nsServiceManagerUtils.h"
|
||||
#include "nsStyleUtil.h"
|
||||
#include "nsThreadUtils.h"
|
||||
|
||||
#ifdef CSS_REPORT_PARSE_ERRORS
|
||||
|
||||
using namespace mozilla;
|
||||
|
||||
namespace {
|
||||
class ShortTermURISpecCache : public Runnable {
|
||||
public:
|
||||
ShortTermURISpecCache() : mPending(false) {}
|
||||
|
||||
nsString const& GetSpec(nsIURI* aURI) {
|
||||
if (mURI != aURI) {
|
||||
mURI = aURI;
|
||||
|
||||
nsAutoCString cSpec;
|
||||
nsresult rv = mURI->GetSpec(cSpec);
|
||||
if (NS_FAILED(rv)) {
|
||||
cSpec.AssignLiteral("[nsIURI::GetSpec failed]");
|
||||
}
|
||||
CopyUTF8toUTF16(cSpec, mSpec);
|
||||
}
|
||||
return mSpec;
|
||||
}
|
||||
|
||||
bool IsInUse() const { return mURI != nullptr; }
|
||||
bool IsPending() const { return mPending; }
|
||||
void SetPending() { mPending = true; }
|
||||
|
||||
// When invoked as a runnable, zap the cache.
|
||||
NS_IMETHOD Run() override {
|
||||
mURI = nullptr;
|
||||
mSpec.Truncate();
|
||||
mPending = false;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
private:
|
||||
nsCOMPtr<nsIURI> mURI;
|
||||
nsString mSpec;
|
||||
bool mPending;
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
static bool sReportErrors;
|
||||
static nsIConsoleService *sConsoleService;
|
||||
static nsIFactory *sScriptErrorFactory;
|
||||
static nsIStringBundle *sStringBundle;
|
||||
static ShortTermURISpecCache *sSpecCache;
|
||||
|
||||
#define CSS_ERRORS_PREF "layout.css.report_errors"
|
||||
|
||||
static bool
|
||||
InitGlobals()
|
||||
{
|
||||
MOZ_ASSERT(!sConsoleService && !sScriptErrorFactory && !sStringBundle,
|
||||
"should not have been called");
|
||||
|
||||
if (NS_FAILED(Preferences::AddBoolVarCache(&sReportErrors, CSS_ERRORS_PREF,
|
||||
true))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIConsoleService> cs = do_GetService(NS_CONSOLESERVICE_CONTRACTID);
|
||||
if (!cs) {
|
||||
return false;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIFactory> sf = do_GetClassObject(NS_SCRIPTERROR_CONTRACTID);
|
||||
if (!sf) {
|
||||
return false;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIStringBundleService> sbs = services::GetStringBundleService();
|
||||
if (!sbs) {
|
||||
return false;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIStringBundle> sb;
|
||||
nsresult rv = sbs->CreateBundle("chrome://global/locale/css.properties",
|
||||
getter_AddRefs(sb));
|
||||
if (NS_FAILED(rv) || !sb) {
|
||||
return false;
|
||||
}
|
||||
|
||||
cs.forget(&sConsoleService);
|
||||
sf.forget(&sScriptErrorFactory);
|
||||
sb.forget(&sStringBundle);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static inline bool
|
||||
ShouldReportErrors()
|
||||
{
|
||||
if (!sConsoleService) {
|
||||
if (!InitGlobals()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return sReportErrors;
|
||||
}
|
||||
|
||||
namespace mozilla {
|
||||
namespace css {
|
||||
|
||||
/* static */ void
|
||||
ErrorReporter::ReleaseGlobals()
|
||||
{
|
||||
NS_IF_RELEASE(sConsoleService);
|
||||
NS_IF_RELEASE(sScriptErrorFactory);
|
||||
NS_IF_RELEASE(sStringBundle);
|
||||
NS_IF_RELEASE(sSpecCache);
|
||||
}
|
||||
|
||||
ErrorReporter::ErrorReporter(const nsCSSScanner& aScanner,
|
||||
const CSSStyleSheet* aSheet,
|
||||
const Loader* aLoader,
|
||||
nsIURI* aURI)
|
||||
: mScanner(&aScanner), mSheet(aSheet), mLoader(aLoader), mURI(aURI),
|
||||
mInnerWindowID(0), mErrorLineNumber(0), mPrevErrorLineNumber(0),
|
||||
mErrorColNumber(0)
|
||||
{
|
||||
}
|
||||
|
||||
ErrorReporter::~ErrorReporter()
|
||||
{
|
||||
// Schedule deferred cleanup for cached data. We want to strike a
|
||||
// balance between performance and memory usage, so we only allow
|
||||
// short-term caching.
|
||||
if (sSpecCache && sSpecCache->IsInUse() && !sSpecCache->IsPending()) {
|
||||
if (NS_FAILED(NS_DispatchToCurrentThread(sSpecCache))) {
|
||||
// Peform the "deferred" cleanup immediately if the dispatch fails.
|
||||
sSpecCache->Run();
|
||||
} else {
|
||||
sSpecCache->SetPending();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ErrorReporter::OutputError()
|
||||
{
|
||||
if (mError.IsEmpty()) {
|
||||
return;
|
||||
}
|
||||
if (!ShouldReportErrors()) {
|
||||
ClearError();
|
||||
return;
|
||||
}
|
||||
|
||||
if (mInnerWindowID == 0 && (mSheet || mLoader)) {
|
||||
if (mSheet) {
|
||||
mInnerWindowID = mSheet->FindOwningWindowInnerID();
|
||||
}
|
||||
if (mInnerWindowID == 0 && mLoader) {
|
||||
nsIDocument* doc = mLoader->GetDocument();
|
||||
if (doc) {
|
||||
mInnerWindowID = doc->InnerWindowID();
|
||||
}
|
||||
}
|
||||
// don't attempt this again, even if we failed
|
||||
mSheet = nullptr;
|
||||
mLoader = nullptr;
|
||||
}
|
||||
|
||||
if (mFileName.IsEmpty()) {
|
||||
if (mURI) {
|
||||
if (!sSpecCache) {
|
||||
sSpecCache = new ShortTermURISpecCache;
|
||||
NS_ADDREF(sSpecCache);
|
||||
}
|
||||
mFileName = sSpecCache->GetSpec(mURI);
|
||||
mURI = nullptr;
|
||||
} else {
|
||||
mFileName.AssignLiteral("from DOM");
|
||||
}
|
||||
}
|
||||
|
||||
nsresult rv;
|
||||
nsCOMPtr<nsIScriptError> errorObject =
|
||||
do_CreateInstance(sScriptErrorFactory, &rv);
|
||||
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
rv = errorObject->InitWithWindowID(mError,
|
||||
mFileName,
|
||||
mErrorLine,
|
||||
mErrorLineNumber,
|
||||
mErrorColNumber,
|
||||
nsIScriptError::warningFlag,
|
||||
"CSS Parser",
|
||||
mInnerWindowID);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
sConsoleService->LogMessage(errorObject);
|
||||
}
|
||||
}
|
||||
|
||||
ClearError();
|
||||
}
|
||||
|
||||
void
|
||||
ErrorReporter::OutputError(uint32_t aLineNumber, uint32_t aLineOffset)
|
||||
{
|
||||
mErrorLineNumber = aLineNumber;
|
||||
mErrorColNumber = aLineOffset;
|
||||
OutputError();
|
||||
}
|
||||
|
||||
void
|
||||
ErrorReporter::ClearError()
|
||||
{
|
||||
mError.Truncate();
|
||||
}
|
||||
|
||||
void
|
||||
ErrorReporter::AddToError(const nsString &aErrorText)
|
||||
{
|
||||
if (!ShouldReportErrors()) return;
|
||||
|
||||
if (mError.IsEmpty()) {
|
||||
mError = aErrorText;
|
||||
mErrorLineNumber = mScanner->GetLineNumber();
|
||||
mErrorColNumber = mScanner->GetColumnNumber();
|
||||
// Retrieve the error line once per line, and reuse the same nsString
|
||||
// for all errors on that line. That causes the text of the line to
|
||||
// be shared among all the nsIScriptError objects.
|
||||
if (mErrorLine.IsEmpty() || mErrorLineNumber != mPrevErrorLineNumber) {
|
||||
// Be careful here: the error line might be really long and OOM
|
||||
// when we try to make a copy here. If so, just leave it empty.
|
||||
if (!mErrorLine.Assign(mScanner->GetCurrentLine(), fallible)) {
|
||||
mErrorLine.Truncate();
|
||||
}
|
||||
mPrevErrorLineNumber = mErrorLineNumber;
|
||||
}
|
||||
} else {
|
||||
mError.AppendLiteral(" ");
|
||||
mError.Append(aErrorText);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ErrorReporter::ReportUnexpected(const char *aMessage)
|
||||
{
|
||||
if (!ShouldReportErrors()) return;
|
||||
|
||||
nsAutoString str;
|
||||
sStringBundle->GetStringFromName(NS_ConvertASCIItoUTF16(aMessage).get(),
|
||||
getter_Copies(str));
|
||||
AddToError(str);
|
||||
}
|
||||
|
||||
void
|
||||
ErrorReporter::ReportUnexpected(const char *aMessage,
|
||||
const nsString &aParam)
|
||||
{
|
||||
if (!ShouldReportErrors()) return;
|
||||
|
||||
nsAutoString qparam;
|
||||
nsStyleUtil::AppendEscapedCSSIdent(aParam, qparam);
|
||||
const char16_t *params[1] = { qparam.get() };
|
||||
|
||||
nsAutoString str;
|
||||
sStringBundle->FormatStringFromName(NS_ConvertASCIItoUTF16(aMessage).get(),
|
||||
params, ArrayLength(params),
|
||||
getter_Copies(str));
|
||||
AddToError(str);
|
||||
}
|
||||
|
||||
void
|
||||
ErrorReporter::ReportUnexpected(const char *aMessage,
|
||||
const nsCSSToken &aToken)
|
||||
{
|
||||
if (!ShouldReportErrors()) return;
|
||||
|
||||
nsAutoString tokenString;
|
||||
aToken.AppendToString(tokenString);
|
||||
const char16_t *params[1] = { tokenString.get() };
|
||||
|
||||
nsAutoString str;
|
||||
sStringBundle->FormatStringFromName(NS_ConvertASCIItoUTF16(aMessage).get(),
|
||||
params, ArrayLength(params),
|
||||
getter_Copies(str));
|
||||
AddToError(str);
|
||||
}
|
||||
|
||||
void
|
||||
ErrorReporter::ReportUnexpected(const char *aMessage,
|
||||
const nsCSSToken &aToken,
|
||||
char16_t aChar)
|
||||
{
|
||||
if (!ShouldReportErrors()) return;
|
||||
|
||||
nsAutoString tokenString;
|
||||
aToken.AppendToString(tokenString);
|
||||
const char16_t charStr[2] = { aChar, 0 };
|
||||
const char16_t *params[2] = { tokenString.get(), charStr };
|
||||
|
||||
nsAutoString str;
|
||||
sStringBundle->FormatStringFromName(NS_ConvertASCIItoUTF16(aMessage).get(),
|
||||
params, ArrayLength(params),
|
||||
getter_Copies(str));
|
||||
AddToError(str);
|
||||
}
|
||||
|
||||
void
|
||||
ErrorReporter::ReportUnexpected(const char *aMessage,
|
||||
const nsString &aParam,
|
||||
const nsString &aValue)
|
||||
{
|
||||
if (!ShouldReportErrors()) return;
|
||||
|
||||
nsAutoString qparam;
|
||||
nsStyleUtil::AppendEscapedCSSIdent(aParam, qparam);
|
||||
const char16_t *params[2] = { qparam.get(), aValue.get() };
|
||||
|
||||
nsAutoString str;
|
||||
sStringBundle->FormatStringFromName(NS_ConvertASCIItoUTF16(aMessage).get(),
|
||||
params, ArrayLength(params),
|
||||
getter_Copies(str));
|
||||
AddToError(str);
|
||||
}
|
||||
|
||||
void
|
||||
ErrorReporter::ReportUnexpectedEOF(const char *aMessage)
|
||||
{
|
||||
if (!ShouldReportErrors()) return;
|
||||
|
||||
nsAutoString innerStr;
|
||||
sStringBundle->GetStringFromName(NS_ConvertASCIItoUTF16(aMessage).get(),
|
||||
getter_Copies(innerStr));
|
||||
const char16_t *params[1] = { innerStr.get() };
|
||||
|
||||
nsAutoString str;
|
||||
sStringBundle->FormatStringFromName(u"PEUnexpEOF2",
|
||||
params, ArrayLength(params),
|
||||
getter_Copies(str));
|
||||
AddToError(str);
|
||||
}
|
||||
|
||||
void
|
||||
ErrorReporter::ReportUnexpectedEOF(char16_t aExpected)
|
||||
{
|
||||
if (!ShouldReportErrors()) return;
|
||||
|
||||
const char16_t expectedStr[] = {
|
||||
char16_t('\''), aExpected, char16_t('\''), char16_t(0)
|
||||
};
|
||||
const char16_t *params[1] = { expectedStr };
|
||||
|
||||
nsAutoString str;
|
||||
sStringBundle->FormatStringFromName(u"PEUnexpEOF2",
|
||||
params, ArrayLength(params),
|
||||
getter_Copies(str));
|
||||
AddToError(str);
|
||||
}
|
||||
|
||||
} // namespace css
|
||||
} // namespace mozilla
|
||||
|
||||
#endif
|
||||
113
layout/style/ErrorReporter.h
Normal file
113
layout/style/ErrorReporter.h
Normal file
|
|
@ -0,0 +1,113 @@
|
|||
/* -*- Mode: C++; 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/. */
|
||||
|
||||
/* diagnostic reporting for CSS style sheet parser */
|
||||
|
||||
#ifndef mozilla_css_ErrorReporter_h_
|
||||
#define mozilla_css_ErrorReporter_h_
|
||||
|
||||
// XXX turn this off for minimo builds
|
||||
#define CSS_REPORT_PARSE_ERRORS
|
||||
|
||||
#include "nsString.h"
|
||||
|
||||
struct nsCSSToken;
|
||||
class nsCSSScanner;
|
||||
class nsIURI;
|
||||
|
||||
namespace mozilla {
|
||||
class CSSStyleSheet;
|
||||
|
||||
namespace css {
|
||||
|
||||
class Loader;
|
||||
|
||||
// If CSS_REPORT_PARSE_ERRORS is not defined, all of this class's
|
||||
// methods become inline stubs.
|
||||
class MOZ_STACK_CLASS ErrorReporter {
|
||||
public:
|
||||
ErrorReporter(const nsCSSScanner &aScanner,
|
||||
const CSSStyleSheet *aSheet,
|
||||
const Loader *aLoader,
|
||||
nsIURI *aURI);
|
||||
~ErrorReporter();
|
||||
|
||||
static void ReleaseGlobals();
|
||||
|
||||
void OutputError();
|
||||
void OutputError(uint32_t aLineNumber, uint32_t aLineOffset);
|
||||
void ClearError();
|
||||
|
||||
// In all overloads of ReportUnexpected, aMessage is a stringbundle
|
||||
// name, which will be processed as a format string with the
|
||||
// indicated number of parameters.
|
||||
|
||||
// no parameters
|
||||
void ReportUnexpected(const char *aMessage);
|
||||
// one parameter, a string
|
||||
void ReportUnexpected(const char *aMessage, const nsString& aParam);
|
||||
// one parameter, a token
|
||||
void ReportUnexpected(const char *aMessage, const nsCSSToken& aToken);
|
||||
// two parameters, a token and a character, in that order
|
||||
void ReportUnexpected(const char *aMessage, const nsCSSToken& aToken,
|
||||
char16_t aChar);
|
||||
// two parameters, a param and a value
|
||||
void ReportUnexpected(const char *aMessage, const nsString& aParam,
|
||||
const nsString& aValue);
|
||||
|
||||
// for ReportUnexpectedEOF, aExpected can be either a stringbundle
|
||||
// name or a single character. In the former case there may not be
|
||||
// any format parameters.
|
||||
void ReportUnexpectedEOF(const char *aExpected);
|
||||
void ReportUnexpectedEOF(char16_t aExpected);
|
||||
|
||||
private:
|
||||
void AddToError(const nsString &aErrorText);
|
||||
|
||||
#ifdef CSS_REPORT_PARSE_ERRORS
|
||||
nsAutoString mError;
|
||||
nsString mErrorLine;
|
||||
nsString mFileName;
|
||||
const nsCSSScanner *mScanner;
|
||||
const CSSStyleSheet *mSheet;
|
||||
const Loader *mLoader;
|
||||
nsIURI *mURI;
|
||||
uint64_t mInnerWindowID;
|
||||
uint32_t mErrorLineNumber;
|
||||
uint32_t mPrevErrorLineNumber;
|
||||
uint32_t mErrorColNumber;
|
||||
#endif
|
||||
};
|
||||
|
||||
#ifndef CSS_REPORT_PARSE_ERRORS
|
||||
inline ErrorReporter::ErrorReporter(const nsCSSScanner&,
|
||||
const CSSStyleSheet*,
|
||||
const Loader*,
|
||||
nsIURI*) {}
|
||||
inline ErrorReporter::~ErrorReporter() {}
|
||||
|
||||
inline void ErrorReporter::ReleaseGlobals() {}
|
||||
|
||||
inline void ErrorReporter::OutputError() {}
|
||||
inline void ErrorReporter::ClearError() {}
|
||||
|
||||
inline void ErrorReporter::ReportUnexpected(const char *) {}
|
||||
inline void ErrorReporter::ReportUnexpected(const char *, const nsString &) {}
|
||||
inline void ErrorReporter::ReportUnexpected(const char *, const nsCSSToken &) {}
|
||||
inline void ErrorReporter::ReportUnexpected(const char *, const nsCSSToken &,
|
||||
char16_t) {}
|
||||
inline void ErrorReporter::ReportUnexpected(const char *, const nsString &,
|
||||
const nsString &) {}
|
||||
|
||||
inline void ErrorReporter::ReportUnexpectedEOF(const char *) {}
|
||||
inline void ErrorReporter::ReportUnexpectedEOF(char16_t) {}
|
||||
|
||||
inline void ErrorReporter::AddToError(const nsString &) {}
|
||||
#endif
|
||||
|
||||
} // namespace css
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // mozilla_css_ErrorReporter_h_
|
||||
808
layout/style/FontFace.cpp
Normal file
808
layout/style/FontFace.cpp
Normal file
|
|
@ -0,0 +1,808 @@
|
|||
/* -*- Mode: C++; 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/. */
|
||||
|
||||
#include "mozilla/dom/FontFace.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include "mozilla/dom/FontFaceBinding.h"
|
||||
#include "mozilla/dom/FontFaceSet.h"
|
||||
#include "mozilla/dom/Promise.h"
|
||||
#include "mozilla/dom/TypedArray.h"
|
||||
#include "mozilla/dom/UnionTypes.h"
|
||||
#include "mozilla/CycleCollectedJSContext.h"
|
||||
#include "nsCSSParser.h"
|
||||
#include "nsCSSRules.h"
|
||||
#include "nsIDocument.h"
|
||||
#include "nsStyleUtil.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
// -- FontFaceBufferSource ---------------------------------------------------
|
||||
|
||||
/**
|
||||
* An object that wraps a FontFace object and exposes its ArrayBuffer
|
||||
* or ArrayBufferView data in a form the user font set can consume.
|
||||
*/
|
||||
class FontFaceBufferSource : public gfxFontFaceBufferSource
|
||||
{
|
||||
public:
|
||||
explicit FontFaceBufferSource(FontFace* aFontFace)
|
||||
: mFontFace(aFontFace) {}
|
||||
virtual void TakeBuffer(uint8_t*& aBuffer, uint32_t& aLength);
|
||||
|
||||
private:
|
||||
RefPtr<FontFace> mFontFace;
|
||||
};
|
||||
|
||||
void
|
||||
FontFaceBufferSource::TakeBuffer(uint8_t*& aBuffer, uint32_t& aLength)
|
||||
{
|
||||
MOZ_ASSERT(mFontFace, "only call TakeBuffer once on a given "
|
||||
"FontFaceBufferSource object");
|
||||
mFontFace->TakeBuffer(aBuffer, aLength);
|
||||
mFontFace = nullptr;
|
||||
}
|
||||
|
||||
// -- Utility functions ------------------------------------------------------
|
||||
|
||||
template<typename T>
|
||||
static void
|
||||
GetDataFrom(const T& aObject, uint8_t*& aBuffer, uint32_t& aLength)
|
||||
{
|
||||
MOZ_ASSERT(!aBuffer);
|
||||
aObject.ComputeLengthAndData();
|
||||
// We use malloc here rather than a FallibleTArray or fallible
|
||||
// operator new[] since the gfxUserFontEntry will be calling free
|
||||
// on it.
|
||||
aBuffer = (uint8_t*) malloc(aObject.Length());
|
||||
if (!aBuffer) {
|
||||
return;
|
||||
}
|
||||
memcpy((void*) aBuffer, aObject.Data(), aObject.Length());
|
||||
aLength = aObject.Length();
|
||||
}
|
||||
|
||||
// -- FontFace ---------------------------------------------------------------
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_CLASS(FontFace)
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(FontFace)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mParent)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mLoaded)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mRule)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mFontFaceSet)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mOtherFontFaceSets)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(FontFace)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mParent)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mLoaded)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mRule)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mFontFaceSet)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mOtherFontFaceSets)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(FontFace)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER
|
||||
NS_IMPL_CYCLE_COLLECTION_TRACE_END
|
||||
|
||||
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(FontFace)
|
||||
NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
|
||||
NS_INTERFACE_MAP_ENTRY(nsISupports)
|
||||
NS_INTERFACE_MAP_END
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTING_ADDREF(FontFace)
|
||||
NS_IMPL_CYCLE_COLLECTING_RELEASE(FontFace)
|
||||
|
||||
FontFace::FontFace(nsISupports* aParent, FontFaceSet* aFontFaceSet)
|
||||
: mParent(aParent)
|
||||
, mLoadedRejection(NS_OK)
|
||||
, mStatus(FontFaceLoadStatus::Unloaded)
|
||||
, mSourceType(SourceType(0))
|
||||
, mSourceBuffer(nullptr)
|
||||
, mSourceBufferLength(0)
|
||||
, mFontFaceSet(aFontFaceSet)
|
||||
, mInFontFaceSet(false)
|
||||
{
|
||||
MOZ_COUNT_CTOR(FontFace);
|
||||
}
|
||||
|
||||
FontFace::~FontFace()
|
||||
{
|
||||
MOZ_COUNT_DTOR(FontFace);
|
||||
|
||||
SetUserFontEntry(nullptr);
|
||||
|
||||
if (mSourceBuffer) {
|
||||
free(mSourceBuffer);
|
||||
}
|
||||
}
|
||||
|
||||
JSObject*
|
||||
FontFace::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
|
||||
{
|
||||
return FontFaceBinding::Wrap(aCx, this, aGivenProto);
|
||||
}
|
||||
|
||||
static FontFaceLoadStatus
|
||||
LoadStateToStatus(gfxUserFontEntry::UserFontLoadState aLoadState)
|
||||
{
|
||||
switch (aLoadState) {
|
||||
case gfxUserFontEntry::UserFontLoadState::STATUS_NOT_LOADED:
|
||||
return FontFaceLoadStatus::Unloaded;
|
||||
case gfxUserFontEntry::UserFontLoadState::STATUS_LOADING:
|
||||
return FontFaceLoadStatus::Loading;
|
||||
case gfxUserFontEntry::UserFontLoadState::STATUS_LOADED:
|
||||
return FontFaceLoadStatus::Loaded;
|
||||
case gfxUserFontEntry::UserFontLoadState::STATUS_FAILED:
|
||||
return FontFaceLoadStatus::Error;
|
||||
}
|
||||
NS_NOTREACHED("invalid aLoadState value");
|
||||
return FontFaceLoadStatus::Error;
|
||||
}
|
||||
|
||||
already_AddRefed<FontFace>
|
||||
FontFace::CreateForRule(nsISupports* aGlobal,
|
||||
FontFaceSet* aFontFaceSet,
|
||||
nsCSSFontFaceRule* aRule)
|
||||
{
|
||||
RefPtr<FontFace> obj = new FontFace(aGlobal, aFontFaceSet);
|
||||
obj->mRule = aRule;
|
||||
obj->mSourceType = eSourceType_FontFaceRule;
|
||||
obj->mInFontFaceSet = true;
|
||||
return obj.forget();
|
||||
}
|
||||
|
||||
already_AddRefed<FontFace>
|
||||
FontFace::Constructor(const GlobalObject& aGlobal,
|
||||
const nsAString& aFamily,
|
||||
const StringOrArrayBufferOrArrayBufferView& aSource,
|
||||
const FontFaceDescriptors& aDescriptors,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
nsISupports* global = aGlobal.GetAsSupports();
|
||||
nsCOMPtr<nsPIDOMWindowInner> window = do_QueryInterface(global);
|
||||
nsIDocument* doc = window->GetDoc();
|
||||
if (!doc) {
|
||||
aRv.Throw(NS_ERROR_FAILURE);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
RefPtr<FontFace> obj = new FontFace(global, doc->Fonts());
|
||||
if (!obj->SetDescriptors(aFamily, aDescriptors)) {
|
||||
return obj.forget();
|
||||
}
|
||||
|
||||
obj->InitializeSource(aSource);
|
||||
return obj.forget();
|
||||
}
|
||||
|
||||
void
|
||||
FontFace::InitializeSource(const StringOrArrayBufferOrArrayBufferView& aSource)
|
||||
{
|
||||
if (aSource.IsString()) {
|
||||
if (!ParseDescriptor(eCSSFontDesc_Src,
|
||||
aSource.GetAsString(),
|
||||
mDescriptors->mSrc)) {
|
||||
Reject(NS_ERROR_DOM_SYNTAX_ERR);
|
||||
|
||||
SetStatus(FontFaceLoadStatus::Error);
|
||||
return;
|
||||
}
|
||||
|
||||
mSourceType = eSourceType_URLs;
|
||||
return;
|
||||
}
|
||||
|
||||
mSourceType = FontFace::eSourceType_Buffer;
|
||||
|
||||
if (aSource.IsArrayBuffer()) {
|
||||
GetDataFrom(aSource.GetAsArrayBuffer(),
|
||||
mSourceBuffer, mSourceBufferLength);
|
||||
} else {
|
||||
MOZ_ASSERT(aSource.IsArrayBufferView());
|
||||
GetDataFrom(aSource.GetAsArrayBufferView(),
|
||||
mSourceBuffer, mSourceBufferLength);
|
||||
}
|
||||
|
||||
SetStatus(FontFaceLoadStatus::Loading);
|
||||
DoLoad();
|
||||
}
|
||||
|
||||
void
|
||||
FontFace::GetFamily(nsString& aResult)
|
||||
{
|
||||
mFontFaceSet->FlushUserFontSet();
|
||||
|
||||
// Serialize the same way as in nsCSSFontFaceStyleDecl::GetPropertyValue.
|
||||
nsCSSValue value;
|
||||
GetDesc(eCSSFontDesc_Family, value);
|
||||
|
||||
aResult.Truncate();
|
||||
|
||||
if (value.GetUnit() == eCSSUnit_Null) {
|
||||
return;
|
||||
}
|
||||
|
||||
nsDependentString family(value.GetStringBufferValue());
|
||||
if (!family.IsEmpty()) {
|
||||
// The string length can be zero when the author passed an invalid
|
||||
// family name or an invalid descriptor to the JS FontFace constructor.
|
||||
nsStyleUtil::AppendEscapedCSSString(family, aResult);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
FontFace::SetFamily(const nsAString& aValue, ErrorResult& aRv)
|
||||
{
|
||||
mFontFaceSet->FlushUserFontSet();
|
||||
SetDescriptor(eCSSFontDesc_Family, aValue, aRv);
|
||||
}
|
||||
|
||||
void
|
||||
FontFace::GetStyle(nsString& aResult)
|
||||
{
|
||||
mFontFaceSet->FlushUserFontSet();
|
||||
GetDesc(eCSSFontDesc_Style, eCSSProperty_font_style, aResult);
|
||||
}
|
||||
|
||||
void
|
||||
FontFace::SetStyle(const nsAString& aValue, ErrorResult& aRv)
|
||||
{
|
||||
mFontFaceSet->FlushUserFontSet();
|
||||
SetDescriptor(eCSSFontDesc_Style, aValue, aRv);
|
||||
}
|
||||
|
||||
void
|
||||
FontFace::GetWeight(nsString& aResult)
|
||||
{
|
||||
mFontFaceSet->FlushUserFontSet();
|
||||
GetDesc(eCSSFontDesc_Weight, eCSSProperty_font_weight, aResult);
|
||||
}
|
||||
|
||||
void
|
||||
FontFace::SetWeight(const nsAString& aValue, ErrorResult& aRv)
|
||||
{
|
||||
mFontFaceSet->FlushUserFontSet();
|
||||
SetDescriptor(eCSSFontDesc_Weight, aValue, aRv);
|
||||
}
|
||||
|
||||
void
|
||||
FontFace::GetStretch(nsString& aResult)
|
||||
{
|
||||
mFontFaceSet->FlushUserFontSet();
|
||||
GetDesc(eCSSFontDesc_Stretch, eCSSProperty_font_stretch, aResult);
|
||||
}
|
||||
|
||||
void
|
||||
FontFace::SetStretch(const nsAString& aValue, ErrorResult& aRv)
|
||||
{
|
||||
mFontFaceSet->FlushUserFontSet();
|
||||
SetDescriptor(eCSSFontDesc_Stretch, aValue, aRv);
|
||||
}
|
||||
|
||||
void
|
||||
FontFace::GetUnicodeRange(nsString& aResult)
|
||||
{
|
||||
mFontFaceSet->FlushUserFontSet();
|
||||
|
||||
// There is no eCSSProperty_unicode_range for us to pass in to GetDesc
|
||||
// to get a serialized (possibly defaulted) value, but that function
|
||||
// doesn't use the property ID for this descriptor anyway.
|
||||
GetDesc(eCSSFontDesc_UnicodeRange, eCSSProperty_UNKNOWN, aResult);
|
||||
}
|
||||
|
||||
void
|
||||
FontFace::SetUnicodeRange(const nsAString& aValue, ErrorResult& aRv)
|
||||
{
|
||||
mFontFaceSet->FlushUserFontSet();
|
||||
SetDescriptor(eCSSFontDesc_UnicodeRange, aValue, aRv);
|
||||
}
|
||||
|
||||
void
|
||||
FontFace::GetVariant(nsString& aResult)
|
||||
{
|
||||
mFontFaceSet->FlushUserFontSet();
|
||||
|
||||
// XXX Just expose the font-variant descriptor as "normal" until we
|
||||
// support it properly (bug 1055385).
|
||||
aResult.AssignLiteral("normal");
|
||||
}
|
||||
|
||||
void
|
||||
FontFace::SetVariant(const nsAString& aValue, ErrorResult& aRv)
|
||||
{
|
||||
mFontFaceSet->FlushUserFontSet();
|
||||
|
||||
// XXX Ignore assignments to variant until we support font-variant
|
||||
// descriptors (bug 1055385).
|
||||
}
|
||||
|
||||
void
|
||||
FontFace::GetFeatureSettings(nsString& aResult)
|
||||
{
|
||||
mFontFaceSet->FlushUserFontSet();
|
||||
GetDesc(eCSSFontDesc_FontFeatureSettings, eCSSProperty_font_feature_settings,
|
||||
aResult);
|
||||
}
|
||||
|
||||
void
|
||||
FontFace::SetFeatureSettings(const nsAString& aValue, ErrorResult& aRv)
|
||||
{
|
||||
mFontFaceSet->FlushUserFontSet();
|
||||
SetDescriptor(eCSSFontDesc_FontFeatureSettings, aValue, aRv);
|
||||
}
|
||||
|
||||
void
|
||||
FontFace::GetDisplay(nsString& aResult)
|
||||
{
|
||||
mFontFaceSet->FlushUserFontSet();
|
||||
GetDesc(eCSSFontDesc_Display, eCSSProperty_UNKNOWN, aResult);
|
||||
}
|
||||
|
||||
void
|
||||
FontFace::SetDisplay(const nsAString& aValue, ErrorResult& aRv)
|
||||
{
|
||||
mFontFaceSet->FlushUserFontSet();
|
||||
SetDescriptor(eCSSFontDesc_Display, aValue, aRv);
|
||||
}
|
||||
|
||||
FontFaceLoadStatus
|
||||
FontFace::Status()
|
||||
{
|
||||
return mStatus;
|
||||
}
|
||||
|
||||
Promise*
|
||||
FontFace::Load(ErrorResult& aRv)
|
||||
{
|
||||
mFontFaceSet->FlushUserFontSet();
|
||||
|
||||
EnsurePromise();
|
||||
|
||||
if (!mLoaded) {
|
||||
aRv.Throw(NS_ERROR_FAILURE);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Calling Load on a FontFace constructed with an ArrayBuffer data source,
|
||||
// or on one that is already loading (or has finished loading), has no
|
||||
// effect.
|
||||
if (mSourceType == eSourceType_Buffer ||
|
||||
mStatus != FontFaceLoadStatus::Unloaded) {
|
||||
return mLoaded;
|
||||
}
|
||||
|
||||
// Calling the user font entry's Load method will end up setting our
|
||||
// status to Loading, but the spec requires us to set it to Loading
|
||||
// here.
|
||||
SetStatus(FontFaceLoadStatus::Loading);
|
||||
|
||||
DoLoad();
|
||||
|
||||
return mLoaded;
|
||||
}
|
||||
|
||||
gfxUserFontEntry*
|
||||
FontFace::CreateUserFontEntry()
|
||||
{
|
||||
if (!mUserFontEntry) {
|
||||
MOZ_ASSERT(!HasRule(),
|
||||
"Rule backed FontFace objects should already have a user font "
|
||||
"entry by the time Load() can be called on them");
|
||||
|
||||
RefPtr<gfxUserFontEntry> newEntry =
|
||||
mFontFaceSet->FindOrCreateUserFontEntryFromFontFace(this);
|
||||
if (newEntry) {
|
||||
SetUserFontEntry(newEntry);
|
||||
}
|
||||
}
|
||||
|
||||
return mUserFontEntry;
|
||||
}
|
||||
|
||||
void
|
||||
FontFace::DoLoad()
|
||||
{
|
||||
if (!CreateUserFontEntry()) {
|
||||
return;
|
||||
}
|
||||
mUserFontEntry->Load();
|
||||
}
|
||||
|
||||
Promise*
|
||||
FontFace::GetLoaded(ErrorResult& aRv)
|
||||
{
|
||||
mFontFaceSet->FlushUserFontSet();
|
||||
|
||||
EnsurePromise();
|
||||
|
||||
if (!mLoaded) {
|
||||
aRv.Throw(NS_ERROR_FAILURE);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return mLoaded;
|
||||
}
|
||||
|
||||
void
|
||||
FontFace::SetStatus(FontFaceLoadStatus aStatus)
|
||||
{
|
||||
if (mStatus == aStatus) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (aStatus < mStatus) {
|
||||
// We're being asked to go backwards in status! Normally, this shouldn't
|
||||
// happen. But it can if the FontFace had a user font entry that had
|
||||
// loaded, but then was given a new one by FontFaceSet::InsertRuleFontFace
|
||||
// if we used a local() rule. For now, just ignore the request to
|
||||
// go backwards in status.
|
||||
return;
|
||||
}
|
||||
|
||||
mStatus = aStatus;
|
||||
|
||||
if (mInFontFaceSet) {
|
||||
mFontFaceSet->OnFontFaceStatusChanged(this);
|
||||
}
|
||||
|
||||
for (FontFaceSet* otherSet : mOtherFontFaceSets) {
|
||||
otherSet->OnFontFaceStatusChanged(this);
|
||||
}
|
||||
|
||||
if (mStatus == FontFaceLoadStatus::Loaded) {
|
||||
if (mLoaded) {
|
||||
mLoaded->MaybeResolve(this);
|
||||
}
|
||||
} else if (mStatus == FontFaceLoadStatus::Error) {
|
||||
if (mSourceType == eSourceType_Buffer) {
|
||||
Reject(NS_ERROR_DOM_SYNTAX_ERR);
|
||||
} else {
|
||||
Reject(NS_ERROR_DOM_NETWORK_ERR);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
FontFace::ParseDescriptor(nsCSSFontDesc aDescID,
|
||||
const nsAString& aString,
|
||||
nsCSSValue& aResult)
|
||||
{
|
||||
nsCSSParser parser;
|
||||
|
||||
nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(mParent);
|
||||
nsCOMPtr<nsIPrincipal> principal = global->PrincipalOrNull();
|
||||
|
||||
nsCOMPtr<nsPIDOMWindowInner> window = do_QueryInterface(mParent);
|
||||
nsCOMPtr<nsIURI> docURI = window->GetDocumentURI();
|
||||
nsCOMPtr<nsIURI> base = window->GetDocBaseURI();
|
||||
|
||||
if (!parser.ParseFontFaceDescriptor(aDescID, aString,
|
||||
docURI, // aSheetURL
|
||||
base,
|
||||
principal,
|
||||
aResult)) {
|
||||
aResult.Reset();
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
FontFace::SetDescriptor(nsCSSFontDesc aFontDesc,
|
||||
const nsAString& aValue,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
NS_ASSERTION(!HasRule(),
|
||||
"we don't handle rule backed FontFace objects yet");
|
||||
if (HasRule()) {
|
||||
return;
|
||||
}
|
||||
|
||||
nsCSSValue parsedValue;
|
||||
if (!ParseDescriptor(aFontDesc, aValue, parsedValue)) {
|
||||
aRv.Throw(NS_ERROR_DOM_SYNTAX_ERR);
|
||||
return;
|
||||
}
|
||||
|
||||
mDescriptors->Get(aFontDesc) = parsedValue;
|
||||
|
||||
// XXX Setting descriptors doesn't actually have any effect on FontFace
|
||||
// objects that have started loading or have already been loaded.
|
||||
}
|
||||
|
||||
bool
|
||||
FontFace::SetDescriptors(const nsAString& aFamily,
|
||||
const FontFaceDescriptors& aDescriptors)
|
||||
{
|
||||
MOZ_ASSERT(!HasRule());
|
||||
MOZ_ASSERT(!mDescriptors);
|
||||
|
||||
mDescriptors = new CSSFontFaceDescriptors;
|
||||
|
||||
// Parse all of the mDescriptors in aInitializer, which are the values
|
||||
// we got from the JS constructor.
|
||||
if (!ParseDescriptor(eCSSFontDesc_Family,
|
||||
aFamily,
|
||||
mDescriptors->mFamily) ||
|
||||
*mDescriptors->mFamily.GetStringBufferValue() == 0 ||
|
||||
!ParseDescriptor(eCSSFontDesc_Style,
|
||||
aDescriptors.mStyle,
|
||||
mDescriptors->mStyle) ||
|
||||
!ParseDescriptor(eCSSFontDesc_Weight,
|
||||
aDescriptors.mWeight,
|
||||
mDescriptors->mWeight) ||
|
||||
!ParseDescriptor(eCSSFontDesc_Stretch,
|
||||
aDescriptors.mStretch,
|
||||
mDescriptors->mStretch) ||
|
||||
!ParseDescriptor(eCSSFontDesc_UnicodeRange,
|
||||
aDescriptors.mUnicodeRange,
|
||||
mDescriptors->mUnicodeRange) ||
|
||||
!ParseDescriptor(eCSSFontDesc_FontFeatureSettings,
|
||||
aDescriptors.mFeatureSettings,
|
||||
mDescriptors->mFontFeatureSettings) ||
|
||||
!ParseDescriptor(eCSSFontDesc_Display,
|
||||
aDescriptors.mDisplay,
|
||||
mDescriptors->mDisplay)) {
|
||||
// XXX Handle font-variant once we support it (bug 1055385).
|
||||
|
||||
// If any of the descriptors failed to parse, none of them should be set
|
||||
// on the FontFace.
|
||||
mDescriptors = new CSSFontFaceDescriptors;
|
||||
|
||||
Reject(NS_ERROR_DOM_SYNTAX_ERR);
|
||||
|
||||
SetStatus(FontFaceLoadStatus::Error);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
FontFace::GetDesc(nsCSSFontDesc aDescID, nsCSSValue& aResult) const
|
||||
{
|
||||
if (HasRule()) {
|
||||
MOZ_ASSERT(mRule);
|
||||
MOZ_ASSERT(!mDescriptors);
|
||||
mRule->GetDesc(aDescID, aResult);
|
||||
} else {
|
||||
aResult = mDescriptors->Get(aDescID);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
FontFace::GetDesc(nsCSSFontDesc aDescID,
|
||||
nsCSSPropertyID aPropID,
|
||||
nsString& aResult) const
|
||||
{
|
||||
MOZ_ASSERT(aDescID == eCSSFontDesc_UnicodeRange ||
|
||||
aDescID == eCSSFontDesc_Display ||
|
||||
aPropID != eCSSProperty_UNKNOWN,
|
||||
"only pass eCSSProperty_UNKNOWN for eCSSFontDesc_UnicodeRange");
|
||||
|
||||
nsCSSValue value;
|
||||
GetDesc(aDescID, value);
|
||||
|
||||
aResult.Truncate();
|
||||
|
||||
// Fill in a default value for missing descriptors.
|
||||
if (value.GetUnit() == eCSSUnit_Null) {
|
||||
if (aDescID == eCSSFontDesc_UnicodeRange) {
|
||||
aResult.AssignLiteral("U+0-10FFFF");
|
||||
} else if (aDescID == eCSSFontDesc_Display) {
|
||||
aResult.AssignLiteral("auto");
|
||||
} else if (aDescID != eCSSFontDesc_Family &&
|
||||
aDescID != eCSSFontDesc_Src) {
|
||||
aResult.AssignLiteral("normal");
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (aDescID == eCSSFontDesc_UnicodeRange) {
|
||||
// Since there's no unicode-range property, we can't use
|
||||
// nsCSSValue::AppendToString to serialize this descriptor.
|
||||
nsStyleUtil::AppendUnicodeRange(value, aResult);
|
||||
} else if (aDescID == eCSSFontDesc_Display) {
|
||||
AppendASCIItoUTF16(nsCSSProps::ValueToKeyword(value.GetIntValue(),
|
||||
nsCSSProps::kFontDisplayKTable),
|
||||
aResult);
|
||||
} else {
|
||||
value.AppendToString(aPropID, aResult, nsCSSValue::eNormalized);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
FontFace::SetUserFontEntry(gfxUserFontEntry* aEntry)
|
||||
{
|
||||
if (mUserFontEntry) {
|
||||
mUserFontEntry->mFontFaces.RemoveElement(this);
|
||||
}
|
||||
|
||||
mUserFontEntry = static_cast<Entry*>(aEntry);
|
||||
if (mUserFontEntry) {
|
||||
mUserFontEntry->mFontFaces.AppendElement(this);
|
||||
|
||||
MOZ_ASSERT(mUserFontEntry->GetUserFontSet() ==
|
||||
mFontFaceSet->GetUserFontSet(),
|
||||
"user font entry must be associated with the same user font set "
|
||||
"as the FontFace");
|
||||
|
||||
// Our newly assigned user font entry might be in the process of or
|
||||
// finished loading, so set our status accordingly. But only do so
|
||||
// if we're not going "backwards" in status, which could otherwise
|
||||
// happen in this case:
|
||||
//
|
||||
// new FontFace("ABC", "url(x)").load();
|
||||
//
|
||||
// where the SetUserFontEntry call (from the after-initialization
|
||||
// DoLoad call) comes after the author's call to load(), which set mStatus
|
||||
// to Loading.
|
||||
FontFaceLoadStatus newStatus =
|
||||
LoadStateToStatus(mUserFontEntry->LoadState());
|
||||
if (newStatus > mStatus) {
|
||||
SetStatus(newStatus);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
FontFace::GetFamilyName(nsString& aResult)
|
||||
{
|
||||
nsCSSValue value;
|
||||
GetDesc(eCSSFontDesc_Family, value);
|
||||
|
||||
if (value.GetUnit() == eCSSUnit_String) {
|
||||
nsString familyname;
|
||||
value.GetStringValue(familyname);
|
||||
aResult.Append(familyname);
|
||||
}
|
||||
|
||||
return !aResult.IsEmpty();
|
||||
}
|
||||
|
||||
void
|
||||
FontFace::DisconnectFromRule()
|
||||
{
|
||||
MOZ_ASSERT(HasRule());
|
||||
|
||||
// Make a copy of the descriptors.
|
||||
mDescriptors = new CSSFontFaceDescriptors;
|
||||
mRule->GetDescriptors(*mDescriptors);
|
||||
mRule = nullptr;
|
||||
mInFontFaceSet = false;
|
||||
}
|
||||
|
||||
bool
|
||||
FontFace::HasFontData() const
|
||||
{
|
||||
return mSourceType == eSourceType_Buffer && mSourceBuffer;
|
||||
}
|
||||
|
||||
void
|
||||
FontFace::TakeBuffer(uint8_t*& aBuffer, uint32_t& aLength)
|
||||
{
|
||||
MOZ_ASSERT(HasFontData());
|
||||
|
||||
aBuffer = mSourceBuffer;
|
||||
aLength = mSourceBufferLength;
|
||||
|
||||
mSourceBuffer = nullptr;
|
||||
mSourceBufferLength = 0;
|
||||
}
|
||||
|
||||
already_AddRefed<gfxFontFaceBufferSource>
|
||||
FontFace::CreateBufferSource()
|
||||
{
|
||||
RefPtr<FontFaceBufferSource> bufferSource = new FontFaceBufferSource(this);
|
||||
return bufferSource.forget();
|
||||
}
|
||||
|
||||
bool
|
||||
FontFace::IsInFontFaceSet(FontFaceSet* aFontFaceSet) const
|
||||
{
|
||||
if (mFontFaceSet == aFontFaceSet) {
|
||||
return mInFontFaceSet;
|
||||
}
|
||||
return mOtherFontFaceSets.Contains(aFontFaceSet);
|
||||
}
|
||||
|
||||
void
|
||||
FontFace::AddFontFaceSet(FontFaceSet* aFontFaceSet)
|
||||
{
|
||||
MOZ_ASSERT(!IsInFontFaceSet(aFontFaceSet));
|
||||
|
||||
if (mFontFaceSet == aFontFaceSet) {
|
||||
mInFontFaceSet = true;
|
||||
} else {
|
||||
mOtherFontFaceSets.AppendElement(aFontFaceSet);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
FontFace::RemoveFontFaceSet(FontFaceSet* aFontFaceSet)
|
||||
{
|
||||
MOZ_ASSERT(IsInFontFaceSet(aFontFaceSet));
|
||||
|
||||
if (mFontFaceSet == aFontFaceSet) {
|
||||
mInFontFaceSet = false;
|
||||
} else {
|
||||
mOtherFontFaceSets.RemoveElement(aFontFaceSet);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
FontFace::Reject(nsresult aResult)
|
||||
{
|
||||
if (mLoaded) {
|
||||
mLoaded->MaybeReject(aResult);
|
||||
} else if (mLoadedRejection == NS_OK) {
|
||||
mLoadedRejection = aResult;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
FontFace::EnsurePromise()
|
||||
{
|
||||
if (mLoaded) {
|
||||
return;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(mParent);
|
||||
|
||||
// If the pref is not set, don't create the Promise (which the page wouldn't
|
||||
// be able to get to anyway) as it causes the window.FontFace constructor
|
||||
// to be created.
|
||||
if (global && FontFaceSet::PrefEnabled()) {
|
||||
ErrorResult rv;
|
||||
mLoaded = Promise::Create(global, rv);
|
||||
|
||||
if (mStatus == FontFaceLoadStatus::Loaded) {
|
||||
mLoaded->MaybeResolve(this);
|
||||
} else if (mLoadedRejection != NS_OK) {
|
||||
mLoaded->MaybeReject(mLoadedRejection);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// -- FontFace::Entry --------------------------------------------------------
|
||||
|
||||
/* virtual */ void
|
||||
FontFace::Entry::SetLoadState(UserFontLoadState aLoadState)
|
||||
{
|
||||
gfxUserFontEntry::SetLoadState(aLoadState);
|
||||
|
||||
for (size_t i = 0; i < mFontFaces.Length(); i++) {
|
||||
mFontFaces[i]->SetStatus(LoadStateToStatus(aLoadState));
|
||||
}
|
||||
}
|
||||
|
||||
/* virtual */ void
|
||||
FontFace::Entry::GetUserFontSets(nsTArray<gfxUserFontSet*>& aResult)
|
||||
{
|
||||
aResult.Clear();
|
||||
|
||||
for (FontFace* f : mFontFaces) {
|
||||
if (f->mInFontFaceSet) {
|
||||
aResult.AppendElement(f->mFontFaceSet->GetUserFontSet());
|
||||
}
|
||||
for (FontFaceSet* s : f->mOtherFontFaceSets) {
|
||||
aResult.AppendElement(s->GetUserFontSet());
|
||||
}
|
||||
}
|
||||
|
||||
// Remove duplicates.
|
||||
aResult.Sort();
|
||||
auto it = std::unique(aResult.begin(), aResult.end());
|
||||
aResult.TruncateLength(it - aResult.begin());
|
||||
}
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
271
layout/style/FontFace.h
Normal file
271
layout/style/FontFace.h
Normal file
|
|
@ -0,0 +1,271 @@
|
|||
/* -*- Mode: C++; 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/. */
|
||||
|
||||
#ifndef mozilla_dom_FontFace_h
|
||||
#define mozilla_dom_FontFace_h
|
||||
|
||||
#include "mozilla/dom/FontFaceBinding.h"
|
||||
#include "gfxUserFontSet.h"
|
||||
#include "nsAutoPtr.h"
|
||||
#include "nsCSSPropertyID.h"
|
||||
#include "nsCSSValue.h"
|
||||
#include "nsWrapperCache.h"
|
||||
|
||||
class gfxFontFaceBufferSource;
|
||||
class nsCSSFontFaceRule;
|
||||
|
||||
namespace mozilla {
|
||||
struct CSSFontFaceDescriptors;
|
||||
namespace dom {
|
||||
class FontFaceBufferSource;
|
||||
struct FontFaceDescriptors;
|
||||
class FontFaceSet;
|
||||
class Promise;
|
||||
class StringOrArrayBufferOrArrayBufferView;
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
class FontFace final : public nsISupports,
|
||||
public nsWrapperCache
|
||||
{
|
||||
friend class mozilla::dom::FontFaceBufferSource;
|
||||
friend class Entry;
|
||||
|
||||
public:
|
||||
class Entry final : public gfxUserFontEntry {
|
||||
friend class FontFace;
|
||||
|
||||
public:
|
||||
Entry(gfxUserFontSet* aFontSet,
|
||||
const nsTArray<gfxFontFaceSrc>& aFontFaceSrcList,
|
||||
uint32_t aWeight,
|
||||
int32_t aStretch,
|
||||
uint8_t aStyle,
|
||||
const nsTArray<gfxFontFeature>& aFeatureSettings,
|
||||
uint32_t aLanguageOverride,
|
||||
gfxSparseBitSet* aUnicodeRanges,
|
||||
uint8_t aFontDisplay)
|
||||
: gfxUserFontEntry(aFontSet, aFontFaceSrcList, aWeight, aStretch,
|
||||
aStyle, aFeatureSettings, aLanguageOverride,
|
||||
aUnicodeRanges, aFontDisplay) {}
|
||||
|
||||
virtual void SetLoadState(UserFontLoadState aLoadState) override;
|
||||
virtual void GetUserFontSets(nsTArray<gfxUserFontSet*>& aResult) override;
|
||||
const AutoTArray<FontFace*,1>& GetFontFaces() { return mFontFaces; }
|
||||
|
||||
protected:
|
||||
// The FontFace objects that use this user font entry. We need to store
|
||||
// an array of these, not just a single pointer, since the user font
|
||||
// cache can return the same entry for different FontFaces that have
|
||||
// the same descriptor values and come from the same origin.
|
||||
AutoTArray<FontFace*,1> mFontFaces;
|
||||
};
|
||||
|
||||
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
|
||||
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(FontFace)
|
||||
|
||||
nsISupports* GetParentObject() const { return mParent; }
|
||||
virtual JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
|
||||
|
||||
static already_AddRefed<FontFace>
|
||||
CreateForRule(nsISupports* aGlobal, FontFaceSet* aFontFaceSet,
|
||||
nsCSSFontFaceRule* aRule);
|
||||
|
||||
nsCSSFontFaceRule* GetRule() { return mRule; }
|
||||
|
||||
void GetDesc(nsCSSFontDesc aDescID, nsCSSValue& aResult) const;
|
||||
|
||||
gfxUserFontEntry* CreateUserFontEntry();
|
||||
gfxUserFontEntry* GetUserFontEntry() const { return mUserFontEntry; }
|
||||
void SetUserFontEntry(gfxUserFontEntry* aEntry);
|
||||
|
||||
/**
|
||||
* Returns whether this object is in the specified FontFaceSet.
|
||||
*/
|
||||
bool IsInFontFaceSet(FontFaceSet* aFontFaceSet) const;
|
||||
|
||||
void AddFontFaceSet(FontFaceSet* aFontFaceSet);
|
||||
void RemoveFontFaceSet(FontFaceSet* aFontFaceSet);
|
||||
|
||||
FontFaceSet* GetPrimaryFontFaceSet() const { return mFontFaceSet; }
|
||||
|
||||
/**
|
||||
* Gets the family name of the FontFace as a raw string (such as 'Times', as
|
||||
* opposed to GetFamily, which returns a CSS-escaped string, such as
|
||||
* '"Times"'). Returns whether a valid family name was available.
|
||||
*/
|
||||
bool GetFamilyName(nsString& aResult);
|
||||
|
||||
/**
|
||||
* Returns whether this object is CSS-connected, i.e. reflecting an
|
||||
* @font-face rule.
|
||||
*/
|
||||
bool HasRule() const { return mRule; }
|
||||
|
||||
/**
|
||||
* Breaks the connection between this FontFace and its @font-face rule.
|
||||
*/
|
||||
void DisconnectFromRule();
|
||||
|
||||
/**
|
||||
* Returns whether there is an ArrayBuffer or ArrayBufferView of font
|
||||
* data.
|
||||
*/
|
||||
bool HasFontData() const;
|
||||
|
||||
/**
|
||||
* Creates a gfxFontFaceBufferSource to represent the font data
|
||||
* in this object.
|
||||
*/
|
||||
already_AddRefed<gfxFontFaceBufferSource> CreateBufferSource();
|
||||
|
||||
/**
|
||||
* Gets a pointer to and the length of the font data stored in the
|
||||
* ArrayBuffer or ArrayBufferView.
|
||||
*/
|
||||
bool GetData(uint8_t*& aBuffer, uint32_t& aLength);
|
||||
|
||||
// Web IDL
|
||||
static already_AddRefed<FontFace>
|
||||
Constructor(const GlobalObject& aGlobal,
|
||||
const nsAString& aFamily,
|
||||
const mozilla::dom::StringOrArrayBufferOrArrayBufferView& aSource,
|
||||
const mozilla::dom::FontFaceDescriptors& aDescriptors,
|
||||
ErrorResult& aRV);
|
||||
|
||||
void GetFamily(nsString& aResult);
|
||||
void SetFamily(const nsAString& aValue, mozilla::ErrorResult& aRv);
|
||||
void GetStyle(nsString& aResult);
|
||||
void SetStyle(const nsAString& aValue, mozilla::ErrorResult& aRv);
|
||||
void GetWeight(nsString& aResult);
|
||||
void SetWeight(const nsAString& aValue, mozilla::ErrorResult& aRv);
|
||||
void GetStretch(nsString& aResult);
|
||||
void SetStretch(const nsAString& aValue, mozilla::ErrorResult& aRv);
|
||||
void GetUnicodeRange(nsString& aResult);
|
||||
void SetUnicodeRange(const nsAString& aValue, mozilla::ErrorResult& aRv);
|
||||
void GetVariant(nsString& aResult);
|
||||
void SetVariant(const nsAString& aValue, mozilla::ErrorResult& aRv);
|
||||
void GetFeatureSettings(nsString& aResult);
|
||||
void SetFeatureSettings(const nsAString& aValue, mozilla::ErrorResult& aRv);
|
||||
void GetDisplay(nsString& aResult);
|
||||
void SetDisplay(const nsAString& aValue, mozilla::ErrorResult& aRv);
|
||||
|
||||
mozilla::dom::FontFaceLoadStatus Status();
|
||||
mozilla::dom::Promise* Load(mozilla::ErrorResult& aRv);
|
||||
mozilla::dom::Promise* GetLoaded(mozilla::ErrorResult& aRv);
|
||||
|
||||
private:
|
||||
FontFace(nsISupports* aParent, FontFaceSet* aFontFaceSet);
|
||||
~FontFace();
|
||||
|
||||
void InitializeSource(const StringOrArrayBufferOrArrayBufferView& aSource);
|
||||
|
||||
// Helper function for Load.
|
||||
void DoLoad();
|
||||
|
||||
/**
|
||||
* Parses a @font-face descriptor value, storing the result in aResult.
|
||||
* Returns whether the parsing was successful.
|
||||
*/
|
||||
bool ParseDescriptor(nsCSSFontDesc aDescID, const nsAString& aString,
|
||||
nsCSSValue& aResult);
|
||||
|
||||
// Helper function for the descriptor setter methods.
|
||||
void SetDescriptor(nsCSSFontDesc aFontDesc,
|
||||
const nsAString& aValue,
|
||||
mozilla::ErrorResult& aRv);
|
||||
|
||||
/**
|
||||
* Sets all of the descriptor values in mDescriptors using values passed
|
||||
* to the JS constructor.
|
||||
*/
|
||||
bool SetDescriptors(const nsAString& aFamily,
|
||||
const FontFaceDescriptors& aDescriptors);
|
||||
|
||||
/**
|
||||
* Sets the current loading status.
|
||||
*/
|
||||
void SetStatus(mozilla::dom::FontFaceLoadStatus aStatus);
|
||||
|
||||
void GetDesc(nsCSSFontDesc aDescID,
|
||||
nsCSSPropertyID aPropID,
|
||||
nsString& aResult) const;
|
||||
|
||||
/**
|
||||
* Returns and takes ownership of the buffer storing the font data.
|
||||
*/
|
||||
void TakeBuffer(uint8_t*& aBuffer, uint32_t& aLength);
|
||||
|
||||
// Acts like mLoaded->MaybeReject(aResult), except it doesn't create mLoaded
|
||||
// if it doesn't already exist.
|
||||
void Reject(nsresult aResult);
|
||||
|
||||
// Creates mLoaded if it doesn't already exist. It may immediately resolve or
|
||||
// reject mLoaded based on mStatus and mLoadedRejection.
|
||||
void EnsurePromise();
|
||||
|
||||
nsCOMPtr<nsISupports> mParent;
|
||||
|
||||
// A Promise that is fulfilled once the font represented by this FontFace is
|
||||
// loaded, and is rejected if the load fails. This promise is created lazily
|
||||
// when JS asks for it.
|
||||
RefPtr<mozilla::dom::Promise> mLoaded;
|
||||
|
||||
// Saves the rejection code for mLoaded if mLoaded hasn't been created yet.
|
||||
nsresult mLoadedRejection;
|
||||
|
||||
// The @font-face rule this FontFace object is reflecting, if it is a
|
||||
// rule backed FontFace.
|
||||
RefPtr<nsCSSFontFaceRule> mRule;
|
||||
|
||||
// The FontFace object's user font entry. This is initially null, but is set
|
||||
// during FontFaceSet::UpdateRules and when a FontFace is explicitly loaded.
|
||||
RefPtr<Entry> mUserFontEntry;
|
||||
|
||||
// The current load status of the font represented by this FontFace.
|
||||
// Note that we can't just reflect the value of the gfxUserFontEntry's
|
||||
// status, since the spec sometimes requires us to go through the event
|
||||
// loop before updating the status, rather than doing it immediately.
|
||||
mozilla::dom::FontFaceLoadStatus mStatus;
|
||||
|
||||
// Represents where a FontFace's data is coming from.
|
||||
enum SourceType {
|
||||
eSourceType_FontFaceRule = 1,
|
||||
eSourceType_URLs,
|
||||
eSourceType_Buffer
|
||||
};
|
||||
|
||||
// Where the font data for this FontFace is coming from.
|
||||
SourceType mSourceType;
|
||||
|
||||
// If the FontFace was constructed with an ArrayBuffer(View), this is a
|
||||
// copy of the data from it.
|
||||
uint8_t* mSourceBuffer;
|
||||
uint32_t mSourceBufferLength;
|
||||
|
||||
// The values corresponding to the font face descriptors, if we are not
|
||||
// a rule backed FontFace object. For rule backed objects, we use
|
||||
// the descriptors stored in mRule.
|
||||
nsAutoPtr<mozilla::CSSFontFaceDescriptors> mDescriptors;
|
||||
|
||||
// The primary FontFaceSet this FontFace is associated with,
|
||||
// regardless of whether it is currently "in" the set.
|
||||
RefPtr<FontFaceSet> mFontFaceSet;
|
||||
|
||||
// Other FontFaceSets (apart from mFontFaceSet) that this FontFace
|
||||
// appears in.
|
||||
nsTArray<RefPtr<FontFaceSet>> mOtherFontFaceSets;
|
||||
|
||||
// Whether this FontFace appears in mFontFaceSet.
|
||||
bool mInFontFaceSet;
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // !defined(mozilla_dom_FontFace_h)
|
||||
1848
layout/style/FontFaceSet.cpp
Normal file
1848
layout/style/FontFaceSet.cpp
Normal file
File diff suppressed because it is too large
Load diff
356
layout/style/FontFaceSet.h
Normal file
356
layout/style/FontFaceSet.h
Normal file
|
|
@ -0,0 +1,356 @@
|
|||
/* -*- Mode: C++; 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/. */
|
||||
|
||||
#ifndef mozilla_dom_FontFaceSet_h
|
||||
#define mozilla_dom_FontFaceSet_h
|
||||
|
||||
#include "mozilla/dom/FontFace.h"
|
||||
#include "mozilla/dom/FontFaceSetBinding.h"
|
||||
#include "mozilla/DOMEventTargetHelper.h"
|
||||
#include "gfxUserFontSet.h"
|
||||
#include "nsCSSRules.h"
|
||||
#include "nsICSSLoaderObserver.h"
|
||||
|
||||
struct gfxFontFaceSrc;
|
||||
class gfxUserFontEntry;
|
||||
class nsFontFaceLoader;
|
||||
class nsIPrincipal;
|
||||
class nsPIDOMWindowInner;
|
||||
|
||||
namespace mozilla {
|
||||
namespace css {
|
||||
class FontFamilyListRefCnt;
|
||||
} // namespace css
|
||||
namespace dom {
|
||||
class FontFace;
|
||||
class Promise;
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
class FontFaceSet final : public DOMEventTargetHelper
|
||||
, public nsIDOMEventListener
|
||||
, public nsICSSLoaderObserver
|
||||
{
|
||||
friend class UserFontSet;
|
||||
|
||||
public:
|
||||
/**
|
||||
* A gfxUserFontSet that integrates with the layout and style systems to
|
||||
* manage @font-face rules and handle network requests for font loading.
|
||||
*
|
||||
* We would combine this class and FontFaceSet into the one class if it were
|
||||
* possible; it's not because FontFaceSet is cycle collected and
|
||||
* gfxUserFontSet isn't (and can't be, as gfx classes don't use the cycle
|
||||
* collector). So UserFontSet exists just to override the needed virtual
|
||||
* methods from gfxUserFontSet and to forward them on FontFaceSet.
|
||||
*/
|
||||
class UserFontSet final : public gfxUserFontSet
|
||||
{
|
||||
friend class FontFaceSet;
|
||||
|
||||
public:
|
||||
explicit UserFontSet(FontFaceSet* aFontFaceSet)
|
||||
: mFontFaceSet(aFontFaceSet)
|
||||
{
|
||||
}
|
||||
|
||||
FontFaceSet* GetFontFaceSet() { return mFontFaceSet; }
|
||||
|
||||
virtual nsresult CheckFontLoad(const gfxFontFaceSrc* aFontFaceSrc,
|
||||
nsIPrincipal** aPrincipal,
|
||||
bool* aBypassCache) override;
|
||||
|
||||
virtual bool IsFontLoadAllowed(nsIURI* aFontLocation,
|
||||
nsIPrincipal* aPrincipal) override;
|
||||
|
||||
virtual nsresult StartLoad(gfxUserFontEntry* aUserFontEntry,
|
||||
const gfxFontFaceSrc* aFontFaceSrc) override;
|
||||
|
||||
void RecordFontLoadDone(uint32_t aFontSize,
|
||||
mozilla::TimeStamp aDoneTime) override;
|
||||
|
||||
protected:
|
||||
virtual bool GetPrivateBrowsing() override;
|
||||
virtual nsresult SyncLoadFontData(gfxUserFontEntry* aFontToLoad,
|
||||
const gfxFontFaceSrc* aFontFaceSrc,
|
||||
uint8_t*& aBuffer,
|
||||
uint32_t& aBufferLength) override;
|
||||
virtual nsresult LogMessage(gfxUserFontEntry* aUserFontEntry,
|
||||
const char* aMessage,
|
||||
uint32_t aFlags = nsIScriptError::errorFlag,
|
||||
nsresult aStatus = NS_OK) override;
|
||||
virtual void DoRebuildUserFontSet() override;
|
||||
virtual already_AddRefed<gfxUserFontEntry> CreateUserFontEntry(
|
||||
const nsTArray<gfxFontFaceSrc>& aFontFaceSrcList,
|
||||
uint32_t aWeight,
|
||||
int32_t aStretch,
|
||||
uint8_t aStyle,
|
||||
const nsTArray<gfxFontFeature>& aFeatureSettings,
|
||||
uint32_t aLanguageOverride,
|
||||
gfxSparseBitSet* aUnicodeRanges,
|
||||
uint8_t aFontDisplay) override;
|
||||
|
||||
private:
|
||||
RefPtr<FontFaceSet> mFontFaceSet;
|
||||
};
|
||||
|
||||
NS_DECL_ISUPPORTS_INHERITED
|
||||
NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(FontFaceSet, DOMEventTargetHelper)
|
||||
NS_DECL_NSIDOMEVENTLISTENER
|
||||
|
||||
FontFaceSet(nsPIDOMWindowInner* aWindow, nsIDocument* aDocument);
|
||||
|
||||
virtual JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
|
||||
|
||||
UserFontSet* GetUserFontSet() { return mUserFontSet; }
|
||||
|
||||
// Called by nsFontFaceLoader when the loader has completed normally.
|
||||
// It's removed from the mLoaders set.
|
||||
void RemoveLoader(nsFontFaceLoader* aLoader);
|
||||
|
||||
bool UpdateRules(const nsTArray<nsFontFaceRuleContainer>& aRules);
|
||||
|
||||
nsPresContext* GetPresContext();
|
||||
|
||||
// search for @font-face rule that matches a platform font entry
|
||||
nsCSSFontFaceRule* FindRuleForEntry(gfxFontEntry* aFontEntry);
|
||||
|
||||
void IncrementGeneration(bool aIsRebuild = false);
|
||||
|
||||
/**
|
||||
* Finds an existing entry in the user font cache or creates a new user
|
||||
* font entry for the given FontFace object.
|
||||
*/
|
||||
static already_AddRefed<gfxUserFontEntry>
|
||||
FindOrCreateUserFontEntryFromFontFace(FontFace* aFontFace);
|
||||
|
||||
/**
|
||||
* Notification method called by a FontFace to indicate that its loading
|
||||
* status has changed.
|
||||
*/
|
||||
void OnFontFaceStatusChanged(FontFace* aFontFace);
|
||||
|
||||
/**
|
||||
* Notification method called by the nsPresContext to indicate that the
|
||||
* refresh driver ticked and flushed style and layout.
|
||||
* were just flushed.
|
||||
*/
|
||||
void DidRefresh();
|
||||
|
||||
/**
|
||||
* Returns whether the "layout.css.font-loading-api.enabled" pref is true.
|
||||
*/
|
||||
static bool PrefEnabled();
|
||||
|
||||
// nsICSSLoaderObserver
|
||||
NS_IMETHOD StyleSheetLoaded(mozilla::StyleSheet* aSheet,
|
||||
bool aWasAlternate,
|
||||
nsresult aStatus) override;
|
||||
|
||||
FontFace* GetFontFaceAt(uint32_t aIndex);
|
||||
|
||||
void FlushUserFontSet();
|
||||
|
||||
static nsPresContext* GetPresContextFor(gfxUserFontSet* aUserFontSet)
|
||||
{
|
||||
FontFaceSet* set = static_cast<UserFontSet*>(aUserFontSet)->mFontFaceSet;
|
||||
return set ? set->GetPresContext() : nullptr;
|
||||
}
|
||||
|
||||
// -- Web IDL --------------------------------------------------------------
|
||||
|
||||
IMPL_EVENT_HANDLER(loading)
|
||||
IMPL_EVENT_HANDLER(loadingdone)
|
||||
IMPL_EVENT_HANDLER(loadingerror)
|
||||
already_AddRefed<mozilla::dom::Promise> Load(JSContext* aCx,
|
||||
const nsAString& aFont,
|
||||
const nsAString& aText,
|
||||
mozilla::ErrorResult& aRv);
|
||||
bool Check(const nsAString& aFont,
|
||||
const nsAString& aText,
|
||||
mozilla::ErrorResult& aRv);
|
||||
mozilla::dom::Promise* GetReady(mozilla::ErrorResult& aRv);
|
||||
mozilla::dom::FontFaceSetLoadStatus Status();
|
||||
|
||||
FontFaceSet* Add(FontFace& aFontFace, mozilla::ErrorResult& aRv);
|
||||
void Clear();
|
||||
bool Delete(FontFace& aFontFace);
|
||||
bool Has(FontFace& aFontFace);
|
||||
uint32_t Size();
|
||||
already_AddRefed<mozilla::dom::FontFaceSetIterator> Entries();
|
||||
already_AddRefed<mozilla::dom::FontFaceSetIterator> Values();
|
||||
void ForEach(JSContext* aCx, FontFaceSetForEachCallback& aCallback,
|
||||
JS::Handle<JS::Value> aThisArg,
|
||||
mozilla::ErrorResult& aRv);
|
||||
|
||||
private:
|
||||
~FontFaceSet();
|
||||
|
||||
/**
|
||||
* Returns whether the given FontFace is currently "in" the FontFaceSet.
|
||||
*/
|
||||
bool HasAvailableFontFace(FontFace* aFontFace);
|
||||
|
||||
/**
|
||||
* Removes any listeners and observers.
|
||||
*/
|
||||
void Disconnect();
|
||||
|
||||
void RemoveDOMContentLoadedListener();
|
||||
|
||||
/**
|
||||
* Returns whether there might be any pending font loads, which should cause
|
||||
* the mReady Promise not to be resolved yet.
|
||||
*/
|
||||
bool MightHavePendingFontLoads();
|
||||
|
||||
/**
|
||||
* Checks to see whether it is time to replace mReady and dispatch a
|
||||
* "loading" event.
|
||||
*/
|
||||
void CheckLoadingStarted();
|
||||
|
||||
/**
|
||||
* Checks to see whether it is time to resolve mReady and dispatch any
|
||||
* "loadingdone" and "loadingerror" events.
|
||||
*/
|
||||
void CheckLoadingFinished();
|
||||
|
||||
/**
|
||||
* Callback for invoking CheckLoadingFinished after going through the
|
||||
* event loop. See OnFontFaceStatusChanged.
|
||||
*/
|
||||
void CheckLoadingFinishedAfterDelay();
|
||||
|
||||
/**
|
||||
* Dispatches a FontFaceSetLoadEvent to this object.
|
||||
*/
|
||||
void DispatchLoadingFinishedEvent(
|
||||
const nsAString& aType,
|
||||
const nsTArray<FontFace*>& aFontFaces);
|
||||
|
||||
// Note: if you add new cycle collected objects to FontFaceRecord,
|
||||
// make sure to update FontFaceSet's cycle collection macros
|
||||
// accordingly.
|
||||
struct FontFaceRecord {
|
||||
RefPtr<FontFace> mFontFace;
|
||||
SheetType mSheetType; // only relevant for mRuleFaces entries
|
||||
|
||||
// When true, indicates that when finished loading, the FontFace should be
|
||||
// included in the subsequent loadingdone/loadingerror event fired at the
|
||||
// FontFaceSet.
|
||||
bool mLoadEventShouldFire;
|
||||
};
|
||||
|
||||
static already_AddRefed<gfxUserFontEntry> FindOrCreateUserFontEntryFromFontFace(
|
||||
const nsAString& aFamilyName,
|
||||
FontFace* aFontFace,
|
||||
SheetType aSheetType);
|
||||
|
||||
// search for @font-face rule that matches a userfont font entry
|
||||
nsCSSFontFaceRule* FindRuleForUserFontEntry(gfxUserFontEntry* aUserFontEntry);
|
||||
|
||||
nsresult StartLoad(gfxUserFontEntry* aUserFontEntry,
|
||||
const gfxFontFaceSrc* aFontFaceSrc);
|
||||
nsresult CheckFontLoad(const gfxFontFaceSrc* aFontFaceSrc,
|
||||
nsIPrincipal** aPrincipal,
|
||||
bool* aBypassCache);
|
||||
bool IsFontLoadAllowed(nsIURI* aFontLocation, nsIPrincipal* aPrincipal);
|
||||
bool GetPrivateBrowsing();
|
||||
nsresult SyncLoadFontData(gfxUserFontEntry* aFontToLoad,
|
||||
const gfxFontFaceSrc* aFontFaceSrc,
|
||||
uint8_t*& aBuffer,
|
||||
uint32_t& aBufferLength);
|
||||
nsresult LogMessage(gfxUserFontEntry* aUserFontEntry,
|
||||
const char* aMessage,
|
||||
uint32_t aFlags,
|
||||
nsresult aStatus);
|
||||
void RebuildUserFontSet();
|
||||
|
||||
void InsertRuleFontFace(FontFace* aFontFace, SheetType aSheetType,
|
||||
nsTArray<FontFaceRecord>& aOldRecords,
|
||||
bool& aFontSetModified);
|
||||
void InsertNonRuleFontFace(FontFace* aFontFace, bool& aFontSetModified);
|
||||
|
||||
#ifdef DEBUG
|
||||
bool HasRuleFontFace(FontFace* aFontFace);
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Returns whether we have any loading FontFace objects in the FontFaceSet.
|
||||
*/
|
||||
bool HasLoadingFontFaces();
|
||||
|
||||
// Helper function for HasLoadingFontFaces.
|
||||
void UpdateHasLoadingFontFaces();
|
||||
|
||||
void ParseFontShorthandForMatching(
|
||||
const nsAString& aFont,
|
||||
RefPtr<mozilla::css::FontFamilyListRefCnt>& aFamilyList,
|
||||
uint32_t& aWeight,
|
||||
int32_t& aStretch,
|
||||
uint8_t& aStyle,
|
||||
ErrorResult& aRv);
|
||||
void FindMatchingFontFaces(const nsAString& aFont,
|
||||
const nsAString& aText,
|
||||
nsTArray<FontFace*>& aFontFaces,
|
||||
mozilla::ErrorResult& aRv);
|
||||
|
||||
TimeStamp GetNavigationStartTimeStamp();
|
||||
|
||||
RefPtr<UserFontSet> mUserFontSet;
|
||||
|
||||
// The document this is a FontFaceSet for.
|
||||
nsCOMPtr<nsIDocument> mDocument;
|
||||
|
||||
// A Promise that is fulfilled once all of the FontFace objects
|
||||
// in mRuleFaces and mNonRuleFaces that started or were loading at the
|
||||
// time the Promise was created have finished loading. It is rejected if
|
||||
// any of those fonts failed to load. mReady is replaced with
|
||||
// a new Promise object whenever mReady is settled and another
|
||||
// FontFace in mRuleFaces or mNonRuleFaces starts to load.
|
||||
// Note that mReady is created lazily when GetReady() is called.
|
||||
RefPtr<mozilla::dom::Promise> mReady;
|
||||
// Whether the ready promise must be resolved when it's created.
|
||||
bool mResolveLazilyCreatedReadyPromise;
|
||||
|
||||
// Set of all loaders pointing to us. These are not strong pointers,
|
||||
// but that's OK because nsFontFaceLoader always calls RemoveLoader on
|
||||
// us before it dies (unless we die first).
|
||||
nsTHashtable< nsPtrHashKey<nsFontFaceLoader> > mLoaders;
|
||||
|
||||
// The @font-face rule backed FontFace objects in the FontFaceSet.
|
||||
nsTArray<FontFaceRecord> mRuleFaces;
|
||||
|
||||
// The non rule backed FontFace objects that have been added to this
|
||||
// FontFaceSet.
|
||||
nsTArray<FontFaceRecord> mNonRuleFaces;
|
||||
|
||||
// The overall status of the loading or loaded fonts in the FontFaceSet.
|
||||
mozilla::dom::FontFaceSetLoadStatus mStatus;
|
||||
|
||||
// Whether mNonRuleFaces has changed since last time UpdateRules ran.
|
||||
bool mNonRuleFacesDirty;
|
||||
|
||||
// Whether any FontFace objects in mRuleFaces or mNonRuleFaces are
|
||||
// loading. Only valid when mHasLoadingFontFacesIsDirty is false. Don't use
|
||||
// this variable directly; call the HasLoadingFontFaces method instead.
|
||||
bool mHasLoadingFontFaces;
|
||||
|
||||
// This variable is only valid when mLoadingDirty is false.
|
||||
bool mHasLoadingFontFacesIsDirty;
|
||||
|
||||
// Whether CheckLoadingFinished calls should be ignored. See comment in
|
||||
// OnFontFaceStatusChanged.
|
||||
bool mDelayedLoadCheck;
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // !defined(mozilla_dom_FontFaceSet_h)
|
||||
80
layout/style/FontFaceSetIterator.cpp
Normal file
80
layout/style/FontFaceSetIterator.cpp
Normal file
|
|
@ -0,0 +1,80 @@
|
|||
/* -*- Mode: C++; 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/. */
|
||||
|
||||
#include "mozilla/dom/FontFaceSetIterator.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION(FontFaceSetIterator, mFontFaceSet)
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(FontFaceSetIterator, AddRef)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(FontFaceSetIterator, Release)
|
||||
|
||||
FontFaceSetIterator::FontFaceSetIterator(FontFaceSet* aFontFaceSet,
|
||||
bool aIsKeyAndValue)
|
||||
: mFontFaceSet(aFontFaceSet)
|
||||
, mNextIndex(0)
|
||||
, mIsKeyAndValue(aIsKeyAndValue)
|
||||
{
|
||||
MOZ_COUNT_CTOR(FontFaceSetIterator);
|
||||
}
|
||||
|
||||
FontFaceSetIterator::~FontFaceSetIterator()
|
||||
{
|
||||
MOZ_COUNT_DTOR(FontFaceSetIterator);
|
||||
}
|
||||
|
||||
bool
|
||||
FontFaceSetIterator::WrapObject(JSContext* aCx,
|
||||
JS::Handle<JSObject*> aGivenProto,
|
||||
JS::MutableHandle<JSObject*> aReflector)
|
||||
{
|
||||
return FontFaceSetIteratorBinding::Wrap(aCx, this, aGivenProto, aReflector);
|
||||
}
|
||||
|
||||
void
|
||||
FontFaceSetIterator::Next(JSContext* aCx, FontFaceSetIteratorResult& aResult,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
if (!mFontFaceSet) {
|
||||
aResult.mDone = true;
|
||||
return;
|
||||
}
|
||||
|
||||
FontFace* face = mFontFaceSet->GetFontFaceAt(mNextIndex++);
|
||||
|
||||
if (!face) {
|
||||
aResult.mValue.setUndefined();
|
||||
aResult.mDone = true;
|
||||
mFontFaceSet = nullptr;
|
||||
return;
|
||||
}
|
||||
|
||||
JS::Rooted<JS::Value> value(aCx);
|
||||
if (!ToJSValue(aCx, face, &value)) {
|
||||
aRv.Throw(NS_ERROR_FAILURE);
|
||||
return;
|
||||
}
|
||||
|
||||
if (mIsKeyAndValue) {
|
||||
JS::AutoValueArray<2> values(aCx);
|
||||
values[0].set(value);
|
||||
values[1].set(value);
|
||||
|
||||
JS::Rooted<JSObject*> array(aCx);
|
||||
array = JS_NewArrayObject(aCx, values);
|
||||
if (array) {
|
||||
aResult.mValue.setObject(*array);
|
||||
}
|
||||
} else {
|
||||
aResult.mValue = value;
|
||||
}
|
||||
|
||||
aResult.mDone = false;
|
||||
}
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
44
layout/style/FontFaceSetIterator.h
Normal file
44
layout/style/FontFaceSetIterator.h
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
/* -*- Mode: C++; 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/. */
|
||||
|
||||
#ifndef mozilla_dom_FontFaceSetIterator_h
|
||||
#define mozilla_dom_FontFaceSetIterator_h
|
||||
|
||||
#include "mozilla/dom/FontFaceSet.h"
|
||||
#include "mozilla/dom/FontFaceSetBinding.h"
|
||||
#include "mozilla/dom/NonRefcountedDOMObject.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
class FontFaceSetIterator final
|
||||
{
|
||||
public:
|
||||
FontFaceSetIterator(mozilla::dom::FontFaceSet* aFontFaceSet,
|
||||
bool aIsKeyAndValue);
|
||||
|
||||
NS_DECL_CYCLE_COLLECTION_NATIVE_CLASS(FontFaceSetIterator)
|
||||
NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(FontFaceSetIterator)
|
||||
|
||||
bool WrapObject(JSContext* aCx,
|
||||
JS::Handle<JSObject*> aGivenProto,
|
||||
JS::MutableHandle<JSObject*> aReflector);
|
||||
|
||||
// WebIDL
|
||||
void Next(JSContext* aCx, FontFaceSetIteratorResult& aResult,
|
||||
mozilla::ErrorResult& aRv);
|
||||
|
||||
private:
|
||||
~FontFaceSetIterator();
|
||||
|
||||
RefPtr<FontFaceSet> mFontFaceSet;
|
||||
uint32_t mNextIndex;
|
||||
bool mIsKeyAndValue;
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // !defined(mozilla_dom_FontFaceSetIterator_h)
|
||||
104
layout/style/GenerateCSSPropsGenerated.py
Normal file
104
layout/style/GenerateCSSPropsGenerated.py
Normal file
|
|
@ -0,0 +1,104 @@
|
|||
# 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/.
|
||||
|
||||
import sys
|
||||
import string
|
||||
import argparse
|
||||
import subprocess
|
||||
import buildconfig
|
||||
from mozbuild import shellutil
|
||||
|
||||
def get_properties(preprocessorHeader):
|
||||
cpp = list(buildconfig.substs['CPP'])
|
||||
cpp += shellutil.split(buildconfig.substs['ACDEFINES'])
|
||||
cpp.append(preprocessorHeader)
|
||||
preprocessed = subprocess.check_output(cpp)
|
||||
properties = [{"name":p[0], "prop":p[1], "id":p[2],
|
||||
"flags":p[3], "pref":p[4], "proptype":p[5]}
|
||||
for (i, p) in enumerate(eval(preprocessed))]
|
||||
|
||||
# Sort the list so that longhand and logical properties are intermingled
|
||||
# first, shorthand properties follow, then aliases appear last. This matches
|
||||
# the order of the nsCSSPropertyID enum.
|
||||
|
||||
def property_compare(x, y):
|
||||
property_order = {"longhand": 0, "logical": 0, "shorthand": 1, "alias": 2}
|
||||
return property_order[x["proptype"]] - property_order[y["proptype"]]
|
||||
|
||||
properties = sorted(properties, cmp=property_compare)
|
||||
|
||||
for i, p in enumerate(properties):
|
||||
p["index"] = i
|
||||
|
||||
# Record each property's IDL name.
|
||||
for p in properties:
|
||||
if "CSS_PROPERTY_INTERNAL" in p["flags"]:
|
||||
p["idlname"] = None
|
||||
else:
|
||||
idl_name = p["prop"]
|
||||
if not idl_name.startswith("Moz"):
|
||||
idl_name = idl_name[0].lower() + idl_name[1:]
|
||||
p["idlname"] = idl_name
|
||||
|
||||
return properties
|
||||
|
||||
def generate_idl_names(properties):
|
||||
names = []
|
||||
for p in properties:
|
||||
if p["proptype"] is "alias":
|
||||
continue
|
||||
if p["idlname"] is None:
|
||||
names.append(" nullptr, // %s" % p["name"])
|
||||
else:
|
||||
names.append(' "%s",' % p["idlname"])
|
||||
return "\n".join(names)
|
||||
|
||||
def generate_assertions(properties):
|
||||
def enum(p):
|
||||
if p["proptype"] is "alias":
|
||||
return "eCSSPropertyAlias_%s" % p["prop"]
|
||||
else:
|
||||
return "eCSSProperty_%s" % p["id"]
|
||||
msg = ('static_assert(%s == %d, "GenerateCSSPropsGenerated.py did not list '
|
||||
'properties in nsCSSPropertyID order");')
|
||||
return "\n".join(map(lambda p: msg % (enum(p), p["index"]), properties))
|
||||
|
||||
def generate_idl_name_positions(properties):
|
||||
# Skip aliases.
|
||||
ps = filter(lambda p: p["proptype"] is not "alias", properties)
|
||||
|
||||
# Sort alphabetically by IDL name.
|
||||
ps = sorted(ps, key=lambda p: p["idlname"])
|
||||
|
||||
# Annotate entries with the sorted position.
|
||||
ps = [(p, position) for position, p in enumerate(ps)]
|
||||
|
||||
# Sort back to nsCSSPropertyID order.
|
||||
ps = sorted(ps, key=lambda (p, position): p["index"])
|
||||
|
||||
return ",\n".join(map(lambda (p, position): " %d" % position, ps))
|
||||
|
||||
def generate(output, cppTemplate, preprocessorHeader):
|
||||
cppFile = open(cppTemplate, "r")
|
||||
cppTemplate = cppFile.read()
|
||||
cppFile.close()
|
||||
|
||||
properties = get_properties(preprocessorHeader)
|
||||
substitutions = {
|
||||
"idl_names": generate_idl_names(properties),
|
||||
"assertions": generate_assertions(properties),
|
||||
"idl_name_positions": generate_idl_name_positions(properties),
|
||||
}
|
||||
output.write("/* THIS IS AN AUTOGENERATED FILE. DO NOT EDIT */\n\n" +
|
||||
string.Template(cppTemplate).substitute(substitutions) + "\n")
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument('cppTemplate', help='CSS property file template')
|
||||
parser.add_argument('preprocessorHeader', help='Header file to pass through the preprocessor')
|
||||
args = parser.parse_args()
|
||||
generate(sys.stdout, args.cppTemplate, args.preprocessorHeader)
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
101
layout/style/GroupRule.h
Normal file
101
layout/style/GroupRule.h
Normal file
|
|
@ -0,0 +1,101 @@
|
|||
/* -*- Mode: C++; 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/. */
|
||||
|
||||
/*
|
||||
* internal interface representing CSS style rules that contain other
|
||||
* rules, such as @media rules
|
||||
*/
|
||||
|
||||
#ifndef mozilla_css_GroupRule_h__
|
||||
#define mozilla_css_GroupRule_h__
|
||||
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "mozilla/IncrementalClearCOMRuleArray.h"
|
||||
#include "mozilla/MemoryReporting.h"
|
||||
#include "mozilla/css/Rule.h"
|
||||
#include "nsCycleCollectionParticipant.h"
|
||||
|
||||
class nsPresContext;
|
||||
class nsMediaQueryResultCacheKey;
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
class CSSStyleSheet;
|
||||
|
||||
namespace css {
|
||||
|
||||
class GroupRuleRuleList;
|
||||
|
||||
// inherits from Rule so it can be shared between
|
||||
// MediaRule and DocumentRule
|
||||
class GroupRule : public Rule
|
||||
{
|
||||
protected:
|
||||
GroupRule(uint32_t aLineNumber, uint32_t aColumnNumber);
|
||||
GroupRule(const GroupRule& aCopy);
|
||||
virtual ~GroupRule();
|
||||
public:
|
||||
|
||||
NS_DECL_CYCLE_COLLECTION_CLASS(GroupRule)
|
||||
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
|
||||
|
||||
// implement part of Rule
|
||||
DECL_STYLE_RULE_INHERIT_NO_DOMRULE
|
||||
#ifdef DEBUG
|
||||
virtual void List(FILE* out = stdout, int32_t aIndent = 0) const override;
|
||||
#endif
|
||||
virtual void SetStyleSheet(CSSStyleSheet* aSheet) override;
|
||||
|
||||
public:
|
||||
void AppendStyleRule(Rule* aRule);
|
||||
|
||||
int32_t StyleRuleCount() const { return mRules.Count(); }
|
||||
Rule* GetStyleRuleAt(int32_t aIndex) const;
|
||||
|
||||
typedef IncrementalClearCOMRuleArray::nsCOMArrayEnumFunc RuleEnumFunc;
|
||||
bool EnumerateRulesForwards(RuleEnumFunc aFunc, void * aData) const;
|
||||
|
||||
/*
|
||||
* The next three methods should never be called unless you have first
|
||||
* called WillDirty() on the parent stylesheet. After they are
|
||||
* called, DidDirty() needs to be called on the sheet.
|
||||
*/
|
||||
nsresult DeleteStyleRuleAt(uint32_t aIndex);
|
||||
nsresult InsertStyleRuleAt(uint32_t aIndex, Rule* aRule);
|
||||
|
||||
virtual bool UseForPresentation(nsPresContext* aPresContext,
|
||||
nsMediaQueryResultCacheKey& aKey) = 0;
|
||||
|
||||
// non-virtual -- it is only called by subclasses
|
||||
size_t SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) const;
|
||||
virtual size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const override = 0;
|
||||
|
||||
static bool
|
||||
CloneRuleInto(Rule* aRule, void* aArray)
|
||||
{
|
||||
RefPtr<Rule> clone = aRule->Clone();
|
||||
static_cast<IncrementalClearCOMRuleArray*>(aArray)->AppendObject(clone);
|
||||
return true;
|
||||
}
|
||||
|
||||
protected:
|
||||
// to help implement nsIDOMCSSRule
|
||||
void AppendRulesToCssText(nsAString& aCssText);
|
||||
|
||||
// to implement common methods on nsIDOMCSSMediaRule and
|
||||
// nsIDOMCSSMozDocumentRule
|
||||
nsresult GetCssRules(nsIDOMCSSRuleList* *aRuleList);
|
||||
nsresult InsertRule(const nsAString & aRule, uint32_t aIndex,
|
||||
uint32_t* _retval);
|
||||
nsresult DeleteRule(uint32_t aIndex);
|
||||
|
||||
IncrementalClearCOMRuleArray mRules;
|
||||
RefPtr<GroupRuleRuleList> mRuleCollection; // lazily constructed
|
||||
};
|
||||
|
||||
} // namespace css
|
||||
} // namespace mozilla
|
||||
|
||||
#endif /* mozilla_css_GroupRule_h__ */
|
||||
133
layout/style/HandleRefPtr.h
Normal file
133
layout/style/HandleRefPtr.h
Normal file
|
|
@ -0,0 +1,133 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
* vim: set ts=2 sw=2 et tw=78:
|
||||
* 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/.
|
||||
*/
|
||||
|
||||
/* smart pointer for strong references to objects through pointer-like
|
||||
* "handle" objects */
|
||||
|
||||
#include <algorithm>
|
||||
#include "mozilla/Assertions.h"
|
||||
|
||||
#ifndef mozilla_HandleRefPtr_h
|
||||
#define mozilla_HandleRefPtr_h
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
/**
|
||||
* A class for holding strong references to handle-managed objects.
|
||||
*
|
||||
* This is intended for use with objects like RestyleManagerHandle,
|
||||
* where the handle type is not a pointer but which can still have
|
||||
* ->AddRef() and ->Release() called on it.
|
||||
*/
|
||||
template<typename T>
|
||||
class HandleRefPtr
|
||||
{
|
||||
public:
|
||||
HandleRefPtr() {}
|
||||
|
||||
HandleRefPtr(HandleRefPtr<T>& aRhs)
|
||||
{
|
||||
assign(aRhs.mHandle);
|
||||
}
|
||||
|
||||
HandleRefPtr(HandleRefPtr<T>&& aRhs)
|
||||
{
|
||||
std::swap(mHandle, aRhs.mHandle);
|
||||
}
|
||||
|
||||
MOZ_IMPLICIT HandleRefPtr(T aRhs)
|
||||
{
|
||||
assign(aRhs);
|
||||
}
|
||||
|
||||
HandleRefPtr<T>& operator=(HandleRefPtr<T>& aRhs)
|
||||
{
|
||||
assign(aRhs.mHandle);
|
||||
return *this;
|
||||
}
|
||||
|
||||
HandleRefPtr<T>& operator=(T aRhs)
|
||||
{
|
||||
assign(aRhs);
|
||||
return *this;
|
||||
}
|
||||
|
||||
~HandleRefPtr() { assign(nullptr); }
|
||||
|
||||
explicit operator bool() const { return !!mHandle; }
|
||||
bool operator!() const { return !mHandle; }
|
||||
|
||||
operator T() const { return mHandle; }
|
||||
T operator->() const { return mHandle; }
|
||||
|
||||
void swap(HandleRefPtr<T>& aOther)
|
||||
{
|
||||
std::swap(mHandle, aOther.mHandle);
|
||||
}
|
||||
|
||||
private:
|
||||
void assign(T aPtr)
|
||||
{
|
||||
// AddRef early so |aPtr| can't disappear underneath us.
|
||||
if (aPtr) {
|
||||
aPtr->AddRef();
|
||||
}
|
||||
|
||||
// Don't release |mHandle| yet: if |mHandle| indirectly owns |this|,
|
||||
// releasing would invalidate |this|. Swap |aPtr| for |mHandle| so that
|
||||
// |aPtr| lives as long as |this|, then release the new |aPtr| (really the
|
||||
// original |mHandle|) so that if |this| is invalidated, we're not using it
|
||||
// any more.
|
||||
std::swap(mHandle, aPtr);
|
||||
|
||||
if (aPtr) {
|
||||
aPtr->Release();
|
||||
}
|
||||
}
|
||||
|
||||
T mHandle;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
inline bool operator==(const HandleRefPtr<T>& aLHS, const HandleRefPtr<T>& aRHS)
|
||||
{
|
||||
return static_cast<T>(aLHS) == static_cast<T>(aRHS);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline bool operator==(const HandleRefPtr<T>& aLHS, T aRHS)
|
||||
{
|
||||
return static_cast<T>(aLHS) == aRHS;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline bool operator==(T aLHS, const HandleRefPtr<T>& aRHS)
|
||||
{
|
||||
return aLHS == static_cast<T>(aRHS);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline bool operator!=(const HandleRefPtr<T>& aLHS, const HandleRefPtr<T>& aRHS)
|
||||
{
|
||||
return !(aLHS == aRHS);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline bool operator!=(const HandleRefPtr<T>& aLHS, T aRHS)
|
||||
{
|
||||
return !(aLHS == aRHS);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline bool operator!=(T aLHS, const HandleRefPtr<T>& aRHS)
|
||||
{
|
||||
return !(aLHS == aRHS);
|
||||
}
|
||||
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // mozilla_HandleRefPtr_h
|
||||
31
layout/style/ImageDocument.css
Normal file
31
layout/style/ImageDocument.css
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
/* -*- Mode: C++; 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/. */
|
||||
|
||||
/*
|
||||
* This CSS stylesheet defines the rules to be applied to any ImageDocuments,
|
||||
* including those in frames.
|
||||
*/
|
||||
|
||||
@media not print {
|
||||
.overflowingVertical, .overflowingHorizontalOnly {
|
||||
cursor: zoom-out;
|
||||
}
|
||||
|
||||
.shrinkToFit {
|
||||
cursor: zoom-in;
|
||||
}
|
||||
}
|
||||
|
||||
@media print {
|
||||
/* We must declare the image as a block element. If we stay as
|
||||
an inline element, our parent LineBox will be inline too and
|
||||
ignore the available height during reflow.
|
||||
This is bad during printing, it means tall image frames won't know
|
||||
the size of the paper and cannot break into continuations along
|
||||
multiple pages. */
|
||||
img {
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
529
layout/style/ImageLoader.cpp
Normal file
529
layout/style/ImageLoader.cpp
Normal file
|
|
@ -0,0 +1,529 @@
|
|||
/* 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/. */
|
||||
|
||||
/* A class that handles style system image loads (other image loads are handled
|
||||
* by the nodes in the content tree).
|
||||
*/
|
||||
|
||||
#include "mozilla/css/ImageLoader.h"
|
||||
#include "nsAutoPtr.h"
|
||||
#include "nsContentUtils.h"
|
||||
#include "nsLayoutUtils.h"
|
||||
#include "nsError.h"
|
||||
#include "nsDisplayList.h"
|
||||
#include "FrameLayerBuilder.h"
|
||||
#include "nsSVGEffects.h"
|
||||
#include "imgIContainer.h"
|
||||
#include "Image.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace css {
|
||||
|
||||
void
|
||||
ImageLoader::DropDocumentReference()
|
||||
{
|
||||
// It's okay if GetPresContext returns null here (due to the presshell pointer
|
||||
// on the document being null) as that means the presshell has already
|
||||
// been destroyed, and it also calls ClearFrames when it is destroyed.
|
||||
ClearFrames(GetPresContext());
|
||||
|
||||
for (auto it = mImages.Iter(); !it.Done(); it.Next()) {
|
||||
ImageLoader::Image* image = it.Get()->GetKey();
|
||||
imgIRequest* request = image->mRequests.GetWeak(mDocument);
|
||||
if (request) {
|
||||
request->CancelAndForgetObserver(NS_BINDING_ABORTED);
|
||||
}
|
||||
image->mRequests.Remove(mDocument);
|
||||
}
|
||||
mImages.Clear();
|
||||
|
||||
mDocument = nullptr;
|
||||
}
|
||||
|
||||
void
|
||||
ImageLoader::AssociateRequestToFrame(imgIRequest* aRequest,
|
||||
nsIFrame* aFrame)
|
||||
{
|
||||
nsCOMPtr<imgINotificationObserver> observer;
|
||||
aRequest->GetNotificationObserver(getter_AddRefs(observer));
|
||||
if (!observer) {
|
||||
// The request has already been canceled, so ignore it. This is ok because
|
||||
// we're not going to get any more notifications from a canceled request.
|
||||
return;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(observer == this);
|
||||
|
||||
FrameSet* frameSet = nullptr;
|
||||
if (mRequestToFrameMap.Get(aRequest, &frameSet)) {
|
||||
NS_ASSERTION(frameSet, "This should never be null!");
|
||||
}
|
||||
|
||||
if (!frameSet) {
|
||||
nsAutoPtr<FrameSet> newFrameSet(new FrameSet());
|
||||
|
||||
mRequestToFrameMap.Put(aRequest, newFrameSet);
|
||||
frameSet = newFrameSet.forget();
|
||||
|
||||
nsPresContext* presContext = GetPresContext();
|
||||
if (presContext) {
|
||||
nsLayoutUtils::RegisterImageRequestIfAnimated(presContext,
|
||||
aRequest,
|
||||
nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
RequestSet* requestSet = nullptr;
|
||||
if (mFrameToRequestMap.Get(aFrame, &requestSet)) {
|
||||
NS_ASSERTION(requestSet, "This should never be null");
|
||||
}
|
||||
|
||||
if (!requestSet) {
|
||||
nsAutoPtr<RequestSet> newRequestSet(new RequestSet());
|
||||
|
||||
mFrameToRequestMap.Put(aFrame, newRequestSet);
|
||||
requestSet = newRequestSet.forget();
|
||||
}
|
||||
|
||||
// Add these to the sets, but only if they're not already there.
|
||||
uint32_t i = frameSet->IndexOfFirstElementGt(aFrame);
|
||||
if (i == 0 || aFrame != frameSet->ElementAt(i-1)) {
|
||||
frameSet->InsertElementAt(i, aFrame);
|
||||
}
|
||||
i = requestSet->IndexOfFirstElementGt(aRequest);
|
||||
if (i == 0 || aRequest != requestSet->ElementAt(i-1)) {
|
||||
requestSet->InsertElementAt(i, aRequest);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ImageLoader::MaybeRegisterCSSImage(ImageLoader::Image* aImage)
|
||||
{
|
||||
NS_ASSERTION(aImage, "This should never be null!");
|
||||
|
||||
bool found = false;
|
||||
aImage->mRequests.GetWeak(mDocument, &found);
|
||||
if (found) {
|
||||
// This document already has a request.
|
||||
return;
|
||||
}
|
||||
|
||||
imgRequestProxy* canonicalRequest = aImage->mRequests.GetWeak(nullptr);
|
||||
if (!canonicalRequest) {
|
||||
// The image was blocked or something.
|
||||
return;
|
||||
}
|
||||
|
||||
RefPtr<imgRequestProxy> request;
|
||||
|
||||
// Ignore errors here. If cloning fails for some reason we'll put a null
|
||||
// entry in the hash and we won't keep trying to clone.
|
||||
mInClone = true;
|
||||
canonicalRequest->Clone(this, getter_AddRefs(request));
|
||||
mInClone = false;
|
||||
|
||||
aImage->mRequests.Put(mDocument, request);
|
||||
|
||||
AddImage(aImage);
|
||||
}
|
||||
|
||||
void
|
||||
ImageLoader::DeregisterCSSImage(ImageLoader::Image* aImage)
|
||||
{
|
||||
RemoveImage(aImage);
|
||||
}
|
||||
|
||||
void
|
||||
ImageLoader::DisassociateRequestFromFrame(imgIRequest* aRequest,
|
||||
nsIFrame* aFrame)
|
||||
{
|
||||
FrameSet* frameSet = nullptr;
|
||||
RequestSet* requestSet = nullptr;
|
||||
|
||||
#ifdef DEBUG
|
||||
{
|
||||
nsCOMPtr<imgINotificationObserver> observer;
|
||||
aRequest->GetNotificationObserver(getter_AddRefs(observer));
|
||||
MOZ_ASSERT(!observer || observer == this);
|
||||
}
|
||||
#endif
|
||||
|
||||
mRequestToFrameMap.Get(aRequest, &frameSet);
|
||||
mFrameToRequestMap.Get(aFrame, &requestSet);
|
||||
|
||||
if (frameSet) {
|
||||
frameSet->RemoveElementSorted(aFrame);
|
||||
}
|
||||
if (requestSet) {
|
||||
requestSet->RemoveElementSorted(aRequest);
|
||||
}
|
||||
|
||||
if (frameSet && !frameSet->Length()) {
|
||||
mRequestToFrameMap.Remove(aRequest);
|
||||
|
||||
nsPresContext* presContext = GetPresContext();
|
||||
if (presContext) {
|
||||
nsLayoutUtils::DeregisterImageRequest(presContext,
|
||||
aRequest,
|
||||
nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
if (requestSet && !requestSet->Length()) {
|
||||
mFrameToRequestMap.Remove(aFrame);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ImageLoader::DropRequestsForFrame(nsIFrame* aFrame)
|
||||
{
|
||||
RequestSet* requestSet = nullptr;
|
||||
if (!mFrameToRequestMap.Get(aFrame, &requestSet)) {
|
||||
return;
|
||||
}
|
||||
|
||||
NS_ASSERTION(requestSet, "This should never be null");
|
||||
|
||||
RequestSet frozenRequestSet(*requestSet);
|
||||
for (RequestSet::size_type i = frozenRequestSet.Length(); i != 0; --i) {
|
||||
imgIRequest* request = frozenRequestSet.ElementAt(i - 1);
|
||||
|
||||
DisassociateRequestFromFrame(request, aFrame);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ImageLoader::SetAnimationMode(uint16_t aMode)
|
||||
{
|
||||
NS_ASSERTION(aMode == imgIContainer::kNormalAnimMode ||
|
||||
aMode == imgIContainer::kDontAnimMode ||
|
||||
aMode == imgIContainer::kLoopOnceAnimMode,
|
||||
"Wrong Animation Mode is being set!");
|
||||
|
||||
for (auto iter = mRequestToFrameMap.ConstIter(); !iter.Done(); iter.Next()) {
|
||||
auto request = static_cast<imgIRequest*>(iter.Key());
|
||||
|
||||
#ifdef DEBUG
|
||||
{
|
||||
nsCOMPtr<imgIRequest> debugRequest = do_QueryInterface(request);
|
||||
NS_ASSERTION(debugRequest == request, "This is bad");
|
||||
}
|
||||
#endif
|
||||
|
||||
nsCOMPtr<imgIContainer> container;
|
||||
request->GetImage(getter_AddRefs(container));
|
||||
if (!container) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// This can fail if the image is in error, and we don't care.
|
||||
container->SetAnimationMode(aMode);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ImageLoader::ClearFrames(nsPresContext* aPresContext)
|
||||
{
|
||||
for (auto iter = mRequestToFrameMap.ConstIter(); !iter.Done(); iter.Next()) {
|
||||
auto request = static_cast<imgIRequest*>(iter.Key());
|
||||
|
||||
#ifdef DEBUG
|
||||
{
|
||||
nsCOMPtr<imgIRequest> debugRequest = do_QueryInterface(request);
|
||||
NS_ASSERTION(debugRequest == request, "This is bad");
|
||||
}
|
||||
#endif
|
||||
|
||||
if (aPresContext) {
|
||||
nsLayoutUtils::DeregisterImageRequest(aPresContext,
|
||||
request,
|
||||
nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
mRequestToFrameMap.Clear();
|
||||
mFrameToRequestMap.Clear();
|
||||
}
|
||||
|
||||
void
|
||||
ImageLoader::LoadImage(nsIURI* aURI, nsIPrincipal* aOriginPrincipal,
|
||||
nsIURI* aReferrer, ImageLoader::Image* aImage)
|
||||
{
|
||||
NS_ASSERTION(aImage->mRequests.Count() == 0, "Huh?");
|
||||
|
||||
aImage->mRequests.Put(nullptr, nullptr);
|
||||
|
||||
if (!aURI) {
|
||||
return;
|
||||
}
|
||||
|
||||
RefPtr<imgRequestProxy> request;
|
||||
nsresult rv = nsContentUtils::LoadImage(aURI, mDocument, mDocument,
|
||||
aOriginPrincipal, aReferrer,
|
||||
mDocument->GetReferrerPolicy(),
|
||||
nullptr, nsIRequest::LOAD_NORMAL,
|
||||
NS_LITERAL_STRING("css"),
|
||||
getter_AddRefs(request));
|
||||
|
||||
if (NS_FAILED(rv) || !request) {
|
||||
return;
|
||||
}
|
||||
|
||||
RefPtr<imgRequestProxy> clonedRequest;
|
||||
mInClone = true;
|
||||
rv = request->Clone(this, getter_AddRefs(clonedRequest));
|
||||
mInClone = false;
|
||||
|
||||
if (NS_FAILED(rv)) {
|
||||
return;
|
||||
}
|
||||
|
||||
aImage->mRequests.Put(nullptr, request);
|
||||
aImage->mRequests.Put(mDocument, clonedRequest);
|
||||
|
||||
AddImage(aImage);
|
||||
}
|
||||
|
||||
void
|
||||
ImageLoader::AddImage(ImageLoader::Image* aImage)
|
||||
{
|
||||
NS_ASSERTION(!mImages.Contains(aImage), "Huh?");
|
||||
mImages.PutEntry(aImage);
|
||||
}
|
||||
|
||||
void
|
||||
ImageLoader::RemoveImage(ImageLoader::Image* aImage)
|
||||
{
|
||||
NS_ASSERTION(mImages.Contains(aImage), "Huh?");
|
||||
mImages.RemoveEntry(aImage);
|
||||
}
|
||||
|
||||
nsPresContext*
|
||||
ImageLoader::GetPresContext()
|
||||
{
|
||||
if (!mDocument) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
nsIPresShell* shell = mDocument->GetShell();
|
||||
if (!shell) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return shell->GetPresContext();
|
||||
}
|
||||
|
||||
void InvalidateImagesCallback(nsIFrame* aFrame,
|
||||
FrameLayerBuilder::DisplayItemData* aItem)
|
||||
{
|
||||
nsDisplayItem::Type type = nsDisplayItem::GetDisplayItemTypeFromKey(aItem->GetDisplayItemKey());
|
||||
uint8_t flags = nsDisplayItem::GetDisplayItemFlagsForType(type);
|
||||
|
||||
if (flags & nsDisplayItem::TYPE_RENDERS_NO_IMAGES) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (nsLayoutUtils::InvalidationDebuggingIsEnabled()) {
|
||||
printf_stderr("Invalidating display item(type=%d) based on frame %p \
|
||||
because it might contain an invalidated image\n", type, aFrame);
|
||||
}
|
||||
aItem->Invalidate();
|
||||
aFrame->SchedulePaint();
|
||||
}
|
||||
|
||||
void
|
||||
ImageLoader::DoRedraw(FrameSet* aFrameSet, bool aForcePaint)
|
||||
{
|
||||
NS_ASSERTION(aFrameSet, "Must have a frame set");
|
||||
NS_ASSERTION(mDocument, "Should have returned earlier!");
|
||||
|
||||
FrameSet::size_type length = aFrameSet->Length();
|
||||
for (FrameSet::size_type i = 0; i < length; i++) {
|
||||
nsIFrame* frame = aFrameSet->ElementAt(i);
|
||||
|
||||
if (frame->StyleVisibility()->IsVisible()) {
|
||||
if (frame->IsFrameOfType(nsIFrame::eTablePart)) {
|
||||
// Tables don't necessarily build border/background display items
|
||||
// for the individual table part frames, so IterateRetainedDataFor
|
||||
// might not find the right display item.
|
||||
frame->InvalidateFrame();
|
||||
} else {
|
||||
FrameLayerBuilder::IterateRetainedDataFor(frame, InvalidateImagesCallback);
|
||||
|
||||
// Update ancestor rendering observers (-moz-element etc)
|
||||
nsIFrame *f = frame;
|
||||
while (f && !f->HasAnyStateBits(NS_FRAME_DESCENDANT_NEEDS_PAINT)) {
|
||||
nsSVGEffects::InvalidateDirectRenderingObservers(f);
|
||||
f = nsLayoutUtils::GetCrossDocParentFrame(f);
|
||||
}
|
||||
|
||||
if (aForcePaint) {
|
||||
frame->SchedulePaint();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
NS_IMPL_ADDREF(ImageLoader)
|
||||
NS_IMPL_RELEASE(ImageLoader)
|
||||
|
||||
NS_INTERFACE_MAP_BEGIN(ImageLoader)
|
||||
NS_INTERFACE_MAP_ENTRY(imgINotificationObserver)
|
||||
NS_INTERFACE_MAP_ENTRY(imgIOnloadBlocker)
|
||||
NS_INTERFACE_MAP_END
|
||||
|
||||
NS_IMETHODIMP
|
||||
ImageLoader::Notify(imgIRequest* aRequest, int32_t aType, const nsIntRect* aData)
|
||||
{
|
||||
if (aType == imgINotificationObserver::SIZE_AVAILABLE) {
|
||||
nsCOMPtr<imgIContainer> image;
|
||||
aRequest->GetImage(getter_AddRefs(image));
|
||||
return OnSizeAvailable(aRequest, image);
|
||||
}
|
||||
|
||||
if (aType == imgINotificationObserver::IS_ANIMATED) {
|
||||
return OnImageIsAnimated(aRequest);
|
||||
}
|
||||
|
||||
if (aType == imgINotificationObserver::FRAME_COMPLETE) {
|
||||
return OnFrameComplete(aRequest);
|
||||
}
|
||||
|
||||
if (aType == imgINotificationObserver::FRAME_UPDATE) {
|
||||
return OnFrameUpdate(aRequest);
|
||||
}
|
||||
|
||||
if (aType == imgINotificationObserver::DECODE_COMPLETE) {
|
||||
nsCOMPtr<imgIContainer> image;
|
||||
aRequest->GetImage(getter_AddRefs(image));
|
||||
if (image && mDocument) {
|
||||
image->PropagateUseCounters(mDocument);
|
||||
}
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
ImageLoader::OnSizeAvailable(imgIRequest* aRequest, imgIContainer* aImage)
|
||||
{
|
||||
nsPresContext* presContext = GetPresContext();
|
||||
if (!presContext) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
aImage->SetAnimationMode(presContext->ImageAnimationMode());
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
ImageLoader::OnImageIsAnimated(imgIRequest* aRequest)
|
||||
{
|
||||
if (!mDocument) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
FrameSet* frameSet = nullptr;
|
||||
if (!mRequestToFrameMap.Get(aRequest, &frameSet)) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Register with the refresh driver now that we are aware that
|
||||
// we are animated.
|
||||
nsPresContext* presContext = GetPresContext();
|
||||
if (presContext) {
|
||||
nsLayoutUtils::RegisterImageRequest(presContext,
|
||||
aRequest,
|
||||
nullptr);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
ImageLoader::OnFrameComplete(imgIRequest* aRequest)
|
||||
{
|
||||
if (!mDocument || mInClone) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
FrameSet* frameSet = nullptr;
|
||||
if (!mRequestToFrameMap.Get(aRequest, &frameSet)) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_ASSERTION(frameSet, "This should never be null!");
|
||||
|
||||
// Since we just finished decoding a frame, we always want to paint, in case
|
||||
// we're now able to paint an image that we couldn't paint before (and hence
|
||||
// that we don't have retained data for).
|
||||
DoRedraw(frameSet, /* aForcePaint = */ true);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
ImageLoader::OnFrameUpdate(imgIRequest* aRequest)
|
||||
{
|
||||
if (!mDocument || mInClone) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
FrameSet* frameSet = nullptr;
|
||||
if (!mRequestToFrameMap.Get(aRequest, &frameSet)) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_ASSERTION(frameSet, "This should never be null!");
|
||||
|
||||
DoRedraw(frameSet, /* aForcePaint = */ false);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
ImageLoader::BlockOnload(imgIRequest* aRequest)
|
||||
{
|
||||
if (!mDocument) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
mDocument->BlockOnload();
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
ImageLoader::UnblockOnload(imgIRequest* aRequest)
|
||||
{
|
||||
if (!mDocument) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
mDocument->UnblockOnload(false);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
ImageLoader::FlushUseCounters()
|
||||
{
|
||||
for (auto iter = mImages.Iter(); !iter.Done(); iter.Next()) {
|
||||
nsPtrHashKey<Image>* key = iter.Get();
|
||||
ImageLoader::Image* image = key->GetKey();
|
||||
|
||||
imgIRequest* request = image->mRequests.GetWeak(mDocument);
|
||||
|
||||
nsCOMPtr<imgIContainer> container;
|
||||
request->GetImage(getter_AddRefs(container));
|
||||
if (container) {
|
||||
static_cast<image::Image*>(container.get())->ReportUseCounters();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace css
|
||||
} // namespace mozilla
|
||||
124
layout/style/ImageLoader.h
Normal file
124
layout/style/ImageLoader.h
Normal file
|
|
@ -0,0 +1,124 @@
|
|||
/* 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/. */
|
||||
|
||||
// A class that handles style system image loads (other image loads are handled
|
||||
// by the nodes in the content tree).
|
||||
|
||||
#ifndef mozilla_css_ImageLoader_h___
|
||||
#define mozilla_css_ImageLoader_h___
|
||||
|
||||
#include "nsClassHashtable.h"
|
||||
#include "nsHashKeys.h"
|
||||
#include "nsTArray.h"
|
||||
#include "imgIRequest.h"
|
||||
#include "imgIOnloadBlocker.h"
|
||||
#include "imgINotificationObserver.h"
|
||||
#include "mozilla/Attributes.h"
|
||||
|
||||
class imgIContainer;
|
||||
class nsIFrame;
|
||||
class nsIDocument;
|
||||
class nsPresContext;
|
||||
class nsIURI;
|
||||
class nsIPrincipal;
|
||||
|
||||
namespace mozilla {
|
||||
namespace css {
|
||||
|
||||
struct ImageValue;
|
||||
|
||||
class ImageLoader final : public imgINotificationObserver,
|
||||
public imgIOnloadBlocker
|
||||
{
|
||||
public:
|
||||
typedef mozilla::css::ImageValue Image;
|
||||
|
||||
explicit ImageLoader(nsIDocument* aDocument)
|
||||
: mDocument(aDocument),
|
||||
mInClone(false)
|
||||
{
|
||||
MOZ_ASSERT(mDocument);
|
||||
}
|
||||
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_IMGIONLOADBLOCKER
|
||||
NS_DECL_IMGINOTIFICATIONOBSERVER
|
||||
|
||||
void DropDocumentReference();
|
||||
|
||||
void MaybeRegisterCSSImage(Image* aImage);
|
||||
void DeregisterCSSImage(Image* aImage);
|
||||
|
||||
void AssociateRequestToFrame(imgIRequest* aRequest,
|
||||
nsIFrame* aFrame);
|
||||
|
||||
void DisassociateRequestFromFrame(imgIRequest* aRequest,
|
||||
nsIFrame* aFrame);
|
||||
|
||||
void DropRequestsForFrame(nsIFrame* aFrame);
|
||||
|
||||
void SetAnimationMode(uint16_t aMode);
|
||||
|
||||
// The prescontext for this ImageLoader's document. We need it to be passed
|
||||
// in because this can be called during presentation destruction after the
|
||||
// presshell pointer on the document has been cleared.
|
||||
void ClearFrames(nsPresContext* aPresContext);
|
||||
|
||||
void LoadImage(nsIURI* aURI, nsIPrincipal* aPrincipal, nsIURI* aReferrer,
|
||||
Image* aCSSValue);
|
||||
|
||||
void DestroyRequest(imgIRequest* aRequest);
|
||||
|
||||
void FlushUseCounters();
|
||||
|
||||
private:
|
||||
~ImageLoader() {}
|
||||
|
||||
// We need to be able to look up the frames associated with a request (for
|
||||
// delivering notifications) and the requests associated with a frame (when
|
||||
// the frame goes away). Thus we maintain hashtables going both ways. These
|
||||
// should always be in sync.
|
||||
|
||||
typedef nsTArray<nsIFrame*> FrameSet;
|
||||
typedef nsTArray<nsCOMPtr<imgIRequest> > RequestSet;
|
||||
typedef nsTHashtable<nsPtrHashKey<Image> > ImageHashSet;
|
||||
typedef nsClassHashtable<nsISupportsHashKey,
|
||||
FrameSet> RequestToFrameMap;
|
||||
typedef nsClassHashtable<nsPtrHashKey<nsIFrame>,
|
||||
RequestSet> FrameToRequestMap;
|
||||
|
||||
void AddImage(Image* aCSSImage);
|
||||
void RemoveImage(Image* aCSSImage);
|
||||
|
||||
nsPresContext* GetPresContext();
|
||||
|
||||
void DoRedraw(FrameSet* aFrameSet, bool aForcePaint);
|
||||
|
||||
nsresult OnSizeAvailable(imgIRequest* aRequest, imgIContainer* aImage);
|
||||
nsresult OnFrameComplete(imgIRequest* aRequest);
|
||||
nsresult OnImageIsAnimated(imgIRequest* aRequest);
|
||||
nsresult OnFrameUpdate(imgIRequest* aRequest);
|
||||
|
||||
// A map of imgIRequests to the nsIFrames that are using them.
|
||||
RequestToFrameMap mRequestToFrameMap;
|
||||
|
||||
// A map of nsIFrames to the imgIRequests they use.
|
||||
FrameToRequestMap mFrameToRequestMap;
|
||||
|
||||
// A weak pointer to our document. Nulled out by DropDocumentReference.
|
||||
nsIDocument* mDocument;
|
||||
|
||||
// The set of all nsCSSValue::Images (whether they're associated a frame or
|
||||
// not). We'll need this when we go away to remove any requests associated
|
||||
// with our document from those Images.
|
||||
ImageHashSet mImages;
|
||||
|
||||
// Are we cloning? If so, ignore any notifications we get.
|
||||
bool mInClone;
|
||||
};
|
||||
|
||||
} // namespace css
|
||||
} // namespace mozilla
|
||||
|
||||
#endif /* mozilla_css_ImageLoader_h___ */
|
||||
72
layout/style/ImportRule.h
Normal file
72
layout/style/ImportRule.h
Normal file
|
|
@ -0,0 +1,72 @@
|
|||
/* -*- Mode: C++; 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/. */
|
||||
|
||||
/* class for CSS @import rules */
|
||||
|
||||
#ifndef mozilla_css_ImportRule_h__
|
||||
#define mozilla_css_ImportRule_h__
|
||||
|
||||
#include "mozilla/Attributes.h"
|
||||
|
||||
#include "mozilla/MemoryReporting.h"
|
||||
#include "mozilla/css/Rule.h"
|
||||
#include "nsIDOMCSSImportRule.h"
|
||||
|
||||
class nsMediaList;
|
||||
class nsString;
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
class CSSStyleSheet;
|
||||
|
||||
namespace css {
|
||||
|
||||
class ImportRule final : public Rule,
|
||||
public nsIDOMCSSImportRule
|
||||
{
|
||||
public:
|
||||
ImportRule(nsMediaList* aMedia, const nsString& aURLSpec,
|
||||
uint32_t aLineNumber, uint32_t aColumnNumber);
|
||||
private:
|
||||
// for |Clone|
|
||||
ImportRule(const ImportRule& aCopy);
|
||||
~ImportRule();
|
||||
public:
|
||||
NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(ImportRule, mozilla::css::Rule)
|
||||
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
|
||||
|
||||
DECL_STYLE_RULE_INHERIT
|
||||
|
||||
#ifdef HAVE_CPP_AMBIGUITY_RESOLVING_USING
|
||||
using Rule::GetStyleSheet; // unhide since nsIDOMCSSImportRule has its own GetStyleSheet
|
||||
#endif
|
||||
|
||||
// Rule methods
|
||||
#ifdef DEBUG
|
||||
virtual void List(FILE* out = stdout, int32_t aIndent = 0) const override;
|
||||
#endif
|
||||
virtual int32_t GetType() const override;
|
||||
virtual already_AddRefed<Rule> Clone() const override;
|
||||
|
||||
void SetSheet(CSSStyleSheet*);
|
||||
|
||||
virtual size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const override;
|
||||
|
||||
// nsIDOMCSSRule interface
|
||||
NS_DECL_NSIDOMCSSRULE
|
||||
|
||||
// nsIDOMCSSImportRule interface
|
||||
NS_DECL_NSIDOMCSSIMPORTRULE
|
||||
|
||||
private:
|
||||
nsString mURLSpec;
|
||||
RefPtr<nsMediaList> mMedia;
|
||||
RefPtr<CSSStyleSheet> mChildSheet;
|
||||
};
|
||||
|
||||
} // namespace css
|
||||
} // namespace mozilla
|
||||
|
||||
#endif /* mozilla_css_ImportRule_h__ */
|
||||
81
layout/style/IncrementalClearCOMRuleArray.cpp
Normal file
81
layout/style/IncrementalClearCOMRuleArray.cpp
Normal file
|
|
@ -0,0 +1,81 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* 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 "mozilla/IncrementalClearCOMRuleArray.h"
|
||||
|
||||
#include <algorithm> // For std::min
|
||||
#include "nsCycleCollector.h"
|
||||
#include "mozilla/DeferredFinalize.h"
|
||||
#include "nsTArray.h"
|
||||
#include "nsCCUncollectableMarker.h"
|
||||
|
||||
using namespace mozilla;
|
||||
|
||||
typedef nsCOMArray<css::Rule> RuleArray;
|
||||
typedef nsTArray<RuleArray> RuleArrayArray;
|
||||
|
||||
|
||||
// These methods are based on those in DeferredFinalizerImpl.
|
||||
|
||||
static void*
|
||||
AppendRulesArrayPointer(void* aData, void* aObject)
|
||||
{
|
||||
RuleArrayArray* rulesArray = static_cast<RuleArrayArray*>(aData);
|
||||
RuleArray* oldRules = static_cast<RuleArray*>(aObject);
|
||||
|
||||
if (!rulesArray) {
|
||||
rulesArray = new RuleArrayArray();
|
||||
}
|
||||
|
||||
RuleArray* newRules = rulesArray->AppendElement();
|
||||
newRules->SwapElements(*oldRules);
|
||||
|
||||
return rulesArray;
|
||||
}
|
||||
|
||||
// Remove up to |aSliceBudget| css::Rules from the arrays, starting at
|
||||
// the end of the last array.
|
||||
static bool
|
||||
DeferredFinalizeRulesArray(uint32_t aSliceBudget, void* aData)
|
||||
{
|
||||
MOZ_ASSERT(aSliceBudget > 0, "nonsensical/useless call with aSliceBudget == 0");
|
||||
RuleArrayArray* rulesArray = static_cast<RuleArrayArray*>(aData);
|
||||
|
||||
size_t newOuterLen = rulesArray->Length();
|
||||
|
||||
while (aSliceBudget > 0 && newOuterLen > 0) {
|
||||
RuleArray& lastArray = rulesArray->ElementAt(newOuterLen - 1);
|
||||
uint32_t innerLen = lastArray.Length();
|
||||
uint32_t currSlice = std::min(innerLen, aSliceBudget);
|
||||
uint32_t newInnerLen = innerLen - currSlice;
|
||||
lastArray.TruncateLength(newInnerLen);
|
||||
aSliceBudget -= currSlice;
|
||||
if (newInnerLen == 0) {
|
||||
newOuterLen -= 1;
|
||||
}
|
||||
}
|
||||
|
||||
rulesArray->TruncateLength(newOuterLen);
|
||||
|
||||
if (newOuterLen == 0) {
|
||||
delete rulesArray;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void
|
||||
IncrementalClearCOMRuleArray::Clear()
|
||||
{
|
||||
// Destroy the array incrementally if it is long and we
|
||||
// haven't started shutting down.
|
||||
if (Length() > 10 && nsCCUncollectableMarker::sGeneration) {
|
||||
DeferredFinalize(AppendRulesArrayPointer, DeferredFinalizeRulesArray, this);
|
||||
} else {
|
||||
nsCOMArray<css::Rule>::Clear();
|
||||
}
|
||||
MOZ_ASSERT(Length() == 0);
|
||||
}
|
||||
28
layout/style/IncrementalClearCOMRuleArray.h
Normal file
28
layout/style/IncrementalClearCOMRuleArray.h
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* 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_IncrementalClearCOMRuleArray_h
|
||||
#define mozilla_IncrementalClearCOMRuleArray_h
|
||||
|
||||
#include "nsCOMArray.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace css {
|
||||
class Rule;
|
||||
} // namespace css
|
||||
|
||||
class IncrementalClearCOMRuleArray : public nsCOMArray<css::Rule>
|
||||
{
|
||||
public:
|
||||
IncrementalClearCOMRuleArray() {}
|
||||
~IncrementalClearCOMRuleArray() { Clear(); }
|
||||
|
||||
void Clear();
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
|
||||
#endif /* !defined(mozilla_IncrementalClearCOMRuleArray_h) */
|
||||
53
layout/style/LayerAnimationInfo.cpp
Normal file
53
layout/style/LayerAnimationInfo.cpp
Normal file
|
|
@ -0,0 +1,53 @@
|
|||
/* vim: set shiftwidth=2 tabstop=8 autoindent cindent expandtab: */
|
||||
/* 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 "LayerAnimationInfo.h"
|
||||
|
||||
#include "nsCSSProps.h" // For nsCSSProps::PropHasFlags
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
/* static */ const LayerAnimationInfo::Record LayerAnimationInfo::sRecords[] =
|
||||
{ { eCSSProperty_transform,
|
||||
nsDisplayItem::TYPE_TRANSFORM,
|
||||
nsChangeHint_UpdateTransformLayer },
|
||||
{ eCSSProperty_opacity,
|
||||
nsDisplayItem::TYPE_OPACITY,
|
||||
nsChangeHint_UpdateOpacityLayer } };
|
||||
|
||||
#ifdef DEBUG
|
||||
/* static */ void
|
||||
LayerAnimationInfo::Initialize()
|
||||
{
|
||||
for (const Record& record : sRecords) {
|
||||
MOZ_ASSERT(nsCSSProps::PropHasFlags(record.mProperty,
|
||||
CSS_PROPERTY_CAN_ANIMATE_ON_COMPOSITOR),
|
||||
"CSS property with entry in LayerAnimation::sRecords does not "
|
||||
"have the CSS_PROPERTY_CAN_ANIMATE_ON_COMPOSITOR flag");
|
||||
}
|
||||
|
||||
// Check that every property with the flag for animating on the
|
||||
// compositor has an entry in LayerAnimationInfo::sRecords.
|
||||
for (nsCSSPropertyID prop = nsCSSPropertyID(0);
|
||||
prop < eCSSProperty_COUNT;
|
||||
prop = nsCSSPropertyID(prop + 1)) {
|
||||
if (nsCSSProps::PropHasFlags(prop,
|
||||
CSS_PROPERTY_CAN_ANIMATE_ON_COMPOSITOR)) {
|
||||
bool found = false;
|
||||
for (const Record& record : sRecords) {
|
||||
if (record.mProperty == prop) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
MOZ_ASSERT(found,
|
||||
"CSS property with the CSS_PROPERTY_CAN_ANIMATE_ON_COMPOSITOR "
|
||||
"flag does not have an entry in LayerAnimationInfo::sRecords");
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
} // namespace mozilla
|
||||
33
layout/style/LayerAnimationInfo.h
Normal file
33
layout/style/LayerAnimationInfo.h
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
/* vim: set shiftwidth=2 tabstop=8 autoindent cindent expandtab: */
|
||||
/* 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_LayerAnimationInfo_h
|
||||
#define mozilla_LayerAnimationInfo_h
|
||||
|
||||
#include "nsChangeHint.h"
|
||||
#include "nsCSSPropertyID.h"
|
||||
#include "nsDisplayList.h" // For nsDisplayItem::Type
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
struct LayerAnimationInfo {
|
||||
#ifdef DEBUG
|
||||
static void Initialize();
|
||||
#endif
|
||||
// For CSS properties that may be animated on a separate layer, represents
|
||||
// a record of the corresponding layer type and change hint.
|
||||
struct Record {
|
||||
nsCSSPropertyID mProperty;
|
||||
nsDisplayItem::Type mLayerType;
|
||||
nsChangeHint mChangeHint;
|
||||
};
|
||||
|
||||
static const size_t kRecords = 2;
|
||||
static const Record sRecords[kRecords];
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
|
||||
#endif /* !defined(mozilla_LayerAnimationInfo_h) */
|
||||
2694
layout/style/Loader.cpp
Normal file
2694
layout/style/Loader.cpp
Normal file
File diff suppressed because it is too large
Load diff
598
layout/style/Loader.h
Normal file
598
layout/style/Loader.h
Normal file
|
|
@ -0,0 +1,598 @@
|
|||
/* -*- Mode: C++; 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/. */
|
||||
|
||||
/* loading of CSS style sheets using the network APIs */
|
||||
|
||||
#ifndef mozilla_css_Loader_h
|
||||
#define mozilla_css_Loader_h
|
||||
|
||||
#include "nsIPrincipal.h"
|
||||
#include "nsAutoPtr.h"
|
||||
#include "nsCompatibility.h"
|
||||
#include "nsCycleCollectionParticipant.h"
|
||||
#include "nsDataHashtable.h"
|
||||
#include "nsRefPtrHashtable.h"
|
||||
#include "nsStringFwd.h"
|
||||
#include "nsTArray.h"
|
||||
#include "nsTObserverArray.h"
|
||||
#include "nsURIHashKey.h"
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "mozilla/CORSMode.h"
|
||||
#include "mozilla/StyleSheetInlines.h"
|
||||
#include "mozilla/Maybe.h"
|
||||
#include "mozilla/MemoryReporting.h"
|
||||
#include "mozilla/StyleBackendType.h"
|
||||
#include "mozilla/StyleSheet.h"
|
||||
#include "mozilla/net/ReferrerPolicy.h"
|
||||
|
||||
class nsICSSLoaderObserver;
|
||||
class nsIConsoleReportCollector;
|
||||
class nsIContent;
|
||||
class nsIDocument;
|
||||
class nsMediaList;
|
||||
class nsIStyleSheetLinkingElement;
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
class Element;
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
class URIPrincipalReferrerPolicyAndCORSModeHashKey : public nsURIHashKey
|
||||
{
|
||||
public:
|
||||
typedef URIPrincipalReferrerPolicyAndCORSModeHashKey* KeyType;
|
||||
typedef const URIPrincipalReferrerPolicyAndCORSModeHashKey* KeyTypePointer;
|
||||
typedef mozilla::net::ReferrerPolicy ReferrerPolicy;
|
||||
|
||||
explicit URIPrincipalReferrerPolicyAndCORSModeHashKey(const URIPrincipalReferrerPolicyAndCORSModeHashKey* aKey)
|
||||
: nsURIHashKey(aKey->mKey),
|
||||
mPrincipal(aKey->mPrincipal),
|
||||
mCORSMode(aKey->mCORSMode),
|
||||
mReferrerPolicy(aKey->mReferrerPolicy)
|
||||
{
|
||||
MOZ_COUNT_CTOR(URIPrincipalReferrerPolicyAndCORSModeHashKey);
|
||||
}
|
||||
|
||||
URIPrincipalReferrerPolicyAndCORSModeHashKey(nsIURI* aURI,
|
||||
nsIPrincipal* aPrincipal,
|
||||
CORSMode aCORSMode,
|
||||
ReferrerPolicy aReferrerPolicy)
|
||||
: nsURIHashKey(aURI),
|
||||
mPrincipal(aPrincipal),
|
||||
mCORSMode(aCORSMode),
|
||||
mReferrerPolicy(aReferrerPolicy)
|
||||
{
|
||||
MOZ_COUNT_CTOR(URIPrincipalReferrerPolicyAndCORSModeHashKey);
|
||||
}
|
||||
URIPrincipalReferrerPolicyAndCORSModeHashKey(const URIPrincipalReferrerPolicyAndCORSModeHashKey& toCopy)
|
||||
: nsURIHashKey(toCopy),
|
||||
mPrincipal(toCopy.mPrincipal),
|
||||
mCORSMode(toCopy.mCORSMode),
|
||||
mReferrerPolicy(toCopy.mReferrerPolicy)
|
||||
{
|
||||
MOZ_COUNT_CTOR(URIPrincipalReferrerPolicyAndCORSModeHashKey);
|
||||
}
|
||||
~URIPrincipalReferrerPolicyAndCORSModeHashKey()
|
||||
{
|
||||
MOZ_COUNT_DTOR(URIPrincipalReferrerPolicyAndCORSModeHashKey);
|
||||
}
|
||||
|
||||
URIPrincipalReferrerPolicyAndCORSModeHashKey* GetKey() const {
|
||||
return const_cast<URIPrincipalReferrerPolicyAndCORSModeHashKey*>(this);
|
||||
}
|
||||
const URIPrincipalReferrerPolicyAndCORSModeHashKey* GetKeyPointer() const { return this; }
|
||||
|
||||
bool KeyEquals(const URIPrincipalReferrerPolicyAndCORSModeHashKey* aKey) const {
|
||||
if (!nsURIHashKey::KeyEquals(aKey->mKey)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!mPrincipal != !aKey->mPrincipal) {
|
||||
// One or the other has a principal, but not both... not equal
|
||||
return false;
|
||||
}
|
||||
|
||||
if (mCORSMode != aKey->mCORSMode) {
|
||||
// Different CORS modes; we don't match
|
||||
return false;
|
||||
}
|
||||
|
||||
if (mReferrerPolicy != aKey->mReferrerPolicy) {
|
||||
// Different ReferrerPolicy; we don't match
|
||||
return false;
|
||||
}
|
||||
|
||||
bool eq;
|
||||
return !mPrincipal ||
|
||||
(NS_SUCCEEDED(mPrincipal->Equals(aKey->mPrincipal, &eq)) && eq);
|
||||
}
|
||||
|
||||
static const URIPrincipalReferrerPolicyAndCORSModeHashKey*
|
||||
KeyToPointer(URIPrincipalReferrerPolicyAndCORSModeHashKey* aKey) { return aKey; }
|
||||
static PLDHashNumber HashKey(const URIPrincipalReferrerPolicyAndCORSModeHashKey* aKey) {
|
||||
return nsURIHashKey::HashKey(aKey->mKey);
|
||||
}
|
||||
|
||||
nsIURI* GetURI() const { return nsURIHashKey::GetKey(); }
|
||||
|
||||
enum { ALLOW_MEMMOVE = true };
|
||||
|
||||
protected:
|
||||
nsCOMPtr<nsIPrincipal> mPrincipal;
|
||||
CORSMode mCORSMode;
|
||||
ReferrerPolicy mReferrerPolicy;
|
||||
};
|
||||
|
||||
|
||||
|
||||
namespace css {
|
||||
|
||||
class SheetLoadData;
|
||||
class ImportRule;
|
||||
|
||||
/*********************
|
||||
* Style sheet reuse *
|
||||
*********************/
|
||||
|
||||
class MOZ_RAII LoaderReusableStyleSheets
|
||||
{
|
||||
public:
|
||||
LoaderReusableStyleSheets()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Look for a reusable sheet (see AddReusableSheet) matching the
|
||||
* given URL. If found, set aResult, remove the reused sheet from
|
||||
* the internal list, and return true. If not found, return false;
|
||||
* in this case, aResult is not modified.
|
||||
*
|
||||
* @param aURL the url to match
|
||||
* @param aResult [out] the style sheet which can be reused
|
||||
*/
|
||||
bool FindReusableStyleSheet(nsIURI* aURL, RefPtr<CSSStyleSheet>& aResult);
|
||||
|
||||
/**
|
||||
* Indicate that a certain style sheet is available for reuse if its
|
||||
* URI matches the URI of an @import. Sheets should be added in the
|
||||
* opposite order in which they are intended to be reused.
|
||||
*
|
||||
* @param aSheet the sheet which can be reused
|
||||
*/
|
||||
void AddReusableSheet(CSSStyleSheet* aSheet) {
|
||||
mReusableSheets.AppendElement(aSheet);
|
||||
}
|
||||
|
||||
private:
|
||||
LoaderReusableStyleSheets(const LoaderReusableStyleSheets&) = delete;
|
||||
LoaderReusableStyleSheets& operator=(const LoaderReusableStyleSheets&) = delete;
|
||||
|
||||
// The sheets that can be reused.
|
||||
nsTArray<RefPtr<CSSStyleSheet>> mReusableSheets;
|
||||
};
|
||||
|
||||
/***********************************************************************
|
||||
* Enum that describes the state of the sheet returned by CreateSheet. *
|
||||
***********************************************************************/
|
||||
enum StyleSheetState {
|
||||
eSheetStateUnknown = 0,
|
||||
eSheetNeedsParser,
|
||||
eSheetPending,
|
||||
eSheetLoading,
|
||||
eSheetComplete
|
||||
};
|
||||
|
||||
class Loader final {
|
||||
typedef mozilla::net::ReferrerPolicy ReferrerPolicy;
|
||||
|
||||
public:
|
||||
explicit Loader(StyleBackendType aType);
|
||||
explicit Loader(nsIDocument*);
|
||||
|
||||
private:
|
||||
// Private destructor, to discourage deletion outside of Release():
|
||||
~Loader();
|
||||
|
||||
public:
|
||||
NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(Loader)
|
||||
NS_DECL_CYCLE_COLLECTION_NATIVE_CLASS(Loader)
|
||||
|
||||
void DropDocumentReference(); // notification that doc is going away
|
||||
|
||||
void SetCompatibilityMode(nsCompatibility aCompatMode)
|
||||
{ mCompatMode = aCompatMode; }
|
||||
nsCompatibility GetCompatibilityMode() { return mCompatMode; }
|
||||
nsresult SetPreferredSheet(const nsAString& aTitle);
|
||||
|
||||
// XXXbz sort out what the deal is with events! When should they fire?
|
||||
|
||||
/**
|
||||
* Load an inline style sheet. If a successful result is returned and
|
||||
* *aCompleted is false, then aObserver is guaranteed to be notified
|
||||
* asynchronously once the sheet is marked complete. If an error is
|
||||
* returned, or if *aCompleted is true, aObserver will not be notified. In
|
||||
* addition to parsing the sheet, this method will insert it into the
|
||||
* stylesheet list of this CSSLoader's document.
|
||||
*
|
||||
* @param aElement the element linking to the stylesheet. This must not be
|
||||
* null and must implement nsIStyleSheetLinkingElement.
|
||||
* @param aBuffer the stylesheet data
|
||||
* @param aLineNumber the line number at which the stylesheet data started.
|
||||
* @param aTitle the title of the sheet.
|
||||
* @param aMedia the media string for the sheet.
|
||||
* @param aObserver the observer to notify when the load completes.
|
||||
* May be null.
|
||||
* @param [out] aCompleted whether parsing of the sheet completed.
|
||||
* @param [out] aIsAlternate whether the stylesheet ended up being an
|
||||
* alternate sheet.
|
||||
*/
|
||||
nsresult LoadInlineStyle(nsIContent* aElement,
|
||||
const nsAString& aBuffer,
|
||||
uint32_t aLineNumber,
|
||||
const nsAString& aTitle,
|
||||
const nsAString& aMedia,
|
||||
mozilla::dom::Element* aScopeElement,
|
||||
nsICSSLoaderObserver* aObserver,
|
||||
bool* aCompleted,
|
||||
bool* aIsAlternate);
|
||||
|
||||
/**
|
||||
* Load a linked (document) stylesheet. If a successful result is returned,
|
||||
* aObserver is guaranteed to be notified asynchronously once the sheet is
|
||||
* loaded and marked complete. If an error is returned, aObserver will not
|
||||
* be notified. In addition to loading the sheet, this method will insert it
|
||||
* into the stylesheet list of this CSSLoader's document.
|
||||
*
|
||||
* @param aElement the element linking to the the stylesheet. May be null.
|
||||
* @param aURL the URL of the sheet.
|
||||
* @param aTitle the title of the sheet.
|
||||
* @param aMedia the media string for the sheet.
|
||||
* @param aHasAlternateRel whether the rel for this link included
|
||||
* "alternate".
|
||||
* @param aCORSMode the CORS mode for this load.
|
||||
* @param aObserver the observer to notify when the load completes.
|
||||
* May be null.
|
||||
* @param [out] aIsAlternate whether the stylesheet actually ended up beinga
|
||||
* an alternate sheet. Note that this need not match
|
||||
* aHasAlternateRel.
|
||||
*/
|
||||
nsresult LoadStyleLink(nsIContent* aElement,
|
||||
nsIURI* aURL,
|
||||
const nsAString& aTitle,
|
||||
const nsAString& aMedia,
|
||||
bool aHasAlternateRel,
|
||||
CORSMode aCORSMode,
|
||||
ReferrerPolicy aReferrerPolicy,
|
||||
const nsAString& aIntegrity,
|
||||
nsICSSLoaderObserver* aObserver,
|
||||
bool* aIsAlternate);
|
||||
|
||||
/**
|
||||
* Load a child (@import-ed) style sheet. In addition to loading the sheet,
|
||||
* this method will insert it into the child sheet list of aParentSheet. If
|
||||
* there is no sheet currently being parsed and the child sheet is not
|
||||
* complete when this method returns, then when the child sheet becomes
|
||||
* complete aParentSheet will be QIed to nsICSSLoaderObserver and
|
||||
* asynchronously notified, just like for LoadStyleLink. Note that if the
|
||||
* child sheet is already complete when this method returns, no
|
||||
* nsICSSLoaderObserver notification will be sent.
|
||||
*
|
||||
* @param aParentSheet the parent of this child sheet
|
||||
* @param aURL the URL of the child sheet
|
||||
* @param aMedia the already-parsed media list for the child sheet
|
||||
* @param aRule the @import rule importing this child. This is used to
|
||||
* properly order the child sheet list of aParentSheet.
|
||||
* @param aSavedSheets any saved style sheets which could be reused
|
||||
* for this load
|
||||
*/
|
||||
nsresult LoadChildSheet(StyleSheet* aParentSheet,
|
||||
nsIURI* aURL,
|
||||
nsMediaList* aMedia,
|
||||
ImportRule* aRule,
|
||||
LoaderReusableStyleSheets* aSavedSheets);
|
||||
|
||||
/**
|
||||
* Synchronously load and return the stylesheet at aURL. Any child sheets
|
||||
* will also be loaded synchronously. Note that synchronous loads over some
|
||||
* protocols may involve spinning up a new event loop, so use of this method
|
||||
* does NOT guarantee not receiving any events before the sheet loads. This
|
||||
* method can be used to load sheets not associated with a document.
|
||||
*
|
||||
* @param aURL the URL of the sheet to load
|
||||
* @param aParsingMode the mode in which to parse the sheet
|
||||
* (see comments at enum SheetParsingMode, above).
|
||||
* @param aUseSystemPrincipal if true, give the resulting sheet the system
|
||||
* principal no matter where it's being loaded from.
|
||||
* @param [out] aSheet the loaded, complete sheet.
|
||||
*
|
||||
* NOTE: At the moment, this method assumes the sheet will be UTF-8, but
|
||||
* ideally it would allow arbitrary encodings. Callers should NOT depend on
|
||||
* non-UTF8 sheets being treated as UTF-8 by this method.
|
||||
*
|
||||
* NOTE: A successful return from this method doesn't indicate anything about
|
||||
* whether the data could be parsed as CSS and doesn't indicate anything
|
||||
* about the status of child sheets of the returned sheet.
|
||||
*/
|
||||
nsresult LoadSheetSync(nsIURI* aURL,
|
||||
SheetParsingMode aParsingMode,
|
||||
bool aUseSystemPrincipal,
|
||||
RefPtr<StyleSheet>* aSheet);
|
||||
|
||||
/**
|
||||
* As above, but defaults aParsingMode to eAuthorSheetFeatures and
|
||||
* aUseSystemPrincipal to false.
|
||||
*/
|
||||
nsresult LoadSheetSync(nsIURI* aURL, RefPtr<StyleSheet>* aSheet) {
|
||||
return LoadSheetSync(aURL, eAuthorSheetFeatures, false, aSheet);
|
||||
}
|
||||
|
||||
/**
|
||||
* Asynchronously load the stylesheet at aURL. If a successful result is
|
||||
* returned, aObserver is guaranteed to be notified asynchronously once the
|
||||
* sheet is loaded and marked complete. This method can be used to load
|
||||
* sheets not associated with a document. This method cannot be used to
|
||||
* load user or agent sheets.
|
||||
*
|
||||
* @param aURL the URL of the sheet to load
|
||||
* @param aOriginPrincipal the principal to use for security checks. This
|
||||
* can be null to indicate that these checks should
|
||||
* be skipped.
|
||||
* @param aCharset the encoding to use for converting the sheet data
|
||||
* from bytes to Unicode. May be empty to indicate that the
|
||||
* charset of the CSSLoader's document should be used. This
|
||||
* is only used if neither the network transport nor the
|
||||
* sheet itself indicate an encoding.
|
||||
* @param aObserver the observer to notify when the load completes.
|
||||
* Must not be null.
|
||||
* @param [out] aSheet the sheet to load. Note that the sheet may well
|
||||
* not be loaded by the time this method returns.
|
||||
*/
|
||||
nsresult LoadSheet(nsIURI* aURL,
|
||||
nsIPrincipal* aOriginPrincipal,
|
||||
const nsCString& aCharset,
|
||||
nsICSSLoaderObserver* aObserver,
|
||||
RefPtr<StyleSheet>* aSheet);
|
||||
|
||||
/**
|
||||
* Same as above, to be used when the caller doesn't care about the
|
||||
* not-yet-loaded sheet.
|
||||
*/
|
||||
nsresult LoadSheet(nsIURI* aURL,
|
||||
bool aIsPreload,
|
||||
nsIPrincipal* aOriginPrincipal,
|
||||
const nsCString& aCharset,
|
||||
nsICSSLoaderObserver* aObserver,
|
||||
CORSMode aCORSMode = CORS_NONE,
|
||||
ReferrerPolicy aReferrerPolicy = mozilla::net::RP_Default,
|
||||
const nsAString& aIntegrity = EmptyString());
|
||||
|
||||
/**
|
||||
* Stop loading all sheets. All nsICSSLoaderObservers involved will be
|
||||
* notified with NS_BINDING_ABORTED as the status, possibly synchronously.
|
||||
*/
|
||||
nsresult Stop(void);
|
||||
|
||||
/**
|
||||
* nsresult Loader::StopLoadingSheet(nsIURI* aURL), which notifies the
|
||||
* nsICSSLoaderObserver with NS_BINDING_ABORTED, was removed in Bug 556446.
|
||||
* It can be found in revision 2c44a32052ad.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Whether the loader is enabled or not.
|
||||
* When disabled, processing of new styles is disabled and an attempt
|
||||
* to do so will fail with a return code of
|
||||
* NS_ERROR_NOT_AVAILABLE. Note that this DOES NOT disable
|
||||
* currently loading styles or already processed styles.
|
||||
*/
|
||||
bool GetEnabled() { return mEnabled; }
|
||||
void SetEnabled(bool aEnabled) { mEnabled = aEnabled; }
|
||||
|
||||
/**
|
||||
* Get the document we live for. May return null.
|
||||
*/
|
||||
nsIDocument* GetDocument() const { return mDocument; }
|
||||
|
||||
/**
|
||||
* Return true if this loader has pending loads (ones that would send
|
||||
* notifications to an nsICSSLoaderObserver attached to this loader).
|
||||
* If called from inside nsICSSLoaderObserver::StyleSheetLoaded, this will
|
||||
* return false if and only if that is the last StyleSheetLoaded
|
||||
* notification the CSSLoader knows it's going to send. In other words, if
|
||||
* two sheets load at once (via load coalescing, e.g.), HasPendingLoads()
|
||||
* will return true during notification for the first one, and false
|
||||
* during notification for the second one.
|
||||
*/
|
||||
bool HasPendingLoads();
|
||||
|
||||
/**
|
||||
* Add an observer to this loader. The observer will be notified
|
||||
* for all loads that would have notified their own observers (even
|
||||
* if those loads don't have observers attached to them).
|
||||
* Load-specific observers will be notified before generic
|
||||
* observers. The loader holds a reference to the observer.
|
||||
*
|
||||
* aObserver must not be null.
|
||||
*/
|
||||
nsresult AddObserver(nsICSSLoaderObserver* aObserver);
|
||||
|
||||
/**
|
||||
* Remove an observer added via AddObserver.
|
||||
*/
|
||||
void RemoveObserver(nsICSSLoaderObserver* aObserver);
|
||||
|
||||
// These interfaces are public only for the benefit of static functions
|
||||
// within nsCSSLoader.cpp.
|
||||
|
||||
// IsAlternate can change our currently selected style set if none
|
||||
// is selected and aHasAlternateRel is false.
|
||||
bool IsAlternate(const nsAString& aTitle, bool aHasAlternateRel);
|
||||
|
||||
typedef nsTArray<RefPtr<SheetLoadData> > LoadDataArray;
|
||||
|
||||
// Measure our size.
|
||||
size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const;
|
||||
|
||||
// Marks all the sheets at the given URI obsolete, and removes them from the
|
||||
// cache.
|
||||
nsresult ObsoleteSheet(nsIURI* aURI);
|
||||
|
||||
private:
|
||||
friend class SheetLoadData;
|
||||
|
||||
nsresult CheckContentPolicy(nsIPrincipal* aSourcePrincipal,
|
||||
nsIURI* aTargetURI,
|
||||
nsISupports* aContext,
|
||||
bool aIsPreload);
|
||||
|
||||
// For inline style, the aURI param is null, but the aLinkingContent
|
||||
// must be non-null then. The loader principal must never be null
|
||||
// if aURI is not null.
|
||||
// *aIsAlternate is set based on aTitle and aHasAlternateRel.
|
||||
nsresult CreateSheet(nsIURI* aURI,
|
||||
nsIContent* aLinkingContent,
|
||||
nsIPrincipal* aLoaderPrincipal,
|
||||
css::SheetParsingMode aParsingMode,
|
||||
CORSMode aCORSMode,
|
||||
ReferrerPolicy aReferrerPolicy,
|
||||
const nsAString& aIntegrity,
|
||||
bool aSyncLoad,
|
||||
bool aHasAlternateRel,
|
||||
const nsAString& aTitle,
|
||||
StyleSheetState& aSheetState,
|
||||
bool *aIsAlternate,
|
||||
RefPtr<StyleSheet>* aSheet);
|
||||
|
||||
// Pass in either a media string or the nsMediaList from the
|
||||
// CSSParser. Don't pass both.
|
||||
// This method will set the sheet's enabled state based on isAlternate
|
||||
void PrepareSheet(StyleSheet* aSheet,
|
||||
const nsAString& aTitle,
|
||||
const nsAString& aMediaString,
|
||||
nsMediaList* aMediaList,
|
||||
dom::Element* aScopeElement,
|
||||
bool isAlternate);
|
||||
|
||||
nsresult InsertSheetInDoc(StyleSheet* aSheet,
|
||||
nsIContent* aLinkingContent,
|
||||
nsIDocument* aDocument);
|
||||
|
||||
nsresult InsertChildSheet(StyleSheet* aSheet,
|
||||
StyleSheet* aParentSheet,
|
||||
ImportRule* aParentRule);
|
||||
|
||||
nsresult InternalLoadNonDocumentSheet(nsIURI* aURL,
|
||||
bool aIsPreload,
|
||||
SheetParsingMode aParsingMode,
|
||||
bool aUseSystemPrincipal,
|
||||
nsIPrincipal* aOriginPrincipal,
|
||||
const nsCString& aCharset,
|
||||
RefPtr<StyleSheet>* aSheet,
|
||||
nsICSSLoaderObserver* aObserver,
|
||||
CORSMode aCORSMode = CORS_NONE,
|
||||
ReferrerPolicy aReferrerPolicy = mozilla::net::RP_Default,
|
||||
const nsAString& aIntegrity = EmptyString());
|
||||
|
||||
// Post a load event for aObserver to be notified about aSheet. The
|
||||
// notification will be sent with status NS_OK unless the load event is
|
||||
// canceled at some point (in which case it will be sent with
|
||||
// NS_BINDING_ABORTED). aWasAlternate indicates the state when the load was
|
||||
// initiated, not the state at some later time. aURI should be the URI the
|
||||
// sheet was loaded from (may be null for inline sheets). aElement is the
|
||||
// owning element for this sheet.
|
||||
nsresult PostLoadEvent(nsIURI* aURI,
|
||||
StyleSheet* aSheet,
|
||||
nsICSSLoaderObserver* aObserver,
|
||||
bool aWasAlternate,
|
||||
nsIStyleSheetLinkingElement* aElement);
|
||||
|
||||
// Start the loads of all the sheets in mPendingDatas
|
||||
void StartAlternateLoads();
|
||||
|
||||
// Handle an event posted by PostLoadEvent
|
||||
void HandleLoadEvent(SheetLoadData* aEvent);
|
||||
|
||||
// Note: LoadSheet is responsible for releasing aLoadData and setting the
|
||||
// sheet to complete on failure.
|
||||
nsresult LoadSheet(SheetLoadData* aLoadData,
|
||||
StyleSheetState aSheetState,
|
||||
bool aIsPreLoad);
|
||||
|
||||
// Parse the stylesheet in aLoadData. The sheet data comes from aInput.
|
||||
// Set aCompleted to true if the parse finished, false otherwise (e.g. if the
|
||||
// sheet had an @import). If aCompleted is true when this returns, then
|
||||
// ParseSheet also called SheetComplete on aLoadData.
|
||||
nsresult ParseSheet(const nsAString& aInput,
|
||||
SheetLoadData* aLoadData,
|
||||
bool& aCompleted);
|
||||
|
||||
// The load of the sheet in aLoadData is done, one way or another. Do final
|
||||
// cleanup, including releasing aLoadData.
|
||||
void SheetComplete(SheetLoadData* aLoadData, nsresult aStatus);
|
||||
|
||||
// The guts of SheetComplete. This may be called recursively on parent datas
|
||||
// or datas that had glommed on to a single load. The array is there so load
|
||||
// datas whose observers need to be notified can be added to it.
|
||||
void DoSheetComplete(SheetLoadData* aLoadData, nsresult aStatus,
|
||||
LoadDataArray& aDatasToNotify);
|
||||
|
||||
StyleBackendType GetStyleBackendType() const;
|
||||
|
||||
struct Sheets {
|
||||
nsBaseHashtable<URIPrincipalReferrerPolicyAndCORSModeHashKey,
|
||||
RefPtr<StyleSheet>,
|
||||
StyleSheet*> mCompleteSheets;
|
||||
nsDataHashtable<URIPrincipalReferrerPolicyAndCORSModeHashKey, SheetLoadData*>
|
||||
mLoadingDatas; // weak refs
|
||||
nsDataHashtable<URIPrincipalReferrerPolicyAndCORSModeHashKey, SheetLoadData*>
|
||||
mPendingDatas; // weak refs
|
||||
};
|
||||
nsAutoPtr<Sheets> mSheets;
|
||||
|
||||
// We're not likely to have many levels of @import... But likely to have
|
||||
// some. Allocate some storage, what the hell.
|
||||
AutoTArray<SheetLoadData*, 8> mParsingDatas;
|
||||
|
||||
// The array of posted stylesheet loaded events (SheetLoadDatas) we have.
|
||||
// Note that these are rare.
|
||||
LoadDataArray mPostedEvents;
|
||||
|
||||
// Our array of "global" observers
|
||||
nsTObserverArray<nsCOMPtr<nsICSSLoaderObserver> > mObservers;
|
||||
|
||||
// This reference is nulled by the Document in it's destructor through
|
||||
// DropDocumentReference().
|
||||
nsIDocument* MOZ_NON_OWNING_REF mDocument; // the document we live for
|
||||
|
||||
|
||||
// Number of datas still waiting to be notified on if we're notifying on a
|
||||
// whole bunch at once (e.g. in one of the stop methods). This is used to
|
||||
// make sure that HasPendingLoads() won't return false until we're notifying
|
||||
// on the last data we're working with.
|
||||
uint32_t mDatasToNotifyOn;
|
||||
|
||||
nsCompatibility mCompatMode;
|
||||
nsString mPreferredSheet; // title of preferred sheet
|
||||
|
||||
// Set explicitly when the Loader(StyleBackendType) constructor is used, or
|
||||
// taken from the document when the Loader(nsIDocument*) constructor is used.
|
||||
mozilla::Maybe<StyleBackendType> mStyleBackendType;
|
||||
|
||||
bool mEnabled; // is enabled to load new styles
|
||||
|
||||
nsCOMPtr<nsIConsoleReportCollector> mReporter;
|
||||
|
||||
#ifdef DEBUG
|
||||
bool mSyncCallback;
|
||||
#endif
|
||||
};
|
||||
|
||||
} // namespace css
|
||||
} // namespace mozilla
|
||||
|
||||
#endif /* mozilla_css_Loader_h */
|
||||
16
layout/style/Makefile.in
Normal file
16
layout/style/Makefile.in
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
# 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/.
|
||||
|
||||
# TODO This list should be emitted to a .pp file via
|
||||
# GenerateCSSPropsGenerated.py (bug 1281614)
|
||||
csspropsidlnames_dependencies = \
|
||||
$(srcdir)/nsCSSPropList.h \
|
||||
$(srcdir)/nsCSSPropAliasList.h \
|
||||
$(srcdir)/nsCSSPropsGenerated.inc.in \
|
||||
$(srcdir)/PythonCSSProps.h \
|
||||
$(srcdir)/GenerateCSSPropsGenerated.py \
|
||||
$(GLOBAL_DEPS) \
|
||||
$(NULL)
|
||||
|
||||
nsCSSPropsGenerated.inc : $(csspropsidlnames_dependencies)
|
||||
207
layout/style/MediaQueryList.cpp
Normal file
207
layout/style/MediaQueryList.cpp
Normal file
|
|
@ -0,0 +1,207 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set shiftwidth=2 tabstop=8 autoindent cindent expandtab: */
|
||||
/* 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/. */
|
||||
|
||||
/* implements DOM interface for querying and observing media queries */
|
||||
|
||||
#include "mozilla/dom/MediaQueryList.h"
|
||||
#include "nsPresContext.h"
|
||||
#include "nsIMediaList.h"
|
||||
#include "nsCSSParser.h"
|
||||
#include "nsIDocument.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
MediaQueryList::MediaQueryList(nsIDocument *aDocument,
|
||||
const nsAString &aMediaQueryList)
|
||||
: mDocument(aDocument),
|
||||
mMediaList(new nsMediaList),
|
||||
mMatchesValid(false)
|
||||
{
|
||||
PR_INIT_CLIST(this);
|
||||
|
||||
nsCSSParser parser;
|
||||
parser.ParseMediaList(aMediaQueryList, nullptr, 0, mMediaList, false);
|
||||
}
|
||||
|
||||
MediaQueryList::~MediaQueryList()
|
||||
{
|
||||
if (mDocument) {
|
||||
PR_REMOVE_LINK(this);
|
||||
}
|
||||
}
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_CLASS(MediaQueryList)
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(MediaQueryList)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDocument)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mCallbacks)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(MediaQueryList)
|
||||
if (tmp->mDocument) {
|
||||
PR_REMOVE_LINK(tmp);
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK(mDocument)
|
||||
}
|
||||
tmp->RemoveAllListeners();
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_TRACE_WRAPPERCACHE(MediaQueryList)
|
||||
|
||||
NS_INTERFACE_MAP_BEGIN(MediaQueryList)
|
||||
NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
|
||||
NS_INTERFACE_MAP_ENTRY(nsISupports)
|
||||
NS_INTERFACE_MAP_ENTRIES_CYCLE_COLLECTION(MediaQueryList)
|
||||
NS_INTERFACE_MAP_END
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTING_ADDREF(MediaQueryList)
|
||||
NS_IMPL_CYCLE_COLLECTING_RELEASE(MediaQueryList)
|
||||
|
||||
void
|
||||
MediaQueryList::GetMedia(nsAString &aMedia)
|
||||
{
|
||||
mMediaList->GetText(aMedia);
|
||||
}
|
||||
|
||||
bool
|
||||
MediaQueryList::Matches()
|
||||
{
|
||||
if (!mMatchesValid) {
|
||||
MOZ_ASSERT(!HasListeners(),
|
||||
"when listeners present, must keep mMatches current");
|
||||
RecomputeMatches();
|
||||
}
|
||||
|
||||
return mMatches;
|
||||
}
|
||||
|
||||
void
|
||||
MediaQueryList::AddListener(MediaQueryListListener& aListener)
|
||||
{
|
||||
if (!HasListeners()) {
|
||||
// When we have listeners, the pres context owns a reference to
|
||||
// this. This is a cyclic reference that can only be broken by
|
||||
// cycle collection.
|
||||
NS_ADDREF_THIS();
|
||||
}
|
||||
|
||||
if (!mMatchesValid) {
|
||||
MOZ_ASSERT(!HasListeners(),
|
||||
"when listeners present, must keep mMatches current");
|
||||
RecomputeMatches();
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < mCallbacks.Length(); ++i) {
|
||||
if (aListener == *mCallbacks[i]) {
|
||||
// Already registered
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (!mCallbacks.AppendElement(&aListener, fallible)) {
|
||||
if (!HasListeners()) {
|
||||
// Append failed; undo the AddRef above.
|
||||
NS_RELEASE_THIS();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
MediaQueryList::RemoveListener(MediaQueryListListener& aListener)
|
||||
{
|
||||
for (uint32_t i = 0; i < mCallbacks.Length(); ++i) {
|
||||
if (aListener == *mCallbacks[i]) {
|
||||
mCallbacks.RemoveElementAt(i);
|
||||
if (!HasListeners()) {
|
||||
// See NS_ADDREF_THIS() in AddListener.
|
||||
NS_RELEASE_THIS();
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
MediaQueryList::RemoveAllListeners()
|
||||
{
|
||||
bool hadListeners = HasListeners();
|
||||
mCallbacks.Clear();
|
||||
if (hadListeners) {
|
||||
// See NS_ADDREF_THIS() in AddListener.
|
||||
NS_RELEASE_THIS();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
MediaQueryList::RecomputeMatches()
|
||||
{
|
||||
if (!mDocument) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (mDocument->GetParentDocument()) {
|
||||
// Flush frames on the parent so our prescontext will get
|
||||
// recreated as needed.
|
||||
mDocument->GetParentDocument()->FlushPendingNotifications(Flush_Frames);
|
||||
// That might have killed our document, so recheck that.
|
||||
if (!mDocument) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
nsIPresShell* shell = mDocument->GetShell();
|
||||
if (!shell) {
|
||||
// XXXbz What's the right behavior here? Spec doesn't say.
|
||||
return;
|
||||
}
|
||||
|
||||
nsPresContext* presContext = shell->GetPresContext();
|
||||
if (!presContext) {
|
||||
// XXXbz What's the right behavior here? Spec doesn't say.
|
||||
return;
|
||||
}
|
||||
|
||||
mMatches = mMediaList->Matches(presContext, nullptr);
|
||||
mMatchesValid = true;
|
||||
}
|
||||
|
||||
void
|
||||
MediaQueryList::MediumFeaturesChanged(
|
||||
nsTArray<HandleChangeData>& aListenersToNotify)
|
||||
{
|
||||
mMatchesValid = false;
|
||||
|
||||
if (HasListeners()) {
|
||||
bool oldMatches = mMatches;
|
||||
RecomputeMatches();
|
||||
if (mMatches != oldMatches) {
|
||||
for (uint32_t i = 0, i_end = mCallbacks.Length(); i != i_end; ++i) {
|
||||
HandleChangeData *d = aListenersToNotify.AppendElement(fallible);
|
||||
if (d) {
|
||||
d->mql = this;
|
||||
d->callback = mCallbacks[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
nsISupports*
|
||||
MediaQueryList::GetParentObject() const
|
||||
{
|
||||
return mDocument;
|
||||
}
|
||||
|
||||
JSObject*
|
||||
MediaQueryList::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
|
||||
{
|
||||
return MediaQueryListBinding::Wrap(aCx, this, aGivenProto);
|
||||
}
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
93
layout/style/MediaQueryList.h
Normal file
93
layout/style/MediaQueryList.h
Normal file
|
|
@ -0,0 +1,93 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set shiftwidth=2 tabstop=8 autoindent cindent expandtab: */
|
||||
/* 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/. */
|
||||
|
||||
/* implements DOM interface for querying and observing media queries */
|
||||
|
||||
#ifndef mozilla_dom_MediaQueryList_h
|
||||
#define mozilla_dom_MediaQueryList_h
|
||||
|
||||
#include "nsISupports.h"
|
||||
#include "nsCycleCollectionParticipant.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsTArray.h"
|
||||
#include "prclist.h"
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "nsWrapperCache.h"
|
||||
#include "mozilla/dom/MediaQueryListBinding.h"
|
||||
|
||||
class nsIDocument;
|
||||
class nsMediaList;
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
class MediaQueryList final : public nsISupports,
|
||||
public nsWrapperCache,
|
||||
public PRCList
|
||||
{
|
||||
public:
|
||||
// The caller who constructs is responsible for calling Evaluate
|
||||
// before calling any other methods.
|
||||
MediaQueryList(nsIDocument *aDocument,
|
||||
const nsAString &aMediaQueryList);
|
||||
private:
|
||||
~MediaQueryList();
|
||||
|
||||
public:
|
||||
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
|
||||
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(MediaQueryList)
|
||||
|
||||
nsISupports* GetParentObject() const;
|
||||
|
||||
struct HandleChangeData {
|
||||
RefPtr<MediaQueryList> mql;
|
||||
RefPtr<mozilla::dom::MediaQueryListListener> callback;
|
||||
};
|
||||
|
||||
// Appends listeners that need notification to aListenersToNotify
|
||||
void MediumFeaturesChanged(nsTArray<HandleChangeData>& aListenersToNotify);
|
||||
|
||||
bool HasListeners() const { return !mCallbacks.IsEmpty(); }
|
||||
|
||||
void RemoveAllListeners();
|
||||
|
||||
JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
|
||||
|
||||
// WebIDL methods
|
||||
void GetMedia(nsAString& aMedia);
|
||||
bool Matches();
|
||||
void AddListener(mozilla::dom::MediaQueryListListener& aListener);
|
||||
void RemoveListener(mozilla::dom::MediaQueryListListener& aListener);
|
||||
|
||||
private:
|
||||
void RecomputeMatches();
|
||||
|
||||
// We only need a pointer to the document to support lazy
|
||||
// reevaluation following dynamic changes. However, this lazy
|
||||
// reevaluation is perhaps somewhat important, since some usage
|
||||
// patterns may involve the creation of large numbers of
|
||||
// MediaQueryList objects which almost immediately become garbage
|
||||
// (after a single call to the .matches getter).
|
||||
//
|
||||
// This pointer does make us a little more dependent on cycle
|
||||
// collection.
|
||||
//
|
||||
// We have a non-null mDocument for our entire lifetime except
|
||||
// after cycle collection unlinking. Having a non-null mDocument
|
||||
// is equivalent to being in that document's mDOMMediaQueryLists
|
||||
// linked list.
|
||||
nsCOMPtr<nsIDocument> mDocument;
|
||||
|
||||
RefPtr<nsMediaList> mMediaList;
|
||||
bool mMatches;
|
||||
bool mMatchesValid;
|
||||
nsTArray<RefPtr<mozilla::dom::MediaQueryListListener>> mCallbacks;
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
#endif /* !defined(mozilla_dom_MediaQueryList_h) */
|
||||
70
layout/style/NameSpaceRule.h
Normal file
70
layout/style/NameSpaceRule.h
Normal file
|
|
@ -0,0 +1,70 @@
|
|||
/* -*- Mode: C++; 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/. */
|
||||
|
||||
/* class for CSS @namespace rules */
|
||||
|
||||
#ifndef mozilla_css_NameSpaceRule_h__
|
||||
#define mozilla_css_NameSpaceRule_h__
|
||||
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "mozilla/MemoryReporting.h"
|
||||
#include "mozilla/css/Rule.h"
|
||||
|
||||
#include "nsIDOMCSSRule.h"
|
||||
|
||||
class nsIAtom;
|
||||
|
||||
// IID for the NameSpaceRule class {f0b0dbe1-5031-4a21-b06a-dc141ef2af98}
|
||||
#define NS_CSS_NAMESPACE_RULE_IMPL_CID \
|
||||
{0xf0b0dbe1, 0x5031, 0x4a21, {0xb0, 0x6a, 0xdc, 0x14, 0x1e, 0xf2, 0xaf, 0x98}}
|
||||
|
||||
|
||||
namespace mozilla {
|
||||
namespace css {
|
||||
|
||||
class NameSpaceRule final : public Rule,
|
||||
public nsIDOMCSSRule
|
||||
{
|
||||
public:
|
||||
NameSpaceRule(nsIAtom* aPrefix, const nsString& aURLSpec,
|
||||
uint32_t aLineNumber, uint32_t aColumnNumber);
|
||||
private:
|
||||
// for |Clone|
|
||||
NameSpaceRule(const NameSpaceRule& aCopy);
|
||||
~NameSpaceRule();
|
||||
public:
|
||||
NS_DECLARE_STATIC_IID_ACCESSOR(NS_CSS_NAMESPACE_RULE_IMPL_CID)
|
||||
|
||||
NS_DECL_ISUPPORTS
|
||||
|
||||
// Rule methods
|
||||
DECL_STYLE_RULE_INHERIT
|
||||
#ifdef DEBUG
|
||||
virtual void List(FILE* out = stdout, int32_t aIndent = 0) const override;
|
||||
#endif
|
||||
virtual int32_t GetType() const override;
|
||||
virtual already_AddRefed<Rule> Clone() const override;
|
||||
|
||||
nsIAtom* GetPrefix() const { return mPrefix; }
|
||||
|
||||
void GetURLSpec(nsString& aURLSpec) const { aURLSpec = mURLSpec; }
|
||||
|
||||
virtual size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const
|
||||
override MOZ_MUST_OVERRIDE;
|
||||
|
||||
// nsIDOMCSSRule interface
|
||||
NS_DECL_NSIDOMCSSRULE
|
||||
|
||||
private:
|
||||
nsCOMPtr<nsIAtom> mPrefix;
|
||||
nsString mURLSpec;
|
||||
};
|
||||
|
||||
NS_DEFINE_STATIC_IID_ACCESSOR(NameSpaceRule, NS_CSS_NAMESPACE_RULE_IMPL_CID)
|
||||
|
||||
} // namespace css
|
||||
} // namespace mozilla
|
||||
|
||||
#endif /* mozilla_css_NameSpaceRule_h__ */
|
||||
41
layout/style/PythonCSSProps.h
Normal file
41
layout/style/PythonCSSProps.h
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
/* A file meant as input to the preprocessor only */
|
||||
|
||||
/* DO_PROP serves as an extra level of indirection to allow expansion
|
||||
of CSS_PROP_DOMPROP_PREFIXED */
|
||||
|
||||
[
|
||||
|
||||
#define PROP_STRINGIFY_INTERNAL(X) #X
|
||||
#define PROP_STRINGIFY(X) PROP_STRINGIFY_INTERNAL(X)
|
||||
|
||||
#define DO_PROP(name, method, id, flags, pref, proptype) \
|
||||
[ #name, #method, #id, PROP_STRINGIFY(flags), pref, proptype ],
|
||||
#define CSS_PROP(name, id, method, flags, pref, parsevariant, kwtable, \
|
||||
stylestruct, stylestructoffset, animtype) \
|
||||
DO_PROP(name, method, id, flags, pref, "longhand")
|
||||
#define CSS_PROP_SHORTHAND(name, id, method, flags, pref) \
|
||||
DO_PROP(name, method, id, flags, pref, "shorthand")
|
||||
#define CSS_PROP_LOGICAL(name, id, method, flags, pref, parsevariant, kwtable, \
|
||||
group, stylestruct, stylestructoffset, animtype) \
|
||||
DO_PROP(name, method, id, flags, pref, "logical")
|
||||
#define CSS_PROP_PUBLIC_OR_PRIVATE(publicname_, privatename_) publicname_
|
||||
|
||||
#include "nsCSSPropList.h"
|
||||
|
||||
#undef CSS_PROP_PUBLIC_OR_PRIVATE
|
||||
#undef CSS_PROP_LOGICAL
|
||||
#undef CSS_PROP_SHORTHAND
|
||||
#undef CSS_PROP
|
||||
|
||||
#define CSS_PROP_ALIAS(name, id, method, pref) \
|
||||
DO_PROP(name, method, id, 0, pref, "alias")
|
||||
|
||||
#include "nsCSSPropAliasList.h"
|
||||
|
||||
#undef CSS_PROP_ALIAS
|
||||
|
||||
#undef DO_PROP
|
||||
#undef PROP_STRINGIFY
|
||||
#undef PROP_STRINGIFY_INTERNAL
|
||||
|
||||
]
|
||||
141
layout/style/Rule.h
Normal file
141
layout/style/Rule.h
Normal file
|
|
@ -0,0 +1,141 @@
|
|||
/* -*- Mode: C++; 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/. */
|
||||
|
||||
/* base class for all rule types in a CSS style sheet */
|
||||
|
||||
#ifndef mozilla_css_Rule_h___
|
||||
#define mozilla_css_Rule_h___
|
||||
|
||||
#include "mozilla/StyleSheetInlines.h"
|
||||
#include "mozilla/MemoryReporting.h"
|
||||
#include "nsISupports.h"
|
||||
#include "nsIDOMCSSRule.h"
|
||||
|
||||
class nsIDocument;
|
||||
struct nsRuleData;
|
||||
template<class T> struct already_AddRefed;
|
||||
class nsHTMLCSSStyleSheet;
|
||||
|
||||
namespace mozilla {
|
||||
namespace css {
|
||||
class GroupRule;
|
||||
|
||||
#define DECL_STYLE_RULE_INHERIT_NO_DOMRULE \
|
||||
/* nothing */
|
||||
|
||||
#define DECL_STYLE_RULE_INHERIT \
|
||||
DECL_STYLE_RULE_INHERIT_NO_DOMRULE \
|
||||
virtual nsIDOMCSSRule* GetDOMRule() override; \
|
||||
virtual nsIDOMCSSRule* GetExistingDOMRule() override;
|
||||
|
||||
class Rule : public nsISupports {
|
||||
protected:
|
||||
Rule(uint32_t aLineNumber, uint32_t aColumnNumber)
|
||||
: mSheet(nullptr),
|
||||
mParentRule(nullptr),
|
||||
mLineNumber(aLineNumber),
|
||||
mColumnNumber(aColumnNumber)
|
||||
{
|
||||
}
|
||||
|
||||
Rule(const Rule& aCopy)
|
||||
: mSheet(aCopy.mSheet),
|
||||
mParentRule(aCopy.mParentRule),
|
||||
mLineNumber(aCopy.mLineNumber),
|
||||
mColumnNumber(aCopy.mColumnNumber)
|
||||
{
|
||||
}
|
||||
|
||||
virtual ~Rule() {}
|
||||
|
||||
public:
|
||||
|
||||
#ifdef DEBUG
|
||||
virtual void List(FILE* out = stdout, int32_t aIndent = 0) const = 0;
|
||||
#endif
|
||||
|
||||
// The constants in this list must maintain the following invariants:
|
||||
// If a rule of type N must appear before a rule of type M in stylesheets
|
||||
// then N < M
|
||||
// Note that CSSStyleSheet::RebuildChildList assumes that no other kinds of
|
||||
// rules can come between two rules of type IMPORT_RULE.
|
||||
enum {
|
||||
UNKNOWN_RULE = 0,
|
||||
CHARSET_RULE,
|
||||
IMPORT_RULE,
|
||||
NAMESPACE_RULE,
|
||||
STYLE_RULE,
|
||||
MEDIA_RULE,
|
||||
FONT_FACE_RULE,
|
||||
PAGE_RULE,
|
||||
KEYFRAME_RULE,
|
||||
KEYFRAMES_RULE,
|
||||
DOCUMENT_RULE,
|
||||
SUPPORTS_RULE,
|
||||
FONT_FEATURE_VALUES_RULE,
|
||||
COUNTER_STYLE_RULE
|
||||
};
|
||||
|
||||
virtual int32_t GetType() const = 0;
|
||||
|
||||
CSSStyleSheet* GetStyleSheet() const { return mSheet; }
|
||||
|
||||
// Return the document the rule lives in, if any
|
||||
nsIDocument* GetDocument() const
|
||||
{
|
||||
CSSStyleSheet* sheet = GetStyleSheet();
|
||||
return sheet ? sheet->GetDocument() : nullptr;
|
||||
}
|
||||
|
||||
virtual void SetStyleSheet(CSSStyleSheet* aSheet);
|
||||
|
||||
void SetParentRule(GroupRule* aRule) {
|
||||
// We don't reference count this up reference. The group rule
|
||||
// will tell us when it's going away or when we're detached from
|
||||
// it.
|
||||
mParentRule = aRule;
|
||||
}
|
||||
|
||||
uint32_t GetLineNumber() const { return mLineNumber; }
|
||||
uint32_t GetColumnNumber() const { return mColumnNumber; }
|
||||
|
||||
/**
|
||||
* Clones |this|. Never returns nullptr.
|
||||
*/
|
||||
virtual already_AddRefed<Rule> Clone() const = 0;
|
||||
|
||||
// Note that this returns null for inline style rules since they aren't
|
||||
// supposed to have a DOM rule representation (and our code wouldn't work).
|
||||
virtual nsIDOMCSSRule* GetDOMRule() = 0;
|
||||
|
||||
// Like GetDOMRule(), but won't create one if we don't have one yet
|
||||
virtual nsIDOMCSSRule* GetExistingDOMRule() = 0;
|
||||
|
||||
// to implement methods on nsIDOMCSSRule
|
||||
nsresult GetParentRule(nsIDOMCSSRule** aParentRule);
|
||||
nsresult GetParentStyleSheet(nsIDOMCSSStyleSheet** aSheet);
|
||||
Rule* GetCSSRule();
|
||||
|
||||
// This is pure virtual because all of Rule's data members are non-owning and
|
||||
// thus measured elsewhere.
|
||||
virtual size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf)
|
||||
const MOZ_MUST_OVERRIDE = 0;
|
||||
|
||||
protected:
|
||||
// This is sometimes null (e.g., for style attributes).
|
||||
CSSStyleSheet* mSheet;
|
||||
// When the parent GroupRule is destroyed, it will call SetParentRule(nullptr)
|
||||
// on this object. (Through SetParentRuleReference);
|
||||
GroupRule* MOZ_NON_OWNING_REF mParentRule;
|
||||
|
||||
// Keep the same type so that MSVC packs them.
|
||||
uint32_t mLineNumber;
|
||||
uint32_t mColumnNumber;
|
||||
};
|
||||
|
||||
} // namespace css
|
||||
} // namespace mozilla
|
||||
|
||||
#endif /* mozilla_css_Rule_h___ */
|
||||
53
layout/style/RuleNodeCacheConditions.cpp
Normal file
53
layout/style/RuleNodeCacheConditions.cpp
Normal file
|
|
@ -0,0 +1,53 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=2 et sw=2 tw=78: */
|
||||
/* 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/. */
|
||||
|
||||
/*
|
||||
* an object that stores the result of determining whether a style struct that
|
||||
* was computed can be cached in the rule tree, and if so, what the cache
|
||||
* key is
|
||||
*/
|
||||
|
||||
#include "RuleNodeCacheConditions.h"
|
||||
|
||||
#include "nsStyleContext.h"
|
||||
#include "WritingModes.h"
|
||||
|
||||
using namespace mozilla;
|
||||
|
||||
bool
|
||||
RuleNodeCacheConditions::Matches(nsStyleContext* aStyleContext) const
|
||||
{
|
||||
MOZ_ASSERT(Cacheable());
|
||||
if ((mBits & eHaveFontSize) &&
|
||||
mFontSize != aStyleContext->StyleFont()->mFont.size) {
|
||||
return false;
|
||||
}
|
||||
if ((mBits & eHaveWritingMode) &&
|
||||
(GetWritingMode() != WritingMode(aStyleContext).GetBits())) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
void
|
||||
RuleNodeCacheConditions::List() const
|
||||
{
|
||||
printf("{ ");
|
||||
bool first = true;
|
||||
if (mBits & eHaveFontSize) {
|
||||
printf("FontSize(%d)", mFontSize);
|
||||
first = false;
|
||||
}
|
||||
if (mBits & eHaveWritingMode) {
|
||||
if (!first) {
|
||||
printf(", ");
|
||||
}
|
||||
printf("WritingMode(0x%x)", GetWritingMode());
|
||||
}
|
||||
printf(" }");
|
||||
}
|
||||
#endif
|
||||
156
layout/style/RuleNodeCacheConditions.h
Normal file
156
layout/style/RuleNodeCacheConditions.h
Normal file
|
|
@ -0,0 +1,156 @@
|
|||
/* -*- Mode: C++; 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/. */
|
||||
|
||||
/*
|
||||
* an object that stores the result of determining whether a style struct that
|
||||
* was computed can be cached in the rule tree, and if so, what the conditions
|
||||
* it relies on are
|
||||
*/
|
||||
|
||||
#ifndef RuleNodeCacheConditions_h_
|
||||
#define RuleNodeCacheConditions_h_
|
||||
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "nsCoord.h"
|
||||
#include "nsTArray.h"
|
||||
|
||||
class nsStyleContext;
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
/**
|
||||
* nsRuleNodeCacheConditions is used to store information about whether
|
||||
* we can store a style struct that we're computing in the rule tree.
|
||||
*
|
||||
* For inherited structs (i.e., structs with inherited properties), we
|
||||
* cache the struct in the rule tree if it does not depend on any data
|
||||
* in the style context tree, and otherwise store it in the style
|
||||
* context tree. This means that for inherited structs, setting any
|
||||
* conditions is equivalent to making the struct uncacheable.
|
||||
*
|
||||
* For reset structs (i.e., structs with non-inherited properties), we
|
||||
* are also able to cache structs in the rule tree conditionally on
|
||||
* certain common conditions. For these structs, setting conditions
|
||||
* (SetFontSizeDependency, SetWritingModeDependency) instead causes the
|
||||
* struct to be stored, with the condition, in the rule tree.
|
||||
*/
|
||||
class RuleNodeCacheConditions
|
||||
{
|
||||
public:
|
||||
RuleNodeCacheConditions()
|
||||
: mFontSize(0), mBits(0) {}
|
||||
RuleNodeCacheConditions(const RuleNodeCacheConditions& aOther)
|
||||
: mFontSize(aOther.mFontSize), mBits(aOther.mBits) {}
|
||||
RuleNodeCacheConditions& operator=(const RuleNodeCacheConditions& aOther)
|
||||
{
|
||||
mFontSize = aOther.mFontSize;
|
||||
mBits = aOther.mBits;
|
||||
return *this;
|
||||
}
|
||||
bool operator==(const RuleNodeCacheConditions& aOther) const
|
||||
{
|
||||
return mFontSize == aOther.mFontSize &&
|
||||
mBits == aOther.mBits;
|
||||
}
|
||||
bool operator!=(const RuleNodeCacheConditions& aOther) const
|
||||
{
|
||||
return !(*this == aOther);
|
||||
}
|
||||
|
||||
bool Matches(nsStyleContext* aStyleContext) const;
|
||||
|
||||
/**
|
||||
* Record that the data being computed depend on the font-size
|
||||
* property of the element for which they are being computed.
|
||||
*
|
||||
* Note that we sometimes actually call this when there is a
|
||||
* dependency on the font-size property of the parent element, but we
|
||||
* only do so while computing inherited structs (nsStyleFont), and we
|
||||
* only store reset structs conditionally.
|
||||
*/
|
||||
void SetFontSizeDependency(nscoord aCoord)
|
||||
{
|
||||
MOZ_ASSERT(!(mBits & eHaveFontSize) || mFontSize == aCoord);
|
||||
mFontSize = aCoord;
|
||||
mBits |= eHaveFontSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* Record that the data being computed depend on the writing mode of
|
||||
* the element for which they are being computed, which in turn
|
||||
* depends on its 'writing-mode', 'direction', and 'text-orientation'
|
||||
* properties.
|
||||
*/
|
||||
void SetWritingModeDependency(uint8_t aWritingMode)
|
||||
{
|
||||
MOZ_ASSERT(!(mBits & eHaveWritingMode) || GetWritingMode() == aWritingMode);
|
||||
mBits |= (static_cast<uint64_t>(aWritingMode) << eWritingModeShift) |
|
||||
eHaveWritingMode;
|
||||
}
|
||||
|
||||
void SetUncacheable()
|
||||
{
|
||||
mBits |= eUncacheable;
|
||||
}
|
||||
|
||||
void Clear()
|
||||
{
|
||||
*this = RuleNodeCacheConditions();
|
||||
}
|
||||
|
||||
bool Cacheable() const
|
||||
{
|
||||
return !(mBits & eUncacheable);
|
||||
}
|
||||
|
||||
bool CacheableWithDependencies() const
|
||||
{
|
||||
return !(mBits & eUncacheable) &&
|
||||
(mBits & eHaveBitsMask) != 0;
|
||||
}
|
||||
|
||||
bool CacheableWithoutDependencies() const
|
||||
{
|
||||
// We're not uncacheable and we have don't have a font-size or
|
||||
// writing mode value.
|
||||
return (mBits & eHaveBitsMask) == 0;
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
void List() const;
|
||||
#endif
|
||||
|
||||
private:
|
||||
enum {
|
||||
eUncacheable = 0x0001,
|
||||
eHaveFontSize = 0x0002,
|
||||
eHaveWritingMode = 0x0004,
|
||||
eHaveBitsMask = 0x00ff,
|
||||
eWritingModeMask = 0xff00,
|
||||
eWritingModeShift = 8,
|
||||
};
|
||||
|
||||
uint8_t GetWritingMode() const
|
||||
{
|
||||
return static_cast<uint8_t>(
|
||||
(mBits & eWritingModeMask) >> eWritingModeShift);
|
||||
}
|
||||
|
||||
// The font size from which em units are derived.
|
||||
nscoord mFontSize;
|
||||
|
||||
// Values in mBits:
|
||||
// bit 0: are we set to "uncacheable"?
|
||||
// bit 1: do we have a font size value?
|
||||
// bit 2: do we have a writing mode value?
|
||||
// bits 3-7: unused
|
||||
// bits 8-15: writing mode (uint8_t)
|
||||
// bits 16-31: unused
|
||||
uint32_t mBits;
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // !defined(RuleNodeCacheConditions_h_)
|
||||
286
layout/style/RuleProcessorCache.cpp
Normal file
286
layout/style/RuleProcessorCache.cpp
Normal file
|
|
@ -0,0 +1,286 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* 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/. */
|
||||
|
||||
/*
|
||||
* cache of re-usable nsCSSRuleProcessors for given sets of style sheets
|
||||
*/
|
||||
|
||||
#include "RuleProcessorCache.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include "nsCSSRuleProcessor.h"
|
||||
#include "nsThreadUtils.h"
|
||||
|
||||
using namespace mozilla;
|
||||
|
||||
NS_IMPL_ISUPPORTS(RuleProcessorCache, nsIMemoryReporter)
|
||||
|
||||
MOZ_DEFINE_MALLOC_SIZE_OF(RuleProcessorCacheMallocSizeOf)
|
||||
|
||||
NS_IMETHODIMP
|
||||
RuleProcessorCache::CollectReports(nsIHandleReportCallback* aHandleReport,
|
||||
nsISupports* aData, bool aAnonymize)
|
||||
{
|
||||
MOZ_COLLECT_REPORT(
|
||||
"explicit/layout/rule-processor-cache", KIND_HEAP, UNITS_BYTES,
|
||||
SizeOfIncludingThis(RuleProcessorCacheMallocSizeOf),
|
||||
"Memory used for cached rule processors.");
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
RuleProcessorCache::~RuleProcessorCache()
|
||||
{
|
||||
UnregisterWeakMemoryReporter(this);
|
||||
|
||||
for (Entry& e : mEntries) {
|
||||
for (DocumentEntry& de : e.mDocumentEntries) {
|
||||
if (de.mRuleProcessor->GetExpirationState()->IsTracked()) {
|
||||
mExpirationTracker.RemoveObject(de.mRuleProcessor);
|
||||
}
|
||||
de.mRuleProcessor->SetInRuleProcessorCache(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
RuleProcessorCache::InitMemoryReporter()
|
||||
{
|
||||
RegisterWeakMemoryReporter(this);
|
||||
}
|
||||
|
||||
/* static */ bool
|
||||
RuleProcessorCache::EnsureGlobal()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
if (gShutdown) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!gRuleProcessorCache) {
|
||||
gRuleProcessorCache = new RuleProcessorCache;
|
||||
gRuleProcessorCache->InitMemoryReporter();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/* static */ void
|
||||
RuleProcessorCache::RemoveSheet(CSSStyleSheet* aSheet)
|
||||
{
|
||||
if (!EnsureGlobal()) {
|
||||
return;
|
||||
}
|
||||
gRuleProcessorCache->DoRemoveSheet(aSheet);
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
/* static */ bool
|
||||
RuleProcessorCache::HasRuleProcessor(nsCSSRuleProcessor* aRuleProcessor)
|
||||
{
|
||||
if (!EnsureGlobal()) {
|
||||
return false;
|
||||
}
|
||||
return gRuleProcessorCache->DoHasRuleProcessor(aRuleProcessor);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* static */ void
|
||||
RuleProcessorCache::RemoveRuleProcessor(nsCSSRuleProcessor* aRuleProcessor)
|
||||
{
|
||||
if (!EnsureGlobal()) {
|
||||
return;
|
||||
}
|
||||
gRuleProcessorCache->DoRemoveRuleProcessor(aRuleProcessor);
|
||||
}
|
||||
|
||||
/* static */ nsCSSRuleProcessor*
|
||||
RuleProcessorCache::GetRuleProcessor(const nsTArray<CSSStyleSheet*>& aSheets,
|
||||
nsPresContext* aPresContext)
|
||||
{
|
||||
if (!EnsureGlobal()) {
|
||||
return nullptr;
|
||||
}
|
||||
return gRuleProcessorCache->DoGetRuleProcessor(aSheets, aPresContext);
|
||||
}
|
||||
|
||||
/* static */ void
|
||||
RuleProcessorCache::PutRuleProcessor(
|
||||
const nsTArray<CSSStyleSheet*>& aSheets,
|
||||
nsTArray<css::DocumentRule*>&& aDocumentRulesInSheets,
|
||||
const nsDocumentRuleResultCacheKey& aCacheKey,
|
||||
nsCSSRuleProcessor* aRuleProcessor)
|
||||
{
|
||||
if (!EnsureGlobal()) {
|
||||
return;
|
||||
}
|
||||
gRuleProcessorCache->DoPutRuleProcessor(aSheets, Move(aDocumentRulesInSheets),
|
||||
aCacheKey, aRuleProcessor);
|
||||
}
|
||||
|
||||
/* static */ void
|
||||
RuleProcessorCache::StartTracking(nsCSSRuleProcessor* aRuleProcessor)
|
||||
{
|
||||
if (!EnsureGlobal()) {
|
||||
return;
|
||||
}
|
||||
return gRuleProcessorCache->DoStartTracking(aRuleProcessor);
|
||||
}
|
||||
|
||||
/* static */ void
|
||||
RuleProcessorCache::StopTracking(nsCSSRuleProcessor* aRuleProcessor)
|
||||
{
|
||||
if (!EnsureGlobal()) {
|
||||
return;
|
||||
}
|
||||
return gRuleProcessorCache->DoStopTracking(aRuleProcessor);
|
||||
}
|
||||
|
||||
void
|
||||
RuleProcessorCache::DoRemoveSheet(CSSStyleSheet* aSheet)
|
||||
{
|
||||
Entry* last = std::remove_if(mEntries.begin(), mEntries.end(),
|
||||
HasSheet_ThenRemoveRuleProcessors(this, aSheet));
|
||||
mEntries.TruncateLength(last - mEntries.begin());
|
||||
}
|
||||
|
||||
nsCSSRuleProcessor*
|
||||
RuleProcessorCache::DoGetRuleProcessor(const nsTArray<CSSStyleSheet*>& aSheets,
|
||||
nsPresContext* aPresContext)
|
||||
{
|
||||
for (Entry& e : mEntries) {
|
||||
if (e.mSheets == aSheets) {
|
||||
for (DocumentEntry& de : e.mDocumentEntries) {
|
||||
if (de.mCacheKey.Matches(aPresContext, e.mDocumentRulesInSheets)) {
|
||||
return de.mRuleProcessor;
|
||||
}
|
||||
}
|
||||
// Entry::mSheets is unique; if we matched aSheets but didn't
|
||||
// find a matching DocumentEntry, we won't find one later in
|
||||
// mEntries.
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void
|
||||
RuleProcessorCache::DoPutRuleProcessor(
|
||||
const nsTArray<CSSStyleSheet*>& aSheets,
|
||||
nsTArray<css::DocumentRule*>&& aDocumentRulesInSheets,
|
||||
const nsDocumentRuleResultCacheKey& aCacheKey,
|
||||
nsCSSRuleProcessor* aRuleProcessor)
|
||||
{
|
||||
MOZ_ASSERT(!aRuleProcessor->IsInRuleProcessorCache());
|
||||
|
||||
Entry* entry = nullptr;
|
||||
for (Entry& e : mEntries) {
|
||||
if (e.mSheets == aSheets) {
|
||||
entry = &e;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!entry) {
|
||||
entry = mEntries.AppendElement();
|
||||
entry->mSheets = aSheets;
|
||||
entry->mDocumentRulesInSheets = aDocumentRulesInSheets;
|
||||
for (CSSStyleSheet* sheet : aSheets) {
|
||||
sheet->SetInRuleProcessorCache();
|
||||
}
|
||||
} else {
|
||||
MOZ_ASSERT(entry->mDocumentRulesInSheets == aDocumentRulesInSheets,
|
||||
"DocumentRule array shouldn't have changed");
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
for (DocumentEntry& de : entry->mDocumentEntries) {
|
||||
MOZ_ASSERT(de.mCacheKey != aCacheKey,
|
||||
"should not have duplicate document cache keys");
|
||||
}
|
||||
#endif
|
||||
|
||||
DocumentEntry* documentEntry = entry->mDocumentEntries.AppendElement();
|
||||
documentEntry->mCacheKey = aCacheKey;
|
||||
documentEntry->mRuleProcessor = aRuleProcessor;
|
||||
aRuleProcessor->SetInRuleProcessorCache(true);
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
bool
|
||||
RuleProcessorCache::DoHasRuleProcessor(nsCSSRuleProcessor* aRuleProcessor)
|
||||
{
|
||||
for (Entry& e : mEntries) {
|
||||
for (DocumentEntry& de : e.mDocumentEntries) {
|
||||
if (de.mRuleProcessor == aRuleProcessor) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
void
|
||||
RuleProcessorCache::DoRemoveRuleProcessor(nsCSSRuleProcessor* aRuleProcessor)
|
||||
{
|
||||
MOZ_ASSERT(aRuleProcessor->IsInRuleProcessorCache());
|
||||
|
||||
aRuleProcessor->SetInRuleProcessorCache(false);
|
||||
mExpirationTracker.RemoveObjectIfTracked(aRuleProcessor);
|
||||
for (Entry& e : mEntries) {
|
||||
for (size_t i = 0; i < e.mDocumentEntries.Length(); i++) {
|
||||
if (e.mDocumentEntries[i].mRuleProcessor == aRuleProcessor) {
|
||||
e.mDocumentEntries.RemoveElementAt(i);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MOZ_ASSERT_UNREACHABLE("should have found rule processor");
|
||||
}
|
||||
|
||||
void
|
||||
RuleProcessorCache::DoStartTracking(nsCSSRuleProcessor* aRuleProcessor)
|
||||
{
|
||||
mExpirationTracker.AddObject(aRuleProcessor);
|
||||
}
|
||||
|
||||
void
|
||||
RuleProcessorCache::DoStopTracking(nsCSSRuleProcessor* aRuleProcessor)
|
||||
{
|
||||
mExpirationTracker.RemoveObjectIfTracked(aRuleProcessor);
|
||||
}
|
||||
|
||||
size_t
|
||||
RuleProcessorCache::SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf)
|
||||
{
|
||||
size_t n = aMallocSizeOf(this);
|
||||
|
||||
int count = 0;
|
||||
n += mEntries.ShallowSizeOfExcludingThis(aMallocSizeOf);
|
||||
for (Entry& e : mEntries) {
|
||||
n += e.mDocumentEntries.ShallowSizeOfExcludingThis(aMallocSizeOf);
|
||||
for (DocumentEntry& de : e.mDocumentEntries) {
|
||||
count++;
|
||||
n += de.mRuleProcessor->SizeOfIncludingThis(aMallocSizeOf);
|
||||
}
|
||||
}
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
void
|
||||
RuleProcessorCache::ExpirationTracker::RemoveObjectIfTracked(
|
||||
nsCSSRuleProcessor* aRuleProcessor)
|
||||
{
|
||||
if (aRuleProcessor->GetExpirationState()->IsTracked()) {
|
||||
RemoveObject(aRuleProcessor);
|
||||
}
|
||||
}
|
||||
|
||||
bool RuleProcessorCache::gShutdown = false;
|
||||
mozilla::StaticRefPtr<RuleProcessorCache> RuleProcessorCache::gRuleProcessorCache;
|
||||
150
layout/style/RuleProcessorCache.h
Normal file
150
layout/style/RuleProcessorCache.h
Normal file
|
|
@ -0,0 +1,150 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* 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/. */
|
||||
|
||||
/*
|
||||
* cache of re-usable nsCSSRuleProcessors for given sets of style sheets
|
||||
*/
|
||||
|
||||
#ifndef mozilla_RuleProcessorCache_h
|
||||
#define mozilla_RuleProcessorCache_h
|
||||
|
||||
#include "mozilla/MemoryReporting.h"
|
||||
#include "mozilla/StaticPtr.h"
|
||||
#include "nsCSSRuleProcessor.h"
|
||||
#include "nsExpirationTracker.h"
|
||||
#include "nsIMediaList.h"
|
||||
#include "nsIMemoryReporter.h"
|
||||
#include "nsTArray.h"
|
||||
|
||||
class nsCSSRuleProcessor;
|
||||
namespace mozilla {
|
||||
class CSSStyleSheet;
|
||||
namespace css {
|
||||
class DocumentRule;
|
||||
} // namespace css
|
||||
} // namespace mozilla
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
/**
|
||||
* The RuleProcessorCache is a singleton object that caches
|
||||
* nsCSSRuleProcessors keyed off a list of style sheets and the result of
|
||||
* evaluating all @-moz-documents in the style sheets. nsStyleSet gets and
|
||||
* puts nsCSSRuleProcessors from/to the RuleProcessorCache.
|
||||
*
|
||||
* State bits on CSSStyleSheet and nsCSSRuleProcessor track whether they are in
|
||||
* the RuleProcessorCache. This lets us remove them from the RuleProcessorCache
|
||||
* when they're going away.
|
||||
*/
|
||||
class RuleProcessorCache final : public nsIMemoryReporter
|
||||
{
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSIMEMORYREPORTER
|
||||
|
||||
public:
|
||||
static nsCSSRuleProcessor* GetRuleProcessor(
|
||||
const nsTArray<CSSStyleSheet*>& aSheets,
|
||||
nsPresContext* aPresContext);
|
||||
static void PutRuleProcessor(
|
||||
const nsTArray<CSSStyleSheet*>& aSheets,
|
||||
nsTArray<css::DocumentRule*>&& aDocumentRulesInSheets,
|
||||
const nsDocumentRuleResultCacheKey& aCacheKey,
|
||||
nsCSSRuleProcessor* aRuleProcessor);
|
||||
static void StartTracking(nsCSSRuleProcessor* aRuleProcessor);
|
||||
static void StopTracking(nsCSSRuleProcessor* aRuleProcessor);
|
||||
|
||||
#ifdef DEBUG
|
||||
static bool HasRuleProcessor(nsCSSRuleProcessor* aRuleProcessor);
|
||||
#endif
|
||||
static void RemoveRuleProcessor(nsCSSRuleProcessor* aRuleProcessor);
|
||||
static void RemoveSheet(CSSStyleSheet* aSheet);
|
||||
|
||||
static void Shutdown() { gShutdown = true; gRuleProcessorCache = nullptr; }
|
||||
|
||||
size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf);
|
||||
|
||||
private:
|
||||
class ExpirationTracker : public nsExpirationTracker<nsCSSRuleProcessor,3>
|
||||
{
|
||||
public:
|
||||
explicit ExpirationTracker(RuleProcessorCache* aCache)
|
||||
: nsExpirationTracker<nsCSSRuleProcessor,3>(
|
||||
10000, "RuleProcessorCache::ExpirationTracker")
|
||||
, mCache(aCache) {}
|
||||
|
||||
void RemoveObjectIfTracked(nsCSSRuleProcessor* aRuleProcessor);
|
||||
|
||||
virtual void NotifyExpired(nsCSSRuleProcessor* aRuleProcessor) override {
|
||||
mCache->RemoveRuleProcessor(aRuleProcessor);
|
||||
}
|
||||
|
||||
private:
|
||||
RuleProcessorCache* mCache;
|
||||
};
|
||||
|
||||
RuleProcessorCache() : mExpirationTracker(this) {}
|
||||
~RuleProcessorCache();
|
||||
|
||||
void InitMemoryReporter();
|
||||
|
||||
static bool EnsureGlobal();
|
||||
static StaticRefPtr<RuleProcessorCache> gRuleProcessorCache;
|
||||
static bool gShutdown;
|
||||
|
||||
void DoRemoveSheet(CSSStyleSheet* aSheet);
|
||||
nsCSSRuleProcessor* DoGetRuleProcessor(
|
||||
const nsTArray<CSSStyleSheet*>& aSheets,
|
||||
nsPresContext* aPresContext);
|
||||
void DoPutRuleProcessor(const nsTArray<CSSStyleSheet*>& aSheets,
|
||||
nsTArray<css::DocumentRule*>&& aDocumentRulesInSheets,
|
||||
const nsDocumentRuleResultCacheKey& aCacheKey,
|
||||
nsCSSRuleProcessor* aRuleProcessor);
|
||||
#ifdef DEBUG
|
||||
bool DoHasRuleProcessor(nsCSSRuleProcessor* aRuleProcessor);
|
||||
#endif
|
||||
void DoRemoveRuleProcessor(nsCSSRuleProcessor* aRuleProcessor);
|
||||
void DoStartTracking(nsCSSRuleProcessor* aRuleProcessor);
|
||||
void DoStopTracking(nsCSSRuleProcessor* aRuleProcessor);
|
||||
|
||||
struct DocumentEntry {
|
||||
nsDocumentRuleResultCacheKey mCacheKey;
|
||||
RefPtr<nsCSSRuleProcessor> mRuleProcessor;
|
||||
};
|
||||
|
||||
struct Entry {
|
||||
nsTArray<CSSStyleSheet*> mSheets;
|
||||
nsTArray<css::DocumentRule*> mDocumentRulesInSheets;
|
||||
nsTArray<DocumentEntry> mDocumentEntries;
|
||||
};
|
||||
|
||||
// Function object to test whether an Entry object has a given sheet
|
||||
// in its mSheets array. If it does, removes all of its rule processors
|
||||
// before returning true.
|
||||
struct HasSheet_ThenRemoveRuleProcessors {
|
||||
HasSheet_ThenRemoveRuleProcessors(RuleProcessorCache* aCache,
|
||||
CSSStyleSheet* aSheet)
|
||||
: mCache(aCache), mSheet(aSheet) {}
|
||||
bool operator()(Entry& aEntry) {
|
||||
if (aEntry.mSheets.Contains(mSheet)) {
|
||||
for (DocumentEntry& de : aEntry.mDocumentEntries) {
|
||||
de.mRuleProcessor->SetInRuleProcessorCache(false);
|
||||
mCache->mExpirationTracker.RemoveObjectIfTracked(de.mRuleProcessor);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
RuleProcessorCache* mCache;
|
||||
CSSStyleSheet* mSheet;
|
||||
};
|
||||
|
||||
ExpirationTracker mExpirationTracker;
|
||||
nsTArray<Entry> mEntries;
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // mozilla_RuleProcessorCache_h
|
||||
122
layout/style/SVGAttrAnimationRuleProcessor.cpp
Normal file
122
layout/style/SVGAttrAnimationRuleProcessor.cpp
Normal file
|
|
@ -0,0 +1,122 @@
|
|||
/* -*- Mode: C++; 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/.
|
||||
*/
|
||||
|
||||
/*
|
||||
* style rule processor for rules from SMIL Animation of SVG mapped
|
||||
* attributes (attributes whose values are mapped into style)
|
||||
*/
|
||||
|
||||
#include "SVGAttrAnimationRuleProcessor.h"
|
||||
#include "nsRuleProcessorData.h"
|
||||
#include "nsSVGElement.h"
|
||||
|
||||
using namespace mozilla;
|
||||
using namespace mozilla::dom;
|
||||
|
||||
SVGAttrAnimationRuleProcessor::SVGAttrAnimationRuleProcessor()
|
||||
{
|
||||
}
|
||||
|
||||
SVGAttrAnimationRuleProcessor::~SVGAttrAnimationRuleProcessor()
|
||||
{
|
||||
}
|
||||
|
||||
NS_IMPL_ISUPPORTS(SVGAttrAnimationRuleProcessor, nsIStyleRuleProcessor)
|
||||
|
||||
/* virtual */ void
|
||||
SVGAttrAnimationRuleProcessor::RulesMatching(ElementRuleProcessorData* aData)
|
||||
{
|
||||
ElementRulesMatching(aData->mElement, aData->mRuleWalker);
|
||||
}
|
||||
|
||||
void
|
||||
SVGAttrAnimationRuleProcessor::ElementRulesMatching(Element* aElement,
|
||||
nsRuleWalker* aRuleWalker)
|
||||
{
|
||||
if (aElement->IsSVGElement()) {
|
||||
static_cast<nsSVGElement*>(aElement)->
|
||||
WalkAnimatedContentStyleRules(aRuleWalker);
|
||||
}
|
||||
}
|
||||
|
||||
/* virtual */ nsRestyleHint
|
||||
SVGAttrAnimationRuleProcessor::HasStateDependentStyle(StateRuleProcessorData* aData)
|
||||
{
|
||||
return nsRestyleHint(0);
|
||||
}
|
||||
|
||||
/* virtual */ nsRestyleHint
|
||||
SVGAttrAnimationRuleProcessor::HasStateDependentStyle(PseudoElementStateRuleProcessorData* aData)
|
||||
{
|
||||
return nsRestyleHint(0);
|
||||
}
|
||||
|
||||
/* virtual */ bool
|
||||
SVGAttrAnimationRuleProcessor::HasDocumentStateDependentStyle(StateRuleProcessorData* aData)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/* virtual */ nsRestyleHint
|
||||
SVGAttrAnimationRuleProcessor::HasAttributeDependentStyle(
|
||||
AttributeRuleProcessorData* aData,
|
||||
RestyleHintData& aRestyleHintDataResult)
|
||||
{
|
||||
return nsRestyleHint(0);
|
||||
}
|
||||
|
||||
/* virtual */ bool
|
||||
SVGAttrAnimationRuleProcessor::MediumFeaturesChanged(nsPresContext* aPresContext)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/* virtual */ void
|
||||
SVGAttrAnimationRuleProcessor::RulesMatching(PseudoElementRuleProcessorData* aData)
|
||||
{
|
||||
// If SMIL Animation of SVG attributes can ever target
|
||||
// pseudo-elements, we need to adjust either
|
||||
// nsStyleSet::RuleNodeWithReplacement or the test in
|
||||
// ElementRestyler::RestyleSelf (added in bug 977991 patch 4) to
|
||||
// handle such styles.
|
||||
}
|
||||
|
||||
/* virtual */ void
|
||||
SVGAttrAnimationRuleProcessor::RulesMatching(AnonBoxRuleProcessorData* aData)
|
||||
{
|
||||
// If SMIL Animation of SVG attributes can ever target anonymous boxes,
|
||||
// see comment in RulesMatching(PseudoElementRuleProcessorData*).
|
||||
}
|
||||
|
||||
#ifdef MOZ_XUL
|
||||
/* virtual */ void
|
||||
SVGAttrAnimationRuleProcessor::RulesMatching(XULTreeRuleProcessorData* aData)
|
||||
{
|
||||
// If SMIL Animation of SVG attributes can ever target XUL tree pseudos,
|
||||
// see comment in RulesMatching(PseudoElementRuleProcessorData*).
|
||||
}
|
||||
#endif
|
||||
|
||||
/* virtual */ size_t
|
||||
SVGAttrAnimationRuleProcessor::SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const
|
||||
{
|
||||
return 0; // SVGAttrAnimationRuleProcessors are charged to the DOM, not layout
|
||||
}
|
||||
|
||||
/* virtual */ size_t
|
||||
SVGAttrAnimationRuleProcessor::SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const
|
||||
{
|
||||
return 0; // SVGAttrAnimationRuleProcessors are charged to the DOM, not layout
|
||||
}
|
||||
|
||||
size_t
|
||||
SVGAttrAnimationRuleProcessor::DOMSizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const
|
||||
{
|
||||
size_t n = aMallocSizeOf(this);
|
||||
|
||||
return n;
|
||||
}
|
||||
68
layout/style/SVGAttrAnimationRuleProcessor.h
Normal file
68
layout/style/SVGAttrAnimationRuleProcessor.h
Normal file
|
|
@ -0,0 +1,68 @@
|
|||
/* -*- Mode: C++; 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/. */
|
||||
|
||||
/*
|
||||
* style rule processor for rules from SMIL Animation of SVG mapped
|
||||
* attributes (attributes whose values are mapped into style)
|
||||
*/
|
||||
|
||||
#ifndef mozilla_SVGAttrAnimationRuleProcessor_h_
|
||||
#define mozilla_SVGAttrAnimationRuleProcessor_h_
|
||||
|
||||
#include "nsIStyleRuleProcessor.h"
|
||||
|
||||
class nsRuleWalker;
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
namespace dom {
|
||||
class Element;
|
||||
} // namespace dom
|
||||
|
||||
class SVGAttrAnimationRuleProcessor final : public nsIStyleRuleProcessor
|
||||
{
|
||||
public:
|
||||
SVGAttrAnimationRuleProcessor();
|
||||
|
||||
private:
|
||||
~SVGAttrAnimationRuleProcessor();
|
||||
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
|
||||
// nsIStyleRuleProcessor API
|
||||
virtual void RulesMatching(ElementRuleProcessorData* aData) override;
|
||||
virtual void RulesMatching(PseudoElementRuleProcessorData* aData) override;
|
||||
virtual void RulesMatching(AnonBoxRuleProcessorData* aData) override;
|
||||
#ifdef MOZ_XUL
|
||||
virtual void RulesMatching(XULTreeRuleProcessorData* aData) override;
|
||||
#endif
|
||||
virtual nsRestyleHint HasStateDependentStyle(StateRuleProcessorData* aData) override;
|
||||
virtual nsRestyleHint HasStateDependentStyle(PseudoElementStateRuleProcessorData* aData) override;
|
||||
virtual bool HasDocumentStateDependentStyle(StateRuleProcessorData* aData) override;
|
||||
virtual nsRestyleHint
|
||||
HasAttributeDependentStyle(AttributeRuleProcessorData* aData,
|
||||
RestyleHintData& aRestyleHintDataResult) override;
|
||||
virtual bool MediumFeaturesChanged(nsPresContext* aPresContext) override;
|
||||
virtual size_t SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf)
|
||||
const MOZ_MUST_OVERRIDE override;
|
||||
virtual size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf)
|
||||
const MOZ_MUST_OVERRIDE override;
|
||||
|
||||
size_t DOMSizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const;
|
||||
|
||||
// A shortcut for nsStyleSet to call RulesMatching with less setup.
|
||||
void ElementRulesMatching(mozilla::dom::Element* aElement,
|
||||
nsRuleWalker* aRuleWalker);
|
||||
|
||||
private:
|
||||
SVGAttrAnimationRuleProcessor(const SVGAttrAnimationRuleProcessor& aCopy) = delete;
|
||||
SVGAttrAnimationRuleProcessor& operator=(const SVGAttrAnimationRuleProcessor& aCopy) = delete;
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
|
||||
#endif /* !defined(mozilla_SVGAttrAnimationRuleProcessor_h_) */
|
||||
146
layout/style/ServoBindingList.h
Normal file
146
layout/style/ServoBindingList.h
Normal file
|
|
@ -0,0 +1,146 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* 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/. */
|
||||
|
||||
/* a list of all Servo binding functions */
|
||||
|
||||
/* This file contains the list of all Servo binding functions. Each
|
||||
* entry is defined as a SERVO_BINDING_FUNC macro with the following
|
||||
* parameters:
|
||||
* - 'name_' the name of the binding function
|
||||
* - 'return_' the return type of the binding function
|
||||
* and the parameter list of the function.
|
||||
*
|
||||
* Users of this list should define a macro
|
||||
* SERVO_BINDING_FUNC(name_, return_, ...)
|
||||
* before including this file.
|
||||
*/
|
||||
|
||||
// Node data
|
||||
SERVO_BINDING_FUNC(Servo_Node_ClearNodeData, void, RawGeckoNodeBorrowed node)
|
||||
|
||||
// Styleset and Stylesheet management
|
||||
SERVO_BINDING_FUNC(Servo_StyleSheet_Empty, RawServoStyleSheetStrong,
|
||||
mozilla::css::SheetParsingMode parsing_mode)
|
||||
SERVO_BINDING_FUNC(Servo_StyleSheet_FromUTF8Bytes, RawServoStyleSheetStrong,
|
||||
const nsACString* data,
|
||||
mozilla::css::SheetParsingMode parsing_mode,
|
||||
const nsACString* base_url,
|
||||
ThreadSafeURIHolder* base,
|
||||
ThreadSafeURIHolder* referrer,
|
||||
ThreadSafePrincipalHolder* principal)
|
||||
SERVO_BINDING_FUNC(Servo_StyleSheet_AddRef, void,
|
||||
RawServoStyleSheetBorrowed sheet)
|
||||
SERVO_BINDING_FUNC(Servo_StyleSheet_Release, void,
|
||||
RawServoStyleSheetBorrowed sheet)
|
||||
SERVO_BINDING_FUNC(Servo_StyleSheet_HasRules, bool,
|
||||
RawServoStyleSheetBorrowed sheet)
|
||||
SERVO_BINDING_FUNC(Servo_StyleSet_Init, RawServoStyleSetOwned)
|
||||
SERVO_BINDING_FUNC(Servo_StyleSet_Drop, void, RawServoStyleSetOwned set)
|
||||
SERVO_BINDING_FUNC(Servo_StyleSet_AppendStyleSheet, void,
|
||||
RawServoStyleSetBorrowed set, RawServoStyleSheetBorrowed sheet)
|
||||
SERVO_BINDING_FUNC(Servo_StyleSet_PrependStyleSheet, void,
|
||||
RawServoStyleSetBorrowed set, RawServoStyleSheetBorrowed sheet)
|
||||
SERVO_BINDING_FUNC(Servo_StyleSet_RemoveStyleSheet, void,
|
||||
RawServoStyleSetBorrowed set, RawServoStyleSheetBorrowed sheet)
|
||||
SERVO_BINDING_FUNC(Servo_StyleSet_InsertStyleSheetBefore, void,
|
||||
RawServoStyleSetBorrowed set, RawServoStyleSheetBorrowed sheet,
|
||||
RawServoStyleSheetBorrowed reference)
|
||||
|
||||
// Animations API
|
||||
SERVO_BINDING_FUNC(Servo_ParseProperty,
|
||||
RawServoDeclarationBlockStrong,
|
||||
const nsACString* property, const nsACString* value,
|
||||
const nsACString* base_url, ThreadSafeURIHolder* base,
|
||||
ThreadSafeURIHolder* referrer,
|
||||
ThreadSafePrincipalHolder* principal)
|
||||
SERVO_BINDING_FUNC(Servo_RestyleWithAddedDeclaration,
|
||||
ServoComputedValuesStrong,
|
||||
RawServoDeclarationBlockBorrowed declarations,
|
||||
ServoComputedValuesBorrowed previous_style)
|
||||
|
||||
// Style attribute
|
||||
SERVO_BINDING_FUNC(Servo_ParseStyleAttribute, RawServoDeclarationBlockStrong,
|
||||
const nsACString* data)
|
||||
SERVO_BINDING_FUNC(Servo_DeclarationBlock_CreateEmpty,
|
||||
RawServoDeclarationBlockStrong)
|
||||
SERVO_BINDING_FUNC(Servo_DeclarationBlock_Clone, RawServoDeclarationBlockStrong,
|
||||
RawServoDeclarationBlockBorrowed declarations)
|
||||
SERVO_BINDING_FUNC(Servo_DeclarationBlock_AddRef, void,
|
||||
RawServoDeclarationBlockBorrowed declarations)
|
||||
SERVO_BINDING_FUNC(Servo_DeclarationBlock_Release, void,
|
||||
RawServoDeclarationBlockBorrowed declarations)
|
||||
SERVO_BINDING_FUNC(Servo_DeclarationBlock_Equals, bool,
|
||||
RawServoDeclarationBlockBorrowed a,
|
||||
RawServoDeclarationBlockBorrowed b)
|
||||
SERVO_BINDING_FUNC(Servo_DeclarationBlock_GetCssText, void,
|
||||
RawServoDeclarationBlockBorrowed declarations,
|
||||
nsAString* result)
|
||||
SERVO_BINDING_FUNC(Servo_DeclarationBlock_SerializeOneValue, void,
|
||||
RawServoDeclarationBlockBorrowed declarations,
|
||||
nsString* buffer)
|
||||
SERVO_BINDING_FUNC(Servo_DeclarationBlock_Count, uint32_t,
|
||||
RawServoDeclarationBlockBorrowed declarations)
|
||||
SERVO_BINDING_FUNC(Servo_DeclarationBlock_GetNthProperty, bool,
|
||||
RawServoDeclarationBlockBorrowed declarations,
|
||||
uint32_t index, nsAString* result)
|
||||
SERVO_BINDING_FUNC(Servo_DeclarationBlock_GetPropertyValue, void,
|
||||
RawServoDeclarationBlockBorrowed declarations,
|
||||
nsIAtom* property, bool is_custom, nsAString* value)
|
||||
SERVO_BINDING_FUNC(Servo_DeclarationBlock_GetPropertyIsImportant, bool,
|
||||
RawServoDeclarationBlockBorrowed declarations,
|
||||
nsIAtom* property, bool is_custom)
|
||||
SERVO_BINDING_FUNC(Servo_DeclarationBlock_SetProperty, bool,
|
||||
RawServoDeclarationBlockBorrowed declarations,
|
||||
nsIAtom* property, bool is_custom,
|
||||
nsACString* value, bool is_important)
|
||||
SERVO_BINDING_FUNC(Servo_DeclarationBlock_RemoveProperty, void,
|
||||
RawServoDeclarationBlockBorrowed declarations,
|
||||
nsIAtom* property, bool is_custom)
|
||||
|
||||
// CSS supports()
|
||||
SERVO_BINDING_FUNC(Servo_CSSSupports, bool,
|
||||
const nsACString* name, const nsACString* value)
|
||||
|
||||
// Computed style data
|
||||
SERVO_BINDING_FUNC(Servo_ComputedValues_Get, ServoComputedValuesStrong,
|
||||
RawGeckoNodeBorrowed node)
|
||||
SERVO_BINDING_FUNC(Servo_ComputedValues_GetForAnonymousBox,
|
||||
ServoComputedValuesStrong,
|
||||
ServoComputedValuesBorrowedOrNull parent_style_or_null,
|
||||
nsIAtom* pseudoTag, RawServoStyleSetBorrowed set)
|
||||
SERVO_BINDING_FUNC(Servo_ComputedValues_GetForPseudoElement,
|
||||
ServoComputedValuesStrong,
|
||||
ServoComputedValuesBorrowed parent_style,
|
||||
RawGeckoElementBorrowed match_element, nsIAtom* pseudo_tag,
|
||||
RawServoStyleSetBorrowed set, bool is_probe)
|
||||
SERVO_BINDING_FUNC(Servo_ComputedValues_Inherit, ServoComputedValuesStrong,
|
||||
ServoComputedValuesBorrowedOrNull parent_style)
|
||||
SERVO_BINDING_FUNC(Servo_ComputedValues_AddRef, void,
|
||||
ServoComputedValuesBorrowed computed_values)
|
||||
SERVO_BINDING_FUNC(Servo_ComputedValues_Release, void,
|
||||
ServoComputedValuesBorrowed computed_values)
|
||||
|
||||
// Initialize Servo components. Should be called exactly once at startup.
|
||||
SERVO_BINDING_FUNC(Servo_Initialize, void)
|
||||
// Shut down Servo components. Should be called exactly once at shutdown.
|
||||
SERVO_BINDING_FUNC(Servo_Shutdown, void)
|
||||
|
||||
// Restyle hints
|
||||
SERVO_BINDING_FUNC(Servo_ComputeRestyleHint, nsRestyleHint,
|
||||
RawGeckoElementBorrowed element, ServoElementSnapshot* snapshot,
|
||||
RawServoStyleSetBorrowed set)
|
||||
|
||||
// Restyle the given subtree.
|
||||
SERVO_BINDING_FUNC(Servo_RestyleSubtree, void,
|
||||
RawGeckoNodeBorrowed node, RawServoStyleSetBorrowed set)
|
||||
|
||||
// Style-struct management.
|
||||
#define STYLE_STRUCT(name, checkdata_cb) \
|
||||
struct nsStyle##name; \
|
||||
SERVO_BINDING_FUNC(Servo_GetStyle##name, const nsStyle##name*, \
|
||||
ServoComputedValuesBorrowedOrNull computed_values)
|
||||
#include "nsStyleStructList.h"
|
||||
#undef STYLE_STRUCT
|
||||
144
layout/style/ServoBindingTypes.h
Normal file
144
layout/style/ServoBindingTypes.h
Normal file
|
|
@ -0,0 +1,144 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* 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_ServoBindingTypes_h
|
||||
#define mozilla_ServoBindingTypes_h
|
||||
|
||||
#include "mozilla/RefPtr.h"
|
||||
#include "mozilla/UniquePtr.h"
|
||||
|
||||
struct ServoComputedValues;
|
||||
struct RawServoStyleSheet;
|
||||
struct RawServoStyleSet;
|
||||
struct RawServoDeclarationBlock;
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
class Element;
|
||||
class StyleChildrenIterator;
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
class nsCSSValue;
|
||||
class nsIDocument;
|
||||
class nsINode;
|
||||
|
||||
using mozilla::dom::StyleChildrenIterator;
|
||||
|
||||
typedef nsINode RawGeckoNode;
|
||||
typedef mozilla::dom::Element RawGeckoElement;
|
||||
typedef nsIDocument RawGeckoDocument;
|
||||
|
||||
// We have these helper types so that we can directly generate
|
||||
// things like &T or Borrowed<T> on the Rust side in the function, providing
|
||||
// additional safety benefits.
|
||||
//
|
||||
// FFI has a problem with templated types, so we just use raw pointers here.
|
||||
//
|
||||
// The "Borrowed" types generate &T or Borrowed<T> in the nullable case.
|
||||
//
|
||||
// The "Owned" types generate Owned<T> or OwnedOrNull<T>. Some of these
|
||||
// are Servo-managed and can be converted to Box<ServoType> on the
|
||||
// Servo side.
|
||||
//
|
||||
// The "Arc" types are Servo-managed Arc<ServoType>s, which are passed
|
||||
// over FFI as Strong<T> (which is nullable).
|
||||
// Note that T != ServoType, rather T is ArcInner<ServoType>
|
||||
#define DECL_BORROWED_REF_TYPE_FOR(type_) typedef type_ const* type_##Borrowed;
|
||||
#define DECL_NULLABLE_BORROWED_REF_TYPE_FOR(type_) typedef type_ const* type_##BorrowedOrNull;
|
||||
#define DECL_BORROWED_MUT_REF_TYPE_FOR(type_) typedef type_* type_##BorrowedMut;
|
||||
#define DECL_NULLABLE_BORROWED_MUT_REF_TYPE_FOR(type_) typedef type_* type_##BorrowedMutOrNull;
|
||||
|
||||
#define DECL_ARC_REF_TYPE_FOR(type_) \
|
||||
DECL_NULLABLE_BORROWED_REF_TYPE_FOR(type_) \
|
||||
DECL_BORROWED_REF_TYPE_FOR(type_) \
|
||||
struct MOZ_MUST_USE_TYPE type_##Strong \
|
||||
{ \
|
||||
type_* mPtr; \
|
||||
already_AddRefed<type_> Consume(); \
|
||||
};
|
||||
|
||||
#define DECL_OWNED_REF_TYPE_FOR(type_) \
|
||||
typedef type_* type_##Owned; \
|
||||
DECL_BORROWED_REF_TYPE_FOR(type_) \
|
||||
DECL_BORROWED_MUT_REF_TYPE_FOR(type_)
|
||||
|
||||
#define DECL_NULLABLE_OWNED_REF_TYPE_FOR(type_) \
|
||||
typedef type_* type_##OwnedOrNull; \
|
||||
DECL_NULLABLE_BORROWED_REF_TYPE_FOR(type_) \
|
||||
DECL_NULLABLE_BORROWED_MUT_REF_TYPE_FOR(type_)
|
||||
|
||||
DECL_ARC_REF_TYPE_FOR(ServoComputedValues)
|
||||
DECL_ARC_REF_TYPE_FOR(RawServoStyleSheet)
|
||||
DECL_ARC_REF_TYPE_FOR(RawServoDeclarationBlock)
|
||||
// This is a reference to a reference of RawServoDeclarationBlock, which
|
||||
// corresponds to Option<&Arc<RawServoDeclarationBlock>> in Servo side.
|
||||
DECL_NULLABLE_BORROWED_REF_TYPE_FOR(RawServoDeclarationBlockStrong)
|
||||
|
||||
DECL_OWNED_REF_TYPE_FOR(RawServoStyleSet)
|
||||
DECL_NULLABLE_OWNED_REF_TYPE_FOR(StyleChildrenIterator)
|
||||
DECL_OWNED_REF_TYPE_FOR(StyleChildrenIterator)
|
||||
|
||||
// We don't use BorrowedMut because the nodes may alias
|
||||
// Servo itself doesn't directly read or mutate these;
|
||||
// it only asks Gecko to do so. In case we wish to in
|
||||
// the future, we should ensure that things being mutated
|
||||
// are protected from noalias violations by a cell type
|
||||
DECL_BORROWED_REF_TYPE_FOR(RawGeckoNode)
|
||||
DECL_NULLABLE_BORROWED_REF_TYPE_FOR(RawGeckoNode)
|
||||
DECL_BORROWED_REF_TYPE_FOR(RawGeckoElement)
|
||||
DECL_NULLABLE_BORROWED_REF_TYPE_FOR(RawGeckoElement)
|
||||
DECL_BORROWED_REF_TYPE_FOR(RawGeckoDocument)
|
||||
DECL_NULLABLE_BORROWED_REF_TYPE_FOR(RawGeckoDocument)
|
||||
DECL_BORROWED_MUT_REF_TYPE_FOR(StyleChildrenIterator)
|
||||
DECL_BORROWED_REF_TYPE_FOR(nsCSSValue)
|
||||
DECL_BORROWED_MUT_REF_TYPE_FOR(nsCSSValue)
|
||||
|
||||
#undef DECL_ARC_REF_TYPE_FOR
|
||||
#undef DECL_OWNED_REF_TYPE_FOR
|
||||
#undef DECL_NULLABLE_OWNED_REF_TYPE_FOR
|
||||
#undef DECL_BORROWED_REF_TYPE_FOR
|
||||
#undef DECL_NULLABLE_BORROWED_REF_TYPE_FOR
|
||||
#undef DECL_BORROWED_MUT_REF_TYPE_FOR
|
||||
#undef DECL_NULLABLE_BORROWED_MUT_REF_TYPE_FOR
|
||||
|
||||
#define DEFINE_REFPTR_TRAITS(name_, type_) \
|
||||
extern "C" { \
|
||||
void Servo_##name_##_AddRef(type_##Borrowed ptr); \
|
||||
void Servo_##name_##_Release(type_##Borrowed ptr); \
|
||||
} \
|
||||
namespace mozilla { \
|
||||
template<> struct RefPtrTraits<type_> { \
|
||||
static void AddRef(type_* aPtr) { \
|
||||
Servo_##name_##_AddRef(aPtr); \
|
||||
} \
|
||||
static void Release(type_* aPtr) { \
|
||||
Servo_##name_##_Release(aPtr); \
|
||||
} \
|
||||
}; \
|
||||
}
|
||||
|
||||
DEFINE_REFPTR_TRAITS(StyleSheet, RawServoStyleSheet)
|
||||
DEFINE_REFPTR_TRAITS(ComputedValues, ServoComputedValues)
|
||||
DEFINE_REFPTR_TRAITS(DeclarationBlock, RawServoDeclarationBlock)
|
||||
|
||||
#undef DEFINE_REFPTR_TRAITS
|
||||
|
||||
extern "C" void Servo_StyleSet_Drop(RawServoStyleSetOwned ptr);
|
||||
|
||||
namespace mozilla {
|
||||
template<>
|
||||
class DefaultDelete<RawServoStyleSet>
|
||||
{
|
||||
public:
|
||||
void operator()(RawServoStyleSet* aPtr) const
|
||||
{
|
||||
Servo_StyleSet_Drop(aPtr);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#endif // mozilla_ServoBindingTypes_h
|
||||
1083
layout/style/ServoBindings.cpp
Normal file
1083
layout/style/ServoBindings.cpp
Normal file
File diff suppressed because it is too large
Load diff
285
layout/style/ServoBindings.h
Normal file
285
layout/style/ServoBindings.h
Normal file
|
|
@ -0,0 +1,285 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* 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_ServoBindings_h
|
||||
#define mozilla_ServoBindings_h
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "mozilla/ServoTypes.h"
|
||||
#include "mozilla/ServoBindingTypes.h"
|
||||
#include "mozilla/ServoElementSnapshot.h"
|
||||
#include "mozilla/css/SheetParsingMode.h"
|
||||
#include "nsChangeHint.h"
|
||||
#include "nsStyleStruct.h"
|
||||
|
||||
/*
|
||||
* API for Servo to access Gecko data structures. This file must compile as valid
|
||||
* C code in order for the binding generator to parse it.
|
||||
*
|
||||
* Functions beginning with Gecko_ are implemented in Gecko and invoked from Servo.
|
||||
* Functions beginning with Servo_ are implemented in Servo and invoked from Gecko.
|
||||
*/
|
||||
|
||||
class nsIAtom;
|
||||
class nsIPrincipal;
|
||||
class nsIURI;
|
||||
struct nsFont;
|
||||
namespace mozilla {
|
||||
class FontFamilyList;
|
||||
enum FontFamilyType : uint32_t;
|
||||
}
|
||||
using mozilla::FontFamilyList;
|
||||
using mozilla::FontFamilyType;
|
||||
using mozilla::ServoElementSnapshot;
|
||||
struct nsStyleList;
|
||||
struct nsStyleImage;
|
||||
struct nsStyleGradientStop;
|
||||
class nsStyleGradient;
|
||||
class nsStyleCoord;
|
||||
struct nsStyleDisplay;
|
||||
|
||||
#define NS_DECL_THREADSAFE_FFI_REFCOUNTING(class_, name_) \
|
||||
void Gecko_AddRef##name_##ArbitraryThread(class_* aPtr); \
|
||||
void Gecko_Release##name_##ArbitraryThread(class_* aPtr);
|
||||
#define NS_IMPL_THREADSAFE_FFI_REFCOUNTING(class_, name_) \
|
||||
static_assert(class_::HasThreadSafeRefCnt::value, \
|
||||
"NS_DECL_THREADSAFE_FFI_REFCOUNTING can only be used with " \
|
||||
"classes that have thread-safe refcounting"); \
|
||||
void Gecko_AddRef##name_##ArbitraryThread(class_* aPtr) \
|
||||
{ NS_ADDREF(aPtr); } \
|
||||
void Gecko_Release##name_##ArbitraryThread(class_* aPtr) \
|
||||
{ NS_RELEASE(aPtr); }
|
||||
|
||||
#define NS_DECL_HOLDER_FFI_REFCOUNTING(class_, name_) \
|
||||
typedef nsMainThreadPtrHolder<class_> ThreadSafe##name_##Holder; \
|
||||
void Gecko_AddRef##name_##ArbitraryThread(ThreadSafe##name_##Holder* aPtr); \
|
||||
void Gecko_Release##name_##ArbitraryThread(ThreadSafe##name_##Holder* aPtr);
|
||||
#define NS_IMPL_HOLDER_FFI_REFCOUNTING(class_, name_) \
|
||||
void Gecko_AddRef##name_##ArbitraryThread(ThreadSafe##name_##Holder* aPtr) \
|
||||
{ NS_ADDREF(aPtr); } \
|
||||
void Gecko_Release##name_##ArbitraryThread(ThreadSafe##name_##Holder* aPtr) \
|
||||
{ NS_RELEASE(aPtr); } \
|
||||
|
||||
extern "C" {
|
||||
|
||||
// Object refcounting.
|
||||
NS_DECL_HOLDER_FFI_REFCOUNTING(nsIPrincipal, Principal)
|
||||
NS_DECL_HOLDER_FFI_REFCOUNTING(nsIURI, URI)
|
||||
|
||||
// DOM Traversal.
|
||||
uint32_t Gecko_ChildrenCount(RawGeckoNodeBorrowed node);
|
||||
bool Gecko_NodeIsElement(RawGeckoNodeBorrowed node);
|
||||
RawGeckoNodeBorrowedOrNull Gecko_GetParentNode(RawGeckoNodeBorrowed node);
|
||||
RawGeckoNodeBorrowedOrNull Gecko_GetFirstChild(RawGeckoNodeBorrowed node);
|
||||
RawGeckoNodeBorrowedOrNull Gecko_GetLastChild(RawGeckoNodeBorrowed node);
|
||||
RawGeckoNodeBorrowedOrNull Gecko_GetPrevSibling(RawGeckoNodeBorrowed node);
|
||||
RawGeckoNodeBorrowedOrNull Gecko_GetNextSibling(RawGeckoNodeBorrowed node);
|
||||
RawGeckoElementBorrowedOrNull Gecko_GetParentElement(RawGeckoElementBorrowed element);
|
||||
RawGeckoElementBorrowedOrNull Gecko_GetFirstChildElement(RawGeckoElementBorrowed element);
|
||||
RawGeckoElementBorrowedOrNull Gecko_GetLastChildElement(RawGeckoElementBorrowed element);
|
||||
RawGeckoElementBorrowedOrNull Gecko_GetPrevSiblingElement(RawGeckoElementBorrowed element);
|
||||
RawGeckoElementBorrowedOrNull Gecko_GetNextSiblingElement(RawGeckoElementBorrowed element);
|
||||
RawGeckoElementBorrowedOrNull Gecko_GetDocumentElement(RawGeckoDocumentBorrowed document);
|
||||
|
||||
// By default, Servo walks the DOM by traversing the siblings of the DOM-view
|
||||
// first child. This generally works, but misses anonymous children, which we
|
||||
// want to traverse during styling. To support these cases, we create an
|
||||
// optional heap-allocated iterator for nodes that need it. If the creation
|
||||
// method returns null, Servo falls back to the aforementioned simpler (and
|
||||
// faster) sibling traversal.
|
||||
StyleChildrenIteratorOwnedOrNull Gecko_MaybeCreateStyleChildrenIterator(RawGeckoNodeBorrowed node);
|
||||
void Gecko_DropStyleChildrenIterator(StyleChildrenIteratorOwned it);
|
||||
RawGeckoNodeBorrowedOrNull Gecko_GetNextStyleChild(StyleChildrenIteratorBorrowedMut it);
|
||||
|
||||
// Selector Matching.
|
||||
uint8_t Gecko_ElementState(RawGeckoElementBorrowed element);
|
||||
bool Gecko_IsHTMLElementInHTMLDocument(RawGeckoElementBorrowed element);
|
||||
bool Gecko_IsLink(RawGeckoElementBorrowed element);
|
||||
bool Gecko_IsTextNode(RawGeckoNodeBorrowed node);
|
||||
bool Gecko_IsVisitedLink(RawGeckoElementBorrowed element);
|
||||
bool Gecko_IsUnvisitedLink(RawGeckoElementBorrowed element);
|
||||
bool Gecko_IsRootElement(RawGeckoElementBorrowed element);
|
||||
nsIAtom* Gecko_LocalName(RawGeckoElementBorrowed element);
|
||||
nsIAtom* Gecko_Namespace(RawGeckoElementBorrowed element);
|
||||
nsIAtom* Gecko_GetElementId(RawGeckoElementBorrowed element);
|
||||
|
||||
// Attributes.
|
||||
#define SERVO_DECLARE_ELEMENT_ATTR_MATCHING_FUNCTIONS(prefix_, implementor_) \
|
||||
nsIAtom* prefix_##AtomAttrValue(implementor_ element, nsIAtom* attribute); \
|
||||
bool prefix_##HasAttr(implementor_ element, nsIAtom* ns, nsIAtom* name); \
|
||||
bool prefix_##AttrEquals(implementor_ element, nsIAtom* ns, nsIAtom* name, \
|
||||
nsIAtom* str, bool ignoreCase); \
|
||||
bool prefix_##AttrDashEquals(implementor_ element, nsIAtom* ns, \
|
||||
nsIAtom* name, nsIAtom* str); \
|
||||
bool prefix_##AttrIncludes(implementor_ element, nsIAtom* ns, \
|
||||
nsIAtom* name, nsIAtom* str); \
|
||||
bool prefix_##AttrHasSubstring(implementor_ element, nsIAtom* ns, \
|
||||
nsIAtom* name, nsIAtom* str); \
|
||||
bool prefix_##AttrHasPrefix(implementor_ element, nsIAtom* ns, \
|
||||
nsIAtom* name, nsIAtom* str); \
|
||||
bool prefix_##AttrHasSuffix(implementor_ element, nsIAtom* ns, \
|
||||
nsIAtom* name, nsIAtom* str); \
|
||||
uint32_t prefix_##ClassOrClassList(implementor_ element, nsIAtom** class_, \
|
||||
nsIAtom*** classList);
|
||||
|
||||
SERVO_DECLARE_ELEMENT_ATTR_MATCHING_FUNCTIONS(Gecko_, RawGeckoElementBorrowed)
|
||||
SERVO_DECLARE_ELEMENT_ATTR_MATCHING_FUNCTIONS(Gecko_Snapshot,
|
||||
ServoElementSnapshot*)
|
||||
|
||||
#undef SERVO_DECLARE_ELEMENT_ATTR_MATCHING_FUNCTIONS
|
||||
|
||||
// Style attributes.
|
||||
RawServoDeclarationBlockStrongBorrowedOrNull
|
||||
Gecko_GetServoDeclarationBlock(RawGeckoElementBorrowed element);
|
||||
|
||||
// Atoms.
|
||||
nsIAtom* Gecko_Atomize(const char* aString, uint32_t aLength);
|
||||
void Gecko_AddRefAtom(nsIAtom* aAtom);
|
||||
void Gecko_ReleaseAtom(nsIAtom* aAtom);
|
||||
const uint16_t* Gecko_GetAtomAsUTF16(nsIAtom* aAtom, uint32_t* aLength);
|
||||
bool Gecko_AtomEqualsUTF8(nsIAtom* aAtom, const char* aString, uint32_t aLength);
|
||||
bool Gecko_AtomEqualsUTF8IgnoreCase(nsIAtom* aAtom, const char* aString, uint32_t aLength);
|
||||
|
||||
// Strings (temporary until bug 1294742)
|
||||
void Gecko_Utf8SliceToString(nsString* aString,
|
||||
const uint8_t* aBuffer,
|
||||
size_t aBufferLen);
|
||||
|
||||
// Font style
|
||||
void Gecko_FontFamilyList_Clear(FontFamilyList* aList);
|
||||
void Gecko_FontFamilyList_AppendNamed(FontFamilyList* aList, nsIAtom* aName);
|
||||
void Gecko_FontFamilyList_AppendGeneric(FontFamilyList* list, FontFamilyType familyType);
|
||||
void Gecko_CopyFontFamilyFrom(nsFont* dst, const nsFont* src);
|
||||
|
||||
// Counter style.
|
||||
void Gecko_SetListStyleType(nsStyleList* style_struct, uint32_t type);
|
||||
void Gecko_CopyListStyleTypeFrom(nsStyleList* dst, const nsStyleList* src);
|
||||
|
||||
// background-image style.
|
||||
// TODO: support element() and -moz-image()
|
||||
void Gecko_SetNullImageValue(nsStyleImage* image);
|
||||
void Gecko_SetGradientImageValue(nsStyleImage* image, nsStyleGradient* gradient);
|
||||
void Gecko_SetUrlImageValue(nsStyleImage* image,
|
||||
const uint8_t* url_bytes,
|
||||
uint32_t url_length,
|
||||
ThreadSafeURIHolder* base_uri,
|
||||
ThreadSafeURIHolder* referrer,
|
||||
ThreadSafePrincipalHolder* principal);
|
||||
void Gecko_CopyImageValueFrom(nsStyleImage* image, const nsStyleImage* other);
|
||||
|
||||
nsStyleGradient* Gecko_CreateGradient(uint8_t shape,
|
||||
uint8_t size,
|
||||
bool repeating,
|
||||
bool legacy_syntax,
|
||||
uint32_t stops);
|
||||
|
||||
// list-style-image style.
|
||||
void Gecko_SetListStyleImageNone(nsStyleList* style_struct);
|
||||
void Gecko_SetListStyleImage(nsStyleList* style_struct,
|
||||
const uint8_t* string_bytes, uint32_t string_length,
|
||||
ThreadSafeURIHolder* base_uri,
|
||||
ThreadSafeURIHolder* referrer,
|
||||
ThreadSafePrincipalHolder* principal);
|
||||
void Gecko_CopyListStyleImageFrom(nsStyleList* dest, const nsStyleList* src);
|
||||
|
||||
// Display style.
|
||||
void Gecko_SetMozBinding(nsStyleDisplay* style_struct,
|
||||
const uint8_t* string_bytes, uint32_t string_length,
|
||||
ThreadSafeURIHolder* base_uri,
|
||||
ThreadSafeURIHolder* referrer,
|
||||
ThreadSafePrincipalHolder* principal);
|
||||
void Gecko_CopyMozBindingFrom(nsStyleDisplay* des, const nsStyleDisplay* src);
|
||||
|
||||
// Dirtiness tracking.
|
||||
uint32_t Gecko_GetNodeFlags(RawGeckoNodeBorrowed node);
|
||||
void Gecko_SetNodeFlags(RawGeckoNodeBorrowed node, uint32_t flags);
|
||||
void Gecko_UnsetNodeFlags(RawGeckoNodeBorrowed node, uint32_t flags);
|
||||
|
||||
// Incremental restyle.
|
||||
// TODO: We would avoid a few ffi calls if we decide to make an API like the
|
||||
// former CalcAndStoreStyleDifference, but that would effectively mean breaking
|
||||
// some safety guarantees in the servo side.
|
||||
//
|
||||
// Also, we might want a ComputedValues to ComputedValues API for animations?
|
||||
// Not if we do them in Gecko...
|
||||
nsStyleContext* Gecko_GetStyleContext(RawGeckoNodeBorrowed node,
|
||||
nsIAtom* aPseudoTagOrNull);
|
||||
nsChangeHint Gecko_CalcStyleDifference(nsStyleContext* oldstyle,
|
||||
ServoComputedValuesBorrowed newstyle);
|
||||
void Gecko_StoreStyleDifference(RawGeckoNodeBorrowed node, nsChangeHint change);
|
||||
|
||||
// `array` must be an nsTArray
|
||||
// If changing this signature, please update the
|
||||
// friend function declaration in nsTArray.h
|
||||
void Gecko_EnsureTArrayCapacity(void* array, size_t capacity, size_t elem_size);
|
||||
|
||||
// Same here, `array` must be an nsTArray<T>, for some T.
|
||||
//
|
||||
// Important note: Only valid for POD types, since destructors won't be run
|
||||
// otherwise. This is ensured with rust traits for the relevant structs.
|
||||
void Gecko_ClearPODTArray(void* array, size_t elem_size, size_t elem_align);
|
||||
|
||||
// Clear the mContents field in nsStyleContent. This is needed to run the
|
||||
// destructors, otherwise we'd leak the images (though we still don't support
|
||||
// those), strings, and whatnot.
|
||||
void Gecko_ClearStyleContents(nsStyleContent* content);
|
||||
void Gecko_CopyStyleContentsFrom(nsStyleContent* content, const nsStyleContent* other);
|
||||
|
||||
void Gecko_EnsureImageLayersLength(nsStyleImageLayers* layers, size_t len,
|
||||
nsStyleImageLayers::LayerType layer_type);
|
||||
|
||||
// Clean up pointer-based coordinates
|
||||
void Gecko_ResetStyleCoord(nsStyleUnit* unit, nsStyleUnion* value);
|
||||
|
||||
// Set an nsStyleCoord to a computed `calc()` value
|
||||
void Gecko_SetStyleCoordCalcValue(nsStyleUnit* unit, nsStyleUnion* value, nsStyleCoord::CalcValue calc);
|
||||
|
||||
void Gecko_CopyClipPathValueFrom(mozilla::StyleClipPath* dst, const mozilla::StyleClipPath* src);
|
||||
|
||||
void Gecko_DestroyClipPath(mozilla::StyleClipPath* clip);
|
||||
mozilla::StyleBasicShape* Gecko_NewBasicShape(mozilla::StyleBasicShapeType type);
|
||||
|
||||
void Gecko_ResetFilters(nsStyleEffects* effects, size_t new_len);
|
||||
void Gecko_CopyFiltersFrom(nsStyleEffects* aSrc, nsStyleEffects* aDest);
|
||||
|
||||
void Gecko_FillAllBackgroundLists(nsStyleImageLayers* layers, uint32_t max_len);
|
||||
void Gecko_FillAllMaskLists(nsStyleImageLayers* layers, uint32_t max_len);
|
||||
NS_DECL_THREADSAFE_FFI_REFCOUNTING(nsStyleCoord::Calc, Calc);
|
||||
|
||||
nsCSSShadowArray* Gecko_NewCSSShadowArray(uint32_t len);
|
||||
NS_DECL_THREADSAFE_FFI_REFCOUNTING(nsCSSShadowArray, CSSShadowArray);
|
||||
|
||||
nsStyleQuoteValues* Gecko_NewStyleQuoteValues(uint32_t len);
|
||||
NS_DECL_THREADSAFE_FFI_REFCOUNTING(nsStyleQuoteValues, QuoteValues);
|
||||
|
||||
nsCSSValueSharedList* Gecko_NewCSSValueSharedList(uint32_t len);
|
||||
void Gecko_CSSValue_SetAbsoluteLength(nsCSSValueBorrowedMut css_value, nscoord len);
|
||||
void Gecko_CSSValue_SetNumber(nsCSSValueBorrowedMut css_value, float number);
|
||||
void Gecko_CSSValue_SetKeyword(nsCSSValueBorrowedMut css_value, nsCSSKeyword keyword);
|
||||
void Gecko_CSSValue_SetPercentage(nsCSSValueBorrowedMut css_value, float percent);
|
||||
void Gecko_CSSValue_SetAngle(nsCSSValueBorrowedMut css_value, float radians);
|
||||
void Gecko_CSSValue_SetCalc(nsCSSValueBorrowedMut css_value, nsStyleCoord::CalcValue calc);
|
||||
void Gecko_CSSValue_SetFunction(nsCSSValueBorrowedMut css_value, int32_t len);
|
||||
nsCSSValueBorrowedMut Gecko_CSSValue_GetArrayItem(nsCSSValueBorrowedMut css_value, int32_t index);
|
||||
NS_DECL_THREADSAFE_FFI_REFCOUNTING(nsCSSValueSharedList, CSSValueSharedList);
|
||||
|
||||
// Style-struct management.
|
||||
#define STYLE_STRUCT(name, checkdata_cb) \
|
||||
void Gecko_Construct_nsStyle##name(nsStyle##name* ptr); \
|
||||
void Gecko_CopyConstruct_nsStyle##name(nsStyle##name* ptr, \
|
||||
const nsStyle##name* other); \
|
||||
void Gecko_Destroy_nsStyle##name(nsStyle##name* ptr);
|
||||
#include "nsStyleStructList.h"
|
||||
#undef STYLE_STRUCT
|
||||
|
||||
#define SERVO_BINDING_FUNC(name_, return_, ...) return_ name_(__VA_ARGS__);
|
||||
#include "mozilla/ServoBindingList.h"
|
||||
#undef SERVO_BINDING_FUNC
|
||||
|
||||
} // extern "C"
|
||||
|
||||
#endif // mozilla_ServoBindings_h
|
||||
110
layout/style/ServoDeclarationBlock.cpp
Normal file
110
layout/style/ServoDeclarationBlock.cpp
Normal file
|
|
@ -0,0 +1,110 @@
|
|||
/* -*- Mode: C++; 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/. */
|
||||
|
||||
#include "mozilla/ServoDeclarationBlock.h"
|
||||
|
||||
#include "mozilla/ServoBindings.h"
|
||||
|
||||
#include "nsCSSProps.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
/* static */ already_AddRefed<ServoDeclarationBlock>
|
||||
ServoDeclarationBlock::FromCssText(const nsAString& aCssText)
|
||||
{
|
||||
NS_ConvertUTF16toUTF8 value(aCssText);
|
||||
RefPtr<RawServoDeclarationBlock>
|
||||
raw = Servo_ParseStyleAttribute(&value).Consume();
|
||||
RefPtr<ServoDeclarationBlock> decl = new ServoDeclarationBlock(raw.forget());
|
||||
return decl.forget();
|
||||
}
|
||||
|
||||
/**
|
||||
* An RAII class holding an atom for the given property.
|
||||
*/
|
||||
class MOZ_STACK_CLASS PropertyAtomHolder
|
||||
{
|
||||
public:
|
||||
explicit PropertyAtomHolder(const nsAString& aProperty)
|
||||
{
|
||||
nsCSSPropertyID propID =
|
||||
nsCSSProps::LookupProperty(aProperty, CSSEnabledState::eForAllContent);
|
||||
if (propID == eCSSPropertyExtra_variable) {
|
||||
mIsCustomProperty = true;
|
||||
mAtom = NS_Atomize(
|
||||
Substring(aProperty, CSS_CUSTOM_NAME_PREFIX_LENGTH)).take();
|
||||
} else {
|
||||
mIsCustomProperty = false;
|
||||
if (propID != eCSSProperty_UNKNOWN) {
|
||||
mAtom = nsCSSProps::AtomForProperty(propID);
|
||||
} else {
|
||||
mAtom = nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
~PropertyAtomHolder()
|
||||
{
|
||||
if (mIsCustomProperty) {
|
||||
NS_RELEASE(mAtom);
|
||||
}
|
||||
}
|
||||
|
||||
explicit operator bool() const { return !!mAtom; }
|
||||
nsIAtom* Atom() const { MOZ_ASSERT(mAtom); return mAtom; }
|
||||
bool IsCustomProperty() const { return mIsCustomProperty; }
|
||||
|
||||
private:
|
||||
nsIAtom* mAtom;
|
||||
bool mIsCustomProperty;
|
||||
};
|
||||
|
||||
void
|
||||
ServoDeclarationBlock::GetPropertyValue(const nsAString& aProperty,
|
||||
nsAString& aValue) const
|
||||
{
|
||||
if (PropertyAtomHolder holder{aProperty}) {
|
||||
Servo_DeclarationBlock_GetPropertyValue(
|
||||
mRaw, holder.Atom(), holder.IsCustomProperty(), &aValue);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ServoDeclarationBlock::GetPropertyValueByID(nsCSSPropertyID aPropID,
|
||||
nsAString& aValue) const
|
||||
{
|
||||
nsIAtom* atom = nsCSSProps::AtomForProperty(aPropID);
|
||||
Servo_DeclarationBlock_GetPropertyValue(mRaw, atom, false, &aValue);
|
||||
}
|
||||
|
||||
bool
|
||||
ServoDeclarationBlock::GetPropertyIsImportant(const nsAString& aProperty) const
|
||||
{
|
||||
if (PropertyAtomHolder holder{aProperty}) {
|
||||
return Servo_DeclarationBlock_GetPropertyIsImportant(
|
||||
mRaw, holder.Atom(), holder.IsCustomProperty());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void
|
||||
ServoDeclarationBlock::RemoveProperty(const nsAString& aProperty)
|
||||
{
|
||||
AssertMutable();
|
||||
if (PropertyAtomHolder holder{aProperty}) {
|
||||
Servo_DeclarationBlock_RemoveProperty(mRaw, holder.Atom(),
|
||||
holder.IsCustomProperty());
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ServoDeclarationBlock::RemovePropertyByID(nsCSSPropertyID aPropID)
|
||||
{
|
||||
AssertMutable();
|
||||
nsIAtom* atom = nsCSSProps::AtomForProperty(aPropID);
|
||||
Servo_DeclarationBlock_RemoveProperty(mRaw, atom, false);
|
||||
}
|
||||
|
||||
} // namespace mozilla
|
||||
72
layout/style/ServoDeclarationBlock.h
Normal file
72
layout/style/ServoDeclarationBlock.h
Normal file
|
|
@ -0,0 +1,72 @@
|
|||
/* -*- Mode: C++; 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/. */
|
||||
|
||||
#ifndef mozilla_ServoDeclarationBlock_h
|
||||
#define mozilla_ServoDeclarationBlock_h
|
||||
|
||||
#include "mozilla/ServoBindings.h"
|
||||
#include "mozilla/DeclarationBlock.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
class ServoDeclarationBlock final : public DeclarationBlock
|
||||
{
|
||||
public:
|
||||
ServoDeclarationBlock()
|
||||
: ServoDeclarationBlock(Servo_DeclarationBlock_CreateEmpty().Consume()) {}
|
||||
|
||||
ServoDeclarationBlock(const ServoDeclarationBlock& aCopy)
|
||||
: DeclarationBlock(aCopy)
|
||||
, mRaw(Servo_DeclarationBlock_Clone(aCopy.mRaw).Consume()) {}
|
||||
|
||||
NS_INLINE_DECL_REFCOUNTING(ServoDeclarationBlock)
|
||||
|
||||
static already_AddRefed<ServoDeclarationBlock>
|
||||
FromCssText(const nsAString& aCssText);
|
||||
|
||||
RawServoDeclarationBlock* Raw() const { return mRaw; }
|
||||
RawServoDeclarationBlock* const* RefRaw() const {
|
||||
static_assert(sizeof(RefPtr<RawServoDeclarationBlock>) ==
|
||||
sizeof(RawServoDeclarationBlock*),
|
||||
"RefPtr should just be a pointer");
|
||||
return reinterpret_cast<RawServoDeclarationBlock* const*>(&mRaw);
|
||||
}
|
||||
|
||||
void ToString(nsAString& aResult) const {
|
||||
Servo_DeclarationBlock_GetCssText(mRaw, &aResult);
|
||||
}
|
||||
|
||||
uint32_t Count() const {
|
||||
return Servo_DeclarationBlock_Count(mRaw);
|
||||
}
|
||||
bool GetNthProperty(uint32_t aIndex, nsAString& aReturn) const {
|
||||
aReturn.Truncate();
|
||||
return Servo_DeclarationBlock_GetNthProperty(mRaw, aIndex, &aReturn);
|
||||
}
|
||||
|
||||
void GetPropertyValue(const nsAString& aProperty, nsAString& aValue) const;
|
||||
void GetPropertyValueByID(nsCSSPropertyID aPropID, nsAString& aValue) const;
|
||||
void GetAuthoredPropertyValue(const nsAString& aProperty,
|
||||
nsAString& aValue) const {
|
||||
GetPropertyValue(aProperty, aValue);
|
||||
}
|
||||
bool GetPropertyIsImportant(const nsAString& aProperty) const;
|
||||
void RemoveProperty(const nsAString& aProperty);
|
||||
void RemovePropertyByID(nsCSSPropertyID aPropID);
|
||||
|
||||
protected:
|
||||
explicit ServoDeclarationBlock(
|
||||
already_AddRefed<RawServoDeclarationBlock> aRaw)
|
||||
: DeclarationBlock(StyleBackendType::Servo), mRaw(aRaw) {}
|
||||
|
||||
private:
|
||||
~ServoDeclarationBlock() {}
|
||||
|
||||
RefPtr<RawServoDeclarationBlock> mRaw;
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // mozilla_ServoDeclarationBlock_h
|
||||
46
layout/style/ServoElementSnapshot.cpp
Normal file
46
layout/style/ServoElementSnapshot.cpp
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* 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 "mozilla/ServoElementSnapshot.h"
|
||||
#include "mozilla/dom/Element.h"
|
||||
#include "nsIContentInlines.h"
|
||||
#include "nsContentUtils.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
ServoElementSnapshot::ServoElementSnapshot(Element* aElement)
|
||||
: mContains(Flags(0))
|
||||
, mState(0)
|
||||
, mExplicitRestyleHint(nsRestyleHint(0))
|
||||
, mExplicitChangeHint(nsChangeHint(0))
|
||||
{
|
||||
mIsHTMLElementInHTMLDocument =
|
||||
aElement->IsHTMLElement() && aElement->IsInHTMLDocument();
|
||||
mIsInChromeDocument =
|
||||
nsContentUtils::IsChromeDoc(aElement->OwnerDoc());
|
||||
}
|
||||
|
||||
void
|
||||
ServoElementSnapshot::AddAttrs(Element* aElement)
|
||||
{
|
||||
MOZ_ASSERT(aElement);
|
||||
|
||||
if (HasAny(Flags::Attributes)) {
|
||||
return;
|
||||
}
|
||||
|
||||
uint32_t attrCount = aElement->GetAttrCount();
|
||||
const nsAttrName* attrName;
|
||||
for (uint32_t i = 0; i < attrCount; ++i) {
|
||||
attrName = aElement->GetAttrNameAt(i);
|
||||
const nsAttrValue* attrValue =
|
||||
aElement->GetParsedAttr(attrName->LocalName(), attrName->NamespaceID());
|
||||
mAttrs.AppendElement(ServoAttrSnapshot(*attrName, *attrValue));
|
||||
}
|
||||
mContains |= Flags::Attributes;
|
||||
}
|
||||
|
||||
} // namespace mozilla
|
||||
169
layout/style/ServoElementSnapshot.h
Normal file
169
layout/style/ServoElementSnapshot.h
Normal file
|
|
@ -0,0 +1,169 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* 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_ServoElementSnapshot_h
|
||||
#define mozilla_ServoElementSnapshot_h
|
||||
|
||||
#include "mozilla/EventStates.h"
|
||||
#include "mozilla/TypedEnumBits.h"
|
||||
#include "mozilla/dom/BorrowedAttrInfo.h"
|
||||
#include "nsAttrName.h"
|
||||
#include "nsAttrValue.h"
|
||||
#include "nsChangeHint.h"
|
||||
#include "nsIAtom.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
namespace dom {
|
||||
class Element;
|
||||
} // namespace dom
|
||||
|
||||
/**
|
||||
* A structure representing a single attribute name and value.
|
||||
*
|
||||
* This is pretty similar to the private nsAttrAndChildArray::InternalAttr.
|
||||
*/
|
||||
struct ServoAttrSnapshot
|
||||
{
|
||||
nsAttrName mName;
|
||||
nsAttrValue mValue;
|
||||
|
||||
ServoAttrSnapshot(const nsAttrName& aName, const nsAttrValue& aValue)
|
||||
: mName(aName)
|
||||
, mValue(aValue)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* A bitflags enum class used to determine what data does a ServoElementSnapshot
|
||||
* contains.
|
||||
*/
|
||||
enum class ServoElementSnapshotFlags : uint8_t
|
||||
{
|
||||
State = 1 << 0,
|
||||
Attributes = 1 << 1,
|
||||
All = State | Attributes
|
||||
};
|
||||
|
||||
MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(ServoElementSnapshotFlags)
|
||||
|
||||
/**
|
||||
* This class holds all non-tree-structural state of an element that might be
|
||||
* used for selector matching eventually.
|
||||
*
|
||||
* This means the attributes, and the element state, such as :hover, :active,
|
||||
* etc...
|
||||
*/
|
||||
class ServoElementSnapshot
|
||||
{
|
||||
typedef dom::BorrowedAttrInfo BorrowedAttrInfo;
|
||||
typedef dom::Element Element;
|
||||
typedef EventStates::ServoType ServoStateType;
|
||||
|
||||
public:
|
||||
typedef ServoElementSnapshotFlags Flags;
|
||||
|
||||
explicit ServoElementSnapshot(Element* aElement);
|
||||
|
||||
bool HasAttrs() { return HasAny(Flags::Attributes); }
|
||||
|
||||
bool HasState() { return HasAny(Flags::State); }
|
||||
|
||||
/**
|
||||
* Captures the given state (if not previously captured).
|
||||
*/
|
||||
void AddState(EventStates aState)
|
||||
{
|
||||
if (!HasAny(Flags::State)) {
|
||||
mState = aState.ServoValue();
|
||||
mContains |= Flags::State;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Captures the given element attributes (if not previously captured).
|
||||
*/
|
||||
void AddAttrs(Element* aElement);
|
||||
|
||||
void AddExplicitChangeHint(nsChangeHint aMinChangeHint)
|
||||
{
|
||||
mExplicitChangeHint |= aMinChangeHint;
|
||||
}
|
||||
|
||||
void AddExplicitRestyleHint(nsRestyleHint aRestyleHint)
|
||||
{
|
||||
mExplicitRestyleHint |= aRestyleHint;
|
||||
}
|
||||
|
||||
nsRestyleHint ExplicitRestyleHint() { return mExplicitRestyleHint; }
|
||||
|
||||
nsChangeHint ExplicitChangeHint() { return mExplicitChangeHint; }
|
||||
|
||||
/**
|
||||
* Needed methods for attribute matching.
|
||||
*/
|
||||
BorrowedAttrInfo GetAttrInfoAt(uint32_t aIndex) const
|
||||
{
|
||||
if (aIndex >= mAttrs.Length()) {
|
||||
return BorrowedAttrInfo(nullptr, nullptr);
|
||||
}
|
||||
return BorrowedAttrInfo(&mAttrs[aIndex].mName, &mAttrs[aIndex].mValue);
|
||||
}
|
||||
|
||||
const nsAttrValue* GetParsedAttr(nsIAtom* aLocalName) const
|
||||
{
|
||||
return GetParsedAttr(aLocalName, kNameSpaceID_None);
|
||||
}
|
||||
|
||||
const nsAttrValue* GetParsedAttr(nsIAtom* aLocalName,
|
||||
int32_t aNamespaceID) const
|
||||
{
|
||||
uint32_t i, len = mAttrs.Length();
|
||||
if (aNamespaceID == kNameSpaceID_None) {
|
||||
// This should be the common case so lets make an optimized loop
|
||||
for (i = 0; i < len; ++i) {
|
||||
if (mAttrs[i].mName.Equals(aLocalName)) {
|
||||
return &mAttrs[i].mValue;
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
for (i = 0; i < len; ++i) {
|
||||
if (mAttrs[i].mName.Equals(aLocalName, aNamespaceID)) {
|
||||
return &mAttrs[i].mValue;
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool IsInChromeDocument() const
|
||||
{
|
||||
return mIsInChromeDocument;
|
||||
}
|
||||
|
||||
bool HasAny(Flags aFlags) { return bool(mContains & aFlags); }
|
||||
|
||||
private:
|
||||
// TODO: Profile, a 1 or 2 element AutoTArray could be worth it, given we know
|
||||
// we're dealing with attribute changes when we take snapshots of attributes,
|
||||
// though it can be wasted space if we deal with a lot of state-only
|
||||
// snapshots.
|
||||
Flags mContains;
|
||||
nsTArray<ServoAttrSnapshot> mAttrs;
|
||||
ServoStateType mState;
|
||||
nsRestyleHint mExplicitRestyleHint;
|
||||
nsChangeHint mExplicitChangeHint;
|
||||
bool mIsHTMLElementInHTMLDocument;
|
||||
bool mIsInChromeDocument;
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
|
||||
#endif
|
||||
479
layout/style/ServoStyleSet.cpp
Normal file
479
layout/style/ServoStyleSet.cpp
Normal file
|
|
@ -0,0 +1,479 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* 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 "mozilla/ServoStyleSet.h"
|
||||
|
||||
#include "mozilla/ServoRestyleManager.h"
|
||||
#include "mozilla/dom/ChildIterator.h"
|
||||
#include "nsCSSAnonBoxes.h"
|
||||
#include "nsCSSPseudoElements.h"
|
||||
#include "nsIDocumentInlines.h"
|
||||
#include "nsPrintfCString.h"
|
||||
#include "nsStyleContext.h"
|
||||
#include "nsStyleSet.h"
|
||||
|
||||
using namespace mozilla;
|
||||
using namespace mozilla::dom;
|
||||
|
||||
ServoStyleSet::ServoStyleSet()
|
||||
: mPresContext(nullptr)
|
||||
, mRawSet(Servo_StyleSet_Init())
|
||||
, mBatching(0)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
ServoStyleSet::Init(nsPresContext* aPresContext)
|
||||
{
|
||||
mPresContext = aPresContext;
|
||||
}
|
||||
|
||||
void
|
||||
ServoStyleSet::BeginShutdown()
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
ServoStyleSet::Shutdown()
|
||||
{
|
||||
mRawSet = nullptr;
|
||||
}
|
||||
|
||||
bool
|
||||
ServoStyleSet::GetAuthorStyleDisabled() const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
nsresult
|
||||
ServoStyleSet::SetAuthorStyleDisabled(bool aStyleDisabled)
|
||||
{
|
||||
MOZ_CRASH("stylo: not implemented");
|
||||
}
|
||||
|
||||
void
|
||||
ServoStyleSet::BeginUpdate()
|
||||
{
|
||||
++mBatching;
|
||||
}
|
||||
|
||||
nsresult
|
||||
ServoStyleSet::EndUpdate()
|
||||
{
|
||||
MOZ_ASSERT(mBatching > 0);
|
||||
if (--mBatching > 0) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// ... do something ...
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
already_AddRefed<nsStyleContext>
|
||||
ServoStyleSet::ResolveStyleFor(Element* aElement,
|
||||
nsStyleContext* aParentContext)
|
||||
{
|
||||
return GetContext(aElement, aParentContext, nullptr,
|
||||
CSSPseudoElementType::NotPseudo);
|
||||
}
|
||||
|
||||
already_AddRefed<nsStyleContext>
|
||||
ServoStyleSet::GetContext(nsIContent* aContent,
|
||||
nsStyleContext* aParentContext,
|
||||
nsIAtom* aPseudoTag,
|
||||
CSSPseudoElementType aPseudoType)
|
||||
{
|
||||
RefPtr<ServoComputedValues> computedValues =
|
||||
Servo_ComputedValues_Get(aContent).Consume();
|
||||
MOZ_ASSERT(computedValues);
|
||||
return GetContext(computedValues.forget(), aParentContext, aPseudoTag, aPseudoType);
|
||||
}
|
||||
|
||||
already_AddRefed<nsStyleContext>
|
||||
ServoStyleSet::GetContext(already_AddRefed<ServoComputedValues> aComputedValues,
|
||||
nsStyleContext* aParentContext,
|
||||
nsIAtom* aPseudoTag,
|
||||
CSSPseudoElementType aPseudoType)
|
||||
{
|
||||
// XXXbholley: nsStyleSet does visited handling here.
|
||||
|
||||
// XXXbholley: Figure out the correct thing to pass here. Does this fixup
|
||||
// duplicate something that servo already does?
|
||||
bool skipFixup = false;
|
||||
|
||||
return NS_NewStyleContext(aParentContext, mPresContext, aPseudoTag,
|
||||
aPseudoType, Move(aComputedValues), skipFixup);
|
||||
}
|
||||
|
||||
already_AddRefed<nsStyleContext>
|
||||
ServoStyleSet::ResolveStyleFor(Element* aElement,
|
||||
nsStyleContext* aParentContext,
|
||||
TreeMatchContext& aTreeMatchContext)
|
||||
{
|
||||
// aTreeMatchContext is used to speed up selector matching,
|
||||
// but if the element already has a ServoComputedValues computed in
|
||||
// advance, then we shouldn't need to use it.
|
||||
return ResolveStyleFor(aElement, aParentContext);
|
||||
}
|
||||
|
||||
already_AddRefed<nsStyleContext>
|
||||
ServoStyleSet::ResolveStyleForText(nsIContent* aTextNode,
|
||||
nsStyleContext* aParentContext)
|
||||
{
|
||||
MOZ_ASSERT(aTextNode && aTextNode->IsNodeOfType(nsINode::eTEXT));
|
||||
MOZ_ASSERT(aTextNode->GetParent());
|
||||
MOZ_ASSERT(aParentContext);
|
||||
|
||||
// Gecko expects text node style contexts to be like elements that match no
|
||||
// rules: inherit the inherit structs, reset the reset structs. This is cheap
|
||||
// enough to do on the main thread, which means that the parallel style system
|
||||
// can avoid worrying about text nodes.
|
||||
const ServoComputedValues* parentComputedValues =
|
||||
aParentContext->StyleSource().AsServoComputedValues();
|
||||
RefPtr<ServoComputedValues> computedValues =
|
||||
Servo_ComputedValues_Inherit(parentComputedValues).Consume();
|
||||
|
||||
return GetContext(computedValues.forget(), aParentContext,
|
||||
nsCSSAnonBoxes::mozText, CSSPseudoElementType::AnonBox);
|
||||
}
|
||||
|
||||
already_AddRefed<nsStyleContext>
|
||||
ServoStyleSet::ResolveStyleForOtherNonElement(nsStyleContext* aParentContext)
|
||||
{
|
||||
// The parent context can be null if the non-element share a style context
|
||||
// with the root of an anonymous subtree.
|
||||
const ServoComputedValues* parent =
|
||||
aParentContext ? aParentContext->StyleSource().AsServoComputedValues() : nullptr;
|
||||
RefPtr<ServoComputedValues> computedValues =
|
||||
Servo_ComputedValues_Inherit(parent).Consume();
|
||||
MOZ_ASSERT(computedValues);
|
||||
|
||||
return GetContext(computedValues.forget(), aParentContext,
|
||||
nsCSSAnonBoxes::mozOtherNonElement,
|
||||
CSSPseudoElementType::AnonBox);
|
||||
}
|
||||
|
||||
already_AddRefed<nsStyleContext>
|
||||
ServoStyleSet::ResolvePseudoElementStyle(Element* aParentElement,
|
||||
CSSPseudoElementType aType,
|
||||
nsStyleContext* aParentContext,
|
||||
Element* aPseudoElement)
|
||||
{
|
||||
if (aPseudoElement) {
|
||||
NS_ERROR("stylo: We don't support CSS_PSEUDO_ELEMENT_SUPPORTS_USER_ACTION_STATE yet");
|
||||
}
|
||||
MOZ_ASSERT(aParentContext);
|
||||
MOZ_ASSERT(aType < CSSPseudoElementType::Count);
|
||||
nsIAtom* pseudoTag = nsCSSPseudoElements::GetPseudoAtom(aType);
|
||||
|
||||
RefPtr<ServoComputedValues> computedValues =
|
||||
Servo_ComputedValues_GetForPseudoElement(
|
||||
aParentContext->StyleSource().AsServoComputedValues(),
|
||||
aParentElement, pseudoTag, mRawSet.get(), /* is_probe = */ false).Consume();
|
||||
MOZ_ASSERT(computedValues);
|
||||
|
||||
return GetContext(computedValues.forget(), aParentContext, pseudoTag, aType);
|
||||
}
|
||||
|
||||
// aFlags is an nsStyleSet flags bitfield
|
||||
already_AddRefed<nsStyleContext>
|
||||
ServoStyleSet::ResolveAnonymousBoxStyle(nsIAtom* aPseudoTag,
|
||||
nsStyleContext* aParentContext,
|
||||
uint32_t aFlags)
|
||||
{
|
||||
MOZ_ASSERT(nsCSSAnonBoxes::IsAnonBox(aPseudoTag));
|
||||
|
||||
MOZ_ASSERT(aFlags == 0 ||
|
||||
aFlags == nsStyleSet::eSkipParentDisplayBasedStyleFixup);
|
||||
bool skipFixup = aFlags & nsStyleSet::eSkipParentDisplayBasedStyleFixup;
|
||||
|
||||
const ServoComputedValues* parentStyle =
|
||||
aParentContext ? aParentContext->StyleSource().AsServoComputedValues()
|
||||
: nullptr;
|
||||
RefPtr<ServoComputedValues> computedValues =
|
||||
Servo_ComputedValues_GetForAnonymousBox(parentStyle, aPseudoTag,
|
||||
mRawSet.get()).Consume();
|
||||
#ifdef DEBUG
|
||||
if (!computedValues) {
|
||||
nsString pseudo;
|
||||
aPseudoTag->ToString(pseudo);
|
||||
NS_ERROR(nsPrintfCString("stylo: could not get anon-box: %s",
|
||||
NS_ConvertUTF16toUTF8(pseudo).get()).get());
|
||||
MOZ_CRASH();
|
||||
}
|
||||
#endif
|
||||
|
||||
return NS_NewStyleContext(aParentContext, mPresContext, aPseudoTag,
|
||||
CSSPseudoElementType::AnonBox,
|
||||
computedValues.forget(), skipFixup);
|
||||
}
|
||||
|
||||
// manage the set of style sheets in the style set
|
||||
nsresult
|
||||
ServoStyleSet::AppendStyleSheet(SheetType aType,
|
||||
ServoStyleSheet* aSheet)
|
||||
{
|
||||
MOZ_ASSERT(aSheet);
|
||||
MOZ_ASSERT(aSheet->IsApplicable());
|
||||
MOZ_ASSERT(nsStyleSet::IsCSSSheetType(aType));
|
||||
|
||||
mSheets[aType].RemoveElement(aSheet);
|
||||
mSheets[aType].AppendElement(aSheet);
|
||||
|
||||
// Maintain a mirrored list of sheets on the servo side.
|
||||
Servo_StyleSet_AppendStyleSheet(mRawSet.get(), aSheet->RawSheet());
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
ServoStyleSet::PrependStyleSheet(SheetType aType,
|
||||
ServoStyleSheet* aSheet)
|
||||
{
|
||||
MOZ_ASSERT(aSheet);
|
||||
MOZ_ASSERT(aSheet->IsApplicable());
|
||||
MOZ_ASSERT(nsStyleSet::IsCSSSheetType(aType));
|
||||
|
||||
mSheets[aType].RemoveElement(aSheet);
|
||||
mSheets[aType].InsertElementAt(0, aSheet);
|
||||
|
||||
// Maintain a mirrored list of sheets on the servo side.
|
||||
Servo_StyleSet_PrependStyleSheet(mRawSet.get(), aSheet->RawSheet());
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
ServoStyleSet::RemoveStyleSheet(SheetType aType,
|
||||
ServoStyleSheet* aSheet)
|
||||
{
|
||||
MOZ_ASSERT(aSheet);
|
||||
MOZ_ASSERT(aSheet->IsApplicable());
|
||||
MOZ_ASSERT(nsStyleSet::IsCSSSheetType(aType));
|
||||
|
||||
mSheets[aType].RemoveElement(aSheet);
|
||||
|
||||
// Maintain a mirrored list of sheets on the servo side.
|
||||
Servo_StyleSet_RemoveStyleSheet(mRawSet.get(), aSheet->RawSheet());
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
ServoStyleSet::ReplaceSheets(SheetType aType,
|
||||
const nsTArray<RefPtr<ServoStyleSheet>>& aNewSheets)
|
||||
{
|
||||
// Gecko uses a two-dimensional array keyed by sheet type, whereas Servo
|
||||
// stores a flattened list. This makes ReplaceSheets a pretty clunky thing
|
||||
// to express. If the need ever arises, we can easily make this more efficent,
|
||||
// probably by aligning the representations better between engines.
|
||||
|
||||
for (ServoStyleSheet* sheet : mSheets[aType]) {
|
||||
Servo_StyleSet_RemoveStyleSheet(mRawSet.get(), sheet->RawSheet());
|
||||
}
|
||||
|
||||
mSheets[aType].Clear();
|
||||
mSheets[aType].AppendElements(aNewSheets);
|
||||
|
||||
for (ServoStyleSheet* sheet : mSheets[aType]) {
|
||||
Servo_StyleSet_AppendStyleSheet(mRawSet.get(), sheet->RawSheet());
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
ServoStyleSet::InsertStyleSheetBefore(SheetType aType,
|
||||
ServoStyleSheet* aNewSheet,
|
||||
ServoStyleSheet* aReferenceSheet)
|
||||
{
|
||||
MOZ_ASSERT(aNewSheet);
|
||||
MOZ_ASSERT(aReferenceSheet);
|
||||
MOZ_ASSERT(aNewSheet->IsApplicable());
|
||||
|
||||
mSheets[aType].RemoveElement(aNewSheet);
|
||||
size_t idx = mSheets[aType].IndexOf(aReferenceSheet);
|
||||
if (idx == mSheets[aType].NoIndex) {
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
|
||||
mSheets[aType].InsertElementAt(idx, aNewSheet);
|
||||
|
||||
// Maintain a mirrored list of sheets on the servo side.
|
||||
Servo_StyleSet_InsertStyleSheetBefore(mRawSet.get(), aNewSheet->RawSheet(),
|
||||
aReferenceSheet->RawSheet());
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
int32_t
|
||||
ServoStyleSet::SheetCount(SheetType aType) const
|
||||
{
|
||||
MOZ_ASSERT(nsStyleSet::IsCSSSheetType(aType));
|
||||
return mSheets[aType].Length();
|
||||
}
|
||||
|
||||
ServoStyleSheet*
|
||||
ServoStyleSet::StyleSheetAt(SheetType aType,
|
||||
int32_t aIndex) const
|
||||
{
|
||||
MOZ_ASSERT(nsStyleSet::IsCSSSheetType(aType));
|
||||
return mSheets[aType][aIndex];
|
||||
}
|
||||
|
||||
nsresult
|
||||
ServoStyleSet::RemoveDocStyleSheet(ServoStyleSheet* aSheet)
|
||||
{
|
||||
return RemoveStyleSheet(SheetType::Doc, aSheet);
|
||||
}
|
||||
|
||||
nsresult
|
||||
ServoStyleSet::AddDocStyleSheet(ServoStyleSheet* aSheet,
|
||||
nsIDocument* aDocument)
|
||||
{
|
||||
RefPtr<StyleSheet> strong(aSheet);
|
||||
|
||||
mSheets[SheetType::Doc].RemoveElement(aSheet);
|
||||
|
||||
size_t index =
|
||||
aDocument->FindDocStyleSheetInsertionPoint(mSheets[SheetType::Doc], aSheet);
|
||||
mSheets[SheetType::Doc].InsertElementAt(index, aSheet);
|
||||
|
||||
// Maintain a mirrored list of sheets on the servo side.
|
||||
ServoStyleSheet* followingSheet =
|
||||
mSheets[SheetType::Doc].SafeElementAt(index + 1);
|
||||
if (followingSheet) {
|
||||
Servo_StyleSet_InsertStyleSheetBefore(mRawSet.get(), aSheet->RawSheet(),
|
||||
followingSheet->RawSheet());
|
||||
} else {
|
||||
Servo_StyleSet_AppendStyleSheet(mRawSet.get(), aSheet->RawSheet());
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
already_AddRefed<nsStyleContext>
|
||||
ServoStyleSet::ProbePseudoElementStyle(Element* aParentElement,
|
||||
CSSPseudoElementType aType,
|
||||
nsStyleContext* aParentContext)
|
||||
{
|
||||
MOZ_ASSERT(aParentContext);
|
||||
MOZ_ASSERT(aType < CSSPseudoElementType::Count);
|
||||
nsIAtom* pseudoTag = nsCSSPseudoElements::GetPseudoAtom(aType);
|
||||
|
||||
RefPtr<ServoComputedValues> computedValues =
|
||||
Servo_ComputedValues_GetForPseudoElement(
|
||||
aParentContext->StyleSource().AsServoComputedValues(),
|
||||
aParentElement, pseudoTag, mRawSet.get(), /* is_probe = */ true).Consume();
|
||||
|
||||
if (!computedValues) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// For :before and :after pseudo-elements, having display: none or no
|
||||
// 'content' property is equivalent to not having the pseudo-element
|
||||
// at all.
|
||||
if (computedValues &&
|
||||
(pseudoTag == nsCSSPseudoElements::before ||
|
||||
pseudoTag == nsCSSPseudoElements::after)) {
|
||||
const nsStyleDisplay *display = Servo_GetStyleDisplay(computedValues);
|
||||
const nsStyleContent *content = Servo_GetStyleContent(computedValues);
|
||||
// XXXldb What is contentCount for |content: ""|?
|
||||
if (display->mDisplay == StyleDisplay::None ||
|
||||
content->ContentCount() == 0) {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
return GetContext(computedValues.forget(), aParentContext, pseudoTag, aType);
|
||||
}
|
||||
|
||||
already_AddRefed<nsStyleContext>
|
||||
ServoStyleSet::ProbePseudoElementStyle(Element* aParentElement,
|
||||
CSSPseudoElementType aType,
|
||||
nsStyleContext* aParentContext,
|
||||
TreeMatchContext& aTreeMatchContext,
|
||||
Element* aPseudoElement)
|
||||
{
|
||||
if (aPseudoElement) {
|
||||
NS_ERROR("stylo: We don't support CSS_PSEUDO_ELEMENT_SUPPORTS_USER_ACTION_STATE yet");
|
||||
}
|
||||
return ProbePseudoElementStyle(aParentElement, aType, aParentContext);
|
||||
}
|
||||
|
||||
nsRestyleHint
|
||||
ServoStyleSet::HasStateDependentStyle(dom::Element* aElement,
|
||||
EventStates aStateMask)
|
||||
{
|
||||
NS_WARNING("stylo: HasStateDependentStyle always returns zero!");
|
||||
return nsRestyleHint(0);
|
||||
}
|
||||
|
||||
nsRestyleHint
|
||||
ServoStyleSet::HasStateDependentStyle(dom::Element* aElement,
|
||||
CSSPseudoElementType aPseudoType,
|
||||
dom::Element* aPseudoElement,
|
||||
EventStates aStateMask)
|
||||
{
|
||||
NS_WARNING("stylo: HasStateDependentStyle always returns zero!");
|
||||
return nsRestyleHint(0);
|
||||
}
|
||||
|
||||
nsRestyleHint
|
||||
ServoStyleSet::ComputeRestyleHint(dom::Element* aElement,
|
||||
ServoElementSnapshot* aSnapshot)
|
||||
{
|
||||
return Servo_ComputeRestyleHint(aElement, aSnapshot, mRawSet.get());
|
||||
}
|
||||
|
||||
static void
|
||||
ClearDirtyBits(nsIContent* aContent)
|
||||
{
|
||||
bool traverseDescendants = aContent->HasDirtyDescendantsForServo();
|
||||
aContent->UnsetIsDirtyAndHasDirtyDescendantsForServo();
|
||||
if (!traverseDescendants) {
|
||||
return;
|
||||
}
|
||||
|
||||
StyleChildrenIterator it(aContent);
|
||||
for (nsIContent* n = it.GetNextChild(); n; n = it.GetNextChild()) {
|
||||
ClearDirtyBits(n);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ServoStyleSet::StyleDocument(bool aLeaveDirtyBits)
|
||||
{
|
||||
// Grab the root.
|
||||
nsIDocument* doc = mPresContext->Document();
|
||||
nsIContent* root = doc->GetRootElement();
|
||||
MOZ_ASSERT(root);
|
||||
|
||||
// Restyle the document, clearing the dirty bits if requested.
|
||||
Servo_RestyleSubtree(root, mRawSet.get());
|
||||
if (!aLeaveDirtyBits) {
|
||||
ClearDirtyBits(root);
|
||||
doc->UnsetHasDirtyDescendantsForServo();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ServoStyleSet::StyleNewSubtree(nsIContent* aContent)
|
||||
{
|
||||
MOZ_ASSERT(aContent->IsDirtyForServo());
|
||||
if (aContent->IsElement() || aContent->IsNodeOfType(nsINode::eTEXT)) {
|
||||
Servo_RestyleSubtree(aContent, mRawSet.get());
|
||||
}
|
||||
ClearDirtyBits(aContent);
|
||||
}
|
||||
|
||||
void
|
||||
ServoStyleSet::StyleNewChildren(nsIContent* aParent)
|
||||
{
|
||||
MOZ_ASSERT(aParent->HasDirtyDescendantsForServo());
|
||||
Servo_RestyleSubtree(aParent, mRawSet.get());
|
||||
ClearDirtyBits(aParent);
|
||||
}
|
||||
175
layout/style/ServoStyleSet.h
Normal file
175
layout/style/ServoStyleSet.h
Normal file
|
|
@ -0,0 +1,175 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* 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_ServoStyleSet_h
|
||||
#define mozilla_ServoStyleSet_h
|
||||
|
||||
#include "mozilla/EnumeratedArray.h"
|
||||
#include "mozilla/EventStates.h"
|
||||
#include "mozilla/ServoBindingTypes.h"
|
||||
#include "mozilla/ServoElementSnapshot.h"
|
||||
#include "mozilla/StyleSheetInlines.h"
|
||||
#include "mozilla/SheetType.h"
|
||||
#include "mozilla/UniquePtr.h"
|
||||
#include "nsCSSPseudoElements.h"
|
||||
#include "nsChangeHint.h"
|
||||
#include "nsIAtom.h"
|
||||
#include "nsTArray.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
class Element;
|
||||
} // namespace dom
|
||||
class CSSStyleSheet;
|
||||
class ServoRestyleManager;
|
||||
class ServoStyleSheet;
|
||||
} // namespace mozilla
|
||||
class nsIDocument;
|
||||
class nsStyleContext;
|
||||
class nsPresContext;
|
||||
struct TreeMatchContext;
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
/**
|
||||
* The set of style sheets that apply to a document, backed by a Servo
|
||||
* Stylist. A ServoStyleSet contains ServoStyleSheets.
|
||||
*/
|
||||
class ServoStyleSet
|
||||
{
|
||||
friend class ServoRestyleManager;
|
||||
public:
|
||||
ServoStyleSet();
|
||||
|
||||
void Init(nsPresContext* aPresContext);
|
||||
void BeginShutdown();
|
||||
void Shutdown();
|
||||
|
||||
bool GetAuthorStyleDisabled() const;
|
||||
nsresult SetAuthorStyleDisabled(bool aStyleDisabled);
|
||||
|
||||
void BeginUpdate();
|
||||
nsresult EndUpdate();
|
||||
|
||||
already_AddRefed<nsStyleContext>
|
||||
ResolveStyleFor(dom::Element* aElement,
|
||||
nsStyleContext* aParentContext);
|
||||
|
||||
already_AddRefed<nsStyleContext>
|
||||
ResolveStyleFor(dom::Element* aElement,
|
||||
nsStyleContext* aParentContext,
|
||||
TreeMatchContext& aTreeMatchContext);
|
||||
|
||||
already_AddRefed<nsStyleContext>
|
||||
ResolveStyleForText(nsIContent* aTextNode,
|
||||
nsStyleContext* aParentContext);
|
||||
|
||||
already_AddRefed<nsStyleContext>
|
||||
ResolveStyleForOtherNonElement(nsStyleContext* aParentContext);
|
||||
|
||||
already_AddRefed<nsStyleContext>
|
||||
ResolvePseudoElementStyle(dom::Element* aParentElement,
|
||||
mozilla::CSSPseudoElementType aType,
|
||||
nsStyleContext* aParentContext,
|
||||
dom::Element* aPseudoElement);
|
||||
|
||||
// aFlags is an nsStyleSet flags bitfield
|
||||
already_AddRefed<nsStyleContext>
|
||||
ResolveAnonymousBoxStyle(nsIAtom* aPseudoTag, nsStyleContext* aParentContext,
|
||||
uint32_t aFlags = 0);
|
||||
|
||||
// manage the set of style sheets in the style set
|
||||
nsresult AppendStyleSheet(SheetType aType, ServoStyleSheet* aSheet);
|
||||
nsresult PrependStyleSheet(SheetType aType, ServoStyleSheet* aSheet);
|
||||
nsresult RemoveStyleSheet(SheetType aType, ServoStyleSheet* aSheet);
|
||||
nsresult ReplaceSheets(SheetType aType,
|
||||
const nsTArray<RefPtr<ServoStyleSheet>>& aNewSheets);
|
||||
nsresult InsertStyleSheetBefore(SheetType aType,
|
||||
ServoStyleSheet* aNewSheet,
|
||||
ServoStyleSheet* aReferenceSheet);
|
||||
|
||||
int32_t SheetCount(SheetType aType) const;
|
||||
ServoStyleSheet* StyleSheetAt(SheetType aType, int32_t aIndex) const;
|
||||
|
||||
nsresult RemoveDocStyleSheet(ServoStyleSheet* aSheet);
|
||||
nsresult AddDocStyleSheet(ServoStyleSheet* aSheet, nsIDocument* aDocument);
|
||||
|
||||
// check whether there is ::before/::after style for an element
|
||||
already_AddRefed<nsStyleContext>
|
||||
ProbePseudoElementStyle(dom::Element* aParentElement,
|
||||
mozilla::CSSPseudoElementType aType,
|
||||
nsStyleContext* aParentContext);
|
||||
|
||||
already_AddRefed<nsStyleContext>
|
||||
ProbePseudoElementStyle(dom::Element* aParentElement,
|
||||
mozilla::CSSPseudoElementType aType,
|
||||
nsStyleContext* aParentContext,
|
||||
TreeMatchContext& aTreeMatchContext,
|
||||
dom::Element* aPseudoElement = nullptr);
|
||||
|
||||
// Test if style is dependent on content state
|
||||
nsRestyleHint HasStateDependentStyle(dom::Element* aElement,
|
||||
EventStates aStateMask);
|
||||
nsRestyleHint HasStateDependentStyle(
|
||||
dom::Element* aElement, mozilla::CSSPseudoElementType aPseudoType,
|
||||
dom::Element* aPseudoElement, EventStates aStateMask);
|
||||
|
||||
/**
|
||||
* Computes a restyle hint given a element and a previous element snapshot.
|
||||
*/
|
||||
nsRestyleHint ComputeRestyleHint(dom::Element* aElement,
|
||||
ServoElementSnapshot* aSnapshot);
|
||||
|
||||
/**
|
||||
* Performs a Servo traversal to compute style for all dirty nodes in the
|
||||
* document. The root element must be non-null.
|
||||
*
|
||||
* If aLeaveDirtyBits is true, the dirty/dirty-descendant bits are not
|
||||
* cleared.
|
||||
*/
|
||||
void StyleDocument(bool aLeaveDirtyBits);
|
||||
|
||||
/**
|
||||
* Eagerly styles a subtree of dirty nodes that were just appended to the
|
||||
* tree. This is used in situations where we need the style immediately and
|
||||
* cannot wait for a future batch restyle.
|
||||
*
|
||||
* The subtree must have the root dirty bit set, which currently gets
|
||||
* propagated to all descendants. The dirty bits are cleared before
|
||||
* returning.
|
||||
*/
|
||||
void StyleNewSubtree(nsIContent* aContent);
|
||||
|
||||
/**
|
||||
* Like the above, but does not assume that the root node is dirty. When
|
||||
* appending multiple children to a potentially-non-dirty node, it's
|
||||
* preferable to call StyleNewChildren on the node rather than making multiple
|
||||
* calls to StyleNewSubtree on each child, since it allows for more
|
||||
* parallelism.
|
||||
*/
|
||||
void StyleNewChildren(nsIContent* aParent);
|
||||
|
||||
private:
|
||||
already_AddRefed<nsStyleContext> GetContext(already_AddRefed<ServoComputedValues>,
|
||||
nsStyleContext* aParentContext,
|
||||
nsIAtom* aPseudoTag,
|
||||
CSSPseudoElementType aPseudoType);
|
||||
|
||||
already_AddRefed<nsStyleContext> GetContext(nsIContent* aContent,
|
||||
nsStyleContext* aParentContext,
|
||||
nsIAtom* aPseudoTag,
|
||||
CSSPseudoElementType aPseudoType);
|
||||
|
||||
nsPresContext* mPresContext;
|
||||
UniquePtr<RawServoStyleSet> mRawSet;
|
||||
EnumeratedArray<SheetType, SheetType::Count,
|
||||
nsTArray<RefPtr<ServoStyleSheet>>> mSheets;
|
||||
int32_t mBatching;
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // mozilla_ServoStyleSet_h
|
||||
143
layout/style/ServoStyleSheet.cpp
Normal file
143
layout/style/ServoStyleSheet.cpp
Normal file
|
|
@ -0,0 +1,143 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* 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 "mozilla/ServoStyleSheet.h"
|
||||
#include "mozilla/StyleBackendType.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
ServoStyleSheet::ServoStyleSheet(css::SheetParsingMode aParsingMode,
|
||||
CORSMode aCORSMode,
|
||||
net::ReferrerPolicy aReferrerPolicy,
|
||||
const dom::SRIMetadata& aIntegrity)
|
||||
: StyleSheet(StyleBackendType::Servo, aParsingMode)
|
||||
, mSheetInfo(aCORSMode, aReferrerPolicy, aIntegrity)
|
||||
{
|
||||
}
|
||||
|
||||
ServoStyleSheet::~ServoStyleSheet()
|
||||
{
|
||||
DropSheet();
|
||||
}
|
||||
|
||||
bool
|
||||
ServoStyleSheet::HasRules() const
|
||||
{
|
||||
return mSheet && Servo_StyleSheet_HasRules(mSheet);
|
||||
}
|
||||
|
||||
void
|
||||
ServoStyleSheet::SetOwningDocument(nsIDocument* aDocument)
|
||||
{
|
||||
// XXXheycam: Traverse to child ServoStyleSheets to set this, like
|
||||
// CSSStyleSheet::SetOwningDocument does.
|
||||
|
||||
mDocument = aDocument;
|
||||
}
|
||||
|
||||
ServoStyleSheet*
|
||||
ServoStyleSheet::GetParentSheet() const
|
||||
{
|
||||
// XXXheycam: When we implement support for child sheets, we'll have
|
||||
// to fix SetOwningDocument to propagate the owning document down
|
||||
// to the children.
|
||||
MOZ_CRASH("stylo: not implemented");
|
||||
}
|
||||
|
||||
void
|
||||
ServoStyleSheet::AppendStyleSheet(ServoStyleSheet* aSheet)
|
||||
{
|
||||
// XXXheycam: When we implement support for child sheets, we'll have
|
||||
// to fix SetOwningDocument to propagate the owning document down
|
||||
// to the children.
|
||||
MOZ_CRASH("stylo: not implemented");
|
||||
}
|
||||
|
||||
nsresult
|
||||
ServoStyleSheet::ParseSheet(const nsAString& aInput,
|
||||
nsIURI* aSheetURI,
|
||||
nsIURI* aBaseURI,
|
||||
nsIPrincipal* aSheetPrincipal,
|
||||
uint32_t aLineNumber)
|
||||
{
|
||||
DropSheet();
|
||||
|
||||
RefPtr<ThreadSafeURIHolder> base = new ThreadSafeURIHolder(aBaseURI);
|
||||
RefPtr<ThreadSafeURIHolder> referrer = new ThreadSafeURIHolder(aSheetURI);
|
||||
RefPtr<ThreadSafePrincipalHolder> principal =
|
||||
new ThreadSafePrincipalHolder(aSheetPrincipal);
|
||||
|
||||
nsCString baseString;
|
||||
nsresult rv = aBaseURI->GetSpec(baseString);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
NS_ConvertUTF16toUTF8 input(aInput);
|
||||
mSheet = Servo_StyleSheet_FromUTF8Bytes(&input, mParsingMode, &baseString,
|
||||
base, referrer, principal).Consume();
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
ServoStyleSheet::LoadFailed()
|
||||
{
|
||||
mSheet = Servo_StyleSheet_Empty(mParsingMode).Consume();
|
||||
}
|
||||
|
||||
void
|
||||
ServoStyleSheet::DropSheet()
|
||||
{
|
||||
mSheet = nullptr;
|
||||
}
|
||||
|
||||
size_t
|
||||
ServoStyleSheet::SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const
|
||||
{
|
||||
MOZ_CRASH("stylo: not implemented");
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
void
|
||||
ServoStyleSheet::List(FILE* aOut, int32_t aIndex) const
|
||||
{
|
||||
MOZ_CRASH("stylo: not implemented");
|
||||
}
|
||||
#endif
|
||||
|
||||
nsMediaList*
|
||||
ServoStyleSheet::Media()
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
nsIDOMCSSRule*
|
||||
ServoStyleSheet::GetDOMOwnerRule() const
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
CSSRuleList*
|
||||
ServoStyleSheet::GetCssRulesInternal(ErrorResult& aRv)
|
||||
{
|
||||
aRv.Throw(NS_ERROR_NOT_IMPLEMENTED);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
uint32_t
|
||||
ServoStyleSheet::InsertRuleInternal(const nsAString& aRule,
|
||||
uint32_t aIndex, ErrorResult& aRv)
|
||||
{
|
||||
aRv.Throw(NS_ERROR_NOT_IMPLEMENTED);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
ServoStyleSheet::DeleteRuleInternal(uint32_t aIndex, ErrorResult& aRv)
|
||||
{
|
||||
aRv.Throw(NS_ERROR_NOT_IMPLEMENTED);
|
||||
}
|
||||
|
||||
} // namespace mozilla
|
||||
90
layout/style/ServoStyleSheet.h
Normal file
90
layout/style/ServoStyleSheet.h
Normal file
|
|
@ -0,0 +1,90 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* 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_ServoStyleSheet_h
|
||||
#define mozilla_ServoStyleSheet_h
|
||||
|
||||
#include "mozilla/dom/SRIMetadata.h"
|
||||
#include "mozilla/RefPtr.h"
|
||||
#include "mozilla/ServoBindingTypes.h"
|
||||
#include "mozilla/StyleSheet.h"
|
||||
#include "mozilla/StyleSheetInfo.h"
|
||||
#include "nsStringFwd.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
/**
|
||||
* CSS style sheet object that is a wrapper for a Servo Stylesheet.
|
||||
*/
|
||||
class ServoStyleSheet : public StyleSheet
|
||||
{
|
||||
public:
|
||||
ServoStyleSheet(css::SheetParsingMode aParsingMode,
|
||||
CORSMode aCORSMode,
|
||||
net::ReferrerPolicy aReferrerPolicy,
|
||||
const dom::SRIMetadata& aIntegrity);
|
||||
|
||||
bool HasRules() const;
|
||||
|
||||
void SetOwningDocument(nsIDocument* aDocument);
|
||||
|
||||
ServoStyleSheet* GetParentSheet() const;
|
||||
void AppendStyleSheet(ServoStyleSheet* aSheet);
|
||||
|
||||
MOZ_MUST_USE nsresult ParseSheet(const nsAString& aInput,
|
||||
nsIURI* aSheetURI,
|
||||
nsIURI* aBaseURI,
|
||||
nsIPrincipal* aSheetPrincipal,
|
||||
uint32_t aLineNumber);
|
||||
|
||||
/**
|
||||
* Called instead of ParseSheet to initialize the Servo stylesheet object
|
||||
* for a failed load. Either ParseSheet or LoadFailed must be called before
|
||||
* adding a ServoStyleSheet to a ServoStyleSet.
|
||||
*/
|
||||
void LoadFailed();
|
||||
|
||||
size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const;
|
||||
|
||||
#ifdef DEBUG
|
||||
void List(FILE* aOut = stdout, int32_t aIndex = 0) const;
|
||||
#endif
|
||||
|
||||
RawServoStyleSheet* RawSheet() const { return mSheet; }
|
||||
|
||||
// WebIDL StyleSheet API
|
||||
nsMediaList* Media() final;
|
||||
|
||||
// WebIDL CSSStyleSheet API
|
||||
// Can't be inline because we can't include ImportRule here. And can't be
|
||||
// called GetOwnerRule because that would be ambiguous with the ImportRule
|
||||
// version.
|
||||
nsIDOMCSSRule* GetDOMOwnerRule() const final;
|
||||
|
||||
void WillDirty() {}
|
||||
void DidDirty() {}
|
||||
|
||||
protected:
|
||||
virtual ~ServoStyleSheet();
|
||||
|
||||
// Internal methods which do not have security check and completeness check.
|
||||
dom::CSSRuleList* GetCssRulesInternal(ErrorResult& aRv);
|
||||
uint32_t InsertRuleInternal(const nsAString& aRule,
|
||||
uint32_t aIndex, ErrorResult& aRv);
|
||||
void DeleteRuleInternal(uint32_t aIndex, ErrorResult& aRv);
|
||||
|
||||
private:
|
||||
void DropSheet();
|
||||
|
||||
RefPtr<RawServoStyleSheet> mSheet;
|
||||
StyleSheetInfo mSheetInfo;
|
||||
|
||||
friend class StyleSheet;
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // mozilla_ServoStyleSheet_h
|
||||
40
layout/style/ServoTypes.h
Normal file
40
layout/style/ServoTypes.h
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* 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_ServoTypes_h
|
||||
#define mozilla_ServoTypes_h
|
||||
|
||||
/*
|
||||
* Type definitions used to interact with Servo. This gets included by nsINode,
|
||||
* so don't add significant include dependencies to this file.
|
||||
*/
|
||||
|
||||
struct ServoNodeData;
|
||||
namespace mozilla {
|
||||
|
||||
/*
|
||||
* Replaced types. These get mapped to associated Servo types in bindgen.
|
||||
*/
|
||||
|
||||
template<typename T>
|
||||
struct ServoUnsafeCell {
|
||||
T value;
|
||||
|
||||
// Ensure that primitive types (i.e. pointers) get zero-initialized.
|
||||
ServoUnsafeCell() : value() {};
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct ServoCell {
|
||||
ServoUnsafeCell<T> value;
|
||||
T Get() const { return value.value; }
|
||||
void Set(T arg) { value.value = arg; }
|
||||
ServoCell() : value() {};
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // mozilla_ServoTypes_h
|
||||
82
layout/style/ServoUtils.h
Normal file
82
layout/style/ServoUtils.h
Normal file
|
|
@ -0,0 +1,82 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* 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/. */
|
||||
|
||||
/* some utilities for stylo */
|
||||
|
||||
#ifndef mozilla_ServoUtils_h
|
||||
#define mozilla_ServoUtils_h
|
||||
|
||||
#include "mozilla/TypeTraits.h"
|
||||
|
||||
#ifdef MOZ_STYLO
|
||||
# define MOZ_DECL_STYLO_CHECK_METHODS \
|
||||
bool IsGecko() const { return !IsServo(); } \
|
||||
bool IsServo() const { return mType == StyleBackendType::Servo; }
|
||||
#else
|
||||
# define MOZ_DECL_STYLO_CHECK_METHODS \
|
||||
bool IsGecko() const { return true; } \
|
||||
bool IsServo() const { return false; }
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Macro used in a base class of |geckotype_| and |servotype_|.
|
||||
* The class should define |StyleBackendType mType;| itself.
|
||||
*/
|
||||
#define MOZ_DECL_STYLO_METHODS(geckotype_, servotype_) \
|
||||
MOZ_DECL_STYLO_CHECK_METHODS \
|
||||
inline geckotype_* AsGecko(); \
|
||||
inline servotype_* AsServo(); \
|
||||
inline const geckotype_* AsGecko() const; \
|
||||
inline const servotype_* AsServo() const;
|
||||
|
||||
/**
|
||||
* Macro used in inline header of class |type_| with its Gecko and Servo
|
||||
* subclasses named |geckotype_| and |servotype_| correspondingly for
|
||||
* implementing the inline methods defined by MOZ_DECL_STYLO_METHODS.
|
||||
*/
|
||||
#define MOZ_DEFINE_STYLO_METHODS(type_, geckotype_, servotype_) \
|
||||
geckotype_* type_::AsGecko() { \
|
||||
MOZ_ASSERT(IsGecko()); \
|
||||
return static_cast<geckotype_*>(this); \
|
||||
} \
|
||||
servotype_* type_::AsServo() { \
|
||||
MOZ_ASSERT(IsServo()); \
|
||||
return static_cast<servotype_*>(this); \
|
||||
} \
|
||||
const geckotype_* type_::AsGecko() const { \
|
||||
MOZ_ASSERT(IsGecko()); \
|
||||
return static_cast<const geckotype_*>(this); \
|
||||
} \
|
||||
const servotype_* type_::AsServo() const { \
|
||||
MOZ_ASSERT(IsServo()); \
|
||||
return static_cast<const servotype_*>(this); \
|
||||
}
|
||||
|
||||
#define MOZ_STYLO_THIS_TYPE mozilla::RemovePointer<decltype(this)>::Type
|
||||
#define MOZ_STYLO_GECKO_TYPE mozilla::RemovePointer<decltype(AsGecko())>::Type
|
||||
#define MOZ_STYLO_SERVO_TYPE mozilla::RemovePointer<decltype(AsServo())>::Type
|
||||
|
||||
/**
|
||||
* Macro used to forward a method call to the concrete method defined by
|
||||
* the Servo or Gecko implementation. The class of the method using it
|
||||
* should use MOZ_DECL_STYLO_METHODS to define basic stylo methods.
|
||||
*/
|
||||
#define MOZ_STYLO_FORWARD_CONCRETE(method_, geckoargs_, servoargs_) \
|
||||
static_assert(!mozilla::IsSame<decltype(&MOZ_STYLO_THIS_TYPE::method_), \
|
||||
decltype(&MOZ_STYLO_GECKO_TYPE::method_)> \
|
||||
::value, "Gecko subclass should define its own " #method_); \
|
||||
static_assert(!mozilla::IsSame<decltype(&MOZ_STYLO_THIS_TYPE::method_), \
|
||||
decltype(&MOZ_STYLO_SERVO_TYPE::method_)> \
|
||||
::value, "Servo subclass should define its own " #method_); \
|
||||
if (IsServo()) { \
|
||||
return AsServo()->method_ servoargs_; \
|
||||
} \
|
||||
return AsGecko()->method_ geckoargs_;
|
||||
|
||||
#define MOZ_STYLO_FORWARD(method_, args_) \
|
||||
MOZ_STYLO_FORWARD_CONCRETE(method_, args_, args_)
|
||||
|
||||
#endif // mozilla_ServoUtils_h
|
||||
43
layout/style/SheetParsingMode.h
Normal file
43
layout/style/SheetParsingMode.h
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* 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_css_SheetParsingMode_h
|
||||
#define mozilla_css_SheetParsingMode_h
|
||||
|
||||
namespace mozilla {
|
||||
namespace css {
|
||||
|
||||
/**
|
||||
* Enum defining the mode in which a sheet is to be parsed. This is
|
||||
* usually, but not always, the same as the cascade level at which the
|
||||
* sheet will apply (see nsStyleSet.h). Most of the Loader APIs only
|
||||
* support loading of author sheets.
|
||||
*
|
||||
* Author sheets are the normal case: styles embedded in or linked
|
||||
* from HTML pages. They are also the most restricted.
|
||||
*
|
||||
* User sheets can do anything author sheets can do, and also get
|
||||
* access to a few CSS extensions that are not yet suitable for
|
||||
* exposure on the public Web, but are very useful for expressing
|
||||
* user style overrides, such as @-moz-document rules.
|
||||
*
|
||||
* Agent sheets have access to all author- and user-sheet features
|
||||
* plus more extensions that are necessary for internal use but,
|
||||
* again, not yet suitable for exposure on the public Web. Some of
|
||||
* these are outright unsafe to expose; in particular, incorrect
|
||||
* styling of anonymous box pseudo-elements can violate layout
|
||||
* invariants.
|
||||
*/
|
||||
enum SheetParsingMode {
|
||||
eAuthorSheetFeatures = 0,
|
||||
eUserSheetFeatures,
|
||||
eAgentSheetFeatures
|
||||
};
|
||||
|
||||
} // namespace css
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // mozilla_css_SheetParsingMode_h
|
||||
38
layout/style/SheetType.h
Normal file
38
layout/style/SheetType.h
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
/* -*- Mode: C++; 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/. */
|
||||
|
||||
/* enum to represent a level in the cascade */
|
||||
|
||||
#ifndef mozilla_SheetType_h
|
||||
#define mozilla_SheetType_h
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
// The "origins" of the CSS cascade, from lowest precedence to
|
||||
// highest (for non-!important rules).
|
||||
//
|
||||
// Be sure to update NS_RULE_NODE_LEVEL_MASK when changing the number
|
||||
// of sheet types; static assertions enforce this.
|
||||
enum class SheetType : uint8_t {
|
||||
Agent, // CSS
|
||||
User, // CSS
|
||||
PresHint,
|
||||
SVGAttrAnimation,
|
||||
Doc, // CSS
|
||||
ScopedDoc,
|
||||
StyleAttr,
|
||||
Override, // CSS
|
||||
Animation,
|
||||
Transition,
|
||||
|
||||
Count,
|
||||
Unknown = 0xff
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // mozilla_SheetType_h
|
||||
4990
layout/style/StyleAnimationValue.cpp
Normal file
4990
layout/style/StyleAnimationValue.cpp
Normal file
File diff suppressed because it is too large
Load diff
602
layout/style/StyleAnimationValue.h
Normal file
602
layout/style/StyleAnimationValue.h
Normal file
|
|
@ -0,0 +1,602 @@
|
|||
/* -*- Mode: C++; 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/. */
|
||||
|
||||
/* Utilities for animation of computed style values */
|
||||
|
||||
#ifndef mozilla_StyleAnimationValue_h_
|
||||
#define mozilla_StyleAnimationValue_h_
|
||||
|
||||
#include "mozilla/gfx/MatrixFwd.h"
|
||||
#include "mozilla/UniquePtr.h"
|
||||
#include "nsStringFwd.h"
|
||||
#include "nsStringBuffer.h"
|
||||
#include "nsCoord.h"
|
||||
#include "nsColor.h"
|
||||
#include "nsCSSProps.h"
|
||||
#include "nsCSSValue.h"
|
||||
#include "nsStyleCoord.h"
|
||||
|
||||
class nsIFrame;
|
||||
class nsStyleContext;
|
||||
class gfx3DMatrix;
|
||||
struct RawServoDeclarationBlock;
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
namespace css {
|
||||
class StyleRule;
|
||||
} // namespace css
|
||||
|
||||
namespace dom {
|
||||
class Element;
|
||||
} // namespace dom
|
||||
|
||||
enum class CSSPseudoElementType : uint8_t;
|
||||
struct PropertyStyleAnimationValuePair;
|
||||
|
||||
/**
|
||||
* Utility class to handle animated style values
|
||||
*/
|
||||
class StyleAnimationValue {
|
||||
public:
|
||||
// Mathematical methods
|
||||
// --------------------
|
||||
/**
|
||||
* Adds |aCount| copies of |aValueToAdd| to |aDest|. The result of this
|
||||
* addition is stored in aDest.
|
||||
*
|
||||
* Note that if |aCount| is 0, then |aDest| will be unchanged. Also, if
|
||||
* this method fails, then |aDest| will be unchanged.
|
||||
*
|
||||
* @param aDest The value to add to.
|
||||
* @param aValueToAdd The value to add.
|
||||
* @param aCount The number of times to add aValueToAdd.
|
||||
* @return true on success, false on failure.
|
||||
*/
|
||||
static MOZ_MUST_USE bool
|
||||
Add(nsCSSPropertyID aProperty, StyleAnimationValue& aDest,
|
||||
const StyleAnimationValue& aValueToAdd, uint32_t aCount) {
|
||||
return AddWeighted(aProperty, 1.0, aDest, aCount, aValueToAdd, aDest);
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates a measure of 'distance' between two colors.
|
||||
*
|
||||
* @param aStartColor The start of the interval for which the distance
|
||||
* should be calculated.
|
||||
* @param aEndColor The end of the interval for which the distance
|
||||
* should be calculated.
|
||||
* @return the result of the calculation.
|
||||
*/
|
||||
static double ComputeColorDistance(const css::RGBAColorData& aStartColor,
|
||||
const css::RGBAColorData& aEndColor);
|
||||
|
||||
/**
|
||||
* Calculates a measure of 'distance' between two values.
|
||||
*
|
||||
* This measure of Distance is guaranteed to be proportional to
|
||||
* portions passed to Interpolate, Add, or AddWeighted. However, for
|
||||
* some types of StyleAnimationValue it may not produce sensible results
|
||||
* for paced animation.
|
||||
*
|
||||
* If this method succeeds, the returned distance value is guaranteed to be
|
||||
* non-negative.
|
||||
*
|
||||
* @param aStartValue The start of the interval for which the distance
|
||||
* should be calculated.
|
||||
* @param aEndValue The end of the interval for which the distance
|
||||
* should be calculated.
|
||||
* @param aStyleContext The style context to use for processing the
|
||||
* translate part of transforms.
|
||||
* @param aDistance The result of the calculation.
|
||||
* @return true on success, false on failure.
|
||||
*/
|
||||
static MOZ_MUST_USE bool
|
||||
ComputeDistance(nsCSSPropertyID aProperty,
|
||||
const StyleAnimationValue& aStartValue,
|
||||
const StyleAnimationValue& aEndValue,
|
||||
nsStyleContext* aStyleContext,
|
||||
double& aDistance);
|
||||
|
||||
/**
|
||||
* Calculates an interpolated value that is the specified |aPortion| between
|
||||
* the two given values.
|
||||
*
|
||||
* This really just does the following calculation:
|
||||
* aResultValue = (1.0 - aPortion) * aStartValue + aPortion * aEndValue
|
||||
*
|
||||
* @param aStartValue The value defining the start of the interval of
|
||||
* interpolation.
|
||||
* @param aEndValue The value defining the end of the interval of
|
||||
* interpolation.
|
||||
* @param aPortion A number in the range [0.0, 1.0] defining the
|
||||
* distance of the interpolated value in the interval.
|
||||
* @param [out] aResultValue The resulting interpolated value.
|
||||
* @return true on success, false on failure.
|
||||
*/
|
||||
static MOZ_MUST_USE bool
|
||||
Interpolate(nsCSSPropertyID aProperty,
|
||||
const StyleAnimationValue& aStartValue,
|
||||
const StyleAnimationValue& aEndValue,
|
||||
double aPortion,
|
||||
StyleAnimationValue& aResultValue) {
|
||||
return AddWeighted(aProperty, 1.0 - aPortion, aStartValue,
|
||||
aPortion, aEndValue, aResultValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* Does the calculation:
|
||||
* aResultValue = aCoeff1 * aValue1 + aCoeff2 * aValue2
|
||||
*
|
||||
* @param [out] aResultValue The resulting interpolated value. May be
|
||||
* the same as aValue1 or aValue2.
|
||||
* @return true on success, false on failure.
|
||||
*
|
||||
* NOTE: Current callers always pass aCoeff1 and aCoeff2 >= 0. They
|
||||
* are currently permitted to be negative; however, if, as we add
|
||||
* support more value types types, we find that this causes
|
||||
* difficulty, we might change this to restrict them to being
|
||||
* positive.
|
||||
*/
|
||||
static MOZ_MUST_USE bool
|
||||
AddWeighted(nsCSSPropertyID aProperty,
|
||||
double aCoeff1, const StyleAnimationValue& aValue1,
|
||||
double aCoeff2, const StyleAnimationValue& aValue2,
|
||||
StyleAnimationValue& aResultValue);
|
||||
|
||||
/**
|
||||
* Accumulates |aValueToAccumulate| onto |aDest| |aCount| times.
|
||||
* The result is stored in |aDest| on success.
|
||||
*
|
||||
* @param aDest The base value to be accumulated.
|
||||
* @param aValueToAccumulate The value to accumulate.
|
||||
* @param aCount The number of times to accumulate
|
||||
* aValueToAccumulate.
|
||||
* @return true on success, false on failure.
|
||||
*
|
||||
* NOTE: This function will work as a wrapper of StyleAnimationValue::Add()
|
||||
* if |aProperty| isn't color or shadow or filter. For these properties,
|
||||
* this function may return a color value that at least one of its components
|
||||
* has a value which is outside the range [0, 1] so that we can calculate
|
||||
* plausible values as interpolation with the return value.
|
||||
*/
|
||||
static MOZ_MUST_USE bool
|
||||
Accumulate(nsCSSPropertyID aProperty, StyleAnimationValue& aDest,
|
||||
const StyleAnimationValue& aValueToAccumulate,
|
||||
uint64_t aCount);
|
||||
|
||||
// Type-conversion methods
|
||||
// -----------------------
|
||||
/**
|
||||
* Creates a computed value for the given specified value
|
||||
* (property ID + string). A style context is needed in case the
|
||||
* specified value depends on inherited style or on the values of other
|
||||
* properties.
|
||||
*
|
||||
* @param aProperty The property whose value we're computing.
|
||||
* @param aTargetElement The content node to which our computed value is
|
||||
* applicable. For pseudo-elements, this is the parent
|
||||
* element to which the pseudo is attached, not the
|
||||
* generated content node.
|
||||
* @param aStyleContext The style context used to compute values from the
|
||||
* specified value. For pseudo-elements, this should
|
||||
* be the style context corresponding to the pseudo
|
||||
* element.
|
||||
* @param aSpecifiedValue The specified value, from which we'll build our
|
||||
* computed value.
|
||||
* @param aUseSVGMode A flag to indicate whether we should parse
|
||||
* |aSpecifiedValue| in SVG mode.
|
||||
* @param [out] aComputedValue The resulting computed value.
|
||||
* @param [out] aIsContextSensitive
|
||||
* Set to true if |aSpecifiedValue| may produce
|
||||
* a different |aComputedValue| depending on other CSS
|
||||
* properties on |aTargetElement| or its ancestors.
|
||||
* false otherwise.
|
||||
* Note that the operation of this method is
|
||||
* significantly faster when |aIsContextSensitive| is
|
||||
* nullptr.
|
||||
* @return true on success, false on failure.
|
||||
*/
|
||||
static MOZ_MUST_USE bool
|
||||
ComputeValue(nsCSSPropertyID aProperty,
|
||||
mozilla::dom::Element* aTargetElement,
|
||||
nsStyleContext* aStyleContext,
|
||||
const nsAString& aSpecifiedValue,
|
||||
bool aUseSVGMode,
|
||||
StyleAnimationValue& aComputedValue,
|
||||
bool* aIsContextSensitive = nullptr);
|
||||
|
||||
/**
|
||||
* Like ComputeValue, but returns an array of StyleAnimationValues.
|
||||
*
|
||||
* On success, when aProperty is a longhand, aResult will have a single
|
||||
* value in it. When aProperty is a shorthand, aResult will be filled with
|
||||
* values for all of aProperty's longhand components. aEnabledState
|
||||
* is used to filter the longhand components that will be appended
|
||||
* to aResult. On failure, aResult might still have partial results
|
||||
* in it.
|
||||
*/
|
||||
static MOZ_MUST_USE bool
|
||||
ComputeValues(nsCSSPropertyID aProperty,
|
||||
mozilla::CSSEnabledState aEnabledState,
|
||||
mozilla::dom::Element* aTargetElement,
|
||||
nsStyleContext* aStyleContext,
|
||||
const nsAString& aSpecifiedValue,
|
||||
bool aUseSVGMode,
|
||||
nsTArray<PropertyStyleAnimationValuePair>& aResult);
|
||||
|
||||
/**
|
||||
* A variant on ComputeValues that takes an nsCSSValue as the specified
|
||||
* value. Only longhand properties are supported.
|
||||
*/
|
||||
static MOZ_MUST_USE bool
|
||||
ComputeValues(nsCSSPropertyID aProperty,
|
||||
mozilla::CSSEnabledState aEnabledState,
|
||||
mozilla::dom::Element* aTargetElement,
|
||||
nsStyleContext* aStyleContext,
|
||||
const nsCSSValue& aSpecifiedValue,
|
||||
bool aUseSVGMode,
|
||||
nsTArray<PropertyStyleAnimationValuePair>& aResult);
|
||||
|
||||
/**
|
||||
* A variant of ComputeValues that takes a RawServoDeclarationBlock
|
||||
* as the specified value.
|
||||
*/
|
||||
static MOZ_MUST_USE bool
|
||||
ComputeValues(nsCSSPropertyID aProperty,
|
||||
mozilla::CSSEnabledState aEnabledState,
|
||||
nsStyleContext* aStyleContext,
|
||||
const RawServoDeclarationBlock& aDeclarations,
|
||||
nsTArray<PropertyStyleAnimationValuePair>& aValues);
|
||||
|
||||
/**
|
||||
* Creates a specified value for the given computed value.
|
||||
*
|
||||
* The first two overloads fill in an nsCSSValue object; the third
|
||||
* produces a string. For the overload that takes a const
|
||||
* StyleAnimationValue& reference, the nsCSSValue result may depend on
|
||||
* objects owned by the |aComputedValue| object, so users of that variant
|
||||
* must keep |aComputedValue| alive longer than |aSpecifiedValue|.
|
||||
* The overload that takes an rvalue StyleAnimationValue reference
|
||||
* transfers ownership for some resources such that the |aComputedValue|
|
||||
* does not depend on the lifetime of |aSpecifiedValue|.
|
||||
*
|
||||
* @param aProperty The property whose value we're uncomputing.
|
||||
* @param aComputedValue The computed value to be converted.
|
||||
* @param [out] aSpecifiedValue The resulting specified value.
|
||||
* @return true on success, false on failure.
|
||||
*
|
||||
* These functions are not MOZ_MUST_USE because failing to check the return
|
||||
* value is common and reasonable.
|
||||
*/
|
||||
static MOZ_MUST_USE bool
|
||||
UncomputeValue(nsCSSPropertyID aProperty,
|
||||
const StyleAnimationValue& aComputedValue,
|
||||
nsCSSValue& aSpecifiedValue);
|
||||
static MOZ_MUST_USE bool
|
||||
UncomputeValue(nsCSSPropertyID aProperty,
|
||||
StyleAnimationValue&& aComputedValue,
|
||||
nsCSSValue& aSpecifiedValue);
|
||||
static MOZ_MUST_USE bool
|
||||
UncomputeValue(nsCSSPropertyID aProperty,
|
||||
const StyleAnimationValue& aComputedValue,
|
||||
nsAString& aSpecifiedValue);
|
||||
|
||||
/**
|
||||
* Gets the computed value for the given property from the given style
|
||||
* context.
|
||||
*
|
||||
* Obtaining the computed value allows us to animate properties when the
|
||||
* content author has specified a value like "inherit" or "initial" or some
|
||||
* other keyword that isn't directly interpolatable, but which *computes* to
|
||||
* something interpolatable.
|
||||
*
|
||||
* @param aProperty The property whose value we're looking up.
|
||||
* @param aStyleContext The style context to check for the computed value.
|
||||
* @param [out] aComputedValue The resulting computed value.
|
||||
* @return true on success, false on failure.
|
||||
*/
|
||||
static MOZ_MUST_USE bool ExtractComputedValue(
|
||||
nsCSSPropertyID aProperty,
|
||||
nsStyleContext* aStyleContext,
|
||||
StyleAnimationValue& aComputedValue);
|
||||
|
||||
/**
|
||||
* Interpolates between 2 matrices by decomposing them.
|
||||
*
|
||||
* @param aMatrix1 First matrix, using CSS pixel units.
|
||||
* @param aMatrix2 Second matrix, using CSS pixel units.
|
||||
* @param aProgress Interpolation value in the range [0.0, 1.0]
|
||||
*/
|
||||
static gfx::Matrix4x4 InterpolateTransformMatrix(const gfx::Matrix4x4 &aMatrix1,
|
||||
const gfx::Matrix4x4 &aMatrix2,
|
||||
double aProgress);
|
||||
|
||||
static already_AddRefed<nsCSSValue::Array>
|
||||
AppendTransformFunction(nsCSSKeyword aTransformFunction,
|
||||
nsCSSValueList**& aListTail);
|
||||
|
||||
/**
|
||||
* The types and values for the values that we extract and animate.
|
||||
*/
|
||||
enum Unit {
|
||||
eUnit_Null, // not initialized
|
||||
eUnit_Normal,
|
||||
eUnit_Auto,
|
||||
eUnit_None,
|
||||
eUnit_Enumerated,
|
||||
eUnit_Visibility, // special case for transitions (which converts
|
||||
// Enumerated to Visibility as needed)
|
||||
eUnit_Integer,
|
||||
eUnit_Coord,
|
||||
eUnit_Percent,
|
||||
eUnit_Float,
|
||||
eUnit_Color, // nsCSSValue* (never null), always with an nscolor or
|
||||
// an nsCSSValueFloatColor
|
||||
eUnit_CurrentColor,
|
||||
eUnit_ComplexColor, // ComplexColorValue* (never null)
|
||||
eUnit_Calc, // nsCSSValue* (never null), always with a single
|
||||
// calc() expression that's either length or length+percent
|
||||
eUnit_ObjectPosition, // nsCSSValue* (never null), always with a
|
||||
// 4-entry nsCSSValue::Array
|
||||
eUnit_URL, // nsCSSValue* (never null), always with a css::URLValue
|
||||
eUnit_DiscreteCSSValue, // nsCSSValue* (never null)
|
||||
eUnit_CSSValuePair, // nsCSSValuePair* (never null)
|
||||
eUnit_CSSValueTriplet, // nsCSSValueTriplet* (never null)
|
||||
eUnit_CSSRect, // nsCSSRect* (never null)
|
||||
eUnit_Dasharray, // nsCSSValueList* (never null)
|
||||
eUnit_Shadow, // nsCSSValueList* (may be null)
|
||||
eUnit_Shape, // nsCSSValue::Array* (never null)
|
||||
eUnit_Filter, // nsCSSValueList* (may be null)
|
||||
eUnit_Transform, // nsCSSValueList* (never null)
|
||||
eUnit_BackgroundPositionCoord, // nsCSSValueList* (never null)
|
||||
eUnit_CSSValuePairList, // nsCSSValuePairList* (never null)
|
||||
eUnit_UnparsedString // nsStringBuffer* (never null)
|
||||
};
|
||||
|
||||
private:
|
||||
Unit mUnit;
|
||||
union {
|
||||
int32_t mInt;
|
||||
nscoord mCoord;
|
||||
float mFloat;
|
||||
nsCSSValue* mCSSValue;
|
||||
nsCSSValuePair* mCSSValuePair;
|
||||
nsCSSValueTriplet* mCSSValueTriplet;
|
||||
nsCSSRect* mCSSRect;
|
||||
nsCSSValue::Array* mCSSValueArray;
|
||||
nsCSSValueList* mCSSValueList;
|
||||
nsCSSValueSharedList* mCSSValueSharedList;
|
||||
nsCSSValuePairList* mCSSValuePairList;
|
||||
nsStringBuffer* mString;
|
||||
css::ComplexColorValue* mComplexColor;
|
||||
} mValue;
|
||||
|
||||
public:
|
||||
Unit GetUnit() const {
|
||||
NS_ASSERTION(mUnit != eUnit_Null, "uninitialized");
|
||||
return mUnit;
|
||||
}
|
||||
|
||||
// Accessor to let us verify assumptions about presence of null unit,
|
||||
// without tripping the assertion in GetUnit().
|
||||
bool IsNull() const {
|
||||
return mUnit == eUnit_Null;
|
||||
}
|
||||
|
||||
int32_t GetIntValue() const {
|
||||
NS_ASSERTION(IsIntUnit(mUnit), "unit mismatch");
|
||||
return mValue.mInt;
|
||||
}
|
||||
nscoord GetCoordValue() const {
|
||||
NS_ASSERTION(mUnit == eUnit_Coord, "unit mismatch");
|
||||
return mValue.mCoord;
|
||||
}
|
||||
float GetPercentValue() const {
|
||||
NS_ASSERTION(mUnit == eUnit_Percent, "unit mismatch");
|
||||
return mValue.mFloat;
|
||||
}
|
||||
float GetFloatValue() const {
|
||||
NS_ASSERTION(mUnit == eUnit_Float, "unit mismatch");
|
||||
return mValue.mFloat;
|
||||
}
|
||||
nsCSSValue* GetCSSValueValue() const {
|
||||
NS_ASSERTION(IsCSSValueUnit(mUnit), "unit mismatch");
|
||||
return mValue.mCSSValue;
|
||||
}
|
||||
nsCSSValuePair* GetCSSValuePairValue() const {
|
||||
NS_ASSERTION(IsCSSValuePairUnit(mUnit), "unit mismatch");
|
||||
return mValue.mCSSValuePair;
|
||||
}
|
||||
nsCSSValueTriplet* GetCSSValueTripletValue() const {
|
||||
NS_ASSERTION(IsCSSValueTripletUnit(mUnit), "unit mismatch");
|
||||
return mValue.mCSSValueTriplet;
|
||||
}
|
||||
nsCSSRect* GetCSSRectValue() const {
|
||||
NS_ASSERTION(IsCSSRectUnit(mUnit), "unit mismatch");
|
||||
return mValue.mCSSRect;
|
||||
}
|
||||
nsCSSValue::Array* GetCSSValueArrayValue() const {
|
||||
NS_ASSERTION(IsCSSValueArrayUnit(mUnit), "unit mismatch");
|
||||
return mValue.mCSSValueArray;
|
||||
}
|
||||
nsCSSValueList* GetCSSValueListValue() const {
|
||||
NS_ASSERTION(IsCSSValueListUnit(mUnit), "unit mismatch");
|
||||
return mValue.mCSSValueList;
|
||||
}
|
||||
nsCSSValueSharedList* GetCSSValueSharedListValue() const {
|
||||
NS_ASSERTION(IsCSSValueSharedListValue(mUnit), "unit mismatch");
|
||||
return mValue.mCSSValueSharedList;
|
||||
}
|
||||
nsCSSValuePairList* GetCSSValuePairListValue() const {
|
||||
NS_ASSERTION(IsCSSValuePairListUnit(mUnit), "unit mismatch");
|
||||
return mValue.mCSSValuePairList;
|
||||
}
|
||||
const char16_t* GetStringBufferValue() const {
|
||||
NS_ASSERTION(IsStringUnit(mUnit), "unit mismatch");
|
||||
return GetBufferValue(mValue.mString);
|
||||
}
|
||||
|
||||
void GetStringValue(nsAString& aBuffer) const {
|
||||
NS_ASSERTION(IsStringUnit(mUnit), "unit mismatch");
|
||||
aBuffer.Truncate();
|
||||
uint32_t len = NS_strlen(GetBufferValue(mValue.mString));
|
||||
mValue.mString->ToString(len, aBuffer);
|
||||
}
|
||||
|
||||
/// @return the scale for this value, calculated with reference to @aForFrame.
|
||||
gfxSize GetScaleValue(const nsIFrame* aForFrame) const;
|
||||
|
||||
const css::ComplexColorData& GetComplexColorData() const {
|
||||
MOZ_ASSERT(mUnit == eUnit_ComplexColor, "unit mismatch");
|
||||
return *mValue.mComplexColor;
|
||||
}
|
||||
StyleComplexColor GetStyleComplexColorValue() const {
|
||||
return GetComplexColorData().ToComplexColor();
|
||||
}
|
||||
|
||||
UniquePtr<nsCSSValueList> TakeCSSValueListValue() {
|
||||
nsCSSValueList* list = GetCSSValueListValue();
|
||||
mValue.mCSSValueList = nullptr;
|
||||
mUnit = eUnit_Null;
|
||||
return UniquePtr<nsCSSValueList>(list);
|
||||
}
|
||||
UniquePtr<nsCSSValuePairList> TakeCSSValuePairListValue() {
|
||||
nsCSSValuePairList* list = GetCSSValuePairListValue();
|
||||
mValue.mCSSValuePairList = nullptr;
|
||||
mUnit = eUnit_Null;
|
||||
return UniquePtr<nsCSSValuePairList>(list);
|
||||
}
|
||||
|
||||
explicit StyleAnimationValue(Unit aUnit = eUnit_Null) : mUnit(aUnit) {
|
||||
NS_ASSERTION(aUnit == eUnit_Null || aUnit == eUnit_Normal ||
|
||||
aUnit == eUnit_Auto || aUnit == eUnit_None,
|
||||
"must be valueless unit");
|
||||
}
|
||||
StyleAnimationValue(const StyleAnimationValue& aOther)
|
||||
: mUnit(eUnit_Null) { *this = aOther; }
|
||||
StyleAnimationValue(StyleAnimationValue&& aOther)
|
||||
: mUnit(aOther.mUnit)
|
||||
, mValue(aOther.mValue)
|
||||
{
|
||||
aOther.mUnit = eUnit_Null;
|
||||
}
|
||||
enum IntegerConstructorType { IntegerConstructor };
|
||||
StyleAnimationValue(int32_t aInt, Unit aUnit, IntegerConstructorType);
|
||||
enum CoordConstructorType { CoordConstructor };
|
||||
StyleAnimationValue(nscoord aLength, CoordConstructorType);
|
||||
enum PercentConstructorType { PercentConstructor };
|
||||
StyleAnimationValue(float aPercent, PercentConstructorType);
|
||||
enum FloatConstructorType { FloatConstructor };
|
||||
StyleAnimationValue(float aFloat, FloatConstructorType);
|
||||
enum ColorConstructorType { ColorConstructor };
|
||||
StyleAnimationValue(nscolor aColor, ColorConstructorType);
|
||||
|
||||
~StyleAnimationValue() { FreeValue(); }
|
||||
|
||||
void SetNormalValue();
|
||||
void SetAutoValue();
|
||||
void SetNoneValue();
|
||||
void SetIntValue(int32_t aInt, Unit aUnit);
|
||||
template<typename T,
|
||||
typename = typename std::enable_if<std::is_enum<T>::value>::type>
|
||||
void SetIntValue(T aInt, Unit aUnit)
|
||||
{
|
||||
static_assert(mozilla::EnumTypeFitsWithin<T, int32_t>::value,
|
||||
"aValue must be an enum that fits within mValue.mInt");
|
||||
SetIntValue(static_cast<int32_t>(aInt), aUnit);
|
||||
}
|
||||
void SetCoordValue(nscoord aCoord);
|
||||
void SetPercentValue(float aPercent);
|
||||
void SetFloatValue(float aFloat);
|
||||
void SetColorValue(nscolor aColor);
|
||||
void SetCurrentColorValue();
|
||||
void SetComplexColorValue(const StyleComplexColor& aColor);
|
||||
void SetComplexColorValue(already_AddRefed<css::ComplexColorValue> aValue);
|
||||
void SetUnparsedStringValue(const nsString& aString);
|
||||
void SetCSSValueArrayValue(nsCSSValue::Array* aValue, Unit aUnit);
|
||||
|
||||
// These setters take ownership of |aValue|, and are therefore named
|
||||
// "SetAndAdopt*".
|
||||
void SetAndAdoptCSSValueValue(nsCSSValue *aValue, Unit aUnit);
|
||||
void SetAndAdoptCSSValuePairValue(nsCSSValuePair *aValue, Unit aUnit);
|
||||
void SetAndAdoptCSSValueTripletValue(nsCSSValueTriplet *aValue, Unit aUnit);
|
||||
void SetAndAdoptCSSRectValue(nsCSSRect *aValue, Unit aUnit);
|
||||
void SetAndAdoptCSSValueListValue(nsCSSValueList *aValue, Unit aUnit);
|
||||
void SetAndAdoptCSSValuePairListValue(nsCSSValuePairList *aValue);
|
||||
|
||||
void SetTransformValue(nsCSSValueSharedList* aList);
|
||||
|
||||
StyleAnimationValue& operator=(const StyleAnimationValue& aOther);
|
||||
StyleAnimationValue& operator=(StyleAnimationValue&& aOther)
|
||||
{
|
||||
MOZ_ASSERT(this != &aOther, "Do not move itself");
|
||||
if (this != &aOther) {
|
||||
FreeValue();
|
||||
mUnit = aOther.mUnit;
|
||||
mValue = aOther.mValue;
|
||||
aOther.mUnit = eUnit_Null;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool operator==(const StyleAnimationValue& aOther) const;
|
||||
bool operator!=(const StyleAnimationValue& aOther) const
|
||||
{ return !(*this == aOther); }
|
||||
|
||||
private:
|
||||
void FreeValue();
|
||||
|
||||
static const char16_t* GetBufferValue(nsStringBuffer* aBuffer) {
|
||||
return static_cast<char16_t*>(aBuffer->Data());
|
||||
}
|
||||
|
||||
static bool IsIntUnit(Unit aUnit) {
|
||||
return aUnit == eUnit_Enumerated || aUnit == eUnit_Visibility ||
|
||||
aUnit == eUnit_Integer;
|
||||
}
|
||||
static bool IsCSSValueUnit(Unit aUnit) {
|
||||
return aUnit == eUnit_Color ||
|
||||
aUnit == eUnit_Calc ||
|
||||
aUnit == eUnit_ObjectPosition ||
|
||||
aUnit == eUnit_URL ||
|
||||
aUnit == eUnit_DiscreteCSSValue;
|
||||
}
|
||||
static bool IsCSSValuePairUnit(Unit aUnit) {
|
||||
return aUnit == eUnit_CSSValuePair;
|
||||
}
|
||||
static bool IsCSSValueTripletUnit(Unit aUnit) {
|
||||
return aUnit == eUnit_CSSValueTriplet;
|
||||
}
|
||||
static bool IsCSSRectUnit(Unit aUnit) {
|
||||
return aUnit == eUnit_CSSRect;
|
||||
}
|
||||
static bool IsCSSValueArrayUnit(Unit aUnit) {
|
||||
return aUnit == eUnit_Shape;
|
||||
}
|
||||
static bool IsCSSValueListUnit(Unit aUnit) {
|
||||
return aUnit == eUnit_Dasharray || aUnit == eUnit_Filter ||
|
||||
aUnit == eUnit_Shadow ||
|
||||
aUnit == eUnit_BackgroundPositionCoord;
|
||||
}
|
||||
static bool IsCSSValueSharedListValue(Unit aUnit) {
|
||||
return aUnit == eUnit_Transform;
|
||||
}
|
||||
static bool IsCSSValuePairListUnit(Unit aUnit) {
|
||||
return aUnit == eUnit_CSSValuePairList;
|
||||
}
|
||||
static bool IsStringUnit(Unit aUnit) {
|
||||
return aUnit == eUnit_UnparsedString;
|
||||
}
|
||||
};
|
||||
|
||||
struct PropertyStyleAnimationValuePair
|
||||
{
|
||||
nsCSSPropertyID mProperty;
|
||||
StyleAnimationValue mValue;
|
||||
};
|
||||
} // namespace mozilla
|
||||
|
||||
#endif
|
||||
23
layout/style/StyleBackendType.h
Normal file
23
layout/style/StyleBackendType.h
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* 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_StyleBackendType_h
|
||||
#define mozilla_StyleBackendType_h
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
/**
|
||||
* Enumeration that represents one of the two supported style system backends.
|
||||
*/
|
||||
enum class StyleBackendType : uint8_t
|
||||
{
|
||||
Gecko = 1,
|
||||
Servo
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // mozilla_StyleBackendType_h
|
||||
45
layout/style/StyleComplexColor.h
Normal file
45
layout/style/StyleComplexColor.h
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* 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/. */
|
||||
|
||||
/* represent a color combines a numeric color and currentcolor */
|
||||
|
||||
#ifndef mozilla_StyleComplexColor_h_
|
||||
#define mozilla_StyleComplexColor_h_
|
||||
|
||||
#include "nsColor.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
/**
|
||||
* This struct represents a combined color from a numeric color and
|
||||
* the current foreground color (currentcolor keyword).
|
||||
* Conceptually, the formula is "color * (1 - p) + currentcolor * p"
|
||||
* where p is mForegroundRatio. See mozilla::LinearBlendColors for
|
||||
* the actual algorithm.
|
||||
*/
|
||||
struct StyleComplexColor
|
||||
{
|
||||
nscolor mColor;
|
||||
uint8_t mForegroundRatio;
|
||||
|
||||
static StyleComplexColor FromColor(nscolor aColor) { return {aColor, 0}; }
|
||||
static StyleComplexColor CurrentColor() { return {NS_RGBA(0, 0, 0, 0), 255}; }
|
||||
|
||||
bool IsNumericColor() const { return mForegroundRatio == 0; }
|
||||
bool IsCurrentColor() const { return mForegroundRatio == 255; }
|
||||
|
||||
bool operator==(const StyleComplexColor& aOther) const {
|
||||
return mForegroundRatio == aOther.mForegroundRatio &&
|
||||
(IsCurrentColor() || mColor == aOther.mColor);
|
||||
}
|
||||
bool operator!=(const StyleComplexColor& aOther) const {
|
||||
return !(*this == aOther);
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // mozilla_StyleComplexColor_h_
|
||||
161
layout/style/StyleContextSource.h
Normal file
161
layout/style/StyleContextSource.h
Normal file
|
|
@ -0,0 +1,161 @@
|
|||
/* -*- Mode: C++; 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/. */
|
||||
|
||||
#ifndef mozilla_StyleContextSource_h
|
||||
#define mozilla_StyleContextSource_h
|
||||
|
||||
#include "mozilla/ServoBindingTypes.h"
|
||||
#include "nsRuleNode.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
// Tagged union between Gecko Rule Nodes and Servo Computed Values.
|
||||
//
|
||||
// The rule node is the node in the lexicographic tree of rule nodes
|
||||
// (the "rule tree") that indicates which style rules are used to
|
||||
// compute the style data, and in what cascading order. The least
|
||||
// specific rule matched is the one whose rule node is a child of the
|
||||
// root of the rule tree, and the most specific rule matched is the
|
||||
// |mRule| member of the rule node.
|
||||
//
|
||||
// In the Servo case, we hold an atomically-refcounted handle to a
|
||||
// Servo ComputedValues struct, which is more or less the Servo equivalent
|
||||
// of an nsStyleContext.
|
||||
|
||||
// Underlying pointer without any strong ownership semantics.
|
||||
struct NonOwningStyleContextSource
|
||||
{
|
||||
MOZ_IMPLICIT NonOwningStyleContextSource(nsRuleNode* aRuleNode)
|
||||
: mBits(reinterpret_cast<uintptr_t>(aRuleNode)) {}
|
||||
explicit NonOwningStyleContextSource(const ServoComputedValues* aComputedValues)
|
||||
: mBits(reinterpret_cast<uintptr_t>(aComputedValues) | 1) {}
|
||||
|
||||
bool operator==(const NonOwningStyleContextSource& aOther) const {
|
||||
MOZ_ASSERT(IsServoComputedValues() == aOther.IsServoComputedValues(),
|
||||
"Comparing Servo to Gecko - probably a bug");
|
||||
return mBits == aOther.mBits;
|
||||
}
|
||||
bool operator!=(const NonOwningStyleContextSource& aOther) const {
|
||||
return !(*this == aOther);
|
||||
}
|
||||
|
||||
// We intentionally avoid exposing IsGeckoRuleNode() here, because that would
|
||||
// encourage callers to do:
|
||||
//
|
||||
// if (source.IsGeckoRuleNode()) {
|
||||
// // Code that we would run unconditionally if it weren't for Servo.
|
||||
// }
|
||||
//
|
||||
// We want these branches to compile away when MOZ_STYLO is disabled, but that
|
||||
// won't happen if there's an implicit null-check.
|
||||
bool IsNull() const { return !mBits; }
|
||||
bool IsGeckoRuleNodeOrNull() const { return !IsServoComputedValues(); }
|
||||
bool IsServoComputedValues() const {
|
||||
#ifdef MOZ_STYLO
|
||||
return mBits & 1;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
nsRuleNode* AsGeckoRuleNode() const {
|
||||
MOZ_ASSERT(IsGeckoRuleNodeOrNull() && !IsNull());
|
||||
return reinterpret_cast<nsRuleNode*>(mBits);
|
||||
}
|
||||
|
||||
const ServoComputedValues* AsServoComputedValues() const {
|
||||
MOZ_ASSERT(IsServoComputedValues());
|
||||
return reinterpret_cast<ServoComputedValues*>(mBits & ~1);
|
||||
}
|
||||
|
||||
bool MatchesNoRules() const {
|
||||
if (IsGeckoRuleNodeOrNull()) {
|
||||
return AsGeckoRuleNode()->IsRoot();
|
||||
}
|
||||
|
||||
// Just assume a Servo-backed StyleContextSource always matches some rules.
|
||||
//
|
||||
// MatchesNoRules is used to ensure style contexts that match no rules
|
||||
// go into a separate mEmptyChild list on their parent. This is only used
|
||||
// as an optimization so that calling FindChildWithRules for style context
|
||||
// sharing is faster for text nodes (which match no rules, and are common).
|
||||
// Since Servo will handle sharing for us, there's no need to split children
|
||||
// into two lists.
|
||||
return false;
|
||||
}
|
||||
|
||||
private:
|
||||
uintptr_t mBits;
|
||||
};
|
||||
|
||||
// Higher-level struct that owns a strong reference to the source. The source
|
||||
// is never null.
|
||||
struct OwningStyleContextSource
|
||||
{
|
||||
explicit OwningStyleContextSource(already_AddRefed<nsRuleNode> aRuleNode)
|
||||
: mRaw(aRuleNode.take())
|
||||
{
|
||||
MOZ_COUNT_CTOR(OwningStyleContextSource);
|
||||
MOZ_ASSERT(!mRaw.IsNull());
|
||||
};
|
||||
|
||||
explicit OwningStyleContextSource(already_AddRefed<ServoComputedValues> aComputedValues)
|
||||
: mRaw(aComputedValues.take())
|
||||
{
|
||||
MOZ_COUNT_CTOR(OwningStyleContextSource);
|
||||
MOZ_ASSERT(!mRaw.IsNull());
|
||||
}
|
||||
|
||||
OwningStyleContextSource(OwningStyleContextSource&& aOther)
|
||||
: mRaw(aOther.mRaw)
|
||||
{
|
||||
MOZ_COUNT_CTOR(OwningStyleContextSource);
|
||||
aOther.mRaw = nullptr;
|
||||
}
|
||||
|
||||
OwningStyleContextSource& operator=(OwningStyleContextSource&) = delete;
|
||||
OwningStyleContextSource(OwningStyleContextSource&) = delete;
|
||||
|
||||
~OwningStyleContextSource() {
|
||||
MOZ_COUNT_DTOR(OwningStyleContextSource);
|
||||
if (mRaw.IsNull()) {
|
||||
// We must have invoked the move constructor.
|
||||
} else if (IsGeckoRuleNode()) {
|
||||
RefPtr<nsRuleNode> releaseme = dont_AddRef(AsGeckoRuleNode());
|
||||
} else {
|
||||
MOZ_ASSERT(IsServoComputedValues());
|
||||
RefPtr<ServoComputedValues> releaseme =
|
||||
dont_AddRef(AsServoComputedValues());
|
||||
}
|
||||
}
|
||||
|
||||
bool operator==(const OwningStyleContextSource& aOther) const {
|
||||
return mRaw == aOther.mRaw;
|
||||
}
|
||||
bool operator!=(const OwningStyleContextSource& aOther) const {
|
||||
return !(*this == aOther);
|
||||
}
|
||||
bool IsNull() const { return mRaw.IsNull(); }
|
||||
bool IsGeckoRuleNode() const {
|
||||
MOZ_ASSERT(!mRaw.IsNull());
|
||||
return mRaw.IsGeckoRuleNodeOrNull();
|
||||
}
|
||||
bool IsServoComputedValues() const { return mRaw.IsServoComputedValues(); }
|
||||
|
||||
NonOwningStyleContextSource AsRaw() const { return mRaw; }
|
||||
nsRuleNode* AsGeckoRuleNode() const { return mRaw.AsGeckoRuleNode(); }
|
||||
ServoComputedValues* AsServoComputedValues() const {
|
||||
return const_cast<ServoComputedValues*>(mRaw.AsServoComputedValues());
|
||||
}
|
||||
|
||||
bool MatchesNoRules() const { return mRaw.MatchesNoRules(); }
|
||||
|
||||
private:
|
||||
NonOwningStyleContextSource mRaw;
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // mozilla_StyleContextSource_h
|
||||
1577
layout/style/StyleRule.cpp
Normal file
1577
layout/style/StyleRule.cpp
Normal file
File diff suppressed because it is too large
Load diff
369
layout/style/StyleRule.h
Normal file
369
layout/style/StyleRule.h
Normal file
|
|
@ -0,0 +1,369 @@
|
|||
/* -*- Mode: C++; 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/. */
|
||||
|
||||
/*
|
||||
* representation of CSS style rules (selectors+declaration) and CSS
|
||||
* selectors
|
||||
*/
|
||||
|
||||
#ifndef mozilla_css_StyleRule_h__
|
||||
#define mozilla_css_StyleRule_h__
|
||||
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "mozilla/MemoryReporting.h"
|
||||
#include "mozilla/css/Rule.h"
|
||||
|
||||
#include "nsString.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsCSSPseudoElements.h"
|
||||
#include "nsIStyleRule.h"
|
||||
|
||||
class nsIAtom;
|
||||
struct nsCSSSelectorList;
|
||||
|
||||
namespace mozilla {
|
||||
enum class CSSPseudoClassType : uint8_t;
|
||||
class CSSStyleSheet;
|
||||
} // namespace mozilla
|
||||
|
||||
struct nsAtomList {
|
||||
public:
|
||||
explicit nsAtomList(nsIAtom* aAtom);
|
||||
explicit nsAtomList(const nsString& aAtomValue);
|
||||
~nsAtomList(void);
|
||||
|
||||
/** Do a deep clone. Should be used only on the first in the linked list. */
|
||||
nsAtomList* Clone() const { return Clone(true); }
|
||||
|
||||
size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const;
|
||||
|
||||
nsCOMPtr<nsIAtom> mAtom;
|
||||
nsAtomList* mNext;
|
||||
private:
|
||||
nsAtomList* Clone(bool aDeep) const;
|
||||
|
||||
nsAtomList(const nsAtomList& aCopy) = delete;
|
||||
nsAtomList& operator=(const nsAtomList& aCopy) = delete;
|
||||
};
|
||||
|
||||
struct nsPseudoClassList {
|
||||
public:
|
||||
typedef mozilla::CSSPseudoClassType CSSPseudoClassType;
|
||||
|
||||
explicit nsPseudoClassList(CSSPseudoClassType aType);
|
||||
nsPseudoClassList(CSSPseudoClassType aType, const char16_t *aString);
|
||||
nsPseudoClassList(CSSPseudoClassType aType, const int32_t *aIntPair);
|
||||
nsPseudoClassList(CSSPseudoClassType aType,
|
||||
nsCSSSelectorList *aSelectorList /* takes ownership */);
|
||||
~nsPseudoClassList(void);
|
||||
|
||||
/** Do a deep clone. Should be used only on the first in the linked list. */
|
||||
nsPseudoClassList* Clone() const { return Clone(true); }
|
||||
|
||||
size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const;
|
||||
|
||||
union {
|
||||
// For a given value of mType, we have either:
|
||||
// a. no value, which means mMemory is always null
|
||||
// (if none of the conditions for (b), (c), or (d) is true)
|
||||
// b. a string value, which means mString/mMemory is non-null
|
||||
// (if nsCSSPseudoClasses::HasStringArg(mType))
|
||||
// c. an integer pair value, which means mNumbers/mMemory is non-null
|
||||
// (if nsCSSPseudoClasses::HasNthPairArg(mType))
|
||||
// d. a selector list, which means mSelectors is non-null
|
||||
// (if nsCSSPseudoClasses::HasSelectorListArg(mType))
|
||||
void* mMemory; // mString and mNumbers use moz_xmalloc/free
|
||||
char16_t* mString;
|
||||
int32_t* mNumbers;
|
||||
nsCSSSelectorList* mSelectors;
|
||||
} u;
|
||||
CSSPseudoClassType mType;
|
||||
nsPseudoClassList* mNext;
|
||||
private:
|
||||
nsPseudoClassList* Clone(bool aDeep) const;
|
||||
|
||||
nsPseudoClassList(const nsPseudoClassList& aCopy) = delete;
|
||||
nsPseudoClassList& operator=(const nsPseudoClassList& aCopy) = delete;
|
||||
};
|
||||
|
||||
#define NS_ATTR_FUNC_SET 0 // [attr]
|
||||
#define NS_ATTR_FUNC_EQUALS 1 // [attr=value]
|
||||
#define NS_ATTR_FUNC_INCLUDES 2 // [attr~=value] (space separated)
|
||||
#define NS_ATTR_FUNC_DASHMATCH 3 // [attr|=value] ('-' truncated)
|
||||
#define NS_ATTR_FUNC_BEGINSMATCH 4 // [attr^=value] (begins with)
|
||||
#define NS_ATTR_FUNC_ENDSMATCH 5 // [attr$=value] (ends with)
|
||||
#define NS_ATTR_FUNC_CONTAINSMATCH 6 // [attr*=value] (contains substring)
|
||||
|
||||
struct nsAttrSelector {
|
||||
public:
|
||||
enum class ValueCaseSensitivity : uint8_t {
|
||||
CaseSensitive,
|
||||
CaseInsensitive,
|
||||
CaseInsensitiveInHTML
|
||||
};
|
||||
|
||||
nsAttrSelector(int32_t aNameSpace, const nsString& aAttr);
|
||||
nsAttrSelector(int32_t aNameSpace, const nsString& aAttr, uint8_t aFunction,
|
||||
const nsString& aValue,
|
||||
ValueCaseSensitivity aValueCaseSensitivity);
|
||||
nsAttrSelector(int32_t aNameSpace, nsIAtom* aLowercaseAttr,
|
||||
nsIAtom* aCasedAttr, uint8_t aFunction,
|
||||
const nsString& aValue,
|
||||
ValueCaseSensitivity aValueCaseSensitivity);
|
||||
~nsAttrSelector(void);
|
||||
|
||||
/** Do a deep clone. Should be used only on the first in the linked list. */
|
||||
nsAttrSelector* Clone() const { return Clone(true); }
|
||||
|
||||
size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const;
|
||||
|
||||
bool IsValueCaseSensitive(bool aInHTML) const {
|
||||
return mValueCaseSensitivity == ValueCaseSensitivity::CaseSensitive ||
|
||||
(!aInHTML &&
|
||||
mValueCaseSensitivity == ValueCaseSensitivity::CaseInsensitiveInHTML);
|
||||
}
|
||||
|
||||
nsString mValue;
|
||||
nsAttrSelector* mNext;
|
||||
nsCOMPtr<nsIAtom> mLowercaseAttr;
|
||||
nsCOMPtr<nsIAtom> mCasedAttr;
|
||||
int32_t mNameSpace;
|
||||
uint8_t mFunction;
|
||||
ValueCaseSensitivity mValueCaseSensitivity;
|
||||
|
||||
private:
|
||||
nsAttrSelector* Clone(bool aDeep) const;
|
||||
|
||||
nsAttrSelector(const nsAttrSelector& aCopy) = delete;
|
||||
nsAttrSelector& operator=(const nsAttrSelector& aCopy) = delete;
|
||||
};
|
||||
|
||||
struct nsCSSSelector {
|
||||
public:
|
||||
typedef mozilla::CSSPseudoClassType CSSPseudoClassType;
|
||||
|
||||
nsCSSSelector(void);
|
||||
~nsCSSSelector(void);
|
||||
|
||||
/** Do a deep clone. Should be used only on the first in the linked list. */
|
||||
nsCSSSelector* Clone() const { return Clone(true, true); }
|
||||
|
||||
void Reset(void);
|
||||
void SetNameSpace(int32_t aNameSpace);
|
||||
void SetTag(const nsString& aTag);
|
||||
void AddID(const nsString& aID);
|
||||
void AddClass(const nsString& aClass);
|
||||
void AddPseudoClass(CSSPseudoClassType aType);
|
||||
void AddPseudoClass(CSSPseudoClassType aType, const char16_t* aString);
|
||||
void AddPseudoClass(CSSPseudoClassType aType, const int32_t* aIntPair);
|
||||
// takes ownership of aSelectorList
|
||||
void AddPseudoClass(CSSPseudoClassType aType,
|
||||
nsCSSSelectorList* aSelectorList);
|
||||
void AddAttribute(int32_t aNameSpace, const nsString& aAttr);
|
||||
void AddAttribute(int32_t aNameSpace, const nsString& aAttr, uint8_t aFunc,
|
||||
const nsString& aValue,
|
||||
nsAttrSelector::ValueCaseSensitivity aValueCaseSensitivity);
|
||||
void SetOperator(char16_t aOperator);
|
||||
|
||||
inline bool HasTagSelector() const {
|
||||
return !!mCasedTag;
|
||||
}
|
||||
|
||||
inline bool IsPseudoElement() const {
|
||||
return mLowercaseTag && !mCasedTag;
|
||||
}
|
||||
|
||||
// Calculate the specificity of this selector (not including its mNext!).
|
||||
int32_t CalcWeight() const;
|
||||
|
||||
void ToString(nsAString& aString, mozilla::CSSStyleSheet* aSheet,
|
||||
bool aAppend = false) const;
|
||||
|
||||
bool IsRestrictedSelector() const {
|
||||
return PseudoType() == mozilla::CSSPseudoElementType::NotPseudo;
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
nsCString RestrictedSelectorToString() const;
|
||||
#endif
|
||||
|
||||
private:
|
||||
void AddPseudoClassInternal(nsPseudoClassList *aPseudoClass);
|
||||
nsCSSSelector* Clone(bool aDeepNext, bool aDeepNegations) const;
|
||||
|
||||
void AppendToStringWithoutCombinators(
|
||||
nsAString& aString,
|
||||
mozilla::CSSStyleSheet* aSheet,
|
||||
bool aUseStandardNamespacePrefixes) const;
|
||||
void AppendToStringWithoutCombinatorsOrNegations(
|
||||
nsAString& aString,
|
||||
mozilla::CSSStyleSheet* aSheet,
|
||||
bool aIsNegated,
|
||||
bool aUseStandardNamespacePrefixes) const;
|
||||
// Returns true if this selector can have a namespace specified (which
|
||||
// happens if and only if the default namespace would apply to this
|
||||
// selector).
|
||||
bool CanBeNamespaced(bool aIsNegated) const;
|
||||
// Calculate the specificity of this selector (not including its mNext
|
||||
// or its mNegations).
|
||||
int32_t CalcWeightWithoutNegations() const;
|
||||
|
||||
public:
|
||||
// Get and set the selector's pseudo type
|
||||
mozilla::CSSPseudoElementType PseudoType() const { return mPseudoType; }
|
||||
void SetPseudoType(mozilla::CSSPseudoElementType aType) {
|
||||
mPseudoType = aType;
|
||||
}
|
||||
|
||||
size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const;
|
||||
|
||||
// For case-sensitive documents, mLowercaseTag is the same as mCasedTag,
|
||||
// but in case-insensitive documents (HTML) mLowercaseTag is lowercase.
|
||||
// Also, for pseudo-elements mCasedTag will be null but mLowercaseTag
|
||||
// contains their name.
|
||||
nsCOMPtr<nsIAtom> mLowercaseTag;
|
||||
nsCOMPtr<nsIAtom> mCasedTag;
|
||||
nsAtomList* mIDList;
|
||||
nsAtomList* mClassList;
|
||||
nsPseudoClassList* mPseudoClassList; // atom for the pseudo, string for
|
||||
// the argument to functional pseudos
|
||||
nsAttrSelector* mAttrList;
|
||||
nsCSSSelector* mNegations;
|
||||
nsCSSSelector* mNext;
|
||||
int32_t mNameSpace;
|
||||
char16_t mOperator;
|
||||
private:
|
||||
// The underlying type of CSSPseudoElementType is uint8_t and
|
||||
// it packs well with mOperator. (char16_t + uint8_t is less than 32bits.)
|
||||
mozilla::CSSPseudoElementType mPseudoType;
|
||||
|
||||
nsCSSSelector(const nsCSSSelector& aCopy) = delete;
|
||||
nsCSSSelector& operator=(const nsCSSSelector& aCopy) = delete;
|
||||
};
|
||||
|
||||
/**
|
||||
* A selector list is the unit of selectors that each style rule has.
|
||||
* For example, "P B, H1 B { ... }" would be a selector list with two
|
||||
* items (where each |nsCSSSelectorList| object's |mSelectors| has
|
||||
* an |mNext| for the P or H1). We represent them as linked lists.
|
||||
*/
|
||||
class inDOMUtils;
|
||||
|
||||
struct nsCSSSelectorList {
|
||||
nsCSSSelectorList(void);
|
||||
~nsCSSSelectorList(void);
|
||||
|
||||
/**
|
||||
* Create a new selector and push it onto the beginning of |mSelectors|,
|
||||
* setting its |mNext| to the current value of |mSelectors|. If there is an
|
||||
* earlier selector, set its |mOperator| to |aOperator|; else |aOperator|
|
||||
* must be char16_t(0).
|
||||
* Returns the new selector.
|
||||
* The list owns the new selector.
|
||||
* The caller is responsible for updating |mWeight|.
|
||||
*/
|
||||
nsCSSSelector* AddSelector(char16_t aOperator);
|
||||
|
||||
/**
|
||||
* Point |mSelectors| to its |mNext|, and delete the first node in the old
|
||||
* |mSelectors|.
|
||||
* Should only be used on a list with more than one selector in it.
|
||||
*/
|
||||
void RemoveRightmostSelector();
|
||||
|
||||
/**
|
||||
* Should be used only on the first in the list
|
||||
*/
|
||||
void ToString(nsAString& aResult, mozilla::CSSStyleSheet* aSheet);
|
||||
|
||||
/**
|
||||
* Do a deep clone. Should be used only on the first in the list.
|
||||
*/
|
||||
nsCSSSelectorList* Clone() const { return Clone(true); }
|
||||
|
||||
size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const;
|
||||
|
||||
nsCSSSelector* mSelectors;
|
||||
int32_t mWeight;
|
||||
nsCSSSelectorList* mNext;
|
||||
protected:
|
||||
friend class inDOMUtils;
|
||||
nsCSSSelectorList* Clone(bool aDeep) const;
|
||||
|
||||
private:
|
||||
nsCSSSelectorList(const nsCSSSelectorList& aCopy) = delete;
|
||||
nsCSSSelectorList& operator=(const nsCSSSelectorList& aCopy) = delete;
|
||||
};
|
||||
|
||||
// 464bab7a-2fce-4f30-ab44-b7a5f3aae57d
|
||||
#define NS_CSS_STYLE_RULE_IMPL_CID \
|
||||
{ 0x464bab7a, 0x2fce, 0x4f30, \
|
||||
{ 0xab, 0x44, 0xb7, 0xa5, 0xf3, 0xaa, 0xe5, 0x7d } }
|
||||
|
||||
namespace mozilla {
|
||||
namespace css {
|
||||
|
||||
class Declaration;
|
||||
class DOMCSSStyleRule;
|
||||
|
||||
class StyleRule final : public Rule
|
||||
{
|
||||
public:
|
||||
StyleRule(nsCSSSelectorList* aSelector,
|
||||
Declaration *aDeclaration,
|
||||
uint32_t aLineNumber, uint32_t aColumnNumber);
|
||||
private:
|
||||
// for |Clone|
|
||||
StyleRule(const StyleRule& aCopy);
|
||||
public:
|
||||
NS_DECLARE_STATIC_IID_ACCESSOR(NS_CSS_STYLE_RULE_IMPL_CID)
|
||||
|
||||
NS_DECL_ISUPPORTS
|
||||
|
||||
// null for style attribute
|
||||
nsCSSSelectorList* Selector() { return mSelector; }
|
||||
|
||||
Declaration* GetDeclaration() const { return mDeclaration; }
|
||||
|
||||
void SetDeclaration(Declaration* aDecl);
|
||||
|
||||
// hooks for DOM rule
|
||||
void GetCssText(nsAString& aCssText);
|
||||
void SetCssText(const nsAString& aCssText);
|
||||
void GetSelectorText(nsAString& aSelectorText);
|
||||
void SetSelectorText(const nsAString& aSelectorText);
|
||||
|
||||
virtual int32_t GetType() const override;
|
||||
|
||||
virtual already_AddRefed<Rule> Clone() const override;
|
||||
|
||||
virtual nsIDOMCSSRule* GetDOMRule() override;
|
||||
|
||||
virtual nsIDOMCSSRule* GetExistingDOMRule() override;
|
||||
|
||||
#ifdef DEBUG
|
||||
virtual void List(FILE* out = stdout, int32_t aIndent = 0) const override;
|
||||
#endif
|
||||
|
||||
virtual size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const override;
|
||||
|
||||
private:
|
||||
~StyleRule();
|
||||
|
||||
private:
|
||||
nsCSSSelectorList* mSelector; // null for style attribute
|
||||
RefPtr<Declaration> mDeclaration;
|
||||
RefPtr<DOMCSSStyleRule> mDOMRule;
|
||||
|
||||
private:
|
||||
StyleRule& operator=(const StyleRule& aCopy) = delete;
|
||||
};
|
||||
|
||||
NS_DEFINE_STATIC_IID_ACCESSOR(StyleRule, NS_CSS_STYLE_RULE_IMPL_CID)
|
||||
|
||||
} // namespace css
|
||||
} // namespace mozilla
|
||||
|
||||
#endif /* mozilla_css_StyleRule_h__ */
|
||||
219
layout/style/StyleSetHandle.h
Normal file
219
layout/style/StyleSetHandle.h
Normal file
|
|
@ -0,0 +1,219 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* 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_StyleSetHandle_h
|
||||
#define mozilla_StyleSetHandle_h
|
||||
|
||||
#include "mozilla/EventStates.h"
|
||||
#include "mozilla/RefPtr.h"
|
||||
#include "mozilla/SheetType.h"
|
||||
#include "mozilla/StyleBackendType.h"
|
||||
#include "mozilla/StyleSheet.h"
|
||||
#include "nsChangeHint.h"
|
||||
#include "nsCSSPseudoElements.h"
|
||||
#include "nsTArray.h"
|
||||
|
||||
namespace mozilla {
|
||||
class CSSStyleSheet;
|
||||
class ServoStyleSet;
|
||||
namespace dom {
|
||||
class Element;
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
class nsIAtom;
|
||||
class nsIContent;
|
||||
class nsIDocument;
|
||||
class nsStyleContext;
|
||||
class nsStyleSet;
|
||||
class nsPresContext;
|
||||
struct TreeMatchContext;
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
#define SERVO_BIT 0x1
|
||||
|
||||
/**
|
||||
* Smart pointer class that can hold a pointer to either an nsStyleSet
|
||||
* or a ServoStyleSet.
|
||||
*/
|
||||
class StyleSetHandle
|
||||
{
|
||||
public:
|
||||
// We define this Ptr class with a StyleSet API that forwards on to the
|
||||
// wrapped pointer, rather than putting these methods on StyleSetHandle
|
||||
// itself, so that we can have StyleSetHandle behave like a smart pointer and
|
||||
// be dereferenced with operator->.
|
||||
class Ptr
|
||||
{
|
||||
public:
|
||||
friend class ::mozilla::StyleSetHandle;
|
||||
|
||||
bool IsGecko() const { return !IsServo(); }
|
||||
bool IsServo() const
|
||||
{
|
||||
MOZ_ASSERT(mValue, "StyleSetHandle null pointer dereference");
|
||||
#ifdef MOZ_STYLO
|
||||
return mValue & SERVO_BIT;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
StyleBackendType BackendType() const
|
||||
{
|
||||
return IsGecko() ? StyleBackendType::Gecko :
|
||||
StyleBackendType::Servo;
|
||||
}
|
||||
|
||||
nsStyleSet* AsGecko()
|
||||
{
|
||||
MOZ_ASSERT(IsGecko());
|
||||
return reinterpret_cast<nsStyleSet*>(mValue);
|
||||
}
|
||||
|
||||
ServoStyleSet* AsServo()
|
||||
{
|
||||
MOZ_ASSERT(IsServo());
|
||||
return reinterpret_cast<ServoStyleSet*>(mValue & ~SERVO_BIT);
|
||||
}
|
||||
|
||||
nsStyleSet* GetAsGecko() { return IsGecko() ? AsGecko() : nullptr; }
|
||||
ServoStyleSet* GetAsServo() { return IsServo() ? AsServo() : nullptr; }
|
||||
|
||||
const nsStyleSet* AsGecko() const
|
||||
{
|
||||
return const_cast<Ptr*>(this)->AsGecko();
|
||||
}
|
||||
|
||||
const ServoStyleSet* AsServo() const
|
||||
{
|
||||
MOZ_ASSERT(IsServo());
|
||||
return const_cast<Ptr*>(this)->AsServo();
|
||||
}
|
||||
|
||||
const nsStyleSet* GetAsGecko() const { return IsGecko() ? AsGecko() : nullptr; }
|
||||
const ServoStyleSet* GetAsServo() const { return IsServo() ? AsServo() : nullptr; }
|
||||
|
||||
// These inline methods are defined in StyleSetHandleInlines.h.
|
||||
inline void Delete();
|
||||
|
||||
// Style set interface. These inline methods are defined in
|
||||
// StyleSetHandleInlines.h and just forward to the underlying
|
||||
// nsStyleSet or ServoStyleSet. See corresponding comments in
|
||||
// nsStyleSet.h for descriptions of these methods.
|
||||
|
||||
inline void Init(nsPresContext* aPresContext);
|
||||
inline void BeginShutdown();
|
||||
inline void Shutdown();
|
||||
inline bool GetAuthorStyleDisabled() const;
|
||||
inline nsresult SetAuthorStyleDisabled(bool aStyleDisabled);
|
||||
inline void BeginUpdate();
|
||||
inline nsresult EndUpdate();
|
||||
inline already_AddRefed<nsStyleContext>
|
||||
ResolveStyleFor(dom::Element* aElement,
|
||||
nsStyleContext* aParentContext);
|
||||
inline already_AddRefed<nsStyleContext>
|
||||
ResolveStyleFor(dom::Element* aElement,
|
||||
nsStyleContext* aParentContext,
|
||||
TreeMatchContext& aTreeMatchContext);
|
||||
inline already_AddRefed<nsStyleContext>
|
||||
ResolveStyleForText(nsIContent* aTextNode,
|
||||
nsStyleContext* aParentContext);
|
||||
inline already_AddRefed<nsStyleContext>
|
||||
ResolveStyleForOtherNonElement(nsStyleContext* aParentContext);
|
||||
inline already_AddRefed<nsStyleContext>
|
||||
ResolvePseudoElementStyle(dom::Element* aParentElement,
|
||||
mozilla::CSSPseudoElementType aType,
|
||||
nsStyleContext* aParentContext,
|
||||
dom::Element* aPseudoElement);
|
||||
inline already_AddRefed<nsStyleContext>
|
||||
ResolveAnonymousBoxStyle(nsIAtom* aPseudoTag, nsStyleContext* aParentContext,
|
||||
uint32_t aFlags = 0);
|
||||
inline nsresult AppendStyleSheet(SheetType aType, StyleSheet* aSheet);
|
||||
inline nsresult PrependStyleSheet(SheetType aType, StyleSheet* aSheet);
|
||||
inline nsresult RemoveStyleSheet(SheetType aType, StyleSheet* aSheet);
|
||||
inline nsresult ReplaceSheets(SheetType aType,
|
||||
const nsTArray<RefPtr<StyleSheet>>& aNewSheets);
|
||||
inline nsresult InsertStyleSheetBefore(SheetType aType,
|
||||
StyleSheet* aNewSheet,
|
||||
StyleSheet* aReferenceSheet);
|
||||
inline int32_t SheetCount(SheetType aType) const;
|
||||
inline StyleSheet* StyleSheetAt(SheetType aType, int32_t aIndex) const;
|
||||
inline nsresult RemoveDocStyleSheet(StyleSheet* aSheet);
|
||||
inline nsresult AddDocStyleSheet(StyleSheet* aSheet, nsIDocument* aDocument);
|
||||
inline already_AddRefed<nsStyleContext>
|
||||
ProbePseudoElementStyle(dom::Element* aParentElement,
|
||||
mozilla::CSSPseudoElementType aType,
|
||||
nsStyleContext* aParentContext);
|
||||
inline already_AddRefed<nsStyleContext>
|
||||
ProbePseudoElementStyle(dom::Element* aParentElement,
|
||||
mozilla::CSSPseudoElementType aType,
|
||||
nsStyleContext* aParentContext,
|
||||
TreeMatchContext& aTreeMatchContext,
|
||||
dom::Element* aPseudoElement = nullptr);
|
||||
inline nsRestyleHint HasStateDependentStyle(dom::Element* aElement,
|
||||
EventStates aStateMask);
|
||||
inline nsRestyleHint HasStateDependentStyle(
|
||||
dom::Element* aElement,
|
||||
mozilla::CSSPseudoElementType aPseudoType,
|
||||
dom::Element* aPseudoElement,
|
||||
EventStates aStateMask);
|
||||
|
||||
inline void RootStyleContextAdded();
|
||||
inline void RootStyleContextRemoved();
|
||||
|
||||
private:
|
||||
// Stores a pointer to an nsStyleSet or a ServoStyleSet. The least
|
||||
// significant bit is 0 for the former, 1 for the latter. This is
|
||||
// valid as the least significant bit will never be used for a pointer
|
||||
// value on platforms we care about.
|
||||
uintptr_t mValue;
|
||||
};
|
||||
|
||||
StyleSetHandle() { mPtr.mValue = 0; }
|
||||
StyleSetHandle(const StyleSetHandle& aOth) { mPtr.mValue = aOth.mPtr.mValue; }
|
||||
MOZ_IMPLICIT StyleSetHandle(nsStyleSet* aSet) { *this = aSet; }
|
||||
MOZ_IMPLICIT StyleSetHandle(ServoStyleSet* aSet) { *this = aSet; }
|
||||
|
||||
StyleSetHandle& operator=(nsStyleSet* aStyleSet)
|
||||
{
|
||||
MOZ_ASSERT(!(reinterpret_cast<uintptr_t>(aStyleSet) & SERVO_BIT),
|
||||
"least significant bit shouldn't be set; we use it for state");
|
||||
mPtr.mValue = reinterpret_cast<uintptr_t>(aStyleSet);
|
||||
return *this;
|
||||
}
|
||||
|
||||
StyleSetHandle& operator=(ServoStyleSet* aStyleSet)
|
||||
{
|
||||
#ifdef MOZ_STYLO
|
||||
MOZ_ASSERT(!(reinterpret_cast<uintptr_t>(aStyleSet) & SERVO_BIT),
|
||||
"least significant bit shouldn't be set; we use it for state");
|
||||
mPtr.mValue =
|
||||
aStyleSet ? (reinterpret_cast<uintptr_t>(aStyleSet) | SERVO_BIT) : 0;
|
||||
return *this;
|
||||
#else
|
||||
MOZ_CRASH("should not have a ServoStyleSet object when MOZ_STYLO is "
|
||||
"disabled");
|
||||
#endif
|
||||
}
|
||||
|
||||
// Make StyleSetHandle usable in boolean contexts.
|
||||
explicit operator bool() const { return !!mPtr.mValue; }
|
||||
bool operator!() const { return !mPtr.mValue; }
|
||||
|
||||
// Make StyleSetHandle behave like a smart pointer.
|
||||
Ptr* operator->() { return &mPtr; }
|
||||
const Ptr* operator->() const { return &mPtr; }
|
||||
|
||||
private:
|
||||
Ptr mPtr;
|
||||
};
|
||||
|
||||
#undef SERVO_BIT
|
||||
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // mozilla_StyleSetHandle_h
|
||||
267
layout/style/StyleSetHandleInlines.h
Normal file
267
layout/style/StyleSetHandleInlines.h
Normal file
|
|
@ -0,0 +1,267 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* 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_StyleSetHandleInlines_h
|
||||
#define mozilla_StyleSetHandleInlines_h
|
||||
|
||||
#include "mozilla/StyleSheetInlines.h"
|
||||
#include "mozilla/ServoStyleSet.h"
|
||||
#include "nsStyleSet.h"
|
||||
|
||||
#define FORWARD_CONCRETE(method_, geckoargs_, servoargs_) \
|
||||
if (IsGecko()) { \
|
||||
return AsGecko()->method_ geckoargs_; \
|
||||
} else { \
|
||||
return AsServo()->method_ servoargs_; \
|
||||
}
|
||||
|
||||
#define FORWARD(method_, args_) FORWARD_CONCRETE(method_, args_, args_)
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
void
|
||||
StyleSetHandle::Ptr::Delete()
|
||||
{
|
||||
if (mValue) {
|
||||
if (IsGecko()) {
|
||||
delete AsGecko();
|
||||
} else {
|
||||
delete AsServo();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
StyleSetHandle::Ptr::Init(nsPresContext* aPresContext)
|
||||
{
|
||||
FORWARD(Init, (aPresContext));
|
||||
}
|
||||
|
||||
void
|
||||
StyleSetHandle::Ptr::BeginShutdown()
|
||||
{
|
||||
FORWARD(BeginShutdown, ());
|
||||
}
|
||||
|
||||
void
|
||||
StyleSetHandle::Ptr::Shutdown()
|
||||
{
|
||||
FORWARD(Shutdown, ());
|
||||
}
|
||||
|
||||
bool
|
||||
StyleSetHandle::Ptr::GetAuthorStyleDisabled() const
|
||||
{
|
||||
FORWARD(GetAuthorStyleDisabled, ());
|
||||
}
|
||||
|
||||
nsresult
|
||||
StyleSetHandle::Ptr::SetAuthorStyleDisabled(bool aStyleDisabled)
|
||||
{
|
||||
FORWARD(SetAuthorStyleDisabled, (aStyleDisabled));
|
||||
}
|
||||
|
||||
void
|
||||
StyleSetHandle::Ptr::BeginUpdate()
|
||||
{
|
||||
FORWARD(BeginUpdate, ());
|
||||
}
|
||||
|
||||
nsresult
|
||||
StyleSetHandle::Ptr::EndUpdate()
|
||||
{
|
||||
FORWARD(EndUpdate, ());
|
||||
}
|
||||
|
||||
// resolve a style context
|
||||
already_AddRefed<nsStyleContext>
|
||||
StyleSetHandle::Ptr::ResolveStyleFor(dom::Element* aElement,
|
||||
nsStyleContext* aParentContext)
|
||||
{
|
||||
FORWARD(ResolveStyleFor, (aElement, aParentContext));
|
||||
}
|
||||
|
||||
already_AddRefed<nsStyleContext>
|
||||
StyleSetHandle::Ptr::ResolveStyleFor(dom::Element* aElement,
|
||||
nsStyleContext* aParentContext,
|
||||
TreeMatchContext& aTreeMatchContext)
|
||||
{
|
||||
FORWARD(ResolveStyleFor, (aElement, aParentContext, aTreeMatchContext));
|
||||
}
|
||||
|
||||
already_AddRefed<nsStyleContext>
|
||||
StyleSetHandle::Ptr::ResolveStyleForText(nsIContent* aTextNode,
|
||||
nsStyleContext* aParentContext)
|
||||
{
|
||||
FORWARD(ResolveStyleForText, (aTextNode, aParentContext));
|
||||
}
|
||||
|
||||
already_AddRefed<nsStyleContext>
|
||||
StyleSetHandle::Ptr::ResolveStyleForOtherNonElement(nsStyleContext* aParentContext)
|
||||
{
|
||||
FORWARD(ResolveStyleForOtherNonElement, (aParentContext));
|
||||
}
|
||||
|
||||
already_AddRefed<nsStyleContext>
|
||||
StyleSetHandle::Ptr::ResolvePseudoElementStyle(dom::Element* aParentElement,
|
||||
CSSPseudoElementType aType,
|
||||
nsStyleContext* aParentContext,
|
||||
dom::Element* aPseudoElement)
|
||||
{
|
||||
FORWARD(ResolvePseudoElementStyle, (aParentElement, aType, aParentContext,
|
||||
aPseudoElement));
|
||||
}
|
||||
|
||||
// aFlags is an nsStyleSet flags bitfield
|
||||
already_AddRefed<nsStyleContext>
|
||||
StyleSetHandle::Ptr::ResolveAnonymousBoxStyle(nsIAtom* aPseudoTag,
|
||||
nsStyleContext* aParentContext,
|
||||
uint32_t aFlags)
|
||||
{
|
||||
FORWARD(ResolveAnonymousBoxStyle, (aPseudoTag, aParentContext, aFlags));
|
||||
}
|
||||
|
||||
// manage the set of style sheets in the style set
|
||||
nsresult
|
||||
StyleSetHandle::Ptr::AppendStyleSheet(SheetType aType, StyleSheet* aSheet)
|
||||
{
|
||||
FORWARD_CONCRETE(AppendStyleSheet, (aType, aSheet->AsGecko()),
|
||||
(aType, aSheet->AsServo()));
|
||||
}
|
||||
|
||||
nsresult
|
||||
StyleSetHandle::Ptr::PrependStyleSheet(SheetType aType, StyleSheet* aSheet)
|
||||
{
|
||||
FORWARD_CONCRETE(PrependStyleSheet, (aType, aSheet->AsGecko()),
|
||||
(aType, aSheet->AsServo()));
|
||||
}
|
||||
|
||||
nsresult
|
||||
StyleSetHandle::Ptr::RemoveStyleSheet(SheetType aType, StyleSheet* aSheet)
|
||||
{
|
||||
FORWARD_CONCRETE(RemoveStyleSheet, (aType, aSheet->AsGecko()),
|
||||
(aType, aSheet->AsServo()));
|
||||
}
|
||||
|
||||
nsresult
|
||||
StyleSetHandle::Ptr::ReplaceSheets(SheetType aType,
|
||||
const nsTArray<RefPtr<StyleSheet>>& aNewSheets)
|
||||
{
|
||||
if (IsGecko()) {
|
||||
nsTArray<RefPtr<CSSStyleSheet>> newSheets(aNewSheets.Length());
|
||||
for (auto& sheet : aNewSheets) {
|
||||
newSheets.AppendElement(sheet->AsGecko());
|
||||
}
|
||||
return AsGecko()->ReplaceSheets(aType, newSheets);
|
||||
} else {
|
||||
nsTArray<RefPtr<ServoStyleSheet>> newSheets(aNewSheets.Length());
|
||||
for (auto& sheet : aNewSheets) {
|
||||
newSheets.AppendElement(sheet->AsServo());
|
||||
}
|
||||
return AsServo()->ReplaceSheets(aType, newSheets);
|
||||
}
|
||||
}
|
||||
|
||||
nsresult
|
||||
StyleSetHandle::Ptr::InsertStyleSheetBefore(SheetType aType,
|
||||
StyleSheet* aNewSheet,
|
||||
StyleSheet* aReferenceSheet)
|
||||
{
|
||||
FORWARD_CONCRETE(
|
||||
InsertStyleSheetBefore,
|
||||
(aType, aNewSheet->AsGecko(), aReferenceSheet->AsGecko()),
|
||||
(aType, aReferenceSheet->AsServo(), aReferenceSheet->AsServo()));
|
||||
}
|
||||
|
||||
int32_t
|
||||
StyleSetHandle::Ptr::SheetCount(SheetType aType) const
|
||||
{
|
||||
FORWARD(SheetCount, (aType));
|
||||
}
|
||||
|
||||
StyleSheet*
|
||||
StyleSetHandle::Ptr::StyleSheetAt(SheetType aType, int32_t aIndex) const
|
||||
{
|
||||
FORWARD(StyleSheetAt, (aType, aIndex));
|
||||
}
|
||||
|
||||
nsresult
|
||||
StyleSetHandle::Ptr::RemoveDocStyleSheet(StyleSheet* aSheet)
|
||||
{
|
||||
FORWARD_CONCRETE(RemoveDocStyleSheet, (aSheet->AsGecko()),
|
||||
(aSheet->AsServo()));
|
||||
}
|
||||
|
||||
nsresult
|
||||
StyleSetHandle::Ptr::AddDocStyleSheet(StyleSheet* aSheet,
|
||||
nsIDocument* aDocument)
|
||||
{
|
||||
FORWARD_CONCRETE(AddDocStyleSheet, (aSheet->AsGecko(), aDocument),
|
||||
(aSheet->AsServo(), aDocument));
|
||||
}
|
||||
|
||||
// check whether there is ::before/::after style for an element
|
||||
already_AddRefed<nsStyleContext>
|
||||
StyleSetHandle::Ptr::ProbePseudoElementStyle(dom::Element* aParentElement,
|
||||
CSSPseudoElementType aType,
|
||||
nsStyleContext* aParentContext)
|
||||
{
|
||||
FORWARD(ProbePseudoElementStyle, (aParentElement, aType, aParentContext));
|
||||
}
|
||||
|
||||
already_AddRefed<nsStyleContext>
|
||||
StyleSetHandle::Ptr::ProbePseudoElementStyle(dom::Element* aParentElement,
|
||||
CSSPseudoElementType aType,
|
||||
nsStyleContext* aParentContext,
|
||||
TreeMatchContext& aTreeMatchContext,
|
||||
dom::Element* aPseudoElement)
|
||||
{
|
||||
FORWARD(ProbePseudoElementStyle, (aParentElement, aType, aParentContext,
|
||||
aTreeMatchContext, aPseudoElement));
|
||||
}
|
||||
|
||||
nsRestyleHint
|
||||
StyleSetHandle::Ptr::HasStateDependentStyle(dom::Element* aElement,
|
||||
EventStates aStateMask)
|
||||
{
|
||||
FORWARD(HasStateDependentStyle, (aElement, aStateMask));
|
||||
}
|
||||
|
||||
nsRestyleHint
|
||||
StyleSetHandle::Ptr::HasStateDependentStyle(dom::Element* aElement,
|
||||
CSSPseudoElementType aPseudoType,
|
||||
dom::Element* aPseudoElement,
|
||||
EventStates aStateMask)
|
||||
{
|
||||
FORWARD(HasStateDependentStyle, (aElement, aPseudoType, aPseudoElement,
|
||||
aStateMask));
|
||||
}
|
||||
|
||||
void
|
||||
StyleSetHandle::Ptr::RootStyleContextAdded()
|
||||
{
|
||||
if (IsGecko()) {
|
||||
AsGecko()->RootStyleContextAdded();
|
||||
} else {
|
||||
// Not needed.
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
StyleSetHandle::Ptr::RootStyleContextRemoved()
|
||||
{
|
||||
if (IsGecko()) {
|
||||
RootStyleContextAdded();
|
||||
} else {
|
||||
// Not needed.
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace mozilla
|
||||
|
||||
#undef FORWARD
|
||||
|
||||
#endif // mozilla_StyleSetHandleInlines_h
|
||||
329
layout/style/StyleSheet.cpp
Normal file
329
layout/style/StyleSheet.cpp
Normal file
|
|
@ -0,0 +1,329 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* 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 "mozilla/StyleSheet.h"
|
||||
|
||||
#include "mozilla/dom/CSSRuleList.h"
|
||||
#include "mozilla/dom/ShadowRoot.h"
|
||||
#include "mozilla/ServoStyleSheet.h"
|
||||
#include "mozilla/StyleSheetInlines.h"
|
||||
#include "mozilla/CSSStyleSheet.h"
|
||||
|
||||
#include "nsNullPrincipal.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
StyleSheet::StyleSheet(StyleBackendType aType, css::SheetParsingMode aParsingMode)
|
||||
: mDocument(nullptr)
|
||||
, mOwningNode(nullptr)
|
||||
, mParsingMode(aParsingMode)
|
||||
, mType(aType)
|
||||
, mDisabled(false)
|
||||
{
|
||||
}
|
||||
|
||||
StyleSheet::StyleSheet(const StyleSheet& aCopy,
|
||||
nsIDocument* aDocumentToUse,
|
||||
nsINode* aOwningNodeToUse)
|
||||
: mTitle(aCopy.mTitle)
|
||||
, mDocument(aDocumentToUse)
|
||||
, mOwningNode(aOwningNodeToUse)
|
||||
, mParsingMode(aCopy.mParsingMode)
|
||||
, mType(aCopy.mType)
|
||||
, mDisabled(aCopy.mDisabled)
|
||||
{
|
||||
}
|
||||
|
||||
// QueryInterface implementation for StyleSheet
|
||||
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(StyleSheet)
|
||||
NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
|
||||
NS_INTERFACE_MAP_ENTRY(nsIDOMStyleSheet)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIDOMCSSStyleSheet)
|
||||
NS_INTERFACE_MAP_END
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTING_ADDREF(StyleSheet)
|
||||
NS_IMPL_CYCLE_COLLECTING_RELEASE(StyleSheet)
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_0(StyleSheet)
|
||||
|
||||
mozilla::dom::CSSStyleSheetParsingMode
|
||||
StyleSheet::ParsingModeDOM()
|
||||
{
|
||||
#define CHECK(X, Y) \
|
||||
static_assert(static_cast<int>(X) == static_cast<int>(Y), \
|
||||
"mozilla::dom::CSSStyleSheetParsingMode and mozilla::css::SheetParsingMode should have identical values");
|
||||
|
||||
CHECK(mozilla::dom::CSSStyleSheetParsingMode::Agent, css::eAgentSheetFeatures);
|
||||
CHECK(mozilla::dom::CSSStyleSheetParsingMode::User, css::eUserSheetFeatures);
|
||||
CHECK(mozilla::dom::CSSStyleSheetParsingMode::Author, css::eAuthorSheetFeatures);
|
||||
|
||||
#undef CHECK
|
||||
|
||||
return static_cast<mozilla::dom::CSSStyleSheetParsingMode>(mParsingMode);
|
||||
}
|
||||
|
||||
bool
|
||||
StyleSheet::IsComplete() const
|
||||
{
|
||||
return SheetInfo().mComplete;
|
||||
}
|
||||
|
||||
void
|
||||
StyleSheet::SetComplete()
|
||||
{
|
||||
NS_ASSERTION(!IsGecko() || !AsGecko()->mDirty,
|
||||
"Can't set a dirty sheet complete!");
|
||||
SheetInfo().mComplete = true;
|
||||
if (mDocument && !mDisabled) {
|
||||
// Let the document know
|
||||
mDocument->BeginUpdate(UPDATE_STYLE);
|
||||
mDocument->SetStyleSheetApplicableState(this, true);
|
||||
mDocument->EndUpdate(UPDATE_STYLE);
|
||||
}
|
||||
|
||||
if (mOwningNode && !mDisabled &&
|
||||
mOwningNode->HasFlag(NODE_IS_IN_SHADOW_TREE) &&
|
||||
mOwningNode->IsContent()) {
|
||||
dom::ShadowRoot* shadowRoot = mOwningNode->AsContent()->GetContainingShadow();
|
||||
shadowRoot->StyleSheetChanged();
|
||||
}
|
||||
}
|
||||
|
||||
StyleSheetInfo::StyleSheetInfo(CORSMode aCORSMode,
|
||||
ReferrerPolicy aReferrerPolicy,
|
||||
const dom::SRIMetadata& aIntegrity)
|
||||
: mPrincipal(nsNullPrincipal::Create())
|
||||
, mCORSMode(aCORSMode)
|
||||
, mReferrerPolicy(aReferrerPolicy)
|
||||
, mIntegrity(aIntegrity)
|
||||
, mComplete(false)
|
||||
#ifdef DEBUG
|
||||
, mPrincipalSet(false)
|
||||
#endif
|
||||
{
|
||||
if (!mPrincipal) {
|
||||
NS_RUNTIMEABORT("nsNullPrincipal::Init failed");
|
||||
}
|
||||
}
|
||||
|
||||
// nsIDOMStyleSheet interface
|
||||
|
||||
NS_IMETHODIMP
|
||||
StyleSheet::GetType(nsAString& aType)
|
||||
{
|
||||
aType.AssignLiteral("text/css");
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
StyleSheet::GetDisabled(bool* aDisabled)
|
||||
{
|
||||
*aDisabled = Disabled();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
StyleSheet::SetDisabled(bool aDisabled)
|
||||
{
|
||||
// DOM method, so handle BeginUpdate/EndUpdate
|
||||
MOZ_AUTO_DOC_UPDATE(mDocument, UPDATE_STYLE, true);
|
||||
if (IsGecko()) {
|
||||
AsGecko()->SetEnabled(!aDisabled);
|
||||
} else {
|
||||
MOZ_CRASH("stylo: unimplemented SetEnabled");
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
StyleSheet::GetOwnerNode(nsIDOMNode** aOwnerNode)
|
||||
{
|
||||
nsCOMPtr<nsIDOMNode> ownerNode = do_QueryInterface(GetOwnerNode());
|
||||
ownerNode.forget(aOwnerNode);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
StyleSheet::GetHref(nsAString& aHref)
|
||||
{
|
||||
if (nsIURI* sheetURI = SheetInfo().mOriginalSheetURI) {
|
||||
nsAutoCString str;
|
||||
nsresult rv = sheetURI->GetSpec(str);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
CopyUTF8toUTF16(str, aHref);
|
||||
} else {
|
||||
SetDOMStringToNull(aHref);
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
StyleSheet::GetTitle(nsAString& aTitle)
|
||||
{
|
||||
aTitle.Assign(mTitle);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// nsIDOMStyleSheet interface
|
||||
|
||||
NS_IMETHODIMP
|
||||
StyleSheet::GetParentStyleSheet(nsIDOMStyleSheet** aParentStyleSheet)
|
||||
{
|
||||
NS_ENSURE_ARG_POINTER(aParentStyleSheet);
|
||||
NS_IF_ADDREF(*aParentStyleSheet = GetParentStyleSheet());
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
StyleSheet::GetMedia(nsIDOMMediaList** aMedia)
|
||||
{
|
||||
NS_ADDREF(*aMedia = Media());
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
StyleSheet::GetOwnerRule(nsIDOMCSSRule** aOwnerRule)
|
||||
{
|
||||
NS_IF_ADDREF(*aOwnerRule = GetDOMOwnerRule());
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
StyleSheet::GetCssRules(nsIDOMCSSRuleList** aCssRules)
|
||||
{
|
||||
ErrorResult rv;
|
||||
nsCOMPtr<nsIDOMCSSRuleList> rules =
|
||||
GetCssRules(*nsContentUtils::SubjectPrincipal(), rv);
|
||||
rules.forget(aCssRules);
|
||||
return rv.StealNSResult();
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
StyleSheet::InsertRule(const nsAString& aRule, uint32_t aIndex,
|
||||
uint32_t* aReturn)
|
||||
{
|
||||
ErrorResult rv;
|
||||
*aReturn =
|
||||
InsertRule(aRule, aIndex, *nsContentUtils::SubjectPrincipal(), rv);
|
||||
return rv.StealNSResult();
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
StyleSheet::DeleteRule(uint32_t aIndex)
|
||||
{
|
||||
ErrorResult rv;
|
||||
DeleteRule(aIndex, *nsContentUtils::SubjectPrincipal(), rv);
|
||||
return rv.StealNSResult();
|
||||
}
|
||||
|
||||
// WebIDL CSSStyleSheet API
|
||||
|
||||
#define FORWARD_INTERNAL(method_, args_) \
|
||||
if (IsServo()) { \
|
||||
return AsServo()->method_ args_; \
|
||||
} \
|
||||
return AsGecko()->method_ args_;
|
||||
|
||||
dom::CSSRuleList*
|
||||
StyleSheet::GetCssRules(nsIPrincipal& aSubjectPrincipal,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
if (!AreRulesAvailable(aSubjectPrincipal, aRv)) {
|
||||
return nullptr;
|
||||
}
|
||||
FORWARD_INTERNAL(GetCssRulesInternal, (aRv))
|
||||
}
|
||||
|
||||
uint32_t
|
||||
StyleSheet::InsertRule(const nsAString& aRule, uint32_t aIndex,
|
||||
nsIPrincipal& aSubjectPrincipal,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
if (!AreRulesAvailable(aSubjectPrincipal, aRv)) {
|
||||
return 0;
|
||||
}
|
||||
FORWARD_INTERNAL(InsertRuleInternal, (aRule, aIndex, aRv))
|
||||
}
|
||||
|
||||
void
|
||||
StyleSheet::DeleteRule(uint32_t aIndex,
|
||||
nsIPrincipal& aSubjectPrincipal,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
if (!AreRulesAvailable(aSubjectPrincipal, aRv)) {
|
||||
return;
|
||||
}
|
||||
FORWARD_INTERNAL(DeleteRuleInternal, (aIndex, aRv))
|
||||
}
|
||||
|
||||
#undef FORWARD_INTERNAL
|
||||
|
||||
void
|
||||
StyleSheet::SubjectSubsumesInnerPrincipal(nsIPrincipal& aSubjectPrincipal,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
StyleSheetInfo& info = SheetInfo();
|
||||
|
||||
if (aSubjectPrincipal.Subsumes(info.mPrincipal)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Allow access only if CORS mode is not NONE
|
||||
if (GetCORSMode() == CORS_NONE) {
|
||||
aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
|
||||
return;
|
||||
}
|
||||
|
||||
// Now make sure we set the principal of our inner to the subjectPrincipal.
|
||||
// We do this because we're in a situation where the caller would not normally
|
||||
// be able to access the sheet, but the sheet has opted in to being read.
|
||||
// Unfortunately, that means it's also opted in to being _edited_, and if the
|
||||
// caller now makes edits to the sheet we want the resulting resource loads,
|
||||
// if any, to look as if they are coming from the caller's principal, not the
|
||||
// original sheet principal.
|
||||
//
|
||||
// That means we need a unique inner, of course. But we don't want to do that
|
||||
// if we're not complete yet. Luckily, all the callers of this method throw
|
||||
// anyway if not complete, so we can just do that here too.
|
||||
if (!info.mComplete) {
|
||||
aRv.Throw(NS_ERROR_DOM_INVALID_ACCESS_ERR);
|
||||
return;
|
||||
}
|
||||
|
||||
WillDirty();
|
||||
|
||||
info.mPrincipal = &aSubjectPrincipal;
|
||||
|
||||
DidDirty();
|
||||
}
|
||||
|
||||
bool
|
||||
StyleSheet::AreRulesAvailable(nsIPrincipal& aSubjectPrincipal,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
// Rules are not available on incomplete sheets.
|
||||
if (!SheetInfo().mComplete) {
|
||||
aRv.Throw(NS_ERROR_DOM_INVALID_ACCESS_ERR);
|
||||
return false;
|
||||
}
|
||||
//-- Security check: Only scripts whose principal subsumes that of the
|
||||
// style sheet can access rule collections.
|
||||
SubjectSubsumesInnerPrincipal(aSubjectPrincipal, aRv);
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// nsWrapperCache
|
||||
|
||||
JSObject*
|
||||
StyleSheet::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
|
||||
{
|
||||
return CSSStyleSheetBinding::Wrap(aCx, this, aGivenProto);
|
||||
}
|
||||
|
||||
} // namespace mozilla
|
||||
210
layout/style/StyleSheet.h
Normal file
210
layout/style/StyleSheet.h
Normal file
|
|
@ -0,0 +1,210 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* 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_StyleSheet_h
|
||||
#define mozilla_StyleSheet_h
|
||||
|
||||
#include "mozilla/css/SheetParsingMode.h"
|
||||
#include "mozilla/dom/CSSStyleSheetBinding.h"
|
||||
#include "mozilla/net/ReferrerPolicy.h"
|
||||
#include "mozilla/StyleBackendType.h"
|
||||
#include "mozilla/CORSMode.h"
|
||||
#include "mozilla/ServoUtils.h"
|
||||
|
||||
#include "nsIDOMCSSStyleSheet.h"
|
||||
#include "nsWrapperCache.h"
|
||||
|
||||
class nsIDocument;
|
||||
class nsINode;
|
||||
class nsIPrincipal;
|
||||
class nsMediaList;
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
class CSSStyleSheet;
|
||||
class ServoStyleSheet;
|
||||
struct StyleSheetInfo;
|
||||
|
||||
namespace dom {
|
||||
class CSSRuleList;
|
||||
class SRIMetadata;
|
||||
} // namespace dom
|
||||
|
||||
/**
|
||||
* Superclass for data common to CSSStyleSheet and ServoStyleSheet.
|
||||
*/
|
||||
class StyleSheet : public nsIDOMCSSStyleSheet
|
||||
, public nsWrapperCache
|
||||
{
|
||||
protected:
|
||||
StyleSheet(StyleBackendType aType, css::SheetParsingMode aParsingMode);
|
||||
StyleSheet(const StyleSheet& aCopy,
|
||||
nsIDocument* aDocumentToUse,
|
||||
nsINode* aOwningNodeToUse);
|
||||
virtual ~StyleSheet() {}
|
||||
|
||||
public:
|
||||
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
|
||||
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(StyleSheet)
|
||||
|
||||
void SetOwningNode(nsINode* aOwningNode)
|
||||
{
|
||||
mOwningNode = aOwningNode;
|
||||
}
|
||||
|
||||
css::SheetParsingMode ParsingMode() { return mParsingMode; }
|
||||
mozilla::dom::CSSStyleSheetParsingMode ParsingModeDOM();
|
||||
|
||||
// The document this style sheet is associated with. May be null
|
||||
nsIDocument* GetDocument() const { return mDocument; }
|
||||
|
||||
/**
|
||||
* Whether the sheet is complete.
|
||||
*/
|
||||
bool IsComplete() const;
|
||||
void SetComplete();
|
||||
|
||||
MOZ_DECL_STYLO_METHODS(CSSStyleSheet, ServoStyleSheet)
|
||||
|
||||
// Whether the sheet is for an inline <style> element.
|
||||
inline bool IsInline() const;
|
||||
|
||||
inline nsIURI* GetSheetURI() const;
|
||||
/* Get the URI this sheet was originally loaded from, if any. Can
|
||||
return null */
|
||||
inline nsIURI* GetOriginalURI() const;
|
||||
inline nsIURI* GetBaseURI() const;
|
||||
/**
|
||||
* SetURIs must be called on all sheets before parsing into them.
|
||||
* SetURIs may only be called while the sheet is 1) incomplete and 2)
|
||||
* has no rules in it
|
||||
*/
|
||||
inline void SetURIs(nsIURI* aSheetURI, nsIURI* aOriginalSheetURI,
|
||||
nsIURI* aBaseURI);
|
||||
|
||||
/**
|
||||
* Whether the sheet is applicable. A sheet that is not applicable
|
||||
* should never be inserted into a style set. A sheet may not be
|
||||
* applicable for a variety of reasons including being disabled and
|
||||
* being incomplete.
|
||||
*/
|
||||
inline bool IsApplicable() const;
|
||||
inline bool HasRules() const;
|
||||
|
||||
// style sheet owner info
|
||||
nsIDocument* GetOwningDocument() const { return mDocument; }
|
||||
inline void SetOwningDocument(nsIDocument* aDocument);
|
||||
nsINode* GetOwnerNode() const { return mOwningNode; }
|
||||
inline StyleSheet* GetParentSheet() const;
|
||||
|
||||
inline void AppendStyleSheet(StyleSheet* aSheet);
|
||||
|
||||
// Principal() never returns a null pointer.
|
||||
inline nsIPrincipal* Principal() const;
|
||||
/**
|
||||
* SetPrincipal should be called on all sheets before parsing into them.
|
||||
* This can only be called once with a non-null principal. Calling this with
|
||||
* a null pointer is allowed and is treated as a no-op.
|
||||
*/
|
||||
inline void SetPrincipal(nsIPrincipal* aPrincipal);
|
||||
|
||||
// Get this style sheet's CORS mode
|
||||
inline CORSMode GetCORSMode() const;
|
||||
// Get this style sheet's Referrer Policy
|
||||
inline net::ReferrerPolicy GetReferrerPolicy() const;
|
||||
// Get this style sheet's integrity metadata
|
||||
inline void GetIntegrity(dom::SRIMetadata& aResult) const;
|
||||
|
||||
inline size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const;
|
||||
#ifdef DEBUG
|
||||
inline void List(FILE* aOut = stdout, int32_t aIndex = 0) const;
|
||||
#endif
|
||||
|
||||
// WebIDL StyleSheet API
|
||||
// The XPCOM GetType is fine for WebIDL.
|
||||
// The XPCOM GetHref is fine for WebIDL
|
||||
// GetOwnerNode is defined above.
|
||||
inline StyleSheet* GetParentStyleSheet() const;
|
||||
// The XPCOM GetTitle is fine for WebIDL.
|
||||
virtual nsMediaList* Media() = 0;
|
||||
bool Disabled() const { return mDisabled; }
|
||||
// The XPCOM SetDisabled is fine for WebIDL.
|
||||
|
||||
// WebIDL CSSStyleSheet API
|
||||
virtual nsIDOMCSSRule* GetDOMOwnerRule() const = 0;
|
||||
dom::CSSRuleList* GetCssRules(nsIPrincipal& aSubjectPrincipal,
|
||||
ErrorResult& aRv);
|
||||
uint32_t InsertRule(const nsAString& aRule, uint32_t aIndex,
|
||||
nsIPrincipal& aSubjectPrincipal,
|
||||
ErrorResult& aRv);
|
||||
void DeleteRule(uint32_t aIndex,
|
||||
nsIPrincipal& aSubjectPrincipal,
|
||||
ErrorResult& aRv);
|
||||
|
||||
// WebIDL miscellaneous bits
|
||||
inline dom::ParentObject GetParentObject() const;
|
||||
JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) final;
|
||||
|
||||
// nsIDOMStyleSheet interface
|
||||
NS_IMETHOD GetType(nsAString& aType) final;
|
||||
NS_IMETHOD GetDisabled(bool* aDisabled) final;
|
||||
NS_IMETHOD SetDisabled(bool aDisabled) final;
|
||||
NS_IMETHOD GetOwnerNode(nsIDOMNode** aOwnerNode) final;
|
||||
NS_IMETHOD GetParentStyleSheet(nsIDOMStyleSheet** aParentStyleSheet) final;
|
||||
NS_IMETHOD GetHref(nsAString& aHref) final;
|
||||
NS_IMETHOD GetTitle(nsAString& aTitle) final;
|
||||
NS_IMETHOD GetMedia(nsIDOMMediaList** aMedia) final;
|
||||
|
||||
// nsIDOMCSSStyleSheet
|
||||
NS_IMETHOD GetOwnerRule(nsIDOMCSSRule** aOwnerRule) final;
|
||||
NS_IMETHOD GetCssRules(nsIDOMCSSRuleList** aCssRules) final;
|
||||
NS_IMETHOD InsertRule(const nsAString& aRule, uint32_t aIndex,
|
||||
uint32_t* aReturn) final;
|
||||
NS_IMETHOD DeleteRule(uint32_t aIndex) final;
|
||||
|
||||
// Changes to sheets should be inside of a WillDirty-DidDirty pair.
|
||||
// However, the calls do not need to be matched; it's ok to call
|
||||
// WillDirty and then make no change and skip the DidDirty call.
|
||||
inline void WillDirty();
|
||||
inline void DidDirty();
|
||||
|
||||
private:
|
||||
// Get a handle to the various stylesheet bits which live on the 'inner' for
|
||||
// gecko stylesheets and live on the StyleSheet for Servo stylesheets.
|
||||
inline StyleSheetInfo& SheetInfo();
|
||||
inline const StyleSheetInfo& SheetInfo() const;
|
||||
|
||||
// Check if the rules are available for read and write.
|
||||
// It does the security check as well as whether the rules have been
|
||||
// completely loaded. aRv will have an exception set if this function
|
||||
// returns false.
|
||||
bool AreRulesAvailable(nsIPrincipal& aSubjectPrincipal,
|
||||
ErrorResult& aRv);
|
||||
|
||||
protected:
|
||||
// Return success if the subject principal subsumes the principal of our
|
||||
// inner, error otherwise. This will also succeed if the subject has
|
||||
// UniversalXPConnect or if access is allowed by CORS. In the latter case,
|
||||
// it will set the principal of the inner to the subject principal.
|
||||
void SubjectSubsumesInnerPrincipal(nsIPrincipal& aSubjectPrincipal,
|
||||
ErrorResult& aRv);
|
||||
|
||||
nsString mTitle;
|
||||
nsIDocument* mDocument; // weak ref; parents maintain this for their children
|
||||
nsINode* mOwningNode; // weak ref
|
||||
|
||||
// mParsingMode controls access to nonstandard style constructs that
|
||||
// are not safe for use on the public Web but necessary in UA sheets
|
||||
// and/or useful in user sheets.
|
||||
css::SheetParsingMode mParsingMode;
|
||||
|
||||
const StyleBackendType mType;
|
||||
bool mDisabled;
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // mozilla_StyleSheet_h
|
||||
52
layout/style/StyleSheetInfo.h
Normal file
52
layout/style/StyleSheetInfo.h
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* 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_StyleSheetInfo_h
|
||||
#define mozilla_StyleSheetInfo_h
|
||||
|
||||
#include "mozilla/dom/SRIMetadata.h"
|
||||
#include "mozilla/net/ReferrerPolicy.h"
|
||||
#include "mozilla/CORSMode.h"
|
||||
|
||||
#include "nsIURI.h"
|
||||
|
||||
namespace mozilla {
|
||||
class CSSStyleSheet;
|
||||
} // namespace mozilla
|
||||
class nsCSSRuleProcessor;
|
||||
class nsIPrincipal;
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
/**
|
||||
* Struct for data common to CSSStyleSheetInner and ServoStyleSheet.
|
||||
*/
|
||||
struct StyleSheetInfo
|
||||
{
|
||||
typedef net::ReferrerPolicy ReferrerPolicy;
|
||||
|
||||
StyleSheetInfo(CORSMode aCORSMode,
|
||||
ReferrerPolicy aReferrerPolicy,
|
||||
const dom::SRIMetadata& aIntegrity);
|
||||
|
||||
nsCOMPtr<nsIURI> mSheetURI; // for error reports, etc.
|
||||
nsCOMPtr<nsIURI> mOriginalSheetURI; // for GetHref. Can be null.
|
||||
nsCOMPtr<nsIURI> mBaseURI; // for resolving relative URIs
|
||||
nsCOMPtr<nsIPrincipal> mPrincipal;
|
||||
CORSMode mCORSMode;
|
||||
// The Referrer Policy of a stylesheet is used for its child sheets, so it is
|
||||
// stored here.
|
||||
ReferrerPolicy mReferrerPolicy;
|
||||
dom::SRIMetadata mIntegrity;
|
||||
bool mComplete;
|
||||
#ifdef DEBUG
|
||||
bool mPrincipalSet;
|
||||
#endif
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // mozilla_StyleSheetInfo_h
|
||||
176
layout/style/StyleSheetInlines.h
Normal file
176
layout/style/StyleSheetInlines.h
Normal file
|
|
@ -0,0 +1,176 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* 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_StyleSheetInlines_h
|
||||
#define mozilla_StyleSheetInlines_h
|
||||
|
||||
#include "mozilla/StyleSheetInfo.h"
|
||||
#include "mozilla/ServoStyleSheet.h"
|
||||
#include "mozilla/CSSStyleSheet.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
MOZ_DEFINE_STYLO_METHODS(StyleSheet, CSSStyleSheet, ServoStyleSheet)
|
||||
|
||||
StyleSheetInfo&
|
||||
StyleSheet::SheetInfo()
|
||||
{
|
||||
if (IsServo()) {
|
||||
return AsServo()->mSheetInfo;
|
||||
}
|
||||
return *AsGecko()->mInner;
|
||||
}
|
||||
|
||||
const StyleSheetInfo&
|
||||
StyleSheet::SheetInfo() const
|
||||
{
|
||||
if (IsServo()) {
|
||||
return AsServo()->mSheetInfo;
|
||||
}
|
||||
return *AsGecko()->mInner;
|
||||
}
|
||||
|
||||
bool
|
||||
StyleSheet::IsInline() const
|
||||
{
|
||||
return !SheetInfo().mOriginalSheetURI;
|
||||
}
|
||||
|
||||
nsIURI*
|
||||
StyleSheet::GetSheetURI() const
|
||||
{
|
||||
return SheetInfo().mSheetURI;
|
||||
}
|
||||
|
||||
nsIURI*
|
||||
StyleSheet::GetOriginalURI() const
|
||||
{
|
||||
return SheetInfo().mOriginalSheetURI;
|
||||
}
|
||||
|
||||
nsIURI*
|
||||
StyleSheet::GetBaseURI() const
|
||||
{
|
||||
return SheetInfo().mBaseURI;
|
||||
}
|
||||
|
||||
void
|
||||
StyleSheet::SetURIs(nsIURI* aSheetURI, nsIURI* aOriginalSheetURI,
|
||||
nsIURI* aBaseURI)
|
||||
{
|
||||
NS_PRECONDITION(aSheetURI && aBaseURI, "null ptr");
|
||||
StyleSheetInfo& info = SheetInfo();
|
||||
MOZ_ASSERT(!HasRules() && !info.mComplete,
|
||||
"Can't call SetURIs on sheets that are complete or have rules");
|
||||
info.mSheetURI = aSheetURI;
|
||||
info.mOriginalSheetURI = aOriginalSheetURI;
|
||||
info.mBaseURI = aBaseURI;
|
||||
}
|
||||
|
||||
bool
|
||||
StyleSheet::IsApplicable() const
|
||||
{
|
||||
return !mDisabled && SheetInfo().mComplete;
|
||||
}
|
||||
|
||||
bool
|
||||
StyleSheet::HasRules() const
|
||||
{
|
||||
MOZ_STYLO_FORWARD(HasRules, ())
|
||||
}
|
||||
|
||||
void
|
||||
StyleSheet::SetOwningDocument(nsIDocument* aDocument)
|
||||
{
|
||||
MOZ_STYLO_FORWARD(SetOwningDocument, (aDocument))
|
||||
}
|
||||
|
||||
StyleSheet*
|
||||
StyleSheet::GetParentSheet() const
|
||||
{
|
||||
MOZ_STYLO_FORWARD(GetParentSheet, ())
|
||||
}
|
||||
|
||||
StyleSheet*
|
||||
StyleSheet::GetParentStyleSheet() const
|
||||
{
|
||||
return GetParentSheet();
|
||||
}
|
||||
|
||||
dom::ParentObject
|
||||
StyleSheet::GetParentObject() const
|
||||
{
|
||||
if (mOwningNode) {
|
||||
return dom::ParentObject(mOwningNode);
|
||||
}
|
||||
return dom::ParentObject(GetParentSheet());
|
||||
}
|
||||
|
||||
void
|
||||
StyleSheet::AppendStyleSheet(StyleSheet* aSheet)
|
||||
{
|
||||
MOZ_STYLO_FORWARD_CONCRETE(AppendStyleSheet,
|
||||
(aSheet->AsGecko()), (aSheet->AsServo()))
|
||||
}
|
||||
|
||||
nsIPrincipal*
|
||||
StyleSheet::Principal() const
|
||||
{
|
||||
return SheetInfo().mPrincipal;
|
||||
}
|
||||
|
||||
void
|
||||
StyleSheet::SetPrincipal(nsIPrincipal* aPrincipal)
|
||||
{
|
||||
StyleSheetInfo& info = SheetInfo();
|
||||
NS_PRECONDITION(!info.mPrincipalSet, "Should only set principal once");
|
||||
if (aPrincipal) {
|
||||
info.mPrincipal = aPrincipal;
|
||||
#ifdef DEBUG
|
||||
info.mPrincipalSet = true;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
CORSMode
|
||||
StyleSheet::GetCORSMode() const
|
||||
{
|
||||
return SheetInfo().mCORSMode;
|
||||
}
|
||||
|
||||
net::ReferrerPolicy
|
||||
StyleSheet::GetReferrerPolicy() const
|
||||
{
|
||||
return SheetInfo().mReferrerPolicy;
|
||||
}
|
||||
|
||||
void
|
||||
StyleSheet::GetIntegrity(dom::SRIMetadata& aResult) const
|
||||
{
|
||||
aResult = SheetInfo().mIntegrity;
|
||||
}
|
||||
|
||||
size_t
|
||||
StyleSheet::SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const
|
||||
{
|
||||
MOZ_STYLO_FORWARD(SizeOfIncludingThis, (aMallocSizeOf))
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
void
|
||||
StyleSheet::List(FILE* aOut, int32_t aIndex) const
|
||||
{
|
||||
MOZ_STYLO_FORWARD(List, (aOut, aIndex))
|
||||
}
|
||||
#endif
|
||||
|
||||
void StyleSheet::WillDirty() { MOZ_STYLO_FORWARD(WillDirty, ()) }
|
||||
void StyleSheet::DidDirty() { MOZ_STYLO_FORWARD(DidDirty, ()) }
|
||||
|
||||
|
||||
}
|
||||
|
||||
#endif // mozilla_StyleSheetInlines_h
|
||||
121
layout/style/StyleStructContext.h
Normal file
121
layout/style/StyleStructContext.h
Normal file
|
|
@ -0,0 +1,121 @@
|
|||
/* -*- Mode: C++; 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/. */
|
||||
|
||||
#ifndef mozilla_StyleStructContext_h
|
||||
#define mozilla_StyleStructContext_h
|
||||
|
||||
#include "CounterStyleManager.h"
|
||||
#include "mozilla/LookAndFeel.h"
|
||||
#include "nsPresContext.h"
|
||||
|
||||
class nsDeviceContext;
|
||||
|
||||
/**
|
||||
* Construction context for style structs.
|
||||
*
|
||||
* Certain Gecko style structs have historically taken an nsPresContext
|
||||
* argument in their constructor, which is used to compute various things. This
|
||||
* makes Gecko style structs document-specific (which Servo style structs are
|
||||
* not), and means that the initial values for style-structs cannot be shared
|
||||
* across the entire runtime (as is the case in Servo).
|
||||
*
|
||||
* We'd like to remove this constraint so that Gecko can get the benefits of the
|
||||
* Servo model, and so that Gecko aligns better with the Servo style system when
|
||||
* using it. Unfortunately, this may require a fair amount of work, especially
|
||||
* related to text zoom.
|
||||
*
|
||||
* So as an intermediate step, we define a reduced API set of "things that are
|
||||
* needed when constructing style structs". This just wraps and forwards to an
|
||||
* nsPresContext in the Gecko case, and returns some default not-always-correct
|
||||
* values in the Servo case. We can then focus on reducing this API surface to
|
||||
* zero, at which point this can be removed.
|
||||
*
|
||||
* We don't put the type in namespace mozilla, since we expect it to be
|
||||
* temporary, and the namespacing would clutter up nsStyleStruct.h.
|
||||
*/
|
||||
#ifdef MOZ_STYLO
|
||||
#define SERVO_DEFAULT(default_val) { if (!mPresContext) { return default_val; } }
|
||||
#else
|
||||
#define SERVO_DEFAULT(default_val) { MOZ_ASSERT(mPresContext); }
|
||||
#endif
|
||||
class StyleStructContext {
|
||||
public:
|
||||
MOZ_IMPLICIT StyleStructContext(nsPresContext* aPresContext)
|
||||
: mPresContext(aPresContext) { MOZ_ASSERT(aPresContext); }
|
||||
static StyleStructContext ServoContext() { return StyleStructContext(); }
|
||||
|
||||
// XXXbholley: Need to make text zoom work with stylo. This probably means
|
||||
// moving the zoom handling out of computed values and into a post-
|
||||
// computation.
|
||||
float TextZoom()
|
||||
{
|
||||
SERVO_DEFAULT(1.0);
|
||||
return mPresContext->TextZoom();
|
||||
}
|
||||
|
||||
const nsFont* GetDefaultFont(uint8_t aFontID)
|
||||
{
|
||||
// NB: The servo case only differ from the default case in terms of which
|
||||
// font pref cache gets used. The distinction is probably unnecessary.
|
||||
SERVO_DEFAULT(mozilla::StaticPresData::Get()->
|
||||
GetDefaultFont(aFontID, GetLanguageFromCharset()));
|
||||
return mPresContext->GetDefaultFont(aFontID, GetLanguageFromCharset());
|
||||
}
|
||||
|
||||
uint32_t GetBidi()
|
||||
{
|
||||
SERVO_DEFAULT(0);
|
||||
return mPresContext->GetBidi();
|
||||
}
|
||||
|
||||
int32_t AppUnitsPerDevPixel();
|
||||
|
||||
nscoord DevPixelsToAppUnits(int32_t aPixels)
|
||||
{
|
||||
return NSIntPixelsToAppUnits(aPixels, AppUnitsPerDevPixel());
|
||||
}
|
||||
|
||||
typedef mozilla::LookAndFeel LookAndFeel;
|
||||
nscolor DefaultColor()
|
||||
{
|
||||
SERVO_DEFAULT(LookAndFeel::GetColor(LookAndFeel::eColorID_WindowForeground,
|
||||
NS_RGB(0x00, 0x00, 0x00)));
|
||||
return mPresContext->DefaultColor();
|
||||
}
|
||||
|
||||
mozilla::CounterStyle* BuildCounterStyle(const nsSubstring& aName)
|
||||
{
|
||||
SERVO_DEFAULT(mozilla::CounterStyleManager::GetBuiltinStyle(NS_STYLE_LIST_STYLE_DISC));
|
||||
return mPresContext->CounterStyleManager()->BuildCounterStyle(aName);
|
||||
}
|
||||
|
||||
nsIAtom* GetLanguageFromCharset() const
|
||||
{
|
||||
SERVO_DEFAULT(nsGkAtoms::x_western);
|
||||
return mPresContext->GetLanguageFromCharset();
|
||||
}
|
||||
|
||||
already_AddRefed<nsIAtom> GetContentLanguage() const
|
||||
{
|
||||
SERVO_DEFAULT(do_AddRef(nsGkAtoms::x_western));
|
||||
return mPresContext->GetContentLanguage();
|
||||
}
|
||||
|
||||
private:
|
||||
nsDeviceContext* DeviceContext()
|
||||
{
|
||||
SERVO_DEFAULT(HackilyFindSomeDeviceContext());
|
||||
return mPresContext->DeviceContext();
|
||||
}
|
||||
|
||||
nsDeviceContext* HackilyFindSomeDeviceContext();
|
||||
|
||||
StyleStructContext() : mPresContext(nullptr) {}
|
||||
nsPresContext* mPresContext;
|
||||
};
|
||||
|
||||
#undef SERVO_DEFAULT
|
||||
|
||||
#endif // mozilla_StyleStructContext_h
|
||||
40
layout/style/TopLevelImageDocument.css
Normal file
40
layout/style/TopLevelImageDocument.css
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
/* -*- Mode: C++; 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/. */
|
||||
|
||||
/*
|
||||
This CSS stylesheet defines the rules to be applied to ImageDocuments that
|
||||
are top level (e.g. not iframes).
|
||||
*/
|
||||
|
||||
@media not print {
|
||||
body {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
img {
|
||||
text-align: center;
|
||||
position: absolute;
|
||||
margin: auto;
|
||||
top: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
}
|
||||
|
||||
img.overflowingVertical {
|
||||
/* If we're overflowing vertically, we need to set margin-top to
|
||||
0. Otherwise we'll end up trying to vertically center, and end
|
||||
up cutting off the top part of the image. */
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
.completeRotation {
|
||||
transition: transform 0.3s ease 0s;
|
||||
}
|
||||
}
|
||||
|
||||
img {
|
||||
image-orientation: from-image;
|
||||
}
|
||||
32
layout/style/TopLevelVideoDocument.css
Normal file
32
layout/style/TopLevelVideoDocument.css
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
/* -*- Mode: C++; 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/. */
|
||||
|
||||
/*
|
||||
This CSS stylesheet defines the rules to be applied to VideoDocuments that
|
||||
are top level (e.g. not iframes).
|
||||
*/
|
||||
|
||||
body {
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
video {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
margin: auto;
|
||||
max-width: 100%;
|
||||
max-height: 100%;
|
||||
-moz-user-select: none;
|
||||
}
|
||||
|
||||
video:focus {
|
||||
outline-width: 0;
|
||||
}
|
||||
343
layout/style/contenteditable.css
Normal file
343
layout/style/contenteditable.css
Normal file
|
|
@ -0,0 +1,343 @@
|
|||
/* -*- Mode: C++; 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/. */
|
||||
|
||||
@namespace url(http://www.w3.org/1999/xhtml); /* set default namespace to HTML */
|
||||
|
||||
*|*::-moz-canvas {
|
||||
cursor: text;
|
||||
}
|
||||
|
||||
*|*:-moz-read-write :-moz-read-only {
|
||||
-moz-user-select: all;
|
||||
}
|
||||
|
||||
*|*:-moz-read-only > :-moz-read-write {
|
||||
/* override the above -moz-user-select: all rule. */
|
||||
-moz-user-select: -moz-text;
|
||||
}
|
||||
|
||||
input:-moz-read-write > .anonymous-div:-moz-read-only,
|
||||
textarea:-moz-read-write > .anonymous-div:-moz-read-only {
|
||||
-moz-user-select: text;
|
||||
}
|
||||
|
||||
/* Use default arrow over objects with size that
|
||||
are selected when clicked on.
|
||||
Override the browser's pointer cursor over links
|
||||
*/
|
||||
|
||||
img:-moz-read-write, img:-moz-read-write[usemap], area:-moz-read-write,
|
||||
object:-moz-read-write, object:-moz-read-write[usemap],
|
||||
applet:-moz-read-write, hr:-moz-read-write, button:-moz-read-write,
|
||||
select:-moz-read-write,
|
||||
a:-moz-read-write:link img, a:-moz-read-write:visited img,
|
||||
a:-moz-read-write:active img, a:-moz-read-write:-moz-only-whitespace[name] {
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
*|*:any-link:-moz-read-write {
|
||||
cursor: text;
|
||||
}
|
||||
|
||||
/* Prevent clicking on links from going to link */
|
||||
a:link:-moz-read-write img, a:visited:-moz-read-write img,
|
||||
a:active:-moz-read-write img {
|
||||
-moz-user-input: none;
|
||||
}
|
||||
|
||||
/* We suppress user/author's prefs for link underline,
|
||||
so we must set explicitly. This isn't good!
|
||||
*/
|
||||
a:link:-moz-read-write {
|
||||
text-decoration: underline -moz-anchor-decoration;
|
||||
color: -moz-hyperlinktext;
|
||||
}
|
||||
|
||||
/* Allow double-clicks on these widgets to open properties dialogs
|
||||
XXX except when the widget has disabled attribute */
|
||||
*|*:-moz-read-write > input:-moz-read-only,
|
||||
*|*:-moz-read-write > button:-moz-read-only,
|
||||
*|*:-moz-read-write > textarea:-moz-read-only {
|
||||
-moz-user-select: all;
|
||||
-moz-user-input: auto !important;
|
||||
-moz-user-focus: none !important;
|
||||
}
|
||||
|
||||
/* XXX Still need a better way of blocking other events to these widgets */
|
||||
select:-moz-read-write,
|
||||
*|*:-moz-read-write > input:disabled,
|
||||
*|*:-moz-read-write > input[type="checkbox"],
|
||||
*|*:-moz-read-write > input[type="radio"],
|
||||
*|*:-moz-read-write > input[type="file"],
|
||||
input[contenteditable="true"]:disabled,
|
||||
input[contenteditable="true"][type="checkbox"],
|
||||
input[contenteditable="true"][type="radio"],
|
||||
input[contenteditable="true"][type="file"] {
|
||||
-moz-user-select: all;
|
||||
-moz-user-input: none !important;
|
||||
-moz-user-focus: none !important;
|
||||
}
|
||||
|
||||
/* emulation of non-standard HTML <marquee> tag */
|
||||
marquee:-moz-read-write {
|
||||
-moz-binding: url('chrome://xbl-marquee/content/xbl-marquee.xml#marquee-horizontal-editable');
|
||||
}
|
||||
|
||||
marquee[direction="up"]:-moz-read-write, marquee[direction="down"]:-moz-read-write {
|
||||
-moz-binding: url('chrome://xbl-marquee/content/xbl-marquee.xml#marquee-vertical-editable');
|
||||
}
|
||||
|
||||
*|*:-moz-read-write > input[type="hidden"],
|
||||
input[contenteditable="true"][type="hidden"] {
|
||||
border: 1px solid black !important;
|
||||
visibility: visible !important;
|
||||
}
|
||||
|
||||
label:-moz-read-write {
|
||||
-moz-user-select: all;
|
||||
}
|
||||
|
||||
*|*::-moz-display-comboboxcontrol-frame {
|
||||
-moz-user-select: text;
|
||||
}
|
||||
|
||||
option:-moz-read-write {
|
||||
-moz-user-select: text;
|
||||
}
|
||||
|
||||
/* the following rules are for Image Resizing */
|
||||
|
||||
span[\_moz_anonclass="mozResizer"] {
|
||||
width: 5px;
|
||||
height: 5px;
|
||||
position: absolute;
|
||||
border: 1px black solid;
|
||||
background-color: white;
|
||||
-moz-user-select: none;
|
||||
z-index: 2147483646; /* max value -1 for this property */
|
||||
}
|
||||
|
||||
/* we can't use :active below */
|
||||
span[\_moz_anonclass="mozResizer"][\_moz_activated],
|
||||
span[\_moz_anonclass="mozResizer"]:hover {
|
||||
background-color: black;
|
||||
}
|
||||
|
||||
span[\_moz_anonclass="mozResizer"].hidden,
|
||||
span[\_moz_anonclass="mozResizingShadow"].hidden,
|
||||
img[\_moz_anonclass="mozResizingShadow"].hidden,
|
||||
span[\_moz_anonclass="mozGrabber"].hidden,
|
||||
span[\_moz_anonclass="mozResizingInfo"].hidden,
|
||||
a[\_moz_anonclass="mozTableRemoveRow"].hidden,
|
||||
a[\_moz_anonclass="mozTableRemoveColumn"].hidden {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
span[\_moz_anonclass="mozResizer"][anonlocation="nw"] {
|
||||
cursor: nw-resize;
|
||||
}
|
||||
span[\_moz_anonclass="mozResizer"][anonlocation="n"] {
|
||||
cursor: n-resize;
|
||||
}
|
||||
span[\_moz_anonclass="mozResizer"][anonlocation="ne"] {
|
||||
cursor: ne-resize;
|
||||
}
|
||||
span[\_moz_anonclass="mozResizer"][anonlocation="w"] {
|
||||
cursor: w-resize;
|
||||
}
|
||||
span[\_moz_anonclass="mozResizer"][anonlocation="e"] {
|
||||
cursor: e-resize;
|
||||
}
|
||||
span[\_moz_anonclass="mozResizer"][anonlocation="sw"] {
|
||||
cursor: sw-resize;
|
||||
}
|
||||
span[\_moz_anonclass="mozResizer"][anonlocation="s"] {
|
||||
cursor: s-resize;
|
||||
}
|
||||
span[\_moz_anonclass="mozResizer"][anonlocation="se"] {
|
||||
cursor: se-resize;
|
||||
}
|
||||
|
||||
span[\_moz_anonclass="mozResizingShadow"],
|
||||
img[\_moz_anonclass="mozResizingShadow"] {
|
||||
outline: thin dashed black;
|
||||
-moz-user-select: none;
|
||||
opacity: 0.5;
|
||||
position: absolute;
|
||||
z-index: 2147483647; /* max value for this property */
|
||||
}
|
||||
|
||||
span[\_moz_anonclass="mozResizingInfo"] {
|
||||
font-family: sans-serif;
|
||||
font-size: x-small;
|
||||
color: black;
|
||||
background-color: #d0d0d0;
|
||||
border: ridge 2px #d0d0d0;
|
||||
padding: 2px;
|
||||
position: absolute;
|
||||
z-index: 2147483647; /* max value for this property */
|
||||
}
|
||||
|
||||
img[\_moz_resizing] {
|
||||
outline: thin solid black;
|
||||
}
|
||||
|
||||
*[\_moz_abspos] {
|
||||
outline: silver ridge 2px;
|
||||
z-index: 2147483645 !important; /* max value -2 for this property */
|
||||
}
|
||||
*[\_moz_abspos="white"] {
|
||||
background-color: white !important;
|
||||
}
|
||||
*[\_moz_abspos="black"] {
|
||||
background-color: black !important;
|
||||
}
|
||||
|
||||
span[\_moz_anonclass="mozGrabber"] {
|
||||
outline: ridge 2px silver;
|
||||
padding: 2px;
|
||||
position: absolute;
|
||||
width: 12px;
|
||||
height: 12px;
|
||||
background-image: url("resource://gre/res/grabber.gif");
|
||||
background-repeat: no-repeat;
|
||||
background-position: center center;
|
||||
-moz-user-select: none;
|
||||
cursor: move;
|
||||
}
|
||||
|
||||
/* INLINE TABLE EDITING */
|
||||
|
||||
a[\_moz_anonclass="mozTableAddColumnBefore"] {
|
||||
position: absolute;
|
||||
z-index: 2147483647; /* max value for this property */
|
||||
text-decoration: none !important;
|
||||
border: none 0px !important;
|
||||
width: 4px;
|
||||
height: 8px;
|
||||
background-image: url("resource://gre/res/table-add-column-before.gif");
|
||||
background-repeat: no-repeat;
|
||||
background-position: center center;
|
||||
-moz-user-select: none;
|
||||
-moz-user-focus: none !important;
|
||||
}
|
||||
|
||||
a[\_moz_anonclass="mozTableAddColumnBefore"]:hover {
|
||||
background-image: url("resource://gre/res/table-add-column-before-hover.gif");
|
||||
}
|
||||
|
||||
a[\_moz_anonclass="mozTableAddColumnBefore"]:active {
|
||||
background-image: url("resource://gre/res/table-add-column-before-active.gif");
|
||||
}
|
||||
|
||||
a[\_moz_anonclass="mozTableAddColumnAfter"] {
|
||||
position: absolute;
|
||||
z-index: 2147483647; /* max value for this property */
|
||||
text-decoration: none !important;
|
||||
border: none 0px !important;
|
||||
width: 4px;
|
||||
height: 8px;
|
||||
background-image: url("resource://gre/res/table-add-column-after.gif");
|
||||
background-repeat: no-repeat;
|
||||
background-position: center center;
|
||||
-moz-user-select: none;
|
||||
-moz-user-focus: none !important;
|
||||
}
|
||||
|
||||
a[\_moz_anonclass="mozTableAddColumnAfter"]:hover {
|
||||
background-image: url("resource://gre/res/table-add-column-after-hover.gif");
|
||||
}
|
||||
|
||||
a[\_moz_anonclass="mozTableAddColumnAfter"]:active {
|
||||
background-image: url("resource://gre/res/table-add-column-after-active.gif");
|
||||
}
|
||||
|
||||
a[\_moz_anonclass="mozTableRemoveColumn"] {
|
||||
position: absolute;
|
||||
z-index: 2147483647; /* max value for this property */
|
||||
text-decoration: none !important;
|
||||
border: none 0px !important;
|
||||
width: 8px;
|
||||
height: 8px;
|
||||
background-image: url("resource://gre/res/table-remove-column.gif");
|
||||
background-repeat: no-repeat;
|
||||
background-position: center center;
|
||||
-moz-user-select: none;
|
||||
-moz-user-focus: none !important;
|
||||
}
|
||||
|
||||
a[\_moz_anonclass="mozTableRemoveColumn"]:hover {
|
||||
background-image: url("resource://gre/res/table-remove-column-hover.gif");
|
||||
}
|
||||
|
||||
a[\_moz_anonclass="mozTableRemoveColumn"]:active {
|
||||
background-image: url("resource://gre/res/table-remove-column-active.gif");
|
||||
}
|
||||
|
||||
a[\_moz_anonclass="mozTableAddRowBefore"] {
|
||||
position: absolute;
|
||||
z-index: 2147483647; /* max value for this property */
|
||||
text-decoration: none !important;
|
||||
border: none 0px !important;
|
||||
width: 8px;
|
||||
height: 4px;
|
||||
background-image: url("resource://gre/res/table-add-row-before.gif");
|
||||
background-repeat: no-repeat;
|
||||
background-position: center center;
|
||||
-moz-user-select: none;
|
||||
-moz-user-focus: none !important;
|
||||
}
|
||||
|
||||
a[\_moz_anonclass="mozTableAddRowBefore"]:hover {
|
||||
background-image: url("resource://gre/res/table-add-row-before-hover.gif");
|
||||
}
|
||||
|
||||
a[\_moz_anonclass="mozTableAddRowBefore"]:active {
|
||||
background-image: url("resource://gre/res/table-add-row-before-active.gif");
|
||||
}
|
||||
|
||||
a[\_moz_anonclass="mozTableAddRowAfter"] {
|
||||
position: absolute;
|
||||
z-index: 2147483647; /* max value for this property */
|
||||
text-decoration: none !important;
|
||||
border: none 0px !important;
|
||||
width: 8px;
|
||||
height: 4px;
|
||||
background-image: url("resource://gre/res/table-add-row-after.gif");
|
||||
background-repeat: no-repeat;
|
||||
background-position: center center;
|
||||
-moz-user-select: none;
|
||||
-moz-user-focus: none !important;
|
||||
}
|
||||
|
||||
a[\_moz_anonclass="mozTableAddRowAfter"]:hover {
|
||||
background-image: url("resource://gre/res/table-add-row-after-hover.gif");
|
||||
}
|
||||
|
||||
a[\_moz_anonclass="mozTableAddRowAfter"]:active {
|
||||
background-image: url("resource://gre/res/table-add-row-after-active.gif");
|
||||
}
|
||||
|
||||
a[\_moz_anonclass="mozTableRemoveRow"] {
|
||||
position: absolute;
|
||||
z-index: 2147483647; /* max value for this property */
|
||||
text-decoration: none !important;
|
||||
border: none 0px !important;
|
||||
width: 8px;
|
||||
height: 8px;
|
||||
background-image: url("resource://gre/res/table-remove-row.gif");
|
||||
background-repeat: no-repeat;
|
||||
background-position: center center;
|
||||
-moz-user-select: none;
|
||||
-moz-user-focus: none !important;
|
||||
}
|
||||
|
||||
a[\_moz_anonclass="mozTableRemoveRow"]:hover {
|
||||
background-image: url("resource://gre/res/table-remove-row-hover.gif");
|
||||
}
|
||||
|
||||
a[\_moz_anonclass="mozTableRemoveRow"]:active {
|
||||
background-image: url("resource://gre/res/table-remove-row-active.gif");
|
||||
}
|
||||
84
layout/style/crashtests/1017798-1.css
Normal file
84
layout/style/crashtests/1017798-1.css
Normal file
|
|
@ -0,0 +1,84 @@
|
|||
/* ----------------------------------
|
||||
* SWITCHES
|
||||
* ---------------------------------- */
|
||||
|
||||
label.pack-switch {
|
||||
display: inline-block;
|
||||
vertical-align: middle;
|
||||
width: 100%;
|
||||
height: 5rem;
|
||||
position: relative;
|
||||
background: none;
|
||||
}
|
||||
|
||||
label.pack-switch span {
|
||||
float: left;
|
||||
font-size: 1.8rem;
|
||||
color: #333;
|
||||
padding: 1rem 0 0;
|
||||
height: 6rem;
|
||||
line-height: 3rem;
|
||||
box-sizing: border-box;
|
||||
display: block;
|
||||
}
|
||||
|
||||
label.pack-switch input {
|
||||
margin: 0;
|
||||
opacity: 0;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
}
|
||||
|
||||
label.pack-switch input:checked ~ span:after {
|
||||
background-position: center bottom;
|
||||
}
|
||||
|
||||
/* ----------------------------------
|
||||
* ON/OFF SWITCHES
|
||||
* ---------------------------------- */
|
||||
|
||||
label.pack-switch input ~ span:after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
right: 0;
|
||||
top: 50%;
|
||||
width: 6rem;
|
||||
margin: -1.4rem 0 0;
|
||||
height: 2.7rem;
|
||||
border-radius: 1.35rem;
|
||||
overflow: hidden;
|
||||
background: #e6e6e6 url(images/background_off.png) no-repeat -3.2rem 0 / 9.2rem 2.7rem;
|
||||
transition: background 0.2s ease;
|
||||
}
|
||||
|
||||
/* switch: 'ON' state */
|
||||
label.pack-switch input:checked ~ span:after {
|
||||
background: #e6e6e6 url(images/background.png) no-repeat 0 0 / 9.2rem 2.7rem;
|
||||
}
|
||||
|
||||
/* switch: disabled state */
|
||||
label.pack-switch input:disabled ~ span:after {
|
||||
opacity: 0.4;
|
||||
}
|
||||
|
||||
label.pack-switch input.uninit ~ span:after {
|
||||
transition: none;
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
* Right-To-Left tweaks
|
||||
*/
|
||||
html[dir="rtl"] label.pack-switch input {
|
||||
left: auto;
|
||||
right: 0;
|
||||
}
|
||||
|
||||
html[dir="rtl"] label.pack-switch input ~ span:after {
|
||||
left: 0;
|
||||
right: auto;
|
||||
}
|
||||
|
||||
html[dir="rtl"] label.pack-switch input ~ span:after {
|
||||
background-position: 0;
|
||||
}
|
||||
124
layout/style/crashtests/1017798-1.html
Normal file
124
layout/style/crashtests/1017798-1.html
Normal file
|
|
@ -0,0 +1,124 @@
|
|||
|
||||
<!DOCTYPE html>
|
||||
<!--
|
||||
This is a slightly minimised, modified and self-contained version of
|
||||
gaia_switch/examples/index.html from the Gaia repository.
|
||||
-->
|
||||
<script>
|
||||
'use strict';
|
||||
|
||||
(function(exports) {
|
||||
|
||||
/**
|
||||
* ComponentUtils is a utility which allows us to use web components earlier
|
||||
* than we should be able to by polyfilling and fixing platform deficiencies.
|
||||
*/
|
||||
var ComponentUtils = {
|
||||
|
||||
/**
|
||||
* Injects a style.css into both the shadow root and outside the shadow
|
||||
* root so we can style projected content. Bug 992249.
|
||||
*/
|
||||
style: function(baseUrl) {
|
||||
var style = document.createElement('style');
|
||||
style.setAttribute('scoped', '');
|
||||
var url = baseUrl + '1017798-1.css';
|
||||
style.innerHTML = '@import url(' + url + ');';
|
||||
|
||||
this.appendChild(style);
|
||||
|
||||
if (!this.shadowRoot) {
|
||||
return;
|
||||
}
|
||||
|
||||
// The setTimeout is necessary to avoid missing @import styles
|
||||
// when appending two stylesheets. Bug 1003294.
|
||||
setTimeout(function nextTick() {
|
||||
this.shadowRoot.appendChild(style.cloneNode(true));
|
||||
}.bind(this));
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
exports.ComponentUtils = ComponentUtils;
|
||||
|
||||
}(window));
|
||||
</script>
|
||||
<script>
|
||||
'use strict';
|
||||
/* global ComponentUtils */
|
||||
|
||||
window.GaiaSwitch = (function(win) {
|
||||
// Extend from the HTMLElement prototype
|
||||
var proto = Object.create(HTMLElement.prototype);
|
||||
|
||||
proto.createdCallback = function() {
|
||||
var shadow = this.createShadowRoot();
|
||||
this._template = template.content.cloneNode(true);
|
||||
this._input = this._template.querySelector('input[type="checkbox"]');
|
||||
|
||||
var checked = this.getAttribute('checked');
|
||||
if (checked !== null) {
|
||||
this._input.checked = true;
|
||||
}
|
||||
|
||||
shadow.appendChild(this._template);
|
||||
|
||||
ComponentUtils.style.call(this, '');
|
||||
};
|
||||
|
||||
/**
|
||||
* Proxy the checked property to the input element.
|
||||
*/
|
||||
Object.defineProperty( proto, 'checked', {
|
||||
get: function() {
|
||||
return this._input.checked;
|
||||
},
|
||||
set: function(value) {
|
||||
this._input.checked = value;
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Proxy the name property to the input element.
|
||||
*/
|
||||
Object.defineProperty( proto, 'name', {
|
||||
get: function() {
|
||||
return this.getAttribute('name');
|
||||
},
|
||||
set: function(value) {
|
||||
this.setAttribute('name', value);
|
||||
}
|
||||
});
|
||||
|
||||
// HACK: Create a <template> in memory at runtime.
|
||||
// When the custom-element is created we clone
|
||||
// this template and inject into the shadow-root.
|
||||
// Prior to this we would have had to copy/paste
|
||||
// the template into the <head> of every app that
|
||||
// wanted to use <gaia-switch>, this would make
|
||||
// markup changes complicated, and could lead to
|
||||
// things getting out of sync. This is a short-term
|
||||
// hack until we can import entire custom-elements
|
||||
// using HTML Imports (bug 877072).
|
||||
var template = document.createElement('template');
|
||||
template.innerHTML = '<label id="switch-label" class="pack-switch">' +
|
||||
'<input type="checkbox">' +
|
||||
'<span><content select="label"></content></span>' +
|
||||
'</label>';
|
||||
|
||||
// Register and return the constructor
|
||||
return document.registerElement('gaia-switch', { prototype: proto });
|
||||
})(window);
|
||||
</script>
|
||||
<body>
|
||||
<section>
|
||||
<gaia-switch>
|
||||
<label>With a label</label>
|
||||
</gaia-switch>
|
||||
</section>
|
||||
<script>
|
||||
window.onload = function() {
|
||||
document.querySelector('gaia-switch').checked = true;
|
||||
};
|
||||
</script>
|
||||
18
layout/style/crashtests/1028514-1.html
Normal file
18
layout/style/crashtests/1028514-1.html
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<script>
|
||||
|
||||
function boom()
|
||||
{
|
||||
document.documentElement.style.animation = "137438953471s bounce";
|
||||
document.documentElement.offsetHeight;
|
||||
document.documentElement.style.animationIterationCount = "infinite";
|
||||
}
|
||||
|
||||
</script>
|
||||
</head>
|
||||
|
||||
<body onload="boom();"></body>
|
||||
</html>
|
||||
33
layout/style/crashtests/105619-1.html
Normal file
33
layout/style/crashtests/105619-1.html
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
|
||||
<html>
|
||||
<head>
|
||||
<title>International Herald Tribune</title>
|
||||
|
||||
<script type="text/javascript">
|
||||
|
||||
function displayFix() {
|
||||
document.getElementById("bodyNode").style.display = "block";
|
||||
}
|
||||
|
||||
</script>
|
||||
<style type="text/css">
|
||||
|
||||
#clippingsContainer {overflow:auto;}
|
||||
#menuSearch {position:absolute;}
|
||||
|
||||
</style>
|
||||
|
||||
</head>
|
||||
|
||||
<body id="bodyNode" onload="displayFix()">
|
||||
<div>
|
||||
<div id="menuSearch"><input type="text"></div>
|
||||
<div id="clippingsContainer"></div>
|
||||
</div>
|
||||
|
||||
<table>
|
||||
<tr><td></td><td></td><td></td></tr>
|
||||
<tr><td></td><td></td><td></td></tr>
|
||||
</table>
|
||||
|
||||
</body></html>
|
||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue