2007-07-27 12:45:02 -04:00
|
|
|
/** The document base functionality
|
|
|
|
* @file */
|
2005-09-15 09:58:31 -04:00
|
|
|
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
|
|
#include "config.h"
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#include <errno.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
|
|
|
|
2021-04-28 10:24:20 -04:00
|
|
|
#ifdef HAVE_IDNA_H
|
|
|
|
#include <idna.h>
|
|
|
|
#endif
|
|
|
|
|
2010-03-30 08:45:19 -04:00
|
|
|
#include <sys/types.h>
|
2010-09-17 10:13:22 -04:00
|
|
|
#ifdef HAVE_NETINET_IN_H
|
|
|
|
#include <netinet/in.h> /* OS/2 needs this after sys/types.h */
|
|
|
|
#endif
|
|
|
|
#ifdef HAVE_SYS_SOCKET_H
|
|
|
|
#include <sys/socket.h> /* OS/2 needs this after sys/types.h */
|
|
|
|
#endif
|
|
|
|
#ifdef HAVE_FCNTL_H
|
|
|
|
#include <fcntl.h> /* OS/2 needs this after sys/types.h */
|
|
|
|
#endif
|
|
|
|
#ifdef HAVE_UNISTD_H
|
|
|
|
#include <unistd.h>
|
|
|
|
#endif
|
|
|
|
#ifdef HAVE_WS2TCPIP_H
|
|
|
|
#include <ws2tcpip.h> /* socklen_t for MinGW */
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef HAVE_GETIFADDRS
|
|
|
|
#ifdef HAVE_NETDB_H
|
|
|
|
#include <netdb.h>
|
|
|
|
#endif
|
|
|
|
#ifdef HAVE_NET_IF_H
|
|
|
|
#include <net/if.h>
|
|
|
|
#endif
|
|
|
|
#ifdef HAVE_IFADDRS_H
|
|
|
|
#include <ifaddrs.h> /* getifaddrs() */
|
|
|
|
#endif
|
|
|
|
#endif /* HAVE_GETIFADDRS */
|
2010-07-03 09:11:54 -04:00
|
|
|
|
2010-09-17 10:13:22 -04:00
|
|
|
#ifdef HAVE_ARPA_INET_H
|
2010-03-30 08:45:19 -04:00
|
|
|
#include <arpa/inet.h>
|
2010-07-03 09:11:54 -04:00
|
|
|
#endif
|
2010-03-30 08:45:19 -04:00
|
|
|
|
2005-09-15 09:58:31 -04:00
|
|
|
#include "elinks.h"
|
|
|
|
|
|
|
|
#include "cache/cache.h"
|
|
|
|
#include "config/options.h"
|
|
|
|
#include "document/document.h"
|
|
|
|
#include "document/forms.h"
|
|
|
|
#include "document/html/frames.h"
|
2021-07-25 17:07:05 -04:00
|
|
|
#include "document/html/iframes.h"
|
2005-09-15 09:58:31 -04:00
|
|
|
#include "document/html/parser.h"
|
|
|
|
#include "document/html/parser/parse.h"
|
|
|
|
#include "document/html/renderer.h"
|
|
|
|
#include "document/options.h"
|
|
|
|
#include "document/refresh.h"
|
2023-09-11 09:48:18 -04:00
|
|
|
#include "document/renderer.h"
|
2021-06-10 09:01:15 -04:00
|
|
|
|
2023-11-27 12:33:44 -05:00
|
|
|
#if defined(CONFIG_ECMASCRIPT_SMJS) || defined(CONFIG_QUICKJS) || defined(CONFIG_MUJS)
|
2023-11-27 10:38:58 -05:00
|
|
|
#include "ecmascript/ecmascript-c.h"
|
2021-06-10 09:01:15 -04:00
|
|
|
#endif
|
|
|
|
|
2023-05-05 14:48:14 -04:00
|
|
|
#ifdef CONFIG_LIBDOM
|
2023-05-15 13:13:38 -04:00
|
|
|
#include "document/libdom/doc.h"
|
2023-05-05 14:48:14 -04:00
|
|
|
#include "document/libdom/mapa.h"
|
2023-01-20 12:03:02 -05:00
|
|
|
#endif
|
|
|
|
|
2005-09-15 09:58:31 -04:00
|
|
|
#include "main/module.h"
|
|
|
|
#include "main/object.h"
|
2010-03-30 08:45:19 -04:00
|
|
|
#include "network/dns.h"
|
2005-09-15 09:58:31 -04:00
|
|
|
#include "protocol/uri.h"
|
|
|
|
#include "terminal/draw.h"
|
2023-05-28 04:53:07 -04:00
|
|
|
#ifdef CONFIG_LIBSIXEL
|
2023-05-26 07:00:38 -04:00
|
|
|
#include "terminal/sixel.h"
|
2023-05-28 04:53:07 -04:00
|
|
|
#endif
|
2005-09-15 09:58:31 -04:00
|
|
|
#include "util/color.h"
|
|
|
|
#include "util/error.h"
|
|
|
|
#include "util/lists.h"
|
|
|
|
#include "util/memory.h"
|
|
|
|
#include "util/string.h"
|
|
|
|
#include "viewer/text/link.h"
|
|
|
|
|
2023-11-27 10:26:09 -05:00
|
|
|
struct document_list {
|
|
|
|
LIST_HEAD_EL(struct document_list);
|
|
|
|
struct document *document;
|
|
|
|
};
|
2023-09-28 13:44:09 -04:00
|
|
|
|
2023-11-27 10:26:09 -05:00
|
|
|
static INIT_LIST_OF(struct document_list, format_cache);
|
2005-09-15 09:58:31 -04:00
|
|
|
|
2022-11-07 14:59:19 -05:00
|
|
|
const char *script_event_hook_name[] = {
|
|
|
|
"click",
|
|
|
|
"dblclick",
|
|
|
|
"mouseover",
|
|
|
|
"hover",
|
|
|
|
"focus",
|
|
|
|
"mouseout",
|
|
|
|
"blur",
|
|
|
|
"keydown",
|
|
|
|
"keyup",
|
2023-09-21 03:30:50 -04:00
|
|
|
"keypress",
|
2023-09-22 10:37:53 -04:00
|
|
|
"keypress",
|
2022-11-07 14:59:19 -05:00
|
|
|
NULL
|
|
|
|
};
|
|
|
|
|
2023-11-27 10:26:09 -05:00
|
|
|
static void add_to_document_list(LIST_OF(struct document_list) *list, struct document *document);
|
|
|
|
|
|
|
|
static void
|
|
|
|
remove_document_from_format_cache(struct document *document)
|
|
|
|
{
|
|
|
|
struct document_list *item;
|
|
|
|
|
|
|
|
foreach (item, format_cache) {
|
|
|
|
if (item->document == document) {
|
|
|
|
del_from_list(item);
|
|
|
|
mem_free(item);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
move_document_to_top_of_format_cache(struct document *document)
|
|
|
|
{
|
|
|
|
struct document_list *item;
|
|
|
|
|
|
|
|
foreach (item, format_cache) {
|
|
|
|
if (item->document == document) {
|
|
|
|
move_to_top_of_list(format_cache, item);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-09-28 13:44:09 -04:00
|
|
|
#if 0
|
|
|
|
static void
|
|
|
|
dump_format_cache(int line)
|
|
|
|
{
|
|
|
|
fprintf(stderr, "line=%d size=%ld", line, format_cache.size());
|
|
|
|
for (auto it = format_cache.begin(); it != format_cache.end(); it++) {
|
|
|
|
fprintf(stderr, " %p", *it);
|
|
|
|
}
|
|
|
|
fprintf(stderr, "\n");
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2012-08-08 16:28:04 -04:00
|
|
|
#ifdef HAVE_INET_NTOP
|
2010-03-30 08:45:19 -04:00
|
|
|
/* DNS callback. */
|
|
|
|
static void
|
|
|
|
found_dns(void *data, struct sockaddr_storage *addr, int addrlen)
|
|
|
|
{
|
2021-01-02 10:20:27 -05:00
|
|
|
char buf[64];
|
|
|
|
const char *res;
|
2010-03-30 08:45:19 -04:00
|
|
|
struct sockaddr *s;
|
2021-01-02 10:20:27 -05:00
|
|
|
char **ip = (char **)data;
|
2010-03-30 08:45:19 -04:00
|
|
|
void *src;
|
|
|
|
|
|
|
|
if (!ip || !addr) return;
|
|
|
|
s = (struct sockaddr *)addr;
|
|
|
|
if (s->sa_family == AF_INET6) {
|
|
|
|
src = &(((struct sockaddr_in6 *)s)->sin6_addr.s6_addr);
|
|
|
|
} else {
|
|
|
|
src = &(((struct sockaddr_in *)s)->sin_addr.s_addr);
|
|
|
|
}
|
|
|
|
res = inet_ntop(s->sa_family, src, buf, 64);
|
|
|
|
if (res) {
|
|
|
|
*ip = stracpy(res);
|
|
|
|
}
|
|
|
|
}
|
2012-08-08 16:28:04 -04:00
|
|
|
#endif
|
2010-03-30 08:45:19 -04:00
|
|
|
|
|
|
|
static void
|
|
|
|
get_ip(struct document *document)
|
|
|
|
{
|
|
|
|
#ifdef HAVE_INET_NTOP
|
|
|
|
struct uri *uri = document->uri;
|
2022-06-01 16:24:07 -04:00
|
|
|
char *host = get_uri_string(uri, URI_DNS_HOST);
|
2021-04-28 10:24:20 -04:00
|
|
|
|
|
|
|
if (host) {
|
|
|
|
find_host(host, &document->querydns, found_dns, &document->ip, 0);
|
|
|
|
mem_free(host);
|
|
|
|
}
|
2010-03-30 08:45:19 -04:00
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2005-09-15 09:58:31 -04:00
|
|
|
struct document *
|
|
|
|
init_document(struct cache_entry *cached, struct document_options *options)
|
|
|
|
{
|
2022-01-16 15:08:50 -05:00
|
|
|
struct document *document = (struct document *)mem_calloc(1, sizeof(*document));
|
2005-09-15 09:58:31 -04:00
|
|
|
|
|
|
|
if (!document) return NULL;
|
|
|
|
|
|
|
|
document->uri = get_uri_reference(cached->uri);
|
|
|
|
|
2010-03-30 08:45:19 -04:00
|
|
|
get_ip(document);
|
|
|
|
|
2005-09-15 09:58:31 -04:00
|
|
|
object_lock(cached);
|
2008-04-20 16:25:10 -04:00
|
|
|
document->cache_id = cached->cache_id;
|
2006-12-09 22:11:04 -05:00
|
|
|
document->cached = cached;
|
2005-09-15 09:58:31 -04:00
|
|
|
|
|
|
|
init_list(document->forms);
|
|
|
|
init_list(document->tags);
|
|
|
|
init_list(document->nodes);
|
|
|
|
|
2023-11-11 10:34:12 -05:00
|
|
|
#ifdef CONFIG_LIBDOM
|
|
|
|
init_string(&document->text);
|
|
|
|
#endif
|
|
|
|
|
2005-09-15 09:58:31 -04:00
|
|
|
#ifdef CONFIG_ECMASCRIPT
|
|
|
|
init_list(document->onload_snippets);
|
2022-09-07 14:41:46 -04:00
|
|
|
init_list(document->timeouts);
|
2005-09-15 09:58:31 -04:00
|
|
|
#endif
|
|
|
|
|
2023-05-19 15:31:51 -04:00
|
|
|
#ifdef CONFIG_LIBSIXEL
|
|
|
|
init_list(document->images);
|
|
|
|
#endif
|
|
|
|
|
2008-01-19 12:56:50 -05:00
|
|
|
#ifdef CONFIG_COMBINE
|
2008-01-03 07:03:08 -05:00
|
|
|
document->comb_x = -1;
|
|
|
|
document->comb_y = -1;
|
|
|
|
#endif
|
2005-09-15 09:58:31 -04:00
|
|
|
object_nolock(document, "document");
|
|
|
|
object_lock(document);
|
|
|
|
|
|
|
|
copy_opt(&document->options, options);
|
2023-11-27 10:26:09 -05:00
|
|
|
add_to_document_list(&format_cache, document);
|
2005-09-15 09:58:31 -04:00
|
|
|
|
|
|
|
return document;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
free_frameset_desc(struct frameset_desc *frameset_desc)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = 0; i < frameset_desc->n; i++) {
|
|
|
|
struct frame_desc *frame_desc = &frameset_desc->frame_desc[i];
|
|
|
|
|
|
|
|
if (frame_desc->subframe)
|
|
|
|
free_frameset_desc(frame_desc->subframe);
|
|
|
|
mem_free_if(frame_desc->name);
|
|
|
|
if (frame_desc->uri)
|
|
|
|
done_uri(frame_desc->uri);
|
|
|
|
}
|
|
|
|
|
|
|
|
mem_free(frameset_desc);
|
|
|
|
}
|
|
|
|
|
2021-07-25 17:07:05 -04:00
|
|
|
static void
|
|
|
|
free_iframeset_desc(struct iframeset_desc *iframeset_desc)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = 0; i < iframeset_desc->n; i++) {
|
|
|
|
struct iframe_desc *iframe_desc = &iframeset_desc->iframe_desc[i];
|
|
|
|
|
|
|
|
// if (iframe_desc->subframe)
|
|
|
|
// free_iframeset_desc(frame_desc->subframe);
|
|
|
|
mem_free_if(iframe_desc->name);
|
|
|
|
if (iframe_desc->uri)
|
|
|
|
done_uri(iframe_desc->uri);
|
|
|
|
}
|
|
|
|
|
|
|
|
mem_free(iframeset_desc);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2005-09-15 09:58:31 -04:00
|
|
|
void
|
|
|
|
done_link_members(struct link *link)
|
|
|
|
{
|
|
|
|
if (link->event_hooks) {
|
|
|
|
struct script_event_hook *evhook, *safety;
|
|
|
|
|
|
|
|
foreachsafe (evhook, safety, *link->event_hooks) {
|
|
|
|
mem_free_if(evhook->src);
|
|
|
|
mem_free(evhook);
|
|
|
|
}
|
|
|
|
mem_free(link->event_hooks);
|
|
|
|
}
|
|
|
|
mem_free_if(get_link_name(link));
|
|
|
|
mem_free_if(link->where);
|
|
|
|
mem_free_if(link->target);
|
|
|
|
mem_free_if(link->title);
|
|
|
|
mem_free_if(link->where_img);
|
|
|
|
mem_free_if(link->points);
|
|
|
|
}
|
|
|
|
|
2021-06-27 07:01:19 -04:00
|
|
|
void
|
|
|
|
reset_document(struct document *document)
|
|
|
|
{
|
|
|
|
assert(document);
|
|
|
|
if_assert_failed return;
|
|
|
|
|
|
|
|
/// assertm(!is_object_used(document), "Attempt to free locked formatted data.");
|
|
|
|
/// if_assert_failed return;
|
|
|
|
|
|
|
|
assert(document->cached);
|
|
|
|
object_unlock(document->cached);
|
|
|
|
|
|
|
|
/// if (document->uri) {
|
|
|
|
/// done_uri(document->uri);
|
|
|
|
/// document->uri = NULL;
|
|
|
|
/// }
|
|
|
|
/// if (document->querydns) {
|
|
|
|
/// kill_dns_request(&document->querydns);
|
|
|
|
/// document->querydns = NULL;
|
|
|
|
/// }
|
|
|
|
/// mem_free_set(&document->ip, NULL);
|
|
|
|
/// mem_free_set(&document->title, NULL);
|
|
|
|
/// if (document->frame_desc) {
|
|
|
|
/// free_frameset_desc(document->frame_desc);
|
|
|
|
/// document->frame_desc = NULL;
|
|
|
|
/// }
|
|
|
|
/// if (document->refresh) {
|
|
|
|
/// done_document_refresh(document->refresh);
|
|
|
|
/// document->refresh = NULL;
|
|
|
|
/// }
|
|
|
|
|
|
|
|
if (document->links) {
|
|
|
|
int pos;
|
|
|
|
|
|
|
|
for (pos = 0; pos < document->nlinks; pos++)
|
|
|
|
done_link_members(&document->links[pos]);
|
|
|
|
|
|
|
|
mem_free_set(&document->links, NULL);
|
|
|
|
document->nlinks = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (document->data) {
|
|
|
|
int pos;
|
|
|
|
|
|
|
|
for (pos = 0; pos < document->height; pos++)
|
2023-05-18 05:12:05 -04:00
|
|
|
mem_free_if(document->data[pos].ch.chars);
|
2021-06-27 07:01:19 -04:00
|
|
|
|
|
|
|
mem_free_set(&document->data, NULL);
|
|
|
|
document->height = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
mem_free_set(&document->lines1, NULL);
|
|
|
|
mem_free_set(&document->lines2, NULL);
|
2021-10-05 14:11:18 -04:00
|
|
|
document->options.was_xml_parsed = 1;
|
2021-06-27 07:01:19 -04:00
|
|
|
/// done_document_options(&document->options);
|
|
|
|
|
|
|
|
while (!list_empty(document->forms)) {
|
2022-01-25 11:52:09 -05:00
|
|
|
done_form((struct form *)document->forms.next);
|
2021-06-27 07:01:19 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef CONFIG_CSS
|
|
|
|
free_uri_list(&document->css_imports);
|
|
|
|
#endif
|
2022-08-04 14:01:26 -04:00
|
|
|
#if defined(CONFIG_ECMASCRIPT_SMJS) || defined(CONFIG_QUICKJS) || defined(CONFIG_MUJS)
|
2022-11-14 15:17:24 -05:00
|
|
|
free_ecmascript_string_list(&document->onload_snippets);
|
2021-06-27 07:01:19 -04:00
|
|
|
free_uri_list(&document->ecmascript_imports);
|
2023-09-22 10:37:53 -04:00
|
|
|
mem_free_set(&document->body_onkeypress, NULL);
|
2021-06-27 07:01:19 -04:00
|
|
|
/// kill_timer(&document->timeout);
|
|
|
|
/// free_document(document->dom);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
free_list(document->tags);
|
|
|
|
free_list(document->nodes);
|
|
|
|
|
|
|
|
mem_free_set(&document->search, NULL);
|
|
|
|
mem_free_set(&document->slines1, NULL);
|
|
|
|
mem_free_set(&document->slines2, NULL);
|
|
|
|
mem_free_set(&document->search_points, NULL);
|
2021-09-11 13:36:03 -04:00
|
|
|
|
|
|
|
#ifdef CONFIG_COMBINE
|
|
|
|
discard_comb_x_y(document);
|
|
|
|
#endif
|
2021-06-27 07:01:19 -04:00
|
|
|
}
|
|
|
|
|
2005-09-15 09:58:31 -04:00
|
|
|
void
|
|
|
|
done_document(struct document *document)
|
|
|
|
{
|
|
|
|
assert(document);
|
|
|
|
if_assert_failed return;
|
|
|
|
|
|
|
|
assertm(!is_object_used(document), "Attempt to free locked formatted data.");
|
|
|
|
if_assert_failed return;
|
|
|
|
|
2006-12-09 22:11:04 -05:00
|
|
|
assert(document->cached);
|
|
|
|
object_unlock(document->cached);
|
2005-09-15 09:58:31 -04:00
|
|
|
|
|
|
|
if (document->uri) done_uri(document->uri);
|
2010-03-30 08:45:19 -04:00
|
|
|
if (document->querydns) kill_dns_request(&document->querydns);
|
|
|
|
mem_free_if(document->ip);
|
2005-09-15 09:58:31 -04:00
|
|
|
mem_free_if(document->title);
|
|
|
|
if (document->frame_desc) free_frameset_desc(document->frame_desc);
|
2021-07-25 17:07:05 -04:00
|
|
|
if (document->iframe_desc) free_iframeset_desc(document->iframe_desc);
|
2005-09-15 09:58:31 -04:00
|
|
|
if (document->refresh) done_document_refresh(document->refresh);
|
|
|
|
|
|
|
|
if (document->links) {
|
|
|
|
int pos;
|
|
|
|
|
|
|
|
for (pos = 0; pos < document->nlinks; pos++)
|
|
|
|
done_link_members(&document->links[pos]);
|
|
|
|
|
|
|
|
mem_free(document->links);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (document->data) {
|
|
|
|
int pos;
|
|
|
|
|
|
|
|
for (pos = 0; pos < document->height; pos++)
|
2023-05-18 05:12:05 -04:00
|
|
|
mem_free_if(document->data[pos].ch.chars);
|
2005-09-15 09:58:31 -04:00
|
|
|
|
|
|
|
mem_free(document->data);
|
|
|
|
}
|
|
|
|
|
|
|
|
mem_free_if(document->lines1);
|
|
|
|
mem_free_if(document->lines2);
|
|
|
|
done_document_options(&document->options);
|
|
|
|
|
|
|
|
while (!list_empty(document->forms)) {
|
2022-01-25 11:52:09 -05:00
|
|
|
done_form((struct form *)document->forms.next);
|
2005-09-15 09:58:31 -04:00
|
|
|
}
|
|
|
|
|
2023-05-26 07:00:38 -04:00
|
|
|
#ifdef CONFIG_LIBSIXEL
|
|
|
|
while (!list_empty(document->images)) {
|
|
|
|
delete_image((struct image *)document->images.next);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2005-09-15 09:58:31 -04:00
|
|
|
#ifdef CONFIG_CSS
|
|
|
|
free_uri_list(&document->css_imports);
|
|
|
|
#endif
|
2022-08-04 14:01:26 -04:00
|
|
|
#if defined(CONFIG_ECMASCRIPT_SMJS) || defined(CONFIG_QUICKJS) || defined(CONFIG_MUJS)
|
2022-11-14 15:17:24 -05:00
|
|
|
free_ecmascript_string_list(&document->onload_snippets);
|
2005-09-15 09:58:31 -04:00
|
|
|
free_uri_list(&document->ecmascript_imports);
|
2023-11-27 10:38:58 -05:00
|
|
|
kill_ecmascript_timeouts(document);
|
2022-09-07 14:41:46 -04:00
|
|
|
free_list(document->timeouts);
|
2023-09-22 10:37:53 -04:00
|
|
|
mem_free_if(document->body_onkeypress);
|
2023-05-15 13:13:38 -04:00
|
|
|
#endif
|
2022-09-07 14:41:46 -04:00
|
|
|
|
2023-05-15 13:13:38 -04:00
|
|
|
#ifdef CONFIG_LIBDOM
|
2023-09-28 06:04:57 -04:00
|
|
|
done_string(&document->text);
|
2021-06-10 09:01:15 -04:00
|
|
|
free_document(document->dom);
|
2023-01-20 11:14:32 -05:00
|
|
|
|
|
|
|
if (document->element_map) {
|
2023-05-05 14:48:14 -04:00
|
|
|
void *mapa = document->element_map;
|
2023-01-20 11:14:32 -05:00
|
|
|
|
2023-11-28 13:43:03 -05:00
|
|
|
delete_map(&mapa);
|
2023-01-20 11:14:32 -05:00
|
|
|
}
|
2023-09-11 08:59:05 -04:00
|
|
|
|
|
|
|
if (document->element_map_rev) {
|
|
|
|
void *mapa = document->element_map_rev;
|
|
|
|
|
2023-11-28 13:43:03 -05:00
|
|
|
delete_map_rev(&mapa);
|
2023-09-11 08:59:05 -04:00
|
|
|
}
|
2005-09-15 09:58:31 -04:00
|
|
|
#endif
|
|
|
|
free_list(document->tags);
|
|
|
|
free_list(document->nodes);
|
|
|
|
|
|
|
|
mem_free_if(document->search);
|
|
|
|
mem_free_if(document->slines1);
|
|
|
|
mem_free_if(document->slines2);
|
2018-04-14 15:49:52 -04:00
|
|
|
mem_free_if(document->search_points);
|
2005-09-15 09:58:31 -04:00
|
|
|
|
2023-11-27 10:26:09 -05:00
|
|
|
remove_document_from_format_cache(document);
|
2005-09-15 09:58:31 -04:00
|
|
|
mem_free(document);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
release_document(struct document *document)
|
|
|
|
{
|
|
|
|
assert(document);
|
|
|
|
if_assert_failed return;
|
|
|
|
|
2024-06-08 08:08:28 -04:00
|
|
|
if (document->refresh) {
|
|
|
|
kill_document_refresh(document->refresh);
|
|
|
|
}
|
2023-11-27 12:33:44 -05:00
|
|
|
#if defined(CONFIG_ECMASCRIPT_SMJS) || defined(CONFIG_QUICKJS) || defined(CONFIG_MUJS)
|
2024-06-08 08:08:28 -04:00
|
|
|
// kill_ecmascript_timeouts(document);
|
|
|
|
// free_list(document->timeouts);
|
2006-10-24 10:47:41 -04:00
|
|
|
#endif
|
2005-09-15 09:58:31 -04:00
|
|
|
object_unlock(document);
|
2023-11-27 10:26:09 -05:00
|
|
|
move_document_to_top_of_format_cache(document);
|
2005-09-15 09:58:31 -04:00
|
|
|
}
|
|
|
|
|
2007-08-30 20:09:40 -04:00
|
|
|
int
|
2021-01-02 10:20:27 -05:00
|
|
|
find_tag(struct document *document, char *name, int namelen)
|
2007-08-30 20:09:40 -04:00
|
|
|
{
|
|
|
|
struct tag *tag;
|
|
|
|
|
|
|
|
foreach (tag, document->tags)
|
2008-10-18 21:25:00 -04:00
|
|
|
if (!c_strlcasecmp(tag->name, -1, name, namelen))
|
2007-08-30 20:09:40 -04:00
|
|
|
return tag->y;
|
|
|
|
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2005-09-15 09:58:31 -04:00
|
|
|
/* Formatted document cache management */
|
|
|
|
|
|
|
|
/* ECMAScript doesn't like anything like CSS since it doesn't modify the
|
|
|
|
* formatted document (yet). */
|
|
|
|
|
2021-06-21 15:01:37 -04:00
|
|
|
#ifdef CONFIG_CSS
|
2005-09-15 09:58:31 -04:00
|
|
|
unsigned long
|
|
|
|
get_document_css_magic(struct document *document)
|
|
|
|
{
|
|
|
|
unsigned long css_magic = 0;
|
|
|
|
struct uri *uri;
|
|
|
|
int index;
|
|
|
|
|
|
|
|
foreach_uri (uri, index, &document->css_imports) {
|
|
|
|
struct cache_entry *cached = find_in_cache(uri);
|
|
|
|
|
2008-04-20 16:25:10 -04:00
|
|
|
if (cached) css_magic += cached->cache_id + cached->data_size;
|
2005-09-15 09:58:31 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
return css_magic;
|
|
|
|
}
|
|
|
|
|
|
|
|
#define check_document_css_magic(document) \
|
|
|
|
((document)->css_magic == get_document_css_magic(document))
|
|
|
|
#else
|
|
|
|
#define check_document_css_magic(document) 1
|
|
|
|
#endif
|
|
|
|
|
|
|
|
void
|
2007-08-30 15:08:24 -04:00
|
|
|
update_cached_document_options(struct session *ses)
|
2005-09-15 09:58:31 -04:00
|
|
|
{
|
|
|
|
struct document *document;
|
|
|
|
struct active_link_options active_link;
|
2023-11-27 10:26:09 -05:00
|
|
|
struct document_list *item;
|
2005-09-15 09:58:31 -04:00
|
|
|
|
|
|
|
memset(&active_link, 0, sizeof(active_link)); /* Safer. */
|
2007-10-12 06:24:53 -04:00
|
|
|
active_link.color.foreground = get_opt_color("document.browse.links.active_link.colors.text", ses);
|
|
|
|
active_link.color.background = get_opt_color("document.browse.links.active_link.colors.background", ses);
|
2009-05-01 15:39:30 -04:00
|
|
|
active_link.insert_mode_color.foreground = get_opt_color("document.browse.links.active_link.insert_mode_colors.text", ses);
|
|
|
|
active_link.insert_mode_color.background = get_opt_color("document.browse.links.active_link.insert_mode_colors.background", ses);
|
2007-10-12 06:19:27 -04:00
|
|
|
active_link.enable_color = get_opt_bool("document.browse.links.active_link.enable_color", ses);
|
2007-08-30 15:08:24 -04:00
|
|
|
active_link.invert = get_opt_bool("document.browse.links.active_link.invert", ses);
|
|
|
|
active_link.underline = get_opt_bool("document.browse.links.active_link.underline", ses);
|
|
|
|
active_link.bold = get_opt_bool("document.browse.links.active_link.bold", ses);
|
2005-09-15 09:58:31 -04:00
|
|
|
|
2023-11-27 10:26:09 -05:00
|
|
|
foreach (item, format_cache) {
|
|
|
|
document = item->document;
|
2005-09-15 09:58:31 -04:00
|
|
|
copy_struct(&document->options.active_link, &active_link);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-11-27 10:26:09 -05:00
|
|
|
static void
|
|
|
|
add_to_document_list(LIST_OF(struct document_list) *list, struct document *document)
|
|
|
|
{
|
|
|
|
struct document_list *item = (struct document_list *)mem_alloc(sizeof(*item));
|
|
|
|
|
|
|
|
if (!item) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
item->document = document;
|
|
|
|
add_to_list_end(*list, item);
|
|
|
|
}
|
|
|
|
|
2005-09-15 09:58:31 -04:00
|
|
|
struct document *
|
|
|
|
get_cached_document(struct cache_entry *cached, struct document_options *options)
|
|
|
|
{
|
2023-09-28 13:44:09 -04:00
|
|
|
struct document *ret = NULL;
|
2023-11-27 10:26:09 -05:00
|
|
|
struct document_list *item, *it;
|
|
|
|
INIT_LIST_OF(struct document_list, to_remove);
|
2023-09-28 13:44:09 -04:00
|
|
|
|
2023-11-27 10:26:09 -05:00
|
|
|
foreach (it, format_cache) {
|
|
|
|
struct document *document = it->document;
|
2005-09-15 09:58:31 -04:00
|
|
|
|
|
|
|
if (!compare_uri(document->uri, cached->uri, 0)
|
|
|
|
|| compare_opt(&document->options, options))
|
|
|
|
continue;
|
|
|
|
|
2024-06-08 08:08:28 -04:00
|
|
|
if (
|
|
|
|
cached->cache_id != document->cache_id
|
2005-09-15 09:58:31 -04:00
|
|
|
|| !check_document_css_magic(document)) {
|
|
|
|
if (!is_object_used(document)) {
|
2023-11-27 10:26:09 -05:00
|
|
|
add_to_document_list(&to_remove, document);
|
2005-09-15 09:58:31 -04:00
|
|
|
}
|
|
|
|
continue;
|
|
|
|
}
|
2023-09-28 13:44:09 -04:00
|
|
|
ret = document;
|
|
|
|
break;
|
|
|
|
}
|
2023-11-27 10:26:09 -05:00
|
|
|
foreach (item, to_remove) {
|
|
|
|
done_document(item->document);
|
2023-09-28 13:44:09 -04:00
|
|
|
}
|
2023-11-27 10:26:09 -05:00
|
|
|
free_list(to_remove);
|
2005-09-15 09:58:31 -04:00
|
|
|
|
2023-09-28 13:44:09 -04:00
|
|
|
if (ret) {
|
2005-09-15 09:58:31 -04:00
|
|
|
/* Reactivate */
|
2023-11-27 10:26:09 -05:00
|
|
|
move_document_to_top_of_format_cache(ret);
|
2023-09-28 13:44:09 -04:00
|
|
|
object_lock(ret);
|
2005-09-15 09:58:31 -04:00
|
|
|
|
2023-09-28 13:44:09 -04:00
|
|
|
return ret;
|
2005-09-15 09:58:31 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
shrink_format_cache(int whole)
|
|
|
|
{
|
2023-09-28 13:44:09 -04:00
|
|
|
struct document *document;
|
2023-11-27 10:26:09 -05:00
|
|
|
struct document_list *item, *it;
|
2007-08-28 12:41:18 -04:00
|
|
|
int format_cache_size = get_opt_int("document.cache.format.size", NULL);
|
2005-09-15 09:58:31 -04:00
|
|
|
int format_cache_entries = 0;
|
2023-11-27 10:26:09 -05:00
|
|
|
INIT_LIST_OF(struct document_list, to_remove);
|
2023-09-28 13:44:09 -04:00
|
|
|
|
2023-11-27 10:26:09 -05:00
|
|
|
foreach (it, format_cache) {
|
|
|
|
document = it->document;
|
2005-09-15 09:58:31 -04:00
|
|
|
|
|
|
|
if (is_object_used(document)) continue;
|
|
|
|
|
|
|
|
format_cache_entries++;
|
|
|
|
|
|
|
|
/* Destroy obsolete renderer documents which are already
|
|
|
|
* out-of-sync. */
|
2008-04-20 16:25:10 -04:00
|
|
|
if (document->cached->cache_id == document->cache_id)
|
2006-12-09 22:11:04 -05:00
|
|
|
continue;
|
2005-09-15 09:58:31 -04:00
|
|
|
|
2023-11-27 10:26:09 -05:00
|
|
|
add_to_document_list(&to_remove, document);
|
2005-09-15 09:58:31 -04:00
|
|
|
format_cache_entries--;
|
|
|
|
}
|
|
|
|
|
|
|
|
assertm(format_cache_entries >= 0, "format_cache_entries underflow on entry");
|
|
|
|
if_assert_failed format_cache_entries = 0;
|
|
|
|
|
2023-11-27 10:26:09 -05:00
|
|
|
foreach (item, to_remove) {
|
|
|
|
done_document(item->document);
|
2023-09-28 13:44:09 -04:00
|
|
|
}
|
2023-11-27 10:26:09 -05:00
|
|
|
free_list(to_remove);
|
2023-09-28 13:44:09 -04:00
|
|
|
|
2023-11-27 10:26:09 -05:00
|
|
|
foreachback (it, format_cache) {
|
|
|
|
document = it->document;
|
2023-09-28 13:44:09 -04:00
|
|
|
|
2005-09-15 09:58:31 -04:00
|
|
|
if (is_object_used(document)) continue;
|
|
|
|
|
|
|
|
/* If we are not purging the whole format cache, stop
|
|
|
|
* once we are below the maximum number of entries. */
|
|
|
|
if (!whole && format_cache_entries <= format_cache_size)
|
|
|
|
break;
|
|
|
|
|
2023-11-27 10:26:09 -05:00
|
|
|
add_to_document_list(&to_remove, document);
|
2005-09-15 09:58:31 -04:00
|
|
|
format_cache_entries--;
|
|
|
|
}
|
2023-11-27 10:26:09 -05:00
|
|
|
foreach (item, to_remove) {
|
|
|
|
done_document(item->document);
|
2023-09-28 13:44:09 -04:00
|
|
|
}
|
2023-11-27 10:26:09 -05:00
|
|
|
free_list(to_remove);
|
2005-09-15 09:58:31 -04:00
|
|
|
|
|
|
|
assertm(format_cache_entries >= 0, "format_cache_entries underflow");
|
|
|
|
if_assert_failed format_cache_entries = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
get_format_cache_size(void)
|
|
|
|
{
|
2023-11-27 10:26:09 -05:00
|
|
|
return list_size(&format_cache);
|
2005-09-15 09:58:31 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
get_format_cache_used_count(void)
|
|
|
|
{
|
2023-11-27 10:26:09 -05:00
|
|
|
struct document_list *it;
|
2005-09-15 09:58:31 -04:00
|
|
|
struct document *document;
|
|
|
|
int i = 0;
|
|
|
|
|
2023-11-27 10:26:09 -05:00
|
|
|
foreach (it, format_cache) {
|
|
|
|
document = it->document;
|
2005-09-15 09:58:31 -04:00
|
|
|
i += is_object_used(document);
|
2023-09-28 13:44:09 -04:00
|
|
|
}
|
2005-09-15 09:58:31 -04:00
|
|
|
return i;
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
get_format_cache_refresh_count(void)
|
|
|
|
{
|
2023-11-27 10:26:09 -05:00
|
|
|
struct document_list *it;
|
2005-09-15 09:58:31 -04:00
|
|
|
struct document *document;
|
|
|
|
int i = 0;
|
|
|
|
|
2023-11-27 10:26:09 -05:00
|
|
|
foreach (it, format_cache) {
|
|
|
|
document = it->document;
|
2023-09-28 13:44:09 -04:00
|
|
|
|
2005-09-15 09:58:31 -04:00
|
|
|
if (document->refresh
|
2023-09-28 13:44:09 -04:00
|
|
|
&& document->refresh->timer != TIMER_ID_UNDEF) {
|
2005-09-15 09:58:31 -04:00
|
|
|
i++;
|
2023-09-28 13:44:09 -04:00
|
|
|
}
|
|
|
|
}
|
2005-09-15 09:58:31 -04:00
|
|
|
return i;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
init_documents(struct module *module)
|
|
|
|
{
|
|
|
|
init_tags_lookup();
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
done_documents(struct module *module)
|
|
|
|
{
|
|
|
|
free_tags_lookup();
|
|
|
|
free_table_cache();
|
|
|
|
}
|
|
|
|
|
2023-09-11 09:48:18 -04:00
|
|
|
#ifdef CONFIG_ECMASCRIPT
|
|
|
|
int
|
|
|
|
get_link_number_by_offset(struct document *document, int offset)
|
|
|
|
{
|
|
|
|
int link;
|
|
|
|
|
|
|
|
if (!document->links_sorted) sort_links(document);
|
|
|
|
|
|
|
|
for (link = 0; link < document->nlinks; link++) {
|
|
|
|
if (document->links[link].element_offset == offset) {
|
|
|
|
return link;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2005-09-15 09:58:31 -04:00
|
|
|
struct module document_module = struct_module(
|
2007-03-22 18:51:56 -04:00
|
|
|
/* Because this module is listed in main_modules rather than
|
|
|
|
* in builtin_modules, its name does not appear in the user
|
|
|
|
* interface and so need not be translatable. */
|
|
|
|
/* name: */ "Document",
|
2005-09-15 09:58:31 -04:00
|
|
|
/* options: */ NULL,
|
|
|
|
/* hooks: */ NULL,
|
|
|
|
/* submodules: */ NULL,
|
|
|
|
/* data: */ NULL,
|
|
|
|
/* init: */ init_documents,
|
|
|
|
/* done: */ done_documents
|
|
|
|
);
|