PDFlibPas pretvara enhanced metafile-ove u stvaran sadržaj PDF stranice zapis po zapis, umesto da ih rasterizuje, i upravo to čini uvezeni grafikon ili CAD crtež oštrim pri svakom uvećanju. Taj konvertor ima oko 6500 linija i pisan je uz VCL, pa je kada je biblioteka dobila Free Pascal cilj proglašen neportabilnim i zamenjen stub-om. To svrstavanje bilo je pogrešno, i način na koji je bilo pogrešno koristan je čas o tome kako ispitati zavisnost pre nego što odlučite da pišete oko nje iznova
Stvarna VCL površina tih 6500 linija ispostavila se malom: klasa bitmapa korišćena zbog piksel formata, čuvanja toka, handle-a, canvas-a i scanline-ova; klasa metafajla korišćena zbog širine, visine i handle-a; i tip boje sa dve konstante. Svaku od njih već je obezbeđivala sopstvena grafička jedinica biblioteke, koja postoji upravo da non-VCL build ima ekvivalente. Konvertor uopšte nije bio blokiran na VCL-u. Bio je blokiran na Free Pascal Windows jedinici
Podela po osi od koje kod stvarno zavisi
Promena dakle nije bila reimplementacija. Bila je to jedna uslovna direktiva: sa "kompajliraj stub kada se gradi bez VCL-a" na "kompajliraj stub kada se ne gradi za Windows". To je ispravna osa, i izricanje razloga čini razliku očiglednom. Enhanced metafile je Windows kontejner. Konvertor je parser za Windows GDI zapise od vrha do dna. Da li domaća aplikacija koristi VCL, drugi skup vidžeta ili nijedan nema nikakve veze sa tim da li se ti zapisi mogu interpretirati; da li je cilj Windows ima sve veze sa tim
Posledice izbora ispravne ose dobijaju se besplatno. C++Builder build-ovi, koji uklanjaju simbol Windows platforme u ovoj biblioteci, zadržavaju stub koji baca izuzetak i ponašaju se tačno kao pre. macOS zadržava stub, ispravno, jer nema GDI zapisa za parsiranje tamo. Delphi VCL build-ovi netaknuti. A Windows build sa non-VCL skupom vidžeta dobija vektorski EMF uvoz kao sporedni efekat, što niko nije morao implementirati. Uslovna direktiva usklađena sa stvarnom zavisnošću pretvara platformski rad u promenu od jedne linije; direktiva usklađena sa pogrešnom pretvara ga u prepisivanje koje nikad ne nađe mesta u planu
Praznina u Free Pascal-u bila su deklaracije, ne logika
Ono što je zapravo nedostajalo bile su Win32 deklaracije koje Delphi Windows jedinica obezbeđuje, a Free Pascalova ne. Njihovo sabiranje u jednu kompatibilnu jedinicu umesto rasipanja uslovnih kroz konvertor održalo je parser čitljivim. Popis je poučan jer pokazuje koliko je neujednačena pokrivenost header-a između dve RTL-a: 113 konstanti tipova zapisa metafajla, dve zastavice proširenog tekstualnog izlaza, tri konstante režima gradient popune, tip pokazivača handle tabele, alias-i za gradient vertex i primitivne zapise, i tri tipa zapisa koje Free Pascal uopšte ne deklariše, koji pokrivaju alpha blending, transparentno blitanje i režim upravljanja bojama
Ništa od toga nije zanimljivo pojedinačno. Sve to mora biti ispravno pre nego što se parser kompajlira, a kompatibilna jedinica je prirodno mesto jer se može uporediti (diff) sa header dokumentacijom kao celina
Onaj koji tiho crta pogrešnu sliku
Dve od tih deklaracija nisu samo nepostojeće, one su prisutne i pogrešne za ovu namenu, i to je deo vredan pamćenja čak i ako nikad ne dirate metafajl
Free Pascal deklariše zapis za stvaranje četke sa ugrađenom run-time strukturom četke, i zapis proširenog pera sa ugrađenom run-time strukturom pera. Obe te run-time strukture deklarišu svoj hatch član kao ceo broj veličine pokazivača, jer u živom GDI pozivu taj član može nositi handle. Metafajl, međutim, uvek čuva 32-bitni oblik, jer raspored zapisa deo je serijalizovanog formata datoteke i ne menja se sa bitnošću procesa
Na 32-bitnim build-ovima dve strukture se slažu i ništa se ne dešava. Na Win64 član veličine pokazivača ima osam bajtova gde datoteka ima četiri, pa se svako polje posle hatch člana čita sa pogrešnog ofseta. Nema izuzetka, nema greške parsiranja, nema upozorenja. Metafajl se jednostavno prikazuje pogrešno: boje iz pogrešnih bajtova, širine pera iz pogrešnih bajtova, i slika koja deluje kao render greška a ne kao greška rasporeda struktura. Delphi isporučuje eksplicitno 32-bitne varijante obe strukture upravo iz tog razloga, i kompatibilna jedinica ih ponovo deklariše na isti način
// Pogrešno na Win64: Hatch je veličine pokazivača, datoteka čuva
// 32 bita, i svako sledeće polje pomera se za četiri bajta bez greške
type
TLogBrushRuntime = record
lbStyle: UINT;
lbColor: COLORREF;
lbHatch: ULONG_PTR; // 8 bajtova u 64-bitnom procesu
end;
// Ispravno: serijalizovani raspored, fiksna širina bez obzira na bitnost
type
TLogBrush32 = record
lbStyle: UINT;
lbColor: COLORREF;
lbHatch: DWORD; // uvek 4 bajta, kao što se čuva u metafajlu
end;
Opšte pravilo: svaka struktura koja se pojavljuje i kao run-time API argument i kao serijalizovani raspored polja traži dve deklaracije, i serijalizovana mora koristiti tipove fiksne širine od početka do kraja. Članovi veličine pokazivača u formatu datoteke uvek su greška koja čeka 64-bitni build
Razlike u potpisima funkcija pripadaju wrapper-u, ne na svakom mestu poziva
Preostale razlike bile su obična neslaganja potpisa, i način da se apsorbuju jest forwarding wrapper umesto uslovnog na svakom od mesta poziva. Funkcija kombinovanja transformacija prima pokazivače pod Free Pascal-om gde Delphi prima referentne parametre, pa wrapper prima reference i prosleđuje adrese. On takođe kopira oba izvorna argumenta u lokalne promenljive prvo, jer konvertor ima mesta poziva gde je odredišna matrica istovremeno jedan od izvora, i prosleđivanje iste adrese dvaput funkciji koja piše dok čita proizvodi transformaciju koja je suptilno pogrešna na način koji se pokazuje samo na rotiranom sadržaju
function CombineTransformCompat(var Dest: TXForm;
const A, B: TXForm): BOOL;
var
SrcA, SrcB: TXForm;
begin
// Prvo kopiraj: pozivaoci legitimno prosleđuju Dest kao A ili B
SrcA := A;
SrcB := B;
{$IFDEF FPC}
Result := Windows.CombineTransform(@Dest, @SrcA, @SrcB);
{$ELSE}
Result := Windows.CombineTransform(Dest, SrcA, SrcB);
{$ENDIF}
end;
Tipovi pravougaonika i tačke su drugi slučaj. Free Pascal tretira zapise pravougaonika i tačke metafajla kao odvojene tipove od opštih grafičkih, pa je osam mesta dodele tražilo eksplicitan cast između zapisa identičnog rasporeda. Oba kompajlera prihvataju cast oblik, pa ta mesta ne nose nikakav uslovni, što vredi malo ružnoće
Šta ovo menja za Free Pascal raspoređivanje
Vektorski EMF uvoz radi na Windows-u pod Free Pascal-om, proizvodeći isti sadržaj stranice kao Delphi build: putanje kao putanje, gradient-i kao sadržaj šablona, tekst kao tekst. Van Windows-a rasterski put ostaje odgovor, i to je ograničenje formata a ne porta. Koordinatno i clipping stanje u koje se konvertor uliva opisano je u članku o CTM i clipping praćenju toka sadržaja, a vektorske primitve koje emituje pokrivene su u vektorskoj grafici, shader-ima i gradient-ima
Ako ispitujete sopstvenu bazu koda za istu priliku, korisna vežba je ona koja je ovo pokrenula: navedite članove koje stvarno koristite iz okvira od kojeg mislite da zavisite. Odgovor je često mnogo kraći nego što sugeriše popis uvoza, i stvarno ograničenje je obično negde sasvim drugde. Putovi uvoza zasnovani na device kontekstu opšte su opisani u članku o pregledu štampe i device kontekstu, a pokrivenost platformi i toolchain-a navedena je na stranici proizvoda losLab PDF Developer Library