Links - implementacni dokumentace

Obsah

O teto dokumentaci

Tato dokumentace obsahuje navrhy autoru, kterak implementovat (byly implementovany) jednotlive casti linksu. Dokumentace neni uplna, najdou se zde pouze nektere casti. Podle teto dokumentace se pak jednotlive casti implementovaly/budou implementovat. V dokumentaci je kladen duraz zejmena na rozhrani, kvuli komunikaci s ostatnimi castmi linksu.

Bookmarky a obecne seznamy

Nejprve je potreba precist dokumentaci o select smycce.

Jak udelat bookmarky

Okno muze vypadat takto:
+--------------- Bookmarks --------------------------------------------------+
|                                                                            |
|      Bookmark 1                                                            |
|  [-] Adresar bookmarku                                                     |
|          Bookmark v adresari                                               |
|      [+] Sbaleny dalsi podadresar                                          |
|     ... atd                                                                |
|                                                                            |
|   [ Pridej ]  [ Edituj ]  [ Adresar ]  [ Presun ] a dalsi tlacitka ...     |
|                                                                            |
+----------------------------------------------------------------------------+

Vytvori se handle_event, kde se budou zachytavat kliky mysi do prislusneho seznamu seznamu bookmarku, stisky klaves nahoru, dolu, + a -. Ostatni eventy se nechaji propadnout do standartniho handleru dialogoveho okna; kod na tlacitka je jiz hotovy.

Prekreslovani bookmarku se umisti do funkce na vykreslovani okna. Nesmi se zapomenout zavolat exclude_rect_from_set pro obdelnik, ktery byl prekreslen, aby nebyl prekreslen znovu bilou.

Princip funkce struct rect_set: struct rect_set je mnozina obdelniku.
Pouzivaji se tyto funkce:
init_rect_set – vyrobi novou mnozinu;
add_to_rect_set – prida obdelnik do mnoziny;
exclude_rect_from_set – vyjme obdelnik z mnoziny a rozstepi vsechny obdelniky, ktere ho prekryvaji.
exclude_from_set – totez jako predchozi, ale ma 4 parametry jako souradnice misto jednoho rect.

Pokud se napriklad zavola add_to_rect_set s obdelnikem (0,0 - 10,10) a nasledovne exclude_rect_from_set s obdelnikem (2,2 - 5,5), pak v mnozine vzniknou ctyri obdelniky (0,0 - 10,2); (0,2 - 2,5); (5,2 - 10,5); (0,5 - 10,10)

Dialog se kresli tak, ze se do struct rect_set *dlg->s ulozi cela procha, kdyz se pak nakresli nejaka polozka, tak se na ni udela exclude_rect_from_set a na konci se prekresli vsechno, co zbylo v mnozine, bile. Tim se zajisti, ze dialogove okno nebude blikat pri prekreslovani.

dlg->s je vyrobena ve funkci draw_dlg, takze pote, co bude zavolana v layoutove funkci, budou nakresleny bookmarky a nakreslene misto vyjmuto z dlg->s. V textovem modu se tyto triky nedelaji (a rect_set tam vubec neexistuje), protoze tam blikani nehrozi.

Dabelsky D_BOX

Typ dialogove polozky D_BOX zasadne nepouzivat. Veskery kod, ktery se na nej odkazuje bude smazan. D_BOX je historicky prezitek a strasna prasarna.

Rozhrani

Bylo by dobre, aby se editor bookmarku dal pouzit i k editovani asociaci, pripon, cookies apod. Proto se musi pocitat s tim, ze polozka seznamu je v podstate libovolna. Muze se to implementovat napiklad takto:
struct list_description {
	void *new_item();
	void edit_item(struct terminal *, void *);
	void delete_item(struct terminal *, void *);
	void print_item(struct terminal *, void *, int x, int y, int width);
};

