1 : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 : /* vim:set tw=80 expandtab softtabstop=2 ts=2 sw=2: */
3 : /* ***** BEGIN LICENSE BLOCK *****
4 : * Version: MPL 1.1/GPL 2.0/LGPL 2.1
5 : *
6 : * The contents of this file are subject to the Mozilla Public License Version
7 : * 1.1 (the "License"); you may not use this file except in compliance with
8 : * the License. You may obtain a copy of the License at
9 : * http://www.mozilla.org/MPL/
10 : *
11 : * Software distributed under the License is distributed on an "AS IS" basis,
12 : * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
13 : * for the specific language governing rights and limitations under the
14 : * License.
15 : *
16 : * The Original Code is Mozilla Communicator client code.
17 : *
18 : * The Initial Developer of the Original Code is
19 : * Netscape Communications Corporation.
20 : * Portions created by the Initial Developer are Copyright (C) 1998
21 : * the Initial Developer. All Rights Reserved.
22 : *
23 : * Contributor(s):
24 : * Mats Palmgren <matspal@gmail.com>
25 : * Ms2ger <ms2ger@gmail.com>
26 : *
27 : * Alternatively, the contents of this file may be used under the terms of
28 : * either of the GNU General Public License Version 2 or later (the "GPL"),
29 : * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
30 : * in which case the provisions of the GPL or the LGPL are applicable instead
31 : * of those above. If you wish to allow use of your version of this file only
32 : * under the terms of either the GPL or the LGPL, and not to allow others to
33 : * use your version of this file under the terms of the MPL, indicate your
34 : * decision by deleting the provisions above and replace them with the notice
35 : * and other provisions required by the GPL or the LGPL. If you do not delete
36 : * the provisions above, a recipient may use your version of this file under
37 : * the terms of any one of the MPL, the GPL or the LGPL.
38 : *
39 : * ***** END LICENSE BLOCK ***** */
40 :
41 : #include "mozilla/Util.h"
42 :
43 : #include "nscore.h"
44 : #include "nsGenericHTMLElement.h"
45 : #include "nsCOMPtr.h"
46 : #include "nsIAtom.h"
47 : #include "nsIContentViewer.h"
48 : #include "mozilla/css/StyleRule.h"
49 : #include "nsIDocument.h"
50 : #include "nsIDocumentEncoder.h"
51 : #include "nsIDOMHTMLBodyElement.h"
52 : #include "nsIDOMHTMLDocument.h"
53 : #include "nsIDOMAttr.h"
54 : #include "nsIDOMDocumentFragment.h"
55 : #include "nsIDOMHTMLElement.h"
56 : #include "nsIDOMHTMLMenuElement.h"
57 : #include "nsIDOMElementCSSInlineStyle.h"
58 : #include "nsIDOMWindow.h"
59 : #include "nsIDOMDocument.h"
60 : #include "nsEventListenerManager.h"
61 : #include "nsMappedAttributes.h"
62 : #include "nsHTMLStyleSheet.h"
63 : #include "nsIHTMLDocument.h"
64 : #include "nsILink.h"
65 : #include "nsPIDOMWindow.h"
66 : #include "nsIStyleRule.h"
67 : #include "nsIURL.h"
68 : #include "nsNetUtil.h"
69 : #include "nsEscape.h"
70 : #include "nsIFrame.h"
71 : #include "nsIScrollableFrame.h"
72 : #include "nsIView.h"
73 : #include "nsIViewManager.h"
74 : #include "nsIWidget.h"
75 : #include "nsRange.h"
76 : #include "nsIPresShell.h"
77 : #include "nsPresContext.h"
78 : #include "nsIDocShell.h"
79 : #include "nsIDocShellTreeItem.h"
80 : #include "nsINameSpaceManager.h"
81 : #include "nsDOMError.h"
82 : #include "nsScriptLoader.h"
83 : #include "nsRuleData.h"
84 :
85 : #include "nsPresState.h"
86 : #include "nsILayoutHistoryState.h"
87 :
88 : #include "nsHTMLParts.h"
89 : #include "nsContentUtils.h"
90 : #include "nsString.h"
91 : #include "nsUnicharUtils.h"
92 : #include "nsGkAtoms.h"
93 : #include "nsEventStateManager.h"
94 : #include "nsIDOMEvent.h"
95 : #include "nsIDOMNSEvent.h"
96 : #include "nsDOMCSSDeclaration.h"
97 : #include "nsITextControlFrame.h"
98 : #include "nsIForm.h"
99 : #include "nsIFormControl.h"
100 : #include "nsIDOMHTMLFormElement.h"
101 : #include "nsHTMLFormElement.h"
102 : #include "nsFocusManager.h"
103 :
104 : #include "nsMutationEvent.h"
105 :
106 : #include "nsContentCID.h"
107 :
108 : #include "nsDOMStringMap.h"
109 :
110 : #include "nsIEditor.h"
111 : #include "nsIEditorIMESupport.h"
112 : #include "nsEventDispatcher.h"
113 : #include "nsLayoutUtils.h"
114 : #include "nsContentCreatorFunctions.h"
115 : #include "mozAutoDocUpdate.h"
116 : #include "nsHtml5Module.h"
117 : #include "nsITextControlElement.h"
118 : #include "mozilla/dom/Element.h"
119 : #include "nsHTMLFieldSetElement.h"
120 : #include "nsHTMLMenuElement.h"
121 : #include "nsAsyncDOMEvent.h"
122 : #include "nsIScriptError.h"
123 :
124 : #include "mozilla/Preferences.h"
125 : #include "mozilla/dom/FromParser.h"
126 :
127 : using namespace mozilla;
128 : using namespace mozilla::dom;
129 :
130 : #include "nsThreadUtils.h"
131 :
132 : class nsINodeInfo;
133 : class nsIDOMNodeList;
134 : class nsRuleWalker;
135 :
136 : // XXX todo: add in missing out-of-memory checks
137 :
138 : //----------------------------------------------------------------------
139 :
140 : #ifdef GATHER_ELEMENT_USEAGE_STATISTICS
141 :
142 : // static objects that have constructors are kinda bad, but we don't
143 : // care here, this is only debugging code!
144 :
145 : static nsHashtable sGEUS_ElementCounts;
146 :
147 : void GEUS_ElementCreated(nsINodeInfo *aNodeInfo)
148 : {
149 : nsAutoString name;
150 : aNodeInfo->GetName(name);
151 :
152 : nsStringKey key(name);
153 :
154 : PRInt32 count = (PRInt32)sGEUS_ElementCounts.Get(&key);
155 :
156 : count++;
157 :
158 : sGEUS_ElementCounts.Put(&key, (void *)count);
159 : }
160 :
161 : bool GEUS_enum_func(nsHashKey *aKey, void *aData, void *aClosure)
162 : {
163 : const PRUnichar *name_chars = ((nsStringKey *)aKey)->GetString();
164 : NS_ConvertUTF16toUTF8 name(name_chars);
165 :
166 : printf ("%s %d\n", name.get(), aData);
167 :
168 : return true;
169 : }
170 :
171 : void GEUS_DumpElementCounts()
172 : {
173 : printf ("Element count statistics:\n");
174 :
175 : sGEUS_ElementCounts.Enumerate(GEUS_enum_func, nsnull);
176 :
177 : printf ("End of element count statistics:\n");
178 : }
179 :
180 : nsresult
181 : nsGenericHTMLElement::Init(nsINodeInfo *aNodeInfo)
182 : {
183 : GEUS_ElementCreated(aNodeInfo);
184 :
185 : return nsGenericHTMLElementBase::Init(aNodeInfo);
186 : }
187 :
188 : #endif
189 :
190 : /**
191 : * nsAutoFocusEvent is used to dispatch a focus event when a
192 : * nsGenericHTMLFormElement is binded to the tree with the autofocus attribute
193 : * enabled.
194 : */
195 : class nsAutoFocusEvent : public nsRunnable
196 0 : {
197 : public:
198 0 : nsAutoFocusEvent(nsGenericHTMLFormElement* aElement) : mElement(aElement) {}
199 :
200 0 : NS_IMETHOD Run() {
201 0 : nsFocusManager* fm = nsFocusManager::GetFocusManager();
202 0 : if (!fm) {
203 0 : return NS_ERROR_NULL_POINTER;
204 : }
205 :
206 0 : nsIDocument* document = mElement->OwnerDoc();
207 :
208 0 : nsPIDOMWindow* window = document->GetWindow();
209 0 : if (!window) {
210 0 : return NS_OK;
211 : }
212 :
213 : // Trying to found the top window (equivalent to window.top).
214 0 : nsCOMPtr<nsIDOMWindow> top;
215 0 : window->GetTop(getter_AddRefs(top));
216 0 : if (top) {
217 0 : window = static_cast<nsPIDOMWindow*>(top.get());
218 : }
219 :
220 0 : if (window->GetFocusedNode()) {
221 0 : return NS_OK;
222 : }
223 :
224 0 : nsCOMPtr<nsIDocument> topDoc = do_QueryInterface(window->GetExtantDocument());
225 0 : if (topDoc && topDoc->GetReadyStateEnum() == nsIDocument::READYSTATE_COMPLETE) {
226 0 : return NS_OK;
227 : }
228 :
229 : // If something is focused in the same document, ignore autofocus.
230 0 : if (!fm->GetFocusedContent() ||
231 0 : fm->GetFocusedContent()->OwnerDoc() != document) {
232 0 : return mElement->Focus();
233 : }
234 :
235 0 : return NS_OK;
236 : }
237 : private:
238 : // NOTE: nsGenericHTMLFormElement is saved as a nsGenericHTMLElement
239 : // because AddRef/Release are ambiguous with nsGenericHTMLFormElement
240 : // and Focus() is declared (and defined) in nsGenericHTMLElement class.
241 : nsRefPtr<nsGenericHTMLElement> mElement;
242 : };
243 :
244 : class nsGenericHTMLElementTearoff : public nsIDOMElementCSSInlineStyle
245 : {
246 0 : NS_DECL_CYCLE_COLLECTING_ISUPPORTS
247 :
248 0 : nsGenericHTMLElementTearoff(nsGenericHTMLElement *aElement)
249 0 : : mElement(aElement)
250 : {
251 0 : }
252 :
253 0 : virtual ~nsGenericHTMLElementTearoff()
254 0 : {
255 0 : }
256 :
257 0 : NS_IMETHOD GetStyle(nsIDOMCSSStyleDeclaration** aStyle)
258 : {
259 : nsresult rv;
260 0 : *aStyle = mElement->GetStyle(&rv);
261 0 : NS_ENSURE_SUCCESS(rv, rv);
262 0 : NS_ADDREF(*aStyle);
263 0 : return NS_OK;
264 : }
265 :
266 1464 : NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(nsGenericHTMLElementTearoff,
267 : nsIDOMElementCSSInlineStyle)
268 :
269 : private:
270 : nsRefPtr<nsGenericHTMLElement> mElement;
271 : };
272 :
273 1464 : NS_IMPL_CYCLE_COLLECTION_1(nsGenericHTMLElementTearoff, mElement)
274 :
275 0 : NS_IMPL_CYCLE_COLLECTING_ADDREF(nsGenericHTMLElementTearoff)
276 0 : NS_IMPL_CYCLE_COLLECTING_RELEASE(nsGenericHTMLElementTearoff)
277 :
278 0 : NS_INTERFACE_TABLE_HEAD(nsGenericHTMLElementTearoff)
279 0 : NS_INTERFACE_TABLE_INHERITED1(nsGenericHTMLElementTearoff,
280 : nsIDOMElementCSSInlineStyle)
281 0 : NS_INTERFACE_TABLE_TO_MAP_SEGUE_CYCLE_COLLECTION(nsGenericHTMLElementTearoff)
282 0 : NS_INTERFACE_MAP_END_AGGREGATED(mElement)
283 :
284 :
285 0 : NS_IMPL_INT_ATTR_DEFAULT_VALUE(nsGenericHTMLElement, TabIndex, tabindex, -1)
286 0 : NS_IMPL_BOOL_ATTR(nsGenericHTMLElement, Hidden, hidden)
287 :
288 : nsresult
289 548 : nsGenericHTMLElement::DOMQueryInterface(nsIDOMHTMLElement *aElement,
290 : REFNSIID aIID, void **aInstancePtr)
291 : {
292 548 : NS_PRECONDITION(aInstancePtr, "null out param");
293 :
294 548 : nsresult rv = NS_ERROR_FAILURE;
295 :
296 : NS_INTERFACE_TABLE_BEGIN
297 : NS_INTERFACE_TABLE_ENTRY(nsIDOMHTMLElement, nsIDOMNode)
298 : NS_INTERFACE_TABLE_ENTRY(nsIDOMHTMLElement, nsIDOMElement)
299 : NS_INTERFACE_TABLE_ENTRY(nsIDOMHTMLElement, nsIDOMHTMLElement)
300 548 : NS_INTERFACE_TABLE_END_WITH_PTR(aElement)
301 :
302 548 : NS_INTERFACE_TABLE_TO_MAP_SEGUE
303 470 : NS_INTERFACE_MAP_ENTRY_TEAROFF(nsIDOMElementCSSInlineStyle,
304 : new nsGenericHTMLElementTearoff(this))
305 470 : NS_INTERFACE_MAP_END
306 :
307 : // No closing bracket, because NS_INTERFACE_MAP_END does that for us.
308 :
309 : nsresult
310 0 : nsGenericHTMLElement::CopyInnerTo(nsGenericElement* aDst) const
311 : {
312 : nsresult rv;
313 0 : PRInt32 i, count = GetAttrCount();
314 0 : for (i = 0; i < count; ++i) {
315 0 : const nsAttrName *name = mAttrsAndChildren.AttrNameAt(i);
316 0 : const nsAttrValue *value = mAttrsAndChildren.AttrAt(i);
317 0 : if (name->Equals(nsGkAtoms::style, kNameSpaceID_None) &&
318 0 : value->Type() == nsAttrValue::eCSSStyleRule) {
319 : // We can't just set this as a string, because that will fail
320 : // to reparse the string into style data until the node is
321 : // inserted into the document. Clone the Rule instead.
322 0 : nsRefPtr<mozilla::css::Rule> ruleClone = value->GetCSSStyleRuleValue()->Clone();
323 0 : nsRefPtr<mozilla::css::StyleRule> styleRule = do_QueryObject(ruleClone);
324 0 : NS_ENSURE_TRUE(styleRule, NS_ERROR_UNEXPECTED);
325 :
326 0 : rv = aDst->SetInlineStyleRule(styleRule, false);
327 0 : NS_ENSURE_SUCCESS(rv, rv);
328 :
329 0 : continue;
330 : }
331 :
332 0 : nsAutoString valStr;
333 0 : value->ToString(valStr);
334 : rv = aDst->SetAttr(name->NamespaceID(), name->LocalName(),
335 0 : name->GetPrefix(), valStr, false);
336 0 : NS_ENSURE_SUCCESS(rv, rv);
337 : }
338 :
339 0 : return NS_OK;
340 : }
341 :
342 : NS_IMETHODIMP
343 0 : nsGenericHTMLElement::SetAttribute(const nsAString& aName,
344 : const nsAString& aValue)
345 : {
346 0 : const nsAttrName* name = InternalGetExistingAttrNameFromQName(aName);
347 :
348 0 : if (!name) {
349 0 : nsresult rv = nsContentUtils::CheckQName(aName, false);
350 0 : NS_ENSURE_SUCCESS(rv, rv);
351 :
352 0 : nsCOMPtr<nsIAtom> nameAtom;
353 0 : if (IsInHTMLDocument()) {
354 0 : nsAutoString lower;
355 0 : rv = nsContentUtils::ASCIIToLower(aName, lower);
356 0 : if (NS_SUCCEEDED(rv)) {
357 0 : nameAtom = do_GetAtom(lower);
358 : }
359 : }
360 : else {
361 0 : nameAtom = do_GetAtom(aName);
362 : }
363 0 : NS_ENSURE_TRUE(nameAtom, NS_ERROR_OUT_OF_MEMORY);
364 :
365 0 : return SetAttr(kNameSpaceID_None, nameAtom, aValue, true);
366 : }
367 :
368 : return SetAttr(name->NamespaceID(), name->LocalName(), name->GetPrefix(),
369 0 : aValue, true);
370 : }
371 :
372 : nsresult
373 0 : nsGenericHTMLElement::GetDataset(nsIDOMDOMStringMap** aDataset)
374 : {
375 0 : nsDOMSlots *slots = DOMSlots();
376 :
377 0 : if (!slots->mDataset) {
378 : // mDataset is a weak reference so assignment will not AddRef.
379 : // AddRef is called before assigning to out parameter.
380 0 : slots->mDataset = new nsDOMStringMap(this);
381 : }
382 :
383 0 : NS_ADDREF(*aDataset = slots->mDataset);
384 0 : return NS_OK;
385 : }
386 :
387 : nsresult
388 0 : nsGenericHTMLElement::ClearDataset()
389 : {
390 0 : nsDOMSlots *slots = GetExistingDOMSlots();
391 :
392 0 : NS_ASSERTION(slots && slots->mDataset,
393 : "Slots should exist and dataset should not be null.");
394 0 : slots->mDataset = nsnull;
395 :
396 0 : return NS_OK;
397 : }
398 :
399 : // Implementation for nsIDOMHTMLElement
400 : nsresult
401 0 : nsGenericHTMLElement::GetId(nsAString& aId)
402 : {
403 0 : GetAttr(kNameSpaceID_None, nsGkAtoms::id, aId);
404 0 : return NS_OK;
405 : }
406 :
407 : nsresult
408 0 : nsGenericHTMLElement::SetId(const nsAString& aId)
409 : {
410 0 : SetAttr(kNameSpaceID_None, nsGkAtoms::id, aId, true);
411 0 : return NS_OK;
412 : }
413 :
414 : nsresult
415 0 : nsGenericHTMLElement::GetTitle(nsAString& aTitle)
416 : {
417 0 : GetAttr(kNameSpaceID_None, nsGkAtoms::title, aTitle);
418 0 : return NS_OK;
419 : }
420 :
421 : nsresult
422 0 : nsGenericHTMLElement::SetTitle(const nsAString& aTitle)
423 : {
424 0 : SetAttr(kNameSpaceID_None, nsGkAtoms::title, aTitle, true);
425 0 : return NS_OK;
426 : }
427 :
428 : nsresult
429 0 : nsGenericHTMLElement::GetLang(nsAString& aLang)
430 : {
431 0 : GetAttr(kNameSpaceID_None, nsGkAtoms::lang, aLang);
432 0 : return NS_OK;
433 : }
434 :
435 : nsresult
436 0 : nsGenericHTMLElement::SetLang(const nsAString& aLang)
437 : {
438 0 : SetAttr(kNameSpaceID_None, nsGkAtoms::lang, aLang, true);
439 0 : return NS_OK;
440 : }
441 :
442 : static const nsAttrValue::EnumTable kDirTable[] = {
443 : { "ltr", NS_STYLE_DIRECTION_LTR },
444 : { "rtl", NS_STYLE_DIRECTION_RTL },
445 : { 0 }
446 : };
447 :
448 0 : NS_IMPL_ENUM_ATTR_DEFAULT_VALUE(nsGenericHTMLElement, Dir, dir, NULL)
449 :
450 : nsresult
451 0 : nsGenericHTMLElement::GetClassName(nsAString& aClassName)
452 : {
453 0 : GetAttr(kNameSpaceID_None, nsGkAtoms::_class, aClassName);
454 0 : return NS_OK;
455 : }
456 :
457 : nsresult
458 0 : nsGenericHTMLElement::SetClassName(const nsAString& aClassName)
459 : {
460 0 : SetAttr(kNameSpaceID_None, nsGkAtoms::_class, aClassName, true);
461 0 : return NS_OK;
462 : }
463 :
464 0 : NS_IMPL_STRING_ATTR(nsGenericHTMLElement, AccessKey, accesskey)
465 :
466 : NS_IMETHODIMP
467 0 : nsGenericHTMLElement::GetAccessKeyLabel(nsAString& aLabel)
468 : {
469 0 : nsPresContext *presContext = GetPresContext();
470 :
471 0 : if (presContext &&
472 0 : presContext->EventStateManager()->GetAccessKeyLabelPrefix(aLabel)) {
473 0 : nsAutoString suffix;
474 0 : GetAccessKey(suffix);
475 0 : aLabel.Append(suffix);
476 : }
477 :
478 0 : return NS_OK;
479 : }
480 :
481 0 : static bool IS_TABLE_CELL(nsIAtom* frameType) {
482 : return nsGkAtoms::tableCellFrame == frameType ||
483 0 : nsGkAtoms::bcTableCellFrame == frameType;
484 : }
485 :
486 : static bool
487 0 : IsOffsetParent(nsIFrame* aFrame)
488 : {
489 0 : nsIAtom* frameType = aFrame->GetType();
490 0 : return (IS_TABLE_CELL(frameType) ||
491 0 : frameType == nsGkAtoms::tableFrame);
492 : }
493 :
494 : void
495 0 : nsGenericHTMLElement::GetOffsetRect(nsRect& aRect, nsIContent** aOffsetParent)
496 : {
497 0 : *aOffsetParent = nsnull;
498 0 : aRect = nsRect();
499 :
500 0 : nsIFrame* frame = GetStyledFrame();
501 0 : if (!frame) {
502 0 : return;
503 : }
504 :
505 0 : nsIFrame* parent = frame->GetParent();
506 0 : nsPoint origin(0, 0);
507 :
508 0 : if (parent && parent->GetType() == nsGkAtoms::tableOuterFrame &&
509 0 : frame->GetType() == nsGkAtoms::tableFrame) {
510 0 : origin = parent->GetPositionIgnoringScrolling();
511 0 : parent = parent->GetParent();
512 : }
513 :
514 0 : Element* docElement = GetCurrentDoc()->GetRootElement();
515 0 : nsIContent* content = frame->GetContent();
516 :
517 0 : if (content && (content->IsHTML(nsGkAtoms::body) || content == docElement)) {
518 0 : parent = frame;
519 : }
520 : else {
521 0 : const bool isPositioned = frame->GetStyleDisplay()->IsPositioned();
522 : const bool isAbsolutelyPositioned =
523 0 : frame->GetStyleDisplay()->IsAbsolutelyPositioned();
524 0 : origin += frame->GetPositionIgnoringScrolling();
525 :
526 0 : for ( ; parent ; parent = parent->GetParent()) {
527 0 : content = parent->GetContent();
528 :
529 : // Stop at the first ancestor that is positioned.
530 0 : if (parent->GetStyleDisplay()->IsPositioned()) {
531 0 : *aOffsetParent = content;
532 0 : NS_IF_ADDREF(*aOffsetParent);
533 0 : break;
534 : }
535 :
536 : // Add the parent's origin to our own to get to the
537 : // right coordinate system.
538 0 : const bool isOffsetParent = !isPositioned && IsOffsetParent(parent);
539 0 : if (!isAbsolutelyPositioned && !isOffsetParent) {
540 0 : origin += parent->GetPositionIgnoringScrolling();
541 : }
542 :
543 0 : if (content) {
544 : // If we've hit the document element, break here.
545 0 : if (content == docElement) {
546 0 : break;
547 : }
548 :
549 : // Break if the ancestor frame type makes it suitable as offset parent
550 : // and this element is *not* positioned or if we found the body element.
551 0 : if (isOffsetParent || content->IsHTML(nsGkAtoms::body)) {
552 0 : *aOffsetParent = content;
553 0 : NS_ADDREF(*aOffsetParent);
554 0 : break;
555 : }
556 : }
557 : }
558 :
559 0 : if (isAbsolutelyPositioned && !*aOffsetParent) {
560 : // If this element is absolutely positioned, but we don't have
561 : // an offset parent it means this element is an absolutely
562 : // positioned child that's not nested inside another positioned
563 : // element, in this case the element's frame's parent is the
564 : // frame for the HTML element so we fail to find the body in the
565 : // parent chain. We want the offset parent in this case to be
566 : // the body, so we just get the body element from the document.
567 :
568 0 : nsCOMPtr<nsIDOMHTMLDocument> html_doc(do_QueryInterface(GetCurrentDoc()));
569 :
570 0 : if (html_doc) {
571 0 : nsCOMPtr<nsIDOMHTMLElement> html_element;
572 0 : html_doc->GetBody(getter_AddRefs(html_element));
573 0 : if (html_element) {
574 0 : CallQueryInterface(html_element, aOffsetParent);
575 : }
576 : }
577 : }
578 : }
579 :
580 : // Subtract the parent border unless it uses border-box sizing.
581 0 : if (parent &&
582 0 : parent->GetStylePosition()->mBoxSizing != NS_STYLE_BOX_SIZING_BORDER) {
583 0 : const nsStyleBorder* border = parent->GetStyleBorder();
584 0 : origin.x -= border->GetActualBorderWidth(NS_SIDE_LEFT);
585 0 : origin.y -= border->GetActualBorderWidth(NS_SIDE_TOP);
586 : }
587 :
588 : // XXX We should really consider subtracting out padding for
589 : // content-box sizing, but we should see what IE does....
590 :
591 : // Convert to pixels.
592 0 : aRect.x = nsPresContext::AppUnitsToIntCSSPixels(origin.x);
593 0 : aRect.y = nsPresContext::AppUnitsToIntCSSPixels(origin.y);
594 :
595 : // Get the union of all rectangles in this and continuation frames.
596 : // It doesn't really matter what we use as aRelativeTo here, since
597 : // we only care about the size. We just have to use something non-null.
598 0 : nsRect rcFrame = nsLayoutUtils::GetAllInFlowRectsUnion(frame, frame);
599 0 : aRect.width = nsPresContext::AppUnitsToIntCSSPixels(rcFrame.width);
600 0 : aRect.height = nsPresContext::AppUnitsToIntCSSPixels(rcFrame.height);
601 : }
602 :
603 : nsresult
604 0 : nsGenericHTMLElement::GetOffsetTop(PRInt32* aOffsetTop)
605 : {
606 0 : nsRect rcFrame;
607 0 : nsCOMPtr<nsIContent> parent;
608 0 : GetOffsetRect(rcFrame, getter_AddRefs(parent));
609 :
610 0 : *aOffsetTop = rcFrame.y;
611 :
612 0 : return NS_OK;
613 : }
614 :
615 : nsresult
616 0 : nsGenericHTMLElement::GetOffsetLeft(PRInt32* aOffsetLeft)
617 : {
618 0 : nsRect rcFrame;
619 0 : nsCOMPtr<nsIContent> parent;
620 0 : GetOffsetRect(rcFrame, getter_AddRefs(parent));
621 :
622 0 : *aOffsetLeft = rcFrame.x;
623 :
624 0 : return NS_OK;
625 : }
626 :
627 : nsresult
628 0 : nsGenericHTMLElement::GetOffsetWidth(PRInt32* aOffsetWidth)
629 : {
630 0 : nsRect rcFrame;
631 0 : nsCOMPtr<nsIContent> parent;
632 0 : GetOffsetRect(rcFrame, getter_AddRefs(parent));
633 :
634 0 : *aOffsetWidth = rcFrame.width;
635 :
636 0 : return NS_OK;
637 : }
638 :
639 : nsresult
640 0 : nsGenericHTMLElement::GetOffsetHeight(PRInt32* aOffsetHeight)
641 : {
642 0 : nsRect rcFrame;
643 0 : nsCOMPtr<nsIContent> parent;
644 0 : GetOffsetRect(rcFrame, getter_AddRefs(parent));
645 :
646 0 : *aOffsetHeight = rcFrame.height;
647 :
648 0 : return NS_OK;
649 : }
650 :
651 : nsresult
652 0 : nsGenericHTMLElement::GetOffsetParent(nsIDOMElement** aOffsetParent)
653 : {
654 0 : nsRect rcFrame;
655 0 : nsCOMPtr<nsIContent> parent;
656 0 : GetOffsetRect(rcFrame, getter_AddRefs(parent));
657 :
658 0 : if (parent) {
659 0 : CallQueryInterface(parent, aOffsetParent);
660 : } else {
661 0 : *aOffsetParent = nsnull;
662 : }
663 :
664 0 : return NS_OK;
665 : }
666 :
667 : nsresult
668 0 : nsGenericHTMLElement::GetMarkup(bool aIncludeSelf, nsAString& aMarkup)
669 : {
670 0 : aMarkup.Truncate();
671 :
672 0 : nsIDocument* doc = OwnerDoc();
673 :
674 0 : nsAutoString contentType;
675 0 : if (IsInHTMLDocument()) {
676 0 : contentType.AssignLiteral("text/html");
677 : } else {
678 0 : doc->GetContentType(contentType);
679 : }
680 :
681 0 : nsCOMPtr<nsIDocumentEncoder> docEncoder = doc->GetCachedEncoder();
682 0 : if (!docEncoder) {
683 : docEncoder =
684 : do_CreateInstance(PromiseFlatCString(
685 0 : nsDependentCString(NS_DOC_ENCODER_CONTRACTID_BASE) +
686 0 : NS_ConvertUTF16toUTF8(contentType)
687 0 : ).get());
688 : }
689 0 : if (!(docEncoder || doc->IsHTML())) {
690 : // This could be some type for which we create a synthetic document. Try
691 : // again as XML
692 0 : contentType.AssignLiteral("application/xml");
693 0 : docEncoder = do_CreateInstance(NS_DOC_ENCODER_CONTRACTID_BASE "application/xml");
694 : }
695 :
696 0 : NS_ENSURE_TRUE(docEncoder, NS_ERROR_FAILURE);
697 :
698 0 : nsresult rv = docEncoder->NativeInit(doc, contentType,
699 : nsIDocumentEncoder::OutputEncodeBasicEntities |
700 : // Output DOM-standard newlines
701 : nsIDocumentEncoder::OutputLFLineBreak |
702 : // Don't do linebreaking that's not present in
703 : // the source
704 0 : nsIDocumentEncoder::OutputRaw);
705 0 : NS_ENSURE_SUCCESS(rv, rv);
706 :
707 0 : if (aIncludeSelf) {
708 0 : docEncoder->SetNativeNode(this);
709 : } else {
710 0 : docEncoder->SetNativeContainerNode(this);
711 : }
712 0 : rv = docEncoder->EncodeToString(aMarkup);
713 0 : if (!aIncludeSelf) {
714 0 : doc->SetCachedEncoder(docEncoder.forget());
715 : }
716 0 : return rv;
717 : }
718 :
719 : nsresult
720 0 : nsGenericHTMLElement::GetInnerHTML(nsAString& aInnerHTML) {
721 0 : return GetMarkup(false, aInnerHTML);
722 : }
723 :
724 : NS_IMETHODIMP
725 0 : nsGenericHTMLElement::GetOuterHTML(nsAString& aOuterHTML) {
726 0 : return GetMarkup(true, aOuterHTML);
727 : }
728 :
729 : void
730 0 : nsGenericHTMLElement::FireMutationEventsForDirectParsing(nsIDocument* aDoc,
731 : nsIContent* aDest,
732 : PRInt32 aOldChildCount)
733 : {
734 : // Fire mutation events. Optimize for the case when there are no listeners
735 0 : PRInt32 newChildCount = aDest->GetChildCount();
736 0 : if (newChildCount && nsContentUtils::
737 0 : HasMutationListeners(aDoc, NS_EVENT_BITS_MUTATION_NODEINSERTED)) {
738 0 : nsAutoTArray<nsCOMPtr<nsIContent>, 50> childNodes;
739 0 : NS_ASSERTION(newChildCount - aOldChildCount >= 0,
740 : "What, some unexpected dom mutation has happened?");
741 0 : childNodes.SetCapacity(newChildCount - aOldChildCount);
742 0 : for (nsIContent* child = aDest->GetFirstChild();
743 : child;
744 0 : child = child->GetNextSibling()) {
745 0 : childNodes.AppendElement(child);
746 : }
747 0 : nsGenericElement::FireNodeInserted(aDoc, aDest, childNodes);
748 : }
749 0 : }
750 :
751 : NS_IMETHODIMP
752 0 : nsGenericHTMLElement::SetInnerHTML(const nsAString& aInnerHTML)
753 : {
754 0 : nsIDocument* doc = OwnerDoc();
755 :
756 : // Batch possible DOMSubtreeModified events.
757 0 : mozAutoSubtreeModified subtree(doc, nsnull);
758 :
759 0 : FireNodeRemovedForChildren();
760 :
761 : // Needed when innerHTML is used in combination with contenteditable
762 0 : mozAutoDocUpdate updateBatch(doc, UPDATE_CONTENT_MODEL, true);
763 :
764 : // Remove childnodes.
765 0 : PRUint32 childCount = GetChildCount();
766 0 : for (PRUint32 i = 0; i < childCount; ++i) {
767 0 : RemoveChildAt(0, true);
768 : }
769 :
770 0 : nsAutoScriptLoaderDisabler sld(doc);
771 :
772 0 : nsresult rv = NS_OK;
773 0 : if (doc->IsHTML()) {
774 0 : PRInt32 oldChildCount = GetChildCount();
775 : rv = nsContentUtils::ParseFragmentHTML(aInnerHTML,
776 : this,
777 : Tag(),
778 : GetNameSpaceID(),
779 0 : doc->GetCompatibilityMode() ==
780 : eCompatibility_NavQuirks,
781 0 : true);
782 : // HTML5 parser has notified, but not fired mutation events.
783 0 : FireMutationEventsForDirectParsing(doc, this, oldChildCount);
784 : } else {
785 0 : nsCOMPtr<nsIDOMDocumentFragment> df;
786 : rv = nsContentUtils::CreateContextualFragment(this, aInnerHTML,
787 : true,
788 0 : getter_AddRefs(df));
789 0 : nsCOMPtr<nsINode> fragment = do_QueryInterface(df);
790 0 : if (NS_SUCCEEDED(rv)) {
791 : // Suppress assertion about node removal mutation events that can't have
792 : // listeners anyway, because no one has had the chance to register mutation
793 : // listeners on the fragment that comes from the parser.
794 0 : nsAutoScriptBlockerSuppressNodeRemoved scriptBlocker;
795 :
796 0 : static_cast<nsINode*>(this)->AppendChild(fragment, &rv);
797 : }
798 : }
799 :
800 0 : return rv;
801 : }
802 :
803 : NS_IMETHODIMP
804 0 : nsGenericHTMLElement::SetOuterHTML(const nsAString& aOuterHTML)
805 : {
806 0 : nsCOMPtr<nsINode> parent = GetNodeParent();
807 0 : if (!parent) {
808 0 : return NS_OK;
809 : }
810 :
811 0 : if (parent->NodeType() == nsIDOMNode::DOCUMENT_NODE) {
812 0 : return NS_ERROR_DOM_NO_MODIFICATION_ALLOWED_ERR;
813 : }
814 :
815 0 : if (OwnerDoc()->IsHTML()) {
816 : nsIAtom* localName;
817 : PRInt32 namespaceID;
818 0 : if (parent->IsElement()) {
819 0 : localName = static_cast<nsIContent*>(parent.get())->Tag();
820 0 : namespaceID = static_cast<nsIContent*>(parent.get())->GetNameSpaceID();
821 : } else {
822 0 : NS_ASSERTION(parent->NodeType() == nsIDOMNode::DOCUMENT_FRAGMENT_NODE,
823 : "How come the parent isn't a document, a fragment or an element?");
824 0 : localName = nsGkAtoms::body;
825 0 : namespaceID = kNameSpaceID_XHTML;
826 : }
827 0 : nsCOMPtr<nsIDOMDocumentFragment> df;
828 0 : nsresult rv = NS_NewDocumentFragment(getter_AddRefs(df),
829 0 : OwnerDoc()->NodeInfoManager());
830 0 : NS_ENSURE_SUCCESS(rv, rv);
831 0 : nsCOMPtr<nsIContent> fragment = do_QueryInterface(df);
832 : nsContentUtils::ParseFragmentHTML(aOuterHTML,
833 : fragment,
834 : localName,
835 : namespaceID,
836 0 : OwnerDoc()->GetCompatibilityMode() ==
837 : eCompatibility_NavQuirks,
838 0 : true);
839 0 : parent->ReplaceChild(fragment, this, &rv);
840 0 : return rv;
841 : }
842 :
843 0 : nsCOMPtr<nsINode> context;
844 0 : if (parent->IsElement()) {
845 0 : context = parent;
846 : } else {
847 0 : NS_ASSERTION(parent->NodeType() == nsIDOMNode::DOCUMENT_FRAGMENT_NODE,
848 : "How come the parent isn't a document, a fragment or an element?");
849 : nsCOMPtr<nsINodeInfo> info =
850 : OwnerDoc()->NodeInfoManager()->GetNodeInfo(nsGkAtoms::body,
851 : nsnull,
852 : kNameSpaceID_XHTML,
853 0 : nsIDOMNode::ELEMENT_NODE);
854 0 : context = NS_NewHTMLBodyElement(info.forget(), FROM_PARSER_FRAGMENT);
855 : }
856 :
857 0 : nsCOMPtr<nsIDOMDocumentFragment> df;
858 : nsresult rv = nsContentUtils::CreateContextualFragment(context,
859 : aOuterHTML,
860 : true,
861 0 : getter_AddRefs(df));
862 0 : NS_ENSURE_SUCCESS(rv, rv);
863 0 : nsCOMPtr<nsINode> fragment = do_QueryInterface(df);
864 0 : parent->ReplaceChild(fragment, this, &rv);
865 0 : return rv;
866 : }
867 :
868 : enum nsAdjacentPosition {
869 : eBeforeBegin,
870 : eAfterBegin,
871 : eBeforeEnd,
872 : eAfterEnd
873 : };
874 :
875 : NS_IMETHODIMP
876 0 : nsGenericHTMLElement::InsertAdjacentHTML(const nsAString& aPosition,
877 : const nsAString& aText)
878 : {
879 : nsAdjacentPosition position;
880 0 : if (aPosition.LowerCaseEqualsLiteral("beforebegin")) {
881 0 : position = eBeforeBegin;
882 0 : } else if (aPosition.LowerCaseEqualsLiteral("afterbegin")) {
883 0 : position = eAfterBegin;
884 0 : } else if (aPosition.LowerCaseEqualsLiteral("beforeend")) {
885 0 : position = eBeforeEnd;
886 0 : } else if (aPosition.LowerCaseEqualsLiteral("afterend")) {
887 0 : position = eAfterEnd;
888 : } else {
889 0 : return NS_ERROR_DOM_SYNTAX_ERR;
890 : }
891 :
892 0 : nsCOMPtr<nsIContent> destination;
893 0 : if (position == eBeforeBegin || position == eAfterEnd) {
894 0 : destination = GetParent();
895 0 : if (!destination) {
896 0 : return NS_ERROR_DOM_NO_MODIFICATION_ALLOWED_ERR;
897 : }
898 : } else {
899 0 : destination = this;
900 : }
901 :
902 0 : nsIDocument* doc = OwnerDoc();
903 :
904 : // Needed when insertAdjacentHTML is used in combination with contenteditable
905 0 : mozAutoDocUpdate updateBatch(doc, UPDATE_CONTENT_MODEL, true);
906 0 : nsAutoScriptLoaderDisabler sld(doc);
907 :
908 : // Batch possible DOMSubtreeModified events.
909 0 : mozAutoSubtreeModified subtree(doc, nsnull);
910 :
911 : nsresult rv;
912 : // Parse directly into destination if possible
913 0 : if (doc->IsHTML() &&
914 : (position == eBeforeEnd ||
915 0 : (position == eAfterEnd && !GetNextSibling()) ||
916 0 : (position == eAfterBegin && !GetFirstChild()))) {
917 0 : PRInt32 oldChildCount = destination->GetChildCount();
918 0 : PRInt32 contextNs = destination->GetNameSpaceID();
919 0 : nsIAtom* contextLocal = destination->Tag();
920 0 : if (contextLocal == nsGkAtoms::html && contextNs == kNameSpaceID_XHTML) {
921 : // For compat with IE6 through IE9. Willful violation of HTML5 as of
922 : // 2011-04-06. CreateContextualFragment does the same already.
923 : // Spec bug: http://www.w3.org/Bugs/Public/show_bug.cgi?id=12434
924 0 : contextLocal = nsGkAtoms::body;
925 : }
926 : rv = nsContentUtils::ParseFragmentHTML(aText,
927 : destination,
928 : contextLocal,
929 : contextNs,
930 0 : doc->GetCompatibilityMode() ==
931 : eCompatibility_NavQuirks,
932 0 : true);
933 : // HTML5 parser has notified, but not fired mutation events.
934 0 : FireMutationEventsForDirectParsing(doc, destination, oldChildCount);
935 0 : return rv;
936 : }
937 :
938 : // couldn't parse directly
939 0 : nsCOMPtr<nsIDOMDocumentFragment> df;
940 : rv = nsContentUtils::CreateContextualFragment(destination,
941 : aText,
942 : true,
943 0 : getter_AddRefs(df));
944 0 : nsCOMPtr<nsINode> fragment = do_QueryInterface(df);
945 0 : NS_ENSURE_SUCCESS(rv, rv);
946 :
947 : // Suppress assertion about node removal mutation events that can't have
948 : // listeners anyway, because no one has had the chance to register mutation
949 : // listeners on the fragment that comes from the parser.
950 0 : nsAutoScriptBlockerSuppressNodeRemoved scriptBlocker;
951 :
952 0 : switch (position) {
953 : case eBeforeBegin:
954 0 : destination->InsertBefore(fragment, this, &rv);
955 0 : break;
956 : case eAfterBegin:
957 0 : static_cast<nsINode*>(this)->InsertBefore(fragment, GetFirstChild(), &rv);
958 0 : break;
959 : case eBeforeEnd:
960 0 : static_cast<nsINode*>(this)->AppendChild(fragment, &rv);
961 0 : break;
962 : case eAfterEnd:
963 0 : destination->InsertBefore(fragment, GetNextSibling(), &rv);
964 0 : break;
965 : }
966 0 : return rv;
967 : }
968 :
969 : nsresult
970 0 : nsGenericHTMLElement::ScrollIntoView(bool aTop, PRUint8 optional_argc)
971 : {
972 0 : nsIDocument *document = GetCurrentDoc();
973 :
974 0 : if (!document) {
975 0 : return NS_OK;
976 : }
977 :
978 : // Get the presentation shell
979 0 : nsCOMPtr<nsIPresShell> presShell = document->GetShell();
980 0 : if (!presShell) {
981 0 : return NS_OK;
982 : }
983 :
984 0 : if (!optional_argc) {
985 0 : aTop = true;
986 : }
987 :
988 : PRIntn vpercent = aTop ? NS_PRESSHELL_SCROLL_TOP :
989 0 : NS_PRESSHELL_SCROLL_BOTTOM;
990 :
991 0 : presShell->ScrollContentIntoView(this, vpercent,
992 : NS_PRESSHELL_SCROLL_ANYWHERE,
993 0 : nsIPresShell::SCROLL_OVERFLOW_HIDDEN);
994 :
995 0 : return NS_OK;
996 : }
997 :
998 : NS_IMETHODIMP
999 0 : nsGenericHTMLElement::GetSpellcheck(bool* aSpellcheck)
1000 : {
1001 0 : NS_ENSURE_ARG_POINTER(aSpellcheck);
1002 0 : *aSpellcheck = false; // Default answer is to not spellcheck
1003 :
1004 : // Has the state has been explicitly set?
1005 : nsIContent* node;
1006 0 : for (node = this; node; node = node->GetParent()) {
1007 0 : if (node->IsHTML()) {
1008 : static nsIContent::AttrValuesArray strings[] =
1009 : {&nsGkAtoms::_true, &nsGkAtoms::_false, nsnull};
1010 0 : switch (node->FindAttrValueIn(kNameSpaceID_None, nsGkAtoms::spellcheck,
1011 0 : strings, eCaseMatters)) {
1012 : case 0: // spellcheck = "true"
1013 0 : *aSpellcheck = true;
1014 : // Fall through
1015 : case 1: // spellcheck = "false"
1016 0 : return NS_OK;
1017 : }
1018 : }
1019 : }
1020 :
1021 : // Is this a chrome element?
1022 0 : if (nsContentUtils::IsChromeDoc(OwnerDoc())) {
1023 0 : return NS_OK; // Not spellchecked by default
1024 : }
1025 :
1026 0 : if (IsCurrentBodyElement()) {
1027 0 : nsCOMPtr<nsIHTMLDocument> doc = do_QueryInterface(GetCurrentDoc());
1028 0 : if (doc) {
1029 0 : *aSpellcheck = doc->IsEditingOn();
1030 : }
1031 :
1032 0 : return NS_OK;
1033 : }
1034 :
1035 : // Is this element editable?
1036 0 : nsCOMPtr<nsIFormControl> formControl = do_QueryInterface(this);
1037 0 : if (!formControl) {
1038 0 : return NS_OK; // Not spellchecked by default
1039 : }
1040 :
1041 : // Is this a multiline plaintext input?
1042 0 : PRInt32 controlType = formControl->GetType();
1043 0 : if (controlType == NS_FORM_TEXTAREA) {
1044 0 : *aSpellcheck = true; // Spellchecked by default
1045 0 : return NS_OK;
1046 : }
1047 :
1048 : // Is this anything other than an input text?
1049 : // Other inputs are not spellchecked.
1050 0 : if (controlType != NS_FORM_INPUT_TEXT) {
1051 0 : return NS_OK; // Not spellchecked by default
1052 : }
1053 :
1054 : // Does the user want input text spellchecked by default?
1055 : // NOTE: Do not reflect a pref value of 0 back to the DOM getter.
1056 : // The web page should not know if the user has disabled spellchecking.
1057 : // We'll catch this in the editor itself.
1058 0 : PRInt32 spellcheckLevel = Preferences::GetInt("layout.spellcheckDefault", 1);
1059 0 : if (spellcheckLevel == 2) { // "Spellcheck multi- and single-line"
1060 0 : *aSpellcheck = true; // Spellchecked by default
1061 : }
1062 :
1063 0 : return NS_OK;
1064 : }
1065 :
1066 : NS_IMETHODIMP
1067 0 : nsGenericHTMLElement::SetSpellcheck(bool aSpellcheck)
1068 : {
1069 0 : if (aSpellcheck) {
1070 0 : return SetAttrHelper(nsGkAtoms::spellcheck, NS_LITERAL_STRING("true"));
1071 : }
1072 :
1073 0 : return SetAttrHelper(nsGkAtoms::spellcheck, NS_LITERAL_STRING("false"));
1074 : }
1075 :
1076 : NS_IMETHODIMP
1077 0 : nsGenericHTMLElement::GetDraggable(bool* aDraggable)
1078 : {
1079 : *aDraggable = AttrValueIs(kNameSpaceID_None, nsGkAtoms::draggable,
1080 0 : nsGkAtoms::_true, eIgnoreCase);
1081 0 : return NS_OK;
1082 : }
1083 :
1084 : NS_IMETHODIMP
1085 0 : nsGenericHTMLElement::SetDraggable(bool aDraggable)
1086 : {
1087 : return SetAttrHelper(nsGkAtoms::draggable,
1088 0 : aDraggable ? NS_LITERAL_STRING("true")
1089 0 : : NS_LITERAL_STRING("false"));
1090 : }
1091 :
1092 : bool
1093 0 : nsGenericHTMLElement::InNavQuirksMode(nsIDocument* aDoc)
1094 : {
1095 0 : return aDoc && aDoc->GetCompatibilityMode() == eCompatibility_NavQuirks;
1096 : }
1097 :
1098 : void
1099 789 : nsGenericHTMLElement::UpdateEditableState(bool aNotify)
1100 : {
1101 : // XXX Should we do this only when in a document?
1102 789 : ContentEditableTristate value = GetContentEditableValue();
1103 789 : if (value != eInherit) {
1104 0 : DoSetEditableFlag(!!value, aNotify);
1105 0 : return;
1106 : }
1107 :
1108 789 : nsStyledElement::UpdateEditableState(aNotify);
1109 : }
1110 :
1111 : nsresult
1112 790 : nsGenericHTMLElement::BindToTree(nsIDocument* aDocument, nsIContent* aParent,
1113 : nsIContent* aBindingParent,
1114 : bool aCompileEventHandlers)
1115 : {
1116 : nsresult rv = nsGenericHTMLElementBase::BindToTree(aDocument, aParent,
1117 : aBindingParent,
1118 790 : aCompileEventHandlers);
1119 790 : NS_ENSURE_SUCCESS(rv, rv);
1120 :
1121 790 : if (aDocument) {
1122 789 : RegAccessKey();
1123 789 : if (HasName()) {
1124 : aDocument->
1125 0 : AddToNameTable(this, GetParsedAttr(nsGkAtoms::name)->GetAtomValue());
1126 : }
1127 789 : if (HasFlag(NODE_IS_EDITABLE) && GetContentEditableValue() == eTrue) {
1128 0 : nsCOMPtr<nsIHTMLDocument> htmlDocument = do_QueryInterface(aDocument);
1129 0 : if (htmlDocument) {
1130 0 : htmlDocument->ChangeContentEditableCount(this, +1);
1131 : }
1132 : }
1133 : }
1134 :
1135 790 : return rv;
1136 : }
1137 :
1138 : void
1139 1249 : nsGenericHTMLElement::UnbindFromTree(bool aDeep, bool aNullParent)
1140 : {
1141 1249 : if (IsInDoc()) {
1142 789 : UnregAccessKey();
1143 : }
1144 :
1145 1249 : RemoveFromNameTable();
1146 :
1147 1249 : if (GetContentEditableValue() == eTrue) {
1148 0 : nsCOMPtr<nsIHTMLDocument> htmlDocument = do_QueryInterface(GetCurrentDoc());
1149 0 : if (htmlDocument) {
1150 0 : htmlDocument->ChangeContentEditableCount(this, -1);
1151 : }
1152 : }
1153 :
1154 1249 : nsStyledElement::UnbindFromTree(aDeep, aNullParent);
1155 1249 : }
1156 :
1157 : nsHTMLFormElement*
1158 1 : nsGenericHTMLElement::FindAncestorForm(nsHTMLFormElement* aCurrentForm)
1159 : {
1160 1 : NS_ASSERTION(!HasAttr(kNameSpaceID_None, nsGkAtoms::form),
1161 : "FindAncestorForm should not be called if @form is set!");
1162 :
1163 : // Make sure we don't end up finding a form that's anonymous from
1164 : // our point of view.
1165 1 : nsIContent* bindingParent = GetBindingParent();
1166 :
1167 1 : nsIContent* content = this;
1168 5 : while (content != bindingParent && content) {
1169 : // If the current ancestor is a form, return it as our form
1170 3 : if (content->IsHTML(nsGkAtoms::form)) {
1171 : #ifdef DEBUG
1172 0 : if (!nsContentUtils::IsInSameAnonymousTree(this, content)) {
1173 : // It's possible that we started unbinding at |content| or
1174 : // some ancestor of it, and |content| and |this| used to all be
1175 : // anonymous. Check for this the hard way.
1176 0 : for (nsIContent* child = this; child != content;
1177 0 : child = child->GetParent()) {
1178 0 : NS_ASSERTION(child->GetParent()->IndexOf(child) != -1,
1179 : "Walked too far?");
1180 : }
1181 : }
1182 : #endif
1183 0 : return static_cast<nsHTMLFormElement*>(content);
1184 : }
1185 :
1186 3 : nsIContent *prevContent = content;
1187 3 : content = prevContent->GetParent();
1188 :
1189 3 : if (!content && aCurrentForm) {
1190 : // We got to the root of the subtree we're in, and we're being removed
1191 : // from the DOM (the only time we get into this method with a non-null
1192 : // aCurrentForm). Check whether aCurrentForm is in the same subtree. If
1193 : // it is, we want to return aCurrentForm, since this case means that
1194 : // we're one of those inputs-in-a-table that have a hacked mForm pointer
1195 : // and a subtree containing both us and the form got removed from the
1196 : // DOM.
1197 0 : if (nsContentUtils::ContentIsDescendantOf(aCurrentForm, prevContent)) {
1198 0 : return aCurrentForm;
1199 : }
1200 : }
1201 : }
1202 :
1203 1 : return nsnull;
1204 : }
1205 :
1206 : static bool
1207 0 : IsArea(nsIContent *aContent)
1208 : {
1209 0 : return (aContent->Tag() == nsGkAtoms::area &&
1210 0 : aContent->IsHTML());
1211 : }
1212 :
1213 : bool
1214 0 : nsGenericHTMLElement::CheckHandleEventForAnchorsPreconditions(nsEventChainVisitor& aVisitor)
1215 : {
1216 0 : NS_PRECONDITION(nsCOMPtr<nsILink>(do_QueryInterface(this)),
1217 : "should be called only when |this| implements |nsILink|");
1218 :
1219 0 : if (!aVisitor.mPresContext) {
1220 : // We need a pres context to do link stuff. Some events (e.g. mutation
1221 : // events) don't have one.
1222 : // XXX: ideally, shouldn't we be able to do what we need without one?
1223 0 : return false;
1224 : }
1225 :
1226 : //Need to check if we hit an imagemap area and if so see if we're handling
1227 : //the event on that map or on a link farther up the tree. If we're on a
1228 : //link farther up, do nothing.
1229 : nsCOMPtr<nsIContent> target = aVisitor.mPresContext->EventStateManager()->
1230 0 : GetEventTargetContent(aVisitor.mEvent);
1231 :
1232 0 : return !target || !IsArea(target) || IsArea(this);
1233 : }
1234 :
1235 : nsresult
1236 0 : nsGenericHTMLElement::PreHandleEventForAnchors(nsEventChainPreVisitor& aVisitor)
1237 : {
1238 0 : nsresult rv = nsGenericHTMLElementBase::PreHandleEvent(aVisitor);
1239 0 : NS_ENSURE_SUCCESS(rv, rv);
1240 :
1241 0 : if (!CheckHandleEventForAnchorsPreconditions(aVisitor)) {
1242 0 : return NS_OK;
1243 : }
1244 :
1245 0 : return PreHandleEventForLinks(aVisitor);
1246 : }
1247 :
1248 : nsresult
1249 0 : nsGenericHTMLElement::PostHandleEventForAnchors(nsEventChainPostVisitor& aVisitor)
1250 : {
1251 0 : if (!CheckHandleEventForAnchorsPreconditions(aVisitor)) {
1252 0 : return NS_OK;
1253 : }
1254 :
1255 0 : return PostHandleEventForLinks(aVisitor);
1256 : }
1257 :
1258 : bool
1259 0 : nsGenericHTMLElement::IsHTMLLink(nsIURI** aURI) const
1260 : {
1261 0 : NS_PRECONDITION(aURI, "Must provide aURI out param");
1262 :
1263 0 : *aURI = GetHrefURIForAnchors().get();
1264 : // We promise out param is non-null if we return true, so base rv on it
1265 0 : return *aURI != nsnull;
1266 : }
1267 :
1268 : already_AddRefed<nsIURI>
1269 0 : nsGenericHTMLElement::GetHrefURIForAnchors() const
1270 : {
1271 : // This is used by the three nsILink implementations and
1272 : // nsHTMLStyleElement.
1273 :
1274 : // Get href= attribute (relative URI).
1275 :
1276 : // We use the nsAttrValue's copy of the URI string to avoid copying.
1277 0 : nsCOMPtr<nsIURI> uri;
1278 0 : GetURIAttr(nsGkAtoms::href, nsnull, getter_AddRefs(uri));
1279 :
1280 0 : return uri.forget();
1281 : }
1282 :
1283 : nsresult
1284 11 : nsGenericHTMLElement::AfterSetAttr(PRInt32 aNamespaceID, nsIAtom* aName,
1285 : const nsAttrValue* aValue, bool aNotify)
1286 : {
1287 11 : if (aNamespaceID == kNameSpaceID_None) {
1288 0 : if (nsContentUtils::IsEventAttributeName(aName, EventNameType_HTML) &&
1289 : aValue) {
1290 0 : NS_ABORT_IF_FALSE(aValue->Type() == nsAttrValue::eString,
1291 : "Expected string value for script body");
1292 0 : nsresult rv = AddScriptEventListener(aName, aValue->GetStringValue());
1293 0 : NS_ENSURE_SUCCESS(rv, rv);
1294 : }
1295 0 : else if (aNotify && aName == nsGkAtoms::spellcheck) {
1296 0 : SyncEditorsOnSubtree(this);
1297 : }
1298 : }
1299 :
1300 : return nsGenericHTMLElementBase::AfterSetAttr(aNamespaceID, aName,
1301 11 : aValue, aNotify);
1302 : }
1303 :
1304 : nsEventListenerManager*
1305 0 : nsGenericHTMLElement::GetEventListenerManagerForAttr(nsIAtom* aAttrName,
1306 : bool* aDefer)
1307 : {
1308 : // Attributes on the body and frameset tags get set on the global object
1309 0 : if ((mNodeInfo->Equals(nsGkAtoms::body) ||
1310 0 : mNodeInfo->Equals(nsGkAtoms::frameset)) &&
1311 : // We only forward some event attributes from body/frameset to window
1312 : (0
1313 : #define EVENT(name_, id_, type_, struct_) /* nothing */
1314 : #define FORWARDED_EVENT(name_, id_, type_, struct_) \
1315 : || nsGkAtoms::on##name_ == aAttrName
1316 : #define WINDOW_EVENT FORWARDED_EVENT
1317 : #include "nsEventNameList.h"
1318 : #undef WINDOW_EVENT
1319 : #undef FORWARDED_EVENT
1320 : #undef EVENT
1321 : )
1322 : ) {
1323 : nsPIDOMWindow *win;
1324 :
1325 : // If we have a document, and it has a window, add the event
1326 : // listener on the window (the inner window). If not, proceed as
1327 : // normal.
1328 : // XXXbz sXBL/XBL2 issue: should we instead use GetCurrentDoc() here,
1329 : // override BindToTree for those classes and munge event listeners there?
1330 0 : nsIDocument *document = OwnerDoc();
1331 :
1332 : // FIXME (https://bugzilla.mozilla.org/show_bug.cgi?id=431767)
1333 : // nsDocument::GetInnerWindow can return an outer window in some cases,
1334 : // we don't want to stick an event listener on an outer window, so
1335 : // bail if it does. See similar code in nsHTMLBodyElement and
1336 : // nsHTMLFramesetElement
1337 0 : *aDefer = false;
1338 0 : if ((win = document->GetInnerWindow()) && win->IsInnerWindow()) {
1339 0 : nsCOMPtr<nsIDOMEventTarget> piTarget(do_QueryInterface(win));
1340 :
1341 0 : return piTarget->GetListenerManager(true);
1342 : }
1343 :
1344 0 : return nsnull;
1345 : }
1346 :
1347 : return nsGenericHTMLElementBase::GetEventListenerManagerForAttr(aAttrName,
1348 0 : aDefer);
1349 : }
1350 :
1351 : nsresult
1352 11 : nsGenericHTMLElement::SetAttr(PRInt32 aNameSpaceID, nsIAtom* aName,
1353 : nsIAtom* aPrefix, const nsAString& aValue,
1354 : bool aNotify)
1355 : {
1356 : bool contentEditable = aNameSpaceID == kNameSpaceID_None &&
1357 11 : aName == nsGkAtoms::contenteditable;
1358 : bool accessKey = aName == nsGkAtoms::accesskey &&
1359 11 : aNameSpaceID == kNameSpaceID_None;
1360 :
1361 11 : PRInt32 change = 0;
1362 11 : if (contentEditable) {
1363 0 : change = GetContentEditableValue() == eTrue ? -1 : 0;
1364 0 : SetMayHaveContentEditableAttr();
1365 : }
1366 :
1367 11 : if (accessKey) {
1368 0 : UnregAccessKey();
1369 : }
1370 :
1371 : nsresult rv = nsStyledElement::SetAttr(aNameSpaceID, aName, aPrefix, aValue,
1372 11 : aNotify);
1373 11 : NS_ENSURE_SUCCESS(rv, rv);
1374 :
1375 11 : if (contentEditable) {
1376 0 : if (aValue.IsEmpty() || aValue.LowerCaseEqualsLiteral("true")) {
1377 0 : change += 1;
1378 : }
1379 :
1380 0 : ChangeEditableState(change);
1381 : }
1382 :
1383 11 : if (accessKey && !aValue.IsEmpty()) {
1384 0 : SetFlags(NODE_HAS_ACCESSKEY);
1385 0 : RegAccessKey();
1386 : }
1387 :
1388 11 : return NS_OK;
1389 : }
1390 :
1391 : nsresult
1392 0 : nsGenericHTMLElement::UnsetAttr(PRInt32 aNameSpaceID, nsIAtom* aAttribute,
1393 : bool aNotify)
1394 : {
1395 0 : bool contentEditable = false;
1396 0 : PRInt32 contentEditableChange = 0;
1397 :
1398 : // Check for event handlers
1399 0 : if (aNameSpaceID == kNameSpaceID_None) {
1400 0 : if (aAttribute == nsGkAtoms::name) {
1401 : // Have to do this before clearing flag. See RemoveFromNameTable
1402 0 : RemoveFromNameTable();
1403 0 : ClearHasName();
1404 : }
1405 0 : else if (aAttribute == nsGkAtoms::contenteditable) {
1406 0 : contentEditable = true;
1407 0 : contentEditableChange = GetContentEditableValue() == eTrue ? -1 : 0;
1408 : }
1409 0 : else if (aAttribute == nsGkAtoms::accesskey) {
1410 : // Have to unregister before clearing flag. See UnregAccessKey
1411 0 : UnregAccessKey();
1412 0 : UnsetFlags(NODE_HAS_ACCESSKEY);
1413 : }
1414 0 : else if (nsContentUtils::IsEventAttributeName(aAttribute,
1415 : EventNameType_HTML)) {
1416 0 : nsEventListenerManager* manager = GetListenerManager(false);
1417 0 : if (manager) {
1418 0 : manager->RemoveScriptEventListener(aAttribute);
1419 : }
1420 : }
1421 :
1422 : // Remove dataset property if necessary.
1423 0 : nsDOMSlots *slots = GetExistingDOMSlots();
1424 0 : if (slots && slots->mDataset) {
1425 0 : slots->mDataset->RemoveProp(aAttribute);
1426 : }
1427 : }
1428 :
1429 : nsresult rv = nsGenericHTMLElementBase::UnsetAttr(aNameSpaceID, aAttribute,
1430 0 : aNotify);
1431 0 : NS_ENSURE_SUCCESS(rv, rv);
1432 :
1433 0 : if (contentEditable) {
1434 0 : ChangeEditableState(contentEditableChange);
1435 : }
1436 :
1437 0 : return NS_OK;
1438 : }
1439 :
1440 : void
1441 0 : nsGenericHTMLElement::GetBaseTarget(nsAString& aBaseTarget) const
1442 : {
1443 0 : OwnerDoc()->GetBaseTarget(aBaseTarget);
1444 0 : }
1445 :
1446 : //----------------------------------------------------------------------
1447 :
1448 : static bool
1449 0 : CanHaveName(nsIAtom* aTag)
1450 : {
1451 : return aTag == nsGkAtoms::img ||
1452 : aTag == nsGkAtoms::form ||
1453 : aTag == nsGkAtoms::applet ||
1454 : aTag == nsGkAtoms::embed ||
1455 0 : aTag == nsGkAtoms::object;
1456 : }
1457 :
1458 : bool
1459 11 : nsGenericHTMLElement::ParseAttribute(PRInt32 aNamespaceID,
1460 : nsIAtom* aAttribute,
1461 : const nsAString& aValue,
1462 : nsAttrValue& aResult)
1463 : {
1464 11 : if (aNamespaceID == kNameSpaceID_None) {
1465 0 : if (aAttribute == nsGkAtoms::dir) {
1466 0 : return aResult.ParseEnumValue(aValue, kDirTable, false);
1467 : }
1468 :
1469 0 : if (aAttribute == nsGkAtoms::tabindex) {
1470 0 : return aResult.ParseIntWithBounds(aValue, -32768, 32767);
1471 : }
1472 :
1473 0 : if (aAttribute == nsGkAtoms::name) {
1474 : // Store name as an atom. name="" means that the element has no name,
1475 : // not that it has an emptystring as the name.
1476 0 : RemoveFromNameTable();
1477 0 : if (aValue.IsEmpty()) {
1478 0 : ClearHasName();
1479 0 : return false;
1480 : }
1481 :
1482 0 : aResult.ParseAtom(aValue);
1483 :
1484 0 : if (CanHaveName(Tag())) {
1485 0 : SetHasName();
1486 0 : AddToNameTable(aResult.GetAtomValue());
1487 : }
1488 :
1489 0 : return true;
1490 : }
1491 :
1492 0 : if (aAttribute == nsGkAtoms::contenteditable) {
1493 0 : aResult.ParseAtom(aValue);
1494 0 : return true;
1495 : }
1496 : }
1497 :
1498 : return nsGenericHTMLElementBase::ParseAttribute(aNamespaceID, aAttribute,
1499 11 : aValue, aResult);
1500 : }
1501 :
1502 : bool
1503 0 : nsGenericHTMLElement::IsAttributeMapped(const nsIAtom* aAttribute) const
1504 : {
1505 : static const MappedAttributeEntry* const map[] = {
1506 : sCommonAttributeMap
1507 : };
1508 :
1509 0 : return FindAttributeDependence(aAttribute, map);
1510 : }
1511 :
1512 : nsMapRuleToAttributesFunc
1513 0 : nsGenericHTMLElement::GetAttributeMappingFunction() const
1514 : {
1515 0 : return &MapCommonAttributesInto;
1516 : }
1517 :
1518 : nsIFormControlFrame*
1519 0 : nsGenericHTMLElement::GetFormControlFrame(bool aFlushFrames)
1520 : {
1521 0 : if (aFlushFrames && IsInDoc()) {
1522 : // Cause a flush of the frames, so we get up-to-date frame information
1523 0 : GetCurrentDoc()->FlushPendingNotifications(Flush_Frames);
1524 : }
1525 0 : nsIFrame* frame = GetPrimaryFrame();
1526 0 : if (frame) {
1527 0 : nsIFormControlFrame* form_frame = do_QueryFrame(frame);
1528 0 : if (form_frame) {
1529 0 : return form_frame;
1530 : }
1531 :
1532 : // If we have generated content, the primary frame will be a
1533 : // wrapper frame.. out real frame will be in its child list.
1534 0 : for (frame = frame->GetFirstPrincipalChild();
1535 : frame;
1536 : frame = frame->GetNextSibling()) {
1537 0 : form_frame = do_QueryFrame(frame);
1538 0 : if (form_frame) {
1539 0 : return form_frame;
1540 : }
1541 : }
1542 : }
1543 :
1544 0 : return nsnull;
1545 : }
1546 :
1547 : /* static */ nsresult
1548 0 : nsGenericHTMLElement::GetPrimaryPresState(nsGenericHTMLElement* aContent,
1549 : nsPresState** aPresState)
1550 : {
1551 0 : NS_ENSURE_ARG_POINTER(aPresState);
1552 0 : *aPresState = nsnull;
1553 :
1554 0 : nsresult result = NS_OK;
1555 :
1556 0 : nsCAutoString key;
1557 0 : nsCOMPtr<nsILayoutHistoryState> history = GetLayoutHistoryAndKey(aContent, false, key);
1558 :
1559 0 : if (history) {
1560 : // Get the pres state for this key, if it doesn't exist, create one
1561 0 : result = history->GetState(key, aPresState);
1562 0 : if (!*aPresState) {
1563 0 : *aPresState = new nsPresState();
1564 0 : result = history->AddState(key, *aPresState);
1565 : }
1566 : }
1567 :
1568 0 : return result;
1569 : }
1570 :
1571 :
1572 : already_AddRefed<nsILayoutHistoryState>
1573 1 : nsGenericHTMLElement::GetLayoutHistoryAndKey(nsGenericHTMLElement* aContent,
1574 : bool aRead,
1575 : nsACString& aKey)
1576 : {
1577 : //
1578 : // Get the pres shell
1579 : //
1580 2 : nsCOMPtr<nsIDocument> doc = aContent->GetDocument();
1581 1 : if (!doc) {
1582 0 : return nsnull;
1583 : }
1584 :
1585 : //
1586 : // Get the history (don't bother with the key if the history is not there)
1587 : //
1588 2 : nsCOMPtr<nsILayoutHistoryState> history = doc->GetLayoutHistoryState();
1589 1 : if (!history) {
1590 1 : return nsnull;
1591 : }
1592 :
1593 0 : if (aRead && !history->HasStates()) {
1594 0 : return nsnull;
1595 : }
1596 :
1597 : //
1598 : // Get the state key
1599 : //
1600 : nsresult rv = nsContentUtils::GenerateStateKey(aContent, doc,
1601 : nsIStatefulFrame::eNoID,
1602 0 : aKey);
1603 0 : if (NS_FAILED(rv)) {
1604 0 : return nsnull;
1605 : }
1606 :
1607 : // If the state key is blank, this is anonymous content or for
1608 : // whatever reason we are not supposed to save/restore state.
1609 0 : if (aKey.IsEmpty()) {
1610 0 : return nsnull;
1611 : }
1612 :
1613 : // Add something unique to content so layout doesn't muck us up
1614 0 : aKey += "-C";
1615 :
1616 0 : return history.forget();
1617 : }
1618 :
1619 : bool
1620 1 : nsGenericHTMLElement::RestoreFormControlState(nsGenericHTMLElement* aContent,
1621 : nsIFormControl* aControl)
1622 : {
1623 2 : nsCAutoString key;
1624 2 : nsCOMPtr<nsILayoutHistoryState> history = GetLayoutHistoryAndKey(aContent, true, key);
1625 1 : if (!history) {
1626 1 : return false;
1627 : }
1628 :
1629 : nsPresState *state;
1630 : // Get the pres state for this key
1631 0 : nsresult rv = history->GetState(key, &state);
1632 0 : if (NS_SUCCEEDED(rv) && state) {
1633 0 : bool result = aControl->RestoreState(state);
1634 0 : history->RemoveState(key);
1635 0 : return result;
1636 : }
1637 :
1638 0 : return false;
1639 : }
1640 :
1641 : // XXX This creates a dependency between content and frames
1642 : nsPresContext*
1643 0 : nsGenericHTMLElement::GetPresContext()
1644 : {
1645 : // Get the document
1646 0 : nsIDocument* doc = GetDocument();
1647 0 : if (doc) {
1648 : // Get presentation shell.
1649 0 : nsIPresShell *presShell = doc->GetShell();
1650 0 : if (presShell) {
1651 0 : return presShell->GetPresContext();
1652 : }
1653 : }
1654 :
1655 0 : return nsnull;
1656 : }
1657 :
1658 : static const nsAttrValue::EnumTable kAlignTable[] = {
1659 : { "left", NS_STYLE_TEXT_ALIGN_LEFT },
1660 : { "right", NS_STYLE_TEXT_ALIGN_RIGHT },
1661 :
1662 : { "top", NS_STYLE_VERTICAL_ALIGN_TOP },
1663 : { "middle", NS_STYLE_VERTICAL_ALIGN_MIDDLE_WITH_BASELINE },
1664 : { "bottom", NS_STYLE_VERTICAL_ALIGN_BASELINE },
1665 :
1666 : { "center", NS_STYLE_VERTICAL_ALIGN_MIDDLE_WITH_BASELINE },
1667 : { "baseline", NS_STYLE_VERTICAL_ALIGN_BASELINE },
1668 :
1669 : { "texttop", NS_STYLE_VERTICAL_ALIGN_TEXT_TOP },
1670 : { "absmiddle", NS_STYLE_VERTICAL_ALIGN_MIDDLE },
1671 : { "abscenter", NS_STYLE_VERTICAL_ALIGN_MIDDLE },
1672 : { "absbottom", NS_STYLE_VERTICAL_ALIGN_BOTTOM },
1673 : { 0 }
1674 : };
1675 :
1676 : static const nsAttrValue::EnumTable kDivAlignTable[] = {
1677 : { "left", NS_STYLE_TEXT_ALIGN_MOZ_LEFT },
1678 : { "right", NS_STYLE_TEXT_ALIGN_MOZ_RIGHT },
1679 : { "center", NS_STYLE_TEXT_ALIGN_MOZ_CENTER },
1680 : { "middle", NS_STYLE_TEXT_ALIGN_MOZ_CENTER },
1681 : { "justify", NS_STYLE_TEXT_ALIGN_JUSTIFY },
1682 : { 0 }
1683 : };
1684 :
1685 : static const nsAttrValue::EnumTable kFrameborderTable[] = {
1686 : { "yes", NS_STYLE_FRAME_YES },
1687 : { "no", NS_STYLE_FRAME_NO },
1688 : { "1", NS_STYLE_FRAME_1 },
1689 : { "0", NS_STYLE_FRAME_0 },
1690 : { 0 }
1691 : };
1692 :
1693 : static const nsAttrValue::EnumTable kScrollingTable[] = {
1694 : { "yes", NS_STYLE_FRAME_YES },
1695 : { "no", NS_STYLE_FRAME_NO },
1696 : { "on", NS_STYLE_FRAME_ON },
1697 : { "off", NS_STYLE_FRAME_OFF },
1698 : { "scroll", NS_STYLE_FRAME_SCROLL },
1699 : { "noscroll", NS_STYLE_FRAME_NOSCROLL },
1700 : { "auto", NS_STYLE_FRAME_AUTO },
1701 : { 0 }
1702 : };
1703 :
1704 : static const nsAttrValue::EnumTable kTableVAlignTable[] = {
1705 : { "top", NS_STYLE_VERTICAL_ALIGN_TOP },
1706 : { "middle", NS_STYLE_VERTICAL_ALIGN_MIDDLE },
1707 : { "bottom", NS_STYLE_VERTICAL_ALIGN_BOTTOM },
1708 : { "baseline",NS_STYLE_VERTICAL_ALIGN_BASELINE },
1709 : { 0 }
1710 : };
1711 :
1712 : bool
1713 0 : nsGenericHTMLElement::ParseAlignValue(const nsAString& aString,
1714 : nsAttrValue& aResult)
1715 : {
1716 0 : return aResult.ParseEnumValue(aString, kAlignTable, false);
1717 : }
1718 :
1719 : //----------------------------------------
1720 :
1721 : static const nsAttrValue::EnumTable kTableHAlignTable[] = {
1722 : { "left", NS_STYLE_TEXT_ALIGN_LEFT },
1723 : { "right", NS_STYLE_TEXT_ALIGN_RIGHT },
1724 : { "center", NS_STYLE_TEXT_ALIGN_CENTER },
1725 : { "char", NS_STYLE_TEXT_ALIGN_CHAR },
1726 : { "justify",NS_STYLE_TEXT_ALIGN_JUSTIFY },
1727 : { 0 }
1728 : };
1729 :
1730 : bool
1731 0 : nsGenericHTMLElement::ParseTableHAlignValue(const nsAString& aString,
1732 : nsAttrValue& aResult)
1733 : {
1734 0 : return aResult.ParseEnumValue(aString, kTableHAlignTable, false);
1735 : }
1736 :
1737 : //----------------------------------------
1738 :
1739 : // This table is used for td, th, tr, col, thead, tbody and tfoot.
1740 : static const nsAttrValue::EnumTable kTableCellHAlignTable[] = {
1741 : { "left", NS_STYLE_TEXT_ALIGN_MOZ_LEFT },
1742 : { "right", NS_STYLE_TEXT_ALIGN_MOZ_RIGHT },
1743 : { "center", NS_STYLE_TEXT_ALIGN_MOZ_CENTER },
1744 : { "char", NS_STYLE_TEXT_ALIGN_CHAR },
1745 : { "justify",NS_STYLE_TEXT_ALIGN_JUSTIFY },
1746 : { "middle", NS_STYLE_TEXT_ALIGN_MOZ_CENTER },
1747 : { "absmiddle", NS_STYLE_TEXT_ALIGN_CENTER },
1748 : { 0 }
1749 : };
1750 :
1751 : bool
1752 0 : nsGenericHTMLElement::ParseTableCellHAlignValue(const nsAString& aString,
1753 : nsAttrValue& aResult)
1754 : {
1755 0 : return aResult.ParseEnumValue(aString, kTableCellHAlignTable, false);
1756 : }
1757 :
1758 : //----------------------------------------
1759 :
1760 : bool
1761 0 : nsGenericHTMLElement::ParseTableVAlignValue(const nsAString& aString,
1762 : nsAttrValue& aResult)
1763 : {
1764 0 : return aResult.ParseEnumValue(aString, kTableVAlignTable, false);
1765 : }
1766 :
1767 : bool
1768 0 : nsGenericHTMLElement::ParseDivAlignValue(const nsAString& aString,
1769 : nsAttrValue& aResult)
1770 : {
1771 0 : return aResult.ParseEnumValue(aString, kDivAlignTable, false);
1772 : }
1773 :
1774 : bool
1775 0 : nsGenericHTMLElement::ParseImageAttribute(nsIAtom* aAttribute,
1776 : const nsAString& aString,
1777 : nsAttrValue& aResult)
1778 : {
1779 0 : if ((aAttribute == nsGkAtoms::width) ||
1780 : (aAttribute == nsGkAtoms::height)) {
1781 0 : return aResult.ParseSpecialIntValue(aString);
1782 : }
1783 0 : if ((aAttribute == nsGkAtoms::hspace) ||
1784 : (aAttribute == nsGkAtoms::vspace) ||
1785 : (aAttribute == nsGkAtoms::border)) {
1786 0 : return aResult.ParseIntWithBounds(aString, 0);
1787 : }
1788 0 : return false;
1789 : }
1790 :
1791 : bool
1792 0 : nsGenericHTMLElement::ParseFrameborderValue(const nsAString& aString,
1793 : nsAttrValue& aResult)
1794 : {
1795 0 : return aResult.ParseEnumValue(aString, kFrameborderTable, false);
1796 : }
1797 :
1798 : bool
1799 0 : nsGenericHTMLElement::ParseScrollingValue(const nsAString& aString,
1800 : nsAttrValue& aResult)
1801 : {
1802 0 : return aResult.ParseEnumValue(aString, kScrollingTable, false);
1803 : }
1804 :
1805 : /**
1806 : * Handle attributes common to all html elements
1807 : */
1808 : void
1809 0 : nsGenericHTMLElement::MapCommonAttributesExceptHiddenInto(const nsMappedAttributes* aAttributes,
1810 : nsRuleData* aData)
1811 : {
1812 0 : if (aData->mSIDs & NS_STYLE_INHERIT_BIT(UserInterface)) {
1813 0 : nsCSSValue* userModify = aData->ValueForUserModify();
1814 0 : if (userModify->GetUnit() == eCSSUnit_Null) {
1815 : const nsAttrValue* value =
1816 0 : aAttributes->GetAttr(nsGkAtoms::contenteditable);
1817 0 : if (value) {
1818 0 : if (value->Equals(nsGkAtoms::_empty, eCaseMatters) ||
1819 0 : value->Equals(nsGkAtoms::_true, eIgnoreCase)) {
1820 : userModify->SetIntValue(NS_STYLE_USER_MODIFY_READ_WRITE,
1821 0 : eCSSUnit_Enumerated);
1822 : }
1823 0 : else if (value->Equals(nsGkAtoms::_false, eIgnoreCase)) {
1824 : userModify->SetIntValue(NS_STYLE_USER_MODIFY_READ_ONLY,
1825 0 : eCSSUnit_Enumerated);
1826 : }
1827 : }
1828 : }
1829 : }
1830 :
1831 0 : if (aData->mSIDs & NS_STYLE_INHERIT_BIT(Font)) {
1832 0 : const nsAttrValue* value = aAttributes->GetAttr(nsGkAtoms::lang);
1833 0 : if (value && value->Type() == nsAttrValue::eString) {
1834 0 : aData->ValueForLang()->SetStringValue(value->GetStringValue(),
1835 0 : eCSSUnit_Ident);
1836 : }
1837 : }
1838 0 : }
1839 :
1840 : void
1841 0 : nsGenericHTMLElement::MapCommonAttributesInto(const nsMappedAttributes* aAttributes,
1842 : nsRuleData* aData)
1843 : {
1844 0 : nsGenericHTMLElement::MapCommonAttributesExceptHiddenInto(aAttributes, aData);
1845 :
1846 0 : if (aData->mSIDs & NS_STYLE_INHERIT_BIT(Display)) {
1847 0 : nsCSSValue* display = aData->ValueForDisplay();
1848 0 : if (display->GetUnit() == eCSSUnit_Null) {
1849 0 : if (aAttributes->IndexOfAttr(nsGkAtoms::hidden, kNameSpaceID_None) >= 0) {
1850 0 : display->SetIntValue(NS_STYLE_DISPLAY_NONE, eCSSUnit_Enumerated);
1851 : }
1852 : }
1853 : }
1854 0 : }
1855 :
1856 : void
1857 1 : nsGenericHTMLFormElement::UpdateEditableFormControlState(bool aNotify)
1858 : {
1859 : // nsCSSFrameConstructor::MaybeConstructLazily is based on the logic of this
1860 : // function, so should be kept in sync with that.
1861 :
1862 1 : ContentEditableTristate value = GetContentEditableValue();
1863 1 : if (value != eInherit) {
1864 0 : DoSetEditableFlag(!!value, aNotify);
1865 0 : return;
1866 : }
1867 :
1868 1 : nsIContent *parent = GetParent();
1869 :
1870 1 : if (parent && parent->HasFlag(NODE_IS_EDITABLE)) {
1871 0 : DoSetEditableFlag(true, aNotify);
1872 0 : return;
1873 : }
1874 :
1875 1 : if (!IsTextControl(false)) {
1876 0 : DoSetEditableFlag(false, aNotify);
1877 0 : return;
1878 : }
1879 :
1880 : // If not contentEditable we still need to check the readonly attribute.
1881 : bool roState;
1882 1 : GetBoolAttr(nsGkAtoms::readonly, &roState);
1883 :
1884 1 : DoSetEditableFlag(!roState, aNotify);
1885 : }
1886 :
1887 :
1888 : /* static */ const nsGenericHTMLElement::MappedAttributeEntry
1889 : nsGenericHTMLElement::sCommonAttributeMap[] = {
1890 : { &nsGkAtoms::contenteditable },
1891 : { &nsGkAtoms::lang },
1892 : { &nsGkAtoms::hidden },
1893 : { nsnull }
1894 : };
1895 :
1896 : /* static */ const nsGenericElement::MappedAttributeEntry
1897 : nsGenericHTMLElement::sImageMarginSizeAttributeMap[] = {
1898 : { &nsGkAtoms::width },
1899 : { &nsGkAtoms::height },
1900 : { &nsGkAtoms::hspace },
1901 : { &nsGkAtoms::vspace },
1902 : { nsnull }
1903 : };
1904 :
1905 : /* static */ const nsGenericElement::MappedAttributeEntry
1906 : nsGenericHTMLElement::sImageAlignAttributeMap[] = {
1907 : { &nsGkAtoms::align },
1908 : { nsnull }
1909 : };
1910 :
1911 : /* static */ const nsGenericElement::MappedAttributeEntry
1912 : nsGenericHTMLElement::sDivAlignAttributeMap[] = {
1913 : { &nsGkAtoms::align },
1914 : { nsnull }
1915 : };
1916 :
1917 : /* static */ const nsGenericElement::MappedAttributeEntry
1918 : nsGenericHTMLElement::sImageBorderAttributeMap[] = {
1919 : { &nsGkAtoms::border },
1920 : { nsnull }
1921 : };
1922 :
1923 : /* static */ const nsGenericElement::MappedAttributeEntry
1924 : nsGenericHTMLElement::sBackgroundAttributeMap[] = {
1925 : { &nsGkAtoms::background },
1926 : { &nsGkAtoms::bgcolor },
1927 : { nsnull }
1928 : };
1929 :
1930 : /* static */ const nsGenericElement::MappedAttributeEntry
1931 : nsGenericHTMLElement::sBackgroundColorAttributeMap[] = {
1932 : { &nsGkAtoms::bgcolor },
1933 : { nsnull }
1934 : };
1935 :
1936 : /* static */ const nsGenericElement::MappedAttributeEntry
1937 : nsGenericHTMLElement::sScrollingAttributeMap[] = {
1938 : { &nsGkAtoms::scrolling },
1939 : { nsnull }
1940 : };
1941 :
1942 : void
1943 0 : nsGenericHTMLElement::MapImageAlignAttributeInto(const nsMappedAttributes* aAttributes,
1944 : nsRuleData* aRuleData)
1945 : {
1946 0 : if (aRuleData->mSIDs & (NS_STYLE_INHERIT_BIT(Display) |
1947 : NS_STYLE_INHERIT_BIT(TextReset))) {
1948 0 : const nsAttrValue* value = aAttributes->GetAttr(nsGkAtoms::align);
1949 0 : if (value && value->Type() == nsAttrValue::eEnum) {
1950 0 : PRInt32 align = value->GetEnumValue();
1951 0 : if (aRuleData->mSIDs & NS_STYLE_INHERIT_BIT(Display)) {
1952 0 : nsCSSValue* cssFloat = aRuleData->ValueForCssFloat();
1953 0 : if (cssFloat->GetUnit() == eCSSUnit_Null) {
1954 0 : if (align == NS_STYLE_TEXT_ALIGN_LEFT) {
1955 0 : cssFloat->SetIntValue(NS_STYLE_FLOAT_LEFT, eCSSUnit_Enumerated);
1956 0 : } else if (align == NS_STYLE_TEXT_ALIGN_RIGHT) {
1957 0 : cssFloat->SetIntValue(NS_STYLE_FLOAT_RIGHT, eCSSUnit_Enumerated);
1958 : }
1959 : }
1960 : }
1961 0 : if (aRuleData->mSIDs & NS_STYLE_INHERIT_BIT(TextReset)) {
1962 0 : nsCSSValue* verticalAlign = aRuleData->ValueForVerticalAlign();
1963 0 : if (verticalAlign->GetUnit() == eCSSUnit_Null) {
1964 0 : switch (align) {
1965 : case NS_STYLE_TEXT_ALIGN_LEFT:
1966 : case NS_STYLE_TEXT_ALIGN_RIGHT:
1967 0 : break;
1968 : default:
1969 0 : verticalAlign->SetIntValue(align, eCSSUnit_Enumerated);
1970 0 : break;
1971 : }
1972 : }
1973 : }
1974 : }
1975 : }
1976 0 : }
1977 :
1978 : void
1979 0 : nsGenericHTMLElement::MapDivAlignAttributeInto(const nsMappedAttributes* aAttributes,
1980 : nsRuleData* aRuleData)
1981 : {
1982 0 : if (aRuleData->mSIDs & NS_STYLE_INHERIT_BIT(Text)) {
1983 0 : nsCSSValue* textAlign = aRuleData->ValueForTextAlign();
1984 0 : if (textAlign->GetUnit() == eCSSUnit_Null) {
1985 : // align: enum
1986 0 : const nsAttrValue* value = aAttributes->GetAttr(nsGkAtoms::align);
1987 0 : if (value && value->Type() == nsAttrValue::eEnum)
1988 0 : textAlign->SetIntValue(value->GetEnumValue(), eCSSUnit_Enumerated);
1989 : }
1990 : }
1991 0 : }
1992 :
1993 :
1994 : void
1995 0 : nsGenericHTMLElement::MapImageMarginAttributeInto(const nsMappedAttributes* aAttributes,
1996 : nsRuleData* aData)
1997 : {
1998 0 : if (!(aData->mSIDs & NS_STYLE_INHERIT_BIT(Margin)))
1999 0 : return;
2000 :
2001 : const nsAttrValue* value;
2002 :
2003 : // hspace: value
2004 0 : value = aAttributes->GetAttr(nsGkAtoms::hspace);
2005 0 : if (value) {
2006 0 : nsCSSValue hval;
2007 0 : if (value->Type() == nsAttrValue::eInteger)
2008 0 : hval.SetFloatValue((float)value->GetIntegerValue(), eCSSUnit_Pixel);
2009 0 : else if (value->Type() == nsAttrValue::ePercent)
2010 0 : hval.SetPercentValue(value->GetPercentValue());
2011 :
2012 0 : if (hval.GetUnit() != eCSSUnit_Null) {
2013 0 : nsCSSValue* left = aData->ValueForMarginLeftValue();
2014 0 : if (left->GetUnit() == eCSSUnit_Null)
2015 0 : *left = hval;
2016 0 : nsCSSValue* right = aData->ValueForMarginRightValue();
2017 0 : if (right->GetUnit() == eCSSUnit_Null)
2018 0 : *right = hval;
2019 : }
2020 : }
2021 :
2022 : // vspace: value
2023 0 : value = aAttributes->GetAttr(nsGkAtoms::vspace);
2024 0 : if (value) {
2025 0 : nsCSSValue vval;
2026 0 : if (value->Type() == nsAttrValue::eInteger)
2027 0 : vval.SetFloatValue((float)value->GetIntegerValue(), eCSSUnit_Pixel);
2028 0 : else if (value->Type() == nsAttrValue::ePercent)
2029 0 : vval.SetPercentValue(value->GetPercentValue());
2030 :
2031 0 : if (vval.GetUnit() != eCSSUnit_Null) {
2032 0 : nsCSSValue* top = aData->ValueForMarginTop();
2033 0 : if (top->GetUnit() == eCSSUnit_Null)
2034 0 : *top = vval;
2035 0 : nsCSSValue* bottom = aData->ValueForMarginBottom();
2036 0 : if (bottom->GetUnit() == eCSSUnit_Null)
2037 0 : *bottom = vval;
2038 : }
2039 : }
2040 : }
2041 :
2042 : void
2043 0 : nsGenericHTMLElement::MapImageSizeAttributesInto(const nsMappedAttributes* aAttributes,
2044 : nsRuleData* aData)
2045 : {
2046 0 : if (!(aData->mSIDs & NS_STYLE_INHERIT_BIT(Position)))
2047 0 : return;
2048 :
2049 : // width: value
2050 0 : nsCSSValue* width = aData->ValueForWidth();
2051 0 : if (width->GetUnit() == eCSSUnit_Null) {
2052 0 : const nsAttrValue* value = aAttributes->GetAttr(nsGkAtoms::width);
2053 0 : if (value && value->Type() == nsAttrValue::eInteger)
2054 0 : width->SetFloatValue((float)value->GetIntegerValue(), eCSSUnit_Pixel);
2055 0 : else if (value && value->Type() == nsAttrValue::ePercent)
2056 0 : width->SetPercentValue(value->GetPercentValue());
2057 : }
2058 :
2059 : // height: value
2060 0 : nsCSSValue* height = aData->ValueForHeight();
2061 0 : if (height->GetUnit() == eCSSUnit_Null) {
2062 0 : const nsAttrValue* value = aAttributes->GetAttr(nsGkAtoms::height);
2063 0 : if (value && value->Type() == nsAttrValue::eInteger)
2064 0 : height->SetFloatValue((float)value->GetIntegerValue(), eCSSUnit_Pixel);
2065 0 : else if (value && value->Type() == nsAttrValue::ePercent)
2066 0 : height->SetPercentValue(value->GetPercentValue());
2067 : }
2068 : }
2069 :
2070 : void
2071 0 : nsGenericHTMLElement::MapImageBorderAttributeInto(const nsMappedAttributes* aAttributes,
2072 : nsRuleData* aData)
2073 : {
2074 0 : if (!(aData->mSIDs & NS_STYLE_INHERIT_BIT(Border)))
2075 0 : return;
2076 :
2077 : // border: pixels
2078 0 : const nsAttrValue* value = aAttributes->GetAttr(nsGkAtoms::border);
2079 0 : if (!value)
2080 0 : return;
2081 :
2082 0 : nscoord val = 0;
2083 0 : if (value->Type() == nsAttrValue::eInteger)
2084 0 : val = value->GetIntegerValue();
2085 :
2086 0 : nsCSSValue* borderLeftWidth = aData->ValueForBorderLeftWidthValue();
2087 0 : if (borderLeftWidth->GetUnit() == eCSSUnit_Null)
2088 0 : borderLeftWidth->SetFloatValue((float)val, eCSSUnit_Pixel);
2089 0 : nsCSSValue* borderTopWidth = aData->ValueForBorderTopWidth();
2090 0 : if (borderTopWidth->GetUnit() == eCSSUnit_Null)
2091 0 : borderTopWidth->SetFloatValue((float)val, eCSSUnit_Pixel);
2092 0 : nsCSSValue* borderRightWidth = aData->ValueForBorderRightWidthValue();
2093 0 : if (borderRightWidth->GetUnit() == eCSSUnit_Null)
2094 0 : borderRightWidth->SetFloatValue((float)val, eCSSUnit_Pixel);
2095 0 : nsCSSValue* borderBottomWidth = aData->ValueForBorderBottomWidth();
2096 0 : if (borderBottomWidth->GetUnit() == eCSSUnit_Null)
2097 0 : borderBottomWidth->SetFloatValue((float)val, eCSSUnit_Pixel);
2098 :
2099 0 : nsCSSValue* borderLeftStyle = aData->ValueForBorderLeftStyleValue();
2100 0 : if (borderLeftStyle->GetUnit() == eCSSUnit_Null)
2101 0 : borderLeftStyle->SetIntValue(NS_STYLE_BORDER_STYLE_SOLID, eCSSUnit_Enumerated);
2102 0 : nsCSSValue* borderTopStyle = aData->ValueForBorderTopStyle();
2103 0 : if (borderTopStyle->GetUnit() == eCSSUnit_Null)
2104 0 : borderTopStyle->SetIntValue(NS_STYLE_BORDER_STYLE_SOLID, eCSSUnit_Enumerated);
2105 0 : nsCSSValue* borderRightStyle = aData->ValueForBorderRightStyleValue();
2106 0 : if (borderRightStyle->GetUnit() == eCSSUnit_Null)
2107 0 : borderRightStyle->SetIntValue(NS_STYLE_BORDER_STYLE_SOLID, eCSSUnit_Enumerated);
2108 0 : nsCSSValue* borderBottomStyle = aData->ValueForBorderBottomStyle();
2109 0 : if (borderBottomStyle->GetUnit() == eCSSUnit_Null)
2110 0 : borderBottomStyle->SetIntValue(NS_STYLE_BORDER_STYLE_SOLID, eCSSUnit_Enumerated);
2111 :
2112 0 : nsCSSValue* borderLeftColor = aData->ValueForBorderLeftColorValue();
2113 0 : if (borderLeftColor->GetUnit() == eCSSUnit_Null)
2114 0 : borderLeftColor->SetIntValue(NS_STYLE_COLOR_MOZ_USE_TEXT_COLOR, eCSSUnit_Enumerated);
2115 0 : nsCSSValue* borderTopColor = aData->ValueForBorderTopColor();
2116 0 : if (borderTopColor->GetUnit() == eCSSUnit_Null)
2117 0 : borderTopColor->SetIntValue(NS_STYLE_COLOR_MOZ_USE_TEXT_COLOR, eCSSUnit_Enumerated);
2118 0 : nsCSSValue* borderRightColor = aData->ValueForBorderRightColorValue();
2119 0 : if (borderRightColor->GetUnit() == eCSSUnit_Null)
2120 0 : borderRightColor->SetIntValue(NS_STYLE_COLOR_MOZ_USE_TEXT_COLOR, eCSSUnit_Enumerated);
2121 0 : nsCSSValue* borderBottomColor = aData->ValueForBorderBottomColor();
2122 0 : if (borderBottomColor->GetUnit() == eCSSUnit_Null)
2123 0 : borderBottomColor->SetIntValue(NS_STYLE_COLOR_MOZ_USE_TEXT_COLOR, eCSSUnit_Enumerated);
2124 : }
2125 :
2126 : void
2127 0 : nsGenericHTMLElement::MapBackgroundInto(const nsMappedAttributes* aAttributes,
2128 : nsRuleData* aData)
2129 : {
2130 0 : if (!(aData->mSIDs & NS_STYLE_INHERIT_BIT(Background)))
2131 0 : return;
2132 :
2133 0 : nsPresContext* presContext = aData->mPresContext;
2134 0 : nsCSSValue* backImage = aData->ValueForBackgroundImage();
2135 0 : if (backImage->GetUnit() == eCSSUnit_Null &&
2136 0 : presContext->UseDocumentColors()) {
2137 : // background
2138 0 : const nsAttrValue* value = aAttributes->GetAttr(nsGkAtoms::background);
2139 0 : if (value && value->Type() == nsAttrValue::eString) {
2140 0 : const nsString& spec = value->GetStringValue();
2141 0 : if (!spec.IsEmpty()) {
2142 : // Resolve url to an absolute url
2143 : // XXX this breaks if the HTML element has an xml:base
2144 : // attribute (the xml:base will not be taken into account)
2145 : // as well as elements with _baseHref set. We need to be able
2146 : // to get to the element somehow, or store the base URI in the
2147 : // attributes.
2148 0 : nsIDocument* doc = presContext->Document();
2149 0 : nsCOMPtr<nsIURI> uri;
2150 : nsresult rv = nsContentUtils::NewURIWithDocumentCharset(
2151 0 : getter_AddRefs(uri), spec, doc, doc->GetDocBaseURI());
2152 0 : if (NS_SUCCEEDED(rv)) {
2153 : // Note that this should generally succeed here, due to the way
2154 : // |spec| is created. Maybe we should just add an nsStringBuffer
2155 : // accessor on nsAttrValue?
2156 0 : nsRefPtr<nsStringBuffer> buffer = nsCSSValue::BufferFromString(spec);
2157 0 : if (NS_LIKELY(buffer)) {
2158 : // XXXbz it would be nice to assert that doc->NodePrincipal() is
2159 : // the same as the principal of the node (which we'd need to store
2160 : // in the mapped attrs or something?)
2161 : nsCSSValue::Image *img =
2162 : new nsCSSValue::Image(uri, buffer, doc->GetDocumentURI(),
2163 0 : doc->NodePrincipal(), doc);
2164 0 : if (NS_LIKELY(img)) {
2165 0 : nsCSSValueList* list = backImage->SetListValue();
2166 0 : list->mValue.SetImageValue(img);
2167 : }
2168 : }
2169 : }
2170 : }
2171 0 : else if (presContext->CompatibilityMode() == eCompatibility_NavQuirks) {
2172 : // in NavQuirks mode, allow the empty string to set the
2173 : // background to empty
2174 0 : nsCSSValueList* list = backImage->SetListValue();
2175 0 : list->mValue.SetNoneValue();
2176 : }
2177 : }
2178 : }
2179 : }
2180 :
2181 : void
2182 0 : nsGenericHTMLElement::MapBGColorInto(const nsMappedAttributes* aAttributes,
2183 : nsRuleData* aData)
2184 : {
2185 0 : if (!(aData->mSIDs & NS_STYLE_INHERIT_BIT(Background)))
2186 0 : return;
2187 :
2188 0 : nsCSSValue* backColor = aData->ValueForBackgroundColor();
2189 0 : if (backColor->GetUnit() == eCSSUnit_Null &&
2190 0 : aData->mPresContext->UseDocumentColors()) {
2191 0 : const nsAttrValue* value = aAttributes->GetAttr(nsGkAtoms::bgcolor);
2192 : nscolor color;
2193 0 : if (value && value->GetColorValue(color)) {
2194 0 : backColor->SetColorValue(color);
2195 : }
2196 : }
2197 : }
2198 :
2199 : void
2200 0 : nsGenericHTMLElement::MapBackgroundAttributesInto(const nsMappedAttributes* aAttributes,
2201 : nsRuleData* aData)
2202 : {
2203 0 : MapBackgroundInto(aAttributes, aData);
2204 0 : MapBGColorInto(aAttributes, aData);
2205 0 : }
2206 :
2207 : void
2208 0 : nsGenericHTMLElement::MapScrollingAttributeInto(const nsMappedAttributes* aAttributes,
2209 : nsRuleData* aData)
2210 : {
2211 0 : if (!(aData->mSIDs & NS_STYLE_INHERIT_BIT(Display)))
2212 0 : return;
2213 :
2214 : // scrolling
2215 : nsCSSValue* overflowValues[2] = {
2216 0 : aData->ValueForOverflowX(),
2217 0 : aData->ValueForOverflowY(),
2218 0 : };
2219 0 : for (PRUint32 i = 0; i < ArrayLength(overflowValues); ++i) {
2220 0 : if (overflowValues[i]->GetUnit() == eCSSUnit_Null) {
2221 0 : const nsAttrValue* value = aAttributes->GetAttr(nsGkAtoms::scrolling);
2222 0 : if (value && value->Type() == nsAttrValue::eEnum) {
2223 : PRInt32 mappedValue;
2224 0 : switch (value->GetEnumValue()) {
2225 : case NS_STYLE_FRAME_ON:
2226 : case NS_STYLE_FRAME_SCROLL:
2227 : case NS_STYLE_FRAME_YES:
2228 0 : mappedValue = NS_STYLE_OVERFLOW_SCROLL;
2229 0 : break;
2230 :
2231 : case NS_STYLE_FRAME_OFF:
2232 : case NS_STYLE_FRAME_NOSCROLL:
2233 : case NS_STYLE_FRAME_NO:
2234 0 : mappedValue = NS_STYLE_OVERFLOW_HIDDEN;
2235 0 : break;
2236 :
2237 : case NS_STYLE_FRAME_AUTO:
2238 0 : mappedValue = NS_STYLE_OVERFLOW_AUTO;
2239 0 : break;
2240 :
2241 : default:
2242 0 : NS_NOTREACHED("unexpected value");
2243 0 : mappedValue = NS_STYLE_OVERFLOW_AUTO;
2244 0 : break;
2245 : }
2246 0 : overflowValues[i]->SetIntValue(mappedValue, eCSSUnit_Enumerated);
2247 : }
2248 : }
2249 : }
2250 : }
2251 :
2252 : //----------------------------------------------------------------------
2253 :
2254 : nsresult
2255 1 : nsGenericHTMLElement::GetAttrHelper(nsIAtom* aAttr, nsAString& aValue)
2256 : {
2257 1 : GetAttr(kNameSpaceID_None, aAttr, aValue);
2258 1 : return NS_OK;
2259 : }
2260 :
2261 : nsresult
2262 0 : nsGenericHTMLElement::SetAttrHelper(nsIAtom* aAttr, const nsAString& aValue)
2263 : {
2264 0 : return SetAttr(kNameSpaceID_None, aAttr, aValue, true);
2265 : }
2266 :
2267 : nsresult
2268 0 : nsGenericHTMLElement::SetBoolAttr(nsIAtom* aAttr, bool aValue)
2269 : {
2270 0 : if (aValue) {
2271 0 : return SetAttr(kNameSpaceID_None, aAttr, EmptyString(), true);
2272 : }
2273 :
2274 0 : return UnsetAttr(kNameSpaceID_None, aAttr, true);
2275 : }
2276 :
2277 : nsresult
2278 1 : nsGenericHTMLElement::GetBoolAttr(nsIAtom* aAttr, bool* aValue) const
2279 : {
2280 1 : *aValue = HasAttr(kNameSpaceID_None, aAttr);
2281 1 : return NS_OK;
2282 : }
2283 :
2284 : nsresult
2285 0 : nsGenericHTMLElement::GetIntAttr(nsIAtom* aAttr, PRInt32 aDefault, PRInt32* aResult)
2286 : {
2287 0 : const nsAttrValue* attrVal = mAttrsAndChildren.GetAttr(aAttr);
2288 0 : if (attrVal && attrVal->Type() == nsAttrValue::eInteger) {
2289 0 : *aResult = attrVal->GetIntegerValue();
2290 : }
2291 : else {
2292 0 : *aResult = aDefault;
2293 : }
2294 0 : return NS_OK;
2295 : }
2296 :
2297 : nsresult
2298 0 : nsGenericHTMLElement::SetIntAttr(nsIAtom* aAttr, PRInt32 aValue)
2299 : {
2300 0 : nsAutoString value;
2301 0 : value.AppendInt(aValue);
2302 :
2303 0 : return SetAttr(kNameSpaceID_None, aAttr, value, true);
2304 : }
2305 :
2306 : nsresult
2307 0 : nsGenericHTMLElement::GetUnsignedIntAttr(nsIAtom* aAttr, PRUint32 aDefault,
2308 : PRUint32* aResult)
2309 : {
2310 0 : const nsAttrValue* attrVal = mAttrsAndChildren.GetAttr(aAttr);
2311 0 : if (attrVal && attrVal->Type() == nsAttrValue::eInteger) {
2312 0 : *aResult = attrVal->GetIntegerValue();
2313 : }
2314 : else {
2315 0 : *aResult = aDefault;
2316 : }
2317 0 : return NS_OK;
2318 : }
2319 :
2320 : nsresult
2321 0 : nsGenericHTMLElement::SetUnsignedIntAttr(nsIAtom* aAttr, PRUint32 aValue)
2322 : {
2323 0 : nsAutoString value;
2324 0 : value.AppendInt(aValue);
2325 :
2326 0 : return SetAttr(kNameSpaceID_None, aAttr, value, true);
2327 : }
2328 :
2329 : nsresult
2330 0 : nsGenericHTMLElement::GetDoubleAttr(nsIAtom* aAttr, double aDefault, double* aResult)
2331 : {
2332 0 : const nsAttrValue* attrVal = mAttrsAndChildren.GetAttr(aAttr);
2333 0 : if (attrVal && attrVal->Type() == nsAttrValue::eDoubleValue) {
2334 0 : *aResult = attrVal->GetDoubleValue();
2335 : }
2336 : else {
2337 0 : *aResult = aDefault;
2338 : }
2339 0 : return NS_OK;
2340 : }
2341 :
2342 : nsresult
2343 0 : nsGenericHTMLElement::SetDoubleAttr(nsIAtom* aAttr, double aValue)
2344 : {
2345 0 : nsAutoString value;
2346 0 : value.AppendFloat(aValue);
2347 :
2348 0 : return SetAttr(kNameSpaceID_None, aAttr, value, true);
2349 : }
2350 :
2351 : nsresult
2352 0 : nsGenericHTMLElement::GetURIAttr(nsIAtom* aAttr, nsIAtom* aBaseAttr, nsAString& aResult)
2353 : {
2354 0 : nsCOMPtr<nsIURI> uri;
2355 0 : bool hadAttr = GetURIAttr(aAttr, aBaseAttr, getter_AddRefs(uri));
2356 0 : if (!hadAttr) {
2357 0 : aResult.Truncate();
2358 0 : return NS_OK;
2359 : }
2360 :
2361 0 : if (!uri) {
2362 : // Just return the attr value
2363 0 : GetAttr(kNameSpaceID_None, aAttr, aResult);
2364 0 : return NS_OK;
2365 : }
2366 :
2367 0 : nsCAutoString spec;
2368 0 : uri->GetSpec(spec);
2369 0 : CopyUTF8toUTF16(spec, aResult);
2370 0 : return NS_OK;
2371 : }
2372 :
2373 : bool
2374 0 : nsGenericHTMLElement::GetURIAttr(nsIAtom* aAttr, nsIAtom* aBaseAttr, nsIURI** aURI) const
2375 : {
2376 0 : *aURI = nsnull;
2377 :
2378 0 : const nsAttrValue* attr = mAttrsAndChildren.GetAttr(aAttr);
2379 0 : if (!attr) {
2380 0 : return false;
2381 : }
2382 :
2383 0 : nsCOMPtr<nsIURI> baseURI = GetBaseURI();
2384 :
2385 0 : if (aBaseAttr) {
2386 0 : nsAutoString baseAttrValue;
2387 0 : if (GetAttr(kNameSpaceID_None, aBaseAttr, baseAttrValue)) {
2388 0 : nsCOMPtr<nsIURI> baseAttrURI;
2389 : nsresult rv =
2390 0 : nsContentUtils::NewURIWithDocumentCharset(getter_AddRefs(baseAttrURI),
2391 : baseAttrValue, OwnerDoc(),
2392 0 : baseURI);
2393 0 : if (NS_FAILED(rv)) {
2394 0 : return true;
2395 : }
2396 0 : baseURI.swap(baseAttrURI);
2397 : }
2398 : }
2399 :
2400 : // Don't care about return value. If it fails, we still want to
2401 : // return true, and *aURI will be null.
2402 : nsContentUtils::NewURIWithDocumentCharset(aURI,
2403 0 : attr->GetStringValue(),
2404 0 : OwnerDoc(), baseURI);
2405 0 : return true;
2406 : }
2407 :
2408 : nsresult
2409 0 : nsGenericHTMLElement::GetURIListAttr(nsIAtom* aAttr, nsAString& aResult)
2410 : {
2411 0 : aResult.Truncate();
2412 :
2413 0 : nsAutoString value;
2414 0 : if (!GetAttr(kNameSpaceID_None, aAttr, value))
2415 0 : return NS_OK;
2416 :
2417 0 : nsIDocument* doc = OwnerDoc();
2418 0 : nsCOMPtr<nsIURI> baseURI = GetBaseURI();
2419 :
2420 : // Value contains relative URIs split on spaces (U+0020)
2421 0 : const PRUnichar *start = value.BeginReading();
2422 0 : const PRUnichar *end = value.EndReading();
2423 0 : const PRUnichar *iter = start;
2424 0 : for (;;) {
2425 0 : if (iter < end && *iter != ' ') {
2426 0 : ++iter;
2427 : } else { // iter is pointing at either end or a space
2428 0 : while (*start == ' ' && start < iter)
2429 0 : ++start;
2430 0 : if (iter != start) {
2431 0 : if (!aResult.IsEmpty())
2432 0 : aResult.Append(PRUnichar(' '));
2433 0 : const nsSubstring& uriPart = Substring(start, iter);
2434 0 : nsCOMPtr<nsIURI> attrURI;
2435 0 : nsContentUtils::NewURIWithDocumentCharset(getter_AddRefs(attrURI),
2436 0 : uriPart, doc, baseURI);
2437 0 : if (attrURI) {
2438 0 : nsCAutoString spec;
2439 0 : attrURI->GetSpec(spec);
2440 0 : AppendUTF8toUTF16(spec, aResult);
2441 : } else {
2442 0 : aResult.Append(uriPart);
2443 : }
2444 : }
2445 0 : start = iter = iter + 1;
2446 0 : if (iter >= end)
2447 : break;
2448 : }
2449 : }
2450 :
2451 0 : return NS_OK;
2452 : }
2453 :
2454 : nsresult
2455 0 : nsGenericHTMLElement::GetEnumAttr(nsIAtom* aAttr,
2456 : const char* aDefault,
2457 : nsAString& aResult)
2458 : {
2459 0 : const nsAttrValue* attrVal = mAttrsAndChildren.GetAttr(aAttr);
2460 :
2461 0 : aResult.Truncate();
2462 :
2463 0 : if (attrVal && attrVal->Type() == nsAttrValue::eEnum) {
2464 0 : attrVal->GetEnumString(aResult, true);
2465 0 : } else if (aDefault) {
2466 0 : AppendASCIItoUTF16(nsDependentCString(aDefault), aResult);
2467 : }
2468 :
2469 0 : return NS_OK;
2470 : }
2471 :
2472 : nsresult
2473 0 : nsGenericHTMLElement::GetContentEditable(nsAString& aContentEditable)
2474 : {
2475 0 : ContentEditableTristate value = GetContentEditableValue();
2476 :
2477 0 : if (value == eTrue) {
2478 0 : aContentEditable.AssignLiteral("true");
2479 : }
2480 0 : else if (value == eFalse) {
2481 0 : aContentEditable.AssignLiteral("false");
2482 : }
2483 : else {
2484 0 : aContentEditable.AssignLiteral("inherit");
2485 : }
2486 :
2487 0 : return NS_OK;
2488 : }
2489 :
2490 : nsresult
2491 0 : nsGenericHTMLElement::SetContentEditable(const nsAString& aContentEditable)
2492 : {
2493 0 : if (nsContentUtils::EqualsLiteralIgnoreASCIICase(aContentEditable, "inherit")) {
2494 0 : UnsetAttr(kNameSpaceID_None, nsGkAtoms::contenteditable, true);
2495 :
2496 0 : return NS_OK;
2497 : }
2498 :
2499 0 : if (nsContentUtils::EqualsLiteralIgnoreASCIICase(aContentEditable, "true")) {
2500 0 : SetAttr(kNameSpaceID_None, nsGkAtoms::contenteditable, NS_LITERAL_STRING("true"), true);
2501 :
2502 0 : return NS_OK;
2503 : }
2504 :
2505 0 : if (nsContentUtils::EqualsLiteralIgnoreASCIICase(aContentEditable, "false")) {
2506 0 : SetAttr(kNameSpaceID_None, nsGkAtoms::contenteditable, NS_LITERAL_STRING("false"), true);
2507 :
2508 0 : return NS_OK;
2509 : }
2510 :
2511 0 : return NS_ERROR_DOM_SYNTAX_ERR;
2512 : }
2513 :
2514 : nsresult
2515 0 : nsGenericHTMLElement::GetIsContentEditable(bool* aContentEditable)
2516 : {
2517 0 : NS_ENSURE_ARG_POINTER(aContentEditable);
2518 :
2519 0 : for (nsIContent* node = this; node; node = node->GetParent()) {
2520 0 : nsGenericHTMLElement* element = FromContent(node);
2521 0 : if (element) {
2522 0 : ContentEditableTristate value = element->GetContentEditableValue();
2523 0 : if (value != eInherit) {
2524 0 : *aContentEditable = value == eTrue;
2525 0 : return NS_OK;
2526 : }
2527 : }
2528 : }
2529 :
2530 0 : *aContentEditable = false;
2531 0 : return NS_OK;
2532 : }
2533 :
2534 : nsresult
2535 0 : nsGenericHTMLElement::GetContextMenu(nsIDOMHTMLMenuElement** aContextMenu)
2536 : {
2537 0 : *aContextMenu = nsnull;
2538 :
2539 0 : nsAutoString value;
2540 0 : GetAttr(kNameSpaceID_None, nsGkAtoms::contextmenu, value);
2541 :
2542 0 : if (value.IsEmpty()) {
2543 0 : return NS_OK;
2544 : }
2545 :
2546 0 : nsIDocument* doc = GetCurrentDoc();
2547 0 : if (doc) {
2548 : nsRefPtr<nsHTMLMenuElement> element =
2549 0 : nsHTMLMenuElement::FromContent(doc->GetElementById(value));
2550 0 : element.forget(aContextMenu);
2551 : }
2552 :
2553 0 : return NS_OK;
2554 : }
2555 :
2556 : //----------------------------------------------------------------------
2557 :
2558 1 : nsGenericHTMLFormElement::nsGenericHTMLFormElement(already_AddRefed<nsINodeInfo> aNodeInfo)
2559 : : nsGenericHTMLElement(aNodeInfo)
2560 : , mForm(nsnull)
2561 1 : , mFieldSet(nsnull)
2562 : {
2563 : // We should add the NS_EVENT_STATE_ENABLED bit here as needed, but
2564 : // that depends on our type, which is not initialized yet. So we
2565 : // have to do this in subclasses.
2566 1 : }
2567 :
2568 2 : nsGenericHTMLFormElement::~nsGenericHTMLFormElement()
2569 : {
2570 1 : if (mFieldSet) {
2571 0 : mFieldSet->RemoveElement(this);
2572 : }
2573 :
2574 : // Check that this element doesn't know anything about its form at this point.
2575 1 : NS_ASSERTION(!mForm, "mForm should be null at this point!");
2576 2 : }
2577 :
2578 23 : NS_IMPL_QUERY_INTERFACE_INHERITED1(nsGenericHTMLFormElement,
2579 : nsGenericHTMLElement,
2580 : nsIFormControl)
2581 :
2582 : bool
2583 6 : nsGenericHTMLFormElement::IsNodeOfType(PRUint32 aFlags) const
2584 : {
2585 6 : return !(aFlags & ~(eCONTENT | eHTML_FORM_CONTROL));
2586 : }
2587 :
2588 : void
2589 0 : nsGenericHTMLFormElement::SaveSubtreeState()
2590 : {
2591 0 : SaveState();
2592 :
2593 0 : nsGenericHTMLElement::SaveSubtreeState();
2594 0 : }
2595 :
2596 : void
2597 0 : nsGenericHTMLFormElement::SetForm(nsIDOMHTMLFormElement* aForm)
2598 : {
2599 0 : NS_PRECONDITION(aForm, "Don't pass null here");
2600 0 : NS_ASSERTION(!mForm,
2601 : "We don't support switching from one non-null form to another.");
2602 :
2603 : // keep a *weak* ref to the form here
2604 0 : mForm = static_cast<nsHTMLFormElement*>(aForm);
2605 0 : }
2606 :
2607 : void
2608 0 : nsGenericHTMLFormElement::ClearForm(bool aRemoveFromForm)
2609 : {
2610 0 : NS_ASSERTION((mForm != nsnull) == HasFlag(ADDED_TO_FORM),
2611 : "Form control should have had flag set correctly");
2612 :
2613 0 : if (!mForm) {
2614 0 : return;
2615 : }
2616 :
2617 0 : if (aRemoveFromForm) {
2618 0 : nsAutoString nameVal, idVal;
2619 0 : GetAttr(kNameSpaceID_None, nsGkAtoms::name, nameVal);
2620 0 : GetAttr(kNameSpaceID_None, nsGkAtoms::id, idVal);
2621 :
2622 0 : mForm->RemoveElement(this, true);
2623 :
2624 0 : if (!nameVal.IsEmpty()) {
2625 0 : mForm->RemoveElementFromTable(this, nameVal);
2626 : }
2627 :
2628 0 : if (!idVal.IsEmpty()) {
2629 0 : mForm->RemoveElementFromTable(this, idVal);
2630 : }
2631 : }
2632 :
2633 0 : UnsetFlags(ADDED_TO_FORM);
2634 0 : mForm = nsnull;
2635 : }
2636 :
2637 : Element*
2638 1 : nsGenericHTMLFormElement::GetFormElement()
2639 : {
2640 1 : return mForm;
2641 : }
2642 :
2643 : nsresult
2644 0 : nsGenericHTMLFormElement::GetForm(nsIDOMHTMLFormElement** aForm)
2645 : {
2646 0 : NS_ENSURE_ARG_POINTER(aForm);
2647 0 : NS_IF_ADDREF(*aForm = mForm);
2648 0 : return NS_OK;
2649 : }
2650 :
2651 : nsIContent::IMEState
2652 0 : nsGenericHTMLFormElement::GetDesiredIMEState()
2653 : {
2654 0 : nsCOMPtr<nsIEditor> editor = nsnull;
2655 0 : nsresult rv = GetEditorInternal(getter_AddRefs(editor));
2656 0 : if (NS_FAILED(rv) || !editor)
2657 0 : return nsGenericHTMLElement::GetDesiredIMEState();
2658 0 : nsCOMPtr<nsIEditorIMESupport> imeEditor = do_QueryInterface(editor);
2659 0 : if (!imeEditor)
2660 0 : return nsGenericHTMLElement::GetDesiredIMEState();
2661 0 : IMEState state;
2662 0 : rv = imeEditor->GetPreferredIMEState(&state);
2663 0 : if (NS_FAILED(rv))
2664 0 : return nsGenericHTMLElement::GetDesiredIMEState();
2665 0 : return state;
2666 : }
2667 :
2668 : nsresult
2669 1 : nsGenericHTMLFormElement::BindToTree(nsIDocument* aDocument,
2670 : nsIContent* aParent,
2671 : nsIContent* aBindingParent,
2672 : bool aCompileEventHandlers)
2673 : {
2674 : nsresult rv = nsGenericHTMLElement::BindToTree(aDocument, aParent,
2675 : aBindingParent,
2676 1 : aCompileEventHandlers);
2677 1 : NS_ENSURE_SUCCESS(rv, rv);
2678 :
2679 : // An autofocus event has to be launched if the autofocus attribute is
2680 : // specified and the element accept the autofocus attribute. In addition,
2681 : // the document should not be already loaded and the "browser.autofocus"
2682 : // preference should be 'true'.
2683 1 : if (IsAutofocusable() && HasAttr(kNameSpaceID_None, nsGkAtoms::autofocus) &&
2684 0 : Preferences::GetBool("browser.autofocus", true)) {
2685 0 : nsCOMPtr<nsIRunnable> event = new nsAutoFocusEvent(this);
2686 0 : rv = NS_DispatchToCurrentThread(event);
2687 0 : NS_ENSURE_SUCCESS(rv, rv);
2688 : }
2689 :
2690 : // If @form is set, the element *has* to be in a document, otherwise it
2691 : // wouldn't be possible to find an element with the corresponding id.
2692 : // If @form isn't set, the element *has* to have a parent, otherwise it
2693 : // wouldn't be possible to find a form ancestor.
2694 : // We should not call UpdateFormOwner if none of these conditions are
2695 : // fulfilled.
2696 1 : if (HasAttr(kNameSpaceID_None, nsGkAtoms::form) ? !!GetCurrentDoc()
2697 : : !!aParent) {
2698 1 : UpdateFormOwner(true, nsnull);
2699 : }
2700 :
2701 : // Set parent fieldset which should be used for the disabled state.
2702 1 : UpdateFieldSet(false);
2703 :
2704 1 : return NS_OK;
2705 : }
2706 :
2707 : void
2708 3 : nsGenericHTMLFormElement::UnbindFromTree(bool aDeep, bool aNullParent)
2709 : {
2710 : // Save state before doing anything
2711 3 : SaveState();
2712 :
2713 3 : if (mForm) {
2714 : // Might need to unset mForm
2715 0 : if (aNullParent) {
2716 : // No more parent means no more form
2717 0 : ClearForm(true);
2718 : } else {
2719 : // Recheck whether we should still have an mForm.
2720 0 : if (HasAttr(kNameSpaceID_None, nsGkAtoms::form) ||
2721 0 : !FindAncestorForm(mForm)) {
2722 0 : ClearForm(true);
2723 : } else {
2724 0 : UnsetFlags(MAYBE_ORPHAN_FORM_ELEMENT);
2725 : }
2726 : }
2727 :
2728 0 : if (!mForm) {
2729 : // Our novalidate state might have changed
2730 0 : UpdateState(false);
2731 : }
2732 : }
2733 :
2734 : // We have to remove the form id observer if there was one.
2735 : // We will re-add one later if needed (during bind to tree).
2736 3 : if (nsContentUtils::HasNonEmptyAttr(this, kNameSpaceID_None,
2737 3 : nsGkAtoms::form)) {
2738 0 : RemoveFormIdObserver();
2739 : }
2740 :
2741 3 : nsGenericHTMLElement::UnbindFromTree(aDeep, aNullParent);
2742 :
2743 : // The element might not have a fieldset anymore.
2744 3 : UpdateFieldSet(false);
2745 3 : }
2746 :
2747 : nsresult
2748 0 : nsGenericHTMLFormElement::BeforeSetAttr(PRInt32 aNameSpaceID, nsIAtom* aName,
2749 : const nsAttrValueOrString* aValue,
2750 : bool aNotify)
2751 : {
2752 0 : if (aNameSpaceID == kNameSpaceID_None) {
2753 0 : nsAutoString tmp;
2754 :
2755 : // remove the control from the hashtable as needed
2756 :
2757 0 : if (mForm && (aName == nsGkAtoms::name || aName == nsGkAtoms::id)) {
2758 0 : GetAttr(kNameSpaceID_None, aName, tmp);
2759 :
2760 0 : if (!tmp.IsEmpty()) {
2761 0 : mForm->RemoveElementFromTable(this, tmp);
2762 : }
2763 : }
2764 :
2765 0 : if (mForm && aName == nsGkAtoms::type) {
2766 0 : GetAttr(kNameSpaceID_None, nsGkAtoms::name, tmp);
2767 :
2768 0 : if (!tmp.IsEmpty()) {
2769 0 : mForm->RemoveElementFromTable(this, tmp);
2770 : }
2771 :
2772 0 : GetAttr(kNameSpaceID_None, nsGkAtoms::id, tmp);
2773 :
2774 0 : if (!tmp.IsEmpty()) {
2775 0 : mForm->RemoveElementFromTable(this, tmp);
2776 : }
2777 :
2778 0 : mForm->RemoveElement(this, false);
2779 :
2780 : // Removing the element from the form can make it not be the default
2781 : // control anymore. Go ahead and notify on that change, though we might
2782 : // end up readding and becoming the default control again in
2783 : // AfterSetAttr.
2784 : // FIXME: Bug 656197
2785 0 : UpdateState(aNotify);
2786 : }
2787 :
2788 0 : if (aName == nsGkAtoms::form) {
2789 : // If @form isn't set or set to the empty string, there were no observer
2790 : // so we don't have to remove it.
2791 0 : if (nsContentUtils::HasNonEmptyAttr(this, kNameSpaceID_None,
2792 0 : nsGkAtoms::form)) {
2793 : // The current form id observer is no longer needed.
2794 : // A new one may be added in AfterSetAttr.
2795 0 : RemoveFormIdObserver();
2796 : }
2797 : }
2798 : }
2799 :
2800 : return nsGenericHTMLElement::BeforeSetAttr(aNameSpaceID, aName,
2801 0 : aValue, aNotify);
2802 : }
2803 :
2804 : nsresult
2805 0 : nsGenericHTMLFormElement::AfterSetAttr(PRInt32 aNameSpaceID, nsIAtom* aName,
2806 : const nsAttrValue* aValue, bool aNotify)
2807 : {
2808 0 : if (aNameSpaceID == kNameSpaceID_None) {
2809 : // add the control to the hashtable as needed
2810 :
2811 0 : if (mForm && (aName == nsGkAtoms::name || aName == nsGkAtoms::id) &&
2812 0 : aValue && !aValue->IsEmptyString()) {
2813 0 : NS_ABORT_IF_FALSE(aValue->Type() == nsAttrValue::eAtom,
2814 : "Expected atom value for name/id");
2815 : mForm->AddElementToTable(this,
2816 0 : nsDependentAtomString(aValue->GetAtomValue()));
2817 : }
2818 :
2819 0 : if (mForm && aName == nsGkAtoms::type) {
2820 0 : nsAutoString tmp;
2821 :
2822 0 : GetAttr(kNameSpaceID_None, nsGkAtoms::name, tmp);
2823 :
2824 0 : if (!tmp.IsEmpty()) {
2825 0 : mForm->AddElementToTable(this, tmp);
2826 : }
2827 :
2828 0 : GetAttr(kNameSpaceID_None, nsGkAtoms::id, tmp);
2829 :
2830 0 : if (!tmp.IsEmpty()) {
2831 0 : mForm->AddElementToTable(this, tmp);
2832 : }
2833 :
2834 0 : mForm->AddElement(this, false, aNotify);
2835 :
2836 : // Adding the element to the form can make it be the default control .
2837 : // Go ahead and notify on that change.
2838 : // Note: no need to notify on CanBeDisabled(), since type attr
2839 : // changes can't affect that.
2840 0 : UpdateState(aNotify);
2841 : }
2842 :
2843 0 : if (aName == nsGkAtoms::form) {
2844 : // We need a new form id observer.
2845 0 : nsIDocument* doc = GetCurrentDoc();
2846 0 : if (doc) {
2847 0 : Element* formIdElement = nsnull;
2848 0 : if (aValue && !aValue->IsEmptyString()) {
2849 0 : formIdElement = AddFormIdObserver();
2850 : }
2851 :
2852 : // Because we have a new @form value (or no more @form), we have to
2853 : // update our form owner.
2854 0 : UpdateFormOwner(false, formIdElement);
2855 : }
2856 : }
2857 : }
2858 :
2859 : return nsGenericHTMLElement::AfterSetAttr(aNameSpaceID, aName,
2860 0 : aValue, aNotify);
2861 : }
2862 :
2863 : nsresult
2864 0 : nsGenericHTMLFormElement::PreHandleEvent(nsEventChainPreVisitor& aVisitor)
2865 : {
2866 0 : if (NS_IS_TRUSTED_EVENT(aVisitor.mEvent)) {
2867 0 : switch (aVisitor.mEvent->message) {
2868 : case NS_FOCUS_CONTENT:
2869 : {
2870 : // Check to see if focus has bubbled up from a form control's
2871 : // child textfield or button. If that's the case, don't focus
2872 : // this parent file control -- leave focus on the child.
2873 0 : nsIFormControlFrame* formControlFrame = GetFormControlFrame(true);
2874 0 : if (formControlFrame &&
2875 0 : aVisitor.mEvent->originalTarget == static_cast<nsINode*>(this))
2876 0 : formControlFrame->SetFocus(true, true);
2877 0 : break;
2878 : }
2879 : case NS_BLUR_CONTENT:
2880 : {
2881 0 : nsIFormControlFrame* formControlFrame = GetFormControlFrame(true);
2882 0 : if (formControlFrame)
2883 0 : formControlFrame->SetFocus(false, false);
2884 0 : break;
2885 : }
2886 : }
2887 : }
2888 :
2889 0 : return nsGenericHTMLElement::PreHandleEvent(aVisitor);
2890 : }
2891 :
2892 : /* virtual */
2893 : bool
2894 9 : nsGenericHTMLFormElement::IsDisabled() const
2895 : {
2896 9 : return HasAttr(kNameSpaceID_None, nsGkAtoms::disabled) ||
2897 9 : (mFieldSet && mFieldSet->IsDisabled());
2898 : }
2899 :
2900 : void
2901 0 : nsGenericHTMLFormElement::ForgetFieldSet(nsIContent* aFieldset)
2902 : {
2903 0 : if (mFieldSet == aFieldset) {
2904 0 : mFieldSet = nsnull;
2905 : }
2906 0 : }
2907 :
2908 : bool
2909 5 : nsGenericHTMLFormElement::CanBeDisabled() const
2910 : {
2911 5 : PRInt32 type = GetType();
2912 : // It's easier to test the types that _cannot_ be disabled
2913 : return
2914 : type != NS_FORM_LABEL &&
2915 : type != NS_FORM_OBJECT &&
2916 : type != NS_FORM_OUTPUT &&
2917 5 : type != NS_FORM_PROGRESS;
2918 : }
2919 :
2920 : bool
2921 0 : nsGenericHTMLFormElement::IsHTMLFocusable(bool aWithMouse,
2922 : bool* aIsFocusable,
2923 : PRInt32* aTabIndex)
2924 : {
2925 0 : if (nsGenericHTMLElement::IsHTMLFocusable(aWithMouse, aIsFocusable, aTabIndex)) {
2926 0 : return true;
2927 : }
2928 :
2929 : #ifdef XP_MACOSX
2930 : *aIsFocusable =
2931 : (!aWithMouse || nsFocusManager::sMouseFocusesFormControl) && *aIsFocusable;
2932 : #endif
2933 0 : return false;
2934 : }
2935 :
2936 : nsEventStates
2937 5 : nsGenericHTMLFormElement::IntrinsicState() const
2938 : {
2939 : // If you add attribute-dependent states here, you need to add them them to
2940 : // AfterSetAttr too. And add them to AfterSetAttr for all subclasses that
2941 : // implement IntrinsicState() and are affected by that attribute.
2942 5 : nsEventStates state = nsGenericHTMLElement::IntrinsicState();
2943 :
2944 5 : if (CanBeDisabled()) {
2945 : // :enabled/:disabled
2946 5 : if (IsDisabled()) {
2947 0 : state |= NS_EVENT_STATE_DISABLED;
2948 0 : state &= ~NS_EVENT_STATE_ENABLED;
2949 : } else {
2950 5 : state &= ~NS_EVENT_STATE_DISABLED;
2951 5 : state |= NS_EVENT_STATE_ENABLED;
2952 : }
2953 : }
2954 :
2955 5 : if (mForm && mForm->IsDefaultSubmitElement(this)) {
2956 0 : NS_ASSERTION(IsSubmitControl(),
2957 : "Default submit element that isn't a submit control.");
2958 : // We are the default submit element (:default)
2959 0 : state |= NS_EVENT_STATE_DEFAULT;
2960 : }
2961 :
2962 : return state;
2963 : }
2964 :
2965 : nsGenericHTMLFormElement::FocusTristate
2966 0 : nsGenericHTMLFormElement::FocusState()
2967 : {
2968 : // We can't be focused if we aren't in a document
2969 0 : nsIDocument* doc = GetCurrentDoc();
2970 0 : if (!doc)
2971 0 : return eUnfocusable;
2972 :
2973 : // first see if we are disabled or not. If disabled then do nothing.
2974 0 : if (IsDisabled()) {
2975 0 : return eUnfocusable;
2976 : }
2977 :
2978 : // If the window is not active, do not allow the focus to bring the
2979 : // window to the front. We update the focus controller, but do
2980 : // nothing else.
2981 0 : nsPIDOMWindow* win = doc->GetWindow();
2982 0 : if (win) {
2983 0 : nsCOMPtr<nsIDOMWindow> rootWindow = do_QueryInterface(win->GetPrivateRoot());
2984 :
2985 0 : nsCOMPtr<nsIFocusManager> fm = do_GetService(FOCUSMANAGER_CONTRACTID);
2986 0 : if (fm && rootWindow) {
2987 0 : nsCOMPtr<nsIDOMWindow> activeWindow;
2988 0 : fm->GetActiveWindow(getter_AddRefs(activeWindow));
2989 0 : if (activeWindow == rootWindow) {
2990 0 : return eActiveWindow;
2991 : }
2992 : }
2993 : }
2994 :
2995 0 : return eInactiveWindow;
2996 : }
2997 :
2998 : Element*
2999 0 : nsGenericHTMLFormElement::AddFormIdObserver()
3000 : {
3001 0 : NS_ASSERTION(GetCurrentDoc(), "When adding a form id observer, "
3002 : "we should be in a document!");
3003 :
3004 0 : nsAutoString formId;
3005 0 : nsIDocument* doc = OwnerDoc();
3006 0 : GetAttr(kNameSpaceID_None, nsGkAtoms::form, formId);
3007 0 : NS_ASSERTION(!formId.IsEmpty(),
3008 : "@form value should not be the empty string!");
3009 0 : nsCOMPtr<nsIAtom> atom = do_GetAtom(formId);
3010 :
3011 0 : return doc->AddIDTargetObserver(atom, FormIdUpdated, this, false);
3012 : }
3013 :
3014 : void
3015 0 : nsGenericHTMLFormElement::RemoveFormIdObserver()
3016 : {
3017 : /**
3018 : * We are using OwnerDoc() because we don't really care about having the
3019 : * element actually being in the tree. If it is not and @form value changes,
3020 : * this method will be called for nothing but removing an observer which does
3021 : * not exist doesn't cost so much (no entry in the hash table) so having a
3022 : * boolean for GetCurrentDoc()/GetOwnerDoc() would make everything look more
3023 : * complex for nothing.
3024 : */
3025 :
3026 0 : nsIDocument* doc = OwnerDoc();
3027 :
3028 : // At this point, we may not have a document anymore. In that case, we can't
3029 : // remove the observer. The document did that for us.
3030 0 : if (!doc) {
3031 0 : return;
3032 : }
3033 :
3034 0 : nsAutoString formId;
3035 0 : GetAttr(kNameSpaceID_None, nsGkAtoms::form, formId);
3036 0 : NS_ASSERTION(!formId.IsEmpty(),
3037 : "@form value should not be the empty string!");
3038 0 : nsCOMPtr<nsIAtom> atom = do_GetAtom(formId);
3039 :
3040 0 : doc->RemoveIDTargetObserver(atom, FormIdUpdated, this, false);
3041 : }
3042 :
3043 :
3044 : /* static */
3045 : bool
3046 0 : nsGenericHTMLFormElement::FormIdUpdated(Element* aOldElement,
3047 : Element* aNewElement,
3048 : void* aData)
3049 : {
3050 : nsGenericHTMLFormElement* element =
3051 0 : static_cast<nsGenericHTMLFormElement*>(aData);
3052 :
3053 0 : NS_ASSERTION(element->IsHTML(), "aData should be an HTML element");
3054 :
3055 0 : element->UpdateFormOwner(false, aNewElement);
3056 :
3057 0 : return true;
3058 : }
3059 :
3060 : bool
3061 0 : nsGenericHTMLFormElement::IsElementDisabledForEvents(PRUint32 aMessage,
3062 : nsIFrame* aFrame)
3063 : {
3064 0 : bool disabled = IsDisabled();
3065 0 : if (!disabled && aFrame) {
3066 0 : const nsStyleUserInterface* uiStyle = aFrame->GetStyleUserInterface();
3067 : disabled = uiStyle->mUserInput == NS_STYLE_USER_INPUT_NONE ||
3068 0 : uiStyle->mUserInput == NS_STYLE_USER_INPUT_DISABLED;
3069 :
3070 : }
3071 0 : return disabled && aMessage != NS_MOUSE_MOVE;
3072 : }
3073 :
3074 : void
3075 1 : nsGenericHTMLFormElement::UpdateFormOwner(bool aBindToTree,
3076 : Element* aFormIdElement)
3077 : {
3078 1 : NS_PRECONDITION(!aBindToTree || !aFormIdElement,
3079 : "aFormIdElement shouldn't be set if aBindToTree is true!");
3080 :
3081 1 : bool needStateUpdate = false;
3082 1 : if (!aBindToTree) {
3083 0 : needStateUpdate = mForm && mForm->IsDefaultSubmitElement(this);
3084 0 : ClearForm(true);
3085 : }
3086 :
3087 1 : nsHTMLFormElement *oldForm = mForm;
3088 :
3089 1 : if (!mForm) {
3090 : // If @form is set, we have to use that to find the form.
3091 2 : nsAutoString formId;
3092 1 : if (GetAttr(kNameSpaceID_None, nsGkAtoms::form, formId)) {
3093 0 : if (!formId.IsEmpty()) {
3094 0 : Element* element = nsnull;
3095 :
3096 0 : if (aBindToTree) {
3097 0 : element = AddFormIdObserver();
3098 : } else {
3099 0 : element = aFormIdElement;
3100 : }
3101 :
3102 0 : NS_ASSERTION(GetCurrentDoc(), "The element should be in a document "
3103 : "when UpdateFormOwner is called!");
3104 0 : NS_ASSERTION(!GetCurrentDoc() ||
3105 : element == GetCurrentDoc()->GetElementById(formId),
3106 : "element should be equals to the current element "
3107 : "associated with the id in @form!");
3108 :
3109 0 : if (element && element->IsHTML(nsGkAtoms::form)) {
3110 0 : mForm = static_cast<nsHTMLFormElement*>(element);
3111 : }
3112 : }
3113 : } else {
3114 : // We now have a parent, so we may have picked up an ancestor form. Search
3115 : // for it. Note that if mForm is already set we don't want to do this,
3116 : // because that means someone (probably the content sink) has already set
3117 : // it to the right value. Also note that even if being bound here didn't
3118 : // change our parent, we still need to search, since our parent chain
3119 : // probably changed _somewhere_.
3120 1 : mForm = FindAncestorForm();
3121 : }
3122 : }
3123 :
3124 1 : if (mForm && !HasFlag(ADDED_TO_FORM)) {
3125 : // Now we need to add ourselves to the form
3126 0 : nsAutoString nameVal, idVal;
3127 0 : GetAttr(kNameSpaceID_None, nsGkAtoms::name, nameVal);
3128 0 : GetAttr(kNameSpaceID_None, nsGkAtoms::id, idVal);
3129 :
3130 0 : SetFlags(ADDED_TO_FORM);
3131 :
3132 : // Notify only if we just found this mForm.
3133 0 : mForm->AddElement(this, true, oldForm == nsnull);
3134 :
3135 0 : if (!nameVal.IsEmpty()) {
3136 0 : mForm->AddElementToTable(this, nameVal);
3137 : }
3138 :
3139 0 : if (!idVal.IsEmpty()) {
3140 0 : mForm->AddElementToTable(this, idVal);
3141 : }
3142 : }
3143 :
3144 1 : if (mForm != oldForm || needStateUpdate) {
3145 0 : UpdateState(true);
3146 : }
3147 1 : }
3148 :
3149 : void
3150 4 : nsGenericHTMLFormElement::UpdateFieldSet(bool aNotify)
3151 : {
3152 4 : nsIContent* parent = nsnull;
3153 4 : nsIContent* prev = nsnull;
3154 :
3155 14 : for (parent = GetParent(); parent;
3156 5 : prev = parent, parent = parent->GetParent()) {
3157 : nsHTMLFieldSetElement* fieldset =
3158 5 : nsHTMLFieldSetElement::FromContent(parent);
3159 5 : if (fieldset &&
3160 0 : (!prev || fieldset->GetFirstLegend() != prev)) {
3161 0 : if (mFieldSet == fieldset) {
3162 : // We already have the right fieldset;
3163 0 : return;
3164 : }
3165 :
3166 0 : if (mFieldSet) {
3167 0 : mFieldSet->RemoveElement(this);
3168 : }
3169 0 : mFieldSet = fieldset;
3170 0 : fieldset->AddElement(this);
3171 :
3172 : // The disabled state may have changed
3173 0 : FieldSetDisabledChanged(aNotify);
3174 0 : return;
3175 : }
3176 : }
3177 :
3178 : // No fieldset found.
3179 4 : if (mFieldSet) {
3180 0 : mFieldSet->RemoveElement(this);
3181 0 : mFieldSet = nsnull;
3182 : // The disabled state may have changed
3183 0 : FieldSetDisabledChanged(aNotify);
3184 : }
3185 : }
3186 :
3187 : void
3188 0 : nsGenericHTMLFormElement::FieldSetDisabledChanged(bool aNotify)
3189 : {
3190 0 : UpdateState(aNotify);
3191 0 : }
3192 :
3193 : //----------------------------------------------------------------------
3194 :
3195 : nsresult
3196 0 : nsGenericHTMLElement::Blur()
3197 : {
3198 0 : if (!ShouldBlur(this)) {
3199 0 : return NS_OK;
3200 : }
3201 :
3202 0 : nsIDocument* doc = GetCurrentDoc();
3203 0 : if (!doc) {
3204 0 : return NS_OK;
3205 : }
3206 :
3207 0 : nsIDOMWindow* win = doc->GetWindow();
3208 0 : nsIFocusManager* fm = nsFocusManager::GetFocusManager();
3209 0 : return (win && fm) ? fm->ClearFocus(win) : NS_OK;
3210 : }
3211 :
3212 : nsresult
3213 0 : nsGenericHTMLElement::Focus()
3214 : {
3215 0 : nsIFocusManager* fm = nsFocusManager::GetFocusManager();
3216 0 : nsCOMPtr<nsIDOMElement> elem = do_QueryInterface(this);
3217 0 : return fm ? fm->SetFocus(elem, 0) : NS_OK;
3218 : }
3219 :
3220 0 : nsresult nsGenericHTMLElement::MozRequestFullScreen()
3221 : {
3222 : // Only grant full-screen requests if this is called from inside a trusted
3223 : // event handler (i.e. inside an event handler for a user initiated event).
3224 : // This stops the full-screen from being abused similar to the popups of old,
3225 : // and it also makes it harder for bad guys' script to go full-screen and
3226 : // spoof the browser chrome/window and phish logins etc.
3227 0 : if (!nsContentUtils::IsRequestFullScreenAllowed()) {
3228 : nsContentUtils::ReportToConsole(nsIScriptError::warningFlag,
3229 : "DOM", OwnerDoc(),
3230 : nsContentUtils::eDOM_PROPERTIES,
3231 0 : "FullScreenDeniedNotInputDriven");
3232 : nsRefPtr<nsAsyncDOMEvent> e =
3233 0 : new nsAsyncDOMEvent(OwnerDoc(),
3234 0 : NS_LITERAL_STRING("mozfullscreenerror"),
3235 : true,
3236 0 : false);
3237 0 : e->PostDOMEvent();
3238 0 : return NS_OK;
3239 : }
3240 :
3241 0 : OwnerDoc()->AsyncRequestFullScreen(this);
3242 :
3243 0 : return NS_OK;
3244 : }
3245 :
3246 0 : nsresult nsGenericHTMLElement::Click()
3247 : {
3248 0 : if (HasFlag(NODE_HANDLING_CLICK))
3249 0 : return NS_OK;
3250 :
3251 : // Strong in case the event kills it
3252 0 : nsCOMPtr<nsIDocument> doc = GetCurrentDoc();
3253 :
3254 0 : nsCOMPtr<nsIPresShell> shell;
3255 0 : nsRefPtr<nsPresContext> context;
3256 0 : if (doc) {
3257 0 : shell = doc->GetShell();
3258 0 : if (shell) {
3259 0 : context = shell->GetPresContext();
3260 : }
3261 : }
3262 :
3263 0 : SetFlags(NODE_HANDLING_CLICK);
3264 :
3265 : // Click() is never called from native code, but it may be
3266 : // called from chrome JS. Mark this event trusted if Click()
3267 : // is called from chrome code.
3268 0 : nsMouseEvent event(nsContentUtils::IsCallerChrome(),
3269 0 : NS_MOUSE_CLICK, nsnull, nsMouseEvent::eReal);
3270 0 : event.inputSource = nsIDOMMouseEvent::MOZ_SOURCE_UNKNOWN;
3271 :
3272 0 : nsEventDispatcher::Dispatch(this, context, &event);
3273 :
3274 0 : UnsetFlags(NODE_HANDLING_CLICK);
3275 0 : return NS_OK;
3276 : }
3277 :
3278 : bool
3279 0 : nsGenericHTMLElement::IsHTMLFocusable(bool aWithMouse,
3280 : bool *aIsFocusable,
3281 : PRInt32 *aTabIndex)
3282 : {
3283 0 : nsIDocument *doc = GetCurrentDoc();
3284 0 : if (!doc || doc->HasFlag(NODE_IS_EDITABLE)) {
3285 : // In designMode documents we only allow focusing the document.
3286 0 : if (aTabIndex) {
3287 0 : *aTabIndex = -1;
3288 : }
3289 :
3290 0 : *aIsFocusable = false;
3291 :
3292 0 : return true;
3293 : }
3294 :
3295 0 : PRInt32 tabIndex = 0; // Default value for non HTML elements with -moz-user-focus
3296 0 : GetTabIndex(&tabIndex);
3297 :
3298 0 : bool override, disabled = false;
3299 0 : if (IsEditableRoot()) {
3300 : // Editable roots should always be focusable.
3301 0 : override = true;
3302 :
3303 : // Ignore the disabled attribute in editable contentEditable/designMode
3304 : // roots.
3305 0 : if (!HasAttr(kNameSpaceID_None, nsGkAtoms::tabindex)) {
3306 : // The default value for tabindex should be 0 for editable
3307 : // contentEditable roots.
3308 0 : tabIndex = 0;
3309 : }
3310 : }
3311 : else {
3312 0 : override = false;
3313 :
3314 : // Just check for disabled attribute on form controls
3315 0 : disabled = IsDisabled();
3316 0 : if (disabled) {
3317 0 : tabIndex = -1;
3318 : }
3319 : }
3320 :
3321 0 : if (aTabIndex) {
3322 0 : *aTabIndex = tabIndex;
3323 : }
3324 :
3325 : // If a tabindex is specified at all, or the default tabindex is 0, we're focusable
3326 : *aIsFocusable =
3327 0 : (tabIndex >= 0 || (!disabled && HasAttr(kNameSpaceID_None, nsGkAtoms::tabindex)));
3328 :
3329 0 : return override;
3330 : }
3331 :
3332 : void
3333 0 : nsGenericHTMLElement::RegUnRegAccessKey(bool aDoReg)
3334 : {
3335 : // first check to see if we have an access key
3336 0 : nsAutoString accessKey;
3337 0 : GetAttr(kNameSpaceID_None, nsGkAtoms::accesskey, accessKey);
3338 0 : if (accessKey.IsEmpty()) {
3339 : return;
3340 : }
3341 :
3342 : // We have an access key, so get the ESM from the pres context.
3343 0 : nsPresContext *presContext = GetPresContext();
3344 :
3345 0 : if (presContext) {
3346 0 : nsEventStateManager *esm = presContext->EventStateManager();
3347 :
3348 : // Register or unregister as appropriate.
3349 0 : if (aDoReg) {
3350 0 : esm->RegisterAccessKey(this, (PRUint32)accessKey.First());
3351 : } else {
3352 0 : esm->UnregisterAccessKey(this, (PRUint32)accessKey.First());
3353 : }
3354 : }
3355 : }
3356 :
3357 : void
3358 0 : nsGenericHTMLElement::PerformAccesskey(bool aKeyCausesActivation,
3359 : bool aIsTrustedEvent)
3360 : {
3361 0 : nsPresContext *presContext = GetPresContext();
3362 0 : if (!presContext)
3363 0 : return;
3364 :
3365 : // It's hard to say what HTML4 wants us to do in all cases.
3366 0 : nsIFocusManager* fm = nsFocusManager::GetFocusManager();
3367 0 : if (fm) {
3368 0 : nsCOMPtr<nsIDOMElement> elem = do_QueryInterface(this);
3369 0 : fm->SetFocus(elem, nsIFocusManager::FLAG_BYKEY);
3370 : }
3371 :
3372 0 : if (aKeyCausesActivation) {
3373 : // Click on it if the users prefs indicate to do so.
3374 : nsMouseEvent event(aIsTrustedEvent, NS_MOUSE_CLICK,
3375 0 : nsnull, nsMouseEvent::eReal);
3376 0 : event.inputSource = nsIDOMMouseEvent::MOZ_SOURCE_KEYBOARD;
3377 :
3378 : nsAutoPopupStatePusher popupStatePusher(aIsTrustedEvent ?
3379 0 : openAllowed : openAbused);
3380 :
3381 0 : nsEventDispatcher::Dispatch(this, presContext, &event);
3382 : }
3383 : }
3384 :
3385 : const nsAttrName*
3386 0 : nsGenericHTMLElement::InternalGetExistingAttrNameFromQName(const nsAString& aStr) const
3387 : {
3388 0 : if (IsInHTMLDocument()) {
3389 0 : nsAutoString lower;
3390 0 : nsContentUtils::ASCIIToLower(aStr, lower);
3391 0 : return mAttrsAndChildren.GetExistingAttrNameFromQName(lower);
3392 : }
3393 :
3394 0 : return mAttrsAndChildren.GetExistingAttrNameFromQName(aStr);
3395 : }
3396 :
3397 : nsresult
3398 0 : nsGenericHTMLElement::GetEditor(nsIEditor** aEditor)
3399 : {
3400 0 : *aEditor = nsnull;
3401 :
3402 0 : if (!nsContentUtils::IsCallerTrustedForWrite()) {
3403 0 : return NS_ERROR_DOM_SECURITY_ERR;
3404 : }
3405 :
3406 0 : return GetEditorInternal(aEditor);
3407 : }
3408 :
3409 : nsresult
3410 0 : nsGenericHTMLElement::GetEditorInternal(nsIEditor** aEditor)
3411 : {
3412 0 : *aEditor = nsnull;
3413 :
3414 0 : nsCOMPtr<nsITextControlElement> textCtrl = do_QueryInterface(this);
3415 0 : if (textCtrl) {
3416 0 : *aEditor = textCtrl->GetTextEditor();
3417 0 : NS_IF_ADDREF(*aEditor);
3418 : }
3419 :
3420 0 : return NS_OK;
3421 : }
3422 :
3423 : already_AddRefed<nsIEditor>
3424 0 : nsGenericHTMLElement::GetAssociatedEditor()
3425 : {
3426 : // If contenteditable is ever implemented, it might need to do something different here?
3427 :
3428 0 : nsIEditor* editor = nsnull;
3429 0 : GetEditorInternal(&editor);
3430 0 : return editor;
3431 : }
3432 :
3433 : bool
3434 0 : nsGenericHTMLElement::IsCurrentBodyElement()
3435 : {
3436 : // TODO Bug 698498: Should this handle the case where GetBody returns a
3437 : // frameset?
3438 0 : nsCOMPtr<nsIDOMHTMLBodyElement> bodyElement = do_QueryInterface(this);
3439 0 : if (!bodyElement) {
3440 0 : return false;
3441 : }
3442 :
3443 : nsCOMPtr<nsIDOMHTMLDocument> htmlDocument =
3444 0 : do_QueryInterface(GetCurrentDoc());
3445 0 : if (!htmlDocument) {
3446 0 : return false;
3447 : }
3448 :
3449 0 : nsCOMPtr<nsIDOMHTMLElement> htmlElement;
3450 0 : htmlDocument->GetBody(getter_AddRefs(htmlElement));
3451 0 : return htmlElement == bodyElement;
3452 : }
3453 :
3454 : // static
3455 : void
3456 0 : nsGenericHTMLElement::SyncEditorsOnSubtree(nsIContent* content)
3457 : {
3458 : /* Sync this node */
3459 0 : nsGenericHTMLElement* element = FromContent(content);
3460 0 : if (element) {
3461 0 : nsCOMPtr<nsIEditor> editor = element->GetAssociatedEditor();
3462 0 : if (editor) {
3463 0 : editor->SyncRealTimeSpell();
3464 : }
3465 : }
3466 :
3467 : /* Sync all children */
3468 0 : for (nsIContent* child = content->GetFirstChild();
3469 : child;
3470 0 : child = child->GetNextSibling()) {
3471 0 : SyncEditorsOnSubtree(child);
3472 : }
3473 0 : }
3474 :
3475 : void
3476 0 : nsGenericHTMLElement::RecompileScriptEventListeners()
3477 : {
3478 0 : PRInt32 i, count = mAttrsAndChildren.AttrCount();
3479 0 : for (i = 0; i < count; ++i) {
3480 0 : const nsAttrName *name = mAttrsAndChildren.AttrNameAt(i);
3481 :
3482 : // Eventlistenener-attributes are always in the null namespace
3483 0 : if (!name->IsAtom()) {
3484 0 : continue;
3485 : }
3486 :
3487 0 : nsIAtom *attr = name->Atom();
3488 0 : if (!nsContentUtils::IsEventAttributeName(attr, EventNameType_HTML)) {
3489 0 : continue;
3490 : }
3491 :
3492 0 : nsAutoString value;
3493 0 : GetAttr(kNameSpaceID_None, attr, value);
3494 0 : AddScriptEventListener(attr, value, true);
3495 : }
3496 0 : }
3497 :
3498 : bool
3499 0 : nsGenericHTMLElement::IsEditableRoot() const
3500 : {
3501 0 : nsIDocument *document = GetCurrentDoc();
3502 0 : if (!document) {
3503 0 : return false;
3504 : }
3505 :
3506 0 : if (document->HasFlag(NODE_IS_EDITABLE)) {
3507 0 : return false;
3508 : }
3509 :
3510 0 : if (GetContentEditableValue() != eTrue) {
3511 0 : return false;
3512 : }
3513 :
3514 0 : nsIContent *parent = GetParent();
3515 :
3516 0 : return !parent || !parent->HasFlag(NODE_IS_EDITABLE);
3517 : }
3518 :
3519 : static void
3520 0 : MakeContentDescendantsEditable(nsIContent *aContent, nsIDocument *aDocument)
3521 : {
3522 : // If aContent is not an element, we just need to update its
3523 : // internal editable state and don't need to notify anyone about
3524 : // that. For elements, we need to send a ContentStateChanged
3525 : // notification.
3526 0 : if (!aContent->IsElement()) {
3527 0 : aContent->UpdateEditableState(false);
3528 0 : return;
3529 : }
3530 :
3531 0 : Element *element = aContent->AsElement();
3532 :
3533 0 : element->UpdateEditableState(true);
3534 :
3535 0 : for (nsIContent *child = aContent->GetFirstChild();
3536 : child;
3537 0 : child = child->GetNextSibling()) {
3538 0 : if (!child->HasAttr(kNameSpaceID_None, nsGkAtoms::contenteditable)) {
3539 0 : MakeContentDescendantsEditable(child, aDocument);
3540 : }
3541 : }
3542 : }
3543 :
3544 : void
3545 0 : nsGenericHTMLElement::ChangeEditableState(PRInt32 aChange)
3546 : {
3547 0 : nsIDocument* document = GetCurrentDoc();
3548 0 : if (!document) {
3549 0 : return;
3550 : }
3551 :
3552 0 : if (aChange != 0) {
3553 : nsCOMPtr<nsIHTMLDocument> htmlDocument =
3554 0 : do_QueryInterface(document);
3555 0 : if (htmlDocument) {
3556 0 : htmlDocument->ChangeContentEditableCount(this, aChange);
3557 : }
3558 : }
3559 :
3560 0 : if (document->HasFlag(NODE_IS_EDITABLE)) {
3561 0 : document = nsnull;
3562 : }
3563 :
3564 : // MakeContentDescendantsEditable is going to call ContentStateChanged for
3565 : // this element and all descendants if editable state has changed.
3566 : // We might as well wrap it all in one script blocker.
3567 0 : nsAutoScriptBlocker scriptBlocker;
3568 0 : MakeContentDescendantsEditable(this, document);
3569 4392 : }
|