~ubuntu-branches/ubuntu/precise/kompozer/precise

« back to all changes in this revision

Viewing changes to mozilla/content/html/content/src/nsHTMLLinkElement.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Anthony Yarusso
  • Date: 2007-08-27 01:11:03 UTC
  • Revision ID: james.westby@ubuntu.com-20070827011103-2jgf4s6532gqu2ka
Tags: upstream-0.7.10
ImportĀ upstreamĀ versionĀ 0.7.10

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 
2
/* ***** BEGIN LICENSE BLOCK *****
 
3
 * Version: NPL 1.1/GPL 2.0/LGPL 2.1
 
4
 *
 
5
 * The contents of this file are subject to the Netscape Public License
 
6
 * Version 1.1 (the "License"); you may not use this file except in
 
7
 * compliance with the License. You may obtain a copy of the License at
 
8
 * http://www.mozilla.org/NPL/
 
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
 *
 
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 NPL, 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 NPL, the GPL or the LGPL.
 
36
 *
 
37
 * ***** END LICENSE BLOCK ***** */
 
38
#include "nsIDOMHTMLLinkElement.h"
 
39
#include "nsIDOMLinkStyle.h"
 
40
#include "nsIDOMEventReceiver.h"
 
41
#include "nsIHTMLContent.h"
 
42
#include "nsGenericHTMLElement.h"
 
43
#include "nsILink.h"
 
44
#include "nsHTMLAtoms.h"
 
45
#include "nsStyleConsts.h"
 
46
#include "nsIPresContext.h"
 
47
#include "nsIDOMStyleSheet.h"
 
48
#include "nsIStyleSheet.h"
 
49
#include "nsIStyleSheetLinkingElement.h"
 
50
#include "nsStyleLinkElement.h"
 
51
#include "nsReadableUtils.h"
 
52
#include "nsUnicharUtils.h"
 
53
#include "nsIURL.h"
 
54
#include "nsNetUtil.h"
 
55
#include "nsIDocument.h"
 
56
#include "nsIDOMEvent.h"
 
57
#include "nsIDOMDocumentEvent.h"
 
58
#include "nsIDOMEventTarget.h"
 
59
#include "nsParserUtils.h"
 
60
 
 
61
class nsHTMLLinkElement : public nsGenericHTMLElement,
 
62
                          public nsIDOMHTMLLinkElement,
 
63
                          public nsILink,
 
64
                          public nsStyleLinkElement
 
65
{
 
66
public:
 
67
  nsHTMLLinkElement();
 
68
  virtual ~nsHTMLLinkElement();
 
69
 
 
70
  // nsISupports
 
71
  NS_DECL_ISUPPORTS_INHERITED
 
72
 
 
73
  // nsIDOMNode
 
74
  NS_FORWARD_NSIDOMNODE_NO_CLONENODE(nsGenericHTMLElement::)
 
75
 
 
76
  // nsIDOMElement
 
77
  NS_FORWARD_NSIDOMELEMENT(nsGenericHTMLElement::)
 
78
 
 
79
  // nsIDOMHTMLElement
 
80
  NS_FORWARD_NSIDOMHTMLELEMENT(nsGenericHTMLElement::)
 
81
 
 
82
  // nsIDOMHTMLLinkElement
 
83
  NS_DECL_NSIDOMHTMLLINKELEMENT
 
84
 
 
85
  // nsILink
 
86
  NS_IMETHOD    GetLinkState(nsLinkState &aState);
 
87
  NS_IMETHOD    SetLinkState(nsLinkState aState);
 
88
  NS_IMETHOD    GetHrefURI(nsIURI** aURI);
 
89
 
 
90
  virtual void SetDocument(nsIDocument* aDocument, PRBool aDeep,
 
91
                           PRBool aCompileEventHandlers);
 
92
  void CreateAndDispatchEvent(nsIDocument* aDoc, const nsString& aRel,
 
93
                              const nsString& aRev,
 
94
                              const nsAString& aEventName);
 
95
  nsresult SetAttr(PRInt32 aNameSpaceID, nsIAtom* aName,
 
96
                   const nsAString& aValue, PRBool aNotify)
 
97
  {
 
98
    return SetAttr(aNameSpaceID, aName, nsnull, aValue, aNotify);
 
99
  }
 
100
  virtual nsresult SetAttr(PRInt32 aNameSpaceID, nsIAtom* aName,
 
101
                           nsIAtom* aPrefix, const nsAString& aValue,
 
102
                           PRBool aNotify);
 
103
  virtual nsresult UnsetAttr(PRInt32 aNameSpaceID, nsIAtom* aAttribute,
 
104
                             PRBool aNotify);
 
105
 
 
106
  virtual nsresult HandleDOMEvent(nsIPresContext* aPresContext,
 
107
                                  nsEvent* aEvent, nsIDOMEvent** aDOMEvent,
 
108
                                  PRUint32 aFlags,
 
109
                                  nsEventStatus* aEventStatus);
 
110
 
 
111
protected:
 
112
  virtual void GetStyleSheetURL(PRBool* aIsInline,
 
113
                                nsIURI** aURI);
 
114
  virtual void GetStyleSheetInfo(nsAString& aTitle,
 
115
                                 nsAString& aType,
 
116
                                 nsAString& aMedia,
 
117
                                 PRBool* aIsAlternate);
 
118
 
 
119
  // The cached visited state
 
120
  nsLinkState mLinkState;
 
121
};
 
