FastReport_FMX_2.8.12/LibD28x64/FMX.frxCmapTableClass.pas
2024-07-06 22:41:12 +02:00

276 lines
9.4 KiB
ObjectPascal

{******************************************}
{ }
{ FastReport FMX v2.0 }
{ Font parser }
{ }
{ Copyright (c) 1998-2013 }
{ by Aleksey Mandrykin, }
{ Fast Reports Inc. }
{ }
{******************************************}
unit FMX.frxCmapTableClass;
interface
uses System.SysUtils, FMX.TTFHelpers, FMX.frxTrueTypeTable;
type // Nested Types
EncodingFormats = (ByteEncoding=0, HighByteMapping=2, SegmentMapping=4, TrimmedTable=6);
TSmallintArray = array of Smallint;
TWordArray = array of Word;
TSegmentMapping = packed record
public segCountX2: Word;
public searchRange: Word;
public entrySelector: Word;
public rangeShift: Word;
end;
Table_CMAP = packed record
public TableVersion: Word;
public NumSubTables: Word;
end;
Table_Encode = packed record
public
Format: Word;
Length: Word;
Version: Word;
end;
Table_ByteEncodingSubTable = packed record
public
Format: Word;
Length: Word;
language: Word;
GlyphIndexArray: Array[0 .. 255] of Byte;
end;
Table_SUBMAP = packed record
public Platform: Word;
public EncodingID: Word;
public TableOffset: Cardinal;
end;
TCmapSubTableTable = class(TObject);
TCmapByteEncodingSubTable = class(TCmapSubTableTable)
private
FGlyphIndexArray: Array[0 .. 255] of Byte;
public
function GetGlyphIndex(ch: Byte): Word;
end;
TMappingTable = packed record
public
EndCount: TWordArray;
GlyphIndexArray: TWordArray;
idDelta: TSmallintArray;
idRangeOffset: TWordArray;
StartCount: TWordArray;
segment_count: Integer;
end;
CmapTableClass = class(TrueTypeTable)
// Fields
private
FByteEncodingSubTable: TCmapByteEncodingSubTable;
FWinCmap: TMappingTable;
FMacCmap: TMappingTable;
// Methods
function InternalGlyphIndex(CMapTable:TMappingTable; ch: Word): Word;
public
constructor Create(src: TrueTypeTable);
destructor Destroy; override;
public function GetGlyphIndex(ch: Word): Word;
private function LoadCmapSegment(segment_ptr: Pointer; segment_count: Integer): TWordArray;
public procedure LoadCmapTable(font: Pointer);
strict private function LoadSignedCmapSegment(segment_ptr: Pointer; segment_count: Integer): TSmallintArray;
end;
implementation
// Methods
constructor CmapTableClass.Create(src: TrueTypeTable);
begin
inherited Create(src);
FWinCmap.segment_count := 0;
FMacCmap.segment_count := 0;
FWinCmap.StartCount := nil;
FMacCmap.StartCount := nil;
FWinCmap.EndCount := nil;
FMacCmap.EndCount := nil;
end;
destructor CmapTableClass.Destroy;
begin
FreeAndNil(FByteEncodingSubTable);
inherited;
end;
function CmapTableClass.GetGlyphIndex(ch: Word): Word;
begin
{$IFDEF MACOS}
Result := InternalGlyphIndex(FMacCmap, ch);
if Result = 0 then
Result := InternalGlyphIndex(FWinCmap, ch);
{$ELSE}
Result := InternalGlyphIndex(FWinCmap, ch);
if Result = 0 then
Result := InternalGlyphIndex(FMacCmap, ch);
{$ENDIF}
if Assigned(FByteEncodingSubTable) and (Result = 0) then
Result := FByteEncodingSubTable.GetGlyphIndex(Byte(ch));
end;
function CmapTableClass.InternalGlyphIndex(CMapTable: TMappingTable;
ch: Word): Word;
var
i,j: Integer;
begin
Result := 0;
i := 0;
while ((i < CMapTable.segment_count)) do
begin
if (CMapTable.EndCount[i] >= ch) then
begin
if (CMapTable.StartCount[i] > ch) then
exit;
if (CMapTable.idRangeOffset[i] = 0) then
begin
Result := Word((ch + CMapTable.idDelta[i]) mod $10000);
exit
end;
j := Word(((CMapTable.idRangeOffset[i] div 2) +
(ch - CMapTable.StartCount[i])) - (CMapTable.segment_count - i));
Result := CMapTable.GlyphIndexArray[j];
exit;
end;
inc(i)
end;
end;
function CmapTableClass.LoadCmapSegment(segment_ptr: Pointer; segment_count: Integer): TWordArray;
var
i: Integer;
ptr: ^Word;
begin
ptr := segment_ptr;
SetLength(Result, segment_count);
i := 0;
while ((i < segment_count)) do
begin
Result[i] := TTF_Helpers.SwapUInt16(ptr^);
Inc(i);
Inc(ptr);
end;
end;
procedure CmapTableClass.LoadCmapTable(font: Pointer);
var
encode_ptr: ^Table_Encode;
encode: Table_Encode;
cmap: ^Table_CMAP;
j, i, subtables_count: Integer;
submap: Table_SUBMAP;
submap_ptr: ^Table_SUBMAP;
ByteEncodingSubTable: ^Table_ByteEncodingSubTable;
segment: TSegmentMapping;
segment_ptr: ^TSegmentMapping;
index_array_size: Cardinal;
CurCmap: ^TMappingTable;
begin
cmap := TTF_Helpers.Increment( font, self.entry.offset );
subtables_count := TTF_Helpers.SwapUInt16(cmap.NumSubTables);
submap_ptr := TTF_Helpers.Increment(cmap, SizeOf(Table_CMAP));
j := 0;
while ((j < subtables_count)) do
begin
// submap := submap_ptr;
submap.Platform := TTF_Helpers.SwapUInt16(submap_ptr.Platform);
submap.EncodingID := TTF_Helpers.SwapUInt16(submap_ptr.EncodingID);
submap.TableOffset := TTF_Helpers.SwapUInt32(submap_ptr.TableOffset);
submap_ptr := TTF_Helpers.Increment(submap_ptr, SizeOf(Table_SUBMAP));
if ((submap.Platform in [1, 3]) and (submap.EncodingID in [0, 1])) then
begin
case submap.Platform of
1: CurCmap := @FMacCmap;
else
CurCmap := @FWinCmap;
end;
encode_ptr := TTF_Helpers.Increment(cmap, submap.TableOffset);
// encode := encode_ptr;
encode.Format := TTF_Helpers.SwapUInt16(encode_ptr.Format);
encode.Length := TTF_Helpers.SwapUInt16(encode_ptr.Length);
encode.Version := TTF_Helpers.SwapUInt16(encode_ptr.Version);
case encode.Format of
0:
begin
if FByteEncodingSubTable = nil then
FByteEncodingSubTable := TCmapByteEncodingSubTable.Create;
ByteEncodingSubTable := (Pointer(encode_ptr));
for i := 0 to 255 do
FByteEncodingSubTable.FGlyphIndexArray[i] := ByteEncodingSubTable.GlyphIndexArray[i];
end;
4:
begin
segment_ptr := TTF_Helpers.Increment(encode_ptr, SizeOf(Table_Encode));
// segment := encode_ptr;
segment.segCountX2 := TTF_Helpers.SwapUInt16(segment_ptr.segCountX2);
segment.searchRange := TTF_Helpers.SwapUInt16(segment_ptr.searchRange);
segment.entrySelector := TTF_Helpers.SwapUInt16(segment_ptr.entrySelector);
segment.rangeShift := TTF_Helpers.SwapUInt16(segment_ptr.rangeShift);
CurCmap^.segment_count := (segment.segCountX2 div 2);
encode_ptr := TTF_Helpers.Increment(segment_ptr, SizeOf(TSegmentMapping));
CurCmap^.endCount := self.LoadCmapSegment(encode_ptr, CurCmap^.segment_count);
encode_ptr := TTF_Helpers.Increment(encode_ptr, (segment.segCountX2 + 2));
CurCmap^.startCount := self.LoadCmapSegment(encode_ptr, CurCmap^.segment_count);
encode_ptr := TTF_Helpers.Increment(encode_ptr, segment.segCountX2);
CurCmap^.idDelta := self.LoadSignedCmapSegment(encode_ptr, CurCmap^.segment_count);
encode_ptr := TTF_Helpers.Increment(encode_ptr, segment.segCountX2);
CurCmap^.idRangeOffset := self.LoadCmapSegment(encode_ptr, CurCmap^.segment_count);
index_array_size := Cardinal((8 + (4 * CurCmap^.segment_count)) * 2);
index_array_size := ((inherited length - index_array_size) div 2);
encode_ptr := TTF_Helpers.Increment(encode_ptr, segment.segCountX2);
CurCmap^.GlyphIndexArray := self.LoadCmapSegment(encode_ptr, index_array_size);
end;
end
end;
inc(j);
continue;
;
end
end;
function CmapTableClass.LoadSignedCmapSegment(segment_ptr: Pointer; segment_count: Integer ): TSmallintArray;
var
i: Integer;
p : PWord;
begin
SetLength(Result, segment_count);
p := segment_ptr;
i := 0;
while ((i < segment_count)) do
begin
{$R-}
Result[i] := TTF_Helpers.SwapInt16(p^);
{$R+}
inc(i);
inc(p);
end;
end;
{ TCmapByteEncodingSubTable }
function TCmapByteEncodingSubTable.GetGlyphIndex(ch: Byte): Word;
begin
Result := FGlyphIndexArray[ch];
end;
end.