Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/layout/svg/SVGObserverUtils.cpp
Line
Count
Source (jump to first uncovered line)
1
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
3
/* This Source Code Form is subject to the terms of the Mozilla Public
4
 * License, v. 2.0. If a copy of the MPL was not distributed with this
5
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6
7
// Main header first:
8
#include "SVGObserverUtils.h"
9
10
// Keep others in (case-insensitive) order:
11
#include "mozilla/RestyleManager.h"
12
#include "nsCSSFrameConstructor.h"
13
#include "nsISupportsImpl.h"
14
#include "nsSVGClipPathFrame.h"
15
#include "nsSVGPaintServerFrame.h"
16
#include "nsSVGFilterFrame.h"
17
#include "nsSVGMaskFrame.h"
18
#include "nsIReflowCallback.h"
19
#include "nsCycleCollectionParticipant.h"
20
#include "SVGGeometryElement.h"
21
#include "SVGTextPathElement.h"
22
#include "SVGUseElement.h"
23
#include "ImageLoader.h"
24
#include "mozilla/net/ReferrerPolicy.h"
25
26
using namespace mozilla::dom;
27
28
namespace mozilla {
29
30
void
31
SVGRenderingObserver::StartObserving()
32
0
{
33
0
  Element* target = GetTarget();
34
0
  if (target) {
35
0
    target->AddMutationObserver(this);
36
0
  }
37
0
}
38
39
void
40
SVGRenderingObserver::StopObserving()
41
0
{
42
0
  Element* target = GetTarget();
43
0
44
0
  if (target) {
45
0
    target->RemoveMutationObserver(this);
46
0
    if (mInObserverList) {
47
0
      SVGObserverUtils::RemoveRenderingObserver(target, this);
48
0
      mInObserverList = false;
49
0
    }
50
0
  }
51
0
  NS_ASSERTION(!mInObserverList, "still in an observer list?");
52
0
}
53
54
static SVGRenderingObserverList*
55
GetObserverList(Element *aElement)
56
0
{
57
0
  return static_cast<SVGRenderingObserverList*>
58
0
    (aElement->GetProperty(nsGkAtoms::renderingobserverlist));
59
0
}
60
61
Element*
62
SVGRenderingObserver::GetReferencedElement()
63
0
{
64
0
  Element* target = GetTarget();
65
#ifdef DEBUG
66
  if (target) {
67
    SVGRenderingObserverList* observerList = GetObserverList(target);
68
    bool inObserverList = observerList && observerList->Contains(this);
69
    NS_ASSERTION(inObserverList == mInObserverList, "failed to track whether we're in our referenced element's observer list!");
70
  } else {
71
    NS_ASSERTION(!mInObserverList, "In whose observer list are we, then?");
72
  }
73
#endif
74
0
  if (target && !mInObserverList) {
75
0
    SVGObserverUtils::AddRenderingObserver(target, this);
76
0
    mInObserverList = true;
77
0
  }
78
0
  return target;
79
0
}
80
81
nsIFrame*
82
SVGRenderingObserver::GetReferencedFrame()
83
0
{
84
0
  Element* referencedElement = GetReferencedElement();
85
0
  return referencedElement ? referencedElement->GetPrimaryFrame() : nullptr;
86
0
}
87
88
nsIFrame*
89
SVGRenderingObserver::GetReferencedFrame(LayoutFrameType aFrameType,
90
                                         bool* aOK)
91
0
{
92
0
  nsIFrame* frame = GetReferencedFrame();
93
0
  if (frame) {
94
0
    if (frame->Type() == aFrameType)
95
0
      return frame;
96
0
    if (aOK) {
97
0
      *aOK = false;
98
0
    }
99
0
  }
100
0
  return nullptr;
101
0
}
102
103
void
104
SVGRenderingObserver::OnNonDOMMutationRenderingChange()
105
0
{
106
0
  mInObserverList = false;
107
0
  OnRenderingChange();
108
0
}
109
110
void
111
SVGRenderingObserver::NotifyEvictedFromRenderingObserverList()
112
0
{
113
0
  mInObserverList = false; // We've been removed from rendering-obs. list.
114
0
  StopObserving();            // Remove ourselves from mutation-obs. list.
115
0
}
116
117
void
118
SVGRenderingObserver::AttributeChanged(dom::Element* aElement,
119
                                       int32_t aNameSpaceID,
120
                                       nsAtom* aAttribute,
121
                                       int32_t aModType,
122
                                       const nsAttrValue* aOldValue)
123
0
{
124
0
  // An attribute belonging to the element that we are observing *or one of its
125
0
  // descendants* has changed.
126
0
  //
127
0
  // In the case of observing a gradient element, say, we want to know if any
128
0
  // of its 'stop' element children change, but we don't actually want to do
129
0
  // anything for changes to SMIL element children, for example. Maybe it's not
130
0
  // worth having logic to optimize for that, but in most cases it could be a
131
0
  // small check?
132
0
  //
133
0
  // XXXjwatt: do we really want to blindly break the link between our
134
0
  // observers and ourselves for all attribute changes? For non-ID changes
135
0
  // surely that is unnecessary.
136
0
137
0
  OnRenderingChange();
138
0
}
139
140
void
141
SVGRenderingObserver::ContentAppended(nsIContent* aFirstNewContent)
142
0
{
143
0
  OnRenderingChange();
144
0
}
145
146
void
147
SVGRenderingObserver::ContentInserted(nsIContent* aChild)
148
0
{
149
0
  OnRenderingChange();
150
0
}
151
152
void
153
SVGRenderingObserver::ContentRemoved(nsIContent* aChild,
154
                                     nsIContent* aPreviousSibling)
155
0
{
156
0
  OnRenderingChange();
157
0
}
158
159
/**
160
 * Note that in the current setup there are two separate observer lists.
161
 *
162
 * In SVGIDRenderingObserver's ctor, the new object adds itself to the
163
 * mutation observer list maintained by the referenced element. In this way the
164
 * SVGIDRenderingObserver is notified if there are any attribute or content
165
 * tree changes to the element or any of its *descendants*.
166
 *
167
 * In SVGIDRenderingObserver::GetReferencedElement() the
168
 * SVGIDRenderingObserver object also adds itself to an
169
 * SVGRenderingObserverList object belonging to the referenced
170
 * element.
171
 *
172
 * XXX: it would be nice to have a clear and concise executive summary of the
173
 * benefits/necessity of maintaining a second observer list.
174
 */
175
176
SVGIDRenderingObserver::SVGIDRenderingObserver(URLAndReferrerInfo* aURI,
177
                                               nsIContent* aObservingContent,
178
                                               bool aReferenceImage)
179
  : mObservedElementTracker(this)
