RenderObject.cpp 110 KB
Newer Older
kocienda's avatar
kocienda committed
1
/**
darin's avatar
darin committed
2
 * This file is part of the html renderer for KDE.
kocienda's avatar
kocienda committed
3 4 5 6
 *
 * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
 *           (C) 1999 Antti Koivisto (koivisto@kde.org)
 *           (C) 2000 Dirk Mueller (mueller@kde.org)
bdakin's avatar
bdakin committed
7
 *           (C) 2004 Allan Sandfeld Jensen (kde@carewolf.com)
darin's avatar
darin committed
8
 * Copyright (C) 2004, 2005, 2006 Apple Computer, Inc.
kocienda's avatar
kocienda committed
9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public License
 * along with this library; see the file COPYING.LIB.  If not, write to
 * the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 * Boston, MA 02111-1307, USA.
 *
 */

mjs's avatar
mjs committed
27
#include "config.h"
darin's avatar
darin committed
28
#include "RenderObject.h"
darin's avatar
darin committed
29

weinig's avatar
weinig committed
30
#include "AXObjectCache.h"
ggaren's avatar
 
ggaren committed
31
#include "AffineTransform.h"
eseidel's avatar
eseidel committed
32
#include "CachedImage.h"
ggaren's avatar
ggaren committed
33
#include "Chrome.h"
bdakin's avatar
bdakin committed
34 35
#include "CounterNode.h"
#include "CounterResetNode.h"
bdakin's avatar
bdakin committed
36
#include "Document.h"
37
#include "Element.h"
darin's avatar
darin committed
38
#include "EventHandler.h"
darin's avatar
darin committed
39
#include "EventNames.h"
darin's avatar
darin committed
40
#include "FloatRect.h"
mjs's avatar
mjs committed
41
#include "Frame.h"
darin's avatar
darin committed
42
#include "FrameView.h"
darin's avatar
darin committed
43
#include "GraphicsContext.h"
44
#include "HTMLNames.h"
bdakin's avatar
bdakin committed
45
#include "HTMLOListElement.h"
bdakin's avatar
bdakin committed
46
#include "HitTestRequest.h"
bdakin's avatar
bdakin committed
47
#include "HitTestResult.h"
weinig's avatar
weinig committed
48
#include "KURL.h"
ggaren's avatar
ggaren committed
49
#include "Page.h"
darin's avatar
darin committed
50 51 52
#include "Position.h"
#include "RenderArena.h"
#include "RenderFlexibleBox.h"
bdakin's avatar
bdakin committed
53
#include "RenderImage.h"
darin's avatar
darin committed
54
#include "RenderInline.h"
55 56 57 58 59
#include "RenderListItem.h"
#include "RenderTableCell.h"
#include "RenderTableCol.h"
#include "RenderTableRow.h"
#include "RenderText.h"
darin's avatar
darin committed
60
#include "RenderTheme.h"
weinig's avatar
 
weinig committed
61
#include "RenderView.h"
ggaren's avatar
 
ggaren committed
62
#include "Screen.h"
weinig's avatar
weinig committed
63
#include "TextResourceDecoder.h"
ggaren's avatar
 
ggaren committed
64
#include "TextStream.h"
65
#include "cssstyleselector.h"
66
#include <algorithm>
67

darin's avatar
darin committed
68 69
using namespace std;

