summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/IO/IO.c13
-rw-r--r--src/IO/about.c70
-rw-r--r--src/IO/http.c270
-rw-r--r--src/Makefile.am3
-rw-r--r--src/cache.c145
-rw-r--r--src/cache.h3
-rw-r--r--src/capi.c149
-rw-r--r--src/colors.c2
-rw-r--r--src/cookies.h3
-rw-r--r--src/css.cc2
-rw-r--r--src/css.hh2
-rw-r--r--src/cssparser.cc68
-rw-r--r--src/decode.c26
-rw-r--r--src/decode.h16
-rw-r--r--src/dicache.c272
-rw-r--r--src/dicache.h13
-rw-r--r--src/dillo.cc20
-rw-r--r--src/domain.c4
-rw-r--r--src/form.cc38
-rw-r--r--src/gif.c19
-rw-r--r--src/html.cc697
-rw-r--r--src/html_charrefs.h2138
-rw-r--r--src/html_common.hh5
-rw-r--r--src/image.cc6
-rw-r--r--src/jpeg.c1
-rw-r--r--src/klist.c2
-rw-r--r--src/menu.cc35
-rw-r--r--src/paths.cc6
-rw-r--r--src/png.c11
-rw-r--r--src/prefs.c3
-rw-r--r--src/prefs.h3
-rw-r--r--src/prefsparser.cc3
-rw-r--r--src/styleengine.cc60
-rw-r--r--src/styleengine.hh2
-rw-r--r--src/table.cc27
-rw-r--r--src/ui.cc2
-rw-r--r--src/uicmd.cc19
-rw-r--r--src/url.c31
-rw-r--r--src/url.h9
-rw-r--r--src/web.cc2
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);
diff --git a/src/capi.c b/src/capi.c
index 531ae34d..242ae294 100644
--- a/src/capi.c
+++ b/src/capi.c
@@ -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
diff --git a/src/css.cc b/src/css.cc
index 5bdf4fdb..5c64c619 100644
--- a/src/css.cc
+++ b/src/css.cc
@@ -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);
}
}
diff --git a/src/css.hh b/src/css.hh
index 22e7e700..c2a28770 100644
--- a/src/css.hh
+++ b/src/css.hh
@@ -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;
diff --git a/src/gif.c b/src/gif.c
index 7ce1e110..adc9f49d 100644
--- a/src/gif.c
+++ b/src/gif.c
@@ -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., "&#47;" or "&#x2F;").
+ * 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 "&copy=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., "&amp;" or "&hellip;").
+ * 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 "&copy=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)
diff --git a/src/jpeg.c b/src/jpeg.c
index 625808fb..5652aa56 100644
--- a/src/jpeg.c
+++ b/src/jpeg.c
@@ -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 {
diff --git a/src/png.c b/src/png.c
index 4f5da1c2..652e861e 100644
--- a/src/png.c
+++ b/src/png.c
@@ -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);
diff --git a/src/ui.cc b/src/ui.cc
index d3bc7ff6..a5785576 100644
--- a/src/ui.cc
+++ b/src/ui.cc
@@ -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);
}
}
diff --git a/src/url.c b/src/url.c
index 9d3e14b2..c1a8396d 100644
--- a/src/url.c
+++ b/src/url.c
@@ -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++) {
diff --git a/src/url.h b/src/url.h
index bb20d789..ef532f76 100644
--- a/src/url.h
+++ b/src/url.h
@@ -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.
diff --git a/src/web.cc b/src/web.cc
index b835610c..a175ddb9 100644
--- a/src/web.cc
+++ b/src/web.cc
@@ -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. */