2 * This file is part of the html renderer for KDE.
4 * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
5 * (C) 1999 Antti Koivisto (koivisto@kde.org)
6 * Copyright (C) 2003, 2004, 2005, 2006 Apple Computer, Inc.
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Library General Public
10 * License as published by the Free Software Foundation; either
11 * version 2 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Library General Public License for more details.
18 * You should have received a copy of the GNU Library General Public License
19 * along with this library; see the file COPYING.LIB. If not, write to
20 * the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
21 * Boston, MA 02111-1307, USA.
23 // -------------------------------------------------------------------------
26 #include "RenderFlow.h"
29 #include "GraphicsContext.h"
30 #include "InlineTextBox.h"
31 #include "HTMLNames.h"
32 #include "RenderArena.h"
33 #include "RenderView.h"
34 #include "RenderInline.h"
40 using namespace HTMLNames;
42 RenderFlow* RenderFlow::createAnonymousFlow(Document* doc, RenderStyle* style)
45 if (style->display() == INLINE)
46 result = new (doc->renderArena()) RenderInline(doc);
48 result = new (doc->renderArena()) RenderBlock(doc);
49 result->setStyle(style);
53 RenderFlow* RenderFlow::continuationBefore(RenderObject* beforeChild)
55 if (beforeChild && beforeChild->parent() == this)
58 RenderFlow* curr = continuation();
59 RenderFlow* nextToLast = this;
60 RenderFlow* last = this;
62 if (beforeChild && beforeChild->parent() == curr) {
63 if (curr->firstChild() == beforeChild)
70 curr = curr->continuation();
73 if (!beforeChild && !last->firstChild())
78 void RenderFlow::addChildWithContinuation(RenderObject* newChild, RenderObject* beforeChild)
80 RenderFlow* flow = continuationBefore(beforeChild);
81 ASSERT(!beforeChild || beforeChild->parent()->isRenderBlock() ||
82 beforeChild->parent()->isRenderInline());
83 RenderFlow* beforeChildParent = beforeChild ? static_cast<RenderFlow*>(beforeChild->parent()) :
84 (flow->continuation() ? flow->continuation() : flow);
86 if (newChild->isFloatingOrPositioned())
87 return beforeChildParent->addChildToFlow(newChild, beforeChild);
89 // A continuation always consists of two potential candidates: an inline or an anonymous
90 // block box holding block children.
91 bool childInline = newChild->isInline();
92 bool bcpInline = beforeChildParent->isInline();
93 bool flowInline = flow->isInline();
95 if (flow == beforeChildParent)
96 return flow->addChildToFlow(newChild, beforeChild);
98 // The goal here is to match up if we can, so that we can coalesce and create the
99 // minimal # of continuations needed for the inline.
100 if (childInline == bcpInline)
101 return beforeChildParent->addChildToFlow(newChild, beforeChild);
102 else if (flowInline == childInline)
103 return flow->addChildToFlow(newChild, 0); // Just treat like an append.
105 return beforeChildParent->addChildToFlow(newChild, beforeChild);
109 void RenderFlow::addChild(RenderObject *newChild, RenderObject *beforeChild)
112 kdDebug( 6040 ) << renderName() << "(RenderFlow)::addChild( " << newChild->renderName() <<
113 ", " << (beforeChild ? beforeChild->renderName() : "0") << " )" << endl;
114 kdDebug( 6040 ) << "current height = " << m_height << endl;
118 return addChildWithContinuation(newChild, beforeChild);
119 return addChildToFlow(newChild, beforeChild);
122 void RenderFlow::extractLineBox(InlineFlowBox* box)
124 m_lastLineBox = box->prevFlowBox();
125 if (box == m_firstLineBox)
127 if (box->prevLineBox())
128 box->prevLineBox()->setNextLineBox(0);
129 box->setPreviousLineBox(0);
130 for (InlineRunBox* curr = box; curr; curr = curr->nextLineBox())
131 curr->setExtracted();
134 void RenderFlow::attachLineBox(InlineFlowBox* box)
137 m_lastLineBox->setNextLineBox(box);
138 box->setPreviousLineBox(m_lastLineBox);
141 m_firstLineBox = box;
142 InlineFlowBox* last = box;
143 for (InlineFlowBox* curr = box; curr; curr = curr->nextFlowBox()) {
144 curr->setExtracted(false);
147 m_lastLineBox = last;
150 void RenderFlow::removeLineBox(InlineFlowBox* box)
152 if (box == m_firstLineBox)
153 m_firstLineBox = box->nextFlowBox();
154 if (box == m_lastLineBox)
155 m_lastLineBox = box->prevFlowBox();
156 if (box->nextLineBox())
157 box->nextLineBox()->setPreviousLineBox(box->prevLineBox());
158 if (box->prevLineBox())
159 box->prevLineBox()->setNextLineBox(box->nextLineBox());
162 void RenderFlow::deleteLineBoxes()
164 if (m_firstLineBox) {
165 RenderArena* arena = renderArena();
166 InlineRunBox *curr=m_firstLineBox, *next=0;
168 next = curr->nextLineBox();
169 curr->destroy(arena);
177 void RenderFlow::destroy()
179 // Detach our continuation first.
181 m_continuation->destroy();
184 // Make sure to destroy anonymous children first while they are still connected to the rest of the tree, so that they will
185 // properly dirty line boxes that they are removed from. Effects that do :before/:after only on hover could crash otherwise.
186 RenderContainer::destroyLeftoverChildren();
188 if (!documentBeingDestroyed()) {
189 if (m_firstLineBox) {
190 // We can't wait for RenderContainer::destroy to clear the selection,
191 // because by then we will have nuked the line boxes.
192 // FIXME: The SelectionController should be responsible for this when it
193 // is notified of DOM mutations.
194 if (isSelectionBorder())
195 view()->clearSelection();
197 // If line boxes are contained inside a root, that means we're an inline.
198 // In that case, we need to remove all the line boxes so that the parent
199 // lines aren't pointing to deleted children. If the first line box does
200 // not have a parent that means they are either already disconnected or
201 // root lines that can just be destroyed without disconnecting.
202 if (m_firstLineBox->parent()) {
203 for (InlineRunBox* box = m_firstLineBox; box; box = box->nextLineBox())
207 // If we are an anonymous block, then our line boxes might have children
208 // that will outlast this block. In the non-anonymous block case those
209 // children will be destroyed by the time we return from this function.
210 if (isAnonymousBlock()) {
211 for (InlineFlowBox* box = m_firstLineBox; box; box = box->nextFlowBox()) {
212 while (InlineBox *childBox = box->firstChild()) {
218 else if (isInline() && parent())
219 parent()->dirtyLinesFromChangedChild(this);
224 RenderContainer::destroy();
227 void RenderFlow::dirtyLinesFromChangedChild(RenderObject* child)
229 if (!parent() || (selfNeedsLayout() && !isInlineFlow()) || isTable())
232 // For an empty inline, go ahead and propagate the check up to our parent.
233 if (isInline() && !firstLineBox())
234 return parent()->dirtyLinesFromChangedChild(this);
236 // Try to figure out which line box we belong in. First try to find a previous
237 // line box by examining our siblings. If we didn't find a line box, then use our
238 // parent's first line box.
239 RootInlineBox* box = 0;
240 RenderObject* curr = 0;
241 for (curr = child->previousSibling(); curr; curr = curr->previousSibling()) {
242 if (curr->isFloatingOrPositioned())
245 if (curr->isReplaced()) {
246 InlineBox* wrapper = curr->inlineBoxWrapper();
248 box = wrapper->root();
250 else if (curr->isText()) {
251 InlineTextBox* textBox = static_cast<RenderText*>(curr)->lastTextBox();
253 box = textBox->root();
255 else if (curr->isInlineFlow()) {
256 InlineRunBox* runBox = static_cast<RenderFlow*>(curr)->lastLineBox();
258 box = runBox->root();
264 if (!box && firstLineBox())
265 box = firstLineBox()->root();
267 // If we found a line box, then dirty it.
269 RootInlineBox* adjacentBox;
272 // dirty the adjacent lines that might be affected
273 // NOTE: we dirty the previous line because RootInlineBox objects cache
274 // the address of the first object on the next line after a BR, which we may be
275 // invalidating here. For more info, see how RenderBlock::layoutInlineChildren
276 // calls setLineBreakInfo with the result of findNextLineBreak. findNextLineBreak,
277 // despite the name, actually returns the first RenderObject after the BR.
278 // <rdar://problem/3849947> "Typing after pasting line does not appear until after window resize."
279 adjacentBox = box->prevRootBox();
281 adjacentBox->markDirty();
282 if (child->isBR() || (curr && curr->isBR())) {
283 adjacentBox = box->nextRootBox();
285 adjacentBox->markDirty();
290 short RenderFlow::lineHeight(bool firstLine, bool isRootLineBox) const
293 RenderStyle* s = style(firstLine);
294 Length lh = s->lineHeight();
295 if (lh.value() < 0) {
297 if (m_lineHeight == -1)
298 m_lineHeight = RenderObject::lineHeight(false);
301 return s->font().lineSpacing();
304 return lh.calcMinValue(s->fontSize());
308 if (m_lineHeight == -1)
309 m_lineHeight = RenderObject::lineHeight(false);
313 void RenderFlow::dirtyLineBoxes(bool fullLayout, bool isRootLineBox)
315 if (!isRootLineBox && isReplaced())
316 return RenderContainer::dirtyLineBoxes(fullLayout, isRootLineBox);
321 for (InlineRunBox* curr = firstLineBox(); curr; curr = curr->nextLineBox())
322 curr->dirtyLineBoxes();
326 InlineBox* RenderFlow::createInlineBox(bool makePlaceHolderBox, bool isRootLineBox, bool isOnlyRun)
328 if (!isRootLineBox &&
329 (isReplaced() || makePlaceHolderBox)) // Inline tables and inline blocks
330 return RenderContainer::createInlineBox(false, isRootLineBox); // (or positioned element placeholders).
332 InlineFlowBox* flowBox = 0;
334 flowBox = new (renderArena()) InlineFlowBox(this);
336 flowBox = new (renderArena()) RootInlineBox(this);
339 m_firstLineBox = m_lastLineBox = flowBox;
341 m_lastLineBox->setNextLineBox(flowBox);
342 flowBox->setPreviousLineBox(m_lastLineBox);
343 m_lastLineBox = flowBox;
349 void RenderFlow::paintLines(PaintInfo& i, int _tx, int _ty)
351 // Only paint during the foreground/selection phases.
352 if (i.phase != PaintPhaseForeground && i.phase != PaintPhaseSelection && i.phase != PaintPhaseOutline
353 && i.phase != PaintPhaseSelfOutline && i.phase != PaintPhaseChildOutlines)
356 bool inlineFlow = isInlineFlow();
358 ASSERT(m_layer); // The only way a compact/run-in/inline could paint like this is if it has a layer.
360 // If we have no lines then we have no work to do.
364 // We can check the first box and last box and avoid painting if we don't
365 // intersect. This is a quick short-circuit that we can take to avoid walking any lines.
366 // FIXME: This check is flawed in the following extremely obscure way:
367 // if some line in the middle has a huge overflow, it might actually extend below the last line.
368 int yPos = firstLineBox()->root()->topOverflow() - maximalOutlineSize(i.phase);
369 int h = maximalOutlineSize(i.phase) + lastLineBox()->root()->bottomOverflow() - yPos;
371 if (yPos >= i.r.bottom() || yPos + h <= i.r.y())
375 RenderFlowSequencedSet outlineObjects;
376 info.outlineObjects = &outlineObjects;
378 // See if our root lines intersect with the dirty rect. If so, then we paint
379 // them. Note that boxes can easily overlap, so we can't make any assumptions
380 // based off positions of our first line box or our last line box.
381 bool isPrinting = document()->printing();
382 for (InlineFlowBox* curr = firstLineBox(); curr; curr = curr->nextFlowBox()) {
384 // FIXME: This is a feeble effort to avoid splitting a line across two pages.
385 // It is utterly inadequate, and this should not be done at paint time at all.
386 // The whole way objects break across pages needs to be redone.
387 RenderView* c = view();
388 // Try to avoid splitting a line vertically, but only if it's less than the height
389 // of the entire page.
390 if (curr->root()->bottomOverflow() - curr->root()->topOverflow() <= c->printRect().height()) {
391 if (_ty + curr->root()->bottomOverflow() > c->printRect().bottom()) {
392 if (_ty + curr->root()->topOverflow() < c->truncatedAt())
393 c->setBestTruncatedAt(_ty + curr->root()->topOverflow(), this);
394 // If we were able to truncate, don't paint.
395 if (_ty + curr->root()->topOverflow() >= c->truncatedAt())
401 int top = min(curr->root()->topOverflow(), curr->root()->selectionTop()) - maximalOutlineSize(info.phase);
402 int bottom = curr->root()->bottomOverflow() + maximalOutlineSize(info.phase);
405 if (yPos < info.r.bottom() && yPos + h > info.r.y())
406 curr->paint(info, _tx, _ty);
409 if (info.phase == PaintPhaseOutline || info.phase == PaintPhaseSelfOutline || info.phase == PaintPhaseChildOutlines) {
410 RenderFlowSequencedSet::iterator end = info.outlineObjects->end();
411 for (RenderFlowSequencedSet::iterator it = info.outlineObjects->begin(); it != end; ++it) {
412 RenderFlow* flow = *it;
413 flow->paintOutline(info.p, _tx, _ty);
415 info.outlineObjects->clear();
419 bool RenderFlow::hitTestLines(NodeInfo& i, int x, int y, int tx, int ty, HitTestAction hitTestAction)
421 if (hitTestAction != HitTestForeground)
424 bool inlineFlow = isInlineFlow();
426 ASSERT(m_layer); // The only way a compact/run-in/inline could paint like this is if it has a layer.
428 // If we have no lines then we have no work to do.
432 // We can check the first box and last box and avoid hit testing if we don't
433 // contain the point. This is a quick short-circuit that we can take to avoid walking any lines.
434 // FIXME: This check is flawed in the following extremely obscure way:
435 // if some line in the middle has a huge overflow, it might actually extend below the last line.
436 if ((y >= ty + lastLineBox()->root()->bottomOverflow()) || (y < ty + firstLineBox()->root()->topOverflow()))
439 // See if our root lines contain the point. If so, then we hit test
440 // them further. Note that boxes can easily overlap, so we can't make any assumptions
441 // based off positions of our first line box or our last line box.
442 for (InlineFlowBox* curr = lastLineBox(); curr; curr = curr->prevFlowBox()) {
443 if (y >= ty + curr->root()->topOverflow() && y < ty + curr->root()->bottomOverflow()) {
444 bool inside = curr->nodeAtPoint(i, x, y, tx, ty);
455 IntRect RenderFlow::getAbsoluteRepaintRect()
457 if (isInlineFlow()) {
458 // Find our leftmost position.
460 int top = firstLineBox() ? firstLineBox()->yPos() : 0;
461 for (InlineRunBox* curr = firstLineBox(); curr; curr = curr->nextLineBox())
462 if (curr == firstLineBox() || curr->xPos() < left)
465 // Now invalidate a rectangle.
466 int ow = style() ? style()->outlineSize() : 0;
470 // We need to add in the relative position offsets of any inlines (including us) up to our
472 RenderBlock* cb = containingBlock();
473 for (RenderObject* inlineFlow = this; inlineFlow && inlineFlow->isInlineFlow() && inlineFlow != cb;
474 inlineFlow = inlineFlow->parent()) {
475 if (inlineFlow->style()->position() == RelativePosition && inlineFlow->layer())
476 inlineFlow->layer()->relativePositionOffset(left, top);
479 IntRect r(-ow+left, -ow+top, width()+ow*2, height()+ow*2);
480 if (cb->hasOverflowClip()) {
481 // cb->height() is inaccurate if we're in the middle of a layout of |cb|, so use the
482 // layer's size instead. Even if the layer's size is wrong, the layer itself will repaint
483 // anyway if its size does change.
486 IntRect boxRect(0, 0, cb->layer()->width(), cb->layer()->height());
487 cb->layer()->subtractScrollOffset(x, y); // For overflow:auto/scroll/hidden.
488 IntRect repaintRect(x, y, r.width(), r.height());
489 r = intersection(repaintRect, boxRect);
491 cb->computeAbsoluteRepaintRect(r);
494 for (RenderObject* curr = firstChild(); curr; curr = curr->nextSibling()) {
495 if (!curr->isText()) {
496 IntRect childRect = curr->getAbsoluteRepaintRectWithOutline(ow);
501 if (continuation() && !continuation()->isInline()) {
502 IntRect contRect = continuation()->getAbsoluteRepaintRectWithOutline(ow);
509 return RenderContainer::getAbsoluteRepaintRect();
513 RenderFlow::lowestPosition(bool includeOverflowInterior, bool includeSelf) const
515 assert(!isInlineFlow());
516 int bottom = includeSelf && m_width > 0 ? m_height : 0;
517 if (!includeOverflowInterior && hasOverflowClip())
520 // FIXME: Come up with a way to use the layer tree to avoid visiting all the kids.
521 // For now, we have to descend into all the children, since we may have a huge abs div inside
522 // a tiny rel div buried somewhere deep in our child tree. In this case we have to get to
524 for (RenderObject *c = firstChild(); c; c = c->nextSibling()) {
525 if (!c->isFloatingOrPositioned() && !c->isText() && !c->isInlineFlow()) {
526 int lp = c->yPos() + c->lowestPosition(false);
527 bottom = max(bottom, lp);
531 if (isRelPositioned())
532 bottom += relativePositionOffsetY();
537 int RenderFlow::rightmostPosition(bool includeOverflowInterior, bool includeSelf) const
539 assert(!isInlineFlow());
540 int right = includeSelf && m_height > 0 ? m_width : 0;
541 if (!includeOverflowInterior && hasOverflowClip())
544 // FIXME: Come up with a way to use the layer tree to avoid visiting all the kids.
545 // For now, we have to descend into all the children, since we may have a huge abs div inside
546 // a tiny rel div buried somewhere deep in our child tree. In this case we have to get to
548 for (RenderObject *c = firstChild(); c; c = c->nextSibling()) {
549 if (!c->isFloatingOrPositioned() && !c->isText() && !c->isInlineFlow()) {
550 int rp = c->xPos() + c->rightmostPosition(false);
551 right = max(right, rp);
555 if (isRelPositioned())
556 right += relativePositionOffsetX();
561 int RenderFlow::leftmostPosition(bool includeOverflowInterior, bool includeSelf) const
563 assert(!isInlineFlow());
564 int left = includeSelf && m_height > 0 ? 0 : m_width;
565 if (!includeOverflowInterior && hasOverflowClip())
568 // FIXME: Come up with a way to use the layer tree to avoid visiting all the kids.
569 // For now, we have to descend into all the children, since we may have a huge abs div inside
570 // a tiny rel div buried somewhere deep in our child tree. In this case we have to get to
572 for (RenderObject *c = firstChild(); c; c = c->nextSibling()) {
573 if (!c->isFloatingOrPositioned() && !c->isText() && !c->isInlineFlow()) {
574 int lp = c->xPos() + c->leftmostPosition(false);
575 left = min(left, lp);
579 if (isRelPositioned())
580 left += relativePositionOffsetX();
585 IntRect RenderFlow::caretRect(int offset, EAffinity affinity, int *extraWidthToEndOfLine)
587 // Do the normal calculation in most cases.
588 if (firstChild() || style()->display() == INLINE)
589 return RenderContainer::caretRect(offset, affinity, extraWidthToEndOfLine);
591 // This is a special case:
592 // The element is not an inline element, and it's empty. So we have to
593 // calculate a fake position to indicate where objects are to be inserted.
595 // FIXME: This does not take into account either :first-line or :first-letter
596 // However, as soon as some content is entered, the line boxes will be
597 // constructed and this kludge is not called any more. So only the caret size
598 // of an empty :first-line'd block is wrong. I think we can live with that.
599 RenderStyle *currentStyle = firstLineStyle();
600 int height = lineHeight(true);
601 const int caretWidth = 1;
603 enum CaretAlignment { alignLeft, alignRight, alignCenter };
605 CaretAlignment alignment = alignLeft;
607 switch (currentStyle->textAlign()) {
610 if (currentStyle->direction() == RTL)
611 alignment = alignRight;
618 alignment = alignCenter;
622 alignment = alignRight;
626 int x = borderLeft() + paddingLeft();
633 x = (x + w - (borderRight() + paddingRight())) / 2;
636 x = w - (borderRight() + paddingRight());
640 if (extraWidthToEndOfLine) {
641 if (isRenderBlock()) {
642 *extraWidthToEndOfLine = w - (x + caretWidth);
644 // FIXME: This code looks wrong.
645 // myRight and containerRight are set up, but then clobbered.
646 // So *extraWidthToEndOfLine will always be 0 here.
648 int myRight = x + caretWidth;
650 absolutePositionForContent(myRight, ignore);
652 int containerRight = containingBlock()->xPos() + containingBlockWidth();
653 absolutePositionForContent(containerRight, ignore);
655 *extraWidthToEndOfLine = containerRight - myRight;
660 absolutePositionForContent(absx, absy);
662 int y = absy + paddingTop() + borderTop();
664 return IntRect(x, y, caretWidth, height);
667 void RenderFlow::addFocusRingRects(GraphicsContext* p, int _tx, int _ty)
670 p->addFocusRingRect(IntRect(_tx, _ty, width(), height()));
672 if (!hasOverflowClip()) {
673 for (InlineRunBox* curr = firstLineBox(); curr; curr = curr->nextLineBox())
674 p->addFocusRingRect(IntRect(_tx + curr->xPos(), _ty + curr->yPos(), curr->width(), curr->height()));
676 for (RenderObject* curr = firstChild(); curr; curr = curr->nextSibling())
677 if (!curr->isText() && !curr->isListMarker())
678 curr->addFocusRingRects(p, _tx + curr->xPos(), _ty + curr->yPos());
682 continuation()->addFocusRingRects(p,
683 _tx - containingBlock()->xPos() + continuation()->xPos(),
684 _ty - containingBlock()->yPos() + continuation()->yPos());
687 void RenderFlow::paintOutline(GraphicsContext* p, int _tx, int _ty)
692 if (style()->outlineStyleIsAuto() || hasOutlineAnnotation()) {
693 int ow = style()->outlineWidth();
694 Color oc = style()->outlineColor();
696 oc = style()->color();
698 p->initFocusRing(ow, style()->outlineOffset());
699 addFocusRingRects(p, _tx, _ty);
700 if (style()->outlineStyleIsAuto())
701 p->drawFocusRing(oc);
703 addPDFURLRect(p, p->focusRingBoundingRect());
707 if (style()->outlineStyleIsAuto() || style()->outlineStyle() <= BHIDDEN)
710 DeprecatedPtrList <IntRect> rects;
711 rects.setAutoDelete(true);
713 rects.append(new IntRect);
714 for (InlineRunBox* curr = firstLineBox(); curr; curr = curr->nextLineBox())
715 rects.append(new IntRect(curr->xPos(), curr->yPos(), curr->width(), curr->height()));
717 rects.append(new IntRect);
719 for (unsigned int i = 1; i < rects.count() - 1; i++)
720 paintOutlineForLine(p, _tx, _ty, *rects.at(i-1), *rects.at(i), *rects.at(i+1));
723 void RenderFlow::paintOutlineForLine(GraphicsContext* p, int tx, int ty, const IntRect &lastline, const IntRect &thisline, const IntRect &nextline)
725 int ow = style()->outlineWidth();
726 EBorderStyle os = style()->outlineStyle();
727 Color oc = style()->outlineColor();
729 oc = style()->color();
731 int offset = style()->outlineOffset();
733 int t = ty + thisline.y() - offset;
734 int l = tx + thisline.x() - offset;
735 int b = ty + thisline.bottom() + offset;
736 int r = tx + thisline.right() + offset;
741 t - (lastline.isEmpty() || thisline.x() < lastline.x() || (lastline.right() - 1) <= thisline.x() ? ow : 0),
743 b + (nextline.isEmpty() || thisline.x() <= nextline.x() || (nextline.right() - 1) <= thisline.x() ? ow : 0),
745 oc, style()->color(), os,
746 (lastline.isEmpty() || thisline.x() < lastline.x() || (lastline.right() - 1) <= thisline.x() ? ow : -ow),
747 (nextline.isEmpty() || thisline.x() <= nextline.x() || (nextline.right() - 1) <= thisline.x() ? ow : -ow));
752 t - (lastline.isEmpty() || lastline.right() < thisline.right() || (thisline.right() - 1) <= lastline.x() ? ow : 0),
754 b + (nextline.isEmpty() || nextline.right() <= thisline.right() || (thisline.right() - 1) <= nextline.x() ? ow : 0),
756 oc, style()->color(), os,
757 (lastline.isEmpty() || lastline.right() < thisline.right() || (thisline.right() - 1) <= lastline.x() ? ow : -ow),
758 (nextline.isEmpty() || nextline.right() <= thisline.right() || (thisline.right() - 1) <= nextline.x() ? ow : -ow));
760 if (thisline.x() < lastline.x())
764 min(r+ow, (lastline.isEmpty() ? 1000000 : tx + lastline.x())),
766 BSTop, oc, style()->color(), os,
768 (!lastline.isEmpty() && tx + lastline.x() + 1 < r + ow) ? -ow : ow);
770 if (lastline.right() < thisline.right())
772 max(lastline.isEmpty() ? -1000000 : tx + lastline.right(), l - ow),
776 BSTop, oc, style()->color(), os,
777 (!lastline.isEmpty() && l - ow < tx + lastline.right()) ? -ow : ow,
781 if (thisline.x() < nextline.x())
785 min(r + ow, !nextline.isEmpty() ? tx + nextline.x() + 1 : 1000000),
787 BSBottom, oc, style()->color(), os,
789 (!nextline.isEmpty() && tx + nextline.x() + 1 < r + ow) ? -ow : ow);
791 if (nextline.right() < thisline.right())
793 max(!nextline.isEmpty() ? tx + nextline.right() : -1000000, l - ow),
797 BSBottom, oc, style()->color(), os,
798 (!nextline.isEmpty() && l - ow < tx + nextline.right()) ? -ow : ow,