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"
37 #include "EventNames.h"
38 #include "FloatRect.h"
40 #include "GraphicsContext.h"
41 #include "HTMLNames.h"
42 #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::addPDFURLRect(GraphicsContext* p, IntRect rect)
1644 Node* node = element();
1647 if (rect.width() > 0 && rect.height() > 0) {
1648 Element* element = static_cast<Element*>(node);
1650 if (element->isLink())
1651 href = element->getAttribute(hrefAttr);
1653 if (!href.isNull()) {
1654 KURL link = element->document()->completeURL(href.deprecatedString());
1656 p->setURLForRect(link, rect);
1664 void RenderObject::addFocusRingRects(GraphicsContext* p, int _tx, int _ty)
1666 // For blocks inside inlines, we go ahead and include margins so that we run right up to the
1667 // inline boxes above and below us (thus getting merged with them to form a single irregular
1669 if (continuation()) {
1670 p->addFocusRingRect(IntRect(_tx, _ty - collapsedMarginTop(), width(), height()+collapsedMarginTop()+collapsedMarginBottom()));
1671 continuation()->addFocusRingRects(p,
1672 _tx - xPos() + continuation()->containingBlock()->xPos(),
1673 _ty - yPos() + continuation()->containingBlock()->yPos());
1676 p->addFocusRingRect(IntRect(_tx, _ty, width(), height()));
1679 void RenderObject::paintOutline(GraphicsContext* p, int _tx, int _ty, int w, int h, const RenderStyle* style)
1684 int ow = style->outlineWidth();
1686 EBorderStyle os = style->outlineStyle();
1688 Color oc = style->outlineColor();
1690 oc = style->color();
1692 int offset = style->outlineOffset();
1694 if (style->outlineStyleIsAuto() || hasOutlineAnnotation()) {
1695 if (!theme()->supportsFocusRing(style)) {
1696 // Only paint the focus ring by hand if the theme isn't able to draw the focus ring.
1697 p->initFocusRing(ow, offset);
1698 if (style->outlineStyleIsAuto())
1699 addFocusRingRects(p, _tx, _ty);
1701 addPDFURLRect(p, p->focusRingBoundingRect());
1702 p->drawFocusRing(oc);
1703 p->clearFocusRing();
1707 if (style->outlineStyleIsAuto() || style->outlineStyle() <= BHIDDEN)
1715 drawBorder(p, _tx-ow, _ty-ow, _tx, _ty+h+ow, BSLeft,
1716 Color(oc), style->color(),
1719 drawBorder(p, _tx-ow, _ty-ow, _tx+w+ow, _ty, BSTop,
1720 Color(oc), style->color(),
1723 drawBorder(p, _tx+w, _ty-ow, _tx+w+ow, _ty+h+ow, BSRight,
1724 Color(oc), style->color(),
1727 drawBorder(p, _tx-ow, _ty+h, _tx+w+ow, _ty+h+ow, BSBottom,
1728 Color(oc), style->color(),
1733 void RenderObject::paint(PaintInfo& i, int tx, int ty)
1737 void RenderObject::repaint(bool immediate)
1739 // Can't use view(), since we might be unrooted.
1740 RenderObject* o = this;
1741 while ( o->parent() ) o = o->parent();
1742 if (!o->isRenderView())
1744 RenderView* c = static_cast<RenderView*>(o);
1745 if (c->printingMode())
1746 return; // Don't repaint if we're printing.
1747 c->repaintViewRectangle(getAbsoluteRepaintRect(), immediate);
1750 void RenderObject::repaintRectangle(const IntRect& r, bool immediate)
1752 // Can't use view(), since we might be unrooted.
1753 RenderObject* o = this;
1754 while ( o->parent() ) o = o->parent();
1755 if (!o->isRenderView())
1757 RenderView* c = static_cast<RenderView*>(o);
1758 if (c->printingMode())
1759 return; // Don't repaint if we're printing.
1761 computeAbsoluteRepaintRect(absRect);
1762 c->repaintViewRectangle(absRect, immediate);
1765 bool RenderObject::repaintAfterLayoutIfNeeded(const IntRect& oldBounds, const IntRect& oldFullBounds)
1767 RenderView* c = view();
1768 if (c->printingMode())
1769 return false; // Don't repaint if we're printing.
1771 IntRect newBounds, newFullBounds;
1772 getAbsoluteRepaintRectIncludingFloats(newBounds, newFullBounds);
1773 if (newBounds == oldBounds && !selfNeedsLayout())
1776 bool fullRepaint = selfNeedsLayout() || newBounds.location() != oldBounds.location() || mustRepaintBackgroundOrBorder();
1778 c->repaintViewRectangle(oldFullBounds);
1779 if (newBounds != oldBounds)
1780 c->repaintViewRectangle(newFullBounds);
1784 // We didn't move, but we did change size. Invalidate the delta, which will consist of possibly
1785 // two rectangles (but typically only one).
1786 int ow = style() ? style()->outlineSize() : 0;
1787 int width = abs(newBounds.width() - oldBounds.width());
1789 c->repaintViewRectangle(IntRect(min(newBounds.x() + newBounds.width(), oldBounds.x() + oldBounds.width()) - borderRight() - ow,
1791 width + borderRight() + ow,
1792 max(newBounds.height(), oldBounds.height())));
1793 int height = abs(newBounds.height() - oldBounds.height());
1795 c->repaintViewRectangle(IntRect(newBounds.x(),
1796 min(newBounds.bottom(), oldBounds.bottom()) - borderBottom() - ow,
1797 max(newBounds.width(), oldBounds.width()),
1798 height + borderBottom() + ow));
1802 void RenderObject::repaintDuringLayoutIfMoved(int x, int y)
1806 void RenderObject::repaintOverhangingFloats(bool paintAllDescendants)
1810 bool RenderObject::checkForRepaintDuringLayout() const
1812 return !document()->view()->needsFullRepaint() && !layer();
1815 void RenderObject::repaintObjectsBeforeLayout()
1817 if (!needsLayout() || isText())
1820 bool blockWithInlineChildren = (isRenderBlock() && !isTable() && normalChildNeedsLayout() && childrenInline());
1821 if (selfNeedsLayout()) {
1823 if (blockWithInlineChildren)
1827 for (RenderObject* current = firstChild(); current; current = current->nextSibling()) {
1828 if (!current->isPositioned()) // RenderBlock subclass method handles walking the positioned objects.
1829 current->repaintObjectsBeforeLayout();
1833 IntRect RenderObject::getAbsoluteRepaintRectWithOutline(int ow)
1835 IntRect r(getAbsoluteRepaintRect());
1838 if (continuation() && !isInline())
1839 r.inflateY(collapsedMarginTop());
1842 for (RenderObject* curr = firstChild(); curr; curr = curr->nextSibling())
1843 if (!curr->isText())
1844 r.unite(curr->getAbsoluteRepaintRectWithOutline(ow));
1849 IntRect RenderObject::getAbsoluteRepaintRect()
1852 return parent()->getAbsoluteRepaintRect();
1856 void RenderObject::getAbsoluteRepaintRectIncludingFloats(IntRect& bounds, IntRect& fullBounds)
1858 bounds = fullBounds = getAbsoluteRepaintRect();
1861 void RenderObject::computeAbsoluteRepaintRect(IntRect& r, bool f)
1864 return parent()->computeAbsoluteRepaintRect(r, f);
1867 void RenderObject::dirtyLinesFromChangedChild(RenderObject* child)
1873 DeprecatedString RenderObject::information() const
1875 DeprecatedString str;
1876 TextStream ts(&str);
1878 << "(" << (style() ? style()->refCount() : 0) << ")"
1879 << ": " << (void*)this << " ";
1880 if (isInline()) ts << "il ";
1881 if (childrenInline()) ts << "ci ";
1882 if (isFloating()) ts << "fl ";
1883 if (isAnonymous()) ts << "an ";
1884 if (isRelPositioned()) ts << "rp ";
1885 if (isPositioned()) ts << "ps ";
1886 if (needsLayout()) ts << "nl ";
1887 if (m_recalcMinMax) ts << "rmm ";
1888 if (style() && style()->zIndex()) ts << "zI: " << style()->zIndex();
1890 if (element()->active())
1892 if (element()->isLink())
1894 if (element()->focused())
1896 ts << " <" << element()->localName().deprecatedString() << ">";
1897 ts << " (" << xPos() << "," << yPos() << "," << width() << "," << height() << ")";
1898 if (isTableCell()) {
1899 const RenderTableCell* cell = static_cast<const RenderTableCell *>(this);
1900 ts << " [r=" << cell->row() << " c=" << cell->col() << " rs=" << cell->rowSpan() << " cs=" << cell->colSpan() << "]";
1906 void RenderObject::dump(TextStream *stream, DeprecatedString ind) const
1908 if (isAnonymous()) { *stream << " anonymous"; }
1909 if (isFloating()) { *stream << " floating"; }
1910 if (isPositioned()) { *stream << " positioned"; }
1911 if (isRelPositioned()) { *stream << " relPositioned"; }
1912 if (isText()) { *stream << " text"; }
1913 if (isInline()) { *stream << " inline"; }
1914 if (isReplaced()) { *stream << " replaced"; }
1915 if (shouldPaintBackgroundOrBorder()) { *stream << " paintBackground"; }
1916 if (needsLayout()) { *stream << " needsLayout"; }
1917 if (minMaxKnown()) { *stream << " minMaxKnown"; }
1920 RenderObject *child = firstChild();
1923 *stream << ind << child->renderName() << ": ";
1924 child->dump(stream,ind+" ");
1925 child = child->nextSibling();
1929 void RenderObject::showTreeForThis() const
1932 element()->showTreeForThis();
1937 static Node *selectStartNode(const RenderObject *object)
1940 bool forcedOn = false;
1942 for (const RenderObject *curr = object; curr; curr = curr->parent()) {
1943 if (curr->style()->userSelect() == SELECT_TEXT)
1945 if (!forcedOn && curr->style()->userSelect() == SELECT_NONE)
1949 node = curr->element();
1952 // somewhere up the render tree there must be an element!
1958 bool RenderObject::canSelect() const
1960 return selectStartNode(this) != 0;
1963 bool RenderObject::shouldSelect() const
1965 if (Node *node = selectStartNode(this))
1966 return EventTargetNodeCast(node)->dispatchHTMLEvent(selectstartEvent, true, true);
1971 Color RenderObject::selectionBackgroundColor() const
1974 if (style()->userSelect() != SELECT_NONE) {
1975 RenderStyle* pseudoStyle = getPseudoStyle(RenderStyle::SELECTION);
1976 if (pseudoStyle && pseudoStyle->backgroundColor().isValid())
1977 color = pseudoStyle->backgroundColor().blendWithWhite();
1979 color = document()->frame()->isActive() ?
1980 theme()->activeSelectionBackgroundColor() :
1981 theme()->inactiveSelectionBackgroundColor();
1987 Color RenderObject::selectionForegroundColor() const
1990 if (style()->userSelect() != SELECT_NONE) {
1991 RenderStyle* pseudoStyle = getPseudoStyle(RenderStyle::SELECTION);
1993 color = pseudoStyle->color();
1995 color = document()->frame()->isActive() ?
1996 theme()->platformActiveSelectionForegroundColor() :
1997 theme()->platformInactiveSelectionForegroundColor();
2003 Node* RenderObject::draggableNode(bool dhtmlOK, bool uaOK, int x, int y, bool& dhtmlWillDrag) const
2005 if (!dhtmlOK && !uaOK)
2008 const RenderObject* curr = this;
2010 Node *elt = curr->element();
2011 if (elt && elt->nodeType() == Node::TEXT_NODE) {
2012 // Since there's no way for the author to address the -webkit-user-drag style for a text node,
2013 // we use our own judgement.
2014 if (uaOK && view()->frameView()->frame()->shouldDragAutoNode(curr->node(), IntPoint(x, y))) {
2015 dhtmlWillDrag = false;
2016 return curr->node();
2017 } else if (curr->shouldSelect()) {
2018 // In this case we have a click in the unselected portion of text. If this text is
2019 // selectable, we want to start the selection process instead of looking for a parent
2024 EUserDrag dragMode = curr->style()->userDrag();
2025 if (dhtmlOK && dragMode == DRAG_ELEMENT) {
2026 dhtmlWillDrag = true;
2027 return curr->node();
2028 } else if (uaOK && dragMode == DRAG_AUTO
2029 && view()->frameView()->frame()->shouldDragAutoNode(curr->node(), IntPoint(x, y)))
2031 dhtmlWillDrag = false;
2032 return curr->node();
2035 curr = curr->parent();
2040 void RenderObject::selectionStartEnd(int& spos, int& epos)
2042 view()->selectionStartEnd(spos, epos);
2045 RenderBlock* RenderObject::createAnonymousBlock()
2047 RenderStyle *newStyle = new (renderArena()) RenderStyle();
2048 newStyle->inheritFrom(m_style);
2049 newStyle->setDisplay(BLOCK);
2051 RenderBlock *newBox = new (renderArena()) RenderBlock(document() /* anonymous box */);
2052 newBox->setStyle(newStyle);
2056 void RenderObject::handleDynamicFloatPositionChange()
2058 // We have gone from not affecting the inline status of the parent flow to suddenly
2059 // having an impact. See if there is a mismatch between the parent flow's
2060 // childrenInline() state and our state.
2061 setInline(style()->isDisplayInlineType());
2062 if (isInline() != parent()->childrenInline()) {
2064 if (parent()->isRenderInline()) {
2065 // We have to split the parent flow.
2066 RenderInline* parentInline = static_cast<RenderInline*>(parent());
2067 RenderBlock* newBox = parentInline->createAnonymousBlock();
2069 RenderFlow* oldContinuation = parent()->continuation();
2070 parentInline->setContinuation(newBox);
2072 RenderObject* beforeChild = nextSibling();
2073 parent()->removeChildNode(this);
2074 parentInline->splitFlow(beforeChild, newBox, this, oldContinuation);
2076 else if (parent()->isRenderBlock())
2077 static_cast<RenderBlock*>(parent())->makeChildrenNonInline();
2080 // An anonymous block must be made to wrap this inline.
2081 RenderBlock* box = createAnonymousBlock();
2082 parent()->insertChildNode(box, this);
2083 box->appendChildNode(parent()->removeChildNode(this));
2088 void RenderObject::setStyle(RenderStyle *style)
2090 if (m_style == style)
2093 bool affectsParentBlock = false;
2094 RenderStyle::Diff d = RenderStyle::Equal;
2096 // If our z-index changes value or our visibility changes,
2097 // we need to dirty our stacking context's z-order list.
2100 if (m_style->visibility() != style->visibility() ||
2101 m_style->zIndex() != style->zIndex() ||
2102 m_style->hasAutoZIndex() != style->hasAutoZIndex())
2103 document()->setDashboardRegionsDirty(true);
2106 if ((m_style->hasAutoZIndex() != style->hasAutoZIndex() ||
2107 m_style->zIndex() != style->zIndex() ||
2108 m_style->visibility() != style->visibility()) && layer()) {
2109 layer()->stackingContext()->dirtyZOrderLists();
2110 if (m_style->hasAutoZIndex() != style->hasAutoZIndex() ||
2111 m_style->visibility() != style->visibility())
2112 layer()->dirtyZOrderLists();
2114 // keep layer hierarchy visibility bits up to date if visibility changes
2115 if (m_style->visibility() != style->visibility()) {
2116 RenderLayer* l = enclosingLayer();
2117 if (style->visibility() == VISIBLE && l)
2118 l->setHasVisibleContent(true);
2119 else if (l && l->hasVisibleContent() &&
2120 (this == l->renderer() || l->renderer()->style()->visibility() != VISIBLE))
2121 l->dirtyVisibleContentStatus();
2125 d = m_style->diff(style);
2127 // If we have no layer(), just treat a RepaintLayer hint as a normal Repaint.
2128 if (d == RenderStyle::RepaintLayer && !layer())
2129 d = RenderStyle::Repaint;
2131 // The background of the root element or the body element could propagate up to
2132 // the canvas. Just dirty the entire canvas when our style changes substantially.
2133 if (d >= RenderStyle::Repaint && element() &&
2134 (element()->hasTagName(htmlTag) || element()->hasTagName(bodyTag)))
2136 else if (m_parent && !isText()) {
2137 // Do a repaint with the old style first, e.g., for example if we go from
2138 // having an outline to not having an outline.
2139 if (d == RenderStyle::RepaintLayer) {
2140 layer()->repaintIncludingDescendants();
2141 if (!(m_style->clip() == style->clip()))
2142 layer()->clearClipRects();
2143 } else if (d == RenderStyle::Repaint || style->outlineSize() < m_style->outlineSize())
2147 // When a layout hint happens, we go ahead and do a repaint of the layer, since the layer could
2148 // end up being destroyed.
2149 if (d == RenderStyle::Layout && layer() &&
2150 (m_style->position() != style->position() ||
2151 m_style->zIndex() != style->zIndex() ||
2152 m_style->hasAutoZIndex() != style->hasAutoZIndex() ||
2153 !(m_style->clip() == style->clip()) ||
2154 m_style->hasClip() != style->hasClip() ||
2155 m_style->opacity() != style->opacity()))
2156 layer()->repaintIncludingDescendants();
2158 // When a layout hint happens and an object's position style changes, we have to do a layout
2159 // to dirty the render tree using the old position value now.
2160 if (d == RenderStyle::Layout && m_parent && m_style->position() != style->position()) {
2161 markContainingBlocksForLayout();
2162 if (m_style->position() == StaticPosition)
2164 if (isRenderBlock()) {
2165 if (style->position() == StaticPosition) {
2166 // Clear our positioned objects list. Our absolutely positioned descendants will be
2167 // inserted into our containing block's positioned objects list during layout.
2168 removePositionedObjects(0);
2169 } else if (m_style->position() == StaticPosition) {
2170 // Remove our absolutely positioned descendants from their current containing block.
2171 // They will be inserted into our positioned objects list during layout.
2172 RenderObject* cb = parent();
2173 while (cb && (cb->style()->position() == StaticPosition || (cb->isInline() && !cb->isReplaced())) && !cb->isRoot() && !cb->isRenderView()) {
2174 if (cb->style()->position() == RelativePosition && cb->isInline() && !cb->isReplaced()) {
2175 cb = cb->containingBlock();
2180 cb->removePositionedObjects(static_cast<RenderBlock*>(this));
2185 if (isFloating() && (m_style->floating() != style->floating()))
2186 // For changes in float styles, we need to conceivably remove ourselves
2187 // from the floating objects list.
2188 removeFromObjectLists();
2189 else if (isPositioned() && (style->position() != AbsolutePosition && style->position() != FixedPosition))
2190 // For changes in positioning styles, we need to conceivably remove ourselves
2191 // from the positioned objects list.
2192 removeFromObjectLists();
2194 affectsParentBlock = m_style && isFloatingOrPositioned() &&
2195 (!style->isFloating() && style->position() != AbsolutePosition && style->position() != FixedPosition)
2196 && parent() && (parent()->isBlockFlow() || parent()->isInlineFlow());
2198 // reset style flags
2200 m_positioned = false;
2201 m_relPositioned = false;
2202 m_paintBackground = false;
2203 m_hasOverflowClip = false;
2206 if (view()->frameView()) {
2207 // FIXME: A better solution would be to only invalidate the fixed regions when scrolling. It's overkill to
2208 // prevent the entire view from blitting on a scroll.
2209 bool oldStyleSlowScroll = style && (style->position() == FixedPosition || style->hasFixedBackgroundImage());
2210 bool newStyleSlowScroll = m_style && (m_style->position() == FixedPosition || m_style->hasFixedBackgroundImage());
2211 if (oldStyleSlowScroll != newStyleSlowScroll) {
2212 if (oldStyleSlowScroll)
2213 view()->frameView()->removeSlowRepaintObject();
2214 if (newStyleSlowScroll)
2215 view()->frameView()->addSlowRepaintObject();
2219 RenderStyle *oldStyle = m_style;
2222 updateBackgroundImages(oldStyle);
2228 oldStyle->deref(renderArena());
2230 setShouldPaintBackgroundOrBorder(m_style->hasBorder() || m_style->hasBackground() || m_style->hasAppearance());
2232 if (affectsParentBlock)
2233 handleDynamicFloatPositionChange();
2235 // No need to ever schedule repaints from a style change of a text run, since
2236 // we already did this for the parent of the text run.
2237 if (d == RenderStyle::Layout && m_parent)
2238 setNeedsLayoutAndMinMaxRecalc();
2239 else if (m_parent && !isText() && (d == RenderStyle::RepaintLayer || d == RenderStyle::Repaint))
2240 // Do a repaint with the new style now, e.g., for example if we go from
2241 // not having an outline to having an outline.
2245 void RenderObject::setStyleInternal(RenderStyle* st)
2250 m_style->deref(renderArena());
2256 void RenderObject::updateBackgroundImages(RenderStyle* oldStyle)
2258 // FIXME: This will be slow when a large number of images is used. Fix by using a dict.
2259 const BackgroundLayer* oldLayers = oldStyle ? oldStyle->backgroundLayers() : 0;
2260 const BackgroundLayer* newLayers = m_style ? m_style->backgroundLayers() : 0;
2261 for (const BackgroundLayer* currOld = oldLayers; currOld; currOld = currOld->next()) {
2262 if (currOld->backgroundImage() && (!newLayers || !newLayers->containsImage(currOld->backgroundImage())))
2263 currOld->backgroundImage()->deref(this);
2265 for (const BackgroundLayer* currNew = newLayers; currNew; currNew = currNew->next()) {
2266 if (currNew->backgroundImage() && (!oldLayers || !oldLayers->containsImage(currNew->backgroundImage())))
2267 currNew->backgroundImage()->ref(this);
2270 CachedImage* oldBorderImage = oldStyle ? oldStyle->borderImage().image() : 0;
2271 CachedImage* newBorderImage = m_style ? m_style->borderImage().image() : 0;
2272 if (oldBorderImage != newBorderImage) {
2274 oldBorderImage->deref(this);
2276 newBorderImage->ref(this);
2280 IntRect RenderObject::viewRect() const
2282 return view()->viewRect();
2285 bool RenderObject::absolutePosition(int &xPos, int &yPos, bool f)
2287 RenderObject* o = parent();
2289 o->absolutePosition(xPos, yPos, f);
2290 yPos += o->borderTopExtra();
2291 if (o->hasOverflowClip())
2292 o->layer()->subtractScrollOffset(xPos, yPos);
2302 IntRect RenderObject::caretRect(int offset, EAffinity affinity, int *extraWidthToEndOfLine)
2304 if (extraWidthToEndOfLine)
2305 *extraWidthToEndOfLine = 0;
2310 int RenderObject::paddingTop() const
2313 Length padding = m_style->paddingTop();
2314 if (padding.isPercent())
2315 w = containingBlock()->contentWidth();
2316 w = padding.calcMinValue(w);
2317 if ( isTableCell() && padding.isAuto() )
2318 w = static_cast<const RenderTableCell *>(this)->table()->cellPadding();
2322 int RenderObject::paddingBottom() const
2325 Length padding = style()->paddingBottom();
2326 if (padding.isPercent())
2327 w = containingBlock()->contentWidth();
2328 w = padding.calcMinValue(w);
2329 if ( isTableCell() && padding.isAuto() )
2330 w = static_cast<const RenderTableCell *>(this)->table()->cellPadding();
2334 int RenderObject::paddingLeft() const
2337 Length padding = style()->paddingLeft();
2338 if (padding.isPercent())
2339 w = containingBlock()->contentWidth();
2340 w = padding.calcMinValue(w);
2341 if ( isTableCell() && padding.isAuto() )
2342 w = static_cast<const RenderTableCell *>(this)->table()->cellPadding();
2346 int RenderObject::paddingRight() const
2349 Length padding = style()->paddingRight();
2350 if (padding.isPercent())
2351 w = containingBlock()->contentWidth();
2352 w = padding.calcMinValue(w);
2353 if ( isTableCell() && padding.isAuto() )
2354 w = static_cast<const RenderTableCell *>(this)->table()->cellPadding();
2358 int RenderObject::tabWidth() const
2360 if (style()->collapseWhiteSpace())
2363 return containingBlock()->tabWidth(true);
2366 RenderView* RenderObject::view() const
2368 return static_cast<RenderView*>(document()->renderer());
2371 RenderObject *RenderObject::container() const
2373 // This method is extremely similar to containingBlock(), but with a few notable
2375 // (1) It can be used on orphaned subtrees, i.e., it can be called safely even when
2376 // the object is not part of the primary document subtree yet.
2377 // (2) For normal flow elements, it just returns the parent.
2378 // (3) For absolute positioned elements, it will return a relative positioned inline.
2379 // containingBlock() simply skips relpositioned inlines and lets an enclosing block handle
2380 // the layout of the positioned object. This does mean that calcAbsoluteHorizontal and
2381 // calcAbsoluteVertical have to use container().
2382 EPosition pos = m_style->position();
2383 RenderObject *o = 0;
2384 if (!isText() && pos == FixedPosition) {
2385 // container() can be called on an object that is not in the
2386 // tree yet. We don't call view() since it will assert if it
2387 // can't get back to the canvas. Instead we just walk as high up
2388 // as we can. If we're in the tree, we'll get the root. If we
2389 // aren't we'll get the root of our little subtree (most likely
2390 // we'll just return 0).
2392 while (o && o->parent()) o = o->parent();
2394 else if (!isText() && pos == AbsolutePosition) {
2395 // Same goes here. We technically just want our containing block, but
2396 // we may not have one if we're part of an uninstalled subtree. We'll
2397 // climb as high as we can though.
2399 while (o && o->style()->position() == StaticPosition && !o->isRoot() && !o->isRenderView())
2407 // This code has been written to anticipate the addition of CSS3-::outside and ::inside generated
2408 // content (and perhaps XBL). That's why it uses the render tree and not the DOM tree.
2409 RenderObject* RenderObject::hoverAncestor() const
2411 return (!isInline() && continuation()) ? continuation() : parent();
2414 bool RenderObject::isSelectionBorder() const
2416 SelectionState st = selectionState();
2417 return st == SelectionStart || st == SelectionEnd || st == SelectionBoth;
2421 void RenderObject::removeFromObjectLists()
2423 if (documentBeingDestroyed())
2427 RenderBlock* outermostBlock = containingBlock();
2428 for (RenderBlock* p = outermostBlock; p && !p->isRenderView(); p = p->containingBlock()) {
2429 if (p->containsFloat(this))
2434 outermostBlock->markAllDescendantsWithFloatsForLayout(this);
2437 if (isPositioned()) {
2439 for (p = parent(); p; p = p->parent()) {
2440 if (p->isRenderBlock())
2441 static_cast<RenderBlock*>(p)->removePositionedObject(this);
2446 RenderArena* RenderObject::renderArena() const
2448 Document* doc = document();
2449 return doc ? doc->renderArena() : 0;
2452 bool RenderObject::documentBeingDestroyed() const
2454 return !document()->renderer();
2457 void RenderObject::destroy()
2459 // If this renderer is being autoscrolled, stop the autoscroll timer
2460 if (document() && document()->frame() && document()->frame()->autoscrollRenderer() == this)
2461 document()->frame()->stopAutoscrollTimer();
2463 if (m_hasCounterNodeMap) {
2464 RenderObjectsToCounterNodeMaps* objectsMap = getRenderObjectsToCounterNodeMaps();
2465 if (CounterNodeMap* counterNodesMap = objectsMap->get(this)) {
2466 CounterNodeMap::const_iterator end = counterNodesMap->end();
2467 for (CounterNodeMap::const_iterator it = counterNodesMap->begin(); it != end; ++it) {
2468 CounterNode* counterNode = it->second;
2469 counterNode->remove();
2473 objectsMap->remove(this);
2474 delete counterNodesMap;
2478 document()->axObjectCache()->remove(this);
2480 // By default no ref-counting. RenderWidget::destroy() doesn't call
2481 // this function because it needs to do ref-counting. If anything
2482 // in this function changes, be sure to fix RenderWidget::destroy() as well.
2486 arenaDelete(document()->renderArena(), this);
2489 void RenderObject::arenaDelete(RenderArena *arena, void *base)
2491 if (m_style->backgroundImage())
2492 m_style->backgroundImage()->deref(this);
2494 m_style->deref(arena);
2497 void *savedBase = baseOfRenderObjectBeingDeleted;
2498 baseOfRenderObjectBeingDeleted = base;
2502 baseOfRenderObjectBeingDeleted = savedBase;
2505 // Recover the size left there for us by operator delete and free the memory.
2506 arena->free(*(size_t *)base, base);
2509 VisiblePosition RenderObject::positionForCoordinates(int x, int y)
2511 return VisiblePosition(element(), caretMinOffset(), DOWNSTREAM);
2514 bool RenderObject::isDragging() const
2516 return m_isDragging;
2519 void RenderObject::updateDragState(bool dragOn)
2521 bool valueChanged = (dragOn != m_isDragging);
2522 m_isDragging = dragOn;
2523 if (valueChanged && style()->affectedByDragRules())
2524 element()->setChanged();
2525 for (RenderObject* curr = firstChild(); curr; curr = curr->nextSibling())
2526 curr->updateDragState(dragOn);
2528 continuation()->updateDragState(dragOn);
2531 bool RenderObject::hitTest(NodeInfo& info, int x, int y, int tx, int ty, HitTestFilter hitTestFilter)
2533 bool inside = false;
2534 if (hitTestFilter != HitTestSelf) {
2535 // First test the foreground layer (lines and inlines).
2536 inside = nodeAtPoint(info, x, y, tx, ty, HitTestForeground);
2538 // Test floats next.
2540 inside = nodeAtPoint(info, x, y, tx, ty, HitTestFloat);
2542 // Finally test to see if the mouse is in the background (within a child block's background).
2544 inside = nodeAtPoint(info, x, y, tx, ty, HitTestChildBlockBackgrounds);
2547 // See if the mouse is inside us but not any of our descendants
2548 if (hitTestFilter != HitTestDescendants && !inside)
2549 inside = nodeAtPoint(info, x, y, tx, ty, HitTestBlockBackground);
2554 void RenderObject::setInnerNode(NodeInfo& info)
2556 if (!info.innerNode() && !isInline() && continuation()) {
2557 // We are in the margins of block elements that are part of a continuation. In
2558 // this case we're actually still inside the enclosing inline element that was
2559 // split. Go ahead and set our inner node accordingly.
2560 info.setInnerNode(continuation()->element());
2561 if (!info.innerNonSharedNode())
2562 info.setInnerNonSharedNode(continuation()->element());
2565 if (!info.innerNode() && element())
2566 info.setInnerNode(element());
2568 if(!info.innerNonSharedNode() && element())
2569 info.setInnerNonSharedNode(element());
2572 bool RenderObject::nodeAtPoint(NodeInfo& info, int _x, int _y, int _tx, int _ty,
2573 HitTestAction hitTestAction)
2578 short RenderObject::verticalPositionHint( bool firstLine ) const
2580 short vpos = m_verticalPosition;
2581 if ( m_verticalPosition == PositionUndefined || firstLine ) {
2582 vpos = getVerticalPosition( firstLine );
2584 m_verticalPosition = vpos;
2590 short RenderObject::getVerticalPosition( bool firstLine ) const
2595 // This method determines the vertical position for inline elements.
2597 EVerticalAlign va = style()->verticalAlign();
2600 } else if ( va == BOTTOM ) {
2601 vpos = PositionBottom;
2602 } else if ( va == LENGTH ) {
2603 vpos = -style()->verticalAlignLength().calcValue( lineHeight( firstLine ) );
2605 bool checkParent = parent()->isInline() && !parent()->isInlineBlockOrInlineTable() && parent()->style()->verticalAlign() != TOP && parent()->style()->verticalAlign() != BOTTOM;
2606 vpos = checkParent ? parent()->verticalPositionHint( firstLine ) : 0;
2607 // don't allow elements nested inside text-top to have a different valignment.
2608 if ( va == BASELINE )
2611 const Font &f = parent()->font(firstLine);
2612 int fontsize = f.pixelSize();
2615 vpos += fontsize/5 + 1;
2616 else if (va == SUPER)
2617 vpos -= fontsize/3 + 1;
2618 else if (va == TEXT_TOP)
2619 vpos += baselinePosition(firstLine) - f.ascent();
2620 else if (va == MIDDLE)
2621 vpos += - (int)(f.xHeight()/2) - lineHeight( firstLine )/2 + baselinePosition( firstLine );
2622 else if (va == TEXT_BOTTOM) {
2623 vpos += f.descent();
2625 vpos -= font(firstLine).descent();
2626 } else if ( va == BASELINE_MIDDLE )
2627 vpos += - lineHeight( firstLine )/2 + baselinePosition( firstLine );
2633 short RenderObject::lineHeight( bool firstLine, bool ) const
2635 RenderStyle* s = style(firstLine);
2637 Length lh = s->lineHeight();
2639 // its "unset", choose nice default
2641 return s->font().lineSpacing();
2644 return lh.calcMinValue(s->fontSize());
2650 short RenderObject::baselinePosition(bool firstLine, bool isRootLineBox) const
2652 const Font& f = font(firstLine);
2653 return f.ascent() + (lineHeight(firstLine, isRootLineBox) - f.height()) / 2;
2656 void RenderObject::invalidateVerticalPositions()
2658 m_verticalPosition = PositionUndefined;
2659 RenderObject *child = firstChild();
2661 child->invalidateVerticalPositions();
2662 child = child->nextSibling();
2666 void RenderObject::recalcMinMaxWidths()
2668 ASSERT( m_recalcMinMax );
2671 kdDebug( 6040 ) << renderName() << " recalcMinMaxWidths() this=" << this <<endl;
2675 updateFirstLetter();
2677 RenderObject *child = firstChild();
2682 if ( ( m_minMaxKnown && child->m_recalcMinMax ) || !child->m_minMaxKnown ) {
2683 cmin = child->minWidth();
2684 cmax = child->maxWidth();
2687 if ( child->m_recalcMinMax )
2688 child->recalcMinMaxWidths();
2689 if ( !child->m_minMaxKnown )
2690 child->calcMinMaxWidth();
2691 if ( m_minMaxKnown && test && (cmin != child->minWidth() || cmax != child->maxWidth()) )
2692 m_minMaxKnown = false;
2693 child = child->nextSibling();
2696 // we need to recalculate, if the contains inline children, as the change could have
2697 // happened somewhere deep inside the child tree. Also do this for blocks or tables that
2698 // are inline (i.e., inline-block and inline-table).
2699 if ((!isInline() || isInlineBlockOrInlineTable()) && childrenInline())
2700 m_minMaxKnown = false;
2702 if ( !m_minMaxKnown )
2704 m_recalcMinMax = false;
2707 void RenderObject::scheduleRelayout()
2709 if (isRenderView()) {
2710 FrameView* view = static_cast<RenderView*>(this)->frameView();
2712 view->scheduleRelayout();
2714 FrameView* v = view() ? view()->frameView() : 0;
2716 v->scheduleRelayoutOfSubtree(node());
2721 void RenderObject::removeLeftoverAnonymousBoxes()
2725 InlineBox* RenderObject::createInlineBox(bool, bool isRootLineBox, bool)
2727 ASSERT(!isRootLineBox);
2728 return new (renderArena()) InlineBox(this);
2731 void RenderObject::dirtyLineBoxes(bool, bool)
2735 InlineBox* RenderObject::inlineBoxWrapper() const
2740 void RenderObject::setInlineBoxWrapper(InlineBox* b)
2744 void RenderObject::deleteLineBoxWrapper()
2748 RenderStyle* RenderObject::firstLineStyle() const
2750 RenderStyle *s = m_style;
2751 const RenderObject* obj = isText() ? parent() : this;
2752 if (obj->isBlockFlow()) {
2753 RenderBlock* firstLineBlock = obj->firstLineBlock();
2755 s = firstLineBlock->getPseudoStyle(RenderStyle::FIRST_LINE, style());
2756 } else if (!obj->isAnonymous() && obj->isInlineFlow()) {
2757 RenderStyle* parentStyle = obj->parent()->firstLineStyle();
2758 if (parentStyle != obj->parent()->style()) {
2759 // A first-line style is in effect. We need to cache a first-line style
2761 style()->setHasPseudoStyle(RenderStyle::FIRST_LINE_INHERITED);
2762 s = obj->getPseudoStyle(RenderStyle::FIRST_LINE_INHERITED, parentStyle);
2768 RenderStyle* RenderObject::getPseudoStyle(RenderStyle::PseudoId pseudo, RenderStyle* parentStyle) const
2770 if (!style()->hasPseudoStyle(pseudo))
2774 parentStyle = style();
2776 RenderStyle* result = style()->getPseudoStyle(pseudo);
2780 Node* node = element();
2782 node = element()->parentNode();
2786 if (pseudo == RenderStyle::FIRST_LINE_INHERITED) {
2787 result = document()->styleSelector()->styleForElement(static_cast<Element*>(node), parentStyle, false);
2788 result->setStyleType(RenderStyle::FIRST_LINE_INHERITED);
2790 result = document()->styleSelector()->pseudoStyleForElement(pseudo, static_cast<Element*>(node), parentStyle);
2792 style()->addPseudoStyle(result);
2793 result->deref(document()->renderArena());
2798 void RenderObject::getTextDecorationColors(int decorations, Color& underline, Color& overline,
2799 Color& linethrough, bool quirksMode)
2801 RenderObject* curr = this;
2803 int currDecs = curr->style()->textDecoration();
2805 if (currDecs & UNDERLINE) {
2806 decorations &= ~UNDERLINE;
2807 underline = curr->style()->color();
2809 if (currDecs & OVERLINE) {
2810 decorations &= ~OVERLINE;
2811 overline = curr->style()->color();
2813 if (currDecs & LINE_THROUGH) {
2814 decorations &= ~LINE_THROUGH;
2815 linethrough = curr->style()->color();
2818 curr = curr->parent();
2819 if (curr && curr->isRenderBlock() && curr->continuation())
2820 curr = curr->continuation();
2821 } while (curr && decorations && (!quirksMode || !curr->element() ||
2822 (!curr->element()->hasTagName(aTag) && !curr->element()->hasTagName(fontTag))));
2824 // If we bailed out, use the element we bailed out at (typically a <font> or <a> element).
2825 if (decorations && curr) {
2826 if (decorations & UNDERLINE)
2827 underline = curr->style()->color();
2828 if (decorations & OVERLINE)
2829 overline = curr->style()->color();
2830 if (decorations & LINE_THROUGH)
2831 linethrough = curr->style()->color();
2835 void RenderObject::updateWidgetPosition()
2839 void RenderObject::addDashboardRegions(Vector<DashboardRegionValue>& regions)
2841 // Convert the style regions to absolute coordinates.
2842 if (style()->visibility() != VISIBLE)
2845 const Vector<StyleDashboardRegion>& styleRegions = style()->dashboardRegions();
2846 unsigned i, count = styleRegions.size();
2847 for (i = 0; i < count; i++){
2848 StyleDashboardRegion styleRegion = styleRegions[i];
2853 DashboardRegionValue region;
2854 region.label = styleRegion.label;
2855 region.bounds = IntRect (
2856 styleRegion.offset.left.value(),
2857 styleRegion.offset.top.value(),
2858 w - styleRegion.offset.left.value() - styleRegion.offset.right.value(),
2859 h - styleRegion.offset.top.value() - styleRegion.offset.bottom.value());
2860 region.type = styleRegion.type;
2862 region.clip = region.bounds;
2863 computeAbsoluteRepaintRect(region.clip);
2864 if (region.clip.height() < 0) {
2865 region.clip.setHeight(0);
2866 region.clip.setWidth(0);
2870 absolutePosition(x, y);
2871 region.bounds.setX(x + styleRegion.offset.left.value());
2872 region.bounds.setY(y + styleRegion.offset.top.value());
2874 if (document()->frame()) {
2875 float pageScaleFactor = scaleFactor(document()->frame()->page());
2876 if (pageScaleFactor != 1.0f) {
2877 region.bounds.scale(pageScaleFactor);
2878 region.clip.scale(pageScaleFactor);
2882 regions.append(region);
2886 void RenderObject::collectDashboardRegions(Vector<DashboardRegionValue>& regions)
2888 // RenderTexts don't have their own style, they just use their parent's style,
2889 // so we don't want to include them.
2893 addDashboardRegions(regions);
2894 for (RenderObject* curr = firstChild(); curr; curr = curr->nextSibling())
2895 curr->collectDashboardRegions(regions);
2899 void RenderObject::collectBorders(DeprecatedValueList<CollapsedBorderValue>& borderStyles)
2901 for (RenderObject* curr = firstChild(); curr; curr = curr->nextSibling())
2902 curr->collectBorders(borderStyles);
2905 bool RenderObject::avoidsFloats() const
2907 return isReplaced() || hasOverflowClip() || isHR();
2910 bool RenderObject::usesLineWidth() const
2912 // 1. All auto-width objects that avoid floats should always use lineWidth
2913 // 2. For objects with a specified width, we match WinIE's behavior:
2914 // (a) tables use contentWidth
2915 // (b) <hr>s use lineWidth
2916 // (c) all other objects use lineWidth in quirks mode and contentWidth in strict mode.
2917 return (avoidsFloats() && (style()->width().isAuto() || isHR() || (style()->htmlHacks() && !isTable())));
2920 CounterNode* RenderObject::findCounter(const String& counterName, bool willNeedLayout,
2921 bool usesSeparator, bool createIfNotFound)
2926 RenderObjectsToCounterNodeMaps* objectsMap = getRenderObjectsToCounterNodeMaps();
2927 CounterNode* newNode = 0;
2928 if (CounterNodeMap* counterNodesMap = objectsMap->get(this))
2929 if (counterNodesMap)
2930 newNode = counterNodesMap->get(counterName);
2936 if (style()->hasCounterReset(counterName) || isRoot()) {
2937 newNode = new CounterResetNode(this);
2938 val = style()->counterReset(counterName);
2939 if (style()->hasCounterIncrement(counterName))
2940 val += style()->counterIncrement(counterName);
2941 newNode->setValue(val);
2942 } else if (style()->hasCounterIncrement(counterName)) {
2943 newNode = new CounterNode(this);
2944 newNode->setValue(style()->counterIncrement(counterName));
2945 } else if (counterName == "list-item") {
2948 String v = static_cast<Element*>(element())->getAttribute("value");
2950 newNode = new CounterResetNode(this);
2956 newNode = new CounterNode(this);
2960 newNode->setValue(val);
2961 } else if (element() && element()->hasTagName(olTag)) {
2962 newNode = new CounterResetNode(this);
2963 newNode->setValue(static_cast<HTMLOListElement*>(element())->start());
2964 } else if (element() &&
2965 (element()->hasTagName(ulTag) ||
2966 element()->hasTagName(menuTag) ||
2967 element()->hasTagName(dirTag))) {
2968 newNode = new CounterResetNode(this);
2969 newNode->setValue(0);
2973 if (!newNode && !createIfNotFound)
2975 else if (!newNode) {
2976 newNode = new CounterNode(this);
2977 newNode->setValue(0);
2981 newNode->setWillNeedLayout();
2983 newNode->setUsesSeparator();
2985 CounterNodeMap* nodeMap;
2986 if (m_hasCounterNodeMap)
2987 nodeMap = objectsMap->get(this);
2989 nodeMap = new CounterNodeMap;
2990 objectsMap->set(this, nodeMap);
2991 m_hasCounterNodeMap = true;
2994 nodeMap->set(counterName, newNode);
2997 RenderObject* n = !isListItem() && previousSibling()
2998 ? previousSibling()->previousSibling() : previousSibling();
3000 CounterNode* current = 0;
3001 for (; n; n = n->previousSibling()) {
3002 current = n->findCounter(counterName, false, false, false);
3007 CounterNode* last = current;
3008 CounterNode* sibling = current;
3009 if (last && !newNode->isReset()) {
3010 // Found render-sibling, now search for later counter-siblings among its render-children
3013 current = n->findCounter(counterName, false, false, false);
3014 if (current && (last->parent() == current->parent() || sibling == current->parent())) {
3016 // If the current counter is not the last, search deeper
3017 if (current->nextSibling()) {
3023 n = n->previousSibling();
3026 if (sibling->isReset()) {
3027 if (last != sibling)
3028 sibling->insertAfter(newNode, last);
3030 sibling->insertAfter(newNode, 0);
3032 last->parent()->insertAfter(newNode, last);
3034 // Nothing found among siblings, let our parent search
3035 last = parent()->findCounter(counterName, false);
3036 if (last->isReset())
3037 last->insertAfter(newNode, 0);
3039 last->parent()->insertAfter(newNode, last);
3046 UChar RenderObject::backslashAsCurrencySymbol() const
3048 if (Node *node = element())
3049 if (Decoder *decoder = node->document()->decoder())
3050 return decoder->encoding().backslashAsCurrencySymbol();
3054 void RenderObject::imageChanged(CachedImage *image)
3056 // Repaint when the background image or border image finishes loading.
3057 // This is needed for RenderBox objects, and also for table objects that hold
3058 // backgrounds that are then respected by the table cells (which are RenderBox
3059 // subclasses). It would be even better to find a more elegant way of doing this that
3060 // would avoid putting this function and the CachedResourceClient base class into RenderObject.
3061 if (image && image->canRender() && parent()) {
3062 if (view() && element() && (element()->hasTagName(htmlTag) || element()->hasTagName(bodyTag)))
3063 view()->repaint(); // repaint the entire canvas since the background gets propagated up
3065 repaint(); // repaint object, which is a box or a container with boxes inside it
3069 bool RenderObject::willRenderImage(CachedImage*)
3071 // Without visibility we won't render (and therefore don't care about animation).
3072 if (style()->visibility() != VISIBLE)
3075 // 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)
3076 // then we don't want to render either.
3077 return !document()->inPageCache() && document()->view()->inWindow();
3080 int RenderObject::maximalOutlineSize(PaintPhase p) const
3082 if (p != PaintPhaseOutline && p != PaintPhaseSelfOutline && p != PaintPhaseChildOutlines)
3084 return static_cast<RenderView*>(document()->renderer())->maximalOutlineSize();
3087 int RenderObject::caretMinOffset() const
3092 int RenderObject::caretMaxOffset() const
3094 return isReplaced() ? 1 : 0;
3097 unsigned RenderObject::caretMaxRenderedOffset() const
3102 int RenderObject::previousOffset (int current) const
3104 int previousOffset = current - 1;
3105 return previousOffset;
3108 int RenderObject::nextOffset (int current) const
3110 int nextOffset = current + 1;
3114 InlineBox *RenderObject::inlineBox(int offset, EAffinity affinity)
3116 return inlineBoxWrapper();
3121 FloatRect RenderObject::relativeBBox(bool) const
3126 AffineTransform RenderObject::localTransform() const
3128 return AffineTransform(1, 0, 0, 1, xPos(), yPos());
3131 void RenderObject::setLocalTransform(const AffineTransform&)
3136 AffineTransform RenderObject::absoluteTransform() const
3139 return localTransform() * parent()->absoluteTransform();
3140 return localTransform();
3149 void showTree(const WebCore::RenderObject* ro)
3152 ro->showTreeForThis();