122
 
 
123
nsresult
 
124
NS_NewHTMLLinkElement(nsIHTMLContent** aInstancePtrResult,
 
125
                      nsINodeInfo *aNodeInfo, PRBool aFromParser)
 
126
{
 
127
  NS_ENSURE_ARG_POINTER(aInstancePtrResult);
 
128
 
 
129
  nsHTMLLinkElement* it = new nsHTMLLinkElement();
 
130
 
 
131
  if (!it) {
 
132
    return NS_ERROR_OUT_OF_MEMORY;
 
133
  }
 
134
 
 
135
  nsresult rv = it->Init(aNodeInfo);
 
136
 
 
137
  if (NS_FAILED(rv)) {
 
138
    delete it;
 
139
 
 
140
    return rv;
 
141
  }
 
142
 
 
143
  *aInstancePtrResult = NS_STATIC_CAST(nsIHTMLContent *, it);
 
144
  NS_ADDREF(*aInstancePtrResult);
 
145
 
 
146
  return NS_OK;
 
147
}
 
148
 
 
149
 
 
150
nsHTMLLinkElement::nsHTMLLinkElement()
 
151
  : mLinkState(eLinkState_Unknown)
 
152
{
 
153
}
 
154
 
 
155
nsHTMLLinkElement::~nsHTMLLinkElement()
 
156
{
 
157
}
 
158
 
 
159
 
 
160
NS_IMPL_ADDREF_INHERITED(nsHTMLLinkElement, nsGenericElement) 
 
161
NS_IMPL_RELEASE_INHERITED(nsHTMLLinkElement, nsGenericElement) 
 
162
 
 
163
 
 
164
// QueryInterface implementation for nsHTMLLinkElement
 
165
NS_HTML_CONTENT_INTERFACE_MAP_BEGIN(nsHTMLLinkElement, nsGenericHTMLElement)
 
166
  NS_INTERFACE_MAP_ENTRY(nsIDOMHTMLLinkElement)
 
167
  NS_INTERFACE_MAP_ENTRY(nsIDOMLinkStyle)
 
168
  NS_INTERFACE_MAP_ENTRY(nsILink)
 
169
  NS_INTERFACE_MAP_ENTRY(nsIStyleSheetLinkingElement)
 
170
  NS_INTERFACE_MAP_ENTRY_CONTENT_CLASSINFO(HTMLLinkElement)
 
171
NS_HTML_CONTENT_INTERFACE_MAP_END
 
172
 
 
173
 
 
174
nsresult
 
175
nsHTMLLinkElement::CloneNode(PRBool aDeep, nsIDOMNode** aReturn)
 
176
{
 
177
  NS_ENSURE_ARG_POINTER(aReturn);
 
178
  *aReturn = nsnull;
 
179
 
 
180
  nsHTMLLinkElement* it = new nsHTMLLinkElement();
 
181
 
 
182
  if (!it) {
 
183
    return NS_ERROR_OUT_OF_MEMORY;
 
184
  }
 
185
 
 
186
  nsCOMPtr<nsIDOMNode> kungFuDeathGrip(it);
 
187
 
 
188
  nsresult rv = it->Init(mNodeInfo);
 
189
 
 
190
  if (NS_FAILED(rv))
 
191
    return rv;
 
192
 
 
193
  CopyInnerTo(it, aDeep);
 
194
 
 
195
  *aReturn = NS_STATIC_CAST(nsIDOMNode *, it);
 
196
 
 
197
  NS_ADDREF(*aReturn);
 
198
 
 
199
  return NS_OK;
 
200
}
 
201
 
 
202
 
 
203
NS_IMETHODIMP
 
204
nsHTMLLinkElement::GetDisabled(PRBool* aDisabled)
 
205
{
 
206
  nsCOMPtr<nsIDOMStyleSheet> ss(do_QueryInterface(mStyleSheet));
 
207
  nsresult result = NS_OK;
 
208
 
 
209
  if (ss) {
 
210
    result = ss->GetDisabled(aDisabled);
 
211
  } else {
 
212
    *aDisabled = PR_FALSE;
 
213
  }
 
214
 
 
215
  return result;
 
216
}
 
