RVUni.pas
上传用户:daoqigc
上传日期:2021-04-20
资源大小:2795k
文件大小:63k
源码类别:

RichEdit

开发平台:

Delphi

  1. {*******************************************************}
  2. {                                                       }
  3. {       RichView                                        }
  4. {       Unicode-related procedures.                     }
  5. {                                                       }
  6. {       Copyright (c) Sergey Tkachenko                  }
  7. {       svt@trichview.com                               }
  8. {       http://www.trichview.com                        }
  9. {                                                       }
  10. {*******************************************************}
  11. unit RVUni;
  12. interface
  13. {$I RV_Defs.inc}
  14. uses SysUtils, Windows, Classes, Graphics,
  15.      RVItem, RVStyle, RVScroll;
  16. type TRVIntegerArray = array[0..100000] of Integer;
  17.      PRVIntegerArray = ^TRVIntegerArray;
  18. type TRVUnsignedArray = array[0..100000] of Cardinal;
  19.      PRVUnsignedArray = ^TRVUnsignedArray;
  20. type TRVWordArray = array[0..100000] of Word;
  21.      PRVWordArray = ^TRVWordArray;
  22. {$IFNDEF RVDONOTUSEUNICODE}
  23. function RVU_FindLineBreak(Str: PRVWordArray; Length: Integer; FullString: Boolean): Pointer;
  24. procedure RVU_GetTextExtentPoint32W(Canvas: TCanvas; str: Pointer; Len: Integer;
  25.   var sz: TSize);
  26. {$ENDIF}
  27. function RVU_Copy(const s: String; Index, Count: Integer;
  28.   ItemOptions: TRVItemOptions): String;
  29. procedure RVU_Delete(var s: String; Index, Count: Integer;
  30.   ItemOptions: TRVItemOptions);
  31. procedure RVU_Insert(const Source: String; var s: String; Index: Integer;
  32.   ItemOptions: TRVItemOptions);
  33. procedure RVU_GetTextExtentExPoint(Canvas: TCanvas; const s: String;
  34.   MaxExtent: Integer; var Fit: Integer; PDx: PRVIntegerArray;
  35.   ItemOptions: TRVItemOptions);
  36. procedure RVU_GetTextExtentExPointPC(Canvas: TCanvas; pc: PChar; Length: Integer;
  37.   MaxExtent: Integer; var Fit: Integer; PDx: PRVIntegerArray;
  38.   ItemOptions: TRVItemOptions; var sz: TSize);
  39. function RVU_GetTextCaretPos(Canvas: TCanvas; const s: String;
  40.   PCP: PRVIntegerArray; ItemOptions: TRVItemOptions;
  41.   Width: Integer): Boolean;
  42. function RVU_GetTextRangeCoords(Canvas: TCanvas; const s: String;
  43.   RangeStartOffs, RangeLength: Integer; ItemOptions: TRVItemOptions;
  44.   Width: Integer; var X1,X2: Integer): Boolean;
  45. function RVU_Length(const s: String; ItemOptions: TRVItemOptions): Integer;
  46. function RVU_TextWidth(const s: String; Canvas: TCanvas;
  47.   ItemOptions: TRVItemOptions): Integer;
  48. function RVU_IsSpace(const s: String; Index: Integer;
  49.   ItemOptions: TRVItemOptions): Boolean;
  50. function RVU_OffsInPChar(Offs: Integer; ItemOptions: TRVItemOptions): Integer;
  51. {$IFDEF RICHVIEWCBDEF3}
  52. function RVU_Charset2CodePage(Charset: TFontCharset): TRVCodePage;
  53. function RVU_Charset2Language(Charset: TFontCharset): Cardinal;
  54. function RVU_GetRawUnicode(const s: WideString):String;
  55. function RVU_RawUnicodeToWideString(const s: String):WideString;
  56. {$ELSE}
  57. function RVU_GetRawUnicode(const s: String):String;
  58. {$ENDIF}
  59. procedure RVU_SwapWordBytes(arr: PWord; Count: Integer);
  60. procedure RVU_ProcessByteOrderMark(var arr: PWord; Count: Integer);
  61. function RVU_AnsiToUnicode(CodePage: TRVCodePage; const s: String): String;
  62. function RVU_AnsiToUTF8(CodePage: TRVCodePage; const s: String): String;
  63. function RVU_UnicodeToAnsi(CodePage: TRVCodePage; const s: String): String;
  64. function RVU_CanBeConvertedToAnsi(CodePage: TRVCodePage; const s: String): Boolean;
  65. function RVU_StrScanW(Str: Pointer; Ch: Word; Length: Integer): Pointer;
  66. function RVU_StrLenW(Str: Pointer): Cardinal;
  67. type TRVUnicodeTestResult = (rvutNo, rvutYes, rvutProbably, rvutEmpty, rvutError);
  68. function RV_TestStreamUnicode(Stream: TStream): TRVUnicodeTestResult;
  69. function RV_TestFileUnicode(const FileName: String): TRVUnicodeTestResult;
  70. function RV_TestStringUnicode(const s: String): TRVUnicodeTestResult;
  71. function RVU_GetKeyboardCodePage: TRVCodePage;
  72. function RVU_KeyToUnicode(const Key: String): String;
  73. {$IFNDEF RVDONOTUSEHTML}
  74. procedure RVU_WriteHTMLEncodedUnicode(Stream: TStream; const s: String;
  75.   NoEmptyLines, SpecialCode: Boolean);
  76. function RVU_GetHTMLEncodedUnicode(const s: String;
  77.   SpecialCode:Boolean): String;
  78. function RVU_UnicodeToUTF8(const s: String; SpecialCode:Boolean): String;  
  79. {$ENDIF}
  80. function RV_ReturnProcessedString(const s: String; TextStyle: TFontInfo;
  81.   LastOnLine, ShowSpecialChars, ForDisplay: Boolean): String;
  82. function RVU_DrawSelectedTextEx(Left, Top, Width, Height: Integer; const s: String;
  83.   Canvas: TCanvas; Index1,Index2: Integer; ItemOptions: TRVItemOptions;
  84.   BiDiMode: TRVBiDiMode): Boolean;
  85. {$IFNDEF RICHVIEWDEF6}
  86. {$IFDEF RICHVIEWCBDEF3}
  87. function Utf8Decode(const S: String): WideString;
  88. function Utf8Encode(const WS: WideString): String;
  89. {$ENDIF}
  90. {$ENDIF}
  91. const
  92.   UNI_LF                 = Word($000A);
  93.   UNI_CR                 = Word($000D);
  94.   UNI_LineSeparator      = Word($2028);
  95.   UNI_ParagraphSeparator = Word($2029);
  96.   UNI_Tab                = Word($0009);  
  97.   UNI_VerticalTab        = Word($000B);
  98.   UNI_FormFeed           = Word($000C);
  99.   UNI_LSB_FIRST          = Word($FEFF);
  100.   UNI_MSB_FIRST          = Word($FFFE);
  101.   UNI_FF                 = Word($000C);
  102.   UNI_HYPHEN             = Word($002D);
  103.   UNI_Space              = Word(ord(' '));
  104.   UNI_ZERO_WIDTH_SPACE   = Word($200B);
  105.   UNI_ZERO_WIDTH_JOINER  = Word($200D);
  106.   UNI_WORD_JOINER        = Word($2060); // zero width non breaking space
  107.   UNI_SOFT_HYPHEN        = Word($00AD);
  108.   UNI_NOT_SIGN           = Word($00AC);
  109.   UNI_LSB_FIRST1         = #$FF;
  110.   UNI_LSB_FIRST2         = #$FE;
  111. function RVMAKELCID(plgid: Word): Cardinal;  
  112. var RVNT: Boolean;
  113. implementation
  114. uses CRVData, RVStr;
  115. const
  116.   GETCHARACTERPLACEMENTFLAGS = {GCP_USEKERNING or }GCP_REORDER or GCP_GLYPHSHAPE or GCP_DIACRITIC;
  117. function MAKELCID(lgid, srtid: Word): Cardinal;
  118. begin
  119.   Result := (Cardinal(srtid) shl 16) or Cardinal(lgid);
  120. end;
  121. function MAKELANGID(p, s: Word): Word;
  122. begin
  123.   Result := (s shl 10) or p;
  124. end;
  125. function RVMAKELCID(plgid: Word): Cardinal;
  126. begin
  127.   Result := MAKELCID(MAKELANGID(plgid, SUBLANG_DEFAULT), SORT_DEFAULT);
  128. end;
  129. {------------------------------------------------------------------------------}
  130. {$IFNDEF RVDONOTUSEUNICODE}
  131. type
  132.   TRVLineBreakClass =
  133.   (
  134.   rvu_lb_OP, // Opening Punctuation
  135.   rvu_lb_CL, // Closing Punctuation
  136.   rvu_lb_QU, // Ambiguous Quotation
  137.   rvu_lb_GL, // Non-breaking ("Glue")
  138.   rvu_lb_NS, // Non Starter
  139.   rvu_lb_EX, // Exclamation/Interrogation
  140.   rvu_lb_SY, // Symbols Allowing Breaks
  141.   rvu_lb_IS, // Infix Separator (Numeric)
  142.   rvu_lb_PR, // Prefix (Numeric)
  143.   rvu_lb_PO, // Postfix (Numeric)
  144.   rvu_lb_NU, // Numeric
  145.   rvu_lb_AL, // Ordinary Alphabetic and Symbol Characters
  146.   rvu_lb_ID, // Ideographic
  147.   rvu_lb_IN, // Inseparable
  148.   rvu_lb_HY, // Hyphen
  149.   rvu_lb_BA, // Break Opportunity After
  150.   rvu_lb_BB, // Break Opportunity Before
  151.   rvu_lb_B2, // Break Opportunity Before and After
  152.   rvu_lb_ZW, // Zero Width Space
  153.   rvu_lb_CM // Attached Characters and Combining Marks
  154.   );
  155.   {
  156.   rvu_lb_BK, // Mandatory Break // may not occur
  157.   rvu_lb_CR, // Carriage Return // may not occur
  158.   rvu_lb_LF, // Line Feed       // may not occur
  159.   rvu_lb_SP, // Space           // special processing
  160.   rvu_lb_SG, // Surrogates                            // treated as AL
  161.   rvu_lb_CB, // Contingent Break Opportunity          // treated as AL
  162.   rvu_lb_XX, // Unknown                               // treated as AL
  163.   rvu_lb_SA, // Complex Context (South East Asian)    // treated as AL
  164.   rvu_lb_AI, // Ambiguous (Alphabetic or Ideographic) // treated as AL
  165.   }
  166.   TRVLineBreakAction =
  167.   (
  168.      bk_DBK,  // direct break
  169.      bk_IBK,  // indirect break
  170.      bk_PBK   // prohibited break
  171.   );
  172. const
  173.   BreakPairs : array [TRVLineBreakClass,TRVLineBreakClass] of TRVLineBreakAction =
  174.   (
  175.   (bk_PBK,bk_PBK,bk_PBK,bk_PBK,bk_PBK,bk_PBK,bk_PBK,bk_PBK,bk_PBK,bk_PBK,bk_PBK,bk_PBK,bk_PBK,bk_PBK,bk_PBK,bk_PBK,bk_PBK,bk_PBK,bk_PBK,bk_IBK),
  176.   (bk_DBK,bk_PBK,bk_IBK,bk_IBK,bk_PBK,bk_PBK,bk_PBK,bk_PBK,bk_DBK,bk_IBK,bk_DBK,bk_DBK,bk_DBK,bk_DBK,bk_IBK,bk_IBK,bk_DBK,bk_DBK,bk_PBK,bk_IBK),
  177.   (bk_PBK,bk_PBK,bk_IBK,bk_IBK,bk_IBK,bk_PBK,bk_PBK,bk_PBK,bk_IBK,bk_IBK,bk_IBK,bk_IBK,bk_IBK,bk_IBK,bk_IBK,bk_IBK,bk_IBK,bk_IBK,bk_PBK,bk_IBK),
  178.   (bk_IBK,bk_PBK,bk_IBK,bk_IBK,bk_IBK,bk_PBK,bk_PBK,bk_PBK,bk_IBK,bk_IBK,bk_IBK,bk_IBK,bk_IBK,bk_IBK,bk_IBK,bk_IBK,bk_IBK,bk_IBK,bk_PBK,bk_IBK),
  179.   (bk_DBK,bk_PBK,bk_IBK,bk_IBK,bk_IBK,bk_PBK,bk_PBK,bk_PBK,bk_DBK,bk_DBK,bk_DBK,bk_DBK,bk_DBK,bk_DBK,bk_IBK,bk_IBK,bk_DBK,bk_DBK,bk_PBK,bk_IBK),
  180.   (bk_DBK,bk_PBK,bk_IBK,bk_IBK,bk_IBK,bk_PBK,bk_PBK,bk_PBK,bk_DBK,bk_DBK,bk_DBK,bk_DBK,bk_DBK,bk_DBK,bk_IBK,bk_IBK,bk_DBK,bk_DBK,bk_PBK,bk_IBK),
  181.   (bk_DBK,bk_PBK,bk_IBK,bk_IBK,bk_IBK,bk_PBK,bk_PBK,bk_PBK,bk_DBK,bk_DBK,bk_IBK,bk_DBK,bk_DBK,bk_DBK,bk_IBK,bk_IBK,bk_DBK,bk_DBK,bk_PBK,bk_IBK),
  182.   (bk_DBK,bk_PBK,bk_IBK,bk_IBK,bk_IBK,bk_PBK,bk_PBK,bk_PBK,bk_DBK,bk_DBK,bk_IBK,bk_DBK,bk_DBK,bk_DBK,bk_IBK,bk_IBK,bk_DBK,bk_DBK,bk_PBK,bk_IBK),
  183.   (bk_IBK,bk_PBK,bk_IBK,bk_IBK,bk_IBK,bk_PBK,bk_PBK,bk_PBK,bk_DBK,bk_DBK,bk_IBK,bk_IBK,bk_IBK,bk_DBK,bk_IBK,bk_IBK,bk_DBK,bk_DBK,bk_PBK,bk_IBK),
  184.   (bk_DBK,bk_PBK,bk_IBK,bk_IBK,bk_IBK,bk_PBK,bk_PBK,bk_PBK,bk_DBK,bk_DBK,bk_DBK,bk_DBK,bk_DBK,bk_DBK,bk_IBK,bk_IBK,bk_DBK,bk_DBK,bk_PBK,bk_IBK),
  185.   (bk_DBK,bk_PBK,bk_IBK,bk_IBK,bk_IBK,bk_PBK,bk_PBK,bk_PBK,bk_DBK,bk_IBK,bk_IBK,bk_IBK,bk_DBK,bk_IBK,bk_IBK,bk_IBK,bk_DBK,bk_DBK,bk_PBK,bk_IBK),
  186.   (bk_DBK,bk_PBK,bk_IBK,bk_IBK,bk_IBK,bk_PBK,bk_PBK,bk_PBK,bk_DBK,bk_DBK,bk_IBK,bk_IBK,bk_DBK,bk_IBK,bk_IBK,bk_IBK,bk_DBK,bk_DBK,bk_PBK,bk_IBK),
  187.   (bk_DBK,bk_PBK,bk_IBK,bk_IBK,bk_IBK,bk_PBK,bk_PBK,bk_PBK,bk_DBK,bk_IBK,bk_DBK,bk_DBK,bk_DBK,bk_IBK,bk_IBK,bk_IBK,bk_DBK,bk_DBK,bk_PBK,bk_IBK),
  188.   (bk_DBK,bk_PBK,bk_IBK,bk_IBK,bk_IBK,bk_PBK,bk_PBK,bk_PBK,bk_DBK,bk_DBK,bk_DBK,bk_DBK,bk_DBK,bk_IBK,bk_IBK,bk_IBK,bk_DBK,bk_DBK,bk_PBK,bk_IBK),
  189.   (bk_DBK,bk_PBK,bk_IBK,bk_IBK,bk_IBK,bk_PBK,bk_PBK,bk_PBK,bk_DBK,bk_DBK,bk_DBK,bk_DBK,bk_DBK,bk_DBK,bk_IBK,bk_IBK,bk_DBK,bk_DBK,bk_PBK,bk_IBK),
  190.   (bk_DBK,bk_PBK,bk_IBK,bk_IBK,bk_IBK,bk_PBK,bk_PBK,bk_PBK,bk_DBK,bk_DBK,bk_DBK,bk_DBK,bk_DBK,bk_DBK,bk_IBK,bk_IBK,bk_DBK,bk_DBK,bk_PBK,bk_IBK),
  191.   (bk_IBK,bk_PBK,bk_IBK,bk_IBK,bk_IBK,bk_PBK,bk_PBK,bk_PBK,bk_IBK,bk_IBK,bk_IBK,bk_IBK,bk_IBK,bk_IBK,bk_IBK,bk_IBK,bk_IBK,bk_IBK,bk_PBK,bk_IBK),
  192.   (bk_DBK,bk_PBK,bk_IBK,bk_IBK,bk_IBK,bk_PBK,bk_PBK,bk_PBK,bk_DBK,bk_DBK,bk_DBK,bk_DBK,bk_DBK,bk_DBK,bk_IBK,bk_IBK,bk_DBK,bk_PBK,bk_PBK,bk_IBK),
  193.   (bk_DBK,bk_DBK,bk_DBK,bk_DBK,bk_DBK,bk_DBK,bk_DBK,bk_DBK,bk_DBK,bk_DBK,bk_DBK,bk_DBK,bk_DBK,bk_DBK,bk_DBK,bk_DBK,bk_DBK,bk_DBK,bk_PBK,bk_IBK),
  194.   (bk_DBK,bk_PBK,bk_IBK,bk_IBK,bk_IBK,bk_PBK,bk_PBK,bk_PBK,bk_DBK,bk_DBK,bk_IBK,bk_IBK,bk_DBK,bk_IBK,bk_IBK,bk_IBK,bk_DBK,bk_DBK,bk_PBK,bk_IBK)
  195.   );
  196. {------------------------------------------------------------------------------}
  197. function GetCharLineBreakClass(Char: Word): TRVLineBreakClass; forward;
  198. {------------------------------------------------------------------------------}
  199. // (We assume that Str[Length] character exists)
  200. // Returns the last character to leave on the line.
  201. // In case of spaces, returns the space
  202. function RVU_FindLineBreak(Str: PRVWordArray; Length: Integer; FullString: Boolean): Pointer;
  203. var i,j: Integer;
  204.     cls, cls2: TRVLineBreakClass;
  205.     act: TRVLineBreakAction;
  206. begin
  207.   Result := nil;
  208.   if Str[Length]=UNI_Space then begin
  209.     { Result := @(Str[Length]);
  210.       exit; // commented Jun 24 2004
  211.     }
  212.     if FullString then begin
  213.       dec(Length);
  214.       if Length=0 then
  215.         exit;
  216.     end;
  217.   end;
  218.   cls := GetCharLineBreakClass(Str[Length]);
  219.   for i := Length-1 downto 0 do begin
  220.     if Str[i]=UNI_Space then
  221.       continue;
  222.     cls2 := GetCharLineBreakClass(Str[i]);
  223.     act := BreakPairs[cls2, cls];
  224.     if (act = bk_IBK) then
  225.       if Str[i+1]<>UNI_Space then
  226.         act := bk_PBK;
  227.     if act in [bk_IBK, bk_DBK] then begin
  228.       j := i;
  229.       while (j+1<Length) and (Str[j+1]=UNI_Space) do
  230.         inc(j);
  231.       Result := @(Str[j]);
  232.       exit;
  233.     end;
  234.     cls := cls2;
  235.   end;
  236. end;
  237. {$ENDIF}
  238. type
  239. {$IFDEF RICHVIEWDEF7}
  240.   {$IFDEF RICHVIEWDEF9}
  241.   TGetCharacterPlacementVal = LongBool;
  242.   {$ELSE}
  243.   TGetCharacterPlacementVal = Integer;
  244.   {$ENDIF}
  245. {$ELSE}
  246.   TGetCharacterPlacementVal = LongBool;
  247. {$ENDIF}
  248. {------------------------------------------------------------------------------}
  249. function RVU_DrawSelectedTextEx_(Left, Top, Width, Height: Integer; const s: String;
  250.   Canvas: TCanvas; Index1,Index2: Integer; ItemOptions: TRVItemOptions): Boolean;
  251. var res: TGCPResultsA;
  252.     i,j: Integer;
  253.     POrder,POrderRev: PRVUnsignedArray;
  254.     PDX: PRVIntegerArray;
  255.     Selected: PChar;
  256.     SelectedCount: Integer;
  257.     DX, idx, idx1, idx2, Start: Integer;
  258.     Len: Integer;
  259.     r: TRect;
  260.     sz, sz2: TSmallPoint;
  261.     UseSz2: Boolean;
  262.     {..........................................}
  263.     procedure InitStructure;
  264.     begin
  265.       FillChar(res, sizeof(res), 0);
  266.       FillChar(POrder^, Len*sizeof(Cardinal), 0);
  267.       res.lStructSize := sizeof(res);
  268.       res.lpOrder := @(POrder[0]);
  269.       res.lpDx    := @(PDX[0]);
  270.       res.nGlyphs := Len;
  271.     end;
  272.     {..........................................}
  273. begin
  274.   if rvioUnicode in ItemOptions then
  275.     Len := Length(s) div 2
  276.   else
  277.     Len := Length(s);
  278.   r.Top := Top;
  279.   r.Bottom := Top+Height;
  280.   POrder := nil;
  281.   POrderRev := nil;
  282.   PDX       := nil;
  283.   Selected  := nil;
  284.   try
  285.     GetMem(POrder,    Len*sizeof(Cardinal));
  286.     GetMem(POrderRev, Len*sizeof(Cardinal));
  287.     GetMem(PDX,       Len*sizeof(Integer));
  288.     SelectedCount := Index2-Index1+1;
  289.     GetMem(Selected, SelectedCount);
  290.     FillChar(Selected^, SelectedCount, 1);
  291.     InitStructure;
  292.     UseSz2 := (rvioUnicode in ItemOptions) or ((GetFontLanguageInfo(Canvas.Handle) and GCP_LIGATE)<>0);
  293.     if UseSz2 then begin
  294.       if rvioUnicode in ItemOptions then
  295.         sz2 := TSmallPoint(GetCharacterPlacementW(Canvas.Handle, Pointer(s),
  296.           TGetCharacterPlacementVal(Len), TGetCharacterPlacementVal(0), res,
  297.           GETCHARACTERPLACEMENTFLAGS or GCP_LIGATE))
  298.       else
  299.         sz2 := TSmallPoint(GetCharacterPlacementA(Canvas.Handle, PChar(s),
  300.           TGetCharacterPlacementVal(Len), TGetCharacterPlacementVal(0), res,
  301.           GETCHARACTERPLACEMENTFLAGS or GCP_LIGATE));
  302.       InitStructure;
  303.     end;
  304.     if rvioUnicode in ItemOptions then
  305.       sz := TSmallPoint(GetCharacterPlacementW(Canvas.Handle, Pointer(s),
  306.         TGetCharacterPlacementVal(Len), TGetCharacterPlacementVal(0), res,
  307.         GETCHARACTERPLACEMENTFLAGS))
  308.     else
  309.       sz := TSmallPoint(GetCharacterPlacementA(Canvas.Handle, PChar(s),
  310.         TGetCharacterPlacementVal(Len), TGetCharacterPlacementVal(0), res,
  311.         GETCHARACTERPLACEMENTFLAGS));
  312.     if UseSz2 then
  313.       sz := sz2;
  314.     Result := (Abs(sz.x-Width)<2) and (sz.y>0);
  315.     if Result then begin
  316.       for i := 0 to Len-1 do
  317.         POrderRev[POrder[i]] := i;
  318.       while SelectedCount>0 do begin
  319.         Start := 0;
  320.         for i := 0 to Len-1 do begin
  321.           idx := POrderRev[i];
  322.           if  (idx+1>=Index1) and (idx+1<=Index2) and
  323.               (Selected[idx+1-Index1]<>#0) then begin
  324.             idx1 := idx+1-1;
  325.             idx2 := idx+1+1;
  326.             while (idx2<=Index2) and (POrder[idx2-1]>POrder[idx+1-1]) and
  327.                   (Integer(POrder[idx2-1]-POrder[idx+1-1])=idx2-(idx+1)) do
  328.               inc(idx2);
  329.             dec(idx2);
  330.             while (idx1>=Index1) and (POrder[idx+1-1]>POrder[idx1-1]) and
  331.                   (Integer(POrder[idx+1-1]-POrder[idx1-1])=(idx+1)-idx1) do
  332.               dec(idx1);
  333.             inc(idx1);
  334.             r.Left := Left+Start;
  335.             r.Right := r.Left;
  336.             for j := idx1 to idx2 do begin
  337.               //Assert(Selected[j-Index1]<>#0);
  338.               Selected[j-Index1] := #0;
  339.               dec(SelectedCount);
  340.               inc(r.Right, PDX[POrder[j-1]]);
  341.             end;
  342.             if rvioUnicode in ItemOptions then begin
  343.               ExtTextOutW(Canvas.Handle, Left,Top, ETO_CLIPPED or ETO_OPAQUE, @r,
  344.                          Pointer(s), Length(s) div 2, nil);
  345.               end
  346.             else begin
  347.               ExtTextOutA(Canvas.Handle, Left,Top, ETO_CLIPPED or ETO_OPAQUE, @r,
  348.                          PChar(s), Length(s), nil);
  349.             end;
  350.             break;
  351.           end;
  352.           dx  := PDX[i];
  353.           inc(Start,dx);
  354.         end;
  355.       end;
  356.     end;
  357.   finally
  358.     FreeMem(POrder);
  359.     FreeMem(POrderRev);
  360.     FreeMem(PDX);
  361.     FreeMem(Selected);
  362.   end;
  363. end;
  364. {------------------------------------------------------------------------------}
  365. function RVU_GetTextCaretPos(Canvas: TCanvas; const s: String;
  366.   PCP: PRVIntegerArray; ItemOptions: TRVItemOptions;
  367.   Width: Integer): Boolean;
  368. var res: TGCPResultsA;
  369.     i: Integer;
  370.     POrder,POrderRev: PRVUnsignedArray;
  371.     PDX: PRVIntegerArray;
  372.     PClass: PChar;
  373.     DX, idx: Integer;
  374.     cls: Char;
  375.     p: Integer;
  376.     Len: Integer;
  377.     sz, sz2: TSmallPoint;
  378.     UseSz2: Boolean;
  379.     {..........................................}
  380.     procedure InitStructure;
  381.     begin
  382.       FillChar(res, sizeof(res), 0);
  383.       FillChar(POrder^, Len*sizeof(Cardinal), 0);
  384.       FillChar(PDX^,    Len*sizeof(Integer),  0);
  385.       FillChar(PClass^, Length(s),            0);
  386.       res.lStructSize := sizeof(res);
  387.       res.nGlyphs := Len;
  388.       res.lpOrder := @(POrder[0]);
  389.       res.lpClass := PClass;
  390.       res.lpDx    := @(PDX[0]);
  391.     end;
  392.     {..........................................}
  393. begin
  394.   if rvioUnicode in ItemOptions then
  395.     Len := Length(s) div 2
  396.   else
  397.     Len := Length(s);
  398.   POrder := nil;
  399.   POrderRev := nil;
  400.   PClass := nil;
  401.   PDX    := nil;
  402.   try
  403.     GetMem(POrder,    Len*sizeof(Cardinal));
  404.     GetMem(POrderRev, Len*sizeof(Cardinal));
  405.     GetMem(PDX,       Len*sizeof(Integer));
  406.     GetMem(PClass,    Length(s)); // for any case
  407.     InitStructure;
  408.     UseSz2 := (rvioUnicode in ItemOptions) or ((GetFontLanguageInfo(Canvas.Handle) and GCP_LIGATE)<>0);
  409.     if UseSz2 then begin
  410.       if rvioUnicode in ItemOptions then
  411.         sz2 := TSmallPoint(GetCharacterPlacementW(Canvas.Handle, Pointer(s),
  412.           TGetCharacterPlacementVal(Len), TGetCharacterPlacementVal(0), res,
  413.           GETCHARACTERPLACEMENTFLAGS or GCP_LIGATE))
  414.       else
  415.         sz2 := TSmallPoint(GetCharacterPlacementA(Canvas.Handle, PChar(s),
  416.           TGetCharacterPlacementVal(Len), TGetCharacterPlacementVal(0), res,
  417.           GETCHARACTERPLACEMENTFLAGS or GCP_LIGATE));
  418.       InitStructure;
  419.     end;
  420.     if rvioUnicode in ItemOptions then
  421.       sz := TSmallPoint(GetCharacterPlacementW(Canvas.Handle, Pointer(s),
  422.         TGetCharacterPlacementVal(Len), TGetCharacterPlacementVal(0), res,
  423.         GETCHARACTERPLACEMENTFLAGS))
  424.     else
  425.       sz := TSmallPoint(GetCharacterPlacementA(Canvas.Handle, PChar(s),
  426.         TGetCharacterPlacementVal(Len), TGetCharacterPlacementVal(0), res,
  427.         GETCHARACTERPLACEMENTFLAGS));
  428.     if UseSz2 then
  429.       sz := sz2;
  430.     Result := (Abs(sz.x-Width)<2) and (sz.y>0);
  431.     if Result then begin
  432.       p := 0;
  433.       for i := 0 to Len-1 do
  434.         POrderRev[POrder[i]] := i;
  435.       for i := 0 to Len-1 do begin
  436.         idx := POrderRev[i];
  437.         {$IFNDEF RVDONOTUSESOFTHYPHENS}
  438.         if (rvioUnicode in ItemOptions) and
  439.            ((PRVWordArray(s)[i]=UNI_ZERO_WIDTH_SPACE) or
  440.             (PRVWordArray(s)[i]=UNI_ZERO_WIDTH_JOINER) or
  441.             (PRVWordArray(s)[i]=UNI_WORD_JOINER)) then
  442.           PDX[i] := 0;
  443.         {$ENDIF}
  444.         dx  := PDX[i];
  445.         cls := PClass[idx];
  446.         if cls in [chr(GCPCLASS_ARABIC),
  447.                    chr(GCPCLASS_HEBREW)] then begin
  448.           PCP[idx+1] := p;
  449.           if idx=0 then
  450.             PCP[0] := p+dx;
  451.           end
  452.         else begin
  453.           PCP[idx+1] := p+dx+1;
  454.           if idx=0 then
  455.             PCP[0] := p;
  456.         end;
  457.         inc(p,dx);
  458.       end;
  459.     end;
  460.   finally
  461.     FreeMem(POrder);
  462.     FreeMem(POrderRev);
  463.     FreeMem(PClass);
  464.     FreeMem(PDX);
  465.   end;
  466. end;
  467. {------------------------------------------------------------------------------}
  468. function RVU_GetTextRangeCoords(Canvas: TCanvas; const s: String;
  469.   RangeStartOffs, RangeLength: Integer; ItemOptions: TRVItemOptions;
  470.   Width: Integer; var X1,X2: Integer): Boolean;
  471. var PCP: PRVIntegerArray;
  472.     X: Integer;
  473.     Len: Integer;
  474. begin
  475.   if rvioUnicode in ItemOptions then
  476.     Len := Length(s) div 2
  477.   else
  478.     Len := Length(s);
  479.   GetMem(PCP, (Len+1)*sizeof(Integer));
  480.   try
  481.     Result := RVU_GetTextCaretPos(Canvas, s, PCP, ItemOptions, Width);
  482.     if Result then begin
  483.       X1 := PCP[RangeStartOffs-1];
  484.       X2 := PCP[RangeStartOffs-1+RangeLength];
  485.       if X2<X1 then begin
  486.         X := X1;
  487.         X1 := X2;
  488.         X2 := X;
  489.       end;
  490.     end;
  491.   finally
  492.     FreeMem(PCP);
  493.   end;
  494. end;
  495. {$IFNDEF RVDONOTUSEUNICODE}
  496. {------------------------------------------------------------------------------}
  497. function RVU_Copy(const s: String; Index, Count: Integer; ItemOptions: TRVItemOptions): String;
  498. begin
  499.   if not (rvioUnicode in ItemOptions) then
  500.     Result := Copy(s, Index, Count)
  501.   else
  502.     Result := Copy(s, 1+(Index-1)*2, Count*2);
  503. end;
  504. {------------------------------------------------------------------------------}
  505. {$IFNDEF RVDONOTUSESOFTHYPHENS}
  506. function GetZWSWidth(Canvas: TCanvas): Integer;
  507. var sz: TSize;
  508.     ch: WideChar;
  509. begin
  510.   ch := WideChar(UNI_ZERO_WIDTH_SPACE);
  511.   GetTextExtentPointW(Canvas.Handle, @ch, 1, sz);
  512.   Result := sz.cx;
  513. end;
  514. function GetZWJWidth(Canvas: TCanvas): Integer;
  515. var sz: TSize;
  516.     ch: WideChar;
  517. begin
  518.   ch := WideChar(UNI_ZERO_WIDTH_JOINER);
  519.   GetTextExtentPointW(Canvas.Handle, @ch, 1, sz);
  520.   Result := sz.cx;
  521. end;
  522. function GetWJWidth(Canvas: TCanvas): Integer;
  523. var sz: TSize;
  524.     ch: WideChar;
  525. begin
  526.   ch := WideChar(UNI_WORD_JOINER);
  527.   GetTextExtentPointW(Canvas.Handle, @ch, 1, sz);
  528.   Result := sz.cx;
  529. end;
  530. {$ENDIF}
  531. {------------------------------------------------------------------------------}
  532. procedure RVU_GetTextExtentPoint32W(Canvas: TCanvas; str: Pointer; Len: Integer;
  533.   var sz: TSize);
  534. {$IFNDEF RVDONOTUSESOFTHYPHENS}
  535. var i: Integer;
  536.     ZWSWidth, ZWJWidth, WJWidth: Integer;
  537. {$ENDIF}
  538. begin
  539.   GetTextExtentPoint32W(Canvas.Handle, str, Len, sz);
  540.   {$IFNDEF RVDONOTUSESOFTHYPHENS}
  541.   ZWSWidth := -1;
  542.   ZWJWidth := -1;
  543.   WJWidth  := -1;
  544.   for i := 0 to Len-1 do
  545.     case PRVWordArray(str)[i] of
  546.       UNI_ZERO_WIDTH_SPACE:
  547.         begin
  548.           if ZWSWidth<0 then
  549.             ZWSWidth := GetZWSWidth(Canvas);
  550.           dec(sz.cx, ZWSWidth);
  551.         end;
  552.       UNI_ZERO_WIDTH_JOINER:
  553.         begin
  554.           if ZWJWidth<0 then
  555.             ZWJWidth := GetZWJWidth(Canvas);
  556.           dec(sz.cx, ZWJWidth);
  557.         end;
  558.       UNI_WORD_JOINER:
  559.         begin
  560.           if WJWidth<0 then
  561.             WJWidth := GetWJWidth(Canvas);
  562.           dec(sz.cx, WJWidth);
  563.         end;
  564.     end;
  565.   {$ENDIF}
  566. end;
  567. {------------------------------------------------------------------------------}
  568. procedure RVU_GetTextExtentExPoint(Canvas: TCanvas; const s: String;
  569.   MaxExtent: Integer; var Fit: Integer; PDx: PRVIntegerArray;
  570.   ItemOptions: TRVItemOptions);
  571. var sz: TSize;
  572.     Len: Integer;
  573. begin
  574.   Len := Length(s);
  575.   if rvioUnicode in ItemOptions then
  576.     Len := Len div 2;
  577.   RVU_GetTextExtentExPointPC(Canvas, PChar(s), Len, MaxExtent, Fit, PDx,
  578.     ItemOptions, sz);
  579. end;
  580. {------------------------------------------------------------------------------}
  581. { Length - length in characters (not bytes) }
  582. procedure RVU_GetTextExtentExPointPC(Canvas: TCanvas; pc: PChar; Length: Integer;
  583.   MaxExtent: Integer; var Fit: Integer; PDx: PRVIntegerArray;
  584.   ItemOptions: TRVItemOptions; var sz: TSize);
  585. var i: Integer;
  586.   {$IFNDEF RVDONOTUSESOFTHYPHENS}
  587.     j, delta: Integer;
  588.     ZWSWidth, ZWJWidth, WJWidth, ZWCount: Integer;
  589.   {$ENDIF}
  590.   {$IFNDEF RICHVIEWDEF4}
  591.     allocated: Boolean;
  592.   {$ELSE}
  593.   {$IFNDEF RVDONOTUSESOFTHYPHENS}
  594.     allocated: Boolean;
  595.   {$ENDIF}
  596.   {$ENDIF}
  597. begin
  598.   if Length=0 then begin
  599.     Fit := 0;
  600.     exit;
  601.   end;
  602.   {$IFNDEF RICHVIEWDEF4}
  603.   allocated := False;
  604.   {$ELSE}
  605.   {$IFNDEF RVDONOTUSESOFTHYPHENS}
  606.   allocated := False;
  607.   {$ENDIF}
  608.   {$ENDIF}
  609.   if not (rvioUnicode in ItemOptions) then begin
  610.     {$IFNDEF RICHVIEWDEF4}
  611.     if PDx=nil then begin
  612.       GetMem(PDx, (Length+1)*sizeof(Integer));
  613.       allocated := True;
  614.     end;
  615.     {$ENDIF}
  616.     GetTextExtentExPointA(Canvas.Handle,  pc, Length, MaxExtent,
  617.       {$IFDEF RICHVIEWDEF4}@Fit, PInteger(PDx),{$ELSE}Fit, PInteger(PDx)^,{$ENDIF}
  618.       sz)
  619.     end
  620.   else if not (RVNT) then begin
  621.     Fit := -1;
  622.     {$IFNDEF RVDONOTUSESOFTHYPHENS}
  623.     ZWSWidth := -1;
  624.     ZWJWidth := -1;
  625.     WJWidth  := -1;
  626.     {$ENDIF}
  627.     for i := 1 to Length do begin
  628.       GetTextExtentPoint32W(Canvas.Handle, Pointer(pc), i, sz);
  629.       {$IFNDEF RVDONOTUSESOFTHYPHENS}
  630.       case PRVWordArray(pc)[i-1] of
  631.         UNI_ZERO_WIDTH_SPACE:
  632.           begin
  633.             if ZWSWidth<0 then
  634.               ZWSWidth := GetZWSWidth(Canvas);
  635.             dec(sz.cx, ZWSWidth);
  636.           end;
  637.         UNI_ZERO_WIDTH_JOINER:
  638.           begin
  639.             if ZWJWidth<0 then
  640.               ZWJWidth := GetZWJWidth(Canvas);
  641.             dec(sz.cx, ZWJWidth);
  642.           end;
  643.         UNI_WORD_JOINER:
  644.           begin
  645.             if WJWidth<0 then
  646.               WJWidth := GetWJWidth(Canvas);
  647.             dec(sz.cx, WJWidth);
  648.           end;
  649.       end;
  650.       {$ENDIF}
  651.       if sz.cx>MaxExtent then begin
  652.         Fit := i-1;
  653.         break;
  654.       end;
  655.       if PDx<>nil then
  656.         PDx[i-1] := sz.cx;
  657.     end;
  658.     if Fit<0 then
  659.       Fit := Length;
  660.     end
  661.   else begin
  662.     {$IFNDEF RICHVIEWDEF4}
  663.     if PDx=nil then begin
  664.       GetMem(PDx, (Length+1)*sizeof(Integer));
  665.       allocated := True;
  666.     end;
  667.     {$ENDIF}
  668.     {$IFNDEF RVDONOTUSESOFTHYPHENS}
  669.     if (PDx=nil) and
  670.        ((RVU_StrScanW(pc, UNI_ZERO_WIDTH_SPACE, Length)<>nil) or
  671.         (RVU_StrScanW(pc, UNI_ZERO_WIDTH_JOINER, Length)<>nil) or
  672.         (RVU_StrScanW(pc, UNI_WORD_JOINER, Length)<>nil)) then begin
  673.       GetMem(PDx, (Length+1)*sizeof(Integer));
  674.       allocated := True;
  675.     end;
  676.     {$ENDIF}
  677.     GetTextExtentExPointW(Canvas.Handle, Pointer(pc), Length, MaxExtent,
  678.       {$IFDEF RICHVIEWDEF4}@Fit, PInteger(PDx),{$ELSE}Fit, PInteger(PDx)^,{$ENDIF}
  679.       sz);
  680.     {$IFNDEF RVDONOTUSESOFTHYPHENS}
  681.     ZWCount := 0;
  682.     for i := 0 to Length-1 do
  683.       if (PRVWordArray(pc)[i]=UNI_ZERO_WIDTH_SPACE) or
  684.          (PRVWordArray(pc)[i]=UNI_ZERO_WIDTH_JOINER) or
  685.          (PRVWordArray(pc)[i]=UNI_WORD_JOINER) then begin
  686.         if i=0 then
  687.           delta := PDx[0]
  688.         else
  689.           delta := PDx[i]-PDx[i-1];
  690.         if delta<>0 then begin
  691.           for j := i to Length-1 do
  692.             dec(PDx[j], delta);
  693.           inc(ZWCount);
  694.         end;
  695.       end;
  696.     if ZWCount>0 then begin
  697.       while (Fit<Length) and (PDx[Fit]<MaxExtent) do
  698.         inc(Fit);
  699.     end;
  700.     {$ENDIF}    
  701.   end;
  702.   {$IFNDEF RICHVIEWDEF4}
  703.   if allocated then
  704.     FreeMem(PDx);
  705.   {$ELSE}
  706.   {$IFNDEF RVDONOTUSESOFTHYPHENS}
  707.   if allocated then
  708.     FreeMem(PDx);  
  709.   {$ENDIF}
  710.   {$ENDIF}
  711. end;
  712. {------------------------------------------------------------------------------}
  713. function RVU_Length(const s: String; ItemOptions: TRVItemOptions): Integer;
  714. begin
  715.   if not (rvioUnicode in ItemOptions) then
  716.     Result := Length(s)
  717.   else
  718.     Result := Length(s) div 2;
  719. end;
  720. {------------------------------------------------------------------------------}
  721. function RVU_TextWidth(const s: String; Canvas: TCanvas;
  722.                        ItemOptions: TRVItemOptions): Integer;
  723. var Size: TSize;
  724. begin
  725.   if not (rvioUnicode in ItemOptions) then
  726.     GetTextExtentPoint32A(Canvas.Handle, PChar(s), Length(s), Size)
  727.   else
  728.     RVU_GetTextExtentPoint32W(Canvas, Pointer(PChar(s)), Length(s) div 2, Size);
  729.   Result := Size.cx;
  730. end;
  731. {------------------------------------------------------------------------------}
  732. function RVU_IsSpace(const s: String; Index: Integer;
  733.                      ItemOptions: TRVItemOptions): Boolean;
  734. begin
  735.   if not (rvioUnicode in ItemOptions) then
  736.     Result := s[Index]=' '
  737.   else
  738.     Result := (s[(Index-1)*2+1]=' ') and (s[Index*2]=#0);
  739. end;
  740. {------------------------------------------------------------------------------}
  741. procedure RVU_Delete(var s: String; Index, Count: Integer; ItemOptions: TRVItemOptions);
  742. begin
  743.   if not (rvioUnicode in ItemOptions) then
  744.     Delete(s, Index, Count)
  745.   else
  746.     Delete(s, (Index-1)*2+1, Count*2);
  747. end;
  748. {------------------------------------------------------------------------------}
  749. procedure RVU_Insert(const Source: String; var s: String; Index: Integer; ItemOptions: TRVItemOptions);
  750. begin
  751.   if not (rvioUnicode in ItemOptions) then
  752.     Insert(Source, s, Index)
  753.   else
  754.     Insert(Source, s, (Index-1)*2+1);
  755. end;
  756. {------------------------------------------------------------------------------}
  757. function RVU_OffsInPChar(Offs: Integer; ItemOptions: TRVItemOptions): Integer;
  758. begin
  759.   if not (rvioUnicode in ItemOptions) then
  760.     Result := Offs
  761.   else
  762.     Result := Offs*2;
  763. end;
  764. {------------------------------------------------------------------------------}
  765. {$ELSE}
  766. {------------------------------------------------------------------------------}
  767. function RVU_Copy(const s: String; Index, Count: Integer; ItemOptions: TRVItemOptions): String;
  768. begin
  769.   Result := Copy(s, Index, Count);
  770. end;
  771. {------------------------------------------------------------------------------}
  772. procedure RVU_GetTextExtentExPoint(Canvas: TCanvas; const s: String;
  773.   MaxExtent: Integer; var Fit: Integer; PDx: PRVIntegerArray;
  774.   ItemOptions: TRVItemOptions);
  775. var sz: TSize;
  776. {$IFNDEF RICHVIEWDEF4}
  777.     allocated: Boolean;
  778. {$ENDIF}
  779. begin
  780.   if Length(s)=0 then begin
  781.     Fit := 0;
  782.     exit;
  783.   end;
  784.   {$IFNDEF RICHVIEWDEF4}
  785.   if PDx=nil then begin
  786.     GetMem(PDx, (Length(s)+1)*sizeof(Integer));
  787.     allocated := True;
  788.     end
  789.   else
  790.     allocated := False;
  791.   {$ENDIF}
  792.   GetTextExtentExPointA(Canvas.Handle,  PChar(s), Length(s), MaxExtent,
  793.     {$IFDEF RICHVIEWDEF4}@Fit, PInteger(PDx),{$ELSE}Fit, PInteger(PDx)^,{$ENDIF}
  794.     sz);
  795.   {$IFNDEF RICHVIEWDEF4}
  796.   if allocated then
  797.     FreeMem(PDx);
  798.   {$ENDIF}
  799. end;
  800. {------------------------------------------------------------------------------}
  801. procedure RVU_GetTextExtentExPointPC(Canvas: TCanvas; pc: PChar;
  802.                                   Length: Integer;
  803.                                   MaxExtent: Integer; var Fit: Integer;
  804.                                   PDx: PRVIntegerArray;
  805.                                   ItemOptions: TRVItemOptions;
  806.                                   var sz: TSize);
  807. {$IFNDEF RICHVIEWDEF4}
  808. var
  809.     allocated: Boolean;
  810. {$ENDIF}
  811. begin
  812.   if Length=0 then begin
  813.     Fit := 0;
  814.     exit;
  815.   end;
  816.   {$IFNDEF RICHVIEWDEF4}
  817.   if PDx=nil then begin
  818.     GetMem(PDx, (Length+1)*sizeof(Integer));
  819.     allocated := True;
  820.     end
  821.   else
  822.     allocated := False;
  823.   {$ENDIF}
  824.   GetTextExtentExPointA(Canvas.Handle,  pc, Length, MaxExtent,
  825.                             {$IFDEF RICHVIEWDEF4}
  826.                             @Fit, PInteger(PDx),
  827.                             {$ELSE}
  828.                             Fit, PInteger(PDx)^,
  829.                             {$ENDIF}
  830.                             sz);
  831.   {$IFNDEF RICHVIEWDEF4}
  832.   if allocated then
  833.     FreeMem(PDx);
  834.   {$ENDIF}
  835. end;
  836. {------------------------------------------------------------------------------}
  837. function RVU_Length(const s: String; ItemOptions: TRVItemOptions): Integer;
  838. begin
  839.   Result := Length(s);
  840. end;
  841. {------------------------------------------------------------------------------}
  842. function RVU_TextWidth(const s: String; Canvas: TCanvas;
  843.                        ItemOptions: TRVItemOptions): Integer;
  844. var Size: TSize;
  845. begin
  846.   GetTextExtentPoint32(Canvas.Handle, PChar(s), Length(s), Size);
  847.   Result := Size.cx;
  848. end;
  849. {------------------------------------------------------------------------------}
  850. function RVU_IsSpace(const s: String; Index: Integer;
  851.                      ItemOptions: TRVItemOptions): Boolean;
  852. begin
  853.   Result := s[Index]=' ';
  854. end;
  855. {------------------------------------------------------------------------------}
  856. procedure RVU_Delete(var s: String; Index, Count: Integer; ItemOptions: TRVItemOptions);
  857. begin
  858.   Delete(s, Index, Count);
  859. end;
  860. {------------------------------------------------------------------------------}
  861. procedure RVU_Insert(const Source: String; var s: String; Index: Integer; ItemOptions: TRVItemOptions);
  862. begin
  863.   Insert(Source, s, Index);
  864. end;
  865. {------------------------------------------------------------------------------}
  866. function RVU_OffsInPChar(Offs: Integer; ItemOptions: TRVItemOptions): Integer;
  867. begin
  868.   Result := Offs;
  869. end;
  870. {$ENDIF}
  871. {------------------------------------------------------------------------------}
  872. function RVU_DrawSelectedTextEx(Left, Top, Width, Height: Integer;
  873.   const s: String; Canvas: TCanvas; Index1,Index2: Integer;
  874.   ItemOptions: TRVItemOptions; BiDiMode: TRVBiDiMode): Boolean;
  875. begin
  876.   if BiDiMode=rvbdUnspecified then
  877.     Result := False
  878.   else
  879.     Result := RVU_DrawSelectedTextEx_(Left, Top, Width, Height, s, Canvas,
  880.       Index1, Index2, ItemOptions);
  881. end;
  882. {------------------------------------------------------------------------------}
  883. {$IFDEF RICHVIEWCBDEF3}
  884. function RVU_Charset2CodePage(Charset: TFontCharset): TRVCodePage;
  885. begin
  886.   // PLEASE REPORT ME ABOUT ERRORS IN THIS TABLE
  887.   case Charset of
  888.     DEFAULT_CHARSET:
  889.       Result := CP_ACP;
  890.     OEM_CHARSET:
  891.        Result := CP_OEMCP;
  892.     MAC_CHARSET:
  893.        Result := CP_MACCP;
  894.     SYMBOL_CHARSET:
  895.       Result := CP_ACP; // ???
  896.     VIETNAMESE_CHARSET:
  897.        Result := 1258;
  898.     ANSI_CHARSET:
  899.       Result := 1252;   // Windows 3.1 US (ANSI)
  900.     SHIFTJIS_CHARSET:
  901.        Result := 932;   // Japan
  902.     HANGEUL_CHARSET:
  903.        Result := 949;   // Korean
  904.     JOHAB_CHARSET:
  905.        Result := 1361;  // Korean (Johab)
  906.     GB2312_CHARSET:
  907.        Result := 936;   // Chinese (PRC, Singapore)
  908.     CHINESEBIG5_CHARSET:
  909.        Result := 950;   // Chinese (Taiwan, Hong Kong)
  910.     GREEK_CHARSET:
  911.        Result := 1253;  // Windows 3.1 Greek
  912.     TURKISH_CHARSET:
  913.        Result := 1254;  // Windows 3.1 Turkish
  914.     HEBREW_CHARSET:
  915.        Result := 1255;   // Hebrew
  916.     ARABIC_CHARSET:
  917.        Result := 1256;   // Arabic
  918.     BALTIC_CHARSET:
  919.        Result := 1257;   // Baltic
  920.     RUSSIAN_CHARSET:
  921.        Result := 1251;   // Windows 3.1 Cyrillic
  922.     THAI_CHARSET:
  923.        Result := 874;    // Thai
  924.     EASTEUROPE_CHARSET:
  925.        Result := 1250;   // Windows 3.1 Eastern European
  926.     else
  927.        Result := CP_ACP;
  928.   end;
  929. end;
  930. {------------------------------------------------------------------------------}
  931. function RVU_Charset2Language(Charset: TFontCharset): Cardinal;
  932. begin
  933.   // PLEASE REPORT ME ABOUT ERRORS IN THIS TABLE
  934.   // Note: trying to make a best guess here;
  935.   // one charset can be used by a lots of languages
  936.   case Charset of
  937.     DEFAULT_CHARSET:
  938.       Result := $0000; // default
  939.     OEM_CHARSET:
  940.        Result := $0400; // default
  941.     MAC_CHARSET:
  942.        Result := $0400; // default
  943.     SYMBOL_CHARSET:
  944.       Result := $0400; // default
  945.     VIETNAMESE_CHARSET:
  946.        Result := $042A;  // by experement with MS Word
  947.     ANSI_CHARSET:
  948.       Result := $0409;   // English US
  949.     SHIFTJIS_CHARSET:
  950.        Result := $0411;   // Japanese
  951.     HANGEUL_CHARSET:
  952.        Result := $0412;   // Korean
  953.     JOHAB_CHARSET:
  954.        Result := $0812;  // Korean (Johab)
  955.     GB2312_CHARSET:
  956.        Result := $0804;   // Chinese (PRC; more options possible here)
  957.     CHINESEBIG5_CHARSET:
  958.        Result := $0404;   // Chinese (Taiwan; more options possible here)
  959.     GREEK_CHARSET:
  960.        Result := $0408;  // Greek
  961.     TURKISH_CHARSET:
  962.        Result := $041F;  // Turkish
  963.     HEBREW_CHARSET:
  964.        Result := $040D;  // Hebrew
  965.     ARABIC_CHARSET:
  966.        Result := $0000;  // default - too many options
  967.     BALTIC_CHARSET:
  968.        Result := $0000;  // default - too many options
  969.     RUSSIAN_CHARSET:
  970.        Result := $0419;   // Russian
  971.     THAI_CHARSET:
  972.        Result := $041E;    // Thai
  973.     EASTEUROPE_CHARSET:
  974.        Result := $0400;   // default - too many options
  975.     else
  976.        Result := $0400;
  977.   end;
  978. end;
  979. {------------------------------------------------------------------------------}
  980. function RVU_RawUnicodeToWideString(const s: String):WideString;
  981. begin
  982.   RVCheckUni(Length(s));
  983.   SetLength(Result, Length(s) div 2);
  984.   Move(Pointer(s)^, Pointer(Result)^, Length(s));
  985. end;
  986. {------------------------------------------------------------------------------}
  987. function RVU_GetRawUnicode(const s: WideString):String;
  988. begin
  989.   SetLength(Result, Length(s)*2);
  990.   Move(Pointer(s)^, Pointer(Result)^, Length(Result));
  991. end;
  992. {$ELSE}
  993. {------------------------------------------------------------------------------}
  994. function RVU_GetRawUnicode(const s: String):String;
  995. begin
  996.   Result := s;
  997. end;
  998. {$ENDIF}
  999. {------------------------------------------------------------------------------}
  1000. procedure RVU_SwapWordBytes(arr: PWord; Count: Integer);
  1001. var i: Integer;
  1002. begin
  1003.   for i := 0 to Count-1 do begin
  1004.     arr^ := Swap(Word(arr^));
  1005.     inc(PChar(arr),2);
  1006.   end;
  1007. end;
  1008. {------------------------------------------------------------------------------}
  1009. procedure RVU_ProcessByteOrderMark(var arr: PWord; Count: Integer);
  1010. begin
  1011.   if Count=0 then
  1012.     exit;
  1013.   case arr^ of
  1014.     UNI_MSB_FIRST:
  1015.       begin
  1016.         inc(PChar(arr), 2);
  1017.         RVU_SwapWordBytes(arr, Count-1);
  1018.       end;
  1019.     UNI_LSB_FIRST:
  1020.       inc(PChar(arr), 2);
  1021.   end;
  1022. end;
  1023. {------------------------------------------------------------------------------}
  1024. function RVU_AnsiToUnicode(CodePage: TRVCodePage; const s: String): String;
  1025. var l: Integer;
  1026. begin
  1027.   if Length(s)=0 then begin
  1028.     Result := '';
  1029.     exit;
  1030.   end;
  1031.   l := MultiByteToWideChar(CodePage,MB_PRECOMPOSED or MB_USEGLYPHCHARS, PChar(s), Length(s),
  1032.                            nil, 0);
  1033.   if (l=0) and (CodePage<>CP_ACP) then begin
  1034.     CodePage := CP_ACP;
  1035.     l := MultiByteToWideChar(CodePage, MB_PRECOMPOSED or MB_USEGLYPHCHARS, PChar(s), Length(s),
  1036.                            nil, 0);
  1037.   end;
  1038.   if l<>0 then begin
  1039.     SetLength(Result, l*2);
  1040.     MultiByteToWideChar(CodePage, MB_PRECOMPOSED or MB_USEGLYPHCHARS, PChar(s), Length(s),
  1041.                              Pointer(Result), l);
  1042.     end
  1043.   else begin
  1044.     SetLength(Result, Length(s)*2);
  1045.     FillChar(PChar(Result)^, Length(Result), 0);
  1046.     for l := 0 to Length(s)-1 do
  1047.       Result[l*2+1] := RVDEFAULTCHARACTER
  1048.   end;
  1049. end;
  1050. {------------------------------------------------------------------------------}
  1051. function RVU_AnsiToUTF8(CodePage: TRVCodePage; const s: String): String;
  1052. begin
  1053.   {$IFDEF RICHVIEWCBDEF3}
  1054.   if s='' then
  1055.     Result := ''
  1056.   else
  1057.     Result := UTF8Encode(RVU_RawUnicodeToWideString((RVU_AnsiToUnicode(CodePage, s))));
  1058.   {$ELSE}
  1059.     Result := s;
  1060.   {$ENDIF}
  1061. end;
  1062. {------------------------------------------------------------------------------}
  1063. function RVU_UnicodeToAnsi(CodePage: TRVCodePage; const s: String): String;
  1064. var l: Integer;
  1065.     DefChar: Char;
  1066.     Flags: Integer;
  1067.     Len: Integer;
  1068. begin
  1069.   if Length(s)=0 then begin
  1070.     Result := '';
  1071.     exit;
  1072.   end;
  1073.   RVCheckUni(Length(s));
  1074.   DefChar := RVDEFAULTCHARACTER;
  1075.   Flags := WC_COMPOSITECHECK or WC_DISCARDNS or WC_SEPCHARS or WC_DEFAULTCHAR;
  1076.   Len := Length(s) div 2;
  1077.   l := WideCharToMultiByte(CodePage, Flags, Pointer(s), Len, nil, 0, @DefChar, nil);
  1078.   if (l=0) and (CodePage<>CP_ACP) then begin
  1079.     CodePage := CP_ACP;
  1080.     l := WideCharToMultiByte(CodePage, Flags, Pointer(s), Len, nil, 0, @DefChar, nil);
  1081.   end;
  1082.   if l<>0 then begin
  1083.     SetLength(Result, l);
  1084.     WideCharToMultiByte(CodePage, Flags, Pointer(s), Len, PChar(Result), l, @DefChar, nil);
  1085.     end
  1086.   else begin
  1087.     SetLength(Result, Len);
  1088.     FillChar(PChar(Result)^, Len, RVDEFAULTCHARACTER);
  1089.   end;
  1090. end;
  1091. {------------------------------------------------------------------------------}
  1092. function RVU_CanBeConvertedToAnsi(CodePage: TRVCodePage; const s: String): Boolean;
  1093. var l: Integer;
  1094.     DefChar: Char;
  1095.     Flags: Integer;
  1096.     Len: Integer;
  1097.     UsedDefChar: LongBool;
  1098. begin
  1099.   if Length(s)=0 then begin
  1100.     Result := True;
  1101.     exit;
  1102.   end;
  1103.   RVCheckUni(Length(s));
  1104.   DefChar := RVDEFAULTCHARACTER;
  1105.   Flags := WC_COMPOSITECHECK or WC_DISCARDNS or WC_SEPCHARS or WC_DEFAULTCHAR;
  1106.   Len := Length(s) div 2;
  1107.   UsedDefChar := False;
  1108.   l := WideCharToMultiByte(CodePage, Flags, Pointer(s), Len, nil, 0, @DefChar, @UsedDefChar);
  1109.   Result := (l>0) and not UsedDefChar;
  1110. end;
  1111. {------------------------------------------------------------------------------}
  1112. function RV_TestStreamUnicode(Stream: TStream): TRVUnicodeTestResult;
  1113. var FirstChar: Word;
  1114.     Len: Integer;
  1115.     s: String;
  1116. begin
  1117.   try
  1118.     if Stream.Size=0 then
  1119.       Result := rvutEmpty
  1120.     else if Stream.Size mod 2 <> 0 then
  1121.       Result := rvutNo
  1122.     else begin
  1123.       Stream.ReadBuffer(FirstChar, 2);
  1124.       if (FirstChar=UNI_LSB_FIRST) or
  1125.          (FirstChar=UNI_MSB_FIRST) then
  1126.         Result := rvutYes
  1127.       else begin
  1128.         Len := Stream.Size-2;
  1129.         if Len>500 then Len := 500;
  1130.         SetLength(s, Len);
  1131.         Stream.ReadBuffer(PChar(s)^, Len);
  1132.         if Pos(#0, s)<>0 then
  1133.           Result := rvutYes
  1134.         else
  1135.           Result := rvutProbably;
  1136.       end;
  1137.     end;
  1138.   except
  1139.     Result := rvutError;
  1140.   end;
  1141. end;
  1142. {------------------------------------------------------------------------------}
  1143. function RV_TestFileUnicode(const FileName: String): TRVUnicodeTestResult;
  1144. var Stream: TFileStream;
  1145. begin
  1146.   try
  1147.     Stream := TFileStream.Create(FileName, fmOpenRead);
  1148.     Result := RV_TestStreamUnicode(Stream);
  1149.     Stream.Free;
  1150.   except
  1151.     Result := rvutError;
  1152.   end;
  1153. end;
  1154. {------------------------------------------------------------------------------}
  1155. function RV_TestStringUnicode(const s: String): TRVUnicodeTestResult;
  1156. var Stream: TMemoryStream;
  1157.     Len: Integer;
  1158. begin
  1159.   if Length(s) mod 2 <> 0 then begin
  1160.     Result := rvutNo;
  1161.     exit;
  1162.   end;
  1163.   Len := Length(s);
  1164.   if Len>500 then
  1165.     Len := 500;
  1166.   try
  1167.     Stream := TMemoryStream.Create;
  1168.     try
  1169.       Stream.SetSize(Len);
  1170.       Stream.WriteBuffer(PChar(s)^, Len);
  1171.       Stream.Position := 0;
  1172.       Result := RV_TestStreamUnicode(Stream);
  1173.     finally
  1174.       Stream.Free;
  1175.     end;
  1176.   except
  1177.     Result := rvutError;  
  1178.   end;
  1179. end;
  1180. {------------------------------------------------------------------------------}
  1181. function RVU_GetKeyboardCodePage: TRVCodePage;
  1182. var Buf: String;
  1183.     Len: Integer;
  1184.     Locale: LCID;
  1185.     {$IFNDEF RICHVIEWCBDEF3}
  1186. const LOCALE_IDEFAULTANSICODEPAGE     = $00001004;
  1187.     {$ENDIF}
  1188. begin
  1189.   Locale := GetKeyboardLayout(0) and $FFFF;
  1190.   Len := GetLocaleInfo(Locale, LOCALE_IDEFAULTANSICODEPAGE, nil, 0);
  1191.   SetLength(Buf, Len);
  1192.   GetLocaleInfo(Locale, LOCALE_IDEFAULTANSICODEPAGE, PChar(Buf), Len);
  1193.   Result := StrToIntDef(Buf, GetACP);
  1194. end;
  1195. {------------------------------------------------------------------------------}
  1196. function RVU_KeyToUnicode(const Key: String): String;
  1197. begin
  1198.   Result :=  RVU_AnsiToUnicode(RVU_GetKeyboardCodePage, Key);
  1199. end;
  1200. {------------------------------------------------------------------------------}
  1201. function RVU_StrScanW(Str: Pointer; Ch: Word; Length: Integer): Pointer;
  1202. // in: Str -> EAX, Ch -> EDX, Length -> ECX
  1203. // out: Result -> EAX
  1204. // Assums Str<>nil
  1205. asm
  1206.     JCXZ @@RetNil
  1207. @@Loop:
  1208.     CMP [EAX], DX
  1209.     JE @@Done
  1210.     INC EAX
  1211.     INC EAX
  1212.     DEC ECX
  1213.     JNZ @@Loop
  1214. @@RetNil:
  1215.     XOR EAX, EAX
  1216. @@Done:
  1217. end;
  1218. {------------------------------------------------------------------------------}
  1219. { returns number of characters in a string excluding the null terminator       }
  1220. function RVU_StrLenW(Str: Pointer): Cardinal;
  1221. // in: Str -> EAX
  1222. // out: Result -> EAX
  1223. asm
  1224.     MOV EDX, EDI
  1225.     MOV EDI, EAX
  1226.     MOV ECX, 0FFFFFFFFH
  1227.     XOR AX, AX
  1228.     REPNE SCASW
  1229.     MOV EAX, 0FFFFFFFEH
  1230.     SUB EAX, ECX
  1231.     MOV EDI, EDX
  1232. end;
  1233. {------------------------------------------------------------------------------}
  1234. {$IFNDEF RVDONOTUSEHTML}
  1235. function GetCharHTMLCode(ch: Char; var prevspace, specialcode: Boolean; last: Boolean): String;
  1236. begin
  1237.   if specialcode then begin
  1238.     Result := ch;
  1239.     prevspace := False;
  1240.     exit;
  1241.   end;
  1242.   if ch='&' then begin
  1243.     Result := '&amp;';
  1244.     prevspace := False;
  1245.     end
  1246.   else if ch='<' then begin
  1247.     Result := '&lt;';
  1248.     prevspace := False;
  1249.     end
  1250.   else if ch='>' then begin
  1251.     Result := '&gt;';
  1252.     prevspace := False;
  1253.     end
  1254.   else if ch=' ' then begin
  1255.     if prevspace or last then begin
  1256.       Result := '&nbsp;';
  1257.       prevspace := False;
  1258.       end
  1259.     else begin
  1260.       Result := ch;
  1261.       prevspace := True;
  1262.       end
  1263.     end
  1264.   else begin
  1265.     Result := ch;
  1266.     prevspace := False;
  1267.   end;
  1268. end;
  1269. {------------------------------------------------------------------------------}
  1270. procedure RVU_WriteHTMLEncodedUnicode(Stream: TStream; const s: String;NoEmptyLines,SpecialCode:Boolean);
  1271. var p: PWord;
  1272.     chars: String;
  1273.     i: Integer;
  1274.     prevspace: Boolean;
  1275.     Len: Integer;
  1276. begin
  1277.   if (Length(s)=0) and NoEmptyLines then begin
  1278.     chars := '&nbsp;';
  1279.     Stream.WriteBuffer(PChar(chars)^,Length(chars));
  1280.   end;
  1281.   prevspace := True;
  1282.   p := PWord(PChar(s));
  1283.   Len := Length(s) div 2;
  1284.   for i := 1 to Len do begin
  1285.     if (p^<128) then
  1286.       chars := GetCharHTMLCode(chr(p^), prevspace, SpecialCode, i=Len)
  1287.     else begin
  1288.       chars := Format('&#%d;',[p^]);
  1289.       prevspace := False;
  1290.     end;
  1291.     Stream.WriteBuffer(PChar(chars)^,Length(chars));
  1292.     inc(PChar(p),2);
  1293.   end;
  1294. end;
  1295. {------------------------------------------------------------------------------}
  1296. function RVU_GetHTMLEncodedUnicode(const s: String; SpecialCode:Boolean): String;
  1297. var p: PWord;
  1298.     i, Len: Integer;
  1299.     prevspace: Boolean;
  1300. begin
  1301.   prevspace := True;
  1302.   Result := '';
  1303.   p := PWord(PChar(s));
  1304.   Len := Length(s) div 2;
  1305.   for i := 1 to Len do begin
  1306.     if (p^<128) then
  1307.       Result := Result+GetCharHTMLCode(chr(p^), prevspace,SpecialCode, i=Len)
  1308.     else if p^=160 then
  1309.       Result := Result+'&nbsp;'
  1310.     else begin
  1311.       Result := Result+Format('&#%d;',[p^]);
  1312.       prevspace := False;
  1313.     end;
  1314.     inc(PChar(p),2);
  1315.   end;
  1316. end;
  1317. {------------------------------------------------------------------------------}
  1318. function GetHTMLEntity(ch: Char): String;
  1319. begin
  1320.   case ch of
  1321.     '&':
  1322.       Result := '&amp;';
  1323.     '<':
  1324.       Result := '&lt;';
  1325.     '>':
  1326.       Result := '&gt;';
  1327.     #160:
  1328.       Result := '&nbsp;';
  1329.     else
  1330.       Result := '';
  1331.   end;
  1332. end;
  1333. {------------------------------------------------------------------------------}
  1334. function RVU_UnicodeToUTF8(const s: String; SpecialCode:Boolean): String;
  1335. {$IFDEF RICHVIEWCBDEF3}
  1336. var p: PWord;
  1337.     i, Len, SeqLen: Integer;
  1338.     prevspace: Boolean;
  1339.     {....................................}
  1340.     procedure AddUTF8(var res: String);
  1341.     var ws: WideString;
  1342.     begin
  1343.       SetLength(ws, SeqLen);
  1344.       Move((PChar(p)-SeqLen*2)^, PWideChar(ws)^, SeqLen*2);
  1345.       res := res+UTF8Encode(ws);
  1346.       SeqLen := 0;
  1347.     end;
  1348.     {....................................}
  1349. {$ENDIF}
  1350. begin
  1351. {$IFDEF RICHVIEWCBDEF3}
  1352.   if SpecialCode then begin
  1353.     Result := UTF8Encode(RVU_RawUnicodeToWideString(s));
  1354.     exit;
  1355.   end;
  1356.   prevspace := True;
  1357.   Result := '';
  1358.   p := PWord(PChar(s));
  1359.   Len := Length(s) div 2;
  1360.   SeqLen := 0;
  1361.   for i := 1 to Len do begin
  1362.     case p^ of
  1363.       ord('&'), ord('<'), ord('>'), 160:
  1364.         begin
  1365.           if SeqLen>0 then
  1366.             AddUTF8(Result);
  1367.           Result := Result+GetHTMLEntity(chr(p^));
  1368.           prevspace := False;
  1369.         end;
  1370.       ord(' '):
  1371.         begin
  1372.           if prevspace or (i=Len) then begin
  1373.             if SeqLen>0 then
  1374.               AddUTF8(Result);
  1375.             Result := Result+'&nbsp;';
  1376.             prevspace := False;
  1377.             end
  1378.           else begin
  1379.             inc(SeqLen);
  1380.             prevspace := True;
  1381.           end;
  1382.         end;
  1383.       else
  1384.         begin
  1385.           inc(SeqLen);
  1386.           prevspace := False;
  1387.         end;
  1388.     end;
  1389.     inc(PChar(p),2);
  1390.   end;
  1391.   if SeqLen>0 then
  1392.     AddUTF8(Result);
  1393. {$ELSE}
  1394.   Result :=RVU_GetHTMLEncodedUnicode(s, SpecialCode);
  1395. {$ENDIF}
  1396. end;
  1397. {$ENDIF}
  1398. {------------------------------------------------------------------------------}
  1399. function RV_ReturnProcessedString(const s: String; TextStyle: TFontInfo;
  1400.   LastOnLine, ShowSpecialChars, ForDisplay: Boolean): String;
  1401. {$IFNDEF RVDONOTUSESOFTHYPHENS}
  1402. {$IFNDEF RVDONOTUSEUNICODE}
  1403. var i, len: Integer;
  1404.     Changed: Boolean;
  1405. {$ENDIF}
  1406. {$ENDIF}
  1407. begin
  1408.   if not (rvscSoftHyphen in RVVisibleSpecialCharacters) then
  1409.     ShowSpecialChars := False;
  1410.   {$IFNDEF RVDONOTUSEALLCAPS}
  1411.   if rvfsAllCaps in TextStyle.StyleEx then begin
  1412.     {$IFNDEF RVDONOTUSEUNICODE}
  1413.     if TextStyle.Unicode then begin
  1414.       if RVNT then begin
  1415.         SetString(Result, PChar(s), Length(s));
  1416.         CharUpperBuffW(Pointer(Result), Length(s) div 2);
  1417.         end
  1418.       else
  1419.         Result := s;
  1420.       end
  1421.     else
  1422.    {$ENDIF}
  1423.      Result := AnsiUpperCase(s);
  1424.    end
  1425.   else
  1426.     Result := s;
  1427.   {$ELSE}
  1428.   Result := s;
  1429.   {$ENDIF}
  1430.   {$IFNDEF RVDONOTUSESOFTHYPHENS}
  1431.   {$IFNDEF RVDONOTUSEUNICODE}
  1432.   if TextStyle.Unicode then begin
  1433.     Changed := False;
  1434.     len := (Length(Result) div 2);
  1435.     if LastOnLine and not ShowSpecialChars then
  1436.       dec(len);
  1437.     for i := 0 to len-1 do
  1438.       if PRVWordArray(PChar(Result))[i]=UNI_SOFT_HYPHEN then begin
  1439.         if not Changed then begin
  1440.           UniqueString(Result);
  1441.           Changed := True;
  1442.         end;
  1443.         if ShowSpecialChars then
  1444.           PRVWordArray(PChar(Result))[i] := UNI_NOT_SIGN
  1445.         else
  1446.           PRVWordArray(PChar(Result))[i] := UNI_ZERO_WIDTH_SPACE;
  1447.       end;
  1448.     if ForDisplay then
  1449.       for i := (Length(Result) div 2)-1 downto 0 do
  1450.         if (PRVWordArray(PChar(Result))[i]=UNI_ZERO_WIDTH_SPACE) or
  1451.            (PRVWordArray(PChar(Result))[i]=UNI_ZERO_WIDTH_JOINER) or
  1452.            (PRVWordArray(PChar(Result))[i]=UNI_WORD_JOINER) then begin
  1453.           if not Changed then begin
  1454.             UniqueString(Result);
  1455.             Changed := True;
  1456.           end;
  1457.           Delete(Result, i*2+1, 2);
  1458.         end;
  1459.   end;
  1460.   {$ENDIF}
  1461.   {$ENDIF}
  1462. end;
  1463. {------------------------------------------------------------------------------}
  1464. procedure RVCheckNT;
  1465. var vi: TOSVersionInfo;
  1466. begin
  1467.   vi.dwOSVersionInfoSize := sizeof(vi);
  1468.   GetVersionEx(vi);
  1469.   RVNT := vi.dwPlatformId=VER_PLATFORM_WIN32_NT;
  1470. end;
  1471. {------------------------------------------------------------------------------}
  1472. {$IFNDEF RVDONOTUSEUNICODE}
  1473. {$O+}
  1474. function GetCharLineBreakClass(Char: Word): TRVLineBreakClass;
  1475. begin
  1476.   case Char of
  1477.     $002D:
  1478.       Result := rvu_lb_HY;
  1479.     $002F:
  1480.       Result := rvu_lb_SY;
  1481.     $200B:
  1482.       Result := rvu_lb_ZW;
  1483.     $2014:
  1484.       Result := rvu_lb_B2;
  1485.     $2024..$2026:
  1486.       Result := rvu_lb_IN;
  1487.     $002C,$002E,$003A..$003B,$0589:
  1488.       Result := rvu_lb_IS;
  1489.     $00A0,$0F0C,$2007,$2011,$202F,$2060,$FEFF:
  1490.       Result := rvu_lb_GL;
  1491.     $00B4,$02C8,$02CC,$1806:
  1492.       Result := rvu_lb_BB;
  1493.     $0009,$007C,$00AD,$058A,$0F0B,$1361,$1680,$17D5,$2000..$2006,$2008..$200A,
  1494.     $2010,$2012..$2013,$2027,$205F:
  1495.       Result := rvu_lb_BA;
  1496.     $0021,$003F,$2762..$2763,$FE56..$FE57,$FF01,$FF1F:
  1497.       Result := rvu_lb_EX;
  1498.     $0022,$0027,$00AB,$00BB,$2018..$2019,$201B..$201D,$201F,$2039..$203A,$23B6,
  1499.     $275B..$275E:
  1500.       Result := rvu_lb_QU;
  1501.     $0024,$002B,$005C,$00A3..$00A5,$00B1,$09F2..$09F3,$0E3F,$17DB,$20A0..$20A6,
  1502.     $20A8..$20B1,$2116,$2212..$2213,$FE69,$FF04,$FFE1,$FFE5..$FFE6:
  1503.       Result := rvu_lb_PR;
  1504.     $0025,$00A2,$00B0,$2030..$2037,$20A7,$2103,$2109,$2126,$FDFC,$FE6A,$FF05,
  1505.     $FFE0:
  1506.       Result := rvu_lb_PO;
  1507.     $0028,$005B,$007B,$0F3A,$0F3C,$169B,$201A,$201E,$2045,$207D,$208D,$2329,
  1508.     $23B4,$2768,$276A,$276C,$276E,$2770,$2772,$2774,$27E6,$27E8,$27EA,$2983,
  1509.     $2985,$2987,$2989,$298B,$298D,$298F,$2991,$2993,$2995,$2997,$29D8,$29DA,
  1510.     $29FC,$3008,$300A,$300C,$300E,$3010,$3014,$3016,$3018,$301A,$301D,$FD3E,
  1511.     $FE35,$FE37,$FE39,$FE3B,$FE3D,$FE3F,$FE41,$FE43,$FE59,$FE5B,$FE5D,$FF08,
  1512.     $FF3B,$FF5B,$FF5F,$FF62:
  1513.       Result := rvu_lb_OP;
  1514.     $0029,$005D,$007D,$0F3B,$0F3D,$169C,$2046,$207E,$208E,$232A,$23B5,$2769,
  1515.     $276B,$276D,$276F,$2771,$2773,$2775,$27E7,$27E9,$27EB,$2984,$2986,$2988,
  1516.     $298A,$298C,$298E,$2990,$2992,$2994,$2996,$2998,$29D9,$29DB,$29FD,
  1517.     $3001..$3002,$3009,$300B,$300D,$300F,$3011,$3015,$3017,$3019,$301B,
  1518.     $301E..$301F,$FD3F,$FE36,$FE38,$FE3A,$FE3C,$FE3E,$FE40,$FE42,$FE44,
  1519.     $FE50,$FE52,$FE5A,$FE5C,$FE5E,$FF09,$FF0C,$FF0E,$FF3D,$FF5D,$FF60..$FF61,
  1520.     $FF63..$FF64:
  1521.       Result := rvu_lb_CL;
  1522.     $0030..$0039,$0660..$0669,$06F0..$06F9,$0966..$096F,$09E6..$09EF,
  1523.     $0A66..$0A6F,$0AE6..$0AEF,$0B66..$0B6F,$0BE7..$0BEF,$0C66..$0C6F,
  1524.     $0CE6..$0CEF,$0D66..$0D6F,$0E50..$0E59,$0ED0..$0ED9,$0F20..$0F29,
  1525.     $1040..$1049,$1369..$1371,$17E0..$17E9,$1810..$1819:
  1526.       Result := rvu_lb_NU;
  1527.     $0E5A..$0E5B,$17D4,$17D6..$17DA,$203C,$2044,$3005,$301C,$303B..$303C,
  1528.     $3041,$3043,$3045,$3047,$3049,$3063,$3083,$3085,$3087,$308E,$3095..$3096,
  1529.     $309B..$309E,$30A0..$30A1,$30A3,$30A5,$30A7,$30A9,$30C3,$30E3,$30E5,$30E7,
  1530.     $30EE,$30F5..$30F6,$30FB,$30FD,$31F0..$31FF,$FE54..$FE55,$FF1A..$FF1B,
  1531.     $FF65,$FF67..$FF70,$FF9E..$FF9F:
  1532.       Result := rvu_lb_NS;
  1533.     $1100..$1159,$115F,$2E80..$2E99,$2E9B..$2EF3,$2F00..$2FD5,$2FF0..$2FFB,
  1534.     $3000,$3003..$3004,$3006..$3007,$3012..$3013,$3020..$3029,$3030..$303A,
  1535.     $303D..$303F,$3042,$3044,$3046,$3048,$304A..$3062,$3064..$3082,$3084,
  1536.     $3086,$3088..$308D,$308F..$3094,$309F,$30A2,$30A4,$30A6,$30A8,$30AA..$30C2,
  1537.     $30C4..$30E2,$30E4,$30E6,$30E8..$30ED,$30EF..$30F4,$30F7..$30FA,$30FC,
  1538.     $30FE..$30FF,$3105..$312C,$3131..$318E,$3190..$31B7,$3200..$321C,
  1539.     $3220..$3243,$3251..$327B,$327F..$32CB,$32D0..$32FE,$3300..$3376,
  1540.     $337B..$33DD,$33E0..$33FE,$3400..$4DB5,$4E00..$9FA5,$A000..$A48C,
  1541.     $A490..$A4C6,$AC00..$D7A3,$F900..$FA2D,$FA30..$FA6A,$FE30..$FE34,
  1542.     $FE45..$FE46,$FE49..$FE4F,$FE51,$FE58,$FE5F..$FE66,$FE68,$FE6B,
  1543.     $FF02..$FF03,$FF06..$FF07,$FF0A..$FF0B,$FF0D,$FF0F..$FF19,$FF1C..$FF1E,
  1544.     $FF20..$FF3A,$FF3C,$FF3E..$FF5A,$FF5C,$FF5E,$FFE2..$FFE4:
  1545.       Result := rvu_lb_ID;
  1546.     $0000..$0008,$000B,$000E..$001F,$007F..$009F,$0300..$034F,$0360..$036F,
  1547.     $0483..$0486,$0488..$0489,$0591..$05A1,$05A3..$05B9,$05BB..$05BD,$05BF,
  1548.     $05C1..$05C2,$05C4,$064B..$0655,$0670,$06D6..$06E4,$06E7..$06E8,
  1549.     $06EA..$06ED,$070F,$0711,$0730..$074A,$07A6..$07B0,$0901..$0903,$093C,
  1550.     $093E..$094D,$0951..$0954,$0962..$0963,$0981..$0983,$09BC,$09BE..$09C4,
  1551.     $09C7..$09C8,$09CB..$09CD,$09D7,$09E2..$09E3,$0A02,$0A3C,$0A3E..$0A42,
  1552.     $0A47..$0A48,$0A4B..$0A4D,$0A70..$0A71,$0A81..$0A83,$0ABC,$0ABE..$0AC5,
  1553.     $0AC7..$0AC9,$0ACB..$0ACD,$0B01..$0B03,$0B3C,$0B3E..$0B43,$0B47..$0B48,
  1554.     $0B4B..$0B4D,$0B56..$0B57,$0B82,$0BBE..$0BC2,$0BC6..$0BC8,$0BCA..$0BCD,
  1555.     $0BD7,$0C01..$0C03,$0C3E..$0C44,$0C46..$0C48,$0C4A..$0C4D,$0C55..$0C56,
  1556.     $0C82..$0C83,$0CBE..$0CC4,$0CC6..$0CC8,$0CCA..$0CCD,$0CD5..$0CD6,
  1557.     $0D02..$0D03,$0D3E..$0D43,$0D46..$0D48,$0D4A..$0D4D,$0D57,$0D82..$0D83,
  1558.     $0DCA,$0DCF..$0DD4,$0DD6,$0DD8..$0DDF,$0DF2..$0DF3,$0E31,$0E34..$0E3A,
  1559.     $0E47..$0E4E,$0EB1,$0EB4..$0EB9,$0EBB..$0EBC,$0EC8..$0ECD,$0F18..$0F19,
  1560.     $0F35,$0F37,$0F39,$0F3E..$0F3F,$0F71..$0F84,$0F86..$0F87,$0F90..$0F97,
  1561.     $0F99..$0FBC,$0FC6,$102C..$1032,$1036..$1039,$1056..$1059,$1160..$11A2,
  1562.     $11A8..$11F9,$1712..$1714,$1732..$1734,$1752..$1753,$1772..$1773,
  1563.     $17B4..$17D3,$180B..$180E,$18A9,$200C..$200F,$202A..$202E,$206A..$206F,
  1564.     $20D0..$20EA,$302A..$302F,$3099..$309A,$FB1E,$FE00..$FE0F,$FE20..$FE23,
  1565.     $FFF9..$FFFB:
  1566.       Result := rvu_lb_CM;
  1567.     else
  1568.       Result := rvu_lb_AL;
  1569.   end;
  1570. end;
  1571. {$ENDIF}
  1572. {$IFNDEF RICHVIEWDEF6}
  1573. {$IFDEF RICHVIEWCBDEF3}
  1574. function Utf8ToUnicode(Dest: PWideChar; MaxDestChars: Cardinal;
  1575.   Source: PChar; SourceBytes: Cardinal): Cardinal;
  1576. var
  1577.   i, count: Cardinal;
  1578.   c: Byte;
  1579.   wc: Cardinal;
  1580. begin
  1581.   if Source = nil then
  1582.   begin
  1583.     Result := 0;
  1584.     Exit;
  1585.   end;
  1586.   Result := Cardinal(-1);
  1587.   count := 0;
  1588.   i := 0;
  1589.   if Dest <> nil then
  1590.   begin
  1591.     while (i < SourceBytes) and (count < MaxDestChars) do
  1592.     begin
  1593.       wc := Cardinal(Source[i]);
  1594.       Inc(i);
  1595.       if (wc and $80) <> 0 then
  1596.       begin
  1597.         if i >= SourceBytes then Exit;          // incomplete multibyte char
  1598.         wc := wc and $3F;
  1599.         if (wc and $20) <> 0 then
  1600.         begin
  1601.           c := Byte(Source[i]);
  1602.           Inc(i);
  1603.           if (c and $C0) <> $80 then Exit;      // malformed trail byte or out of range char
  1604.           if i >= SourceBytes then Exit;        // incomplete multibyte char
  1605.           wc := (wc shl 6) or (c and $3F);
  1606.         end;
  1607.         c := Byte(Source[i]);
  1608.         Inc(i);
  1609.         if (c and $C0) <> $80 then Exit;       // malformed trail byte
  1610.         Dest[count] := WideChar((wc shl 6) or (c and $3F));
  1611.       end
  1612.       else
  1613.         Dest[count] := WideChar(wc);
  1614.       Inc(count);
  1615.     end;
  1616.     if count >= MaxDestChars then count := MaxDestChars-1;
  1617.     Dest[count] := #0;
  1618.   end
  1619.   else
  1620.   begin
  1621.     while (i < SourceBytes) do
  1622.     begin
  1623.       c := Byte(Source[i]);
  1624.       Inc(i);
  1625.       if (c and $80) <> 0 then
  1626.       begin
  1627.         if i >= SourceBytes then Exit;          // incomplete multibyte char
  1628.         c := c and $3F;
  1629.         if (c and $20) <> 0 then
  1630.         begin
  1631.           c := Byte(Source[i]);
  1632.           Inc(i);
  1633.           if (c and $C0) <> $80 then Exit;      // malformed trail byte or out of range char
  1634.           if i >= SourceBytes then Exit;        // incomplete multibyte char
  1635.         end;
  1636.         c := Byte(Source[i]);
  1637.         Inc(i);
  1638.         if (c and $C0) <> $80 then Exit;       // malformed trail byte
  1639.       end;
  1640.       Inc(count);
  1641.     end;
  1642.   end;
  1643.   Result := count+1;
  1644. end;
  1645. function UnicodeToUtf8(Dest: PChar; MaxDestBytes: Cardinal; Source: PWideChar; SourceChars: Cardinal): Cardinal;
  1646. var
  1647.   i, count: Cardinal;
  1648.   c: Cardinal;
  1649. begin
  1650.   Result := 0;
  1651.   if Source = nil then Exit;
  1652.   count := 0;
  1653.   i := 0;
  1654.   if Dest <> nil then
  1655.   begin
  1656.     while (i < SourceChars) and (count < MaxDestBytes) do
  1657.     begin
  1658.       c := Cardinal(Source[i]);
  1659.       Inc(i);
  1660.       if c <= $7F then
  1661.       begin
  1662.         Dest[count] := Char(c);
  1663.         Inc(count);
  1664.       end
  1665.       else if c > $7FF then
  1666.       begin
  1667.         if count + 3 > MaxDestBytes then
  1668.           break;
  1669.         Dest[count] := Char($E0 or (c shr 12));
  1670.         Dest[count+1] := Char($80 or ((c shr 6) and $3F));
  1671.         Dest[count+2] := Char($80 or (c and $3F));
  1672.         Inc(count,3);
  1673.       end
  1674.       else //  $7F < Source[i] <= $7FF
  1675.       begin
  1676.         if count + 2 > MaxDestBytes then
  1677.           break;
  1678.         Dest[count] := Char($C0 or (c shr 6));
  1679.         Dest[count+1] := Char($80 or (c and $3F));
  1680.         Inc(count,2);
  1681.       end;
  1682.     end;
  1683.     if count >= MaxDestBytes then count := MaxDestBytes-1;
  1684.     Dest[count] := #0;
  1685.   end
  1686.   else
  1687.   begin
  1688.     while i < SourceChars do
  1689.     begin
  1690.       c := Integer(Source[i]);
  1691.       Inc(i);
  1692.       if c > $7F then
  1693.       begin
  1694.         if c > $7FF then
  1695.           Inc(count);
  1696.         Inc(count);
  1697.       end;
  1698.       Inc(count);
  1699.     end;
  1700.   end;
  1701.   Result := count+1;  // convert zero based index to byte count
  1702. end;
  1703. function Utf8Decode(const S: String): WideString;
  1704. var
  1705.   L: Integer;
  1706.   Temp: WideString;
  1707. begin
  1708.   Result := '';
  1709.   if S = '' then Exit;
  1710.   SetLength(Temp, Length(S));
  1711.   L := Utf8ToUnicode(PWideChar(Temp), Length(Temp)+1, PChar(S), Length(S));
  1712.   if L > 0 then
  1713.     SetLength(Temp, L-1)
  1714.   else
  1715.     Temp := '';
  1716.   Result := Temp;
  1717. end;
  1718. function Utf8Encode(const WS: WideString): String;
  1719. var
  1720.   L: Integer;
  1721.   Temp: String;
  1722. begin
  1723.   Result := '';
  1724.   if WS = '' then Exit;
  1725.   SetLength(Temp, Length(WS) * 3); // SetLength includes space for null terminator
  1726.   L := UnicodeToUtf8(PChar(Temp), Length(Temp)+1, PWideChar(WS), Length(WS));
  1727.   if L > 0 then
  1728.     SetLength(Temp, L-1)
  1729.   else
  1730.     Temp := '';
  1731.   Result := Temp;
  1732. end;
  1733. {$ENDIF}
  1734. {$ENDIF}
  1735. {
  1736. type TRVBiDiClass =
  1737.  (
  1738.    rvu_bd_BN,  // Boundary neutral (type of RLE etc after explicit levels)
  1739.    rvu_bd_S,   // Segment Separator (TAB)
  1740.    rvu_bd_B,   // Paragraph Separator
  1741.    rvu_bd_WS,  // White space
  1742.    rvu_bd_ON,  // Other Neutral
  1743.    rvu_bd_ET,  // European Terminator (post/prefix e.g. $ and %)
  1744.    rvu_bd_CS,  // Common Separator
  1745.    rvu_bd_ES,  // European Separator
  1746.    rvu_bd_EN,  // European Number
  1747.    rvu_bd_L,   // Left Letter
  1748.    rvu_bd_NSM, // Non-spacing Mark
  1749.    rvu_bd_R,   // Right Letter
  1750.    rvu_bd_AL,  // Arabic Letter (Right-to-left)
  1751.    rvu_bd_AN,  // Arabic Number
  1752.    rvu_bd_LRE,
  1753.    rvu_bd_RLE,
  1754.    rvu_bd_RLE,
  1755.    rvu_bd_PDF,
  1756.    rvu_bd_LRO,
  1757.    rvu_bd_RLO
  1758.  );
  1759. function GetBiDiClass(chr: WideChar): TRVBiDiClass;
  1760. begin
  1761.   case ord(chr) of
  1762.     $0000..$0008,$000E..$001B,$007F..$0084,$0086..$009F,$070F,$180B..$180E,
  1763.     $200B..$200D,$206A..$206F,$FEFF,$FFF9..$FFFB:
  1764.       Result := rvu_bd_BN;
  1765.     $0009,$000B,$001F:
  1766.       Result := rvu_bd_S;
  1767.     $000A,$000D,$001C..$001E,$0085,$2029:
  1768.       Result := rvu_bd_B
  1769.     $000C,$0020,$1680,$2000..$200A,$2028,$202F,$3000:
  1770.       Result := rvu_bd_WS
  1771.     $0021..$0022,$0026..$002A,$003B..$0040,$005B..$0060,$007B..$007E,$00A1,
  1772.     $00A6..$00A9,$00AB..$00AF,$00B4,$00B6..$00B8,$00BB..$00BF,$00D7,$00F7,
  1773.     $02B9..$02BA,$02C2..$02CF,$02D2..$02DF,$02E5..$02ED,$0374..$0375,
  1774.     $037E..$0385,$0387,$058A,$06E9,$0F3A..$0F3D,$169B..$169C,$1800..$180A,
  1775.     $1FBD,$1FBF..$1FC1,$1FCD..$1FCF,$1FDD..$1FDF,$1FED..$1FEF,$1FFD..$1FFE,
  1776.     $2010..$2027,$2035..$204D,$207C..$207E,$208C..$208E,$2100..$2101,
  1777.     $2103..$2106,$2108..$2109,$2114,$2116..$2118,$211E..$2123,$2125,$2127,$2129,
  1778.     $2132,$213A..$215F,$2190..$2211,$2214..$2335,$237B..$2394,$2396..$244A,
  1779.     $2500..$2FFB,$3001..$3004,$3008..$3020,$3030,$3036..$3037,$303E..$303F,
  1780.     $309B..$309C,$30FB,$A490..$A4C6,$FD3E..$FD3F,$FE30..$FE4F,$FE51,$FE54,
  1781.     $FE56..$FE5E,$FE60..$FE61,$FE64..$FE68,$FE6B,$FF01..$FF02,$FF06..$FF0A,
  1782.     $FF1B..$FF20,$FF3B..$FF40,$FF5B..$FF65,$FFE2..$FFE4,$FFE8..$FFEE,
  1783.     $FFFC..$FFFD:
  1784.       Result := rvu_bd_ON;
  1785.     $0023..$0025,$002B,$002D,$00A2..$00A5,$00B0..$00B1,$066A,$09F2..$09F3,$0E3F,
  1786.     $17DB,$2030..$2034,$207A..$207B,$208A..$208B,$20A0..$20AF,$212E,
  1787.     $2212..$2213,$FB29,$FE5F,$FE62..$FE63,$FE69..$FE6A,$FF03..$FF05,
  1788.     $FF0B,$FF0D,$FFE0..$FFE1,$FFE5..$FFE6:
  1789.       Result := rvu_bd_ET;
  1790.     $002C,$002E,$003A,$00A0,$060C,$FE50,$FE52,$FE55,$FF0C,$FF0E,$FF1A:
  1791.       Result := rvu_bd_CS;
  1792.     $002F,$FF0F:
  1793.       Result := rvu_bd_ES;
  1794.     $0030..$0039,$00B2..$00B3,$00B9,$06F0..$06F9,$2070..$2079,$2080..$2089,
  1795.     $2460..$249B,$24EA,$FF10..$FF19:
  1796.       Result := rvu_bd_EN;
  1797.     $0300..$0362,$0483..$0489,$0591..$05BD,$05BF,$05C1..$05C2,$05C4,
  1798.     $064B..$0655,$0670,$06D6..$06E4,$06E7..$06E8,$06EA..$06ED,$0711,
  1799.     $0730..$074A,$07A6..$0902,$093C,$0941..$0948,$094D,$0951..$0954,
  1800.     $0962..$0963,$0981,$09BC,$09C1..$09C4,$09CD,$09E2..$09E3,$0A02,$0A3C,
  1801.     $0A41..$0A4D,$0A70..$0A71,$0A81..$0A82,$0ABC,$0AC1..$0AC8,$0ACD,$0B01,$0B3C,
  1802.     $0B3F,$0B41..$0B43,$0B4D..$0B56,$0B82,$0BC0,$0BCD,$0C3E..$0C40,$0C46..$0C56,
  1803.     $0CBF,$0CC6,$0CCC..$0CCD,$0D41..$0D43,$0D4D,$0DCA,$0DD2..$0DD6,$0E31,
  1804.     $0E34..$0E3A,$0E47..$0E4E,$0EB1,$0EB4..$0EBC,$0EC8..$0ECD,$0F18..$0F19,
  1805.     $0F35,$0F37,$0F39,$0F71..$0F7E,$0F80..$0F84,$0F86..$0F87,$0F90..$0FBC,$0FC6,
  1806.     $102D..$1030,$1032..$1037,$1039,$1058..$1059,$17B7..$17BD,$17C6,
  1807.     $17C9..$17D3,$18A9,$20D0..$20E3,$302A..$302F,$3099..$309A,$FB1E,
  1808.     $FE20..$FE23:
  1809.       Result := rvu_bd_NSM;
  1810.     $05BE,$05C0,$05C3,$05D0..$05F4,$200F,$FB1D,$FB1F..$FB28,$FB2A..$FB4F:
  1811.       Result := rvu_bd_R;
  1812.     $061B..$064A,$066D,$0671..$06D5,$06E5..$06E6,$06FA..$070D,$0710,
  1813.     $0712..$072C,$0780..$07A5,$FB50..$FD3D,$FD50..$FDFB,$FE70..$FEFC:
  1814.       Result := rvu_bd_AL;
  1815.     $0660..$0669,$066B..$066C:
  1816.       Result := rvu_bd_AN;
  1817.     $202A:
  1818.       Result := rvu_bd_LRE;
  1819.     $202B:
  1820.       Result := rvu_bd_RLE;
  1821.     $202C:
  1822.       Result := rvu_bd_PDF;
  1823.     $202D:
  1824.       Result := rvu_bd_LRO;
  1825.     $202E:
  1826.       Result := rvu_bd_RLO;
  1827.     else
  1828.       Result :=  rvu_bd_L;
  1829.   end;
  1830. end;
  1831. }
  1832. initialization
  1833.   RVCheckNT
  1834. end.