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 #include "mozilla/dom/SVGSwitchElement.h"
8
9 #include "nsLayoutUtils.h"
10 #include "nsSVGUtils.h"
11 #include "mozilla/Preferences.h"
12 #include "mozilla/dom/SVGSwitchElementBinding.h"
13
14 class nsIFrame;
15
16 NS_IMPL_NS_NEW_NAMESPACED_SVG_ELEMENT(Switch)
17
18 namespace mozilla {
19 namespace dom {
20
WrapNode(JSContext * aCx,JS::Handle<JSObject * > aGivenProto)21 JSObject* SVGSwitchElement::WrapNode(JSContext* aCx,
22 JS::Handle<JSObject*> aGivenProto) {
23 return SVGSwitchElementBinding::Wrap(aCx, this, aGivenProto);
24 }
25
26 //----------------------------------------------------------------------
27 // nsISupports methods
28
NS_IMPL_CYCLE_COLLECTION_INHERITED(SVGSwitchElement,SVGSwitchElementBase,mActiveChild)29 NS_IMPL_CYCLE_COLLECTION_INHERITED(SVGSwitchElement, SVGSwitchElementBase,
30 mActiveChild)
31
32 NS_IMPL_ADDREF_INHERITED(SVGSwitchElement, SVGSwitchElementBase)
33 NS_IMPL_RELEASE_INHERITED(SVGSwitchElement, SVGSwitchElementBase)
34
35 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(SVGSwitchElement)
36 NS_INTERFACE_MAP_END_INHERITING(SVGSwitchElementBase)
37
38 //----------------------------------------------------------------------
39 // Implementation
40
41 SVGSwitchElement::SVGSwitchElement(
42 already_AddRefed<mozilla::dom::NodeInfo>& aNodeInfo)
43 : SVGSwitchElementBase(aNodeInfo) {}
44
~SVGSwitchElement()45 SVGSwitchElement::~SVGSwitchElement() {}
46
MaybeInvalidate()47 void SVGSwitchElement::MaybeInvalidate() {
48 // We must not change mActiveChild until after
49 // InvalidateAndScheduleBoundsUpdate has been called, otherwise
50 // it will not correctly invalidate the old mActiveChild area.
51
52 nsIContent* newActiveChild = FindActiveChild();
53
54 if (newActiveChild == mActiveChild) {
55 return;
56 }
57
58 nsIFrame* frame = GetPrimaryFrame();
59 if (frame) {
60 nsLayoutUtils::PostRestyleEvent(this, nsRestyleHint(0),
61 nsChangeHint_InvalidateRenderingObservers);
62 nsSVGUtils::ScheduleReflowSVG(frame);
63 }
64
65 mActiveChild = newActiveChild;
66 }
67
68 //----------------------------------------------------------------------
69 // nsIDOMNode methods
70
NS_IMPL_ELEMENT_CLONE_WITH_INIT(SVGSwitchElement)71 NS_IMPL_ELEMENT_CLONE_WITH_INIT(SVGSwitchElement)
72
73 //----------------------------------------------------------------------
74 // nsINode methods
75
76 nsresult SVGSwitchElement::InsertChildBefore(nsIContent* aKid,
77 nsIContent* aBeforeThis,
78 bool aNotify) {
79 nsresult rv =
80 SVGSwitchElementBase::InsertChildBefore(aKid, aBeforeThis, aNotify);
81 if (NS_SUCCEEDED(rv)) {
82 MaybeInvalidate();
83 }
84 return rv;
85 }
86
InsertChildAt_Deprecated(nsIContent * aKid,uint32_t aIndex,bool aNotify)87 nsresult SVGSwitchElement::InsertChildAt_Deprecated(nsIContent* aKid,
88 uint32_t aIndex,
89 bool aNotify) {
90 nsresult rv =
91 SVGSwitchElementBase::InsertChildAt_Deprecated(aKid, aIndex, aNotify);
92 if (NS_SUCCEEDED(rv)) {
93 MaybeInvalidate();
94 }
95 return rv;
96 }
97
RemoveChildAt_Deprecated(uint32_t aIndex,bool aNotify)98 void SVGSwitchElement::RemoveChildAt_Deprecated(uint32_t aIndex, bool aNotify) {
99 SVGSwitchElementBase::RemoveChildAt_Deprecated(aIndex, aNotify);
100 MaybeInvalidate();
101 }
102
RemoveChildNode(nsIContent * aKid,bool aNotify)103 void SVGSwitchElement::RemoveChildNode(nsIContent* aKid, bool aNotify) {
104 SVGSwitchElementBase::RemoveChildNode(aKid, aNotify);
105 MaybeInvalidate();
106 }
107
108 //----------------------------------------------------------------------
109 // nsIContent methods
110
NS_IMETHODIMP_(bool)111 NS_IMETHODIMP_(bool)
112 SVGSwitchElement::IsAttributeMapped(const nsAtom* name) const {
113 static const MappedAttributeEntry* const map[] = {sFEFloodMap,
114 sFiltersMap,
115 sFontSpecificationMap,
116 sGradientStopMap,
117 sLightingEffectsMap,
118 sMarkersMap,
119 sTextContentElementsMap,
120 sViewportsMap};
121
122 return FindAttributeDependence(name, map) ||
123 SVGSwitchElementBase::IsAttributeMapped(name);
124 }
125
126 //----------------------------------------------------------------------
127 // Implementation Helpers:
128
FindActiveChild() const129 nsIContent* SVGSwitchElement::FindActiveChild() const {
130 nsAutoString acceptLangs;
131 Preferences::GetLocalizedString("intl.accept_languages", acceptLangs);
132
133 if (!acceptLangs.IsEmpty()) {
134 int32_t bestLanguagePreferenceRank = -1;
135 nsIContent* bestChild = nullptr;
136 nsIContent* defaultChild = nullptr;
137 for (nsIContent* child = nsINode::GetFirstChild(); child;
138 child = child->GetNextSibling()) {
139 if (!child->IsElement()) {
140 continue;
141 }
142 nsCOMPtr<SVGTests> tests(do_QueryInterface(child));
143 if (tests) {
144 if (tests->PassesConditionalProcessingTests(
145 SVGTests::kIgnoreSystemLanguage)) {
146 int32_t languagePreferenceRank =
147 tests->GetBestLanguagePreferenceRank(acceptLangs);
148 switch (languagePreferenceRank) {
149 case 0:
150 // best possible match
151 return child;
152 case -1:
153 // no match
154 break;
155 case -2:
156 // no systemLanguage attribute. If there's nothing better
157 // we'll use the first such child.
158 if (!defaultChild) {
159 defaultChild = child;
160 }
161 break;
162 default:
163 if (bestLanguagePreferenceRank == -1 ||
164 languagePreferenceRank < bestLanguagePreferenceRank) {
165 bestLanguagePreferenceRank = languagePreferenceRank;
166 bestChild = child;
167 }
168 break;
169 }
170 }
171 } else if (!bestChild) {
172 bestChild = child;
173 }
174 }
175 return bestChild ? bestChild : defaultChild;
176 }
177
178 for (nsIContent* child = nsINode::GetFirstChild(); child;
179 child = child->GetNextSibling()) {
180 if (!child->IsElement()) {
181 continue;
182 }
183 nsCOMPtr<SVGTests> tests(do_QueryInterface(child));
184 if (!tests || tests->PassesConditionalProcessingTests(&acceptLangs)) {
185 return child;
186 }
187 }
188 return nullptr;
189 }
190
191 } // namespace dom
192 } // namespace mozilla
193