diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/IO/IO.c | 13 | ||||
-rw-r--r-- | src/IO/about.c | 70 | ||||
-rw-r--r-- | src/IO/http.c | 270 | ||||
-rw-r--r-- | src/Makefile.am | 3 | ||||
-rw-r--r-- | src/cache.c | 145 | ||||
-rw-r--r-- | src/cache.h | 3 | ||||
-rw-r--r-- | src/capi.c | 149 | ||||
-rw-r--r-- | src/colors.c | 2 | ||||
-rw-r--r-- | src/cookies.h | 3 | ||||
-rw-r--r-- | src/css.cc | 2 | ||||
-rw-r--r-- | src/css.hh | 2 | ||||
-rw-r--r-- | src/cssparser.cc | 68 | ||||
-rw-r--r-- | src/decode.c | 26 | ||||
-rw-r--r-- | src/decode.h | 16 | ||||
-rw-r--r-- | src/dicache.c | 272 | ||||
-rw-r--r-- | src/dicache.h | 13 | ||||
-rw-r--r-- | src/dillo.cc | 20 | ||||
-rw-r--r-- | src/domain.c | 4 | ||||
-rw-r--r-- | src/form.cc | 38 | ||||
-rw-r--r-- | src/gif.c | 19 | ||||
-rw-r--r-- | src/html.cc | 697 | ||||
-rw-r--r-- | src/html_charrefs.h | 2138 | ||||
-rw-r--r-- | src/html_common.hh | 5 | ||||
-rw-r--r-- | src/image.cc | 6 | ||||
-rw-r--r-- | src/jpeg.c | 1 | ||||
-rw-r--r-- | src/klist.c | 2 | ||||
-rw-r--r-- | src/menu.cc | 35 | ||||
-rw-r--r-- | src/paths.cc | 6 | ||||
-rw-r--r-- | src/png.c | 11 | ||||
-rw-r--r-- | src/prefs.c | 3 | ||||
-rw-r--r-- | src/prefs.h | 3 | ||||
-rw-r--r-- | src/prefsparser.cc | 3 | ||||
-rw-r--r-- | src/styleengine.cc | 60 | ||||
-rw-r--r-- | src/styleengine.hh | 2 | ||||
-rw-r--r-- | src/table.cc | 27 | ||||
-rw-r--r-- | src/ui.cc | 2 | ||||
-rw-r--r-- | src/uicmd.cc | 19 | ||||
-rw-r--r-- | src/url.c | 31 | ||||
-rw-r--r-- | src/url.h | 9 | ||||
-rw-r--r-- | src/web.cc | 2 |
40 files changed, 3338 insertions, 862 deletions
diff --git a/src/IO/IO.c b/src/IO/IO.c index a0a8bba5..0addf486 100644 --- a/src/IO/IO.c +++ b/src/IO/IO.c @@ -298,6 +298,8 @@ static void IO_fd_write_cb(int fd, void *data) } else { if (IO_callback(io) == 0) a_IOwatch_remove_fd(fd, DIO_WRITE); + if (io->Status) + a_IO_ccc(OpAbort, 1, FWD, io->Info, NULL, NULL); } } @@ -350,6 +352,7 @@ void a_IO_ccc(int Op, int Branch, int Dir, ChainLink *Info, switch (Op) { case OpStart: io = IO_new(IOWrite); + io->Info = Info; Info->LocalKey = io; break; case OpSend: @@ -384,6 +387,13 @@ void a_IO_ccc(int Op, int Branch, int Dir, ChainLink *Info, } else { /* 1 FWD */ /* Write-data status */ switch (Op) { + case OpAbort: + io = Info->LocalKey; + IO_close_fd(io, IO_StopRdWr); + IO_free(io); + a_Chain_fcb(OpAbort, Info, NULL, NULL); + dFree(Info); + break; default: MSG_WARN("Unused CCC\n"); break; @@ -406,9 +416,10 @@ void a_IO_ccc(int Op, int Branch, int Dir, ChainLink *Info, IO_submit(io); } break; + case OpEnd: case OpAbort: io = Info->LocalKey; - IO_close_fd(io, IO_StopRdWr); + IO_close_fd(io, Op == OpEnd ? IO_StopRd : IO_StopRdWr); IO_free(io); dFree(Info); break; diff --git a/src/IO/about.c b/src/IO/about.c index 5ffe7dff..0cc3b427 100644 --- a/src/IO/about.c +++ b/src/IO/about.c @@ -229,29 +229,32 @@ const char *const AboutSplash= "<table border='0' cellpadding='5' cellspacing='1' width='100%'>\n" "<tr>\n" " <td bgcolor='#CCCCCC'>\n" -" <h4>Release overview</h4>\n" -" December 24, 2014\n" +" <h4>Notes</h4>\n" "<tr>\n" " <td bgcolor='#FFFFFF'>\n" " <table border='0' cellspacing='0' cellpadding='5'>\n" " <tr>\n" " <td>\n" -"<p>\n" -"The dillo-3.0.4.1 release brings you fixes:\n" "<ul>\n" -"<li> for linking with the recently-released fltk-1.3.3\n" -" (we don't use <tt>fl_oldfocus</tt> anymore).\n" -"<li> to make sure that windows are resizable with fltk-1.3.3.\n" -"<li> not to load background images, or follow redirections or meta refresh,\n" -" in <tt>--local</tt> mode (security).\n" -"<li> to permit linking on OS X (remove our <tt>Fl_Printer</tt> stub).\n" -"<li> for a crash when searching from the address bar and no search urls are\n" -" found in dillorc.\n" +" <li> There's a\n" +" <a href='http://www.dillo.org/dillorc'>dillorc</a>\n" +" (readable config) file inside the tarball. It is well-commented\n" +" and has plenty of options to customize dillo, so <STRONG>copy\n" +" it</STRONG> to your <STRONG>~/.dillo/</STRONG> directory, and\n" +" modify it to your taste.\n" +" <li> The right mouse button brings up a context-sensitive menu\n" +" (available on pages, links, images, forms, the Back and Forward buttons,\n" +" and the bug meter).\n" +" <li> Cookies are disabled by default for privacy. To log into certain\n" +" sites, you may need to <a href='http://www.dillo.org/Cookies.txt'>enable\n" +" cookies selectively</a>.\n" +" <li> Frames, Java and Javascript are not supported.\n" +" <li> This release is mainly intended for <strong>developers</strong>\n" +" and <strong>advanced users</strong>.\n" +" <li> Documentation for developers is in the <CODE>/doc</CODE>\n" +" dir inside the tarball; you can find directions on everything\n" +" else at the home page.\n" "</ul>\n" -"<p>\n" -"...that shouldn't have to wait until dillo-3.1 is ready with its floating\n" -"elements and assorted good things.\n" -"<p>\n" " </table>\n" "</table>\n" "</table>\n" @@ -262,32 +265,29 @@ const char *const AboutSplash= "<table border='0' cellpadding='5' cellspacing='1' width='100%'>\n" "<tr>\n" " <td bgcolor='#CCCCCC'>\n" -" <h4>Notes</h4>\n" +" <h4>Release overview</h4>\n" +" December 24, 2014\n" "<tr>\n" " <td bgcolor='#FFFFFF'>\n" " <table border='0' cellspacing='0' cellpadding='5'>\n" " <tr>\n" " <td>\n" +"<p>\n" +"The dillo-3.0.4.1 release brings you fixes:\n" "<ul>\n" -" <li> There's a\n" -" <a href='http://www.dillo.org/dillorc'>dillorc</a>\n" -" (readable config) file inside the tarball. It is well-commented\n" -" and has plenty of options to customize dillo, so <STRONG>copy\n" -" it</STRONG> to your <STRONG>~/.dillo/</STRONG> directory, and\n" -" modify it to your taste.\n" -" <li> Documentation for developers is in the <CODE>/doc</CODE>\n" -" dir inside the tarball; you can find directions on everything\n" -" else at the home page.\n" -" <li> The right mouse button brings up a context-sensitive menu\n" -" (available on pages, links, images, forms, the Back and Forward buttons,\n" -" and the bug meter).\n" -" <li> Dillo behaves very nicely when browsing local files, images, and HTML.\n" -" It's also very good for Internet searching.\n" -" <li> This release is mainly intended for <strong>developers</strong>\n" -" and <strong>advanced users</strong>.\n" -" <li> Frames, Java and Javascript are not supported.\n" +"<li> for linking with the recently-released fltk-1.3.3\n" +" (we don't use <tt>fl_oldfocus</tt> anymore).\n" +"<li> to make sure that windows are resizable with fltk-1.3.3.\n" +"<li> not to load background images, or follow redirections or meta refresh,\n" +" in <tt>--local</tt> mode (security).\n" +"<li> to permit linking on OS X (remove our <tt>Fl_Printer</tt> stub).\n" +"<li> for a crash when searching from the address bar and no search urls are\n" +" found in dillorc.\n" "</ul>\n" -"<br>\n" +"<p>\n" +"...that shouldn't have to wait until dillo-3.1 is ready with its floating\n" +"elements and assorted good things.\n" +"<p>\n" " </table>\n" "</table>\n" "</table>\n" diff --git a/src/IO/http.c b/src/IO/http.c index a0021a9e..49b3a3ac 100644 --- a/src/IO/http.c +++ b/src/IO/http.c @@ -48,6 +48,8 @@ D_STMT_START { \ #define _MSG_BW(web, root, ...) +static const int HTTP_PORT = 80; + static const int HTTP_SOCKET_USE_PROXY = 0x1; static const int HTTP_SOCKET_QUEUED = 0x4; static const int HTTP_SOCKET_TO_BE_FREED = 0x8; @@ -67,28 +69,23 @@ typedef struct { /* Data structures and functions to queue sockets that need to be * delayed due to the per host connection limit. */ -typedef struct SocketQueueEntry { - SocketData_t* sock; - struct SocketQueueEntry *next ; -} SocketQueueEntry_t; - -typedef struct { - SocketQueueEntry_t *head; - SocketQueueEntry_t *tail; -} SocketQueue_t; - typedef struct { char *host; - int active_connections; - SocketQueue_t queue; + int active_conns; + Dlist *queue; } HostConnection_t; -static void Http_socket_queue_init(SocketQueue_t *sq); -static void Http_socket_enqueue(SocketQueue_t *sq, SocketData_t* sock); -static SocketData_t* Http_socket_dequeue(SocketQueue_t *sq); +typedef struct { + int fd; + int skey; +} FdMapEntry_t; + +static void Http_socket_enqueue(HostConnection_t *hc, SocketData_t* sock); +static SocketData_t* Http_socket_dequeue(HostConnection_t *hc); static HostConnection_t *Http_host_connection_get(const char *host); static void Http_host_connection_remove(HostConnection_t *hc); static int Http_connect_socket(ChainLink *Info); +static void Http_send_query(ChainLink *Info, SocketData_t *S); static void Http_socket_free(int SKey); /* @@ -101,6 +98,11 @@ static char *HTTP_Proxy_Auth_base64 = NULL; static char *HTTP_Language_hdr = NULL; static Dlist *host_connections; +/* TODO: If fd_map will stick around in its present form (FDs and SocketData_t) + * then consider whether having both this and ValidSocks is necessary. + */ +static Dlist *fd_map; + /* * Initialize proxy vars and Accept-Language header */ @@ -125,6 +127,7 @@ int a_Http_init(void) */ host_connections = dList_new(5); + fd_map = dList_new(20); return 0; } @@ -155,14 +158,39 @@ void a_Http_set_proxy_passwd(const char *str) static int Http_sock_new(void) { SocketData_t *S = dNew0(SocketData_t, 1); + S->SockFD = -1; return a_Klist_insert(&ValidSocks, S); } +/* + * Compare by FD. + */ +static int Http_fd_map_cmp(const void *v1, const void *v2) +{ + int fd = VOIDP2INT(v2); + const FdMapEntry_t *e = v1; + + return (fd == e->fd) ? 0 : 1; +} + +/* + * Remove and free entry from fd_map. + */ +static void Http_fd_map_remove_entry(int fd) +{ + void *data = dList_find_custom(fd_map, INT2VOIDP(fd), Http_fd_map_cmp); + + if (data) { + dList_remove_fast(fd_map, data); + dFree(data); + } +} + static void Http_connect_queued_sockets(HostConnection_t *hc) { SocketData_t *sd; - while (hc->active_connections < prefs.http_max_conns && - (sd = Http_socket_dequeue(&hc->queue))) { + while (hc->active_conns < prefs.http_max_conns && + (sd = Http_socket_dequeue(hc))) { sd->flags &= ~HTTP_SOCKET_QUEUED; @@ -177,8 +205,17 @@ static void Http_connect_queued_sockets(HostConnection_t *hc) Http_socket_free(VOIDP2INT(Info->LocalKey)); /* free sd */ dFree(Info); } else { + FdMapEntry_t *e = dNew0(FdMapEntry_t, 1); + + e->fd = sd->SockFD; + e->skey = VOIDP2INT(sd->Info->LocalKey); + dList_append(fd_map, e); + + hc->active_conns++; + a_Chain_bcb(OpSend, sd->Info, &sd->SockFD, "FD"); + a_Chain_fcb(OpSend, sd->Info, &sd->SockFD, "FD"); + Http_send_query(sd->Info, sd); sd->connected_to = hc->host; - hc->active_connections++; } } } @@ -197,11 +234,13 @@ static void Http_socket_free(int SKey) if (S->flags & HTTP_SOCKET_QUEUED) { S->flags |= HTTP_SOCKET_TO_BE_FREED; } else { + if (S->SockFD != -1) + Http_fd_map_remove_entry(S->SockFD); if (S->connected_to) { HostConnection_t *hc = Http_host_connection_get(S->connected_to); - hc->active_connections--; + hc->active_conns--; Http_connect_queued_sockets(hc); - if (hc->active_connections == 0) + if (hc->active_conns == 0) Http_host_connection_remove(hc); } dFree(S); @@ -275,6 +314,10 @@ Dstr *a_Http_make_query_str(const DilloUrl *url, const DilloUrl *requester, web_flags & WEB_Stylesheet ? "text/css,*/*;q=0.1" : "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"; + const char *connection_hdr_val = + (prefs.http_persistent_conns == TRUE && + !dStrAsciiCasecmp(URL_SCHEME(url), "http")) ? "keep-alive" : "close"; + if (use_proxy) { dStr_sprintfa(request_uri, "%s%s", URL_STR(url), @@ -309,15 +352,15 @@ Dstr *a_Http_make_query_str(const DilloUrl *url, const DilloUrl *requester, "DNT: 1\r\n" "%s" /* proxy auth */ "%s" /* referer */ - "Connection: close\r\n" + "Connection: %s\r\n" "Content-Type: %s\r\n" "Content-Length: %ld\r\n" "%s" /* cookies */ "\r\n", request_uri->str, URL_AUTHORITY(url), prefs.http_user_agent, accept_hdr_value, HTTP_Language_hdr, auth ? auth : "", - proxy_auth->str, referer, content_type->str, (long)URL_DATA(url)->len, - cookies); + proxy_auth->str, referer, connection_hdr_val, content_type->str, + (long)URL_DATA(url)->len, cookies); dStr_append_l(query, URL_DATA(url)->str, URL_DATA(url)->len); dStr_free(content_type, TRUE); } else { @@ -333,13 +376,13 @@ Dstr *a_Http_make_query_str(const DilloUrl *url, const DilloUrl *requester, "DNT: 1\r\n" "%s" /* proxy auth */ "%s" /* referer */ - "Connection: close\r\n" + "Connection: %s\r\n" "%s" /* cache control */ "%s" /* cookies */ "\r\n", request_uri->str, URL_AUTHORITY(url), prefs.http_user_agent, accept_hdr_value, HTTP_Language_hdr, auth ? auth : "", - proxy_auth->str, referer, + proxy_auth->str, referer, connection_hdr_val, (URL_FLAGS(url) & URL_E2EQuery) ? "Pragma: no-cache\r\nCache-Control: no-cache\r\n" : "", cookies); @@ -416,7 +459,7 @@ static int Http_connect_socket(ChainLink *Info) struct sockaddr_in *sin = (struct sockaddr_in *)&name; socket_len = sizeof(struct sockaddr_in); sin->sin_family = dh->af; - sin->sin_port = S->port ? htons(S->port) : htons(DILLO_URL_HTTP_PORT); + sin->sin_port = S->port ? htons(S->port) : htons(HTTP_PORT); memcpy(&sin->sin_addr, dh->data, (size_t)dh->alen); if (a_Web_valid(S->web) && (S->web->flags & WEB_RootUrl)) MSG("Connecting to %s\n", inet_ntoa(sin->sin_addr)); @@ -430,7 +473,7 @@ static int Http_connect_socket(ChainLink *Info) socket_len = sizeof(struct sockaddr_in6); sin6->sin6_family = dh->af; sin6->sin6_port = - S->port ? htons(S->port) : htons(DILLO_URL_HTTP_PORT); + S->port ? htons(S->port) : htons(HTTP_PORT); memcpy(&sin6->sin6_addr, dh->data, dh->alen); inet_ntop(dh->af, dh->data, buf, sizeof(buf)); if (a_Web_valid(S->web) && (S->web->flags & WEB_RootUrl)) @@ -447,9 +490,6 @@ static int Http_connect_socket(ChainLink *Info) dClose(S->SockFD); MSG("Http_connect_socket ERROR: %s\n", dStrerror(S->Err)); } else { - a_Chain_bcb(OpSend, Info, &S->SockFD, "FD"); - a_Chain_fcb(OpSend, Info, &S->SockFD, "FD"); - Http_send_query(S->Info, S); return 0; /* Success */ } } @@ -491,7 +531,6 @@ static int Http_must_use_proxy(const DilloUrl *url) /* * Return a new string for the request used to tunnel HTTPS through a proxy. - * As of 2009, the best reference appears to be section 5 of RFC 2817. */ char *a_Http_make_connect_str(const DilloUrl *url) { @@ -565,11 +604,11 @@ static void Http_dns_cb(int Status, Dlist *addr_list, void *data) hc = Http_host_connection_get(URL_HOST(HTTP_Proxy)); else hc = Http_host_connection_get(URL_HOST(S->web->url)); - Http_socket_enqueue(&hc->queue, S); + Http_socket_enqueue(hc, S); Http_connect_queued_sockets(hc); } else { /* DNS wasn't able to resolve the hostname */ - MSG_BW(S->web, 0, "ERROR: Dns can't resolve %s", + MSG_BW(S->web, 0, "ERROR: DNS can't resolve %s", (S->flags & HTTP_SOCKET_USE_PROXY) ? URL_HOST_(HTTP_Proxy) : URL_HOST_(S->web->url)); a_Chain_bfcb(OpAbort, S->Info, NULL, "Both"); @@ -620,6 +659,46 @@ static int Http_get(ChainLink *Info, void *Data1) } /* + * If any entry in the socket data queue can reuse our connection, set it up + * and send off a new query. + */ +static void Http_socket_reuse(int SKey) +{ + SocketData_t *new_sd, *old_sd = a_Klist_get_data(ValidSocks, SKey); + HostConnection_t *hc = Http_host_connection_get(old_sd->connected_to); + int i, n = dList_length(hc->queue); + + for (i = 0; i < n; i++) { + new_sd = dList_nth_data(hc->queue, i); + + if (a_Web_valid(new_sd->web) && old_sd->port == new_sd->port) { + new_sd->SockFD = old_sd->SockFD; + Http_fd_map_remove_entry(old_sd->SockFD); + a_Klist_remove(ValidSocks, SKey); + dFree(old_sd); + + dList_remove(hc->queue, new_sd); + new_sd->flags &= ~HTTP_SOCKET_QUEUED; + FdMapEntry_t *e = dNew0(FdMapEntry_t, 1); + e->fd = new_sd->SockFD; + e->skey = VOIDP2INT(new_sd->Info->LocalKey); + dList_append(fd_map, e); + + a_Chain_bcb(OpSend, new_sd->Info, &new_sd->SockFD, "FD"); + a_Chain_fcb(OpSend, new_sd->Info, &new_sd->SockFD, "FD"); + Http_send_query(new_sd->Info, new_sd); + new_sd->connected_to = hc->host; + return; + } + } + dClose(old_sd->SockFD); + Http_fd_map_remove_entry(old_sd->SockFD); + a_Klist_remove(ValidSocks, SKey); + hc->active_conns--; + dFree(old_sd); +} + +/* * CCC function for the HTTP module */ void a_Http_ccc(int Op, int Branch, int Dir, ChainLink *Info, @@ -648,7 +727,6 @@ void a_Http_ccc(int Op, int Branch, int Dir, ChainLink *Info, case OpEnd: /* finished the HTTP query branch */ a_Chain_bcb(OpEnd, Info, NULL, NULL); - Http_socket_free(SKey); dFree(Info); break; case OpAbort: @@ -659,51 +737,97 @@ void a_Http_ccc(int Op, int Branch, int Dir, ChainLink *Info, break; } } else { /* 1 FWD */ + SocketData_t *sd; /* HTTP send-query status branch */ switch (Op) { + case OpAbort: + if ((sd = a_Klist_get_data(ValidSocks, SKey))) + MSG_BW(sd->web, 1, "Can't get %s", URL_STR(sd->web->url)); + a_Chain_fcb(OpAbort, Info, NULL, "Both"); + Http_socket_free(SKey); + dFree(Info); + break; default: MSG_WARN("Unused CCC\n"); break; } } + } else if (Branch == 2) { + if (Dir == FWD) { + /* Receiving from server */ + switch (Op) { + case OpSend: + /* Data1 = dbuf */ + a_Chain_fcb(OpSend, Info, Data1, "send_page_2eof"); + break; + case OpEnd: + a_Chain_fcb(OpEnd, Info, NULL, NULL); + Http_socket_free(SKey); + dFree(Info); + break; + default: + MSG_WARN("Unused CCC\n"); + break; + } + } else { /* 2 BCK */ + switch (Op) { + case OpStart: + a_Chain_link_new(Info, a_Http_ccc, BCK, a_IO_ccc, 2, 2); + a_Chain_bcb(OpStart, Info, NULL, NULL); /* IORead */ + break; + case OpSend: + if (Data2) { + if (!strcmp(Data2, "FD")) { + int fd = *(int*)Data1; + FdMapEntry_t *fme = dList_find_custom(fd_map, INT2VOIDP(fd), + Http_fd_map_cmp); + Info->LocalKey = INT2VOIDP(fme->skey); + a_Chain_bcb(OpSend, Info, Data1, Data2); + } else if (!strcmp(Data2, "reply_complete")) { + a_Chain_bfcb(OpEnd, Info, NULL, NULL); + Http_socket_reuse(SKey); + dFree(Info); + } + } + break; + case OpAbort: + a_Chain_bcb(OpAbort, Info, NULL, NULL); + dFree(Info); + break; + default: + MSG_WARN("Unused CCC\n"); + break; + } + } } } - -static void Http_socket_queue_init(SocketQueue_t *sq) -{ - sq->head = NULL; - sq->tail = NULL; -} - -static void Http_socket_enqueue(SocketQueue_t *sq, SocketData_t* sock) +/* + * Add socket data to the queue. Pages/stylesheets/etc. have higher priority + * than images. + */ +static void Http_socket_enqueue(HostConnection_t *hc, SocketData_t* sock) { - SocketQueueEntry_t *se = dNew(SocketQueueEntry_t, 1); + if ((sock->web->flags & WEB_Image) == 0) { + int i, n = dList_length(hc->queue); - se->sock = sock; - se->next = NULL; + for (i = 0; i < n; i++) { + SocketData_t *curr = dList_nth_data(hc->queue, i); - if (sq->tail) - sq->tail->next = se; - sq->tail = se; - - if (! sq->head) - sq->head = se; + if (a_Web_valid(curr->web) && (curr->web->flags & WEB_Image)) { + dList_insert_pos(hc->queue, sock, i); + return; + } + } + } + dList_append(hc->queue, sock); } -static SocketData_t* Http_socket_dequeue(SocketQueue_t *sq) +static SocketData_t* Http_socket_dequeue(HostConnection_t *hc) { - SocketQueueEntry_t *se = sq->head; - SocketData_t *sd = NULL; - - if (se) { - sq->head = se->next; - if (sq->tail == se) - sq->tail = NULL; - sd = se->sock; - dFree(se); - } + SocketData_t *sd = dList_nth_data(hc->queue, 0); + dList_remove(hc->queue, sd); return sd; } @@ -720,7 +844,7 @@ static HostConnection_t *Http_host_connection_get(const char *host) } hc = dNew0(HostConnection_t, 1); - Http_socket_queue_init(&hc->queue); + hc->queue = dList_new(10); hc->host = dStrdup(host); dList_append(host_connections, hc); @@ -729,7 +853,8 @@ static HostConnection_t *Http_host_connection_get(const char *host) static void Http_host_connection_remove(HostConnection_t *hc) { - assert(hc->queue.head == NULL); + assert(dList_length(hc->queue) == 0); + dList_free(hc->queue); dList_remove_fast(host_connections, hc); dFree(hc->host); dFree(hc); @@ -738,15 +863,29 @@ static void Http_host_connection_remove(HostConnection_t *hc) static void Http_host_connection_remove_all() { HostConnection_t *hc; + SocketData_t *sd; while (dList_length(host_connections) > 0) { hc = (HostConnection_t*) dList_nth_data(host_connections, 0); - while (Http_socket_dequeue(&hc->queue)); + while ((sd = Http_socket_dequeue(hc))) + dFree(sd); Http_host_connection_remove(hc); } dList_free(host_connections); } +static void Http_fd_map_remove_all() +{ + FdMapEntry_t *fme; + int i, n = dList_length(fd_map); + + for (i = 0; i < n; i++) { + fme = (FdMapEntry_t *) dList_nth_data(fd_map, i); + dFree(fme); + } + dList_free(fd_map); +} + /* * Deallocate memory used by http module * (Call this one at exit time) @@ -754,6 +893,7 @@ static void Http_host_connection_remove_all() void a_Http_freeall(void) { Http_host_connection_remove_all(); + Http_fd_map_remove_all(); a_Klist_free(&ValidSocks); a_Url_free(HTTP_Proxy); dFree(HTTP_Proxy_Auth_base64); diff --git a/src/Makefile.am b/src/Makefile.am index 65a42cad..597a743b 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -2,7 +2,9 @@ AM_CPPFLAGS= \ -I$(top_srcdir) \ -DDILLO_SYSCONF='"$(sysconfdir)/"' \ -DDILLO_DOCDIR='"$(docdir)/"' \ + -DCUR_WORKING_DIR='"@BASE_CUR_WORKING_DIR@/src"' \ @LIBJPEG_CPPFLAGS@ + AM_CFLAGS = @LIBPNG_CFLAGS@ AM_CXXFLAGS = @LIBPNG_CFLAGS@ @LIBFLTK_CXXFLAGS@ @@ -96,6 +98,7 @@ dillo_SOURCES = \ plain.cc \ html.cc \ html.hh \ + html_charrefs.h \ html_common.hh \ form.cc \ form.hh \ diff --git a/src/cache.c b/src/cache.c index 14e862b5..189e18d5 100644 --- a/src/cache.c +++ b/src/cache.c @@ -55,7 +55,7 @@ typedef struct { Dstr *Data; /* Pointer to raw data */ Dstr *UTF8Data; /* Data after charset translation */ int DataRefcount; /* Reference count */ - Decode *TransferDecoder; /* Transfer decoder (e.g., chunked) */ + DecodeTransfer *TransferDecoder; /* Transfer decoder (e.g., chunked) */ Decode *ContentDecoder; /* Data decoder (e.g., gzip) */ Decode *CharsetDecoder; /* Translates text to UTF-8 encoding */ int ExpectedSize; /* Goal size of the HTTP transfer (0 if unknown)*/ @@ -110,7 +110,7 @@ static int Cache_entry_by_url_cmp(const void *v1, const void *v2) } /* - * Initialize dicache data + * Initialize cache data */ void a_Cache_init(void) { @@ -205,7 +205,7 @@ static void Cache_entry_init(CacheEntry_t *NewEntry, const DilloUrl *Url) NewEntry->CharsetDecoder = NULL; NewEntry->ExpectedSize = 0; NewEntry->TransferSize = 0; - NewEntry->Flags = CA_IsEmpty; + NewEntry->Flags = CA_IsEmpty | CA_KeepAlive; } /* @@ -308,7 +308,7 @@ static void Cache_entry_free(CacheEntry_t *entry) if (entry->CharsetDecoder) a_Decode_free(entry->CharsetDecoder); if (entry->TransferDecoder) - a_Decode_free(entry->TransferDecoder); + a_Decode_transfer_free(entry->TransferDecoder); if (entry->ContentDecoder) a_Decode_free(entry->ContentDecoder); dFree(entry); @@ -498,7 +498,7 @@ const char *a_Cache_set_content_type(const DilloUrl *url, const char *ctype, _MSG("a_Cache_set_content_type {%s} {%s}\n", ctype, URL_STR(url)); curr = Cache_current_content_type(entry); - if (entry->TypeMeta || (*from == 'h' && entry->TypeHdr) ) { + if (entry->TypeMeta || (*from == 'h' && entry->TypeHdr) ) { /* Type is already been set. Do nothing. * BTW, META overrides TypeHdr */ } else { @@ -652,7 +652,8 @@ static Dlist *Cache_parse_multiple_fields(const char *header, static void Cache_parse_header(CacheEntry_t *entry) { char *header = entry->Header->str; - char *Length, *Type, *location_str, *encoding; + bool_t server1point0 = !strncmp(entry->Header->str, "HTTP/1.0", 8); + char *Length, *Type, *location_str, *encoding, *connection; #ifndef DISABLE_COOKIES Dlist *Cookies; #endif @@ -716,6 +717,17 @@ static void Cache_parse_header(CacheEntry_t *entry) dList_free(warnings); } + if (server1point0) + entry->Flags &= ~CA_KeepAlive; + + if ((connection = Cache_parse_field(header, "Connection"))) { + if (!dStrAsciiCasecmp(connection, "close")) + entry->Flags &= ~CA_KeepAlive; + else if (server1point0 && !dStrAsciiCasecmp(connection, "keep-alive")) + entry->Flags |= CA_KeepAlive; + dFree(connection); + } + /* * Get Transfer-Encoding and initialize decoder */ @@ -834,6 +846,54 @@ static int Cache_get_header(CacheEntry_t *entry, return 0; } +static void Cache_finish_msg(CacheEntry_t *entry) +{ + if (entry->Flags & CA_GotData) { + /* already finished */ + return; + } + + if ((entry->ExpectedSize || entry->TransferSize) && + entry->TypeHdr == NULL) { + MSG_HTTP("Message with a body lacked Content-Type header.\n"); + } + if ((entry->Flags & CA_GotLength) && + (entry->ExpectedSize != entry->TransferSize)) { + MSG_HTTP("Content-Length does NOT match message body at\n" + "%s\n", URL_STR_(entry->Url)); + MSG("Expected size: %d, Transfer size: %d\n", + entry->ExpectedSize, entry->TransferSize); + } + if (!entry->TransferSize && !(entry->Flags & CA_Redirect) && + (entry->Flags & WEB_RootUrl)) { + char *eol = strchr(entry->Header->str, '\n'); + if (eol) { + char *status_line = dStrndup(entry->Header->str, + eol - entry->Header->str); + MSG_HTTP("Body of %s was empty. Server sent status: %s\n", + URL_STR_(entry->Url), status_line); + dFree(status_line); + } + } + entry->Flags |= CA_GotData; + entry->Flags &= ~CA_Stopped; /* it may catch up! */ + if (entry->TransferDecoder) { + a_Decode_transfer_free(entry->TransferDecoder); + entry->TransferDecoder = NULL; + } + if (entry->ContentDecoder) { + a_Decode_free(entry->ContentDecoder); + entry->ContentDecoder = NULL; + } + dStr_fit(entry->Data); /* fit buffer size! */ + + if ((entry = Cache_process_queue(entry))) { + if (entry->Flags & CA_GotHeader) { + Cache_unref_data(entry); + } + } +} + /* * Receive new data, update the reception buffer (for next read), update the * cache, and service the client queue. @@ -842,16 +902,17 @@ static int Cache_get_header(CacheEntry_t *entry, * 'Op' is the operation to perform * 'VPtr' is a (void) pointer to the IO control structure */ -void a_Cache_process_dbuf(int Op, const char *buf, size_t buf_size, - const DilloUrl *Url) +bool_t a_Cache_process_dbuf(int Op, const char *buf, size_t buf_size, + const DilloUrl *Url) { int offset, len; const char *str; Dstr *dstr1, *dstr2, *dstr3; + bool_t done = FALSE; CacheEntry_t *entry = Cache_entry_search(Url); /* Assert a valid entry (not aborted) */ - dReturn_if_fail (entry != NULL); + dReturn_val_if_fail (entry != NULL, FALSE); _MSG("__a_Cache_process_dbuf__\n"); @@ -875,7 +936,8 @@ void a_Cache_process_dbuf(int Op, const char *buf, size_t buf_size, /* Decode arrived data (<= 3 stages) */ if (entry->TransferDecoder) { - dstr1 = a_Decode_process(entry->TransferDecoder, str, len); + dstr1 = a_Decode_transfer_process(entry->TransferDecoder, str,len); + done = a_Decode_transfer_finished(entry->TransferDecoder); str = dstr1->str; len = dstr1->len; } @@ -896,51 +958,37 @@ void a_Cache_process_dbuf(int Op, const char *buf, size_t buf_size, if (entry->Data->len) entry->Flags &= ~CA_IsEmpty; + if ((entry->Flags & CA_GotLength) && + (entry->TransferSize >= entry->ExpectedSize)) { + done = TRUE; + } + if (!(entry->Flags & CA_KeepAlive)) { + /* Let IOClose finish it later */ + done = FALSE; + } + entry = Cache_process_queue(entry); + + if (entry && done) + Cache_finish_msg(entry); } } else if (Op == IOClose) { - if ((entry->ExpectedSize || entry->TransferSize) && - entry->TypeHdr == NULL) { - MSG_HTTP("Message with a body lacked Content-Type header.\n"); - } - if ((entry->Flags & CA_GotLength) && - (entry->ExpectedSize != entry->TransferSize)) { - MSG_HTTP("Content-Length does NOT match message body at\n" - "%s\n", URL_STR_(entry->Url)); - MSG("Expected size: %d, Transfer size: %d\n", - entry->ExpectedSize, entry->TransferSize); - } - if (!entry->TransferSize && !(entry->Flags & CA_Redirect) && - (entry->Flags & WEB_RootUrl)) { - char *eol = strchr(entry->Header->str, '\n'); - if (eol) { - char *status_line = dStrndup(entry->Header->str, - eol - entry->Header->str); - MSG_HTTP("Body was empty. Server sent status: %s\n", status_line); - dFree(status_line); - } - } - entry->Flags |= CA_GotData; - entry->Flags &= ~CA_Stopped; /* it may catch up! */ - if (entry->TransferDecoder) { - a_Decode_free(entry->TransferDecoder); - entry->TransferDecoder = NULL; - } - if (entry->ContentDecoder) { - a_Decode_free(entry->ContentDecoder); - entry->ContentDecoder = NULL; - } - dStr_fit(entry->Data); /* fit buffer size! */ + Cache_finish_msg(entry); + } else if (Op == IOAbort) { + int i; + CacheClient_t *Client; - if ((entry = Cache_process_queue(entry))) { - if (entry->Flags & CA_GotHeader) { - Cache_unref_data(entry); + for (i = 0; (Client = dList_nth_data(ClientQueue, i)); ++i) { + if (Client->Url == entry->Url) { + DilloWeb *web = (DilloWeb *)Client->Web; + + a_Bw_remove_client(web->bw, Client->Key); + Cache_client_dequeue(Client); + --i; /* Keep the index value in the next iteration */ } } - } else if (Op == IOAbort) { - /* unused */ - MSG("a_Cache_process_dbuf Op = IOAbort; not implemented!\n"); } + return done; } /* @@ -1264,7 +1312,6 @@ static CacheEntry_t *Cache_process_queue(CacheEntry_t *entry) /* Trigger cleanup when there are no cache clients */ if (dList_length(ClientQueue) == 0) { - _MSG(" a_Dicache_cleanup()\n"); a_Dicache_cleanup(); } diff --git a/src/cache.h b/src/cache.h index c39e4600..f3b064f2 100644 --- a/src/cache.h +++ b/src/cache.h @@ -33,6 +33,7 @@ extern "C" { #define CA_InternalUrl 0x800 /* URL content is generated by dillo */ #define CA_HugeFile 0x1000 /* URL content is too big */ #define CA_IsEmpty 0x2000 /* True until a byte of content arrives */ +#define CA_KeepAlive 0x4000 typedef struct CacheClient CacheClient_t; @@ -67,7 +68,7 @@ const char *a_Cache_set_content_type(const DilloUrl *url, const char *ctype, const char *from); uint_t a_Cache_get_flags(const DilloUrl *url); uint_t a_Cache_get_flags_with_redirection(const DilloUrl *url); -void a_Cache_process_dbuf(int Op, const char *buf, size_t buf_size, +bool_t a_Cache_process_dbuf(int Op, const char *buf, size_t buf_size, const DilloUrl *Url); int a_Cache_download_enabled(const DilloUrl *url); void a_Cache_entry_remove_by_url(DilloUrl *url); @@ -345,7 +345,7 @@ static char *Capi_dpi_build_cmd(DilloWeb *web, char *server) /* * Send the requested URL's source to the "view source" dpi */ -static void Capi_dpi_send_source(BrowserWindow *bw, DilloUrl *url) +static void Capi_dpi_send_source(BrowserWindow *bw, DilloUrl *url) { char *p, *buf, *cmd, size_str[32], *server="vsource"; int buf_size; @@ -385,81 +385,80 @@ int a_Capi_open_url(DilloWeb *web, CA_Callback_t Call, void *CbData) int safe = 0, ret = 0, use_cache = 0; /* web->requester is NULL if the action is initiated by user */ - if (!(a_Capi_get_flags(web->url) & CAPI_IsCached || - web->requester == NULL || - a_Domain_permit(web->requester, web->url))) { - return 0; - } - - /* reload test */ - reload = (!(a_Capi_get_flags(web->url) & CAPI_IsCached) || - (URL_FLAGS(web->url) & URL_E2EQuery)); - - if (web->flags & WEB_Download) { - /* download request: if cached save from cache, else - * for http, ftp or https, use the downloads dpi */ - if (a_Capi_get_flags_with_redirection(web->url) & CAPI_IsCached) { - if (web->filename) { - if ((web->stream = fopen(web->filename, "w"))) { - use_cache = 1; - } else { - MSG_WARN("Cannot open \"%s\" for writing.\n", web->filename); + if (a_Capi_get_flags(web->url) & CAPI_IsCached || + web->requester == NULL || + a_Domain_permit(web->requester, web->url)) { + + /* reload test */ + reload = (!(a_Capi_get_flags(web->url) & CAPI_IsCached) || + (URL_FLAGS(web->url) & URL_E2EQuery)); + + if (web->flags & WEB_Download) { + /* download request: if cached save from cache, else + * for http, ftp or https, use the downloads dpi */ + if (a_Capi_get_flags_with_redirection(web->url) & CAPI_IsCached) { + if (web->filename) { + if ((web->stream = fopen(web->filename, "w"))) { + use_cache = 1; + } else { + MSG_WARN("Cannot open \"%s\" for writing.\n", web->filename); + } } + } else if (a_Cache_download_enabled(web->url)) { + server = "downloads"; + cmd = Capi_dpi_build_cmd(web, server); + a_Capi_dpi_send_cmd(web->url, web->bw, cmd, server, 1); + dFree(cmd); + } else { + MSG_WARN("Ignoring download request for '%s': " + "not in cache and not downloadable.\n", + URL_STR(web->url)); } - } else if (a_Cache_download_enabled(web->url)) { - server = "downloads"; - cmd = Capi_dpi_build_cmd(web, server); - a_Capi_dpi_send_cmd(web->url, web->bw, cmd, server, 1); - dFree(cmd); - } else { - MSG_WARN("Ignoring download request for '%s': " - "not in cache and not downloadable.\n", - URL_STR(web->url)); - } - - } else if (Capi_url_uses_dpi(web->url, &server)) { - /* dpi request */ - if ((safe = a_Capi_dpi_verify_request(web->bw, web->url))) { - if (dStrAsciiCasecmp(scheme, "dpi") == 0) { - if (strcmp(server, "vsource") == 0) { - /* allow "view source" reload upon user request */ - } else { - /* make the other "dpi:/" prefixed urls always reload. */ - a_Url_set_flags(web->url, URL_FLAGS(web->url) | URL_E2EQuery); - reload = 1; + + } else if (Capi_url_uses_dpi(web->url, &server)) { + /* dpi request */ + if ((safe = a_Capi_dpi_verify_request(web->bw, web->url))) { + if (dStrAsciiCasecmp(scheme, "dpi") == 0) { + if (strcmp(server, "vsource") == 0) { + /* allow "view source" reload upon user request */ + } else { + /* make the other "dpi:/" prefixed urls always reload. */ + a_Url_set_flags(web->url, URL_FLAGS(web->url) |URL_E2EQuery); + reload = 1; + } + } + if (reload) { + a_Capi_conn_abort_by_url(web->url); + /* Send dpip command */ + _MSG("a_Capi_open_url, reload url='%s'\n", URL_STR(web->url)); + cmd = Capi_dpi_build_cmd(web, server); + a_Capi_dpi_send_cmd(web->url, web->bw, cmd, server, 1); + dFree(cmd); + if (strcmp(server, "vsource") == 0) { + Capi_dpi_send_source(web->bw, web->url); + } } + use_cache = 1; } + dFree(server); + + } else if (!dStrAsciiCasecmp(scheme, "http")) { + /* http request */ if (reload) { a_Capi_conn_abort_by_url(web->url); - /* Send dpip command */ - _MSG("a_Capi_open_url, reload url='%s'\n", URL_STR(web->url)); - cmd = Capi_dpi_build_cmd(web, server); - a_Capi_dpi_send_cmd(web->url, web->bw, cmd, server, 1); - dFree(cmd); - if (strcmp(server, "vsource") == 0) { - Capi_dpi_send_source(web->bw, web->url); - } + /* create a new connection and start the CCC operations */ + conn = Capi_conn_new(web->url, web->bw, "http", "none"); + /* start the reception branch before the query one because the DNS + * may callback immediately. This may avoid a race condition. */ + a_Capi_ccc(OpStart, 2, BCK, a_Chain_new(), conn, "http"); + a_Capi_ccc(OpStart, 1, BCK, a_Chain_new(), conn, web); } use_cache = 1; - } - dFree(server); - - } else if (!dStrAsciiCasecmp(scheme, "http")) { - /* http request */ - if (reload) { - a_Capi_conn_abort_by_url(web->url); - /* create a new connection and start the CCC operations */ - conn = Capi_conn_new(web->url, web->bw, "http", "none"); - /* start the reception branch before the query one because the DNS - * may callback immediately. This may avoid a race condition. */ - a_Capi_ccc(OpStart, 2, BCK, a_Chain_new(), conn, "http"); - a_Capi_ccc(OpStart, 1, BCK, a_Chain_new(), conn, web); - } - use_cache = 1; - } else if (!dStrAsciiCasecmp(scheme, "about")) { - /* internal request */ - use_cache = 1; + } else if (!dStrAsciiCasecmp(scheme, "about")) { + /* internal request */ + use_cache = 1; + } } if (use_cache) { @@ -681,6 +680,7 @@ void a_Capi_ccc(int Op, int Branch, int Dir, ChainLink *Info, case OpAbort: conn = Info->LocalKey; conn->InfoSend = NULL; + a_Cache_process_dbuf(IOAbort, NULL, 0, conn->url); if (Data2) { if (!strcmp(Data2, "DpidERROR")) { a_UIcmd_set_msg(conn->bw, @@ -714,7 +714,10 @@ void a_Capi_ccc(int Op, int Branch, int Dir, ChainLink *Info, Capi_conn_ref(conn); Info->LocalKey = conn; conn->InfoRecv = Info; - a_Chain_link_new(Info, a_Capi_ccc, BCK, a_Dpi_ccc, 2, 2); + if (strcmp(conn->server, "http") == 0) + a_Chain_link_new(Info, a_Capi_ccc, BCK, a_Http_ccc, 2, 2); + else + a_Chain_link_new(Info, a_Capi_ccc, BCK, a_Dpi_ccc, 2, 2); a_Chain_bcb(OpStart, Info, NULL, Data2); break; case OpSend: @@ -744,7 +747,15 @@ void a_Capi_ccc(int Op, int Branch, int Dir, ChainLink *Info, if (strcmp(Data2, "send_page_2eof") == 0) { /* Data1 = dbuf */ DataBuf *dbuf = Data1; - a_Cache_process_dbuf(IORead, dbuf->Buf, dbuf->Size, conn->url); + bool_t finished = a_Cache_process_dbuf(IORead, dbuf->Buf, + dbuf->Size, conn->url); + if (finished && Capi_conn_valid(conn) && conn->InfoRecv) { + /* If we have a persistent connection where cache tells us + * that we've received the full response, and cache didn't + * trigger an abort and tear everything down, tell upstream. + */ + a_Chain_bcb(OpSend, conn->InfoRecv, NULL, "reply_complete"); + } } else if (strcmp(Data2, "send_status_message") == 0) { a_UIcmd_set_msg(conn->bw, "%s", Data1); } else if (strcmp(Data2, "chat") == 0) { diff --git a/src/colors.c b/src/colors.c index fe3598eb..237e63a1 100644 --- a/src/colors.c +++ b/src/colors.c @@ -303,7 +303,7 @@ int32_t a_Color_parse (const char *str, int32_t default_color, int *err) static int Color_distance(long c1, long c2) { return (labs((c1 & 0x0000ff) - (c2 & 0x0000ff)) + - labs(((c1 & 0x00ff00) - (c2 & 0x00ff00)) >> 8) + + labs(((c1 & 0x00ff00) - (c2 & 0x00ff00)) >> 8) + labs(((c1 & 0xff0000) - (c2 & 0xff0000)) >> 16)) / 75; } #endif diff --git a/src/cookies.h b/src/cookies.h index 1cdb82ac..5e4d8c59 100644 --- a/src/cookies.h +++ b/src/cookies.h @@ -5,18 +5,17 @@ extern "C" { #endif /* __cplusplus */ +void a_Cookies_init( void ); #ifdef DISABLE_COOKIES # define a_Cookies_get_query(url, requester) dStrdup("") # define a_Cookies_set() ; -# define a_Cookies_init() ; # define a_Cookies_freeall() ; #else char *a_Cookies_get_query(const DilloUrl *query_url, const DilloUrl *requester); void a_Cookies_set(Dlist *cookie_string, const DilloUrl *set_url, const char *server_date); - void a_Cookies_init( void ); void a_Cookies_freeall( void ); #endif @@ -544,7 +544,7 @@ void CssContext::addRule (CssSelector *sel, CssPropertyList *props, if (order == CSS_PRIMARY_USER_AGENT) { userAgentSheet.addRule (rule); - } else { + } else { sheet[order].addRule (rule); } } @@ -133,7 +133,7 @@ inline float CSS_LENGTH_VALUE (CssLength l) { case CSS_LENGTH_TYPE_EX: case CSS_LENGTH_TYPE_PERCENTAGE: case CSS_LENGTH_TYPE_RELATIVE: - return ((float)(l & ~7)) / (1 << 15); + return ((float)(l & ~7)) / (1 << 15); case CSS_LENGTH_TYPE_AUTO: return 0.0; default: diff --git a/src/cssparser.cc b/src/cssparser.cc index 369dd67f..1487a605 100644 --- a/src/cssparser.cc +++ b/src/cssparser.cc @@ -72,6 +72,10 @@ static const char *const Css_border_width_enum_vals[] = { "thin", "medium", "thick", NULL }; +static const char *const Css_clear_enum_vals[] = { + "left", "right", "both", "none", NULL +}; + static const char *const Css_cursor_enum_vals[] = { "crosshair", "default", "pointer", "move", "e-resize", "ne-resize", "nw-resize", "n-resize", "se-resize", "sw-resize", "s-resize", @@ -84,6 +88,10 @@ static const char *const Css_display_enum_vals[] = { "table-cell", NULL }; +static const char *const Css_float_enum_vals[] = { + "none", "left", "right", NULL +}; + static const char *const Css_font_size_enum_vals[] = { "large", "larger", "medium", "small", "smaller", "xx-large", "xx-small", "x-large", "x-small", NULL @@ -121,6 +129,14 @@ static const char *const Css_list_style_type_enum_vals[] = { "katakana-iroha", "none", NULL }; +static const char *const Css_overflow_enum_vals[] = { + "visible", "hidden", "scroll", "auto", NULL +}; + +static const char *const Css_position_enum_vals[] = { + "static", "relative", "absolute", "fixed", NULL +}; + static const char *const Css_text_align_enum_vals[] = { "left", "right", "center", "justify", "string", NULL }; @@ -182,9 +198,9 @@ const CssPropertyInfo Css_property_info[CSS_PROPERTY_LAST] = { Css_border_style_enum_vals}, {"border-top-width", {CSS_TYPE_ENUM, CSS_TYPE_LENGTH, CSS_TYPE_UNUSED}, Css_border_width_enum_vals}, - {"bottom", {CSS_TYPE_UNUSED}, NULL}, + {"bottom", {CSS_TYPE_LENGTH_PERCENTAGE, CSS_TYPE_UNUSED}, NULL}, {"caption-side", {CSS_TYPE_UNUSED}, NULL}, - {"clear", {CSS_TYPE_UNUSED}, NULL}, + {"clear", {CSS_TYPE_ENUM, CSS_TYPE_UNUSED}, Css_clear_enum_vals}, {"clip", {CSS_TYPE_UNUSED}, NULL}, {"color", {CSS_TYPE_COLOR, CSS_TYPE_UNUSED}, NULL}, {"content", {CSS_TYPE_STRING, CSS_TYPE_UNUSED}, NULL}, @@ -194,7 +210,7 @@ const CssPropertyInfo Css_property_info[CSS_PROPERTY_LAST] = { {"direction", {CSS_TYPE_UNUSED}, NULL}, {"display", {CSS_TYPE_ENUM, CSS_TYPE_UNUSED}, Css_display_enum_vals}, {"empty-cells", {CSS_TYPE_UNUSED}, NULL}, - {"float", {CSS_TYPE_UNUSED}, NULL}, + {"float", {CSS_TYPE_ENUM, CSS_TYPE_UNUSED}, Css_float_enum_vals}, {"font-family", {CSS_TYPE_SYMBOL, CSS_TYPE_UNUSED}, NULL}, {"font-size", {CSS_TYPE_ENUM, CSS_TYPE_LENGTH_PERCENTAGE, CSS_TYPE_UNUSED}, Css_font_size_enum_vals}, @@ -227,21 +243,25 @@ const CssPropertyInfo Css_property_info[CSS_PROPERTY_LAST] = { {CSS_TYPE_SIGNED_LENGTH, CSS_TYPE_AUTO, CSS_TYPE_UNUSED}, NULL}, {"marker-offset", {CSS_TYPE_UNUSED}, NULL}, {"marks", {CSS_TYPE_UNUSED}, NULL}, - {"max-height", {CSS_TYPE_UNUSED}, NULL}, - {"max-width", {CSS_TYPE_UNUSED}, NULL}, - {"min-height", {CSS_TYPE_UNUSED}, NULL}, - {"min-width", {CSS_TYPE_UNUSED}, NULL}, + {"max-height", {CSS_TYPE_LENGTH_PERCENTAGE, CSS_TYPE_AUTO, CSS_TYPE_UNUSED}, + NULL}, + {"max-width", {CSS_TYPE_LENGTH_PERCENTAGE, CSS_TYPE_AUTO, CSS_TYPE_UNUSED}, + NULL}, + {"min-height", {CSS_TYPE_LENGTH_PERCENTAGE, CSS_TYPE_AUTO, CSS_TYPE_UNUSED}, + NULL}, + {"min-width", {CSS_TYPE_LENGTH_PERCENTAGE, CSS_TYPE_AUTO, CSS_TYPE_UNUSED}, + NULL}, {"outline-color", {CSS_TYPE_UNUSED}, NULL}, {"outline-style", {CSS_TYPE_UNUSED}, NULL}, {"outline-width", {CSS_TYPE_UNUSED}, NULL}, - {"overflow", {CSS_TYPE_UNUSED}, NULL}, + {"overflow", {CSS_TYPE_ENUM, CSS_TYPE_UNUSED}, Css_overflow_enum_vals}, {"padding-bottom", {CSS_TYPE_LENGTH, CSS_TYPE_UNUSED}, NULL}, {"padding-left", {CSS_TYPE_LENGTH, CSS_TYPE_UNUSED}, NULL}, {"padding-right", {CSS_TYPE_LENGTH, CSS_TYPE_UNUSED}, NULL}, {"padding-top", {CSS_TYPE_LENGTH, CSS_TYPE_UNUSED}, NULL}, - {"position", {CSS_TYPE_UNUSED}, NULL}, + {"position", {CSS_TYPE_ENUM, CSS_TYPE_UNUSED}, Css_position_enum_vals}, {"quotes", {CSS_TYPE_UNUSED}, NULL}, - {"right", {CSS_TYPE_UNUSED}, NULL}, + {"right", {CSS_TYPE_LENGTH_PERCENTAGE, CSS_TYPE_UNUSED}, NULL}, {"text-align", {CSS_TYPE_ENUM, CSS_TYPE_UNUSED}, Css_text_align_enum_vals}, {"text-decoration", {CSS_TYPE_MULTI_ENUM, CSS_TYPE_UNUSED}, Css_text_decoration_enum_vals}, @@ -249,7 +269,7 @@ const CssPropertyInfo Css_property_info[CSS_PROPERTY_LAST] = { {"text-shadow", {CSS_TYPE_UNUSED}, NULL}, {"text-transform", {CSS_TYPE_ENUM, CSS_TYPE_UNUSED}, Css_text_transform_enum_vals}, - {"top", {CSS_TYPE_UNUSED}, NULL}, + {"top", {CSS_TYPE_LENGTH_PERCENTAGE, CSS_TYPE_UNUSED}, NULL}, {"unicode-bidi", {CSS_TYPE_UNUSED}, NULL}, {"vertical-align",{CSS_TYPE_ENUM, CSS_TYPE_UNUSED},Css_vertical_align_vals}, {"visibility", {CSS_TYPE_UNUSED}, NULL}, @@ -277,7 +297,7 @@ typedef struct { } type; const CssPropertyName *properties; /* CSS_SHORTHAND_MULTIPLE: * must be terminated by - * CSS_PROPERTY_END + * CSS_PROPERTY_END * CSS_SHORTHAND_DIRECTIONS: * must have length 4 * CSS_SHORTHAND_BORDERS: @@ -720,7 +740,9 @@ bool CssParser::tokenMatchesProperty(CssPropertyName prop, CssValueType *type) dStrAsciiCasecmp(tval, "top") == 0 || dStrAsciiCasecmp(tval, "bottom") == 0)) return true; - // Fall Through (lenght and percentage) + if (ttype == CSS_TK_DECINT || ttype == CSS_TK_FLOAT) + return true; + break; case CSS_TYPE_LENGTH_PERCENTAGE: case CSS_TYPE_LENGTH_PERCENTAGE_NUMBER: case CSS_TYPE_LENGTH: @@ -766,7 +788,8 @@ bool CssParser::tokenMatchesProperty(CssPropertyName prop, CssValueType *type) case CSS_TYPE_URI: if (ttype == CSS_TK_SYMBOL && - dStrAsciiCasecmp(tval, "url") == 0) + (dStrAsciiCasecmp(tval, "url") == 0 || + dStrAsciiCasecmp(tval, "none") == 0)) return true; break; @@ -1044,12 +1067,16 @@ bool CssParser::parseValue(CssPropertyName prop, break; case CSS_TYPE_URI: - if (ttype == CSS_TK_SYMBOL && - dStrAsciiCasecmp(tval, "url") == 0) { - val->strVal = parseUrl(); - nextToken(); - if (val->strVal) + if (ttype == CSS_TK_SYMBOL) { + if (dStrAsciiCasecmp(tval, "url") == 0) { + val->strVal = parseUrl(); + if (val->strVal) + ret = true; + } else if (dStrAsciiCasecmp(tval, "none") == 0) { + val->strVal = NULL; ret = true; + } + nextToken(); } break; @@ -1106,6 +1133,9 @@ bool CssParser::parseValue(CssPropertyName prop, if (parseValue(prop, CSS_TYPE_LENGTH_PERCENTAGE, &valTmp)) { pos[i] = valTmp.intVal; ret = true; + } else if (parseValue(prop, CSS_TYPE_SIGNED_LENGTH, &valTmp)) { + pos[i] = valTmp.intVal; + ret = true; } else // ... but something may still fail. h[i] = v[i] = false; diff --git a/src/decode.c b/src/decode.c index 53a0d621..6d838d41 100644 --- a/src/decode.c +++ b/src/decode.c @@ -21,9 +21,10 @@ static const int bufsize = 8*1024; /* - * Decode chunked data + * Decode 'Transfer-Encoding: chunked' data */ -static Dstr *Decode_chunked(Decode *dc, const char *instr, int inlen) +Dstr *a_Decode_transfer_process(DecodeTransfer *dc, const char *instr, + int inlen) { char *inputPtr, *eol; int inputRemaining; @@ -66,6 +67,7 @@ static Dstr *Decode_chunked(Decode *dc, const char *instr, int inlen) } if (!(chunkRemaining = strtol(inputPtr, NULL, 0x10))) { + dc->finished = TRUE; break; /* A chunk length of 0 means we're done! */ } inputRemaining -= (eol - inputPtr) + 1; @@ -80,10 +82,16 @@ static Dstr *Decode_chunked(Decode *dc, const char *instr, int inlen) return output; } -static void Decode_chunked_free(Decode *dc) +bool_t a_Decode_transfer_finished(DecodeTransfer *dc) +{ + return dc->finished; +} + +void a_Decode_transfer_free(DecodeTransfer *dc) { dFree(dc->state); dStr_free(dc->leftover, 1); + dFree(dc); } static void Decode_compression_free(Decode *dc) @@ -208,7 +216,7 @@ static Dstr *Decode_deflate(Decode *dc, const char *instr, int inlen) dStr_free(output, 1); (void)inflateEnd(zs); dFree(dc->state); - dc->state = zs = dNew(z_stream, 1);; + dc->state = zs = dNew(z_stream, 1); zs->zalloc = NULL; zs->zfree = NULL; zs->next_in = NULL; @@ -280,19 +288,17 @@ static void Decode_charset_free(Decode *dc) /* * Initialize transfer decoder. Currently handles "chunked". */ -Decode *a_Decode_transfer_init(const char *format) +DecodeTransfer *a_Decode_transfer_init(const char *format) { - Decode *dc = NULL; + DecodeTransfer *dc = NULL; if (format && !dStrAsciiCasecmp(format, "chunked")) { int *chunk_remaining = dNew(int, 1); *chunk_remaining = 0; - dc = dNew(Decode, 1); + dc = dNew(DecodeTransfer, 1); dc->leftover = dStr_new(""); dc->state = chunk_remaining; - dc->decode = Decode_chunked; - dc->free = Decode_chunked_free; - dc->buffer = NULL; /* not used */ + dc->finished = FALSE; _MSG("chunked!\n"); } return dc; diff --git a/src/decode.h b/src/decode.h index 279807a6..06c987f6 100644 --- a/src/decode.h +++ b/src/decode.h @@ -15,7 +15,21 @@ typedef struct Decode { void (*free) (struct Decode *dc); } Decode; -Decode *a_Decode_transfer_init(const char *format); +/* I'm not going to shoehorn the decoders into the same form anymore. They + * can evolve independently. + */ +typedef struct DecodeTransfer { + Dstr *leftover; + void *state; + bool_t finished; /* has the terminating chunk been seen? */ +} DecodeTransfer; + +DecodeTransfer *a_Decode_transfer_init(const char *format); +Dstr *a_Decode_transfer_process(DecodeTransfer *dc, const char *instr, + int inlen); +bool_t a_Decode_transfer_finished(DecodeTransfer *dc); +void a_Decode_transfer_free(DecodeTransfer *dc); + Decode *a_Decode_content_init(const char *format); Decode *a_Decode_charset_init(const char *format); Dstr *a_Decode_process(Decode *dc, const char *instr, int inlen); diff --git a/src/dicache.c b/src/dicache.c index db3b86b2..a2904c32 100644 --- a/src/dicache.c +++ b/src/dicache.c @@ -28,15 +28,10 @@ enum { DIC_Jpeg }; -typedef struct { - int valid; /* flag */ - DilloUrl *url; /* primary "Key" for this dicache entry */ - DICacheEntry *first; /* pointer to the first dicache entry in this list */ -} DICacheNode; /* - * List of DICacheNode. One node per URL. Each node may have several - * versions of the same image in a linked list. + * List of DICacheEntry. May hold several versions of the same image, + * although most of the time it holds just one. */ static Dlist *CachedIMGs = NULL; @@ -45,24 +40,20 @@ static uint_t dicache_size_total; /* invariant: dicache_size_total is * of all the images in the dicache. */ /* - * Compare two dicache nodes + * Compare function for image entries */ -static int Dicache_node_cmp(const void *v1, const void *v2) +static int Dicache_entry_cmp(const void *v1, const void *v2) { - const DICacheNode *n1 = v1, *n2 = v2; - - return a_Url_cmp(n1->url, n2->url); -} - -/* - * Compare function for searching a node by Url - */ -static int Dicache_node_by_url_cmp(const void *v1, const void *v2) -{ - const DICacheNode *node = v1; - const DilloUrl *url = v2; - - return a_Url_cmp(node->url, url); + const DICacheEntry *e1 = v1, *e2 = v2; + + int st = a_Url_cmp(e1->url, e2->url); + if (st == 0) { + if (e2->version == DIC_Last) + st = (e1->Flags & DIF_Last ? 0 : -1); + else + st = (e1->version - e2->version); + } + return st; } /* @@ -83,6 +74,8 @@ static DICacheEntry *Dicache_entry_new(void) entry->width = 0; entry->height = 0; + entry->Flags = DIF_Valid; + entry->SurvCleanup = 0; entry->type = DILLO_IMG_TYPE_NOTSET; entry->cmap = NULL; entry->v_imgbuf = NULL; @@ -97,41 +90,29 @@ static DICacheEntry *Dicache_entry_new(void) entry->DecoderData = NULL; entry->DecodedSize = 0; - entry->next = NULL; - return entry; } /* * Add a new entry in the dicache - * (a single node (URL) may have several entries) + * (a single URL may have several entries) */ static DICacheEntry *Dicache_add_entry(const DilloUrl *Url) { - DICacheEntry *entry; - DICacheNode *node; + DICacheEntry e, *entry, *last; entry = Dicache_entry_new(); - - if ((node = dList_find_sorted(CachedIMGs, Url, Dicache_node_by_url_cmp))) { - /* this URL is already in CachedIMGs, add entry at the END of the list */ - DICacheEntry *ptr = node->first; - - node->valid = 1; - for ( ; ptr->next; ptr = ptr->next); - ptr->next = entry; - entry->version = ptr->version+1; - entry->url = node->url; - - } else { /* no node yet, so create one */ - DICacheNode *node = dNew(DICacheNode, 1); - - node->url = a_Url_dup(Url); - entry->url = node->url; - node->first = entry; - node->valid = 1; - dList_insert_sorted(CachedIMGs, node, Dicache_node_cmp); + e.url = (DilloUrl*)Url; + e.version = DIC_Last; + last = dList_find_sorted(CachedIMGs, &e, Dicache_entry_cmp); + if (last) { + /* URL is already in CachedIMGs, make a new version */ + last->Flags &= ~DIF_Last; + entry->version = last->version + 1; } + entry->url = a_Url_dup(Url); + entry->Flags |= DIF_Last; + dList_insert_sorted(CachedIMGs, entry, Dicache_entry_cmp); return entry; } @@ -145,23 +126,15 @@ static DICacheEntry *Dicache_add_entry(const DilloUrl *Url) */ DICacheEntry *a_Dicache_get_entry(const DilloUrl *Url, int version) { - DICacheNode *node; + DICacheEntry e; DICacheEntry *entry = NULL; dReturn_val_if_fail(version != 0, NULL); - - node = dList_find_sorted(CachedIMGs, Url, Dicache_node_by_url_cmp); - if (node) { - if (version == DIC_Last) { - if (node->valid) { - entry = node->first; - for ( ; (entry && entry->next); entry = entry->next); - } - } else { - entry = node->first; - for ( ; entry && entry->version != version; entry = entry->next) ; - } - } + e.url = (DilloUrl*)Url; + e.version = version; + entry = dList_find_sorted(CachedIMGs, &e, Dicache_entry_cmp); + if (entry && !(entry->Flags & DIF_Valid) && version == DIC_Last) + entry = NULL; return entry; } @@ -170,57 +143,48 @@ DICacheEntry *a_Dicache_get_entry(const DilloUrl *Url, int version) */ static void Dicache_remove(const DilloUrl *Url, int version) { - DICacheNode *node; - DICacheEntry *entry, *prev; - _MSG("Dicache_remove url=%s\n", URL_STR(Url)); - node = dList_find_sorted(CachedIMGs, Url, Dicache_node_by_url_cmp); - prev = entry = (node) ? node->first : NULL; + DICacheEntry e, *entry; - while (entry && (entry->version != version) ) { - prev = entry; - entry = entry->next; - } - - if (entry) { - _MSG("Dicache_remove Decoder=%p DecoderData=%p\n", - entry->Decoder, entry->DecoderData); - /* Eliminate this dicache entry */ - dFree(entry->cmap); - a_Bitvec_free(entry->BitVec); - a_Imgbuf_unref(entry->v_imgbuf); - if (entry->Decoder) { - entry->Decoder(CA_Abort, entry->DecoderData); - } - dicache_size_total -= entry->TotalSize; - - if (node->first == entry) { - if (!entry->next) { - /* last entry with this URL. Remove the node as well */ - dList_remove(CachedIMGs, node); - a_Url_free(node->url); - dFree(node); - } else - node->first = entry->next; - } else { - prev->next = entry->next; - } - dFree(entry); + _MSG("Dicache_remove url=%s\n", URL_STR(Url)); + e.url = (DilloUrl*)Url; + e.version = version; + entry = dList_find_sorted(CachedIMGs, &e, Dicache_entry_cmp); + dReturn_if (entry == NULL); + + _MSG("Dicache_remove Imgbuf=%p Decoder=%p DecoderData=%p\n", + entry->v_imgbuf, entry->Decoder, entry->DecoderData); + /* Eliminate this dicache entry */ + dList_remove(CachedIMGs, entry); + dicache_size_total -= entry->TotalSize; + + /* entry cleanup */ + a_Url_free(entry->url); + dFree(entry->cmap); + a_Bitvec_free(entry->BitVec); + a_Imgbuf_unref(entry->v_imgbuf); + if (entry->Decoder) { + entry->Decoder(CA_Abort, entry->DecoderData); } + dFree(entry); } /* - * Unrefs the counter of a dicache entry, and _if_ no DwImage is acessing - * this buffer, then we call Dicache_remove() to do the job. + * Unrefs the counter of a dicache entry (it counts cache clients). + * If there're no clients and no imgbuf, remove the entry. + * Otherwise, let a_Dicache_cleanup() do the job later + * (keeping it cached meanwhile for e.g. reload, repush, back/fwd). */ void a_Dicache_unref(const DilloUrl *Url, int version) { DICacheEntry *entry; - _MSG("a_Dicache_unref\n"); if ((entry = a_Dicache_get_entry(Url, version))) { - if (--entry->RefCount == 0) { + _MSG("a_Dicache_unref: RefCount=%d State=%d ImgbufLastRef=%d\n", + entry->RefCount, entry->State, + entry->v_imgbuf ? a_Imgbuf_last_reference(entry->v_imgbuf) : -1); + if (entry->RefCount > 0) --entry->RefCount; + if (entry->RefCount == 0 && entry->v_imgbuf == NULL) Dicache_remove(Url, version); - } } } @@ -244,11 +208,9 @@ DICacheEntry* a_Dicache_ref(const DilloUrl *Url, int version) */ void a_Dicache_invalidate_entry(const DilloUrl *Url) { - DICacheNode *node; - - node = dList_find_sorted(CachedIMGs, Url, Dicache_node_by_url_cmp); - if (node) - node->valid = 0; + DICacheEntry *entry = a_Dicache_get_entry(Url, DIC_Last); + if (entry) + entry->Flags &= ~DIF_Valid; } @@ -256,7 +218,9 @@ void a_Dicache_invalidate_entry(const DilloUrl *Url) /* * Set image's width, height & type - * (By now, we'll use the image information despite the html tags --Jcid) + * - 'width' and 'height' come from the image data. + * - HTML width and height attrs are handled with setNonCssHint. + * - CSS sizing is handled by the CSS engine. */ void a_Dicache_set_parms(DilloUrl *url, int version, DilloImage *Image, uint_t width, uint_t height, DilloImgType type, @@ -269,7 +233,7 @@ void a_Dicache_set_parms(DilloUrl *url, int version, DilloImage *Image, /* Find the DicEntry for this Image */ DicEntry = a_Dicache_get_entry(url, version); dReturn_if_fail ( DicEntry != NULL ); - /* Parameters already set? */ + /* Parameters already set? Don't do it twice. */ dReturn_if_fail ( DicEntry->State < DIC_SetParms ); _MSG(" RefCount=%d version=%d\n", DicEntry->RefCount, DicEntry->version); @@ -292,7 +256,7 @@ void a_Dicache_set_parms(DilloUrl *url, int version, DilloImage *Image, /* * Implement the set_cmap method for the Image */ -void a_Dicache_set_cmap(DilloUrl *url, int version, DilloImage *Image, +void a_Dicache_set_cmap(DilloUrl *url, int version, int bg_color, const uchar_t *cmap, uint_t num_colors, int num_colors_max, int bg_index) { @@ -305,9 +269,9 @@ void a_Dicache_set_cmap(DilloUrl *url, int version, DilloImage *Image, DicEntry->cmap = dNew0(uchar_t, 3 * num_colors_max); memcpy(DicEntry->cmap, cmap, 3 * num_colors); if (bg_index >= 0 && (uint_t)bg_index < num_colors) { - DicEntry->cmap[bg_index * 3] = (Image->bg_color >> 16) & 0xff; - DicEntry->cmap[bg_index * 3 + 1] = (Image->bg_color >> 8) & 0xff; - DicEntry->cmap[bg_index * 3 + 2] = (Image->bg_color) & 0xff; + DicEntry->cmap[bg_index * 3] = (bg_color >> 16) & 0xff; + DicEntry->cmap[bg_index * 3 + 1] = (bg_color >> 8) & 0xff; + DicEntry->cmap[bg_index * 3 + 2] = (bg_color) & 0xff; } DicEntry->State = DIC_SetCmap; @@ -368,6 +332,9 @@ void a_Dicache_close(DilloUrl *url, int version, CacheClient_t *Client) /* a_Dicache_unref() may free DicEntry */ _MSG("a_Dicache_close RefCount=%d\n", DicEntry->RefCount - 1); + _MSG("a_Dicache_close DIC_Close=%d State=%d\n", DIC_Close, DicEntry->State); + _MSG(" a_Dicache_close imgbuf=%p Decoder=%p DecoderData=%p\n", + DicEntry->v_imgbuf, DicEntry->Decoder, DicEntry->DecoderData); if (DicEntry->State < DIC_Close) { DicEntry->State = DIC_Close; @@ -410,24 +377,29 @@ static void *Dicache_image(int ImgType, const char *MimeType, void *Ptr, DicEntry = a_Dicache_get_entry(web->url, DIC_Last); if (!DicEntry) { - /* Let's create an entry for this image... */ + /* Create an entry for this image... */ DicEntry = Dicache_add_entry(web->url); - DicEntry->DecoderData = - (ImgType == DIC_Png) ? - a_Png_new(web->Image, DicEntry->url, DicEntry->version) : - (ImgType == DIC_Gif) ? - a_Gif_new(web->Image, DicEntry->url, DicEntry->version) : - (ImgType == DIC_Jpeg) ? - a_Jpeg_new(web->Image, DicEntry->url, DicEntry->version) : - NULL; + /* Attach a decoder */ + if (ImgType == DIC_Jpeg) { + DicEntry->Decoder = (CA_Callback_t)a_Jpeg_callback; + DicEntry->DecoderData = + a_Jpeg_new(web->Image, DicEntry->url, DicEntry->version); + } else if (ImgType == DIC_Gif) { + DicEntry->Decoder = (CA_Callback_t)a_Gif_callback; + DicEntry->DecoderData = + a_Gif_new(web->Image, DicEntry->url, DicEntry->version); + } else if (ImgType == DIC_Png) { + DicEntry->Decoder = (CA_Callback_t)a_Png_callback; + DicEntry->DecoderData = + a_Png_new(web->Image, DicEntry->url, DicEntry->version); + } } else { /* Repeated image */ a_Dicache_ref(DicEntry->url, DicEntry->version); } - DicEntry->Decoder = (ImgType == DIC_Png) ? (CA_Callback_t)a_Png_callback : - (ImgType == DIC_Gif) ? (CA_Callback_t)a_Gif_callback : - (ImgType == DIC_Jpeg) ? (CA_Callback_t)a_Jpeg_callback: - NULL; + /* Survive three cleanup passes (set to zero = old behaviour). */ + DicEntry->SurvCleanup = 3; + *Data = DicEntry->DecoderData; *Call = (CA_Callback_t) a_Dicache_callback; @@ -535,52 +507,42 @@ void a_Dicache_callback(int Op, CacheClient_t *Client) void a_Dicache_cleanup(void) { int i; - DICacheNode *node; DICacheEntry *entry; - _MSG("a_Dicache_cleanup\n"); - for (i = 0; i < dList_length(CachedIMGs); ++i) { - node = dList_nth_data(CachedIMGs, i); - /* iterate each entry of this node */ - for (entry = node->first; entry; entry = entry->next) { - if (entry->v_imgbuf && - a_Imgbuf_last_reference(entry->v_imgbuf)) { - /* free this unused entry */ - if (entry->next) { - Dicache_remove(node->url, entry->version); - } else { - Dicache_remove(node->url, entry->version); - --i; - break; - } - } + for (i = 0; (entry = dList_nth_data(CachedIMGs, i)); ++i) { + _MSG(" SurvCleanup = %d\n", entry->SurvCleanup); + if (entry->RefCount == 0 && + (!entry->v_imgbuf || a_Imgbuf_last_reference(entry->v_imgbuf))) { + if (--entry->SurvCleanup >= 0) + continue; /* keep the entry one more pass */ + + /* free this unused entry */ + Dicache_remove(entry->url, entry->version); + --i; /* adjust counter */ } } + MSG("a_Dicache_cleanup: length = %d\n", dList_length(CachedIMGs)); } /* ------------------------------------------------------------------------- */ /* * Deallocate memory used by dicache module - * (Call this one at exit time) + * (Call this one at exit time, with no cache clients queued) */ void a_Dicache_freeall(void) { - DICacheNode *node; DICacheEntry *entry; - /* Remove every dicache node and its entries */ - while ((node = dList_nth_data(CachedIMGs, 0))) { - while ((entry = node->first)) { - node->first = entry->next; - dFree(entry->cmap); - a_Bitvec_free(entry->BitVec); - a_Imgbuf_unref(entry->v_imgbuf); - dicache_size_total -= entry->TotalSize; - } - dList_remove_fast(CachedIMGs, node); - a_Url_free(node->url); - dFree(node); + /* Remove all the dicache entries */ + while ((entry = dList_nth_data(CachedIMGs, dList_length(CachedIMGs)-1))) { + dList_remove_fast(CachedIMGs, entry); + a_Url_free(entry->url); + dFree(entry->cmap); + a_Bitvec_free(entry->BitVec); + a_Imgbuf_unref(entry->v_imgbuf); + dicache_size_total -= entry->TotalSize; + dFree(entry); } dList_free(CachedIMGs); } diff --git a/src/dicache.h b/src/dicache.h index df8a8b89..7d5ef6ee 100644 --- a/src/dicache.h +++ b/src/dicache.h @@ -12,6 +12,9 @@ extern "C" { /* Symbolic name to request the last version of an image */ #define DIC_Last -1 +/* Flags: Last version, Valid entry */ +#define DIF_Last 1 +#define DIF_Valid 2 /* These will reflect the entry's "state" */ @@ -26,8 +29,10 @@ typedef enum { typedef struct DICacheEntry { DilloUrl *url; /* Image URL for this entry */ - uint_t width, height; /* As taken from image data */ DilloImgType type; /* Image type */ + uint_t width, height; /* As taken from image data */ + short Flags; /* See Flags */ + short SurvCleanup; /* Cleanup-pass survival for unused images */ uchar_t *cmap; /* Color map */ void *v_imgbuf; /* Void pointer to an Imgbuf object */ uint_t TotalSize; /* Amount of memory the image takes up */ @@ -38,11 +43,9 @@ typedef struct DICacheEntry { int version; /* Version number, used for different versions of the same URL image */ + uint_t DecodedSize; /* Size of already decoded data */ CA_Callback_t Decoder; /* Client function */ void *DecoderData; /* Client function data */ - uint_t DecodedSize; /* Size of already decoded data */ - - struct DICacheEntry *next; /* Link to the next "newer" version */ } DICacheEntry; @@ -61,7 +64,7 @@ void a_Dicache_callback(int Op, CacheClient_t *Client); void a_Dicache_set_parms(DilloUrl *url, int version, DilloImage *Image, uint_t width, uint_t height, DilloImgType type, double gamma); -void a_Dicache_set_cmap(DilloUrl *url, int version, DilloImage *Image, +void a_Dicache_set_cmap(DilloUrl *url, int version, int bg_color, const uchar_t *cmap, uint_t num_colors, int num_colors_max, int bg_index); void a_Dicache_new_scan(const DilloUrl *url, int version); diff --git a/src/dillo.cc b/src/dillo.cc index ee2f4da4..0a68cb59 100644 --- a/src/dillo.cc +++ b/src/dillo.cc @@ -56,7 +56,9 @@ #include "lout/debug.hh" #include "dw/fltkcore.hh" +#include "dw/widget.hh" #include "dw/textblock.hh" +#include "dw/table.hh" /* * Command line options structure @@ -377,10 +379,18 @@ static DilloUrl *makeStartUrl(char *str, bool local) */ int main(int argc, char **argv) { - DBG_OBJ_COLOR("#c0ff80", "dw::*"); - DBG_OBJ_COLOR("#c0c0ff", "dw::fltk::*"); - DBG_OBJ_COLOR("#ffa0a0", "dw::core::*"); - DBG_OBJ_COLOR("#ffe0a0", "dw::core::style::*"); + DBG_OBJ_COLOR ("dw::*", "#c0ff80"); + DBG_OBJ_COLOR ("dw::fltk::*", "#c0c0ff"); + DBG_OBJ_COLOR ("dw::core::*", "#ffa0a0"); + DBG_OBJ_COLOR ("dw::core::style::*", "#ffe0a0"); + + DBG_OBJ_COLOR ("dw::Image", "#80ffa0"); + DBG_OBJ_COLOR ("dw::Textblock", "#f0ff80"); + DBG_OBJ_COLOR ("dw::OutOfFlowMgr", "#d0ff80"); + DBG_OBJ_COLOR ("dw::AlignedTextblock", "#e0ff80"); + DBG_OBJ_COLOR ("dw::ListItem", "#b0ff80"); + DBG_OBJ_COLOR ("dw::TableCell", "#80ff80"); + DBG_OBJ_COLOR ("dw::Table", "#80ffc0"); uint_t opt_id; uint_t options_got = 0; @@ -475,6 +485,8 @@ int main(int argc, char **argv) a_UIcmd_init(); StyleEngine::init(); + dw::core::Widget::setAdjustMinWidth (prefs.adjust_min_width); + dw::Table::setAdjustTableMinWidth (prefs.adjust_table_min_width); dw::Textblock::setPenaltyHyphen (prefs.penalty_hyphen); dw::Textblock::setPenaltyHyphen2 (prefs.penalty_hyphen_2); dw::Textblock::setPenaltyEmDashLeft (prefs.penalty_em_dash_left); diff --git a/src/domain.c b/src/domain.c index ea5c4948..8bff39de 100644 --- a/src/domain.c +++ b/src/domain.c @@ -129,7 +129,7 @@ bool_t a_Domain_permit(const DilloUrl *source, const DilloUrl *dest) ret = source_host[0] == '\0' || !dStrAsciiCasecmp(URL_SCHEME(dest), "data"); if (ret == FALSE) - MSG("Domain: DENIED from %s to %s.\n", source_host, URL_STR(dest)); + MSG("Domain: DENIED %s -> %s.\n", source_host, URL_STR(dest)); return ret; } @@ -151,7 +151,7 @@ bool_t a_Domain_permit(const DilloUrl *source, const DilloUrl *dest) if (ret == FALSE) { const char *src = source_host[0] ? source_host : URL_STR(source); - MSG("Domain: DENIED from %s to %s.\n", src, dest_host); + MSG("Domain: DENIED %s -> %s.\n", src, dest_host); } return ret; } diff --git a/src/form.cc b/src/form.cc index 07c12815..9e7dc4f6 100644 --- a/src/form.cc +++ b/src/form.cc @@ -343,7 +343,7 @@ void Html_tag_open_form(DilloHtml *html, const char *tag, int tagsize) HT2TB(html)->addParbreak (9, html->wordStyle ()); if (html->InFlags & IN_FORM) { - BUG_MSG("nested forms\n"); + BUG_MSG("Nested <form>."); return; } html->InFlags |= IN_FORM; @@ -356,14 +356,14 @@ void Html_tag_open_form(DilloHtml *html, const char *tag, int tagsize) if (!dStrAsciiCasecmp(attrbuf, "post")) { method = DILLO_HTML_METHOD_POST; } else if (dStrAsciiCasecmp(attrbuf, "get")) { - BUG_MSG("Unknown form submission method \"%s\"\n", attrbuf); + BUG_MSG("<form> submission method unknown: '%s'.", attrbuf); } } if ((attrbuf = a_Html_get_attr(html, tag, tagsize, "action"))) action = a_Html_url_new(html, attrbuf, NULL, 0); else { if (html->DocType != DT_HTML || html->DocTypeVersion <= 4.01f) - BUG_MSG("action attribute is required for <form>\n"); + BUG_MSG("<form> requires action attribute."); action = a_Url_dup(html->base_url); } content_type = DILLO_HTML_ENC_URLENCODED; @@ -417,7 +417,7 @@ static int Html_input_get_size(DilloHtml *html, const char *attrbuf) if (size < 1 || size > MAX_SIZE) { int badSize = size; size = (size < 1 ? 20 : MAX_SIZE); - BUG_MSG("input size=%d, using size=%d instead\n", badSize, size); + BUG_MSG("<input> size=%d, using size=%d instead.", badSize, size); } } return size; @@ -437,11 +437,11 @@ void Html_tag_open_input(DilloHtml *html, const char *tag, int tagsize) ResourceFactory *factory; if (html->InFlags & IN_SELECT) { - BUG_MSG("<input> element inside <select>\n"); + BUG_MSG("<input> inside <select>."); return; } if (html->InFlags & IN_BUTTON) { - BUG_MSG("<input> element inside <button>\n"); + BUG_MSG("<input> inside <button>."); return; } @@ -507,12 +507,12 @@ void Html_tag_open_input(DilloHtml *html, const char *tag, int tagsize) DilloHtmlForm *form = html->getCurrentForm(); if (form->method != DILLO_HTML_METHOD_POST) { valid = false; - BUG_MSG("Forms with file input MUST use HTTP POST method\n"); + BUG_MSG("<form> with file input MUST use HTTP POST method."); MSG("File input ignored in form not using HTTP POST method\n"); } else if (form->content_type != DILLO_HTML_ENC_MULTIPART) { valid = false; - BUG_MSG("Forms with file input MUST use multipart/form-data" - " encoding\n"); + BUG_MSG("<form> with file input MUST use multipart/form-data" + " encoding."); MSG("File input ignored in form not using multipart/form-data" " encoding\n"); } @@ -641,25 +641,25 @@ void Html_tag_content_textarea(DilloHtml *html, const char *tag, int tagsize) cols = strtol(attrbuf, NULL, 10); } else { if (html->DocType != DT_HTML || html->DocTypeVersion <= 4.01f) - BUG_MSG("cols attribute is required for <textarea>\n"); + BUG_MSG("<textarea> requires cols attribute."); cols = 20; } if (cols < 1 || cols > MAX_COLS) { int badCols = cols; cols = (cols < 1 ? 20 : MAX_COLS); - BUG_MSG("textarea cols=%d, using cols=%d instead\n", badCols, cols); + BUG_MSG("<textarea> cols=%d, using cols=%d instead.", badCols, cols); } if ((attrbuf = a_Html_get_attr(html, tag, tagsize, "rows"))) { rows = strtol(attrbuf, NULL, 10); } else { if (html->DocType != DT_HTML || html->DocTypeVersion <= 4.01f) - BUG_MSG("rows attribute is required for <textarea>\n"); + BUG_MSG("<textarea> requires rows attribute."); rows = 10; } if (rows < 1 || rows > MAX_ROWS) { int badRows = rows; rows = (rows < 1 ? 2 : MAX_ROWS); - BUG_MSG("textarea rows=%d, using rows=%d instead\n", badRows, rows); + BUG_MSG("<textarea> rows=%d, using rows=%d instead.", badRows, rows); } name = NULL; if ((attrbuf = a_Html_get_attr(html, tag, tagsize, "name"))) @@ -799,11 +799,11 @@ void Html_tag_close_select(DilloHtml *html) void Html_tag_open_optgroup(DilloHtml *html, const char *tag, int tagsize) { if (!(html->InFlags & IN_SELECT)) { - BUG_MSG("<optgroup> element outside <select>\n"); + BUG_MSG("<optgroup> outside <select>."); return; } if (html->InFlags & IN_OPTGROUP) { - BUG_MSG("nested <optgroup>\n"); + BUG_MSG("Nested <optgroup>."); return; } if (html->InFlags & IN_OPTION) { @@ -821,7 +821,7 @@ void Html_tag_open_optgroup(DilloHtml *html, const char *tag, int tagsize) bool enabled = (a_Html_get_attr(html, tag, tagsize, "disabled") == NULL); if (!label) { - BUG_MSG("label attribute is required for <optgroup>\n"); + BUG_MSG("<optgroup> requires label attribute."); label = strdup(""); } @@ -859,7 +859,7 @@ void Html_tag_close_optgroup(DilloHtml *html) void Html_tag_open_option(DilloHtml *html, const char *tag, int tagsize) { if (!(html->InFlags & IN_SELECT)) { - BUG_MSG("<option> element outside <select>\n"); + BUG_MSG("<option> outside <select>."); return; } if (html->InFlags & IN_OPTION) @@ -918,7 +918,7 @@ void Html_tag_open_button(DilloHtml *html, const char *tag, int tagsize) inp_type = DILLO_HTML_INPUT_BUTTON_SUBMIT; } else { inp_type = DILLO_HTML_INPUT_UNKNOWN; - BUG_MSG("Unknown button type: \"%s\"\n", type); + BUG_MSG("<button> type unknown: '%s'.", type); } if (inp_type != DILLO_HTML_INPUT_UNKNOWN) { @@ -945,9 +945,7 @@ void Html_tag_open_button(DilloHtml *html, const char *tag, int tagsize) embed = new Embed(resource); // a_Dw_button_set_sensitive (DW_BUTTON (button), FALSE); - HT2TB(html)->addParbreak (5, html->wordStyle ()); HT2TB(html)->addWidget (embed, html->backgroundStyle ()); - HT2TB(html)->addParbreak (5, html->wordStyle ()); S_TOP(html)->textblock = html->dw = page; @@ -103,9 +103,7 @@ typedef struct { size_t ColorMap_ofs; uint_t ColorResolution; uint_t NumColors; -#if 0 - int Background; -#endif + int Background; uint_t spill_line_index; #if 0 uint_t AspectRatio; /* AspectRatio (not used) */ @@ -165,9 +163,7 @@ void *a_Gif_new(DilloImage *Image, DilloUrl *url, int version) gif->state = 0; gif->Start_Ofs = 0; gif->linebuf = NULL; -#if 0 - gif->Background = -1; -#endif + gif->Background = Image->bg_color; gif->transparent = -1; gif->num_spill_lines_max = 0; gif->spill_lines = NULL; @@ -222,7 +218,7 @@ static void Gif_write(DilloGif *gif, void *Buf, uint_t BufSize) int bufsize, bytes_consumed; /* Sanity checks */ - if (!Buf || !gif->Image || BufSize == 0) + if (!Buf || BufSize == 0) return; buf = ((uchar_t *) Buf) + gif->Start_Ofs; @@ -804,8 +800,8 @@ static size_t Gif_do_img_desc(DilloGif *gif, void *Buf, if (bsize < 10) return 0; - gif->Width = LM_to_uint(buf[4], buf[5]); - gif->Height = LM_to_uint(buf[6], buf[7]); + gif->Width = LM_to_uint(buf[4], buf[5]); + gif->Height = LM_to_uint(buf[6], buf[7]); /* check max image size */ if (gif->Width <= 0 || gif->Height <= 0 || @@ -820,6 +816,7 @@ static size_t Gif_do_img_desc(DilloGif *gif, void *Buf, a_Dicache_set_parms(gif->url, gif->version, gif->Image, gif->Width, gif->Height, DILLO_IMG_TYPE_INDEXED, 1 / 2.2); + gif->Image = NULL; /* safeguard: hereafter it may be freed by its owner */ Flags = buf[8]; @@ -850,8 +847,8 @@ static size_t Gif_do_img_desc(DilloGif *gif, void *Buf, gif->spill_line_index = 0; gif->linebuf = dMalloc(gif->Width); gif->state = 3; /*Process the lzw data next */ - if (gif->Image && gif->ColorMap_ofs) { - a_Dicache_set_cmap(gif->url, gif->version, gif->Image, + if (gif->ColorMap_ofs) { + a_Dicache_set_cmap(gif->url, gif->version, gif->Background, (uchar_t *) Buf + gif->ColorMap_ofs, gif->NumColors, 256, gif->transparent); } diff --git a/src/html.cc b/src/html.cc index a8c70879..a1452858 100644 --- a/src/html.cc +++ b/src/html.cc @@ -26,6 +26,7 @@ #include "msg.h" #include "binaryconst.h" #include "colors.h" +#include "html_charrefs.h" #include "utf8.hh" #include "misc.h" @@ -132,9 +133,11 @@ void DilloHtml::bugMessage(const char *format, ... ) { va_list argp; + if (bw->num_page_bugs) + dStr_append_c(bw->page_bugs, '\n'); dStr_sprintfa(bw->page_bugs, "HTML warning: line %d, ", - getCurTagLineNumber()); + getCurrLineNumber()); va_start(argp, format); dStr_vsprintfa(bw->page_bugs, format, argp); va_end(argp); @@ -158,15 +161,15 @@ DilloUrl *a_Html_url_new(DilloHtml *html, const char *suffix = (n_ic) > 1 ? "s" : ""; n_ic_spc = URL_ILLEGAL_CHARS_SPC(url); if (n_ic == n_ic_spc) { - BUG_MSG("URL has %d illegal space%s\n", n_ic, suffix); + BUG_MSG("URL has %d illegal space%s ('%s').", n_ic, suffix, url_str); } else if (n_ic_spc == 0) { - BUG_MSG("URL has %d illegal character%s in {00-1F, 7F} range\n", - n_ic, suffix); + BUG_MSG("URL has %d illegal byte%s in {00-1F, 7F-FF} range ('%s').", + n_ic, suffix, url_str); } else { - BUG_MSG("URL has %d illegal character%s: " - "%d space%s, and %d in {00-1F, 7F} range\n", + BUG_MSG("URL has %d illegal byte%s: " + "%d space%s and %d in {00-1F, 7F-FF} range ('%s').", n_ic, suffix, - n_ic_spc, n_ic_spc > 1 ? "s" : "", n_ic-n_ic_spc); + n_ic_spc, n_ic_spc > 1 ? "s" : "", n_ic-n_ic_spc, url_str); } } return url; @@ -290,7 +293,7 @@ void a_Html_tag_set_align_attr(DilloHtml *html, const char *tag, int tagsize) TextAlignType textAlignType = TEXT_ALIGN_LEFT; if (html->DocType == DT_HTML && html->DocTypeVersion >= 5.0f) - BUG_MSG("The align attribute is obsolete in HTML5.\n"); + BUG_MSG("The align attribute is obsolete in HTML5."); if (dStrAsciiCasecmp (align, "left") == 0) textAlignType = TEXT_ALIGN_LEFT; @@ -334,7 +337,7 @@ bool a_Html_tag_set_valign_attr(DilloHtml *html, const char *tag, int tagsize) if ((attr = a_Html_get_attr(html, tag, tagsize, "valign"))) { if (html->DocType == DT_HTML && html->DocTypeVersion >= 5.0f) - BUG_MSG("The valign attribute is obsolete in HTML5.\n"); + BUG_MSG("The valign attribute is obsolete in HTML5."); if (dStrAsciiCasecmp (attr, "top") == 0) valign = VALIGN_TOP; @@ -356,15 +359,24 @@ bool a_Html_tag_set_valign_attr(DilloHtml *html, const char *tag, int tagsize) /* * Create and add a new Textblock to the current Textblock */ -static void Html_add_textblock(DilloHtml *html, int space) +static void Html_add_textblock(DilloHtml *html, bool addBreaks, int breakSpace) { Textblock *textblock = new Textblock (prefs.limit_text_width); - HT2TB(html)->addParbreak (space, html->wordStyle ()); - HT2TB(html)->addWidget (textblock, html->style ()); - HT2TB(html)->addParbreak (space, html->wordStyle ()); + if (addBreaks) + HT2TB(html)->addParbreak (breakSpace, html->wordStyle ()); + HT2TB(html)->addWidget (textblock, html->style ()); /* Works also for floats + etc. */ + if (addBreaks) + HT2TB(html)->addParbreak (breakSpace, html->wordStyle ()); S_TOP(html)->textblock = html->dw = textblock; - S_TOP(html)->hand_over_break = true; + if (addBreaks) + S_TOP(html)->hand_over_break = true; +} + +static bool Html_will_textblock_be_out_of_flow(DilloHtml *html) +{ + return HT2TB(html)->isStyleOutOfFlow (html->style ()); } /* @@ -397,9 +409,8 @@ DilloHtml::DilloHtml(BrowserWindow *p_bw, const DilloUrl *url, stop_parser = false; - CurrTagOfs = 0; - OldTagOfs = 0; - OldTagLine = 1; + CurrOfs = OldOfs = 0; + OldLine = 1; DocType = DT_NONE; /* assume Tag Soup 0.0! :-) */ DocTypeVersion = 0.0f; @@ -539,10 +550,10 @@ void DilloHtml::write(char *Buf, int BufSize, int Eof) } /* - * Return the line number of the tag being processed by the parser. + * Return the line number of the tag/word being processed by the parser. * Also update the offsets. */ -int DilloHtml::getCurTagLineNumber() +int DilloHtml::getCurrLineNumber() { int i, ofs, line; const char *p = Start_Buf; @@ -551,13 +562,13 @@ int DilloHtml::getCurTagLineNumber() /* Disable line counting for META hack. Buffers differ. */ dReturn_val_if((InFlags & IN_META_HACK), -1); - ofs = CurrTagOfs; - line = OldTagLine; - for (i = OldTagOfs; i < ofs; ++i) + ofs = CurrOfs; + line = OldLine; + for (i = OldOfs; i < ofs; ++i) if (p[i] == '\n' || (p[i] == '\r' && p[i+1] != '\n')) ++line; - OldTagOfs = CurrTagOfs; - OldTagLine = line; + OldOfs = CurrOfs; + OldLine = line; return line; } @@ -787,113 +798,16 @@ void a_Html_stash_init(DilloHtml *html) dStr_truncate(html->Stash, 0); } -/* Entities list from the HTML 4.01 DTD */ -typedef struct { - const char *entity; - int isocode; -} Ent_t; - -#define NumEnt 252 -static const Ent_t Entities[NumEnt] = { - {"AElig",0306}, {"Aacute",0301}, {"Acirc",0302}, {"Agrave",0300}, - {"Alpha",01621},{"Aring",0305}, {"Atilde",0303}, {"Auml",0304}, - {"Beta",01622}, {"Ccedil",0307}, {"Chi",01647}, {"Dagger",020041}, - {"Delta",01624},{"ETH",0320}, {"Eacute",0311}, {"Ecirc",0312}, - {"Egrave",0310},{"Epsilon",01625},{"Eta",01627}, {"Euml",0313}, - {"Gamma",01623},{"Iacute",0315}, {"Icirc",0316}, {"Igrave",0314}, - {"Iota",01631}, {"Iuml",0317}, {"Kappa",01632}, {"Lambda",01633}, - {"Mu",01634}, {"Ntilde",0321}, {"Nu",01635}, {"OElig",0522}, - {"Oacute",0323},{"Ocirc",0324}, {"Ograve",0322}, {"Omega",01651}, - {"Omicron",01637},{"Oslash",0330},{"Otilde",0325},{"Ouml",0326}, - {"Phi",01646}, {"Pi",01640}, {"Prime",020063},{"Psi",01650}, - {"Rho",01641}, {"Scaron",0540}, {"Sigma",01643}, {"THORN",0336}, - {"Tau",01644}, {"Theta",01630}, {"Uacute",0332}, {"Ucirc",0333}, - {"Ugrave",0331},{"Upsilon",01645},{"Uuml",0334}, {"Xi",01636}, - {"Yacute",0335},{"Yuml",0570}, {"Zeta",01626}, {"aacute",0341}, - {"acirc",0342}, {"acute",0264}, {"aelig",0346}, {"agrave",0340}, - {"alefsym",020465},{"alpha",01661},{"amp",38}, {"and",021047}, - {"ang",021040}, {"aring",0345}, {"asymp",021110},{"atilde",0343}, - {"auml",0344}, {"bdquo",020036},{"beta",01662}, {"brvbar",0246}, - {"bull",020042},{"cap",021051}, {"ccedil",0347}, {"cedil",0270}, - {"cent",0242}, {"chi",01707}, {"circ",01306}, {"clubs",023143}, - {"cong",021105},{"copy",0251}, {"crarr",020665},{"cup",021052}, - {"curren",0244},{"dArr",020723}, {"dagger",020040},{"darr",020623}, - {"deg",0260}, {"delta",01664}, {"diams",023146},{"divide",0367}, - {"eacute",0351},{"ecirc",0352}, {"egrave",0350}, {"empty",021005}, - {"emsp",020003},{"ensp",020002}, {"epsilon",01665},{"equiv",021141}, - {"eta",01667}, {"eth",0360}, {"euml",0353}, {"euro",020254}, - {"exist",021003},{"fnof",0622}, {"forall",021000},{"frac12",0275}, - {"frac14",0274},{"frac34",0276}, {"frasl",020104},{"gamma",01663}, - {"ge",021145}, {"gt",62}, {"hArr",020724}, {"harr",020624}, - {"hearts",023145},{"hellip",020046},{"iacute",0355},{"icirc",0356}, - {"iexcl",0241}, {"igrave",0354}, {"image",020421},{"infin",021036}, - {"int",021053}, {"iota",01671}, {"iquest",0277}, {"isin",021010}, - {"iuml",0357}, {"kappa",01672}, {"lArr",020720}, {"lambda",01673}, - {"lang",021451},{"laquo",0253}, {"larr",020620}, {"lceil",021410}, - {"ldquo",020034},{"le",021144}, {"lfloor",021412},{"lowast",021027}, - {"loz",022712}, {"lrm",020016}, {"lsaquo",020071},{"lsquo",020030}, - {"lt",60}, {"macr",0257}, {"mdash",020024},{"micro",0265}, - {"middot",0267},{"minus",021022},{"mu",01674}, {"nabla",021007}, - {"nbsp",0240}, {"ndash",020023},{"ne",021140}, {"ni",021013}, - {"not",0254}, {"notin",021011},{"nsub",021204}, {"ntilde",0361}, - {"nu",01675}, {"oacute",0363}, {"ocirc",0364}, {"oelig",0523}, - {"ograve",0362},{"oline",020076},{"omega",01711}, {"omicron",01677}, - {"oplus",021225},{"or",021050}, {"ordf",0252}, {"ordm",0272}, - {"oslash",0370},{"otilde",0365}, {"otimes",021227},{"ouml",0366}, - {"para",0266}, {"part",021002}, {"permil",020060},{"perp",021245}, - {"phi",01706}, {"pi",01700}, {"piv",01726}, {"plusmn",0261}, - {"pound",0243}, {"prime",020062},{"prod",021017}, {"prop",021035}, - {"psi",01710}, {"quot",34}, {"rArr",020722}, {"radic",021032}, - {"rang",021452},{"raquo",0273}, {"rarr",020622}, {"rceil",021411}, - {"rdquo",020035},{"real",020434},{"reg",0256}, {"rfloor",021413}, - {"rho",01701}, {"rlm",020017}, {"rsaquo",020072},{"rsquo",020031}, - {"sbquo",020032},{"scaron",0541},{"sdot",021305}, {"sect",0247}, - {"shy",0255}, {"sigma",01703}, {"sigmaf",01702},{"sim",021074}, - {"spades",023140},{"sub",021202},{"sube",021206}, {"sum",021021}, - {"sup",021203}, {"sup1",0271}, {"sup2",0262}, {"sup3",0263}, - {"supe",021207},{"szlig",0337}, {"tau",01704}, {"there4",021064}, - {"theta",01670},{"thetasym",01721},{"thinsp",020011},{"thorn",0376}, - {"tilde",01334},{"times",0327}, {"trade",020442},{"uArr",020721}, - {"uacute",0372},{"uarr",020621}, {"ucirc",0373}, {"ugrave",0371}, - {"uml",0250}, {"upsih",01722}, {"upsilon",01705},{"uuml",0374}, - {"weierp",020430},{"xi",01676}, {"yacute",0375}, {"yen",0245}, - {"yuml",0377}, {"zeta",01666}, {"zwj",020015}, {"zwnj",020014} -}; - - -/* - * Comparison function for binary search - */ -static int Html_entity_comp(const void *a, const void *b) -{ - return strcmp(((Ent_t *)a)->entity, ((Ent_t *)b)->entity); -} - -/* - * Binary search of 'key' in entity list - */ -static int Html_entity_search(char *key) -{ - Ent_t *res, EntKey; - - EntKey.entity = key; - res = (Ent_t*) bsearch(&EntKey, Entities, NumEnt, - sizeof(Ent_t), Html_entity_comp); - if (res) - return (res - Entities); - return -1; -} - /* * This is M$ non-standard "smart quotes" (w1252). Now even deprecated by them! * * SGML for HTML4.01 defines c >= 128 and c <= 159 as UNUSED. - * TODO: Probably I should remove this hack, and add a HTML warning. --Jcid + * TODO: Probably I should remove this hack. --Jcid */ -static int Html_ms_stupid_quotes_2ucs(int isocode) +static int Html_ms_stupid_quotes_2ucs(int codepoint) { int ret; - switch (isocode) { + switch (codepoint) { case 145: case 146: ret = '\''; break; case 147: @@ -901,130 +815,233 @@ static int Html_ms_stupid_quotes_2ucs(int isocode) case 149: ret = 176; break; case 150: case 151: ret = '-'; break; - default: ret = isocode; break; + default: ret = codepoint; break; } return ret; } /* - * Given an entity, return the UCS character code. - * Returns a negative value (error code) if not a valid entity. - * - * The first character *token is assumed to be == '&' - * - * For valid entities, *entsize is set to the length of the parsed entity. + * Parse a numeric character reference (e.g., "/" or "/"). + * The "&#" has already been consumed. */ -static int Html_parse_entity(DilloHtml *html, const char *token, - int toksize, int *entsize) +static const char *Html_parse_numeric_charref(DilloHtml *html, char *tok, + bool_t is_attr, int *entsize) { - int isocode, i; - char *tok, *s, c; + static char buf[5]; + char *s = tok; + int n, codepoint = -1; - token++; - tok = s = toksize ? dStrndup(token, (uint_t)toksize) : dStrdup(token); - - isocode = -1; - - if (*s == '#') { - /* numeric character reference */ - errno = 0; - if (*++s == 'x' || *s == 'X') { - if (isxdigit(*++s)) { - /* strtol with base 16 accepts leading "0x" - we don't */ - if (*s == '0' && s[1] == 'x') { - s++; - isocode = 0; - } else { - isocode = strtol(s, &s, 16); - } + errno = 0; + + if (*s == 'x' || *s == 'X') { + if (isxdigit(*++s)) { + /* strtol with base 16 accepts leading "0x" - we don't */ + if (*s == '0' && s[1] == 'x') { + s++; + codepoint = 0; + } else { + codepoint = strtol(s, &s, 16); } - } else if (isdigit(*s)) { - isocode = strtol(s, &s, 10); } + } else if (isdigit(*s)) { + codepoint = strtol(s, &s, 10); + } + if (errno) + codepoint = -1; - if (!isocode || errno || isocode > 0xffff) { - /* this catches null bytes, errors and codes >= 0xFFFF */ - BUG_MSG("numeric character reference \"%s\" out of range\n", tok); - isocode = -2; + if (*s == ';') + s++; + else { + if (prefs.show_extra_warnings && (html->DocType == DT_XHTML || + (html->DocType == DT_HTML && html->DocTypeVersion <= 4.01f))) { + char c = *s; + *s = '\0'; + BUG_MSG("Character reference '&#%s' lacks ';'.", tok); + *s = c; } - - if (isocode != -1) { - if (*s == ';') - s++; - else if (prefs.show_extra_warnings) - BUG_MSG("numeric character reference without trailing ';'\n"); + /* Don't require ';' for old HTML, except that our current heuristic + * is to require it in attributes to avoid cases like "©=1" found + * in URLs. + */ + if (is_attr || html->DocType == DT_XHTML || + (html->DocType == DT_HTML && html->DocTypeVersion >= 5.0f)) { + return NULL; } - } else if (isalpha(*s)) { - /* character entity reference */ - while (*++s && (isalnum(*s) || strchr(":_.-", *s))) ; - c = *s; - *s = 0; + } + if ((codepoint < 0x20 && codepoint != '\t' && codepoint != '\n' && + codepoint != '\f') || + (codepoint >= 0x7f && codepoint <= 0x9f) || + (codepoint >= 0xd800 && codepoint <= 0xdfff) || codepoint > 0x10ffff || + ((codepoint & 0xfffe) == 0xfffe) || + (!(html->DocType == DT_HTML && html->DocTypeVersion >= 5.0f) && + codepoint > 0xffff)) { + /* this catches null bytes, errors, codes out of range, disallowed + * control chars, permanently undefined chars, and surrogates. + */ + char c = *s; + *s = '\0'; + BUG_MSG("Numeric character reference '&#%s' is not valid.", tok); + *s = c; - if ((i = Html_entity_search(tok)) >= 0) { - isocode = Entities[i].isocode; + codepoint = (codepoint >= 145 && codepoint <= 151) ? + Html_ms_stupid_quotes_2ucs(codepoint) : -1; + } + if (codepoint != -1) { + if (codepoint >= 128) { + n = a_Utf8_encode(codepoint, buf); } else { - if (html->DocType == DT_XHTML && !strcmp(tok, "apos")) { - isocode = 0x27; - } else { - if ((html->DocType == DT_HTML && html->DocTypeVersion == 4.01f) || - html->DocType == DT_XHTML) - BUG_MSG("undefined character entity '%s'\n", tok); - isocode = -3; - } + n = 1; + buf[0] = (char) codepoint; + } + assert(n < 5); + buf[n] = '\0'; + *entsize = s-tok+2; + return buf; + } else { + return NULL; + } +} + +/* + * Comparison function for binary search + */ +static int Html_charref_comp(const void *a, const void *b) +{ + return strcmp(((Charref_t *)a)->ref, ((Charref_t *)b)->ref); +} + +/* + * Binary search of 'key' in charref list + */ +static Charref_t *Html_charref_search(char *key) +{ + Charref_t RefKey; + + RefKey.ref = key; + return (Charref_t*) bsearch(&RefKey, Charrefs, NumRef, + sizeof(Charref_t), Html_charref_comp); +} + +/* + * Parse a named character reference (e.g., "&" or "…"). + * The "&" has already been consumed. + */ +static const char *Html_parse_named_charref(DilloHtml *html, char *tok, + bool_t is_attr, int *entsize) +{ + Charref_t *p; + char c; + char *s = tok; + const char *ret = NULL; + + while (*++s && (isalnum(*s) || strchr(":_.-", *s))) ; + c = *s; + *s = '\0'; + if (c != ';') { + if (prefs.show_extra_warnings && (html->DocType == DT_XHTML || + (html->DocType == DT_HTML && html->DocTypeVersion <= 4.01f))) + BUG_MSG("Character reference '&%s' lacks ';'.", tok); + + /* Don't require ';' for old HTML, except that our current heuristic + * is to require it in attributes to avoid cases like "©=1" found + * in URLs. + */ + if (is_attr || html->DocType == DT_XHTML || + (html->DocType == DT_HTML && html->DocTypeVersion >= 5.0f)) { + return ret; } - if (c == ';') - s++; - else if (prefs.show_extra_warnings) - BUG_MSG("character entity reference without trailing ';'\n"); } + if ((p = Html_charref_search(tok))) { + ret = (html->DocType == DT_HTML && html->DocTypeVersion >= 5.0f) ? + p->html5_str : p->html4_str; + } + + if (!ret && html->DocType == DT_XHTML && !strcmp(tok, "apos")) + ret = "'"; + + *s = c; + if (c == ';') + s++; + + if (!ret) { + c = *s; + *s = '\0'; + BUG_MSG("Undefined character reference '&%s'.", tok); + *s = c; + } *entsize = s-tok+1; - dFree(tok); + return ret; +} + +/* + * Given an entity, return the corresponding string. + * Returns NULL if not a valid entity. + * + * The first character *token is assumed to be == '&' + * + * For valid entities, *entsize is set to the length of the parsed entity. + */ +static const char *Html_parse_entity(DilloHtml *html, const char *token, + int toksize, int *entsize, bool_t is_attr) +{ + const char *ret = NULL; + char *tok; - if (isocode >= 145 && isocode <= 151) { - /* TODO: remove this hack. */ - isocode = Html_ms_stupid_quotes_2ucs(isocode); - } else if (isocode == -1 && prefs.show_extra_warnings) - BUG_MSG("literal '&'\n"); + token++; + tok = dStrndup(token, (uint_t)toksize); + + if (*tok == '#') { + ret = Html_parse_numeric_charref(html, tok+1, is_attr, entsize); + } else if (isalpha(*tok)) { + ret = Html_parse_named_charref(html, tok, is_attr, entsize); + } else if (prefs.show_extra_warnings && + (!(html->DocType == DT_HTML && html->DocTypeVersion >= 5.0f))) { + // HTML5 doesn't mind literal '&'s. + BUG_MSG("Literal '&'."); + } + dFree(tok); - return isocode; + return ret; } /* - * Convert all the entities in a token to utf8 encoding. Takes - * a token and its length, and returns a newly allocated string. + * Parse all the entities in a token. Takes the token and its length, and + * returns a newly allocated string. */ char *a_Html_parse_entities(DilloHtml *html, const char *token, int toksize) { const char *esc_set = "&"; - char *new_str, buf[4]; - int i, j, k, n, s, isocode, entsize; - - new_str = dStrndup(token, toksize); - s = strcspn(new_str, esc_set); - if (new_str[s] == 0) - return new_str; - - for (i = j = s; i < toksize; i++) { - if (token[i] == '&' && - (isocode = Html_parse_entity(html, token+i, - toksize-i, &entsize)) >= 0) { - if (isocode >= 128) { - /* multibyte encoding */ - n = a_Utf8_encode(isocode, buf); - for (k = 0; k < n; ++k) - new_str[j++] = buf[k]; + int i, s, entsize; + char *str; + + s = strcspn(token, esc_set); + if (s >= toksize) { + /* no ampersands */ + str = dStrndup(token, toksize); + } else { + Dstr *ds = dStr_sized_new(toksize); + + dStr_append_l(ds, token, s); + + for (i = s; i < toksize; i++) { + const char *entstr; + const bool_t is_attr = FALSE; + + if (token[i] == '&' && + (entstr = Html_parse_entity(html, token+i, toksize-i, &entsize, + is_attr))) { + dStr_append(ds, entstr); + i += entsize-1; } else { - new_str[j++] = (char) isocode; + dStr_append_c(ds, token[i]); } - i += entsize-1; - } else { - new_str[j++] = token[i]; } + str = ds->str; + dStr_free(ds, 0); } - new_str[j] = '\0'; - return new_str; + return str; } /* @@ -1095,7 +1112,7 @@ static void Html_process_space(DilloHtml *html, const char *space, break; case '\t': if (prefs.show_extra_warnings) - BUG_MSG("TAB character inside <PRE>\n"); + BUG_MSG("TAB character inside <pre>."); offset = TAB_SIZE - html->pre_column % TAB_SIZE; spaceCnt += offset; html->pre_column += offset; @@ -1314,7 +1331,7 @@ static void Html_tag_cleanup_to_idx(DilloHtml *html, int idx) int toptag_idx = S_TOP(html)->tag_idx; TagInfo toptag = Tags[toptag_idx]; if (s_sz > idx + 1 && toptag.EndTag != 'O') - BUG_MSG(" - forcing close of open tag: <%s>\n", toptag.name); + BUG_MSG(" - forcing close of open tag: <%s>.", toptag.name); _MSG("Close: %*s%s\n", size," ", toptag.name); if (toptag.close) toptag.close(html); @@ -1372,10 +1389,10 @@ static void Html_tag_cleanup_at_close(DilloHtml *html, int new_idx) if (matched) { Html_tag_cleanup_to_idx(html, stack_idx); } else if (expected) { - BUG_MSG("unexpected closing tag: </%s> -- expected </%s>.\n", + BUG_MSG("Unexpected closing tag: </%s> -- expected </%s>.", new_tag.name, Tags[tag_idx].name); } else { - BUG_MSG("unexpected closing tag: </%s>.\n", new_tag.name); + BUG_MSG("Unexpected closing tag: </%s>.", new_tag.name); } } @@ -1411,7 +1428,7 @@ static void Html_tag_cleanup_nested_inputs(DilloHtml *html, int new_idx) } if (matched) { - BUG_MSG("attempt to nest <%s> element inside <%s> -- closing <%s>\n", + BUG_MSG("Attempt to nest <%s> element inside <%s> -- closing <%s>.", Tags[new_idx].name, Tags[u_idx].name, Tags[u_idx].name); Html_tag_cleanup_to_idx(html, stack_idx); } else { @@ -1481,7 +1498,7 @@ CssLength a_Html_parse_length (DilloHtml *html, const char *attr) else { /* allow only whitespaces */ if (*end && !isspace (*end)) { - BUG_MSG("Garbage after length: %s\n", attr); + BUG_MSG("Garbage after length: '%s'.", attr); l = CSS_CREATE_LENGTH(0.0, CSS_LENGTH_TYPE_AUTO); } } @@ -1501,7 +1518,7 @@ int32_t a_Html_color_parse(DilloHtml *html, const char *str, int32_t color = a_Color_parse(str, default_color, &err); if (err) { - BUG_MSG("color \"%s\" is not in \"#RRGGBB\" format\n", str); + BUG_MSG("Color '%s' is not in \"#RRGGBB\" format.", str); } return color; } @@ -1518,8 +1535,8 @@ static int bool valid = *val && !strchr(val, ' '); if (!valid) { - BUG_MSG("'%s' value must not be empty and must not contain spaces.\n", - attrname); + BUG_MSG("'%s' value \"%s\" must not be empty and must not contain " + "spaces.", attrname, val); } return valid ? 1 : 0; } else { @@ -1530,8 +1547,8 @@ static int break; if (val[i] || !(isascii(val[0]) && isalpha(val[0]))) - BUG_MSG("'%s' value \"%s\" is not of the form " - "[A-Za-z][A-Za-z0-9:_.-]*\n", attrname, val); + BUG_MSG("%s attribute value \"%s\" is not of the form " + "'[A-Za-z][A-Za-z0-9:_.-]*'.", attrname, val); return !(val[i]); } @@ -1559,7 +1576,6 @@ static int static void Html_parse_doctype(DilloHtml *html, const char *tag, int tagsize) { static const char HTML_SGML_sig [] = "<!DOCTYPE HTML PUBLIC "; - static const char HTML5_sig [] = "<!DOCTYPE html>"; static const char HTML20 [] = "-//IETF//DTD HTML"; static const char HTML32 [] = "-//W3C//DTD HTML 3.2"; static const char HTML40 [] = "-//W3C//DTD HTML 4.0"; @@ -1596,7 +1612,7 @@ static void Html_parse_doctype(DilloHtml *html, const char *tag, int tagsize) _MSG("New: {%s}\n", ntag); if (html->DocType != DT_NONE) - BUG_MSG("Multiple DOCTYPE declarations.\n"); + BUG_MSG("Multiple DOCTYPE declarations."); /* The default DT_NONE type is TagSoup */ if (i > strlen(HTML_SGML_sig) && // avoid out of bounds reads! @@ -1624,13 +1640,14 @@ static void Html_parse_doctype(DilloHtml *html, const char *tag, int tagsize) html->DocType = DT_HTML; html->DocTypeVersion = 2.0f; } - } else if (!dStrAsciiCasecmp(ntag, HTML5_sig)) { + } else if (!dStrAsciiCasecmp(ntag, "<!DOCTYPE html>") || + !dStrAsciiCasecmp(ntag, "<!DOCTYPE html >")) { html->DocType = DT_HTML; html->DocTypeVersion = 5.0f; } if (html->DocType == DT_NONE) { html->DocType = DT_UNRECOGNIZED; - BUG_MSG("DOCTYPE not recognized:\n%s.\n", ntag); + BUG_MSG("DOCTYPE not recognized: ('%s').", ntag); } dFree(ntag); } @@ -1649,7 +1666,7 @@ static void Html_tag_open_html(DilloHtml *html, const char *tag, int tagsize) ++html->Num_HTML; if (html->Num_HTML > 1) { - BUG_MSG("HTML element was already open\n"); + BUG_MSG("<html> was already open."); html->ReqTagClose = true; } } @@ -1668,7 +1685,7 @@ static void Html_tag_close_html(DilloHtml *html) static void Html_tag_open_head(DilloHtml *html, const char *tag, int tagsize) { if (html->InFlags & IN_BODY) { - BUG_MSG("HEAD element must go before the BODY section\n"); + BUG_MSG("<head> must go before the BODY section."); html->ReqTagClose = true; return; } @@ -1676,10 +1693,10 @@ static void Html_tag_open_head(DilloHtml *html, const char *tag, int tagsize) if (html->Num_HEAD < UCHAR_MAX) ++html->Num_HEAD; if (html->InFlags & IN_HEAD) { - BUG_MSG("HEAD element was already open\n"); + BUG_MSG("<head> was already open."); html->ReqTagClose = true; } else if (html->Num_HEAD > 1) { - BUG_MSG("HEAD section already finished -- ignoring\n"); + BUG_MSG("<head> already finished -- ignoring."); html->ReqTagClose = true; } else { html->InFlags |= IN_HEAD; @@ -1696,7 +1713,7 @@ static void Html_tag_close_head(DilloHtml *html) if (html->Num_HEAD == 1) { /* match for the well formed start of HEAD section */ if (html->Num_TITLE == 0) - BUG_MSG("HEAD section lacks the TITLE element\n"); + BUG_MSG("<head> lacks <title>."); html->InFlags &= ~IN_HEAD; @@ -1726,9 +1743,9 @@ static void Html_tag_open_title(DilloHtml *html, const char *tag, int tagsize) if (html->Num_TITLE < UCHAR_MAX) ++html->Num_TITLE; if (html->Num_TITLE > 1) - BUG_MSG("A redundant TITLE element was found\n"); + BUG_MSG("Redundant <title>."); } else { - BUG_MSG("TITLE element must be inside the HEAD section -- ignoring\n"); + BUG_MSG("<title> must be inside <head> -- ignoring."); } } @@ -1776,7 +1793,7 @@ static void Html_tag_open_style(DilloHtml *html, const char *tag, int tagsize) if (!(attrbuf = a_Html_get_attr(html, tag, tagsize, "type"))) { if (html->DocType != DT_HTML || html->DocTypeVersion <= 4.01f) - BUG_MSG("type attribute is required for <style>\n"); + BUG_MSG("<style> requires type attribute."); } else if (dStrAsciiCasecmp(attrbuf, "text/css")) { html->loadCssFromStash = false; } @@ -1800,8 +1817,8 @@ static void Html_tag_open_style(DilloHtml *html, const char *tag, int tagsize) static void Html_tag_close_style(DilloHtml *html) { if (prefs.parse_embedded_css && html->loadCssFromStash) - html->styleEngine->parse(html, html->base_url, html->Stash->str, html->Stash->len, - CSS_ORIGIN_AUTHOR); + html->styleEngine->parse(html, html->base_url, html->Stash->str, + html->Stash->len, CSS_ORIGIN_AUTHOR); } /* @@ -1825,21 +1842,21 @@ static void Html_tag_open_body(DilloHtml *html, const char *tag, int tagsize) ++html->Num_BODY; if (html->Num_BODY > 1) { - BUG_MSG("BODY element was already open\n"); + BUG_MSG("<body> was already open."); html->ReqTagClose = true; return; } if (html->InFlags & IN_HEAD) { /* if we're here, it's bad XHTML, no need to recover */ - BUG_MSG("unclosed HEAD element\n"); + BUG_MSG("Unclosed <head>."); } if ((attrbuf = a_Html_get_attr(html, tag, tagsize, "bgcolor"))) { color = a_Html_color_parse(html, attrbuf, -1); if (html->DocType == DT_HTML && html->DocTypeVersion >= 5.0f) - BUG_MSG("<body> bgcolor attribute is obsolete.\n"); + BUG_MSG("<body> bgcolor attribute is obsolete."); if (color != -1) html->styleEngine->setNonCssHint (CSS_PROPERTY_BACKGROUND_COLOR, @@ -1850,7 +1867,7 @@ static void Html_tag_open_body(DilloHtml *html, const char *tag, int tagsize) color = a_Html_color_parse(html, attrbuf, -1); if (html->DocType == DT_HTML && html->DocTypeVersion >= 5.0f) - BUG_MSG("<body> text attribute is obsolete.\n"); + BUG_MSG("<body> text attribute is obsolete."); if (color != -1) html->styleEngine->setNonCssHint (CSS_PROPERTY_COLOR, @@ -1862,13 +1879,13 @@ static void Html_tag_open_body(DilloHtml *html, const char *tag, int tagsize) if ((attrbuf = a_Html_get_attr(html, tag, tagsize, "link"))) { html->non_css_link_color = a_Html_color_parse(html, attrbuf, -1); if (html->DocType == DT_HTML && html->DocTypeVersion >= 5.0f) - BUG_MSG("<body> link attribute is obsolete.\n"); + BUG_MSG("<body> link attribute is obsolete."); } if ((attrbuf = a_Html_get_attr(html, tag, tagsize, "vlink"))) { html->non_css_visited_color = a_Html_color_parse(html, attrbuf, -1); if (html->DocType == DT_HTML && html->DocTypeVersion >= 5.0f) - BUG_MSG("<body> vlink attribute is obsolete.\n"); + BUG_MSG("<body> vlink attribute is obsolete."); } html->dw->setStyle (html->style ()); @@ -2012,7 +2029,7 @@ static void Html_tag_content_frameset (DilloHtml *html, { HT2TB(html)->addParbreak (9, html->wordStyle ()); HT2TB(html)->addText("--FRAME--", html->wordStyle ()); - Html_add_textblock(html, 5); + Html_add_textblock(html, true, 5); } /* @@ -2089,8 +2106,8 @@ void a_Html_common_image_attrs(DilloHtml *html, const char *tag, int tagsize) { char *width_ptr, *height_ptr; const char *attrbuf; - CssLength l_w = CSS_CREATE_LENGTH(0.0, CSS_LENGTH_TYPE_AUTO); - CssLength l_h = CSS_CREATE_LENGTH(0.0, CSS_LENGTH_TYPE_AUTO); + CssLength l_w = CSS_CREATE_LENGTH(0.0, CSS_LENGTH_TYPE_AUTO); + CssLength l_h = CSS_CREATE_LENGTH(0.0, CSS_LENGTH_TYPE_AUTO); int w = 0, h = 0; if (prefs.show_tooltip && @@ -2123,7 +2140,7 @@ void a_Html_common_image_attrs(DilloHtml *html, const char *tag, int tagsize) */ if (w < 0 || h < 0 || w > IMAGE_MAX_AREA || h > IMAGE_MAX_AREA || - (h > 0 && w > IMAGE_MAX_AREA / h)) { + (h > 0 && w > IMAGE_MAX_AREA / h)) { dFree(width_ptr); dFree(height_ptr); width_ptr = height_ptr = NULL; @@ -2176,6 +2193,8 @@ DilloImage *a_Html_image_new(DilloHtml *html, const char *tag, int tagsize) dw::Image *dw = new dw::Image(alt_ptr); image = a_Image_new(html->dw->getLayout(), (void*)(dw::core::ImgRenderer*)dw, 0); + + a_Image_ref(image); if (HT2TB(html)->getBgColor()) image->bg_color = HT2TB(html)->getBgColor()->getColor(); @@ -2192,10 +2211,10 @@ DilloImage *a_Html_image_new(DilloHtml *html, const char *tag, int tagsize) if (load_now && Html_load_image(html->bw, url, html->page_url, image)) { // hi->image is NULL if dillo tries to load the image immediately hi->image = NULL; + a_Image_unref(image); } else { // otherwise a reference is kept in html->images hi->image = image; - a_Image_ref(image); } dFree(alt_ptr); @@ -2338,7 +2357,7 @@ static void Html_tag_content_map(DilloHtml *html, const char *tag, int tagsize) DilloUrl *url; if (html->InFlags & IN_MAP) { - BUG_MSG("nested <map>\n"); + BUG_MSG("Nested <map>."); } else { if ((attrbuf = a_Html_get_attr(html, tag, tagsize, "name"))) { html->InFlags |= IN_MAP; @@ -2348,7 +2367,7 @@ static void Html_tag_content_map(DilloHtml *html, const char *tag, int tagsize) a_Url_free (url); dFree(hash_name); } else { - BUG_MSG("name attribute is required for <map>\n"); + BUG_MSG("<map> requires name attribute."); } } } @@ -2400,7 +2419,7 @@ misc::SimpleVector<int> *Html_read_coords(DilloHtml *html, const char *str) if (!*newtail) break; if (*newtail != ',') { - BUG_MSG("area coords must be integers separated by commas.\n"); + BUG_MSG("<area> coords must be integers separated by commas."); } tail = newtail + 1; } @@ -2423,7 +2442,7 @@ static void Shape *shape = NULL; if (!(html->InFlags & IN_MAP)) { - BUG_MSG("<area> element not inside <map>\n"); + BUG_MSG("<area> not inside <map>."); return; } attrbuf = a_Html_get_attr(html, tag, tagsize, "shape"); @@ -2439,7 +2458,7 @@ static void } else if (dStrnAsciiCasecmp(attrbuf, "poly", 4) == 0) { type = POLYGON; } else { - BUG_MSG("<area> unknown shape: \"%s\"\n", attrbuf); + BUG_MSG("<area> unknown shape: '%s'.", attrbuf); type = UNKNOWN; } if (type == RECTANGLE || type == CIRCLE || type == POLYGON) { @@ -2449,7 +2468,7 @@ static void if (type == RECTANGLE) { if (coords->size() != 4) - BUG_MSG("<area> rectangle must have four coordinate values\n"); + BUG_MSG("<area> rectangle must have four coordinate values."); if (coords->size() >= 4) shape = new Rectangle(coords->get(0), coords->get(1), @@ -2457,7 +2476,7 @@ static void coords->get(3) - coords->get(1)); } else if (type == CIRCLE) { if (coords->size() != 3) - BUG_MSG("<area> circle must have three coordinate values\n"); + BUG_MSG("<area> circle must have three coordinate values."); if (coords->size() >= 3) shape = new Circle(coords->get(0), coords->get(1), coords->get(2)); @@ -2465,7 +2484,7 @@ static void Polygon *poly; int i; if (coords->size() % 2) - BUG_MSG("<area> polygon with odd number of coordinates\n"); + BUG_MSG("<area> polygon with odd number of coordinates."); shape = poly = new Polygon(); for (i = 0; i < (coords->size() / 2); i++) poly->addPoint(coords->get(2*i), coords->get(2*i + 1)); @@ -2601,11 +2620,11 @@ static void Html_tag_open_source(DilloHtml *html, const char *tag, const char *attrbuf; if (!(html->InFlags & IN_MEDIA)) { - BUG_MSG("<source> element not inside a media element.\n"); + BUG_MSG("<source> not inside a media element."); return; } if (!(attrbuf = a_Html_get_attr(html, tag, tagsize, "src"))) { - BUG_MSG("src attribute is required in <source> element.\n"); + BUG_MSG("<source> requires src attribute."); return; } else { DilloUrl *url = a_Html_url_new(html, attrbuf, NULL, 0); @@ -2682,7 +2701,7 @@ static const char* Html_get_javascript_link(DilloHtml *html) if ((ch == '"' || ch == '\'') && (p2 = strchr(Buf->str + i + 1 , ch))) { p1 = Buf->str + i; - BUG_MSG("link depends on javascript()\n"); + BUG_MSG("Link depends on javascript()."); dStr_truncate(Buf, p2 - Buf->str); dStr_erase(Buf, 0, p1 - Buf->str + 1); } @@ -2697,7 +2716,8 @@ static void Html_add_anchor(DilloHtml *html, const char *name) { _MSG("Registering ANCHOR: %s\n", name); if (!HT2TB(html)->addAnchor (name, html->style ())) - BUG_MSG("Anchor names must be unique within the document ('%s')\n",name); + BUG_MSG("Anchor names must be unique within the document (\"%s\").", + name); /* * According to Sec. 12.2.1 of the HTML 4.01 spec, "anchor names that * differ only in case may not appear in the same document", but @@ -2767,7 +2787,8 @@ static void Html_tag_open_a(DilloHtml *html, const char *tag, int tagsize) /* We compare the "id" value with the url-decoded "name" value */ if (!id || strcmp(nameVal, id)) { if (id) - BUG_MSG("'id' and 'name' attribute of <a> tag differ\n"); + BUG_MSG("In <a>, id ('%s') and name ('%s') attributes differ.", + id, nameVal); Html_add_anchor(html, nameVal); } @@ -2790,7 +2811,7 @@ static void Html_tag_close_a(DilloHtml *html) static void Html_tag_open_blockquote(DilloHtml *html, const char *tag, int tagsize) { - Html_add_textblock(html, 9); + Html_add_textblock(html, true, 9); } /* @@ -2843,7 +2864,7 @@ static void Html_tag_open_ul(DilloHtml *html, const char *tag, int tagsize) html->styleEngine->setNonCssHint (CSS_PROPERTY_LIST_STYLE_TYPE, CSS_TYPE_ENUM, list_style_type); if (html->DocType == DT_HTML && html->DocTypeVersion >= 5.0f) - BUG_MSG("<ul> type attribute is obsolete.\n"); + BUG_MSG("<ul> type attribute is obsolete."); } S_TOP(html)->list_type = HTML_LIST_UNORDERED; @@ -2865,7 +2886,7 @@ static void Html_tag_open_dir(DilloHtml *html, const char *tag, int tagsize) S_TOP(html)->ref_list_item = NULL; if (prefs.show_extra_warnings) - BUG_MSG("Obsolete list type; use <UL> instead\n"); + BUG_MSG("Obsolete list type; use <ul> instead."); } /* @@ -2873,7 +2894,16 @@ static void Html_tag_open_dir(DilloHtml *html, const char *tag, int tagsize) */ static void Html_tag_open_menu(DilloHtml *html, const char *tag, int tagsize) { - Html_tag_open_dir(html, tag, tagsize); + /* In another bit of ridiculous mess from the HTML5 world, the menu + * element, which was deprecated in HTML4: + * - does not appear at all in W3C's HTML5 spec + * - appears in WHATWG's HTML5 doc and the W3C's 5.1 draft, where it + * means something totally different than it did in the old days + * (now it's for popup menus and toolbar menus rather than being a + * sort of list). + */ + if (!(html->DocType == DT_HTML && html->DocTypeVersion >= 5.0f)) + Html_tag_open_dir(html, tag, tagsize); } /* @@ -2906,7 +2936,7 @@ static void Html_tag_open_ol(DilloHtml *html, const char *tag, int tagsize) if ((attrbuf = a_Html_get_attr(html, tag, tagsize, "start")) && (n = (int) strtol(attrbuf, NULL, 10)) < 0) { - BUG_MSG( "illegal '-' character in START attribute; Starting from 0\n"); + BUG_MSG("Illegal '-' character in START attribute; Starting from 0."); n = 0; } S_TOP(html)->list_number = n; @@ -2923,7 +2953,7 @@ static void Html_tag_open_li(DilloHtml *html, const char *tag, int tagsize) const char *attrbuf; if (S_TOP(html)->list_type == HTML_LIST_NONE) - BUG_MSG("<li> outside <ul> or <ol>\n"); + BUG_MSG("<li> outside <ul> or <ol>."); html->InFlags |= IN_LI; @@ -2934,7 +2964,7 @@ static void Html_tag_open_li(DilloHtml *html, const char *tag, int tagsize) // ordered if ((attrbuf = a_Html_get_attr(html, tag, tagsize, "value")) && (*list_number = strtol(attrbuf, NULL, 10)) < 0) { - BUG_MSG("illegal negative LIST VALUE attribute; Starting from 0\n"); + BUG_MSG("Illegal negative list value attribute; Starting from 0."); *list_number = 0; } } @@ -2961,7 +2991,7 @@ static void Html_tag_open_hr(DilloHtml *html, const char *tag, int tagsize) width_ptr = a_Html_get_attr_wdef(html, tag, tagsize, "width", NULL); if (width_ptr) { if (html->DocType == DT_HTML && html->DocTypeVersion >= 5.0f) - BUG_MSG("<hr> width attribute is obsolete.\n"); + BUG_MSG("<hr> width attribute is obsolete."); html->styleEngine->setNonCssHint (CSS_PROPERTY_WIDTH, CSS_TYPE_LENGTH_PERCENTAGE, a_Html_parse_length (html, width_ptr)); @@ -2971,7 +3001,7 @@ static void Html_tag_open_hr(DilloHtml *html, const char *tag, int tagsize) if ((attrbuf = a_Html_get_attr(html, tag, tagsize, "size"))) { size = strtol(attrbuf, NULL, 10); if (html->DocType == DT_HTML && html->DocTypeVersion >= 5.0f) - BUG_MSG("<hr> size attribute is obsolete.\n"); + BUG_MSG("<hr> size attribute is obsolete."); } a_Html_tag_set_align_attr(html, tag, tagsize); @@ -2979,7 +3009,7 @@ static void Html_tag_open_hr(DilloHtml *html, const char *tag, int tagsize) /* TODO: evaluate attribute */ if (a_Html_get_attr(html, tag, tagsize, "noshade")) { if (html->DocType == DT_HTML && html->DocTypeVersion >= 5.0f) - BUG_MSG("<hr> noshade attribute is obsolete.\n"); + BUG_MSG("<hr> noshade attribute is obsolete."); html->styleEngine->setNonCssHint (CSS_PROPERTY_BORDER_TOP_STYLE, CSS_TYPE_ENUM, BORDER_SOLID); html->styleEngine->setNonCssHint (CSS_PROPERTY_BORDER_BOTTOM_STYLE, @@ -3045,7 +3075,7 @@ static void Html_tag_open_dt(DilloHtml *html, const char *tag, int tagsize) */ static void Html_tag_open_dd(DilloHtml *html, const char *tag, int tagsize) { - Html_add_textblock(html, 9); + Html_add_textblock(html, true, 9); } /* @@ -3134,7 +3164,7 @@ static void Html_tag_open_meta(DilloHtml *html, const char *tag, int tagsize) /* only valid inside HEAD */ if (!(html->InFlags & IN_HEAD)) { - BUG_MSG("META element must be inside the HEAD section\n"); + BUG_MSG("<meta> must be inside the HEAD section."); return; } @@ -3167,7 +3197,7 @@ static void Html_tag_open_meta(DilloHtml *html, const char *tag, int tagsize) if (a_Url_cmp(html->base_url, new_url) == 0) { /* redirection loop, or empty url string: ignore */ - BUG_MSG("META refresh: %s\n", + BUG_MSG("<meta> refresh: %s.", *mr_url ? "redirection loop" : "no target URL"); } else if (delay == 0) { /* zero-delay redirection */ @@ -3237,27 +3267,26 @@ void a_Html_load_stylesheet(DilloHtml *html, DilloUrl *url) dReturn_if (url == NULL || ! prefs.load_stylesheets); _MSG("Html_load_stylesheet: "); - if (a_Capi_get_buf(url, &data, &len)) { + if ((a_Capi_get_flags_with_redirection(url) & CAPI_Completed) && + a_Capi_get_buf(url, &data, &len)) { _MSG("cached URL=%s len=%d", URL_STR(url), len); - if (a_Capi_get_flags_with_redirection(url) & CAPI_Completed) { - if (strncmp("@charset \"", data, 10) == 0) { - char *endq = strchr(data+10, '"'); - - if (endq && (endq - data <= 51)) { - /* IANA limits charset names to 40 characters */ - char *content_type; - - *endq = '\0'; - content_type = dStrconcat("text/css; charset=", data+10, NULL); - *endq = '"'; - a_Capi_unref_buf(url); - a_Capi_set_content_type(url, content_type, "meta"); - dFree(content_type); - a_Capi_get_buf(url, &data, &len); - } + if (strncmp("@charset \"", data, 10) == 0) { + char *endq = strchr(data+10, '"'); + + if (endq && (endq - data <= 51)) { + /* IANA limits charset names to 40 characters */ + char *content_type; + + *endq = '\0'; + content_type = dStrconcat("text/css; charset=", data+10, NULL); + *endq = '"'; + a_Capi_unref_buf(url); + a_Capi_set_content_type(url, content_type, "meta"); + dFree(content_type); + a_Capi_get_buf(url, &data, &len); } - html->styleEngine->parse(html, url, data, len, CSS_ORIGIN_AUTHOR); } + html->styleEngine->parse(html, url, data, len, CSS_ORIGIN_AUTHOR); a_Capi_unref_buf(url); } else { /* Fill a Web structure for the cache query */ @@ -3296,7 +3325,7 @@ static void Html_tag_open_link(DilloHtml *html, const char *tag, int tagsize) /* Ignore LINK outside HEAD */ if (!(html->InFlags & IN_HEAD)) { - BUG_MSG("LINK element must be inside the HEAD section\n"); + BUG_MSG("<link> must be inside the HEAD section."); return; } /* Remote stylesheets enabled? */ @@ -3341,12 +3370,12 @@ static void Html_tag_open_base(DilloHtml *html, const char *tag, int tagsize) a_Url_free(html->base_url); html->base_url = BaseUrl; } else { - BUG_MSG("base URI is relative (it MUST be absolute)\n"); + BUG_MSG("<base> URI is relative (it MUST be absolute)."); a_Url_free(BaseUrl); } } } else { - BUG_MSG("the BASE element must appear in the HEAD section\n"); + BUG_MSG("<base> not inside HEAD section."); } } @@ -3635,10 +3664,10 @@ static int Html_needs_optional_close(int old_idx, int cur_idx) } else if (old_idx == i_TR) { /* TR closes TR */ return (cur_idx == i_TR); - } else if (old_idx == i_DD) { + } else if (old_idx == i_DD) { /* DD is closed by DD and DT */ return (cur_idx == i_DD || cur_idx == i_DT); - } else if (old_idx == i_OPTION) { + } else if (old_idx == i_OPTION) { return 1; // OPTION always needs close } @@ -3684,7 +3713,7 @@ static void Html_stack_cleanup_at_open(DilloHtml *html, int new_idx) /* we have an inline (or empty) container... */ if (Tags[oldtag_idx].EndTag == 'R') { - BUG_MSG("<%s> is not allowed to contain <%s>. -- closing <%s>\n", + BUG_MSG("<%s> is not allowed to contain <%s>. -- closing <%s>.", Tags[oldtag_idx].name, Tags[new_idx].name, Tags[oldtag_idx].name); } @@ -3713,7 +3742,7 @@ static void Html_test_section(DilloHtml *html, int new_idx, int IsCloseTag) int tag_idx; if (!(html->InFlags & IN_HTML) && html->DocType == DT_NONE) - BUG_MSG("the required DOCTYPE declaration is missing.\n"); + BUG_MSG("The required DOCTYPE declaration is missing."); if (!(html->InFlags & IN_HTML)) { tag = "<html>"; @@ -3763,6 +3792,7 @@ static void Html_test_section(DilloHtml *html, int new_idx, int IsCloseTag) static void Html_parse_common_attrs(DilloHtml *html, char *tag, int tagsize) { const char *attrbuf; + char lang[3]; if (tagsize >= 8 && /* length of "<t id=i>" */ (attrbuf = a_Html_get_attr(html, tag, tagsize, "id"))) { @@ -3788,24 +3818,25 @@ static void Html_parse_common_attrs(DilloHtml *html, char *tag, int tagsize) html->styleEngine->setStyle (attrbuf); } - /* handle "xml:lang" and "lang" attributes */ - int hasXmlLang = 0; + /* handle "xml:lang" and "lang" attributes + * We use only the first two chars of the value to deal with + * extended language tags (see http://www.rfc-editor.org/rfc/bcp/bcp47.txt) + */ + memset(lang, 0, sizeof(lang)); if (tagsize >= 14) { /* length of "<t xml:lang=i>" */ attrbuf = a_Html_get_attr(html, tag, tagsize, "xml:lang"); - if (attrbuf) { - html->styleEngine->setNonCssHint(PROPERTY_X_LANG, CSS_TYPE_STRING, - attrbuf); - hasXmlLang = 1; - } + if (attrbuf) + strncpy(lang, attrbuf, 2); } - if (!hasXmlLang && tagsize >= 10) { /* 'xml:lang' prevails over 'lang' */ + if (!lang[0] && tagsize >= 10) { /* 'xml:lang' prevails over 'lang' */ /* length of "<t lang=i>" */ attrbuf = a_Html_get_attr(html, tag, tagsize, "lang"); if (attrbuf) - html->styleEngine->setNonCssHint(PROPERTY_X_LANG, CSS_TYPE_STRING, - attrbuf); + strncpy(lang, attrbuf, 2); } + if (lang[0]) + html->styleEngine->setNonCssHint(PROPERTY_X_LANG, CSS_TYPE_STRING, lang); } /* @@ -3829,7 +3860,7 @@ static void Html_check_html5_obsolete(DilloHtml *html, int ni) } for (int i = 0; i < 9; i++) { if (indexes[i] == ni) { - BUG_MSG("<%s> is obsolete in HTML5.\n", Tags[ni].name); + BUG_MSG("<%s> is obsolete in HTML5.", Tags[ni].name); break; } } @@ -3837,8 +3868,12 @@ static void Html_check_html5_obsolete(DilloHtml *html, int ni) static void Html_display_block(DilloHtml *html) { - //HT2TB(html)->addParbreak (5, html->styleEngine->wordStyle ()); - Html_add_textblock(html, 0); + Html_add_textblock(html, !Html_will_textblock_be_out_of_flow (html), 0); +} + +static void Html_display_inline_block(DilloHtml *html) +{ + Html_add_textblock(html, false, 0); } static void Html_display_listitem(DilloHtml *html) @@ -3919,7 +3954,7 @@ static void Html_process_tag(DilloHtml *html, char *tag, int tagsize) /* TODO: this is only raising a warning, take some defined action. * Note: apache uses IMG inside PRE (we could use its "alt"). */ if ((html->InFlags & IN_PRE) && Html_tag_pre_excludes(ni)) - BUG_MSG("<pre> is not allowed to contain <%s>\n", Tags[ni].name); + BUG_MSG("<pre> is not allowed to contain <%s>.", Tags[ni].name); /* Make sure these elements don't nest each other */ if (html->InFlags & (IN_BUTTON | IN_SELECT | IN_TEXTAREA)) @@ -3943,6 +3978,9 @@ static void Html_process_tag(DilloHtml *html, char *tag, int tagsize) case DISPLAY_BLOCK: Html_display_block(html); break; + case DISPLAY_INLINE_BLOCK: + Html_display_inline_block(html); + break; case DISPLAY_LIST_ITEM: Html_display_listitem(html); break; @@ -3950,7 +3988,6 @@ static void Html_process_tag(DilloHtml *html, char *tag, int tagsize) S_TOP(html)->display_none = true; break; case DISPLAY_INLINE: - case DISPLAY_INLINE_BLOCK: // TODO: implement inline-block default: break; } @@ -4018,7 +4055,7 @@ static const char *Html_get_attr2(DilloHtml *html, const char *attrname, int tag_parsing_flags) { - int i, isocode, entsize, Found = 0, delimiter = 0, attr_pos = 0; + int i, entsize, Found = 0, delimiter = 0, attr_pos = 0; Dstr *Buf = html->attr_data; DilloHtmlTagParsingState state = SEEK_ATTR_START; @@ -4077,16 +4114,12 @@ static const char *Html_get_attr2(DilloHtml *html, state = FINISHED; } else if (tag[i] == '&' && (tag_parsing_flags & HTML_ParseEntities)) { - if ((isocode = Html_parse_entity(html, tag+i, - tagsize-i, &entsize)) >= 0) { - if (isocode >= 128) { - char buf[4]; - int k, n = a_Utf8_encode(isocode, buf); - for (k = 0; k < n; ++k) - dStr_append_c(Buf, buf[k]); - } else { - dStr_append_c(Buf, (char) isocode); - } + const char *entstr; + const bool_t is_attr = TRUE; + + if ((entstr = Html_parse_entity(html, tag+i, tagsize-i, &entsize, + is_attr))) { + dStr_append(Buf, entstr); i += entsize-1; } else { dStr_append_c(Buf, tag[i]); @@ -4228,7 +4261,7 @@ static int Html_write_raw(DilloHtml *html, char *buf, int bufsize, int Eof) buf_index = bufsize; } else { /* Tag: search end of tag (skipping over quoted strings) */ - html->CurrTagOfs = html->Start_Ofs + token_start; + html->CurrOfs = html->Start_Ofs + token_start; while ( buf_index < bufsize ) { buf_index++; @@ -4249,7 +4282,7 @@ static int Html_write_raw(DilloHtml *html, char *buf, int bufsize, int Eof) if (buf[offset] == ch || !buf[offset]) { buf_index = offset; } else { - BUG_MSG("attribute lacks closing quote\n"); + BUG_MSG("Attribute lacks closing quote."); break; } } @@ -4257,7 +4290,7 @@ static int Html_write_raw(DilloHtml *html, char *buf, int bufsize, int Eof) /* unterminated tag detected */ p = dStrndup(buf+token_start+1, strcspn(buf+token_start+1, " <\n\r\t")); - BUG_MSG("<%s> element lacks its closing '>'\n", p); + BUG_MSG("<%s> lacks its closing '>'.", p); dFree(p); --buf_index; break; @@ -4272,6 +4305,8 @@ static int Html_write_raw(DilloHtml *html, char *buf, int bufsize, int Eof) } } else { /* A Word: search for whitespace or tag open */ + html->CurrOfs = html->Start_Ofs + token_start; + while (++buf_index < bufsize) { buf_index += strcspn(buf + buf_index, " <\n\r\t\f\v"); if (buf[buf_index] == '<' && (ch = buf[buf_index + 1]) && diff --git a/src/html_charrefs.h b/src/html_charrefs.h new file mode 100644 index 00000000..38f3849f --- /dev/null +++ b/src/html_charrefs.h @@ -0,0 +1,2138 @@ +#ifndef HTML_CHARREFS_H +#define HTML_CHARREFS_H + +typedef struct { + const char *ref; + const char *html5_str; + const char *html4_str; +} Charref_t; + +#define NumRef 2125 +static const Charref_t Charrefs[NumRef] = { +{"AElig", "Æ", "Æ"}, +{"AMP", "&", NULL}, +{"Aacute", "Á", "Á"}, +{"Abreve", "Ă", NULL}, +{"Acirc", "Â", "Â"}, +{"Acy", "А", NULL}, +{"Afr", "𝔄", NULL}, +{"Agrave", "À", "À"}, +{"Alpha", "Α", "Α"}, +{"Amacr", "Ā", NULL}, +{"And", "⩓", NULL}, +{"Aogon", "Ą", NULL}, +{"Aopf", "𝔸", NULL}, +{"ApplyFunction", "", NULL}, +{"Aring", "Å", "Å"}, +{"Ascr", "𝒜", NULL}, +{"Assign", "≔", NULL}, +{"Atilde", "Ã", "Ã"}, +{"Auml", "Ä", "Ä"}, +{"Backslash", "∖", NULL}, +{"Barv", "⫧", NULL}, +{"Barwed", "⌆", NULL}, +{"Bcy", "Б", NULL}, +{"Because", "∵", NULL}, +{"Bernoullis", "ℬ", NULL}, +{"Beta", "Β", "Β"}, +{"Bfr", "𝔅", NULL}, +{"Bopf", "𝔹", NULL}, +{"Breve", "˘", NULL}, +{"Bscr", "ℬ", NULL}, +{"Bumpeq", "≎", NULL}, +{"CHcy", "Ч", NULL}, +{"COPY", "©", NULL}, +{"Cacute", "Ć", NULL}, +{"Cap", "⋒", NULL}, +{"CapitalDifferentialD", "ⅅ", NULL}, +{"Cayleys", "ℭ", NULL}, +{"Ccaron", "Č", NULL}, +{"Ccedil", "Ç", "Ç"}, +{"Ccirc", "Ĉ", NULL}, +{"Cconint", "∰", NULL}, +{"Cdot", "Ċ", NULL}, +{"Cedilla", "¸", NULL}, +{"CenterDot", "·", NULL}, +{"Cfr", "ℭ", NULL}, +{"Chi", "Χ", "Χ"}, +{"CircleDot", "⊙", NULL}, +{"CircleMinus", "⊖", NULL}, +{"CirclePlus", "⊕", NULL}, +{"CircleTimes", "⊗", NULL}, +{"ClockwiseContourIntegral", "∲", NULL}, +{"CloseCurlyDoubleQuote", "”", NULL}, +{"CloseCurlyQuote", "’", NULL}, +{"Colon", "∷", NULL}, +{"Colone", "⩴", NULL}, +{"Congruent", "≡", NULL}, +{"Conint", "∯", NULL}, +{"ContourIntegral", "∮", NULL}, +{"Copf", "ℂ", NULL}, +{"Coproduct", "∐", NULL}, +{"CounterClockwiseContourIntegral", "∳", NULL}, +{"Cross", "⨯", NULL}, +{"Cscr", "𝒞", NULL}, +{"Cup", "⋓", NULL}, +{"CupCap", "≍", NULL}, +{"DD", "ⅅ", NULL}, +{"DDotrahd", "⤑", NULL}, +{"DJcy", "Ђ", NULL}, +{"DScy", "Ѕ", NULL}, +{"DZcy", "Џ", NULL}, +{"Dagger", "‡", "‡"}, +{"Darr", "↡", NULL}, +{"Dashv", "⫤", NULL}, +{"Dcaron", "Ď", NULL}, +{"Dcy", "Д", NULL}, +{"Del", "∇", NULL}, +{"Delta", "Δ", "Δ"}, +{"Dfr", "𝔇", NULL}, +{"DiacriticalAcute", "´", NULL}, +{"DiacriticalDot", "˙", NULL}, +{"DiacriticalDoubleAcute", "˝", NULL}, +{"DiacriticalGrave", "`", NULL}, +{"DiacriticalTilde", "˜", NULL}, +{"Diamond", "⋄", NULL}, +{"DifferentialD", "ⅆ", NULL}, +{"Dopf", "𝔻", NULL}, +{"Dot", "¨", NULL}, +{"DotDot", "⃜", NULL}, +{"DotEqual", "≐", NULL}, +{"DoubleContourIntegral", "∯", NULL}, +{"DoubleDot", "¨", NULL}, +{"DoubleDownArrow", "⇓", NULL}, +{"DoubleLeftArrow", "⇐", NULL}, +{"DoubleLeftRightArrow", "⇔", NULL}, +{"DoubleLeftTee", "⫤", NULL}, +{"DoubleLongLeftArrow", "⟸", NULL}, +{"DoubleLongLeftRightArrow", "⟺", NULL}, +{"DoubleLongRightArrow", "⟹", NULL}, +{"DoubleRightArrow", "⇒", NULL}, +{"DoubleRightTee", "⊨", NULL}, +{"DoubleUpArrow", "⇑", NULL}, +{"DoubleUpDownArrow", "⇕", NULL}, +{"DoubleVerticalBar", "∥", NULL}, +{"DownArrow", "↓", NULL}, +{"DownArrowBar", "⤓", NULL}, +{"DownArrowUpArrow", "⇵", NULL}, +{"DownBreve", "̑", NULL}, +{"DownLeftRightVector", "⥐", NULL}, +{"DownLeftTeeVector", "⥞", NULL}, +{"DownLeftVector", "↽", NULL}, +{"DownLeftVectorBar", "⥖", NULL}, +{"DownRightTeeVector", "⥟", NULL}, +{"DownRightVector", "⇁", NULL}, +{"DownRightVectorBar", "⥗", NULL}, +{"DownTee", "⊤", NULL}, +{"DownTeeArrow", "↧", NULL}, +{"Downarrow", "⇓", NULL}, +{"Dscr", "𝒟", NULL}, +{"Dstrok", "Đ", NULL}, +{"ENG", "Ŋ", NULL}, +{"ETH", "Ð", "Ð"}, +{"Eacute", "É", "É"}, +{"Ecaron", "Ě", NULL}, +{"Ecirc", "Ê", "Ê"}, +{"Ecy", "Э", NULL}, +{"Edot", "Ė", NULL}, +{"Efr", "𝔈", NULL}, +{"Egrave", "È", "È"}, +{"Element", "∈", NULL}, +{"Emacr", "Ē", NULL}, +{"EmptySmallSquare", "◻", NULL}, +{"EmptyVerySmallSquare", "▫", NULL}, +{"Eogon", "Ę", NULL}, +{"Eopf", "𝔼", NULL}, +{"Epsilon", "Ε", "Ε"}, +{"Equal", "⩵", NULL}, +{"EqualTilde", "≂", NULL}, +{"Equilibrium", "⇌", NULL}, +{"Escr", "ℰ", NULL}, +{"Esim", "⩳", NULL}, +{"Eta", "Η", "Η"}, +{"Euml", "Ë", "Ë"}, +{"Exists", "∃", NULL}, +{"ExponentialE", "ⅇ", NULL}, +{"Fcy", "Ф", NULL}, +{"Ffr", "𝔉", NULL}, +{"FilledSmallSquare", "◼", NULL}, +{"FilledVerySmallSquare", "▪", NULL}, +{"Fopf", "𝔽", NULL}, +{"ForAll", "∀", NULL}, +{"Fouriertrf", "ℱ", NULL}, +{"Fscr", "ℱ", NULL}, +{"GJcy", "Ѓ", NULL}, +{"GT", ">", NULL}, +{"Gamma", "Γ", "Γ"}, +{"Gammad", "Ϝ", NULL}, +{"Gbreve", "Ğ", NULL}, +{"Gcedil", "Ģ", NULL}, +{"Gcirc", "Ĝ", NULL}, +{"Gcy", "Г", NULL}, +{"Gdot", "Ġ", NULL}, +{"Gfr", "𝔊", NULL}, +{"Gg", "⋙", NULL}, +{"Gopf", "𝔾", NULL}, +{"GreaterEqual", "≥", NULL}, +{"GreaterEqualLess", "⋛", NULL}, +{"GreaterFullEqual", "≧", NULL}, +{"GreaterGreater", "⪢", NULL}, +{"GreaterLess", "≷", NULL}, +{"GreaterSlantEqual", "⩾", NULL}, +{"GreaterTilde", "≳", NULL}, +{"Gscr", "𝒢", NULL}, +{"Gt", "≫", NULL}, +{"HARDcy", "Ъ", NULL}, +{"Hacek", "ˇ", NULL}, +{"Hat", "^", NULL}, +{"Hcirc", "Ĥ", NULL}, +{"Hfr", "ℌ", NULL}, +{"HilbertSpace", "ℋ", NULL}, +{"Hopf", "ℍ", NULL}, +{"HorizontalLine", "─", NULL}, +{"Hscr", "ℋ", NULL}, +{"Hstrok", "Ħ", NULL}, +{"HumpDownHump", "≎", NULL}, +{"HumpEqual", "≏", NULL}, +{"IEcy", "Е", NULL}, +{"IJlig", "IJ", NULL}, +{"IOcy", "Ё", NULL}, +{"Iacute", "Í", "Í"}, +{"Icirc", "Î", "Î"}, +{"Icy", "И", NULL}, +{"Idot", "İ", NULL}, +{"Ifr", "ℑ", NULL}, +{"Igrave", "Ì", "Ì"}, +{"Im", "ℑ", NULL}, +{"Imacr", "Ī", NULL}, +{"ImaginaryI", "ⅈ", NULL}, +{"Implies", "⇒", NULL}, +{"Int", "∬", NULL}, +{"Integral", "∫", NULL}, +{"Intersection", "⋂", NULL}, +{"InvisibleComma", "", NULL}, +{"InvisibleTimes", "", NULL}, +{"Iogon", "Į", NULL}, +{"Iopf", "𝕀", NULL}, +{"Iota", "Ι", "Ι"}, +{"Iscr", "ℐ", NULL}, +{"Itilde", "Ĩ", NULL}, +{"Iukcy", "І", NULL}, +{"Iuml", "Ï", "Ï"}, +{"Jcirc", "Ĵ", NULL}, +{"Jcy", "Й", NULL}, +{"Jfr", "𝔍", NULL}, +{"Jopf", "𝕁", NULL}, +{"Jscr", "𝒥", NULL}, +{"Jsercy", "Ј", NULL}, +{"Jukcy", "Є", NULL}, +{"KHcy", "Х", NULL}, +{"KJcy", "Ќ", NULL}, +{"Kappa", "Κ", "Κ"}, +{"Kcedil", "Ķ", NULL}, +{"Kcy", "К", NULL}, +{"Kfr", "𝔎", NULL}, +{"Kopf", "𝕂", NULL}, +{"Kscr", "𝒦", NULL}, +{"LJcy", "Љ", NULL}, +{"LT", "<", NULL}, +{"Lacute", "Ĺ", NULL}, +{"Lambda", "Λ", "Λ"}, +{"Lang", "⟪", NULL}, +{"Laplacetrf", "ℒ", NULL}, +{"Larr", "↞", NULL}, +{"Lcaron", "Ľ", NULL}, +{"Lcedil", "Ļ", NULL}, +{"Lcy", "Л", NULL}, +{"LeftAngleBracket", "⟨", NULL}, +{"LeftArrow", "←", NULL}, +{"LeftArrowBar", "⇤", NULL}, +{"LeftArrowRightArrow", "⇆", NULL}, +{"LeftCeiling", "⌈", NULL}, +{"LeftDoubleBracket", "⟦", NULL}, +{"LeftDownTeeVector", "⥡", NULL}, +{"LeftDownVector", "⇃", NULL}, +{"LeftDownVectorBar", "⥙", NULL}, +{"LeftFloor", "⌊", NULL}, +{"LeftRightArrow", "↔", NULL}, +{"LeftRightVector", "⥎", NULL}, +{"LeftTee", "⊣", NULL}, +{"LeftTeeArrow", "↤", NULL}, +{"LeftTeeVector", "⥚", NULL}, +{"LeftTriangle", "⊲", NULL}, +{"LeftTriangleBar", "⧏", NULL}, +{"LeftTriangleEqual", "⊴", NULL}, +{"LeftUpDownVector", "⥑", NULL}, +{"LeftUpTeeVector", "⥠", NULL}, +{"LeftUpVector", "↿", NULL}, +{"LeftUpVectorBar", "⥘", NULL}, +{"LeftVector", "↼", NULL}, +{"LeftVectorBar", "⥒", NULL}, +{"Leftarrow", "⇐", NULL}, +{"Leftrightarrow", "⇔", NULL}, +{"LessEqualGreater", "⋚", NULL}, +{"LessFullEqual", "≦", NULL}, +{"LessGreater", "≶", NULL}, +{"LessLess", "⪡", NULL}, +{"LessSlantEqual", "⩽", NULL}, +{"LessTilde", "≲", NULL}, +{"Lfr", "𝔏", NULL}, +{"Ll", "⋘", NULL}, +{"Lleftarrow", "⇚", NULL}, +{"Lmidot", "Ŀ", NULL}, +{"LongLeftArrow", "⟵", NULL}, +{"LongLeftRightArrow", "⟷", NULL}, +{"LongRightArrow", "⟶", NULL}, +{"Longleftarrow", "⟸", NULL}, +{"Longleftrightarrow", "⟺", NULL}, +{"Longrightarrow", "⟹", NULL}, +{"Lopf", "𝕃", NULL}, +{"LowerLeftArrow", "↙", NULL}, +{"LowerRightArrow", "↘", NULL}, +{"Lscr", "ℒ", NULL}, +{"Lsh", "↰", NULL}, +{"Lstrok", "Ł", NULL}, +{"Lt", "≪", NULL}, +{"Map", "⤅", NULL}, +{"Mcy", "М", NULL}, +{"MediumSpace", " ", NULL}, +{"Mellintrf", "ℳ", NULL}, +{"Mfr", "𝔐", NULL}, +{"MinusPlus", "∓", NULL}, +{"Mopf", "𝕄", NULL}, +{"Mscr", "ℳ", NULL}, +{"Mu", "Μ", "Μ"}, +{"NJcy", "Њ", NULL}, +{"Nacute", "Ń", NULL}, +{"Ncaron", "Ň", NULL}, +{"Ncedil", "Ņ", NULL}, +{"Ncy", "Н", NULL}, +{"NegativeMediumSpace", "", NULL}, +{"NegativeThickSpace", "", NULL}, +{"NegativeThinSpace", "", NULL}, +{"NegativeVeryThinSpace", "", NULL}, +{"NestedGreaterGreater", "≫", NULL}, +{"NestedLessLess", "≪", NULL}, +{"NewLine", "\n", NULL}, +{"Nfr", "𝔑", NULL}, +{"NoBreak", "", NULL}, +{"NonBreakingSpace", " ", NULL}, +{"Nopf", "ℕ", NULL}, +{"Not", "⫬", NULL}, +{"NotCongruent", "≢", NULL}, +{"NotCupCap", "≭", NULL}, +{"NotDoubleVerticalBar", "∦", NULL}, +{"NotElement", "∉", NULL}, +{"NotEqual", "≠", NULL}, +{"NotEqualTilde", "≂̸", NULL}, +{"NotExists", "∄", NULL}, +{"NotGreater", "≯", NULL}, +{"NotGreaterEqual", "≱", NULL}, +{"NotGreaterFullEqual", "≧̸", NULL}, +{"NotGreaterGreater", "≫̸", NULL}, +{"NotGreaterLess", "≹", NULL}, +{"NotGreaterSlantEqual", "⩾̸", NULL}, +{"NotGreaterTilde", "≵", NULL}, +{"NotHumpDownHump", "≎̸", NULL}, +{"NotHumpEqual", "≏̸", NULL}, +{"NotLeftTriangle", "⋪", NULL}, +{"NotLeftTriangleBar", "⧏̸", NULL}, +{"NotLeftTriangleEqual", "⋬", NULL}, +{"NotLess", "≮", NULL}, +{"NotLessEqual", "≰", NULL}, +{"NotLessGreater", "≸", NULL}, +{"NotLessLess", "≪̸", NULL}, +{"NotLessSlantEqual", "⩽̸", NULL}, +{"NotLessTilde", "≴", NULL}, +{"NotNestedGreaterGreater", "⪢̸", NULL}, +{"NotNestedLessLess", "⪡̸", NULL}, +{"NotPrecedes", "⊀", NULL}, +{"NotPrecedesEqual", "⪯̸", NULL}, +{"NotPrecedesSlantEqual", "⋠", NULL}, +{"NotReverseElement", "∌", NULL}, +{"NotRightTriangle", "⋫", NULL}, +{"NotRightTriangleBar", "⧐̸", NULL}, +{"NotRightTriangleEqual", "⋭", NULL}, +{"NotSquareSubset", "⊏̸", NULL}, +{"NotSquareSubsetEqual", "⋢", NULL}, +{"NotSquareSuperset", "⊐̸", NULL}, +{"NotSquareSupersetEqual", "⋣", NULL}, +{"NotSubset", "⊂⃒", NULL}, +{"NotSubsetEqual", "⊈", NULL}, +{"NotSucceeds", "⊁", NULL}, +{"NotSucceedsEqual", "⪰̸", NULL}, +{"NotSucceedsSlantEqual", "⋡", NULL}, +{"NotSucceedsTilde", "≿̸", NULL}, +{"NotSuperset", "⊃⃒", NULL}, +{"NotSupersetEqual", "⊉", NULL}, +{"NotTilde", "≁", NULL}, +{"NotTildeEqual", "≄", NULL}, +{"NotTildeFullEqual", "≇", NULL}, +{"NotTildeTilde", "≉", NULL}, +{"NotVerticalBar", "∤", NULL}, +{"Nscr", "𝒩", NULL}, +{"Ntilde", "Ñ", "Ñ"}, +{"Nu", "Ν", "Ν"}, +{"OElig", "Œ", "Œ"}, +{"Oacute", "Ó", "Ó"}, +{"Ocirc", "Ô", "Ô"}, +{"Ocy", "О", NULL}, +{"Odblac", "Ő", NULL}, +{"Ofr", "𝔒", NULL}, +{"Ograve", "Ò", "Ò"}, +{"Omacr", "Ō", NULL}, +{"Omega", "Ω", "Ω"}, +{"Omicron", "Ο", "Ο"}, +{"Oopf", "𝕆", NULL}, +{"OpenCurlyDoubleQuote", "“", NULL}, +{"OpenCurlyQuote", "‘", NULL}, +{"Or", "⩔", NULL}, +{"Oscr", "𝒪", NULL}, +{"Oslash", "Ø", "Ø"}, +{"Otilde", "Õ", "Õ"}, +{"Otimes", "⨷", NULL}, +{"Ouml", "Ö", "Ö"}, +{"OverBar", "‾", NULL}, +{"OverBrace", "⏞", NULL}, +{"OverBracket", "⎴", NULL}, +{"OverParenthesis", "⏜", NULL}, +{"PartialD", "∂", NULL}, +{"Pcy", "П", NULL}, +{"Pfr", "𝔓", NULL}, +{"Phi", "Φ", "Φ"}, +{"Pi", "Π", "Π"}, +{"PlusMinus", "±", NULL}, +{"Poincareplane", "ℌ", NULL}, +{"Popf", "ℙ", NULL}, +{"Pr", "⪻", NULL}, +{"Precedes", "≺", NULL}, +{"PrecedesEqual", "⪯", NULL}, +{"PrecedesSlantEqual", "≼", NULL}, +{"PrecedesTilde", "≾", NULL}, +{"Prime", "″", "″"}, +{"Product", "∏", NULL}, +{"Proportion", "∷", NULL}, +{"Proportional", "∝", NULL}, +{"Pscr", "𝒫", NULL}, +{"Psi", "Ψ", "Ψ"}, +{"QUOT", "\"", NULL}, +{"Qfr", "𝔔", NULL}, +{"Qopf", "ℚ", NULL}, +{"Qscr", "𝒬", NULL}, +{"RBarr", "⤐", NULL}, +{"REG", "®", NULL}, +{"Racute", "Ŕ", NULL}, +{"Rang", "⟫", NULL}, +{"Rarr", "↠", NULL}, +{"Rarrtl", "⤖", NULL}, +{"Rcaron", "Ř", NULL}, +{"Rcedil", "Ŗ", NULL}, +{"Rcy", "Р", NULL}, +{"Re", "ℜ", NULL}, +{"ReverseElement", "∋", NULL}, +{"ReverseEquilibrium", "⇋", NULL}, +{"ReverseUpEquilibrium", "⥯", NULL}, +{"Rfr", "ℜ", NULL}, +{"Rho", "Ρ", "Ρ"}, +{"RightAngleBracket", "⟩", NULL}, +{"RightArrow", "→", NULL}, +{"RightArrowBar", "⇥", NULL}, +{"RightArrowLeftArrow", "⇄", NULL}, +{"RightCeiling", "⌉", NULL}, +{"RightDoubleBracket", "⟧", NULL}, +{"RightDownTeeVector", "⥝", NULL}, +{"RightDownVector", "⇂", NULL}, +{"RightDownVectorBar", "⥕", NULL}, +{"RightFloor", "⌋", NULL}, +{"RightTee", "⊢", NULL}, +{"RightTeeArrow", "↦", NULL}, +{"RightTeeVector", "⥛", NULL}, +{"RightTriangle", "⊳", NULL}, +{"RightTriangleBar", "⧐", NULL}, +{"RightTriangleEqual", "⊵", NULL}, +{"RightUpDownVector", "⥏", NULL}, +{"RightUpTeeVector", "⥜", NULL}, +{"RightUpVector", "↾", NULL}, +{"RightUpVectorBar", "⥔", NULL}, +{"RightVector", "⇀", NULL}, +{"RightVectorBar", "⥓", NULL}, +{"Rightarrow", "⇒", NULL}, +{"Ropf", "ℝ", NULL}, +{"RoundImplies", "⥰", NULL}, +{"Rrightarrow", "⇛", NULL}, +{"Rscr", "ℛ", NULL}, +{"Rsh", "↱", NULL}, +{"RuleDelayed", "⧴", NULL}, +{"SHCHcy", "Щ", NULL}, +{"SHcy", "Ш", NULL}, +{"SOFTcy", "Ь", NULL}, +{"Sacute", "Ś", NULL}, +{"Sc", "⪼", NULL}, +{"Scaron", "Š", "Š"}, +{"Scedil", "Ş", NULL}, +{"Scirc", "Ŝ", NULL}, +{"Scy", "С", NULL}, +{"Sfr", "𝔖", NULL}, +{"ShortDownArrow", "↓", NULL}, +{"ShortLeftArrow", "←", NULL}, +{"ShortRightArrow", "→", NULL}, +{"ShortUpArrow", "↑", NULL}, +{"Sigma", "Σ", "Σ"}, +{"SmallCircle", "∘", NULL}, +{"Sopf", "𝕊", NULL}, +{"Sqrt", "√", NULL}, +{"Square", "□", NULL}, +{"SquareIntersection", "⊓", NULL}, +{"SquareSubset", "⊏", NULL}, +{"SquareSubsetEqual", "⊑", NULL}, +{"SquareSuperset", "⊐", NULL}, +{"SquareSupersetEqual", "⊒", NULL}, +{"SquareUnion", "⊔", NULL}, +{"Sscr", "𝒮", NULL}, +{"Star", "⋆", NULL}, +{"Sub", "⋐", NULL}, +{"Subset", "⋐", NULL}, +{"SubsetEqual", "⊆", NULL}, +{"Succeeds", "≻", NULL}, +{"SucceedsEqual", "⪰", NULL}, +{"SucceedsSlantEqual", "≽", NULL}, +{"SucceedsTilde", "≿", NULL}, +{"SuchThat", "∋", NULL}, +{"Sum", "∑", NULL}, +{"Sup", "⋑", NULL}, +{"Superset", "⊃", NULL}, +{"SupersetEqual", "⊇", NULL}, +{"Supset", "⋑", NULL}, +{"THORN", "Þ", "Þ"}, +{"TRADE", "™", NULL}, +{"TSHcy", "Ћ", NULL}, +{"TScy", "Ц", NULL}, +{"Tab", "\t", NULL}, +{"Tau", "Τ", "Τ"}, +{"Tcaron", "Ť", NULL}, +{"Tcedil", "Ţ", NULL}, +{"Tcy", "Т", NULL}, +{"Tfr", "𝔗", NULL}, +{"Therefore", "∴", NULL}, +{"Theta", "Θ", "Θ"}, +{"ThickSpace", " ", NULL}, +{"ThinSpace", " ", NULL}, +{"Tilde", "∼", NULL}, +{"TildeEqual", "≃", NULL}, +{"TildeFullEqual", "≅", NULL}, +{"TildeTilde", "≈", NULL}, +{"Topf", "𝕋", NULL}, +{"TripleDot", "⃛", NULL}, +{"Tscr", "𝒯", NULL}, +{"Tstrok", "Ŧ", NULL}, +{"Uacute", "Ú", "Ú"}, +{"Uarr", "↟", NULL}, +{"Uarrocir", "⥉", NULL}, +{"Ubrcy", "Ў", NULL}, +{"Ubreve", "Ŭ", NULL}, +{"Ucirc", "Û", "Û"}, +{"Ucy", "У", NULL}, +{"Udblac", "Ű", NULL}, +{"Ufr", "𝔘", NULL}, +{"Ugrave", "Ù", "Ù"}, +{"Umacr", "Ū", NULL}, +{"UnderBar", "_", NULL}, +{"UnderBrace", "⏟", NULL}, +{"UnderBracket", "⎵", NULL}, +{"UnderParenthesis", "⏝", NULL}, +{"Union", "⋃", NULL}, +{"UnionPlus", "⊎", NULL}, +{"Uogon", "Ų", NULL}, +{"Uopf", "𝕌", NULL}, +{"UpArrow", "↑", NULL}, +{"UpArrowBar", "⤒", NULL}, +{"UpArrowDownArrow", "⇅", NULL}, +{"UpDownArrow", "↕", NULL}, +{"UpEquilibrium", "⥮", NULL}, +{"UpTee", "⊥", NULL}, +{"UpTeeArrow", "↥", NULL}, +{"Uparrow", "⇑", NULL}, +{"Updownarrow", "⇕", NULL}, +{"UpperLeftArrow", "↖", NULL}, +{"UpperRightArrow", "↗", NULL}, +{"Upsi", "ϒ", NULL}, +{"Upsilon", "Υ", "Υ"}, +{"Uring", "Ů", NULL}, +{"Uscr", "𝒰", NULL}, +{"Utilde", "Ũ", NULL}, +{"Uuml", "Ü", "Ü"}, +{"VDash", "⊫", NULL}, +{"Vbar", "⫫", NULL}, +{"Vcy", "В", NULL}, +{"Vdash", "⊩", NULL}, +{"Vdashl", "⫦", NULL}, +{"Vee", "⋁", NULL}, +{"Verbar", "‖", NULL}, +{"Vert", "‖", NULL}, +{"VerticalBar", "∣", NULL}, +{"VerticalLine", "|", NULL}, +{"VerticalSeparator", "❘", NULL}, +{"VerticalTilde", "≀", NULL}, +{"VeryThinSpace", " ", NULL}, +{"Vfr", "𝔙", NULL}, +{"Vopf", "𝕍", NULL}, +{"Vscr", "𝒱", NULL}, +{"Vvdash", "⊪", NULL}, +{"Wcirc", "Ŵ", NULL}, +{"Wedge", "⋀", NULL}, +{"Wfr", "𝔚", NULL}, +{"Wopf", "𝕎", NULL}, +{"Wscr", "𝒲", NULL}, +{"Xfr", "𝔛", NULL}, +{"Xi", "Ξ", "Ξ"}, +{"Xopf", "𝕏", NULL}, +{"Xscr", "𝒳", NULL}, +{"YAcy", "Я", NULL}, +{"YIcy", "Ї", NULL}, +{"YUcy", "Ю", NULL}, +{"Yacute", "Ý", "Ý"}, +{"Ycirc", "Ŷ", NULL}, +{"Ycy", "Ы", NULL}, +{"Yfr", "𝔜", NULL}, +{"Yopf", "𝕐", NULL}, +{"Yscr", "𝒴", NULL}, +{"Yuml", "Ÿ", "Ÿ"}, +{"ZHcy", "Ж", NULL}, +{"Zacute", "Ź", NULL}, +{"Zcaron", "Ž", NULL}, +{"Zcy", "З", NULL}, +{"Zdot", "Ż", NULL}, +{"ZeroWidthSpace", "", NULL}, +{"Zeta", "Ζ", "Ζ"}, +{"Zfr", "ℨ", NULL}, +{"Zopf", "ℤ", NULL}, +{"Zscr", "𝒵", NULL}, +{"aacute", "á", "á"}, +{"abreve", "ă", NULL}, +{"ac", "∾", NULL}, +{"acE", "∾̳", NULL}, +{"acd", "∿", NULL}, +{"acirc", "â", "â"}, +{"acute", "´", "´"}, +{"acy", "а", NULL}, +{"aelig", "æ", "æ"}, +{"af", "", NULL}, +{"afr", "𝔞", NULL}, +{"agrave", "à", "à"}, +{"alefsym", "ℵ", "ℵ"}, +{"aleph", "ℵ", NULL}, +{"alpha", "α", "α"}, +{"amacr", "ā", NULL}, +{"amalg", "⨿", NULL}, +{"amp", "&", "&"}, +{"and", "∧", "∧"}, +{"andand", "⩕", NULL}, +{"andd", "⩜", NULL}, +{"andslope", "⩘", NULL}, +{"andv", "⩚", NULL}, +{"ang", "∠", "∠"}, +{"ange", "⦤", NULL}, +{"angle", "∠", NULL}, +{"angmsd", "∡", NULL}, +{"angmsdaa", "⦨", NULL}, +{"angmsdab", "⦩", NULL}, +{"angmsdac", "⦪", NULL}, +{"angmsdad", "⦫", NULL}, +{"angmsdae", "⦬", NULL}, +{"angmsdaf", "⦭", NULL}, +{"angmsdag", "⦮", NULL}, +{"angmsdah", "⦯", NULL}, +{"angrt", "∟", NULL}, +{"angrtvb", "⊾", NULL}, +{"angrtvbd", "⦝", NULL}, +{"angsph", "∢", NULL}, +{"angst", "Å", NULL}, +{"angzarr", "⍼", NULL}, +{"aogon", "ą", NULL}, +{"aopf", "𝕒", NULL}, +{"ap", "≈", NULL}, +{"apE", "⩰", NULL}, +{"apacir", "⩯", NULL}, +{"ape", "≊", NULL}, +{"apid", "≋", NULL}, +{"apos", "'", NULL}, +{"approx", "≈", NULL}, +{"approxeq", "≊", NULL}, +{"aring", "å", "å"}, +{"ascr", "𝒶", NULL}, +{"ast", "*", NULL}, +{"asymp", "≈", "≈"}, +{"asympeq", "≍", NULL}, +{"atilde", "ã", "ã"}, +{"auml", "ä", "ä"}, +{"awconint", "∳", NULL}, +{"awint", "⨑", NULL}, +{"bNot", "⫭", NULL}, +{"backcong", "≌", NULL}, +{"backepsilon", "϶", NULL}, +{"backprime", "‵", NULL}, +{"backsim", "∽", NULL}, +{"backsimeq", "⋍", NULL}, +{"barvee", "⊽", NULL}, +{"barwed", "⌅", NULL}, +{"barwedge", "⌅", NULL}, +{"bbrk", "⎵", NULL}, +{"bbrktbrk", "⎶", NULL}, +{"bcong", "≌", NULL}, +{"bcy", "б", NULL}, +{"bdquo", "„", "„"}, +{"becaus", "∵", NULL}, +{"because", "∵", NULL}, +{"bemptyv", "⦰", NULL}, +{"bepsi", "϶", NULL}, +{"bernou", "ℬ", NULL}, +{"beta", "β", "β"}, +{"beth", "ℶ", NULL}, +{"between", "≬", NULL}, +{"bfr", "𝔟", NULL}, +{"bigcap", "⋂", NULL}, +{"bigcirc", "◯", NULL}, +{"bigcup", "⋃", NULL}, +{"bigodot", "⨀", NULL}, +{"bigoplus", "⨁", NULL}, +{"bigotimes", "⨂", NULL}, +{"bigsqcup", "⨆", NULL}, +{"bigstar", "★", NULL}, +{"bigtriangledown", "▽", NULL}, +{"bigtriangleup", "△", NULL}, +{"biguplus", "⨄", NULL}, +{"bigvee", "⋁", NULL}, +{"bigwedge", "⋀", NULL}, +{"bkarow", "⤍", NULL}, +{"blacklozenge", "⧫", NULL}, +{"blacksquare", "▪", NULL}, +{"blacktriangle", "▴", NULL}, +{"blacktriangledown", "▾", NULL}, +{"blacktriangleleft", "◂", NULL}, +{"blacktriangleright", "▸", NULL}, +{"blank", "␣", NULL}, +{"blk12", "▒", NULL}, +{"blk14", "░", NULL}, +{"blk34", "▓", NULL}, +{"block", "█", NULL}, +{"bne", "=⃥", NULL}, +{"bnequiv", "≡⃥", NULL}, +{"bnot", "⌐", NULL}, +{"bopf", "𝕓", NULL}, +{"bot", "⊥", NULL}, +{"bottom", "⊥", NULL}, +{"bowtie", "⋈", NULL}, +{"boxDL", "╗", NULL}, +{"boxDR", "╔", NULL}, +{"boxDl", "╖", NULL}, +{"boxDr", "╓", NULL}, +{"boxH", "═", NULL}, +{"boxHD", "╦", NULL}, +{"boxHU", "╩", NULL}, +{"boxHd", "╤", NULL}, +{"boxHu", "╧", NULL}, +{"boxUL", "╝", NULL}, +{"boxUR", "╚", NULL}, +{"boxUl", "╜", NULL}, +{"boxUr", "╙", NULL}, +{"boxV", "║", NULL}, +{"boxVH", "╬", NULL}, +{"boxVL", "╣", NULL}, +{"boxVR", "╠", NULL}, +{"boxVh", "╫", NULL}, +{"boxVl", "╢", NULL}, +{"boxVr", "╟", NULL}, +{"boxbox", "⧉", NULL}, +{"boxdL", "╕", NULL}, +{"boxdR", "╒", NULL}, +{"boxdl", "┐", NULL}, +{"boxdr", "┌", NULL}, +{"boxh", "─", NULL}, +{"boxhD", "╥", NULL}, +{"boxhU", "╨", NULL}, +{"boxhd", "┬", NULL}, +{"boxhu", "┴", NULL}, +{"boxminus", "⊟", NULL}, +{"boxplus", "⊞", NULL}, +{"boxtimes", "⊠", NULL}, +{"boxuL", "╛", NULL}, +{"boxuR", "╘", NULL}, +{"boxul", "┘", NULL}, +{"boxur", "└", NULL}, +{"boxv", "│", NULL}, +{"boxvH", "╪", NULL}, +{"boxvL", "╡", NULL}, +{"boxvR", "╞", NULL}, +{"boxvh", "┼", NULL}, +{"boxvl", "┤", NULL}, +{"boxvr", "├", NULL}, +{"bprime", "‵", NULL}, +{"breve", "˘", NULL}, +{"brvbar", "¦", "¦"}, +{"bscr", "𝒷", NULL}, +{"bsemi", "⁏", NULL}, +{"bsim", "∽", NULL}, +{"bsime", "⋍", NULL}, +{"bsol", "\\", NULL}, +{"bsolb", "⧅", NULL}, +{"bsolhsub", "⟈", NULL}, +{"bull", "•", "•"}, +{"bullet", "•", NULL}, +{"bump", "≎", NULL}, +{"bumpE", "⪮", NULL}, +{"bumpe", "≏", NULL}, +{"bumpeq", "≏", NULL}, +{"cacute", "ć", NULL}, +{"cap", "∩", "∩"}, +{"capand", "⩄", NULL}, +{"capbrcup", "⩉", NULL}, +{"capcap", "⩋", NULL}, +{"capcup", "⩇", NULL}, +{"capdot", "⩀", NULL}, +{"caps", "∩︀", NULL}, +{"caret", "⁁", NULL}, +{"caron", "ˇ", NULL}, +{"ccaps", "⩍", NULL}, +{"ccaron", "č", NULL}, +{"ccedil", "ç", "ç"}, +{"ccirc", "ĉ", NULL}, +{"ccups", "⩌", NULL}, +{"ccupssm", "⩐", NULL}, +{"cdot", "ċ", NULL}, +{"cedil", "¸", "¸"}, +{"cemptyv", "⦲", NULL}, +{"cent", "¢", "¢"}, +{"centerdot", "·", NULL}, +{"cfr", "𝔠", NULL}, +{"chcy", "ч", NULL}, +{"check", "✓", NULL}, +{"checkmark", "✓", NULL}, +{"chi", "χ", "χ"}, +{"cir", "○", NULL}, +{"cirE", "⧃", NULL}, +{"circ", "ˆ", "ˆ"}, +{"circeq", "≗", NULL}, +{"circlearrowleft", "↺", NULL}, +{"circlearrowright", "↻", NULL}, +{"circledR", "®", NULL}, +{"circledS", "Ⓢ", NULL}, +{"circledast", "⊛", NULL}, +{"circledcirc", "⊚", NULL}, +{"circleddash", "⊝", NULL}, +{"cire", "≗", NULL}, +{"cirfnint", "⨐", NULL}, +{"cirmid", "⫯", NULL}, +{"cirscir", "⧂", NULL}, +{"clubs", "♣", "♣"}, +{"clubsuit", "♣", NULL}, +{"colon", ":", NULL}, +{"colone", "≔", NULL}, +{"coloneq", "≔", NULL}, +{"comma", ",", NULL}, +{"commat", "@", NULL}, +{"comp", "∁", NULL}, +{"compfn", "∘", NULL}, +{"complement", "∁", NULL}, +{"complexes", "ℂ", NULL}, +{"cong", "≅", "≅"}, +{"congdot", "⩭", NULL}, +{"conint", "∮", NULL}, +{"copf", "𝕔", NULL}, +{"coprod", "∐", NULL}, +{"copy", "©", "©"}, +{"copysr", "℗", NULL}, +{"crarr", "↵", "↵"}, +{"cross", "✗", NULL}, +{"cscr", "𝒸", NULL}, +{"csub", "⫏", NULL}, +{"csube", "⫑", NULL}, +{"csup", "⫐", NULL}, +{"csupe", "⫒", NULL}, +{"ctdot", "⋯", NULL}, +{"cudarrl", "⤸", NULL}, +{"cudarrr", "⤵", NULL}, +{"cuepr", "⋞", NULL}, +{"cuesc", "⋟", NULL}, +{"cularr", "↶", NULL}, +{"cularrp", "⤽", NULL}, +{"cup", "∪", "∪"}, +{"cupbrcap", "⩈", NULL}, +{"cupcap", "⩆", NULL}, +{"cupcup", "⩊", NULL}, +{"cupdot", "⊍", NULL}, +{"cupor", "⩅", NULL}, +{"cups", "∪︀", NULL}, +{"curarr", "↷", NULL}, +{"curarrm", "⤼", NULL}, +{"curlyeqprec", "⋞", NULL}, +{"curlyeqsucc", "⋟", NULL}, +{"curlyvee", "⋎", NULL}, +{"curlywedge", "⋏", NULL}, +{"curren", "¤", "¤"}, +{"curvearrowleft", "↶", NULL}, +{"curvearrowright", "↷", NULL}, +{"cuvee", "⋎", NULL}, +{"cuwed", "⋏", NULL}, +{"cwconint", "∲", NULL}, +{"cwint", "∱", NULL}, +{"cylcty", "⌭", NULL}, +{"dArr", "⇓", "⇓"}, +{"dHar", "⥥", NULL}, +{"dagger", "†", "†"}, +{"daleth", "ℸ", NULL}, +{"darr", "↓", "↓"}, +{"dash", "‐", NULL}, +{"dashv", "⊣", NULL}, +{"dbkarow", "⤏", NULL}, +{"dblac", "˝", NULL}, +{"dcaron", "ď", NULL}, +{"dcy", "д", NULL}, +{"dd", "ⅆ", NULL}, +{"ddagger", "‡", NULL}, +{"ddarr", "⇊", NULL}, +{"ddotseq", "⩷", NULL}, +{"deg", "°", "°"}, +{"delta", "δ", "δ"}, +{"demptyv", "⦱", NULL}, +{"dfisht", "⥿", NULL}, +{"dfr", "𝔡", NULL}, +{"dharl", "⇃", NULL}, +{"dharr", "⇂", NULL}, +{"diam", "⋄", NULL}, +{"diamond", "⋄", NULL}, +{"diamondsuit", "♦", NULL}, +{"diams", "♦", "♦"}, +{"die", "¨", NULL}, +{"digamma", "ϝ", NULL}, +{"disin", "⋲", NULL}, +{"div", "÷", NULL}, +{"divide", "÷", "÷"}, +{"divideontimes", "⋇", NULL}, +{"divonx", "⋇", NULL}, +{"djcy", "ђ", NULL}, +{"dlcorn", "⌞", NULL}, +{"dlcrop", "⌍", NULL}, +{"dollar", "$", NULL}, +{"dopf", "𝕕", NULL}, +{"dot", "˙", NULL}, +{"doteq", "≐", NULL}, +{"doteqdot", "≑", NULL}, +{"dotminus", "∸", NULL}, +{"dotplus", "∔", NULL}, +{"dotsquare", "⊡", NULL}, +{"doublebarwedge", "⌆", NULL}, +{"downarrow", "↓", NULL}, +{"downdownarrows", "⇊", NULL}, +{"downharpoonleft", "⇃", NULL}, +{"downharpoonright", "⇂", NULL}, +{"drbkarow", "⤐", NULL}, +{"drcorn", "⌟", NULL}, +{"drcrop", "⌌", NULL}, +{"dscr", "𝒹", NULL}, +{"dscy", "ѕ", NULL}, +{"dsol", "⧶", NULL}, +{"dstrok", "đ", NULL}, +{"dtdot", "⋱", NULL}, +{"dtri", "▿", NULL}, +{"dtrif", "▾", NULL}, +{"duarr", "⇵", NULL}, +{"duhar", "⥯", NULL}, +{"dwangle", "⦦", NULL}, +{"dzcy", "џ", NULL}, +{"dzigrarr", "⟿", NULL}, +{"eDDot", "⩷", NULL}, +{"eDot", "≑", NULL}, +{"eacute", "é", "é"}, +{"easter", "⩮", NULL}, +{"ecaron", "ě", NULL}, +{"ecir", "≖", NULL}, +{"ecirc", "ê", "ê"}, +{"ecolon", "≕", NULL}, +{"ecy", "э", NULL}, +{"edot", "ė", NULL}, +{"ee", "ⅇ", NULL}, +{"efDot", "≒", NULL}, +{"efr", "𝔢", NULL}, +{"eg", "⪚", NULL}, +{"egrave", "è", "è"}, +{"egs", "⪖", NULL}, +{"egsdot", "⪘", NULL}, +{"el", "⪙", NULL}, +{"elinters", "⏧", NULL}, +{"ell", "ℓ", NULL}, +{"els", "⪕", NULL}, +{"elsdot", "⪗", NULL}, +{"emacr", "ē", NULL}, +{"empty", "∅", "∅"}, +{"emptyset", "∅", NULL}, +{"emptyv", "∅", NULL}, +{"emsp", " ", " "}, +{"emsp13", " ", NULL}, +{"emsp14", " ", NULL}, +{"eng", "ŋ", NULL}, +{"ensp", " ", " "}, +{"eogon", "ę", NULL}, +{"eopf", "𝕖", NULL}, +{"epar", "⋕", NULL}, +{"eparsl", "⧣", NULL}, +{"eplus", "⩱", NULL}, +{"epsi", "ε", NULL}, +{"epsilon", "ε", "ε"}, +{"epsiv", "ϵ", NULL}, +{"eqcirc", "≖", NULL}, +{"eqcolon", "≕", NULL}, +{"eqsim", "≂", NULL}, +{"eqslantgtr", "⪖", NULL}, +{"eqslantless", "⪕", NULL}, +{"equals", "=", NULL}, +{"equest", "≟", NULL}, +{"equiv", "≡", "≡"}, +{"equivDD", "⩸", NULL}, +{"eqvparsl", "⧥", NULL}, +{"erDot", "≓", NULL}, +{"erarr", "⥱", NULL}, +{"escr", "ℯ", NULL}, +{"esdot", "≐", NULL}, +{"esim", "≂", NULL}, +{"eta", "η", "η"}, +{"eth", "ð", "ð"}, +{"euml", "ë", "ë"}, +{"euro", "€", "€"}, +{"excl", "!", NULL}, +{"exist", "∃", "∃"}, +{"expectation", "ℰ", NULL}, +{"exponentiale", "ⅇ", NULL}, +{"fallingdotseq", "≒", NULL}, +{"fcy", "ф", NULL}, +{"female", "♀", NULL}, +{"ffilig", "ffi", NULL}, +{"fflig", "ff", NULL}, +{"ffllig", "ffl", NULL}, +{"ffr", "𝔣", NULL}, +{"filig", "fi", NULL}, +{"fjlig", "fj", NULL}, +{"flat", "♭", NULL}, +{"fllig", "fl", NULL}, +{"fltns", "▱", NULL}, +{"fnof", "ƒ", "ƒ"}, +{"fopf", "𝕗", NULL}, +{"forall", "∀", "∀"}, +{"fork", "⋔", NULL}, +{"forkv", "⫙", NULL}, +{"fpartint", "⨍", NULL}, +{"frac12", "½", "½"}, +{"frac13", "⅓", NULL}, +{"frac14", "¼", "¼"}, +{"frac15", "⅕", NULL}, +{"frac16", "⅙", NULL}, +{"frac18", "⅛", NULL}, +{"frac23", "⅔", NULL}, +{"frac25", "⅖", NULL}, +{"frac34", "¾", "¾"}, +{"frac35", "⅗", NULL}, +{"frac38", "⅜", NULL}, +{"frac45", "⅘", NULL}, +{"frac56", "⅚", NULL}, +{"frac58", "⅝", NULL}, +{"frac78", "⅞", NULL}, +{"frasl", "⁄", "⁄"}, +{"frown", "⌢", NULL}, +{"fscr", "𝒻", NULL}, +{"gE", "≧", NULL}, +{"gEl", "⪌", NULL}, +{"gacute", "ǵ", NULL}, +{"gamma", "γ", "γ"}, +{"gammad", "ϝ", NULL}, +{"gap", "⪆", NULL}, +{"gbreve", "ğ", NULL}, +{"gcirc", "ĝ", NULL}, +{"gcy", "г", NULL}, +{"gdot", "ġ", NULL}, +{"ge", "≥", "≥"}, +{"gel", "⋛", NULL}, +{"geq", "≥", NULL}, +{"geqq", "≧", NULL}, +{"geqslant", "⩾", NULL}, +{"ges", "⩾", NULL}, +{"gescc", "⪩", NULL}, +{"gesdot", "⪀", NULL}, +{"gesdoto", "⪂", NULL}, +{"gesdotol", "⪄", NULL}, +{"gesl", "⋛︀", NULL}, +{"gesles", "⪔", NULL}, +{"gfr", "𝔤", NULL}, +{"gg", "≫", NULL}, +{"ggg", "⋙", NULL}, +{"gimel", "ℷ", NULL}, +{"gjcy", "ѓ", NULL}, +{"gl", "≷", NULL}, +{"glE", "⪒", NULL}, +{"gla", "⪥", NULL}, +{"glj", "⪤", NULL}, +{"gnE", "≩", NULL}, +{"gnap", "⪊", NULL}, +{"gnapprox", "⪊", NULL}, +{"gne", "⪈", NULL}, +{"gneq", "⪈", NULL}, +{"gneqq", "≩", NULL}, +{"gnsim", "⋧", NULL}, +{"gopf", "𝕘", NULL}, +{"grave", "`", NULL}, +{"gscr", "ℊ", NULL}, +{"gsim", "≳", NULL}, +{"gsime", "⪎", NULL}, +{"gsiml", "⪐", NULL}, +{"gt", ">", ">"}, +{"gtcc", "⪧", NULL}, +{"gtcir", "⩺", NULL}, +{"gtdot", "⋗", NULL}, +{"gtlPar", "⦕", NULL}, +{"gtquest", "⩼", NULL}, +{"gtrapprox", "⪆", NULL}, +{"gtrarr", "⥸", NULL}, +{"gtrdot", "⋗", NULL}, +{"gtreqless", "⋛", NULL}, +{"gtreqqless", "⪌", NULL}, +{"gtrless", "≷", NULL}, +{"gtrsim", "≳", NULL}, +{"gvertneqq", "≩︀", NULL}, +{"gvnE", "≩︀", NULL}, +{"hArr", "⇔", "⇔"}, +{"hairsp", " ", NULL}, +{"half", "½", NULL}, +{"hamilt", "ℋ", NULL}, +{"hardcy", "ъ", NULL}, +{"harr", "↔", "↔"}, +{"harrcir", "⥈", NULL}, +{"harrw", "↭", NULL}, +{"hbar", "ℏ", NULL}, +{"hcirc", "ĥ", NULL}, +{"hearts", "♥", "♥"}, +{"heartsuit", "♥", NULL}, +{"hellip", "…", "…"}, +{"hercon", "⊹", NULL}, +{"hfr", "𝔥", NULL}, +{"hksearow", "⤥", NULL}, +{"hkswarow", "⤦", NULL}, +{"hoarr", "⇿", NULL}, +{"homtht", "∻", NULL}, +{"hookleftarrow", "↩", NULL}, +{"hookrightarrow", "↪", NULL}, +{"hopf", "𝕙", NULL}, +{"horbar", "―", NULL}, +{"hscr", "𝒽", NULL}, +{"hslash", "ℏ", NULL}, +{"hstrok", "ħ", NULL}, +{"hybull", "⁃", NULL}, +{"hyphen", "‐", NULL}, +{"iacute", "í", "í"}, +{"ic", "", NULL}, +{"icirc", "î", "î"}, +{"icy", "и", NULL}, +{"iecy", "е", NULL}, +{"iexcl", "¡", "¡"}, +{"iff", "⇔", NULL}, +{"ifr", "𝔦", NULL}, +{"igrave", "ì", "ì"}, +{"ii", "ⅈ", NULL}, +{"iiiint", "⨌", NULL}, +{"iiint", "∭", NULL}, +{"iinfin", "⧜", NULL}, +{"iiota", "℩", NULL}, +{"ijlig", "ij", NULL}, +{"imacr", "ī", NULL}, +{"image", "ℑ", "ℑ"}, +{"imagline", "ℐ", NULL}, +{"imagpart", "ℑ", NULL}, +{"imath", "ı", NULL}, +{"imof", "⊷", NULL}, +{"imped", "Ƶ", NULL}, +{"in", "∈", NULL}, +{"incare", "℅", NULL}, +{"infin", "∞", "∞"}, +{"infintie", "⧝", NULL}, +{"inodot", "ı", NULL}, +{"int", "∫", "∫"}, +{"intcal", "⊺", NULL}, +{"integers", "ℤ", NULL}, +{"intercal", "⊺", NULL}, +{"intlarhk", "⨗", NULL}, +{"intprod", "⨼", NULL}, +{"iocy", "ё", NULL}, +{"iogon", "į", NULL}, +{"iopf", "𝕚", NULL}, +{"iota", "ι", "ι"}, +{"iprod", "⨼", NULL}, +{"iquest", "¿", "¿"}, +{"iscr", "𝒾", NULL}, +{"isin", "∈", "∈"}, +{"isinE", "⋹", NULL}, +{"isindot", "⋵", NULL}, +{"isins", "⋴", NULL}, +{"isinsv", "⋳", NULL}, +{"isinv", "∈", NULL}, +{"it", "", NULL}, +{"itilde", "ĩ", NULL}, +{"iukcy", "і", NULL}, +{"iuml", "ï", "ï"}, +{"jcirc", "ĵ", NULL}, +{"jcy", "й", NULL}, +{"jfr", "𝔧", NULL}, +{"jmath", "ȷ", NULL}, +{"jopf", "𝕛", NULL}, +{"jscr", "𝒿", NULL}, +{"jsercy", "ј", NULL}, +{"jukcy", "є", NULL}, +{"kappa", "κ", "κ"}, +{"kappav", "ϰ", NULL}, +{"kcedil", "ķ", NULL}, +{"kcy", "к", NULL}, +{"kfr", "𝔨", NULL}, +{"kgreen", "ĸ", NULL}, +{"khcy", "х", NULL}, +{"kjcy", "ќ", NULL}, +{"kopf", "𝕜", NULL}, +{"kscr", "𝓀", NULL}, +{"lAarr", "⇚", NULL}, +{"lArr", "⇐", "⇐"}, +{"lAtail", "⤛", NULL}, +{"lBarr", "⤎", NULL}, +{"lE", "≦", NULL}, +{"lEg", "⪋", NULL}, +{"lHar", "⥢", NULL}, +{"lacute", "ĺ", NULL}, +{"laemptyv", "⦴", NULL}, +{"lagran", "ℒ", NULL}, +{"lambda", "λ", "λ"}, +{"lang", "⟨", "〈"}, +{"langd", "⦑", NULL}, +{"langle", "⟨", NULL}, +{"lap", "⪅", NULL}, +{"laquo", "«", "«"}, +{"larr", "←", "←"}, +{"larrb", "⇤", NULL}, +{"larrbfs", "⤟", NULL}, +{"larrfs", "⤝", NULL}, +{"larrhk", "↩", NULL}, +{"larrlp", "↫", NULL}, +{"larrpl", "⤹", NULL}, +{"larrsim", "⥳", NULL}, +{"larrtl", "↢", NULL}, +{"lat", "⪫", NULL}, +{"latail", "⤙", NULL}, +{"late", "⪭", NULL}, +{"lates", "⪭︀", NULL}, +{"lbarr", "⤌", NULL}, +{"lbbrk", "❲", NULL}, +{"lbrace", "{", NULL}, +{"lbrack", "[", NULL}, +{"lbrke", "⦋", NULL}, +{"lbrksld", "⦏", NULL}, +{"lbrkslu", "⦍", NULL}, +{"lcaron", "ľ", NULL}, +{"lcedil", "ļ", NULL}, +{"lceil", "⌈", "⌈"}, +{"lcub", "{", NULL}, +{"lcy", "л", NULL}, +{"ldca", "⤶", NULL}, +{"ldquo", "“", "“"}, +{"ldquor", "„", NULL}, +{"ldrdhar", "⥧", NULL}, +{"ldrushar", "⥋", NULL}, +{"ldsh", "↲", NULL}, +{"le", "≤", "≤"}, +{"leftarrow", "←", NULL}, +{"leftarrowtail", "↢", NULL}, +{"leftharpoondown", "↽", NULL}, +{"leftharpoonup", "↼", NULL}, +{"leftleftarrows", "⇇", NULL}, +{"leftrightarrow", "↔", NULL}, +{"leftrightarrows", "⇆", NULL}, +{"leftrightharpoons", "⇋", NULL}, +{"leftrightsquigarrow", "↭", NULL}, +{"leftthreetimes", "⋋", NULL}, +{"leg", "⋚", NULL}, +{"leq", "≤", NULL}, +{"leqq", "≦", NULL}, +{"leqslant", "⩽", NULL}, +{"les", "⩽", NULL}, +{"lescc", "⪨", NULL}, +{"lesdot", "⩿", NULL}, +{"lesdoto", "⪁", NULL}, +{"lesdotor", "⪃", NULL}, +{"lesg", "⋚︀", NULL}, +{"lesges", "⪓", NULL}, +{"lessapprox", "⪅", NULL}, +{"lessdot", "⋖", NULL}, +{"lesseqgtr", "⋚", NULL}, +{"lesseqqgtr", "⪋", NULL}, +{"lessgtr", "≶", NULL}, +{"lesssim", "≲", NULL}, +{"lfisht", "⥼", NULL}, +{"lfloor", "⌊", "⌊"}, +{"lfr", "𝔩", NULL}, +{"lg", "≶", NULL}, +{"lgE", "⪑", NULL}, +{"lhard", "↽", NULL}, +{"lharu", "↼", NULL}, +{"lharul", "⥪", NULL}, +{"lhblk", "▄", NULL}, +{"ljcy", "љ", NULL}, +{"ll", "≪", NULL}, +{"llarr", "⇇", NULL}, +{"llcorner", "⌞", NULL}, +{"llhard", "⥫", NULL}, +{"lltri", "◺", NULL}, +{"lmidot", "ŀ", NULL}, +{"lmoust", "⎰", NULL}, +{"lmoustache", "⎰", NULL}, +{"lnE", "≨", NULL}, +{"lnap", "⪉", NULL}, +{"lnapprox", "⪉", NULL}, +{"lne", "⪇", NULL}, +{"lneq", "⪇", NULL}, +{"lneqq", "≨", NULL}, +{"lnsim", "⋦", NULL}, +{"loang", "⟬", NULL}, +{"loarr", "⇽", NULL}, +{"lobrk", "⟦", NULL}, +{"longleftarrow", "⟵", NULL}, +{"longleftrightarrow", "⟷", NULL}, +{"longmapsto", "⟼", NULL}, +{"longrightarrow", "⟶", NULL}, +{"looparrowleft", "↫", NULL}, +{"looparrowright", "↬", NULL}, +{"lopar", "⦅", NULL}, +{"lopf", "𝕝", NULL}, +{"loplus", "⨭", NULL}, +{"lotimes", "⨴", NULL}, +{"lowast", "∗", "∗"}, +{"lowbar", "_", NULL}, +{"loz", "◊", "◊"}, +{"lozenge", "◊", NULL}, +{"lozf", "⧫", NULL}, +{"lpar", "(", NULL}, +{"lparlt", "⦓", NULL}, +{"lrarr", "⇆", NULL}, +{"lrcorner", "⌟", NULL}, +{"lrhar", "⇋", NULL}, +{"lrhard", "⥭", NULL}, +{"lrm", "", ""}, +{"lrtri", "⊿", NULL}, +{"lsaquo", "‹", "‹"}, +{"lscr", "𝓁", NULL}, +{"lsh", "↰", NULL}, +{"lsim", "≲", NULL}, +{"lsime", "⪍", NULL}, +{"lsimg", "⪏", NULL}, +{"lsqb", "[", NULL}, +{"lsquo", "‘", "‘"}, +{"lsquor", "‚", NULL}, +{"lstrok", "ł", NULL}, +{"lt", "<", "<"}, +{"ltcc", "⪦", NULL}, +{"ltcir", "⩹", NULL}, +{"ltdot", "⋖", NULL}, +{"lthree", "⋋", NULL}, +{"ltimes", "⋉", NULL}, +{"ltlarr", "⥶", NULL}, +{"ltquest", "⩻", NULL}, +{"ltrPar", "⦖", NULL}, +{"ltri", "◃", NULL}, +{"ltrie", "⊴", NULL}, +{"ltrif", "◂", NULL}, +{"lurdshar", "⥊", NULL}, +{"luruhar", "⥦", NULL}, +{"lvertneqq", "≨︀", NULL}, +{"lvnE", "≨︀", NULL}, +{"mDDot", "∺", NULL}, +{"macr", "¯", "¯"}, +{"male", "♂", NULL}, +{"malt", "✠", NULL}, +{"maltese", "✠", NULL}, +{"map", "↦", NULL}, +{"mapsto", "↦", NULL}, +{"mapstodown", "↧", NULL}, +{"mapstoleft", "↤", NULL}, +{"mapstoup", "↥", NULL}, +{"marker", "▮", NULL}, +{"mcomma", "⨩", NULL}, +{"mcy", "м", NULL}, +{"mdash", "—", "—"}, +{"measuredangle", "∡", NULL}, +{"mfr", "𝔪", NULL}, +{"mho", "℧", NULL}, +{"micro", "µ", "µ"}, +{"mid", "∣", NULL}, +{"midast", "*", NULL}, +{"midcir", "⫰", NULL}, +{"middot", "·", "·"}, +{"minus", "−", "−"}, +{"minusb", "⊟", NULL}, +{"minusd", "∸", NULL}, +{"minusdu", "⨪", NULL}, +{"mlcp", "⫛", NULL}, +{"mldr", "…", NULL}, +{"mnplus", "∓", NULL}, +{"models", "⊧", NULL}, +{"mopf", "𝕞", NULL}, +{"mp", "∓", NULL}, +{"mscr", "𝓂", NULL}, +{"mstpos", "∾", NULL}, +{"mu", "μ", "μ"}, +{"multimap", "⊸", NULL}, +{"mumap", "⊸", NULL}, +{"nGg", "⋙̸", NULL}, +{"nGt", "≫⃒", NULL}, +{"nGtv", "≫̸", NULL}, +{"nLeftarrow", "⇍", NULL}, +{"nLeftrightarrow", "⇎", NULL}, +{"nLl", "⋘̸", NULL}, +{"nLt", "≪⃒", NULL}, +{"nLtv", "≪̸", NULL}, +{"nRightarrow", "⇏", NULL}, +{"nVDash", "⊯", NULL}, +{"nVdash", "⊮", NULL}, +{"nabla", "∇", "∇"}, +{"nacute", "ń", NULL}, +{"nang", "∠⃒", NULL}, +{"nap", "≉", NULL}, +{"napE", "⩰̸", NULL}, +{"napid", "≋̸", NULL}, +{"napos", "ʼn", NULL}, +{"napprox", "≉", NULL}, +{"natur", "♮", NULL}, +{"natural", "♮", NULL}, +{"naturals", "ℕ", NULL}, +{"nbsp", " ", " "}, +{"nbump", "≎̸", NULL}, +{"nbumpe", "≏̸", NULL}, +{"ncap", "⩃", NULL}, +{"ncaron", "ň", NULL}, +{"ncedil", "ņ", NULL}, +{"ncong", "≇", NULL}, +{"ncongdot", "⩭̸", NULL}, +{"ncup", "⩂", NULL}, +{"ncy", "н", NULL}, +{"ndash", "–", "–"}, +{"ne", "≠", "≠"}, +{"neArr", "⇗", NULL}, +{"nearhk", "⤤", NULL}, +{"nearr", "↗", NULL}, +{"nearrow", "↗", NULL}, +{"nedot", "≐̸", NULL}, +{"nequiv", "≢", NULL}, +{"nesear", "⤨", NULL}, +{"nesim", "≂̸", NULL}, +{"nexist", "∄", NULL}, +{"nexists", "∄", NULL}, +{"nfr", "𝔫", NULL}, +{"ngE", "≧̸", NULL}, +{"nge", "≱", NULL}, +{"ngeq", "≱", NULL}, +{"ngeqq", "≧̸", NULL}, +{"ngeqslant", "⩾̸", NULL}, +{"nges", "⩾̸", NULL}, +{"ngsim", "≵", NULL}, +{"ngt", "≯", NULL}, +{"ngtr", "≯", NULL}, +{"nhArr", "⇎", NULL}, +{"nharr", "↮", NULL}, +{"nhpar", "⫲", NULL}, +{"ni", "∋", "∋"}, +{"nis", "⋼", NULL}, +{"nisd", "⋺", NULL}, +{"niv", "∋", NULL}, +{"njcy", "њ", NULL}, +{"nlArr", "⇍", NULL}, +{"nlE", "≦̸", NULL}, +{"nlarr", "↚", NULL}, +{"nldr", "‥", NULL}, +{"nle", "≰", NULL}, +{"nleftarrow", "↚", NULL}, +{"nleftrightarrow", "↮", NULL}, +{"nleq", "≰", NULL}, +{"nleqq", "≦̸", NULL}, +{"nleqslant", "⩽̸", NULL}, +{"nles", "⩽̸", NULL}, +{"nless", "≮", NULL}, +{"nlsim", "≴", NULL}, +{"nlt", "≮", NULL}, +{"nltri", "⋪", NULL}, +{"nltrie", "⋬", NULL}, +{"nmid", "∤", NULL}, +{"nopf", "𝕟", NULL}, +{"not", "¬", "¬"}, +{"notin", "∉", "∉"}, +{"notinE", "⋹̸", NULL}, +{"notindot", "⋵̸", NULL}, +{"notinva", "∉", NULL}, +{"notinvb", "⋷", NULL}, +{"notinvc", "⋶", NULL}, +{"notni", "∌", NULL}, +{"notniva", "∌", NULL}, +{"notnivb", "⋾", NULL}, +{"notnivc", "⋽", NULL}, +{"npar", "∦", NULL}, +{"nparallel", "∦", NULL}, +{"nparsl", "⫽⃥", NULL}, +{"npart", "∂̸", NULL}, +{"npolint", "⨔", NULL}, +{"npr", "⊀", NULL}, +{"nprcue", "⋠", NULL}, +{"npre", "⪯̸", NULL}, +{"nprec", "⊀", NULL}, +{"npreceq", "⪯̸", NULL}, +{"nrArr", "⇏", NULL}, +{"nrarr", "↛", NULL}, +{"nrarrc", "⤳̸", NULL}, +{"nrarrw", "↝̸", NULL}, +{"nrightarrow", "↛", NULL}, +{"nrtri", "⋫", NULL}, +{"nrtrie", "⋭", NULL}, +{"nsc", "⊁", NULL}, +{"nsccue", "⋡", NULL}, +{"nsce", "⪰̸", NULL}, +{"nscr", "𝓃", NULL}, +{"nshortmid", "∤", NULL}, +{"nshortparallel", "∦", NULL}, +{"nsim", "≁", NULL}, +{"nsime", "≄", NULL}, +{"nsimeq", "≄", NULL}, +{"nsmid", "∤", NULL}, +{"nspar", "∦", NULL}, +{"nsqsube", "⋢", NULL}, +{"nsqsupe", "⋣", NULL}, +{"nsub", "⊄", "⊄"}, +{"nsubE", "⫅̸", NULL}, +{"nsube", "⊈", NULL}, +{"nsubset", "⊂⃒", NULL}, +{"nsubseteq", "⊈", NULL}, +{"nsubseteqq", "⫅̸", NULL}, +{"nsucc", "⊁", NULL}, +{"nsucceq", "⪰̸", NULL}, +{"nsup", "⊅", NULL}, +{"nsupE", "⫆̸", NULL}, +{"nsupe", "⊉", NULL}, +{"nsupset", "⊃⃒", NULL}, +{"nsupseteq", "⊉", NULL}, +{"nsupseteqq", "⫆̸", NULL}, +{"ntgl", "≹", NULL}, +{"ntilde", "ñ", "ñ"}, +{"ntlg", "≸", NULL}, +{"ntriangleleft", "⋪", NULL}, +{"ntrianglelefteq", "⋬", NULL}, +{"ntriangleright", "⋫", NULL}, +{"ntrianglerighteq", "⋭", NULL}, +{"nu", "ν", "ν"}, +{"num", "#", NULL}, +{"numero", "№", NULL}, +{"numsp", " ", NULL}, +{"nvDash", "⊭", NULL}, +{"nvHarr", "⤄", NULL}, +{"nvap", "≍⃒", NULL}, +{"nvdash", "⊬", NULL}, +{"nvge", "≥⃒", NULL}, +{"nvgt", ">⃒", NULL}, +{"nvinfin", "⧞", NULL}, +{"nvlArr", "⤂", NULL}, +{"nvle", "≤⃒", NULL}, +{"nvlt", "<⃒", NULL}, +{"nvltrie", "⊴⃒", NULL}, +{"nvrArr", "⤃", NULL}, +{"nvrtrie", "⊵⃒", NULL}, +{"nvsim", "∼⃒", NULL}, +{"nwArr", "⇖", NULL}, +{"nwarhk", "⤣", NULL}, +{"nwarr", "↖", NULL}, +{"nwarrow", "↖", NULL}, +{"nwnear", "⤧", NULL}, +{"oS", "Ⓢ", NULL}, +{"oacute", "ó", "ó"}, +{"oast", "⊛", NULL}, +{"ocir", "⊚", NULL}, +{"ocirc", "ô", "ô"}, +{"ocy", "о", NULL}, +{"odash", "⊝", NULL}, +{"odblac", "ő", NULL}, +{"odiv", "⨸", NULL}, +{"odot", "⊙", NULL}, +{"odsold", "⦼", NULL}, +{"oelig", "œ", "œ"}, +{"ofcir", "⦿", NULL}, +{"ofr", "𝔬", NULL}, +{"ogon", "˛", NULL}, +{"ograve", "ò", "ò"}, +{"ogt", "⧁", NULL}, +{"ohbar", "⦵", NULL}, +{"ohm", "Ω", NULL}, +{"oint", "∮", NULL}, +{"olarr", "↺", NULL}, +{"olcir", "⦾", NULL}, +{"olcross", "⦻", NULL}, +{"oline", "‾", "‾"}, +{"olt", "⧀", NULL}, +{"omacr", "ō", NULL}, +{"omega", "ω", "ω"}, +{"omicron", "ο", "ο"}, +{"omid", "⦶", NULL}, +{"ominus", "⊖", NULL}, +{"oopf", "𝕠", NULL}, +{"opar", "⦷", NULL}, +{"operp", "⦹", NULL}, +{"oplus", "⊕", "⊕"}, +{"or", "∨", "∨"}, +{"orarr", "↻", NULL}, +{"ord", "⩝", NULL}, +{"order", "ℴ", NULL}, +{"orderof", "ℴ", NULL}, +{"ordf", "ª", "ª"}, +{"ordm", "º", "º"}, +{"origof", "⊶", NULL}, +{"oror", "⩖", NULL}, +{"orslope", "⩗", NULL}, +{"orv", "⩛", NULL}, +{"oscr", "ℴ", NULL}, +{"oslash", "ø", "ø"}, +{"osol", "⊘", NULL}, +{"otilde", "õ", "õ"}, +{"otimes", "⊗", "⊗"}, +{"otimesas", "⨶", NULL}, +{"ouml", "ö", "ö"}, +{"ovbar", "⌽", NULL}, +{"par", "∥", NULL}, +{"para", "¶", "¶"}, +{"parallel", "∥", NULL}, +{"parsim", "⫳", NULL}, +{"parsl", "⫽", NULL}, +{"part", "∂", "∂"}, +{"pcy", "п", NULL}, +{"percnt", "%", NULL}, +{"period", ".", NULL}, +{"permil", "‰", "‰"}, +{"perp", "⊥", "⊥"}, +{"pertenk", "‱", NULL}, +{"pfr", "𝔭", NULL}, +{"phi", "φ", "φ"}, +{"phiv", "ϕ", NULL}, +{"phmmat", "ℳ", NULL}, +{"phone", "☎", NULL}, +{"pi", "π", "π"}, +{"pitchfork", "⋔", NULL}, +{"piv", "ϖ", "ϖ"}, +{"planck", "ℏ", NULL}, +{"planckh", "ℎ", NULL}, +{"plankv", "ℏ", NULL}, +{"plus", "+", NULL}, +{"plusacir", "⨣", NULL}, +{"plusb", "⊞", NULL}, +{"pluscir", "⨢", NULL}, +{"plusdo", "∔", NULL}, +{"plusdu", "⨥", NULL}, +{"pluse", "⩲", NULL}, +{"plusmn", "±", "±"}, +{"plussim", "⨦", NULL}, +{"plustwo", "⨧", NULL}, +{"pm", "±", NULL}, +{"pointint", "⨕", NULL}, +{"popf", "𝕡", NULL}, +{"pound", "£", "£"}, +{"pr", "≺", NULL}, +{"prE", "⪳", NULL}, +{"prap", "⪷", NULL}, +{"prcue", "≼", NULL}, +{"pre", "⪯", NULL}, +{"prec", "≺", NULL}, +{"precapprox", "⪷", NULL}, +{"preccurlyeq", "≼", NULL}, +{"preceq", "⪯", NULL}, +{"precnapprox", "⪹", NULL}, +{"precneqq", "⪵", NULL}, +{"precnsim", "⋨", NULL}, +{"precsim", "≾", NULL}, +{"prime", "′", "′"}, +{"primes", "ℙ", NULL}, +{"prnE", "⪵", NULL}, +{"prnap", "⪹", NULL}, +{"prnsim", "⋨", NULL}, +{"prod", "∏", "∏"}, +{"profalar", "⌮", NULL}, +{"profline", "⌒", NULL}, +{"profsurf", "⌓", NULL}, +{"prop", "∝", "∝"}, +{"propto", "∝", NULL}, +{"prsim", "≾", NULL}, +{"prurel", "⊰", NULL}, +{"pscr", "𝓅", NULL}, +{"psi", "ψ", "ψ"}, +{"puncsp", " ", NULL}, +{"qfr", "𝔮", NULL}, +{"qint", "⨌", NULL}, +{"qopf", "𝕢", NULL}, +{"qprime", "⁗", NULL}, +{"qscr", "𝓆", NULL}, +{"quaternions", "ℍ", NULL}, +{"quatint", "⨖", NULL}, +{"quest", "?", NULL}, +{"questeq", "≟", NULL}, +{"quot", "\"", "\""}, +{"rAarr", "⇛", NULL}, +{"rArr", "⇒", "⇒"}, +{"rAtail", "⤜", NULL}, +{"rBarr", "⤏", NULL}, +{"rHar", "⥤", NULL}, +{"race", "∽̱", NULL}, +{"racute", "ŕ", NULL}, +{"radic", "√", "√"}, +{"raemptyv", "⦳", NULL}, +{"rang", "⟩", "〉"}, +{"rangd", "⦒", NULL}, +{"range", "⦥", NULL}, +{"rangle", "⟩", NULL}, +{"raquo", "»", "»"}, +{"rarr", "→", "→"}, +{"rarrap", "⥵", NULL}, +{"rarrb", "⇥", NULL}, +{"rarrbfs", "⤠", NULL}, +{"rarrc", "⤳", NULL}, +{"rarrfs", "⤞", NULL}, +{"rarrhk", "↪", NULL}, +{"rarrlp", "↬", NULL}, +{"rarrpl", "⥅", NULL}, +{"rarrsim", "⥴", NULL}, +{"rarrtl", "↣", NULL}, +{"rarrw", "↝", NULL}, +{"ratail", "⤚", NULL}, +{"ratio", "∶", NULL}, +{"rationals", "ℚ", NULL}, +{"rbarr", "⤍", NULL}, +{"rbbrk", "❳", NULL}, +{"rbrace", "}", NULL}, +{"rbrack", "]", NULL}, +{"rbrke", "⦌", NULL}, +{"rbrksld", "⦎", NULL}, +{"rbrkslu", "⦐", NULL}, +{"rcaron", "ř", NULL}, +{"rcedil", "ŗ", NULL}, +{"rceil", "⌉", "⌉"}, +{"rcub", "}", NULL}, +{"rcy", "р", NULL}, +{"rdca", "⤷", NULL}, +{"rdldhar", "⥩", NULL}, +{"rdquo", "”", "”"}, +{"rdquor", "”", NULL}, +{"rdsh", "↳", NULL}, +{"real", "ℜ", "ℜ"}, +{"realine", "ℛ", NULL}, +{"realpart", "ℜ", NULL}, +{"reals", "ℝ", NULL}, +{"rect", "▭", NULL}, +{"reg", "®", "®"}, +{"rfisht", "⥽", NULL}, +{"rfloor", "⌋", "⌋"}, +{"rfr", "𝔯", NULL}, +{"rhard", "⇁", NULL}, +{"rharu", "⇀", NULL}, +{"rharul", "⥬", NULL}, +{"rho", "ρ", "ρ"}, +{"rhov", "ϱ", NULL}, +{"rightarrow", "→", NULL}, +{"rightarrowtail", "↣", NULL}, +{"rightharpoondown", "⇁", NULL}, +{"rightharpoonup", "⇀", NULL}, +{"rightleftarrows", "⇄", NULL}, +{"rightleftharpoons", "⇌", NULL}, +{"rightrightarrows", "⇉", NULL}, +{"rightsquigarrow", "↝", NULL}, +{"rightthreetimes", "⋌", NULL}, +{"ring", "˚", NULL}, +{"risingdotseq", "≓", NULL}, +{"rlarr", "⇄", NULL}, +{"rlhar", "⇌", NULL}, +{"rlm", "", ""}, +{"rmoust", "⎱", NULL}, +{"rmoustache", "⎱", NULL}, +{"rnmid", "⫮", NULL}, +{"roang", "⟭", NULL}, +{"roarr", "⇾", NULL}, +{"robrk", "⟧", NULL}, +{"ropar", "⦆", NULL}, +{"ropf", "𝕣", NULL}, +{"roplus", "⨮", NULL}, +{"rotimes", "⨵", NULL}, +{"rpar", ")", NULL}, +{"rpargt", "⦔", NULL}, +{"rppolint", "⨒", NULL}, +{"rrarr", "⇉", NULL}, +{"rsaquo", "›", "›"}, +{"rscr", "𝓇", NULL}, +{"rsh", "↱", NULL}, +{"rsqb", "]", NULL}, +{"rsquo", "’", "’"}, +{"rsquor", "’", NULL}, +{"rthree", "⋌", NULL}, +{"rtimes", "⋊", NULL}, +{"rtri", "▹", NULL}, +{"rtrie", "⊵", NULL}, +{"rtrif", "▸", NULL}, +{"rtriltri", "⧎", NULL}, +{"ruluhar", "⥨", NULL}, +{"rx", "℞", NULL}, +{"sacute", "ś", NULL}, +{"sbquo", "‚", "‚"}, +{"sc", "≻", NULL}, +{"scE", "⪴", NULL}, +{"scap", "⪸", NULL}, +{"scaron", "š", "š"}, +{"sccue", "≽", NULL}, +{"sce", "⪰", NULL}, +{"scedil", "ş", NULL}, +{"scirc", "ŝ", NULL}, +{"scnE", "⪶", NULL}, +{"scnap", "⪺", NULL}, +{"scnsim", "⋩", NULL}, +{"scpolint", "⨓", NULL}, +{"scsim", "≿", NULL}, +{"scy", "с", NULL}, +{"sdot", "⋅", "⋅"}, +{"sdotb", "⊡", NULL}, +{"sdote", "⩦", NULL}, +{"seArr", "⇘", NULL}, +{"searhk", "⤥", NULL}, +{"searr", "↘", NULL}, +{"searrow", "↘", NULL}, +{"sect", "§", "§"}, +{"semi", ";", NULL}, +{"seswar", "⤩", NULL}, +{"setminus", "∖", NULL}, +{"setmn", "∖", NULL}, +{"sext", "✶", NULL}, +{"sfr", "𝔰", NULL}, +{"sfrown", "⌢", NULL}, +{"sharp", "♯", NULL}, +{"shchcy", "щ", NULL}, +{"shcy", "ш", NULL}, +{"shortmid", "∣", NULL}, +{"shortparallel", "∥", NULL}, +{"shy", "", ""}, +{"sigma", "σ", "σ"}, +{"sigmaf", "ς", "ς"}, +{"sigmav", "ς", NULL}, +{"sim", "∼", "∼"}, +{"simdot", "⩪", NULL}, +{"sime", "≃", NULL}, +{"simeq", "≃", NULL}, +{"simg", "⪞", NULL}, +{"simgE", "⪠", NULL}, +{"siml", "⪝", NULL}, +{"simlE", "⪟", NULL}, +{"simne", "≆", NULL}, +{"simplus", "⨤", NULL}, +{"simrarr", "⥲", NULL}, +{"slarr", "←", NULL}, +{"smallsetminus", "∖", NULL}, +{"smashp", "⨳", NULL}, +{"smeparsl", "⧤", NULL}, +{"smid", "∣", NULL}, +{"smile", "⌣", NULL}, +{"smt", "⪪", NULL}, +{"smte", "⪬", NULL}, +{"smtes", "⪬︀", NULL}, +{"softcy", "ь", NULL}, +{"sol", "/", NULL}, +{"solb", "⧄", NULL}, +{"solbar", "⌿", NULL}, +{"sopf", "𝕤", NULL}, +{"spades", "♠", "♠"}, +{"spadesuit", "♠", NULL}, +{"spar", "∥", NULL}, +{"sqcap", "⊓", NULL}, +{"sqcaps", "⊓︀", NULL}, +{"sqcup", "⊔", NULL}, +{"sqcups", "⊔︀", NULL}, +{"sqsub", "⊏", NULL}, +{"sqsube", "⊑", NULL}, +{"sqsubset", "⊏", NULL}, +{"sqsubseteq", "⊑", NULL}, +{"sqsup", "⊐", NULL}, +{"sqsupe", "⊒", NULL}, +{"sqsupset", "⊐", NULL}, +{"sqsupseteq", "⊒", NULL}, +{"squ", "□", NULL}, +{"square", "□", NULL}, +{"squarf", "▪", NULL}, +{"squf", "▪", NULL}, +{"srarr", "→", NULL}, +{"sscr", "𝓈", NULL}, +{"ssetmn", "∖", NULL}, +{"ssmile", "⌣", NULL}, +{"sstarf", "⋆", NULL}, +{"star", "☆", NULL}, +{"starf", "★", NULL}, +{"straightepsilon", "ϵ", NULL}, +{"straightphi", "ϕ", NULL}, +{"strns", "¯", NULL}, +{"sub", "⊂", "⊂"}, +{"subE", "⫅", NULL}, +{"subdot", "⪽", NULL}, +{"sube", "⊆", "⊆"}, +{"subedot", "⫃", NULL}, +{"submult", "⫁", NULL}, +{"subnE", "⫋", NULL}, +{"subne", "⊊", NULL}, +{"subplus", "⪿", NULL}, +{"subrarr", "⥹", NULL}, +{"subset", "⊂", NULL}, +{"subseteq", "⊆", NULL}, +{"subseteqq", "⫅", NULL}, +{"subsetneq", "⊊", NULL}, +{"subsetneqq", "⫋", NULL}, +{"subsim", "⫇", NULL}, +{"subsub", "⫕", NULL}, +{"subsup", "⫓", NULL}, +{"succ", "≻", NULL}, +{"succapprox", "⪸", NULL}, +{"succcurlyeq", "≽", NULL}, +{"succeq", "⪰", NULL}, +{"succnapprox", "⪺", NULL}, +{"succneqq", "⪶", NULL}, +{"succnsim", "⋩", NULL}, +{"succsim", "≿", NULL}, +{"sum", "∑", "∑"}, +{"sung", "♪", NULL}, +{"sup", "⊃", "⊃"}, +{"sup1", "¹", "¹"}, +{"sup2", "²", "²"}, +{"sup3", "³", "³"}, +{"supE", "⫆", NULL}, +{"supdot", "⪾", NULL}, +{"supdsub", "⫘", NULL}, +{"supe", "⊇", "⊇"}, +{"supedot", "⫄", NULL}, +{"suphsol", "⟉", NULL}, +{"suphsub", "⫗", NULL}, +{"suplarr", "⥻", NULL}, +{"supmult", "⫂", NULL}, +{"supnE", "⫌", NULL}, +{"supne", "⊋", NULL}, +{"supplus", "⫀", NULL}, +{"supset", "⊃", NULL}, +{"supseteq", "⊇", NULL}, +{"supseteqq", "⫆", NULL}, +{"supsetneq", "⊋", NULL}, +{"supsetneqq", "⫌", NULL}, +{"supsim", "⫈", NULL}, +{"supsub", "⫔", NULL}, +{"supsup", "⫖", NULL}, +{"swArr", "⇙", NULL}, +{"swarhk", "⤦", NULL}, +{"swarr", "↙", NULL}, +{"swarrow", "↙", NULL}, +{"swnwar", "⤪", NULL}, +{"szlig", "ß", "ß"}, +{"target", "⌖", NULL}, +{"tau", "τ", "τ"}, +{"tbrk", "⎴", NULL}, +{"tcaron", "ť", NULL}, +{"tcedil", "ţ", NULL}, +{"tcy", "т", NULL}, +{"tdot", "⃛", NULL}, +{"telrec", "⌕", NULL}, +{"tfr", "𝔱", NULL}, +{"there4", "∴", "∴"}, +{"therefore", "∴", NULL}, +{"theta", "θ", "θ"}, +{"thetasym", "ϑ", "ϑ"}, +{"thetav", "ϑ", NULL}, +{"thickapprox", "≈", NULL}, +{"thicksim", "∼", NULL}, +{"thinsp", " ", " "}, +{"thkap", "≈", NULL}, +{"thksim", "∼", NULL}, +{"thorn", "þ", "þ"}, +{"tilde", "˜", "˜"}, +{"times", "×", "×"}, +{"timesb", "⊠", NULL}, +{"timesbar", "⨱", NULL}, +{"timesd", "⨰", NULL}, +{"tint", "∭", NULL}, +{"toea", "⤨", NULL}, +{"top", "⊤", NULL}, +{"topbot", "⌶", NULL}, +{"topcir", "⫱", NULL}, +{"topf", "𝕥", NULL}, +{"topfork", "⫚", NULL}, +{"tosa", "⤩", NULL}, +{"tprime", "‴", NULL}, +{"trade", "™", "™"}, +{"triangle", "▵", NULL}, +{"triangledown", "▿", NULL}, +{"triangleleft", "◃", NULL}, +{"trianglelefteq", "⊴", NULL}, +{"triangleq", "≜", NULL}, +{"triangleright", "▹", NULL}, +{"trianglerighteq", "⊵", NULL}, +{"tridot", "◬", NULL}, +{"trie", "≜", NULL}, +{"triminus", "⨺", NULL}, +{"triplus", "⨹", NULL}, +{"trisb", "⧍", NULL}, +{"tritime", "⨻", NULL}, +{"trpezium", "⏢", NULL}, +{"tscr", "𝓉", NULL}, +{"tscy", "ц", NULL}, +{"tshcy", "ћ", NULL}, +{"tstrok", "ŧ", NULL}, +{"twixt", "≬", NULL}, +{"twoheadleftarrow", "↞", NULL}, +{"twoheadrightarrow", "↠", NULL}, +{"uArr", "⇑", "⇑"}, +{"uHar", "⥣", NULL}, +{"uacute", "ú", "ú"}, +{"uarr", "↑", "↑"}, +{"ubrcy", "ў", NULL}, +{"ubreve", "ŭ", NULL}, +{"ucirc", "û", "û"}, +{"ucy", "у", NULL}, +{"udarr", "⇅", NULL}, +{"udblac", "ű", NULL}, +{"udhar", "⥮", NULL}, +{"ufisht", "⥾", NULL}, +{"ufr", "𝔲", NULL}, +{"ugrave", "ù", "ù"}, +{"uharl", "↿", NULL}, +{"uharr", "↾", NULL}, +{"uhblk", "▀", NULL}, +{"ulcorn", "⌜", NULL}, +{"ulcorner", "⌜", NULL}, +{"ulcrop", "⌏", NULL}, +{"ultri", "◸", NULL}, +{"umacr", "ū", NULL}, +{"uml", "¨", "¨"}, +{"uogon", "ų", NULL}, +{"uopf", "𝕦", NULL}, +{"uparrow", "↑", NULL}, +{"updownarrow", "↕", NULL}, +{"upharpoonleft", "↿", NULL}, +{"upharpoonright", "↾", NULL}, +{"uplus", "⊎", NULL}, +{"upsi", "υ", NULL}, +{"upsih", "ϒ", "ϒ"}, +{"upsilon", "υ", "υ"}, +{"upuparrows", "⇈", NULL}, +{"urcorn", "⌝", NULL}, +{"urcorner", "⌝", NULL}, +{"urcrop", "⌎", NULL}, +{"uring", "ů", NULL}, +{"urtri", "◹", NULL}, +{"uscr", "𝓊", NULL}, +{"utdot", "⋰", NULL}, +{"utilde", "ũ", NULL}, +{"utri", "▵", NULL}, +{"utrif", "▴", NULL}, +{"uuarr", "⇈", NULL}, +{"uuml", "ü", "ü"}, +{"uwangle", "⦧", NULL}, +{"vArr", "⇕", NULL}, +{"vBar", "⫨", NULL}, +{"vBarv", "⫩", NULL}, +{"vDash", "⊨", NULL}, +{"vangrt", "⦜", NULL}, +{"varepsilon", "ϵ", NULL}, +{"varkappa", "ϰ", NULL}, +{"varnothing", "∅", NULL}, +{"varphi", "ϕ", NULL}, +{"varpi", "ϖ", NULL}, +{"varpropto", "∝", NULL}, +{"varr", "↕", NULL}, +{"varrho", "ϱ", NULL}, +{"varsigma", "ς", NULL}, +{"varsubsetneq", "⊊︀", NULL}, +{"varsubsetneqq", "⫋︀", NULL}, +{"varsupsetneq", "⊋︀", NULL}, +{"varsupsetneqq", "⫌︀", NULL}, +{"vartheta", "ϑ", NULL}, +{"vartriangleleft", "⊲", NULL}, +{"vartriangleright", "⊳", NULL}, +{"vcy", "в", NULL}, +{"vdash", "⊢", NULL}, +{"vee", "∨", NULL}, +{"veebar", "⊻", NULL}, +{"veeeq", "≚", NULL}, +{"vellip", "⋮", NULL}, +{"verbar", "|", NULL}, +{"vert", "|", NULL}, +{"vfr", "𝔳", NULL}, +{"vltri", "⊲", NULL}, +{"vnsub", "⊂⃒", NULL}, +{"vnsup", "⊃⃒", NULL}, +{"vopf", "𝕧", NULL}, +{"vprop", "∝", NULL}, +{"vrtri", "⊳", NULL}, +{"vscr", "𝓋", NULL}, +{"vsubnE", "⫋︀", NULL}, +{"vsubne", "⊊︀", NULL}, +{"vsupnE", "⫌︀", NULL}, +{"vsupne", "⊋︀", NULL}, +{"vzigzag", "⦚", NULL}, +{"wcirc", "ŵ", NULL}, +{"wedbar", "⩟", NULL}, +{"wedge", "∧", NULL}, +{"wedgeq", "≙", NULL}, +{"weierp", "℘", "℘"}, +{"wfr", "𝔴", NULL}, +{"wopf", "𝕨", NULL}, +{"wp", "℘", NULL}, +{"wr", "≀", NULL}, +{"wreath", "≀", NULL}, +{"wscr", "𝓌", NULL}, +{"xcap", "⋂", NULL}, +{"xcirc", "◯", NULL}, +{"xcup", "⋃", NULL}, +{"xdtri", "▽", NULL}, +{"xfr", "𝔵", NULL}, +{"xhArr", "⟺", NULL}, +{"xharr", "⟷", NULL}, +{"xi", "ξ", "ξ"}, +{"xlArr", "⟸", NULL}, +{"xlarr", "⟵", NULL}, +{"xmap", "⟼", NULL}, +{"xnis", "⋻", NULL}, +{"xodot", "⨀", NULL}, +{"xopf", "𝕩", NULL}, +{"xoplus", "⨁", NULL}, +{"xotime", "⨂", NULL}, +{"xrArr", "⟹", NULL}, +{"xrarr", "⟶", NULL}, +{"xscr", "𝓍", NULL}, +{"xsqcup", "⨆", NULL}, +{"xuplus", "⨄", NULL}, +{"xutri", "△", NULL}, +{"xvee", "⋁", NULL}, +{"xwedge", "⋀", NULL}, +{"yacute", "ý", "ý"}, +{"yacy", "я", NULL}, +{"ycirc", "ŷ", NULL}, +{"ycy", "ы", NULL}, +{"yen", "¥", "¥"}, +{"yfr", "𝔶", NULL}, +{"yicy", "ї", NULL}, +{"yopf", "𝕪", NULL}, +{"yscr", "𝓎", NULL}, +{"yucy", "ю", NULL}, +{"yuml", "ÿ", "ÿ"}, +{"zacute", "ź", NULL}, +{"zcaron", "ž", NULL}, +{"zcy", "з", NULL}, +{"zdot", "ż", NULL}, +{"zeetrf", "ℨ", NULL}, +{"zeta", "ζ", "ζ"}, +{"zfr", "𝔷", NULL}, +{"zhcy", "ж", NULL}, +{"zigrarr", "⇝", NULL}, +{"zopf", "𝕫", NULL}, +{"zscr", "𝓏", NULL}, +{"zwj", "", ""}, +{"zwnj", "", ""}, +}; +#endif /* HTML_CHARREFS_H */ diff --git a/src/html_common.hh b/src/html_common.hh index 147807b3..68ed0d08 100644 --- a/src/html_common.hh +++ b/src/html_common.hh @@ -156,8 +156,7 @@ public: //BUG: for now everything is public char *content_type, *charset; bool stop_parser; - size_t CurrTagOfs; - size_t OldTagOfs, OldTagLine; + size_t CurrOfs, OldOfs, OldLine; DilloHtmlDocumentType DocType; /* as given by DOCTYPE tag */ float DocTypeVersion; /* HTML or XHTML version number */ @@ -211,7 +210,7 @@ public: void bugMessage(const char *format, ... ); void connectSignals(dw::core::Widget *dw); void write(char *Buf, int BufSize, int Eof); - int getCurTagLineNumber(); + int getCurrLineNumber(); void finishParsing(int ClientKey); int formNew(DilloHtmlMethod method, const DilloUrl *action, DilloHtmlEnc enc, const char *charset); diff --git a/src/image.cc b/src/image.cc index 9915023a..97270eef 100644 --- a/src/image.cc +++ b/src/image.cc @@ -106,9 +106,11 @@ void a_Image_set_parms(DilloImage *Image, void *v_imgbuf, DilloUrl *url, int version, uint_t width, uint_t height, DilloImgType type) { - _MSG("a_Image_set_parms: width=%d height=%d\n", width, height); + _MSG("a_Image_set_parms: width=%d height=%d iw=%d ih=%d\n", + width, height, Image->width, Image->height); - bool resize = (Image->width != width || Image->height != height); + /* Resize from 0,0 to width,height */ + bool resize = true; I2IR(Image)->setBuffer((Imgbuf*)v_imgbuf, resize); if (!Image->BitVec) @@ -304,6 +304,7 @@ static void Jpeg_write(DilloJpeg *jpeg, void *Buf, uint_t BufSize) (uint_t)jpeg->cinfo.image_width, (uint_t)jpeg->cinfo.image_height, type, 1 / 2.2); + jpeg->Image = NULL; /* safeguard: may be freed by its owner later */ /* decompression step 4 (see libjpeg.doc) */ jpeg->state = DILLO_JPEG_STARTING; diff --git a/src/klist.c b/src/klist.c index 813269a3..e5e695e2 100644 --- a/src/klist.c +++ b/src/klist.c @@ -74,7 +74,7 @@ int a_Klist_insert(Klist_t **Klist, void *Data) a_Klist_get_data((*Klist), (*Klist)->Counter)); Node = dNew(KlistNode_t, 1); - Node->Key = (*Klist)->Counter; + Node->Key = (*Klist)->Counter; Node->Data = Data; dList_insert_sorted((*Klist)->List, Node, Klist_node_by_node_cmp); return (*Klist)->Counter; diff --git a/src/menu.cc b/src/menu.cc index b93106e1..e86c3a06 100644 --- a/src/menu.cc +++ b/src/menu.cc @@ -232,17 +232,31 @@ static void Menu_stylesheet_cb(Fl_Widget*, void *vUrl) } } +static void Menu_bugmeter_validate(const char *validator_url) +{ + if (popup_url && + dStrAsciiCasecmp(URL_SCHEME(popup_url), "dpi")) { + const char *popup_str = URL_STR(popup_url), + *ptr = strrchr(popup_str, '#'); + char *no_fragment = ptr ? dStrndup(popup_str, ptr - popup_str) + : dStrdup(popup_str); + char *encoded = a_Url_encode_hex_str(no_fragment); + Dstr *dstr = dStr_sized_new(128); + + dStr_sprintf(dstr, validator_url, encoded); + a_UIcmd_open_urlstr(popup_bw, dstr->str); + dStr_free(dstr, 1); + dFree(encoded); + dFree(no_fragment); + } +} + /* * Validate URL with the W3C */ static void Menu_bugmeter_validate_w3c_cb(Fl_Widget*, void*) { - Dstr *dstr = dStr_sized_new(128); - - dStr_sprintf(dstr, "http://validator.w3.org/check?uri=%s", - URL_STR(popup_url)); - a_UIcmd_open_urlstr(popup_bw, dstr->str); - dStr_free(dstr, 1); + Menu_bugmeter_validate("http://validator.w3.org/check?uri=%s"); } /* @@ -250,13 +264,8 @@ static void Menu_bugmeter_validate_w3c_cb(Fl_Widget*, void*) */ static void Menu_bugmeter_validate_wdg_cb(Fl_Widget*, void*) { - Dstr *dstr = dStr_sized_new(128); - - dStr_sprintf(dstr, - "http://www.htmlhelp.org/cgi-bin/validate.cgi?url=%s&warnings=yes", - URL_STR(popup_url)); - a_UIcmd_open_urlstr(popup_bw, dstr->str); - dStr_free(dstr, 1); + Menu_bugmeter_validate( + "http://www.htmlhelp.org/cgi-bin/validate.cgi?url=%s&warnings=yes"); } /* diff --git a/src/paths.cc b/src/paths.cc index 32478728..bb233de8 100644 --- a/src/paths.cc +++ b/src/paths.cc @@ -38,16 +38,16 @@ void Paths::init(void) oldWorkingDir = dGetcwd(); rc = chdir("/tmp"); if (rc == -1) { - MSG("paths: error changing directory to /tmp: %s\n", + MSG("paths: Error changing directory to /tmp: %s\n", dStrerror(errno)); } path = dStrconcat(dGethomedir(), "/.dillo", NULL); if (stat(path, &st) == -1) { if (errno == ENOENT) { - MSG("paths: creating directory %s.\n", path); + MSG("paths: Creating directory '%s/'\n", path); if (mkdir(path, 0700) < 0) { - MSG("paths: error creating directory %s: %s\n", + MSG("paths: Error creating directory %s: %s\n", path, dStrerror(errno)); } } else { @@ -62,6 +62,7 @@ typedef struct { DilloImage *Image; /* Image meta data */ DilloUrl *url; /* Primary Key for the dicache */ int version; /* Secondary Key for the dicache */ + int bgcolor; /* Parent widget background color */ png_uint_32 width; /* png image width */ png_uint_32 height; /* png image height */ @@ -102,8 +103,8 @@ void Png_error_handling(png_structp png_ptr, png_const_charp msg) { DilloPng *png; - MSG("Png_error_handling: %s\n", msg); png = png_get_error_ptr(png_ptr); + MSG("Png_error_handling: %s: %s\n", URL_STR(png->url), msg); png->error = 1; png->state = IS_finished; @@ -204,6 +205,7 @@ Png_datainfo_callback(png_structp png_ptr, png_infop info_ptr) a_Dicache_set_parms(png->url, png->version, png->Image, (uint_t)png->width, (uint_t)png->height, DILLO_IMG_TYPE_RGB, file_gamma); + png->Image = NULL; /* safeguard: hereafter it may be freed by its owner */ } static void @@ -244,9 +246,9 @@ static void /* TODO: maybe change prefs.bg_color to `a_Dw_widget_get_bg_color`, * when background colors are correctly implementated */ - bg_blue = (png->Image->bg_color) & 0xFF; - bg_green = (png->Image->bg_color>>8) & 0xFF; - bg_red = (png->Image->bg_color>>16) & 0xFF; + bg_blue = (png->bgcolor) & 0xFF; + bg_green = (png->bgcolor>>8) & 0xFF; + bg_red = (png->bgcolor>>16) & 0xFF; for (i = 0; i < png->width; i++) { a = *(data+3); @@ -433,6 +435,7 @@ void *a_Png_new(DilloImage *Image, DilloUrl *url, int version) png->Image = Image; png->url = url; png->version = version; + png->bgcolor = Image->bg_color; png->error = 0; png->ipbuf = NULL; png->ipbufstart = 0; diff --git a/src/prefs.c b/src/prefs.c index fbd17f33..abcbfcd0 100644 --- a/src/prefs.c +++ b/src/prefs.c @@ -63,10 +63,13 @@ void a_Prefs_init(void) prefs.http_language = NULL; prefs.http_proxy = NULL; prefs.http_max_conns = 6; + prefs.http_persistent_conns = FALSE; prefs.http_proxyuser = NULL; prefs.http_referer = dStrdup(PREFS_HTTP_REFERER); prefs.http_user_agent = dStrdup(PREFS_HTTP_USER_AGENT); prefs.limit_text_width = FALSE; + prefs.adjust_min_width = FALSE; + prefs.adjust_table_min_width = TRUE; prefs.load_images=TRUE; prefs.load_background_images=FALSE; prefs.load_stylesheets=TRUE; diff --git a/src/prefs.h b/src/prefs.h index bb97651e..ac52786e 100644 --- a/src/prefs.h +++ b/src/prefs.h @@ -66,6 +66,8 @@ typedef struct { int panel_size; bool_t small_icons; bool_t limit_text_width; + bool_t adjust_min_width; + bool_t adjust_table_min_width; bool_t w3c_plus_heuristics; bool_t focus_new_tab; double font_factor; @@ -91,6 +93,7 @@ typedef struct { bool_t load_background_images; bool_t load_stylesheets; bool_t parse_embedded_css; + bool_t http_persistent_conns; int32_t buffered_drawing; char *font_serif; char *font_sans_serif; diff --git a/src/prefsparser.cc b/src/prefsparser.cc index 81b097e7..d54d017b 100644 --- a/src/prefsparser.cc +++ b/src/prefsparser.cc @@ -73,11 +73,14 @@ int PrefsParser::parseOption(char *name, char *value) { "home", &prefs.home, PREFS_URL }, { "http_language", &prefs.http_language, PREFS_STRING }, { "http_max_conns", &prefs.http_max_conns, PREFS_INT32 }, + { "http_persistent_conns", &prefs.http_persistent_conns, PREFS_BOOL }, { "http_proxy", &prefs.http_proxy, PREFS_URL }, { "http_proxyuser", &prefs.http_proxyuser, PREFS_STRING }, { "http_referer", &prefs.http_referer, PREFS_STRING }, { "http_user_agent", &prefs.http_user_agent, PREFS_STRING }, { "limit_text_width", &prefs.limit_text_width, PREFS_BOOL }, + { "adjust_min_width", &prefs.adjust_min_width, PREFS_BOOL }, + { "adjust_table_min_width", &prefs.adjust_table_min_width, PREFS_BOOL }, { "load_images", &prefs.load_images, PREFS_BOOL }, { "load_background_images", &prefs.load_background_images, PREFS_BOOL }, { "load_stylesheets", &prefs.load_stylesheets, PREFS_BOOL }, diff --git a/src/styleengine.cc b/src/styleengine.cc index e07ab3d5..98b02b69 100644 --- a/src/styleengine.cc +++ b/src/styleengine.cc @@ -71,6 +71,7 @@ StyleEngine::StyleEngine (dw::core::Layout *layout, this->pageUrl = pageUrl ? a_Url_dup(pageUrl) : NULL; this->baseUrl = baseUrl ? a_Url_dup(baseUrl) : NULL; importDepth = 0; + dpmm = layout->dpiX () / 25.4; /* assume dpiX == dpiY */ stackPush (); Node *n = stack->getLastRef (); @@ -112,7 +113,7 @@ StyleEngine::~StyleEngine () { void StyleEngine::stackPush () { static const Node emptyNode = { - NULL, NULL, NULL, NULL, NULL, NULL, false, NULL + NULL, NULL, NULL, NULL, NULL, NULL, false, false, NULL }; stack->setSize (stack->size () + 1, emptyNode); @@ -145,6 +146,8 @@ void StyleEngine::startElement (int element, BrowserWindow *bw) { dn->element = element; n->doctreeNode = dn; + if (stack->size () > 1) + n->displayNone = stack->getRef (stack->size () - 2)->displayNone; } void StyleEngine::startElement (const char *tagname, BrowserWindow *bw) { @@ -152,7 +155,7 @@ void StyleEngine::startElement (const char *tagname, BrowserWindow *bw) { } void StyleEngine::setId (const char *id) { - DoctreeNode *dn = doctree->top (); + DoctreeNode *dn = doctree->top (); assert (dn->id == NULL); dn->id = dStrdup (id); } @@ -364,8 +367,8 @@ void StyleEngine::apply (int i, StyleAttrs *attrs, CssPropertyList *props, DilloUrl *imgUrl = NULL; /* Determine font first so it can be used to resolve relative lengths. */ - for (int i = 0; i < props->size (); i++) { - CssProperty *p = props->getRef (i); + for (int j = 0; j < props->size (); j++) { + CssProperty *p = props->getRef (j); switch (p->name) { case CSS_PROPERTY_FONT_FAMILY: @@ -512,8 +515,8 @@ void StyleEngine::apply (int i, StyleAttrs *attrs, CssPropertyList *props, attrs->font = Font::create (layout, &fontAttrs); - for (int i = 0; i < props->size (); i++) { - CssProperty *p = props->getRef (i); + for (int j = 0; j < props->size (); j++) { + CssProperty *p = props->getRef (j); switch (p->name) { /* \todo missing cases */ @@ -588,6 +591,12 @@ void StyleEngine::apply (int i, StyleAttrs *attrs, CssPropertyList *props, computeValue (&attrs->hBorderSpacing, p->value.intVal,attrs->font); computeValue (&attrs->vBorderSpacing, p->value.intVal,attrs->font); break; + case CSS_PROPERTY_BOTTOM: + computeLength (&attrs->bottom, p->value.intVal, attrs->font); + break; + case CSS_PROPERTY_CLEAR: + attrs->clear = (ClearType) p->value.intVal; + break; case CSS_PROPERTY_COLOR: attrs->color = Color::create (layout, p->value.intVal); break; @@ -596,6 +605,14 @@ void StyleEngine::apply (int i, StyleAttrs *attrs, CssPropertyList *props, break; case CSS_PROPERTY_DISPLAY: attrs->display = (DisplayType) p->value.intVal; + if (attrs->display == DISPLAY_NONE) + stack->getRef (i)->displayNone = true; + break; + case CSS_PROPERTY_FLOAT: + attrs->vloat = (FloatType) p->value.intVal; + break; + case CSS_PROPERTY_LEFT: + computeLength (&attrs->left, p->value.intVal, attrs->font); break; case CSS_PROPERTY_LINE_HEIGHT: if (p->type == CSS_TYPE_ENUM) { //only valid enum value is "normal" @@ -636,6 +653,9 @@ void StyleEngine::apply (int i, StyleAttrs *attrs, CssPropertyList *props, if (attrs->margin.top < 0) // \todo fix negative margins in dw/* attrs->margin.top = 0; break; + case CSS_PROPERTY_OVERFLOW: + attrs->overflow = (Overflow) p->value.intVal; + break; case CSS_PROPERTY_PADDING_TOP: computeValue (&attrs->padding.top, p->value.intVal, attrs->font); break; @@ -648,6 +668,12 @@ void StyleEngine::apply (int i, StyleAttrs *attrs, CssPropertyList *props, case CSS_PROPERTY_PADDING_RIGHT: computeValue (&attrs->padding.right, p->value.intVal, attrs->font); break; + case CSS_PROPERTY_POSITION: + attrs->position = (Position) p->value.intVal; + break; + case CSS_PROPERTY_RIGHT: + computeLength (&attrs->right, p->value.intVal, attrs->font); + break; case CSS_PROPERTY_TEXT_ALIGN: attrs->textAlign = (TextAlignType) p->value.intVal; break; @@ -660,6 +686,9 @@ void StyleEngine::apply (int i, StyleAttrs *attrs, CssPropertyList *props, case CSS_PROPERTY_TEXT_TRANSFORM: attrs->textTransform = (TextTransform) p->value.intVal; break; + case CSS_PROPERTY_TOP: + computeLength (&attrs->top, p->value.intVal, attrs->font); + break; case CSS_PROPERTY_VERTICAL_ALIGN: attrs->valign = (VAlignType) p->value.intVal; break; @@ -687,6 +716,18 @@ void StyleEngine::apply (int i, StyleAttrs *attrs, CssPropertyList *props, else if (attrs->wordSpacing < -1000) attrs->wordSpacing = -1000; break; + case CSS_PROPERTY_MIN_WIDTH: + computeLength (&attrs->minWidth, p->value.intVal, attrs->font); + break; + case CSS_PROPERTY_MAX_WIDTH: + computeLength (&attrs->maxWidth, p->value.intVal, attrs->font); + break; + case CSS_PROPERTY_MIN_HEIGHT: + computeLength (&attrs->minHeight, p->value.intVal, attrs->font); + break; + case CSS_PROPERTY_MAX_HEIGHT: + computeLength (&attrs->maxHeight, p->value.intVal, attrs->font); + break; case PROPERTY_X_LINK: attrs->x_link = p->value.intVal; break; @@ -709,7 +750,7 @@ void StyleEngine::apply (int i, StyleAttrs *attrs, CssPropertyList *props, } if (imgUrl && prefs.load_background_images && - attrs->display != DISPLAY_NONE && + !stack->getRef (i)->displayNone && !(URL_FLAGS(pageUrl) & URL_SpamSafe)) { attrs->backgroundImage = StyleImage::create(); @@ -741,11 +782,6 @@ void StyleEngine::apply (int i, StyleAttrs *attrs, CssPropertyList *props, * \brief Resolve relative lengths to absolute values. */ bool StyleEngine::computeValue (int *dest, CssLength value, Font *font) { - static float dpmm; - - if (dpmm == 0.0) - dpmm = layout->dpiX () / 25.4; /* assume dpiX == dpiY */ - switch (CSS_LENGTH_TYPE (value)) { case CSS_LENGTH_TYPE_PX: *dest = (int) CSS_LENGTH_VALUE (value); diff --git a/src/styleengine.hh b/src/styleengine.hh index 41f892d7..db3e3b85 100644 --- a/src/styleengine.hh +++ b/src/styleengine.hh @@ -27,6 +27,7 @@ class StyleEngine { dw::core::style::Style *wordStyle; dw::core::style::Style *backgroundStyle; bool inheritBackgroundColor; + bool displayNone; DoctreeNode *doctreeNode; }; @@ -35,6 +36,7 @@ class StyleEngine { CssContext *cssContext; Doctree *doctree; int importDepth; + float dpmm; DilloUrl *pageUrl, *baseUrl; void stackPush (); diff --git a/src/table.cc b/src/table.cc index a3002ebf..188becbc 100644 --- a/src/table.cc +++ b/src/table.cc @@ -15,6 +15,7 @@ #include "dw/style.hh" #include "dw/textblock.hh" #include "dw/table.hh" +#include "dw/simpletablecell.hh" #include "prefs.h" #include "msg.h" @@ -48,13 +49,13 @@ void Html_tag_open_table(DilloHtml *html, const char *tag, int tagsize) if ((attrbuf = a_Html_get_attr(html, tag, tagsize, "cellspacing"))) { cellspacing = strtol (attrbuf, NULL, 10); if (html->DocType == DT_HTML && html->DocTypeVersion >= 5.0f) - BUG_MSG("<table> cellspacing attribute is obsolete.\n"); + BUG_MSG("<table> cellspacing attribute is obsolete."); } if ((attrbuf = a_Html_get_attr(html, tag, tagsize, "cellpadding"))) { cellpadding = strtol (attrbuf, NULL, 10); if (html->DocType == DT_HTML && html->DocTypeVersion >= 5.0f) - BUG_MSG("<table> cellpadding attribute is obsolete.\n"); + BUG_MSG("<table> cellpadding attribute is obsolete."); } if (border != -1) { @@ -88,7 +89,7 @@ void Html_tag_open_table(DilloHtml *html, const char *tag, int tagsize) CSS_TYPE_LENGTH_PERCENTAGE, a_Html_parse_length (html, attrbuf)); if (html->DocType == DT_HTML && html->DocTypeVersion >= 5.0f) - BUG_MSG("<table> width attribute is obsolete.\n"); + BUG_MSG("<table> width attribute is obsolete."); } if ((attrbuf = a_Html_get_attr(html, tag, tagsize, "align"))) { @@ -102,7 +103,7 @@ void Html_tag_open_table(DilloHtml *html, const char *tag, int tagsize) html->styleEngine->setNonCssHint (CSS_PROPERTY_TEXT_ALIGN, CSS_TYPE_ENUM, TEXT_ALIGN_CENTER); if (html->DocType == DT_HTML && html->DocTypeVersion >= 5.0f) - BUG_MSG("<table> align attribute is obsolete.\n"); + BUG_MSG("<table> align attribute is obsolete."); } if ((attrbuf = a_Html_get_attr(html, tag, tagsize, "bgcolor"))) { @@ -111,7 +112,7 @@ void Html_tag_open_table(DilloHtml *html, const char *tag, int tagsize) html->styleEngine->setNonCssHint (CSS_PROPERTY_BACKGROUND_COLOR, CSS_TYPE_COLOR, bgcolor); if (html->DocType == DT_HTML && html->DocTypeVersion >= 5.0f) - BUG_MSG("<table> bgcolor attribute is obsolete.\n"); + BUG_MSG("<table> bgcolor attribute is obsolete."); } html->style (); // evaluate now, so we can build non-css hints for the cells @@ -192,7 +193,7 @@ void Html_tag_open_tr(DilloHtml *html, const char *tag, int tagsize) html->styleEngine->setNonCssHint (CSS_PROPERTY_BACKGROUND_COLOR, CSS_TYPE_COLOR, bgcolor); if (html->DocType == DT_HTML && html->DocTypeVersion >= 5.0f) - BUG_MSG("<tr> bgcolor attribute is obsolete.\n"); + BUG_MSG("<tr> bgcolor attribute is obsolete."); } if (a_Html_get_attr (html, tag, tagsize, "align")) { @@ -379,7 +380,7 @@ static void Html_tag_open_table_cell(DilloHtml *html, } if (a_Html_get_attr(html, tag, tagsize, "nowrap")) { if (html->DocType == DT_HTML && html->DocTypeVersion >= 5.0f) - BUG_MSG("<t%c> nowrap attribute is obsolete.\n", + BUG_MSG("<t%c> nowrap attribute is obsolete.", (tagsize >=3 && (D_ASCII_TOLOWER(tag[2]) == 'd')) ? 'd' : 'h'); html->styleEngine->setNonCssHint(CSS_PROPERTY_WHITE_SPACE, CSS_TYPE_ENUM, WHITE_SPACE_NOWRAP); @@ -392,7 +393,7 @@ static void Html_tag_open_table_cell(DilloHtml *html, CSS_TYPE_LENGTH_PERCENTAGE, a_Html_parse_length (html, attrbuf)); if (html->DocType == DT_HTML && html->DocTypeVersion >= 5.0f) - BUG_MSG("<t%c> width attribute is obsolete.\n", + BUG_MSG("<t%c> width attribute is obsolete.", (tagsize >=3 && (D_ASCII_TOLOWER(tag[2]) == 'd')) ? 'd' : 'h'); } @@ -404,7 +405,7 @@ static void Html_tag_open_table_cell(DilloHtml *html, html->styleEngine->setNonCssHint (CSS_PROPERTY_BACKGROUND_COLOR, CSS_TYPE_COLOR, bgcolor); if (html->DocType == DT_HTML && html->DocTypeVersion >= 5.0f) - BUG_MSG("<t%c> bgcolor attribute is obsolete.\n", + BUG_MSG("<t%c> bgcolor attribute is obsolete.", (tagsize >=3 && (D_ASCII_TOLOWER(tag[2]) == 'd')) ? 'd' : 'h'); } @@ -423,12 +424,12 @@ static void Html_tag_content_table_cell(DilloHtml *html, switch (S_TOP(html)->table_mode) { case DILLO_HTML_TABLE_MODE_NONE: - BUG_MSG("<t%c> outside <table>\n", + BUG_MSG("<t%c> outside <table>.", (tagsize >=3 && (D_ASCII_TOLOWER(tag[2]) == 'd')) ? 'd' : 'h'); return; case DILLO_HTML_TABLE_MODE_TOP: - BUG_MSG("<t%c> outside <tr>\n", + BUG_MSG("<t%c> outside <tr>.", (tagsize >=3 && (D_ASCII_TOLOWER(tag[2]) == 'd')) ? 'd' : 'h'); /* a_Dw_table_add_cell takes care that dillo does not crash. */ /* continues */ @@ -445,11 +446,11 @@ static void Html_tag_content_table_cell(DilloHtml *html, rowspan = MAX(1, strtol (attrbuf, NULL, 10)); if (html->style ()->textAlign == TEXT_ALIGN_STRING) - col_tb = new dw::TableCell ( + col_tb = new AlignedTableCell ( ((dw::Table*)S_TOP(html)->table)->getCellRef (), prefs.limit_text_width); else - col_tb = new Textblock (prefs.limit_text_width); + col_tb = new SimpleTableCell (prefs.limit_text_width); if (html->style()->borderCollapse == BORDER_MODEL_COLLAPSE){ Html_set_collapsing_border_model(html, col_tb); @@ -816,7 +816,7 @@ void UI::set_location(const char *str) { if (!str) str = ""; Location->value(str); - Location->position(strlen(str)); + Location->position((Fl::focus() == Location) ? strlen(str) : 0); } /* diff --git a/src/uicmd.cc b/src/uicmd.cc index e1100219..5225be75 100644 --- a/src/uicmd.cc +++ b/src/uicmd.cc @@ -71,6 +71,7 @@ static const char *save_dir = ""; static BrowserWindow *UIcmd_tab_new(CustTabs *tabs, UI *old_ui, int focus); static void close_tab_btn_cb (Fl_Widget *w, void *cb_data); static char *UIcmd_make_search_str(const char *str); +static void UIcmd_set_window_labels(Fl_Window *win, const char *str); //---------------------------------------------------------------------------- @@ -433,7 +434,7 @@ void CustTabs::switch_tab(CustTabButton *cbtn) // Update window title if ((bw = a_UIcmd_get_bw_by_widget(cbtn->ui()))) { const char *title = (cbtn->ui())->label(); - cbtn->window()->copy_label(title ? title : ""); + UIcmd_set_window_labels(cbtn->window(), title ? title : ""); } // Update focus priority increase_focus_counter(); @@ -568,6 +569,18 @@ BrowserWindow *a_UIcmd_browser_window_new(int ww, int wh, } /* + * Set the window name and icon name. + */ +static void UIcmd_set_window_labels(Fl_Window *win, const char *str) +{ + const char *copy; + + win->Fl_Widget::copy_label(str); + copy = win->label(); + win->label(copy, copy); +} + +/* * Create a new Tab button, UI and its associated BrowserWindow data * structure. */ @@ -606,7 +619,7 @@ static BrowserWindow *UIcmd_tab_new(CustTabs *tabs, UI *old_ui, int focus) // Clear the window title if (focus) - new_ui->window()->copy_label(new_ui->label()); + UIcmd_set_window_labels(new_ui->window(), new_ui->label()); // WORKAROUND: see findbar_toggle() new_ui->findbar_toggle(0); @@ -1413,7 +1426,7 @@ void a_UIcmd_set_page_title(BrowserWindow *bw, const char *label) if (a_UIcmd_get_bw_by_widget(BW2UI(bw)->tabs()->wizard()->value()) == bw) { // This is the focused bw, set window title - BW2UI(bw)->window()->copy_label(title); + UIcmd_set_window_labels(BW2UI(bw)->window(), title); } } @@ -366,23 +366,23 @@ DilloUrl* a_Url_new(const char *url_str, const char *base_url) dReturn_val_if_fail (url_str != NULL, NULL); - /* Count illegal characters (0x00-0x1F, 0x7F and space) */ + /* Count illegal characters (0x00-0x1F, 0x7F-0xFF and space) */ n_ic = n_ic_spc = 0; for (p = (char*)url_str; *p; p++) { n_ic_spc += (*p == ' ') ? 1 : 0; - n_ic += (*p != ' ' && *p > 0x1F && *p != 0x7F) ? 0 : 1; + n_ic += (*p != ' ' && *p > 0x1F && *p < 0x7F) ? 0 : 1; } if (n_ic) { /* Encode illegal characters (they could also be stripped). * There's no standard for illegal chars; we chose to encode. */ p = str1 = dNew(char, strlen(url_str) + 2*n_ic + 1); for (i = 0; url_str[i]; ++i) - if (url_str[i] > 0x1F && url_str[i] != 0x7F && url_str[i] != ' ') + if (url_str[i] > 0x1F && url_str[i] < 0x7F && url_str[i] != ' ') *p++ = url_str[i]; - else { - *p++ = '%'; - *p++ = HEX[(url_str[i] >> 4) & 15]; - *p++ = HEX[url_str[i] & 15]; + else { + *p++ = '%'; + *p++ = HEX[(url_str[i] >> 4) & 15]; + *p++ = HEX[url_str[i] & 15]; } *p = 0; urlstr = str1; @@ -509,7 +509,7 @@ void a_Url_set_ismap_coords(DilloUrl *u, char *coord_str) if (!u->ismap_url_len) { /* Save base-url length (without coords) */ - u->ismap_url_len = URL_STR_(u) ? u->url_string->len : 0; + u->ismap_url_len = URL_STR_(u) ? u->url_string->len : 0; a_Url_set_flags(u, URL_FLAGS(u) | URL_Ismap); } if (u->url_string) { @@ -611,7 +611,7 @@ char *a_Url_encode_hex_str(const char *str) /* * RFC-3986 suggests this stripping when "importing" URLs from other media. * Strip: "URL:", enclosing < >, and embedded whitespace. - * (We also strip illegal chars: 00-1F and 7F) + * (We also strip illegal chars: 00-1F and 7F-FF) */ char *a_Url_string_strip_delimiters(const char *str) { @@ -626,7 +626,7 @@ char *a_Url_string_strip_delimiters(const char *str) text++; for (p = new_str; *text; text++) - if (*text > 0x1F && *text != 0x7F && *text != ' ') + if (*text > 0x1F && *text < 0x7F && *text != ' ') *p++ = *text; if (p > new_str && p[-1] == '>') --p; @@ -688,14 +688,17 @@ static uint_t Url_host_public_internal_dots(const char *host) if (tld_len > 0) { /* These TLDs were chosen by examining the current publicsuffix list - * in February 2014 and picking out those where it was simplest for + * in October 2014 and picking out those where it was simplest for * them to describe the situation by beginning with a "*.[tld]" rule * or every rule was "[something].[tld]". + * + * TODO: Consider the old publicsuffix code again. This TLD list has + * shrunk and shrunk over the years, and has become a poorer and + * poorer approximation of administrative boundaries. */ - const char *const tlds[] = {"bd","bn","ck","cy","er","et","fj","fk", + const char *const tlds[] = {"bd","bn","ck","cy","er","fj","fk", "gu","il","jm","ke","kh","kw","mm","mz", - "ni","np","nz","pg","tr","uk","ye","za", - "zm","zw"}; + "ni","np","pg","ye","za","zm","zw"}; uint_t i, tld_num = sizeof(tlds) / sizeof(tlds[0]); for (i = 0; i < tld_num; i++) { @@ -13,15 +13,6 @@ #include "../dlib/dlib.h" -#define DILLO_URL_HTTP_PORT 80 -#define DILLO_URL_HTTPS_PORT 443 -#define DILLO_URL_FTP_PORT 21 -#define DILLO_URL_MAILTO_PORT 25 -#define DILLO_URL_NEWS_PORT 119 -#define DILLO_URL_TELNET_PORT 23 -#define DILLO_URL_GOPHER_PORT 70 - - /* * Values for DilloUrl->flags. * Specifies which which action to perform with an URL. @@ -128,7 +128,7 @@ DilloWeb* a_Web_new(BrowserWindow *bw, const DilloUrl *url, web->flags = 0; web->Image = NULL; web->filename = NULL; - web->stream = NULL; + web->stream = NULL; web->SavedBytes = 0; web->bgColor = 0x000000; /* Dummy value will be overwritten * in a_Web_dispatch_by_type. */ |