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