14 #include "cache/cache.h"
15 #include "config/options.h"
16 #include "document/document.h"
17 #include "document/dom/renderer.h"
18 #include "document/html/frames.h"
19 #include "document/html/renderer.h"
20 #include "document/plain/renderer.h"
21 #include "document/renderer.h"
22 #include "document/view.h"
23 #include "ecmascript/ecmascript.h"
24 #include "encoding/encoding.h"
25 #include "intl/charsets.h"
26 #include "main/main.h"
27 #include "main/object.h"
28 #include "protocol/header.h"
29 #include "protocol/protocol.h"
30 #include "protocol/uri.h"
31 #include "session/location.h"
32 #include "session/session.h"
33 #include "terminal/terminal.h"
34 #include "terminal/window.h"
35 #include "util/error.h"
36 #include "util/memory.h"
37 #include "util/string.h"
38 #include "viewer/text/view.h"
39 #include "viewer/text/vs.h"
42 #ifdef CONFIG_ECMASCRIPT
43 /* XXX: This function is de facto obsolete, since we do not need to copy
44 * snippets around anymore (we process them in one go after the document is
45 * loaded; gradual processing was practically impossible because the snippets
46 * could reorder randomly during the loading - consider i.e.
47 * <body onLoad><script></body>: first just <body> is loaded, but then the
48 * rest of the document is loaded and <script> gets before <body>; do not even
49 * imagine the trouble with rewritten (through scripting hooks) documents;
50 * besides, implementing document.write() will be much simpler).
51 * But I want to take no risk by reworking that now. --pasky */
53 add_snippets(struct ecmascript_interpreter
*interpreter
,
54 LIST_OF(struct string_list_item
) *doc_snippets
,
55 LIST_OF(struct string_list_item
) *queued_snippets
)
57 struct string_list_item
*doc_current
= doc_snippets
->next
;
60 if (list_empty(*queued_snippets
) && interpreter
->vs
->doc_view
->session
)
61 unset_led_value(interpreter
->vs
->doc_view
->session
->status
.ecmascript_led
);
64 if (list_empty(*doc_snippets
) || !get_opt_bool("ecmascript.enable"))
67 /* We do this all only once per view_state now. */
68 if (!list_empty(*queued_snippets
)) {
69 /* So if we already did it, we shouldn't need to do it again.
70 * This is the case of moving around in history - we have all
71 * what happenned recorded in the view_state and needn't bother
75 struct string_list_item
*iterator
= queued_snippets
->next
;
77 while (iterator
!= (struct string_list_item
*) queued_snippets
) {
78 if (doc_current
== (struct string_list_item
*) doc_snippets
) {
79 INTERNAL("add_snippets(): doc_snippets shorter than queued_snippets!");
83 DBG("Comparing snippets\n%.*s\n###### vs #####\n%.*s\n #####",
84 iterator
->string
.length
, iterator
->string
.source
,
85 doc_current
->string
.length
, doc_current
->string
.source
);
87 assert(!strlcmp(iterator
->string
.source
,
88 iterator
->string
.length
,
89 doc_current
->string
.source
,
90 doc_current
->string
.length
));
92 doc_current
= doc_current
->next
;
93 iterator
= iterator
->next
;
100 for (; doc_current
!= (struct string_list_item
*) doc_snippets
;
101 doc_current
= doc_current
->next
) {
102 add_to_string_list(queued_snippets
, doc_current
->string
.source
,
103 doc_current
->string
.length
);
105 DBG("Adding snippet\n%.*s\n #####",
106 doc_current
->string
.length
,
107 doc_current
->string
.source
);
113 process_snippets(struct ecmascript_interpreter
*interpreter
,
114 LIST_OF(struct string_list_item
) *snippets
,
115 struct string_list_item
**current
)
118 *current
= snippets
->next
;
119 for (; *current
!= (struct string_list_item
*) snippets
;
120 (*current
) = (*current
)->next
) {
121 struct string
*string
= &(*current
)->string
;
122 unsigned char *uristring
;
124 struct cache_entry
*cached
;
125 struct fragment
*fragment
;
127 if (string
->length
== 0)
130 if (*string
->source
!= '^') {
131 /* Evaluate <script>code</script> snippet */
132 ecmascript_eval(interpreter
, string
, NULL
);
136 /* Eval external <script src="reference"></script> snippet */
137 uristring
= string
->source
+ 1;
138 if (!*uristring
) continue;
140 uri
= get_uri(uristring
, URI_BASE
);
143 cached
= get_redirected_cache_entry(uri
);
147 /* At this time (!gradual_rerendering), we should've
148 * already retrieved this though. So it must've been
149 * that it went away because unused and the cache was
150 * already too full. */
152 /* Disabled because gradual rerendering can be triggered
153 * by numerous events other than a ecmascript reference
154 * completing like the original document and CSS. Problem
155 * is that we should never continue this loop but rather
156 * break out if that is the case. Somehow we need to
157 * be able to derive URI loading problems at this point
158 * or maybe remove reference snippets if they fail to load.
160 * This FIFO queue handling should be used for also CSS
161 * imports so it would be cool if it could be general
162 * enough for that. Using it for frames with the FIFOing
163 * disabled probably wouldn't hurt either.
165 * To top this thing off it would be nice if it also
166 * handled dependency tracking between references so that
167 * CSS documents will not disappear from the cache
168 * before all referencing HTML documents has been deleted
171 * Reported as bug 533. */
172 /* Pasky's explanation: If we get the doc in a single
173 * shot, before calling draw_formatted() we didn't have
174 * anything additional queued for loading and the cache
175 * entry was already loaded, so we didn't get
176 * gradual_loading set. But then while parsing the
177 * document we got some external references and trying
178 * to process them right now. Boom.
180 * The obvious solution would be to always call
181 * draw_formatted() with gradual_loading in
182 * doc_loading_callback() and if we are sure the
183 * loading is really over, call it one more time
184 * without gradual_loading set. I'm not sure about
185 * the implications though so I won't do it before
187 ERROR("The script of %s was lost in too full a cache!",
193 fragment
= get_cache_fragment(cached
);
195 struct string code
= INIT_STRING(fragment
->data
, fragment
->length
);
197 ecmascript_eval(interpreter
, &code
, NULL
);
204 render_encoded_document(struct cache_entry
*cached
, struct document
*document
)
206 struct uri
*uri
= cached
->uri
;
207 enum stream_encoding encoding
= ENCODING_NONE
;
208 struct fragment
*fragment
= get_cache_fragment(cached
);
209 struct string buffer
= INIT_STRING("", 0);
211 /* Even empty documents have to be rendered so that info in the protocol
212 * header, such as refresh info, get processed. (bug 625) */
214 buffer
.source
= fragment
->data
;
215 buffer
.length
= fragment
->length
;
218 if (uri
->protocol
!= PROTOCOL_FILE
) {
219 unsigned char *extension
= get_extension_from_uri(uri
);
222 encoding
= guess_encoding(extension
);
226 if (encoding
!= ENCODING_NONE
) {
228 unsigned char *source
;
230 source
= decode_encoded_buffer(encoding
, buffer
.source
,
231 buffer
.length
, &length
);
233 buffer
.source
= source
;
234 buffer
.length
= length
;
236 encoding
= ENCODING_NONE
;
241 if (document
->options
.plain
) {
243 if (cached
->content_type
244 && (!strcasecmp("text/html", cached
->content_type
)
245 || !strcasecmp("application/xhtml+xml", cached
->content_type
)
246 || !strcasecmp("application/docbook+xml", cached
->content_type
)
247 || !strcasecmp("application/rss+xml", cached
->content_type
)
248 || !strcasecmp("application/xbel+xml", cached
->content_type
)
249 || !strcasecmp("application/x-xbel", cached
->content_type
)
250 || !strcasecmp("application/xbel", cached
->content_type
)))
251 render_dom_document(cached
, document
, &buffer
);
254 render_plain_document(cached
, document
, &buffer
);
258 if (cached
->content_type
259 && (!strlcasecmp("application/rss+xml", 19, cached
->content_type
, -1)))
260 render_dom_document(cached
, document
, &buffer
);
263 render_html_document(cached
, document
, &buffer
);
266 if (encoding
!= ENCODING_NONE
) {
267 done_string(&buffer
);
272 render_document(struct view_state
*vs
, struct document_view
*doc_view
,
273 struct document_options
*options
)
276 struct document
*document
;
277 struct cache_entry
*cached
;
279 assert(vs
&& doc_view
&& options
);
280 if_assert_failed
return;
283 DBG("(Re%u)Rendering %s on doc_view %p [%s] while attaching it to %p",
284 options
->gradual_rerendering
, struri(vs
->uri
),
285 doc_view
, doc_view
->name
, vs
);
288 name
= doc_view
->name
;
289 doc_view
->name
= NULL
;
291 detach_formatted(doc_view
);
293 doc_view
->name
= name
;
295 doc_view
->last_x
= doc_view
->last_y
= -1;
298 /* This is a nice idea, but doesn't always work: in particular when
299 * there's a frame name conflict. You loaded something to the vs'
300 * frame, but later something tried to get loaded to a frame with
301 * the same name and we got back this frame again, so we are now
302 * overriding the original document with a cuckoo. This assert()ion
303 * should be re-enabled when we start to get this right (which is
304 * very complex, but someone should rewrite the frames support
305 * anyway). --pasky */
306 assert(!vs
->doc_view
);
309 /* It will be still detached, no worries - hopefully it still
310 * resides in ses->scrn_frames. */
311 assert(vs
->doc_view
->vs
== vs
);
312 vs
->doc_view
->used
= 0; /* A bit risky, but... */
313 vs
->doc_view
->vs
= NULL
;
315 #ifdef CONFIG_ECMASCRIPT
316 vs
->ecmascript_fragile
= 1; /* And is this good? ;-) */
320 vs
->doc_view
= doc_view
;
322 cached
= find_in_cache(vs
->uri
);
324 INTERNAL("document %s to format not found", struri(vs
->uri
));
328 document
= get_cached_document(cached
, options
);
330 doc_view
->document
= document
;
332 document
= init_document(cached
, options
);
333 if (!document
) return;
334 doc_view
->document
= document
;
338 render_encoded_document(cached
, document
);
339 sort_links(document
);
340 if (!document
->title
) {
341 enum uri_component components
;
343 if (document
->uri
->protocol
== PROTOCOL_FILE
) {
344 components
= URI_PATH
;
346 components
= URI_PUBLIC
;
349 document
->title
= get_uri_string(document
->uri
, components
);
350 if (document
->title
) {
352 if (doc_view
->document
->options
.utf8
)
353 decode_uri(document
->title
);
355 #endif /* CONFIG_UTF8 */
356 decode_uri_for_display(document
->title
);
361 document
->css_magic
= get_document_css_magic(document
);
364 #ifdef CONFIG_ECMASCRIPT
365 if (!vs
->ecmascript_fragile
)
366 assert(vs
->ecmascript
);
367 if (!options
->gradual_rerendering
) {
368 /* We also reset the state if the underlying document changed
369 * from the last time we did the snippets. This may be
370 * triggered i.e. when redrawing a document which has been
371 * reloaded in a different tab meanwhile (OTOH we don't want
372 * to reset the state if we are redrawing a document we have
373 * already drawn before).
375 * (vs->ecmascript->onload_snippets_owner) check may be
376 * superfluous since we should always have
377 * vs->ecmascript_fragile set in those cases; that's why we
378 * don't ever bother to re-zero it if we are suddenly doing
379 * gradual rendering again.
381 * XXX: What happens if a document is still loading in the
382 * other tab when we press ^L here? */
383 if (vs
->ecmascript_fragile
384 || (vs
->ecmascript
&& vs
->ecmascript
->onload_snippets_owner
385 && document
->id
!= vs
->ecmascript
->onload_snippets_owner
))
386 ecmascript_reset_state(vs
);
387 assert(vs
->ecmascript
);
388 vs
->ecmascript
->onload_snippets_owner
= document
->id
;
390 /* Passing of the onload_snippets pointers gives *_snippets()
391 * some feeling of universality, shall we ever get any other
393 add_snippets(vs
->ecmascript
,
394 &document
->onload_snippets
,
395 &vs
->ecmascript
->onload_snippets
);
396 process_snippets(vs
->ecmascript
, &vs
->ecmascript
->onload_snippets
,
397 &vs
->ecmascript
->current_onload_snippet
);
401 /* If we do not care about the height and width of the document
402 * just use the setup values. */
404 copy_box(&doc_view
->box
, &document
->options
.box
);
406 if (!document
->options
.needs_width
)
407 doc_view
->box
.width
= options
->box
.width
;
409 if (!document
->options
.needs_height
)
410 doc_view
->box
.height
= options
->box
.height
;
415 render_document_frames(struct session
*ses
, int no_cache
)
417 struct document_options doc_opts
;
418 struct document_view
*doc_view
;
419 struct document_view
*current_doc_view
= NULL
;
420 struct view_state
*vs
= NULL
;
422 if (!ses
->doc_view
) {
423 ses
->doc_view
= mem_calloc(1, sizeof(*ses
->doc_view
));
424 if (!ses
->doc_view
) return;
425 ses
->doc_view
->session
= ses
;
426 ses
->doc_view
->search_word
= &ses
->search_word
;
429 if (have_location(ses
)) vs
= &cur_loc(ses
)->vs
;
431 init_document_options(&doc_opts
);
433 set_box(&doc_opts
.box
, 0, 0,
434 ses
->tab
->term
->width
, ses
->tab
->term
->height
);
436 if (ses
->status
.show_title_bar
) {
438 doc_opts
.box
.height
--;
440 if (ses
->status
.show_status_bar
) doc_opts
.box
.height
--;
441 if (ses
->status
.show_tabs_bar
) {
442 doc_opts
.box
.height
--;
443 if (ses
->status
.show_tabs_bar_at_top
) doc_opts
.box
.y
++;
446 doc_opts
.color_mode
= get_opt_int_tree(ses
->tab
->term
->spec
, "colors");
447 if (!get_opt_bool_tree(ses
->tab
->term
->spec
, "underline"))
448 doc_opts
.color_flags
|= COLOR_ENHANCE_UNDERLINE
;
450 doc_opts
.cp
= get_opt_codepage_tree(ses
->tab
->term
->spec
, "charset");
451 doc_opts
.no_cache
= no_cache
& 1;
452 doc_opts
.gradual_rerendering
= !!(no_cache
& 2);
455 if (vs
->plain
< 0) vs
->plain
= 0;
456 doc_opts
.plain
= vs
->plain
;
457 doc_opts
.wrap
= vs
->wrap
;
462 foreach (doc_view
, ses
->scrn_frames
) doc_view
->used
= 0;
464 if (vs
) render_document(vs
, ses
->doc_view
, &doc_opts
);
466 if (document_has_frames(ses
->doc_view
->document
)) {
467 current_doc_view
= current_frame(ses
);
468 format_frames(ses
, ses
->doc_view
->document
->frame_desc
, &doc_opts
, 0);
471 foreach (doc_view
, ses
->scrn_frames
) {
472 struct document_view
*prev_doc_view
= doc_view
->prev
;
474 if (doc_view
->used
) continue;
476 detach_formatted(doc_view
);
477 del_from_list(doc_view
);
479 doc_view
= prev_doc_view
;
482 if (current_doc_view
) {
485 foreach (doc_view
, ses
->scrn_frames
) {
486 if (document_has_frames(doc_view
->document
)) continue;
487 if (doc_view
== current_doc_view
) {
488 cur_loc(ses
)->vs
.current_link
= n
;
497 comp_links(struct link
*l1
, struct link
*l2
)
500 if_assert_failed
return 0;
501 return (l1
->number
- l2
->number
);
505 sort_links(struct document
*document
)
510 if_assert_failed
return;
511 if (!document
->nlinks
) return;
513 if (document
->links_sorted
) return;
514 assert(document
->links
);
515 if_assert_failed
return;
517 qsort(document
->links
, document
->nlinks
, sizeof(*document
->links
),
518 (void *) comp_links
);
520 if (!document
->height
) return;
522 mem_free_if(document
->lines1
);
523 document
->lines1
= mem_calloc(document
->height
, sizeof(*document
->lines1
));
524 mem_free_if(document
->lines2
);
525 if (!document
->lines1
) return;
526 document
->lines2
= mem_calloc(document
->height
, sizeof(*document
->lines2
));
527 if (!document
->lines2
) {
528 mem_free(document
->lines1
);
532 for (i
= 0; i
< document
->nlinks
; i
++) {
533 struct link
*link
= &document
->links
[i
];
536 if (!link
->npoints
) {
537 done_link_members(link
);
538 memmove(link
, link
+ 1,
539 (document
->nlinks
- i
- 1) * sizeof(*link
));
544 p
= link
->points
[0].y
;
545 q
= link
->points
[link
->npoints
- 1].y
;
546 if (p
> q
) j
= p
, p
= q
, q
= j
;
547 for (j
= p
; j
<= q
; j
++) {
548 assertm(j
< document
->height
, "link out of screen");
549 if_assert_failed
continue;
550 document
->lines2
[j
] = &document
->links
[i
];
551 if (!document
->lines1
[j
])
552 document
->lines1
[j
] = &document
->links
[i
];
555 document
->links_sorted
= 1;
559 get_convert_table(unsigned char *head
, int to_cp
,
560 int default_cp
, int *from_cp
,
561 enum cp_status
*cp_status
, int ignore_server_cp
)
563 unsigned char *part
= head
;
567 if_assert_failed
return NULL
;
569 if (ignore_server_cp
) {
570 if (cp_status
) *cp_status
= CP_STATUS_IGNORED
;
571 if (from_cp
) *from_cp
= default_cp
;
572 return get_translation_table(default_cp
, to_cp
);
575 while (cp_index
== -1) {
576 unsigned char *ct_charset
;
578 unsigned char *a
= parse_header(part
, "Content-Type", &part
);
581 /* Content type info from document meta header.
582 * scan_http_equiv() appends the meta stuff to the protocol header before
583 * this function is called. Last Content-Type header field is used. */
585 while ((meta
= parse_header(part
, "Content-Type", &part
))) {
586 mem_free_set(&a
, meta
);
589 parse_header_param(a
, "charset", &ct_charset
);
591 cp_index
= get_cp_index(ct_charset
);
592 mem_free(ct_charset
);
597 if (cp_index
== -1) {
598 unsigned char *a
= parse_header(head
, "Content-Charset", NULL
);
601 cp_index
= get_cp_index(a
);
606 if (cp_index
== -1) {
607 unsigned char *a
= parse_header(head
, "Charset", NULL
);
610 cp_index
= get_cp_index(a
);
615 if (cp_index
== -1) {
616 cp_index
= default_cp
;
617 if (cp_status
) *cp_status
= CP_STATUS_ASSUMED
;
619 if (cp_status
) *cp_status
= CP_STATUS_SERVER
;
622 if (from_cp
) *from_cp
= cp_index
;
624 return get_translation_table(cp_index
, to_cp
);