Changeset 32605 in webkit


Ignore:
Timestamp:
Apr 27, 2008 9:46:17 PM (16 years ago)
Author:
mitz@apple.com
Message:

WebCore:

Reviewed by Darin Adler.

Test: editing/selection/move-left-right.html

  • editing/SelectionController.cpp: (WebCore::SelectionController::modifyMovingRight): Added. Currently implemented for character granularity, all other being treated as "forward". (WebCore::SelectionController::modifyMovingForward): Renamed modifyMovingRightForward() to this. (WebCore::SelectionController::modifyMovingLeft): Added. Currently implemented for character granularity, all other being treated as "backward". (WebCore::SelectionController::modifyMovingBackward): Renamed modifyMovingLeftBackward() to this. (WebCore::SelectionController::modify): Changed to call either the visual (left/right) or logical (backward/forward) methods depending on the 'dir' argument for moves.
  • editing/SelectionController.h:
  • editing/VisiblePosition.cpp: (WebCore::VisiblePosition::leftVisuallyDistinctCandidate): Added. (WebCore::VisiblePosition::left): Added. (WebCore::VisiblePosition::rightVisuallyDistinctCandidate): Added. (WebCore::VisiblePosition::right): Added.
  • editing/VisiblePosition.h:

LayoutTests:

Reviewed by Darin Adler.

  • editing/selection/move-left-right-expected.txt: Added.
  • editing/selection/move-left-right.html: Added.
  • platform/mac/editing/selection/move-left-right-expected.txt: Added.
Location:
trunk
Files:
3 added
6 edited

Legend:

