Home | History | Annotate | Download | only in rendering
      1 /*
      2  * Copyright (C) 2009, 2010 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 "ContentData.h"
     32 #include "RenderBlock.h"
     33 #include "RenderCounter.h"
     34 #include "RenderImage.h"
     35 #include "RenderImageResourceStyleImage.h"
     36 #include "RenderInline.h"
     37 #include "RenderLayer.h"
     38 #include "RenderListItem.h"
     39 #include "RenderQuote.h"
     40 #include "RenderStyle.h"
     41 #include "RenderTextFragment.h"
     42 #include "RenderView.h"
     43 
     44 namespace WebCore {
     45 
     46 void RenderObjectChildList::destroyLeftoverChildren()
     47 {
     48     while (firstChild()) {
     49         if (firstChild()->isListMarker() || (firstChild()->style()->styleType() == FIRST_LETTER && !firstChild()->isText()))
     50             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.
     51         else if (firstChild()->isRunIn() && firstChild()->node()) {
     52             firstChild()->node()->setRenderer(0);
     53             firstChild()->node()->setNeedsStyleRecalc();
     54             firstChild()->destroy();
     55         } else {
     56             // 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.
     57             if (firstChild()->node())
     58                 firstChild()->node()->setRenderer(0);
     59             firstChild()->destroy();
     60         }
     61     }
     62 }
     63 
     64 RenderObject* RenderObjectChildList::removeChildNode(RenderObject* owner, RenderObject* oldChild, bool fullRemove)
     65 {
     66     ASSERT(oldChild->parent() == owner);
     67 
     68     // So that we'll get the appropriate dirty bit set (either that a normal flow child got yanked or
     69     // that a positioned child got yanked).  We also repaint, so that the area exposed when the child
     70     // disappears gets repainted properly.
     71     if (!owner->documentBeingDestroyed() && fullRemove && oldChild->m_everHadLayout) {
     72         oldChild->setNeedsLayoutAndPrefWidthsRecalc();
     73         if (oldChild->isBody())
     74             owner->view()->repaint();
     75         else
     76             oldChild->repaint();
     77     }
     78 
     79     // If we have a line box wrapper, delete it.
     80     if (oldChild->isBox())
     81         toRenderBox(oldChild)->deleteLineBoxWrapper();
     82 
     83     if (!owner->documentBeingDestroyed() && fullRemove) {
     84         // if we remove visible child from an invisible parent, we don't know the layer visibility any more
     85         RenderLayer* layer = 0;
     86         if (owner->style()->visibility() != VISIBLE && oldChild->style()->visibility() == VISIBLE && !oldChild->hasLayer()) {
     87             layer = owner->enclosingLayer();
     88             layer->dirtyVisibleContentStatus();
     89         }
     90 
     91          // Keep our layer hierarchy updated.
     92         if (oldChild->firstChild() || oldChild->hasLayer()) {
     93             if (!layer)
     94                 layer = owner->enclosingLayer();
     95             oldChild->removeLayers(layer);
     96         }
     97 
     98         if (oldChild->isListItem())
     99             toRenderListItem(oldChild)->updateListMarkerNumbers();
    100 
    101         if (oldChild->isPositioned() && owner->childrenInline())
    102             owner->dirtyLinesFromChangedChild(oldChild);
    103 
    104 #if ENABLE(SVG)
    105         // Update cached boundaries in SVG renderers, if a child is removed.
    106         owner->setNeedsBoundariesUpdate();
    107 #endif
    108     }
    109 
    110     // If oldChild is the start or end of the selection, then clear the selection to
    111     // avoid problems of invalid pointers.
    112     // FIXME: The SelectionController should be responsible for this when it
    113     // is notified of DOM mutations.
    114     if (!owner->documentBeingDestroyed() && oldChild->isSelectionBorder())
    115         owner->view()->clearSelection();
    116 
    117     // remove the child
    118     if (oldChild->previousSibling())
    119         oldChild->previousSibling()->setNextSibling(oldChild->nextSibling());
    120     if (oldChild->nextSibling())
    121         oldChild->nextSibling()->setPreviousSibling(oldChild->previousSibling());
    122 
    123     if (firstChild() == oldChild)
    124         setFirstChild(oldChild->nextSibling());
    125     if (lastChild() == oldChild)
    126         setLastChild(oldChild->previousSibling());
    127 
    128     oldChild->setPreviousSibling(0);
    129     oldChild->setNextSibling(0);
    130     oldChild->setParent(0);
    131 
    132     RenderCounter::rendererRemovedFromTree(oldChild);
    133     RenderQuote::rendererRemovedFromTree(oldChild);
    134 
    135     if (AXObjectCache::accessibilityEnabled())
    136         owner->document()->axObjectCache()->childrenChanged(owner);
    137 
    138     return oldChild;
    139 }
    140 
    141 void RenderObjectChildList::appendChildNode(RenderObject* owner, RenderObject* newChild, bool fullAppend)
    142 {
    143     ASSERT(newChild->parent() == 0);
    144     ASSERT(!owner->isBlockFlow() || (!newChild->isTableSection() && !newChild->isTableRow() && !newChild->isTableCell()));
    145 
    146     newChild->setParent(owner);
    147     RenderObject* lChild = lastChild();
    148 
    149     if (lChild) {
    150         newChild->setPreviousSibling(lChild);
    151         lChild->setNextSibling(newChild);
    152     } else
    153         setFirstChild(newChild);
    154 
    155     setLastChild(newChild);
    156 
    157     if (fullAppend) {
    158         // Keep our layer hierarchy updated.  Optimize for the common case where we don't have any children
    159         // and don't have a layer attached to ourselves.
    160         RenderLayer* layer = 0;
    161         if (newChild->firstChild() || newChild->hasLayer()) {
    162             layer = owner->enclosingLayer();
    163             newChild->addLayers(layer, newChild);
    164         }
    165 
    166         // if the new child is visible but this object was not, tell the layer it has some visible content
    167         // that needs to be drawn and layer visibility optimization can't be used
    168         if (owner->style()->visibility() != VISIBLE && newChild->style()->visibility() == VISIBLE && !newChild->hasLayer()) {
    169             if (!layer)
    170                 layer = owner->enclosingLayer();
    171             if (layer)
    172                 layer->setHasVisibleContent(true);
    173         }
    174 
    175         if (newChild->isListItem())
    176             toRenderListItem(newChild)->updateListMarkerNumbers();
    177 
    178         if (!newChild->isFloatingOrPositioned() && owner->childrenInline())
    179             owner->dirtyLinesFromChangedChild(newChild);
    180     }
    181     RenderCounter::rendererSubtreeAttached(newChild);
    182     RenderQuote::rendererSubtreeAttached(newChild);
    183     newChild->setNeedsLayoutAndPrefWidthsRecalc(); // Goes up the containing block hierarchy.
    184     if (!owner->normalChildNeedsLayout())
    185         owner->setChildNeedsLayout(true); // We may supply the static position for an absolute positioned child.
    186 
    187     if (AXObjectCache::accessibilityEnabled())
    188         owner->document()->axObjectCache()->childrenChanged(owner);
    189 }
    190 
    191 void RenderObjectChildList::insertChildNode(RenderObject* owner, RenderObject* child, RenderObject* beforeChild, bool fullInsert)
    192 {
    193     if (!beforeChild) {
    194         appendChildNode(owner, child, fullInsert);
    195         return;
    196     }
    197 
    198     ASSERT(!child->parent());
    199     while (beforeChild->parent() != owner && beforeChild->parent()->isAnonymousBlock())
    200         beforeChild = beforeChild->parent();
    201     ASSERT(beforeChild->parent() == owner);
    202 
    203     ASSERT(!owner->isBlockFlow() || (!child->isTableSection() && !child->isTableRow() && !child->isTableCell()));
    204 
    205     if (beforeChild == firstChild())
    206         setFirstChild(child);
    207 
    208     RenderObject* prev = beforeChild->previousSibling();
    209     child->setNextSibling(beforeChild);
    210     beforeChild->setPreviousSibling(child);
    211     if (prev)
    212         prev->setNextSibling(child);
    213     child->setPreviousSibling(prev);
    214 
    215     child->setParent(owner);
    216 
    217     if (fullInsert) {
    218         // Keep our layer hierarchy updated.  Optimize for the common case where we don't have any children
    219         // and don't have a layer attached to ourselves.
    220         RenderLayer* layer = 0;
    221         if (child->firstChild() || child->hasLayer()) {
    222             layer = owner->enclosingLayer();
    223             child->addLayers(layer, child);
    224         }
    225 
    226         // if the new child is visible but this object was not, tell the layer it has some visible content
    227         // that needs to be drawn and layer visibility optimization can't be used
    228         if (owner->style()->visibility() != VISIBLE && child->style()->visibility() == VISIBLE && !child->hasLayer()) {
    229             if (!layer)
    230                 layer = owner->enclosingLayer();
    231             if (layer)
    232                 layer->setHasVisibleContent(true);
    233         }
    234 
    235         if (child->isListItem())
    236             toRenderListItem(child)->updateListMarkerNumbers();
    237 
    238         if (!child->isFloating() && owner->childrenInline())
    239             owner->dirtyLinesFromChangedChild(child);
    240     }
    241 
    242     RenderCounter::rendererSubtreeAttached(child);
    243     RenderQuote::rendererSubtreeAttached(child);
    244     child->setNeedsLayoutAndPrefWidthsRecalc();
    245     if (!owner->normalChildNeedsLayout())
    246         owner->setChildNeedsLayout(true); // We may supply the static position for an absolute positioned child.
    247 
    248     if (AXObjectCache::accessibilityEnabled())
    249         owner->document()->axObjectCache()->childrenChanged(owner);
    250 }
    251 
    252 static RenderObject* findBeforeAfterParent(RenderObject* object)
    253 {
    254     // Only table parts need to search for the :before or :after parent
    255     if (!(object->isTable() || object->isTableSection() || object->isTableRow()))
    256         return object;
    257 
    258     RenderObject* beforeAfterParent = object;
    259     while (beforeAfterParent && !(beforeAfterParent->isText() || beforeAfterParent->isImage()))
    260         beforeAfterParent = beforeAfterParent->firstChild();
    261     return beforeAfterParent ? beforeAfterParent->parent() : 0;
    262 }
    263 
    264 RenderObject* RenderObjectChildList::beforePseudoElementRenderer(const RenderObject* owner) const
    265 {
    266     // An anonymous (generated) inline run-in that has PseudoId BEFORE must come from a grandparent.
    267     // Therefore we should skip these generated run-ins when checking our immediate children.
    268     // If we don't find our :before child immediately, then we should check if we own a
    269     // generated inline run-in in the next level of children.
    270     RenderObject* first = const_cast<RenderObject*>(owner);
    271     do {
    272         first = first->firstChild();
    273         // Skip list markers and generated run-ins.
    274         while (first && (first->isListMarker() || (first->isRenderInline() && first->isRunIn())))
    275             first = first->nextInPreOrderAfterChildren(owner);
    276     } while (first && first->isAnonymous() && first->style()->styleType() == NOPSEUDO);
    277 
    278     if (!first)
    279         return 0;
    280 
    281     if (first->style()->styleType() == BEFORE)
    282         return first;
    283 
    284     // Check for a possible generated run-in, using run-in positioning rules.
    285     first = owner->firstChild();
    286     if (!first->isRenderBlock())
    287         return 0;
    288 
    289     first = first->firstChild();
    290     // We still need to skip any list markers that could exist before the run-in.
    291     while (first && first->isListMarker())
    292         first = first->nextSibling();
    293     if (first && first->style()->styleType() == BEFORE && first->isRenderInline() && first->isRunIn())
    294         return first;
    295 
    296     return 0;
    297 }
    298 
    299 RenderObject* RenderObjectChildList::afterPseudoElementRenderer(const RenderObject* owner) const
    300 {
    301     RenderObject* last = const_cast<RenderObject*>(owner);
    302     do {
    303         last = last->lastChild();
    304     } while (last && last->isAnonymous() && last->style()->styleType() == NOPSEUDO && !last->isListMarker());
    305     if (last && last->style()->styleType() != AFTER)
    306         return 0;
    307     return last;
    308 }
    309 
    310 void RenderObjectChildList::updateBeforeAfterContent(RenderObject* owner, PseudoId type, const RenderObject* styledObject)
    311 {
    312     // Double check that the document did in fact use generated content rules.  Otherwise we should not have been called.
    313     ASSERT(owner->document()->usesBeforeAfterRules());
    314 
    315     // In CSS2, before/after pseudo-content cannot nest.  Check this first.
    316     if (owner->style()->styleType() == BEFORE || owner->style()->styleType() == AFTER)
    317         return;
    318 
    319     if (!styledObject)
    320         styledObject = owner;
    321 
    322     RenderStyle* pseudoElementStyle = styledObject->getCachedPseudoStyle(type);
    323     RenderObject* child;
    324     switch (type) {
    325     case BEFORE:
    326         child = beforePseudoElementRenderer(owner);
    327         break;
    328     case AFTER:
    329         child = afterPseudoElementRenderer(owner);
    330         break;
    331     default:
    332         ASSERT_NOT_REACHED();
    333         return;
    334     }
    335 
    336     // Whether or not we currently have generated content attached.
    337     bool oldContentPresent = child;
    338 
    339     // Whether or not we now want generated content.
    340     bool newContentWanted = pseudoElementStyle && pseudoElementStyle->display() != NONE;
    341 
    342     // For <q><p/></q>, if this object is the inline continuation of the <q>, we only want to generate
    343     // :after content and not :before content.
    344     if (newContentWanted && type == BEFORE && owner->isElementContinuation())
    345         newContentWanted = false;
    346 
    347     // Similarly, if we're the beginning of a <q>, and there's an inline continuation for our object,
    348     // then we don't generate the :after content.
    349     if (newContentWanted && type == AFTER && owner->virtualContinuation())
    350         newContentWanted = false;
    351 
    352     // If we don't want generated content any longer, or if we have generated content, but it's no longer
    353     // identical to the new content data we want to build render objects for, then we nuke all
    354     // of the old generated content.
    355     if (oldContentPresent && (!newContentWanted || Node::diff(child->style(), pseudoElementStyle) == Node::Detach)) {
    356         // Nuke the child.
    357         if (child->style()->styleType() == type) {
    358             oldContentPresent = false;
    359             child->destroy();
    360             child = (type == BEFORE) ? owner->virtualChildren()->firstChild() : owner->virtualChildren()->lastChild();
    361         }
    362     }
    363 
    364     // If we have no pseudo-element style or if the pseudo-element style's display type is NONE, then we
    365     // have no generated content and can now return.
    366     if (!newContentWanted)
    367         return;
    368 
    369     if (owner->isRenderInline() && !pseudoElementStyle->isDisplayInlineType() && pseudoElementStyle->floating() == FNONE &&
    370         !(pseudoElementStyle->position() == AbsolutePosition || pseudoElementStyle->position() == FixedPosition))
    371         // According to the CSS2 spec (the end of section 12.1), the only allowed
    372         // display values for the pseudo style are NONE and INLINE for inline flows.
    373         // FIXME: CSS2.1 lifted this restriction, but block display types will crash.
    374         // For now we at least relax the restriction to allow all inline types like inline-block
    375         // and inline-table.
    376         pseudoElementStyle->setDisplay(INLINE);
    377 
    378     if (oldContentPresent) {
    379         if (child && child->style()->styleType() == type) {
    380             // We have generated content present still.  We want to walk this content and update our
    381             // style information with the new pseudo-element style.
    382             child->setStyle(pseudoElementStyle);
    383 
    384             RenderObject* beforeAfterParent = findBeforeAfterParent(child);
    385             if (!beforeAfterParent)
    386                 return;
    387 
    388             // Note that if we ever support additional types of generated content (which should be way off
    389             // in the future), this code will need to be patched.
    390             for (RenderObject* genChild = beforeAfterParent->firstChild(); genChild; genChild = genChild->nextSibling()) {
    391                 if (genChild->isText())
    392                     // Generated text content is a child whose style also needs to be set to the pseudo-element style.
    393                     genChild->setStyle(pseudoElementStyle);
    394                 else if (genChild->isImage()) {
    395                     // Images get an empty style that inherits from the pseudo.
    396                     RefPtr<RenderStyle> style = RenderStyle::create();
    397                     style->inheritFrom(pseudoElementStyle);
    398                     genChild->setStyle(style.release());
    399                 } else {
    400                     // RenderListItem may insert a list marker here. We do not need to care about this case.
    401                     // Otherwise, genChild must be a first-letter container. updateFirstLetter() will take care of it.
    402                     ASSERT(genChild->isListMarker() || genChild->style()->styleType() == FIRST_LETTER);
    403                 }
    404             }
    405         }
    406         return; // We've updated the generated content. That's all we needed to do.
    407     }
    408 
    409     RenderObject* insertBefore = (type == BEFORE) ? owner->virtualChildren()->firstChild() : 0;
    410 
    411     // Generated content consists of a single container that houses multiple children (specified
    412     // by the content property).  This generated content container gets the pseudo-element style set on it.
    413     RenderObject* generatedContentContainer = 0;
    414 
    415     // Walk our list of generated content and create render objects for each.
    416     for (const ContentData* content = pseudoElementStyle->contentData(); content; content = content->next()) {
    417         RenderObject* renderer = 0;
    418         switch (content->type()) {
    419             case CONTENT_NONE:
    420                 break;
    421             case CONTENT_TEXT:
    422                 renderer = new (owner->renderArena()) RenderTextFragment(owner->document() /* anonymous object */, content->text());
    423                 renderer->setStyle(pseudoElementStyle);
    424                 break;
    425             case CONTENT_OBJECT: {
    426                 RenderImage* image = new (owner->renderArena()) RenderImage(owner->document()); // anonymous object
    427                 RefPtr<RenderStyle> style = RenderStyle::create();
    428                 style->inheritFrom(pseudoElementStyle);
    429                 image->setStyle(style.release());
    430                 if (StyleImage* styleImage = content->image())
    431                     image->setImageResource(RenderImageResourceStyleImage::create(styleImage));
    432                 else
    433                     image->setImageResource(RenderImageResource::create());
    434                 renderer = image;
    435                 break;
    436             }
    437         case CONTENT_COUNTER:
    438             renderer = new (owner->renderArena()) RenderCounter(owner->document(), *content->counter());
    439             renderer->setStyle(pseudoElementStyle);
    440             break;
    441         case CONTENT_QUOTE:
    442             renderer = new (owner->renderArena()) RenderQuote(owner->document(), content->quote());
    443             renderer->setStyle(pseudoElementStyle);
    444             break;
    445         }
    446 
    447         if (renderer) {
    448             if (!generatedContentContainer) {
    449                 // Make a generated box that might be any display type now that we are able to drill down into children
    450                 // to find the original content properly.
    451                 generatedContentContainer = RenderObject::createObject(owner->document(), pseudoElementStyle);
    452                 ASSERT(styledObject->node()); // The styled object cannot be anonymous or else it could not have ':before' or ':after' pseudo elements.
    453                 generatedContentContainer->setNode(styledObject->node()); // This allows access to the generatingNode.
    454                 generatedContentContainer->setStyle(pseudoElementStyle);
    455                 if (!owner->isChildAllowed(generatedContentContainer, pseudoElementStyle)) {
    456                     // The generated content container is not allowed here -> abort.
    457                     generatedContentContainer->destroy();
    458                     renderer->destroy();
    459                     return;
    460                 }
    461                 owner->addChild(generatedContentContainer, insertBefore);
    462             }
    463             if (generatedContentContainer->isChildAllowed(renderer, pseudoElementStyle))
    464                 generatedContentContainer->addChild(renderer);
    465             else
    466                 renderer->destroy();
    467         }
    468     }
    469 }
    470 
    471 } // namespace WebCore
    472