darin's avatar
darin committed
70 71 72
namespace WebCore {

using namespace EventNames;
73
using namespace HTMLNames;
kocienda's avatar
kocienda committed
74

darin's avatar
darin committed
75
#ifndef NDEBUG
weinig's avatar
weinig committed
76
static void* baseOfRenderObjectBeingDeleted;
darin's avatar
darin committed
77 78
#endif

bdakin's avatar
bdakin committed
79 80 81 82 83 84 85 86 87
typedef HashMap<String, CounterNode*> CounterNodeMap;
typedef HashMap<const RenderObject*, CounterNodeMap*> RenderObjectsToCounterNodeMaps;

static RenderObjectsToCounterNodeMaps* getRenderObjectsToCounterNodeMaps()
{
    static RenderObjectsToCounterNodeMaps objectsMap;
    return &objectsMap;
}

88 89 90 91 92
void* RenderObject::operator new(size_t sz, RenderArena* renderArena) throw()
{
    return renderArena->allocate(sz);
}

darin's avatar
darin committed
93 94
void RenderObject::operator delete(void* ptr, size_t sz)
{
darin's avatar
darin committed
95
    ASSERT(baseOfRenderObjectBeingDeleted == ptr);
weinig's avatar
weinig committed
96

harrison's avatar
harrison committed
97
    // Stash size where destroy can find it.
darin's avatar
darin committed
98
    *(size_t *)ptr = sz;
99 100
}

weinig's avatar
weinig committed
101
RenderObject* RenderObject::createObject(Node* node, RenderStyle* style)
kocienda's avatar
kocienda committed
102
{
weinig's avatar
weinig committed
103
    RenderObject* o = 0;
ggaren's avatar
ggaren committed
104
    RenderArena* arena = node->document()->renderArena();
weinig's avatar
weinig committed
105 106 107

    if (ContentData* contentData = style->contentData()) {
        RenderImage* contentImage = new (arena) RenderImage(node);
bdakin's avatar
bdakin committed
108 109 110 111 112 113 114 115
        if (contentImage) {
            contentImage->setStyle(style);
            contentImage->setContentObject(contentData->contentObject());
            contentImage->setIsAnonymousImage(true);
        }
        return contentImage;
    }

weinig's avatar
weinig committed
116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160
    switch (style->display()) {
        case NONE:
            break;
        case INLINE:
            o = new (arena) RenderInline(node);
            break;
        case BLOCK:
            o = new (arena) RenderBlock(node);
            break;
        case INLINE_BLOCK:
            o = new (arena) RenderBlock(node);
            break;
        case LIST_ITEM:
            o = new (arena) RenderListItem(node);
            break;
        case RUN_IN:
        case COMPACT:
            o = new (arena) RenderBlock(node);
            break;
        case TABLE:
        case INLINE_TABLE:
            o = new (arena) RenderTable(node);
            break;
        case TABLE_ROW_GROUP:
        case TABLE_HEADER_GROUP:
        case TABLE_FOOTER_GROUP:
            o = new (arena) RenderTableSection(node);
            break;
        case TABLE_ROW:
            o = new (arena) RenderTableRow(node);
            break;
        case TABLE_COLUMN_GROUP:
        case TABLE_COLUMN:
            o = new (arena) RenderTableCol(node);
            break;
        case TABLE_CELL:
            o = new (arena) RenderTableCell(node);
            break;
        case TABLE_CAPTION:
            o = new (arena) RenderBlock(node);
            break;
        case BOX:
        case INLINE_BOX:
            o = new (arena) RenderFlexibleBox(node);
            break;
kocienda's avatar
kocienda committed
161 162 163 164
    }
    return o;
}

mjs's avatar
mjs committed
165
#ifndef NDEBUG
weinig's avatar
weinig committed
166 167 168
struct RenderObjectCounter {
    static int count;
    ~RenderObjectCounter() { if (count != 0) fprintf(stderr, "LEAK: %d RenderObject\n", count); }
mjs's avatar
mjs committed
169 170 171
};
int RenderObjectCounter::count;
static RenderObjectCounter renderObjectCounter;
darin's avatar
darin committed
172
#endif
mjs's avatar
mjs committed
173

174
RenderObject::RenderObject(Node* node)
weinig's avatar
weinig committed
175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197
    : CachedResourceClient()
    , m_style(0)
    , m_node(node)
    , m_parent(0)
    , m_previous(0)
    , m_next(0)
    , m_verticalPosition(PositionUndefined)
    , m_needsLayout(false)
    , m_normalChildNeedsLayout(false)
    , m_posChildNeedsLayout(false)
    , m_minMaxKnown(false)
    , m_floating(false)
    , m_positioned(false)
    , m_relPositioned(false)
    , m_paintBackground(false)
    , m_isAnonymous(node == node->document())
    , m_recalcMinMax(false)
    , m_isText(false)
    , m_inline(true)
    , m_replaced(false)
    , m_isDragging(false)
    , m_hasOverflowClip(false)
    , m_hasCounterNodeMap(false)
198
{
199
#ifndef NDEBUG
mjs's avatar
mjs committed
200 201
    ++RenderObjectCounter::count;
#endif
kocienda's avatar
kocienda committed
202 203 204 205
}

RenderObject::~RenderObject()
{
206
#ifndef NDEBUG
mjs's avatar
mjs committed
207 208
    --RenderObjectCounter::count;
#endif
kocienda's avatar
kocienda committed
209 210
}

weinig's avatar
weinig committed
211
bool RenderObject::isDescendantOf(const RenderObject* obj) const
212
{
weinig's avatar
weinig committed
213
    for (const RenderObject* r = this; r; r = r->m_parent) {
214 215
        if (r == obj)
            return true;
weinig's avatar
weinig committed
216
    }
217 218 219
    return false;
}

220 221
bool RenderObject::isRoot() const
{
weinig's avatar
weinig committed
222
    return element() && element()->renderer() == this && element()->document()->documentElement() == element();
223 224
}

225 226
bool RenderObject::isBody() const
{
227
    return element() && element()->renderer() == this && element()->hasTagName(bodyTag);
228 229
}

230 231
bool RenderObject::isHR() const
{
232
    return element() && element()->hasTagName(hrTag);
233 234
}

235 236
bool RenderObject::isHTMLMarquee() const
{
237
    return element() && element()->renderer() == this && element()->hasTagName(marqueeTag);
238 239
}

240 241 242 243
bool RenderObject::canHaveChildren() const
{
    return false;
}
kocienda's avatar
kocienda committed
244

245 246 247 248 249 250 251 252 253 254
RenderFlow* RenderObject::continuation() const
{
    return 0;
}

bool RenderObject::isInlineContinuation() const
{
    return false;
}

weinig's avatar
weinig committed
255
void RenderObject::addChild(RenderObject*, RenderObject*)
kocienda's avatar
kocienda committed
256
{
weinig's avatar
weinig committed
257
    ASSERT_NOT_REACHED();
kocienda's avatar
kocienda committed
258 259
}

weinig's avatar
weinig committed
260
RenderObject* RenderObject::removeChildNode(RenderObject*)
kocienda's avatar
kocienda committed
261
{
weinig's avatar
weinig committed
262
    ASSERT_NOT_REACHED();
kocienda's avatar
kocienda committed
263 264 265
    return 0;
}

weinig's avatar
weinig committed
266
void RenderObject::removeChild(RenderObject*)
kocienda's avatar
kocienda committed
267
{
weinig's avatar
weinig committed
268
    ASSERT_NOT_REACHED();
kocienda's avatar
kocienda committed
269 270 271 272
}

void RenderObject::appendChildNode(RenderObject*)
{
weinig's avatar
weinig committed
273
    ASSERT_NOT_REACHED();
kocienda's avatar
kocienda committed
274 275 276 277
}

void RenderObject::insertChildNode(RenderObject*, RenderObject*)
{
weinig's avatar
weinig committed
278
    ASSERT_NOT_REACHED();
kocienda's avatar
kocienda committed
279 280
}

weinig's avatar
weinig committed
281
RenderObject* RenderObject::nextInPreOrder() const
kocienda's avatar
kocienda committed
282
{
justing's avatar
justing committed
283 284
    if (RenderObject* o = firstChild())
        return o;
weinig's avatar
weinig committed
285

justing's avatar
justing committed
286 287
    return nextInPreOrderAfterChildren();
}
harrison's avatar
harrison committed
288

justing's avatar
justing committed
289 290 291 292 293 294 295 296 297 298
RenderObject* RenderObject::nextInPreOrderAfterChildren() const
{
    RenderObject* o;
    if (!(o = nextSibling())) {
        o = parent();
        while (o && !o->nextSibling())
            o = o->parent();
        if (o)
            o = o->nextSibling();
    }
weinig's avatar
weinig committed
299

justing's avatar
justing committed
300
    return o;
kocienda's avatar
kocienda committed
301 302
}

weinig's avatar
weinig committed
303
RenderObject* RenderObject::previousInPreOrder() const
kocienda's avatar
kocienda committed
304
{
justing's avatar
justing committed
305 306 307 308
    if (RenderObject* o = previousSibling()) {
        while (o->lastChild())
            o = o->lastChild();
        return o;
kocienda's avatar
kocienda committed
309
    }
harrison's avatar
harrison committed
310 311

    return parent();
kocienda's avatar
kocienda committed
312 313
}

justing's avatar
justing committed
314 315 316 317 318 319 320 321
RenderObject* RenderObject::childAt(unsigned index) const
{
    RenderObject* child = firstChild();
    for (unsigned i = 0; child && i < index; i++)
        child = child->nextSibling();
    return child;
}

kocienda's avatar
kocienda committed
322 323
bool RenderObject::isEditable() const
{
weinig's avatar
weinig committed
324 325 326
    RenderText* textRenderer = 0;
    if (isText())
        textRenderer = static_cast<RenderText*>(const_cast<RenderObject*>(this));
kocienda's avatar
kocienda committed
327

weinig's avatar
weinig committed
328
    return style()->visibility() == VISIBLE &&
kocienda's avatar
kocienda committed
329
        element() && element()->isContentEditable() &&
weinig's avatar
weinig committed
330 331 332
        ((isBlockFlow() && !firstChild()) ||
        isReplaced() ||
        isBR() ||
kocienda's avatar
kocienda committed
333
        (textRenderer && textRenderer->firstTextBox()));
kocienda's avatar
kocienda committed
334 335
}

weinig's avatar
weinig committed
336
RenderObject* RenderObject::nextEditable() const
kocienda's avatar
kocienda committed
337
{
weinig's avatar
weinig committed
338 339
    RenderObject* r = const_cast<RenderObject*>(this);
    RenderObject* n = firstChild();
kocienda's avatar
kocienda committed
340
    if (n) {
weinig's avatar
weinig committed
341 342 343
        while (n) {
            r = n;
            n = n->firstChild();
kocienda's avatar
kocienda committed
344 345 346
        }
        if (r->isEditable())
            return r;
weinig's avatar
weinig committed
347
        else
kocienda's avatar
kocienda committed
348 349 350 351 352
            return r->nextEditable();
    }
    n = r->nextSibling();
    if (n) {
        r = n;
weinig's avatar
weinig committed
353 354 355
        while (n) {
            r = n;
            n = n->firstChild();
kocienda's avatar
kocienda committed
356 357 358
        }
        if (r->isEditable())
            return r;
weinig's avatar
weinig committed
359
        else
kocienda's avatar
kocienda committed
360 361 362 363 364 365 366 367 368
            return r->nextEditable();
    }
    n = r->parent();
    while (n) {
        r = n;
        n = r->nextSibling();
        if (n) {
            r = n;
            n = r->firstChild();
weinig's avatar
weinig committed
369 370 371
            while (n) {
                r = n;
                n = n->firstChild();
kocienda's avatar
kocienda committed
372 373 374
            }
            if (r->isEditable())
                return r;
weinig's avatar
weinig committed
375
            else
kocienda's avatar
kocienda committed
376 377 378 379
                return r->nextEditable();
        }
        n = r->parent();
    }
weinig's avatar
weinig committed
380

kocienda's avatar
kocienda committed
381 382 383
    return 0;
}

weinig's avatar
weinig committed
384
RenderObject* RenderObject::previousEditable() const
kocienda's avatar
kocienda committed
385
{
weinig's avatar
weinig committed
386 387
    RenderObject* r = const_cast<RenderObject*>(this);
    RenderObject* n = firstChild();
kocienda's avatar
kocienda committed
388
    if (n) {
weinig's avatar
weinig committed
389 390 391
        while (n) {
            r = n;
            n = n->lastChild();
kocienda's avatar
kocienda committed
392 393 394
        }
        if (r->isEditable())
            return r;
weinig's avatar
weinig committed
395
        else
kocienda's avatar
kocienda committed
396 397 398 399 400
            return r->previousEditable();
    }
    n = r->previousSibling();
    if (n) {
        r = n;
weinig's avatar
weinig committed
401 402 403
        while (n) {
            r = n;
            n = n->lastChild();
kocienda's avatar
kocienda committed
404 405 406
        }
        if (r->isEditable())
            return r;
weinig's avatar
weinig committed
407
        else
kocienda's avatar
kocienda committed
408
            return r->previousEditable();
weinig's avatar
weinig committed
409
    }
kocienda's avatar
kocienda committed
410 411 412 413 414 415 416
    n = r->parent();
    while (n) {
        r = n;
        n = r->previousSibling();
        if (n) {
            r = n;
            n = r->lastChild();
weinig's avatar
weinig committed
417 418 419
            while (n) {
                r = n;
                n = n->lastChild();
kocienda's avatar
kocienda committed
420 421 422
            }
            if (r->isEditable())
                return r;
weinig's avatar
weinig committed
423
            else
kocienda's avatar
kocienda committed
424 425 426 427
                return r->previousEditable();
        }
        n = r->parent();
    }
weinig's avatar
weinig committed
428

kocienda's avatar
kocienda committed
429
    return 0;
weinig's avatar
weinig committed
430
}
kocienda's avatar
kocienda committed
431

weinig's avatar
weinig committed
432
RenderObject* RenderObject::firstLeafChild() const
kocienda's avatar
kocienda committed
433
{
weinig's avatar
weinig committed
434
    RenderObject* r = firstChild();
kocienda's avatar
kocienda committed
435
    while (r) {
weinig's avatar
weinig committed
436
        RenderObject* n = 0;
kocienda's avatar
kocienda committed
437 438 439 440 441 442 443 444
        n = r->firstChild();
        if (!n)
            break;
        r = n;
    }
    return r;
}

weinig's avatar
weinig committed
445
RenderObject* RenderObject::lastLeafChild() const
kocienda's avatar
kocienda committed
446
{
weinig's avatar
weinig committed
447
    RenderObject* r = lastChild();
kocienda's avatar
kocienda committed
448
    while (r) {
weinig's avatar
weinig committed
449
        RenderObject* n = 0;
kocienda's avatar
kocienda committed
450 451 452 453 454 455 456 457
        n = r->lastChild();
        if (!n)
            break;
        r = n;
    }
    return r;
}

458 459
static void addLayers(RenderObject* obj, RenderLayer* parentLayer, RenderObject*& newObject,
                      RenderLayer*& beforeChild)
460
{
461 462 463 464 465 466 467 468 469
    if (obj->layer()) {
        if (!beforeChild && newObject) {
            // We need to figure out the layer that follows newObject.  We only do
            // this the first time we find a child layer, and then we update the
            // pointer values for newObject and beforeChild used by everyone else.
            beforeChild = newObject->parent()->findNextLayer(parentLayer, newObject);
            newObject = 0;
        }
        parentLayer->addChild(obj->layer(), beforeChild);
470 471 472
        return;
    }

473 474 475 476 477 478 479 480
    for (RenderObject* curr = obj->firstChild(); curr; curr = curr->nextSibling())
        addLayers(curr, parentLayer, newObject, beforeChild);
}

void RenderObject::addLayers(RenderLayer* parentLayer, RenderObject* newObject)
{
    if (!parentLayer)
        return;
weinig's avatar
weinig committed
481

482 483
    RenderObject* object = newObject;
    RenderLayer* beforeChild = 0;
darin's avatar
darin committed
484
    WebCore::addLayers(this, parentLayer, object, beforeChild);
485 486 487 488 489 490
}

void RenderObject::removeLayers(RenderLayer* parentLayer)
{
    if (!parentLayer)
        return;
weinig's avatar
weinig committed
491

492 493 494 495 496 497 498 499 500
    if (layer()) {
        parentLayer->removeChild(layer());
        return;
    }

    for (RenderObject* curr = firstChild(); curr; curr = curr->nextSibling())
        curr->removeLayers(parentLayer);
}

501 502 503 504
void RenderObject::moveLayers(RenderLayer* oldParent, RenderLayer* newParent)
{
    if (!newParent)
        return;
weinig's avatar
weinig committed
505

506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522
    if (layer()) {
        if (oldParent)
            oldParent->removeChild(layer());
        newParent->addChild(layer());
        return;
    }

    for (RenderObject* curr = firstChild(); curr; curr = curr->nextSibling())
        curr->moveLayers(oldParent, newParent);
}

RenderLayer* RenderObject::findNextLayer(RenderLayer* parentLayer, RenderObject* startPoint,
                                         bool checkParent)
{
    // Error check the parent layer passed in.  If it's null, we can't find anything.
    if (!parentLayer)
        return 0;
weinig's avatar
weinig committed
523

adele's avatar
adele committed
524 525 526 527
    // Step 1: If our layer is a child of the desired parent, then return our layer.
    RenderLayer* ourLayer = layer();
    if (ourLayer && ourLayer->parent() == parentLayer)
        return ourLayer;
weinig's avatar
weinig committed
528

adele's avatar
adele committed
529 530 531 532 533 534 535
    // Step 2: If we don't have a layer, or our layer is the desired parent, then descend
    // into our siblings trying to find the next layer whose parent is the desired parent.
    if (!ourLayer || ourLayer == parentLayer) {
        for (RenderObject* curr = startPoint ? startPoint->nextSibling() : firstChild();
             curr; curr = curr->nextSibling()) {
            RenderLayer* nextLayer = curr->findNextLayer(parentLayer, 0, false);
            if (nextLayer)
536 537 538
                return nextLayer;
        }
    }
weinig's avatar
weinig committed
539

adele's avatar
adele committed
540
    // Step 3: If our layer is the desired parent layer, then we're finished.  We didn't
541 542 543
    // find anything.
    if (parentLayer == ourLayer)
        return 0;
weinig's avatar
weinig committed
544

545 546 547 548
    // Step 4: If |checkParent| is set, climb up to our parent and check its siblings that
    // follow us to see if we can locate a layer.
    if (checkParent && parent())
        return parent()->findNextLayer(parentLayer, this, true);
weinig's avatar
weinig committed
549

550 551
    return 0;
}
weinig's avatar
weinig committed
552

553
RenderLayer* RenderObject::enclosingLayer() const
554
{
555
    const RenderObject* curr = this;
556
    while (curr) {
weinig's avatar
weinig committed
557
        RenderLayer* layer = curr->layer();
darin's avatar
darin committed
558 559
        if (layer)
            return layer;
560 561 562 563 564
        curr = curr->parent();
    }
    return 0;
}

565 566
bool RenderObject::requiresLayer()
{
567
    return isRoot() || isPositioned() || isRelPositioned() || isTransparent() || hasOverflowClip();
568 569
}

570 571 572 573 574 575
RenderBlock* RenderObject::firstLineBlock() const
{
    return 0;
}

void RenderObject::updateFirstLetter()
weinig's avatar
weinig committed
576 577
{
}
578

579 580
int RenderObject::offsetLeft() const
{
darin's avatar
darin committed
581 582 583
    RenderObject* offsetPar = offsetParent();
    if (!offsetPar)
        return 0;
584 585
    int x = xPos();
    if (!isPositioned()) {
antti's avatar
antti committed
586
        if (isRelPositioned())
darin's avatar
darin committed
587
            x += static_cast<const RenderBox*>(this)->relativePositionOffsetX();
588 589 590 591 592 593 594 595 596 597 598
        RenderObject* curr = parent();
        while (curr && curr != offsetPar) {
            x += curr->xPos();
            curr = curr->parent();
        }
    }
    return x;
}

int RenderObject::offsetTop() const
{
darin's avatar
darin committed
599 600 601
    RenderObject* offsetPar = offsetParent();
    if (!offsetPar)
        return 0;
602 603
    int y = yPos();
    if (!isPositioned()) {
antti's avatar
antti committed
604
        if (isRelPositioned())
darin's avatar
darin committed
605
            y += static_cast<const RenderBox*>(this)->relativePositionOffsetY();
606 607
        RenderObject* curr = parent();
        while (curr && curr != offsetPar) {
adele's avatar
adele committed
608 609
            if (!curr->isTableRow())
                y += curr->yPos();
610 611 612 613 614
            curr = curr->parent();
        }
    }
    return y;
}
weinig's avatar
weinig committed
615

616 617
RenderObject* RenderObject::offsetParent() const
{
618
    // FIXME: It feels like this function could almost be written using containing blocks.
darin's avatar
darin committed
619 620
    if (isBody())
        return 0;
weinig's avatar
weinig committed
621

622
    bool skipTables = isPositioned() || isRelPositioned();
623
    RenderObject* curr = parent();
weinig's avatar
weinig committed
624 625
    while (curr && (!curr->element() ||
                    (!curr->isPositioned() && !curr->isRelPositioned() &&
626 627
                        !(!style()->htmlHacks() && skipTables ? curr->isRoot() : curr->isBody())))) {
        if (!skipTables && curr->element() && (curr->isTableCell() || curr->isTable()))
628
            break;
629
        curr = curr->parent();
630
    }
631 632
    return curr;
}
633

634 635
// More IE extensions.  clientWidth and clientHeight represent the interior of an object
// excluding border and scrollbar.
636
int RenderObject::clientWidth() const
637 638
{
    return width() - borderLeft() - borderRight() -
639
        (includeVerticalScrollbarSize() ? layer()->verticalScrollbarWidth() : 0);
640 641
}

642
int RenderObject::clientHeight() const
643 644
{
    return height() - borderTop() - borderBottom() -
645
      (includeHorizontalScrollbarSize() ? layer()->horizontalScrollbarHeight() : 0);
646 647 648 649
}

// scrollWidth/scrollHeight will be the same as clientWidth/clientHeight unless the
// object has overflow:hidden/scroll/auto specified and also has overflow.
650
int RenderObject::scrollWidth() const
651
{
652
    return hasOverflowClip() ? layer()->scrollWidth() : overflowWidth();
653 654
}

655
int RenderObject::scrollHeight() const
656
{
657
    return hasOverflowClip() ? layer()->scrollHeight() : overflowHeight();
658 659
}

660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681
int RenderObject::scrollLeft() const
{
    return hasOverflowClip() ? layer()->scrollXOffset() : 0;
}

int RenderObject::scrollTop() const
{
    return hasOverflowClip() ? layer()->scrollYOffset() : 0;
}

void RenderObject::setScrollLeft(int newLeft)
{
    if (hasOverflowClip())
        layer()->scrollToXOffset(newLeft);
}

void RenderObject::setScrollTop(int newTop)
{
    if (hasOverflowClip())
        layer()->scrollToYOffset(newTop);
}

darin's avatar
darin committed
682
bool RenderObject::scroll(ScrollDirection direction, ScrollGranularity granularity, float multiplier)
cblu's avatar
cblu committed
683
{
weinig's avatar
weinig committed
684
    RenderLayer* l = layer();
685
    if (l && l->scroll(direction, granularity, multiplier))
cblu's avatar
cblu committed
686
        return true;
weinig's avatar
weinig committed
687
    RenderBlock* b = containingBlock();
688
    if (b && !b->isRenderView())
cblu's avatar
cblu committed
689 690 691 692
        return b->scroll(direction, granularity, multiplier);
    return false;
}

adele's avatar
adele committed
693 694
bool RenderObject::shouldAutoscroll() const
{
adele's avatar
adele committed
695
    return ((isRoot()) || (hasOverflowClip() && (scrollsOverflow() || (node() && node()->isContentEditable()))));
adele's avatar
adele committed
696 697 698 699 700 701 702 703
}

void RenderObject::autoscroll()
{
    if (RenderLayer* l = layer())
        l->autoscroll();
}

704
bool RenderObject::hasStaticX() const
705
{
weinig's avatar
weinig committed
706
    return (style()->left().isAuto() && style()->right().isAuto()) || style()->left().isStatic() || style()->right().isStatic();
707 708
}

709
bool RenderObject::hasStaticY() const
710
{
711
    return (style()->top().isAuto() && style()->bottom().isAuto()) || style()->top().isStatic();
712 713
}

714
void RenderObject::markAllDescendantsWithFloatsForLayout(RenderObject*)
715 716 717
{
}

weinig's avatar
weinig committed
718
void RenderObject::setNeedsLayout(bool b, bool markParents)
719
{
720
    bool alreadyNeededLayout = m_needsLayout;
721
    m_needsLayout = b;
722
    if (b) {
723
        if (!alreadyNeededLayout && markParents)
724
            markContainingBlocksForLayout();
weinig's avatar
weinig committed
725
    } else {
726 727 728 729
        m_posChildNeedsLayout = false;
        m_normalChildNeedsLayout = false;
    }
}
hyatt's avatar
hyatt committed
730

731
void RenderObject::setChildNeedsLayout(bool b, bool markParents)
732 733 734 735
{
    bool alreadyNeededLayout = m_normalChildNeedsLayout;
    m_normalChildNeedsLayout = b;
    if (b) {
736
        if (!alreadyNeededLayout && markParents)
737
            markContainingBlocksForLayout();
weinig's avatar
weinig committed
738
    } else {
739 740 741 742
        m_posChildNeedsLayout = false;
        m_normalChildNeedsLayout = false;
    }
}
743

adele's avatar
adele committed
744
void RenderObject::markContainingBlocksForLayout(bool scheduleRelayout)
745
{
weinig's avatar
weinig committed
746 747
    RenderObject* o = container();
    RenderObject* last = this;
748 749

    while (o) {
mjs's avatar
mjs committed
750
        if (!last->isText() && (last->style()->position() == FixedPosition || last->style()->position() == AbsolutePosition)) {
751 752 753
            if (o->m_posChildNeedsLayout)
                return;
            o->m_posChildNeedsLayout = true;
adele's avatar
adele committed
754
        } else {
755 756 757 758 759 760
            if (o->m_normalChildNeedsLayout)
                return;
            o->m_normalChildNeedsLayout = true;
        }

        last = o;
adele's avatar
adele committed
761
        if (scheduleRelayout && (last->isTextField() || last->isTextArea()))
adele's avatar
adele committed
762
            break;
763
        o = o->container();
764
    }
765

adele's avatar
adele committed
766 767
    if (scheduleRelayout)
        last->scheduleRelayout();
768
}
769

770
RenderBlock* RenderObject::containingBlock() const
kocienda's avatar
kocienda committed
771
{
weinig's avatar
weinig committed
772 773
    if (isTableCell())
        return static_cast<const RenderTableCell*>(this)->table();
774
    if (isRenderView())
775
        return (RenderBlock*)this;
776

weinig's avatar
weinig committed
777
    RenderObject* o = parent();
mjs's avatar
mjs committed
778
    if (!isText() && m_style->position() == FixedPosition) {
779
        while ( o && !o->isRenderView() )
kocienda's avatar
kocienda committed
780
            o = o->parent();
weinig's avatar
weinig committed
781
    } else if (!isText() && m_style->position() == AbsolutePosition) {
782
        while (o && (o->style()->position() == StaticPosition || (o->isInline() && !o->isReplaced())) && !o->isRenderView()) {
783 784 785 786 787
            // For relpositioned inlines, we return the nearest enclosing block.  We don't try
            // to return the inline itself.  This allows us to avoid having a positioned objects
            // list in all RenderInlines and lets us return a strongly-typed RenderBlock* result
            // from this method.  The container() method can actually be used to obtain the
            // inline directly.
mjs's avatar
mjs committed
788
            if (o->style()->position() == RelativePosition && o->isInline() && !o->isReplaced())
789
                return o->containingBlock();
kocienda's avatar
kocienda committed
790
            o = o->parent();
791
        }
kocienda's avatar
kocienda committed
792
    } else {
793
        while (o && ((o->isInline() && !o->isReplaced()) || o->isTableRow() || o->isTableSection()
eseidel's avatar
eseidel committed
794
                     || o->isTableCol() || o->isFrameSet()
ddkilzer's avatar
ddkilzer committed
795
#ifdef SVG_SUPPORT
eseidel's avatar
eseidel committed
796 797 798
                     || o->isKCanvasContainer()
#endif
                     ))
kocienda's avatar
kocienda committed
799 800
            o = o->parent();
    }
801

802
    if (!o || !o->isRenderBlock())
803
        return 0; // Probably doesn't happen any more, but leave just in case. -dwh
weinig's avatar
weinig committed
804

805
    return static_cast<RenderBlock*>(o);
kocienda's avatar
kocienda committed
806 807
}

808
int RenderObject::containingBlockWidth() const
kocienda's avatar
kocienda committed
809
{
weinig's avatar
weinig committed
810
    // FIXME ?
kocienda's avatar
kocienda committed
811 812 813 814 815
    return containingBlock()->contentWidth();
}

int RenderObject::containingBlockHeight() const
{
weinig's avatar
weinig committed
816
    // FIXME ?
kocienda's avatar
kocienda committed
817 818 819
    return containingBlock()->contentHeight();
}

820 821 822 823 824
bool RenderObject::mustRepaintBackgroundOrBorder() const
{
    // If we don't have a background/border, then nothing to do.
    if (!shouldPaintBackgroundOrBorder())
        return false;
weinig's avatar
weinig committed
825

826 827
    // Ok, let's check the background first.
    const BackgroundLayer* bgLayer = style()->backgroundLayers();
weinig's avatar
weinig committed
828 829

    // Nobody will use multiple background layers without wanting fancy positioning.
830
    if (bgLayer->next())
weinig's avatar
weinig committed
831 832
        return true;

833 834
    // Make sure we have a valid background image.
    CachedImage* bg = bgLayer->backgroundImage();
835
    bool shouldPaintBackgroundImage = bg && bg->canRender();
weinig's avatar
weinig committed
836

837
    // These are always percents or auto.
weinig's avatar
weinig committed
838 839 840 841 842 843
    if (shouldPaintBackgroundImage &&
            (bgLayer->backgroundXPosition().value() != 0 || bgLayer->backgroundYPosition().value() != 0 ||
             bgLayer->backgroundSize().width.isPercent() || bgLayer->backgroundSize().height.isPercent()))
        // The background image will shift unpredictably if the size changes.
        return true;

844 845 846 847
    // Background is ok.  Let's check border.
    if (style()->hasBorder()) {
        // Border images are not ok.
        CachedImage* borderImage = style()->borderImage().image();
848
        bool shouldPaintBorderImage = borderImage && borderImage->canRender();
weinig's avatar
weinig committed
849 850

        // If the image hasn't loaded, we're still using the normal border style.
851
        if (shouldPaintBorderImage && borderImage->isLoaded())
weinig's avatar
weinig committed
852
            return true;
853 854 855 856 857
    }

    return false;
}

weinig's avatar
weinig committed
858 859 860
void RenderObject::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)
bdakin's avatar
bdakin committed
861
{
weinig's avatar
weinig committed
862
    if ((style == DOUBLE && thickness / 2 < 3) || ((style == RIDGE || style == GROOVE) && thickness / 2 < 2))
bdakin's avatar
bdakin committed
863
        style = SOLID;
weinig's avatar
weinig committed
864

adele's avatar
adele committed
865 866 867 868 869 870
    if (!c.isValid()) {
        if (style == INSET || style == OUTSET || style == RIDGE || style == GROOVE)
            c.setRGB(238, 238, 238);
        else
            c = textColor;
    }
weinig's avatar
weinig committed
871

bdakin's avatar
bdakin committed
872 873 874 875 876
    switch (style) {
        case BNONE:
        case BHIDDEN:
            return;
        case DOTTED:
weinig's avatar
weinig committed
877
            graphicsContext->setPen(Pen(c, thickness == 1 ? 0 : static_cast<int>(thickness), Pen::DotLine));
bdakin's avatar
bdakin committed
878
        case DASHED:
weinig's avatar
weinig committed
879 880 881 882 883 884
            if (style == DASHED)
                graphicsContext->setPen(Pen(c, thickness == 1 ? 0 : static_cast<int>(thickness), Pen::DashLine));

            if (thickness > 0)
                graphicsContext->drawArc(IntRect(x, y, radius.width() * 2, radius.height() * 2), thickness, angleStart, angleSpan);

bdakin's avatar
bdakin committed
885 886
            break;
        case DOUBLE: {
weinig's avatar
weinig committed
887 888 889 890 891
            float third = thickness / 3.0f;
            float innerThird = (thickness + 1.0f) / 6.0f;
            int shiftForInner = static_cast<int>(innerThird * 2.5f);
            graphicsContext->setPen(Pen::NoPen);

bdakin's avatar
bdakin committed
892 893 894 895 896 897 898 899 900 901
            int outerY = y;
            int outerHeight = radius.height() * 2;
            int innerX = x + shiftForInner;
            int innerY = y + shiftForInner;
            int innerWidth = (radius.width() - shiftForInner) * 2;
            int innerHeight = (radius.height() - shiftForInner) * 2;
            if (innerThird > 1 && (s == BSTop || (firstCorner && (s == BSLeft || s == BSRight)))) {
                outerHeight += 2;
                innerHeight += 2;
            }
weinig's avatar
weinig committed
902 903 904 905

            graphicsContext->drawArc(IntRect(x, outerY, radius.width() * 2, outerHeight), third, angleStart, angleSpan);
            graphicsContext->drawArc(IntRect(innerX, innerY, innerWidth, innerHeight), (innerThird > 2) ? innerThird - 1 : innerThird,
                                     angleStart, angleSpan);
bdakin's avatar
bdakin committed
906 907 908 909 910
            break;
        }
        case GROOVE:
        case RIDGE: {
            Color c2;
weinig's avatar
weinig committed
911 912
            if ((style == RIDGE && (s == BSTop || s == BSLeft)) ||
                    (style == GROOVE && (s == BSBottom || s == BSRight)))
bdakin's avatar
bdakin committed
913 914 915 916 917 918
                c2 = c.dark();
            else {
                c2 = c;
                c = c.dark();
            }

weinig's avatar
weinig committed
919 920 921 922 923 924 925 926 927 928
            graphicsContext->setPen(Pen::NoPen);
            graphicsContext->setFillColor(c);
            graphicsContext->drawArc(IntRect(x, y, radius.width() * 2, radius.height() * 2), thickness, angleStart, angleSpan);

            float halfThickness = (thickness + 1.0f) / 4.0f;
            int shiftForInner = static_cast<int>(halfThickness * 1.5f);
            graphicsContext->setFillColor(c2);
            graphicsContext->drawArc(IntRect(x + shiftForInner, y + shiftForInner, (radius.width() - shiftForInner) * 2,
                                     (radius.height() - shiftForInner) * 2), (halfThickness > 2) ? halfThickness - 1 : halfThickness,
                                     angleStart, angleSpan);
bdakin's avatar
bdakin committed
929 930 931
            break;
        }
        case INSET: