(next);
int strlen = nextText->stringLength();
QChar *str = nextText->text();
if (strlen &&
((str[0].unicode() == ' ') ||
(next->style()->whiteSpace() != PRE && str[0] == '\n')))
// If the next item on the line is text, and if we did not end with
// a space, then the next text run continues our word (and so it needs to
// keep adding to |tmpW|. Just update and continue.
checkForBreak = true;
else
checkForBreak = false;
bool canPlaceOnLine = (w + tmpW <= width+1) || !isNormal;
if (canPlaceOnLine && checkForBreak) {
w += tmpW;
tmpW = 0;
lBreak.obj = next;
lBreak.pos = 0;
}
}
}
}
if (checkForBreak && (w + tmpW > width+1)) {
//kdDebug() << " too wide w=" << w << " tmpW = " << tmpW << " width = " << width << endl;
//kdDebug() << "start=" << start.obj << " current=" << o << endl;
// if we have floats, try to get below them.
if (currentCharacterIsSpace && !ignoringSpaces && o->style()->whiteSpace() != PRE)
trailingSpaceObject = 0;
int fb = nearestFloatBottom(m_height);
int newLineWidth = lineWidth(fb);
// See if |tmpW| will fit on the new line. As long as it does not,
// keep adjusting our float bottom until we find some room.
int lastFloatBottom = m_height;
while (lastFloatBottom < fb && tmpW > newLineWidth) {
lastFloatBottom = fb;
fb = nearestFloatBottom(fb);
newLineWidth = lineWidth(fb);
}
if( !w && m_height < fb && width < newLineWidth ) {
m_height = fb;
width = newLineWidth;
#ifdef DEBUG_LINEBREAKS
kdDebug() << "RenderBlock::findNextLineBreak new position at " << m_height << " newWidth " << width << endl;
#endif
}
// |width| may have been adjusted because we got shoved down past a float (thus
// giving us more room), so we need to retest, and only jump to
// the end label if we still don't fit on the line. -dwh
if (w + tmpW > width+1)
goto end;
}
last = o;
o = next;
if (!last->isFloatingOrPositioned() && last->isReplaced() && last->style()->whiteSpace() == NORMAL) {
// Go ahead and add in tmpW.
w += tmpW;
tmpW = 0;
lBreak.obj = o;
lBreak.pos = 0;
}
// Clear out our character space bool, since inline s don't collapse whitespace
// with adjacent inline normal/nowrap spans.
if (last->style()->whiteSpace() == PRE)
currentCharacterIsSpace = false;
pos = 0;
}
#ifdef DEBUG_LINEBREAKS
kdDebug( 6041 ) << "end of par, width = " << width << " linewidth = " << w + tmpW << endl;
#endif
if( w + tmpW <= width || (last && last->style()->whiteSpace() == NOWRAP)) {
lBreak.obj = 0;
lBreak.pos = 0;
}
end:
if( lBreak == start && !lBreak.obj->isBR() ) {
// we just add as much as possible
if ( m_pre ) {
if(pos != 0) {
lBreak.obj = o;
lBreak.pos = pos - 1;
} else {
lBreak.obj = last;
lBreak.pos = last->isText() ? last->length() : 0;
}
} else if( lBreak.obj ) {
if( last != o ) {
// better to break between object boundaries than in the middle of a word
lBreak.obj = o;
lBreak.pos = 0;
} else {
// Don't ever break in the middle of a word if we can help it.
// There's no room at all. We just have to be on this line,
// even though we'll spill out.
lBreak.obj = o;
lBreak.pos = pos;
}
}
}
// make sure we consume at least one char/object.
if( lBreak == start )
lBreak.increment(bidi);
#ifdef DEBUG_LINEBREAKS
kdDebug(6041) << "regular break sol: " << start.obj << " " << start.pos << " end: " << lBreak.obj << " " << lBreak.pos << " width=" << w << endl;
#endif
// Sanity check our midpoints.
checkMidpoints(lBreak, bidi);
if (trailingSpaceObject) {
// This object is either going to be part of the last midpoint, or it is going
// to be the actual endpoint. In both cases we just decrease our pos by 1 level to
// exclude the space, allowing it to - in effect - collapse into the newline.
if (sNumMidpoints%2==1) {
BidiIterator* midpoints = smidpoints->data();
midpoints[sNumMidpoints-1].pos--;
}
//else if (lBreak.pos > 0)
// lBreak.pos--;
else if (lBreak.obj == 0 && trailingSpaceObject->isText()) {
// Add a new end midpoint that stops right at the very end.
RenderText* text = static_cast(trailingSpaceObject);
unsigned pos = text->length() >=2 ? text->length() - 2 : UINT_MAX;
BidiIterator endMid ( 0, trailingSpaceObject, pos );
addMidpoint(endMid);
}
}
// We might have made lBreak an iterator that points past the end
// of the object. Do this adjustment to make it point to the start
// of the next object instead to avoid confusing the rest of the
// code.
if (lBreak.pos > 0) {
lBreak.pos--;
lBreak.increment(bidi);
}
if (lBreak.obj && lBreak.pos >= 2 && lBreak.obj->isText()) {
// For soft hyphens on line breaks, we have to chop out the midpoints that made us
// ignore the hyphen so that it will render at the end of the line.
QChar c = static_cast(lBreak.obj)->text()[lBreak.pos-1];
if (c.unicode() == SOFT_HYPHEN)
chopMidpointsAt(lBreak.obj, lBreak.pos-2);
}
return lBreak;
}
void RenderBlock::checkLinesForOverflow()
{
// FIXME: Inline blocks can have overflow. Need to understand when those objects are present on a line
// and factor that in somehow.
m_overflowWidth = m_width;
for (RootInlineBox* curr = firstRootBox(); curr; curr = curr->nextRootBox()) {
m_overflowLeft = kMin(curr->leftOverflow(), m_overflowLeft);
m_overflowTop = kMin(curr->topOverflow(), m_overflowTop);
m_overflowWidth = kMax(curr->rightOverflow(), m_overflowWidth);
m_overflowHeight = kMax(curr->bottomOverflow(), m_overflowHeight);
}
}
void RenderBlock::deleteEllipsisLineBoxes()
{
for (RootInlineBox* curr = firstRootBox(); curr; curr = curr->nextRootBox())
curr->clearTruncation();
}
void RenderBlock::checkLinesForTextOverflow()
{
// Determine the width of the ellipsis using the current font.
QChar ellipsis = 0x2026; // FIXME: CSS3 says this is configurable, also need to use 0x002E (FULL STOP) if 0x2026 not renderable
static AtomicString ellipsisStr(ellipsis);
const Font& firstLineFont = style(true)->htmlFont();
const Font& font = style()->htmlFont();
int firstLineEllipsisWidth = firstLineFont.width(&ellipsis, 1, 0);
int ellipsisWidth = (font == firstLineFont) ? firstLineEllipsisWidth : font.width(&ellipsis, 1, 0);
// For LTR text truncation, we want to get the right edge of our padding box, and then we want to see
// if the right edge of a line box exceeds that. For RTL, we use the left edge of the padding box and
// check the left edge of the line box to see if it is less
// Include the scrollbar for overflow blocks, which means we want to use "contentWidth()"
bool ltr = style()->direction() == LTR;
for (RootInlineBox* curr = firstRootBox(); curr; curr = curr->nextRootBox()) {
int blockEdge = ltr ? rightOffset(curr->yPos()) : leftOffset(curr->yPos());
int lineBoxEdge = ltr ? curr->xPos() + curr->width() : curr->xPos();
if ((ltr && lineBoxEdge > blockEdge) || (!ltr && lineBoxEdge < blockEdge)) {
// This line spills out of our box in the appropriate direction. Now we need to see if the line
// can be truncated. In order for truncation to be possible, the line must have sufficient space to
// accommodate our truncation string, and no replaced elements (images, tables) can overlap the ellipsis
// space.
int width = curr == firstRootBox() ? firstLineEllipsisWidth : ellipsisWidth;
if (curr->canAccommodateEllipsis(ltr, blockEdge, lineBoxEdge, width))
curr->placeEllipsis(ellipsisStr, ltr, blockEdge, width);
}
}
}
// For --enable-final
#undef BIDI_DEBUG
#undef DEBUG_LINEBREAKS
#undef DEBUG_LAYOUT
}