nsSVGEffects.cpp 30 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013
  1. /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
  2. /* This Source Code Form is subject to the terms of the Mozilla Public
  3. * License, v. 2.0. If a copy of the MPL was not distributed with this
  4. * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
  5. // Main header first:
  6. #include "nsSVGEffects.h"
  7. // Keep others in (case-insensitive) order:
  8. #include "mozilla/RestyleManagerHandle.h"
  9. #include "mozilla/RestyleManagerHandleInlines.h"
  10. #include "nsCSSFrameConstructor.h"
  11. #include "nsISupportsImpl.h"
  12. #include "nsSVGClipPathFrame.h"
  13. #include "nsSVGPaintServerFrame.h"
  14. #include "nsSVGPathGeometryElement.h"
  15. #include "nsSVGFilterFrame.h"
  16. #include "nsSVGMaskFrame.h"
  17. #include "nsIReflowCallback.h"
  18. #include "nsCycleCollectionParticipant.h"
  19. #include "SVGUseElement.h"
  20. using namespace mozilla;
  21. using namespace mozilla::dom;
  22. void
  23. nsSVGRenderingObserver::StartListening()
  24. {
  25. Element* target = GetTarget();
  26. if (target) {
  27. target->AddMutationObserver(this);
  28. }
  29. }
  30. void
  31. nsSVGRenderingObserver::StopListening()
  32. {
  33. Element* target = GetTarget();
  34. if (target) {
  35. target->RemoveMutationObserver(this);
  36. if (mInObserverList) {
  37. nsSVGEffects::RemoveRenderingObserver(target, this);
  38. mInObserverList = false;
  39. }
  40. }
  41. NS_ASSERTION(!mInObserverList, "still in an observer list?");
  42. }
  43. static nsSVGRenderingObserverList *
  44. GetObserverList(Element *aElement)
  45. {
  46. return static_cast<nsSVGRenderingObserverList*>
  47. (aElement->GetProperty(nsGkAtoms::renderingobserverlist));
  48. }
  49. Element*
  50. nsSVGRenderingObserver::GetReferencedElement()
  51. {
  52. Element* target = GetTarget();
  53. #ifdef DEBUG
  54. if (target) {
  55. nsSVGRenderingObserverList *observerList = GetObserverList(target);
  56. bool inObserverList = observerList && observerList->Contains(this);
  57. NS_ASSERTION(inObserverList == mInObserverList, "failed to track whether we're in our referenced element's observer list!");
  58. } else {
  59. NS_ASSERTION(!mInObserverList, "In whose observer list are we, then?");
  60. }
  61. #endif
  62. if (target && !mInObserverList) {
  63. nsSVGEffects::AddRenderingObserver(target, this);
  64. mInObserverList = true;
  65. }
  66. return target;
  67. }
  68. nsIFrame*
  69. nsSVGRenderingObserver::GetReferencedFrame()
  70. {
  71. Element* referencedElement = GetReferencedElement();
  72. return referencedElement ? referencedElement->GetPrimaryFrame() : nullptr;
  73. }
  74. nsIFrame*
  75. nsSVGRenderingObserver::GetReferencedFrame(nsIAtom* aFrameType, bool* aOK)
  76. {
  77. nsIFrame* frame = GetReferencedFrame();
  78. if (frame) {
  79. if (frame->GetType() == aFrameType)
  80. return frame;
  81. if (aOK) {
  82. *aOK = false;
  83. }
  84. }
  85. return nullptr;
  86. }
  87. void
  88. nsSVGRenderingObserver::InvalidateViaReferencedElement()
  89. {
  90. mInObserverList = false;
  91. DoUpdate();
  92. }
  93. void
  94. nsSVGRenderingObserver::NotifyEvictedFromRenderingObserverList()
  95. {
  96. mInObserverList = false; // We've been removed from rendering-obs. list.
  97. StopListening(); // Remove ourselves from mutation-obs. list.
  98. }
  99. void
  100. nsSVGRenderingObserver::AttributeChanged(nsIDocument* aDocument,
  101. dom::Element* aElement,
  102. int32_t aNameSpaceID,
  103. nsIAtom* aAttribute,
  104. int32_t aModType,
  105. const nsAttrValue* aOldValue)
  106. {
  107. // An attribute belonging to the element that we are observing *or one of its
  108. // descendants* has changed.
  109. //
  110. // In the case of observing a gradient element, say, we want to know if any
  111. // of its 'stop' element children change, but we don't actually want to do
  112. // anything for changes to SMIL element children, for example. Maybe it's not
  113. // worth having logic to optimize for that, but in most cases it could be a
  114. // small check?
  115. //
  116. // XXXjwatt: do we really want to blindly break the link between our
  117. // observers and ourselves for all attribute changes? For non-ID changes
  118. // surely that is unnecessary.
  119. DoUpdate();
  120. }
  121. void
  122. nsSVGRenderingObserver::ContentAppended(nsIDocument* aDocument,
  123. nsIContent* aContainer,
  124. nsIContent* aFirstNewContent,
  125. int32_t /* unused */)
  126. {
  127. DoUpdate();
  128. }
  129. void
  130. nsSVGRenderingObserver::ContentInserted(nsIDocument* aDocument,
  131. nsIContent* aContainer,
  132. nsIContent* aChild,
  133. int32_t /* unused */)
  134. {
  135. DoUpdate();
  136. }
  137. void
  138. nsSVGRenderingObserver::ContentRemoved(nsIDocument* aDocument,
  139. nsIContent* aContainer,
  140. nsIContent* aChild,
  141. int32_t aIndexInContainer,
  142. nsIContent* aPreviousSibling)
  143. {
  144. DoUpdate();
  145. }
  146. /**
  147. * Note that in the current setup there are two separate observer lists.
  148. *
  149. * In nsSVGIDRenderingObserver's ctor, the new object adds itself to the
  150. * mutation observer list maintained by the referenced element. In this way the
  151. * nsSVGIDRenderingObserver is notified if there are any attribute or content
  152. * tree changes to the element or any of its *descendants*.
  153. *
  154. * In nsSVGIDRenderingObserver::GetReferencedElement() the
  155. * nsSVGIDRenderingObserver object also adds itself to an
  156. * nsSVGRenderingObserverList object belonging to the referenced
  157. * element.
  158. *
  159. * XXX: it would be nice to have a clear and concise executive summary of the
  160. * benefits/necessity of maintaining a second observer list.
  161. */
  162. nsSVGIDRenderingObserver::nsSVGIDRenderingObserver(nsIURI* aURI,
  163. nsIContent* aObservingContent,
  164. bool aReferenceImage)
  165. : mElement(this)
  166. {
  167. // Start watching the target element
  168. mElement.Reset(aObservingContent, aURI, true, aReferenceImage);
  169. StartListening();
  170. }
  171. nsSVGIDRenderingObserver::~nsSVGIDRenderingObserver()
  172. {
  173. StopListening();
  174. }
  175. void
  176. nsSVGIDRenderingObserver::DoUpdate()
  177. {
  178. if (mElement.get() && mInObserverList) {
  179. nsSVGEffects::RemoveRenderingObserver(mElement.get(), this);
  180. mInObserverList = false;
  181. }
  182. }
  183. void
  184. nsSVGFrameReferenceFromProperty::Detach()
  185. {
  186. mFrame = nullptr;
  187. mFramePresShell = nullptr;
  188. }
  189. nsIFrame*
  190. nsSVGFrameReferenceFromProperty::Get()
  191. {
  192. if (mFramePresShell && mFramePresShell->IsDestroying()) {
  193. // mFrame is no longer valid.
  194. Detach();
  195. }
  196. return mFrame;
  197. }
  198. NS_IMPL_ISUPPORTS(nsSVGRenderingObserverProperty, nsIMutationObserver)
  199. void
  200. nsSVGRenderingObserverProperty::DoUpdate()
  201. {
  202. nsSVGIDRenderingObserver::DoUpdate();
  203. nsIFrame* frame = mFrameReference.Get();
  204. if (frame && frame->IsFrameOfType(nsIFrame::eSVG)) {
  205. // Changes should propagate out to things that might be observing
  206. // the referencing frame or its ancestors.
  207. nsLayoutUtils::PostRestyleEvent(
  208. frame->GetContent()->AsElement(), nsRestyleHint(0),
  209. nsChangeHint_InvalidateRenderingObservers);
  210. }
  211. }
  212. NS_IMPL_CYCLE_COLLECTING_ADDREF(nsSVGFilterReference)
  213. NS_IMPL_CYCLE_COLLECTING_RELEASE(nsSVGFilterReference)
  214. NS_IMPL_CYCLE_COLLECTION_CLASS(nsSVGFilterReference)
  215. NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsSVGFilterReference)
  216. NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mElement)
  217. NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
  218. NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsSVGFilterReference)
  219. tmp->StopListening();
  220. NS_IMPL_CYCLE_COLLECTION_UNLINK(mElement);
  221. NS_IMPL_CYCLE_COLLECTION_UNLINK_END
  222. NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsSVGFilterReference)
  223. NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsSVGIDRenderingObserver)
  224. NS_INTERFACE_MAP_ENTRY(nsIMutationObserver)
  225. NS_INTERFACE_MAP_ENTRY(nsISVGFilterReference)
  226. NS_INTERFACE_MAP_END
  227. nsSVGFilterFrame *
  228. nsSVGFilterReference::GetFilterFrame()
  229. {
  230. return static_cast<nsSVGFilterFrame *>
  231. (GetReferencedFrame(nsGkAtoms::svgFilterFrame, nullptr));
  232. }
  233. void
  234. nsSVGFilterReference::DoUpdate()
  235. {
  236. nsSVGIDRenderingObserver::DoUpdate();
  237. if (mFilterChainObserver) {
  238. mFilterChainObserver->Invalidate();
  239. }
  240. }
  241. NS_IMPL_CYCLE_COLLECTING_ADDREF(nsSVGFilterChainObserver)
  242. NS_IMPL_CYCLE_COLLECTING_RELEASE(nsSVGFilterChainObserver)
  243. NS_IMPL_CYCLE_COLLECTION_CLASS(nsSVGFilterChainObserver)
  244. NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsSVGFilterChainObserver)
  245. NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mReferences)
  246. NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
  247. NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsSVGFilterChainObserver)
  248. tmp->DetachReferences();
  249. NS_IMPL_CYCLE_COLLECTION_UNLINK(mReferences);
  250. NS_IMPL_CYCLE_COLLECTION_UNLINK_END
  251. NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsSVGFilterChainObserver)
  252. NS_INTERFACE_MAP_ENTRY(nsISupports)
  253. NS_INTERFACE_MAP_END
  254. nsSVGFilterChainObserver::nsSVGFilterChainObserver(const nsTArray<nsStyleFilter>& aFilters,
  255. nsIContent* aFilteredElement,
  256. nsIFrame* aFilteredFrame)
  257. {
  258. for (uint32_t i = 0; i < aFilters.Length(); i++) {
  259. if (aFilters[i].GetType() != NS_STYLE_FILTER_URL)
  260. continue;
  261. // aFilteredFrame can be null if this filter belongs to a
  262. // CanvasRenderingContext2D.
  263. nsCOMPtr<nsIURI> filterURL = aFilteredFrame
  264. ? nsSVGEffects::GetFilterURI(aFilteredFrame, i)
  265. : aFilters[i].GetURL()->ResolveLocalRef(aFilteredElement);
  266. RefPtr<nsSVGFilterReference> reference =
  267. new nsSVGFilterReference(filterURL, aFilteredElement, this);
  268. mReferences.AppendElement(reference);
  269. }
  270. }
  271. nsSVGFilterChainObserver::~nsSVGFilterChainObserver()
  272. {
  273. DetachReferences();
  274. }
  275. bool
  276. nsSVGFilterChainObserver::ReferencesValidResources()
  277. {
  278. for (uint32_t i = 0; i < mReferences.Length(); i++) {
  279. if (!mReferences[i]->ReferencesValidResource())
  280. return false;
  281. }
  282. return true;
  283. }
  284. bool
  285. nsSVGFilterChainObserver::IsInObserverLists() const
  286. {
  287. for (uint32_t i = 0; i < mReferences.Length(); i++) {
  288. if (!mReferences[i]->IsInObserverList())
  289. return false;
  290. }
  291. return true;
  292. }
  293. void
  294. nsSVGFilterProperty::DoUpdate()
  295. {
  296. nsIFrame* frame = mFrameReference.Get();
  297. if (!frame)
  298. return;
  299. // Repaint asynchronously in case the filter frame is being torn down
  300. nsChangeHint changeHint =
  301. nsChangeHint(nsChangeHint_RepaintFrame);
  302. if (frame && frame->IsFrameOfType(nsIFrame::eSVG)) {
  303. // Changes should propagate out to things that might be observing
  304. // the referencing frame or its ancestors.
  305. changeHint |= nsChangeHint_InvalidateRenderingObservers;
  306. }
  307. // Don't need to request UpdateOverflow if we're being reflowed.
  308. if (!(frame->GetStateBits() & NS_FRAME_IN_REFLOW)) {
  309. changeHint |= nsChangeHint_UpdateOverflow;
  310. }
  311. frame->PresContext()->RestyleManager()->PostRestyleEvent(
  312. frame->GetContent()->AsElement(), nsRestyleHint(0), changeHint);
  313. }
  314. void
  315. nsSVGMarkerProperty::DoUpdate()
  316. {
  317. nsSVGRenderingObserverProperty::DoUpdate();
  318. nsIFrame* frame = mFrameReference.Get();
  319. if (!frame)
  320. return;
  321. NS_ASSERTION(frame->IsFrameOfType(nsIFrame::eSVG), "SVG frame expected");
  322. // Repaint asynchronously in case the marker frame is being torn down
  323. nsChangeHint changeHint =
  324. nsChangeHint(nsChangeHint_RepaintFrame);
  325. // Don't need to request ReflowFrame if we're being reflowed.
  326. if (!(frame->GetStateBits() & NS_FRAME_IN_REFLOW)) {
  327. changeHint |= nsChangeHint_InvalidateRenderingObservers;
  328. // XXXjwatt: We need to unify SVG into standard reflow so we can just use
  329. // nsChangeHint_NeedReflow | nsChangeHint_NeedDirtyReflow here.
  330. // XXXSDL KILL THIS!!!
  331. nsSVGUtils::ScheduleReflowSVG(frame);
  332. }
  333. frame->PresContext()->RestyleManager()->PostRestyleEvent(
  334. frame->GetContent()->AsElement(), nsRestyleHint(0), changeHint);
  335. }
  336. NS_IMPL_ISUPPORTS(nsSVGMaskProperty, nsISupports)
  337. nsSVGMaskProperty::nsSVGMaskProperty(nsIFrame* aFrame)
  338. {
  339. const nsStyleSVGReset *svgReset = aFrame->StyleSVGReset();
  340. for (uint32_t i = 0; i < svgReset->mMask.mImageCount; i++) {
  341. nsCOMPtr<nsIURI> maskUri = nsSVGEffects::GetMaskURI(aFrame, i);
  342. nsSVGPaintingProperty* prop = new nsSVGPaintingProperty(maskUri, aFrame,
  343. false);
  344. mProperties.AppendElement(prop);
  345. }
  346. }
  347. bool
  348. nsSVGTextPathProperty::TargetIsValid()
  349. {
  350. Element* target = GetTarget();
  351. return target && target->IsSVGElement(nsGkAtoms::path);
  352. }
  353. void
  354. nsSVGTextPathProperty::DoUpdate()
  355. {
  356. nsSVGRenderingObserverProperty::DoUpdate();
  357. nsIFrame* frame = mFrameReference.Get();
  358. if (!frame)
  359. return;
  360. NS_ASSERTION(frame->IsFrameOfType(nsIFrame::eSVG) || frame->IsSVGText(),
  361. "SVG frame expected");
  362. // Avoid getting into an infinite loop of reflows if the <textPath> is
  363. // pointing to one of its ancestors. TargetIsValid returns true iff
  364. // the target element is a <path> element, and we would not have this
  365. // nsSVGTextPathProperty if this <textPath> were a descendant of the
  366. // target <path>.
  367. //
  368. // Note that we still have to post the restyle event when we
  369. // change from being valid to invalid, so that mPositions on the
  370. // SVGTextFrame gets updated, skipping the <textPath>, ensuring
  371. // that nothing gets painted for that element.
  372. bool nowValid = TargetIsValid();
  373. if (!mValid && !nowValid) {
  374. // Just return if we were previously invalid, and are still invalid.
  375. return;
  376. }
  377. mValid = nowValid;
  378. // Repaint asynchronously in case the path frame is being torn down
  379. nsChangeHint changeHint =
  380. nsChangeHint(nsChangeHint_RepaintFrame | nsChangeHint_UpdateTextPath);
  381. frame->PresContext()->RestyleManager()->PostRestyleEvent(
  382. frame->GetContent()->AsElement(), nsRestyleHint(0), changeHint);
  383. }
  384. static void
  385. InvalidateAllContinuations(nsIFrame* aFrame)
  386. {
  387. for (nsIFrame* f = aFrame; f;
  388. f = nsLayoutUtils::GetNextContinuationOrIBSplitSibling(f)) {
  389. f->InvalidateFrame();
  390. }
  391. }
  392. void
  393. nsSVGPaintingProperty::DoUpdate()
  394. {
  395. nsSVGRenderingObserverProperty::DoUpdate();
  396. nsIFrame* frame = mFrameReference.Get();
  397. if (!frame)
  398. return;
  399. if (frame->GetStateBits() & NS_FRAME_SVG_LAYOUT) {
  400. nsLayoutUtils::PostRestyleEvent(
  401. frame->GetContent()->AsElement(), nsRestyleHint(0),
  402. nsChangeHint_InvalidateRenderingObservers);
  403. frame->InvalidateFrameSubtree();
  404. } else {
  405. InvalidateAllContinuations(frame);
  406. }
  407. }
  408. static nsSVGFilterProperty*
  409. GetOrCreateFilterProperty(nsIFrame* aFrame)
  410. {
  411. const nsStyleEffects* effects = aFrame->StyleEffects();
  412. if (!effects->HasFilters())
  413. return nullptr;
  414. nsSVGFilterProperty *prop =
  415. aFrame->GetProperty(nsSVGEffects::FilterProperty());
  416. if (prop)
  417. return prop;
  418. prop = new nsSVGFilterProperty(effects->mFilters, aFrame);
  419. NS_ADDREF(prop);
  420. aFrame->SetProperty(nsSVGEffects::FilterProperty(), prop);
  421. return prop;
  422. }
  423. static nsSVGMaskProperty*
  424. GetOrCreateMaskProperty(nsIFrame* aFrame)
  425. {
  426. nsSVGMaskProperty *prop = aFrame->GetProperty(nsSVGEffects::MaskProperty());
  427. if (prop)
  428. return prop;
  429. prop = new nsSVGMaskProperty(aFrame);
  430. NS_ADDREF(prop);
  431. aFrame->SetProperty(nsSVGEffects::MaskProperty(), prop);
  432. return prop;
  433. }
  434. template<class T>
  435. static T*
  436. GetEffectProperty(nsIURI* aURI, nsIFrame* aFrame,
  437. const mozilla::FramePropertyDescriptor<T>* aProperty)
  438. {
  439. if (!aURI)
  440. return nullptr;
  441. T* prop = aFrame->GetProperty(aProperty);
  442. if (prop)
  443. return prop;
  444. prop = new T(aURI, aFrame, false);
  445. NS_ADDREF(prop);
  446. aFrame->SetProperty(aProperty, prop);
  447. return prop;
  448. }
  449. nsSVGMarkerProperty*
  450. nsSVGEffects::GetMarkerProperty(nsIURI* aURI, nsIFrame* aFrame,
  451. const mozilla::FramePropertyDescriptor<nsSVGMarkerProperty>* aProperty)
  452. {
  453. MOZ_ASSERT(aFrame->GetType() == nsGkAtoms::svgPathGeometryFrame &&
  454. static_cast<nsSVGPathGeometryElement*>(aFrame->GetContent())->IsMarkable(),
  455. "Bad frame");
  456. return GetEffectProperty(aURI, aFrame, aProperty);
  457. }
  458. nsSVGTextPathProperty*
  459. nsSVGEffects::GetTextPathProperty(nsIURI* aURI, nsIFrame* aFrame,
  460. const mozilla::FramePropertyDescriptor<nsSVGTextPathProperty>* aProperty)
  461. {
  462. return GetEffectProperty(aURI, aFrame, aProperty);
  463. }
  464. nsSVGPaintingProperty*
  465. nsSVGEffects::GetPaintingProperty(nsIURI* aURI, nsIFrame* aFrame,
  466. const mozilla::FramePropertyDescriptor<nsSVGPaintingProperty>* aProperty)
  467. {
  468. return GetEffectProperty(aURI, aFrame, aProperty);
  469. }
  470. nsSVGPaintingProperty*
  471. nsSVGEffects::GetPaintingPropertyForURI(nsIURI* aURI, nsIFrame* aFrame,
  472. URIObserverHashtablePropertyDescriptor aProperty)
  473. {
  474. if (!aURI)
  475. return nullptr;
  476. nsSVGEffects::URIObserverHashtable *hashtable =
  477. aFrame->GetProperty(aProperty);
  478. if (!hashtable) {
  479. hashtable = new nsSVGEffects::URIObserverHashtable();
  480. aFrame->SetProperty(aProperty, hashtable);
  481. }
  482. nsSVGPaintingProperty* prop =
  483. static_cast<nsSVGPaintingProperty*>(hashtable->GetWeak(aURI));
  484. if (!prop) {
  485. bool watchImage = aProperty == nsSVGEffects::BackgroundImageProperty();
  486. prop = new nsSVGPaintingProperty(aURI, aFrame, watchImage);
  487. hashtable->Put(aURI, prop);
  488. }
  489. return prop;
  490. }
  491. nsSVGEffects::EffectProperties
  492. nsSVGEffects::GetEffectProperties(nsIFrame* aFrame)
  493. {
  494. NS_ASSERTION(!aFrame->GetPrevContinuation(), "aFrame should be first continuation");
  495. EffectProperties result;
  496. const nsStyleSVGReset *style = aFrame->StyleSVGReset();
  497. result.mFilter = GetOrCreateFilterProperty(aFrame);
  498. if (style->mClipPath.GetType() == StyleShapeSourceType::URL) {
  499. nsCOMPtr<nsIURI> pathURI = nsSVGEffects::GetClipPathURI(aFrame);
  500. result.mClipPath =
  501. GetPaintingProperty(pathURI, aFrame, ClipPathProperty());
  502. } else {
  503. result.mClipPath = nullptr;
  504. }
  505. MOZ_ASSERT(style->mMask.mImageCount > 0);
  506. result.mMask = style->mMask.HasLayerWithImage()
  507. ? GetOrCreateMaskProperty(aFrame) : nullptr;
  508. return result;
  509. }
  510. nsSVGPaintServerFrame *
  511. nsSVGEffects::GetPaintServer(nsIFrame* aTargetFrame,
  512. nsStyleSVGPaint nsStyleSVG::* aPaint,
  513. PaintingPropertyDescriptor aType)
  514. {
  515. const nsStyleSVG* svgStyle = aTargetFrame->StyleSVG();
  516. if ((svgStyle->*aPaint).Type() != eStyleSVGPaintType_Server)
  517. return nullptr;
  518. // If we're looking at a frame within SVG text, then we need to look up
  519. // to find the right frame to get the painting property off. We should at
  520. // least look up past a text frame, and if the text frame's parent is the
  521. // anonymous block frame, then we look up to its parent (the SVGTextFrame).
  522. nsIFrame* frame = aTargetFrame;
  523. if (frame->GetContent()->IsNodeOfType(nsINode::eTEXT)) {
  524. frame = frame->GetParent();
  525. nsIFrame* grandparent = frame->GetParent();
  526. if (grandparent && grandparent->GetType() == nsGkAtoms::svgTextFrame) {
  527. frame = grandparent;
  528. }
  529. }
  530. nsCOMPtr<nsIURI> paintServerURL = nsSVGEffects::GetPaintURI(frame, aPaint);
  531. nsSVGPaintingProperty *property =
  532. nsSVGEffects::GetPaintingProperty(paintServerURL, frame, aType);
  533. if (!property)
  534. return nullptr;
  535. nsIFrame *result = property->GetReferencedFrame();
  536. if (!result)
  537. return nullptr;
  538. nsIAtom *type = result->GetType();
  539. if (type != nsGkAtoms::svgLinearGradientFrame &&
  540. type != nsGkAtoms::svgRadialGradientFrame &&
  541. type != nsGkAtoms::svgPatternFrame)
  542. return nullptr;
  543. return static_cast<nsSVGPaintServerFrame*>(result);
  544. }
  545. nsSVGClipPathFrame *
  546. nsSVGEffects::EffectProperties::GetClipPathFrame(bool* aOK)
  547. {
  548. if (!mClipPath)
  549. return nullptr;
  550. nsSVGClipPathFrame *frame = static_cast<nsSVGClipPathFrame *>
  551. (mClipPath->GetReferencedFrame(nsGkAtoms::svgClipPathFrame, aOK));
  552. if (frame && aOK && *aOK) {
  553. *aOK = frame->IsValid();
  554. }
  555. return frame;
  556. }
  557. nsSVGMaskFrame *
  558. nsSVGEffects::EffectProperties::GetFirstMaskFrame(bool* aOK)
  559. {
  560. if (!mMask) {
  561. return nullptr;
  562. }
  563. const nsTArray<RefPtr<nsSVGPaintingProperty>>& props = mMask->GetProps();
  564. if (props.IsEmpty()) {
  565. return nullptr;
  566. }
  567. return static_cast<nsSVGMaskFrame *>
  568. (props[0]->GetReferencedFrame(nsGkAtoms::svgMaskFrame, aOK));
  569. }
  570. nsTArray<nsSVGMaskFrame *>
  571. nsSVGEffects::EffectProperties::GetMaskFrames()
  572. {
  573. nsTArray<nsSVGMaskFrame *> result;
  574. if (!mMask)
  575. return result;
  576. bool ok = false;
  577. const nsTArray<RefPtr<nsSVGPaintingProperty>>& props = mMask->GetProps();
  578. for (size_t i = 0; i < props.Length(); i++) {
  579. nsSVGMaskFrame* maskFrame =
  580. static_cast<nsSVGMaskFrame *>(props[i]->GetReferencedFrame(
  581. nsGkAtoms::svgMaskFrame, &ok));
  582. result.AppendElement(maskFrame);
  583. }
  584. return result;
  585. }
  586. void
  587. nsSVGEffects::UpdateEffects(nsIFrame* aFrame)
  588. {
  589. NS_ASSERTION(aFrame->GetContent()->IsElement(),
  590. "aFrame's content should be an element");
  591. aFrame->DeleteProperty(FilterProperty());
  592. aFrame->DeleteProperty(MaskProperty());
  593. aFrame->DeleteProperty(ClipPathProperty());
  594. aFrame->DeleteProperty(MarkerBeginProperty());
  595. aFrame->DeleteProperty(MarkerMiddleProperty());
  596. aFrame->DeleteProperty(MarkerEndProperty());
  597. aFrame->DeleteProperty(FillProperty());
  598. aFrame->DeleteProperty(StrokeProperty());
  599. aFrame->DeleteProperty(BackgroundImageProperty());
  600. // Ensure that the filter is repainted correctly
  601. // We can't do that in DoUpdate as the referenced frame may not be valid
  602. GetOrCreateFilterProperty(aFrame);
  603. if (aFrame->GetType() == nsGkAtoms::svgPathGeometryFrame &&
  604. static_cast<nsSVGPathGeometryElement*>(aFrame->GetContent())->IsMarkable()) {
  605. // Set marker properties here to avoid reference loops
  606. nsCOMPtr<nsIURI> markerURL =
  607. GetMarkerURI(aFrame, &nsStyleSVG::mMarkerStart);
  608. GetMarkerProperty(markerURL, aFrame, MarkerBeginProperty());
  609. markerURL = GetMarkerURI(aFrame, &nsStyleSVG::mMarkerMid);
  610. GetMarkerProperty(markerURL, aFrame, MarkerMiddleProperty());
  611. markerURL = GetMarkerURI(aFrame, &nsStyleSVG::mMarkerEnd);
  612. GetMarkerProperty(markerURL, aFrame, MarkerEndProperty());
  613. }
  614. }
  615. nsSVGFilterProperty*
  616. nsSVGEffects::GetFilterProperty(nsIFrame* aFrame)
  617. {
  618. NS_ASSERTION(!aFrame->GetPrevContinuation(), "aFrame should be first continuation");
  619. if (!aFrame->StyleEffects()->HasFilters())
  620. return nullptr;
  621. return aFrame->GetProperty(FilterProperty());
  622. }
  623. void
  624. nsSVGRenderingObserverList::InvalidateAll()
  625. {
  626. if (mObservers.Count() == 0)
  627. return;
  628. AutoTArray<nsSVGRenderingObserver*,10> observers;
  629. for (auto it = mObservers.Iter(); !it.Done(); it.Next()) {
  630. observers.AppendElement(it.Get()->GetKey());
  631. }
  632. mObservers.Clear();
  633. for (uint32_t i = 0; i < observers.Length(); ++i) {
  634. observers[i]->InvalidateViaReferencedElement();
  635. }
  636. }
  637. void
  638. nsSVGRenderingObserverList::InvalidateAllForReflow()
  639. {
  640. if (mObservers.Count() == 0)
  641. return;
  642. AutoTArray<nsSVGRenderingObserver*,10> observers;
  643. for (auto it = mObservers.Iter(); !it.Done(); it.Next()) {
  644. nsSVGRenderingObserver* obs = it.Get()->GetKey();
  645. if (obs->ObservesReflow()) {
  646. observers.AppendElement(obs);
  647. it.Remove();
  648. }
  649. }
  650. for (uint32_t i = 0; i < observers.Length(); ++i) {
  651. observers[i]->InvalidateViaReferencedElement();
  652. }
  653. }
  654. void
  655. nsSVGRenderingObserverList::RemoveAll()
  656. {
  657. AutoTArray<nsSVGRenderingObserver*,10> observers;
  658. for (auto it = mObservers.Iter(); !it.Done(); it.Next()) {
  659. observers.AppendElement(it.Get()->GetKey());
  660. }
  661. mObservers.Clear();
  662. // Our list is now cleared. We need to notify the observers we've removed,
  663. // so they can update their state & remove themselves as mutation-observers.
  664. for (uint32_t i = 0; i < observers.Length(); ++i) {
  665. observers[i]->NotifyEvictedFromRenderingObserverList();
  666. }
  667. }
  668. void
  669. nsSVGEffects::AddRenderingObserver(Element* aElement,
  670. nsSVGRenderingObserver* aObserver)
  671. {
  672. nsSVGRenderingObserverList *observerList = GetObserverList(aElement);
  673. if (!observerList) {
  674. observerList = new nsSVGRenderingObserverList();
  675. if (!observerList)
  676. return;
  677. aElement->SetProperty(nsGkAtoms::renderingobserverlist, observerList,
  678. nsINode::DeleteProperty<nsSVGRenderingObserverList>);
  679. }
  680. aElement->SetHasRenderingObservers(true);
  681. observerList->Add(aObserver);
  682. }
  683. void
  684. nsSVGEffects::RemoveRenderingObserver(Element* aElement,
  685. nsSVGRenderingObserver* aObserver)
  686. {
  687. nsSVGRenderingObserverList *observerList = GetObserverList(aElement);
  688. if (observerList) {
  689. NS_ASSERTION(observerList->Contains(aObserver),
  690. "removing observer from an element we're not observing?");
  691. observerList->Remove(aObserver);
  692. if (observerList->IsEmpty()) {
  693. aElement->SetHasRenderingObservers(false);
  694. }
  695. }
  696. }
  697. void
  698. nsSVGEffects::RemoveAllRenderingObservers(Element* aElement)
  699. {
  700. nsSVGRenderingObserverList *observerList = GetObserverList(aElement);
  701. if (observerList) {
  702. observerList->RemoveAll();
  703. aElement->SetHasRenderingObservers(false);
  704. }
  705. }
  706. void
  707. nsSVGEffects::InvalidateRenderingObservers(nsIFrame* aFrame)
  708. {
  709. NS_ASSERTION(!aFrame->GetPrevContinuation(), "aFrame must be first continuation");
  710. nsIContent* content = aFrame->GetContent();
  711. if (!content || !content->IsElement())
  712. return;
  713. // If the rendering has changed, the bounds may well have changed too:
  714. aFrame->DeleteProperty(nsSVGUtils::ObjectBoundingBoxProperty());
  715. nsSVGRenderingObserverList *observerList =
  716. GetObserverList(content->AsElement());
  717. if (observerList) {
  718. observerList->InvalidateAll();
  719. return;
  720. }
  721. // Check ancestor SVG containers. The root frame cannot be of type
  722. // eSVGContainer so we don't have to check f for null here.
  723. for (nsIFrame *f = aFrame->GetParent();
  724. f->IsFrameOfType(nsIFrame::eSVGContainer); f = f->GetParent()) {
  725. if (f->GetContent()->IsElement()) {
  726. observerList = GetObserverList(f->GetContent()->AsElement());
  727. if (observerList) {
  728. observerList->InvalidateAll();
  729. return;
  730. }
  731. }
  732. }
  733. }
  734. void
  735. nsSVGEffects::InvalidateDirectRenderingObservers(Element* aElement, uint32_t aFlags /* = 0 */)
  736. {
  737. nsIFrame* frame = aElement->GetPrimaryFrame();
  738. if (frame) {
  739. // If the rendering has changed, the bounds may well have changed too:
  740. frame->DeleteProperty(nsSVGUtils::ObjectBoundingBoxProperty());
  741. }
  742. if (aElement->HasRenderingObservers()) {
  743. nsSVGRenderingObserverList *observerList = GetObserverList(aElement);
  744. if (observerList) {
  745. if (aFlags & INVALIDATE_REFLOW) {
  746. observerList->InvalidateAllForReflow();
  747. } else {
  748. observerList->InvalidateAll();
  749. }
  750. }
  751. }
  752. }
  753. void
  754. nsSVGEffects::InvalidateDirectRenderingObservers(nsIFrame* aFrame, uint32_t aFlags /* = 0 */)
  755. {
  756. nsIContent* content = aFrame->GetContent();
  757. if (content && content->IsElement()) {
  758. InvalidateDirectRenderingObservers(content->AsElement(), aFlags);
  759. }
  760. }
  761. already_AddRefed<nsIURI>
  762. nsSVGEffects::GetBaseURLForLocalRef(nsIContent* content, nsIURI* aDocURI)
  763. {
  764. MOZ_ASSERT(content);
  765. // For a local-reference URL, resolve that fragment against the current
  766. // document that relative URLs are resolved against.
  767. nsCOMPtr<nsIURI> baseURI = content->OwnerDoc()->GetDocumentURI();
  768. if (content->IsInAnonymousSubtree()) {
  769. nsIContent* bindingParent = content->GetBindingParent();
  770. nsCOMPtr<nsIURI> originalURI;
  771. // content is in a shadow tree. If this URL was specified in the subtree
  772. // referenced by the <use>(or -moz-binding) element, and that subtree came
  773. // from a separate resource document, then we want the fragment-only URL
  774. // to resolve to an element from the resource document. Otherwise, the
  775. // URL was specified somewhere in the document with the <use> element, and
  776. // we want the fragment-only URL to resolve to an element in that document.
  777. if (bindingParent) {
  778. if (content->IsAnonymousContentInSVGUseSubtree()) {
  779. SVGUseElement* useElement = static_cast<SVGUseElement*>(bindingParent);
  780. originalURI = useElement->GetSourceDocURI();
  781. } else {
  782. nsXBLBinding* binding = bindingParent->GetXBLBinding();
  783. if (binding) {
  784. originalURI = binding->GetSourceDocURI();
  785. } else {
  786. MOZ_ASSERT(content->IsInNativeAnonymousSubtree(),
  787. "an non-native anonymous tree which is not from "
  788. "an XBL binding?");
  789. }
  790. }
  791. if (originalURI) {
  792. bool isEqualsExceptRef = false;
  793. aDocURI->EqualsExceptRef(originalURI, &isEqualsExceptRef);
  794. if (isEqualsExceptRef) {
  795. baseURI = originalURI;
  796. }
  797. }
  798. }
  799. }
  800. return baseURI.forget();
  801. }
  802. static already_AddRefed<nsIURI>
  803. ResolveURLUsingLocalRef(nsIFrame* aFrame, const css::URLValueData* aURL)
  804. {
  805. MOZ_ASSERT(aFrame);
  806. if (!aURL) {
  807. return nullptr;
  808. }
  809. // Non-local-reference URL.
  810. if (!aURL->IsLocalRef()) {
  811. nsCOMPtr<nsIURI> result = aURL->GetURI();
  812. return result.forget();
  813. }
  814. nsCOMPtr<nsIURI> baseURI =
  815. nsSVGEffects::GetBaseURLForLocalRef(aFrame->GetContent(), aURL->GetURI());
  816. return aURL->ResolveLocalRef(baseURI);
  817. }
  818. already_AddRefed<nsIURI>
  819. nsSVGEffects::GetMarkerURI(nsIFrame* aFrame,
  820. RefPtr<css::URLValue> nsStyleSVG::* aMarker)
  821. {
  822. return ResolveURLUsingLocalRef(aFrame, aFrame->StyleSVG()->*aMarker);
  823. }
  824. already_AddRefed<nsIURI>
  825. nsSVGEffects::GetClipPathURI(nsIFrame* aFrame)
  826. {
  827. const nsStyleSVGReset* svgResetStyle = aFrame->StyleSVGReset();
  828. MOZ_ASSERT(svgResetStyle->mClipPath.GetType() == StyleShapeSourceType::URL);
  829. css::URLValue* url = svgResetStyle->mClipPath.GetURL();
  830. return ResolveURLUsingLocalRef(aFrame, url);
  831. }
  832. already_AddRefed<nsIURI>
  833. nsSVGEffects::GetFilterURI(nsIFrame* aFrame, uint32_t aIndex)
  834. {
  835. const nsStyleEffects* effects = aFrame->StyleEffects();
  836. MOZ_ASSERT(effects->mFilters.Length() > aIndex);
  837. MOZ_ASSERT(effects->mFilters[aIndex].GetType() == NS_STYLE_FILTER_URL);
  838. return ResolveURLUsingLocalRef(aFrame, effects->mFilters[aIndex].GetURL());
  839. }
  840. already_AddRefed<nsIURI>
  841. nsSVGEffects::GetFilterURI(nsIFrame* aFrame, const nsStyleFilter& aFilter)
  842. {
  843. MOZ_ASSERT(aFrame->StyleEffects()->mFilters.Length());
  844. MOZ_ASSERT(aFilter.GetType() == NS_STYLE_FILTER_URL);
  845. return ResolveURLUsingLocalRef(aFrame, aFilter.GetURL());
  846. }
  847. already_AddRefed<nsIURI>
  848. nsSVGEffects::GetPaintURI(nsIFrame* aFrame,
  849. nsStyleSVGPaint nsStyleSVG::* aPaint)
  850. {
  851. const nsStyleSVG* svgStyle = aFrame->StyleSVG();
  852. MOZ_ASSERT((svgStyle->*aPaint).Type() ==
  853. nsStyleSVGPaintType::eStyleSVGPaintType_Server);
  854. return ResolveURLUsingLocalRef(aFrame,
  855. (svgStyle->*aPaint).GetPaintServer());
  856. }
  857. already_AddRefed<nsIURI>
  858. nsSVGEffects::GetMaskURI(nsIFrame* aFrame, uint32_t aIndex)
  859. {
  860. const nsStyleSVGReset* svgReset = aFrame->StyleSVGReset();
  861. MOZ_ASSERT(svgReset->mMask.mLayers.Length() > aIndex);
  862. return ResolveURLUsingLocalRef(aFrame,
  863. svgReset->mMask.mLayers[aIndex].mSourceURI);
  864. }