Node.cpp 125 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780
  1. /*
  2. * Copyright (c) 2018-2024, Andreas Kling <andreas@ladybird.org>
  3. * Copyright (c) 2021-2022, Linus Groh <linusg@serenityos.org>
  4. * Copyright (c) 2021, Luke Wilde <lukew@serenityos.org>
  5. * Copyright (c) 2024, Jelle Raaijmakers <jelle@ladybird.org>
  6. *
  7. * SPDX-License-Identifier: BSD-2-Clause
  8. */
  9. #include <AK/HashTable.h>
  10. #include <AK/StringBuilder.h>
  11. #include <LibGC/DeferGC.h>
  12. #include <LibJS/Runtime/FunctionObject.h>
  13. #include <LibRegex/Regex.h>
  14. #include <LibWeb/Bindings/MainThreadVM.h>
  15. #include <LibWeb/Bindings/NodePrototype.h>
  16. #include <LibWeb/DOM/Attr.h>
  17. #include <LibWeb/DOM/CDATASection.h>
  18. #include <LibWeb/DOM/Comment.h>
  19. #include <LibWeb/DOM/DocumentType.h>
  20. #include <LibWeb/DOM/Element.h>
  21. #include <LibWeb/DOM/ElementFactory.h>
  22. #include <LibWeb/DOM/Event.h>
  23. #include <LibWeb/DOM/EventDispatcher.h>
  24. #include <LibWeb/DOM/IDLEventListener.h>
  25. #include <LibWeb/DOM/LiveNodeList.h>
  26. #include <LibWeb/DOM/MutationType.h>
  27. #include <LibWeb/DOM/NamedNodeMap.h>
  28. #include <LibWeb/DOM/Node.h>
  29. #include <LibWeb/DOM/NodeIterator.h>
  30. #include <LibWeb/DOM/ProcessingInstruction.h>
  31. #include <LibWeb/DOM/Range.h>
  32. #include <LibWeb/DOM/ShadowRoot.h>
  33. #include <LibWeb/DOM/StaticNodeList.h>
  34. #include <LibWeb/DOM/XMLDocument.h>
  35. #include <LibWeb/HTML/CustomElements/CustomElementReactionNames.h>
  36. #include <LibWeb/HTML/HTMLAnchorElement.h>
  37. #include <LibWeb/HTML/HTMLDocument.h>
  38. #include <LibWeb/HTML/HTMLFieldSetElement.h>
  39. #include <LibWeb/HTML/HTMLImageElement.h>
  40. #include <LibWeb/HTML/HTMLInputElement.h>
  41. #include <LibWeb/HTML/HTMLLegendElement.h>
  42. #include <LibWeb/HTML/HTMLSelectElement.h>
  43. #include <LibWeb/HTML/HTMLSlotElement.h>
  44. #include <LibWeb/HTML/HTMLStyleElement.h>
  45. #include <LibWeb/HTML/HTMLTableElement.h>
  46. #include <LibWeb/HTML/HTMLTextAreaElement.h>
  47. #include <LibWeb/HTML/Navigable.h>
  48. #include <LibWeb/HTML/NavigableContainer.h>
  49. #include <LibWeb/HTML/Parser/HTMLParser.h>
  50. #include <LibWeb/Infra/CharacterTypes.h>
  51. #include <LibWeb/Layout/Node.h>
  52. #include <LibWeb/Layout/TextNode.h>
  53. #include <LibWeb/MathML/MathMLElement.h>
  54. #include <LibWeb/Namespace.h>
  55. #include <LibWeb/Painting/Paintable.h>
  56. #include <LibWeb/Painting/PaintableBox.h>
  57. #include <LibWeb/SVG/SVGElement.h>
  58. #include <LibWeb/SVG/SVGTitleElement.h>
  59. #include <LibWeb/XLink/AttributeNames.h>
  60. namespace Web::DOM {
  61. static UniqueNodeID s_next_unique_id;
  62. static HashMap<UniqueNodeID, Node*> s_node_directory;
  63. static UniqueNodeID allocate_unique_id(Node* node)
  64. {
  65. auto id = s_next_unique_id;
  66. ++s_next_unique_id;
  67. s_node_directory.set(id, node);
  68. return id;
  69. }
  70. static void deallocate_unique_id(UniqueNodeID node_id)
  71. {
  72. if (!s_node_directory.remove(node_id))
  73. VERIFY_NOT_REACHED();
  74. }
  75. Node* Node::from_unique_id(UniqueNodeID unique_id)
  76. {
  77. return s_node_directory.get(unique_id).value_or(nullptr);
  78. }
  79. Node::Node(JS::Realm& realm, Document& document, NodeType type)
  80. : EventTarget(realm)
  81. , m_document(&document)
  82. , m_type(type)
  83. , m_unique_id(allocate_unique_id(this))
  84. {
  85. }
  86. Node::Node(Document& document, NodeType type)
  87. : Node(document.realm(), document, type)
  88. {
  89. }
  90. Node::~Node() = default;
  91. void Node::finalize()
  92. {
  93. Base::finalize();
  94. deallocate_unique_id(m_unique_id);
  95. }
  96. void Node::visit_edges(Cell::Visitor& visitor)
  97. {
  98. Base::visit_edges(visitor);
  99. visitor.visit(m_document);
  100. visitor.visit(m_parent);
  101. visitor.visit(m_first_child);
  102. visitor.visit(m_last_child);
  103. visitor.visit(m_next_sibling);
  104. visitor.visit(m_previous_sibling);
  105. visitor.visit(m_child_nodes);
  106. visitor.visit(m_layout_node);
  107. visitor.visit(m_paintable);
  108. if (m_registered_observer_list) {
  109. visitor.visit(*m_registered_observer_list);
  110. }
  111. }
  112. // https://dom.spec.whatwg.org/#dom-node-baseuri
  113. String Node::base_uri() const
  114. {
  115. // Return this’s node document’s document base URL, serialized.
  116. return document().base_url().to_string();
  117. }
  118. const HTML::HTMLAnchorElement* Node::enclosing_link_element() const
  119. {
  120. for (auto* node = this; node; node = node->parent()) {
  121. if (!is<HTML::HTMLAnchorElement>(*node))
  122. continue;
  123. auto const& anchor_element = static_cast<HTML::HTMLAnchorElement const&>(*node);
  124. if (anchor_element.has_attribute(HTML::AttributeNames::href))
  125. return &anchor_element;
  126. }
  127. return nullptr;
  128. }
  129. const HTML::HTMLElement* Node::enclosing_html_element() const
  130. {
  131. return first_ancestor_of_type<HTML::HTMLElement>();
  132. }
  133. const HTML::HTMLElement* Node::enclosing_html_element_with_attribute(FlyString const& attribute) const
  134. {
  135. for (auto* node = this; node; node = node->parent()) {
  136. if (is<HTML::HTMLElement>(*node) && verify_cast<HTML::HTMLElement>(*node).has_attribute(attribute))
  137. return verify_cast<HTML::HTMLElement>(node);
  138. }
  139. return nullptr;
  140. }
  141. Optional<String> Node::alternative_text() const
  142. {
  143. return {};
  144. }
  145. // https://dom.spec.whatwg.org/#concept-descendant-text-content
  146. String Node::descendant_text_content() const
  147. {
  148. StringBuilder builder;
  149. for_each_in_subtree_of_type<Text>([&](auto& text_node) {
  150. builder.append(text_node.data());
  151. return TraversalDecision::Continue;
  152. });
  153. return builder.to_string_without_validation();
  154. }
  155. // https://dom.spec.whatwg.org/#dom-node-textcontent
  156. Optional<String> Node::text_content() const
  157. {
  158. // The textContent getter steps are to return the following, switching on the interface this implements:
  159. // If DocumentFragment or Element, return the descendant text content of this.
  160. if (is<DocumentFragment>(this) || is<Element>(this))
  161. return descendant_text_content();
  162. // If CharacterData, return this’s data.
  163. if (is<CharacterData>(this))
  164. return static_cast<CharacterData const&>(*this).data();
  165. // If Attr node, return this's value.
  166. if (is<Attr>(*this))
  167. return static_cast<Attr const&>(*this).value();
  168. // Otherwise, return null
  169. return {};
  170. }
  171. // https://dom.spec.whatwg.org/#ref-for-dom-node-textcontent%E2%91%A0
  172. void Node::set_text_content(Optional<String> const& maybe_content)
  173. {
  174. // The textContent setter steps are to, if the given value is null, act as if it was the empty string instead,
  175. // and then do as described below, switching on the interface this implements:
  176. auto content = maybe_content.value_or(String {});
  177. // If DocumentFragment or Element, string replace all with the given value within this.
  178. if (is<DocumentFragment>(this) || is<Element>(this)) {
  179. string_replace_all(content);
  180. }
  181. // If CharacterData, replace data with node this, offset 0, count this’s length, and data the given value.
  182. else if (is<CharacterData>(this)) {
  183. auto* character_data_node = verify_cast<CharacterData>(this);
  184. character_data_node->set_data(content);
  185. // FIXME: CharacterData::set_data is not spec compliant. Make this match the spec when set_data becomes spec compliant.
  186. // Do note that this will make this function able to throw an exception.
  187. }
  188. // If Attr, set an existing attribute value with this and the given value.
  189. if (is<Attr>(*this)) {
  190. static_cast<Attr&>(*this).set_value(content);
  191. }
  192. // Otherwise, do nothing.
  193. if (is_connected()) {
  194. invalidate_style(StyleInvalidationReason::NodeSetTextContent);
  195. document().invalidate_layout_tree();
  196. }
  197. document().bump_dom_tree_version();
  198. }
  199. // https://dom.spec.whatwg.org/#dom-node-normalize
  200. WebIDL::ExceptionOr<void> Node::normalize()
  201. {
  202. auto contiguous_exclusive_text_nodes_excluding_self = [](Node& node) {
  203. // https://dom.spec.whatwg.org/#contiguous-exclusive-text-nodes
  204. // The contiguous exclusive Text nodes of a node node are node, node’s previous sibling exclusive Text node, if any,
  205. // and its contiguous exclusive Text nodes, and node’s next sibling exclusive Text node, if any,
  206. // and its contiguous exclusive Text nodes, avoiding any duplicates.
  207. // NOTE: The callers of this method require node itself to be excluded.
  208. Vector<Text*> nodes;
  209. auto* current_node = node.previous_sibling();
  210. while (current_node && current_node->is_exclusive_text()) {
  211. nodes.append(static_cast<Text*>(current_node));
  212. current_node = current_node->previous_sibling();
  213. }
  214. // Reverse the order of the nodes so that they are in tree order.
  215. nodes.reverse();
  216. current_node = node.next_sibling();
  217. while (current_node && current_node->is_exclusive_text()) {
  218. nodes.append(static_cast<Text*>(current_node));
  219. current_node = current_node->next_sibling();
  220. }
  221. return nodes;
  222. };
  223. // The normalize() method steps are to run these steps for each descendant exclusive Text node node of this
  224. Vector<Text&> descendant_exclusive_text_nodes;
  225. for_each_in_inclusive_subtree_of_type<Text>([&](Text const& node) {
  226. if (!node.is_cdata_section())
  227. descendant_exclusive_text_nodes.append(const_cast<Text&>(node));
  228. return TraversalDecision::Continue;
  229. });
  230. for (auto& node : descendant_exclusive_text_nodes) {
  231. // 1. Let length be node’s length.
  232. auto& character_data = static_cast<CharacterData&>(node);
  233. auto length = character_data.length_in_utf16_code_units();
  234. // 2. If length is zero, then remove node and continue with the next exclusive Text node, if any.
  235. if (length == 0) {
  236. if (node.parent())
  237. node.remove();
  238. continue;
  239. }
  240. // 3. Let data be the concatenation of the data of node’s contiguous exclusive Text nodes (excluding itself), in tree order.
  241. StringBuilder data;
  242. for (auto const& text_node : contiguous_exclusive_text_nodes_excluding_self(node))
  243. data.append(text_node->data());
  244. // 4. Replace data with node node, offset length, count 0, and data data.
  245. TRY(character_data.replace_data(length, 0, MUST(data.to_string())));
  246. // 5. Let currentNode be node’s next sibling.
  247. auto* current_node = node.next_sibling();
  248. // 6. While currentNode is an exclusive Text node:
  249. while (current_node && current_node->is_exclusive_text()) {
  250. // 1. For each live range whose start node is currentNode, add length to its start offset and set its start node to node.
  251. for (auto& range : Range::live_ranges()) {
  252. if (range->start_container() == current_node)
  253. TRY(range->set_start(node, range->start_offset() + length));
  254. }
  255. // 2. For each live range whose end node is currentNode, add length to its end offset and set its end node to node.
  256. for (auto& range : Range::live_ranges()) {
  257. if (range->end_container() == current_node)
  258. TRY(range->set_end(node, range->end_offset() + length));
  259. }
  260. // 3. For each live range whose start node is currentNode’s parent and start offset is currentNode’s index, set its start node to node and its start offset to length.
  261. for (auto& range : Range::live_ranges()) {
  262. if (range->start_container() == current_node->parent() && range->start_offset() == current_node->index())
  263. TRY(range->set_start(node, length));
  264. }
  265. // 4. For each live range whose end node is currentNode’s parent and end offset is currentNode’s index, set its end node to node and its end offset to length.
  266. for (auto& range : Range::live_ranges()) {
  267. if (range->end_container() == current_node->parent() && range->end_offset() == current_node->index())
  268. TRY(range->set_end(node, length));
  269. }
  270. // 5. Add currentNode’s length to length.
  271. length += static_cast<Text&>(*current_node).length();
  272. // 6. Set currentNode to its next sibling.
  273. current_node = current_node->next_sibling();
  274. }
  275. // 7. Remove node’s contiguous exclusive Text nodes (excluding itself), in tree order.
  276. for (auto const& text_node : contiguous_exclusive_text_nodes_excluding_self(node))
  277. text_node->remove();
  278. }
  279. return {};
  280. }
  281. // https://dom.spec.whatwg.org/#dom-node-nodevalue
  282. Optional<String> Node::node_value() const
  283. {
  284. // The nodeValue getter steps are to return the following, switching on the interface this implements:
  285. // If Attr, return this’s value.
  286. if (is<Attr>(this)) {
  287. return verify_cast<Attr>(this)->value();
  288. }
  289. // If CharacterData, return this’s data.
  290. if (is<CharacterData>(this)) {
  291. return verify_cast<CharacterData>(this)->data();
  292. }
  293. // Otherwise, return null.
  294. return {};
  295. }
  296. // https://dom.spec.whatwg.org/#ref-for-dom-node-nodevalue%E2%91%A0
  297. void Node::set_node_value(Optional<String> const& maybe_value)
  298. {
  299. // The nodeValue setter steps are to, if the given value is null, act as if it was the empty string instead,
  300. // and then do as described below, switching on the interface this implements:
  301. auto value = maybe_value.value_or(String {});
  302. // If Attr, set an existing attribute value with this and the given value.
  303. if (is<Attr>(this)) {
  304. verify_cast<Attr>(this)->set_value(move(value));
  305. } else if (is<CharacterData>(this)) {
  306. // If CharacterData, replace data with node this, offset 0, count this’s length, and data the given value.
  307. verify_cast<CharacterData>(this)->set_data(value);
  308. }
  309. // Otherwise, do nothing.
  310. }
  311. // https://html.spec.whatwg.org/multipage/document-sequences.html#node-navigable
  312. GC::Ptr<HTML::Navigable> Node::navigable() const
  313. {
  314. auto& document = const_cast<Document&>(this->document());
  315. if (auto cached_navigable = document.cached_navigable()) {
  316. if (cached_navigable->active_document() == &document)
  317. return cached_navigable;
  318. }
  319. // To get the node navigable of a node node, return the navigable whose active document is node's node document,
  320. // or null if there is no such navigable.
  321. auto navigable = HTML::Navigable::navigable_with_active_document(document);
  322. document.set_cached_navigable(navigable);
  323. return navigable;
  324. }
  325. [[maybe_unused]] static StringView to_string(StyleInvalidationReason reason)
  326. {
  327. #define __ENUMERATE_STYLE_INVALIDATION_REASON(reason) \
  328. case StyleInvalidationReason::reason: \
  329. return #reason##sv;
  330. switch (reason) {
  331. ENUMERATE_STYLE_INVALIDATION_REASONS(__ENUMERATE_STYLE_INVALIDATION_REASON)
  332. default:
  333. VERIFY_NOT_REACHED();
  334. }
  335. }
  336. void Node::invalidate_style(StyleInvalidationReason reason)
  337. {
  338. if (is_character_data())
  339. return;
  340. // FIXME: This is very not optimal! We should figure out a smaller set of elements to invalidate,
  341. // but right now the :has() selector means we have to invalidate everything.
  342. if (!is_document() && document().style_computer().has_has_selectors()) {
  343. document().invalidate_style(reason);
  344. return;
  345. }
  346. if (!needs_style_update() && !document().needs_full_style_update()) {
  347. dbgln_if(STYLE_INVALIDATION_DEBUG, "Invalidate style ({}): {}", to_string(reason), debug_description());
  348. }
  349. if (is_document()) {
  350. auto& document = static_cast<DOM::Document&>(*this);
  351. document.set_needs_full_style_update(true);
  352. document.schedule_style_update();
  353. return;
  354. }
  355. // If the document is already marked for a full style update, there's no need to do anything here.
  356. if (document().needs_full_style_update()) {
  357. return;
  358. }
  359. // When invalidating style for a node, we actually invalidate:
  360. // - the node itself
  361. // - all of its descendants
  362. // - all of its preceding siblings and their descendants (only on DOM insert/remove)
  363. // - all of its subsequent siblings and their descendants
  364. // FIXME: This is a lot of invalidation and we should implement more sophisticated invalidation to do less work!
  365. auto invalidate_entire_subtree = [&](Node& subtree_root) {
  366. subtree_root.for_each_in_inclusive_subtree([&](Node& node) {
  367. node.m_needs_style_update = true;
  368. if (node.has_children())
  369. node.m_child_needs_style_update = true;
  370. if (auto shadow_root = node.is_element() ? static_cast<DOM::Element&>(node).shadow_root() : nullptr) {
  371. node.m_child_needs_style_update = true;
  372. shadow_root->m_needs_style_update = true;
  373. if (shadow_root->has_children())
  374. shadow_root->m_child_needs_style_update = true;
  375. }
  376. return TraversalDecision::Continue;
  377. });
  378. };
  379. invalidate_entire_subtree(*this);
  380. if (reason == StyleInvalidationReason::NodeInsertBefore || reason == StyleInvalidationReason::NodeRemove) {
  381. for (auto* sibling = previous_sibling(); sibling; sibling = sibling->previous_sibling()) {
  382. if (sibling->is_element())
  383. invalidate_entire_subtree(*sibling);
  384. }
  385. }
  386. for (auto* sibling = next_sibling(); sibling; sibling = sibling->next_sibling()) {
  387. if (sibling->is_element())
  388. invalidate_entire_subtree(*sibling);
  389. }
  390. for (auto* ancestor = parent_or_shadow_host(); ancestor; ancestor = ancestor->parent_or_shadow_host())
  391. ancestor->m_child_needs_style_update = true;
  392. document().schedule_style_update();
  393. }
  394. String Node::child_text_content() const
  395. {
  396. if (!is<ParentNode>(*this))
  397. return String {};
  398. StringBuilder builder;
  399. verify_cast<ParentNode>(*this).for_each_child([&](auto& child) {
  400. if (is<Text>(child)) {
  401. auto maybe_content = verify_cast<Text>(child).text_content();
  402. if (maybe_content.has_value())
  403. builder.append(maybe_content.value());
  404. }
  405. return IterationDecision::Continue;
  406. });
  407. return MUST(builder.to_string());
  408. }
  409. // https://dom.spec.whatwg.org/#concept-tree-root
  410. Node& Node::root()
  411. {
  412. // The root of an object is itself, if its parent is null, or else it is the root of its parent.
  413. // The root of a tree is any object participating in that tree whose parent is null.
  414. Node* root = this;
  415. while (root->parent())
  416. root = root->parent();
  417. return *root;
  418. }
  419. // https://dom.spec.whatwg.org/#concept-shadow-including-root
  420. Node& Node::shadow_including_root()
  421. {
  422. // The shadow-including root of an object is its root’s host’s shadow-including root,
  423. // if the object’s root is a shadow root; otherwise its root.
  424. auto& node_root = root();
  425. if (is<ShadowRoot>(node_root)) {
  426. if (auto* host = static_cast<ShadowRoot&>(node_root).host(); host)
  427. return host->shadow_including_root();
  428. }
  429. return node_root;
  430. }
  431. // https://dom.spec.whatwg.org/#connected
  432. bool Node::is_connected() const
  433. {
  434. // An element is connected if its shadow-including root is a document.
  435. return shadow_including_root().is_document();
  436. }
  437. // https://html.spec.whatwg.org/multipage/infrastructure.html#browsing-context-connected
  438. bool Node::is_browsing_context_connected() const
  439. {
  440. // A node is browsing-context connected when it is connected and its shadow-including root's browsing context is non-null.
  441. return is_connected() && shadow_including_root().document().browsing_context();
  442. }
  443. // https://dom.spec.whatwg.org/#concept-node-ensure-pre-insertion-validity
  444. WebIDL::ExceptionOr<void> Node::ensure_pre_insertion_validity(GC::Ref<Node> node, GC::Ptr<Node> child) const
  445. {
  446. // 1. If parent is not a Document, DocumentFragment, or Element node, then throw a "HierarchyRequestError" DOMException.
  447. if (!is<Document>(this) && !is<DocumentFragment>(this) && !is<Element>(this))
  448. return WebIDL::HierarchyRequestError::create(realm(), "Can only insert into a document, document fragment or element"_string);
  449. // 2. If node is a host-including inclusive ancestor of parent, then throw a "HierarchyRequestError" DOMException.
  450. if (node->is_host_including_inclusive_ancestor_of(*this))
  451. return WebIDL::HierarchyRequestError::create(realm(), "New node is an ancestor of this node"_string);
  452. // 3. If child is non-null and its parent is not parent, then throw a "NotFoundError" DOMException.
  453. if (child && child->parent() != this)
  454. return WebIDL::NotFoundError::create(realm(), "This node is not the parent of the given child"_string);
  455. // FIXME: All the following "Invalid node type for insertion" messages could be more descriptive.
  456. // 4. If node is not a DocumentFragment, DocumentType, Element, or CharacterData node, then throw a "HierarchyRequestError" DOMException.
  457. if (!is<DocumentFragment>(*node) && !is<DocumentType>(*node) && !is<Element>(*node) && !is<Text>(*node) && !is<Comment>(*node) && !is<ProcessingInstruction>(*node) && !is<CDATASection>(*node))
  458. return WebIDL::HierarchyRequestError::create(realm(), "Invalid node type for insertion"_string);
  459. // 5. If either node is a Text node and parent is a document, or node is a doctype and parent is not a document, then throw a "HierarchyRequestError" DOMException.
  460. if ((is<Text>(*node) && is<Document>(this)) || (is<DocumentType>(*node) && !is<Document>(this)))
  461. return WebIDL::HierarchyRequestError::create(realm(), "Invalid node type for insertion"_string);
  462. // 6. If parent is a document, and any of the statements below, switched on the interface node implements, are true, then throw a "HierarchyRequestError" DOMException.
  463. if (is<Document>(this)) {
  464. // DocumentFragment
  465. if (is<DocumentFragment>(*node)) {
  466. // If node has more than one element child or has a Text node child.
  467. // Otherwise, if node has one element child and either parent has an element child, child is a doctype, or child is non-null and a doctype is following child.
  468. auto node_element_child_count = verify_cast<DocumentFragment>(*node).child_element_count();
  469. if ((node_element_child_count > 1 || node->has_child_of_type<Text>())
  470. || (node_element_child_count == 1 && (has_child_of_type<Element>() || is<DocumentType>(child.ptr()) || (child && child->has_following_node_of_type_in_tree_order<DocumentType>())))) {
  471. return WebIDL::HierarchyRequestError::create(realm(), "Invalid node type for insertion"_string);
  472. }
  473. } else if (is<Element>(*node)) {
  474. // Element
  475. // If parent has an element child, child is a doctype, or child is non-null and a doctype is following child.
  476. if (has_child_of_type<Element>() || is<DocumentType>(child.ptr()) || (child && child->has_following_node_of_type_in_tree_order<DocumentType>()))
  477. return WebIDL::HierarchyRequestError::create(realm(), "Invalid node type for insertion"_string);
  478. } else if (is<DocumentType>(*node)) {
  479. // DocumentType
  480. // parent has a doctype child, child is non-null and an element is preceding child, or child is null and parent has an element child.
  481. if (has_child_of_type<DocumentType>() || (child && child->has_preceding_node_of_type_in_tree_order<Element>()) || (!child && has_child_of_type<Element>()))
  482. return WebIDL::HierarchyRequestError::create(realm(), "Invalid node type for insertion"_string);
  483. }
  484. }
  485. return {};
  486. }
  487. // https://dom.spec.whatwg.org/#concept-node-insert
  488. void Node::insert_before(GC::Ref<Node> node, GC::Ptr<Node> child, bool suppress_observers)
  489. {
  490. // 1. Let nodes be node’s children, if node is a DocumentFragment node; otherwise « node ».
  491. Vector<GC::Root<Node>> nodes;
  492. if (is<DocumentFragment>(*node))
  493. nodes = node->children_as_vector();
  494. else
  495. nodes.append(GC::make_root(*node));
  496. // 2. Let count be nodes’s size.
  497. auto count = nodes.size();
  498. // 3. If count is 0, then return.
  499. if (count == 0)
  500. return;
  501. // 4. If node is a DocumentFragment node, then:
  502. if (is<DocumentFragment>(*node)) {
  503. // 1. Remove its children with the suppress observers flag set.
  504. node->remove_all_children(true);
  505. // 2. Queue a tree mutation record for node with « », nodes, null, and null.
  506. // NOTE: This step intentionally does not pay attention to the suppress observers flag.
  507. node->queue_tree_mutation_record({}, nodes, nullptr, nullptr);
  508. }
  509. // 5. If child is non-null, then:
  510. if (child) {
  511. // 1. For each live range whose start node is parent and start offset is greater than child’s index, increase its start offset by count.
  512. for (auto& range : Range::live_ranges()) {
  513. if (range->start_container() == this && range->start_offset() > child->index())
  514. range->increase_start_offset({}, count);
  515. }
  516. // 2. For each live range whose end node is parent and end offset is greater than child’s index, increase its end offset by count.
  517. for (auto& range : Range::live_ranges()) {
  518. if (range->end_container() == this && range->end_offset() > child->index())
  519. range->increase_end_offset({}, count);
  520. }
  521. }
  522. // 6. Let previousSibling be child’s previous sibling or parent’s last child if child is null.
  523. GC::Ptr<Node> previous_sibling;
  524. if (child)
  525. previous_sibling = child->previous_sibling();
  526. else
  527. previous_sibling = last_child();
  528. // 7. For each node in nodes, in tree order:
  529. // FIXME: In tree order
  530. for (auto& node_to_insert : nodes) {
  531. // 1. Adopt node into parent’s node document.
  532. document().adopt_node(*node_to_insert);
  533. // 2. If child is null, then append node to parent’s children.
  534. if (!child)
  535. append_child_impl(*node_to_insert);
  536. // 3. Otherwise, insert node into parent’s children before child’s index.
  537. else
  538. insert_before_impl(*node_to_insert, child);
  539. // 4. If parent is a shadow host whose shadow root’s slot assignment is "named" and node is a slottable, then
  540. // assign a slot for node.
  541. if (is_element()) {
  542. auto& element = static_cast<DOM::Element&>(*this);
  543. auto is_named_shadow_host = element.is_shadow_host()
  544. && element.shadow_root()->slot_assignment() == Bindings::SlotAssignmentMode::Named;
  545. if (is_named_shadow_host && node_to_insert->is_slottable())
  546. assign_a_slot(node_to_insert->as_slottable());
  547. }
  548. // 5. If parent’s root is a shadow root, and parent is a slot whose assigned nodes is the empty list, then run
  549. // signal a slot change for parent.
  550. if (root().is_shadow_root() && is<HTML::HTMLSlotElement>(*this)) {
  551. auto& slot = static_cast<HTML::HTMLSlotElement&>(*this);
  552. if (slot.assigned_nodes_internal().is_empty())
  553. signal_a_slot_change(slot);
  554. }
  555. // 6. Run assign slottables for a tree with node’s root.
  556. assign_slottables_for_a_tree(node_to_insert->root());
  557. node_to_insert->invalidate_style(StyleInvalidationReason::NodeInsertBefore);
  558. // 7. For each shadow-including inclusive descendant inclusiveDescendant of node, in shadow-including tree order:
  559. node_to_insert->for_each_shadow_including_inclusive_descendant([&](Node& inclusive_descendant) {
  560. // 1. Run the insertion steps with inclusiveDescendant.
  561. inclusive_descendant.inserted();
  562. // 2. If inclusiveDescendant is connected, then:
  563. // NOTE: This is not specified here in the spec, but these steps can only be performed on an element.
  564. if (inclusive_descendant.is_connected() && is<DOM::Element>(inclusive_descendant)) {
  565. auto& element = static_cast<DOM::Element&>(inclusive_descendant);
  566. // 1. If inclusiveDescendant is custom, then enqueue a custom element callback reaction with inclusiveDescendant,
  567. // callback name "connectedCallback", and an empty argument list.
  568. if (element.is_custom()) {
  569. GC::RootVector<JS::Value> empty_arguments { vm().heap() };
  570. element.enqueue_a_custom_element_callback_reaction(HTML::CustomElementReactionNames::connectedCallback, move(empty_arguments));
  571. }
  572. // 2. Otherwise, try to upgrade inclusiveDescendant.
  573. // NOTE: If this successfully upgrades inclusiveDescendant, its connectedCallback will be enqueued automatically during
  574. // the upgrade an element algorithm.
  575. else {
  576. element.try_to_upgrade();
  577. }
  578. }
  579. return TraversalDecision::Continue;
  580. });
  581. }
  582. // 8. If suppress observers flag is unset, then queue a tree mutation record for parent with nodes, « », previousSibling, and child.
  583. if (!suppress_observers) {
  584. queue_tree_mutation_record(nodes, {}, previous_sibling.ptr(), child.ptr());
  585. }
  586. // 9. Run the children changed steps for parent.
  587. children_changed();
  588. // 10. Let staticNodeList be a list of nodes, initially « ».
  589. // Spec-Note: We collect all nodes before calling the post-connection steps on any one of them, instead of calling
  590. // the post-connection steps while we’re traversing the node tree. This is because the post-connection
  591. // steps can modify the tree’s structure, making live traversal unsafe, possibly leading to the
  592. // post-connection steps being called multiple times on the same node.
  593. GC::RootVector<GC::Ref<Node>> static_node_list(heap());
  594. // 11. For each node of nodes, in tree order:
  595. for (auto& node : nodes) {
  596. // 1. For each shadow-including inclusive descendant inclusiveDescendant of node, in shadow-including tree
  597. // order, append inclusiveDescendant to staticNodeList.
  598. node->for_each_shadow_including_inclusive_descendant([&static_node_list](Node& inclusive_descendant) {
  599. static_node_list.append(inclusive_descendant);
  600. return TraversalDecision::Continue;
  601. });
  602. }
  603. // 12. For each node of staticNodeList, if node is connected, then run the post-connection steps with node.
  604. for (auto& node : static_node_list) {
  605. if (node->is_connected())
  606. node->post_connection();
  607. }
  608. if (is_connected()) {
  609. // FIXME: This will need to become smarter when we implement the :has() selector.
  610. invalidate_style(StyleInvalidationReason::ParentOfInsertedNode);
  611. document().invalidate_layout_tree();
  612. }
  613. document().bump_dom_tree_version();
  614. }
  615. // https://dom.spec.whatwg.org/#concept-node-pre-insert
  616. WebIDL::ExceptionOr<GC::Ref<Node>> Node::pre_insert(GC::Ref<Node> node, GC::Ptr<Node> child)
  617. {
  618. // 1. Ensure pre-insertion validity of node into parent before child.
  619. TRY(ensure_pre_insertion_validity(node, child));
  620. // 2. Let referenceChild be child.
  621. auto reference_child = child;
  622. // 3. If referenceChild is node, then set referenceChild to node’s next sibling.
  623. if (reference_child == node)
  624. reference_child = node->next_sibling();
  625. // 4. Insert node into parent before referenceChild.
  626. insert_before(node, reference_child);
  627. // 5. Return node.
  628. return node;
  629. }
  630. // https://dom.spec.whatwg.org/#dom-node-removechild
  631. WebIDL::ExceptionOr<GC::Ref<Node>> Node::remove_child(GC::Ref<Node> child)
  632. {
  633. // The removeChild(child) method steps are to return the result of pre-removing child from this.
  634. return pre_remove(child);
  635. }
  636. // https://dom.spec.whatwg.org/#concept-node-pre-remove
  637. WebIDL::ExceptionOr<GC::Ref<Node>> Node::pre_remove(GC::Ref<Node> child)
  638. {
  639. // 1. If child’s parent is not parent, then throw a "NotFoundError" DOMException.
  640. if (child->parent() != this)
  641. return WebIDL::NotFoundError::create(realm(), "Child does not belong to this node"_string);
  642. // 2. Remove child.
  643. child->remove();
  644. // 3. Return child.
  645. return child;
  646. }
  647. // https://dom.spec.whatwg.org/#concept-node-append
  648. WebIDL::ExceptionOr<GC::Ref<Node>> Node::append_child(GC::Ref<Node> node)
  649. {
  650. // To append a node to a parent, pre-insert node into parent before null.
  651. return pre_insert(node, nullptr);
  652. }
  653. // https://dom.spec.whatwg.org/#concept-node-remove
  654. void Node::remove(bool suppress_observers)
  655. {
  656. // 1. Let parent be node’s parent
  657. auto* parent = this->parent();
  658. // 2. Assert: parent is non-null.
  659. VERIFY(parent);
  660. // 3. Let index be node’s index.
  661. auto index = this->index();
  662. // 4. For each live range whose start node is an inclusive descendant of node, set its start to (parent, index).
  663. for (auto& range : Range::live_ranges()) {
  664. if (range->start_container()->is_inclusive_descendant_of(*this))
  665. MUST(range->set_start(*parent, index));
  666. }
  667. // 5. For each live range whose end node is an inclusive descendant of node, set its end to (parent, index).
  668. for (auto& range : Range::live_ranges()) {
  669. if (range->end_container()->is_inclusive_descendant_of(*this))
  670. MUST(range->set_end(*parent, index));
  671. }
  672. // 6. For each live range whose start node is parent and start offset is greater than index, decrease its start offset by 1.
  673. for (auto& range : Range::live_ranges()) {
  674. if (range->start_container() == parent && range->start_offset() > index)
  675. range->decrease_start_offset({}, 1);
  676. }
  677. // 7. For each live range whose end node is parent and end offset is greater than index, decrease its end offset by 1.
  678. for (auto& range : Range::live_ranges()) {
  679. if (range->end_container() == parent && range->end_offset() > index)
  680. range->decrease_end_offset({}, 1);
  681. }
  682. // 8. For each NodeIterator object iterator whose root’s node document is node’s node document, run the NodeIterator pre-removing steps given node and iterator.
  683. document().for_each_node_iterator([&](NodeIterator& node_iterator) {
  684. node_iterator.run_pre_removing_steps(*this);
  685. });
  686. // 9. Let oldPreviousSibling be node’s previous sibling.
  687. GC::Ptr<Node> old_previous_sibling = previous_sibling();
  688. // 10. Let oldNextSibling be node’s next sibling.
  689. GC::Ptr<Node> old_next_sibling = next_sibling();
  690. if (is_connected()) {
  691. // Since the tree structure is about to change, we need to invalidate both style and layout.
  692. // In the future, we should find a way to only invalidate the parts that actually need it.
  693. invalidate_style(StyleInvalidationReason::NodeRemove);
  694. // NOTE: If we didn't have a layout node before, rebuilding the layout tree isn't gonna give us one
  695. // after we've been removed from the DOM.
  696. if (layout_node()) {
  697. document().invalidate_layout_tree();
  698. }
  699. }
  700. // 11. Remove node from its parent’s children.
  701. parent->remove_child_impl(*this);
  702. // 12. If node is assigned, then run assign slottables for node’s assigned slot.
  703. if (auto assigned_slot = assigned_slot_for_node(*this))
  704. assign_slottables(*assigned_slot);
  705. // 13. If parent’s root is a shadow root, and parent is a slot whose assigned nodes is the empty list, then run
  706. // signal a slot change for parent.
  707. if (parent->root().is_shadow_root() && is<HTML::HTMLSlotElement>(parent)) {
  708. auto& slot = static_cast<HTML::HTMLSlotElement&>(*parent);
  709. if (slot.assigned_nodes_internal().is_empty())
  710. signal_a_slot_change(slot);
  711. }
  712. // 14. If node has an inclusive descendant that is a slot, then:
  713. auto has_descendent_slot = false;
  714. for_each_in_inclusive_subtree_of_type<HTML::HTMLSlotElement>([&](auto const&) {
  715. has_descendent_slot = true;
  716. return TraversalDecision::Break;
  717. });
  718. if (has_descendent_slot) {
  719. // 1. Run assign slottables for a tree with parent’s root.
  720. assign_slottables_for_a_tree(parent->root());
  721. // 2. Run assign slottables for a tree with node.
  722. assign_slottables_for_a_tree(*this);
  723. }
  724. // 15. Run the removing steps with node and parent.
  725. removed_from(parent);
  726. // 16. Let isParentConnected be parent’s connected.
  727. bool is_parent_connected = parent->is_connected();
  728. // 17. If node is custom and isParentConnected is true, then enqueue a custom element callback reaction with node,
  729. // callback name "disconnectedCallback", and an empty argument list.
  730. // Spec Note: It is intentional for now that custom elements do not get parent passed.
  731. // This might change in the future if there is a need.
  732. if (is<DOM::Element>(*this)) {
  733. auto& element = static_cast<DOM::Element&>(*this);
  734. if (element.is_custom() && is_parent_connected) {
  735. GC::RootVector<JS::Value> empty_arguments { vm().heap() };
  736. element.enqueue_a_custom_element_callback_reaction(HTML::CustomElementReactionNames::disconnectedCallback, move(empty_arguments));
  737. }
  738. }
  739. // 18. For each shadow-including descendant descendant of node, in shadow-including tree order, then:
  740. for_each_shadow_including_descendant([&](Node& descendant) {
  741. // 1. Run the removing steps with descendant
  742. descendant.removed_from(nullptr);
  743. // 2. If descendant is custom and isParentConnected is true, then enqueue a custom element callback reaction with descendant,
  744. // callback name "disconnectedCallback", and an empty argument list.
  745. if (is<DOM::Element>(descendant)) {
  746. auto& element = static_cast<DOM::Element&>(descendant);
  747. if (element.is_custom() && is_parent_connected) {
  748. GC::RootVector<JS::Value> empty_arguments { vm().heap() };
  749. element.enqueue_a_custom_element_callback_reaction(HTML::CustomElementReactionNames::disconnectedCallback, move(empty_arguments));
  750. }
  751. }
  752. return TraversalDecision::Continue;
  753. });
  754. // 19. For each inclusive ancestor inclusiveAncestor of parent, and then for each registered of inclusiveAncestor’s registered observer list,
  755. // if registered’s options["subtree"] is true, then append a new transient registered observer
  756. // whose observer is registered’s observer, options is registered’s options, and source is registered to node’s registered observer list.
  757. for (auto* inclusive_ancestor = parent; inclusive_ancestor; inclusive_ancestor = inclusive_ancestor->parent()) {
  758. if (!inclusive_ancestor->m_registered_observer_list)
  759. continue;
  760. for (auto& registered : *inclusive_ancestor->m_registered_observer_list) {
  761. if (registered->options().subtree) {
  762. auto transient_observer = TransientRegisteredObserver::create(registered->observer(), registered->options(), registered);
  763. add_registered_observer(move(transient_observer));
  764. }
  765. }
  766. }
  767. // 20. If suppress observers flag is unset, then queue a tree mutation record for parent with « », « node », oldPreviousSibling, and oldNextSibling.
  768. if (!suppress_observers) {
  769. parent->queue_tree_mutation_record({}, { *this }, old_previous_sibling.ptr(), old_next_sibling.ptr());
  770. }
  771. // 21. Run the children changed steps for parent.
  772. parent->children_changed();
  773. document().bump_dom_tree_version();
  774. }
  775. // https://dom.spec.whatwg.org/#concept-node-replace
  776. WebIDL::ExceptionOr<GC::Ref<Node>> Node::replace_child(GC::Ref<Node> node, GC::Ref<Node> child)
  777. {
  778. // If parent is not a Document, DocumentFragment, or Element node, then throw a "HierarchyRequestError" DOMException.
  779. if (!is<Document>(this) && !is<DocumentFragment>(this) && !is<Element>(this))
  780. return WebIDL::HierarchyRequestError::create(realm(), "Can only insert into a document, document fragment or element"_string);
  781. // 2. If node is a host-including inclusive ancestor of parent, then throw a "HierarchyRequestError" DOMException.
  782. if (node->is_host_including_inclusive_ancestor_of(*this))
  783. return WebIDL::HierarchyRequestError::create(realm(), "New node is an ancestor of this node"_string);
  784. // 3. If child’s parent is not parent, then throw a "NotFoundError" DOMException.
  785. if (child->parent() != this)
  786. return WebIDL::NotFoundError::create(realm(), "This node is not the parent of the given child"_string);
  787. // FIXME: All the following "Invalid node type for insertion" messages could be more descriptive.
  788. // 4. If node is not a DocumentFragment, DocumentType, Element, or CharacterData node, then throw a "HierarchyRequestError" DOMException.
  789. if (!is<DocumentFragment>(*node) && !is<DocumentType>(*node) && !is<Element>(*node) && !is<Text>(*node) && !is<Comment>(*node) && !is<ProcessingInstruction>(*node))
  790. return WebIDL::HierarchyRequestError::create(realm(), "Invalid node type for insertion"_string);
  791. // 5. If either node is a Text node and parent is a document, or node is a doctype and parent is not a document, then throw a "HierarchyRequestError" DOMException.
  792. if ((is<Text>(*node) && is<Document>(this)) || (is<DocumentType>(*node) && !is<Document>(this)))
  793. return WebIDL::HierarchyRequestError::create(realm(), "Invalid node type for insertion"_string);
  794. // If parent is a document, and any of the statements below, switched on the interface node implements, are true, then throw a "HierarchyRequestError" DOMException.
  795. if (is<Document>(this)) {
  796. // DocumentFragment
  797. if (is<DocumentFragment>(*node)) {
  798. // If node has more than one element child or has a Text node child.
  799. // Otherwise, if node has one element child and either parent has an element child that is not child or a doctype is following child.
  800. auto node_element_child_count = verify_cast<DocumentFragment>(*node).child_element_count();
  801. if ((node_element_child_count > 1 || node->has_child_of_type<Text>())
  802. || (node_element_child_count == 1 && (first_child_of_type<Element>() != child || child->has_following_node_of_type_in_tree_order<DocumentType>()))) {
  803. return WebIDL::HierarchyRequestError::create(realm(), "Invalid node type for insertion"_string);
  804. }
  805. } else if (is<Element>(*node)) {
  806. // Element
  807. // parent has an element child that is not child or a doctype is following child.
  808. if (first_child_of_type<Element>() != child || child->has_following_node_of_type_in_tree_order<DocumentType>())
  809. return WebIDL::HierarchyRequestError::create(realm(), "Invalid node type for insertion"_string);
  810. } else if (is<DocumentType>(*node)) {
  811. // DocumentType
  812. // parent has a doctype child that is not child, or an element is preceding child.
  813. if (first_child_of_type<DocumentType>() != child || child->has_preceding_node_of_type_in_tree_order<Element>())
  814. return WebIDL::HierarchyRequestError::create(realm(), "Invalid node type for insertion"_string);
  815. }
  816. }
  817. // 7. Let referenceChild be child’s next sibling.
  818. GC::Ptr<Node> reference_child = child->next_sibling();
  819. // 8. If referenceChild is node, then set referenceChild to node’s next sibling.
  820. if (reference_child == node)
  821. reference_child = node->next_sibling();
  822. // 9. Let previousSibling be child’s previous sibling.
  823. GC::Ptr<Node> previous_sibling = child->previous_sibling();
  824. // 10. Let removedNodes be the empty set.
  825. Vector<GC::Root<Node>> removed_nodes;
  826. // 11. If child’s parent is non-null, then:
  827. // NOTE: The above can only be false if child is node.
  828. if (child->parent()) {
  829. // 1. Set removedNodes to « child ».
  830. removed_nodes.append(GC::make_root(*child));
  831. // 2. Remove child with the suppress observers flag set.
  832. child->remove(true);
  833. }
  834. // 12. Let nodes be node’s children if node is a DocumentFragment node; otherwise « node ».
  835. Vector<GC::Root<Node>> nodes;
  836. if (is<DocumentFragment>(*node))
  837. nodes = node->children_as_vector();
  838. else
  839. nodes.append(GC::make_root(*node));
  840. // AD-HOC: Since removing the child may have executed arbitrary code, we have to verify
  841. // the sanity of inserting `node` before `reference_child` again, as well as
  842. // `child` not being reinserted elsewhere.
  843. if (!reference_child || (reference_child->parent() == this && !child->parent_node())) {
  844. // 13. Insert node into parent before referenceChild with the suppress observers flag set.
  845. insert_before(node, reference_child, true);
  846. }
  847. // 14. Queue a tree mutation record for parent with nodes, removedNodes, previousSibling, and referenceChild.
  848. queue_tree_mutation_record(move(nodes), move(removed_nodes), previous_sibling.ptr(), reference_child.ptr());
  849. // 15. Return child.
  850. return child;
  851. }
  852. // https://dom.spec.whatwg.org/#concept-node-clone
  853. WebIDL::ExceptionOr<GC::Ref<Node>> Node::clone_node(Document* document, bool clone_children)
  854. {
  855. // 1. If document is not given, let document be node’s node document.
  856. if (!document)
  857. document = m_document.ptr();
  858. GC::Ptr<Node> copy;
  859. // 2. If node is an element, then:
  860. if (is<Element>(this)) {
  861. // 1. Let copy be the result of creating an element, given document, node’s local name, node’s namespace, node’s namespace prefix, and node’s is value, with the synchronous custom elements flag unset.
  862. auto& element = *verify_cast<Element>(this);
  863. auto element_copy = DOM::create_element(*document, element.local_name(), element.namespace_uri(), element.prefix(), element.is_value(), false).release_value_but_fixme_should_propagate_errors();
  864. // 2. For each attribute in node’s attribute list:
  865. element.for_each_attribute([&](auto& name, auto& value) {
  866. // 1. Let copyAttribute be a clone of attribute.
  867. // 2. Append copyAttribute to copy.
  868. element_copy->append_attribute(name, value);
  869. });
  870. copy = move(element_copy);
  871. }
  872. // 3. Otherwise, let copy be a node that implements the same interfaces as node, and fulfills these additional requirements, switching on the interface node implements:
  873. else if (is<Document>(this)) {
  874. // Document
  875. auto document_ = verify_cast<Document>(this);
  876. auto document_copy = [&] -> GC::Ref<Document> {
  877. switch (document_->document_type()) {
  878. case Document::Type::XML:
  879. return XMLDocument::create(realm(), document_->url());
  880. case Document::Type::HTML:
  881. return HTML::HTMLDocument::create(realm(), document_->url());
  882. default:
  883. return Document::create(realm(), document_->url());
  884. }
  885. }();
  886. // Set copy’s encoding, content type, URL, origin, type, and mode to those of node.
  887. document_copy->set_encoding(document_->encoding());
  888. document_copy->set_content_type(document_->content_type());
  889. document_copy->set_url(document_->url());
  890. document_copy->set_origin(document_->origin());
  891. document_copy->set_document_type(document_->document_type());
  892. document_copy->set_quirks_mode(document_->mode());
  893. copy = move(document_copy);
  894. } else if (is<DocumentType>(this)) {
  895. // DocumentType
  896. auto document_type = verify_cast<DocumentType>(this);
  897. auto document_type_copy = realm().create<DocumentType>(*document);
  898. // Set copy’s name, public ID, and system ID to those of node.
  899. document_type_copy->set_name(document_type->name());
  900. document_type_copy->set_public_id(document_type->public_id());
  901. document_type_copy->set_system_id(document_type->system_id());
  902. copy = move(document_type_copy);
  903. } else if (is<Attr>(this)) {
  904. // Attr
  905. // Set copy’s namespace, namespace prefix, local name, and value to those of node.
  906. auto& attr = static_cast<Attr&>(*this);
  907. copy = attr.clone(*document);
  908. } else if (is<Text>(this)) {
  909. // Text
  910. auto& text = static_cast<Text&>(*this);
  911. // Set copy’s data to that of node.
  912. copy = [&]() -> GC::Ref<Text> {
  913. switch (type()) {
  914. case NodeType::TEXT_NODE:
  915. return realm().create<Text>(*document, text.data());
  916. case NodeType::CDATA_SECTION_NODE:
  917. return realm().create<CDATASection>(*document, text.data());
  918. default:
  919. VERIFY_NOT_REACHED();
  920. }
  921. }();
  922. } else if (is<Comment>(this)) {
  923. // Comment
  924. auto comment = verify_cast<Comment>(this);
  925. // Set copy’s data to that of node.
  926. auto comment_copy = realm().create<Comment>(*document, comment->data());
  927. copy = move(comment_copy);
  928. } else if (is<ProcessingInstruction>(this)) {
  929. // ProcessingInstruction
  930. auto processing_instruction = verify_cast<ProcessingInstruction>(this);
  931. // Set copy’s target and data to those of node.
  932. auto processing_instruction_copy = realm().create<ProcessingInstruction>(*document, processing_instruction->data(), processing_instruction->target());
  933. copy = processing_instruction_copy;
  934. }
  935. // Otherwise, Do nothing.
  936. else if (is<DocumentFragment>(this)) {
  937. copy = realm().create<DocumentFragment>(*document);
  938. }
  939. // FIXME: 4. Set copy’s node document and document to copy, if copy is a document, and set copy’s node document to document otherwise.
  940. // 5. Run any cloning steps defined for node in other applicable specifications and pass copy, node, document and the clone children flag if set, as parameters.
  941. TRY(cloned(*copy, clone_children));
  942. // 6. If the clone children flag is set, clone all the children of node and append them to copy, with document as specified and the clone children flag being set.
  943. if (clone_children) {
  944. for (auto child = first_child(); child; child = child->next_sibling()) {
  945. TRY(copy->append_child(TRY(child->clone_node(document, true))));
  946. }
  947. }
  948. // 7. If node is a shadow host whose shadow root’s clonable is true:
  949. if (is_element() && static_cast<Element const&>(*this).is_shadow_host() && static_cast<Element const&>(*this).shadow_root()->clonable()) {
  950. // 1. Assert: copy is not a shadow host.
  951. VERIFY(!copy->is_element() || !static_cast<Element const&>(*copy).is_shadow_host());
  952. // 2. Run attach a shadow root with copy, node’s shadow root’s mode, true, node’s shadow root’s serializable,
  953. // node’s shadow root’s delegates focus, and node’s shadow root’s slot assignment.
  954. auto& node_shadow_root = *static_cast<Element&>(*this).shadow_root();
  955. TRY(static_cast<Element&>(*copy).attach_a_shadow_root(node_shadow_root.mode(), true, node_shadow_root.serializable(), node_shadow_root.delegates_focus(), node_shadow_root.slot_assignment()));
  956. // 3. Set copy’s shadow root’s declarative to node’s shadow root’s declarative.
  957. static_cast<Element&>(*copy).shadow_root()->set_declarative(node_shadow_root.declarative());
  958. // 4. For each child child of node’s shadow root, in tree order:
  959. // append the result of cloning child with document and the clone children flag set, to copy’s shadow root.
  960. for (auto child = node_shadow_root.first_child(); child; child = child->next_sibling()) {
  961. TRY(static_cast<Element&>(*copy).shadow_root()->append_child(TRY(child->clone_node(document, true))));
  962. }
  963. }
  964. // 7. Return copy.
  965. VERIFY(copy);
  966. return GC::Ref { *copy };
  967. }
  968. // https://dom.spec.whatwg.org/#dom-node-clonenode
  969. WebIDL::ExceptionOr<GC::Ref<Node>> Node::clone_node_binding(bool deep)
  970. {
  971. // 1. If this is a shadow root, then throw a "NotSupportedError" DOMException.
  972. if (is<ShadowRoot>(*this))
  973. return WebIDL::NotSupportedError::create(realm(), "Cannot clone shadow root"_string);
  974. // 2. Return a clone of this, with the clone children flag set if deep is true.
  975. return clone_node(nullptr, deep);
  976. }
  977. void Node::set_document(Badge<Document>, Document& document)
  978. {
  979. if (m_document.ptr() == &document)
  980. return;
  981. m_document = &document;
  982. if (needs_style_update() || child_needs_style_update()) {
  983. // NOTE: We unset and reset the "needs style update" flag here.
  984. // This ensures that there's a pending style update in the new document
  985. // that will eventually assign some style to this node if needed.
  986. set_needs_style_update(false);
  987. set_needs_style_update(true);
  988. }
  989. }
  990. // https://w3c.github.io/editing/docs/execCommand/#editable
  991. bool Node::is_editable() const
  992. {
  993. // Something is editable if it is a node; it is not an editing host;
  994. if (is_editing_host())
  995. return false;
  996. // it does not have a contenteditable attribute set to the false state;
  997. if (is<HTML::HTMLElement>(this) && static_cast<HTML::HTMLElement const&>(*this).content_editable_state() == HTML::ContentEditableState::False)
  998. return false;
  999. // its parent is an editing host or editable;
  1000. if (!parent() || !parent()->is_editable_or_editing_host())
  1001. return false;
  1002. // and either it is an HTML element,
  1003. if (is<HTML::HTMLElement>(this))
  1004. return true;
  1005. // or it is an svg or math element,
  1006. if (is<SVG::SVGElement>(this) || is<MathML::MathMLElement>(this))
  1007. return true;
  1008. // or it is not an Element and its parent is an HTML element.
  1009. return !is<Element>(this) && is<HTML::HTMLElement>(parent());
  1010. }
  1011. // https://html.spec.whatwg.org/multipage/interaction.html#editing-host
  1012. bool Node::is_editing_host() const
  1013. {
  1014. // NOTE: Both conditions below require this to be an HTML element.
  1015. if (!is<HTML::HTMLElement>(this))
  1016. return false;
  1017. // An editing host is either an HTML element with its contenteditable attribute in the true state or
  1018. // plaintext-only state,
  1019. auto state = static_cast<HTML::HTMLElement const&>(*this).content_editable_state();
  1020. if (state == HTML::ContentEditableState::True || state == HTML::ContentEditableState::PlaintextOnly)
  1021. return true;
  1022. // or a child HTML element of a Document whose design mode enabled is true.
  1023. return is<Document>(parent()) && static_cast<Document const&>(*parent()).design_mode_enabled_state();
  1024. }
  1025. void Node::set_layout_node(Badge<Layout::Node>, GC::Ref<Layout::Node> layout_node)
  1026. {
  1027. m_layout_node = layout_node;
  1028. }
  1029. void Node::detach_layout_node(Badge<Layout::TreeBuilder>)
  1030. {
  1031. m_layout_node = nullptr;
  1032. }
  1033. EventTarget* Node::get_parent(Event const&)
  1034. {
  1035. // A node’s get the parent algorithm, given an event, returns the node’s assigned slot, if node is assigned;
  1036. // otherwise node’s parent.
  1037. if (auto assigned_slot = assigned_slot_for_node(*this))
  1038. return assigned_slot.ptr();
  1039. return parent();
  1040. }
  1041. void Node::set_needs_inherited_style_update(bool value)
  1042. {
  1043. if (m_needs_inherited_style_update == value)
  1044. return;
  1045. m_needs_inherited_style_update = value;
  1046. if (m_needs_inherited_style_update) {
  1047. for (auto* ancestor = parent_or_shadow_host(); ancestor; ancestor = ancestor->parent_or_shadow_host()) {
  1048. if (ancestor->m_child_needs_style_update)
  1049. break;
  1050. ancestor->m_child_needs_style_update = true;
  1051. }
  1052. document().schedule_style_update();
  1053. }
  1054. }
  1055. void Node::set_needs_style_update(bool value)
  1056. {
  1057. if (m_needs_style_update == value)
  1058. return;
  1059. m_needs_style_update = value;
  1060. if (m_needs_style_update) {
  1061. for (auto* ancestor = parent_or_shadow_host(); ancestor; ancestor = ancestor->parent_or_shadow_host()) {
  1062. if (ancestor->m_child_needs_style_update)
  1063. break;
  1064. ancestor->m_child_needs_style_update = true;
  1065. }
  1066. document().schedule_style_update();
  1067. }
  1068. }
  1069. void Node::post_connection()
  1070. {
  1071. }
  1072. void Node::inserted()
  1073. {
  1074. set_needs_style_update(true);
  1075. }
  1076. void Node::removed_from(Node*)
  1077. {
  1078. m_layout_node = nullptr;
  1079. m_paintable = nullptr;
  1080. }
  1081. ParentNode* Node::parent_or_shadow_host()
  1082. {
  1083. if (is<ShadowRoot>(*this))
  1084. return static_cast<ShadowRoot&>(*this).host();
  1085. return verify_cast<ParentNode>(parent());
  1086. }
  1087. Element* Node::parent_or_shadow_host_element()
  1088. {
  1089. if (is<ShadowRoot>(*this))
  1090. return static_cast<ShadowRoot&>(*this).host();
  1091. if (!parent())
  1092. return nullptr;
  1093. if (is<Element>(*parent()))
  1094. return static_cast<Element*>(parent());
  1095. if (is<ShadowRoot>(*parent()))
  1096. return static_cast<ShadowRoot&>(*parent()).host();
  1097. return nullptr;
  1098. }
  1099. Slottable Node::as_slottable()
  1100. {
  1101. VERIFY(is_slottable());
  1102. if (is_element())
  1103. return GC::Ref { static_cast<Element&>(*this) };
  1104. return GC::Ref { static_cast<Text&>(*this) };
  1105. }
  1106. GC::Ref<NodeList> Node::child_nodes()
  1107. {
  1108. if (!m_child_nodes) {
  1109. m_child_nodes = LiveNodeList::create(realm(), *this, LiveNodeList::Scope::Children, [](auto&) {
  1110. return true;
  1111. });
  1112. }
  1113. return *m_child_nodes;
  1114. }
  1115. Vector<GC::Root<Node>> Node::children_as_vector() const
  1116. {
  1117. Vector<GC::Root<Node>> nodes;
  1118. for_each_child([&](auto& child) {
  1119. nodes.append(GC::make_root(child));
  1120. return IterationDecision::Continue;
  1121. });
  1122. return nodes;
  1123. }
  1124. void Node::remove_all_children(bool suppress_observers)
  1125. {
  1126. while (GC::Ptr<Node> child = first_child())
  1127. child->remove(suppress_observers);
  1128. }
  1129. // https://dom.spec.whatwg.org/#dom-node-comparedocumentposition
  1130. u16 Node::compare_document_position(GC::Ptr<Node> other)
  1131. {
  1132. // 1. If this is other, then return zero.
  1133. if (this == other.ptr())
  1134. return DOCUMENT_POSITION_EQUAL;
  1135. // 2. Let node1 be other and node2 be this.
  1136. Node* node1 = other.ptr();
  1137. Node* node2 = this;
  1138. // 3. Let attr1 and attr2 be null.
  1139. Attr* attr1 = nullptr;
  1140. Attr* attr2 = nullptr;
  1141. // 4. If node1 is an attribute, then set attr1 to node1 and node1 to attr1’s element.
  1142. if (is<Attr>(node1)) {
  1143. attr1 = verify_cast<Attr>(node1);
  1144. node1 = const_cast<Element*>(attr1->owner_element());
  1145. }
  1146. // 5. If node2 is an attribute, then:
  1147. if (is<Attr>(node2)) {
  1148. // 1. Set attr2 to node2 and node2 to attr2’s element.
  1149. attr2 = verify_cast<Attr>(node2);
  1150. node2 = const_cast<Element*>(attr2->owner_element());
  1151. // 2. If attr1 and node1 are non-null, and node2 is node1, then:
  1152. if (attr1 && node1 && node2 == node1) {
  1153. // FIXME: 1. For each attr in node2’s attribute list:
  1154. // 1. If attr equals attr1, then return the result of adding DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC and DOCUMENT_POSITION_PRECEDING.
  1155. // 2. If attr equals attr2, then return the result of adding DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC and DOCUMENT_POSITION_FOLLOWING.
  1156. }
  1157. }
  1158. // 6. If node1 or node2 is null, or node1’s root is not node2’s root, then return the result of adding
  1159. // DOCUMENT_POSITION_DISCONNECTED, DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC, and either DOCUMENT_POSITION_PRECEDING or DOCUMENT_POSITION_FOLLOWING, with the constraint that this is to be consistent, together.
  1160. if ((node1 == nullptr || node2 == nullptr) || (&node1->root() != &node2->root()))
  1161. return DOCUMENT_POSITION_DISCONNECTED | DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC | (node1 > node2 ? DOCUMENT_POSITION_PRECEDING : DOCUMENT_POSITION_FOLLOWING);
  1162. Vector<Node*> node1_ancestors;
  1163. for (auto* node = node1; node; node = node->parent())
  1164. node1_ancestors.append(node);
  1165. Vector<Node*> node2_ancestors;
  1166. for (auto* node = node2; node; node = node->parent())
  1167. node2_ancestors.append(node);
  1168. auto it_node1_ancestors = node1_ancestors.rbegin();
  1169. auto it_node2_ancestors = node2_ancestors.rbegin();
  1170. // Walk ancestor chains of both nodes starting from root
  1171. while (it_node1_ancestors != node1_ancestors.rend() && it_node2_ancestors != node2_ancestors.rend()) {
  1172. auto* ancestor1 = *it_node1_ancestors;
  1173. auto* ancestor2 = *it_node2_ancestors;
  1174. // If ancestors of nodes at the same level in the tree are different then preceding node is the one with lower sibling position
  1175. if (ancestor1 != ancestor2) {
  1176. auto* node = ancestor1;
  1177. while (node) {
  1178. if (node == ancestor2)
  1179. return DOCUMENT_POSITION_PRECEDING;
  1180. node = node->next_sibling();
  1181. }
  1182. return DOCUMENT_POSITION_FOLLOWING;
  1183. }
  1184. it_node1_ancestors++;
  1185. it_node2_ancestors++;
  1186. }
  1187. // NOTE: If nodes in ancestors chains are the same but one chain is longer, then one node is ancestor of another.
  1188. // The node with shorter ancestors chain is the ancestor.
  1189. // The node with longer ancestors chain is the descendant.
  1190. // 7. If node1 is an ancestor of node2 and attr1 is null, or node1 is node2 and attr2 is non-null, then return the result of adding DOCUMENT_POSITION_CONTAINS to DOCUMENT_POSITION_PRECEDING.
  1191. if ((node1_ancestors.size() < node2_ancestors.size() && !attr1) || (node1 == node2 && attr2))
  1192. return DOCUMENT_POSITION_CONTAINS | DOCUMENT_POSITION_PRECEDING;
  1193. // 8. If node1 is a descendant of node2 and attr2 is null, or node1 is node2 and attr1 is non-null, then return the result of adding DOCUMENT_POSITION_CONTAINED_BY to DOCUMENT_POSITION_FOLLOWING.
  1194. if ((node1_ancestors.size() > node2_ancestors.size() && !attr2) || (node1 == node2 && attr1))
  1195. return DOCUMENT_POSITION_CONTAINED_BY | DOCUMENT_POSITION_FOLLOWING;
  1196. // 9. If node1 is preceding node2, then return DOCUMENT_POSITION_PRECEDING.
  1197. if (node1_ancestors.size() < node2_ancestors.size())
  1198. return DOCUMENT_POSITION_PRECEDING;
  1199. // 10. Return DOCUMENT_POSITION_FOLLOWING.
  1200. return DOCUMENT_POSITION_FOLLOWING;
  1201. }
  1202. // https://dom.spec.whatwg.org/#concept-tree-host-including-inclusive-ancestor
  1203. bool Node::is_host_including_inclusive_ancestor_of(Node const& other) const
  1204. {
  1205. // An object A is a host-including inclusive ancestor of an object B,
  1206. // if either A is an inclusive ancestor of B,
  1207. if (is_inclusive_ancestor_of(other))
  1208. return true;
  1209. // or if B’s root has a non-null host and A is a host-including inclusive ancestor of B’s root’s host
  1210. if (is<DocumentFragment>(other.root())
  1211. && static_cast<DocumentFragment const&>(other.root()).host()
  1212. && is_inclusive_ancestor_of(*static_cast<DocumentFragment const&>(other.root()).host())) {
  1213. return true;
  1214. }
  1215. return false;
  1216. }
  1217. // https://dom.spec.whatwg.org/#dom-node-ownerdocument
  1218. GC::Ptr<Document> Node::owner_document() const
  1219. {
  1220. // The ownerDocument getter steps are to return null, if this is a document; otherwise this’s node document.
  1221. if (is_document())
  1222. return nullptr;
  1223. return m_document;
  1224. }
  1225. // This function tells us whether a node is interesting enough to show up
  1226. // in the DOM inspector. This hides two things:
  1227. // - Non-rendered whitespace
  1228. // - Rendered whitespace between block-level elements
  1229. bool Node::is_uninteresting_whitespace_node() const
  1230. {
  1231. if (!is<Text>(*this))
  1232. return false;
  1233. if (!static_cast<Text const&>(*this).data().bytes_as_string_view().is_whitespace())
  1234. return false;
  1235. if (!layout_node())
  1236. return true;
  1237. if (auto parent = layout_node()->parent(); parent && parent->is_anonymous())
  1238. return true;
  1239. return false;
  1240. }
  1241. void Node::serialize_tree_as_json(JsonObjectSerializer<StringBuilder>& object) const
  1242. {
  1243. MUST(object.add("name"sv, node_name()));
  1244. MUST(object.add("id"sv, unique_id().value()));
  1245. if (is_document()) {
  1246. MUST(object.add("type"sv, "document"));
  1247. } else if (is_element()) {
  1248. MUST(object.add("type"sv, "element"));
  1249. auto const* element = static_cast<DOM::Element const*>(this);
  1250. if (element->has_attributes()) {
  1251. auto attributes = MUST(object.add_object("attributes"sv));
  1252. element->for_each_attribute([&attributes](auto& name, auto& value) {
  1253. MUST(attributes.add(name, value));
  1254. });
  1255. MUST(attributes.finish());
  1256. }
  1257. if (element->is_navigable_container()) {
  1258. auto const* container = static_cast<HTML::NavigableContainer const*>(element);
  1259. if (auto const* content_document = container->content_document()) {
  1260. auto children = MUST(object.add_array("children"sv));
  1261. JsonObjectSerializer<StringBuilder> content_document_object = MUST(children.add_object());
  1262. content_document->serialize_tree_as_json(content_document_object);
  1263. MUST(content_document_object.finish());
  1264. MUST(children.finish());
  1265. }
  1266. }
  1267. if (paintable_box()) {
  1268. if (paintable_box()->is_scrollable()) {
  1269. MUST(object.add("scrollable"sv, true));
  1270. }
  1271. if (!paintable_box()->is_visible()) {
  1272. MUST(object.add("invisible"sv, true));
  1273. }
  1274. if (paintable_box()->has_stacking_context()) {
  1275. MUST(object.add("stackingContext"sv, true));
  1276. }
  1277. }
  1278. } else if (is_text()) {
  1279. MUST(object.add("type"sv, "text"));
  1280. auto text_node = static_cast<DOM::Text const*>(this);
  1281. MUST(object.add("text"sv, text_node->data()));
  1282. } else if (is_comment()) {
  1283. MUST(object.add("type"sv, "comment"sv));
  1284. MUST(object.add("data"sv, static_cast<DOM::Comment const&>(*this).data()));
  1285. } else if (is_shadow_root()) {
  1286. MUST(object.add("type"sv, "shadow-root"));
  1287. MUST(object.add("mode"sv, static_cast<DOM::ShadowRoot const&>(*this).mode() == Bindings::ShadowRootMode::Open ? "open"sv : "closed"sv));
  1288. }
  1289. MUST((object.add("visible"sv, !!layout_node())));
  1290. auto const* element = is_element() ? static_cast<DOM::Element const*>(this) : nullptr;
  1291. if (has_child_nodes()
  1292. || (element && (element->is_shadow_host() || element->has_pseudo_elements()))) {
  1293. auto children = MUST(object.add_array("children"sv));
  1294. auto add_child = [&children](DOM::Node const& child) {
  1295. if (child.is_uninteresting_whitespace_node())
  1296. return IterationDecision::Continue;
  1297. JsonObjectSerializer<StringBuilder> child_object = MUST(children.add_object());
  1298. child.serialize_tree_as_json(child_object);
  1299. MUST(child_object.finish());
  1300. return IterationDecision::Continue;
  1301. };
  1302. for_each_child(add_child);
  1303. if (element) {
  1304. // Pseudo-elements don't have DOM nodes,so we have to add them separately.
  1305. element->serialize_pseudo_elements_as_json(children);
  1306. if (element->is_shadow_host())
  1307. add_child(*element->shadow_root());
  1308. }
  1309. MUST(children.finish());
  1310. }
  1311. }
  1312. // https://html.spec.whatwg.org/multipage/webappapis.html#concept-n-script
  1313. // https://whatpr.org/html/9893/webappapis.html#concept-n-script
  1314. bool Node::is_scripting_enabled() const
  1315. {
  1316. // Scripting is enabled for a node node if node's node document's browsing context is non-null, and scripting is enabled for node's relevant realm.
  1317. return document().browsing_context() && HTML::is_scripting_enabled(HTML::relevant_realm(*this));
  1318. }
  1319. // https://html.spec.whatwg.org/multipage/webappapis.html#concept-n-noscript
  1320. // https://whatpr.org/html/9893/webappapis.html#concept-n-script
  1321. bool Node::is_scripting_disabled() const
  1322. {
  1323. // Scripting is disabled for a node when scripting is not enabled, i.e., when its node document's browsing context is null or when scripting is disabled for its relevant realm.
  1324. return !is_scripting_enabled();
  1325. }
  1326. // https://dom.spec.whatwg.org/#dom-node-contains
  1327. bool Node::contains(GC::Ptr<Node> other) const
  1328. {
  1329. // The contains(other) method steps are to return true if other is an inclusive descendant of this; otherwise false (including when other is null).
  1330. return other && other->is_inclusive_descendant_of(*this);
  1331. }
  1332. // https://dom.spec.whatwg.org/#concept-shadow-including-descendant
  1333. bool Node::is_shadow_including_descendant_of(Node const& other) const
  1334. {
  1335. // An object A is a shadow-including descendant of an object B,
  1336. // if A is a descendant of B,
  1337. if (is_descendant_of(other))
  1338. return true;
  1339. // or A’s root is a shadow root
  1340. if (!is<ShadowRoot>(root()))
  1341. return false;
  1342. // and A’s root’s host is a shadow-including inclusive descendant of B.
  1343. auto& shadow_root = verify_cast<ShadowRoot>(root());
  1344. return shadow_root.host() && shadow_root.host()->is_shadow_including_inclusive_descendant_of(other);
  1345. }
  1346. // https://dom.spec.whatwg.org/#concept-shadow-including-inclusive-descendant
  1347. bool Node::is_shadow_including_inclusive_descendant_of(Node const& other) const
  1348. {
  1349. // A shadow-including inclusive descendant is an object or one of its shadow-including descendants.
  1350. return &other == this || is_shadow_including_descendant_of(other);
  1351. }
  1352. // https://dom.spec.whatwg.org/#concept-shadow-including-ancestor
  1353. bool Node::is_shadow_including_ancestor_of(Node const& other) const
  1354. {
  1355. // An object A is a shadow-including ancestor of an object B, if and only if B is a shadow-including descendant of A.
  1356. return other.is_shadow_including_descendant_of(*this);
  1357. }
  1358. // https://dom.spec.whatwg.org/#concept-shadow-including-inclusive-ancestor
  1359. bool Node::is_shadow_including_inclusive_ancestor_of(Node const& other) const
  1360. {
  1361. // A shadow-including inclusive ancestor is an object or one of its shadow-including ancestors.
  1362. return other.is_shadow_including_inclusive_descendant_of(*this);
  1363. }
  1364. // https://dom.spec.whatwg.org/#concept-node-replace-all
  1365. void Node::replace_all(GC::Ptr<Node> node)
  1366. {
  1367. // 1. Let removedNodes be parent’s children.
  1368. auto removed_nodes = children_as_vector();
  1369. // 2. Let addedNodes be the empty set.
  1370. Vector<GC::Root<Node>> added_nodes;
  1371. // 3. If node is a DocumentFragment node, then set addedNodes to node’s children.
  1372. if (node && is<DocumentFragment>(*node)) {
  1373. added_nodes = node->children_as_vector();
  1374. }
  1375. // 4. Otherwise, if node is non-null, set addedNodes to « node ».
  1376. else if (node) {
  1377. added_nodes.append(GC::make_root(*node));
  1378. }
  1379. // 5. Remove all parent’s children, in tree order, with the suppress observers flag set.
  1380. remove_all_children(true);
  1381. // 6. If node is non-null, then insert node into parent before null with the suppress observers flag set.
  1382. if (node)
  1383. insert_before(*node, nullptr, true);
  1384. // 7. If either addedNodes or removedNodes is not empty, then queue a tree mutation record for parent with addedNodes, removedNodes, null, and null.
  1385. if (!added_nodes.is_empty() || !removed_nodes.is_empty()) {
  1386. queue_tree_mutation_record(move(added_nodes), move(removed_nodes), nullptr, nullptr);
  1387. }
  1388. }
  1389. // https://dom.spec.whatwg.org/#string-replace-all
  1390. void Node::string_replace_all(String const& string)
  1391. {
  1392. // 1. Let node be null.
  1393. GC::Ptr<Node> node;
  1394. // 2. If string is not the empty string, then set node to a new Text node whose data is string and node document is parent’s node document.
  1395. if (!string.is_empty())
  1396. node = realm().create<Text>(document(), string);
  1397. // 3. Replace all with node within parent.
  1398. replace_all(node);
  1399. }
  1400. // https://html.spec.whatwg.org/multipage/dynamic-markup-insertion.html#fragment-serializing-algorithm-steps
  1401. WebIDL::ExceptionOr<String> Node::serialize_fragment(DOMParsing::RequireWellFormed require_well_formed, FragmentSerializationMode fragment_serialization_mode) const
  1402. {
  1403. // 1. Let context document be the value of node's node document.
  1404. auto const& context_document = document();
  1405. // 2. If context document is an HTML document, return the result of HTML fragment serialization algorithm with node, false, and « ».
  1406. if (context_document.is_html_document())
  1407. return HTML::HTMLParser::serialize_html_fragment(*this, HTML::HTMLParser::SerializableShadowRoots::No, {}, fragment_serialization_mode);
  1408. // 3. Return the XML serialization of node given require well-formed.
  1409. // AD-HOC: XML serialization algorithm returns the "outer" XML serialization of the node.
  1410. // For inner, concatenate the serialization of all children.
  1411. if (fragment_serialization_mode == FragmentSerializationMode::Inner) {
  1412. StringBuilder markup;
  1413. for (auto* child = first_child(); child; child = child->next_sibling()) {
  1414. auto child_markup = TRY(DOMParsing::serialize_node_to_xml_string(*child, require_well_formed));
  1415. markup.append(child_markup.bytes_as_string_view());
  1416. }
  1417. return MUST(markup.to_string());
  1418. }
  1419. return DOMParsing::serialize_node_to_xml_string(*this, require_well_formed);
  1420. }
  1421. // https://html.spec.whatwg.org/multipage/dynamic-markup-insertion.html#unsafely-set-html
  1422. WebIDL::ExceptionOr<void> Node::unsafely_set_html(Element& context_element, StringView html)
  1423. {
  1424. // 1. Let newChildren be the result of the HTML fragment parsing algorithm given contextElement, html, and true.
  1425. auto new_children = HTML::HTMLParser::parse_html_fragment(context_element, html, HTML::HTMLParser::AllowDeclarativeShadowRoots::Yes);
  1426. // 2. Let fragment be a new DocumentFragment whose node document is contextElement’s node document.
  1427. auto fragment = realm().create<DocumentFragment>(context_element.document());
  1428. // 3. For each node in newChildren, append node to fragment.
  1429. for (auto& child : new_children)
  1430. // I don't know if this can throw here, but let's be safe.
  1431. (void)TRY(fragment->append_child(*child));
  1432. // 4. Replace all with fragment within contextElement.
  1433. replace_all(fragment);
  1434. return {};
  1435. }
  1436. // https://dom.spec.whatwg.org/#dom-node-issamenode
  1437. bool Node::is_same_node(Node const* other_node) const
  1438. {
  1439. // The isSameNode(otherNode) method steps are to return true if otherNode is this; otherwise false.
  1440. return this == other_node;
  1441. }
  1442. // https://dom.spec.whatwg.org/#dom-node-isequalnode
  1443. bool Node::is_equal_node(Node const* other_node) const
  1444. {
  1445. // The isEqualNode(otherNode) method steps are to return true if otherNode is non-null and this equals otherNode; otherwise false.
  1446. if (!other_node)
  1447. return false;
  1448. // Fast path for testing a node against itself.
  1449. if (this == other_node)
  1450. return true;
  1451. // A node A equals a node B if all of the following conditions are true:
  1452. // A and B implement the same interfaces.
  1453. if (!node_name().equals_ignoring_ascii_case(other_node->node_name()))
  1454. return false;
  1455. // The following are equal, switching on the interface A implements:
  1456. switch (node_type()) {
  1457. case (u16)NodeType::DOCUMENT_TYPE_NODE: {
  1458. // Its name, public ID, and system ID.
  1459. auto& this_doctype = verify_cast<DocumentType>(*this);
  1460. auto& other_doctype = verify_cast<DocumentType>(*other_node);
  1461. if (this_doctype.name() != other_doctype.name()
  1462. || this_doctype.public_id() != other_doctype.public_id()
  1463. || this_doctype.system_id() != other_doctype.system_id())
  1464. return false;
  1465. break;
  1466. }
  1467. case (u16)NodeType::ELEMENT_NODE: {
  1468. // Its namespace, namespace prefix, local name, and its attribute list’s size.
  1469. auto& this_element = verify_cast<Element>(*this);
  1470. auto& other_element = verify_cast<Element>(*other_node);
  1471. if (this_element.namespace_uri() != other_element.namespace_uri()
  1472. || this_element.prefix() != other_element.prefix()
  1473. || this_element.local_name() != other_element.local_name()
  1474. || this_element.attribute_list_size() != other_element.attribute_list_size())
  1475. return false;
  1476. // If A is an element, each attribute in its attribute list has an attribute that equals an attribute in B’s attribute list.
  1477. bool has_same_attributes = true;
  1478. this_element.for_each_attribute([&](auto const& attribute) {
  1479. if (other_element.get_attribute_ns(attribute.namespace_uri(), attribute.local_name()) != attribute.value())
  1480. has_same_attributes = false;
  1481. });
  1482. if (!has_same_attributes)
  1483. return false;
  1484. break;
  1485. }
  1486. case (u16)NodeType::COMMENT_NODE:
  1487. case (u16)NodeType::TEXT_NODE: {
  1488. // Its data.
  1489. auto& this_cdata = verify_cast<CharacterData>(*this);
  1490. auto& other_cdata = verify_cast<CharacterData>(*other_node);
  1491. if (this_cdata.data() != other_cdata.data())
  1492. return false;
  1493. break;
  1494. }
  1495. case (u16)NodeType::ATTRIBUTE_NODE: {
  1496. // Its namespace, local name, and value.
  1497. auto& this_attr = verify_cast<Attr>(*this);
  1498. auto& other_attr = verify_cast<Attr>(*other_node);
  1499. if (this_attr.namespace_uri() != other_attr.namespace_uri())
  1500. return false;
  1501. if (this_attr.local_name() != other_attr.local_name())
  1502. return false;
  1503. if (this_attr.value() != other_attr.value())
  1504. return false;
  1505. break;
  1506. }
  1507. case (u16)NodeType::PROCESSING_INSTRUCTION_NODE: {
  1508. // Its target and data.
  1509. auto& this_processing_instruction = verify_cast<ProcessingInstruction>(*this);
  1510. auto& other_processing_instruction = verify_cast<ProcessingInstruction>(*other_node);
  1511. if (this_processing_instruction.target() != other_processing_instruction.target())
  1512. return false;
  1513. if (this_processing_instruction.data() != other_processing_instruction.data())
  1514. return false;
  1515. break;
  1516. }
  1517. default:
  1518. break;
  1519. }
  1520. // A and B have the same number of children.
  1521. if (child_count() != other_node->child_count())
  1522. return false;
  1523. // Each child of A equals the child of B at the identical index.
  1524. auto* this_child = first_child();
  1525. auto* other_child = other_node->first_child();
  1526. while (this_child) {
  1527. VERIFY(other_child);
  1528. if (!this_child->is_equal_node(other_child))
  1529. return false;
  1530. this_child = this_child->next_sibling();
  1531. other_child = other_child->next_sibling();
  1532. }
  1533. return true;
  1534. }
  1535. // https://dom.spec.whatwg.org/#locate-a-namespace
  1536. Optional<String> Node::locate_a_namespace(Optional<String> const& prefix) const
  1537. {
  1538. // To locate a namespace for a node using prefix, switch on the interface node implements:
  1539. // Element
  1540. if (is<Element>(*this)) {
  1541. // 1. If prefix is "xml", then return the XML namespace.
  1542. if (prefix == "xml")
  1543. return Web::Namespace::XML.to_string();
  1544. // 2. If prefix is "xmlns", then return the XMLNS namespace.
  1545. if (prefix == "xmlns")
  1546. return Web::Namespace::XMLNS.to_string();
  1547. // 3. If its namespace is non-null and its namespace prefix is prefix, then return namespace.
  1548. auto& element = verify_cast<Element>(*this);
  1549. if (element.namespace_uri().has_value() && element.prefix() == prefix)
  1550. return element.namespace_uri()->to_string();
  1551. // 4. If it has an attribute whose namespace is the XMLNS namespace, namespace prefix is "xmlns", and local name is prefix,
  1552. // or if prefix is null and it has an attribute whose namespace is the XMLNS namespace, namespace prefix is null,
  1553. // and local name is "xmlns", then return its value if it is not the empty string, and null otherwise.
  1554. if (auto* attributes = element.attributes()) {
  1555. for (size_t i = 0; i < attributes->length(); ++i) {
  1556. auto& attr = *attributes->item(i);
  1557. if (attr.namespace_uri() == Web::Namespace::XMLNS) {
  1558. if ((attr.prefix() == "xmlns" && attr.local_name() == prefix) || (!prefix.has_value() && !attr.prefix().has_value() && attr.local_name() == "xmlns")) {
  1559. auto value = attr.value();
  1560. if (!value.is_empty())
  1561. return value;
  1562. return {};
  1563. }
  1564. }
  1565. }
  1566. }
  1567. // 5. If its parent element is null, then return null.
  1568. auto* parent_element = element.parent_element();
  1569. if (!element.parent_element())
  1570. return {};
  1571. // 6. Return the result of running locate a namespace on its parent element using prefix.
  1572. return parent_element->locate_a_namespace(prefix);
  1573. }
  1574. // Document
  1575. if (is<Document>(*this)) {
  1576. // 1. If its document element is null, then return null.
  1577. auto* document_element = verify_cast<Document>(*this).document_element();
  1578. if (!document_element)
  1579. return {};
  1580. // 2. Return the result of running locate a namespace on its document element using prefix.
  1581. return document_element->locate_a_namespace(prefix);
  1582. }
  1583. // DocumentType
  1584. // DocumentFragment
  1585. if (is<DocumentType>(*this) || is<DocumentFragment>(*this)) {
  1586. // Return null.
  1587. return {};
  1588. }
  1589. // Attr
  1590. if (is<Attr>(*this)) {
  1591. // 1. If its element is null, then return null.
  1592. auto* element = verify_cast<Attr>(*this).owner_element();
  1593. if (!element)
  1594. return {};
  1595. // 2. Return the result of running locate a namespace on its element using prefix.
  1596. return element->locate_a_namespace(prefix);
  1597. }
  1598. // Otherwise
  1599. // 1. If its parent element is null, then return null.
  1600. auto* parent_element = this->parent_element();
  1601. if (!parent_element)
  1602. return {};
  1603. // 2. Return the result of running locate a namespace on its parent element using prefix.
  1604. return parent_element->locate_a_namespace(prefix);
  1605. }
  1606. // https://dom.spec.whatwg.org/#dom-node-lookupnamespaceuri
  1607. Optional<String> Node::lookup_namespace_uri(Optional<String> prefix) const
  1608. {
  1609. // 1. If prefix is the empty string, then set it to null.
  1610. if (prefix.has_value() && prefix->is_empty())
  1611. prefix = {};
  1612. // 2. Return the result of running locate a namespace for this using prefix.
  1613. return locate_a_namespace(prefix);
  1614. }
  1615. // https://dom.spec.whatwg.org/#dom-node-lookupprefix
  1616. Optional<String> Node::lookup_prefix(Optional<String> namespace_) const
  1617. {
  1618. // 1. If namespace is null or the empty string, then return null.
  1619. if (!namespace_.has_value() || namespace_->is_empty())
  1620. return {};
  1621. // 2. Switch on the interface this implements:
  1622. // Element
  1623. if (is<Element>(*this)) {
  1624. // Return the result of locating a namespace prefix for it using namespace.
  1625. auto& element = verify_cast<Element>(*this);
  1626. return element.locate_a_namespace_prefix(namespace_);
  1627. }
  1628. // Document
  1629. if (is<Document>(*this)) {
  1630. // Return the result of locating a namespace prefix for its document element, if its document element is non-null; otherwise null.
  1631. auto* document_element = verify_cast<Document>(*this).document_element();
  1632. if (!document_element)
  1633. return {};
  1634. return document_element->locate_a_namespace_prefix(namespace_);
  1635. }
  1636. // DocumentType
  1637. // DocumentFragment
  1638. if (is<DocumentType>(*this) || is<DocumentFragment>(*this))
  1639. // Return null
  1640. return {};
  1641. // Attr
  1642. if (is<Attr>(*this)) {
  1643. // Return the result of locating a namespace prefix for its element, if its element is non-null; otherwise null.
  1644. auto* element = verify_cast<Attr>(*this).owner_element();
  1645. if (!element)
  1646. return {};
  1647. return element->locate_a_namespace_prefix(namespace_);
  1648. }
  1649. // Otherwise
  1650. // Return the result of locating a namespace prefix for its parent element, if its parent element is non-null; otherwise null.
  1651. auto* parent_element = this->parent_element();
  1652. if (!parent_element)
  1653. return {};
  1654. return parent_element->locate_a_namespace_prefix(namespace_);
  1655. }
  1656. // https://dom.spec.whatwg.org/#dom-node-isdefaultnamespace
  1657. bool Node::is_default_namespace(Optional<String> namespace_) const
  1658. {
  1659. // 1. If namespace is the empty string, then set it to null.
  1660. if (namespace_.has_value() && namespace_->is_empty())
  1661. namespace_ = {};
  1662. // 2. Let defaultNamespace be the result of running locate a namespace for this using null.
  1663. auto default_namespace = locate_a_namespace({});
  1664. // 3. Return true if defaultNamespace is the same as namespace; otherwise false.
  1665. return default_namespace == namespace_;
  1666. }
  1667. // https://dom.spec.whatwg.org/#in-a-document-tree
  1668. bool Node::in_a_document_tree() const
  1669. {
  1670. // An element is in a document tree if its root is a document.
  1671. return root().is_document();
  1672. }
  1673. // https://dom.spec.whatwg.org/#dom-node-getrootnode
  1674. GC::Ref<Node> Node::get_root_node(GetRootNodeOptions const& options)
  1675. {
  1676. // The getRootNode(options) method steps are to return this’s shadow-including root if options["composed"] is true;
  1677. if (options.composed)
  1678. return shadow_including_root();
  1679. // otherwise this’s root.
  1680. return root();
  1681. }
  1682. String Node::debug_description() const
  1683. {
  1684. StringBuilder builder;
  1685. builder.append(node_name().to_deprecated_fly_string().to_lowercase());
  1686. if (is_element()) {
  1687. auto const& element = static_cast<DOM::Element const&>(*this);
  1688. if (element.id().has_value())
  1689. builder.appendff("#{}", element.id().value());
  1690. for (auto const& class_name : element.class_names())
  1691. builder.appendff(".{}", class_name);
  1692. }
  1693. return MUST(builder.to_string());
  1694. }
  1695. // https://dom.spec.whatwg.org/#concept-node-length
  1696. size_t Node::length() const
  1697. {
  1698. // 1. If node is a DocumentType or Attr node, then return 0.
  1699. if (is_document_type() || is_attribute())
  1700. return 0;
  1701. // 2. If node is a CharacterData node, then return node’s data’s length.
  1702. if (is_character_data())
  1703. return verify_cast<CharacterData>(*this).length_in_utf16_code_units();
  1704. // 3. Return the number of node’s children.
  1705. return child_count();
  1706. }
  1707. void Node::set_paintable(GC::Ptr<Painting::Paintable> paintable)
  1708. {
  1709. m_paintable = paintable;
  1710. }
  1711. void Node::clear_paintable()
  1712. {
  1713. m_paintable = nullptr;
  1714. }
  1715. Painting::Paintable const* Node::paintable() const
  1716. {
  1717. return m_paintable;
  1718. }
  1719. Painting::Paintable* Node::paintable()
  1720. {
  1721. return m_paintable;
  1722. }
  1723. Painting::PaintableBox const* Node::paintable_box() const
  1724. {
  1725. if (paintable() && paintable()->is_paintable_box())
  1726. return static_cast<Painting::PaintableBox const*>(paintable());
  1727. return nullptr;
  1728. }
  1729. Painting::PaintableBox* Node::paintable_box()
  1730. {
  1731. if (paintable() && paintable()->is_paintable_box())
  1732. return static_cast<Painting::PaintableBox*>(paintable());
  1733. return nullptr;
  1734. }
  1735. // https://dom.spec.whatwg.org/#queue-a-mutation-record
  1736. void Node::queue_mutation_record(FlyString const& type, Optional<FlyString> const& attribute_name, Optional<FlyString> const& attribute_namespace, Optional<String> const& old_value, Vector<GC::Root<Node>> added_nodes, Vector<GC::Root<Node>> removed_nodes, Node* previous_sibling, Node* next_sibling) const
  1737. {
  1738. // NOTE: We defer garbage collection until the end of the scope, since we can't safely use MutationObserver* as a hashmap key otherwise.
  1739. // FIXME: This is a total hack.
  1740. GC::DeferGC defer_gc(heap());
  1741. // 1. Let interestedObservers be an empty map.
  1742. // mutationObserver -> mappedOldValue
  1743. OrderedHashMap<MutationObserver*, Optional<String>> interested_observers;
  1744. // 2. Let nodes be the inclusive ancestors of target.
  1745. // 3. For each node in nodes, and then for each registered of node’s registered observer list:
  1746. for (auto* node = this; node; node = node->parent()) {
  1747. if (!node->m_registered_observer_list)
  1748. continue;
  1749. for (auto& registered_observer : *node->m_registered_observer_list) {
  1750. // 1. Let options be registered’s options.
  1751. auto& options = registered_observer->options();
  1752. // 2. If none of the following are true
  1753. // - node is not target and options["subtree"] is false
  1754. // - type is "attributes" and options["attributes"] either does not exist or is false
  1755. // - type is "attributes", options["attributeFilter"] exists, and options["attributeFilter"] does not contain name or namespace is non-null
  1756. // - type is "characterData" and options["characterData"] either does not exist or is false
  1757. // - type is "childList" and options["childList"] is false
  1758. // then:
  1759. if (!(node != this && !options.subtree)
  1760. && !(type == MutationType::attributes && (!options.attributes.has_value() || !options.attributes.value()))
  1761. && !(type == MutationType::attributes && options.attribute_filter.has_value() && (attribute_namespace.has_value() || !options.attribute_filter->contains_slow(attribute_name.value_or(String {}))))
  1762. && !(type == MutationType::characterData && (!options.character_data.has_value() || !options.character_data.value()))
  1763. && !(type == MutationType::childList && !options.child_list)) {
  1764. // 1. Let mo be registered’s observer.
  1765. auto mutation_observer = registered_observer->observer();
  1766. // 2. If interestedObservers[mo] does not exist, then set interestedObservers[mo] to null.
  1767. if (!interested_observers.contains(mutation_observer))
  1768. interested_observers.set(mutation_observer, {});
  1769. // 3. If either type is "attributes" and options["attributeOldValue"] is true, or type is "characterData" and options["characterDataOldValue"] is true, then set interestedObservers[mo] to oldValue.
  1770. if ((type == MutationType::attributes && options.attribute_old_value.has_value() && options.attribute_old_value.value()) || (type == MutationType::characterData && options.character_data_old_value.has_value() && options.character_data_old_value.value()))
  1771. interested_observers.set(mutation_observer, old_value);
  1772. }
  1773. }
  1774. }
  1775. // OPTIMIZATION: If there are no interested observers, bail without doing any more work.
  1776. if (interested_observers.is_empty())
  1777. return;
  1778. auto added_nodes_list = StaticNodeList::create(realm(), move(added_nodes));
  1779. auto removed_nodes_list = StaticNodeList::create(realm(), move(removed_nodes));
  1780. // 4. For each observer → mappedOldValue of interestedObservers:
  1781. for (auto& interested_observer : interested_observers) {
  1782. // FIXME: The MutationRecord constructor shuld take an Optional<FlyString> attribute name and namespace
  1783. Optional<String> string_attribute_name;
  1784. if (attribute_name.has_value())
  1785. string_attribute_name = attribute_name->to_string();
  1786. Optional<String> string_attribute_namespace;
  1787. if (attribute_namespace.has_value())
  1788. string_attribute_name = attribute_namespace->to_string();
  1789. // 1. Let record be a new MutationRecord object with its type set to type, target set to target, attributeName set to name, attributeNamespace set to namespace, oldValue set to mappedOldValue,
  1790. // addedNodes set to addedNodes, removedNodes set to removedNodes, previousSibling set to previousSibling, and nextSibling set to nextSibling.
  1791. auto record = MutationRecord::create(realm(), type, *this, added_nodes_list, removed_nodes_list, previous_sibling, next_sibling, string_attribute_name, string_attribute_namespace, /* mappedOldValue */ interested_observer.value);
  1792. // 2. Enqueue record to observer’s record queue.
  1793. interested_observer.key->enqueue_record({}, move(record));
  1794. }
  1795. // 5. Queue a mutation observer microtask.
  1796. Bindings::queue_mutation_observer_microtask(document());
  1797. }
  1798. // https://dom.spec.whatwg.org/#queue-a-tree-mutation-record
  1799. void Node::queue_tree_mutation_record(Vector<GC::Root<Node>> added_nodes, Vector<GC::Root<Node>> removed_nodes, Node* previous_sibling, Node* next_sibling)
  1800. {
  1801. // 1. Assert: either addedNodes or removedNodes is not empty.
  1802. VERIFY(added_nodes.size() > 0 || removed_nodes.size() > 0);
  1803. // 2. Queue a mutation record of "childList" for target with null, null, null, addedNodes, removedNodes, previousSibling, and nextSibling.
  1804. queue_mutation_record(MutationType::childList, {}, {}, {}, move(added_nodes), move(removed_nodes), previous_sibling, next_sibling);
  1805. }
  1806. void Node::append_child_impl(GC::Ref<Node> node)
  1807. {
  1808. VERIFY(!node->m_parent);
  1809. if (!is_child_allowed(*node))
  1810. return;
  1811. if (m_last_child)
  1812. m_last_child->m_next_sibling = node.ptr();
  1813. node->m_previous_sibling = m_last_child;
  1814. node->m_parent = this;
  1815. m_last_child = node.ptr();
  1816. if (!m_first_child)
  1817. m_first_child = m_last_child;
  1818. }
  1819. void Node::insert_before_impl(GC::Ref<Node> node, GC::Ptr<Node> child)
  1820. {
  1821. if (!child)
  1822. return append_child_impl(move(node));
  1823. VERIFY(!node->m_parent);
  1824. VERIFY(child->parent() == this);
  1825. node->m_previous_sibling = child->m_previous_sibling;
  1826. node->m_next_sibling = child;
  1827. if (child->m_previous_sibling)
  1828. child->m_previous_sibling->m_next_sibling = node;
  1829. if (m_first_child == child)
  1830. m_first_child = node;
  1831. child->m_previous_sibling = node;
  1832. node->m_parent = this;
  1833. }
  1834. void Node::remove_child_impl(GC::Ref<Node> node)
  1835. {
  1836. VERIFY(node->m_parent.ptr() == this);
  1837. if (m_first_child == node)
  1838. m_first_child = node->m_next_sibling;
  1839. if (m_last_child == node)
  1840. m_last_child = node->m_previous_sibling;
  1841. if (node->m_next_sibling)
  1842. node->m_next_sibling->m_previous_sibling = node->m_previous_sibling;
  1843. if (node->m_previous_sibling)
  1844. node->m_previous_sibling->m_next_sibling = node->m_next_sibling;
  1845. node->m_next_sibling = nullptr;
  1846. node->m_previous_sibling = nullptr;
  1847. node->m_parent = nullptr;
  1848. }
  1849. bool Node::is_ancestor_of(Node const& other) const
  1850. {
  1851. for (auto* ancestor = other.parent(); ancestor; ancestor = ancestor->parent()) {
  1852. if (ancestor == this)
  1853. return true;
  1854. }
  1855. return false;
  1856. }
  1857. bool Node::is_inclusive_ancestor_of(Node const& other) const
  1858. {
  1859. return &other == this || is_ancestor_of(other);
  1860. }
  1861. bool Node::is_descendant_of(Node const& other) const
  1862. {
  1863. return other.is_ancestor_of(*this);
  1864. }
  1865. bool Node::is_inclusive_descendant_of(Node const& other) const
  1866. {
  1867. return other.is_inclusive_ancestor_of(*this);
  1868. }
  1869. // https://dom.spec.whatwg.org/#concept-tree-following
  1870. bool Node::is_following(Node const& other) const
  1871. {
  1872. // An object A is following an object B if A and B are in the same tree and A comes after B in tree order.
  1873. for (auto* node = previous_in_pre_order(); node; node = node->previous_in_pre_order()) {
  1874. if (node == &other)
  1875. return true;
  1876. }
  1877. return false;
  1878. }
  1879. void Node::build_accessibility_tree(AccessibilityTreeNode& parent)
  1880. {
  1881. if (is_uninteresting_whitespace_node())
  1882. return;
  1883. if (is_document()) {
  1884. auto* document = static_cast<DOM::Document*>(this);
  1885. auto* document_element = document->document_element();
  1886. if (document_element && document_element->include_in_accessibility_tree()) {
  1887. parent.set_value(document_element);
  1888. if (document_element->has_child_nodes())
  1889. document_element->for_each_child([&parent](DOM::Node& child) {
  1890. child.build_accessibility_tree(parent);
  1891. return IterationDecision::Continue;
  1892. });
  1893. }
  1894. } else if (is_element()) {
  1895. auto const* element = static_cast<DOM::Element const*>(this);
  1896. if (is<HTML::HTMLScriptElement>(element) || is<HTML::HTMLStyleElement>(element))
  1897. return;
  1898. if (element->include_in_accessibility_tree()) {
  1899. auto current_node = AccessibilityTreeNode::create(&document(), this);
  1900. parent.append_child(current_node);
  1901. if (has_child_nodes()) {
  1902. for_each_child([&current_node](DOM::Node& child) {
  1903. child.build_accessibility_tree(*current_node);
  1904. return IterationDecision::Continue;
  1905. });
  1906. }
  1907. } else if (has_child_nodes()) {
  1908. for_each_child([&parent](DOM::Node& child) {
  1909. child.build_accessibility_tree(parent);
  1910. return IterationDecision::Continue;
  1911. });
  1912. }
  1913. } else if (is_text()) {
  1914. parent.append_child(AccessibilityTreeNode::create(&document(), this));
  1915. if (has_child_nodes()) {
  1916. for_each_child([&parent](DOM::Node& child) {
  1917. child.build_accessibility_tree(parent);
  1918. return IterationDecision::Continue;
  1919. });
  1920. }
  1921. }
  1922. }
  1923. // https://www.w3.org/TR/accname-1.2/#mapping_additional_nd_te
  1924. ErrorOr<String> Node::name_or_description(NameOrDescription target, Document const& document, HashTable<UniqueNodeID>& visited_nodes, IsDescendant is_descendant) const
  1925. {
  1926. // The text alternative for a given element is computed as follows:
  1927. // 1. Set the root node to the given element, the current node to the root node, and the total accumulated text to the
  1928. // empty string (""). If the root node's role prohibits naming, return the empty string ("").
  1929. auto const* root_node = this;
  1930. auto const* current_node = root_node;
  1931. StringBuilder total_accumulated_text;
  1932. visited_nodes.set(unique_id());
  1933. if (is_element()) {
  1934. auto const* element = static_cast<DOM::Element const*>(this);
  1935. auto role = element->role_from_role_attribute_value();
  1936. // Per https://w3c.github.io/html-aam/#el-aside and https://w3c.github.io/html-aam/#el-section, computing a
  1937. // default role for an aside element or section element requires first computing its accessible name — that is,
  1938. // calling into this name_or_description code. But if we then try to determine a default role for the aside
  1939. // element or section element here, that’d then end up calling right back into this name_or_description code —
  1940. // which would cause the calls to loop infinitely. So to avoid that, we only compute a default role here if this
  1941. // isn’t an aside element or section element.
  1942. // https://github.com/w3c/aria/issues/2391
  1943. if (!role.has_value() && element->local_name() != HTML::TagNames::aside && element->local_name() != HTML::TagNames::section)
  1944. role = element->default_role();
  1945. // 2. Compute the text alternative for the current node:
  1946. // A. Hidden Not Referenced: If the current node is hidden and is:
  1947. // i. Not part of an aria-labelledby or aria-describedby traversal, where the node directly referenced by that
  1948. // relation was hidden.
  1949. // ii. Nor part of a native host language text alternative element (e.g. label in HTML) or attribute traversal,
  1950. // where the root of that traversal was hidden.
  1951. // Return the empty string.
  1952. //
  1953. // NOTE: Nodes with CSS properties display:none, visibility:hidden, visibility:collapse or content-visibility:hidden:
  1954. // They are considered hidden, as they match the guidelines "not perceivable" and "explicitly hidden".
  1955. //
  1956. // AD-HOC: We don’t implement this step here — because strictly implementing this would cause us to return early
  1957. // whenever encountering a node (element, actually) that “is hidden and is not directly referenced by
  1958. // aria-labelledby or aria-describedby”, without traversing down through that element’s subtree to see if it has
  1959. // (1) any descendant elements that are directly referenced and/or (2) any un-hidden nodes. So we instead (in
  1960. // substep G below) traverse upward through ancestor nodes of every text node, and check in that way to do the
  1961. // equivalent of what this step seems to have been intended to do.
  1962. // https://github.com/w3c/aria/issues/2387
  1963. // B. Otherwise:
  1964. // - if computing a name, and the current node has an aria-labelledby attribute that contains at least one valid
  1965. // IDREF, and the current node is not already part of an aria-labelledby traversal, process its IDREFs in the
  1966. // order they occur:
  1967. // - or, if computing a description, and the current node has an aria-describedby attribute that contains at least
  1968. // one valid IDREF, and the current node is not already part of an aria-describedby traversal, process its IDREFs
  1969. // in the order they occur:
  1970. auto aria_labelled_by = element->aria_labelled_by();
  1971. auto aria_described_by = element->aria_described_by();
  1972. if ((target == NameOrDescription::Name && aria_labelled_by.has_value() && Node::first_valid_id(*aria_labelled_by, document).has_value())
  1973. || (target == NameOrDescription::Description && aria_described_by.has_value() && Node::first_valid_id(*aria_described_by, document).has_value())) {
  1974. // i. Set the accumulated text to the empty string.
  1975. total_accumulated_text.clear();
  1976. Vector<StringView> id_list;
  1977. if (target == NameOrDescription::Name) {
  1978. id_list = aria_labelled_by->bytes_as_string_view().split_view_if(Infra::is_ascii_whitespace);
  1979. } else {
  1980. id_list = aria_described_by->bytes_as_string_view().split_view_if(Infra::is_ascii_whitespace);
  1981. }
  1982. // ii. For each IDREF:
  1983. for (auto const& id_ref : id_list) {
  1984. auto node = document.get_element_by_id(MUST(FlyString::from_utf8(id_ref)));
  1985. if (!node)
  1986. continue;
  1987. // AD-HOC: The “For each IDREF” substep in the spec doesn’t seem to explicitly require the following
  1988. // check for an aria-label value; but the “div group explicitly labelledby self and heading” subtest at
  1989. // https://wpt.fyi/results/accname/name/comp_labelledby.html won’t pass unless we do this check.
  1990. // https://github.com/w3c/aria/issues/2388
  1991. if (target == NameOrDescription::Name && node->aria_label().has_value() && !node->aria_label()->is_empty() && !node->aria_label()->bytes_as_string_view().is_whitespace()) {
  1992. total_accumulated_text.append(' ');
  1993. total_accumulated_text.append(node->aria_label().value());
  1994. }
  1995. if (visited_nodes.contains(node->unique_id()))
  1996. continue;
  1997. // a. Set the current node to the node referenced by the IDREF.
  1998. current_node = node;
  1999. // b. Compute the text alternative of the current node beginning with step 2. Set the result to that text alternative.
  2000. auto result = TRY(node->name_or_description(target, document, visited_nodes));
  2001. // c. Append the result, with a space, to the accumulated text.
  2002. total_accumulated_text.append(' ');
  2003. total_accumulated_text.append(result);
  2004. }
  2005. // iii. Return the accumulated text.
  2006. // AD-HOC: This substep in the spec doesn’t seem to explicitly require the following check for an aria-label
  2007. // value; but the “button's hidden referenced name (visibility:hidden) with hidden aria-labelledby traversal
  2008. // falls back to aria-label” subtest at https://wpt.fyi/results/accname/name/comp_labelledby.html won’t pass
  2009. // unless we do this check.
  2010. // https://github.com/w3c/aria/issues/2388
  2011. if (total_accumulated_text.string_view().is_whitespace() && target == NameOrDescription::Name && element->aria_label().has_value() && !element->aria_label()->is_empty() && !element->aria_label()->bytes_as_string_view().is_whitespace())
  2012. return element->aria_label().release_value();
  2013. return total_accumulated_text.to_string();
  2014. }
  2015. // D. AriaLabel: Otherwise, if the current node has an aria-label attribute whose value is not undefined, not
  2016. // the empty string, nor, when trimmed of whitespace, is not the empty string:
  2017. //
  2018. // AD-HOC: We’ve reordered substeps C and D from https://w3c.github.io/accname/#step2 — because
  2019. // the more-specific per-HTML-element requirements at https://w3c.github.io/html-aam/#accname-computation
  2020. // necessitate doing so, and the “input with label for association is superceded by aria-label” subtest at
  2021. // https://wpt.fyi/results/accname/name/comp_label.html won’t pass unless we do this reordering.
  2022. // Spec PR: https://github.com/w3c/aria/pull/2377
  2023. if (target == NameOrDescription::Name && element->aria_label().has_value() && !element->aria_label()->is_empty() && !element->aria_label()->bytes_as_string_view().is_whitespace()) {
  2024. // TODO: - If traversal of the current node is due to recursion and the current node is an embedded control as defined in step 2E, ignore aria-label and skip to rule 2E.
  2025. // https://github.com/w3c/aria/pull/2385 and https://github.com/w3c/accname/issues/173
  2026. if (!element->is_html_slot_element())
  2027. return element->aria_label().value();
  2028. }
  2029. // C. Embedded Control: Otherwise, if the current node is a control embedded within the label (e.g. any element
  2030. // directly referenced by aria-labelledby) for another widget, where the user can adjust the embedded control's
  2031. // value, then return the embedded control as part of the text alternative in the following manner:
  2032. GC::Ptr<DOM::NodeList> labels;
  2033. if (is<HTML::HTMLElement>(this))
  2034. labels = (const_cast<HTML::HTMLElement&>(static_cast<HTML::HTMLElement const&>(*current_node))).labels();
  2035. if (labels != nullptr && labels->length() > 0) {
  2036. StringBuilder builder;
  2037. for (u32 i = 0; i < labels->length(); i++) {
  2038. auto nodes = labels->item(i)->children_as_vector();
  2039. for (auto const& node : nodes) {
  2040. // AD-HOC: https://wpt.fyi/results/accname/name/comp_host_language_label.html has “encapsulation”
  2041. // tests, from which can be induced a requirement that when computing the accessible name for a
  2042. // <label>-ed form control (“embedded control”), then any content (text content or attribute values)
  2043. // from the control itself that would otherwise be included in the accessible-name computation for
  2044. // it ancestor <label> must instead be skipped and not included. The HTML-AAM spec seems to maybe
  2045. // be trying to achieve that result by expressing specific steps for each particular type of form
  2046. // control. But what all that reduces/optimizes/simplifies down to is just, “skip over self”.
  2047. // https://github.com/w3c/aria/issues/2389
  2048. if (node == this)
  2049. continue;
  2050. if (node->is_element()) {
  2051. auto const& element = static_cast<DOM::Element const&>(*node);
  2052. auto role = element.role_or_default();
  2053. if (role == ARIA::Role::textbox) {
  2054. // i. Textbox: If the embedded control has role textbox, return its value.
  2055. if (is<HTML::HTMLInputElement>(*node)) {
  2056. auto const& element = static_cast<HTML::HTMLInputElement const&>(*node);
  2057. if (element.has_attribute(HTML::AttributeNames::value))
  2058. builder.append(element.value());
  2059. } else
  2060. builder.append(node->text_content().value());
  2061. } else if (role == ARIA::Role::combobox) {
  2062. // ii. Combobox/Listbox: If the embedded control has role combobox or listbox, return the text
  2063. // alternative of the chosen option.
  2064. if (is<HTML::HTMLInputElement>(*node)) {
  2065. auto const& element = static_cast<HTML::HTMLInputElement const&>(*node);
  2066. if (element.has_attribute(HTML::AttributeNames::value))
  2067. builder.append(element.value());
  2068. } else if (is<HTML::HTMLSelectElement>(*node)) {
  2069. auto const& element = static_cast<HTML::HTMLSelectElement const&>(*node);
  2070. builder.append(element.value());
  2071. } else
  2072. builder.append(node->text_content().value());
  2073. } else if (role == ARIA::Role::listbox) {
  2074. // ii. Combobox/Listbox: If the embedded control has role combobox or listbox, return the text
  2075. // alternative of the chosen option.
  2076. if (is<HTML::HTMLSelectElement>(*node)) {
  2077. auto const& element = static_cast<HTML::HTMLSelectElement const&>(*node);
  2078. builder.append(element.value());
  2079. }
  2080. auto children = node->children_as_vector();
  2081. for (auto& child : children) {
  2082. if (child->is_element()) {
  2083. auto const& element = static_cast<DOM::Element const&>(*child);
  2084. auto role = element.role_or_default();
  2085. if (role == ARIA::Role::option && element.aria_selected() == "true")
  2086. builder.append(element.text_content().value());
  2087. }
  2088. }
  2089. } else if (role == ARIA::Role::spinbutton || role == ARIA::Role::slider) {
  2090. auto aria_valuenow = element.aria_value_now();
  2091. auto aria_valuetext = element.aria_value_text();
  2092. // iii. Range: If the embedded control has role range (e.g., a spinbutton or slider):
  2093. // a. If the aria-valuetext property is present, return its value,
  2094. if (aria_valuetext.has_value())
  2095. builder.append(aria_valuetext.value());
  2096. // b. Otherwise, if the aria-valuenow property is present, return its value
  2097. else if (aria_valuenow.has_value())
  2098. builder.append(aria_valuenow.value());
  2099. // c. Otherwise, use the value as specified by a host language attribute.
  2100. else if (is<HTML::HTMLInputElement>(*node)) {
  2101. auto const& element = static_cast<HTML::HTMLInputElement const&>(*node);
  2102. if (element.has_attribute(HTML::AttributeNames::value))
  2103. builder.append(element.value());
  2104. }
  2105. }
  2106. } else if (node->is_text()) {
  2107. auto const& text_node = static_cast<DOM::Text const&>(*node);
  2108. builder.append(text_node.data());
  2109. }
  2110. }
  2111. }
  2112. return builder.to_string();
  2113. }
  2114. // E. Host Language Label: Otherwise, if the current node's native markup provides an attribute (e.g. alt) or
  2115. // element (e.g. HTML label or SVG title) that defines a text alternative, return that alternative in the form
  2116. // of a flat string as defined by the host language.
  2117. // TODO: Confirm (through existing WPT test cases) whether HTMLLabelElement is already handled (by the code for
  2118. // step C. “Embedded Control” above) in conformance with the spec requirements — and if not, then add handling.
  2119. //
  2120. // https://w3c.github.io/html-aam/#img-element-accessible-name-computation
  2121. // use alt attribute, even if its value is the empty string.
  2122. // See also https://wpt.fyi/results/accname/name/comp_tooltip.tentative.html.
  2123. if (is<HTML::HTMLImageElement>(*element) && element->has_attribute(HTML::AttributeNames::alt))
  2124. return element->get_attribute(HTML::AttributeNames::alt).value();
  2125. // https://w3c.github.io/svg-aam/#mapping_additional_nd
  2126. Optional<String> title_element_text;
  2127. if (element->is_svg_element()) {
  2128. // If the current node has at least one direct child title element, select the appropriate title based on
  2129. // the language rules for the SVG specification, and return the title text alternative as a flat string.
  2130. element->for_each_child_of_type<SVG::SVGTitleElement>([&](SVG::SVGTitleElement const& title) mutable {
  2131. title_element_text = title.text_content();
  2132. return IterationDecision::Break;
  2133. });
  2134. if (title_element_text.has_value())
  2135. return title_element_text.release_value();
  2136. // If the current node is a link, and there was no child title element, but it has an xlink:title attribute,
  2137. // return the value of that attribute.
  2138. if (auto title_attribute = element->get_attribute_ns(Namespace::XLink, XLink::AttributeNames::title); title_attribute.has_value())
  2139. return title_attribute.release_value();
  2140. }
  2141. // https://w3c.github.io/html-aam/#table-element-accessible-name-computation
  2142. // 2. If the accessible name is still empty, then: if the table element has a child that is a caption element,
  2143. // then use the subtree of the first such element.
  2144. if (is<HTML::HTMLTableElement>(*element))
  2145. if (auto& table = (const_cast<HTML::HTMLTableElement&>(static_cast<HTML::HTMLTableElement const&>(*element))); table.caption())
  2146. return table.caption()->text_content().release_value();
  2147. // https://w3c.github.io/html-aam/#fieldset-element-accessible-name-computation
  2148. // 2. If the accessible name is still empty, then: if the fieldset element has a child that is a legend element,
  2149. // then use the subtree of the first such element.
  2150. if (is<HTML::HTMLFieldSetElement>(*element)) {
  2151. Optional<String> legend;
  2152. auto& fieldset = (const_cast<HTML::HTMLFieldSetElement&>(static_cast<HTML::HTMLFieldSetElement const&>(*element)));
  2153. fieldset.for_each_child_of_type<HTML::HTMLLegendElement>([&](HTML::HTMLLegendElement const& element) mutable {
  2154. legend = element.text_content().release_value();
  2155. return IterationDecision::Break;
  2156. });
  2157. if (legend.has_value())
  2158. return legend.release_value();
  2159. }
  2160. if (is<HTML::HTMLInputElement>(*element)) {
  2161. auto& input = (const_cast<HTML::HTMLInputElement&>(static_cast<HTML::HTMLInputElement const&>(*element)));
  2162. // https://w3c.github.io/html-aam/#input-type-button-input-type-submit-and-input-type-reset-accessible-name-computation
  2163. // 3. Otherwise use the value attribute.
  2164. if (input.type_state() == HTML::HTMLInputElement::TypeAttributeState::Button
  2165. || input.type_state() == HTML::HTMLInputElement::TypeAttributeState::SubmitButton
  2166. || input.type_state() == HTML::HTMLInputElement::TypeAttributeState::ResetButton)
  2167. if (auto value = input.get_attribute(HTML::AttributeNames::value); value.has_value())
  2168. return value.release_value();
  2169. // https://w3c.github.io/html-aam/#input-type-image-accessible-name-computation
  2170. // 3. Otherwise use alt attribute if present and its value is not the empty string.
  2171. if (input.type_state() == HTML::HTMLInputElement::TypeAttributeState::ImageButton)
  2172. if (auto alt = element->get_attribute(HTML::AttributeNames::alt); alt.has_value())
  2173. return alt.release_value();
  2174. }
  2175. // F. Name From Content: Otherwise, if the current node's role allows name from content, or if the current node
  2176. // is referenced by aria-labelledby, aria-describedby, or is a native host language text alternative element
  2177. // (e.g. label in HTML), or is a descendant of a native host language text alternative element:
  2178. if ((role.has_value() && ARIA::allows_name_from_content(role.value())) || element->is_referenced() || is_descendant == IsDescendant::Yes) {
  2179. // i. Set the accumulated text to the empty string.
  2180. total_accumulated_text.clear();
  2181. // ii. Name From Generated Content: Check for CSS generated textual content associated with the current node
  2182. // and include it in the accumulated text. The CSS ::before and ::after pseudo elements [CSS2] can provide
  2183. // textual content for elements that have a content model.
  2184. // a. For ::before pseudo elements, User agents MUST prepend CSS textual content, without a space, to the textual
  2185. // content of the current node.
  2186. // b. For ::after pseudo elements, User agents MUST append CSS textual content, without a space, to the textual
  2187. // content of the current node. NOTE: The code for handling the ::after pseudo elements case is further below,
  2188. // following the “iii. For each child node of the current node” code.
  2189. if (auto before = element->get_pseudo_element_node(CSS::Selector::PseudoElement::Type::Before)) {
  2190. if (before->computed_values().content().alt_text.has_value())
  2191. total_accumulated_text.append(before->computed_values().content().alt_text.release_value());
  2192. else
  2193. total_accumulated_text.append(before->computed_values().content().data);
  2194. }
  2195. // iii. Determine Child Nodes: Determine the rendered child nodes of the current node:
  2196. // iii. Determine Child Nodes: Determine the rendered child nodes of the current node:
  2197. // c. [Otherwise,] set the rendered child nodes to be the child nodes of the current node.
  2198. auto child_nodes = current_node->children_as_vector();
  2199. // a. If the current node has an attached shadow root, set the rendered child nodes to be the child nodes of
  2200. // the shadow root.
  2201. if (element->is_shadow_host() && element->shadow_root() && element->shadow_root()->is_connected())
  2202. child_nodes = element->shadow_root()->children_as_vector();
  2203. // b. Otherwise, if the current node is a slot with assigned nodes, set the rendered child nodes to be the
  2204. // assigned nodes of the current node.
  2205. if (element->is_html_slot_element()) {
  2206. total_accumulated_text.append(element->text_content().value());
  2207. child_nodes = static_cast<HTML::HTMLSlotElement const*>(element)->assigned_nodes();
  2208. }
  2209. // iv. Name From Each Child: For each rendered child node of the current node
  2210. for (auto& child_node : child_nodes) {
  2211. if (!child_node->is_element() && !child_node->is_text())
  2212. continue;
  2213. bool should_add_space = true;
  2214. const_cast<DOM::Document&>(document).update_layout();
  2215. auto const* layout_node = child_node->layout_node();
  2216. if (layout_node) {
  2217. auto display = layout_node->display();
  2218. if (display.is_inline_outside() && display.is_flow_inside()) {
  2219. should_add_space = false;
  2220. }
  2221. }
  2222. if (visited_nodes.contains(child_node->unique_id()))
  2223. continue;
  2224. // a. Set the current node to the child node.
  2225. current_node = child_node;
  2226. // b. Compute the text alternative of the current node beginning with step 2. Set the result to that text alternative.
  2227. auto result = MUST(current_node->name_or_description(target, document, visited_nodes, IsDescendant::Yes));
  2228. // J. Append a space character and the result of each step above to the total accumulated text.
  2229. // AD-HOC: Doing the space-adding here is in a different order from what the spec states.
  2230. if (should_add_space)
  2231. total_accumulated_text.append(' ');
  2232. // c. Append the result to the accumulated text.
  2233. total_accumulated_text.append(result);
  2234. }
  2235. // NOTE: See step ii.b above.
  2236. if (auto after = element->get_pseudo_element_node(CSS::Selector::PseudoElement::Type::After)) {
  2237. if (after->computed_values().content().alt_text.has_value())
  2238. total_accumulated_text.append(after->computed_values().content().alt_text.release_value());
  2239. else
  2240. total_accumulated_text.append(after->computed_values().content().data);
  2241. }
  2242. // v. Return the accumulated text if it is not the empty string ("").
  2243. if (!total_accumulated_text.is_empty())
  2244. return total_accumulated_text.to_string();
  2245. // Important: Each node in the subtree is consulted only once. If text has been collected from a descendant,
  2246. // but is referenced by another IDREF in some descendant node, then that second, or subsequent, reference is
  2247. // not followed. This is done to avoid infinite loops.
  2248. }
  2249. }
  2250. // G. Text Node: Otherwise, if the current node is a Text Node, return its textual contents.
  2251. //
  2252. // AD-HOC: The spec doesn’t require ascending through the parent node and ancestor nodes of every text node we
  2253. // reach — the way we’re doing there. But we implement it this way because the spec algorithm as written doesn’t
  2254. // appear to achieve what it seems to be intended to achieve. Specifically, the spec algorithm as written doesn’t
  2255. // cause traversal through element subtrees in way that’s necessary to check for descendants that are referenced by
  2256. // aria-labelledby or aria-describedby and/or un-hidden. See the comment for substep A above.
  2257. if (is_text() && (!parent_element() || (parent_element()->is_referenced() || !parent_element()->is_hidden() || !parent_element()->has_hidden_ancestor() || parent_element()->has_referenced_and_hidden_ancestor()))) {
  2258. if (layout_node() && layout_node()->is_text_node())
  2259. return verify_cast<Layout::TextNode>(layout_node())->text_for_rendering();
  2260. return text_content().release_value();
  2261. }
  2262. // H. Otherwise, if the current node is a descendant of an element whose Accessible Name or Accessible Description
  2263. // is being computed, and contains descendants, proceed to 2F.i.
  2264. //
  2265. // AD-HOC: We don’t implement this step here — because is essentially unreachable code in the spec algorithm.
  2266. // We could never get here without descending through every subtree of an element whose Accessible Name or
  2267. // Accessible Description is being computed. And in our implementation of substep F about, we’re anyway already
  2268. // recursively descending through all the child nodes of every element whose Accessible Name or Accessible
  2269. // Description is being computed, in a way that never leads to this substep H every being hit.
  2270. // I. Otherwise, if the current node has a Tooltip attribute, return its value.
  2271. //
  2272. // https://www.w3.org/TR/accname-1.2/#dfn-tooltip-attribute
  2273. // Any host language attribute that would result in a user agent generating a tooltip such as in response to a mouse
  2274. // hover in desktop user agents.
  2275. // FIXME: Support SVG tooltips and CSS tooltips
  2276. if (is<HTML::HTMLElement>(this)) {
  2277. auto const* element = static_cast<HTML::HTMLElement const*>(this);
  2278. auto tooltip = element->title();
  2279. if (tooltip.has_value() && !tooltip->is_empty())
  2280. return tooltip.release_value();
  2281. }
  2282. // 3. After all steps are completed, the total accumulated text is used as the accessible name or accessible description
  2283. // of the element that initiated the computation.
  2284. return total_accumulated_text.to_string();
  2285. }
  2286. // https://www.w3.org/TR/accname-1.2/#mapping_additional_nd_name
  2287. ErrorOr<String> Node::accessible_name(Document const& document) const
  2288. {
  2289. HashTable<UniqueNodeID> visited_nodes;
  2290. // User agents MUST compute an accessible name using the rules outlined below in the section titled Accessible Name and Description Computation.
  2291. return name_or_description(NameOrDescription::Name, document, visited_nodes);
  2292. }
  2293. // https://www.w3.org/TR/accname-1.2/#mapping_additional_nd_description
  2294. ErrorOr<String> Node::accessible_description(Document const& document) const
  2295. {
  2296. // If aria-describedby is present, user agents MUST compute the accessible description by concatenating the text alternatives for elements referenced by an aria-describedby attribute on the current element.
  2297. // The text alternatives for the referenced elements are computed using a number of methods, outlined below in the section titled Accessible Name and Description Computation.
  2298. if (!is_element())
  2299. return String {};
  2300. auto const* element = static_cast<Element const*>(this);
  2301. auto described_by = element->aria_described_by();
  2302. if (!described_by.has_value())
  2303. return String {};
  2304. HashTable<UniqueNodeID> visited_nodes;
  2305. StringBuilder builder;
  2306. auto id_list = described_by->bytes_as_string_view().split_view_if(Infra::is_ascii_whitespace);
  2307. for (auto const& id : id_list) {
  2308. if (auto description_element = document.get_element_by_id(MUST(FlyString::from_utf8(id)))) {
  2309. auto description = TRY(
  2310. description_element->name_or_description(NameOrDescription::Description, document,
  2311. visited_nodes));
  2312. if (!description.is_empty()) {
  2313. if (builder.is_empty()) {
  2314. builder.append(description);
  2315. } else {
  2316. builder.append(" "sv);
  2317. builder.append(description);
  2318. }
  2319. }
  2320. }
  2321. }
  2322. return builder.to_string();
  2323. }
  2324. Optional<StringView> Node::first_valid_id(StringView value, Document const& document)
  2325. {
  2326. auto id_list = value.split_view_if(Infra::is_ascii_whitespace);
  2327. for (auto const& id : id_list) {
  2328. if (document.get_element_by_id(MUST(FlyString::from_utf8(id))))
  2329. return id;
  2330. }
  2331. return {};
  2332. }
  2333. void Node::add_registered_observer(RegisteredObserver& registered_observer)
  2334. {
  2335. if (!m_registered_observer_list)
  2336. m_registered_observer_list = make<Vector<GC::Ref<RegisteredObserver>>>();
  2337. m_registered_observer_list->append(registered_observer);
  2338. }
  2339. }
  2340. namespace IPC {
  2341. template<>
  2342. ErrorOr<void> encode(Encoder& encoder, Web::UniqueNodeID const& value)
  2343. {
  2344. return encode(encoder, value.value());
  2345. }
  2346. template<>
  2347. ErrorOr<Web::UniqueNodeID> decode(Decoder& decoder)
  2348. {
  2349. auto value = TRY(decoder.decode<i64>());
  2350. return Web::UniqueNodeID(value);
  2351. }
  2352. }