• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**
2  * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
3  *           (C) 1999 Antti Koivisto (koivisto@kde.org)
4  *           (C) 2000 Dirk Mueller (mueller@kde.org)
5  *           (C) 2004 Allan Sandfeld Jensen (kde@carewolf.com)
6  * Copyright (C) 2003, 2004, 2005, 2006, 2007 Apple Inc. All rights reserved.
7  * Copyright (C) 2006 Andrew Wellington (proton@wiretapped.net)
8  *
9  * This library is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU Library General Public
11  * License as published by the Free Software Foundation; either
12  * version 2 of the License, or (at your option) any later version.
13  *
14  * This library is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17  * Library General Public License for more details.
18  *
19  * You should have received a copy of the GNU Library General Public License
20  * along with this library; see the file COPYING.LIB.  If not, write to
21  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
22  * Boston, MA 02110-1301, USA.
23  *
24  */
25 
26 #include "config.h"
27 #include "RenderContainer.h"
28 
29 #include "AXObjectCache.h"
30 #include "Document.h"
31 #include "RenderCounter.h"
32 #include "RenderImageGeneratedContent.h"
33 #include "RenderInline.h"
34 #include "RenderLayer.h"
35 #include "RenderListItem.h"
36 #include "RenderTable.h"
37 #include "RenderTextFragment.h"
38 #include "RenderView.h"
39 #include "htmlediting.h"
40 
41 namespace WebCore {
42 
RenderContainer(Node * node)43 RenderContainer::RenderContainer(Node* node)
44     : RenderBox(node)
45     , m_firstChild(0)
46     , m_lastChild(0)
47 {
48 }
49 
~RenderContainer()50 RenderContainer::~RenderContainer()
51 {
52 }
53 
destroy()54 void RenderContainer::destroy()
55 {
56     destroyLeftoverChildren();
57     RenderBox::destroy();
58 }
59 
destroyLeftoverChildren()60 void RenderContainer::destroyLeftoverChildren()
61 {
62     while (m_firstChild) {
63         if (m_firstChild->isListMarker() || (m_firstChild->style()->styleType() == RenderStyle::FIRST_LETTER && !m_firstChild->isText()))
64             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.
65         else {
66         // 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.
67             if (m_firstChild->element())
68                 m_firstChild->element()->setRenderer(0);
69             m_firstChild->destroy();
70         }
71     }
72 }
73 
canHaveChildren() const74 bool RenderContainer::canHaveChildren() const
75 {
76     return true;
77 }
78 
updateListMarkerNumbers(RenderObject * child)79 static void updateListMarkerNumbers(RenderObject* child)
80 {
81     for (RenderObject* r = child; r; r = r->nextSibling())
82         if (r->isListItem())
83             static_cast<RenderListItem*>(r)->updateValue();
84 }
85 
addChild(RenderObject * newChild,RenderObject * beforeChild)86 void RenderContainer::addChild(RenderObject* newChild, RenderObject* beforeChild)
87 {
88     bool needsTable = false;
89 
90     if (newChild->isListItem())
91         updateListMarkerNumbers(beforeChild ? beforeChild : m_lastChild);
92     else if (newChild->isTableCol() && newChild->style()->display() == TABLE_COLUMN_GROUP)
93         needsTable = !isTable();
94     else if (newChild->isRenderBlock() && newChild->style()->display() == TABLE_CAPTION)
95         needsTable = !isTable();
96     else if (newChild->isTableSection())
97         needsTable = !isTable();
98     else if (newChild->isTableRow())
99         needsTable = !isTableSection();
100     else if (newChild->isTableCell()) {
101         needsTable = !isTableRow();
102         // I'm not 100% sure this is the best way to fix this, but without this
103         // change we recurse infinitely when trying to render the CSS2 test page:
104         // http://www.bath.ac.uk/%7Epy8ieh/internet/eviltests/htmlbodyheadrendering2.html.
105         // See Radar 2925291.
106         if (needsTable && isTableCell() && !m_firstChild && !newChild->isTableCell())
107             needsTable = false;
108     }
109 
110     if (needsTable) {
111         RenderTable* table;
112         RenderObject* afterChild = beforeChild ? beforeChild->previousSibling() : m_lastChild;
113         if (afterChild && afterChild->isAnonymous() && afterChild->isTable())
114             table = static_cast<RenderTable*>(afterChild);
115         else {
116             table = new (renderArena()) RenderTable(document() /* is anonymous */);
117             RefPtr<RenderStyle> newStyle = RenderStyle::create();
118             newStyle->inheritFrom(style());
119             newStyle->setDisplay(TABLE);
120             table->setStyle(newStyle.release());
121             addChild(table, beforeChild);
122         }
123         table->addChild(newChild);
124     } else {
125         // just add it...
126         insertChildNode(newChild, beforeChild);
127     }
128 
129     if (newChild->isText() && newChild->style()->textTransform() == CAPITALIZE) {
130         RefPtr<StringImpl> textToTransform = toRenderText(newChild)->originalText();
131         if (textToTransform)
132             toRenderText(newChild)->setText(textToTransform.release(), true);
133     }
134 }
135 
removeChildNode(RenderObject * oldChild,bool fullRemove)136 RenderObject* RenderContainer::removeChildNode(RenderObject* oldChild, bool fullRemove)
137 {
138     ASSERT(oldChild->parent() == this);
139 
140     // So that we'll get the appropriate dirty bit set (either that a normal flow child got yanked or
141     // that a positioned child got yanked).  We also repaint, so that the area exposed when the child
142     // disappears gets repainted properly.
143     if (!documentBeingDestroyed() && fullRemove && oldChild->m_everHadLayout) {
144         oldChild->setNeedsLayoutAndPrefWidthsRecalc();
145         oldChild->repaint();
146     }
147 
148     // If we have a line box wrapper, delete it.
149     oldChild->deleteLineBoxWrapper();
150 
151     if (!documentBeingDestroyed() && fullRemove) {
152         // if we remove visible child from an invisible parent, we don't know the layer visibility any more
153         RenderLayer* layer = 0;
154         if (m_style->visibility() != VISIBLE && oldChild->style()->visibility() == VISIBLE && !oldChild->hasLayer()) {
155             layer = enclosingLayer();
156             layer->dirtyVisibleContentStatus();
157         }
158 
159          // Keep our layer hierarchy updated.
160         if (oldChild->firstChild() || oldChild->hasLayer()) {
161             if (!layer) layer = enclosingLayer();
162             oldChild->removeLayers(layer);
163         }
164 
165         // renumber ordered lists
166         if (oldChild->isListItem())
167             updateListMarkerNumbers(oldChild->nextSibling());
168 
169         if (oldChild->isPositioned() && childrenInline())
170             dirtyLinesFromChangedChild(oldChild);
171     }
172 
173     // If oldChild is the start or end of the selection, then clear the selection to
174     // avoid problems of invalid pointers.
175     // FIXME: The SelectionController should be responsible for this when it
176     // is notified of DOM mutations.
177     if (!documentBeingDestroyed() && oldChild->isSelectionBorder())
178         view()->clearSelection();
179 
180     // remove the child
181     if (oldChild->previousSibling())
182         oldChild->previousSibling()->setNextSibling(oldChild->nextSibling());
183     if (oldChild->nextSibling())
184         oldChild->nextSibling()->setPreviousSibling(oldChild->previousSibling());
185 
186     if (m_firstChild == oldChild)
187         m_firstChild = oldChild->nextSibling();
188     if (m_lastChild == oldChild)
189         m_lastChild = oldChild->previousSibling();
190 
191     oldChild->setPreviousSibling(0);
192     oldChild->setNextSibling(0);
193     oldChild->setParent(0);
194 
195     if (AXObjectCache::accessibilityEnabled())
196         document()->axObjectCache()->childrenChanged(this);
197 
198     return oldChild;
199 }
200 
removeChild(RenderObject * oldChild)201 void RenderContainer::removeChild(RenderObject* oldChild)
202 {
203     // We do this here instead of in removeChildNode, since the only extremely low-level uses of remove/appendChildNode
204     // cannot affect the positioned object list, and the floating object list is irrelevant (since the list gets cleared on
205     // layout anyway).
206     oldChild->removeFromObjectLists();
207 
208     removeChildNode(oldChild);
209 }
210 
beforeAfterContainer(RenderStyle::PseudoId type)211 RenderObject* RenderContainer::beforeAfterContainer(RenderStyle::PseudoId type)
212 {
213     if (type == RenderStyle::BEFORE) {
214         RenderObject* first = this;
215         do {
216             // Skip list markers.
217             first = first->firstChild();
218             while (first && first->isListMarker())
219                 first = first->nextSibling();
220         } while (first && first->isAnonymous() && first->style()->styleType() == RenderStyle::NOPSEUDO);
221         if (first && first->style()->styleType() != type)
222             return 0;
223         return first;
224     }
225     if (type == RenderStyle::AFTER) {
226         RenderObject* last = this;
227         do {
228             last = last->lastChild();
229         } while (last && last->isAnonymous() && last->style()->styleType() == RenderStyle::NOPSEUDO && !last->isListMarker());
230         if (last && last->style()->styleType() != type)
231             return 0;
232         return last;
233     }
234 
235     ASSERT_NOT_REACHED();
236     return 0;
237 }
238 
updateBeforeAfterContent(RenderStyle::PseudoId type)239 void RenderContainer::updateBeforeAfterContent(RenderStyle::PseudoId type)
240 {
241     // If this is an anonymous wrapper, then the parent applies its own pseudo-element style to it.
242     if (parent() && parent()->createsAnonymousWrapper())
243         return;
244     updateBeforeAfterContentForContainer(type, this);
245 }
246 
findBeforeAfterParent(RenderObject * object)247 static RenderObject* findBeforeAfterParent(RenderObject* object)
248 {
249     // Only table parts need to search for the :before or :after parent
250     if (!(object->isTable() || object->isTableSection() || object->isTableRow()))
251         return object;
252 
253     RenderObject* beforeAfterParent = object;
254     while (beforeAfterParent && !(beforeAfterParent->isText() || beforeAfterParent->isImage()))
255         beforeAfterParent = beforeAfterParent->firstChild();
256     return beforeAfterParent;
257 }
258 
updateBeforeAfterContentForContainer(RenderStyle::PseudoId type,RenderContainer * styledObject)259 void RenderContainer::updateBeforeAfterContentForContainer(RenderStyle::PseudoId type, RenderContainer* styledObject)
260 {
261     // Double check that the document did in fact use generated content rules.  Otherwise we should not have been called.
262     ASSERT(document()->usesBeforeAfterRules());
263 
264     // In CSS2, before/after pseudo-content cannot nest.  Check this first.
265     if (style()->styleType() == RenderStyle::BEFORE || style()->styleType() == RenderStyle::AFTER)
266         return;
267 
268     RenderStyle* pseudoElementStyle = styledObject->getCachedPseudoStyle(type);
269     RenderObject* child = beforeAfterContainer(type);
270 
271     // Whether or not we currently have generated content attached.
272     bool oldContentPresent = child;
273 
274     // Whether or not we now want generated content.
275     bool newContentWanted = pseudoElementStyle && pseudoElementStyle->display() != NONE;
276 
277     // For <q><p/></q>, if this object is the inline continuation of the <q>, we only want to generate
278     // :after content and not :before content.
279     if (newContentWanted && type == RenderStyle::BEFORE && isInlineContinuation())
280         newContentWanted = false;
281 
282     // Similarly, if we're the beginning of a <q>, and there's an inline continuation for our object,
283     // then we don't generate the :after content.
284     if (newContentWanted && type == RenderStyle::AFTER && isRenderInline() && static_cast<RenderInline*>(this)->continuation())
285         newContentWanted = false;
286 
287     // If we don't want generated content any longer, or if we have generated content, but it's no longer
288     // identical to the new content data we want to build render objects for, then we nuke all
289     // of the old generated content.
290     if (!newContentWanted || (oldContentPresent && Node::diff(child->style(), pseudoElementStyle) == Node::Detach)) {
291         // Nuke the child.
292         if (child && child->style()->styleType() == type) {
293             oldContentPresent = false;
294             child->destroy();
295             child = (type == RenderStyle::BEFORE) ? m_firstChild : m_lastChild;
296         }
297     }
298 
299     // If we have no pseudo-element style or if the pseudo-element style's display type is NONE, then we
300     // have no generated content and can now return.
301     if (!newContentWanted)
302         return;
303 
304     if (isRenderInline() && !pseudoElementStyle->isDisplayInlineType() && pseudoElementStyle->floating() == FNONE &&
305         !(pseudoElementStyle->position() == AbsolutePosition || pseudoElementStyle->position() == FixedPosition))
306         // According to the CSS2 spec (the end of section 12.1), the only allowed
307         // display values for the pseudo style are NONE and INLINE for inline flows.
308         // FIXME: CSS2.1 lifted this restriction, but block display types will crash.
309         // For now we at least relax the restriction to allow all inline types like inline-block
310         // and inline-table.
311         pseudoElementStyle->setDisplay(INLINE);
312 
313     if (oldContentPresent) {
314         if (child && child->style()->styleType() == type) {
315             // We have generated content present still.  We want to walk this content and update our
316             // style information with the new pseudo-element style.
317             child->setStyle(pseudoElementStyle);
318 
319             RenderObject* beforeAfterParent = findBeforeAfterParent(child);
320             if (!beforeAfterParent)
321                 return;
322 
323             // Note that if we ever support additional types of generated content (which should be way off
324             // in the future), this code will need to be patched.
325             for (RenderObject* genChild = beforeAfterParent->firstChild(); genChild; genChild = genChild->nextSibling()) {
326                 if (genChild->isText())
327                     // Generated text content is a child whose style also needs to be set to the pseudo-element style.
328                     genChild->setStyle(pseudoElementStyle);
329                 else if (genChild->isImage()) {
330                     // Images get an empty style that inherits from the pseudo.
331                     RefPtr<RenderStyle> style = RenderStyle::create();
332                     style->inheritFrom(pseudoElementStyle);
333                     genChild->setStyle(style.release());
334                 } else
335                     // Must be a first-letter container. updateFirstLetter() will take care of it.
336                     ASSERT(genChild->style()->styleType() == RenderStyle::FIRST_LETTER);
337             }
338         }
339         return; // We've updated the generated content. That's all we needed to do.
340     }
341 
342     RenderObject* insertBefore = (type == RenderStyle::BEFORE) ? firstChild() : 0;
343 
344     // Generated content consists of a single container that houses multiple children (specified
345     // by the content property).  This generated content container gets the pseudo-element style set on it.
346     RenderObject* generatedContentContainer = 0;
347 
348     // Walk our list of generated content and create render objects for each.
349     for (const ContentData* content = pseudoElementStyle->contentData(); content; content = content->m_next) {
350         RenderObject* renderer = 0;
351         switch (content->m_type) {
352             case CONTENT_NONE:
353                 break;
354             case CONTENT_TEXT:
355                 renderer = new (renderArena()) RenderTextFragment(document() /* anonymous object */, content->m_content.m_text);
356                 renderer->setStyle(pseudoElementStyle);
357                 break;
358             case CONTENT_OBJECT: {
359                 RenderImageGeneratedContent* image = new (renderArena()) RenderImageGeneratedContent(document()); // anonymous object
360                 RefPtr<RenderStyle> style = RenderStyle::create();
361                 style->inheritFrom(pseudoElementStyle);
362                 image->setStyle(style.release());
363                 if (StyleImage* styleImage = content->m_content.m_image)
364                     image->setStyleImage(styleImage);
365                 renderer = image;
366                 break;
367             }
368             case CONTENT_COUNTER:
369                 renderer = new (renderArena()) RenderCounter(document(), *content->m_content.m_counter);
370                 renderer->setStyle(pseudoElementStyle);
371                 break;
372         }
373 
374         if (renderer) {
375             if (!generatedContentContainer) {
376                 // Make a generated box that might be any display type now that we are able to drill down into children
377                 // to find the original content properly.
378                 generatedContentContainer = RenderObject::createObject(document(), pseudoElementStyle);
379                 generatedContentContainer->setStyle(pseudoElementStyle);
380                 addChild(generatedContentContainer, insertBefore);
381             }
382             generatedContentContainer->addChild(renderer);
383         }
384     }
385 }
386 
isAfterContent(RenderObject * child) const387 bool RenderContainer::isAfterContent(RenderObject* child) const
388 {
389     if (!child)
390         return false;
391     if (child->style()->styleType() != RenderStyle::AFTER)
392         return false;
393     // Text nodes don't have their own styles, so ignore the style on a text node.
394     if (child->isText() && !child->isBR())
395         return false;
396     return true;
397 }
398 
invalidateCountersInContainer(RenderObject * container)399 static void invalidateCountersInContainer(RenderObject* container)
400 {
401     if (!container)
402         return;
403     container = findBeforeAfterParent(container);
404     if (!container)
405         return;
406     for (RenderObject* content = container->firstChild(); content; content = content->nextSibling()) {
407         if (content->isCounter())
408             static_cast<RenderCounter*>(content)->invalidate();
409     }
410 }
411 
invalidateCounters()412 void RenderContainer::invalidateCounters()
413 {
414     if (documentBeingDestroyed())
415         return;
416 
417     invalidateCountersInContainer(beforeAfterContainer(RenderStyle::BEFORE));
418     invalidateCountersInContainer(beforeAfterContainer(RenderStyle::AFTER));
419 }
420 
appendChildNode(RenderObject * newChild,bool fullAppend)421 void RenderContainer::appendChildNode(RenderObject* newChild, bool fullAppend)
422 {
423     ASSERT(newChild->parent() == 0);
424     ASSERT(!isBlockFlow() || (!newChild->isTableSection() && !newChild->isTableRow() && !newChild->isTableCell()));
425 
426     newChild->setParent(this);
427     RenderObject* lChild = m_lastChild;
428 
429     if (lChild) {
430         newChild->setPreviousSibling(lChild);
431         lChild->setNextSibling(newChild);
432     } else
433         m_firstChild = newChild;
434 
435     m_lastChild = newChild;
436 
437     if (fullAppend) {
438         // Keep our layer hierarchy updated.  Optimize for the common case where we don't have any children
439         // and don't have a layer attached to ourselves.
440         RenderLayer* layer = 0;
441         if (newChild->firstChild() || newChild->hasLayer()) {
442             layer = enclosingLayer();
443             newChild->addLayers(layer, newChild);
444         }
445 
446         // if the new child is visible but this object was not, tell the layer it has some visible content
447         // that needs to be drawn and layer visibility optimization can't be used
448         if (style()->visibility() != VISIBLE && newChild->style()->visibility() == VISIBLE && !newChild->hasLayer()) {
449             if (!layer)
450                 layer = enclosingLayer();
451             if (layer)
452                 layer->setHasVisibleContent(true);
453         }
454 
455         if (!newChild->isFloatingOrPositioned() && childrenInline())
456             dirtyLinesFromChangedChild(newChild);
457     }
458 
459     newChild->setNeedsLayoutAndPrefWidthsRecalc(); // Goes up the containing block hierarchy.
460     if (!normalChildNeedsLayout())
461         setChildNeedsLayout(true); // We may supply the static position for an absolute positioned child.
462 
463     if (AXObjectCache::accessibilityEnabled())
464         document()->axObjectCache()->childrenChanged(this);
465 }
466 
insertChildNode(RenderObject * child,RenderObject * beforeChild,bool fullInsert)467 void RenderContainer::insertChildNode(RenderObject* child, RenderObject* beforeChild, bool fullInsert)
468 {
469     if (!beforeChild) {
470         appendChildNode(child);
471         return;
472     }
473 
474     ASSERT(!child->parent());
475     while (beforeChild->parent() != this && beforeChild->parent()->isAnonymousBlock())
476         beforeChild = beforeChild->parent();
477     ASSERT(beforeChild->parent() == this);
478 
479     ASSERT(!isBlockFlow() || (!child->isTableSection() && !child->isTableRow() && !child->isTableCell()));
480 
481     if (beforeChild == m_firstChild)
482         m_firstChild = child;
483 
484     RenderObject* prev = beforeChild->previousSibling();
485     child->setNextSibling(beforeChild);
486     beforeChild->setPreviousSibling(child);
487     if(prev) prev->setNextSibling(child);
488     child->setPreviousSibling(prev);
489 
490     child->setParent(this);
491 
492     if (fullInsert) {
493         // Keep our layer hierarchy updated.  Optimize for the common case where we don't have any children
494         // and don't have a layer attached to ourselves.
495         RenderLayer* layer = 0;
496         if (child->firstChild() || child->hasLayer()) {
497             layer = enclosingLayer();
498             child->addLayers(layer, child);
499         }
500 
501         // if the new child is visible but this object was not, tell the layer it has some visible content
502         // that needs to be drawn and layer visibility optimization can't be used
503         if (style()->visibility() != VISIBLE && child->style()->visibility() == VISIBLE && !child->hasLayer()) {
504             if (!layer)
505                 layer = enclosingLayer();
506             if (layer)
507                 layer->setHasVisibleContent(true);
508         }
509 
510 
511         if (!child->isFloating() && childrenInline())
512             dirtyLinesFromChangedChild(child);
513     }
514 
515     child->setNeedsLayoutAndPrefWidthsRecalc();
516     if (!normalChildNeedsLayout())
517         setChildNeedsLayout(true); // We may supply the static position for an absolute positioned child.
518 
519     if (AXObjectCache::accessibilityEnabled())
520         document()->axObjectCache()->childrenChanged(this);
521 }
522 
layout()523 void RenderContainer::layout()
524 {
525     ASSERT(needsLayout());
526 
527     LayoutStateMaintainer statePusher(view(), this, IntSize(x(), y()));
528 
529     RenderObject* child = m_firstChild;
530     while (child) {
531         child->layoutIfNeeded();
532         ASSERT(child->isRenderInline() || !child->needsLayout());
533         child = child->nextSibling();
534     }
535 
536     statePusher.pop();
537     setNeedsLayout(false);
538 }
539 
removeLeftoverAnonymousBlock(RenderBlock * child)540 void RenderContainer::removeLeftoverAnonymousBlock(RenderBlock* child)
541 {
542     ASSERT(child->isAnonymousBlock());
543     ASSERT(!child->childrenInline());
544 
545     if (child->continuation())
546         return;
547 
548     RenderObject* firstAnChild = child->firstChild();
549     RenderObject* lastAnChild = child->lastChild();
550     if (firstAnChild) {
551         RenderObject* o = firstAnChild;
552         while(o) {
553             o->setParent(this);
554             o = o->nextSibling();
555         }
556         firstAnChild->setPreviousSibling(child->previousSibling());
557         lastAnChild->setNextSibling(child->nextSibling());
558         if (child->previousSibling())
559             child->previousSibling()->setNextSibling(firstAnChild);
560         if (child->nextSibling())
561             child->nextSibling()->setPreviousSibling(lastAnChild);
562     } else {
563         if (child->previousSibling())
564             child->previousSibling()->setNextSibling(child->nextSibling());
565         if (child->nextSibling())
566             child->nextSibling()->setPreviousSibling(child->previousSibling());
567     }
568     if (child == m_firstChild)
569         m_firstChild = firstAnChild;
570     if (child == m_lastChild)
571         m_lastChild = lastAnChild;
572     child->setParent(0);
573     child->setPreviousSibling(0);
574     child->setNextSibling(0);
575     if (!child->isText()) {
576         RenderContainer *c = static_cast<RenderContainer*>(child);
577         c->m_firstChild = 0;
578         c->m_next = 0;
579     }
580     child->destroy();
581 }
582 
positionForCoordinates(int xPos,int yPos)583 VisiblePosition RenderContainer::positionForCoordinates(int xPos, int yPos)
584 {
585     // no children...return this render object's element, if there is one, and offset 0
586     if (!m_firstChild)
587         return VisiblePosition(element(), 0, DOWNSTREAM);
588 
589     if (isTable() && element()) {
590         int right = contentWidth() + borderRight() + paddingRight() + borderLeft() + paddingLeft();
591         int bottom = contentHeight() + borderTop() + paddingTop() + borderBottom() + paddingBottom();
592 
593         if (xPos < 0 || xPos > right || yPos < 0 || yPos > bottom) {
594             if (xPos <= right / 2)
595                 return VisiblePosition(Position(element(), 0));
596             else
597                 return VisiblePosition(Position(element(), maxDeepOffset(element())));
598         }
599     }
600 
601     // Pass off to the closest child.
602     int minDist = INT_MAX;
603     RenderBox* closestRenderer = 0;
604     int newX = xPos;
605     int newY = yPos;
606     if (isTableRow()) {
607         newX += x();
608         newY += y();
609     }
610     for (RenderObject* renderObject = m_firstChild; renderObject; renderObject = renderObject->nextSibling()) {
611         if (!renderObject->firstChild() && !renderObject->isInline() && !renderObject->isBlockFlow()
612             || renderObject->style()->visibility() != VISIBLE)
613             continue;
614 
615         if (!renderObject->isBox())
616             continue;
617 
618         RenderBox* renderer = toRenderBox(renderObject);
619 
620         int top = borderTop() + paddingTop() + (isTableRow() ? 0 : renderer->y());
621         int bottom = top + renderer->contentHeight();
622         int left = borderLeft() + paddingLeft() + (isTableRow() ? 0 : renderer->x());
623         int right = left + renderer->contentWidth();
624 
625         if (xPos <= right && xPos >= left && yPos <= top && yPos >= bottom) {
626             if (renderer->isTableRow())
627                 return renderer->positionForCoordinates(xPos + newX - renderer->x(), yPos + newY - renderer->y());
628             return renderer->positionForCoordinates(xPos - renderer->x(), yPos - renderer->y());
629         }
630 
631         // Find the distance from (x, y) to the box.  Split the space around the box into 8 pieces
632         // and use a different compare depending on which piece (x, y) is in.
633         IntPoint cmp;
634         if (xPos > right) {
635             if (yPos < top)
636                 cmp = IntPoint(right, top);
637             else if (yPos > bottom)
638                 cmp = IntPoint(right, bottom);
639             else
640                 cmp = IntPoint(right, yPos);
641         } else if (xPos < left) {
642             if (yPos < top)
643                 cmp = IntPoint(left, top);
644             else if (yPos > bottom)
645                 cmp = IntPoint(left, bottom);
646             else
647                 cmp = IntPoint(left, yPos);
648         } else {
649             if (yPos < top)
650                 cmp = IntPoint(xPos, top);
651             else
652                 cmp = IntPoint(xPos, bottom);
653         }
654 
655         int x1minusx2 = cmp.x() - xPos;
656         int y1minusy2 = cmp.y() - yPos;
657 
658         int dist = x1minusx2 * x1minusx2 + y1minusy2 * y1minusy2;
659         if (dist < minDist) {
660             closestRenderer = renderer;
661             minDist = dist;
662         }
663     }
664 
665     if (closestRenderer)
666         return closestRenderer->positionForCoordinates(newX - closestRenderer->x(), newY - closestRenderer->y());
667 
668     return VisiblePosition(element(), 0, DOWNSTREAM);
669 }
670 
addLineBoxRects(Vector<IntRect> & rects,unsigned start,unsigned end,bool)671 void RenderContainer::addLineBoxRects(Vector<IntRect>& rects, unsigned start, unsigned end, bool)
672 {
673     if (!m_firstChild && (isInline() || isAnonymousBlock())) {
674         FloatPoint absPos = localToAbsolute(FloatPoint());
675         absoluteRects(rects, absPos.x(), absPos.y());
676         return;
677     }
678 
679     if (!m_firstChild)
680         return;
681 
682     unsigned offset = start;
683     for (RenderObject* child = childAt(start); child && offset < end; child = child->nextSibling(), ++offset) {
684         if (child->isText() || child->isInline() || child->isAnonymousBlock()) {
685             FloatPoint absPos = child->localToAbsolute(FloatPoint());
686             child->absoluteRects(rects, absPos.x(), absPos.y());
687         }
688     }
689 }
690 
collectAbsoluteLineBoxQuads(Vector<FloatQuad> & quads,unsigned start,unsigned end,bool)691 void RenderContainer::collectAbsoluteLineBoxQuads(Vector<FloatQuad>& quads, unsigned start, unsigned end, bool /*useSelectionHeight*/)
692 {
693     if (!m_firstChild && (isInline() || isAnonymousBlock())) {
694         absoluteQuads(quads);
695         return;
696     }
697 
698     if (!m_firstChild)
699         return;
700 
701     unsigned offset = start;
702     for (RenderObject* child = childAt(start); child && offset < end; child = child->nextSibling(), ++offset) {
703         if (child->isText() || child->isInline() || child->isAnonymousBlock())
704             child->absoluteQuads(quads);
705     }
706 }
707 
708 #ifdef ANDROID_LAYOUT
hasChildTable() const709 bool RenderContainer::hasChildTable() const
710 {
711     if (!firstChild())
712         return false;
713     for (RenderObject* child = firstChild(); child; child = child->nextSibling()) {
714         if (child->isTable()) {
715             return true;
716         } else if (child->hasChildTable() == true) {
717             return true;
718         }
719     }
720     return false;
721 }
722 #endif
723 
724 #undef DEBUG_LAYOUT
725 
726 } // namespace WebCore
727