PDFlibPas muuntaa enhanced metafile -tiedostot aidoksi PDF-sivusisällöksi tietue kerrallaan rasteroimisen sijaan, ja juuri se pitää tuodun kaavion tai CAD-piirustuksen terävänä missä tahansa zoomaustasossa. Kyseinen muunnin on noin 6500 riviä pitkä ja se kirjoitettiin VCL:ää vasten, joten kun kirjasto sai Free Pascal -tavoitteen, se luokiteltiin siirtokelvottomaksi ja korvattiin stubilla. Luokittelu oli väärä, ja tapa, jolla se oli väärä, on hyödyllinen oppitunti siitä, miten riippuvuus auditoidaan ennen kuin päätetään kirjoittaa sen ympärille uusi toteutus
Noiden 6500 rivin todellinen VCL-pinta osoittautui pieneksi: bittikarttaluokka, jota käytettiin sen pikselimuodon, virran tallennuksen, kahvan, piirtopinnan ja scanline-rivien vuoksi; metafile-luokka, jota käytettiin sen leveyden, korkeuden ja kahvan vuoksi; sekä väarityyppi kahdella vakiolla. Jokainen niistä oli jo olemassa kirjaston omassa grafiikkayksikössä, joka on olemassa täsmälleen siksi, että ei-VCL-käännöksellä on vastineet käytössään. Muunnin ei ollut VCL:n takana jumissa lainkaan. Se oli jumissa Free Pascalin Windows-yksikössä
Jaa sen akselin mukaan, josta koodi todella riippuu
Muutos ei siis ollut uudelleentoteutus. Se oli yksi ehdollinen kohta: kohteesta ”käännä stub, kun rakennetaan ilman VCL:ää” kohteeseen ”käännä stub, kun ei rakenneta Windowsille”. Se on oikea akseli, ja syyn sanoittaminen tekee eron ilmeiseksi. Enhanced metafile on Windows-säiliö. Muunnin on alusta loppuun Windows GDI -tietueiden jäsennin. Sillä, käyttääkö isäntäsovellus VCL:ää, toista widgettijoukkoa vai ei mitään, ei ole mitään tekemistä sen kanssa, voidaanko kyseiset tietueet tulkita; sillä, onko kohde Windows, on kaikki tekemistä sen kanssa
Oikean akselin valitsemisen seuraukset syntyvät itsestään. C++Builder-käännökset, jotka poistavat Windows-alustasymbolin määrittelyn tässä kirjastossa, säilyttävät poikkeuksen heittävän stubin ja käyttäytyvät täsmälleen kuten ennenkin. macOS säilyttää stubin, oikein, koska siellä ei ole GDI-tietueita jäsennettäväksi. Delphi VCL -käännökset pysyvät koskemattomina. Ja Windows-käännös, jossa on ei-VCL-widgettijoukko, saa vektori-EMF-tuonnin sivuvaikutuksena, jota kukaan ei joudu toteuttamaan. Todellisen riippuvuuden mukainen ehdollinen kohta muuttaa alustatyön yhden rivin muutokseksi; väärän riippuvuuden mukainen muuttaa sen uudelleenkirjoitukseksi, joka ei koskaan päädy suunnitelmiin
Free Pascalin aukko oli deklaraatioita, ei logiikkaa
Todellisuudessa puuttuivat ne Win32-deklaraatiot, jotka Delphin Windows-yksikkö tarjoaa ja Free Pascal ei. Niiden kokoaminen yhteen yhteensopivuusyksikköön ehdollisten kohtien sirottelemisen sijaan muunnimeen piti jäsentimen luettavana. Luettelo on opettavainen, koska se osoittaa, kuinka epätasainen otsikkokattavuus näiden kahden RTL:n välillä on: 113 metafile-tietuetyypin vakioita, kaksi laajennettua tekstintulostuslippua, kolme liukuväritäytön tilavakiota, kahvataulukon osoitintyyppi, aliakset liukuvärin verteksi- ja primitiivitietueille sekä kolme tietuetyyppiä, joita Free Pascal ei julista lainkaan, kattaen alfasekoituksen, läpikuultavan blittauksen ja värinhallintatilan
Mikään niistä ei ole yksittäin kiinnostavaa. Kaiken on oltava oikein ennen kuin jäsenin kääntyy, ja yhteensopivuusyksikkö on luonnollinen koti, koska sen voi diffata otsikkodokumentaatiota vastaan yhtenä kokonaisuutena
Se yksi, joka piirtää hiljaa väärän kuvan
Kaksi niistä deklaraatioista ei ainoastaan puutu, ne ovat läsnä ja väärin tähän tarkoitukseen, ja tämä on se osa, joka kannattaa muistaa, vaikka et koskaan koskisi metafileen
Free Pascal julistaa siveltimen luontitietueen upotettuna siihen ajonaikaisen sivellinrakenteen kanssa, ja laajennetun kynätietueen upotettuna ajonaikaisen kynärakenteen kanssa. Molemmat ajonaikaiset rakenteet julistavat hatch-jäsenensä osoitinkokoiseksi kokonaisluvuksi, koska oikeassa GDI-kutsussa se jäsen voi kantaa kahvaa. Metafile tallentaa kuitenkin aina 32-bittisen muodon, koska tietueasettelu on osa sarjallistettua tiedostomuotoa eikä muutu prosessin bittisyyden mukaan
32-bittisillä käännöksillä ne kaksi sopivat yhteen eikä mitään tapahdu. Win64:llä osoitinkokoinen jäsen on kahdeksan tavua sillä, kun tiedostossa on neljä, joten jokainen hatch-jäsenen jälkeinen kenttä luetaan väärästä siirtymästä. Ei poikkeusta, ei jäsennysvirhettä eikä varoitusta. Metafile vain renderöityy väärin: vääriltä tavuilta tulevia värejä, vääriltä tavuilta tulevia kynänleveyksiä ja kuva, joka näyttää renderöintivirheeltä eikä struct-asettelun virheeltä. Delphi toimittaa nimenomaisesti 32-bittiset variantit molemmista rakenteista täsmälleen tästä syystä, ja yhteensopivuusyksikkö julistaa ne samalla tavalla uudelleen
// Väärin Win64:llä: Hatch on osoitinkokoinen, tiedosto tallentaa 32 bittiä,
// ja jokainen sitä seuraava kenttä siirtyy neljällä tavulla ilman virhettä
type
TLogBrushRuntime = record
lbStyle: UINT;
lbColor: COLORREF;
lbHatch: ULONG_PTR; // 8 tavua 64-bittisessä prosessissa
end;
// Oikein: sarjallistettu asettelu, kiinteä leveys riippumatta bittisyydestä
type
TLogBrush32 = record
lbStyle: UINT;
lbColor: COLORREF;
lbHatch: DWORD; // aina 4 tavua, kuten metafileen tallennettuna
end;
Yleinen sääntö: mikä tahansa rakenne, joka esiintyy sekä ajonaikaisena API-argumenttina että sarjallistettuna kenttäasetteluna, tarvitsee kaksi deklaraatiota, ja sarjallistetun on käytettävä kiinteän leveyden tyyppejä alusta loppuun. Osoitinkokoiset jäsenet tiedostomuodossa ovat aina virhe, joka odottaa 64-bittistä käännöstä
Signatuurieroista kuuluu kääreeseen, ei jokaiselle kutsupaikalle
Loput erot olivat tavallisia signatuurin täsmäämättömyyksiä, ja tapa omaksua ne on välittävä kääre eikä ehdollinen kohta jokaisella kutsupaikalla. Transformatioita yhdistävä funktio ottaa osoittimia Free Pascalilla, missä Delphi ottaa viiteparametreja, joten kääre ottaa viitteet ja välittää osoitteet. Se kopioi myös molemmat lähdeargumentit lokaaleihin ensin, koska muuntimella on kutsupaikkoja, joissa kohdematriisi on yhtä aikaa yksi lähteistä, ja saman osoitteen välittäminen kahdesti funktiolle, joka kirjoittaa lukiessaan, tuottaa transformaation, joka on hienovaraisesti väärin tavalla, joka ilmenee vain kierretyllä sisällöllä
function CombineTransformCompat(var Dest: TXForm;
const A, B: TXForm): BOOL;
var
SrcA, SrcB: TXForm;
begin
// Kopioi ensin: kutsujat välittävät laillisesti Destin A:na tai B:na
SrcA := A;
SrcB := B;
{$IFDEF FPC}
Result := Windows.CombineTransform(@Dest, @SrcA, @SrcB);
{$ELSE}
Result := Windows.CombineTransform(Dest, SrcA, SrcB);
{$ENDIF}
end;
Suorakulmio- ja pistetyypit ovat toinen tapaus. Free Pascal käsittelee metafile-suorakulmio- ja pistetietueet erillisinä tyyppeinä yleisistä grafiikkatietueista, joten kahdeksan sijoituspaikkaa tarvitsi eksplisiittisen tyypinmuunnoksen identtisen asettelun tietueiden välillä. Molemmat kääntäjät hyväksyvät muunnosmuodon, joten kyseiset paikat eivät kanna lainkaan ehdollista kohtaa, mikä on pienen rumuuden arvoista
Mitä tämä muuttaa Free Pascal -käyttöönotossa
Vektori-EMF-tuonti toimii Windowsilla Free Pascalilla tuottaen saman sivusisällön kuin Delphi-käännös: polut polkuina, liukuvärit kuviosisältönä, teksti tekstinä. Windowsin ulkopuolella rasteripolku pysyy vastauksena, ja se on muodon rajoitus eikä porttauksen. Koordinaatti- ja leikkaustila, johon muunnin syöttää, on kuvattu artikkelissa sisältövirran CTM- ja leikkaustilan seurannasta, ja sen emittoimat vektoriprimitiivit käsitellään artikkelissa vektorigrafiikka, shaderit ja liukuvärit
Jos auditoit omaa koodikantaasi saman mahdollisuuden varalta, hyödyllinen harjoitus on se, joka aloitti tämän: luettele jäsenet, joita todella käytät kehyksestä, josta luulet riippuvasi. Vastaus on usein paljon lyhyempi kuin tuontiluettelo antaa ymmärtää, ja todellinen rajoite on yleensä jossakin aivan muualla. Laitekontekstiin perustuvat tuontipolut yleisesti on kuvattu artikkelissa tulostusesikatselusta ja laitekontekstista, ja alusta- ja työkalukettukattavuus on lueteltu losLab PDF Developer Library -tuotesivulla