| OLD | NEW |
| 1 /** | 1 /** |
| 2 * Copyright (C) 1999 Lars Knoll (knoll@kde.org) | 2 * Copyright (C) 1999 Lars Knoll (knoll@kde.org) |
| 3 * (C) 1999 Antti Koivisto (koivisto@kde.org) | 3 * (C) 1999 Antti Koivisto (koivisto@kde.org) |
| 4 * (C) 2000 Dirk Mueller (mueller@kde.org) | 4 * (C) 2000 Dirk Mueller (mueller@kde.org) |
| 5 * (C) 2004 Allan Sandfeld Jensen (kde@carewolf.com) | 5 * (C) 2004 Allan Sandfeld Jensen (kde@carewolf.com) |
| 6 * Copyright (C) 2003, 2004, 2005, 2006, 2007 Apple Inc. All rights reserved. | 6 * Copyright (C) 2003, 2004, 2005, 2006, 2007 Apple Inc. All rights reserved. |
| 7 * Copyright (C) 2006 Andrew Wellington (proton@wiretapped.net) | 7 * Copyright (C) 2006 Andrew Wellington (proton@wiretapped.net) |
| 8 * | 8 * |
| 9 * This library is free software; you can redistribute it and/or | 9 * This library is free software; you can redistribute it and/or |
| 10 * modify it under the terms of the GNU Library General Public | 10 * modify it under the terms of the GNU Library General Public |
| (...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 89 table = new (renderArena()) RenderTable(document() /* is anonymous *
/); | 89 table = new (renderArena()) RenderTable(document() /* is anonymous *
/); |
| 90 RefPtr<RenderStyle> newStyle = RenderStyle::create(); | 90 RefPtr<RenderStyle> newStyle = RenderStyle::create(); |
| 91 newStyle->inheritFrom(style()); | 91 newStyle->inheritFrom(style()); |
| 92 newStyle->setDisplay(TABLE); | 92 newStyle->setDisplay(TABLE); |
| 93 table->setStyle(newStyle.release()); | 93 table->setStyle(newStyle.release()); |
| 94 addChild(table, beforeChild); | 94 addChild(table, beforeChild); |
| 95 } | 95 } |
| 96 table->addChild(newChild); | 96 table->addChild(newChild); |
| 97 } else { | 97 } else { |
| 98 // just add it... | 98 // just add it... |
| 99 insertChildNode(newChild, beforeChild); | 99 children()->insertChildNode(this, newChild, beforeChild); |
| 100 } | 100 } |
| 101 | 101 |
| 102 if (newChild->isText() && newChild->style()->textTransform() == CAPITALIZE)
{ | 102 if (newChild->isText() && newChild->style()->textTransform() == CAPITALIZE)
{ |
| 103 RefPtr<StringImpl> textToTransform = toRenderText(newChild)->originalTex
t(); | 103 RefPtr<StringImpl> textToTransform = toRenderText(newChild)->originalTex
t(); |
| 104 if (textToTransform) | 104 if (textToTransform) |
| 105 toRenderText(newChild)->setText(textToTransform.release(), true); | 105 toRenderText(newChild)->setText(textToTransform.release(), true); |
| 106 } | 106 } |
| 107 } | 107 } |
| 108 | 108 |
| 109 RenderObject* RenderContainer::removeChildNode(RenderObject* oldChild, bool full
Remove) | |
| 110 { | |
| 111 ASSERT(oldChild->parent() == this); | |
| 112 | |
| 113 // So that we'll get the appropriate dirty bit set (either that a normal flo
w child got yanked or | |
| 114 // that a positioned child got yanked). We also repaint, so that the area e
xposed when the child | |
| 115 // disappears gets repainted properly. | |
| 116 if (!documentBeingDestroyed() && fullRemove && oldChild->m_everHadLayout) { | |
| 117 oldChild->setNeedsLayoutAndPrefWidthsRecalc(); | |
| 118 oldChild->repaint(); | |
| 119 } | |
| 120 | |
| 121 // If we have a line box wrapper, delete it. | |
| 122 oldChild->deleteLineBoxWrapper(); | |
| 123 | |
| 124 if (!documentBeingDestroyed() && fullRemove) { | |
| 125 // if we remove visible child from an invisible parent, we don't know th
e layer visibility any more | |
| 126 RenderLayer* layer = 0; | |
| 127 if (m_style->visibility() != VISIBLE && oldChild->style()->visibility()
== VISIBLE && !oldChild->hasLayer()) { | |
| 128 layer = enclosingLayer(); | |
| 129 layer->dirtyVisibleContentStatus(); | |
| 130 } | |
| 131 | |
| 132 // Keep our layer hierarchy updated. | |
| 133 if (oldChild->firstChild() || oldChild->hasLayer()) { | |
| 134 if (!layer) layer = enclosingLayer(); | |
| 135 oldChild->removeLayers(layer); | |
| 136 } | |
| 137 | |
| 138 // renumber ordered lists | |
| 139 if (oldChild->isListItem()) | |
| 140 updateListMarkerNumbers(oldChild->nextSibling()); | |
| 141 | |
| 142 if (oldChild->isPositioned() && childrenInline()) | |
| 143 dirtyLinesFromChangedChild(oldChild); | |
| 144 } | |
| 145 | |
| 146 // If oldChild is the start or end of the selection, then clear the selectio
n to | |
| 147 // avoid problems of invalid pointers. | |
| 148 // FIXME: The SelectionController should be responsible for this when it | |
| 149 // is notified of DOM mutations. | |
| 150 if (!documentBeingDestroyed() && oldChild->isSelectionBorder()) | |
| 151 view()->clearSelection(); | |
| 152 | |
| 153 // remove the child | |
| 154 if (oldChild->previousSibling()) | |
| 155 oldChild->previousSibling()->setNextSibling(oldChild->nextSibling()); | |
| 156 if (oldChild->nextSibling()) | |
| 157 oldChild->nextSibling()->setPreviousSibling(oldChild->previousSibling())
; | |
| 158 | |
| 159 if (children()->firstChild() == oldChild) | |
| 160 children()->setFirstChild(oldChild->nextSibling()); | |
| 161 if (children()->lastChild() == oldChild) | |
| 162 children()->setLastChild(oldChild->previousSibling()); | |
| 163 | |
| 164 oldChild->setPreviousSibling(0); | |
| 165 oldChild->setNextSibling(0); | |
| 166 oldChild->setParent(0); | |
| 167 | |
| 168 if (AXObjectCache::accessibilityEnabled()) | |
| 169 document()->axObjectCache()->childrenChanged(this); | |
| 170 | |
| 171 return oldChild; | |
| 172 } | |
| 173 | |
| 174 void RenderContainer::removeChild(RenderObject* oldChild) | 109 void RenderContainer::removeChild(RenderObject* oldChild) |
| 175 { | 110 { |
| 176 // We do this here instead of in removeChildNode, since the only extremely l
ow-level uses of remove/appendChildNode | 111 // We do this here instead of in removeChildNode, since the only extremely l
ow-level uses of remove/appendChildNode |
| 177 // cannot affect the positioned object list, and the floating object list is
irrelevant (since the list gets cleared on | 112 // cannot affect the positioned object list, and the floating object list is
irrelevant (since the list gets cleared on |
| 178 // layout anyway). | 113 // layout anyway). |
| 179 oldChild->removeFromObjectLists(); | 114 oldChild->removeFromObjectLists(); |
| 180 | 115 m_children.removeChildNode(this, oldChild); |
| 181 removeChildNode(oldChild); | |
| 182 } | |
| 183 | |
| 184 RenderObject* RenderContainer::beforeAfterContainer(RenderStyle::PseudoId type) | |
| 185 { | |
| 186 if (type == RenderStyle::BEFORE) { | |
| 187 RenderObject* first = this; | |
| 188 do { | |
| 189 // Skip list markers. | |
| 190 first = first->firstChild(); | |
| 191 while (first && first->isListMarker()) | |
| 192 first = first->nextSibling(); | |
| 193 } while (first && first->isAnonymous() && first->style()->styleType() ==
RenderStyle::NOPSEUDO); | |
| 194 if (first && first->style()->styleType() != type) | |
| 195 return 0; | |
| 196 return first; | |
| 197 } | |
| 198 if (type == RenderStyle::AFTER) { | |
| 199 RenderObject* last = this; | |
| 200 do { | |
| 201 last = last->lastChild(); | |
| 202 } while (last && last->isAnonymous() && last->style()->styleType() == Re
nderStyle::NOPSEUDO && !last->isListMarker()); | |
| 203 if (last && last->style()->styleType() != type) | |
| 204 return 0; | |
| 205 return last; | |
| 206 } | |
| 207 | |
| 208 ASSERT_NOT_REACHED(); | |
| 209 return 0; | |
| 210 } | |
| 211 | |
| 212 void RenderContainer::updateBeforeAfterContent(RenderStyle::PseudoId type) | |
| 213 { | |
| 214 // If this is an anonymous wrapper, then the parent applies its own pseudo-e
lement style to it. | |
| 215 if (parent() && parent()->createsAnonymousWrapper()) | |
| 216 return; | |
| 217 updateBeforeAfterContentForContainer(type, this); | |
| 218 } | |
| 219 | |
| 220 static RenderObject* findBeforeAfterParent(RenderObject* object) | |
| 221 { | |
| 222 // Only table parts need to search for the :before or :after parent | |
| 223 if (!(object->isTable() || object->isTableSection() || object->isTableRow())
) | |
| 224 return object; | |
| 225 | |
| 226 RenderObject* beforeAfterParent = object; | |
| 227 while (beforeAfterParent && !(beforeAfterParent->isText() || beforeAfterPare
nt->isImage())) | |
| 228 beforeAfterParent = beforeAfterParent->firstChild(); | |
| 229 return beforeAfterParent; | |
| 230 } | |
| 231 | |
| 232 void RenderContainer::updateBeforeAfterContentForContainer(RenderStyle::PseudoId
type, RenderContainer* styledObject) | |
| 233 { | |
| 234 // Double check that the document did in fact use generated content rules.
Otherwise we should not have been called. | |
| 235 ASSERT(document()->usesBeforeAfterRules()); | |
| 236 | |
| 237 // In CSS2, before/after pseudo-content cannot nest. Check this first. | |
| 238 if (style()->styleType() == RenderStyle::BEFORE || style()->styleType() == R
enderStyle::AFTER) | |
| 239 return; | |
| 240 | |
| 241 RenderStyle* pseudoElementStyle = styledObject->getCachedPseudoStyle(type); | |
| 242 RenderObject* child = beforeAfterContainer(type); | |
| 243 | |
| 244 // Whether or not we currently have generated content attached. | |
| 245 bool oldContentPresent = child; | |
| 246 | |
| 247 // Whether or not we now want generated content. | |
| 248 bool newContentWanted = pseudoElementStyle && pseudoElementStyle->display()
!= NONE; | |
| 249 | |
| 250 // For <q><p/></q>, if this object is the inline continuation of the <q>, we
only want to generate | |
| 251 // :after content and not :before content. | |
| 252 if (newContentWanted && type == RenderStyle::BEFORE && isRenderInline() && t
oRenderInline(this)->isInlineContinuation()) | |
| 253 newContentWanted = false; | |
| 254 | |
| 255 // Similarly, if we're the beginning of a <q>, and there's an inline continu
ation for our object, | |
| 256 // then we don't generate the :after content. | |
| 257 if (newContentWanted && type == RenderStyle::AFTER && isRenderInline() && to
RenderInline(this)->continuation()) | |
| 258 newContentWanted = false; | |
| 259 | |
| 260 // If we don't want generated content any longer, or if we have generated co
ntent, but it's no longer | |
| 261 // identical to the new content data we want to build render objects for, th
en we nuke all | |
| 262 // of the old generated content. | |
| 263 if (!newContentWanted || (oldContentPresent && Node::diff(child->style(), ps
eudoElementStyle) == Node::Detach)) { | |
| 264 // Nuke the child. | |
| 265 if (child && child->style()->styleType() == type) { | |
| 266 oldContentPresent = false; | |
| 267 child->destroy(); | |
| 268 child = (type == RenderStyle::BEFORE) ? children()->firstChild() : c
hildren()->lastChild(); | |
| 269 } | |
| 270 } | |
| 271 | |
| 272 // If we have no pseudo-element style or if the pseudo-element style's displ
ay type is NONE, then we | |
| 273 // have no generated content and can now return. | |
| 274 if (!newContentWanted) | |
| 275 return; | |
| 276 | |
| 277 if (isRenderInline() && !pseudoElementStyle->isDisplayInlineType() && pseudo
ElementStyle->floating() == FNONE && | |
| 278 !(pseudoElementStyle->position() == AbsolutePosition || pseudoElementSty
le->position() == FixedPosition)) | |
| 279 // According to the CSS2 spec (the end of section 12.1), the only allowe
d | |
| 280 // display values for the pseudo style are NONE and INLINE for inline fl
ows. | |
| 281 // FIXME: CSS2.1 lifted this restriction, but block display types will c
rash. | |
| 282 // For now we at least relax the restriction to allow all inline types l
ike inline-block | |
| 283 // and inline-table. | |
| 284 pseudoElementStyle->setDisplay(INLINE); | |
| 285 | |
| 286 if (oldContentPresent) { | |
| 287 if (child && child->style()->styleType() == type) { | |
| 288 // We have generated content present still. We want to walk this co
ntent and update our | |
| 289 // style information with the new pseudo-element style. | |
| 290 child->setStyle(pseudoElementStyle); | |
| 291 | |
| 292 RenderObject* beforeAfterParent = findBeforeAfterParent(child); | |
| 293 if (!beforeAfterParent) | |
| 294 return; | |
| 295 | |
| 296 // Note that if we ever support additional types of generated conten
t (which should be way off | |
| 297 // in the future), this code will need to be patched. | |
| 298 for (RenderObject* genChild = beforeAfterParent->firstChild(); genCh
ild; genChild = genChild->nextSibling()) { | |
| 299 if (genChild->isText()) | |
| 300 // Generated text content is a child whose style also needs
to be set to the pseudo-element style. | |
| 301 genChild->setStyle(pseudoElementStyle); | |
| 302 else if (genChild->isImage()) { | |
| 303 // Images get an empty style that inherits from the pseudo. | |
| 304 RefPtr<RenderStyle> style = RenderStyle::create(); | |
| 305 style->inheritFrom(pseudoElementStyle); | |
| 306 genChild->setStyle(style.release()); | |
| 307 } else | |
| 308 // Must be a first-letter container. updateFirstLetter() wil
l take care of it. | |
| 309 ASSERT(genChild->style()->styleType() == RenderStyle::FIRST_
LETTER); | |
| 310 } | |
| 311 } | |
| 312 return; // We've updated the generated content. That's all we needed to
do. | |
| 313 } | |
| 314 | |
| 315 RenderObject* insertBefore = (type == RenderStyle::BEFORE) ? children()->fir
stChild() : 0; | |
| 316 | |
| 317 // Generated content consists of a single container that houses multiple chi
ldren (specified | |
| 318 // by the content property). This generated content container gets the pseu
do-element style set on it. | |
| 319 RenderObject* generatedContentContainer = 0; | |
| 320 | |
| 321 // Walk our list of generated content and create render objects for each. | |
| 322 for (const ContentData* content = pseudoElementStyle->contentData(); content
; content = content->m_next) { | |
| 323 RenderObject* renderer = 0; | |
| 324 switch (content->m_type) { | |
| 325 case CONTENT_NONE: | |
| 326 break; | |
| 327 case CONTENT_TEXT: | |
| 328 renderer = new (renderArena()) RenderTextFragment(document() /*
anonymous object */, content->m_content.m_text); | |
| 329 renderer->setStyle(pseudoElementStyle); | |
| 330 break; | |
| 331 case CONTENT_OBJECT: { | |
| 332 RenderImageGeneratedContent* image = new (renderArena()) RenderI
mageGeneratedContent(document()); // anonymous object | |
| 333 RefPtr<RenderStyle> style = RenderStyle::create(); | |
| 334 style->inheritFrom(pseudoElementStyle); | |
| 335 image->setStyle(style.release()); | |
| 336 if (StyleImage* styleImage = content->m_content.m_image) | |
| 337 image->setStyleImage(styleImage); | |
| 338 renderer = image; | |
| 339 break; | |
| 340 } | |
| 341 case CONTENT_COUNTER: | |
| 342 renderer = new (renderArena()) RenderCounter(document(), *conten
t->m_content.m_counter); | |
| 343 renderer->setStyle(pseudoElementStyle); | |
| 344 break; | |
| 345 } | |
| 346 | |
| 347 if (renderer) { | |
| 348 if (!generatedContentContainer) { | |
| 349 // Make a generated box that might be any display type now that
we are able to drill down into children | |
| 350 // to find the original content properly. | |
| 351 generatedContentContainer = RenderObject::createObject(document(
), pseudoElementStyle); | |
| 352 generatedContentContainer->setStyle(pseudoElementStyle); | |
| 353 addChild(generatedContentContainer, insertBefore); | |
| 354 } | |
| 355 generatedContentContainer->addChild(renderer); | |
| 356 } | |
| 357 } | |
| 358 } | |
| 359 | |
| 360 bool RenderContainer::isAfterContent(RenderObject* child) const | |
| 361 { | |
| 362 if (!child) | |
| 363 return false; | |
| 364 if (child->style()->styleType() != RenderStyle::AFTER) | |
| 365 return false; | |
| 366 // Text nodes don't have their own styles, so ignore the style on a text nod
e. | |
| 367 if (child->isText() && !child->isBR()) | |
| 368 return false; | |
| 369 return true; | |
| 370 } | |
| 371 | |
| 372 static void invalidateCountersInContainer(RenderObject* container) | |
| 373 { | |
| 374 if (!container) | |
| 375 return; | |
| 376 container = findBeforeAfterParent(container); | |
| 377 if (!container) | |
| 378 return; | |
| 379 for (RenderObject* content = container->firstChild(); content; content = con
tent->nextSibling()) { | |
| 380 if (content->isCounter()) | |
| 381 static_cast<RenderCounter*>(content)->invalidate(); | |
| 382 } | |
| 383 } | |
| 384 | |
| 385 void RenderContainer::invalidateCounters() | |
| 386 { | |
| 387 if (documentBeingDestroyed()) | |
| 388 return; | |
| 389 | |
| 390 invalidateCountersInContainer(beforeAfterContainer(RenderStyle::BEFORE)); | |
| 391 invalidateCountersInContainer(beforeAfterContainer(RenderStyle::AFTER)); | |
| 392 } | |
| 393 | |
| 394 void RenderContainer::appendChildNode(RenderObject* newChild, bool fullAppend) | |
| 395 { | |
| 396 ASSERT(newChild->parent() == 0); | |
| 397 ASSERT(!isBlockFlow() || (!newChild->isTableSection() && !newChild->isTableR
ow() && !newChild->isTableCell())); | |
| 398 | |
| 399 newChild->setParent(this); | |
| 400 RenderObject* lChild = children()->lastChild(); | |
| 401 | |
| 402 if (lChild) { | |
| 403 newChild->setPreviousSibling(lChild); | |
| 404 lChild->setNextSibling(newChild); | |
| 405 } else | |
| 406 children()->setFirstChild(newChild); | |
| 407 | |
| 408 children()->setLastChild(newChild); | |
| 409 | |
| 410 if (fullAppend) { | |
| 411 // Keep our layer hierarchy updated. Optimize for the common case where
we don't have any children | |
| 412 // and don't have a layer attached to ourselves. | |
| 413 RenderLayer* layer = 0; | |
| 414 if (newChild->firstChild() || newChild->hasLayer()) { | |
| 415 layer = enclosingLayer(); | |
| 416 newChild->addLayers(layer, newChild); | |
| 417 } | |
| 418 | |
| 419 // if the new child is visible but this object was not, tell the layer i
t has some visible content | |
| 420 // that needs to be drawn and layer visibility optimization can't be use
d | |
| 421 if (style()->visibility() != VISIBLE && newChild->style()->visibility()
== VISIBLE && !newChild->hasLayer()) { | |
| 422 if (!layer) | |
| 423 layer = enclosingLayer(); | |
| 424 if (layer) | |
| 425 layer->setHasVisibleContent(true); | |
| 426 } | |
| 427 | |
| 428 if (!newChild->isFloatingOrPositioned() && childrenInline()) | |
| 429 dirtyLinesFromChangedChild(newChild); | |
| 430 } | |
| 431 | |
| 432 newChild->setNeedsLayoutAndPrefWidthsRecalc(); // Goes up the containing blo
ck hierarchy. | |
| 433 if (!normalChildNeedsLayout()) | |
| 434 setChildNeedsLayout(true); // We may supply the static position for an a
bsolute positioned child. | |
| 435 | |
| 436 if (AXObjectCache::accessibilityEnabled()) | |
| 437 document()->axObjectCache()->childrenChanged(this); | |
| 438 } | |
| 439 | |
| 440 void RenderContainer::insertChildNode(RenderObject* child, RenderObject* beforeC
hild, bool fullInsert) | |
| 441 { | |
| 442 if (!beforeChild) { | |
| 443 appendChildNode(child); | |
| 444 return; | |
| 445 } | |
| 446 | |
| 447 ASSERT(!child->parent()); | |
| 448 while (beforeChild->parent() != this && beforeChild->parent()->isAnonymousBl
ock()) | |
| 449 beforeChild = beforeChild->parent(); | |
| 450 ASSERT(beforeChild->parent() == this); | |
| 451 | |
| 452 ASSERT(!isBlockFlow() || (!child->isTableSection() && !child->isTableRow() &
& !child->isTableCell())); | |
| 453 | |
| 454 if (beforeChild == children()->firstChild()) | |
| 455 children()->setFirstChild(child); | |
| 456 | |
| 457 RenderObject* prev = beforeChild->previousSibling(); | |
| 458 child->setNextSibling(beforeChild); | |
| 459 beforeChild->setPreviousSibling(child); | |
| 460 if(prev) prev->setNextSibling(child); | |
| 461 child->setPreviousSibling(prev); | |
| 462 | |
| 463 child->setParent(this); | |
| 464 | |
| 465 if (fullInsert) { | |
| 466 // Keep our layer hierarchy updated. Optimize for the common case where
we don't have any children | |
| 467 // and don't have a layer attached to ourselves. | |
| 468 RenderLayer* layer = 0; | |
| 469 if (child->firstChild() || child->hasLayer()) { | |
| 470 layer = enclosingLayer(); | |
| 471 child->addLayers(layer, child); | |
| 472 } | |
| 473 | |
| 474 // if the new child is visible but this object was not, tell the layer i
t has some visible content | |
| 475 // that needs to be drawn and layer visibility optimization can't be use
d | |
| 476 if (style()->visibility() != VISIBLE && child->style()->visibility() ==
VISIBLE && !child->hasLayer()) { | |
| 477 if (!layer) | |
| 478 layer = enclosingLayer(); | |
| 479 if (layer) | |
| 480 layer->setHasVisibleContent(true); | |
| 481 } | |
| 482 | |
| 483 | |
| 484 if (!child->isFloating() && childrenInline()) | |
| 485 dirtyLinesFromChangedChild(child); | |
| 486 } | |
| 487 | |
| 488 child->setNeedsLayoutAndPrefWidthsRecalc(); | |
| 489 if (!normalChildNeedsLayout()) | |
| 490 setChildNeedsLayout(true); // We may supply the static position for an a
bsolute positioned child. | |
| 491 | |
| 492 if (AXObjectCache::accessibilityEnabled()) | |
| 493 document()->axObjectCache()->childrenChanged(this); | |
| 494 } | |
| 495 | |
| 496 VisiblePosition RenderContainer::positionForCoordinates(int xPos, int yPos) | |
| 497 { | |
| 498 // no children...return this render object's element, if there is one, and o
ffset 0 | |
| 499 if (!children()->firstChild()) | |
| 500 return VisiblePosition(element(), 0, DOWNSTREAM); | |
| 501 | |
| 502 if (isTable() && element()) { | |
| 503 int right = contentWidth() + borderRight() + paddingRight() + borderLeft
() + paddingLeft(); | |
| 504 int bottom = contentHeight() + borderTop() + paddingTop() + borderBottom
() + paddingBottom(); | |
| 505 | |
| 506 if (xPos < 0 || xPos > right || yPos < 0 || yPos > bottom) { | |
| 507 if (xPos <= right / 2) | |
| 508 return VisiblePosition(Position(element(), 0)); | |
| 509 else | |
| 510 return VisiblePosition(Position(element(), maxDeepOffset(element
()))); | |
| 511 } | |
| 512 } | |
| 513 | |
| 514 // Pass off to the closest child. | |
| 515 int minDist = INT_MAX; | |
| 516 RenderBox* closestRenderer = 0; | |
| 517 int newX = xPos; | |
| 518 int newY = yPos; | |
| 519 if (isTableRow()) { | |
| 520 newX += x(); | |
| 521 newY += y(); | |
| 522 } | |
| 523 for (RenderObject* renderObject = children()->firstChild(); renderObject; re
nderObject = renderObject->nextSibling()) { | |
| 524 if (!renderObject->firstChild() && !renderObject->isInline() && !renderO
bject->isBlockFlow() | |
| 525 || renderObject->style()->visibility() != VISIBLE) | |
| 526 continue; | |
| 527 | |
| 528 if (!renderObject->isBox()) | |
| 529 continue; | |
| 530 | |
| 531 RenderBox* renderer = toRenderBox(renderObject); | |
| 532 | |
| 533 int top = borderTop() + paddingTop() + (isTableRow() ? 0 : renderer->y()
); | |
| 534 int bottom = top + renderer->contentHeight(); | |
| 535 int left = borderLeft() + paddingLeft() + (isTableRow() ? 0 : renderer->
x()); | |
| 536 int right = left + renderer->contentWidth(); | |
| 537 | |
| 538 if (xPos <= right && xPos >= left && yPos <= top && yPos >= bottom) { | |
| 539 if (renderer->isTableRow()) | |
| 540 return renderer->positionForCoordinates(xPos + newX - renderer->
x(), yPos + newY - renderer->y()); | |
| 541 return renderer->positionForCoordinates(xPos - renderer->x(), yPos -
renderer->y()); | |
| 542 } | |
| 543 | |
| 544 // Find the distance from (x, y) to the box. Split the space around the
box into 8 pieces | |
| 545 // and use a different compare depending on which piece (x, y) is in. | |
| 546 IntPoint cmp; | |
| 547 if (xPos > right) { | |
| 548 if (yPos < top) | |
| 549 cmp = IntPoint(right, top); | |
| 550 else if (yPos > bottom) | |
| 551 cmp = IntPoint(right, bottom); | |
| 552 else | |
| 553 cmp = IntPoint(right, yPos); | |
| 554 } else if (xPos < left) { | |
| 555 if (yPos < top) | |
| 556 cmp = IntPoint(left, top); | |
| 557 else if (yPos > bottom) | |
| 558 cmp = IntPoint(left, bottom); | |
| 559 else | |
| 560 cmp = IntPoint(left, yPos); | |
| 561 } else { | |
| 562 if (yPos < top) | |
| 563 cmp = IntPoint(xPos, top); | |
| 564 else | |
| 565 cmp = IntPoint(xPos, bottom); | |
| 566 } | |
| 567 | |
| 568 int x1minusx2 = cmp.x() - xPos; | |
| 569 int y1minusy2 = cmp.y() - yPos; | |
| 570 | |
| 571 int dist = x1minusx2 * x1minusx2 + y1minusy2 * y1minusy2; | |
| 572 if (dist < minDist) { | |
| 573 closestRenderer = renderer; | |
| 574 minDist = dist; | |
| 575 } | |
| 576 } | |
| 577 | |
| 578 if (closestRenderer) | |
| 579 return closestRenderer->positionForCoordinates(newX - closestRenderer->x
(), newY - closestRenderer->y()); | |
| 580 | |
| 581 return VisiblePosition(element(), 0, DOWNSTREAM); | |
| 582 } | 116 } |
| 583 | 117 |
| 584 void RenderContainer::addLineBoxRects(Vector<IntRect>& rects, unsigned start, un
signed end, bool) | 118 void RenderContainer::addLineBoxRects(Vector<IntRect>& rects, unsigned start, un
signed end, bool) |
| 585 { | 119 { |
| 586 if (!children()->firstChild() && (isInline() || isAnonymousBlock())) { | 120 if (!children()->firstChild() && (isInline() || isAnonymousBlock())) { |
| 587 FloatPoint absPos = localToAbsolute(FloatPoint()); | 121 FloatPoint absPos = localToAbsolute(FloatPoint()); |
| 588 absoluteRects(rects, absPos.x(), absPos.y()); | 122 absoluteRects(rects, absPos.x(), absPos.y()); |
| 589 return; | 123 return; |
| 590 } | 124 } |
| 591 | 125 |
| (...skipping 22 matching lines...) Expand all Loading... |
| 614 unsigned offset = start; | 148 unsigned offset = start; |
| 615 for (RenderObject* child = childAt(start); child && offset < end; child = ch
ild->nextSibling(), ++offset) { | 149 for (RenderObject* child = childAt(start); child && offset < end; child = ch
ild->nextSibling(), ++offset) { |
| 616 if (child->isText() || child->isInline() || child->isAnonymousBlock()) | 150 if (child->isText() || child->isInline() || child->isAnonymousBlock()) |
| 617 child->absoluteQuads(quads); | 151 child->absoluteQuads(quads); |
| 618 } | 152 } |
| 619 } | 153 } |
| 620 | 154 |
| 621 #undef DEBUG_LAYOUT | 155 #undef DEBUG_LAYOUT |
| 622 | 156 |
| 623 } // namespace WebCore | 157 } // namespace WebCore |
| OLD | NEW |