Oblikovanje besedila v komponenti PDFium gre skozi en namestitveni objekt. ConfigureTextShaper namesti oblikovalca, skozi katerega se usmerja vsak vstopni klic oblikovanja, zamenjajoč in sproščujoč karkoli je bilo tam; ActiveTextShaper vrne nameščenega in ustvari privzeto platformo ob prvi uporabi; ActiveTextShaperName poroča, katero zaledje je živo; ClearTextShaper spusti namestitev in pusti privzeto biti znova ustvarjeno. Na Windows je privzeto TPdfUniscribeTextShaper. Pod Free Pascalom obstaja TPdfHarfBuzzTextShaper, ki veže libharfbuzz ob zagonu, tako da je manjkajoča knjižnica poročano stanje in ne odpoved nalaganja
En vmesnik, dve zaledji, ki delita delo popolnoma drugače. Razumevanje te asimetrije je tisto, kar ustavi prenosljivo pot pred proizvodnjo besedila, ki je oblikovano pravilno in pozicionirano napačno
Zakaj je zaledje Windows en razred in prenosljivo trije kosi?
Ker je Uniscribe štiri API-ji, ki se pretvarjajo, da so enega. ScriptItemize razdeli niz po skripti in razreši dvosmjerne ravni; ScriptShape preslika znake v glife; ScriptPlace izračuna predkorake in odmike; ScriptLayout da nastale teke v vizualni vrstni red. Zaledje, zgrajeno nanj, torej nima ničesar več za dodati, kar je razlog, zakaj je oblikovalec Windows en razred z eno metodo
HarfBuzz pokriva srednji dve. Oblikuje in umešča tek, katerega smer in skripto je klicatelj že odločil, in nima mnenja o tem, kako se odstavek razdeli v teke ali v katerem vrstnem redu se ti teki pojavijo. Torej prenosljivo zaledje preskrbi ostalo: dvosmjerni algoritem razreši ravni vgradnje, funkcije Unicode HarfBuzz razdelijo besedilo po skripti in teki so razporejeni v vizualnem vrstnem redu, ki ga proizvede pravilo L2 UAX #9. Dvosmjerna polovica je dovolj obsežna, da je lastna enota, opisana v članku o ravnih vgradnje UAX #9
Oblikovalec ne razrešuje pisav in to je namerno
Uniscribe bere binarno pisavo iz konteksta naprave GDI. Ni prenosljivega ustrežnika tega in izumljanje enega znotraj oblikovalne enote bi pomenilo odločanje, v imenu vsake aplikacije, ali pisave pridejo iz fontconfig, iz CoreText, iz mape pisav aplikacije ali iz podatkovne baze. Torej zaledje HarfBuzz vzame razreševalnik: povratni klic, ki preslika ime pisave v bajte TrueType ali OpenType. Vračanje False spodleti zahtevo oblikovanja na enak način, kot jo spodleti neberljiva pisava GDI na Windows
uses
FPdfTextShaping
{$IFDEF FPC}
, FPdfTextShapingHb
{$ENDIF}
;
function TFontCatalogue.Resolve(const FontName: WideString;
out FontData: TBytes): Boolean;
var
Path: string;
begin
// Vaša politika: fontconfig, CoreText, mapa pisav aplikacije,
// podatkovna baza
Result := FLookup.TryGetValue(LowerCase(FontName), Path);
if Result then
FontData := TFile.ReadAllBytes(Path);
end;
procedure InstallShaper(Catalogue: TFontCatalogue);
begin
{$IFDEF FPC}
// Lastnina gre k enoti; pokličite enkrat med zagonom,
// preden karkoli oblikuje besedilo
ConfigureTextShaper(TPdfHarfBuzzTextShaper.Create(Catalogue.Resolve));
{$ENDIF}
// Na Delphiju je privzeta platforma (Uniscribe) ustvarjena na zahtevo,
// tako da ni potrebna nobena namestitev sploh
LogInfo('shaping backend: ' + ActiveTextShaperName);
end;
Ohranjanje odkrivanja pisav zunaj oblikovalca ima drugo korist, ki se pokaže na strežnikih: isti proces lahko oblikuje z naborom vgrajenih pisav, ki nima ničesar s tem, kar je nameščeno na stroju, kar je tisto, kar želite, ko mora biti izhod bajtno reproducirljiv čez gostitelje. Komponenta prav tako izpostavi ponudnika pisav gostiteljskega sistema za primere, kjer res želite nameščene pisave, pokrito v članku o ponudniku sistemskih pisav
Zapis rezultata je zaledje-nevtralen in klastri so razlog
Obe zaledji izpolnita isti TPdfShapedText: izvorno besedilo, ime pisave, velikost, bajte pisave, matriko tekov, skupno širino, število glifov in logično število znakov. Vsak TPdfShapedRun nosi svoj razpon v izvornem besedilu, svoj vizualni položaj X, svojo širino, svojo dvosmjerno raven in zastavico z desne na levo, plus svoje glife. Vsak TPdfShapedGlyph nosi identifikator glifa, predkorak, odmika X in Y in klaster, ki mu pripada, kot začetek in dolžino v izvornem besedilu
Tista polja klastrov so tisto, kar naredi zapis uporaben in ne zgolj informativen. Oblikovanje ni preslikava ena-na-ena: zlog Devanagari postane en glif iz štirih znakov, arabska ligatura združi dva in en sam znak lahko proizvede več oznak. Brez razponov klastrov ne morete umeriti strešice, izvesti preizkusa zadetka klik ali poudariti izbire, ker ne morete povedati, katerim znakom glif pripada. Z njimi je aritmetika lokalna in ista koda deluje za obe zaledji
var
Shaped: TPdfShapedText;
R, G: Integer;
begin
if ShapePdfText(Line, 'Noto Sans Arabic', 14, ptdAuto, Shaped) then
for R := 0 to High(Shaped.Runs) do
begin
// Teki že prispejo v vizualnem vrstnem redu z izpolnjenim VisualX
X := Shaped.Runs[R].VisualX;
for G := 0 to High(Shaped.Runs[R].Glyphs) do
begin
EmitGlyph(Shaped.Runs[R].Glyphs[G].GlyphID,
X + Shaped.Runs[R].Glyphs[G].OffsetX,
Shaped.Runs[R].Glyphs[G].OffsetY);
X := X + Shaped.Runs[R].Glyphs[G].Advance;
end;
end;
end;
Proračuni pripadajo zapisu možnosti
TPdfTextShapingOptions nosi smer plus tri omejitve: največ znakov, največ glifov in največ tekov, z razredno funkcijo Default, ki izpolni smiselne vrednosti. Omejitve niso paranoja o deformiranem vhodu; so aritmetika. Oblikovanje se razširi: pisava z agresivno kontekstualno substitucijo lahko izda več glifov kot vhodnih znakov in odstavek, ki izmenjuje skripte vsakih nekaj znakov, proizvede tek na preklop. Dokument, sestavljen, da maksimirata oboje, spremeni skromen niz v veliko dodelitev, in storitev, ki oblikuje besedilo iz nezaupanih PDF-jev, potrebuje omejitev, ki jo je izbrala, in ne omejitve, ki jo vsili stroj
Nastavitev smeri izrecno namesto puščanje na samodejni je vredna početja, kadar koli jo že veste. Samodejni aplicira pravila smeri odstavka, da ugane iz prvega močnega znaka, kar je prav za prosto besedilo in narobe za polje obrazca, katerega smer je lastnost polja in ne vrednosti, ki jo je nekdo natipal vanj
Vezava ob zagonu in ne gradbena odvisnost
Zaledje HarfBuzz naloži knjižnico dinamično. To je odločitev namestitve z resničnimi posledicami: ena binarna datoteka teče na stroju s HarfBuzz in na stroju brez njega, poročajoč zmanjšano zmožnost v drugem primeru namesto spodletel zagon. Za knjižnico, poslano drugim razvijalcem, je to edina delujoča ureditev, ker ne morete zahtevati, da vsak potrošnik PDF komponente pridobi in ujema z različico oblikovalno knjižnico, ki je morda ne potrebuje
Ustrezno pravilo za klicatelje je preveriti. ActiveTextShaper vrne nil, ko platforma nima privzetega in ni bilo nastavljenega nobenega, vstopna točka oblikovanja pa to poroča kot nerazpoložljivega oblikovalca in ne kot odpoved oblikovanja. To so različni problemi in si zaslužijo različna sporočila: eno je vrzel namestitve, drugo je težava pisave ali besedila
Namestite enkrat, preden karkoli oblikuje
Namestitev zamenja in sprosti prejšnjega oblikovalca, tako da je klicanje njega večkrat varno ampak brez točke, in klicanje njega, medtem ko druga nit oblikuje, ni varno sploh. Naredite to med zagonom. Če morate pasti nazaj na privzeto platformo kasneje, posredujte nil, kar je prav tako način, kako razveljavite dvojnika testa na koncu testa
Ko je zaledje nameščeno, se merjenje in ovijanje obnašata enako na obeh platformah, ker porabita metrike tekov in glifov namesto klicanja platforme neposredno; model ovijanja je opisan v članku o merjenju besedila in ovijanju besed. Podprte platforme in orodjarne za komponento so navedene na strani produkta PDFium Delphi component