217
 
 
218
NS_IMETHODIMP 
 
219
nsHTMLLinkElement::SetDisabled(PRBool aDisabled)
 
220
{
 
221
  nsCOMPtr<nsIDOMStyleSheet> ss(do_QueryInterface(mStyleSheet));
 
222
  nsresult result = NS_OK;
 
223
 
 
224
  if (ss) {
 
225
    result = ss->SetDisabled(aDisabled);
 
226
  }
 
227
 
 
228
  return result;
 
229
}
 
230
 
 
231
 
 
232
NS_IMPL_STRING_ATTR(nsHTMLLinkElement, Charset, charset)
 
233
NS_IMPL_URI_ATTR(nsHTMLLinkElement, Href, href)
 
234
NS_IMPL_STRING_ATTR(nsHTMLLinkElement, Hreflang, hreflang)
 
235
NS_IMPL_STRING_ATTR(nsHTMLLinkElement, Media, media)
 
236
NS_IMPL_STRING_ATTR(nsHTMLLinkElement, Rel, rel)
 
237
NS_IMPL_STRING_ATTR(nsHTMLLinkElement, Rev, rev)
 
238
NS_IMPL_STRING_ATTR(nsHTMLLinkElement, Target, target)
 
239
NS_IMPL_STRING_ATTR(nsHTMLLinkElement, Type, type)
 
240
 
 
241
void
 
242
nsHTMLLinkElement::SetDocument(nsIDocument* aDocument, PRBool aDeep,
 
243
                               PRBool aCompileEventHandlers)
 
244
{
 
245
  nsCOMPtr<nsIDocument> oldDoc = mDocument;
 
246
 
 
247
  nsAutoString rel;
 
248
  nsAutoString rev;
 
249
  GetAttr(kNameSpaceID_None, nsHTMLAtoms::rel, rel);
 
250
  GetAttr(kNameSpaceID_None, nsHTMLAtoms::rev, rev);
 
251
    
 
252
  CreateAndDispatchEvent(oldDoc, rel, rev,
 
253
                         NS_LITERAL_STRING("DOMLinkRemoved"));
 
254
 
 
255
  // Do the removal and addition into the new doc.
 
256
  nsGenericHTMLElement::SetDocument(aDocument, aDeep, aCompileEventHandlers);
 
257
  UpdateStyleSheet(oldDoc);
 
258
                
 
259
  CreateAndDispatchEvent(mDocument, rel, rev,
 
260
                         NS_LITERAL_STRING("DOMLinkAdded"));
 
261
}
 
262
 
 
263
void
 
264
nsHTMLLinkElement::CreateAndDispatchEvent(nsIDocument* aDoc,
 
265
                                          const nsString& aRel,
 
266
                                          const nsString& aRev, 
 
267
                                          const nsAString& aEventName)
 
268
{
 
269
  if (!aDoc)
 
270
    return;
 
271
 
 
272
  // In the unlikely case that both rev is specified *and* rel=stylesheet,
 
273
  // this code will cause the event to fire, on the principle that maybe the
 
274
  // page really does want to specify that it's author is a stylesheet. Since
 
275
  // this should never actually happen and the performance hit is minimal,
 
276
  // doing the "right" thing costs virtually nothing here, even if it doesn't
 
277
  // make much sense.
 
278
  if (aRev.IsEmpty() &&
 
279
      (aRel.IsEmpty() || aRel.EqualsIgnoreCase("stylesheet")))
 
280
    return;
 
281
 
 
282
  nsCOMPtr<nsIDOMDocumentEvent> docEvent(do_QueryInterface(aDoc));
 
283
  nsCOMPtr<nsIDOMEvent> event;
 
284
  docEvent->CreateEvent(NS_LITERAL_STRING("Events"), getter_AddRefs(event));
 
285
  if (event) {
 
286
    event->InitEvent(aEventName, PR_TRUE, PR_TRUE);
 
287
    PRBool noDefault;
 
288
    nsCOMPtr<nsIDOMEventTarget> target =
 
289
      do_QueryInterface(NS_STATIC_CAST(nsIDOMNode*, this));
 
290
    if (target)
 
291
      target->DispatchEvent(event, &noDefault);
 
292
  }
 
293
}
 
294
 
 
295
nsresult
 
296
nsHTMLLinkElement::SetAttr(PRInt32 aNameSpaceID, nsIAtom* aName,
 
297
                           nsIAtom* aPrefix, const nsAString& aValue,
 
298
                           PRBool aNotify)
 
299
{
 
300
  if (aName == nsHTMLAtoms::href && kNameSpaceID_None == aNameSpaceID) {
 
301
    SetLinkState(eLinkState_Unknown);
 
302
  }
 
303
 
 
304
  nsresult rv = nsGenericHTMLElement::SetAttr(aNameSpaceID, aName, aPrefix,
 
305
                                              aValue, aNotify);
 
306
  if (NS_SUCCEEDED(rv)) {
 
307
    UpdateStyleSheet();
 
308
  }
 
309
 
 
310
  return rv;
 
311
}
 
