1 : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 : /* ***** BEGIN LICENSE BLOCK *****
3 : * Version: MPL 1.1/GPL 2.0/LGPL 2.1
4 : *
5 : * The contents of this file are subject to the Mozilla Public License Version
6 : * 1.1 (the "License"); you may not use this file except in compliance with
7 : * the License. You may obtain a copy of the License at
8 : * http://www.mozilla.org/MPL/
9 : *
10 : * Software distributed under the License is distributed on an "AS IS" basis,
11 : * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 : * for the specific language governing rights and limitations under the
13 : * License.
14 : *
15 : * The Original Code is the Mozilla SVG project.
16 : *
17 : * The Initial Developer of the Original Code is
18 : * IBM Corporation.
19 : * Portions created by the Initial Developer are Copyright (C) 2004
20 : * IBM Corporation. All Rights Reserved.
21 : *
22 : * Contributor(s):
23 : * IBM Corporation (original author)
24 : *
25 : * Alternatively, the contents of this file may be used under the terms of
26 : * either the GNU General Public License Version 2 or later (the "GPL"), or
27 : * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
28 : * in which case the provisions of the GPL or the LGPL are applicable instead
29 : * of those above. If you wish to allow use of your version of this file only
30 : * under the terms of either the GPL or the LGPL, and not to allow others to
31 : * use your version of this file under the terms of the MPL, indicate your
32 : * decision by deleting the provisions above and replace them with the notice
33 : * and other provisions required by the GPL or the LGPL. If you do not delete
34 : * the provisions above, a recipient may use your version of this file under
35 : * the terms of any one of the MPL, the GPL or the LGPL.
36 : *
37 : * ***** END LICENSE BLOCK ***** */
38 :
39 : #include "nsSVGElement.h"
40 : #include "nsGkAtoms.h"
41 : #include "nsIDOMSVGStyleElement.h"
42 : #include "nsUnicharUtils.h"
43 : #include "nsIDocument.h"
44 : #include "nsStyleLinkElement.h"
45 : #include "nsContentUtils.h"
46 :
47 : typedef nsSVGElement nsSVGStyleElementBase;
48 :
49 : class nsSVGStyleElement : public nsSVGStyleElementBase,
50 : public nsIDOMSVGStyleElement,
51 : public nsStyleLinkElement,
52 : public nsStubMutationObserver
53 0 : {
54 : protected:
55 : friend nsresult NS_NewSVGStyleElement(nsIContent **aResult,
56 : already_AddRefed<nsINodeInfo> aNodeInfo);
57 : nsSVGStyleElement(already_AddRefed<nsINodeInfo> aNodeInfo);
58 :
59 : public:
60 : NS_DECL_ISUPPORTS_INHERITED
61 : NS_DECL_NSIDOMSVGSTYLEELEMENT
62 :
63 : // xxx I wish we could use virtual inheritance
64 0 : NS_FORWARD_NSIDOMNODE(nsSVGStyleElementBase::)
65 0 : NS_FORWARD_NSIDOMELEMENT(nsSVGStyleElementBase::)
66 0 : NS_FORWARD_NSIDOMSVGELEMENT(nsSVGStyleElementBase::)
67 :
68 : // nsIContent
69 : virtual nsresult BindToTree(nsIDocument* aDocument, nsIContent* aParent,
70 : nsIContent* aBindingParent,
71 : bool aCompileEventHandlers);
72 : virtual void UnbindFromTree(bool aDeep = true,
73 : bool aNullParent = true);
74 0 : nsresult SetAttr(PRInt32 aNameSpaceID, nsIAtom* aName,
75 : const nsAString& aValue, bool aNotify)
76 : {
77 0 : return SetAttr(aNameSpaceID, aName, nsnull, aValue, aNotify);
78 : }
79 : virtual nsresult SetAttr(PRInt32 aNameSpaceID, nsIAtom* aName,
80 : nsIAtom* aPrefix, const nsAString& aValue,
81 : bool aNotify);
82 : virtual nsresult UnsetAttr(PRInt32 aNameSpaceID, nsIAtom* aAttribute,
83 : bool aNotify);
84 :
85 : virtual nsresult Clone(nsINodeInfo *aNodeInfo, nsINode **aResult) const;
86 :
87 : // nsIMutationObserver
88 : NS_DECL_NSIMUTATIONOBSERVER_CHARACTERDATACHANGED
89 : NS_DECL_NSIMUTATIONOBSERVER_CONTENTAPPENDED
90 : NS_DECL_NSIMUTATIONOBSERVER_CONTENTINSERTED
91 : NS_DECL_NSIMUTATIONOBSERVER_CONTENTREMOVED
92 :
93 : virtual nsXPCClassInfo* GetClassInfo();
94 : protected:
95 : // Dummy init method to make the NS_IMPL_NS_NEW_SVG_ELEMENT and
96 : // NS_IMPL_ELEMENT_CLONE_WITH_INIT usable with this class. This should be
97 : // completely optimized away.
98 0 : inline nsresult Init()
99 : {
100 0 : return NS_OK;
101 : }
102 :
103 : // nsStyleLinkElement overrides
104 : already_AddRefed<nsIURI> GetStyleSheetURL(bool* aIsInline);
105 :
106 : void GetStyleSheetInfo(nsAString& aTitle,
107 : nsAString& aType,
108 : nsAString& aMedia,
109 : bool* aIsAlternate);
110 : /**
111 : * Common method to call from the various mutation observer methods.
112 : * aContent is a content node that's either the one that changed or its
113 : * parent; we should only respond to the change if aContent is non-anonymous.
114 : */
115 : void ContentChanged(nsIContent* aContent);
116 : };
117 :
118 :
119 0 : NS_IMPL_NS_NEW_SVG_ELEMENT(Style)
120 :
121 :
122 : //----------------------------------------------------------------------
123 : // nsISupports methods
124 :
125 0 : NS_IMPL_ADDREF_INHERITED(nsSVGStyleElement,nsSVGStyleElementBase)
126 0 : NS_IMPL_RELEASE_INHERITED(nsSVGStyleElement,nsSVGStyleElementBase)
127 :
128 0 : DOMCI_NODE_DATA(SVGStyleElement, nsSVGStyleElement)
129 :
130 0 : NS_INTERFACE_TABLE_HEAD(nsSVGStyleElement)
131 0 : NS_NODE_INTERFACE_TABLE7(nsSVGStyleElement, nsIDOMNode, nsIDOMElement,
132 : nsIDOMSVGElement, nsIDOMSVGStyleElement,
133 : nsIDOMLinkStyle, nsIStyleSheetLinkingElement,
134 : nsIMutationObserver)
135 0 : NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(SVGStyleElement)
136 0 : NS_INTERFACE_MAP_END_INHERITING(nsSVGStyleElementBase)
137 :
138 : //----------------------------------------------------------------------
139 : // Implementation
140 :
141 0 : nsSVGStyleElement::nsSVGStyleElement(already_AddRefed<nsINodeInfo> aNodeInfo)
142 0 : : nsSVGStyleElementBase(aNodeInfo)
143 : {
144 0 : AddMutationObserver(this);
145 0 : }
146 :
147 :
148 : //----------------------------------------------------------------------
149 : // nsIDOMNode methods
150 :
151 :
152 0 : NS_IMPL_ELEMENT_CLONE_WITH_INIT(nsSVGStyleElement)
153 :
154 :
155 : //----------------------------------------------------------------------
156 : // nsIContent methods
157 :
158 : nsresult
159 0 : nsSVGStyleElement::BindToTree(nsIDocument* aDocument, nsIContent* aParent,
160 : nsIContent* aBindingParent,
161 : bool aCompileEventHandlers)
162 : {
163 : nsresult rv = nsSVGStyleElementBase::BindToTree(aDocument, aParent,
164 : aBindingParent,
165 0 : aCompileEventHandlers);
166 0 : NS_ENSURE_SUCCESS(rv, rv);
167 :
168 0 : void (nsSVGStyleElement::*update)() = &nsSVGStyleElement::UpdateStyleSheetInternal;
169 0 : nsContentUtils::AddScriptRunner(NS_NewRunnableMethod(this, update));
170 :
171 0 : return rv;
172 : }
173 :
174 : void
175 0 : nsSVGStyleElement::UnbindFromTree(bool aDeep, bool aNullParent)
176 : {
177 0 : nsCOMPtr<nsIDocument> oldDoc = GetCurrentDoc();
178 :
179 0 : nsSVGStyleElementBase::UnbindFromTree(aDeep, aNullParent);
180 0 : UpdateStyleSheetInternal(oldDoc);
181 0 : }
182 :
183 : nsresult
184 0 : nsSVGStyleElement::SetAttr(PRInt32 aNameSpaceID, nsIAtom* aName,
185 : nsIAtom* aPrefix, const nsAString& aValue,
186 : bool aNotify)
187 : {
188 : nsresult rv = nsSVGStyleElementBase::SetAttr(aNameSpaceID, aName, aPrefix,
189 0 : aValue, aNotify);
190 0 : if (NS_SUCCEEDED(rv)) {
191 : UpdateStyleSheetInternal(nsnull,
192 : aNameSpaceID == kNameSpaceID_None &&
193 : (aName == nsGkAtoms::title ||
194 : aName == nsGkAtoms::media ||
195 0 : aName == nsGkAtoms::type));
196 : }
197 :
198 0 : return rv;
199 : }
200 :
201 : nsresult
202 0 : nsSVGStyleElement::UnsetAttr(PRInt32 aNameSpaceID, nsIAtom* aAttribute,
203 : bool aNotify)
204 : {
205 : nsresult rv = nsSVGStyleElementBase::UnsetAttr(aNameSpaceID, aAttribute,
206 0 : aNotify);
207 0 : if (NS_SUCCEEDED(rv)) {
208 : UpdateStyleSheetInternal(nsnull,
209 : aNameSpaceID == kNameSpaceID_None &&
210 : (aAttribute == nsGkAtoms::title ||
211 : aAttribute == nsGkAtoms::media ||
212 0 : aAttribute == nsGkAtoms::type));
213 : }
214 :
215 0 : return rv;
216 : }
217 :
218 : //----------------------------------------------------------------------
219 : // nsIMutationObserver methods
220 :
221 : void
222 0 : nsSVGStyleElement::CharacterDataChanged(nsIDocument* aDocument,
223 : nsIContent* aContent,
224 : CharacterDataChangeInfo* aInfo)
225 : {
226 0 : ContentChanged(aContent);
227 0 : }
228 :
229 : void
230 0 : nsSVGStyleElement::ContentAppended(nsIDocument* aDocument,
231 : nsIContent* aContainer,
232 : nsIContent* aFirstNewContent,
233 : PRInt32 aNewIndexInContainer)
234 : {
235 0 : ContentChanged(aContainer);
236 0 : }
237 :
238 : void
239 0 : nsSVGStyleElement::ContentInserted(nsIDocument* aDocument,
240 : nsIContent* aContainer,
241 : nsIContent* aChild,
242 : PRInt32 aIndexInContainer)
243 : {
244 0 : ContentChanged(aChild);
245 0 : }
246 :
247 : void
248 0 : nsSVGStyleElement::ContentRemoved(nsIDocument* aDocument,
249 : nsIContent* aContainer,
250 : nsIContent* aChild,
251 : PRInt32 aIndexInContainer,
252 : nsIContent* aPreviousSibling)
253 : {
254 0 : ContentChanged(aChild);
255 0 : }
256 :
257 : void
258 0 : nsSVGStyleElement::ContentChanged(nsIContent* aContent)
259 : {
260 0 : if (nsContentUtils::IsInSameAnonymousTree(this, aContent)) {
261 0 : UpdateStyleSheetInternal(nsnull);
262 : }
263 0 : }
264 :
265 : //----------------------------------------------------------------------
266 : // nsIDOMSVGStyleElement methods
267 :
268 : /* attribute DOMString xmlspace; */
269 0 : NS_IMETHODIMP nsSVGStyleElement::GetXmlspace(nsAString & aXmlspace)
270 : {
271 0 : GetAttr(kNameSpaceID_XML, nsGkAtoms::space, aXmlspace);
272 :
273 0 : return NS_OK;
274 : }
275 0 : NS_IMETHODIMP nsSVGStyleElement::SetXmlspace(const nsAString & aXmlspace)
276 : {
277 0 : return SetAttr(kNameSpaceID_XML, nsGkAtoms::space, aXmlspace, true);
278 : }
279 :
280 : /* attribute DOMString type; */
281 0 : NS_IMETHODIMP nsSVGStyleElement::GetType(nsAString & aType)
282 : {
283 0 : GetAttr(kNameSpaceID_None, nsGkAtoms::type, aType);
284 :
285 0 : return NS_OK;
286 : }
287 0 : NS_IMETHODIMP nsSVGStyleElement::SetType(const nsAString & aType)
288 : {
289 0 : return SetAttr(kNameSpaceID_None, nsGkAtoms::type, aType, true);
290 : }
291 :
292 : /* attribute DOMString media; */
293 0 : NS_IMETHODIMP nsSVGStyleElement::GetMedia(nsAString & aMedia)
294 : {
295 0 : GetAttr(kNameSpaceID_None, nsGkAtoms::media, aMedia);
296 :
297 0 : return NS_OK;
298 : }
299 0 : NS_IMETHODIMP nsSVGStyleElement::SetMedia(const nsAString & aMedia)
300 : {
301 0 : return SetAttr(kNameSpaceID_None, nsGkAtoms::media, aMedia, true);
302 : }
303 :
304 : /* attribute DOMString title; */
305 0 : NS_IMETHODIMP nsSVGStyleElement::GetTitle(nsAString & aTitle)
306 : {
307 0 : GetAttr(kNameSpaceID_None, nsGkAtoms::title, aTitle);
308 :
309 0 : return NS_OK;
310 : }
311 0 : NS_IMETHODIMP nsSVGStyleElement::SetTitle(const nsAString & aTitle)
312 : {
313 0 : return SetAttr(kNameSpaceID_None, nsGkAtoms::title, aTitle, true);
314 : }
315 :
316 : //----------------------------------------------------------------------
317 : // nsStyleLinkElement methods
318 :
319 : already_AddRefed<nsIURI>
320 0 : nsSVGStyleElement::GetStyleSheetURL(bool* aIsInline)
321 : {
322 0 : *aIsInline = true;
323 0 : return nsnull;
324 : }
325 :
326 : void
327 0 : nsSVGStyleElement::GetStyleSheetInfo(nsAString& aTitle,
328 : nsAString& aType,
329 : nsAString& aMedia,
330 : bool* aIsAlternate)
331 : {
332 0 : *aIsAlternate = false;
333 :
334 0 : nsAutoString title;
335 0 : GetAttr(kNameSpaceID_None, nsGkAtoms::title, title);
336 0 : title.CompressWhitespace();
337 0 : aTitle.Assign(title);
338 :
339 0 : GetAttr(kNameSpaceID_None, nsGkAtoms::media, aMedia);
340 : // The SVG spec is formulated in terms of the CSS2 spec,
341 : // which specifies that media queries are case insensitive.
342 0 : nsContentUtils::ASCIIToLower(aMedia);
343 :
344 0 : GetAttr(kNameSpaceID_None, nsGkAtoms::type, aType);
345 0 : if (aType.IsEmpty()) {
346 0 : aType.AssignLiteral("text/css");
347 : }
348 :
349 : return;
350 : }
|