Warning, file /frameworks/khtml/src/rendering/render_object.cpp was not indexed or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).

0001 /**
0002  * This file is part of the html renderer for KDE.
0003  *
0004  * Copyright (C) 1999-2003 Lars Knoll (knoll@kde.org)
0005  *           (C) 1999 Antti Koivisto (koivisto@kde.org)
0006  *           (C) 2000-2003 Dirk Mueller (mueller@kde.org)
0007  *           (C) 2004-2008 Apple Computer, Inc.
0008  *           (C) 2006 Germain Garand <germain@ebooksfrance.org>
0009  *           (C) 2008-2009 Fredrik Höglund <fredrik@kde.org>
0010  *
0011  * This library is free software; you can redistribute it and/or
0012  * modify it under the terms of the GNU Library General Public
0013  * License as published by the Free Software Foundation; either
0014  * version 2 of the License, or (at your option) any later version.
0015  *
0016  * This library is distributed in the hope that it will be useful,
0017  * but WITHOUT ANY WARRANTY; without even the implied warranty of
0018  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
0019  * Library General Public License for more details.
0020  *
0021  * You should have received a copy of the GNU Library General Public License
0022  * along with this library; see the file COPYING.LIB.  If not, write to
0023  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
0024  * Boston, MA 02110-1301, USA.
0025  *
0026  */
0027 
0028 #include "rendering/render_object.h"
0029 #include "rendering/render_table.h"
0030 #include "rendering/render_list.h"
0031 #include "rendering/render_canvas.h"
0032 #include "rendering/render_block.h"
0033 #include "rendering/render_arena.h"
0034 #include "rendering/render_layer.h"
0035 #include "rendering/render_line.h"
0036 #include "rendering/render_inline.h"
0037 #include "rendering/render_text.h"
0038 #include "rendering/render_replaced.h"
0039 #include "rendering/render_generated.h"
0040 #include "rendering/counter_tree.h"
0041 
0042 #include "xml/dom_elementimpl.h"
0043 #include "dom/dom_doc.h"
0044 #include "misc/loader.h"
0045 #include "misc/borderarcstroker.h"
0046 
0047 #include "khtml_debug.h"
0048 #include <QPainter>
0049 #include "khtmlview.h"
0050 #include <khtml_part.h>
0051 #include <QPaintEngine>
0052 
0053 using namespace DOM;
0054 using namespace khtml;
0055 
0056 #define RED_LUMINOSITY        30
0057 #define GREEN_LUMINOSITY      59
0058 #define BLUE_LUMINOSITY       11
0059 #define INTENSITY_FACTOR      25
0060 #define LIGHT_FACTOR          0
0061 #define LUMINOSITY_FACTOR     75
0062 
0063 #define MAX_COLOR             255
0064 #define COLOR_DARK_THRESHOLD  51
0065 #define COLOR_LIGHT_THRESHOLD 204
0066 
0067 #define COLOR_LITE_BS_FACTOR 45
0068 #define COLOR_LITE_TS_FACTOR 70
0069 
0070 #define COLOR_DARK_BS_FACTOR 30
0071 #define COLOR_DARK_TS_FACTOR 50
0072 
0073 #define LIGHT_GRAY qRgb(192, 192, 192)
0074 #define DARK_GRAY  qRgb(96, 96, 96)
0075 
0076 #ifndef NDEBUG
0077 static void *baseOfRenderObjectBeingDeleted;
0078 #endif
0079 
0080 QCache<quint64, QPixmap> *RenderObject::s_dashedLineCache = nullptr;
0081 
0082 void RenderObject::cleanup()
0083 {
0084     delete s_dashedLineCache;
0085     s_dashedLineCache = nullptr;
0086 }
0087 
0088 //#define MASK_DEBUG
0089 
0090 void *RenderObject::operator new(size_t sz, RenderArena *renderArena) throw()
0091 {
0092     return renderArena->allocate(sz);
0093 }
0094 
0095 void RenderObject::operator delete(void *ptr, size_t sz)
0096 {
0097     assert(baseOfRenderObjectBeingDeleted == ptr);
0098 
0099 #ifdef KHTML_USE_ARENA_ALLOCATOR
0100     // Stash size where detach can find it.
0101     *(size_t *)ptr = sz;
0102 #endif
0103 }
0104 
0105 RenderObject *RenderObject::createObject(DOM::NodeImpl *node,  RenderStyle *style)
0106 {
0107     RenderObject *o = nullptr;
0108     khtml::RenderArena *arena = node->document()->renderArena();
0109     switch (style->display()) {
0110     case NONE:
0111         break;
0112     case INLINE:
0113         o = new(arena) RenderInline(node);
0114         break;
0115     case BLOCK:
0116         o = new(arena) RenderBlock(node);
0117         break;
0118     case INLINE_BLOCK:
0119         o = new(arena) RenderBlock(node);
0120         break;
0121     case LIST_ITEM:
0122         o = new(arena) RenderListItem(node);
0123         break;
0124     case RUN_IN:
0125     case COMPACT:
0126         o = new(arena) RenderBlock(node);
0127         break;
0128     case TABLE:
0129     case INLINE_TABLE:
0130         style->setFlowAroundFloats(true);
0131         o = new(arena) RenderTable(node);
0132         break;
0133     case TABLE_ROW_GROUP:
0134     case TABLE_HEADER_GROUP:
0135     case TABLE_FOOTER_GROUP:
0136         o = new(arena) RenderTableSection(node);
0137         break;
0138     case TABLE_ROW:
0139         o = new(arena) RenderTableRow(node);
0140         break;
0141     case TABLE_COLUMN_GROUP:
0142     case TABLE_COLUMN:
0143         o = new(arena) RenderTableCol(node);
0144         break;
0145     case TABLE_CELL:
0146         o = new(arena) RenderTableCell(node);
0147         break;
0148     case TABLE_CAPTION:
0149         o = new(arena) RenderBlock(node);
0150         break;
0151     }
0152     return o;
0153 }
0154 
0155 RenderObject::RenderObject(DOM::NodeImpl *node)
0156     : CachedObjectClient(),
0157       m_style(nullptr),
0158       m_node(node),
0159       m_parent(nullptr),
0160       m_previous(nullptr),
0161       m_next(nullptr),
0162       m_verticalPosition(PositionUndefined),
0163       m_needsLayout(false),
0164       m_normalChildNeedsLayout(false),
0165       m_markedForRepaint(false),
0166       m_posChildNeedsLayout(false),
0167       m_minMaxKnown(false),
0168       m_floating(false),
0169 
0170       m_positioned(false),
0171       m_relPositioned(false),
0172       m_paintBackground(false),
0173 
0174       m_isAnonymous(node->isDocumentNode()),
0175       m_recalcMinMax(false),
0176       m_isText(false),
0177       m_inline(true),
0178       m_attached(false),
0179 
0180       m_replaced(false),
0181       m_mouseInside(false),
0182       m_hasFirstLine(false),
0183       m_isSelectionBorder(false),
0184       m_isRoot(false),
0185       m_afterPageBreak(false),
0186       m_needsPageClear(false),
0187       m_containsPageBreak(false),
0188       m_hasOverflowClip(false),
0189       m_inPosObjectList(false),
0190       m_doNotDelete(false)
0191 {
0192     assert(node);
0193     if (node->document()->documentElement() == node) {
0194         setIsRoot(true);
0195     }
0196 }
0197 
0198 RenderObject::~RenderObject()
0199 {
0200     const BackgroundLayer *bgLayer = m_style->backgroundLayers();
0201     while (bgLayer) {
0202         if (bgLayer->backgroundImage()) {
0203             bgLayer->backgroundImage()->deref(this);
0204         }
0205         bgLayer = bgLayer->next();
0206     }
0207 
0208     m_style->deref();
0209 }
0210 
0211 RenderObject *RenderObject::objectBelow() const
0212 {
0213     RenderObject *obj = firstChild();
0214     if (!obj) {
0215         obj = nextSibling();
0216         if (!obj) {
0217             obj = parent();
0218             while (obj && !obj->nextSibling()) {
0219                 obj = obj->parent();
0220             }
0221             if (obj) {
0222                 obj = obj->nextSibling();
0223             }
0224         }
0225     }
0226     return obj;
0227 }
0228 
0229 RenderObject *RenderObject::objectAbove() const
0230 {
0231     RenderObject *obj = previousSibling();
0232     if (!obj) {
0233         return parent();
0234     }
0235 
0236     RenderObject *last = obj->lastChild();
0237     while (last) {
0238         obj = last;
0239         last = last->lastChild();
0240     }
0241     return obj;
0242 }
0243 /*
0244 bool RenderObject::isRoot() const
0245 {
0246     return !isAnonymous() &&
0247         element()->document()->documentElement() == element();
0248 }*/
0249 
0250 bool RenderObject::isHR() const
0251 {
0252     return element() && element()->id() == ID_HR;
0253 }
0254 bool RenderObject::isWordBreak() const
0255 {
0256     return element() && element()->id() == ID_WBR;
0257 }
0258 bool RenderObject::isHTMLMarquee() const
0259 {
0260     return element() && element()->renderer() == this && element()->id() == ID_MARQUEE;
0261 }
0262 
0263 void RenderObject::addChild(RenderObject *, RenderObject *)
0264 {
0265     KHTMLAssert(0);
0266 }
0267 
0268 RenderObject *RenderObject::removeChildNode(RenderObject *)
0269 {
0270     KHTMLAssert(0);
0271     return nullptr;
0272 }
0273 
0274 void RenderObject::removeChild(RenderObject *)
0275 {
0276     KHTMLAssert(0);
0277 }
0278 
0279 void RenderObject::appendChildNode(RenderObject *)
0280 {
0281     KHTMLAssert(0);
0282 }
0283 
0284 void RenderObject::insertChildNode(RenderObject *, RenderObject *)
0285 {
0286     KHTMLAssert(0);
0287 }
0288 
0289 RenderObject *RenderObject::nextRenderer() const
0290 {
0291     if (firstChild()) {
0292         return firstChild();
0293     } else if (nextSibling()) {
0294         return nextSibling();
0295     } else {
0296         const RenderObject *r = this;
0297         while (r && !r->nextSibling()) {
0298             r = r->parent();
0299         }
0300         if (r) {
0301             return r->nextSibling();
0302         }
0303     }
0304     return nullptr;
0305 }
0306 
0307 RenderObject *RenderObject::previousRenderer() const
0308 {
0309     if (previousSibling()) {
0310         RenderObject *r = previousSibling();
0311         while (r->lastChild()) {
0312             r = r->lastChild();
0313         }
0314         return r;
0315     } else if (parent()) {
0316         return parent();
0317     } else {
0318         return nullptr;
0319     }
0320 }
0321 
0322 bool RenderObject::isEditable() const
0323 {
0324     RenderText *textRenderer = nullptr;
0325     if (isText()) {
0326         textRenderer = static_cast<RenderText *>(const_cast<RenderObject *>(this));
0327     }
0328 
0329     return style()->visibility() == VISIBLE &&
0330            element() && element()->isContentEditable() &&
0331            ((isBlockFlow() && !firstChild()) ||
0332             isReplaced() ||
0333             isBR() ||
0334             (textRenderer && textRenderer->firstTextBox()));
0335 }
0336 
0337 RenderObject *RenderObject::nextEditable() const
0338 {
0339     RenderObject *r = const_cast<RenderObject *>(this);
0340     RenderObject *n = firstChild();
0341     if (n) {
0342         while (n) {
0343             r = n;
0344             n = n->firstChild();
0345         }
0346         if (r->isEditable()) {
0347             return r;
0348         } else {
0349             return r->nextEditable();
0350         }
0351     }
0352     n = r->nextSibling();
0353     if (n) {
0354         r = n;
0355         while (n) {
0356             r = n;
0357             n = n->firstChild();
0358         }
0359         if (r->isEditable()) {
0360             return r;
0361         } else {
0362             return r->nextEditable();
0363         }
0364     }
0365     n = r->parent();
0366     while (n) {
0367         r = n;
0368         n = r->nextSibling();
0369         if (n) {
0370             r = n;
0371             n = r->firstChild();
0372             while (n) {
0373                 r = n;
0374                 n = n->firstChild();
0375             }
0376             if (r->isEditable()) {
0377                 return r;
0378             } else {
0379                 return r->nextEditable();
0380             }
0381         }
0382         n = r->parent();
0383     }
0384     return nullptr;
0385 }
0386 
0387 RenderObject *RenderObject::previousEditable() const
0388 {
0389     RenderObject *r = const_cast<RenderObject *>(this);
0390     RenderObject *n = firstChild();
0391     if (n) {
0392         while (n) {
0393             r = n;
0394             n = n->lastChild();
0395         }
0396         if (r->isEditable()) {
0397             return r;
0398         } else {
0399             return r->previousEditable();
0400         }
0401     }
0402     n = r->previousSibling();
0403     if (n) {
0404         r = n;
0405         while (n) {
0406             r = n;
0407             n = n->lastChild();
0408         }
0409         if (r->isEditable()) {
0410             return r;
0411         } else {
0412             return r->previousEditable();
0413         }
0414     }
0415     n = r->parent();
0416     while (n) {
0417         r = n;
0418         n = r->previousSibling();
0419         if (n) {
0420             r = n;
0421             n = r->lastChild();
0422             while (n) {
0423                 r = n;
0424                 n = n->lastChild();
0425             }
0426             if (r->isEditable()) {
0427                 return r;
0428             } else {
0429                 return r->previousEditable();
0430             }
0431         }
0432         n = r->parent();
0433     }
0434     return nullptr;
0435 }
0436 
0437 RenderObject *RenderObject::firstLeafChild() const
0438 {
0439     RenderObject *r = firstChild();
0440     while (r) {
0441         RenderObject *n = nullptr;
0442         n = r->firstChild();
0443         if (!n) {
0444             break;
0445         }
0446         r = n;
0447     }
0448     return r;
0449 }
0450 
0451 RenderObject *RenderObject::lastLeafChild() const
0452 {
0453     RenderObject *r = lastChild();
0454     while (r) {
0455         RenderObject *n = nullptr;
0456         n = r->lastChild();
0457         if (!n) {
0458             break;
0459         }
0460         r = n;
0461     }
0462     return r;
0463 }
0464 
0465 static void addLayers(RenderObject *obj, RenderLayer *parentLayer, RenderObject *&newObject,
0466                       RenderLayer *&beforeChild)
0467 {
0468     if (obj->layer()) {
0469         if (!beforeChild && newObject) {
0470             // We need to figure out the layer that follows newObject.  We only do
0471             // this the first time we find a child layer, and then we update the
0472             // pointer values for newObject and beforeChild used by everyone else.
0473             beforeChild = newObject->parent()->findNextLayer(parentLayer, newObject);
0474             newObject = nullptr;
0475         }
0476         parentLayer->addChild(obj->layer(), beforeChild);
0477         return;
0478     }
0479 
0480     for (RenderObject *curr = obj->firstChild(); curr; curr = curr->nextSibling()) {
0481         addLayers(curr, parentLayer, newObject, beforeChild);
0482     }
0483 }
0484 
0485 void RenderObject::addLayers(RenderLayer *parentLayer, RenderObject *newObject)
0486 {
0487     if (!parentLayer) {
0488         return;
0489     }
0490 
0491     RenderObject *object = newObject;
0492     RenderLayer *beforeChild = nullptr;
0493     ::addLayers(this, parentLayer, object, beforeChild);
0494 }
0495 
0496 void RenderObject::removeLayers(RenderLayer *parentLayer)
0497 {
0498     if (!parentLayer) {
0499         return;
0500     }
0501 
0502     if (layer()) {
0503         parentLayer->removeChild(layer());
0504         return;
0505     }
0506 
0507     for (RenderObject *curr = firstChild(); curr; curr = curr->nextSibling()) {
0508         curr->removeLayers(parentLayer);
0509     }
0510 }
0511 
0512 void RenderObject::moveLayers(RenderLayer *oldParent, RenderLayer *newParent)
0513 {
0514     if (!newParent) {
0515         return;
0516     }
0517 
0518     if (layer()) {
0519         if (oldParent) {
0520             oldParent->removeChild(layer());
0521         }
0522         newParent->addChild(layer());
0523         return;
0524     }
0525 
0526     for (RenderObject *curr = firstChild(); curr; curr = curr->nextSibling()) {
0527         curr->moveLayers(oldParent, newParent);
0528     }
0529 }
0530 
0531 RenderLayer *RenderObject::findNextLayer(RenderLayer *parentLayer, RenderObject *startPoint,
0532         bool checkParent)
0533 {
0534     // Error check the parent layer passed in.  If it's null, we can't find anything.
0535     if (!parentLayer) {
0536         return nullptr;
0537     }
0538 
0539     // Step 1: If our layer is a child of the desired parent, then return our layer.
0540     RenderLayer *ourLayer = layer();
0541     if (ourLayer && ourLayer->parent() == parentLayer) {
0542         return ourLayer;
0543     }
0544 
0545     // Step 2: If we don't have a layer, or our layer is the desired parent, then descend
0546     // into our siblings trying to find the next layer whose parent is the desired parent.
0547     if (!ourLayer || ourLayer == parentLayer) {
0548         for (RenderObject *curr = startPoint ? startPoint->nextSibling() : firstChild();
0549                 curr; curr = curr->nextSibling()) {
0550             RenderLayer *nextLayer = curr->findNextLayer(parentLayer, nullptr, false);
0551             if (nextLayer) {
0552                 return nextLayer;
0553             }
0554         }
0555     }
0556 
0557     // Step 3: If our layer is the desired parent layer, then we're finished.  We didn't
0558     // find anything.
0559     if (parentLayer == ourLayer) {
0560         return nullptr;
0561     }
0562 
0563     // Step 4: If |checkParent| is set, climb up to our parent and check its siblings that
0564     // follow us to see if we can locate a layer.
0565     if (checkParent && parent()) {
0566         return parent()->findNextLayer(parentLayer, this, true);
0567     }
0568 
0569     return nullptr;
0570 }
0571 
0572 RenderLayer *RenderObject::enclosingLayer() const
0573 {
0574     const RenderObject *curr = this;
0575     while (curr) {
0576         RenderLayer *layer = curr->layer();
0577         if (layer) {
0578             return layer;
0579         }
0580         curr = curr->parent();
0581     }
0582     return nullptr;
0583 }
0584 
0585 RenderLayer *RenderObject::enclosingStackingContext() const
0586 {
0587     RenderLayer *l = enclosingLayer();
0588     while (l && !l->isStackingContext()) {
0589         l = l->parent();
0590     }
0591     return l;
0592 }
0593 
0594 QRectF RenderObject::clientRectToViewport(const QRectF &rect)
0595 {
0596     int offsetX = document()->part()->view()->contentsX();
0597     int offsetY = document()->part()->view()->contentsY();
0598 
0599     QRectF newRect(rect.x() - offsetX, rect.y() - offsetY,
0600                    rect.width(), rect.height());
0601 
0602     return newRect;
0603 }
0604 
0605 QList<QRectF> RenderObject::getClientRects()
0606 {
0607     QList<QRectF> ret;
0608 
0609     int x = 0;
0610     int y = 0;
0611     absolutePosition(x, y);
0612 
0613     QRectF rect(x, y, width(), height());
0614     ret.append(clientRectToViewport(rect));
0615 
0616     return ret;
0617 }
0618 
0619 int RenderObject::offsetLeft() const
0620 {
0621     if (isBody()) {
0622         return 0;
0623     }
0624 
0625     int x, dummy;
0626     RenderObject *offsetPar = offsetParent();
0627     if (!offsetPar || offsetPar->isBody()) {
0628         if (style()->position() == PFIXED) {
0629             return xPos();
0630         } else {
0631             absolutePosition(x, dummy);
0632             return x;
0633         }
0634     }
0635 
0636     x = xPos() - offsetPar->borderLeft();
0637     if (isPositioned()) {
0638         return x;
0639     }
0640 
0641     if (isRelPositioned()) {
0642         int y = 0;
0643         static_cast<const RenderBox *>(this)->relativePositionOffset(x, y);
0644     }
0645 
0646     for (RenderObject *curr = parent();
0647             curr && curr != offsetPar;
0648             curr = curr->parent()) {
0649         x += curr->xPos();
0650     }
0651 
0652     return x;
0653 }
0654 
0655 int RenderObject::offsetTop() const
0656 {
0657     if (isBody()) {
0658         return 0;
0659     }
0660 
0661     int y, dummy;
0662     RenderObject *offsetPar = offsetParent();
0663     if (!offsetPar || offsetPar->isBody()) {
0664         if (style()->position() == PFIXED) {
0665             return yPos();
0666         } else {
0667             absolutePosition(dummy, y);
0668             return y;
0669         }
0670     }
0671 
0672     y = yPos() - offsetPar->borderTop();
0673     if (isPositioned()) {
0674         return y;
0675     }
0676 
0677     if (isRelPositioned()) {
0678         int x = 0;
0679         static_cast<const RenderBox *>(this)->relativePositionOffset(x, y);
0680     }
0681     for (RenderObject *curr = parent();
0682             curr && curr != offsetPar;
0683             curr = curr->parent()) {
0684         y += curr->yPos();
0685     }
0686 
0687     return y;
0688 }
0689 
0690 RenderObject *RenderObject::offsetParent() const
0691 {
0692     if (isBody() || style()->position() == PFIXED) {
0693         return nullptr;
0694     }
0695 
0696     // can't really use containing blocks here (#113280)
0697     bool skipTables = isPositioned() || isRelPositioned();
0698     bool strict = !style()->htmlHacks();
0699     RenderObject *curr = parent();
0700     while (curr && (!curr->element() ||
0701                     (!curr->isPositioned() && !curr->isRelPositioned() &&
0702                      !(strict && skipTables ? curr->isRoot() : curr->isBody())))) {
0703         if (!skipTables && curr->element() && (curr->isTableCell() || curr->isTable())) {
0704             break;
0705         }
0706         curr = curr->parent();
0707     }
0708     return curr;
0709 }
0710 
0711 // IE extensions.
0712 // clientWidth and clientHeight represent the interior of an object
0713 short RenderObject::clientWidth() const
0714 {
0715     return width() - borderLeft() - borderRight() -
0716            (layer() ? layer()->verticalScrollbarWidth() : 0);
0717 }
0718 
0719 int RenderObject::clientLeft() const
0720 {
0721     return borderLeft();
0722 }
0723 
0724 int RenderObject::clientTop() const
0725 {
0726     return borderTop();
0727 }
0728 
0729 int RenderObject::clientHeight() const
0730 {
0731     return height() - borderTop() - borderBottom() -
0732            (layer() ? layer()->horizontalScrollbarHeight() : 0);
0733 }
0734 
0735 // scrollWidth/scrollHeight is the size including the overflow area
0736 short RenderObject::scrollWidth() const
0737 {
0738     return (hasOverflowClip() && layer()) ? layer()->scrollWidth() : overflowWidth() - overflowLeft();
0739 }
0740 
0741 int RenderObject::scrollHeight() const
0742 {
0743     return (hasOverflowClip() && layer()) ? layer()->scrollHeight() : overflowHeight() - overflowTop();
0744 }
0745 
0746 void RenderObject::updatePixmap(const QRect & /*r*/, CachedImage *image)
0747 {
0748 #ifdef __GNUC__
0749 #warning "FIXME: Check if complete!"
0750 #endif
0751     //repaint bg when it finished loading
0752     if (image && parent() && style() && style()->backgroundLayers()->containsImage(image)) {
0753         isBody() ? canvas()->repaint() : repaint();
0754     }
0755 }
0756 
0757 void RenderObject::setNeedsLayout(bool b, bool markParents)
0758 {
0759     bool alreadyNeededLayout = m_needsLayout;
0760     m_needsLayout = b;
0761     if (b) {
0762         if (!alreadyNeededLayout && markParents && m_parent) {
0763             dirtyFormattingContext(false);
0764             markContainingBlocksForLayout();
0765         }
0766     } else {
0767         m_posChildNeedsLayout = false;
0768         m_normalChildNeedsLayout = false;
0769     }
0770 }
0771 
0772 void RenderObject::setChildNeedsLayout(bool b, bool markParents)
0773 {
0774     bool alreadyNeededLayout = m_normalChildNeedsLayout;
0775     m_normalChildNeedsLayout = b;
0776     if (b) {
0777         if (!alreadyNeededLayout && markParents) {
0778             markContainingBlocksForLayout();
0779         }
0780     } else {
0781         m_posChildNeedsLayout = false;
0782         m_normalChildNeedsLayout = false;
0783     }
0784 }
0785 
0786 void RenderObject::markContainingBlocksForLayout()
0787 {
0788     RenderObject *o = container();
0789     RenderObject *last = this;
0790 
0791     while (o) {
0792         if (!last->isText() && (last->style()->position() == PFIXED || last->style()->position() == PABSOLUTE)) {
0793             if (o->m_posChildNeedsLayout) {
0794                 return;
0795             }
0796             o->m_posChildNeedsLayout = true;
0797         } else {
0798             if (o->m_normalChildNeedsLayout) {
0799                 return;
0800             }
0801             o->m_normalChildNeedsLayout = true;
0802         }
0803 
0804         last = o;
0805         o = o->container();
0806     }
0807 
0808     last->scheduleRelayout();
0809 }
0810 
0811 RenderBlock *RenderObject::containingBlock() const
0812 {
0813     if (isTableCell()) {
0814         return static_cast<RenderBlock *>(parent()->parent()->parent());
0815     }
0816     if (isCanvas()) {
0817         return const_cast<RenderBlock *>(static_cast<const RenderBlock *>(this));
0818     }
0819 
0820     RenderObject *o = parent();
0821     if (m_style->position() == PFIXED) {
0822         while (o && !o->isCanvas()) {
0823             o = o->parent();
0824         }
0825     } else if (m_style->position() == PABSOLUTE) {
0826         while (o &&
0827                 (o->style()->position() == PSTATIC || (o->isInline() && !o->isReplaced())) && !o->isCanvas()) {
0828             // for relpos inlines, return the nearest block - it will host the positioned objects list
0829             if (o->isInline() && !o->isReplaced() && o->style()->position() == PRELATIVE) {
0830                 return o->containingBlock();
0831             }
0832             o = o->parent();
0833         }
0834     } else {
0835         while (o && ((o->isInline() && !o->isReplaced()) || o->isTableRow() || o->isTableSection() ||
0836                      o->isTableCol() || o->isFrameSet() ||
0837                      o->isSVGContainer() || o->isSVGRoot()))   // for svg
0838 
0839         {
0840             o = o->parent();
0841         }
0842     }
0843     // this is just to make sure we return a valid element.
0844     // the case below should never happen...
0845     if (!o || !o->isRenderBlock()) {
0846         if (!isCanvas()) {
0847 #ifndef NDEBUG
0848             qCDebug(KHTML_LOG) << this << ": " << renderName() << "(RenderObject): No containingBlock!";
0849             const RenderObject *p = this;
0850             while (p->parent()) {
0851                 p = p->parent();
0852             }
0853             p->printTree();
0854 #endif
0855         }
0856         return canvas(); // likely wrong, but better than a crash
0857     }
0858 
0859     return static_cast<RenderBlock *>(o);
0860 }
0861 
0862 short RenderObject::containingBlockWidth(RenderObject *) const
0863 {
0864     // ###
0865     return containingBlock()->contentWidth();
0866 }
0867 
0868 int RenderObject::containingBlockHeight(RenderObject *) const
0869 {
0870     // ###
0871     return containingBlock()->contentHeight();
0872 }
0873 
0874 bool RenderObject::sizesToMaxWidth() const
0875 {
0876     // Marquees in WinIE are like a mixture of blocks and inline-blocks.  They size as though they're blocks,
0877     // but they allow text to sit on the same line as the marquee.
0878     if (isFloating() || isCompact() ||
0879             (isInlineBlockOrInlineTable() && !isHTMLMarquee()) ||
0880             (element() && (element()->id() == ID_BUTTON || element()->id() == ID_LEGEND))) {
0881         return true;
0882     }
0883 
0884     // Children of a horizontal marquee do not fill the container by default.
0885     // FIXME: Need to deal with MAUTO value properly.  It could be vertical.
0886     if (parent()->style()->overflowX() == OMARQUEE) {
0887         EMarqueeDirection dir = parent()->style()->marqueeDirection();
0888         if (dir == MAUTO || dir == MFORWARD || dir == MBACKWARD || dir == MLEFT || dir == MRIGHT) {
0889             return true;
0890         }
0891     }
0892 
0893 #ifdef APPLE_CHANGES    // ### what the heck is a flexbox?
0894     // Flexible horizontal boxes lay out children at their maxwidths.  Also vertical boxes
0895     // that don't stretch their kids lay out their children at their maxwidths.
0896     if (parent()->isFlexibleBox() &&
0897             (parent()->style()->boxOrient() == HORIZONTAL || parent()->style()->boxAlign() != BSTRETCH)) {
0898         return true;
0899     }
0900 #endif
0901 
0902     return false;
0903 }
0904 
0905 // from Mozilla's nsCSSColorUtils.cpp
0906 static int brightness(int red, int green, int blue)
0907 {
0908 
0909     int intensity = (red + green + blue) / 3;
0910 
0911     int luminosity =
0912         ((RED_LUMINOSITY * red) / 100) +
0913         ((GREEN_LUMINOSITY * green) / 100) +
0914         ((BLUE_LUMINOSITY * blue) / 100);
0915 
0916     return ((intensity * INTENSITY_FACTOR) +
0917             (luminosity * LUMINOSITY_FACTOR)) / 100;
0918 }
0919 
0920 static void calc3DColor(QColor &color, bool darken)
0921 {
0922     int rb = color.red();
0923     int gb = color.green();
0924     int bb = color.blue();
0925     int a = color.alpha();
0926 
0927     int brightness_ = brightness(rb, gb, bb);
0928 
0929     int f0, f1;
0930     if (brightness_ < COLOR_DARK_THRESHOLD) {
0931         f0 = COLOR_DARK_BS_FACTOR;
0932         f1 = COLOR_DARK_TS_FACTOR;
0933     } else if (brightness_ > COLOR_LIGHT_THRESHOLD) {
0934         f0 = COLOR_LITE_BS_FACTOR;
0935         f1 = COLOR_LITE_TS_FACTOR;
0936     } else {
0937         f0 = COLOR_DARK_BS_FACTOR +
0938              (brightness_ *
0939               (COLOR_LITE_BS_FACTOR - COLOR_DARK_BS_FACTOR) / MAX_COLOR);
0940         f1 = COLOR_DARK_TS_FACTOR +
0941              (brightness_ *
0942               (COLOR_LITE_TS_FACTOR - COLOR_DARK_TS_FACTOR) / MAX_COLOR);
0943     }
0944 
0945     if (darken) {
0946         int r = rb - (f0 * rb / 100);
0947         int g = gb - (f0 * gb / 100);
0948         int b = bb - (f0 * bb / 100);
0949         if ((r == rb) && (g == gb) && (b == bb)) {
0950             color = (color == Qt::black) ? QColor(DARK_GRAY) : QColor(Qt::black);
0951         } else {
0952             color.setRgb(r, g, b);
0953         }
0954     } else {
0955         int r = qMin(rb + (f1 * (MAX_COLOR - rb) / 100), 255);
0956         int g = qMin(gb + (f1 * (MAX_COLOR - gb) / 100), 255);
0957         int b = qMin(bb + (f1 * (MAX_COLOR - bb) / 100), 255);
0958         if ((r == rb) && (g == gb) && (b == bb)) {
0959             color = (color == Qt::white) ? QColor(LIGHT_GRAY) : QColor(Qt::white);
0960         } else {
0961             color.setRgb(r, g, b);
0962         }
0963     }
0964     color.setAlpha(a);
0965 }
0966 
0967 void RenderObject::drawBorder(QPainter *p, int x1, int y1, int x2, int y2,
0968                               BorderSide s, QColor c, const QColor &textcolor, EBorderStyle style,
0969                               int adjbw1, int adjbw2, bool invalidisInvert, qreal *nextDashOffset)
0970 {
0971     if (nextDashOffset && style != DOTTED && style != DASHED) {
0972         *nextDashOffset = 0;
0973     }
0974 
0975     if (p->hasClipping() && !p->clipRegion().boundingRect().intersects(QRect(x1, y1, x2 - x1, y2 - y1))) {
0976         if (nextDashOffset && (style == DOTTED || style == DASHED)) {
0977             *nextDashOffset += (s == BSTop || s == BSBottom) ? (x2 - x1) : (y2 - y1);
0978         }
0979         return;
0980     }
0981 
0982     int width = (s == BSTop || s == BSBottom ? y2 - y1 : x2 - x1);
0983 
0984     if (style == DOUBLE && width < 3) {
0985         style = SOLID;
0986     }
0987 
0988     if (!c.isValid()) {
0989         if (invalidisInvert) {
0990             // handle 'outline-color: invert'
0991             if (p->paintEngine() && p->paintEngine()->hasFeature(QPaintEngine::BlendModes)) {
0992                 p->setCompositionMode(QPainter::CompositionMode_Difference);
0993                 c = Qt::white;
0994             } else {
0995                 // 'invert' is not supported on this platform (for instance XRender)
0996                 // CSS3 UI 8.4: If the UA does not support the 'invert' value then the initial value of
0997                 // the 'outline-color' property is the 'currentColor' [CSS3COLOR] keyword.
0998                 c = m_style->color();
0999             }
1000         } else {
1001             if (style == INSET || style == OUTSET || style == RIDGE || style ==
1002                     GROOVE) {
1003                 c = Qt::white;
1004             } else {
1005                 c = textcolor;
1006             }
1007         }
1008     }
1009 
1010     switch (style) {
1011     case BNATIVE:
1012     case BNONE:
1013     case BHIDDEN:
1014         // should not happen
1015         if (invalidisInvert && p->compositionMode() == QPainter::CompositionMode_Difference) {
1016             p->setCompositionMode(QPainter::CompositionMode_SourceOver);
1017         }
1018 
1019         return;
1020     case DOTTED:
1021     case DASHED: {
1022         if (width <= 0) {
1023             break;
1024         }
1025 
1026         //Figure out on/off spacing
1027         int onLen  = width;
1028         int offLen = width;
1029 
1030         if (style == DASHED) {
1031             if (width == 1) {
1032                 onLen  = 3;
1033                 offLen = 3;
1034             } else {
1035                 onLen  = width  * 3;
1036                 offLen = width;
1037             }
1038         }
1039 
1040         // Compute the offset for the dash pattern, taking the direction of
1041         // the line into account. (The borders are drawn counter-clockwise)
1042         QPoint offset(0, 0);
1043         if (nextDashOffset) {
1044             switch (s) {
1045             // The left border is drawn top to bottom
1046             case BSLeft:
1047                 offset.ry() = -qRound(*nextDashOffset);
1048                 *nextDashOffset += (y2 - y1);
1049                 break;
1050 
1051             // The bottom border is drawn left to right
1052             case BSBottom:
1053                 offset.rx() = -qRound(*nextDashOffset);
1054                 *nextDashOffset += (x2 - x1);
1055                 break;
1056 
1057             // The top border is drawn right to left
1058             case BSTop:
1059                 offset.rx() = (x2 - x1) + offLen + qRound(*nextDashOffset);
1060                 *nextDashOffset += (x2 - x1);
1061                 break;
1062 
1063             // The right border is drawn bottom to top
1064             case BSRight:
1065                 offset.ry() = (y2 - y1) + offLen + qRound(*nextDashOffset);
1066                 *nextDashOffset += (y2 - y1);
1067                 break;
1068             }
1069 
1070             offset.rx() = offset.x() % (onLen + offLen);
1071             offset.ry() = offset.y() % (onLen + offLen);
1072         }
1073 
1074         if ((onLen + offLen) <= 32 && width < 0x7fff) {
1075             if (!s_dashedLineCache) {
1076                 s_dashedLineCache = new QCache<quint64, QPixmap>(30);
1077             }
1078 
1079             bool horizontal = (s == BSBottom || s == BSTop);
1080             quint64 key = int(horizontal) << 31 | (onLen & 0xff) << 23 | (offLen & 0xff) << 15 | (width & 0x7fff);
1081             key = key << 32 | c.rgba();
1082 
1083             QPixmap *tilePtr = s_dashedLineCache->object(key);
1084             QPixmap tile;
1085             if (!tilePtr) {
1086                 QPainterPath path;
1087                 int size = (onLen + offLen) * (64 / (onLen + offLen));
1088                 if (horizontal) {
1089                     tilePtr = new QPixmap(size, width);
1090                     tilePtr->fill(Qt::transparent);
1091                     for (int x = 0; x < tilePtr->width(); x += onLen + offLen) {
1092                         path.addRect(x, 0, onLen, tilePtr->height());
1093                     }
1094                 } else { //Vertical
1095                     tilePtr = new QPixmap(width, size);
1096                     tilePtr->fill(Qt::transparent);
1097                     for (int y = 0; y < tilePtr->height(); y += onLen + offLen) {
1098                         path.addRect(0, y, tilePtr->width(), onLen);
1099                     }
1100                 }
1101                 QPainter p2(tilePtr);
1102                 p2.fillPath(path, c);
1103                 p2.end();
1104                 tile = tilePtr->copy();
1105                 s_dashedLineCache->insert(key, tilePtr);
1106             }
1107             else {
1108                 tile = *tilePtr;
1109             }
1110 
1111             QRect r = QRect(x1, y1, x2 - x1, y2 - y1);
1112             if (p->hasClipping()) {
1113                 r &= p->clipRegion().boundingRect();
1114             }
1115 
1116             // Make sure we're drawing the pattern in the correct phase
1117             if (horizontal && r.left() > x1) {
1118                 offset.rx() += (x1 - r.left());
1119             } else if (!horizontal && r.top() > y1) {
1120                 offset.ry() += (y1 - r.top());
1121             }
1122 
1123             p->drawTiledPixmap(r, tile, -offset);
1124         } else {
1125             const QRect bounding(x1, y1, x2 - x1, y2 - y1);
1126             QPainterPath path;
1127             if (s == BSBottom || s == BSTop) { //Horizontal
1128                 if (offset.x() > 0) {
1129                     offset.rx() -= onLen + offLen;
1130                 }
1131                 for (int x = x1 + offset.x(); x < x2; x += onLen + offLen) {
1132                     const QRect r(x, y1, qMin(onLen, (x2 - x)), width);
1133                     path.addRect(r & bounding);
1134                 }
1135             } else { //Vertical
1136                 if (offset.y() > 0) {
1137                     offset.ry() -= onLen + offLen;
1138                 }
1139                 for (int y = y1 + offset.y(); y < y2; y += onLen + offLen) {
1140                     const QRect r(x1, y, width, qMin(onLen, (y2 - y)));
1141                     path.addRect(r & bounding);
1142                 }
1143             }
1144 
1145             p->fillPath(path, c);
1146         }
1147         break;
1148     }
1149     case DOUBLE: {
1150         int third = (width + 1) / 3;
1151 
1152         if (adjbw1 == 0 && adjbw2 == 0) {
1153             p->setPen(Qt::NoPen);
1154             p->setBrush(c);
1155             switch (s) {
1156             case BSTop:
1157             case BSBottom:
1158                 p->drawRect(x1, y1, x2 - x1, third);
1159                 p->drawRect(x1, y2 - third, x2 - x1, third);
1160                 break;
1161             case BSLeft:
1162                 p->drawRect(x1, y1, third, y2 - y1);
1163                 p->drawRect(x2 - third, y1, third, y2 - y1);
1164                 break;
1165             case BSRight:
1166                 p->drawRect(x1, y1, third, y2 - y1);
1167                 p->drawRect(x2 - third, y1, third, y2 - y1);
1168                 break;
1169             }
1170         } else {
1171             int adjbw1bigthird;
1172             if (adjbw1 > 0) {
1173                 adjbw1bigthird = adjbw1 + 1;
1174             } else {
1175                 adjbw1bigthird = adjbw1 - 1;
1176             }
1177             adjbw1bigthird /= 3;
1178 
1179             int adjbw2bigthird;
1180             if (adjbw2 > 0) {
1181                 adjbw2bigthird = adjbw2 + 1;
1182             } else {
1183                 adjbw2bigthird = adjbw2 - 1;
1184             }
1185             adjbw2bigthird /= 3;
1186 
1187             switch (s) {
1188             case BSTop:
1189                 drawBorder(p, x1 + qMax((-adjbw1 * 2 + 1) / 3, 0), y1, x2 - qMax((-adjbw2 * 2 + 1) / 3, 0), y1 + third, s, c, textcolor, SOLID, adjbw1bigthird, adjbw2bigthird);
1190                 drawBorder(p, x1 + qMax((adjbw1 * 2 + 1) / 3, 0), y2 - third, x2 - qMax((adjbw2 * 2 + 1) / 3, 0), y2, s, c, textcolor, SOLID, adjbw1bigthird, adjbw2bigthird);
1191                 break;
1192             case BSLeft:
1193                 drawBorder(p, x1, y1 + qMax((-adjbw1 * 2 + 1) / 3, 0), x1 + third, y2 - qMax((-adjbw2 * 2 + 1) / 3, 0), s, c, textcolor, SOLID, adjbw1bigthird, adjbw2bigthird);
1194                 drawBorder(p, x2 - third, y1 + qMax((adjbw1 * 2 + 1) / 3, 0), x2, y2 - qMax((adjbw2 * 2 + 1) / 3, 0), s, c, textcolor, SOLID, adjbw1bigthird, adjbw2bigthird);
1195                 break;
1196             case BSBottom:
1197                 drawBorder(p, x1 + qMax((adjbw1 * 2 + 1) / 3, 0), y1, x2 - qMax((adjbw2 * 2 + 1) / 3, 0), y1 + third, s, c, textcolor, SOLID, adjbw1bigthird, adjbw2bigthird);
1198                 drawBorder(p, x1 + qMax((-adjbw1 * 2 + 1) / 3, 0), y2 - third, x2 - qMax((-adjbw2 * 2 + 1) / 3, 0), y2, s, c, textcolor, SOLID, adjbw1bigthird, adjbw2bigthird);
1199                 break;
1200             case BSRight:
1201                 drawBorder(p, x1, y1 + qMax((adjbw1 * 2 + 1) / 3, 0), x1 + third, y2 - qMax((adjbw2 * 2 + 1) / 3, 0), s, c, textcolor, SOLID, adjbw1bigthird, adjbw2bigthird);
1202                 drawBorder(p, x2 - third, y1 + qMax((-adjbw1 * 2 + 1) / 3, 0), x2, y2 - qMax((-adjbw2 * 2 + 1) / 3, 0), s, c, textcolor, SOLID, adjbw1bigthird, adjbw2bigthird);
1203                 break;
1204             default:
1205                 break;
1206             }
1207         }
1208         break;
1209     }
1210     case RIDGE:
1211     case GROOVE: {
1212         EBorderStyle s1;
1213         EBorderStyle s2;
1214         if (style == GROOVE) {
1215             s1 = INSET;
1216             s2 = OUTSET;
1217         } else {
1218             s1 = OUTSET;
1219             s2 = INSET;
1220         }
1221 
1222         int adjbw1bighalf;
1223         int adjbw2bighalf;
1224         if (adjbw1 > 0) {
1225             adjbw1bighalf = adjbw1 + 1;
1226         } else {
1227             adjbw1bighalf = adjbw1 - 1;
1228         }
1229         adjbw1bighalf /= 2;
1230 
1231         if (adjbw2 > 0) {
1232             adjbw2bighalf = adjbw2 + 1;
1233         } else {
1234             adjbw2bighalf = adjbw2 - 1;
1235         }
1236         adjbw2bighalf /= 2;
1237 
1238         switch (s) {
1239         case BSTop:
1240             drawBorder(p, x1 + qMax(-adjbw1, 0) / 2,  y1, x2 - qMax(-adjbw2, 0) / 2, (y1 + y2 + 1) / 2, s, c, textcolor, s1, adjbw1bighalf, adjbw2bighalf);
1241             drawBorder(p, x1 + qMax(adjbw1 + 1, 0) / 2, (y1 + y2 + 1) / 2, x2 - qMax(adjbw2 + 1, 0) / 2,  y2, s, c, textcolor, s2, adjbw1 / 2, adjbw2 / 2);
1242             break;
1243         case BSLeft:
1244             drawBorder(p,  x1, y1 + qMax(-adjbw1, 0) / 2, (x1 + x2 + 1) / 2, y2 - qMax(-adjbw2, 0) / 2, s, c, textcolor, s1, adjbw1bighalf, adjbw2bighalf);
1245             drawBorder(p, (x1 + x2 + 1) / 2, y1 + qMax(adjbw1 + 1, 0) / 2,  x2, y2 - qMax(adjbw2 + 1, 0) / 2, s, c, textcolor, s2, adjbw1 / 2, adjbw2 / 2);
1246             break;
1247         case BSBottom:
1248             drawBorder(p, x1 + qMax(adjbw1, 0) / 2,  y1, x2 - qMax(adjbw2, 0) / 2, (y1 + y2 + 1) / 2, s, c, textcolor, s2,  adjbw1bighalf, adjbw2bighalf);
1249             drawBorder(p, x1 + qMax(-adjbw1 + 1, 0) / 2, (y1 + y2 + 1) / 2, x2 - qMax(-adjbw2 + 1, 0) / 2,  y2, s, c, textcolor, s1, adjbw1 / 2, adjbw2 / 2);
1250             break;
1251         case BSRight:
1252             drawBorder(p,  x1, y1 + qMax(adjbw1, 0) / 2, (x1 + x2 + 1) / 2, y2 - qMax(adjbw2, 0) / 2, s, c, textcolor, s2, adjbw1bighalf, adjbw2bighalf);
1253             drawBorder(p, (x1 + x2 + 1) / 2, y1 + qMax(-adjbw1 + 1, 0) / 2,  x2, y2 - qMax(-adjbw2 + 1, 0) / 2, s, c, textcolor, s1, adjbw1 / 2, adjbw2 / 2);
1254             break;
1255         }
1256         break;
1257     }
1258     case INSET:
1259     case OUTSET:
1260         calc3DColor(c, (style == OUTSET && (s == BSBottom || s == BSRight)) ||
1261                     (style == INSET && (s == BSTop || s == BSLeft)));
1262     /* nobreak; */
1263     case SOLID:
1264         p->setPen(Qt::NoPen);
1265         p->setBrush(c);
1266         Q_ASSERT(x2 >= x1);
1267         Q_ASSERT(y2 >= y1);
1268         if (adjbw1 == 0 && adjbw2 == 0) {
1269             p->drawRect(x1, y1, x2 - x1, y2 - y1);
1270             return;
1271         }
1272         QPolygon quad(4);
1273         switch (s) {
1274         case BSTop:
1275             quad.setPoints(4,
1276                            x1 + qMax(-adjbw1, 0), y1,
1277                            x1 + qMax(adjbw1, 0), y2,
1278                            x2 - qMax(adjbw2, 0), y2,
1279                            x2 - qMax(-adjbw2, 0), y1);
1280             break;
1281         case BSBottom:
1282             quad.setPoints(4,
1283                            x1 + qMax(adjbw1, 0), y1,
1284                            x1 + qMax(-adjbw1, 0), y2,
1285                            x2 - qMax(-adjbw2, 0), y2,
1286                            x2 - qMax(adjbw2, 0), y1);
1287             break;
1288         case BSLeft:
1289             quad.setPoints(4,
1290                            x1, y1 + qMax(-adjbw1, 0),
1291                            x1, y2 - qMax(-adjbw2, 0),
1292                            x2, y2 - qMax(adjbw2, 0),
1293                            x2, y1 + qMax(adjbw1, 0));
1294             break;
1295         case BSRight:
1296             quad.setPoints(4,
1297                            x1, y1 + qMax(adjbw1, 0),
1298                            x1, y2 - qMax(adjbw2, 0),
1299                            x2, y2 - qMax(-adjbw2, 0),
1300                            x2, y1 + qMax(-adjbw1, 0));
1301             break;
1302         }
1303         p->drawConvexPolygon(quad);
1304         break;
1305     }
1306 
1307     if (invalidisInvert && p->compositionMode() == QPainter::CompositionMode_Difference) {
1308         p->setCompositionMode(QPainter::CompositionMode_SourceOver);
1309     }
1310 }
1311 
1312 void RenderObject::calcBorderRadii(QPoint &topLeftRadii, QPoint &topRightRadii, QPoint &bottomLeftRadii, QPoint &bottomRightRadii, int w, int h) const
1313 {
1314     // CSS Backgrounds and Borders Module Level 3 (https://www.w3.org/TR/2014/CR-css3-background-20140909/), chapter 5.5:
1315     // "Corner curves must not overlap: When the sum of any two adjacent border radii exceeds the size of the border box,
1316     //  UAs must proportionally reduce the used values of all border radii until none of them overlap.
1317     //  The algorithm for reducing radii is as follows: ..."
1318 
1319     const RenderStyle *s = style();
1320     if (!s->hasBorderRadius()) {
1321         return;
1322     }
1323 
1324     // Border radii Length is Fixed|Percent
1325     topLeftRadii.rx() = s->borderTopLeftRadius().horizontal.minWidth(w);
1326     topLeftRadii.ry() = s->borderTopLeftRadius().vertical.minWidth(h);
1327     topRightRadii.rx() = s->borderTopRightRadius().horizontal.minWidth(w);
1328     topRightRadii.ry() = s->borderTopRightRadius().vertical.minWidth(h);
1329     bottomLeftRadii.rx() = s->borderBottomLeftRadius().horizontal.minWidth(w);
1330     bottomLeftRadii.ry() = s->borderBottomLeftRadius().vertical.minWidth(h);
1331     bottomRightRadii.rx() = s->borderBottomRightRadius().horizontal.minWidth(w);
1332     bottomRightRadii.ry() = s->borderBottomRightRadius().vertical.minWidth(h);
1333 
1334     // Adjust the border radii so they don't overlap when taking the size of the box into account.
1335 
1336     const int horS = qMax(topLeftRadii.x() + topRightRadii.x(), bottomLeftRadii.x() + bottomRightRadii.x());
1337     const int verS = qMax(topLeftRadii.y() + bottomLeftRadii.y(), topRightRadii.y() + bottomRightRadii.y());
1338 
1339     qreal f = 1.0;
1340     if (horS > 0) {
1341         f = qMin(f, w / qreal(horS));
1342     }
1343     if (verS > 0) {
1344         f = qMin(f, h / qreal(verS));
1345     }
1346 
1347     if (f < 1.0) {
1348         topLeftRadii *= f;
1349         topRightRadii *= f;
1350         bottomLeftRadii *= f;
1351         bottomRightRadii *= f;
1352     }
1353 }
1354 
1355 static QImage blendCornerImages(const QImage &image1, const QImage &image2)
1356 {
1357     QImage mask(image1.size(), QImage::Format_ARGB32_Premultiplied);
1358     QImage composite = image1;
1359     QImage temp = image2;
1360 
1361     // Construct the mask image
1362     QConicalGradient gradient(mask.width() / 2, mask.height() / 2, 0);
1363     gradient.setColorAt(0.00, Qt::transparent);
1364     gradient.setColorAt(0.25, Qt::black);
1365     gradient.setColorAt(0.50, Qt::black);
1366     gradient.setColorAt(0.75, Qt::transparent);
1367     gradient.setColorAt(1.00, Qt::transparent);
1368 
1369     QBrush gradientBrush = gradient;
1370 
1371     if (mask.width() != mask.height()) {
1372         int min = qMin(mask.width(), mask.height());
1373         QTransform xform;
1374         xform.translate(mask.width() / 2, mask.height() / 2);
1375         xform.scale(min / mask.width(), min / mask.height());
1376         gradientBrush.setTransform(xform);
1377     }
1378 
1379     QPainter p;
1380     p.begin(&mask);
1381     p.setCompositionMode(QPainter::CompositionMode_Source);
1382     p.fillRect(mask.rect(), gradientBrush);
1383     p.end();
1384 
1385     p.begin(&temp);
1386     p.setCompositionMode(QPainter::CompositionMode_DestinationIn);
1387     p.drawImage(0, 0, mask);
1388     p.end();
1389 
1390     p.begin(&composite);
1391     p.setCompositionMode(QPainter::CompositionMode_DestinationOut);
1392     p.drawImage(0, 0, mask);
1393     p.setCompositionMode(QPainter::CompositionMode_SourceOver);
1394     p.drawImage(0, 0, temp);
1395     p.end();
1396 
1397     return composite;
1398 }
1399 
1400 static QBrush cornerGradient(int cx, int cy, const QPoint &radius, int angleStart, int angleSpan,
1401                              const QColor &startColor, const QColor &finalColor)
1402 {
1403     QConicalGradient g(0, 0, angleStart);
1404     g.setColorAt(0, startColor);
1405     g.setColorAt(angleSpan / 360.0, finalColor);
1406 
1407     QBrush brush(g);
1408 
1409     QTransform xform;
1410     xform.translate(cx, cy);
1411 
1412     if (radius.x() < radius.y()) {
1413         xform.scale(radius.x() / radius.y(), 1);
1414     } else if (radius.y() < radius.x()) {
1415         xform.scale(1, radius.y() / radius.x());
1416     }
1417 
1418     brush.setTransform(xform);
1419     return brush;
1420 }
1421 
1422 void RenderObject::drawBorderArc(QPainter *p, int x, int y, float horThickness, float vertThickness,
1423                                  const QPoint &radius, int angleStart, int angleSpan, const QBrush &brush,
1424                                  const QColor &textColor, EBorderStyle style, qreal *nextDashOffset) const
1425 {
1426     QColor c = brush.color();
1427     if (!c.isValid()) {
1428         if (style == INSET || style == OUTSET || style == RIDGE || style == GROOVE) {
1429             c = Qt::white;
1430         } else {
1431             c = textColor;
1432         }
1433     }
1434 
1435     QColor light = c;
1436     QColor dark = c;
1437     calc3DColor(light, false);
1438     calc3DColor(dark, true);
1439 
1440     if (style == DOUBLE && horThickness < 3 && vertThickness < 3) {
1441         style = SOLID;
1442     }
1443 
1444     if (nextDashOffset && style != DOTTED && style != DASHED) {
1445         *nextDashOffset = 0;
1446     }
1447 
1448     p->save();
1449     p->setRenderHint(QPainter::Antialiasing);
1450 
1451     switch (style) {
1452     case BNATIVE:
1453     case BNONE:
1454     case BHIDDEN: {
1455         // Should not happen
1456         break;
1457     }
1458 
1459     case SOLID: {
1460         const QRect outerRect = QRect(x - radius.x(), y - radius.y(), radius.x() * 2, radius.y() * 2);
1461         const QRect innerRect = outerRect.adjusted(horThickness, vertThickness, -horThickness, -vertThickness);
1462         QPainterPath path;
1463         path.arcMoveTo(outerRect, angleStart);
1464         path.arcTo(outerRect, angleStart, angleSpan);
1465         if (innerRect.isValid()) {
1466             path.arcTo(innerRect, angleStart + angleSpan, -angleSpan);
1467         } else {
1468             path.lineTo(x, y);
1469         }
1470         path.closeSubpath();
1471         p->fillPath(path, brush);
1472         break;
1473     }
1474 
1475     case DOUBLE: {
1476         const qreal hw = (horThickness + 1) / 3;
1477         const qreal vw = (vertThickness + 1) / 3;
1478 
1479         QPoint br(radius.x() - hw * 2 + 1, radius.y() - vw * 2 + 1);
1480 
1481         drawBorderArc(p, x, y, hw, vw, radius, angleStart, angleSpan, brush, textColor, SOLID);
1482         drawBorderArc(p, x, y, hw, vw, br, angleStart, angleSpan, brush, textColor, SOLID);
1483         break;
1484     }
1485 
1486     case INSET:
1487     case OUTSET: {
1488         QImage image1(radius.x() * 2, radius.y() * 2, QImage::Format_ARGB32_Premultiplied);
1489         image1.fill(0);
1490 
1491         QImage image2 = image1;
1492 
1493         const QColor c1 = style == OUTSET ? dark : light;
1494         const QColor c2 = style == OUTSET ? light : dark;
1495 
1496         QPainter p2;
1497         p2.begin(&image1);
1498         drawBorderArc(&p2, radius.x(), radius.y(), horThickness, vertThickness,
1499                       radius, angleStart, angleSpan, c1, textColor, SOLID);
1500         p2.end();
1501 
1502         p2.begin(&image2);
1503         drawBorderArc(&p2, radius.x(), radius.y(), horThickness, vertThickness,
1504                       radius, angleStart, angleSpan, c2, textColor, SOLID);
1505         p2.end();
1506 
1507         p->drawImage(x - radius.x(), y - radius.y(), blendCornerImages(image1, image2));
1508         break;
1509     }
1510 
1511     case RIDGE:
1512     case GROOVE: {
1513         QImage image1(radius.x() * 2, radius.y() * 2, QImage::Format_ARGB32_Premultiplied);
1514         image1.fill(0);
1515 
1516         QImage image2 = image1;
1517 
1518         const QColor c1 = style == RIDGE ? dark : light;
1519         const QColor c2 = style == RIDGE ? light : dark;
1520 
1521         const qreal hw = horThickness / 2;
1522         const qreal vw = vertThickness / 2;
1523         int cx = radius.x();
1524         int cy = radius.y();
1525 
1526         QPoint innerRadius(radius.x() - hw, radius.y() - vw);
1527 
1528         QPainter p2;
1529         p2.begin(&image1);
1530         drawBorderArc(&p2, cx, cy, hw, vw, radius, angleStart, angleSpan, c1, textColor, SOLID);
1531         drawBorderArc(&p2, cx, cy, hw, vw, innerRadius, angleStart, angleSpan, c2, textColor, SOLID);
1532         p2.end();
1533 
1534         p2.begin(&image2);
1535         drawBorderArc(&p2, cx, cy, hw, vw, radius, angleStart, angleSpan, c2, textColor, SOLID);
1536         drawBorderArc(&p2, cx, cy, hw, vw, innerRadius, angleStart, angleSpan, c1, textColor, SOLID);
1537         p2.end();
1538 
1539         p->drawImage(x - radius.x(), y - radius.y(), blendCornerImages(image1, image2));
1540         break;
1541     }
1542 
1543     case DOTTED:
1544     case DASHED: {
1545         const QRectF rect = QRectF(x - radius.x(), y - radius.y(), radius.x() * 2, radius.y() * 2);
1546         int width;
1547 
1548         // Figure out which border we're starting from
1549         angleStart = angleStart % 360;
1550         if (angleStart < 0) {
1551             angleStart += 360;
1552         }
1553 
1554         if ((angleStart > 45 && angleStart <= 135) || (angleStart > 225 && angleStart <= 315)) {
1555             width = vertThickness;
1556         } else {
1557             width = horThickness;
1558         }
1559 
1560         int onLen  = width;
1561         int offLen = width;
1562 
1563         if (style == DASHED) {
1564             if (width == 1) {
1565                 onLen  = 3;
1566                 offLen = 3;
1567             } else {
1568                 onLen  = width  * 3;
1569                 offLen = width;
1570             }
1571         }
1572 
1573         BorderArcStroker stroker;
1574         stroker.setArc(rect, angleStart, angleSpan);
1575         stroker.setPenWidth(horThickness, vertThickness);
1576         stroker.setDashPattern(onLen, offLen);
1577         stroker.setDashOffset(*nextDashOffset);
1578 
1579         const QPainterPath path = stroker.createStroke(nextDashOffset);
1580         p->fillPath(path, brush);
1581     }
1582     }
1583 
1584     p->restore();
1585 }
1586 
1587 void RenderObject::paintBorder(QPainter *p, int _tx, int _ty, int w, int h, const RenderStyle *style, bool begin, bool end)
1588 {
1589     const QColor &tc = style->borderTopColor();
1590     const QColor &bc = style->borderBottomColor();
1591     const QColor &lc = style->borderLeftColor();
1592     const QColor &rc = style->borderRightColor();
1593 
1594     bool tt = style->borderTopIsTransparent();
1595     bool bt = style->borderBottomIsTransparent();
1596     bool rt = style->borderRightIsTransparent();
1597     bool lt = style->borderLeftIsTransparent();
1598 
1599     EBorderStyle ts = style->borderTopStyle();
1600     EBorderStyle bs = style->borderBottomStyle();
1601     EBorderStyle ls = style->borderLeftStyle();
1602     EBorderStyle rs = style->borderRightStyle();
1603 
1604     bool render_t = ts > BHIDDEN && !tt;
1605     bool render_l = ls > BHIDDEN && begin && !lt;
1606     bool render_r = rs > BHIDDEN && end && !rt;
1607     bool render_b = bs > BHIDDEN && !bt;
1608 
1609     QPoint topLeftRadii, topRightRadii, bottomLeftRadii, bottomRightRadii;
1610     calcBorderRadii(topLeftRadii, topRightRadii, bottomLeftRadii, bottomRightRadii, w, h);
1611 
1612     bool upperLeftBorderStylesMatch = render_l && (ts == ls) && (tc == lc);
1613     bool upperRightBorderStylesMatch = render_r && (ts == rs) && (tc == rc);
1614     bool lowerLeftBorderStylesMatch = render_l && (bs == ls) && (bc == lc);
1615     bool lowerRightBorderStylesMatch = render_r && (bs == rs) && (bc == rc);
1616 
1617     // We do a gradient transition for dotted, dashed, solid and double lines
1618     // when the styles match but the colors differ.
1619     bool upperLeftGradient = render_t && render_l && ts == ls && tc != lc && ts > OUTSET;
1620     bool upperRightGradient = render_t && render_r && ts == rs && tc != rc && ts > OUTSET;
1621     bool lowerLeftGradient = render_b && render_l && bs == ls && bc != lc && bs > OUTSET;
1622     bool lowerRightGradient = render_b && render_r && bs == rs && bc != rc && bs > OUTSET;
1623 
1624     qreal nextDashOffset = 0;
1625 
1626     // Draw the borders counter-clockwise starting with the upper right corner
1627     if (render_t) {
1628         bool ignore_left = (topLeftRadii.x() > 0) ||
1629                            ((tc == lc) && (tt == lt) &&
1630                             (ts >= OUTSET) &&
1631                             (ls == DOTTED || ls == DASHED || ls == SOLID || ls == OUTSET));
1632 
1633         bool ignore_right = (topRightRadii.x() > 0) ||
1634                             ((tc == rc) && (tt == rt) &&
1635                              (ts >= OUTSET) &&
1636                              (rs == DOTTED || rs == DASHED || rs == SOLID || rs == INSET));
1637 
1638         int x = _tx + topLeftRadii.x();
1639         int x2 = _tx + w - topRightRadii.x();
1640 
1641         if (!topRightRadii.isNull()) {
1642             int x = _tx + w - topRightRadii.x();
1643             int y = _ty + topRightRadii.y();
1644             int startAngle, span;
1645 
1646             if (upperRightBorderStylesMatch || upperRightGradient) {
1647                 startAngle = 0;
1648                 span = 90;
1649             } else {
1650                 startAngle = 45;
1651                 span = 45;
1652             }
1653 
1654             const QBrush brush = upperRightGradient ?
1655                                  cornerGradient(x, y, topRightRadii, startAngle, span, rc, tc) : tc;
1656 
1657             // Draw the upper right arc
1658             drawBorderArc(p, x, y, style->borderRightWidth(), style->borderTopWidth(),
1659                           topRightRadii, startAngle, span, brush, style->color(), ts, &nextDashOffset);
1660         }
1661 
1662         drawBorder(p, x, _ty, x2, _ty + style->borderTopWidth(), BSTop, tc, style->color(), ts,
1663                    ignore_left ? 0 : style->borderLeftWidth(),
1664                    ignore_right ? 0 : style->borderRightWidth(), false, &nextDashOffset);
1665 
1666         if (!topLeftRadii.isNull()) {
1667             int x = _tx + topLeftRadii.x();
1668             int y = _ty + topLeftRadii.y();
1669             int startAngle = 90;
1670             int span = (upperLeftBorderStylesMatch || upperLeftGradient) ? 90 : 45;
1671             const QBrush brush = upperLeftGradient ?
1672                                  cornerGradient(x, y, topLeftRadii, startAngle, span, tc, lc) : tc;
1673 
1674             // Draw the upper left arc
1675             drawBorderArc(p, x, y, style->borderLeftWidth(), style->borderTopWidth(),
1676                           topLeftRadii, startAngle, span, brush, style->color(), ts, &nextDashOffset);
1677         } else if (ls == DASHED || ls == DOTTED) {
1678             nextDashOffset = 0;    // Reset the offset to avoid partially overlapping dashes
1679         }
1680     }
1681 
1682     if (render_l) {
1683         bool ignore_top = (topLeftRadii.y() > 0) ||
1684                           ((tc == lc) && (tt == lt) &&
1685                            (ls >= OUTSET) &&
1686                            (ts == DOTTED || ts == DASHED || ts == SOLID || ts == OUTSET));
1687 
1688         bool ignore_bottom = (bottomLeftRadii.y() > 0) ||
1689                              ((bc == lc) && (bt == lt) &&
1690                               (ls >= OUTSET) &&
1691                               (bs == DOTTED || bs == DASHED || bs == SOLID || bs == INSET));
1692 
1693         int y = _ty + topLeftRadii.y();
1694         int y2 = _ty + h - bottomLeftRadii.y();
1695 
1696         if (!upperLeftBorderStylesMatch && !upperLeftGradient && !topLeftRadii.isNull()) {
1697             int x = _tx + topLeftRadii.x();
1698             int y = _ty + topLeftRadii.y();
1699             int startAngle = 135;
1700             int span = 45;
1701 
1702             // Draw the upper left arc
1703             drawBorderArc(p, x, y, style->borderLeftWidth(), style->borderTopWidth(),
1704                           topLeftRadii, startAngle, span, lc, style->color(), ls, &nextDashOffset);
1705         }
1706 
1707         drawBorder(p, _tx, y, _tx + style->borderLeftWidth(), y2, BSLeft, lc, style->color(), ls,
1708                    ignore_top ? 0 : style->borderTopWidth(),
1709                    ignore_bottom ? 0 : style->borderBottomWidth(), false, &nextDashOffset);
1710 
1711         if (!lowerLeftBorderStylesMatch && !lowerLeftGradient && !bottomLeftRadii.isNull()) {
1712             int x = _tx + bottomLeftRadii.x();
1713             int y = _ty + h - bottomLeftRadii.y();
1714             int startAngle = 180;
1715             int span = 45;
1716 
1717             // Draw the bottom left arc
1718             drawBorderArc(p, x, y, style->borderLeftWidth(), style->borderBottomWidth(),
1719                           bottomLeftRadii, startAngle, span, lc, style->color(), ls, &nextDashOffset);
1720         }
1721 
1722         // Reset the offset to avoid partially overlapping dashes
1723         if (bottomLeftRadii.isNull() && (bs == DASHED || bs == DOTTED)) {
1724             nextDashOffset = 0;
1725         }
1726     }
1727 
1728     if (render_b) {
1729         bool ignore_left = (bottomLeftRadii.x() > 0) ||
1730                            ((bc == lc) && (bt == lt) &&
1731                             (bs >= OUTSET) &&
1732                             (ls == DOTTED || ls == DASHED || ls == SOLID || ls == INSET));
1733 
1734         bool ignore_right = (bottomRightRadii.x() > 0) ||
1735                             ((bc == rc) && (bt == rt) &&
1736                              (bs >= OUTSET) &&
1737                              (rs == DOTTED || rs == DASHED || rs == SOLID || rs == OUTSET));
1738 
1739         int x = _tx + bottomLeftRadii.x();
1740         int x2 = _tx + w - bottomRightRadii.x();
1741 
1742         if (!bottomLeftRadii.isNull()) {
1743             int x = _tx + bottomLeftRadii.x();
1744             int y = _ty + h - bottomLeftRadii.y();
1745             int startAngle, span;
1746 
1747             if (lowerLeftBorderStylesMatch || lowerLeftGradient) {
1748                 startAngle = 180;
1749                 span = 90;
1750             } else {
1751                 startAngle = 225;
1752                 span = 45;
1753             }
1754 
1755             const QBrush brush = lowerLeftGradient ?
1756                                  cornerGradient(x, y, bottomLeftRadii, startAngle, span, lc, bc) : bc;
1757 
1758             // Draw the bottom left arc
1759             drawBorderArc(p, x, y, style->borderLeftWidth(), style->borderBottomWidth(),
1760                           bottomLeftRadii, startAngle, span, brush, style->color(), bs, &nextDashOffset);
1761         }
1762 
1763         drawBorder(p, x, _ty + h - style->borderBottomWidth(), x2, _ty + h, BSBottom, bc, style->color(), bs,
1764                    ignore_left ? 0 : style->borderLeftWidth(),
1765                    ignore_right ? 0 : style->borderRightWidth(), false, &nextDashOffset);
1766 
1767         if (!bottomRightRadii.isNull()) {
1768             int x = _tx + w - bottomRightRadii.x();
1769             int y = _ty + h - bottomRightRadii.y();
1770             int startAngle = 270;
1771             int span = (lowerRightBorderStylesMatch || lowerRightGradient) ? 90 : 45;
1772             const QBrush brush = lowerRightGradient ?
1773                                  cornerGradient(x, y, bottomRightRadii, startAngle, span, bc, rc) : bc;
1774 
1775             // Draw the bottom right arc
1776             drawBorderArc(p, x, y, style->borderRightWidth(), style->borderBottomWidth(),
1777                           bottomRightRadii, startAngle, span, brush, style->color(), bs, &nextDashOffset);
1778         } else if (rs == DASHED || rs == DOTTED) {
1779             nextDashOffset = 0;    // Reset the offset to avoid partially overlapping dashes
1780         }
1781     }
1782 
1783     if (render_r) {
1784         bool ignore_top = (topRightRadii.y() > 0) ||
1785                           ((tc == rc) && (tt == rt) &&
1786                            (rs >= DOTTED || rs == INSET) &&
1787                            (ts == DOTTED || ts == DASHED || ts == SOLID || ts == OUTSET));
1788 
1789         bool ignore_bottom = (bottomRightRadii.y() > 0) ||
1790                              ((bc == rc) && (bt == rt) &&
1791                               (rs >= DOTTED || rs == INSET) &&
1792                               (bs == DOTTED || bs == DASHED || bs == SOLID || bs == INSET));
1793 
1794         int y = _ty + topRightRadii.y();
1795         int y2 = _ty + h - bottomRightRadii.y();
1796 
1797         if (!lowerRightBorderStylesMatch && !lowerRightGradient && !bottomRightRadii.isNull()) {
1798             int x = _tx + w - bottomRightRadii.x();
1799             int y = _ty + h - bottomRightRadii.y();
1800             int startAngle = 315;
1801             int span = 45;
1802 
1803             // Draw the bottom right arc
1804             drawBorderArc(p, x, y, style->borderRightWidth(), style->borderBottomWidth(),
1805                           bottomRightRadii, startAngle, span, rc, style->color(), rs, &nextDashOffset);
1806         }
1807 
1808         drawBorder(p, _tx + w - style->borderRightWidth(), y, _tx + w, y2, BSRight, rc, style->color(), rs,
1809                    ignore_top ? 0 : style->borderTopWidth(),
1810                    ignore_bottom ? 0 : style->borderBottomWidth(), false, &nextDashOffset);
1811 
1812         if (!upperRightBorderStylesMatch && !upperRightGradient && !topRightRadii.isNull()) {
1813             int x = _tx + w - topRightRadii.x();
1814             int y = _ty + topRightRadii.y();
1815             int startAngle = 0;
1816             int span = 45;
1817 
1818             // Draw the upper right arc
1819             drawBorderArc(p, x, y, style->borderRightWidth(), style->borderTopWidth(),
1820                           topRightRadii, startAngle, span, rc, style->color(), rs, &nextDashOffset);
1821         }
1822     }
1823 }
1824 
1825 void RenderObject::paintOutline(QPainter *p, int _tx, int _ty, int w, int h, const RenderStyle *style)
1826 {
1827     int ow = style->outlineWidth();
1828     if (!ow) {
1829         return;
1830     }
1831 
1832     const QColor &oc = style->outlineColor();
1833     EBorderStyle os = style->outlineStyle();
1834     int offset = style->outlineOffset();
1835 
1836 #ifdef APPLE_CHANGES
1837     if (style->outlineStyleIsAuto()) {
1838         p->initFocusRing(ow, offset, oc);
1839         addFocusRingRects(p, _tx, _ty);
1840         p->drawFocusRing();
1841         p->clearFocusRing();
1842         return;
1843     }
1844 #endif
1845 
1846     _tx -= offset;
1847     _ty -= offset;
1848     w += 2 * offset;
1849     h += 2 * offset;
1850 
1851     drawBorder(p, _tx - ow, _ty - ow, _tx, _ty + h + ow, BSLeft,
1852                QColor(oc), style->color(),
1853                os, ow, ow, true);
1854 
1855     drawBorder(p, _tx - ow, _ty - ow, _tx + w + ow, _ty, BSTop,
1856                QColor(oc), style->color(),
1857                os, ow, ow, true);
1858 
1859     drawBorder(p, _tx + w, _ty - ow, _tx + w + ow, _ty + h + ow, BSRight,
1860                QColor(oc), style->color(),
1861                os, ow, ow, true);
1862 
1863     drawBorder(p, _tx - ow, _ty + h, _tx + w + ow, _ty + h + ow, BSBottom,
1864                QColor(oc), style->color(),
1865                os, ow, ow, true);
1866 
1867 }
1868 
1869 void RenderObject::paint(PaintInfo &, int /*tx*/, int /*ty*/)
1870 {
1871 }
1872 
1873 void RenderObject::repaintRectangle(int x, int y, int w, int h, Priority p, bool f)
1874 {
1875     if (parent()) {
1876         parent()->repaintRectangle(x, y, w, h, p, f);
1877     }
1878 }
1879 
1880 #ifdef ENABLE_DUMP
1881 
1882 QString RenderObject::information() const
1883 {
1884     QString str;
1885     int x; int y;
1886     absolutePosition(x, y);
1887     x += inlineXPos();
1888     y += inlineYPos();
1889     QTextStream ts(&str, QIODevice::WriteOnly);
1890     ts << renderName()
1891        << "(" << (style() ? style()->refCount() : 0) << ")"
1892        << ": " << (void *)this << "  ";
1893     ts << "{" << x << " " << y << "} ";
1894     if (isInline()) {
1895         ts << "il ";
1896     }
1897     if (childrenInline()) {
1898         ts << "ci ";
1899     }
1900     if (isFloating()) {
1901         ts << "fl ";
1902     }
1903     if (isAnonymous()) {
1904         ts << "an ";
1905     }
1906     if (isRelPositioned()) {
1907         ts << "rp ";
1908     }
1909     if (isPositioned()) {
1910         ts << "ps ";
1911     }
1912     if (isReplaced()) {
1913         ts << "rp ";
1914     }
1915     if (needsLayout()) {
1916         ts << "nl ";
1917     }
1918     if (minMaxKnown()) {
1919         ts << "mmk ";
1920     }
1921     if (m_recalcMinMax) {
1922         ts << "rmm ";
1923     }
1924     if (mouseInside()) {
1925         ts << "mi ";
1926     }
1927     if (style() && style()->zIndex()) {
1928         ts << "zI: " << style()->zIndex();
1929     }
1930     if (style() && style()->hasAutoZIndex()) {
1931         ts << "zI: auto ";
1932     }
1933     if (element()) {
1934         if (element()->active()) {
1935             ts << "act ";
1936         }
1937         if (element()->hasAnchor()) {
1938             ts << "anchor ";
1939         }
1940         if (element()->focused()) {
1941             ts << "focus ";
1942         }
1943         ts << " <" << LocalName::fromId(localNamePart(element()->id())).toString().string() << ">";
1944 
1945     } else if (isPseudoAnonymous() && style() && style()->styleType() != RenderStyle::NOPSEUDO) {
1946         ts << " <" << LocalName::fromId(localNamePart(node()->id())).toString().string();
1947         QString pseudo;
1948         switch (style()->styleType()) {
1949         case RenderStyle::FIRST_LETTER:
1950             pseudo = ":first-letter"; break;
1951         case RenderStyle::BEFORE:
1952             pseudo = ":before"; break;
1953         case RenderStyle::AFTER:
1954             pseudo = ":after"; break;
1955         default:
1956             pseudo = ":pseudo-element";
1957         }
1958         ts << pseudo;
1959         ts << ">";
1960     }
1961     ts << " (" << xPos() << "," << yPos() << "," << width() << "," << height() << ")"
1962        << " [" << minWidth() << "-" << maxWidth() << "]"
1963        << " { mT: " << marginTop() << " qT: " << isTopMarginQuirk()
1964        << " mB: " << marginBottom() << " qB: " << isBottomMarginQuirk()
1965        << "}"
1966        << (isTableCell() ?
1967            (QLatin1String(" [r=") +
1968             QString::number(static_cast<const RenderTableCell *>(this)->row()) +
1969             QLatin1String(" c=") +
1970             QString::number(static_cast<const RenderTableCell *>(this)->col()) +
1971             QLatin1String(" rs=") +
1972             QString::number(static_cast<const RenderTableCell *>(this)->rowSpan()) +
1973             QLatin1String(" cs=") +
1974             QString::number(static_cast<const RenderTableCell *>(this)->colSpan()) +
1975             QLatin1String("]")) : QString());
1976     if (layer()) {
1977         ts << " layer=" << layer();
1978     }
1979     if (continuation()) {
1980         ts << " continuation=" << continuation();
1981     }
1982     if (isText()) {
1983         ts << " \"" << QString::fromRawData(static_cast<const RenderText *>(this)->text(), qMin(static_cast<const RenderText *>(this)->length(), 10u)) << "\"";
1984     }
1985     return str;
1986 }
1987 
1988 void RenderObject::printTree(int indent) const
1989 {
1990     QString ind;
1991     ind.fill(' ', indent);
1992 
1993     // qCDebug(KHTML_LOG) << (ind + information());
1994 
1995     RenderObject *child = firstChild();
1996     while (child != nullptr) {
1997         child->printTree(indent + 2);
1998         child = child->nextSibling();
1999     }
2000 }
2001 
2002 static QTextStream &operator<<(QTextStream &ts, const QRect &r)
2003 {
2004     return ts << "at (" << r.x() << "," << r.y() << ") size " << r.width() << "x" << r.height();
2005 }
2006 
2007 //A bit like getTagName, but handles XML, too.
2008 static QString lookupTagName(NodeImpl *node)
2009 {
2010     return LocalName::fromId(node->id()).toString().string();
2011 }
2012 
2013 void RenderObject::dump(QTextStream &ts, const QString &ind) const
2014 {
2015     if (!layer()) {
2016         ts << endl;
2017     }
2018 
2019     ts << ind << renderName();
2020 
2021     if (style() && style()->zIndex()) {
2022         ts << " zI: " << style()->zIndex();
2023     }
2024 
2025     if (element()) {
2026         QString tagName(lookupTagName(element()));
2027         if (!tagName.isEmpty()) {
2028             ts << " {" << tagName << "}";
2029         }
2030     } else if (isPseudoAnonymous() && style() && style()->styleType() != RenderStyle::NOPSEUDO) {
2031         QString pseudo;
2032         QString tagName(lookupTagName(node()));
2033         switch (style()->styleType()) {
2034         case RenderStyle::FIRST_LETTER:
2035             pseudo = ":first-letter"; break;
2036         case RenderStyle::BEFORE:
2037             pseudo = ":before"; break;
2038         case RenderStyle::AFTER:
2039             pseudo = ":after"; break;
2040         default:
2041             pseudo = ":pseudo-element";
2042         }
2043         ts << " {" << tagName << pseudo << "}";
2044     }
2045 
2046     QRect r(xPos(), yPos(), width(), height());
2047     ts << " " << r;
2048 
2049     if (parent()) {
2050         ts << style()->createDiff(*parent()->style());
2051     }
2052 
2053     if (isAnonymous()) {
2054         ts << " anonymousBox";
2055     }
2056     if (isFloating()) {
2057         ts << " floating";
2058     }
2059     if (isPositioned()) {
2060         ts << " positioned";
2061     }
2062     if (isRelPositioned()) {
2063         ts << " relPositioned";
2064     }
2065     if (isText()) {
2066         ts << " text";
2067     }
2068     if (isInline()) {
2069         ts << " inline";
2070     }
2071     if (isReplaced()) {
2072         ts << " replaced";
2073     }
2074     if (shouldPaintBackgroundOrBorder()) {
2075         ts << " paintBackground";
2076     }
2077     if (needsLayout()) {
2078         ts << " needsLayout";
2079     }
2080     if (minMaxKnown()) {
2081         ts << " minMaxKnown";
2082     }
2083     if (hasFirstLine()) {
2084         ts << " hasFirstLine";
2085     }
2086     if (afterPageBreak()) {
2087         ts << " afterPageBreak";
2088     }
2089 }
2090 
2091 void RenderObject::printLineBoxTree() const
2092 {
2093     RenderObject *child = firstChild();
2094     for (; child; child = child->nextSibling()) {
2095         child->printLineBoxTree();
2096     }
2097     if (isRenderBlock()) {
2098         const RenderBlock *block = static_cast<const RenderBlock *>(this);
2099         RootInlineBox *rootBox = block->firstRootBox();
2100         for (; rootBox; rootBox = rootBox->nextRootBox()) {
2101             rootBox->printTree();
2102         }
2103     }
2104 }
2105 #endif
2106 
2107 bool RenderObject::shouldSelect() const
2108 {
2109 #if 0 // ### merge
2110     const RenderObject *curr = this;
2111     DOM::NodeImpl *node = 0;
2112     bool forcedOn = false;
2113 
2114     while (curr) {
2115         if (curr->style()->userSelect() == SELECT_TEXT) {
2116             forcedOn = true;
2117         }
2118         if (!forcedOn && curr->style()->userSelect() == SELECT_NONE) {
2119             return false;
2120         }
2121 
2122         if (!node) {
2123             node = curr->element();
2124         }
2125         curr = curr->parent();
2126     }
2127 
2128     // somewhere up the render tree there must be an element!
2129     assert(node);
2130 
2131     return node->dispatchHTMLEvent(DOM::EventImpl::SELECTSTART_EVENT, true, true);
2132 #else
2133     return true;
2134 #endif
2135 }
2136 
2137 void RenderObject::selectionStartEnd(int &spos, int &epos)
2138 {
2139     if (parent()) {
2140         parent()->selectionStartEnd(spos, epos);
2141     }
2142 }
2143 
2144 void RenderObject::setStyle(RenderStyle *style)
2145 {
2146     if (m_style == style) {
2147         return;
2148     }
2149 
2150     RenderStyle::Diff d = m_style ? m_style->diff(style) : RenderStyle::Layout;
2151     //qDebug("m_style: %p new style, diff=%d", m_style,  d);
2152 
2153     Priority pri = NormalPriority;
2154     if (m_style) {
2155         pri = HighPriority;
2156         if (d >= RenderStyle::Visible && !isText() && m_parent &&
2157                 (d == RenderStyle::Position ||
2158                  m_style->outlineWidth() > style->outlineWidth() ||
2159                  (!m_style->hidesOverflow() && style->hidesOverflow()) ||
2160                  (m_style->hasClip() && !(m_style->clip() == style->clip())))) {
2161             // schedule a repaint with the old style
2162             if (layer() && !isInlineFlow()) {
2163                 layer()->repaint(pri);
2164             } else {
2165                 repaint(pri);
2166             }
2167         }
2168 
2169         if ((isFloating() && m_style->floating() != style->floating()) ||
2170                 (isPositioned() && m_style->position() != style->position() &&
2171                  style->position() != PABSOLUTE && style->position() != PFIXED)) {
2172             removeFromObjectLists();
2173         }
2174 
2175         if (layer()) {
2176             if ((m_style->hasAutoZIndex() != style->hasAutoZIndex() ||
2177                     m_style->zIndex() != style->zIndex() ||
2178                     m_style->visibility() != style->visibility())) {
2179                 layer()->stackingContext()->dirtyZOrderLists();
2180                 layer()->dirtyZOrderLists();
2181             }
2182             // keep layer hierarchy visibility bits up to date if visibility changes
2183             if (m_style->visibility() != style->visibility()) {
2184                 RenderLayer *l = enclosingLayer();
2185                 if (style->visibility() == VISIBLE && l) {
2186                     l->setHasVisibleContent(true);
2187                 } else if (l && l->hasVisibleContent() &&
2188                            (this == l->renderer() || l->renderer()->style()->visibility() != VISIBLE)) {
2189                     l->dirtyVisibleContentStatus();
2190                 }
2191             }
2192         }
2193 
2194         // reset style flags
2195         m_floating = false;
2196         m_positioned = false;
2197         m_relPositioned = false;
2198         m_paintBackground = false;
2199         m_hasOverflowClip = false;
2200     }
2201 
2202     // only honor z-index for non-static objects and objects with opacity
2203     if (style->position() == PSTATIC && style->opacity() == 1.0f) {
2204         style->setHasAutoZIndex();
2205     }
2206     // force establishment of a stacking context by transparent objects, as those define
2207     // the bounds of an atomically painted region.
2208     if (style->hasAutoZIndex() && (isRoot() || style->opacity() < 1.0f)) {
2209         style->setZIndex(0);
2210     }
2211 
2212     if (d > RenderStyle::Position &&
2213             (style->hasFixedBackgroundImage() != (m_style && m_style->hasFixedBackgroundImage())
2214              || (style->position() == PFIXED) != (m_style && (m_style->position() == PFIXED)))
2215             && canvas() && canvas()->view()) {
2216         // some sort of fixed object is added or removed. Let's find out more and report to the canvas,
2217         // so that it does some bookkeeping and optimizes the view's background display mode accordingly.
2218         bool fixedBG = style->hasFixedBackgroundImage();
2219         bool oldFixedBG = m_style && m_style->hasFixedBackgroundImage();
2220         bool fixedPos = (style->position() == PFIXED);
2221         bool oldFixedPos = m_style && (m_style->position() == PFIXED);
2222         if (fixedBG != oldFixedBG) {
2223             if (fixedBG) {
2224                 canvas()->addStaticObject(this);
2225             } else {
2226                 canvas()->removeStaticObject(this);
2227             }
2228         }
2229         if (fixedPos != oldFixedPos) {
2230             if (fixedPos) {
2231                 canvas()->addStaticObject(this, true /*positioned*/);
2232             } else {
2233                 canvas()->removeStaticObject(this, true);
2234             }
2235         }
2236     }
2237 
2238     RenderStyle *oldStyle = m_style;
2239     m_style = style;
2240 
2241     updateBackgroundImages(oldStyle);
2242 
2243     m_style->ref();
2244 
2245     if (oldStyle) {
2246         oldStyle->deref();
2247     }
2248 
2249     setShouldPaintBackgroundOrBorder(m_style->hasBorder() || m_style->hasBackground());
2250 
2251     m_hasFirstLine = (style->getPseudoStyle(RenderStyle::FIRST_LINE) != nullptr);
2252     if (m_parent) {
2253         if (d == RenderStyle::Position && !attemptDirectLayerTranslation()) {
2254             d = RenderStyle::Layout;
2255         }
2256 
2257         if (d > RenderStyle::Position) {
2258             // we must perform a full layout
2259             if (!isText() && d == RenderStyle::CbLayout) {
2260                 dirtyFormattingContext(true);
2261             }
2262             setNeedsLayoutAndMinMaxRecalc();
2263         } else if (!isText() && d >= RenderStyle::Visible) {
2264             // a repaint is enough
2265             if (layer()) {
2266                 if (canvas() && canvas()->needsWidgetMasks()) {
2267                     // update our widget masks
2268                     RenderLayer *p, *d = nullptr;
2269                     for (p = layer()->parent(); p; p = p->parent())
2270                         if (p->hasOverlaidWidgets()) {
2271                             d = p;
2272                         }
2273                     if (d) { // deepest
2274                         d->updateWidgetMasks(canvas()->layer());
2275                     }
2276                 }
2277             }
2278             if (layer() && !isInlineFlow()) {
2279                 layer()->repaint(pri);
2280             } else {
2281                 repaint(pri);
2282             }
2283         }
2284     }
2285 }
2286 
2287 bool RenderObject::attemptDirectLayerTranslation()
2288 {
2289     // When the difference between two successive styles is only 'Position'
2290     // we may attempt to save a layout by directly updating the object position.
2291 
2292     KHTMLAssert(m_style->position() != PSTATIC);
2293     if (!layer()) {
2294         return false;
2295     }
2296     setInline(m_style->isDisplayInlineType());
2297     setPositioned(m_style->position() != PRELATIVE);
2298     setRelPositioned(m_style->position() == PRELATIVE);
2299     int oldXPos = xPos();
2300     int oldYPos = yPos();
2301     int oldWidth = width();
2302     int oldHeight = height();
2303     calcWidth();
2304     calcHeight();
2305     if (oldWidth != width() || oldHeight != height()) {
2306         // implicit size change or overconstrained dimensions:
2307         // we'll need a layout.
2308         setWidth(oldWidth);
2309         setHeight(oldHeight);
2310         // qCDebug(KHTML_LOG) << "Layer translation failed for " << information();
2311         return false;
2312     }
2313     layer()->updateLayerPosition();
2314     if (m_style->position() != PFIXED) {
2315         bool needsDocSizeUpdate = true;
2316         RenderObject *cb = container();
2317         while (cb) {
2318             if (cb->hasOverflowClip() && cb->layer()) {
2319                 cb->layer()->checkScrollbarsAfterLayout();
2320                 needsDocSizeUpdate = false;
2321                 break;
2322             }
2323             cb = cb->container();
2324         }
2325         if (needsDocSizeUpdate && canvas()) {
2326             bool posXOffset = (xPos() - oldXPos >= 0);
2327             bool posYOffset = (yPos() - oldYPos >= 0);
2328             canvas()->updateDocSizeAfterLayerTranslation(this, posXOffset, posYOffset);
2329         }
2330     }
2331     // success
2332     return true;
2333 }
2334 
2335 void RenderObject::dirtyFormattingContext(bool checkContainer)
2336 {
2337     if (m_markedForRepaint && !checkContainer) {
2338         return;
2339     }
2340     m_markedForRepaint = true;
2341     if (layer() && (style()->position() == PFIXED || style()->position() == PABSOLUTE)) {
2342         return;
2343     }
2344     if (m_parent && (checkContainer || style()->width().isAuto() || style()->height().isAuto() ||
2345                      !(isFloating() || flowAroundFloats() || isTableCell()))) {
2346         m_parent->dirtyFormattingContext(false);
2347     }
2348 }
2349 
2350 void RenderObject::repaintDuringLayout()
2351 {
2352     if (canvas()->needsFullRepaint() || isText()) {
2353         return;
2354     }
2355     if (layer() && !isInlineFlow()) {
2356         layer()->repaint(NormalPriority, true);
2357     } else {
2358         repaint();
2359         canvas()->deferredRepaint(this);
2360     }
2361 }
2362 
2363 void RenderObject::updateBackgroundImages(RenderStyle *oldStyle)
2364 {
2365     // FIXME: This will be slow when a large number of images is used.  Fix by using a dict.
2366     const BackgroundLayer *oldLayers = oldStyle ? oldStyle->backgroundLayers() : nullptr;
2367     const BackgroundLayer *newLayers = m_style ? m_style->backgroundLayers() : nullptr;
2368     for (const BackgroundLayer *currOld = oldLayers; currOld; currOld = currOld->next()) {
2369         if (currOld->backgroundImage() && (!newLayers || !newLayers->containsImage(currOld->backgroundImage()))) {
2370             currOld->backgroundImage()->deref(this);
2371         }
2372     }
2373     for (const BackgroundLayer *currNew = newLayers; currNew; currNew = currNew->next()) {
2374         if (currNew->backgroundImage() && (!oldLayers || !oldLayers->containsImage(currNew->backgroundImage()))) {
2375             currNew->backgroundImage()->ref(this);
2376         }
2377     }
2378 }
2379 
2380 QRect RenderObject::viewRect() const
2381 {
2382     return containingBlock()->viewRect();
2383 }
2384 
2385 bool RenderObject::absolutePosition(int &xPos, int &yPos, bool f) const
2386 {
2387     RenderObject *p = parent();
2388     if (p) {
2389         p->absolutePosition(xPos, yPos, f);
2390         if (p->hasOverflowClip()) {
2391             p->layer()->subtractScrollOffset(xPos, yPos);
2392         }
2393         return true;
2394     } else {
2395         xPos = yPos = 0;
2396         return false;
2397     }
2398 }
2399 
2400 void RenderObject::caretPos(int /*offset*/, int /*flags*/, int &_x, int &_y, int &width, int &height) const
2401 {
2402     _x = _y = height = -1;
2403     width = 1;        // the caret has a default width of one pixel. If you want
2404     // to check for validity, only test the x-coordinate for >= 0.
2405 }
2406 
2407 int RenderObject::paddingTop() const
2408 {
2409     int w = 0;
2410     Length padding = m_style->paddingTop();
2411     if (padding.isPercent()) {
2412         w = containingBlock()->contentWidth();
2413     }
2414     w = padding.minWidth(w);
2415     if (isTableCell() && padding.isAuto()) {
2416         w = static_cast<const RenderTableCell *>(this)->table()->cellPadding();
2417     }
2418     return w;
2419 }
2420 
2421 int RenderObject::paddingBottom() const
2422 {
2423     int w = 0;
2424     Length padding = style()->paddingBottom();
2425     if (padding.isPercent()) {
2426         w = containingBlock()->contentWidth();
2427     }
2428     w = padding.minWidth(w);
2429     if (isTableCell() && padding.isAuto()) {
2430         w = static_cast<const RenderTableCell *>(this)->table()->cellPadding();
2431     }
2432     return w;
2433 }
2434 
2435 int RenderObject::paddingLeft() const
2436 {
2437     int w = 0;
2438     Length padding = style()->paddingLeft();
2439     if (padding.isPercent()) {
2440         w = containingBlock()->contentWidth();
2441     }
2442     w = padding.minWidth(w);
2443     if (isTableCell() && padding.isAuto()) {
2444         w = static_cast<const RenderTableCell *>(this)->table()->cellPadding();
2445     }
2446     return w;
2447 }
2448 
2449 int RenderObject::paddingRight() const
2450 {
2451     int w = 0;
2452     Length padding = style()->paddingRight();
2453     if (padding.isPercent()) {
2454         w = containingBlock()->contentWidth();
2455     }
2456     w = padding.minWidth(w);
2457     if (isTableCell() && padding.isAuto()) {
2458         w = static_cast<const RenderTableCell *>(this)->table()->cellPadding();
2459     }
2460     return w;
2461 }
2462 
2463 RenderObject *RenderObject::container() const
2464 {
2465     // This method is extremely similar to containingBlock(), but with a few notable
2466     // exceptions.
2467     // (1) It can be used on orphaned subtrees, i.e., it can be called safely even when
2468     // the object is not part of the primary document subtree yet.
2469     // (2) For normal flow elements, it just returns the parent.
2470     // (3) For absolute positioned elements, it will return a relative positioned inline.
2471     // containingBlock() simply skips relpositioned inlines and lets an enclosing block handle
2472     // the layout of the positioned object.  This does mean that calcAbsoluteHorizontal and
2473     // calcAbsoluteVertical have to use container().
2474     EPosition pos = m_style->position();
2475     RenderObject *o = nullptr;
2476     if (pos == PFIXED) {
2477         // container() can be called on an object that is not in the
2478         // tree yet.  We don't call canvas() since it will assert if it
2479         // can't get back to the canvas.  Instead we just walk as high up
2480         // as we can.  If we're in the tree, we'll get the root.  If we
2481         // aren't we'll get the root of our little subtree (most likely
2482         // we'll just return 0).
2483         o = parent();
2484         while (o && o->parent()) {
2485             o = o->parent();
2486         }
2487     } else if (pos == PABSOLUTE) {
2488         // Same goes here.  We technically just want our containing block, but
2489         // we may not have one if we're part of an uninstalled subtree.  We'll
2490         // climb as high as we can though.
2491         o = parent();
2492         while (o && o->style()->position() == PSTATIC && !o->isCanvas()) {
2493             o = o->parent();
2494         }
2495     } else {
2496         o = parent();
2497     }
2498     return o;
2499 }
2500 
2501 DOM::DocumentImpl *RenderObject::document() const
2502 {
2503     return m_node->document();
2504 }
2505 
2506 void RenderObject::removeFromObjectLists()
2507 {
2508     // in destruction mode, don't care.
2509     if (documentBeingDestroyed()) {
2510         return;
2511     }
2512 
2513     if (isFloating()) {
2514         RenderBlock *outermostBlock = containingBlock();
2515         for (RenderBlock *p = outermostBlock; p && !p->isCanvas() && p->containsFloat(this);) {
2516             outermostBlock = p;
2517             if (p->isFloatingOrPositioned()) {
2518                 break;
2519             }
2520             p = p->containingBlock();
2521         }
2522 
2523         if (outermostBlock) {
2524             outermostBlock->markAllDescendantsWithFloatsForLayout(this);
2525         }
2526 
2527         RenderObject *p;
2528         for (p = parent(); p; p = p->parent()) {
2529             if (p->isRenderBlock()) {
2530                 static_cast<RenderBlock *>(p)->removeFloatingObject(this);
2531             }
2532         }
2533 
2534     }
2535 
2536     if (inPosObjectList()) {
2537         RenderObject *p;
2538         for (p = parent(); p; p = p->parent()) {
2539             if (p->isRenderBlock()) {
2540                 static_cast<RenderBlock *>(p)->removePositionedObject(this);
2541             }
2542         }
2543     }
2544 }
2545 
2546 RenderArena *RenderObject::renderArena() const
2547 {
2548     return m_node->document()->renderArena();
2549 }
2550 
2551 void RenderObject::detach()
2552 {
2553     detachCounters();
2554     remove();
2555 
2556     // make sure our DOM-node don't think we exist
2557     if (node() && node()->renderer() == this) {
2558         node()->setRenderer(nullptr);
2559     }
2560 
2561     // by default no refcounting
2562     arenaDelete(renderArena(), this);
2563 }
2564 
2565 void RenderObject::remove()
2566 {
2567     if (m_parent) {
2568         m_parent->removeChild(this);
2569         if (isFloating() || inPosObjectList()) {
2570             removeFromObjectLists();
2571         }
2572     }
2573 }
2574 
2575 void RenderObject::arenaDelete(RenderArena *arena, void *base)
2576 {
2577 #ifndef NDEBUG
2578     void *savedBase = baseOfRenderObjectBeingDeleted;
2579     baseOfRenderObjectBeingDeleted = base;
2580 #endif
2581     delete this;
2582 #ifndef NDEBUG
2583     baseOfRenderObjectBeingDeleted = savedBase;
2584 #endif
2585 
2586     // Recover the size left there for us by operator delete and free the memory.
2587     arena->free(*(size_t *)base, base);
2588 }
2589 
2590 void RenderObject::arenaDelete(RenderArena *arena)
2591 {
2592     // static_cast unfortunately doesn't work, since we multiple inherit
2593     // in eg. RenderWidget.
2594     arenaDelete(arena, dynamic_cast<void *>(this));
2595 }
2596 
2597 RenderPosition RenderObject::positionForCoordinates(int /*x*/, int /*y*/)
2598 {
2599     return RenderPosition(element(), caretMinOffset());
2600 }
2601 
2602 bool RenderObject::isPointInsideSelection(int x, int y, const Selection &sel) const
2603 {
2604     SelectionState selstate = selectionState();
2605     if (selstate == SelectionInside) {
2606         return true;
2607     }
2608     if (selstate == SelectionNone || !element()) {
2609         return false;
2610     }
2611     return element()->isPointInsideSelection(x, y, sel);
2612 }
2613 
2614 #if 0
2615 FindSelectionResult RenderObject::checkSelectionPoint(int _x, int _y, int _tx, int _ty, DOM::NodeImpl *&node, int &offset, SelPointState &state)
2616 {
2617 #if 0
2618     NodeInfo info(true, false);
2619     if (nodeAtPoint(info, _x, _y, _tx, _ty) && info.innerNode()) {
2620         RenderObject *r = info.innerNode()->renderer();
2621         if (r) {
2622             if (r == this) {
2623                 node = info.innerNode();
2624                 offset = 0; // we have no text...
2625                 return SelectionPointInside;
2626             } else {
2627                 return r->checkSelectionPoint(_x, _y, _tx, _ty, node, offset, state);
2628             }
2629         }
2630     }
2631     //qCDebug(KHTML_LOG) << "nodeAtPoint Failed. Fallback - hmm, SelectionPointAfter";
2632     node = 0;
2633     offset = 0;
2634     return SelectionPointAfter;
2635 #endif
2636     int off = offset;
2637     DOM::NodeImpl *nod = node;
2638 
2639     for (RenderObject *child = firstChild(); child; child = child->nextSibling()) {
2640         // ignore empty text boxes, they produce totally bogus information
2641         // for caret navigation (LS)
2642         if (child->isText() && !static_cast<RenderText *>(child)->firstTextBox()) {
2643             continue;
2644         }
2645 
2646 //        qCDebug(KHTML_LOG) << "iterating " << (child ? child->renderName() : "") << "@" << child << (child->isText() ? " contains: \"" + QString::fromRawData(static_cast<RenderText *>(child)->text(), qMin(static_cast<RenderText *>(child)->length(), 10u)) + "\"" : QString());
2647 //        qCDebug(KHTML_LOG) << "---------- checkSelectionPoint recursive -----------";
2648         khtml::FindSelectionResult pos = child->checkSelectionPoint(_x, _y, _tx + xPos(), _ty + yPos(), nod, off, state);
2649 //        qCDebug(KHTML_LOG) << "-------- end checkSelectionPoint recursive ---------";
2650 //        qCDebug(KHTML_LOG) << this << " child->findSelectionNode returned result=" << pos << " nod=" << nod << " off=" << off;
2651         switch (pos) {
2652         case SelectionPointBeforeInLine:
2653         case SelectionPointInside:
2654             //qCDebug(KHTML_LOG) << "RenderObject::checkSelectionPoint " << this << " returning SelectionPointInside offset=" << offset;
2655             node = nod;
2656             offset = off;
2657             return SelectionPointInside;
2658         case SelectionPointBefore:
2659             //x,y is before this element -> stop here
2660             if (state.m_lastNode) {
2661                 node = state.m_lastNode;
2662                 offset = state.m_lastOffset;
2663                 //qCDebug(KHTML_LOG) << "RenderObject::checkSelectionPoint " << this << " before this child "
2664                 //              << node << "-> returning SelectionPointInside, offset=" << offset;
2665                 return SelectionPointInside;
2666             } else {
2667                 node = nod;
2668                 offset = off;
2669                 //qCDebug(KHTML_LOG) << "RenderObject::checkSelectionPoint " << this << " before us -> returning SelectionPointBefore " << node << "/" << offset;
2670                 return SelectionPointBefore;
2671             }
2672             break;
2673         case SelectionPointAfter:
2674             if (state.m_afterInLine) {
2675                 break;
2676             }
2677         // fall through
2678         case SelectionPointAfterInLine:
2679             if (pos == SelectionPointAfterInLine) {
2680                 state.m_afterInLine = true;
2681             }
2682             //qCDebug(KHTML_LOG) << "RenderObject::checkSelectionPoint: selection after: " << nod << " offset: " << off << " afterInLine: " << state.m_afterInLine;
2683             state.m_lastNode = nod;
2684             state.m_lastOffset = off;
2685             // No "return" here, obviously. We must keep looking into the children.
2686             break;
2687         }
2688     }
2689     // If we are after the last child, return lastNode/lastOffset
2690     // But lastNode can be 0L if there is no child, for instance.
2691     if (state.m_lastNode) {
2692         node = state.m_lastNode;
2693         offset = state.m_lastOffset;
2694     }
2695     //qCDebug(KHTML_LOG) << "fallback - SelectionPointAfter  node=" << node << " offset=" << offset;
2696     return SelectionPointAfter;
2697 }
2698 #endif
2699 
2700 bool RenderObject::mouseInside() const
2701 {
2702     if (!m_mouseInside && continuation()) {
2703         return continuation()->mouseInside();
2704     }
2705     return m_mouseInside;
2706 }
2707 
2708 bool RenderObject::nodeAtPoint(NodeInfo &info, int _x, int _y, int _tx, int _ty, HitTestAction hitTestAction, bool inside)
2709 {
2710     int tx = _tx + xPos();
2711     int ty = _ty + yPos();
2712 
2713     inside |= (style()->visibility() != HIDDEN &&
2714                (_y >= ty) && (_y < ty + height()) && (_x >= tx) && (_x < tx + width())) || isRoot() || isBody();
2715     bool inOverflowRect = inside;
2716     if (!inOverflowRect) {
2717         int ol = overflowLeft();
2718         int ot = overflowTop();
2719         QRect overflowRect(tx + ol, ty + ot, overflowWidth() - ol, overflowHeight() - ot);
2720         inOverflowRect = overflowRect.contains(_x, _y);
2721     }
2722 
2723     // ### table should have its own, more performant method
2724     if (hitTestAction != HitTestSelfOnly &&
2725             ((!isRenderBlock() ||
2726               !static_cast<RenderBlock *>(this)->isPointInScrollbar(_x, _y, _tx, _ty)) &&
2727              (inOverflowRect || isInline() || isRoot() || isCanvas() ||
2728               isTableRow() || isTableSection() || inside || mouseInside()))) {
2729         if (hitTestAction == HitTestChildrenOnly) {
2730             inside = false;
2731         }
2732         if (hasOverflowClip() && layer()) {
2733             layer()->subtractScrollOffset(tx, ty);
2734         }
2735         for (RenderObject *child = lastChild(); child; child = child->previousSibling())
2736             if (!child->layer() && child->nodeAtPoint(info, _x, _y, tx, ty, HitTestAll)) {
2737                 inside = true;
2738             }
2739     }
2740 
2741     if (inside) {
2742         setInnerNode(info);
2743     }
2744 
2745     return inside;
2746 }
2747 
2748 void RenderObject::setInnerNode(NodeInfo &info)
2749 {
2750     if (!info.innerNode() && !isInline() && continuation()) {
2751         // We are in the margins of block elements that are part of a continuation.  In
2752         // this case we're actually still inside the enclosing inline element that was
2753         // split.  Go ahead and set our inner node accordingly.
2754         info.setInnerNode(continuation()->element());
2755         if (!info.innerNonSharedNode()) {
2756             info.setInnerNonSharedNode(continuation()->element());
2757         }
2758     }
2759 
2760     if (!info.innerNode() && element()) {
2761         info.setInnerNode(element());
2762     }
2763 
2764     if (!info.innerNonSharedNode() && element()) {
2765         info.setInnerNonSharedNode(element());
2766     }
2767 }
2768 
2769 short RenderObject::verticalPositionHint(bool firstLine) const
2770 {
2771     short vpos = m_verticalPosition;
2772     if (m_verticalPosition == PositionUndefined || firstLine) {
2773         vpos = getVerticalPosition(firstLine);
2774         if (!firstLine) {
2775             const_cast<RenderObject *>(this)->m_verticalPosition = vpos;
2776         }
2777     }
2778     return vpos;
2779 
2780 }
2781 
2782 short RenderObject::getVerticalPosition(bool firstLine, RenderObject *ref) const
2783 {
2784     // vertical align for table cells has a different meaning
2785     int vpos = 0;
2786     if (!isTableCell() && isInline()) {
2787         EVerticalAlign va = style()->verticalAlign();
2788         if (va == TOP) {
2789             vpos = PositionTop;
2790         } else if (va == BOTTOM) {
2791             vpos = PositionBottom;
2792         } else {
2793             if (!ref) {
2794                 ref = parent();
2795             }
2796             bool checkParent = ref->isInline() && !ref->isReplacedBlock() &&
2797                                !(ref->style()->verticalAlign() == TOP || ref->style()->verticalAlign() == BOTTOM);
2798             vpos = checkParent ? ref->verticalPositionHint(firstLine) : 0;
2799             // don't allow elements nested inside text-top to have a different valignment.
2800             if (va == BASELINE) {
2801                 return vpos;
2802             } else if (va == LENGTH) {
2803                 return vpos - style()->verticalAlignLength().width(lineHeight(firstLine));
2804             }
2805 
2806             const QFont &f = ref->font(firstLine);
2807             int fontsize = f.pixelSize();
2808 
2809             if (va == SUB) {
2810                 vpos += fontsize / 5 + 1;
2811             } else if (va == SUPER) {
2812                 vpos -= fontsize / 3 + 1;
2813             } else if (va == TEXT_TOP) {
2814                 vpos += baselinePosition(firstLine) - (QFontMetrics(f).ascent() + QFontMetrics(f).leading() / 2);
2815             } else if (va == MIDDLE) {
2816                 QRect b = QFontMetrics(f).boundingRect('x');
2817                 vpos += -b.height() / 2 - lineHeight(firstLine) / 2 + baselinePosition(firstLine);
2818             } else if (va == TEXT_BOTTOM) {
2819                 vpos += QFontMetrics(f).descent() + QFontMetrics(f).leading() / 2;
2820                 if (!isReplaced()) {
2821                     vpos -= (lineHeight(firstLine) - baselinePosition(firstLine));
2822                 }
2823             } else if (va == BASELINE_MIDDLE) {
2824                 vpos += - lineHeight(firstLine) / 2 + baselinePosition(firstLine);
2825             }
2826         }
2827     }
2828     return vpos;
2829 }
2830 
2831 short RenderObject::lineHeight(bool firstLine) const
2832 {
2833     // Inline blocks are replaced elements. Otherwise, just pass off to
2834     // the base class.  If we're being queried as though we're the root line
2835     // box, then the fact that we're an inline-block is irrelevant, and we behave
2836     // just like a block.
2837 
2838     if (isReplaced() && (!isInlineBlockOrInlineTable() || !needsLayout())) {
2839         return height() + marginTop() + marginBottom();
2840     }
2841 
2842     Length lh;
2843     if (firstLine && hasFirstLine()) {
2844         RenderStyle *pseudoStyle  = style()->getPseudoStyle(RenderStyle::FIRST_LINE);
2845         if (pseudoStyle) {
2846             lh = pseudoStyle->lineHeight();
2847         }
2848     } else {
2849         lh = style()->lineHeight();
2850     }
2851 
2852     // its "unset", choose nice default
2853     if (lh.isNegative()) {
2854         return style()->htmlFont().lineSpacing();
2855     }
2856 
2857     if (lh.isPercent()) {
2858         return lh.minWidth(style()->font().pixelSize());
2859     }
2860 
2861     // its fixed
2862     return lh.value();
2863 }
2864 
2865 short RenderObject::baselinePosition(bool firstLine) const
2866 {
2867     // If we're an inline-block and need layout, it means our replaced boundaries
2868     // are not yet fully established, so we behave just like a block.
2869     if (isReplaced() && (!isInlineBlockOrInlineTable() || !needsLayout())) {
2870         return height() + marginTop() + marginBottom();
2871     }
2872 
2873     const QFontMetrics &fm = fontMetrics(firstLine);
2874     return fm.ascent() + (lineHeight(firstLine) - fm.height()) / 2;
2875 }
2876 
2877 void RenderObject::invalidateVerticalPosition()
2878 {
2879     m_verticalPosition = PositionUndefined;
2880 }
2881 
2882 void RenderObject::recalcMinMaxWidths()
2883 {
2884     KHTMLAssert(m_recalcMinMax);
2885 
2886 #ifdef DEBUG_LAYOUT
2887     qCDebug(KHTML_LOG) << renderName() << " recalcMinMaxWidths() this=" << this;
2888 #endif
2889 
2890     RenderObject *child = firstChild();
2891     int cmin = 0;
2892     int cmax = 0;
2893 
2894     while (child) {
2895         bool test = false;
2896         if ((m_minMaxKnown && child->m_recalcMinMax) || !child->m_minMaxKnown) {
2897             cmin = child->minWidth();
2898             cmax = child->maxWidth();
2899             test = true;
2900         }
2901         if (child->m_recalcMinMax) {
2902             child->recalcMinMaxWidths();
2903         }
2904         if (!child->m_minMaxKnown) {
2905             child->calcMinMaxWidth();
2906         }
2907         if (m_minMaxKnown && test && (cmin != child->minWidth() || cmax != child->maxWidth())) {
2908             m_minMaxKnown = false;
2909         }
2910         child = child->nextSibling();
2911     }
2912 
2913     // we need to recalculate, if the contains inline children, as the change could have
2914     // happened somewhere deep inside the child tree
2915     if ((!isInline() || isReplacedBlock()) && childrenInline()) {
2916         m_minMaxKnown = false;
2917     }
2918 
2919     if (!m_minMaxKnown) {
2920         calcMinMaxWidth();
2921     }
2922     m_recalcMinMax = false;
2923 }
2924 
2925 void RenderObject::scheduleRelayout(RenderObject *clippedObj)
2926 {
2927     if (!isCanvas()) {
2928         return;
2929     }
2930     KHTMLView *view = static_cast<RenderCanvas *>(this)->view();
2931     if (view) {
2932         view->scheduleRelayout(clippedObj);
2933     }
2934 }
2935 
2936 InlineBox *RenderObject::createInlineBox(bool /*makePlaceHolderBox*/, bool /*isRootLineBox*/)
2937 {
2938     KHTMLAssert(false);
2939     return nullptr;
2940 }
2941 
2942 void RenderObject::getTextDecorationColors(int decorations, QColor &underline, QColor &overline,
2943         QColor &linethrough, bool quirksMode)
2944 {
2945     RenderObject *curr = this;
2946     do {
2947         RenderStyle *st = curr->style();
2948         int currDecs = st->textDecoration();
2949         if (currDecs) {
2950             if (currDecs & UNDERLINE) {
2951                 decorations &= ~UNDERLINE;
2952                 underline = st->color();
2953             }
2954             if (currDecs & OVERLINE) {
2955                 decorations &= ~OVERLINE;
2956                 overline = st->color();
2957             }
2958             if (currDecs & LINE_THROUGH) {
2959                 decorations &= ~LINE_THROUGH;
2960                 linethrough = st->color();
2961             }
2962         }
2963         curr = curr->parent();
2964         if (curr && curr->isRenderBlock() && curr->continuation()) {
2965             curr = curr->continuation();
2966         }
2967     } while (curr && decorations && (!quirksMode || !curr->element() ||
2968                                      (curr->element()->id() != ID_A && curr->element()->id() != ID_FONT)));
2969 
2970     // If we bailed out, use the element we bailed out at (typically a <font> or <a> element).
2971     if (decorations && curr) {
2972         RenderStyle *st = curr->style();
2973         if (decorations & UNDERLINE) {
2974             underline = st->color();
2975         }
2976         if (decorations & OVERLINE) {
2977             overline = st->color();
2978         }
2979         if (decorations & LINE_THROUGH) {
2980             linethrough = st->color();
2981         }
2982     }
2983 }
2984 
2985 int RenderObject::maximalOutlineSize(PaintAction p) const
2986 {
2987     if (p != PaintActionOutline) {
2988         return 0;
2989     }
2990     return static_cast<RenderCanvas *>(document()->renderer())->maximalOutlineSize();
2991 }
2992 
2993 void RenderObject::collectBorders(QList<CollapsedBorderValue> &borderStyles)
2994 {
2995     for (RenderObject *curr = firstChild(); curr; curr = curr->nextSibling()) {
2996         curr->collectBorders(borderStyles);
2997     }
2998 }
2999 
3000 bool RenderObject::flowAroundFloats() const
3001 {
3002     return isReplaced() || hasOverflowClip() || style()->flowAroundFloats();
3003 }
3004 
3005 bool RenderObject::usesLineWidth() const
3006 {
3007     // All auto-width objects that avoid floats should always use lineWidth
3008     // unless they are floating or inline. We only care about objects that grow
3009     // to fill the available space.
3010     return (!isInline() || isHTMLMarquee()) && flowAroundFloats() && style()->width().isAuto() && !isFloating();
3011 }
3012 
3013 long RenderObject::caretMinOffset() const
3014 {
3015     return 0;
3016 }
3017 
3018 long RenderObject::caretMaxOffset() const
3019 {
3020     return 0;
3021 }
3022 
3023 unsigned long RenderObject::caretMaxRenderedOffset() const
3024 {
3025     return 0;
3026 }
3027 
3028 InlineBox *RenderObject::inlineBox(long /*offset*/)
3029 {
3030     if (isBox()) {
3031         return static_cast<RenderBox *>(this)->placeHolderBox();
3032     }
3033     return nullptr;
3034 }
3035 
3036 bool RenderObject::hasCounter(const DOMString &counter) const
3037 {
3038     if (style() && (!isText() || isCounter())) {
3039         if (lookupCounter(counter)) {
3040             return true;
3041         }
3042         if (style()->hasCounterReset(counter)) {
3043             return true;
3044         } else if (style()->hasCounterIncrement(counter)) {
3045             return true;
3046         }
3047     }
3048     if (counter == "list-item") {
3049         if (isListItem()) {
3050             return true;
3051         }
3052         if (element() && (
3053                     element()->id() == ID_OL ||
3054                     element()->id() == ID_UL ||
3055                     element()->id() == ID_MENU ||
3056                     element()->id() == ID_DIR)) {
3057             return true;
3058         }
3059     } else if (counter == "-khtml-quotes" && isQuote()) {
3060         return (static_cast<const RenderQuote *>(this)->quoteCount() != 0);
3061     }
3062     return false;
3063 }
3064 
3065 CounterNode *RenderObject::getCounter(const DOMString &counter, bool view, bool counters)
3066 {
3067 //     qCDebug(KHTML_LOG) << renderName() << " getCounter(" << counter << ")";
3068 
3069     if (!style()) {
3070         return nullptr;
3071     }
3072 
3073     if (isText() && !isCounter()) {
3074         return nullptr;
3075     }
3076 
3077     CounterNode *i = lookupCounter(counter);
3078     if (i) {
3079         return i;
3080     }
3081     int val = 0;
3082 
3083     if (style()->hasCounterReset(counter) || isRoot()) {
3084         i = new CounterReset(this);
3085         val = style()->counterReset(counter);
3086         if (style()->hasCounterIncrement(counter)) {
3087             val += style()->counterIncrement(counter);
3088         }
3089 //         qCDebug(KHTML_LOG) << renderName() << " counter-reset: " << counter << " " << val;
3090     } else if (style()->hasCounterIncrement(counter)) {
3091         i = new CounterNode(this);
3092         val = style()->counterIncrement(counter);
3093 //         qCDebug(KHTML_LOG) << renderName() << " counter-increment: " << counter << " " << val;
3094     } else if (counter == "list-item") {
3095         if (isListItem()) {
3096             if (element() && element()->id() == ID_LI) {
3097                 DOMString v = static_cast<ElementImpl *>(element())->getAttribute(ATTR_VALUE);
3098                 if (!v.isEmpty()) {
3099                     i = new CounterReset(this);
3100                     val = v.toInt();
3101 //                     qCDebug(KHTML_LOG) << renderName() << " counter-reset: " << counter << " " << val;
3102                 }
3103             }
3104             if (!i) {
3105                 i = new CounterNode(this);
3106                 val = 1;
3107 //                 qCDebug(KHTML_LOG) << renderName() << " counter-increment: " << counter << " " << val;
3108             }
3109         } else if (element() && element()->id() == ID_OL) {
3110             i = new CounterReset(this);
3111             DOMString v = static_cast<ElementImpl *>(element())->getAttribute(ATTR_START);
3112             if (!v.isEmpty()) {
3113                 val = v.toInt() - 1;
3114             } else {
3115                 val = 0;
3116             }
3117 //             qCDebug(KHTML_LOG) << renderName() << " counter-reset: " << counter << " " << val;
3118         } else if (element() &&
3119                    (element()->id() == ID_UL ||
3120                     element()->id() == ID_MENU ||
3121                     element()->id() == ID_DIR)) {
3122             i = new CounterReset(this);
3123             val = 0;
3124 //             qCDebug(KHTML_LOG) << renderName() << " counter-reset: " << counter << " " << val;
3125         }
3126     } else if (counter == "-khtml-quotes" && isQuote()) {
3127         i = new CounterNode(this);
3128         val = static_cast<RenderQuote *>(this)->quoteCount();
3129     }
3130 
3131     if (!i) {
3132         i = new CounterNode(this);
3133         val = 0;
3134 //         qCDebug(KHTML_LOG) << renderName() << " counter-increment: " << counter << " " << val;
3135     }
3136     i->setValue(val);
3137     if (view) {
3138         i->setIsVisual();
3139     }
3140     if (counters) {
3141         i->setHasCounters();
3142     }
3143 
3144     insertCounter(counter, i);
3145 
3146     if (!isRoot()) {
3147         CounterNode *last = nullptr, *current = nullptr;
3148         RenderObject *n = previousSibling();
3149         while (n) {
3150             if (n->hasCounter(counter)) {
3151                 current = n->getCounter(counter);
3152                 break;
3153             } else {
3154                 n = n->previousSibling();
3155             }
3156         }
3157         last = current;
3158 
3159         CounterNode *sibling = current;
3160         // counter-reset on same render-level is our counter-parent
3161         if (last) {
3162             // Found render-sibling, now search for later counter-siblings among its render-children
3163             n = n->lastChild();
3164             while (n) {
3165                 if (n->hasCounter(counter)) {
3166                     current = n->getCounter(counter);
3167                     if (last->parent() == current->parent() || sibling == current->parent()) {
3168                         last = current;
3169                         // If the current counter is not the last, search deeper
3170                         if (current->nextSibling()) {
3171                             n = n->lastChild();
3172                             continue;
3173                         } else {
3174                             break;
3175                         }
3176                     }
3177                 }
3178                 n = n->previousSibling();
3179             }
3180             if (sibling->isReset()) {
3181                 if (last != sibling) {
3182                     sibling->insertAfter(i, last);
3183                 } else {
3184                     sibling->insertAfter(i, nullptr);
3185                 }
3186             } else if (last->parent()) {
3187                 last->parent()->insertAfter(i, last);
3188             }
3189         } else if (parent()) {
3190             // Nothing found among siblings, let our parent search
3191             last = parent()->getCounter(counter, false);
3192             if (last->isReset()) {
3193                 last->insertAfter(i, nullptr);
3194             } else if (last->parent()) {
3195                 last->parent()->insertAfter(i, last);
3196             }
3197         }
3198     }
3199 
3200     return i;
3201 }
3202 
3203 CounterNode *RenderObject::lookupCounter(const DOMString &counter) const
3204 {
3205     QHash<DOMString, khtml::CounterNode *> *counters = document()->counters(this);
3206     return counters ? counters->value(counter) : nullptr;
3207 }
3208 
3209 void RenderObject::detachCounters()
3210 {
3211     QHash<DOMString, khtml::CounterNode *> *counters = document()->counters(this);
3212     if (!counters) {
3213         return;
3214     }
3215 
3216     QHashIterator<DOMString, khtml::CounterNode *> i(*counters);
3217 
3218     while (i.hasNext()) {
3219         i.next();
3220         i.value()->remove();
3221         delete i.value();
3222     }
3223     document()->removeCounters(this);
3224 }
3225 
3226 void RenderObject::insertCounter(const DOMString &counter, CounterNode *val)
3227 {
3228     QHash<DOMString, khtml::CounterNode *> *counters = document()->counters(this);
3229 
3230     if (!counters) {
3231         counters = new QHash<DOMString, khtml::CounterNode *>();
3232         document()->setCounters(this, counters);
3233     }
3234 
3235     counters->insert(counter, val);
3236 }
3237 
3238 void RenderObject::updateWidgetMasks()
3239 {
3240     for (RenderObject *curr = firstChild(); curr; curr = curr->nextSibling()) {
3241         if (curr->isWidget() && static_cast<RenderWidget *>(curr)->needsMask()) {
3242             QWidget *w = static_cast<RenderWidget *>(curr)->widget();
3243             if (!w) {
3244                 return;
3245             }
3246             RenderLayer *l = curr->enclosingStackingContext();
3247             QRegion r = l ? l->getMask() : QRegion();
3248             int x, y;
3249             if (!r.isEmpty() && curr->absolutePosition(x, y)) {
3250                 int pbx = curr->borderLeft() + curr->paddingLeft();
3251                 int pby = curr->borderTop() + curr->paddingTop();
3252                 x += pbx;
3253                 y += pby;
3254                 r = r.intersect(QRect(x, y,
3255                                       curr->width() - pbx - curr->borderRight() - curr->paddingRight(),
3256                                       curr->height() - pby - curr->borderBottom() - curr->paddingBottom()));
3257 #ifdef MASK_DEBUG
3258                 QVector<QRect> ar = r.rects();
3259                 qCDebug(KHTML_LOG) << "|| Setting widget mask for " << curr->information();
3260                 for (int i = 0; i < ar.size(); ++i) {
3261                     qCDebug(KHTML_LOG) << "     " <<  ar[i];
3262                 }
3263 #endif
3264                 r.translate(-x, -y);
3265 
3266                 // ### Scrollarea's widget doesn't update when mask change.
3267                 // Might be a Qt bug. Might be the way we handle updates. Investigate.
3268                 if (::qobject_cast<QScrollArea *>(w)) {
3269                     QScrollArea *sa = static_cast<QScrollArea *>(w);
3270                     if (!w->mask().isEmpty()) {
3271                         QPoint off(sa->horizontalScrollBar()->value(),
3272                                    sa->verticalScrollBar()->value());
3273                         sa->widget()->update(w->mask().translated(off));
3274                         sa->horizontalScrollBar()->update();
3275                         sa->verticalScrollBar()->update();
3276                     }
3277                 }
3278                 w->setMask(r);
3279             } else {
3280                 w->clearMask();
3281             }
3282         } else if (!curr->layer() || !curr->layer()->isStackingContext()) {
3283             curr->updateWidgetMasks();
3284         }
3285 
3286     }
3287 }
3288 
3289 QRegion RenderObject::visibleFlowRegion(int x, int y) const
3290 {
3291     QRegion r;
3292     bool returnSelf = false;
3293     for (RenderObject *ro = firstChild(); ro; ro = ro->nextSibling()) {
3294         if (!ro->layer() && !ro->isFloating() && ro->style()->visibility() == VISIBLE) {
3295             const RenderStyle *s = ro->style();
3296             int ow = s->outlineSize();
3297             if (ro->isInlineFlow() || ro->isText()) {
3298                 returnSelf = true;
3299                 break;
3300             }
3301             if (s->backgroundImage() || s->backgroundColor().isValid() || s->hasBorder() || ro->isReplaced() || ow) {
3302                 r += QRect(x - ow + ro->effectiveXPos(), y - ow + ro->effectiveYPos(),
3303                            ro->effectiveWidth() + ow * 2, ro->effectiveHeight() + ow * 2);
3304             } else {
3305                 r += ro->visibleFlowRegion(x + ro->xPos(), y + ro->yPos());
3306             }
3307         }
3308     }
3309     if (hasFloats()) {
3310         r += static_cast<const RenderBlock *>(this)->visibleFloatingRegion(x, y);
3311     }
3312     if (returnSelf) {
3313         int ow = style()->outlineSize();
3314         r += QRect(x - xPos() - ow + effectiveXPos(), y - yPos() - ow + effectiveYPos(),
3315                    effectiveWidth() + ow * 2, effectiveHeight() + ow * 2);
3316     }
3317     return r;
3318 }
3319 
3320 // SVG
3321 FloatRect RenderObject::relativeBBox(bool includeStroke) const
3322 {
3323     Q_UNUSED(includeStroke);
3324     return FloatRect();
3325 }
3326 
3327 AffineTransform RenderObject::localTransform() const
3328 {
3329     return AffineTransform(1, 0, 0, 1, xPos(), yPos());
3330 }
3331 
3332 AffineTransform RenderObject::absoluteTransform() const
3333 {
3334     if (parent()) {
3335         return localTransform() * parent()->absoluteTransform();
3336     }
3337     return localTransform();
3338 }
3339 // END SVG
3340 
3341 #undef RED_LUMINOSITY
3342 #undef GREEN_LUMINOSITY
3343 #undef BLUE_LUMINOSITY
3344 #undef INTENSITY_FACTOR
3345 #undef LIGHT_FACTOR
3346 #undef LUMINOSITY_FACTOR
3347 
3348 #undef MAX_COLOR
3349 #undef COLOR_DARK_THRESHOLD
3350 #undef COLOR_LIGHT_THRESHOLD
3351 
3352 #undef COLOR_LITE_BS_FACTOR
3353 #undef COLOR_LITE_TS_FACTOR
3354 
3355 #undef COLOR_DARK_BS_FACTOR
3356 #undef COLOR_DARK_TS_FACTOR
3357 
3358 #undef LIGHT_GRAY
3359 #undef DARK_GRAY
3360