1 /* 2 * Copyright (C) 1999 Lars Knoll (knoll (at) kde.org) 3 * (C) 1999 Antti Koivisto (koivisto (at) kde.org) 4 * (C) 2000 Dirk Mueller (mueller (at) kde.org) 5 * (C) 2004 Allan Sandfeld Jensen (kde (at) carewolf.com) 6 * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2011 Apple Inc. All rights reserved. 7 * Copyright (C) 2009 Google Inc. All rights reserved. 8 * Copyright (C) 2009 Torch Mobile Inc. All rights reserved. (http://www.torchmobile.com/) 9 * 10 * This library is free software; you can redistribute it and/or 11 * modify it under the terms of the GNU Library General Public 12 * License as published by the Free Software Foundation; either 13 * version 2 of the License, or (at your option) any later version. 14 * 15 * This library is distributed in the hope that it will be useful, 16 * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 18 * Library General Public License for more details. 19 * 20 * You should have received a copy of the GNU Library General Public License 21 * along with this library; see the file COPYING.LIB. If not, write to 22 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 23 * Boston, MA 02110-1301, USA. 24 * 25 */ 26 27 #include "config.h" 28 #include "core/rendering/RenderObject.h" 29 30 #include "HTMLNames.h" 31 #include "RuntimeEnabledFeatures.h" 32 #include "core/accessibility/AXObjectCache.h" 33 #include "core/animation/ActiveAnimations.h" 34 #include "core/css/resolver/StyleResolver.h" 35 #include "core/editing/EditingBoundary.h" 36 #include "core/editing/FrameSelection.h" 37 #include "core/editing/htmlediting.h" 38 #include "core/html/HTMLAnchorElement.h" 39 #include "core/html/HTMLElement.h" 40 #include "core/html/HTMLHtmlElement.h" 41 #include "core/html/HTMLTableElement.h" 42 #include "core/page/EventHandler.h" 43 #include "core/page/Frame.h" 44 #include "core/page/FrameView.h" 45 #include "core/page/Page.h" 46 #include "core/page/Settings.h" 47 #include "core/page/UseCounter.h" 48 #include "core/page/animation/AnimationController.h" 49 #include "core/platform/Partitions.h" 50 #include "core/platform/graphics/FloatQuad.h" 51 #include "core/platform/graphics/GraphicsContext.h" 52 #include "core/platform/graphics/transforms/TransformState.h" 53 #include "core/rendering/FlowThreadController.h" 54 #include "core/rendering/HitTestResult.h" 55 #include "core/rendering/RenderCounter.h" 56 #include "core/rendering/RenderDeprecatedFlexibleBox.h" 57 #include "core/rendering/RenderFlexibleBox.h" 58 #include "core/rendering/RenderGeometryMap.h" 59 #include "core/rendering/RenderGrid.h" 60 #include "core/rendering/RenderImage.h" 61 #include "core/rendering/RenderImageResourceStyleImage.h" 62 #include "core/rendering/RenderInline.h" 63 #include "core/rendering/RenderLayer.h" 64 #include "core/rendering/RenderLayerBacking.h" 65 #include "core/rendering/RenderLayerCompositor.h" 66 #include "core/rendering/RenderLazyBlock.h" 67 #include "core/rendering/RenderListItem.h" 68 #include "core/rendering/RenderMarquee.h" 69 #include "core/rendering/RenderMultiColumnBlock.h" 70 #include "core/rendering/RenderNamedFlowThread.h" 71 #include "core/rendering/RenderRegion.h" 72 #include "core/rendering/RenderRuby.h" 73 #include "core/rendering/RenderRubyText.h" 74 #include "core/rendering/RenderScrollbarPart.h" 75 #include "core/rendering/RenderTableCaption.h" 76 #include "core/rendering/RenderTableCell.h" 77 #include "core/rendering/RenderTableCol.h" 78 #include "core/rendering/RenderTableRow.h" 79 #include "core/rendering/RenderTheme.h" 80 #include "core/rendering/RenderView.h" 81 #include "core/rendering/style/ContentData.h" 82 #include "core/rendering/style/CursorList.h" 83 #include "core/rendering/svg/SVGRenderSupport.h" 84 #include "wtf/RefCountedLeakCounter.h" 85 #include "wtf/UnusedParam.h" 86 #include <algorithm> 87 #include <stdio.h> 88 89 using namespace std; 90 91 namespace WebCore { 92 93 using namespace HTMLNames; 94 95 #ifndef NDEBUG 96 97 RenderObject::SetLayoutNeededForbiddenScope::SetLayoutNeededForbiddenScope(RenderObject* renderObject, bool isForbidden) 98 : m_renderObject(renderObject) 99 , m_preexistingForbidden(m_renderObject->isSetNeedsLayoutForbidden()) 100 { 101 m_renderObject->setNeedsLayoutIsForbidden(isForbidden); 102 } 103 104 RenderObject::SetLayoutNeededForbiddenScope::~SetLayoutNeededForbiddenScope() 105 { 106 m_renderObject->setNeedsLayoutIsForbidden(m_preexistingForbidden); 107 } 108 #endif 109 110 struct SameSizeAsRenderObject { 111 virtual ~SameSizeAsRenderObject() { } // Allocate vtable pointer. 112 void* pointers[5]; 113 #ifndef NDEBUG 114 unsigned m_debugBitfields : 2; 115 #endif 116 unsigned m_bitfields; 117 }; 118 119 COMPILE_ASSERT(sizeof(RenderObject) == sizeof(SameSizeAsRenderObject), RenderObject_should_stay_small); 120 121 bool RenderObject::s_affectsParentBlock = false; 122 123 RenderObjectAncestorLineboxDirtySet* RenderObject::s_ancestorLineboxDirtySet = 0; 124 125 void* RenderObject::operator new(size_t sz) 126 { 127 ASSERT(isMainThread()); 128 return partitionAlloc(Partitions::getRenderingPartition(), sz); 129 } 130 131 void RenderObject::operator delete(void* ptr) 132 { 133 ASSERT(isMainThread()); 134 partitionFree(ptr); 135 } 136 137 RenderObject* RenderObject::createObject(Element* element, RenderStyle* style) 138 { 139 Document* doc = element->document(); 140 141 // Minimal support for content properties replacing an entire element. 142 // Works only if we have exactly one piece of content and it's a URL. 143 // Otherwise acts as if we didn't support this feature. 144 const ContentData* contentData = style->contentData(); 145 if (contentData && !contentData->next() && contentData->isImage() && !element->isPseudoElement()) { 146 RenderImage* image = new RenderImage(element); 147 // RenderImageResourceStyleImage requires a style being present on the image but we don't want to 148 // trigger a style change now as the node is not fully attached. Moving this code to style change 149 // doesn't make sense as it should be run once at renderer creation. 150 image->setStyleInternal(style); 151 if (const StyleImage* styleImage = static_cast<const ImageContentData*>(contentData)->image()) { 152 image->setImageResource(RenderImageResourceStyleImage::create(const_cast<StyleImage*>(styleImage))); 153 image->setIsGeneratedContent(); 154 } else 155 image->setImageResource(RenderImageResource::create()); 156 image->setStyleInternal(0); 157 return image; 158 } 159 160 if (element->hasTagName(rubyTag)) { 161 if (style->display() == INLINE) 162 return new RenderRubyAsInline(element); 163 else if (style->display() == BLOCK) 164 return new RenderRubyAsBlock(element); 165 } 166 // treat <rt> as ruby text ONLY if it still has its default treatment of block 167 if (element->hasTagName(rtTag) && style->display() == BLOCK) 168 return new RenderRubyText(element); 169 if (RuntimeEnabledFeatures::cssRegionsEnabled() && style->isDisplayRegionType() && !style->regionThread().isEmpty() && doc->renderView()) 170 return new RenderRegion(element, 0); 171 172 if (style->display() == RUN_IN) 173 UseCounter::count(doc, UseCounter::CSSDisplayRunIn); 174 else if (style->display() == COMPACT) 175 UseCounter::count(doc, UseCounter::CSSDisplayCompact); 176 177 switch (style->display()) { 178 case NONE: 179 return 0; 180 case INLINE: 181 return new RenderInline(element); 182 case BLOCK: 183 case INLINE_BLOCK: 184 case RUN_IN: 185 case COMPACT: 186 if ((!style->hasAutoColumnCount() || !style->hasAutoColumnWidth()) && doc->regionBasedColumnsEnabled()) 187 return new RenderMultiColumnBlock(element); 188 return new RenderBlock(element); 189 case LIST_ITEM: 190 return new RenderListItem(element); 191 case TABLE: 192 case INLINE_TABLE: 193 return new RenderTable(element); 194 case TABLE_ROW_GROUP: 195 case TABLE_HEADER_GROUP: 196 case TABLE_FOOTER_GROUP: 197 return new RenderTableSection(element); 198 case TABLE_ROW: 199 return new RenderTableRow(element); 200 case TABLE_COLUMN_GROUP: 201 case TABLE_COLUMN: 202 return new RenderTableCol(element); 203 case TABLE_CELL: 204 return new RenderTableCell(element); 205 case TABLE_CAPTION: 206 return new RenderTableCaption(element); 207 case BOX: 208 case INLINE_BOX: 209 return new RenderDeprecatedFlexibleBox(element); 210 case FLEX: 211 case INLINE_FLEX: 212 return new RenderFlexibleBox(element); 213 case GRID: 214 case INLINE_GRID: 215 return new RenderGrid(element); 216 case LAZY_BLOCK: 217 return new RenderLazyBlock(element); 218 } 219 220 return 0; 221 } 222 223 DEFINE_DEBUG_ONLY_GLOBAL(WTF::RefCountedLeakCounter, renderObjectCounter, ("RenderObject")); 224 225 RenderObject::RenderObject(Node* node) 226 : ImageResourceClient() 227 , m_style(0) 228 , m_node(node) 229 , m_parent(0) 230 , m_previous(0) 231 , m_next(0) 232 #ifndef NDEBUG 233 , m_hasAXObject(false) 234 , m_setNeedsLayoutForbidden(false) 235 #endif 236 , m_bitfields(node) 237 { 238 #ifndef NDEBUG 239 renderObjectCounter.increment(); 240 #endif 241 } 242 243 RenderObject::~RenderObject() 244 { 245 #ifndef NDEBUG 246 ASSERT(!m_hasAXObject); 247 renderObjectCounter.decrement(); 248 #endif 249 } 250 251 RenderTheme* RenderObject::theme() const 252 { 253 ASSERT(document()->page()); 254 255 return document()->page()->theme(); 256 } 257 258 #ifndef NDEBUG 259 String RenderObject::debugName() const 260 { 261 StringBuilder name; 262 name.append(renderName()); 263 264 if (Node* node = this->node()) { 265 name.append(' '); 266 name.append(node->debugName()); 267 } 268 269 return name.toString(); 270 } 271 #endif 272 273 bool RenderObject::isDescendantOf(const RenderObject* obj) const 274 { 275 for (const RenderObject* r = this; r; r = r->m_parent) { 276 if (r == obj) 277 return true; 278 } 279 return false; 280 } 281 282 bool RenderObject::isBody() const 283 { 284 return node() && node()->hasTagName(bodyTag); 285 } 286 287 bool RenderObject::isHR() const 288 { 289 return node() && node()->hasTagName(hrTag); 290 } 291 292 bool RenderObject::isLegend() const 293 { 294 return node() && node()->hasTagName(legendTag); 295 } 296 297 void RenderObject::setFlowThreadStateIncludingDescendants(FlowThreadState state) 298 { 299 setFlowThreadState(state); 300 301 for (RenderObject* child = firstChild(); child; child = child->nextSibling()) { 302 // If the child is a fragmentation context it already updated the descendants flag accordingly. 303 if (child->isRenderFlowThread()) 304 continue; 305 ASSERT(state != child->flowThreadState()); 306 child->setFlowThreadStateIncludingDescendants(state); 307 } 308 } 309 310 bool RenderObject::requiresAnonymousTableWrappers(const RenderObject* newChild) const 311 { 312 // Check should agree with: 313 // CSS 2.1 Tables: 17.2.1 Anonymous table objects 314 // http://www.w3.org/TR/CSS21/tables.html#anonymous-boxes 315 if (newChild->isRenderTableCol()) { 316 const RenderTableCol* newTableColumn = toRenderTableCol(newChild); 317 bool isColumnInColumnGroup = newTableColumn->isTableColumn() && isRenderTableCol(); 318 return !isTable() && !isColumnInColumnGroup; 319 } else if (newChild->isTableCaption()) 320 return !isTable(); 321 else if (newChild->isTableSection()) 322 return !isTable(); 323 else if (newChild->isTableRow()) 324 return !isTableSection(); 325 else if (newChild->isTableCell()) 326 return !isTableRow(); 327 return false; 328 } 329 330 void RenderObject::addChild(RenderObject* newChild, RenderObject* beforeChild) 331 { 332 RenderObjectChildList* children = virtualChildren(); 333 ASSERT(children); 334 if (!children) 335 return; 336 337 if (requiresAnonymousTableWrappers(newChild)) { 338 // Generate an anonymous table or reuse existing one from previous child 339 // Per: 17.2.1 Anonymous table objects 3. Generate missing parents 340 // http://www.w3.org/TR/CSS21/tables.html#anonymous-boxes 341 RenderTable* table; 342 RenderObject* afterChild = beforeChild ? beforeChild->previousSibling() : children->lastChild(); 343 if (afterChild && afterChild->isAnonymous() && afterChild->isTable() && !afterChild->isBeforeContent()) 344 table = toRenderTable(afterChild); 345 else { 346 table = RenderTable::createAnonymousWithParentRenderer(this); 347 addChild(table, beforeChild); 348 } 349 table->addChild(newChild); 350 } else 351 children->insertChildNode(this, newChild, beforeChild); 352 353 if (newChild->isText() && newChild->style()->textTransform() == CAPITALIZE) 354 toRenderText(newChild)->transformText(); 355 356 // SVG creates renderers for <g display="none">, as SVG requires children of hidden 357 // <g>s to have renderers - at least that's how our implementation works. Consider: 358 // <g display="none"><foreignObject><body style="position: relative">FOO... 359 // - requiresLayer() would return true for the <body>, creating a new RenderLayer 360 // - when the document is painted, both layers are painted. The <body> layer doesn't 361 // know that it's inside a "hidden SVG subtree", and thus paints, even if it shouldn't. 362 // To avoid the problem alltogether, detect early if we're inside a hidden SVG subtree 363 // and stop creating layers at all for these cases - they're not used anyways. 364 if (newChild->hasLayer() && !layerCreationAllowedForSubtree()) 365 toRenderLayerModelObject(newChild)->layer()->removeOnlyThisLayer(); 366 } 367 368 void RenderObject::removeChild(RenderObject* oldChild) 369 { 370 RenderObjectChildList* children = virtualChildren(); 371 ASSERT(children); 372 if (!children) 373 return; 374 375 children->removeChildNode(this, oldChild); 376 } 377 378 RenderObject* RenderObject::nextInPreOrder() const 379 { 380 if (RenderObject* o = firstChild()) 381 return o; 382 383 return nextInPreOrderAfterChildren(); 384 } 385 386 RenderObject* RenderObject::nextInPreOrderAfterChildren() const 387 { 388 RenderObject* o; 389 if (!(o = nextSibling())) { 390 o = parent(); 391 while (o && !o->nextSibling()) 392 o = o->parent(); 393 if (o) 394 o = o->nextSibling(); 395 } 396 397 return o; 398 } 399 400 RenderObject* RenderObject::nextInPreOrder(const RenderObject* stayWithin) const 401 { 402 if (RenderObject* o = firstChild()) 403 return o; 404 405 return nextInPreOrderAfterChildren(stayWithin); 406 } 407 408 RenderObject* RenderObject::nextInPreOrderAfterChildren(const RenderObject* stayWithin) const 409 { 410 if (this == stayWithin) 411 return 0; 412 413 const RenderObject* current = this; 414 RenderObject* next; 415 while (!(next = current->nextSibling())) { 416 current = current->parent(); 417 if (!current || current == stayWithin) 418 return 0; 419 } 420 return next; 421 } 422 423 RenderObject* RenderObject::previousInPreOrder() const 424 { 425 if (RenderObject* o = previousSibling()) { 426 while (o->lastChild()) 427 o = o->lastChild(); 428 return o; 429 } 430 431 return parent(); 432 } 433 434 RenderObject* RenderObject::previousInPreOrder(const RenderObject* stayWithin) const 435 { 436 if (this == stayWithin) 437 return 0; 438 439 return previousInPreOrder(); 440 } 441 442 RenderObject* RenderObject::childAt(unsigned index) const 443 { 444 RenderObject* child = firstChild(); 445 for (unsigned i = 0; child && i < index; i++) 446 child = child->nextSibling(); 447 return child; 448 } 449 450 RenderObject* RenderObject::firstLeafChild() const 451 { 452 RenderObject* r = firstChild(); 453 while (r) { 454 RenderObject* n = 0; 455 n = r->firstChild(); 456 if (!n) 457 break; 458 r = n; 459 } 460 return r; 461 } 462 463 RenderObject* RenderObject::lastLeafChild() const 464 { 465 RenderObject* r = lastChild(); 466 while (r) { 467 RenderObject* n = 0; 468 n = r->lastChild(); 469 if (!n) 470 break; 471 r = n; 472 } 473 return r; 474 } 475 476 static void addLayers(RenderObject* obj, RenderLayer* parentLayer, RenderObject*& newObject, 477 RenderLayer*& beforeChild) 478 { 479 if (obj->hasLayer()) { 480 if (!beforeChild && newObject) { 481 // We need to figure out the layer that follows newObject. We only do 482 // this the first time we find a child layer, and then we update the 483 // pointer values for newObject and beforeChild used by everyone else. 484 beforeChild = newObject->parent()->findNextLayer(parentLayer, newObject); 485 newObject = 0; 486 } 487 parentLayer->addChild(toRenderLayerModelObject(obj)->layer(), beforeChild); 488 return; 489 } 490 491 for (RenderObject* curr = obj->firstChild(); curr; curr = curr->nextSibling()) 492 addLayers(curr, parentLayer, newObject, beforeChild); 493 } 494 495 void RenderObject::addLayers(RenderLayer* parentLayer) 496 { 497 if (!parentLayer) 498 return; 499 500 RenderObject* object = this; 501 RenderLayer* beforeChild = 0; 502 WebCore::addLayers(this, parentLayer, object, beforeChild); 503 } 504 505 void RenderObject::removeLayers(RenderLayer* parentLayer) 506 { 507 if (!parentLayer) 508 return; 509 510 if (hasLayer()) { 511 parentLayer->removeChild(toRenderLayerModelObject(this)->layer()); 512 return; 513 } 514 515 for (RenderObject* curr = firstChild(); curr; curr = curr->nextSibling()) 516 curr->removeLayers(parentLayer); 517 } 518 519 void RenderObject::moveLayers(RenderLayer* oldParent, RenderLayer* newParent) 520 { 521 if (!newParent) 522 return; 523 524 if (hasLayer()) { 525 RenderLayer* layer = toRenderLayerModelObject(this)->layer(); 526 ASSERT(oldParent == layer->parent()); 527 if (oldParent) 528 oldParent->removeChild(layer); 529 newParent->addChild(layer); 530 return; 531 } 532 533 for (RenderObject* curr = firstChild(); curr; curr = curr->nextSibling()) 534 curr->moveLayers(oldParent, newParent); 535 } 536 537 RenderLayer* RenderObject::findNextLayer(RenderLayer* parentLayer, RenderObject* startPoint, 538 bool checkParent) 539 { 540 // Error check the parent layer passed in. If it's null, we can't find anything. 541 if (!parentLayer) 542 return 0; 543 544 // Step 1: If our layer is a child of the desired parent, then return our layer. 545 RenderLayer* ourLayer = hasLayer() ? toRenderLayerModelObject(this)->layer() : 0; 546 if (ourLayer && ourLayer->parent() == parentLayer) 547 return ourLayer; 548 549 // Step 2: If we don't have a layer, or our layer is the desired parent, then descend 550 // into our siblings trying to find the next layer whose parent is the desired parent. 551 if (!ourLayer || ourLayer == parentLayer) { 552 for (RenderObject* curr = startPoint ? startPoint->nextSibling() : firstChild(); 553 curr; curr = curr->nextSibling()) { 554 RenderLayer* nextLayer = curr->findNextLayer(parentLayer, 0, false); 555 if (nextLayer) 556 return nextLayer; 557 } 558 } 559 560 // Step 3: If our layer is the desired parent layer, then we're finished. We didn't 561 // find anything. 562 if (parentLayer == ourLayer) 563 return 0; 564 565 // Step 4: If |checkParent| is set, climb up to our parent and check its siblings that 566 // follow us to see if we can locate a layer. 567 if (checkParent && parent()) 568 return parent()->findNextLayer(parentLayer, this, true); 569 570 return 0; 571 } 572 573 RenderLayer* RenderObject::enclosingLayer() const 574 { 575 const RenderObject* curr = this; 576 while (curr) { 577 RenderLayer* layer = curr->hasLayer() ? toRenderLayerModelObject(curr)->layer() : 0; 578 if (layer) 579 return layer; 580 curr = curr->parent(); 581 } 582 return 0; 583 } 584 585 bool RenderObject::scrollRectToVisible(const LayoutRect& rect, const ScrollAlignment& alignX, const ScrollAlignment& alignY) 586 { 587 RenderLayer* enclosingLayer = this->enclosingLayer(); 588 if (!enclosingLayer) 589 return false; 590 591 enclosingLayer->scrollRectToVisible(rect, alignX, alignY); 592 return true; 593 } 594 595 RenderBox* RenderObject::enclosingBox() const 596 { 597 RenderObject* curr = const_cast<RenderObject*>(this); 598 while (curr) { 599 if (curr->isBox()) 600 return toRenderBox(curr); 601 curr = curr->parent(); 602 } 603 604 ASSERT_NOT_REACHED(); 605 return 0; 606 } 607 608 RenderBoxModelObject* RenderObject::enclosingBoxModelObject() const 609 { 610 RenderObject* curr = const_cast<RenderObject*>(this); 611 while (curr) { 612 if (curr->isBoxModelObject()) 613 return toRenderBoxModelObject(curr); 614 curr = curr->parent(); 615 } 616 617 ASSERT_NOT_REACHED(); 618 return 0; 619 } 620 621 RenderFlowThread* RenderObject::locateFlowThreadContainingBlock() const 622 { 623 ASSERT(flowThreadState() != NotInsideFlowThread); 624 625 // See if we have the thread cached because we're in the middle of layout. 626 RenderFlowThread* flowThread = view()->flowThreadController()->currentRenderFlowThread(); 627 if (flowThread) 628 return flowThread; 629 630 // Not in the middle of layout so have to find the thread the slow way. 631 RenderObject* curr = const_cast<RenderObject*>(this); 632 while (curr) { 633 if (curr->isRenderFlowThread()) 634 return toRenderFlowThread(curr); 635 curr = curr->containingBlock(); 636 } 637 return 0; 638 } 639 640 RenderNamedFlowThread* RenderObject::renderNamedFlowThreadWrapper() const 641 { 642 RenderObject* object = const_cast<RenderObject*>(this); 643 while (object && object->isAnonymousBlock() && !object->isRenderNamedFlowThread()) 644 object = object->parent(); 645 646 return object && object->isRenderNamedFlowThread() ? toRenderNamedFlowThread(object) : 0; 647 } 648 649 RenderBlock* RenderObject::firstLineBlock() const 650 { 651 return 0; 652 } 653 654 static inline bool objectIsRelayoutBoundary(const RenderObject* object) 655 { 656 // FIXME: In future it may be possible to broaden these conditions in order to improve performance. 657 if (object->isTextControl()) 658 return true; 659 660 if (object->isSVGRoot()) 661 return true; 662 663 if (!object->hasOverflowClip()) 664 return false; 665 666 if (object->style()->width().isIntrinsicOrAuto() || object->style()->height().isIntrinsicOrAuto() || object->style()->height().isPercent()) 667 return false; 668 669 // Table parts can't be relayout roots since the table is responsible for layouting all the parts. 670 if (object->isTablePart()) 671 return false; 672 673 return true; 674 } 675 676 void RenderObject::markContainingBlocksForLayout(bool scheduleRelayout, RenderObject* newRoot) 677 { 678 ASSERT(!scheduleRelayout || !newRoot); 679 ASSERT(!isSetNeedsLayoutForbidden()); 680 681 RenderObject* object = container(); 682 RenderObject* last = this; 683 684 bool simplifiedNormalFlowLayout = needsSimplifiedNormalFlowLayout() && !selfNeedsLayout() && !normalChildNeedsLayout(); 685 686 while (object) { 687 #ifndef NDEBUG 688 // FIXME: Remove this once we remove the special cases for counters, quotes and mathml 689 // calling setNeedsLayout during preferred width computation. 690 SetLayoutNeededForbiddenScope layoutForbiddenScope(object, isSetNeedsLayoutForbidden()); 691 #endif 692 693 if (object->selfNeedsLayout()) 694 return; 695 696 // Don't mark the outermost object of an unrooted subtree. That object will be 697 // marked when the subtree is added to the document. 698 RenderObject* container = object->container(); 699 if (!container && !object->isRenderView()) 700 return; 701 if (!last->isText() && last->style()->hasOutOfFlowPosition()) { 702 bool willSkipRelativelyPositionedInlines = !object->isRenderBlock() || object->isAnonymousBlock(); 703 // Skip relatively positioned inlines and anonymous blocks to get to the enclosing RenderBlock. 704 while (object && (!object->isRenderBlock() || object->isAnonymousBlock())) 705 object = object->container(); 706 if (!object || object->posChildNeedsLayout()) 707 return; 708 if (willSkipRelativelyPositionedInlines) 709 container = object->container(); 710 object->setPosChildNeedsLayout(true); 711 simplifiedNormalFlowLayout = true; 712 ASSERT(!object->isSetNeedsLayoutForbidden()); 713 } else if (simplifiedNormalFlowLayout) { 714 if (object->needsSimplifiedNormalFlowLayout()) 715 return; 716 object->setNeedsSimplifiedNormalFlowLayout(true); 717 ASSERT(!object->isSetNeedsLayoutForbidden()); 718 } else { 719 if (object->normalChildNeedsLayout()) 720 return; 721 object->setNormalChildNeedsLayout(true); 722 ASSERT(!object->isSetNeedsLayoutForbidden()); 723 } 724 725 if (object == newRoot) 726 return; 727 728 last = object; 729 if (scheduleRelayout && objectIsRelayoutBoundary(last)) 730 break; 731 object = container; 732 } 733 734 if (scheduleRelayout) 735 last->scheduleRelayout(); 736 } 737 738 #ifndef NDEBUG 739 void RenderObject::checkBlockPositionedObjectsNeedLayout() 740 { 741 ASSERT(!needsLayout()); 742 743 if (isRenderBlock()) 744 toRenderBlock(this)->checkPositionedObjectsNeedLayout(); 745 } 746 #endif 747 748 void RenderObject::setPreferredLogicalWidthsDirty(bool shouldBeDirty, MarkingBehavior markParents) 749 { 750 bool alreadyDirty = preferredLogicalWidthsDirty(); 751 m_bitfields.setPreferredLogicalWidthsDirty(shouldBeDirty); 752 if (shouldBeDirty && !alreadyDirty && markParents == MarkContainingBlockChain && (isText() || !style()->hasOutOfFlowPosition())) 753 invalidateContainerPreferredLogicalWidths(); 754 } 755 756 void RenderObject::invalidateContainerPreferredLogicalWidths() 757 { 758 // In order to avoid pathological behavior when inlines are deeply nested, we do include them 759 // in the chain that we mark dirty (even though they're kind of irrelevant). 760 RenderObject* o = isTableCell() ? containingBlock() : container(); 761 while (o && !o->preferredLogicalWidthsDirty()) { 762 // Don't invalidate the outermost object of an unrooted subtree. That object will be 763 // invalidated when the subtree is added to the document. 764 RenderObject* container = o->isTableCell() ? o->containingBlock() : o->container(); 765 if (!container && !o->isRenderView()) 766 break; 767 768 o->m_bitfields.setPreferredLogicalWidthsDirty(true); 769 if (o->style()->hasOutOfFlowPosition()) 770 // A positioned object has no effect on the min/max width of its containing block ever. 771 // We can optimize this case and not go up any further. 772 break; 773 o = container; 774 } 775 } 776 777 void RenderObject::setLayerNeedsFullRepaint() 778 { 779 ASSERT(hasLayer()); 780 toRenderLayerModelObject(this)->layer()->setRepaintStatus(NeedsFullRepaint); 781 } 782 783 void RenderObject::setLayerNeedsFullRepaintForPositionedMovementLayout() 784 { 785 ASSERT(hasLayer()); 786 toRenderLayerModelObject(this)->layer()->setRepaintStatus(NeedsFullRepaintForPositionedMovementLayout); 787 } 788 789 RenderBlock* RenderObject::containingBlock() const 790 { 791 RenderObject* o = parent(); 792 if (!o && isRenderScrollbarPart()) 793 o = toRenderScrollbarPart(this)->rendererOwningScrollbar(); 794 if (!isText() && m_style->position() == FixedPosition) { 795 while (o) { 796 if (o->canContainFixedPositionObjects()) 797 break; 798 o = o->parent(); 799 } 800 ASSERT(!o || !o->isAnonymousBlock()); 801 } else if (!isText() && m_style->position() == AbsolutePosition) { 802 while (o) { 803 // For relpositioned inlines, we return the nearest non-anonymous enclosing block. We don't try 804 // to return the inline itself. This allows us to avoid having a positioned objects 805 // list in all RenderInlines and lets us return a strongly-typed RenderBlock* result 806 // from this method. The container() method can actually be used to obtain the 807 // inline directly. 808 if (o->style()->position() != StaticPosition && (!o->isInline() || o->isReplaced())) 809 break; 810 if (o->isRenderView()) 811 break; 812 if (o->hasTransform() && o->isRenderBlock()) 813 break; 814 815 if (o->style()->hasInFlowPosition() && o->isInline() && !o->isReplaced()) { 816 o = o->containingBlock(); 817 break; 818 } 819 if (o->isSVGForeignObject()) //foreignObject is the containing block for contents inside it 820 break; 821 822 o = o->parent(); 823 } 824 825 while (o && o->isAnonymousBlock()) 826 o = o->containingBlock(); 827 } else { 828 while (o && ((o->isInline() && !o->isReplaced()) || !o->isRenderBlock())) 829 o = o->parent(); 830 } 831 832 if (!o || !o->isRenderBlock()) 833 return 0; // This can still happen in case of an orphaned tree 834 835 return toRenderBlock(o); 836 } 837 838 static bool mustRepaintFillLayers(const RenderObject* renderer, const FillLayer* layer) 839 { 840 // Nobody will use multiple layers without wanting fancy positioning. 841 if (layer->next()) 842 return true; 843 844 // Make sure we have a valid image. 845 StyleImage* img = layer->image(); 846 if (!img || !img->canRender(renderer, renderer->style()->effectiveZoom())) 847 return false; 848 849 if (!layer->xPosition().isZero() || !layer->yPosition().isZero()) 850 return true; 851 852 EFillSizeType sizeType = layer->sizeType(); 853 854 if (sizeType == Contain || sizeType == Cover) 855 return true; 856 857 if (sizeType == SizeLength) { 858 if (layer->sizeLength().width().isPercent() || layer->sizeLength().height().isPercent()) 859 return true; 860 } else if (img->usesImageContainerSize()) 861 return true; 862 863 return false; 864 } 865 866 bool RenderObject::borderImageIsLoadedAndCanBeRendered() const 867 { 868 ASSERT(style()->hasBorder()); 869 870 StyleImage* borderImage = style()->borderImage().image(); 871 return borderImage && borderImage->canRender(this, style()->effectiveZoom()) && borderImage->isLoaded(); 872 } 873 874 bool RenderObject::mustRepaintBackgroundOrBorder() const 875 { 876 if (hasMask() && mustRepaintFillLayers(this, style()->maskLayers())) 877 return true; 878 879 // If we don't have a background/border/mask, then nothing to do. 880 if (!hasBoxDecorations()) 881 return false; 882 883 if (mustRepaintFillLayers(this, style()->backgroundLayers())) 884 return true; 885 886 // Our fill layers are ok. Let's check border. 887 if (style()->hasBorder() && borderImageIsLoadedAndCanBeRendered()) 888 return true; 889 890 return false; 891 } 892 893 void RenderObject::drawLineForBoxSide(GraphicsContext* graphicsContext, int x1, int y1, int x2, int y2, 894 BoxSide side, Color color, EBorderStyle style, 895 int adjacentWidth1, int adjacentWidth2, bool antialias) 896 { 897 int thickness; 898 int length; 899 if (side == BSTop || side == BSBottom) { 900 thickness = y2 - y1; 901 length = x2 - x1; 902 } else { 903 thickness = x2 - x1; 904 length = y2 - y1; 905 } 906 907 // FIXME: We really would like this check to be an ASSERT as we don't want to draw empty borders. However 908 // nothing guarantees that the following recursive calls to drawLineForBoxSide will have non-null dimensions. 909 if (!thickness || !length) 910 return; 911 912 if (style == DOUBLE && thickness < 3) 913 style = SOLID; 914 915 switch (style) { 916 case BNONE: 917 case BHIDDEN: 918 return; 919 case DOTTED: 920 case DASHED: { 921 if (thickness > 0) { 922 bool wasAntialiased = graphicsContext->shouldAntialias(); 923 StrokeStyle oldStrokeStyle = graphicsContext->strokeStyle(); 924 graphicsContext->setShouldAntialias(antialias); 925 graphicsContext->setStrokeColor(color); 926 graphicsContext->setStrokeThickness(thickness); 927 graphicsContext->setStrokeStyle(style == DASHED ? DashedStroke : DottedStroke); 928 929 switch (side) { 930 case BSBottom: 931 case BSTop: 932 graphicsContext->drawLine(IntPoint(x1, (y1 + y2) / 2), IntPoint(x2, (y1 + y2) / 2)); 933 break; 934 case BSRight: 935 case BSLeft: 936 graphicsContext->drawLine(IntPoint((x1 + x2) / 2, y1), IntPoint((x1 + x2) / 2, y2)); 937 break; 938 } 939 graphicsContext->setShouldAntialias(wasAntialiased); 940 graphicsContext->setStrokeStyle(oldStrokeStyle); 941 } 942 break; 943 } 944 case DOUBLE: { 945 int thirdOfThickness = (thickness + 1) / 3; 946 ASSERT(thirdOfThickness); 947 948 if (adjacentWidth1 == 0 && adjacentWidth2 == 0) { 949 StrokeStyle oldStrokeStyle = graphicsContext->strokeStyle(); 950 graphicsContext->setStrokeStyle(NoStroke); 951 graphicsContext->setFillColor(color); 952 953 bool wasAntialiased = graphicsContext->shouldAntialias(); 954 graphicsContext->setShouldAntialias(antialias); 955 956 switch (side) { 957 case BSTop: 958 case BSBottom: 959 graphicsContext->drawRect(IntRect(x1, y1, length, thirdOfThickness)); 960 graphicsContext->drawRect(IntRect(x1, y2 - thirdOfThickness, length, thirdOfThickness)); 961 break; 962 case BSLeft: 963 case BSRight: 964 // FIXME: Why do we offset the border by 1 in this case but not the other one? 965 if (length > 1) { 966 graphicsContext->drawRect(IntRect(x1, y1 + 1, thirdOfThickness, length - 1)); 967 graphicsContext->drawRect(IntRect(x2 - thirdOfThickness, y1 + 1, thirdOfThickness, length - 1)); 968 } 969 break; 970 } 971 972 graphicsContext->setShouldAntialias(wasAntialiased); 973 graphicsContext->setStrokeStyle(oldStrokeStyle); 974 } else { 975 int adjacent1BigThird = ((adjacentWidth1 > 0) ? adjacentWidth1 + 1 : adjacentWidth1 - 1) / 3; 976 int adjacent2BigThird = ((adjacentWidth2 > 0) ? adjacentWidth2 + 1 : adjacentWidth2 - 1) / 3; 977 978 switch (side) { 979 case BSTop: 980 drawLineForBoxSide(graphicsContext, x1 + max((-adjacentWidth1 * 2 + 1) / 3, 0), 981 y1, x2 - max((-adjacentWidth2 * 2 + 1) / 3, 0), y1 + thirdOfThickness, 982 side, color, SOLID, adjacent1BigThird, adjacent2BigThird, antialias); 983 drawLineForBoxSide(graphicsContext, x1 + max((adjacentWidth1 * 2 + 1) / 3, 0), 984 y2 - thirdOfThickness, x2 - max((adjacentWidth2 * 2 + 1) / 3, 0), y2, 985 side, color, SOLID, adjacent1BigThird, adjacent2BigThird, antialias); 986 break; 987 case BSLeft: 988 drawLineForBoxSide(graphicsContext, x1, y1 + max((-adjacentWidth1 * 2 + 1) / 3, 0), 989 x1 + thirdOfThickness, y2 - max((-adjacentWidth2 * 2 + 1) / 3, 0), 990 side, color, SOLID, adjacent1BigThird, adjacent2BigThird, antialias); 991 drawLineForBoxSide(graphicsContext, x2 - thirdOfThickness, y1 + max((adjacentWidth1 * 2 + 1) / 3, 0), 992 x2, y2 - max((adjacentWidth2 * 2 + 1) / 3, 0), 993 side, color, SOLID, adjacent1BigThird, adjacent2BigThird, antialias); 994 break; 995 case BSBottom: 996 drawLineForBoxSide(graphicsContext, x1 + max((adjacentWidth1 * 2 + 1) / 3, 0), 997 y1, x2 - max((adjacentWidth2 * 2 + 1) / 3, 0), y1 + thirdOfThickness, 998 side, color, SOLID, adjacent1BigThird, adjacent2BigThird, antialias); 999 drawLineForBoxSide(graphicsContext, x1 + max((-adjacentWidth1 * 2 + 1) / 3, 0), 1000 y2 - thirdOfThickness, x2 - max((-adjacentWidth2 * 2 + 1) / 3, 0), y2, 1001 side, color, SOLID, adjacent1BigThird, adjacent2BigThird, antialias); 1002 break; 1003 case BSRight: 1004 drawLineForBoxSide(graphicsContext, x1, y1 + max((adjacentWidth1 * 2 + 1) / 3, 0), 1005 x1 + thirdOfThickness, y2 - max((adjacentWidth2 * 2 + 1) / 3, 0), 1006 side, color, SOLID, adjacent1BigThird, adjacent2BigThird, antialias); 1007 drawLineForBoxSide(graphicsContext, x2 - thirdOfThickness, y1 + max((-adjacentWidth1 * 2 + 1) / 3, 0), 1008 x2, y2 - max((-adjacentWidth2 * 2 + 1) / 3, 0), 1009 side, color, SOLID, adjacent1BigThird, adjacent2BigThird, antialias); 1010 break; 1011 default: 1012 break; 1013 } 1014 } 1015 break; 1016 } 1017 case RIDGE: 1018 case GROOVE: { 1019 EBorderStyle s1; 1020 EBorderStyle s2; 1021 if (style == GROOVE) { 1022 s1 = INSET; 1023 s2 = OUTSET; 1024 } else { 1025 s1 = OUTSET; 1026 s2 = INSET; 1027 } 1028 1029 int adjacent1BigHalf = ((adjacentWidth1 > 0) ? adjacentWidth1 + 1 : adjacentWidth1 - 1) / 2; 1030 int adjacent2BigHalf = ((adjacentWidth2 > 0) ? adjacentWidth2 + 1 : adjacentWidth2 - 1) / 2; 1031 1032 switch (side) { 1033 case BSTop: 1034 drawLineForBoxSide(graphicsContext, x1 + max(-adjacentWidth1, 0) / 2, y1, x2 - max(-adjacentWidth2, 0) / 2, (y1 + y2 + 1) / 2, 1035 side, color, s1, adjacent1BigHalf, adjacent2BigHalf, antialias); 1036 drawLineForBoxSide(graphicsContext, x1 + max(adjacentWidth1 + 1, 0) / 2, (y1 + y2 + 1) / 2, x2 - max(adjacentWidth2 + 1, 0) / 2, y2, 1037 side, color, s2, adjacentWidth1 / 2, adjacentWidth2 / 2, antialias); 1038 break; 1039 case BSLeft: 1040 drawLineForBoxSide(graphicsContext, x1, y1 + max(-adjacentWidth1, 0) / 2, (x1 + x2 + 1) / 2, y2 - max(-adjacentWidth2, 0) / 2, 1041 side, color, s1, adjacent1BigHalf, adjacent2BigHalf, antialias); 1042 drawLineForBoxSide(graphicsContext, (x1 + x2 + 1) / 2, y1 + max(adjacentWidth1 + 1, 0) / 2, x2, y2 - max(adjacentWidth2 + 1, 0) / 2, 1043 side, color, s2, adjacentWidth1 / 2, adjacentWidth2 / 2, antialias); 1044 break; 1045 case BSBottom: 1046 drawLineForBoxSide(graphicsContext, x1 + max(adjacentWidth1, 0) / 2, y1, x2 - max(adjacentWidth2, 0) / 2, (y1 + y2 + 1) / 2, 1047 side, color, s2, adjacent1BigHalf, adjacent2BigHalf, antialias); 1048 drawLineForBoxSide(graphicsContext, x1 + max(-adjacentWidth1 + 1, 0) / 2, (y1 + y2 + 1) / 2, x2 - max(-adjacentWidth2 + 1, 0) / 2, y2, 1049 side, color, s1, adjacentWidth1 / 2, adjacentWidth2 / 2, antialias); 1050 break; 1051 case BSRight: 1052 drawLineForBoxSide(graphicsContext, x1, y1 + max(adjacentWidth1, 0) / 2, (x1 + x2 + 1) / 2, y2 - max(adjacentWidth2, 0) / 2, 1053 side, color, s2, adjacent1BigHalf, adjacent2BigHalf, antialias); 1054 drawLineForBoxSide(graphicsContext, (x1 + x2 + 1) / 2, y1 + max(-adjacentWidth1 + 1, 0) / 2, x2, y2 - max(-adjacentWidth2 + 1, 0) / 2, 1055 side, color, s1, adjacentWidth1 / 2, adjacentWidth2 / 2, antialias); 1056 break; 1057 } 1058 break; 1059 } 1060 case INSET: 1061 // FIXME: Maybe we should lighten the colors on one side like Firefox. 1062 // https://bugs.webkit.org/show_bug.cgi?id=58608 1063 if (side == BSTop || side == BSLeft) 1064 color = color.dark(); 1065 // fall through 1066 case OUTSET: 1067 if (style == OUTSET && (side == BSBottom || side == BSRight)) 1068 color = color.dark(); 1069 // fall through 1070 case SOLID: { 1071 StrokeStyle oldStrokeStyle = graphicsContext->strokeStyle(); 1072 graphicsContext->setStrokeStyle(NoStroke); 1073 graphicsContext->setFillColor(color); 1074 ASSERT(x2 >= x1); 1075 ASSERT(y2 >= y1); 1076 if (!adjacentWidth1 && !adjacentWidth2) { 1077 // Turn off antialiasing to match the behavior of drawConvexPolygon(); 1078 // this matters for rects in transformed contexts. 1079 bool wasAntialiased = graphicsContext->shouldAntialias(); 1080 graphicsContext->setShouldAntialias(antialias); 1081 graphicsContext->drawRect(IntRect(x1, y1, x2 - x1, y2 - y1)); 1082 graphicsContext->setShouldAntialias(wasAntialiased); 1083 graphicsContext->setStrokeStyle(oldStrokeStyle); 1084 return; 1085 } 1086 FloatPoint quad[4]; 1087 switch (side) { 1088 case BSTop: 1089 quad[0] = FloatPoint(x1 + max(-adjacentWidth1, 0), y1); 1090 quad[1] = FloatPoint(x1 + max(adjacentWidth1, 0), y2); 1091 quad[2] = FloatPoint(x2 - max(adjacentWidth2, 0), y2); 1092 quad[3] = FloatPoint(x2 - max(-adjacentWidth2, 0), y1); 1093 break; 1094 case BSBottom: 1095 quad[0] = FloatPoint(x1 + max(adjacentWidth1, 0), y1); 1096 quad[1] = FloatPoint(x1 + max(-adjacentWidth1, 0), y2); 1097 quad[2] = FloatPoint(x2 - max(-adjacentWidth2, 0), y2); 1098 quad[3] = FloatPoint(x2 - max(adjacentWidth2, 0), y1); 1099 break; 1100 case BSLeft: 1101 quad[0] = FloatPoint(x1, y1 + max(-adjacentWidth1, 0)); 1102 quad[1] = FloatPoint(x1, y2 - max(-adjacentWidth2, 0)); 1103 quad[2] = FloatPoint(x2, y2 - max(adjacentWidth2, 0)); 1104 quad[3] = FloatPoint(x2, y1 + max(adjacentWidth1, 0)); 1105 break; 1106 case BSRight: 1107 quad[0] = FloatPoint(x1, y1 + max(adjacentWidth1, 0)); 1108 quad[1] = FloatPoint(x1, y2 - max(adjacentWidth2, 0)); 1109 quad[2] = FloatPoint(x2, y2 - max(-adjacentWidth2, 0)); 1110 quad[3] = FloatPoint(x2, y1 + max(-adjacentWidth1, 0)); 1111 break; 1112 } 1113 1114 graphicsContext->drawConvexPolygon(4, quad, antialias); 1115 graphicsContext->setStrokeStyle(oldStrokeStyle); 1116 break; 1117 } 1118 } 1119 } 1120 1121 void RenderObject::paintFocusRing(PaintInfo& paintInfo, const LayoutPoint& paintOffset, RenderStyle* style) 1122 { 1123 Vector<IntRect> focusRingRects; 1124 addFocusRingRects(focusRingRects, paintOffset, paintInfo.paintContainer); 1125 if (style->outlineStyleIsAuto()) 1126 paintInfo.context->drawFocusRing(focusRingRects, style->outlineWidth(), style->outlineOffset(), resolveColor(style, CSSPropertyOutlineColor)); 1127 else 1128 addPDFURLRect(paintInfo.context, unionRect(focusRingRects)); 1129 } 1130 1131 void RenderObject::addPDFURLRect(GraphicsContext* context, const LayoutRect& rect) 1132 { 1133 if (rect.isEmpty()) 1134 return; 1135 Node* n = node(); 1136 if (!n || !n->isLink() || !n->isElementNode()) 1137 return; 1138 const AtomicString& href = toElement(n)->getAttribute(hrefAttr); 1139 if (href.isNull()) 1140 return; 1141 KURL url = n->document()->completeURL(href); 1142 if (!url.isValid()) 1143 return; 1144 if (context->supportsURLFragments() && url.hasFragmentIdentifier() && equalIgnoringFragmentIdentifier(url, n->document()->baseURL())) { 1145 String name = url.fragmentIdentifier(); 1146 if (document()->findAnchor(name)) 1147 context->setURLFragmentForRect(name, pixelSnappedIntRect(rect)); 1148 return; 1149 } 1150 context->setURLForRect(url, pixelSnappedIntRect(rect)); 1151 } 1152 1153 void RenderObject::paintOutline(PaintInfo& paintInfo, const LayoutRect& paintRect) 1154 { 1155 if (!hasOutline()) 1156 return; 1157 1158 RenderStyle* styleToUse = style(); 1159 LayoutUnit outlineWidth = styleToUse->outlineWidth(); 1160 1161 int outlineOffset = styleToUse->outlineOffset(); 1162 1163 if (styleToUse->outlineStyleIsAuto() || hasOutlineAnnotation()) { 1164 if (theme()->shouldDrawDefaultFocusRing(this)) { 1165 // Only paint the focus ring by hand if the theme isn't able to draw the focus ring. 1166 paintFocusRing(paintInfo, paintRect.location(), styleToUse); 1167 } 1168 } 1169 1170 if (styleToUse->outlineStyleIsAuto() || styleToUse->outlineStyle() == BNONE) 1171 return; 1172 1173 IntRect inner = pixelSnappedIntRect(paintRect); 1174 inner.inflate(outlineOffset); 1175 1176 IntRect outer = pixelSnappedIntRect(inner); 1177 outer.inflate(outlineWidth); 1178 1179 // FIXME: This prevents outlines from painting inside the object. See bug 12042 1180 if (outer.isEmpty()) 1181 return; 1182 1183 EBorderStyle outlineStyle = styleToUse->outlineStyle(); 1184 Color outlineColor = resolveColor(styleToUse, CSSPropertyOutlineColor); 1185 1186 GraphicsContext* graphicsContext = paintInfo.context; 1187 bool useTransparencyLayer = outlineColor.hasAlpha(); 1188 if (useTransparencyLayer) { 1189 if (outlineStyle == SOLID) { 1190 Path path; 1191 path.addRect(outer); 1192 path.addRect(inner); 1193 graphicsContext->setFillRule(RULE_EVENODD); 1194 graphicsContext->setFillColor(outlineColor); 1195 graphicsContext->fillPath(path); 1196 return; 1197 } 1198 graphicsContext->beginTransparencyLayer(static_cast<float>(outlineColor.alpha()) / 255); 1199 outlineColor = Color(outlineColor.red(), outlineColor.green(), outlineColor.blue()); 1200 } 1201 1202 int leftOuter = outer.x(); 1203 int leftInner = inner.x(); 1204 int rightOuter = outer.maxX(); 1205 int rightInner = inner.maxX(); 1206 int topOuter = outer.y(); 1207 int topInner = inner.y(); 1208 int bottomOuter = outer.maxY(); 1209 int bottomInner = inner.maxY(); 1210 1211 drawLineForBoxSide(graphicsContext, leftOuter, topOuter, leftInner, bottomOuter, BSLeft, outlineColor, outlineStyle, outlineWidth, outlineWidth); 1212 drawLineForBoxSide(graphicsContext, leftOuter, topOuter, rightOuter, topInner, BSTop, outlineColor, outlineStyle, outlineWidth, outlineWidth); 1213 drawLineForBoxSide(graphicsContext, rightInner, topOuter, rightOuter, bottomOuter, BSRight, outlineColor, outlineStyle, outlineWidth, outlineWidth); 1214 drawLineForBoxSide(graphicsContext, leftOuter, bottomInner, rightOuter, bottomOuter, BSBottom, outlineColor, outlineStyle, outlineWidth, outlineWidth); 1215 1216 if (useTransparencyLayer) 1217 graphicsContext->endTransparencyLayer(); 1218 } 1219 1220 IntRect RenderObject::absoluteBoundingBoxRect(bool useTransforms) const 1221 { 1222 if (useTransforms) { 1223 Vector<FloatQuad> quads; 1224 absoluteQuads(quads); 1225 1226 size_t n = quads.size(); 1227 if (!n) 1228 return IntRect(); 1229 1230 IntRect result = quads[0].enclosingBoundingBox(); 1231 for (size_t i = 1; i < n; ++i) 1232 result.unite(quads[i].enclosingBoundingBox()); 1233 return result; 1234 } 1235 1236 FloatPoint absPos = localToAbsolute(); 1237 Vector<IntRect> rects; 1238 absoluteRects(rects, flooredLayoutPoint(absPos)); 1239 1240 size_t n = rects.size(); 1241 if (!n) 1242 return IntRect(); 1243 1244 LayoutRect result = rects[0]; 1245 for (size_t i = 1; i < n; ++i) 1246 result.unite(rects[i]); 1247 return pixelSnappedIntRect(result); 1248 } 1249 1250 void RenderObject::absoluteFocusRingQuads(Vector<FloatQuad>& quads) 1251 { 1252 Vector<IntRect> rects; 1253 // FIXME: addFocusRingRects() needs to be passed this transform-unaware 1254 // localToAbsolute() offset here because RenderInline::addFocusRingRects() 1255 // implicitly assumes that. This doesn't work correctly with transformed 1256 // descendants. 1257 FloatPoint absolutePoint = localToAbsolute(); 1258 addFocusRingRects(rects, flooredLayoutPoint(absolutePoint)); 1259 size_t count = rects.size(); 1260 for (size_t i = 0; i < count; ++i) { 1261 IntRect rect = rects[i]; 1262 rect.move(-absolutePoint.x(), -absolutePoint.y()); 1263 quads.append(localToAbsoluteQuad(FloatQuad(rect))); 1264 } 1265 } 1266 1267 FloatRect RenderObject::absoluteBoundingBoxRectForRange(const Range* range) 1268 { 1269 if (!range || !range->startContainer()) 1270 return FloatRect(); 1271 1272 if (range->ownerDocument()) 1273 range->ownerDocument()->updateLayout(); 1274 1275 Vector<FloatQuad> quads; 1276 range->textQuads(quads); 1277 1278 FloatRect result; 1279 for (size_t i = 0; i < quads.size(); ++i) 1280 result.unite(quads[i].boundingBox()); 1281 1282 return result; 1283 } 1284 1285 void RenderObject::addAbsoluteRectForLayer(LayoutRect& result) 1286 { 1287 if (hasLayer()) 1288 result.unite(absoluteBoundingBoxRectIgnoringTransforms()); 1289 for (RenderObject* current = firstChild(); current; current = current->nextSibling()) 1290 current->addAbsoluteRectForLayer(result); 1291 } 1292 1293 LayoutRect RenderObject::paintingRootRect(LayoutRect& topLevelRect) 1294 { 1295 LayoutRect result = absoluteBoundingBoxRectIgnoringTransforms(); 1296 topLevelRect = result; 1297 for (RenderObject* current = firstChild(); current; current = current->nextSibling()) 1298 current->addAbsoluteRectForLayer(result); 1299 return result; 1300 } 1301 1302 void RenderObject::paint(PaintInfo&, const LayoutPoint&) 1303 { 1304 } 1305 1306 RenderLayerModelObject* RenderObject::containerForRepaint() const 1307 { 1308 RenderView* v = view(); 1309 if (!v) 1310 return 0; 1311 1312 RenderLayerModelObject* repaintContainer = 0; 1313 1314 if (v->usesCompositing()) { 1315 if (RenderLayer* parentLayer = enclosingLayer()) { 1316 RenderLayer* compLayer = parentLayer->enclosingCompositingLayerForRepaint(); 1317 if (compLayer) 1318 repaintContainer = compLayer->renderer(); 1319 } 1320 } 1321 1322 if (document()->view()->hasSoftwareFilters()) { 1323 if (RenderLayer* parentLayer = enclosingLayer()) { 1324 RenderLayer* enclosingFilterLayer = parentLayer->enclosingFilterLayer(); 1325 if (enclosingFilterLayer) 1326 return enclosingFilterLayer->renderer(); 1327 } 1328 } 1329 1330 // If we have a flow thread, then we need to do individual repaints within the RenderRegions instead. 1331 // Return the flow thread as a repaint container in order to create a chokepoint that allows us to change 1332 // repainting to do individual region repaints. 1333 RenderFlowThread* parentRenderFlowThread = flowThreadContainingBlock(); 1334 if (parentRenderFlowThread) { 1335 // The ancestor document will do the reparenting when the repaint propagates further up. 1336 // We're just a seamless child document, and we don't need to do the hacking. 1337 if (parentRenderFlowThread && parentRenderFlowThread->document() != document()) 1338 return repaintContainer; 1339 // If we have already found a repaint container then we will repaint into that container only if it is part of the same 1340 // flow thread. Otherwise we will need to catch the repaint call and send it to the flow thread. 1341 RenderFlowThread* repaintContainerFlowThread = repaintContainer ? repaintContainer->flowThreadContainingBlock() : 0; 1342 if (!repaintContainerFlowThread || repaintContainerFlowThread != parentRenderFlowThread) 1343 repaintContainer = parentRenderFlowThread; 1344 } 1345 return repaintContainer; 1346 } 1347 1348 void RenderObject::repaintUsingContainer(const RenderLayerModelObject* repaintContainer, const IntRect& r) const 1349 { 1350 if (!repaintContainer) { 1351 view()->repaintViewRectangle(r); 1352 return; 1353 } 1354 1355 if (repaintContainer->isRenderFlowThread()) { 1356 toRenderFlowThread(repaintContainer)->repaintRectangleInRegions(r); 1357 return; 1358 } 1359 1360 if (repaintContainer->hasFilter() && repaintContainer->layer() && repaintContainer->layer()->requiresFullLayerImageForFilters()) { 1361 repaintContainer->layer()->setFilterBackendNeedsRepaintingInRect(r); 1362 return; 1363 } 1364 1365 RenderView* v = view(); 1366 if (repaintContainer->isRenderView()) { 1367 ASSERT(repaintContainer == v); 1368 bool viewHasCompositedLayer = v->hasLayer() && v->layer()->isComposited(); 1369 if (!viewHasCompositedLayer) { 1370 IntRect repaintRectangle = r; 1371 if (viewHasCompositedLayer && v->layer()->transform()) 1372 repaintRectangle = v->layer()->transform()->mapRect(r); 1373 v->repaintViewRectangle(repaintRectangle); 1374 return; 1375 } 1376 } 1377 1378 if (v->usesCompositing()) { 1379 ASSERT(repaintContainer->hasLayer() && repaintContainer->layer()->isComposited()); 1380 repaintContainer->layer()->setBackingNeedsRepaintInRect(r); 1381 } 1382 } 1383 1384 void RenderObject::repaint() const 1385 { 1386 // Don't repaint if we're unrooted (note that view() still returns the view when unrooted) 1387 RenderView* view; 1388 if (!isRooted(&view)) 1389 return; 1390 1391 if (view->printing()) 1392 return; // Don't repaint if we're printing. 1393 1394 RenderLayerModelObject* repaintContainer = containerForRepaint(); 1395 repaintUsingContainer(repaintContainer ? repaintContainer : view, pixelSnappedIntRect(clippedOverflowRectForRepaint(repaintContainer))); 1396 } 1397 1398 void RenderObject::repaintRectangle(const LayoutRect& r) const 1399 { 1400 // Don't repaint if we're unrooted (note that view() still returns the view when unrooted) 1401 RenderView* view; 1402 if (!isRooted(&view)) 1403 return; 1404 1405 if (view->printing()) 1406 return; // Don't repaint if we're printing. 1407 1408 LayoutRect dirtyRect(r); 1409 1410 // FIXME: layoutDelta needs to be applied in parts before/after transforms and 1411 // repaint containers. https://bugs.webkit.org/show_bug.cgi?id=23308 1412 dirtyRect.move(view->layoutDelta()); 1413 1414 RenderLayerModelObject* repaintContainer = containerForRepaint(); 1415 computeRectForRepaint(repaintContainer, dirtyRect); 1416 repaintUsingContainer(repaintContainer ? repaintContainer : view, pixelSnappedIntRect(dirtyRect)); 1417 } 1418 1419 IntRect RenderObject::pixelSnappedAbsoluteClippedOverflowRect() const 1420 { 1421 return pixelSnappedIntRect(absoluteClippedOverflowRect()); 1422 } 1423 1424 bool RenderObject::repaintAfterLayoutIfNeeded(const RenderLayerModelObject* repaintContainer, const LayoutRect& oldBounds, const LayoutRect& oldOutlineBox, const LayoutRect* newBoundsPtr, const LayoutRect* newOutlineBoxRectPtr) 1425 { 1426 RenderView* v = view(); 1427 if (v->printing()) 1428 return false; // Don't repaint if we're printing. 1429 1430 // This ASSERT fails due to animations. See https://bugs.webkit.org/show_bug.cgi?id=37048 1431 // ASSERT(!newBoundsPtr || *newBoundsPtr == clippedOverflowRectForRepaint(repaintContainer)); 1432 LayoutRect newBounds = newBoundsPtr ? *newBoundsPtr : clippedOverflowRectForRepaint(repaintContainer); 1433 LayoutRect newOutlineBox; 1434 1435 bool fullRepaint = selfNeedsLayout(); 1436 // Presumably a background or a border exists if border-fit:lines was specified. 1437 if (!fullRepaint && style()->borderFit() == BorderFitLines) 1438 fullRepaint = true; 1439 if (!fullRepaint && style()->hasBorderRadius()) { 1440 // If a border-radius exists and width/height is smaller than 1441 // radius width/height, we cannot use delta-repaint. 1442 RoundedRect oldRoundedRect = style()->getRoundedBorderFor(oldBounds, v); 1443 RoundedRect newRoundedRect = style()->getRoundedBorderFor(newBounds, v); 1444 fullRepaint = oldRoundedRect.radii() != newRoundedRect.radii(); 1445 } 1446 if (!fullRepaint) { 1447 // This ASSERT fails due to animations. See https://bugs.webkit.org/show_bug.cgi?id=37048 1448 // ASSERT(!newOutlineBoxRectPtr || *newOutlineBoxRectPtr == outlineBoundsForRepaint(repaintContainer)); 1449 newOutlineBox = newOutlineBoxRectPtr ? *newOutlineBoxRectPtr : outlineBoundsForRepaint(repaintContainer); 1450 if (newOutlineBox.location() != oldOutlineBox.location() || (mustRepaintBackgroundOrBorder() && (newBounds != oldBounds || newOutlineBox != oldOutlineBox))) 1451 fullRepaint = true; 1452 } 1453 1454 if (!repaintContainer) 1455 repaintContainer = v; 1456 1457 if (fullRepaint) { 1458 repaintUsingContainer(repaintContainer, pixelSnappedIntRect(oldBounds)); 1459 if (newBounds != oldBounds) 1460 repaintUsingContainer(repaintContainer, pixelSnappedIntRect(newBounds)); 1461 return true; 1462 } 1463 1464 if (newBounds == oldBounds && newOutlineBox == oldOutlineBox) 1465 return false; 1466 1467 LayoutUnit deltaLeft = newBounds.x() - oldBounds.x(); 1468 if (deltaLeft > 0) 1469 repaintUsingContainer(repaintContainer, pixelSnappedIntRect(oldBounds.x(), oldBounds.y(), deltaLeft, oldBounds.height())); 1470 else if (deltaLeft < 0) 1471 repaintUsingContainer(repaintContainer, pixelSnappedIntRect(newBounds.x(), newBounds.y(), -deltaLeft, newBounds.height())); 1472 1473 LayoutUnit deltaRight = newBounds.maxX() - oldBounds.maxX(); 1474 if (deltaRight > 0) 1475 repaintUsingContainer(repaintContainer, pixelSnappedIntRect(oldBounds.maxX(), newBounds.y(), deltaRight, newBounds.height())); 1476 else if (deltaRight < 0) 1477 repaintUsingContainer(repaintContainer, pixelSnappedIntRect(newBounds.maxX(), oldBounds.y(), -deltaRight, oldBounds.height())); 1478 1479 LayoutUnit deltaTop = newBounds.y() - oldBounds.y(); 1480 if (deltaTop > 0) 1481 repaintUsingContainer(repaintContainer, pixelSnappedIntRect(oldBounds.x(), oldBounds.y(), oldBounds.width(), deltaTop)); 1482 else if (deltaTop < 0) 1483 repaintUsingContainer(repaintContainer, pixelSnappedIntRect(newBounds.x(), newBounds.y(), newBounds.width(), -deltaTop)); 1484 1485 LayoutUnit deltaBottom = newBounds.maxY() - oldBounds.maxY(); 1486 if (deltaBottom > 0) 1487 repaintUsingContainer(repaintContainer, pixelSnappedIntRect(newBounds.x(), oldBounds.maxY(), newBounds.width(), deltaBottom)); 1488 else if (deltaBottom < 0) 1489 repaintUsingContainer(repaintContainer, pixelSnappedIntRect(oldBounds.x(), newBounds.maxY(), oldBounds.width(), -deltaBottom)); 1490 1491 if (newOutlineBox == oldOutlineBox) 1492 return false; 1493 1494 // We didn't move, but we did change size. Invalidate the delta, which will consist of possibly 1495 // two rectangles (but typically only one). 1496 RenderStyle* outlineStyle = outlineStyleForRepaint(); 1497 LayoutUnit outlineWidth = outlineStyle->outlineSize(); 1498 LayoutBoxExtent insetShadowExtent = style()->getBoxShadowInsetExtent(); 1499 LayoutUnit width = absoluteValue(newOutlineBox.width() - oldOutlineBox.width()); 1500 if (width) { 1501 LayoutUnit shadowLeft; 1502 LayoutUnit shadowRight; 1503 style()->getBoxShadowHorizontalExtent(shadowLeft, shadowRight); 1504 int borderRight = isBox() ? toRenderBox(this)->borderRight() : 0; 1505 LayoutUnit boxWidth = isBox() ? toRenderBox(this)->width() : LayoutUnit(); 1506 LayoutUnit minInsetRightShadowExtent = min<LayoutUnit>(-insetShadowExtent.right(), min<LayoutUnit>(newBounds.width(), oldBounds.width())); 1507 LayoutUnit borderWidth = max<LayoutUnit>(borderRight, max<LayoutUnit>(valueForLength(style()->borderTopRightRadius().width(), boxWidth, v), valueForLength(style()->borderBottomRightRadius().width(), boxWidth, v))); 1508 LayoutUnit decorationsWidth = max<LayoutUnit>(-outlineStyle->outlineOffset(), borderWidth + minInsetRightShadowExtent) + max<LayoutUnit>(outlineWidth, shadowRight); 1509 LayoutRect rightRect(newOutlineBox.x() + min(newOutlineBox.width(), oldOutlineBox.width()) - decorationsWidth, 1510 newOutlineBox.y(), 1511 width + decorationsWidth, 1512 max(newOutlineBox.height(), oldOutlineBox.height())); 1513 LayoutUnit right = min<LayoutUnit>(newBounds.maxX(), oldBounds.maxX()); 1514 if (rightRect.x() < right) { 1515 rightRect.setWidth(min(rightRect.width(), right - rightRect.x())); 1516 repaintUsingContainer(repaintContainer, pixelSnappedIntRect(rightRect)); 1517 } 1518 } 1519 LayoutUnit height = absoluteValue(newOutlineBox.height() - oldOutlineBox.height()); 1520 if (height) { 1521 LayoutUnit shadowTop; 1522 LayoutUnit shadowBottom; 1523 style()->getBoxShadowVerticalExtent(shadowTop, shadowBottom); 1524 int borderBottom = isBox() ? toRenderBox(this)->borderBottom() : 0; 1525 LayoutUnit boxHeight = isBox() ? toRenderBox(this)->height() : LayoutUnit(); 1526 LayoutUnit minInsetBottomShadowExtent = min<LayoutUnit>(-insetShadowExtent.bottom(), min<LayoutUnit>(newBounds.height(), oldBounds.height())); 1527 LayoutUnit borderHeight = max<LayoutUnit>(borderBottom, max<LayoutUnit>(valueForLength(style()->borderBottomLeftRadius().height(), boxHeight, v), valueForLength(style()->borderBottomRightRadius().height(), boxHeight, v))); 1528 LayoutUnit decorationsHeight = max<LayoutUnit>(-outlineStyle->outlineOffset(), borderHeight + minInsetBottomShadowExtent) + max<LayoutUnit>(outlineWidth, shadowBottom); 1529 LayoutRect bottomRect(newOutlineBox.x(), 1530 min(newOutlineBox.maxY(), oldOutlineBox.maxY()) - decorationsHeight, 1531 max(newOutlineBox.width(), oldOutlineBox.width()), 1532 height + decorationsHeight); 1533 LayoutUnit bottom = min(newBounds.maxY(), oldBounds.maxY()); 1534 if (bottomRect.y() < bottom) { 1535 bottomRect.setHeight(min(bottomRect.height(), bottom - bottomRect.y())); 1536 repaintUsingContainer(repaintContainer, pixelSnappedIntRect(bottomRect)); 1537 } 1538 } 1539 return false; 1540 } 1541 1542 bool RenderObject::checkForRepaintDuringLayout() const 1543 { 1544 return !document()->view()->needsFullRepaint() && !hasLayer() && everHadLayout(); 1545 } 1546 1547 LayoutRect RenderObject::rectWithOutlineForRepaint(const RenderLayerModelObject* repaintContainer, LayoutUnit outlineWidth) const 1548 { 1549 LayoutRect r(clippedOverflowRectForRepaint(repaintContainer)); 1550 r.inflate(outlineWidth); 1551 return r; 1552 } 1553 1554 LayoutRect RenderObject::clippedOverflowRectForRepaint(const RenderLayerModelObject*) const 1555 { 1556 ASSERT_NOT_REACHED(); 1557 return LayoutRect(); 1558 } 1559 1560 void RenderObject::computeRectForRepaint(const RenderLayerModelObject* repaintContainer, LayoutRect& rect, bool fixed) const 1561 { 1562 if (repaintContainer == this) 1563 return; 1564 1565 if (RenderObject* o = parent()) { 1566 if (o->isBlockFlow()) { 1567 RenderBlock* cb = toRenderBlock(o); 1568 if (cb->hasColumns()) 1569 cb->adjustRectForColumns(rect); 1570 } 1571 1572 if (o->hasOverflowClip()) { 1573 RenderBox* boxParent = toRenderBox(o); 1574 boxParent->applyCachedClipAndScrollOffsetForRepaint(rect); 1575 if (rect.isEmpty()) 1576 return; 1577 } 1578 1579 o->computeRectForRepaint(repaintContainer, rect, fixed); 1580 } 1581 } 1582 1583 void RenderObject::computeFloatRectForRepaint(const RenderLayerModelObject*, FloatRect&, bool) const 1584 { 1585 ASSERT_NOT_REACHED(); 1586 } 1587 1588 void RenderObject::dirtyLinesFromChangedChild(RenderObject*) 1589 { 1590 } 1591 1592 #ifndef NDEBUG 1593 1594 void RenderObject::showTreeForThis() const 1595 { 1596 if (node()) 1597 node()->showTreeForThis(); 1598 } 1599 1600 void RenderObject::showRenderTreeForThis() const 1601 { 1602 showRenderTree(this, 0); 1603 } 1604 1605 void RenderObject::showLineTreeForThis() const 1606 { 1607 if (containingBlock()) 1608 containingBlock()->showLineTreeAndMark(0, 0, 0, 0, this); 1609 } 1610 1611 void RenderObject::showRenderObject() const 1612 { 1613 showRenderObject(0); 1614 } 1615 1616 void RenderObject::showRenderObject(int printedCharacters) const 1617 { 1618 // As this function is intended to be used when debugging, the 1619 // this pointer may be 0. 1620 if (!this) { 1621 fputs("(null)\n", stderr); 1622 return; 1623 } 1624 1625 printedCharacters += fprintf(stderr, "%s %p", renderName(), this); 1626 1627 if (node()) { 1628 if (printedCharacters) 1629 for (; printedCharacters < showTreeCharacterOffset; printedCharacters++) 1630 fputc(' ', stderr); 1631 fputc('\t', stderr); 1632 node()->showNode(); 1633 } else 1634 fputc('\n', stderr); 1635 } 1636 1637 void RenderObject::showRenderTreeAndMark(const RenderObject* markedObject1, const char* markedLabel1, const RenderObject* markedObject2, const char* markedLabel2, int depth) const 1638 { 1639 int printedCharacters = 0; 1640 if (markedObject1 == this && markedLabel1) 1641 printedCharacters += fprintf(stderr, "%s", markedLabel1); 1642 if (markedObject2 == this && markedLabel2) 1643 printedCharacters += fprintf(stderr, "%s", markedLabel2); 1644 for (; printedCharacters < depth * 2; printedCharacters++) 1645 fputc(' ', stderr); 1646 1647 showRenderObject(printedCharacters); 1648 if (!this) 1649 return; 1650 1651 for (const RenderObject* child = firstChild(); child; child = child->nextSibling()) 1652 child->showRenderTreeAndMark(markedObject1, markedLabel1, markedObject2, markedLabel2, depth + 1); 1653 } 1654 1655 #endif // NDEBUG 1656 1657 static bool shouldUseSelectionColor(const RenderStyle& style) 1658 { 1659 return style.userSelect() != SELECT_NONE || style.userModify() != READ_ONLY; 1660 } 1661 1662 Color RenderObject::selectionBackgroundColor() const 1663 { 1664 Color backgroundColor= Color::transparent; 1665 if (shouldUseSelectionColor(*style())) { 1666 RefPtr<RenderStyle> pseudoStyle = getUncachedPseudoStyle(PseudoStyleRequest(SELECTION)); 1667 if (pseudoStyle) { 1668 StyleColor styleColor = resolveCurrentColor(pseudoStyle.get(), CSSPropertyBackgroundColor); 1669 if (styleColor.isValid()) 1670 return styleColor.color().blendWithWhite(); 1671 } 1672 1673 backgroundColor = frame()->selection()->isFocusedAndActive() ? 1674 theme()->activeSelectionBackgroundColor() : 1675 theme()->inactiveSelectionBackgroundColor(); 1676 } 1677 1678 return backgroundColor; 1679 } 1680 1681 Color RenderObject::selectionColor(int colorProperty) const 1682 { 1683 // If the element is unselectable, or we are only painting the selection, 1684 // don't override the foreground color with the selection foreground color. 1685 if (!shouldUseSelectionColor(*style()) 1686 || (frame()->view()->paintBehavior() & PaintBehaviorSelectionOnly)) 1687 return Color::transparent; 1688 1689 Color color; 1690 if (RefPtr<RenderStyle> pseudoStyle = getUncachedPseudoStyle(PseudoStyleRequest(SELECTION))) { 1691 StyleColor styleColor = resolveCurrentColor(pseudoStyle.get(), colorProperty); 1692 color = styleColor.isValid() ? styleColor.color() : resolveColor(pseudoStyle.get(), CSSPropertyColor); 1693 } else 1694 color = frame()->selection()->isFocusedAndActive() ? 1695 theme()->activeSelectionForegroundColor() : 1696 theme()->inactiveSelectionForegroundColor(); 1697 1698 return color; 1699 } 1700 1701 Color RenderObject::selectionForegroundColor() const 1702 { 1703 return selectionColor(CSSPropertyWebkitTextFillColor); 1704 } 1705 1706 Color RenderObject::selectionEmphasisMarkColor() const 1707 { 1708 return selectionColor(CSSPropertyWebkitTextEmphasisColor); 1709 } 1710 1711 void RenderObject::selectionStartEnd(int& spos, int& epos) const 1712 { 1713 view()->selectionStartEnd(spos, epos); 1714 } 1715 1716 void RenderObject::handleDynamicFloatPositionChange() 1717 { 1718 // We have gone from not affecting the inline status of the parent flow to suddenly 1719 // having an impact. See if there is a mismatch between the parent flow's 1720 // childrenInline() state and our state. 1721 setInline(style()->isDisplayInlineType()); 1722 if (isInline() != parent()->childrenInline()) { 1723 if (!isInline()) 1724 toRenderBoxModelObject(parent())->childBecameNonInline(this); 1725 else { 1726 // An anonymous block must be made to wrap this inline. 1727 RenderBlock* block = toRenderBlock(parent())->createAnonymousBlock(); 1728 RenderObjectChildList* childlist = parent()->virtualChildren(); 1729 childlist->insertChildNode(parent(), block, this); 1730 block->children()->appendChildNode(block, childlist->removeChildNode(parent(), this)); 1731 } 1732 } 1733 } 1734 1735 void RenderObject::setAnimatableStyle(PassRefPtr<RenderStyle> style) 1736 { 1737 if (!isText() && style) { 1738 if (!RuntimeEnabledFeatures::webAnimationsCSSEnabled()) { 1739 setStyle(animation()->updateAnimations(this, style.get())); 1740 return; 1741 } 1742 if (node() && node()->isElementNode()) { 1743 Element* element = toElement(node()); 1744 if (CSSAnimations::needsUpdate(element, style.get())) 1745 element->ensureActiveAnimations()->cssAnimations()->update(element, style.get()); 1746 } 1747 } 1748 setStyle(style); 1749 } 1750 1751 StyleDifference RenderObject::adjustStyleDifference(StyleDifference diff, unsigned contextSensitiveProperties) const 1752 { 1753 // If transform changed, and we are not composited, need to do a layout. 1754 if (contextSensitiveProperties & ContextSensitivePropertyTransform) { 1755 // Text nodes share style with their parents but transforms don't apply to them, 1756 // hence the !isText() check. 1757 // FIXME: when transforms are taken into account for overflow, we will need to do a layout. 1758 if (!isText() && (!hasLayer() || !toRenderLayerModelObject(this)->layer()->isComposited())) { 1759 // We need to set at least SimplifiedLayout, but if PositionedMovementOnly is already set 1760 // then we actually need SimplifiedLayoutAndPositionedMovement. 1761 if (!hasLayer()) 1762 diff = StyleDifferenceLayout; // FIXME: Do this for now since SimplifiedLayout cannot handle updating floating objects lists. 1763 else if (diff < StyleDifferenceLayoutPositionedMovementOnly) 1764 diff = StyleDifferenceSimplifiedLayout; 1765 else if (diff < StyleDifferenceSimplifiedLayout) 1766 diff = StyleDifferenceSimplifiedLayoutAndPositionedMovement; 1767 } else if (diff < StyleDifferenceRecompositeLayer) 1768 diff = StyleDifferenceRecompositeLayer; 1769 } 1770 1771 // If opacity changed, and we are not composited, need to repaint (also 1772 // ignoring text nodes) 1773 if (contextSensitiveProperties & ContextSensitivePropertyOpacity) { 1774 if (!isText() && (!hasLayer() || !toRenderLayerModelObject(this)->layer()->isComposited())) 1775 diff = StyleDifferenceRepaintLayer; 1776 else if (diff < StyleDifferenceRecompositeLayer) 1777 diff = StyleDifferenceRecompositeLayer; 1778 } 1779 1780 if ((contextSensitiveProperties & ContextSensitivePropertyFilter) && hasLayer()) { 1781 RenderLayer* layer = toRenderLayerModelObject(this)->layer(); 1782 if (!layer->isComposited() || layer->paintsWithFilters()) 1783 diff = StyleDifferenceRepaintLayer; 1784 else if (diff < StyleDifferenceRecompositeLayer) 1785 diff = StyleDifferenceRecompositeLayer; 1786 } 1787 1788 // The answer to requiresLayer() for plugins, iframes, and canvas can change without the actual 1789 // style changing, since it depends on whether we decide to composite these elements. When the 1790 // layer status of one of these elements changes, we need to force a layout. 1791 if (diff == StyleDifferenceEqual && style() && isLayerModelObject()) { 1792 if (hasLayer() != toRenderLayerModelObject(this)->requiresLayer()) 1793 diff = StyleDifferenceLayout; 1794 } 1795 1796 // If we have no layer(), just treat a RepaintLayer hint as a normal Repaint. 1797 if (diff == StyleDifferenceRepaintLayer && !hasLayer()) 1798 diff = StyleDifferenceRepaint; 1799 1800 return diff; 1801 } 1802 1803 void RenderObject::setPseudoStyle(PassRefPtr<RenderStyle> pseudoStyle) 1804 { 1805 ASSERT(pseudoStyle->styleType() == BEFORE || pseudoStyle->styleType() == AFTER); 1806 1807 // FIXME: We should consider just making all pseudo items use an inherited style. 1808 1809 // Images are special and must inherit the pseudoStyle so the width and height of 1810 // the pseudo element doesn't change the size of the image. In all other cases we 1811 // can just share the style. 1812 // 1813 // Quotes are also RenderInline, so we need to create an inherited style to avoid 1814 // getting an inline with positioning or an invalid display. 1815 // 1816 if (isImage() || isQuote()) { 1817 RefPtr<RenderStyle> style = RenderStyle::create(); 1818 style->inheritFrom(pseudoStyle.get()); 1819 setStyle(style.release()); 1820 return; 1821 } 1822 1823 setStyle(pseudoStyle); 1824 } 1825 1826 inline bool RenderObject::hasImmediateNonWhitespaceTextChild() const 1827 { 1828 for (const RenderObject* r = firstChild(); r; r = r->nextSibling()) { 1829 if (r->isText() && !toRenderText(r)->isAllCollapsibleWhitespace()) 1830 return true; 1831 } 1832 return false; 1833 } 1834 1835 inline bool RenderObject::shouldRepaintForStyleDifference(StyleDifference diff) const 1836 { 1837 return diff == StyleDifferenceRepaint || (diff == StyleDifferenceRepaintIfText && hasImmediateNonWhitespaceTextChild()); 1838 } 1839 1840 void RenderObject::setStyle(PassRefPtr<RenderStyle> style) 1841 { 1842 if (m_style == style) { 1843 // We need to run through adjustStyleDifference() for iframes, plugins, and canvas so 1844 // style sharing is disabled for them. That should ensure that we never hit this code path. 1845 ASSERT(!isRenderIFrame() && !isEmbeddedObject() && !isCanvas()); 1846 return; 1847 } 1848 1849 StyleDifference diff = StyleDifferenceEqual; 1850 unsigned contextSensitiveProperties = ContextSensitivePropertyNone; 1851 if (m_style) 1852 diff = m_style->diff(style.get(), contextSensitiveProperties); 1853 1854 diff = adjustStyleDifference(diff, contextSensitiveProperties); 1855 1856 styleWillChange(diff, style.get()); 1857 1858 RefPtr<RenderStyle> oldStyle = m_style.release(); 1859 setStyleInternal(style); 1860 1861 updateFillImages(oldStyle ? oldStyle->backgroundLayers() : 0, m_style ? m_style->backgroundLayers() : 0); 1862 updateFillImages(oldStyle ? oldStyle->maskLayers() : 0, m_style ? m_style->maskLayers() : 0); 1863 1864 updateImage(oldStyle ? oldStyle->borderImage().image() : 0, m_style ? m_style->borderImage().image() : 0); 1865 updateImage(oldStyle ? oldStyle->maskBoxImage().image() : 0, m_style ? m_style->maskBoxImage().image() : 0); 1866 1867 // We need to ensure that view->maximalOutlineSize() is valid for any repaints that happen 1868 // during styleDidChange (it's used by clippedOverflowRectForRepaint()). 1869 if (m_style->outlineWidth() > 0 && m_style->outlineSize() > maximalOutlineSize(PaintPhaseOutline)) 1870 toRenderView(document()->renderer())->setMaximalOutlineSize(m_style->outlineSize()); 1871 1872 bool doesNotNeedLayout = !m_parent || isText(); 1873 1874 styleDidChange(diff, oldStyle.get()); 1875 1876 // FIXME: |this| might be destroyed here. This can currently happen for a RenderTextFragment when 1877 // its first-letter block gets an update in RenderTextFragment::styleDidChange. For RenderTextFragment(s), 1878 // we will safely bail out with the doesNotNeedLayout flag. We might want to broaden this condition 1879 // in the future as we move renderer changes out of layout and into style changes. 1880 if (doesNotNeedLayout) 1881 return; 1882 1883 // Now that the layer (if any) has been updated, we need to adjust the diff again, 1884 // check whether we should layout now, and decide if we need to repaint. 1885 StyleDifference updatedDiff = adjustStyleDifference(diff, contextSensitiveProperties); 1886 1887 if (diff <= StyleDifferenceLayoutPositionedMovementOnly) { 1888 if (updatedDiff == StyleDifferenceLayout) 1889 setNeedsLayoutAndPrefWidthsRecalc(); 1890 else if (updatedDiff == StyleDifferenceLayoutPositionedMovementOnly) 1891 setNeedsPositionedMovementLayout(); 1892 else if (updatedDiff == StyleDifferenceSimplifiedLayoutAndPositionedMovement) { 1893 setNeedsPositionedMovementLayout(); 1894 setNeedsSimplifiedNormalFlowLayout(); 1895 } else if (updatedDiff == StyleDifferenceSimplifiedLayout) 1896 setNeedsSimplifiedNormalFlowLayout(); 1897 } 1898 1899 if (updatedDiff == StyleDifferenceRepaintLayer || shouldRepaintForStyleDifference(updatedDiff)) { 1900 // Do a repaint with the new style now, e.g., for example if we go from 1901 // not having an outline to having an outline. 1902 repaint(); 1903 } 1904 } 1905 1906 static inline bool rendererHasBackground(const RenderObject* renderer) 1907 { 1908 return renderer && renderer->hasBackground(); 1909 } 1910 1911 void RenderObject::styleWillChange(StyleDifference diff, const RenderStyle* newStyle) 1912 { 1913 if (m_style) { 1914 // If our z-index changes value or our visibility changes, 1915 // we need to dirty our stacking context's z-order list. 1916 if (newStyle) { 1917 bool visibilityChanged = m_style->visibility() != newStyle->visibility() 1918 || m_style->zIndex() != newStyle->zIndex() 1919 || m_style->hasAutoZIndex() != newStyle->hasAutoZIndex(); 1920 if (visibilityChanged) { 1921 document()->setAnnotatedRegionsDirty(true); 1922 if (AXObjectCache* cache = document()->existingAXObjectCache()) 1923 cache->childrenChanged(parent()); 1924 } 1925 1926 // Keep layer hierarchy visibility bits up to date if visibility changes. 1927 if (m_style->visibility() != newStyle->visibility()) { 1928 if (RenderLayer* l = enclosingLayer()) { 1929 if (newStyle->visibility() == VISIBLE) 1930 l->setHasVisibleContent(); 1931 else if (l->hasVisibleContent() && (this == l->renderer() || l->renderer()->style()->visibility() != VISIBLE)) { 1932 l->dirtyVisibleContentStatus(); 1933 if (diff > StyleDifferenceRepaintLayer) 1934 repaint(); 1935 } 1936 } 1937 } 1938 } 1939 1940 if (m_parent && (newStyle->outlineSize() < m_style->outlineSize() || shouldRepaintForStyleDifference(diff))) 1941 repaint(); 1942 if (isFloating() && (m_style->floating() != newStyle->floating())) 1943 // For changes in float styles, we need to conceivably remove ourselves 1944 // from the floating objects list. 1945 toRenderBox(this)->removeFloatingOrPositionedChildFromBlockLists(); 1946 else if (isOutOfFlowPositioned() && (m_style->position() != newStyle->position())) 1947 // For changes in positioning styles, we need to conceivably remove ourselves 1948 // from the positioned objects list. 1949 toRenderBox(this)->removeFloatingOrPositionedChildFromBlockLists(); 1950 1951 s_affectsParentBlock = isFloatingOrOutOfFlowPositioned() 1952 && (!newStyle->isFloating() && !newStyle->hasOutOfFlowPosition()) 1953 && parent() && (parent()->isBlockFlow() || parent()->isRenderInline()); 1954 1955 // reset style flags 1956 if (diff == StyleDifferenceLayout || diff == StyleDifferenceLayoutPositionedMovementOnly) { 1957 setFloating(false); 1958 clearPositionedState(); 1959 } 1960 setHorizontalWritingMode(true); 1961 setHasBoxDecorations(false); 1962 setHasOverflowClip(false); 1963 setHasTransform(false); 1964 setHasReflection(false); 1965 } else 1966 s_affectsParentBlock = false; 1967 1968 if (view()->frameView()) { 1969 bool shouldBlitOnFixedBackgroundImage = false; 1970 #if ENABLE(FAST_MOBILE_SCROLLING) 1971 // On low-powered/mobile devices, preventing blitting on a scroll can cause noticeable delays 1972 // when scrolling a page with a fixed background image. As an optimization, assuming there are 1973 // no fixed positoned elements on the page, we can acclerate scrolling (via blitting) if we 1974 // ignore the CSS property "background-attachment: fixed". 1975 shouldBlitOnFixedBackgroundImage = true; 1976 #endif 1977 1978 bool newStyleSlowScroll = newStyle && !shouldBlitOnFixedBackgroundImage && newStyle->hasFixedBackgroundImage(); 1979 bool oldStyleSlowScroll = m_style && !shouldBlitOnFixedBackgroundImage && m_style->hasFixedBackgroundImage(); 1980 1981 bool drawsRootBackground = isRoot() || (isBody() && !rendererHasBackground(document()->documentElement()->renderer())); 1982 if (drawsRootBackground && !shouldBlitOnFixedBackgroundImage) { 1983 if (view()->compositor()->supportsFixedRootBackgroundCompositing()) { 1984 if (newStyleSlowScroll && newStyle->hasEntirelyFixedBackground()) 1985 newStyleSlowScroll = false; 1986 1987 if (oldStyleSlowScroll && m_style->hasEntirelyFixedBackground()) 1988 oldStyleSlowScroll = false; 1989 } 1990 } 1991 1992 if (oldStyleSlowScroll != newStyleSlowScroll) { 1993 if (oldStyleSlowScroll) 1994 view()->frameView()->removeSlowRepaintObject(); 1995 if (newStyleSlowScroll) 1996 view()->frameView()->addSlowRepaintObject(); 1997 } 1998 } 1999 } 2000 2001 static bool areNonIdenticalCursorListsEqual(const RenderStyle* a, const RenderStyle* b) 2002 { 2003 ASSERT(a->cursors() != b->cursors()); 2004 return a->cursors() && b->cursors() && *a->cursors() == *b->cursors(); 2005 } 2006 2007 static inline bool areCursorsEqual(const RenderStyle* a, const RenderStyle* b) 2008 { 2009 return a->cursor() == b->cursor() && (a->cursors() == b->cursors() || areNonIdenticalCursorListsEqual(a, b)); 2010 } 2011 2012 void RenderObject::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle) 2013 { 2014 if (s_affectsParentBlock) 2015 handleDynamicFloatPositionChange(); 2016 2017 if (!m_parent) 2018 return; 2019 2020 if (diff == StyleDifferenceLayout || diff == StyleDifferenceSimplifiedLayout) { 2021 RenderCounter::rendererStyleChanged(this, oldStyle, m_style.get()); 2022 2023 // If the object already needs layout, then setNeedsLayout won't do 2024 // any work. But if the containing block has changed, then we may need 2025 // to mark the new containing blocks for layout. The change that can 2026 // directly affect the containing block of this object is a change to 2027 // the position style. 2028 if (needsLayout() && oldStyle->position() != m_style->position()) 2029 markContainingBlocksForLayout(); 2030 2031 if (diff == StyleDifferenceLayout) 2032 setNeedsLayoutAndPrefWidthsRecalc(); 2033 else 2034 setNeedsSimplifiedNormalFlowLayout(); 2035 } else if (diff == StyleDifferenceSimplifiedLayoutAndPositionedMovement) { 2036 setNeedsPositionedMovementLayout(); 2037 setNeedsSimplifiedNormalFlowLayout(); 2038 } else if (diff == StyleDifferenceLayoutPositionedMovementOnly) 2039 setNeedsPositionedMovementLayout(); 2040 2041 // Don't check for repaint here; we need to wait until the layer has been 2042 // updated by subclasses before we know if we have to repaint (in setStyle()). 2043 2044 if (oldStyle && !areCursorsEqual(oldStyle, style())) { 2045 if (Frame* frame = this->frame()) 2046 frame->eventHandler()->dispatchFakeMouseMoveEventSoon(); 2047 } 2048 } 2049 2050 void RenderObject::propagateStyleToAnonymousChildren(bool blockChildrenOnly) 2051 { 2052 // FIXME: We could save this call when the change only affected non-inherited properties. 2053 for (RenderObject* child = firstChild(); child; child = child->nextSibling()) { 2054 if (!child->isAnonymous() || child->style()->styleType() != NOPSEUDO) 2055 continue; 2056 2057 if (blockChildrenOnly && !child->isRenderBlock()) 2058 continue; 2059 2060 if (child->isRenderFullScreen() || child->isRenderFullScreenPlaceholder()) 2061 continue; 2062 2063 RefPtr<RenderStyle> newStyle = RenderStyle::createAnonymousStyleWithDisplay(style(), child->style()->display()); 2064 if (style()->specifiesColumns()) { 2065 if (child->style()->specifiesColumns()) 2066 newStyle->inheritColumnPropertiesFrom(style()); 2067 if (child->style()->columnSpan()) 2068 newStyle->setColumnSpan(ColumnSpanAll); 2069 } 2070 2071 // Preserve the position style of anonymous block continuations as they can have relative or sticky position when 2072 // they contain block descendants of relative or sticky positioned inlines. 2073 if (child->isInFlowPositioned() && toRenderBlock(child)->isAnonymousBlockContinuation()) 2074 newStyle->setPosition(child->style()->position()); 2075 2076 child->setStyle(newStyle.release()); 2077 } 2078 } 2079 2080 void RenderObject::updateFillImages(const FillLayer* oldLayers, const FillLayer* newLayers) 2081 { 2082 // Optimize the common case 2083 if (oldLayers && !oldLayers->next() && newLayers && !newLayers->next() && (oldLayers->image() == newLayers->image())) 2084 return; 2085 2086 // Go through the new layers and addClients first, to avoid removing all clients of an image. 2087 for (const FillLayer* currNew = newLayers; currNew; currNew = currNew->next()) { 2088 if (currNew->image()) 2089 currNew->image()->addClient(this); 2090 } 2091 2092 for (const FillLayer* currOld = oldLayers; currOld; currOld = currOld->next()) { 2093 if (currOld->image()) 2094 currOld->image()->removeClient(this); 2095 } 2096 } 2097 2098 void RenderObject::updateImage(StyleImage* oldImage, StyleImage* newImage) 2099 { 2100 if (oldImage != newImage) { 2101 if (oldImage) 2102 oldImage->removeClient(this); 2103 if (newImage) 2104 newImage->addClient(this); 2105 } 2106 } 2107 2108 LayoutRect RenderObject::viewRect() const 2109 { 2110 return view()->viewRect(); 2111 } 2112 2113 FloatPoint RenderObject::localToAbsolute(const FloatPoint& localPoint, MapCoordinatesFlags mode) const 2114 { 2115 TransformState transformState(TransformState::ApplyTransformDirection, localPoint); 2116 mapLocalToContainer(0, transformState, mode | ApplyContainerFlip); 2117 transformState.flatten(); 2118 2119 return transformState.lastPlanarPoint(); 2120 } 2121 2122 FloatPoint RenderObject::absoluteToLocal(const FloatPoint& containerPoint, MapCoordinatesFlags mode) const 2123 { 2124 TransformState transformState(TransformState::UnapplyInverseTransformDirection, containerPoint); 2125 mapAbsoluteToLocalPoint(mode, transformState); 2126 transformState.flatten(); 2127 2128 return transformState.lastPlanarPoint(); 2129 } 2130 2131 FloatQuad RenderObject::absoluteToLocalQuad(const FloatQuad& quad, MapCoordinatesFlags mode) const 2132 { 2133 TransformState transformState(TransformState::UnapplyInverseTransformDirection, quad.boundingBox().center(), quad); 2134 mapAbsoluteToLocalPoint(mode, transformState); 2135 transformState.flatten(); 2136 return transformState.lastPlanarQuad(); 2137 } 2138 2139 void RenderObject::mapLocalToContainer(const RenderLayerModelObject* repaintContainer, TransformState& transformState, MapCoordinatesFlags mode, bool* wasFixed) const 2140 { 2141 if (repaintContainer == this) 2142 return; 2143 2144 RenderObject* o = parent(); 2145 if (!o) 2146 return; 2147 2148 // FIXME: this should call offsetFromContainer to share code, but I'm not sure it's ever called. 2149 LayoutPoint centerPoint = roundedLayoutPoint(transformState.mappedPoint()); 2150 if (mode & ApplyContainerFlip && o->isBox()) { 2151 if (o->style()->isFlippedBlocksWritingMode()) 2152 transformState.move(toRenderBox(o)->flipForWritingModeIncludingColumns(roundedLayoutPoint(transformState.mappedPoint())) - centerPoint); 2153 mode &= ~ApplyContainerFlip; 2154 } 2155 2156 LayoutSize columnOffset; 2157 o->adjustForColumns(columnOffset, roundedLayoutPoint(transformState.mappedPoint())); 2158 if (!columnOffset.isZero()) 2159 transformState.move(columnOffset); 2160 2161 if (o->hasOverflowClip()) 2162 transformState.move(-toRenderBox(o)->scrolledContentOffset()); 2163 2164 o->mapLocalToContainer(repaintContainer, transformState, mode, wasFixed); 2165 } 2166 2167 const RenderObject* RenderObject::pushMappingToContainer(const RenderLayerModelObject* ancestorToStopAt, RenderGeometryMap& geometryMap) const 2168 { 2169 ASSERT_UNUSED(ancestorToStopAt, ancestorToStopAt != this); 2170 2171 RenderObject* container = parent(); 2172 if (!container) 2173 return 0; 2174 2175 // FIXME: this should call offsetFromContainer to share code, but I'm not sure it's ever called. 2176 LayoutSize offset; 2177 if (container->hasOverflowClip()) 2178 offset = -toRenderBox(container)->scrolledContentOffset(); 2179 2180 geometryMap.push(this, offset, hasColumns()); 2181 2182 return container; 2183 } 2184 2185 void RenderObject::mapAbsoluteToLocalPoint(MapCoordinatesFlags mode, TransformState& transformState) const 2186 { 2187 RenderObject* o = parent(); 2188 if (o) { 2189 o->mapAbsoluteToLocalPoint(mode, transformState); 2190 if (o->hasOverflowClip()) 2191 transformState.move(toRenderBox(o)->scrolledContentOffset()); 2192 } 2193 } 2194 2195 bool RenderObject::shouldUseTransformFromContainer(const RenderObject* containerObject) const 2196 { 2197 // hasTransform() indicates whether the object has transform, transform-style or perspective. We just care about transform, 2198 // so check the layer's transform directly. 2199 return (hasLayer() && toRenderLayerModelObject(this)->layer()->transform()) || (containerObject && containerObject->style()->hasPerspective()); 2200 } 2201 2202 void RenderObject::getTransformFromContainer(const RenderObject* containerObject, const LayoutSize& offsetInContainer, TransformationMatrix& transform) const 2203 { 2204 transform.makeIdentity(); 2205 transform.translate(offsetInContainer.width(), offsetInContainer.height()); 2206 RenderLayer* layer; 2207 if (hasLayer() && (layer = toRenderLayerModelObject(this)->layer()) && layer->transform()) 2208 transform.multiply(layer->currentTransform()); 2209 2210 if (containerObject && containerObject->hasLayer() && containerObject->style()->hasPerspective()) { 2211 // Perpsective on the container affects us, so we have to factor it in here. 2212 ASSERT(containerObject->hasLayer()); 2213 FloatPoint perspectiveOrigin = toRenderLayerModelObject(containerObject)->layer()->perspectiveOrigin(); 2214 2215 TransformationMatrix perspectiveMatrix; 2216 perspectiveMatrix.applyPerspective(containerObject->style()->perspective()); 2217 2218 transform.translateRight3d(-perspectiveOrigin.x(), -perspectiveOrigin.y(), 0); 2219 transform = perspectiveMatrix * transform; 2220 transform.translateRight3d(perspectiveOrigin.x(), perspectiveOrigin.y(), 0); 2221 } 2222 } 2223 2224 FloatQuad RenderObject::localToContainerQuad(const FloatQuad& localQuad, const RenderLayerModelObject* repaintContainer, MapCoordinatesFlags mode, bool* wasFixed) const 2225 { 2226 // Track the point at the center of the quad's bounding box. As mapLocalToContainer() calls offsetFromContainer(), 2227 // it will use that point as the reference point to decide which column's transform to apply in multiple-column blocks. 2228 TransformState transformState(TransformState::ApplyTransformDirection, localQuad.boundingBox().center(), localQuad); 2229 mapLocalToContainer(repaintContainer, transformState, mode | ApplyContainerFlip | UseTransforms, wasFixed); 2230 transformState.flatten(); 2231 2232 return transformState.lastPlanarQuad(); 2233 } 2234 2235 FloatPoint RenderObject::localToContainerPoint(const FloatPoint& localPoint, const RenderLayerModelObject* repaintContainer, MapCoordinatesFlags mode, bool* wasFixed) const 2236 { 2237 TransformState transformState(TransformState::ApplyTransformDirection, localPoint); 2238 mapLocalToContainer(repaintContainer, transformState, mode | ApplyContainerFlip | UseTransforms, wasFixed); 2239 transformState.flatten(); 2240 2241 return transformState.lastPlanarPoint(); 2242 } 2243 2244 LayoutSize RenderObject::offsetFromContainer(RenderObject* o, const LayoutPoint& point, bool* offsetDependsOnPoint) const 2245 { 2246 ASSERT(o == container()); 2247 2248 LayoutSize offset; 2249 2250 o->adjustForColumns(offset, point); 2251 2252 if (o->hasOverflowClip()) 2253 offset -= toRenderBox(o)->scrolledContentOffset(); 2254 2255 if (offsetDependsOnPoint) 2256 *offsetDependsOnPoint = hasColumns() || o->isRenderFlowThread(); 2257 2258 return offset; 2259 } 2260 2261 LayoutSize RenderObject::offsetFromAncestorContainer(RenderObject* container) const 2262 { 2263 LayoutSize offset; 2264 LayoutPoint referencePoint; 2265 const RenderObject* currContainer = this; 2266 do { 2267 RenderObject* nextContainer = currContainer->container(); 2268 ASSERT(nextContainer); // This means we reached the top without finding container. 2269 if (!nextContainer) 2270 break; 2271 ASSERT(!currContainer->hasTransform()); 2272 LayoutSize currentOffset = currContainer->offsetFromContainer(nextContainer, referencePoint); 2273 offset += currentOffset; 2274 referencePoint.move(currentOffset); 2275 currContainer = nextContainer; 2276 } while (currContainer != container); 2277 2278 return offset; 2279 } 2280 2281 LayoutRect RenderObject::localCaretRect(InlineBox*, int, LayoutUnit* extraWidthToEndOfLine) 2282 { 2283 if (extraWidthToEndOfLine) 2284 *extraWidthToEndOfLine = 0; 2285 2286 return LayoutRect(); 2287 } 2288 2289 void RenderObject::computeLayerHitTestRects(LayerHitTestRects& layerRects) const 2290 { 2291 // Figure out what layer our container is in. Any offset (or new layer) for this 2292 // renderer within it's container will be applied in addLayerHitTestRects. 2293 LayoutPoint layerOffset; 2294 const RenderLayer* currentLayer = 0; 2295 2296 if (!hasLayer()) { 2297 RenderObject* container = this->container(); 2298 if (container) { 2299 currentLayer = container->enclosingLayer(); 2300 if (currentLayer && currentLayer->renderer() != container) { 2301 layerOffset.move(container->offsetFromAncestorContainer(currentLayer->renderer())); 2302 // If the layer itself is scrolled, we have to undo the subtraction of its scroll 2303 // offset since we want the offset relative to the scrolling content, not the 2304 // element itself. 2305 layerOffset.move(currentLayer->scrolledContentOffset()); 2306 } 2307 } else { 2308 currentLayer = enclosingLayer(); 2309 } 2310 if (!currentLayer) 2311 return; 2312 } 2313 2314 this->addLayerHitTestRects(layerRects, currentLayer, layerOffset, LayoutRect()); 2315 } 2316 2317 void RenderObject::addLayerHitTestRects(LayerHitTestRects& layerRects, const RenderLayer* currentLayer, const LayoutPoint& layerOffset, const LayoutRect& containerRect) const 2318 { 2319 ASSERT(currentLayer); 2320 ASSERT(currentLayer == this->enclosingLayer()); 2321 2322 // Compute the rects for this renderer only and add them to the results. 2323 // Note that we could avoid passing the offset and instead adjust each result, but this 2324 // seems slightly simpler. 2325 Vector<LayoutRect> ownRects; 2326 LayoutRect newContainerRect; 2327 computeSelfHitTestRects(ownRects, layerOffset); 2328 2329 LayerHitTestRects::iterator iter = layerRects.find(currentLayer); 2330 if (iter == layerRects.end()) 2331 iter = layerRects.add(currentLayer, Vector<LayoutRect>()).iterator; 2332 for (size_t i = 0; i < ownRects.size(); i++) { 2333 if (!containerRect.contains(ownRects[i])) { 2334 iter->value.append(ownRects[i]); 2335 if (newContainerRect.isEmpty()) 2336 newContainerRect = ownRects[i]; 2337 } 2338 } 2339 if (newContainerRect.isEmpty()) 2340 newContainerRect = containerRect; 2341 2342 // If it's possible for children to have rects outside our bounds, then we need to descend into 2343 // the children and compute them. 2344 // Ideally there would be other cases where we could detect that children couldn't have rects 2345 // outside our bounds and prune the tree walk. 2346 // Note that we don't use Region here because Union is O(N) - better to just keep a list of 2347 // partially redundant rectangles. If we find examples where this is expensive, then we could 2348 // rewrite Region to be more efficient. See https://bugs.webkit.org/show_bug.cgi?id=100814. 2349 if (!isRenderView()) { 2350 for (RenderObject* curr = firstChild(); curr; curr = curr->nextSibling()) { 2351 curr->addLayerHitTestRects(layerRects, currentLayer, layerOffset, newContainerRect); 2352 } 2353 } 2354 } 2355 2356 bool RenderObject::isRooted(RenderView** view) const 2357 { 2358 const RenderObject* o = this; 2359 while (o->parent()) 2360 o = o->parent(); 2361 2362 if (!o->isRenderView()) 2363 return false; 2364 2365 if (view) 2366 *view = const_cast<RenderView*>(toRenderView(o)); 2367 2368 return true; 2369 } 2370 2371 RenderObject* RenderObject::rendererForRootBackground() 2372 { 2373 ASSERT(isRoot()); 2374 if (!hasBackground() && node() && isHTMLHtmlElement(node())) { 2375 // Locate the <body> element using the DOM. This is easier than trying 2376 // to crawl around a render tree with potential :before/:after content and 2377 // anonymous blocks created by inline <body> tags etc. We can locate the <body> 2378 // render object very easily via the DOM. 2379 HTMLElement* body = document()->body(); 2380 RenderObject* bodyObject = (body && body->hasLocalName(bodyTag)) ? body->renderer() : 0; 2381 if (bodyObject) 2382 return bodyObject; 2383 } 2384 2385 return this; 2386 } 2387 2388 RespectImageOrientationEnum RenderObject::shouldRespectImageOrientation() const 2389 { 2390 // Respect the image's orientation if it's being used as a full-page image or it's 2391 // an <img> and the setting to respect it everywhere is set. 2392 return document()->isImageDocument() || 2393 (document()->settings() && document()->settings()->shouldRespectImageOrientation() && node() && node()->hasTagName(HTMLNames::imgTag)) ? RespectImageOrientation : DoNotRespectImageOrientation; 2394 } 2395 2396 bool RenderObject::hasOutlineAnnotation() const 2397 { 2398 return node() && node()->isLink() && document()->printing(); 2399 } 2400 2401 bool RenderObject::hasEntirelyFixedBackground() const 2402 { 2403 return m_style->hasEntirelyFixedBackground(); 2404 } 2405 2406 RenderObject* RenderObject::container(const RenderLayerModelObject* repaintContainer, bool* repaintContainerSkipped) const 2407 { 2408 if (repaintContainerSkipped) 2409 *repaintContainerSkipped = false; 2410 2411 // This method is extremely similar to containingBlock(), but with a few notable 2412 // exceptions. 2413 // (1) It can be used on orphaned subtrees, i.e., it can be called safely even when 2414 // the object is not part of the primary document subtree yet. 2415 // (2) For normal flow elements, it just returns the parent. 2416 // (3) For absolute positioned elements, it will return a relative positioned inline. 2417 // containingBlock() simply skips relpositioned inlines and lets an enclosing block handle 2418 // the layout of the positioned object. This does mean that computePositionedLogicalWidth and 2419 // computePositionedLogicalHeight have to use container(). 2420 RenderObject* o = parent(); 2421 2422 if (isText()) 2423 return o; 2424 2425 EPosition pos = m_style->position(); 2426 if (pos == FixedPosition) { 2427 // container() can be called on an object that is not in the 2428 // tree yet. We don't call view() since it will assert if it 2429 // can't get back to the canvas. Instead we just walk as high up 2430 // as we can. If we're in the tree, we'll get the root. If we 2431 // aren't we'll get the root of our little subtree (most likely 2432 // we'll just return 0). 2433 // FIXME: The definition of view() has changed to not crawl up the render tree. It might 2434 // be safe now to use it. 2435 while (o && o->parent() && !(o->hasTransform() && o->isRenderBlock())) { 2436 // foreignObject is the containing block for its contents. 2437 if (o->isSVGForeignObject()) 2438 break; 2439 2440 // The render flow thread is the top most containing block 2441 // for the fixed positioned elements. 2442 if (o->isOutOfFlowRenderFlowThread()) 2443 break; 2444 2445 if (repaintContainerSkipped && o == repaintContainer) 2446 *repaintContainerSkipped = true; 2447 2448 o = o->parent(); 2449 } 2450 } else if (pos == AbsolutePosition) { 2451 // Same goes here. We technically just want our containing block, but 2452 // we may not have one if we're part of an uninstalled subtree. We'll 2453 // climb as high as we can though. 2454 while (o && o->style()->position() == StaticPosition && !o->isRenderView() && !(o->hasTransform() && o->isRenderBlock())) { 2455 if (o->isSVGForeignObject()) // foreignObject is the containing block for contents inside it 2456 break; 2457 2458 if (repaintContainerSkipped && o == repaintContainer) 2459 *repaintContainerSkipped = true; 2460 2461 o = o->parent(); 2462 } 2463 } 2464 2465 return o; 2466 } 2467 2468 bool RenderObject::isSelectionBorder() const 2469 { 2470 SelectionState st = selectionState(); 2471 return st == SelectionStart || st == SelectionEnd || st == SelectionBoth; 2472 } 2473 2474 inline void RenderObject::clearLayoutRootIfNeeded() const 2475 { 2476 if (frame()) { 2477 if (FrameView* view = frame()->view()) { 2478 if (view->layoutRoot() == this) { 2479 if (!documentBeingDestroyed()) 2480 ASSERT_NOT_REACHED(); 2481 // This indicates a failure to layout the child, which is why 2482 // the layout root is still set to |this|. Make sure to clear it 2483 // since we are getting destroyed. 2484 view->clearLayoutRoot(); 2485 } 2486 } 2487 } 2488 } 2489 2490 void RenderObject::willBeDestroyed() 2491 { 2492 // Destroy any leftover anonymous children. 2493 RenderObjectChildList* children = virtualChildren(); 2494 if (children) 2495 children->destroyLeftoverChildren(); 2496 2497 // If this renderer is being autoscrolled, stop the autoscroll timer 2498 2499 // FIXME: RenderObject::destroy should not get called with a renderer whose document 2500 // has a null frame, so we assert this. However, we don't want release builds to crash which is why we 2501 // check that the frame is not null. 2502 ASSERT(frame()); 2503 if (frame() && frame()->page()) 2504 frame()->page()->stopAutoscrollIfNeeded(this); 2505 2506 animation()->cancelAnimations(this); 2507 2508 // For accessibility management, notify the parent of the imminent change to its child set. 2509 // We do it now, before remove(), while the parent pointer is still available. 2510 if (AXObjectCache* cache = document()->existingAXObjectCache()) 2511 cache->childrenChanged(this->parent()); 2512 2513 remove(); 2514 2515 // The remove() call above may invoke axObjectCache()->childrenChanged() on the parent, which may require the AX render 2516 // object for this renderer. So we remove the AX render object now, after the renderer is removed. 2517 if (AXObjectCache* cache = document()->existingAXObjectCache()) 2518 cache->remove(this); 2519 2520 #ifndef NDEBUG 2521 if (!documentBeingDestroyed() && view() && view()->hasRenderNamedFlowThreads()) { 2522 // After remove, the object and the associated information should not be in any flow thread. 2523 const RenderNamedFlowThreadList* flowThreadList = view()->flowThreadController()->renderNamedFlowThreadList(); 2524 for (RenderNamedFlowThreadList::const_iterator iter = flowThreadList->begin(); iter != flowThreadList->end(); ++iter) { 2525 const RenderNamedFlowThread* renderFlowThread = *iter; 2526 ASSERT(!renderFlowThread->hasChild(this)); 2527 ASSERT(!renderFlowThread->hasChildInfo(this)); 2528 } 2529 } 2530 #endif 2531 2532 // If this renderer had a parent, remove should have destroyed any counters 2533 // attached to this renderer and marked the affected other counters for 2534 // reevaluation. This apparently redundant check is here for the case when 2535 // this renderer had no parent at the time remove() was called. 2536 2537 if (hasCounterNodeMap()) 2538 RenderCounter::destroyCounterNodes(this); 2539 2540 // FIXME: Would like to do this in RenderBoxModelObject, but the timing is so complicated that this can't easily 2541 // be moved into RenderBoxModelObject::destroy. 2542 if (hasLayer()) { 2543 setHasLayer(false); 2544 toRenderLayerModelObject(this)->destroyLayer(); 2545 } 2546 2547 setAncestorLineBoxDirty(false); 2548 2549 clearLayoutRootIfNeeded(); 2550 } 2551 2552 void RenderObject::insertedIntoTree() 2553 { 2554 // FIXME: We should ASSERT(isRooted()) here but generated content makes some out-of-order insertion. 2555 2556 // Keep our layer hierarchy updated. Optimize for the common case where we don't have any children 2557 // and don't have a layer attached to ourselves. 2558 RenderLayer* layer = 0; 2559 if (firstChild() || hasLayer()) { 2560 layer = parent()->enclosingLayer(); 2561 addLayers(layer); 2562 } 2563 2564 // If |this| is visible but this object was not, tell the layer it has some visible content 2565 // that needs to be drawn and layer visibility optimization can't be used 2566 if (parent()->style()->visibility() != VISIBLE && style()->visibility() == VISIBLE && !hasLayer()) { 2567 if (!layer) 2568 layer = parent()->enclosingLayer(); 2569 if (layer) 2570 layer->setHasVisibleContent(); 2571 } 2572 2573 if (!isFloating() && parent()->childrenInline()) 2574 parent()->dirtyLinesFromChangedChild(this); 2575 2576 if (RenderNamedFlowThread* containerFlowThread = parent()->renderNamedFlowThreadWrapper()) 2577 containerFlowThread->addFlowChild(this); 2578 } 2579 2580 void RenderObject::willBeRemovedFromTree() 2581 { 2582 // FIXME: We should ASSERT(isRooted()) but we have some out-of-order removals which would need to be fixed first. 2583 2584 // If we remove a visible child from an invisible parent, we don't know the layer visibility any more. 2585 RenderLayer* layer = 0; 2586 if (parent()->style()->visibility() != VISIBLE && style()->visibility() == VISIBLE && !hasLayer()) { 2587 if ((layer = parent()->enclosingLayer())) 2588 layer->dirtyVisibleContentStatus(); 2589 } 2590 2591 // Keep our layer hierarchy updated. 2592 if (firstChild() || hasLayer()) { 2593 if (!layer) 2594 layer = parent()->enclosingLayer(); 2595 removeLayers(layer); 2596 } 2597 2598 if (isOutOfFlowPositioned() && parent()->childrenInline()) 2599 parent()->dirtyLinesFromChangedChild(this); 2600 2601 removeFromRenderFlowThread(); 2602 2603 if (RenderNamedFlowThread* containerFlowThread = parent()->renderNamedFlowThreadWrapper()) 2604 containerFlowThread->removeFlowChild(this); 2605 2606 // Update cached boundaries in SVG renderers if a child is removed. 2607 parent()->setNeedsBoundariesUpdate(); 2608 } 2609 2610 void RenderObject::removeFromRenderFlowThread() 2611 { 2612 if (flowThreadState() == NotInsideFlowThread) 2613 return; 2614 2615 // Sometimes we remove the element from the flow, but it's not destroyed at that time. 2616 // It's only until later when we actually destroy it and remove all the children from it. 2617 // Currently, that happens for firstLetter elements and list markers. 2618 // Pass in the flow thread so that we don't have to look it up for all the children. 2619 removeFromRenderFlowThreadRecursive(flowThreadContainingBlock()); 2620 } 2621 2622 void RenderObject::removeFromRenderFlowThreadRecursive(RenderFlowThread* renderFlowThread) 2623 { 2624 if (const RenderObjectChildList* children = virtualChildren()) { 2625 for (RenderObject* child = children->firstChild(); child; child = child->nextSibling()) 2626 child->removeFromRenderFlowThreadRecursive(renderFlowThread); 2627 } 2628 2629 RenderFlowThread* localFlowThread = renderFlowThread; 2630 if (flowThreadState() == InsideInFlowThread) 2631 localFlowThread = flowThreadContainingBlock(); // We have to ask. We can't just assume we are in the same flow thread. 2632 if (localFlowThread) 2633 localFlowThread->removeFlowChildInfo(this); 2634 setFlowThreadState(NotInsideFlowThread); 2635 } 2636 2637 void RenderObject::destroyAndCleanupAnonymousWrappers() 2638 { 2639 // If the tree is destroyed, there is no need for a clean-up phase. 2640 if (documentBeingDestroyed()) { 2641 destroy(); 2642 return; 2643 } 2644 2645 RenderObject* destroyRoot = this; 2646 for (RenderObject* destroyRootParent = destroyRoot->parent(); destroyRootParent && destroyRootParent->isAnonymous(); destroyRoot = destroyRootParent, destroyRootParent = destroyRootParent->parent()) { 2647 // Anonymous block continuations are tracked and destroyed elsewhere (see the bottom of RenderBlock::removeChild) 2648 if (destroyRootParent->isRenderBlock() && toRenderBlock(destroyRootParent)->isAnonymousBlockContinuation()) 2649 break; 2650 // Render flow threads are tracked by the FlowThreadController, so we can't destroy them here. 2651 // Column spans are tracked elsewhere. 2652 if (destroyRootParent->isRenderFlowThread() || destroyRootParent->isAnonymousColumnSpanBlock()) 2653 break; 2654 2655 if (destroyRootParent->firstChild() != this || destroyRootParent->lastChild() != this) 2656 break; 2657 } 2658 2659 destroyRoot->destroy(); 2660 2661 // WARNING: |this| is deleted here. 2662 } 2663 2664 void RenderObject::destroy() 2665 { 2666 willBeDestroyed(); 2667 postDestroy(); 2668 } 2669 2670 void RenderObject::postDestroy() 2671 { 2672 // It seems ugly that this is not in willBeDestroyed(). 2673 if (m_style) { 2674 for (const FillLayer* bgLayer = m_style->backgroundLayers(); bgLayer; bgLayer = bgLayer->next()) { 2675 if (StyleImage* backgroundImage = bgLayer->image()) 2676 backgroundImage->removeClient(this); 2677 } 2678 2679 for (const FillLayer* maskLayer = m_style->maskLayers(); maskLayer; maskLayer = maskLayer->next()) { 2680 if (StyleImage* maskImage = maskLayer->image()) 2681 maskImage->removeClient(this); 2682 } 2683 2684 if (StyleImage* borderImage = m_style->borderImage().image()) 2685 borderImage->removeClient(this); 2686 2687 if (StyleImage* maskBoxImage = m_style->maskBoxImage().image()) 2688 maskBoxImage->removeClient(this); 2689 } 2690 2691 delete this; 2692 } 2693 2694 PositionWithAffinity RenderObject::positionForPoint(const LayoutPoint&) 2695 { 2696 return createPositionWithAffinity(caretMinOffset(), DOWNSTREAM); 2697 } 2698 2699 void RenderObject::updateDragState(bool dragOn) 2700 { 2701 bool valueChanged = (dragOn != isDragging()); 2702 setIsDragging(dragOn); 2703 if (valueChanged && node() && (style()->affectedByDrag() || (node()->isElementNode() && toElement(node())->childrenAffectedByDrag()))) 2704 node()->setNeedsStyleRecalc(); 2705 for (RenderObject* curr = firstChild(); curr; curr = curr->nextSibling()) 2706 curr->updateDragState(dragOn); 2707 } 2708 2709 bool RenderObject::isComposited() const 2710 { 2711 return hasLayer() && toRenderLayerModelObject(this)->layer()->isComposited(); 2712 } 2713 2714 bool RenderObject::hitTest(const HitTestRequest& request, HitTestResult& result, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, HitTestFilter hitTestFilter) 2715 { 2716 bool inside = false; 2717 if (hitTestFilter != HitTestSelf) { 2718 // First test the foreground layer (lines and inlines). 2719 inside = nodeAtPoint(request, result, locationInContainer, accumulatedOffset, HitTestForeground); 2720 2721 // Test floats next. 2722 if (!inside) 2723 inside = nodeAtPoint(request, result, locationInContainer, accumulatedOffset, HitTestFloat); 2724 2725 // Finally test to see if the mouse is in the background (within a child block's background). 2726 if (!inside) 2727 inside = nodeAtPoint(request, result, locationInContainer, accumulatedOffset, HitTestChildBlockBackgrounds); 2728 } 2729 2730 // See if the mouse is inside us but not any of our descendants 2731 if (hitTestFilter != HitTestDescendants && !inside) 2732 inside = nodeAtPoint(request, result, locationInContainer, accumulatedOffset, HitTestBlockBackground); 2733 2734 return inside; 2735 } 2736 2737 void RenderObject::updateHitTestResult(HitTestResult& result, const LayoutPoint& point) 2738 { 2739 if (result.innerNode()) 2740 return; 2741 2742 Node* node = this->node(); 2743 2744 // If we hit the anonymous renderers inside generated content we should 2745 // actually hit the generated content so walk up to the PseudoElement. 2746 if (!node && parent() && parent()->isBeforeOrAfterContent()) { 2747 for (RenderObject* renderer = parent(); renderer && !node; renderer = renderer->parent()) 2748 node = renderer->node(); 2749 } 2750 2751 if (node) { 2752 result.setInnerNode(node); 2753 if (!result.innerNonSharedNode()) 2754 result.setInnerNonSharedNode(node); 2755 result.setLocalPoint(point); 2756 } 2757 } 2758 2759 bool RenderObject::nodeAtPoint(const HitTestRequest&, HitTestResult&, const HitTestLocation& /*locationInContainer*/, const LayoutPoint& /*accumulatedOffset*/, HitTestAction) 2760 { 2761 return false; 2762 } 2763 2764 void RenderObject::scheduleRelayout() 2765 { 2766 if (isRenderView()) { 2767 FrameView* view = toRenderView(this)->frameView(); 2768 if (view) 2769 view->scheduleRelayout(); 2770 } else { 2771 if (isRooted()) { 2772 if (RenderView* renderView = view()) { 2773 if (FrameView* frameView = renderView->frameView()) 2774 frameView->scheduleRelayoutOfSubtree(this); 2775 } 2776 } 2777 } 2778 } 2779 2780 void RenderObject::layout() 2781 { 2782 StackStats::LayoutCheckPoint layoutCheckPoint; 2783 ASSERT(needsLayout()); 2784 RenderObject* child = firstChild(); 2785 while (child) { 2786 child->layoutIfNeeded(); 2787 ASSERT(!child->needsLayout()); 2788 child = child->nextSibling(); 2789 } 2790 clearNeedsLayout(); 2791 } 2792 2793 // FIXME: Do we need this method at all? If setNeedsLayout early returns in all the right places, 2794 // then MarkOnlyThis is not needed for performance or correctness. 2795 void RenderObject::forceLayout() 2796 { 2797 // This is the only way it's safe to use MarkOnlyThis (i.e. if we're immediately going to call layout). 2798 // FIXME: Add asserts that we only ever do the MarkOnlyThis behavior from here. 2799 setNeedsLayout(MarkOnlyThis); 2800 layout(); 2801 } 2802 2803 // FIXME: Does this do anything different than forceLayout given that we're passing MarkOnlyThis. 2804 // I don't think it does and we should change all callers to use forceLayout. 2805 void RenderObject::forceChildLayout() 2806 { 2807 setChildNeedsLayout(MarkOnlyThis); 2808 forceLayout(); 2809 } 2810 2811 enum StyleCacheState { 2812 Cached, 2813 Uncached 2814 }; 2815 2816 static PassRefPtr<RenderStyle> firstLineStyleForCachedUncachedType(StyleCacheState type, const RenderObject* renderer, RenderStyle* style) 2817 { 2818 const RenderObject* rendererForFirstLineStyle = renderer; 2819 if (renderer->isBeforeOrAfterContent()) 2820 rendererForFirstLineStyle = renderer->parent(); 2821 2822 if (rendererForFirstLineStyle->isBlockFlow()) { 2823 if (RenderBlock* firstLineBlock = rendererForFirstLineStyle->firstLineBlock()) { 2824 if (type == Cached) 2825 return firstLineBlock->getCachedPseudoStyle(FIRST_LINE, style); 2826 return firstLineBlock->getUncachedPseudoStyle(PseudoStyleRequest(FIRST_LINE), style, firstLineBlock == renderer ? style : 0); 2827 } 2828 } else if (!rendererForFirstLineStyle->isAnonymous() && rendererForFirstLineStyle->isRenderInline()) { 2829 RenderStyle* parentStyle = rendererForFirstLineStyle->parent()->firstLineStyle(); 2830 if (parentStyle != rendererForFirstLineStyle->parent()->style()) { 2831 if (type == Cached) { 2832 // A first-line style is in effect. Cache a first-line style for ourselves. 2833 rendererForFirstLineStyle->style()->setHasPseudoStyle(FIRST_LINE_INHERITED); 2834 return rendererForFirstLineStyle->getCachedPseudoStyle(FIRST_LINE_INHERITED, parentStyle); 2835 } 2836 return rendererForFirstLineStyle->getUncachedPseudoStyle(PseudoStyleRequest(FIRST_LINE_INHERITED), parentStyle, style); 2837 } 2838 } 2839 return 0; 2840 } 2841 2842 PassRefPtr<RenderStyle> RenderObject::uncachedFirstLineStyle(RenderStyle* style) const 2843 { 2844 if (!document()->styleSheetCollection()->usesFirstLineRules()) 2845 return 0; 2846 2847 ASSERT(!isText()); 2848 2849 return firstLineStyleForCachedUncachedType(Uncached, this, style); 2850 } 2851 2852 RenderStyle* RenderObject::cachedFirstLineStyle() const 2853 { 2854 ASSERT(document()->styleSheetCollection()->usesFirstLineRules()); 2855 2856 if (RefPtr<RenderStyle> style = firstLineStyleForCachedUncachedType(Cached, isText() ? parent() : this, m_style.get())) 2857 return style.get(); 2858 2859 return m_style.get(); 2860 } 2861 2862 RenderStyle* RenderObject::getCachedPseudoStyle(PseudoId pseudo, RenderStyle* parentStyle) const 2863 { 2864 if (pseudo < FIRST_INTERNAL_PSEUDOID && !style()->hasPseudoStyle(pseudo)) 2865 return 0; 2866 2867 RenderStyle* cachedStyle = style()->getCachedPseudoStyle(pseudo); 2868 if (cachedStyle) 2869 return cachedStyle; 2870 2871 RefPtr<RenderStyle> result = getUncachedPseudoStyle(PseudoStyleRequest(pseudo), parentStyle); 2872 if (result) 2873 return style()->addCachedPseudoStyle(result.release()); 2874 return 0; 2875 } 2876 2877 PassRefPtr<RenderStyle> RenderObject::getUncachedPseudoStyle(const PseudoStyleRequest& pseudoStyleRequest, RenderStyle* parentStyle, RenderStyle* ownStyle) const 2878 { 2879 if (pseudoStyleRequest.pseudoId < FIRST_INTERNAL_PSEUDOID && !ownStyle && !style()->hasPseudoStyle(pseudoStyleRequest.pseudoId)) 2880 return 0; 2881 2882 if (!parentStyle) { 2883 ASSERT(!ownStyle); 2884 parentStyle = style(); 2885 } 2886 2887 // FIXME: This "find nearest element parent" should be a helper function. 2888 Node* n = node(); 2889 while (n && !n->isElementNode()) 2890 n = n->parentNode(); 2891 if (!n) 2892 return 0; 2893 Element* element = toElement(n); 2894 2895 if (pseudoStyleRequest.pseudoId == FIRST_LINE_INHERITED) { 2896 RefPtr<RenderStyle> result = document()->styleResolver()->styleForElement(element, parentStyle, DisallowStyleSharing); 2897 result->setStyleType(FIRST_LINE_INHERITED); 2898 return result.release(); 2899 } 2900 2901 return document()->styleResolver()->pseudoStyleForElement(element, pseudoStyleRequest, parentStyle); 2902 } 2903 2904 bool RenderObject::hasBlendMode() const 2905 { 2906 return RuntimeEnabledFeatures::cssCompositingEnabled() && style() && style()->hasBlendMode(); 2907 } 2908 2909 static Color decorationColor(const RenderObject* object, RenderStyle* style) 2910 { 2911 StyleColor result; 2912 // Check for text decoration color first. 2913 result = object->resolveStyleColor(style, CSSPropertyTextDecorationColor); 2914 if (result.isValid()) 2915 return result.color(); 2916 if (style->textStrokeWidth() > 0) { 2917 // Prefer stroke color if possible but not if it's fully transparent. 2918 result = object->resolveColor(style, CSSPropertyWebkitTextStrokeColor); 2919 if (result.alpha()) 2920 return result.color(); 2921 } 2922 2923 result = object->resolveColor(style, CSSPropertyWebkitTextFillColor); 2924 return result.color(); 2925 } 2926 2927 void RenderObject::getTextDecorationColors(int decorations, Color& underline, Color& overline, 2928 Color& linethrough, bool quirksMode, bool firstlineStyle) 2929 { 2930 RenderObject* curr = this; 2931 RenderStyle* styleToUse = 0; 2932 TextDecoration currDecs = TextDecorationNone; 2933 Color resultColor; 2934 do { 2935 styleToUse = curr->style(firstlineStyle); 2936 currDecs = styleToUse->textDecoration(); 2937 resultColor = decorationColor(this, styleToUse); 2938 // Parameter 'decorations' is cast as an int to enable the bitwise operations below. 2939 if (currDecs) { 2940 if (currDecs & TextDecorationUnderline) { 2941 decorations &= ~TextDecorationUnderline; 2942 underline = resultColor; 2943 } 2944 if (currDecs & TextDecorationOverline) { 2945 decorations &= ~TextDecorationOverline; 2946 overline = resultColor; 2947 } 2948 if (currDecs & TextDecorationLineThrough) { 2949 decorations &= ~TextDecorationLineThrough; 2950 linethrough = resultColor; 2951 } 2952 } 2953 if (curr->isRubyText()) 2954 return; 2955 curr = curr->parent(); 2956 if (curr && curr->isAnonymousBlock() && toRenderBlock(curr)->continuation()) 2957 curr = toRenderBlock(curr)->continuation(); 2958 } while (curr && decorations && (!quirksMode || !curr->node() || (!isHTMLAnchorElement(curr->node()) && !curr->node()->hasTagName(fontTag)))); 2959 2960 // If we bailed out, use the element we bailed out at (typically a <font> or <a> element). 2961 if (decorations && curr) { 2962 styleToUse = curr->style(firstlineStyle); 2963 resultColor = decorationColor(this, styleToUse); 2964 if (decorations & TextDecorationUnderline) 2965 underline = resultColor; 2966 if (decorations & TextDecorationOverline) 2967 overline = resultColor; 2968 if (decorations & TextDecorationLineThrough) 2969 linethrough = resultColor; 2970 } 2971 } 2972 2973 void RenderObject::addAnnotatedRegions(Vector<AnnotatedRegionValue>& regions) 2974 { 2975 // Convert the style regions to absolute coordinates. 2976 if (style()->visibility() != VISIBLE || !isBox()) 2977 return; 2978 2979 RenderBox* box = toRenderBox(this); 2980 FloatPoint absPos = localToAbsolute(); 2981 2982 if (style()->getDraggableRegionMode() == DraggableRegionNone) 2983 return; 2984 AnnotatedRegionValue region; 2985 region.draggable = style()->getDraggableRegionMode() == DraggableRegionDrag; 2986 region.bounds = LayoutRect(absPos.x(), absPos.y(), box->width(), box->height()); 2987 regions.append(region); 2988 } 2989 2990 void RenderObject::collectAnnotatedRegions(Vector<AnnotatedRegionValue>& regions) 2991 { 2992 // RenderTexts don't have their own style, they just use their parent's style, 2993 // so we don't want to include them. 2994 if (isText()) 2995 return; 2996 2997 addAnnotatedRegions(regions); 2998 for (RenderObject* curr = firstChild(); curr; curr = curr->nextSibling()) 2999 curr->collectAnnotatedRegions(regions); 3000 } 3001 3002 bool RenderObject::willRenderImage(ImageResource*) 3003 { 3004 // Without visibility we won't render (and therefore don't care about animation). 3005 if (style()->visibility() != VISIBLE) 3006 return false; 3007 3008 // We will not render a new image when Active DOM is suspended 3009 if (document()->activeDOMObjectsAreSuspended()) 3010 return false; 3011 3012 // If we're not in a window (i.e., we're dormant from being in a background tab) 3013 // then we don't want to render either. 3014 return !document()->view()->isOffscreen(); 3015 } 3016 3017 int RenderObject::maximalOutlineSize(PaintPhase p) const 3018 { 3019 if (p != PaintPhaseOutline && p != PaintPhaseSelfOutline && p != PaintPhaseChildOutlines) 3020 return 0; 3021 return view()->maximalOutlineSize(); 3022 } 3023 3024 int RenderObject::caretMinOffset() const 3025 { 3026 return 0; 3027 } 3028 3029 int RenderObject::caretMaxOffset() const 3030 { 3031 if (isReplaced()) 3032 return node() ? max(1U, node()->childNodeCount()) : 1; 3033 if (isHR()) 3034 return 1; 3035 return 0; 3036 } 3037 3038 int RenderObject::previousOffset(int current) const 3039 { 3040 return current - 1; 3041 } 3042 3043 int RenderObject::previousOffsetForBackwardDeletion(int current) const 3044 { 3045 return current - 1; 3046 } 3047 3048 int RenderObject::nextOffset(int current) const 3049 { 3050 return current + 1; 3051 } 3052 3053 void RenderObject::adjustRectForOutlineAndShadow(LayoutRect& rect) const 3054 { 3055 int outlineSize = outlineStyleForRepaint()->outlineSize(); 3056 if (const ShadowData* boxShadow = style()->boxShadow()) { 3057 boxShadow->adjustRectForShadow(rect, outlineSize); 3058 return; 3059 } 3060 3061 rect.inflate(outlineSize); 3062 } 3063 3064 AnimationController* RenderObject::animation() const 3065 { 3066 return frame()->animation(); 3067 } 3068 3069 bool RenderObject::isInert() const 3070 { 3071 const RenderObject* renderer = this; 3072 while (!renderer->node()) 3073 renderer = renderer->parent(); 3074 const Node* parentNode = renderer->node(); 3075 while (parentNode && !parentNode->isElementNode()) 3076 parentNode = parentNode->parentNode(); 3077 return parentNode && toElement(parentNode)->isInert(); 3078 } 3079 3080 void RenderObject::imageChanged(ImageResource* image, const IntRect* rect) 3081 { 3082 imageChanged(static_cast<WrappedImagePtr>(image), rect); 3083 } 3084 3085 RenderObject* RenderObject::hoverAncestor() const 3086 { 3087 // When searching for the hover ancestor and encountering a named flow thread, 3088 // the search will continue with the DOM ancestor of the top-most element 3089 // in the named flow thread. 3090 // See https://code.google.com/p/chromium/issues/detail?id=243278 3091 RenderObject* hoverAncestor = parent(); 3092 3093 // Skip anonymous blocks directly flowed into flow threads as it would 3094 // prevent us from continuing the search on the DOM tree when reaching the named flow thread. 3095 if (hoverAncestor && hoverAncestor->isAnonymousBlock() && hoverAncestor->parent() && hoverAncestor->parent()->isRenderNamedFlowThread()) 3096 hoverAncestor = hoverAncestor->parent(); 3097 3098 if (hoverAncestor && hoverAncestor->isRenderNamedFlowThread()) { 3099 hoverAncestor = 0; 3100 3101 Node* node = this->node(); 3102 if (node) { 3103 Node* domAncestorNode = node->parentNode(); 3104 if (domAncestorNode) 3105 hoverAncestor = domAncestorNode->renderer(); 3106 } 3107 } 3108 3109 return hoverAncestor; 3110 } 3111 3112 Element* RenderObject::offsetParent() const 3113 { 3114 if (isRoot() || isBody()) 3115 return 0; 3116 3117 if (isOutOfFlowPositioned() && style()->position() == FixedPosition) 3118 return 0; 3119 3120 // If A is an area HTML element which has a map HTML element somewhere in the ancestor 3121 // chain return the nearest ancestor map HTML element and stop this algorithm. 3122 // FIXME: Implement! 3123 3124 float effectiveZoom = style()->effectiveZoom(); 3125 Node* node = 0; 3126 for (RenderObject* ancestor = parent(); ancestor; ancestor = ancestor->parent()) { 3127 // Spec: http://www.w3.org/TR/cssom-view/#offset-attributes 3128 3129 // CSS regions specification says that region flows should return the body element as their offsetParent. 3130 if (ancestor->isRenderNamedFlowThread()) 3131 return document()->body(); 3132 3133 node = ancestor->node(); 3134 3135 if (!node) 3136 continue; 3137 3138 if (ancestor->isPositioned()) 3139 break; 3140 3141 if (node->hasTagName(HTMLNames::bodyTag)) 3142 break; 3143 3144 if (!isPositioned() && (isHTMLTableElement(node) || node->hasTagName(tdTag) || node->hasTagName(thTag))) 3145 break; 3146 3147 // Webkit specific extension where offsetParent stops at zoom level changes. 3148 if (effectiveZoom != ancestor->style()->effectiveZoom()) 3149 break; 3150 } 3151 3152 return node && node->isElementNode() ? toElement(node) : 0; 3153 } 3154 3155 PositionWithAffinity RenderObject::createPositionWithAffinity(int offset, EAffinity affinity) 3156 { 3157 // If this is a non-anonymous renderer in an editable area, then it's simple. 3158 if (Node* node = nonPseudoNode()) { 3159 if (!node->rendererIsEditable()) { 3160 // If it can be found, we prefer a visually equivalent position that is editable. 3161 Position position = createLegacyEditingPosition(node, offset); 3162 Position candidate = position.downstream(CanCrossEditingBoundary); 3163 if (candidate.deprecatedNode()->rendererIsEditable()) 3164 return PositionWithAffinity(candidate, affinity); 3165 candidate = position.upstream(CanCrossEditingBoundary); 3166 if (candidate.deprecatedNode()->rendererIsEditable()) 3167 return PositionWithAffinity(candidate, affinity); 3168 } 3169 // FIXME: Eliminate legacy editing positions 3170 return PositionWithAffinity(createLegacyEditingPosition(node, offset), affinity); 3171 } 3172 3173 // We don't want to cross the boundary between editable and non-editable 3174 // regions of the document, but that is either impossible or at least 3175 // extremely unlikely in any normal case because we stop as soon as we 3176 // find a single non-anonymous renderer. 3177 3178 // Find a nearby non-anonymous renderer. 3179 RenderObject* child = this; 3180 while (RenderObject* parent = child->parent()) { 3181 // Find non-anonymous content after. 3182 RenderObject* renderer = child; 3183 while ((renderer = renderer->nextInPreOrder(parent))) { 3184 if (Node* node = renderer->nonPseudoNode()) 3185 return PositionWithAffinity(firstPositionInOrBeforeNode(node), DOWNSTREAM); 3186 } 3187 3188 // Find non-anonymous content before. 3189 renderer = child; 3190 while ((renderer = renderer->previousInPreOrder())) { 3191 if (renderer == parent) 3192 break; 3193 if (Node* node = renderer->nonPseudoNode()) 3194 return PositionWithAffinity(lastPositionInOrAfterNode(node), DOWNSTREAM); 3195 } 3196 3197 // Use the parent itself unless it too is anonymous. 3198 if (Node* node = parent->nonPseudoNode()) 3199 return PositionWithAffinity(firstPositionInOrBeforeNode(node), DOWNSTREAM); 3200 3201 // Repeat at the next level up. 3202 child = parent; 3203 } 3204 3205 // Everything was anonymous. Give up. 3206 return PositionWithAffinity(); 3207 } 3208 3209 PositionWithAffinity RenderObject::createPositionWithAffinity(const Position& position) 3210 { 3211 if (position.isNotNull()) 3212 return PositionWithAffinity(position); 3213 3214 ASSERT(!node()); 3215 return createPositionWithAffinity(0, DOWNSTREAM); 3216 } 3217 3218 CursorDirective RenderObject::getCursor(const LayoutPoint&, Cursor&) const 3219 { 3220 return SetCursorBasedOnStyle; 3221 } 3222 3223 bool RenderObject::canUpdateSelectionOnRootLineBoxes() 3224 { 3225 if (needsLayout()) 3226 return false; 3227 3228 RenderBlock* containingBlock = this->containingBlock(); 3229 return containingBlock ? !containingBlock->needsLayout() : true; 3230 } 3231 3232 // We only create "generated" child renderers like one for first-letter if: 3233 // - the firstLetterBlock can have children in the DOM and 3234 // - the block doesn't have any special assumption on its text children. 3235 // This correctly prevents form controls from having such renderers. 3236 bool RenderObject::canHaveGeneratedChildren() const 3237 { 3238 return canHaveChildren(); 3239 } 3240 3241 bool RenderObject::canBeReplacedWithInlineRunIn() const 3242 { 3243 return true; 3244 } 3245 3246 RenderSVGResourceContainer* RenderObject::toRenderSVGResourceContainer() 3247 { 3248 ASSERT_NOT_REACHED(); 3249 return 0; 3250 } 3251 3252 void RenderObject::setNeedsBoundariesUpdate() 3253 { 3254 if (RenderObject* renderer = parent()) 3255 renderer->setNeedsBoundariesUpdate(); 3256 } 3257 3258 FloatRect RenderObject::objectBoundingBox() const 3259 { 3260 ASSERT_NOT_REACHED(); 3261 return FloatRect(); 3262 } 3263 3264 FloatRect RenderObject::strokeBoundingBox() const 3265 { 3266 ASSERT_NOT_REACHED(); 3267 return FloatRect(); 3268 } 3269 3270 // Returns the smallest rectangle enclosing all of the painted content 3271 // respecting clipping, masking, filters, opacity, stroke-width and markers 3272 FloatRect RenderObject::repaintRectInLocalCoordinates() const 3273 { 3274 ASSERT_NOT_REACHED(); 3275 return FloatRect(); 3276 } 3277 3278 AffineTransform RenderObject::localTransform() const 3279 { 3280 static const AffineTransform identity; 3281 return identity; 3282 } 3283 3284 const AffineTransform& RenderObject::localToParentTransform() const 3285 { 3286 static const AffineTransform identity; 3287 return identity; 3288 } 3289 3290 bool RenderObject::nodeAtFloatPoint(const HitTestRequest&, HitTestResult&, const FloatPoint&, HitTestAction) 3291 { 3292 ASSERT_NOT_REACHED(); 3293 return false; 3294 } 3295 3296 // FIXME: This should really use local coords 3297 // Works on absolute coords - expensive to call 3298 bool RenderObject::isContainedInParentBoundingBox() const 3299 { 3300 if (!parent()) 3301 return false; 3302 3303 IntRect parentRect = parent()->absoluteBoundingBoxRect(); 3304 return parentRect.contains(absoluteBoundingBoxRect()); 3305 } 3306 3307 } // namespace WebCore 3308 3309 #ifndef NDEBUG 3310 3311 void showTree(const WebCore::RenderObject* object) 3312 { 3313 if (object) 3314 object->showTreeForThis(); 3315 } 3316 3317 void showLineTree(const WebCore::RenderObject* object) 3318 { 3319 if (object) 3320 object->showLineTreeForThis(); 3321 } 3322 3323 void showRenderTree(const WebCore::RenderObject* object1) 3324 { 3325 showRenderTree(object1, 0); 3326 } 3327 3328 void showRenderTree(const WebCore::RenderObject* object1, const WebCore::RenderObject* object2) 3329 { 3330 if (object1) { 3331 const WebCore::RenderObject* root = object1; 3332 while (root->parent()) 3333 root = root->parent(); 3334 root->showRenderTreeAndMark(object1, "*", object2, "-", 0); 3335 } 3336 } 3337 3338 #endif 3339