312
 
 
313
nsresult
 
314
nsHTMLLinkElement::UnsetAttr(PRInt32 aNameSpaceID, nsIAtom* aAttribute,
 
315
                             PRBool aNotify)
 
316
{
 
317
  nsresult rv = nsGenericHTMLElement::UnsetAttr(aNameSpaceID, aAttribute,
 
318
                                                aNotify);
 
319
  if (NS_SUCCEEDED(rv)) {
 
320
    UpdateStyleSheet();
 
321
  }
 
322
 
 
323
  return rv;
 
324
}
 
325
 
 
326
nsresult
 
327
nsHTMLLinkElement::HandleDOMEvent(nsIPresContext* aPresContext,
 
328
                           nsEvent* aEvent,
 
329
                           nsIDOMEvent** aDOMEvent,
 
330
                           PRUint32 aFlags,
 
331
                           nsEventStatus* aEventStatus)
 
332
{
 
333
  return HandleDOMEventForAnchors(aPresContext, aEvent, aDOMEvent,
 
334
                                  aFlags, aEventStatus);
 
335
}
 
336
 
 
337
NS_IMETHODIMP
 
338
nsHTMLLinkElement::GetLinkState(nsLinkState &aState)
 
339
{
 
340
  aState = mLinkState;
 
341
  return NS_OK;
 
342
}
 
343
 
 
344
NS_IMETHODIMP
 
345
nsHTMLLinkElement::SetLinkState(nsLinkState aState)
 
346
{
 
347
  mLinkState = aState;
 
348
  return NS_OK;
 
349
}
 
350
 
 
351
NS_IMETHODIMP
 
352
nsHTMLLinkElement::GetHrefURI(nsIURI** aURI)
 
353
{
 
354
  return GetHrefURIForAnchors(aURI);
 
355
}
 
356
 
 
357
void
 
358
nsHTMLLinkElement::GetStyleSheetURL(PRBool* aIsInline,
 
359
                                    nsIURI** aURI)
 
360
{
 
361
  *aIsInline = PR_FALSE;
 
362
  GetHrefURIForAnchors(aURI);
 
363
  return;
 
364
}
 
365
 
 
366
void
 
367
nsHTMLLinkElement::GetStyleSheetInfo(nsAString& aTitle,
 
368
                                     nsAString& aType,
 
369
                                     nsAString& aMedia,
 
370
                                     PRBool* aIsAlternate)
 
371
{
 
372
  aTitle.Truncate();
 
373
  aType.Truncate();
 
374
  aMedia.Truncate();
 
375
  *aIsAlternate = PR_FALSE;
 
376
 
 
377
  nsAutoString rel;
 
378
  nsStringArray linkTypes(4);
 
379
  GetAttr(kNameSpaceID_None, nsHTMLAtoms::rel, rel);
 
380
  nsStyleLinkElement::ParseLinkTypes(rel, linkTypes);
 
381
  // Is it a stylesheet link?
 
382
  if (linkTypes.IndexOf(NS_LITERAL_STRING("stylesheet")) < 0) {
 
383
    return;
 
384
  }
 
385
 
 
386
  nsAutoString title;
 
387
  GetAttr(kNameSpaceID_None, nsHTMLAtoms::title, title);
 
388
  title.CompressWhitespace();
 
389
  aTitle.Assign(title);
 
390
 
 
391
  // If alternate, does it have title?
 
392
  if (-1 != linkTypes.IndexOf(NS_LITERAL_STRING("alternate"))) {
 
393
    if (aTitle.IsEmpty()) { // alternates must have title
 
394
      return;
 
395
    } else {
 
396
      *aIsAlternate = PR_TRUE;
 
397
    }
 
398
  }
 
399
 
 
400
  GetAttr(kNameSpaceID_None, nsHTMLAtoms::media, aMedia);
 
401
  ToLowerCase(aMedia); // HTML4.0 spec is inconsistent, make it case INSENSITIVE
 
402
 
 
403
  nsAutoString mimeType;
 
404
  nsAutoString notUsed;
 
405
  GetAttr(kNameSpaceID_None, nsHTMLAtoms::type, aType);
 
406
  nsParserUtils::SplitMimeType(aType, mimeType, notUsed);
 
407
  if (!mimeType.IsEmpty() && !mimeType.EqualsIgnoreCase("text/css")) {
 
408
    return;
 
409
  }
 
410
 
 
411
  // If we get here we assume that we're loading a css file, so set the
 
412
  // type to 'text/css'
 
413
  aType.Assign(NS_LITERAL_STRING("text/css"));
 
414
 
 
415
  return;
 
416
}