@@ -170,7 +170,7 @@ struct BuilderContext {
170170
171171 // https://www.w3.org/TR/css-inline-3/#model
172172 void flushRootInlineBoxIntoAnonymousBox () {
173- if (not rootInlineBox ().active ())
173+ if (not _rootInlineBox or not rootInlineBox ().active ())
174174 return ;
175175
176176 // The root inline box inherits from its parent block container, but is otherwise unstyleable.
@@ -289,6 +289,7 @@ struct BuilderContext {
289289};
290290
291291static void _buildNode (BuilderContext bc, Gc::Ref<Dom::Node> node);
292+ static void _buildPseudoElement (BuilderContext bc, Rc<Dom::PseudoElement> pseudoElement);
292293
293294// MARK: Build void/leaves ---------------------------------------------------------
294295
@@ -424,11 +425,6 @@ bool _alwaysInlineBlock(Gc::Ref<Dom::Element> el) {
424425static void _buildChildren (BuilderContext bc, Gc::Ref<Dom::Node> parent);
425426
426427static void createAndBuildInlineFlowfromElement (BuilderContext bc, Rc<Style::SpecifiedValues> style, Gc::Ref<Dom::Element> el) {
427- if (el->qualifiedName == Html::BR_TAG) {
428- bc.flushRootInlineBoxIntoAnonymousBox ();
429- return ;
430- }
431-
432428 if (isVoidElement (el)) {
433429 _buildVoidElement (bc, el);
434430 return ;
@@ -442,9 +438,7 @@ static void createAndBuildInlineFlowfromElement(BuilderContext bc, Rc<Style::Spe
442438}
443439
444440static void buildBlockFlowFromElement (BuilderContext bc, Gc::Ref<Dom::Element> el) {
445- if (el->qualifiedName == Html::BR_TAG) {
446- // do nothing
447- } else if (el->qualifiedName == Svg::SVG_TAG) {
441+ if (el->qualifiedName == Svg::SVG_TAG) {
448442 bc.content () = _buildSVG (el);
449443 } else if (isVoidElement (el)) {
450444 _buildVoidElement (bc, el);
@@ -668,6 +662,10 @@ static void _buildTableBox(BuilderContext tableWrapperBc, Gc::Ref<Dom::Element>
668662 searchAndBuildCaption ();
669663 }
670664
665+ if (auto before = el->getPseudoElement (Dom::PseudoElement::BEFORE)) {
666+ _buildPseudoElement (tableWrapperBc, before.unwrap ());
667+ }
668+
671669 // An anonymous table-row box must be generated around each sequence of consecutive children of a table-root
672670 // box which are not proper table child boxes.
673671 _buildTableChildrenWhileWrappingIntoAnonymousBox (tableWrapperBc.toTableContent (tableBox), *el, tableBoxStyle, true , [](Display const & display) {
@@ -678,6 +676,10 @@ static void _buildTableBox(BuilderContext tableWrapperBc, Gc::Ref<Dom::Element>
678676 if (not captionsOnTop) {
679677 searchAndBuildCaption ();
680678 }
679+
680+ if (auto before = el->getPseudoElement (Dom::PseudoElement::AFTER)) {
681+ _buildPseudoElement (tableWrapperBc, before.unwrap ());
682+ }
681683}
682684
683685static Box _createTableWrapperAndBuildTable (BuilderContext bc, Rc<Style::SpecifiedValues> tableStyle, Gc::Ref<Dom::Element> tableBoxEl) {
@@ -742,9 +744,18 @@ static void _innerDisplayDispatchCreationOfInlineLevelBox(BuilderContext bc, Gc:
742744// MARK: Dispatching from Node to builder based on outside role ------------------------------------------------------
743745
744746static void _buildChildren (BuilderContext bc, Gc::Ref<Dom::Node> parent) {
747+ auto el = parent->is <Dom::Element>();
748+ if (auto before = el ? el->getPseudoElement (Dom::PseudoElement::BEFORE) : NONE) {
749+ _buildPseudoElement (bc, before.unwrap ());
750+ }
751+
745752 for (auto child = parent->firstChild (); child; child = child->nextSibling ()) {
746753 _buildNode (bc, *child);
747754 }
755+
756+ if (auto after = el ? el->getPseudoElement (Dom::PseudoElement::AFTER) : NONE) {
757+ _buildPseudoElement (bc, after.unwrap ());
758+ }
748759}
749760
750761static void _buildChildBoxDisplay (BuilderContext bc, Gc::Ref<Dom::Node> node, Display display) {
@@ -801,6 +812,29 @@ static void _buildNode(BuilderContext bc, Gc::Ref<Dom::Node> node) {
801812 }
802813}
803814
815+ export Box _buildBlockPseudoElement (Dom::PseudoElement& el) {
816+ auto proseStyle = _proseStyleFromStyle (*el.specifiedValues (), el.specifiedValues ()->fontFace );
817+
818+ if (el.specifiedValues ()->content .is <String>()) {
819+ auto prose = makeRc<Gfx::Prose>(proseStyle);
820+ prose->append (el.specifiedValues ()->content .unwrap <String>().str ());
821+ return {el.specifiedValues (), InlineBox{prose}, nullptr };
822+ }
823+
824+ return {el.specifiedValues (), nullptr };
825+ }
826+
827+ static void _buildPseudoElement (BuilderContext bc, Rc<Dom::PseudoElement> pseudoElement) {
828+ auto style = pseudoElement->specifiedValues ();
829+ auto display = style->display ;
830+ if (display == Display::NONE)
831+ return ;
832+
833+ // FIXME: Treat all pseudo element as block
834+ bc.flushRootInlineBoxIntoAnonymousBox ();
835+ bc.addToParentBox (_buildBlockPseudoElement (*pseudoElement));
836+ }
837+
804838// MARK: Entry points -----------------------------------------------------------------
805839
806840static auto dumpBoxes = Debug::Flag::debug(" web-boxes" s, " Dump the constructed boxes" s);
0 commit comments