• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
3  *           (C) 1999 Antti Koivisto (koivisto@kde.org)
4  *           (C) 2000 Dirk Mueller (mueller@kde.org)
5  *           (C) 2004 Allan Sandfeld Jensen (kde@carewolf.com)
6  * Copyright (C) 2004, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved.
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Library General Public
10  * License as published by the Free Software Foundation; either
11  * version 2 of the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * Library General Public License for more details.
17  *
18  * You should have received a copy of the GNU Library General Public License
19  * along with this library; see the file COPYING.LIB.  If not, write to
20  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
21  * Boston, MA 02110-1301, USA.
22  *
23  */
24 
25 #include "config.h"
26 #include "RenderObject.h"
27 
28 #include "AXObjectCache.h"
29 #include "CSSStyleSelector.h"
30 #include "FloatQuad.h"
31 #include "FrameView.h"
32 #include "GraphicsContext.h"
33 #include "HTMLNames.h"
34 #include "HitTestResult.h"
35 #include "Page.h"
36 #include "RenderArena.h"
37 #include "RenderCounter.h"
38 #include "RenderFlexibleBox.h"
39 #include "RenderImageGeneratedContent.h"
40 #include "RenderInline.h"
41 #include "RenderListItem.h"
42 #include "RenderTableCell.h"
43 #include "RenderTableCol.h"
44 #include "RenderTableRow.h"
45 #include "RenderTheme.h"
46 #include "RenderView.h"
47 #include <algorithm>
48 #ifdef ANDROID_LAYOUT
49 #include "Settings.h"
50 #endif
51 #include <stdio.h>
52 #include <wtf/RefCountedLeakCounter.h>
53 
54 #if ENABLE(WML)
55 #include "WMLNames.h"
56 #endif
57 
58 using namespace std;
59 
60 namespace WebCore {
61 
62 using namespace HTMLNames;
63 
64 #ifndef NDEBUG
65 static void* baseOfRenderObjectBeingDeleted;
66 #endif
67 
68 bool RenderObject::s_affectsParentBlock = false;
69 
operator new(size_t sz,RenderArena * renderArena)70 void* RenderObject::operator new(size_t sz, RenderArena* renderArena) throw()
71 {
72     return renderArena->allocate(sz);
73 }
74 
operator delete(void * ptr,size_t sz)75 void RenderObject::operator delete(void* ptr, size_t sz)
76 {
77     ASSERT(baseOfRenderObjectBeingDeleted == ptr);
78 
79     // Stash size where destroy can find it.
80     *(size_t *)ptr = sz;
81 }
82 
createObject(Node * node,RenderStyle * style)83 RenderObject* RenderObject::createObject(Node* node, RenderStyle* style)
84 {
85     Document* doc = node->document();
86     RenderArena* arena = doc->renderArena();
87 
88     // Minimal support for content properties replacing an entire element.
89     // Works only if we have exactly one piece of content and it's a URL.
90     // Otherwise acts as if we didn't support this feature.
91     const ContentData* contentData = style->contentData();
92     if (contentData && !contentData->m_next && contentData->m_type == CONTENT_OBJECT && doc != node) {
93         RenderImageGeneratedContent* image = new (arena) RenderImageGeneratedContent(node);
94         image->setStyle(style);
95         if (StyleImage* styleImage = contentData->m_content.m_image)
96             image->setStyleImage(styleImage);
97         return image;
98     }
99 
100     RenderObject* o = 0;
101 
102     switch (style->display()) {
103         case NONE:
104             break;
105         case INLINE:
106             o = new (arena) RenderInline(node);
107             break;
108         case BLOCK:
109             o = new (arena) RenderBlock(node);
110             break;
111         case INLINE_BLOCK:
112             o = new (arena) RenderBlock(node);
113             break;
114         case LIST_ITEM:
115             o = new (arena) RenderListItem(node);
116             break;
117         case RUN_IN:
118         case COMPACT:
119             o = new (arena) RenderBlock(node);
120             break;
121         case TABLE:
122         case INLINE_TABLE:
123             o = new (arena) RenderTable(node);
124             break;
125         case TABLE_ROW_GROUP:
126         case TABLE_HEADER_GROUP:
127         case TABLE_FOOTER_GROUP:
128             o = new (arena) RenderTableSection(node);
129             break;
130         case TABLE_ROW:
131             o = new (arena) RenderTableRow(node);
132             break;
133         case TABLE_COLUMN_GROUP:
134         case TABLE_COLUMN:
135             o = new (arena) RenderTableCol(node);
136             break;
137         case TABLE_CELL:
138             o = new (arena) RenderTableCell(node);
139             break;
140         case TABLE_CAPTION:
141             o = new (arena) RenderBlock(node);
142             break;
143         case BOX:
144         case INLINE_BOX:
145             o = new (arena) RenderFlexibleBox(node);
146             break;
147     }
148 
149     return o;
150 }
151 
152 #ifndef NDEBUG
153 static WTF::RefCountedLeakCounter renderObjectCounter("RenderObject");
154 #endif
155 
RenderObject(Node * node)156 RenderObject::RenderObject(Node* node)
157     : CachedResourceClient()
158     , m_style(0)
159     , m_node(node)
160     , m_parent(0)
161     , m_previous(0)
162     , m_next(0)
163 #ifndef NDEBUG
164     , m_hasAXObject(false)
165     , m_setNeedsLayoutForbidden(false)
166 #endif
167     , m_verticalPosition(PositionUndefined)
168     , m_needsLayout(false)
169     , m_needsPositionedMovementLayout(false)
170     , m_normalChildNeedsLayout(false)
171     , m_posChildNeedsLayout(false)
172     , m_prefWidthsDirty(false)
173     , m_floating(false)
174     , m_positioned(false)
175     , m_relPositioned(false)
176     , m_paintBackground(false)
177     , m_isAnonymous(node == node->document())
178     , m_isText(false)
179     , m_isBox(false)
180     , m_inline(true)
181     , m_replaced(false)
182     , m_isDragging(false)
183     , m_hasLayer(false)
184     , m_hasOverflowClip(false)
185     , m_hasTransform(false)
186     , m_hasReflection(false)
187     , m_hasOverrideSize(false)
188     , m_hasCounterNodeMap(false)
189     , m_everHadLayout(false)
190 {
191 #ifndef NDEBUG
192     renderObjectCounter.increment();
193 #endif
194 }
195 
~RenderObject()196 RenderObject::~RenderObject()
197 {
198     ASSERT(!node() || documentBeingDestroyed() || !document()->frame()->view() || document()->frame()->view()->layoutRoot() != this);
199 #ifndef NDEBUG
200     ASSERT(!m_hasAXObject);
201     renderObjectCounter.decrement();
202 #endif
203 }
204 
isDescendantOf(const RenderObject * obj) const205 bool RenderObject::isDescendantOf(const RenderObject* obj) const
206 {
207     for (const RenderObject* r = this; r; r = r->m_parent) {
208         if (r == obj)
209             return true;
210     }
211     return false;
212 }
213 
isBody() const214 bool RenderObject::isBody() const
215 {
216     return node()->hasTagName(bodyTag);
217 }
218 
isHR() const219 bool RenderObject::isHR() const
220 {
221     return element() && element()->hasTagName(hrTag);
222 }
223 
isHTMLMarquee() const224 bool RenderObject::isHTMLMarquee() const
225 {
226     return element() && element()->renderer() == this && element()->hasTagName(marqueeTag);
227 }
228 
canHaveChildren() const229 bool RenderObject::canHaveChildren() const
230 {
231     return false;
232 }
233 
isInlineContinuation() const234 bool RenderObject::isInlineContinuation() const
235 {
236     return false;
237 }
238 
addChild(RenderObject *,RenderObject *)239 void RenderObject::addChild(RenderObject*, RenderObject*)
240 {
241     ASSERT_NOT_REACHED();
242 }
243 
removeChildNode(RenderObject *,bool)244 RenderObject* RenderObject::removeChildNode(RenderObject*, bool)
245 {
246     ASSERT_NOT_REACHED();
247     return 0;
248 }
249 
removeChild(RenderObject *)250 void RenderObject::removeChild(RenderObject*)
251 {
252     ASSERT_NOT_REACHED();
253 }
254 
moveChildNode(RenderObject *)255 void RenderObject::moveChildNode(RenderObject*)
256 {
257     ASSERT_NOT_REACHED();
258 }
259 
appendChildNode(RenderObject *,bool)260 void RenderObject::appendChildNode(RenderObject*, bool)
261 {
262     ASSERT_NOT_REACHED();
263 }
264 
insertChildNode(RenderObject *,RenderObject *,bool)265 void RenderObject::insertChildNode(RenderObject*, RenderObject*, bool)
266 {
267     ASSERT_NOT_REACHED();
268 }
269 
nextInPreOrder() const270 RenderObject* RenderObject::nextInPreOrder() const
271 {
272     if (RenderObject* o = firstChild())
273         return o;
274 
275     return nextInPreOrderAfterChildren();
276 }
277 
nextInPreOrderAfterChildren() const278 RenderObject* RenderObject::nextInPreOrderAfterChildren() const
279 {
280     RenderObject* o;
281     if (!(o = nextSibling())) {
282         o = parent();
283         while (o && !o->nextSibling())
284             o = o->parent();
285         if (o)
286             o = o->nextSibling();
287     }
288 
289     return o;
290 }
291 
nextInPreOrder(RenderObject * stayWithin) const292 RenderObject* RenderObject::nextInPreOrder(RenderObject* stayWithin) const
293 {
294     if (RenderObject* o = firstChild())
295         return o;
296 
297     return nextInPreOrderAfterChildren(stayWithin);
298 }
299 
nextInPreOrderAfterChildren(RenderObject * stayWithin) const300 RenderObject* RenderObject::nextInPreOrderAfterChildren(RenderObject* stayWithin) const
301 {
302     if (this == stayWithin)
303         return 0;
304 
305     RenderObject* o;
306     if (!(o = nextSibling())) {
307         o = parent();
308         while (o && !o->nextSibling()) {
309             if (o == stayWithin)
310                 return 0;
311             o = o->parent();
312         }
313         if (o)
314             o = o->nextSibling();
315     }
316 
317     return o;
318 }
319 
previousInPreOrder() const320 RenderObject* RenderObject::previousInPreOrder() const
321 {
322     if (RenderObject* o = previousSibling()) {
323         while (o->lastChild())
324             o = o->lastChild();
325         return o;
326     }
327 
328     return parent();
329 }
330 
childAt(unsigned index) const331 RenderObject* RenderObject::childAt(unsigned index) const
332 {
333     RenderObject* child = firstChild();
334     for (unsigned i = 0; child && i < index; i++)
335         child = child->nextSibling();
336     return child;
337 }
338 
isEditable() const339 bool RenderObject::isEditable() const
340 {
341     RenderText* textRenderer = 0;
342     if (isText())
343         textRenderer = toRenderText(const_cast<RenderObject*>(this));
344 
345     return style()->visibility() == VISIBLE &&
346         element() && element()->isContentEditable() &&
347         ((isBlockFlow() && !firstChild()) ||
348         isReplaced() ||
349         isBR() ||
350         (textRenderer && textRenderer->firstTextBox()));
351 }
352 
firstLeafChild() const353 RenderObject* RenderObject::firstLeafChild() const
354 {
355     RenderObject* r = firstChild();
356     while (r) {
357         RenderObject* n = 0;
358         n = r->firstChild();
359         if (!n)
360             break;
361         r = n;
362     }
363     return r;
364 }
365 
lastLeafChild() const366 RenderObject* RenderObject::lastLeafChild() const
367 {
368     RenderObject* r = lastChild();
369     while (r) {
370         RenderObject* n = 0;
371         n = r->lastChild();
372         if (!n)
373             break;
374         r = n;
375     }
376     return r;
377 }
378 
addLayers(RenderObject * obj,RenderLayer * parentLayer,RenderObject * & newObject,RenderLayer * & beforeChild)379 static void addLayers(RenderObject* obj, RenderLayer* parentLayer, RenderObject*& newObject,
380                       RenderLayer*& beforeChild)
381 {
382     if (obj->hasLayer()) {
383         if (!beforeChild && newObject) {
384             // We need to figure out the layer that follows newObject.  We only do
385             // this the first time we find a child layer, and then we update the
386             // pointer values for newObject and beforeChild used by everyone else.
387             beforeChild = newObject->parent()->findNextLayer(parentLayer, newObject);
388             newObject = 0;
389         }
390         parentLayer->addChild(toRenderBox(obj)->layer(), beforeChild);
391         return;
392     }
393 
394     for (RenderObject* curr = obj->firstChild(); curr; curr = curr->nextSibling())
395         addLayers(curr, parentLayer, newObject, beforeChild);
396 }
397 
addLayers(RenderLayer * parentLayer,RenderObject * newObject)398 void RenderObject::addLayers(RenderLayer* parentLayer, RenderObject* newObject)
399 {
400     if (!parentLayer)
401         return;
402 
403     RenderObject* object = newObject;
404     RenderLayer* beforeChild = 0;
405     WebCore::addLayers(this, parentLayer, object, beforeChild);
406 }
407 
removeLayers(RenderLayer * parentLayer)408 void RenderObject::removeLayers(RenderLayer* parentLayer)
409 {
410     if (!parentLayer)
411         return;
412 
413     if (hasLayer()) {
414         parentLayer->removeChild(toRenderBox(this)->layer());
415         return;
416     }
417 
418     for (RenderObject* curr = firstChild(); curr; curr = curr->nextSibling())
419         curr->removeLayers(parentLayer);
420 }
421 
moveLayers(RenderLayer * oldParent,RenderLayer * newParent)422 void RenderObject::moveLayers(RenderLayer* oldParent, RenderLayer* newParent)
423 {
424     if (!newParent)
425         return;
426 
427     if (hasLayer()) {
428         RenderLayer* layer = toRenderBox(this)->layer();
429         if (oldParent)
430             oldParent->removeChild(layer);
431         newParent->addChild(layer);
432         return;
433     }
434 
435     for (RenderObject* curr = firstChild(); curr; curr = curr->nextSibling())
436         curr->moveLayers(oldParent, newParent);
437 }
438 
findNextLayer(RenderLayer * parentLayer,RenderObject * startPoint,bool checkParent)439 RenderLayer* RenderObject::findNextLayer(RenderLayer* parentLayer, RenderObject* startPoint,
440                                          bool checkParent)
441 {
442     // Error check the parent layer passed in.  If it's null, we can't find anything.
443     if (!parentLayer)
444         return 0;
445 
446     // Step 1: If our layer is a child of the desired parent, then return our layer.
447     RenderLayer* ourLayer = hasLayer() ? toRenderBox(this)->layer() : 0;
448     if (ourLayer && ourLayer->parent() == parentLayer)
449         return ourLayer;
450 
451     // Step 2: If we don't have a layer, or our layer is the desired parent, then descend
452     // into our siblings trying to find the next layer whose parent is the desired parent.
453     if (!ourLayer || ourLayer == parentLayer) {
454         for (RenderObject* curr = startPoint ? startPoint->nextSibling() : firstChild();
455              curr; curr = curr->nextSibling()) {
456             RenderLayer* nextLayer = curr->findNextLayer(parentLayer, 0, false);
457             if (nextLayer)
458                 return nextLayer;
459         }
460     }
461 
462     // Step 3: If our layer is the desired parent layer, then we're finished.  We didn't
463     // find anything.
464     if (parentLayer == ourLayer)
465         return 0;
466 
467     // Step 4: If |checkParent| is set, climb up to our parent and check its siblings that
468     // follow us to see if we can locate a layer.
469     if (checkParent && parent())
470         return parent()->findNextLayer(parentLayer, this, true);
471 
472     return 0;
473 }
474 
enclosingLayer() const475 RenderLayer* RenderObject::enclosingLayer() const
476 {
477     const RenderObject* curr = this;
478     while (curr) {
479         RenderLayer* layer = curr->hasLayer() ? toRenderBox(curr)->layer() : 0;
480         if (layer)
481             return layer;
482         curr = curr->parent();
483     }
484     return 0;
485 }
486 
enclosingBox() const487 RenderBox* RenderObject::enclosingBox() const
488 {
489     RenderObject* curr = const_cast<RenderObject*>(this);
490     while (curr) {
491         if (curr->isBox())
492             return toRenderBox(curr);
493         curr = curr->parent();
494     }
495 
496     ASSERT_NOT_REACHED();
497     return 0;
498 }
499 
firstLineBlock() const500 RenderBlock* RenderObject::firstLineBlock() const
501 {
502     return 0;
503 }
504 
hasStaticX() const505 bool RenderObject::hasStaticX() const
506 {
507     return (style()->left().isAuto() && style()->right().isAuto()) || style()->left().isStatic() || style()->right().isStatic();
508 }
509 
hasStaticY() const510 bool RenderObject::hasStaticY() const
511 {
512     return (style()->top().isAuto() && style()->bottom().isAuto()) || style()->top().isStatic();
513 }
514 
setPrefWidthsDirty(bool b,bool markParents)515 void RenderObject::setPrefWidthsDirty(bool b, bool markParents)
516 {
517     bool alreadyDirty = m_prefWidthsDirty;
518     m_prefWidthsDirty = b;
519     if (b && !alreadyDirty && markParents && (isText() || (style()->position() != FixedPosition && style()->position() != AbsolutePosition)))
520         invalidateContainerPrefWidths();
521 }
522 
invalidateContainerPrefWidths()523 void RenderObject::invalidateContainerPrefWidths()
524 {
525     // In order to avoid pathological behavior when inlines are deeply nested, we do include them
526     // in the chain that we mark dirty (even though they're kind of irrelevant).
527     RenderObject* o = isTableCell() ? containingBlock() : container();
528     while (o && !o->m_prefWidthsDirty) {
529         o->m_prefWidthsDirty = true;
530         if (o->style()->position() == FixedPosition || o->style()->position() == AbsolutePosition)
531             // A positioned object has no effect on the min/max width of its containing block ever.
532             // We can optimize this case and not go up any further.
533             break;
534         o = o->isTableCell() ? o->containingBlock() : o->container();
535     }
536 }
537 
setNeedsLayout(bool b,bool markParents)538 void RenderObject::setNeedsLayout(bool b, bool markParents)
539 {
540     bool alreadyNeededLayout = m_needsLayout;
541     m_needsLayout = b;
542     if (b) {
543         ASSERT(!isSetNeedsLayoutForbidden());
544         if (!alreadyNeededLayout) {
545             if (markParents)
546                 markContainingBlocksForLayout();
547             if (hasLayer())
548                 toRenderBox(this)->layer()->setNeedsFullRepaint();
549         }
550     } else {
551         m_everHadLayout = true;
552         m_posChildNeedsLayout = false;
553         m_normalChildNeedsLayout = false;
554         m_needsPositionedMovementLayout = false;
555     }
556 }
557 
setChildNeedsLayout(bool b,bool markParents)558 void RenderObject::setChildNeedsLayout(bool b, bool markParents)
559 {
560     bool alreadyNeededLayout = m_normalChildNeedsLayout;
561     m_normalChildNeedsLayout = b;
562     if (b) {
563         ASSERT(!isSetNeedsLayoutForbidden());
564         if (!alreadyNeededLayout && markParents)
565             markContainingBlocksForLayout();
566     } else {
567         m_posChildNeedsLayout = false;
568         m_normalChildNeedsLayout = false;
569         m_needsPositionedMovementLayout = false;
570     }
571 }
572 
setNeedsPositionedMovementLayout()573 void RenderObject::setNeedsPositionedMovementLayout()
574 {
575     bool alreadyNeededLayout = needsLayout();
576     m_needsPositionedMovementLayout = true;
577     if (!alreadyNeededLayout) {
578         markContainingBlocksForLayout();
579         if (hasLayer())
580             toRenderBox(this)->layer()->setNeedsFullRepaint();
581     }
582 }
583 
objectIsRelayoutBoundary(const RenderObject * obj)584 static inline bool objectIsRelayoutBoundary(const RenderObject *obj)
585 {
586     // FIXME: In future it may be possible to broaden this condition in order to improve performance.
587     // Table cells are excluded because even when their CSS height is fixed, their height()
588     // may depend on their contents.
589     return obj->isTextField() || obj->isTextArea()
590         || obj->hasOverflowClip() && !obj->style()->width().isIntrinsicOrAuto() && !obj->style()->height().isIntrinsicOrAuto() && !obj->style()->height().isPercent() && !obj->isTableCell()
591 #if ENABLE(SVG)
592            || obj->isSVGRoot()
593 #endif
594            ;
595 }
596 
markContainingBlocksForLayout(bool scheduleRelayout,RenderObject * newRoot)597 void RenderObject::markContainingBlocksForLayout(bool scheduleRelayout, RenderObject* newRoot)
598 {
599     ASSERT(!scheduleRelayout || !newRoot);
600 
601     RenderObject* o = container();
602     RenderObject* last = this;
603 
604     while (o) {
605         if (!last->isText() && (last->style()->position() == FixedPosition || last->style()->position() == AbsolutePosition)) {
606             if (last->hasStaticY()) {
607                 RenderObject* parent = last->parent();
608                 if (!parent->normalChildNeedsLayout()) {
609                     parent->setChildNeedsLayout(true, false);
610                     if (parent != newRoot)
611                         parent->markContainingBlocksForLayout(scheduleRelayout, newRoot);
612                 }
613             }
614             if (o->m_posChildNeedsLayout)
615                 return;
616             o->m_posChildNeedsLayout = true;
617             ASSERT(!o->isSetNeedsLayoutForbidden());
618         } else {
619             if (o->m_normalChildNeedsLayout)
620                 return;
621             o->m_normalChildNeedsLayout = true;
622             ASSERT(!o->isSetNeedsLayoutForbidden());
623         }
624 
625         if (o == newRoot)
626             return;
627 
628         last = o;
629         if (scheduleRelayout && objectIsRelayoutBoundary(last))
630             break;
631         o = o->container();
632     }
633 
634     if (scheduleRelayout)
635         last->scheduleRelayout();
636 }
637 
containingBlock() const638 RenderBlock* RenderObject::containingBlock() const
639 {
640     if (isTableCell()) {
641         const RenderTableCell* cell = static_cast<const RenderTableCell*>(this);
642         if (parent() && cell->section())
643             return cell->table();
644         return 0;
645     }
646 
647     if (isRenderView())
648         return const_cast<RenderBlock*>(static_cast<const RenderBlock*>(this));
649 
650     RenderObject* o = parent();
651     if (!isText() && m_style->position() == FixedPosition) {
652         while (o && !o->isRenderView() && !(o->hasTransform() && o->isRenderBlock()))
653             o = o->parent();
654     } else if (!isText() && m_style->position() == AbsolutePosition) {
655         while (o && (o->style()->position() == StaticPosition || (o->isInline() && !o->isReplaced())) && !o->isRenderView() && !(o->hasTransform() && o->isRenderBlock())) {
656             // For relpositioned inlines, we return the nearest enclosing block.  We don't try
657             // to return the inline itself.  This allows us to avoid having a positioned objects
658             // list in all RenderInlines and lets us return a strongly-typed RenderBlock* result
659             // from this method.  The container() method can actually be used to obtain the
660             // inline directly.
661             if (o->style()->position() == RelativePosition && o->isInline() && !o->isReplaced())
662                 return o->containingBlock();
663             o = o->parent();
664         }
665     } else {
666         while (o && ((o->isInline() && !o->isReplaced()) || o->isTableRow() || o->isTableSection()
667                      || o->isTableCol() || o->isFrameSet() || o->isMedia()
668 #if ENABLE(SVG)
669                      || o->isSVGContainer() || o->isSVGRoot()
670 #endif
671                      ))
672             o = o->parent();
673     }
674 
675     if (!o || !o->isRenderBlock())
676         return 0; // Probably doesn't happen any more, but leave just in case. -dwh
677 
678     return static_cast<RenderBlock*>(o);
679 }
680 
containingBlockWidth() const681 int RenderObject::containingBlockWidth() const
682 {
683     // FIXME ?
684     return containingBlock()->availableWidth();
685 }
686 
containingBlockHeight() const687 int RenderObject::containingBlockHeight() const
688 {
689     // FIXME ?
690     return containingBlock()->contentHeight();
691 }
692 
mustRepaintFillLayers(const RenderObject * renderer,const FillLayer * layer)693 static bool mustRepaintFillLayers(const RenderObject* renderer, const FillLayer* layer)
694 {
695     // Nobody will use multiple layers without wanting fancy positioning.
696     if (layer->next())
697         return true;
698 
699     // Make sure we have a valid image.
700     StyleImage* img = layer->image();
701     bool shouldPaintBackgroundImage = img && img->canRender(renderer->style()->effectiveZoom());
702 
703     // These are always percents or auto.
704     if (shouldPaintBackgroundImage &&
705         (!layer->xPosition().isZero() || !layer->yPosition().isZero() ||
706          layer->size().width().isPercent() || layer->size().height().isPercent()))
707         // The image will shift unpredictably if the size changes.
708         return true;
709 
710     return false;
711 }
712 
mustRepaintBackgroundOrBorder() const713 bool RenderObject::mustRepaintBackgroundOrBorder() const
714 {
715     if (hasMask() && mustRepaintFillLayers(this, style()->maskLayers()))
716         return true;
717 
718     // If we don't have a background/border/mask, then nothing to do.
719     if (!hasBoxDecorations())
720         return false;
721 
722     if (mustRepaintFillLayers(this, style()->backgroundLayers()))
723         return true;
724 
725     // Our fill layers are ok.  Let's check border.
726     if (style()->hasBorder()) {
727         // Border images are not ok.
728         StyleImage* borderImage = style()->borderImage().image();
729         bool shouldPaintBorderImage = borderImage && borderImage->canRender(style()->effectiveZoom());
730 
731         // If the image hasn't loaded, we're still using the normal border style.
732         if (shouldPaintBorderImage && borderImage->isLoaded())
733             return true;
734     }
735 
736     return false;
737 }
738 
drawBorderArc(GraphicsContext * graphicsContext,int x,int y,float thickness,IntSize radius,int angleStart,int angleSpan,BorderSide s,Color c,const Color & textColor,EBorderStyle style,bool firstCorner)739 void RenderObject::drawBorderArc(GraphicsContext* graphicsContext, int x, int y, float thickness, IntSize radius,
740                                  int angleStart, int angleSpan, BorderSide s, Color c, const Color& textColor,
741                                  EBorderStyle style, bool firstCorner)
742 {
743     if ((style == DOUBLE && thickness / 2 < 3) || ((style == RIDGE || style == GROOVE) && thickness / 2 < 2))
744         style = SOLID;
745 
746     if (!c.isValid()) {
747         if (style == INSET || style == OUTSET || style == RIDGE || style == GROOVE)
748             c.setRGB(238, 238, 238);
749         else
750             c = textColor;
751     }
752 
753     switch (style) {
754         case BNONE:
755         case BHIDDEN:
756             return;
757         case DOTTED:
758         case DASHED:
759             graphicsContext->setStrokeColor(c);
760             graphicsContext->setStrokeStyle(style == DOTTED ? DottedStroke : DashedStroke);
761             graphicsContext->setStrokeThickness(thickness);
762             graphicsContext->strokeArc(IntRect(x, y, radius.width() * 2, radius.height() * 2), angleStart, angleSpan);
763             break;
764         case DOUBLE: {
765             float third = thickness / 3.0f;
766             float innerThird = (thickness + 1.0f) / 6.0f;
767             int shiftForInner = static_cast<int>(innerThird * 2.5f);
768 
769             int outerY = y;
770             int outerHeight = radius.height() * 2;
771             int innerX = x + shiftForInner;
772             int innerY = y + shiftForInner;
773             int innerWidth = (radius.width() - shiftForInner) * 2;
774             int innerHeight = (radius.height() - shiftForInner) * 2;
775             if (innerThird > 1 && (s == BSTop || (firstCorner && (s == BSLeft || s == BSRight)))) {
776                 outerHeight += 2;
777                 innerHeight += 2;
778             }
779 
780             graphicsContext->setStrokeStyle(SolidStroke);
781             graphicsContext->setStrokeColor(c);
782             graphicsContext->setStrokeThickness(third);
783             graphicsContext->strokeArc(IntRect(x, outerY, radius.width() * 2, outerHeight), angleStart, angleSpan);
784             graphicsContext->setStrokeThickness(innerThird > 2 ? innerThird - 1 : innerThird);
785             graphicsContext->strokeArc(IntRect(innerX, innerY, innerWidth, innerHeight), angleStart, angleSpan);
786             break;
787         }
788         case GROOVE:
789         case RIDGE: {
790             Color c2;
791             if ((style == RIDGE && (s == BSTop || s == BSLeft)) ||
792                     (style == GROOVE && (s == BSBottom || s == BSRight)))
793                 c2 = c.dark();
794             else {
795                 c2 = c;
796                 c = c.dark();
797             }
798 
799             graphicsContext->setStrokeStyle(SolidStroke);
800             graphicsContext->setStrokeColor(c);
801             graphicsContext->setStrokeThickness(thickness);
802             graphicsContext->strokeArc(IntRect(x, y, radius.width() * 2, radius.height() * 2), angleStart, angleSpan);
803 
804             float halfThickness = (thickness + 1.0f) / 4.0f;
805             int shiftForInner = static_cast<int>(halfThickness * 1.5f);
806             graphicsContext->setStrokeColor(c2);
807             graphicsContext->setStrokeThickness(halfThickness > 2 ? halfThickness - 1 : halfThickness);
808             graphicsContext->strokeArc(IntRect(x + shiftForInner, y + shiftForInner, (radius.width() - shiftForInner) * 2,
809                                        (radius.height() - shiftForInner) * 2), angleStart, angleSpan);
810             break;
811         }
812         case INSET:
813             if (s == BSTop || s == BSLeft)
814                 c = c.dark();
815         case OUTSET:
816             if (style == OUTSET && (s == BSBottom || s == BSRight))
817                 c = c.dark();
818         case SOLID:
819             graphicsContext->setStrokeStyle(SolidStroke);
820             graphicsContext->setStrokeColor(c);
821             graphicsContext->setStrokeThickness(thickness);
822             graphicsContext->strokeArc(IntRect(x, y, radius.width() * 2, radius.height() * 2), angleStart, angleSpan);
823             break;
824     }
825 }
826 
drawBorder(GraphicsContext * graphicsContext,int x1,int y1,int x2,int y2,BorderSide s,Color c,const Color & textcolor,EBorderStyle style,int adjbw1,int adjbw2)827 void RenderObject::drawBorder(GraphicsContext* graphicsContext, int x1, int y1, int x2, int y2,
828                               BorderSide s, Color c, const Color& textcolor, EBorderStyle style,
829                               int adjbw1, int adjbw2)
830 {
831     int width = (s == BSTop || s == BSBottom ? y2 - y1 : x2 - x1);
832 
833     if (style == DOUBLE && width < 3)
834         style = SOLID;
835 
836     if (!c.isValid()) {
837         if (style == INSET || style == OUTSET || style == RIDGE || style == GROOVE)
838             c.setRGB(238, 238, 238);
839         else
840             c = textcolor;
841     }
842 
843     switch (style) {
844         case BNONE:
845         case BHIDDEN:
846             return;
847         case DOTTED:
848         case DASHED:
849             graphicsContext->setStrokeColor(c);
850             graphicsContext->setStrokeThickness(width);
851             graphicsContext->setStrokeStyle(style == DASHED ? DashedStroke : DottedStroke);
852 
853             if (width > 0)
854                 switch (s) {
855                     case BSBottom:
856                     case BSTop:
857                         graphicsContext->drawLine(IntPoint(x1, (y1 + y2) / 2), IntPoint(x2, (y1 + y2) / 2));
858                         break;
859                     case BSRight:
860                     case BSLeft:
861                         graphicsContext->drawLine(IntPoint((x1 + x2) / 2, y1), IntPoint((x1 + x2) / 2, y2));
862                         break;
863                 }
864             break;
865         case DOUBLE: {
866             int third = (width + 1) / 3;
867 
868             if (adjbw1 == 0 && adjbw2 == 0) {
869                 graphicsContext->setStrokeStyle(NoStroke);
870                 graphicsContext->setFillColor(c);
871                 switch (s) {
872                     case BSTop:
873                     case BSBottom:
874                         graphicsContext->drawRect(IntRect(x1, y1, x2 - x1, third));
875                         graphicsContext->drawRect(IntRect(x1, y2 - third, x2 - x1, third));
876                         break;
877                     case BSLeft:
878                         graphicsContext->drawRect(IntRect(x1, y1 + 1, third, y2 - y1 - 1));
879                         graphicsContext->drawRect(IntRect(x2 - third, y1 + 1, third, y2 - y1 - 1));
880                         break;
881                     case BSRight:
882                         graphicsContext->drawRect(IntRect(x1, y1 + 1, third, y2 - y1 - 1));
883                         graphicsContext->drawRect(IntRect(x2 - third, y1 + 1, third, y2 - y1 - 1));
884                         break;
885                 }
886             } else {
887                 int adjbw1bigthird = ((adjbw1 > 0) ? adjbw1 + 1 : adjbw1 - 1) / 3;
888                 int adjbw2bigthird = ((adjbw2 > 0) ? adjbw2 + 1 : adjbw2 - 1) / 3;
889 
890                 switch (s) {
891                     case BSTop:
892                         drawBorder(graphicsContext, x1 + max((-adjbw1 * 2 + 1) / 3, 0),
893                                    y1, x2 - max((-adjbw2 * 2 + 1) / 3, 0), y1 + third,
894                                    s, c, textcolor, SOLID, adjbw1bigthird, adjbw2bigthird);
895                         drawBorder(graphicsContext, x1 + max((adjbw1 * 2 + 1) / 3, 0),
896                                    y2 - third, x2 - max((adjbw2 * 2 + 1) / 3, 0), y2,
897                                    s, c, textcolor, SOLID, adjbw1bigthird, adjbw2bigthird);
898                         break;
899                     case BSLeft:
900                         drawBorder(graphicsContext, x1, y1 + max((-adjbw1 * 2 + 1) / 3, 0),
901                                    x1 + third, y2 - max((-adjbw2 * 2 + 1) / 3, 0),
902                                    s, c, textcolor, SOLID, adjbw1bigthird, adjbw2bigthird);
903                         drawBorder(graphicsContext, x2 - third, y1 + max((adjbw1 * 2 + 1) / 3, 0),
904                                    x2, y2 - max((adjbw2 * 2 + 1) / 3, 0),
905                                    s, c, textcolor, SOLID, adjbw1bigthird, adjbw2bigthird);
906                         break;
907                     case BSBottom:
908                         drawBorder(graphicsContext, x1 + max((adjbw1 * 2 + 1) / 3, 0),
909                                    y1, x2 - max((adjbw2 * 2 + 1) / 3, 0), y1 + third,
910                                    s, c, textcolor, SOLID, adjbw1bigthird, adjbw2bigthird);
911                         drawBorder(graphicsContext, x1 + max((-adjbw1 * 2 + 1) / 3, 0),
912                                    y2 - third, x2 - max((-adjbw2 * 2 + 1) / 3, 0), y2,
913                                    s, c, textcolor, SOLID, adjbw1bigthird, adjbw2bigthird);
914                         break;
915                     case BSRight:
916                         drawBorder(graphicsContext, x1, y1 + max((adjbw1 * 2 + 1) / 3, 0),
917                                    x1 + third, y2 - max(( adjbw2 * 2 + 1) / 3, 0),
918                                    s, c, textcolor, SOLID, adjbw1bigthird, adjbw2bigthird);
919                         drawBorder(graphicsContext, x2 - third, y1 + max((-adjbw1 * 2 + 1) / 3, 0),
920                                    x2, y2 - max((-adjbw2 * 2 + 1) / 3, 0),
921                                    s, c, textcolor, SOLID, adjbw1bigthird, adjbw2bigthird);
922                         break;
923                     default:
924                         break;
925                 }
926             }
927             break;
928         }
929         case RIDGE:
930         case GROOVE:
931         {
932             EBorderStyle s1;
933             EBorderStyle s2;
934             if (style == GROOVE) {
935                 s1 = INSET;
936                 s2 = OUTSET;
937             } else {
938                 s1 = OUTSET;
939                 s2 = INSET;
940             }
941 
942             int adjbw1bighalf = ((adjbw1 > 0) ? adjbw1 + 1 : adjbw1 - 1) / 2;
943             int adjbw2bighalf = ((adjbw2 > 0) ? adjbw2 + 1 : adjbw2 - 1) / 2;
944 
945             switch (s) {
946                 case BSTop:
947                     drawBorder(graphicsContext, x1 + max(-adjbw1, 0) / 2, y1, x2 - max(-adjbw2, 0) / 2, (y1 + y2 + 1) / 2,
948                                s, c, textcolor, s1, adjbw1bighalf, adjbw2bighalf);
949                     drawBorder(graphicsContext, x1 + max(adjbw1 + 1, 0) / 2, (y1 + y2 + 1) / 2, x2 - max(adjbw2 + 1, 0) / 2, y2,
950                                s, c, textcolor, s2, adjbw1 / 2, adjbw2 / 2);
951                     break;
952                 case BSLeft:
953                     drawBorder(graphicsContext, x1, y1 + max(-adjbw1, 0) / 2, (x1 + x2 + 1) / 2, y2 - max(-adjbw2, 0) / 2,
954                                s, c, textcolor, s1, adjbw1bighalf, adjbw2bighalf);
955                     drawBorder(graphicsContext, (x1 + x2 + 1) / 2, y1 + max(adjbw1 + 1, 0) / 2, x2, y2 - max(adjbw2 + 1, 0) / 2,
956                                s, c, textcolor, s2, adjbw1 / 2, adjbw2 / 2);
957                     break;
958                 case BSBottom:
959                     drawBorder(graphicsContext, x1 + max(adjbw1, 0) / 2, y1, x2 - max(adjbw2, 0) / 2, (y1 + y2 + 1) / 2,
960                                s, c, textcolor, s2, adjbw1bighalf, adjbw2bighalf);
961                     drawBorder(graphicsContext, x1 + max(-adjbw1 + 1, 0) / 2, (y1 + y2 + 1) / 2, x2 - max(-adjbw2 + 1, 0) / 2, y2,
962                                s, c, textcolor, s1, adjbw1/2, adjbw2/2);
963                     break;
964                 case BSRight:
965                     drawBorder(graphicsContext, x1, y1 + max(adjbw1, 0) / 2, (x1 + x2 + 1) / 2, y2 - max(adjbw2, 0) / 2,
966                                s, c, textcolor, s2, adjbw1bighalf, adjbw2bighalf);
967                     drawBorder(graphicsContext, (x1 + x2 + 1) / 2, y1 + max(-adjbw1 + 1, 0) / 2, x2, y2 - max(-adjbw2 + 1, 0) / 2,
968                                s, c, textcolor, s1, adjbw1/2, adjbw2/2);
969                     break;
970             }
971             break;
972         }
973         case INSET:
974             if (s == BSTop || s == BSLeft)
975                 c = c.dark();
976             // fall through
977         case OUTSET:
978             if (style == OUTSET && (s == BSBottom || s == BSRight))
979                 c = c.dark();
980             // fall through
981         case SOLID: {
982             graphicsContext->setStrokeStyle(NoStroke);
983             graphicsContext->setFillColor(c);
984             ASSERT(x2 >= x1);
985             ASSERT(y2 >= y1);
986             if (!adjbw1 && !adjbw2) {
987                 graphicsContext->drawRect(IntRect(x1, y1, x2 - x1, y2 - y1));
988                 return;
989             }
990             FloatPoint quad[4];
991             switch (s) {
992                 case BSTop:
993                     quad[0] = FloatPoint(x1 + max(-adjbw1, 0), y1);
994                     quad[1] = FloatPoint(x1 + max(adjbw1, 0), y2);
995                     quad[2] = FloatPoint(x2 - max(adjbw2, 0), y2);
996                     quad[3] = FloatPoint(x2 - max(-adjbw2, 0), y1);
997                     break;
998                 case BSBottom:
999                     quad[0] = FloatPoint(x1 + max(adjbw1, 0), y1);
1000                     quad[1] = FloatPoint(x1 + max(-adjbw1, 0), y2);
1001                     quad[2] = FloatPoint(x2 - max(-adjbw2, 0), y2);
1002                     quad[3] = FloatPoint(x2 - max(adjbw2, 0), y1);
1003                     break;
1004                 case BSLeft:
1005                     quad[0] = FloatPoint(x1, y1 + max(-adjbw1, 0));
1006                     quad[1] = FloatPoint(x1, y2 - max(-adjbw2, 0));
1007                     quad[2] = FloatPoint(x2, y2 - max(adjbw2, 0));
1008                     quad[3] = FloatPoint(x2, y1 + max(adjbw1, 0));
1009                     break;
1010                 case BSRight:
1011                     quad[0] = FloatPoint(x1, y1 + max(adjbw1, 0));
1012                     quad[1] = FloatPoint(x1, y2 - max(adjbw2, 0));
1013                     quad[2] = FloatPoint(x2, y2 - max(-adjbw2, 0));
1014                     quad[3] = FloatPoint(x2, y1 + max(-adjbw1, 0));
1015                     break;
1016             }
1017             graphicsContext->drawConvexPolygon(4, quad);
1018             break;
1019         }
1020     }
1021 }
1022 
paintNinePieceImage(GraphicsContext * graphicsContext,int tx,int ty,int w,int h,const RenderStyle * style,const NinePieceImage & ninePieceImage,CompositeOperator op)1023 bool RenderObject::paintNinePieceImage(GraphicsContext* graphicsContext, int tx, int ty, int w, int h, const RenderStyle* style,
1024                                        const NinePieceImage& ninePieceImage, CompositeOperator op)
1025 {
1026     StyleImage* styleImage = ninePieceImage.image();
1027     if (!styleImage || !styleImage->canRender(style->effectiveZoom()))
1028         return false;
1029 
1030     if (!styleImage->isLoaded())
1031         return true; // Never paint a nine-piece image incrementally, but don't paint the fallback borders either.
1032 
1033     // If we have a border radius, the image gets clipped to the rounded rect.
1034     bool clipped = false;
1035     if (style->hasBorderRadius()) {
1036         IntRect clipRect(tx, ty, w, h);
1037         graphicsContext->save();
1038         graphicsContext->addRoundedRectClip(clipRect, style->borderTopLeftRadius(), style->borderTopRightRadius(),
1039                                             style->borderBottomLeftRadius(), style->borderBottomRightRadius());
1040         clipped = true;
1041     }
1042 
1043     // FIXME: border-image is broken with full page zooming when tiling has to happen, since the tiling function
1044     // doesn't have any understanding of the zoom that is in effect on the tile.
1045     styleImage->setImageContainerSize(IntSize(w, h));
1046     IntSize imageSize = styleImage->imageSize(this, 1.0f);
1047     int imageWidth = imageSize.width();
1048     int imageHeight = imageSize.height();
1049 
1050     int topSlice = min(imageHeight, ninePieceImage.m_slices.top().calcValue(imageHeight));
1051     int bottomSlice = min(imageHeight, ninePieceImage.m_slices.bottom().calcValue(imageHeight));
1052     int leftSlice = min(imageWidth, ninePieceImage.m_slices.left().calcValue(imageWidth));
1053     int rightSlice = min(imageWidth, ninePieceImage.m_slices.right().calcValue(imageWidth));
1054 
1055     ENinePieceImageRule hRule = ninePieceImage.horizontalRule();
1056     ENinePieceImageRule vRule = ninePieceImage.verticalRule();
1057 
1058     bool fitToBorder = style->borderImage() == ninePieceImage;
1059 
1060     int leftWidth = fitToBorder ? style->borderLeftWidth() : leftSlice;
1061     int topWidth = fitToBorder ? style->borderTopWidth() : topSlice;
1062     int rightWidth = fitToBorder ? style->borderRightWidth() : rightSlice;
1063     int bottomWidth = fitToBorder ? style->borderBottomWidth() : bottomSlice;
1064 
1065     bool drawLeft = leftSlice > 0 && leftWidth > 0;
1066     bool drawTop = topSlice > 0 && topWidth > 0;
1067     bool drawRight = rightSlice > 0 && rightWidth > 0;
1068     bool drawBottom = bottomSlice > 0 && bottomWidth > 0;
1069     bool drawMiddle = (imageWidth - leftSlice - rightSlice) > 0 && (w - leftWidth - rightWidth) > 0 &&
1070                       (imageHeight - topSlice - bottomSlice) > 0 && (h - topWidth - bottomWidth) > 0;
1071 
1072     Image* image = styleImage->image(this, imageSize);
1073 
1074     if (drawLeft) {
1075         // Paint the top and bottom left corners.
1076 
1077         // The top left corner rect is (tx, ty, leftWidth, topWidth)
1078         // The rect to use from within the image is obtained from our slice, and is (0, 0, leftSlice, topSlice)
1079         if (drawTop)
1080             graphicsContext->drawImage(image, IntRect(tx, ty, leftWidth, topWidth),
1081                                        IntRect(0, 0, leftSlice, topSlice), op);
1082 
1083         // The bottom left corner rect is (tx, ty + h - bottomWidth, leftWidth, bottomWidth)
1084         // The rect to use from within the image is (0, imageHeight - bottomSlice, leftSlice, botomSlice)
1085         if (drawBottom)
1086             graphicsContext->drawImage(image, IntRect(tx, ty + h - bottomWidth, leftWidth, bottomWidth),
1087                                        IntRect(0, imageHeight - bottomSlice, leftSlice, bottomSlice), op);
1088 
1089         // Paint the left edge.
1090         // Have to scale and tile into the border rect.
1091         graphicsContext->drawTiledImage(image, IntRect(tx, ty + topWidth, leftWidth,
1092                                         h - topWidth - bottomWidth),
1093                                         IntRect(0, topSlice, leftSlice, imageHeight - topSlice - bottomSlice),
1094                                         Image::StretchTile, (Image::TileRule)vRule, op);
1095     }
1096 
1097     if (drawRight) {
1098         // Paint the top and bottom right corners
1099         // The top right corner rect is (tx + w - rightWidth, ty, rightWidth, topWidth)
1100         // The rect to use from within the image is obtained from our slice, and is (imageWidth - rightSlice, 0, rightSlice, topSlice)
1101         if (drawTop)
1102             graphicsContext->drawImage(image, IntRect(tx + w - rightWidth, ty, rightWidth, topWidth),
1103                                        IntRect(imageWidth - rightSlice, 0, rightSlice, topSlice), op);
1104 
1105         // The bottom right corner rect is (tx + w - rightWidth, ty + h - bottomWidth, rightWidth, bottomWidth)
1106         // The rect to use from within the image is (imageWidth - rightSlice, imageHeight - bottomSlice, rightSlice, bottomSlice)
1107         if (drawBottom)
1108             graphicsContext->drawImage(image, IntRect(tx + w - rightWidth, ty + h - bottomWidth, rightWidth, bottomWidth),
1109                                        IntRect(imageWidth - rightSlice, imageHeight - bottomSlice, rightSlice, bottomSlice), op);
1110 
1111         // Paint the right edge.
1112         graphicsContext->drawTiledImage(image, IntRect(tx + w - rightWidth, ty + topWidth, rightWidth,
1113                                         h - topWidth - bottomWidth),
1114                                         IntRect(imageWidth - rightSlice, topSlice, rightSlice, imageHeight - topSlice - bottomSlice),
1115                                         Image::StretchTile, (Image::TileRule)vRule, op);
1116     }
1117 
1118     // Paint the top edge.
1119     if (drawTop)
1120         graphicsContext->drawTiledImage(image, IntRect(tx + leftWidth, ty, w - leftWidth - rightWidth, topWidth),
1121                                         IntRect(leftSlice, 0, imageWidth - rightSlice - leftSlice, topSlice),
1122                                         (Image::TileRule)hRule, Image::StretchTile, op);
1123 
1124     // Paint the bottom edge.
1125     if (drawBottom)
1126         graphicsContext->drawTiledImage(image, IntRect(tx + leftWidth, ty + h - bottomWidth,
1127                                         w - leftWidth - rightWidth, bottomWidth),
1128                                         IntRect(leftSlice, imageHeight - bottomSlice, imageWidth - rightSlice - leftSlice, bottomSlice),
1129                                         (Image::TileRule)hRule, Image::StretchTile, op);
1130 
1131     // Paint the middle.
1132     if (drawMiddle)
1133         graphicsContext->drawTiledImage(image, IntRect(tx + leftWidth, ty + topWidth, w - leftWidth - rightWidth,
1134                                         h - topWidth - bottomWidth),
1135                                         IntRect(leftSlice, topSlice, imageWidth - rightSlice - leftSlice, imageHeight - topSlice - bottomSlice),
1136                                         (Image::TileRule)hRule, (Image::TileRule)vRule, op);
1137 
1138     // Clear the clip for the border radius.
1139     if (clipped)
1140         graphicsContext->restore();
1141 
1142     return true;
1143 }
1144 
paintBorder(GraphicsContext * graphicsContext,int tx,int ty,int w,int h,const RenderStyle * style,bool begin,bool end)1145 void RenderObject::paintBorder(GraphicsContext* graphicsContext, int tx, int ty, int w, int h,
1146                                const RenderStyle* style, bool begin, bool end)
1147 {
1148     if (paintNinePieceImage(graphicsContext, tx, ty, w, h, style, style->borderImage()))
1149         return;
1150 
1151     const Color& tc = style->borderTopColor();
1152     const Color& bc = style->borderBottomColor();
1153     const Color& lc = style->borderLeftColor();
1154     const Color& rc = style->borderRightColor();
1155 
1156     bool tt = style->borderTopIsTransparent();
1157     bool bt = style->borderBottomIsTransparent();
1158     bool rt = style->borderRightIsTransparent();
1159     bool lt = style->borderLeftIsTransparent();
1160 
1161     EBorderStyle ts = style->borderTopStyle();
1162     EBorderStyle bs = style->borderBottomStyle();
1163     EBorderStyle ls = style->borderLeftStyle();
1164     EBorderStyle rs = style->borderRightStyle();
1165 
1166     bool renderTop = ts > BHIDDEN && !tt;
1167     bool renderLeft = ls > BHIDDEN && begin && !lt;
1168     bool renderRight = rs > BHIDDEN && end && !rt;
1169     bool renderBottom = bs > BHIDDEN && !bt;
1170 
1171     // Need sufficient width and height to contain border radius curves.  Sanity check our border radii
1172     // and our width/height values to make sure the curves can all fit. If not, then we won't paint
1173     // any border radii.
1174     bool renderRadii = false;
1175     IntSize topLeft = style->borderTopLeftRadius();
1176     IntSize topRight = style->borderTopRightRadius();
1177     IntSize bottomLeft = style->borderBottomLeftRadius();
1178     IntSize bottomRight = style->borderBottomRightRadius();
1179 
1180     if (style->hasBorderRadius() &&
1181         static_cast<unsigned>(w) >= static_cast<unsigned>(topLeft.width()) + static_cast<unsigned>(topRight.width()) &&
1182         static_cast<unsigned>(w) >= static_cast<unsigned>(bottomLeft.width()) + static_cast<unsigned>(bottomRight.width()) &&
1183         static_cast<unsigned>(h) >= static_cast<unsigned>(topLeft.height()) + static_cast<unsigned>(bottomLeft.height()) &&
1184         static_cast<unsigned>(h) >= static_cast<unsigned>(topRight.height()) + static_cast<unsigned>(bottomRight.height()))
1185         renderRadii = true;
1186 
1187     // Clip to the rounded rectangle.
1188     if (renderRadii) {
1189         graphicsContext->save();
1190         graphicsContext->addRoundedRectClip(IntRect(tx, ty, w, h), topLeft, topRight, bottomLeft, bottomRight);
1191     }
1192 
1193     int firstAngleStart, secondAngleStart, firstAngleSpan, secondAngleSpan;
1194     float thickness;
1195     bool upperLeftBorderStylesMatch = renderLeft && (ts == ls) && (tc == lc);
1196     bool upperRightBorderStylesMatch = renderRight && (ts == rs) && (tc == rc) && (ts != OUTSET) && (ts != RIDGE) && (ts != INSET) && (ts != GROOVE);
1197     bool lowerLeftBorderStylesMatch = renderLeft && (bs == ls) && (bc == lc) && (bs != OUTSET) && (bs != RIDGE) && (bs != INSET) && (bs != GROOVE);
1198     bool lowerRightBorderStylesMatch = renderRight && (bs == rs) && (bc == rc);
1199 
1200     if (renderTop) {
1201         bool ignore_left = (renderRadii && topLeft.width() > 0) ||
1202             (tc == lc && tt == lt && ts >= OUTSET &&
1203              (ls == DOTTED || ls == DASHED || ls == SOLID || ls == OUTSET));
1204 
1205         bool ignore_right = (renderRadii && topRight.width() > 0) ||
1206             (tc == rc && tt == rt && ts >= OUTSET &&
1207              (rs == DOTTED || rs == DASHED || rs == SOLID || rs == INSET));
1208 
1209         int x = tx;
1210         int x2 = tx + w;
1211         if (renderRadii) {
1212             x += topLeft.width();
1213             x2 -= topRight.width();
1214         }
1215 
1216         drawBorder(graphicsContext, x, ty, x2, ty + style->borderTopWidth(), BSTop, tc, style->color(), ts,
1217                    ignore_left ? 0 : style->borderLeftWidth(), ignore_right ? 0 : style->borderRightWidth());
1218 
1219         if (renderRadii) {
1220             int leftY = ty;
1221 
1222             // We make the arc double thick and let the clip rect take care of clipping the extra off.
1223             // We're doing this because it doesn't seem possible to match the curve of the clip exactly
1224             // with the arc-drawing function.
1225             thickness = style->borderTopWidth() * 2;
1226 
1227             if (topLeft.width()) {
1228                 int leftX = tx;
1229                 // The inner clip clips inside the arc. This is especially important for 1px borders.
1230                 bool applyLeftInnerClip = (style->borderLeftWidth() < topLeft.width())
1231                     && (style->borderTopWidth() < topLeft.height())
1232                     && (ts != DOUBLE || style->borderTopWidth() > 6);
1233                 if (applyLeftInnerClip) {
1234                     graphicsContext->save();
1235                     graphicsContext->addInnerRoundedRectClip(IntRect(leftX, leftY, topLeft.width() * 2, topLeft.height() * 2),
1236                                                              style->borderTopWidth());
1237                 }
1238 
1239                 firstAngleStart = 90;
1240                 firstAngleSpan = upperLeftBorderStylesMatch ? 90 : 45;
1241 
1242                 // Draw upper left arc
1243                 drawBorderArc(graphicsContext, leftX, leftY, thickness, topLeft, firstAngleStart, firstAngleSpan,
1244                               BSTop, tc, style->color(), ts, true);
1245                 if (applyLeftInnerClip)
1246                     graphicsContext->restore();
1247             }
1248 
1249             if (topRight.width()) {
1250                 int rightX = tx + w - topRight.width() * 2;
1251                 bool applyRightInnerClip = (style->borderRightWidth() < topRight.width())
1252                     && (style->borderTopWidth() < topRight.height())
1253                     && (ts != DOUBLE || style->borderTopWidth() > 6);
1254                 if (applyRightInnerClip) {
1255                     graphicsContext->save();
1256                     graphicsContext->addInnerRoundedRectClip(IntRect(rightX, leftY, topRight.width() * 2, topRight.height() * 2),
1257                                                              style->borderTopWidth());
1258                 }
1259 
1260                 if (upperRightBorderStylesMatch) {
1261                     secondAngleStart = 0;
1262                     secondAngleSpan = 90;
1263                 } else {
1264                     secondAngleStart = 45;
1265                     secondAngleSpan = 45;
1266                 }
1267 
1268                 // Draw upper right arc
1269                 drawBorderArc(graphicsContext, rightX, leftY, thickness, topRight, secondAngleStart, secondAngleSpan,
1270                               BSTop, tc, style->color(), ts, false);
1271                 if (applyRightInnerClip)
1272                     graphicsContext->restore();
1273             }
1274         }
1275     }
1276 
1277     if (renderBottom) {
1278         bool ignore_left = (renderRadii && bottomLeft.width() > 0) ||
1279             (bc == lc && bt == lt && bs >= OUTSET &&
1280              (ls == DOTTED || ls == DASHED || ls == SOLID || ls == OUTSET));
1281 
1282         bool ignore_right = (renderRadii && bottomRight.width() > 0) ||
1283             (bc == rc && bt == rt && bs >= OUTSET &&
1284              (rs == DOTTED || rs == DASHED || rs == SOLID || rs == INSET));
1285 
1286         int x = tx;
1287         int x2 = tx + w;
1288         if (renderRadii) {
1289             x += bottomLeft.width();
1290             x2 -= bottomRight.width();
1291         }
1292 
1293         drawBorder(graphicsContext, x, ty + h - style->borderBottomWidth(), x2, ty + h, BSBottom, bc, style->color(), bs,
1294                    ignore_left ? 0 : style->borderLeftWidth(), ignore_right ? 0 : style->borderRightWidth());
1295 
1296         if (renderRadii) {
1297             thickness = style->borderBottomWidth() * 2;
1298 
1299             if (bottomLeft.width()) {
1300                 int leftX = tx;
1301                 int leftY = ty + h - bottomLeft.height() * 2;
1302                 bool applyLeftInnerClip = (style->borderLeftWidth() < bottomLeft.width())
1303                     && (style->borderBottomWidth() < bottomLeft.height())
1304                     && (bs != DOUBLE || style->borderBottomWidth() > 6);
1305                 if (applyLeftInnerClip) {
1306                     graphicsContext->save();
1307                     graphicsContext->addInnerRoundedRectClip(IntRect(leftX, leftY, bottomLeft.width() * 2, bottomLeft.height() * 2),
1308                                                              style->borderBottomWidth());
1309                 }
1310 
1311                 if (lowerLeftBorderStylesMatch) {
1312                     firstAngleStart = 180;
1313                     firstAngleSpan = 90;
1314                 } else {
1315                     firstAngleStart = 225;
1316                     firstAngleSpan = 45;
1317                 }
1318 
1319                 // Draw lower left arc
1320                 drawBorderArc(graphicsContext, leftX, leftY, thickness, bottomLeft, firstAngleStart, firstAngleSpan,
1321                               BSBottom, bc, style->color(), bs, true);
1322                 if (applyLeftInnerClip)
1323                     graphicsContext->restore();
1324             }
1325 
1326             if (bottomRight.width()) {
1327                 int rightY = ty + h - bottomRight.height() * 2;
1328                 int rightX = tx + w - bottomRight.width() * 2;
1329                 bool applyRightInnerClip = (style->borderRightWidth() < bottomRight.width())
1330                     && (style->borderBottomWidth() < bottomRight.height())
1331                     && (bs != DOUBLE || style->borderBottomWidth() > 6);
1332                 if (applyRightInnerClip) {
1333                     graphicsContext->save();
1334                     graphicsContext->addInnerRoundedRectClip(IntRect(rightX, rightY, bottomRight.width() * 2, bottomRight.height() * 2),
1335                                                              style->borderBottomWidth());
1336                 }
1337 
1338                 secondAngleStart = 270;
1339                 secondAngleSpan = lowerRightBorderStylesMatch ? 90 : 45;
1340 
1341                 // Draw lower right arc
1342                 drawBorderArc(graphicsContext, rightX, rightY, thickness, bottomRight, secondAngleStart, secondAngleSpan,
1343                               BSBottom, bc, style->color(), bs, false);
1344                 if (applyRightInnerClip)
1345                     graphicsContext->restore();
1346             }
1347         }
1348     }
1349 
1350     if (renderLeft) {
1351         bool ignore_top = (renderRadii && topLeft.height() > 0) ||
1352             (tc == lc && tt == lt && ls >= OUTSET &&
1353              (ts == DOTTED || ts == DASHED || ts == SOLID || ts == OUTSET));
1354 
1355         bool ignore_bottom = (renderRadii && bottomLeft.height() > 0) ||
1356             (bc == lc && bt == lt && ls >= OUTSET &&
1357              (bs == DOTTED || bs == DASHED || bs == SOLID || bs == INSET));
1358 
1359         int y = ty;
1360         int y2 = ty + h;
1361         if (renderRadii) {
1362             y += topLeft.height();
1363             y2 -= bottomLeft.height();
1364         }
1365 
1366         drawBorder(graphicsContext, tx, y, tx + style->borderLeftWidth(), y2, BSLeft, lc, style->color(), ls,
1367                    ignore_top ? 0 : style->borderTopWidth(), ignore_bottom ? 0 : style->borderBottomWidth());
1368 
1369         if (renderRadii && (!upperLeftBorderStylesMatch || !lowerLeftBorderStylesMatch)) {
1370             int topX = tx;
1371             thickness = style->borderLeftWidth() * 2;
1372 
1373             if (!upperLeftBorderStylesMatch && topLeft.width()) {
1374                 int topY = ty;
1375                 bool applyTopInnerClip = (style->borderLeftWidth() < topLeft.width())
1376                     && (style->borderTopWidth() < topLeft.height())
1377                     && (ls != DOUBLE || style->borderLeftWidth() > 6);
1378                 if (applyTopInnerClip) {
1379                     graphicsContext->save();
1380                     graphicsContext->addInnerRoundedRectClip(IntRect(topX, topY, topLeft.width() * 2, topLeft.height() * 2),
1381                                                              style->borderLeftWidth());
1382                 }
1383 
1384                 firstAngleStart = 135;
1385                 firstAngleSpan = 45;
1386 
1387                 // Draw top left arc
1388                 drawBorderArc(graphicsContext, topX, topY, thickness, topLeft, firstAngleStart, firstAngleSpan,
1389                               BSLeft, lc, style->color(), ls, true);
1390                 if (applyTopInnerClip)
1391                     graphicsContext->restore();
1392             }
1393 
1394             if (!lowerLeftBorderStylesMatch && bottomLeft.width()) {
1395                 int bottomY = ty + h - bottomLeft.height() * 2;
1396                 bool applyBottomInnerClip = (style->borderLeftWidth() < bottomLeft.width())
1397                     && (style->borderBottomWidth() < bottomLeft.height())
1398                     && (ls != DOUBLE || style->borderLeftWidth() > 6);
1399                 if (applyBottomInnerClip) {
1400                     graphicsContext->save();
1401                     graphicsContext->addInnerRoundedRectClip(IntRect(topX, bottomY, bottomLeft.width() * 2, bottomLeft.height() * 2),
1402                                                              style->borderLeftWidth());
1403                 }
1404 
1405                 secondAngleStart = 180;
1406                 secondAngleSpan = 45;
1407 
1408                 // Draw bottom left arc
1409                 drawBorderArc(graphicsContext, topX, bottomY, thickness, bottomLeft, secondAngleStart, secondAngleSpan,
1410                               BSLeft, lc, style->color(), ls, false);
1411                 if (applyBottomInnerClip)
1412                     graphicsContext->restore();
1413             }
1414         }
1415     }
1416 
1417     if (renderRight) {
1418         bool ignore_top = (renderRadii && topRight.height() > 0) ||
1419             ((tc == rc) && (tt == rt) &&
1420             (rs >= DOTTED || rs == INSET) &&
1421             (ts == DOTTED || ts == DASHED || ts == SOLID || ts == OUTSET));
1422 
1423         bool ignore_bottom = (renderRadii && bottomRight.height() > 0) ||
1424             ((bc == rc) && (bt == rt) &&
1425             (rs >= DOTTED || rs == INSET) &&
1426             (bs == DOTTED || bs == DASHED || bs == SOLID || bs == INSET));
1427 
1428         int y = ty;
1429         int y2 = ty + h;
1430         if (renderRadii) {
1431             y += topRight.height();
1432             y2 -= bottomRight.height();
1433         }
1434 
1435         drawBorder(graphicsContext, tx + w - style->borderRightWidth(), y, tx + w, y2, BSRight, rc, style->color(), rs,
1436                    ignore_top ? 0 : style->borderTopWidth(), ignore_bottom ? 0 : style->borderBottomWidth());
1437 
1438         if (renderRadii && (!upperRightBorderStylesMatch || !lowerRightBorderStylesMatch)) {
1439             thickness = style->borderRightWidth() * 2;
1440 
1441             if (!upperRightBorderStylesMatch && topRight.width()) {
1442                 int topX = tx + w - topRight.width() * 2;
1443                 int topY = ty;
1444                 bool applyTopInnerClip = (style->borderRightWidth() < topRight.width())
1445                     && (style->borderTopWidth() < topRight.height())
1446                     && (rs != DOUBLE || style->borderRightWidth() > 6);
1447                 if (applyTopInnerClip) {
1448                     graphicsContext->save();
1449                     graphicsContext->addInnerRoundedRectClip(IntRect(topX, topY, topRight.width() * 2, topRight.height() * 2),
1450                                                              style->borderRightWidth());
1451                 }
1452 
1453                 firstAngleStart = 0;
1454                 firstAngleSpan = 45;
1455 
1456                 // Draw top right arc
1457                 drawBorderArc(graphicsContext, topX, topY, thickness, topRight, firstAngleStart, firstAngleSpan,
1458                               BSRight, rc, style->color(), rs, true);
1459                 if (applyTopInnerClip)
1460                     graphicsContext->restore();
1461             }
1462 
1463             if (!lowerRightBorderStylesMatch && bottomRight.width()) {
1464                 int bottomX = tx + w - bottomRight.width() * 2;
1465                 int bottomY = ty + h - bottomRight.height() * 2;
1466                 bool applyBottomInnerClip = (style->borderRightWidth() < bottomRight.width())
1467                     && (style->borderBottomWidth() < bottomRight.height())
1468                     && (rs != DOUBLE || style->borderRightWidth() > 6);
1469                 if (applyBottomInnerClip) {
1470                     graphicsContext->save();
1471                     graphicsContext->addInnerRoundedRectClip(IntRect(bottomX, bottomY, bottomRight.width() * 2, bottomRight.height() * 2),
1472                                                              style->borderRightWidth());
1473                 }
1474 
1475                 secondAngleStart = 315;
1476                 secondAngleSpan = 45;
1477 
1478                 // Draw bottom right arc
1479                 drawBorderArc(graphicsContext, bottomX, bottomY, thickness, bottomRight, secondAngleStart, secondAngleSpan,
1480                               BSRight, rc, style->color(), rs, false);
1481                 if (applyBottomInnerClip)
1482                     graphicsContext->restore();
1483             }
1484         }
1485     }
1486 
1487     if (renderRadii)
1488         graphicsContext->restore();
1489 }
1490 
paintBoxShadow(GraphicsContext * context,int tx,int ty,int w,int h,const RenderStyle * s,bool begin,bool end)1491 void RenderObject::paintBoxShadow(GraphicsContext* context, int tx, int ty, int w, int h, const RenderStyle* s, bool begin, bool end)
1492 {
1493     // FIXME: Deal with border-image.  Would be great to use border-image as a mask.
1494 
1495     IntRect rect(tx, ty, w, h);
1496     bool hasBorderRadius = s->hasBorderRadius();
1497     bool hasOpaqueBackground = s->backgroundColor().isValid() && s->backgroundColor().alpha() == 255;
1498     for (ShadowData* shadow = s->boxShadow(); shadow; shadow = shadow->next) {
1499         context->save();
1500 
1501         IntSize shadowOffset(shadow->x, shadow->y);
1502         int shadowBlur = shadow->blur;
1503         IntRect fillRect(rect);
1504 
1505         if (hasBorderRadius) {
1506             IntRect shadowRect(rect);
1507             shadowRect.inflate(shadowBlur);
1508             shadowRect.move(shadowOffset);
1509             context->clip(shadowRect);
1510 
1511             // Move the fill just outside the clip, adding 1 pixel separation so that the fill does not
1512             // bleed in (due to antialiasing) if the context is transformed.
1513             IntSize extraOffset(w + max(0, shadowOffset.width()) + shadowBlur + 1, 0);
1514             shadowOffset -= extraOffset;
1515             fillRect.move(extraOffset);
1516         }
1517 
1518         context->setShadow(shadowOffset, shadowBlur, shadow->color);
1519         if (hasBorderRadius) {
1520             IntSize topLeft = begin ? s->borderTopLeftRadius() : IntSize();
1521             IntSize topRight = end ? s->borderTopRightRadius() : IntSize();
1522             IntSize bottomLeft = begin ? s->borderBottomLeftRadius() : IntSize();
1523             IntSize bottomRight = end ? s->borderBottomRightRadius() : IntSize();
1524             if (!hasOpaqueBackground)
1525                 context->clipOutRoundedRect(rect, topLeft, topRight, bottomLeft, bottomRight);
1526             context->fillRoundedRect(fillRect, topLeft, topRight, bottomLeft, bottomRight, Color::black);
1527         } else {
1528             if (!hasOpaqueBackground)
1529                 context->clipOut(rect);
1530             context->fillRect(fillRect, Color::black);
1531         }
1532         context->restore();
1533     }
1534 }
1535 
addPDFURLRect(GraphicsContext * context,const IntRect & rect)1536 void RenderObject::addPDFURLRect(GraphicsContext* context, const IntRect& rect)
1537 {
1538     if (rect.isEmpty())
1539         return;
1540     Node* node = element();
1541     if (!node || !node->isLink() || !node->isElementNode())
1542         return;
1543     const AtomicString& href = static_cast<Element*>(node)->getAttribute(hrefAttr);
1544     if (href.isNull())
1545         return;
1546     context->setURLForRect(node->document()->completeURL(href), rect);
1547 }
1548 
paintOutline(GraphicsContext * graphicsContext,int tx,int ty,int w,int h,const RenderStyle * style)1549 void RenderObject::paintOutline(GraphicsContext* graphicsContext, int tx, int ty, int w, int h, const RenderStyle* style)
1550 {
1551     if (!hasOutline())
1552         return;
1553 
1554     int ow = style->outlineWidth();
1555     EBorderStyle os = style->outlineStyle();
1556 
1557     Color oc = style->outlineColor();
1558     if (!oc.isValid())
1559         oc = style->color();
1560 
1561     int offset = style->outlineOffset();
1562 
1563     if (style->outlineStyleIsAuto() || hasOutlineAnnotation()) {
1564         if (!theme()->supportsFocusRing(style)) {
1565             // Only paint the focus ring by hand if the theme isn't able to draw the focus ring.
1566             graphicsContext->initFocusRing(ow, offset);
1567             if (style->outlineStyleIsAuto())
1568                 addFocusRingRects(graphicsContext, tx, ty);
1569             else
1570                 addPDFURLRect(graphicsContext, graphicsContext->focusRingBoundingRect());
1571             graphicsContext->drawFocusRing(oc);
1572             graphicsContext->clearFocusRing();
1573         }
1574     }
1575 
1576     if (style->outlineStyleIsAuto() || style->outlineStyle() == BNONE)
1577         return;
1578 
1579     tx -= offset;
1580     ty -= offset;
1581     w += 2 * offset;
1582     h += 2 * offset;
1583 
1584     if (h < 0 || w < 0)
1585         return;
1586 
1587     drawBorder(graphicsContext, tx - ow, ty - ow, tx, ty + h + ow,
1588                BSLeft, Color(oc), style->color(), os, ow, ow);
1589 
1590     drawBorder(graphicsContext, tx - ow, ty - ow, tx + w + ow, ty,
1591                BSTop, Color(oc), style->color(), os, ow, ow);
1592 
1593     drawBorder(graphicsContext, tx + w, ty - ow, tx + w + ow, ty + h + ow,
1594                BSRight, Color(oc), style->color(), os, ow, ow);
1595 
1596     drawBorder(graphicsContext, tx - ow, ty + h, tx + w + ow, ty + h + ow,
1597                BSBottom, Color(oc), style->color(), os, ow, ow);
1598 }
1599 
addLineBoxRects(Vector<IntRect> &,unsigned,unsigned,bool)1600 void RenderObject::addLineBoxRects(Vector<IntRect>&, unsigned, unsigned, bool)
1601 {
1602 }
1603 
absoluteBoundingBoxRect(bool useTransforms)1604 IntRect RenderObject::absoluteBoundingBoxRect(bool useTransforms)
1605 {
1606     if (useTransforms) {
1607         Vector<FloatQuad> quads;
1608         absoluteQuads(quads);
1609 
1610         size_t n = quads.size();
1611         if (!n)
1612             return IntRect();
1613 
1614         IntRect result = quads[0].enclosingBoundingBox();
1615         for (size_t i = 1; i < n; ++i)
1616             result.unite(quads[i].enclosingBoundingBox());
1617         return result;
1618     }
1619 
1620     FloatPoint absPos = localToAbsolute();
1621     Vector<IntRect> rects;
1622     absoluteRects(rects, absPos.x(), absPos.y());
1623 
1624     size_t n = rects.size();
1625     if (!n)
1626         return IntRect();
1627 
1628     IntRect result = rects[0];
1629     for (size_t i = 1; i < n; ++i)
1630         result.unite(rects[i]);
1631     return result;
1632 }
1633 
addAbsoluteRectForLayer(IntRect & result)1634 void RenderObject::addAbsoluteRectForLayer(IntRect& result)
1635 {
1636     if (hasLayer())
1637         result.unite(absoluteBoundingBoxRect());
1638     for (RenderObject* current = firstChild(); current; current = current->nextSibling())
1639         current->addAbsoluteRectForLayer(result);
1640 }
1641 
paintingRootRect(IntRect & topLevelRect)1642 IntRect RenderObject::paintingRootRect(IntRect& topLevelRect)
1643 {
1644     IntRect result = absoluteBoundingBoxRect();
1645     topLevelRect = result;
1646     for (RenderObject* current = firstChild(); current; current = current->nextSibling())
1647         current->addAbsoluteRectForLayer(result);
1648     return result;
1649 }
1650 
paint(PaintInfo &,int,int)1651 void RenderObject::paint(PaintInfo& /*paintInfo*/, int /*tx*/, int /*ty*/)
1652 {
1653 }
1654 
containerForRepaint() const1655 RenderBox* RenderObject::containerForRepaint() const
1656 {
1657     // For now, all repaints are root-relative.
1658     return 0;
1659 }
1660 
repaint(bool immediate)1661 void RenderObject::repaint(bool immediate)
1662 {
1663     // Can't use view(), since we might be unrooted.
1664     RenderObject* o = this;
1665     while (o->parent())
1666         o = o->parent();
1667     if (!o->isRenderView())
1668         return;
1669 
1670     RenderView* view = static_cast<RenderView*>(o);
1671     if (view->printing())
1672         return; // Don't repaint if we're printing.
1673 
1674     view->repaintViewRectangle(absoluteClippedOverflowRect(), immediate);
1675 }
1676 
repaintRectangle(const IntRect & r,bool immediate)1677 void RenderObject::repaintRectangle(const IntRect& r, bool immediate)
1678 {
1679     // Can't use view(), since we might be unrooted.
1680     RenderObject* o = this;
1681     while (o->parent())
1682         o = o->parent();
1683     if (!o->isRenderView())
1684         return;
1685 
1686     RenderView* view = static_cast<RenderView*>(o);
1687     if (view->printing())
1688         return; // Don't repaint if we're printing.
1689 
1690     IntRect absRect(r);
1691 
1692     // FIXME: layoutDelta needs to be applied in parts before/after transforms and
1693     // repaint containers. https://bugs.webkit.org/show_bug.cgi?id=23308
1694     absRect.move(view->layoutDelta());
1695 
1696     computeAbsoluteRepaintRect(absRect);
1697     view->repaintViewRectangle(absRect, immediate);
1698 }
1699 
repaintAfterLayoutIfNeeded(const IntRect & oldBounds,const IntRect & oldOutlineBox)1700 bool RenderObject::repaintAfterLayoutIfNeeded(const IntRect& oldBounds, const IntRect& oldOutlineBox)
1701 {
1702     RenderView* v = view();
1703     if (v->printing())
1704         return false; // Don't repaint if we're printing.
1705 
1706     IntRect newBounds = absoluteClippedOverflowRect();
1707     IntRect newOutlineBox;
1708 
1709     bool fullRepaint = selfNeedsLayout();
1710     // Presumably a background or a border exists if border-fit:lines was specified.
1711     if (!fullRepaint && style()->borderFit() == BorderFitLines)
1712         fullRepaint = true;
1713     if (!fullRepaint) {
1714         newOutlineBox = absoluteOutlineBounds();
1715         if (newOutlineBox.location() != oldOutlineBox.location() || (mustRepaintBackgroundOrBorder() && (newBounds != oldBounds || newOutlineBox != oldOutlineBox)))
1716             fullRepaint = true;
1717     }
1718     if (fullRepaint) {
1719         v->repaintViewRectangle(oldBounds);
1720         if (newBounds != oldBounds)
1721             v->repaintViewRectangle(newBounds);
1722         return true;
1723     }
1724 
1725     if (newBounds == oldBounds && newOutlineBox == oldOutlineBox)
1726         return false;
1727 
1728     int deltaLeft = newBounds.x() - oldBounds.x();
1729     if (deltaLeft > 0)
1730         v->repaintViewRectangle(IntRect(oldBounds.x(), oldBounds.y(), deltaLeft, oldBounds.height()));
1731     else if (deltaLeft < 0)
1732         v->repaintViewRectangle(IntRect(newBounds.x(), newBounds.y(), -deltaLeft, newBounds.height()));
1733 
1734     int deltaRight = newBounds.right() - oldBounds.right();
1735     if (deltaRight > 0)
1736         v->repaintViewRectangle(IntRect(oldBounds.right(), newBounds.y(), deltaRight, newBounds.height()));
1737     else if (deltaRight < 0)
1738         v->repaintViewRectangle(IntRect(newBounds.right(), oldBounds.y(), -deltaRight, oldBounds.height()));
1739 
1740     int deltaTop = newBounds.y() - oldBounds.y();
1741     if (deltaTop > 0)
1742         v->repaintViewRectangle(IntRect(oldBounds.x(), oldBounds.y(), oldBounds.width(), deltaTop));
1743     else if (deltaTop < 0)
1744         v->repaintViewRectangle(IntRect(newBounds.x(), newBounds.y(), newBounds.width(), -deltaTop));
1745 
1746     int deltaBottom = newBounds.bottom() - oldBounds.bottom();
1747     if (deltaBottom > 0)
1748         v->repaintViewRectangle(IntRect(newBounds.x(), oldBounds.bottom(), newBounds.width(), deltaBottom));
1749     else if (deltaBottom < 0)
1750         v->repaintViewRectangle(IntRect(oldBounds.x(), newBounds.bottom(), oldBounds.width(), -deltaBottom));
1751 
1752     if (newOutlineBox == oldOutlineBox)
1753         return false;
1754 
1755     // We didn't move, but we did change size.  Invalidate the delta, which will consist of possibly
1756     // two rectangles (but typically only one).
1757     RenderFlow* continuation = virtualContinuation();
1758     RenderStyle* outlineStyle = !isInline() && continuation ? continuation->style() : style();
1759     int ow = outlineStyle->outlineSize();
1760     ShadowData* boxShadow = style()->boxShadow();
1761     int width = abs(newOutlineBox.width() - oldOutlineBox.width());
1762     if (width) {
1763         int shadowRight = 0;
1764         for (ShadowData* shadow = boxShadow; shadow; shadow = shadow->next)
1765             shadowRight = max(shadow->x + shadow->blur, shadowRight);
1766 
1767         int borderRight = isBox() ? toRenderBox(this)->borderRight() : 0;
1768         int borderWidth = max(-outlineStyle->outlineOffset(), max(borderRight, max(style()->borderTopRightRadius().width(), style()->borderBottomRightRadius().width()))) + max(ow, shadowRight);
1769         IntRect rightRect(newOutlineBox.x() + min(newOutlineBox.width(), oldOutlineBox.width()) - borderWidth,
1770             newOutlineBox.y(),
1771             width + borderWidth,
1772             max(newOutlineBox.height(), oldOutlineBox.height()));
1773         int right = min(newBounds.right(), oldBounds.right());
1774         if (rightRect.x() < right) {
1775             rightRect.setWidth(min(rightRect.width(), right - rightRect.x()));
1776             v->repaintViewRectangle(rightRect);
1777         }
1778     }
1779     int height = abs(newOutlineBox.height() - oldOutlineBox.height());
1780     if (height) {
1781         int shadowBottom = 0;
1782         for (ShadowData* shadow = boxShadow; shadow; shadow = shadow->next)
1783             shadowBottom = max(shadow->y + shadow->blur, shadowBottom);
1784 
1785         int borderBottom = isBox() ? toRenderBox(this)->borderBottom() : 0;
1786         int borderHeight = max(-outlineStyle->outlineOffset(), max(borderBottom, max(style()->borderBottomLeftRadius().height(), style()->borderBottomRightRadius().height()))) + max(ow, shadowBottom);
1787         IntRect bottomRect(newOutlineBox.x(),
1788             min(newOutlineBox.bottom(), oldOutlineBox.bottom()) - borderHeight,
1789             max(newOutlineBox.width(), oldOutlineBox.width()),
1790             height + borderHeight);
1791         int bottom = min(newBounds.bottom(), oldBounds.bottom());
1792         if (bottomRect.y() < bottom) {
1793             bottomRect.setHeight(min(bottomRect.height(), bottom - bottomRect.y()));
1794             v->repaintViewRectangle(bottomRect);
1795         }
1796     }
1797     return false;
1798 }
1799 
repaintDuringLayoutIfMoved(const IntRect &)1800 void RenderObject::repaintDuringLayoutIfMoved(const IntRect&)
1801 {
1802 }
1803 
repaintOverhangingFloats(bool)1804 void RenderObject::repaintOverhangingFloats(bool)
1805 {
1806 }
1807 
checkForRepaintDuringLayout() const1808 bool RenderObject::checkForRepaintDuringLayout() const
1809 {
1810     // FIXME: <https://bugs.webkit.org/show_bug.cgi?id=20885> It is probably safe to also require
1811     // m_everHadLayout. Currently, only RenderBlock::layoutBlock() adds this condition. See also
1812     // <https://bugs.webkit.org/show_bug.cgi?id=15129>.
1813     return !document()->view()->needsFullRepaint() && !hasLayer();
1814 }
1815 
rectWithOutlineForRepaint(RenderBox * repaintContainer,int outlineWidth)1816 IntRect RenderObject::rectWithOutlineForRepaint(RenderBox* repaintContainer, int outlineWidth)
1817 {
1818     IntRect r(clippedOverflowRectForRepaint(repaintContainer));
1819     r.inflate(outlineWidth);
1820 
1821     if (virtualContinuation() && !isInline())
1822         r.inflateY(toRenderBox(this)->collapsedMarginTop());
1823 
1824     if (isRenderInline()) {
1825         for (RenderObject* curr = firstChild(); curr; curr = curr->nextSibling()) {
1826             if (!curr->isText())
1827                 r.unite(curr->rectWithOutlineForRepaint(repaintContainer, outlineWidth));
1828         }
1829     }
1830 
1831     return r;
1832 }
1833 
clippedOverflowRectForRepaint(RenderBox * repaintContainer)1834 IntRect RenderObject::clippedOverflowRectForRepaint(RenderBox* repaintContainer)
1835 {
1836     if (parent())
1837         return parent()->clippedOverflowRectForRepaint(repaintContainer);
1838     return IntRect();
1839 }
1840 
computeRectForRepaint(IntRect & rect,RenderBox * repaintContainer,bool fixed)1841 void RenderObject::computeRectForRepaint(IntRect& rect, RenderBox* repaintContainer, bool fixed)
1842 {
1843     if (repaintContainer == this)
1844         return;
1845 
1846     if (RenderObject* o = parent()) {
1847         if (o->isBlockFlow()) {
1848             RenderBlock* cb = static_cast<RenderBlock*>(o);
1849             if (cb->hasColumns())
1850                 cb->adjustRectForColumns(rect);
1851         }
1852 
1853         if (o->hasOverflowClip()) {
1854             // o->height() is inaccurate if we're in the middle of a layout of |o|, so use the
1855             // layer's size instead.  Even if the layer's size is wrong, the layer itself will repaint
1856             // anyway if its size does change.
1857             RenderBox* boxParent = toRenderBox(o);
1858 
1859             IntRect boxRect(0, 0, boxParent->layer()->width(), boxParent->layer()->height());
1860             int x = rect.x();
1861             int y = rect.y();
1862             boxParent->layer()->subtractScrolledContentOffset(x, y); // For overflow:auto/scroll/hidden.
1863             IntRect repaintRect(x, y, rect.width(), rect.height());
1864             rect = intersection(repaintRect, boxRect);
1865             if (rect.isEmpty())
1866                 return;
1867         }
1868 
1869         o->computeRectForRepaint(rect, repaintContainer, fixed);
1870     }
1871 }
1872 
dirtyLinesFromChangedChild(RenderObject *)1873 void RenderObject::dirtyLinesFromChangedChild(RenderObject*)
1874 {
1875 }
1876 
1877 #ifndef NDEBUG
1878 
showTreeForThis() const1879 void RenderObject::showTreeForThis() const
1880 {
1881     if (element())
1882         element()->showTreeForThis();
1883 }
1884 
1885 #endif // NDEBUG
1886 
selectionBackgroundColor() const1887 Color RenderObject::selectionBackgroundColor() const
1888 {
1889     Color color;
1890     if (style()->userSelect() != SELECT_NONE) {
1891         RenderStyle* pseudoStyle = getCachedPseudoStyle(RenderStyle::SELECTION);
1892         if (pseudoStyle && pseudoStyle->backgroundColor().isValid())
1893             color = pseudoStyle->backgroundColor().blendWithWhite();
1894         else
1895             color = document()->frame()->selection()->isFocusedAndActive() ?
1896                     theme()->activeSelectionBackgroundColor() :
1897                     theme()->inactiveSelectionBackgroundColor();
1898     }
1899 
1900     return color;
1901 }
1902 
selectionForegroundColor() const1903 Color RenderObject::selectionForegroundColor() const
1904 {
1905     Color color;
1906     if (style()->userSelect() == SELECT_NONE)
1907         return color;
1908 
1909     if (RenderStyle* pseudoStyle = getCachedPseudoStyle(RenderStyle::SELECTION)) {
1910         color = pseudoStyle->textFillColor();
1911         if (!color.isValid())
1912             color = pseudoStyle->color();
1913     } else
1914         color = document()->frame()->selection()->isFocusedAndActive() ?
1915                 theme()->activeSelectionForegroundColor() :
1916                 theme()->inactiveSelectionForegroundColor();
1917 
1918     return color;
1919 }
1920 
draggableNode(bool dhtmlOK,bool uaOK,int x,int y,bool & dhtmlWillDrag) const1921 Node* RenderObject::draggableNode(bool dhtmlOK, bool uaOK, int x, int y, bool& dhtmlWillDrag) const
1922 {
1923     if (!dhtmlOK && !uaOK)
1924         return 0;
1925 
1926     for (const RenderObject* curr = this; curr; curr = curr->parent()) {
1927         Node* elt = curr->element();
1928         if (elt && elt->nodeType() == Node::TEXT_NODE) {
1929             // Since there's no way for the author to address the -webkit-user-drag style for a text node,
1930             // we use our own judgement.
1931             if (uaOK && view()->frameView()->frame()->eventHandler()->shouldDragAutoNode(curr->node(), IntPoint(x, y))) {
1932                 dhtmlWillDrag = false;
1933                 return curr->node();
1934             }
1935             if (elt->canStartSelection())
1936                 // In this case we have a click in the unselected portion of text.  If this text is
1937                 // selectable, we want to start the selection process instead of looking for a parent
1938                 // to try to drag.
1939                 return 0;
1940         } else {
1941             EUserDrag dragMode = curr->style()->userDrag();
1942             if (dhtmlOK && dragMode == DRAG_ELEMENT) {
1943                 dhtmlWillDrag = true;
1944                 return curr->node();
1945             }
1946             if (uaOK && dragMode == DRAG_AUTO
1947                     && view()->frameView()->frame()->eventHandler()->shouldDragAutoNode(curr->node(), IntPoint(x, y))) {
1948                 dhtmlWillDrag = false;
1949                 return curr->node();
1950             }
1951         }
1952     }
1953     return 0;
1954 }
1955 
selectionStartEnd(int & spos,int & epos) const1956 void RenderObject::selectionStartEnd(int& spos, int& epos) const
1957 {
1958     view()->selectionStartEnd(spos, epos);
1959 }
1960 
createAnonymousBlock()1961 RenderBlock* RenderObject::createAnonymousBlock()
1962 {
1963     RefPtr<RenderStyle> newStyle = RenderStyle::create();
1964     newStyle->inheritFrom(m_style.get());
1965     newStyle->setDisplay(BLOCK);
1966 
1967     RenderBlock* newBox = new (renderArena()) RenderBlock(document() /* anonymous box */);
1968     newBox->setStyle(newStyle.release());
1969     return newBox;
1970 }
1971 
handleDynamicFloatPositionChange()1972 void RenderObject::handleDynamicFloatPositionChange()
1973 {
1974     // We have gone from not affecting the inline status of the parent flow to suddenly
1975     // having an impact.  See if there is a mismatch between the parent flow's
1976     // childrenInline() state and our state.
1977     setInline(style()->isDisplayInlineType());
1978     if (isInline() != parent()->childrenInline()) {
1979         if (!isInline()) {
1980             if (parent()->isRenderInline()) {
1981                 // We have to split the parent flow.
1982                 RenderInline* parentInline = static_cast<RenderInline*>(parent());
1983                 RenderBlock* newBox = parentInline->createAnonymousBlock();
1984 
1985                 RenderFlow* oldContinuation = parentInline->continuation();
1986                 parentInline->setContinuation(newBox);
1987 
1988                 RenderObject* beforeChild = nextSibling();
1989                 parent()->removeChildNode(this);
1990                 parentInline->splitFlow(beforeChild, newBox, this, oldContinuation);
1991             } else if (parent()->isRenderBlock()) {
1992                 RenderBlock* o = static_cast<RenderBlock*>(parent());
1993                 o->makeChildrenNonInline();
1994                 if (o->isAnonymousBlock() && o->parent())
1995                     o->parent()->removeLeftoverAnonymousBlock(o);
1996                 // o may be dead here
1997             }
1998         } else {
1999             // An anonymous block must be made to wrap this inline.
2000             RenderBlock* box = createAnonymousBlock();
2001             parent()->insertChildNode(box, this);
2002             box->appendChildNode(parent()->removeChildNode(this));
2003         }
2004     }
2005 }
2006 
setAnimatableStyle(PassRefPtr<RenderStyle> style)2007 void RenderObject::setAnimatableStyle(PassRefPtr<RenderStyle> style)
2008 {
2009     if (!isText() && style)
2010         setStyle(animation()->updateAnimations(this, style.get()));
2011     else
2012         setStyle(style);
2013 }
2014 
setStyle(PassRefPtr<RenderStyle> style)2015 void RenderObject::setStyle(PassRefPtr<RenderStyle> style)
2016 {
2017     if (m_style == style)
2018         return;
2019 
2020     RenderStyle::Diff diff = RenderStyle::Equal;
2021     if (m_style)
2022         diff = m_style->diff(style.get());
2023 
2024     // If we have no layer(), just treat a RepaintLayer hint as a normal Repaint.
2025     if (diff == RenderStyle::RepaintLayer && !hasLayer())
2026         diff = RenderStyle::Repaint;
2027 
2028     styleWillChange(diff, style.get());
2029 
2030     RefPtr<RenderStyle> oldStyle = m_style.release();
2031     m_style = style;
2032 
2033     updateFillImages(oldStyle ? oldStyle->backgroundLayers() : 0, m_style ? m_style->backgroundLayers() : 0);
2034     updateFillImages(oldStyle ? oldStyle->maskLayers() : 0, m_style ? m_style->maskLayers() : 0);
2035 
2036     updateImage(oldStyle ? oldStyle->borderImage().image() : 0, m_style ? m_style->borderImage().image() : 0);
2037     updateImage(oldStyle ? oldStyle->maskBoxImage().image() : 0, m_style ? m_style->maskBoxImage().image() : 0);
2038 
2039     styleDidChange(diff, oldStyle.get());
2040 }
2041 
setStyleInternal(PassRefPtr<RenderStyle> style)2042 void RenderObject::setStyleInternal(PassRefPtr<RenderStyle> style)
2043 {
2044     m_style = style;
2045 }
2046 
styleWillChange(RenderStyle::Diff diff,const RenderStyle * newStyle)2047 void RenderObject::styleWillChange(RenderStyle::Diff diff, const RenderStyle* newStyle)
2048 {
2049     if (m_style) {
2050         // If our z-index changes value or our visibility changes,
2051         // we need to dirty our stacking context's z-order list.
2052         if (newStyle) {
2053 #if ENABLE(DASHBOARD_SUPPORT)
2054             if (m_style->visibility() != newStyle->visibility() ||
2055                     m_style->zIndex() != newStyle->zIndex() ||
2056                     m_style->hasAutoZIndex() != newStyle->hasAutoZIndex())
2057                 document()->setDashboardRegionsDirty(true);
2058 #endif
2059 
2060             // Keep layer hierarchy visibility bits up to date if visibility changes.
2061             if (m_style->visibility() != newStyle->visibility()) {
2062                 if (RenderLayer* l = enclosingLayer()) {
2063                     if (newStyle->visibility() == VISIBLE)
2064                         l->setHasVisibleContent(true);
2065                     else if (l->hasVisibleContent() && (this == l->renderer() || l->renderer()->style()->visibility() != VISIBLE)) {
2066                         l->dirtyVisibleContentStatus();
2067                         if (diff > RenderStyle::RepaintLayer)
2068                             repaint();
2069                     }
2070                 }
2071             }
2072         }
2073 
2074         if (m_parent && (diff == RenderStyle::Repaint || newStyle->outlineSize() < m_style->outlineSize()))
2075             repaint();
2076         if (isFloating() && (m_style->floating() != newStyle->floating()))
2077             // For changes in float styles, we need to conceivably remove ourselves
2078             // from the floating objects list.
2079             removeFromObjectLists();
2080         else if (isPositioned() && (newStyle->position() != AbsolutePosition && newStyle->position() != FixedPosition))
2081             // For changes in positioning styles, we need to conceivably remove ourselves
2082             // from the positioned objects list.
2083             removeFromObjectLists();
2084 
2085         s_affectsParentBlock = isFloatingOrPositioned() &&
2086             (!newStyle->isFloating() && newStyle->position() != AbsolutePosition && newStyle->position() != FixedPosition)
2087             && parent() && (parent()->isBlockFlow() || parent()->isRenderInline());
2088 
2089         // reset style flags
2090         if (diff == RenderStyle::Layout || diff == RenderStyle::LayoutPositionedMovementOnly) {
2091             m_floating = false;
2092             m_positioned = false;
2093             m_relPositioned = false;
2094         }
2095         m_paintBackground = false;
2096         m_hasOverflowClip = false;
2097         m_hasTransform = false;
2098         m_hasReflection = false;
2099     } else
2100         s_affectsParentBlock = false;
2101 
2102     if (view()->frameView()) {
2103         // FIXME: A better solution would be to only invalidate the fixed regions when scrolling.  It's overkill to
2104         // prevent the entire view from blitting on a scroll.
2105         bool newStyleSlowScroll = newStyle && (newStyle->position() == FixedPosition || newStyle->hasFixedBackgroundImage());
2106         bool oldStyleSlowScroll = m_style && (m_style->position() == FixedPosition || m_style->hasFixedBackgroundImage());
2107         if (oldStyleSlowScroll != newStyleSlowScroll) {
2108             if (oldStyleSlowScroll)
2109                 view()->frameView()->removeSlowRepaintObject();
2110             if (newStyleSlowScroll)
2111                 view()->frameView()->addSlowRepaintObject();
2112         }
2113     }
2114 }
2115 
styleDidChange(RenderStyle::Diff diff,const RenderStyle *)2116 void RenderObject::styleDidChange(RenderStyle::Diff diff, const RenderStyle*)
2117 {
2118     setHasBoxDecorations(m_style->hasBorder() || m_style->hasBackground() || m_style->hasAppearance() || m_style->boxShadow());
2119 
2120     if (s_affectsParentBlock)
2121         handleDynamicFloatPositionChange();
2122 
2123     if (!m_parent)
2124         return;
2125 
2126     if (diff == RenderStyle::Layout)
2127         setNeedsLayoutAndPrefWidthsRecalc();
2128     else if (diff == RenderStyle::LayoutPositionedMovementOnly)
2129         setNeedsPositionedMovementLayout();
2130     else if (diff == RenderStyle::RepaintLayer || diff == RenderStyle::Repaint)
2131         // Do a repaint with the new style now, e.g., for example if we go from
2132         // not having an outline to having an outline.
2133         repaint();
2134 }
2135 
updateFillImages(const FillLayer * oldLayers,const FillLayer * newLayers)2136 void RenderObject::updateFillImages(const FillLayer* oldLayers, const FillLayer* newLayers)
2137 {
2138     // FIXME: This will be slow when a large number of images is used.  Fix by using a dict.
2139     for (const FillLayer* currOld = oldLayers; currOld; currOld = currOld->next()) {
2140         if (currOld->image() && (!newLayers || !newLayers->containsImage(currOld->image())))
2141             currOld->image()->removeClient(this);
2142     }
2143     for (const FillLayer* currNew = newLayers; currNew; currNew = currNew->next()) {
2144         if (currNew->image() && (!oldLayers || !oldLayers->containsImage(currNew->image())))
2145             currNew->image()->addClient(this);
2146     }
2147 }
2148 
updateImage(StyleImage * oldImage,StyleImage * newImage)2149 void RenderObject::updateImage(StyleImage* oldImage, StyleImage* newImage)
2150 {
2151     if (oldImage != newImage) {
2152         if (oldImage)
2153             oldImage->removeClient(this);
2154         if (newImage)
2155             newImage->addClient(this);
2156     }
2157 }
2158 
viewRect() const2159 IntRect RenderObject::viewRect() const
2160 {
2161     return view()->viewRect();
2162 }
2163 
localToAbsolute(FloatPoint localPoint,bool fixed,bool useTransforms) const2164 FloatPoint RenderObject::localToAbsolute(FloatPoint localPoint, bool fixed, bool useTransforms) const
2165 {
2166     RenderObject* o = parent();
2167     if (o) {
2168         if (o->hasOverflowClip())
2169             localPoint -= toRenderBox(o)->layer()->scrolledContentOffset();
2170         return o->localToAbsolute(localPoint, fixed, useTransforms);
2171     }
2172 
2173     return FloatPoint();
2174 }
2175 
absoluteToLocal(FloatPoint containerPoint,bool fixed,bool useTransforms) const2176 FloatPoint RenderObject::absoluteToLocal(FloatPoint containerPoint, bool fixed, bool useTransforms) const
2177 {
2178     RenderObject* o = parent();
2179     if (o) {
2180         FloatPoint localPoint = o->absoluteToLocal(containerPoint, fixed, useTransforms);
2181         if (o->hasOverflowClip())
2182             localPoint += toRenderBox(o)->layer()->scrolledContentOffset();
2183         return localPoint;
2184     }
2185     return FloatPoint();
2186 }
2187 
localToContainerQuad(const FloatQuad & localQuad,RenderBox * repaintContainer,bool fixed) const2188 FloatQuad RenderObject::localToContainerQuad(const FloatQuad& localQuad, RenderBox* repaintContainer, bool fixed) const
2189 {
2190     if (repaintContainer == this)
2191         return localQuad;
2192 
2193     RenderObject* o = parent();
2194     if (o) {
2195         FloatQuad quad = localQuad;
2196         if (o->hasOverflowClip())
2197             quad -= toRenderBox(o)->layer()->scrolledContentOffset();
2198         return o->localToContainerQuad(quad, repaintContainer, fixed);
2199     }
2200 
2201     return FloatQuad();
2202 }
2203 
offsetFromContainer(RenderObject * o) const2204 IntSize RenderObject::offsetFromContainer(RenderObject* o) const
2205 {
2206     ASSERT(o == container());
2207 
2208     IntSize offset;
2209     if (o->hasOverflowClip())
2210         offset -= toRenderBox(o)->layer()->scrolledContentOffset();
2211 
2212     return offset;
2213 }
2214 
localCaretRect(InlineBox *,int,int * extraWidthToEndOfLine)2215 IntRect RenderObject::localCaretRect(InlineBox*, int, int* extraWidthToEndOfLine)
2216 {
2217    if (extraWidthToEndOfLine)
2218        *extraWidthToEndOfLine = 0;
2219 
2220     return IntRect();
2221 }
2222 
view() const2223 RenderView* RenderObject::view() const
2224 {
2225     return static_cast<RenderView*>(document()->renderer());
2226 }
2227 
hasOutlineAnnotation() const2228 bool RenderObject::hasOutlineAnnotation() const
2229 {
2230     return element() && element()->isLink() && document()->printing();
2231 }
2232 
container() const2233 RenderObject* RenderObject::container() const
2234 {
2235     // This method is extremely similar to containingBlock(), but with a few notable
2236     // exceptions.
2237     // (1) It can be used on orphaned subtrees, i.e., it can be called safely even when
2238     // the object is not part of the primary document subtree yet.
2239     // (2) For normal flow elements, it just returns the parent.
2240     // (3) For absolute positioned elements, it will return a relative positioned inline.
2241     // containingBlock() simply skips relpositioned inlines and lets an enclosing block handle
2242     // the layout of the positioned object.  This does mean that calcAbsoluteHorizontal and
2243     // calcAbsoluteVertical have to use container().
2244     RenderObject* o = parent();
2245 
2246     if (isText())
2247         return o;
2248 
2249     EPosition pos = m_style->position();
2250     if (pos == FixedPosition) {
2251         // container() can be called on an object that is not in the
2252         // tree yet.  We don't call view() since it will assert if it
2253         // can't get back to the canvas.  Instead we just walk as high up
2254         // as we can.  If we're in the tree, we'll get the root.  If we
2255         // aren't we'll get the root of our little subtree (most likely
2256         // we'll just return 0).
2257         // FIXME: The definition of view() has changed to not crawl up the render tree.  It might
2258         // be safe now to use it.
2259         while (o && o->parent() && !(o->hasTransform() && o->isRenderBlock()))
2260             o = o->parent();
2261     } else if (pos == AbsolutePosition) {
2262         // Same goes here.  We technically just want our containing block, but
2263         // we may not have one if we're part of an uninstalled subtree.  We'll
2264         // climb as high as we can though.
2265         while (o && o->style()->position() == StaticPosition && !o->isRenderView() && !(o->hasTransform() && o->isRenderBlock()))
2266             o = o->parent();
2267     }
2268 
2269     return o;
2270 }
2271 
2272 // This code has been written to anticipate the addition of CSS3-::outside and ::inside generated
2273 // content (and perhaps XBL).  That's why it uses the render tree and not the DOM tree.
hoverAncestor() const2274 RenderObject* RenderObject::hoverAncestor() const
2275 {
2276     return (!isInline() && virtualContinuation()) ? virtualContinuation() : parent();
2277 }
2278 
isSelectionBorder() const2279 bool RenderObject::isSelectionBorder() const
2280 {
2281     SelectionState st = selectionState();
2282     return st == SelectionStart || st == SelectionEnd || st == SelectionBoth;
2283 }
2284 
removeFromObjectLists()2285 void RenderObject::removeFromObjectLists()
2286 {
2287     if (documentBeingDestroyed())
2288         return;
2289 
2290     if (isFloating()) {
2291         RenderBlock* outermostBlock = containingBlock();
2292         for (RenderBlock* p = outermostBlock; p && !p->isRenderView(); p = p->containingBlock()) {
2293             if (p->containsFloat(this))
2294                 outermostBlock = p;
2295         }
2296 
2297         if (outermostBlock)
2298             outermostBlock->markAllDescendantsWithFloatsForLayout(toRenderBox(this), false);
2299     }
2300 
2301     if (isPositioned()) {
2302         RenderObject* p;
2303         for (p = parent(); p; p = p->parent()) {
2304             if (p->isRenderBlock())
2305                 static_cast<RenderBlock*>(p)->removePositionedObject(toRenderBox(this));
2306         }
2307     }
2308 }
2309 
documentBeingDestroyed() const2310 bool RenderObject::documentBeingDestroyed() const
2311 {
2312     return !document()->renderer();
2313 }
2314 
destroy()2315 void RenderObject::destroy()
2316 {
2317     // If this renderer is being autoscrolled, stop the autoscroll timer
2318     if (document()->frame() && document()->frame()->eventHandler()->autoscrollRenderer() == this)
2319         document()->frame()->eventHandler()->stopAutoscrollTimer(true);
2320 
2321     if (m_hasCounterNodeMap)
2322         RenderCounter::destroyCounterNodes(this);
2323 
2324     if (AXObjectCache::accessibilityEnabled()) {
2325         document()->axObjectCache()->childrenChanged(this->parent());
2326         document()->axObjectCache()->remove(this);
2327     }
2328     animation()->cancelAnimations(this);
2329 
2330     // By default no ref-counting. RenderWidget::destroy() doesn't call
2331     // this function because it needs to do ref-counting. If anything
2332     // in this function changes, be sure to fix RenderWidget::destroy() as well.
2333 
2334     remove();
2335 
2336     // FIXME: Would like to do this in RenderBox, but the timing is so complicated that this can't easily
2337     // be moved into RenderBox::destroy.
2338     RenderArena* arena = renderArena();
2339     if (hasLayer())
2340         toRenderBox(this)->layer()->destroy(arena);
2341     arenaDelete(arena, this);
2342 }
2343 
arenaDelete(RenderArena * arena,void * base)2344 void RenderObject::arenaDelete(RenderArena* arena, void* base)
2345 {
2346     if (m_style) {
2347         for (const FillLayer* bgLayer = m_style->backgroundLayers(); bgLayer; bgLayer = bgLayer->next()) {
2348             if (StyleImage* backgroundImage = bgLayer->image())
2349                 backgroundImage->removeClient(this);
2350         }
2351 
2352         for (const FillLayer* maskLayer = m_style->maskLayers(); maskLayer; maskLayer = maskLayer->next()) {
2353             if (StyleImage* maskImage = maskLayer->image())
2354                 maskImage->removeClient(this);
2355         }
2356 
2357         if (StyleImage* borderImage = m_style->borderImage().image())
2358             borderImage->removeClient(this);
2359 
2360         if (StyleImage* maskBoxImage = m_style->maskBoxImage().image())
2361             maskBoxImage->removeClient(this);
2362     }
2363 
2364 #ifndef NDEBUG
2365     void* savedBase = baseOfRenderObjectBeingDeleted;
2366     baseOfRenderObjectBeingDeleted = base;
2367 #endif
2368     delete this;
2369 #ifndef NDEBUG
2370     baseOfRenderObjectBeingDeleted = savedBase;
2371 #endif
2372 
2373     // Recover the size left there for us by operator delete and free the memory.
2374     arena->free(*(size_t*)base, base);
2375 }
2376 
positionForCoordinates(int,int)2377 VisiblePosition RenderObject::positionForCoordinates(int, int)
2378 {
2379     return VisiblePosition(element(), caretMinOffset(), DOWNSTREAM);
2380 }
2381 
positionForPoint(const IntPoint & point)2382 VisiblePosition RenderObject::positionForPoint(const IntPoint& point)
2383 {
2384     return positionForCoordinates(point.x(), point.y());
2385 }
2386 
updateDragState(bool dragOn)2387 void RenderObject::updateDragState(bool dragOn)
2388 {
2389     bool valueChanged = (dragOn != m_isDragging);
2390     m_isDragging = dragOn;
2391     if (valueChanged && style()->affectedByDragRules())
2392         element()->setChanged();
2393     for (RenderObject* curr = firstChild(); curr; curr = curr->nextSibling())
2394         curr->updateDragState(dragOn);
2395     RenderFlow* continuation = virtualContinuation();
2396     if (continuation)
2397         continuation->updateDragState(dragOn);
2398 }
2399 
hitTest(const HitTestRequest & request,HitTestResult & result,const IntPoint & point,int tx,int ty,HitTestFilter hitTestFilter)2400 bool RenderObject::hitTest(const HitTestRequest& request, HitTestResult& result, const IntPoint& point, int tx, int ty, HitTestFilter hitTestFilter)
2401 {
2402     bool inside = false;
2403     if (hitTestFilter != HitTestSelf) {
2404         // First test the foreground layer (lines and inlines).
2405         inside = nodeAtPoint(request, result, point.x(), point.y(), tx, ty, HitTestForeground);
2406 
2407         // Test floats next.
2408         if (!inside)
2409             inside = nodeAtPoint(request, result, point.x(), point.y(), tx, ty, HitTestFloat);
2410 
2411         // Finally test to see if the mouse is in the background (within a child block's background).
2412         if (!inside)
2413             inside = nodeAtPoint(request, result, point.x(), point.y(), tx, ty, HitTestChildBlockBackgrounds);
2414     }
2415 
2416     // See if the mouse is inside us but not any of our descendants
2417     if (hitTestFilter != HitTestDescendants && !inside)
2418         inside = nodeAtPoint(request, result, point.x(), point.y(), tx, ty, HitTestBlockBackground);
2419 
2420     return inside;
2421 }
2422 
updateHitTestResult(HitTestResult & result,const IntPoint & point)2423 void RenderObject::updateHitTestResult(HitTestResult& result, const IntPoint& point)
2424 {
2425     if (result.innerNode())
2426         return;
2427 
2428     Node* node = element();
2429     IntPoint localPoint(point);
2430     if (isRenderView())
2431         node = document()->documentElement();
2432     else if (!isInline() && virtualContinuation())
2433         // We are in the margins of block elements that are part of a continuation.  In
2434         // this case we're actually still inside the enclosing inline element that was
2435         // split.  Go ahead and set our inner node accordingly.
2436         node = virtualContinuation()->element();
2437 
2438     if (node) {
2439         if (node->renderer() && node->renderer()->virtualContinuation() && node->renderer() != this) {
2440             // We're in the continuation of a split inline.  Adjust our local point to be in the coordinate space
2441             // of the principal renderer's containing block.  This will end up being the innerNonSharedNode.
2442             RenderBlock* firstBlock = node->renderer()->containingBlock();
2443 
2444             // Get our containing block.
2445             RenderBox* block = toRenderBox(this);
2446             if (isInline())
2447                 block = containingBlock();
2448 
2449             localPoint.move(block->x() - firstBlock->x(), block->y() - firstBlock->y());
2450         }
2451 
2452         result.setInnerNode(node);
2453         if (!result.innerNonSharedNode())
2454             result.setInnerNonSharedNode(node);
2455         result.setLocalPoint(localPoint);
2456     }
2457 }
2458 
nodeAtPoint(const HitTestRequest &,HitTestResult &,int,int,int,int,HitTestAction)2459 bool RenderObject::nodeAtPoint(const HitTestRequest&, HitTestResult&, int /*x*/, int /*y*/, int /*tx*/, int /*ty*/, HitTestAction)
2460 {
2461     return false;
2462 }
2463 
verticalPositionHint(bool firstLine) const2464 int RenderObject::verticalPositionHint(bool firstLine) const
2465 {
2466     if (firstLine) // We're only really a first-line style if the document actually uses first-line rules.
2467         firstLine = document()->usesFirstLineRules();
2468     int vpos = m_verticalPosition;
2469     if (m_verticalPosition == PositionUndefined || firstLine) {
2470         vpos = getVerticalPosition(firstLine);
2471         if (!firstLine)
2472             m_verticalPosition = vpos;
2473     }
2474 
2475     return vpos;
2476 }
2477 
getVerticalPosition(bool firstLine) const2478 int RenderObject::getVerticalPosition(bool firstLine) const
2479 {
2480     if (!isInline())
2481         return 0;
2482 
2483     // This method determines the vertical position for inline elements.
2484     int vpos = 0;
2485     EVerticalAlign va = style()->verticalAlign();
2486     if (va == TOP)
2487         vpos = PositionTop;
2488     else if (va == BOTTOM)
2489         vpos = PositionBottom;
2490     else {
2491         bool checkParent = parent()->isInline() && !parent()->isInlineBlockOrInlineTable() && parent()->style()->verticalAlign() != TOP && parent()->style()->verticalAlign() != BOTTOM;
2492         vpos = checkParent ? parent()->verticalPositionHint(firstLine) : 0;
2493         // don't allow elements nested inside text-top to have a different valignment.
2494         if (va == BASELINE)
2495             return vpos;
2496 
2497         const Font& f = parent()->style(firstLine)->font();
2498         int fontsize = f.pixelSize();
2499 
2500         if (va == SUB)
2501             vpos += fontsize / 5 + 1;
2502         else if (va == SUPER)
2503             vpos -= fontsize / 3 + 1;
2504         else if (va == TEXT_TOP)
2505             vpos += baselinePosition(firstLine) - f.ascent();
2506         else if (va == MIDDLE)
2507             vpos += -static_cast<int>(f.xHeight() / 2) - lineHeight(firstLine) / 2 + baselinePosition(firstLine);
2508         else if (va == TEXT_BOTTOM) {
2509             vpos += f.descent();
2510             if (!isReplaced())
2511                 vpos -= style(firstLine)->font().descent();
2512         } else if (va == BASELINE_MIDDLE)
2513             vpos += -lineHeight(firstLine) / 2 + baselinePosition(firstLine);
2514         else if (va == LENGTH)
2515             vpos -= style()->verticalAlignLength().calcValue(lineHeight(firstLine));
2516     }
2517 
2518     return vpos;
2519 }
2520 
lineHeight(bool firstLine,bool) const2521 int RenderObject::lineHeight(bool firstLine, bool /*isRootLineBox*/) const
2522 {
2523     RenderStyle* s = style(firstLine);
2524 
2525     Length lh = s->lineHeight();
2526 
2527     // its "unset", choose nice default
2528     if (lh.isNegative())
2529         return s->font().lineSpacing();
2530 
2531     if (lh.isPercent())
2532         return lh.calcMinValue(s->fontSize());
2533 
2534     // its fixed
2535     return lh.value();
2536 }
2537 
baselinePosition(bool firstLine,bool isRootLineBox) const2538 int RenderObject::baselinePosition(bool firstLine, bool isRootLineBox) const
2539 {
2540     const Font& f = style(firstLine)->font();
2541     return f.ascent() + (lineHeight(firstLine, isRootLineBox) - f.height()) / 2;
2542 }
2543 
scheduleRelayout()2544 void RenderObject::scheduleRelayout()
2545 {
2546     if (isRenderView()) {
2547         FrameView* view = static_cast<RenderView*>(this)->frameView();
2548         if (view)
2549             view->scheduleRelayout();
2550     } else if (parent()) {
2551         FrameView* v = view() ? view()->frameView() : 0;
2552         if (v)
2553             v->scheduleRelayoutOfSubtree(this);
2554     }
2555 }
2556 
removeLeftoverAnonymousBlock(RenderBlock *)2557 void RenderObject::removeLeftoverAnonymousBlock(RenderBlock*)
2558 {
2559 }
2560 
createInlineBox(bool,bool unusedIsRootLineBox,bool)2561 InlineBox* RenderObject::createInlineBox(bool, bool unusedIsRootLineBox, bool)
2562 {
2563     ASSERT_UNUSED(unusedIsRootLineBox, !unusedIsRootLineBox);
2564     return new (renderArena()) InlineBox(this);
2565 }
2566 
dirtyLineBoxes(bool,bool)2567 void RenderObject::dirtyLineBoxes(bool, bool)
2568 {
2569 }
2570 
inlineBoxWrapper() const2571 InlineBox* RenderObject::inlineBoxWrapper() const
2572 {
2573     return 0;
2574 }
2575 
setInlineBoxWrapper(InlineBox *)2576 void RenderObject::setInlineBoxWrapper(InlineBox*)
2577 {
2578 }
2579 
deleteLineBoxWrapper()2580 void RenderObject::deleteLineBoxWrapper()
2581 {
2582 }
2583 
firstLineStyle() const2584 RenderStyle* RenderObject::firstLineStyle() const
2585 {
2586     if (!document()->usesFirstLineRules())
2587         return m_style.get();
2588 
2589     RenderStyle* s = m_style.get();
2590     const RenderObject* obj = isText() ? parent() : this;
2591     if (obj->isBlockFlow()) {
2592         RenderBlock* firstLineBlock = obj->firstLineBlock();
2593         if (firstLineBlock)
2594             s = firstLineBlock->getCachedPseudoStyle(RenderStyle::FIRST_LINE, style());
2595     } else if (!obj->isAnonymous() && obj->isRenderInline()) {
2596         RenderStyle* parentStyle = obj->parent()->firstLineStyle();
2597         if (parentStyle != obj->parent()->style()) {
2598             // A first-line style is in effect. We need to cache a first-line style
2599             // for ourselves.
2600             style()->setHasPseudoStyle(RenderStyle::FIRST_LINE_INHERITED);
2601             s = obj->getCachedPseudoStyle(RenderStyle::FIRST_LINE_INHERITED, parentStyle);
2602         }
2603     }
2604     return s;
2605 }
2606 
getCachedPseudoStyle(RenderStyle::PseudoId pseudo,RenderStyle * parentStyle) const2607 RenderStyle* RenderObject::getCachedPseudoStyle(RenderStyle::PseudoId pseudo, RenderStyle* parentStyle) const
2608 {
2609     if (pseudo < RenderStyle::FIRST_INTERNAL_PSEUDOID && !style()->hasPseudoStyle(pseudo))
2610         return 0;
2611 
2612     RenderStyle* cachedStyle = style()->getCachedPseudoStyle(pseudo);
2613     if (cachedStyle)
2614         return cachedStyle;
2615 
2616     RefPtr<RenderStyle> result = getUncachedPseudoStyle(pseudo, parentStyle);
2617     if (result)
2618         return style()->addCachedPseudoStyle(result.release());
2619     return 0;
2620 }
2621 
getUncachedPseudoStyle(RenderStyle::PseudoId pseudo,RenderStyle * parentStyle) const2622 PassRefPtr<RenderStyle> RenderObject::getUncachedPseudoStyle(RenderStyle::PseudoId pseudo, RenderStyle* parentStyle) const
2623 {
2624     if (pseudo < RenderStyle::FIRST_INTERNAL_PSEUDOID && !style()->hasPseudoStyle(pseudo))
2625         return 0;
2626 
2627     if (!parentStyle)
2628         parentStyle = style();
2629 
2630     Node* node = element();
2631     while (node && !node->isElementNode())
2632         node = node->parentNode();
2633     if (!node)
2634         return 0;
2635 
2636     RefPtr<RenderStyle> result;
2637     if (pseudo == RenderStyle::FIRST_LINE_INHERITED) {
2638         result = document()->styleSelector()->styleForElement(static_cast<Element*>(node), parentStyle, false);
2639         result->setStyleType(RenderStyle::FIRST_LINE_INHERITED);
2640     } else
2641         result = document()->styleSelector()->pseudoStyleForElement(pseudo, static_cast<Element*>(node), parentStyle);
2642     return result.release();
2643 }
2644 
decorationColor(RenderStyle * style)2645 static Color decorationColor(RenderStyle* style)
2646 {
2647     Color result;
2648     if (style->textStrokeWidth() > 0) {
2649         // Prefer stroke color if possible but not if it's fully transparent.
2650         result = style->textStrokeColor();
2651         if (!result.isValid())
2652             result = style->color();
2653         if (result.alpha())
2654             return result;
2655     }
2656 
2657     result = style->textFillColor();
2658     if (!result.isValid())
2659         result = style->color();
2660     return result;
2661 }
2662 
getTextDecorationColors(int decorations,Color & underline,Color & overline,Color & linethrough,bool quirksMode)2663 void RenderObject::getTextDecorationColors(int decorations, Color& underline, Color& overline,
2664                                            Color& linethrough, bool quirksMode)
2665 {
2666     RenderObject* curr = this;
2667     do {
2668         int currDecs = curr->style()->textDecoration();
2669         if (currDecs) {
2670             if (currDecs & UNDERLINE) {
2671                 decorations &= ~UNDERLINE;
2672                 underline = decorationColor(curr->style());
2673             }
2674             if (currDecs & OVERLINE) {
2675                 decorations &= ~OVERLINE;
2676                 overline = decorationColor(curr->style());
2677             }
2678             if (currDecs & LINE_THROUGH) {
2679                 decorations &= ~LINE_THROUGH;
2680                 linethrough = decorationColor(curr->style());
2681             }
2682         }
2683         curr = curr->parent();
2684         if (curr && curr->isRenderBlock() && curr->virtualContinuation())
2685             curr = curr->virtualContinuation();
2686     } while (curr && decorations && (!quirksMode || !curr->element() ||
2687                                      (!curr->element()->hasTagName(aTag) && !curr->element()->hasTagName(fontTag))));
2688 
2689     // If we bailed out, use the element we bailed out at (typically a <font> or <a> element).
2690     if (decorations && curr) {
2691         if (decorations & UNDERLINE)
2692             underline = decorationColor(curr->style());
2693         if (decorations & OVERLINE)
2694             overline = decorationColor(curr->style());
2695         if (decorations & LINE_THROUGH)
2696             linethrough = decorationColor(curr->style());
2697     }
2698 }
2699 
updateWidgetPosition()2700 void RenderObject::updateWidgetPosition()
2701 {
2702 }
2703 
2704 #if ENABLE(DASHBOARD_SUPPORT)
addDashboardRegions(Vector<DashboardRegionValue> & regions)2705 void RenderObject::addDashboardRegions(Vector<DashboardRegionValue>& regions)
2706 {
2707     // Convert the style regions to absolute coordinates.
2708     if (style()->visibility() != VISIBLE || !isBox())
2709         return;
2710 
2711     RenderBox* box = toRenderBox(this);
2712 
2713     const Vector<StyleDashboardRegion>& styleRegions = style()->dashboardRegions();
2714     unsigned i, count = styleRegions.size();
2715     for (i = 0; i < count; i++) {
2716         StyleDashboardRegion styleRegion = styleRegions[i];
2717 
2718         int w = box->width();
2719         int h = box->height();
2720 
2721         DashboardRegionValue region;
2722         region.label = styleRegion.label;
2723         region.bounds = IntRect(styleRegion.offset.left().value(),
2724                                 styleRegion.offset.top().value(),
2725                                 w - styleRegion.offset.left().value() - styleRegion.offset.right().value(),
2726                                 h - styleRegion.offset.top().value() - styleRegion.offset.bottom().value());
2727         region.type = styleRegion.type;
2728 
2729         region.clip = region.bounds;
2730         computeAbsoluteRepaintRect(region.clip);
2731         if (region.clip.height() < 0) {
2732             region.clip.setHeight(0);
2733             region.clip.setWidth(0);
2734         }
2735 
2736         FloatPoint absPos = localToAbsolute();
2737         region.bounds.setX(absPos.x() + styleRegion.offset.left().value());
2738         region.bounds.setY(absPos.y() + styleRegion.offset.top().value());
2739 
2740         if (document()->frame()) {
2741             float pageScaleFactor = document()->frame()->page()->chrome()->scaleFactor();
2742             if (pageScaleFactor != 1.0f) {
2743                 region.bounds.scale(pageScaleFactor);
2744                 region.clip.scale(pageScaleFactor);
2745             }
2746         }
2747 
2748         regions.append(region);
2749     }
2750 }
2751 
collectDashboardRegions(Vector<DashboardRegionValue> & regions)2752 void RenderObject::collectDashboardRegions(Vector<DashboardRegionValue>& regions)
2753 {
2754     // RenderTexts don't have their own style, they just use their parent's style,
2755     // so we don't want to include them.
2756     if (isText())
2757         return;
2758 
2759     addDashboardRegions(regions);
2760     for (RenderObject* curr = firstChild(); curr; curr = curr->nextSibling())
2761         curr->collectDashboardRegions(regions);
2762 }
2763 #endif
2764 
avoidsFloats() const2765 bool RenderObject::avoidsFloats() const
2766 {
2767     return isReplaced() || hasOverflowClip() || isHR();
2768 }
2769 
shrinkToAvoidFloats() const2770 bool RenderObject::shrinkToAvoidFloats() const
2771 {
2772     // FIXME: Technically we should be able to shrink replaced elements on a line, but this is difficult to accomplish, since this
2773     // involves doing a relayout during findNextLineBreak and somehow overriding the containingBlockWidth method to return the
2774     // current remaining width on a line.
2775     if (isInline() && !isHTMLMarquee() || !avoidsFloats())
2776         return false;
2777 
2778     // All auto-width objects that avoid floats should always use lineWidth.
2779     return style()->width().isAuto();
2780 }
2781 
willRenderImage(CachedImage *)2782 bool RenderObject::willRenderImage(CachedImage*)
2783 {
2784     // Without visibility we won't render (and therefore don't care about animation).
2785     if (style()->visibility() != VISIBLE)
2786         return false;
2787 
2788     // 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)
2789     // then we don't want to render either.
2790     return !document()->inPageCache() && !document()->view()->isOffscreen();
2791 }
2792 
maximalOutlineSize(PaintPhase p) const2793 int RenderObject::maximalOutlineSize(PaintPhase p) const
2794 {
2795     if (p != PaintPhaseOutline && p != PaintPhaseSelfOutline && p != PaintPhaseChildOutlines)
2796         return 0;
2797     return static_cast<RenderView*>(document()->renderer())->maximalOutlineSize();
2798 }
2799 
caretMinOffset() const2800 int RenderObject::caretMinOffset() const
2801 {
2802     return 0;
2803 }
2804 
caretMaxOffset() const2805 int RenderObject::caretMaxOffset() const
2806 {
2807     if (isReplaced())
2808         return element() ? max(1U, element()->childNodeCount()) : 1;
2809     if (isHR())
2810         return 1;
2811     return 0;
2812 }
2813 
caretMaxRenderedOffset() const2814 unsigned RenderObject::caretMaxRenderedOffset() const
2815 {
2816     return 0;
2817 }
2818 
previousOffset(int current) const2819 int RenderObject::previousOffset(int current) const
2820 {
2821     return current - 1;
2822 }
2823 
nextOffset(int current) const2824 int RenderObject::nextOffset(int current) const
2825 {
2826     return current + 1;
2827 }
2828 
adjustRectForOutlineAndShadow(IntRect & rect) const2829 void RenderObject::adjustRectForOutlineAndShadow(IntRect& rect) const
2830 {
2831     int outlineSize = !isInline() && virtualContinuation() ? virtualContinuation()->style()->outlineSize() : style()->outlineSize();
2832     if (ShadowData* boxShadow = style()->boxShadow()) {
2833         int shadowLeft = 0;
2834         int shadowRight = 0;
2835         int shadowTop = 0;
2836         int shadowBottom = 0;
2837 
2838         do {
2839             shadowLeft = min(boxShadow->x - boxShadow->blur - outlineSize, shadowLeft);
2840             shadowRight = max(boxShadow->x + boxShadow->blur + outlineSize, shadowRight);
2841             shadowTop = min(boxShadow->y - boxShadow->blur - outlineSize, shadowTop);
2842             shadowBottom = max(boxShadow->y + boxShadow->blur + outlineSize, shadowBottom);
2843 
2844             boxShadow = boxShadow->next;
2845         } while (boxShadow);
2846 
2847         rect.move(shadowLeft, shadowTop);
2848         rect.setWidth(rect.width() - shadowLeft + shadowRight);
2849         rect.setHeight(rect.height() - shadowTop + shadowBottom);
2850     } else
2851         rect.inflate(outlineSize);
2852 }
2853 
animation() const2854 AnimationController* RenderObject::animation() const
2855 {
2856     return document()->frame()->animation();
2857 }
2858 
imageChanged(CachedImage * image,const IntRect * rect)2859 void RenderObject::imageChanged(CachedImage* image, const IntRect* rect)
2860 {
2861     imageChanged(static_cast<WrappedImagePtr>(image), rect);
2862 }
2863 
2864 #if ENABLE(SVG)
2865 
relativeBBox(bool) const2866 FloatRect RenderObject::relativeBBox(bool) const
2867 {
2868     return FloatRect();
2869 }
2870 
localTransform() const2871 TransformationMatrix RenderObject::localTransform() const
2872 {
2873     return TransformationMatrix();
2874 }
2875 
absoluteTransform() const2876 TransformationMatrix RenderObject::absoluteTransform() const
2877 {
2878     if (parent())
2879         return localTransform() * parent()->absoluteTransform();
2880     return localTransform();
2881 }
2882 
2883 #endif // ENABLE(SVG)
2884 
2885 } // namespace WebCore
2886 
2887 #ifndef NDEBUG
2888 
showTree(const WebCore::RenderObject * ro)2889 void showTree(const WebCore::RenderObject* ro)
2890 {
2891     if (ro)
2892         ro->showTreeForThis();
2893 }
2894 
2895 #endif
2896