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

DBCS character boundary detection for cursor positioning logic.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • 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.
Note: See TracChangeset for help on using the changeset viewer.