180
0
{
181
0
  // Start watching the target element
182
0
  nsCOMPtr<nsIURI> uri;
183
0
  nsCOMPtr<nsIURI> referrer;
184
0
  uint32_t referrerPolicy = mozilla::net::RP_Unset;
185
0
  if (aURI) {
186
0
    uri = aURI->GetURI();
187
0
    referrer = aURI->GetReferrer();
188
0
    referrerPolicy = aURI->GetReferrerPolicy();
189
0
  }
190
0
191
0
  mObservedElementTracker.Reset(aObservingContent, uri, referrer,
192
0
                                referrerPolicy, true, aReferenceImage);
193
0
  StartObserving();
194
0
}
195
196
SVGIDRenderingObserver::~SVGIDRenderingObserver()
197
0
{
198
0
  StopObserving();
199
0
}
200
201
void
202
SVGIDRenderingObserver::OnRenderingChange()
203
0
{
204
0
  if (mObservedElementTracker.get() && mInObserverList) {
205
0
    SVGObserverUtils::RemoveRenderingObserver(mObservedElementTracker.get(), this);
206
0
    mInObserverList = false;
207
0
  }
208
0
}
209
210
void
211
nsSVGFrameReferenceFromProperty::Detach()
212
0
{
213
0
  mFrame = nullptr;
214
0
  mFramePresShell = nullptr;
215
0
}
216
217
nsIFrame*
218
nsSVGFrameReferenceFromProperty::Get()
219
0
{
220
0
  if (mFramePresShell && mFramePresShell->IsDestroying()) {
221
0
    // mFrame is no longer valid.
222
0
    Detach();
223
0
  }
224
0
  return mFrame;
225
0
}
226
227
228
NS_IMPL_ISUPPORTS(SVGTemplateElementObserver, nsIMutationObserver)
229
230
void
231
SVGTemplateElementObserver::OnRenderingChange()
232
0
{
233
0
  SVGIDRenderingObserver::OnRenderingChange();
234
0
235
0
  if (nsIFrame* frame = mFrameReference.Get()) {
236
0
    // We know that we don't need to walk the parent chain notifying rendering
237
0
    // observers since changes to a gradient etc. do not affect ancestor
238
0
    // elements.  So we only invalidate *direct* rendering observers here.
239
0
    // Since we don't need to walk the parent chain, we don't need to worry
240
0
    // about coalescing multiple invalidations by using a change hint as we do
241
0
    // in nsSVGRenderingObserverProperty::OnRenderingChange.
242
0
    SVGObserverUtils::InvalidateDirectRenderingObservers(frame);
243
0
  }
244
0
}
245
246
247
NS_IMPL_ISUPPORTS(nsSVGRenderingObserverProperty, nsIMutationObserver)
248
249
void
250
nsSVGRenderingObserverProperty::OnRenderingChange()
251
0
{
252
0
  SVGIDRenderingObserver::OnRenderingChange();
253
0
254
0
  nsIFrame* frame = mFrameReference.Get();
255
0
256
0
  if (frame && frame->HasAllStateBits(NS_FRAME_SVG_LAYOUT)) {
257
0
    // We need to notify anything that is observing the referencing frame or
258
0
    // any of its ancestors that the referencing frame has been invalidated.
259
0
    // Since walking the parent chain checking for observers is expensive we
260
0
    // do that using a change hint (multiple change hints of the same type are
261
0
    // coalesced).
262
0
    nsLayoutUtils::PostRestyleEvent(
263
0
      frame->GetContent()->AsElement(), nsRestyleHint(0),
264
0
      nsChangeHint_InvalidateRenderingObservers);
265
0
  }
266
0
}
267
268
269
NS_IMPL_CYCLE_COLLECTING_ADDREF(SVGFilterObserver)
270
NS_IMPL_CYCLE_COLLECTING_RELEASE(SVGFilterObserver)
271
272
0
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(SVGFilterObserver)
273
0
  NS_INTERFACE_MAP_ENTRY(nsISupports)
274
0
  NS_INTERFACE_MAP_ENTRY(nsIMutationObserver)
275
0
  NS_INTERFACE_MAP_ENTRY(SVGFilterObserver)
276
0
NS_INTERFACE_MAP_END
277
278
NS_IMPL_CYCLE_COLLECTION_CLASS(SVGFilterObserver)
279
280
0
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(SVGFilterObserver)
281
0
  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mObservedElementTracker)
282
0
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
283
284
0
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(SVGFilterObserver)
285
0
  tmp->StopObserving();
286
0
  NS_IMPL_CYCLE_COLLECTION_UNLINK(mObservedElementTracker);
287
0
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
288
289
nsSVGFilterFrame *
290
SVGFilterObserver::GetFilterFrame()
291
0
{
292
0
  return static_cast<nsSVGFilterFrame*>(
293
0
    GetReferencedFrame(LayoutFrameType::SVGFilter, nullptr));
294
0
}
295
296
void
297
SVGFilterObserver::OnRenderingChange()
298
0
{
299
0
  SVGIDRenderingObserver::OnRenderingChange();
300
0
301
0
  if (mFilterObserverList) {
302
0
    mFilterObserverList->Invalidate();
303
0
  }
304
0
}
305
306
NS_IMPL_CYCLE_COLLECTING_ADDREF(SVGFilterObserverList)
307
NS_IMPL_CYCLE_COLLECTING_RELEASE(SVGFilterObserverList)
308
309
NS_IMPL_CYCLE_COLLECTION_CLASS(SVGFilterObserverList)
310
311
0
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(SVGFilterObserverList)
312
0
  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mObservers)
313
0
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
314
315
0
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(SVGFilterObserverList)
316
0
  tmp->DetachObservers();
317
0
  NS_IMPL_CYCLE_COLLECTION_UNLINK(mObservers);
318
0
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
319
320
0
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(SVGFilterObserverList)
321
0
  NS_INTERFACE_MAP_ENTRY(nsISupports)
322
0
NS_INTERFACE_MAP_END
323
324
SVGFilterObserverList::SVGFilterObserverList(const nsTArray<nsStyleFilter>& aFilters,
325
                                             nsIContent* aFilteredElement,
326
                                             nsIFrame* aFilteredFrame)
