Changeset 82588 in webkit


Ignore:
Timestamp:
Mar 31, 2011 9:17:25 AM (13 years ago)
Author:
xji@chromium.org
Message:

2011-03-30 Xiaomei Ji <xji@chromium.org>

Reviewed by Ryosuke Niwa.

Experiment with moving caret by word in visual order.
https://bugs.webkit.org/show_bug.cgi?id=57336

  • editing/selection/move-by-word-visually-expected.txt: Added.
  • editing/selection/move-by-word-visually.html: Added.

2011-03-30 Xiaomei Ji <xji@chromium.org>

Reviewed by Ryosuke Niwa.

Experiment with moving caret by word in visual order.
https://bugs.webkit.org/show_bug.cgi?id=57336

Follow Firefox's convention in Windows,
In LTR block, word break visually moves cursor to the left boundary of words,
In RTL block, word break visually moves cursor to the right boundary of words.

This is the 1st version of implementing "move caret by word in visual order".
It only works in the following situation:

  1. For a LTR box in a LTR block or a RTL box in RTL block, when caret is at the left boundary of the box and we are looking for the word boundary in right.
  2. For a LTR or RTL box in a LTR block, when caret is at the left boundary of the box and we are looking for the word boundary in left and previous box is a LTR box.
  3. For a LTR or RTL box in a RTL block, when the caret is at the right boundary of the box and we are looking for the word boundary in right and next box is RTL box.

An experimental granularity is introduced, as a side effect, functions having switch statements
to handle those granularities have to add more one case to handle this new granularity.
The experimental granularity is exposed though JS by '-webkit-visual-word".

The overall algorithm is looping through inline boxes visually and looking
for the visually nearest word break position.

Test: editing/selection/move-by-word-visually.html

  • editing/SelectionController.cpp: (WebCore::SelectionController::modifyExtendingRight): (WebCore::SelectionController::modifyExtendingForward): (WebCore::SelectionController::modifyMovingRight): (WebCore::SelectionController::modifyMovingForward): (WebCore::SelectionController::modifyExtendingLeft): (WebCore::SelectionController::modifyExtendingBackward): (WebCore::SelectionController::modifyMovingLeft): (WebCore::SelectionController::modifyMovingBackward):
  • editing/TextGranularity.h:
  • editing/VisibleSelection.cpp: (WebCore::VisibleSelection::setStartAndEndFromBaseAndExtentRespectingGranularity):
  • editing/visible_units.cpp: (WebCore::previousWordBreakInBoxInsideBlockWithSameDirectionality): (WebCore::wordBoundaryInBox): (WebCore::wordBoundaryInAdjacentBoxes): (WebCore::leftWordBoundary): (WebCore::rightWordBoundary): (WebCore::leftWordPosition): (WebCore::rightWordPosition):
  • editing/visible_units.h:
  • page/DOMSelection.cpp: (WebCore::DOMSelection::modify):
Location:
trunk
Files:
2 added
8 edited

Legend:

