Dizajner bira font sa jednoslojnim a za naslove, ili precrtanu nulu za tabele, ili set dekorativnih velikih slova za naslovnicu. Ti glifovi su vec u fontu. Jednostavno nisu podrazumevani. Podrazumevano a se mapira sa karaktera kroz cmap tabelu na jedan glif, a alternativa sedi nekoliko ID-ova glifa dalje, dostizna samo kroz pravilo supstitucije. Produkcija te alternative u PDF-u znaci citanje pravila i emitovanje zamenskog glifa u toku sadrzaja. Ovaj clanak govori o citanju tih pravila, onih sa jednom supstitucijom, u Object Pascalu bez izvorne biblioteke za oblikovanje ispod
Opseg je namerno uzan. Stilski setovi i alternative su supstitucije jedan-glif-ulaz, jedan-glif-izlaz. To je deo OpenType rasporeda koji se moze razresiti malim, deterministickim prelaskom tabele, sto ga cini dobrim izborom za Pascal engine koji zeli ostati slobodan od C zavisnosti
Zasto cisti Delphi umesto HarfBuzz-a
HarfBuzz je ocigledан odgovor na "oblikuj ovaj tekst", i za potpuno dvosmerno, Indic ili arapsko oblikovanje on je pravi odgovor. To je takode C biblioteka. Njeno vezivanje u Delphi ili C++Builder proizvod znaci isporucivanje izvornog objekta za svaku ciljnu platformu i arhitekturu, uskladivanje njene konvencije pozivanja, pracenje njenog ritma izdavanja i citanje njenih uslova licence u odnosu na vase. Nista od toga nije tesko izolovano. Sve to je trenje koje nikad ne nestaje, i ne kupuje nista kada je stvarni zahtev "daj mi ss01 oblik ovog slova"
Jednoj supstituciji nije potreban engine za oblikovanje. Potreban joj je parser za nekoliko GSUB podformata tabele i binarno pretrazivanje ili dva. Pisanje toga u Pascalu drzi ceo lanac alata unutar jednog kompajlera. Postena granica je da ovaj pristup radi sa pretrazivanjima glif supstitucija i nicim drugim. To nije bidi rezolucija, nije Indic preuredivanje, i nije automatsko kontekstualno oblikovanje. Gde su ta potrebna, potrebna su, i pretrazivanje jedne supstitucije nece ih zameniti
GSUB hijerarhija, od vrha do dna
Tabela Supstitucije Glifova organizovana je kao lanac indirekтnosti, i upit za supstituciju prolazi lancem odozgo. Na vrhu je ScriptList. Oznaka skripte kao sto je latn bira unos, a posebna oznaka DFLT je podrazumevana skripta koja se primenjuje kada se ne poklapa nijedna specificnija skripta. Unos skripte pokazuje na LangSys, jezicki sistem, sa podrazumevanim LangSys-om za uobicajeni slucaj i opcionalnim imenovanim za jezike kojima je potrebno razlicito ponasanje. Turski je uobicajeni primer, gde sa i bez tacke zahtevaju sopstveno rukovanje
LangSys imenuje skup indeksa karakteristika. Svaki indeks pokazuje u FeatureList, gde rekord karakteristike nosi cetvorobajtnu oznaku, ss01 medu njima, i listu indeksa pretrazivanja. Ti indeksi konacno pokazuju u LookupList, gde zive stvarne podtabele supstitucije. Dakle, razresavanje ss01 znaci: pronadi skriptu, pronadi njen LangSys, pronadi karakteristiku cija je oznaka ss01, prikupi pretrazivanja koja imenuje i primeni ih. HotPDF podrazumevano koristi DFLT skriptu i podrazumevani LangSys, sto je ono sto vecina latinskih tekstualnih dizajna isporucuje, i izlaze nacin za prepisivanje oznake skripte kada font zice svoje karakteristike pod specificnom skriptom
Tabele pokrivenosti odlucuju ko ucestvuje
Svaka podtabela supstitucije pocinje istim pitanjem: da li ovaj ulazni glif ucestvuje u ovom pravilu, i ako da, gde sedi u sopstvenom indeksiranju pravila. Na to pitanje odgovara tabela pokrivenosti, a odgovor je indeks pokrivenosti, mali ordinalni koji ostatak podtabele koristi za trazenje sta glif postaje
Pokrivenost dolazi u dva formata. Format 1 je lista ID-ova glifa sortiranih u rastucем redosledu. Glif se pronalazi binarnim pretrazivanjem, a njegova pozicija u listi je njegov indeks pokrivenosti. Format 2 je lista rekorda opsega, svaki sa pocetnim glifom, krajnjim glifom i indeksom pokrivenosti na koji se pocetni glif mapira. Glif unutar opsega dobija svoj indeks pokrivenosti odmicanjem od pocetka opsega. Format 1 je kompaktan kada su ucesnici glifovi rasprseni, Format 2 kada padaju u neprekidne sekvence. Oba su sortirana, pa se oba pretrazuju u logaritamskom vremenu, i oba vracaju ili indeks pokrivenosti ili cisto "nije pokriveno" sto motoru omogucava da ostavi glif na miru
Jednostruka Supstitucija, dva formata
Jednostruka Supstitucija je LookupType 1, i mapira jedan glif na tacno jednu zamenu. Takode ima dva formata, a podela je optimizacija prostora. Format 1 cuva jednu potpisanu deltu. ID izlaznog glifa je ID ulaznog glifa plus ta delta, modulo 65536. Ovako font kodira supstituciju gde svaki ucesnik glif sedi na istom fiksnom odmaku od svoje alternative, na primer blok lining figura smestenih na konstantnoj udaljenosti od odgovarajucih oldstyle figura. Tabela pokrivenosti kaze koji glifovi se kvalifikuju, a jedna delta sluzi svima njima
Format 2 cuva eksplicitni niz ID-ova zamenskih glifova. Indeks pokrivenosti iz tabele pokrivenosti je indeks u taj niz, pa glif na indeksu pokrivenosti 0 postaje prvi unos niza, indeks pokrivenosti 1 drugi, i tako dalje. Format 2 se koristi kada alternative nisu na jednoobraznom odmaku, sto je uobicajeni slucaj za rucno izgradene stilske setove. Upit je isti sa strane pozivaoca u oba slucaja. Uzmi ulazni glif, provuci ga kroz pokrivenost, i ako je pokriven, primeni deltu ili procitaj slot niza
var
Pdf: THotPDF;
BaseGID, AltGID: Word;
begin
Pdf := THotPDF.Create(nil);
try
Pdf.BeginDoc;
Pdf.RegisterUnicodeTTF('C:\Fonts\MyStylisticFace.ttf');
Pdf.SetFont('My Stylistic Face', 12, []);
// Default glyph for 'a' through the font's cmap.
BaseGID := Pdf.GetUnicodeGlyphForCodepoint(Ord('a'));
// Stylistic Set 1: resolve the alternate via GSUB LookupType 1.
AltGID := Pdf.GetSingleSubstituteGlyph(BaseGID, 'ss01');
// AltGID = BaseGID means the feature did not touch this glyph.
if AltGID <> BaseGID then
{ emit AltGID in the content stream };
finally
Pdf.Free;
end;
end;
Ugovor vredan paznje je propustanje. GetSingleSubstituteGlyph vraca nepromenjen ID ulaznog glifa na svakom promasaju: nema fonta, nema GSUB tabele, nema odgovarajuce karakteristike, nema pogotka pokrivenosti. To znaci da je poziv bezbedan za pozivanje bezuslovno. Pitate za alternativu, i ako je nema, dobijate nazad tacno ono sto ste stavili, pa kod pozivaoca nikad ne mora da sprecijalno obradi font kome nedostaje karakteristika
Sta oznake stilskih karakteristika znace
Oznaka karakteristike je ceo recnik za koju alternativu pitate, i oznake relevantne za stilski rad su kratak spisak. Glavni par je salt, stilske alternative, sveobuhvatni pristup alternativnim oblicima glifa, i ss01 do ss20, dvadeset numerisanih stilskih setova koje font moze definisati, svaki imenovani skup supstitucija koje dizajner grupise zajedno. Font bi mogao staviti jednoslojno a i pravo R pod ss03, na primer, tako da omogucavanje tog jednog seta menja stil oba
Oko njih sede jos nekoliko oznaka jednostruke supstitucije. aalt je pristup-svim-alternativama, unija svake alternative koju glif ima, obicno prezentovana kao karakteristika palete glifova. titl bira naslovna velika slova izrezana za velike velicine. subs i sups zamenjuju prave indeksne i eksponentne cifre umesto skaliranih podrazumevanih. ordn daje ordinalne oblike, podignuta slova u 1. i 2. frac gradi razlomke, mada puni dijagonalni razlomci takode se oslanjaju na ligaturnu i kontekstualnu logiku koja prelazi plain jednostruku supstituciju. Za slucajeve s jednim glifom, mehanizam je identican ss01: prosledi oznaku upitu supstitucije i procitaj alternativni glif
// Try a stylistic-set feature, then fall back to plain alternates.
function ResolveAlternate(Pdf: THotPDF; BaseGID: Word;
const PreferredTag: AnsiString): Word;
begin
Result := Pdf.GetSingleSubstituteGlyph(BaseGID, PreferredTag);
if Result = BaseGID then
Result := Pdf.GetSingleSubstituteGlyph(BaseGID, 'salt');
// Still BaseGID if neither feature covers this glyph.
end;
cmap format 12 i dopunske ravni
Pre nego sto se bilo koja supstitucija pokrene, karakter mora postati glif, i to je posao cmap tabele. Upit supstitucije pocinje od ID-a glifa, pa je put uvek karakter-do-glifa kroz cmap, zatim glif-do-alternative kroz GSUB. Zanimljivi deo cmap je njen doseg. Podtabela formata 4 pokriva Osnovnu Viselingvalnu Ravan, prvih 65536 kodnih tacaka, i to je dovoljno za vecinu latinicnog teksta. Nije dovoljno za kodne tacke od U+10000 navise, dopunske ravni, gde sada zive matematicki alfanumericki znaci, mnogi simboli i nekoliko zivih pisama
Format 12 je podtabela koja pokriva celi opseg U+0000 do U+10FFFF. To je sortirana lista grupa, svaka grupa pocetna kodna tacka, krajnja kodna tacka i pocetni ID glifa, pa se neprekidni niz kodnih tacaka mapira na neprekidni niz glifova. HotPDF razresava kodne tacke hibridnom strategijom koja se poklapa sa nacinom oblikovanja podataka. Kodne tacke u BMP-u se serve iz direktnog niza indeksiranog kodom tacke, jedno pretrazivanje bez pretrage. Kodne tacke u dopunskim ravnima se serve iz retke tabele sortirane po kodnoj tacki i pretrazene binarnim pretrazivanjem. Rezultat je da GetUnicodeGlyphForCodepoint uzima pun Cardinal i odgovara ispravno kroz celi opseg, vracajuci ID glifa 0, glif .notdef, za svaku kodnu tacku koju font ne mapira
var
Pdf: THotPDF;
Cp: Cardinal;
GID, StyledGID: Word;
begin
// A supplementary-plane code point: U+1D49C MATHEMATICAL SCRIPT CAPITAL A.
Cp := $1D49C;
GID := Pdf.GetUnicodeGlyphForCodepoint(Cp); // format 12 lookup
if GID <> 0 then
StyledGID := Pdf.GetSingleSubstituteGlyph(GID, 'ss01')
else
StyledGID := 0; // font has no glyph for this code point
end;
Gde se ova pretrazivanja zaustavljaju
API-ji jednostruke supstitucije odgovaraju na jedan oblik pitanja, i vredi biti jasan o tome na sta ne odgovaraju. LookupType 1 je jedan od osam tipova supstitucije. Upit ne radi LookupType 2 visestruku supstituciju, gde jedan glif postaje vise, niti LookupType 4 ligaturnu supstituciju, gde vise glifova postaje jedan. Ne radi kontekstualne i lancane-kontekstualne tipove, LookupTypes 5 i 6, koji se aktiviraju samo kada se glif pojavi u odredenom okruzenju, niti ekstenziju i obrnute-lancane tipove. Dijagonalni razlomak, Devanagari spoj ili arapska inicijalna-medijalna-finalna kaskada je problem sekvence, i pretrazivanje jednostruke supstitucije po glifu to ne moze izraziti
Takode ne vrsi automatsko oblikovanje. Nista ovde ne pregleda niz teksta, odlucuje koje karakteristike ukljuciti i primenjuje ih redosledom koji skripta zahteva. Pozivaoc bira oznaku karakteristike i primenjuje je glif po glif. To je tacno pravi alat za stilske setove i alternative, koji su opt-in i lokalni, i tacno pogresan alat za skriptu kojoj je potrebno preuredivanje. Odrzavanje granice ostrom je ono sto ce putanju supstitucije drzati malom i predvidivom
Za slucajeve kojima je zaista potreban rad na nivou sekvence, prica o slozenim pismima obradena je u nasem clanku o oblikovanju teksta slozenih pisama u Delphi-ju. Ako su vase supstitucije deo veceg posla izvestavanja koji takode postavlja slike i druge fontove na stranicu, vodic za izlaz izvestaja sa fontovima i slikama pokriva kako ti delovi idu zajedno. Sve to se pokrece na istom engineu, HotPDF Component za Delphi i C++Builder, koji nosi GSUB upite supstitucije pored ugradivanja fonta, podseta i tekst API-ja obradenih drugde na ovom blogu