layout/svg/nsSVGEffects.cpp

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

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

mercurial