Unmodified
Added
Removed
  • trunk/LayoutTests/ChangeLog

    r82579 r82588  
     12011-03-30  Xiaomei Ji  <xji@chromium.org>
     2
     3        Reviewed by Ryosuke Niwa.
     4
     5        Experiment with moving caret by word in visual order.
     6        https://bugs.webkit.org/show_bug.cgi?id=57336
     7
     8        * editing/selection/move-by-word-visually-expected.txt: Added.
     9        * editing/selection/move-by-word-visually.html: Added.
     10
    1112011-03-31  Pavel Podivilov  <podivilov@chromium.org>
    212
  • trunk/Source/WebCore/ChangeLog

    r82584 r82588  
     12011-03-30  Xiaomei Ji  <xji@chromium.org>
     2
     3        Reviewed by Ryosuke Niwa.
     4
     5        Experiment with moving caret by word in visual order.
     6        https://bugs.webkit.org/show_bug.cgi?id=57336
     7
     8        Follow Firefox's convention in Windows,
     9        In LTR block, word break visually moves cursor to the left boundary of words,
     10        In RTL block, word break visually moves cursor to the right boundary of words.
     11
     12        This is the 1st version of implementing "move caret by word in visual order".
     13        It only works in the following situation:
     14        1. For a LTR box in a LTR block or a RTL box in RTL block,
     15        when caret is at the left boundary of the box and we are looking for
     16        the word boundary in right.
     17        2. For a LTR or RTL box in a LTR block, when caret is at the left boundary
     18        of the box and we are looking for the word boundary in left and
     19        previous box is a LTR box.
     20        3. For a LTR or RTL box in a RTL block, when the caret is at the right
     21        boundary of the box and we are looking for the word boundary in right and next box is RTL box.
     22
     23        An experimental granularity is introduced, as a side effect, functions having switch statements
     24        to handle those granularities have to add more one case to handle this new granularity.
     25        The experimental granularity is exposed though JS by '-webkit-visual-word".
     26
     27        The overall algorithm is looping through inline boxes visually and looking
     28        for the visually nearest word break position.
     29
     30        Test: editing/selection/move-by-word-visually.html
     31
     32        * editing/SelectionController.cpp:
     33        (WebCore::SelectionController::modifyExtendingRight):
     34        (WebCore::SelectionController::modifyExtendingForward):
     35        (WebCore::SelectionController::modifyMovingRight):
     36        (WebCore::SelectionController::modifyMovingForward):
     37        (WebCore::SelectionController::modifyExtendingLeft):
     38        (WebCore::SelectionController::modifyExtendingBackward):
     39        (WebCore::SelectionController::modifyMovingLeft):
     40        (WebCore::SelectionController::modifyMovingBackward):
     41        * editing/TextGranularity.h:
     42        * editing/VisibleSelection.cpp:
     43        (WebCore::VisibleSelection::setStartAndEndFromBaseAndExtentRespectingGranularity):
     44        * editing/visible_units.cpp:
     45        (WebCore::previousWordBreakInBoxInsideBlockWithSameDirectionality):
     46        (WebCore::wordBoundaryInBox):
     47        (WebCore::wordBoundaryInAdjacentBoxes):
     48        (WebCore::leftWordBoundary):
     49        (WebCore::rightWordBoundary):
     50        (WebCore::leftWordPosition):
     51        (WebCore::rightWordPosition):
     52        * editing/visible_units.h:
     53        * page/DOMSelection.cpp:
     54        (WebCore::DOMSelection::modify):
     55
    1562011-03-31  Dimitri Glazkov  <dglazkov@chromium.org>
    257
  • trunk/Source/WebCore/editing/SelectionController.cpp

    r82121 r82588  
    448448        // FIXME: implement all of the above?
    449449        pos = modifyExtendingForward(granularity);
     450        break;
     451    case WebKitVisualWordGranularity:
     452        break;
    450453    }
    451454    return pos;
     
    486489        else
    487490            pos = endOfDocument(pos);
     491        break;
     492    case WebKitVisualWordGranularity:
    488493        break;
    489494    }
     
    518523        pos = rightBoundaryOfLine(startForPlatform(), directionOfEnclosingBlock());
    519524        break;
     525    case WebKitVisualWordGranularity:
     526        pos = rightWordPosition(VisiblePosition(m_selection.extent(), m_selection.affinity()));
     527        break;
    520528    }
    521529    return pos;
     
    565573        else
    566574            pos = endOfDocument(pos);
     575        break;
     576    case WebKitVisualWordGranularity:
    567577        break;
    568578    }
     
    605615    case DocumentBoundary:
    606616        pos = modifyExtendingBackward(granularity);
     617        break;
     618    case WebKitVisualWordGranularity:
     619        break;
    607620    }
    608621    return pos;
     
    648661        else
    649662            pos = startOfDocument(pos);
     663        break;
     664    case WebKitVisualWordGranularity:
    650665        break;
    651666    }
     
    667682        break;
    668683    case WordGranularity:
     684        pos = leftWordPosition(VisiblePosition(m_selection.extent(), m_selection.affinity()));
     685        break;
    669686    case SentenceGranularity:
    670687    case LineGranularity:
     
    679696        pos = leftBoundaryOfLine(startForPlatform(), directionOfEnclosingBlock());
    680697        break;
     698    case WebKitVisualWordGranularity:
     699        pos = leftWordPosition(VisiblePosition(m_selection.extent(), m_selection.affinity()));
     700        break;
    681701    }
    682702    return pos;
     
    720740        else
    721741            pos = startOfDocument(pos);
     742        break;
     743    case WebKitVisualWordGranularity:
    722744        break;
    723745    }
  • trunk/Source/WebCore/editing/TextGranularity.h

    r18874 r82588  
    4040    LineBoundary,
    4141    ParagraphBoundary,
    42     DocumentBoundary
     42    DocumentBoundary,
     43    // FIXME: this is added temporarily for experiment with visually move
     44    // caret by wordGranularity. Once all patches are landed, it should be removed.
     45    WebKitVisualWordGranularity
    4346};
    4447
  • trunk/Source/WebCore/editing/VisibleSelection.cpp

    r81518 r82588  
    381381            m_end = endOfSentence(VisiblePosition(m_end, m_affinity)).deepEquivalent();
    382382            break;
     383        case WebKitVisualWordGranularity:
     384            break;
    383385    }
    384386   
  • trunk/Source/WebCore/editing/visible_units.cpp

    r82447 r82588  
    3838#include "TextIterator.h"
    3939#include "VisiblePosition.h"
     40#include "VisibleSelection.h"
    4041#include "htmlediting.h"
    4142#include <wtf/unicode/Unicode.h>
     
    11471148}
    11481149
    1149 }
     1150static const int invalidOffset = -1;
     1151   
     1152static VisiblePosition previousWordBreakInBoxInsideBlockWithSameDirectionality(const InlineBox* box, const VisiblePosition& previousWordBreak, int& offsetOfWordBreak)
     1153{
     1154    bool hasSeenWordBreakInThisBox = previousWordBreak.isNotNull();
     1155    // In a LTR block, the word break should be on the left boundary of a word.
     1156    // In a RTL block, the word break should be on the right boundary of a word.
     1157    // Because nextWordPosition() returns the word break on the right boundary of the word for LTR text,
     1158    // we need to use previousWordPosition() to traverse words within the inline boxes from right to left
     1159    // to find the previous word break (i.e. the first word break on the left). The same applies to RTL text.
     1160   
     1161    VisiblePosition wordBreak = hasSeenWordBreakInThisBox ? previousWordBreak : Position(box->renderer()->node(), box->caretMaxOffset(), Position::PositionIsOffsetInAnchor);
     1162
     1163    // FIXME: handle multi-spaces (http://webkit.org/b/57543).
     1164   
     1165    wordBreak = previousWordPosition(wordBreak);
     1166    if (previousWordBreak == wordBreak)
     1167        return VisiblePosition();
     1168
     1169    InlineBox* boxContainingPreviousWordBreak;
     1170    wordBreak.getInlineBoxAndOffset(boxContainingPreviousWordBreak, offsetOfWordBreak);
     1171    if (boxContainingPreviousWordBreak != box)
     1172        return VisiblePosition();
     1173    return wordBreak;
     1174}
     1175
     1176static VisiblePosition previousWordBreakInBox(const InlineBox* box, int offset, TextDirection blockDirection)
     1177{
     1178    int offsetOfWordBreak = 0;
     1179    VisiblePosition wordBreak;
     1180    while (true) {
     1181        if (box->direction() == blockDirection)
     1182            wordBreak = previousWordBreakInBoxInsideBlockWithSameDirectionality(box, wordBreak, offsetOfWordBreak);
     1183        // FIXME: Implement the 'else' case when the box direction is not equal to the block direction.
     1184        if (wordBreak.isNull())
     1185            break;
     1186        if (offset == invalidOffset || offsetOfWordBreak != offset)
     1187            return wordBreak;
     1188    }       
     1189    return VisiblePosition();
     1190}
     1191
     1192static VisiblePosition leftWordBoundary(const InlineBox* box, int offset, TextDirection blockDirection)
     1193{
     1194    VisiblePosition wordBreak;
     1195    for  (const InlineBox* adjacentBox = box; adjacentBox; adjacentBox = adjacentBox->prevLeafChild()) {
     1196        if (blockDirection == LTR)
     1197            wordBreak = previousWordBreakInBox(adjacentBox, adjacentBox == box ? offset : invalidOffset, blockDirection);
     1198        // FIXME: Implement the "else" case.
     1199        if (wordBreak.isNotNull())
     1200            return wordBreak;
     1201    }
     1202    return VisiblePosition();
     1203}
     1204 
     1205static VisiblePosition rightWordBoundary(const InlineBox* box, int offset, TextDirection blockDirection)
     1206{
     1207   
     1208    VisiblePosition wordBreak;
     1209    for (const InlineBox* adjacentBox = box; adjacentBox; adjacentBox = adjacentBox->nextLeafChild()) {
     1210        if (blockDirection == RTL)
     1211            wordBreak = previousWordBreakInBox(adjacentBox, adjacentBox == box ? offset : invalidOffset, blockDirection);
     1212        // FIXME: Implement the "else" case.
     1213        if (!wordBreak.isNull())
     1214            return wordBreak;
     1215    }
     1216    return VisiblePosition();
     1217}
     1218
     1219VisiblePosition leftWordPosition(const VisiblePosition& visiblePosition)
     1220{
     1221    InlineBox* box;
     1222    int offset;
     1223    visiblePosition.getInlineBoxAndOffset(box, offset);
     1224    TextDirection blockDirection = directionOfEnclosingBlock(visiblePosition.deepEquivalent());
     1225   
     1226    // FIXME: If the box's directionality is the same as that of the enclosing block, when the offset is at the box boundary
     1227    // and the direction is towards inside the box, do I still need to make it a special case? For example, a LTR box inside a LTR block,
     1228    // when offset is at box's caretMinOffset and the direction is DirectionRight, should it be taken care as a general case?
     1229    if (offset == box->caretLeftmostOffset())
     1230        return leftWordBoundary(box->prevLeafChild(), invalidOffset, blockDirection);
     1231    if (offset == box->caretRightmostOffset())
     1232        return leftWordBoundary(box, offset, blockDirection);
     1233   
     1234    // FIXME: Not implemented.
     1235    return VisiblePosition();
     1236}
     1237
     1238VisiblePosition rightWordPosition(const VisiblePosition& visiblePosition)
     1239{
     1240    InlineBox* box;
     1241    int offset;
     1242    visiblePosition.getInlineBoxAndOffset(box, offset);
     1243    TextDirection blockDirection = directionOfEnclosingBlock(visiblePosition.deepEquivalent());
     1244   
     1245    if (offset == box->caretLeftmostOffset())
     1246        return rightWordBoundary(box, offset, blockDirection);
     1247    if (offset == box->caretRightmostOffset())
     1248        return rightWordBoundary(box->nextLeafChild(), -1, blockDirection);
     1249   
     1250    // FIXME: Not implemented.
     1251    return VisiblePosition();
     1252}
     1253
     1254}
  • trunk/Source/WebCore/editing/visible_units.h

    r82447 r82588  
    4343VisiblePosition previousWordPosition(const VisiblePosition &);
    4444VisiblePosition nextWordPosition(const VisiblePosition &);
     45VisiblePosition rightWordPosition(const VisiblePosition&);
     46VisiblePosition leftWordPosition(const VisiblePosition&);
    4547
    4648// sentences
  • trunk/Source/WebCore/page/DOMSelection.cpp

    r80604 r82588  
    333333    else if (equalIgnoringCase(granularityString, "documentboundary"))
    334334        granularity = DocumentBoundary;
     335    else if (equalIgnoringCase(granularityString, "-webkit-visual-word"))
     336        granularity = WebKitVisualWordGranularity;
    335337    else
    336338        return;
Note: See TracChangeset for help on using the changeset viewer.