diff options
author | Abou Al Montacir <abou.almontacir@sfr.fr> | 2013-10-14 18:34:04 +0200 |
---|---|---|
committer | Abou Al Montacir <abou.almontacir@sfr.fr> | 2013-10-14 18:34:04 +0200 |
commit | e613d5c357aebc41ca83e7e3beea3441e61299af (patch) | |
tree | d75f294045eb040eda0a17671995bd6492a4e37a /fpcsrc/rtl/objpas/freebidi.pp | |
parent | e36b5ea6c1e2551c5bad449e6b729d8ee195d62d (diff) | |
download | fpc-e613d5c357aebc41ca83e7e3beea3441e61299af.tar.gz |
Imported Upstream version 2.6.2upstream/2.6.2
Diffstat (limited to 'fpcsrc/rtl/objpas/freebidi.pp')
-rw-r--r-- | fpcsrc/rtl/objpas/freebidi.pp | 336 |
1 files changed, 336 insertions, 0 deletions
diff --git a/fpcsrc/rtl/objpas/freebidi.pp b/fpcsrc/rtl/objpas/freebidi.pp new file mode 100644 index 00000000..df36376d --- /dev/null +++ b/fpcsrc/rtl/objpas/freebidi.pp @@ -0,0 +1,336 @@ +{ +Author Mazen NEIFER +Licence LGPL +} +unit FreeBIDI; + +{$mode objfpc}{$H+} + +interface + +type + TCharacter = WideChar; + TString = WideString; + TDirection=( + drNONE, + drRTL, + drLTR + ); + TVisualToLogical = Array[Byte]Of Byte; + TFontInfoPtr = Pointer; + TCharWidthRoutine = function(Character:TCharacter;FontInfo:TFontInfoPtr):Integer; + +var + FontInfoPtr:TFontInfoPtr; + CharWidth:TCharWidthRoutine; + +{****************************Logical aspects***********************************} +{Returns the number of logical characters} +function LLength(const Src:TString):Cardinal; +{Converts visual position to logical position} +function LPos(const Src:TString; vp:Integer; pDir:TDirection):Cardinal; +{****************************Visual aspects************************************} +{Returns the number of visual characters} +function VLength(const Src:TString; pDir:TDirection):Cardinal; +{Converts a logical position to a visual position} +function VPos(const Src:TString; lp:Integer; pDir, cDir:TDirection):Cardinal; +function VPos(UTF8Char:PChar; Len:integer; BytePos:integer):Cardinal; +{Returns character at a given visual position according to paragraph direction} +function VCharOf(Src:TString; vp:Integer; dir:TDirection):TCharacter; +{Inserts a string into another paying attention of RTL/LTR direction} +procedure VInsert(const Src:TString; var Dest:TString; vp:Integer; pDir:TDirection); +{Deletes a string into another paying attention of RTL/LTR direction} +procedure VDelete(var str:TString; vp, len:Integer; pDir:TDirection); +{Resturns a sub string of source string} +//function VCopy(const Src:TString; vStart, vWidth:Integer):TString; +{Resturns the visual image of current string} +function VStr(const Src:TString; pDir:TDirection):TString; +{****************************Helper routines***********************************} +{Returns direction of a character} +function DirectionOf(Character:TCharacter):TDirection; +{Returns contextual direction of caracter in a string} +function DirectionOf(Src:TString; lp:Integer; pDir:TDirection):TDirection; +{Inserts a char as if it was typed using keyboard in the most user friendly way. +Returns the new cursor position after insersion depending on the new visual text} +function InsertChar(Src:TCharacter; var Dest:TString; vp:Integer; pDir:TDirection):Integer; +{Returns a table mapping each visual position to its logical position in an UTF8* +string} +function VisualToLogical(const Src:TString; pDir:TDirection):TVisualToLogical; + +implementation + +function DefaultCharWidth(Character:TCharacter; FontInfoPtr:TFontInfoPtr):Integer; +begin + case Character of + #9: + Result := 8; + else + Result := 1; + end; +end; +function DumpStr(const Src:TString):String; +var + i:Integer; +begin + Result := ''; + for i:= 1 to Length(Src) do + case Src[i] of + #0..#127: + Result := Result + Src[i]; + else + Result := Result + '$' + HexStr(Ord(Src[i]),4); + end; +end; +function ComputeCharLength(p:PChar):Cardinal; +begin + if ord(p^)<%11000000 + then +{regular single byte character (#0 is a normal char, this is UTF8Charascal ;)} + Result:=1 + else if ((ord(p^) and %11100000) = %11000000) + then + if (ord(p[1]) and %11000000) = %10000000 then + Result:=2 + else + Result:=1 + else if ((ord(p^) and %11110000) = %11100000) + then + if ((ord(p[1]) and %11000000) = %10000000) + and ((ord(p[2]) and %11000000) = %10000000) + then + Result:=3 + else + Result:=1 + else if ((ord(p^) and %11111000) = %11110000) + then + if ((ord(p[1]) and %11000000) = %10000000) + and ((ord(p[2]) and %11000000) = %10000000) + and ((ord(p[3]) and %11000000) = %10000000) + then + Result:=4 + else + Result:=1 + else + Result:=1 +end; + +{****************************Logical aspects***********************************} +function LLength(const Src:TString):Cardinal; +begin + Result := Length(Src); +end; + +function LPos(const Src:TString; vp:Integer; pDir:TDirection):Cardinal; +var + v2l:TVisualToLogical; + i:integer; +begin + v2l := VisualToLogical(Src, pDir); + if vp <= v2l[0] + then + Result := v2l[vp] + else + Result := Length(Src) + 1; +end; + +{****************************Visual aspects************************************} +function VLength(const Src:TString; pDir:TDirection):Cardinal; +var + Count:Integer; +begin + Result := 0; + Count := Length(Src); + while (Count > 0) do + begin + Result := Result + CharWidth(Src[Count], FontInfoPtr); + Count := Count - 1; + end; +end; + +function VPos(const Src:TString; lp:Integer; pDir, cDir:TDirection):Cardinal; +var + v2l:TVisualToLogical; + vp:Integer; +begin + v2l := VisualToLogical(Src, pDir); + for vp := 1 to v2l[0] do + if lp = v2l[vp] + then + begin + Exit(vp); + end; + Result := v2l[0]; +end; + +function VPos(UTF8Char:PChar; Len:integer; BytePos:integer):Cardinal; +begin +end; + + +function VCharOf(Src:TString; vp:Integer; dir:TDirection):TCharacter; +var + CharLen: LongInt; +begin + Result := Src[LPos(Src, vp, dir)]; +end; + +{****************************Helper routines***********************************} +function DirectionOf(Character:TCharacter):TDirection; +begin + case Character of + #9,#32, + '/', + '{','}', + '[',']', + '(',')': + Result := drNONE; + #$0590..#$05FF, //Hebrew + #$0600..#$06FF: //Arabic + Result := drRTL; + else + Result := drLTR; + end; +end; + +function DirectionOf(Src:TString; lp:Integer; pDir:TDirection):TDirection; +var + c:TCharacter; + lDir,rDir:TDirection; + p:Integer; +begin + if(lp <= 0) + then + lp := 1; +{Seek for proper character direction} + c := Src[lp]; + lDir := DirectionOf(c); +{Seek for left character direction if it is neutral} + p := lp; + while(p > 1) and (lDir = drNONE)do + begin + c := Src[p - 1]; + lDir := DirectionOf(c); + p := p - Length(c); + end; +{Seek for right character direction if it is neutral} + p := lp; + repeat + c := Src[p]; + rDir := DirectionOf(c); + p := p + Length(c); + until(p > Length(Src)) or (rDir <> drNONE); + if(lDir = rDir) + then + Result := rDir + else + Result := pDir; +end; + +function VisualToLogical(const Src:TString; pDir:TDirection):TVisualToLogical; + procedure Insert(value:Byte; var v2l:TVisualToLogical; InsPos:Byte); + var + l:Byte; + begin + if v2l[0] < 255 + then + Inc(InsPos); + if InsPos > v2l[0] + then + InsPos := v2l[0]; + for l := v2l[0] downto InsPos do + v2l[l] := v2l[l-1]; + v2l[InsPos] := Value; + end; +var + lp, vp : Integer; + cDir,lDir:TDirection; + Character:TCharacter; +i:Integer; +begin + Result[0] := 0; + lp := 1; + vp := 1; + lDir := drNONE; + while lp <= Length(Src) do + begin + Character := Src[lp]; + cDir := DirectionOf(Src, lp, pDir); + Inc(Result[0]); + case cDir of + drRTL: + begin + lDir := drRTL; + end; + drLTR: + begin + lDir := drLTR; + vp := Result[0]; + end; + else + vp := Result[0]; + end; + Insert(lp, Result, vp); + lp := lp + 1; + end; +end; + +function InsertChar(Src:TCharacter; var Dest:TString; vp:Integer; pDir:TDirection):Integer; +var + vSrc,vDest:TString; +begin + vSrc := VStr(Src,pDir); + vDest := VStr(Dest,pDir); + Insert(vSrc, vDest, vp); + Dest := VStr(vDest, pDir); + case DirectionOf(Src) of + drRTL: + Result := vp; + drLTR: + Result := vp + 1; + else + if(vp < Length(vDest)) and (DirectionOf(vDest[vp + 1]) = drRTL) + then + Result := vp + else + Result := vp + 1; + end; +end; + +procedure VInsert(const Src:TString;var Dest:TString; vp:Integer; pDir:TDirection); +var + vSrc,vDest:TString; +begin + vSrc := VStr(Src,pDir); + vDest := VStr(Dest,pDir); + Insert(vSrc, vDest, vp); + Dest := VStr(vDest, pDir); +end; + +procedure VDelete(var str:TString; vp, len:Integer; pDir:TDirection); +var + v2l:TVisualToLogical; + i:Integer; +begin + v2l := VisualToLogical(str, pDir); + for i := 1 to v2l[0] do + if(v2l[i] >= vp) and (v2l[i] < vp + len) + then + Delete(str, v2l[i], 1); +end; + +function VStr(const Src:TString; pDir:TDirection):TString; +var + v2lSrc:TVisualToLogical; + vp:Integer; +begin + v2lSrc := VisualToLogical(Src,pDir); + SetLength(Result, v2lSrc[0]); + for vp := 1 to v2lSrc[0] do + Result[vp] := Src[v2lSrc[vp]]; +end; + +initialization + + CharWidth := @DefaultCharWidth; + +end. |