276 lines
9.4 KiB
ObjectPascal
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.
|