12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013 |
- /* -*- 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/. */
- // Main header first:
- #include "nsSVGEffects.h"
- // Keep others in (case-insensitive) order:
- #include "mozilla/RestyleManagerHandle.h"
- #include "mozilla/RestyleManagerHandleInlines.h"
- #include "nsCSSFrameConstructor.h"
- #include "nsISupportsImpl.h"
- #include "nsSVGClipPathFrame.h"
- #include "nsSVGPaintServerFrame.h"
- #include "nsSVGPathGeometryElement.h"
- #include "nsSVGFilterFrame.h"
- #include "nsSVGMaskFrame.h"
- #include "nsIReflowCallback.h"
- #include "nsCycleCollectionParticipant.h"
- #include "SVGUseElement.h"
- using namespace mozilla;
- using namespace mozilla::dom;
- void
- nsSVGRenderingObserver::StartListening()
- {
- Element* target = GetTarget();
- if (target) {
- target->AddMutationObserver(this);
- }
- }
- void
- nsSVGRenderingObserver::StopListening()
- {
- Element* target = GetTarget();
- if (target) {
- target->RemoveMutationObserver(this);
- if (mInObserverList) {
- nsSVGEffects::RemoveRenderingObserver(target, this);
- mInObserverList = false;
- }
- }
- NS_ASSERTION(!mInObserverList, "still in an observer list?");
- }
- static nsSVGRenderingObserverList *
- GetObserverList(Element *aElement)
- {
- return static_cast<nsSVGRenderingObserverList*>
- (aElement->GetProperty(nsGkAtoms::renderingobserverlist));
- }
- Element*
- nsSVGRenderingObserver::GetReferencedElement()
- {
- Element* target = GetTarget();
- #ifdef DEBUG
- if (target) {
- nsSVGRenderingObserverList *observerList = GetObserverList(target);
- bool inObserverList = observerList && observerList->Contains(this);
- NS_ASSERTION(inObserverList == mInObserverList, "failed to track whether we're in our referenced element's observer list!");
- } else {
- NS_ASSERTION(!mInObserverList, "In whose observer list are we, then?");
- }
- #endif
- if (target && !mInObserverList) {
- nsSVGEffects::AddRenderingObserver(target, this);
- mInObserverList = true;
- }
- return target;
- }
- nsIFrame*
- nsSVGRenderingObserver::GetReferencedFrame()
- {
- Element* referencedElement = GetReferencedElement();
- return referencedElement ? referencedElement->GetPrimaryFrame() : nullptr;
- }
- nsIFrame*
- nsSVGRenderingObserver::GetReferencedFrame(nsIAtom* aFrameType, bool* aOK)
- {
- nsIFrame* frame = GetReferencedFrame();
- if (frame) {
- if (frame->GetType() == aFrameType)
- return frame;
- if (aOK) {
- *aOK = false;
- }
- }
- return nullptr;
- }
- void
- nsSVGRenderingObserver::InvalidateViaReferencedElement()
- {
- mInObserverList = false;
- DoUpdate();
- }
- void
- nsSVGRenderingObserver::NotifyEvictedFromRenderingObserverList()
- {
- mInObserverList = false; // We've been removed from rendering-obs. list.
- StopListening(); // Remove ourselves from mutation-obs. list.
- }
- void
- nsSVGRenderingObserver::AttributeChanged(nsIDocument* aDocument,
- dom::Element* aElement,
- int32_t aNameSpaceID,
- nsIAtom* aAttribute,
- int32_t aModType,
- const nsAttrValue* aOldValue)
- {
- // An attribute belonging to the element that we are observing *or one of its
- // descendants* has changed.
- //
- // In the case of observing a gradient element, say, we want to know if any
- // of its 'stop' element children change, but we don't actually want to do
- // anything for changes to SMIL element children, for example. Maybe it's not
- // worth having logic to optimize for that, but in most cases it could be a
- // small check?
- //
- // XXXjwatt: do we really want to blindly break the link between our
- // observers and ourselves for all attribute changes? For non-ID changes
- // surely that is unnecessary.
- DoUpdate();
- }
- void
- nsSVGRenderingObserver::ContentAppended(nsIDocument* aDocument,
- nsIContent* aContainer,
- nsIContent* aFirstNewContent,
- int32_t /* unused */)
- {
- DoUpdate();
- }
- void
- nsSVGRenderingObserver::ContentInserted(nsIDocument* aDocument,
- nsIContent* aContainer,
- nsIContent* aChild,
- int32_t /* unused */)
- {
- DoUpdate();
- }
- void
- nsSVGRenderingObserver::ContentRemoved(nsIDocument* aDocument,
- nsIContent* aContainer,
- nsIContent* aChild,
- int32_t aIndexInContainer,
- nsIContent* aPreviousSibling)
- {
- DoUpdate();
- }
- /**
- * Note that in the current setup there are two separate observer lists.
- *
- * In nsSVGIDRenderingObserver's ctor, the new object adds itself to the
- * mutation observer list maintained by the referenced element. In this way the
- * nsSVGIDRenderingObserver is notified if there are any attribute or content
- * tree changes to the element or any of its *descendants*.
- *
- * In nsSVGIDRenderingObserver::GetReferencedElement() the
- * nsSVGIDRenderingObserver object also adds itself to an
- * nsSVGRenderingObserverList object belonging to the referenced
- * element.
- *
- * XXX: it would be nice to have a clear and concise executive summary of the
- * benefits/necessity of maintaining a second observer list.
- */
- nsSVGIDRenderingObserver::nsSVGIDRenderingObserver(nsIURI* aURI,
- nsIContent* aObservingContent,
- bool aReferenceImage)
- : mElement(this)
- {
- // Start watching the target element
- mElement.Reset(aObservingContent, aURI, true, aReferenceImage);
- StartListening();
- }
- nsSVGIDRenderingObserver::~nsSVGIDRenderingObserver()
- {
- StopListening();
- }
- void
- nsSVGIDRenderingObserver::DoUpdate()
- {
- if (mElement.get() && mInObserverList) {
- nsSVGEffects::RemoveRenderingObserver(mElement.get(), this);
- mInObserverList = false;
- }
- }
- void
- nsSVGFrameReferenceFromProperty::Detach()
- {
- mFrame = nullptr;
- mFramePresShell = nullptr;
- }
- nsIFrame*
- nsSVGFrameReferenceFromProperty::Get()
- {
- if (mFramePresShell && mFramePresShell->IsDestroying()) {
- // mFrame is no longer valid.
- Detach();
- }
- return mFrame;
- }
- NS_IMPL_ISUPPORTS(nsSVGRenderingObserverProperty, nsIMutationObserver)
- void
- nsSVGRenderingObserverProperty::DoUpdate()
- {
- nsSVGIDRenderingObserver::DoUpdate();
- nsIFrame* frame = mFrameReference.Get();
- if (frame && frame->IsFrameOfType(nsIFrame::eSVG)) {
- // Changes should propagate out to things that might be observing
- // the referencing frame or its ancestors.
- nsLayoutUtils::PostRestyleEvent(
- frame->GetContent()->AsElement(), nsRestyleHint(0),
- nsChangeHint_InvalidateRenderingObservers);
- }
- }
- NS_IMPL_CYCLE_COLLECTING_ADDREF(nsSVGFilterReference)
- NS_IMPL_CYCLE_COLLECTING_RELEASE(nsSVGFilterReference)
- NS_IMPL_CYCLE_COLLECTION_CLASS(nsSVGFilterReference)
- NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsSVGFilterReference)
- NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mElement)
- NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
- NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsSVGFilterReference)
- tmp->StopListening();
- NS_IMPL_CYCLE_COLLECTION_UNLINK(mElement);
- NS_IMPL_CYCLE_COLLECTION_UNLINK_END
- NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsSVGFilterReference)
- NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsSVGIDRenderingObserver)
- NS_INTERFACE_MAP_ENTRY(nsIMutationObserver)
- NS_INTERFACE_MAP_ENTRY(nsISVGFilterReference)
- NS_INTERFACE_MAP_END
- nsSVGFilterFrame *
- nsSVGFilterReference::GetFilterFrame()
- {
- return static_cast<nsSVGFilterFrame *>
- (GetReferencedFrame(nsGkAtoms::svgFilterFrame, nullptr));
- }
- void
- nsSVGFilterReference::DoUpdate()
- {
- nsSVGIDRenderingObserver::DoUpdate();
- if (mFilterChainObserver) {
- mFilterChainObserver->Invalidate();
- }
- }
- NS_IMPL_CYCLE_COLLECTING_ADDREF(nsSVGFilterChainObserver)
- NS_IMPL_CYCLE_COLLECTING_RELEASE(nsSVGFilterChainObserver)
- NS_IMPL_CYCLE_COLLECTION_CLASS(nsSVGFilterChainObserver)
- NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsSVGFilterChainObserver)
- NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mReferences)
- NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
- NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsSVGFilterChainObserver)
- tmp->DetachReferences();
- NS_IMPL_CYCLE_COLLECTION_UNLINK(mReferences);
- NS_IMPL_CYCLE_COLLECTION_UNLINK_END
- NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsSVGFilterChainObserver)
- NS_INTERFACE_MAP_ENTRY(nsISupports)
- NS_INTERFACE_MAP_END
- nsSVGFilterChainObserver::nsSVGFilterChainObserver(const nsTArray<nsStyleFilter>& aFilters,
- nsIContent* aFilteredElement,
- nsIFrame* aFilteredFrame)
- {
- for (uint32_t i = 0; i < aFilters.Length(); i++) {
- if (aFilters[i].GetType() != NS_STYLE_FILTER_URL)
- continue;
- // aFilteredFrame can be null if this filter belongs to a
- // CanvasRenderingContext2D.
- nsCOMPtr<nsIURI> filterURL = aFilteredFrame
- ? nsSVGEffects::GetFilterURI(aFilteredFrame, i)
- : aFilters[i].GetURL()->ResolveLocalRef(aFilteredElement);
- RefPtr<nsSVGFilterReference> reference =
- new nsSVGFilterReference(filterURL, aFilteredElement, this);
- mReferences.AppendElement(reference);
- }
- }
- nsSVGFilterChainObserver::~nsSVGFilterChainObserver()
- {
- DetachReferences();
- }
- bool
- nsSVGFilterChainObserver::ReferencesValidResources()
- {
- for (uint32_t i = 0; i < mReferences.Length(); i++) {
- if (!mReferences[i]->ReferencesValidResource())
- return false;
- }
- return true;
- }
- bool
- nsSVGFilterChainObserver::IsInObserverLists() const
- {
- for (uint32_t i = 0; i < mReferences.Length(); i++) {
- if (!mReferences[i]->IsInObserverList())
- return false;
- }
- return true;
- }
- void
- nsSVGFilterProperty::DoUpdate()
- {
- nsIFrame* frame = mFrameReference.Get();
- if (!frame)
- return;
- // Repaint asynchronously in case the filter frame is being torn down
- nsChangeHint changeHint =
- nsChangeHint(nsChangeHint_RepaintFrame);
- if (frame && frame->IsFrameOfType(nsIFrame::eSVG)) {
- // Changes should propagate out to things that might be observing
- // the referencing frame or its ancestors.
- changeHint |= nsChangeHint_InvalidateRenderingObservers;
- }
- // Don't need to request UpdateOverflow if we're being reflowed.
- if (!(frame->GetStateBits() & NS_FRAME_IN_REFLOW)) {
- changeHint |= nsChangeHint_UpdateOverflow;
- }
- frame->PresContext()->RestyleManager()->PostRestyleEvent(
- frame->GetContent()->AsElement(), nsRestyleHint(0), changeHint);
- }
- void
- nsSVGMarkerProperty::DoUpdate()
- {
- nsSVGRenderingObserverProperty::DoUpdate();
- nsIFrame* frame = mFrameReference.Get();
- if (!frame)
- return;
- NS_ASSERTION(frame->IsFrameOfType(nsIFrame::eSVG), "SVG frame expected");
- // Repaint asynchronously in case the marker frame is being torn down
- nsChangeHint changeHint =
- nsChangeHint(nsChangeHint_RepaintFrame);
- // Don't need to request ReflowFrame if we're being reflowed.
- if (!(frame->GetStateBits() & NS_FRAME_IN_REFLOW)) {
- changeHint |= nsChangeHint_InvalidateRenderingObservers;
- // XXXjwatt: We need to unify SVG into standard reflow so we can just use
- // nsChangeHint_NeedReflow | nsChangeHint_NeedDirtyReflow here.
- // XXXSDL KILL THIS!!!
- nsSVGUtils::ScheduleReflowSVG(frame);
- }
- frame->PresContext()->RestyleManager()->PostRestyleEvent(
- frame->GetContent()->AsElement(), nsRestyleHint(0), changeHint);
- }
- NS_IMPL_ISUPPORTS(nsSVGMaskProperty, nsISupports)
- nsSVGMaskProperty::nsSVGMaskProperty(nsIFrame* aFrame)
- {
- const nsStyleSVGReset *svgReset = aFrame->StyleSVGReset();
- for (uint32_t i = 0; i < svgReset->mMask.mImageCount; i++) {
- nsCOMPtr<nsIURI> maskUri = nsSVGEffects::GetMaskURI(aFrame, i);
- nsSVGPaintingProperty* prop = new nsSVGPaintingProperty(maskUri, aFrame,
- false);
- mProperties.AppendElement(prop);
- }
- }
- bool
- nsSVGTextPathProperty::TargetIsValid()
- {
- Element* target = GetTarget();
- return target && target->IsSVGElement(nsGkAtoms::path);
- }
- void
- nsSVGTextPathProperty::DoUpdate()
- {
- nsSVGRenderingObserverProperty::DoUpdate();
- nsIFrame* frame = mFrameReference.Get();
- if (!frame)
- return;
- NS_ASSERTION(frame->IsFrameOfType(nsIFrame::eSVG) || frame->IsSVGText(),
- "SVG frame expected");
- // Avoid getting into an infinite loop of reflows if the <textPath> is
- // pointing to one of its ancestors. TargetIsValid returns true iff
- // the target element is a <path> element, and we would not have this
- // nsSVGTextPathProperty if this <textPath> were a descendant of the
- // target <path>.
- //
- // Note that we still have to post the restyle event when we
- // change from being valid to invalid, so that mPositions on the
- // SVGTextFrame gets updated, skipping the <textPath>, ensuring
- // that nothing gets painted for that element.
- bool nowValid = TargetIsValid();
- if (!mValid && !nowValid) {
- // Just return if we were previously invalid, and are still invalid.
- return;
- }
- mValid = nowValid;
- // Repaint asynchronously in case the path frame is being torn down
- nsChangeHint changeHint =
- nsChangeHint(nsChangeHint_RepaintFrame | nsChangeHint_UpdateTextPath);
- frame->PresContext()->RestyleManager()->PostRestyleEvent(
- frame->GetContent()->AsElement(), nsRestyleHint(0), changeHint);
- }
- static void
- InvalidateAllContinuations(nsIFrame* aFrame)
- {
- for (nsIFrame* f = aFrame; f;
- f = nsLayoutUtils::GetNextContinuationOrIBSplitSibling(f)) {
- f->InvalidateFrame();
- }
- }
- void
- nsSVGPaintingProperty::DoUpdate()
- {
- nsSVGRenderingObserverProperty::DoUpdate();
- nsIFrame* frame = mFrameReference.Get();
- if (!frame)
- return;
- if (frame->GetStateBits() & NS_FRAME_SVG_LAYOUT) {
- nsLayoutUtils::PostRestyleEvent(
- frame->GetContent()->AsElement(), nsRestyleHint(0),
- nsChangeHint_InvalidateRenderingObservers);
- frame->InvalidateFrameSubtree();
- } else {
- InvalidateAllContinuations(frame);
- }
- }
- static nsSVGFilterProperty*
- GetOrCreateFilterProperty(nsIFrame* aFrame)
- {
- const nsStyleEffects* effects = aFrame->StyleEffects();
- if (!effects->HasFilters())
- return nullptr;
- nsSVGFilterProperty *prop =
- aFrame->GetProperty(nsSVGEffects::FilterProperty());
- if (prop)
- return prop;
- prop = new nsSVGFilterProperty(effects->mFilters, aFrame);
- NS_ADDREF(prop);
- aFrame->SetProperty(nsSVGEffects::FilterProperty(), prop);
- return prop;
- }
- static nsSVGMaskProperty*
- GetOrCreateMaskProperty(nsIFrame* aFrame)
- {
- nsSVGMaskProperty *prop = aFrame->GetProperty(nsSVGEffects::MaskProperty());
- if (prop)
- return prop;
- prop = new nsSVGMaskProperty(aFrame);
- NS_ADDREF(prop);
- aFrame->SetProperty(nsSVGEffects::MaskProperty(), prop);
- return prop;
- }
- template<class T>
- static T*
- GetEffectProperty(nsIURI* aURI, nsIFrame* aFrame,
- const mozilla::FramePropertyDescriptor<T>* aProperty)
- {
- if (!aURI)
- return nullptr;
- T* prop = aFrame->GetProperty(aProperty);
- if (prop)
- return prop;
- prop = new T(aURI, aFrame, false);
- NS_ADDREF(prop);
- aFrame->SetProperty(aProperty, prop);
- return prop;
- }
- nsSVGMarkerProperty*
- nsSVGEffects::GetMarkerProperty(nsIURI* aURI, nsIFrame* aFrame,
- const mozilla::FramePropertyDescriptor<nsSVGMarkerProperty>* aProperty)
- {
- MOZ_ASSERT(aFrame->GetType() == nsGkAtoms::svgPathGeometryFrame &&
- static_cast<nsSVGPathGeometryElement*>(aFrame->GetContent())->IsMarkable(),
- "Bad frame");
- return GetEffectProperty(aURI, aFrame, aProperty);
- }
- nsSVGTextPathProperty*
- nsSVGEffects::GetTextPathProperty(nsIURI* aURI, nsIFrame* aFrame,
- const mozilla::FramePropertyDescriptor<nsSVGTextPathProperty>* aProperty)
- {
- return GetEffectProperty(aURI, aFrame, aProperty);
- }
- nsSVGPaintingProperty*
- nsSVGEffects::GetPaintingProperty(nsIURI* aURI, nsIFrame* aFrame,
- const mozilla::FramePropertyDescriptor<nsSVGPaintingProperty>* aProperty)
- {
- return GetEffectProperty(aURI, aFrame, aProperty);
- }
- nsSVGPaintingProperty*
- nsSVGEffects::GetPaintingPropertyForURI(nsIURI* aURI, nsIFrame* aFrame,
- URIObserverHashtablePropertyDescriptor aProperty)
- {
- if (!aURI)
- return nullptr;
- nsSVGEffects::URIObserverHashtable *hashtable =
- aFrame->GetProperty(aProperty);
- if (!hashtable) {
- hashtable = new nsSVGEffects::URIObserverHashtable();
- aFrame->SetProperty(aProperty, hashtable);
- }
- nsSVGPaintingProperty* prop =
- static_cast<nsSVGPaintingProperty*>(hashtable->GetWeak(aURI));
- if (!prop) {
- bool watchImage = aProperty == nsSVGEffects::BackgroundImageProperty();
- prop = new nsSVGPaintingProperty(aURI, aFrame, watchImage);
- hashtable->Put(aURI, prop);
- }
- return prop;
- }
- nsSVGEffects::EffectProperties
- nsSVGEffects::GetEffectProperties(nsIFrame* aFrame)
- {
- NS_ASSERTION(!aFrame->GetPrevContinuation(), "aFrame should be first continuation");
- EffectProperties result;
- const nsStyleSVGReset *style = aFrame->StyleSVGReset();
- result.mFilter = GetOrCreateFilterProperty(aFrame);
- if (style->mClipPath.GetType() == StyleShapeSourceType::URL) {
- nsCOMPtr<nsIURI> pathURI = nsSVGEffects::GetClipPathURI(aFrame);
- result.mClipPath =
- GetPaintingProperty(pathURI, aFrame, ClipPathProperty());
- } else {
- result.mClipPath = nullptr;
- }
- MOZ_ASSERT(style->mMask.mImageCount > 0);
- result.mMask = style->mMask.HasLayerWithImage()
- ? GetOrCreateMaskProperty(aFrame) : nullptr;
- return result;
- }
- nsSVGPaintServerFrame *
- nsSVGEffects::GetPaintServer(nsIFrame* aTargetFrame,
- nsStyleSVGPaint nsStyleSVG::* aPaint,
- PaintingPropertyDescriptor aType)
- {
- const nsStyleSVG* svgStyle = aTargetFrame->StyleSVG();
- if ((svgStyle->*aPaint).Type() != eStyleSVGPaintType_Server)
- return nullptr;
- // If we're looking at a frame within SVG text, then we need to look up
- // to find the right frame to get the painting property off. We should at
- // least look up past a text frame, and if the text frame's parent is the
- // anonymous block frame, then we look up to its parent (the SVGTextFrame).
- nsIFrame* frame = aTargetFrame;
- if (frame->GetContent()->IsNodeOfType(nsINode::eTEXT)) {
- frame = frame->GetParent();
- nsIFrame* grandparent = frame->GetParent();
- if (grandparent && grandparent->GetType() == nsGkAtoms::svgTextFrame) {
- frame = grandparent;
- }
- }
- nsCOMPtr<nsIURI> paintServerURL = nsSVGEffects::GetPaintURI(frame, aPaint);
- nsSVGPaintingProperty *property =
- nsSVGEffects::GetPaintingProperty(paintServerURL, frame, aType);
- if (!property)
- return nullptr;
- nsIFrame *result = property->GetReferencedFrame();
- if (!result)
- return nullptr;
- nsIAtom *type = result->GetType();
- if (type != nsGkAtoms::svgLinearGradientFrame &&
- type != nsGkAtoms::svgRadialGradientFrame &&
- type != nsGkAtoms::svgPatternFrame)
- return nullptr;
- return static_cast<nsSVGPaintServerFrame*>(result);
- }
- nsSVGClipPathFrame *
- nsSVGEffects::EffectProperties::GetClipPathFrame(bool* aOK)
- {
- if (!mClipPath)
- return nullptr;
- nsSVGClipPathFrame *frame = static_cast<nsSVGClipPathFrame *>
- (mClipPath->GetReferencedFrame(nsGkAtoms::svgClipPathFrame, aOK));
- if (frame && aOK && *aOK) {
- *aOK = frame->IsValid();
- }
- return frame;
- }
- nsSVGMaskFrame *
- nsSVGEffects::EffectProperties::GetFirstMaskFrame(bool* aOK)
- {
- if (!mMask) {
- return nullptr;
- }
- const nsTArray<RefPtr<nsSVGPaintingProperty>>& props = mMask->GetProps();
- if (props.IsEmpty()) {
- return nullptr;
- }
- return static_cast<nsSVGMaskFrame *>
- (props[0]->GetReferencedFrame(nsGkAtoms::svgMaskFrame, aOK));
- }
- nsTArray<nsSVGMaskFrame *>
- nsSVGEffects::EffectProperties::GetMaskFrames()
- {
- nsTArray<nsSVGMaskFrame *> result;
- if (!mMask)
- return result;
- bool ok = false;
- const nsTArray<RefPtr<nsSVGPaintingProperty>>& props = mMask->GetProps();
- for (size_t i = 0; i < props.Length(); i++) {
- nsSVGMaskFrame* maskFrame =
- static_cast<nsSVGMaskFrame *>(props[i]->GetReferencedFrame(
- nsGkAtoms::svgMaskFrame, &ok));
- result.AppendElement(maskFrame);
- }
- return result;
- }
- void
- nsSVGEffects::UpdateEffects(nsIFrame* aFrame)
- {
- NS_ASSERTION(aFrame->GetContent()->IsElement(),
- "aFrame's content should be an element");
- aFrame->DeleteProperty(FilterProperty());
- aFrame->DeleteProperty(MaskProperty());
- aFrame->DeleteProperty(ClipPathProperty());
- aFrame->DeleteProperty(MarkerBeginProperty());
- aFrame->DeleteProperty(MarkerMiddleProperty());
- aFrame->DeleteProperty(MarkerEndProperty());
- aFrame->DeleteProperty(FillProperty());
- aFrame->DeleteProperty(StrokeProperty());
- aFrame->DeleteProperty(BackgroundImageProperty());
- // Ensure that the filter is repainted correctly
- // We can't do that in DoUpdate as the referenced frame may not be valid
- GetOrCreateFilterProperty(aFrame);
- if (aFrame->GetType() == nsGkAtoms::svgPathGeometryFrame &&
- static_cast<nsSVGPathGeometryElement*>(aFrame->GetContent())->IsMarkable()) {
- // Set marker properties here to avoid reference loops
- nsCOMPtr<nsIURI> markerURL =
- GetMarkerURI(aFrame, &nsStyleSVG::mMarkerStart);
- GetMarkerProperty(markerURL, aFrame, MarkerBeginProperty());
- markerURL = GetMarkerURI(aFrame, &nsStyleSVG::mMarkerMid);
- GetMarkerProperty(markerURL, aFrame, MarkerMiddleProperty());
- markerURL = GetMarkerURI(aFrame, &nsStyleSVG::mMarkerEnd);
- GetMarkerProperty(markerURL, aFrame, MarkerEndProperty());
- }
- }
- nsSVGFilterProperty*
- nsSVGEffects::GetFilterProperty(nsIFrame* aFrame)
- {
- NS_ASSERTION(!aFrame->GetPrevContinuation(), "aFrame should be first continuation");
- if (!aFrame->StyleEffects()->HasFilters())
- return nullptr;
- return aFrame->GetProperty(FilterProperty());
- }
- void
- nsSVGRenderingObserverList::InvalidateAll()
- {
- if (mObservers.Count() == 0)
- return;
- AutoTArray<nsSVGRenderingObserver*,10> observers;
- for (auto it = mObservers.Iter(); !it.Done(); it.Next()) {
- observers.AppendElement(it.Get()->GetKey());
- }
- mObservers.Clear();
- for (uint32_t i = 0; i < observers.Length(); ++i) {
- observers[i]->InvalidateViaReferencedElement();
- }
- }
- void
- nsSVGRenderingObserverList::InvalidateAllForReflow()
- {
- if (mObservers.Count() == 0)
- return;
- AutoTArray<nsSVGRenderingObserver*,10> observers;
- for (auto it = mObservers.Iter(); !it.Done(); it.Next()) {
- nsSVGRenderingObserver* obs = it.Get()->GetKey();
- if (obs->ObservesReflow()) {
- observers.AppendElement(obs);
- it.Remove();
- }
- }
- for (uint32_t i = 0; i < observers.Length(); ++i) {
- observers[i]->InvalidateViaReferencedElement();
- }
- }
- void
- nsSVGRenderingObserverList::RemoveAll()
- {
- AutoTArray<nsSVGRenderingObserver*,10> observers;
- for (auto it = mObservers.Iter(); !it.Done(); it.Next()) {
- observers.AppendElement(it.Get()->GetKey());
- }
- mObservers.Clear();
- // Our list is now cleared. We need to notify the observers we've removed,
- // so they can update their state & remove themselves as mutation-observers.
- for (uint32_t i = 0; i < observers.Length(); ++i) {
- observers[i]->NotifyEvictedFromRenderingObserverList();
- }
- }
- void
- nsSVGEffects::AddRenderingObserver(Element* aElement,
- nsSVGRenderingObserver* aObserver)
- {
- nsSVGRenderingObserverList *observerList = GetObserverList(aElement);
- if (!observerList) {
- observerList = new nsSVGRenderingObserverList();
- if (!observerList)
- return;
- aElement->SetProperty(nsGkAtoms::renderingobserverlist, observerList,
- nsINode::DeleteProperty<nsSVGRenderingObserverList>);
- }
- aElement->SetHasRenderingObservers(true);
- observerList->Add(aObserver);
- }
- void
- nsSVGEffects::RemoveRenderingObserver(Element* aElement,
- nsSVGRenderingObserver* aObserver)
- {
- nsSVGRenderingObserverList *observerList = GetObserverList(aElement);
- if (observerList) {
- NS_ASSERTION(observerList->Contains(aObserver),
- "removing observer from an element we're not observing?");
- observerList->Remove(aObserver);
- if (observerList->IsEmpty()) {
- aElement->SetHasRenderingObservers(false);
- }
- }
- }
- void
- nsSVGEffects::RemoveAllRenderingObservers(Element* aElement)
- {
- nsSVGRenderingObserverList *observerList = GetObserverList(aElement);
- if (observerList) {
- observerList->RemoveAll();
- aElement->SetHasRenderingObservers(false);
- }
- }
- void
- nsSVGEffects::InvalidateRenderingObservers(nsIFrame* aFrame)
- {
- NS_ASSERTION(!aFrame->GetPrevContinuation(), "aFrame must be first continuation");
- nsIContent* content = aFrame->GetContent();
- if (!content || !content->IsElement())
- return;
- // If the rendering has changed, the bounds may well have changed too:
- aFrame->DeleteProperty(nsSVGUtils::ObjectBoundingBoxProperty());
- nsSVGRenderingObserverList *observerList =
- GetObserverList(content->AsElement());
- if (observerList) {
- observerList->InvalidateAll();
- return;
- }
- // Check ancestor SVG containers. The root frame cannot be of type
- // eSVGContainer so we don't have to check f for null here.
- for (nsIFrame *f = aFrame->GetParent();
- f->IsFrameOfType(nsIFrame::eSVGContainer); f = f->GetParent()) {
- if (f->GetContent()->IsElement()) {
- observerList = GetObserverList(f->GetContent()->AsElement());
- if (observerList) {
- observerList->InvalidateAll();
- return;
- }
- }
- }
- }
- void
- nsSVGEffects::InvalidateDirectRenderingObservers(Element* aElement, uint32_t aFlags /* = 0 */)
- {
- nsIFrame* frame = aElement->GetPrimaryFrame();
- if (frame) {
- // If the rendering has changed, the bounds may well have changed too:
- frame->DeleteProperty(nsSVGUtils::ObjectBoundingBoxProperty());
- }
- if (aElement->HasRenderingObservers()) {
- nsSVGRenderingObserverList *observerList = GetObserverList(aElement);
- if (observerList) {
- if (aFlags & INVALIDATE_REFLOW) {
- observerList->InvalidateAllForReflow();
- } else {
- observerList->InvalidateAll();
- }
- }
- }
- }
- void
- nsSVGEffects::InvalidateDirectRenderingObservers(nsIFrame* aFrame, uint32_t aFlags /* = 0 */)
- {
- nsIContent* content = aFrame->GetContent();
- if (content && content->IsElement()) {
- InvalidateDirectRenderingObservers(content->AsElement(), aFlags);
- }
- }
- already_AddRefed<nsIURI>
- nsSVGEffects::GetBaseURLForLocalRef(nsIContent* content, nsIURI* aDocURI)
- {
- MOZ_ASSERT(content);
- // For a local-reference URL, resolve that fragment against the current
- // document that relative URLs are resolved against.
- nsCOMPtr<nsIURI> baseURI = content->OwnerDoc()->GetDocumentURI();
- if (content->IsInAnonymousSubtree()) {
- nsIContent* bindingParent = content->GetBindingParent();
- nsCOMPtr<nsIURI> originalURI;
- // content is in a shadow tree. If this URL was specified in the subtree
- // referenced by the <use>(or -moz-binding) element, and that subtree came
- // from a separate resource document, then we want the fragment-only URL
- // to resolve to an element from the resource document. Otherwise, the
- // URL was specified somewhere in the document with the <use> element, and
- // we want the fragment-only URL to resolve to an element in that document.
- if (bindingParent) {
- if (content->IsAnonymousContentInSVGUseSubtree()) {
- SVGUseElement* useElement = static_cast<SVGUseElement*>(bindingParent);
- originalURI = useElement->GetSourceDocURI();
- } else {
- nsXBLBinding* binding = bindingParent->GetXBLBinding();
- if (binding) {
- originalURI = binding->GetSourceDocURI();
- } else {
- MOZ_ASSERT(content->IsInNativeAnonymousSubtree(),
- "an non-native anonymous tree which is not from "
- "an XBL binding?");
- }
- }
- if (originalURI) {
- bool isEqualsExceptRef = false;
- aDocURI->EqualsExceptRef(originalURI, &isEqualsExceptRef);
- if (isEqualsExceptRef) {
- baseURI = originalURI;
- }
- }
- }
- }
- return baseURI.forget();
- }
- static already_AddRefed<nsIURI>
- ResolveURLUsingLocalRef(nsIFrame* aFrame, const css::URLValueData* aURL)
- {
- MOZ_ASSERT(aFrame);
- if (!aURL) {
- return nullptr;
- }
- // Non-local-reference URL.
- if (!aURL->IsLocalRef()) {
- nsCOMPtr<nsIURI> result = aURL->GetURI();
- return result.forget();
- }
- nsCOMPtr<nsIURI> baseURI =
- nsSVGEffects::GetBaseURLForLocalRef(aFrame->GetContent(), aURL->GetURI());
- return aURL->ResolveLocalRef(baseURI);
- }
- already_AddRefed<nsIURI>
- nsSVGEffects::GetMarkerURI(nsIFrame* aFrame,
- RefPtr<css::URLValue> nsStyleSVG::* aMarker)
- {
- return ResolveURLUsingLocalRef(aFrame, aFrame->StyleSVG()->*aMarker);
- }
- already_AddRefed<nsIURI>
- nsSVGEffects::GetClipPathURI(nsIFrame* aFrame)
- {
- const nsStyleSVGReset* svgResetStyle = aFrame->StyleSVGReset();
- MOZ_ASSERT(svgResetStyle->mClipPath.GetType() == StyleShapeSourceType::URL);
- css::URLValue* url = svgResetStyle->mClipPath.GetURL();
- return ResolveURLUsingLocalRef(aFrame, url);
- }
- already_AddRefed<nsIURI>
- nsSVGEffects::GetFilterURI(nsIFrame* aFrame, uint32_t aIndex)
- {
- const nsStyleEffects* effects = aFrame->StyleEffects();
- MOZ_ASSERT(effects->mFilters.Length() > aIndex);
- MOZ_ASSERT(effects->mFilters[aIndex].GetType() == NS_STYLE_FILTER_URL);
- return ResolveURLUsingLocalRef(aFrame, effects->mFilters[aIndex].GetURL());
- }
- already_AddRefed<nsIURI>
- nsSVGEffects::GetFilterURI(nsIFrame* aFrame, const nsStyleFilter& aFilter)
- {
- MOZ_ASSERT(aFrame->StyleEffects()->mFilters.Length());
- MOZ_ASSERT(aFilter.GetType() == NS_STYLE_FILTER_URL);
- return ResolveURLUsingLocalRef(aFrame, aFilter.GetURL());
- }
- already_AddRefed<nsIURI>
- nsSVGEffects::GetPaintURI(nsIFrame* aFrame,
- nsStyleSVGPaint nsStyleSVG::* aPaint)
- {
- const nsStyleSVG* svgStyle = aFrame->StyleSVG();
- MOZ_ASSERT((svgStyle->*aPaint).Type() ==
- nsStyleSVGPaintType::eStyleSVGPaintType_Server);
- return ResolveURLUsingLocalRef(aFrame,
- (svgStyle->*aPaint).GetPaintServer());
- }
- already_AddRefed<nsIURI>
- nsSVGEffects::GetMaskURI(nsIFrame* aFrame, uint32_t aIndex)
- {
- const nsStyleSVGReset* svgReset = aFrame->StyleSVGReset();
- MOZ_ASSERT(svgReset->mMask.mLayers.Length() > aIndex);
- return ResolveURLUsingLocalRef(aFrame,
- svgReset->mMask.mLayers[aIndex].mSourceURI);
- }
|