2 * This file is part of the html renderer for KDE.
4 * Copyright (C) 1999-2003 Lars Knoll (knoll@kde.org)
5 * (C) 1999 Antti Koivisto (koivisto@kde.org)
6 * (C) 2000-2003 Dirk Mueller (mueller@kde.org)
7 * (C) 2004-2008 Apple Computer, Inc.
8 * (C) 2006 Germain Garand <germain@ebooksfrance.org>
9 * (C) 2008-2009 Fredrik Höglund <fredrik@kde.org>
11 * This library is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU Library General Public
13 * License as published by the Free Software Foundation; either
14 * version 2 of the License, or (at your option) any later version.
16 * This library is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 * Library General Public License for more details.
21 * You should have received a copy of the GNU Library General Public License
22 * along with this library; see the file COPYING.LIB. If not, write to
23 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
24 * Boston, MA 02110-1301, USA.
28 #include "rendering/render_object.h"
29 #include "rendering/render_table.h"
30 #include "rendering/render_list.h"
31 #include "rendering/render_canvas.h"
32 #include "rendering/render_block.h"
33 #include "rendering/render_arena.h"
34 #include "rendering/render_layer.h"
35 #include "rendering/render_line.h"
36 #include "rendering/render_inline.h"
37 #include "rendering/render_text.h"
38 #include "rendering/render_replaced.h"
39 #include "rendering/render_generated.h"
40 #include "rendering/counter_tree.h"
42 #include "xml/dom_elementimpl.h"
43 #include "xml/dom_docimpl.h"
44 #include "xml/dom_position.h"
45 #include "dom/dom_doc.h"
46 #include "misc/htmlhashes.h"
47 #include "misc/loader.h"
48 #include "misc/borderarcstroker.h"
52 #include <QtGui/QPainter>
53 #include "khtmlview.h"
54 #include <khtml_part.h>
55 #include <QPaintEngine>
59 using namespace khtml
;
61 #define RED_LUMINOSITY 30
62 #define GREEN_LUMINOSITY 59
63 #define BLUE_LUMINOSITY 11
64 #define INTENSITY_FACTOR 25
65 #define LIGHT_FACTOR 0
66 #define LUMINOSITY_FACTOR 75
69 #define COLOR_DARK_THRESHOLD 51
70 #define COLOR_LIGHT_THRESHOLD 204
72 #define COLOR_LITE_BS_FACTOR 45
73 #define COLOR_LITE_TS_FACTOR 70
75 #define COLOR_DARK_BS_FACTOR 30
76 #define COLOR_DARK_TS_FACTOR 50
78 #define LIGHT_GRAY qRgb(192, 192, 192)
79 #define DARK_GRAY qRgb(96, 96, 96)
82 static void *baseOfRenderObjectBeingDeleted
;
85 QCache
<quint64
, QPixmap
> *RenderObject::s_dashedLineCache
= 0;
87 void RenderObject::cleanup()
89 delete s_dashedLineCache
;
90 s_dashedLineCache
= 0;
95 void* RenderObject::operator new(size_t sz
, RenderArena
* renderArena
) throw()
97 return renderArena
->allocate(sz
);
100 void RenderObject::operator delete(void* ptr
, size_t sz
)
102 assert(baseOfRenderObjectBeingDeleted
== ptr
);
104 #ifdef KHTML_USE_ARENA_ALLOCATOR
105 // Stash size where detach can find it.
110 RenderObject
*RenderObject::createObject(DOM::NodeImpl
* node
, RenderStyle
* style
)
113 khtml::RenderArena
* arena
= node
->document()->renderArena();
114 switch(style
->display())
119 o
= new (arena
) RenderInline(node
);
122 o
= new (arena
) RenderBlock(node
);
125 o
= new (arena
) RenderBlock(node
);
128 o
= new (arena
) RenderListItem(node
);
132 o
= new (arena
) RenderBlock(node
);
136 style
->setFlowAroundFloats(true);
137 o
= new (arena
) RenderTable(node
);
139 case TABLE_ROW_GROUP
:
140 case TABLE_HEADER_GROUP
:
141 case TABLE_FOOTER_GROUP
:
142 o
= new (arena
) RenderTableSection(node
);
145 o
= new (arena
) RenderTableRow(node
);
147 case TABLE_COLUMN_GROUP
:
149 o
= new (arena
) RenderTableCol(node
);
152 o
= new (arena
) RenderTableCell(node
);
155 o
= new (arena
) RenderBlock(node
);
162 RenderObject::RenderObject(DOM::NodeImpl
* node
)
163 : CachedObjectClient(),
169 m_verticalPosition( PositionUndefined
),
170 m_needsLayout( false ),
171 m_normalChildNeedsLayout( false ),
172 m_markedForRepaint( false ),
173 m_posChildNeedsLayout( false ),
174 m_minMaxKnown( false ),
177 m_positioned( false ),
178 m_relPositioned( false ),
179 m_paintBackground( false ),
181 m_isAnonymous( node
->isDocumentNode() ),
182 m_recalcMinMax( false ),
188 m_mouseInside( false ),
189 m_hasFirstLine( false ),
190 m_isSelectionBorder( false ),
192 m_afterPageBreak( false ),
193 m_needsPageClear( false ),
194 m_containsPageBreak( false ),
195 m_hasOverflowClip(false),
196 m_inPosObjectList(false),
200 if (node
->document()->documentElement() == node
) setIsRoot(true);
203 RenderObject::~RenderObject()
205 const BackgroundLayer
* bgLayer
= m_style
->backgroundLayers();
207 if(bgLayer
->backgroundImage())
208 bgLayer
->backgroundImage()->deref(this);
209 bgLayer
= bgLayer
->next();
215 RenderObject
* RenderObject::objectBelow() const
217 RenderObject
* obj
= firstChild();
223 while (obj
&& !obj
->nextSibling())
226 obj
= obj
->nextSibling();
232 RenderObject
* RenderObject::objectAbove() const
234 RenderObject
* obj
= previousSibling();
238 RenderObject
* last
= obj
->lastChild();
242 last
= last
->lastChild();
247 bool RenderObject::isRoot() const
249 return !isAnonymous() &&
250 element()->document()->documentElement() == element();
253 bool RenderObject::isHR() const
255 return element() && element()->id() == ID_HR
;
257 bool RenderObject::isWordBreak() const
259 return element() && element()->id() == ID_WBR
;
261 bool RenderObject::isHTMLMarquee() const
263 return element() && element()->renderer() == this && element()->id() == ID_MARQUEE
;
266 void RenderObject::addChild(RenderObject
* , RenderObject
*)
271 RenderObject
* RenderObject::removeChildNode(RenderObject
*)
277 void RenderObject::removeChild(RenderObject
*)
282 void RenderObject::appendChildNode(RenderObject
*)
287 void RenderObject::insertChildNode(RenderObject
*, RenderObject
*)
292 RenderObject
*RenderObject::nextRenderer() const
296 else if (nextSibling())
297 return nextSibling();
299 const RenderObject
*r
= this;
300 while (r
&& !r
->nextSibling())
303 return r
->nextSibling();
308 RenderObject
*RenderObject::previousRenderer() const
310 if (previousSibling()) {
311 RenderObject
*r
= previousSibling();
312 while (r
->lastChild())
324 bool RenderObject::isEditable() const
326 RenderText
*textRenderer
= 0;
328 textRenderer
= static_cast<RenderText
*>(const_cast<RenderObject
*>(this));
331 return style()->visibility() == VISIBLE
&&
332 element() && element()->isContentEditable() &&
333 ((isBlockFlow() && !firstChild()) ||
336 (textRenderer
&& textRenderer
->firstTextBox()));
339 RenderObject
*RenderObject::nextEditable() const
341 RenderObject
*r
= const_cast<RenderObject
*>(this);
342 RenderObject
*n
= firstChild();
351 return r
->nextEditable();
353 n
= r
->nextSibling();
363 return r
->nextEditable();
368 n
= r
->nextSibling();
379 return r
->nextEditable();
386 RenderObject
*RenderObject::previousEditable() const
388 RenderObject
*r
= const_cast<RenderObject
*>(this);
389 RenderObject
*n
= firstChild();
398 return r
->previousEditable();
400 n
= r
->previousSibling();
410 return r
->previousEditable();
415 n
= r
->previousSibling();
426 return r
->previousEditable();
433 RenderObject
*RenderObject::firstLeafChild() const
435 RenderObject
*r
= firstChild();
446 RenderObject
*RenderObject::lastLeafChild() const
448 RenderObject
*r
= lastChild();
459 static void addLayers(RenderObject
* obj
, RenderLayer
* parentLayer
, RenderObject
*& newObject
,
460 RenderLayer
*& beforeChild
)
463 if (!beforeChild
&& newObject
) {
464 // We need to figure out the layer that follows newObject. We only do
465 // this the first time we find a child layer, and then we update the
466 // pointer values for newObject and beforeChild used by everyone else.
467 beforeChild
= newObject
->parent()->findNextLayer(parentLayer
, newObject
);
470 parentLayer
->addChild(obj
->layer(), beforeChild
);
474 for (RenderObject
* curr
= obj
->firstChild(); curr
; curr
= curr
->nextSibling())
475 addLayers(curr
, parentLayer
, newObject
, beforeChild
);
478 void RenderObject::addLayers(RenderLayer
* parentLayer
, RenderObject
* newObject
)
483 RenderObject
* object
= newObject
;
484 RenderLayer
* beforeChild
= 0;
485 ::addLayers(this, parentLayer
, object
, beforeChild
);
488 void RenderObject::removeLayers(RenderLayer
* parentLayer
)
494 parentLayer
->removeChild(layer());
498 for (RenderObject
* curr
= firstChild(); curr
; curr
= curr
->nextSibling())
499 curr
->removeLayers(parentLayer
);
502 void RenderObject::moveLayers(RenderLayer
* oldParent
, RenderLayer
* newParent
)
509 oldParent
->removeChild(layer());
510 newParent
->addChild(layer());
514 for (RenderObject
* curr
= firstChild(); curr
; curr
= curr
->nextSibling())
515 curr
->moveLayers(oldParent
, newParent
);
518 RenderLayer
* RenderObject::findNextLayer(RenderLayer
* parentLayer
, RenderObject
* startPoint
,
521 // Error check the parent layer passed in. If it's null, we can't find anything.
525 // Step 1: If our layer is a child of the desired parent, then return our layer.
526 RenderLayer
* ourLayer
= layer();
527 if (ourLayer
&& ourLayer
->parent() == parentLayer
)
530 // Step 2: If we don't have a layer, or our layer is the desired parent, then descend
531 // into our siblings trying to find the next layer whose parent is the desired parent.
532 if (!ourLayer
|| ourLayer
== parentLayer
) {
533 for (RenderObject
* curr
= startPoint
? startPoint
->nextSibling() : firstChild();
534 curr
; curr
= curr
->nextSibling()) {
535 RenderLayer
* nextLayer
= curr
->findNextLayer(parentLayer
, 0, false);
541 // Step 3: If our layer is the desired parent layer, then we're finished. We didn't
543 if (parentLayer
== ourLayer
)
546 // Step 4: If |checkParent| is set, climb up to our parent and check its siblings that
547 // follow us to see if we can locate a layer.
548 if (checkParent
&& parent())
549 return parent()->findNextLayer(parentLayer
, this, true);
554 RenderLayer
* RenderObject::enclosingLayer() const
556 const RenderObject
* curr
= this;
558 RenderLayer
*layer
= curr
->layer();
561 curr
= curr
->parent();
566 RenderLayer
* RenderObject::enclosingStackingContext() const
568 RenderLayer
* l
= enclosingLayer();
569 while (l
&& !l
->isStackingContext())
574 int RenderObject::offsetLeft() const
579 RenderObject
* offsetPar
= offsetParent();
581 if (!offsetPar
|| offsetPar
->isBody()) {
582 absolutePosition(x
, dummy
);
586 x
= xPos() -offsetPar
->borderLeft();
587 if ( isPositioned() )
590 if (isRelPositioned()) {
592 static_cast<const RenderBox
*>(this)->relativePositionOffset(x
, y
);
595 for( RenderObject
* curr
= parent();
596 curr
&& curr
!= offsetPar
;
597 curr
= curr
->parent() )
603 int RenderObject::offsetTop() const
608 RenderObject
* offsetPar
= offsetParent();
611 if (!offsetPar
|| offsetPar
->isBody()) {
612 absolutePosition(dummy
, y
);
616 y
= yPos() -offsetPar
->borderTop();
617 if ( isPositioned() )
620 if (isRelPositioned()) {
622 static_cast<const RenderBox
*>(this)->relativePositionOffset(x
, y
);
624 for( RenderObject
* curr
= parent();
625 curr
&& curr
!= offsetPar
;
626 curr
= curr
->parent() )
632 RenderObject
* RenderObject::offsetParent() const
634 if (isBody() || style()->position() == PFIXED
)
637 // can't really use containing blocks here (#113280)
638 bool skipTables
= isPositioned() || isRelPositioned();
639 bool strict
= !style()->htmlHacks();
640 RenderObject
* curr
= parent();
641 while (curr
&& (!curr
->element() ||
642 (!curr
->isPositioned() && !curr
->isRelPositioned() &&
643 !(strict
&& skipTables
? curr
->isRoot() : curr
->isBody())))) {
644 if (!skipTables
&& curr
->element() && (curr
->isTableCell() || curr
->isTable()))
646 curr
= curr
->parent();
652 // clientWidth and clientHeight represent the interior of an object
653 short RenderObject::clientWidth() const
655 return width() - borderLeft() - borderRight() -
656 (layer() ? layer()->verticalScrollbarWidth() : 0);
659 int RenderObject::clientLeft() const
664 int RenderObject::clientTop() const
669 int RenderObject::clientHeight() const
671 return height() - borderTop() - borderBottom() -
672 (layer() ? layer()->horizontalScrollbarHeight() : 0);
675 // scrollWidth/scrollHeight is the size including the overflow area
676 short RenderObject::scrollWidth() const
678 return (hasOverflowClip() && layer()) ? layer()->scrollWidth() : overflowWidth() - overflowLeft();
681 int RenderObject::scrollHeight() const
683 return (hasOverflowClip() && layer()) ? layer()->scrollHeight() : overflowHeight() - overflowTop();
686 void RenderObject::updatePixmap(const QRect
& /*r*/, CachedImage
* image
)
689 #warning "FIXME: Check if complete!"
691 //repaint bg when it finished loading
692 if(image
&& parent() && style() && style()->backgroundLayers()->containsImage(image
)) {
693 isBody() ? canvas()->repaint() : repaint();
697 void RenderObject::setNeedsLayout(bool b
, bool markParents
)
699 bool alreadyNeededLayout
= m_needsLayout
;
702 if (!alreadyNeededLayout
&& markParents
&& m_parent
) {
703 dirtyFormattingContext( false );
704 markContainingBlocksForLayout();
708 m_posChildNeedsLayout
= false;
709 m_normalChildNeedsLayout
= false;
713 void RenderObject::setChildNeedsLayout(bool b
, bool markParents
)
715 bool alreadyNeededLayout
= m_normalChildNeedsLayout
;
716 m_normalChildNeedsLayout
= b
;
718 if (!alreadyNeededLayout
&& markParents
)
719 markContainingBlocksForLayout();
722 m_posChildNeedsLayout
= false;
723 m_normalChildNeedsLayout
= false;
727 void RenderObject::markContainingBlocksForLayout()
729 RenderObject
*o
= container();
730 RenderObject
*last
= this;
733 if (!last
->isText() && (last
->style()->position() == PFIXED
|| last
->style()->position() == PABSOLUTE
)) {
734 if (o
->m_posChildNeedsLayout
)
736 o
->m_posChildNeedsLayout
= true;
739 if (o
->m_normalChildNeedsLayout
)
741 o
->m_normalChildNeedsLayout
= true;
748 last
->scheduleRelayout();
751 RenderBlock
*RenderObject::containingBlock() const
754 return static_cast<RenderBlock
*>( parent()->parent()->parent() );
756 return const_cast<RenderBlock
*>( static_cast<const RenderBlock
*>(this) );
758 RenderObject
*o
= parent();
759 if(m_style
->position() == PFIXED
) {
760 while ( o
&& !o
->isCanvas() )
763 else if(m_style
->position() == PABSOLUTE
) {
765 ( o
->style()->position() == PSTATIC
|| ( o
->isInline() && !o
->isReplaced() ) ) && !o
->isCanvas()) {
766 // for relpos inlines, return the nearest block - it will host the positioned objects list
767 if (o
->isInline() && !o
->isReplaced() && o
->style()->position() == PRELATIVE
)
768 return o
->containingBlock();
772 while(o
&& ( ( o
->isInline() && !o
->isReplaced() ) || o
->isTableRow() || o
->isTableSection() ||
773 o
->isTableCol() || o
->isFrameSet() ||
774 o
->isSVGContainer() || o
->isSVGRoot() ) ) // for svg
778 // this is just to make sure we return a valid element.
779 // the case below should never happen...
780 if(!o
|| !o
->isRenderBlock()) {
783 kDebug( 6040 ) << this << ": " << renderName() << "(RenderObject): No containingBlock!";
784 kDebug( 6040 ) << kBacktrace();
785 const RenderObject
* p
= this;
786 while (p
->parent()) p
= p
->parent();
790 return canvas(); // likely wrong, but better than a crash
793 return static_cast<RenderBlock
*>( o
);
796 short RenderObject::containingBlockWidth(RenderObject
*) const
799 return containingBlock()->contentWidth();
802 int RenderObject::containingBlockHeight(RenderObject
*) const
805 return containingBlock()->contentHeight();
808 bool RenderObject::sizesToMaxWidth() const
810 // Marquees in WinIE are like a mixture of blocks and inline-blocks. They size as though they're blocks,
811 // but they allow text to sit on the same line as the marquee.
812 if (isFloating() || isCompact() ||
813 (isInlineBlockOrInlineTable() && !isHTMLMarquee()) ||
814 (element() && (element()->id() == ID_BUTTON
|| element()->id() == ID_LEGEND
)))
817 // Children of a horizontal marquee do not fill the container by default.
818 // FIXME: Need to deal with MAUTO value properly. It could be vertical.
819 if (parent()->style()->overflowX() == OMARQUEE
) {
820 EMarqueeDirection dir
= parent()->style()->marqueeDirection();
821 if (dir
== MAUTO
|| dir
== MFORWARD
|| dir
== MBACKWARD
|| dir
== MLEFT
|| dir
== MRIGHT
)
825 #ifdef APPLE_CHANGES // ### what the heck is a flexbox?
826 // Flexible horizontal boxes lay out children at their maxwidths. Also vertical boxes
827 // that don't stretch their kids lay out their children at their maxwidths.
828 if (parent()->isFlexibleBox() &&
829 (parent()->style()->boxOrient() == HORIZONTAL
|| parent()->style()->boxAlign() != BSTRETCH
))
836 // from Mozilla's nsCSSColorUtils.cpp
837 static int brightness(int red
, int green
, int blue
)
840 int intensity
= (red
+ green
+ blue
) / 3;
843 ((RED_LUMINOSITY
* red
) / 100) +
844 ((GREEN_LUMINOSITY
* green
) / 100) +
845 ((BLUE_LUMINOSITY
* blue
) / 100);
847 return ((intensity
* INTENSITY_FACTOR
) +
848 (luminosity
* LUMINOSITY_FACTOR
)) / 100;
851 static void calc3DColor(QColor
&color
, bool darken
)
853 int rb
= color
.red();
854 int gb
= color
.green();
855 int bb
= color
.blue();
856 int a
= color
.alpha();
858 int brightness_
= brightness(rb
,gb
,bb
);
861 if (brightness_
< COLOR_DARK_THRESHOLD
) {
862 f0
= COLOR_DARK_BS_FACTOR
;
863 f1
= COLOR_DARK_TS_FACTOR
;
864 } else if (brightness_
> COLOR_LIGHT_THRESHOLD
) {
865 f0
= COLOR_LITE_BS_FACTOR
;
866 f1
= COLOR_LITE_TS_FACTOR
;
868 f0
= COLOR_DARK_BS_FACTOR
+
870 (COLOR_LITE_BS_FACTOR
- COLOR_DARK_BS_FACTOR
) / MAX_COLOR
);
871 f1
= COLOR_DARK_TS_FACTOR
+
873 (COLOR_LITE_TS_FACTOR
- COLOR_DARK_TS_FACTOR
) / MAX_COLOR
);
877 int r
= rb
- (f0
* rb
/ 100);
878 int g
= gb
- (f0
* gb
/ 100);
879 int b
= bb
- (f0
* bb
/ 100);
880 if ((r
== rb
) && (g
== gb
) && (b
== bb
))
881 color
= (color
== Qt::black
) ? QColor(DARK_GRAY
) : QColor(Qt::black
);
883 color
.setRgb(r
, g
, b
);
885 int r
= qMin(rb
+ (f1
* (MAX_COLOR
- rb
) / 100), 255);
886 int g
= qMin(gb
+ (f1
* (MAX_COLOR
- gb
) / 100), 255);
887 int b
= qMin(bb
+ (f1
* (MAX_COLOR
- bb
) / 100), 255);
888 if ((r
== rb
) && (g
== gb
) && (b
== bb
))
889 color
= (color
== Qt::white
) ? QColor(LIGHT_GRAY
) : QColor(Qt::white
);
891 color
.setRgb(r
, g
, b
);
896 void RenderObject::drawBorder(QPainter
*p
, int x1
, int y1
, int x2
, int y2
,
897 BorderSide s
, QColor c
, const QColor
& textcolor
, EBorderStyle style
,
898 int adjbw1
, int adjbw2
, bool invalidisInvert
, qreal
*nextDashOffset
)
900 if(nextDashOffset
&& style
!= DOTTED
&& style
!= DASHED
)
903 if (p
->hasClipping() && !p
->clipRegion().boundingRect().intersects(QRect(x1
, y1
, x2
- x1
, y2
- y1
))) {
904 if (nextDashOffset
&& (style
== DOTTED
|| style
== DASHED
))
905 *nextDashOffset
+= (s
== BSTop
|| s
== BSBottom
) ? (x2
- x1
) : (y2
- y1
);
909 int width
= (s
==BSTop
||s
==BSBottom
?y2
-y1
:x2
-x1
);
911 if(style
== DOUBLE
&& width
< 3)
917 // handle 'outline-color: invert'
918 if (p
->paintEngine()->hasFeature(QPaintEngine::BlendModes
)) {
919 p
->setCompositionMode(QPainter::CompositionMode_Difference
);
922 // 'invert' is not supported on this platform (for instance XRender)
923 // CSS3 UI 8.4: If the UA does not support the 'invert' value then the initial value of
924 // the 'outline-color' property is the 'currentColor' [CSS3COLOR] keyword.
925 c
= m_style
->color();
929 if(style
== INSET
|| style
== OUTSET
|| style
== RIDGE
|| style
==
943 if(invalidisInvert
&& p
->compositionMode() == QPainter::CompositionMode_Difference
)
944 p
->setCompositionMode(QPainter::CompositionMode_SourceOver
);
953 //Figure out on/off spacing
971 // Compute the offset for the dash pattern, taking the direction of
972 // the line into account. (The borders are drawn counter-clockwise)
974 if (nextDashOffset
) {
977 // The left border is drawn top to bottom
979 offset
.ry() = -qRound(*nextDashOffset
);
980 *nextDashOffset
+= (y2
- y1
);
983 // The bottom border is drawn left to right
985 offset
.rx() = -qRound(*nextDashOffset
);
986 *nextDashOffset
+= (x2
- x1
);
989 // The top border is drawn right to left
991 offset
.rx() = (x2
- x1
) + offLen
+ qRound(*nextDashOffset
);
992 *nextDashOffset
+= (x2
- x1
);
995 // The right border is drawn bottom to top
997 offset
.ry() = (y2
- y1
) + offLen
+ qRound(*nextDashOffset
);
998 *nextDashOffset
+= (y2
- y1
);
1002 offset
.rx() = offset
.x() % (onLen
+ offLen
);
1003 offset
.ry() = offset
.y() % (onLen
+ offLen
);
1006 if ((onLen
+ offLen
) <= 32 && width
< 0x7fff)
1008 if (!s_dashedLineCache
)
1009 s_dashedLineCache
= new QCache
<quint64
, QPixmap
>(30);
1011 bool horizontal
= (s
== BSBottom
|| s
== BSTop
);
1012 quint64 key
= int(horizontal
) << 31 | (onLen
& 0xff) << 23 | (offLen
& 0xff) << 15 | (width
& 0x7fff);
1013 key
= key
<< 32 | c
.rgba();
1015 QPixmap
*tile
= s_dashedLineCache
->object(key
);
1019 int size
= (onLen
+ offLen
) * (64 / (onLen
+ offLen
));
1022 tile
= new QPixmap(size
, width
);
1023 tile
->fill(Qt::transparent
);
1024 for (int x
= 0; x
< tile
->width(); x
+= onLen
+ offLen
)
1025 path
.addRect(x
, 0, onLen
, tile
->height());
1029 tile
= new QPixmap(width
, size
);
1030 tile
->fill(Qt::transparent
);
1031 for (int y
= 0; y
< tile
->height(); y
+= onLen
+ offLen
)
1032 path
.addRect(0, y
, tile
->width(), onLen
);
1035 p2
.fillPath(path
, c
);
1037 s_dashedLineCache
->insert(key
, tile
);
1040 QRect r
= QRect(x1
, y1
, x2
- x1
, y2
- y1
);
1041 if (p
->hasClipping())
1042 r
&= p
->clipRegion().boundingRect();
1044 // Make sure we're drawing the pattern in the correct phase
1045 if (horizontal
&& r
.left() > x1
)
1046 offset
.rx() += (x1
- r
.left());
1047 else if (!horizontal
&& r
.top() > y1
)
1048 offset
.ry() += (y1
- r
.top());
1050 p
->drawTiledPixmap(r
, *tile
, -offset
);
1054 const QRect
bounding(x1
, y1
, x2
- x1
, y2
- y1
);
1056 if (s
== BSBottom
|| s
== BSTop
) //Horizontal
1059 offset
.rx() -= onLen
+ offLen
;
1060 for (int x
= x1
+ offset
.x(); x
< x2
; x
+= onLen
+ offLen
) {
1061 const QRect
r(x
, y1
, qMin(onLen
, (x2
- x
)), width
);
1062 path
.addRect(r
& bounding
);
1068 offset
.ry() -= onLen
+ offLen
;
1069 for (int y
= y1
+ offset
.y(); y
< y2
; y
+= onLen
+ offLen
) {
1070 const QRect
r(x1
, y
, width
, qMin(onLen
, (y2
- y
)));
1071 path
.addRect(r
& bounding
);
1075 p
->fillPath(path
, c
);
1081 int third
= (width
+1)/3;
1083 if (adjbw1
== 0 && adjbw2
== 0)
1085 p
->setPen(Qt::NoPen
);
1091 p
->drawRect(x1
, y1
, x2
-x1
, third
);
1092 p
->drawRect(x1
, y2
-third
, x2
-x1
, third
);
1095 p
->drawRect(x1
, y1
, third
, y2
-y1
);
1096 p
->drawRect(x2
-third
, y1
, third
, y2
-y1
);
1099 p
->drawRect(x1
, y1
, third
, y2
-y1
);
1100 p
->drawRect(x2
-third
, y1
, third
, y2
-y1
);
1107 if (adjbw1
>0) adjbw1bigthird
= adjbw1
+1;
1108 else adjbw1bigthird
= adjbw1
- 1;
1109 adjbw1bigthird
/= 3;
1112 if (adjbw2
>0) adjbw2bigthird
= adjbw2
+ 1;
1113 else adjbw2bigthird
= adjbw2
- 1;
1114 adjbw2bigthird
/= 3;
1119 drawBorder(p
, x1
+qMax((-adjbw1
*2+1)/3,0), y1
, x2
-qMax((-adjbw2
*2+1)/3,0), y1
+ third
, s
, c
, textcolor
, SOLID
, adjbw1bigthird
, adjbw2bigthird
);
1120 drawBorder(p
, x1
+qMax(( adjbw1
*2+1)/3,0), y2
- third
, x2
-qMax(( adjbw2
*2+1)/3,0), y2
, s
, c
, textcolor
, SOLID
, adjbw1bigthird
, adjbw2bigthird
);
1123 drawBorder(p
, x1
, y1
+qMax((-adjbw1
*2+1)/3,0), x1
+third
, y2
-qMax((-adjbw2
*2+1)/3,0), s
, c
, textcolor
, SOLID
, adjbw1bigthird
, adjbw2bigthird
);
1124 drawBorder(p
, x2
- third
, y1
+qMax(( adjbw1
*2+1)/3,0), x2
, y2
-qMax(( adjbw2
*2+1)/3,0), s
, c
, textcolor
, SOLID
, adjbw1bigthird
, adjbw2bigthird
);
1127 drawBorder(p
, x1
+qMax(( adjbw1
*2+1)/3,0), y1
, x2
-qMax(( adjbw2
*2+1)/3,0), y1
+third
, s
, c
, textcolor
, SOLID
, adjbw1bigthird
, adjbw2bigthird
);
1128 drawBorder(p
, x1
+qMax((-adjbw1
*2+1)/3,0), y2
-third
, x2
-qMax((-adjbw2
*2+1)/3,0), y2
, s
, c
, textcolor
, SOLID
, adjbw1bigthird
, adjbw2bigthird
);
1131 drawBorder(p
, x1
, y1
+qMax(( adjbw1
*2+1)/3,0), x1
+third
, y2
-qMax(( adjbw2
*2+1)/3,0), s
, c
, textcolor
, SOLID
, adjbw1bigthird
, adjbw2bigthird
);
1132 drawBorder(p
, x2
-third
, y1
+qMax((-adjbw1
*2+1)/3,0), x2
, y2
-qMax((-adjbw2
*2+1)/3,0), s
, c
, textcolor
, SOLID
, adjbw1bigthird
, adjbw2bigthird
);
1158 if (adjbw1
>0) adjbw1bighalf
=adjbw1
+1;
1159 else adjbw1bighalf
=adjbw1
-1;
1162 if (adjbw2
>0) adjbw2bighalf
=adjbw2
+1;
1163 else adjbw2bighalf
=adjbw2
-1;
1169 drawBorder(p
, x1
+qMax(-adjbw1
,0)/2, y1
, x2
-qMax(-adjbw2
,0)/2, (y1
+y2
+1)/2, s
, c
, textcolor
, s1
, adjbw1bighalf
, adjbw2bighalf
);
1170 drawBorder(p
, x1
+qMax( adjbw1
+1,0)/2, (y1
+y2
+1)/2, x2
-qMax( adjbw2
+1,0)/2, y2
, s
, c
, textcolor
, s2
, adjbw1
/2, adjbw2
/2);
1173 drawBorder(p
, x1
, y1
+qMax(-adjbw1
,0)/2, (x1
+x2
+1)/2, y2
-qMax(-adjbw2
,0)/2, s
, c
, textcolor
, s1
, adjbw1bighalf
, adjbw2bighalf
);
1174 drawBorder(p
, (x1
+x2
+1)/2, y1
+qMax( adjbw1
+1,0)/2, x2
, y2
-qMax( adjbw2
+1,0)/2, s
, c
, textcolor
, s2
, adjbw1
/2, adjbw2
/2);
1177 drawBorder(p
, x1
+qMax( adjbw1
,0)/2, y1
, x2
-qMax( adjbw2
,0)/2, (y1
+y2
+1)/2, s
, c
, textcolor
, s2
, adjbw1bighalf
, adjbw2bighalf
);
1178 drawBorder(p
, x1
+qMax(-adjbw1
+1,0)/2, (y1
+y2
+1)/2, x2
-qMax(-adjbw2
+1,0)/2, y2
, s
, c
, textcolor
, s1
, adjbw1
/2, adjbw2
/2);
1181 drawBorder(p
, x1
, y1
+qMax( adjbw1
,0)/2, (x1
+x2
+1)/2, y2
-qMax( adjbw2
,0)/2, s
, c
, textcolor
, s2
, adjbw1bighalf
, adjbw2bighalf
);
1182 drawBorder(p
, (x1
+x2
+1)/2, y1
+qMax(-adjbw1
+1,0)/2, x2
, y2
-qMax(-adjbw2
+1,0)/2, s
, c
, textcolor
, s1
, adjbw1
/2, adjbw2
/2);
1189 calc3DColor(c
, (style
== OUTSET
&& (s
== BSBottom
|| s
== BSRight
)) ||
1190 (style
== INSET
&& ( s
== BSTop
|| s
== BSLeft
) ) );
1193 p
->setPen(Qt::NoPen
);
1197 if (adjbw1
==0 && adjbw2
== 0) {
1198 p
->drawRect(x1
,y1
,x2
-x1
,y2
-y1
);
1205 x1
+qMax(-adjbw1
,0), y1
,
1206 x1
+qMax( adjbw1
,0), y2
,
1207 x2
-qMax( adjbw2
,0), y2
,
1208 x2
-qMax(-adjbw2
,0), y1
);
1212 x1
+qMax( adjbw1
,0), y1
,
1213 x1
+qMax(-adjbw1
,0), y2
,
1214 x2
-qMax(-adjbw2
,0), y2
,
1215 x2
-qMax( adjbw2
,0), y1
);
1219 x1
, y1
+qMax(-adjbw1
,0),
1220 x1
, y2
-qMax(-adjbw2
,0),
1221 x2
, y2
-qMax( adjbw2
,0),
1222 x2
, y1
+qMax( adjbw1
,0));
1226 x1
, y1
+qMax( adjbw1
,0),
1227 x1
, y2
-qMax( adjbw2
,0),
1228 x2
, y2
-qMax(-adjbw2
,0),
1229 x2
, y1
+qMax(-adjbw1
,0));
1232 p
->drawConvexPolygon(quad
);
1236 if(invalidisInvert
&& p
->compositionMode() == QPainter::CompositionMode_Difference
)
1237 p
->setCompositionMode(QPainter::CompositionMode_SourceOver
);
1240 void RenderObject::adjustBorderRadii(BorderRadii
&tl
, BorderRadii
&tr
, BorderRadii
&bl
, BorderRadii
&br
, int w
, int h
) const
1242 // CSS Backgrounds and Borders Module Level 3 (WD-css3-background-20080910), chapter 4.5:
1243 // " Corners do not overlap: When the sum of two adjacent corner radii exceeds the size of the border box,
1244 // UAs must reduce one or more of the radii. The algorithm for reducing radii is as follows:"
1245 // The sum of two adjacent radii may not be more than the width or height (whichever is relevant) of the box.
1246 // If any sum exceeds that value, all radii are reduced according to the following formula:"
1247 const int horS
= qMax(tl
.horizontal
+ tr
.horizontal
, bl
.horizontal
+ br
.horizontal
);
1248 const int verS
= qMax(tl
.vertical
+ bl
.vertical
, tr
.vertical
+ br
.vertical
);
1252 f
= qMin(f
, w
/ qreal(horS
));
1254 f
= qMin(f
, h
/ qreal(verS
));
1268 static QImage
blendCornerImages(const QImage
&image1
, const QImage
&image2
)
1270 QImage
mask(image1
.size(), QImage::Format_ARGB32_Premultiplied
);
1271 QImage composite
= image1
;
1272 QImage temp
= image2
;
1274 // Construct the mask image
1275 QConicalGradient
gradient(mask
.width() / 2, mask
.height() / 2, 0);
1276 gradient
.setColorAt(0.00, Qt::transparent
);
1277 gradient
.setColorAt(0.25, Qt::black
);
1278 gradient
.setColorAt(0.50, Qt::black
);
1279 gradient
.setColorAt(0.75, Qt::transparent
);
1280 gradient
.setColorAt(1.00, Qt::transparent
);
1282 QBrush gradientBrush
= gradient
;
1284 if (mask
.width() != mask
.height()) {
1285 int min
= qMin(mask
.width(), mask
.height());
1287 xform
.translate(mask
.width() / 2, mask
.height() / 2);
1288 xform
.scale(min
/ mask
.width(), min
/ mask
.height());
1289 gradientBrush
.setTransform(xform
);
1294 p
.setCompositionMode(QPainter::CompositionMode_Source
);
1295 p
.fillRect(mask
.rect(), gradientBrush
);
1299 p
.setCompositionMode(QPainter::CompositionMode_DestinationIn
);
1300 p
.drawImage(0, 0, mask
);
1303 p
.begin(&composite
);
1304 p
.setCompositionMode(QPainter::CompositionMode_DestinationOut
);
1305 p
.drawImage(0, 0, mask
);
1306 p
.setCompositionMode(QPainter::CompositionMode_SourceOver
);
1307 p
.drawImage(0, 0, temp
);
1313 static QBrush
cornerGradient(int cx
, int cy
, const BorderRadii
&radius
, int angleStart
, int angleSpan
,
1314 const QColor
&startColor
, const QColor
&finalColor
)
1316 QConicalGradient
g(0, 0, angleStart
);
1317 g
.setColorAt(0, startColor
);
1318 g
.setColorAt(angleSpan
/ 360.0, finalColor
);
1323 xform
.translate(cx
, cy
);
1325 if (radius
.horizontal
< radius
.vertical
)
1326 xform
.scale(radius
.horizontal
/ radius
.vertical
, 1);
1327 else if (radius
.vertical
< radius
.horizontal
)
1328 xform
.scale(1, radius
.vertical
/ radius
.horizontal
);
1330 brush
.setTransform(xform
);
1334 void RenderObject::drawBorderArc(QPainter
*p
, int x
, int y
, float horThickness
, float vertThickness
,
1335 const BorderRadii
&radius
, int angleStart
, int angleSpan
, const QBrush
&brush
,
1336 const QColor
&textColor
, EBorderStyle style
, qreal
*nextDashOffset
) const
1338 QColor c
= brush
.color();
1340 if (style
== INSET
|| style
== OUTSET
|| style
== RIDGE
|| style
== GROOVE
)
1348 calc3DColor(light
, false);
1349 calc3DColor(dark
, true);
1351 if (style
== DOUBLE
&& horThickness
< 3 && vertThickness
< 3)
1354 if (nextDashOffset
&& style
!= DOTTED
&& style
!= DASHED
)
1355 *nextDashOffset
= 0;
1358 p
->setRenderHint(QPainter::Antialiasing
);
1366 // Should not happen
1372 const QRect outerRect
= QRect(x
- radius
.horizontal
, y
- radius
.vertical
, radius
.horizontal
* 2, radius
.vertical
* 2);
1373 const QRect innerRect
= outerRect
.adjusted(horThickness
, vertThickness
, -horThickness
, -vertThickness
);
1375 path
.arcMoveTo(outerRect
, angleStart
);
1376 path
.arcTo(outerRect
, angleStart
, angleSpan
);
1377 if (innerRect
.isValid())
1378 path
.arcTo(innerRect
, angleStart
+ angleSpan
, -angleSpan
);
1381 path
.closeSubpath();
1382 p
->fillPath(path
, brush
);
1388 const qreal hw
= (horThickness
+ 1) / 3;
1389 const qreal vw
= (vertThickness
+ 1) / 3;
1392 br
.horizontal
= radius
.horizontal
- hw
* 2 + 1;
1393 br
.vertical
= radius
.vertical
- vw
* 2 + 1;
1395 drawBorderArc(p
, x
, y
, hw
, vw
, radius
, angleStart
, angleSpan
, brush
, textColor
, SOLID
);
1396 drawBorderArc(p
, x
, y
, hw
, vw
, br
, angleStart
, angleSpan
, brush
, textColor
, SOLID
);
1403 QImage
image1(radius
.horizontal
* 2, radius
.vertical
* 2, QImage::Format_ARGB32_Premultiplied
);
1406 QImage image2
= image1
;
1408 const QColor c1
= style
== OUTSET
? dark
: light
;
1409 const QColor c2
= style
== OUTSET
? light
: dark
;
1413 drawBorderArc(&p2
, radius
.horizontal
, radius
.vertical
, horThickness
, vertThickness
,
1414 radius
, angleStart
, angleSpan
, c1
, textColor
, SOLID
);
1418 drawBorderArc(&p2
, radius
.horizontal
, radius
.vertical
, horThickness
, vertThickness
,
1419 radius
, angleStart
, angleSpan
, c2
, textColor
, SOLID
);
1422 p
->drawImage(x
- radius
.horizontal
, y
- radius
.vertical
, blendCornerImages(image1
, image2
));
1429 QImage
image1(radius
.horizontal
* 2, radius
.vertical
* 2, QImage::Format_ARGB32_Premultiplied
);
1432 QImage image2
= image1
;
1434 const QColor c1
= style
== RIDGE
? dark
: light
;
1435 const QColor c2
= style
== RIDGE
? light
: dark
;
1437 const qreal hw
= horThickness
/ 2;
1438 const qreal vw
= vertThickness
/ 2;
1439 int cx
= radius
.horizontal
;
1440 int cy
= radius
.vertical
;
1442 BorderRadii innerRadius
;
1443 innerRadius
.horizontal
= radius
.horizontal
- hw
;
1444 innerRadius
.vertical
= radius
.vertical
- vw
;
1448 drawBorderArc(&p2
, cx
, cy
, hw
, vw
, radius
, angleStart
, angleSpan
, c1
, textColor
, SOLID
);
1449 drawBorderArc(&p2
, cx
, cy
, hw
, vw
, innerRadius
, angleStart
, angleSpan
, c2
, textColor
, SOLID
);
1453 drawBorderArc(&p2
, cx
, cy
, hw
, vw
, radius
, angleStart
, angleSpan
, c2
, textColor
, SOLID
);
1454 drawBorderArc(&p2
, cx
, cy
, hw
, vw
, innerRadius
, angleStart
, angleSpan
, c1
, textColor
, SOLID
);
1457 p
->drawImage(x
- radius
.horizontal
, y
- radius
.vertical
, blendCornerImages(image1
, image2
));
1464 const QRectF rect
= QRectF(x
- radius
.horizontal
, y
- radius
.vertical
, radius
.horizontal
* 2, radius
.vertical
* 2);
1467 // Figure out which border we're starting from
1468 angleStart
= angleStart
% 360;
1472 if ((angleStart
> 45 && angleStart
<= 135) || (angleStart
> 225 && angleStart
<= 315))
1473 width
= vertThickness
;
1475 width
= horThickness
;
1480 if (style
== DASHED
)
1494 BorderArcStroker stroker
;
1495 stroker
.setArc(rect
, angleStart
, angleSpan
);
1496 stroker
.setPenWidth(horThickness
, vertThickness
);
1497 stroker
.setDashPattern(onLen
, offLen
);
1498 stroker
.setDashOffset(*nextDashOffset
);
1500 const QPainterPath path
= stroker
.createStroke(nextDashOffset
);
1501 p
->fillPath(path
, brush
);
1508 void RenderObject::paintBorder(QPainter
*p
, int _tx
, int _ty
, int w
, int h
, const RenderStyle
* style
, bool begin
, bool end
)
1510 const QColor
& tc
= style
->borderTopColor();
1511 const QColor
& bc
= style
->borderBottomColor();
1512 const QColor
& lc
= style
->borderLeftColor();
1513 const QColor
& rc
= style
->borderRightColor();
1515 bool tt
= style
->borderTopIsTransparent();
1516 bool bt
= style
->borderBottomIsTransparent();
1517 bool rt
= style
->borderRightIsTransparent();
1518 bool lt
= style
->borderLeftIsTransparent();
1520 EBorderStyle ts
= style
->borderTopStyle();
1521 EBorderStyle bs
= style
->borderBottomStyle();
1522 EBorderStyle ls
= style
->borderLeftStyle();
1523 EBorderStyle rs
= style
->borderRightStyle();
1525 bool render_t
= ts
> BHIDDEN
&& !tt
;
1526 bool render_l
= ls
> BHIDDEN
&& begin
&& !lt
;
1527 bool render_r
= rs
> BHIDDEN
&& end
&& !rt
;
1528 bool render_b
= bs
> BHIDDEN
&& !bt
;
1530 BorderRadii topLeft
= style
->borderTopLeftRadius();
1531 BorderRadii topRight
= style
->borderTopRightRadius();
1532 BorderRadii bottomLeft
= style
->borderBottomLeftRadius();
1533 BorderRadii bottomRight
= style
->borderBottomRightRadius();
1535 if (style
->hasBorderRadius()) {
1536 // Adjust the border radii so they don't overlap when taking the size of the box
1538 adjustBorderRadii(topLeft
, topRight
, bottomLeft
, bottomRight
, w
, h
);
1541 bool upperLeftBorderStylesMatch
= render_l
&& (ts
== ls
) && (tc
== lc
);
1542 bool upperRightBorderStylesMatch
= render_r
&& (ts
== rs
) && (tc
== rc
);
1543 bool lowerLeftBorderStylesMatch
= render_l
&& (bs
== ls
) && (bc
== lc
);
1544 bool lowerRightBorderStylesMatch
= render_r
&& (bs
== rs
) && (bc
== rc
);
1546 // We do a gradient transition for dotted, dashed, solid and double lines
1547 // when the styles match but the colors differ.
1548 bool upperLeftGradient
= render_t
&& render_l
&& ts
== ls
&& tc
!= lc
&& ts
> OUTSET
;
1549 bool upperRightGradient
= render_t
&& render_r
&& ts
== rs
&& tc
!= rc
&& ts
> OUTSET
;
1550 bool lowerLeftGradient
= render_b
&& render_l
&& bs
== ls
&& bc
!= lc
&& bs
> OUTSET
;
1551 bool lowerRightGradient
= render_b
&& render_r
&& bs
== rs
&& bc
!= rc
&& bs
> OUTSET
;
1553 qreal nextDashOffset
= 0;
1555 // Draw the borders counter-clockwise starting with the upper right corner
1557 bool ignore_left
= (topLeft
.horizontal
> 0) ||
1558 ((tc
== lc
) && (tt
== lt
) &&
1560 (ls
== DOTTED
|| ls
== DASHED
|| ls
== SOLID
|| ls
== OUTSET
));
1562 bool ignore_right
= (topRight
.horizontal
> 0) ||
1563 ((tc
== rc
) && (tt
== rt
) &&
1565 (rs
== DOTTED
|| rs
== DASHED
|| rs
== SOLID
|| rs
== INSET
));
1567 int x
= _tx
+ topLeft
.horizontal
;
1568 int x2
= _tx
+ w
- topRight
.horizontal
;
1570 if (topRight
.hasBorderRadius()) {
1571 int x
= _tx
+ w
- topRight
.horizontal
;
1572 int y
= _ty
+ topRight
.vertical
;
1573 int startAngle
, span
;
1575 if (upperRightBorderStylesMatch
|| upperRightGradient
) {
1583 const QBrush brush
= upperRightGradient
?
1584 cornerGradient(x
, y
, topRight
, startAngle
, span
, rc
, tc
) : tc
;
1586 // Draw the upper right arc
1587 drawBorderArc(p
, x
, y
, style
->borderRightWidth(), style
->borderTopWidth(),
1588 topRight
, startAngle
, span
, brush
, style
->color(), ts
, &nextDashOffset
);
1591 drawBorder(p
, x
, _ty
, x2
, _ty
+ style
->borderTopWidth(), BSTop
, tc
, style
->color(), ts
,
1592 ignore_left
?0:style
->borderLeftWidth(),
1593 ignore_right
?0:style
->borderRightWidth(), false, &nextDashOffset
);
1595 if (topLeft
.hasBorderRadius()) {
1596 int x
= _tx
+ topLeft
.horizontal
;
1597 int y
= _ty
+ topLeft
.vertical
;
1598 int startAngle
= 90;
1599 int span
= (upperLeftBorderStylesMatch
|| upperLeftGradient
) ? 90 : 45;
1600 const QBrush brush
= upperLeftGradient
?
1601 cornerGradient(x
, y
, topLeft
, startAngle
, span
, tc
, lc
) : tc
;
1603 // Draw the upper left arc
1604 drawBorderArc(p
, x
, y
, style
->borderLeftWidth(), style
->borderTopWidth(),
1605 topLeft
, startAngle
, span
, brush
, style
->color(), ts
, &nextDashOffset
);
1606 } else if (ls
== DASHED
|| ls
== DOTTED
)
1607 nextDashOffset
= 0; // Reset the offset to avoid partially overlapping dashes
1612 bool ignore_top
= (topLeft
.vertical
> 0) ||
1613 ((tc
== lc
) && (tt
== lt
) &&
1615 (ts
== DOTTED
|| ts
== DASHED
|| ts
== SOLID
|| ts
== OUTSET
));
1617 bool ignore_bottom
= (bottomLeft
.vertical
> 0) ||
1618 ((bc
== lc
) && (bt
== lt
) &&
1620 (bs
== DOTTED
|| bs
== DASHED
|| bs
== SOLID
|| bs
== INSET
));
1622 int y
= _ty
+ topLeft
.vertical
;
1623 int y2
= _ty
+ h
- bottomLeft
.vertical
;
1625 if (!upperLeftBorderStylesMatch
&& !upperLeftGradient
&& topLeft
.hasBorderRadius()) {
1626 int x
= _tx
+ topLeft
.horizontal
;
1627 int y
= _ty
+ topLeft
.vertical
;
1628 int startAngle
= 135;
1631 // Draw the upper left arc
1632 drawBorderArc(p
, x
, y
, style
->borderLeftWidth(), style
->borderTopWidth(),
1633 topLeft
, startAngle
, span
, lc
, style
->color(), ls
, &nextDashOffset
);
1636 drawBorder(p
, _tx
, y
, _tx
+ style
->borderLeftWidth(), y2
, BSLeft
, lc
, style
->color(), ls
,
1637 ignore_top
?0:style
->borderTopWidth(),
1638 ignore_bottom
?0:style
->borderBottomWidth(), false, &nextDashOffset
);
1640 if (!lowerLeftBorderStylesMatch
&& !lowerLeftGradient
&& bottomLeft
.hasBorderRadius()) {
1641 int x
= _tx
+ bottomLeft
.horizontal
;
1642 int y
= _ty
+ h
- bottomLeft
.vertical
;
1643 int startAngle
= 180;
1646 // Draw the bottom left arc
1647 drawBorderArc(p
, x
, y
, style
->borderLeftWidth(), style
->borderBottomWidth(),
1648 bottomLeft
, startAngle
, span
, lc
, style
->color(), ls
, &nextDashOffset
);
1651 // Reset the offset to avoid partially overlapping dashes
1652 if (!bottomLeft
.hasBorderRadius() && (bs
== DASHED
|| bs
== DOTTED
))
1657 bool ignore_left
= (bottomLeft
.horizontal
> 0) ||
1658 ((bc
== lc
) && (bt
== lt
) &&
1660 (ls
== DOTTED
|| ls
== DASHED
|| ls
== SOLID
|| ls
== INSET
));
1662 bool ignore_right
= (bottomRight
.horizontal
> 0) ||
1663 ((bc
== rc
) && (bt
== rt
) &&
1665 (rs
== DOTTED
|| rs
== DASHED
|| rs
== SOLID
|| rs
== OUTSET
));
1667 int x
= _tx
+ bottomLeft
.horizontal
;
1668 int x2
= _tx
+ w
- bottomRight
.horizontal
;
1670 if (bottomLeft
.hasBorderRadius()) {
1671 int x
= _tx
+ bottomLeft
.horizontal
;
1672 int y
= _ty
+ h
- bottomLeft
.vertical
;
1673 int startAngle
, span
;
1675 if (lowerLeftBorderStylesMatch
|| lowerLeftGradient
) {
1683 const QBrush brush
= lowerLeftGradient
?
1684 cornerGradient(x
, y
, bottomLeft
, startAngle
, span
, lc
, bc
) : bc
;
1686 // Draw the bottom left arc
1687 drawBorderArc(p
, x
, y
, style
->borderLeftWidth(), style
->borderBottomWidth(),
1688 bottomLeft
, startAngle
, span
, brush
, style
->color(), bs
, &nextDashOffset
);
1691 drawBorder(p
, x
, _ty
+ h
- style
->borderBottomWidth(), x2
, _ty
+ h
, BSBottom
, bc
, style
->color(), bs
,
1692 ignore_left
?0:style
->borderLeftWidth(),
1693 ignore_right
?0:style
->borderRightWidth(), false, &nextDashOffset
);
1695 if (bottomRight
.hasBorderRadius()) {
1696 int x
= _tx
+ w
- bottomRight
.horizontal
;
1697 int y
= _ty
+ h
- bottomRight
.vertical
;
1698 int startAngle
= 270;
1699 int span
= (lowerRightBorderStylesMatch
|| lowerRightGradient
) ? 90 : 45;
1700 const QBrush brush
= lowerRightGradient
?
1701 cornerGradient(x
, y
, bottomRight
, startAngle
, span
, bc
, rc
) : bc
;
1703 // Draw the bottom right arc
1704 drawBorderArc(p
, x
, y
, style
->borderRightWidth(), style
->borderBottomWidth(),
1705 bottomRight
, startAngle
, span
, brush
, style
->color(), bs
, &nextDashOffset
);
1707 else if (rs
== DASHED
|| rs
== DOTTED
)
1708 nextDashOffset
= 0; // Reset the offset to avoid partially overlapping dashes
1713 bool ignore_top
= (topRight
.vertical
> 0) ||
1714 ((tc
== rc
) && (tt
== rt
) &&
1715 (rs
>= DOTTED
|| rs
== INSET
) &&
1716 (ts
== DOTTED
|| ts
== DASHED
|| ts
== SOLID
|| ts
== OUTSET
));
1718 bool ignore_bottom
= (bottomRight
.vertical
> 0) ||
1719 ((bc
== rc
) && (bt
== rt
) &&
1720 (rs
>= DOTTED
|| rs
== INSET
) &&
1721 (bs
== DOTTED
|| bs
== DASHED
|| bs
== SOLID
|| bs
== INSET
));
1723 int y
= _ty
+ topRight
.vertical
;
1724 int y2
= _ty
+ h
- bottomRight
.vertical
;
1726 if (!lowerRightBorderStylesMatch
&& !lowerRightGradient
&& bottomRight
.hasBorderRadius()) {
1727 int x
= _tx
+ w
- bottomRight
.horizontal
;
1728 int y
= _ty
+ h
- bottomRight
.vertical
;
1729 int startAngle
= 315;
1732 // Draw the bottom right arc
1733 drawBorderArc(p
, x
, y
, style
->borderRightWidth(), style
->borderBottomWidth(),
1734 bottomRight
, startAngle
, span
, rc
, style
->color(), rs
, &nextDashOffset
);
1737 drawBorder(p
, _tx
+ w
- style
->borderRightWidth(), y
, _tx
+ w
, y2
, BSRight
, rc
, style
->color(), rs
,
1738 ignore_top
?0:style
->borderTopWidth(),
1739 ignore_bottom
?0:style
->borderBottomWidth(), false, &nextDashOffset
);
1741 if (!upperRightBorderStylesMatch
&& !upperRightGradient
&& topRight
.hasBorderRadius()) {
1742 int x
= _tx
+ w
- topRight
.horizontal
;
1743 int y
= _ty
+ topRight
.vertical
;
1747 // Draw the upper right arc
1748 drawBorderArc(p
, x
, y
, style
->borderRightWidth(), style
->borderTopWidth(),
1749 topRight
, startAngle
, span
, rc
, style
->color(), rs
, &nextDashOffset
);
1754 void RenderObject::paintOutline(QPainter
*p
, int _tx
, int _ty
, int w
, int h
, const RenderStyle
* style
)
1756 int ow
= style
->outlineWidth();
1759 const QColor
& oc
= style
->outlineColor();
1760 EBorderStyle os
= style
->outlineStyle();
1761 int offset
= style
->outlineOffset();
1763 #ifdef APPLE_CHANGES
1764 if (style
->outlineStyleIsAuto()) {
1765 p
->initFocusRing(ow
, offset
, oc
);
1766 addFocusRingRects(p
, _tx
, _ty
);
1768 p
->clearFocusRing();
1778 drawBorder(p
, _tx
-ow
, _ty
-ow
, _tx
, _ty
+h
+ow
, BSLeft
,
1779 QColor(oc
), style
->color(),
1782 drawBorder(p
, _tx
-ow
, _ty
-ow
, _tx
+w
+ow
, _ty
, BSTop
,
1783 QColor(oc
), style
->color(),
1786 drawBorder(p
, _tx
+w
, _ty
-ow
, _tx
+w
+ow
, _ty
+h
+ow
, BSRight
,
1787 QColor(oc
), style
->color(),
1790 drawBorder(p
, _tx
-ow
, _ty
+h
, _tx
+w
+ow
, _ty
+h
+ow
, BSBottom
,
1791 QColor(oc
), style
->color(),
1796 void RenderObject::paint( PaintInfo
&, int /*tx*/, int /*ty*/)
1800 void RenderObject::repaintRectangle(int x
, int y
, int w
, int h
, Priority p
, bool f
)
1802 if(parent()) parent()->repaintRectangle(x
, y
, w
, h
, p
, f
);
1807 QString
RenderObject::information() const
1811 absolutePosition(x
,y
);
1814 QTextStream
ts( &str
, QIODevice::WriteOnly
);
1816 << "(" << (style() ? style()->refCount() : 0) << ")"
1817 << ": " << (void*)this << " ";
1818 ts
<< "{" << x
<< " " << y
<< "} ";
1819 if (isInline()) ts
<< "il ";
1820 if (childrenInline()) ts
<< "ci ";
1821 if (isFloating()) ts
<< "fl ";
1822 if (isAnonymous()) ts
<< "an ";
1823 if (isRelPositioned()) ts
<< "rp ";
1824 if (isPositioned()) ts
<< "ps ";
1825 if (isReplaced()) ts
<< "rp ";
1826 if (needsLayout()) ts
<< "nl ";
1827 if (minMaxKnown()) ts
<< "mmk ";
1828 if (m_recalcMinMax
) ts
<< "rmm ";
1829 if (mouseInside()) ts
<< "mi ";
1830 if (style() && style()->zIndex()) ts
<< "zI: " << style()->zIndex();
1831 if (style() && style()->hasAutoZIndex()) ts
<< "zI: auto ";
1833 if (element()->active()) ts
<< "act ";
1834 if (element()->hasAnchor()) ts
<< "anchor ";
1835 if (element()->focused()) ts
<< "focus ";
1836 ts
<< " <" << LocalName::fromId(localNamePart(element()->id())).toString().string() << ">";
1838 } else if (isPseudoAnonymous() && style() && style()->styleType() != RenderStyle::NOPSEUDO
) {
1839 ts
<< " <" << LocalName::fromId(localNamePart(node()->id())).toString().string();
1841 switch (style()->styleType()) {
1842 case RenderStyle::FIRST_LETTER
:
1843 pseudo
= ":first-letter"; break;
1844 case RenderStyle::BEFORE
:
1845 pseudo
= ":before"; break;
1846 case RenderStyle::AFTER
:
1847 pseudo
= ":after"; break;
1849 pseudo
= ":pseudo-element";
1854 ts
<< " (" << xPos() << "," << yPos() << "," << width() << "," << height() << ")"
1855 << " [" << minWidth() << "-" << maxWidth() << "]"
1856 << " { mT: " << marginTop() << " qT: " << isTopMarginQuirk()
1857 << " mB: " << marginBottom() << " qB: " << isBottomMarginQuirk()
1860 ( QLatin1String(" [r=") +
1861 QString::number( static_cast<const RenderTableCell
*>(this)->row() ) +
1862 QLatin1String(" c=") +
1863 QString::number( static_cast<const RenderTableCell
*>(this)->col() ) +
1864 QLatin1String(" rs=") +
1865 QString::number( static_cast<const RenderTableCell
*>(this)->rowSpan() ) +
1866 QLatin1String(" cs=") +
1867 QString::number( static_cast<const RenderTableCell
*>(this)->colSpan() ) +
1868 QLatin1String("]") ) : QString() );
1870 ts
<< " layer=" << layer();
1871 if ( continuation() )
1872 ts
<< " continuation=" << continuation();
1874 ts
<< " \"" << QString::fromRawData(static_cast<const RenderText
*>(this)->text(), qMin(static_cast<const RenderText
*>(this)->length(), 10u)) << "\"";
1878 void RenderObject::printTree(int indent
) const
1881 ind
.fill(' ', indent
);
1883 kDebug() << (ind
+ information());
1885 RenderObject
*child
= firstChild();
1888 child
->printTree(indent
+2);
1889 child
= child
->nextSibling();
1893 static QTextStream
&operator<<(QTextStream
&ts
, const QRect
&r
)
1895 return ts
<< "at (" << r
.x() << "," << r
.y() << ") size " << r
.width() << "x" << r
.height();
1898 //A bit like getTagName, but handles XML, too.
1899 static QString
lookupTagName(NodeImpl
* node
) {
1900 return LocalName::fromId(node
->id()).toString().string();
1903 void RenderObject::dump(QTextStream
&ts
, const QString
&ind
) const
1908 ts
<< ind
<< renderName();
1910 if (style() && style()->zIndex()) {
1911 ts
<< " zI: " << style()->zIndex();
1915 QString
tagName(lookupTagName(element()));
1916 if (!tagName
.isEmpty()) {
1917 ts
<< " {" << tagName
<< "}";
1919 } else if (isPseudoAnonymous() && style() && style()->styleType() != RenderStyle::NOPSEUDO
) {
1921 QString
tagName(lookupTagName(node()));
1922 switch (style()->styleType()) {
1923 case RenderStyle::FIRST_LETTER
:
1924 pseudo
= ":first-letter"; break;
1925 case RenderStyle::BEFORE
:
1926 pseudo
= ":before"; break;
1927 case RenderStyle::AFTER
:
1928 pseudo
= ":after"; break;
1930 pseudo
= ":pseudo-element";
1932 ts
<< " {" << tagName
<< pseudo
<< "}";
1935 QRect
r(xPos(), yPos(), width(), height());
1939 ts
<< style()->createDiff( *parent()->style() );
1941 if (isAnonymous()) { ts
<< " anonymousBox"; }
1942 if (isFloating()) { ts
<< " floating"; }
1943 if (isPositioned()) { ts
<< " positioned"; }
1944 if (isRelPositioned()) { ts
<< " relPositioned"; }
1945 if (isText()) { ts
<< " text"; }
1946 if (isInline()) { ts
<< " inline"; }
1947 if (isReplaced()) { ts
<< " replaced"; }
1948 if (shouldPaintBackgroundOrBorder()) { ts
<< " paintBackground"; }
1949 if (needsLayout()) { ts
<< " needsLayout"; }
1950 if (minMaxKnown()) { ts
<< " minMaxKnown"; }
1951 if (hasFirstLine()) { ts
<< " hasFirstLine"; }
1952 if (afterPageBreak()) { ts
<< " afterPageBreak"; }
1956 bool RenderObject::shouldSelect() const
1959 const RenderObject
* curr
= this;
1960 DOM::NodeImpl
*node
= 0;
1961 bool forcedOn
= false;
1964 if (curr
->style()->userSelect() == SELECT_TEXT
)
1966 if (!forcedOn
&& curr
->style()->userSelect() == SELECT_NONE
)
1970 node
= curr
->element();
1971 curr
= curr
->parent();
1974 // somewhere up the render tree there must be an element!
1977 return node
->dispatchHTMLEvent(DOM::EventImpl::SELECTSTART_EVENT
, true, true);
1983 void RenderObject::selectionStartEnd(int& spos
, int& epos
)
1986 parent()->selectionStartEnd(spos
, epos
);
1989 void RenderObject::setStyle(RenderStyle
*style
)
1991 if (m_style
== style
)
1994 RenderStyle::Diff d
= m_style
? m_style
->diff( style
) : RenderStyle::Layout
;
1995 //qDebug("m_style: %p new style, diff=%d", m_style, d);
1997 Priority pri
= NormalPriority
;
2000 if ( d
>= RenderStyle::Visible
&& !isText() && m_parent
&&
2001 ( d
== RenderStyle::Position
||
2002 m_style
->outlineWidth() > style
->outlineWidth() ||
2003 (!m_style
->hidesOverflow() && style
->hidesOverflow()) ||
2004 ( m_style
->hasClip() && !(m_style
->clip() == style
->clip()) ) ) ) {
2005 // schedule a repaint with the old style
2006 if (layer() && !isInlineFlow())
2007 layer()->repaint(pri
);
2012 if ( ( isFloating() && m_style
->floating() != style
->floating() ) ||
2013 ( isPositioned() && m_style
->position() != style
->position() &&
2014 style
->position() != PABSOLUTE
&& style
->position() != PFIXED
) )
2015 removeFromObjectLists();
2018 if ( ( m_style
->hasAutoZIndex() != style
->hasAutoZIndex() ||
2019 m_style
->zIndex() != style
->zIndex() ||
2020 m_style
->visibility() != style
->visibility() ) ) {
2021 layer()->stackingContext()->dirtyZOrderLists();
2022 layer()->dirtyZOrderLists();
2024 // keep layer hierarchy visibility bits up to date if visibility changes
2025 if (m_style
->visibility() != style
->visibility()) {
2026 RenderLayer
* l
= enclosingLayer();
2027 if (style
->visibility() == VISIBLE
&& l
)
2028 l
->setHasVisibleContent(true);
2029 else if (l
&& l
->hasVisibleContent() &&
2030 (this == l
->renderer() || l
->renderer()->style()->visibility() != VISIBLE
))
2031 l
->dirtyVisibleContentStatus();
2035 // reset style flags
2037 m_positioned
= false;
2038 m_relPositioned
= false;
2039 m_paintBackground
= false;
2040 m_hasOverflowClip
= false;
2043 // only honor z-index for non-static objects and objects with opacity
2044 if ( style
->position() == PSTATIC
&& style
->opacity() == 1.0f
) {
2045 style
->setHasAutoZIndex();
2047 // force establishment of a stacking context by transparent objects, as those define
2048 // the bounds of an atomically painted region.
2049 if (style
->hasAutoZIndex() && (isRoot() || style
->opacity() < 1.0f
))
2050 style
->setZIndex( 0 );
2052 if ( d
> RenderStyle::Position
&&
2053 (style
->hasFixedBackgroundImage() != (m_style
&& m_style
->hasFixedBackgroundImage())
2054 || (style
->position() == PFIXED
) != (m_style
&& (m_style
->position() == PFIXED
)))
2055 && canvas() && canvas()->view() ) {
2056 // some sort of fixed object is added or removed. Let's find out more and report to the canvas,
2057 // so that it does some bookkeeping and optimizes the view's background display mode accordingly.
2058 bool fixedBG
= style
->hasFixedBackgroundImage();
2059 bool oldFixedBG
= m_style
&& m_style
->hasFixedBackgroundImage();
2060 bool fixedPos
= (style
->position() == PFIXED
);
2061 bool oldFixedPos
= m_style
&& (m_style
->position() == PFIXED
);
2062 if (fixedBG
!= oldFixedBG
) {
2064 canvas()->addStaticObject(this);
2066 canvas()->removeStaticObject(this);
2069 if (fixedPos
!= oldFixedPos
) {
2071 canvas()->addStaticObject( this, true /*positioned*/ );
2073 canvas()->removeStaticObject( this, true );
2077 RenderStyle
*oldStyle
= m_style
;
2080 updateBackgroundImages(oldStyle
);
2087 setShouldPaintBackgroundOrBorder(m_style
->hasBorder() || m_style
->hasBackground());
2089 m_hasFirstLine
= (style
->getPseudoStyle(RenderStyle::FIRST_LINE
) != 0);
2091 if (d
== RenderStyle::Position
&& !attemptDirectLayerTranslation())
2092 d
= RenderStyle::Layout
;
2094 if ( d
> RenderStyle::Position
) {
2095 // we must perform a full layout
2096 if (!isText() && d
== RenderStyle::CbLayout
) {
2097 dirtyFormattingContext( true );
2099 setNeedsLayoutAndMinMaxRecalc();
2100 } else if (!isText() && d
>= RenderStyle::Visible
) {
2101 // a repaint is enough
2103 if (canvas() && canvas()->needsWidgetMasks()) {
2104 // update our widget masks
2105 RenderLayer
*p
, *d
= 0;
2106 for (p
=layer()->parent();p
;p
=p
->parent())
2107 if (p
->hasOverlaidWidgets()) d
=p
;
2109 d
->updateWidgetMasks( canvas()->layer() );
2112 if (layer() && !isInlineFlow())
2113 layer()->repaint(pri
);
2120 bool RenderObject::attemptDirectLayerTranslation()
2122 // When the difference between two successive styles is only 'Position'
2123 // we may attempt to save a layout by directly updating the object position.
2125 KHTMLAssert( m_style
->position() != PSTATIC
);
2128 setInline(m_style
->isDisplayInlineType());
2129 setPositioned(m_style
->position() != PRELATIVE
);
2130 setRelPositioned(m_style
->position() == PRELATIVE
);
2131 int oldXPos
= xPos();
2132 int oldYPos
= yPos();
2133 int oldWidth
= width();
2134 int oldHeight
= height();
2137 if (oldWidth
!= width() || oldHeight
!= height()) {
2138 // implicit size change or overconstrained dimensions:
2139 // we'll need a layout.
2141 setHeight(oldHeight
);
2142 // kDebug() << "Layer translation failed for " << information();
2145 layer()->updateLayerPosition();
2146 if (m_style
->position() != PFIXED
) {
2147 bool needsDocSizeUpdate
= true;
2148 RenderObject
*cb
= container();
2150 if (cb
->hasOverflowClip() && cb
->layer()) {
2151 cb
->layer()->checkScrollbarsAfterLayout();
2152 needsDocSizeUpdate
= false;
2155 cb
= cb
->container();
2157 if (needsDocSizeUpdate
&& canvas()) {
2158 bool posXOffset
= (xPos()-oldXPos
>= 0);
2159 bool posYOffset
= (yPos()-oldYPos
>= 0);
2160 canvas()->updateDocSizeAfterLayerTranslation(this, posXOffset
, posYOffset
);
2167 void RenderObject::dirtyFormattingContext( bool checkContainer
)
2169 if (m_markedForRepaint
&& !checkContainer
)
2171 m_markedForRepaint
= true;
2172 if (layer() && (style()->position() == PFIXED
|| style()->position() == PABSOLUTE
))
2174 if (m_parent
&& (checkContainer
|| style()->width().isVariable() || style()->height().isVariable() ||
2175 !(isFloating() || flowAroundFloats() || isTableCell())))
2176 m_parent
->dirtyFormattingContext(false);
2179 void RenderObject::repaintDuringLayout()
2181 if (canvas()->needsFullRepaint() || isText())
2183 if (layer() && !isInlineFlow()) {
2184 layer()->repaint( NormalPriority
, true );
2187 canvas()->deferredRepaint( this );
2191 void RenderObject::updateBackgroundImages(RenderStyle
* oldStyle
)
2193 // FIXME: This will be slow when a large number of images is used. Fix by using a dict.
2194 const BackgroundLayer
* oldLayers
= oldStyle
? oldStyle
->backgroundLayers() : 0;
2195 const BackgroundLayer
* newLayers
= m_style
? m_style
->backgroundLayers() : 0;
2196 for (const BackgroundLayer
* currOld
= oldLayers
; currOld
; currOld
= currOld
->next()) {
2197 if (currOld
->backgroundImage() && (!newLayers
|| !newLayers
->containsImage(currOld
->backgroundImage())))
2198 currOld
->backgroundImage()->deref(this);
2200 for (const BackgroundLayer
* currNew
= newLayers
; currNew
; currNew
= currNew
->next()) {
2201 if (currNew
->backgroundImage() && (!oldLayers
|| !oldLayers
->containsImage(currNew
->backgroundImage())))
2202 currNew
->backgroundImage()->ref(this);
2206 QRect
RenderObject::viewRect() const
2208 return containingBlock()->viewRect();
2211 bool RenderObject::absolutePosition(int &xPos
, int &yPos
, bool f
) const
2213 RenderObject
* p
= parent();
2215 p
->absolutePosition(xPos
, yPos
, f
);
2216 if ( p
->hasOverflowClip() )
2217 p
->layer()->subtractScrollOffset( xPos
, yPos
);
2227 void RenderObject::caretPos(int /*offset*/, int /*flags*/, int &_x
, int &_y
, int &width
, int &height
) const
2229 _x
= _y
= height
= -1;
2230 width
= 1; // the caret has a default width of one pixel. If you want
2231 // to check for validity, only test the x-coordinate for >= 0.
2234 int RenderObject::paddingTop() const
2237 Length padding
= m_style
->paddingTop();
2238 if (padding
.isPercent())
2239 w
= containingBlock()->contentWidth();
2240 w
= padding
.minWidth(w
);
2241 if ( isTableCell() && padding
.isVariable() )
2242 w
= static_cast<const RenderTableCell
*>(this)->table()->cellPadding();
2246 int RenderObject::paddingBottom() const
2249 Length padding
= style()->paddingBottom();
2250 if (padding
.isPercent())
2251 w
= containingBlock()->contentWidth();
2252 w
= padding
.minWidth(w
);
2253 if ( isTableCell() && padding
.isVariable() )
2254 w
= static_cast<const RenderTableCell
*>(this)->table()->cellPadding();
2258 int RenderObject::paddingLeft() const
2261 Length padding
= style()->paddingLeft();
2262 if (padding
.isPercent())
2263 w
= containingBlock()->contentWidth();
2264 w
= padding
.minWidth(w
);
2265 if ( isTableCell() && padding
.isVariable() )
2266 w
= static_cast<const RenderTableCell
*>(this)->table()->cellPadding();
2270 int RenderObject::paddingRight() const
2273 Length padding
= style()->paddingRight();
2274 if (padding
.isPercent())
2275 w
= containingBlock()->contentWidth();
2276 w
= padding
.minWidth(w
);
2277 if ( isTableCell() && padding
.isVariable() )
2278 w
= static_cast<const RenderTableCell
*>(this)->table()->cellPadding();
2282 RenderObject
*RenderObject::container() const
2284 // This method is extremely similar to containingBlock(), but with a few notable
2286 // (1) It can be used on orphaned subtrees, i.e., it can be called safely even when
2287 // the object is not part of the primary document subtree yet.
2288 // (2) For normal flow elements, it just returns the parent.
2289 // (3) For absolute positioned elements, it will return a relative positioned inline.
2290 // containingBlock() simply skips relpositioned inlines and lets an enclosing block handle
2291 // the layout of the positioned object. This does mean that calcAbsoluteHorizontal and
2292 // calcAbsoluteVertical have to use container().
2293 EPosition pos
= m_style
->position();
2294 RenderObject
*o
= 0;
2295 if( pos
== PFIXED
) {
2296 // container() can be called on an object that is not in the
2297 // tree yet. We don't call canvas() since it will assert if it
2298 // can't get back to the canvas. Instead we just walk as high up
2299 // as we can. If we're in the tree, we'll get the root. If we
2300 // aren't we'll get the root of our little subtree (most likely
2301 // we'll just return 0).
2303 while ( o
&& o
->parent() ) o
= o
->parent();
2305 else if ( pos
== PABSOLUTE
) {
2306 // Same goes here. We technically just want our containing block, but
2307 // we may not have one if we're part of an uninstalled subtree. We'll
2308 // climb as high as we can though.
2310 while (o
&& o
->style()->position() == PSTATIC
&& !o
->isCanvas())
2318 DOM::DocumentImpl
* RenderObject::document() const
2320 return m_node
->document();
2323 void RenderObject::removeFromObjectLists()
2325 // in destruction mode, don't care.
2326 if ( documentBeingDestroyed() ) return;
2329 RenderBlock
* outermostBlock
= containingBlock();
2330 for (RenderBlock
* p
= outermostBlock
; p
&& !p
->isCanvas() && p
->containsFloat(this);) {
2332 if (p
->isFloatingOrPositioned())
2334 p
= p
->containingBlock();
2338 outermostBlock
->markAllDescendantsWithFloatsForLayout(this);
2341 if (isPositioned()) {
2343 for (p
= parent(); p
; p
= p
->parent()) {
2344 if (p
->isRenderBlock())
2345 static_cast<RenderBlock
*>(p
)->removePositionedObject(this);
2350 RenderArena
* RenderObject::renderArena() const
2352 return m_node
->document()->renderArena();
2355 void RenderObject::detach()
2360 // make sure our DOM-node don't think we exist
2361 if ( node() && node()->renderer() == this)
2362 node()->setRenderer(0);
2364 // by default no refcounting
2365 arenaDelete(renderArena(), this);
2368 void RenderObject::arenaDelete(RenderArena
*arena
, void *base
)
2371 void *savedBase
= baseOfRenderObjectBeingDeleted
;
2372 baseOfRenderObjectBeingDeleted
= base
;
2376 baseOfRenderObjectBeingDeleted
= savedBase
;
2379 // Recover the size left there for us by operator delete and free the memory.
2380 arena
->free(*(size_t *)base
, base
);
2383 void RenderObject::arenaDelete(RenderArena
*arena
)
2385 // static_cast unfortunately doesn't work, since we multiple inherit
2386 // in eg. RenderWidget.
2387 arenaDelete(arena
, dynamic_cast<void *>(this));
2390 Position
RenderObject::positionForCoordinates(int /*x*/, int /*y*/)
2392 return Position(element(), caretMinOffset());
2395 bool RenderObject::isPointInsideSelection(int x
, int y
, const Selection
&sel
) const
2397 SelectionState selstate
= selectionState();
2398 if (selstate
== SelectionInside
) return true;
2399 if (selstate
== SelectionNone
|| !element()) return false;
2400 return element()->isPointInsideSelection(x
, y
, sel
);
2404 FindSelectionResult
RenderObject::checkSelectionPoint( int _x
, int _y
, int _tx
, int _ty
, DOM::NodeImpl
*& node
, int & offset
, SelPointState
&state
)
2407 NodeInfo
info(true, false);
2408 if ( nodeAtPoint( info
, _x
, _y
, _tx
, _ty
) && info
.innerNode() )
2410 RenderObject
* r
= info
.innerNode()->renderer();
2413 node
= info
.innerNode();
2414 offset
= 0; // we have no text...
2415 return SelectionPointInside
;
2418 return r
->checkSelectionPoint( _x
, _y
, _tx
, _ty
, node
, offset
, state
);
2421 //kDebug(6030) << "nodeAtPoint Failed. Fallback - hmm, SelectionPointAfter";
2424 return SelectionPointAfter
;
2427 DOM::NodeImpl
* nod
= node
;
2429 for (RenderObject
*child
= firstChild(); child
; child
=child
->nextSibling()) {
2430 // ignore empty text boxes, they produce totally bogus information
2431 // for caret navigation (LS)
2432 if (child
->isText() && !static_cast<RenderText
*>(child
)->firstTextBox())
2435 // kDebug(6040) << "iterating " << (child ? child->renderName() : "") << "@" << child << (child->isText() ? " contains: \"" + QString::fromRawData(static_cast<RenderText *>(child)->text(), qMin(static_cast<RenderText *>(child)->length(), 10u)) + "\"" : QString());
2436 // kDebug(6040) << "---------- checkSelectionPoint recursive -----------";
2437 khtml::FindSelectionResult pos
= child
->checkSelectionPoint(_x
, _y
, _tx
+xPos(), _ty
+yPos(), nod
, off
, state
);
2438 // kDebug(6040) << "-------- end checkSelectionPoint recursive ---------";
2439 // kDebug(6030) << this << " child->findSelectionNode returned result=" << pos << " nod=" << nod << " off=" << off;
2441 case SelectionPointBeforeInLine
:
2442 case SelectionPointInside
:
2443 //kDebug(6030) << "RenderObject::checkSelectionPoint " << this << " returning SelectionPointInside offset=" << offset;
2446 return SelectionPointInside
;
2447 case SelectionPointBefore
:
2448 //x,y is before this element -> stop here
2449 if ( state
.m_lastNode
) {
2450 node
= state
.m_lastNode
;
2451 offset
= state
.m_lastOffset
;
2452 //kDebug(6030) << "RenderObject::checkSelectionPoint " << this << " before this child "
2453 // << node << "-> returning SelectionPointInside, offset=" << offset << endl;
2454 return SelectionPointInside
;
2458 //kDebug(6030) << "RenderObject::checkSelectionPoint " << this << " before us -> returning SelectionPointBefore " << node << "/" << offset;
2459 return SelectionPointBefore
;
2462 case SelectionPointAfter
:
2463 if (state
.m_afterInLine
) break;
2465 case SelectionPointAfterInLine
:
2466 if (pos
== SelectionPointAfterInLine
) state
.m_afterInLine
= true;
2467 //kDebug(6030) << "RenderObject::checkSelectionPoint: selection after: " << nod << " offset: " << off << " afterInLine: " << state.m_afterInLine;
2468 state
.m_lastNode
= nod
;
2469 state
.m_lastOffset
= off
;
2470 // No "return" here, obviously. We must keep looking into the children.
2474 // If we are after the last child, return lastNode/lastOffset
2475 // But lastNode can be 0L if there is no child, for instance.
2476 if ( state
.m_lastNode
)
2478 node
= state
.m_lastNode
;
2479 offset
= state
.m_lastOffset
;
2481 //kDebug(6030) << "fallback - SelectionPointAfter node=" << node << " offset=" << offset;
2482 return SelectionPointAfter
;
2486 bool RenderObject::mouseInside() const
2488 if (!m_mouseInside
&& continuation())
2489 return continuation()->mouseInside();
2490 return m_mouseInside
;
2493 bool RenderObject::nodeAtPoint(NodeInfo
& info
, int _x
, int _y
, int _tx
, int _ty
, HitTestAction hitTestAction
, bool inside
)
2495 int tx
= _tx
+ xPos();
2496 int ty
= _ty
+ yPos();
2498 inside
|= ( style()->visibility() != HIDDEN
&&
2499 (_y
>= ty
) && (_y
< ty
+ height()) && (_x
>= tx
) && (_x
< tx
+ width())) || isRoot() || isBody();
2500 bool inOverflowRect
= inside
;
2501 if ( !inOverflowRect
) {
2502 int ol
= overflowLeft();
2503 int ot
= overflowTop();
2504 QRect
overflowRect( tx
+ol
, ty
+ot
, overflowWidth()-ol
, overflowHeight()-ot
);
2505 inOverflowRect
= overflowRect
.contains( _x
, _y
);
2508 // ### table should have its own, more performant method
2509 if (hitTestAction
!= HitTestSelfOnly
&&
2510 (( !isRenderBlock() ||
2511 !static_cast<RenderBlock
*>( this )->isPointInScrollbar( _x
, _y
, _tx
, _ty
)) &&
2512 (inOverflowRect
|| isInline() || isRoot() || isCanvas() ||
2513 isTableRow() || isTableSection() || inside
|| mouseInside() ))) {
2514 if ( hitTestAction
== HitTestChildrenOnly
)
2516 if ( hasOverflowClip() && layer() )
2517 layer()->subtractScrollOffset(tx
, ty
);
2518 for (RenderObject
* child
= lastChild(); child
; child
= child
->previousSibling())
2519 if (!child
->layer() && child
->nodeAtPoint(info
, _x
, _y
, tx
, ty
, HitTestAll
))
2530 void RenderObject::setInnerNode(NodeInfo
& info
)
2532 if (!info
.innerNode() && !isInline() && continuation()) {
2533 // We are in the margins of block elements that are part of a continuation. In
2534 // this case we're actually still inside the enclosing inline element that was
2535 // split. Go ahead and set our inner node accordingly.
2536 info
.setInnerNode(continuation()->element());
2537 if (!info
.innerNonSharedNode())
2538 info
.setInnerNonSharedNode(continuation()->element());
2541 if (!info
.innerNode() && element())
2542 info
.setInnerNode(element());
2544 if(!info
.innerNonSharedNode() && element())
2545 info
.setInnerNonSharedNode(element());
2549 short RenderObject::verticalPositionHint( bool firstLine
) const
2551 short vpos
= m_verticalPosition
;
2552 if ( m_verticalPosition
== PositionUndefined
|| firstLine
) {
2553 vpos
= getVerticalPosition( firstLine
);
2555 const_cast<RenderObject
*>(this)->m_verticalPosition
= vpos
;
2561 short RenderObject::getVerticalPosition( bool firstLine
, RenderObject
* ref
) const
2563 // vertical align for table cells has a different meaning
2565 if ( !isTableCell() && isInline() ) {
2566 EVerticalAlign va
= style()->verticalAlign();
2569 } else if ( va
== BOTTOM
) {
2570 vpos
= PositionBottom
;
2572 if (!ref
) ref
= parent();
2573 bool checkParent
= ref
->isInline() && !ref
->isReplacedBlock() &&
2574 !( ref
->style()->verticalAlign() == TOP
|| ref
->style()->verticalAlign() == BOTTOM
);
2575 vpos
= checkParent
? ref
->verticalPositionHint( firstLine
) : 0;
2576 // don't allow elements nested inside text-top to have a different valignment.
2577 if ( va
== BASELINE
)
2579 else if ( va
== LENGTH
)
2580 return vpos
- style()->verticalAlignLength().width( lineHeight( firstLine
) );
2582 const QFont
&f
= ref
->font( firstLine
);
2583 int fontsize
= f
.pixelSize();
2586 vpos
+= fontsize
/5 + 1;
2587 else if ( va
== SUPER
)
2588 vpos
-= fontsize
/3 + 1;
2589 else if ( va
== TEXT_TOP
) {
2590 vpos
+= baselinePosition( firstLine
) - (QFontMetrics(f
).ascent() + QFontMetrics(f
).leading()/2);
2591 } else if ( va
== MIDDLE
) {
2592 QRect b
= QFontMetrics(f
).boundingRect('x');
2593 vpos
+= -b
.height()/2 - lineHeight( firstLine
)/2 + baselinePosition( firstLine
);
2594 } else if ( va
== TEXT_BOTTOM
) {
2595 vpos
+= QFontMetrics(f
).descent() + QFontMetrics(f
).leading()/2;
2596 if ( !isReplaced() )
2597 vpos
-= fontMetrics(firstLine
).descent();
2598 } else if ( va
== BASELINE_MIDDLE
)
2599 vpos
+= - lineHeight( firstLine
)/2 + baselinePosition( firstLine
);
2605 short RenderObject::lineHeight( bool firstLine
) const
2607 // Inline blocks are replaced elements. Otherwise, just pass off to
2608 // the base class. If we're being queried as though we're the root line
2609 // box, then the fact that we're an inline-block is irrelevant, and we behave
2610 // just like a block.
2612 if (isReplaced() && (!isInlineBlockOrInlineTable() || !needsLayout()))
2613 return height()+marginTop()+marginBottom();
2616 if( firstLine
&& hasFirstLine() ) {
2617 RenderStyle
*pseudoStyle
= style()->getPseudoStyle(RenderStyle::FIRST_LINE
);
2619 lh
= pseudoStyle
->lineHeight();
2622 lh
= style()->lineHeight();
2624 // its "unset", choose nice default
2625 if ( lh
.value() < 0 )
2626 return style()->fontMetrics().lineSpacing();
2628 if ( lh
.isPercent() )
2629 return lh
.minWidth( style()->font().pixelSize() );
2635 short RenderObject::baselinePosition( bool firstLine
) const
2637 // If we're an inline-block and need layout, it means our replaced boundaries
2638 // are not yet fully established, so we behave just like a block.
2639 if (isReplaced() && (!isInlineBlockOrInlineTable() || !needsLayout()))
2640 return height()+marginTop()+marginBottom();
2642 const QFontMetrics
&fm
= fontMetrics( firstLine
);
2643 return fm
.ascent() + ( lineHeight( firstLine
) - fm
.height() ) / 2;
2646 void RenderObject::invalidateVerticalPosition()
2648 m_verticalPosition
= PositionUndefined
;
2651 void RenderObject::recalcMinMaxWidths()
2653 KHTMLAssert( m_recalcMinMax
);
2656 kDebug( 6040 ) << renderName() << " recalcMinMaxWidths() this=" << this;
2659 RenderObject
*child
= firstChild();
2665 if ( ( m_minMaxKnown
&& child
->m_recalcMinMax
) || !child
->m_minMaxKnown
) {
2666 cmin
= child
->minWidth();
2667 cmax
= child
->maxWidth();
2670 if ( child
->m_recalcMinMax
)
2671 child
->recalcMinMaxWidths();
2672 if ( !child
->m_minMaxKnown
)
2673 child
->calcMinMaxWidth();
2674 if ( m_minMaxKnown
&& test
&& (cmin
!= child
->minWidth() || cmax
!= child
->maxWidth()) )
2675 m_minMaxKnown
= false;
2676 child
= child
->nextSibling();
2679 // we need to recalculate, if the contains inline children, as the change could have
2680 // happened somewhere deep inside the child tree
2681 if ( ( !isInline() || isReplacedBlock() ) && childrenInline() )
2682 m_minMaxKnown
= false;
2684 if ( !m_minMaxKnown
)
2686 m_recalcMinMax
= false;
2689 void RenderObject::scheduleRelayout(RenderObject
*clippedObj
)
2691 if (!isCanvas()) return;
2692 KHTMLView
*view
= static_cast<RenderCanvas
*>(this)->view();
2694 view
->scheduleRelayout(clippedObj
);
2697 InlineBox
* RenderObject::createInlineBox(bool /*makePlaceHolderBox*/, bool /*isRootLineBox*/)
2703 void RenderObject::getTextDecorationColors(int decorations
, QColor
& underline
, QColor
& overline
,
2704 QColor
& linethrough
, bool quirksMode
)
2706 RenderObject
* curr
= this;
2708 RenderStyle
*st
= curr
->style();
2709 int currDecs
= st
->textDecoration();
2711 if (currDecs
& UNDERLINE
) {
2712 decorations
&= ~UNDERLINE
;
2713 underline
= st
->color();
2715 if (currDecs
& OVERLINE
) {
2716 decorations
&= ~OVERLINE
;
2717 overline
= st
->color();
2719 if (currDecs
& LINE_THROUGH
) {
2720 decorations
&= ~LINE_THROUGH
;
2721 linethrough
= st
->color();
2724 curr
= curr
->parent();
2725 if (curr
&& curr
->isRenderBlock() && curr
->continuation())
2726 curr
= curr
->continuation();
2727 } while (curr
&& decorations
&& (!quirksMode
|| !curr
->element() ||
2728 (curr
->element()->id() != ID_A
&& curr
->element()->id() != ID_FONT
)));
2730 // If we bailed out, use the element we bailed out at (typically a <font> or <a> element).
2731 if (decorations
&& curr
) {
2732 RenderStyle
*st
= curr
->style();
2733 if (decorations
& UNDERLINE
)
2734 underline
= st
->color();
2735 if (decorations
& OVERLINE
)
2736 overline
= st
->color();
2737 if (decorations
& LINE_THROUGH
)
2738 linethrough
= st
->color();
2742 int RenderObject::maximalOutlineSize(PaintAction p
) const
2744 if (p
!= PaintActionOutline
)
2746 return static_cast<RenderCanvas
*>(document()->renderer())->maximalOutlineSize();
2749 void RenderObject::collectBorders(QList
<CollapsedBorderValue
>& borderStyles
)
2751 for (RenderObject
* curr
= firstChild(); curr
; curr
= curr
->nextSibling())
2752 curr
->collectBorders(borderStyles
);
2755 bool RenderObject::flowAroundFloats() const
2757 return isReplaced() || hasOverflowClip() || style()->flowAroundFloats();
2760 bool RenderObject::usesLineWidth() const
2762 // 1. All auto-width objects that avoid floats should always use lineWidth
2763 // 2. For objects with a specified width, we match WinIE's behavior:
2764 // (a) tables use contentWidth
2765 // (b) <hr>s use lineWidth
2766 // (c) all other objects use lineWidth in quirks mode and contentWidth in strict mode.
2767 return (flowAroundFloats() && (style()->width().isVariable() || isHR() || (style()->htmlHacks() && !isTable())));
2770 long RenderObject::caretMinOffset() const
2775 long RenderObject::caretMaxOffset() const
2780 unsigned long RenderObject::caretMaxRenderedOffset() const
2785 InlineBox
*RenderObject::inlineBox(long /*offset*/)
2788 return static_cast<RenderBox
*>(this)->placeHolderBox();
2792 bool RenderObject::hasCounter(const QString
& counter
) const
2794 if (style() && (!isText() || isCounter())) {
2795 if (lookupCounter(counter
)) return true;
2796 if (style()->hasCounterReset(counter
)) {
2799 else if (style()->hasCounterIncrement(counter
)) {
2803 if (counter
== "list-item") {
2804 if (isListItem()) return true;
2806 element()->id() == ID_OL
||
2807 element()->id() == ID_UL
||
2808 element()->id() == ID_MENU
||
2809 element()->id() == ID_DIR
))
2812 if (counter
== "-khtml-quotes" && isQuote()) {
2813 return (static_cast<const RenderQuote
*>(this)->quoteCount() != 0);
2818 CounterNode
* RenderObject::getCounter(const QString
& counter
, bool view
, bool counters
)
2820 // kDebug( 6040 ) << renderName() << " getCounter(" << counter << ")";
2822 if (!style()) return 0;
2824 if (isText() && !isCounter()) return 0;
2826 CounterNode
*i
= lookupCounter(counter
);
2830 if (style()->hasCounterReset(counter
) || isRoot()) {
2831 i
= new CounterReset(this);
2832 val
= style()->counterReset(counter
);
2833 if (style()->hasCounterIncrement(counter
)) {
2834 val
+= style()->counterIncrement(counter
);
2836 // kDebug( 6040 ) << renderName() << " counter-reset: " << counter << " " << val;
2839 if (style()->hasCounterIncrement(counter
)) {
2840 i
= new CounterNode(this);
2841 val
= style()->counterIncrement(counter
);
2842 // kDebug( 6040 ) << renderName() << " counter-increment: " << counter << " " << val;
2844 else if (counter
== "list-item") {
2846 if (element() && element()->id() == ID_LI
) {
2847 DOMString v
= static_cast<ElementImpl
*>(element())->getAttribute(ATTR_VALUE
);
2848 if ( !v
.isEmpty() ) {
2849 i
= new CounterReset(this);
2851 // kDebug( 6040 ) << renderName() << " counter-reset: " << counter << " " << val;
2855 i
= new CounterNode(this);
2857 // kDebug( 6040 ) << renderName() << " counter-increment: " << counter << " " << val;
2861 if (element() && element()->id() == ID_OL
) {
2862 i
= new CounterReset(this);
2863 DOMString v
= static_cast<ElementImpl
*>(element())->getAttribute(ATTR_START
);
2868 // kDebug( 6040 ) << renderName() << " counter-reset: " << counter << " " << val;
2872 (element()->id() == ID_UL
||
2873 element()->id() == ID_MENU
||
2874 element()->id() == ID_DIR
))
2876 i
= new CounterReset(this);
2878 // kDebug( 6040 ) << renderName() << " counter-reset: " << counter << " " << val;
2881 else if (counter
== "-khtml-quotes" && isQuote()) {
2882 i
= new CounterNode(this);
2883 val
= static_cast<RenderQuote
*>(this)->quoteCount();
2887 i
= new CounterNode(this);
2889 // kDebug( 6040 ) << renderName() << " counter-increment: " << counter << " " << val;
2892 if (view
) i
->setIsVisual();
2893 if (counters
) i
->setHasCounters();
2895 insertCounter(counter
, i
);
2898 CounterNode
*last
=0, *current
=0;
2899 RenderObject
*n
= previousSibling();
2901 if (n
->hasCounter(counter
)) {
2902 current
= n
->getCounter(counter
);
2906 n
= n
->previousSibling();
2910 CounterNode
*sibling
= current
;
2911 // counter-reset on same render-level is our counter-parent
2913 // Found render-sibling, now search for later counter-siblings among its render-children
2916 if (n
->hasCounter(counter
)) {
2917 current
= n
->getCounter(counter
);
2918 if (last
->parent() == current
->parent() || sibling
== current
->parent()) {
2920 // If the current counter is not the last, search deeper
2921 if (current
->nextSibling()) {
2929 n
= n
->previousSibling();
2931 if (sibling
->isReset())
2933 if (last
!= sibling
)
2934 sibling
->insertAfter(i
, last
);
2936 sibling
->insertAfter(i
, 0);
2938 else if (last
->parent())
2939 last
->parent()->insertAfter(i
, last
);
2941 else if (parent()) {
2942 // Nothing found among siblings, let our parent search
2943 last
= parent()->getCounter(counter
, false);
2944 if (last
->isReset())
2945 last
->insertAfter(i
, 0);
2946 else if (last
->parent())
2947 last
->parent()->insertAfter(i
, last
);
2954 CounterNode
* RenderObject::lookupCounter(const QString
& counter
) const
2956 QHash
<QString
,khtml::CounterNode
*>* counters
= document()->counters(this);
2957 return counters
? counters
->value(counter
) : 0;
2960 void RenderObject::detachCounters()
2962 QHash
<QString
,khtml::CounterNode
*>* counters
= document()->counters(this);
2963 if (!counters
) return;
2965 QHashIterator
<QString
,khtml::CounterNode
*> i(*counters
);
2967 while (i
.hasNext()) {
2969 i
.value()->remove();
2972 document()->removeCounters(this);
2975 void RenderObject::insertCounter(const QString
& counter
, CounterNode
* val
)
2977 QHash
<QString
,khtml::CounterNode
*>* counters
= document()->counters(this);
2980 counters
= new QHash
<QString
,khtml::CounterNode
*>();
2981 document()->setCounters(this, counters
);
2984 counters
->insert(counter
, val
);
2987 void RenderObject::updateWidgetMasks() {
2988 for (RenderObject
* curr
= firstChild(); curr
; curr
= curr
->nextSibling()) {
2989 if ( curr
->isWidget() && static_cast<RenderWidget
*>(curr
)->needsMask() ) {
2990 QWidget
* w
= static_cast<RenderWidget
*>(curr
)->widget();
2993 RenderLayer
* l
= curr
->enclosingStackingContext();
2994 QRegion r
= l
? l
->getMask() : QRegion();
2996 if (!r
.isEmpty() && curr
->absolutePosition(x
,y
)) {
2997 int pbx
= curr
->borderLeft()+curr
->paddingLeft();
2998 int pby
= curr
->borderTop()+curr
->paddingTop();
3001 r
= r
.intersect(QRect(x
,y
,
3002 curr
->width()-pbx
-curr
->borderRight()-curr
->paddingRight(),
3003 curr
->height()-pby
-curr
->borderBottom()-curr
->paddingBottom()));
3005 QVector
<QRect
> ar
= r
.rects();
3006 kDebug(6040) << "|| Setting widget mask for " << curr
->information();
3007 for (int i
= 0; i
< ar
.size() ; ++i
) {
3008 kDebug(6040) << " " << ar
[i
];
3013 // ### Scrollarea's widget doesn't update when mask change.
3014 // Might be a Qt bug. Might be the way we handle updates. Investigate.
3015 if (::qobject_cast
<QScrollArea
*>(w
)) {
3016 QScrollArea
* sa
= static_cast<QScrollArea
*>(w
);
3017 if (!w
->mask().isEmpty()) {
3018 QPoint
off( sa
->horizontalScrollBar()->value(),
3019 sa
->verticalScrollBar()->value() );
3020 sa
->widget()->update(w
->mask().translated(off
));
3021 sa
->horizontalScrollBar()->update();
3022 sa
->verticalScrollBar()->update();
3030 else if (!curr
->layer() || !curr
->layer()->isStackingContext())
3031 curr
->updateWidgetMasks();
3036 QRegion
RenderObject::visibleFlowRegion(int x
, int y
) const
3039 bool returnSelf
= false;
3040 for (RenderObject
* ro
=firstChild();ro
;ro
=ro
->nextSibling()) {
3041 if( !ro
->layer() && !ro
->isFloating() && ro
->style()->visibility() == VISIBLE
) {
3042 // ### fix horizontal float extent
3043 const RenderStyle
*s
= ro
->style();
3044 int ow
= s
->outlineSize();
3045 if (ro
->isInlineFlow() || ro
->isText()) {
3049 if ( s
->backgroundImage() || s
->backgroundColor().isValid() || s
->hasBorder() || ro
->isReplaced() ) {
3050 r
+= QRect(x
-ow
+ro
->effectiveXPos(),y
-ow
+ ro
->effectiveYPos(),
3051 ro
->effectiveWidth()+ow
*2, ro
->effectiveHeight()+ow
*2);
3053 r
+= ro
->visibleFlowRegion(x
+ro
->xPos(), y
+ro
->yPos());
3058 int ow
= style()->outlineSize();
3059 r
+= QRect(x
-xPos()-ow
+effectiveXPos(),y
-yPos()-ow
+ effectiveYPos(),
3060 effectiveWidth()+ow
*2, effectiveHeight()+ow
*2);
3066 FloatRect
RenderObject::relativeBBox(bool includeStroke
) const
3071 AffineTransform
RenderObject::localTransform() const
3073 return AffineTransform(1, 0, 0, 1, xPos(), yPos());
3076 AffineTransform
RenderObject::absoluteTransform() const
3079 return localTransform() * parent()->absoluteTransform();
3080 return localTransform();
3084 #undef RED_LUMINOSITY
3085 #undef GREEN_LUMINOSITY
3086 #undef BLUE_LUMINOSITY
3087 #undef INTENSITY_FACTOR
3089 #undef LUMINOSITY_FACTOR
3092 #undef COLOR_DARK_THRESHOLD
3093 #undef COLOR_LIGHT_THRESHOLD
3095 #undef COLOR_LITE_BS_FACTOR
3096 #undef COLOR_LITE_TS_FACTOR
3098 #undef COLOR_DARK_BS_FACTOR
3099 #undef COLOR_DARK_TS_FACTOR