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