1 /** The document base functionality
15 #include "cache/cache.h"
16 #include "config/options.h"
17 #include "document/document.h"
18 #include "document/forms.h"
19 #include "document/html/frames.h"
20 #include "document/html/parser.h"
21 #include "document/html/parser/parse.h"
22 #include "document/html/renderer.h"
23 #include "document/options.h"
24 #include "document/refresh.h"
25 #include "main/module.h"
26 #include "main/object.h"
27 #include "protocol/uri.h"
28 #include "terminal/draw.h"
29 #include "util/color.h"
30 #include "util/error.h"
31 #include "util/lists.h"
32 #include "util/memory.h"
33 #include "util/string.h"
34 #include "viewer/text/link.h"
37 static INIT_LIST_OF(struct document
, format_cache
);
40 init_document(struct cache_entry
*cached
, struct document_options
*options
)
42 struct document
*document
= mem_calloc(1, sizeof(*document
));
44 if (!document
) return NULL
;
46 document
->uri
= get_uri_reference(cached
->uri
);
49 document
->id
= cached
->id
;
50 document
->cached
= cached
;
52 init_list(document
->forms
);
53 init_list(document
->tags
);
54 init_list(document
->nodes
);
56 #ifdef CONFIG_ECMASCRIPT
57 init_list(document
->onload_snippets
);
60 object_nolock(document
, "document");
61 object_lock(document
);
63 copy_opt(&document
->options
, options
);
65 add_to_list(format_cache
, document
);
71 free_frameset_desc(struct frameset_desc
*frameset_desc
)
75 for (i
= 0; i
< frameset_desc
->n
; i
++) {
76 struct frame_desc
*frame_desc
= &frameset_desc
->frame_desc
[i
];
78 if (frame_desc
->subframe
)
79 free_frameset_desc(frame_desc
->subframe
);
80 mem_free_if(frame_desc
->name
);
82 done_uri(frame_desc
->uri
);
85 mem_free(frameset_desc
);
89 done_link_members(struct link
*link
)
91 if (link
->event_hooks
) {
92 struct script_event_hook
*evhook
, *safety
;
94 foreachsafe (evhook
, safety
, *link
->event_hooks
) {
95 mem_free_if(evhook
->src
);
98 mem_free(link
->event_hooks
);
100 mem_free_if(get_link_name(link
));
101 mem_free_if(link
->where
);
102 mem_free_if(link
->target
);
103 mem_free_if(link
->title
);
104 mem_free_if(link
->where_img
);
105 mem_free_if(link
->points
);
109 done_document(struct document
*document
)
112 if_assert_failed
return;
114 assertm(!is_object_used(document
), "Attempt to free locked formatted data.");
115 if_assert_failed
return;
117 assert(document
->cached
);
118 object_unlock(document
->cached
);
120 if (document
->uri
) done_uri(document
->uri
);
121 mem_free_if(document
->title
);
122 if (document
->frame_desc
) free_frameset_desc(document
->frame_desc
);
123 if (document
->refresh
) done_document_refresh(document
->refresh
);
125 if (document
->links
) {
128 for (pos
= 0; pos
< document
->nlinks
; pos
++)
129 done_link_members(&document
->links
[pos
]);
131 mem_free(document
->links
);
134 if (document
->data
) {
137 for (pos
= 0; pos
< document
->height
; pos
++)
138 mem_free_if(document
->data
[pos
].chars
);
140 mem_free(document
->data
);
143 mem_free_if(document
->lines1
);
144 mem_free_if(document
->lines2
);
145 done_document_options(&document
->options
);
147 while (!list_empty(document
->forms
)) {
148 done_form(document
->forms
.next
);
152 free_uri_list(&document
->css_imports
);
154 #ifdef CONFIG_ECMASCRIPT
155 free_string_list(&document
->onload_snippets
);
156 free_uri_list(&document
->ecmascript_imports
);
157 kill_timer(&document
->timeout
);
160 free_list(document
->tags
);
161 free_list(document
->nodes
);
163 mem_free_if(document
->search
);
164 mem_free_if(document
->slines1
);
165 mem_free_if(document
->slines2
);
167 del_from_list(document
);
172 release_document(struct document
*document
)
175 if_assert_failed
return;
177 if (document
->refresh
) kill_document_refresh(document
->refresh
);
178 #ifdef CONFIG_ECMASCRIPT
179 kill_timer(&document
->timeout
);
181 object_unlock(document
);
182 move_to_top_of_list(format_cache
, document
);
186 find_tag(struct document
*document
, unsigned char *name
, int namelen
)
190 foreach (tag
, document
->tags
)
191 if (!strlcasecmp(tag
->name
, -1, name
, namelen
))
197 /* Formatted document cache management */
199 /* ECMAScript doesn't like anything like CSS since it doesn't modify the
200 * formatted document (yet). */
204 get_document_css_magic(struct document
*document
)
206 unsigned long css_magic
= 0;
210 foreach_uri (uri
, index
, &document
->css_imports
) {
211 struct cache_entry
*cached
= find_in_cache(uri
);
213 if (cached
) css_magic
+= cached
->id
+ cached
->data_size
;
219 #define check_document_css_magic(document) \
220 ((document)->css_magic == get_document_css_magic(document))
222 #define check_document_css_magic(document) 1
226 update_cached_document_options(void)
228 struct document
*document
;
229 struct active_link_options active_link
;
231 memset(&active_link
, 0, sizeof(active_link
)); /* Safer. */
232 active_link
.fg
= get_opt_color("document.browse.links.active_link.colors.text");
233 active_link
.bg
= get_opt_color("document.browse.links.active_link.colors.background");
234 active_link
.color
= get_opt_bool("document.browse.links.active_link.enable_color");
235 active_link
.invert
= get_opt_bool("document.browse.links.active_link.invert");
236 active_link
.underline
= get_opt_bool("document.browse.links.active_link.underline");
237 active_link
.bold
= get_opt_bool("document.browse.links.active_link.bold");
239 foreach (document
, format_cache
) {
240 copy_struct(&document
->options
.active_link
, &active_link
);
245 get_cached_document(struct cache_entry
*cached
, struct document_options
*options
)
247 struct document
*document
, *next
;
249 foreachsafe (document
, next
, format_cache
) {
250 if (!compare_uri(document
->uri
, cached
->uri
, 0)
251 || compare_opt(&document
->options
, options
))
254 if (options
->no_cache
255 || cached
->id
!= document
->id
256 || !check_document_css_magic(document
)) {
257 if (!is_object_used(document
)) {
258 done_document(document
);
264 move_to_top_of_list(format_cache
, document
);
266 object_lock(document
);
275 shrink_format_cache(int whole
)
277 struct document
*document
, *next
;
278 int format_cache_size
= get_opt_int("document.cache.format.size");
279 int format_cache_entries
= 0;
281 foreachsafe (document
, next
, format_cache
) {
282 if (is_object_used(document
)) continue;
284 format_cache_entries
++;
286 /* Destroy obsolete renderer documents which are already
288 if (document
->cached
->id
== document
->id
)
291 done_document(document
);
292 format_cache_entries
--;
295 assertm(format_cache_entries
>= 0, "format_cache_entries underflow on entry");
296 if_assert_failed format_cache_entries
= 0;
298 foreachbacksafe (document
, next
, format_cache
) {
299 if (is_object_used(document
)) continue;
301 /* If we are not purging the whole format cache, stop
302 * once we are below the maximum number of entries. */
303 if (!whole
&& format_cache_entries
<= format_cache_size
)
306 done_document(document
);
307 format_cache_entries
--;
310 assertm(format_cache_entries
>= 0, "format_cache_entries underflow");
311 if_assert_failed format_cache_entries
= 0;
315 get_format_cache_size(void)
317 return list_size(&format_cache
);
321 get_format_cache_used_count(void)
323 struct document
*document
;
326 foreach (document
, format_cache
)
327 i
+= is_object_used(document
);
332 get_format_cache_refresh_count(void)
334 struct document
*document
;
337 foreach (document
, format_cache
)
338 if (document
->refresh
339 && document
->refresh
->timer
!= TIMER_ID_UNDEF
)
345 init_documents(struct module
*module
)
351 done_documents(struct module
*module
)
357 struct module document_module
= struct_module(
358 /* Because this module is listed in main_modules rather than
359 * in builtin_modules, its name does not appear in the user
360 * interface and so need not be translatable. */
361 /* name: */ "Document",
364 /* submodules: */ NULL
,
366 /* init: */ init_documents
,
367 /* done: */ done_documents