void RenderContainer::updatePseudoChild(RenderStyle::PseudoId type, RenderObject* child) { // In CSS2, before/after pseudo-content cannot nest. Check this first. if (style()->styleType() == RenderStyle::BEFORE || style()->styleType() == RenderStyle::AFTER) return; RenderStyle* pseudo = getPseudoStyle(type); // Whether or not we currently have generated content attached. bool oldContentPresent = child && (child->style()->styleType() == type); // Whether or not we now want generated content. bool newContentWanted = pseudo && pseudo->display() != NONE; // For <q><p/></q>, if this object is the inline continuation of the <q>, we only want to generate // :after content and not :before content. if (type == RenderStyle::BEFORE && isInlineContinuation()) newContentWanted = false; // Similarly, if we're the beginning of a <q>, and there's an inline continuation for our object, // then we don't generate the :after content. if (type == RenderStyle::AFTER && isRenderInline() && continuation()) newContentWanted = false; // If we don't want generated content any longer, or if we have generated content, but it's no longer // identical to the new content data we want to build render objects for, then we nuke all // of the old generated content. if (!newContentWanted || (oldContentPresent && !child->style()->contentDataEquivalent(pseudo))) { // Nuke the child. if (child && child->style()->styleType() == type) { oldContentPresent = false; removeChild(child); child = (type == RenderStyle::BEFORE) ? firstChild() : lastChild(); } } // If we have no pseudo-style or if the pseudo's display type is NONE, then we // have no generated content and can now return. if (!newContentWanted) return; if (isInlineFlow() && pseudo->display() != INLINE) // According to the CSS2 spec (the end of section 12.1), the only allowed // display values for the pseudo style are NONE and INLINE. Since we already // determined that the pseudo is not display NONE, any display other than // inline should be mutated to INLINE. pseudo->setDisplay(INLINE); if (oldContentPresent) { if (child && child->style()->styleType() == type) { // We have generated content present still. We want to walk this content and update our // style information with the new pseudo style. child->setStyle(pseudo); // Note that if we ever support additional types of generated content (which should be way off // in the future), this code will need to be patched. for (RenderObject* genChild = child->firstChild(); genChild; genChild = genChild->nextSibling()) { if (genChild->isText()) // Generated text content is a child whose style also needs to be set to the pseudo // style. genChild->setStyle(pseudo); else { // Images get an empty style that inherits from the pseudo. RenderStyle* style = new (renderArena()) RenderStyle(); style->inheritFrom(pseudo); genChild->setStyle(style); } } } return; // We've updated the generated content. That's all we needed to do. } RenderObject* insertBefore = (type == RenderStyle::BEFORE) ? child : 0; // Generated content consists of a single container that houses multiple children (specified // by the content property). This pseudo container gets the pseudo style set on it. RenderObject* pseudoContainer = 0; // Now walk our list of generated content and create render objects for every type // we encounter. for (ContentData* contentData = pseudo->contentData(); contentData; contentData = contentData->_nextContent) { if (!pseudoContainer) pseudoContainer = RenderFlow::createAnonymousFlow(document(), pseudo); /* anonymous box */ if (contentData->contentType() == CONTENT_TEXT) { RenderText* t = new (renderArena()) RenderTextFragment(document() /*anonymous object */, contentData->contentText()); t->setStyle(pseudo); pseudoContainer->addChild(t); } else if (contentData->contentType() == CONTENT_OBJECT) { RenderImage* img = new (renderArena()) RenderImage(document()); /* Anonymous object */ RenderStyle* style = new (renderArena()) RenderStyle(); style->inheritFrom(pseudo); img->setStyle(style); img->setContentObject(contentData->contentObject()); pseudoContainer->addChild(img); } } if (pseudoContainer) { // Add the pseudo after we've installed all our content, so that addChild will be able to find the text // inside the inline for e.g., first-letter styling. addChild(pseudoContainer, insertBefore); } }