Changeset 24485 in webkit


Ignore:
Timestamp:
Jul 20, 2007 12:01:55 PM (17 years ago)
Author:
pewtermoose
Message:

2007-07-20 Mitz Pettel <mitz@webkit.org>

Reviewed by Darin.

No layout test possible because there is no change in functionality.

This patch generalizes RenderBlock's implementation of the Unicode Bidi Algorithm
in the form of the BidiResolver class template. An instance of a BidiResolver class
can generate a sequence of runs with corresponding level and override attributes,
given a range specified by start and end iterators. The iterators can optionally
call back to the BidiResolver instance to push or pop explicit embedding levels.

The patch replaces BidiState with a specialization of BidiResolver that uses
BidiIterators and generates BidiRuns. It also eliminates some of the file statics
in bidi.cpp, instead relying on BidiResolver data members.

The patch makes the BidiContext part of BidiStatus, thus making BidiStatus the
entire state that needs to be saved and restored in order to restart the bidi
algorithm at a given point. Previously, you had to keep and pass around two
separate structures, namely the BidiContext and the BidiStatus.

bidiReorderCharacters is implemented without relying on render objects, using
a BidiResolver specialization that uses simple character buffer iterators and
simple run structures.

  • WebCore.pro:
  • WebCore.vcproj/WebCore.vcproj:
  • WebCore.xcodeproj/project.pbxproj:
  • WebCoreSources.bkl:
  • platform/BidiContext.cpp: Added. (WebCore::operator==):
  • platform/BidiContext.h: Added. (WebCore::BidiContext::BidiContext): (WebCore::BidiContext::ref): (WebCore::BidiContext::deref): (WebCore::BidiContext::parent): (WebCore::BidiContext::level): (WebCore::BidiContext::dir): (WebCore::BidiContext::override):
  • platform/BidiReorderCharacters.cpp: Added. (WebCore::CharacterBufferIterator::CharacterBufferIterator): (WebCore::CharacterBufferIterator::offset): (WebCore::CharacterBufferIterator::increment): (WebCore::CharacterBufferIterator::atEnd): (WebCore::CharacterBufferIterator::current): (WebCore::CharacterBufferIterator::direction): (WebCore::CharacterBufferIterator::operator==): (WebCore::CharacterBufferIterator::operator!=): (WebCore::::appendRun): (WebCore::bidiReorderCharacters):
  • platform/BidiReorderCharacters.h: Added.
  • platform/BidiResolver.h: Added. (WebCore::BidiStatus::BidiStatus): (WebCore::operator==): (WebCore::operator!=): (WebCore::BidiCharacterRun::BidiCharacterRun): (WebCore::BidiCharacterRun::reversed): (WebCore::BidiCharacterRun::dirOverride): (WebCore::BidiCharacterRun::next): (WebCore::BidiResolver::): (WebCore::BidiResolver::context): (WebCore::BidiResolver::setContext): (WebCore::BidiResolver::setLastDir): (WebCore::BidiResolver::setLastStrongDir): (WebCore::BidiResolver::setEorDir): (WebCore::BidiResolver::dir): (WebCore::BidiResolver::setDir): (WebCore::BidiResolver::status): (WebCore::BidiResolver::setStatus): (WebCore::BidiResolver::adjustEmbedding): (WebCore::BidiResolver::setAdjustEmbedding): (WebCore::BidiResolver::firstRun): (WebCore::BidiResolver::lastRun): (WebCore::BidiResolver::runCount): (WebCore::::embed): (WebCore::::deleteRuns): (WebCore::::reverseRuns): (WebCore::::createBidiRunsForLine):
  • platform/win/PopupMenuWin.cpp: (WebCore::PopupMenu::paint):
  • rendering/RenderBlock.h:
  • rendering/RenderFileUploadControl.cpp: (WebCore::RenderFileUploadControl::paintObject):
  • rendering/RenderListBox.cpp: (WebCore::RenderListBox::paintItemForeground):
  • rendering/RootInlineBox.cpp: (WebCore::RootInlineBox::childRemoved): (WebCore::RootInlineBox::lineBreakBidiStatus): (WebCore::RootInlineBox::setLineBreakInfo):
  • rendering/RootInlineBox.h: (WebCore::RootInlineBox::RootInlineBox):
  • rendering/bidi.cpp: (WebCore::BidiIterator::BidiIterator): (WebCore::BidiState::deleteRuns): (WebCore::operator==): (WebCore::operator!=): (WebCore::bidiNext): (WebCore::bidiFirst): (WebCore::BidiState::addRun): (WebCore::appendRunsForObject): (WebCore::BidiState::appendRun): (WebCore::RenderBlock::constructLine): (WebCore::RenderBlock::computeHorizontalPositionsForLine): (WebCore::RenderBlock::computeVerticalPositionsForLine): (WebCore::RenderBlock::bidiReorderLine): (WebCore::buildCompactRuns): (WebCore::RenderBlock::layoutInlineChildren): (WebCore::RenderBlock::determineStartPosition): (WebCore::RenderBlock::determineEndPosition): (WebCore::RenderBlock::matchedEndLine): (WebCore::RenderBlock::skipWhitespace):
  • rendering/bidi.h: (WebCore::BidiRun::BidiRun): (WebCore::BidiRun::next):
Location:
trunk/WebCore
Files:
5 added
13 edited

Legend:

