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 Mozilla Communicator client code.
16 : *
17 : * The Initial Developer of the Original Code is
18 : * Netscape Communications Corporation.
19 : * Portions created by the Initial Developer are Copyright (C) 1998
20 : * the Initial Developer. All Rights Reserved.
21 : *
22 : * Contributor(s):
23 : *
24 : * Alternatively, the contents of this file may be used under the terms of
25 : * either of the GNU General Public License Version 2 or later (the "GPL"),
26 : * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
27 : * in which case the provisions of the GPL or the LGPL are applicable instead
28 : * of those above. If you wish to allow use of your version of this file only
29 : * under the terms of either the GPL or the LGPL, and not to allow others to
30 : * use your version of this file under the terms of the MPL, indicate your
31 : * decision by deleting the provisions above and replace them with the notice
32 : * and other provisions required by the GPL or the LGPL. If you do not delete
33 : * the provisions above, a recipient may use your version of this file under
34 : * the terms of any one of the MPL, the GPL or the LGPL.
35 : *
36 : * ***** END LICENSE BLOCK ***** */
37 :
38 : #include "mozilla/Util.h"
39 :
40 : #include "nsIDOMHTMLParamElement.h"
41 : #include "nsIDOMHTMLBaseElement.h"
42 : #include "nsIDOMHTMLDirectoryElement.h"
43 : #include "nsIDOMHTMLQuoteElement.h"
44 : #include "nsIDOMHTMLHeadElement.h"
45 : #include "nsIDOMHTMLHtmlElement.h"
46 : #include "nsGenericHTMLElement.h"
47 :
48 : #include "nsGkAtoms.h"
49 : #include "nsStyleConsts.h"
50 : #include "nsRuleData.h"
51 : #include "nsMappedAttributes.h"
52 : #include "nsContentUtils.h"
53 :
54 : using namespace mozilla;
55 :
56 : // XXX nav4 has type= start= (same as OL/UL)
57 : extern nsAttrValue::EnumTable kListTypeTable[];
58 :
59 : class nsHTMLSharedElement : public nsGenericHTMLElement,
60 : public nsIDOMHTMLParamElement,
61 : public nsIDOMHTMLBaseElement,
62 : public nsIDOMHTMLDirectoryElement,
63 : public nsIDOMHTMLQuoteElement,
64 : public nsIDOMHTMLHeadElement,
65 : public nsIDOMHTMLHtmlElement
66 : {
67 : public:
68 : nsHTMLSharedElement(already_AddRefed<nsINodeInfo> aNodeInfo);
69 : virtual ~nsHTMLSharedElement();
70 :
71 : // nsISupports
72 : NS_DECL_ISUPPORTS_INHERITED
73 :
74 : // nsIDOMNode
75 0 : NS_FORWARD_NSIDOMNODE(nsGenericHTMLElement::)
76 :
77 : // nsIDOMElement
78 0 : NS_FORWARD_NSIDOMELEMENT(nsGenericHTMLElement::)
79 :
80 : // nsIDOMHTMLElement
81 0 : NS_FORWARD_NSIDOMHTMLELEMENT(nsGenericHTMLElement::)
82 :
83 : // nsIDOMHTMLParamElement
84 : NS_DECL_NSIDOMHTMLPARAMELEMENT
85 :
86 : // nsIDOMHTMLBaseElement
87 : NS_DECL_NSIDOMHTMLBASEELEMENT
88 :
89 : // nsIDOMHTMLDirectoryElement
90 : NS_DECL_NSIDOMHTMLDIRECTORYELEMENT
91 :
92 : // nsIDOMHTMLQuoteElement
93 : NS_DECL_NSIDOMHTMLQUOTEELEMENT
94 :
95 : // nsIDOMHTMLHeadElement
96 : NS_DECL_NSIDOMHTMLHEADELEMENT
97 :
98 : // nsIDOMHTMLHtmlElement
99 : NS_DECL_NSIDOMHTMLHTMLELEMENT
100 :
101 : // nsIContent
102 : virtual bool ParseAttribute(PRInt32 aNamespaceID,
103 : nsIAtom* aAttribute,
104 : const nsAString& aValue,
105 : nsAttrValue& aResult);
106 : nsresult SetAttr(PRInt32 aNameSpaceID, nsIAtom* aName,
107 : const nsAString& aValue, bool aNotify)
108 : {
109 : return SetAttr(aNameSpaceID, aName, nsnull, aValue, aNotify);
110 : }
111 : virtual nsresult SetAttr(PRInt32 aNameSpaceID, nsIAtom* aName,
112 : nsIAtom* aPrefix, const nsAString& aValue,
113 : bool aNotify);
114 :
115 : virtual nsresult UnsetAttr(PRInt32 aNameSpaceID, nsIAtom* aName,
116 : bool aNotify);
117 :
118 : virtual nsresult BindToTree(nsIDocument* aDocument, nsIContent* aParent,
119 : nsIContent* aBindingParent,
120 : bool aCompileEventHandlers);
121 :
122 : virtual void UnbindFromTree(bool aDeep = true,
123 : bool aNullParent = true);
124 :
125 : virtual nsMapRuleToAttributesFunc GetAttributeMappingFunction() const;
126 : NS_IMETHOD_(bool) IsAttributeMapped(const nsIAtom* aAttribute) const;
127 :
128 : virtual nsresult Clone(nsINodeInfo *aNodeInfo, nsINode **aResult) const;
129 :
130 0 : virtual nsXPCClassInfo* GetClassInfo()
131 : {
132 0 : return static_cast<nsXPCClassInfo*>(GetClassInfoInternal());
133 : }
134 : nsIClassInfo* GetClassInfoInternal();
135 : };
136 :
137 940 : NS_IMPL_NS_NEW_HTML_ELEMENT(Shared)
138 :
139 :
140 470 : nsHTMLSharedElement::nsHTMLSharedElement(already_AddRefed<nsINodeInfo> aNodeInfo)
141 470 : : nsGenericHTMLElement(aNodeInfo)
142 : {
143 470 : }
144 :
145 940 : nsHTMLSharedElement::~nsHTMLSharedElement()
146 : {
147 1880 : }
148 :
149 :
150 4710 : NS_IMPL_ADDREF_INHERITED(nsHTMLSharedElement, nsGenericElement)
151 4710 : NS_IMPL_RELEASE_INHERITED(nsHTMLSharedElement, nsGenericElement)
152 :
153 :
154 : DOMCI_DATA(HTMLParamElement, nsHTMLSharedElement)
155 : DOMCI_DATA(HTMLBaseElement, nsHTMLSharedElement)
156 : DOMCI_DATA(HTMLDirectoryElement, nsHTMLSharedElement)
157 : DOMCI_DATA(HTMLQuoteElement, nsHTMLSharedElement)
158 : DOMCI_DATA(HTMLHeadElement, nsHTMLSharedElement)
159 : DOMCI_DATA(HTMLHtmlElement, nsHTMLSharedElement)
160 :
161 : nsIClassInfo*
162 0 : nsHTMLSharedElement::GetClassInfoInternal()
163 : {
164 0 : if (mNodeInfo->Equals(nsGkAtoms::param)) {
165 0 : return NS_GetDOMClassInfoInstance(eDOMClassInfo_HTMLParamElement_id);
166 : }
167 0 : if (mNodeInfo->Equals(nsGkAtoms::base)) {
168 0 : return NS_GetDOMClassInfoInstance(eDOMClassInfo_HTMLBaseElement_id);
169 : }
170 0 : if (mNodeInfo->Equals(nsGkAtoms::dir)) {
171 0 : return NS_GetDOMClassInfoInstance(eDOMClassInfo_HTMLDirectoryElement_id);
172 : }
173 0 : if (mNodeInfo->Equals(nsGkAtoms::q)) {
174 0 : return NS_GetDOMClassInfoInstance(eDOMClassInfo_HTMLQuoteElement_id);
175 : }
176 0 : if (mNodeInfo->Equals(nsGkAtoms::blockquote)) {
177 0 : return NS_GetDOMClassInfoInstance(eDOMClassInfo_HTMLQuoteElement_id);
178 : }
179 0 : if (mNodeInfo->Equals(nsGkAtoms::head)) {
180 0 : return NS_GetDOMClassInfoInstance(eDOMClassInfo_HTMLHeadElement_id);
181 : }
182 0 : if (mNodeInfo->Equals(nsGkAtoms::html)) {
183 0 : return NS_GetDOMClassInfoInstance(eDOMClassInfo_HTMLHtmlElement_id);
184 : }
185 0 : return nsnull;
186 : }
187 :
188 : // QueryInterface implementation for nsHTMLSharedElement
189 14203 : NS_INTERFACE_TABLE_HEAD(nsHTMLSharedElement)
190 : NS_HTML_CONTENT_INTERFACE_TABLE_AMBIGUOUS_BEGIN(nsHTMLSharedElement,
191 : nsIDOMHTMLParamElement)
192 14203 : NS_OFFSET_AND_INTERFACE_TABLE_END
193 14203 : NS_HTML_CONTENT_INTERFACE_TABLE_TO_MAP_SEGUE_AMBIGUOUS(nsHTMLSharedElement,
194 : nsGenericHTMLElement,
195 : nsIDOMHTMLParamElement)
196 234 : NS_INTERFACE_MAP_ENTRY_IF_TAG(nsIDOMHTMLParamElement, param)
197 234 : NS_INTERFACE_MAP_ENTRY_IF_TAG(nsIDOMHTMLBaseElement, base)
198 234 : NS_INTERFACE_MAP_ENTRY_IF_TAG(nsIDOMHTMLDirectoryElement, dir)
199 234 : NS_INTERFACE_MAP_ENTRY_IF_TAG(nsIDOMHTMLQuoteElement, q)
200 234 : NS_INTERFACE_MAP_ENTRY_IF_TAG(nsIDOMHTMLQuoteElement, blockquote)
201 234 : NS_INTERFACE_MAP_ENTRY_IF_TAG(nsIDOMHTMLHeadElement, head)
202 234 : NS_INTERFACE_MAP_ENTRY_IF_TAG(nsIDOMHTMLHtmlElement, html)
203 :
204 234 : NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO_GETTER(GetClassInfoInternal)
205 234 : NS_HTML_CONTENT_INTERFACE_MAP_END
206 :
207 :
208 0 : NS_IMPL_ELEMENT_CLONE(nsHTMLSharedElement)
209 :
210 : // nsIDOMHTMLParamElement
211 0 : NS_IMPL_STRING_ATTR(nsHTMLSharedElement, Name, name)
212 0 : NS_IMPL_STRING_ATTR(nsHTMLSharedElement, Type, type)
213 0 : NS_IMPL_STRING_ATTR(nsHTMLSharedElement, Value, value)
214 0 : NS_IMPL_STRING_ATTR(nsHTMLSharedElement, ValueType, valuetype)
215 :
216 : // nsIDOMHTMLDirectoryElement
217 0 : NS_IMPL_BOOL_ATTR(nsHTMLSharedElement, Compact, compact)
218 :
219 : // nsIDOMHTMLQuoteElement
220 0 : NS_IMPL_URI_ATTR(nsHTMLSharedElement, Cite, cite)
221 :
222 : // nsIDOMHTMLHeadElement
223 : // Empty
224 :
225 : // nsIDOMHTMLHtmlElement
226 0 : NS_IMPL_STRING_ATTR(nsHTMLSharedElement, Version, version)
227 :
228 : // nsIDOMHTMLBaseElement
229 0 : NS_IMPL_STRING_ATTR(nsHTMLSharedElement, Target, target)
230 : NS_IMETHODIMP
231 0 : nsHTMLSharedElement::GetHref(nsAString& aValue)
232 : {
233 0 : nsAutoString href;
234 0 : GetAttr(kNameSpaceID_None, nsGkAtoms::href, href);
235 :
236 0 : nsCOMPtr<nsIURI> uri;
237 0 : nsIDocument* doc = OwnerDoc();
238 : nsContentUtils::NewURIWithDocumentCharset(
239 0 : getter_AddRefs(uri), href, doc, doc->GetDocumentURI());
240 :
241 0 : if (!uri) {
242 0 : aValue = href;
243 0 : return NS_OK;
244 : }
245 :
246 0 : nsCAutoString spec;
247 0 : uri->GetSpec(spec);
248 0 : CopyUTF8toUTF16(spec, aValue);
249 :
250 0 : return NS_OK;
251 : }
252 : NS_IMETHODIMP
253 0 : nsHTMLSharedElement::SetHref(const nsAString& aValue)
254 : {
255 0 : return SetAttrHelper(nsGkAtoms::href, aValue);
256 : }
257 :
258 :
259 : bool
260 1 : nsHTMLSharedElement::ParseAttribute(PRInt32 aNamespaceID,
261 : nsIAtom* aAttribute,
262 : const nsAString& aValue,
263 : nsAttrValue& aResult)
264 : {
265 1 : if (aNamespaceID == kNameSpaceID_None &&
266 0 : mNodeInfo->Equals(nsGkAtoms::dir)) {
267 0 : if (aAttribute == nsGkAtoms::type) {
268 0 : return aResult.ParseEnumValue(aValue, kListTypeTable, false);
269 : }
270 0 : if (aAttribute == nsGkAtoms::start) {
271 0 : return aResult.ParseIntWithBounds(aValue, 1);
272 : }
273 : }
274 :
275 : return nsGenericHTMLElement::ParseAttribute(aNamespaceID, aAttribute, aValue,
276 1 : aResult);
277 : }
278 :
279 : static void
280 0 : DirectoryMapAttributesIntoRule(const nsMappedAttributes* aAttributes,
281 : nsRuleData* aData)
282 : {
283 0 : if (aData->mSIDs & NS_STYLE_INHERIT_BIT(List)) {
284 0 : nsCSSValue* listStyleType = aData->ValueForListStyleType();
285 0 : if (listStyleType->GetUnit() == eCSSUnit_Null) {
286 : // type: enum
287 0 : const nsAttrValue* value = aAttributes->GetAttr(nsGkAtoms::type);
288 0 : if (value) {
289 0 : if (value->Type() == nsAttrValue::eEnum) {
290 0 : listStyleType->SetIntValue(value->GetEnumValue(), eCSSUnit_Enumerated);
291 : } else {
292 0 : listStyleType->SetIntValue(NS_STYLE_LIST_STYLE_DISC, eCSSUnit_Enumerated);
293 : }
294 : }
295 : }
296 : }
297 :
298 0 : nsGenericHTMLElement::MapCommonAttributesInto(aAttributes, aData);
299 0 : }
300 :
301 : NS_IMETHODIMP_(bool)
302 0 : nsHTMLSharedElement::IsAttributeMapped(const nsIAtom* aAttribute) const
303 : {
304 0 : if (mNodeInfo->Equals(nsGkAtoms::dir)) {
305 : static const MappedAttributeEntry attributes[] = {
306 : { &nsGkAtoms::type },
307 : // { &nsGkAtoms::compact }, // XXX
308 : { nsnull}
309 : };
310 :
311 : static const MappedAttributeEntry* const map[] = {
312 : attributes,
313 : sCommonAttributeMap,
314 : };
315 :
316 0 : return FindAttributeDependence(aAttribute, map);
317 : }
318 :
319 0 : return nsGenericHTMLElement::IsAttributeMapped(aAttribute);
320 : }
321 :
322 : static void
323 0 : SetBaseURIUsingFirstBaseWithHref(nsIDocument* aDocument, nsIContent* aMustMatch)
324 : {
325 0 : NS_PRECONDITION(aDocument, "Need a document!");
326 :
327 0 : for (nsIContent* child = aDocument->GetFirstChild(); child;
328 0 : child = child->GetNextNode()) {
329 0 : if (child->IsHTML(nsGkAtoms::base) &&
330 0 : child->HasAttr(kNameSpaceID_None, nsGkAtoms::href)) {
331 0 : if (aMustMatch && child != aMustMatch) {
332 0 : return;
333 : }
334 :
335 : // Resolve the <base> element's href relative to our document URI
336 0 : nsAutoString href;
337 0 : child->GetAttr(kNameSpaceID_None, nsGkAtoms::href, href);
338 :
339 0 : nsCOMPtr<nsIURI> newBaseURI;
340 : nsContentUtils::NewURIWithDocumentCharset(
341 0 : getter_AddRefs(newBaseURI), href, aDocument,
342 0 : aDocument->GetDocumentURI());
343 :
344 : // Try to set our base URI. If that fails, try to set base URI to null
345 0 : nsresult rv = aDocument->SetBaseURI(newBaseURI);
346 0 : if (NS_FAILED(rv)) {
347 0 : aDocument->SetBaseURI(nsnull);
348 : }
349 : return;
350 : }
351 : }
352 :
353 0 : aDocument->SetBaseURI(nsnull);
354 : }
355 :
356 : static void
357 0 : SetBaseTargetUsingFirstBaseWithTarget(nsIDocument* aDocument,
358 : nsIContent* aMustMatch)
359 : {
360 0 : NS_PRECONDITION(aDocument, "Need a document!");
361 :
362 0 : for (nsIContent* child = aDocument->GetFirstChild(); child;
363 0 : child = child->GetNextNode()) {
364 0 : if (child->IsHTML(nsGkAtoms::base) &&
365 0 : child->HasAttr(kNameSpaceID_None, nsGkAtoms::target)) {
366 0 : if (aMustMatch && child != aMustMatch) {
367 0 : return;
368 : }
369 :
370 0 : nsString target;
371 0 : child->GetAttr(kNameSpaceID_None, nsGkAtoms::target, target);
372 0 : aDocument->SetBaseTarget(target);
373 : return;
374 : }
375 : }
376 :
377 0 : aDocument->SetBaseTarget(EmptyString());
378 : }
379 :
380 : nsresult
381 1 : nsHTMLSharedElement::SetAttr(PRInt32 aNameSpaceID, nsIAtom* aName,
382 : nsIAtom* aPrefix, const nsAString& aValue,
383 : bool aNotify)
384 : {
385 : nsresult rv = nsGenericHTMLElement::SetAttr(aNameSpaceID, aName, aPrefix,
386 1 : aValue, aNotify);
387 1 : NS_ENSURE_SUCCESS(rv, rv);
388 :
389 : // If the href attribute of a <base> tag is changing, we may need to update
390 : // the document's base URI, which will cause all the links on the page to be
391 : // re-resolved given the new base. If the target attribute is changing, we
392 : // similarly need to change the base target.
393 1 : if (mNodeInfo->Equals(nsGkAtoms::base) &&
394 : aNameSpaceID == kNameSpaceID_None &&
395 0 : IsInDoc()) {
396 0 : if (aName == nsGkAtoms::href) {
397 0 : SetBaseURIUsingFirstBaseWithHref(GetCurrentDoc(), this);
398 0 : } else if (aName == nsGkAtoms::target) {
399 0 : SetBaseTargetUsingFirstBaseWithTarget(GetCurrentDoc(), this);
400 : }
401 : }
402 :
403 1 : return NS_OK;
404 : }
405 :
406 : nsresult
407 0 : nsHTMLSharedElement::UnsetAttr(PRInt32 aNameSpaceID, nsIAtom* aName,
408 : bool aNotify)
409 : {
410 0 : nsresult rv = nsGenericHTMLElement::UnsetAttr(aNameSpaceID, aName, aNotify);
411 0 : NS_ENSURE_SUCCESS(rv, rv);
412 :
413 : // If we're the first <base> with an href and our href attribute is being
414 : // unset, then we're no longer the first <base> with an href, and we need to
415 : // find the new one. Similar for target.
416 0 : if (mNodeInfo->Equals(nsGkAtoms::base) &&
417 : aNameSpaceID == kNameSpaceID_None &&
418 0 : IsInDoc()) {
419 0 : if (aName == nsGkAtoms::href) {
420 0 : SetBaseURIUsingFirstBaseWithHref(GetCurrentDoc(), nsnull);
421 0 : } else if (aName == nsGkAtoms::target) {
422 0 : SetBaseTargetUsingFirstBaseWithTarget(GetCurrentDoc(), nsnull);
423 : }
424 : }
425 :
426 0 : return NS_OK;
427 : }
428 :
429 : nsresult
430 470 : nsHTMLSharedElement::BindToTree(nsIDocument* aDocument, nsIContent* aParent,
431 : nsIContent* aBindingParent,
432 : bool aCompileEventHandlers)
433 : {
434 : nsresult rv = nsGenericHTMLElement::BindToTree(aDocument, aParent,
435 : aBindingParent,
436 470 : aCompileEventHandlers);
437 470 : NS_ENSURE_SUCCESS(rv, rv);
438 :
439 : // The document stores a pointer to its base URI and base target, which we may
440 : // need to update here.
441 470 : if (mNodeInfo->Equals(nsGkAtoms::base) &&
442 : aDocument) {
443 1 : if (HasAttr(kNameSpaceID_None, nsGkAtoms::href)) {
444 0 : SetBaseURIUsingFirstBaseWithHref(aDocument, this);
445 : }
446 1 : if (HasAttr(kNameSpaceID_None, nsGkAtoms::target)) {
447 0 : SetBaseTargetUsingFirstBaseWithTarget(aDocument, this);
448 : }
449 : }
450 :
451 470 : return NS_OK;
452 : }
453 :
454 : void
455 640 : nsHTMLSharedElement::UnbindFromTree(bool aDeep, bool aNullParent)
456 : {
457 640 : nsIDocument* doc = GetCurrentDoc();
458 :
459 640 : nsGenericHTMLElement::UnbindFromTree(aDeep, aNullParent);
460 :
461 : // If we're removing a <base> from a document, we may need to update the
462 : // document's base URI and base target
463 640 : if (doc && mNodeInfo->Equals(nsGkAtoms::base)) {
464 1 : if (HasAttr(kNameSpaceID_None, nsGkAtoms::href)) {
465 0 : SetBaseURIUsingFirstBaseWithHref(doc, nsnull);
466 : }
467 1 : if (HasAttr(kNameSpaceID_None, nsGkAtoms::target)) {
468 0 : SetBaseTargetUsingFirstBaseWithTarget(doc, nsnull);
469 : }
470 : }
471 640 : }
472 :
473 : nsMapRuleToAttributesFunc
474 0 : nsHTMLSharedElement::GetAttributeMappingFunction() const
475 : {
476 0 : if (mNodeInfo->Equals(nsGkAtoms::dir)) {
477 0 : return &DirectoryMapAttributesIntoRule;
478 : }
479 :
480 0 : return nsGenericHTMLElement::GetAttributeMappingFunction();
481 : }
|