LCOV - code coverage report
Current view: top level - editor/libeditor - HTMLEditUtils.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 0 176 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 42 0.0 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.13