--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/webengine/osswebengine/WebCore/rendering/RenderContainer.cpp Mon Mar 30 12:54:55 2009 +0300
@@ -0,0 +1,655 @@
+/**
+ * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
+ * (C) 1999 Antti Koivisto (koivisto@kde.org)
+ * (C) 2000 Dirk Mueller (mueller@kde.org)
+ * (C) 2004 Allan Sandfeld Jensen (kde@carewolf.com)
+ * Copyright (C) 2003, 2004, 2005, 2006, 2007 Apple Inc. All rights reserved.
+ * Copyright (C) 2006 Andrew Wellington (proton@wiretapped.net)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "config.h"
+#include "RenderContainer.h"
+
+#include "AXObjectCache.h"
+#include "Document.h"
+#include "RenderCounter.h"
+#include "RenderImage.h"
+#include "RenderLayer.h"
+#include "RenderListItem.h"
+#include "RenderTable.h"
+#include "RenderTextFragment.h"
+#include "RenderView.h"
+#include "htmlediting.h"
+
+namespace WebCore {
+
+RenderContainer::RenderContainer(Node* node)
+ : RenderBox(node)
+ , m_firstChild(0)
+ , m_lastChild(0)
+{
+}
+
+RenderContainer::~RenderContainer()
+{
+}
+
+void RenderContainer::destroy()
+{
+ destroyLeftoverChildren();
+ RenderBox::destroy();
+}
+
+void RenderContainer::destroyLeftoverChildren()
+{
+ while (m_firstChild) {
+ if (m_firstChild->isListMarker() || (m_firstChild->style()->styleType() == RenderStyle::FIRST_LETTER && !m_firstChild->isText()))
+ m_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.
+ else {
+ // 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.
+ if (m_firstChild->element())
+ m_firstChild->element()->setRenderer(0);
+ m_firstChild->destroy();
+ }
+ }
+}
+
+bool RenderContainer::canHaveChildren() const
+{
+ return true;
+}
+
+static void updateListMarkerNumbers(RenderObject* child)
+{
+ for (RenderObject* r = child; r; r = r->nextSibling())
+ if (r->isListItem())
+ static_cast<RenderListItem*>(r)->updateValue();
+}
+
+void RenderContainer::addChild(RenderObject* newChild, RenderObject* beforeChild)
+{
+ bool needsTable = false;
+
+ if (newChild->isListItem())
+ updateListMarkerNumbers(beforeChild ? beforeChild : m_lastChild);
+ else if (newChild->isTableCol() && newChild->style()->display() == TABLE_COLUMN_GROUP)
+ needsTable = !isTable();
+ else if (newChild->isRenderBlock() && newChild->style()->display() == TABLE_CAPTION)
+ needsTable = !isTable();
+ else if (newChild->isTableSection())
+ needsTable = !isTable();
+ else if (newChild->isTableRow())
+ needsTable = !isTableSection();
+ else if (newChild->isTableCell()) {
+ needsTable = !isTableRow();
+ // I'm not 100% sure this is the best way to fix this, but without this
+ // change we recurse infinitely when trying to render the CSS2 test page:
+ // http://www.bath.ac.uk/%7Epy8ieh/internet/eviltests/htmlbodyheadrendering2.html.
+ // See Radar 2925291.
+ if (needsTable && isTableCell() && !m_firstChild && !newChild->isTableCell())
+ needsTable = false;
+ }
+
+ if (needsTable) {
+ RenderTable *table;
+ if(!beforeChild)
+ beforeChild = m_lastChild;
+ if(beforeChild && beforeChild->isAnonymous() && beforeChild->isTable())
+ table = static_cast<RenderTable*>(beforeChild);
+ else {
+ table = new (renderArena()) RenderTable(document() /* is anonymous */);
+ RenderStyle *newStyle = new (renderArena()) RenderStyle;
+ newStyle->inheritFrom(style());
+ newStyle->setDisplay(TABLE);
+ table->setStyle(newStyle);
+ addChild(table, beforeChild);
+ }
+ table->addChild(newChild);
+ } else {
+ // just add it...
+ insertChildNode(newChild, beforeChild);
+ }
+
+ if (newChild->isText() && newChild->style()->textTransform() == CAPITALIZE) {
+ RefPtr<StringImpl> textToTransform = static_cast<RenderText*>(newChild)->originalText();
+ if (textToTransform)
+ static_cast<RenderText*>(newChild)->setText(textToTransform.release(), true);
+ }
+}
+
+RenderObject* RenderContainer::removeChildNode(RenderObject* oldChild, bool fullRemove)
+{
+ ASSERT(oldChild->parent() == this);
+
+ // So that we'll get the appropriate dirty bit set (either that a normal flow child got yanked or
+ // that a positioned child got yanked). We also repaint, so that the area exposed when the child
+ // disappears gets repainted properly.
+ if (!documentBeingDestroyed() && fullRemove) {
+ oldChild->setNeedsLayoutAndPrefWidthsRecalc();
+ oldChild->repaint();
+ }
+
+ // If we have a line box wrapper, delete it.
+ oldChild->deleteLineBoxWrapper();
+
+ if (!documentBeingDestroyed() && fullRemove) {
+ // if we remove visible child from an invisible parent, we don't know the layer visibility any more
+ RenderLayer* layer = 0;
+ if (m_style->visibility() != VISIBLE && oldChild->style()->visibility() == VISIBLE && !oldChild->hasLayer()) {
+ layer = enclosingLayer();
+ layer->dirtyVisibleContentStatus();
+ }
+
+ // Keep our layer hierarchy updated.
+ if (oldChild->firstChild() || oldChild->hasLayer()) {
+ if (!layer) layer = enclosingLayer();
+ oldChild->removeLayers(layer);
+ }
+
+ // renumber ordered lists
+ if (oldChild->isListItem())
+ updateListMarkerNumbers(oldChild->nextSibling());
+
+ if (oldChild->isPositioned() && childrenInline())
+ dirtyLinesFromChangedChild(oldChild);
+ }
+
+ // If oldChild is the start or end of the selection, then clear the selection to
+ // avoid problems of invalid pointers.
+ // FIXME: The SelectionController should be responsible for this when it
+ // is notified of DOM mutations.
+ if (!documentBeingDestroyed() && oldChild->isSelectionBorder())
+ view()->clearSelection();
+
+ // remove the child
+ if (oldChild->previousSibling())
+ oldChild->previousSibling()->setNextSibling(oldChild->nextSibling());
+ if (oldChild->nextSibling())
+ oldChild->nextSibling()->setPreviousSibling(oldChild->previousSibling());
+
+ if (m_firstChild == oldChild)
+ m_firstChild = oldChild->nextSibling();
+ if (m_lastChild == oldChild)
+ m_lastChild = oldChild->previousSibling();
+
+ oldChild->setPreviousSibling(0);
+ oldChild->setNextSibling(0);
+ oldChild->setParent(0);
+
+ if (AXObjectCache::accessibilityEnabled())
+ document()->axObjectCache()->childrenChanged(this);
+
+ return oldChild;
+}
+
+void RenderContainer::removeChild(RenderObject* oldChild)
+{
+ // We do this here instead of in removeChildNode, since the only extremely low-level uses of remove/appendChildNode
+ // cannot affect the positioned object list, and the floating object list is irrelevant (since the list gets cleared on
+ // layout anyway).
+ oldChild->removeFromObjectLists();
+
+ removeChildNode(oldChild);
+}
+
+RenderObject* RenderContainer::beforeAfterContainer(RenderStyle::PseudoId type)
+{
+ if (type == RenderStyle::BEFORE) {
+ RenderObject* first = this;
+ do {
+ // Skip list markers.
+ first = first->firstChild();
+ while (first && first->isListMarker())
+ first = first->nextSibling();
+ } while (first && first->isAnonymous() && first->style()->styleType() == RenderStyle::NOPSEUDO);
+ if (first && first->style()->styleType() != type)
+ return 0;
+ return first;
+ }
+ if (type == RenderStyle::AFTER) {
+ RenderObject* last = this;
+ do {
+ last = last->lastChild();
+ } while (last && last->isAnonymous() && last->style()->styleType() == RenderStyle::NOPSEUDO && !last->isListMarker());
+ if (last && last->style()->styleType() != type)
+ return 0;
+ return last;
+ }
+
+ ASSERT_NOT_REACHED();
+ return 0;
+}
+
+void RenderContainer::updateBeforeAfterContent(RenderStyle::PseudoId type)
+{
+ // If this is an anonymous wrapper, then the parent applies its own pseudo-element style to it.
+ if (parent() && parent()->createsAnonymousWrapper())
+ return;
+ updateBeforeAfterContentForContainer(type, this);
+}
+
+void RenderContainer::updateBeforeAfterContentForContainer(RenderStyle::PseudoId type, RenderContainer* styledObject)
+{
+ // In CSS2, before/after pseudo-content cannot nest. Check this first.
+ if (style()->styleType() == RenderStyle::BEFORE || style()->styleType() == RenderStyle::AFTER)
+ return;
+
+ RenderStyle* pseudoElementStyle = styledObject->getPseudoStyle(type);
+ RenderObject* child = beforeAfterContainer(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 == 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 (newContentWanted && 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(pseudoElementStyle))) {
+ // Nuke the child.
+ if (child && child->style()->styleType() == type) {
+ oldContentPresent = false;
+ child->destroy();
+ child = (type == RenderStyle::BEFORE) ? m_firstChild : m_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 (isInlineFlow() && !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);
+
+ // 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-element style.
+ genChild->setStyle(pseudoElementStyle);
+ else if (genChild->isImage()) {
+ // Images get an empty style that inherits from the pseudo.
+ RenderStyle* style = new (renderArena()) RenderStyle;
+ style->inheritFrom(pseudoElementStyle);
+ genChild->setStyle(style);
+ } else
+ // Must be a first-letter container. updateFirstLetter() will take care of it.
+ ASSERT(genChild->style()->styleType() == RenderStyle::FIRST_LETTER);
+ }
+ }
+ return; // We've updated the generated content. That's all we needed to do.
+ }
+
+ RenderObject* insertBefore = (type == RenderStyle::BEFORE) ? 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->m_next) {
+ RenderObject* renderer = 0;
+ switch (content->m_type) {
+ case CONTENT_NONE:
+ break;
+ case CONTENT_TEXT:
+ renderer = new (renderArena()) RenderTextFragment(document() /* anonymous object */, content->m_content.m_text);
+ renderer->setStyle(pseudoElementStyle);
+ break;
+ case CONTENT_OBJECT:
+ if (CachedResource* resource = content->m_content.m_object)
+ if (resource->type() == CachedResource::ImageResource) {
+ RenderImage* image = new (renderArena()) RenderImage(document()); // anonymous object
+ RenderStyle* style = new (renderArena()) RenderStyle;
+ style->inheritFrom(pseudoElementStyle);
+ image->setStyle(style);
+ image->setCachedImage(static_cast<CachedImage*>(resource));
+ image->setIsAnonymousImage(true);
+ renderer = image;
+ }
+ break;
+ case CONTENT_COUNTER:
+ renderer = new (renderArena()) RenderCounter(document(), *content->m_content.m_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(document(), pseudoElementStyle);
+ generatedContentContainer->setStyle(pseudoElementStyle);
+ }
+ generatedContentContainer->addChild(renderer);
+ }
+ }
+
+ // 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.
+ if (generatedContentContainer)
+ addChild(generatedContentContainer, insertBefore);
+}
+
+bool RenderContainer::isAfterContent(RenderObject* child) const
+{
+ if (!child)
+ return false;
+ if (child->style()->styleType() != RenderStyle::AFTER)
+ return false;
+ // Text nodes don't have their own styles, so ignore the style on a text node.
+ if (child->isText() && !child->isBR())
+ return false;
+ return true;
+}
+
+void RenderContainer::appendChildNode(RenderObject* newChild, bool fullAppend)
+{
+ ASSERT(newChild->parent() == 0);
+ ASSERT(!isBlockFlow() || (!newChild->isTableSection() && !newChild->isTableRow() && !newChild->isTableCell()));
+
+ newChild->setParent(this);
+ RenderObject* lChild = m_lastChild;
+
+ if (lChild) {
+ newChild->setPreviousSibling(lChild);
+ lChild->setNextSibling(newChild);
+ } else
+ m_firstChild = newChild;
+
+ m_lastChild = newChild;
+
+ if (fullAppend) {
+ // Keep our layer hierarchy updated. Optimize for the common case where we don't have any children
+ // and don't have a layer attached to ourselves.
+ RenderLayer* layer = 0;
+ if (newChild->firstChild() || newChild->hasLayer()) {
+ layer = enclosingLayer();
+ newChild->addLayers(layer, newChild);
+ }
+
+ // if the new child is visible but this object was not, tell the layer it has some visible content
+ // that needs to be drawn and layer visibility optimization can't be used
+ if (style()->visibility() != VISIBLE && newChild->style()->visibility() == VISIBLE && !newChild->hasLayer()) {
+ if (!layer)
+ layer = enclosingLayer();
+ if (layer)
+ layer->setHasVisibleContent(true);
+ }
+
+ if (!newChild->isFloatingOrPositioned() && childrenInline())
+ dirtyLinesFromChangedChild(newChild);
+ }
+
+ newChild->setNeedsLayoutAndPrefWidthsRecalc(); // Goes up the containing block hierarchy.
+ if (!normalChildNeedsLayout())
+ setChildNeedsLayout(true); // We may supply the static position for an absolute positioned child.
+
+ if (AXObjectCache::accessibilityEnabled())
+ document()->axObjectCache()->childrenChanged(this);
+}
+
+void RenderContainer::insertChildNode(RenderObject* child, RenderObject* beforeChild, bool fullInsert)
+{
+ if (!beforeChild) {
+ appendChildNode(child);
+ return;
+ }
+
+ ASSERT(!child->parent());
+ while (beforeChild->parent() != this && beforeChild->parent()->isAnonymousBlock())
+ beforeChild = beforeChild->parent();
+ ASSERT(beforeChild->parent() == this);
+
+ ASSERT(!isBlockFlow() || (!child->isTableSection() && !child->isTableRow() && !child->isTableCell()));
+
+ if (beforeChild == m_firstChild)
+ m_firstChild = child;
+
+ RenderObject* prev = beforeChild->previousSibling();
+ child->setNextSibling(beforeChild);
+ beforeChild->setPreviousSibling(child);
+ if(prev) prev->setNextSibling(child);
+ child->setPreviousSibling(prev);
+
+ child->setParent(this);
+
+ if (fullInsert) {
+ // Keep our layer hierarchy updated. Optimize for the common case where we don't have any children
+ // and don't have a layer attached to ourselves.
+ RenderLayer* layer = 0;
+ if (child->firstChild() || child->hasLayer()) {
+ layer = enclosingLayer();
+ child->addLayers(layer, child);
+ }
+
+ // if the new child is visible but this object was not, tell the layer it has some visible content
+ // that needs to be drawn and layer visibility optimization can't be used
+ if (style()->visibility() != VISIBLE && child->style()->visibility() == VISIBLE && !child->hasLayer()) {
+ if (!layer)
+ layer = enclosingLayer();
+ if (layer)
+ layer->setHasVisibleContent(true);
+ }
+
+
+ if (!child->isFloating() && childrenInline())
+ dirtyLinesFromChangedChild(child);
+ }
+
+ child->setNeedsLayoutAndPrefWidthsRecalc();
+ if (!normalChildNeedsLayout())
+ setChildNeedsLayout(true); // We may supply the static position for an absolute positioned child.
+
+ if (AXObjectCache::accessibilityEnabled())
+ document()->axObjectCache()->childrenChanged(this);
+}
+
+void RenderContainer::layout()
+{
+ ASSERT(needsLayout());
+
+ view()->pushLayoutState(this, IntSize(m_x, m_y));
+
+ RenderObject* child = m_firstChild;
+ while (child) {
+ child->layoutIfNeeded();
+ ASSERT(child->isRenderInline() || !child->needsLayout());
+ child = child->nextSibling();
+ }
+
+ view()->popLayoutState();
+ setNeedsLayout(false);
+}
+
+void RenderContainer::removeLeftoverAnonymousBlock(RenderBlock* child)
+{
+ ASSERT(child->isAnonymousBlock());
+ ASSERT(!child->childrenInline());
+
+ if (child->continuation())
+ return;
+
+ RenderObject* firstAnChild = child->firstChild();
+ RenderObject* lastAnChild = child->lastChild();
+ if (firstAnChild) {
+ RenderObject* o = firstAnChild;
+ while(o) {
+ o->setParent(this);
+ o = o->nextSibling();
+ }
+ firstAnChild->setPreviousSibling(child->previousSibling());
+ lastAnChild->setNextSibling(child->nextSibling());
+ if (child->previousSibling())
+ child->previousSibling()->setNextSibling(firstAnChild);
+ if (child->nextSibling())
+ child->nextSibling()->setPreviousSibling(lastAnChild);
+ } else {
+ if (child->previousSibling())
+ child->previousSibling()->setNextSibling(child->nextSibling());
+ if (child->nextSibling())
+ child->nextSibling()->setPreviousSibling(child->previousSibling());
+ }
+ if (child == m_firstChild)
+ m_firstChild = firstAnChild;
+ if (child == m_lastChild)
+ m_lastChild = lastAnChild;
+ child->setParent(0);
+ child->setPreviousSibling(0);
+ child->setNextSibling(0);
+ if (!child->isText()) {
+ RenderContainer *c = static_cast<RenderContainer*>(child);
+ c->m_firstChild = 0;
+ c->m_next = 0;
+ }
+ child->destroy();
+}
+
+VisiblePosition RenderContainer::positionForCoordinates(int x, int y)
+{
+ // no children...return this render object's element, if there is one, and offset 0
+ if (!m_firstChild)
+ return VisiblePosition(element(), 0, DOWNSTREAM);
+
+ if (isTable() && element()) {
+ int right = contentWidth() + borderRight() + paddingRight() + borderLeft() + paddingLeft();
+ int bottom = contentHeight() + borderTop() + paddingTop() + borderBottom() + paddingBottom();
+
+ if (x < 0 || x > right || y < 0 || y > bottom) {
+ if (x <= right / 2)
+ return VisiblePosition(Position(element(), 0));
+ else
+ return VisiblePosition(Position(element(), maxDeepOffset(element())));
+ }
+ }
+
+ // Pass off to the closest child.
+ int minDist = INT_MAX;
+ RenderObject* closestRenderer = 0;
+ int newX = x;
+ int newY = y;
+ if (isTableRow()) {
+ newX += xPos();
+ newY += yPos();
+ }
+ for (RenderObject* renderer = m_firstChild; renderer; renderer = renderer->nextSibling()) {
+ if (!renderer->firstChild() && !renderer->isInline() && !renderer->isBlockFlow()
+ || renderer->style()->visibility() != VISIBLE)
+ continue;
+
+ int top = borderTop() + paddingTop() + (isTableRow() ? 0 : renderer->yPos());
+ int bottom = top + renderer->contentHeight();
+ int left = borderLeft() + paddingLeft() + (isTableRow() ? 0 : renderer->xPos());
+ int right = left + renderer->contentWidth();
+
+ if (x <= right && x >= left && y <= top && y >= bottom) {
+ if (renderer->isTableRow())
+ return renderer->positionForCoordinates(x + newX - renderer->xPos(), y + newY - renderer->yPos());
+ return renderer->positionForCoordinates(x - renderer->xPos(), y - renderer->yPos());
+ }
+
+ // Find the distance from (x, y) to the box. Split the space around the box into 8 pieces
+ // and use a different compare depending on which piece (x, y) is in.
+ IntPoint cmp;
+ if (x > right) {
+ if (y < top)
+ cmp = IntPoint(right, top);
+ else if (y > bottom)
+ cmp = IntPoint(right, bottom);
+ else
+ cmp = IntPoint(right, y);
+ } else if (x < left) {
+ if (y < top)
+ cmp = IntPoint(left, top);
+ else if (y > bottom)
+ cmp = IntPoint(left, bottom);
+ else
+ cmp = IntPoint(left, y);
+ } else {
+ if (y < top)
+ cmp = IntPoint(x, top);
+ else
+ cmp = IntPoint(x, bottom);
+ }
+
+ int x1minusx2 = cmp.x() - x;
+ int y1minusy2 = cmp.y() - y;
+
+ int dist = x1minusx2 * x1minusx2 + y1minusy2 * y1minusy2;
+ if (dist < minDist) {
+ closestRenderer = renderer;
+ minDist = dist;
+ }
+ }
+
+ if (closestRenderer)
+ return closestRenderer->positionForCoordinates(newX - closestRenderer->xPos(), newY - closestRenderer->yPos());
+
+ return VisiblePosition(element(), 0, DOWNSTREAM);
+}
+
+void RenderContainer::addLineBoxRects(Vector<IntRect>& rects, unsigned start, unsigned end)
+{
+ if (!m_firstChild && (isInline() || isAnonymousBlock())) {
+ int x, y;
+ absolutePositionForContent(x, y);
+ absoluteRects(rects, x, y);
+ return;
+ }
+
+ if (!m_firstChild)
+ return;
+
+ unsigned offset = start;
+ for (RenderObject* child = childAt(start); child && offset < end; child = child->nextSibling(), ++offset) {
+ if (child->isText() || child->isInline() || child->isAnonymousBlock()) {
+ int x, y;
+ child->absolutePositionForContent(x, y);
+ child->absoluteRects(rects, x, y);
+ }
+ }
+}
+
+#undef DEBUG_LAYOUT
+
+} // namespace WebCore