327
0
{
328
0
  for (uint32_t i = 0; i < aFilters.Length(); i++) {
329
0
    if (aFilters[i].GetType() != NS_STYLE_FILTER_URL)
330
0
      continue;
331
0
332
0
    // aFilteredFrame can be null if this filter belongs to a
333
0
    // CanvasRenderingContext2D.
334
0
    RefPtr<URLAndReferrerInfo> filterURL;
335
0
    if (aFilteredFrame) {
336
0
      filterURL = SVGObserverUtils::GetFilterURI(aFilteredFrame, i);
337
0
    } else {
338
0
      nsCOMPtr<nsIURI> resolvedURI =
339
0
        aFilters[i].GetURL()->ResolveLocalRef(aFilteredElement);
340
0
      if (resolvedURI) {
341
0
        filterURL = new URLAndReferrerInfo(
342
0
          resolvedURI,
343
0
          aFilters[i].GetURL()->mExtraData->GetReferrer(),
344
0
          aFilters[i].GetURL()->mExtraData->GetReferrerPolicy());
345
0
      }
346
0
    }
347
0
348
0
    RefPtr<SVGFilterObserver> observer =
349
0
      new SVGFilterObserver(filterURL, aFilteredElement, this);
350
0
    mObservers.AppendElement(observer);
351
0
  }
352
0
}
353
354
SVGFilterObserverList::~SVGFilterObserverList()
355
0
{
356
0
  DetachObservers();
357
0
}
358
359
bool
360
SVGFilterObserverList::ReferencesValidResources()
361
0
{
362
0
  for (uint32_t i = 0; i < mObservers.Length(); i++) {
363
0
    if (!mObservers[i]->ReferencesValidResource()) {
364
0
      return false;
365
0
    }
366
0
  }
367
0
  return true;
368
0
}
369
370
bool
371
SVGFilterObserverList::IsInObserverLists() const
372
0
{
373
0
  for (uint32_t i = 0; i < mObservers.Length(); i++) {
374
0
    if (!mObservers[i]->IsInObserverList()) {
375
0
      return false;
376
0
    }
377
0
  }
378
0
  return true;
379
0
}
380
381
void
382
SVGFilterObserverListForCSSProp::OnRenderingChange()
383
0
{
384
0
  nsIFrame* frame = mFrameReference.Get();
385
0
  if (!frame)
386
0
    return;
387
0
388
0
  // Repaint asynchronously in case the filter frame is being torn down
389
0
  nsChangeHint changeHint =
390
0
    nsChangeHint(nsChangeHint_RepaintFrame);
391
0
392
0
  // Since we don't call nsSVGRenderingObserverProperty::
393
0
  // OnRenderingChange, we have to add this bit ourselves.
394
0
  if (frame->HasAllStateBits(NS_FRAME_SVG_LAYOUT)) {
395
0
    // Changes should propagate out to things that might be observing
396
0
    // the referencing frame or its ancestors.
397
0
    changeHint |= nsChangeHint_InvalidateRenderingObservers;
398
0
  }
399
0
400
0
  // Don't need to request UpdateOverflow if we're being reflowed.
401
0
  if (!(frame->GetStateBits() & NS_FRAME_IN_REFLOW)) {
402
0
    changeHint |= nsChangeHint_UpdateOverflow;
403
0
  }
404
0
  frame->PresContext()->RestyleManager()->PostRestyleEvent(
405
0
    frame->GetContent()->AsElement(), nsRestyleHint(0), changeHint);
406
0
}
407
408
void
409
SVGMarkerObserver::OnRenderingChange()
410
0
{
411
0
  nsSVGRenderingObserverProperty::OnRenderingChange();
412
0
413
0
  nsIFrame* frame = mFrameReference.Get();
414
0
  if (!frame)
415
0
    return;
416
0
417
0
  NS_ASSERTION(frame->IsFrameOfType(nsIFrame::eSVG), "SVG frame expected");
418
0
419
0
  // Don't need to request ReflowFrame if we're being reflowed.
420
0
  if (!(frame->GetStateBits() & NS_FRAME_IN_REFLOW)) {
421
0
    // XXXjwatt: We need to unify SVG into standard reflow so we can just use
422
0
    // nsChangeHint_NeedReflow | nsChangeHint_NeedDirtyReflow here.
423
0
    // XXXSDL KILL THIS!!!
424
0
    nsSVGUtils::ScheduleReflowSVG(frame);
425
0
  }
426
0
  frame->PresContext()->RestyleManager()->PostRestyleEvent(
427
0
    frame->GetContent()->AsElement(), nsRestyleHint(0),
428
0
    nsChangeHint_RepaintFrame);
429
0
}
430
431
NS_IMPL_ISUPPORTS(SVGMaskObserverList, nsISupports)
432
433
SVGMaskObserverList::SVGMaskObserverList(nsIFrame* aFrame)
434
 : mFrame(aFrame)
