PDFlibPas konverterer utvidede metafiler til ekte PDF-sideinnhold post for post, i stedet for å rasterisere dem, noe som er det som holder et importert diagram eller en CAD-tegning skarp ved enhver zoom. Den konvertereren er på omtrent 6500 linjer og ble skrevet mot VCL, så da biblioteket fikk et Free Pascal-mål, ble den klassifisert som ikke-porterbar og erstattet med en stub. Den klassifiseringen var feil, og måten den var feil på, er en nyttig lekse i hvordan man reviderer en avhengighet før man bestemmer seg for å skrive om rundt den
Den faktiske VCL-overflaten av de 6500 linjene viste seg å være liten: en bitmap-klasse brukt for sitt pikselformat, strømlagring, håndtak, canvas og scanlines; en metafilklasse brukt for sin bredde, høyde og sitt håndtak; og fargetypen med to konstanter. Hver av dem var allerede levert av bibliotekets egen grafikkenhet, som finnes nettopp for at ikke-VCL-bygget skal ha tilsvarender. Konvertereren var ikke blokkert på VCL i det hele tatt. Den var blokkert på Free Pascal Windows-enheten
Skill langs aksen koden faktisk avhenger av
Så endringen var ikke en re-implementering. Det var én betingelse: fra «kompiler stubben når det bygges uten VCL» til «kompiler stubben når det ikke bygges for Windows». Det er den riktige aksen, og å angi hvorfor gjør forskjellen åpenbar. En utvidet metafil er en Windows-beholder. Konvertereren er en parser for Windows GDI-poster fra topp til bunn. Om vertsapplikasjonen bruker VCL, et annet widget-sett eller intet widget-sett i det hele tatt, har ingenting med om de postene kan tolkes å gjøre; om målet er Windows har alt med det å gjøre
Konsekvensene av å velge riktig akse følger gratis. C++Builder-bygg, som undefinerer Windows-plattformsymbolet i dette biblioteket, beholder den kastende stubben og oppfører seg nøyaktig som før. macOS beholder stubben, korrekt, fordi det ikke finnes noen GDI-poster å parse der. Delphi VCL-bygg er urørt. Og et Windows-bygg med et ikke-VCL widget-sett får vektor-EMF-import som en bieffekt, noe ingen måtte implementere. En betingelse justert mot den reelle avhengigheten gjør plattformsarbeid til en énlinjes endring; en betingelse justert mot feil en gjør det til en omskriving som aldri blir planlagt
Free Pascal-hullet var deklarasjoner, ikke logikk
Det som faktisk manglet, var Win32-deklarasjonene som Delphi Windows-enheten leverer og Free Pascal-enheten ikke gjør. Å samle dem i én enkelt kompatibilitetsenhet i stedet for å strø betingelser gjennom konvertereren holdt parseren lesbar. Listen er lærerik fordi den viser hvor ujevn header-dekningen er mellom de to RTL-ene: 113 konstanter for metafilposttyper, to flagg for utvidet tekstoutput, tre konstanter for gradientfyllmodus, en pekertype for håndtakstabell, aliaser for gradientvertex- og primitivpostene, og tre posttyper som Free Pascal ikke deklarerer i det hele tatt, som dekker alfa-blending, transparent blitting og fargehåndteringsmodus
Ingen av dette er interessant individuelt. Alt av det må være riktig før parseren kompilerer, og en kompatibilitetsenhet er det naturlige hjemmet fordi den kan diffes mot header-dokumentasjonen som én enhet
Den som lydløst tegner feil bilde
To av de deklarasjonene er ikke bare manglende, de er til stede og feil for dette formålet, og dette er delen verdt å huske selv om du aldri rører en metafil
Free Pascal deklarerer børsteopprettingsposten med kjøretidsbørstestrukturen innebygd i seg, og den utvidete penneposten med kjøretidspennestrukturen innebygd i seg. Begge de kjøretidsstrukturene deklarerer sitt hatch-medlem som et pekerstørrelse heltall, for i et levende GDI-kall kan det medlemmet bære et håndtak. En metafil lagrer derimot alltid 32-bitsformen, fordi postoppsettet er en del av det serialiserte filformatet og ikke endrer seg med prosessens bitthet
På 32-bits bygg er de to enige og ingenting skjer. På Win64 er det pekerstørrelse medlemmet åtte byte der filen har fire, så hvert felt etter hatch-medlemmet leses fra feil forskyvning. Det er intet unntak, ingen parsefeil og ingen advarsel. Metafilen blir bare tegnet feil: farger fra feil byte, pennebredder fra feil byte, og et bilde som ser ut som en renderingsfeil snarere enn en struct-oppsettfeil. Delphi leverer eksplisitt 32-bits varianter av begge strukturene av nettopp denne grunnen, og kompatibilitetsenheten re-deklarerer dem på samme måte
// Feil på Win64: Hatch er pekerstørrelse, filen lagrer 32 bits,
// og hvert følgende felt forskjøves med fire byte uten feil
type
TLogBrushRuntime = record
lbStyle: UINT;
lbColor: COLORREF;
lbHatch: ULONG_PTR; // 8 byte i en 64-bits prosess
end;
// Riktig: det serialiserte oppsettet, fast bredde uansett bitthet
type
TLogBrush32 = record
lbStyle: UINT;
lbColor: COLORREF;
lbHatch: DWORD; // alltid 4 byte, slik det lagres i metafilen
end;
Den generelle regelen: enhver struktur som opptrer både som kjøretids-API-argument og som serialisert feltoppsett trenger to deklarasjoner, og den serialiserte må bruke fastbreddetyper gjennomgående. Pekerstørrelse medlemmer i et filformat er alltid en feil som venter på et 64-bits bygg
Signaturforskjeller hører hjemme i en wrapper, ikke ved hvert kallsted
De gjenværende forskjellene var ordinære signaturavvik, og måten å absorbere dem på, er en videresendings-wrapper snarere enn en betingelse ved hvert kallsted. Transformkombineringsfunksjonen tar pekere under Free Pascal der Delphi tar referanseparametre, så wrapperen tar referanser og sender adresser. Den kopierer også begge kildeargumentene inn i lokaler først, fordi konvertereren har kallsteder der målmatriksen samtidig er én av kildene, og å sende den samme adressen to ganger til en funksjon som skriver mens den leser, produserer en transform som er subtilt feil på en måte som bare viser seg på rotert innhold
function CombineTransformCompat(var Dest: TXForm;
const A, B: TXForm): BOOL;
var
SrcA, SrcB: TXForm;
begin
// Kopier først: kallere sender legitimt Dest som A eller B
SrcA := A;
SrcB := B;
{$IFDEF FPC}
Result := Windows.CombineTransform(@Dest, @SrcA, @SrcB);
{$ELSE}
Result := Windows.CombineTransform(Dest, SrcA, SrcB);
{$ENDIF}
end;
Rektangel- og punkttypene er det andre tilfellet. Free Pascal behandler metafilens rektangel- og punktposter som distinkte typer fra de generelle grafikktypene, så åtte tildelingssteder trengte en eksplisitt typecast mellom records med identisk oppsett. Begge kompilatorene aksepterer cast-formen, så de stedene bærer ingen betingelse i det hele tatt, noe som er verdt litt stygghet
Hva dette endrer for en Free Pascal-utrulling
Vektor-EMF-import fungerer på Windows under Free Pascal og produserer det samme sideinnholdet som Delphi-bygget: paths som paths, gradienter som mønsterinnhold, tekst som tekst. Utenfor Windows forblir rasterveien svaret, og det er en begrensning ved formatet snarere enn ved porteringen. Koordinat- og klippingstilstanden konvertereren mater inn i, er beskrevet i artikkelen om innholdsstrømmens CTM- og klippingssporing, og vektorprimitivene den sender ut, er dekket i vektorgrafikk, shaders og gradienter
Hvis du reviderer din egen kodebase for den samme muligheten, er den nyttige øvelsen den som startet dette: list opp medlemmene du faktisk bruker fra rammeverket du tror du er avhengig av. Svaret er ofte mye kortere enn importlisten antyder, og den reelle begrensningen ligger som regel et helt annet sted. Importveier basert på device context er generelt beskrevet i artikkelen om utskriftsforhåndsvisning og device context, og plattform- og verktøykjededekning er oppført på produktsiden for losLab PDF Developer Library