Obsah
Položky zakončené lomítkem jsou adresáře, ostatní položky jsou soubory.
- TEST/ - adresář s regtestem.
- pages/ - obsahuje jednotlivé stránky pro regtest.
- commit - skript, který do CVS commitne výsledek regtestu
- log - log regtestu, kam se píše, kde to na co spadlo
- msg - jako log, ale s trochu jinými informacemi
- regtest - skript, který dělá regtest.
- Unicode/ - překladové tabulky z různých znakových sad do unikódu.
- doc/ - dokumentace, návody, postupy
- examples/ - příklady na funkci Linkse
- amen/ - javascripty, které shodí jiné prohlížeče
- links_cal/ - kalibrace Linkse
- calibration.html - HTML s kalibrací, anglicky
- kalibrace.html - HTML s kalibrací, česky
- tex/ - dokumentace ve formátu TeX
- screenshots/ - ukázky z prohlížeče ve tvaru obrázků, které se
stanou součástí TeXové dokumentace.
- Makefile - makefile, který TeXovou dokumentaci zkompiluje
- README - český stručný popis adresáře s TeXovou dokumentací
- diagram.eps - diagram vnitřní struktury prohlížeče
- links.eps - logo prohlížeče Links
- links.text - makra pro TeX, použitá v dokumentaci
- links_doc.html - verze links_doc.html, podle které byla psaná
TeXová dokumentace
- projektova.tex - projektová dokumentace
- tables.tex - makra pro tabulky, použitá v dokumentaci
- toc.tex - makra pro generování obsahu v TeXové dokumentaci
Linkse
- user.tex - uživatelská dokumentace
- vyvojova.tex - vývojová dokumentace
- byro.html - byrokratická dokumentace k 18.10.2001
- ch56.txt - jakýsi výkřik dokumentace k Javascriptu, který tam
asi dal PerM
- diagram.png - master od diagramu vnitřní struktury prohlížeče
Links, před Javascriptem, ale s popisky jednotlivých políček
- diagram2.png - master od diagramu vnitřní struktury
prohlížeče Links, po Javascriptu, ale bez popisek jednotlivých políček
(diagram je určen pro přidání do TeXové dokumentace, a tam je popis v
textu).
- genps.png - ilustračně dokumentační obrázek k programu genps
- links_doc.html - tento soubor
- zadani.html - specifikace projektu Links
- zasedani.html - zápis ze zasedání
- graphics/ - v tomto adresáři jsou věci týkající se grafiky.
- font/ - fonty.
Každé písmenko je uloženo jako obrázek png, přičemž jsou dovoleny všechny
platné barevnosti a jiné featury formátu png (nicméně se nedoporučují,
protože mohou omezit běh prohlížeče na platformě se staarou libpng). Budou automaticky
zkonvertovány do šedotónu a výsledný obrázek použit jako alfa kanál pro
výrobu písmenek v linksu. Bílá barva je inkoust, černá je pozadí.
V současné době jsou přímo v adresáři font písmenka typu 1bc4.png, kde
1bc4 je hexa kód znaku v unicode.
- image_test_kit/ - kit na testování různých druhů obrázků.
Tímto se testuje, jestli dekodér některého formátu na některé architektuře
nepadá. Prohlížeč se pustí na index.html. Testovací HTML stránka
obsahuje kompletní sadu PNG Test Suite Icons od
Willema van Schaika.
- system_font/ - systémový font. Je to font, z kterého uživatel
nesmí odebírat písmenka, protože na existenci těchto písmenek se prohlížeč
spoléhá. Momentálně je tam pouze kaňka, která signalizuje znak, k němuž se
nepodařilo najít ekvivalent v žádném z fontů v prohlížeči.
- Fontmap - soubor, který se používá při
přidávání fontů do Linkse z Ghostscripta. Viz také makefont
- Makefile - makefile, který postaví improcess, genps, pbm2png a clip.
- links.xpm - ikona 48x48 na desktop.
- makefont - skript. Viz makefont
- pbm2png - program. Viz pbm2png
- pbm2png.c - zdroják od pbm2png
- pdf2html - skript. Viz pdf2html
- spacer.png - 112 pixelů vysoký obrázek používaný makefontem k oddělení akcentu a písmenka při
poloautomatické výrobě akcentovaných písmenek
- intl/ - internacionalizace.
- *.lng - Soubory s překlady menu do různých jazyků
- gen-intl - skript, který z jednotlivých *.lng vyrobí zdroják
v jazyce C
- synclang - skript, který synchronizuje ostatní jazyky podle
angličtiny. Přidá-li se nějaká položka v menu, stačí to napsat do
english.lng a pak pustit synclang, čímž se tato položka objeví i v
ostatních jazycích (nepřeložená, samozřejmě) a už stačí položku přeložit
(nebo ji tam nechat, pokud překlad neznáme, aby nějaký vývojář ovládající
dotyčný jazy položku přeložil).
- synclang.awk - pomocný skript pro synclang v jazyce AWK.
Pro bližší popis, jak se přidávají nové jazyky a jak se upravují a přidávají
nové texty, čtěte intl.txt v adresáři intl
- parser/ - parser Javascriptu
- gen - vygeneruje parser Flexem a Bisonem, opraví warning na
unitialized yystype yyval pomocí sedu.Q
- javascr.l - vstup pro Flex
- javascript.y - vstup pro Bison
- AUTHORS - autoři a credits.
- BUGS - známé bugy.
- EXTERNAL_BUGS - popisy bug nezaviněných linksem - co nechodí s
kterými vadnými knihovnami. V linksu by na tyto věci měl být workaround
typu "milej pane narazil jste na png-čko, který vaše braindamaged libpng
neni schopna zpracovat ani kdyby se rozkrájela, tak si stáhněte novou
libpng", nebo workaroundy, které se neprojevují navenek ničím jiným nežli
nepříliš svižnou performancí (jako třeba emulace vga_drawscansegment
pomocí putpixel v braindamaged svgalib).
- COPYING - GNU licence.
- Changelog - obsahuje změny mezi jednotlivými verzemi. Také mírně postarší.
- INSTALL - návod k instalaci.
- NEWS - fosilní novinky v linksu.
- README - velmi stručná dokumentace o ovládání. Také
již hodně dlouho nespatřila VI.
- SITES - kde se textový links dá stáhnout.
- TODO - co je třeba udělat v textovém linksu.
- links.1 - manpage od linksu.
- aclocal.m4 - je automaticky generovaný aclocalem. Nešahat,
vyrobí se nový když se pustí aclocal.
- configure.in - do tohoto souboru se přidávají nové testy, které se mají provádět v configure.
Většinou to spočívá v pokusu
najít nějaký soubor nebo nějakou funkci, zkompilovat s nějakou knihovnou a
podle výsledku nastavit nějaké makro, ktere se pak později použije někde
ve zdrojácích linkse.
- convert_bookmarks - skript na převedení starého souboru bookmarku
(lineární) na nový (stromový) tvar bookmarku. Nevytváří adresáře, jen čistě
převede do formy čitelné novými bookmarky. Je nutné, aby si uživatel vyrobil
případné adresáře a do nich pak jednotlivé bookmarky přemístil.
- generate_font - pomocný program pro zakompilování
fontových souborů do spustitelného souboru links.
- install-sh - asi se používá při make
install, aby se správné soubory nainstalovaly na správné místo.
- links - binárko linkse, vyrobí se kompilací ("./configure; make").
- mailcap.pl - zkonvertuje mailcap do links.cfg. Dělal to někdo
zvenku. A je to v Perlu.
- missing - nějaký interní script od autoconf & spol.
- mkinstalldirs - další interní script, zřejmě nějak souvisí ještě s install-sh a autoconfem.
- rebuild - script na kompletní přebuildování linkse. Doporučuje se používat. Když chcete linkse od
základů překonfigurovat a překompilovat, tak to pusťte a ono to všechno
zařídí. Je v tom magická sekvence příkazů, které nikdo nerozumí, byla
odněkud opsána, nicméně to funguje.
- configure - to je ten profláknutý skript. Links se standardně
instaluje configure; make.
- Makefile.am - zdroják pro výrobu Makefile pomocí automake. Když někdo chce přidat soubor do linkse,
tak stačí napsat řádku jménoprogramu_SOURCE=jména všech zdrojáků .c oddělených mezerami a na
řádku bin_PROGRAMS= přidat výsledné jméno toho programu (musí se shodovat
se jménem programu z jménoprogramu_SOURCES).
- arrow.c - generátor šipečky z arrow.png do arrow.inc.
- af_unix.c - komunikace mezi několika spuštěnými linksy přes unix domain sockets.
- beos.c - emulace braindamaged syscallů na beosu.
- bfu.c - klikátka, dialogy - vše potřebné pro BFU.
Funguje jak v grafice, tak v textu. Menu jsou v menu.c a překvapivě ne
tady.
- bookmarks.c - bookmarky.
- builtin.c - volání upcallů, implementace vestavěných metod a objektů v javascriptu.
- cache.c - obecná LRU cache na dokumenty.
- calibrate.c - zdroják od programu calibrate.
- clip.c - zdroják od programu clip
- charsets.c - funkce na konverze mezi určitou kódovou stránkou a unikódem.
- cookies.c - sušenky.
- connect.c - výroba spojení.
- context.c - funkce pro správu javascript kontextu.
- default.c - nastavení všeho možného, nahrávání a ukládání nastavení na disk, parsování příkazové řádky.
- dip.c - digital image processing. Zvládá tisk řetězců, písmen, počítání délky řetezců.
Jsou zde funkce pro nahrávání
písmenek, cacheování písmenek a jejich metrik.
Dále je tu změna měřítka
šedotónových bitmap a pronásobení 2 konstantních barev přes alpha masku. Gamma
korekce 3*8 bitů barevné bitmapy.
- dither.c - brutálně optimalizované ditherovací enginy.
Pozor, kód vykazuje značnou brutalitu, pouze pro otrlé a/nebo
opilé čtenáře. Používá se Floyd-Steinberg s maskou, která je nakreslená v
kódu. Tato metoda byla vybrána po shlédnutí testu výsledků různých metod
na Grafice I od kolegy Pelikána, tak proboha ať nikoho nenapadne to vylepšovat --
už to víc nejde! Ditheruje se na úplně všech barevných módech a to proto,
že to vypadá lépe v případě, že gamma transformace není identita, a/nebo
v případě, že se zobrazuje PNG nebo TIFF obrázek s 16 bity na barevnou
složku.
Vzhledem k tomu, že ditherování se provádí v 16-bitovém režimu (tedy 48
bitů na pixel), a samozřejmě v prostoru úměrném světlu, je to
super-ultra-delikatesně kvalitní, nezávisle na tom, jak crappy rozlišení
si nastavíme.
- dns.c - DNS resoluce.
- drivers.c - společný zdroják pro grafické drivery. Nyní obsahuje
svgalib, pmshell (v OS/2), framebuffer a a X. Dále jsou zde virtuální devicy.
- error.c - chybové hlášky, chytání segfaultů a memory leaků.
- file.c - kód pro loadování souboru na lokálním počítači.
- finger.c - Links umí i finger, zkuste napsat "links
finger://user@machine" a nebudete věřit svým očím! Toto je zdroják.
- font_include.c - PNG fonty připravené k zakompilování do binárka. Vytváří se automaticky při rebuildu.
Je velký.
- ftp.c - FTP kód.
- generate_font.c - zdroják od generate_font
- genps.c - zdroják od programu genps.
- html.c - HTML parser.
- html_r.c - HTML renderer pro textový mod.
- html_gr.c - HTML renderer pro grafický mód.
- html_tbl.c - tabulky v HTML.
- http.c - navazování HTTP konexí.
- https.c - HTTPS protokol.
- img.c - zobrazování obrázků v grafickém módu. Momentálně příliš kódu neobsahuje.
- improcess.c - zdroják od programu improcess, který
slouží k jednoduchým manipulacím s černobílými obrázky písmen při přidávání
těchto do fontového systému Linksu.
- ipret.c - interpret javascriptího mezikódu.
- javascr.l - lexikální analyzátor, zdroják pro flex.
- javascript.y - syntaktický analyzátor s generátorem stromového mezikódu, zdroják pro bisona.
- jsint.c - rozhraní mezi javascriptem a linksem, upcally.
- kbd.c - klávesnice. Používá se i v svgalibě, abychom si
nemuseli dělat autorepeat a hlavně abychom mohli využít překlad národních
písmenek dělaný kernelem.
- language.c - kód na překlad menu do cizích jazyků.
- listedit.c - obecná implementace seznamů včetně hotových klikátek
pro uživatele. Pak už jen stačí napsat krátký kód jako například pro bookmarky
a bookmarky jsou hotovy. Dá se použít i pro správu jiných věcí, než jsou jen
bookmarky (extensions, asociace, cookies...)
- lru.c - LRU cache na ukládání písmenek.
- mailto.c - slouží k obsluhování <a
href="mailto:...">blabla</a>.
- main.c - tady je main aby se to vůbec dalo spustit. Taky je tu
inicializace a deinicializace všech subsystémů včetně grafického. Prostě
když nějaký *.c má funkci ci dělá inicializaci tak jí to tu většinou
zavolá. Pak je tu taky deinicializace (proces opačný). Není tu
select_loop.
- memory.c - memory management, funkce na alokování a
dealokování paměti, detekce memory leaků atd.
- menu.c - veškerá menu.
- ns.c - kód obsluhující prostor proměnných v javascriptu.
- objreq.c - request objektů, řeší například redirecty a podobně.
- os_dep.c - věci jakkoliv závislé na OS.
- pbm2png.c - zdroják od pbm2png
- pmshell.c - je na úrovni svgalib.c, akorát je na pmshell pod
OS/2.
- pomocny.c - pomocný 200B soubor pro Javascript.
- sched.c - schedulování síťových spojení, včetně keepalive spojení.
- select.c - celý život linkse se odehrává v
select_loop... Tak
tady ji máte.
- session.c - řeší pohyb po dokumentu, historii, nahrávání a
zobrazování dokumentů, cachuje zformátované dokumenty.
- svgalib.c - jako pmshell.c ale pro svgalib.
- terminal.c - veškeré funkce pro práci s terminálem.
- types.c - typy souborů a jejich přípony, volání externích
prohlížečů.
- url.c - parsování URL.
- view.c - zobrazování dokumentů v textovém módu.
- view_gr.c - zobrazování dokumentů v grafickém módu.
- wb02links.c - je zdroják od wb02links
- win32.c - někdo se pokoušel o port na WIN-32, ale je to zabugované.
- x.c - grafický driver pro X-Window System.
- acconfig.h - automaticky se generuje při autoconfu, když se
smaže, musí se znova pustit rebuild.
- cfg.h - includování konfiguračního .h, který vytvoří configure.
- codepage.h - počet znakových sad.
- config2.h - automaticky generované skriptem configure.
- language.h - automaticky generované gen-intl.
- links.h - aby u každého soubor.c nemuselo být soubor.h, tak je
všechno na jedné hromadě a odpadají starosti s vzájemnými inkluzemi.
- os_dep.h - dependence na různé OS, includuje se před standardními libc includy.
- os_depx.h - podobně jako os_dep.h, ale includuje se až po libc includech.
- setup.h - defaultní nastavení. Startovací URL, defaultní
timeouty, barvy menu a dialogů a podobně.
- config.h - automaticky generováno configure.
- tree.h - opcodes mezikódu javascriptu (javascript.y), používá se v generátoru mezikódu a následně v interpretru (ipret.c).
- typy.h - definice typů proměnných javascriptu.
- struct.h - potřebné struktury (zejména js_context, namespace) pro javascript.
Aby program mohl pracovat s rozličnými grafickými zařízeními, bylo navrženo
rozhraní pro grafické drivery. Každý grafický driver obsluhuje jeden grafický
subsystém (SVGAlib, OS/2, X). Na grafickém driveru může být vytvořeno několik
grafických zařízení. V okennich systémech je každé grafické zařízení jedno
okno; v neokenních systémech jsou použita virtuální zařízení - třeba na SVGAlib
je možno virtuální zařízení přepínat pomocí Alt-1 - Alt-0. Za běhu programu může
být aktivní pouze jeden driver, na který ukazuje proměnná drv.
Každý driver je popsán strukturou struct graphics_driver, která má následující
položky:
-
unsigned char *name
-
Jméno driveru.
-
unsigned char *(*init_driver)(unsigned char *param)
-
Inicializuje driver. Vrátí NULL při úspěchu nebo alokovaný řetězec
obsahující
popis chyby při neúspěchu. Na začátku programu se může zavolat init_driver, a na konci
se pak musí shutdown_driver. Po shutdown_driver může následovat další cyklus. Při přechodu do
dalšího cyklu musí být všechny devicy seshutdownované.
-
struct graphics_device *(*init_device)(void)
-
Vytvoří nové zařízení. Může se zavolat víckrat init_device, ale pak se pro každé device
musí zavolat shutdown_device dříve, než se zavolá shutdown_driver.
-
void (*shutdown_device)(struct graphics_device *dev)
-
Ukončí zařízení.
-
void (*shutdown_driver)(void)
-
Ukončí činnost celého driveru. Předpokládá se, že při volání této funkce jsou už
všechna zařízení ukončena a v driveru nejsou registrovány žádné bitmapy ani
barvy.
-
unsigned char *(*get_driver_param)(void)
-
Vrací poitner na řetězec s parametrem funkce init_driver nebo NULL (funkce init_driver
by se měla příště zavolat s tímto parametrem, pokud uživatel neřekne jinak).
Používá se k zapamatování grafického módu, velikosti okna a podobně.
-
int (*get_empty_bitmap)(struct bitmap *dest)
-
Před voláním této funkce jsou vyplněny položky x a y v struct bitmap. Obě musí být >0. V
ostatních jsou odpadky. Funkce
alokuje místo na bitmapu, nastaví hodnoty skip a data, ponechá hodnotu user, může nastavit
flags. Můžeme předpokládat, že
po volání get_empty_bitmap bude zavoláno register_bitmap.
Po get_empty_bitmap
uživatel nesmí šahat na x, y, skip, data, flags. Do user může uživatel
hrabat jak chce - je to jeho.
Návratová hodnota je 0 pokud je bitmapa naalokovaná na heapu, 1 pokud je ve videopaměti
a 2 pokud je v X serveru.
-
int (*get_filled_bitmap)(struct bitmap *dest, unsgned char *pattern, int n_bytes)
- Před voláním této funkce jsou vyplněny položky x a y v struct bitmap. Obě musí být >0. V ostatních jsou
odpadky. Funkce alokuje místo na bitmapu, nastaví hodnoty skip a data, ponechá hodnotu user, může
nastavit flags. Bitmapa bude od výroby už zaregistrovaná a bude vyplněna vzorkem pattern. Patern ukazuje na pole o velikosti n_bytes, bitmapa bude temito byty vyplnena. Muze se (snad) predpokladat, ze n_bytes je stejna hodnota, jako
nastavi graficky driver pro pocet bitu v pixelu.
Bitmapa bude už zaregistrová, takže
dovolené operace na ní jsou: prepare_strip,
unregister_bitmap, draw_bitmap,
draw_bitmaps.
Návratová hodnota je 0 pokud je bitmapa naalokovaná na heapu, 1 pokud je ve videopaměti
a 2 pokud je v X serveru.
-
void (*register_bitmap)(struct bitmap *bmp)
-
Registruje vyplněnou bitmapu. Může (ale nemusí) přenést data bitmapy do videoram
a odalokovat je. Čili po register_bitmap je už pointer ve struct bitmap
neplatný!
-
void *(*prepare_strip)(struct bitmap *bmp, int top, int lines)
-
Připraví bitmapu na zápis vodorovného pruhu co je přes celou šířku
bitmapy. bmp musí být zaregistrovaná bitmapa. top
je první řádek co se bude měnit. length je počet měněnych řádků, musí být >0,
jinak to spadne na segfault. Pruh
nesmí být mimo bitmapu ani trčet nahoře ani dole z bitmapy jinak to má nárok spadnout na segfault. Pointer
co tahle funkce vrátí je pointer na který se má začít zapisovat data a při
zápisu celého řádku se skočí o bmp->skip. Po zavolání
prepare_strip() musí být zavolán právě jednou odpovídající commit_strip().
-
void (*commit_strip)(struct bitmap *bmp, int top, int lines)
-
Commitne změny do bitmapy. bmp musí být připravena pomocí prepare_strip() a
top a lines musí být stejné jako v prepare_strip() jináč to má nárok
spadnout. Po commitnutí se už do bitmapy zase nesmí hrabat.
-
void (*unregister_bitmap)(struct bitmap *bmp)
-
Uvolní bitmapu. Nesahá na bmp->x a bmp->y.
-
void (*draw_bitmap)(struct graphics_device *dev, struct bitmap *hndl, int
x, int y)
-
Nakreslí bitmapu na dané zařízení na danou pozici.
-
void (*draw_bitmaps)(struct graphics_device *dev, struct bitmap **hndls,
int n, int x, int y)
-
Nakreslí několik bitmap za sebe. Všechny bitmapy musejí mít stejnou výšku.
Funkce je tu proto, aby se snížil overhead při volání draw_bitmap.
-
long (*get_color)(int rgb)
-
Alokuje barvu. Parametr je ve tvaru R*65536+G*256+B, kde R, G, B jsou
čísla 0 az 255. Číslo 0 reprezentuje 0 (žádné elektrony do monitoru),
Číslo 255 reprezentuje maximum elektronů do monitoru, co se dá vytřískat
z videokarty. Vrátí handle barvy. Handle
je specifický pro daný driver. Handle může být předáván funkcím pro kreslení čar
a plnění nebo uvolněn pomocí následující funkce. Každý handle musí být uvolněn
před ukončením driveru pomocí free_color.
-
void (*free_color)(long color)
-
Uvolní barvu.
-
void (*fill_area)(struct graphics_device *dev, int x1, int y1, int x2, int
y2, long color)
-
Vyplní daný obdélník danou barvou. Budou vyplněny všechny pixely o
souřadnicích [x,y],
které leží uvnitř ořezávací oblasti a splňují podmínku:
(x>=x1)&&(x<x2)&&(y>=y1)&&(y<y2). Tedy
v případě, že x1<x2 a y1<y2,
x1,y1 v obdélníku bude a x2,y2 tam už nebude.
-
void (*draw_hline)(struct graphics_device *dev, int left, int y, int
right, long color)
-
Nakreslí horizontální čáru. Bod left,y na ní leží, bod right,y na ní neleží. Pokud left<=right, pak je čára prázdná.
-
void (*draw_vline)(struct graphics_device *dev, int x, int top, int
bottom, long color)
-
Nakreslí vertikální čáru. Bod x,top na ní leží, bod x,bottom na ní
neleží. Pokud je top>=bottom, pak je čára prázdná.
-
int (*hscroll)(struct graphics_device *dev, struct rect_set **set, int sc)
-
Scroll. Posune aktuální ořezávanou oblast o sc pixelu doprava (eventuálně
doleva, pokud je sc záporné). Oblast odkryta scrollováním je nedefinovaná.
Návratová hodnota:
0 - program nemusí překreslovat odkrytou oblast, bude
zavolána funkce redraw (viz níže).
1 - program by měl překreslit odkrytou oblast.
Typicky by se hodnota 1 měla vracet na ne-okenních systémech (svgalib,
framebuffer, dos), kde máme jistotu, že po překreslení odkrytého obdélníku bude
obrazovka konzistentní.
Na druhou stranu v okenních systémech (X, OS/2) může být okno, které
scrollujeme, překryto jiným oknem a program neví, které části má překreslit.
Musí mu být tedy grafickým driverem zaslán požadavek redraw.
Pokud set není rovna NULL, obsahuje obdélníky, které je potřeba
překreslit (oblast, která byla přikrytá jiným oknem). Program musí tuto oblast
překreslit sám, grafický driver to neumí.
Kdyby nebylo jasno, co je posunout oblast doprava, tak to je načíst klipovací obdélník,
nakreslit ho na místo které je více vpravo než kde obdélník původně byl. A při kreslení se
samozřejmě klipuje na nastavenou oblast, takže část dat se při tom kreslení zahodí. A část
plochy zůstane původní pro libovolný obsah obdélníku. Toto je odkrytá oblast.
-
int (*vscroll)(struct graphics_device *dev, struct rect_set **set, int sc)
-
Totéž jako hscroll, ale scrolluje oblast nahoru (když je sc záporné) nebo dolů.
-
void (*set_clip_area)(struct graphics_device *dev, struct rect *r)
-
Nastaví oblast pro ořezávání. Veškeré funkce budou pracovat pouze na této
oblasti. struct rect má položky x1, x2, y1, y2, což jsou souřadnice oblasti. x1,y1 patří
do clip_area, x2,y2 tam již nepatří.
-
int (*block)(struct graphics_device *dev)
-
Vrati puvodni textovy videomod, vrati handlovani mysi a
klavesnice a zajisti, ze kreslici funkce nebudou uz nic kreslit (to jde
zajistit celkem jednoduse -- mas tam uz makro TEST_INACTIVITY a promennou
current_virtual_device).
Pokud se ti zavola block a ty jses uz zablokovany (predtim bylo zavolano
block a jeste nebylo zavolano unblock), tak nedelas nic a vratis 1. Jinak
vratis 0.
Pro drivery, kde neni potreba blokovat terminal pri pousteni externich programu
(X, Pmshell), tahle funkce vraci 0 a nedela nic.
-
void (*unblock)(struct graphics_device *dev)
-
Obnovi zpet graficky mod, klavesnici a mys, a nakonec zavola
redraw_handler -- cili prekresleni cele obrazovky.
Musi se brat v potaz, ze graphics_device,
na kretem se ten externi program pustil (a tedy to, co dostanes jako
parametr) muze byt jiny, nez aktualni grapgics_device. Takze budes
prekreslovat radsi current_virtual_device, pokud je nenulovy.
-
int depth
-
Barevná hloubka:
bity 0-2 - počet bytů na pixel. Pixely chodí do bitmapového zobrazovače
tak, že každý pixel okupuje celý počet bytů, a žádný byte není okupován
dvěma pixely. Proto např. 1 bit na pixel se nekóduje jako 8 pixelů na
byte, ale každý byte obsahuje jeden pixel a tudíž 7 bitů v byte je pak
nevyužitých. V případě, že v obrazové paměti jsou pixely v bytech nějak
úchylně nasekány, musí je zobrazovač překódovávat.
bity 3-7 - počet bitů na pixel - 1, 4, 8, 15, 16, 24
bit 8 - misordered -
to je flag ve svgalibě, který říká, že karta místo layoutu RGBRGBRGB má
BGRBGRBGR, a některé ostatní layouty mohou být také podobně otočeny. Interní
informace grafického driveru, kterou používá pro správnou konstrukci barevných
dat z r,g,b.
bit 9 - misordered2. Pro 4 byty na pixel jsou 3 různé možné paměťové organizace.
Tento bit je zde proto, že jen bit 8 by to nemohl rozlišit.
Zde je definice paměťové organizace pro jednotlivé podporované depth.
depth, které nejsou v tabulce, jsou nepodoporované. Všechny depth v
tabulce jsou podporované dither.c. V tabulce pokud například červená má
barevnou hloubku 5, pak R0 je nejméně významný bit a R4 nejvíce významný
bit červeného kanálu.
Bity v bajtu jsou číslovány: 0 má váhu 1, 7 má váhu 128.
| depth deka |
depth hexa |
Barevná hloubka |
Paměťová organizace: offset bytu v
paměti |
| +0 |
+1 |
+2 |
+3 |
| R | G | B |
7 |
6 |
5 |
4 |
3 |
2 |
1 |
0 |
7 |
6 |
5 |
4 |
3 |
2 |
1 |
0 |
7 |
6 |
5 |
4 |
3 |
2 |
1 |
0 |
7 |
6 |
5 |
4 |
3 |
2 |
1 |
0 |
| 33 | 0x21 | 1 | 2 | 1 |
| | | |
R0 | G1 | G0 | B0 |
| 65 | 0x41 | 3 | 3 | 2 |
R2 | R1 | R0 | G2 |
G1 | G0 | B1 | B0 |
| 122 | 0x7A | 5 | 5 | 5 |
G2 | G1 | G0 | B4 |
B3 | B2 | B1 | B0 |
| R4 | R3 | R2 |
R1 | R0 | G4 | G3 |
| 130 | 0x82 | 5 | 6 | 5 |
G2 | G1 | G0 | B4 |
B3 | B2 | B1 | B0 |
R4 | R3 | R2 | R1 |
R0 | G5 | G4 | G3 |
| 195 | 0xc3 | 8 | 8 | 8 |
B7 | B6 | B5 | B4 |
B3 | B2 | B1 | B0 |
G7 | G6 | G5 | G4 |
G3 | G2 | G1 | G0 |
R7 | R6 | R5 | R4 |
R3 | R2 | R1 | R0 |
| 196 | 0xc4 | 8 | 8 | 8 |
B7 | B6 | B5 | B4 |
B3 | B2 | B1 | B0 |
G7 | G6 | G5 | G4 |
G3 | G2 | G1 | G0 |
R7 | R6 | R5 | R4 |
R3 | R2 | R1 | R0 |
0 | 0 | 0 | 0 |
0 | 0 | 0 | 0 |
| 451 | 0x1c3 | 8 | 8 | 8 |
R7 | R6 | R5 | R4 |
R3 | R2 | R1 | R0 |
G7 | G6 | G5 | G4 |
G3 | G2 | G1 | G0 |
B7 | B6 | B5 | B4 |
B3 | B2 | B1 | B0 |
| 452 | 0x1c4 | 8 | 8 | 8 |
0 | 0 | 0 | 0 |
0 | 0 | 0 | 0 |
B7 | B6 | B5 | B4 |
B3 | B2 | B1 | B0 |
G7 | G6 | G5 | G4 |
G3 | G2 | G1 | G0 |
R7 | R6 | R5 | R4 |
R3 | R2 | R1 | R0 |
| 708 | 0x2c4 | 8 | 8 | 8 |
0 | 0 | 0 | 0 |
0 | 0 | 0 | 0 |
R7 | R6 | R5 | R4 |
R3 | R2 | R1 | R0 |
G7 | G6 | G5 | G4 |
G3 | G2 | G1 | G0 |
B7 | B6 | B5 | B4 |
B3 | B2 | B1 | B0 |
-
int x, y
-
Velikost obrazovky - pouze pro drivery, které používají virtuální
zařízení. Protože se u okenního systému může stát, že každé okno bude
jinak veliké, neboť uživatel může okénka resizovat.
-
int flags
-
Flagy, které nastaví grafický driver v init_driver. Vzniknou zORováním některých z následujících konstant:
- GD_DONT_USE_SCROLL - scroll je pomalý a vyplatí se volat kompletní
překreslení místo scrollu. Program by tedy pokud možno neměl používat scroll a měl
by překreslovat celou situaci.
- GD_NEED_CODEPAGE - kódování klávesnice nemůže být zjištěno ze
systému, kódování se tedy bere podle proměnné codepage, kterou uživatel
může nastavit v menu.
-
int codepage
-
Kódová stránka klávesnice.
Struktura graphics_device má následující položky:
-
struct rect size
-
Velikost zařízení. size.x1 == 0, size.y1 == 0, size.x2 a size.y2 obsahují
aktuální velikost okna.
-
struct rect clip
-
Aktuální ořezávací oblast. Program může tuto položku číst, ale nesmí
tam zapisovat. Změna ořezávací oblasti se dělá přes set_clip_area.
-
struct graphics_driver *drv
-
Driver, ke kterému zařízení náleží.
-
void *driver_data
-
Data soukromá pro grafický driver. Program by na to neměl sahat.
-
void *user_data
-
Data soukromá pro program. Grafický driver by na to neměl sahat.
-
void (*redraw_handler)(struct graphics_device *dev, struct rect *r)
-
Sem si program uloží pointer na funkci, kterou driver zavolá, když bude potřeba
překreslit část obrazovky. redraw se nevolá při inicializaci okna. Jestli
se redraw volá při přepnutí grafické konzole, to nevím, to ví Mikuláš.
-
void (*resize_handler)(struct graphics_device *dev)
-
Sem program uloží funkci, kterou driver zavolá, když je změněna velikost
zařízení.
-
void (*keyboard_handler)(struct graphics_device *dev, int key, int
flags)
-
Sem program uloží funkci, kterou driver zavolá, když je zmáčknuta klávesa.
Parametr key je konstanta typu KBD_xxx nebo UNICODE kód klávesy. KBD_CTRL_C se
posílá při stisknutí ctrl+c v programu, ne však při zavření okna v okenním
systému (windowmanagerem). Při KBD_CTRL_C se může objevit dialog, jestli chce
uživatel opravdu končit. KBD_CLOSE je poslán při požadavku o zavření okna (z
windowmanageru), program se ukončí bez dalšího ptaní lusera. flags obsahuje
zORované následující konstanty: KBD_SHIFT, KBD_CTRL, KBD_ALT. KBD_SHIFT se
posilá pouze pro speciální klávesy (enter, šipky ...), ne pro písmena nebo
ascii znaky.
-
void (*mouse_handler)(struct graphics_device *dev, int x, int y, int
buttons)
-
Sem program uloží funkci, kterou driver zavolá, když je pohnuto s myší.
buttons obsahuje zakódovaná tlačítka. Tlačítka se kódují ORováním jedné
konstanty z každé následující skupiny. B_LEFT, B_MIDDLE, B_RIGHT, B_WHEELUP,
B_WHEELDOWN, B_WHEELUP1, B_WHEELDOWN1 - tlačítka. U kolečka se posílá vždy akce
B_MOVE. B_WHEELUP1 a B_WHEELDOWN1 znamená posunutí o 1 řádek (16 pixelů), používá se na
OS/2, kde lze nastavit počet eventů na otočení kolečka. B_WHEELUP a B_WHEELDOWN znamená
scroll kolečkem o více řádků (64 pixelů), používá se v X a SVGAlib. B_DOWN, B_UP, B_DRAG,
B_MOVE - akce: tlačítko bylo zmáčknuto; tlačítko bylo puštěno; tlačítko je zmáčklé a
pohnula se myš; myš se pohybuje (v tomto případě se kód tlačítka ignoruje), . Pro
přístup k jednotlivým skupinám slouží masky BM_BUTT a BM_ACT. Jestliže je zmáčknuto více
tlačítek, posílají se sekvenčně v pořadí v jakém přišly driveru eventy, v případě B_DRAG
platí vždy poslední zmáčklé tlačítko.
Poslední 4 funkce volá driver, když došlo k nějaké události. Aby se předešlo
race-conditionům, musí být funkce volány z bezpečného místa - t.j. z
handlerů
vytvořených v modulu select.c.
Grafický driver nesmí tyto funkce volat ze svých funkcí volaných z programu.
Například, když program zavolá hscroll, grafický driver nesmí
volat redraw rovnou z kontextu hscroll, ale musí si na to registrovat buď
bottom half nebo timer s časem 0. Kdyby to volal rovnou, tak by v programu
vzniklo rekurzivní volání, a to by nevedlo k ničemu dobrému.
Virtuální devicy jsou metoda, jak na jednu obrazovku fyzickou umístit několik
obrazovek virtuálních přepínaných pomocí nějakých kláves (na svgalib je to Alt-1
až Alt-0). Používají se u neokenních systémů (svgalib), protože uživatel typicky
chce browsit v několika oknech současně. Tvůrce grafického driveru nemusí
virtuální devicy používat, ale pak si bude muset funkce pro správu deviců napsat
sám.
-
int init_virtual_devices(struct graphics_driver *drv, int n)
-
Zavolá se typicky z init_driver. Naalokuje n virtuálních zařízení.
Návratová
hodnota: 0 - OK.
-
void shutdown_virtual_devices()
-
Zavolá se z shutdown_driver. Odalokuje paměť pro virtuálni devicy
-
struct graphics_device *init_virtual_device()
-
Dá se jako funkce init_device do struktury graphics_driver.
-
void shutdown_virtual_device(struct graphics_device *dev)
-
Dá se jako funkce shutdown_device do struktury graphics_driver.
-
void switch_virtual_device(int i)
-
Přepne virtuální device na device s číslem i. Nastaví current_virtual_device a
pak tomuto devicu pošle redraw. Typicky se tato funkce volá z handleru
klávesnice grafickeho driveru. Pokud driver zjistí, že stisknutá klávesa má
přepnout virtual device, klávesu nepředává dál programu, ale zavolá
switch_virtual_device.
-
struct graphics_device *current_virtual_device
-
Proměnná ukazuje na virtual device, který je aktuálně zvolený (může být i NULL).
V každé funkci grafického driveru, která něco kreslí, by se mělo zjistit, zda
device, na který se má kreslit == current_virtual_device, a pouze v takovém
případě kreslení provést. Jinak se budou do obrazu prolínat kusy grafiky z
neviditelných deviců, což může, ale nemusí působit esteticky.
Formát obrazových dat je charakterizován jednotlivými přítomnými kanály,
jejich hloubkou, paměťovou organizací a gammou (alpha nemá gammu).
- alpha, 8 bit je výstupní formát generátoru písmenek.
- red, green, blue, 16 bit, data úměrná osvětlení vycházejícímu z monitoru
uživatele je formát vystupující z img.c do dither.c při kreslení obrázků.
Je to také výsledný formát při dekódování obrázků v případě, že obrázek nemá alphu.
Pokud se škáluje, výstupem škálovače je také tento formát.
- red, green, blue, alpha, 16 bit, data úměrná osvětlení vycházejícímu
z monitoru je formát vystupující z dekodéru obrázků v případě, že obrázek
má alphu. Pokud se škáluje, výstupem škálovače je také takovýto formát.
Tento program vyrábí z
arrow.png (který je ve formátu PNG, kde barvy číslo 0,1,2 udávají
šipečku, okolí a průhlednost) do arrow.inc, který obsahuje řady
32-bitových čísel, pro šipečku i pro její průhlednostní masku. Šířka šipečky
musí být 32 pixelů.
Tento program vyrábí černě až bíle vybarvenou obrazovku, v 256 stupních.
Pracuje v truecolor režimu 640x480x16M. Používá se k měření gamma monitoru
pomocí měřiče světla (hardwarového to zařízení).
Obsahuje texty o různých barvách. Vhodné pro testování linkse v grafickém
režimu, zejména ditherování, zmenšování písmenek a správné gammy.
Ořeže boxy z pngček - písmenek pro linkse. Volá pomocný program improcess.
Vezme soubory v
adresáři font a vyrobí z nich soubor font_include.c, který se přikompiluje
do linkse a obsahuje interní strukturu obsahující font ve formátu PNG.
Tato data jsou tím pádem uložena ve spustitelném souboru links a
uživatel není obtěžován žádnými dodatečnými datovými adresáři, čímž se
silně zvyšuje přenositelnost celého systému (nebylo jasné, kam by se měly
tyto soubory umisťovat, neboť takováto místa vhodná pro umisťování těchto
souborů jsou silně závislá na konkrétním typu systému a vznikaly by s tím
jen problémy). Fonty se do systému přidávají tak, že se přidá do
adresáře font, pak se pustí generate_font a pak se překompiluje
links příkazem make.
Je určen k výrobě linksových fontů z fontů v Ghostscriptu. Vyrobí
soubor letters.ps, který obsahuje všechna písmena od 0 do 255
tohoto fontu, přičemž kolem nich jsou boxy pro správné oříznutí. Tento
program není určen pro ruční spouštění.
Uvnitř zdrojáku genps.c uživatel může nastavit proměnné
h_margin, v_margin, font_pos, font_height, paper_height. Viz následující
obrázek:

paper_height musí odpovídat výšce papíru, která je nastavena v pdf2html,
tedy A4 (není důvod to měnit), což je 297. rozměrem těchto všech
proměnných je 1 milimetr.
Program improcess představuje nástroj pro základní manipulace s
černobílými obrázky PNG. Program nahraje obrázek, provádí na něm unární
operace (není tedy možno kombinovat dva obrázky do sebe) a nakonec jej
uloží do souboru. syntaxe je improcess infile cmdfile outfile,
kde infile je původní obrázek, outfile nový a cmdfile soubor s příkazy.
infile může být totožné s outfile, k destrukci dat při tom nedojde.
cmdfile obsahuje řádky, kde každý řádek definuje jeden příkaz. Příkazy
jsou tvaru příkaz argument argument ..., kde argument může být pouze
znaménkové decimální nebo hexadecimální (s 0x prefixem) číslo. Šedé tóny
jsou reprezentovány čísly typu int, kde 0 je černá, 0xffffff bílá a při
operacích je možno vyjet až do rozsahu -0x80000000 až 0x7fffffff, přičemž
dále dojde k přetečení a nedefinovanému stupni šedé. Čísla
v argumentu udávající barvu se řídí také touto konvencí. Program umí
následující příkazy:
- clip - ořeže do rozsahu mezi černou a bílou.
- threshold level - prahování. Pokud je pixel >= level, pak se
vybělí,
jinak se vyčerní.
- flip - transpozice. Prohodí se levá a horní hrana obrazu.
- append lines value - přidání řádků. Přidá lines řádků dospod obrazu,
které budou vyplněny barvou value.
- detract lines - odstranění řádků. Odstraní lines řádků zespoda
obrazu
- mirror - zrcadlení. Prohodí levou a pravou hranu obrazu.
- blurbox pixels - krabicové rozmazání. Provede konvoluci krabicovým konvolučním jádrem o
výšce 1 pixel, šířce 2*pixels+1 centrovaném na počátku souřadné
soustavy.
- gaussian repeat pixels - gaussovské rozmazání. Provede repeat-krát blurbox pixels.
- * multiplier - násobení. Vynásobí všechny pixely hodnotou multiplier.
- / divisor - dělení. Vydělí všechny pixely hodnotou divisor.
- + value - přičítání. Přičte k obrazu hodnotu value.
- >> shift - posuv doprava. Vynásobí obraz 2^-shift.
- << shift - posuv doleva. Vynásobí obraz 2^shift.
Neplatný příkaz bude ignorován a bude se pokračovat v provádění. Před
uložením do souboru musejí být všechny pixely mezi černou a bílou,
budou-li mimo tento rozsah, jejich hodnota v souboru bude nedefinovaná.
Typické použití programu je pro ztluštění nebo ztenčení písmenek, které
se provede gaussovským rozmazáním, vynásobením, přičtením a ořezáním.
Je shellový skript, který vyrobí font do adresáře ./font/,
přičemž typ fontu je definován v souboru Fontmap. Musí se
spouštět z adresáře, ve kterém jsou zdrojáky linkse. Je určen k ručnímu
spouštění. Na systému musí být nainstalován Ghostscript.
Vyrábí z toku dat ve formátu více zkonkatenovaných souborů pbm (což je
přesně formát který teče z ghostscripta ve skriptu
pdf2html) sérii pngček 17-násobným vodorovně a 15-násobným svisle
převzorkováním. Není určen pro ruční spouštění.
Je skript, který vyrobí z *.pdf nebo *.ps sérii pngček.
Provádí převzorkování 15-násobné svisle a 17-násobné vodorovně do 8-bitové
stupnice šedé. Výstupní gamma je 1.0. Vystupni obrazek obsahuje chunk gAMA
(informace o gamma obrazku) a tento je nastaven na 1.0. Volá program pbm2png.
Smaže tohle.
Slouží k převodu souboru font_cache.dat z wb0 na soubor pngček
vhodných jako font pro Linkse. Musí se nainstalovat wb0, pak pustit wb0
-h100 nebo kolik chceme (takhle to bude vysoké 100 pixelů) a wb0
vytvoří ve svém pomocném adresáři soubor font_cache.dat.
Pak pustíme wb02links, přičemž font_cache.dat musí být v aktuálním
adresáři. Vygenerují se nám pngčka do adresáře ./font/.
- Spustitelné programy ve formátu elf, core, *.o, *.core. To za nás udělá make
clean
- Adresář .deps
- Makefile, Makefile.in
- aclocal.m4
- config.h, config.h.in, config.log, configure, config.cache
- autoh*, ale to se při používání rebuild a nepouštění
autoheader ručně nevyskytuje
- *.swp, když jsme hodně prasili
- .links_svga_modeinfo
- config.status
- letters.ps
Když pustíte purge, smaže se všechno tohle, kromě těch
*.swp.
- bfu.c
- memory.c
- links.c
- Adresář font, v něm všechny soubory ????.png
- A mnoho dalších
- Nejsou zde uvedeny bugy v Linksu, neboť ten je přece psán technologií
BugFree(TM), a tak tam z principu žádné být nemohou.
- Některé staré libpng neumí zpracovávat určité druhy (ty exotičtější)
pngček, protože v nich chybí funkce pro rozhraní k vlastnostem, které tato
pngčka mají. Proto links v případě, že je zkompilován s takto vadnou
libpng, toto automaticky díky autoconfu pozná a v případě že na takové png
narazí, spadne s hláškou, aby si uživatel pořídil lepší libpng. Proto je
nutno používat rozumně novou libpng.
- Některé vadné stránky postrádají druhou uvozovku za klikacím tlačítkem
Odešli, takže se tam toto nezobrazí a uživatelé si stěžují na špatné adrese.
- Ve svgalib je velmi špatně napsán kód pro primitivní operace v
16-barevných módem a 2-barevných módech, takže tyto módy jedou pomalu - může za to
svgalib a nikoliv Links.
- svgalib před 1.9.4 musí být suid root a za to links taky nemůže. Nová
svgalib již má v kernelu modul, a uživatelský program je pak neškodný.
- libpng zhruba před 1.2.0 obsahovala bugu v MMX optimalizovaném kódu,
která způsobovala, že když libpng byla zkompilovaná s optimalizací pro MMX
a zobrazila určitý obrázek z testovacího kitu na PNGčka, Links spadnul na
segfault, protože se celý adresní prostor přepsal opakující se konstantní
hodnotou.
Javascript může hackovat do objektů - a to zejména do jakéhokoliv html
tagu (tzn. změny barev, linků pod rukama... lze vytvářet nová okna).
Jak je to s vytvářením nových linků jsem zatím nenašel.
Méně příjemná věc, kterou jsem zpozoroval je, že skript může hackovat do
okna - přes objekty document a window. Bude potřeba důkladně navrhnout, jak
javascriptu umožníme zapisovat do dokumentu přes
document.write("<A href="odkaz.html">text odkazu</a>");
vytvořit nový link a pak pod něj zapisovat.
Prostě ten text, co se bude vypisovat přes write, se musí protáhnout html
parserem!
Scriptové příkazy mimo funkci, tj. napsané jako main v Pascalu se provádějí
sekvenčně (v pořadí, v jakém jsou v dokumentu za sebou), neukončeny skript
v Netscapovi neproběhne (musí se začínat <script> a skončit
</script>). Jakmile to druhé chybí, tak se ten kus skriptu
neprovede.
Objekt navigátor - bude mít vlastnosti spojené s navigací, zařídí PerM.
Vložené funkce se při parsování nejvýše syntakticky a sémanticky rozeberou -
neexistuje nic jako funkce autoexec, ale místo toho se provádí kód mimo funkční
definice, tudíž by bylo patrně nejlepší udělat parsování skriptů rovnou při
nahrávání (rychlejší interpretace a pak můžu účinněji zasáhnout když zjistím
malér). Kromě toho: Je třeba funkce Settimer, která za nějaký čásek pošle údaj
o tom, že přišla událost vyprchání času... Budu tedy muset být schopen
rozhodnout, jestli přišel timeout, nebo jestli přišla jiná událost jako třeba
mouseclick... Ještě je třeba chytat události na objektech - kdy se kde pohybuje
myš, kdy se s ní cvaklo... kdy se dvojclicklo...
Objekt history - archivuje, kde jsme byli - nemělo by být těžké to udělat:
Je možno zavolat Go back.
Javascript umí měnit i obsahy různých framů, tedy:
Je otázka, jestli se mi mají posílat všechny události, které se staly,
nebo jestli si mám já říct o události, které mě zajímají a nechat
si ohlásit jenom ty. Druhé řešení by možná bylo lepší, protože by nebylo
kvůli nevýznamným událostem nutné volat mé handlery.
Javascripty umí taky procmailovat. V normě to však není, takže
to patrně nepodpoříme.
Reagovat lze na Abort - onAbort,
onBlur,onChange - textová políčka, seznam vúběrů...,
onClick,onDragDrop,onError,onFocus - windows and all.
Aktuální seznam není nikde snadno k dispozici, zkusíme vydumpovat
kde co je v nějaké verzi Netscape Navigatora a položky, které se podaří
zdokumentovat implementujeme. Norma Javascript 1.1 popisuje úplně jiné
rozhraní, než je ve skutečnosti implementováno. Tudíž bude potřeba asi
udělat něco mezi tím.
Multitask javascriptu je kooperativní, tzn. že
dokud skript běží a nevolá nějakou funkci, tak je nepřerušitelný - viz
PerMova kalkulačka vylepšená někde na PerMových stránkách. Ve chvíli, kdy je spuštěna
funkce Settimeout, je skript pozastavený a tudíž je možno spustit něco jiného.
Pak přijde událost, nasadí proces zpátky na koleje.
Netscape Navigator má zajímavý option, že když se spustí
program:
<script language="javascript">
while(1);
</script>
tak je potřeba celého Navigatora zabít, jelikož javascript v Netscape
Navigatorovi není přerušitelný. To je poněkud pofidérní vlastnost,
tu bych odstranil zaschedulováním po každém statementu (pokud se to ukáže
jako moc časté, tak třeba jednou za 100 statementů).
Jinými slovy my uděláme multitasking "částečně preemptivní", tedy tak, aby
nešlo dvakrát spustit stejný skript přes sebe, ale dva různé skripty ano.
O multitaskingu se v normě javascript 1.1 nic nepíše, tudíž předpokládám,
že si jej lze udělat dle vlastního uvážení
Toto by si měl přečíst každý, kdo do Linkse bude něco programovat.
Links je psán celý v C, C++ se nepoužívá. Links je psán tak, aby byl
zkompilovatelný klasickým ANSI C bez GNU rozšíření. Je třeba dát pozor na
následující rozšíření, která sice projdou v gcc, ale neprojdou v ANSI C
(a kterých byl původní links plný a dostával jsem na to stížnosti):
-
C++ komentáře
-
// tohle v cc neprojde
/* je potřeba používat tyto komentáře */
-
Label na konci bloku
-
fn()
{
nějaký kód....
label:
}
Je třeba nahradit
fn()
{
nějaký kód....
label:;
}
-
Inicializace struktur nekonstantními výrazy
-
struct bla {
int a, b;
};
int a1, a2;
fn()
{
struct bla x = {a1, a2};
}
K otestování přenositelnosti linksu na ANSI C je třeba ho nahrát na Solarisy
nebo Irixy na Malé Straně a napsat (za současného modlení aby na Irixu
nespadl slabostí kernel)
export CC=cc
./configure
make
Pak se to bude kompilovat ANSI C místo GNU C. Vypise to spoustu warningů, ale
výsledný kód je funkční.
Napíšeme foo.c. Přidáme do Makefile.am do řádku links_SOURCES foo.c a
na začátek foo.c dáme #include "cfg.h" a #include
"links.h".
configure.in je shell script, ve kterém jsou makra. Makra jsou procesorem
m4 expandována na další příkazy shellu (jak psát portabilní
shell skripty se dočtete v info autoconf). Řetězce se v m4 dávají do [ hranatých
závorek ]
Nejčastěji používaná makra:
-
AC_DEFINE(SYMBOL)
AC_DEFINE(SYMBOL, HODNOTA)
-
definuje SYMBOL v config.h (např. AC_DEFINE(CHCEME_FLEXI_LIBU)). Symbol
se také musí vyskytovat v souboru acconfig.h (nevím proč).
-
AC_TRY_LINK(includy, tělo_main, úspěch-skript, neúspěch-skript)
-
vyrobí program, který bude na začátku obsahovat includy, pak main(){ a
tělo main a pak ukončovací }. Pokusí se program slinkovat, pokud se to
povede, vykoná úspěch-skript, jinak neúspěch-skript.
-
AC_CACHE_CHECK(hláška, ac_cv_proměnná, skript)
-
pokud je ac_cv_proměnná v config.cache, tak ji nahraje z té cache; jinak
vykoná skript. Předpokládá se, že skript nastaví ac_cv_proměnnou. Ta je
uložena do config.cache a při dalším puštění se už skript nevyvolává.
Další makra - viz info autoconf.
Nesmí se předpokládat, že sizeof(int) == sizeof(void *). Neplatí to na
Alphě. Je možno předpokládat, že sizeof(int) <= sizeof(void *) <=
sizeof(long).
char je na některých systémech signed a na některých (třeba ty IRIXy na Malé
Straně) unsigned. Aby se zabránilo chybám (jaké v původním linksu taky skutečně
byly), tak se před každý char bude psát
unsigned. char bez specifikace se v kódu vyskytnout
nesmí, signed char se
může použít, když je znaménko potřeba.
Nepoužívat malloc, realloc, free. Místo toho používat
mem_alloc, mem_realloc, mem_free. Tyto funkce mají navíc kontrolu
na memory leaky. Když se vyskytne leak, tak se při ukončení napíše soubor a
řádek, kde se příslušná paměť alokovala, a dumpne se core.
mem_alloc nikdy nevrátí NULL. Vstup nesmí být 0.
mem_calloc - je jako mem_alloc, ale vynuluje blok.
mem_realloc - je místo reallocu.
mem_free - nesmí se volat s argumentem 0.
mem_alloc, mem_realloc, mem_free není možno používat v threadech.
Následující funkce je třeba volat při různých chybových stavech.
f/printf by se pokud možno nemělo používat vůbec - třeba jednoho
dne bude potřeba zpracovávání chyb změnit.
-
void error(unsigned char *str, ...)
-
Syntax je jako u printf. Vypíše chybové hlašení. Používá se k ošetřování různých
vnějších chyb, jako třeba, že došla paměť (je voláno přímo z
mem_realloc). Kód
pokračuje za funkcí.
-
void debug(unsigned char *str, ...)
-
Vypíše DEBUG MESSAGE at file:line: str... a zastaví běh na jednu
sekundu, aby bylo možno zprávu přecíst. Syntax je jako printf.
Používá se při debugování, neměla by se vyskytnout nikde ve výsledném
kódu.
-
void internal(unsigned char *str, ...)
-
Pro ošetřování "can't happen" situací. Funkce vypíše hlášení
INTERNAL ERROR at
file:line: str..., zastaví browser a způsobí core dump. Syntax je jako
printf.
Pokud si je člověk jist, že nějaká podmínka má platit, ale že by platit
nemusela, pokud se někde vyskytl bug, měl by tuto podmínku otestovat, a pokud
neplatí zavolat internal. Čím dřív se bug zachytí, tím líp se hledá, proto by
se tato funkce měla hojně používat. Funkce se může (a měla by se) vyskytovat ve
výsledném hotovém kódu. Možná bysme ji mohli odstranit leda tak v té verzi k
obhajobě.
-
void do_not_optimize_here(void *p)
-
Nedělá vůbec nic. Slouží jen k oblbnutí překladace, aby neprováděl optimalizace.
Ano - i gcc 2.7.2.1 má bugy v optimalizaci.
-
unsigned char upcase(unsigned char chr)
-
Převede znak na velká písmena.
-
int casecmp(unsigend char *s1, unsigned char *s2, int len)
-
Jako memcmp, ale ignoruje velikost písmen. Je taky zaručeno (což
v memcmp
není!), že nebude sahat za první neshodující se byte, takže je možné použít k
porovnávání začátků řetězců.
-
unsigned char *stracpy(unsigned char *str)
-
Zkopíruje řetězec do nově alokovaného místa. Výsledek je nutno po použití
uvolnit pomocí mem_free.
-
unsigned char *memacpy(unsigned char *str, int n)
-
Zkopíruje n bytů ze str do nově alokované paměti, přida nulu na konec a
vrátí
pointer.
-
void add_to_strn(unsigned char **str1, unsigned char *str2)
-
Realokuje řetězec str1 a zkopíruje na jeho konec str2. str1 je pointer na
pointer na řetězec - může se změnit při realokaci. Není to moc rychlé,
lepší
použít následující funkce.
Následující funkce patří k sobě a mohou být používány pouze na řetězcích
vytvořených pomocí init_str().
Datová struktura reprezentuje posloupnost znaků, z nichž žádný není nulový
(tedy to, co se mysli pod pojmem řetězec v jazyce C). Instance této struktury
je definována ukazatelem a délkou. Délka je vždy >=0, a vyjadřuje počet těch
znaků, které jsou reprezentovány. Ukazatel je vždy !=NULL. Podíváme-li se do
paměti, na kterou ukazuje ukazatel, uvidíme tam obsah této datové struktury, za
kterým bude nulový znak (terminátor), a na další obsah této paměti se již nesmí
koukat. Ukazatel vždy vznikl z mem_alloc nebo mem_realloc. Destrukce struktury
se provádí tak, že se zavolá mem_free na ukazatel. Konstrukce se nesmí dělat
pokoutně, musí se použít init_str().
Datová struktura je implementována exponenciálni prealokací o základu 2. Kód těchto funkcí je
v souboru links.h.
-
unsigned char *init_str()
-
Alokuje řetězec pro použití dalších funkcí. Vrácený pointer
reprezentuje prázdný řetězec.
-
void add_to_str(unsigned char **str, int *len, unsigned char *str2)
-
Přidá řetězec str2 na konec řetězce str. Řetězec str musel být alokován
pomocí
init_str().
-
void add_bytes_to_str(unsigned char **str, int *len, unsigned char *str2,
int len2)
-
Jako add_to_str, ale přidá len2 bytů z adresy str2. Byty z adresy str2 nebudou
odalokovány.
-
void add_char_to_str(unsigned char **str, int *len, unsigned char
chr)
-
Přidá jeden znak.
-
void add_num_to_str(unsigned char **str, int *len, int num)
-
Přidá číslo v dekadickém zápise.
-
void add_knum_to_str(unsigned char **str, int *len, int num)
-
Přidá číslo v "lidsky čitelném zápise", čili s použitím
písmenek "k" (kilo) a "M" (mega). Kilo vyjadřuje 1024 a mega vyjadřuje 1048576
(což je 1024*1024). Jinak je to stejné jako add_num_to_str.
Typické použití těchto funkcí vypadá asi takto. Je to poměrne efektivní,
protože
funkce dělají prealokaci (exponencialni) a tak nevolají realloc při každém
přidání.
{
int l = 0;
unsigned char *str = init_str();
add_to_str(&str, &l, "Text:");
add_chr_to_str(&str, &l, ' ');
add_num_to_str(&str, &l, 10);
printf(str);
mem_free(str);
}
Toto je špatně:
{
int l = 5;
unsigned char *str = stracpy("12345");
add_to_str(&str, &l, "bla");
}
Funkce stracpy nedělá potřebnou prealokaci, takže to bude střílet
do paměti.
Pokud nějakou strukturu chceme řetězit v seznamu, musíme zajistit, aby
první dva
prvky té struktury byly pointery na next a prev. Pokud budou položky
next a prev
na jiném místě, bude se do struktury střílet!
struct polozka_seznamu {
struct polozka_seznamu *next;
struct polozka_seznamu *prev;
/* a tady jsou uz dalsi volitelne polozky */
int a, b;
unsigned char c;
}
Hlavu seznamu deklarujeme takto:
struct list_head hlava_seznamu = { &hlava_seznamu, &hlava_seznamu };
-
add_to_list(hlava_seznamu, polozka_seznamu)
-
Přidá položku do seznamu.
-
add_at_pos(prvek_v_seznamu, položka_seznamu)
-
prvek_v_seznamu je už zařazen v nějakém seznamu, makro přidá položka_seznamu do
seznamu za příslušný prvek.
-
foreach(proměnná, hlava_seznamu)
-
Expanduje se jako for cyklus, který pro proměnnou projde všechny prvky seznamu.
Tělo cyklu nesmí smazat aktuální prvek.
-
foreachback(proměnna, hlava_seznamu)
-
Jako foreach, ale projde seznam pozpátku.
-
free_list(hlava_seznamu)
-
Zavolá mem_free na všecky prvky seznamu a seznam vyprázdní.
-
int list_empty(list_head)
-
Vrátí 1, pokud je seznam prázdný. Jinak vrátí nulu.
Textový / grafický mód
Links má běžet v textovém i grafickém módu. Zkompilovat jde buď jen pro textový
mód nebo pro textový i grafický mód (./configure --enable-graphics). V grafickém
módu se pouští s parametrem -g.
Kód by měl být psán tak, aby uživatele, kteří chcou pouze textový prohlížeč
nebyli zatěžováni spoustou grafických funkcí. Textový prohlížeč by měl zůstat
rozumně malý.
Pokud je links zkompilován pro textový i grafický mód, je definováno makro G.
Proměnná F určuje, zda links právě běží v textovém(0) nebo grafickém(1) módu.
Pokud byl links zkompilován pouze pro textový mód, je F makro, které je
definované na hodnotu 0. Typický kód, mající se rozdvojit podle módu, vypadá
takto:
if (!F) {
kód pro textový mód...
#ifdef G
} else {
kód pro grafický mód...
#endif
}
Existují další makra pro usnadnění rozhodování:
-
gf_val(x, y)
-
Vrátí hodnotu x, pokud běží browser v textovém módu, y, pokud běží v grafickém.
-
NO_GFX
-
Zavolá interní chybu, pokud běží browser v textovém módu. Lepší zavolat interní
chybu, než pak spadnout při sahání na neinicializované struktury...
-
NO_TXT
-
Zavolá interní chybu, pokud běží browser v grafickém módu.
Tento odstavec popisuje, jak font ve formátu *.pfb, *.afm, *.pfa
(nebo jeho části) přidat do prohlížeče Links. Vstupem procedury je
font ve formátu, který je schopen přečíst Ghostscript a výstupem sada
obrázků ve formátu PNG, které se přidají do adresáře
graphics/font/<jméno fontu>.
Přidávání fontů je poloautomatické s použitím několika scriptů a
pomocných programů, které jsou přibaleny v CVS vydání Linkse. Tyto
programy nejsou v běžné distribuci, protože pro instalaci a běh prohlížeče
nejsou potřeba. Programy se kompilují také bez použití configure, a
vyžadují ke svému běhu striktnější verzi libpng než samotný prohlížeč
(nejsou tam workaroundy na schopnosti libpng, které chybějí ve starých
verzích). Procedura také vyžaduje, aby na systému byl nainstalován
Imagemagick (program convert). Během přidání je možno vygenerovat agregované symboly, kde už
stačí jen jednoduchá editace GIMPem, a můžeme tak dodělat chybějící
akcenty z fontů, které nemají příslušné symboly.
Celý proces probíhá následovně: Uživatel zadá do Fontmap, který chce
font, a pak pustí skript makefont. Výstupem makefontu bude hromada
souborů ve formátu PNG v adresáři font/new. Program makefont provádí
následující akce:
- Spustí program genps, který vygeneruje soubor letters.ps
- Spustí skript pdfhtml, který vygeneruje samotná písmenka z letters.ps,
která nad a pod sebou budou mít pomocné bílé obdélníky. skript pdf2html
spouští ghostscript, jehož výstup jde přes rouru ve formátu pbm (pouze
bílé a černé pixely) do
programu pbm2png, který provede decimaci dat 17x vodorovně a 15x svisle.
- Odstraní odpadky po skriptu pdf2html - tento skript byl původně určen
pro převod PDF do HTML se sadou PNG obrázků, a z důvodů zjednodušení
vývoje je zde použit beze změny.
- Spustí program clip. Tento odřeže (za pomocí volání programu
improcess a convert) režijní obdélníky z obrázků
písmenek a podle tabulek, které v clip.c jsou zaprogramovány,
provede přečíslování fontu (z rosahu 0-255) na Unicode (0000-ffff) a podle
další tabulky, která je také zakompilovaná v clip.c, spojení některých
dvojic znaků fontu do unicodových znaků. Mezi znaky dvojice je vložen
kostkovaný blok (spacer.png), který slouží k jednoznačnému
optickému oddělení znaků pro práci v GIMPu. Je vysoký 112 pixelů, což je
také výška výstupních znaků skriptu makefont. Pokud uživatel nastaví jinou
výšku, musí spacer.png změnit, aby procedura vůbec fungovala. Jinak totiž
convert odmítne znaky spojit.
Kterak postupovat jako uživatel
- Vstoupíme do adresáře graphics/
V genps.c můžeme provést nastavení, ale to jen v extrémním
případě, a defaultní hodnoty v komentářích necháme, aby se vědělo, co tam
patří. Celý systém je totiž seřízený na následující podmínky:
- Výška obrázku je 112 pixelů
- Písmenko X (0058.png) na fontu /CenturySchL a /CenturySchL-Bold je
přesně 67 pixelů vysoké, nahoře a dole má ostré přechody mezi 0 (černá) a
255 (bílá), čili tam nejsou šedé pixely, dole je 23 pixelů mezera
Proto tam nechte defaultní hodnoty:
float font_pos=300;
float font_height=392.9619;
float h_margin=100;
float v_margin=120;
float paper_height=842;
- Pustíme make
- Pustíme genps
- Upravíme
soubor Fontmap. Ten obsahuje 1 z následujících typů řádek:
/Links-generated (c059016l.pfb) ;
/Links-generated (/usr/local/share/ghostscript/fonts/c059016l.pfb) ;
/Links-generated /CenturySchL-Bold ;
Komentáře se dělají pomocí % na začátku řádku. Buď se tam může
napsat rovnou jméno souboru s fontem (pokud je v adresáři kde ho
Ghostscript najde, 1. řádek), nebo cesta (2. řádek) a nebo jméno fontu
který už je v Ghostscriptu nadefinovaný (3. řádek). Vybereme si 1 z nich,
modifikujeme podle našeho fontu a ostatní zakomentujeme.
přidá
Když máme font pro ghostscript (většinou *.pfb a *.afm, to *.pfb jsou
písmenka a *.afm je metrika), tak se dá pomocí pomocných programů a
skriptů přidat.
Zkontrolujeme, jestli v clip.c máme napsanou překladovou
tabulku pro daný font. Máme-li například japonské písmo Hiragana, podíváme
se kde je #ifdef HIRAGANA a tam je tabulka copy[] a
merge[]. Copy říká která písmenka se z fontu mají okopírovat
rovnou a merge říká ty akcentované co se pak budou lepit gimpem. v
copy[] je vždy po sobě číslo znaku ve fontu ghostscriptu (0-255)
a číslo znaku v unicode (0-65535). V merge jsou trojice: číslo znaku v
ghostscriptu, číslo příslušného akcentu v ghostscriptu, a číslo v unicode
na který se to má zmergovat. Pokud v clip.c pro příslušné písmo tyto
tabulky nejsou, tak si přidáme #define a připíšeme si je. Můžeme stávající
tabulky také opravit, když zjistíme že je v nich chyba. Nejlépe se tabulky
píšou tak, že si dáme v Xech do 1 okna gv letters.ps a do
vedlejšího prohlížeč s unikódovými tabulkami z http://www.unicode.org. Do třetího okna
dáme vi clip.c a vizuálně hledáme ke každému unikódovému znaku
odpovídající znak v letters.ps a rovnou to píšeme do zdrojáku clip.c.
V makefontu je možno nastavit ořezávání zhora a zdola, a
rozlišení. Ale nenastavujte to, jen v případě, že nebude zbytí. Nechte
defaultní hodnoty:
export hundred_dpi=1703
export top_promile=198
export bottom_promile=238
- Pustíme makefont a on nám font vyjede do font/new/. Pak gimpem zpracujeme
mergeované akcenty. V GIMPu vždy nahrajeme obrázek se sloučeným písmenkem
a akcentem (mezi nimi je čtverečkovaný pruh), přesuneme akcent nad
písmenko, odřízneme čtverečkovaný pruh a část, kde byl akcent, a uložíme.
Pomocí makefont se vygenerují do adresáře
font/new/ písmenka která jsou ve fontu přímo. Písmenka s akcentem která
tam nejsou, ale je tam to písmenko a akcent se vygenerují že v tom
výsledném obrázku je vlevo písmenko, mezi tím takový kostkovaný pruh a
vpravo akcent. Pak se vezme gimp a akcent se přendá nad písmenko do
esteticky hodnotné polohy a odřízne se kostkované pruh a to, co je vpravo od
kostkovaného pruhu. Pak se to uloží do obrázku zpět. Při troše zručnosti
takovéto akcentování jde celkem rychle.
- Po zpracování všech sloučených znaků GIMPem je nutno na výsledné
soubory pustit korekci pomocí programu improcess, protože GIMP nesprávně
ukládá gammu a písmenka by byla při velkém zvětšení zbytečně zubatá.
Na každý obrázek.png se pustí improcess -f obrázek.png "" obrázek.png,
čímž se násilím nastaví gamma na 1.0 a obrázek bude zase v pořádku.
Vzniklá png vrazíme do nějakého vhodného adresáře ve font/ a je hotovo.
- Pokud je nahoře nebo dole moc velký nebo moc malý okraj nebo účaří
písmen není v 5/24 výšky (odspoda), tak změníme nastavení
top_margin a bottom_margin v makefont. top_margin udává promile výšky
A4 které budou zahozeny jako horní okraj, analogicky bottom_margin.
Chceme-li, aby se měnilo rozlišení výstupního písmene (aby bylo jemnější
nebo hrubší), tak se změní ten_dpi v makefont.
- Pokud chceme vytvořit nový font (toto dělejte jen v případě, že by se
znaky kryly, zbytečně mnoho adresářů s fonty by mohlo prohlížeč zpomalit),
vytvoříme adresář se jménem ve formátu popsaném v tomto
odstavci. Pokud chceme přidat aliasy na první položku jména, vytvoříme
v adresáři soubor aliases a do něj napíšeme jednotlivé varianty, každou
na začátek samostatného řádku.
- Vytvořené soubory zkopírujeme do příslušného adresáře s fontem.
- Pustíme v adresáři graphics skript gen.
- cd ..
- make - tím se fonty zakompilují do prohlížeče.
Pokud chceme přidat do prohlížeče unicode znaky, které jsou pro nás
důležité, ale nemáme od nich soubor čitelný Ghostscriptem, ale pouze
papírovou předlohu a scanner, stačí písmo nascannovat, nahrát do GIMPu,
invertovat, oříznout tak, aby účaří bylo na 5/24 výšky (počítáno odspoda),
vhodně stranově oříznout, pomocí image -> colors -> levels oříznout
zašuměné bílé a černé partie (bez změny gammy, předpokládáme, že scanner
jako většina scannerů generuje výstup s gammou 1.0) a uložit do souboru
????.png, kde ???? je hexadecimální kód Unicode znaku.
Zde se popisuje, jak fungují (jak jsou naprogramovány, jaké jsou invarianty,
jakými principy se řídí) různé činnosti linkse.
Fonty, to jsou ty čtverečky a obdélníčky na kterých je namalováno
písmenko které je vidět na obrazovce. Při jejich tištění se nepoužívají
žádné fontovací fuknce X, svgalib, pmshell ani ničeho podobného. Používají
se pouze funkce pro tištění bitmap. Bitmapy jsou renderovány linksem (čímž
je zaručeno, že bude moci být 100% kontrolováno, jak budou vypadat) přímo
ve formátu vhodném pro dané výstupní zařízení (záleží na aspect ratio,
barevné hloubce, schopnosti zobrazovat barevně nebo černobíle atd.) a pak
jsou kresleny na obrazovku.
Základem pro fonty jsou obrázky písmenek, tak jak mají vypadat. Souvislý
text se skládá z řádek, což jsou stejně vysoké pruhy textu. V obrázku písmenka
(toho v adresáři font) je horní okraj (horní hrana nejsvrchnější
pixelové řady) ztotožněn s hraniční přímkou těchto pruhů, a dolní hrana (dolní
okraj nejspodnější pixelové řady) je stotožněna s hraniční přímkou o jednu řadu
níže. Hraniční přímka je útvar o nulové tloušťce.
Překrývání ani ligatury se nepodporují z důvodu, že přinášejí málo
vizuálniho zlepšení za cenu zavlečení obtížných problémů do sázení,
tištění, scrollování, rozsvěcování části textu a podobně. Italické písmo
se nepodporuje z důvodu, že by mezera mezi písmeny z důvodu překryvu byla
někdy zaměnitelná s mezerou mezi slovy.
Partie, které jsou v obrázcích bílé, budou kresleny
"inkoustem", partie černé budou kresleny "papírem".
Části s barvou mezi tím budou kresleny lineárně (ve fotonovém prostoru)
mezi tím (tedy např. je-li png 8-bitové a barva z rozsahu 0 (černá) - 255
(bílá) je 12, pak bude smícháno 12/255 inkoustu a (255-12)/255 papíru).
Když jsou písmenka barevná (což se nedoporučuje, protože to má za následek
zbytečné zvětšení PNG), tak se zkonvertují na černobílé podle
aproximační formulky vyjadřující přibližný jas vnímaný člověkem.
Předlohy písmenek jsou hodně vysoké obrázky, například 100 pixelů. Pro
kreslení řekněme 16 pixelů
vysokého písmenka je třeba bitmapu zmenšit. Na to se použije algoritmus, který namapuje výstupní
pixely na vstupní (oboje pixely bere jako obdélníky) a v každém výstupním pixelu vypočítá průměrnou
barvu na základě informací o pixelech vstupních. Dělá se to převzorkováním v jednom směru a
následným převzorkováním v druhém směru. Pořadí se volí tak, aby mezivýsledek měl tu menší plochu
z obou možných variant.
Písmenka, která jsou moc titěrná, takto vyjdou správně - tedy tak, jak by se
jevila, kdyby byla natištěna na papíře a snímána idealizovanou televizní
kamerou. Ovšem, jak je mozno vidět v televizi při záběru na dokument s malým
písmem (a jak také vyplývá z naměřených funkcí vnímání kontrastu v
závislosti na prostorové frekvenci u lidského oka), když jsou písmenka malá, vypadají šedivě a nevýrazně. Je to způsobeno
faktem, že malé černé a bílé detaily vytvoří šedivou, která způsobuje
subjektivní vjem sníženého kontrastu. Tomuto se předchází následnou korekcí,
která slučuje filtr pro zvýšení konstrastu (s oříznutím na černou a bílou,
samozřejmě) a filtr pro zvýšení ostrosti. Parametry filtru byly voleny
empiricky, aby to dobře vypadalo. Byly dělány také pokusy s převzorkováním
ostrou dolní propustí namísto mapování obdélníků, ale výsledek byl špatný
(ačkoliv metoda byla ta jediná matematicky správná pro převzorkování velkého
obrazu na malý tak, aby se reprezentovatelné frekvence zachovaly beze změny
amplitudy i fáze).
Pro tento kombinovaný filtr je použita matice 3x3 bodů natvrdo zakódovaná do algoritmu (a
optimalizovaná na základě symetrie). Filtr se
používá do výšky písmenek 32 pixelů, dále se již nepoužívá.
Zdrojové PNG soubory jsou uloženy ve spustitelném souboru. Program
generate_font slouží pro výrobu font_include.c, jenž obsahuje pole bajtů
zapsané v syntaxi jazyka C, ve kterém jsou uloženy po sobě v pořadí podle čísla
znaků všechny potřebné PNG, a pomocnou tabulku umožňující nalézt písmeno a
zjistit, jak je jeho PNG dlouhé. PNG se v paměti rozkóduje pomocí libpng a
putuje dále do zpracování.
Výhody celého tohoto přístupu jsou následující: pro kompletní funkci
prohlížeče je potřeba jeden soubor a příslušné nainstalované knihovny (v
případě, že je zkompilován staticky, je třeba jen jeden spustitelný soubor,
který může být puštěn i misto initu), nevznikají tedy potíže s tím, kam umístit
data na různých operačních systémech. Vzhled a podporované fonty nejsou
platformně a konfiguračně závislé. Písmenka se dají snadno přidávat (stačí
získat vzor písmenka ve tvaru obrázku bez omezení na výšku a šířku, ten je
možno získat i z tištěného materiálu nascanováním, úpravou obrazu GIMPem a
uložením ve formátu PNG) pouhým překompilováním prohlížeče (což je standarní
instalační procedura). Písmenka jsou dobře čitelná i při malé pixelové výšce (na
rozdíl od neantialiasovaných fontů, které jsou při nízkých výškách téměř nebo
zcela nečitelné).
Písmenka z PNG jsou standardně uložena 8-bitová šedá s gammou 1.0 což odpovídá tomu, že jsou
přímo úměrná světlu vycházejícímu z obrazkovky. Použijeme-li je jako alpha masku na
16-bitové barvy, vzniknou nám čísla 0 až 255*255*257. K tomuto číslu
přičteme 127 a vydělíme to 255, čímž dostaneme číslo v rozsahu 0-255*257 (65535).
V případě, že je za písmenky obrázek, použije se místo jednolité pozaďové
16-bitové barvy 16-bitový obrázek. U pozaďového obrázku se alpha ignoruje.
Ruzné druhy písma jsou dělány tak, že každý druh písma má
extra sadu obrázků. Podtržené písmo se dělá přikreslováním podtrhávací
čáry přes font: při kreslení znaků se nastaví clip nad podtrhovací čáru,
pak se nakreslí podtrhovací čára a clip se nastaví pod podtrhovací
čáru a nakreslí se písmenka znovu.
Jinak má každý font jméno ve formátu family-weight-slant-adstyl-spacing. Family
může být libovolné jméno (fonty ho mají malými písmeny, nehledí se na
velká a malá písmena) složené jen z písmen a podtržítek. weight je
"bold" nebo "medium", slant je "italic" nebo
"roman", adstyl je "sans" nebo "serif",
spacing je "mono" nebo "vari".
Když se hledá vhodný font, tak se napřed chce, aby seděly všechny
položky co označují font. Tím se najde v souboru font/catalogue jediný
font, který se dá na první místo a vyškrtne se. Pak se zruší postupně
položky family, adstyl, weight, spacing, slant. Po zrušení každé položky
se projde katalog a vyhovující fonty se nasází na další místa. Nakonec je
průchod se zrušenými všemi položkami, a tam musí projít všechny fonty,
takže se všechny fonty tímto seřadí do žebříčku oblíbenosti pro zadaný
požadavek na font. To se nacpe do struktury struct font, a když se hledá
písmenko, tak se po hitparádě jde zezhora dolů a dokavaď se nenajde, tak
se jde. Když se nenajde ani na posledním místě, tak se vrátí prázdné
písmenko s rozměry 0 x 0 nebo něco podobného, což vyústí v to, že se místo
písmenka vůbec nic nezobrazí - prostě v textu chybí.
Do monitoru vstupuje elektrický signál a
vystupuje z něj optický signál. Elektrický signál je přímo úměrný počtu
elektronů a optický signál počtu fotonů. Co je foton a elektron snad každý ví.
Všechny elektrony jsou stejně velké. Všechny fotony jedné vlnové délky jsou
stejně velké.
Počet fotonů není přímo úměrný počtu elektronů na vstupu. Platí například,
že fotony=elektrony^2.2. To 2.2 je gamma toho monitoru. Obdobné kalkulace platí
i pro jiná zařízení, pokud jsme schopni se dohodnout, v jakých jednotkách se
měří vstupní a výstupní veličiny zařízení. Ne každý monitor má gammu stejnou. A
gamma jedoho exempláře monitoru se může lišit i pro jednotlivé kanály red,
green, blue. Nejlepší je proto gammu změřit pomocí testovacího obrazce a
nastavit ji do prohlížeče, protože pak dostaneme nejdokonalejší obraz. Při
zadání nesprávných hodnot gamma mohou vzniknout závady zobrazování jako barevné
závoje při ditherování, příliš kontrastní jedny partie obrazu a nedostatečně
kontrastní ostatní partie obrazu, případně nesprávné podání barevného tónu v
určitých partiích. V případě, že není možno určit gammu, lze použít aproximaci,
kdy se všechny tři gammy nastaví stejně, a to na hodnotu 2.2.
Základní podmínka pro to, abychom očekávali vůbec věrný obraz, je nastavit
správně jas monitoru. S kontrastem si pak budeme moct kroutit jak chceme,
kvalitu obrazu neovlivní, jen jeho intenzitu. Nastavovací procedura následuje:
nastavte kontrast na minimum a jas na maximum. Zmenšete obraz abyste jasně
viděli rozdíl mezi rámečkem obrazu ještě zasaženým elektronovým paprskem a
krajem skla paprskem nezasaženým. Pak snižte jas dokud nepřestane být vidět toto
rozhraní. Pro zlepšení viditelnosti je vhodně zhasnout, zatáhnout záclony a
podobně. Jakmile rozhraní přestane být vidět, jas se již nesmí dále ubírat. V
tomto okamžiku velmi opatrně nalepte kus lepicí pásky na knoflík jasu aby se
již nedal nikdy více otáčet nebo se zapřísahejte na Bibli, že do elektronického
menu již nikdy na jas nesáhnete. Pak si nastavte kontrast dle libosti a
zvětšete obraz zpět do původní velikosti. V případě, že nejste proceduru
schopni provést přesne, je lepší nechat jas trochu větší než trochu menší.
Pro přesný popis této procedury se
podívejte semhle.
Display gamma je gamma exponent mezi hodnotou vstupující do grafického
ovladače (například do paměti grafické karty, do X protokolu, atd.) a počtem
fotonů vystupujících z luminoforu obrazovky následkem ozáření elektronovým
paprskem.
Jaký má display gamma exponent, to říkají proměnné display_red_gamma,
display_green_gamma a display_blue gamma. Protože gammy se mohou lišit pro
různé barevné kanály, tak jsou tam tři. Cílem zobrazení linksu je, aby počet
fotonů dopadajícího do oka uživatele při osvětlení 64 luxů byl stejný jako počet fotonů dopadajícího
do oka uživatele, sedícího před monitorem s gammou monitoru 2.2 a gammou obrázku
1/2.2 (obrázek podle sRGB standardu) při osvětlení 64 luxů.
V případě, že máme obrázek sRGB a monitor s gammou 2.2 a osvětlení 64 luxů,
postupuje links následovně: vezme raw data z obrázku a šoupne je do obrazovky.
Pokud je osvětlení jiné, hodí se před šoupnutím obrázek umocnit na následující
čísla:
| Osvětlení | Umocnit na |
| 0lx | 1.333333333333 |
| 15lx | 1.111111111111 |
| 64lx | 1.000000000000 |
| >=200lx | 0.888888888888 |
Tato magická čísla označme jako user_gamma a nechme je nastavit uživatele.
V případě, že gammy monitoru jsou jiné, a gamma obrázku je jiná, dělají se tyto akce:
- Dekóduj obrázek jako raw data
- Umocni raw data na user_gamma/obrazek_gamma
- Pošli to do ditherovače
- Zditheruj to, teď je to úměrné osvětlení co fakt poleze z monitoru
- Umocni to na 1/display_gamma
- Pošli to do monitoru
Proto je ve zdrojovém kódu dip.c wanted_red_gamma, wanted_green_gamma a
wanted_blue gamma. Jsou to gammy, které jsou zařazeny do obrazového řetězce
jako exponenciální funkce x^-wanted_red_gamma, x^-wanted_green_gamma,
x^-wanted_blue_gamma.
V přenosovém řetězci uvnitř linksu se dělají následující procedury:
- Nahraje se PNG obrázek písmenka do paměti a to tak, aby hodnoty uložené v paměti
vygenerované přímo knihovnou libpng byly přímo úměrné osvětlení předmětu (tedy počtu fotonů)
onoho virtuálního písmenka.
- Vypočte se barva pozadí z HTML podle specifikace HTML 4.0 (sRGB barevny prostor), aby tato
barva byla vyjádřena ve fotonech. Tedy se vezme číslo z HTML a umocní se na 0,45454545... .
Barvy z HTML jsou interpretovány
podle standardu sRGB.
- Namíchají se barvy podle alfa-masky, kterou písmenko představuje. Hodnota 255 je úplná
opacita inkoustu písmenka a hodnota 0 je úplná transparence inkoustu.
- Vzniklé písmenko (které je přímo úměrné fotonům na scéně) je
gamma-korigováno 1/wanted_gamma/display_gamma.
Hodnoty jsou tedy umocněny na 1/display_gamma/wanted_gamma.
- Vzniklý obrázek je ditherován v ditherovací engine. Ditherovací engine očekává obrázek úměrný tomu,
jak vstupuje do displaye, ale ditherovací engine zná gammu displaye a počítá s ní. Ditherovací
engine tedy gammu dat nemění, ale ke své správné funkci gammu displaye znát potřebuje, protože
předpokládá, že barvy se aditivně sčítají sčítáním fotonů dopadlých na jednotlivé receptory v oku.
- Z ditherovacího engine vypadnou data, která již gammu definovanu nemají, a představují interní
reprezentaci grafického driveru.
- Driver to nacpe na obrazovku
- Výsledný obraz leze ze skla obrazovky do oka pozorovatele. Počet fotonů tohoto obrazu je
počet fotonů na scéně umocněný na 1/wanted_gamma. Wanted gamma jsou doporučeny jako 1.0 (pro jasně
osvětlené pracoviště), 1.125 (normální pracoviště), 1.25 (temné pracoviště), 1.5 (temná komora, jako
například při promítání diapozitivů).
V případě zobrazování obrázku z png, jpg, a podobně, se dělají
náledující procedury:
- Požádá se grafická knihovna (libpng, libjpeg) o to, aby vydala obrázek
ve formátu 3x8 bitů s gammou 1/display_gamma/wanted_gamma.
- tato data se nechají ditherovat ditherovací engine. Ten vydá
nespecifická data pro display.
- Data se zobrazí na obrazovce. Výsledné světlo je světlo na reálné
scéně umocněné na 1/wanted_gamma.
Vzhledem k tomu, že nejrozumnější (a nejběžnější) je PNG a JPG obrázky
ukládat s gammou rovnou 0.45454545 (gamma sRGB standardu), nevzniká v
řetězci degradace, která by vznikla, přenášely-li by se někde 8-bitová
data s gammou 1 (tedy úměrná osvětlení scény).
Celý život linkse se odehrává ve funkci select_loop, která pomocí funkce select
čeká na ruzné události. Pomocí následujících funkcí si můžeme objednat čekání na
néjakou událost, vždy je třeba specifikovat funkci, která se zavolá, až daná
událost nastane, a pointer, ktery se jí předá:
-
void set_handlers(int fd, void (*read_handler)(void *), void
(*write_handler)(void *), void (*error_handler)(void *), void *data)
-
Registruje handler na čtení, zápis a chybu příslušného file descriptoru. Až bude
z fd možno číst, zavolá se funkce read_handler, až bude možno zapisovat, zavolá
se write_handler, při chybě se zavola error_handler. Funkce se zavolají s
parametrem data. Funkce můžou být NULL - v tom případě se na danou událost
přestane čekat.
-
int install_timer(ttime t, void (*fn)(void *), void *data)
-
t je doba v milisekundách. Za danou dobu zavolá funkci
fn a předá ji parametr
data. Vrátí handle timeru, který je možno použít k předčasnému ukončení. Pokud
vrátí -1, došlo k neúspěchu.
-
void kill_timer(int timer_handle)
-
Předčasně ukončí timer s příslušným handlem. Pokud handle není platný timer,
vyvolá INTERNAL ERROR a dumpne core.
-
void install_signal_handler(int signal, void (*fn)(void *), void *data,
int immediate)
-
Čeká na signál. Při přijmutí signálu zavolá funkci fn s parametrem data.
Pokud je immediate 0, funkce je zavolána až se kód vrátí do select_loop.
Pokud je parametr immediate nastaven na 1, funkce je zavolána ihned - v
takovém
případě můžou být všechny struktury v nekonzistentním stavu, proto na ně
není
dobré sahat ani volat funkce, co na ně sahaji (nesmí se třeba ani alokovat
pamět). fn == NULL znamená odinstalace handleru.
-
ttime get_time()
-
Vrátí čas v milisekundách. Vrácená hodnota se plynule zvětšuje, ale nemůžeme z
ní usuzovat, jaký je reálný čas. Funkce je použitelná pro měření, jak dlouho
nějaká akce trvala.
-
int register_bottom_half(void (*)(void *), void *)
-
Způsobí, že daná funkce bude zavolána okamžitě, až se program vrátí do select
smyčky. Jakmile byl bottom half registrován, nejde ho zrušit (pozor na to,
když
je objekt, který byl předán funkci jako parametr, mezitím odalokován). Když je
registrována stejná funkce se stejným parametrem vícekrát, zavolá se pouze
jednou. Bottom halfy se typicky používají pro odalokování ruzných struktur (jako
třeba terminál).
Podobného efektu lze docílit registrováním timeru s časem nula. Rozdíl je v tom,
že když registrujeme funkci se stejným parametrem vícekrát, taky bude
vícekrát
zavolána. Timer jde taky předčasně zrušit, proto je ve většině případů
lepší,
než bottom halfy.
Ke stahování dokumentu slouží object requester. Je možno ho nalézt v objreq.c.
-
void request_object(struct terminal *term, unsigned char *url, int pri, int
cache, void (*upcall)(struct object_request *, void *), void *data, struct
object_request **rqp)
-
Stáhne objekt ze sítě.
term je terminál, na který se budou
vypisovat otázky ohledně stahování. url je url, které se má stáhnout.
pri je priorita (konstanta PRI_xxx).
cache je úroveň, s jakou se má používat cache. Je definována makry
NC_xxx. Typicky se používá NC_CACHE.
upcall je funkce, která se zavolá s parametrem data.
Upcall se volá periodicky, každou 0.1s až 1s po dobu, po kterou je spojení živé.
Na místo rqp se uloží pointer na request.
-
struct object_request
- Čtením
object_request->state lze zjišťovat stav natahování:
Živé spojení:
O_WAITING – ještě se nezačalo nic stahovat.
O_LOADING – už se stahuje, je stažena část dokumentu.
Spojení se už ukončilo:
O_FAILED – nepodařilo se nic stáhnout.
O_INCOMPLETE – stáhla se část a pak spojení spadlo.
O_OK – stáhl se celý dokument.
Přesnější popis chyby je možno získat z object_request->stat.state.
To je některá z konstant S_xxx, která určuje přímo typ chyby, ke
které došlo, nebo stav, ve kterém se spojení právě nachází.
object_request->ce ukazuje na položku v cachi, kam se stahuje. Může
být NULL, pokud se zatím nic nestáhlo. Tato položka je platná pouze ve stavech
O_LOADING, O_INCOMPLETE a O_OK. V struct cache_entry je uložena
HTTP hlavička a seznam fragmentu. Pomocí funkce defrag_entry lze
položku kdykoli defragmentovat a fragmenty spojit do jednoho, nebo to lze
nechat tak, a rozebírat jednotlivé fragmenty.
-
void release_object(struct object_request **rqq)
-
Tato funkce uvolní object request. Pokud se ještě něco stahuje, tak se to zruší,
případně odloží na pozadí, a cachová položka je odemčena, takže může být
uvolněna. Zavoláním této funkcí, se nelze na data objektu nijak dostat.
Interpret sestává z těchto částí:
- lexikální analyzátor
- syntaktický analyzátor
- generátor interkódu
- interpret interkódu
1. Lexikální analyzátor
K napsání lexikálního analyzátoru byl použit prostředek flex.
Zdrojové texty jsou v souboru javascr.l. Úkolem lexikální analýzy je
rozbit vstupní řetězec do sady tokenů, které postupují dále k syntaktické
analýze. Tokeny mohou být nemálo typů. Lexikální pravidla byla opsána
z normy javascript 1.1 od Netscape Corporation a poněkud upravena s vyhlídkou
na snazší syntaktickou analýzu. Např. každe řídící slovo má svůj vlastní
typ tokenu (while, for,...). K syntaktické analýze postupují tokeny
číslované typem long (možná by stačil int, ale jelikož při jeho psaní nebylo
jasné, jestli nebude potřeba místo čísla vracet pointer, byl vybran typ,
který je konvertovatelný na pointer.
Typy tokenu: Řidícím slovům stačí pouze long říkající vše. Jedná-li
se o nějaký literál, pak pro boolské literály jsou použity dva různé tokeny
(TRUE a FALSE), pro nullový literál token NULL. Numerický
literál odesílá ještě v proměnné yylval buďto hodnotu celého čísla, nebo
pointer na necelé. yylval je typu long kvůli přetypovatelnosti na integer i
pointer. Řetězce posílají v proměnné yylval ukazatel na místo v paměti, kde se
řetězec nachází.
Identifikátory:
Každemu identifikátoru je již při lexikální analýze
přiřazen klíč, pod kterým bude v celém programu vystupovat (tento klíč
je jednoznačný i pro "vnořené" identifikátory, tedy ať už se identifikátor
vyskytuje jako proměnná a stejně se jmenuje kupř. nějaká metoda nějakého
objektu, budou mít tyto klíče stejné. Kde se objekt identifikátorem odkazovaný
v paměti nachází se zjišťuje z "adresného prostoru", který je až záležitostí
interpretu mezikódu. Při lexikální analýze tedy vzniká jakýsi "namespace",
který přiřazuje každému identifikátoru nějaký klíč. Indexování proměnných
klíčem bylo vybráno proto, že porovnat dva longy je podstatně rychlejší,
než testovat shodu dvou řetězců (zdržení se realizuje za každý výskyt
proměnné ve zdrojovém textu, nikoliv za každý dotaz na ni při interpretaci).
Lexikální analýza též odstraňuje komentáře a tomu podobné pro význam programu
nepotřebné věci (konce řádku, zbytečné mezery...).
2. Syntaktický analyzátor
Syntaktická analýza se děje automatem vygenerovaným programem bison.
Zdrojový kód lze nalézt v souboru javascript.y. Syntaktická analýza dostává
na vstupu jednotlivé tokeny a má "říct, jak spolu souvisejí", tedy postavit
syntaktický strom podle pravidel gramatiky. Tuto gramatiku jsme téměř opsali
opět z normy javascript 1.1. Lexikální i syntaktická analýza předcházejí
vlastní interpretaci, jelikož interpretování "z čisté vody", tedy z čistého
zdrojového kódu právě interpretovaného javascriptu by bylo značně zdlouhavé,
navíc bison neposkytuje dostatečně komfortní prostředí pro samotnou
interpretaci - bylo by nutné udržovat pohromadě syntaktický analyzér
(který
je už sám o sobě dost dlouhý) v jednom souboru s interpretačními pravidly
(ta jsou ještě delší). Syntaktický analyzér pouze podle pravidel opsaných
z gramatiky z posloupnosti tokenů postaví syntaktický strom tvaru:
Operátor, ukazatel na první argument, ukazatel na druhý argument,... ukaza-
tel na šestý argument.
Šest argumentů není nikdy použito (maximum jsou čtyři,
návrh natvrdo sestrojit sedmice je podložen těmito argumenty:
Sice je v určitém smyslu poněkud marnotratný (průměrný počet potomků ve
stromě je mezi dvěma a třemi), navíc není zcela pružný (změna gramatiky
může někde vynutit třeba 7 synů), zato je ale poměrně jednoduchý,
není potřeba udržovat počet synů a komplikovaně pro ně alokovat a odalokovavat
paměť, navíc změna gramatiky by reprezentovala takový zásah do interpretu,
že přidání pár slotů na syny by byla nevinná dětská hra (i když samotné
přidání nějakých pravidel by rovněž problémem nebylo - postačovalo by
přidat příslušná pravidla do javascript.y, eventuálně nové tokeny do
javascr.l a změny interpretující funkce do ipret.c).
3. Generátor mezikódu
Generování interkódu probíhá při syntaktické analýze. Celý výpočet
javascriptu je zavřen ve struktuře struct js_context, která obsahuje zejména:
- timer (interní záležitost - používá se ke kontrole správnosti naplánování
běhu javascriptu),
- callback (opět interní záležitost) - ukončí celé interpretování,
- id okna, které příslušný javascript obhospodařuje,
- zámek, který chrání interpretaci před časově závislou chybou (racem),
- dva ukazatele na syntaktický strom - jeden ukazuje do kořene a druhý
do právě interpretovaného vrcholu,
- zásobník argumentů - na ten se ukládají výsledky jednotlivých kroků
interpretace,
- zásobník rodičů - říká, kterými vrcholy se výpočet ve stromě sestupně
ubíral, než došlo k našemu zavolání. Tento zásobník obsahuje
pouze ty rodiče, kteří ještě nedopočítali, tedy jimž je po
ukončení našeho výpočtu potřeba ještě vrátit řízení.
- addrspace - pojmenovaný lnamespace jako localnamespace. Udržuje informace
o stavu proměnných podle jim přiřazených klíčů (klíč, typ proměnné,
hodnota, ev. ukazatel na ni...)
- namespace - sada dvojic klíč, řetězec identifikující proměnnou. Je ho
potřeba udržovat po celou dobu výpočtu, jelikož javascript se
může při běhu modifikovat a volat znovu lexikální analyzér (a tudíž
i vše za ním následující).
Fosilie: Funkce terminál a neterminál. V minulosti se jevilo jako dobrý
nápad rozlišovat, co je terminál (nemá potomky typu pointer, ale hodnota)
a co neterminál (rodič nějakých terminálů nebo neterminálu). Posléze se
však ukázalo, že uzle jsou natolik heterogenní, že takovéto dělení
je úplně zbytečné. Až bude trocha času na civilizování kódu, tak jednu
z těchto funkcí vymažu (možná už jsem to udělal, ale nepamatuju se).
4. Interpret mezikódu
Interpret mezikódu
je nejnáročnější částí celého interpretu. Jeho hlavní část lze najít v souboru
ipret.c. Interpretace probíhá tak, že funkce ipret postupně a organizovaně
prohlíží strom. Jediné, co potřebuje vědět, je, v kterém vrcholu teď stojíme,
kolikátý argument daného operátora zpracováváme a jaké argumenty už máme
spočítané. Když má operátor vypočteny všechny argumenty, spočítá svou hodnotu
a vrátí řízení "nadřazenému uzlu", který jeho výpočet použije jako jeden
ze svých argumentů. Důležité je, že argumenty se udržují na zásobníku argumentů
a vlastnosti zásobníku zaručují, že ve chvíli, kdy se budeme shánět po svých
argumentech je tam budeme mít v pořadí: poslední, předposlední,... první
(pokud nechceme jinak). Stejně tak teoretické vlastnosti zásobníku zaručují,
že vždy po ukončení výpočtu v současném uzlu se vrátíme do bezprostředně
předcházejícího uzlu, který má ještě zájem počítat (zájem počítat už např.
nemá operátor program, který již zavolal svůj druhý argument. Funkce
program vznikla z pravidla:
program -> program program,
tedy pouze řetezí jednotlivé bloky programu.
Vztahy k okolí:
Interpretace začíná zavoláním js_create_context, která vytvoří strukturu
js_context (popsanou výše). V budoucnu v této funkci budou do namespaců
a addrspaců doplňovány vestavěne funkce. Jejich podpora ještě není napsána,
ale dle mého názoru by neměla patřit mezi těžké partie.
Když je potřeba interpretování zastavit (dočasně ukončit), zavolám
callback. Po tomto zavolání mohu být ještě probuzen znovu dalším požadavkem.
Je-li potřeba s příslušným skriptem již definitivně skoncovat, zavolá
se funkce js_destroy_context, která zruší kontext a tím i všechna data se
skriptem spojená.
Závěr:
Pokouším se napsat interpret javascriptu podle dostupných informací.
Ukázalo se, jak jsem podle různých tvrzení vyučujících překladačů předpokládal,
že se jedná o poměrně náročné, zato však zajímavé programování s ohledem na
to, že je potřeba ošetřovat různé speciální případy a navrhovat různé věci,
které nepatří mezi zcela obvyklé partie programování a které vyžadují
relativně abstraktní a teoretické uvažování.
Interface
Pro upcally navrhuju tento interface:
upcall(long upcall_id,int id_volajícího_dokumentu,struct upcall_arg *argumenty);
Za odallokování argumentu si ručí příjemce, vracet se bude typ long a to
povětšinou jako pointer na řetězec. Nula znamená void. Bude-li potřeba,
bude se vracet struct upcall_arg*.
struct upcall_arg { char* argument;
struct arg* next;
}
Původně jsem chtěl předávat char**, ale byla by tu nutnost znát předem počet
argumentů.
Debugovani javascriptu
Podle definovanosti konstant DEBUZIM a BRUTALDEBUG se vypisuji nebo nevypisuji
hlasky o tom, jak probiha analyza. Zavislost na nicem neni. Podobne funguji
i makra debug (puvodni debug oddefinovano v ipret.c a ns.c)
a idebug (v builtin.c, context.c). Budto jsou definovana jako printf, nebo
se misto nich vrazi prazdne misto, normalne jsou vypnute. Pak jsou tu
konstanty DEBUGMEMORY - podle ni se nastavuje komentar k argumentum
ulozenym na bufferu, DEBUZ_KRACHY - pri internalu a js_erroru vysype
do links_debug.err udaje o miste, kde se to stalo. Konstanta DEBUZ_KRACHY
je ponekud nebezpecna a v normalnim provozu by nemela byt definovana!
U konstanty DEBUGMEMORY je dulezite, aby byla nastavena jenom kdyz se
alokuje pomoci debug_mem_alloc a freeuje pomoci debug_mem_free, proto
je kolem nich v struct.h ifdef na to, jestli je DEBUGLEVEL 2.
Popis
V souboru listedit.c jsou funkce a datové struktury umožňující
jednoduše nadefinovat nějaký seznam, se kterým uživatel linksu bude pracovat.
S využitím funkcí z listedit.c se dají vytvořit velice jednoduchým
přídavným kódem například bookmarky, asociace, přípony, ...
Seznam může být buď plochý, nebo stromový. Plochý seznam je lineární seznam,
kde jedna položka následuje druhou. Ve stromovém seznamu jsou krom položek ještě
adresáře. V adresářích mohou být položky nebo další adresáře.
Obecné seznamy neřeší vyrábění seznamů, jejich ukládání na disk, čtení z
disku. To si musí implementátor obstarat sám.
Ovládání uživatelem
Při zavolání funkce create_list_window se uživateli Linksu zobrazí
okno se seznamem. Po seznamu se může pohybovat klávesami nahoru, dolů, home,
end, page-up, page-down, tím se vybírá položka seznamu. Klávesami doleva,
doprava se pohybuje po tlačítkách ve spodní části okna, klávesou enter se
"zmáčkne" příslušné tlačítko ve spodní části okna. Navíc u
stromového seznamu se klávesami + / - otevře/zavře adresář, mezerníkem se
otevřený adresář zavře, zavřený se otevře.
Uživatel také může užít myši. Pravé tlačítko+pohyb scrolluje seznamem
nahoru/dolů. Pokud se klikne levým tlačítkem na popis položky, položka se
vybere. Navíc u stromového seznamu levé tlačítko na symbolu adresáře
otevře/zavře adresář.
V hlavním okně jsou tato tlačítka:
- Folder - pouze u stromového seznamu, vytvoří nový adresář za vybranou položkou, pokud je
vybraná položka otevřený adresář, vloží do něj.
- Add - přidá položku do seznamu za aktuální položku, pokud je položka
otevřený adresář, vloží do něj.
- Delete - smaže položku pod kurzorem, pokud se jedná o adresař smaže i
jeho obsah
- Edit - edituje aktuální položku
- Unselect all - odznačí všechny položky.
- Move přestěhuje označené položky za aktuálně vybranou
položku. Pokud je aktuálně vybraná položka otevřený adresář, přesune do
něj.
- Close - zavře okno
- Uživatelské tlačítko - je možno nadefinovat jedno uživatelské tlačítko (viz
níže), které provede nějakou akci na položce pod kurzorem (ne na adresáře). Například u bookmarku
tlačítko "Goto"
Datové struktury a funkce
Seznamy používají dvě významné datové struktury. První z nich je struct
list. Tato struktura obsahuje vlastní seznam.
Obsahuje tyto části:
- void *next - ukazatel na následující položku
- void *prev - ukazatel na předchozí položku
- unsigned char type - 0. bit říká, zda se jedná o adresář (1),
nebo o položku (0); 1. bit říká, zda je adresář otevřený (1), nebo
uzavřený (0). 1. bit není pro položku využit; 2.bit říká, zda
je položka označena (1 znamená označeno).
- int depth - hloubka položky, hlava má hloubku -1.
- void *fotr - pokud se jedná o stromový seznam, ukazuje na
otce (adresář, ve kterém je bezprostředně položka), používá se pro práci
se zavřenými adresáři
Druhá struktura je struct list_description, obsahuje popis seznamu. Pro
každou implementaci seznamu je potřeba vytvořit jednu takovouto strukturu, ta se
pak předává všem funkcím pracujícím se seznamy.
Struktura obashuje tyto položky:
- unsigned char type - definuje, zda se jedná o plochý (hodnota
0) nebo stromový (hodnota 1) seznam
- struct list* list - ukazatel na vlastní seznam
- void *(*new_item)(void * initial_data) - funkce na vytvoření nové položky
v seznamu, naalokuje novou položku a vrátí na ni ukazatel. Argument jsou
buď data na inicialisaci polozky (získaná od funkce
default_value, nebo NULL, když má být daná položka prázdná.
Jestliže initial_data není NULL, funkce musí tato data
odalokovat.
- void (*edit_item)(struct dialog_data * dlg, void * item, void(*
ok_fn)(struct dialog_data *,void *,void *,struct list_description *),
void * ok_arg, unsigned char dlg_title) - funkce na editaci položky.
Vytvoří dialog, ve kterém může uživatel editovat příslušnou položku.
item je editovaná položka. Funkce ok_fn se zavolá při
úspěšném ukončení editace (typicky zmáčknutí OK v editačním dialogu),
jako první argument se jí předá dlg, druhý argument je
ok_arg, třetím argumentem se jí předá pointer na editovanou položku,
jako poslední argument se jí předá popis seznamu. Argument
dlg_title může nabývat hodnot TITLE_EDIT nebo
TITLE_ADD. Tento argument se v editační funkci využije pro
rozlišení textu pro uživatele (zda se jedná o přidávání nové položky,
nebo o editaci již existující položky).
- void *(*default_value)(struct session *ses, unsigned char
type) - používá se, když uživatel klikne na tlačítko "vyrob
novou položku". Tato funkce vytvoří (naalokuje) data pro inicialisaci nové
položky. Data jsou ve formátu, který si implementátor zvolí, předávají
se funkci new_item, která data následovně odalokuje (viz výše).
Argument type se používá pro rozlišení adresáře (hodnota 0) a
položky (hodnota 1).
- void (*delete_item)(void *) - smaže položku seznamu. Pokud
předchůdce/následovník není NULL, upraví ukazatele předchůdce a
následovníka.
- void (*copy_item)(void * old, void * new) - dostane dvě
naalokované položky, zkopíruje obsah old do new s výjimkou
pointerů provazujících seznam. Data v old položce (nikoliv
položku old !) odalokuje.
- unsigned char *type_item(void *item, int what) -
naalokuje řetězec (bez předalokace), do kterého vytiskne položku item. Argument
what rozlišuje, zda se má vytisknout celá položka (hodnota 0) -
například při mazání položky, nebo pouze titulek položky (hodnota 1).
Funkce by měla být schopna u stromového seznamu vytisknout i hlavu
seznamu, typicky by měla tisknout nějaký fixní text (například "
Bookmarky").
- int codepage číslo kódové stránky, ve které se předávají všechny
řetězce.
- int window_width - šířka hlavního okna na zobrazování seznamu.
- int n_items - počet položek, které se mají zobrazovat v
hlavním okně.
- int item_description - kód řetězce popisující položku (např.
"bookmark").
- int already_in_use - kód řetězce např. "Bookmarky jsou
již otevřeny v jiném okně"
- int delete_dialog_title - kód řetězce s titulkem dialogu na
mazání položky.
- int window_title - kód řetězce s titulkem hlavního okna
- int button - kód řetězce s popiskou uživatelského tlačítka
- void (*button_fn)(struct session *ses, void *item) - funkce
uživatelského tlačítka (např. "Goto bookmark". Pokud
uživatelské tlačítko není definováno, button_fn je NULL. Tlačítko
nefunguje na adresáře ani na hlavu seznamu (u stromového seznamu). Pokud
bude třeba funkci předávat další argumenty, definice se přepíše.
Vnitřní proměnné, všechny by měly být nastaveny na 0:
- struct list *current_pos - ukazatel na položku pod kurzorem v
hlavním okně
- struct list *win_offset - ukazatel na 1. položku v hlavním
okně
- int win_pos - vertikální pozice kurzoru v hlavním okně
- int open - 0=hlavní okno zavřeno, 1=hlavní okno otevřeno
- int modified - data byla modifikována, bylo by dobré je potřeba
uložit na disk (pokud se ukládají). Pokud je modified 0, není seznam
potřeba ukládat, protože se nezměnil.
- struct dialog_data *dlg - ukazatel na dialog s hlavním oknem, je
platný jen v případě, že open je rovno 1.
Jediné funkce viditelné navenek listedit.c jsou
extern int create_list_window(struct list_description *,struct list *,struct terminal *,struct session *);
Tato funkce vytvoří hlavní okno se seznamem.
extern void redraw_list_window(struct list_description *ld);
Překreslí obsah okna se seznamem.
extern void reinit_list_window(struct list_description *ld);
Znovu inicialisuje okno do stavu jako po spuštění create_list_window. To
znamená přesune kurzor a výhled na seznam na začátek a překreslí.
Stromový seznam
Každý člen seznamu má u sebe proměnné: hloubka, typ (adresář/položka), flag
otevřeno/zavřeno, ukazatel na otce.
Hloubka je číslo od 0 výše, hlava má jako jediná hloubku -1. Stromový
seznam je interně uložen jako lineární seznam. Adresář je uložen tak, že je
nejprve adresář a za ním následuje jeho obsah. Obsah adresáře je tedy po
adresáři nasledující souvislý blok položek, ktere mají hloubku větší než hloubka
dotyčného adresáře.
Typ může být buď 1 (adresář), nebo 0 (položka). Flag
otevřeno/zavřeno se používá jen u adresáře. U položky se ignoruje.
Ukazatel na otce slouží k urychlení vykreslování seznamu. Když jsou
některé adresáře zavřené, tak je potřeba jejich obsah přeskočit.
Přidávání a editace položek - funkce edit_item
Když uživatel zmáčkne tlačítko add, vyrobí se nová položka (zavolá se funkce
new_item), která se nepřidá do seznamu. Poté se zavolá funkce
edit_item na editaci položky. Po úspěšné editaci položky (zmáčknutí
"OK")
se teprve položka přidá do seznamu. Při zmáčknutí "cancel" se položka smaže.
Při editování položky (uživatel zmáčkne tlačítko "edit") se vytvoří nová
položka, zkopíruje se do ní obsah té původní (zavolá se copy_item) a opět
se zavolá edit_item. Jestliže uživatel zruší editaci tlačítkem
"cancel", položka se smaže. V opačném případě se obsah položky
zkopíruje zpět do původní (opět pomocí copy_item) a položka se smaže.
Při zmáčknutí "cancel" tedy funkce edit_item musí položku
smazat. Při zmáčknutí "OK" je zavolána funkce, kterou edit_item
dostane jako argument (viz výše).
Přístup do seznamu z více oken (instancí linksu)
Struktury nejsou odolné proti více paralelním přístupům (například ve
struct list_description je pozice kurzoru v okně atd.), proto je přístup
z více oken zakázán. Funkce create_list_window nejprve nastaví ve
struct list_description proměnnou open na 1, při zavření hlavního
okna se proměnná open nastaví na 0. Pokud se při zavolání funkce
create_list_window zjistí, že proměnná open je nastavena na 1,
uživateli se objeví upozornění, že okno je již jednou otevřeno a že ho nejprve
musí zavřít. Pochopitelně toto platí pro stejný seznam. Není problém mít
otevřeno více oken, každé od jiného seznamu.
Použitý princip umožňuje závodění. V "ideálním případě" se totiž
může stát, že výše popsaný test selže a tedy bude okno seznamu otevřeno
vícekrát. Jelikož je vysoce nepravděpodobné, že se toto uživateli podaří
(kliknout ve více oknech současně na otevření okna se seznamem, a ještě mít stěstí, že
operační systém naschedulujuje oba procesy ve "vhodném" pořadí), tak
by vynaložené úsilí na implementaci precisního zamykání bylo neadekvátní k
výsledku. Proto se zvolila jednodušší varianta.
Obrázky jsou v img.c a imgcache.c, gif.c, xbm.c, png.c, jpeg.c a tiff.c . Rozhraní je následující:
- Funkce: insert_image, img_draw_image, img_change_image, img_destruct_image. Všechny
tyto funkce krom change_image jsou volány ze sazeče HTML který si je volá jak se mu
milostivě zamane. insert_image vytvoří objekt g_object_image a vloží ho do
HTML vysázeného dokumentu. destruct_image to g_object_image zničí.
destruct_image se nesmí volat víckrát na ten samý objekt. destruct_image
se smí volat jen na objekt vytvořený pomocí insert_image.
draw_image má za argument g_object_image vzniklý z insert_image, na který
nebyl zavolán destruct_image. Nakreslí obrázek.
change_image změní grafická data v g_object_image, nesmí se volat na
g_object_image, na který byl zavolán destruct_image.
- Struktury: struct g_object_image, cached_image g_object_image
je rozšířením struct g_object. g_object_image má položky id, name, border,
src, které může číst Javascript. Položky které nejsou ani v g_object ani
nejsou pro Javascript jsou pouze pro interní potřebu obrázků. cached_image
je struktura zcela interní pro obrázky. Javascript nesmí hrabat na cimg.
Javascrip může velikost obrázku získat z xw a yw v g_object_image.
- Globální proměnné: žádné.
- Funkce používané obrázky: funkce pro všeobecné použití.
Přesný popis rozhraní
- insert_image dostane g_part, image_description. Její
povinností je vyrobit struct g_object_image a vyplnit do položky
mouse_event g_text_mouse, do draw img_draw_image, do destruct
img_destruct_image, do get_list NULL. link_num a link_order musí
zkopírovat z image_description. Do map musí dát NULL. Do xw a yw
rozměr obrázku (takový jaký plyne z obrázku samotného, určení v HTML
kódu nebo spojením obou těchto údajů, případně, pokud něco z toho není
známo, může být rozměr jakýkoliv si insert_image dočasně usmyslí) patřičně
zvětšený podle momentálního nastavení uživatelem. xw i yw
musí být >=0. id,
border, vspace a hspace musí opsat ze struktury
image_description (tyto údaje jsou pro Javascript). Musí vždy provést
image->name=stracpy(im->name);
image->src=stracpy(im->url);
Pokud je insert_flag v image_description nenulový, musí insert_image ještě obrázek vložit do seznamu obrázků ve f_data:
add_to_list(current_f_data->images,&image->image_list);
.
Jinak musí provést:
image->image_list.prev=NULL;
image->image_list.next=NULL;
insert_image může zavolat af=request_additional_file(). Pokud se dá zjistit
rozměr obrázku z již stažených dat ze sítě, musí ho zjistit a podle toho
nastavit xw a yw. Pokud nedá (a hrozí že se později rozměr změní), musí
nastavit af->need_reparse na 1. need_reparse se smí jen nastavit na 1
a nesmí se nulovat. V tom případě se při zavolání
img_draw_image obrázek nemusí nakreslit korektně - může být velký a uřízlý
nebo malý a doplněný pozadím. Stejně se to má chovat, když se obrázek
reloadne a bude mít pak jiné rozměry. img_draw nesmí měnit xw a yw. xw a
yw nastavuje insert_image na začátku při vytvoření struct g_object_image.
- img_draw_image dostane struct g_object_image a souřadnice a
musí zobrazit obrázek na dané souřadnice, přičemž musí právě počmárat
obdélník s velikostí xw a yw. Nesmí ani přetahovat ani nechávat prázdná místa.
Když je obrázek už stažen a přesto nejsou známy jeho oba rozměry, pak se musí
nakreslit rozbitý rámeček s rozměry, jako kdyby místo obrázku se stahla ikonka
s lebkou. Když ještě obrázek není stažen a nejsou známy jeho rozměry, tak se
musí zobrazit to samé jako s lebkou, jen místo lebky je tam ta červená ikona.
Když je obrázek stažen a jsou známy jeho rozměry tak se zobrazí obrázek a tam
kde to ještě není dotažené tak pozadí.
Jestli se stáhlo něco nového tak se to musí zpracovat před nakreslením
obrázku.
- img_change_image dostane pointer na g_object_image, string s URL, string se src atributem a pointer na f_data.
Funkce zajistí nahrazení grafických dat v g_object_image daty z obrázku na
daném URL. Jestliže obrázek s daným URL bude již v cachi, použije obrázek z
cache. Jestliže dané URL bude stejné jako URL v g_object_image, zahájí se
stahování obrázku ze sítě bez ohledu na cache (to je z důvodu, aby se dal měnit
obrázek, když se změní a jméno zůstane).
Funkce nebude nikterak sahat na rozměry g_object_image. Pokud obrázek na
daném URL bude menší, doplní se v g_object_image pozadím. Pokud bude větší, v
g_object_image bude výřez od levého horního rohu. Funkce bude volána ze select
smyčky. Z funkce se musí zavolat request_additional_file a
refresh_image, které zajistí, že se obrázek bude automaticky periodicky
překreslovat během natahování.
- img_destruct_image musí kromě vlastních operací obrázků
vždy zavolat:
if (goi->name)mem_free(goi->name);
if (goi->src)mem_free(goi->src);
release_image_map(goi->map);
del_from_list(&goi->image_list);
a musí zcela vylikvidovat struct g_object_image *goi a zavolat
mem_free(goi).
- struct g_object_image do xw a yw nesmí nikdo hrabat kromě
funkce insert_image a img_destruct_image. Nesmí tam hrabat ani
img_draw_image. xw a yw nesmí být <0 když program není momentálně v
nějaké funkci od obrázků.
Popis struct cached_image
Struct cached_image může být v rozličných roztodivných stavech. Hlavní
stavová proměnná je state.
Proměnná state může mít hodnotu 0, 1, 2, 3, 4, 5, 6, 7, 12, 13, 14, nebo 15.
Představuje stavy ve kterých se nacacheovaný obrázek nachází
a zhruba znamená toto:
| Stav |
Ví se typ souboru? |
Hlavička obrázku (určující width a height) byla přečtena |
wanted_xw i wanted_yw urceno, obojí současně |
Obrazový proud skončil - buď skončilo spojení
nebo dekodér řekl, že už dál dekódovat nebude, ať už proto,
že obrázek skončil, nebo že se v něm narazilo na chybu) |
img_draw_image nareslí (a uživatel uvidí) |
bitmapa |
Obrazová data (buffer, rows_added) |
Obrazové informace (width, height, buffer_bytes_per_pixel,
red_gamma, green_gamma, blue_gamma) |
dregs |
Odkud se bere xww a yww |
decoder, last_length |
image_type |
gamma_stamp |
need_reparse |
gamma_table |
Stav |
| 0 |
0 |
0 |
0 |
0 |
Rám |
Neplatné |
Neplatné |
Neplatné |
Neplatné |
xww= wanted_xw< 0? scale(32): wanted_xw; yww= wanted_yw< 0?
scale(32): wanted_yw) |
Neplatné |
Neplatné |
Neplatí |
1 |
Neplatí |
0 |
| 1 |
0 |
0 |
0 |
1 |
Rozbitý rám |
Neplatné |
Neplatné |
Neplatné |
Neplatné |
xww= wanted_xw< 0? scale(32): wanted_xw; yww= wanted_yw< 0?
scale(32): wanted_yw |
Neplatné |
Neplatné |
Neplatí |
0 |
Neplatí |
1 |
| 2 |
0 |
0 |
1 |
0 |
Rám |
Neplatné |
Neplatné |
Neplatné |
Neplatné |
xww=wanted_xw, yww=wanted_yw |
Neplatné |
Neplatné |
Neplatí |
0 |
Neplatí |
2 |
| 3 |
0 |
0 |
1 |
1 |
Rozbitý rám |
Neplatné |
Neplatné |
Neplatné |
Neplatné |
xww=wanted_xw, yww=wanted_yw |
Neplatné |
Neplatné |
Neplatí |
0 |
Neplatí |
3 |
| 4 |
0 |
1 |
0 |
0 |
Tohle jsou nesmyslné stavy které nikdy nesmějí
nastat. |
4 |
| 5 |
0 |
1 |
0 |
1 |
5 |
| 6 |
0 |
1 |
1 |
0 |
6 |
| 7 |
0 |
1 |
1 |
1 |
7 |
| 8 |
1 |
0 |
0 |
0 |
Rám |
Neplatné |
Neplatné |
Neplatné |
Neplatné |
xww= wanted_xw< 0? scale(32): wanted_xw; yww= wanted_yw< 0?
scale(32): wanted_yw |
Běží |
Platný |
Neplatí |
1 |
Neplatí |
8 |
| 9 |
1 |
0 |
0 |
1 |
Rozbitý rám |
Neplatné |
Neplatné |
Neplatné |
Neplatné |
xww= wanted_xw< 0? scale(32): wanted_xw; yww= wanted_yw< 0?
scale(32): wanted_yw |
Neplatné |
Neplatné |
Neplatí |
0 |
Neplatí |
9 |
| 10 |
1 |
0 |
1 |
0 |
Rám |
Neplatné |
Neplatné |
Neplatné |
Neplatné |
xww=wanted_xw, yww=wanted_yw |
Běží |
Platný |
Neplatí |
0 |
Neplatí |
10 |
| 11 |
1 |
0 |
1 |
1 |
Rozbitý rám |
Neplatné |
Neplatné |
Neplatné |
Neplatné |
xww=wanted_xw, yww=wanted_yw |
Neplatné |
Neplatné |
Neplatí |
0 |
Neplatí |
11 |
| 12 |
1 |
1 |
0 |
0 |
Obrázek |
bmp->user? obrázek: nic |
strip_optimized ? neplatí : platí
| Platí |
strip_optimized ? platí nebo NULL: neplatí |
Pokud (wanted_xw< 0&& wanted_yw< 0), tak xww=scale(width)
a yww=scale(height). Pokud (wanted_xw>= 0&& wanted_yw< 0), pak
xww=wanted_xw a yww= (xww* height+ (width>> 1))/ width. Pokud
(wanted_yw>= 0&& wanted_xw< 0), pak yww=wanted_yw a xww=
(yww* width+ (height>> 1))/ height. |
Běží |
Platný |
Platí |
0 |
NULL nebo naalokována na umocnění na user_gamma/cimg->*_cimg_gamma |
12 |
| 13 |
1 |
1 |
0 |
1 |
Obrázek |
Obrázek |
Neplatné |
Neplatné |
Neplatné |
Pokud (wanted_xw< 0&& wanted_yw< 0), tak xww=scale(width)
a yww=scale(height). Pokud (wanted_xw>= 0&& wanted_yw< 0), pak
xww=wanted_xw a yww= (xww* height+ (width>> 1))/ width. Pokud
(wanted_yw>= 0&& wanted_xw< 0), pak yww=wanted_yw a xww=
(yww* width+ (height>> 1))/ height. width a height jsou
rozměry které měl obrázek při dekódování, nikoliv již aktuální stav
položky v cimg (tam už můžou být odpadky) |
Neplatné |
Neplatné |
Platí |
0 |
Neplatí |
13 |
| 14 |
1 |
1 |
1 |
0 |
Obrázek |
bmp->user? obrázek: nic |
strip_optimized ? neplatí : platí |
Platí |
strip_optimized ? platí nebo NULL : neplatí |
xww=wanted_xw, yww=wanted_yw |
Běží |
Platný |
Platí |
0 |
NULL nebo naalokována na umocnění na user_gamma/cimg->*_cimg_gamma |
14 |
| 15 |
1 |
1 |
1 |
1 |
Obrázek |
Obrázek |
Neplatné |
Neplatné |
Neplatné |
xww=wanted_xw, yww=wanted_yw |
Neplatné |
Platí |
Platí |
0 |
Neplatí |
15 |
Uvedené hodnoty jsou zaručeny pouze mimo funkce obrázků. Funkce obrázků
mohou být v různých polovičatých stavech a položky používat na různé
pomocné úkony takže tam to zaručeno není.
scale(něco) může představovat hodnotu odpovídající staršímu nastavení
global_fdatac->ses->ds.image_scale. Což ovšem nevadí, protože jak si
jednou obrázek "nadiktuje" svoje rozměry, tak se tyto rozměry
předají při návratu insert_image sázeči, a tomu je jedno, co v nich je.
Následující tabulka říká, při jakých příležitostech dochází k
přechodům mezi jednotlivými stavy:
| Stav po přechodu |
| 0 | 1 | 2 | 3 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 |
| Stav před přechodem | 0 | Nic | Soubor je celý stažen | | | Je znam typ souboru | | | | | | | |
| 1 | count2 se změnil | Nic | | | | | | | | | | |
| 2 | | | Nic | Soubor
skončil | | | Je
znám typ souboru | | | | | |
| 3 | | | count2 se změnil | Nic | | | | | | | | |
| 8 | count2 se
změnil | | | | Nic | Soubor
skončil | | | Přečetla se hlavička | | |
| 9 | count2 se
změnil | | | | | Nic | | | | | | |
| 10 | | | count2 se
změnil | | | | Nic | Soubor
skončil | | | Přečetla se hlavička | |
| 11 | | | zvětšil se
count2 | | | | | Nic | | | |
|
| 12 | count2 se
zvětšil | | | | | | | | Nic | Skončil
soubor | | |
| 13 | count2 se
zvětšil | | | | | | | | | Nic | | |
| 14 | | | count2 se
zvětšil | | | | | | | | Nic | Soubor
skončil |
| 15 | | | count2 se
zvětšil | | | | | | | | | Nic |
wanted_xw, wanted_yw Jsou požadované rozměry obrázku vyjádřené v
pixelech displaye. Jsou to tedy hodnoty z tagů width a height
naškálované na img->scale. Pokud tag nebyl specifikován, je v příslušné
proměnné -1. ani wanted_xw ani wanted_yw nesmí nabývat hodnoty 0.
scale je škálování pro které položka z cache platí. Při
hledání položek v cachi se ignoruje v případě, že wanted_x a wanted_y jsou
obě specifikované (aby se mohly ztotožnit obrázky které se neliší ve
výsledné velikosti).
xww a yww jsou výsledný rozměr obrázku podle aktuálních
vědomostí, vyjádřený v pixelech displaye. V případě, že se nějaký rozměr
nedá nijak určit, dá se tam provizorně scale(32). xww i yww musí být
>=1.
image_type pokud platí, definuje, o jaký druh obrázku se jedná
z hlediska Content-Type. Zjištění typu, pro který není do Linksu vestavěn
dekodér, se považuje za chybu v kódovém proudu a interpretuje se, jako
kdyby soubor skončil, proto v proměnné image_type je v případě platnosti
vždy hodnota poukazující na konkrétní typ toku obrazového kódu. Pokud se
identifikuje nějaký známý typ, do image_type se přiřadí jedna z konstant
IM_PNG, IM_MNG, IM_JPG, IM_PCX, IM_BMP, IM_TIF, IM_GIF.
rows_added když platí a je nula tak to znamená, že bitmapa
zobrazuje přesně to samé, co je v bufferu a také to znamená, že bitmapa je
platná. Pokud rows_added platí a je 1, pak to znamená, že do bufferu bylo
zapsáno a nebyla updatována bitmapa, tudíž bitmapu nelze kreslit, neboť by
zobrazovala starý stav, a tudíž je nutno před kreslením bitmapy nebo
likvidací bufferu nutno buffer předělat do bitmapy. platné rows_added a
rows_added==1 neznamená nutně, že bitmapa je neplatná. Když je rows_added
platné a bitmapa neplatná, je vždy nastaveno rows_added na 1.
buffer má paměťovou organizaci pro 8-bitové kanály podle následující tabulky.
R, G, B jsou barevné složky, A je alpha. Složky jsou uloženy v charech.
| buffer_bytes_per_pixel | Obsah paměti (po charech) | <