435
0
{
436
0
  const nsStyleSVGReset *svgReset = aFrame->StyleSVGReset();
437
0
438
0
  for (uint32_t i = 0; i < svgReset->mMask.mImageCount; i++) {
439
0
    RefPtr<URLAndReferrerInfo> maskUri =
440
0
      SVGObserverUtils::GetMaskURI(aFrame, i);
441
0
    bool hasRef = false;
442
0
    if (maskUri) {
443
0
      maskUri->GetURI()->GetHasRef(&hasRef);
444
0
    }
445
0
446
0
    // Accrording to maskUri, nsSVGPaintingProperty's ctor may trigger an
447
0
    // external SVG resource download, so we should pass maskUri in only if
448
0
    // maskUri has a chance pointing to an SVG mask resource.
449
0
    //
450
0
    // And, an URL may refer to an SVG mask resource if it consists of
451
0
    // a fragment.
452
0
    nsSVGPaintingProperty* prop =
453
0
      new nsSVGPaintingProperty(hasRef ? maskUri.get() : nullptr,
454
0
                                aFrame, false);
455
0
    mProperties.AppendElement(prop);
456
0
  }
457
0
}
458
459
void
460
SVGMaskObserverList::ResolveImage(uint32_t aIndex)
461
0
{
462
0
  const nsStyleSVGReset* svgReset = mFrame->StyleSVGReset();
463
0
  MOZ_ASSERT(aIndex < svgReset->mMask.mImageCount);
464
0
465
0
  nsStyleImage& image =
466
0
    const_cast<nsStyleImage&>(svgReset->mMask.mLayers[aIndex].mImage);
467
0
468
0
  if (!image.IsResolved()) {
469
0
    MOZ_ASSERT(image.GetType() == nsStyleImageType::eStyleImageType_Image);
470
0
    image.ResolveImage(mFrame->PresContext(), nullptr);
471
0
472
0
    mozilla::css::ImageLoader* imageLoader =
473
0
      mFrame->PresContext()->Document()->StyleImageLoader();
474
0
    if (imgRequestProxy* req = image.GetImageData()) {
475
0
      imageLoader->AssociateRequestToFrame(req, mFrame, 0);
476
0
    }
477
0
  }
478
0
}
479
480
bool
481
SVGTextPathObserver::TargetIsValid()
482
0
{
483
0
  Element* target = GetTarget();
484
0
  return target && target->IsSVGElement(nsGkAtoms::path);
485
0
}
486
487
void
488
SVGTextPathObserver::OnRenderingChange()
489
0
{
490
0
  nsSVGRenderingObserverProperty::OnRenderingChange();
491
0
492
0
  nsIFrame* frame = mFrameReference.Get();
493
0
  if (!frame)
494
0
    return;
495
0
496
0
  NS_ASSERTION(frame->IsFrameOfType(nsIFrame::eSVG) ||
497
0
               nsSVGUtils::IsInSVGTextSubtree(frame),
498
0
               "SVG frame expected");
499
0
500
0
  // Avoid getting into an infinite loop of reflows if the <textPath> is
501
0
  // pointing to one of its ancestors.  TargetIsValid returns true iff
502
0
  // the target element is a <path> element, and we would not have this
503
0
  // SVGTextPathObserver if this <textPath> were a descendant of the
504
0
  // target <path>.
505
0
  //
506
0
  // Note that we still have to post the restyle event when we
507
0
  // change from being valid to invalid, so that mPositions on the
508
0
  // SVGTextFrame gets updated, skipping the <textPath>, ensuring
509
0
  // that nothing gets painted for that element.
510
0
  bool nowValid = TargetIsValid();
511
0
  if (!mValid && !nowValid) {
512
0
    // Just return if we were previously invalid, and are still invalid.
513
0
    return;
514
0
  }
515
0
  mValid = nowValid;
516
0
517
0
  // Repaint asynchronously in case the path frame is being torn down
518
0
  nsChangeHint changeHint =
519
0
    nsChangeHint(nsChangeHint_RepaintFrame | nsChangeHint_UpdateTextPath);
520
0
  frame->PresContext()->RestyleManager()->PostRestyleEvent(
521
0
    frame->GetContent()->AsElement(), nsRestyleHint(0), changeHint);
522
0
}
523
524
static void
525
InvalidateAllContinuations(nsIFrame* aFrame)
526
0
{
527
0
  for (nsIFrame* f = aFrame; f;
528
0
       f = nsLayoutUtils::GetNextContinuationOrIBSplitSibling(f)) {
529
0
    f->InvalidateFrame();
530
0
  }
531
0
}
532
533
void
534
nsSVGPaintingProperty::OnRenderingChange()
535
0
{
536
0
  nsSVGRenderingObserverProperty::OnRenderingChange();
537
0
538
0
  nsIFrame* frame = mFrameReference.Get();
539
0
  if (!frame)
540
0
    return;
541
0
542
0
  if (frame->GetStateBits() & NS_FRAME_SVG_LAYOUT) {
543
0
    frame->InvalidateFrameSubtree();
544
0
  } else {
545
0
    InvalidateAllContinuations(frame);
546
0
  }
547
0
}
548
549
static SVGFilterObserverListForCSSProp*
550
GetOrCreateFilterObserverListForCSS(nsIFrame* aFrame)
551
0
{
552
0
  const nsStyleEffects* effects = aFrame->StyleEffects();
553
0
  if (!effects->HasFilters())
554
0
    return nullptr;
555
0
556
0
  SVGFilterObserverListForCSSProp* observers =
557
0
    aFrame->GetProperty(SVGObserverUtils::FilterProperty());
558
0
  if (observers) {
559
0
    return observers;
560
0
  }
561
0
  observers = new SVGFilterObserverListForCSSProp(effects->mFilters, aFrame);
562
0
  NS_ADDREF(observers);
563
0
  aFrame->SetProperty(SVGObserverUtils::FilterProperty(), observers);
564
0
  return observers;
565
0
}
566
567
static SVGMaskObserverList*
568
GetOrCreateMaskProperty(nsIFrame* aFrame)
569
0
{
570
0
  SVGMaskObserverList *prop =
571
0
    aFrame->GetProperty(SVGObserverUtils::MaskProperty());
572
0
  if (prop)
573
0
    return prop;
574
0
575
0
  prop = new SVGMaskObserverList(aFrame);
576
0
  NS_ADDREF(prop);
577
0
  aFrame->SetProperty(SVGObserverUtils::MaskProperty(), prop);
578
0
  return prop;
579
0
}
580
581
template<class T>
582
static T*
583
GetEffectProperty(URLAndReferrerInfo* aURI, nsIFrame* aFrame,
584
  const mozilla::FramePropertyDescriptor<T>* aProperty)
585
0
{
586
0
  if (!aURI)
587
0
    return nullptr;
588
0
589
0
  T* prop = aFrame->GetProperty(aProperty);
590
0
  if (prop)
591
0
    return prop;
592
0
  prop = new T(aURI, aFrame, false);
593
0
  NS_ADDREF(prop);
594
0
  aFrame->SetProperty(aProperty, prop);
595
0
  return prop;
596
0
}
Unexecuted instantiation: Unified_cpp_layout_svg0.cpp:mozilla::SVGMarkerObserver* mozilla::GetEffectProperty<mozilla::SVGMarkerObserver>(mozilla::URLAndReferrerInfo*, nsIFrame*, mozilla::FramePropertyDescriptor<mozilla::SVGMarkerObserver> const*)
Unexecuted instantiation: Unified_cpp_layout_svg0.cpp:mozilla::SVGTextPathObserver* mozilla::GetEffectProperty<mozilla::SVGTextPathObserver>(mozilla::URLAndReferrerInfo*, nsIFrame*, mozilla::FramePropertyDescriptor<mozilla::SVGTextPathObserver> const*)
Unexecuted instantiation: Unified_cpp_layout_svg0.cpp:mozilla::SVGTemplateElementObserver* mozilla::GetEffectProperty<mozilla::SVGTemplateElementObserver>(mozilla::URLAndReferrerInfo*, nsIFrame*, mozilla::FramePropertyDescriptor<mozilla::SVGTemplateElementObserver> const*)
Unexecuted instantiation: Unified_cpp_layout_svg0.cpp:mozilla::nsSVGPaintingProperty* mozilla::GetEffectProperty<mozilla::nsSVGPaintingProperty>(mozilla::URLAndReferrerInfo*, nsIFrame*, mozilla::FramePropertyDescriptor<mozilla::nsSVGPaintingProperty> const*)
597
598
bool
599
SVGObserverUtils::GetMarkerFrames(nsIFrame* aMarkedFrame,
600
                                  nsSVGMarkerFrame*(*aFrames)[3])
