Wed, 31 Dec 2014 06:09:35 +0100
Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.
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 "nsEditProperty.h" // for nsEditProperty, etc
14 #include "nsEditor.h" // for nsEditor
15 #include "nsError.h" // for NS_SUCCEEDED
16 #include "nsGkAtoms.h" // for nsGkAtoms, nsGkAtoms::a, etc
17 #include "nsHTMLEditUtils.h"
18 #include "nsHTMLTags.h"
19 #include "nsIAtom.h" // for nsIAtom
20 #include "nsIDOMHTMLAnchorElement.h" // for nsIDOMHTMLAnchorElement
21 #include "nsIDOMNode.h" // for nsIDOMNode
22 #include "nsNameSpaceManager.h" // for kNameSpaceID_None
23 #include "nsLiteralString.h" // for NS_LITERAL_STRING
24 #include "nsString.h" // for nsAutoString
25 #include "nsTextEditUtils.h" // for nsTextEditUtils
27 using namespace mozilla;
29 ///////////////////////////////////////////////////////////////////////////
30 //
31 bool
32 nsHTMLEditUtils::IsBig(nsIDOMNode* aNode)
33 {
34 return nsEditor::NodeIsType(aNode, nsEditProperty::big);
35 }
38 ///////////////////////////////////////////////////////////////////////////
39 // IsInlineStyle true if node is an inline style
40 //
41 bool
42 nsHTMLEditUtils::IsInlineStyle(nsIDOMNode* aNode)
43 {
44 NS_PRECONDITION(aNode, "null parent passed to nsHTMLEditUtils::IsInlineStyle");
45 nsCOMPtr<nsINode> node = do_QueryInterface(aNode);
46 return node && IsInlineStyle(node);
47 }
49 bool
50 nsHTMLEditUtils::IsInlineStyle(nsINode* aNode)
51 {
52 MOZ_ASSERT(aNode);
53 nsIAtom* nodeAtom = aNode->Tag();
54 return (nodeAtom == nsEditProperty::b)
55 || (nodeAtom == nsEditProperty::i)
56 || (nodeAtom == nsEditProperty::u)
57 || (nodeAtom == nsEditProperty::tt)
58 || (nodeAtom == nsEditProperty::s)
59 || (nodeAtom == nsEditProperty::strike)
60 || (nodeAtom == nsEditProperty::big)
61 || (nodeAtom == nsEditProperty::small)
62 || (nodeAtom == nsEditProperty::sub)
63 || (nodeAtom == nsEditProperty::sup)
64 || (nodeAtom == nsEditProperty::font);
65 }
67 ///////////////////////////////////////////////////////////////////////////
68 // IsFormatNode true if node is a format node
69 //
70 bool
71 nsHTMLEditUtils::IsFormatNode(nsIDOMNode* aNode)
72 {
73 NS_PRECONDITION(aNode, "null parent passed to nsHTMLEditUtils::IsFormatNode");
74 nsCOMPtr<nsINode> node = do_QueryInterface(aNode);
75 return node && IsFormatNode(node);
76 }
78 bool
79 nsHTMLEditUtils::IsFormatNode(nsINode* aNode)
80 {
81 MOZ_ASSERT(aNode);
82 nsIAtom* nodeAtom = aNode->Tag();
83 return (nodeAtom == nsEditProperty::p)
84 || (nodeAtom == nsEditProperty::pre)
85 || (nodeAtom == nsEditProperty::h1)
86 || (nodeAtom == nsEditProperty::h2)
87 || (nodeAtom == nsEditProperty::h3)
88 || (nodeAtom == nsEditProperty::h4)
89 || (nodeAtom == nsEditProperty::h5)
90 || (nodeAtom == nsEditProperty::h6)
91 || (nodeAtom == nsEditProperty::address);
92 }
94 ///////////////////////////////////////////////////////////////////////////
95 // IsNodeThatCanOutdent true if node is a list, list item, or blockquote
96 //
97 bool
98 nsHTMLEditUtils::IsNodeThatCanOutdent(nsIDOMNode* aNode)
99 {
100 NS_PRECONDITION(aNode, "null parent passed to nsHTMLEditUtils::IsNodeThatCanOutdent");
101 nsCOMPtr<nsIAtom> nodeAtom = nsEditor::GetTag(aNode);
102 return (nodeAtom == nsEditProperty::ul)
103 || (nodeAtom == nsEditProperty::ol)
104 || (nodeAtom == nsEditProperty::dl)
105 || (nodeAtom == nsEditProperty::li)
106 || (nodeAtom == nsEditProperty::dd)
107 || (nodeAtom == nsEditProperty::dt)
108 || (nodeAtom == nsEditProperty::blockquote);
109 }
111 ///////////////////////////////////////////////////////////////////////////
112 //
113 bool
114 nsHTMLEditUtils::IsSmall(nsIDOMNode* aNode)
115 {
116 return nsEditor::NodeIsType(aNode, nsEditProperty::small);
117 }
120 /********************************************************
121 * helper methods from nsHTMLEditRules
122 ********************************************************/
124 ///////////////////////////////////////////////////////////////////////////
125 // IsHeader: true if node an html header
126 //
127 bool
128 nsHTMLEditUtils::IsHeader(nsIDOMNode* aNode)
129 {
130 NS_PRECONDITION(aNode, "null parent passed to nsHTMLEditUtils::IsHeader");
131 nsCOMPtr<nsIAtom> nodeAtom = nsEditor::GetTag(aNode);
132 return (nodeAtom == nsEditProperty::h1)
133 || (nodeAtom == nsEditProperty::h2)
134 || (nodeAtom == nsEditProperty::h3)
135 || (nodeAtom == nsEditProperty::h4)
136 || (nodeAtom == nsEditProperty::h5)
137 || (nodeAtom == nsEditProperty::h6);
138 }
141 ///////////////////////////////////////////////////////////////////////////
142 // IsParagraph: true if node an html paragraph
143 //
144 bool
145 nsHTMLEditUtils::IsParagraph(nsIDOMNode* aNode)
146 {
147 return nsEditor::NodeIsType(aNode, nsEditProperty::p);
148 }
151 ///////////////////////////////////////////////////////////////////////////
152 // IsHR: true if node an horizontal rule
153 //
154 bool
155 nsHTMLEditUtils::IsHR(nsIDOMNode* aNode)
156 {
157 return nsEditor::NodeIsType(aNode, nsEditProperty::hr);
158 }
161 ///////////////////////////////////////////////////////////////////////////
162 // IsListItem: true if node an html list item
163 //
164 bool
165 nsHTMLEditUtils::IsListItem(nsIDOMNode* aNode)
166 {
167 NS_PRECONDITION(aNode, "null parent passed to nsHTMLEditUtils::IsListItem");
168 nsCOMPtr<nsINode> node = do_QueryInterface(aNode);
169 return node && IsListItem(node);
170 }
172 bool
173 nsHTMLEditUtils::IsListItem(nsINode* node)
174 {
175 MOZ_ASSERT(node);
176 nsCOMPtr<nsIAtom> nodeAtom = node->Tag();
177 return (nodeAtom == nsEditProperty::li)
178 || (nodeAtom == nsEditProperty::dd)
179 || (nodeAtom == nsEditProperty::dt);
180 }
183 ///////////////////////////////////////////////////////////////////////////
184 // IsTableElement: true if node an html table, td, tr, ...
185 //
186 bool
187 nsHTMLEditUtils::IsTableElement(nsIDOMNode* aNode)
188 {
189 NS_PRECONDITION(aNode, "null node passed to nsHTMLEditor::IsTableElement");
190 nsCOMPtr<nsINode> node = do_QueryInterface(aNode);
191 return node && IsTableElement(node);
192 }
194 bool
195 nsHTMLEditUtils::IsTableElement(nsINode* node)
196 {
197 MOZ_ASSERT(node);
198 nsCOMPtr<nsIAtom> nodeAtom = node->Tag();
199 return (nodeAtom == nsEditProperty::table)
200 || (nodeAtom == nsEditProperty::tr)
201 || (nodeAtom == nsEditProperty::td)
202 || (nodeAtom == nsEditProperty::th)
203 || (nodeAtom == nsEditProperty::thead)
204 || (nodeAtom == nsEditProperty::tfoot)
205 || (nodeAtom == nsEditProperty::tbody)
206 || (nodeAtom == nsEditProperty::caption);
207 }
209 ///////////////////////////////////////////////////////////////////////////
210 // IsTableElementButNotTable: true if node an html td, tr, ... (doesn't include table)
211 //
212 bool
213 nsHTMLEditUtils::IsTableElementButNotTable(nsIDOMNode* aNode)
214 {
215 NS_PRECONDITION(aNode, "null node passed to nsHTMLEditor::IsTableElementButNotTable");
216 nsCOMPtr<nsINode> node = do_QueryInterface(aNode);
217 return node && IsTableElementButNotTable(node);
218 }
220 bool
221 nsHTMLEditUtils::IsTableElementButNotTable(nsINode* aNode)
222 {
223 MOZ_ASSERT(aNode);
224 nsCOMPtr<nsIAtom> nodeAtom = aNode->Tag();
225 return (nodeAtom == nsEditProperty::tr)
226 || (nodeAtom == nsEditProperty::td)
227 || (nodeAtom == nsEditProperty::th)
228 || (nodeAtom == nsEditProperty::thead)
229 || (nodeAtom == nsEditProperty::tfoot)
230 || (nodeAtom == nsEditProperty::tbody)
231 || (nodeAtom == nsEditProperty::caption);
232 }
234 ///////////////////////////////////////////////////////////////////////////
235 // IsTable: true if node an html table
236 //
237 bool
238 nsHTMLEditUtils::IsTable(nsIDOMNode* aNode)
239 {
240 return nsEditor::NodeIsType(aNode, nsEditProperty::table);
241 }
243 ///////////////////////////////////////////////////////////////////////////
244 // IsTableRow: true if node an html tr
245 //
246 bool
247 nsHTMLEditUtils::IsTableRow(nsIDOMNode* aNode)
248 {
249 return nsEditor::NodeIsType(aNode, nsEditProperty::tr);
250 }
253 ///////////////////////////////////////////////////////////////////////////
254 // IsTableCell: true if node an html td or th
255 //
256 bool
257 nsHTMLEditUtils::IsTableCell(nsIDOMNode* aNode)
258 {
259 NS_PRECONDITION(aNode, "null parent passed to nsHTMLEditUtils::IsTableCell");
260 nsCOMPtr<nsINode> node = do_QueryInterface(aNode);
261 return node && IsTableCell(node);
262 }
264 bool
265 nsHTMLEditUtils::IsTableCell(nsINode* node)
266 {
267 MOZ_ASSERT(node);
268 nsCOMPtr<nsIAtom> nodeAtom = node->Tag();
269 return (nodeAtom == nsEditProperty::td)
270 || (nodeAtom == nsEditProperty::th);
271 }
274 ///////////////////////////////////////////////////////////////////////////
275 // IsTableCell: true if node an html td or th
276 //
277 bool
278 nsHTMLEditUtils::IsTableCellOrCaption(nsIDOMNode* aNode)
279 {
280 NS_PRECONDITION(aNode, "null parent passed to nsHTMLEditUtils::IsTableCell");
281 nsCOMPtr<nsIAtom> nodeAtom = nsEditor::GetTag(aNode);
282 return (nodeAtom == nsEditProperty::td)
283 || (nodeAtom == nsEditProperty::th)
284 || (nodeAtom == nsEditProperty::caption);
285 }
288 ///////////////////////////////////////////////////////////////////////////
289 // IsList: true if node an html list
290 //
291 bool
292 nsHTMLEditUtils::IsList(nsIDOMNode* aNode)
293 {
294 NS_PRECONDITION(aNode, "null parent passed to nsHTMLEditUtils::IsList");
295 nsCOMPtr<nsINode> node = do_QueryInterface(aNode);
296 return node && IsList(node);
297 }
299 bool
300 nsHTMLEditUtils::IsList(nsINode* node)
301 {
302 MOZ_ASSERT(node);
303 nsCOMPtr<nsIAtom> nodeAtom = node->Tag();
304 return (nodeAtom == nsEditProperty::ul)
305 || (nodeAtom == nsEditProperty::ol)
306 || (nodeAtom == nsEditProperty::dl);
307 }
310 ///////////////////////////////////////////////////////////////////////////
311 // IsOrderedList: true if node an html ordered list
312 //
313 bool
314 nsHTMLEditUtils::IsOrderedList(nsIDOMNode* aNode)
315 {
316 return nsEditor::NodeIsType(aNode, nsEditProperty::ol);
317 }
320 ///////////////////////////////////////////////////////////////////////////
321 // IsUnorderedList: true if node an html unordered list
322 //
323 bool
324 nsHTMLEditUtils::IsUnorderedList(nsIDOMNode* aNode)
325 {
326 return nsEditor::NodeIsType(aNode, nsEditProperty::ul);
327 }
330 ///////////////////////////////////////////////////////////////////////////
331 // IsBlockquote: true if node an html blockquote node
332 //
333 bool
334 nsHTMLEditUtils::IsBlockquote(nsIDOMNode* aNode)
335 {
336 return nsEditor::NodeIsType(aNode, nsEditProperty::blockquote);
337 }
340 ///////////////////////////////////////////////////////////////////////////
341 // IsPre: true if node an html pre node
342 //
343 bool
344 nsHTMLEditUtils::IsPre(nsIDOMNode* aNode)
345 {
346 return nsEditor::NodeIsType(aNode, nsEditProperty::pre);
347 }
350 ///////////////////////////////////////////////////////////////////////////
351 // IsImage: true if node an html image node
352 //
353 bool
354 nsHTMLEditUtils::IsImage(nsIDOMNode* aNode)
355 {
356 return nsEditor::NodeIsType(aNode, nsEditProperty::img);
357 }
359 bool
360 nsHTMLEditUtils::IsLink(nsIDOMNode *aNode)
361 {
362 NS_ENSURE_TRUE(aNode, false);
363 nsCOMPtr<nsIDOMHTMLAnchorElement> anchor = do_QueryInterface(aNode);
364 if (anchor)
365 {
366 nsAutoString tmpText;
367 if (NS_SUCCEEDED(anchor->GetHref(tmpText)) && !tmpText.IsEmpty())
368 return true;
369 }
370 return false;
371 }
373 bool
374 nsHTMLEditUtils::IsNamedAnchor(nsIDOMNode *aNode)
375 {
376 nsCOMPtr<nsINode> node = do_QueryInterface(aNode);
377 return node && IsNamedAnchor(node);
378 }
380 bool
381 nsHTMLEditUtils::IsNamedAnchor(nsINode* aNode)
382 {
383 MOZ_ASSERT(aNode);
384 if (!aNode->IsElement() || !aNode->AsElement()->IsHTML(nsGkAtoms::a)) {
385 return false;
386 }
388 nsAutoString text;
389 return aNode->AsElement()->GetAttr(kNameSpaceID_None, nsGkAtoms::name,
390 text) && !text.IsEmpty();
391 }
394 ///////////////////////////////////////////////////////////////////////////
395 // IsDiv: true if node an html div node
396 //
397 bool
398 nsHTMLEditUtils::IsDiv(nsIDOMNode* aNode)
399 {
400 return nsEditor::NodeIsType(aNode, nsEditProperty::div);
401 }
404 ///////////////////////////////////////////////////////////////////////////
405 // IsMozDiv: true if node an html div node with type = _moz
406 //
407 bool
408 nsHTMLEditUtils::IsMozDiv(nsIDOMNode* aNode)
409 {
410 if (IsDiv(aNode) && nsTextEditUtils::HasMozAttr(aNode)) return true;
411 return false;
412 }
416 ///////////////////////////////////////////////////////////////////////////
417 // IsMailCite: true if node an html blockquote with type=cite
418 //
419 bool
420 nsHTMLEditUtils::IsMailCite(nsIDOMNode* aNode)
421 {
422 NS_PRECONDITION(aNode, "null parent passed to nsHTMLEditUtils::IsMailCite");
423 nsCOMPtr<nsINode> node = do_QueryInterface(aNode);
424 return node && IsMailCite(node);
425 }
427 bool
428 nsHTMLEditUtils::IsMailCite(nsINode* aNode)
429 {
430 MOZ_ASSERT(aNode);
432 // don't ask me why, but our html mailcites are id'd by "type=cite"...
433 if (aNode->IsElement() &&
434 aNode->AsElement()->AttrValueIs(kNameSpaceID_None, nsGkAtoms::type,
435 NS_LITERAL_STRING("cite"),
436 eIgnoreCase)) {
437 return true;
438 }
440 // ... but our plaintext mailcites by "_moz_quote=true". go figure.
441 if (aNode->IsElement() &&
442 aNode->AsElement()->AttrValueIs(kNameSpaceID_None, nsGkAtoms::mozquote,
443 NS_LITERAL_STRING("true"),
444 eIgnoreCase)) {
445 return true;
446 }
448 return false;
449 }
452 ///////////////////////////////////////////////////////////////////////////
453 // IsFormWidget: true if node is a form widget of some kind
454 //
455 bool
456 nsHTMLEditUtils::IsFormWidget(nsIDOMNode* aNode)
457 {
458 NS_PRECONDITION(aNode, "null node passed to nsHTMLEditUtils::IsFormWidget");
459 nsCOMPtr<nsINode> node = do_QueryInterface(aNode);
460 return node && IsFormWidget(node);
461 }
463 bool
464 nsHTMLEditUtils::IsFormWidget(nsINode* aNode)
465 {
466 MOZ_ASSERT(aNode);
467 nsCOMPtr<nsIAtom> nodeAtom = aNode->Tag();
468 return (nodeAtom == nsEditProperty::textarea)
469 || (nodeAtom == nsEditProperty::select)
470 || (nodeAtom == nsEditProperty::button)
471 || (nodeAtom == nsEditProperty::output)
472 || (nodeAtom == nsEditProperty::keygen)
473 || (nodeAtom == nsEditProperty::progress)
474 || (nodeAtom == nsEditProperty::meter)
475 || (nodeAtom == nsEditProperty::input);
476 }
478 bool
479 nsHTMLEditUtils::SupportsAlignAttr(nsIDOMNode* aNode)
480 {
481 NS_PRECONDITION(aNode, "null node passed to nsHTMLEditUtils::SupportsAlignAttr");
482 nsCOMPtr<nsIAtom> nodeAtom = nsEditor::GetTag(aNode);
483 return (nodeAtom == nsEditProperty::hr)
484 || (nodeAtom == nsEditProperty::table)
485 || (nodeAtom == nsEditProperty::tbody)
486 || (nodeAtom == nsEditProperty::tfoot)
487 || (nodeAtom == nsEditProperty::thead)
488 || (nodeAtom == nsEditProperty::tr)
489 || (nodeAtom == nsEditProperty::td)
490 || (nodeAtom == nsEditProperty::th)
491 || (nodeAtom == nsEditProperty::div)
492 || (nodeAtom == nsEditProperty::p)
493 || (nodeAtom == nsEditProperty::h1)
494 || (nodeAtom == nsEditProperty::h2)
495 || (nodeAtom == nsEditProperty::h3)
496 || (nodeAtom == nsEditProperty::h4)
497 || (nodeAtom == nsEditProperty::h5)
498 || (nodeAtom == nsEditProperty::h6);
499 }
501 // We use bitmasks to test containment of elements. Elements are marked to be
502 // in certain groups by setting the mGroup member of the nsElementInfo struct
503 // to the corresponding GROUP_ values (OR'ed together). Similarly, elements are
504 // marked to allow containment of certain groups by setting the
505 // mCanContainGroups member of the nsElementInfo struct to the corresponding
506 // GROUP_ values (OR'ed together).
507 // Testing containment then simply consists of checking whether the
508 // mCanContainGroups bitmask of an element and the mGroup bitmask of a
509 // potential child overlap.
511 #define GROUP_NONE 0
513 // body, head, html
514 #define GROUP_TOPLEVEL (1 << 1)
516 // base, link, meta, script, style, title
517 #define GROUP_HEAD_CONTENT (1 << 2)
519 // b, big, i, s, small, strike, tt, u
520 #define GROUP_FONTSTYLE (1 << 3)
522 // abbr, acronym, cite, code, datalist, del, dfn, em, ins, kbd, mark, samp,
523 // strong, var
524 #define GROUP_PHRASE (1 << 4)
526 // a, applet, basefont, bdo, br, font, iframe, img, map, meter, object, output,
527 // progress, q, script, span, sub, sup
528 #define GROUP_SPECIAL (1 << 5)
530 // button, form, input, label, select, textarea
531 #define GROUP_FORMCONTROL (1 << 6)
533 // address, applet, article, aside, blockquote, button, center, del, dir, div,
534 // dl, fieldset, figure, footer, form, h1, h2, h3, h4, h5, h6, header, hgroup,
535 // hr, iframe, ins, main, map, menu, nav, noframes, noscript, object, ol, p,
536 // pre, table, section, ul
537 #define GROUP_BLOCK (1 << 7)
539 // frame, frameset
540 #define GROUP_FRAME (1 << 8)
542 // col, tbody
543 #define GROUP_TABLE_CONTENT (1 << 9)
545 // tr
546 #define GROUP_TBODY_CONTENT (1 << 10)
548 // td, th
549 #define GROUP_TR_CONTENT (1 << 11)
551 // col
552 #define GROUP_COLGROUP_CONTENT (1 << 12)
554 // param
555 #define GROUP_OBJECT_CONTENT (1 << 13)
557 // li
558 #define GROUP_LI (1 << 14)
560 // area
561 #define GROUP_MAP_CONTENT (1 << 15)
563 // optgroup, option
564 #define GROUP_SELECT_CONTENT (1 << 16)
566 // option
567 #define GROUP_OPTIONS (1 << 17)
569 // dd, dt
570 #define GROUP_DL_CONTENT (1 << 18)
572 // p
573 #define GROUP_P (1 << 19)
575 // text, whitespace, newline, comment
576 #define GROUP_LEAF (1 << 20)
578 // XXX This is because the editor does sublists illegally.
579 // ol, ul
580 #define GROUP_OL_UL (1 << 21)
582 // h1, h2, h3, h4, h5, h6
583 #define GROUP_HEADING (1 << 22)
585 // figcaption
586 #define GROUP_FIGCAPTION (1 << 23)
588 #define GROUP_INLINE_ELEMENT \
589 (GROUP_FONTSTYLE | GROUP_PHRASE | GROUP_SPECIAL | GROUP_FORMCONTROL | \
590 GROUP_LEAF)
592 #define GROUP_FLOW_ELEMENT (GROUP_INLINE_ELEMENT | GROUP_BLOCK)
594 struct nsElementInfo
595 {
596 #ifdef DEBUG
597 eHTMLTags mTag;
598 #endif
599 uint32_t mGroup;
600 uint32_t mCanContainGroups;
601 bool mIsContainer;
602 bool mCanContainSelf;
603 };
605 #ifdef DEBUG
606 #define ELEM(_tag, _isContainer, _canContainSelf, _group, _canContainGroups) \
607 { eHTMLTag_##_tag, _group, _canContainGroups, _isContainer, _canContainSelf }
608 #else
609 #define ELEM(_tag, _isContainer, _canContainSelf, _group, _canContainGroups) \
610 { _group, _canContainGroups, _isContainer, _canContainSelf }
611 #endif
613 static const nsElementInfo kElements[eHTMLTag_userdefined] = {
614 ELEM(a, true, false, GROUP_SPECIAL, GROUP_INLINE_ELEMENT),
615 ELEM(abbr, true, true, GROUP_PHRASE, GROUP_INLINE_ELEMENT),
616 ELEM(acronym, true, true, GROUP_PHRASE, GROUP_INLINE_ELEMENT),
617 ELEM(address, true, true, GROUP_BLOCK,
618 GROUP_INLINE_ELEMENT | GROUP_P),
619 ELEM(applet, true, true, GROUP_SPECIAL | GROUP_BLOCK,
620 GROUP_FLOW_ELEMENT | GROUP_OBJECT_CONTENT),
621 ELEM(area, false, false, GROUP_MAP_CONTENT, GROUP_NONE),
622 ELEM(article, true, true, GROUP_BLOCK, GROUP_FLOW_ELEMENT),
623 ELEM(aside, true, true, GROUP_BLOCK, GROUP_FLOW_ELEMENT),
624 ELEM(audio, false, false, GROUP_NONE, GROUP_NONE),
625 ELEM(b, true, true, GROUP_FONTSTYLE, GROUP_INLINE_ELEMENT),
626 ELEM(base, false, false, GROUP_HEAD_CONTENT, GROUP_NONE),
627 ELEM(basefont, false, false, GROUP_SPECIAL, GROUP_NONE),
628 ELEM(bdo, true, true, GROUP_SPECIAL, GROUP_INLINE_ELEMENT),
629 ELEM(bgsound, false, false, GROUP_NONE, GROUP_NONE),
630 ELEM(big, true, true, GROUP_FONTSTYLE, GROUP_INLINE_ELEMENT),
631 ELEM(blockquote, true, true, GROUP_BLOCK, GROUP_FLOW_ELEMENT),
632 ELEM(body, true, true, GROUP_TOPLEVEL, GROUP_FLOW_ELEMENT),
633 ELEM(br, false, false, GROUP_SPECIAL, GROUP_NONE),
634 ELEM(button, true, true, GROUP_FORMCONTROL | GROUP_BLOCK,
635 GROUP_FLOW_ELEMENT),
636 ELEM(canvas, false, false, GROUP_NONE, GROUP_NONE),
637 ELEM(caption, true, true, GROUP_NONE, GROUP_INLINE_ELEMENT),
638 ELEM(center, true, true, GROUP_BLOCK, GROUP_FLOW_ELEMENT),
639 ELEM(cite, true, true, GROUP_PHRASE, GROUP_INLINE_ELEMENT),
640 ELEM(code, true, true, GROUP_PHRASE, GROUP_INLINE_ELEMENT),
641 ELEM(col, false, false, GROUP_TABLE_CONTENT | GROUP_COLGROUP_CONTENT,
642 GROUP_NONE),
643 ELEM(colgroup, true, false, GROUP_NONE, GROUP_COLGROUP_CONTENT),
644 ELEM(content, true, false, GROUP_NONE, GROUP_INLINE_ELEMENT),
645 ELEM(data, true, false, GROUP_PHRASE, GROUP_INLINE_ELEMENT),
646 ELEM(datalist, true, false, GROUP_PHRASE,
647 GROUP_OPTIONS | GROUP_INLINE_ELEMENT),
648 ELEM(dd, true, false, GROUP_DL_CONTENT, GROUP_FLOW_ELEMENT),
649 ELEM(del, true, true, GROUP_PHRASE | GROUP_BLOCK, GROUP_FLOW_ELEMENT),
650 ELEM(dfn, true, true, GROUP_PHRASE, GROUP_INLINE_ELEMENT),
651 ELEM(dir, true, false, GROUP_BLOCK, GROUP_LI),
652 ELEM(div, true, true, GROUP_BLOCK, GROUP_FLOW_ELEMENT),
653 ELEM(dl, true, false, GROUP_BLOCK, GROUP_DL_CONTENT),
654 ELEM(dt, true, true, GROUP_DL_CONTENT, GROUP_INLINE_ELEMENT),
655 ELEM(em, true, true, GROUP_PHRASE, GROUP_INLINE_ELEMENT),
656 ELEM(embed, false, false, GROUP_NONE, GROUP_NONE),
657 ELEM(fieldset, true, true, GROUP_BLOCK, GROUP_FLOW_ELEMENT),
658 ELEM(figcaption, true, false, GROUP_FIGCAPTION, GROUP_FLOW_ELEMENT),
659 ELEM(figure, true, true, GROUP_BLOCK,
660 GROUP_FLOW_ELEMENT | GROUP_FIGCAPTION),
661 ELEM(font, true, true, GROUP_SPECIAL, GROUP_INLINE_ELEMENT),
662 ELEM(footer, true, true, GROUP_BLOCK, GROUP_FLOW_ELEMENT),
663 ELEM(form, true, true, GROUP_BLOCK, GROUP_FLOW_ELEMENT),
664 ELEM(frame, false, false, GROUP_FRAME, GROUP_NONE),
665 ELEM(frameset, true, true, GROUP_FRAME, GROUP_FRAME),
666 ELEM(h1, true, false, GROUP_BLOCK | GROUP_HEADING,
667 GROUP_INLINE_ELEMENT),
668 ELEM(h2, true, false, GROUP_BLOCK | GROUP_HEADING,
669 GROUP_INLINE_ELEMENT),
670 ELEM(h3, true, false, GROUP_BLOCK | GROUP_HEADING,
671 GROUP_INLINE_ELEMENT),
672 ELEM(h4, true, false, GROUP_BLOCK | GROUP_HEADING,
673 GROUP_INLINE_ELEMENT),
674 ELEM(h5, true, false, GROUP_BLOCK | GROUP_HEADING,
675 GROUP_INLINE_ELEMENT),
676 ELEM(h6, true, false, GROUP_BLOCK | GROUP_HEADING,
677 GROUP_INLINE_ELEMENT),
678 ELEM(head, true, false, GROUP_TOPLEVEL, GROUP_HEAD_CONTENT),
679 ELEM(header, true, true, GROUP_BLOCK, GROUP_FLOW_ELEMENT),
680 ELEM(hgroup, true, false, GROUP_BLOCK, GROUP_HEADING),
681 ELEM(hr, false, false, GROUP_BLOCK, GROUP_NONE),
682 ELEM(html, true, false, GROUP_TOPLEVEL, GROUP_TOPLEVEL),
683 ELEM(i, true, true, GROUP_FONTSTYLE, GROUP_INLINE_ELEMENT),
684 ELEM(iframe, true, true, GROUP_SPECIAL | GROUP_BLOCK,
685 GROUP_FLOW_ELEMENT),
686 ELEM(image, false, false, GROUP_NONE, GROUP_NONE),
687 ELEM(img, false, false, GROUP_SPECIAL, GROUP_NONE),
688 ELEM(input, false, false, GROUP_FORMCONTROL, GROUP_NONE),
689 ELEM(ins, true, true, GROUP_PHRASE | GROUP_BLOCK, GROUP_FLOW_ELEMENT),
690 ELEM(kbd, true, true, GROUP_PHRASE, GROUP_INLINE_ELEMENT),
691 ELEM(keygen, false, false, GROUP_FORMCONTROL, GROUP_NONE),
692 ELEM(label, true, false, GROUP_FORMCONTROL, GROUP_INLINE_ELEMENT),
693 ELEM(legend, true, true, GROUP_NONE, GROUP_INLINE_ELEMENT),
694 ELEM(li, true, false, GROUP_LI, GROUP_FLOW_ELEMENT),
695 ELEM(link, false, false, GROUP_HEAD_CONTENT, GROUP_NONE),
696 ELEM(listing, false, false, GROUP_NONE, GROUP_NONE),
697 ELEM(main, true, true, GROUP_BLOCK, GROUP_FLOW_ELEMENT),
698 ELEM(map, true, true, GROUP_SPECIAL, GROUP_BLOCK | GROUP_MAP_CONTENT),
699 ELEM(mark, true, true, GROUP_PHRASE, GROUP_INLINE_ELEMENT),
700 ELEM(marquee, false, false, GROUP_NONE, GROUP_NONE),
701 ELEM(menu, true, true, GROUP_BLOCK, GROUP_LI | GROUP_FLOW_ELEMENT),
702 ELEM(menuitem, false, false, GROUP_NONE, GROUP_NONE),
703 ELEM(meta, false, false, GROUP_HEAD_CONTENT, GROUP_NONE),
704 ELEM(meter, true, false, GROUP_SPECIAL, GROUP_FLOW_ELEMENT),
705 ELEM(multicol, false, false, GROUP_NONE, GROUP_NONE),
706 ELEM(nav, true, true, GROUP_BLOCK, GROUP_FLOW_ELEMENT),
707 ELEM(nobr, false, false, GROUP_NONE, GROUP_NONE),
708 ELEM(noembed, false, false, GROUP_NONE, GROUP_NONE),
709 ELEM(noframes, true, true, GROUP_BLOCK, GROUP_FLOW_ELEMENT),
710 ELEM(noscript, true, true, GROUP_BLOCK, GROUP_FLOW_ELEMENT),
711 ELEM(object, true, true, GROUP_SPECIAL | GROUP_BLOCK,
712 GROUP_FLOW_ELEMENT | GROUP_OBJECT_CONTENT),
713 // XXX Can contain self and ul because editor does sublists illegally.
714 ELEM(ol, true, true, GROUP_BLOCK | GROUP_OL_UL,
715 GROUP_LI | GROUP_OL_UL),
716 ELEM(optgroup, true, false, GROUP_SELECT_CONTENT,
717 GROUP_OPTIONS),
718 ELEM(option, true, false,
719 GROUP_SELECT_CONTENT | GROUP_OPTIONS, GROUP_LEAF),
720 ELEM(output, true, true, GROUP_SPECIAL, GROUP_INLINE_ELEMENT),
721 ELEM(p, true, false, GROUP_BLOCK | GROUP_P, GROUP_INLINE_ELEMENT),
722 ELEM(param, false, false, GROUP_OBJECT_CONTENT, GROUP_NONE),
723 ELEM(plaintext, false, false, GROUP_NONE, GROUP_NONE),
724 ELEM(pre, true, true, GROUP_BLOCK, GROUP_INLINE_ELEMENT),
725 ELEM(progress, true, false, GROUP_SPECIAL, GROUP_FLOW_ELEMENT),
726 ELEM(q, true, true, GROUP_SPECIAL, GROUP_INLINE_ELEMENT),
727 ELEM(s, true, true, GROUP_FONTSTYLE, GROUP_INLINE_ELEMENT),
728 ELEM(samp, true, true, GROUP_PHRASE, GROUP_INLINE_ELEMENT),
729 ELEM(script, true, false, GROUP_HEAD_CONTENT | GROUP_SPECIAL,
730 GROUP_LEAF),
731 ELEM(section, true, true, GROUP_BLOCK, GROUP_FLOW_ELEMENT),
732 ELEM(select, true, false, GROUP_FORMCONTROL, GROUP_SELECT_CONTENT),
733 ELEM(shadow, true, false, GROUP_NONE, GROUP_INLINE_ELEMENT),
734 ELEM(small, true, true, GROUP_FONTSTYLE, GROUP_INLINE_ELEMENT),
735 ELEM(source, false, false, GROUP_NONE, GROUP_NONE),
736 ELEM(span, true, true, GROUP_SPECIAL, GROUP_INLINE_ELEMENT),
737 ELEM(strike, true, true, GROUP_FONTSTYLE, GROUP_INLINE_ELEMENT),
738 ELEM(strong, true, true, GROUP_PHRASE, GROUP_INLINE_ELEMENT),
739 ELEM(style, true, false, GROUP_HEAD_CONTENT, GROUP_LEAF),
740 ELEM(sub, true, true, GROUP_SPECIAL, GROUP_INLINE_ELEMENT),
741 ELEM(sup, true, true, GROUP_SPECIAL, GROUP_INLINE_ELEMENT),
742 ELEM(table, true, false, GROUP_BLOCK, GROUP_TABLE_CONTENT),
743 ELEM(tbody, true, false, GROUP_TABLE_CONTENT, GROUP_TBODY_CONTENT),
744 ELEM(td, true, false, GROUP_TR_CONTENT, GROUP_FLOW_ELEMENT),
745 ELEM(textarea, true, false, GROUP_FORMCONTROL, GROUP_LEAF),
746 ELEM(tfoot, true, false, GROUP_NONE, GROUP_TBODY_CONTENT),
747 ELEM(th, true, false, GROUP_TR_CONTENT, GROUP_FLOW_ELEMENT),
748 ELEM(thead, true, false, GROUP_NONE, GROUP_TBODY_CONTENT),
749 ELEM(template, false, false, GROUP_NONE, GROUP_NONE),
750 ELEM(time, true, false, GROUP_PHRASE, GROUP_INLINE_ELEMENT),
751 ELEM(title, true, false, GROUP_HEAD_CONTENT, GROUP_LEAF),
752 ELEM(tr, true, false, GROUP_TBODY_CONTENT, GROUP_TR_CONTENT),
753 ELEM(track, false, false, GROUP_NONE, GROUP_NONE),
754 ELEM(tt, true, true, GROUP_FONTSTYLE, GROUP_INLINE_ELEMENT),
755 ELEM(u, true, true, GROUP_FONTSTYLE, GROUP_INLINE_ELEMENT),
756 // XXX Can contain self and ol because editor does sublists illegally.
757 ELEM(ul, true, true, GROUP_BLOCK | GROUP_OL_UL,
758 GROUP_LI | GROUP_OL_UL),
759 ELEM(var, true, true, GROUP_PHRASE, GROUP_INLINE_ELEMENT),
760 ELEM(video, false, false, GROUP_NONE, GROUP_NONE),
761 ELEM(wbr, false, false, GROUP_NONE, GROUP_NONE),
762 ELEM(xmp, false, false, GROUP_NONE, GROUP_NONE),
764 // These aren't elements.
765 ELEM(text, false, false, GROUP_LEAF, GROUP_NONE),
766 ELEM(whitespace, false, false, GROUP_LEAF, GROUP_NONE),
767 ELEM(newline, false, false, GROUP_LEAF, GROUP_NONE),
768 ELEM(comment, false, false, GROUP_LEAF, GROUP_NONE),
769 ELEM(entity, false, false, GROUP_NONE, GROUP_NONE),
770 ELEM(doctypeDecl, false, false, GROUP_NONE, GROUP_NONE),
771 ELEM(markupDecl, false, false, GROUP_NONE, GROUP_NONE),
772 ELEM(instruction, false, false, GROUP_NONE, GROUP_NONE),
774 ELEM(userdefined, true, false, GROUP_NONE, GROUP_FLOW_ELEMENT)
775 };
777 bool
778 nsHTMLEditUtils::CanContain(int32_t aParent, int32_t aChild)
779 {
780 NS_ASSERTION(aParent > eHTMLTag_unknown && aParent <= eHTMLTag_userdefined,
781 "aParent out of range!");
782 NS_ASSERTION(aChild > eHTMLTag_unknown && aChild <= eHTMLTag_userdefined,
783 "aChild out of range!");
785 #ifdef DEBUG
786 static bool checked = false;
787 if (!checked) {
788 checked = true;
789 int32_t i;
790 for (i = 1; i <= eHTMLTag_userdefined; ++i) {
791 NS_ASSERTION(kElements[i - 1].mTag == i,
792 "You need to update kElements (missing tags).");
793 }
794 }
795 #endif
797 // Special-case button.
798 if (aParent == eHTMLTag_button) {
799 static const eHTMLTags kButtonExcludeKids[] = {
800 eHTMLTag_a,
801 eHTMLTag_fieldset,
802 eHTMLTag_form,
803 eHTMLTag_iframe,
804 eHTMLTag_input,
805 eHTMLTag_select,
806 eHTMLTag_textarea
807 };
809 uint32_t j;
810 for (j = 0; j < ArrayLength(kButtonExcludeKids); ++j) {
811 if (kButtonExcludeKids[j] == aChild) {
812 return false;
813 }
814 }
815 }
817 // Deprecated elements.
818 if (aChild == eHTMLTag_bgsound) {
819 return false;
820 }
822 // Bug #67007, dont strip userdefined tags.
823 if (aChild == eHTMLTag_userdefined) {
824 return true;
825 }
827 const nsElementInfo& parent = kElements[aParent - 1];
828 if (aParent == aChild) {
829 return parent.mCanContainSelf;
830 }
832 const nsElementInfo& child = kElements[aChild - 1];
833 return (parent.mCanContainGroups & child.mGroup) != 0;
834 }
836 bool
837 nsHTMLEditUtils::IsContainer(int32_t aTag)
838 {
839 NS_ASSERTION(aTag > eHTMLTag_unknown && aTag <= eHTMLTag_userdefined,
840 "aTag out of range!");
842 return kElements[aTag - 1].mIsContainer;
843 }