Kdyz si kazdy pak da ruzne funkce, a tak bude moci editovat v podstate libovolne polozky. new_item vyrobi prazdnou polozku, edit_item zobrazi dialogove okno na editaci polozky, delete_item zobrazi dialogove okno na smazani polozky, print_item vypise polozku na danou pozici. Mozna budou potreba dalsi funkce, toto je jen navrh, ne dogaticky pevne rozhrani.

Mozne bugy

Pokud se okno bookmarku otevre socasne na vice terminalech, tak je samozrejme mozne, ze se budou dit nepekne veci, kdyz se bude mnohokrat vrtat do stejne struktury. Bud se kod musi psat tak, ze se s tim bude pocitat (t.j. vzdy kdyz se vratis rizeni do hlavni smycky, musi se pocitat s tim, ze se vsechny struktury mohly zmenit), nebo (coz je jednodussi) se toto proste nepovoli – pokud je okno otevreno na jednom terminalu, tak se nemuze otevrit na jinem.

Taky se musi davat pozor na memory leaky – zejmena ty vznikle zmacknutim Ctrl-C v nejakem okne. Pri ladeni je nutne zmacknout Ctrl-C v kazdem stavu, v jakem se editor muze nachazet (nejlepe pri tom jeste pouzit electric fence).

Interface pro dip

Interface pro psani textu

void init_dip();
Inicializuje modul dip.
void shutdown_dip();
Shodi modul dip – uvolni vsechny cache apod.
struct style *g_get_style(int fg, int bg, int size, unsigned char *font, int fflags);
Vrati pointer na styl. fg je barva popredi ve tvaru (red << 16) + (green << 8) + blue. bg je podobne barva pozadi. bg == -1 znamena, ze se pod text bude podkladat obrazek text se nebude tisknou pomoci standartni g_print_text, ale pomoci jine funkce, ktera bude delat podkladani. size je vyska v pixelech. font je retezec popisujici font. Je potreba napsat nejake rozumne mapovani retezcu na fonty. Pokud je !strcasecmp(font, "fixed"), pak by se mel pouzit neproporcionalni font. fflags je bitovy OR nasledujicich hodnot: FF_BOLD, FF_ITALIC, FF_UNDERLINE.
struct style je soukromy typ pro dip modul, neni specifikovano, co ma obsahovat. (asi by bylo dobre tu definici presunout do dip.c a do links.h dat pouze struct style;)
void g_free_style(struct style *styl)
Uvolni styl. Neznamena, ze se struktura musi okamzite odalokovat, ale, ze muze byt odalokovana.
struct style *g_clone_style(struct style *styl)
Udela kopii stylu.
void g_print_text(struct graphics_driver *gd, struct graphics_device *dev, int x, int y, struct style *style, unsigned char *text, int *width)
Vytiskne text, pokud width != NULL, tak tam ulozi velikost textu na tu pozici.
int g_text_width(struct style *style, unsigned char *text);
Vrati sirku textu.
int g_char_width(struct style *style, unsigned char ch);
Vrati sirku znaku.
int g_wrap_text(struct wrap_struct *w);
Toto je znacna prasarna, mozna jeste bude prepisana / vyhozena. Zatim se musi napsat podobne, jak napsana je.

Ohledne sirek pisem: pokud styl nema FF_ITALIC, pak musi platit, ze sirka spojeni dvou retezcu je soucet jejich sirek. Kod v bfu.c to predpoklada. U kurzivy to pochopitelne neplati, kurziva se musi tisknout tak, aby se horni konec jednoho pismene prekryval s dolnim koncem jineho.

Jak to asi implementovat

Bude jedna globalni hash tabulka stylu. Kazdy styl ma pocitadlo pouziti. Pri g_get_style se prohleda tabulka a pokud se ten samy styl nalezne, tak se mu zvysi pocitadlo. Pokud se nenalezne, tak bude vytvoren, zarazen do hashe a nastavi se mu pocitadlo pouziti na 1. U hashovaci funkce je nutno se vyvarovat nasobeni, deleni nebo modulo, ponevadz tyto operace trvaji dost dlouho. Zasadne pouzivat operace jako napriklad +, -, ^, &, |, (<<, >> jsou uz pomalejsi, ale pouzit se taky daji). Pri zavolani g_free_style stylu se snizi pocitadlo pouziti a odstrani se z hashe, pokud uz v nem nejsou zadna nacachovana pismenka (viz nize.) Pri g_clone_style bude vracen ten samy styl a zvysi se mu pocitadlo pouziti.

