1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 #include "mozilla/ArrayUtils.h" // for ArrayLength
7 #include "mozilla/Assertions.h" // for MOZ_ASSERT, etc
8 #include "mozilla/dom/Element.h" // for Element, nsINode
9 #include "nsAString.h" // for nsAString_internal::IsEmpty
10 #include "nsCOMPtr.h" // for nsCOMPtr, operator==, etc
11 #include "nsCaseTreatment.h"
12 #include "nsDebug.h" // for NS_PRECONDITION, etc
13 #include "nsEditor.h" // for nsEditor
14 #include "nsError.h" // for NS_SUCCEEDED
15 #include "nsGkAtoms.h" // for nsGkAtoms, nsGkAtoms::a, etc
16 #include "nsHTMLEditUtils.h"
17 #include "nsHTMLTags.h"
18 #include "nsIAtom.h" // for nsIAtom
19 #include "nsIDOMHTMLAnchorElement.h" // for nsIDOMHTMLAnchorElement
20 #include "nsIDOMNode.h" // for nsIDOMNode
21 #include "nsNameSpaceManager.h" // for kNameSpaceID_None
22 #include "nsLiteralString.h" // for NS_LITERAL_STRING
23 #include "nsString.h" // for nsAutoString
24 #include "nsTextEditUtils.h" // for nsTextEditUtils
26 using namespace mozilla
;
28 ///////////////////////////////////////////////////////////////////////////
31 nsHTMLEditUtils::IsBig(nsIDOMNode
* aNode
)
33 return nsEditor::NodeIsType(aNode
, nsGkAtoms::big
);
37 ///////////////////////////////////////////////////////////////////////////
38 // IsInlineStyle true if node is an inline style
41 nsHTMLEditUtils::IsInlineStyle(nsIDOMNode
* aNode
)
43 NS_PRECONDITION(aNode
, "null parent passed to nsHTMLEditUtils::IsInlineStyle");
44 nsCOMPtr
<nsINode
> node
= do_QueryInterface(aNode
);
45 return node
&& IsInlineStyle(node
);
49 nsHTMLEditUtils::IsInlineStyle(nsINode
* aNode
)
52 nsIAtom
* nodeAtom
= aNode
->Tag();
53 return (nodeAtom
== nsGkAtoms::b
)
54 || (nodeAtom
== nsGkAtoms::i
)
55 || (nodeAtom
== nsGkAtoms::u
)
56 || (nodeAtom
== nsGkAtoms::tt
)
57 || (nodeAtom
== nsGkAtoms::s
)
58 || (nodeAtom
== nsGkAtoms::strike
)
59 || (nodeAtom
== nsGkAtoms::big
)
60 || (nodeAtom
== nsGkAtoms::small
)
61 || (nodeAtom
== nsGkAtoms::sub
)
62 || (nodeAtom
== nsGkAtoms::sup
)
63 || (nodeAtom
== nsGkAtoms::font
);
66 ///////////////////////////////////////////////////////////////////////////
67 // IsFormatNode true if node is a format node
70 nsHTMLEditUtils::IsFormatNode(nsIDOMNode
* aNode
)
72 NS_PRECONDITION(aNode
, "null parent passed to nsHTMLEditUtils::IsFormatNode");
73 nsCOMPtr
<nsINode
> node
= do_QueryInterface(aNode
);
74 return node
&& IsFormatNode(node
);
78 nsHTMLEditUtils::IsFormatNode(nsINode
* aNode
)
81 nsIAtom
* nodeAtom
= aNode
->Tag();
82 return (nodeAtom
== nsGkAtoms::p
)
83 || (nodeAtom
== nsGkAtoms::pre
)
84 || (nodeAtom
== nsGkAtoms::h1
)
85 || (nodeAtom
== nsGkAtoms::h2
)
86 || (nodeAtom
== nsGkAtoms::h3
)
87 || (nodeAtom
== nsGkAtoms::h4
)
88 || (nodeAtom
== nsGkAtoms::h5
)
89 || (nodeAtom
== nsGkAtoms::h6
)
90 || (nodeAtom
== nsGkAtoms::address
);
93 ///////////////////////////////////////////////////////////////////////////
94 // IsNodeThatCanOutdent true if node is a list, list item, or blockquote
97 nsHTMLEditUtils::IsNodeThatCanOutdent(nsIDOMNode
* aNode
)
99 NS_PRECONDITION(aNode
, "null parent passed to nsHTMLEditUtils::IsNodeThatCanOutdent");
100 nsCOMPtr
<nsIAtom
> nodeAtom
= nsEditor::GetTag(aNode
);
101 return (nodeAtom
== nsGkAtoms::ul
)
102 || (nodeAtom
== nsGkAtoms::ol
)
103 || (nodeAtom
== nsGkAtoms::dl
)
104 || (nodeAtom
== nsGkAtoms::li
)
105 || (nodeAtom
== nsGkAtoms::dd
)
106 || (nodeAtom
== nsGkAtoms::dt
)
107 || (nodeAtom
== nsGkAtoms::blockquote
);
110 ///////////////////////////////////////////////////////////////////////////
113 nsHTMLEditUtils::IsSmall(nsIDOMNode
* aNode
)
115 return nsEditor::NodeIsType(aNode
, nsGkAtoms::small
);
119 /********************************************************
120 * helper methods from nsHTMLEditRules
121 ********************************************************/
123 ///////////////////////////////////////////////////////////////////////////
124 // IsHeader: true if node an html header
127 nsHTMLEditUtils::IsHeader(nsIDOMNode
* aNode
)
129 NS_PRECONDITION(aNode
, "null parent passed to nsHTMLEditUtils::IsHeader");
130 nsCOMPtr
<nsIAtom
> nodeAtom
= nsEditor::GetTag(aNode
);
131 return (nodeAtom
== nsGkAtoms::h1
)
132 || (nodeAtom
== nsGkAtoms::h2
)
133 || (nodeAtom
== nsGkAtoms::h3
)
134 || (nodeAtom
== nsGkAtoms::h4
)
135 || (nodeAtom
== nsGkAtoms::h5
)
136 || (nodeAtom
== nsGkAtoms::h6
);
140 ///////////////////////////////////////////////////////////////////////////
141 // IsParagraph: true if node an html paragraph
144 nsHTMLEditUtils::IsParagraph(nsIDOMNode
* aNode
)
146 return nsEditor::NodeIsType(aNode
, nsGkAtoms::p
);
150 ///////////////////////////////////////////////////////////////////////////
151 // IsHR: true if node an horizontal rule
154 nsHTMLEditUtils::IsHR(nsIDOMNode
* aNode
)
156 return nsEditor::NodeIsType(aNode
, nsGkAtoms::hr
);
160 ///////////////////////////////////////////////////////////////////////////
161 // IsListItem: true if node an html list item
164 nsHTMLEditUtils::IsListItem(nsIDOMNode
* aNode
)
166 NS_PRECONDITION(aNode
, "null parent passed to nsHTMLEditUtils::IsListItem");
167 nsCOMPtr
<nsINode
> node
= do_QueryInterface(aNode
);
168 return node
&& IsListItem(node
);
172 nsHTMLEditUtils::IsListItem(nsINode
* node
)
175 nsCOMPtr
<nsIAtom
> nodeAtom
= node
->Tag();
176 return (nodeAtom
== nsGkAtoms::li
)
177 || (nodeAtom
== nsGkAtoms::dd
)
178 || (nodeAtom
== nsGkAtoms::dt
);
182 ///////////////////////////////////////////////////////////////////////////
183 // IsTableElement: true if node an html table, td, tr, ...
186 nsHTMLEditUtils::IsTableElement(nsIDOMNode
* aNode
)
188 NS_PRECONDITION(aNode
, "null node passed to nsHTMLEditor::IsTableElement");
189 nsCOMPtr
<nsINode
> node
= do_QueryInterface(aNode
);
190 return node
&& IsTableElement(node
);
194 nsHTMLEditUtils::IsTableElement(nsINode
* node
)
197 nsCOMPtr
<nsIAtom
> nodeAtom
= node
->Tag();
198 return (nodeAtom
== nsGkAtoms::table
)
199 || (nodeAtom
== nsGkAtoms::tr
)
200 || (nodeAtom
== nsGkAtoms::td
)
201 || (nodeAtom
== nsGkAtoms::th
)
202 || (nodeAtom
== nsGkAtoms::thead
)
203 || (nodeAtom
== nsGkAtoms::tfoot
)
204 || (nodeAtom
== nsGkAtoms::tbody
)
205 || (nodeAtom
== nsGkAtoms::caption
);
208 ///////////////////////////////////////////////////////////////////////////
209 // IsTableElementButNotTable: true if node an html td, tr, ... (doesn't include table)
212 nsHTMLEditUtils::IsTableElementButNotTable(nsIDOMNode
* aNode
)
214 NS_PRECONDITION(aNode
, "null node passed to nsHTMLEditor::IsTableElementButNotTable");
215 nsCOMPtr
<nsINode
> node
= do_QueryInterface(aNode
);
216 return node
&& IsTableElementButNotTable(node
);
220 nsHTMLEditUtils::IsTableElementButNotTable(nsINode
* aNode
)
223 nsCOMPtr
<nsIAtom
> nodeAtom
= aNode
->Tag();
224 return (nodeAtom
== nsGkAtoms::tr
)
225 || (nodeAtom
== nsGkAtoms::td
)
226 || (nodeAtom
== nsGkAtoms::th
)
227 || (nodeAtom
== nsGkAtoms::thead
)
228 || (nodeAtom
== nsGkAtoms::tfoot
)
229 || (nodeAtom
== nsGkAtoms::tbody
)
230 || (nodeAtom
== nsGkAtoms::caption
);
233 ///////////////////////////////////////////////////////////////////////////
234 // IsTable: true if node an html table
237 nsHTMLEditUtils::IsTable(nsIDOMNode
* aNode
)
239 return nsEditor::NodeIsType(aNode
, nsGkAtoms::table
);
243 nsHTMLEditUtils::IsTable(nsINode
* aNode
)
245 return aNode
&& aNode
->IsElement() && aNode
->Tag() == nsGkAtoms::table
;
248 ///////////////////////////////////////////////////////////////////////////
249 // IsTableRow: true if node an html tr
252 nsHTMLEditUtils::IsTableRow(nsIDOMNode
* aNode
)
254 return nsEditor::NodeIsType(aNode
, nsGkAtoms::tr
);
258 ///////////////////////////////////////////////////////////////////////////
259 // IsTableCell: true if node an html td or th
262 nsHTMLEditUtils::IsTableCell(nsIDOMNode
* aNode
)
264 NS_PRECONDITION(aNode
, "null parent passed to nsHTMLEditUtils::IsTableCell");
265 nsCOMPtr
<nsINode
> node
= do_QueryInterface(aNode
);
266 return node
&& IsTableCell(node
);
270 nsHTMLEditUtils::IsTableCell(nsINode
* node
)
273 nsCOMPtr
<nsIAtom
> nodeAtom
= node
->Tag();
274 return (nodeAtom
== nsGkAtoms::td
)
275 || (nodeAtom
== nsGkAtoms::th
);
279 ///////////////////////////////////////////////////////////////////////////
280 // IsTableCell: true if node an html td or th
283 nsHTMLEditUtils::IsTableCellOrCaption(nsIDOMNode
* aNode
)
285 NS_PRECONDITION(aNode
, "null parent passed to nsHTMLEditUtils::IsTableCell");
286 nsCOMPtr
<nsIAtom
> nodeAtom
= nsEditor::GetTag(aNode
);
287 return (nodeAtom
== nsGkAtoms::td
)
288 || (nodeAtom
== nsGkAtoms::th
)
289 || (nodeAtom
== nsGkAtoms::caption
);
293 ///////////////////////////////////////////////////////////////////////////
294 // IsList: true if node an html list
297 nsHTMLEditUtils::IsList(nsIDOMNode
* aNode
)
299 NS_PRECONDITION(aNode
, "null parent passed to nsHTMLEditUtils::IsList");
300 nsCOMPtr
<nsINode
> node
= do_QueryInterface(aNode
);
301 return node
&& IsList(node
);
305 nsHTMLEditUtils::IsList(nsINode
* node
)
308 nsCOMPtr
<nsIAtom
> nodeAtom
= node
->Tag();
309 return (nodeAtom
== nsGkAtoms::ul
)
310 || (nodeAtom
== nsGkAtoms::ol
)
311 || (nodeAtom
== nsGkAtoms::dl
);
315 ///////////////////////////////////////////////////////////////////////////
316 // IsOrderedList: true if node an html ordered list
319 nsHTMLEditUtils::IsOrderedList(nsIDOMNode
* aNode
)
321 return nsEditor::NodeIsType(aNode
, nsGkAtoms::ol
);
325 ///////////////////////////////////////////////////////////////////////////
326 // IsUnorderedList: true if node an html unordered list
329 nsHTMLEditUtils::IsUnorderedList(nsIDOMNode
* aNode
)
331 return nsEditor::NodeIsType(aNode
, nsGkAtoms::ul
);
335 ///////////////////////////////////////////////////////////////////////////
336 // IsBlockquote: true if node an html blockquote node
339 nsHTMLEditUtils::IsBlockquote(nsIDOMNode
* aNode
)
341 return nsEditor::NodeIsType(aNode
, nsGkAtoms::blockquote
);
345 ///////////////////////////////////////////////////////////////////////////
346 // IsPre: true if node an html pre node
349 nsHTMLEditUtils::IsPre(nsIDOMNode
* aNode
)
351 return nsEditor::NodeIsType(aNode
, nsGkAtoms::pre
);
355 ///////////////////////////////////////////////////////////////////////////
356 // IsImage: true if node an html image node
359 nsHTMLEditUtils::IsImage(nsIDOMNode
* aNode
)
361 return nsEditor::NodeIsType(aNode
, nsGkAtoms::img
);
365 nsHTMLEditUtils::IsLink(nsIDOMNode
*aNode
)
367 nsCOMPtr
<nsINode
> node
= do_QueryInterface(aNode
);
368 return node
&& IsLink(node
);
372 nsHTMLEditUtils::IsLink(nsINode
* aNode
)
376 nsCOMPtr
<nsIDOMHTMLAnchorElement
> anchor
= do_QueryInterface(aNode
);
379 nsAutoString tmpText
;
380 if (NS_SUCCEEDED(anchor
->GetHref(tmpText
)) && !tmpText
.IsEmpty()) {
388 nsHTMLEditUtils::IsNamedAnchor(nsIDOMNode
*aNode
)
390 nsCOMPtr
<nsINode
> node
= do_QueryInterface(aNode
);
391 return node
&& IsNamedAnchor(node
);
395 nsHTMLEditUtils::IsNamedAnchor(nsINode
* aNode
)
398 if (!aNode
->IsElement() || !aNode
->AsElement()->IsHTML(nsGkAtoms::a
)) {
403 return aNode
->AsElement()->GetAttr(kNameSpaceID_None
, nsGkAtoms::name
,
404 text
) && !text
.IsEmpty();
408 ///////////////////////////////////////////////////////////////////////////
409 // IsDiv: true if node an html div node
412 nsHTMLEditUtils::IsDiv(nsIDOMNode
* aNode
)
414 return nsEditor::NodeIsType(aNode
, nsGkAtoms::div
);
418 ///////////////////////////////////////////////////////////////////////////
419 // IsMozDiv: true if node an html div node with type = _moz
422 nsHTMLEditUtils::IsMozDiv(nsIDOMNode
* aNode
)
424 if (IsDiv(aNode
) && nsTextEditUtils::HasMozAttr(aNode
)) return true;
429 nsHTMLEditUtils::IsMozDiv(nsINode
* aNode
)
432 return aNode
->Tag() == nsGkAtoms::div
&&
433 nsTextEditUtils::HasMozAttr(GetAsDOMNode(aNode
));
437 ///////////////////////////////////////////////////////////////////////////
438 // IsMailCite: true if node an html blockquote with type=cite
441 nsHTMLEditUtils::IsMailCite(nsIDOMNode
* aNode
)
443 NS_PRECONDITION(aNode
, "null parent passed to nsHTMLEditUtils::IsMailCite");
444 nsCOMPtr
<nsINode
> node
= do_QueryInterface(aNode
);
445 return node
&& IsMailCite(node
);
449 nsHTMLEditUtils::IsMailCite(nsINode
* aNode
)
453 // don't ask me why, but our html mailcites are id'd by "type=cite"...
454 if (aNode
->IsElement() &&
455 aNode
->AsElement()->AttrValueIs(kNameSpaceID_None
, nsGkAtoms::type
,
456 NS_LITERAL_STRING("cite"),
461 // ... but our plaintext mailcites by "_moz_quote=true". go figure.
462 if (aNode
->IsElement() &&
463 aNode
->AsElement()->AttrValueIs(kNameSpaceID_None
, nsGkAtoms::mozquote
,
464 NS_LITERAL_STRING("true"),
473 ///////////////////////////////////////////////////////////////////////////
474 // IsFormWidget: true if node is a form widget of some kind
477 nsHTMLEditUtils::IsFormWidget(nsIDOMNode
* aNode
)
479 NS_PRECONDITION(aNode
, "null node passed to nsHTMLEditUtils::IsFormWidget");
480 nsCOMPtr
<nsINode
> node
= do_QueryInterface(aNode
);
481 return node
&& IsFormWidget(node
);
485 nsHTMLEditUtils::IsFormWidget(nsINode
* aNode
)
488 nsCOMPtr
<nsIAtom
> nodeAtom
= aNode
->Tag();
489 return (nodeAtom
== nsGkAtoms::textarea
)
490 || (nodeAtom
== nsGkAtoms::select
)
491 || (nodeAtom
== nsGkAtoms::button
)
492 || (nodeAtom
== nsGkAtoms::output
)
493 || (nodeAtom
== nsGkAtoms::keygen
)
494 || (nodeAtom
== nsGkAtoms::progress
)
495 || (nodeAtom
== nsGkAtoms::meter
)
496 || (nodeAtom
== nsGkAtoms::input
);
500 nsHTMLEditUtils::SupportsAlignAttr(nsIDOMNode
* aNode
)
502 NS_PRECONDITION(aNode
, "null node passed to nsHTMLEditUtils::SupportsAlignAttr");
503 nsCOMPtr
<nsIAtom
> nodeAtom
= nsEditor::GetTag(aNode
);
504 return (nodeAtom
== nsGkAtoms::hr
)
505 || (nodeAtom
== nsGkAtoms::table
)
506 || (nodeAtom
== nsGkAtoms::tbody
)
507 || (nodeAtom
== nsGkAtoms::tfoot
)
508 || (nodeAtom
== nsGkAtoms::thead
)
509 || (nodeAtom
== nsGkAtoms::tr
)
510 || (nodeAtom
== nsGkAtoms::td
)
511 || (nodeAtom
== nsGkAtoms::th
)
512 || (nodeAtom
== nsGkAtoms::div
)
513 || (nodeAtom
== nsGkAtoms::p
)
514 || (nodeAtom
== nsGkAtoms::h1
)
515 || (nodeAtom
== nsGkAtoms::h2
)
516 || (nodeAtom
== nsGkAtoms::h3
)
517 || (nodeAtom
== nsGkAtoms::h4
)
518 || (nodeAtom
== nsGkAtoms::h5
)
519 || (nodeAtom
== nsGkAtoms::h6
);
522 // We use bitmasks to test containment of elements. Elements are marked to be
523 // in certain groups by setting the mGroup member of the nsElementInfo struct
524 // to the corresponding GROUP_ values (OR'ed together). Similarly, elements are
525 // marked to allow containment of certain groups by setting the
526 // mCanContainGroups member of the nsElementInfo struct to the corresponding
527 // GROUP_ values (OR'ed together).
528 // Testing containment then simply consists of checking whether the
529 // mCanContainGroups bitmask of an element and the mGroup bitmask of a
530 // potential child overlap.
535 #define GROUP_TOPLEVEL (1 << 1)
537 // base, link, meta, script, style, title
538 #define GROUP_HEAD_CONTENT (1 << 2)
540 // b, big, i, s, small, strike, tt, u
541 #define GROUP_FONTSTYLE (1 << 3)
543 // abbr, acronym, cite, code, datalist, del, dfn, em, ins, kbd, mark, rb, rp
544 // rt, rtc, ruby, samp, strong, var
545 #define GROUP_PHRASE (1 << 4)
547 // a, applet, basefont, bdo, br, font, iframe, img, map, meter, object, output,
548 // picture, progress, q, script, span, sub, sup
549 #define GROUP_SPECIAL (1 << 5)
551 // button, form, input, label, select, textarea
552 #define GROUP_FORMCONTROL (1 << 6)
554 // address, applet, article, aside, blockquote, button, center, del, dir, div,
555 // dl, fieldset, figure, footer, form, h1, h2, h3, h4, h5, h6, header, hgroup,
556 // hr, iframe, ins, main, map, menu, nav, noframes, noscript, object, ol, p,
557 // pre, table, section, ul
558 #define GROUP_BLOCK (1 << 7)
561 #define GROUP_FRAME (1 << 8)
564 #define GROUP_TABLE_CONTENT (1 << 9)
567 #define GROUP_TBODY_CONTENT (1 << 10)
570 #define GROUP_TR_CONTENT (1 << 11)
573 #define GROUP_COLGROUP_CONTENT (1 << 12)
576 #define GROUP_OBJECT_CONTENT (1 << 13)
579 #define GROUP_LI (1 << 14)
582 #define GROUP_MAP_CONTENT (1 << 15)
585 #define GROUP_SELECT_CONTENT (1 << 16)
588 #define GROUP_OPTIONS (1 << 17)
591 #define GROUP_DL_CONTENT (1 << 18)
594 #define GROUP_P (1 << 19)
596 // text, whitespace, newline, comment
597 #define GROUP_LEAF (1 << 20)
599 // XXX This is because the editor does sublists illegally.
601 #define GROUP_OL_UL (1 << 21)
603 // h1, h2, h3, h4, h5, h6
604 #define GROUP_HEADING (1 << 22)
607 #define GROUP_FIGCAPTION (1 << 23)
609 // picture members (img, source)
610 #define GROUP_PICTURE_CONTENT (1 << 24)
612 #define GROUP_INLINE_ELEMENT \
613 (GROUP_FONTSTYLE | GROUP_PHRASE | GROUP_SPECIAL | GROUP_FORMCONTROL | \
616 #define GROUP_FLOW_ELEMENT (GROUP_INLINE_ELEMENT | GROUP_BLOCK)
624 uint32_t mCanContainGroups
;
626 bool mCanContainSelf
;
630 #define ELEM(_tag, _isContainer, _canContainSelf, _group, _canContainGroups) \
631 { eHTMLTag_##_tag, _group, _canContainGroups, _isContainer, _canContainSelf }
633 #define ELEM(_tag, _isContainer, _canContainSelf, _group, _canContainGroups) \
634 { _group, _canContainGroups, _isContainer, _canContainSelf }
637 static const nsElementInfo kElements
[eHTMLTag_userdefined
] = {
638 ELEM(a
, true, false, GROUP_SPECIAL
, GROUP_INLINE_ELEMENT
),
639 ELEM(abbr
, true, true, GROUP_PHRASE
, GROUP_INLINE_ELEMENT
),
640 ELEM(acronym
, true, true, GROUP_PHRASE
, GROUP_INLINE_ELEMENT
),
641 ELEM(address
, true, true, GROUP_BLOCK
,
642 GROUP_INLINE_ELEMENT
| GROUP_P
),
643 ELEM(applet
, true, true, GROUP_SPECIAL
| GROUP_BLOCK
,
644 GROUP_FLOW_ELEMENT
| GROUP_OBJECT_CONTENT
),
645 ELEM(area
, false, false, GROUP_MAP_CONTENT
, GROUP_NONE
),
646 ELEM(article
, true, true, GROUP_BLOCK
, GROUP_FLOW_ELEMENT
),
647 ELEM(aside
, true, true, GROUP_BLOCK
, GROUP_FLOW_ELEMENT
),
648 ELEM(audio
, false, false, GROUP_NONE
, GROUP_NONE
),
649 ELEM(b
, true, true, GROUP_FONTSTYLE
, GROUP_INLINE_ELEMENT
),
650 ELEM(base
, false, false, GROUP_HEAD_CONTENT
, GROUP_NONE
),
651 ELEM(basefont
, false, false, GROUP_SPECIAL
, GROUP_NONE
),
652 ELEM(bdo
, true, true, GROUP_SPECIAL
, GROUP_INLINE_ELEMENT
),
653 ELEM(bgsound
, false, false, GROUP_NONE
, GROUP_NONE
),
654 ELEM(big
, true, true, GROUP_FONTSTYLE
, GROUP_INLINE_ELEMENT
),
655 ELEM(blockquote
, true, true, GROUP_BLOCK
, GROUP_FLOW_ELEMENT
),
656 ELEM(body
, true, true, GROUP_TOPLEVEL
, GROUP_FLOW_ELEMENT
),
657 ELEM(br
, false, false, GROUP_SPECIAL
, GROUP_NONE
),
658 ELEM(button
, true, true, GROUP_FORMCONTROL
| GROUP_BLOCK
,
660 ELEM(canvas
, false, false, GROUP_NONE
, GROUP_NONE
),
661 ELEM(caption
, true, true, GROUP_NONE
, GROUP_INLINE_ELEMENT
),
662 ELEM(center
, true, true, GROUP_BLOCK
, GROUP_FLOW_ELEMENT
),
663 ELEM(cite
, true, true, GROUP_PHRASE
, GROUP_INLINE_ELEMENT
),
664 ELEM(code
, true, true, GROUP_PHRASE
, GROUP_INLINE_ELEMENT
),
665 ELEM(col
, false, false, GROUP_TABLE_CONTENT
| GROUP_COLGROUP_CONTENT
,
667 ELEM(colgroup
, true, false, GROUP_NONE
, GROUP_COLGROUP_CONTENT
),
668 ELEM(content
, true, false, GROUP_NONE
, GROUP_INLINE_ELEMENT
),
669 ELEM(data
, true, false, GROUP_PHRASE
, GROUP_INLINE_ELEMENT
),
670 ELEM(datalist
, true, false, GROUP_PHRASE
,
671 GROUP_OPTIONS
| GROUP_INLINE_ELEMENT
),
672 ELEM(dd
, true, false, GROUP_DL_CONTENT
, GROUP_FLOW_ELEMENT
),
673 ELEM(del
, true, true, GROUP_PHRASE
| GROUP_BLOCK
, GROUP_FLOW_ELEMENT
),
674 ELEM(dfn
, true, true, GROUP_PHRASE
, GROUP_INLINE_ELEMENT
),
675 ELEM(dir
, true, false, GROUP_BLOCK
, GROUP_LI
),
676 ELEM(div
, true, true, GROUP_BLOCK
, GROUP_FLOW_ELEMENT
),
677 ELEM(dl
, true, false, GROUP_BLOCK
, GROUP_DL_CONTENT
),
678 ELEM(dt
, true, true, GROUP_DL_CONTENT
, GROUP_INLINE_ELEMENT
),
679 ELEM(em
, true, true, GROUP_PHRASE
, GROUP_INLINE_ELEMENT
),
680 ELEM(embed
, false, false, GROUP_NONE
, GROUP_NONE
),
681 ELEM(fieldset
, true, true, GROUP_BLOCK
, GROUP_FLOW_ELEMENT
),
682 ELEM(figcaption
, true, false, GROUP_FIGCAPTION
, GROUP_FLOW_ELEMENT
),
683 ELEM(figure
, true, true, GROUP_BLOCK
,
684 GROUP_FLOW_ELEMENT
| GROUP_FIGCAPTION
),
685 ELEM(font
, true, true, GROUP_SPECIAL
, GROUP_INLINE_ELEMENT
),
686 ELEM(footer
, true, true, GROUP_BLOCK
, GROUP_FLOW_ELEMENT
),
687 ELEM(form
, true, true, GROUP_BLOCK
, GROUP_FLOW_ELEMENT
),
688 ELEM(frame
, false, false, GROUP_FRAME
, GROUP_NONE
),
689 ELEM(frameset
, true, true, GROUP_FRAME
, GROUP_FRAME
),
690 ELEM(h1
, true, false, GROUP_BLOCK
| GROUP_HEADING
,
691 GROUP_INLINE_ELEMENT
),
692 ELEM(h2
, true, false, GROUP_BLOCK
| GROUP_HEADING
,
693 GROUP_INLINE_ELEMENT
),
694 ELEM(h3
, true, false, GROUP_BLOCK
| GROUP_HEADING
,
695 GROUP_INLINE_ELEMENT
),
696 ELEM(h4
, true, false, GROUP_BLOCK
| GROUP_HEADING
,
697 GROUP_INLINE_ELEMENT
),
698 ELEM(h5
, true, false, GROUP_BLOCK
| GROUP_HEADING
,
699 GROUP_INLINE_ELEMENT
),
700 ELEM(h6
, true, false, GROUP_BLOCK
| GROUP_HEADING
,
701 GROUP_INLINE_ELEMENT
),
702 ELEM(head
, true, false, GROUP_TOPLEVEL
, GROUP_HEAD_CONTENT
),
703 ELEM(header
, true, true, GROUP_BLOCK
, GROUP_FLOW_ELEMENT
),
704 ELEM(hgroup
, true, false, GROUP_BLOCK
, GROUP_HEADING
),
705 ELEM(hr
, false, false, GROUP_BLOCK
, GROUP_NONE
),
706 ELEM(html
, true, false, GROUP_TOPLEVEL
, GROUP_TOPLEVEL
),
707 ELEM(i
, true, true, GROUP_FONTSTYLE
, GROUP_INLINE_ELEMENT
),
708 ELEM(iframe
, true, true, GROUP_SPECIAL
| GROUP_BLOCK
,
710 ELEM(image
, false, false, GROUP_NONE
, GROUP_NONE
),
711 ELEM(img
, false, false, GROUP_SPECIAL
| GROUP_PICTURE_CONTENT
, GROUP_NONE
),
712 ELEM(input
, false, false, GROUP_FORMCONTROL
, GROUP_NONE
),
713 ELEM(ins
, true, true, GROUP_PHRASE
| GROUP_BLOCK
, GROUP_FLOW_ELEMENT
),
714 ELEM(kbd
, true, true, GROUP_PHRASE
, GROUP_INLINE_ELEMENT
),
715 ELEM(keygen
, false, false, GROUP_FORMCONTROL
, GROUP_NONE
),
716 ELEM(label
, true, false, GROUP_FORMCONTROL
, GROUP_INLINE_ELEMENT
),
717 ELEM(legend
, true, true, GROUP_NONE
, GROUP_INLINE_ELEMENT
),
718 ELEM(li
, true, false, GROUP_LI
, GROUP_FLOW_ELEMENT
),
719 ELEM(link
, false, false, GROUP_HEAD_CONTENT
, GROUP_NONE
),
720 ELEM(listing
, false, false, GROUP_NONE
, GROUP_NONE
),
721 ELEM(main
, true, true, GROUP_BLOCK
, GROUP_FLOW_ELEMENT
),
722 ELEM(map
, true, true, GROUP_SPECIAL
, GROUP_BLOCK
| GROUP_MAP_CONTENT
),
723 ELEM(mark
, true, true, GROUP_PHRASE
, GROUP_INLINE_ELEMENT
),
724 ELEM(marquee
, false, false, GROUP_NONE
, GROUP_NONE
),
725 ELEM(menu
, true, true, GROUP_BLOCK
, GROUP_LI
| GROUP_FLOW_ELEMENT
),
726 ELEM(menuitem
, false, false, GROUP_NONE
, GROUP_NONE
),
727 ELEM(meta
, false, false, GROUP_HEAD_CONTENT
, GROUP_NONE
),
728 ELEM(meter
, true, false, GROUP_SPECIAL
, GROUP_FLOW_ELEMENT
),
729 ELEM(multicol
, false, false, GROUP_NONE
, GROUP_NONE
),
730 ELEM(nav
, true, true, GROUP_BLOCK
, GROUP_FLOW_ELEMENT
),
731 ELEM(nobr
, false, false, GROUP_NONE
, GROUP_NONE
),
732 ELEM(noembed
, false, false, GROUP_NONE
, GROUP_NONE
),
733 ELEM(noframes
, true, true, GROUP_BLOCK
, GROUP_FLOW_ELEMENT
),
734 ELEM(noscript
, true, true, GROUP_BLOCK
, GROUP_FLOW_ELEMENT
),
735 ELEM(object
, true, true, GROUP_SPECIAL
| GROUP_BLOCK
,
736 GROUP_FLOW_ELEMENT
| GROUP_OBJECT_CONTENT
),
737 // XXX Can contain self and ul because editor does sublists illegally.
738 ELEM(ol
, true, true, GROUP_BLOCK
| GROUP_OL_UL
,
739 GROUP_LI
| GROUP_OL_UL
),
740 ELEM(optgroup
, true, false, GROUP_SELECT_CONTENT
,
742 ELEM(option
, true, false,
743 GROUP_SELECT_CONTENT
| GROUP_OPTIONS
, GROUP_LEAF
),
744 ELEM(output
, true, true, GROUP_SPECIAL
, GROUP_INLINE_ELEMENT
),
745 ELEM(p
, true, false, GROUP_BLOCK
| GROUP_P
, GROUP_INLINE_ELEMENT
),
746 ELEM(param
, false, false, GROUP_OBJECT_CONTENT
, GROUP_NONE
),
747 ELEM(picture
, true, false, GROUP_SPECIAL
, GROUP_PICTURE_CONTENT
),
748 ELEM(plaintext
, false, false, GROUP_NONE
, GROUP_NONE
),
749 ELEM(pre
, true, true, GROUP_BLOCK
, GROUP_INLINE_ELEMENT
),
750 ELEM(progress
, true, false, GROUP_SPECIAL
, GROUP_FLOW_ELEMENT
),
751 ELEM(q
, true, true, GROUP_SPECIAL
, GROUP_INLINE_ELEMENT
),
752 ELEM(rb
, true, true, GROUP_PHRASE
, GROUP_INLINE_ELEMENT
),
753 ELEM(rp
, true, true, GROUP_PHRASE
, GROUP_INLINE_ELEMENT
),
754 ELEM(rt
, true, true, GROUP_PHRASE
, GROUP_INLINE_ELEMENT
),
755 ELEM(rtc
, true, true, GROUP_PHRASE
, GROUP_INLINE_ELEMENT
),
756 ELEM(ruby
, true, true, GROUP_PHRASE
, GROUP_INLINE_ELEMENT
),
757 ELEM(s
, true, true, GROUP_FONTSTYLE
, GROUP_INLINE_ELEMENT
),
758 ELEM(samp
, true, true, GROUP_PHRASE
, GROUP_INLINE_ELEMENT
),
759 ELEM(script
, true, false, GROUP_HEAD_CONTENT
| GROUP_SPECIAL
,
761 ELEM(section
, true, true, GROUP_BLOCK
, GROUP_FLOW_ELEMENT
),
762 ELEM(select
, true, false, GROUP_FORMCONTROL
, GROUP_SELECT_CONTENT
),
763 ELEM(shadow
, true, false, GROUP_NONE
, GROUP_INLINE_ELEMENT
),
764 ELEM(small
, true, true, GROUP_FONTSTYLE
, GROUP_INLINE_ELEMENT
),
765 ELEM(source
, false, false, GROUP_PICTURE_CONTENT
, GROUP_NONE
),
766 ELEM(span
, true, true, GROUP_SPECIAL
, GROUP_INLINE_ELEMENT
),
767 ELEM(strike
, true, true, GROUP_FONTSTYLE
, GROUP_INLINE_ELEMENT
),
768 ELEM(strong
, true, true, GROUP_PHRASE
, GROUP_INLINE_ELEMENT
),
769 ELEM(style
, true, false, GROUP_HEAD_CONTENT
, GROUP_LEAF
),
770 ELEM(sub
, true, true, GROUP_SPECIAL
, GROUP_INLINE_ELEMENT
),
771 ELEM(sup
, true, true, GROUP_SPECIAL
, GROUP_INLINE_ELEMENT
),
772 ELEM(table
, true, false, GROUP_BLOCK
, GROUP_TABLE_CONTENT
),
773 ELEM(tbody
, true, false, GROUP_TABLE_CONTENT
, GROUP_TBODY_CONTENT
),
774 ELEM(td
, true, false, GROUP_TR_CONTENT
, GROUP_FLOW_ELEMENT
),
775 ELEM(textarea
, true, false, GROUP_FORMCONTROL
, GROUP_LEAF
),
776 ELEM(tfoot
, true, false, GROUP_NONE
, GROUP_TBODY_CONTENT
),
777 ELEM(th
, true, false, GROUP_TR_CONTENT
, GROUP_FLOW_ELEMENT
),
778 ELEM(thead
, true, false, GROUP_NONE
, GROUP_TBODY_CONTENT
),
779 ELEM(template, false, false, GROUP_NONE
, GROUP_NONE
),
780 ELEM(time
, true, false, GROUP_PHRASE
, GROUP_INLINE_ELEMENT
),
781 ELEM(title
, true, false, GROUP_HEAD_CONTENT
, GROUP_LEAF
),
782 ELEM(tr
, true, false, GROUP_TBODY_CONTENT
, GROUP_TR_CONTENT
),
783 ELEM(track
, false, false, GROUP_NONE
, GROUP_NONE
),
784 ELEM(tt
, true, true, GROUP_FONTSTYLE
, GROUP_INLINE_ELEMENT
),
785 ELEM(u
, true, true, GROUP_FONTSTYLE
, GROUP_INLINE_ELEMENT
),
786 // XXX Can contain self and ol because editor does sublists illegally.
787 ELEM(ul
, true, true, GROUP_BLOCK
| GROUP_OL_UL
,
788 GROUP_LI
| GROUP_OL_UL
),
789 ELEM(var
, true, true, GROUP_PHRASE
, GROUP_INLINE_ELEMENT
),
790 ELEM(video
, false, false, GROUP_NONE
, GROUP_NONE
),
791 ELEM(wbr
, false, false, GROUP_NONE
, GROUP_NONE
),
792 ELEM(xmp
, false, false, GROUP_NONE
, GROUP_NONE
),
794 // These aren't elements.
795 ELEM(text
, false, false, GROUP_LEAF
, GROUP_NONE
),
796 ELEM(whitespace
, false, false, GROUP_LEAF
, GROUP_NONE
),
797 ELEM(newline
, false, false, GROUP_LEAF
, GROUP_NONE
),
798 ELEM(comment
, false, false, GROUP_LEAF
, GROUP_NONE
),
799 ELEM(entity
, false, false, GROUP_NONE
, GROUP_NONE
),
800 ELEM(doctypeDecl
, false, false, GROUP_NONE
, GROUP_NONE
),
801 ELEM(markupDecl
, false, false, GROUP_NONE
, GROUP_NONE
),
802 ELEM(instruction
, false, false, GROUP_NONE
, GROUP_NONE
),
804 ELEM(userdefined
, true, false, GROUP_NONE
, GROUP_FLOW_ELEMENT
)
808 nsHTMLEditUtils::CanContain(int32_t aParent
, int32_t aChild
)
810 NS_ASSERTION(aParent
> eHTMLTag_unknown
&& aParent
<= eHTMLTag_userdefined
,
811 "aParent out of range!");
812 NS_ASSERTION(aChild
> eHTMLTag_unknown
&& aChild
<= eHTMLTag_userdefined
,
813 "aChild out of range!");
816 static bool checked
= false;
820 for (i
= 1; i
<= eHTMLTag_userdefined
; ++i
) {
821 NS_ASSERTION(kElements
[i
- 1].mTag
== i
,
822 "You need to update kElements (missing tags).");
827 // Special-case button.
828 if (aParent
== eHTMLTag_button
) {
829 static const eHTMLTags kButtonExcludeKids
[] = {
840 for (j
= 0; j
< ArrayLength(kButtonExcludeKids
); ++j
) {
841 if (kButtonExcludeKids
[j
] == aChild
) {
847 // Deprecated elements.
848 if (aChild
== eHTMLTag_bgsound
) {
852 // Bug #67007, dont strip userdefined tags.
853 if (aChild
== eHTMLTag_userdefined
) {
857 const nsElementInfo
& parent
= kElements
[aParent
- 1];
858 if (aParent
== aChild
) {
859 return parent
.mCanContainSelf
;
862 const nsElementInfo
& child
= kElements
[aChild
- 1];
863 return (parent
.mCanContainGroups
& child
.mGroup
) != 0;
867 nsHTMLEditUtils::IsContainer(int32_t aTag
)
869 NS_ASSERTION(aTag
> eHTMLTag_unknown
&& aTag
<= eHTMLTag_userdefined
,
870 "aTag out of range!");
872 return kElements
[aTag
- 1].mIsContainer
;