Warning, file /frameworks/khtml/src/rendering/render_line.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) 2003-2007 Apple Computer, Inc.
0005  *           (C) 2006-2007 Germain Garand (germain@ebooksfrance.org)
0006  *
0007  * This library is free software; you can redistribute it and/or
0008  * modify it under the terms of the GNU Library General Public
0009  * License as published by the Free Software Foundation; either
0010  * version 2 of the License, or (at your option) any later version.
0011  *
0012  * This library is distributed in the hope that it will be useful,
0013  * but WITHOUT ANY WARRANTY; without even the implied warranty of
0014  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
0015  * Library General Public License for more details.
0016  *
0017  * You should have received a copy of the GNU Library General Public License
0018  * along with this library; see the file COPYING.LIB.  If not, write to
0019  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
0020  * Boston, MA 02110-1301, USA.
0021  */
0022 // -------------------------------------------------------------------------
0023 
0024 #include "render_line.h"
0025 
0026 #include "khtml_debug.h"
0027 #include <assert.h>
0028 #include <QPainter>
0029 
0030 #include "render_flow.h"
0031 #include "render_text.h"
0032 #include "render_table.h"
0033 #include "render_inline.h"
0034 #include "render_block.h"
0035 #include "render_arena.h"
0036 #include <xml/dom_nodeimpl.h>
0037 #include <xml/dom_docimpl.h>
0038 #include <html/html_formimpl.h>
0039 #include <khtmlview.h>
0040 
0041 using namespace DOM;
0042 using namespace khtml;
0043 
0044 #ifndef NDEBUG
0045 static bool inInlineBoxDetach;
0046 #endif
0047 
0048 class khtml::EllipsisBox : public InlineBox
0049 {
0050 public:
0051     EllipsisBox(RenderObject *obj, const DOM::DOMString &ellipsisStr, InlineFlowBox *p,
0052                 int w, int y, int h, int b, bool firstLine, InlineBox *markupBox)
0053         : InlineBox(obj), m_str(ellipsisStr)
0054     {
0055         m_parent = p;
0056         m_width = w;
0057         m_y = y;
0058         m_height = h;
0059         m_baseline = b;
0060         m_firstLine = firstLine;
0061         m_constructed = true;
0062         m_markupBox = markupBox;
0063     }
0064 
0065     void paint(RenderObject::PaintInfo &i, int _tx, int _ty) override;
0066     bool nodeAtPoint(RenderObject::NodeInfo &info, int _x, int _y, int _tx, int _ty) override;
0067 
0068 private:
0069     DOM::DOMString m_str;
0070     InlineBox *m_markupBox;
0071 };
0072 
0073 void InlineBox::remove()
0074 {
0075     if (m_parent) {
0076         m_parent->removeFromLine(this);
0077     }
0078 }
0079 
0080 void InlineBox::detach(RenderArena *renderArena, bool noRemove)
0081 {
0082     if (!noRemove) {
0083         remove();
0084     }
0085 
0086 #ifndef NDEBUG
0087     inInlineBoxDetach = true;
0088 #endif
0089     delete this;
0090 #ifndef NDEBUG
0091     inInlineBoxDetach = false;
0092 #endif
0093 
0094     // Recover the size left there for us by operator delete and free the memory.
0095     renderArena->free(*(size_t *)this, this);
0096 }
0097 
0098 void *InlineBox::operator new(size_t sz, RenderArena *renderArena) throw()
0099 {
0100     return renderArena->allocate(sz);
0101 }
0102 
0103 void InlineBox::operator delete(void *ptr, size_t sz)
0104 {
0105     assert(inInlineBoxDetach);
0106 #ifdef KHTML_USE_ARENA_ALLOCATOR
0107     // Stash size where detach can find it.
0108     *(size_t *)ptr = sz;
0109 #endif
0110 }
0111 
0112 static bool needsOutlinePhaseRepaint(RenderObject *o, RenderObject::PaintInfo &i, int tx, int ty)
0113 {
0114     if (o->style()->outlineWidth() <= 0) {
0115         return false;
0116     }
0117     QRect r(tx + o->xPos(), ty + o->yPos(), o->width(), o->height());
0118     if (r.intersects(i.r)) {
0119         return false;
0120     }
0121     r.adjust(-o->style()->outlineSize(),
0122              -o->style()->outlineSize(),
0123              o->style()->outlineSize(),
0124              o->style()->outlineSize());
0125     if (!r.intersects(i.r)) {
0126         return false;
0127     }
0128     return true;
0129 }
0130 
0131 void InlineBox::paint(RenderObject::PaintInfo &i, int tx, int ty)
0132 {
0133     if (i.phase == PaintActionOutline && !needsOutlinePhaseRepaint(object(), i, tx, ty)) {
0134         return;
0135     }
0136 
0137     // Paint all phases of replaced elements atomically, as though the replaced element established its
0138     // own stacking context.  (See Appendix E.2, section 6.4 on inline block/table elements in the CSS2.1
0139     // specification.)
0140     bool paintSelectionOnly = i.phase == PaintActionSelection;
0141     RenderObject::PaintInfo info(i.p, i.r, paintSelectionOnly ? i.phase : PaintActionElementBackground);
0142     object()->paint(info, tx, ty);
0143     if (!paintSelectionOnly) {
0144         info.phase = PaintActionChildBackgrounds;
0145         object()->paint(info, tx, ty);
0146         info.phase = PaintActionFloat;
0147         object()->paint(info, tx, ty);
0148         info.phase = PaintActionForeground;
0149         object()->paint(info, tx, ty);
0150         info.phase = PaintActionOutline;
0151         object()->paint(info, tx, ty);
0152     }
0153 }
0154 
0155 bool InlineBox::nodeAtPoint(RenderObject::NodeInfo &i, int x, int y, int tx, int ty)
0156 {
0157     // Hit test all phases of replaced elements atomically, as though the replaced element established its
0158     // own stacking context.  (See Appendix E.2, section 6.4 on inline block/table elements in the CSS2.1
0159     // specification.)
0160     bool inside = false;
0161     return object()->nodeAtPoint(i, x, y, tx, ty, HitTestAll, inside); // ### port hitTest
0162 }
0163 
0164 long InlineBox::caretMinOffset() const
0165 {
0166     return 0;
0167 }
0168 
0169 long InlineBox::caretMaxOffset() const
0170 {
0171     return 1;
0172 }
0173 
0174 unsigned long InlineBox::caretMaxRenderedOffset() const
0175 {
0176     return 1;
0177 }
0178 
0179 RootInlineBox *InlineBox::root()
0180 {
0181     if (m_parent) {
0182         return m_parent->root();
0183     }
0184     assert(isRootInlineBox());
0185     return static_cast<RootInlineBox *>(this);
0186 }
0187 
0188 InlineFlowBox::~InlineFlowBox()
0189 {
0190 }
0191 
0192 void InlineFlowBox::extractLine()
0193 {
0194     if (!m_extracted) {
0195         static_cast<RenderFlow *>(m_object)->extractLineBox(this);
0196     }
0197     for (InlineBox *child = firstChild(); child; child = child->nextOnLine()) {
0198         child->extractLine();
0199     }
0200 }
0201 
0202 void InlineFlowBox::attachLine()
0203 {
0204     if (m_extracted) {
0205         static_cast<RenderFlow *>(m_object)->attachLineBox(this);
0206     }
0207     for (InlineBox *child = firstChild(); child; child = child->nextOnLine()) {
0208         child->attachLine();
0209     }
0210 }
0211 
0212 void InlineFlowBox::deleteLine(RenderArena *arena)
0213 {
0214     InlineBox *child = firstChild();
0215     InlineBox *next = nullptr;
0216     while (child) {
0217         assert(this == child->parent());
0218         next = child->nextOnLine();
0219 #ifndef NDEBUG
0220         child->setParent(nullptr);
0221 #endif
0222         child->deleteLine(arena);
0223         child = next;
0224     }
0225 #ifndef NDEBUG
0226     m_firstChild = nullptr;
0227     m_lastChild = nullptr;
0228 #endif
0229 
0230     m_object->removeInlineBox(this);
0231     detach(arena, true /*no remove*/);
0232 }
0233 
0234 void InlineFlowBox::removeFromLine(InlineBox *child)
0235 {
0236     if (!m_dirty) {
0237         dirtyInlineBoxes();
0238     }
0239 
0240     root()->childRemoved(child);
0241 
0242     if (child == m_firstChild) {
0243         m_firstChild = child->nextOnLine();
0244     }
0245     if (child == m_lastChild) {
0246         m_lastChild = child->prevOnLine();
0247     }
0248     if (child->nextOnLine()) {
0249         child->nextOnLine()->m_prev = child->prevOnLine();
0250     }
0251     if (child->prevOnLine()) {
0252         child->prevOnLine()->m_next = child->nextOnLine();
0253     }
0254 
0255     child->setParent(nullptr);
0256 }
0257 
0258 void InlineBox::dirtyInlineBoxes()
0259 {
0260     markDirty();
0261     for (InlineFlowBox *curr = parent(); curr && !curr->isDirty(); curr = curr->parent()) {
0262         curr->markDirty();
0263     }
0264 }
0265 
0266 void InlineBox::deleteLine(RenderArena *arena)
0267 {
0268     if (!m_extracted && m_object->isBox()) {
0269         static_cast<RenderBox *>(m_object)->setPlaceHolderBox(nullptr);
0270     }
0271     detach(arena, true /*no remove*/);
0272 }
0273 
0274 void InlineBox::extractLine()
0275 {
0276     m_extracted = true;
0277     if (m_object->isBox()) {
0278         static_cast<RenderBox *>(m_object)->setPlaceHolderBox(nullptr);
0279     }
0280 }
0281 
0282 void InlineBox::attachLine()
0283 {
0284     m_extracted = false;
0285     if (m_object->isBox()) {
0286         static_cast<RenderBox *>(m_object)->setPlaceHolderBox(this);
0287     }
0288 }
0289 
0290 void InlineBox::adjustPosition(int dx, int dy)
0291 {
0292     m_x += dx;
0293     m_y += dy;
0294     if (m_object->isReplaced() || m_object->isBR()) {
0295         m_object->setPos(m_object->xPos() + dx, m_object->yPos() + dy);
0296     }
0297 }
0298 
0299 bool InlineBox::canAccommodateEllipsisBox(bool ltr, int blockEdge, int ellipsisWidth)
0300 {
0301     // Non-replaced elements can always accommodate an ellipsis.
0302     if (!m_object || !m_object->isReplaced()) {
0303         return true;
0304     }
0305 
0306     QRect boxRect(m_x, 0, m_width, 10);
0307     QRect ellipsisRect(ltr ? blockEdge - ellipsisWidth : blockEdge, 0, ellipsisWidth, 10);
0308     return !(boxRect.intersects(ellipsisRect));
0309 }
0310 
0311 int InlineBox::placeEllipsisBox(bool /*ltr*/, int /*blockEdge*/, int /*ellipsisWidth*/, bool &)
0312 {
0313     // Use -1 to mean "we didn't set the position."
0314     return -1;
0315 }
0316 
0317 bool InlineBox::nextOnLineExists() const
0318 {
0319     if (!parent()) {
0320         return false;
0321     }
0322 
0323     if (nextOnLine()) {
0324         return true;
0325     }
0326 
0327     return parent()->nextOnLineExists();
0328 }
0329 
0330 bool InlineBox::prevOnLineExists() const
0331 {
0332     if (!parent()) {
0333         return false;
0334     }
0335 
0336     if (prevOnLine()) {
0337         return true;
0338     }
0339 
0340     return parent()->prevOnLineExists();
0341 }
0342 
0343 InlineBox *InlineBox::firstLeafChild()
0344 {
0345     return this;
0346 }
0347 
0348 InlineBox *InlineBox::lastLeafChild()
0349 {
0350     return this;
0351 }
0352 
0353 InlineBox *InlineBox::closestLeafChildForXPos(int _x, int _tx)
0354 {
0355     if (!isInlineFlowBox()) {
0356         return this;
0357     }
0358 
0359     InlineFlowBox *flowBox = static_cast<InlineFlowBox *>(this);
0360     if (!flowBox->firstChild()) {
0361         return this;
0362     }
0363 
0364     InlineBox *box = flowBox->closestChildForXPos(_x, _tx);
0365     if (!box) {
0366         return this;
0367     }
0368 
0369     return box->closestLeafChildForXPos(_x, _tx);
0370 }
0371 
0372 #ifdef ENABLE_DUMP
0373 static QString getInlineBoxType(const InlineBox *box)
0374 {
0375     if (box->isInlineTextBox()) {
0376         return "Text";
0377     }
0378     if (box->isRootInlineBox()) {
0379         return "RootBox";
0380     }
0381     if (box->isInlineFlowBox()) {
0382         return "FlowBox";
0383     }
0384     if (box->isPlaceHolderBox()) {
0385         return "PlaceHolderBox";
0386     }
0387     return "InlineBox";
0388 }
0389 
0390 QString InlineBox::information() const
0391 {
0392     QString result;
0393     QTextStream out(&result, QIODevice::WriteOnly);
0394     out << getInlineBoxType(this) << "(" << (void *)this << ") "
0395         << "Pos" << "(" << xPos() << "," << yPos() << ") "
0396         << "Size" << "(" << width() << "," << height() << ") "
0397         << "Overflow" << "(" << topOverflow() << "," << bottomOverflow() << ") "
0398         << (object() ? object()->renderName() : "NoRenderObject") << "(" << (void *)object() << ") ";
0399     if (isInlineTextBox()) {
0400         const InlineTextBox *textBox = static_cast<const InlineTextBox *>(this);
0401         out << "Text[" << textBox->renderText()->data().substring(textBox->start(), textBox->len()).string() << "]";
0402     }
0403     return result;
0404 }
0405 
0406 void InlineBox::printTree(int indent) const
0407 {
0408     QString temp;
0409     temp.fill(' ', indent);
0410 
0411     // qCDebug(KHTML_LOG) << (temp + information());
0412     if (isRootInlineBox()) {
0413         // const RootInlineBox* root = static_cast<const RootInlineBox*>(this);
0414     }
0415     if (isInlineTextBox()) {
0416         //
0417     }
0418     if (isInlineFlowBox()) {
0419         const InlineFlowBox *flowBox = static_cast<const InlineFlowBox *>(this);
0420         for (InlineBox *box = flowBox->firstChild(); box; box = box->nextOnLine()) {
0421             box->printTree(indent + 2);
0422         }
0423     }
0424 }
0425 #endif
0426 
0427 int InlineFlowBox::marginLeft() const
0428 {
0429     if (!includeLeftEdge()) {
0430         return 0;
0431     }
0432 
0433     RenderStyle *cstyle = object()->style();
0434     Length margin = cstyle->marginLeft();
0435     if (!margin.isAuto()) {
0436         return (margin.isFixed() ? margin.value() : object()->marginLeft());
0437     }
0438     return 0;
0439 }
0440 
0441 int InlineFlowBox::marginRight() const
0442 {
0443     if (!includeRightEdge()) {
0444         return 0;
0445     }
0446 
0447     RenderStyle *cstyle = object()->style();
0448     Length margin = cstyle->marginRight();
0449     if (!margin.isAuto()) {
0450         return (margin.isFixed() ? margin.value() : object()->marginRight());
0451     }
0452     return 0;
0453 }
0454 
0455 int InlineFlowBox::marginBorderPaddingLeft() const
0456 {
0457     return marginLeft() + borderLeft() + paddingLeft();
0458 }
0459 
0460 int InlineFlowBox::marginBorderPaddingRight() const
0461 {
0462     return marginRight() + borderRight() + paddingRight();
0463 }
0464 
0465 int InlineFlowBox::getFlowSpacingWidth() const
0466 {
0467     int totWidth = marginBorderPaddingLeft() + marginBorderPaddingRight();
0468     for (InlineBox *curr = firstChild(); curr; curr = curr->nextOnLine()) {
0469         if (curr->isInlineFlowBox()) {
0470             totWidth += static_cast<InlineFlowBox *>(curr)->getFlowSpacingWidth();
0471         }
0472     }
0473     return totWidth;
0474 }
0475 
0476 bool InlineFlowBox::nextOnLineExists()
0477 {
0478     if (!parent()) {
0479         return false;
0480     }
0481 
0482     if (nextOnLine()) {
0483         return true;
0484     }
0485 
0486     return parent()->nextOnLineExists();
0487 }
0488 
0489 bool InlineFlowBox::prevOnLineExists()
0490 {
0491     if (!parent()) {
0492         return false;
0493     }
0494 
0495     if (prevOnLine()) {
0496         return true;
0497     }
0498 
0499     return parent()->prevOnLineExists();
0500 }
0501 
0502 bool InlineFlowBox::onEndChain(RenderObject *endObject)
0503 {
0504     if (!endObject) {
0505         return false;
0506     }
0507 
0508     if (endObject == object()) {
0509         return true;
0510     }
0511 
0512     RenderObject *curr = endObject;
0513     RenderObject *parent = curr->parent();
0514     while (parent && !parent->isRenderBlock()) {
0515         if (parent->lastChild() != curr || parent == object()) {
0516             return false;
0517         }
0518 
0519         curr = parent;
0520         parent = curr->parent();
0521     }
0522 
0523     return true;
0524 }
0525 
0526 void InlineFlowBox::determineSpacingForFlowBoxes(bool lastLine, RenderObject *endObject)
0527 {
0528     // All boxes start off open.  They will not apply any margins/border/padding on
0529     // any side.
0530     bool includeLeftEdge = false;
0531     bool includeRightEdge = false;
0532 
0533     RenderFlow *flow = static_cast<RenderFlow *>(object());
0534 
0535     // The root inline box never has borders/margins/padding.
0536     if (parent()) {
0537         bool ltr = flow->style()->direction() == LTR;
0538 
0539         // Check to see if all initial lines are unconstructed.  If so, then
0540         // we know the inline began on this line.
0541         if (!flow->firstLineBox()->isConstructed() && !object()->isInlineContinuation()) {
0542             if (ltr && flow->firstLineBox() == this) {
0543                 includeLeftEdge = true;
0544             } else if (!ltr && flow->lastLineBox() == this) {
0545                 includeRightEdge = true;
0546             }
0547         }
0548 
0549         // In order to determine if the inline ends on this line, we check three things:
0550         // (1) If we are the last line and we don't have a continuation(), then we can
0551         // close up.
0552         // (2) If the last line box for the flow has an object following it on the line (ltr,
0553         // reverse for rtl), then the inline has closed.
0554         // (3) The line may end on the inline.  If we are the last child (climbing up
0555         // the end object's chain), then we just closed as well.
0556         if (!flow->lastLineBox()->isConstructed()) {
0557             if (ltr) {
0558                 if (!nextLineBox() &&
0559                         ((lastLine && !object()->continuation()) || nextOnLineExists()
0560                          || onEndChain(endObject))) {
0561                     includeRightEdge = true;
0562                 }
0563             } else {
0564                 if ((!prevLineBox() || prevLineBox()->isConstructed()) &&
0565                         ((lastLine && !object()->continuation()) ||
0566                          prevOnLineExists() || onEndChain(endObject))) {
0567                     includeLeftEdge = true;
0568                 }
0569             }
0570 
0571         }
0572     }
0573 
0574     setEdges(includeLeftEdge, includeRightEdge);
0575 
0576     // Recur into our children.
0577     for (InlineBox *currChild = firstChild(); currChild; currChild = currChild->nextOnLine()) {
0578         if (currChild->isInlineFlowBox()) {
0579             InlineFlowBox *currFlow = static_cast<InlineFlowBox *>(currChild);
0580             currFlow->determineSpacingForFlowBoxes(lastLine, endObject);
0581         }
0582     }
0583 }
0584 
0585 int InlineFlowBox::placeBoxesHorizontally(int x)
0586 {
0587     // Set our x position.
0588     setXPos(x);
0589 
0590     int startX = x;
0591     x += borderLeft() + paddingLeft();
0592 
0593     for (InlineBox *curr = firstChild(); curr; curr = curr->nextOnLine()) {
0594         if (curr->object()->isText()) {
0595             InlineTextBox *text = static_cast<InlineTextBox *>(curr);
0596             text->setXPos(x);
0597             x += curr->width();
0598         } else {
0599             if (curr->object()->isPositioned()) {
0600                 if (curr->object()->parent()->style()->direction() == LTR) {
0601                     curr->setXPos(x);
0602                 } else {
0603                     // Our offset that we cache needs to be from the edge of the right border box and
0604                     // not the left border box.  We have to subtract |x| from the width of the block
0605                     // (which can be obtained by walking up to the root line box).
0606                     InlineBox *root = this;
0607                     while (!root->isRootInlineBox()) {
0608                         root = root->parent();
0609                     }
0610                     curr->setXPos(root->object()->width() - x);
0611                 }
0612                 continue; // The positioned object has no effect on the width.
0613             }
0614             if (curr->object()->isInlineFlow()) {
0615                 InlineFlowBox *flow = static_cast<InlineFlowBox *>(curr);
0616                 x += flow->marginLeft();
0617                 x = flow->placeBoxesHorizontally(x);
0618                 x += flow->marginRight();
0619             } else {
0620                 x += curr->object()->marginLeft();
0621                 curr->setXPos(x);
0622                 x += curr->width() + curr->object()->marginRight();
0623             }
0624         }
0625     }
0626 
0627     x += borderRight() + paddingRight();
0628     setWidth(x - startX);
0629     return x;
0630 }
0631 
0632 void InlineFlowBox::verticallyAlignBoxes(int &heightOfBlock)
0633 {
0634     int maxPositionTop = 0;
0635     int maxPositionBottom = 0;
0636     int maxAscent = 0;
0637     int maxDescent = 0;
0638 
0639     // Figure out if we're in strict mode.
0640     RenderObject *curr = object();
0641     while (curr && !curr->element()) {
0642         curr = curr->container();
0643     }
0644     bool strictMode = (curr && curr->document()->inStrictMode());
0645 
0646     computeLogicalBoxHeights(maxPositionTop, maxPositionBottom, maxAscent, maxDescent, strictMode);
0647 
0648     if (maxAscent + maxDescent < qMax(maxPositionTop, maxPositionBottom)) {
0649         adjustMaxAscentAndDescent(maxAscent, maxDescent, maxPositionTop, maxPositionBottom);
0650     }
0651 
0652     int maxHeight = maxAscent + maxDescent;
0653     int topPosition = heightOfBlock;
0654     int bottomPosition = heightOfBlock;
0655     placeBoxesVertically(heightOfBlock, maxHeight, maxAscent, strictMode, topPosition, bottomPosition);
0656 
0657     setOverflowPositions(topPosition, bottomPosition);
0658 
0659     // Shrink boxes with no text children in quirks and almost strict mode.
0660     if (!strictMode) {
0661         shrinkBoxesWithNoTextChildren(topPosition, bottomPosition);
0662     }
0663 
0664     heightOfBlock += maxHeight;
0665 }
0666 
0667 void InlineFlowBox::adjustMaxAscentAndDescent(int &maxAscent, int &maxDescent,
0668         int maxPositionTop, int maxPositionBottom)
0669 {
0670     for (InlineBox *curr = firstChild(); curr; curr = curr->nextOnLine()) {
0671         // The computed lineheight needs to be extended for the
0672         // positioned elements
0673         // see khtmltests/rendering/html_align.html
0674 
0675         if (curr->object()->isPositioned()) {
0676             continue;    // Positioned placeholders don't affect calculations.
0677         }
0678         if (curr->yPos() == PositionTop || curr->yPos() == PositionBottom) {
0679             if (curr->yPos() == PositionTop) {
0680                 if (maxAscent + maxDescent < curr->height()) {
0681                     maxDescent = curr->height() - maxAscent;
0682                 }
0683             } else {
0684                 if (maxAscent + maxDescent < curr->height()) {
0685                     maxAscent = curr->height() - maxDescent;
0686                 }
0687             }
0688 
0689             if (maxAscent + maxDescent >= qMax(maxPositionTop, maxPositionBottom)) {
0690                 break;
0691             }
0692         }
0693 
0694         if (curr->isInlineFlowBox()) {
0695             static_cast<InlineFlowBox *>(curr)->adjustMaxAscentAndDescent(maxAscent, maxDescent, maxPositionTop, maxPositionBottom);
0696         }
0697     }
0698 }
0699 
0700 void InlineFlowBox::computeLogicalBoxHeights(int &maxPositionTop, int &maxPositionBottom,
0701         int &maxAscent, int &maxDescent, bool strictMode)
0702 {
0703     if (isRootInlineBox()) {
0704         // Examine our root box.
0705         setHeight(object()->lineHeight(m_firstLine));
0706         bool isTableCell = object()->isTableCell();
0707         if (isTableCell) {
0708             RenderTableCell *tableCell = static_cast<RenderTableCell *>(object());
0709             setBaseline(tableCell->RenderBlock::baselinePosition(m_firstLine));
0710         } else {
0711             setBaseline(object()->baselinePosition(m_firstLine));
0712         }
0713         if (hasTextChildren() || strictMode) {
0714             int ascent = baseline();
0715             int descent = height() - ascent;
0716             if (maxAscent < ascent) {
0717                 maxAscent = ascent;
0718             }
0719             if (maxDescent < descent) {
0720                 maxDescent = descent;
0721             }
0722         }
0723     }
0724 
0725     for (InlineBox *curr = firstChild(); curr; curr = curr->nextOnLine()) {
0726         if (curr->object()->isPositioned()) {
0727             continue;    // Positioned placeholders don't affect calculations.
0728         }
0729 
0730         curr->setHeight(curr->object()->lineHeight(m_firstLine));
0731         curr->setBaseline(curr->object()->baselinePosition(m_firstLine));
0732         curr->setYPos(curr->object()->verticalPositionHint(m_firstLine));
0733         if (curr->yPos() == PositionTop) {
0734             if (maxPositionTop < curr->height()) {
0735                 maxPositionTop = curr->height();
0736             }
0737         } else if (curr->yPos() == PositionBottom) {
0738             if (maxPositionBottom < curr->height()) {
0739                 maxPositionBottom = curr->height();
0740             }
0741         } else if (curr->hasTextChildren() || strictMode) {
0742             int ascent = curr->baseline() - curr->yPos();
0743             int descent = curr->height() - ascent;
0744             if (maxAscent < ascent) {
0745                 maxAscent = ascent;
0746             }
0747             if (maxDescent < descent) {
0748                 maxDescent = descent;
0749             }
0750         }
0751 
0752         if (curr->isInlineFlowBox()) {
0753             static_cast<InlineFlowBox *>(curr)->computeLogicalBoxHeights(maxPositionTop, maxPositionBottom, maxAscent, maxDescent, strictMode);
0754         }
0755     }
0756 }
0757 
0758 void InlineFlowBox::placeBoxesVertically(int y, int maxHeight, int maxAscent, bool strictMode,
0759         int &topPosition, int &bottomPosition)
0760 {
0761     if (isRootInlineBox()) {
0762         setYPos(y + maxAscent - baseline());// Place our root box.
0763         // CSS2: 10.8.1 - line-height on the block level element specifies the *minimum*
0764         // height of the generated line box
0765         if (hasTextChildren() && maxHeight < object()->lineHeight(m_firstLine)) {
0766             maxHeight = object()->lineHeight(m_firstLine);
0767         }
0768     }
0769 
0770     for (InlineBox *curr = firstChild(); curr; curr = curr->nextOnLine()) {
0771         if (curr->object()->isPositioned()) {
0772             continue;    // Positioned placeholders don't affect calculations.
0773         }
0774 
0775         // Adjust boxes to use their real box y/height and not the logical height (as dictated by
0776         // line-height).
0777         if (curr->isInlineFlowBox())
0778             static_cast<InlineFlowBox *>(curr)->placeBoxesVertically(y, maxHeight, maxAscent, strictMode,
0779                     topPosition, bottomPosition);
0780 
0781         bool childAffectsTopBottomPos = true;
0782 
0783         if (curr->yPos() == PositionTop) {
0784             curr->setYPos(y);
0785         } else if (curr->yPos() == PositionBottom) {
0786             curr->setYPos(y + maxHeight - curr->height());
0787         } else {
0788             if (!strictMode && !curr->hasTextDescendant()) {
0789                 childAffectsTopBottomPos = false;
0790             }
0791             curr->setYPos(curr->yPos() + y + maxAscent - curr->baseline());
0792         }
0793         int newY = curr->yPos();
0794         int newHeight = curr->height();
0795         int newBaseline = curr->baseline();
0796         int overflowTop = 0;
0797         int overflowBottom = 0;
0798         if (curr->isInlineTextBox() || curr->isInlineFlowBox()) {
0799             const QFontMetrics &fm = curr->object()->fontMetrics(m_firstLine);
0800 #ifdef APPLE_CHANGES
0801             newBaseline = fm.ascent();
0802             newY += curr->baseline() - newBaseline;
0803             newHeight = newBaseline + fm.descent();
0804 #else
0805             // only adjust if the leading delta is superior to the font's natural leading
0806             if (qAbs(fm.ascent() - curr->baseline()) > fm.leading() / 2) {
0807                 int ascent = fm.ascent() + fm.leading() / 2;
0808                 newBaseline = ascent;
0809                 newY += curr->baseline() - newBaseline;
0810                 newHeight = fm.lineSpacing();
0811             }
0812 #endif
0813             for (ShadowData *shadow = curr->object()->style()->textShadow(); shadow; shadow = shadow->next) {
0814                 overflowTop = qMin(overflowTop, shadow->y - shadow->blur);
0815                 overflowBottom = qMax(overflowBottom, shadow->y + shadow->blur);
0816             }
0817             if (curr->isInlineFlowBox()) {
0818                 newHeight += curr->object()->borderTop() + curr->object()->paddingTop() +
0819                              curr->object()->borderBottom() + curr->object()->paddingBottom();
0820                 newY -= curr->object()->borderTop() + curr->object()->paddingTop();
0821                 newBaseline += curr->object()->borderTop() + curr->object()->paddingTop();
0822             }
0823         } else {
0824             newY += curr->object()->marginTop();
0825             newHeight = curr->height() - (curr->object()->marginTop() + curr->object()->marginBottom());
0826             overflowTop = curr->object()->overflowTop();
0827             overflowBottom = curr->object()->overflowHeight() - newHeight;
0828         }
0829         curr->setYPos(newY);
0830         curr->setHeight(newHeight);
0831         curr->setBaseline(newBaseline);
0832 
0833         if (childAffectsTopBottomPos) {
0834             topPosition = qMin(topPosition, newY + overflowTop);
0835             bottomPosition = qMax(bottomPosition, newY + newHeight + overflowBottom);
0836         }
0837     }
0838 
0839     if (isRootInlineBox()) {
0840         const QFontMetrics &fm = object()->fontMetrics(m_firstLine);
0841 #ifdef APPLE_CHANGES
0842         setHeight(fm.ascent() + fm.descent());
0843         setYPos(yPos() + baseline() - fm.ascent());
0844         setBaseline(fm.ascent());
0845 #else
0846         if (qAbs(fm.ascent() - baseline()) > fm.leading() / 2) {
0847             int ascent = fm.ascent() + fm.leading() / 2;
0848             setHeight(fm.lineSpacing());
0849             setYPos(yPos() + baseline() - ascent);
0850             setBaseline(ascent);
0851         }
0852 #endif
0853         if (hasTextDescendant() || strictMode) {
0854             if (yPos() < topPosition) {
0855                 topPosition = yPos();
0856             }
0857             if (yPos() + height() > bottomPosition) {
0858                 bottomPosition = yPos() + height();
0859             }
0860         }
0861     }
0862 }
0863 
0864 void InlineFlowBox::shrinkBoxesWithNoTextChildren(int topPos, int bottomPos)
0865 {
0866     // First shrink our kids.
0867     for (InlineBox *curr = firstChild(); curr; curr = curr->nextOnLine()) {
0868         if (curr->object()->isPositioned()) {
0869             continue;    // Positioned placeholders don't affect calculations.
0870         }
0871 
0872         if (curr->isInlineFlowBox()) {
0873             static_cast<InlineFlowBox *>(curr)->shrinkBoxesWithNoTextChildren(topPos, bottomPos);
0874         }
0875     }
0876 
0877     // See if we have text children. If not, then we need to shrink ourselves to fit on the line.
0878     if (!hasTextDescendant()) {
0879         if (yPos() < topPos) {
0880             setYPos(topPos);
0881         }
0882         if (yPos() + height() > bottomPos) {
0883             setHeight(bottomPos - yPos());
0884         }
0885         if (baseline() > height()) {
0886             setBaseline(height());
0887         }
0888     }
0889 }
0890 
0891 bool InlineFlowBox::nodeAtPoint(RenderObject::NodeInfo &i, int x, int y, int tx, int ty)
0892 {
0893     // Check children first.
0894     for (InlineBox *curr = lastChild(); curr; curr = curr->prevOnLine()) {
0895         if (!curr->object()->layer() && curr->nodeAtPoint(i, x, y, tx, ty)) {
0896             object()->setInnerNode(i);
0897             return true;
0898         }
0899     }
0900 
0901     // Now check ourselves.
0902     QRect rect(tx + m_x, ty + m_y, m_width, m_height);
0903     if (object()->style()->visibility() == VISIBLE && rect.contains(x, y)) {
0904         object()->setInnerNode(i);
0905         return true;
0906     }
0907 
0908     return false;
0909 }
0910 
0911 void InlineFlowBox::paint(RenderObject::PaintInfo &i, int tx, int ty)
0912 {
0913     bool intersectsDamageRect = true;
0914     int xPos = tx + m_x - object()->maximalOutlineSize(i.phase);
0915     int w = width() + 2 * object()->maximalOutlineSize(i.phase);
0916     if ((xPos >= i.r.x() + i.r.width()) || (xPos + w <= i.r.x())) {
0917         intersectsDamageRect = false;
0918     }
0919 
0920     if (intersectsDamageRect) {
0921         if (i.phase == PaintActionOutline) {
0922             // Add ourselves to the paint info struct's list of inlines that need to paint their
0923             // outlines.
0924             if (object()->style()->visibility() == VISIBLE && object()->style()->outlineWidth() > 0 &&
0925                     !object()->isInlineContinuation() && !isRootInlineBox()) {
0926                 if (!i.outlineObjects) {
0927                     i.outlineObjects = new QList<RenderFlow *>;
0928                 }
0929                 i.outlineObjects->append(static_cast<RenderFlow *>(object()));
0930             }
0931         } else {
0932             // 1. Paint our background and border.
0933             paintBackgroundAndBorder(i, tx, ty);
0934 
0935             // 2. Paint our underline and overline.
0936             paintDecorations(i, tx, ty, false);
0937         }
0938     }
0939 
0940     // 3. Paint our children.
0941     for (InlineBox *curr = firstChild(); curr; curr = curr->nextOnLine()) {
0942         if (!curr->object()->layer()) {
0943             curr->paint(i, tx, ty);
0944         }
0945     }
0946 
0947     // 4. Paint our strike-through
0948     if (intersectsDamageRect && i.phase != PaintActionOutline) {
0949         paintDecorations(i, tx, ty, true);
0950     }
0951 }
0952 
0953 void InlineFlowBox::paintAllBackgrounds(QPainter *p, const QColor &c, const BackgroundLayer *bgLayer,
0954                                         QRect clipr, int _tx, int _ty, int w, int h)
0955 {
0956     if (!bgLayer) {
0957         return;
0958     }
0959     paintAllBackgrounds(p, c, bgLayer->next(), clipr, _tx, _ty, w, h);
0960     paintOneBackground(p, c, bgLayer, clipr, _tx, _ty, w, h);
0961 }
0962 
0963 void InlineFlowBox::paintOneBackground(QPainter *p, const QColor &c, const BackgroundLayer *bgLayer,
0964                                        QRect clipr, int _tx, int _ty, int w, int h)
0965 {
0966     CachedImage *bg = bgLayer->backgroundImage();
0967     bool hasBackgroundImage = bg && bg->isComplete() &&
0968                               !bg->isTransparent() && !bg->isErrorImage();
0969     if (!hasBackgroundImage || (!prevLineBox() && !nextLineBox()) || !parent())
0970         object()->paintBackgroundExtended(p, c, bgLayer, clipr, _tx, _ty, w, h, borderLeft(), borderRight(), paddingLeft(), paddingRight(),
0971                                           object()->borderTop(), object()->borderBottom(), object()->paddingTop(), object()->paddingBottom());
0972     else {
0973         // We have a background image that spans multiple lines.
0974         // We need to adjust _tx and _ty by the width of all previous lines.
0975         // Think of background painting on inlines as though you had one long line, a single continuous
0976         // strip.  Even though that strip has been broken up across multiple lines, you still paint it
0977         // as though you had one single line.  This means each line has to pick up the background where
0978         // the previous line left off.
0979         // FIXME: What the heck do we do with RTL here? The math we're using is obviously not right,
0980         // but it isn't even clear how this should work at all.
0981         int xOffsetOnLine = 0;
0982         for (InlineRunBox *curr = prevLineBox(); curr; curr = curr->prevLineBox()) {
0983             xOffsetOnLine += curr->width();
0984         }
0985         int startX = _tx - xOffsetOnLine;
0986         int totalWidth = xOffsetOnLine;
0987         for (InlineRunBox *curr = this; curr; curr = curr->nextLineBox()) {
0988             totalWidth += curr->width();
0989         }
0990         p->save();
0991         p->setClipRect(QRect(_tx, _ty, width(), height()));
0992         object()->paintBackgroundExtended(p, c, bgLayer, clipr, startX, _ty,
0993                                           totalWidth, h, borderLeft(), borderRight(), paddingLeft(), paddingRight(),
0994                                           object()->borderTop(), object()->borderBottom(), object()->paddingTop(), object()->paddingBottom());
0995         p->restore();
0996     }
0997 }
0998 
0999 void InlineFlowBox::paintBackgroundAndBorder(RenderObject::PaintInfo &pI, int _tx, int _ty)
1000 {
1001     if (object()->style()->visibility() != VISIBLE || pI.phase != PaintActionForeground) {
1002         return;
1003     }
1004 
1005     // Move x/y to our coordinates.
1006     _tx += m_x;
1007     _ty += m_y;
1008 
1009     int w = width();
1010     int h = height();
1011 
1012     QRect cr;
1013     cr.setX(qMax(_tx, pI.r.x()));
1014     cr.setY(qMax(_ty, pI.r.y()));
1015     cr.setWidth(_tx < pI.r.x() ? qMax(0, w - (pI.r.x() - _tx)) : qMin(pI.r.width(), w));
1016     cr.setHeight(_ty < pI.r.y() ? qMax(0, h - (pI.r.y() - _ty)) : qMin(pI.r.height(), h));
1017 
1018     // You can use p::first-line to specify a background. If so, the root line boxes for
1019     // a line may actually have to paint a background.
1020     RenderStyle *styleToUse = object()->style(m_firstLine);
1021     if ((!parent() && m_firstLine && styleToUse != object()->style()) ||
1022             (parent() && object()->shouldPaintBackgroundOrBorder())) {
1023         QColor c = styleToUse->backgroundColor();
1024         paintAllBackgrounds(pI.p, c, styleToUse->backgroundLayers(), cr, _tx, _ty, w, h);
1025 
1026         // ::first-line cannot be used to put borders on a line. Always paint borders with our
1027         // non-first-line style.
1028         if (parent() && object()->style()->hasBorder()) {
1029             object()->paintBorder(pI.p, _tx, _ty, w, h, object()->style(), includeLeftEdge(), includeRightEdge());
1030         }
1031     }
1032 }
1033 
1034 static bool shouldDrawDecoration(RenderObject *obj)
1035 {
1036     bool shouldDraw = false;
1037     for (RenderObject *curr = obj->firstChild();
1038             curr; curr = curr->nextSibling()) {
1039         if (curr->isInlineFlow()) {
1040             shouldDraw = true;
1041             break;
1042         } else if (curr->isText() && !curr->isBR() && (curr->style()->preserveWS() ||
1043                    !curr->element() || !curr->element()->containsOnlyWhitespace())) {
1044             shouldDraw = true;
1045             break;
1046         }
1047     }
1048     return shouldDraw;
1049 }
1050 
1051 void InlineFlowBox::paintDecorations(RenderObject::PaintInfo &pI, int _tx, int _ty, bool paintedChildren)
1052 {
1053     // Now paint our text decorations. We only do this if we aren't in quirks mode (i.e., in
1054     // almost-strict mode or strict mode).
1055     if (object()->style()->htmlHacks() || object()->style()->visibility() != VISIBLE) {
1056         return;
1057     }
1058 
1059     _tx += m_x;
1060     _ty += m_y;
1061     RenderStyle *styleToUse = object()->style(m_firstLine);
1062     int deco = parent() ? styleToUse->textDecoration() : styleToUse->textDecorationsInEffect();
1063     if (deco != TDNONE &&
1064             ((!paintedChildren && ((deco & UNDERLINE) || (deco & OVERLINE))) || (paintedChildren && (deco & LINE_THROUGH))) &&
1065             shouldDrawDecoration(object())) {
1066         // We must have child boxes and have decorations defined.
1067         _tx += borderLeft() + paddingLeft();
1068         int w = m_width - (borderLeft() + paddingLeft() + borderRight() + paddingRight());
1069         if (!w) {
1070             return;
1071         }
1072         const QFontMetrics &fm = object()->fontMetrics(m_firstLine);
1073         // thick lines on small fonts look ugly
1074         int thickness = fm.height() > 20 ? fm.lineWidth() : 1;
1075         QColor underline, overline, linethrough;
1076         underline = overline = linethrough = styleToUse->color();
1077         if (!parent()) {
1078             object()->getTextDecorationColors(deco, underline, overline, linethrough);
1079         }
1080 
1081         if (styleToUse->font() != pI.p->font()) {
1082             pI.p->setFont(styleToUse->font());
1083         }
1084 
1085         if (deco & UNDERLINE && !paintedChildren) {
1086             int underlineOffset = (fm.height() + m_baseline) / 2;
1087             if (underlineOffset <= m_baseline) {
1088                 underlineOffset = m_baseline + 1;
1089             }
1090 
1091             pI.p->fillRect(_tx, _ty + underlineOffset, w, thickness, underline);
1092         }
1093         if (deco & OVERLINE && !paintedChildren) {
1094             pI.p->fillRect(_tx, _ty, w, thickness, overline);
1095         }
1096         if (deco & LINE_THROUGH && paintedChildren) {
1097             pI.p->fillRect(_tx, _ty + 2 * m_baseline / 3, w, thickness, linethrough);
1098         }
1099     }
1100 }
1101 
1102 bool InlineFlowBox::canAccommodateEllipsisBox(bool ltr, int blockEdge, int ellipsisWidth)
1103 {
1104     for (InlineBox *box = firstChild(); box; box = box->nextOnLine()) {
1105         if (!box->canAccommodateEllipsisBox(ltr, blockEdge, ellipsisWidth)) {
1106             return false;
1107         }
1108     }
1109     return true;
1110 }
1111 
1112 int InlineFlowBox::placeEllipsisBox(bool ltr, int blockEdge, int ellipsisWidth, bool &foundBox)
1113 {
1114     int result = -1;
1115     for (InlineBox *box = firstChild(); box; box = box->nextOnLine()) {
1116         int currResult = box->placeEllipsisBox(ltr, blockEdge, ellipsisWidth, foundBox);
1117         if (currResult != -1 && result == -1) {
1118             result = currResult;
1119         }
1120     }
1121     return result;
1122 }
1123 
1124 void InlineFlowBox::clearTruncation()
1125 {
1126     for (InlineBox *box = firstChild(); box; box = box->nextOnLine()) {
1127         box->clearTruncation();
1128     }
1129 }
1130 
1131 void EllipsisBox::paint(RenderObject::PaintInfo &i, int _tx, int _ty)
1132 {
1133     QPainter *p = i.p;
1134     RenderStyle *_style = m_firstLine ? m_object->style(true) : m_object->style();
1135     if (_style->font() != p->font()) {
1136         p->setFont(_style->font());
1137     }
1138 
1139     const Font *font = &_style->htmlFont();
1140     QColor textColor = _style->color();
1141     if (textColor != p->pen().color()) {
1142         p->setPen(textColor);
1143     }
1144     /*
1145     bool setShadow = false;
1146     if (_style->textShadow()) {
1147         p->setShadow(_style->textShadow()->x, _style->textShadow()->y,
1148                      _style->textShadow()->blur, _style->textShadow()->color);
1149         setShadow = true;
1150     }*/
1151 
1152     const DOMString &str = m_str.string();
1153     font->drawText(p, m_x + _tx,
1154                    m_y + _ty + m_baseline,
1155                    (str.implementation())->s,
1156                    str.length(), 0, str.length(),
1157                    0,
1158                    Qt::LeftToRight, _style->visuallyOrdered());
1159 
1160     /*
1161     if (setShadow)
1162         p->clearShadow();
1163     */
1164 
1165     if (m_markupBox) {
1166         // Paint the markup box
1167         _tx += m_x + m_width - m_markupBox->xPos();
1168         _ty += m_y + m_baseline - (m_markupBox->yPos() + m_markupBox->baseline());
1169         m_markupBox->object()->paint(i, _tx, _ty);
1170     }
1171 }
1172 
1173 bool EllipsisBox::nodeAtPoint(RenderObject::NodeInfo &info, int _x, int _y, int _tx, int _ty)
1174 {
1175     // Hit test the markup box.
1176     if (m_markupBox) {
1177         _tx += m_x + m_width - m_markupBox->xPos();
1178         _ty += m_y + m_baseline - (m_markupBox->yPos() + m_markupBox->baseline());
1179         if (m_markupBox->nodeAtPoint(info, _x, _y, _tx, _ty)) {
1180             object()->setInnerNode(info);
1181             return true;
1182         }
1183     }
1184 
1185     QRect rect(_tx + m_x, _ty + m_y, m_width, m_height);
1186     if (object()->style()->visibility() == VISIBLE && rect.contains(_x, _y)) {
1187         object()->setInnerNode(info);
1188         return true;
1189     }
1190     return false;
1191 }
1192 
1193 void RootInlineBox::detach(RenderArena *arena, bool noRemove)
1194 {
1195     if (m_lineBreakContext) {
1196         m_lineBreakContext->deref();
1197     }
1198     m_lineBreakContext = nullptr;
1199     detachEllipsisBox(arena);
1200     InlineFlowBox::detach(arena, noRemove);
1201 
1202 }
1203 
1204 void RootInlineBox::detachEllipsisBox(RenderArena *arena)
1205 {
1206     if (m_ellipsisBox) {
1207         m_ellipsisBox->detach(arena);
1208         m_ellipsisBox = nullptr;
1209     }
1210 }
1211 
1212 void RootInlineBox::clearTruncation()
1213 {
1214     if (m_ellipsisBox) {
1215         detachEllipsisBox(m_object->renderArena());
1216         InlineFlowBox::clearTruncation();
1217     }
1218 }
1219 
1220 bool RootInlineBox::canAccommodateEllipsis(bool ltr, int blockEdge, int lineBoxEdge, int ellipsisWidth)
1221 {
1222     // First sanity-check the unoverflowed width of the whole line to see if there is sufficient room.
1223     int delta = ltr ? lineBoxEdge - blockEdge : blockEdge - lineBoxEdge;
1224     if (width() - delta < ellipsisWidth) {
1225         return false;
1226     }
1227 
1228     // Next iterate over all the line boxes on the line.  If we find a replaced element that intersects
1229     // then we refuse to accommodate the ellipsis.  Otherwise we're ok.
1230     return InlineFlowBox::canAccommodateEllipsisBox(ltr, blockEdge, ellipsisWidth);
1231 }
1232 
1233 void RootInlineBox::placeEllipsis(const DOMString &ellipsisStr,  bool ltr, int blockEdge, int ellipsisWidth, InlineBox *markupBox)
1234 {
1235     // Create an ellipsis box.
1236     m_ellipsisBox = new(m_object->renderArena()) EllipsisBox(m_object, ellipsisStr, this,
1237             ellipsisWidth - (markupBox ? markupBox->width() : 0),
1238             yPos(), height(), baseline(), !prevRootBox(),
1239             markupBox);
1240 
1241     if (ltr && (xPos() + width() + ellipsisWidth) <= blockEdge) {
1242         m_ellipsisBox->m_x = xPos() + width();
1243         return;
1244     }
1245 
1246     // Now attempt to find the nearest glyph horizontally and place just to the right (or left in RTL)
1247     // of that glyph.  Mark all of the objects that intersect the ellipsis box as not painting (as being
1248     // truncated).
1249     bool foundBox = false;
1250     m_ellipsisBox->m_x = placeEllipsisBox(ltr, blockEdge, ellipsisWidth, foundBox);
1251 }
1252 
1253 int RootInlineBox::placeEllipsisBox(bool ltr, int blockEdge, int ellipsisWidth, bool &foundBox)
1254 {
1255     int result = InlineFlowBox::placeEllipsisBox(ltr, blockEdge, ellipsisWidth, foundBox);
1256     if (result == -1) {
1257         result = ltr ? blockEdge - ellipsisWidth : blockEdge;
1258     }
1259     return result;
1260 }
1261 
1262 void RootInlineBox::paintEllipsisBox(RenderObject::PaintInfo &i, int _tx, int _ty) const
1263 {
1264     if (m_ellipsisBox) {
1265         m_ellipsisBox->paint(i, _tx, _ty);
1266     }
1267 }
1268 
1269 void RootInlineBox::paint(RenderObject::PaintInfo &i, int tx, int ty)
1270 {
1271     InlineFlowBox::paint(i, tx, ty);
1272     paintEllipsisBox(i, tx, ty);
1273 }
1274 
1275 bool RootInlineBox::nodeAtPoint(RenderObject::NodeInfo &i, int x, int y, int tx, int ty)
1276 {
1277     if (m_ellipsisBox && object()->style()->visibility() == VISIBLE) {
1278         if (m_ellipsisBox->nodeAtPoint(i, x, y, tx, ty)) {
1279             object()->setInnerNode(i);
1280             return true;
1281         }
1282     }
1283     return InlineFlowBox::nodeAtPoint(i, x, y, tx, ty);
1284 }
1285 
1286 BidiStatus RootInlineBox::lineBreakBidiStatus() const
1287 {
1288     BidiStatus st;
1289     st.eor = KDE_CAST_BF_ENUM(QChar::Direction, m_lineBreakBidiStatusEor);
1290     st.last = KDE_CAST_BF_ENUM(QChar::Direction, m_lineBreakBidiStatusLast);
1291     st.lastStrong = KDE_CAST_BF_ENUM(QChar::Direction, m_lineBreakBidiStatusLastStrong);
1292     return st;
1293 }
1294 
1295 void RootInlineBox::childRemoved(InlineBox *box)
1296 {
1297     if (box->object() == m_lineBreakObj) {
1298         setLineBreakInfo(nullptr, 0, BidiStatus(), nullptr);
1299     }
1300 
1301     for (RootInlineBox *prev = prevRootBox(); prev && prev->lineBreakObj() == box->object(); prev = prev->prevRootBox()) {
1302         prev->setLineBreakInfo(nullptr, 0, BidiStatus(), nullptr);
1303         prev->markDirty();
1304     }
1305 }
1306 
1307 void RootInlineBox::setLineBreakInfo(RenderObject *obj, unsigned breakPos, const BidiStatus &status, BidiContext *context)
1308 {
1309     m_lineBreakObj = obj;
1310     m_lineBreakPos = breakPos;
1311     m_lineBreakBidiStatusEor = status.eor;
1312     m_lineBreakBidiStatusLastStrong = status.lastStrong;
1313     m_lineBreakBidiStatusLast = status.last;
1314     if (m_lineBreakContext) {
1315         m_lineBreakContext->deref();
1316     }
1317     m_lineBreakContext = context;
1318     if (m_lineBreakContext) {
1319         m_lineBreakContext->ref();
1320     }
1321 }
1322 
1323 InlineBox *InlineFlowBox::firstLeafChild()
1324 {
1325     InlineBox *box = firstChild();
1326     while (box) {
1327         InlineBox *next = nullptr;
1328         if (!box->isInlineFlowBox()) {
1329             break;
1330         }
1331         next = static_cast<InlineFlowBox *>(box)->firstChild();
1332         if (!next) {
1333             break;
1334         }
1335         box = next;
1336     }
1337     return box;
1338 }
1339 
1340 InlineBox *InlineFlowBox::lastLeafChild()
1341 {
1342     InlineBox *box = lastChild();
1343     while (box) {
1344         InlineBox *next = nullptr;
1345         if (!box->isInlineFlowBox()) {
1346             break;
1347         }
1348         next = static_cast<InlineFlowBox *>(box)->lastChild();
1349         if (!next) {
1350             break;
1351         }
1352         box = next;
1353     }
1354     return box;
1355 }
1356 
1357 InlineBox *InlineFlowBox::closestChildForXPos(int _x, int _tx)
1358 {
1359     if (_x < _tx + firstChild()->m_x)
1360         // if the x coordinate is to the left of the first child
1361     {
1362         return firstChild();
1363     } else if (_x >= _tx + lastChild()->m_x + lastChild()->m_width)
1364         // if the x coordinate is to the right of the last child
1365     {
1366         return lastChild();
1367     } else
1368         // look for the closest child;
1369         // check only the right edges, since the left edge of the first
1370         // box has already been checked
1371         for (InlineBox *box = firstChild(); box; box = box->nextOnLine())
1372             if (_x < _tx + box->m_x + box->m_width) {
1373                 return box;
1374             }
1375 
1376     return nullptr;
1377 }
1378