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