Changeset 421 for trunk


Ignore:
Timestamp:
Mar 1, 2019, 8:09:20 PM (6 years ago)
Author:
ataylor
Message:

DBCS character boundary detection for cursor positioning logic.

Location:
trunk/Components
Files:
3 edited

Legend:

Unmodified
Added
Removed
  • trunk/Components/RichTextDocumentUnit.pas

    r420 r421  
    142142function IsDBCSSecondByte( const CharByte: Byte;
    143143                           const Codepage: LongInt ): boolean;
    144 
    145 // Adjusts the character position to the beginning or end of any multi-byte
    146 // character.
    147 procedure MoveToCharacterBoundary(     TextPointer: PChar;
    148                                    var Index:       LongInt;
    149                                    var Offset:      LongInt;
    150                                        RowStart:    LongInt;
    151                                        Codepage:    LongInt;
    152                                        Advance:     Boolean; );
    153144//
    154145// ALT ends
     
    850841    P := NextP;
    851842  end;
     843
     844  Q[ 0 ] := #0;         // ALT test
     845
    852846  result := PCharDiff( Q, Buffer );
    853847end;
     
    960954    end;
    961955end;
    962 
    963 // Given a string position, check to see if it's in the middle of a double-byte
    964 // character; if so, move back by one position so that we're sitting immediately
    965 // in front of the double-byte character instead.
    966 //
    967 procedure MoveToCharacterBoundary(     TextPointer: PChar;
    968                                    var Index:       LongInt;
    969                                    var Offset:      LongInt;
    970                                        RowStart:    LongInt;
    971                                        Codepage:    LongInt;
    972                                        Advance:     Boolean; );
    973 var
    974   P:         PChar;
    975   NextP:     PChar;
    976   Element:   TTextElement;
    977   InsideDBC: boolean;
    978 begin
    979   if ( Offset > 0 ) and
    980      ( Codepage in [ 932, 936, 942, 943, 949, 950, 1381, 1386 ]) then
    981   begin
    982     P := TextPointer + RowStart;
    983     InsideDBC := false;
    984 
    985     // Because parsing of byte types is state based, we must verify every
    986     // byte's type from the beginning of the line until we reach the target.
    987     while RowStart < Index do
    988     begin
    989       Element := ExtractNextTextElement( P, NextP );
    990       CheckSpecialElementType( Element.Character, Element.ElementType, InsideDBC, Codepage );
    991       P := NextP;
    992       inc( RowStart );
    993     end;
    994 
    995     // We've reached the target position, and the current parsing state should
    996     // be correctly set. So now we can safely determine the target byte's type.
    997     Element := ExtractNextTextElement( P, NextP );
    998     CheckSpecialElementType( Element.Character, Element.ElementType, InsideDBC, Codepage );
    999     if InsideDBC then
    1000     begin
    1001       // If this the first byte of a double byte character, move position by one.
    1002       if Advance Then
    1003       Begin
    1004         inc( Index );
    1005         inc( Offset );
    1006       End
    1007       Else
    1008       Begin
    1009         dec( Index );
    1010         dec( Offset );
    1011       End
    1012     end;
    1013   end;
    1014 
    1015 end;
    1016956//
    1017957// ALT ends
  • trunk/Components/RichTextLayoutUnit.pas

    r420 r421  
    7575
    7676    Codepage:    ULong;       // ALT
     77
     78// TEMP (ALT)
     79    DebugLog: TextFile;
     80// TEMP (ALT)
     81
    7782
    7883    // Drawing functions
     
    121126    Function GetTextEnd: longint;
    122127
     128    // ALT
     129    Function FindCharacterBoundary(    TextPointer: PChar;
     130                                   var Index:       LongInt;
     131                                       Advance:     Boolean; ): LongInt;
     132
    123133  Public
    124134    constructor Create( Text: PChar;
     
    177187  FRichTextSettings := RichTextSettings;
    178188
     189{
     190AssignFile( DebugLog, 'parse.txt');
     191ReWrite( DebugLog );
     192WriteLn( DebugLog, 'Opened log for writing.');
     193}
     194
    179195  FImages := Images;
    180196
     
    212228  FreeMem( Flines, FAllocatedNumLines * sizeof( TLayoutLine ) );
    213229  FLinks.Destroy;
     230
     231{
     232// TEMP (ALT)
     233WriteLn( DebugLog, '=============================');
     234CloseFile( DebugLog );
     235// TEMP (ALT)
     236}
    214237
    215238  Inherited Destroy;
     
    932955  Style: TTextDrawStyle;
    933956  NewMarginX: longint;
     957  InsideDBC:   Boolean;     // ALT
    934958begin
    935959  Line := FLines[ LineIndex ];
     
    941965
    942966  StartedDrawing := false;
     967  InsideDBC := false;       // ALT
    943968
    944969  while P < EndP do
    945970  begin
    946971    Element := ExtractNextTextElement( P, NextP );
     972    CheckSpecialElementType( Element.Character, Element.ElementType, InsideDBC, Codepage );   // ALT
    947973
    948974    case Element.ElementType of
    949975      teWordBreak,
    950976      teText,
     977      teWrapChar,       // ALT
     978      teLeadByte,       // ALT
    951979      teImage:
    952980      begin
     
    967995
    968996        // Now find out how wide the thing is
    969         inc( X, GetElementWidth( Element ) );
    970 
    971       end;
     997        if (( Element.ElementType = teLeadByte ) And ( EndP > P )) then    // ALT
     998          inc( X, FFontManager.CJKTextWidth( 2, P ))
     999        else
     1000          inc( X, GetElementWidth( Element ) );
     1001
     1002      end;
     1003
     1004      // teSecondByte: do nothing and continue to next byte (ALT)
    9721005
    9731006      teStyle:
     
    12051238end;
    12061239
     1240// ALT begins
     1241//
     1242// Given a text position, check if it's in the middle of a double-byte
     1243// character; if so, shift the position one byte forwards or backwards.
     1244//
     1245function TRichTextLayout.FindCharacterBoundary(     TextPointer: PChar;     // pointer to text
     1246                                                var Index:       LongInt;   // position (byte index) within text
     1247                                                    Advance:     Boolean;   // whether to adjust position forward
     1248                                              ): LongInt;                   // returns new offset within line
     1249var
     1250  P:         PChar;             // pointer to current character in string
     1251  NextP:     PChar;             // pointer to the following character, if any
     1252  Element:   TTextElement;      // element data about the current character
     1253  CurrentPos:  LongInt;           // index of first character of line
     1254  Line:      LongInt;           // current line number
     1255  Offset:    LongInt;           // offset position within current line
     1256  InsideDBC: boolean;
     1257begin
     1258  if ( Offset > 0 ) and
     1259     ( Codepage in [ 932, 936, 942, 943, 949, 950, 1381, 1386 ]) then
     1260  begin
     1261    // Because parsing of byte types is state based, we must verify every
     1262    // byte's type from the beginning of the line until we reach the target.
     1263    //
     1264    Line := GetLineFromCharIndex( Index );
     1265    CurrentPos := GetCharIndex( FLines[ Line ].Text );
     1266    P := TextPointer + CurrentPos;
     1267    Offset := 0;
     1268    InsideDBC := false;
     1269
     1270    while CurrentPos < Index do
     1271    begin
     1272      Element := ExtractNextTextElement( P, NextP );
     1273      CheckSpecialElementType( Element.Character, Element.ElementType, InsideDBC, Codepage );
     1274      CurrentPos := CurrentPos + PCharPointerDiff( NextP, P );
     1275      Offset := Offset + PCharPointerDiff( NextP, P );
     1276      P := NextP;
     1277    end;
     1278
     1279    // We've reached the target position, and the current parsing state should
     1280    // be correctly set. So now we can safely determine the target byte's type.
     1281    //
     1282    Element := ExtractNextTextElement( P, NextP );
     1283    CheckSpecialElementType( Element.Character, Element.ElementType, InsideDBC, Codepage );
     1284
     1285    if Element.ElementType = teSecondByte then
     1286    begin
     1287      // If we are inside a a double byte character, shift position by one.
     1288      if Advance Then
     1289      Begin
     1290        inc( Index );
     1291        inc( Offset );
     1292      End
     1293      Else
     1294      Begin
     1295        dec( Index );
     1296        dec( Offset );
     1297      End
     1298    end;
     1299
     1300  end;
     1301
     1302  Result := Offset;
     1303end;
     1304//
     1305// ALT ends
     1306
    12071307Initialization
    12081308End.
  • trunk/Components/RichTextView.PAS

    r420 r421  
    8787    FCursorRow: longint;
    8888    FCursorOffset: longint;
     89
     90    FCursorMoveRight: boolean;    // ALT - TRUE if cursor is moving to the right
    8991
    9092    FSelectionStart: longint;
     
    460462Procedure TRichTextView.SetSelectionStartInternal( SelectionStart: longint );
    461463var
     464  Line:   longint;     // ALT
    462465  Offset: longint;     // ALT
    463466begin
     
    470473      ClearSelection;
    471474
    472   // ALT
    473   Offset := FCursorOffset;
    474   MoveToCharacterBoundary( FText, SelectionStart, FCursorOffset, Offset, FLayout.Codepage, false );
     475// Should already be ensured by this point?
     476//  FLayout.FindCharacterBoundary( FText, SelectionStart, false );    // ALT
    475477
    476478  FSelectionStart := SelectionStart;
     
    485487  StartRedrawLine: longint;
    486488  EndRedrawLine: longint;
    487   Offset: longint;         // ALT
     489  Offset: longint;          // ALT
     490  Line:   longint;          // ALT
    488491  OldClip: TRect;
    489492begin
     
    491494    exit;
    492495
    493   // ALT
    494   Offset := FCursorOffset;
    495   MoveToCharacterBoundary( FText, SelectionEnd, FCursorOffset, Offset, FLayout.Codepage, false );
     496// Should already be ensured by this point?
     497//  FLayout.FindCharacterBoundary( FText, SelectionEnd, false );      // ALT
    496498
    497499  if FSelectionStart = -1 then
     
    955957                               Offset,
    956958                               Link );
     959
    957960end;
    958961
     
    12571260  // ALT - move to nearest character boundary
    12581261  Index := FLayout.GetCharIndex( Line.Text ) + FCursorOffset;
    1259   RowStart := FLayout.GetCharIndex( Line.Text );
    1260   MoveToCharacterBoundary( FText, Index, FCursorOffset, RowStart, FLayout.Codepage, false );
     1262
     1263  FLayout.FindCharacterBoundary( FText, Index, FCursorMoveRight );
     1264  FCursorOffset := FLayout.GetOffsetFromCharIndex( Index, CursorRow );
     1265  FCursorMoveRight := false;
     1266  // ALT
    12611267
    12621268  FLayout.GetXFromOffset( FCursorOffset, CursorRow, X );
     
    19982004  Row: longint;
    19992005begin
     2006  FCursorMoveRight := false;    // ALT
     2007
    20002008  if SelectionSet then
    20012009  begin
     
    20372045                                           PreserveSelection: boolean );
    20382046var
    2039 //  P: PChar;                 // ALT
    2040 //  NextP: PChar;             // ALT
    2041 //  Element: TTextElement;    // ALT
    2042 //  InsideDBC: boolean;       // ALT
    20432047  RowStart: longint;        // ALT
    20442048  MoveRight: boolean;       // ALT
     
    20482052
    20492053  Index := FLayout.GetCharIndex( FLayout.FLines[ Row ].Text ) + Offset;
    2050 
    2051 // ALT
    2052 {
    2053   if ( Offset > 0 ) and
    2054      ( FLayout.Codepage in [ 932, 936, 942, 943, 949, 950, 1381, 1386 ]) then
    2055   begin
    2056     RowStart := FLayout.GetCharIndex( FLayout.FLines[ Row ].Text );
    2057     P := FText + RowStart;
    2058     InsideDBC := false;
    2059     while RowStart < Index do
    2060     begin
    2061       Element := ExtractNextTextElement( P, NextP );
    2062       CheckSpecialElementType( Element.Character, Element.ElementType, InsideDBC, FLayout.Codepage );
    2063       P := NextP;
    2064       inc( RowStart );
    2065     end;
    2066     Element := ExtractNextTextElement( P, NextP );
    2067     CheckSpecialElementType( Element.Character, Element.ElementType, InsideDBC, FLayout.Codepage );
    2068     if InsideDBC then
    2069     begin
    2070       dec( Index );
    2071       dec( Offset );
    2072     end;
    2073   end;
    2074 }
    2075 
    20762054  RowStart := FLayout.GetCharIndex( FLayout.FLines[ Row ].Text );
    20772055
    2078   // ALT
    2079   if Offset = ( FCursorOffset + 1 ) then
    2080     MoveRight := true
    2081   else
    2082     MoveRight := false;
    2083   MoveToCharacterBoundary( FText, Index, Offset, RowStart, FLayout.Codepage, MoveRight );
    2084 
    2085   FCursorOffset := Offset;
     2056  Offset := FLayout.FindCharacterBoundary( FText, Index, FCursorMoveRight );  // ALT
     2057  FCursorOffset := FLayout.GetOffsetFromCharIndex( Index, Row );
    20862058  FCursorRow := Row;
    20872059
     
    21062078  Line: TLayoutLine;
    21072079begin
     2080  FCursorMoveRight := true;
    21082081  P := FText + CursorIndex;
    21092082
     
    24232396begin
    24242397  CursorVisible := FSelectionStart <> -1;
     2398  FCursorMoveRight := false;
    24252399
    24262400  Case KeyCode of
Note: See TracChangeset for help on using the changeset viewer.