601
0
{
602
0
  MOZ_ASSERT(!aMarkedFrame->GetPrevContinuation() &&
603
0
             aMarkedFrame->IsSVGGeometryFrame() &&
604
0
             static_cast<SVGGeometryElement*>(aMarkedFrame->GetContent())->IsMarkable(),
605
0
             "Bad frame");
606
0
607
0
  bool foundMarker = false;
608
0
  RefPtr<URLAndReferrerInfo> markerURL;
609
0
  SVGMarkerObserver* observer;
610
0
  nsIFrame* marker;
611
0
612
0
#define GET_MARKER(type)                                                      \
613
0
  markerURL = GetMarkerURI(aMarkedFrame, &nsStyleSVG::mMarker##type);         \
614
0
  observer = GetEffectProperty(markerURL, aMarkedFrame,                       \
615
0
                               SVGObserverUtils::Marker##type##Property());   \
616
0
  marker = observer ?                                                         \
617
0
           observer->GetReferencedFrame(LayoutFrameType::SVGMarker, nullptr) :\
618
0
           nullptr;                                                           \
619
0
  foundMarker = foundMarker || bool(marker);                                  \
620
0
  (*aFrames)[nsSVGMark::e##type] = static_cast<nsSVGMarkerFrame*>(marker);
621
0
622
0
  GET_MARKER(Start)
623
0
  GET_MARKER(Mid)
624
0
  GET_MARKER(End)
625
0
626
0
#undef GET_MARKER
627
0
628
0
  return foundMarker;
629
0
}
630
631
SVGGeometryElement*
632
SVGObserverUtils::GetTextPathsReferencedPath(nsIFrame* aTextPathFrame)
633
0
{
634
0
  SVGTextPathObserver* property =
635
0
    aTextPathFrame->GetProperty(SVGObserverUtils::HrefAsTextPathProperty());
636
0
637
0
  if (!property) {
638
0
    nsIContent* content = aTextPathFrame->GetContent();
639
0
    nsAutoString href;
640
0
    static_cast<SVGTextPathElement*>(content)->HrefAsString(href);
641
0
    if (href.IsEmpty()) {
642
0
      return nullptr; // no URL
643
0
    }
644
0
645
0
    nsCOMPtr<nsIURI> targetURI;
646
0
    nsCOMPtr<nsIURI> base = content->GetBaseURI();
647
0
    nsContentUtils::NewURIWithDocumentCharset(getter_AddRefs(targetURI), href,
648
0
                                              content->GetUncomposedDoc(), base);
649
0
650
0
    // There's no clear refererer policy spec about non-CSS SVG resource references
651
0
    // Bug 1415044 to investigate which referrer we should use
652
0
    RefPtr<URLAndReferrerInfo> target =
653
0
      new URLAndReferrerInfo(targetURI,
654
0
                             content->OwnerDoc()->GetDocumentURI(),
655
0
                             content->OwnerDoc()->GetReferrerPolicy());
656
0
657
0
    property = GetEffectProperty(target, aTextPathFrame,
658
0
                                 HrefAsTextPathProperty());
659
0
    if (!property) {
660
0
      return nullptr;
661
0
    }
662
0
  }
663
0
664
0
  Element* element = property->GetReferencedElement();
665
0
  return (element && element->IsNodeOfType(nsINode::eSHAPE)) ?
666
0
    static_cast<SVGGeometryElement*>(element) : nullptr;
667
0
}
668
669
void
670
SVGObserverUtils::RemoveTextPathObserver(nsIFrame* aTextPathFrame)
671
0
{
672
0
  aTextPathFrame->DeleteProperty(HrefAsTextPathProperty());
673
0
}
674
675
SVGTemplateElementObserver*
676
SVGObserverUtils::GetTemplateElementObserver(URLAndReferrerInfo* aURI,
677
  nsIFrame* aFrame,
678
  const mozilla::FramePropertyDescriptor<SVGTemplateElementObserver>* aProperty)
679
0
{
680
0
  return GetEffectProperty(aURI, aFrame, aProperty);
681
0
}
682
683
nsSVGPaintingProperty*
684
SVGObserverUtils::GetPaintingProperty(URLAndReferrerInfo* aURI, nsIFrame* aFrame,
685
  const mozilla::FramePropertyDescriptor<nsSVGPaintingProperty>* aProperty)
686
0
{
687
0
  return GetEffectProperty(aURI, aFrame, aProperty);
688
0
}
689
690
nsSVGPaintingProperty*
691
SVGObserverUtils::GetPaintingPropertyForURI(URLAndReferrerInfo* aURI,
692
  nsIFrame* aFrame,
693
  URIObserverHashtablePropertyDescriptor aProperty)
694
0
{
695
0
  if (!aURI)
696
0
    return nullptr;
697
0
698
0
  SVGObserverUtils::URIObserverHashtable *hashtable =
699
0
    aFrame->GetProperty(aProperty);
700
0
  if (!hashtable) {
701
0
    hashtable = new SVGObserverUtils::URIObserverHashtable();
702
0
    aFrame->SetProperty(aProperty, hashtable);
703
0
  }
704
0
  nsSVGPaintingProperty* prop =
705
0
    static_cast<nsSVGPaintingProperty*>(hashtable->GetWeak(aURI));
706
0
  if (!prop) {
707
0
    bool watchImage = aProperty == SVGObserverUtils::BackgroundImageProperty();
708
0
    prop = new nsSVGPaintingProperty(aURI, aFrame, watchImage);
709
0
    hashtable->Put(aURI, prop);
710
0
  }
711
0
  return prop;
712
0
}
713
714
SVGObserverUtils::EffectProperties
715
SVGObserverUtils::GetEffectProperties(nsIFrame* aFrame)
716
0
{
717
0
  NS_ASSERTION(!aFrame->GetPrevContinuation(), "aFrame should be first continuation");
718
0
719
0
  EffectProperties result;
720
0
  const nsStyleSVGReset *style = aFrame->StyleSVGReset();
721
0
722
0
  result.mFilterObservers = GetOrCreateFilterObserverListForCSS(aFrame);
723
0
724
0
  if (style->mClipPath.GetType() == StyleShapeSourceType::URL) {
725
0
    RefPtr<URLAndReferrerInfo> pathURI = SVGObserverUtils::GetClipPathURI(aFrame);
726
0
    result.mClipPath =
727
0
      GetPaintingProperty(pathURI, aFrame, ClipPathProperty());
728
0
  } else {
729
0
    result.mClipPath = nullptr;
730
0
  }
731
0
732
0
  MOZ_ASSERT(style->mMask.mImageCount > 0);
733
0
  result.mMaskObservers = style->HasMask()
734
0
                          ? GetOrCreateMaskProperty(aFrame) : nullptr;
735
0
736
0
  return result;
737
0
}
738
739
nsSVGPaintServerFrame *
740
SVGObserverUtils::GetPaintServer(nsIFrame* aTargetFrame,
741
                                 nsStyleSVGPaint nsStyleSVG::* aPaint)
742
0
{
743
0
  // If we're looking at a frame within SVG text, then we need to look up
744
0
  // to find the right frame to get the painting property off.  We should at
745
0
  // least look up past a text frame, and if the text frame's parent is the
746
0
  // anonymous block frame, then we look up to its parent (the SVGTextFrame).
747
0
  nsIFrame* frame = aTargetFrame;
748
0
  if (frame->GetContent()->IsText()) {
749
0
    frame = frame->GetParent();
750
0
    nsIFrame* grandparent = frame->GetParent();
751
0
    if (grandparent && grandparent->IsSVGTextFrame()) {
752
0
      frame = grandparent;
753
0
    }
754
0
  }
755
0
756
0
  const nsStyleSVG* svgStyle = frame->StyleSVG();
757
0
  if ((svgStyle->*aPaint).Type() != eStyleSVGPaintType_Server)
758
0
    return nullptr;
759
0
760
0
  RefPtr<URLAndReferrerInfo> paintServerURL =
761
0
    SVGObserverUtils::GetPaintURI(frame, aPaint);
762
0
  MOZ_ASSERT(aPaint == &nsStyleSVG::mFill || aPaint == &nsStyleSVG::mStroke);
763
0
  PaintingPropertyDescriptor propDesc = (aPaint == &nsStyleSVG::mFill) ?
764
0
                                        SVGObserverUtils::FillProperty() :
765
0
                                        SVGObserverUtils::StrokeProperty();
766
0
  nsSVGPaintingProperty *property =
767
0
    SVGObserverUtils::GetPaintingProperty(paintServerURL, frame, propDesc);
768
0
  if (!property)
769
0
    return nullptr;
770
0
  nsIFrame* result = property->GetReferencedFrame();
771
0
  if (!result)
772
0
    return nullptr;
773
0
774
0
  LayoutFrameType type = result->Type();
775
0
  if (type != LayoutFrameType::SVGLinearGradient &&
776
0
      type != LayoutFrameType::SVGRadialGradient &&
777
0
      type != LayoutFrameType::SVGPattern)
778
0
    return nullptr;
779
0
780
0
  return static_cast<nsSVGPaintServerFrame*>(result);
781
0
}
782
783
nsSVGClipPathFrame *
784
SVGObserverUtils::EffectProperties::GetClipPathFrame()
785
0
{
786
0
  if (!mClipPath)
787
0
    return nullptr;
788
0
789
0
  nsSVGClipPathFrame* frame = static_cast<nsSVGClipPathFrame*>(
790
0
    mClipPath->GetReferencedFrame(LayoutFrameType::SVGClipPath, nullptr));
791
0
792
0
  return frame;
793
0
}
794
795
nsTArray<nsSVGMaskFrame *>
796
SVGObserverUtils::EffectProperties::GetMaskFrames()
797
0
{
798
0
  nsTArray<nsSVGMaskFrame *> result;
799
0
  if (!mMaskObservers) {
800
0
    return result;
801
0
  }
802
0
803
0
  bool ok = true;
804
0
  const nsTArray<RefPtr<nsSVGPaintingProperty>>& observers =
805
0
    mMaskObservers->GetObservers();
806
0
  for (size_t i = 0; i < observers.Length(); i++) {
807
0
    nsSVGMaskFrame* maskFrame = static_cast<nsSVGMaskFrame*>(
808
0
      observers[i]->GetReferencedFrame(LayoutFrameType::SVGMask, &ok));
809
0
    MOZ_ASSERT(!maskFrame || ok);
810
0
    if (!ok) {
811
0
      // We can not find the specific SVG mask resource in the downloaded SVG
812
0
      // document. There are two possibilities:
813
0
      // 1. The given resource id is invalid.
814
0
      // 2. The given resource id refers to a viewbox.
815
0
      //
816
0
      // Hand it over to the style image.
817
0
      mMaskObservers->ResolveImage(i);
818
0
    }
819
0
    result.AppendElement(maskFrame);
820
0
  }
821
0
822
0
  return result;
823
0
}
824
825
bool
826
SVGObserverUtils::EffectProperties::HasNoOrValidEffects()
827
0
{
828
0
  return HasNoOrValidClipPath() && HasNoOrValidMask() && HasNoOrValidFilter();
829
0
}
830
831
bool
832
SVGObserverUtils::EffectProperties::HasNoOrValidClipPath()
833
0
{
834
0
  if (mClipPath) {
835
0
    bool ok = true;
836
0
    nsSVGClipPathFrame* frame = static_cast<nsSVGClipPathFrame*>(
837
0
      mClipPath->GetReferencedFrame(LayoutFrameType::SVGClipPath, &ok));
838
0
    if (!ok || (frame && !frame->IsValid())) {
839
0
      return false;
840
0
    }
841
0
  }
842
0
843
0
  return true;
844
0
}
845
846
bool
847
SVGObserverUtils::EffectProperties::HasNoOrValidMask()
848
0
{
849
0
  if (mMaskObservers) {
850
0
    bool ok = true;
851
0
    const nsTArray<RefPtr<nsSVGPaintingProperty>>& observers =
852
0
      mMaskObservers->GetObservers();
853
0
    for (size_t i = 0; i < observers.Length(); i++) {
854
0
      observers[i]->GetReferencedFrame(LayoutFrameType::SVGMask, &ok);
855
0
      if (!ok) {
856
0
        return false;
857
0
      }
858
0
    }
859
0
  }
860
0
861
0
  return true;
862
0
}
863
864
void
865
SVGObserverUtils::UpdateEffects(nsIFrame* aFrame)
866
0
{
867
0
  NS_ASSERTION(aFrame->GetContent()->IsElement(),
868
0
               "aFrame's content should be an element");
869
0
870
0
  aFrame->DeleteProperty(FilterProperty());
871
0
  aFrame->DeleteProperty(MaskProperty());
872
0
  aFrame->DeleteProperty(ClipPathProperty());
873
0
  aFrame->DeleteProperty(MarkerStartProperty());
874
0
  aFrame->DeleteProperty(MarkerMidProperty());
875
0
  aFrame->DeleteProperty(MarkerEndProperty());
876
0
  aFrame->DeleteProperty(FillProperty());
877
0
  aFrame->DeleteProperty(StrokeProperty());
878
0
  aFrame->DeleteProperty(BackgroundImageProperty());
879
0
880
0
  // Ensure that the filter is repainted correctly
881
0
  // We can't do that in OnRenderingChange as the referenced frame may
882
0
  // not be valid
883
0
  GetOrCreateFilterObserverListForCSS(aFrame);
884
0
885
0
  if (aFrame->IsSVGGeometryFrame() &&
886
0
      static_cast<SVGGeometryElement*>(aFrame->GetContent())->IsMarkable()) {
887
0
    // Set marker properties here to avoid reference loops
888
0
    RefPtr<URLAndReferrerInfo> markerURL =
889
0
      GetMarkerURI(aFrame, &nsStyleSVG::mMarkerStart);
890
0
    GetEffectProperty(markerURL, aFrame, MarkerStartProperty());
891
0
    markerURL = GetMarkerURI(aFrame, &nsStyleSVG::mMarkerMid);
892
0
    GetEffectProperty(markerURL, aFrame, MarkerMidProperty());
893
0
    markerURL = GetMarkerURI(aFrame, &nsStyleSVG::mMarkerEnd);
894
0
    GetEffectProperty(markerURL, aFrame, MarkerEndProperty());
895
0
  }
896
0
}
897
898
SVGFilterObserverListForCSSProp*
899
SVGObserverUtils::GetFilterObserverList(nsIFrame* aFrame)
900
0
{
901
0
  NS_ASSERTION(!aFrame->GetPrevContinuation(), "aFrame should be first continuation");
902
0
903
0
  if (!aFrame->StyleEffects()->HasFilters())
904
0
    return nullptr;
905
0
906
0
  return aFrame->GetProperty(FilterProperty());
907
0
}
908
909
void
910
SVGRenderingObserverList::InvalidateAll()
911
0
{
912
0
  if (mObservers.Count() == 0)
913
0
    return;
914
0
915
0
  AutoTArray<SVGRenderingObserver*,10> observers;
916
0
917
0
  for (auto it = mObservers.Iter(); !it.Done(); it.Next()) {
918
0
    observers.AppendElement(it.Get()->GetKey());
919
0
  }
920
0
  mObservers.Clear();
921
0
922
0
  for (uint32_t i = 0; i < observers.Length(); ++i) {
923
0
    observers[i]->OnNonDOMMutationRenderingChange();
924
0
  }
925
0
}
926
927
void
928
SVGRenderingObserverList::InvalidateAllForReflow()
929
0
{
930
0
  if (mObservers.Count() == 0)
931
0
    return;
932
0
933
0
  AutoTArray<SVGRenderingObserver*,10> observers;
934
0
935
0
  for (auto it = mObservers.Iter(); !it.Done(); it.Next()) {
936
0
    SVGRenderingObserver* obs = it.Get()->GetKey();
937
0
    if (obs->ObservesReflow()) {
938
0
      observers.AppendElement(obs);
939
0
      it.Remove();
940
0
    }
941
0
  }
942
0
943
0
  for (uint32_t i = 0; i < observers.Length(); ++i) {
944
0
    observers[i]->OnNonDOMMutationRenderingChange();
945
0
  }
946
0
}
947
948
void
949
SVGRenderingObserverList::RemoveAll()
950
0
{
951
0
  AutoTArray<SVGRenderingObserver*,10> observers;
952
0
953
0
  for (auto it = mObservers.Iter(); !it.Done(); it.Next()) {
954
0
    observers.AppendElement(it.Get()->GetKey());
955
0
  }
956
0
  mObservers.Clear();
957
0
958
0
  // Our list is now cleared.  We need to notify the observers we've removed,
959
0
  // so they can update their state & remove themselves as mutation-observers.
960
0
  for (uint32_t i = 0; i < observers.Length(); ++i) {
961
0
    observers[i]->NotifyEvictedFromRenderingObserverList();
962
0
  }
963
0
}
964
965
void
966
SVGObserverUtils::AddRenderingObserver(Element* aElement,
967
                                       SVGRenderingObserver* aObserver)
968
0
{
969
0
  SVGRenderingObserverList* observerList = GetObserverList(aElement);
970
0
  if (!observerList) {
971
0
    observerList = new SVGRenderingObserverList();
972
0
    if (!observerList)
973
0
      return;
974
0
    aElement->SetProperty(nsGkAtoms::renderingobserverlist, observerList,
975
0
                          nsINode::DeleteProperty<SVGRenderingObserverList>);
976
0
  }
977
0
  aElement->SetHasRenderingObservers(true);
978
0
  observerList->Add(aObserver);
979
0
}
980
981
void
982
SVGObserverUtils::RemoveRenderingObserver(Element* aElement,
983
                                          SVGRenderingObserver* aObserver)
984
0
{
985
0
  SVGRenderingObserverList* observerList = GetObserverList(aElement);
986
0
  if (observerList) {
987
0
    NS_ASSERTION(observerList->Contains(aObserver),
988
0
                 "removing observer from an element we're not observing?");
989
0
    observerList->Remove(aObserver);
990
0
    if (observerList->IsEmpty()) {
991
0
      aElement->SetHasRenderingObservers(false);
992
0
    }
993
0
  }
994
0
}
995
996
void
997
SVGObserverUtils::RemoveAllRenderingObservers(Element* aElement)
998
0
{
999
0
  SVGRenderingObserverList* observerList = GetObserverList(aElement);
1000
0
  if (observerList) {
1001
0
    observerList->RemoveAll();
1002
0
    aElement->SetHasRenderingObservers(false);
1003
0
  }
1004
0
}
1005
1006
void
1007
SVGObserverUtils::InvalidateRenderingObservers(nsIFrame* aFrame)
1008
0
{
1009
0
  NS_ASSERTION(!aFrame->GetPrevContinuation(), "aFrame must be first continuation");
1010
0
1011
0
  nsIContent* content = aFrame->GetContent();
1012
0
  if (!content || !content->IsElement())
1013
0
    return;
1014
0
1015
0
  // If the rendering has changed, the bounds may well have changed too:
1016
0
  aFrame->DeleteProperty(nsSVGUtils::ObjectBoundingBoxProperty());
1017
0
1018
0
  SVGRenderingObserverList* observerList =
1019
0
    GetObserverList(content->AsElement());
1020
0
  if (observerList) {
1021
0
    observerList->InvalidateAll();
1022
0
    return;
1023
0
  }
1024
0
1025
0
  // Check ancestor SVG containers. The root frame cannot be of type
1026
0
  // eSVGContainer so we don't have to check f for null here.
1027
0
  for (nsIFrame *f = aFrame->GetParent();
1028
0
       f->IsFrameOfType(nsIFrame::eSVGContainer); f = f->GetParent()) {
1029
0
    if (f->GetContent()->IsElement()) {
1030
0
      observerList = GetObserverList(f->GetContent()->AsElement());
1031
0
      if (observerList) {
1032
0
        observerList->InvalidateAll();
1033
0
        return;
1034
0
      }
1035
0
    }
1036
0
  }
1037
0
}
1038
1039
void
1040
SVGObserverUtils::InvalidateDirectRenderingObservers(Element* aElement,
1041
                                                     uint32_t aFlags /* = 0 */)
1042
0
{
1043
0
  nsIFrame* frame = aElement->GetPrimaryFrame();
1044
0
  if (frame) {
1045
0
    // If the rendering has changed, the bounds may well have changed too:
1046
0
    frame->DeleteProperty(nsSVGUtils::ObjectBoundingBoxProperty());
1047
0
  }
1048
0
1049
0
  if (aElement->HasRenderingObservers()) {
1050
0
    SVGRenderingObserverList* observerList = GetObserverList(aElement);
1051
0
    if (observerList) {
1052
0
      if (aFlags & INVALIDATE_REFLOW) {
1053
0
        observerList->InvalidateAllForReflow();
1054
0
      } else {
1055
0
        observerList->InvalidateAll();
1056
0
      }
1057
0
    }
1058
0
  }
1059
0
}
1060
1061
void
1062
SVGObserverUtils::InvalidateDirectRenderingObservers(nsIFrame* aFrame,
1063
                                                     uint32_t aFlags /* = 0 */)
1064
0
{
1065
0
  nsIContent* content = aFrame->GetContent();
1066
0
  if (content && content->IsElement()) {
1067
0
    InvalidateDirectRenderingObservers(content->AsElement(), aFlags);
1068
0
  }
1069
0
}
1070
1071
already_AddRefed<nsIURI>
1072
SVGObserverUtils::GetBaseURLForLocalRef(nsIContent* content, nsIURI* aDocURI)
1073
0
{
1074
0
  MOZ_ASSERT(content);
1075
0
1076
0
  // For a local-reference URL, resolve that fragment against the current
1077
0
  // document that relative URLs are resolved against.
1078
0
  nsCOMPtr<nsIURI> baseURI = content->OwnerDoc()->GetDocumentURI();
1079
0
1080
0
  nsCOMPtr<nsIURI> originalURI;
1081
0
  // Content is in a shadow tree.  If this URL was specified in the subtree
1082
0
  // referenced by the <use>(or -moz-binding) element, and that subtree came
1083
0
  // from a separate resource document, then we want the fragment-only URL
1084
0
  // to resolve to an element from the resource document.  Otherwise, the
1085
0
  // URL was specified somewhere in the document with the <use> element, and
1086
0
  // we want the fragment-only URL to resolve to an element in that document.
1087
0
  if (SVGUseElement* use = content->GetContainingSVGUseShadowHost()) {
1088
0
    originalURI = use->GetSourceDocURI();
1089
0
  } else if (content->IsInAnonymousSubtree()) {
1090
0
    nsIContent* bindingParent = content->GetBindingParent();
1091
0
1092
0
    if (bindingParent) {
1093
0
      nsXBLBinding* binding = bindingParent->GetXBLBinding();
1094
0
      if (binding) {
1095
0
        originalURI = binding->GetSourceDocURI();
1096
0
      } else {
1097
0
        MOZ_ASSERT(content->IsInNativeAnonymousSubtree(),
1098
0
                   "a non-native anonymous tree which is not from "
1099
0
                   "an XBL binding?");
1100
0
      }
1101
0
    }
1102
0
  }
1103
0
1104
0
  if (originalURI) {
1105
0
    bool isEqualsExceptRef = false;
1106
0
    aDocURI->EqualsExceptRef(originalURI, &isEqualsExceptRef);
1107
0
    if (isEqualsExceptRef) {
1108
0
      return originalURI.forget();
1109
0
    }
1110
0
  }
1111
0
1112
0
  return baseURI.forget();
1113
0
}
1114
1115
static already_AddRefed<URLAndReferrerInfo>
1116
ResolveURLUsingLocalRef(nsIFrame* aFrame, const css::URLValueData* aURL)
1117
0
{
1118
0
  MOZ_ASSERT(aFrame);
1119
0
1120
0
  if (!aURL) {
1121
0
    return nullptr;
1122
0
  }
1123
0
1124
0
  nsCOMPtr<nsIURI> uri = aURL->GetURI();
1125
0
  RefPtr<URLAndReferrerInfo> result;
1126
0
1127
0
  // Non-local-reference URL.
1128
0
  if (!aURL->IsLocalRef()) {
1129
0
    if (!uri) {
1130
0
      return nullptr;
1131
0
    }
1132
0
    result = new URLAndReferrerInfo(uri,
1133
0
                                    aURL->mExtraData->GetReferrer(),
1134
0
                                    aURL->mExtraData->GetReferrerPolicy());
1135
0
    return result.forget();
1136
0
  }
1137
0
1138
0
  nsCOMPtr<nsIURI> baseURI =
1139
0
    SVGObserverUtils::GetBaseURLForLocalRef(aFrame->GetContent(), uri);
1140
0
1141
0
  nsCOMPtr<nsIURI> resolvedURI = aURL->ResolveLocalRef(baseURI);
1142
0
  if (!resolvedURI) {
1143
0
    return nullptr;
1144
0
  }
1145
0
1146
0
  result = new URLAndReferrerInfo(resolvedURI,
1147
0
                                  aURL->mExtraData->GetReferrer(),
1148
0
                                  aURL->mExtraData->GetReferrerPolicy());
1149
0
  return result.forget();
1150
0
}
1151
1152
already_AddRefed<URLAndReferrerInfo>
1153
SVGObserverUtils::GetMarkerURI(nsIFrame* aFrame,
1154
                               RefPtr<css::URLValue> nsStyleSVG::* aMarker)
1155
0
{
1156
0
  return ResolveURLUsingLocalRef(aFrame, aFrame->StyleSVG()->*aMarker);
1157
0
}
1158
1159
already_AddRefed<URLAndReferrerInfo>
1160
SVGObserverUtils::GetClipPathURI(nsIFrame* aFrame)
1161
0
{
1162
0
  const nsStyleSVGReset* svgResetStyle = aFrame->StyleSVGReset();
1163
0
  MOZ_ASSERT(svgResetStyle->mClipPath.GetType() == StyleShapeSourceType::URL);
1164
0
1165
0
  css::URLValue* url = svgResetStyle->mClipPath.GetURL();
1166
0
  return ResolveURLUsingLocalRef(aFrame, url);
1167
0
}
1168
1169
already_AddRefed<URLAndReferrerInfo>
1170
SVGObserverUtils::GetFilterURI(nsIFrame* aFrame, uint32_t aIndex)
1171
0
{
1172
0
  const nsStyleEffects* effects = aFrame->StyleEffects();
1173
0
  MOZ_ASSERT(effects->mFilters.Length() > aIndex);
1174
0
  MOZ_ASSERT(effects->mFilters[aIndex].GetType() == NS_STYLE_FILTER_URL);
1175
0
1176
0
  return ResolveURLUsingLocalRef(aFrame, effects->mFilters[aIndex].GetURL());
1177
0
}
1178
1179
already_AddRefed<URLAndReferrerInfo>
1180
SVGObserverUtils::GetFilterURI(nsIFrame* aFrame, const nsStyleFilter& aFilter)
1181
0
{
1182
0
  MOZ_ASSERT(aFrame->StyleEffects()->mFilters.Length());
1183
0
  MOZ_ASSERT(aFilter.GetType() == NS_STYLE_FILTER_URL);
1184
0
1185
0
  return ResolveURLUsingLocalRef(aFrame, aFilter.GetURL());
1186
0
}
1187
1188
already_AddRefed<URLAndReferrerInfo>
1189
SVGObserverUtils::GetPaintURI(nsIFrame* aFrame,
1190
                              nsStyleSVGPaint nsStyleSVG::* aPaint)
1191
0
{
1192
0
  const nsStyleSVG* svgStyle = aFrame->StyleSVG();
1193
0
  MOZ_ASSERT((svgStyle->*aPaint).Type() ==
1194
0
             nsStyleSVGPaintType::eStyleSVGPaintType_Server);
1195
0
1196
0
  return ResolveURLUsingLocalRef(aFrame,
1197
0
                                 (svgStyle->*aPaint).GetPaintServer());
1198
0
}
1199
1200
already_AddRefed<URLAndReferrerInfo>
1201
SVGObserverUtils::GetMaskURI(nsIFrame* aFrame, uint32_t aIndex)
1202
0
{
1203
0
  const nsStyleSVGReset* svgReset = aFrame->StyleSVGReset();
1204
0
  MOZ_ASSERT(svgReset->mMask.mLayers.Length() > aIndex);
1205
0
1206
0
  css::URLValueData* data =
1207
0
    svgReset->mMask.mLayers[aIndex].mImage.GetURLValue();
1208
0
  return ResolveURLUsingLocalRef(aFrame, data);
1209
0
}
1210
1211
} // namespace mozilla
1212