Kazdy styl ma hashovou tabulku pismen. Pristup k ni musi byt rychly, nejlepsi by asi bylo pouze 'znak & (velikost_hashe - 1)'. Kdyz bude potreba tisknout pismeno, ktere neni v hashi, tak se do hashe prida.

Pismena (a dalsi objekty – jako napr. obrazky) tvori LRU seznam. Dobre by bylo udelat neco jako:

struct lru_object {
	struct lru_object *next;
	struct lru_object *prev;
	void (*release)(struct lru_object *);
};
a pak:
struct letter {
	struct letter *next;
	struct letter *prev;
	void (*release)(struct letter *);
	struct bitmap *bmp;
	a dalsi polozky ...
};
a
struct image {
	struct image *next;
	struct image *prev;
	void (*release)(struct image *);
	a dalsi polozky...
};

Do LRU cache by se mely dat davat ruzne objekty, kazdy bude mit funkci release, ktera bude zavolana na posledni objekt v seznamu.

Pri tisku pismena by se pismeno melo dat na zacatek seznamu – to bude masirovat pamet (jedno presunuti objektu = 6 zapisu). Pokud by se to melo omezit, mohou se pouzit active/inactive listy, jako ma FreeBSD v memory managementu :-) Ale to asi neni potreba, protoze zapisovani do videopameti je daleko pomalejsi...

Pri mazani pismena z cache je potreba smazat i styl, ve kterem pismeno je, pokud styl nemaji uz zadna jina pismena.

Mazani objektu z cache by se nemelo provadet po jednom, ale tak, jak to dela Linux nebo BSD – maze se spousta naraz, a pak dlouho nic. Je to lepsi, nez kdyz se cache spravuje systemem "jednu polozku pridam/jednu odeberu".

Nesmi se tez opomenout, ze cilem spravy cache neni pevne dodrzet kvotu, ale poskytnout dobry vykon. Kdyz bude na obrazovce spousta velkych pismenek nebo obrazku, tak by byl nesmysl pri kazdem prekresleni obrazovky generovat vsechna pismena jen proto, ze jejich velikost je nad kvotou.
Mozne reseni: 2 kvoty (tvrda a mekka) a timeout. Z cache se bude mazat pokud velikost_cache >= tvrda_kvota || velikost_cache >= mekka_kvota && cas_posledniho_objektu >= timeout.

Bylo by dobre spravu cache obrazku narazit na memory.c : register_cache_upcall, aby Links mohl behat i na systemech bez virtualni pameti (MS-DOS). Funguje to tak, ze se zavola void register_cache_upcall(int (*upcall)(int), unsigned char *name). upcall je funkce, ktera se zavola pokud dochazi pamet, name je jmeno cachoveho subsystemu (dip), pouziva se pro chybove hlasky. Links obcas zavola upcall s parametrem:

Prislusna funkce upcall vrati hodnotu, ktera je OR nasledujicich maker:

Dale je potreba pocitat s tim, ze upcall muze byt zavolan kdykoli, kdyz je zavolano mem_alloc nebo mem_realloc. Taky se v upcallu neda alokovat zadna pamet, protoze upcall se vola pri nedostatku pameti (pak by to tuhlo jak memory management v tucnackovi :-) ).

Obrazky

Dekodovany obrazek je popsan strukturou struct decoded_image. Struktura je soukroma pro modul; modul si do ni muze dat, co chce. Napise se funkce
void g_print_text_on_image(struct graphics_driver *gd, struct graphics_device *dev, int x, int y, struct style *style, unsigned char *text, int *width, struct decoded_image *i, int xoff, int yoff);
ktera vypise text podlozeny danym obrazkem. xoff a yoff jsou offsety posunuti obrazku (v pixelu na obrazovce o souradnicich [x, y] bude pixel obrazku o souradnicich [xoff, yoff]). xoff a yoff muzou byt vetsi, nez je obrazek, v takovem pripade se berou modulo velikost obrazku. Obrazek se pod textem periodicky opakuje.

