diff options
author | tpearson <tpearson@283d02a7-25f6-0310-bc7c-ecb5cbfe19da> | 2010-09-03 17:11:27 +0000 |
---|---|---|
committer | tpearson <tpearson@283d02a7-25f6-0310-bc7c-ecb5cbfe19da> | 2010-09-03 17:11:27 +0000 |
commit | d0abc1a165ce7130e802d892e1417617a99a3ba0 (patch) | |
tree | 7dc885cf1d4bca7a30bfa8877164008c4966f6b3 /khtml/rendering | |
parent | c5415f69834f13834179331af41329980fe8a3e8 (diff) | |
download | tdelibs-d0abc1a165ce7130e802d892e1417617a99a3ba0.tar.gz tdelibs-d0abc1a165ce7130e802d892e1417617a99a3ba0.zip |
Merge commit 1170303 from the Enterprise branch
git-svn-id: svn://anonsvn.kde.org/home/kde/branches/trinity/kdelibs@1171389 283d02a7-25f6-0310-bc7c-ecb5cbfe19da
Diffstat (limited to 'khtml/rendering')
-rw-r--r-- | khtml/rendering/bidi.cpp | 279 | ||||
-rw-r--r-- | khtml/rendering/bidi.h | 66 | ||||
-rw-r--r-- | khtml/rendering/render_block.cpp | 68 | ||||
-rw-r--r-- | khtml/rendering/render_line.cpp | 4 | ||||
-rw-r--r-- | khtml/rendering/render_object.cpp | 5 | ||||
-rw-r--r-- | khtml/rendering/render_object.h | 1 | ||||
-rw-r--r-- | khtml/rendering/render_style.cpp | 5 | ||||
-rw-r--r-- | khtml/rendering/render_style.h | 7 |
8 files changed, 222 insertions, 213 deletions
diff --git a/khtml/rendering/bidi.cpp b/khtml/rendering/bidi.cpp index 19de828a0..bd010047a 100644 --- a/khtml/rendering/bidi.cpp +++ b/khtml/rendering/bidi.cpp @@ -44,10 +44,10 @@ namespace khtml { // an iterator which goes through a BidiParagraph struct BidiIterator { - BidiIterator() : par(0), obj(0), pos(0) {} - BidiIterator(RenderBlock *_par, RenderObject *_obj, unsigned int _pos) : par(_par), obj(_obj), pos(_pos) {} + BidiIterator() : par(0), obj(0), pos(0), endOfInline(0) {} + BidiIterator(RenderBlock *_par, RenderObject *_obj, unsigned int _pos, bool eoi=false) : par(_par), obj(_obj), pos(_pos), endOfInline(eoi) {} - void increment( BidiState &bidi ); + void increment( BidiState &bidi, bool skipInlines=true ); bool atEnd() const; @@ -57,6 +57,7 @@ struct BidiIterator RenderBlock *par; RenderObject *obj; unsigned int pos; + bool endOfInline; }; @@ -128,21 +129,6 @@ static int getBorderPaddingMargin(RenderObject* child, bool endOfInline) return result; } -static int inlineWidth(RenderObject* child, bool start = true, bool end = true) -{ - int extraWidth = 0; - RenderObject* parent = child->parent(); - while (parent->isInline() && !parent->isInlineBlockOrInlineTable()) { - if (start && parent->firstChild() == child) - extraWidth += getBorderPaddingMargin(parent, false); - if (end && parent->lastChild() == child) - extraWidth += getBorderPaddingMargin(parent, true); - child = parent; - parent = child->parent(); - } - return extraWidth; -} - #ifndef NDEBUG static bool inBidiRunDetach; #endif @@ -241,15 +227,19 @@ inline bool operator!=( const BidiIterator &it1, const BidiIterator &it2 ) return false; } +// when modifying this function, make sure you check InlineMinMaxIterator::next() as well. static inline RenderObject *Bidinext(RenderObject *par, RenderObject *current, BidiState &bidi, - bool skipInlines = true) + bool skipInlines = true, bool *endOfInline = 0 ) { RenderObject *next = 0; + bool oldEndOfInline = endOfInline ? *endOfInline : false; + if (oldEndOfInline) + *endOfInline = false; while(current != 0) { //kdDebug( 6040 ) << "current = " << current << endl; - if (!current->isFloating() && !current->isReplaced() && !current->isPositioned()) { + if (!oldEndOfInline && !current->isFloating() && !current->isReplaced() && !current->isPositioned()) { next = current->firstChild(); if ( next && adjustEmbedding ) { EUnicodeBidi ub = next->style()->unicodeBidi(); @@ -262,6 +252,12 @@ static inline RenderObject *Bidinext(RenderObject *par, RenderObject *current, B } } if (!next) { + if (!skipInlines && !oldEndOfInline && current->isInlineFlow() && endOfInline) { + next = current; + *endOfInline = true; + break; + } + while (current && current != par) { next = current->nextSibling(); if (next) break; @@ -269,6 +265,11 @@ static inline RenderObject *Bidinext(RenderObject *par, RenderObject *current, B embed( TQChar::DirPDF, bidi ); } current = current->parent(); + if (!skipInlines && current && current != par && current->isInlineFlow() && endOfInline) { + next = current; + *endOfInline = true; + break; + } } } @@ -300,17 +301,17 @@ static RenderObject *first( RenderObject *par, BidiState &bidi, bool skipInlines return o; } -inline void BidiIterator::increment (BidiState &bidi) +inline void BidiIterator::increment (BidiState &bidi, bool skipInlines) { if(!obj) return; if(obj->isText()) { pos++; if(pos >= static_cast<RenderText *>(obj)->stringLength()) { - obj = Bidinext( par, obj, bidi ); + obj = Bidinext( par, obj, bidi, skipInlines ); pos = 0; } } else { - obj = Bidinext( par, obj, bidi ); + obj = Bidinext( par, obj, bidi, skipInlines, &endOfInline ); pos = 0; } } @@ -1322,45 +1323,6 @@ void RenderBlock::bidiReorderLine(const BidiIterator &start, const BidiIterator #endif } -#ifdef APPLE_CHANGES // KDE handles compact blocks differently -static void buildCompactRuns(RenderObject* compactObj, BidiState &bidi) -{ - sBuildingCompactRuns = true; - if (!compactObj->isRenderBlock()) { - // Just append a run for our object. - isLineEmpty = false; - addRun(new (compactObj->renderArena()) BidiRun(0, compactObj->length(), compactObj, bidi.context, dir)); - } - else { - // Format the compact like it is its own single line. We build up all the runs for - // the little compact and then reorder them for bidi. - RenderBlock* compactBlock = static_cast<RenderBlock*>(compactObj); - adjustEmbedding = true; - BidiIterator start(compactBlock, first(compactBlock, bidi), 0); - adjustEmbedding = false; - BidiIterator end = start; - - betweenMidpoints = false; - isLineEmpty = true; - previousLineBrokeAtBR = true; - - end = compactBlock->findNextLineBreak(start, bidi); - if (!isLineEmpty) - compactBlock->bidiReorderLine(start, end, bidi); - } - - - sCompactFirstBidiRun = sFirstBidiRun; - sCompactLastBidiRun = sLastBidiRun; - sCompactBidiRunCount = sBidiRunCount; - - sNumMidpoints = 0; - sCurrMidpoint = 0; - betweenMidpoints = false; - sBuildingCompactRuns = false; -} -#endif - void RenderBlock::layoutInlineChildren(bool relayoutChildren, int breakBeforeLine) { BidiState bidi; @@ -1470,13 +1432,6 @@ void RenderBlock::layoutInlineChildren(bool relayoutChildren, int breakBeforeLin oldStart = start; oldBidi = bidi; } -#ifdef APPLE_CHANGES // KDE handles compact blocks differently - if (m_firstLine && firstChild() && firstChild()->isCompact()) { - buildCompactRuns(firstChild(), bidi); - start.obj = firstChild()->nextSibling(); - end = start; - } -#endif if (lineCount == breakBeforeLine) { m_height = pageTopAfter(oldPos); pagebreakHint = true; @@ -1491,15 +1446,6 @@ redo_linebreak: // At the same time we figure out where border/padding/margin should be applied for // inline flow boxes. -#ifdef APPLE_CHANGES // KDE handles compact blocks differently - if (sCompactFirstBidiRun) { - // We have a compact line sharing this line. Link the compact runs - // to our runs to create a single line of runs. - sCompactLastBidiRun->nextRun = sFirstBidiRun; - sFirstBidiRun = sCompactFirstBidiRun; - sBidiRunCount += sCompactBidiRunCount; - } -#endif if (sBidiRunCount) { InlineFlowBox* lineBox = constructLine(start, end); if (lineBox) { @@ -1698,7 +1644,7 @@ BidiIterator RenderBlock::findNextLineBreak(BidiIterator &start, BidiState &bidi } } adjustEmbedding = true; - start.increment(bidi); + start.increment(bidi, false /*skipInlines*/); adjustEmbedding = false; } @@ -1714,6 +1660,11 @@ BidiIterator RenderBlock::findNextLineBreak(BidiIterator &start, BidiState &bidi return start; } + // This variable says we have encountered an object after which initial whitespace should be ignored (e.g. InlineFlows at the begining of a line). + // Either we have nothing to do, if there is no whitespace after the object... or we have to enter the ignoringSpaces state. + // This dilemma will be resolved when we have a peek at the next object. + bool checkShouldIgnoreInitialWhitespace = false; + // This variable is used only if whitespace isn't set to PRE, and it tells us whether // or not we are currently ignoring whitespace. bool ignoringSpaces = false; @@ -1727,13 +1678,14 @@ BidiIterator RenderBlock::findNextLineBreak(BidiIterator &start, BidiState &bidi BidiIterator lBreak = start; - RenderObject *o = start.obj; - RenderObject *last = o; + InlineMinMaxIterator it(start.par, start.obj, start.endOfInline, false /*skipPositioned*/); + InlineMinMaxIterator lastIt = it; int pos = start.pos; bool prevLineBrokeCleanly = previousLineBrokeAtBR; previousLineBrokeAtBR = false; + RenderObject* o = it.current; while( o ) { #ifdef DEBUG_LINEBREAKS kdDebug(6041) << "new object "<< o <<" width = " << w <<" tmpw = " << tmpW << endl; @@ -1742,6 +1694,7 @@ BidiIterator RenderBlock::findNextLineBreak(BidiIterator &start, BidiState &bidi if( w + tmpW <= width ) { lBreak.obj = o; lBreak.pos = 0; + lBreak.endOfInline = it.endOfInline; // A <br> always breaks a line, so don't let the line be collapsed // away. Also, the space at the end of a line with a <br> does not @@ -1792,13 +1745,22 @@ BidiIterator RenderBlock::findNextLineBreak(BidiIterator &start, BidiState &bidi } } } else if (o->isInlineFlow()) { - // Only empty inlines matter. We treat those similarly to replaced elements. - KHTMLAssert(!o->firstChild()); - tmpW += o->marginLeft()+o->borderLeft()+o->paddingLeft()+ - o->marginRight()+o->borderRight()+o->paddingRight(); + tmpW += getBorderPaddingMargin(o, it.endOfInline); + if (isLineEmpty) isLineEmpty = !tmpW; + if (o->isWordBreak()) { // #### shouldn't be an InlineFlow! + w += tmpW; + tmpW = 0; + lBreak.obj = o; + lBreak.pos = 0; + lBreak.endOfInline = it.endOfInline; + } else if (!it.endOfInline) { + // this is the beginning of the line (other non-initial inline flows are handled directly when + // incrementing the iterator below). We want to skip initial whitespace as much as possible. + checkShouldIgnoreInitialWhitespace = true; + } } else if ( o->isReplaced() || o->isGlyph() ) { EWhiteSpace currWS = o->style()->whiteSpace(); - EWhiteSpace lastWS = last->style()->whiteSpace(); + EWhiteSpace lastWS = lastIt.current->style()->whiteSpace(); // WinIE marquees have different whitespace characteristics by default when viewed from // the outside vs. the inside. Text inside is NOWRAP, and so we altered the marquee's @@ -1806,8 +1768,8 @@ BidiIterator RenderBlock::findNextLineBreak(BidiIterator &start, BidiState &bidi // for the marquee when checking for line breaking. if (o->isHTMLMarquee() && o->layer() && o->layer()->marquee()) currWS = o->layer()->marquee()->whiteSpace(); - if (last->isHTMLMarquee() && last->layer() && last->layer()->marquee()) - lastWS = last->layer()->marquee()->whiteSpace(); + if (lastIt.current->isHTMLMarquee() && lastIt.current->layer() && lastIt.current->layer()->marquee()) + lastWS = lastIt.current->layer()->marquee()->whiteSpace(); // Break on replaced elements if either has normal white-space. if (currWS == NORMAL || lastWS == NORMAL) { @@ -1815,9 +1777,10 @@ BidiIterator RenderBlock::findNextLineBreak(BidiIterator &start, BidiState &bidi tmpW = 0; lBreak.obj = o; lBreak.pos = 0; + lBreak.endOfInline = false; } - tmpW += o->width()+o->marginLeft()+o->marginRight()+inlineWidth(o); + tmpW += o->width()+o->marginLeft()+o->marginRight(); if (ignoringSpaces) { BidiIterator startMid( 0, o, 0 ); addMidpoint(startMid); @@ -1828,21 +1791,7 @@ BidiIterator RenderBlock::findNextLineBreak(BidiIterator &start, BidiState &bidi trailingSpaceObject = 0; if (o->isListMarker() && o->style()->listStylePosition() == OUTSIDE) { - // The marker must not have an effect on whitespace at the start - // of the line. We start ignoring spaces to make sure that any additional - // spaces we see will be discarded. - // - // Optimize for a common case. If we can't find whitespace after the list - // item, then this is all moot. -dwh - RenderObject* next = Bidinext( start.par, o, bidi ); - if (!style()->preserveWS() && next && next->isText() && static_cast<RenderText*>(next)->stringLength() > 0 && - (static_cast<RenderText*>(next)->text()[0].category() == TQChar::Separator_Space || - static_cast<RenderText*>(next)->text()[0] == '\n')) { - currentCharacterIsSpace = true; - ignoringSpaces = true; - BidiIterator endMid( 0, o, 0 ); - addMidpoint(endMid); - } + checkShouldIgnoreInitialWhitespace = true; } } else if ( o->isText() ) { RenderText *t = static_cast<RenderText *>(o); @@ -1859,10 +1808,8 @@ BidiIterator RenderBlock::findNextLineBreak(BidiIterator &start, BidiState &bidi #ifdef APPLE_CHANGES int wordSpacing = o->style()->wordSpacing(); #endif - bool appliedStartWidth = pos > 0; // If the span originated on a previous line, - // then assume the start width has been applied. - bool appliedEndWidth = false; bool nextIsSoftBreakable = false; + bool checkBreakWord = autoWrap && (o->style()->wordWrap() == WWBREAKWORD); while(len) { bool previousCharacterIsSpace = currentCharacterIsSpace; @@ -1870,6 +1817,8 @@ BidiIterator RenderBlock::findNextLineBreak(BidiIterator &start, BidiState &bidi nextIsSoftBreakable = false; const TQChar c = str[pos]; currentCharacterIsSpace = c == ' '; + checkBreakWord &= !w; // only break words when no other breaking opportunity exists earlier + // on the line (even within the text object we are currently processing) if (preserveWS || !currentCharacterIsSpace) isLineEmpty = false; @@ -1921,13 +1870,11 @@ BidiIterator RenderBlock::findNextLineBreak(BidiIterator &start, BidiState &bidi } } - if ( (preserveLF && c == '\n') || (autoWrap && (isBreakable( str, pos, strlen ) || isSoftBreakable)) ) { + const bool isbreakablePosition = (preserveLF && c == '\n') || (autoWrap && + (isBreakable( str, pos, strlen ) || isSoftBreakable)); + if ( isbreakablePosition || checkBreakWord ) { tmpW += t->width(lastSpace, pos - lastSpace, f); - if (!appliedStartWidth) { - tmpW += inlineWidth(o, true, false); - appliedStartWidth = true; - } #ifdef APPLE_CHANGES applyWordSpacing = (wordSpacing && currentCharacterIsSpace && !previousCharacterIsSpace && !t->containsOnlyWhitespace(pos+1, strlen-(pos+1))); @@ -1957,9 +1904,14 @@ BidiIterator RenderBlock::findNextLineBreak(BidiIterator &start, BidiState &bidi } if (autoWrap) { - if (w+tmpW > width) + if (w+tmpW > width) { + if (checkBreakWord && pos) { + lBreak.obj = o; + lBreak.pos = pos-1; + lBreak.endOfInline = false; + } goto end; - else if ( (pos > 1 && str[pos-1].unicode() == SOFT_HYPHEN) ) + } else if ( (pos > 1 && str[pos-1].unicode() == SOFT_HYPHEN) ) // Subtract the width of the soft hyphen out since we fit on a line. tmpW -= t->width(pos-1, 1, f); } @@ -1967,6 +1919,7 @@ BidiIterator RenderBlock::findNextLineBreak(BidiIterator &start, BidiState &bidi if( preserveLF && *(str+pos) == '\n' ) { lBreak.obj = o; lBreak.pos = pos; + lBreak.endOfInline = false; #ifdef DEBUG_LINEBREAKS kdDebug(6041) << "forced break sol: " << start.obj << " " << start.pos << " end: " << lBreak.obj << " " << lBreak.pos << " width=" << w << endl; @@ -1974,11 +1927,12 @@ BidiIterator RenderBlock::findNextLineBreak(BidiIterator &start, BidiState &bidi return lBreak; } - if ( autoWrap ) { + if ( autoWrap && isbreakablePosition ) { w += tmpW; tmpW = 0; lBreak.obj = o; lBreak.pos = pos; + lBreak.endOfInline = false; } lastSpace = pos; @@ -2016,31 +1970,63 @@ BidiIterator RenderBlock::findNextLineBreak(BidiIterator &start, BidiState &bidi len--; } - // IMPORTANT: pos is > length here! - if (!ignoringSpaces) + if (!ignoringSpaces) { + // We didn't find any space that would be beyond the line |width|. + // Lets add to |tmpW| the remaining width since the last space we found. + // Before we test this new |tmpW| however, we will have to look ahead to check + // if the next object/position can serve as a line breaking opportunity. tmpW += t->width(lastSpace, pos - lastSpace, f); - if (!appliedStartWidth) - tmpW += inlineWidth(o, true, false); - if (!appliedEndWidth) - tmpW += inlineWidth(o, false, true); + if (checkBreakWord && !w && pos && tmpW > width) { + // Avoid doing the costly lookahead for break-word, + // since we know we are allowed to break. + lBreak.obj = o; + lBreak.pos = pos-1; + lBreak.endOfInline = false; + goto end; + } + } } else KHTMLAssert( false ); - RenderObject* next = Bidinext(start.par, o, bidi); - bool autoWrap = o->style()->autoWrap(); + InlineMinMaxIterator savedIt = lastIt; + lastIt = it; + o = it.next(); + + // advance the iterator to the next non-inline-flow + while (o && o->isInlineFlow() && !o->isWordBreak()) { + tmpW += getBorderPaddingMargin(o, it.endOfInline); + if (isLineEmpty) isLineEmpty = !tmpW; + o = it.next(); + } + + if (checkShouldIgnoreInitialWhitespace) { + // Check if we should switch to ignoringSpaces state + if (!style()->preserveWS() && it.current && it.current->isText()) { + const RenderText* rt = static_cast<RenderText*>(it.current); + if (rt->stringLength() > 0 && (rt->text()[0].category() == TQChar::Separator_Space || rt->text()[0] == '\n')) { + currentCharacterIsSpace = true; + ignoringSpaces = true; + BidiIterator endMid( 0, lastIt.current, 0 ); + addMidpoint(endMid); + } + } + checkShouldIgnoreInitialWhitespace = false; + } + + bool autoWrap = lastIt.current->style()->autoWrap(); bool checkForBreak = autoWrap; - if (w && w + tmpW > width && lBreak.obj && !o->style()->preserveLF() && !autoWrap) + if (w && w + tmpW > width && lBreak.obj && !lastIt.current->style()->preserveLF() && !autoWrap) checkForBreak = true; - else if (next && o->isText() && next->isText() && !next->isBR()) { - if (autoWrap || next->style()->autoWrap()) { + else if (it.current && lastIt.current->isText() && it.current->isText() && !it.current->isBR()) { + if (autoWrap || it.current->style()->autoWrap()) { if (currentCharacterIsSpace) checkForBreak = true; else { checkForBreak = false; - RenderText* nextText = static_cast<RenderText*>(next); + RenderText* nextText = static_cast<RenderText*>(it.current); if (nextText->stringLength() != 0) { TQChar c = nextText->text()[0]; - if (c == ' ' || c == '\t' || (c == '\n' && !next->style()->preserveLF())) { + if (c == ' ' || c == '\t' || (c == '\n' && !it.current->style()->preserveLF())) { // 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. @@ -2052,8 +2038,9 @@ BidiIterator RenderBlock::findNextLineBreak(BidiIterator &start, BidiState &bidi if (canPlaceOnLine && checkForBreak) { w += tmpW; tmpW = 0; - lBreak.obj = next; + lBreak.obj = it.current; lBreak.pos = 0; + lBreak.endOfInline = it.endOfInline; } } } @@ -2063,7 +2050,7 @@ BidiIterator RenderBlock::findNextLineBreak(BidiIterator &start, BidiState &bidi //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()->preserveWS()) + if (currentCharacterIsSpace && !ignoringSpaces && !lastIt.current->style()->preserveWS()) trailingSpaceObject = 0; int fb = nearestFloatBottom(m_height); @@ -2087,24 +2074,26 @@ BidiIterator RenderBlock::findNextLineBreak(BidiIterator &start, BidiState &bidi // |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) + if (w + tmpW > width) { + it = lastIt; + lastIt = savedIt; + o = it.current; goto end; + } } - last = o; - o = next; - - if (!last->isFloatingOrPositioned() && last->isReplaced() && last->style()->autoWrap()) { + if (!lastIt.current->isFloatingOrPositioned() && lastIt.current->isReplaced() && lastIt.current->style()->autoWrap()) { // Go ahead and add in tmpW. w += tmpW; tmpW = 0; lBreak.obj = o; lBreak.pos = 0; + lBreak.endOfInline = it.endOfInline; } // Clear out our character space bool, since inline <pre>s don't collapse whitespace // with adjacent inline normal/nowrap spans. - if (last->style()->preserveWS()) + if (lastIt.current->style()->preserveWS()) currentCharacterIsSpace = false; pos = 0; @@ -2113,9 +2102,10 @@ BidiIterator RenderBlock::findNextLineBreak(BidiIterator &start, BidiState &bidi #ifdef DEBUG_LINEBREAKS kdDebug( 6041 ) << "end of par, width = " << width << " linewidth = " << w + tmpW << endl; #endif - if( w + tmpW <= width || (last && !last->style()->autoWrap())) { + if( w + tmpW <= width || (lastIt.current && !lastIt.current->style()->autoWrap())) { lBreak.obj = 0; lBreak.pos = 0; + lBreak.endOfInline = false; } end: @@ -2127,21 +2117,25 @@ BidiIterator RenderBlock::findNextLineBreak(BidiIterator &start, BidiState &bidi if(pos != 0) { lBreak.obj = o; lBreak.pos = pos - 1; + lBreak.endOfInline = it.endOfInline; } else { - lBreak.obj = last; - lBreak.pos = last->isText() ? last->length() : 0; + lBreak.obj = lastIt.current; + lBreak.pos = lastIt.current->isText() ? lastIt.current->length() : 0; + lBreak.endOfInline = lastIt.endOfInline; } } else if( lBreak.obj ) { - if( last != o ) { + if( lastIt.current != o ) { // better to break between object boundaries than in the middle of a word lBreak.obj = o; lBreak.pos = 0; + lBreak.endOfInline = it.endOfInline; } 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; + lBreak.endOfInline = it.endOfInline; } } } @@ -2150,8 +2144,11 @@ BidiIterator RenderBlock::findNextLineBreak(BidiIterator &start, BidiState &bidi start = posStart; // make sure we consume at least one char/object. - if( lBreak == start ) + // and avoid returning an InlineFlow + // (FIXME: turn those wordbreaks into empty text objects - they shouldn't be inline flows!) + if( lBreak == start || (lBreak.obj && lBreak.obj->isInlineFlow() && !lBreak.obj->isWordBreak())) { lBreak.increment(bidi); + } #ifdef DEBUG_LINEBREAKS kdDebug(6041) << "regular break sol: " << start.obj << " " << start.pos << " end: " << lBreak.obj << " " << lBreak.pos << " width=" << w << endl; diff --git a/khtml/rendering/bidi.h b/khtml/rendering/bidi.h index 15a9ab906..c8776ce19 100644 --- a/khtml/rendering/bidi.h +++ b/khtml/rendering/bidi.h @@ -24,6 +24,7 @@ #define BIDI_H #include <tqstring.h> +#include "rendering/render_object.h" namespace khtml { class RenderArena; @@ -101,6 +102,71 @@ public: struct BidiIterator; struct BidiState; + struct InlineMinMaxIterator + { + /* InlineMinMaxIterator is a class that will iterate over all render objects that contribute to + inline min/max width calculations. Note the following about the way it walks: + (1) Positioned content is skipped (since it does not contribute to min/max width of a block) + (2) We do not drill into the children of floats or replaced elements, since you can't break + in the middle of such an element. + (3) Inline flows (e.g., <a>, <span>, <i>) are walked twice, since each side can have + distinct borders/margin/padding that contribute to the min/max width. + */ + RenderObject* parent; + RenderObject* current; + bool endOfInline; + bool skipPositioned; + InlineMinMaxIterator(RenderObject* p, RenderObject* o, bool eOI=false, bool skipPos=true) + :parent(p), current(o), endOfInline(eOI), skipPositioned(skipPos) {} + inline RenderObject* next(); + }; + + inline RenderObject* InlineMinMaxIterator::next() + { + RenderObject* result = 0; + bool oldEndOfInline = endOfInline; + endOfInline = false; + while (current != 0 || (current == parent)) + { + //kDebug( 6040 ) << "current = " << current; + if (!oldEndOfInline && + (current == parent || + (!current->isFloating() && !current->isReplaced() && !current->isPositioned()))) + result = current->firstChild(); + if (!result) { + // We hit the end of our inline. (It was empty, e.g., <span></span>.) + if (!oldEndOfInline && current->isInlineFlow()) { + result = current; + endOfInline = true; + break; + } + while (current && current != parent) { + result = current->nextSibling(); + if (result) break; + current = current->parent(); + if (current && current != parent && current->isInlineFlow()) { + result = current; + endOfInline = true; + break; + } + } + } + + if (!result) break; + + if ((!skipPositioned || !result->isPositioned()) && (result->isText() || result->isBR() || + result->isFloatingOrPositioned() || result->isReplaced() || result->isGlyph() || result->isInlineFlow())) + break; + + current = result; + result = 0; + } + + // Update our position. + current = result; + return current; + } + } #endif diff --git a/khtml/rendering/render_block.cpp b/khtml/rendering/render_block.cpp index d036b9d09..ccbb6fad0 100644 --- a/khtml/rendering/render_block.cpp +++ b/khtml/rendering/render_block.cpp @@ -2623,74 +2623,6 @@ void RenderBlock::calcMinMaxWidth() // ### compare with min/max width set in style sheet... } -struct InlineMinMaxIterator -{ -/* InlineMinMaxIterator is a class that will iterate over all render objects that contribute to - inline min/max width calculations. Note the following about the way it walks: - (1) Positioned content is skipped (since it does not contribute to min/max width of a block) - (2) We do not drill into the children of floats or replaced elements, since you can't break - in the middle of such an element. - (3) Inline flows (e.g., <a>, <span>, <i>) are walked twice, since each side can have - distinct borders/margin/padding that contribute to the min/max width. -*/ - RenderObject* parent; - RenderObject* current; - bool endOfInline; - - InlineMinMaxIterator(RenderObject* p, RenderObject* o, bool end = false) - :parent(p), current(o), endOfInline(end) {} - - RenderObject* next(); -}; - -RenderObject* InlineMinMaxIterator::next() -{ - RenderObject* result = 0; - bool oldEndOfInline = endOfInline; - endOfInline = false; - while (current != 0 || (current == parent)) - { - //kdDebug( 6040 ) << "current = " << current << endl; - if (!oldEndOfInline && - (current == parent || - (!current->isFloating() && !current->isReplaced() && !current->isPositioned()))) - result = current->firstChild(); - if (!result) { - // We hit the end of our inline. (It was empty, e.g., <span></span>.) - if (!oldEndOfInline && current->isInlineFlow()) { - result = current; - endOfInline = true; - break; - } - - while (current && current != parent) { - result = current->nextSibling(); - if (result) break; - current = current->parent(); - if (current && current != parent && current->isInlineFlow()) { - result = current; - endOfInline = true; - break; - } - } - } - - if (!result) break; - - if (!result->isPositioned() && (result->isText() || result->isBR() || - result->isFloating() || result->isReplaced() || - result->isInlineFlow())) - break; - - current = result; - result = 0; - } - - // Update our position. - current = result; - return current; -} - // bidi.cpp defines the following functions too. // Maybe these should not be static, after all... diff --git a/khtml/rendering/render_line.cpp b/khtml/rendering/render_line.cpp index f3b769e9c..2bcbe366e 100644 --- a/khtml/rendering/render_line.cpp +++ b/khtml/rendering/render_line.cpp @@ -271,8 +271,8 @@ bool InlineFlowBox::onEndChain(RenderObject* endObject) RenderObject* curr = endObject; RenderObject* parent = curr->parent(); - while (parent && !parent->isRenderBlock() || parent == object()) { - if (parent->lastChild() != curr) + while (parent && !parent->isRenderBlock()) { + if (parent->lastChild() != curr || parent == object()) return false; curr = parent; diff --git a/khtml/rendering/render_object.cpp b/khtml/rendering/render_object.cpp index c1f7fd754..c5ee68720 100644 --- a/khtml/rendering/render_object.cpp +++ b/khtml/rendering/render_object.cpp @@ -244,6 +244,11 @@ bool RenderObject::isHR() const return element() && element()->id() == ID_HR; } +bool RenderObject::isWordBreak() const +{ + return element() && element()->id() == ID_WBR; +} + bool RenderObject::isHTMLMarquee() const { return element() && element()->renderer() == this && element()->id() == ID_MARQUEE; diff --git a/khtml/rendering/render_object.h b/khtml/rendering/render_object.h index 1242f8e87..f7f772387 100644 --- a/khtml/rendering/render_object.h +++ b/khtml/rendering/render_object.h @@ -282,6 +282,7 @@ public: virtual bool isApplet() const { return false; } bool isHTMLMarquee() const; + bool isWordBreak() const; bool isAnonymous() const { return m_isAnonymous; } void setIsAnonymous(bool b) { m_isAnonymous = b; } diff --git a/khtml/rendering/render_style.cpp b/khtml/rendering/render_style.cpp index 18c520ad4..a71dd4116 100644 --- a/khtml/rendering/render_style.cpp +++ b/khtml/rendering/render_style.cpp @@ -429,7 +429,7 @@ bool StyleCSS3NonInheritedData::operator==(const StyleCSS3NonInheritedData& o) c } StyleCSS3InheritedData::StyleCSS3InheritedData() -:Shared<StyleCSS3InheritedData>(), textShadow(0) +:Shared<StyleCSS3InheritedData>(), textShadow(0), wordWrap(RenderStyle::initialWordWrap()) #ifdef APPLE_CHANGES , userModify(READ_ONLY), textSizeAdjust(RenderStyle::initialTextSizeAdjust()) #endif @@ -441,6 +441,7 @@ StyleCSS3InheritedData::StyleCSS3InheritedData(const StyleCSS3InheritedData& o) :Shared<StyleCSS3InheritedData>() { textShadow = o.textShadow ? new ShadowData(*o.textShadow) : 0; + wordWrap = o.wordWrap; #ifdef APPLE_CHANGES userModify = o.userModify; textSizeAdjust = o.textSizeAdjust; @@ -454,7 +455,7 @@ StyleCSS3InheritedData::~StyleCSS3InheritedData() bool StyleCSS3InheritedData::operator==(const StyleCSS3InheritedData& o) const { - return shadowDataEquivalent(o) + return shadowDataEquivalent(o) && (wordWrap == o.wordWrap) #ifdef APPLE_CHANGES && (userModify == o.userModify) && (textSizeAdjust == o.textSizeAdjust) #endif diff --git a/khtml/rendering/render_style.h b/khtml/rendering/render_style.h index b1c1e5306..29b369ca1 100644 --- a/khtml/rendering/render_style.h +++ b/khtml/rendering/render_style.h @@ -192,6 +192,9 @@ enum EFloat { FNONE = 0, FLEFT = 0x01, FRIGHT = 0x02, FLEFT_ALIGN = 0x05, FRIGHT_ALIGN = 0x06 }; +enum EWordWrap { + WWNORMAL = 0, WWBREAKWORD = 0x01 +}; //------------------------------------------------ // Border attributes. Not inherited. @@ -702,6 +705,7 @@ class StyleCSS3InheritedData : public Shared<StyleCSS3InheritedData> EUserModify userModify : 2; // Flag used for editing state bool textSizeAdjust : 1; // An Apple extension. Not really CSS3 but not worth making a new struct over. #endif + EWordWrap wordWrap : 1; private: StyleCSS3InheritedData &operator=(const StyleCSS3InheritedData &); }; @@ -1195,6 +1199,7 @@ public: return background->m_outline._offset; } ShadowData* textShadow() const { return css3InheritedData->textShadow; } + EWordWrap wordWrap() const { return css3InheritedData->wordWrap; } float opacity() { return css3NonInheritedData->opacity; } EUserInput userInput() const { return inherited_flags.f._user_input; } @@ -1346,6 +1351,7 @@ public: // CSS3 Setters void setBoxSizing( EBoxSizing b ) { SET_VAR(box,box_sizing,b); } void setOutlineOffset(unsigned short v) { SET_VAR(background,m_outline._offset,v) } + void setWordWrap(EWordWrap w) { SET_VAR(css3InheritedData, wordWrap, w); } void setTextShadow(ShadowData* val, bool add=false); void setOpacity(float f) { SET_VAR(css3NonInheritedData, opacity, f); } void setUserInput(EUserInput ui) { inherited_flags.f._user_input = ui; } @@ -1424,6 +1430,7 @@ public: static EDisplay initialDisplay() { return INLINE; } static EEmptyCell initialEmptyCells() { return SHOW; } static EFloat initialFloating() { return FNONE; } + static EWordWrap initialWordWrap() { return WWNORMAL; } static EListStylePosition initialListStylePosition() { return OUTSIDE; } static EListStyleType initialListStyleType() { return LDISC; } static EOverflow initialOverflowX() { return OVISIBLE; } |