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/. */
7 #include "SVGTransformableElement.h"
9 #include "DOMSVGAnimatedTransformList.h"
10 #include "mozilla/dom/MutationEventBinding.h"
11 #include "nsContentUtils.h"
14 using namespace mozilla::gfx
;
16 namespace mozilla::dom
{
18 already_AddRefed
<DOMSVGAnimatedTransformList
>
19 SVGTransformableElement::Transform() {
20 // We're creating a DOM wrapper, so we must tell GetAnimatedTransformList
21 // to allocate the DOMSVGAnimatedTransformList if it hasn't already done so:
22 return DOMSVGAnimatedTransformList::GetDOMWrapper(
23 GetAnimatedTransformList(DO_ALLOCATE
), this);
26 //----------------------------------------------------------------------
29 nsChangeHint
SVGTransformableElement::GetAttributeChangeHint(
30 const nsAtom
* aAttribute
, int32_t aModType
) const {
32 SVGElement::GetAttributeChangeHint(aAttribute
, aModType
);
33 if (aAttribute
== nsGkAtoms::transform
||
34 aAttribute
== nsGkAtoms::mozAnimateMotionDummyAttr
) {
36 const_cast<SVGTransformableElement
*>(this)->GetPrimaryFrame();
37 retval
|= nsChangeHint_InvalidateRenderingObservers
;
38 if (!frame
|| frame
->HasAnyStateBits(NS_FRAME_IS_NONDISPLAY
)) {
42 bool isAdditionOrRemoval
= false;
43 if (aModType
== MutationEvent_Binding::ADDITION
||
44 aModType
== MutationEvent_Binding::REMOVAL
) {
45 isAdditionOrRemoval
= true;
47 MOZ_ASSERT(aModType
== MutationEvent_Binding::MODIFICATION
,
48 "Unknown modification type.");
49 if (!mTransforms
|| !mTransforms
->HasTransform()) {
50 // New value is empty, treat as removal.
51 // FIXME: Should we just rely on CreatedOrRemovedOnLastChange?
52 isAdditionOrRemoval
= true;
53 } else if (mTransforms
->CreatedOrRemovedOnLastChange()) {
54 // Old value was empty, treat as addition.
55 isAdditionOrRemoval
= true;
59 if (isAdditionOrRemoval
) {
60 retval
|= nsChangeHint_ComprehensiveAddOrRemoveTransform
;
62 // We just assume the old and new transforms are different.
63 retval
|= nsChangeHint_UpdatePostTransformOverflow
|
64 nsChangeHint_UpdateTransformLayer
;
70 bool SVGTransformableElement::IsEventAttributeNameInternal(nsAtom
* aName
) {
71 return nsContentUtils::IsEventAttributeName(aName
, EventNameType_SVGGraphic
);
74 //----------------------------------------------------------------------
75 // SVGElement overrides
77 gfxMatrix
SVGTransformableElement::PrependLocalTransformsTo(
78 const gfxMatrix
& aMatrix
, SVGTransformTypes aWhich
) const {
79 if (aWhich
== eChildToUserSpace
) {
80 // We don't have any eUserSpaceToParent transforms. (Sub-classes that do
81 // must override this function and handle that themselves.)
84 return GetUserToParentTransform(mAnimateMotionTransform
.get(),
89 const gfx::Matrix
* SVGTransformableElement::GetAnimateMotionTransform() const {
90 return mAnimateMotionTransform
.get();
93 void SVGTransformableElement::SetAnimateMotionTransform(
94 const gfx::Matrix
* aMatrix
) {
95 if ((!aMatrix
&& !mAnimateMotionTransform
) ||
96 (aMatrix
&& mAnimateMotionTransform
&&
97 aMatrix
->FuzzyEquals(*mAnimateMotionTransform
))) {
100 bool transformSet
= mTransforms
&& mTransforms
->IsExplicitlySet();
101 bool prevSet
= mAnimateMotionTransform
|| transformSet
;
102 mAnimateMotionTransform
=
103 aMatrix
? MakeUnique
<gfx::Matrix
>(*aMatrix
) : nullptr;
104 bool nowSet
= mAnimateMotionTransform
|| transformSet
;
106 if (prevSet
&& !nowSet
) {
107 modType
= MutationEvent_Binding::REMOVAL
;
108 } else if (!prevSet
&& nowSet
) {
109 modType
= MutationEvent_Binding::ADDITION
;
111 modType
= MutationEvent_Binding::MODIFICATION
;
113 DidAnimateTransformList(modType
);
114 nsIFrame
* frame
= GetPrimaryFrame();
116 // If the result of this transform and any other transforms on this frame
117 // is the identity matrix, then DoApplyRenderingChangeToTree won't handle
118 // our nsChangeHint_UpdateTransformLayer hint since aFrame->IsTransformed()
119 // will return false. That's fine, but we still need to schedule a repaint,
120 // and that won't otherwise happen. Since it's cheap to call SchedulePaint,
121 // we don't bother to check IsTransformed().
122 frame
->SchedulePaint();
126 SVGAnimatedTransformList
* SVGTransformableElement::GetAnimatedTransformList(
128 if (!mTransforms
&& (aFlags
& DO_ALLOCATE
)) {
129 mTransforms
= MakeUnique
<SVGAnimatedTransformList
>();
131 return mTransforms
.get();
135 gfxMatrix
SVGTransformableElement::GetUserToParentTransform(
136 const gfx::Matrix
* aAnimateMotionTransform
,
137 const SVGAnimatedTransformList
* aTransforms
) {
140 if (aAnimateMotionTransform
) {
141 result
.PreMultiply(ThebesMatrix(*aAnimateMotionTransform
));
145 result
.PreMultiply(aTransforms
->GetAnimValue().GetConsolidationMatrix());
151 } // namespace mozilla::dom