PDFlibPas pretvara enhanced metafile u stvarni sadržaj PDF stranice zapis po zapis, umjesto da ih pretvara u rastrovu sliku, što je upravo ono što uvezeni grafikon ili CAD crtež drži oštrim pri bilo kojem zumiranju. Taj pretvarač ima oko 6500 redaka i pisan je u odnosu na VCL, pa je kada je knjižnica dobila Free Pascal cilj klasificiran kao neprenosiv i začepčen. Ta je klasifikacija bila pogrešna, a način na koji je bila pogrešna korisna je lekcija o tome kako pregledati ovisnost prije nego što odlučite pisati oko nje iznova
Stvarna VCL površina tih 6500 redaka pokazala se malom: bitmap klasa korištena zbog svog pikselnog formata, spremanja u tok, handlea, canvasa i scanlineova; metafile klasa korištena zbog svoje širine, visine i handlea; te tip boje s dvije konstante. Svaki od njih već je pružala vlastita grafička jedinica knjižnice, koja postoji upravo zato da ne-VCL izgradnja ima ekvivalente. Pretvarač uopće nije bio blokiran na VCL-u. Bio je blokiran na Free Pascal jedinici Windows
Podijelite po osi na kojoj kôd stvarno ovisi
Promjena dakle nije bila ponovna implementacija. Bio je to jedan uvjetni izraz: iz "kompajliraj začepčenu verziju kada se gradi bez VCL-a" u "kompajliraj začepčenu verziju kada se ne gradi za Windows". To je ispravna os, a iznošenje razloga čini razliku očiglednom. Enhanced metafile je Windows spremnik. Pretvarač je parser za Windows GDI zapise od vrha do dna. Hoće li host aplikacija koristiti VCL, drugi skup widgeta ili nikakav skup widgeta nema nikakve veze s time mogu li se ti zapisi tumačiti; je li cilj Windows ima sve s tim veze
Posljedice odabira ispravne osi dobivaju se besplatno. C++Builder izgradnje, koje poništavaju simbol Windows platforme u ovoj knjižnici, zadržavaju začepčenu verziju koja baca iznimku i ponašaju se točno kao i prije. macOS zadržava začepčenu verziju, ispravno, jer tamo nema GDI zapisa za raščlanjivanje. Delphi VCL izgradnje nisu dirane. A Windows izgradnja s ne-VCL skupom widgeta dobiva vektorski EMF uvoz kao nusprodukt, što nitko nije morao implementirati. Uvjet usklađen sa stvarnom ovisnošću pretvara platformski rad u promjenu od jednog retka; uvjet usklađen s pogrešnom pretvara ga u prepisivanje koje nikad ne dođe na red
Razmak na Free Pascalu bili su deklaracije, ne logika
Ono što je stvarno nedostajalo bile su Win32 deklaracije koje pruža Delphi jedinica Windows, a ne pruža ona Free Pascalova. Njihovo sabiranje u jednu jedinicu za kompatibilnost umjesto rasipanja uvjetnih izraza kroz pretvarač zadržalo je parser čitljivim. Popis je poučan jer pokazuje koliko je nejednaka pokrivenost zaglavlja između dva RTL-a: 113 konstanti tipova metafile zapisa, dvije zastavice proširenog tekstualnog izlaza, tri konstante načina gradient ispune, tip pokazivača na tablicu handlea, aliasi za gradient vršne i primitivne zapise te tri tipa zapisa koje Free Pascal uopće ne deklarira, pokrivajući alfa miješanje, prozirno blitanje i način upravljanja bojama
Ništa od toga nije zanimljivo pojedinačno. Sve to mora biti ispravno prije nego se parser kompajlira, a jedinica za kompatibilnost prirodni je dom jer se može usporediti s dokumentacijom zaglavlja kao cjelina
Onaj koji tiho crta pogrešnu sliku
Dvije od tih deklaracija nisu samo izostale, one su prisutne i pogrešne za ovu svrhu, a to je dio vrijedan pamćenja čak i ako nikad ne dirate metafile
Free Pascal deklarira zapis stvaranja kista s ugrađenom strukturom kista iz vremena izvođenja, a zapis proširene olovke s ugrađenom strukturom olovke iz vremena izvođenja. Obje te strukture iz vremena izvođenja deklariraju svoj član hatch kao cijeli broj veličine pokazivača, jer u živom GDI pozivu taj član može nositi handle. Metafile, međutim, uvijek sprema 32-bitni oblik, jer je raspored zapisa dio serijaliziranog formata datoteke i ne mijenja se s bitnošću procesa
Na 32-bitnim izgradnjama ta se dva slažu i ništa se ne događa. Na Win64 član veličine pokazivača ima osam bajtova gdje datoteka ima četiri, pa se svako polje nakon člana hatch čita s pogrešnog pomaka. Nema iznimke, nema pogreške raščlambe i nema upozorenja. Metafile se jednostavno pogrešno prikazuje: boje iz pogrešnih bajtova, širine olovaka iz pogrešnih bajtova i slika koja izgleda kao greška prikazivanja, a ne greška rasporeda strukture. Delphi isporučuje izričito 32-bitne varijante obiju struktura upravo iz tog razloga, a jedinica za kompatibilnost ih ponovno deklarira na isti način
// Pogrešno na Win64: Hatch je veličine pokazivača, datoteka sprema
// 32 bita, a svako sljedeće polje pomakne se za četiri bajta bez
// ijedne pogreške
type
TLogBrushRuntime = record
lbStyle: UINT;
lbColor: COLORREF;
lbHatch: ULONG_PTR; // 8 bajtova u 64-bitnom procesu
end;
// Ispravno: serijalizirani raspored, fiksna širina bez obzira na bitnost
type
TLogBrush32 = record
lbStyle: UINT;
lbColor: COLORREF;
lbHatch: DWORD; // uvijek 4 bajta, kako je spremljeno u metafileu
end;
Opće pravilo: svaka struktura koja se pojavljuje i kao argument API-ja u vremenu izvođenja i kao raspored polja serijalizirane datoteke treba dvije deklaracije, a serijalizirana mora koristiti tipove fiksne širine od početka do kraja. Članovi veličine pokazivača u formatu datoteke uvijek su greška koja čeka 64-bitnu izgradnju
Razlike u potpisima pripadaju omotu, ne svakom mjestu poziva
Preostale razlike bile su obične nepodudarnosti potpisa, a način da ih se upije jest prosljeđujući omot umjesto uvjetnog izraza na svakom od mjesta poziva. Funkcija kombiniranja transformacija uzima pokazivače pod Free Pascalom gdje Delphi uzima referentne parametre, pa omot uzima reference i prosljeđuje adrese. On također najprije kopira oba izvorna argumenta u lokalne varijable, jer pretvarač ima mjesta poziva gdje je odredišna matrica istodobno jedan od izvora, a prosljeđ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
// Najprije kopiraj: pozivatelji legitimno prosljeđ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 pravokutnika i točke su drugi slučaj. Free Pascal tretira metafile zapise pravokutnika i točke kao odvojene tipove od općih grafičkih, pa je osam mjesta dodjele trebalo eksplicitnu pretvorbu između zapisa istog rasporeda. Oba kompajlera prihvaćaju oblik s pretvorbom, pa ta mjesta ne nose nikakav uvjetni izraz, što vrijedi malo ružnoće
Što ovo mijenja za raspoređivanje na Free Pascalu
Vektorski EMF uvoz radi na Windowsu pod Free Pascalom, proizvodeći isti sadržaj stranice kao Delphi izgradnja: staze kao staze, gradijente kao sadržaj uzorka, tekst kao tekst. Izvan Windowsa rastrovani put ostaje odgovor, a to je ograničenje formata, ne prijenosa. Koordinatno i izrezno stanje u koje pretvarač utječe opisano je u članku o praćenju CTM i izrezivanja toka sadržaja, a vektorske primitivne koje emitira pokrivene su u vektorskoj grafici, shaderima i gradijentima
Ako pregledavate vlastitu bazu kôda za istu priliku, korisna vježba je ona koja je ovo pokrenula: napravite popis članova koje stvarno koristite iz okvira od kojega mislite da ovisite. Odgovor je često znatno kraći nego što to sugerira popis uvoza, a stvarno ograničenje obično je negdje sasvim drugdje. Putovi uvoza temeljeni na kontekstu uređaja općenito opisani su u članku o pretpregledu ispisa i kontekstu uređaja, a pokrivenost platformi i alatnim lancima navedena je na stranici proizvoda losLab PDF Developer Library