{******************************************} { } { FastReport FMX v2.0 } { Font parser } { } { Copyright (c) 1998-2013 } { by Aleksey Mandrykin, } { Fast Reports Inc. } { } {******************************************} unit FMX.frxGlyphTableClass; {$HINTS OFF} interface uses FMX.TTFHelpers, System.Classes, FMX.frxTrueTypeTable; type // Nested Types TIntegerList = TList; CompositeFlags = (ARG_1_AND_2_ARE_WORDS=1, ARGS_ARE_XY_VALUES=2, MORE_COMPONENTS=$20, OVERLAP_COMPOUND=$400, RESERVED=$10, ROUND_XY_TO_GRID=4, SCALED_COMPONENT_OFFSET=$800, UNSCALED_COMPONENT_OFFSET=$10000, USE_MY_METRICS=$200, WE_HAVE_A_SCALE=8, WE_HAVE_A_TWO_BY_TWO=$80, WE_HAVE_AN_X_AND_Y_SCALE=$40, WE_HAVE_INSTRUCTIONS=$100); GlyphFlags = (ON_CURVE=1, REP=8, X_POSITIVE=$10, X_SAME=$10, X_SHORT=2, Y_POSITIVE=$20, Y_SAME=$20, Y_SHORT=4); CompositeGlyphHeader = packed record public flags: Word; public glyphIndex: Word; end; GlyphHeader = packed record public numberOfContours: Smallint; public xMin: Smallint; public yMin: Smallint; public xMax: Smallint; public yMax: Smallint; end; GlyphTableClass = class(TrueTypeTable) strict private glyph_table_ptr: Pointer; // Methods public constructor Create(src: TrueTypeTable); { strict private procedure AddSpline(path: GraphicsPath; pntStart: PointF; pntB: PointF; pntEnd: PointF; position: Point); private function GetGlyph(glyph_offset: Integer; glyph_data_size: Integer; font_rsize: Single; position: Point; [Out] var gheader: GlyphHeader): GraphicsPath; } public function CheckGlyph(glyph_offset: Integer; glyph_size: Integer): TIntegerList; private function GetGlyphHeader(glyph_offset: Integer): GlyphHeader; public procedure Load(font: Pointer); override; strict private function ReadRawByte(ptr: Pointer; var val: Byte): Pointer; end; GlyphPoint = class // Properties // public property Point: TPointF read get_Point; // Fields public end_of_contour: boolean; public on_curve: boolean; public x: Single; public y: Single; end; implementation //function GlyphPoint.get_Point: TPointF; //begin // Result := PointF(x, y); //end; // Methods constructor GlyphTableClass.Create(src: TrueTypeTable); begin inherited Create(src); end; { procedure GlyphTableClass.AddSpline(path: GraphicsPath; pntStart: PointF; pntB: PointF; pntEnd: PointF; position: Point); begin pnt1 := pntStart; inc(pnt1.X, (0.6666667 * (pntB.X - pntStart.X))); inc(pnt1.Y, (0.6666667 * (pntB.Y - pntStart.Y))); pnt2 := pntB; inc(pnt2.X, ((pntEnd.X - pntB.X) div 3)); inc(pnt2.Y, ((pntEnd.Y - pntB.Y) div 3)); path.AddBezier(pntStart, pnt1, pnt2, pntEnd) end; } function GlyphTableClass.CheckGlyph(glyph_offset: Integer; glyph_size: Integer): TIntegerlist; var gheader: GlyphHeader; pcgh: ^CompositeGlyphHeader; cgh: CompositeGlyphHeader; CompositeIndexes: TIntegerlist; glyph_ptr: Pointer; composite_header_ptr: Pointer; num_instr: Integer; pword: ^Word; begin CompositeIndexes := TIntegerlist.Create; gheader := self.GetGlyphHeader(glyph_offset); glyph_ptr := TTF_Helpers.Increment(self.glyph_table_ptr, glyph_offset); if (gheader.numberOfContours < 0) then begin composite_header_ptr := TTF_Helpers.Increment(glyph_ptr, SizeOf(GlyphHeader)); repeat pcgh := composite_header_ptr; cgh.flags := TTF_Helpers.SwapUInt16(pcgh.flags); cgh.glyphIndex := TTF_Helpers.SwapUInt16(pcgh.glyphIndex); CompositeIndexes.Add( Pointer(cgh.glyphIndex) ); // Skip composite_header_ptr := TTF_Helpers.Increment(composite_header_ptr, SizeOf(CompositeGlyphHeader)); if ((cgh.flags and 1) <> 0) then composite_header_ptr := TTF_Helpers.Increment(composite_header_ptr, 4) else composite_header_ptr := TTF_Helpers.Increment(composite_header_ptr, 2); if ((cgh.flags and 8) <> 0) then composite_header_ptr := TTF_Helpers.Increment(composite_header_ptr, 2) else if ((cgh.flags and $40) <> 0) then composite_header_ptr := TTF_Helpers.Increment(composite_header_ptr, 4) else if ((cgh.flags and $80) <> 0) then composite_header_ptr := TTF_Helpers.Increment(composite_header_ptr, 8) until ((cgh.flags and $20) = 0); if ((cgh.flags and $100) <> 0) then begin pword := composite_header_ptr; num_instr := TTF_Helpers.SwapUInt16( pword^ ); composite_header_ptr := TTF_Helpers.Increment(composite_header_ptr, (2 + num_instr)) end end; Result := CompositeIndexes; exit end; { function GlyphTableClass.GetGlyph(glyph_offset: Integer; glyph_data_size: Integer; font_rsize: Single; position: Point; [Out] var gheader: GlyphHeader): GraphicsPath; var i: Integer; val: Byte; sign: boolean; &end: PointF; next: PointF; implied: PointF; next_on_curve: boolean; begin glyph_ptr := TTF_Helpers.Increment(self.glyph_table_ptr, glyph_offset); gheader := (Marshal.PtrToStructure(glyph_ptr, typeof(GlyphHeader)) as GlyphHeader); gheader.numberOfContours := TTF_Helpers.SwapInt16(gheader.numberOfContours); gheader.xMax := TTF_Helpers.SwapInt16(gheader.xMax); gheader.yMax := TTF_Helpers.SwapInt16(gheader.yMax); gheader.xMin := TTF_Helpers.SwapInt16(gheader.xMin); gheader.yMin := TTF_Helpers.SwapInt16(gheader.yMin); endPtsOfContours := New(array[gheader.numberOfContours] of Word); ptr := TTF_Helpers.Increment(glyph_ptr, Marshal.SizeOf((gheader as GlyphHeader))); i := 0; while ((i < endPtsOfContours.Length)) do begin endPtsOfContours[i] := TTF_Helpers.SwapUInt16((Marshal.PtrToStructure(ptr, typeof(Word)) as Word)); ptr := TTF_Helpers.Increment(ptr, 2); inc(i) end; instructions_count := TTF_Helpers.SwapUInt16((Marshal.PtrToStructure(ptr, typeof(Word)) as Word)); ptr := TTF_Helpers.Increment(ptr, 2); instructions := New(array[instructions_count] of Byte); Marshal.Copy(ptr, instructions, 0, instructions.Length); ptr := TTF_Helpers.Increment(ptr, instructions.Length); number_of_points := (endPtsOfContours[(endPtsOfContours.Length - 1)] + 1); flags := New(array[number_of_points] of Byte); points := New(array[number_of_points] of GlyphPoint); repeatCount := 0; repeatFlag := 0; i := 0; while ((i < number_of_points)) do begin if (repeatCount > 0) then begin flags[i] := repeatFlag; repeatCount := ((repeatCount - 1) as Byte) end else begin ptr := self.ReadRawByte(ptr, @(flags[i])); if ((flags[i] and 8) <> 0) then begin ptr := self.ReadRawByte(ptr, @(repeatCount)); repeatFlag := flags[i] end end; points[i] := GlyphPoint.Create; points[i].on_curve := ((flags[i] and 1) <> 0); inc(i) end; i := 0; while ((i < endPtsOfContours.Length)) do begin points[endPtsOfContours[i]].end_of_contour := true; inc(i) end; last := 0; i := 0; while ((i < number_of_points)) do begin sign := ((flags[i] and $10) <> 0); if ((flags[i] and 2) <> 0) then begin val := Marshal.ReadByte(ptr); ptr := TTF_Helpers.Increment(ptr, 1); last := ((last + } {pseudo} {(if sign then (val as Smallint) else (-val as Smallint))) as Smallint) end else if (not sign) then begin last := ((last + TTF_Helpers.SwapInt16(Marshal.ReadInt16(ptr))) as Smallint); ptr := TTF_Helpers.Increment(ptr, 2) end; points[i].x := ((last as Single) div font_rsize); inc(i) end; last := 0; i := 0; while ((i < number_of_points)) do begin sign := ((flags[i] and $20) <> 0); if ((flags[i] and 4) <> 0) then begin val := Marshal.ReadByte(ptr); ptr := TTF_Helpers.Increment(ptr, 1); last := ((last + }{pseudo}{ (if sign then (val as Smallint) else (-val as Smallint))) as Smallint) end else if (not sign) then begin last := ((last + TTF_Helpers.SwapInt16(Marshal.ReadInt16(ptr))) as Smallint); ptr := TTF_Helpers.Increment(ptr, 2) end; points[i].y := ((last as Single) div font_rsize); inc(i) end; start_new_contour := true; idx := 0; path := GraphicsPath.Create(FillMode.Winding); first_point := points[idx]; start_new_contour := true; beg := PointF.Create((points[0].Point.X + position.X), (position.Y - points[0].Point.Y)); first := beg; idx := 0; while ((idx < points.Length)) do begin curent_on_curve := points[idx].on_curve; if ((idx + 1) < points.Length) then begin next := PointF.Create((points[(idx + 1)].Point.X + position.X), (position.Y - points[(idx + 1)].Point.Y)); next_on_curve := points[(idx + 1)].on_curve end else begin next := PointF.Create((points[0].Point.X + position.X), (position.Y - points[0].Point.Y)); next_on_curve := points[0].on_curve end; if (start_new_contour) then begin path.StartFigure; first := beg; start_new_contour := false end; if (points[idx].end_of_contour) then begin start_new_contour := true; implied := PointF.Create((points[idx].Point.X + position.X), (position.Y - points[idx].Point.Y)); end := first; if (curent_on_curve) then path.AddLine(beg, end) else self.AddSpline(path, beg, implied, end, position); beg := next end else if (curent_on_curve) then if (next_on_curve) then begin end := next; path.AddLine(beg, end); beg := end end else begin implied := PointF.Create((points[idx].Point.X + position.X), (position.Y - points[idx].Point.Y)); if (next_on_curve) then begin end := next; self.AddSpline(path, beg, implied, end, position); beg := end end else begin X := ((position.X + ((points[(idx + 1)].x - points[idx].x) div 2)) + points[idx].x); Y := (position.Y - (((points[(idx + 1)].y - points[idx].y) div 2) + points[idx].y)); end := PointF.Create(X, Y); self.AddSpline(path, beg, implied, end, position); beg := end end end; inc(idx) end; begin Result := path; exit end end; } function GlyphTableClass.GetGlyphHeader(glyph_offset: Integer): GlyphHeader; var gheader: ^GlyphHeader; begin gheader := TTF_Helpers.Increment(self.glyph_table_ptr, glyph_offset); Result.numberOfContours := TTF_Helpers.SwapInt16(gheader.numberOfContours); Result.xMax := TTF_Helpers.SwapInt16(gheader.xMax); Result.yMax := TTF_Helpers.SwapInt16(gheader.yMax); Result.xMin := TTF_Helpers.SwapInt16(gheader.xMin); Result.yMin := TTF_Helpers.SwapInt16(gheader.yMin); end; procedure GlyphTableClass.Load(font: Pointer); begin self.glyph_table_ptr := TTF_Helpers.Increment(font, self.entry.offset) end; function GlyphTableClass.ReadRawByte(ptr: Pointer; var val: Byte): Pointer; var p: ^Byte; begin p := ptr; val := p^; Result := TTF_Helpers.Increment(ptr, 1) end; {$HINTS ON} end.