Jak natahovat obrazky bude popsano casem...

Interface pro obrazky

Obrazky obcas bude potreba stahovat. K tomu slouzi object requester. Je treba implementovat nasledujici funkce:

struct decoded_image *img_get_decoded_image(struct object_request *rq)
Obrazek je jiz stazeny pomoci object requesteru, pripadne pouze cast, obrazek se musi dekodovat. struct decoded_image je struktura, ktera bude popisovat dekodovany obrazek (vhodny napriklad k podkladani textu apod.). struktury se budou ukladat do obrazkove cache indexovane pomoci URL a delky souboru (aby se vyresilo prubezne stahovani obrazku) a pouzije se refcount — t.j. kdyz nekdo bude chcit tentyz obrazek znovu dekodovat, tak se vrati pouze pointer z cache a zvysi se mu refcount. Stare neuplne obrazky je treba z cache prednostne mazat, ale pouze pokud maji nulovy refcount.

Tato funkce nemusi resit animaci obrazku — bude proste treba vracet prvni ramec.

void img_release_decoded_image(struct decoded_image *d)
Snizi obrazku refcount, pripadne ho odlozi do cache.
Kdyz nekdo zavola img_get_decoded_image, tak je treba zajistit, aby nebyla struktura zmenena, dokud se nezavola img_release_decoded_image.
void img_draw_decoded_image(struct graphics_device *dev, struct decoded_image *d, int x, int y, int xw, int yw, int xo, int yo)
Nakresli obrazek do oblasti zacinajici na x, y o velikosti xw, yw a s offsetem pocatecniho bodu obrazku xo, yo. (napr, kdyz xo = 5, yo = 10, tak na pozici x,y das pixel, ktery je v obrazku na pozici 5,10). Kdyz je obrazek mensi, nez oblast, tak se bude zabalovat. Kdyz je xo a yo vetsi, nez velikost obrazku, tak se tez bude pocitat modulo velikosti obrazku. Pouzivat se bude ke kresleni pozadi.
int img_get_image_size(struct object_request *rq, int *x, int *y)
V object_request je obrazek. Funkce se pokusi zjistit velikost obrazku. Vrati:
0 - velikost je zjistena a ulozena do *x a *y
1 - velikost neni zjistena, obrazek je neuplny, je treba pockat, nez se nahraje vic (toto muze byt vraceno, pokud je object_request ve stavu O_WAITING nebo O_LOADING)
2 - velikost neni zjistena a ani zjistit nejde, protoze obrazek je poskozeny, nebo tam zadny neni, nebo doslo k chybe
Tato funkce musi byt schopna pracovat s neuplnymi obrazky. Snazi se z neuplneho obrazku zjistit velikost.
struct img_active *img_draw_active_image(unsigned char *url, struct window *w, int x, int y, int xw, int yw, struct rect *clip, long color_under, struct decoded_image *image_under, int xo, int yo)
Tato funkce si sama stahne obrazek a bude ho zobrazovat v danem okne na dane pozici s danym orezavacim obdelnikem. Obrazek bude animovat. xw, yw urcuji velikost obrazku — obrazek je pripadne potreba na tuto velikost roztahnout nebo zuzit. Pokud je image_under == NULL, obrazek bude podlozen barvou color_under (ve formatu 0x00RRGGBB). Pokud je image_under != NULL, obrazek bude podlozen jinym obrazkem. Offset podlozeneho obrazku je xo, yo.
Tato funkce si sama obrazek stahne, bude ho zobrazovat, jak se postupne stahuje, a bude ho animovat. Vsechny k tomu potrebne informace si ulozi do struktury struct img_active, kterou si alokuje. Ke stahovani bude pouzivat object_requester, k animovani timery.
void img_release_active_image(struct img_active *img)
Funkce zpusobi, ze se obrazek kresleny pomoci img_draw_active_image prestane zobrazovat. Neznamena to ovsem, ze se prestane nahravat. Nahravat se bude porad na pozadi, pouze se zmeny nebudou zobrazovat na obrazovku, dokud zase nekdo nezavola img_draw_active_image.

