Home | History | Annotate | Download | only in rendering
      1 /*
      2  * Copyright (C) 2009 Apple Inc.  All rights reserved.
      3  * Copyright (C) Research In Motion Limited 2010. All rights reserved.
      4  *
      5  * Redistribution and use in source and binary forms, with or without
      6  * modification, are permitted provided that the following conditions
      7  * are met:
      8  * 1. Redistributions of source code must retain the above copyright
      9  *    notice, this list of conditions and the following disclaimer.
     10  * 2. Redistributions in binary form must reproduce the above copyright
     11  *    notice, this list of conditions and the following disclaimer in the
     12  *    documentation and/or other materials provided with the distribution.
     13  *
     14  * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
     15  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     17  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
     18  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
     19  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
     20  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
     21  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
     22  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     23  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     24  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     25  */
     26 
     27 #include "config.h"
     28 #include "RenderObjectChildList.h"
     29 
     30 #include "AXObjectCache.h"
     31 #include "RenderBlock.h"
     32 #include "RenderCounter.h"
     33 #include "RenderImageGeneratedContent.h"
     34 #include "RenderInline.h"
     35 #include "RenderLayer.h"
     36 #include "RenderListItem.h"
     37 #include "RenderStyle.h"
     38 #include "RenderTextFragment.h"
     39 #include "RenderView.h"
     40 
     41 namespace WebCore {
     42 
     43 static void updateListMarkerNumbers(RenderObject* child)
     44 {
     45     for (RenderObject* sibling = child; sibling; sibling = sibling->nextSibling()) {
     46         if (sibling->isListItem())
     47             toRenderListItem(sibling)->updateValue();
     48     }
     49 }
     50 
     51 void RenderObjectChildList::destroyLeftoverChildren()
     52 {
     53     while (firstChild()) {
     54         if (firstChild()->isListMarker() || (firstChild()->style()->styleType() == FIRST_LETTER && !firstChild()->isText()))
     55             firstChild()->remove();  // List markers are owned by their enclosing list and so don't get destroyed by this container. Similarly, first letters are destroyed by their remaining text fragment.
     56         else if (firstChild()->isRunIn() && firstChild()->node()) {
     57             firstChild()->node()->setRenderer(0);
     58             firstChild()->node()->setNeedsStyleRecalc();
     59             firstChild()->destroy();
     60         } else {
     61             // Destroy any anonymous children remaining in the render tree, as well as implicit (shadow) DOM elements like those used in the engine-based text fields.
     62             if (firstChild()->node())
     63                 firstChild()->node()->setRenderer(0);
     64             firstChild()->destroy();
     65         }
     66     }
     67 }
     68 
     69 RenderObject* RenderObjectChildList::removeChildNode(RenderObject* owner, RenderObject* oldChild, bool fullRemove)
     70 {
     71     ASSERT(oldChild->parent() == owner);
     72 
     73     // So that we'll get the appropriate dirty bit set (either that a normal flow child got yanked or
     74     // that a positioned child got yanked).  We also repaint, so that the area exposed when the child
     75     // disappears gets repainted properly.
     76     if (!owner->documentBeingDestroyed() && fullRemove && oldChild->m_everHadLayout) {
     77         oldChild->setNeedsLayoutAndPrefWidthsRecalc();
     78         oldChild->repaint();
     79     }
     80 
     81     // If we have a line box wrapper, delete it.
     82     if (oldChild->isBox())
     83         toRenderBox(oldChild)->deleteLineBoxWrapper();
     84 
     85     if (!owner->documentBeingDestroyed() && fullRemove) {
     86         // if we remove visible child from an invisible parent, we don't know the layer visibility any more
     87         RenderLayer* layer = 0;
     88         if (owner->style()->visibility() != VISIBLE && oldChild->style()->visibility() == VISIBLE && !oldChild->hasLayer()) {
     89             layer = owner->enclosingLayer();
     90             layer->dirtyVisibleContentStatus();
     91         }
     92 
     93          // Keep our layer hierarchy updated.
     94         if (oldChild->firstChild() || oldChild->hasLayer()) {
     95             if (!layer)
     96                 layer = owner->enclosingLayer();
     97             oldChild->removeLayers(layer);
     98         }
     99 
    100         // renumber ordered lists
    101         if (oldChild->isListItem())
    102             updateListMarkerNumbers(oldChild->nextSibling());
    103 
    104         if (oldChild->isPositioned() && owner->childrenInline())
    105             owner->dirtyLinesFromChangedChild(oldChild);
    106     }
    107 
    108     // If oldChild is the start or end of the selection, then clear the selection to
    109     // avoid problems of invalid pointers.
    110     // FIXME: The SelectionController should be responsible for this when it
    111     // is notified of DOM mutations.
    112     if (!owner->documentBeingDestroyed() && oldChild->isSelectionBorder())
    113         owner->view()->clearSelection();
    114 
    115     // remove the child
    116     if (oldChild->previousSibling())
    117         oldChild->previousSibling()->setNextSibling(oldChild->nextSibling());
    118     if (oldChild->nextSibling())
    119         oldChild->nextSibling()->setPreviousSibling(oldChild->previousSibling());
    120 
    121     if (firstChild() == oldChild)
    122         setFirstChild(oldChild->nextSibling());
    123     if (lastChild() == oldChild)
    124         setLastChild(oldChild->previousSibling());
    125 
    126     oldChild->setPreviousSibling(0);
    127     oldChild->setNextSibling(0);
    128     oldChild->setParent(0);
    129 
    130     if (AXObjectCache::accessibilityEnabled())
    131         owner->document()->axObjectCache()->childrenChanged(owner);
    132 
    133     return oldChild;
    134 }
    135 
    136 void RenderObjectChildList::appendChildNode(RenderObject* owner, RenderObject* newChild, bool fullAppend)
    137 {
    138     ASSERT(newChild->parent() == 0);
    139     ASSERT(!owner->isBlockFlow() || (!newChild->isTableSection() && !newChild->isTableRow() && !newChild->isTableCell()));
    140 
    141     newChild->setParent(owner);
    142     RenderObject* lChild = lastChild();
    143 
    144     if (lChild) {
    145         newChild->setPreviousSibling(lChild);
    146         lChild->setNextSibling(newChild);
    147     } else
    148         setFirstChild(newChild);
    149 
    150     setLastChild(newChild);
    151 
    152     if (fullAppend) {
    153         // Keep our layer hierarchy updated.  Optimize for the common case where we don't have any children
    154         // and don't have a layer attached to ourselves.
    155         RenderLayer* layer = 0;
    156         if (newChild->firstChild() || newChild->hasLayer()) {
    157             layer = owner->enclosingLayer();
    158             newChild->addLayers(layer, newChild);
    159         }
    160 
    161         // if the new child is visible but this object was not, tell the layer it has some visible content
    162         // that needs to be drawn and layer visibility optimization can't be used
    163         if (owner->style()->visibility() != VISIBLE && newChild->style()->visibility() == VISIBLE && !newChild->hasLayer()) {
    164             if (!layer)
    165                 layer = owner->enclosingLayer();
    166             if (layer)
    167                 layer->setHasVisibleContent(true);
    168         }
    169 
    170         if (!newChild->isFloatingOrPositioned() && owner->childrenInline())
    171             owner->dirtyLinesFromChangedChild(newChild);
    172     }
    173 
    174     newChild->setNeedsLayoutAndPrefWidthsRecalc(); // Goes up the containing block hierarchy.
    175     if (!owner->normalChildNeedsLayout())
    176         owner->setChildNeedsLayout(true); // We may supply the static position for an absolute positioned child.
    177 
    178     if (AXObjectCache::accessibilityEnabled())
    179         owner->document()->axObjectCache()->childrenChanged(owner);
    180 }
    181 
    182 void RenderObjectChildList::insertChildNode(RenderObject* owner, RenderObject* child, RenderObject* beforeChild, bool fullInsert)
    183 {
    184     if (!beforeChild) {
    185         appendChildNode(owner, child);
    186         return;
    187     }
    188 
    189     ASSERT(!child->parent());
    190     while (beforeChild->parent() != owner && beforeChild->parent()->isAnonymousBlock())
    191         beforeChild = beforeChild->parent();
    192     ASSERT(beforeChild->parent() == owner);
    193 
    194     ASSERT(!owner->isBlockFlow() || (!child->isTableSection() && !child->isTableRow() && !child->isTableCell()));
    195 
    196     if (beforeChild == firstChild())
    197         setFirstChild(child);
    198 
    199     RenderObject* prev = beforeChild->previousSibling();
    200     child->setNextSibling(beforeChild);
    201     beforeChild->setPreviousSibling(child);
    202     if (prev)
    203         prev->setNextSibling(child);
    204     child->setPreviousSibling(prev);
    205 
    206     child->setParent(owner);
    207 
    208     if (fullInsert) {
    209         // Keep our layer hierarchy updated.  Optimize for the common case where we don't have any children
    210         // and don't have a layer attached to ourselves.
    211         RenderLayer* layer = 0;
    212         if (child->firstChild() || child->hasLayer()) {
    213             layer = owner->enclosingLayer();
    214             child->addLayers(layer, child);
    215         }
    216 
    217         // if the new child is visible but this object was not, tell the layer it has some visible content
    218         // that needs to be drawn and layer visibility optimization can't be used
    219         if (owner->style()->visibility() != VISIBLE && child->style()->visibility() == VISIBLE && !child->hasLayer()) {
    220             if (!layer)
    221                 layer = owner->enclosingLayer();
    222             if (layer)
    223                 layer->setHasVisibleContent(true);
    224         }
    225 
    226 
    227         if (!child->isFloating() && owner->childrenInline())
    228             owner->dirtyLinesFromChangedChild(child);
    229     }
    230 
    231     child->setNeedsLayoutAndPrefWidthsRecalc();
    232     if (!owner->normalChildNeedsLayout())
    233         owner->setChildNeedsLayout(true); // We may supply the static position for an absolute positioned child.
    234 
    235     if (AXObjectCache::accessibilityEnabled())
    236         owner->document()->axObjectCache()->childrenChanged(owner);
    237 }
    238 
    239 static RenderObject* beforeAfterContainer(RenderObject* container, PseudoId type)
    240 {
    241     if (type == BEFORE) {
    242         RenderObject* first = container;
    243         do {
    244             // Skip list markers.
    245             first = first->firstChild();
    246             while (first && first->isListMarker())
    247                 first = first->nextSibling();
    248         } while (first && first->isAnonymous() && first->style()->styleType() == NOPSEUDO);
    249         if (first && first->style()->styleType() != type)
    250             return 0;
    251         return first;
    252     }
    253     if (type == AFTER) {
    254         RenderObject* last = container;
    255         do {
    256             last = last->lastChild();
    257         } while (last && last->isAnonymous() && last->style()->styleType() == NOPSEUDO && !last->isListMarker());
    258         if (last && last->style()->styleType() != type)
    259             return 0;
    260         return last;
    261     }
    262 
    263     ASSERT_NOT_REACHED();
    264     return 0;
    265 }
    266 
    267 static RenderObject* findBeforeAfterParent(RenderObject* object)
    268 {
    269     // Only table parts need to search for the :before or :after parent
    270     if (!(object->isTable() || object->isTableSection() || object->isTableRow()))
    271         return object;
    272 
    273     RenderObject* beforeAfterParent = object;
    274     while (beforeAfterParent && !(beforeAfterParent->isText() || beforeAfterParent->isImage()))
    275         beforeAfterParent = beforeAfterParent->firstChild();
    276     return beforeAfterParent;
    277 }
    278 
    279 static void invalidateCountersInContainer(RenderObject* container, const AtomicString& identifier)
    280 {
    281     if (!container)
    282         return;
    283     container = findBeforeAfterParent(container);
    284     if (!container)
    285         return;
    286     // Sometimes the counter is attached directly on the container.
    287     if (container->isCounter()) {
    288         toRenderCounter(container)->invalidate(identifier);
    289         return;
    290     }
    291     for (RenderObject* content = container->firstChild(); content; content = content->nextSibling()) {
    292         if (content->isCounter())
    293             toRenderCounter(content)->invalidate(identifier);
    294     }
    295 }
    296 
    297 void RenderObjectChildList::invalidateCounters(RenderObject* owner, const AtomicString& identifier)
    298 {
    299     ASSERT(!owner->documentBeingDestroyed());
    300     invalidateCountersInContainer(beforeAfterContainer(owner, BEFORE), identifier);
    301     invalidateCountersInContainer(beforeAfterContainer(owner, AFTER), identifier);
    302 }
    303 
    304 void RenderObjectChildList::updateBeforeAfterContent(RenderObject* owner, PseudoId type, RenderObject* styledObject)
    305 {
    306     // Double check that the document did in fact use generated content rules.  Otherwise we should not have been called.
    307     ASSERT(owner->document()->usesBeforeAfterRules());
    308 
    309     // In CSS2, before/after pseudo-content cannot nest.  Check this first.
    310     if (owner->style()->styleType() == BEFORE || owner->style()->styleType() == AFTER)
    311         return;
    312 
    313     if (!styledObject)
    314         styledObject = owner;
    315 
    316     RenderStyle* pseudoElementStyle = styledObject->getCachedPseudoStyle(type);
    317     RenderObject* child = beforeAfterContainer(owner, type);
    318 
    319     // Whether or not we currently have generated content attached.
    320     bool oldContentPresent = child;
    321 
    322     // Whether or not we now want generated content.
    323     bool newContentWanted = pseudoElementStyle && pseudoElementStyle->display() != NONE;
    324 
    325     // For <q><p/></q>, if this object is the inline continuation of the <q>, we only want to generate
    326     // :after content and not :before content.
    327     if (newContentWanted && type == BEFORE && owner->isRenderInline() && toRenderInline(owner)->isInlineContinuation())
    328         newContentWanted = false;
    329 
    330     // Similarly, if we're the beginning of a <q>, and there's an inline continuation for our object,
    331     // then we don't generate the :after content.
    332     if (newContentWanted && type == AFTER && owner->isRenderInline() && toRenderInline(owner)->continuation())
    333         newContentWanted = false;
    334 
    335     // If we don't want generated content any longer, or if we have generated content, but it's no longer
    336     // identical to the new content data we want to build render objects for, then we nuke all
    337     // of the old generated content.
    338     if (!newContentWanted || (oldContentPresent && Node::diff(child->style(), pseudoElementStyle) == Node::Detach)) {
    339         // Nuke the child.
    340         if (child && child->style()->styleType() == type) {
    341             oldContentPresent = false;
    342             child->destroy();
    343             child = (type == BEFORE) ? owner->virtualChildren()->firstChild() : owner->virtualChildren()->lastChild();
    344         }
    345     }
    346 
    347     // If we have no pseudo-element style or if the pseudo-element style's display type is NONE, then we
    348     // have no generated content and can now return.
    349     if (!newContentWanted)
    350         return;
    351 
    352     if (owner->isRenderInline() && !pseudoElementStyle->isDisplayInlineType() && pseudoElementStyle->floating() == FNONE &&
    353         !(pseudoElementStyle->position() == AbsolutePosition || pseudoElementStyle->position() == FixedPosition))
    354         // According to the CSS2 spec (the end of section 12.1), the only allowed
    355         // display values for the pseudo style are NONE and INLINE for inline flows.
    356         // FIXME: CSS2.1 lifted this restriction, but block display types will crash.
    357         // For now we at least relax the restriction to allow all inline types like inline-block
    358         // and inline-table.
    359         pseudoElementStyle->setDisplay(INLINE);
    360 
    361     if (oldContentPresent) {
    362         if (child && child->style()->styleType() == type) {
    363             // We have generated content present still.  We want to walk this content and update our
    364             // style information with the new pseudo-element style.
    365             child->setStyle(pseudoElementStyle);
    366 
    367             RenderObject* beforeAfterParent = findBeforeAfterParent(child);
    368             if (!beforeAfterParent)
    369                 return;
    370 
    371             // Note that if we ever support additional types of generated content (which should be way off
    372             // in the future), this code will need to be patched.
    373             for (RenderObject* genChild = beforeAfterParent->firstChild(); genChild; genChild = genChild->nextSibling()) {
    374                 if (genChild->isText())
    375                     // Generated text content is a child whose style also needs to be set to the pseudo-element style.
    376                     genChild->setStyle(pseudoElementStyle);
    377                 else if (genChild->isImage()) {
    378                     // Images get an empty style that inherits from the pseudo.
    379                     RefPtr<RenderStyle> style = RenderStyle::create();
    380                     style->inheritFrom(pseudoElementStyle);
    381                     genChild->setStyle(style.release());
    382                 } else {
    383                     // RenderListItem may insert a list marker here. We do not need to care about this case.
    384                     // Otherwise, genChild must be a first-letter container. updateFirstLetter() will take care of it.
    385                     ASSERT(genChild->isListMarker() || genChild->style()->styleType() == FIRST_LETTER);
    386                 }
    387             }
    388         }
    389         return; // We've updated the generated content. That's all we needed to do.
    390     }
    391 
    392     RenderObject* insertBefore = (type == BEFORE) ? owner->virtualChildren()->firstChild() : 0;
    393 
    394     // Generated content consists of a single container that houses multiple children (specified
    395     // by the content property).  This generated content container gets the pseudo-element style set on it.
    396     RenderObject* generatedContentContainer = 0;
    397 
    398     // Walk our list of generated content and create render objects for each.
    399     for (const ContentData* content = pseudoElementStyle->contentData(); content; content = content->next()) {
    400         RenderObject* renderer = 0;
    401         switch (content->type()) {
    402             case CONTENT_NONE:
    403                 break;
    404             case CONTENT_TEXT:
    405                 renderer = new (owner->renderArena()) RenderTextFragment(owner->document() /* anonymous object */, content->text());
    406                 renderer->setStyle(pseudoElementStyle);
    407                 break;
    408             case CONTENT_OBJECT: {
    409                 RenderImageGeneratedContent* image = new (owner->renderArena()) RenderImageGeneratedContent(owner->document()); // anonymous object
    410                 RefPtr<RenderStyle> style = RenderStyle::create();
    411                 style->inheritFrom(pseudoElementStyle);
    412                 image->setStyle(style.release());
    413                 if (StyleImage* styleImage = content->image())
    414                     image->setStyleImage(styleImage);
    415                 renderer = image;
    416                 break;
    417             }
    418             case CONTENT_COUNTER:
    419                 renderer = new (owner->renderArena()) RenderCounter(owner->document(), *content->counter());
    420                 renderer->setStyle(pseudoElementStyle);
    421                 break;
    422         }
    423 
    424         if (renderer) {
    425             if (!generatedContentContainer) {
    426                 // Make a generated box that might be any display type now that we are able to drill down into children
    427                 // to find the original content properly.
    428                 generatedContentContainer = RenderObject::createObject(owner->document(), pseudoElementStyle);
    429                 generatedContentContainer->setStyle(pseudoElementStyle);
    430                 owner->addChild(generatedContentContainer, insertBefore);
    431             }
    432             if (generatedContentContainer->isChildAllowed(renderer, pseudoElementStyle))
    433                 generatedContentContainer->addChild(renderer);
    434             else
    435                 renderer->destroy();
    436         }
    437     }
    438 }
    439 
    440 } // namespace WebCore
    441