Unmodified
Added
Removed
  • trunk/WebCore/ChangeLog

    r24484 r24485  
     12007-07-20  Mitz Pettel  <mitz@webkit.org>
     2
     3        Reviewed by Darin.
     4
     5        - http://bugs.webkit.org/show_bug.cgi?id=14626
     6          Make bidiReorderCharacters independent of RenderBlock
     7
     8        No layout test possible because there is no change in functionality.
     9
     10        This patch generalizes RenderBlock's implementation of the Unicode Bidi Algorithm
     11        in the form of the BidiResolver class template. An instance of a BidiResolver class
     12        can generate a sequence of runs with corresponding level and override attributes,
     13        given a range specified by start and end iterators. The iterators can optionally
     14        call back to the BidiResolver instance to push or pop explicit embedding levels.
     15
     16        The patch replaces BidiState with a specialization of BidiResolver that uses
     17        BidiIterators and generates BidiRuns. It also eliminates some of the file statics
     18        in bidi.cpp, instead relying on BidiResolver data members.
     19
     20        The patch makes the BidiContext part of BidiStatus, thus making BidiStatus the
     21        entire state that needs to be saved and restored in order to restart the bidi
     22        algorithm at a given point. Previously, you had to keep and pass around two
     23        separate structures, namely the BidiContext and the BidiStatus.
     24
     25        bidiReorderCharacters is implemented without relying on render objects, using
     26        a BidiResolver specialization that uses simple character buffer iterators and
     27        simple run structures.
     28
     29        * WebCore.pro:
     30        * WebCore.vcproj/WebCore.vcproj:
     31        * WebCore.xcodeproj/project.pbxproj:
     32        * WebCoreSources.bkl:
     33        * platform/BidiContext.cpp: Added.
     34        (WebCore::operator==):
     35        * platform/BidiContext.h: Added.
     36        (WebCore::BidiContext::BidiContext):
     37        (WebCore::BidiContext::ref):
     38        (WebCore::BidiContext::deref):
     39        (WebCore::BidiContext::parent):
     40        (WebCore::BidiContext::level):
     41        (WebCore::BidiContext::dir):
     42        (WebCore::BidiContext::override):
     43        * platform/BidiReorderCharacters.cpp: Added.
     44        (WebCore::CharacterBufferIterator::CharacterBufferIterator):
     45        (WebCore::CharacterBufferIterator::offset):
     46        (WebCore::CharacterBufferIterator::increment):
     47        (WebCore::CharacterBufferIterator::atEnd):
     48        (WebCore::CharacterBufferIterator::current):
     49        (WebCore::CharacterBufferIterator::direction):
     50        (WebCore::CharacterBufferIterator::operator==):
     51        (WebCore::CharacterBufferIterator::operator!=):
     52        (WebCore::::appendRun):
     53        (WebCore::bidiReorderCharacters):
     54        * platform/BidiReorderCharacters.h: Added.
     55        * platform/BidiResolver.h: Added.
     56        (WebCore::BidiStatus::BidiStatus):
     57        (WebCore::operator==):
     58        (WebCore::operator!=):
     59        (WebCore::BidiCharacterRun::BidiCharacterRun):
     60        (WebCore::BidiCharacterRun::reversed):
     61        (WebCore::BidiCharacterRun::dirOverride):
     62        (WebCore::BidiCharacterRun::next):
     63        (WebCore::BidiResolver::):
     64        (WebCore::BidiResolver::context):
     65        (WebCore::BidiResolver::setContext):
     66        (WebCore::BidiResolver::setLastDir):
     67        (WebCore::BidiResolver::setLastStrongDir):
     68        (WebCore::BidiResolver::setEorDir):
     69        (WebCore::BidiResolver::dir):
     70        (WebCore::BidiResolver::setDir):
     71        (WebCore::BidiResolver::status):
     72        (WebCore::BidiResolver::setStatus):
     73        (WebCore::BidiResolver::adjustEmbedding):
     74        (WebCore::BidiResolver::setAdjustEmbedding):
     75        (WebCore::BidiResolver::firstRun):
     76        (WebCore::BidiResolver::lastRun):
     77        (WebCore::BidiResolver::runCount):
     78        (WebCore::::embed):
     79        (WebCore::::deleteRuns):
     80        (WebCore::::reverseRuns):
     81        (WebCore::::createBidiRunsForLine):
     82        * platform/win/PopupMenuWin.cpp:
     83        (WebCore::PopupMenu::paint):
     84        * rendering/RenderBlock.h:
     85        * rendering/RenderFileUploadControl.cpp:
     86        (WebCore::RenderFileUploadControl::paintObject):
     87        * rendering/RenderListBox.cpp:
     88        (WebCore::RenderListBox::paintItemForeground):
     89        * rendering/RootInlineBox.cpp:
     90        (WebCore::RootInlineBox::childRemoved):
     91        (WebCore::RootInlineBox::lineBreakBidiStatus):
     92        (WebCore::RootInlineBox::setLineBreakInfo):
     93        * rendering/RootInlineBox.h:
     94        (WebCore::RootInlineBox::RootInlineBox):
     95        * rendering/bidi.cpp:
     96        (WebCore::BidiIterator::BidiIterator):
     97        (WebCore::BidiState::deleteRuns):
     98        (WebCore::operator==):
     99        (WebCore::operator!=):
     100        (WebCore::bidiNext):
     101        (WebCore::bidiFirst):
     102        (WebCore::BidiState::addRun):
     103        (WebCore::appendRunsForObject):
     104        (WebCore::BidiState::appendRun):
     105        (WebCore::RenderBlock::constructLine):
     106        (WebCore::RenderBlock::computeHorizontalPositionsForLine):
     107        (WebCore::RenderBlock::computeVerticalPositionsForLine):
     108        (WebCore::RenderBlock::bidiReorderLine):
     109        (WebCore::buildCompactRuns):
     110        (WebCore::RenderBlock::layoutInlineChildren):
     111        (WebCore::RenderBlock::determineStartPosition):
     112        (WebCore::RenderBlock::determineEndPosition):
     113        (WebCore::RenderBlock::matchedEndLine):
     114        (WebCore::RenderBlock::skipWhitespace):
     115        * rendering/bidi.h:
     116        (WebCore::BidiRun::BidiRun):
     117        (WebCore::BidiRun::next):
     118
    11192007-07-20  Darin Adler  <darin@apple.com>
    2120
  • trunk/WebCore/WebCore.pro

    r24477 r24485  
    587587    platform/AtomicString.cpp \
    588588    platform/Base64.cpp \
     589    platform/BidiContext.cpp \
     590    platform/BidiReorderCharacters.cpp \
    589591    platform/ContextMenu.cpp \
    590592    platform/CString.cpp \
  • trunk/WebCore/WebCore.vcproj/WebCore.vcproj

    r24417 r24485  
    28882888                        <File
    28892889                                RelativePath="..\platform\Base64.h"
     2890                                >
     2891                        </File>
     2892                        <File
     2893                                RelativePath="..\platform\BidiContext.cpp"
     2894                                >
     2895                        </File>
     2896                        <File
     2897                                RelativePath="..\platform\BidiContext.h"
     2898                                >
     2899                        </File>
     2900                        <File
     2901                                RelativePath="..\platform\BidiReorderCharacters.cpp"
     2902                                >
     2903                        </File>
     2904                        <File
     2905                                RelativePath="..\platform\BidiReorderCharacters.h"
     2906                                >
     2907                        </File>
     2908                        <File
     2909                                RelativePath="..\platform\BidiResolver.h"
    28902910                                >
    28912911                        </File>
  • trunk/WebCore/WebCore.xcodeproj/project.pbxproj

    r24465 r24485  
    280280                37919C230B7D188600A56998 /* PositionIterator.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 37919C210B7D188600A56998 /* PositionIterator.cpp */; };
    281281                37919C240B7D188600A56998 /* PositionIterator.h in Headers */ = {isa = PBXBuildFile; fileRef = 37919C220B7D188600A56998 /* PositionIterator.h */; settings = {ATTRIBUTES = (); }; };
     282                0F31CBF92B654730BA0535E8 /* BidiContext.h in Headers */ = {isa = PBXBuildFile; fileRef = 514AF320BE854014A7DA49FB /* BidiContext.h */; settings = {ATTRIBUTES = (Private, ); }; };
     283                F971E27FD70F4382BC66D792 /* BidiContext.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A579C284B928484FB9A446BC /* BidiContext.cpp */; };
    282284                448A29BF0A46D9CB0030759F /* JSHTMLOptionsCollection.h in Headers */ = {isa = PBXBuildFile; fileRef = 448A29BD0A46D9CB0030759F /* JSHTMLOptionsCollection.h */; };
    283285                448A29C00A46D9CB0030759F /* JSHTMLOptionsCollection.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 448A29BE0A46D9CB0030759F /* JSHTMLOptionsCollection.cpp */; };
     
    27252727                B2FA3E180AB75A6F000E5AC4 /* JSSVGZoomEvent.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B2FA3D300AB75A6F000E5AC4 /* JSSVGZoomEvent.cpp */; };
    27262728                B2FA3E190AB75A6F000E5AC4 /* JSSVGZoomEvent.h in Headers */ = {isa = PBXBuildFile; fileRef = B2FA3D310AB75A6F000E5AC4 /* JSSVGZoomEvent.h */; };
     2729                B402007C0C4D217800210AA6 /* BidiReorderCharacters.h in Headers */ = {isa = PBXBuildFile; fileRef = B402007A0C4D217800210AA6 /* BidiReorderCharacters.h */; };
     2730                B402007D0C4D217800210AA6 /* BidiReorderCharacters.cpp in Sources */ = {isa = PBXBuildFile; fileRef = B402007B0C4D217800210AA6 /* BidiReorderCharacters.cpp */; };
     2731                B402FD0B0C4C9C3900210AA6 /* BidiResolver.h in Headers */ = {isa = PBXBuildFile; fileRef = B402FD090C4C9C3900210AA6 /* BidiResolver.h */; settings = {ATTRIBUTES = (Private, ); }; };
    27272732                BC066F6F09FEB2FA00C589A7 /* WebCoreTextRenderer.h in Headers */ = {isa = PBXBuildFile; fileRef = BC066F6C09FEB2FA00C589A7 /* WebCoreTextRenderer.h */; settings = {ATTRIBUTES = (Private, ); }; };
    27282733                BC06ED060BFD5BAE00856E9D /* JSHTMLTableSectionElement.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BC06ED040BFD5BAE00856E9D /* JSHTMLTableSectionElement.cpp */; };
     
    29112916                BCEA4790097CAAC80094C9E4 /* CSSComputedStyleDeclaration.h in Headers */ = {isa = PBXBuildFile; fileRef = BCEA477D097CAAC80094C9E4 /* CSSComputedStyleDeclaration.h */; };
    29122917                BCEA4852097D93020094C9E4 /* bidi.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BCEA4813097D93020094C9E4 /* bidi.cpp */; };
    2913                 BCEA4853097D93020094C9E4 /* bidi.h in Headers */ = {isa = PBXBuildFile; fileRef = BCEA4814097D93020094C9E4 /* bidi.h */; settings = {ATTRIBUTES = (Private, ); }; };
     2918                BCEA4853097D93020094C9E4 /* bidi.h in Headers */ = {isa = PBXBuildFile; fileRef = BCEA4814097D93020094C9E4 /* bidi.h */; };
    29142919                BCEA4854097D93020094C9E4 /* break_lines.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BCEA4815097D93020094C9E4 /* break_lines.cpp */; };
    29152920                BCEA4855097D93020094C9E4 /* break_lines.h in Headers */ = {isa = PBXBuildFile; fileRef = BCEA4816097D93020094C9E4 /* break_lines.h */; };
     
    35173522                37919C210B7D188600A56998 /* PositionIterator.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = PositionIterator.cpp; sourceTree = "<group>"; };
    35183523                37919C220B7D188600A56998 /* PositionIterator.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = PositionIterator.h; sourceTree = "<group>"; };
     3524                514AF320BE854014A7DA49FB /* BidiContext.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BidiContext.h; sourceTree = "<group>"; };
     3525                A579C284B928484FB9A446BC /* BidiContext.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = BidiContext.cpp; sourceTree = "<group>"; };
    35193526                448A29BD0A46D9CB0030759F /* JSHTMLOptionsCollection.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = JSHTMLOptionsCollection.h; sourceTree = "<group>"; };
    35203527                448A29BE0A46D9CB0030759F /* JSHTMLOptionsCollection.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = JSHTMLOptionsCollection.cpp; sourceTree = "<group>"; };
     
    60486055                B2FA3D300AB75A6F000E5AC4 /* JSSVGZoomEvent.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = JSSVGZoomEvent.cpp; sourceTree = "<group>"; };
    60496056                B2FA3D310AB75A6F000E5AC4 /* JSSVGZoomEvent.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = JSSVGZoomEvent.h; sourceTree = "<group>"; };
     6057                B402007A0C4D217800210AA6 /* BidiReorderCharacters.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BidiReorderCharacters.h; sourceTree = "<group>"; };
     6058                B402007B0C4D217800210AA6 /* BidiReorderCharacters.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = BidiReorderCharacters.cpp; sourceTree = "<group>"; };
     6059                B402FD090C4C9C3900210AA6 /* BidiResolver.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BidiResolver.h; sourceTree = "<group>"; };
    60506060                BC066F6C09FEB2FA00C589A7 /* WebCoreTextRenderer.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = WebCoreTextRenderer.h; sourceTree = "<group>"; };
    60516061                BC06ED040BFD5BAE00856E9D /* JSHTMLTableSectionElement.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = JSHTMLTableSectionElement.cpp; sourceTree = "<group>"; };
     
    95089518                                E11D51910B2E7A5F0056C188 /* Base64.h */,
    95099519                                E11D51920B2E7A5F0056C188 /* Base64.cpp */,
     9520                                514AF320BE854014A7DA49FB /* BidiContext.h */,
     9521                                A579C284B928484FB9A446BC /* BidiContext.cpp */,
     9522                                B402007A0C4D217800210AA6 /* BidiReorderCharacters.h */,
     9523                                B402007B0C4D217800210AA6 /* BidiReorderCharacters.cpp */,
     9524                                B402FD090C4C9C3900210AA6 /* BidiResolver.h */,
    95109525                                65F5382009B2B55700F3DC4A /* character-sets.txt */,
    95119526                                93C7B5F30B52D89100B5477E /* CharacterNames.h */,
     
    1168011695                                BC772C470C4EB2C60083285F /* XMLHttpRequest.h in Headers */,
    1168111696                                BC772C4F0C4EB3040083285F /* MIMETypeRegistry.h in Headers */,
     11697                                B402FD0B0C4C9C3900210AA6 /* BidiResolver.h in Headers */,
     11698                                B402007C0C4D217800210AA6 /* BidiReorderCharacters.h in Headers */,
     11699                                0F31CBF92B654730BA0535E8 /* BidiContext.h in Headers */,
    1168211700                        );
    1168311701                        runOnlyForDeploymentPostprocessing = 0;
     
    1311513133                                BC772C4E0C4EB3040083285F /* MIMETypeRegistry.cpp in Sources */,
    1311613134                                BC772C5E0C4EB3440083285F /* MIMETypeRegistryMac.mm in Sources */,
     13135                                F971E27FD70F4382BC66D792 /* BidiContext.cpp in Sources */,
     13136                                B402007D0C4D217800210AA6 /* BidiReorderCharacters.cpp in Sources */,
    1311713137                        );
    1311813138                        runOnlyForDeploymentPostprocessing = 0;
  • trunk/WebCore/WebCoreSources.bkl

    r24422 r24485  
    163163        platform/AtomicString.cpp
    164164        platform/Base64.cpp
     165        platform/BidiContext.cpp
     166        platform/BidiReorderCharacters.cpp
    165167        platform/CString.cpp
    166168        platform/ContextMenu.cpp
  • trunk/WebCore/platform/win/PopupMenuWin.cpp

    r24481 r24485  
    2222#include "PopupMenu.h"
    2323
     24#include "BidiReorderCharacters.h"
    2425#include "Document.h"
    2526#include "FloatRect.h"
     
    493494        const UChar* string = itemText.characters();
    494495        TextStyle textStyle(0, 0, 0, false, true);
    495         RenderBlock::CharacterBuffer characterBuffer;
     496        CharacterBuffer characterBuffer;
    496497
    497498        if (clientStyle->direction() == RTL && clientStyle->unicodeBidi() == Override)
     
    500501            // If necessary, reorder characters by running the string through the bidi algorithm
    501502            characterBuffer.append(string, length);
    502             RenderBlock::bidiReorderCharacters(client()->clientDocument(), clientStyle, characterBuffer);
     503            bidiReorderCharacters(characterBuffer, clientStyle->direction() == RTL, clientStyle->unicodeBidi() == Override, clientStyle->visuallyOrdered());
    503504            string = characterBuffer.data();
    504505        }
  • trunk/WebCore/rendering/RenderBlock.h

    r24255 r24485  
    3232namespace WebCore {
    3333
     34class BidiIterator;
     35class BidiRun;
    3436class Position;
     37class RootInlineBox;
     38
     39template <class Iterator, class Run> class BidiResolver;
     40typedef BidiResolver<BidiIterator, BidiRun> BidiState;
    3541
    3642enum CaretType { CursorCaret, DragCaret };
     
    3844class RenderBlock : public RenderFlow {
    3945public:
    40     typedef Vector<UChar, 1024> CharacterBuffer;
    41     static void bidiReorderCharacters(Document*, RenderStyle*, CharacterBuffer&);
    42 
    4346    RenderBlock(Node*);
    4447    virtual ~RenderBlock();
     
    122125
    123126    // the implementation of the following functions is in bidi.cpp
    124     void bidiReorderLine(const BidiIterator& start, const BidiIterator& end, BidiState& bidi);
    125     RootInlineBox* determineStartPosition(bool fullLayout, BidiIterator& start, BidiState& bidi);
     127    void bidiReorderLine(const BidiIterator& start, const BidiIterator& end, BidiState&);
     128    RootInlineBox* determineStartPosition(bool fullLayout, BidiIterator& start, BidiState&);
    126129    RootInlineBox* determineEndPosition(RootInlineBox* startBox, BidiIterator& cleanLineStart,
    127                                         BidiStatus& cleanLineBidiStatus, BidiContext*& cleanLineBidiContext,
     130                                        BidiStatus& cleanLineBidiStatus,
    128131                                        int& yPos);
    129     bool matchedEndLine(const BidiIterator& start, const BidiStatus& status, BidiContext* context,
    130                         const BidiIterator& endLineStart, const BidiStatus& endLineStatus, BidiContext* endLineContext,
     132    bool matchedEndLine(const BidiIterator& start, const BidiStatus& status,
     133                        const BidiIterator& endLineStart, const BidiStatus& endLineStatus,
    131134                        RootInlineBox*& endLine, int& endYPos, int& repaintBottom, int& repaintTop);
    132135    bool generatesLineBoxesForInlineChild(RenderObject*);
     
    135138    RootInlineBox* constructLine(const BidiIterator& start, const BidiIterator& end);
    136139    InlineFlowBox* createLineBoxes(RenderObject*);
    137     void computeHorizontalPositionsForLine(RootInlineBox*, BidiState&);
     140    void computeHorizontalPositionsForLine(RootInlineBox*, bool reachedEnd);
    138141    void computeVerticalPositionsForLine(RootInlineBox*);
    139142    void checkLinesForOverflow();
  • trunk/WebCore/rendering/RenderFileUploadControl.cpp

    r24327 r24485  
    2222#include "RenderFileUploadControl.h"
    2323
     24#include "BidiReorderCharacters.h"
    2425#include "FrameView.h"
    2526#include "GraphicsContext.h"
     
    178179        const UChar* string = displayedFilename.characters();
    179180        TextStyle textStyle(0, 0, 0, false, true);
    180         RenderBlock::CharacterBuffer characterBuffer;
     181        CharacterBuffer characterBuffer;
    181182
    182183        if (style()->direction() == RTL && style()->unicodeBidi() == Override)
     
    185186            // If necessary, reorder characters by running the string through the bidi algorithm
    186187            characterBuffer.append(string, length);
    187             RenderBlock::bidiReorderCharacters(document(), style(), characterBuffer);
     188            bidiReorderCharacters(characterBuffer, style()->direction() == RTL, style()->unicodeBidi() == Override, style()->visuallyOrdered());
    188189            string = characterBuffer.data();
    189190        }
  • trunk/WebCore/rendering/RenderListBox.cpp

    r24327 r24485  
    3232#include "RenderListBox.h"
    3333
     34#include "BidiReorderCharacters.h"
    3435#include "Document.h"
    3536#include "EventHandler.h"
     
    332333    const UChar* string = itemText.characters();
    333334    TextStyle textStyle(0, 0, 0, false, true);
    334     RenderBlock::CharacterBuffer characterBuffer;
     335    CharacterBuffer characterBuffer;
    335336
    336337    if (itemStyle->direction() == RTL && itemStyle->unicodeBidi() == Override)
     
    339340        // If necessary, reorder characters by running the string through the bidi algorithm
    340341        characterBuffer.append(string, length);
    341         RenderBlock::bidiReorderCharacters(document(), itemStyle, characterBuffer);
     342        bidiReorderCharacters(characterBuffer, itemStyle->direction() == RTL, itemStyle->unicodeBidi() == Override, itemStyle->visuallyOrdered());
    342343        string = characterBuffer.data();
    343344    }
  • trunk/WebCore/rendering/RootInlineBox.cpp

    r22037 r24485  
    2323#include "RootInlineBox.h"
    2424
     25#include "BidiResolver.h"
    2526#include "Document.h"
    2627#include "EllipsisBox.h"
     
    195196{
    196197    if (box->object() == m_lineBreakObj)
    197         setLineBreakInfo(0, 0, 0, 0);
     198        setLineBreakInfo(0, 0, BidiStatus());
    198199
    199200    for (RootInlineBox* prev = prevRootBox(); prev && prev->lineBreakObj() == box->object(); prev = prev->prevRootBox()) {
    200         prev->setLineBreakInfo(0, 0, 0, 0);
     201        prev->setLineBreakInfo(0, 0, BidiStatus());
    201202        prev->markDirty();
    202203    }
     
    354355}
    355356
    356 void RootInlineBox::setLineBreakInfo(RenderObject* obj, unsigned breakPos, BidiStatus* status, BidiContext* context)
     357BidiStatus RootInlineBox::lineBreakBidiStatus() const
     358{
     359    return BidiStatus(m_lineBreakBidiStatusEor, m_lineBreakBidiStatusLastStrong, m_lineBreakBidiStatusLast, m_lineBreakContext);
     360}
     361
     362void RootInlineBox::setLineBreakInfo(RenderObject* obj, unsigned breakPos, const BidiStatus& status)
    357363{
    358364    m_lineBreakObj = obj;
    359365    m_lineBreakPos = breakPos;
    360     m_lineBreakContext = context;
    361     if (status) {
    362         m_lineBreakBidiStatusEor = status->eor;
    363         m_lineBreakBidiStatusLastStrong = status->lastStrong;
    364         m_lineBreakBidiStatusLast = status->last;
    365     }
     366    m_lineBreakBidiStatusEor = status.eor;
     367    m_lineBreakBidiStatusLastStrong = status.lastStrong;
     368    m_lineBreakBidiStatusLast = status.last;
     369    m_lineBreakContext = status.context;
    366370}
    367371
  • trunk/WebCore/rendering/RootInlineBox.h

    r22037 r24485  
    2424#define RootInlineBox_h
    2525
    26 #include "bidi.h"
     26#include "BidiContext.h"
    2727#include "InlineFlowBox.h"
    2828
    2929namespace WebCore {
    3030
     31class BidiStatus;
    3132class EllipsisBox;
    3233class HitTestResult;
     
    4041        , m_lineBreakObj(0)
    4142        , m_lineBreakPos(0)
    42         , m_lineBreakContext(0)
    4343    {
    4444    }
     
    6565
    6666    RenderObject* lineBreakObj() const { return m_lineBreakObj; }
    67     BidiStatus lineBreakBidiStatus() const {
    68         BidiStatus status;
    69         status.eor = m_lineBreakBidiStatusEor;
    70         status.lastStrong = m_lineBreakBidiStatusLastStrong;
    71         status.last = m_lineBreakBidiStatusLast;
    72         return status;
    73     }
    74     BidiContext* lineBreakBidiContext() const { return m_lineBreakContext.get(); }
    75     void setLineBreakInfo(RenderObject*, unsigned breakPos, BidiStatus*, BidiContext*);
     67    BidiStatus lineBreakBidiStatus() const;
     68    void setLineBreakInfo(RenderObject*, unsigned breakPos, const BidiStatus&);
    7669
    7770    unsigned lineBreakPos() const { return m_lineBreakPos; }
     
    159152    RenderObject* m_lineBreakObj;
    160153    unsigned m_lineBreakPos;
    161 
    162154    RefPtr<BidiContext> m_lineBreakContext;
    163155
  • trunk/WebCore/rendering/bidi.cpp

    r24278 r24485  
    4646const unsigned cMaxLineDepth = 200;
    4747
    48 // an iterator which traverses all the objects within a block
    49 struct BidiIterator {
    50     BidiIterator() : block(0), obj(0), pos(0) {}
    51     BidiIterator(RenderBlock* b, RenderObject* o, unsigned int p)
    52         : block(b), obj(o), pos(p) {}
    53    
    54     void increment(BidiState& state);
     48class BidiIterator {
     49public:
     50    BidiIterator()
     51        : block(0)
     52        , obj(0)
     53        , pos(0)
     54    {
     55    }
     56
     57    BidiIterator(RenderBlock* b, RenderObject* o, unsigned p)
     58        : block(b)
     59        , obj(o)
     60        , pos(p)
     61    {
     62    }
     63
     64    void increment(BidiResolver<BidiIterator, BidiRun>& state);
    5565    bool atEnd() const;
    56    
     66
    5767    UChar current() const;
    58     Direction direction() const;
     68    WTF::Unicode::Direction direction() const;
    5969
    6070    RenderBlock* block;
     
    6272    unsigned int pos;
    6373};
    64 
    65 struct BidiState {
    66     BidiState() : context(0), dir(OtherNeutral), adjustEmbedding(false), reachedEndOfLine(false) {}
    67    
    68     BidiIterator sor;
    69     BidiIterator eor;
    70     BidiIterator last;
    71     BidiIterator current;
    72     RefPtr<BidiContext> context;
    73     BidiStatus status;
    74     Direction dir;
    75     bool adjustEmbedding;
    76     BidiIterator endOfLine;
    77     bool reachedEndOfLine;
    78     BidiIterator lastBeforeET;
    79 };
    80 
    81 inline bool operator==(const BidiStatus& status1, const BidiStatus& status2)
    82 {
    83     return status1.eor == status2.eor && status1.last == status2.last && status1.lastStrong == status2.lastStrong;
    84 }
    85 
    86 inline bool operator!=(const BidiStatus& status1, const BidiStatus& status2)
    87 {
    88     return !(status1 == status2);
    89 }
    9074
    9175// Used to track a list of chained bidi runs.
     
    9478static BidiRun* sLogicallyLastBidiRun;
    9579static int sBidiRunCount;
    96 static BidiRun* sCompactFirstBidiRun;
    97 static BidiRun* sCompactLastBidiRun;
    98 static int sCompactBidiRunCount;
    99 static bool sBuildingCompactRuns;
    10080
    10181// Midpoint globals.  The goal is not to do any allocation when dealing with
     
    10989static bool isLineEmpty = true;
    11090static bool previousLineBrokeCleanly = true;
    111 static bool emptyRun = true;
    11291static int numSpaces;
    113 
    114 static void embed(Direction, BidiState&);
    115 static void appendRun(BidiState&);
    116 static void deleteBidiRuns(RenderArena*);
    117 
    118 void RenderBlock::bidiReorderCharacters(Document* document, RenderStyle* style, CharacterBuffer& characterBuffer)
    119 {
    120     unsigned bufferLength = characterBuffer.size();
    121     // Create a local copy of the buffer.
    122     String string(characterBuffer.data(), bufferLength);
    123 
    124     // Create anonymous RenderBlock   
    125     RenderStyle* blockStyle = new (document->renderArena()) RenderStyle();
    126     blockStyle->inheritFrom(style);
    127     blockStyle->setDisplay(BLOCK);
    128     blockStyle->setWhiteSpace(PRE);
    129     RenderBlock* block = new (document->renderArena()) RenderBlock(document);
    130     block->setStyle(blockStyle);
    131    
    132     // Create RenderText
    133     RenderText* text = new (document->renderArena()) RenderText(document, string.impl());
    134     text->setStyle(blockStyle);
    135     block->appendChildNode(text, false);
    136    
    137     // Call bidiReorderLine
    138     BidiState bidi;
    139     PassRefPtr<BidiContext> startEmbed;
    140     if (style->direction() == LTR) {
    141         startEmbed = new BidiContext(0, LeftToRight, NULL, style->unicodeBidi() == Override);
    142         bidi.status.eor = LeftToRight;
    143     } else {
    144         startEmbed = new BidiContext(1, RightToLeft, NULL, style->unicodeBidi() == Override);
    145         bidi.status.eor = RightToLeft;
    146     }
    147     bidi.status.lastStrong = startEmbed->dir();
    148     bidi.status.last = startEmbed->dir();
    149     bidi.status.eor = startEmbed->dir();
    150     bidi.context = startEmbed;
    151     bidi.dir = OtherNeutral;
    152     betweenMidpoints = false;
    153    
    154     block->bidiReorderLine(BidiIterator(block, text, 0), BidiIterator(block, text, bufferLength), bidi);
    155    
    156     // Fill the characterBuffer.
    157     int index = 0;
    158     BidiRun* r = sFirstBidiRun;
    159     while (r) {
    160         bool reversed = r->reversed(style->visuallyOrdered());
    161         // If there's only one run, and it doesn't need to be reversed, return early
    162         if (sBidiRunCount == 1 && !reversed)
    163             break;
    164         for (int i = r->start; i < r->stop; ++i) {
    165             if (reversed)
    166                 characterBuffer[index] = string[r->stop + r->start - i - 1];
    167             else
    168                 characterBuffer[index] = string[i];
    169             ++index;
    170         }
    171         r = r->nextRun;
    172     }
    173 
    174     // Tear down temporary RenderBlock, RenderText, and BidiRuns
    175     block->removeChildNode(text, false);
    176     text->destroy();
    177     block->destroy();
    178     deleteBidiRuns(document->renderArena());
    179 }
    18092
    18193static int getBPMWidth(int childValue, Length cssUnit)
     
    267179}
    268180
    269 static void deleteBidiRuns(RenderArena* arena)
    270 {
    271     emptyRun = true;
    272     if (!sFirstBidiRun)
     181template <>
     182void BidiState::deleteRuns()
     183{
     184    if (!m_firstRun)
    273185        return;
    274186
    275     BidiRun* curr = sFirstBidiRun;
     187    BidiRun* curr = m_firstRun;
    276188    while (curr) {
    277         BidiRun* s = curr->nextRun;
    278         curr->destroy(arena);
     189        BidiRun* s = curr->next();
     190        curr->destroy(curr->obj->renderArena());
    279191        curr = s;
    280192    }
    281    
    282     sFirstBidiRun = 0;
    283     sLastBidiRun = 0;
    284     sBidiRunCount = 0;
     193
     194    m_firstRun = 0;
     195    m_lastRun = 0;
     196    m_runCount = 0;
    285197}
    286198
    287199// ---------------------------------------------------------------------
    288200
    289 /* a small helper class used internally to resolve Bidi embedding levels.
    290    Each line of text caches the embedding level at the start of the line for faster
    291    relayouting
    292 */
    293 BidiContext::BidiContext(unsigned char l, Direction e, BidiContext *p, bool o)
    294     : level(l), override(o), m_dir(e)
    295 {
    296     parent = p;
    297     if (p)
    298         p->ref();
    299     count = 0;
    300 }
    301 
    302 BidiContext::~BidiContext()
    303 {
    304     if (parent)
    305         parent->deref();
    306 }
    307 
    308 void BidiContext::ref() const
    309 {
    310     count++;
    311 }
    312 
    313 void BidiContext::deref() const
    314 {
    315     count--;
    316     if (count <= 0)
    317         delete this;
    318 }
    319 
    320 bool operator==(const BidiContext& c1, const BidiContext& c2)
    321 {
    322     if (&c1 == &c2)
    323         return true;
    324     if (c1.level != c2.level || c1.override != c2.override || c1.dir() != c2.dir())
    325         return false;
    326     if (!c1.parent)
    327         return !c2.parent;
    328     return c2.parent && *c1.parent == *c2.parent;
    329 }
    330 
    331 inline bool operator!=(const BidiContext& c1, const BidiContext& c2)
    332 {
    333     return !(c1 == c2);
    334 }
    335 
    336 // ---------------------------------------------------------------------
    337 
    338201inline bool operator==(const BidiIterator& it1, const BidiIterator& it2)
    339202{
    340     if (it1.pos != it2.pos)
    341         return false;
    342     if (it1.obj != it2.obj)
    343         return false;
    344     return true;
     203    return it1.pos == it2.pos && it1.obj == it2.obj;
    345204}
    346205
    347206inline bool operator!=(const BidiIterator& it1, const BidiIterator& it2)
    348207{
    349     if (it1.pos != it2.pos)
    350         return true;
    351     if (it1.obj != it2.obj)
    352         return true;
    353     return false;
     208    return it1.pos != it2.pos || it1.obj != it2.obj;
    354209}
    355210
     
    366221        if (!oldEndOfInline && !current->isFloating() && !current->isReplaced() && !current->isPositioned()) {
    367222            next = current->firstChild();
    368             if (next && bidi.adjustEmbedding && next->isInlineFlow()) {
     223            if (next && bidi.adjustEmbedding() && next->isInlineFlow()) {
    369224                EUnicodeBidi ub = next->style()->unicodeBidi();
    370225                if (ub != UBNormal) {
     
    373228                        ? (dir == RTL ? RightToLeftEmbedding : LeftToRightEmbedding)
    374229                        : (dir == RTL ? RightToLeftOverride : LeftToRightOverride));
    375                     embed(d, bidi);
     230                    bidi.embed(d);
    376231                }
    377232            }
     
    387242
    388243            while (current && current != block) {
    389                 if (bidi.adjustEmbedding && current->isInlineFlow() && current->style()->unicodeBidi() != UBNormal)
    390                     embed(PopDirectionalFormat, bidi);
     244                if (bidi.adjustEmbedding() && current->isInlineFlow() && current->style()->unicodeBidi() != UBNormal)
     245                    bidi.embed(PopDirectionalFormat);
    391246
    392247                next = current->nextSibling();
    393248                if (next) {
    394                     if (bidi.adjustEmbedding && next->isInlineFlow()) {
     249                    if (bidi.adjustEmbedding() && next->isInlineFlow()) {
    395250                        EUnicodeBidi ub = next->style()->unicodeBidi();
    396251                        if (ub != UBNormal) {
     
    399254                                ? (dir == RTL ? RightToLeftEmbedding: LeftToRightEmbedding)
    400255                                : (dir == RTL ? RightToLeftOverride : LeftToRightOverride));
    401                             embed(d, bidi);
     256                            bidi.embed(d);
    402257                        }
    403258                    }
     
    434289    RenderObject* o = block->firstChild();
    435290    if (o->isInlineFlow()) {
    436         if (bidi.adjustEmbedding) {
     291        if (bidi.adjustEmbedding()) {
    437292            EUnicodeBidi ub = o->style()->unicodeBidi();
    438293            if (ub != UBNormal) {
     
    441296                    ? (dir == RTL ? RightToLeftEmbedding : LeftToRightEmbedding)
    442297                    : (dir == RTL ? RightToLeftOverride : LeftToRightOverride));
    443                 embed(d, bidi);
     298                bidi.embed(d);
    444299            }
    445300        }
     
    504359// -------------------------------------------------------------------------------------------------
    505360
    506 static void addRun(BidiRun* bidiRun)
    507 {
    508     if (!sFirstBidiRun)
    509         sFirstBidiRun = sLastBidiRun = bidiRun;
    510     else {
    511         sLastBidiRun->nextRun = bidiRun;
    512         sLastBidiRun = bidiRun;
    513     }
    514     sBidiRunCount++;
    515     bidiRun->compact = sBuildingCompactRuns;
     361template <>
     362inline void BidiState::addRun(BidiRun* bidiRun)
     363{
     364    if (!m_firstRun)
     365        m_firstRun = bidiRun;
     366    else
     367        m_lastRun->m_next = bidiRun;
     368    m_lastRun = bidiRun;
     369    m_runCount++;
     370
     371    sLogicallyLastBidiRun = bidiRun;
    516372
    517373    // Compute the number of spaces in this run,
     
    519375        RenderText* text = static_cast<RenderText*>(bidiRun->obj);
    520376        if (text->characters()) {
    521             for (int i = bidiRun->start; i < bidiRun->stop; i++) {
     377            for (int i = bidiRun->m_start; i < bidiRun->m_stop; i++) {
    522378                UChar c = text->characters()[i];
    523379                if (c == ' ' || c == '\n' || c == '\t')
     
    526382        }
    527383    }
    528 }
    529 
    530 static void reverseRuns(int start, int end)
    531 {
    532     if (start >= end)
    533         return;
    534 
    535     ASSERT(start >= 0 && end < sBidiRunCount);
    536    
    537     // Get the item before the start of the runs to reverse and put it in
    538     // |beforeStart|.  |curr| should point to the first run to reverse.
    539     BidiRun* curr = sFirstBidiRun;
    540     BidiRun* beforeStart = 0;
    541     int i = 0;
    542     while (i < start) {
    543         i++;
    544         beforeStart = curr;
    545         curr = curr->nextRun;
    546     }
    547 
    548     BidiRun* startRun = curr;
    549     while (i < end) {
    550         i++;
    551         curr = curr->nextRun;
    552     }
    553     BidiRun* endRun = curr;
    554     BidiRun* afterEnd = curr->nextRun;
    555 
    556     i = start;
    557     curr = startRun;
    558     BidiRun* newNext = afterEnd;
    559     while (i <= end) {
    560         // Do the reversal.
    561         BidiRun* next = curr->nextRun;
    562         curr->nextRun = newNext;
    563         newNext = curr;
    564         curr = next;
    565         i++;
    566     }
    567 
    568     // Now hook up beforeStart and afterEnd to the newStart and newEnd.
    569     if (beforeStart)
    570         beforeStart->nextRun = endRun;
    571     else
    572         sFirstBidiRun = endRun;
    573 
    574     startRun->nextRun = afterEnd;
    575     if (!afterEnd)
    576         sLastBidiRun = startRun;
    577384}
    578385
     
    637444}
    638445
    639 static void appendRunsForObject(int start, int end, RenderObject* obj, BidiState &bidi)
     446static void appendRunsForObject(int start, int end, RenderObject* obj, BidiState& bidi)
    640447{
    641448    if (start > end || obj->isFloating() ||
     
    660467    else {
    661468        if (!smidpoints || !haveNextMidpoint || (obj != nextMidpoint.obj)) {
    662             addRun(new (obj->renderArena()) BidiRun(start, end, obj, bidi.context.get(), bidi.dir));
     469            bidi.addRun(new (obj->renderArena()) BidiRun(start, end, obj, bidi.context(), bidi.dir()));
    663470            return;
    664471        }
     
    671478            if (nextMidpoint.pos != UINT_MAX) { // UINT_MAX means stop at the object and don't include any of it.
    672479                if (int(nextMidpoint.pos+1) > start)
    673                     addRun(new (obj->renderArena())
    674                         BidiRun(start, nextMidpoint.pos+1, obj, bidi.context.get(), bidi.dir));
     480                    bidi.addRun(new (obj->renderArena())
     481                        BidiRun(start, nextMidpoint.pos+1, obj, bidi.context(), bidi.dir()));
    675482                return appendRunsForObject(nextMidpoint.pos+1, end, obj, bidi);
    676483            }
    677484        }
    678485        else
    679            addRun(new (obj->renderArena()) BidiRun(start, end, obj, bidi.context.get(), bidi.dir));
    680     }
    681 }
    682 
    683 static void appendRun(BidiState &bidi)
    684 {
    685     if (emptyRun || !bidi.eor.obj)
     486           bidi.addRun(new (obj->renderArena()) BidiRun(start, end, obj, bidi.context(), bidi.dir()));
     487    }
     488}
     489
     490template <>
     491void BidiState::appendRun()
     492{
     493    if (emptyRun || eor.atEnd())
    686494        return;
    687 #if defined(BIDI_DEBUG) && BIDI_DEBUG > 1
    688     kdDebug(6041) << "appendRun: dir="<<(int)dir<<endl;
    689 #endif
    690 
    691     bool b = bidi.adjustEmbedding;
    692     bidi.adjustEmbedding = false;
    693 
    694     int start = bidi.sor.pos;
    695     RenderObject *obj = bidi.sor.obj;
    696     while (obj && obj != bidi.eor.obj && obj != bidi.endOfLine.obj) {
    697         appendRunsForObject(start, obj->length(), obj, bidi);       
     495    bool b = m_adjustEmbedding;
     496    m_adjustEmbedding = false;
     497
     498    int start = sor.pos;
     499    RenderObject *obj = sor.obj;
     500    while (obj && obj != eor.obj && obj != endOfLine.obj) {
     501        appendRunsForObject(start, obj->length(), obj, *this);       
    698502        start = 0;
    699         obj = bidiNext(bidi.sor.block, obj, bidi);
     503        obj = bidiNext(sor.block, obj, *this);
    700504    }
    701505    if (obj) {
    702         unsigned pos = obj == bidi.eor.obj ? bidi.eor.pos : UINT_MAX;
    703         if (obj == bidi.endOfLine.obj && bidi.endOfLine.pos <= pos) {
    704             bidi.reachedEndOfLine = true;
    705             pos = bidi.endOfLine.pos;
     506        unsigned pos = obj == eor.obj ? eor.pos : UINT_MAX;
     507        if (obj == endOfLine.obj && endOfLine.pos <= pos) {
     508            reachedEndOfLine = true;
     509            pos = endOfLine.pos;
    706510        }
    707511        // It's OK to add runs for zero-length RenderObjects, just don't make the run larger than it should be
    708512        int end = obj->length() ? pos+1 : 0;
    709         appendRunsForObject(start, end, obj, bidi);
    710     }
    711    
    712     bidi.eor.increment(bidi);
    713     bidi.sor = bidi.eor;
    714     bidi.dir = OtherNeutral;
    715     bidi.status.eor = OtherNeutral;
    716     bidi.adjustEmbedding = b;
    717 }
    718 
    719 static void embed(Direction d, BidiState& bidi)
    720 {
    721     bool b = bidi.adjustEmbedding;
    722     bidi.adjustEmbedding = false;
    723     if (d == PopDirectionalFormat) {
    724         BidiContext *c = bidi.context->parent;
    725         if (c) {
    726             if (!emptyRun && bidi.eor != bidi.last) {
    727                 ASSERT(bidi.status.eor != OtherNeutral);
    728                 // bidi.sor ... bidi.eor ... bidi.last eor; need to append the bidi.sor-bidi.eor run or extend it through bidi.last
    729                 ASSERT(bidi.status.last == EuropeanNumberSeparator
    730                     || bidi.status.last == EuropeanNumberTerminator
    731                     || bidi.status.last == CommonNumberSeparator
    732                     || bidi.status.last == BoundaryNeutral
    733                     || bidi.status.last == BlockSeparator
    734                     || bidi.status.last == SegmentSeparator
    735                     || bidi.status.last == WhiteSpaceNeutral
    736                     || bidi.status.last == OtherNeutral);
    737                 if (bidi.dir == OtherNeutral)
    738                     bidi.dir = bidi.context->dir();
    739                 if (bidi.context->dir() == LeftToRight) {
    740                     // bidi.sor ... bidi.eor ... bidi.last L
    741                     if (bidi.status.eor == EuropeanNumber) {
    742                         if (bidi.status.lastStrong != LeftToRight) {
    743                             bidi.dir = EuropeanNumber;
    744                             appendRun(bidi);
    745                         }
    746                     } else if (bidi.status.eor == ArabicNumber) {
    747                         bidi.dir = ArabicNumber;
    748                         appendRun(bidi);
    749                     } else if (bidi.status.eor != LeftToRight)
    750                         appendRun(bidi);
    751                 } else if (bidi.status.eor != RightToLeft && bidi.status.eor != RightToLeftArabic)
    752                     appendRun(bidi);
    753                 bidi.eor = bidi.last;
    754             }
    755             appendRun(bidi);
    756             emptyRun = true;
    757             // sor for the new run is determined by the higher level (rule X10)
    758             bidi.status.last = bidi.context->dir();
    759             bidi.status.lastStrong = bidi.context->dir();
    760             bidi.context = c;
    761             bidi.status.eor = bidi.context->dir();
    762             bidi.eor.obj = 0;
    763         }
    764     } else {
    765         Direction runDir;
    766         if (d == RightToLeftEmbedding || d == RightToLeftOverride)
    767             runDir = RightToLeft;
    768         else
    769             runDir = LeftToRight;
    770         bool override = d == LeftToRightOverride || d == RightToLeftOverride;
    771 
    772         unsigned char level = bidi.context->level;
    773         if (runDir == RightToLeft) {
    774             if (level%2) // we have an odd level
    775                 level += 2;
    776             else
    777                 level++;
    778         } else {
    779             if (level%2) // we have an odd level
    780                 level++;
    781             else
    782                 level += 2;
    783         }
    784 
    785         if (level < 61) {
    786             if (!emptyRun && bidi.eor != bidi.last) {
    787                 ASSERT(bidi.status.eor != OtherNeutral);
    788                 // bidi.sor ... bidi.eor ... bidi.last eor; need to append the bidi.sor-bidi.eor run or extend it through bidi.last
    789                 ASSERT(bidi.status.last == EuropeanNumberSeparator
    790                     || bidi.status.last == EuropeanNumberTerminator
    791                     || bidi.status.last == CommonNumberSeparator
    792                     || bidi.status.last == BoundaryNeutral
    793                     || bidi.status.last == BlockSeparator
    794                     || bidi.status.last == SegmentSeparator
    795                     || bidi.status.last == WhiteSpaceNeutral
    796                     || bidi.status.last == OtherNeutral);
    797                 if (bidi.dir == OtherNeutral)
    798                     bidi.dir = runDir;
    799                 if (runDir == LeftToRight) {
    800                     // bidi.sor ... bidi.eor ... bidi.last L
    801                     if (bidi.status.eor == EuropeanNumber) {
    802                         if (bidi.status.lastStrong != LeftToRight) {
    803                             bidi.dir = EuropeanNumber;
    804                             appendRun(bidi);
    805                             if (bidi.context->dir() != LeftToRight)
    806                                 bidi.dir = RightToLeft;
    807                         }
    808                     } else if (bidi.status.eor == ArabicNumber) {
    809                         bidi.dir = ArabicNumber;
    810                         appendRun(bidi);
    811                         if (bidi.context->dir() != LeftToRight) {
    812                             bidi.eor = bidi.last;
    813                             bidi.dir = RightToLeft;
    814                             appendRun(bidi);
    815                         }
    816                     } else if (bidi.status.eor != LeftToRight) {
    817                         if (bidi.context->dir() == LeftToRight || bidi.status.lastStrong == LeftToRight)
    818                             appendRun(bidi);
    819                         else
    820                             bidi.dir = RightToLeft;
    821                     }
    822                 } else if (bidi.status.eor != RightToLeft && bidi.status.eor != RightToLeftArabic) {
    823                     // bidi.sor ... bidi.eor ... bidi.last R; bidi.eor=L/EN/AN; EN,AN behave like R (rule N1)
    824                     if (bidi.context->dir() == RightToLeft || bidi.status.lastStrong == RightToLeft || bidi.status.lastStrong == RightToLeftArabic)
    825                         appendRun(bidi);
    826                     else
    827                         bidi.dir = LeftToRight;
    828                 }
    829                 bidi.eor = bidi.last;
    830             }
    831             appendRun(bidi);
    832             emptyRun = true;
    833             bidi.context = new BidiContext(level, runDir, bidi.context.get(), override);
    834             bidi.status.last = runDir;
    835             bidi.status.lastStrong = runDir;
    836             bidi.status.eor = runDir;
    837             bidi.eor.obj = 0;
    838         }
    839     }
    840     bidi.adjustEmbedding = b;
     513        appendRunsForObject(start, end, obj, *this);
     514    }
     515   
     516    eor.increment(*this);
     517    sor = eor;
     518    m_direction = OtherNeutral;
     519    m_status.eor = OtherNeutral;
     520    m_adjustEmbedding = b;
    841521}
    842522
     
    901581
    902582    InlineFlowBox* parentBox = 0;
    903     for (BidiRun* r = sFirstBidiRun; r; r = r->nextRun) {
     583    for (BidiRun* r = sFirstBidiRun; r; r = r->next()) {
    904584        // Create a box for our object.
    905585        bool isOnlyRun = (sBidiRunCount == 1);
     
    920600            if (r->box->isInlineTextBox()) {
    921601                InlineTextBox *text = static_cast<InlineTextBox*>(r->box);
    922                 text->setStart(r->start);
    923                 text->setLen(r->stop - r->start);
     602                text->setStart(r->m_start);
     603                text->setLen(r->m_stop - r->m_start);
    924604                bool visuallyOrdered = r->obj->style()->visuallyOrdered();
    925605                text->m_reversed = r->reversed(visuallyOrdered);
     
    950630}
    951631
    952 void RenderBlock::computeHorizontalPositionsForLine(RootInlineBox* lineBox, BidiState& bidi)
     632void RenderBlock::computeHorizontalPositionsForLine(RootInlineBox* lineBox, bool reachedEnd)
    953633{
    954634    // First determine our total width.
     
    957637    BidiRun* r = 0;
    958638    bool needsWordSpacing = false;
    959     for (r = sFirstBidiRun; r; r = r->nextRun) {
     639    for (r = sFirstBidiRun; r; r = r->next()) {
    960640        if (!r->box || r->obj->isPositioned() || r->box->isLineBreak())
    961641            continue; // Positioned objects are only participating to figure out their
     
    964644        if (r->obj->isText()) {
    965645            RenderText* rt = static_cast<RenderText*>(r->obj);
    966             int textWidth = rt->width(r->start, r->stop-r->start, totWidth, m_firstLine);
     646            int textWidth = rt->width(r->m_start, r->m_stop - r->m_start, totWidth, m_firstLine);
    967647            int effectiveWidth = textWidth;
    968648            int rtLength = rt->textLength();
    969649            if (rtLength != 0) {
    970                 if (r->start == 0 && needsWordSpacing && DeprecatedChar(rt->characters()[r->start]).isSpace())
     650                if (!r->m_start && needsWordSpacing && DeprecatedChar(rt->characters()[r->m_start]).isSpace())
    971651                    effectiveWidth += rt->style(m_firstLine)->font().wordSpacing();
    972                 needsWordSpacing = !DeprecatedChar(rt->characters()[r->stop-1]).isSpace() && r->stop == rtLength;         
     652                needsWordSpacing = !DeprecatedChar(rt->characters()[r->m_stop - 1]).isSpace() && r->m_stop == rtLength;         
    973653            }
    974654            r->box->setWidth(textWidth);
     
    1007687            break;
    1008688        case JUSTIFY:
    1009             if (numSpaces != 0 && !bidi.current.atEnd() && !lineBox->endsWithBreak())
     689            if (numSpaces != 0 && !reachedEnd && !lineBox->endsWithBreak())
    1010690                break;
    1011691            // fall through
     
    1033713
    1034714    if (numSpaces > 0) {
    1035         for (r = sFirstBidiRun; r; r = r->nextRun) {
     715        for (r = sFirstBidiRun; r; r = r->next()) {
    1036716            if (!r->box) continue;
    1037717
     
    1040720                // get the number of spaces in the run
    1041721                int spaces = 0;
    1042                 for ( int i = r->start; i < r->stop; i++ ) {
     722                for (int i = r->m_start; i < r->m_stop; i++) {
    1043723                    UChar c = static_cast<RenderText*>(r->obj)->characters()[i];
    1044724                    if (c == ' ' || c == '\n' || c == '\t')
     
    1079759       
    1080760    // Now make sure we place replaced render objects correctly.
    1081     for (BidiRun* r = sFirstBidiRun; r; r = r->nextRun) {
     761    for (BidiRun* r = sFirstBidiRun; r; r = r->next()) {
    1082762        if (!r->box)
    1083763            continue; // Skip runs with no line boxes.
     
    1103783    }
    1104784
    1105     sFirstBidiRun = 0;
    1106     sLastBidiRun = 0;
    1107     sBidiRunCount = 0;
    1108 
    1109     ASSERT(bidi.dir == OtherNeutral);
    1110 
    1111     emptyRun = true;
    1112 
    1113     bidi.eor.obj = 0;
    1114 
    1115785    numSpaces = 0;
    1116786
    1117     bidi.current = start;
    1118     bidi.last = bidi.current;
    1119     bool pastEnd = false;
    1120     BidiState stateAtEnd;
    1121 
    1122     while (true) {
    1123         Direction dirCurrent;
    1124         if (pastEnd && (previousLineBrokeCleanly || bidi.current.atEnd())) {
    1125             BidiContext *c = bidi.context.get();
    1126             while (c->parent)
    1127                 c = c->parent;
    1128             dirCurrent = c->dir();
    1129             if (previousLineBrokeCleanly) {
    1130                 // A deviation from the Unicode Bidi Algorithm in order to match
    1131                 // Mac OS X text and WinIE: a hard line break resets bidi state.
    1132                 stateAtEnd.context = c;
    1133                 stateAtEnd.status.eor = dirCurrent;
    1134                 stateAtEnd.status.last = dirCurrent;
    1135                 stateAtEnd.status.lastStrong = dirCurrent;
    1136             }
    1137         } else {
    1138             dirCurrent = bidi.current.direction();
    1139             if (bidi.context->override
    1140                     && dirCurrent != RightToLeftEmbedding
    1141                     && dirCurrent != LeftToRightEmbedding
    1142                     && dirCurrent != RightToLeftOverride
    1143                     && dirCurrent != LeftToRightOverride
    1144                     && dirCurrent != PopDirectionalFormat)
    1145                 dirCurrent = bidi.context->dir();
    1146             else if (dirCurrent == NonSpacingMark)
    1147                 dirCurrent = bidi.status.last;
    1148         }
    1149 
    1150         ASSERT(bidi.status.eor != OtherNeutral);
    1151         switch (dirCurrent) {
    1152 
    1153         // embedding and overrides (X1-X9 in the Bidi specs)
    1154         case RightToLeftEmbedding:
    1155         case LeftToRightEmbedding:
    1156         case RightToLeftOverride:
    1157         case LeftToRightOverride:
    1158         case PopDirectionalFormat:
    1159             embed(dirCurrent, bidi);
    1160             break;
    1161 
    1162             // strong types
    1163         case LeftToRight:
    1164             switch(bidi.status.last) {
    1165                 case RightToLeft:
    1166                 case RightToLeftArabic:
    1167                 case EuropeanNumber:
    1168                 case ArabicNumber:
    1169                     if (bidi.status.last != EuropeanNumber || bidi.status.lastStrong != LeftToRight)
    1170                         appendRun(bidi);
    1171                     break;
    1172                 case LeftToRight:
    1173                     break;
    1174                 case EuropeanNumberSeparator:
    1175                 case EuropeanNumberTerminator:
    1176                 case CommonNumberSeparator:
    1177                 case BoundaryNeutral:
    1178                 case BlockSeparator:
    1179                 case SegmentSeparator:
    1180                 case WhiteSpaceNeutral:
    1181                 case OtherNeutral:
    1182                     if (bidi.status.eor == EuropeanNumber) {
    1183                         if (bidi.status.lastStrong != LeftToRight) {
    1184                             // the numbers need to be on a higher embedding level, so let's close that run
    1185                             bidi.dir = EuropeanNumber;
    1186                             appendRun(bidi);
    1187                             if (bidi.context->dir() != LeftToRight) {
    1188                                 // the neutrals take the embedding direction, which is R
    1189                                 bidi.eor = bidi.last;
    1190                                 bidi.dir = RightToLeft;
    1191                                 appendRun(bidi);
    1192                             }
    1193                         }
    1194                     } else if (bidi.status.eor == ArabicNumber) {
    1195                         // Arabic numbers are always on a higher embedding level, so let's close that run
    1196                         bidi.dir = ArabicNumber;
    1197                         appendRun(bidi);
    1198                         if (bidi.context->dir() != LeftToRight) {
    1199                             // the neutrals take the embedding direction, which is R
    1200                             bidi.eor = bidi.last;
    1201                             bidi.dir = RightToLeft;
    1202                             appendRun(bidi);
    1203                         }
    1204                     } else if(bidi.status.eor != LeftToRight) {
    1205                         //last stuff takes embedding dir
    1206                         if (bidi.context->dir() != LeftToRight && bidi.status.lastStrong != LeftToRight) {
    1207                             bidi.eor = bidi.last;
    1208                             bidi.dir = RightToLeft;
    1209                         }
    1210                         appendRun(bidi);
    1211                     }
    1212                 default:
    1213                     break;
    1214             }
    1215             bidi.eor = bidi.current;
    1216             bidi.status.eor = LeftToRight;
    1217             bidi.status.lastStrong = LeftToRight;
    1218             bidi.dir = LeftToRight;
    1219             break;
    1220         case RightToLeftArabic:
    1221         case RightToLeft:
    1222             switch (bidi.status.last) {
    1223                 case LeftToRight:
    1224                 case EuropeanNumber:
    1225                 case ArabicNumber:
    1226                     appendRun(bidi);
    1227                 case RightToLeft:
    1228                 case RightToLeftArabic:
    1229                     break;
    1230                 case EuropeanNumberSeparator:
    1231                 case EuropeanNumberTerminator:
    1232                 case CommonNumberSeparator:
    1233                 case BoundaryNeutral:
    1234                 case BlockSeparator:
    1235                 case SegmentSeparator:
    1236                 case WhiteSpaceNeutral:
    1237                 case OtherNeutral:
    1238                     if (bidi.status.eor != RightToLeft && bidi.status.eor != RightToLeftArabic) {
    1239                         //last stuff takes embedding dir
    1240                         if (bidi.context->dir() != RightToLeft && bidi.status.lastStrong != RightToLeft
    1241                             && bidi.status.lastStrong != RightToLeftArabic) {
    1242                             bidi.eor = bidi.last;
    1243                             bidi.dir = LeftToRight;
    1244                         }
    1245                         appendRun(bidi);
    1246                     }
    1247                 default:
    1248                     break;
    1249             }
    1250             bidi.eor = bidi.current;
    1251             bidi.status.eor = RightToLeft;
    1252             bidi.status.lastStrong = dirCurrent;
    1253             bidi.dir = RightToLeft;
    1254             break;
    1255 
    1256             // weak types:
    1257 
    1258         case EuropeanNumber:
    1259             if (bidi.status.lastStrong != RightToLeftArabic) {
    1260                 // if last strong was AL change EN to AN
    1261                 switch (bidi.status.last) {
    1262                     case EuropeanNumber:
    1263                     case LeftToRight:
    1264                         break;
    1265                     case RightToLeft:
    1266                     case RightToLeftArabic:
    1267                     case ArabicNumber:
    1268                         bidi.eor = bidi.last;
    1269                         appendRun(bidi);
    1270                         bidi.dir = EuropeanNumber;
    1271                         break;
    1272                     case EuropeanNumberSeparator:
    1273                     case CommonNumberSeparator:
    1274                         if (bidi.status.eor == EuropeanNumber)
    1275                             break;
    1276                     case EuropeanNumberTerminator:
    1277                     case BoundaryNeutral:
    1278                     case BlockSeparator:
    1279                     case SegmentSeparator:
    1280                     case WhiteSpaceNeutral:
    1281                     case OtherNeutral:
    1282                         if (bidi.status.eor == RightToLeft) {
    1283                             // neutrals go to R
    1284                             bidi.eor = bidi.status.last == EuropeanNumberTerminator ? bidi.lastBeforeET : bidi.last;
    1285                             appendRun(bidi);
    1286                             bidi.dir = EuropeanNumber;
    1287                         } else if (bidi.status.eor != LeftToRight &&
    1288                                  (bidi.status.eor != EuropeanNumber || bidi.status.lastStrong != LeftToRight) &&
    1289                                  bidi.dir != LeftToRight) {
    1290                             // numbers on both sides, neutrals get right to left direction
    1291                             appendRun(bidi);
    1292                             bidi.eor = bidi.status.last == EuropeanNumberTerminator ? bidi.lastBeforeET : bidi.last;
    1293                             bidi.dir = RightToLeft;
    1294                             appendRun(bidi);
    1295                             bidi.dir = EuropeanNumber;
    1296                         }
    1297                     default:
    1298                         break;
    1299                 }
    1300                 bidi.eor = bidi.current;
    1301                 bidi.status.eor = EuropeanNumber;
    1302                 if (bidi.dir == OtherNeutral)
    1303                     bidi.dir = LeftToRight;
    1304                 break;
    1305             }
    1306         case ArabicNumber:
    1307             dirCurrent = ArabicNumber;
    1308             switch (bidi.status.last) {
    1309                 case LeftToRight:
    1310                     if (bidi.context->dir() == LeftToRight)
    1311                         appendRun(bidi);
    1312                     break;
    1313                 case ArabicNumber:
    1314                     break;
    1315                 case RightToLeft:
    1316                 case RightToLeftArabic:
    1317                 case EuropeanNumber:
    1318                     bidi.eor = bidi.last;
    1319                     appendRun(bidi);
    1320                     break;
    1321                 case CommonNumberSeparator:
    1322                     if (bidi.status.eor == ArabicNumber)
    1323                         break;
    1324                 case EuropeanNumberSeparator:
    1325                 case EuropeanNumberTerminator:
    1326                 case BoundaryNeutral:
    1327                 case BlockSeparator:
    1328                 case SegmentSeparator:
    1329                 case WhiteSpaceNeutral:
    1330                 case OtherNeutral:
    1331                     if (bidi.status.eor != RightToLeft && bidi.status.eor != RightToLeftArabic) {
    1332                         // run of L before neutrals, neutrals take embedding dir (N2)
    1333                         if (bidi.context->dir() == RightToLeft || bidi.status.lastStrong == RightToLeft
    1334                             || bidi.status.lastStrong == RightToLeftArabic) {
    1335                             // the embedding direction is R
    1336                             // close the L run
    1337                             appendRun(bidi);
    1338                             // neutrals become an R run
    1339                             bidi.dir = RightToLeft;
    1340                         } else {
    1341                             // the embedding direction is L
    1342                             // append neutrals to the L run and close it
    1343                             bidi.dir = LeftToRight;
    1344                         }
    1345                     }
    1346                     bidi.eor = bidi.last;
    1347                     appendRun(bidi);
    1348                 default:
    1349                     break;
    1350             }
    1351             bidi.eor = bidi.current;
    1352             bidi.status.eor = ArabicNumber;
    1353             if (bidi.dir == OtherNeutral)
    1354                 bidi.dir = ArabicNumber;
    1355             break;
    1356         case EuropeanNumberSeparator:
    1357         case CommonNumberSeparator:
    1358             break;
    1359         case EuropeanNumberTerminator:
    1360             if (bidi.status.last == EuropeanNumber) {
    1361                 dirCurrent = EuropeanNumber;
    1362                 bidi.eor = bidi.current;
    1363                 bidi.status.eor = dirCurrent;
    1364             } else if (bidi.status.last != EuropeanNumberTerminator)
    1365                 bidi.lastBeforeET = emptyRun ? bidi.eor : bidi.last;
    1366             break;
    1367 
    1368         // boundary neutrals should be ignored
    1369         case BoundaryNeutral:
    1370             if (bidi.eor == bidi.last)
    1371                 bidi.eor = bidi.current;
    1372             break;
    1373             // neutrals
    1374         case BlockSeparator:
    1375             // ### what do we do with newline and paragraph seperators that come to here?
    1376             break;
    1377         case SegmentSeparator:
    1378             // ### implement rule L1
    1379             break;
    1380         case WhiteSpaceNeutral:
    1381             break;
    1382         case OtherNeutral:
    1383             break;
    1384         default:
    1385             break;
    1386         }
    1387 
    1388         if (pastEnd) {
    1389             if (bidi.eor == bidi.current) {
    1390                 if (!bidi.reachedEndOfLine) {
    1391                     bidi.eor = bidi.endOfLine;
    1392                     switch (bidi.status.eor) {
    1393                         case LeftToRight:
    1394                         case RightToLeft:
    1395                         case ArabicNumber:
    1396                             bidi.dir = bidi.status.eor;
    1397                             break;
    1398                         case EuropeanNumber:
    1399                             bidi.dir = bidi.status.lastStrong == LeftToRight ? LeftToRight : EuropeanNumber;
    1400                             break;
    1401                         default:
    1402                             ASSERT(false);
    1403                     }
    1404                     appendRun(bidi);
    1405                 }
    1406                 bidi = stateAtEnd;
    1407                 bidi.dir = OtherNeutral;
    1408                 break;
    1409             }
    1410         }
    1411 
    1412         // set status.last as needed.
    1413         switch (dirCurrent) {
    1414             case EuropeanNumberTerminator:
    1415                 if (bidi.status.last != EuropeanNumber)
    1416                     bidi.status.last = EuropeanNumberTerminator;
    1417                 break;
    1418             case EuropeanNumberSeparator:
    1419             case CommonNumberSeparator:
    1420             case SegmentSeparator:
    1421             case WhiteSpaceNeutral:
    1422             case OtherNeutral:
    1423                 switch(bidi.status.last) {
    1424                     case LeftToRight:
    1425                     case RightToLeft:
    1426                     case RightToLeftArabic:
    1427                     case EuropeanNumber:
    1428                     case ArabicNumber:
    1429                         bidi.status.last = dirCurrent;
    1430                         break;
    1431                     default:
    1432                         bidi.status.last = OtherNeutral;
    1433                     }
    1434                 break;
    1435             case NonSpacingMark:
    1436             case BoundaryNeutral:
    1437             case RightToLeftEmbedding:
    1438             case LeftToRightEmbedding:
    1439             case RightToLeftOverride:
    1440             case LeftToRightOverride:
    1441             case PopDirectionalFormat:
    1442                 // ignore these
    1443                 break;
    1444             case EuropeanNumber:
    1445                 // fall through
    1446             default:
    1447                 bidi.status.last = dirCurrent;
    1448         }
    1449 
    1450         bidi.last = bidi.current;
    1451 
    1452         if (emptyRun && !(dirCurrent == RightToLeftEmbedding
    1453                 || dirCurrent == LeftToRightEmbedding
    1454                 || dirCurrent == RightToLeftOverride
    1455                 || dirCurrent == LeftToRightOverride
    1456                 || dirCurrent == PopDirectionalFormat)) {
    1457             bidi.sor = bidi.current;
    1458             emptyRun = false;
    1459         }
    1460 
    1461         // this causes the operator ++ to open and close embedding levels as needed
    1462         // for the CSS unicode-bidi property
    1463         bidi.adjustEmbedding = true;
    1464         bidi.current.increment(bidi);
    1465         bidi.adjustEmbedding = false;
    1466         if (emptyRun && (dirCurrent == RightToLeftEmbedding
    1467                 || dirCurrent == LeftToRightEmbedding
    1468                 || dirCurrent == RightToLeftOverride
    1469                 || dirCurrent == LeftToRightOverride
    1470                 || dirCurrent == PopDirectionalFormat)) {
    1471             // exclude the embedding char itself from the new run so that ATSUI will never see it
    1472             bidi.eor.obj = 0;
    1473             bidi.last = bidi.current;
    1474             bidi.sor = bidi.current;
    1475         }
    1476 
    1477         if (!pastEnd && (bidi.current == end || bidi.current.atEnd())) {
    1478             if (emptyRun)
    1479                 break;
    1480             stateAtEnd = bidi;
    1481             bidi.endOfLine = bidi.last;
    1482             pastEnd = true;
    1483         }
    1484     }
    1485 
    1486     sLogicallyLastBidiRun = sLastBidiRun;
    1487 
    1488     // reorder line according to run structure...
    1489     // do not reverse for visually ordered web sites
    1490     if (!style()->visuallyOrdered()) {
    1491 
    1492         // first find highest and lowest levels
    1493         unsigned char levelLow = 128;
    1494         unsigned char levelHigh = 0;
    1495         BidiRun* r = sFirstBidiRun;
    1496         while (r) {
    1497             if (r->level > levelHigh)
    1498                 levelHigh = r->level;
    1499             if (r->level < levelLow)
    1500                 levelLow = r->level;
    1501             r = r->nextRun;
    1502         }
    1503 
    1504         // implements reordering of the line (L2 according to Bidi spec):
    1505         // L2. From the highest level found in the text to the lowest odd level on each line,
    1506         // reverse any contiguous sequence of characters that are at that level or higher.
    1507 
    1508         // reversing is only done up to the lowest odd level
    1509         if (!(levelLow%2))
    1510             levelLow++;
    1511 
    1512         int count = sBidiRunCount - 1;
    1513 
    1514         while (levelHigh >= levelLow) {
    1515             int i = 0;
    1516             BidiRun* currRun = sFirstBidiRun;
    1517             while (i < count) {
    1518                 while (i < count && currRun && currRun->level < levelHigh) {
    1519                     i++;
    1520                     currRun = currRun->nextRun;
    1521                 }
    1522                 int start = i;
    1523                 while (i <= count && currRun && currRun->level >= levelHigh) {
    1524                     i++;
    1525                     currRun = currRun->nextRun;
    1526                 }
    1527                 int end = i-1;
    1528                 reverseRuns(start, end);
    1529             }
    1530             levelHigh--;
    1531         }
    1532     }
    1533     bidi.endOfLine.obj = 0;
     787    bidi.createBidiRunsForLine(start, end, style()->visuallyOrdered(), previousLineBrokeCleanly);
     788
     789    sFirstBidiRun = bidi.firstRun();
     790    sLastBidiRun = bidi.lastRun();
     791    sBidiRunCount = bidi.runCount();
    1534792}
    1535793
    1536794static void buildCompactRuns(RenderObject* compactObj, BidiState& bidi)
    1537795{
    1538     sBuildingCompactRuns = true;
    1539     if (!compactObj->isRenderBlock()) {
    1540         // Just append a run for our object.
    1541         isLineEmpty = false;
    1542         addRun(new (compactObj->renderArena()) BidiRun(0, compactObj->length(), compactObj, bidi.context.get(), bidi.dir));
    1543     }
    1544     else {
    1545         // Format the compact like it is its own single line.  We build up all the runs for
    1546         // the little compact and then reorder them for bidi.
    1547         RenderBlock* compactBlock = static_cast<RenderBlock*>(compactObj);
    1548         bidi.adjustEmbedding = true;
    1549         BidiIterator start(compactBlock, bidiFirst(compactBlock, bidi), 0);
    1550         bidi.adjustEmbedding = false;
    1551         BidiIterator end = start;
    1552    
    1553         betweenMidpoints = false;
    1554         isLineEmpty = true;
    1555         previousLineBrokeCleanly = true;
    1556        
    1557         end = compactBlock->findNextLineBreak(start, bidi);
    1558         if (!isLineEmpty)
    1559             compactBlock->bidiReorderLine(start, end, bidi);
    1560     }
    1561 
    1562     sCompactFirstBidiRun = sFirstBidiRun;
    1563     sCompactLastBidiRun = sLastBidiRun;
    1564     sCompactBidiRunCount = sBidiRunCount;
     796    ASSERT(compactObj->isRenderBlock());
     797    ASSERT(!bidi.firstRun());
     798
     799    // Format the compact like it is its own single line.  We build up all the runs for
     800    // the little compact and then reorder them for bidi.
     801    RenderBlock* compactBlock = static_cast<RenderBlock*>(compactObj);
     802    bidi.setAdjustEmbedding(true);
     803    BidiIterator start(compactBlock, bidiFirst(compactBlock, bidi), 0);
     804    bidi.setAdjustEmbedding(false);
     805    BidiIterator end = start;
     806
     807    betweenMidpoints = false;
     808    isLineEmpty = true;
     809    previousLineBrokeCleanly = true;
     810   
     811    end = compactBlock->findNextLineBreak(start, bidi);
     812    if (!isLineEmpty)
     813        compactBlock->bidiReorderLine(start, end, bidi);
     814
     815    for (BidiRun* run = bidi.firstRun(); run; run = run->next())
     816        run->compact = true;
    1565817   
    1566818    sNumMidpoints = 0;
    1567819    sCurrMidpoint = 0;
    1568820    betweenMidpoints = false;
    1569     sBuildingCompactRuns = false;
    1570821}
    1571822
     
    1651902        }
    1652903
    1653         BidiContext *startEmbed;
    1654         if (style()->direction() == LTR) {
    1655             startEmbed = new BidiContext(0, LeftToRight, NULL, style()->unicodeBidi() == Override);
    1656             bidi.status.eor = LeftToRight;
    1657         } else {
    1658             startEmbed = new BidiContext(1, RightToLeft, NULL, style()->unicodeBidi() == Override);
    1659             bidi.status.eor = RightToLeft;
    1660         }
    1661 
    1662         bidi.status.lastStrong = startEmbed->dir();
    1663         bidi.status.last = startEmbed->dir();
    1664         bidi.status.eor = startEmbed->dir();
    1665         bidi.context = startEmbed;
    1666         bidi.dir = OtherNeutral;
     904        BidiContext* startEmbed;
     905        if (style()->direction() == LTR)
     906            startEmbed = new BidiContext(0, LeftToRight, style()->unicodeBidi() == Override);
     907        else
     908            startEmbed = new BidiContext(1, RightToLeft, style()->unicodeBidi() == Override);
     909
     910        bidi.setLastStrongDir(startEmbed->dir());
     911        bidi.setLastDir(startEmbed->dir());
     912        bidi.setEorDir(startEmbed->dir());
     913        bidi.setContext(startEmbed);
    1667914       
    1668915        if (!smidpoints)
     
    1671918        sNumMidpoints = 0;
    1672919        sCurrMidpoint = 0;
    1673         sCompactFirstBidiRun = sCompactLastBidiRun = 0;
    1674         sCompactBidiRunCount = 0;
    1675920       
    1676921        // We want to skip ahead to the first dirty line
     
    1682927        BidiIterator cleanLineStart;
    1683928        BidiStatus cleanLineBidiStatus;
    1684         BidiContext* cleanLineBidiContext = 0;
    1685929        int endLineYPos = 0;
    1686930        RootInlineBox* endLine = (fullLayout || !startLine) ?
    1687                                  0 : determineEndPosition(startLine, cleanLineStart, cleanLineBidiStatus, cleanLineBidiContext, endLineYPos);
    1688         if (endLine && cleanLineBidiContext)
    1689             cleanLineBidiContext->ref();
     931                                 0 : determineEndPosition(startLine, cleanLineStart, cleanLineBidiStatus, endLineYPos);
     932
    1690933        if (startLine) {
    1691934            useRepaintBounds = true;
     
    1709952        while (!end.atEnd()) {
    1710953            start = end;
    1711             if (endLine && (endLineMatched = matchedEndLine(start, bidi.status, bidi.context.get(), cleanLineStart, cleanLineBidiStatus, cleanLineBidiContext, endLine, endLineYPos, repaintBottom, repaintTop)))
     954            if (endLine && (endLineMatched = matchedEndLine(start, bidi.status(), cleanLineStart, cleanLineBidiStatus, endLine, endLineYPos, repaintBottom, repaintTop)))
    1712955                break;
    1713956
     
    1721964            end = findNextLineBreak(start, bidi);
    1722965            if (start.atEnd()) {
    1723                 deleteBidiRuns(renderArena());
     966                bidi.deleteRuns();
    1724967                break;
    1725968            }
     
    1730973                // At the same time we figure out where border/padding/margin should be applied for
    1731974                // inline flow boxes.
    1732                 if (sCompactFirstBidiRun) {
    1733                     // We have a compact line sharing this line.  Link the compact runs
    1734                     // to our runs to create a single line of runs.
    1735                     sCompactLastBidiRun->nextRun = sFirstBidiRun;
    1736                     sFirstBidiRun = sCompactFirstBidiRun;
    1737                     sBidiRunCount += sCompactBidiRunCount;
    1738                 }
    1739975
    1740976                RootInlineBox* lineBox = 0;
     
    1743979                    if (lineBox) {
    1744980                        lineBox->setEndsWithBreak(previousLineBrokeCleanly);
    1745                        
     981
    1746982                        // Now we position all of our text runs horizontally.
    1747                         computeHorizontalPositionsForLine(lineBox, bidi);
     983                        computeHorizontalPositionsForLine(lineBox, end.atEnd());
    1748984       
    1749985                        // Now position our text runs vertically.
     
    1758994                }
    1759995
    1760                 deleteBidiRuns(renderArena());
     996                bidi.deleteRuns();
    1761997               
    1762998                if (end == start) {
    1763                     bidi.adjustEmbedding = true;
     999                    bidi.setAdjustEmbedding(true);
    17641000                    end.increment(bidi);
    1765                     bidi.adjustEmbedding = false;
     1001                    bidi.setAdjustEmbedding(false);
    17661002                }
    17671003
    17681004                if (lineBox) {
    1769                     lineBox->setLineBreakInfo(end.obj, end.pos, &bidi.status, bidi.context.get());
     1005                    lineBox->setLineBreakInfo(end.obj, end.pos, bidi.status());
    17701006                    if (useRepaintBounds) {
    17711007                        repaintTop = min(repaintTop, lineBox->topOverflow());
     
    17801016            sNumMidpoints = 0;
    17811017            sCurrMidpoint = 0;
    1782             sCompactFirstBidiRun = sCompactLastBidiRun = 0;
    1783             sCompactBidiRunCount = 0;
    17841018        }
    17851019       
     
    18121046                }
    18131047            }
    1814             if (cleanLineBidiContext)
    1815                 cleanLineBidiContext->deref();
    18161048        }
    18171049    }
     
    18901122        startObj = last->lineBreakObj();
    18911123        pos = last->lineBreakPos();
    1892         bidi.status = last->lineBreakBidiStatus();
    1893         bidi.context = last->lineBreakBidiContext();
     1124        bidi.setStatus(last->lineBreakBidiStatus());
    18941125    } else {
    1895         bidi.adjustEmbedding = true;
     1126        bidi.setAdjustEmbedding(true);
    18961127        startObj = bidiFirst(this, bidi, 0);
    1897         bidi.adjustEmbedding = false;
     1128        bidi.setAdjustEmbedding(false);
    18981129    }
    18991130       
     
    19031134}
    19041135
    1905 RootInlineBox* RenderBlock::determineEndPosition(RootInlineBox* startLine, BidiIterator& cleanLineStart,
    1906                                                  BidiStatus& cleanLineBidiStatus, BidiContext*& cleanLineBidiContext,
    1907                                                  int& yPos)
     1136RootInlineBox* RenderBlock::determineEndPosition(RootInlineBox* startLine, BidiIterator& cleanLineStart, BidiStatus& cleanLineBidiStatus, int& yPos)
    19081137{
    19091138    RootInlineBox* last = 0;
     
    19251154    cleanLineStart = BidiIterator(this, prev->lineBreakObj(), prev->lineBreakPos());
    19261155    cleanLineBidiStatus = prev->lineBreakBidiStatus();
    1927     cleanLineBidiContext = prev->lineBreakBidiContext();
    19281156    yPos = prev->blockHeight();
    19291157   
     
    19351163}
    19361164
    1937 bool RenderBlock::matchedEndLine(const BidiIterator& start, const BidiStatus& status, BidiContext* context,
    1938                                  const BidiIterator& endLineStart, const BidiStatus& endLineStatus, BidiContext* endLineContext,
     1165bool RenderBlock::matchedEndLine(const BidiIterator& start, const BidiStatus& status,
     1166                                 const BidiIterator& endLineStart, const BidiStatus& endLineStatus,
    19391167                                 RootInlineBox*& endLine, int& endYPos, int& repaintBottom, int& repaintTop)
    19401168{
    19411169    if (start == endLineStart)
    1942         return status == endLineStatus && *context == *endLineContext;
     1170        return status == endLineStatus;
    19431171    else {
    19441172        // The first clean line doesn't match, but we can check a handful of following lines to try
     
    19491177            if (line->lineBreakObj() == start.obj && line->lineBreakPos() == start.pos) {
    19501178                // We have a match.
    1951                 if (line->lineBreakBidiStatus() != status || *line->lineBreakBidiContext() != *context)
     1179                if (line->lineBreakBidiStatus() != status)
    19521180                    return false; // ...but the bidi state doesn't match.
    19531181                RootInlineBox* result = line->nextRootBox();
     
    20371265    // object iteration process.
    20381266    int w = lineWidth(m_height);
    2039     bidi.adjustEmbedding = true;
     1267    bidi.setAdjustEmbedding(true);
    20401268
    20411269    while (!it.atEnd() && !requiresLineBox(it)) {
     
    20791307    }
    20801308
    2081     bidi.adjustEmbedding = false;
     1309    bidi.setAdjustEmbedding(false);
    20821310    return w;
    20831311}
  • trunk/WebCore/rendering/bidi.h

    r19414 r24485  
    2525#define bidi_h
    2626
    27 #include <wtf/unicode/Unicode.h>
     27#include "BidiResolver.h"
    2828
    2929namespace WebCore {
    3030
    31     class RenderArena;
    32     class RenderBlock;
    33     class RenderObject;
    34     class InlineBox;
     31class BidiIterator;
     32class RenderArena;
     33class RenderBlock;
     34class RenderObject;
     35class InlineBox;
    3536
    36     struct BidiStatus {
    37         BidiStatus()
    38             : eor(WTF::Unicode::OtherNeutral)
    39             , lastStrong(WTF::Unicode::OtherNeutral)
    40             , last(WTF::Unicode::OtherNeutral)
    41         {
    42         }
     37struct BidiRun : BidiCharacterRun {
     38    BidiRun(int start, int stop, RenderObject* o, BidiContext* context, WTF::Unicode::Direction dir)
     39        : BidiCharacterRun(start, stop, context, dir)
     40        , obj(o)
     41        , box(0)
     42        , compact(false)
     43    {
     44    }
    4345
    44         WTF::Unicode::Direction eor;
    45         WTF::Unicode::Direction lastStrong;
    46         WTF::Unicode::Direction last;
    47     };
     46    void destroy(RenderArena*);
    4847
    49     class BidiContext {
    50     public:
    51         BidiContext(unsigned char level, WTF::Unicode::Direction embedding, BidiContext* parent = 0, bool override = false);
    52         ~BidiContext();
     48    // Overloaded new operator.
     49    void* operator new(size_t, RenderArena*) throw();
    5350
    54         void ref() const;
    55         void deref() const;
     51    // Overridden to prevent the normal delete from being called.
     52    void operator delete(void*, size_t);
    5653
    57         WTF::Unicode::Direction dir() const { return static_cast<WTF::Unicode::Direction>(m_dir); }
     54    BidiRun* next() { return static_cast<BidiRun*>(m_next); }
    5855
    59         unsigned char level;
    60         bool override : 1;
    61         unsigned m_dir : 5; // WTF::Unicode::Direction
     56private:
     57    // The normal operator new is disallowed.
     58    void* operator new(size_t) throw();
    6259
    63         BidiContext* parent;
    64 
    65         // refcounting....
    66         mutable int count;
    67     };
    68 
    69     struct BidiRun {
    70         BidiRun(int start_, int stop_, RenderObject* o, BidiContext* context, WTF::Unicode::Direction dir)
    71             : start(start_)
    72             , stop(stop_)
    73             , obj(o)
    74             , box(0)
    75             , override(context->override)
    76             , nextRun(0)
    77         {
    78             if (dir == WTF::Unicode::OtherNeutral)
    79                 dir = context->dir();
    80 
    81             level = context->level;
    82 
    83             // add level of run (cases I1 & I2)
    84             if (level % 2) {
    85                 if(dir == WTF::Unicode::LeftToRight || dir == WTF::Unicode::ArabicNumber || dir == WTF::Unicode::EuropeanNumber)
    86                     level++;
    87             } else {
    88                 if (dir == WTF::Unicode::RightToLeft)
    89                     level++;
    90                 else if (dir == WTF::Unicode::ArabicNumber || dir == WTF::Unicode::EuropeanNumber)
    91                     level += 2;
    92             }
    93         }
    94 
    95         void destroy(RenderArena*);
    96 
    97         // Overloaded new operator.
    98         void* operator new(size_t, RenderArena*) throw();
    99 
    100         // Overridden to prevent the normal delete from being called.
    101         void operator delete(void*, size_t);
    102 
    103     private:
    104         // The normal operator new is disallowed.
    105         void* operator new(size_t) throw();
    106 
    107     public:
    108         int start;
    109         int stop;
    110 
    111         RenderObject* obj;
    112         InlineBox* box;
    113 
    114         // explicit + implicit levels here
    115         unsigned char level;
    116         bool override : 1;
    117         bool compact : 1;
    118 
    119         BidiRun* nextRun;
    120        
    121         bool reversed(bool visuallyOrdered) { return level % 2 && !visuallyOrdered; }
    122         bool dirOverride(bool visuallyOrdered) { return override || visuallyOrdered; }
    123     };
    124 
    125     struct BidiIterator;
    126     struct BidiState;
     60public:
     61    RenderObject* obj;
     62    InlineBox* box;
     63    bool compact;
     64};
    12765
    12866} // namespace WebCore
Note: See TracChangeset for help on using the changeset viewer.