U poslednich dvou funkci je treba resit takove situace, jako napriklad kdyz se dvakrat na tentyz obrazek zavola img_draw_active_image, aby obrazek byl dekodovan pouze jednou apod. Take kdyz se zavola img_draw_active_image, pak hned img_release_active_image a pak zas img_draw_active_image, tak by se cely obrazek nemel znovu dekodovat. Doporucuji udelat dalsi zvenku neviditelnou strukturu, na kterou bude img_active ukazovat. V teto strukture se budou ukladat vsechna data ohledne nahravani a dekodovani, struktura bude take obsahovat seznam img_active na ni ukazujicich, a kdyz prijdou ze site nejaka data, tak je vsechna prekresli.

Interface pro javascript

Nejdriv je potreba precist si o select smycce v select.html.

struct javascript_context bude zakladni struktura obsahujici kontext javascriptu. Tato struktura je soukroma pro modul js.c, proto si modul do ni muze davat, co chce. Jlikoz muze soucasne bezet vice javascriptu (predpokladam jeden na kazdy ram), je treba veskery stav javascript engine dat do teto struktury. Nemelo by tam byt prilis mnoho globalnich promennych. Je treba si uvedomit, ze javascript pracuje s kodem stahnutym ze site a proto musi byt extremne bezpecny. Nedelat zadna pole staticke velikosti – vzdy si pamet pro vsemozne retezce alokovat dynamicky (viz. info o retezcich). A uz vubec nedelat pole na zasobniku!

Zakladni funkce jsou:

struct javascript_context *js_create_context(void *p)
POZOR ZMENA - viz Update 3
Vyrobi novy javascript context. p je parametr, ktery bude predavan, kdyz bude potreba provest nejake volani do interfacu.
void js_destroy_context(struct javascript_context *context)
Zrusi kontext. Pozadavek na zruseni muze prijit kdykoli, kdyz javascript preda rizeni nekomu jinemu. Je treba zajistit, aby byly odalokovany vsechny bloky pameti (jinak pri skonceni Linkse budedetekovan memory leak), odstraneny porcovaci tabulky flexe a bizona, odstraneny veskere registrovane timery nebo bottom halfy (bottom half predcasne odstranit nejde - proto by v pripade pouziti bottom halfu bylo dobre napsat kod tak, aby js_destroy_context nastavil flag, ze se kontext ma zrusit a registroval bottom half, ktery po zjisteni, ze je nastaven flag, zrusil kontext).
void js_execute_code(struct javascript_context *context, unsigned char *code, int len)
POZOR ZMENA - viz Update 2
Spusti nejaky kod v javascript engine. Muze se stat, ze v javascript engine prave nejaky kod bezi — v takovem pripade se kod musi ulozit do fronty a spustit se pozdeji. Je treba brat ohled na to, ze v pripade opusteni teto funkce muze kod na dane pozici prestat existovat. Jsou tedy 2 moznosti, jak to napsat:

Upcally

Javascript muze zasahovat do ruznych casti browseru. Aby to bylo bezpecne, nebude rovnou zasahovat do browseru, ale zavola nejake funkce z interface. Upcally je mozno volat pouze z nejnizsi urovne — t.j. z funkce volane z timeru, bottom halfu, signal nebo file handlu (signal ani file handly nebudou potreba). Napriklad bude zavolan js_execute_code, JS z nej zavola treba js_upcall_open_url, pak se vrati z js_execute_code do funkce, ktera ho zavolala — a aktualni dokument prestane existovat, coz vyusti v CRASH.

