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"
35 #include "TextResourceDecoder.h"
38 #include "EventNames.h"
39 #include "FloatRect.h"
41 #include "GraphicsContext.h"
42 #include "HTMLNames.h"
43 #include "HTMLOListElement.h"
45 #include "HitTestRequest.h"
46 #include "HitTestResult.h"
48 #include "RenderArena.h"
49 #include "RenderFlexibleBox.h"
50 #include "RenderImage.h"
51 #include "RenderInline.h"
52 #include "RenderListItem.h"
53 #include "RenderTableCell.h"
54 #include "RenderTableCol.h"
55 #include "RenderTableRow.h"
56 #include "RenderText.h"
57 #include "RenderTheme.h"
58 #include "RenderView.h"
60 #include "TextStream.h"
61 #include "cssstyleselector.h"
68 using namespace EventNames;
69 using namespace HTMLNames;
72 static void *baseOfRenderObjectBeingDeleted;
75 typedef HashMap<String, CounterNode*> CounterNodeMap;
76 typedef HashMap<const RenderObject*, CounterNodeMap*> RenderObjectsToCounterNodeMaps;
78 static RenderObjectsToCounterNodeMaps* getRenderObjectsToCounterNodeMaps()
80 static RenderObjectsToCounterNodeMaps objectsMap;
84 void* RenderObject::operator new(size_t sz, RenderArena* renderArena) throw()
86 return renderArena->allocate(sz);
89 void RenderObject::operator delete(void* ptr, size_t sz)
91 ASSERT(baseOfRenderObjectBeingDeleted == ptr);
93 // Stash size where destroy can find it.
97 RenderObject *RenderObject::createObject(Node* node, RenderStyle* style)
100 RenderArena* arena = node->document()->renderArena();
102 if (ContentData *contentData = style->contentData()) {
103 RenderImage *contentImage = new (arena) RenderImage(node);
105 contentImage->setStyle(style);
106 contentImage->setContentObject(contentData->contentObject());
107 contentImage->setIsAnonymousImage(true);
112 switch(style->display())
117 o = new (arena) RenderInline(node);
120 o = new (arena) RenderBlock(node);
123 o = new (arena) RenderBlock(node);
126 o = new (arena) RenderListItem(node);
130 o = new (arena) RenderBlock(node);
134 o = new (arena) RenderTable(node);
136 case TABLE_ROW_GROUP:
137 case TABLE_HEADER_GROUP:
138 case TABLE_FOOTER_GROUP:
139 o = new (arena) RenderTableSection(node);
142 o = new (arena) RenderTableRow(node);
144 case TABLE_COLUMN_GROUP:
146 o = new (arena) RenderTableCol(node);
149 o = new (arena) RenderTableCell(node);
152 o = new (arena) RenderBlock(node);
156 o = new (arena) RenderFlexibleBox(node);
163 struct RenderObjectCounter {
165 ~RenderObjectCounter() { if (count != 0) fprintf(stderr, "LEAK: %d RenderObject\n", count); }
167 int RenderObjectCounter::count;
168 static RenderObjectCounter renderObjectCounter;
171 RenderObject::RenderObject(Node* node)
172 : CachedResourceClient(),
178 m_verticalPosition( PositionUndefined ),
179 m_needsLayout( false ),
180 m_normalChildNeedsLayout( false ),
181 m_posChildNeedsLayout( false ),
182 m_minMaxKnown( false ),
185 m_positioned( false ),
186 m_relPositioned( false ),
187 m_paintBackground( false ),
189 m_isAnonymous( node == node->document() ),
190 m_recalcMinMax( false ),
195 m_isDragging( false ),
196 m_hasOverflowClip(false),
197 m_hasCounterNodeMap(false)
200 ++RenderObjectCounter::count;
204 RenderObject::~RenderObject()
207 --RenderObjectCounter::count;
211 bool RenderObject::isDescendantOf(const RenderObject *obj) const
213 for (const RenderObject *r = this; r; r = r->m_parent)
219 bool RenderObject::isRoot() const
221 return element() && element()->renderer() == this &&
222 element()->document()->documentElement() == element();
225 bool RenderObject::isBody() const
227 return element() && element()->renderer() == this && element()->hasTagName(bodyTag);
230 bool RenderObject::isHR() const
232 return element() && element()->hasTagName(hrTag);
235 bool RenderObject::isHTMLMarquee() const
237 return element() && element()->renderer() == this && element()->hasTagName(marqueeTag);
240 bool RenderObject::canHaveChildren() const
245 RenderFlow* RenderObject::continuation() const
250 bool RenderObject::isInlineContinuation() const
255 void RenderObject::addChild(RenderObject* , RenderObject *)
260 RenderObject* RenderObject::removeChildNode(RenderObject* )
266 void RenderObject::removeChild(RenderObject* )
271 void RenderObject::appendChildNode(RenderObject*)
276 void RenderObject::insertChildNode(RenderObject*, RenderObject*)
281 RenderObject *RenderObject::nextInPreOrder() const
283 if (RenderObject* o = firstChild())
286 return nextInPreOrderAfterChildren();
289 RenderObject* RenderObject::nextInPreOrderAfterChildren() const
292 if (!(o = nextSibling())) {
294 while (o && !o->nextSibling())
297 o = o->nextSibling();
302 RenderObject *RenderObject::previousInPreOrder() const
304 if (RenderObject* o = previousSibling()) {
305 while (o->lastChild())
313 RenderObject* RenderObject::childAt(unsigned index) const
315 RenderObject* child = firstChild();
316 for (unsigned i = 0; child && i < index; i++)
317 child = child->nextSibling();
321 bool RenderObject::isEditable() const
323 RenderText *textRenderer = 0;
325 textRenderer = static_cast<RenderText *>(const_cast<RenderObject *>(this));
328 return style()->visibility() == VISIBLE &&
329 element() && element()->isContentEditable() &&
330 ((isBlockFlow() && !firstChild()) ||
333 (textRenderer && textRenderer->firstTextBox()));
336 RenderObject *RenderObject::nextEditable() const
338 RenderObject *r = const_cast<RenderObject *>(this);
339 RenderObject *n = firstChild();
348 return r->nextEditable();
350 n = r->nextSibling();
360 return r->nextEditable();
365 n = r->nextSibling();
376 return r->nextEditable();
383 RenderObject *RenderObject::previousEditable() const
385 RenderObject *r = const_cast<RenderObject *>(this);
386 RenderObject *n = firstChild();
395 return r->previousEditable();
397 n = r->previousSibling();
407 return r->previousEditable();
412 n = r->previousSibling();
423 return r->previousEditable();
430 RenderObject *RenderObject::firstLeafChild() const
432 RenderObject *r = firstChild();
443 RenderObject *RenderObject::lastLeafChild() const
445 RenderObject *r = lastChild();
456 static void addLayers(RenderObject* obj, RenderLayer* parentLayer, RenderObject*& newObject,
457 RenderLayer*& beforeChild)
460 if (!beforeChild && newObject) {
461 // We need to figure out the layer that follows newObject. We only do
462 // this the first time we find a child layer, and then we update the
463 // pointer values for newObject and beforeChild used by everyone else.
464 beforeChild = newObject->parent()->findNextLayer(parentLayer, newObject);
467 parentLayer->addChild(obj->layer(), beforeChild);
471 for (RenderObject* curr = obj->firstChild(); curr; curr = curr->nextSibling())
472 addLayers(curr, parentLayer, newObject, beforeChild);
475 void RenderObject::addLayers(RenderLayer* parentLayer, RenderObject* newObject)
480 RenderObject* object = newObject;
481 RenderLayer* beforeChild = 0;
482 WebCore::addLayers(this, parentLayer, object, beforeChild);
485 void RenderObject::removeLayers(RenderLayer* parentLayer)
491 parentLayer->removeChild(layer());
495 for (RenderObject* curr = firstChild(); curr; curr = curr->nextSibling())
496 curr->removeLayers(parentLayer);
499 void RenderObject::moveLayers(RenderLayer* oldParent, RenderLayer* newParent)
506 oldParent->removeChild(layer());
507 newParent->addChild(layer());
511 for (RenderObject* curr = firstChild(); curr; curr = curr->nextSibling())
512 curr->moveLayers(oldParent, newParent);
515 RenderLayer* RenderObject::findNextLayer(RenderLayer* parentLayer, RenderObject* startPoint,
518 // Error check the parent layer passed in. If it's null, we can't find anything.
522 // Step 1: If our layer is a child of the desired parent, then return our layer.
523 RenderLayer* ourLayer = layer();
524 if (ourLayer && ourLayer->parent() == parentLayer)
527 // Step 2: If we don't have a layer, or our layer is the desired parent, then descend
528 // into our siblings trying to find the next layer whose parent is the desired parent.
529 if (!ourLayer || ourLayer == parentLayer) {
530 for (RenderObject* curr = startPoint ? startPoint->nextSibling() : firstChild();
531 curr; curr = curr->nextSibling()) {
532 RenderLayer* nextLayer = curr->findNextLayer(parentLayer, 0, false);
538 // Step 3: If our layer is the desired parent layer, then we're finished. We didn't
540 if (parentLayer == ourLayer)
543 // Step 4: If |checkParent| is set, climb up to our parent and check its siblings that
544 // follow us to see if we can locate a layer.
545 if (checkParent && parent())
546 return parent()->findNextLayer(parentLayer, this, true);
551 RenderLayer* RenderObject::enclosingLayer() const
553 const RenderObject* curr = this;
555 RenderLayer *layer = curr->layer();
558 curr = curr->parent();
563 bool RenderObject::requiresLayer()
565 return isRoot() || isPositioned() || isRelPositioned() || isTransparent() || hasOverflowClip();
568 RenderBlock* RenderObject::firstLineBlock() const
573 void RenderObject::updateFirstLetter()
576 int RenderObject::offsetLeft() const
578 RenderObject* offsetPar = offsetParent();
582 if (!isPositioned()) {
583 if (isRelPositioned())
584 x += static_cast<const RenderBox*>(this)->relativePositionOffsetX();
585 RenderObject* curr = parent();
586 while (curr && curr != offsetPar) {
588 curr = curr->parent();
594 int RenderObject::offsetTop() const
596 RenderObject* offsetPar = offsetParent();
600 if (!isPositioned()) {
601 if (isRelPositioned())
602 y += static_cast<const RenderBox*>(this)->relativePositionOffsetY();
603 RenderObject* curr = parent();
604 while (curr && curr != offsetPar) {
605 if (!curr->isTableRow())
607 curr = curr->parent();
613 RenderObject* RenderObject::offsetParent() const
615 // FIXME: It feels like this function could almost be written using containing blocks.
618 bool skipTables = isPositioned() || isRelPositioned();
619 RenderObject* curr = parent();
620 while (curr && (!curr->element() ||
621 (!curr->isPositioned() && !curr->isRelPositioned() &&
622 !(!style()->htmlHacks() && skipTables ? curr->isRoot() : curr->isBody())))) {
623 if (!skipTables && curr->element() && (curr->isTableCell() || curr->isTable()))
625 curr = curr->parent();
630 // More IE extensions. clientWidth and clientHeight represent the interior of an object
631 // excluding border and scrollbar.
632 int RenderObject::clientWidth() const
634 return width() - borderLeft() - borderRight() -
635 (includeVerticalScrollbarSize() ? layer()->verticalScrollbarWidth() : 0);
638 int RenderObject::clientHeight() const
640 return height() - borderTop() - borderBottom() -
641 (includeHorizontalScrollbarSize() ? layer()->horizontalScrollbarHeight() : 0);
644 // scrollWidth/scrollHeight will be the same as clientWidth/clientHeight unless the
645 // object has overflow:hidden/scroll/auto specified and also has overflow.
646 int RenderObject::scrollWidth() const
648 return hasOverflowClip() ? layer()->scrollWidth() : overflowWidth();
651 int RenderObject::scrollHeight() const
653 return hasOverflowClip() ? layer()->scrollHeight() : overflowHeight();
656 int RenderObject::scrollLeft() const
658 return hasOverflowClip() ? layer()->scrollXOffset() : 0;
661 int RenderObject::scrollTop() const
663 return hasOverflowClip() ? layer()->scrollYOffset() : 0;
666 void RenderObject::setScrollLeft(int newLeft)
668 if (hasOverflowClip())
669 layer()->scrollToXOffset(newLeft);
672 void RenderObject::setScrollTop(int newTop)
674 if (hasOverflowClip())
675 layer()->scrollToYOffset(newTop);
678 bool RenderObject::scroll(ScrollDirection direction, ScrollGranularity granularity, float multiplier)
680 RenderLayer *l = layer();
681 if (l && l->scroll(direction, granularity, multiplier))
683 RenderBlock *b = containingBlock();
684 if (b && !b->isRenderView())
685 return b->scroll(direction, granularity, multiplier);
689 bool RenderObject::shouldAutoscroll() const
691 return ((isRoot()) || (hasOverflowClip() && (scrollsOverflow() || (node() && node()->isContentEditable()))));
694 void RenderObject::autoscroll()
696 if (RenderLayer* l = layer())
700 bool RenderObject::hasStaticX() const
702 return (style()->left().isAuto() && style()->right().isAuto()) ||
703 style()->left().isStatic() ||
704 style()->right().isStatic();
707 bool RenderObject::hasStaticY() const
709 return (style()->top().isAuto() && style()->bottom().isAuto()) || style()->top().isStatic();
712 void RenderObject::markAllDescendantsWithFloatsForLayout(RenderObject*)
716 void RenderObject::setNeedsLayout(bool b, bool markParents)
718 bool alreadyNeededLayout = m_needsLayout;
721 if (!alreadyNeededLayout && markParents)
722 markContainingBlocksForLayout();
725 m_posChildNeedsLayout = false;
726 m_normalChildNeedsLayout = false;
730 void RenderObject::setChildNeedsLayout(bool b, bool markParents)
732 bool alreadyNeededLayout = m_normalChildNeedsLayout;
733 m_normalChildNeedsLayout = b;
735 if (!alreadyNeededLayout && markParents)
736 markContainingBlocksForLayout();
739 m_posChildNeedsLayout = false;
740 m_normalChildNeedsLayout = false;
744 void RenderObject::markContainingBlocksForLayout(bool scheduleRelayout)
746 RenderObject *o = container();
747 RenderObject *last = this;
750 if (!last->isText() && (last->style()->position() == FixedPosition || last->style()->position() == AbsolutePosition)) {
751 if (o->m_posChildNeedsLayout)
753 o->m_posChildNeedsLayout = true;
755 if (o->m_normalChildNeedsLayout)
757 o->m_normalChildNeedsLayout = true;
761 if (scheduleRelayout && (last->isTextField() || last->isTextArea()))
766 if (scheduleRelayout)
767 last->scheduleRelayout();
770 RenderBlock* RenderObject::containingBlock() const
773 return static_cast<const RenderTableCell *>(this)->table();
775 return (RenderBlock*)this;
777 RenderObject *o = parent();
778 if (!isText() && m_style->position() == FixedPosition) {
779 while ( o && !o->isRenderView() )
782 else if (!isText() && m_style->position() == AbsolutePosition) {
783 while (o && (o->style()->position() == StaticPosition || (o->isInline() && !o->isReplaced())) && !o->isRenderView()) {
784 // For relpositioned inlines, we return the nearest enclosing block. We don't try
785 // to return the inline itself. This allows us to avoid having a positioned objects
786 // list in all RenderInlines and lets us return a strongly-typed RenderBlock* result
787 // from this method. The container() method can actually be used to obtain the
789 if (o->style()->position() == RelativePosition && o->isInline() && !o->isReplaced())
790 return o->containingBlock();
794 while (o && ((o->isInline() && !o->isReplaced()) || o->isTableRow() || o->isTableSection()
795 || o->isTableCol() || o->isFrameSet()
797 || o->isKCanvasContainer()
803 if (!o || !o->isRenderBlock())
804 return 0; // Probably doesn't happen any more, but leave just in case. -dwh
806 return static_cast<RenderBlock*>(o);
809 int RenderObject::containingBlockWidth() const
812 return containingBlock()->contentWidth();
815 int RenderObject::containingBlockHeight() const
818 return containingBlock()->contentHeight();
821 bool RenderObject::mustRepaintBackgroundOrBorder() const
823 // If we don't have a background/border, then nothing to do.
824 if (!shouldPaintBackgroundOrBorder())
827 // Ok, let's check the background first.
828 const BackgroundLayer* bgLayer = style()->backgroundLayers();
830 return true; // Nobody will use multiple background layers without wanting fancy positioning.
832 // Make sure we have a valid background image.
833 CachedImage* bg = bgLayer->backgroundImage();
834 bool shouldPaintBackgroundImage = bg && bg->canRender();
836 // These are always percents or auto.
837 if (shouldPaintBackgroundImage &&
838 (bgLayer->backgroundXPosition().value() != 0 || bgLayer->backgroundYPosition().value() != 0
839 || bgLayer->backgroundSize().width.isPercent() || bgLayer->backgroundSize().height.isPercent()))
840 return true; // The background image will shift unpredictably if the size changes.
842 // Background is ok. Let's check border.
843 if (style()->hasBorder()) {
844 // Border images are not ok.
845 CachedImage* borderImage = style()->borderImage().image();
846 bool shouldPaintBorderImage = borderImage && borderImage->canRender();
847 if (shouldPaintBorderImage && borderImage->isLoaded())
848 return true; // If the image hasn't loaded, we're still using the normal border style.
854 void RenderObject::drawBorderArc(GraphicsContext* p, int x, int y, float thickness, IntSize radius, int angleStart,
855 int angleSpan, BorderSide s, Color c, const Color& textColor, EBorderStyle style, bool firstCorner)
857 if ((style == DOUBLE && ((thickness / 2) < 3)) ||
858 ((style == RIDGE || style == GROOVE) && ((thickness / 2) < 2)))
862 if (style == INSET || style == OUTSET || style == RIDGE || style == GROOVE)
863 c.setRGB(238, 238, 238);
873 p->setPen(Pen(c, thickness == 1 ? 0 : (int)thickness, Pen::DotLine));
876 p->setPen(Pen(c, thickness == 1 ? 0 : (int)thickness, Pen::DashLine));
879 if (s == BSBottom || s == BSTop)
880 p->drawArc(IntRect(x, y, radius.width() * 2, radius.height() * 2), thickness, angleStart, angleSpan);
881 else //We are drawing a left or right border
882 p->drawArc(IntRect(x, y, radius.width() * 2, radius.height() * 2), thickness, angleStart, angleSpan);
887 float third = thickness / 3;
888 float innerThird = (thickness + 1) / 6;
889 int shiftForInner = (int)(innerThird * 2.5);
890 p->setPen(Pen::NoPen);
893 int outerHeight = radius.height() * 2;
894 int innerX = x + shiftForInner;
895 int innerY = y + shiftForInner;
896 int innerWidth = (radius.width() - shiftForInner) * 2;
897 int innerHeight = (radius.height() - shiftForInner) * 2;
898 if (innerThird > 1 && (s == BSTop || (firstCorner && (s == BSLeft || s == BSRight)))) {
903 p->drawArc(IntRect(x, outerY, radius.width() * 2, outerHeight), third, angleStart, angleSpan);
904 p->drawArc(IntRect(innerX, innerY, innerWidth, innerHeight), (innerThird > 2) ? innerThird - 1 : innerThird,
905 angleStart, angleSpan);
911 if ((style == RIDGE && (s == BSTop || s == BSLeft)) ||
912 (style == GROOVE && (s == BSBottom || s == BSRight)))
919 p->setPen(Pen::NoPen);
920 p->setFillColor(c.rgb());
921 p->drawArc(IntRect(x, y, radius.width() * 2, radius.height() * 2), thickness, angleStart, angleSpan);
923 float halfThickness = (thickness + 1) / 4;
924 int shiftForInner = (int)(halfThickness * 1.5);
925 p->setFillColor(c2.rgb());
926 p->drawArc(IntRect(x + shiftForInner, y + shiftForInner, (radius.width() - shiftForInner) * 2,
927 (radius.height() - shiftForInner) * 2), (halfThickness > 2) ? halfThickness - 1 : halfThickness,
928 angleStart, angleSpan);
932 if(s == BSTop || s == BSLeft)
935 if(style == OUTSET && (s == BSBottom || s == BSRight))
938 p->setPen(Pen::NoPen);
939 p->setFillColor(c.rgb());
940 p->drawArc(IntRect(x, y, radius.width() * 2, radius.height() * 2), thickness, angleStart, angleSpan);
945 void RenderObject::drawBorder(GraphicsContext* p, int x1, int y1, int x2, int y2,
946 BorderSide s, Color c, const Color& textcolor, EBorderStyle style,
947 int adjbw1, int adjbw2)
949 int width = (s == BSTop || s == BSBottom ? y2 - y1 : x2 - x1);
951 if (style == DOUBLE && width < 3)
955 if (style == INSET || style == OUTSET || style == RIDGE || style == GROOVE)
956 c.setRGB(238, 238, 238);
967 p->setPen(Pen(c, width == 1 ? 0 : width, Pen::DotLine));
971 p->setPen(Pen(c, width == 1 ? 0 : width, Pen::DashLine));
978 p->drawLine(IntPoint(x1, (y1+y2)/2), IntPoint(x2, (y1+y2)/2));
982 p->drawLine(IntPoint((x1+x2)/2, y1), IntPoint((x1+x2)/2, y2));
990 int third = (width+1)/3;
992 if (adjbw1 == 0 && adjbw2 == 0)
994 p->setPen(Pen::NoPen);
995 p->setFillColor(c.rgb());
1000 p->drawRect(IntRect(x1, y1 , x2-x1, third));
1001 p->drawRect(IntRect(x1, y2-third, x2-x1, third));
1004 p->drawRect(IntRect(x1 , y1+1, third, y2-y1-1));
1005 p->drawRect(IntRect(x2-third, y1+1, third, y2-y1-1));
1008 p->drawRect(IntRect(x1 , y1+1, third, y2-y1-1));
1009 p->drawRect(IntRect(x2-third, y1+1, third, y2-y1-1));
1017 adjbw1bigthird = adjbw1+1;
1019 adjbw1bigthird = adjbw1 - 1;
1020 adjbw1bigthird /= 3;
1024 adjbw2bigthird = adjbw2 + 1;
1026 adjbw2bigthird = adjbw2 - 1;
1027 adjbw2bigthird /= 3;
1032 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);
1033 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);
1036 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);
1037 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);
1040 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);
1041 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);
1044 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);
1045 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);
1071 if (adjbw1>0) adjbw1bighalf=adjbw1+1;
1072 else adjbw1bighalf=adjbw1-1;
1075 if (adjbw2>0) adjbw2bighalf=adjbw2+1;
1076 else adjbw2bighalf=adjbw2-1;
1082 drawBorder(p, x1+max(-adjbw1 ,0)/2, y1 , x2-max(-adjbw2,0)/2, (y1+y2+1)/2, s, c, textcolor, s1, adjbw1bighalf, adjbw2bighalf);
1083 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);
1086 drawBorder(p, x1 , y1+max(-adjbw1 ,0)/2, (x1+x2+1)/2, y2-max(-adjbw2,0)/2, s, c, textcolor, s1, adjbw1bighalf, adjbw2bighalf);
1087 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);
1090 drawBorder(p, x1+max( adjbw1 ,0)/2, y1 , x2-max( adjbw2,0)/2, (y1+y2+1)/2, s, c, textcolor, s2, adjbw1bighalf, adjbw2bighalf);
1091 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);
1094 drawBorder(p, x1 , y1+max( adjbw1 ,0)/2, (x1+x2+1)/2, y2-max( adjbw2,0)/2, s, c, textcolor, s2, adjbw1bighalf, adjbw2bighalf);
1095 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);
1101 if (s == BSTop || s == BSLeft)
1105 if (style == OUTSET && (s == BSBottom || s == BSRight))
1110 p->setPen(Pen::NoPen);
1114 if (!adjbw1 && !adjbw2) {
1115 p->drawRect(IntRect(x1, y1, x2 - x1, y2 - y1));
1121 quad[0] = FloatPoint(x1 + max(-adjbw1, 0), y1);
1122 quad[1] = FloatPoint(x1 + max( adjbw1, 0), y2);
1123 quad[2] = FloatPoint(x2 - max( adjbw2, 0), y2);
1124 quad[3] = FloatPoint(x2 - max(-adjbw2, 0), y1);
1127 quad[0] = FloatPoint(x1 + max( adjbw1, 0), y1);
1128 quad[1] = FloatPoint(x1 + max(-adjbw1, 0), y2);
1129 quad[2] = FloatPoint(x2 - max(-adjbw2, 0), y2);
1130 quad[3] = FloatPoint(x2 - max( adjbw2, 0), y1);
1133 quad[0] = FloatPoint(x1, y1 + max(-adjbw1, 0));
1134 quad[1] = FloatPoint(x1, y2 - max(-adjbw2, 0));
1135 quad[2] = FloatPoint(x2, y2 - max( adjbw2, 0));
1136 quad[3] = FloatPoint(x2, y1 + max( adjbw1, 0));
1139 quad[0] = FloatPoint(x1, y1 + max( adjbw1, 0));
1140 quad[1] = FloatPoint(x1, y2 - max( adjbw2, 0));
1141 quad[2] = FloatPoint(x2, y2 - max(-adjbw2, 0));
1142 quad[3] = FloatPoint(x2, y1 + max(-adjbw1, 0));
1145 p->drawConvexPolygon(4, quad);
1151 bool RenderObject::paintBorderImage(GraphicsContext* p, int _tx, int _ty, int w, int h, const RenderStyle* style)
1153 CachedImage* borderImage = style->borderImage().image();
1154 if (!borderImage->isLoaded())
1155 return true; // Never paint a border image incrementally, but don't paint the fallback borders either.
1157 // If we have a border radius, the border image gets clipped to the rounded rect.
1158 bool clipped = false;
1159 if (style->hasBorderRadius()) {
1160 IntRect clipRect(_tx, _ty, w, h);
1162 p->addRoundedRectClip(clipRect,
1163 style->borderTopLeftRadius(), style->borderTopRightRadius(),
1164 style->borderBottomLeftRadius(), style->borderBottomRightRadius());
1168 int imageWidth = borderImage->image()->width();
1169 int imageHeight = borderImage->image()->height();
1171 int topSlice = min(imageHeight, style->borderImage().m_slices.top.calcValue(borderImage->image()->height()));
1172 int bottomSlice = min(imageHeight, style->borderImage().m_slices.bottom.calcValue(borderImage->image()->height()));
1173 int leftSlice = min(imageWidth, style->borderImage().m_slices.left.calcValue(borderImage->image()->width()));
1174 int rightSlice = min(imageWidth, style->borderImage().m_slices.right.calcValue(borderImage->image()->width()));
1176 EBorderImageRule hRule = style->borderImage().horizontalRule();
1177 EBorderImageRule vRule = style->borderImage().verticalRule();
1179 bool drawLeft = leftSlice > 0 && style->borderLeftWidth() > 0;
1180 bool drawTop = topSlice > 0 && style->borderTopWidth() > 0;
1181 bool drawRight = rightSlice > 0 && style->borderRightWidth() > 0;
1182 bool drawBottom = bottomSlice > 0 && style->borderBottomWidth() > 0;
1183 bool drawMiddle = (imageWidth - leftSlice - rightSlice) > 0 && (w - style->borderLeftWidth() - style->borderRightWidth()) > 0 &&
1184 (imageHeight - topSlice - bottomSlice) > 0 && (h - style->borderTopWidth() - style->borderBottomWidth()) > 0;
1187 // Paint the top and bottom left corners.
1189 // The top left corner rect is (_tx, _ty, leftWidth, topWidth)
1190 // The rect to use from within the image is obtained from our slice, and is (0, 0, leftSlice, topSlice)
1192 p->drawImage(borderImage->image(), IntRect(_tx, _ty, style->borderLeftWidth(), style->borderTopWidth()),
1193 IntRect(0, 0, leftSlice, topSlice));
1195 // The bottom left corner rect is (_tx, _ty + h - bottomWidth, leftWidth, bottomWidth)
1196 // The rect to use from within the image is (0, imageHeight - bottomSlice, leftSlice, botomSlice)
1198 p->drawImage(borderImage->image(), IntRect(_tx, _ty + h - style->borderBottomWidth(), style->borderLeftWidth(), style->borderBottomWidth()),
1199 IntRect(0, imageHeight - bottomSlice, leftSlice, bottomSlice));
1201 // Paint the left edge.
1202 // Have to scale and tile into the border rect.
1203 p->drawTiledImage(borderImage->image(), IntRect(_tx, _ty + style->borderTopWidth(), style->borderLeftWidth(),
1204 h - style->borderTopWidth() - style->borderBottomWidth()),
1205 IntRect(0, topSlice, leftSlice, imageHeight - topSlice - bottomSlice),
1206 Image::StretchTile, (Image::TileRule)vRule);
1210 // Paint the top and bottom right corners
1211 // The top right corner rect is (_tx + w - rightWidth, _ty, rightWidth, topWidth)
1212 // The rect to use from within the image is obtained from our slice, and is (imageWidth - rightSlice, 0, rightSlice, topSlice)
1214 p->drawImage(borderImage->image(), IntRect(_tx + w - style->borderRightWidth(), _ty, style->borderRightWidth(), style->borderTopWidth()),
1215 IntRect(imageWidth - rightSlice, 0, rightSlice, topSlice));
1217 // The bottom right corner rect is (_tx + w - rightWidth, _ty + h - bottomWidth, rightWidth, bottomWidth)
1218 // The rect to use from within the image is (imageWidth - rightSlice, imageHeight - bottomSlice, rightSlice, botomSlice)
1220 p->drawImage(borderImage->image(), IntRect(_tx + w - style->borderRightWidth(), _ty + h - style->borderBottomWidth(), style->borderRightWidth(), style->borderBottomWidth()),
1221 IntRect(imageWidth - rightSlice, imageHeight - bottomSlice, rightSlice, bottomSlice));
1223 // Paint the right edge.
1224 p->drawTiledImage(borderImage->image(), IntRect(_tx + w - style->borderRightWidth(), _ty + style->borderTopWidth(), style->borderRightWidth(),
1225 h - style->borderTopWidth() - style->borderBottomWidth()),
1226 IntRect(imageWidth - rightSlice, topSlice, rightSlice, imageHeight - topSlice - bottomSlice),
1227 Image::StretchTile, (Image::TileRule)vRule);
1230 // Paint the top edge.
1232 p->drawTiledImage(borderImage->image(), IntRect(_tx + style->borderLeftWidth(), _ty, w - style->borderLeftWidth() - style->borderRightWidth(), style->borderTopWidth()),
1233 IntRect(leftSlice, 0, imageWidth - rightSlice - leftSlice, topSlice),
1234 (Image::TileRule)hRule, Image::StretchTile);
1236 // Paint the bottom edge.
1238 p->drawTiledImage(borderImage->image(), IntRect(_tx + style->borderLeftWidth(), _ty + h - style->borderBottomWidth(),
1239 w - style->borderLeftWidth() - style->borderRightWidth(), style->borderBottomWidth()),
1240 IntRect(leftSlice, imageHeight - bottomSlice, imageWidth - rightSlice - leftSlice, bottomSlice),
1241 (Image::TileRule)hRule, Image::StretchTile);
1243 // Paint the middle.
1245 p->drawTiledImage(borderImage->image(), IntRect(_tx + style->borderLeftWidth(), _ty + style->borderTopWidth(), w - style->borderLeftWidth() - style->borderRightWidth(),
1246 h - style->borderTopWidth() - style->borderBottomWidth()),
1247 IntRect(leftSlice, topSlice, imageWidth - rightSlice - leftSlice, imageHeight - topSlice - bottomSlice),
1248 (Image::TileRule)hRule, (Image::TileRule)vRule);
1250 // Clear the clip for the border radius.
1257 void RenderObject::paintBorder(GraphicsContext* p, int _tx, int _ty, int w, int h, const RenderStyle* style, bool begin, bool end)
1259 CachedImage* borderImage = style->borderImage().image();
1260 bool shouldPaintBackgroundImage = borderImage && borderImage->canRender();
1261 if (shouldPaintBackgroundImage)
1262 shouldPaintBackgroundImage = paintBorderImage(p, _tx, _ty, w, h, style);
1264 if (shouldPaintBackgroundImage)
1267 const Color& tc = style->borderTopColor();
1268 const Color& bc = style->borderBottomColor();
1269 const Color& lc = style->borderLeftColor();
1270 const Color& rc = style->borderRightColor();
1272 bool tt = style->borderTopIsTransparent();
1273 bool bt = style->borderBottomIsTransparent();
1274 bool rt = style->borderRightIsTransparent();
1275 bool lt = style->borderLeftIsTransparent();
1277 EBorderStyle ts = style->borderTopStyle();
1278 EBorderStyle bs = style->borderBottomStyle();
1279 EBorderStyle ls = style->borderLeftStyle();
1280 EBorderStyle rs = style->borderRightStyle();
1282 bool renderTop = ts > BHIDDEN && !tt;
1283 bool renderLeft = ls > BHIDDEN && begin && !lt;
1284 bool renderRight = rs > BHIDDEN && end && !rt;
1285 bool renderBottom = bs > BHIDDEN && !bt;
1287 // Need sufficient width and height to contain border radius curves. Sanity check our top/bottom
1288 // values and our width/height values to make sure the curves can all fit. If not, then we won't paint
1289 // any border radii.
1290 bool renderRadii = false;
1291 IntSize topLeft = style->borderTopLeftRadius();
1292 IntSize topRight = style->borderTopRightRadius();
1293 IntSize bottomLeft = style->borderBottomLeftRadius();
1294 IntSize bottomRight = style->borderBottomRightRadius();
1296 if (style->hasBorderRadius()) {
1297 int requiredWidth = max(topLeft.width() + topRight.width(), bottomLeft.width() + bottomRight.width());
1298 int requiredHeight = max(topLeft.height() + bottomLeft.height(), topRight.height() + bottomRight.height());
1299 renderRadii = (requiredWidth <= w && requiredHeight <= h);
1302 // Clip to the rounded rectangle.
1305 p->addRoundedRectClip(IntRect(_tx, _ty, w, h), topLeft, topRight, bottomLeft, bottomRight);
1308 int firstAngleStart, secondAngleStart, firstAngleSpan, secondAngleSpan;
1310 bool upperLeftBorderStylesMatch = renderLeft && (ts == ls) && (tc == lc) && (ts != INSET) && (ts != GROOVE);
1311 bool upperRightBorderStylesMatch = renderRight && (ts == rs) && (tc == rc) && (ts != OUTSET) && (ts != RIDGE);
1312 bool lowerLeftBorderStylesMatch = renderLeft && (bs == ls) && (bc == lc) && (bs != OUTSET) && (bs != RIDGE);
1313 bool lowerRightBorderStylesMatch = renderRight && (bs == rs) && (bc == rc) && (bs != INSET) && (bs != GROOVE);
1316 bool ignore_left = (renderRadii && topLeft.width() > 0) ||
1317 ((tc == lc) && (tt == lt) &&
1319 (ls == DOTTED || ls == DASHED || ls == SOLID || ls == OUTSET));
1321 bool ignore_right = (renderRadii && topRight.width() > 0) ||
1322 ((tc == rc) && (tt == rt) &&
1324 (rs == DOTTED || rs == DASHED || rs == SOLID || rs == INSET));
1329 x += topLeft.width();
1330 x2 -= topRight.width();
1333 drawBorder(p, x, _ty, x2, _ty + style->borderTopWidth(), BSTop, tc, style->color(), ts,
1334 ignore_left ? 0 : style->borderLeftWidth(),
1335 ignore_right? 0 : style->borderRightWidth());
1340 int rightX = _tx + w - topRight.width() * 2;
1341 firstAngleStart = 90;
1342 firstAngleSpan = upperLeftBorderStylesMatch ? 90 : 45;
1344 // We make the arc double thick and let the clip rect take care of clipping the extra off.
1345 // We're doing this because it doesn't seem possible to match the curve of the clip exactly
1346 // with the arc-drawing function.
1347 thickness = style->borderTopWidth() * 2;
1349 if (upperRightBorderStylesMatch) {
1350 secondAngleStart = 0;
1351 secondAngleSpan = 90;
1353 secondAngleStart = 45;
1354 secondAngleSpan = 45;
1357 // The inner clip clips inside the arc. This is especially important for 1px borders.
1358 bool applyLeftInnerClip = (style->borderLeftWidth() < topLeft.width())
1359 && (style->borderTopWidth() < topLeft.height())
1360 && (ts != DOUBLE || style->borderTopWidth() > 6);
1361 if (applyLeftInnerClip) {
1363 p->addInnerRoundedRectClip(IntRect(leftX, leftY, topLeft.width() * 2, topLeft.height() * 2),
1364 style->borderTopWidth());
1367 // Draw upper left arc
1368 drawBorderArc(p, leftX, leftY, thickness, topLeft, firstAngleStart, firstAngleSpan,
1369 BSTop, tc, style->color(), ts, true);
1370 if (applyLeftInnerClip)
1373 bool applyRightInnerClip = (style->borderRightWidth() < topRight.width())
1374 && (style->borderTopWidth() < topRight.height())
1375 && (ts != DOUBLE || style->borderTopWidth() > 6);
1376 if (applyRightInnerClip) {
1378 p->addInnerRoundedRectClip(IntRect(rightX, leftY, topRight.width() * 2, topRight.height() * 2),
1379 style->borderTopWidth());
1382 // Draw upper right arc
1383 drawBorderArc(p, rightX, leftY, thickness, topRight, secondAngleStart, secondAngleSpan,
1384 BSTop, tc, style->color(), ts, false);
1385 if (applyRightInnerClip)
1391 bool ignore_left = (renderRadii && bottomLeft.width() > 0) ||
1392 ((bc == lc) && (bt == lt) &&
1394 (ls == DOTTED || ls == DASHED || ls == SOLID || ls == OUTSET));
1396 bool ignore_right = (renderRadii && bottomRight.width() > 0) ||
1397 ((bc == rc) && (bt == rt) &&
1399 (rs == DOTTED || rs == DASHED || rs == SOLID || rs == INSET));
1404 x += bottomLeft.width();
1405 x2 -= bottomRight.width();
1408 drawBorder(p, x, _ty + h - style->borderBottomWidth(), x2, _ty + h, BSBottom, bc, style->color(), bs,
1409 ignore_left ? 0 :style->borderLeftWidth(),
1410 ignore_right? 0 :style->borderRightWidth());
1414 int leftY = _ty + h - bottomLeft.height() * 2;
1415 int rightX = _tx + w - bottomRight.width() * 2;
1416 secondAngleStart = 270;
1417 secondAngleSpan = upperRightBorderStylesMatch ? 90 : 45;
1418 thickness = style->borderBottomWidth() * 2;
1420 if (upperLeftBorderStylesMatch) {
1421 firstAngleStart = 180;
1422 firstAngleSpan = 90;
1424 firstAngleStart = 225;
1425 firstAngleSpan = 45;
1428 bool applyLeftInnerClip = (style->borderLeftWidth() < bottomLeft.width())
1429 && (style->borderBottomWidth() < bottomLeft.height())
1430 && (bs != DOUBLE || style->borderBottomWidth() > 6);
1431 if (applyLeftInnerClip) {
1433 p->addInnerRoundedRectClip(IntRect(leftX, leftY, bottomLeft.width() * 2, bottomLeft.height() * 2),
1434 style->borderBottomWidth());
1437 // Draw lower left arc
1438 drawBorderArc(p, leftX, leftY, thickness, bottomLeft, firstAngleStart, firstAngleSpan,
1439 BSBottom, bc, style->color(), bs, true);
1440 if (applyLeftInnerClip)
1443 bool applyRightInnerClip = (style->borderRightWidth() < bottomRight.width())
1444 && (style->borderBottomWidth() < bottomRight.height())
1445 && (bs != DOUBLE || style->borderBottomWidth() > 6);
1446 if (applyRightInnerClip) {
1448 p->addInnerRoundedRectClip(IntRect(rightX, leftY, bottomRight.width() * 2, bottomRight.height() * 2),
1449 style->borderBottomWidth());
1452 // Draw lower right arc
1453 drawBorderArc(p, rightX, leftY, thickness, bottomRight, secondAngleStart, secondAngleSpan,
1454 BSBottom, bc, style->color(), bs, false);
1455 if (applyRightInnerClip)
1461 bool ignore_top = (renderRadii && topLeft.height() > 0) ||
1462 ((tc == lc) && (tt == lt) &&
1464 (ts == DOTTED || ts == DASHED || ts == SOLID || ts == OUTSET));
1466 bool ignore_bottom = (renderRadii && bottomLeft.height() > 0) ||
1467 ((bc == lc) && (bt == lt) &&
1469 (bs == DOTTED || bs == DASHED || bs == SOLID || bs == INSET));
1474 y += topLeft.height();
1475 y2 -= bottomLeft.height();
1478 drawBorder(p, _tx, y, _tx + style->borderLeftWidth(), y2, BSLeft, lc, style->color(), ls,
1479 ignore_top?0:style->borderTopWidth(),
1480 ignore_bottom?0:style->borderBottomWidth());
1482 if (renderRadii && (!upperLeftBorderStylesMatch || !lowerLeftBorderStylesMatch)) {
1485 int bottomY = _ty + h - bottomLeft.height() * 2;
1486 firstAngleStart = 135;
1487 secondAngleStart = 180;
1488 firstAngleSpan = secondAngleSpan = 45;
1489 thickness = style->borderLeftWidth() * 2;
1491 bool applyTopInnerClip = (style->borderLeftWidth() < topLeft.width())
1492 && (style->borderTopWidth() < topLeft.height())
1493 && (ls != DOUBLE || style->borderLeftWidth() > 6);
1494 if (applyTopInnerClip) {
1496 p->addInnerRoundedRectClip(IntRect(topX, topY, topLeft.width() * 2, topLeft.height() * 2),
1497 style->borderLeftWidth());
1500 // Draw top left arc
1501 drawBorderArc(p, topX, topY, thickness, topLeft, firstAngleStart, firstAngleSpan,
1502 BSLeft, lc, style->color(), ls, true);
1503 if (applyTopInnerClip)
1506 bool applyBottomInnerClip = (style->borderLeftWidth() < bottomLeft.width())
1507 && (style->borderBottomWidth() < bottomLeft.height())
1508 && (ls != DOUBLE || style->borderLeftWidth() > 6);
1509 if (applyBottomInnerClip) {
1511 p->addInnerRoundedRectClip(IntRect(topX, bottomY, bottomLeft.width() * 2, bottomLeft.height() * 2),
1512 style->borderLeftWidth());
1515 // Draw bottom left arc
1516 drawBorderArc(p, topX, bottomY, thickness, bottomLeft, secondAngleStart, secondAngleSpan,
1517 BSLeft, lc, style->color(), ls, false);
1518 if (applyBottomInnerClip)
1524 bool ignore_top = (renderRadii && topRight.height() > 0) ||
1525 ((tc == rc) && (tt == rt) &&
1526 (rs >= DOTTED || rs == INSET) &&
1527 (ts == DOTTED || ts == DASHED || ts == SOLID || ts == OUTSET));
1529 bool ignore_bottom = (renderRadii && bottomRight.height() > 0) ||
1530 ((bc == rc) && (bt == rt) &&
1531 (rs >= DOTTED || rs == INSET) &&
1532 (bs == DOTTED || bs == DASHED || bs == SOLID || bs == INSET));
1537 y += topRight.height();
1538 y2 -= bottomRight.height();
1541 drawBorder(p, _tx + w - style->borderRightWidth(), y, _tx + w, y2, BSRight, rc, style->color(), rs,
1542 ignore_top?0:style->borderTopWidth(),
1543 ignore_bottom?0:style->borderBottomWidth());
1545 if (renderRadii && (!upperRightBorderStylesMatch || !lowerRightBorderStylesMatch)) {
1546 int topX = _tx + w - topRight.width() * 2;
1548 int bottomY = _ty + h - bottomRight.height() * 2;
1549 firstAngleStart = 0;
1550 secondAngleStart = 315;
1551 firstAngleSpan = secondAngleSpan = 45;
1552 thickness = style->borderRightWidth() * 2;
1554 bool applyTopInnerClip = (style->borderRightWidth() < topRight.width())
1555 && (style->borderTopWidth() < topRight.height())
1556 && (rs != DOUBLE || style->borderRightWidth() > 6);
1557 if (applyTopInnerClip) {
1559 p->addInnerRoundedRectClip(IntRect(topX, topY, topRight.width() * 2, topRight.height() * 2),
1560 style->borderRightWidth());
1563 // Draw top right arc
1564 drawBorderArc(p, topX, topY, thickness, topRight, firstAngleStart, firstAngleSpan,
1565 BSRight, rc, style->color(), rs, true);
1566 if (applyTopInnerClip)
1569 bool applyBottomInnerClip = (style->borderRightWidth() < bottomRight.width())
1570 && (style->borderBottomWidth() < bottomRight.height())
1571 && (rs != DOUBLE || style->borderRightWidth() > 6);
1572 if (applyBottomInnerClip) {
1574 p->addInnerRoundedRectClip(IntRect(topX, bottomY, bottomRight.width() * 2, bottomRight.height() * 2),
1575 style->borderRightWidth());
1578 // Draw bottom right arc
1579 drawBorderArc(p, topX, bottomY, thickness, bottomRight, secondAngleStart, secondAngleSpan,
1580 BSRight, rc, style->color(), rs, false);
1581 if (applyBottomInnerClip)
1587 p->restore(); // Undo the clip.
1590 void RenderObject::lineBoxRects(Vector<IntRect>&)
1594 void RenderObject::absoluteRects(Vector<IntRect>& rects, int tx, int ty)
1596 // For blocks inside inlines, we go ahead and include margins so that we run right up to the
1597 // inline boxes above and below us (thus getting merged with them to form a single irregular
1599 if (continuation()) {
1600 rects.append(IntRect(tx, ty - collapsedMarginTop(),
1601 width(), height()+collapsedMarginTop()+collapsedMarginBottom()));
1602 continuation()->absoluteRects(rects,
1603 tx - xPos() + continuation()->containingBlock()->xPos(),
1604 ty - yPos() + continuation()->containingBlock()->yPos());
1607 rects.append(IntRect(tx, ty, width(), height() + borderTopExtra() + borderBottomExtra()));
1610 IntRect RenderObject::absoluteBoundingBoxRect()
1613 absolutePosition(x, y);
1614 Vector<IntRect> rects;
1615 absoluteRects(rects, x, y);
1617 size_t n = rects.size();
1621 IntRect result = rects[0];
1622 for (size_t i = 1; i < n; ++i)
1623 result.unite(rects[i]);
1627 void RenderObject::addAbsoluteRectForLayer(IntRect& result)
1630 result.unite(absoluteBoundingBoxRect());
1631 for (RenderObject* current = firstChild(); current; current = current->nextSibling())
1632 current->addAbsoluteRectForLayer(result);
1635 IntRect RenderObject::paintingRootRect(IntRect& topLevelRect)
1637 IntRect result = absoluteBoundingBoxRect();
1638 topLevelRect = result;
1639 for (RenderObject* current = firstChild(); current; current = current->nextSibling())
1640 current->addAbsoluteRectForLayer(result);
1644 void RenderObject::addPDFURLRect(GraphicsContext* p, IntRect rect)
1646 Node* node = element();
1649 if (rect.width() > 0 && rect.height() > 0) {
1650 Element* element = static_cast<Element*>(node);
1652 if (element->isLink())
1653 href = element->getAttribute(hrefAttr);
1655 if (!href.isNull()) {
1656 KURL link = element->document()->completeURL(href.deprecatedString());
1658 p->setURLForRect(link, rect);
1666 void RenderObject::addFocusRingRects(GraphicsContext* p, int _tx, int _ty)
1668 // For blocks inside inlines, we go ahead and include margins so that we run right up to the
1669 // inline boxes above and below us (thus getting merged with them to form a single irregular
1671 if (continuation()) {
1672 p->addFocusRingRect(IntRect(_tx, _ty - collapsedMarginTop(), width(), height()+collapsedMarginTop()+collapsedMarginBottom()));
1673 continuation()->addFocusRingRects(p,
1674 _tx - xPos() + continuation()->containingBlock()->xPos(),
1675 _ty - yPos() + continuation()->containingBlock()->yPos());
1678 p->addFocusRingRect(IntRect(_tx, _ty, width(), height()));
1681 void RenderObject::paintOutline(GraphicsContext* p, int _tx, int _ty, int w, int h, const RenderStyle* style)
1686 int ow = style->outlineWidth();
1688 EBorderStyle os = style->outlineStyle();
1690 Color oc = style->outlineColor();
1692 oc = style->color();
1694 int offset = style->outlineOffset();
1696 if (style->outlineStyleIsAuto() || hasOutlineAnnotation()) {
1697 if (!theme()->supportsFocusRing(style)) {
1698 // Only paint the focus ring by hand if the theme isn't able to draw the focus ring.
1699 p->initFocusRing(ow, offset);
1700 if (style->outlineStyleIsAuto())
1701 addFocusRingRects(p, _tx, _ty);
1703 addPDFURLRect(p, p->focusRingBoundingRect());
1704 p->drawFocusRing(oc);
1705 p->clearFocusRing();
1709 if (style->outlineStyleIsAuto() || style->outlineStyle() <= BHIDDEN)
1717 drawBorder(p, _tx-ow, _ty-ow, _tx, _ty+h+ow, BSLeft,
1718 Color(oc), style->color(),
1721 drawBorder(p, _tx-ow, _ty-ow, _tx+w+ow, _ty, BSTop,
1722 Color(oc), style->color(),
1725 drawBorder(p, _tx+w, _ty-ow, _tx+w+ow, _ty+h+ow, BSRight,
1726 Color(oc), style->color(),
1729 drawBorder(p, _tx-ow, _ty+h, _tx+w+ow, _ty+h+ow, BSBottom,
1730 Color(oc), style->color(),
1735 void RenderObject::paint(PaintInfo& /*paintInfo*/, int /*tx*/, int /*ty*/)
1739 void RenderObject::repaint(bool immediate)
1741 // Can't use view(), since we might be unrooted.
1742 RenderObject* o = this;
1743 while ( o->parent() ) o = o->parent();
1744 if (!o->isRenderView())
1746 RenderView* c = static_cast<RenderView*>(o);
1747 if (c->printingMode())
1748 return; // Don't repaint if we're printing.
1749 c->repaintViewRectangle(getAbsoluteRepaintRect(), immediate);
1752 void RenderObject::repaintRectangle(const IntRect& r, bool immediate)
1754 // Can't use view(), since we might be unrooted.
1755 RenderObject* o = this;
1756 while ( o->parent() ) o = o->parent();
1757 if (!o->isRenderView())
1759 RenderView* c = static_cast<RenderView*>(o);
1760 if (c->printingMode())
1761 return; // Don't repaint if we're printing.
1763 computeAbsoluteRepaintRect(absRect);
1764 c->repaintViewRectangle(absRect, immediate);
1767 bool RenderObject::repaintAfterLayoutIfNeeded(const IntRect& oldBounds, const IntRect& oldFullBounds)
1769 RenderView* c = view();
1770 if (c->printingMode())
1771 return false; // Don't repaint if we're printing.
1773 IntRect newBounds, newFullBounds;
1774 getAbsoluteRepaintRectIncludingFloats(newBounds, newFullBounds);
1775 if (newBounds == oldBounds && !selfNeedsLayout())
1778 bool fullRepaint = selfNeedsLayout() || newBounds.location() != oldBounds.location() || mustRepaintBackgroundOrBorder();
1780 c->repaintViewRectangle(oldFullBounds);
1781 if (newBounds != oldBounds)
1782 c->repaintViewRectangle(newFullBounds);
1786 // We didn't move, but we did change size. Invalidate the delta, which will consist of possibly
1787 // two rectangles (but typically only one).
1788 int ow = style() ? style()->outlineSize() : 0;
1789 int width = abs(newBounds.width() - oldBounds.width());
1791 c->repaintViewRectangle(IntRect(min(newBounds.x() + newBounds.width(), oldBounds.x() + oldBounds.width()) - borderRight() - ow,
1793 width + borderRight() + ow,
1794 max(newBounds.height(), oldBounds.height())));
1795 int height = abs(newBounds.height() - oldBounds.height());
1797 c->repaintViewRectangle(IntRect(newBounds.x(),
1798 min(newBounds.bottom(), oldBounds.bottom()) - borderBottom() - ow,
1799 max(newBounds.width(), oldBounds.width()),
1800 height + borderBottom() + ow));
1804 void RenderObject::repaintDuringLayoutIfMoved(int x, int y)
1808 void RenderObject::repaintOverhangingFloats(bool paintAllDescendants)
1812 bool RenderObject::checkForRepaintDuringLayout() const
1814 return !document()->view()->needsFullRepaint() && !layer();
1817 void RenderObject::repaintObjectsBeforeLayout()
1819 if (!needsLayout() || isText())
1822 bool blockWithInlineChildren = (isRenderBlock() && !isTable() && normalChildNeedsLayout() && childrenInline());
1823 if (selfNeedsLayout()) {
1825 if (blockWithInlineChildren)
1829 for (RenderObject* current = firstChild(); current; current = current->nextSibling()) {
1830 if (!current->isPositioned()) // RenderBlock subclass method handles walking the positioned objects.
1831 current->repaintObjectsBeforeLayout();
1835 IntRect RenderObject::getAbsoluteRepaintRectWithOutline(int ow)
1837 IntRect r(getAbsoluteRepaintRect());
1840 if (continuation() && !isInline())
1841 r.inflateY(collapsedMarginTop());
1844 for (RenderObject* curr = firstChild(); curr; curr = curr->nextSibling())
1845 if (!curr->isText())
1846 r.unite(curr->getAbsoluteRepaintRectWithOutline(ow));
1851 IntRect RenderObject::getAbsoluteRepaintRect()
1854 return parent()->getAbsoluteRepaintRect();
1858 void RenderObject::getAbsoluteRepaintRectIncludingFloats(IntRect& bounds, IntRect& fullBounds)
1860 bounds = fullBounds = getAbsoluteRepaintRect();
1863 void RenderObject::computeAbsoluteRepaintRect(IntRect& r, bool f)
1866 return parent()->computeAbsoluteRepaintRect(r, f);
1869 void RenderObject::dirtyLinesFromChangedChild(RenderObject* child)
1875 DeprecatedString RenderObject::information() const
1877 DeprecatedString str;
1878 TextStream ts(&str);
1880 << "(" << (style() ? style()->refCount() : 0) << ")"
1881 << ": " << (void*)this << " ";
1882 if (isInline()) ts << "il ";
1883 if (childrenInline()) ts << "ci ";
1884 if (isFloating()) ts << "fl ";
1885 if (isAnonymous()) ts << "an ";
1886 if (isRelPositioned()) ts << "rp ";
1887 if (isPositioned()) ts << "ps ";
1888 if (needsLayout()) ts << "nl ";
1889 if (m_recalcMinMax) ts << "rmm ";
1890 if (style() && style()->zIndex()) ts << "zI: " << style()->zIndex();
1892 if (element()->active())
1894 if (element()->isLink())
1896 if (element()->focused())
1898 ts << " <" << element()->localName().deprecatedString() << ">";
1899 ts << " (" << xPos() << "," << yPos() << "," << width() << "," << height() << ")";
1900 if (isTableCell()) {
1901 const RenderTableCell* cell = static_cast<const RenderTableCell *>(this);
1902 ts << " [r=" << cell->row() << " c=" << cell->col() << " rs=" << cell->rowSpan() << " cs=" << cell->colSpan() << "]";
1908 void RenderObject::dump(TextStream *stream, DeprecatedString ind) const
1910 if (isAnonymous()) { *stream << " anonymous"; }
1911 if (isFloating()) { *stream << " floating"; }
1912 if (isPositioned()) { *stream << " positioned"; }
1913 if (isRelPositioned()) { *stream << " relPositioned"; }
1914 if (isText()) { *stream << " text"; }
1915 if (isInline()) { *stream << " inline"; }
1916 if (isReplaced()) { *stream << " replaced"; }
1917 if (shouldPaintBackgroundOrBorder()) { *stream << " paintBackground"; }
1918 if (needsLayout()) { *stream << " needsLayout"; }
1919 if (minMaxKnown()) { *stream << " minMaxKnown"; }
1922 RenderObject *child = firstChild();
1925 *stream << ind << child->renderName() << ": ";
1926 child->dump(stream,ind+" ");
1927 child = child->nextSibling();
1931 void RenderObject::showTreeForThis() const
1934 element()->showTreeForThis();
1939 static Node *selectStartNode(const RenderObject *object)
1942 bool forcedOn = false;
1944 for (const RenderObject *curr = object; curr; curr = curr->parent()) {
1945 if (curr->style()->userSelect() == SELECT_TEXT)
1947 if (!forcedOn && curr->style()->userSelect() == SELECT_NONE)
1951 node = curr->element();
1954 // somewhere up the render tree there must be an element!
1960 bool RenderObject::canSelect() const
1962 return selectStartNode(this) != 0;
1965 bool RenderObject::shouldSelect() const
1967 if (Node *node = selectStartNode(this))
1968 return EventTargetNodeCast(node)->dispatchHTMLEvent(selectstartEvent, true, true);
1973 Color RenderObject::selectionBackgroundColor() const
1976 if (style()->userSelect() != SELECT_NONE) {
1977 RenderStyle* pseudoStyle = getPseudoStyle(RenderStyle::SELECTION);
1978 if (pseudoStyle && pseudoStyle->backgroundColor().isValid())
1979 color = pseudoStyle->backgroundColor().blendWithWhite();
1981 color = document()->frame()->isActive() ?
1982 theme()->activeSelectionBackgroundColor() :
1983 theme()->inactiveSelectionBackgroundColor();
1989 Color RenderObject::selectionForegroundColor() const
1992 if (style()->userSelect() != SELECT_NONE) {
1993 RenderStyle* pseudoStyle = getPseudoStyle(RenderStyle::SELECTION);
1995 color = pseudoStyle->color();
1997 color = document()->frame()->isActive() ?
1998 theme()->platformActiveSelectionForegroundColor() :
1999 theme()->platformInactiveSelectionForegroundColor();
2005 Node* RenderObject::draggableNode(bool dhtmlOK, bool uaOK, int x, int y, bool& dhtmlWillDrag) const
2007 if (!dhtmlOK && !uaOK)
2010 const RenderObject* curr = this;
2012 Node *elt = curr->element();
2013 if (elt && elt->nodeType() == Node::TEXT_NODE) {
2014 // Since there's no way for the author to address the -webkit-user-drag style for a text node,
2015 // we use our own judgement.
2016 if (uaOK && view()->frameView()->frame()->shouldDragAutoNode(curr->node(), IntPoint(x, y))) {
2017 dhtmlWillDrag = false;
2018 return curr->node();
2019 } else if (curr->shouldSelect()) {
2020 // In this case we have a click in the unselected portion of text. If this text is
2021 // selectable, we want to start the selection process instead of looking for a parent
2026 EUserDrag dragMode = curr->style()->userDrag();
2027 if (dhtmlOK && dragMode == DRAG_ELEMENT) {
2028 dhtmlWillDrag = true;
2029 return curr->node();
2030 } else if (uaOK && dragMode == DRAG_AUTO
2031 && view()->frameView()->frame()->shouldDragAutoNode(curr->node(), IntPoint(x, y)))
2033 dhtmlWillDrag = false;
2034 return curr->node();
2037 curr = curr->parent();
2042 void RenderObject::selectionStartEnd(int& spos, int& epos)
2044 view()->selectionStartEnd(spos, epos);
2047 RenderBlock* RenderObject::createAnonymousBlock()
2049 RenderStyle *newStyle = new (renderArena()) RenderStyle();
2050 newStyle->inheritFrom(m_style);
2051 newStyle->setDisplay(BLOCK);
2053 RenderBlock *newBox = new (renderArena()) RenderBlock(document() /* anonymous box */);
2054 newBox->setStyle(newStyle);
2058 void RenderObject::handleDynamicFloatPositionChange()
2060 // We have gone from not affecting the inline status of the parent flow to suddenly
2061 // having an impact. See if there is a mismatch between the parent flow's
2062 // childrenInline() state and our state.
2063 setInline(style()->isDisplayInlineType());
2064 if (isInline() != parent()->childrenInline()) {
2066 if (parent()->isRenderInline()) {
2067 // We have to split the parent flow.
2068 RenderInline* parentInline = static_cast<RenderInline*>(parent());
2069 RenderBlock* newBox = parentInline->createAnonymousBlock();
2071 RenderFlow* oldContinuation = parent()->continuation();
2072 parentInline->setContinuation(newBox);
2074 RenderObject* beforeChild = nextSibling();
2075 parent()->removeChildNode(this);
2076 parentInline->splitFlow(beforeChild, newBox, this, oldContinuation);
2078 else if (parent()->isRenderBlock())
2079 static_cast<RenderBlock*>(parent())->makeChildrenNonInline();
2082 // An anonymous block must be made to wrap this inline.
2083 RenderBlock* box = createAnonymousBlock();
2084 parent()->insertChildNode(box, this);
2085 box->appendChildNode(parent()->removeChildNode(this));
2090 void RenderObject::setStyle(RenderStyle *style)
2092 if (m_style == style)
2095 bool affectsParentBlock = false;
2096 RenderStyle::Diff d = RenderStyle::Equal;
2098 // If our z-index changes value or our visibility changes,
2099 // we need to dirty our stacking context's z-order list.
2102 if (m_style->visibility() != style->visibility() ||
2103 m_style->zIndex() != style->zIndex() ||
2104 m_style->hasAutoZIndex() != style->hasAutoZIndex())
2105 document()->setDashboardRegionsDirty(true);
2108 if ((m_style->hasAutoZIndex() != style->hasAutoZIndex() ||
2109 m_style->zIndex() != style->zIndex() ||
2110 m_style->visibility() != style->visibility()) && layer()) {
2111 layer()->stackingContext()->dirtyZOrderLists();
2112 if (m_style->hasAutoZIndex() != style->hasAutoZIndex() ||
2113 m_style->visibility() != style->visibility())
2114 layer()->dirtyZOrderLists();
2116 // keep layer hierarchy visibility bits up to date if visibility changes
2117 if (m_style->visibility() != style->visibility()) {
2118 RenderLayer* l = enclosingLayer();
2119 if (style->visibility() == VISIBLE && l)
2120 l->setHasVisibleContent(true);
2121 else if (l && l->hasVisibleContent() &&
2122 (this == l->renderer() || l->renderer()->style()->visibility() != VISIBLE))
2123 l->dirtyVisibleContentStatus();
2127 d = m_style->diff(style);
2129 // If we have no layer(), just treat a RepaintLayer hint as a normal Repaint.
2130 if (d == RenderStyle::RepaintLayer && !layer())
2131 d = RenderStyle::Repaint;
2133 // The background of the root element or the body element could propagate up to
2134 // the canvas. Just dirty the entire canvas when our style changes substantially.
2135 if (d >= RenderStyle::Repaint && element() &&
2136 (element()->hasTagName(htmlTag) || element()->hasTagName(bodyTag)))
2138 else if (m_parent && !isText()) {
2139 // Do a repaint with the old style first, e.g., for example if we go from
2140 // having an outline to not having an outline.
2141 if (d == RenderStyle::RepaintLayer) {
2142 layer()->repaintIncludingDescendants();
2143 if (!(m_style->clip() == style->clip()))
2144 layer()->clearClipRects();
2145 } else if (d == RenderStyle::Repaint || style->outlineSize() < m_style->outlineSize())
2149 // When a layout hint happens, we go ahead and do a repaint of the layer, since the layer could
2150 // end up being destroyed.
2151 if (d == RenderStyle::Layout && layer() &&
2152 (m_style->position() != style->position() ||
2153 m_style->zIndex() != style->zIndex() ||
2154 m_style->hasAutoZIndex() != style->hasAutoZIndex() ||
2155 !(m_style->clip() == style->clip()) ||
2156 m_style->hasClip() != style->hasClip() ||
2157 m_style->opacity() != style->opacity()))
2158 layer()->repaintIncludingDescendants();
2160 // When a layout hint happens and an object's position style changes, we have to do a layout
2161 // to dirty the render tree using the old position value now.
2162 if (d == RenderStyle::Layout && m_parent && m_style->position() != style->position()) {
2163 markContainingBlocksForLayout();
2164 if (m_style->position() == StaticPosition)
2166 if (isRenderBlock()) {
2167 if (style->position() == StaticPosition) {
2168 // Clear our positioned objects list. Our absolutely positioned descendants will be
2169 // inserted into our containing block's positioned objects list during layout.
2170 removePositionedObjects(0);
2171 } else if (m_style->position() == StaticPosition) {
2172 // Remove our absolutely positioned descendants from their current containing block.
2173 // They will be inserted into our positioned objects list during layout.
2174 RenderObject* cb = parent();
2175 while (cb && (cb->style()->position() == StaticPosition || (cb->isInline() && !cb->isReplaced())) && !cb->isRoot() && !cb->isRenderView()) {
2176 if (cb->style()->position() == RelativePosition && cb->isInline() && !cb->isReplaced()) {
2177 cb = cb->containingBlock();
2182 cb->removePositionedObjects(static_cast<RenderBlock*>(this));
2187 if (isFloating() && (m_style->floating() != style->floating()))
2188 // For changes in float styles, we need to conceivably remove ourselves
2189 // from the floating objects list.
2190 removeFromObjectLists();
2191 else if (isPositioned() && (style->position() != AbsolutePosition && style->position() != FixedPosition))
2192 // For changes in positioning styles, we need to conceivably remove ourselves
2193 // from the positioned objects list.
2194 removeFromObjectLists();
2196 affectsParentBlock = m_style && isFloatingOrPositioned() &&
2197 (!style->isFloating() && style->position() != AbsolutePosition && style->position() != FixedPosition)
2198 && parent() && (parent()->isBlockFlow() || parent()->isInlineFlow());
2200 // reset style flags
2202 m_positioned = false;
2203 m_relPositioned = false;
2204 m_paintBackground = false;
2205 m_hasOverflowClip = false;
2208 if (view()->frameView()) {
2209 // FIXME: A better solution would be to only invalidate the fixed regions when scrolling. It's overkill to
2210 // prevent the entire view from blitting on a scroll.
2211 bool oldStyleSlowScroll = style && (style->position() == FixedPosition || style->hasFixedBackgroundImage());
2212 bool newStyleSlowScroll = m_style && (m_style->position() == FixedPosition || m_style->hasFixedBackgroundImage());
2213 if (oldStyleSlowScroll != newStyleSlowScroll) {
2214 if (oldStyleSlowScroll)
2215 view()->frameView()->removeSlowRepaintObject();
2216 if (newStyleSlowScroll)
2217 view()->frameView()->addSlowRepaintObject();
2221 RenderStyle *oldStyle = m_style;
2224 updateBackgroundImages(oldStyle);
2230 oldStyle->deref(renderArena());
2232 setShouldPaintBackgroundOrBorder(m_style->hasBorder() || m_style->hasBackground() || m_style->hasAppearance());
2234 if (affectsParentBlock)
2235 handleDynamicFloatPositionChange();
2237 // No need to ever schedule repaints from a style change of a text run, since
2238 // we already did this for the parent of the text run.
2239 if (d == RenderStyle::Layout && m_parent)
2240 setNeedsLayoutAndMinMaxRecalc();
2241 else if (m_parent && !isText() && (d == RenderStyle::RepaintLayer || d == RenderStyle::Repaint))
2242 // Do a repaint with the new style now, e.g., for example if we go from
2243 // not having an outline to having an outline.
2247 void RenderObject::setStyleInternal(RenderStyle* st)
2252 m_style->deref(renderArena());
2258 void RenderObject::updateBackgroundImages(RenderStyle* oldStyle)
2260 // FIXME: This will be slow when a large number of images is used. Fix by using a dict.
2261 const BackgroundLayer* oldLayers = oldStyle ? oldStyle->backgroundLayers() : 0;
2262 const BackgroundLayer* newLayers = m_style ? m_style->backgroundLayers() : 0;
2263 for (const BackgroundLayer* currOld = oldLayers; currOld; currOld = currOld->next()) {
2264 if (currOld->backgroundImage() && (!newLayers || !newLayers->containsImage(currOld->backgroundImage())))
2265 currOld->backgroundImage()->deref(this);
2267 for (const BackgroundLayer* currNew = newLayers; currNew; currNew = currNew->next()) {
2268 if (currNew->backgroundImage() && (!oldLayers || !oldLayers->containsImage(currNew->backgroundImage())))
2269 currNew->backgroundImage()->ref(this);
2272 CachedImage* oldBorderImage = oldStyle ? oldStyle->borderImage().image() : 0;
2273 CachedImage* newBorderImage = m_style ? m_style->borderImage().image() : 0;
2274 if (oldBorderImage != newBorderImage) {
2276 oldBorderImage->deref(this);
2278 newBorderImage->ref(this);
2282 IntRect RenderObject::viewRect() const
2284 return view()->viewRect();
2287 bool RenderObject::absolutePosition(int &xPos, int &yPos, bool f)
2289 RenderObject* o = parent();
2291 o->absolutePosition(xPos, yPos, f);
2292 yPos += o->borderTopExtra();
2293 if (o->hasOverflowClip())
2294 o->layer()->subtractScrollOffset(xPos, yPos);
2304 IntRect RenderObject::caretRect(int offset, EAffinity affinity, int *extraWidthToEndOfLine)
2306 if (extraWidthToEndOfLine)
2307 *extraWidthToEndOfLine = 0;
2312 int RenderObject::paddingTop() const
2315 Length padding = m_style->paddingTop();
2316 if (padding.isPercent())
2317 w = containingBlock()->contentWidth();
2318 w = padding.calcMinValue(w);
2319 if ( isTableCell() && padding.isAuto() )
2320 w = static_cast<const RenderTableCell *>(this)->table()->cellPadding();
2324 int RenderObject::paddingBottom() const
2327 Length padding = style()->paddingBottom();
2328 if (padding.isPercent())
2329 w = containingBlock()->contentWidth();
2330 w = padding.calcMinValue(w);
2331 if ( isTableCell() && padding.isAuto() )
2332 w = static_cast<const RenderTableCell *>(this)->table()->cellPadding();
2336 int RenderObject::paddingLeft() const
2339 Length padding = style()->paddingLeft();
2340 if (padding.isPercent())
2341 w = containingBlock()->contentWidth();
2342 w = padding.calcMinValue(w);
2343 if ( isTableCell() && padding.isAuto() )
2344 w = static_cast<const RenderTableCell *>(this)->table()->cellPadding();
2348 int RenderObject::paddingRight() const
2351 Length padding = style()->paddingRight();
2352 if (padding.isPercent())
2353 w = containingBlock()->contentWidth();
2354 w = padding.calcMinValue(w);
2355 if ( isTableCell() && padding.isAuto() )
2356 w = static_cast<const RenderTableCell *>(this)->table()->cellPadding();
2360 int RenderObject::tabWidth() const
2362 if (style()->collapseWhiteSpace())
2365 return containingBlock()->tabWidth(true);
2368 RenderView* RenderObject::view() const
2370 return static_cast<RenderView*>(document()->renderer());
2373 bool RenderObject::hasOutlineAnnotation() const
2375 return element() && element()->isLink() && document()->printing();
2378 RenderObject *RenderObject::container() const
2380 // This method is extremely similar to containingBlock(), but with a few notable
2382 // (1) It can be used on orphaned subtrees, i.e., it can be called safely even when
2383 // the object is not part of the primary document subtree yet.
2384 // (2) For normal flow elements, it just returns the parent.
2385 // (3) For absolute positioned elements, it will return a relative positioned inline.
2386 // containingBlock() simply skips relpositioned inlines and lets an enclosing block handle
2387 // the layout of the positioned object. This does mean that calcAbsoluteHorizontal and
2388 // calcAbsoluteVertical have to use container().
2389 EPosition pos = m_style->position();
2390 RenderObject *o = 0;
2391 if (!isText() && pos == FixedPosition) {
2392 // container() can be called on an object that is not in the
2393 // tree yet. We don't call view() since it will assert if it
2394 // can't get back to the canvas. Instead we just walk as high up
2395 // as we can. If we're in the tree, we'll get the root. If we
2396 // aren't we'll get the root of our little subtree (most likely
2397 // we'll just return 0).
2399 while (o && o->parent()) o = o->parent();
2401 else if (!isText() && pos == AbsolutePosition) {
2402 // Same goes here. We technically just want our containing block, but
2403 // we may not have one if we're part of an uninstalled subtree. We'll
2404 // climb as high as we can though.
2406 while (o && o->style()->position() == StaticPosition && !o->isRenderView())
2414 // This code has been written to anticipate the addition of CSS3-::outside and ::inside generated
2415 // content (and perhaps XBL). That's why it uses the render tree and not the DOM tree.
2416 RenderObject* RenderObject::hoverAncestor() const
2418 return (!isInline() && continuation()) ? continuation() : parent();
2421 bool RenderObject::isSelectionBorder() const
2423 SelectionState st = selectionState();
2424 return st == SelectionStart || st == SelectionEnd || st == SelectionBoth;
2428 void RenderObject::removeFromObjectLists()
2430 if (documentBeingDestroyed())
2434 RenderBlock* outermostBlock = containingBlock();
2435 for (RenderBlock* p = outermostBlock; p && !p->isRenderView(); p = p->containingBlock()) {
2436 if (p->containsFloat(this))
2441 outermostBlock->markAllDescendantsWithFloatsForLayout(this);
2444 if (isPositioned()) {
2446 for (p = parent(); p; p = p->parent()) {
2447 if (p->isRenderBlock())
2448 static_cast<RenderBlock*>(p)->removePositionedObject(this);
2453 RenderArena* RenderObject::renderArena() const
2455 Document* doc = document();
2456 return doc ? doc->renderArena() : 0;
2459 bool RenderObject::documentBeingDestroyed() const
2461 return !document()->renderer();
2464 void RenderObject::destroy()
2466 // If this renderer is being autoscrolled, stop the autoscroll timer
2467 if (document() && document()->frame() && document()->frame()->autoscrollRenderer() == this)
2468 document()->frame()->stopAutoscrollTimer(true);
2470 if (m_hasCounterNodeMap) {
2471 RenderObjectsToCounterNodeMaps* objectsMap = getRenderObjectsToCounterNodeMaps();
2472 if (CounterNodeMap* counterNodesMap = objectsMap->get(this)) {
2473 CounterNodeMap::const_iterator end = counterNodesMap->end();
2474 for (CounterNodeMap::const_iterator it = counterNodesMap->begin(); it != end; ++it) {
2475 CounterNode* counterNode = it->second;
2476 counterNode->remove();
2480 objectsMap->remove(this);
2481 delete counterNodesMap;
2485 document()->axObjectCache()->remove(this);
2487 // By default no ref-counting. RenderWidget::destroy() doesn't call
2488 // this function because it needs to do ref-counting. If anything
2489 // in this function changes, be sure to fix RenderWidget::destroy() as well.
2493 arenaDelete(document()->renderArena(), this);
2496 void RenderObject::arenaDelete(RenderArena *arena, void *base)
2498 if (m_style->backgroundImage())
2499 m_style->backgroundImage()->deref(this);
2501 m_style->deref(arena);
2504 void *savedBase = baseOfRenderObjectBeingDeleted;
2505 baseOfRenderObjectBeingDeleted = base;
2509 baseOfRenderObjectBeingDeleted = savedBase;
2512 // Recover the size left there for us by operator delete and free the memory.
2513 arena->free(*(size_t *)base, base);
2516 VisiblePosition RenderObject::positionForCoordinates(int x, int y)
2518 return VisiblePosition(element(), caretMinOffset(), DOWNSTREAM);
2521 bool RenderObject::isDragging() const
2523 return m_isDragging;
2526 void RenderObject::updateDragState(bool dragOn)
2528 bool valueChanged = (dragOn != m_isDragging);
2529 m_isDragging = dragOn;
2530 if (valueChanged && style()->affectedByDragRules())
2531 element()->setChanged();
2532 for (RenderObject* curr = firstChild(); curr; curr = curr->nextSibling())
2533 curr->updateDragState(dragOn);
2535 continuation()->updateDragState(dragOn);
2538 bool RenderObject::hitTest(const HitTestRequest& request, HitTestResult& result, int x, int y, int tx, int ty, HitTestFilter hitTestFilter)
2540 bool inside = false;
2541 if (hitTestFilter != HitTestSelf) {
2542 // First test the foreground layer (lines and inlines).
2543 inside = nodeAtPoint(request, result, x, y, tx, ty, HitTestForeground);
2545 // Test floats next.
2547 inside = nodeAtPoint(request, result, x, y, tx, ty, HitTestFloat);
2549 // Finally test to see if the mouse is in the background (within a child block's background).
2551 inside = nodeAtPoint(request, result, x, y, tx, ty, HitTestChildBlockBackgrounds);
2554 // See if the mouse is inside us but not any of our descendants
2555 if (hitTestFilter != HitTestDescendants && !inside)
2556 inside = nodeAtPoint(request, result, x, y, tx, ty, HitTestBlockBackground);
2561 void RenderObject::setInnerNode(HitTestResult& result)
2563 if (result.innerNode())
2566 Node* node = element();
2568 node = document()->documentElement();
2569 else if (!isInline() && continuation())
2570 // We are in the margins of block elements that are part of a continuation. In
2571 // this case we're actually still inside the enclosing inline element that was
2572 // split. Go ahead and set our inner node accordingly.
2573 node = continuation()->element();
2576 result.setInnerNode(node);
2577 if (!result.innerNonSharedNode())
2578 result.setInnerNonSharedNode(node);
2582 bool RenderObject::nodeAtPoint(const HitTestRequest& request, HitTestResult& result,
2583 int _x, int _y, int _tx, int _ty, HitTestAction hitTestAction)
2588 short RenderObject::verticalPositionHint( bool firstLine ) const
2590 short vpos = m_verticalPosition;
2591 if ( m_verticalPosition == PositionUndefined || firstLine ) {
2592 vpos = getVerticalPosition( firstLine );
2594 m_verticalPosition = vpos;
2600 short RenderObject::getVerticalPosition( bool firstLine ) const
2605 // This method determines the vertical position for inline elements.
2607 EVerticalAlign va = style()->verticalAlign();
2610 } else if ( va == BOTTOM ) {
2611 vpos = PositionBottom;
2612 } else if ( va == LENGTH ) {
2613 vpos = -style()->verticalAlignLength().calcValue( lineHeight( firstLine ) );
2615 bool checkParent = parent()->isInline() && !parent()->isInlineBlockOrInlineTable() && parent()->style()->verticalAlign() != TOP && parent()->style()->verticalAlign() != BOTTOM;
2616 vpos = checkParent ? parent()->verticalPositionHint( firstLine ) : 0;
2617 // don't allow elements nested inside text-top to have a different valignment.
2618 if ( va == BASELINE )
2621 const Font &f = parent()->font(firstLine);
2622 int fontsize = f.pixelSize();
2625 vpos += fontsize/5 + 1;
2626 else if (va == SUPER)
2627 vpos -= fontsize/3 + 1;
2628 else if (va == TEXT_TOP)
2629 vpos += baselinePosition(firstLine) - f.ascent();
2630 else if (va == MIDDLE)
2631 vpos += - (int)(f.xHeight()/2) - lineHeight( firstLine )/2 + baselinePosition( firstLine );
2632 else if (va == TEXT_BOTTOM) {
2633 vpos += f.descent();
2635 vpos -= font(firstLine).descent();
2636 } else if ( va == BASELINE_MIDDLE )
2637 vpos += - lineHeight( firstLine )/2 + baselinePosition( firstLine );
2643 short RenderObject::lineHeight( bool firstLine, bool ) const
2645 RenderStyle* s = style(firstLine);
2647 Length lh = s->lineHeight();
2649 // its "unset", choose nice default
2651 return s->font().lineSpacing();
2654 return lh.calcMinValue(s->fontSize());
2660 short RenderObject::baselinePosition(bool firstLine, bool isRootLineBox) const
2662 const Font& f = font(firstLine);
2663 return f.ascent() + (lineHeight(firstLine, isRootLineBox) - f.height()) / 2;
2666 void RenderObject::invalidateVerticalPositions()
2668 m_verticalPosition = PositionUndefined;
2669 RenderObject *child = firstChild();
2671 child->invalidateVerticalPositions();
2672 child = child->nextSibling();
2676 void RenderObject::recalcMinMaxWidths()
2678 ASSERT( m_recalcMinMax );
2681 kdDebug( 6040 ) << renderName() << " recalcMinMaxWidths() this=" << this <<endl;
2685 updateFirstLetter();
2687 RenderObject *child = firstChild();
2692 if ( ( m_minMaxKnown && child->m_recalcMinMax ) || !child->m_minMaxKnown ) {
2693 cmin = child->minWidth();
2694 cmax = child->maxWidth();
2697 if ( child->m_recalcMinMax )
2698 child->recalcMinMaxWidths();
2699 if ( !child->m_minMaxKnown )
2700 child->calcMinMaxWidth();
2701 if ( m_minMaxKnown && test && (cmin != child->minWidth() || cmax != child->maxWidth()) )
2702 m_minMaxKnown = false;
2703 child = child->nextSibling();
2706 // we need to recalculate, if the contains inline children, as the change could have
2707 // happened somewhere deep inside the child tree. Also do this for blocks or tables that
2708 // are inline (i.e., inline-block and inline-table).
2709 if ((!isInline() || isInlineBlockOrInlineTable()) && childrenInline())
2710 m_minMaxKnown = false;
2712 if ( !m_minMaxKnown )
2714 m_recalcMinMax = false;
2717 void RenderObject::scheduleRelayout()
2719 if (isRenderView()) {
2720 FrameView* view = static_cast<RenderView*>(this)->frameView();
2722 view->scheduleRelayout();
2724 FrameView* v = view() ? view()->frameView() : 0;
2726 v->scheduleRelayoutOfSubtree(node());
2731 void RenderObject::removeLeftoverAnonymousBoxes()
2735 InlineBox* RenderObject::createInlineBox(bool, bool isRootLineBox, bool)
2737 ASSERT(!isRootLineBox);
2738 return new (renderArena()) InlineBox(this);
2741 void RenderObject::dirtyLineBoxes(bool, bool)
2745 InlineBox* RenderObject::inlineBoxWrapper() const
2750 void RenderObject::setInlineBoxWrapper(InlineBox* b)
2754 void RenderObject::deleteLineBoxWrapper()
2758 RenderStyle* RenderObject::firstLineStyle() const
2760 RenderStyle *s = m_style;
2761 const RenderObject* obj = isText() ? parent() : this;
2762 if (obj->isBlockFlow()) {
2763 RenderBlock* firstLineBlock = obj->firstLineBlock();
2765 s = firstLineBlock->getPseudoStyle(RenderStyle::FIRST_LINE, style());
2766 } else if (!obj->isAnonymous() && obj->isInlineFlow()) {
2767 RenderStyle* parentStyle = obj->parent()->firstLineStyle();
2768 if (parentStyle != obj->parent()->style()) {
2769 // A first-line style is in effect. We need to cache a first-line style
2771 style()->setHasPseudoStyle(RenderStyle::FIRST_LINE_INHERITED);
2772 s = obj->getPseudoStyle(RenderStyle::FIRST_LINE_INHERITED, parentStyle);
2778 RenderStyle* RenderObject::getPseudoStyle(RenderStyle::PseudoId pseudo, RenderStyle* parentStyle) const
2780 if (!style()->hasPseudoStyle(pseudo))
2784 parentStyle = style();
2786 RenderStyle* result = style()->getPseudoStyle(pseudo);
2790 Node* node = element();
2792 node = element()->parentNode();
2796 if (pseudo == RenderStyle::FIRST_LINE_INHERITED) {
2797 result = document()->styleSelector()->styleForElement(static_cast<Element*>(node), parentStyle, false);
2798 result->setStyleType(RenderStyle::FIRST_LINE_INHERITED);
2800 result = document()->styleSelector()->pseudoStyleForElement(pseudo, static_cast<Element*>(node), parentStyle);
2802 style()->addPseudoStyle(result);
2803 result->deref(document()->renderArena());
2808 void RenderObject::getTextDecorationColors(int decorations, Color& underline, Color& overline,
2809 Color& linethrough, bool quirksMode)
2811 RenderObject* curr = this;
2813 int currDecs = curr->style()->textDecoration();
2815 if (currDecs & UNDERLINE) {
2816 decorations &= ~UNDERLINE;
2817 underline = curr->style()->color();
2819 if (currDecs & OVERLINE) {
2820 decorations &= ~OVERLINE;
2821 overline = curr->style()->color();
2823 if (currDecs & LINE_THROUGH) {
2824 decorations &= ~LINE_THROUGH;
2825 linethrough = curr->style()->color();
2828 curr = curr->parent();
2829 if (curr && curr->isRenderBlock() && curr->continuation())
2830 curr = curr->continuation();
2831 } while (curr && decorations && (!quirksMode || !curr->element() ||
2832 (!curr->element()->hasTagName(aTag) && !curr->element()->hasTagName(fontTag))));
2834 // If we bailed out, use the element we bailed out at (typically a <font> or <a> element).
2835 if (decorations && curr) {
2836 if (decorations & UNDERLINE)
2837 underline = curr->style()->color();
2838 if (decorations & OVERLINE)
2839 overline = curr->style()->color();
2840 if (decorations & LINE_THROUGH)
2841 linethrough = curr->style()->color();
2845 void RenderObject::updateWidgetPosition()
2849 void RenderObject::addDashboardRegions(Vector<DashboardRegionValue>& regions)
2851 // Convert the style regions to absolute coordinates.
2852 if (style()->visibility() != VISIBLE)
2855 const Vector<StyleDashboardRegion>& styleRegions = style()->dashboardRegions();
2856 unsigned i, count = styleRegions.size();
2857 for (i = 0; i < count; i++){
2858 StyleDashboardRegion styleRegion = styleRegions[i];
2863 DashboardRegionValue region;
2864 region.label = styleRegion.label;
2865 region.bounds = IntRect (
2866 styleRegion.offset.left.value(),
2867 styleRegion.offset.top.value(),
2868 w - styleRegion.offset.left.value() - styleRegion.offset.right.value(),
2869 h - styleRegion.offset.top.value() - styleRegion.offset.bottom.value());
2870 region.type = styleRegion.type;
2872 region.clip = region.bounds;
2873 computeAbsoluteRepaintRect(region.clip);
2874 if (region.clip.height() < 0) {
2875 region.clip.setHeight(0);
2876 region.clip.setWidth(0);
2880 absolutePosition(x, y);
2881 region.bounds.setX(x + styleRegion.offset.left.value());
2882 region.bounds.setY(y + styleRegion.offset.top.value());
2884 if (document()->frame()) {
2885 float pageScaleFactor = scaleFactor(document()->frame()->page());
2886 if (pageScaleFactor != 1.0f) {
2887 region.bounds.scale(pageScaleFactor);
2888 region.clip.scale(pageScaleFactor);
2892 regions.append(region);
2896 void RenderObject::collectDashboardRegions(Vector<DashboardRegionValue>& regions)
2898 // RenderTexts don't have their own style, they just use their parent's style,
2899 // so we don't want to include them.
2903 addDashboardRegions(regions);
2904 for (RenderObject* curr = firstChild(); curr; curr = curr->nextSibling())
2905 curr->collectDashboardRegions(regions);
2909 void RenderObject::collectBorders(DeprecatedValueList<CollapsedBorderValue>& borderStyles)
2911 for (RenderObject* curr = firstChild(); curr; curr = curr->nextSibling())
2912 curr->collectBorders(borderStyles);
2915 bool RenderObject::avoidsFloats() const
2917 return isReplaced() || hasOverflowClip() || isHR();
2920 bool RenderObject::usesLineWidth() const
2922 // 1. All auto-width objects that avoid floats should always use lineWidth
2923 // 2. For objects with a specified width, we match WinIE's behavior:
2924 // (a) tables use contentWidth
2925 // (b) <hr>s use lineWidth
2926 // (c) all other objects use lineWidth in quirks mode and contentWidth in strict mode.
2927 return (avoidsFloats() && (style()->width().isAuto() || isHR() || (style()->htmlHacks() && !isTable())));
2930 CounterNode* RenderObject::findCounter(const String& counterName, bool willNeedLayout,
2931 bool usesSeparator, bool createIfNotFound)
2936 RenderObjectsToCounterNodeMaps* objectsMap = getRenderObjectsToCounterNodeMaps();
2937 CounterNode* newNode = 0;
2938 if (CounterNodeMap* counterNodesMap = objectsMap->get(this))
2939 if (counterNodesMap)
2940 newNode = counterNodesMap->get(counterName);
2946 if (style()->hasCounterReset(counterName) || isRoot()) {
2947 newNode = new CounterResetNode(this);
2948 val = style()->counterReset(counterName);
2949 if (style()->hasCounterIncrement(counterName))
2950 val += style()->counterIncrement(counterName);
2951 newNode->setValue(val);
2952 } else if (style()->hasCounterIncrement(counterName)) {
2953 newNode = new CounterNode(this);
2954 newNode->setValue(style()->counterIncrement(counterName));
2955 } else if (counterName == "list-item") {
2958 String v = static_cast<Element*>(element())->getAttribute("value");
2960 newNode = new CounterResetNode(this);
2966 newNode = new CounterNode(this);
2970 newNode->setValue(val);
2971 } else if (element() && element()->hasTagName(olTag)) {
2972 newNode = new CounterResetNode(this);
2973 newNode->setValue(static_cast<HTMLOListElement*>(element())->start());
2974 } else if (element() &&
2975 (element()->hasTagName(ulTag) ||
2976 element()->hasTagName(menuTag) ||
2977 element()->hasTagName(dirTag))) {
2978 newNode = new CounterResetNode(this);
2979 newNode->setValue(0);
2983 if (!newNode && !createIfNotFound)
2985 else if (!newNode) {
2986 newNode = new CounterNode(this);
2987 newNode->setValue(0);
2991 newNode->setWillNeedLayout();
2993 newNode->setUsesSeparator();
2995 CounterNodeMap* nodeMap;
2996 if (m_hasCounterNodeMap)
2997 nodeMap = objectsMap->get(this);
2999 nodeMap = new CounterNodeMap;
3000 objectsMap->set(this, nodeMap);
3001 m_hasCounterNodeMap = true;
3004 nodeMap->set(counterName, newNode);
3007 RenderObject* n = !isListItem() && previousSibling()
3008 ? previousSibling()->previousSibling() : previousSibling();
3010 CounterNode* current = 0;
3011 for (; n; n = n->previousSibling()) {
3012 current = n->findCounter(counterName, false, false, false);
3017 CounterNode* last = current;
3018 CounterNode* sibling = current;
3019 if (last && !newNode->isReset()) {
3020 // Found render-sibling, now search for later counter-siblings among its render-children
3023 current = n->findCounter(counterName, false, false, false);
3024 if (current && (last->parent() == current->parent() || sibling == current->parent())) {
3026 // If the current counter is not the last, search deeper
3027 if (current->nextSibling()) {
3033 n = n->previousSibling();
3036 if (sibling->isReset()) {
3037 if (last != sibling)
3038 sibling->insertAfter(newNode, last);
3040 sibling->insertAfter(newNode, 0);
3042 last->parent()->insertAfter(newNode, last);
3044 // Nothing found among siblings, let our parent search
3045 last = parent()->findCounter(counterName, false);
3046 if (last->isReset())
3047 last->insertAfter(newNode, 0);
3049 last->parent()->insertAfter(newNode, last);
3056 UChar RenderObject::backslashAsCurrencySymbol() const
3058 if (Node *node = element())
3059 if (TextResourceDecoder *decoder = node->document()->decoder())
3060 return decoder->encoding().backslashAsCurrencySymbol();
3064 void RenderObject::imageChanged(CachedImage *image)
3066 // Repaint when the background image or border image finishes loading.
3067 // This is needed for RenderBox objects, and also for table objects that hold
3068 // backgrounds that are then respected by the table cells (which are RenderBox
3069 // subclasses). It would be even better to find a more elegant way of doing this that
3070 // would avoid putting this function and the CachedResourceClient base class into RenderObject.
3071 if (image && image->canRender() && parent()) {
3072 if (view() && element() && (element()->hasTagName(htmlTag) || element()->hasTagName(bodyTag)))
3073 view()->repaint(); // repaint the entire canvas since the background gets propagated up
3075 repaint(); // repaint object, which is a box or a container with boxes inside it
3079 bool RenderObject::willRenderImage(CachedImage*)
3081 // Without visibility we won't render (and therefore don't care about animation).
3082 if (style()->visibility() != VISIBLE)
3085 // 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)
3086 // then we don't want to render either.
3087 return !document()->inPageCache() && document()->view()->inWindow();
3090 int RenderObject::maximalOutlineSize(PaintPhase p) const
3092 if (p != PaintPhaseOutline && p != PaintPhaseSelfOutline && p != PaintPhaseChildOutlines)
3094 return static_cast<RenderView*>(document()->renderer())->maximalOutlineSize();
3097 int RenderObject::caretMinOffset() const
3102 int RenderObject::caretMaxOffset() const
3104 return isReplaced() ? 1 : 0;
3107 unsigned RenderObject::caretMaxRenderedOffset() const
3112 int RenderObject::previousOffset (int current) const
3114 int previousOffset = current - 1;
3115 return previousOffset;
3118 int RenderObject::nextOffset (int current) const
3120 int nextOffset = current + 1;
3124 InlineBox *RenderObject::inlineBox(int offset, EAffinity affinity)
3126 return inlineBoxWrapper();
3131 FloatRect RenderObject::relativeBBox(bool) const
3136 AffineTransform RenderObject::localTransform() const
3138 return AffineTransform(1, 0, 0, 1, xPos(), yPos());
3141 void RenderObject::setLocalTransform(const AffineTransform&)
3146 AffineTransform RenderObject::absoluteTransform() const
3149 return localTransform() * parent()->absoluteTransform();
3150 return localTransform();
3159 void showTree(const WebCore::RenderObject* ro)
3162 ro->showTreeForThis();