2 * This file is part of the html renderer for KDE.
4 * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
5 * (C) 1999 Antti Koivisto (koivisto@kde.org)
6 * (C) 2000 Dirk Mueller (mueller@kde.org)
7 * (C) 2004 Allan Sandfeld Jensen (kde@carewolf.com)
8 * Copyright (C) 2004, 2005, 2006 Apple Computer, Inc.
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.
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.
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., 59 Temple Place - Suite 330,
23 * Boston, MA 02111-1307, USA.
28 #include "RenderObject.h"
30 #include "AXObjectCache.h"
31 #include "AffineTransform.h"
32 #include "CachedImage.h"
33 #include "CounterNode.h"
34 #include "CounterResetNode.h"
38 #include "EventNames.h"
39 #include "FloatRect.h"
41 #include "GraphicsContext.h"
42 #include "HTMLNames.h"
43 #include "HTMLOListElement.h"
45 #include "RenderArena.h"
46 #include "RenderFlexibleBox.h"
47 #include "RenderImage.h"
48 #include "RenderInline.h"
49 #include "RenderListItem.h"
50 #include "RenderTableCell.h"
51 #include "RenderTableCol.h"
52 #include "RenderTableRow.h"
53 #include "RenderText.h"
54 #include "RenderTheme.h"
55 #include "RenderView.h"
57 #include "TextStream.h"
58 #include "cssstyleselector.h"
65 using namespace EventNames;
66 using namespace HTMLNames;
69 static void *baseOfRenderObjectBeingDeleted;
72 typedef HashMap<String, CounterNode*> CounterNodeMap;
73 typedef HashMap<const RenderObject*, CounterNodeMap*> RenderObjectsToCounterNodeMaps;
75 static RenderObjectsToCounterNodeMaps* getRenderObjectsToCounterNodeMaps()
77 static RenderObjectsToCounterNodeMaps objectsMap;
81 void* RenderObject::operator new(size_t sz, RenderArena* renderArena) throw()
83 return renderArena->allocate(sz);
86 void RenderObject::operator delete(void* ptr, size_t sz)
88 ASSERT(baseOfRenderObjectBeingDeleted == ptr);
90 // Stash size where destroy can find it.
94 RenderObject *RenderObject::createObject(Node* node, RenderStyle* style)
97 RenderArena* arena = node->document()->renderArena();
99 if (ContentData *contentData = style->contentData()) {
100 RenderImage *contentImage = new (arena) RenderImage(node);
102 contentImage->setStyle(style);
103 contentImage->setContentObject(contentData->contentObject());
104 contentImage->setIsAnonymousImage(true);
109 switch(style->display())
114 o = new (arena) RenderInline(node);
117 o = new (arena) RenderBlock(node);
120 o = new (arena) RenderBlock(node);
123 o = new (arena) RenderListItem(node);
127 o = new (arena) RenderBlock(node);
131 o = new (arena) RenderTable(node);
133 case TABLE_ROW_GROUP:
134 case TABLE_HEADER_GROUP:
135 case TABLE_FOOTER_GROUP:
136 o = new (arena) RenderTableSection(node);
139 o = new (arena) RenderTableRow(node);
141 case TABLE_COLUMN_GROUP:
143 o = new (arena) RenderTableCol(node);
146 o = new (arena) RenderTableCell(node);
149 o = new (arena) RenderBlock(node);
153 o = new (arena) RenderFlexibleBox(node);
160 struct RenderObjectCounter {
162 ~RenderObjectCounter() { if (count != 0) fprintf(stderr, "LEAK: %d RenderObject\n", count); }
164 int RenderObjectCounter::count;
165 static RenderObjectCounter renderObjectCounter;
168 RenderObject::RenderObject(Node* node)
169 : CachedResourceClient(),
175 m_verticalPosition( PositionUndefined ),
176 m_needsLayout( false ),
177 m_normalChildNeedsLayout( false ),
178 m_posChildNeedsLayout( false ),
179 m_minMaxKnown( false ),
182 m_positioned( false ),
183 m_relPositioned( false ),
184 m_paintBackground( false ),
186 m_isAnonymous( node == node->document() ),
187 m_recalcMinMax( false ),
192 m_isDragging( false ),
193 m_hasOverflowClip(false),
194 m_hasCounterNodeMap(false)
197 ++RenderObjectCounter::count;
201 RenderObject::~RenderObject()
204 --RenderObjectCounter::count;
208 bool RenderObject::isDescendantOf(const RenderObject *obj) const
210 for (const RenderObject *r = this; r; r = r->m_parent)
216 bool RenderObject::isRoot() const
218 return element() && element()->renderer() == this &&
219 element()->document()->documentElement() == element();
222 bool RenderObject::isBody() const
224 return element() && element()->renderer() == this && element()->hasTagName(bodyTag);
227 bool RenderObject::isHR() const
229 return element() && element()->hasTagName(hrTag);
232 bool RenderObject::isHTMLMarquee() const
234 return element() && element()->renderer() == this && element()->hasTagName(marqueeTag);
237 bool RenderObject::canHaveChildren() const
242 RenderFlow* RenderObject::continuation() const
247 bool RenderObject::isInlineContinuation() const
252 void RenderObject::addChild(RenderObject* , RenderObject *)
257 RenderObject* RenderObject::removeChildNode(RenderObject* )
263 void RenderObject::removeChild(RenderObject* )
268 void RenderObject::appendChildNode(RenderObject*)
273 void RenderObject::insertChildNode(RenderObject*, RenderObject*)
278 RenderObject *RenderObject::nextInPreOrder() const
280 if (RenderObject* o = firstChild())
283 return nextInPreOrderAfterChildren();
286 RenderObject* RenderObject::nextInPreOrderAfterChildren() const
289 if (!(o = nextSibling())) {
291 while (o && !o->nextSibling())
294 o = o->nextSibling();
299 RenderObject *RenderObject::previousInPreOrder() const
301 if (RenderObject* o = previousSibling()) {
302 while (o->lastChild())
310 RenderObject* RenderObject::childAt(unsigned index) const
312 RenderObject* child = firstChild();
313 for (unsigned i = 0; child && i < index; i++)
314 child = child->nextSibling();
318 bool RenderObject::isEditable() const
320 RenderText *textRenderer = 0;
322 textRenderer = static_cast<RenderText *>(const_cast<RenderObject *>(this));
325 return style()->visibility() == VISIBLE &&
326 element() && element()->isContentEditable() &&
327 ((isBlockFlow() && !firstChild()) ||
330 (textRenderer && textRenderer->firstTextBox()));
333 RenderObject *RenderObject::nextEditable() const
335 RenderObject *r = const_cast<RenderObject *>(this);
336 RenderObject *n = firstChild();
345 return r->nextEditable();
347 n = r->nextSibling();
357 return r->nextEditable();
362 n = r->nextSibling();
373 return r->nextEditable();
380 RenderObject *RenderObject::previousEditable() const
382 RenderObject *r = const_cast<RenderObject *>(this);
383 RenderObject *n = firstChild();
392 return r->previousEditable();
394 n = r->previousSibling();
404 return r->previousEditable();
409 n = r->previousSibling();
420 return r->previousEditable();
427 RenderObject *RenderObject::firstLeafChild() const
429 RenderObject *r = firstChild();
440 RenderObject *RenderObject::lastLeafChild() const
442 RenderObject *r = lastChild();
453 static void addLayers(RenderObject* obj, RenderLayer* parentLayer, RenderObject*& newObject,
454 RenderLayer*& beforeChild)
457 if (!beforeChild && newObject) {
458 // We need to figure out the layer that follows newObject. We only do
459 // this the first time we find a child layer, and then we update the
460 // pointer values for newObject and beforeChild used by everyone else.
461 beforeChild = newObject->parent()->findNextLayer(parentLayer, newObject);
464 parentLayer->addChild(obj->layer(), beforeChild);
468 for (RenderObject* curr = obj->firstChild(); curr; curr = curr->nextSibling())
469 addLayers(curr, parentLayer, newObject, beforeChild);
472 void RenderObject::addLayers(RenderLayer* parentLayer, RenderObject* newObject)
477 RenderObject* object = newObject;
478 RenderLayer* beforeChild = 0;
479 WebCore::addLayers(this, parentLayer, object, beforeChild);
482 void RenderObject::removeLayers(RenderLayer* parentLayer)
488 parentLayer->removeChild(layer());
492 for (RenderObject* curr = firstChild(); curr; curr = curr->nextSibling())
493 curr->removeLayers(parentLayer);
496 void RenderObject::moveLayers(RenderLayer* oldParent, RenderLayer* newParent)
503 oldParent->removeChild(layer());
504 newParent->addChild(layer());
508 for (RenderObject* curr = firstChild(); curr; curr = curr->nextSibling())
509 curr->moveLayers(oldParent, newParent);
512 RenderLayer* RenderObject::findNextLayer(RenderLayer* parentLayer, RenderObject* startPoint,
515 // Error check the parent layer passed in. If it's null, we can't find anything.
519 // Step 1: If our layer is a child of the desired parent, then return our layer.
520 RenderLayer* ourLayer = layer();
521 if (ourLayer && ourLayer->parent() == parentLayer)
524 // Step 2: If we don't have a layer, or our layer is the desired parent, then descend
525 // into our siblings trying to find the next layer whose parent is the desired parent.
526 if (!ourLayer || ourLayer == parentLayer) {
527 for (RenderObject* curr = startPoint ? startPoint->nextSibling() : firstChild();
528 curr; curr = curr->nextSibling()) {
529 RenderLayer* nextLayer = curr->findNextLayer(parentLayer, 0, false);
535 // Step 3: If our layer is the desired parent layer, then we're finished. We didn't
537 if (parentLayer == ourLayer)
540 // Step 4: If |checkParent| is set, climb up to our parent and check its siblings that
541 // follow us to see if we can locate a layer.
542 if (checkParent && parent())
543 return parent()->findNextLayer(parentLayer, this, true);
548 RenderLayer* RenderObject::enclosingLayer() const
550 const RenderObject* curr = this;
552 RenderLayer *layer = curr->layer();
555 curr = curr->parent();
560 bool RenderObject::requiresLayer()
562 return isRoot() || isPositioned() || isRelPositioned() || isTransparent() || hasOverflowClip();
565 RenderBlock* RenderObject::firstLineBlock() const
570 void RenderObject::updateFirstLetter()
573 int RenderObject::offsetLeft() const
575 RenderObject* offsetPar = offsetParent();
579 if (!isPositioned()) {
580 if (isRelPositioned())
581 x += static_cast<const RenderBox*>(this)->relativePositionOffsetX();
582 RenderObject* curr = parent();
583 while (curr && curr != offsetPar) {
585 curr = curr->parent();
591 int RenderObject::offsetTop() const
593 RenderObject* offsetPar = offsetParent();
597 if (!isPositioned()) {
598 if (isRelPositioned())
599 y += static_cast<const RenderBox*>(this)->relativePositionOffsetY();
600 RenderObject* curr = parent();
601 while (curr && curr != offsetPar) {
602 if (!curr->isTableRow())
604 curr = curr->parent();
610 RenderObject* RenderObject::offsetParent() const
612 // FIXME: It feels like this function could almost be written using containing blocks.
615 bool skipTables = isPositioned() || isRelPositioned();
616 RenderObject* curr = parent();
617 while (curr && (!curr->element() ||
618 (!curr->isPositioned() && !curr->isRelPositioned() &&
619 !(!style()->htmlHacks() && skipTables ? curr->isRoot() : curr->isBody())))) {
620 if (!skipTables && curr->element() && (curr->isTableCell() || curr->isTable()))
622 curr = curr->parent();
627 // More IE extensions. clientWidth and clientHeight represent the interior of an object
628 // excluding border and scrollbar.
629 int RenderObject::clientWidth() const
631 return width() - borderLeft() - borderRight() -
632 (includeVerticalScrollbarSize() ? layer()->verticalScrollbarWidth() : 0);
635 int RenderObject::clientHeight() const
637 return height() - borderTop() - borderBottom() -
638 (includeHorizontalScrollbarSize() ? layer()->horizontalScrollbarHeight() : 0);
641 // scrollWidth/scrollHeight will be the same as clientWidth/clientHeight unless the
642 // object has overflow:hidden/scroll/auto specified and also has overflow.
643 int RenderObject::scrollWidth() const
645 return hasOverflowClip() ? layer()->scrollWidth() : overflowWidth();
648 int RenderObject::scrollHeight() const
650 return hasOverflowClip() ? layer()->scrollHeight() : overflowHeight();
653 int RenderObject::scrollLeft() const
655 return hasOverflowClip() ? layer()->scrollXOffset() : 0;
658 int RenderObject::scrollTop() const
660 return hasOverflowClip() ? layer()->scrollYOffset() : 0;
663 void RenderObject::setScrollLeft(int newLeft)
665 if (hasOverflowClip())
666 layer()->scrollToXOffset(newLeft);
669 void RenderObject::setScrollTop(int newTop)
671 if (hasOverflowClip())
672 layer()->scrollToYOffset(newTop);
675 bool RenderObject::scroll(ScrollDirection direction, ScrollGranularity granularity, float multiplier)
677 RenderLayer *l = layer();
678 if (l && l->scroll(direction, granularity, multiplier))
680 RenderBlock *b = containingBlock();
681 if (b && !b->isRenderView())
682 return b->scroll(direction, granularity, multiplier);
686 bool RenderObject::shouldAutoscroll() const
688 return ((isRoot()) || (hasOverflowClip() && (scrollsOverflow() || (node() && node()->isContentEditable()))));
691 void RenderObject::autoscroll()
693 if (RenderLayer* l = layer())
697 bool RenderObject::hasStaticX() const
699 return (style()->left().isAuto() && style()->right().isAuto()) ||
700 style()->left().isStatic() ||
701 style()->right().isStatic();
704 bool RenderObject::hasStaticY() const
706 return (style()->top().isAuto() && style()->bottom().isAuto()) || style()->top().isStatic();
709 void RenderObject::markAllDescendantsWithFloatsForLayout(RenderObject*)
713 void RenderObject::setNeedsLayout(bool b, bool markParents)
715 bool alreadyNeededLayout = m_needsLayout;
718 if (!alreadyNeededLayout && markParents)
719 markContainingBlocksForLayout();
722 m_posChildNeedsLayout = false;
723 m_normalChildNeedsLayout = false;
727 void RenderObject::setChildNeedsLayout(bool b, bool markParents)
729 bool alreadyNeededLayout = m_normalChildNeedsLayout;
730 m_normalChildNeedsLayout = b;
732 if (!alreadyNeededLayout && markParents)
733 markContainingBlocksForLayout();
736 m_posChildNeedsLayout = false;
737 m_normalChildNeedsLayout = false;
741 void RenderObject::markContainingBlocksForLayout(bool scheduleRelayout)
743 RenderObject *o = container();
744 RenderObject *last = this;
747 if (!last->isText() && (last->style()->position() == FixedPosition || last->style()->position() == AbsolutePosition)) {
748 if (o->m_posChildNeedsLayout)
750 o->m_posChildNeedsLayout = true;
752 if (o->m_normalChildNeedsLayout)
754 o->m_normalChildNeedsLayout = true;
758 if (scheduleRelayout && (last->isTextField() || last->isTextArea()))
763 if (scheduleRelayout)
764 last->scheduleRelayout();
767 RenderBlock* RenderObject::containingBlock() const
770 return static_cast<const RenderTableCell *>(this)->table();
772 return (RenderBlock*)this;
774 RenderObject *o = parent();
775 if (!isText() && m_style->position() == FixedPosition) {
776 while ( o && !o->isRenderView() )
779 else if (!isText() && m_style->position() == AbsolutePosition) {
780 while (o && (o->style()->position() == StaticPosition || (o->isInline() && !o->isReplaced()))
781 && !o->isRoot() && !o->isRenderView()) {
782 // For relpositioned inlines, we return the nearest 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
787 if (o->style()->position() == RelativePosition && o->isInline() && !o->isReplaced())
788 return o->containingBlock();
792 while (o && ((o->isInline() && !o->isReplaced()) || o->isTableRow() || o->isTableSection()
793 || o->isTableCol() || o->isFrameSet()
795 || o->isKCanvasContainer()
801 if (!o || !o->isRenderBlock())
802 return 0; // Probably doesn't happen any more, but leave just in case. -dwh
804 return static_cast<RenderBlock*>(o);
807 int RenderObject::containingBlockWidth() const
810 return containingBlock()->contentWidth();
813 int RenderObject::containingBlockHeight() const
816 return containingBlock()->contentHeight();
819 bool RenderObject::mustRepaintBackgroundOrBorder() const
821 // If we don't have a background/border, then nothing to do.
822 if (!shouldPaintBackgroundOrBorder())
825 // Ok, let's check the background first.
826 const BackgroundLayer* bgLayer = style()->backgroundLayers();
828 return true; // Nobody will use multiple background layers without wanting fancy positioning.
830 // Make sure we have a valid background image.
831 CachedImage* bg = bgLayer->backgroundImage();
832 bool shouldPaintBackgroundImage = bg && bg->canRender();
834 // These are always percents or auto.
835 if (shouldPaintBackgroundImage &&
836 (bgLayer->backgroundXPosition().value() != 0 || bgLayer->backgroundYPosition().value() != 0
837 || bgLayer->backgroundSize().width.isPercent() || bgLayer->backgroundSize().height.isPercent()))
838 return true; // The background image will shift unpredictably if the size changes.
840 // Background is ok. Let's check border.
841 if (style()->hasBorder()) {
842 // Border images are not ok.
843 CachedImage* borderImage = style()->borderImage().image();
844 bool shouldPaintBorderImage = borderImage && borderImage->canRender();
845 if (shouldPaintBorderImage && borderImage->isLoaded())
846 return true; // If the image hasn't loaded, we're still using the normal border style.
852 void RenderObject::drawBorderArc(GraphicsContext* p, int x, int y, float thickness, IntSize radius, int angleStart,
853 int angleSpan, BorderSide s, Color c, const Color& textColor, EBorderStyle style, bool firstCorner)
855 if ((style == DOUBLE && ((thickness / 2) < 3)) ||
856 ((style == RIDGE || style == GROOVE) && ((thickness / 2) < 2)))
860 if (style == INSET || style == OUTSET || style == RIDGE || style == GROOVE)
861 c.setRGB(238, 238, 238);
871 p->setPen(Pen(c, thickness == 1 ? 0 : (int)thickness, Pen::DotLine));
874 p->setPen(Pen(c, thickness == 1 ? 0 : (int)thickness, Pen::DashLine));
877 if (s == BSBottom || s == BSTop)
878 p->drawArc(IntRect(x, y, radius.width() * 2, radius.height() * 2), thickness, angleStart, angleSpan);
879 else //We are drawing a left or right border
880 p->drawArc(IntRect(x, y, radius.width() * 2, radius.height() * 2), thickness, angleStart, angleSpan);
885 float third = thickness / 3;
886 float innerThird = (thickness + 1) / 6;
887 int shiftForInner = (int)(innerThird * 2.5);
888 p->setPen(Pen::NoPen);
891 int outerHeight = radius.height() * 2;
892 int innerX = x + shiftForInner;
893 int innerY = y + shiftForInner;
894 int innerWidth = (radius.width() - shiftForInner) * 2;
895 int innerHeight = (radius.height() - shiftForInner) * 2;
896 if (innerThird > 1 && (s == BSTop || (firstCorner && (s == BSLeft || s == BSRight)))) {
901 p->drawArc(IntRect(x, outerY, radius.width() * 2, outerHeight), third, angleStart, angleSpan);
902 p->drawArc(IntRect(innerX, innerY, innerWidth, innerHeight), (innerThird > 2) ? innerThird - 1 : innerThird,
903 angleStart, angleSpan);
909 if ((style == RIDGE && (s == BSTop || s == BSLeft)) ||
910 (style == GROOVE && (s == BSBottom || s == BSRight)))
917 p->setPen(Pen::NoPen);
918 p->setFillColor(c.rgb());
919 p->drawArc(IntRect(x, y, radius.width() * 2, radius.height() * 2), thickness, angleStart, angleSpan);
921 float halfThickness = (thickness + 1) / 4;
922 int shiftForInner = (int)(halfThickness * 1.5);
923 p->setFillColor(c2.rgb());
924 p->drawArc(IntRect(x + shiftForInner, y + shiftForInner, (radius.width() - shiftForInner) * 2,
925 (radius.height() - shiftForInner) * 2), (halfThickness > 2) ? halfThickness - 1 : halfThickness,
926 angleStart, angleSpan);
930 if(s == BSTop || s == BSLeft)
933 if(style == OUTSET && (s == BSBottom || s == BSRight))
936 p->setPen(Pen::NoPen);
937 p->setFillColor(c.rgb());
938 p->drawArc(IntRect(x, y, radius.width() * 2, radius.height() * 2), thickness, angleStart, angleSpan);
943 void RenderObject::drawBorder(GraphicsContext* p, int x1, int y1, int x2, int y2,
944 BorderSide s, Color c, const Color& textcolor, EBorderStyle style,
945 int adjbw1, int adjbw2)
947 int width = (s == BSTop || s == BSBottom ? y2 - y1 : x2 - x1);
949 if (style == DOUBLE && width < 3)
953 if (style == INSET || style == OUTSET || style == RIDGE || style == GROOVE)
954 c.setRGB(238, 238, 238);
965 p->setPen(Pen(c, width == 1 ? 0 : width, Pen::DotLine));
969 p->setPen(Pen(c, width == 1 ? 0 : width, Pen::DashLine));
976 p->drawLine(IntPoint(x1, (y1+y2)/2), IntPoint(x2, (y1+y2)/2));
980 p->drawLine(IntPoint((x1+x2)/2, y1), IntPoint((x1+x2)/2, y2));
988 int third = (width+1)/3;
990 if (adjbw1 == 0 && adjbw2 == 0)
992 p->setPen(Pen::NoPen);
993 p->setFillColor(c.rgb());
998 p->drawRect(IntRect(x1, y1 , x2-x1, third));
999 p->drawRect(IntRect(x1, y2-third, x2-x1, third));
1002 p->drawRect(IntRect(x1 , y1+1, third, y2-y1-1));
1003 p->drawRect(IntRect(x2-third, y1+1, third, y2-y1-1));
1006 p->drawRect(IntRect(x1 , y1+1, third, y2-y1-1));
1007 p->drawRect(IntRect(x2-third, y1+1, third, y2-y1-1));
1015 adjbw1bigthird = adjbw1+1;
1017 adjbw1bigthird = adjbw1 - 1;
1018 adjbw1bigthird /= 3;
1022 adjbw2bigthird = adjbw2 + 1;
1024 adjbw2bigthird = adjbw2 - 1;
1025 adjbw2bigthird /= 3;
1030 drawBorder(p, x1+max((-adjbw1*2+1)/3,0), y1 , x2-max((-adjbw2*2+1)/3,0), y1 + third, s, c, textcolor, SOLID, adjbw1bigthird, adjbw2bigthird);
1031 drawBorder(p, x1+max(( adjbw1*2+1)/3,0), y2 - third, x2-max(( adjbw2*2+1)/3,0), y2 , s, c, textcolor, SOLID, adjbw1bigthird, adjbw2bigthird);
1034 drawBorder(p, x1 , y1+max((-adjbw1*2+1)/3,0), x1+third, y2-max((-adjbw2*2+1)/3,0), s, c, textcolor, SOLID, adjbw1bigthird, adjbw2bigthird);
1035 drawBorder(p, x2 - third, y1+max(( adjbw1*2+1)/3,0), x2 , y2-max(( adjbw2*2+1)/3,0), s, c, textcolor, SOLID, adjbw1bigthird, adjbw2bigthird);
1038 drawBorder(p, x1+max(( adjbw1*2+1)/3,0), y1 , x2-max(( adjbw2*2+1)/3,0), y1+third, s, c, textcolor, SOLID, adjbw1bigthird, adjbw2bigthird);
1039 drawBorder(p, x1+max((-adjbw1*2+1)/3,0), y2-third, x2-max((-adjbw2*2+1)/3,0), y2 , s, c, textcolor, SOLID, adjbw1bigthird, adjbw2bigthird);
1042 drawBorder(p, x1 , y1+max(( adjbw1*2+1)/3,0), x1+third, y2-max(( adjbw2*2+1)/3,0), s, c, textcolor, SOLID, adjbw1bigthird, adjbw2bigthird);
1043 drawBorder(p, x2-third, y1+max((-adjbw1*2+1)/3,0), x2 , y2-max((-adjbw2*2+1)/3,0), s, c, textcolor, SOLID, adjbw1bigthird, adjbw2bigthird);
1069 if (adjbw1>0) adjbw1bighalf=adjbw1+1;
1070 else adjbw1bighalf=adjbw1-1;
1073 if (adjbw2>0) adjbw2bighalf=adjbw2+1;
1074 else adjbw2bighalf=adjbw2-1;
1080 drawBorder(p, x1+max(-adjbw1 ,0)/2, y1 , x2-max(-adjbw2,0)/2, (y1+y2+1)/2, s, c, textcolor, s1, adjbw1bighalf, adjbw2bighalf);
1081 drawBorder(p, x1+max( adjbw1+1,0)/2, (y1+y2+1)/2, x2-max( adjbw2+1,0)/2, y2 , s, c, textcolor, s2, adjbw1/2, adjbw2/2);
1084 drawBorder(p, x1 , y1+max(-adjbw1 ,0)/2, (x1+x2+1)/2, y2-max(-adjbw2,0)/2, s, c, textcolor, s1, adjbw1bighalf, adjbw2bighalf);
1085 drawBorder(p, (x1+x2+1)/2, y1+max( adjbw1+1,0)/2, x2 , y2-max( adjbw2+1,0)/2, s, c, textcolor, s2, adjbw1/2, adjbw2/2);
1088 drawBorder(p, x1+max( adjbw1 ,0)/2, y1 , x2-max( adjbw2,0)/2, (y1+y2+1)/2, s, c, textcolor, s2, adjbw1bighalf, adjbw2bighalf);
1089 drawBorder(p, x1+max(-adjbw1+1,0)/2, (y1+y2+1)/2, x2-max(-adjbw2+1,0)/2, y2 , s, c, textcolor, s1, adjbw1/2, adjbw2/2);
1092 drawBorder(p, x1 , y1+max( adjbw1 ,0)/2, (x1+x2+1)/2, y2-max( adjbw2,0)/2, s, c, textcolor, s2, adjbw1bighalf, adjbw2bighalf);
1093 drawBorder(p, (x1+x2+1)/2, y1+max(-adjbw1+1,0)/2, x2 , y2-max(-adjbw2+1,0)/2, s, c, textcolor, s1, adjbw1/2, adjbw2/2);
1099 if (s == BSTop || s == BSLeft)
1103 if (style == OUTSET && (s == BSBottom || s == BSRight))
1108 p->setPen(Pen::NoPen);
1112 if (!adjbw1 && !adjbw2) {
1113 p->drawRect(IntRect(x1, y1, x2 - x1, y2 - y1));
1119 quad[0] = FloatPoint(x1 + max(-adjbw1, 0), y1);
1120 quad[1] = FloatPoint(x1 + max( adjbw1, 0), y2);
1121 quad[2] = FloatPoint(x2 - max( adjbw2, 0), y2);
1122 quad[3] = FloatPoint(x2 - max(-adjbw2, 0), y1);
1125 quad[0] = FloatPoint(x1 + max( adjbw1, 0), y1);
1126 quad[1] = FloatPoint(x1 + max(-adjbw1, 0), y2);
1127 quad[2] = FloatPoint(x2 - max(-adjbw2, 0), y2);
1128 quad[3] = FloatPoint(x2 - max( adjbw2, 0), y1);
1131 quad[0] = FloatPoint(x1, y1 + max(-adjbw1, 0));
1132 quad[1] = FloatPoint(x1, y2 - max(-adjbw2, 0));
1133 quad[2] = FloatPoint(x2, y2 - max( adjbw2, 0));
1134 quad[3] = FloatPoint(x2, y1 + max( adjbw1, 0));
1137 quad[0] = FloatPoint(x1, y1 + max( adjbw1, 0));
1138 quad[1] = FloatPoint(x1, y2 - max( adjbw2, 0));
1139 quad[2] = FloatPoint(x2, y2 - max(-adjbw2, 0));
1140 quad[3] = FloatPoint(x2, y1 + max(-adjbw1, 0));
1143 p->drawConvexPolygon(4, quad);
1149 bool RenderObject::paintBorderImage(GraphicsContext* p, int _tx, int _ty, int w, int h, const RenderStyle* style)
1151 CachedImage* borderImage = style->borderImage().image();
1152 if (!borderImage->isLoaded())
1153 return true; // Never paint a border image incrementally, but don't paint the fallback borders either.
1155 // If we have a border radius, the border image gets clipped to the rounded rect.
1156 bool clipped = false;
1157 if (style->hasBorderRadius()) {
1158 IntRect clipRect(_tx, _ty, w, h);
1160 p->addRoundedRectClip(clipRect,
1161 style->borderTopLeftRadius(), style->borderTopRightRadius(),
1162 style->borderBottomLeftRadius(), style->borderBottomRightRadius());
1166 int imageWidth = borderImage->image()->width();
1167 int imageHeight = borderImage->image()->height();
1169 int topSlice = min(imageHeight, style->borderImage().m_slices.top.calcValue(borderImage->image()->height()));
1170 int bottomSlice = min(imageHeight, style->borderImage().m_slices.bottom.calcValue(borderImage->image()->height()));
1171 int leftSlice = min(imageWidth, style->borderImage().m_slices.left.calcValue(borderImage->image()->width()));
1172 int rightSlice = min(imageWidth, style->borderImage().m_slices.right.calcValue(borderImage->image()->width()));
1174 EBorderImageRule hRule = style->borderImage().horizontalRule();
1175 EBorderImageRule vRule = style->borderImage().verticalRule();
1177 bool drawLeft = leftSlice > 0 && style->borderLeftWidth() > 0;
1178 bool drawTop = topSlice > 0 && style->borderTopWidth() > 0;
1179 bool drawRight = rightSlice > 0 && style->borderRightWidth() > 0;
1180 bool drawBottom = bottomSlice > 0 && style->borderBottomWidth() > 0;
1181 bool drawMiddle = (imageWidth - leftSlice - rightSlice) > 0 && (w - style->borderLeftWidth() - style->borderRightWidth()) > 0 &&
1182 (imageHeight - topSlice - bottomSlice) > 0 && (h - style->borderTopWidth() - style->borderBottomWidth()) > 0;
1185 // Paint the top and bottom left corners.
1187 // The top left corner rect is (_tx, _ty, leftWidth, topWidth)
1188 // The rect to use from within the image is obtained from our slice, and is (0, 0, leftSlice, topSlice)
1190 p->drawImage(borderImage->image(), IntRect(_tx, _ty, style->borderLeftWidth(), style->borderTopWidth()),
1191 IntRect(0, 0, leftSlice, topSlice));
1193 // The bottom left corner rect is (_tx, _ty + h - bottomWidth, leftWidth, bottomWidth)
1194 // The rect to use from within the image is (0, imageHeight - bottomSlice, leftSlice, botomSlice)
1196 p->drawImage(borderImage->image(), IntRect(_tx, _ty + h - style->borderBottomWidth(), style->borderLeftWidth(), style->borderBottomWidth()),
1197 IntRect(0, imageHeight - bottomSlice, leftSlice, bottomSlice));
1199 // Paint the left edge.
1200 // Have to scale and tile into the border rect.
1201 p->drawTiledImage(borderImage->image(), IntRect(_tx, _ty + style->borderTopWidth(), style->borderLeftWidth(),
1202 h - style->borderTopWidth() - style->borderBottomWidth()),
1203 IntRect(0, topSlice, leftSlice, imageHeight - topSlice - bottomSlice),
1204 Image::StretchTile, (Image::TileRule)vRule);
1208 // Paint the top and bottom right corners
1209 // The top right corner rect is (_tx + w - rightWidth, _ty, rightWidth, topWidth)
1210 // The rect to use from within the image is obtained from our slice, and is (imageWidth - rightSlice, 0, rightSlice, topSlice)
1212 p->drawImage(borderImage->image(), IntRect(_tx + w - style->borderRightWidth(), _ty, style->borderRightWidth(), style->borderTopWidth()),
1213 IntRect(imageWidth - rightSlice, 0, rightSlice, topSlice));
1215 // The bottom right corner rect is (_tx + w - rightWidth, _ty + h - bottomWidth, rightWidth, bottomWidth)
1216 // The rect to use from within the image is (imageWidth - rightSlice, imageHeight - bottomSlice, rightSlice, botomSlice)
1218 p->drawImage(borderImage->image(), IntRect(_tx + w - style->borderRightWidth(), _ty + h - style->borderBottomWidth(), style->borderRightWidth(), style->borderBottomWidth()),
1219 IntRect(imageWidth - rightSlice, imageHeight - bottomSlice, rightSlice, bottomSlice));
1221 // Paint the right edge.
1222 p->drawTiledImage(borderImage->image(), IntRect(_tx + w - style->borderRightWidth(), _ty + style->borderTopWidth(), style->borderRightWidth(),
1223 h - style->borderTopWidth() - style->borderBottomWidth()),
1224 IntRect(imageWidth - rightSlice, topSlice, rightSlice, imageHeight - topSlice - bottomSlice),
1225 Image::StretchTile, (Image::TileRule)vRule);
1228 // Paint the top edge.
1230 p->drawTiledImage(borderImage->image(), IntRect(_tx + style->borderLeftWidth(), _ty, w - style->borderLeftWidth() - style->borderRightWidth(), style->borderTopWidth()),
1231 IntRect(leftSlice, 0, imageWidth - rightSlice - leftSlice, topSlice),
1232 (Image::TileRule)hRule, Image::StretchTile);
1234 // Paint the bottom edge.
1236 p->drawTiledImage(borderImage->image(), IntRect(_tx + style->borderLeftWidth(), _ty + h - style->borderBottomWidth(),
1237 w - style->borderLeftWidth() - style->borderRightWidth(), style->borderBottomWidth()),
1238 IntRect(leftSlice, imageHeight - bottomSlice, imageWidth - rightSlice - leftSlice, bottomSlice),
1239 (Image::TileRule)hRule, Image::StretchTile);
1241 // Paint the middle.
1243 p->drawTiledImage(borderImage->image(), IntRect(_tx + style->borderLeftWidth(), _ty + style->borderTopWidth(), w - style->borderLeftWidth() - style->borderRightWidth(),
1244 h - style->borderTopWidth() - style->borderBottomWidth()),
1245 IntRect(leftSlice, topSlice, imageWidth - rightSlice - leftSlice, imageHeight - topSlice - bottomSlice),
1246 (Image::TileRule)hRule, (Image::TileRule)vRule);
1248 // Clear the clip for the border radius.
1255 void RenderObject::paintBorder(GraphicsContext* p, int _tx, int _ty, int w, int h, const RenderStyle* style, bool begin, bool end)
1257 CachedImage* borderImage = style->borderImage().image();
1258 bool shouldPaintBackgroundImage = borderImage && borderImage->canRender();
1259 if (shouldPaintBackgroundImage)
1260 shouldPaintBackgroundImage = paintBorderImage(p, _tx, _ty, w, h, style);
1262 if (shouldPaintBackgroundImage)
1265 const Color& tc = style->borderTopColor();
1266 const Color& bc = style->borderBottomColor();
1267 const Color& lc = style->borderLeftColor();
1268 const Color& rc = style->borderRightColor();
1270 bool tt = style->borderTopIsTransparent();
1271 bool bt = style->borderBottomIsTransparent();
1272 bool rt = style->borderRightIsTransparent();
1273 bool lt = style->borderLeftIsTransparent();
1275 EBorderStyle ts = style->borderTopStyle();
1276 EBorderStyle bs = style->borderBottomStyle();
1277 EBorderStyle ls = style->borderLeftStyle();
1278 EBorderStyle rs = style->borderRightStyle();
1280 bool renderTop = ts > BHIDDEN && !tt;
1281 bool renderLeft = ls > BHIDDEN && begin && !lt;
1282 bool renderRight = rs > BHIDDEN && end && !rt;
1283 bool renderBottom = bs > BHIDDEN && !bt;
1285 // Need sufficient width and height to contain border radius curves. Sanity check our top/bottom
1286 // values and our width/height values to make sure the curves can all fit. If not, then we won't paint
1287 // any border radii.
1288 bool renderRadii = false;
1289 IntSize topLeft = style->borderTopLeftRadius();
1290 IntSize topRight = style->borderTopRightRadius();
1291 IntSize bottomLeft = style->borderBottomLeftRadius();
1292 IntSize bottomRight = style->borderBottomRightRadius();
1294 if (style->hasBorderRadius()) {
1295 int requiredWidth = max(topLeft.width() + topRight.width(), bottomLeft.width() + bottomRight.width());
1296 int requiredHeight = max(topLeft.height() + bottomLeft.height(), topRight.height() + bottomRight.height());
1297 renderRadii = (requiredWidth <= w && requiredHeight <= h);
1300 // Clip to the rounded rectangle.
1303 p->addRoundedRectClip(IntRect(_tx, _ty, w, h), topLeft, topRight, bottomLeft, bottomRight);
1306 int firstAngleStart, secondAngleStart, firstAngleSpan, secondAngleSpan;
1308 bool upperLeftBorderStylesMatch = renderLeft && (ts == ls) && (tc == lc) && (ts != INSET) && (ts != GROOVE);
1309 bool upperRightBorderStylesMatch = renderRight && (ts == rs) && (tc == rc) && (ts != OUTSET) && (ts != RIDGE);
1310 bool lowerLeftBorderStylesMatch = renderLeft && (bs == ls) && (bc == lc) && (bs != OUTSET) && (bs != RIDGE);
1311 bool lowerRightBorderStylesMatch = renderRight && (bs == rs) && (bc == rc) && (bs != INSET) && (bs != GROOVE);
1314 bool ignore_left = (renderRadii && topLeft.width() > 0) ||
1315 ((tc == lc) && (tt == lt) &&
1317 (ls == DOTTED || ls == DASHED || ls == SOLID || ls == OUTSET));
1319 bool ignore_right = (renderRadii && topRight.width() > 0) ||
1320 ((tc == rc) && (tt == rt) &&
1322 (rs == DOTTED || rs == DASHED || rs == SOLID || rs == INSET));
1327 x += topLeft.width();
1328 x2 -= topRight.width();
1331 drawBorder(p, x, _ty, x2, _ty + style->borderTopWidth(), BSTop, tc, style->color(), ts,
1332 ignore_left ? 0 : style->borderLeftWidth(),
1333 ignore_right? 0 : style->borderRightWidth());
1338 int rightX = _tx + w - topRight.width() * 2;
1339 firstAngleStart = 90;
1340 firstAngleSpan = upperLeftBorderStylesMatch ? 90 : 45;
1342 // We make the arc double thick and let the clip rect take care of clipping the extra off.
1343 // We're doing this because it doesn't seem possible to match the curve of the clip exactly
1344 // with the arc-drawing function.
1345 thickness = style->borderTopWidth() * 2;
1347 if (upperRightBorderStylesMatch) {
1348 secondAngleStart = 0;
1349 secondAngleSpan = 90;
1351 secondAngleStart = 45;
1352 secondAngleSpan = 45;
1355 // The inner clip clips inside the arc. This is especially important for 1px borders.
1356 bool applyLeftInnerClip = (style->borderLeftWidth() < topLeft.width())
1357 && (style->borderTopWidth() < topLeft.height())
1358 && (ts != DOUBLE || style->borderTopWidth() > 6);
1359 if (applyLeftInnerClip) {
1361 p->addInnerRoundedRectClip(IntRect(leftX, leftY, topLeft.width() * 2, topLeft.height() * 2),
1362 style->borderTopWidth());
1365 // Draw upper left arc
1366 drawBorderArc(p, leftX, leftY, thickness, topLeft, firstAngleStart, firstAngleSpan,
1367 BSTop, tc, style->color(), ts, true);
1368 if (applyLeftInnerClip)
1371 bool applyRightInnerClip = (style->borderRightWidth() < topRight.width())
1372 && (style->borderTopWidth() < topRight.height())
1373 && (ts != DOUBLE || style->borderTopWidth() > 6);
1374 if (applyRightInnerClip) {
1376 p->addInnerRoundedRectClip(IntRect(rightX, leftY, topRight.width() * 2, topRight.height() * 2),
1377 style->borderTopWidth());
1380 // Draw upper right arc
1381 drawBorderArc(p, rightX, leftY, thickness, topRight, secondAngleStart, secondAngleSpan,
1382 BSTop, tc, style->color(), ts, false);
1383 if (applyRightInnerClip)
1389 bool ignore_left = (renderRadii && bottomLeft.width() > 0) ||
1390 ((bc == lc) && (bt == lt) &&
1392 (ls == DOTTED || ls == DASHED || ls == SOLID || ls == OUTSET));
1394 bool ignore_right = (renderRadii && bottomRight.width() > 0) ||
1395 ((bc == rc) && (bt == rt) &&
1397 (rs == DOTTED || rs == DASHED || rs == SOLID || rs == INSET));
1402 x += bottomLeft.width();
1403 x2 -= bottomRight.width();
1406 drawBorder(p, x, _ty + h - style->borderBottomWidth(), x2, _ty + h, BSBottom, bc, style->color(), bs,
1407 ignore_left ? 0 :style->borderLeftWidth(),
1408 ignore_right? 0 :style->borderRightWidth());
1412 int leftY = _ty + h - bottomLeft.height() * 2;
1413 int rightX = _tx + w - bottomRight.width() * 2;
1414 secondAngleStart = 270;
1415 secondAngleSpan = upperRightBorderStylesMatch ? 90 : 45;
1416 thickness = style->borderBottomWidth() * 2;
1418 if (upperLeftBorderStylesMatch) {
1419 firstAngleStart = 180;
1420 firstAngleSpan = 90;
1422 firstAngleStart = 225;
1423 firstAngleSpan = 45;
1426 bool applyLeftInnerClip = (style->borderLeftWidth() < bottomLeft.width())
1427 && (style->borderBottomWidth() < bottomLeft.height())
1428 && (bs != DOUBLE || style->borderBottomWidth() > 6);
1429 if (applyLeftInnerClip) {
1431 p->addInnerRoundedRectClip(IntRect(leftX, leftY, bottomLeft.width() * 2, bottomLeft.height() * 2),
1432 style->borderBottomWidth());
1435 // Draw lower left arc
1436 drawBorderArc(p, leftX, leftY, thickness, bottomLeft, firstAngleStart, firstAngleSpan,
1437 BSBottom, bc, style->color(), bs, true);
1438 if (applyLeftInnerClip)
1441 bool applyRightInnerClip = (style->borderRightWidth() < bottomRight.width())
1442 && (style->borderBottomWidth() < bottomRight.height())
1443 && (bs != DOUBLE || style->borderBottomWidth() > 6);
1444 if (applyRightInnerClip) {
1446 p->addInnerRoundedRectClip(IntRect(rightX, leftY, bottomRight.width() * 2, bottomRight.height() * 2),
1447 style->borderBottomWidth());
1450 // Draw lower right arc
1451 drawBorderArc(p, rightX, leftY, thickness, bottomRight, secondAngleStart, secondAngleSpan,
1452 BSBottom, bc, style->color(), bs, false);
1453 if (applyRightInnerClip)
1459 bool ignore_top = (renderRadii && topLeft.height() > 0) ||
1460 ((tc == lc) && (tt == lt) &&
1462 (ts == DOTTED || ts == DASHED || ts == SOLID || ts == OUTSET));
1464 bool ignore_bottom = (renderRadii && bottomLeft.height() > 0) ||
1465 ((bc == lc) && (bt == lt) &&
1467 (bs == DOTTED || bs == DASHED || bs == SOLID || bs == INSET));
1472 y += topLeft.height();
1473 y2 -= bottomLeft.height();
1476 drawBorder(p, _tx, y, _tx + style->borderLeftWidth(), y2, BSLeft, lc, style->color(), ls,
1477 ignore_top?0:style->borderTopWidth(),
1478 ignore_bottom?0:style->borderBottomWidth());
1480 if (renderRadii && (!upperLeftBorderStylesMatch || !lowerLeftBorderStylesMatch)) {
1483 int bottomY = _ty + h - bottomLeft.height() * 2;
1484 firstAngleStart = 135;
1485 secondAngleStart = 180;
1486 firstAngleSpan = secondAngleSpan = 45;
1487 thickness = style->borderLeftWidth() * 2;
1489 bool applyTopInnerClip = (style->borderLeftWidth() < topLeft.width())
1490 && (style->borderTopWidth() < topLeft.height())
1491 && (ls != DOUBLE || style->borderLeftWidth() > 6);
1492 if (applyTopInnerClip) {
1494 p->addInnerRoundedRectClip(IntRect(topX, topY, topLeft.width() * 2, topLeft.height() * 2),
1495 style->borderLeftWidth());
1498 // Draw top left arc
1499 drawBorderArc(p, topX, topY, thickness, topLeft, firstAngleStart, firstAngleSpan,
1500 BSLeft, lc, style->color(), ls, true);
1501 if (applyTopInnerClip)
1504 bool applyBottomInnerClip = (style->borderLeftWidth() < bottomLeft.width())
1505 && (style->borderBottomWidth() < bottomLeft.height())
1506 && (ls != DOUBLE || style->borderLeftWidth() > 6);
1507 if (applyBottomInnerClip) {
1509 p->addInnerRoundedRectClip(IntRect(topX, bottomY, bottomLeft.width() * 2, bottomLeft.height() * 2),
1510 style->borderLeftWidth());
1513 // Draw bottom left arc
1514 drawBorderArc(p, topX, bottomY, thickness, bottomLeft, secondAngleStart, secondAngleSpan,
1515 BSLeft, lc, style->color(), ls, false);
1516 if (applyBottomInnerClip)
1522 bool ignore_top = (renderRadii && topRight.height() > 0) ||
1523 ((tc == rc) && (tt == rt) &&
1524 (rs >= DOTTED || rs == INSET) &&
1525 (ts == DOTTED || ts == DASHED || ts == SOLID || ts == OUTSET));
1527 bool ignore_bottom = (renderRadii && bottomRight.height() > 0) ||
1528 ((bc == rc) && (bt == rt) &&
1529 (rs >= DOTTED || rs == INSET) &&
1530 (bs == DOTTED || bs == DASHED || bs == SOLID || bs == INSET));
1535 y += topRight.height();
1536 y2 -= bottomRight.height();
1539 drawBorder(p, _tx + w - style->borderRightWidth(), y, _tx + w, y2, BSRight, rc, style->color(), rs,
1540 ignore_top?0:style->borderTopWidth(),
1541 ignore_bottom?0:style->borderBottomWidth());
1543 if (renderRadii && (!upperRightBorderStylesMatch || !lowerRightBorderStylesMatch)) {
1544 int topX = _tx + w - topRight.width() * 2;
1546 int bottomY = _ty + h - bottomRight.height() * 2;
1547 firstAngleStart = 0;
1548 secondAngleStart = 315;
1549 firstAngleSpan = secondAngleSpan = 45;
1550 thickness = style->borderRightWidth() * 2;
1552 bool applyTopInnerClip = (style->borderRightWidth() < topRight.width())
1553 && (style->borderTopWidth() < topRight.height())
1554 && (rs != DOUBLE || style->borderRightWidth() > 6);
1555 if (applyTopInnerClip) {
1557 p->addInnerRoundedRectClip(IntRect(topX, topY, topRight.width() * 2, topRight.height() * 2),
1558 style->borderRightWidth());
1561 // Draw top right arc
1562 drawBorderArc(p, topX, topY, thickness, topRight, firstAngleStart, firstAngleSpan,
1563 BSRight, rc, style->color(), rs, true);
1564 if (applyTopInnerClip)
1567 bool applyBottomInnerClip = (style->borderRightWidth() < bottomRight.width())
1568 && (style->borderBottomWidth() < bottomRight.height())
1569 && (rs != DOUBLE || style->borderRightWidth() > 6);
1570 if (applyBottomInnerClip) {
1572 p->addInnerRoundedRectClip(IntRect(topX, bottomY, bottomRight.width() * 2, bottomRight.height() * 2),
1573 style->borderRightWidth());
1576 // Draw bottom right arc
1577 drawBorderArc(p, topX, bottomY, thickness, bottomRight, secondAngleStart, secondAngleSpan,
1578 BSRight, rc, style->color(), rs, false);
1579 if (applyBottomInnerClip)
1585 p->restore(); // Undo the clip.
1588 void RenderObject::lineBoxRects(Vector<IntRect>&)
1592 void RenderObject::absoluteRects(Vector<IntRect>& rects, int tx, int ty)
1594 // For blocks inside inlines, we go ahead and include margins so that we run right up to the
1595 // inline boxes above and below us (thus getting merged with them to form a single irregular
1597 if (continuation()) {
1598 rects.append(IntRect(tx, ty - collapsedMarginTop(),
1599 width(), height()+collapsedMarginTop()+collapsedMarginBottom()));
1600 continuation()->absoluteRects(rects,
1601 tx - xPos() + continuation()->containingBlock()->xPos(),
1602 ty - yPos() + continuation()->containingBlock()->yPos());
1605 rects.append(IntRect(tx, ty, width(), height() + borderTopExtra() + borderBottomExtra()));
1608 IntRect RenderObject::absoluteBoundingBoxRect()
1611 absolutePosition(x, y);
1612 Vector<IntRect> rects;
1613 absoluteRects(rects, x, y);
1615 size_t n = rects.size();
1619 IntRect result = rects[0];
1620 for (size_t i = 1; i < n; ++i)
1621 result.unite(rects[i]);
1625 void RenderObject::addAbsoluteRectForLayer(IntRect& result)
1628 result.unite(absoluteBoundingBoxRect());
1629 for (RenderObject* current = firstChild(); current; current = current->nextSibling())
1630 current->addAbsoluteRectForLayer(result);
1633 IntRect RenderObject::paintingRootRect(IntRect& topLevelRect)
1635 IntRect result = absoluteBoundingBoxRect();
1636 topLevelRect = result;
1637 for (RenderObject* current = firstChild(); current; current = current->nextSibling())
1638 current->addAbsoluteRectForLayer(result);
1642 void RenderObject::addFocusRingRects(GraphicsContext* p, int _tx, int _ty)
1644 // For blocks inside inlines, we go ahead and include margins so that we run right up to the
1645 // inline boxes above and below us (thus getting merged with them to form a single irregular
1647 if (continuation()) {
1648 p->addFocusRingRect(IntRect(_tx, _ty - collapsedMarginTop(), width(), height()+collapsedMarginTop()+collapsedMarginBottom()));
1649 continuation()->addFocusRingRects(p,
1650 _tx - xPos() + continuation()->containingBlock()->xPos(),
1651 _ty - yPos() + continuation()->containingBlock()->yPos());
1654 p->addFocusRingRect(IntRect(_tx, _ty, width(), height()));
1657 void RenderObject::paintOutline(GraphicsContext* p, int _tx, int _ty, int w, int h, const RenderStyle* style)
1659 int ow = style->outlineWidth();
1662 EBorderStyle os = style->outlineStyle();
1666 Color oc = style->outlineColor();
1668 oc = style->color();
1670 int offset = style->outlineOffset();
1672 if (style->outlineStyleIsAuto()) {
1673 if (!theme()->supportsFocusRing(style)) {
1674 // Only paint the focus ring by hand if the theme isn't able to draw the focus ring.
1675 p->initFocusRing(ow, offset);
1676 addFocusRingRects(p, _tx, _ty);
1677 p->drawFocusRing(oc);
1678 p->clearFocusRing();
1688 drawBorder(p, _tx-ow, _ty-ow, _tx, _ty+h+ow, BSLeft,
1689 Color(oc), style->color(),
1692 drawBorder(p, _tx-ow, _ty-ow, _tx+w+ow, _ty, BSTop,
1693 Color(oc), style->color(),
1696 drawBorder(p, _tx+w, _ty-ow, _tx+w+ow, _ty+h+ow, BSRight,
1697 Color(oc), style->color(),
1700 drawBorder(p, _tx-ow, _ty+h, _tx+w+ow, _ty+h+ow, BSBottom,
1701 Color(oc), style->color(),
1706 void RenderObject::paint(PaintInfo& i, int tx, int ty)
1710 void RenderObject::repaint(bool immediate)
1712 // Can't use view(), since we might be unrooted.
1713 RenderObject* o = this;
1714 while ( o->parent() ) o = o->parent();
1715 if (!o->isRenderView())
1717 RenderView* c = static_cast<RenderView*>(o);
1718 if (c->printingMode())
1719 return; // Don't repaint if we're printing.
1720 c->repaintViewRectangle(getAbsoluteRepaintRect(), immediate);
1723 void RenderObject::repaintRectangle(const IntRect& r, bool immediate)
1725 // Can't use view(), since we might be unrooted.
1726 RenderObject* o = this;
1727 while ( o->parent() ) o = o->parent();
1728 if (!o->isRenderView())
1730 RenderView* c = static_cast<RenderView*>(o);
1731 if (c->printingMode())
1732 return; // Don't repaint if we're printing.
1734 computeAbsoluteRepaintRect(absRect);
1735 c->repaintViewRectangle(absRect, immediate);
1738 bool RenderObject::repaintAfterLayoutIfNeeded(const IntRect& oldBounds, const IntRect& oldFullBounds)
1740 RenderView* c = view();
1741 if (c->printingMode())
1742 return false; // Don't repaint if we're printing.
1744 IntRect newBounds, newFullBounds;
1745 getAbsoluteRepaintRectIncludingFloats(newBounds, newFullBounds);
1746 if (newBounds == oldBounds && !selfNeedsLayout())
1749 bool fullRepaint = selfNeedsLayout() || newBounds.location() != oldBounds.location() || mustRepaintBackgroundOrBorder();
1751 c->repaintViewRectangle(oldFullBounds);
1752 if (newBounds != oldBounds)
1753 c->repaintViewRectangle(newFullBounds);
1757 // We didn't move, but we did change size. Invalidate the delta, which will consist of possibly
1758 // two rectangles (but typically only one).
1759 int ow = style() ? style()->outlineSize() : 0;
1760 int width = abs(newBounds.width() - oldBounds.width());
1762 c->repaintViewRectangle(IntRect(min(newBounds.x() + newBounds.width(), oldBounds.x() + oldBounds.width()) - borderRight() - ow,
1764 width + borderRight() + ow,
1765 max(newBounds.height(), oldBounds.height())));
1766 int height = abs(newBounds.height() - oldBounds.height());
1768 c->repaintViewRectangle(IntRect(newBounds.x(),
1769 min(newBounds.bottom(), oldBounds.bottom()) - borderBottom() - ow,
1770 max(newBounds.width(), oldBounds.width()),
1771 height + borderBottom() + ow));
1775 void RenderObject::repaintDuringLayoutIfMoved(int x, int y)
1779 void RenderObject::repaintOverhangingFloats(bool paintAllDescendants)
1783 bool RenderObject::checkForRepaintDuringLayout() const
1785 return !document()->view()->needsFullRepaint() && !layer();
1788 void RenderObject::repaintObjectsBeforeLayout()
1790 if (!needsLayout() || isText())
1793 bool blockWithInlineChildren = (isRenderBlock() && !isTable() && normalChildNeedsLayout() && childrenInline());
1794 if (selfNeedsLayout()) {
1796 if (blockWithInlineChildren)
1800 for (RenderObject* current = firstChild(); current; current = current->nextSibling()) {
1801 if (!current->isPositioned()) // RenderBlock subclass method handles walking the positioned objects.
1802 current->repaintObjectsBeforeLayout();
1806 IntRect RenderObject::getAbsoluteRepaintRectWithOutline(int ow)
1808 IntRect r(getAbsoluteRepaintRect());
1811 if (continuation() && !isInline())
1812 r.inflateY(collapsedMarginTop());
1815 for (RenderObject* curr = firstChild(); curr; curr = curr->nextSibling())
1816 if (!curr->isText())
1817 r.unite(curr->getAbsoluteRepaintRectWithOutline(ow));
1822 IntRect RenderObject::getAbsoluteRepaintRect()
1825 return parent()->getAbsoluteRepaintRect();
1829 void RenderObject::getAbsoluteRepaintRectIncludingFloats(IntRect& bounds, IntRect& fullBounds)
1831 bounds = fullBounds = getAbsoluteRepaintRect();
1834 void RenderObject::computeAbsoluteRepaintRect(IntRect& r, bool f)
1837 return parent()->computeAbsoluteRepaintRect(r, f);
1840 void RenderObject::dirtyLinesFromChangedChild(RenderObject* child)
1846 DeprecatedString RenderObject::information() const
1848 DeprecatedString str;
1849 TextStream ts(&str);
1851 << "(" << (style() ? style()->refCount() : 0) << ")"
1852 << ": " << (void*)this << " ";
1853 if (isInline()) ts << "il ";
1854 if (childrenInline()) ts << "ci ";
1855 if (isFloating()) ts << "fl ";
1856 if (isAnonymous()) ts << "an ";
1857 if (isRelPositioned()) ts << "rp ";
1858 if (isPositioned()) ts << "ps ";
1859 if (needsLayout()) ts << "nl ";
1860 if (m_recalcMinMax) ts << "rmm ";
1861 if (style() && style()->zIndex()) ts << "zI: " << style()->zIndex();
1863 if (element()->active())
1865 if (element()->isLink())
1867 if (element()->focused())
1869 ts << " <" << element()->localName().deprecatedString() << ">";
1870 ts << " (" << xPos() << "," << yPos() << "," << width() << "," << height() << ")";
1871 if (isTableCell()) {
1872 const RenderTableCell* cell = static_cast<const RenderTableCell *>(this);
1873 ts << " [r=" << cell->row() << " c=" << cell->col() << " rs=" << cell->rowSpan() << " cs=" << cell->colSpan() << "]";
1879 void RenderObject::dump(TextStream *stream, DeprecatedString ind) const
1881 if (isAnonymous()) { *stream << " anonymous"; }
1882 if (isFloating()) { *stream << " floating"; }
1883 if (isPositioned()) { *stream << " positioned"; }
1884 if (isRelPositioned()) { *stream << " relPositioned"; }
1885 if (isText()) { *stream << " text"; }
1886 if (isInline()) { *stream << " inline"; }
1887 if (isReplaced()) { *stream << " replaced"; }
1888 if (shouldPaintBackgroundOrBorder()) { *stream << " paintBackground"; }
1889 if (needsLayout()) { *stream << " needsLayout"; }
1890 if (minMaxKnown()) { *stream << " minMaxKnown"; }
1893 RenderObject *child = firstChild();
1896 *stream << ind << child->renderName() << ": ";
1897 child->dump(stream,ind+" ");
1898 child = child->nextSibling();
1902 void RenderObject::showTreeForThis() const
1905 element()->showTreeForThis();
1910 static Node *selectStartNode(const RenderObject *object)
1913 bool forcedOn = false;
1915 for (const RenderObject *curr = object; curr; curr = curr->parent()) {
1916 if (curr->style()->userSelect() == SELECT_TEXT)
1918 if (!forcedOn && curr->style()->userSelect() == SELECT_NONE)
1922 node = curr->element();
1925 // somewhere up the render tree there must be an element!
1931 bool RenderObject::canSelect() const
1933 return selectStartNode(this) != 0;
1936 bool RenderObject::shouldSelect() const
1938 if (Node *node = selectStartNode(this))
1939 return EventTargetNodeCast(node)->dispatchHTMLEvent(selectstartEvent, true, true);
1944 Color RenderObject::selectionBackgroundColor() const
1947 if (style()->userSelect() != SELECT_NONE) {
1948 RenderStyle* pseudoStyle = getPseudoStyle(RenderStyle::SELECTION);
1949 if (pseudoStyle && pseudoStyle->backgroundColor().isValid())
1950 color = pseudoStyle->backgroundColor().blendWithWhite();
1952 color = document()->frame()->isActive() ?
1953 theme()->activeSelectionBackgroundColor() :
1954 theme()->inactiveSelectionBackgroundColor();
1960 Color RenderObject::selectionForegroundColor() const
1963 if (style()->userSelect() != SELECT_NONE) {
1964 RenderStyle* pseudoStyle = getPseudoStyle(RenderStyle::SELECTION);
1966 color = pseudoStyle->color();
1968 color = document()->frame()->isActive() ?
1969 theme()->platformActiveSelectionForegroundColor() :
1970 theme()->platformInactiveSelectionForegroundColor();
1976 Node* RenderObject::draggableNode(bool dhtmlOK, bool uaOK, int x, int y, bool& dhtmlWillDrag) const
1978 if (!dhtmlOK && !uaOK)
1981 const RenderObject* curr = this;
1983 Node *elt = curr->element();
1984 if (elt && elt->nodeType() == Node::TEXT_NODE) {
1985 // Since there's no way for the author to address the -webkit-user-drag style for a text node,
1986 // we use our own judgement.
1987 if (uaOK && view()->frameView()->frame()->shouldDragAutoNode(curr->node(), IntPoint(x, y))) {
1988 dhtmlWillDrag = false;
1989 return curr->node();
1990 } else if (curr->shouldSelect()) {
1991 // In this case we have a click in the unselected portion of text. If this text is
1992 // selectable, we want to start the selection process instead of looking for a parent
1997 EUserDrag dragMode = curr->style()->userDrag();
1998 if (dhtmlOK && dragMode == DRAG_ELEMENT) {
1999 dhtmlWillDrag = true;
2000 return curr->node();
2001 } else if (uaOK && dragMode == DRAG_AUTO
2002 && view()->frameView()->frame()->shouldDragAutoNode(curr->node(), IntPoint(x, y)))
2004 dhtmlWillDrag = false;
2005 return curr->node();
2008 curr = curr->parent();
2013 void RenderObject::selectionStartEnd(int& spos, int& epos)
2015 view()->selectionStartEnd(spos, epos);
2018 RenderBlock* RenderObject::createAnonymousBlock()
2020 RenderStyle *newStyle = new (renderArena()) RenderStyle();
2021 newStyle->inheritFrom(m_style);
2022 newStyle->setDisplay(BLOCK);
2024 RenderBlock *newBox = new (renderArena()) RenderBlock(document() /* anonymous box */);
2025 newBox->setStyle(newStyle);
2029 void RenderObject::handleDynamicFloatPositionChange()
2031 // We have gone from not affecting the inline status of the parent flow to suddenly
2032 // having an impact. See if there is a mismatch between the parent flow's
2033 // childrenInline() state and our state.
2034 setInline(style()->isDisplayInlineType());
2035 if (isInline() != parent()->childrenInline()) {
2037 if (parent()->isRenderInline()) {
2038 // We have to split the parent flow.
2039 RenderInline* parentInline = static_cast<RenderInline*>(parent());
2040 RenderBlock* newBox = parentInline->createAnonymousBlock();
2042 RenderFlow* oldContinuation = parent()->continuation();
2043 parentInline->setContinuation(newBox);
2045 RenderObject* beforeChild = nextSibling();
2046 parent()->removeChildNode(this);
2047 parentInline->splitFlow(beforeChild, newBox, this, oldContinuation);
2049 else if (parent()->isRenderBlock())
2050 static_cast<RenderBlock*>(parent())->makeChildrenNonInline();
2053 // An anonymous block must be made to wrap this inline.
2054 RenderBlock* box = createAnonymousBlock();
2055 parent()->insertChildNode(box, this);
2056 box->appendChildNode(parent()->removeChildNode(this));
2061 void RenderObject::setStyle(RenderStyle *style)
2063 if (m_style == style)
2066 bool affectsParentBlock = false;
2067 RenderStyle::Diff d = RenderStyle::Equal;
2069 // If our z-index changes value or our visibility changes,
2070 // we need to dirty our stacking context's z-order list.
2073 if (m_style->visibility() != style->visibility() ||
2074 m_style->zIndex() != style->zIndex() ||
2075 m_style->hasAutoZIndex() != style->hasAutoZIndex())
2076 document()->setDashboardRegionsDirty(true);
2079 if ((m_style->hasAutoZIndex() != style->hasAutoZIndex() ||
2080 m_style->zIndex() != style->zIndex() ||
2081 m_style->visibility() != style->visibility()) && layer()) {
2082 layer()->stackingContext()->dirtyZOrderLists();
2083 if (m_style->hasAutoZIndex() != style->hasAutoZIndex() ||
2084 m_style->visibility() != style->visibility())
2085 layer()->dirtyZOrderLists();
2087 // keep layer hierarchy visibility bits up to date if visibility changes
2088 if (m_style->visibility() != style->visibility()) {
2089 RenderLayer* l = enclosingLayer();
2090 if (style->visibility() == VISIBLE && l)
2091 l->setHasVisibleContent(true);
2092 else if (l && l->hasVisibleContent() &&
2093 (this == l->renderer() || l->renderer()->style()->visibility() != VISIBLE))
2094 l->dirtyVisibleContentStatus();
2098 d = m_style->diff(style);
2100 // If we have no layer(), just treat a RepaintLayer hint as a normal Repaint.
2101 if (d == RenderStyle::RepaintLayer && !layer())
2102 d = RenderStyle::Repaint;
2104 // The background of the root element or the body element could propagate up to
2105 // the canvas. Just dirty the entire canvas when our style changes substantially.
2106 if (d >= RenderStyle::Repaint && element() &&
2107 (element()->hasTagName(htmlTag) || element()->hasTagName(bodyTag)))
2109 else if (m_parent && !isText()) {
2110 // Do a repaint with the old style first, e.g., for example if we go from
2111 // having an outline to not having an outline.
2112 if (d == RenderStyle::RepaintLayer) {
2113 layer()->repaintIncludingDescendants();
2114 if (!(m_style->clip() == style->clip()))
2115 layer()->clearClipRects();
2116 } else if (d == RenderStyle::Repaint || style->outlineSize() < m_style->outlineSize())
2120 // When a layout hint happens, we go ahead and do a repaint of the layer, since the layer could
2121 // end up being destroyed.
2122 if (d == RenderStyle::Layout && layer() &&
2123 (m_style->position() != style->position() ||
2124 m_style->zIndex() != style->zIndex() ||
2125 m_style->hasAutoZIndex() != style->hasAutoZIndex() ||
2126 !(m_style->clip() == style->clip()) ||
2127 m_style->hasClip() != style->hasClip() ||
2128 m_style->opacity() != style->opacity()))
2129 layer()->repaintIncludingDescendants();
2131 // When a layout hint happens and an object's position style changes, we have to do a layout
2132 // to dirty the render tree using the old position value now.
2133 if (d == RenderStyle::Layout && m_parent && m_style->position() != style->position()) {
2134 markContainingBlocksForLayout();
2135 if (m_style->position() == StaticPosition)
2137 if (isRenderBlock()) {
2138 if (style->position() == StaticPosition) {
2139 // Clear our positioned objects list. Our absolutely positioned descendants will be
2140 // inserted into our containing block's positioned objects list during layout.
2141 removePositionedObjects(0);
2142 } else if (m_style->position() == StaticPosition) {
2143 // Remove our absolutely positioned descendants from their current containing block.
2144 // They will be inserted into our positioned objects list during layout.
2145 RenderObject* cb = parent();
2146 while (cb && (cb->style()->position() == StaticPosition || (cb->isInline() && !cb->isReplaced())) && !cb->isRoot() && !cb->isRenderView()) {
2147 if (cb->style()->position() == RelativePosition && cb->isInline() && !cb->isReplaced()) {
2148 cb = cb->containingBlock();
2153 cb->removePositionedObjects(static_cast<RenderBlock*>(this));
2158 if (isFloating() && (m_style->floating() != style->floating()))
2159 // For changes in float styles, we need to conceivably remove ourselves
2160 // from the floating objects list.
2161 removeFromObjectLists();
2162 else if (isPositioned() && (style->position() != AbsolutePosition && style->position() != FixedPosition))
2163 // For changes in positioning styles, we need to conceivably remove ourselves
2164 // from the positioned objects list.
2165 removeFromObjectLists();
2167 affectsParentBlock = m_style && isFloatingOrPositioned() &&
2168 (!style->isFloating() && style->position() != AbsolutePosition && style->position() != FixedPosition)
2169 && parent() && (parent()->isBlockFlow() || parent()->isInlineFlow());
2171 // reset style flags
2173 m_positioned = false;
2174 m_relPositioned = false;
2175 m_paintBackground = false;
2176 m_hasOverflowClip = false;
2179 if (view()->frameView()) {
2180 // FIXME: A better solution would be to only invalidate the fixed regions when scrolling. It's overkill to
2181 // prevent the entire view from blitting on a scroll.
2182 bool oldStyleSlowScroll = style && (style->position() == FixedPosition || style->hasFixedBackgroundImage());
2183 bool newStyleSlowScroll = m_style && (m_style->position() == FixedPosition || m_style->hasFixedBackgroundImage());
2184 if (oldStyleSlowScroll != newStyleSlowScroll) {
2185 if (oldStyleSlowScroll)
2186 view()->frameView()->removeSlowRepaintObject();
2187 if (newStyleSlowScroll)
2188 view()->frameView()->addSlowRepaintObject();
2192 RenderStyle *oldStyle = m_style;
2195 updateBackgroundImages(oldStyle);
2201 oldStyle->deref(renderArena());
2203 setShouldPaintBackgroundOrBorder(m_style->hasBorder() || m_style->hasBackground() || m_style->hasAppearance());
2205 if (affectsParentBlock)
2206 handleDynamicFloatPositionChange();
2208 // No need to ever schedule repaints from a style change of a text run, since
2209 // we already did this for the parent of the text run.
2210 if (d == RenderStyle::Layout && m_parent)
2211 setNeedsLayoutAndMinMaxRecalc();
2212 else if (m_parent && !isText() && (d == RenderStyle::RepaintLayer || d == RenderStyle::Repaint))
2213 // Do a repaint with the new style now, e.g., for example if we go from
2214 // not having an outline to having an outline.
2218 void RenderObject::setStyleInternal(RenderStyle* st)
2223 m_style->deref(renderArena());
2229 void RenderObject::updateBackgroundImages(RenderStyle* oldStyle)
2231 // FIXME: This will be slow when a large number of images is used. Fix by using a dict.
2232 const BackgroundLayer* oldLayers = oldStyle ? oldStyle->backgroundLayers() : 0;
2233 const BackgroundLayer* newLayers = m_style ? m_style->backgroundLayers() : 0;
2234 for (const BackgroundLayer* currOld = oldLayers; currOld; currOld = currOld->next()) {
2235 if (currOld->backgroundImage() && (!newLayers || !newLayers->containsImage(currOld->backgroundImage())))
2236 currOld->backgroundImage()->deref(this);
2238 for (const BackgroundLayer* currNew = newLayers; currNew; currNew = currNew->next()) {
2239 if (currNew->backgroundImage() && (!oldLayers || !oldLayers->containsImage(currNew->backgroundImage())))
2240 currNew->backgroundImage()->ref(this);
2243 CachedImage* oldBorderImage = oldStyle ? oldStyle->borderImage().image() : 0;
2244 CachedImage* newBorderImage = m_style ? m_style->borderImage().image() : 0;
2245 if (oldBorderImage != newBorderImage) {
2247 oldBorderImage->deref(this);
2249 newBorderImage->ref(this);
2253 IntRect RenderObject::viewRect() const
2255 return view()->viewRect();
2258 bool RenderObject::absolutePosition(int &xPos, int &yPos, bool f)
2260 RenderObject* o = parent();
2262 o->absolutePosition(xPos, yPos, f);
2263 yPos += o->borderTopExtra();
2264 if (o->hasOverflowClip())
2265 o->layer()->subtractScrollOffset(xPos, yPos);
2275 IntRect RenderObject::caretRect(int offset, EAffinity affinity, int *extraWidthToEndOfLine)
2277 if (extraWidthToEndOfLine)
2278 *extraWidthToEndOfLine = 0;
2283 int RenderObject::paddingTop() const
2286 Length padding = m_style->paddingTop();
2287 if (padding.isPercent())
2288 w = containingBlock()->contentWidth();
2289 w = padding.calcMinValue(w);
2290 if ( isTableCell() && padding.isAuto() )
2291 w = static_cast<const RenderTableCell *>(this)->table()->cellPadding();
2295 int RenderObject::paddingBottom() const
2298 Length padding = style()->paddingBottom();
2299 if (padding.isPercent())
2300 w = containingBlock()->contentWidth();
2301 w = padding.calcMinValue(w);
2302 if ( isTableCell() && padding.isAuto() )
2303 w = static_cast<const RenderTableCell *>(this)->table()->cellPadding();
2307 int RenderObject::paddingLeft() const
2310 Length padding = style()->paddingLeft();
2311 if (padding.isPercent())
2312 w = containingBlock()->contentWidth();
2313 w = padding.calcMinValue(w);
2314 if ( isTableCell() && padding.isAuto() )
2315 w = static_cast<const RenderTableCell *>(this)->table()->cellPadding();
2319 int RenderObject::paddingRight() const
2322 Length padding = style()->paddingRight();
2323 if (padding.isPercent())
2324 w = containingBlock()->contentWidth();
2325 w = padding.calcMinValue(w);
2326 if ( isTableCell() && padding.isAuto() )
2327 w = static_cast<const RenderTableCell *>(this)->table()->cellPadding();
2331 int RenderObject::tabWidth() const
2333 if (style()->collapseWhiteSpace())
2336 return containingBlock()->tabWidth(true);
2339 RenderView* RenderObject::view() const
2341 return static_cast<RenderView*>(document()->renderer());
2344 RenderObject *RenderObject::container() const
2346 // This method is extremely similar to containingBlock(), but with a few notable
2348 // (1) It can be used on orphaned subtrees, i.e., it can be called safely even when
2349 // the object is not part of the primary document subtree yet.
2350 // (2) For normal flow elements, it just returns the parent.
2351 // (3) For absolute positioned elements, it will return a relative positioned inline.
2352 // containingBlock() simply skips relpositioned inlines and lets an enclosing block handle
2353 // the layout of the positioned object. This does mean that calcAbsoluteHorizontal and
2354 // calcAbsoluteVertical have to use container().
2355 EPosition pos = m_style->position();
2356 RenderObject *o = 0;
2357 if (!isText() && pos == FixedPosition) {
2358 // container() can be called on an object that is not in the
2359 // tree yet. We don't call view() since it will assert if it
2360 // can't get back to the canvas. Instead we just walk as high up
2361 // as we can. If we're in the tree, we'll get the root. If we
2362 // aren't we'll get the root of our little subtree (most likely
2363 // we'll just return 0).
2365 while (o && o->parent()) o = o->parent();
2367 else if (!isText() && pos == AbsolutePosition) {
2368 // Same goes here. We technically just want our containing block, but
2369 // we may not have one if we're part of an uninstalled subtree. We'll
2370 // climb as high as we can though.
2372 while (o && o->style()->position() == StaticPosition && !o->isRoot() && !o->isRenderView())
2380 // This code has been written to anticipate the addition of CSS3-::outside and ::inside generated
2381 // content (and perhaps XBL). That's why it uses the render tree and not the DOM tree.
2382 RenderObject* RenderObject::hoverAncestor() const
2384 return (!isInline() && continuation()) ? continuation() : parent();
2387 bool RenderObject::isSelectionBorder() const
2389 SelectionState st = selectionState();
2390 return st == SelectionStart || st == SelectionEnd || st == SelectionBoth;
2394 void RenderObject::removeFromObjectLists()
2396 if (documentBeingDestroyed())
2400 RenderBlock* outermostBlock = containingBlock();
2401 for (RenderBlock* p = outermostBlock; p && !p->isRenderView(); p = p->containingBlock()) {
2402 if (p->containsFloat(this))
2407 outermostBlock->markAllDescendantsWithFloatsForLayout(this);
2410 if (isPositioned()) {
2412 for (p = parent(); p; p = p->parent()) {
2413 if (p->isRenderBlock())
2414 static_cast<RenderBlock*>(p)->removePositionedObject(this);
2419 RenderArena* RenderObject::renderArena() const
2421 Document* doc = document();
2422 return doc ? doc->renderArena() : 0;
2425 bool RenderObject::documentBeingDestroyed() const
2427 return !document()->renderer();
2430 void RenderObject::destroy()
2432 // If this renderer is being autoscrolled, stop the autoscroll timer
2433 if (document() && document()->frame() && document()->frame()->autoscrollRenderer() == this)
2434 document()->frame()->stopAutoscrollTimer();
2436 if (m_hasCounterNodeMap) {
2437 RenderObjectsToCounterNodeMaps* objectsMap = getRenderObjectsToCounterNodeMaps();
2438 if (CounterNodeMap* counterNodesMap = objectsMap->get(this)) {
2439 CounterNodeMap::const_iterator end = counterNodesMap->end();
2440 for (CounterNodeMap::const_iterator it = counterNodesMap->begin(); it != end; ++it) {
2441 CounterNode* counterNode = it->second;
2442 counterNode->remove();
2446 objectsMap->remove(this);
2447 delete counterNodesMap;
2451 document()->axObjectCache()->remove(this);
2453 // By default no ref-counting. RenderWidget::destroy() doesn't call
2454 // this function because it needs to do ref-counting. If anything
2455 // in this function changes, be sure to fix RenderWidget::destroy() as well.
2459 arenaDelete(document()->renderArena(), this);
2462 void RenderObject::arenaDelete(RenderArena *arena, void *base)
2464 if (m_style->backgroundImage())
2465 m_style->backgroundImage()->deref(this);
2467 m_style->deref(arena);
2470 void *savedBase = baseOfRenderObjectBeingDeleted;
2471 baseOfRenderObjectBeingDeleted = base;
2475 baseOfRenderObjectBeingDeleted = savedBase;
2478 // Recover the size left there for us by operator delete and free the memory.
2479 arena->free(*(size_t *)base, base);
2482 VisiblePosition RenderObject::positionForCoordinates(int x, int y)
2484 return VisiblePosition(element(), caretMinOffset(), DOWNSTREAM);
2487 bool RenderObject::isDragging() const
2489 return m_isDragging;
2492 void RenderObject::updateDragState(bool dragOn)
2494 bool valueChanged = (dragOn != m_isDragging);
2495 m_isDragging = dragOn;
2496 if (valueChanged && style()->affectedByDragRules())
2497 element()->setChanged();
2498 for (RenderObject* curr = firstChild(); curr; curr = curr->nextSibling())
2499 curr->updateDragState(dragOn);
2501 continuation()->updateDragState(dragOn);
2504 bool RenderObject::hitTest(NodeInfo& info, int x, int y, int tx, int ty, HitTestFilter hitTestFilter)
2506 bool inside = false;
2507 if (hitTestFilter != HitTestSelf) {
2508 // First test the foreground layer (lines and inlines).
2509 inside = nodeAtPoint(info, x, y, tx, ty, HitTestForeground);
2511 // Test floats next.
2513 inside = nodeAtPoint(info, x, y, tx, ty, HitTestFloat);
2515 // Finally test to see if the mouse is in the background (within a child block's background).
2517 inside = nodeAtPoint(info, x, y, tx, ty, HitTestChildBlockBackgrounds);
2520 // See if the mouse is inside us but not any of our descendants
2521 if (hitTestFilter != HitTestDescendants && !inside)
2522 inside = nodeAtPoint(info, x, y, tx, ty, HitTestBlockBackground);
2527 void RenderObject::setInnerNode(NodeInfo& info)
2529 if (!info.innerNode() && !isInline() && continuation()) {
2530 // We are in the margins of block elements that are part of a continuation. In
2531 // this case we're actually still inside the enclosing inline element that was
2532 // split. Go ahead and set our inner node accordingly.
2533 info.setInnerNode(continuation()->element());
2534 if (!info.innerNonSharedNode())
2535 info.setInnerNonSharedNode(continuation()->element());
2538 if (!info.innerNode() && element())
2539 info.setInnerNode(element());
2541 if(!info.innerNonSharedNode() && element())
2542 info.setInnerNonSharedNode(element());
2545 bool RenderObject::nodeAtPoint(NodeInfo& info, int _x, int _y, int _tx, int _ty,
2546 HitTestAction hitTestAction)
2551 short RenderObject::verticalPositionHint( bool firstLine ) const
2553 short vpos = m_verticalPosition;
2554 if ( m_verticalPosition == PositionUndefined || firstLine ) {
2555 vpos = getVerticalPosition( firstLine );
2557 m_verticalPosition = vpos;
2563 short RenderObject::getVerticalPosition( bool firstLine ) const
2568 // This method determines the vertical position for inline elements.
2570 EVerticalAlign va = style()->verticalAlign();
2573 } else if ( va == BOTTOM ) {
2574 vpos = PositionBottom;
2575 } else if ( va == LENGTH ) {
2576 vpos = -style()->verticalAlignLength().calcValue( lineHeight( firstLine ) );
2578 bool checkParent = parent()->isInline() && !parent()->isInlineBlockOrInlineTable() && parent()->style()->verticalAlign() != TOP && parent()->style()->verticalAlign() != BOTTOM;
2579 vpos = checkParent ? parent()->verticalPositionHint( firstLine ) : 0;
2580 // don't allow elements nested inside text-top to have a different valignment.
2581 if ( va == BASELINE )
2584 const Font &f = parent()->font(firstLine);
2585 int fontsize = f.pixelSize();
2588 vpos += fontsize/5 + 1;
2589 else if (va == SUPER)
2590 vpos -= fontsize/3 + 1;
2591 else if (va == TEXT_TOP)
2592 vpos += baselinePosition(firstLine) - f.ascent();
2593 else if (va == MIDDLE)
2594 vpos += - (int)(f.xHeight()/2) - lineHeight( firstLine )/2 + baselinePosition( firstLine );
2595 else if (va == TEXT_BOTTOM) {
2596 vpos += f.descent();
2598 vpos -= font(firstLine).descent();
2599 } else if ( va == BASELINE_MIDDLE )
2600 vpos += - lineHeight( firstLine )/2 + baselinePosition( firstLine );
2606 short RenderObject::lineHeight( bool firstLine, bool ) const
2608 RenderStyle* s = style(firstLine);
2610 Length lh = s->lineHeight();
2612 // its "unset", choose nice default
2614 return s->font().lineSpacing();
2617 return lh.calcMinValue(s->fontSize());
2623 short RenderObject::baselinePosition(bool firstLine, bool isRootLineBox) const
2625 const Font& f = font(firstLine);
2626 return f.ascent() + (lineHeight(firstLine, isRootLineBox) - f.height()) / 2;
2629 void RenderObject::invalidateVerticalPositions()
2631 m_verticalPosition = PositionUndefined;
2632 RenderObject *child = firstChild();
2634 child->invalidateVerticalPositions();
2635 child = child->nextSibling();
2639 void RenderObject::recalcMinMaxWidths()
2641 ASSERT( m_recalcMinMax );
2644 kdDebug( 6040 ) << renderName() << " recalcMinMaxWidths() this=" << this <<endl;
2648 updateFirstLetter();
2650 RenderObject *child = firstChild();
2655 if ( ( m_minMaxKnown && child->m_recalcMinMax ) || !child->m_minMaxKnown ) {
2656 cmin = child->minWidth();
2657 cmax = child->maxWidth();
2660 if ( child->m_recalcMinMax )
2661 child->recalcMinMaxWidths();
2662 if ( !child->m_minMaxKnown )
2663 child->calcMinMaxWidth();
2664 if ( m_minMaxKnown && test && (cmin != child->minWidth() || cmax != child->maxWidth()) )
2665 m_minMaxKnown = false;
2666 child = child->nextSibling();
2669 // we need to recalculate, if the contains inline children, as the change could have
2670 // happened somewhere deep inside the child tree. Also do this for blocks or tables that
2671 // are inline (i.e., inline-block and inline-table).
2672 if ((!isInline() || isInlineBlockOrInlineTable()) && childrenInline())
2673 m_minMaxKnown = false;
2675 if ( !m_minMaxKnown )
2677 m_recalcMinMax = false;
2680 void RenderObject::scheduleRelayout()
2682 if (isRenderView()) {
2683 FrameView* view = static_cast<RenderView*>(this)->frameView();
2685 view->scheduleRelayout();
2687 FrameView* v = view() ? view()->frameView() : 0;
2689 v->scheduleRelayoutOfSubtree(node());
2694 void RenderObject::removeLeftoverAnonymousBoxes()
2698 InlineBox* RenderObject::createInlineBox(bool, bool isRootLineBox, bool)
2700 ASSERT(!isRootLineBox);
2701 return new (renderArena()) InlineBox(this);
2704 void RenderObject::dirtyLineBoxes(bool, bool)
2708 InlineBox* RenderObject::inlineBoxWrapper() const
2713 void RenderObject::setInlineBoxWrapper(InlineBox* b)
2717 void RenderObject::deleteLineBoxWrapper()
2721 RenderStyle* RenderObject::firstLineStyle() const
2723 RenderStyle *s = m_style;
2724 const RenderObject* obj = isText() ? parent() : this;
2725 if (obj->isBlockFlow()) {
2726 RenderBlock* firstLineBlock = obj->firstLineBlock();
2728 s = firstLineBlock->getPseudoStyle(RenderStyle::FIRST_LINE, style());
2729 } else if (!obj->isAnonymous() && obj->isInlineFlow()) {
2730 RenderStyle* parentStyle = obj->parent()->firstLineStyle();
2731 if (parentStyle != obj->parent()->style()) {
2732 // A first-line style is in effect. We need to cache a first-line style
2734 style()->setHasPseudoStyle(RenderStyle::FIRST_LINE_INHERITED);
2735 s = obj->getPseudoStyle(RenderStyle::FIRST_LINE_INHERITED, parentStyle);
2741 RenderStyle* RenderObject::getPseudoStyle(RenderStyle::PseudoId pseudo, RenderStyle* parentStyle) const
2743 if (!style()->hasPseudoStyle(pseudo))
2747 parentStyle = style();
2749 RenderStyle* result = style()->getPseudoStyle(pseudo);
2753 Node* node = element();
2755 node = element()->parentNode();
2759 if (pseudo == RenderStyle::FIRST_LINE_INHERITED) {
2760 result = document()->styleSelector()->styleForElement(static_cast<Element*>(node), parentStyle, false);
2761 result->setStyleType(RenderStyle::FIRST_LINE_INHERITED);
2763 result = document()->styleSelector()->pseudoStyleForElement(pseudo, static_cast<Element*>(node), parentStyle);
2765 style()->addPseudoStyle(result);
2766 result->deref(document()->renderArena());
2771 void RenderObject::getTextDecorationColors(int decorations, Color& underline, Color& overline,
2772 Color& linethrough, bool quirksMode)
2774 RenderObject* curr = this;
2776 int currDecs = curr->style()->textDecoration();
2778 if (currDecs & UNDERLINE) {
2779 decorations &= ~UNDERLINE;
2780 underline = curr->style()->color();
2782 if (currDecs & OVERLINE) {
2783 decorations &= ~OVERLINE;
2784 overline = curr->style()->color();
2786 if (currDecs & LINE_THROUGH) {
2787 decorations &= ~LINE_THROUGH;
2788 linethrough = curr->style()->color();
2791 curr = curr->parent();
2792 if (curr && curr->isRenderBlock() && curr->continuation())
2793 curr = curr->continuation();
2794 } while (curr && decorations && (!quirksMode || !curr->element() ||
2795 (!curr->element()->hasTagName(aTag) && !curr->element()->hasTagName(fontTag))));
2797 // If we bailed out, use the element we bailed out at (typically a <font> or <a> element).
2798 if (decorations && curr) {
2799 if (decorations & UNDERLINE)
2800 underline = curr->style()->color();
2801 if (decorations & OVERLINE)
2802 overline = curr->style()->color();
2803 if (decorations & LINE_THROUGH)
2804 linethrough = curr->style()->color();
2808 void RenderObject::updateWidgetPosition()
2812 void RenderObject::addDashboardRegions(Vector<DashboardRegionValue>& regions)
2814 // Convert the style regions to absolute coordinates.
2815 if (style()->visibility() != VISIBLE)
2818 const Vector<StyleDashboardRegion>& styleRegions = style()->dashboardRegions();
2819 unsigned i, count = styleRegions.size();
2820 for (i = 0; i < count; i++){
2821 StyleDashboardRegion styleRegion = styleRegions[i];
2826 DashboardRegionValue region;
2827 region.label = styleRegion.label;
2828 region.bounds = IntRect (
2829 styleRegion.offset.left.value(),
2830 styleRegion.offset.top.value(),
2831 w - styleRegion.offset.left.value() - styleRegion.offset.right.value(),
2832 h - styleRegion.offset.top.value() - styleRegion.offset.bottom.value());
2833 region.type = styleRegion.type;
2835 region.clip = region.bounds;
2836 computeAbsoluteRepaintRect(region.clip);
2837 if (region.clip.height() < 0) {
2838 region.clip.setHeight(0);
2839 region.clip.setWidth(0);
2843 absolutePosition(x, y);
2844 region.bounds.setX(x + styleRegion.offset.left.value());
2845 region.bounds.setY(y + styleRegion.offset.top.value());
2847 if (document()->frame()) {
2848 float pageScaleFactor = scaleFactor(document()->frame()->page());
2849 if (pageScaleFactor != 1.0f) {
2850 region.bounds.scale(pageScaleFactor);
2851 region.clip.scale(pageScaleFactor);
2855 regions.append(region);
2859 void RenderObject::collectDashboardRegions(Vector<DashboardRegionValue>& regions)
2861 // RenderTexts don't have their own style, they just use their parent's style,
2862 // so we don't want to include them.
2866 addDashboardRegions(regions);
2867 for (RenderObject* curr = firstChild(); curr; curr = curr->nextSibling())
2868 curr->collectDashboardRegions(regions);
2872 void RenderObject::collectBorders(DeprecatedValueList<CollapsedBorderValue>& borderStyles)
2874 for (RenderObject* curr = firstChild(); curr; curr = curr->nextSibling())
2875 curr->collectBorders(borderStyles);
2878 bool RenderObject::avoidsFloats() const
2880 return isReplaced() || hasOverflowClip() || isHR();
2883 bool RenderObject::usesLineWidth() const
2885 // 1. All auto-width objects that avoid floats should always use lineWidth
2886 // 2. For objects with a specified width, we match WinIE's behavior:
2887 // (a) tables use contentWidth
2888 // (b) <hr>s use lineWidth
2889 // (c) all other objects use lineWidth in quirks mode and contentWidth in strict mode.
2890 return (avoidsFloats() && (style()->width().isAuto() || isHR() || (style()->htmlHacks() && !isTable())));
2893 CounterNode* RenderObject::findCounter(const String& counterName, bool willNeedLayout,
2894 bool usesSeparator, bool createIfNotFound)
2899 RenderObjectsToCounterNodeMaps* objectsMap = getRenderObjectsToCounterNodeMaps();
2900 CounterNode* newNode = 0;
2901 if (CounterNodeMap* counterNodesMap = objectsMap->get(this))
2902 if (counterNodesMap)
2903 newNode = counterNodesMap->get(counterName);
2909 if (style()->hasCounterReset(counterName) || isRoot()) {
2910 newNode = new CounterResetNode(this);
2911 val = style()->counterReset(counterName);
2912 if (style()->hasCounterIncrement(counterName))
2913 val += style()->counterIncrement(counterName);
2914 newNode->setValue(val);
2915 } else if (style()->hasCounterIncrement(counterName)) {
2916 newNode = new CounterNode(this);
2917 newNode->setValue(style()->counterIncrement(counterName));
2918 } else if (counterName == "list-item") {
2921 String v = static_cast<Element*>(element())->getAttribute("value");
2923 newNode = new CounterResetNode(this);
2929 newNode = new CounterNode(this);
2933 newNode->setValue(val);
2934 } else if (element() && element()->hasTagName(olTag)) {
2935 newNode = new CounterResetNode(this);
2936 newNode->setValue(static_cast<HTMLOListElement*>(element())->start());
2937 } else if (element() &&
2938 (element()->hasTagName(ulTag) ||
2939 element()->hasTagName(menuTag) ||
2940 element()->hasTagName(dirTag))) {
2941 newNode = new CounterResetNode(this);
2942 newNode->setValue(0);
2946 if (!newNode && !createIfNotFound)
2948 else if (!newNode) {
2949 newNode = new CounterNode(this);
2950 newNode->setValue(0);
2954 newNode->setWillNeedLayout();
2956 newNode->setUsesSeparator();
2958 CounterNodeMap* nodeMap;
2959 if (m_hasCounterNodeMap)
2960 nodeMap = objectsMap->get(this);
2962 nodeMap = new CounterNodeMap;
2963 objectsMap->set(this, nodeMap);
2964 m_hasCounterNodeMap = true;
2967 nodeMap->set(counterName, newNode);
2970 RenderObject* n = !isListItem() && previousSibling()
2971 ? previousSibling()->previousSibling() : previousSibling();
2973 CounterNode* current = 0;
2974 for (; n; n = n->previousSibling()) {
2975 current = n->findCounter(counterName, false, false, false);
2980 CounterNode* last = current;
2981 CounterNode* sibling = current;
2982 if (last && !newNode->isReset()) {
2983 // Found render-sibling, now search for later counter-siblings among its render-children
2986 current = n->findCounter(counterName, false, false, false);
2987 if (current && (last->parent() == current->parent() || sibling == current->parent())) {
2989 // If the current counter is not the last, search deeper
2990 if (current->nextSibling()) {
2996 n = n->previousSibling();
2999 if (sibling->isReset()) {
3000 if (last != sibling)
3001 sibling->insertAfter(newNode, last);
3003 sibling->insertAfter(newNode, 0);
3005 last->parent()->insertAfter(newNode, last);
3007 // Nothing found among siblings, let our parent search
3008 last = parent()->findCounter(counterName, false);
3009 if (last->isReset())
3010 last->insertAfter(newNode, 0);
3012 last->parent()->insertAfter(newNode, last);
3019 UChar RenderObject::backslashAsCurrencySymbol() const
3021 if (Node *node = element())
3022 if (Decoder *decoder = node->document()->decoder())
3023 return decoder->encoding().backslashAsCurrencySymbol();
3027 void RenderObject::imageChanged(CachedImage *image)
3029 // Repaint when the background image or border image finishes loading.
3030 // This is needed for RenderBox objects, and also for table objects that hold
3031 // backgrounds that are then respected by the table cells (which are RenderBox
3032 // subclasses). It would be even better to find a more elegant way of doing this that
3033 // would avoid putting this function and the CachedResourceClient base class into RenderObject.
3034 if (image && image->canRender() && parent()) {
3035 if (view() && element() && (element()->hasTagName(htmlTag) || element()->hasTagName(bodyTag)))
3036 view()->repaint(); // repaint the entire canvas since the background gets propagated up
3038 repaint(); // repaint object, which is a box or a container with boxes inside it
3042 bool RenderObject::willRenderImage(CachedImage*)
3044 // Without visibility we won't render (and therefore don't care about animation).
3045 if (style()->visibility() != VISIBLE)
3048 // If we're not in a window (i.e., we're dormant from being put in the b/f cache or in a background tab)
3049 // then we don't want to render either.
3050 return !document()->inPageCache() && document()->view()->inWindow();
3053 int RenderObject::maximalOutlineSize(PaintPhase p) const
3055 if (p != PaintPhaseOutline && p != PaintPhaseSelfOutline && p != PaintPhaseChildOutlines)
3057 return static_cast<RenderView*>(document()->renderer())->maximalOutlineSize();
3060 int RenderObject::caretMinOffset() const
3065 int RenderObject::caretMaxOffset() const
3067 return isReplaced() ? 1 : 0;
3070 unsigned RenderObject::caretMaxRenderedOffset() const
3075 int RenderObject::previousOffset (int current) const
3077 int previousOffset = current - 1;
3078 return previousOffset;
3081 int RenderObject::nextOffset (int current) const
3083 int nextOffset = current + 1;
3087 InlineBox *RenderObject::inlineBox(int offset, EAffinity affinity)
3089 return inlineBoxWrapper();
3094 FloatRect RenderObject::relativeBBox(bool) const
3099 AffineTransform RenderObject::localTransform() const
3101 return AffineTransform(1, 0, 0, 1, xPos(), yPos());
3104 void RenderObject::setLocalTransform(const AffineTransform&)
3109 AffineTransform RenderObject::absoluteTransform() const
3112 return localTransform() * parent()->absoluteTransform();
3113 return localTransform();
3122 void showTree(const WebCore::RenderObject* ro)
3125 ro->showTreeForThis();