Proto se musi zaregistrovat signal handler s casem 0 nebo bottom half, ktery teprve bude moci zavolat js_upcall_open_url. Protoze ho zavola rovnou z select smycky, nestane se, ze by se pak provedl navrat do funkce, pricemz struktura, se kterou pracovala neexistuje.

Domluvime se na upcallech a pak se zacnou implementovat.

Odblokovani

Neni dobre, aby smycka v javascriptu zatuhla cely browser. Proto je potreba aby se cas od casu nastavil timer s casem 0 (pozor - bottom half v tomto pripade nebude fungovat - kdyz se z bottom halfu registruje dalsi bottom half, tak se nikdo jiny k lizu nedostane), a z funkce se vyskocilo. Funkce, ktera se jako timer registruje, bude pokracovat ve vykonavani javascriptu, ale mezitim se budou moci stat jine veci, jako treba osetreni stisku klavesy nebo stahnuti neceho ze site. Pokud bude javascript takto odblokovan, musi se pocitat s tim, ze muze byt zavolat js_destroy_context a vsechno se bude muset zrusit.
Aby se JS neodblokovaval moc casto nebo moc malo casto, pouzije se funkce get_time k mereni casu. get_time vola funkci kernelu gettimeofday, ktera neni moc rychla, takze by se nemela volat po kazdem prikazu, ale trochu mene casteji.

Kde se bude kod vykonavat, je velku jedno. Asi nejlepsi by bylo primo z js_execute_code nevykonavat zadny kod (protoze se z neho nesmi delat upcally), ale vyrobit vyznamovy strom a (pokud neni prave vykonavan zadny jiny kod v danem kontextu) nastavit timer s hodnotou 0 nebo bottom half, ze ktereho se teprve bude kod vykonavat.

Update 1: popis dokumentu

Kazdy dokument ma svoje ID. ID dokumentu jsou "vecne rostouci" – kdyz je nejaky dokument zrusen, jeho ID bude prideleno az po 2^32 jinych dokumentech. Kazdy objekt v dokumentu ma ID. Muze se predpokladat, ze nekolik objektu ruzneho typu muze mit stejne ID (kdyby toto rozhodnuti prilis vadilo, tak se da zrusit...). Objekt je urcen jednoznacne trojici (id dokumentu, id objektu, typ objektu) – pri vsech upcallech se bude predavat id dokumentu a id objektu; typ vyplyva z volane funkce. Pri upcallech je mozno zadavat spatna id dokumentu nebo objektu. Kdyz se tak stane, tak upcall neprovede nic, pripadne nevrati nic.

Budeme mit strukturu struct js_document_description. Ta bude popisovat, jake objekty se v dokumentu nalezaji, jaka maji jmena, pripadne jejich tagy a podobne. U kazdeho objektu bude taky ulozeno ID (ale neni to nutne; muze se napriklad vytvorit pole nejakych objektu a rici, ze ID je index v tom poli). Struktura nebude popisovat aktualni stavy objektu – bude v ni napriklad receno, ze nekde je nejaka polozka formulare, ktera se nejak jmenuje, ale nebude tam uz jeji obsah. Struktura se bude menit pouze pri pusteni html engine.
V pripade, ze dokument obsahuje ramy, bude struktura obsahovat ID objektu ramu, pres ktera se budes moci pres urcity upcall zeptat na ID dokumentu ramu.

Bude mozno volat tyto funkce:

struct js_document_description *js_upcall_get_document_description(void *p, long doc_id).
p je pointer predany pri js_create_context.
id je ID dokumentu.
Tato funkce vrati popis dokumentu, pripadne NULL (nutno testovat - at to nepada, jako Netscape!), pokud dokument s danym id neexistuje. Je treba dbat na to, ze kdyz se JS odblokuje, tak tato struktura muze zmizet - musi se tedy znovu zavolat js_upcall_get_document_description. V pripade, ze nedoslo k preporcovani nebo zmizeni dokumentu, funkce pri dalsim volani vrati jiz existujici strukturu – da se tedy predpokladat, ze to bude jeste docela rychle.
S pointerem na strukturu se jiz da hledat ve strukture ID objektu podle libovolnych kriterii.

