On Tue 4 Oct 2011, michael.vancann...@wisa.be wrote: > If you need some UTF8 extensions to the freetype unit, feel free to make > some suggestions, and we'll see what we can do. > > When the unit was made, unicode support was a thing of the distant future. > (a future which of course crept up on us faster than we imagined)
attached is a patch, which (if applied correctly...) seems to work, yay! Here is a picture: http://david9.freepgs.com/i/spline-unicode-text.png I copied a few UTF8 string functions from the LCLProc unit, so that is kind of sloppy but there it is. I'm not sure if analogs exist within fpc. Surprisingly little needed to be changed!
diff --git a/packages/fcl-image/src/freetype.pp b/packages/fcl-image/src/freetype.pp index 92ba876..4a17dae 100644 --- a/packages/fcl-image/src/freetype.pp +++ b/packages/fcl-image/src/freetype.pp @@ -36,6 +36,7 @@ uses sysutils, classes, freetypeh, FPImgCmn; {$endif} type + chartype = cardinal; FreeTypeException = class (exception); @@ -71,7 +72,7 @@ type PMgrGlyph = ^TMgrGlyph; TMgrGlyph = record - Character : char; + Character : chartype; GlyphIndex : FT_UInt; Glyph : PFT_Glyph; end; @@ -117,8 +118,8 @@ type procedure GetSize (aSize, aResolution : integer); function CreateSize (aSize, aResolution : integer) : PMgrSize; procedure SetPixelSize (aSize, aResolution : integer); - function GetGlyph (c : char) : PMgrGlyph; - function CreateGlyph (c : char) : PMgrGlyph; + function GetGlyph (c : chartype) : PMgrGlyph; + function CreateGlyph (c : chartype) : PMgrGlyph; procedure MakeTransformation (angle:real; out Transformation:FT_Matrix); procedure InitMakeString (FontID, Size:integer); function MakeString (FontId:integer; Text:string; size:integer; angle:real) : TStringBitmaps; @@ -526,13 +527,13 @@ begin end; end; -function TFontManager.CreateGlyph (c : char) : PMgrGlyph; +function TFontManager.CreateGlyph (c : chartype) : PMgrGlyph; var e : integer; begin new (result); FillByte(Result^,SizeOf(Result),0); result^.character := c; - result^.GlyphIndex := FT_Get_Char_Index (CurFont.font, ord(c)); + result^.GlyphIndex := FT_Get_Char_Index (CurFont.font, c); //WriteFT_Face(CurFont.Font); e := FT_Load_Glyph (CurFont.font, result^.GlyphIndex, FT_Load_Default); if e <> 0 then @@ -547,7 +548,7 @@ begin CurSize^.Glyphs.Add (result); end; -function TFontManager.GetGlyph (c : char) : PMgrGlyph; +function TFontManager.GetGlyph (c : chartype) : PMgrGlyph; var r : integer; begin With CurSize^ do @@ -569,11 +570,126 @@ begin UseKerning := ((Curfont.font^.face_flags and FT_FACE_FLAG_KERNING) <> 0); end; +function UTF8CharacterLength(p: PChar): integer; +begin + if p<>nil then begin + if ord(p^)<%11000000 then begin + // regular single byte character (#0 is a character, this is pascal ;) + Result:=1; + end + else if ((ord(p^) and %11100000) = %11000000) then begin + // could be 2 byte character + if (ord(p[1]) and %11000000) = %10000000 then + Result:=2 + else + Result:=1; + end + else if ((ord(p^) and %11110000) = %11100000) then begin + // could be 3 byte character + if ((ord(p[1]) and %11000000) = %10000000) + and ((ord(p[2]) and %11000000) = %10000000) then + Result:=3 + else + Result:=1; + end + else if ((ord(p^) and %11111000) = %11110000) then begin + // could be 4 byte character + 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; + end + else + Result:=1 + end else + Result:=0; +end; + +function UTF8Length(p: PChar; ByteCount: PtrInt): PtrInt; +var + CharLen: LongInt; +begin + Result:=0; + while (ByteCount>0) do begin + inc(Result); + CharLen:=UTF8CharacterLength(p); + inc(p,CharLen); + dec(ByteCount,CharLen); + end; +end; + +function UTF8Length(const s: string): PtrInt; +begin + Result:=UTF8Length(PChar(s),length(s)); +end; + +function UTF8CharacterToUnicode(p: PChar; out CharLen: integer): Cardinal; +begin + if p<>nil then begin + if ord(p^)<%11000000 then begin + // regular single byte character (#0 is a normal char, this is pascal ;) + Result:=ord(p^); + CharLen:=1; + end + else if ((ord(p^) and %11100000) = %11000000) then begin + // could be double byte character + if (ord(p[1]) and %11000000) = %10000000 then begin + Result:=((ord(p^) and %00011111) shl 6) + or (ord(p[1]) and %00111111); + CharLen:=2; + end else begin + Result:=ord(p^); + CharLen:=1; + end; + end + else if ((ord(p^) and %11110000) = %11100000) then begin + // could be triple byte character + if ((ord(p[1]) and %11000000) = %10000000) + and ((ord(p[2]) and %11000000) = %10000000) then begin + Result:=((ord(p^) and %00011111) shl 12) + or ((ord(p[1]) and %00111111) shl 6) + or (ord(p[2]) and %00111111); + CharLen:=3; + end else begin + Result:=ord(p^); + CharLen:=1; + end; + end + else if ((ord(p^) and %11111000) = %11110000) then begin + // could be 4 byte character + if ((ord(p[1]) and %11000000) = %10000000) + and ((ord(p[2]) and %11000000) = %10000000) + and ((ord(p[3]) and %11000000) = %10000000) then begin + Result:=((ord(p^) and %00001111) shl 18) + or ((ord(p[1]) and %00111111) shl 12) + or ((ord(p[2]) and %00111111) shl 6) + or (ord(p[3]) and %00111111); + CharLen:=4; + end else begin + Result:=ord(p^); + CharLen:=1; + end; + end + else begin + // invalid character + Result:=ord(p^); + CharLen:=1; + end; + end else begin + Result:=0; + CharLen:=0; + end; +end; + function TFontManager.MakeString (FontId:integer; Text:string; size:integer; angle:real) : TStringBitmaps; var g : PMgrGlyph; bm : PFT_BitmapGlyph; gl : PFT_Glyph; - prevIndex, prevx, c, r, rx : integer; + prevIndex, prevx, c, r, rx, cl : integer; + uc : chartype; + pc : pchar; pre, adv, pos, kern : FT_Vector; buf : PByteArray; reverse : boolean; @@ -586,7 +702,7 @@ begin else begin InitMakeString (FontID, Size); - c := length(text); + c := utf8length(text); result := TStringBitmaps.Create(c); if (CurRenderMode = FT_RENDER_MODE_MONO) then result.FMode := btBlackWhite @@ -599,10 +715,16 @@ begin pos.y := 0; pre.x := 0; pre.y := 0; - for r := 0 to c-1 do - begin + pc := pchar(text); + r := -1; + // get the unicode for the character. Also performed at the end of the while loop. + uc := UTF8CharacterToUnicode (pc, cl); + while (uc>0) and (cl>0) do begin // retrieve loaded glyph - g := GetGlyph (Text[r+1]); + g := GetGlyph (uc); + // increment pchar by character length + inc (pc, cl); + inc (r); // check kerning if UseKerning and (g^.glyphindex <>0) and (PrevIndex <> 0) then begin @@ -665,7 +787,9 @@ begin pre.x := prevx; // finish rendered glyph FT_Done_Glyph (gl); - end; + // Get the next unicode + uc := UTF8CharacterToUnicode (pc, cl); + end; result.FText := Text; result.CalculateGlobals; end; @@ -675,15 +799,16 @@ function TFontManager.MakeString (FontId:integer; Text:string; Size:integer) : T var g : PMgrGlyph; bm : PFT_BitmapGlyph; gl : PFT_Glyph; - e, prevIndex, prevx, c, r, rx : integer; + e, prevIndex, prevx, r, rx, cl : integer; + uc : chartype; + pc : pchar; pos, kern : FT_Vector; buf : PByteArray; reverse : boolean; begin CurFont := GetFont(FontID); InitMakeString (FontID, Size); - c := length(text); - result := TStringBitmaps.Create(c); + result := TStringBitmaps.Create(utf8length(text)); if (CurRenderMode = FT_RENDER_MODE_MONO) then result.FMode := btBlackWhite else @@ -692,10 +817,16 @@ begin prevx := 0; pos.x := 0; pos.y := 0; - for r := 0 to c-1 do - begin + pc := pchar(text); + r := -1; + // get the unicode for the character. Also performed at the end of the while loop. + uc := UTF8CharacterToUnicode (pc, cl); + while (cl>0) and (uc>0) do begin // retrieve loaded glyph - g := GetGlyph (Text[r+1]); + g := GetGlyph (uc); + // increment pchar by character length + inc (pc, cl); + inc (r); // check kerning if UseKerning and (g^.glyphindex <>0) and (PrevIndex <> 0) then begin @@ -751,7 +882,9 @@ begin pos.x := prevx; // finish rendered glyph FT_Done_Glyph (gl); - end; + // Get the next unicode + uc := UTF8CharacterToUnicode (pc, cl); + end; // while result.FText := Text; result.CalculateGlobals; end;
_______________________________________________ fpc-pascal maillist - fpc-pascal@lists.freepascal.org http://lists.freepascal.org/mailman/listinfo/fpc-pascal