static void invalidateCountersInContainer(RenderObject* container)
{
    if (!container)
        return;
    container = findBeforeAfterParent(container);
    if (!container)
        return;
    for (RenderObject* content = container->firstChild(); content; content = content->nextSibling()) {
        if (content->isCounter())
            toRenderCounter(content)->invalidate();
    }
}
예제 #2
0
void RenderObjectChildList::updateBeforeAfterStyle(RenderObject* child, PseudoId type, RenderStyle* pseudoElementStyle)
{
    if (!child || child->style()->styleType() != type)
        return;

    // We have generated content present still. We want to walk this content and update our
    // style information with the new pseudo-element style.
    child->setStyle(pseudoElementStyle);

    RenderObject* beforeAfterParent = findBeforeAfterParent(child);
    if (!beforeAfterParent)
        return;

    // When beforeAfterParent is not equal to child (e.g. in tables),
    // we need to create new styles inheriting from pseudoElementStyle
    // on all the intermediate parents (leaving their display same).
    if (beforeAfterParent != child) {
        RenderObject* curr = beforeAfterParent;
        while (curr && curr != child) {
            ASSERT(curr->isAnonymous());
            RefPtr<RenderStyle> newStyle = RenderStyle::create();
            newStyle->inheritFrom(pseudoElementStyle);
            newStyle->setDisplay(curr->style()->display());
            newStyle->setStyleType(curr->style()->styleType());
            curr->setStyle(newStyle);
            curr = curr->parent();
        }
    }

    // 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 = beforeAfterParent->firstChild(); genChild; genChild = genChild->nextSibling()) {
        if (genChild->isText())
            // Generated text content is a child whose style also needs to be set to the pseudo-element style.
            genChild->setStyle(pseudoElementStyle);
        else if (genChild->isImage()) {
            // Images get an empty style that inherits from the pseudo.
            RefPtr<RenderStyle> style = RenderStyle::create();
            style->inheritFrom(pseudoElementStyle);
            genChild->setStyle(style.release());
        } else {
            // RenderListItem may insert a list marker here. We do not need to care about this case.
            // Otherwise, genChild must be a first-letter container. updateFirstLetter() will take care of it.
            ASSERT(genChild->isListMarker() || genChild->style()->styleType() == FIRST_LETTER);
        }
    }
}
예제 #3
0
static void invalidateCountersInContainer(RenderObject* container, const AtomicString& identifier)
{
    if (!container)
        return;
    container = findBeforeAfterParent(container);
    if (!container)
        return;
    // Sometimes the counter is attached directly on the container.
    if (container->isCounter()) {
        toRenderCounter(container)->invalidate(identifier);
        return;
    }
    for (RenderObject* content = container->firstChild(); content; content = content->nextSibling()) {
        if (content->isCounter())
            toRenderCounter(content)->invalidate(identifier);
    }
}
예제 #4
0
void RenderObjectChildList::updateBeforeAfterContent(RenderObject* owner, PseudoId type, RenderObject* styledObject)
{
    // Double check that the document did in fact use generated content rules.  Otherwise we should not have been called.
    ASSERT(owner->document()->usesBeforeAfterRules());

    // In CSS2, before/after pseudo-content cannot nest.  Check this first.
    if (owner->style()->styleType() == BEFORE || owner->style()->styleType() == AFTER)
        return;
    
    if (!styledObject)
        styledObject = owner;

    RenderStyle* pseudoElementStyle = styledObject->getCachedPseudoStyle(type);
    RenderObject* child = beforeAfterContainer(owner, type);

    // Whether or not we currently have generated content attached.
    bool oldContentPresent = child;

    // Whether or not we now want generated content.
    bool newContentWanted = pseudoElementStyle && pseudoElementStyle->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 (newContentWanted && type == BEFORE && owner->isElementContinuation())
        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 (newContentWanted && type == AFTER && owner->virtualContinuation())
        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 (oldContentPresent && (!newContentWanted || Node::diff(child->style(), pseudoElementStyle) == Node::Detach)) {
        // Nuke the child. 
        if (child->style()->styleType() == type) {
            oldContentPresent = false;
            child->destroy();
            child = (type == BEFORE) ? owner->virtualChildren()->firstChild() : owner->virtualChildren()->lastChild();
        }
    }

    // If we have no pseudo-element style or if the pseudo-element style's display type is NONE, then we
    // have no generated content and can now return.
    if (!newContentWanted)
        return;

    if (owner->isRenderInline() && !pseudoElementStyle->isDisplayInlineType() && pseudoElementStyle->floating() == FNONE &&
        !(pseudoElementStyle->position() == AbsolutePosition || pseudoElementStyle->position() == FixedPosition))
        // According to the CSS2 spec (the end of section 12.1), the only allowed
        // display values for the pseudo style are NONE and INLINE for inline flows.
        // FIXME: CSS2.1 lifted this restriction, but block display types will crash.
        // For now we at least relax the restriction to allow all inline types like inline-block
        // and inline-table.
        pseudoElementStyle->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-element style.
            child->setStyle(pseudoElementStyle);

            RenderObject* beforeAfterParent = findBeforeAfterParent(child);
            if (!beforeAfterParent)
                return;

            // 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 = beforeAfterParent->firstChild(); genChild; genChild = genChild->nextSibling()) {
                if (genChild->isText())
                    // Generated text content is a child whose style also needs to be set to the pseudo-element style.
                    genChild->setStyle(pseudoElementStyle);
                else if (genChild->isImage()) {
                    // Images get an empty style that inherits from the pseudo.
                    RefPtr<RenderStyle> style = RenderStyle::create();
                    style->inheritFrom(pseudoElementStyle);
                    genChild->setStyle(style.release());
                } else {
                    // RenderListItem may insert a list marker here. We do not need to care about this case.
                    // Otherwise, genChild must be a first-letter container. updateFirstLetter() will take care of it.
                    ASSERT(genChild->isListMarker() || genChild->style()->styleType() == FIRST_LETTER);
                }
            }
        }
        return; // We've updated the generated content. That's all we needed to do.
    }
    
    RenderObject* insertBefore = (type == BEFORE) ? owner->virtualChildren()->firstChild() : 0;

    // Generated content consists of a single container that houses multiple children (specified
    // by the content property).  This generated content container gets the pseudo-element style set on it.
    RenderObject* generatedContentContainer = 0;
    
    // Walk our list of generated content and create render objects for each.
    for (const ContentData* content = pseudoElementStyle->contentData(); content; content = content->next()) {
        RenderObject* renderer = 0;
        switch (content->type()) {
            case CONTENT_NONE:
                break;
            case CONTENT_TEXT:
                renderer = new (owner->renderArena()) RenderTextFragment(owner->document() /* anonymous object */, content->text());
                renderer->setStyle(pseudoElementStyle);
                break;
            case CONTENT_OBJECT: {
                RenderImageGeneratedContent* image = new (owner->renderArena()) RenderImageGeneratedContent(owner->document()); // anonymous object
                RefPtr<RenderStyle> style = RenderStyle::create();
                style->inheritFrom(pseudoElementStyle);
                image->setStyle(style.release());
                if (StyleImage* styleImage = content->image())
                    image->setStyleImage(styleImage);
                renderer = image;
                break;
            }
            case CONTENT_COUNTER:
                renderer = new (owner->renderArena()) RenderCounter(owner->document(), *content->counter());
                renderer->setStyle(pseudoElementStyle);
                break;
        }

        if (renderer) {
            if (!generatedContentContainer) {
                // Make a generated box that might be any display type now that we are able to drill down into children
                // to find the original content properly.
                generatedContentContainer = RenderObject::createObject(owner->document(), pseudoElementStyle);
                generatedContentContainer->setStyle(pseudoElementStyle);
                owner->addChild(generatedContentContainer, insertBefore);
            }
            generatedContentContainer->addChild(renderer);
        }
    }
}