[webkit-changes] cvs commit: WebCore/khtml/rendering bidi.cpp bidi.h render_block.h render_line.cpp render_line.h

Eric eseidel at opensource.apple.com
Sun Nov 27 14:52:10 PST 2005


eseidel     05/11/27 14:52:10

  Modified:    .        ChangeLog
               khtml/rendering bidi.cpp bidi.h render_block.h
                        render_line.cpp render_line.h
  Log:
  Bug #: 5172
  Submitted by: mitz
  Reviewed by: hyatt
          One test case added:
          fast/text/international/bidi-layout-across-linebreak.html
  
          Fix for: http://bugzilla.opendarwin.org/show_bug.cgi?id=5172
  
          * khtml/rendering/bidi.cpp:
          (khtml::BidiState::BidiState):
          (khtml::operator==):
          (khtml::operator!=):
          (khtml::BidiIterator::increment):
          (khtml::appendRunsForObject):
          (khtml::appendRun):
          (khtml::embed):
          (khtml::RenderBlock::computeHorizontalPositionsForLine):
          (khtml::RenderBlock::computeVerticalPositionsForLine):
          (khtml::RenderBlock::bidiReorderLine):
          (khtml::buildCompactRuns):
          (khtml::RenderBlock::layoutInlineChildren):
          (khtml::RenderBlock::determineStartPosition):
          (khtml::RenderBlock::determineEndPosition):
          (khtml::RenderBlock::matchedEndLine):
          (khtml::RenderBlock::findNextLineBreak):
          * khtml/rendering/bidi.h:
          (khtml::BidiStatus::BidiStatus):
          * khtml/rendering/render_block.h:
          * khtml/rendering/render_line.cpp:
          (khtml::RootInlineBox::childRemoved):
          (khtml::RootInlineBox::setLineBreakInfo):
          * khtml/rendering/render_line.h:
          (khtml::RootInlineBox::RootInlineBox):
          (khtml::RootInlineBox::lineBreakBidiStatus):
          (khtml::RootInlineBox::lineBreakBidiContext):
  
  Revision  Changes    Path
  1.409     +37 -0     WebCore/ChangeLog
  
  Index: ChangeLog
  ===================================================================
  RCS file: /cvs/root/WebCore/ChangeLog,v
  retrieving revision 1.408
  retrieving revision 1.409
  diff -u -r1.408 -r1.409
  --- ChangeLog	27 Nov 2005 11:02:10 -0000	1.408
  +++ ChangeLog	27 Nov 2005 22:52:04 -0000	1.409
  @@ -1,3 +1,40 @@
  +2005-11-27  Mitz Pettel  <opendarwin.org at mitzpettel.com>
  +
  +        Reviewed by hyatt.  Committed by eseidel.
  +
  +        One test case added:
  +        fast/text/international/bidi-layout-across-linebreak.html
  +
  +        Fix for: http://bugzilla.opendarwin.org/show_bug.cgi?id=5172
  +
  +        * khtml/rendering/bidi.cpp:
  +        (khtml::BidiState::BidiState):
  +        (khtml::operator==):
  +        (khtml::operator!=):
  +        (khtml::BidiIterator::increment):
  +        (khtml::appendRunsForObject):
  +        (khtml::appendRun):
  +        (khtml::embed):
  +        (khtml::RenderBlock::computeHorizontalPositionsForLine):
  +        (khtml::RenderBlock::computeVerticalPositionsForLine):
  +        (khtml::RenderBlock::bidiReorderLine):
  +        (khtml::buildCompactRuns):
  +        (khtml::RenderBlock::layoutInlineChildren):
  +        (khtml::RenderBlock::determineStartPosition):
  +        (khtml::RenderBlock::determineEndPosition):
  +        (khtml::RenderBlock::matchedEndLine):
  +        (khtml::RenderBlock::findNextLineBreak):
  +        * khtml/rendering/bidi.h:
  +        (khtml::BidiStatus::BidiStatus):
  +        * khtml/rendering/render_block.h:
  +        * khtml/rendering/render_line.cpp:
  +        (khtml::RootInlineBox::childRemoved):
  +        (khtml::RootInlineBox::setLineBreakInfo):
  +        * khtml/rendering/render_line.h:
  +        (khtml::RootInlineBox::RootInlineBox):
  +        (khtml::RootInlineBox::lineBreakBidiStatus):
  +        (khtml::RootInlineBox::lineBreakBidiContext):
  +
   2005-11-26  Eric Seidel  <eseidel at apple.com>
   
           Reviewed by mjs.
  
  
  
  1.157     +194 -165  WebCore/khtml/rendering/bidi.cpp
  
  Index: bidi.cpp
  ===================================================================
  RCS file: /cvs/root/WebCore/khtml/rendering/bidi.cpp,v
  retrieving revision 1.156
  retrieving revision 1.157
  diff -u -r1.156 -r1.157
  --- bidi.cpp	3 Nov 2005 23:53:57 -0000	1.156
  +++ bidi.cpp	27 Nov 2005 22:52:08 -0000	1.157
  @@ -29,6 +29,7 @@
   #include "render_canvas.h"
   #include "khtmlview.h"
   #include "xml/dom_docimpl.h"
  +#include "misc/shared.h"
   
   #include "kdebug.h"
   #include "qdatetime.h"
  @@ -57,27 +58,31 @@
       unsigned int pos;
   };
   
  -struct BidiStatus {
  -    BidiStatus() : eor(QChar::DirON), lastStrong(QChar::DirON), last(QChar::DirON) {}
  -    
  -    QChar::Direction eor;
  -    QChar::Direction lastStrong;
  -    QChar::Direction last;
  -};
  -    
   struct BidiState {
  -    BidiState() : context(0), dir(QChar::DirON), adjustEmbedding(false) {}
  +    BidiState() : context(0), dir(QChar::DirON), adjustEmbedding(false), reachedEndOfLine(false) {}
       
       BidiIterator sor;
       BidiIterator eor;
       BidiIterator last;
       BidiIterator current;
  -    BidiContext* context;
  +    SharedPtr<BidiContext> context;
       BidiStatus status;
       QChar::Direction dir;
       bool adjustEmbedding;
  +    BidiIterator endOfLine;
  +    bool reachedEndOfLine;
   };
   
  +inline bool operator==(const BidiStatus& status1, const BidiStatus& status2)
  +{
  +    return status1.eor == status2.eor && status1.last == status2.last && status1.lastStrong == status2.lastStrong;
  +}
  +
  +inline bool operator!=(const BidiStatus& status1, const BidiStatus& status2)
  +{
  +    return !(status1 == status2);
  +}
  +
   // Used to track a list of chained bidi runs.
   static BidiRun* sFirstBidiRun;
   static BidiRun* sLastBidiRun;
  @@ -225,6 +230,20 @@
           delete this;
   }
   
  +bool operator==(const BidiContext& c1, const BidiContext& c2)
  +{
  +    if (&c1 == &c2)
  +        return true;
  +    if (c1.level != c2.level || c1.override != c2.override || c1.dir != c2.dir || c1.basicDir != c2.basicDir)
  +        return false;
  +    return c1.parent && c2.parent && *c1.parent == *c2.parent;
  +}
  +
  +inline bool operator!=(const BidiContext& c1, const BidiContext& c2)
  +{
  +    return !(c1 == c2);
  +}
  +
   // ---------------------------------------------------------------------
   
   inline bool operator==(const BidiIterator& it1, const BidiIterator& it2)
  @@ -329,7 +348,7 @@
           return;
       if (obj->isText()) {
           pos++;
  -        if(pos >= static_cast<RenderText *>(obj)->stringLength()) {
  +        if (pos >= static_cast<RenderText *>(obj)->stringLength()) {
               obj = bidiNext(block, obj, bidi);
               pos = 0;
           }
  @@ -531,7 +550,7 @@
       }
       else {
           if (!smidpoints || !haveNextMidpoint || (obj != nextMidpoint.obj)) {
  -            addRun(new (obj->renderArena()) BidiRun(start, end, obj, bidi.context, bidi.dir));
  +            addRun(new (obj->renderArena()) BidiRun(start, end, obj, bidi.context.get(), bidi.dir));
               return;
           }
           
  @@ -543,12 +562,12 @@
               if (nextMidpoint.pos != UINT_MAX) { // UINT_MAX means stop at the object and don't include any of it.
                   if (int(nextMidpoint.pos+1) > start)
                       addRun(new (obj->renderArena())
  -                        BidiRun(start, nextMidpoint.pos+1, obj, bidi.context, bidi.dir));
  +                        BidiRun(start, nextMidpoint.pos+1, obj, bidi.context.get(), bidi.dir));
                   return appendRunsForObject(nextMidpoint.pos+1, end, obj, bidi);
               }
           }
           else
  -           addRun(new (obj->renderArena()) BidiRun(start, end, obj, bidi.context, bidi.dir));
  +           addRun(new (obj->renderArena()) BidiRun(start, end, obj, bidi.context.get(), bidi.dir));
       }
   }
   
  @@ -565,14 +584,19 @@
   
       int start = bidi.sor.pos;
       RenderObject *obj = bidi.sor.obj;
  -    while (obj && obj != bidi.eor.obj) {
  +    while (obj && obj != bidi.eor.obj && obj != bidi.endOfLine.obj) {
           appendRunsForObject(start, obj->length(), obj, bidi);        
           start = 0;
           obj = bidiNext(bidi.sor.block, obj, bidi);
       }
       if (obj) {
  +        unsigned pos = obj == bidi.eor.obj ? bidi.eor.pos : UINT_MAX;
  +        if (obj == bidi.endOfLine.obj && bidi.endOfLine.pos <= pos) {
  +            bidi.reachedEndOfLine = true;
  +            pos = bidi.endOfLine.pos;
  +        }
           // It's OK to add runs for zero-length RenderObjects, just don't make the run larger than it should be
  -        int end = obj->length() ? bidi.eor.pos + 1 : 0;
  +        int end = obj->length() ? pos+1 : 0;
           appendRunsForObject(start, end, obj, bidi);
       }
       
  @@ -617,7 +641,6 @@
               // sor for the new run is determined by the higher level (rule X10)
   	    bidi.status.last = bidi.context->dir;
   	    bidi.status.lastStrong = bidi.context->dir;
  -	    bidi.context->deref();
   	    bidi.context = c;
               bidi.status.eor = bidi.context->dir;
               bidi.eor.obj = 0;
  @@ -684,8 +707,7 @@
               }
               appendRun(bidi);
               emptyRun = true;
  -            bidi.context = new BidiContext(level, runDir, bidi.context, override);
  -            bidi.context->ref();
  +            bidi.context = new BidiContext(level, runDir, bidi.context.get(), override);
               bidi.status.last = runDir;
               bidi.status.lastStrong = runDir;
               bidi.status.eor = runDir;
  @@ -873,7 +895,7 @@
           case CENTER:
           case KHTML_CENTER:
               int xd = (availableWidth - totWidth)/2;
  -            x += xd >0 ? xd : 0;
  +            x += xd > 0 ? xd : 0;
               numSpaces = 0;
               break;
       }
  @@ -926,7 +948,8 @@
           
       // Now make sure we place replaced render objects correctly.
       for (BidiRun* r = sFirstBidiRun; r; r = r->nextRun) {
  -        if (!r->box) continue; // Skip runs with no line boxes.
  +        if (!r->box)
  +            continue; // Skip runs with no line boxes.
   
           // Align positioned boxes with the top of the line box.  This is
           // a reasonable approximation of an appropriate y position.
  @@ -952,26 +975,36 @@
       sLastBidiRun = 0;
       sBidiRunCount = 0;
   
  +    assert(bidi.dir == QChar::DirON);
  +
       emptyRun = true;
  -    bidi.dir = QChar::DirON;
  -    bidi.status.eor = bidi.context->dir;
  +
       bidi.eor.obj = 0;
   
       numSpaces = 0;
   
       bidi.current = start;
       bidi.last = bidi.current;
  -    bool atEnd = false;
  +    bool pastEnd = false;
  +    bool resetBidiAtEnd = false;
  +    BidiState stateAtEnd;
   
       while (true) {
           QChar::Direction dirCurrent;
  -        if (atEnd) {
  +        if (pastEnd && (resetBidiAtEnd || bidi.current.atEnd())) {
               //kdDebug(6041) << "atEnd" << endl;
  -            BidiContext *c = bidi.context;
  -            if ( bidi.current.atEnd())
  -                while ( c->parent )
  -                    c = c->parent;
  +            BidiContext *c = bidi.context.get();
  +            while (c->parent)
  +                c = c->parent;
               dirCurrent = c->dir;
  +            if (resetBidiAtEnd) {
  +                // A deviation from the Unicode Bidi Algorithm in order to match
  +                // Mac OS X text and WinIE: a hard line break resets bidi state.
  +                stateAtEnd.context = c;
  +                stateAtEnd.status.eor = dirCurrent;
  +                stateAtEnd.status.last = dirCurrent;
  +                stateAtEnd.status.lastStrong = dirCurrent;
  +            }
           } else {
               dirCurrent = bidi.current.direction();
               if (bidi.context->override && dirCurrent != QChar::DirRLE && dirCurrent != QChar::DirLRE && dirCurrent != QChar::DirRLO && dirCurrent != QChar::DirLRO && dirCurrent != QChar::DirPDF)
  @@ -1001,11 +1034,8 @@
                   case QChar::DirAN:
                       if (bidi.status.last != QChar::DirEN || bidi.status.lastStrong != QChar::DirL)
                           appendRun(bidi);
  -                    bidi.dir = QChar::DirL;
  -                    // fall through
  +                    break;
                   case QChar::DirL:
  -                    bidi.eor = bidi.current;
  -                    bidi.status.eor = QChar::DirL;
                       break;
                   case QChar::DirES:
                   case QChar::DirET:
  @@ -1037,34 +1067,31 @@
                               bidi.dir = QChar::DirR;
                               appendRun(bidi);
                           }
  -                    } else if (bidi.status.eor != QChar::DirL) {
  -                        // last stuff takes embedding dir
  -                        if (bidi.context->dir == QChar::DirL || bidi.status.lastStrong == QChar::DirL)
  -                            appendRun(bidi);
  -                        else {
  -                            bidi.dir = QChar::DirR; 
  +                    } else if(bidi.status.eor != QChar::DirL) {
  +                        //last stuff takes embedding dir
  +                        if (bidi.context->dir != QChar::DirL && bidi.status.lastStrong != QChar::DirL) {
                               bidi.eor = bidi.last; 
  -                            appendRun(bidi); 
  +                            bidi.dir = QChar::DirR; 
                           }
  +                        appendRun(bidi); 
                       }
  -                    bidi.eor = bidi.current;
  -                    bidi.status.eor = QChar::DirL;
                   default:
                       break;
  -                }
  +            }
  +            bidi.eor = bidi.current;
  +            bidi.status.eor = QChar::DirL;
               bidi.status.lastStrong = QChar::DirL;
               bidi.dir = QChar::DirL;
               break;
           case QChar::DirAL:
           case QChar::DirR:
  -            switch(bidi.status.last) {
  +            switch (bidi.status.last) {
                   case QChar::DirL:
                   case QChar::DirEN:
                   case QChar::DirAN:
                       appendRun(bidi);
                   case QChar::DirR:
                   case QChar::DirAL:
  -                    bidi.eor = bidi.current;
                       break;
                   case QChar::DirES:
                   case QChar::DirET:
  @@ -1076,20 +1103,17 @@
                   case QChar::DirON:
                       if (bidi.status.eor != QChar::DirR && bidi.status.eor != QChar::DirAL) {
                           //last stuff takes embedding dir
  -                        if(bidi.context->dir == QChar::DirR || bidi.status.lastStrong == QChar::DirR 
  -                            || bidi.status.lastStrong == QChar::DirAL) { 
  -                            appendRun(bidi);
  -                            bidi.eor = bidi.current;
  -                        } else {
  -                            bidi.dir = QChar::DirL; 
  +                        if (bidi.context->dir != QChar::DirR && bidi.status.lastStrong != QChar::DirR 
  +                            && bidi.status.lastStrong != QChar::DirAL) {
                               bidi.eor = bidi.last;
  -                            appendRun(bidi);
  +                            bidi.dir = QChar::DirL; 
                           }
  -                    } else
  -                        bidi.eor = bidi.current;
  +                        appendRun(bidi);
  +                    }
                   default:
                       break;
  -                }
  +            }
  +            bidi.eor = bidi.current;
               bidi.status.eor = QChar::DirR;
               bidi.status.lastStrong = dirCurrent;
               bidi.dir = QChar::DirR;
  @@ -1098,87 +1122,73 @@
               // weak types:
   
           case QChar::DirEN:
  -            if (!(bidi.status.lastStrong == QChar::DirAL)) {
  +            if (bidi.status.lastStrong != QChar::DirAL) {
                   // if last strong was AL change EN to AN
                   switch (bidi.status.last) {
                       case QChar::DirET:
  -			if (bidi.status.lastStrong == QChar::DirR || bidi.status.lastStrong == QChar::DirAL) {
  -			    appendRun(bidi);
  +                        if (bidi.status.lastStrong == QChar::DirR || bidi.status.lastStrong == QChar::DirAL) {
  +                            appendRun(bidi);
                               bidi.dir = QChar::DirEN;
  -                            bidi.status.eor = QChar::DirEN;
   			}
   			// fall through
                       case QChar::DirEN:
                       case QChar::DirL:
  -                        bidi.eor = bidi.current;
  -                        bidi.status.eor = dirCurrent;
                           break;
                       case QChar::DirR:
                       case QChar::DirAL:
                       case QChar::DirAN:
                           bidi.eor = bidi.last;
                           appendRun(bidi);
  -                        bidi.eor = bidi.current;
  -                        bidi.status.eor = QChar::DirEN;
                           bidi.dir = QChar::DirEN;
                           break;
                       case QChar::DirES:
                       case QChar::DirCS:
                           if (bidi.status.eor == QChar::DirEN)
  -                            bidi.eor = bidi.current; break;
  +                            break;
                       case QChar::DirBN:
                       case QChar::DirB:
                       case QChar::DirS:
                       case QChar::DirWS:
                       case QChar::DirON:
  -                        if(bidi.status.eor == QChar::DirR) {
  +                        if (bidi.status.eor == QChar::DirR) {
                               // neutrals go to R
                               bidi.eor = bidi.last;
                               appendRun(bidi);
                               bidi.dir = QChar::DirEN;
  -                            bidi.status.eor = QChar::DirEN;
  -                        } else if (bidi.status.eor == QChar::DirL ||
  -                                 (bidi.status.eor == QChar::DirEN && bidi.status.lastStrong == QChar::DirL)) {
  -                            bidi.eor = bidi.current; 
  -                            bidi.status.eor = dirCurrent;
  -                        } else {
  +                        } else if (bidi.status.eor != QChar::DirL &&
  +                                 (bidi.status.eor != QChar::DirEN || bidi.status.lastStrong != QChar::DirL) &&
  +                                 bidi.dir != QChar::DirL) {
                               // numbers on both sides, neutrals get right to left direction
  -                            if (bidi.dir != QChar::DirL) {
  -                                appendRun(bidi);
  -                                bidi.eor = bidi.last;
  -                                bidi.dir = QChar::DirR;
  -                                appendRun(bidi);
  -                                bidi.dir = QChar::DirEN;
  -                                bidi.status.eor = QChar::DirEN;
  -                            } else
  -                                bidi.eor = bidi.current; bidi.status.eor = dirCurrent;
  +                            appendRun(bidi);
  +                            bidi.eor = bidi.last;
  +                            bidi.dir = QChar::DirR;
  +                            appendRun(bidi);
  +                            bidi.dir = QChar::DirEN;
                           }
                       default:
                           break;
  -                    }
  +                }
  +                bidi.eor = bidi.current;
  +                bidi.status.eor = QChar::DirEN;
                   if (bidi.dir == QChar::DirON)
                       bidi.dir = QChar::DirL;
                   break;
               }
           case QChar::DirAN:
               dirCurrent = QChar::DirAN;
  -            switch(bidi.status.last) {
  +            switch (bidi.status.last) {
                   case QChar::DirL:
                   case QChar::DirAN:
  -                    bidi.eor = bidi.current; bidi.status.eor = QChar::DirAN; break;
  +                    break;
                   case QChar::DirR:
                   case QChar::DirAL:
                   case QChar::DirEN:
                       bidi.eor = bidi.last;
                       appendRun(bidi);
  -                    bidi.eor = bidi.current;
  -                    bidi.status.eor = QChar::DirAN;
  -                    bidi.dir = QChar::DirAN;
                       break;
                   case QChar::DirCS:
                       if (bidi.status.eor == QChar::DirAN)
  -                        bidi.eor = bidi.current; 
  -                    break;
  +                        break;
                   case QChar::DirES:
                   case QChar::DirET:
                   case QChar::DirBN:
  @@ -1194,27 +1204,20 @@
                               // close the L run
                               appendRun(bidi);
                               // neutrals become an R run
  -                            bidi.eor = bidi.last;
                               bidi.dir = QChar::DirR;
  -                            appendRun(bidi);
  -                            bidi.eor = bidi.current;
                           } else {
                               // the embedding direction is L
                               // append neutrals to the L run and close it
                               bidi.dir = QChar::DirL; 
  -                            bidi.eor = bidi.last;
  -                            appendRun(bidi);
                           }
  -                    } else {
  -                        bidi.eor = bidi.last;
  -                        appendRun(bidi);
  -                        bidi.eor = bidi.current;
                       }
  -                    bidi.dir = QChar::DirAN;
  -                    bidi.status.eor = QChar::DirAN;
  +                    bidi.eor = bidi.last;
  +                    appendRun(bidi);
                   default:
                       break;
               }
  +            bidi.eor = bidi.current;
  +            bidi.status.eor = QChar::DirAN;
               if (bidi.dir == QChar::DirON)
                   bidi.dir = QChar::DirAN;
               break;
  @@ -1261,8 +1264,29 @@
               break;
           }
   
  -        if (bidi.current.atEnd())
  -            break;
  +        if (pastEnd) {
  +            if (bidi.eor == bidi.current) {
  +                if (!bidi.reachedEndOfLine) {
  +                    bidi.eor = bidi.endOfLine;
  +                    switch (bidi.status.eor) {
  +                        case QChar::DirL:
  +                        case QChar::DirR:
  +                        case QChar::DirAN:
  +                            bidi.dir = bidi.status.eor;
  +                            break;
  +                        case QChar::DirEN:
  +                            bidi.dir = bidi.status.lastStrong == QChar::DirL ? QChar::DirL : QChar::DirEN;
  +                            break;
  +                        default:
  +                            assert(false);
  +                    }
  +                    appendRun(bidi);
  +                }
  +                bidi = stateAtEnd;
  +                bidi.dir = QChar::DirON;
  +                break;
  +            }
  +        }
   
           // set status.last as needed.
           switch (dirCurrent) {
  @@ -1302,8 +1326,6 @@
                   bidi.status.last = dirCurrent;
           }
   
  -	if (atEnd)
  -            break;
           bidi.last = bidi.current;
   
   	if (emptyRun && !(dirCurrent == QChar::DirRLE || dirCurrent == QChar::DirLRE || dirCurrent == QChar::DirRLO || dirCurrent == QChar::DirLRO || dirCurrent == QChar::DirPDF)) {
  @@ -1323,44 +1345,42 @@
               bidi.sor = bidi.current;
           }
   
  -	if (bidi.current == end) {
  -	    if (emptyRun)
  -		break;
  -	    atEnd = true;
  -	}
  -    }
  -
  -    if (!emptyRun && bidi.sor != bidi.current) {
  -        bidi.eor = bidi.last;
  -        appendRun(bidi);
  +        if (!pastEnd && (bidi.current == end || bidi.current.atEnd())) {
  +            if (emptyRun)
  +                break;
  +            stateAtEnd = bidi;
  +            bidi.endOfLine = bidi.last;
  +            pastEnd = true;
  +            resetBidiAtEnd = previousLineBrokeCleanly || (end.obj && end.obj->style()->preserveNewline() && end.current() == '\n');
  +        }
       }
   
       // reorder line according to run structure...
  +    // do not reverse for visually ordered web sites
  +    if (!style()->visuallyOrdered()) {
   
  -    // first find highest and lowest levels
  -    uchar levelLow = 128;
  -    uchar levelHigh = 0;
  -    BidiRun* r = sFirstBidiRun;
  -    while (r) {
  -        if (r->level > levelHigh)
  -            levelHigh = r->level;
  -        if (r->level < levelLow)
  -            levelLow = r->level;
  -        r = r->nextRun;
  -    }
  -
  -    // implements reordering of the line (L2 according to Bidi spec):
  -    // L2. From the highest level found in the text to the lowest odd level on each line,
  -    // reverse any contiguous sequence of characters that are at that level or higher.
  -
  -    // reversing is only done up to the lowest odd level
  -    if (!(levelLow%2))
  -        levelLow++;
  +        // first find highest and lowest levels
  +        uchar levelLow = 128;
  +        uchar levelHigh = 0;
  +        BidiRun* r = sFirstBidiRun;
  +        while (r) {
  +            if (r->level > levelHigh)
  +                levelHigh = r->level;
  +            if (r->level < levelLow)
  +                levelLow = r->level;
  +            r = r->nextRun;
  +        }
  +
  +        // implements reordering of the line (L2 according to Bidi spec):
  +        // L2. From the highest level found in the text to the lowest odd level on each line,
  +        // reverse any contiguous sequence of characters that are at that level or higher.
  +
  +        // reversing is only done up to the lowest odd level
  +        if (!(levelLow%2))
  +            levelLow++;
   
  -    int count = sBidiRunCount - 1;
  +        int count = sBidiRunCount - 1;
   
  -    // do not reverse for visually ordered web sites
  -    if (!style()->visuallyOrdered()) {
           while (levelHigh >= levelLow) {
               int i = 0;
               BidiRun* currRun = sFirstBidiRun;
  @@ -1380,6 +1400,7 @@
               levelHigh--;
           }
       }
  +    bidi.endOfLine.obj = 0;
   }
   
   static void buildCompactRuns(RenderObject* compactObj, BidiState& bidi)
  @@ -1388,7 +1409,7 @@
       if (!compactObj->isRenderBlock()) {
           // Just append a run for our object.
           isLineEmpty = false;
  -        addRun(new (compactObj->renderArena()) BidiRun(0, compactObj->length(), compactObj, bidi.context, bidi.dir));
  +        addRun(new (compactObj->renderArena()) BidiRun(0, compactObj->length(), compactObj, bidi.context.get(), bidi.dir));
       }
       else {
           // Format the compact like it is its own single line.  We build up all the runs for
  @@ -1507,11 +1528,12 @@
               startEmbed = new BidiContext( 1, QChar::DirR, NULL, style()->unicodeBidi() == Override );
               bidi.status.eor = QChar::DirR;
           }
  -        startEmbed->ref();
   
           bidi.status.lastStrong = startEmbed->dir;
           bidi.status.last = startEmbed->dir;
  +        bidi.status.eor = startEmbed->dir;
           bidi.context = startEmbed;
  +        bidi.dir = QChar::DirON;
           
           if (!smidpoints)
               smidpoints = new QMemArray<BidiIterator>;
  @@ -1528,9 +1550,13 @@
           // We also find the first clean line and extract these lines.  We will add them back
           // if we determine that we're able to synchronize after handling all our dirty lines.
           BidiIterator cleanLineStart;
  +        BidiStatus cleanLineBidiStatus;
  +        BidiContext* cleanLineBidiContext;
           int endLineYPos;
           RootInlineBox* endLine = (fullLayout || !startLine) ? 
  -                                 0 : determineEndPosition(startLine, cleanLineStart, endLineYPos);
  +                                 0 : determineEndPosition(startLine, cleanLineStart, cleanLineBidiStatus, cleanLineBidiContext, endLineYPos);
  +        if (endLine && cleanLineBidiContext)
  +            cleanLineBidiContext->ref();
           if (startLine) {
               useRepaintRect = true;
               startLineBottom = startLine->bottomOverflow();
  @@ -1550,7 +1576,7 @@
           bool endLineMatched = false;
           while (!end.atEnd()) {
               start = end;
  -            if (endLine && (endLineMatched = matchedEndLine(start, cleanLineStart, endLine, endLineYPos)))
  +            if (endLine && (endLineMatched = matchedEndLine(start, bidi.status, bidi.context.get(), cleanLineStart, cleanLineBidiStatus, cleanLineBidiContext, endLine, endLineYPos)))
                   break;
   
               betweenMidpoints = false;
  @@ -1561,7 +1587,8 @@
                   end = start;
               }
               end = findNextLineBreak(start, bidi);
  -            if( start.atEnd() ) break;
  +            if (start.atEnd())
  +                break;
               if (!isLineEmpty) {
                   bidiReorderLine(start, end, bidi);
   
  @@ -1599,7 +1626,7 @@
                   }
   
                   if (lineBox)
  -                    lineBox->setLineBreakInfo(end.obj, end.pos);
  +                    lineBox->setLineBreakInfo(end.obj, end.pos, &bidi.status, bidi.context.get());
                   
                   m_firstLine = false;
                   newLine();
  @@ -1610,8 +1637,6 @@
               sCompactFirstBidiRun = sCompactLastBidiRun = 0;
               sCompactBidiRunCount = 0;
           }
  -        startEmbed->deref();
  -        //embed->deref();
           
           if (endLine) {
               if (endLineMatched) {
  @@ -1654,6 +1679,8 @@
                       line = next;
                   }
               }
  +            if (cleanLineBidiContext)
  +                cleanLineBidiContext->deref();
           }
       }
   
  @@ -1716,8 +1743,7 @@
               }
               KHTMLAssert(!m_firstLineBox && !m_lastLineBox);
           }
  -    }
  -    else {
  +    } else {
           for (curr = firstRootBox(); curr && !curr->isDirty(); curr = curr->nextRootBox());
           if (curr) {
               // We have a dirty line.
  @@ -1726,8 +1752,7 @@
                   if (!curr->prevRootBox()->endsWithBreak())
                       curr = curr->prevRootBox();  // The previous line didn't break cleanly, so treat it as dirty also.
               }
  -        }
  -        else {
  +        } else {
               // No dirty lines were found.
               // If the last line didn't break cleanly, treat it as dirty.
               if (lastRootBox() && !lastRootBox()->endsWithBreak())
  @@ -1747,18 +1772,18 @@
               m_overflowHeight = bottomOfLine;
           startObj = last->lineBreakObj();
           pos = last->lineBreakPos();
  -    }
  -    else
  +        bidi.status = last->lineBreakBidiStatus();
  +        bidi.context = last->lineBreakBidiContext();
  +    } else
           startObj = bidiFirst(this, bidi, 0);
           
  -    bidi.adjustEmbedding = true;
       start = BidiIterator(this, startObj, pos);
  -    bidi.adjustEmbedding = false;
       
       return curr;
   }
   
   RootInlineBox* RenderBlock::determineEndPosition(RootInlineBox* startLine, BidiIterator& cleanLineStart,
  +                                                 BidiStatus& cleanLineBidiStatus, BidiContext*& cleanLineBidiContext,
                                                    int& yPos)
   {
       RootInlineBox* last = 0;
  @@ -1776,7 +1801,10 @@
       if (!last)
           return 0;
       
  -    cleanLineStart = BidiIterator(this, last->prevRootBox()->lineBreakObj(), last->prevRootBox()->lineBreakPos());
  +    RootInlineBox* prev = last->prevRootBox();
  +    cleanLineStart = BidiIterator(this, prev->lineBreakObj(), prev->lineBreakPos());
  +    cleanLineBidiStatus = prev->lineBreakBidiStatus();
  +    cleanLineBidiContext = prev->lineBreakBidiContext();
       yPos = last->prevRootBox()->blockHeight();
       
       for (RootInlineBox* line = last; line; line = line->nextRootBox())
  @@ -1786,11 +1814,12 @@
       return last;
   }
   
  -bool RenderBlock::matchedEndLine(const BidiIterator& start, const BidiIterator& endLineStart, 
  -                                 RootInlineBox*& endLine, int& endYPos)
  +bool RenderBlock::matchedEndLine(const BidiIterator& start, const BidiStatus& status, BidiContext* context,
  +                                 const BidiIterator& endLineStart, const BidiStatus& endLineStatus,
  +                                 BidiContext* endLineContext, RootInlineBox*& endLine, int& endYPos)
   {
       if (start == endLineStart)
  -        return true; // The common case. All the data we already have is correct.
  +        return status == endLineStatus && *context == *endLineContext;
       else {
           // The first clean line doesn't match, but we can check a handful of following lines to try
           // to match back up.
  @@ -1799,6 +1828,8 @@
           for (int i = 0; i < numLines && line; i++, line = line->nextRootBox()) {
               if (line->lineBreakObj() == start.obj && line->lineBreakPos() == start.pos) {
                   // We have a match.
  +                if (line->lineBreakBidiStatus() != status || *line->lineBreakBidiContext() != *context)
  +                    return false; // ...but the bidi state doesn't match.
                   RootInlineBox* result = line->nextRootBox();
                                   
                   // Set our yPos to be the block height of endLine.
  @@ -1951,7 +1982,7 @@
                   if (!isLineEmpty) {
                       // only check the clear status for non-empty lines.
                       EClear clear = o->style()->clear();
  -                    if(clear != CNONE)
  +                    if (clear != CNONE)
                           m_clearStatus = (EClear) (m_clearStatus | clear);
                   }
               }
  @@ -2067,13 +2098,13 @@
                       }
                   }
               }
  -        } else if ( o->isText() ) {
  +        } else if (o->isText()) {
               RenderText *t = static_cast<RenderText *>(o);
               int strlen = t->stringLength();
               int len = strlen - pos;
               QChar *str = t->text();
   
  -            const Font *f = t->htmlFont( m_firstLine );
  +            const Font *f = t->htmlFont(m_firstLine);
               // proportional font, needs a bit more work.
               int lastSpace = pos;
               int wordSpacing = o->style()->wordSpacing();
  @@ -2201,13 +2232,12 @@
                                   }
                               }
                               goto end; // Didn't fit. Jump to the end.
  -                        }
  -                        else if (pos > 0 && str[pos-1].unicode() == SOFT_HYPHEN)
  +                        } else if (pos > 0 && 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, w+tmpW);
                       }
   
  -                    if( *(str+pos) == '\n' && o->style()->preserveNewline()) {
  +                    if (*(str+pos) == '\n' && o->style()->preserveNewline()) {
                           lBreak.obj = o;
                           lBreak.pos = pos;
                           return lBreak;
  @@ -2239,13 +2269,12 @@
                               lastSpace = pos;
                           }
                       }
  -                }
  -                else if (ignoringSpaces) {
  +                } else if (ignoringSpaces) {
                       // Stop ignoring spaces and begin at this
                       // new point.
                       ignoringSpaces = false;
                       lastSpace = pos; // e.g., "Foo    goo", don't add in any of the ignored spaces.
  -                    BidiIterator startMid ( 0, o, pos );
  +                    BidiIterator startMid(0, o, pos);
                       addMidpoint(startMid);
                   }
   
  @@ -2416,7 +2445,7 @@
               // Add a new end midpoint that stops right at the very end.
               RenderText* text = static_cast<RenderText *>(trailingSpaceObject);
               unsigned pos = text->length() >=2 ? text->length() - 2 : UINT_MAX;
  -            BidiIterator endMid ( 0, trailingSpaceObject, pos );
  +            BidiIterator endMid(0, trailingSpaceObject, pos);
               addMidpoint(endMid);
           }
       }
  
  
  
  1.18      +8 -0      WebCore/khtml/rendering/bidi.h
  
  Index: bidi.h
  ===================================================================
  RCS file: /cvs/root/WebCore/khtml/rendering/bidi.h,v
  retrieving revision 1.17
  retrieving revision 1.18
  diff -u -r1.17 -r1.18
  --- bidi.h	6 Oct 2005 00:53:55 -0000	1.17
  +++ bidi.h	27 Nov 2005 22:52:08 -0000	1.18
  @@ -32,6 +32,14 @@
       class RenderObject;
       class InlineBox;
   
  +    struct BidiStatus {
  +        BidiStatus() : eor(QChar::DirON), lastStrong(QChar::DirON), last(QChar::DirON) {}
  +        
  +        QChar::Direction eor;
  +        QChar::Direction lastStrong;
  +        QChar::Direction last;
  +    };
  +        
       class BidiContext {
       public:
   	BidiContext(unsigned char level, QChar::Direction embedding, BidiContext *parent = 0, bool override = false);
  
  
  
  1.73      +6 -3      WebCore/khtml/rendering/render_block.h
  
  Index: render_block.h
  ===================================================================
  RCS file: /cvs/root/WebCore/khtml/rendering/render_block.h,v
  retrieving revision 1.72
  retrieving revision 1.73
  diff -u -r1.72 -r1.73
  --- render_block.h	3 Nov 2005 21:05:59 -0000	1.72
  +++ render_block.h	27 Nov 2005 22:52:08 -0000	1.73
  @@ -124,9 +124,12 @@
       // the implementation of the following functions is in bidi.cpp
       void bidiReorderLine(const BidiIterator &start, const BidiIterator &end, BidiState &bidi );
       RootInlineBox* determineStartPosition(bool fullLayout, BidiIterator &start, BidiState &bidi);
  -    RootInlineBox* determineEndPosition(RootInlineBox* startBox, BidiIterator& cleanLineStart, int& yPos);
  -    bool matchedEndLine(const BidiIterator& start, const BidiIterator& endLineStart, 
  -                        RootInlineBox*& endLine, int& endYPos);
  +    RootInlineBox* determineEndPosition(RootInlineBox* startBox, BidiIterator& cleanLineStart,
  +                                        BidiStatus& cleanLineBidiStatus, BidiContext*& cleanLineBidiContext,
  +                                        int& yPos);
  +    bool matchedEndLine(const BidiIterator& start, const BidiStatus& status, BidiContext* context,
  +                        const BidiIterator& endLineStart, const BidiStatus& endLineStatus,
  +                        BidiContext* endLineContext, RootInlineBox*& endLine, int& endYPos);
       int skipWhitespace(BidiIterator &, BidiState &);
       BidiIterator findNextLineBreak(BidiIterator &start, BidiState &info );
       RootInlineBox* constructLine(const BidiIterator& start, const BidiIterator& end);
  
  
  
  1.58      +10 -2     WebCore/khtml/rendering/render_line.cpp
  
  Index: render_line.cpp
  ===================================================================
  RCS file: /cvs/root/WebCore/khtml/rendering/render_line.cpp,v
  retrieving revision 1.57
  retrieving revision 1.58
  diff -u -r1.57 -r1.58
  --- render_line.cpp	21 Nov 2005 01:20:25 -0000	1.57
  +++ render_line.cpp	27 Nov 2005 22:52:09 -0000	1.58
  @@ -1216,11 +1216,11 @@
   void RootInlineBox::childRemoved(InlineBox* box)
   {
       if (box->object() == m_lineBreakObj)
  -        setLineBreakInfo(0,0);
  +        setLineBreakInfo(0, 0, 0, 0);
   
       RootInlineBox* prev = prevRootBox();
       if (prev && prev->lineBreakObj() == box->object()) {
  -        prev->setLineBreakInfo(0,0);
  +        prev->setLineBreakInfo(0, 0, 0, 0);
           prev->markDirty();
       }
   }
  @@ -1363,5 +1363,13 @@
       return lastLeaf;
   }
   
  +void RootInlineBox::setLineBreakInfo(RenderObject* obj, uint breakPos, BidiStatus* status, BidiContext* context)
  +{
  +    m_lineBreakObj = obj;
  +    m_lineBreakPos = breakPos;
  +    m_lineBreakContext = context;
  +    if (status)
  +        m_lineBreakBidiStatus = *status;
  +}
   }
   
  
  
  
  1.33      +10 -4     WebCore/khtml/rendering/render_line.h
  
  Index: render_line.h
  ===================================================================
  RCS file: /cvs/root/WebCore/khtml/rendering/render_line.h,v
  retrieving revision 1.32
  retrieving revision 1.33
  diff -u -r1.32 -r1.33
  --- render_line.h	6 Oct 2005 00:53:57 -0000	1.32
  +++ render_line.h	27 Nov 2005 22:52:09 -0000	1.33
  @@ -23,6 +23,8 @@
   #define RENDER_LINE_H
   
   #include "rendering/render_object.h"
  +#include "bidi.h"
  +#include "misc/shared.h"
   
   namespace DOM {
   class AtomicString;
  @@ -302,10 +304,10 @@
   public:
       RootInlineBox(RenderObject* obj)
       : InlineFlowBox(obj), m_topOverflow(0), m_bottomOverflow(0), m_leftOverflow(0), m_rightOverflow(0),
  -      m_lineBreakObj(0), m_lineBreakPos(0), 
  +      m_lineBreakObj(0), m_lineBreakPos(0), m_lineBreakContext(0),
         m_blockHeight(0), m_endsWithBreak(false), m_hasSelectedChildren(false), m_ellipsisBox(0)
       {}
  -    
  +        
       virtual void destroy(RenderArena* renderArena);
       void detachEllipsisBox(RenderArena* renderArena);
   
  @@ -321,8 +323,7 @@
       virtual int rightOverflow() { return m_rightOverflow; }
       virtual void setVerticalOverflowPositions(int top, int bottom) { m_topOverflow = top; m_bottomOverflow = bottom; }
       void setHorizontalOverflowPositions(int left, int right) { m_leftOverflow = left; m_rightOverflow = right; }
  -    void setLineBreakInfo(RenderObject* obj, uint breakPos)
  -    { m_lineBreakObj = obj; m_lineBreakPos = breakPos; }
  +    void setLineBreakInfo(RenderObject* obj, uint breakPos, BidiStatus* status, BidiContext* context);
       void setLineBreakPos(int p) { m_lineBreakPos = p; }
   
       void setBlockHeight(int h) { m_blockHeight = h; }
  @@ -332,6 +333,8 @@
       bool endsWithBreak() const { return m_endsWithBreak; }
       RenderObject* lineBreakObj() const { return m_lineBreakObj; }
       uint lineBreakPos() const { return m_lineBreakPos; }
  +    BidiStatus lineBreakBidiStatus() const { return m_lineBreakBidiStatus; }
  +    BidiContext* lineBreakBidiContext() const { return m_lineBreakContext.get(); }
   
       void childRemoved(InlineBox* box);
   
  @@ -380,6 +383,9 @@
       RenderObject* m_lineBreakObj;
       uint m_lineBreakPos;
       
  +    BidiStatus m_lineBreakBidiStatus;
  +    SharedPtr<BidiContext> m_lineBreakContext;
  +    
       // The height of the block at the end of this line.  This is where the next line starts.
       int m_blockHeight;
       
  
  
  



More information about the webkit-changes mailing list