Unmodified
Added
Removed
  • trunk/LayoutTests/ChangeLog

    r32604 r32605  
     12008-04-27  Dan Bernstein  <mitz@apple.com>
     2
     3        Reviewed by Darin Adler.
     4
     5        - test for https://bugs.webkit.org/show_bug.cgi?id=3729
     6          <rdar://problem/4036353> REGRESSION: arrow keys move insertion bar backwards in RTL text
     7
     8        * editing/selection/move-left-right-expected.txt: Added.
     9        * editing/selection/move-left-right.html: Added.
     10        * platform/mac/editing/selection/move-left-right-expected.txt: Added.
     11
    1122008-04-27  Sam Weinig  <sam@webkit.org>
    213
  • trunk/WebCore/ChangeLog

    r32604 r32605  
     12008-04-27  Dan Bernstein  <mitz@apple.com>
     2
     3        Reviewed by Darin Adler.
     4
     5        - fix https://bugs.webkit.org/show_bug.cgi?id=3729
     6          <rdar://problem/4036353> REGRESSION: arrow keys move insertion bar backwards in RTL text
     7
     8        Test: editing/selection/move-left-right.html
     9
     10        * editing/SelectionController.cpp:
     11        (WebCore::SelectionController::modifyMovingRight): Added. Currently
     12        implemented for character granularity, all other being treated as
     13        "forward".
     14        (WebCore::SelectionController::modifyMovingForward): Renamed
     15        modifyMovingRightForward() to this.
     16        (WebCore::SelectionController::modifyMovingLeft): Added. Currently
     17        implemented for character granularity, all other being treated as
     18        "backward".
     19        (WebCore::SelectionController::modifyMovingBackward): Renamed
     20        modifyMovingLeftBackward() to this.
     21        (WebCore::SelectionController::modify): Changed to call either the
     22        visual (left/right) or logical (backward/forward) methods depending on
     23        the 'dir' argument for moves.
     24        * editing/SelectionController.h:
     25        * editing/VisiblePosition.cpp:
     26        (WebCore::VisiblePosition::leftVisuallyDistinctCandidate): Added.
     27        (WebCore::VisiblePosition::left): Added.
     28        (WebCore::VisiblePosition::rightVisuallyDistinctCandidate): Added.
     29        (WebCore::VisiblePosition::right): Added.
     30        * editing/VisiblePosition.h:
     31
    1322008-04-27  Sam Weinig  <sam@webkit.org>
    233
  • trunk/WebCore/editing/SelectionController.cpp

    r32508 r32605  
    286286}
    287287
    288 VisiblePosition SelectionController::modifyMovingRightForward(TextGranularity granularity)
     288VisiblePosition SelectionController::modifyMovingRight(TextGranularity granularity)
     289{
     290    VisiblePosition pos;
     291    switch (granularity) {
     292        case CharacterGranularity:
     293            if (isRange())
     294                pos = VisiblePosition(m_sel.end(), m_sel.affinity());
     295            else
     296                pos = VisiblePosition(m_sel.extent(), m_sel.affinity()).right(true);
     297            break;
     298        case WordGranularity:
     299        case SentenceGranularity:
     300        case LineGranularity:
     301        case ParagraphGranularity:
     302        case SentenceBoundary:
     303        case LineBoundary:
     304        case ParagraphBoundary:
     305        case DocumentBoundary:
     306            // FIXME: Implement all of the above.
     307            pos = modifyMovingForward(granularity);
     308            break;
     309    }
     310    return pos;
     311}
     312
     313VisiblePosition SelectionController::modifyMovingForward(TextGranularity granularity)
    289314{
    290315    VisiblePosition pos;
     
    379404}
    380405
    381 VisiblePosition SelectionController::modifyMovingLeftBackward(TextGranularity granularity)
     406VisiblePosition SelectionController::modifyMovingLeft(TextGranularity granularity)
     407{
     408    VisiblePosition pos;
     409    switch (granularity) {
     410        case CharacterGranularity:
     411            if (isRange())
     412                pos = VisiblePosition(m_sel.start(), m_sel.affinity());
     413            else
     414                pos = VisiblePosition(m_sel.extent(), m_sel.affinity()).left(true);
     415            break;
     416        case WordGranularity:
     417        case SentenceGranularity:
     418        case LineGranularity:
     419        case ParagraphGranularity:
     420        case SentenceBoundary:
     421        case LineBoundary:
     422        case ParagraphBoundary:
     423        case DocumentBoundary:
     424            // FIXME: Implement all of the above.
     425            pos = modifyMovingBackward(granularity);
     426            break;
     427    }
     428    return pos;
     429}
     430
     431VisiblePosition SelectionController::modifyMovingBackward(TextGranularity granularity)
    382432{
    383433    VisiblePosition pos;
     
    441491    VisiblePosition pos;
    442492    switch (dir) {
    443         // EDIT FIXME: These need to handle bidi
    444493        case RIGHT:
     494            if (alter == MOVE)
     495                pos = modifyMovingRight(granularity);
     496            else
     497                pos = modifyExtendingRightForward(granularity);
     498            break;
    445499        case FORWARD:
    446500            if (alter == EXTEND)
    447501                pos = modifyExtendingRightForward(granularity);
    448502            else
    449                 pos = modifyMovingRightForward(granularity);
     503                pos = modifyMovingForward(granularity);
    450504            break;
    451505        case LEFT:
     506            if (alter == MOVE)
     507                pos = modifyMovingLeft(granularity);
     508            else
     509                pos = modifyExtendingLeftBackward(granularity);
     510            break;
    452511        case BACKWARD:
    453512            if (alter == EXTEND)
    454513                pos = modifyExtendingLeftBackward(granularity);
    455514            else
    456                 pos = modifyMovingLeftBackward(granularity);
     515                pos = modifyMovingBackward(granularity);
    457516            break;
    458517    }
  • trunk/WebCore/editing/SelectionController.h

    r29581 r32605  
    126126
    127127    VisiblePosition modifyExtendingRightForward(TextGranularity);
    128     VisiblePosition modifyMovingRightForward(TextGranularity);
     128    VisiblePosition modifyMovingRight(TextGranularity);
     129    VisiblePosition modifyMovingForward(TextGranularity);
    129130    VisiblePosition modifyExtendingLeftBackward(TextGranularity);
    130     VisiblePosition modifyMovingLeftBackward(TextGranularity);
     131    VisiblePosition modifyMovingLeft(TextGranularity);
     132    VisiblePosition modifyMovingBackward(TextGranularity);
    131133
    132134    void layout();
  • trunk/WebCore/editing/VisiblePosition.cpp

    r32508 r32605  
    103103}
    104104
     105Position VisiblePosition::leftVisuallyDistinctCandidate() const
     106{
     107    Position p = m_deepPosition;
     108    Position downstreamStart = p.downstream();
     109
     110    TextDirection primaryDirection = LTR;
     111    for (RenderObject* r = p.node()->renderer(); r; r = r->parent()) {
     112        if (r->isBlockFlow()) {
     113            primaryDirection = r->style()->direction();
     114            break;
     115        }
     116    }
     117
     118    while (true) {
     119        InlineBox* box;
     120        int offset;
     121        p.getInlineBoxAndOffset(m_affinity, primaryDirection, box, offset);
     122        if (!box)
     123            return primaryDirection == LTR ? previousVisuallyDistinctCandidate(p) : nextVisuallyDistinctCandidate(p);
     124
     125        RenderObject* renderer = box->object();
     126
     127        while (true) {
     128            if ((renderer->isReplaced() || renderer->isBR()) && offset == box->caretRightmostOffset())
     129                return box->direction() == LTR ? previousVisuallyDistinctCandidate(p) : nextVisuallyDistinctCandidate(p);
     130
     131            offset = box->direction() == LTR ? renderer->previousOffset(offset) : renderer->nextOffset(offset);
     132
     133            int caretMinOffset = box->caretMinOffset();
     134            int caretMaxOffset = box->caretMaxOffset();
     135
     136            if (offset > caretMinOffset && offset < caretMaxOffset)
     137                break;
     138
     139            if (box->direction() == LTR ? offset < caretMinOffset : offset > caretMaxOffset) {
     140                // Overshot to the left.
     141                InlineBox* prevBox = box->prevLeafChild();
     142                if (!prevBox)
     143                    return primaryDirection == LTR ? previousVisuallyDistinctCandidate(p) : nextVisuallyDistinctCandidate(p);;
     144
     145                // Reposition at the other logical position corresponding to our edge's visual position and go for another round.
     146                box = prevBox;
     147                renderer = box->object();
     148                offset = prevBox->caretRightmostOffset();
     149                continue;
     150            }
     151
     152            ASSERT(offset == box->caretLeftmostOffset());
     153
     154            unsigned char level = box->bidiLevel();
     155            InlineBox* prevBox = box->prevLeafChild();
     156
     157            if (box->direction() == primaryDirection) {
     158                if (!prevBox || prevBox->bidiLevel() >= level)
     159                    break;
     160
     161                level = prevBox->bidiLevel();
     162
     163                InlineBox* nextBox = box;
     164                do {
     165                    nextBox = nextBox->nextLeafChild();
     166                } while (nextBox && nextBox->bidiLevel() > level);
     167
     168                if (nextBox && nextBox->bidiLevel() == level)
     169                    break;
     170
     171                while (InlineBox* prevBox = box->prevLeafChild()) {
     172                    if (prevBox->bidiLevel() < level)
     173                        break;
     174                    box = prevBox;
     175                }
     176                renderer = box->object();
     177                offset = box->caretRightmostOffset();
     178                if (box->direction() == primaryDirection)
     179                    break;
     180                continue;
     181            }
     182
     183            if (prevBox) {
     184                box = prevBox;
     185                renderer = box->object();
     186                offset = box->caretRightmostOffset();
     187                if (box->bidiLevel() > level) {
     188                    do {
     189                        prevBox = box->prevLeafChild();
     190                    } while (prevBox && prevBox->bidiLevel() > level);
     191
     192                    if (!prevBox || prevBox->bidiLevel() < level)
     193                        continue;
     194                }
     195            } else {
     196                // Trailing edge of a secondary run. Set to the leading edge of the entire run.
     197                while (true) {
     198                    while (InlineBox* nextBox = box->nextLeafChild()) {
     199                        if (nextBox->bidiLevel() < level)
     200                            break;
     201                        box = nextBox;
     202                    }
     203                    if (box->bidiLevel() == level)
     204                        break;
     205                    level = box->bidiLevel();
     206                    while (InlineBox* prevBox = box->prevLeafChild()) {
     207                        if (prevBox->bidiLevel() < level)
     208                            break;
     209                        box = prevBox;
     210                    }
     211                    if (box->bidiLevel() == level)
     212                        break;
     213                    level = box->bidiLevel();
     214                }
     215                renderer = box->object();
     216                offset = primaryDirection == LTR ? box->caretMinOffset() : box->caretMaxOffset();
     217            }
     218            break;
     219        }
     220
     221        p = Position(renderer->element(), offset);
     222
     223        if (p.isCandidate() && p.downstream() != downstreamStart || p.atStart() || p.atEnd())
     224            return p;
     225    }
     226}
     227
     228VisiblePosition VisiblePosition::left(bool stayInEditableContent) const
     229{
     230    Position pos = leftVisuallyDistinctCandidate();
     231    if (pos.atStart() || pos.atEnd())
     232        return VisiblePosition();
     233
     234    VisiblePosition left = VisiblePosition(pos, DOWNSTREAM);
     235    ASSERT(left != *this);
     236
     237    if (!stayInEditableContent)
     238        return left;
     239
     240    // FIXME: This may need to do something different from "before".
     241    return honorEditableBoundaryAtOrBefore(left);
     242}
     243
     244Position VisiblePosition::rightVisuallyDistinctCandidate() const
     245{
     246    Position p = m_deepPosition;
     247    Position downstreamStart = p.downstream();
     248
     249    TextDirection primaryDirection = LTR;
     250    for (RenderObject* r = p.node()->renderer(); r; r = r->parent()) {
     251        if (r->isBlockFlow()) {
     252            primaryDirection = r->style()->direction();
     253            break;
     254        }
     255    }
     256
     257    while (true) {
     258        InlineBox* box;
     259        int offset;
     260        p.getInlineBoxAndOffset(m_affinity, primaryDirection, box, offset);
     261        if (!box)
     262            return primaryDirection == LTR ? nextVisuallyDistinctCandidate(p) : previousVisuallyDistinctCandidate(p);
     263
     264        RenderObject* renderer = box->object();
     265
     266        while (true) {
     267            if ((renderer->isReplaced() || renderer->isBR()) && offset == box->caretLeftmostOffset())
     268                return box->direction() == LTR ? nextVisuallyDistinctCandidate(p) : previousVisuallyDistinctCandidate(p);
     269
     270            offset = box->direction() == LTR ? renderer->nextOffset(offset) : renderer->previousOffset(offset);
     271
     272            int caretMinOffset = box->caretMinOffset();
     273            int caretMaxOffset = box->caretMaxOffset();
     274
     275            if (offset > caretMinOffset && offset < caretMaxOffset)
     276                break;
     277
     278            if (box->direction() == LTR ? offset > caretMaxOffset : offset < caretMinOffset) {
     279                // Overshot to the right.
     280                InlineBox* nextBox = box->nextLeafChild();
     281                if (!nextBox)
     282                    return primaryDirection == LTR ? nextVisuallyDistinctCandidate(p) : previousVisuallyDistinctCandidate(p);;
     283
     284                // Reposition at the other logical position corresponding to our edge's visual position and go for another round.
     285                box = nextBox;
     286                renderer = box->object();
     287                offset = nextBox->caretLeftmostOffset();
     288                continue;
     289            }
     290
     291            ASSERT(offset == box->caretRightmostOffset());
     292
     293            unsigned char level = box->bidiLevel();
     294            InlineBox* nextBox = box->nextLeafChild();
     295
     296            if (box->direction() == primaryDirection) {
     297                if (!nextBox || nextBox->bidiLevel() >= level)
     298                    break;
     299
     300                level = nextBox->bidiLevel();
     301
     302                InlineBox* prevBox = box;
     303                do {
     304                    prevBox = prevBox->prevLeafChild();
     305                } while (prevBox && prevBox->bidiLevel() > level);
     306
     307                if (prevBox && prevBox->bidiLevel() == level)   // For example, abc FED 123 ^ CBA
     308                    break;
     309
     310                // For example, abc 123 ^ CBA
     311                while (InlineBox* nextBox = box->nextLeafChild()) {
     312                    if (nextBox->bidiLevel() < level)
     313                        break;
     314                    box = nextBox;
     315                }
     316                renderer = box->object();
     317                offset = box->caretLeftmostOffset();
     318                if (box->direction() == primaryDirection)
     319                    break;
     320                continue;
     321            }
     322
     323            if (nextBox) {
     324                box = nextBox;
     325                renderer = box->object();
     326                offset = box->caretLeftmostOffset();
     327                if (box->bidiLevel() > level) {
     328                    do {
     329                        nextBox = box->nextLeafChild();
     330                    } while (nextBox && nextBox->bidiLevel() > level);
     331
     332                    if (!nextBox || nextBox->bidiLevel() < level)
     333                        continue;
     334                }
     335            } else {
     336                // Trailing edge of a secondary run. Set to the leading edge of the entire run.
     337                while (true) {
     338                    while (InlineBox* prevBox = box->prevLeafChild()) {
     339                        if (prevBox->bidiLevel() < level)
     340                            break;
     341                        box = prevBox;
     342                    }
     343                    if (box->bidiLevel() == level)
     344                        break;
     345                    level = box->bidiLevel();
     346                    while (InlineBox* nextBox = box->nextLeafChild()) {
     347                        if (nextBox->bidiLevel() < level)
     348                            break;
     349                        box = nextBox;
     350                    }
     351                    if (box->bidiLevel() == level)
     352                        break;
     353                    level = box->bidiLevel();
     354                }
     355                renderer = box->object();
     356                offset = primaryDirection == LTR ? box->caretMaxOffset() : box->caretMinOffset();
     357            }
     358            break;
     359        }
     360
     361        p = Position(renderer->element(), offset);
     362
     363        if (p.isCandidate() && p.downstream() != downstreamStart || p.atStart() || p.atEnd())
     364            return p;
     365    }
     366}
     367
     368VisiblePosition VisiblePosition::right(bool stayInEditableContent) const
     369{
     370    Position pos = rightVisuallyDistinctCandidate();
     371    if (pos.atStart() || pos.atEnd())
     372        return VisiblePosition();
     373
     374    VisiblePosition right = VisiblePosition(pos, DOWNSTREAM);
     375    ASSERT(right != *this);
     376
     377    if (!stayInEditableContent)
     378        return right;
     379
     380    // FIXME: This may need to do something different from "after".
     381    return honorEditableBoundaryAtOrAfter(right);
     382}
     383
    105384VisiblePosition VisiblePosition::honorEditableBoundaryAtOrBefore(const VisiblePosition &pos) const
    106385{
  • trunk/WebCore/editing/VisiblePosition.h

    r32508 r32605  
    7171    VisiblePosition honorEditableBoundaryAtOrAfter(const VisiblePosition&) const;
    7272
     73    VisiblePosition left(bool stayInEditableContent = false) const;
     74    VisiblePosition right(bool stayInEditableContent = false) const;
     75
    7376    UChar characterAfter() const;
    7477    UChar characterBefore() const { return previous().characterAfter(); }
     
    98101    void init(const Position&, EAffinity);
    99102    Position canonicalPosition(const Position&);
     103
     104    Position leftVisuallyDistinctCandidate() const;
     105    Position rightVisuallyDistinctCandidate() const;
    100106
    101107    Position m_deepPosition;
Note: See TracChangeset for help on using the changeset viewer.