Update 2: zmena vyznamu js_execute_code

void js_execute_code(struct javascript_context *context, unsigned char *code, int len, void (*callback)(void *p))
Po skonceni vykonavani kodu se zavola callback s parametrem p, ktery byl predan pri vytvareni contextu. Funkci callback je potreba zavolat z nejnizsi urovne – t.j. ne primo z funkce js_execute_code. Pokud je context zrusen pomoci js_destroy_context, tak callback uz zavolano nebude.

Je zaruceno, ze kdyz se vykonava nejaky kod, a jeste nebyl zavolan callback, tak js_execute_code nebude zavolana znovu. Kdyby se to stalo, tak je nutne nahlasit INTERNAL ERROR. Frontu pozadavku na spusteni kodu budu delat u sebe.
Pote zavolani callback uz neni mozno volat zadne funkce pro modifikaci dokumentu.

Update 3: prvni implementace

struct javascript_context *js_create_context(void *p, long id)
Funkce dostane jako parametr id ramu, ktereho se kontext tyka.

Jiz je napsano prvni implementaci rozhrani na javascript. Jediny upcall, ktery tam zatim je, je

void js_upcall_document_write(void *p, unsigned char *str, int len)
provede funkci document.write. p je pointer predany pri js_create_context. Funkce by mela spravne zvladat i kdyz script pomoci document.write vytvori jiny script.

Implementace je zatim primitivni – cte obsahy tagu <SCRIPT>, pocka 1 sekundu, prekonvertuje na velka pismena a predava je, jako by na byla zavolana document.write. Rozhrani mezi linksem a javascriptem je v jsint.c (tam budou dopisovany upcally). Vlastni interpret je v js.c. Zatim se neumi provadet javascript pri eventech (i kdyz uz je to trochu pripraveno).

Struktury

Kazda session je popsana strukturou struct session. Kazdy ram je popsan strukturou struct f_data_c. Ram popisujici cele okno v session je session->screen. Ram ma podramy f_data_c->subframes a pointer na rodice f_data_c->parent. Pokud je to nejvyssi ram, je parrent == NULL. Ram muze (ale nemusi - pozor na NULL) mit pointer na view_state a na f_data. view_state popisuje vsechny promenlive veci (prave aktivni link, stavy formularu). f_data popisuje zformatovany dokument. view_state se ukladaji do historie, f_data se ukladaji do cache zformatovanych dokumentu.

Upcally

Na upcally existuje funkce struct js_document_description *js_upcall_get_document_description(void *p, long doc_id), ktera ma vratit popis dokumentu. V popisu dokumentu zatim nic neni. Dalsi potrebne polozky (napr. seznam polozek formulare atd.) se navrhnou a pridaji. Analogicky k tomu funkce void jsint_destroy_document_description(struct f_data *f) tuto strukturu zrusi.

Upcally budou vypadat, jako napriklad unsigned char *js_upcall_get_form_entry_value(void *p, long doc_id, long entry_id). Upcall by mel pomoci jsint_find_document nalezt prislusny ram, pak pomoci jsint_can_access zjistit, zda ma pravo pristupovat (musi se delat — jinak je to security BUG!). Az se obdrzi f_data_c ciloveho dokumentu, tak se v jeho view_state ta polozka muze najit. Je potreba davat pozor na veskera preteceni. Nikdy se nesmi spolehat, ze se JS nic nezmenilo. Muze se treba vyskytnout view_state, ve kterem zadne polozky formulare nejsou, a kod pri tom nesmi spadnout.

Upcall na document.write tam uz je hotovy. Pokud bude potreba zasahovat do zformatovaneho dokumentu (treba menit linky apod.), muze se zasahovat rovnou do f_data. Ale pozor: pote, co se zmeni neco v f_data musis se nastavit f_data->uncacheable na 1, aby se ten dokument se zmenami neulozil do cache. Taky by se pak mela zavolat draw_fd, aby se vsechny zmeny nakreslily.