Bug Summary

File:desktop/browser_window.c
Warning:line 907, column 2
Value stored to 'res' is never read

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-pc-linux-gnu -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name browser_window.c -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -pic-is-pie -mframe-pointer=none -fmath-errno -ffp-contract=on -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -fdebug-compilation-dir=/var/lib/jenkins/workspace/scan-build-netsurf -fcoverage-compilation-dir=/var/lib/jenkins/workspace/scan-build-netsurf -resource-dir /usr/lib/llvm-19/lib/clang/19 -isystem /usr/include/mit-krb5 -I . -I include -I build/Linux-monkey -I frontends -I content/handlers -D WITH_JPEG -U WITH_PDF_EXPORT -D LIBICONV_PLUG -I /var/lib/jenkins/artifacts-x86_64-linux-gnu/include -I /var/lib/jenkins/artifacts-x86_64-linux-gnu/include -I /var/lib/jenkins/artifacts-x86_64-linux-gnu/include -I /usr/include/x86_64-linux-gnu -I /usr/include/p11-kit-1 -D WITH_CURL -D WITH_OPENSSL -I /var/lib/jenkins/artifacts-x86_64-linux-gnu/include -D UTF8PROC_EXPORTS -D WITH_UTF8PROC -I /usr/include/webp -D WITH_WEBP -I /usr/include/libpng16 -D WITH_PNG -I /var/lib/jenkins/artifacts-x86_64-linux-gnu/include/ -D WITH_BMP -I /var/lib/jenkins/artifacts-x86_64-linux-gnu/include -D WITH_GIF -I /var/lib/jenkins/artifacts-x86_64-linux-gnu/include -D WITH_NSPSL -I /var/lib/jenkins/artifacts-x86_64-linux-gnu/include -D WITH_NSLOG -D NETSURF_UA_FORMAT_STRING="Mozilla/5.0 (%s) NetSurf/%d.%d" -D NETSURF_HOMEPAGE="about:welcome" -D NETSURF_LOG_LEVEL=VERBOSE -D NETSURF_BUILTIN_LOG_FILTER="(level:WARNING || cat:jserrors)" -D NETSURF_BUILTIN_VERBOSE_FILTER="(level:VERBOSE || cat:jserrors)" -D STMTEXPR=1 -D monkey -D nsmonkey -D MONKEY_RESPATH="/var/lib/jenkins/artifacts-x86_64-linux-gnu/share/netsurf/" -D _POSIX_C_SOURCE=200809L -D _XOPEN_SOURCE=700 -D _BSD_SOURCE -D _DEFAULT_SOURCE -D _NETBSD_SOURCE -D DUK_OPT_HAVE_CUSTOM_H -internal-isystem /usr/lib/llvm-19/lib/clang/19/include -internal-isystem /usr/local/include -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/14/../../../../x86_64-linux-gnu/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -O2 -Wwrite-strings -Wno-unused-parameter -Wno-unused-but-set-variable -std=c99 -fconst-strings -ferror-limit 19 -fgnuc-version=4.2.1 -fskip-odr-check-in-gmf -vectorize-loops -vectorize-slp -analyzer-display-progress -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /var/lib/jenkins/workspace/scan-build-netsurf/clangScanBuildReports/2025-11-24-141556-2225918-1 -x c desktop/browser_window.c
1/*
2 * Copyright 2008 Michael Drake <tlsa@netsurf-browser.org>
3 * Copyright 2010 Daniel Silverstone <dsilvers@digital-scurf.org>
4 * Copyright 2010-2020 Vincent Sanders <vince@netsurf-browser.org>
5 *
6 * This file is part of NetSurf, http://www.netsurf-browser.org/
7 *
8 * NetSurf is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; version 2 of the License.
11 *
12 * NetSurf is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program. If not, see <http://www.gnu.org/licenses/>.
19 */
20
21/**
22 * \file
23 *
24 * Browser window creation and manipulation implementation.
25 */
26
27#include "utils/config.h"
28
29#include <stdlib.h>
30#include <string.h>
31#include <math.h>
32#include <nsutils/time.h>
33
34#include "utils/errors.h"
35#include "utils/log.h"
36#include "utils/corestrings.h"
37#include "utils/messages.h"
38#include "utils/nsoption.h"
39#include "netsurf/types.h"
40#include "netsurf/browser_window.h"
41#include "netsurf/window.h"
42#include "netsurf/misc.h"
43#include "netsurf/content.h"
44#include "netsurf/search.h"
45#include "netsurf/plotters.h"
46#include "content/content.h"
47#include "content/hlcache.h"
48#include "content/urldb.h"
49#include "content/content_debug.h"
50
51#include "html/html.h"
52#include "html/form_internal.h"
53#include "javascript/js.h"
54
55#include "desktop/browser_private.h"
56#include "desktop/scrollbar.h"
57#include "desktop/gui_internal.h"
58#include "desktop/download.h"
59#include "desktop/frames.h"
60#include "desktop/global_history.h"
61#include "desktop/textinput.h"
62#include "desktop/hotlist.h"
63#include "desktop/knockout.h"
64#include "desktop/browser_history.h"
65#include "desktop/theme.h"
66
67#ifdef WITH_THEME_INSTALL
68#include "desktop/theme.h"
69#endif
70
71/**
72 * smallest scale that can be applied to a browser window
73 */
74#define SCALE_MINIMUM0.2 0.2
75
76/**
77 * largests scale that can be applied to a browser window
78 */
79#define SCALE_MAXIMUM10.0 10.0
80
81/**
82 * maximum frame depth
83 */
84#define FRAME_DEPTH8 8
85
86/* Forward declare internal navigation function */
87static nserror browser_window__navigate_internal(
88 struct browser_window *bw, struct browser_fetch_parameters *params);
89
90
91/**
92 * Close and destroy all child browser window.
93 *
94 * \param bw browser window
95 */
96static void browser_window_destroy_children(struct browser_window *bw)
97{
98 int i;
99
100 if (bw->children) {
101 for (i = 0; i < (bw->rows * bw->cols); i++) {
102 browser_window_destroy_internal(&bw->children[i]);
103 }
104 free(bw->children);
105 bw->children = NULL((void*)0);
106 bw->rows = 0;
107 bw->cols = 0;
108 }
109}
110
111
112/**
113 * Free the stored fetch parameters
114 *
115 * \param bw The browser window
116 */
117static void
118browser_window__free_fetch_parameters(struct browser_fetch_parameters *params)
119{
120 if (params->url != NULL((void*)0)) {
121 nsurl_unref(params->url);
122 params->url = NULL((void*)0);
123 }
124 if (params->referrer != NULL((void*)0)) {
125 nsurl_unref(params->referrer);
126 params->referrer = NULL((void*)0);
127 }
128 if (params->post_urlenc != NULL((void*)0)) {
129 free(params->post_urlenc);
130 params->post_urlenc = NULL((void*)0);
131 }
132 if (params->post_multipart != NULL((void*)0)) {
133 fetch_multipart_data_destroy(params->post_multipart);
134 params->post_multipart = NULL((void*)0);
135 }
136 if (params->parent_charset != NULL((void*)0)) {
137 free(params->parent_charset);
138 params->parent_charset = NULL((void*)0);
139 }
140}
141
142
143/**
144 * Get position of scrollbar widget within browser window.
145 *
146 * \param bw The browser window
147 * \param horizontal Whether to get position of horizontal scrollbar
148 * \param x Updated to x-coord of top left of scrollbar widget
149 * \param y Updated to y-coord of top left of scrollbar widget
150 */
151static inline void
152browser_window_get_scrollbar_pos(struct browser_window *bw,
153 bool_Bool horizontal,
154 int *x, int *y)
155{
156 if (horizontal) {
157 *x = 0;
158 *y = bw->height - SCROLLBAR_WIDTH16;
159 } else {
160 *x = bw->width - SCROLLBAR_WIDTH16;
161 *y = 0;
162 }
163}
164
165
166/**
167 * Get browser window horizontal scrollbar widget length
168 *
169 * \param bw The browser window
170 * \return the scrollbar's length
171 */
172static inline int get_horz_scrollbar_len(struct browser_window *bw)
173{
174 if (bw->scroll_y == NULL((void*)0)) {
175 return bw->width;
176 }
177 return bw->width - SCROLLBAR_WIDTH16;
178}
179
180
181/**
182 * Get browser window vertical scrollbar widget length
183 *
184 * \param bw The browser window
185 * \return the scrollbar's length
186 */
187static inline int get_vert_scrollbar_len(struct browser_window *bw)
188{
189 return bw->height;
190}
191
192
193/**
194 * Set or remove a selection.
195 *
196 * \param bw browser window with selection
197 * \param selection true if bw has a selection, false if removing selection
198 * \param read_only true iff selection is read only (e.g. can't cut it)
199 */
200static void
201browser_window_set_selection(struct browser_window *bw,
202 bool_Bool selection,
203 bool_Bool read_only)
204{
205 struct browser_window *top;
206
207 assert(bw != NULL)((bw != ((void*)0)) ? (void) (0) : __assert_fail ("bw != NULL"
, "desktop/browser_window.c", 207, __extension__ __PRETTY_FUNCTION__
))
;
208
209 top = browser_window_get_root(bw);
210
211 assert(top != NULL)((top != ((void*)0)) ? (void) (0) : __assert_fail ("top != NULL"
, "desktop/browser_window.c", 211, __extension__ __PRETTY_FUNCTION__
))
;
212
213 if (bw != top->selection.bw &&
214 top->selection.bw != NULL((void*)0) &&
215 top->selection.bw->current_content != NULL((void*)0)) {
216 /* clear old selection */
217 content_clear_selection(top->selection.bw->current_content);
218 }
219
220 if (selection) {
221 top->selection.bw = bw;
222 } else {
223 top->selection.bw = NULL((void*)0);
224 }
225
226 top->selection.read_only = read_only;
227}
228
229
230/**
231 * Set the scroll position of a browser window.
232 *
233 * scrolls the viewport to ensure the specified rectangle of the
234 * content is shown.
235 *
236 * \param bw window to scroll
237 * \param rect The rectangle to ensure is shown.
238 * \return NSERROR_OK on success or apropriate error code.
239 */
240static nserror
241browser_window_set_scroll(struct browser_window *bw, const struct rect *rect)
242{
243 if (bw->window != NULL((void*)0)) {
244 return guit->window->set_scroll(bw->window, rect);
245 }
246
247 if (bw->scroll_x != NULL((void*)0)) {
248 scrollbar_set(bw->scroll_x, rect->x0, false0);
249 }
250 if (bw->scroll_y != NULL((void*)0)) {
251 scrollbar_set(bw->scroll_y, rect->y0, false0);
252 }
253
254 return NSERROR_OK;
255}
256
257
258/**
259 * Internal helper for getting the positional features
260 *
261 * \param[in] bw browser window to examine.
262 * \param[in] x x-coordinate of point of interest
263 * \param[in] y y-coordinate of point of interest
264 * \param[out] data Feature structure to update.
265 * \return NSERROR_OK or appropriate error code on faliure.
266 */
267static nserror
268browser_window__get_contextual_content(struct browser_window *bw,
269 int x, int y,
270 struct browser_window_features *data)
271{
272 nserror ret = NSERROR_OK;
273
274 /* Handle (i)frame scroll offset (core-managed browser windows only) */
275 x += scrollbar_get_offset(bw->scroll_x);
276 y += scrollbar_get_offset(bw->scroll_y);
277
278 if (bw->children) {
279 /* Browser window has children, so pass request on to
280 * appropriate child.
281 */
282 struct browser_window *bwc;
283 int cur_child;
284 int children = bw->rows * bw->cols;
285
286 /* Loop through all children of bw */
287 for (cur_child = 0; cur_child < children; cur_child++) {
288 /* Set current child */
289 bwc = &bw->children[cur_child];
290
291 /* Skip this frame if (x, y) coord lies outside */
292 if ((x < bwc->x) ||
293 (bwc->x + bwc->width < x) ||
294 (y < bwc->y) ||
295 (bwc->y + bwc->height < y)) {
296 continue;
297 }
298
299 /* Pass request into this child */
300 return browser_window__get_contextual_content(bwc,
301 (x - bwc->x), (y - bwc->y), data);
302 }
303
304 /* Coordinate not contained by any frame */
305
306 } else if (bw->current_content != NULL((void*)0)) {
307 /* Pass request to content */
308 ret = content_get_contextual_content(bw->current_content,
309 x, y, data);
310 data->main = bw->current_content;
311 }
312
313 return ret;
314}
315
316
317/**
318 * implements the download operation of a window navigate
319 */
320static nserror
321browser_window_download(struct browser_window *bw,
322 nsurl *url,
323 nsurl *nsref,
324 uint32_t fetch_flags,
325 bool_Bool fetch_is_post,
326 llcache_post_data *post)
327{
328 llcache_handle *l;
329 struct browser_window *root;
330 nserror error;
331
332 root = browser_window_get_root(bw);
333 assert(root != NULL)((root != ((void*)0)) ? (void) (0) : __assert_fail ("root != NULL"
, "desktop/browser_window.c", 333, __extension__ __PRETTY_FUNCTION__
))
;
334
335 fetch_flags |= LLCACHE_RETRIEVE_FORCE_FETCH;
336 fetch_flags |= LLCACHE_RETRIEVE_STREAM_DATA;
337
338 error = llcache_handle_retrieve(url, fetch_flags, nsref,
339 fetch_is_post ? post : NULL((void*)0),
340 NULL((void*)0), NULL((void*)0), &l);
341 if (error == NSERROR_NO_FETCH_HANDLER) {
342 /* no internal handler for this type, call out to frontend */
343 error = guit->misc->launch_url(url);
344 } else if (error != NSERROR_OK) {
345 NSLOG(netsurf, INFO, "Failed to fetch download: %d", error)do { if (NSLOG_LEVEL_INFO >= NSLOG_LEVEL_VERBOSE) { static
nslog_entry_context_t _nslog_ctx = { &__nslog_category_netsurf
, NSLOG_LEVEL_INFO, "desktop/browser_window.c", sizeof("desktop/browser_window.c"
) - 1, __PRETTY_FUNCTION__, sizeof(__PRETTY_FUNCTION__) - 1, 345
, }; nslog__log(&_nslog_ctx, "Failed to fetch download: %d"
, error); } } while(0)
;
346 } else {
347 error = download_context_create(l, root->window);
348 if (error != NSERROR_OK) {
349 NSLOG(netsurf, INFO,do { if (NSLOG_LEVEL_INFO >= NSLOG_LEVEL_VERBOSE) { static
nslog_entry_context_t _nslog_ctx = { &__nslog_category_netsurf
, NSLOG_LEVEL_INFO, "desktop/browser_window.c", sizeof("desktop/browser_window.c"
) - 1, __PRETTY_FUNCTION__, sizeof(__PRETTY_FUNCTION__) - 1, 350
, }; nslog__log(&_nslog_ctx, "Failed creating download context: %d"
, error); } } while(0)
350 "Failed creating download context: %d", error)do { if (NSLOG_LEVEL_INFO >= NSLOG_LEVEL_VERBOSE) { static
nslog_entry_context_t _nslog_ctx = { &__nslog_category_netsurf
, NSLOG_LEVEL_INFO, "desktop/browser_window.c", sizeof("desktop/browser_window.c"
) - 1, __PRETTY_FUNCTION__, sizeof(__PRETTY_FUNCTION__) - 1, 350
, }; nslog__log(&_nslog_ctx, "Failed creating download context: %d"
, error); } } while(0)
;
351 llcache_handle_abort(l);
352 llcache_handle_release(l);
353 }
354 }
355
356 return error;
357}
358
359
360/**
361 * recursively check browser windows for activity
362 *
363 * \param bw browser window to start checking from.
364 */
365static bool_Bool browser_window_check_throbber(struct browser_window *bw)
366{
367 int children, index;
368
369 if (bw->throbbing)
370 return true1;
371
372 if (bw->children) {
373 children = bw->rows * bw->cols;
374 for (index = 0; index < children; index++) {
375 if (browser_window_check_throbber(&bw->children[index]))
376 return true1;
377 }
378 }
379
380 if (bw->iframes) {
381 for (index = 0; index < bw->iframe_count; index++) {
382 if (browser_window_check_throbber(&bw->iframes[index]))
383 return true1;
384 }
385 }
386
387 return false0;
388}
389
390
391/**
392 * Start the busy indicator.
393 *
394 * \param bw browser window
395 */
396static nserror browser_window_start_throbber(struct browser_window *bw)
397{
398 bw->throbbing = true1;
399
400 while (bw->parent)
401 bw = bw->parent;
402
403 return guit->window->event(bw->window, GW_EVENT_START_THROBBER);
404}
405
406
407/**
408 * Stop the busy indicator.
409 *
410 * \param bw browser window
411 */
412static nserror browser_window_stop_throbber(struct browser_window *bw)
413{
414 nserror res = NSERROR_OK;
415
416 bw->throbbing = false0;
417
418 while (bw->parent) {
419 bw = bw->parent;
420 }
421
422 if (!browser_window_check_throbber(bw)) {
423 res = guit->window->event(bw->window, GW_EVENT_STOP_THROBBER);
424 }
425 return res;
426}
427
428
429/**
430 * Callback for fetchcache() for browser window favicon fetches.
431 *
432 * \param c content handle of favicon
433 * \param event The event to process
434 * \param pw a context containing the browser window
435 * \return NSERROR_OK on success else appropriate error code.
436 */
437static nserror
438browser_window_favicon_callback(hlcache_handle *c,
439 const hlcache_event *event,
440 void *pw)
441{
442 struct browser_window *bw = pw;
443
444 switch (event->type) {
445 case CONTENT_MSG_DONE:
446 if (bw->favicon.current != NULL((void*)0)) {
447 content_close(bw->favicon.current);
448 hlcache_handle_release(bw->favicon.current);
449 }
450
451 bw->favicon.current = c;
452 bw->favicon.loading = NULL((void*)0);
453
454 /* content_get_bitmap on the hlcache_handle should give
455 * the favicon bitmap at this point
456 */
457 guit->window->set_icon(bw->window, c);
458 break;
459
460 case CONTENT_MSG_ERROR:
461
462 /* clean up after ourselves */
463 if (c == bw->favicon.loading) {
464 bw->favicon.loading = NULL((void*)0);
465 } else if (c == bw->favicon.current) {
466 bw->favicon.current = NULL((void*)0);
467 }
468
469 hlcache_handle_release(c);
470
471 if (bw->favicon.failed == false0) {
472 nsurl *nsref = NULL((void*)0);
473 nsurl *nsurl;
474 nserror error;
475
476 bw->favicon.failed = true1;
477
478 error = nsurl_create("resource:favicon.ico", &nsurl);
479 if (error != NSERROR_OK) {
480 NSLOG(netsurf, INFO,do { if (NSLOG_LEVEL_INFO >= NSLOG_LEVEL_VERBOSE) { static
nslog_entry_context_t _nslog_ctx = { &__nslog_category_netsurf
, NSLOG_LEVEL_INFO, "desktop/browser_window.c", sizeof("desktop/browser_window.c"
) - 1, __PRETTY_FUNCTION__, sizeof(__PRETTY_FUNCTION__) - 1, 481
, }; nslog__log(&_nslog_ctx, "Unable to create default location url"
); } } while(0)
481 "Unable to create default location url")do { if (NSLOG_LEVEL_INFO >= NSLOG_LEVEL_VERBOSE) { static
nslog_entry_context_t _nslog_ctx = { &__nslog_category_netsurf
, NSLOG_LEVEL_INFO, "desktop/browser_window.c", sizeof("desktop/browser_window.c"
) - 1, __PRETTY_FUNCTION__, sizeof(__PRETTY_FUNCTION__) - 1, 481
, }; nslog__log(&_nslog_ctx, "Unable to create default location url"
); } } while(0)
;
482 } else {
483 hlcache_handle_retrieve(nsurl,
484 HLCACHE_RETRIEVE_SNIFF_TYPE,
485 nsref, NULL((void*)0),
486 browser_window_favicon_callback,
487 bw, NULL((void*)0), CONTENT_IMAGE,
488 &bw->favicon.loading);
489
490 nsurl_unref(nsurl);
491 }
492
493 }
494 break;
495
496 default:
497 break;
498
499 }
500 return NSERROR_OK;
501}
502
503
504/**
505 * update the favicon associated with the browser window
506 *
507 * \param c the page content handle.
508 * \param bw A top level browser window.
509 * \param link A link context or NULL to attempt fallback scanning.
510 */
511static nserror
512browser_window_update_favicon(hlcache_handle *c,
513 struct browser_window *bw,
514 struct content_rfc5988_link *link)
515{
516 nsurl *nsref = NULL((void*)0);
517 nsurl *nsurl;
518 nserror res;
519
520 assert(c != NULL)((c != ((void*)0)) ? (void) (0) : __assert_fail ("c != NULL",
"desktop/browser_window.c", 520, __extension__ __PRETTY_FUNCTION__
))
;
521 assert(bw !=NULL)((bw !=((void*)0)) ? (void) (0) : __assert_fail ("bw !=NULL",
"desktop/browser_window.c", 521, __extension__ __PRETTY_FUNCTION__
))
;
522
523 if (bw->window == NULL((void*)0)) {
524 /* Not top-level browser window; not interested */
525 return NSERROR_OK;
526 }
527
528 /* already fetching the favicon - use that */
529 if (bw->favicon.loading != NULL((void*)0)) {
530 return NSERROR_OK;
531 }
532
533 bw->favicon.failed = false0;
534
535 if (link == NULL((void*)0)) {
536 /* Look for "icon" */
537 link = content_find_rfc5988_link(c, corestring_lwc_icon);
538 }
539
540 if (link == NULL((void*)0)) {
541 /* Look for "shortcut icon" */
542 link = content_find_rfc5988_link(c, corestring_lwc_shortcut_icon);
543 }
544
545 if (link == NULL((void*)0)) {
546 lwc_string *scheme;
547 bool_Bool speculative_default = false0;
548 bool_Bool match;
549
550 nsurl = hlcache_handle_get_url(c);
551
552 scheme = nsurl_get_component(nsurl, NSURL_SCHEME);
553
554 /* If the document was fetched over http(s), then speculate
555 * that there's a favicon living at /favicon.ico */
556 if ((lwc_string_caseless_isequal(scheme,({ lwc_error __lwc_err = lwc_error_ok; lwc_string *__lwc_str1
= (scheme); lwc_string *__lwc_str2 = (corestring_lwc_http); _Bool
*__lwc_ret = (&match); if (__lwc_str1->insensitive ==
((void*)0)) { __lwc_err = lwc__intern_caseless_string(__lwc_str1
); } if (__lwc_err == lwc_error_ok && __lwc_str2->
insensitive == ((void*)0)) { __lwc_err = lwc__intern_caseless_string
(__lwc_str2); } if (__lwc_err == lwc_error_ok) *__lwc_ret = (
__lwc_str1->insensitive == __lwc_str2->insensitive); __lwc_err
; })
557 corestring_lwc_http,({ lwc_error __lwc_err = lwc_error_ok; lwc_string *__lwc_str1
= (scheme); lwc_string *__lwc_str2 = (corestring_lwc_http); _Bool
*__lwc_ret = (&match); if (__lwc_str1->insensitive ==
((void*)0)) { __lwc_err = lwc__intern_caseless_string(__lwc_str1
); } if (__lwc_err == lwc_error_ok && __lwc_str2->
insensitive == ((void*)0)) { __lwc_err = lwc__intern_caseless_string
(__lwc_str2); } if (__lwc_err == lwc_error_ok) *__lwc_ret = (
__lwc_str1->insensitive == __lwc_str2->insensitive); __lwc_err
; })
558 &match)({ lwc_error __lwc_err = lwc_error_ok; lwc_string *__lwc_str1
= (scheme); lwc_string *__lwc_str2 = (corestring_lwc_http); _Bool
*__lwc_ret = (&match); if (__lwc_str1->insensitive ==
((void*)0)) { __lwc_err = lwc__intern_caseless_string(__lwc_str1
); } if (__lwc_err == lwc_error_ok && __lwc_str2->
insensitive == ((void*)0)) { __lwc_err = lwc__intern_caseless_string
(__lwc_str2); } if (__lwc_err == lwc_error_ok) *__lwc_ret = (
__lwc_str1->insensitive == __lwc_str2->insensitive); __lwc_err
; })
== lwc_error_ok &&
559 match) ||
560 (lwc_string_caseless_isequal(scheme,({ lwc_error __lwc_err = lwc_error_ok; lwc_string *__lwc_str1
= (scheme); lwc_string *__lwc_str2 = (corestring_lwc_https);
_Bool *__lwc_ret = (&match); if (__lwc_str1->insensitive
== ((void*)0)) { __lwc_err = lwc__intern_caseless_string(__lwc_str1
); } if (__lwc_err == lwc_error_ok && __lwc_str2->
insensitive == ((void*)0)) { __lwc_err = lwc__intern_caseless_string
(__lwc_str2); } if (__lwc_err == lwc_error_ok) *__lwc_ret = (
__lwc_str1->insensitive == __lwc_str2->insensitive); __lwc_err
; })
561 corestring_lwc_https,({ lwc_error __lwc_err = lwc_error_ok; lwc_string *__lwc_str1
= (scheme); lwc_string *__lwc_str2 = (corestring_lwc_https);
_Bool *__lwc_ret = (&match); if (__lwc_str1->insensitive
== ((void*)0)) { __lwc_err = lwc__intern_caseless_string(__lwc_str1
); } if (__lwc_err == lwc_error_ok && __lwc_str2->
insensitive == ((void*)0)) { __lwc_err = lwc__intern_caseless_string
(__lwc_str2); } if (__lwc_err == lwc_error_ok) *__lwc_ret = (
__lwc_str1->insensitive == __lwc_str2->insensitive); __lwc_err
; })
562 &match)({ lwc_error __lwc_err = lwc_error_ok; lwc_string *__lwc_str1
= (scheme); lwc_string *__lwc_str2 = (corestring_lwc_https);
_Bool *__lwc_ret = (&match); if (__lwc_str1->insensitive
== ((void*)0)) { __lwc_err = lwc__intern_caseless_string(__lwc_str1
); } if (__lwc_err == lwc_error_ok && __lwc_str2->
insensitive == ((void*)0)) { __lwc_err = lwc__intern_caseless_string
(__lwc_str2); } if (__lwc_err == lwc_error_ok) *__lwc_ret = (
__lwc_str1->insensitive == __lwc_str2->insensitive); __lwc_err
; })
== lwc_error_ok &&
563 match)) {
564 speculative_default = true1;
565 }
566
567 lwc_string_unref(scheme){ lwc_string *__lwc_s = (scheme); ((__lwc_s != ((void*)0)) ? (
void) (0) : __assert_fail ("__lwc_s != NULL", "desktop/browser_window.c"
, 567, __extension__ __PRETTY_FUNCTION__)); __lwc_s->refcnt
--; if ((__lwc_s->refcnt == 0) || ((__lwc_s->refcnt == 1
) && (__lwc_s->insensitive == __lwc_s))) lwc_string_destroy
(__lwc_s); }
;
568
569 if (speculative_default) {
570 /* no favicon via link, try for the default location */
571 res = nsurl_join(nsurl, "/favicon.ico", &nsurl);
572 } else {
573 bw->favicon.failed = true1;
574 res = nsurl_create("resource:favicon.ico", &nsurl);
575 }
576 if (res != NSERROR_OK) {
577 NSLOG(netsurf, INFO,do { if (NSLOG_LEVEL_INFO >= NSLOG_LEVEL_VERBOSE) { static
nslog_entry_context_t _nslog_ctx = { &__nslog_category_netsurf
, NSLOG_LEVEL_INFO, "desktop/browser_window.c", sizeof("desktop/browser_window.c"
) - 1, __PRETTY_FUNCTION__, sizeof(__PRETTY_FUNCTION__) - 1, 578
, }; nslog__log(&_nslog_ctx, "Unable to create default location url"
); } } while(0)
578 "Unable to create default location url")do { if (NSLOG_LEVEL_INFO >= NSLOG_LEVEL_VERBOSE) { static
nslog_entry_context_t _nslog_ctx = { &__nslog_category_netsurf
, NSLOG_LEVEL_INFO, "desktop/browser_window.c", sizeof("desktop/browser_window.c"
) - 1, __PRETTY_FUNCTION__, sizeof(__PRETTY_FUNCTION__) - 1, 578
, }; nslog__log(&_nslog_ctx, "Unable to create default location url"
); } } while(0)
;
579 return res;
580 }
581 } else {
582 nsurl = nsurl_ref(link->href);
583 }
584
585 if (link == NULL((void*)0)) {
586 NSLOG(netsurf, INFO,do { if (NSLOG_LEVEL_INFO >= NSLOG_LEVEL_VERBOSE) { static
nslog_entry_context_t _nslog_ctx = { &__nslog_category_netsurf
, NSLOG_LEVEL_INFO, "desktop/browser_window.c", sizeof("desktop/browser_window.c"
) - 1, __PRETTY_FUNCTION__, sizeof(__PRETTY_FUNCTION__) - 1, 588
, }; nslog__log(&_nslog_ctx, "fetching general favicon from '%s'"
, nsurl_access(nsurl)); } } while(0)
587 "fetching general favicon from '%s'",do { if (NSLOG_LEVEL_INFO >= NSLOG_LEVEL_VERBOSE) { static
nslog_entry_context_t _nslog_ctx = { &__nslog_category_netsurf
, NSLOG_LEVEL_INFO, "desktop/browser_window.c", sizeof("desktop/browser_window.c"
) - 1, __PRETTY_FUNCTION__, sizeof(__PRETTY_FUNCTION__) - 1, 588
, }; nslog__log(&_nslog_ctx, "fetching general favicon from '%s'"
, nsurl_access(nsurl)); } } while(0)
588 nsurl_access(nsurl))do { if (NSLOG_LEVEL_INFO >= NSLOG_LEVEL_VERBOSE) { static
nslog_entry_context_t _nslog_ctx = { &__nslog_category_netsurf
, NSLOG_LEVEL_INFO, "desktop/browser_window.c", sizeof("desktop/browser_window.c"
) - 1, __PRETTY_FUNCTION__, sizeof(__PRETTY_FUNCTION__) - 1, 588
, }; nslog__log(&_nslog_ctx, "fetching general favicon from '%s'"
, nsurl_access(nsurl)); } } while(0)
;
589 } else {
590 NSLOG(netsurf, INFO,do { if (NSLOG_LEVEL_INFO >= NSLOG_LEVEL_VERBOSE) { static
nslog_entry_context_t _nslog_ctx = { &__nslog_category_netsurf
, NSLOG_LEVEL_INFO, "desktop/browser_window.c", sizeof("desktop/browser_window.c"
) - 1, __PRETTY_FUNCTION__, sizeof(__PRETTY_FUNCTION__) - 1, 593
, }; nslog__log(&_nslog_ctx, "fetching favicon rel:%s '%s'"
, ({((link->rel != ((void*)0)) ? (void) (0) : __assert_fail
("link->rel != NULL", "desktop/browser_window.c", 593, __extension__
__PRETTY_FUNCTION__)); (const char *)((link->rel)+1);}), nsurl_access
(nsurl)); } } while(0)
591 "fetching favicon rel:%s '%s'",do { if (NSLOG_LEVEL_INFO >= NSLOG_LEVEL_VERBOSE) { static
nslog_entry_context_t _nslog_ctx = { &__nslog_category_netsurf
, NSLOG_LEVEL_INFO, "desktop/browser_window.c", sizeof("desktop/browser_window.c"
) - 1, __PRETTY_FUNCTION__, sizeof(__PRETTY_FUNCTION__) - 1, 593
, }; nslog__log(&_nslog_ctx, "fetching favicon rel:%s '%s'"
, ({((link->rel != ((void*)0)) ? (void) (0) : __assert_fail
("link->rel != NULL", "desktop/browser_window.c", 593, __extension__
__PRETTY_FUNCTION__)); (const char *)((link->rel)+1);}), nsurl_access
(nsurl)); } } while(0)
592 lwc_string_data(link->rel),do { if (NSLOG_LEVEL_INFO >= NSLOG_LEVEL_VERBOSE) { static
nslog_entry_context_t _nslog_ctx = { &__nslog_category_netsurf
, NSLOG_LEVEL_INFO, "desktop/browser_window.c", sizeof("desktop/browser_window.c"
) - 1, __PRETTY_FUNCTION__, sizeof(__PRETTY_FUNCTION__) - 1, 593
, }; nslog__log(&_nslog_ctx, "fetching favicon rel:%s '%s'"
, ({((link->rel != ((void*)0)) ? (void) (0) : __assert_fail
("link->rel != NULL", "desktop/browser_window.c", 593, __extension__
__PRETTY_FUNCTION__)); (const char *)((link->rel)+1);}), nsurl_access
(nsurl)); } } while(0)
593 nsurl_access(nsurl))do { if (NSLOG_LEVEL_INFO >= NSLOG_LEVEL_VERBOSE) { static
nslog_entry_context_t _nslog_ctx = { &__nslog_category_netsurf
, NSLOG_LEVEL_INFO, "desktop/browser_window.c", sizeof("desktop/browser_window.c"
) - 1, __PRETTY_FUNCTION__, sizeof(__PRETTY_FUNCTION__) - 1, 593
, }; nslog__log(&_nslog_ctx, "fetching favicon rel:%s '%s'"
, ({((link->rel != ((void*)0)) ? (void) (0) : __assert_fail
("link->rel != NULL", "desktop/browser_window.c", 593, __extension__
__PRETTY_FUNCTION__)); (const char *)((link->rel)+1);}), nsurl_access
(nsurl)); } } while(0)
;
594 }
595
596 res = hlcache_handle_retrieve(nsurl,
597 HLCACHE_RETRIEVE_SNIFF_TYPE,
598 nsref,
599 NULL((void*)0),
600 browser_window_favicon_callback,
601 bw,
602 NULL((void*)0),
603 CONTENT_IMAGE,
604 &bw->favicon.loading);
605
606 nsurl_unref(nsurl);
607
608 return res;
609}
610
611
612/**
613 * Handle meta http-equiv refresh time elapsing by loading a new page.
614 *
615 * \param p browser window to refresh with new page
616 */
617static void browser_window_refresh(void *p)
618{
619 struct browser_window *bw = p;
620 nsurl *url;
621 nsurl *refresh;
622 hlcache_handle *parent = NULL((void*)0);
623 enum browser_window_nav_flags flags = BW_NAVIGATE_UNVERIFIABLE;
624
625 assert(bw->current_content != NULL &&((bw->current_content != ((void*)0) && (content_get_status
(bw->current_content) == CONTENT_STATUS_READY || content_get_status
(bw->current_content) == CONTENT_STATUS_DONE)) ? (void) (0
) : __assert_fail ("bw->current_content != NULL && (content_get_status(bw->current_content) == CONTENT_STATUS_READY || content_get_status(bw->current_content) == CONTENT_STATUS_DONE)"
, "desktop/browser_window.c", 629, __extension__ __PRETTY_FUNCTION__
))
626 (content_get_status(bw->current_content) ==((bw->current_content != ((void*)0) && (content_get_status
(bw->current_content) == CONTENT_STATUS_READY || content_get_status
(bw->current_content) == CONTENT_STATUS_DONE)) ? (void) (0
) : __assert_fail ("bw->current_content != NULL && (content_get_status(bw->current_content) == CONTENT_STATUS_READY || content_get_status(bw->current_content) == CONTENT_STATUS_DONE)"
, "desktop/browser_window.c", 629, __extension__ __PRETTY_FUNCTION__
))
627 CONTENT_STATUS_READY ||((bw->current_content != ((void*)0) && (content_get_status
(bw->current_content) == CONTENT_STATUS_READY || content_get_status
(bw->current_content) == CONTENT_STATUS_DONE)) ? (void) (0
) : __assert_fail ("bw->current_content != NULL && (content_get_status(bw->current_content) == CONTENT_STATUS_READY || content_get_status(bw->current_content) == CONTENT_STATUS_DONE)"
, "desktop/browser_window.c", 629, __extension__ __PRETTY_FUNCTION__
))
628 content_get_status(bw->current_content) ==((bw->current_content != ((void*)0) && (content_get_status
(bw->current_content) == CONTENT_STATUS_READY || content_get_status
(bw->current_content) == CONTENT_STATUS_DONE)) ? (void) (0
) : __assert_fail ("bw->current_content != NULL && (content_get_status(bw->current_content) == CONTENT_STATUS_READY || content_get_status(bw->current_content) == CONTENT_STATUS_DONE)"
, "desktop/browser_window.c", 629, __extension__ __PRETTY_FUNCTION__
))
629 CONTENT_STATUS_DONE))((bw->current_content != ((void*)0) && (content_get_status
(bw->current_content) == CONTENT_STATUS_READY || content_get_status
(bw->current_content) == CONTENT_STATUS_DONE)) ? (void) (0
) : __assert_fail ("bw->current_content != NULL && (content_get_status(bw->current_content) == CONTENT_STATUS_READY || content_get_status(bw->current_content) == CONTENT_STATUS_DONE)"
, "desktop/browser_window.c", 629, __extension__ __PRETTY_FUNCTION__
))
;
630
631 /* Ignore if the refresh URL has gone
632 * (may happen if a fetch error occurred) */
633 refresh = content_get_refresh_url(bw->current_content);
634 if (refresh == NULL((void*)0))
635 return;
636
637 /* mark this content as invalid so it gets flushed from the cache */
638 content_invalidate_reuse_data(bw->current_content);
639
640 url = hlcache_handle_get_url(bw->current_content);
641 if ((url == NULL((void*)0)) || (nsurl_compare(url, refresh, NSURL_COMPLETE))) {
642 flags |= BW_NAVIGATE_HISTORY;
643 }
644
645 /* Treat an (almost) immediate refresh in a top-level browser window as
646 * if it were an HTTP redirect, and thus make the resulting fetch
647 * verifiable.
648 *
649 * See fetchcache.c for why redirected fetches should be verifiable at
650 * all.
651 */
652 if (bw->refresh_interval <= 100 && bw->parent == NULL((void*)0)) {
653 flags &= ~BW_NAVIGATE_UNVERIFIABLE;
654 } else {
655 parent = bw->current_content;
656 }
657
658 browser_window_navigate(bw,
659 refresh,
660 url,
661 flags,
662 NULL((void*)0),
663 NULL((void*)0),
664 parent);
665
666}
667
668
669/**
670 * Transfer the loading_content to a new download window.
671 */
672static void
673browser_window_convert_to_download(struct browser_window *bw,
674 llcache_handle *stream)
675{
676 struct browser_window *root = browser_window_get_root(bw);
677 nserror error;
678
679 assert(root != NULL)((root != ((void*)0)) ? (void) (0) : __assert_fail ("root != NULL"
, "desktop/browser_window.c", 679, __extension__ __PRETTY_FUNCTION__
))
;
680
681 error = download_context_create(stream, root->window);
682 if (error != NSERROR_OK) {
683 llcache_handle_abort(stream);
684 llcache_handle_release(stream);
685 }
686
687 /* remove content from browser window */
688 hlcache_handle_release(bw->loading_content);
689 bw->loading_content = NULL((void*)0);
690
691 browser_window_stop_throbber(bw);
692}
693
694
695/**
696 * scroll to a fragment if present
697 *
698 * \param bw browser window
699 * \return true if the scroll was sucessful
700 */
701static bool_Bool frag_scroll(struct browser_window *bw)
702{
703 struct rect rect;
704
705 if (bw->frag_id == NULL((void*)0)) {
706 return false0;
707 }
708
709 if (!html_get_id_offset(bw->current_content,
710 bw->frag_id,
711 &rect.x0,
712 &rect.y0)) {
713 return false0;
714 }
715
716 rect.x1 = rect.x0;
717 rect.y1 = rect.y0;
718 if (browser_window_set_scroll(bw, &rect) == NSERROR_OK) {
719 if (bw->current_content != NULL((void*)0) &&
720 bw->history != NULL((void*)0) &&
721 bw->history->current != NULL((void*)0)) {
722 browser_window_history_update(bw, bw->current_content);
723 }
724 return true1;
725 }
726 return false0;
727}
728
729
730/**
731 * Redraw browser window, set extent to content, and update title.
732 *
733 * \param bw browser_window
734 * \param scroll_to_top move view to top of page
735 */
736static void browser_window_update(struct browser_window *bw, bool_Bool scroll_to_top)
737{
738 static const struct rect zrect = {
739 .x0 = 0,
740 .y0 = 0,
741 .x1 = 0,
742 .y1 = 0
743 };
744
745 if (bw->current_content == NULL((void*)0)) {
746 return;
747 }
748
749 switch (bw->browser_window_type) {
750
751 case BROWSER_WINDOW_NORMAL:
752 /* Root browser window, constituting a front end window/tab */
753 guit->window->set_title(bw->window,
754 content_get_title(bw->current_content));
755
756 browser_window_update_extent(bw);
757
758 /* if frag_id exists, then try to scroll to it */
759 /** @todo don't do this if the user has scrolled */
760 if (!frag_scroll(bw)) {
761 if (scroll_to_top) {
762 browser_window_set_scroll(bw, &zrect);
763 }
764 }
765
766 guit->window->invalidate(bw->window, NULL((void*)0));
767
768 break;
769
770 case BROWSER_WINDOW_IFRAME:
771 /* Internal iframe browser window */
772 assert(bw->parent != NULL)((bw->parent != ((void*)0)) ? (void) (0) : __assert_fail (
"bw->parent != NULL", "desktop/browser_window.c", 772, __extension__
__PRETTY_FUNCTION__))
;
773 assert(bw->parent->current_content != NULL)((bw->parent->current_content != ((void*)0)) ? (void) (
0) : __assert_fail ("bw->parent->current_content != NULL"
, "desktop/browser_window.c", 773, __extension__ __PRETTY_FUNCTION__
))
;
774
775 browser_window_update_extent(bw);
776
777 if (scroll_to_top) {
778 browser_window_set_scroll(bw, &zrect);
779 }
780
781 /* if frag_id exists, then try to scroll to it */
782 /** @todo don't do this if the user has scrolled */
783 frag_scroll(bw);
784
785 browser_window_invalidate_iframe(bw);
786
787 break;
788
789 case BROWSER_WINDOW_FRAME:
790 {
791 struct rect rect;
792 browser_window_update_extent(bw);
793
794 if (scroll_to_top) {
795 browser_window_set_scroll(bw, &zrect);
796 }
797
798 /* if frag_id exists, then try to scroll to it */
799 /** @todo don't do this if the user has scrolled */
800 frag_scroll(bw);
801
802 rect.x0 = scrollbar_get_offset(bw->scroll_x);
803 rect.y0 = scrollbar_get_offset(bw->scroll_y);
804 rect.x1 = rect.x0 + bw->width;
805 rect.y1 = rect.y0 + bw->height;
806
807 browser_window_invalidate_rect(bw, &rect);
808 }
809 break;
810
811 default:
812 case BROWSER_WINDOW_FRAMESET:
813 /* Nothing to do */
814 break;
815 }
816}
817
818
819/**
820 * handle message for content ready on browser window
821 */
822static nserror browser_window_content_ready(struct browser_window *bw)
1
[debug] analyzing from browser_window_content_ready
823{
824 int width, height;
825 nserror res = NSERROR_OK;
826
827 /* close and release the current window content */
828 if (bw->current_content != NULL((void*)0)) {
829 content_close(bw->current_content);
830 hlcache_handle_release(bw->current_content);
831 }
832
833 bw->current_content = bw->loading_content;
834 bw->loading_content = NULL((void*)0);
835
836 if (!bw->internal_nav) {
837 /* Transfer the fetch parameters */
838 browser_window__free_fetch_parameters(&bw->current_parameters);
839 bw->current_parameters = bw->loading_parameters;
840 memset(&bw->loading_parameters, 0, sizeof(bw->loading_parameters));
841 /* Transfer the certificate chain */
842 cert_chain_free(bw->current_cert_chain);
843 bw->current_cert_chain = bw->loading_cert_chain;
844 bw->loading_cert_chain = NULL((void*)0);
845 }
846
847 /* Format the new content to the correct dimensions */
848 browser_window_get_dimensions(bw, &width, &height);
849 width /= bw->scale;
850 height /= bw->scale;
851 content_reformat(bw->current_content, false0, width, height);
852
853 /* history */
854 if (bw->history_add && bw->history && !bw->internal_nav) {
855 nsurl *url = hlcache_handle_get_url(bw->current_content);
856
857 if (urldb_add_url(url)) {
858 urldb_set_url_title(url, content_get_title(bw->current_content));
859 urldb_update_url_visit_data(url);
860 urldb_set_url_content_type(url,
861 content_get_type(bw->current_content));
862
863 /* This is safe as we've just added the URL */
864 global_history_add(urldb_get_url(url));
865 }
866 /**
867 * \todo Urldb / Thumbnails / Local history brokenness
868 *
869 * We add to local history after calling urldb_add_url rather
870 * than in the block above. If urldb_add_url fails (as it
871 * will for urls like "about:about", "about:config" etc),
872 * there would be no local history node, and later calls to
873 * history_update will either explode or overwrite the node
874 * for the previous URL.
875 *
876 * We call it after, rather than before urldb_add_url because
877 * history_add calls bitmap render, which tries to register
878 * the thumbnail with urldb. That thumbnail registration
879 * fails if the url doesn't exist in urldb already, and only
880 * urldb-registered thumbnails get freed. So if we called
881 * history_add before urldb_add_url we would leak thumbnails
882 * for all newly visited URLs. With the history_add call
883 * after, we only leak the thumbnails when urldb does not add
884 * the URL.
885 *
886 * Also, since browser_window_history_add can create a
887 * thumbnail (content_redraw), we need to do it after
888 * content_reformat.
889 */
890 browser_window_history_add(bw, bw->current_content, bw->frag_id);
891 }
892
893 browser_window_remove_caret(bw, false0);
894
895 if (bw->window != NULL((void*)0)) {
896 guit->window->event(bw->window, GW_EVENT_NEW_CONTENT);
897
898 browser_window_refresh_url_bar(bw);
899 }
900
901 /* new content; set scroll_to_top */
902 browser_window_update(bw, true1);
903 content_open(bw->current_content, bw, 0, 0);
904 browser_window_set_status(bw, content_get_status_message(bw->current_content));
905
906 /* frames */
907 res = browser_window_create_frameset(bw);
2
Value stored to 'res' is never read
908
909 /* iframes */
910 res = browser_window_create_iframes(bw);
911
912 /* Indicate page status may have changed */
913 if (res == NSERROR_OK) {
914 struct browser_window *root = browser_window_get_root(bw);
915 res = guit->window->event(root->window, GW_EVENT_PAGE_INFO_CHANGE);
916 }
917
918 return res;
919}
920
921
922/**
923 * handle message for content done on browser window
924 */
925static nserror
926browser_window_content_done(struct browser_window *bw)
927{
928 float sx, sy;
929 struct rect rect;
930 int scrollx;
931 int scrolly;
932
933 if (bw->window == NULL((void*)0)) {
934 /* Updated browser window's scrollbars. */
935 /**
936 * \todo update browser window scrollbars before CONTENT_MSG_DONE
937 */
938 browser_window_reformat(bw, true1, bw->width, bw->height);
939 browser_window_handle_scrollbars(bw);
940 }
941
942 browser_window_update(bw, false0);
943 browser_window_set_status(bw, content_get_status_message(bw->current_content));
944 browser_window_stop_throbber(bw);
945 browser_window_update_favicon(bw->current_content, bw, NULL((void*)0));
946
947 if (browser_window_history_get_scroll(bw, &sx, &sy) == NSERROR_OK) {
948 scrollx = (int)((float)content_get_width(bw->current_content) * sx);
949 scrolly = (int)((float)content_get_height(bw->current_content) * sy);
950 rect.x0 = rect.x1 = scrollx;
951 rect.y0 = rect.y1 = scrolly;
952 if (browser_window_set_scroll(bw, &rect) != NSERROR_OK) {
953 NSLOG(netsurf, WARNING,do { if (NSLOG_LEVEL_WARNING >= NSLOG_LEVEL_VERBOSE) { static
nslog_entry_context_t _nslog_ctx = { &__nslog_category_netsurf
, NSLOG_LEVEL_WARNING, "desktop/browser_window.c", sizeof("desktop/browser_window.c"
) - 1, __PRETTY_FUNCTION__, sizeof(__PRETTY_FUNCTION__) - 1, 955
, }; nslog__log(&_nslog_ctx, "Unable to set browser scroll offsets to %d by %d"
, scrollx, scrolly); } } while(0)
954 "Unable to set browser scroll offsets to %d by %d",do { if (NSLOG_LEVEL_WARNING >= NSLOG_LEVEL_VERBOSE) { static
nslog_entry_context_t _nslog_ctx = { &__nslog_category_netsurf
, NSLOG_LEVEL_WARNING, "desktop/browser_window.c", sizeof("desktop/browser_window.c"
) - 1, __PRETTY_FUNCTION__, sizeof(__PRETTY_FUNCTION__) - 1, 955
, }; nslog__log(&_nslog_ctx, "Unable to set browser scroll offsets to %d by %d"
, scrollx, scrolly); } } while(0)
955 scrollx, scrolly)do { if (NSLOG_LEVEL_WARNING >= NSLOG_LEVEL_VERBOSE) { static
nslog_entry_context_t _nslog_ctx = { &__nslog_category_netsurf
, NSLOG_LEVEL_WARNING, "desktop/browser_window.c", sizeof("desktop/browser_window.c"
) - 1, __PRETTY_FUNCTION__, sizeof(__PRETTY_FUNCTION__) - 1, 955
, }; nslog__log(&_nslog_ctx, "Unable to set browser scroll offsets to %d by %d"
, scrollx, scrolly); } } while(0)
;
956 }
957 }
958
959 if (!bw->internal_nav) {
960 browser_window_history_update(bw, bw->current_content);
961 hotlist_update_url(hlcache_handle_get_url(bw->current_content));
962 }
963
964 if (bw->refresh_interval != -1) {
965 guit->misc->schedule(bw->refresh_interval * 10,
966 browser_window_refresh, bw);
967 }
968
969 return NSERROR_OK;
970}
971
972
973/**
974 * Handle query responses from SSL requests
975 */
976static nserror
977browser_window__handle_ssl_query_response(bool_Bool proceed, void *pw)
978{
979 struct browser_window *bw = (struct browser_window *)pw;
980
981 /* If we're in the process of loading, stop the load */
982 if (bw->loading_content != NULL((void*)0)) {
983 /* We had a loading content (maybe auth page?) */
984 browser_window_stop(bw);
985 browser_window_remove_caret(bw, false0);
986 browser_window_destroy_children(bw);
987 browser_window_destroy_iframes(bw);
988 }
989
990 if (!proceed) {
991 /* We're processing a "back to safety", do a rough-and-ready
992 * nav to the old 'current' parameters, with any post data
993 * stripped away
994 */
995 return browser_window__reload_current_parameters(bw);
996 }
997
998 /* We're processing a "proceed" attempt from the form */
999 /* First, we permit the SSL */
1000 urldb_set_cert_permissions(bw->loading_parameters.url, true1);
1001
1002 /* And then we navigate to the original loading parameters */
1003 bw->internal_nav = false0;
1004
1005 return browser_window__navigate_internal(bw, &bw->loading_parameters);
1006}
1007
1008
1009/**
1010 * Unpack a "username:password" to components.
1011 *
1012 * \param[in] userpass The input string to split.
1013 * \param[in] username_out Returns username on success. Owned by caller.
1014 * \param[out] password_out Returns password on success. Owned by caller.
1015 * \return NSERROR_OK, or appropriate error code.
1016 */
1017static nserror
1018browser_window__unpack_userpass(const char *userpass,
1019 char **username_out,
1020 char **password_out)
1021{
1022 const char *tmp;
1023 char *username;
1024 char *password;
1025 size_t len;
1026
1027 if (userpass == NULL((void*)0)) {
1028 username = malloc(1);
1029 password = malloc(1);
1030 if (username == NULL((void*)0) || password == NULL((void*)0)) {
1031 free(username);
1032 free(password);
1033 return NSERROR_NOMEM;
1034 }
1035 username[0] = '\0';
1036 password[0] = '\0';
1037
1038 *username_out = username;
1039 *password_out = password;
1040 return NSERROR_OK;
1041 }
1042
1043 tmp = strchr(userpass, ':');
1044 if (tmp == NULL((void*)0)) {
1045 return NSERROR_BAD_PARAMETER;
1046 } else {
1047 size_t len2;
1048 len = tmp - userpass;
1049 len2 = strlen(++tmp);
1050
1051 username = malloc(len + 1);
1052 password = malloc(len2 + 1);
1053 if (username == NULL((void*)0) || password == NULL((void*)0)) {
1054 free(username);
1055 free(password);
1056 return NSERROR_NOMEM;
1057 }
1058 memcpy(username, userpass, len);
1059 username[len] = '\0';
1060 memcpy(password, tmp, len2 + 1);
1061 }
1062
1063 *username_out = username;
1064 *password_out = password;
1065 return NSERROR_OK;
1066}
1067
1068
1069/**
1070 * Build a "username:password" from components.
1071 *
1072 * \param[in] username The username component.
1073 * \param[in] password The password component.
1074 * \param[out] userpass_out Returns combined string on success.
1075 * Owned by caller.
1076 * \return NSERROR_OK, or appropriate error code.
1077 */
1078static nserror
1079browser_window__build_userpass(const char *username,
1080 const char *password,
1081 char **userpass_out)
1082{
1083 char *userpass;
1084 size_t len;
1085
1086 len = strlen(username) + 1 + strlen(password) + 1;
1087
1088 userpass = malloc(len);
1089 if (userpass == NULL((void*)0)) {
1090 return NSERROR_NOMEM;
1091 }
1092
1093 snprintf(userpass, len, "%s:%s", username, password);
1094
1095 *userpass_out = userpass;
1096 return NSERROR_OK;
1097}
1098
1099
1100/**
1101 * Handle a response from the UI when prompted for credentials
1102 */
1103static nserror
1104browser_window__handle_userpass_response(nsurl *url,
1105 const char *realm,
1106 const char *username,
1107 const char *password,
1108 void *pw)
1109{
1110 struct browser_window *bw = (struct browser_window *)pw;
1111 char *userpass;
1112 nserror err;
1113
1114 err = browser_window__build_userpass(username, password, &userpass);
1115 if (err != NSERROR_OK) {
1116 return err;
1117 }
1118
1119 urldb_set_auth_details(url, realm, userpass);
1120
1121 free(userpass);
1122
1123 /**
1124 * \todo QUERY - Eventually this should fill out the form *NOT* nav
1125 * to the original location
1126 */
1127 /* Finally navigate to the original loading parameters */
1128 if (bw->loading_content != NULL((void*)0)) {
1129 /* We had a loading content (maybe auth page?) */
1130 browser_window_stop(bw);
1131 browser_window_remove_caret(bw, false0);
1132 browser_window_destroy_children(bw);
1133 browser_window_destroy_iframes(bw);
1134 }
1135 bw->internal_nav = false0;
1136 return browser_window__navigate_internal(bw, &bw->loading_parameters);
1137}
1138
1139
1140/**
1141 * Handle login request (BAD_AUTH) during fetch
1142 *
1143 */
1144static nserror
1145browser_window__handle_login(struct browser_window *bw,
1146 const char *realm,
1147 nsurl *url) {
1148 char *username = NULL((void*)0), *password = NULL((void*)0);
1149 nserror err = NSERROR_OK;
1150 struct browser_fetch_parameters params;
1151
1152 memset(&params, 0, sizeof(params));
1153
1154 /* Step one, retrieve what we have */
1155 err = browser_window__unpack_userpass(
1156 urldb_get_auth_details(url, realm),
1157 &username, &password);
1158 if (err != NSERROR_OK) {
1159 goto out;
1160 }
1161
1162 /* Step two, construct our fetch parameters */
1163 params.url = nsurl_ref(corestring_nsurl_about_query_auth);
1164 params.referrer = nsurl_ref(url);
1165 params.flags = BW_NAVIGATE_HISTORY | BW_NAVIGATE_NO_TERMINAL_HISTORY_UPDATE | BW_NAVIGATE_INTERNAL;
1166
1167 err = fetch_multipart_data_new_kv(&params.post_multipart,
1168 "siteurl",
1169 nsurl_access(url));
1170 if (err != NSERROR_OK) {
1171 goto out;
1172 }
1173
1174 err = fetch_multipart_data_new_kv(&params.post_multipart,
1175 "realm",
1176 realm);
1177 if (err != NSERROR_OK) {
1178 goto out;
1179 }
1180
1181 err = fetch_multipart_data_new_kv(&params.post_multipart,
1182 "username",
1183 username);
1184 if (err != NSERROR_OK) {
1185 goto out;
1186 }
1187
1188 err = fetch_multipart_data_new_kv(&params.post_multipart,
1189 "password",
1190 password);
1191 if (err != NSERROR_OK) {
1192 goto out;
1193 }
1194
1195 /* Now we issue the fetch */
1196 bw->internal_nav = true1;
1197 err = browser_window__navigate_internal(bw, &params);
1198
1199 if (err != NSERROR_OK) {
1200 goto out;
1201 }
1202
1203 err = guit->misc->login(url, realm, username, password,
1204 browser_window__handle_userpass_response, bw);
1205
1206 if (err == NSERROR_NOT_IMPLEMENTED) {
1207 err = NSERROR_OK;
1208 }
1209 out:
1210 if (username != NULL((void*)0)) {
1211 free(username);
1212 }
1213 if (password != NULL((void*)0)) {
1214 free(password);
1215 }
1216 browser_window__free_fetch_parameters(&params);
1217 return err;
1218}
1219
1220
1221/**
1222 * Handle a certificate verification request (BAD_CERTS) during a fetch
1223 */
1224static nserror
1225browser_window__handle_bad_certs(struct browser_window *bw,
1226 nsurl *url)
1227{
1228 struct browser_fetch_parameters params;
1229 nserror err;
1230 /* Initially we don't know WHY the SSL cert was bad */
1231 const char *reason = messages_get_sslcode(SSL_CERT_ERR_UNKNOWN);
1232 size_t depth;
1233 nsurl *chainurl = NULL((void*)0);
1234
1235 memset(&params, 0, sizeof(params));
1236
1237 params.url = nsurl_ref(corestring_nsurl_about_query_ssl);
1238 params.referrer = nsurl_ref(url);
1239 params.flags = BW_NAVIGATE_HISTORY | BW_NAVIGATE_NO_TERMINAL_HISTORY_UPDATE | BW_NAVIGATE_INTERNAL;
1240
1241 err = fetch_multipart_data_new_kv(&params.post_multipart,
1242 "siteurl",
1243 nsurl_access(url));
1244 if (err != NSERROR_OK) {
1245 goto out;
1246 }
1247
1248 if (bw->loading_cert_chain != NULL((void*)0)) {
1249 for (depth = 0; depth < bw->loading_cert_chain->depth; ++depth) {
1250 size_t idx = bw->loading_cert_chain->depth - (depth + 1);
1251 ssl_cert_err err = bw->loading_cert_chain->certs[idx].err;
1252 if (err != SSL_CERT_ERR_OK) {
1253 reason = messages_get_sslcode(err);
1254 break;
1255 }
1256 }
1257
1258 err = cert_chain_to_query(bw->loading_cert_chain, &chainurl);
1259 if (err != NSERROR_OK) {
1260 goto out;
1261 }
1262
1263 err = fetch_multipart_data_new_kv(&params.post_multipart,
1264 "chainurl",
1265 nsurl_access(chainurl));
1266 if (err != NSERROR_OK) {
1267 goto out;
1268 }
1269 }
1270
1271 err = fetch_multipart_data_new_kv(&params.post_multipart,
1272 "reason",
1273 reason);
1274 if (err != NSERROR_OK) {
1275 goto out;
1276 }
1277
1278 /* Now we issue the fetch */
1279 bw->internal_nav = true1;
1280 err = browser_window__navigate_internal(bw, &params);
1281 if (err != NSERROR_OK) {
1282 goto out;
1283 }
1284
1285 out:
1286 browser_window__free_fetch_parameters(&params);
1287 if (chainurl != NULL((void*)0))
1288 nsurl_unref(chainurl);
1289 return err;
1290}
1291
1292
1293/**
1294 * Handle a timeout during a fetch
1295 */
1296static nserror
1297browser_window__handle_timeout(struct browser_window *bw, nsurl *url)
1298{
1299 struct browser_fetch_parameters params;
1300 nserror err;
1301
1302 memset(&params, 0, sizeof(params));
1303
1304 params.url = nsurl_ref(corestring_nsurl_about_query_timeout);
1305 params.referrer = nsurl_ref(url);
1306 params.flags = BW_NAVIGATE_HISTORY | BW_NAVIGATE_NO_TERMINAL_HISTORY_UPDATE | BW_NAVIGATE_INTERNAL;
1307
1308 err = fetch_multipart_data_new_kv(&params.post_multipart,
1309 "siteurl",
1310 nsurl_access(url));
1311 if (err != NSERROR_OK) {
1312 goto out;
1313 }
1314
1315 /* Now we issue the fetch */
1316 bw->internal_nav = true1;
1317 err = browser_window__navigate_internal(bw, &params);
1318 if (err != NSERROR_OK) {
1319 goto out;
1320 }
1321
1322 out:
1323 browser_window__free_fetch_parameters(&params);
1324 return err;
1325}
1326
1327
1328/**
1329 * Handle non specific errors during a fetch
1330 */
1331static nserror
1332browser_window__handle_fetcherror(struct browser_window *bw,
1333 const char *reason,
1334 nsurl *url)
1335{
1336 struct browser_fetch_parameters params;
1337 nserror err;
1338
1339 memset(&params, 0, sizeof(params));
1340
1341 params.url = nsurl_ref(corestring_nsurl_about_query_fetcherror);
1342 params.referrer = nsurl_ref(url);
1343 params.flags = BW_NAVIGATE_HISTORY | BW_NAVIGATE_NO_TERMINAL_HISTORY_UPDATE | BW_NAVIGATE_INTERNAL;
1344
1345 err = fetch_multipart_data_new_kv(&params.post_multipart,
1346 "siteurl",
1347 nsurl_access(url));
1348 if (err != NSERROR_OK) {
1349 goto out;
1350 }
1351
1352 err = fetch_multipart_data_new_kv(&params.post_multipart,
1353 "reason",
1354 reason);
1355 if (err != NSERROR_OK) {
1356 goto out;
1357 }
1358
1359 /* Now we issue the fetch */
1360 bw->internal_nav = true1;
1361 err = browser_window__navigate_internal(bw, &params);
1362 if (err != NSERROR_OK) {
1363 goto out;
1364 }
1365
1366 out:
1367 browser_window__free_fetch_parameters(&params);
1368 return err;
1369}
1370
1371
1372/**
1373 * Handle errors during content fetch
1374 */
1375static nserror
1376browser_window__handle_error(struct browser_window *bw,
1377 hlcache_handle *c,
1378 const hlcache_event *event)
1379{
1380 const char *message = event->data.errordata.errormsg;
1381 nserror code = event->data.errordata.errorcode;
1382 nserror res;
1383 nsurl *url = hlcache_handle_get_url(c);
1384
1385 /* Unexpected OK? */
1386 assert(code != NSERROR_OK)((code != NSERROR_OK) ? (void) (0) : __assert_fail ("code != NSERROR_OK"
, "desktop/browser_window.c", 1386, __extension__ __PRETTY_FUNCTION__
))
;
1387
1388 if (message == NULL((void*)0)) {
1389 message = messages_get_errorcode(code);
1390 } else {
1391 message = messages_get(message);
1392 }
1393
1394 if (c == bw->loading_content) {
1395 bw->loading_content = NULL((void*)0);
1396 } else if (c == bw->current_content) {
1397 bw->current_content = NULL((void*)0);
1398 browser_window_remove_caret(bw, false0);
1399 }
1400
1401 hlcache_handle_release(c);
1402
1403 switch (code) {
1404 case NSERROR_BAD_AUTH:
1405 res = browser_window__handle_login(bw, message, url);
1406 break;
1407
1408 case NSERROR_BAD_CERTS:
1409 res = browser_window__handle_bad_certs(bw, url);
1410 break;
1411
1412 case NSERROR_TIMEOUT:
1413 res = browser_window__handle_timeout(bw, url);
1414 break;
1415
1416 default:
1417 res = browser_window__handle_fetcherror(bw, message, url);
1418 break;
1419 }
1420
1421 return res;
1422}
1423
1424
1425/**
1426 * Update URL bar for a given browser window to given URL
1427 *
1428 * \param bw Browser window to update URL bar for.
1429 * \param url URL for content displayed by bw including any fragment.
1430 */
1431static inline nserror
1432browser_window_refresh_url_bar_internal(struct browser_window *bw, nsurl *url)
1433{
1434 assert(bw)((bw) ? (void) (0) : __assert_fail ("bw", "desktop/browser_window.c"
, 1434, __extension__ __PRETTY_FUNCTION__))
;
1435 assert(url)((url) ? (void) (0) : __assert_fail ("url", "desktop/browser_window.c"
, 1435, __extension__ __PRETTY_FUNCTION__))
;
1436
1437 if ((bw->parent != NULL((void*)0)) || (bw->window == NULL((void*)0))) {
1438 /* Not root window or no gui window so do not set a URL */
1439 return NSERROR_OK;
1440 }
1441
1442 return guit->window->set_url(bw->window, url);
1443}
1444
1445
1446/**
1447 * Browser window content event callback handler.
1448 */
1449static nserror
1450browser_window_callback(hlcache_handle *c, const hlcache_event *event, void *pw)
1451{
1452 struct browser_window *bw = pw;
1453 nserror res = NSERROR_OK;
1454
1455 switch (event->type) {
1456 case CONTENT_MSG_SSL_CERTS:
1457 /* SSL certificate information has arrived, store it */
1458 cert_chain_free(bw->loading_cert_chain);
1459 cert_chain_dup(event->data.chain, &bw->loading_cert_chain);
1460 break;
1461
1462 case CONTENT_MSG_LOG:
1463 browser_window_console_log(bw,
1464 event->data.log.src,
1465 event->data.log.msg,
1466 event->data.log.msglen,
1467 event->data.log.flags);
1468 break;
1469
1470 case CONTENT_MSG_DOWNLOAD:
1471 assert(bw->loading_content == c)((bw->loading_content == c) ? (void) (0) : __assert_fail (
"bw->loading_content == c", "desktop/browser_window.c", 1471
, __extension__ __PRETTY_FUNCTION__))
;
1472
1473 browser_window_convert_to_download(bw, event->data.download);
1474
1475 if (bw->current_content != NULL((void*)0)) {
1476 browser_window_refresh_url_bar(bw);
1477 }
1478 break;
1479
1480 case CONTENT_MSG_LOADING:
1481 assert(bw->loading_content == c)((bw->loading_content == c) ? (void) (0) : __assert_fail (
"bw->loading_content == c", "desktop/browser_window.c", 1481
, __extension__ __PRETTY_FUNCTION__))
;
1482
1483#ifdef WITH_THEME_INSTALL
1484 if (content_get_type(c) == CONTENT_THEME) {
1485 theme_install_start(c);
1486 bw->loading_content = NULL((void*)0);
1487 browser_window_stop_throbber(bw);
1488 } else
1489#endif
1490 {
1491 bw->refresh_interval = -1;
1492 browser_window_set_status(bw,
1493 content_get_status_message(c));
1494 }
1495 break;
1496
1497 case CONTENT_MSG_READY:
1498 assert(bw->loading_content == c)((bw->loading_content == c) ? (void) (0) : __assert_fail (
"bw->loading_content == c", "desktop/browser_window.c", 1498
, __extension__ __PRETTY_FUNCTION__))
;
1499
1500 res = browser_window_content_ready(bw);
1501 break;
1502
1503 case CONTENT_MSG_DONE:
1504 assert(bw->current_content == c)((bw->current_content == c) ? (void) (0) : __assert_fail (
"bw->current_content == c", "desktop/browser_window.c", 1504
, __extension__ __PRETTY_FUNCTION__))
;
1505
1506 res = browser_window_content_done(bw);
1507 break;
1508
1509 case CONTENT_MSG_ERROR:
1510 res = browser_window__handle_error(bw, c, event);
1511 break;
1512
1513 case CONTENT_MSG_REDIRECT:
1514 if (urldb_add_url(event->data.redirect.from)) {
1515 urldb_update_url_visit_data(event->data.redirect.from);
1516 }
1517 browser_window_refresh_url_bar_internal(bw, event->data.redirect.to);
1518 break;
1519
1520 case CONTENT_MSG_STATUS:
1521 if (event->data.explicit_status_text == NULL((void*)0)) {
1522 /* Object content's status text updated */
1523 const char *status = NULL((void*)0);
1524 if (bw->loading_content != NULL((void*)0)) {
1525 /* Give preference to any loading content */
1526 status = content_get_status_message(
1527 bw->loading_content);
1528 }
1529
1530 if (status == NULL((void*)0)) {
1531 status = content_get_status_message(c);
1532 }
1533
1534 if (status != NULL((void*)0)) {
1535 browser_window_set_status(bw, status);
1536 }
1537 } else {
1538 /* Object content wants to set explicit message */
1539 browser_window_set_status(bw,
1540 event->data.explicit_status_text);
1541 }
1542 break;
1543
1544 case CONTENT_MSG_REFORMAT:
1545 if (c == bw->current_content) {
1546 /* recompute frameset */
1547 browser_window_recalculate_frameset(bw);
1548
1549 /* recompute iframe positions, sizes and scrollbars */
1550 browser_window_recalculate_iframes(bw);
1551 }
1552
1553 /* Hide any caret, but don't remove it */
1554 browser_window_remove_caret(bw, true1);
1555
1556 if (!(event->data.background)) {
1557 /* Reformatted content should be redrawn */
1558 browser_window_update(bw, false0);
1559 }
1560 break;
1561
1562 case CONTENT_MSG_REDRAW:
1563 {
1564 struct rect rect = {
1565 .x0 = event->data.redraw.x,
1566 .y0 = event->data.redraw.y,
1567 .x1 = event->data.redraw.x + event->data.redraw.width,
1568 .y1 = event->data.redraw.y + event->data.redraw.height
1569 };
1570
1571 browser_window_invalidate_rect(bw, &rect);
1572 }
1573 break;
1574
1575 case CONTENT_MSG_REFRESH:
1576 bw->refresh_interval = event->data.delay * 100;
1577 break;
1578
1579 case CONTENT_MSG_LINK: /* content has an rfc5988 link element */
1580 {
1581 bool_Bool match;
1582
1583 /* Handle "icon" and "shortcut icon" */
1584 if ((lwc_string_caseless_isequal(({ lwc_error __lwc_err = lwc_error_ok; lwc_string *__lwc_str1
= (event->data.rfc5988_link->rel); lwc_string *__lwc_str2
= (corestring_lwc_icon); _Bool *__lwc_ret = (&match); if
(__lwc_str1->insensitive == ((void*)0)) { __lwc_err = lwc__intern_caseless_string
(__lwc_str1); } if (__lwc_err == lwc_error_ok && __lwc_str2
->insensitive == ((void*)0)) { __lwc_err = lwc__intern_caseless_string
(__lwc_str2); } if (__lwc_err == lwc_error_ok) *__lwc_ret = (
__lwc_str1->insensitive == __lwc_str2->insensitive); __lwc_err
; })
1585 event->data.rfc5988_link->rel,({ lwc_error __lwc_err = lwc_error_ok; lwc_string *__lwc_str1
= (event->data.rfc5988_link->rel); lwc_string *__lwc_str2
= (corestring_lwc_icon); _Bool *__lwc_ret = (&match); if
(__lwc_str1->insensitive == ((void*)0)) { __lwc_err = lwc__intern_caseless_string
(__lwc_str1); } if (__lwc_err == lwc_error_ok && __lwc_str2
->insensitive == ((void*)0)) { __lwc_err = lwc__intern_caseless_string
(__lwc_str2); } if (__lwc_err == lwc_error_ok) *__lwc_ret = (
__lwc_str1->insensitive == __lwc_str2->insensitive); __lwc_err
; })
1586 corestring_lwc_icon,({ lwc_error __lwc_err = lwc_error_ok; lwc_string *__lwc_str1
= (event->data.rfc5988_link->rel); lwc_string *__lwc_str2
= (corestring_lwc_icon); _Bool *__lwc_ret = (&match); if
(__lwc_str1->insensitive == ((void*)0)) { __lwc_err = lwc__intern_caseless_string
(__lwc_str1); } if (__lwc_err == lwc_error_ok && __lwc_str2
->insensitive == ((void*)0)) { __lwc_err = lwc__intern_caseless_string
(__lwc_str2); } if (__lwc_err == lwc_error_ok) *__lwc_ret = (
__lwc_str1->insensitive == __lwc_str2->insensitive); __lwc_err
; })
1587 &match)({ lwc_error __lwc_err = lwc_error_ok; lwc_string *__lwc_str1
= (event->data.rfc5988_link->rel); lwc_string *__lwc_str2
= (corestring_lwc_icon); _Bool *__lwc_ret = (&match); if
(__lwc_str1->insensitive == ((void*)0)) { __lwc_err = lwc__intern_caseless_string
(__lwc_str1); } if (__lwc_err == lwc_error_ok && __lwc_str2
->insensitive == ((void*)0)) { __lwc_err = lwc__intern_caseless_string
(__lwc_str2); } if (__lwc_err == lwc_error_ok) *__lwc_ret = (
__lwc_str1->insensitive == __lwc_str2->insensitive); __lwc_err
; })
== lwc_error_ok && match) ||
1588 (lwc_string_caseless_isequal(({ lwc_error __lwc_err = lwc_error_ok; lwc_string *__lwc_str1
= (event->data.rfc5988_link->rel); lwc_string *__lwc_str2
= (corestring_lwc_shortcut_icon); _Bool *__lwc_ret = (&match
); if (__lwc_str1->insensitive == ((void*)0)) { __lwc_err =
lwc__intern_caseless_string(__lwc_str1); } if (__lwc_err == lwc_error_ok
&& __lwc_str2->insensitive == ((void*)0)) { __lwc_err
= lwc__intern_caseless_string(__lwc_str2); } if (__lwc_err ==
lwc_error_ok) *__lwc_ret = (__lwc_str1->insensitive == __lwc_str2
->insensitive); __lwc_err; })
1589 event->data.rfc5988_link->rel,({ lwc_error __lwc_err = lwc_error_ok; lwc_string *__lwc_str1
= (event->data.rfc5988_link->rel); lwc_string *__lwc_str2
= (corestring_lwc_shortcut_icon); _Bool *__lwc_ret = (&match
); if (__lwc_str1->insensitive == ((void*)0)) { __lwc_err =
lwc__intern_caseless_string(__lwc_str1); } if (__lwc_err == lwc_error_ok
&& __lwc_str2->insensitive == ((void*)0)) { __lwc_err
= lwc__intern_caseless_string(__lwc_str2); } if (__lwc_err ==
lwc_error_ok) *__lwc_ret = (__lwc_str1->insensitive == __lwc_str2
->insensitive); __lwc_err; })
1590 corestring_lwc_shortcut_icon,({ lwc_error __lwc_err = lwc_error_ok; lwc_string *__lwc_str1
= (event->data.rfc5988_link->rel); lwc_string *__lwc_str2
= (corestring_lwc_shortcut_icon); _Bool *__lwc_ret = (&match
); if (__lwc_str1->insensitive == ((void*)0)) { __lwc_err =
lwc__intern_caseless_string(__lwc_str1); } if (__lwc_err == lwc_error_ok
&& __lwc_str2->insensitive == ((void*)0)) { __lwc_err
= lwc__intern_caseless_string(__lwc_str2); } if (__lwc_err ==
lwc_error_ok) *__lwc_ret = (__lwc_str1->insensitive == __lwc_str2
->insensitive); __lwc_err; })
1591 &match)({ lwc_error __lwc_err = lwc_error_ok; lwc_string *__lwc_str1
= (event->data.rfc5988_link->rel); lwc_string *__lwc_str2
= (corestring_lwc_shortcut_icon); _Bool *__lwc_ret = (&match
); if (__lwc_str1->insensitive == ((void*)0)) { __lwc_err =
lwc__intern_caseless_string(__lwc_str1); } if (__lwc_err == lwc_error_ok
&& __lwc_str2->insensitive == ((void*)0)) { __lwc_err
= lwc__intern_caseless_string(__lwc_str2); } if (__lwc_err ==
lwc_error_ok) *__lwc_ret = (__lwc_str1->insensitive == __lwc_str2
->insensitive); __lwc_err; })
== lwc_error_ok && match)) {
1592 /* it's a favicon perhaps start a fetch for it */
1593 browser_window_update_favicon(c, bw,
1594 event->data.rfc5988_link);
1595 }
1596 }
1597 break;
1598
1599 case CONTENT_MSG_GETTHREAD:
1600 {
1601 /* only the content object created by the browser
1602 * window requires a new javascript thread object
1603 */
1604 jsthread *thread;
1605 assert(bw->loading_content == c)((bw->loading_content == c) ? (void) (0) : __assert_fail (
"bw->loading_content == c", "desktop/browser_window.c", 1605
, __extension__ __PRETTY_FUNCTION__))
;
1606
1607 if (js_newthread(bw->jsheap,
1608 bw,
1609 hlcache_handle_get_content(c),
1610 &thread) == NSERROR_OK) {
1611 /* The content which is requesting the thread
1612 * is required to keep hold of it and
1613 * to destroy it when it is finished with it.
1614 */
1615 *(event->data.jsthread) = thread;
1616 }
1617 }
1618 break;
1619
1620 case CONTENT_MSG_GETDIMS:
1621 {
1622 int width;
1623 int height;
1624
1625 browser_window_get_dimensions(bw, &width, &height);
1626
1627 *(event->data.getdims.viewport_width) = width / bw->scale;
1628 *(event->data.getdims.viewport_height) = height / bw->scale;
1629 break;
1630 }
1631
1632 case CONTENT_MSG_SCROLL:
1633 {
1634 struct rect rect = {
1635 .x0 = event->data.scroll.x0,
1636 .y0 = event->data.scroll.y0,
1637 };
1638
1639 /* Content wants to be scrolled */
1640 if (bw->current_content != c) {
1641 break;
1642 }
1643
1644 if (event->data.scroll.area) {
1645 rect.x1 = event->data.scroll.x1;
1646 rect.y1 = event->data.scroll.y1;
1647 } else {
1648 rect.x1 = event->data.scroll.x0;
1649 rect.y1 = event->data.scroll.y0;
1650 }
1651 browser_window_set_scroll(bw, &rect);
1652
1653 break;
1654 }
1655
1656 case CONTENT_MSG_DRAGSAVE:
1657 {
1658 /* Content wants drag save of a content */
1659 struct browser_window *root = browser_window_get_root(bw);
1660 hlcache_handle *save = event->data.dragsave.content;
1661
1662 if (save == NULL((void*)0)) {
1663 save = c;
1664 }
1665
1666 switch(event->data.dragsave.type) {
1667 case CONTENT_SAVE_ORIG:
1668 guit->window->drag_save_object(root->window,
1669 save,
1670 GUI_SAVE_OBJECT_ORIG);
1671 break;
1672
1673 case CONTENT_SAVE_NATIVE:
1674 guit->window->drag_save_object(root->window,
1675 save,
1676 GUI_SAVE_OBJECT_NATIVE);
1677 break;
1678
1679 case CONTENT_SAVE_COMPLETE:
1680 guit->window->drag_save_object(root->window,
1681 save,
1682 GUI_SAVE_COMPLETE);
1683 break;
1684
1685 case CONTENT_SAVE_SOURCE:
1686 guit->window->drag_save_object(root->window,
1687 save,
1688 GUI_SAVE_SOURCE);
1689 break;
1690 }
1691 }
1692 break;
1693
1694 case CONTENT_MSG_SAVELINK:
1695 {
1696 /* Content wants a link to be saved */
1697 struct browser_window *root = browser_window_get_root(bw);
1698 guit->window->save_link(root->window,
1699 event->data.savelink.url,
1700 event->data.savelink.title);
1701 }
1702 break;
1703
1704 case CONTENT_MSG_POINTER:
1705 /* Content wants to have specific mouse pointer */
1706 browser_window_set_pointer(bw, event->data.pointer);
1707 break;
1708
1709 case CONTENT_MSG_DRAG:
1710 {
1711 browser_drag_type bdt = DRAGGING_NONE;
1712
1713 switch (event->data.drag.type) {
1714 case CONTENT_DRAG_NONE:
1715 bdt = DRAGGING_NONE;
1716 break;
1717 case CONTENT_DRAG_SCROLL:
1718 bdt = DRAGGING_CONTENT_SCROLLBAR;
1719 break;
1720 case CONTENT_DRAG_SELECTION:
1721 bdt = DRAGGING_SELECTION;
1722 break;
1723 }
1724 browser_window_set_drag_type(bw, bdt, event->data.drag.rect);
1725 }
1726 break;
1727
1728 case CONTENT_MSG_CARET:
1729 switch (event->data.caret.type) {
1730 case CONTENT_CARET_REMOVE:
1731 browser_window_remove_caret(bw, false0);
1732 break;
1733 case CONTENT_CARET_HIDE:
1734 browser_window_remove_caret(bw, true1);
1735 break;
1736 case CONTENT_CARET_SET_POS:
1737 browser_window_place_caret(bw,
1738 event->data.caret.pos.x,
1739 event->data.caret.pos.y,
1740 event->data.caret.pos.height,
1741 event->data.caret.pos.clip);
1742 break;
1743 }
1744 break;
1745
1746 case CONTENT_MSG_SELECTION:
1747 browser_window_set_selection(bw,
1748 event->data.selection.selection,
1749 event->data.selection.read_only);
1750 break;
1751
1752 case CONTENT_MSG_SELECTMENU:
1753 if (event->data.select_menu.gadget->type == GADGET_SELECT) {
1754 struct browser_window *root =
1755 browser_window_get_root(bw);
1756 guit->window->create_form_select_menu(root->window,
1757 event->data.select_menu.gadget);
1758 }
1759
1760 break;
1761
1762 case CONTENT_MSG_GADGETCLICK:
1763 if (event->data.gadget_click.gadget->type == GADGET_FILE) {
1764 struct browser_window *root =
1765 browser_window_get_root(bw);
1766 guit->window->file_gadget_open(root->window, c,
1767 event->data.gadget_click.gadget);
1768 }
1769
1770 break;
1771
1772
1773 case CONTENT_MSG_TEXTSEARCH:
1774 switch (event->data.textsearch.type) {
1775 case CONTENT_TEXTSEARCH_FIND:
1776 guit->search->hourglass(event->data.textsearch.state,
1777 event->data.textsearch.ctx);
1778 break;
1779
1780 case CONTENT_TEXTSEARCH_MATCH:
1781 guit->search->status(event->data.textsearch.state,
1782 event->data.textsearch.ctx);
1783 break;
1784
1785 case CONTENT_TEXTSEARCH_BACK:
1786 guit->search->back_state(event->data.textsearch.state,
1787 event->data.textsearch.ctx);
1788 break;
1789
1790 case CONTENT_TEXTSEARCH_FORWARD:
1791 guit->search->forward_state(event->data.textsearch.state,
1792 event->data.textsearch.ctx);
1793 break;
1794
1795 case CONTENT_TEXTSEARCH_RECENT:
1796 guit->search->add_recent(event->data.textsearch.string,
1797 event->data.textsearch.ctx);
1798
1799 break;
1800 }
1801 break;
1802
1803 default:
1804 break;
1805 }
1806
1807 return res;
1808}
1809
1810
1811/**
1812 * internal scheduled reformat callback.
1813 *
1814 * scheduled reformat callback to allow reformats from unthreaded context.
1815 *
1816 * \param vbw The browser window to be reformatted
1817 */
1818static void scheduled_reformat(void *vbw)
1819{
1820 struct browser_window *bw = vbw;
1821 int width;
1822 int height;
1823 nserror res;
1824
1825 res = guit->window->get_dimensions(bw->window, &width, &height);
1826 if (res == NSERROR_OK) {
1827 browser_window_reformat(bw, false0, width, height);
1828 }
1829}
1830
1831/* exported interface documented in desktop/browser_private.h */
1832nserror browser_window_destroy_internal(struct browser_window *bw)
1833{
1834 assert(bw)((bw) ? (void) (0) : __assert_fail ("bw", "desktop/browser_window.c"
, 1834, __extension__ __PRETTY_FUNCTION__))
;
1835
1836 browser_window_destroy_children(bw);
1837 browser_window_destroy_iframes(bw);
1838
1839 /* Destroy scrollbars */
1840 if (bw->scroll_x != NULL((void*)0)) {
1841 scrollbar_destroy(bw->scroll_x);
1842 }
1843
1844 if (bw->scroll_y != NULL((void*)0)) {
1845 scrollbar_destroy(bw->scroll_y);
1846 }
1847
1848 /* clear any pending callbacks */
1849 guit->misc->schedule(-1, browser_window_refresh, bw);
1850 NSLOG(netsurf, INFO,do { if (NSLOG_LEVEL_INFO >= NSLOG_LEVEL_VERBOSE) { static
nslog_entry_context_t _nslog_ctx = { &__nslog_category_netsurf
, NSLOG_LEVEL_INFO, "desktop/browser_window.c", sizeof("desktop/browser_window.c"
) - 1, __PRETTY_FUNCTION__, sizeof(__PRETTY_FUNCTION__) - 1, 1851
, }; nslog__log(&_nslog_ctx, "Clearing reformat schedule for browser window %p"
, bw); } } while(0)
1851 "Clearing reformat schedule for browser window %p", bw)do { if (NSLOG_LEVEL_INFO >= NSLOG_LEVEL_VERBOSE) { static
nslog_entry_context_t _nslog_ctx = { &__nslog_category_netsurf
, NSLOG_LEVEL_INFO, "desktop/browser_window.c", sizeof("desktop/browser_window.c"
) - 1, __PRETTY_FUNCTION__, sizeof(__PRETTY_FUNCTION__) - 1, 1851
, }; nslog__log(&_nslog_ctx, "Clearing reformat schedule for browser window %p"
, bw); } } while(0)
;
1852 guit->misc->schedule(-1, scheduled_reformat, bw);
1853
1854 /* If this brower window is not the root window, and has focus, unset
1855 * the root browser window's focus pointer. */
1856 if (!bw->window) {
1857 struct browser_window *top = browser_window_get_root(bw);
1858
1859 if (top->focus == bw)
1860 top->focus = top;
1861
1862 if (top->selection.bw == bw) {
1863 browser_window_set_selection(top, false0, false0);
1864 }
1865 }
1866
1867 /* Destruction order is important: we must ensure that the frontend
1868 * destroys any window(s) associated with this browser window before
1869 * we attempt any destructive cleanup.
1870 */
1871
1872 if (bw->window) {
1873 /* Only the root window has a GUI window */
1874 guit->window->destroy(bw->window);
1875 }
1876
1877 if (bw->loading_content != NULL((void*)0)) {
1878 hlcache_handle_abort(bw->loading_content);
1879 hlcache_handle_release(bw->loading_content);
1880 bw->loading_content = NULL((void*)0);
1881 }
1882
1883 if (bw->current_content != NULL((void*)0)) {
1884 content_close(bw->current_content);
1885 hlcache_handle_release(bw->current_content);
1886 bw->current_content = NULL((void*)0);
1887 }
1888
1889 if (bw->favicon.loading != NULL((void*)0)) {
1890 hlcache_handle_abort(bw->favicon.loading);
1891 hlcache_handle_release(bw->favicon.loading);
1892 bw->favicon.loading = NULL((void*)0);
1893 }
1894
1895 if (bw->favicon.current != NULL((void*)0)) {
1896 content_close(bw->favicon.current);
1897 hlcache_handle_release(bw->favicon.current);
1898 bw->favicon.current = NULL((void*)0);
1899 }
1900
1901 if (bw->jsheap != NULL((void*)0)) {
1902 js_destroyheap(bw->jsheap);
1903 bw->jsheap = NULL((void*)0);
1904 }
1905
1906 /* These simply free memory, so are safe here */
1907
1908 if (bw->frag_id != NULL((void*)0)) {
1909 lwc_string_unref(bw->frag_id){ lwc_string *__lwc_s = (bw->frag_id); ((__lwc_s != ((void
*)0)) ? (void) (0) : __assert_fail ("__lwc_s != NULL", "desktop/browser_window.c"
, 1909, __extension__ __PRETTY_FUNCTION__)); __lwc_s->refcnt
--; if ((__lwc_s->refcnt == 0) || ((__lwc_s->refcnt == 1
) && (__lwc_s->insensitive == __lwc_s))) lwc_string_destroy
(__lwc_s); }
;
1910 }
1911
1912 browser_window_history_destroy(bw);
1913
1914 cert_chain_free(bw->current_cert_chain);
1915 cert_chain_free(bw->loading_cert_chain);
1916 bw->current_cert_chain = NULL((void*)0);
1917 bw->loading_cert_chain = NULL((void*)0);
1918
1919 free(bw->name);
1920 free(bw->status.text);
1921 bw->status.text = NULL((void*)0);
1922 browser_window__free_fetch_parameters(&bw->current_parameters);
1923 browser_window__free_fetch_parameters(&bw->loading_parameters);
1924 NSLOG(netsurf, INFO, "Status text cache match:miss %d:%d",do { if (NSLOG_LEVEL_INFO >= NSLOG_LEVEL_VERBOSE) { static
nslog_entry_context_t _nslog_ctx = { &__nslog_category_netsurf
, NSLOG_LEVEL_INFO, "desktop/browser_window.c", sizeof("desktop/browser_window.c"
) - 1, __PRETTY_FUNCTION__, sizeof(__PRETTY_FUNCTION__) - 1, 1925
, }; nslog__log(&_nslog_ctx, "Status text cache match:miss %d:%d"
, bw->status.match, bw->status.miss); } } while(0)
1925 bw->status.match, bw->status.miss)do { if (NSLOG_LEVEL_INFO >= NSLOG_LEVEL_VERBOSE) { static
nslog_entry_context_t _nslog_ctx = { &__nslog_category_netsurf
, NSLOG_LEVEL_INFO, "desktop/browser_window.c", sizeof("desktop/browser_window.c"
) - 1, __PRETTY_FUNCTION__, sizeof(__PRETTY_FUNCTION__) - 1, 1925
, }; nslog__log(&_nslog_ctx, "Status text cache match:miss %d:%d"
, bw->status.match, bw->status.miss); } } while(0)
;
1926
1927 return NSERROR_OK;
1928}
1929
1930
1931/**
1932 * Set browser window scale.
1933 *
1934 * \param bw Browser window.
1935 * \param absolute scale value.
1936 * \return NSERROR_OK on success else error code
1937 */
1938static nserror
1939browser_window_set_scale_internal(struct browser_window *bw, float scale)
1940{
1941 int i;
1942 nserror res = NSERROR_OK;
1943
1944 /* do not apply tiny changes in scale */
1945 if (fabs(bw->scale - scale) < 0.0001)
1946 return res;
1947
1948 bw->scale = scale;
1949
1950 if (bw->current_content != NULL((void*)0)) {
1951 if (content_can_reformat(bw->current_content) == false0) {
1952 browser_window_update(bw, false0);
1953 } else {
1954 res = browser_window_schedule_reformat(bw);
1955 }
1956 }
1957
1958 /* scale frames */
1959 for (i = 0; i < (bw->cols * bw->rows); i++) {
1960 res = browser_window_set_scale_internal(&bw->children[i], scale);
1961 }
1962
1963 /* scale iframes */
1964 for (i = 0; i < bw->iframe_count; i++) {
1965 res = browser_window_set_scale_internal(&bw->iframes[i], scale);
1966 }
1967
1968 return res;
1969}
1970
1971
1972/**
1973 * Find browser window.
1974 *
1975 * \param bw Browser window.
1976 * \param target Name of target.
1977 * \param depth Depth to scan.
1978 * \param page The browser window page.
1979 * \param rdepth The rdepth.
1980 * \param bw_target the output browser window.
1981 */
1982static void
1983browser_window_find_target_internal(struct browser_window *bw,
1984 const char *target,
1985 int depth,
1986 struct browser_window *page,
1987 int *rdepth,
1988 struct browser_window **bw_target)
1989{
1990 int i;
1991
1992 if ((bw->name) && (!strcasecmp(bw->name, target))) {
1993 if ((bw == page) || (depth > *rdepth)) {
1994 *rdepth = depth;
1995 *bw_target = bw;
1996 }
1997 }
1998
1999 if ((!bw->children) && (!bw->iframes))
2000 return;
2001
2002 depth++;
2003
2004 if (bw->children != NULL((void*)0)) {
2005 for (i = 0; i < (bw->cols * bw->rows); i++) {
2006 if ((bw->children[i].name) &&
2007 (!strcasecmp(bw->children[i].name,
2008 target))) {
2009 if ((page == &bw->children[i]) ||
2010 (depth > *rdepth)) {
2011 *rdepth = depth;
2012 *bw_target = &bw->children[i];
2013 }
2014 }
2015 if (bw->children[i].children)
2016 browser_window_find_target_internal(
2017 &bw->children[i],
2018 target, depth, page,
2019 rdepth, bw_target);
2020 }
2021 }
2022
2023 if (bw->iframes != NULL((void*)0)) {
2024 for (i = 0; i < bw->iframe_count; i++) {
2025 browser_window_find_target_internal(&bw->iframes[i],
2026 target,
2027 depth,
2028 page,
2029 rdepth,
2030 bw_target);
2031 }
2032 }
2033}
2034
2035
2036/**
2037 * Handles the end of a drag operation in a browser window.
2038 *
2039 * \param bw browser window
2040 * \param mouse state of mouse buttons and modifier keys
2041 * \param x coordinate of mouse
2042 * \param y coordinate of mouse
2043 *
2044 * \todo Remove this function, once these things are associated with content,
2045 * rather than bw.
2046 */
2047static void
2048browser_window_mouse_drag_end(struct browser_window *bw,
2049 browser_mouse_state mouse,
2050 int x, int y)
2051{
2052 int scr_x, scr_y;
2053
2054 switch (bw->drag.type) {
2055 case DRAGGING_SELECTION:
2056 case DRAGGING_OTHER:
2057 case DRAGGING_CONTENT_SCROLLBAR:
2058 /* Drag handled by content handler */
2059 break;
2060
2061 case DRAGGING_SCR_X:
2062
2063 browser_window_get_scrollbar_pos(bw, true1, &scr_x, &scr_y);
2064
2065 scr_x = x - scr_x - scrollbar_get_offset(bw->scroll_x);
2066 scr_y = y - scr_y - scrollbar_get_offset(bw->scroll_y);
2067
2068 scrollbar_mouse_drag_end(bw->scroll_x, mouse, scr_x, scr_y);
2069
2070 bw->drag.type = DRAGGING_NONE;
2071 break;
2072
2073 case DRAGGING_SCR_Y:
2074
2075 browser_window_get_scrollbar_pos(bw, false0, &scr_x, &scr_y);
2076
2077 scr_x = x - scr_x - scrollbar_get_offset(bw->scroll_x);
2078 scr_y = y - scr_y - scrollbar_get_offset(bw->scroll_y);
2079
2080 scrollbar_mouse_drag_end(bw->scroll_y, mouse, scr_x, scr_y);
2081
2082 bw->drag.type = DRAGGING_NONE;
2083 break;
2084
2085 default:
2086 browser_window_set_drag_type(bw, DRAGGING_NONE, NULL((void*)0));
2087 break;
2088 }
2089}
2090
2091/**
2092 * Process mouse click event
2093 *
2094 * \param bw The browsing context receiving the event
2095 * \param mouse The mouse event state
2096 * \param x The scaled x co-ordinate of the event
2097 * \param y The scaled y co-ordinate of the event
2098 */
2099static void
2100browser_window_mouse_click_internal(struct browser_window *bw,
2101 browser_mouse_state mouse,
2102 int x, int y)
2103{
2104 hlcache_handle *c = bw->current_content;
2105 const char *status = NULL((void*)0);
2106 browser_pointer_shape pointer = BROWSER_POINTER_DEFAULT;
2107
2108 if (bw->children) {
2109 /* Browser window has children (frames) */
2110 struct browser_window *child;
2111 int cur_child;
2112 int children = bw->rows * bw->cols;
2113
2114 for (cur_child = 0; cur_child < children; cur_child++) {
2115
2116 child = &bw->children[cur_child];
2117
2118 if ((x < child->x) ||
2119 (y < child->y) ||
2120 (child->x + child->width < x) ||
2121 (child->y + child->height < y)) {
2122 /* Click not in this child */
2123 continue;
2124 }
2125
2126 /* It's this child that contains the click; pass it
2127 * on to child. */
2128 browser_window_mouse_click_internal(
2129 child,
2130 mouse,
2131 x - child->x + scrollbar_get_offset(child->scroll_x),
2132 y - child->y + scrollbar_get_offset(child->scroll_y));
2133
2134 /* Mouse action was for this child, we're done */
2135 return;
2136 }
2137
2138 return;
2139 }
2140
2141 if (!c)
2142 return;
2143
2144 if (bw->scroll_x != NULL((void*)0)) {
2145 int scr_x, scr_y;
2146 browser_window_get_scrollbar_pos(bw, true1, &scr_x, &scr_y);
2147 scr_x = x - scr_x - scrollbar_get_offset(bw->scroll_x);
2148 scr_y = y - scr_y - scrollbar_get_offset(bw->scroll_y);
2149
2150 if (scr_x > 0 && scr_x < get_horz_scrollbar_len(bw) &&
2151 scr_y > 0 && scr_y < SCROLLBAR_WIDTH16) {
2152 status = scrollbar_mouse_status_to_message(
2153 scrollbar_mouse_action(
2154 bw->scroll_x, mouse,
2155 scr_x, scr_y));
2156 pointer = BROWSER_POINTER_DEFAULT;
2157
2158 if (status != NULL((void*)0))
2159 browser_window_set_status(bw, status);
2160
2161 browser_window_set_pointer(bw, pointer);
2162 return;
2163 }
2164 }
2165
2166 if (bw->scroll_y != NULL((void*)0)) {
2167 int scr_x, scr_y;
2168 browser_window_get_scrollbar_pos(bw, false0, &scr_x, &scr_y);
2169 scr_x = x - scr_x - scrollbar_get_offset(bw->scroll_x);
2170 scr_y = y - scr_y - scrollbar_get_offset(bw->scroll_y);
2171
2172 if (scr_y > 0 && scr_y < get_vert_scrollbar_len(bw) &&
2173 scr_x > 0 && scr_x < SCROLLBAR_WIDTH16) {
2174 status = scrollbar_mouse_status_to_message(
2175 scrollbar_mouse_action(
2176 bw->scroll_y,
2177 mouse,
2178 scr_x,
2179 scr_y));
2180 pointer = BROWSER_POINTER_DEFAULT;
2181
2182 if (status != NULL((void*)0)) {
2183 browser_window_set_status(bw, status);
2184 }
2185
2186 browser_window_set_pointer(bw, pointer);
2187 return;
2188 }
2189 }
2190
2191 switch (content_get_type(c)) {
2192 case CONTENT_HTML:
2193 case CONTENT_TEXTPLAIN:
2194 {
2195 /* Give bw focus */
2196 struct browser_window *root_bw = browser_window_get_root(bw);
2197 if (bw != root_bw->focus) {
2198 browser_window_remove_caret(bw, false0);
2199 browser_window_set_selection(bw, false0, true1);
2200 root_bw->focus = bw;
2201 }
2202
2203 /* Pass mouse action to content */
2204 content_mouse_action(c, bw, mouse, x, y);
2205 }
2206 break;
2207 default:
2208 if (mouse & BROWSER_MOUSE_MOD_2) {
2209 if (mouse & BROWSER_MOUSE_DRAG_2) {
2210 guit->window->drag_save_object(bw->window, c,
2211 GUI_SAVE_OBJECT_NATIVE);
2212 } else if (mouse & BROWSER_MOUSE_DRAG_1) {
2213 guit->window->drag_save_object(bw->window, c,
2214 GUI_SAVE_OBJECT_ORIG);
2215 }
2216 } else if (mouse & (BROWSER_MOUSE_DRAG_1 |
2217 BROWSER_MOUSE_DRAG_2)) {
2218 browser_window_page_drag_start(bw, x, y);
2219 browser_window_set_pointer(bw, BROWSER_POINTER_MOVE);
2220 }
2221 break;
2222 }
2223}
2224
2225
2226/**
2227 * Process mouse movement event
2228 *
2229 * \param bw The browsing context receiving the event
2230 * \param mouse The mouse event state
2231 * \param x The scaled x co-ordinate of the event
2232 * \param y The scaled y co-ordinate of the event
2233 */
2234static void
2235browser_window_mouse_track_internal(struct browser_window *bw,
2236 browser_mouse_state mouse,
2237 int x, int y)
2238{
2239 hlcache_handle *c = bw->current_content;
2240 const char *status = NULL((void*)0);
2241 browser_pointer_shape pointer = BROWSER_POINTER_DEFAULT;
2242
2243 if (bw->window != NULL((void*)0) && bw->drag.window && bw != bw->drag.window) {
2244 /* This is the root browser window and there's an active drag
2245 * in a sub window.
2246 * Pass the mouse action straight on to that bw. */
2247 struct browser_window *drag_bw = bw->drag.window;
2248 int off_x = 0;
2249 int off_y = 0;
2250
2251 browser_window_get_position(drag_bw, true1, &off_x, &off_y);
2252
2253 if (drag_bw->browser_window_type == BROWSER_WINDOW_FRAME) {
2254 browser_window_mouse_track_internal(drag_bw,
2255 mouse,
2256 x - off_x,
2257 y - off_y);
2258
2259 } else if (drag_bw->browser_window_type == BROWSER_WINDOW_IFRAME) {
2260 browser_window_mouse_track_internal(drag_bw, mouse,
2261 x - off_x / bw->scale,
2262 y - off_y / bw->scale);
2263 }
2264 return;
2265 }
2266
2267 if (bw->children) {
2268 /* Browser window has children (frames) */
2269 struct browser_window *child;
2270 int cur_child;
2271 int children = bw->rows * bw->cols;
2272
2273 for (cur_child = 0; cur_child < children; cur_child++) {
2274
2275 child = &bw->children[cur_child];
2276
2277 if ((x < child->x) ||
2278 (y < child->y) ||
2279 (child->x + child->width < x) ||
2280 (child->y + child->height < y)) {
2281 /* Click not in this child */
2282 continue;
2283 }
2284
2285 /* It's this child that contains the mouse; pass
2286 * mouse action on to child */
2287 browser_window_mouse_track_internal(
2288 child,
2289 mouse,
2290 x - child->x + scrollbar_get_offset(child->scroll_x),
2291 y - child->y + scrollbar_get_offset(child->scroll_y));
2292
2293 /* Mouse action was for this child, we're done */
2294 return;
2295 }
2296
2297 /* Odd if we reached here, but nothing else can use the click
2298 * when there are children. */
2299 return;
2300 }
2301
2302 if (c == NULL((void*)0) && bw->drag.type != DRAGGING_FRAME) {
2303 return;
2304 }
2305
2306 if (bw->drag.type != DRAGGING_NONE && !mouse) {
2307 browser_window_mouse_drag_end(bw, mouse, x, y);
2308 }
2309
2310 /* Browser window's horizontal scrollbar */
2311 if (bw->scroll_x != NULL((void*)0) && bw->drag.type != DRAGGING_SCR_Y) {
2312 int scr_x, scr_y;
2313 browser_window_get_scrollbar_pos(bw, true1, &scr_x, &scr_y);
2314 scr_x = x - scr_x - scrollbar_get_offset(bw->scroll_x);
2315 scr_y = y - scr_y - scrollbar_get_offset(bw->scroll_y);
2316
2317 if ((bw->drag.type == DRAGGING_SCR_X) ||
2318 (scr_x > 0 &&
2319 scr_x < get_horz_scrollbar_len(bw) &&
2320 scr_y > 0 &&
2321 scr_y < SCROLLBAR_WIDTH16 &&
2322 bw->drag.type == DRAGGING_NONE)) {
2323 /* Start a scrollbar drag, or continue existing drag */
2324 status = scrollbar_mouse_status_to_message(
2325 scrollbar_mouse_action(bw->scroll_x,
2326 mouse,
2327 scr_x,
2328 scr_y));
2329 pointer = BROWSER_POINTER_DEFAULT;
2330
2331 if (status != NULL((void*)0)) {
2332 browser_window_set_status(bw, status);
2333 }
2334
2335 browser_window_set_pointer(bw, pointer);
2336 return;
2337 }
2338 }
2339
2340 /* Browser window's vertical scrollbar */
2341 if (bw->scroll_y != NULL((void*)0)) {
2342 int scr_x, scr_y;
2343 browser_window_get_scrollbar_pos(bw, false0, &scr_x, &scr_y);
2344 scr_x = x - scr_x - scrollbar_get_offset(bw->scroll_x);
2345 scr_y = y - scr_y - scrollbar_get_offset(bw->scroll_y);
2346
2347 if ((bw->drag.type == DRAGGING_SCR_Y) ||
2348 (scr_y > 0 &&
2349 scr_y < get_vert_scrollbar_len(bw) &&
2350 scr_x > 0 &&
2351 scr_x < SCROLLBAR_WIDTH16 &&
2352 bw->drag.type == DRAGGING_NONE)) {
2353 /* Start a scrollbar drag, or continue existing drag */
2354 status = scrollbar_mouse_status_to_message(
2355 scrollbar_mouse_action(bw->scroll_y,
2356 mouse,
2357 scr_x,
2358 scr_y));
2359 pointer = BROWSER_POINTER_DEFAULT;
2360
2361 if (status != NULL((void*)0)) {
2362 browser_window_set_status(bw, status);
2363 }
2364
2365 browser_window_set_pointer(bw, pointer);
2366 return;
2367 }
2368 }
2369
2370 if (bw->drag.type == DRAGGING_FRAME) {
2371 browser_window_resize_frame(bw, bw->x + x, bw->y + y);
2372 } else if (bw->drag.type == DRAGGING_PAGE_SCROLL) {
2373 /* mouse movement since drag started */
2374 struct rect rect;
2375
2376 rect.x0 = bw->drag.start_x - x;
2377 rect.y0 = bw->drag.start_y - y;
2378
2379 /* new scroll offsets */
2380 rect.x0 += bw->drag.start_scroll_x;
2381 rect.y0 += bw->drag.start_scroll_y;
2382
2383 bw->drag.start_scroll_x = rect.x1 = rect.x0;
2384 bw->drag.start_scroll_y = rect.y1 = rect.y0;
2385
2386 browser_window_set_scroll(bw, &rect);
2387 } else {
2388 assert(c != NULL)((c != ((void*)0)) ? (void) (0) : __assert_fail ("c != NULL",
"desktop/browser_window.c", 2388, __extension__ __PRETTY_FUNCTION__
))
;
2389 content_mouse_track(c, bw, mouse, x, y);
2390 }
2391}
2392
2393
2394/**
2395 * perform a scroll operation at a given coordinate
2396 *
2397 * \param bw The browsing context receiving the event
2398 * \param x The scaled x co-ordinate of the event
2399 * \param y The scaled y co-ordinate of the event
2400 */
2401static bool_Bool
2402browser_window_scroll_at_point_internal(struct browser_window *bw,
2403 int x, int y,
2404 int scrx, int scry)
2405{
2406 assert(bw != NULL)((bw != ((void*)0)) ? (void) (0) : __assert_fail ("bw != NULL"
, "desktop/browser_window.c", 2406, __extension__ __PRETTY_FUNCTION__
))
;
2407
2408 /* Handle (i)frame scroll offset (core-managed browser windows only) */
2409 x += scrollbar_get_offset(bw->scroll_x);
2410 y += scrollbar_get_offset(bw->scroll_y);
2411
2412 if (bw->children) {
2413 /* Browser window has children, so pass request on to
2414 * appropriate child */
2415 struct browser_window *bwc;
2416 int cur_child;
2417 int children = bw->rows * bw->cols;
2418
2419 /* Loop through all children of bw */
2420 for (cur_child = 0; cur_child < children; cur_child++) {
2421 /* Set current child */
2422 bwc = &bw->children[cur_child];
2423
2424 /* Skip this frame if (x, y) coord lies outside */
2425 if (x < bwc->x || bwc->x + bwc->width < x ||
2426 y < bwc->y || bwc->y + bwc->height < y)
2427 continue;
2428
2429 /* Pass request into this child */
2430 return browser_window_scroll_at_point_internal(
2431 bwc,
2432 (x - bwc->x),
2433 (y - bwc->y),
2434 scrx, scry);
2435 }
2436 }
2437
2438 /* Try to scroll any current content */
2439 if (bw->current_content != NULL((void*)0) &&
2440 content_scroll_at_point(bw->current_content, x, y, scrx, scry) == true1) {
2441 /* Scroll handled by current content */
2442 return true1;
2443 }
2444
2445 /* Try to scroll this window. */
2446 return (int)scrollbar_scroll(bw->scroll_y, scry) |
2447 (int)scrollbar_scroll(bw->scroll_x, scrx);
2448}
2449
2450
2451/**
2452 * allows a dragged file to be dropped into a browser window at a position
2453 *
2454 * \param bw The browsing context receiving the event
2455 * \param x The scaled x co-ordinate of the event
2456 * \param y The scaled y co-ordinate of the event
2457 * \param file filename to be put in the widget
2458 */
2459static bool_Bool
2460browser_window_drop_file_at_point_internal(struct browser_window *bw,
2461 int x, int y,
2462 char *file)
2463{
2464 assert(bw != NULL)((bw != ((void*)0)) ? (void) (0) : __assert_fail ("bw != NULL"
, "desktop/browser_window.c", 2464, __extension__ __PRETTY_FUNCTION__
))
;
2465
2466 /* Handle (i)frame scroll offset (core-managed browser windows only) */
2467 x += scrollbar_get_offset(bw->scroll_x);
2468 y += scrollbar_get_offset(bw->scroll_y);
2469
2470 if (bw->children) {
2471 /* Browser window has children, so pass request on to
2472 * appropriate child */
2473 struct browser_window *bwc;
2474 int cur_child;
2475 int children = bw->rows * bw->cols;
2476
2477 /* Loop through all children of bw */
2478 for (cur_child = 0; cur_child < children; cur_child++) {
2479 /* Set current child */
2480 bwc = &bw->children[cur_child];
2481
2482 /* Skip this frame if (x, y) coord lies outside */
2483 if (x < bwc->x || bwc->x + bwc->width < x ||
2484 y < bwc->y || bwc->y + bwc->height < y)
2485 continue;
2486
2487 /* Pass request into this child */
2488 return browser_window_drop_file_at_point_internal(
2489 bwc,
2490 (x - bwc->x),
2491 (y - bwc->y),
2492 file);
2493 }
2494 }
2495
2496 /* Pass file drop on to any content */
2497 if (bw->current_content != NULL((void*)0)) {
2498 return content_drop_file_at_point(bw->current_content,
2499 x, y, file);
2500 }
2501
2502 return false0;
2503}
2504
2505
2506/**
2507 * Check if this is an internal navigation URL.
2508 *
2509 * This safely checks if the given url is an internal navigation even
2510 * for urls with no scheme or path.
2511 *
2512 * \param url The URL to check
2513 * \return true if an internal navigation url else false
2514 */
2515static bool_Bool
2516is_internal_navigate_url(nsurl *url)
2517{
2518 bool_Bool is_internal = false0;
2519 lwc_string *scheme, *path;
2520
2521 scheme = nsurl_get_component(url, NSURL_SCHEME);
2522 if (scheme != NULL((void*)0)) {
2523 path = nsurl_get_component(url, NSURL_PATH);
2524 if (path != NULL((void*)0)) {
2525 if (scheme == corestring_lwc_about) {
2526 if (path == corestring_lwc_query_auth) {
2527 is_internal = true1;
2528 } else if (path == corestring_lwc_query_ssl) {
2529 is_internal = true1;
2530 } else if (path == corestring_lwc_query_timeout) {
2531 is_internal = true1;
2532 } else if (path == corestring_lwc_query_fetcherror) {
2533 is_internal = true1;
2534 }
2535 }
2536 lwc_string_unref(path){ lwc_string *__lwc_s = (path); ((__lwc_s != ((void*)0)) ? (void
) (0) : __assert_fail ("__lwc_s != NULL", "desktop/browser_window.c"
, 2536, __extension__ __PRETTY_FUNCTION__)); __lwc_s->refcnt
--; if ((__lwc_s->refcnt == 0) || ((__lwc_s->refcnt == 1
) && (__lwc_s->insensitive == __lwc_s))) lwc_string_destroy
(__lwc_s); }
;
2537 }
2538 lwc_string_unref(scheme){ lwc_string *__lwc_s = (scheme); ((__lwc_s != ((void*)0)) ? (
void) (0) : __assert_fail ("__lwc_s != NULL", "desktop/browser_window.c"
, 2538, __extension__ __PRETTY_FUNCTION__)); __lwc_s->refcnt
--; if ((__lwc_s->refcnt == 0) || ((__lwc_s->refcnt == 1
) && (__lwc_s->insensitive == __lwc_s))) lwc_string_destroy
(__lwc_s); }
;
2539 }
2540 return is_internal;
2541}
2542
2543
2544/* exported interface, documented in netsurf/browser_window.h */
2545nserror
2546browser_window_get_name(struct browser_window *bw, const char **out_name)
2547{
2548 assert(bw != NULL)((bw != ((void*)0)) ? (void) (0) : __assert_fail ("bw != NULL"
, "desktop/browser_window.c", 2548, __extension__ __PRETTY_FUNCTION__
))
;
2549
2550 *out_name = bw->name;
2551
2552 return NSERROR_OK;
2553}
2554
2555
2556/* exported interface, documented in netsurf/browser_window.h */
2557nserror
2558browser_window_set_name(struct browser_window *bw, const char *name)
2559{
2560 char *nname = NULL((void*)0);
2561
2562 assert(bw != NULL)((bw != ((void*)0)) ? (void) (0) : __assert_fail ("bw != NULL"
, "desktop/browser_window.c", 2562, __extension__ __PRETTY_FUNCTION__
))
;
2563
2564 if (name != NULL((void*)0)) {
2565 nname = strdup(name);
2566 if (nname == NULL((void*)0)) {
2567 return NSERROR_NOMEM;
2568 }
2569 }
2570
2571 if (bw->name != NULL((void*)0)) {
2572 free(bw->name);
2573 }
2574
2575 bw->name = nname;
2576
2577 return NSERROR_OK;
2578}
2579
2580
2581/* exported interface, documented in netsurf/browser_window.h */
2582bool_Bool
2583browser_window_redraw(struct browser_window *bw,
2584 int x, int y,
2585 const struct rect *clip,
2586 const struct redraw_context *ctx)
2587{
2588 struct redraw_context new_ctx = *ctx;
2589 int width = 0;
2590 int height = 0;
2591 bool_Bool plot_ok = true1;
2592 content_type content_type;
2593 struct content_redraw_data data;
2594 struct rect content_clip;
2595 nserror res;
2596
2597 if (bw == NULL((void*)0)) {
2598 NSLOG(netsurf, INFO, "NULL browser window")do { if (NSLOG_LEVEL_INFO >= NSLOG_LEVEL_VERBOSE) { static
nslog_entry_context_t _nslog_ctx = { &__nslog_category_netsurf
, NSLOG_LEVEL_INFO, "desktop/browser_window.c", sizeof("desktop/browser_window.c"
) - 1, __PRETTY_FUNCTION__, sizeof(__PRETTY_FUNCTION__) - 1, 2598
, }; nslog__log(&_nslog_ctx, "NULL browser window"); } } while
(0)
;
2599 return false0;
2600 }
2601
2602 x /= bw->scale;
2603 y /= bw->scale;
2604
2605 if ((bw->current_content == NULL((void*)0)) &&
2606 (bw->children == NULL((void*)0))) {
2607 /* Browser window has no content, render blank fill */
2608 ctx->plot->clip(ctx, clip);
2609 return (ctx->plot->rectangle(ctx, plot_style_fill_white, clip) == NSERROR_OK);
2610 }
2611
2612 /* Browser window has content OR children (frames) */
2613 if ((bw->window != NULL((void*)0)) &&
2614 (ctx->plot->option_knockout)) {
2615 /* Root browser window: start knockout */
2616 knockout_plot_start(ctx, &new_ctx);
2617 }
2618
2619 new_ctx.plot->clip(ctx, clip);
2620
2621 /* Handle redraw of any browser window children */
2622 if (bw->children) {
2623 struct browser_window *child;
2624 int cur_child;
2625 int children = bw->rows * bw->cols;
2626
2627 if (bw->window != NULL((void*)0)) {
2628 /* Root browser window; start with blank fill */
2629 plot_ok &= (new_ctx.plot->rectangle(ctx,
2630 plot_style_fill_white,
2631 clip) == NSERROR_OK);
2632 }
2633
2634 /* Loop through all children of bw */
2635 for (cur_child = 0; cur_child < children; cur_child++) {
2636 /* Set current child */
2637 child = &bw->children[cur_child];
2638
2639 /* Get frame edge area in global coordinates */
2640 content_clip.x0 = (x + child->x) * child->scale;
2641 content_clip.y0 = (y + child->y) * child->scale;
2642 content_clip.x1 = content_clip.x0 +
2643 child->width * child->scale;
2644 content_clip.y1 = content_clip.y0 +
2645 child->height * child->scale;
2646
2647 /* Intersect it with clip rectangle */
2648 if (content_clip.x0 < clip->x0)
2649 content_clip.x0 = clip->x0;
2650 if (content_clip.y0 < clip->y0)
2651 content_clip.y0 = clip->y0;
2652 if (clip->x1 < content_clip.x1)
2653 content_clip.x1 = clip->x1;
2654 if (clip->y1 < content_clip.y1)
2655 content_clip.y1 = clip->y1;
2656
2657 /* Skip this frame if it lies outside clip rectangle */
2658 if (content_clip.x0 >= content_clip.x1 ||
2659 content_clip.y0 >= content_clip.y1)
2660 continue;
2661
2662 /* Redraw frame */
2663 plot_ok &= browser_window_redraw(child,
2664 x + child->x,
2665 y + child->y,
2666 &content_clip,
2667 &new_ctx);
2668 }
2669
2670 /* Nothing else to redraw for browser windows with children;
2671 * cleanup and return
2672 */
2673 if (bw->window != NULL((void*)0) && ctx->plot->option_knockout) {
2674 /* Root browser window: knockout end */
2675 knockout_plot_end(ctx);
2676 }
2677
2678 return plot_ok;
2679 }
2680
2681 /* Handle browser windows with content to redraw */
2682
2683 content_type = content_get_type(bw->current_content);
2684 if (content_type != CONTENT_HTML && content_type != CONTENT_TEXTPLAIN) {
2685 /* Set render area according to scale */
2686 width = content_get_width(bw->current_content) * bw->scale;
2687 height = content_get_height(bw->current_content) * bw->scale;
2688
2689 /* Non-HTML may not fill viewport to extents, so plot white
2690 * background fill */
2691 plot_ok &= (new_ctx.plot->rectangle(&new_ctx,
2692 plot_style_fill_white,
2693 clip) == NSERROR_OK);
2694 }
2695
2696 /* Set up content redraw data */
2697 data.x = x - scrollbar_get_offset(bw->scroll_x);
2698 data.y = y - scrollbar_get_offset(bw->scroll_y);
2699 data.width = width;
2700 data.height = height;
2701
2702 data.background_colour = 0xFFFFFF;
2703 data.scale = bw->scale;
2704 data.repeat_x = false0;
2705 data.repeat_y = false0;
2706
2707 content_clip = *clip;
2708
2709 if (!bw->window) {
2710 int x0 = x * bw->scale;
2711 int y0 = y * bw->scale;
2712 int x1 = (x + bw->width - ((bw->scroll_y != NULL((void*)0)) ?
2713 SCROLLBAR_WIDTH16 : 0)) * bw->scale;
2714 int y1 = (y + bw->height - ((bw->scroll_x != NULL((void*)0)) ?
2715 SCROLLBAR_WIDTH16 : 0)) * bw->scale;
2716
2717 if (content_clip.x0 < x0) content_clip.x0 = x0;
2718 if (content_clip.y0 < y0) content_clip.y0 = y0;
2719 if (x1 < content_clip.x1) content_clip.x1 = x1;
2720 if (y1 < content_clip.y1) content_clip.y1 = y1;
2721 }
2722
2723 /* Render the content */
2724 plot_ok &= content_redraw(bw->current_content, &data,
2725 &content_clip, &new_ctx);
2726
2727 /* Back to full clip rect */
2728 new_ctx.plot->clip(&new_ctx, clip);
2729
2730 if (!bw->window) {
2731 /* Render scrollbars */
2732 int off_x, off_y;
2733 if (bw->scroll_x != NULL((void*)0)) {
2734 browser_window_get_scrollbar_pos(bw, true1,
2735 &off_x, &off_y);
2736 res = scrollbar_redraw(bw->scroll_x,
2737 x + off_x, y + off_y, clip,
2738 bw->scale, &new_ctx);
2739 if (res != NSERROR_OK) {
2740 plot_ok = false0;
2741 }
2742 }
2743 if (bw->scroll_y != NULL((void*)0)) {
2744 browser_window_get_scrollbar_pos(bw, false0,
2745 &off_x, &off_y);
2746 res = scrollbar_redraw(bw->scroll_y,
2747 x + off_x, y + off_y, clip,
2748 bw->scale, &new_ctx);
2749 if (res != NSERROR_OK) {
2750 plot_ok = false0;
2751 }
2752 }
2753 }
2754
2755 if (bw->window != NULL((void*)0) && ctx->plot->option_knockout) {
2756 /* Root browser window: end knockout */
2757 knockout_plot_end(ctx);
2758 }
2759
2760 return plot_ok;
2761}
2762
2763
2764/* exported interface, documented in netsurf/browser_window.h */
2765bool_Bool browser_window_redraw_ready(struct browser_window *bw)
2766{
2767 if (bw == NULL((void*)0)) {
2768 NSLOG(netsurf, INFO, "NULL browser window")do { if (NSLOG_LEVEL_INFO >= NSLOG_LEVEL_VERBOSE) { static
nslog_entry_context_t _nslog_ctx = { &__nslog_category_netsurf
, NSLOG_LEVEL_INFO, "desktop/browser_window.c", sizeof("desktop/browser_window.c"
) - 1, __PRETTY_FUNCTION__, sizeof(__PRETTY_FUNCTION__) - 1, 2768
, }; nslog__log(&_nslog_ctx, "NULL browser window"); } } while
(0)
;
2769 return false0;
2770 } else if (bw->current_content != NULL((void*)0)) {
2771 /* Can't render locked contents */
2772 return !content_is_locked(bw->current_content);
2773 }
2774
2775 return true1;
2776}
2777
2778
2779/* exported interface, documented in browser_private.h */
2780void browser_window_update_extent(struct browser_window *bw)
2781{
2782 if (bw->window != NULL((void*)0)) {
2783 /* Front end window */
2784 guit->window->event(bw->window, GW_EVENT_UPDATE_EXTENT);
2785 } else {
2786 /* Core-managed browser window */
2787 browser_window_handle_scrollbars(bw);
2788 }
2789}
2790
2791
2792/* exported interface, documented in netsurf/browser_window.h */
2793void
2794browser_window_get_position(struct browser_window *bw,
2795 bool_Bool root,
2796 int *pos_x,
2797 int *pos_y)
2798{
2799 *pos_x = 0;
2800 *pos_y = 0;
2801
2802 assert(bw != NULL)((bw != ((void*)0)) ? (void) (0) : __assert_fail ("bw != NULL"
, "desktop/browser_window.c", 2802, __extension__ __PRETTY_FUNCTION__
))
;
2803
2804 while (bw) {
2805 switch (bw->browser_window_type) {
2806
2807 case BROWSER_WINDOW_FRAMESET:
2808 *pos_x += bw->x * bw->scale;
2809 *pos_y += bw->y * bw->scale;
2810 break;
2811
2812 case BROWSER_WINDOW_NORMAL:
2813 /* There is no offset to the root browser window */
2814 break;
2815
2816 case BROWSER_WINDOW_FRAME:
2817 /* Iframe and Frame handling is identical;
2818 * fall though */
2819 case BROWSER_WINDOW_IFRAME:
2820 *pos_x += (bw->x - scrollbar_get_offset(bw->scroll_x)) *
2821 bw->scale;
2822 *pos_y += (bw->y - scrollbar_get_offset(bw->scroll_y)) *
2823 bw->scale;
2824 break;
2825 }
2826
2827 bw = bw->parent;
2828
2829 if (!root) {
2830 /* return if we just wanted the position in the parent
2831 * browser window. */
2832 return;
2833 }
2834 }
2835}
2836
2837
2838/* exported interface, documented in netsurf/browser_window.h */
2839void browser_window_set_position(struct browser_window *bw, int x, int y)
2840{
2841 assert(bw != NULL)((bw != ((void*)0)) ? (void) (0) : __assert_fail ("bw != NULL"
, "desktop/browser_window.c", 2841, __extension__ __PRETTY_FUNCTION__
))
;
2842
2843 if (bw->window == NULL((void*)0)) {
2844 /* Core managed browser window */
2845 bw->x = x;
2846 bw->y = y;
2847 } else {
2848 NSLOG(netsurf, INFO,do { if (NSLOG_LEVEL_INFO >= NSLOG_LEVEL_VERBOSE) { static
nslog_entry_context_t _nslog_ctx = { &__nslog_category_netsurf
, NSLOG_LEVEL_INFO, "desktop/browser_window.c", sizeof("desktop/browser_window.c"
) - 1, __PRETTY_FUNCTION__, sizeof(__PRETTY_FUNCTION__) - 1, 2849
, }; nslog__log(&_nslog_ctx, "Asked to set position of front end window."
); } } while(0)
2849 "Asked to set position of front end window.")do { if (NSLOG_LEVEL_INFO >= NSLOG_LEVEL_VERBOSE) { static
nslog_entry_context_t _nslog_ctx = { &__nslog_category_netsurf
, NSLOG_LEVEL_INFO, "desktop/browser_window.c", sizeof("desktop/browser_window.c"
) - 1, __PRETTY_FUNCTION__, sizeof(__PRETTY_FUNCTION__) - 1, 2849
, }; nslog__log(&_nslog_ctx, "Asked to set position of front end window."
); } } while(0)
;
2850 assert(0)((0) ? (void) (0) : __assert_fail ("0", "desktop/browser_window.c"
, 2850, __extension__ __PRETTY_FUNCTION__))
;
2851 }
2852}
2853
2854
2855/* exported interface, documented in netsurf/browser_window.h */
2856void
2857browser_window_set_drag_type(struct browser_window *bw,
2858 browser_drag_type type,
2859 const struct rect *rect)
2860{
2861 struct browser_window *top_bw = browser_window_get_root(bw);
2862 gui_drag_type gtype;
2863
2864 bw->drag.type = type;
2865
2866 if (type == DRAGGING_NONE) {
2867 top_bw->drag.window = NULL((void*)0);
2868 } else {
2869 top_bw->drag.window = bw;
2870
2871 switch (type) {
2872 case DRAGGING_SELECTION:
2873 /** \todo tell front end */
2874 return;
2875 case DRAGGING_SCR_X:
2876 case DRAGGING_SCR_Y:
2877 case DRAGGING_CONTENT_SCROLLBAR:
2878 gtype = GDRAGGING_SCROLLBAR;
2879 break;
2880 default:
2881 gtype = GDRAGGING_OTHER;
2882 break;
2883 }
2884
2885 guit->window->drag_start(top_bw->window, gtype, rect);
2886 }
2887}
2888
2889
2890/* exported interface, documented in netsurf/browser_window.h */
2891browser_drag_type browser_window_get_drag_type(struct browser_window *bw)
2892{
2893 return bw->drag.type;
2894}
2895
2896
2897/* exported interface, documented in netsurf/browser_window.h */
2898struct browser_window * browser_window_get_root(struct browser_window *bw)
2899{
2900 while (bw && bw->parent) {
2901 bw = bw->parent;
2902 }
2903 return bw;
2904}
2905
2906
2907/* exported interface, documented in netsurf/browser_window.h */
2908browser_editor_flags browser_window_get_editor_flags(struct browser_window *bw)
2909{
2910 browser_editor_flags ed_flags = BW_EDITOR_NONE;
2911 assert(bw->window)((bw->window) ? (void) (0) : __assert_fail ("bw->window"
, "desktop/browser_window.c", 2911, __extension__ __PRETTY_FUNCTION__
))
;
2912 assert(bw->parent == NULL)((bw->parent == ((void*)0)) ? (void) (0) : __assert_fail (
"bw->parent == NULL", "desktop/browser_window.c", 2912, __extension__
__PRETTY_FUNCTION__))
;
2913
2914 if (bw->selection.bw != NULL((void*)0)) {
2915 ed_flags |= BW_EDITOR_CAN_COPY;
2916
2917 if (!bw->selection.read_only)
2918 ed_flags |= BW_EDITOR_CAN_CUT;
2919 }
2920
2921 if (bw->can_edit)
2922 ed_flags |= BW_EDITOR_CAN_PASTE;
2923
2924 return ed_flags;
2925}
2926
2927
2928/* exported interface, documented in netsurf/browser_window.h */
2929bool_Bool browser_window_can_select(struct browser_window *bw)
2930{
2931 if (bw == NULL((void*)0) || bw->current_content == NULL((void*)0))
2932 return false0;
2933
2934 /* TODO: We shouldn't have to know about specific content types
2935 * here. There should be a content_is_selectable() call. */
2936 if (content_get_type(bw->current_content) != CONTENT_HTML &&
2937 content_get_type(bw->current_content) !=
2938 CONTENT_TEXTPLAIN)
2939 return false0;
2940
2941 return true1;
2942}
2943
2944
2945/* exported interface, documented in netsurf/browser_window.h */
2946char * browser_window_get_selection(struct browser_window *bw)
2947{
2948 assert(bw->window)((bw->window) ? (void) (0) : __assert_fail ("bw->window"
, "desktop/browser_window.c", 2948, __extension__ __PRETTY_FUNCTION__
))
;
2949 assert(bw->parent == NULL)((bw->parent == ((void*)0)) ? (void) (0) : __assert_fail (
"bw->parent == NULL", "desktop/browser_window.c", 2949, __extension__
__PRETTY_FUNCTION__))
;
2950
2951 if (bw->selection.bw == NULL((void*)0) ||
2952 bw->selection.bw->current_content == NULL((void*)0))
2953 return NULL((void*)0);
2954
2955 return content_get_selection(bw->selection.bw->current_content);
2956}
2957
2958
2959/* exported interface, documented in netsurf/browser_window.h */
2960bool_Bool browser_window_can_search(struct browser_window *bw)
2961{
2962 if (bw == NULL((void*)0) || bw->current_content == NULL((void*)0))
2963 return false0;
2964
2965 /** \todo We shouldn't have to know about specific content
2966 * types here. There should be a content_is_searchable() call.
2967 */
2968 if ((content_get_type(bw->current_content) != CONTENT_HTML) &&
2969 (content_get_type(bw->current_content) != CONTENT_TEXTPLAIN)) {
2970 return false0;
2971 }
2972
2973 return true1;
2974}
2975
2976
2977/* exported interface, documented in netsurf/browser_window.h */
2978bool_Bool browser_window_is_frameset(struct browser_window *bw)
2979{
2980 return (bw->children != NULL((void*)0));
2981}
2982
2983
2984/* exported interface, documented in netsurf/browser_window.h */
2985nserror
2986browser_window_get_scrollbar_type(struct browser_window *bw,
2987 browser_scrolling *h,
2988 browser_scrolling *v)
2989{
2990 *h = bw->scrolling;
2991 *v = bw->scrolling;
2992
2993 return NSERROR_OK;
2994}
2995
2996
2997/* exported interface, documented in netsurf/browser_window.h */
2998nserror
2999browser_window_get_features(struct browser_window *bw,
3000 int x, int y,
3001 struct browser_window_features *data)
3002{
3003 /* clear the features structure to empty values */
3004 data->link = NULL((void*)0);
3005 data->link_title = NULL((void*)0);
3006 data->link_title_length = 0;
3007 data->object = NULL((void*)0);
3008 data->main = NULL((void*)0);
3009 data->form_features = CTX_FORM_NONE;
3010
3011 return browser_window__get_contextual_content(bw,
3012 x / bw->scale,
3013 y / bw->scale,
3014 data);
3015}
3016
3017
3018/* exported interface, documented in netsurf/browser_window.h */
3019bool_Bool
3020browser_window_scroll_at_point(struct browser_window *bw,
3021 int x, int y,
3022 int scrx, int scry)
3023{
3024 return browser_window_scroll_at_point_internal(bw,
3025 x / bw->scale,
3026 y / bw->scale,
3027 scrx,
3028 scry);
3029}
3030
3031
3032/* exported interface, documented in netsurf/browser_window.h */
3033bool_Bool
3034browser_window_drop_file_at_point(struct browser_window *bw,
3035 int x, int y,
3036 char *file)
3037{
3038 return browser_window_drop_file_at_point_internal(bw,
3039 x / bw->scale,
3040 y / bw->scale,
3041 file);
3042}
3043
3044
3045/* exported interface, documented in netsurf/browser_window.h */
3046void
3047browser_window_set_gadget_filename(struct browser_window *bw,
3048 struct form_control *gadget,
3049 const char *fn)
3050{
3051 html_set_file_gadget_filename(bw->current_content, gadget, fn);
3052}
3053
3054
3055/* exported interface, documented in netsurf/browser_window.h */
3056nserror
3057browser_window_debug_dump(struct browser_window *bw,
3058 FILE *f,
3059 enum content_debug op)
3060{
3061 if (bw->current_content != NULL((void*)0)) {
3062 return content_debug_dump(bw->current_content, f, op);
3063 }
3064 return NSERROR_OK;
3065}
3066
3067
3068/* exported interface, documented in netsurf/browser_window.h */
3069nserror browser_window_debug(struct browser_window *bw, enum content_debug op)
3070{
3071 if (bw->current_content != NULL((void*)0)) {
3072 return content_debug(bw->current_content, op);
3073 }
3074 return NSERROR_OK;
3075}
3076
3077
3078/* exported interface, documented in netsurf/browser_window.h */
3079nserror
3080browser_window_create(enum browser_window_create_flags flags,
3081 nsurl *url,
3082 nsurl *referrer,
3083 struct browser_window *existing,
3084 struct browser_window **bw)
3085{
3086 gui_window_create_flags gw_flags = GW_CREATE_NONE;
3087 struct browser_window *ret;
3088 nserror err;
3089
3090 /* Check parameters */
3091 if (flags & BW_CREATE_CLONE) {
3092 if (existing == NULL((void*)0)) {
3093 assert(0 && "Failed: No existing window provided.")((0 && "Failed: No existing window provided.") ? (void
) (0) : __assert_fail ("0 && \"Failed: No existing window provided.\""
, "desktop/browser_window.c", 3093, __extension__ __PRETTY_FUNCTION__
))
;
3094 return NSERROR_BAD_PARAMETER;
3095 }
3096 }
3097
3098 if (!(flags & BW_CREATE_HISTORY)) {
3099 if (!(flags & BW_CREATE_CLONE) || existing == NULL((void*)0)) {
3100 assert(0 && "Failed: Must have existing for history.")((0 && "Failed: Must have existing for history.") ? (
void) (0) : __assert_fail ("0 && \"Failed: Must have existing for history.\""
, "desktop/browser_window.c", 3100, __extension__ __PRETTY_FUNCTION__
))
;
3101 return NSERROR_BAD_PARAMETER;
3102 }
3103 }
3104
3105 ret = calloc(1, sizeof(struct browser_window));
3106 if (ret == NULL((void*)0)) {
3107 return NSERROR_NOMEM;
3108 }
3109
3110 /* Initialise common parts */
3111 err = browser_window_initialise_common(flags, ret, existing);
3112 if (err != NSERROR_OK) {
3113 browser_window_destroy(ret);
3114 return err;
3115 }
3116
3117 /* window characteristics */
3118 ret->browser_window_type = BROWSER_WINDOW_NORMAL;
3119 ret->scrolling = BW_SCROLLING_YES;
3120 ret->border = true1;
3121 ret->no_resize = true1;
3122 ret->focus = ret;
3123
3124 /* initialise last action with creation time */
3125 nsu_getmonotonic_ms(&ret->last_action);
3126
3127 /* The existing gui_window is on the top-level existing
3128 * browser_window. */
3129 existing = browser_window_get_root(existing);
3130
3131 /* Set up gui_window creation flags */
3132 if (flags & BW_CREATE_TAB)
3133 gw_flags |= GW_CREATE_TAB;
3134 if (flags & BW_CREATE_CLONE)
3135 gw_flags |= GW_CREATE_CLONE;
3136 if (flags & BW_CREATE_FOREGROUND)
3137 gw_flags |= GW_CREATE_FOREGROUND;
3138 if (flags & BW_CREATE_FOCUS_LOCATION)
3139 gw_flags |= GW_CREATE_FOCUS_LOCATION;
3140
3141 ret->window = guit->window->create(ret,
3142 (existing != NULL((void*)0)) ? existing->window : NULL((void*)0),
3143 gw_flags);
3144
3145 if (ret->window == NULL((void*)0)) {
3146 browser_window_destroy(ret);
3147 return NSERROR_BAD_PARAMETER;
3148 }
3149
3150 if (url != NULL((void*)0)) {
3151 enum browser_window_nav_flags nav_flags;
3152 nav_flags = BW_NAVIGATE_NO_TERMINAL_HISTORY_UPDATE;
3153 if (flags & BW_CREATE_UNVERIFIABLE) {
3154 nav_flags |= BW_NAVIGATE_UNVERIFIABLE;
3155 }
3156 if (flags & BW_CREATE_HISTORY) {
3157 nav_flags |= BW_NAVIGATE_HISTORY;
3158 }
3159 browser_window_navigate(ret,
3160 url,
3161 referrer,
3162 nav_flags,
3163 NULL((void*)0),
3164 NULL((void*)0),
3165 NULL((void*)0));
3166 }
3167
3168 if (bw != NULL((void*)0)) {
3169 *bw = ret;
3170 }
3171
3172 return NSERROR_OK;
3173}
3174
3175
3176/* exported internal interface, documented in desktop/browser_private.h */
3177nserror
3178browser_window_initialise_common(enum browser_window_create_flags flags,
3179 struct browser_window *bw,
3180 const struct browser_window *existing)
3181{
3182 nserror err;
3183 assert(bw)((bw) ? (void) (0) : __assert_fail ("bw", "desktop/browser_window.c"
, 3183, __extension__ __PRETTY_FUNCTION__))
;
3184
3185 /* new javascript context for each window/(i)frame */
3186 err = js_newheap(nsoption_int(script_timeout)(nsoptions[NSOPTION_script_timeout].value.i), &bw->jsheap);
3187 if (err != NSERROR_OK)
3188 return err;
3189
3190 if (flags & BW_CREATE_CLONE) {
3191 assert(existing != NULL)((existing != ((void*)0)) ? (void) (0) : __assert_fail ("existing != NULL"
, "desktop/browser_window.c", 3191, __extension__ __PRETTY_FUNCTION__
))
;
3192
3193 /* clone history */
3194 err = browser_window_history_clone(existing, bw);
3195
3196 /* copy the scale */
3197 bw->scale = existing->scale;
3198 } else {
3199 /* create history */
3200 err = browser_window_history_create(bw);
3201
3202 /* default scale */
3203 bw->scale = (float) nsoption_int(scale)(nsoptions[NSOPTION_scale].value.i) / 100.0;
3204 }
3205
3206 if (err != NSERROR_OK)
3207 return err;
3208
3209 /* window characteristics */
3210 bw->refresh_interval = -1;
3211
3212 bw->drag.type = DRAGGING_NONE;
3213
3214 bw->scroll_x = NULL((void*)0);
3215 bw->scroll_y = NULL((void*)0);
3216
3217 bw->focus = NULL((void*)0);
3218
3219 /* initialise status text cache */
3220 bw->status.text = NULL((void*)0);
3221 bw->status.text_len = 0;
3222 bw->status.match = 0;
3223 bw->status.miss = 0;
3224
3225 return NSERROR_OK;
3226}
3227
3228
3229/* exported interface, documented in netsurf/browser_window.h */
3230void browser_window_destroy(struct browser_window *bw)
3231{
3232 /* can't destoy child windows on their own */
3233 assert(!bw->parent)((!bw->parent) ? (void) (0) : __assert_fail ("!bw->parent"
, "desktop/browser_window.c", 3233, __extension__ __PRETTY_FUNCTION__
))
;
3234
3235 /* destroy */
3236 browser_window_destroy_internal(bw);
3237 free(bw);
3238}
3239
3240
3241/* exported interface, documented in netsurf/browser_window.h */
3242nserror browser_window_refresh_url_bar(struct browser_window *bw)
3243{
3244 nserror ret;
3245 nsurl *display_url, *url;
3246
3247 assert(bw)((bw) ? (void) (0) : __assert_fail ("bw", "desktop/browser_window.c"
, 3247, __extension__ __PRETTY_FUNCTION__))
;
3248
3249 if (bw->parent != NULL((void*)0)) {
3250 /* Not root window; don't set a URL in GUI URL bar */
3251 return NSERROR_OK;
3252 }
3253
3254 if (bw->current_content == NULL((void*)0)) {
3255 /* no content so return about:blank */
3256 ret = browser_window_refresh_url_bar_internal(bw,
3257 corestring_nsurl_about_blank);
3258 } else if (bw->throbbing && bw->loading_parameters.url != NULL((void*)0)) {
3259 /* Throbbing and we have loading parameters, use those */
3260 url = bw->loading_parameters.url;
3261 ret = browser_window_refresh_url_bar_internal(bw, url);
3262 } else if (bw->frag_id == NULL((void*)0)) {
3263 if (bw->internal_nav) {
3264 url = bw->loading_parameters.url;
3265 } else {
3266 url = hlcache_handle_get_url(bw->current_content);
3267 }
3268 ret = browser_window_refresh_url_bar_internal(bw, url);
3269 } else {
3270 /* Combine URL and Fragment */
3271 if (bw->internal_nav) {
3272 url = bw->loading_parameters.url;
3273 } else {
3274 url = hlcache_handle_get_url(bw->current_content);
3275 }
3276 ret = nsurl_refragment(
3277 url,
3278 bw->frag_id, &display_url);
3279 if (ret == NSERROR_OK) {
3280 ret = browser_window_refresh_url_bar_internal(bw,
3281 display_url);
3282 nsurl_unref(display_url);
3283 }
3284 }
3285
3286 return ret;
3287}
3288
3289
3290/* exported interface documented in netsurf/browser_window.h */
3291nserror
3292browser_window_navigate(struct browser_window *bw,
3293 nsurl *url,
3294 nsurl *referrer,
3295 enum browser_window_nav_flags flags,
3296 char *post_urlenc,
3297 struct fetch_multipart_data *post_multipart,
3298 hlcache_handle *parent)
3299{
3300 int depth = 0;
3301 struct browser_window *cur;
3302 uint32_t fetch_flags = 0;
3303 bool_Bool fetch_is_post = (post_urlenc != NULL((void*)0) || post_multipart != NULL((void*)0));
3304 llcache_post_data post;
3305 hlcache_child_context child;
3306 nserror error;
3307 bool_Bool is_internal = false0;
3308 struct browser_fetch_parameters params, *pass_params = NULL((void*)0);
3309
3310 assert(bw)((bw) ? (void) (0) : __assert_fail ("bw", "desktop/browser_window.c"
, 3310, __extension__ __PRETTY_FUNCTION__))
;
3311 assert(url)((url) ? (void) (0) : __assert_fail ("url", "desktop/browser_window.c"
, 3311, __extension__ __PRETTY_FUNCTION__))
;
3312
3313 NSLOG(netsurf, INFO, "bw %p, url %s", bw, nsurl_access(url))do { if (NSLOG_LEVEL_INFO >= NSLOG_LEVEL_VERBOSE) { static
nslog_entry_context_t _nslog_ctx = { &__nslog_category_netsurf
, NSLOG_LEVEL_INFO, "desktop/browser_window.c", sizeof("desktop/browser_window.c"
) - 1, __PRETTY_FUNCTION__, sizeof(__PRETTY_FUNCTION__) - 1, 3313
, }; nslog__log(&_nslog_ctx, "bw %p, url %s", bw, nsurl_access
(url)); } } while(0)
;
3314
3315 /*
3316 * determine if navigation is internal url, if so, we do not
3317 * do certain things during the load.
3318 */
3319 is_internal = is_internal_navigate_url(url);
3320
3321 if (is_internal &&
3322 !(flags & BW_NAVIGATE_INTERNAL)) {
3323 /* Internal navigation detected, but flag not set, only allow
3324 * this is there's a fetch multipart
3325 */
3326 if (post_multipart == NULL((void*)0)) {
3327 return NSERROR_NEED_DATA;
3328 }
3329 /* It *is* internal, set it as such */
3330 flags |= BW_NAVIGATE_INTERNAL | BW_NAVIGATE_HISTORY;
3331 /* If we were previously internal, don't update again */
3332 if (bw->internal_nav) {
3333 flags |= BW_NAVIGATE_NO_TERMINAL_HISTORY_UPDATE;
3334 }
3335 }
3336
3337 /* If we're navigating and we have a history entry and a content
3338 * then update the history entry before we navigate to save our
3339 * current state. However since history navigation pre-moves
3340 * the history state, we ensure that we only do this if we've not
3341 * been suppressed. In the suppressed case, the history code
3342 * updates the history itself before navigating.
3343 */
3344 if (bw->current_content != NULL((void*)0) &&
3345 bw->history != NULL((void*)0) &&
3346 bw->history->current != NULL((void*)0) &&
3347 !is_internal &&
3348 !(flags & BW_NAVIGATE_NO_TERMINAL_HISTORY_UPDATE)) {
3349 browser_window_history_update(bw, bw->current_content);
3350 }
3351
3352 /* don't allow massively nested framesets */
3353 for (cur = bw; cur->parent; cur = cur->parent) {
3354 depth++;
3355 }
3356 if (depth > FRAME_DEPTH8) {
3357 NSLOG(netsurf, INFO, "frame depth too high.")do { if (NSLOG_LEVEL_INFO >= NSLOG_LEVEL_VERBOSE) { static
nslog_entry_context_t _nslog_ctx = { &__nslog_category_netsurf
, NSLOG_LEVEL_INFO, "desktop/browser_window.c", sizeof("desktop/browser_window.c"
) - 1, __PRETTY_FUNCTION__, sizeof(__PRETTY_FUNCTION__) - 1, 3357
, }; nslog__log(&_nslog_ctx, "frame depth too high."); } }
while(0)
;
3358 return NSERROR_FRAME_DEPTH;
3359 }
3360
3361 /* Set up retrieval parameters */
3362 if (!(flags & BW_NAVIGATE_UNVERIFIABLE)) {
3363 fetch_flags |= LLCACHE_RETRIEVE_VERIFIABLE;
3364 }
3365
3366 if (post_multipart != NULL((void*)0)) {
3367 post.type = LLCACHE_POST_MULTIPART;
3368 post.data.multipart = post_multipart;
3369 } else if (post_urlenc != NULL((void*)0)) {
3370 post.type = LLCACHE_POST_URL_ENCODED;
3371 post.data.urlenc = post_urlenc;
3372 }
3373
3374 child.charset = content_get_encoding(parent, CONTENT_ENCODING_NORMAL);
3375 if ((parent != NULL((void*)0)) && (content_get_type(parent) == CONTENT_HTML)) {
3376 child.quirks = content_get_quirks(parent);
3377 } else {
3378 child.quirks = false0;
3379 }
3380
3381 url = nsurl_ref(url);
3382
3383 if (referrer != NULL((void*)0)) {
3384 referrer = nsurl_ref(referrer);
3385 }
3386
3387 /* Get download out of the way */
3388 if ((flags & BW_NAVIGATE_DOWNLOAD) != 0) {
3389 error = browser_window_download(bw,
3390 url,
3391 referrer,
3392 fetch_flags,
3393 fetch_is_post,
3394 &post);
3395 nsurl_unref(url);
3396 if (referrer != NULL((void*)0)) {
3397 nsurl_unref(referrer);
3398 }
3399 return error;
3400 }
3401
3402 if (bw->frag_id != NULL((void*)0)) {
3403 lwc_string_unref(bw->frag_id){ lwc_string *__lwc_s = (bw->frag_id); ((__lwc_s != ((void
*)0)) ? (void) (0) : __assert_fail ("__lwc_s != NULL", "desktop/browser_window.c"
, 3403, __extension__ __PRETTY_FUNCTION__)); __lwc_s->refcnt
--; if ((__lwc_s->refcnt == 0) || ((__lwc_s->refcnt == 1
) && (__lwc_s->insensitive == __lwc_s))) lwc_string_destroy
(__lwc_s); }
;
3404 }
3405 bw->frag_id = NULL((void*)0);
3406
3407 if (nsurl_has_component(url, NSURL_FRAGMENT)) {
3408 bool_Bool same_url = false0;
3409
3410 bw->frag_id = nsurl_get_component(url, NSURL_FRAGMENT);
3411
3412 /* Compare new URL with existing one (ignoring fragments) */
3413 if ((bw->current_content != NULL((void*)0)) &&
3414 (hlcache_handle_get_url(bw->current_content) != NULL((void*)0))) {
3415 same_url = nsurl_compare(
3416 url,
3417 hlcache_handle_get_url(bw->current_content),
3418 NSURL_COMPLETE);
3419 }
3420
3421 /* if we're simply moving to another ID on the same page,
3422 * don't bother to fetch, just update the window.
3423 */
3424 if ((same_url) &&
3425 (fetch_is_post == false0) &&
3426 (nsurl_has_component(url, NSURL_QUERY) == false0)) {
3427 nsurl_unref(url);
3428
3429 if (referrer != NULL((void*)0)) {
3430 nsurl_unref(referrer);
3431 }
3432
3433 if ((flags & BW_NAVIGATE_HISTORY) != 0) {
3434 browser_window_history_add(bw,
3435 bw->current_content,
3436 bw->frag_id);
3437 }
3438
3439 browser_window_update(bw, false0);
3440
3441 if (bw->current_content != NULL((void*)0)) {
3442 browser_window_refresh_url_bar(bw);
3443 }
3444 return NSERROR_OK;
3445 }
3446 }
3447
3448 browser_window_stop(bw);
3449 browser_window_remove_caret(bw, false0);
3450 browser_window_destroy_children(bw);
3451 browser_window_destroy_iframes(bw);
3452
3453 /* Set up the fetch parameters */
3454 memset(&params, 0, sizeof(params));
3455
3456 params.url = nsurl_ref(url);
3457
3458 if (referrer != NULL((void*)0)) {
3459 params.referrer = nsurl_ref(referrer);
3460 }
3461
3462 params.flags = flags;
3463
3464 if (post_urlenc != NULL((void*)0)) {
3465 params.post_urlenc = strdup(post_urlenc);
3466 }
3467
3468 if (post_multipart != NULL((void*)0)) {
3469 params.post_multipart = fetch_multipart_data_clone(post_multipart);
3470 }
3471
3472 if (parent != NULL((void*)0)) {
3473 params.parent_charset = strdup(child.charset);
3474 params.parent_quirks = child.quirks;
3475 }
3476
3477 bw->internal_nav = is_internal;
3478
3479 if (is_internal) {
3480 pass_params = &params;
3481 } else {
3482 /* At this point, we're navigating, so store the fetch parameters */
3483 browser_window__free_fetch_parameters(&bw->loading_parameters);
3484 memcpy(&bw->loading_parameters, &params, sizeof(params));
3485 memset(&params, 0, sizeof(params));
3486 pass_params = &bw->loading_parameters;
3487 }
3488
3489 error = browser_window__navigate_internal(bw, pass_params);
3490
3491 nsurl_unref(url);
3492
3493 if (referrer != NULL((void*)0)) {
3494 nsurl_unref(referrer);
3495 }
3496
3497 if (is_internal) {
3498 browser_window__free_fetch_parameters(&params);
3499 }
3500
3501 return error;
3502}
3503
3504
3505/**
3506 * Internal navigation handler for normal fetches
3507 */
3508static nserror
3509navigate_internal_real(struct browser_window *bw,
3510 struct browser_fetch_parameters *params)
3511{
3512 uint32_t fetch_flags = 0;
3513 bool_Bool fetch_is_post;
3514 llcache_post_data post;
3515 hlcache_child_context child;
3516 nserror res;
3517 hlcache_handle *c;
3518
3519 NSLOG(netsurf, INFO, "Loading '%s'", nsurl_access(params->url))do { if (NSLOG_LEVEL_INFO >= NSLOG_LEVEL_VERBOSE) { static
nslog_entry_context_t _nslog_ctx = { &__nslog_category_netsurf
, NSLOG_LEVEL_INFO, "desktop/browser_window.c", sizeof("desktop/browser_window.c"
) - 1, __PRETTY_FUNCTION__, sizeof(__PRETTY_FUNCTION__) - 1, 3519
, }; nslog__log(&_nslog_ctx, "Loading '%s'", nsurl_access
(params->url)); } } while(0)
;
3520
3521 fetch_is_post = (params->post_urlenc != NULL((void*)0) || params->post_multipart != NULL((void*)0));
3522
3523 /* Clear SSL info for load */
3524 cert_chain_free(bw->loading_cert_chain);
3525 bw->loading_cert_chain = NULL((void*)0);
3526
3527 /* Set up retrieval parameters */
3528 if (!(params->flags & BW_NAVIGATE_UNVERIFIABLE)) {
3529 fetch_flags |= LLCACHE_RETRIEVE_VERIFIABLE;
3530 }
3531
3532 if (params->post_multipart != NULL((void*)0)) {
3533 post.type = LLCACHE_POST_MULTIPART;
3534 post.data.multipart = params->post_multipart;
3535 } else if (params->post_urlenc != NULL((void*)0)) {
3536 post.type = LLCACHE_POST_URL_ENCODED;
3537 post.data.urlenc = params->post_urlenc;
3538 }
3539
3540 if (params->parent_charset != NULL((void*)0)) {
3541 child.charset = params->parent_charset;
3542 child.quirks = params->parent_quirks;
3543 }
3544
3545 browser_window_set_status(bw, messages_get("Loading"));
3546 bw->history_add = (params->flags & BW_NAVIGATE_HISTORY);
3547
3548 /* Verifiable fetches may trigger a download */
3549 if (!(params->flags & BW_NAVIGATE_UNVERIFIABLE)) {
3550 fetch_flags |= HLCACHE_RETRIEVE_MAY_DOWNLOAD;
3551 }
3552
3553 res = hlcache_handle_retrieve(params->url,
3554 fetch_flags | HLCACHE_RETRIEVE_SNIFF_TYPE,
3555 params->referrer,
3556 fetch_is_post ? &post : NULL((void*)0),
3557 browser_window_callback,
3558 bw,
3559 params->parent_charset != NULL((void*)0) ? &child : NULL((void*)0),
3560 CONTENT_ANY,
3561 &c);
3562
3563 switch (res) {
3564 case NSERROR_OK:
3565 bw->loading_content = c;
3566 browser_window_start_throbber(bw);
3567 if (bw->window != NULL((void*)0)) {
3568 guit->window->set_icon(bw->window, NULL((void*)0));
3569 }
3570 if (bw->internal_nav == false0) {
3571 res = browser_window_refresh_url_bar_internal(bw,
3572 params->url);
3573 }
3574 break;
3575
3576 case NSERROR_NO_FETCH_HANDLER: /* no handler for this type */
3577 /** \todo does this always try and download even
3578 * unverifiable content?
3579 */
3580 res = guit->misc->launch_url(params->url);
3581 break;
3582
3583 default: /* report error to user */
3584 browser_window_set_status(bw, messages_get_errorcode(res));
3585 break;
3586
3587 }
3588
3589 /* Record time */
3590 nsu_getmonotonic_ms(&bw->last_action);
3591
3592 return res;
3593}
3594
3595
3596/**
3597 * Internal navigation handler for the authentication query handler
3598 *
3599 * If the parameters indicate we're processing a *response* from the handler
3600 * then we deal with that, otherwise we pass it on to the about: handler
3601 */
3602static nserror
3603navigate_internal_query_auth(struct browser_window *bw,
3604 struct browser_fetch_parameters *params)
3605{
3606 char *userpass = NULL((void*)0);
3607 const char *username, *password, *realm, *siteurl;
3608 nsurl *sitensurl;
3609 nserror res;
3610 bool_Bool is_login = false0, is_cancel = false0;
3611
3612 assert(params->post_multipart != NULL)((params->post_multipart != ((void*)0)) ? (void) (0) : __assert_fail
("params->post_multipart != NULL", "desktop/browser_window.c"
, 3612, __extension__ __PRETTY_FUNCTION__))
;
3613
3614 is_login = fetch_multipart_data_find(params->post_multipart, "login") != NULL((void*)0);
3615 is_cancel = fetch_multipart_data_find(params->post_multipart, "cancel") != NULL((void*)0);
3616
3617 if (!(is_login || is_cancel)) {
3618 /* This is a request, so pass it on */
3619 return navigate_internal_real(bw, params);
3620 }
3621
3622 if (is_cancel) {
3623 /* We're processing a cancel, do a rough-and-ready nav to
3624 * about:blank
3625 */
3626 browser_window__free_fetch_parameters(&bw->loading_parameters);
3627 bw->loading_parameters.url = nsurl_ref(corestring_nsurl_about_blank);
3628 bw->loading_parameters.flags = BW_NAVIGATE_NO_TERMINAL_HISTORY_UPDATE | BW_NAVIGATE_INTERNAL;
3629 bw->internal_nav = true1;
3630 return browser_window__navigate_internal(bw, &bw->loading_parameters);
3631 }
3632
3633 /* We're processing a "login" attempt from the form */
3634
3635 /* Retrieve the data */
3636 username = fetch_multipart_data_find(params->post_multipart, "username");
3637 password = fetch_multipart_data_find(params->post_multipart, "password");
3638 realm = fetch_multipart_data_find(params->post_multipart, "realm");
3639 siteurl = fetch_multipart_data_find(params->post_multipart, "siteurl");
3640
3641 if (username == NULL((void*)0) || password == NULL((void*)0) ||
3642 realm == NULL((void*)0) || siteurl == NULL((void*)0)) {
3643 /* Bad inputs, simply fail */
3644 return NSERROR_INVALID;
3645 }
3646
3647 /* Parse the URL */
3648 res = nsurl_create(siteurl, &sitensurl);
3649 if (res != NSERROR_OK) {
3650 return res;
3651 }
3652
3653 /* Construct the username/password */
3654 res = browser_window__build_userpass(username, password, &userpass);
3655 if (res != NSERROR_OK) {
3656 nsurl_unref(sitensurl);
3657 return res;
3658 }
3659
3660 /* And let urldb know */
3661 urldb_set_auth_details(sitensurl, realm, userpass);
3662
3663 /* Clean up */
3664 free(userpass);
3665 nsurl_unref(sitensurl);
3666
3667 /* Finally navigate to the original loading parameters */
3668 bw->internal_nav = false0;
3669 return navigate_internal_real(bw, &bw->loading_parameters);
3670}
3671
3672
3673/**
3674 * Internal navigation handler for the SSL/privacy query page.
3675 *
3676 * If the parameters indicate we're processing a *response* from the handler
3677 * then we deal with that, otherwise we pass it on to the about: handler
3678 */
3679static nserror
3680navigate_internal_query_ssl(struct browser_window *bw,
3681 struct browser_fetch_parameters *params)
3682{
3683 bool_Bool is_proceed = false0, is_back = false0;
3684 const char *siteurl = NULL((void*)0);
3685 nsurl *siteurl_ns;
3686
3687 assert(params->post_multipart != NULL)((params->post_multipart != ((void*)0)) ? (void) (0) : __assert_fail
("params->post_multipart != NULL", "desktop/browser_window.c"
, 3687, __extension__ __PRETTY_FUNCTION__))
;
3688
3689 is_proceed = fetch_multipart_data_find(params->post_multipart, "proceed") != NULL((void*)0);
3690 is_back = fetch_multipart_data_find(params->post_multipart, "back") != NULL((void*)0);
3691 siteurl = fetch_multipart_data_find(params->post_multipart, "siteurl");
3692
3693 if (!(is_proceed || is_back) || siteurl == NULL((void*)0)) {
3694 /* This is a request, so pass it on */
3695 return navigate_internal_real(bw, params);
3696 }
3697
3698 if (nsurl_create(siteurl, &siteurl_ns) != NSERROR_OK) {
3699 NSLOG(netsurf, ERROR, "Unable to reset ssl loading parameters")do { if (NSLOG_LEVEL_ERROR >= NSLOG_LEVEL_VERBOSE) { static
nslog_entry_context_t _nslog_ctx = { &__nslog_category_netsurf
, NSLOG_LEVEL_ERROR, "desktop/browser_window.c", sizeof("desktop/browser_window.c"
) - 1, __PRETTY_FUNCTION__, sizeof(__PRETTY_FUNCTION__) - 1, 3699
, }; nslog__log(&_nslog_ctx, "Unable to reset ssl loading parameters"
); } } while(0)
;
3700 } else {
3701 /* In order that we may proceed, replace the loading parameters */
3702 nsurl_unref(bw->loading_parameters.url);
3703 bw->loading_parameters.url = siteurl_ns;
3704 }
3705
3706 return browser_window__handle_ssl_query_response(is_proceed, bw);
3707}
3708
3709
3710/**
3711 * Internal navigation handler for the timeout query page.
3712 *
3713 * If the parameters indicate we're processing a *response* from the handler
3714 * then we deal with that, otherwise we pass it on to the about: handler
3715 */
3716static nserror
3717navigate_internal_query_timeout(struct browser_window *bw,
3718 struct browser_fetch_parameters *params)
3719{
3720 bool_Bool is_retry = false0, is_back = false0;
3721
3722 NSLOG(netsurf, INFO, "bw:%p params:%p", bw, params)do { if (NSLOG_LEVEL_INFO >= NSLOG_LEVEL_VERBOSE) { static
nslog_entry_context_t _nslog_ctx = { &__nslog_category_netsurf
, NSLOG_LEVEL_INFO, "desktop/browser_window.c", sizeof("desktop/browser_window.c"
) - 1, __PRETTY_FUNCTION__, sizeof(__PRETTY_FUNCTION__) - 1, 3722
, }; nslog__log(&_nslog_ctx, "bw:%p params:%p", bw, params
); } } while(0)
;
3723
3724 assert(params->post_multipart != NULL)((params->post_multipart != ((void*)0)) ? (void) (0) : __assert_fail
("params->post_multipart != NULL", "desktop/browser_window.c"
, 3724, __extension__ __PRETTY_FUNCTION__))
;
3725
3726 is_retry = fetch_multipart_data_find(params->post_multipart, "retry") != NULL((void*)0);
3727 is_back = fetch_multipart_data_find(params->post_multipart, "back") != NULL((void*)0);
3728
3729 if (is_back) {
3730 /* do a rough-and-ready nav to the old 'current'
3731 * parameters, with any post data stripped away
3732 */
3733 return browser_window__reload_current_parameters(bw);
3734 }
3735
3736 if (is_retry) {
3737 /* Finally navigate to the original loading parameters */
3738 bw->internal_nav = false0;
3739 return navigate_internal_real(bw, &bw->loading_parameters);
3740 }
3741
3742 return navigate_internal_real(bw, params);
3743}
3744
3745
3746/**
3747 * Internal navigation handler for the fetch error query page.
3748 *
3749 * If the parameters indicate we're processing a *response* from the handler
3750 * then we deal with that, otherwise we pass it on to the about: handler
3751 */
3752static nserror
3753navigate_internal_query_fetcherror(struct browser_window *bw,
3754 struct browser_fetch_parameters *params)
3755{
3756 bool_Bool is_retry = false0, is_back = false0;
3757
3758 NSLOG(netsurf, INFO, "bw:%p params:%p", bw, params)do { if (NSLOG_LEVEL_INFO >= NSLOG_LEVEL_VERBOSE) { static
nslog_entry_context_t _nslog_ctx = { &__nslog_category_netsurf
, NSLOG_LEVEL_INFO, "desktop/browser_window.c", sizeof("desktop/browser_window.c"
) - 1, __PRETTY_FUNCTION__, sizeof(__PRETTY_FUNCTION__) - 1, 3758
, }; nslog__log(&_nslog_ctx, "bw:%p params:%p", bw, params
); } } while(0)
;
3759
3760 assert(params->post_multipart != NULL)((params->post_multipart != ((void*)0)) ? (void) (0) : __assert_fail
("params->post_multipart != NULL", "desktop/browser_window.c"
, 3760, __extension__ __PRETTY_FUNCTION__))
;
3761
3762 is_retry = fetch_multipart_data_find(params->post_multipart, "retry") != NULL((void*)0);
3763 is_back = fetch_multipart_data_find(params->post_multipart, "back") != NULL((void*)0);
3764
3765 if (is_back) {
3766 /* do a rough-and-ready nav to the old 'current'
3767 * parameters, with any post data stripped away
3768 */
3769 return browser_window__reload_current_parameters(bw);
3770 }
3771
3772 if (is_retry) {
3773 /* Finally navigate to the original loading parameters */
3774 bw->internal_nav = false0;
3775 return navigate_internal_real(bw, &bw->loading_parameters);
3776 }
3777
3778 return navigate_internal_real(bw, params);
3779}
3780
3781
3782/**
3783 * dispatch to internal query handlers or normal navigation
3784 *
3785 * Here we determine if we're navigating to an internal query URI and
3786 * if so, what we need to do about it.
3787 *
3788 * \note these check must match those in is_internal_navigate_url()
3789 *
3790 * If we're not, then we just move on to the real navigate.
3791 */
3792nserror
3793browser_window__navigate_internal(struct browser_window *bw,
3794 struct browser_fetch_parameters *params)
3795{
3796 lwc_string *scheme, *path;
3797
3798 /* All our special URIs are in the about: scheme */
3799 scheme = nsurl_get_component(params->url, NSURL_SCHEME);
3800 if (scheme != corestring_lwc_about) {
3801 lwc_string_unref(scheme){ lwc_string *__lwc_s = (scheme); ((__lwc_s != ((void*)0)) ? (
void) (0) : __assert_fail ("__lwc_s != NULL", "desktop/browser_window.c"
, 3801, __extension__ __PRETTY_FUNCTION__)); __lwc_s->refcnt
--; if ((__lwc_s->refcnt == 0) || ((__lwc_s->refcnt == 1
) && (__lwc_s->insensitive == __lwc_s))) lwc_string_destroy
(__lwc_s); }
;
3802 goto normal_fetch;
3803 }
3804 lwc_string_unref(scheme){ lwc_string *__lwc_s = (scheme); ((__lwc_s != ((void*)0)) ? (
void) (0) : __assert_fail ("__lwc_s != NULL", "desktop/browser_window.c"
, 3804, __extension__ __PRETTY_FUNCTION__)); __lwc_s->refcnt
--; if ((__lwc_s->refcnt == 0) || ((__lwc_s->refcnt == 1
) && (__lwc_s->insensitive == __lwc_s))) lwc_string_destroy
(__lwc_s); }
;
3805
3806 /* Is it the auth query handler? */
3807 path = nsurl_get_component(params->url, NSURL_PATH);
3808 if (path == corestring_lwc_query_auth) {
3809 lwc_string_unref(path){ lwc_string *__lwc_s = (path); ((__lwc_s != ((void*)0)) ? (void
) (0) : __assert_fail ("__lwc_s != NULL", "desktop/browser_window.c"
, 3809, __extension__ __PRETTY_FUNCTION__)); __lwc_s->refcnt
--; if ((__lwc_s->refcnt == 0) || ((__lwc_s->refcnt == 1
) && (__lwc_s->insensitive == __lwc_s))) lwc_string_destroy
(__lwc_s); }
;
3810 return navigate_internal_query_auth(bw, params);
3811 }
3812 if (path == corestring_lwc_query_ssl) {
3813 lwc_string_unref(path){ lwc_string *__lwc_s = (path); ((__lwc_s != ((void*)0)) ? (void
) (0) : __assert_fail ("__lwc_s != NULL", "desktop/browser_window.c"
, 3813, __extension__ __PRETTY_FUNCTION__)); __lwc_s->refcnt
--; if ((__lwc_s->refcnt == 0) || ((__lwc_s->refcnt == 1
) && (__lwc_s->insensitive == __lwc_s))) lwc_string_destroy
(__lwc_s); }
;
3814 return navigate_internal_query_ssl(bw, params);
3815 }
3816 if (path == corestring_lwc_query_timeout) {
3817 lwc_string_unref(path){ lwc_string *__lwc_s = (path); ((__lwc_s != ((void*)0)) ? (void
) (0) : __assert_fail ("__lwc_s != NULL", "desktop/browser_window.c"
, 3817, __extension__ __PRETTY_FUNCTION__)); __lwc_s->refcnt
--; if ((__lwc_s->refcnt == 0) || ((__lwc_s->refcnt == 1
) && (__lwc_s->insensitive == __lwc_s))) lwc_string_destroy
(__lwc_s); }
;
3818 return navigate_internal_query_timeout(bw, params);
3819 }
3820 if (path == corestring_lwc_query_fetcherror) {
3821 lwc_string_unref(path){ lwc_string *__lwc_s = (path); ((__lwc_s != ((void*)0)) ? (void
) (0) : __assert_fail ("__lwc_s != NULL", "desktop/browser_window.c"
, 3821, __extension__ __PRETTY_FUNCTION__)); __lwc_s->refcnt
--; if ((__lwc_s->refcnt == 0) || ((__lwc_s->refcnt == 1
) && (__lwc_s->insensitive == __lwc_s))) lwc_string_destroy
(__lwc_s); }
;
3822 return navigate_internal_query_fetcherror(bw, params);
3823 }
3824 if (path != NULL((void*)0)) {
3825 lwc_string_unref(path){ lwc_string *__lwc_s = (path); ((__lwc_s != ((void*)0)) ? (void
) (0) : __assert_fail ("__lwc_s != NULL", "desktop/browser_window.c"
, 3825, __extension__ __PRETTY_FUNCTION__)); __lwc_s->refcnt
--; if ((__lwc_s->refcnt == 0) || ((__lwc_s->refcnt == 1
) && (__lwc_s->insensitive == __lwc_s))) lwc_string_destroy
(__lwc_s); }
;
3826 }
3827
3828 /* Fall through to a normal about: fetch */
3829
3830 normal_fetch:
3831 return navigate_internal_real(bw, params);
3832}
3833
3834
3835/* Exported interface, documented in netsurf/browser_window.h */
3836bool_Bool browser_window_up_available(struct browser_window *bw)
3837{
3838 bool_Bool result = false0;
3839
3840 if (bw != NULL((void*)0) && bw->current_content != NULL((void*)0)) {
3841 nsurl *parent;
3842 nserror err;
3843 err = nsurl_parent(hlcache_handle_get_url(bw->current_content),
3844 &parent);
3845 if (err == NSERROR_OK) {
3846 result = nsurl_compare(hlcache_handle_get_url(
3847 bw->current_content),
3848 parent,
3849 NSURL_COMPLETE) == false0;
3850 nsurl_unref(parent);
3851 }
3852 }
3853
3854 return result;
3855}
3856
3857
3858/* Exported interface, documented in netsurf/browser_window.h */
3859nserror browser_window_navigate_up(struct browser_window *bw, bool_Bool new_window)
3860{
3861 nsurl *current, *parent;
3862 nserror err;
3863
3864 if (bw == NULL((void*)0))
3865 return NSERROR_BAD_PARAMETER;
3866
3867 current = browser_window_access_url(bw);
3868
3869 err = nsurl_parent(current, &parent);
3870 if (err != NSERROR_OK) {
3871 return err;
3872 }
3873
3874 if (nsurl_compare(current, parent, NSURL_COMPLETE) == true1) {
3875 /* Can't go up to parent from here */
3876 nsurl_unref(parent);
3877 return NSERROR_OK;
3878 }
3879
3880 if (new_window) {
3881 err = browser_window_create(BW_CREATE_CLONE,
3882 parent, NULL((void*)0), bw, NULL((void*)0));
3883 } else {
3884 err = browser_window_navigate(bw, parent, NULL((void*)0),
3885 BW_NAVIGATE_HISTORY,
3886 NULL((void*)0), NULL((void*)0), NULL((void*)0));
3887 }
3888
3889 nsurl_unref(parent);
3890 return err;
3891}
3892
3893
3894/* Exported interface, documented in include/netsurf/browser_window.h */
3895nsurl* browser_window_access_url(const struct browser_window *bw)
3896{
3897 assert(bw != NULL)((bw != ((void*)0)) ? (void) (0) : __assert_fail ("bw != NULL"
, "desktop/browser_window.c", 3897, __extension__ __PRETTY_FUNCTION__
))
;
3898
3899 if (bw->current_content != NULL((void*)0)) {
3900 return hlcache_handle_get_url(bw->current_content);
3901
3902 } else if (bw->loading_content != NULL((void*)0)) {
3903 /* TODO: should we return this? */
3904 return hlcache_handle_get_url(bw->loading_content);
3905 }
3906
3907 return corestring_nsurl_about_blank;
3908}
3909
3910
3911/* Exported interface, documented in include/netsurf/browser_window.h */
3912nserror
3913browser_window_get_url(struct browser_window *bw, bool_Bool fragment,nsurl** url_out)
3914{
3915 nserror err;
3916 nsurl *url;
3917
3918 assert(bw != NULL)((bw != ((void*)0)) ? (void) (0) : __assert_fail ("bw != NULL"
, "desktop/browser_window.c", 3918, __extension__ __PRETTY_FUNCTION__
))
;
3919
3920 if (!fragment || bw->frag_id == NULL((void*)0) || bw->loading_content != NULL((void*)0)) {
3921 /* If there's a loading content, then the bw->frag_id will have
3922 * been trampled, possibly with a new frag_id, but we will
3923 * still be returning the current URL, so in this edge case
3924 * we just drop any fragment. */
3925 url = nsurl_ref(browser_window_access_url(bw));
3926
3927 } else {
3928 err = nsurl_refragment(browser_window_access_url(bw),
3929 bw->frag_id, &url);
3930 if (err != NSERROR_OK) {
3931 return err;
3932 }
3933 }
3934
3935 *url_out = url;
3936 return NSERROR_OK;
3937}
3938
3939
3940/* Exported interface, documented in netsurf/browser_window.h */
3941const char* browser_window_get_title(struct browser_window *bw)
3942{
3943 assert(bw != NULL)((bw != ((void*)0)) ? (void) (0) : __assert_fail ("bw != NULL"
, "desktop/browser_window.c", 3943, __extension__ __PRETTY_FUNCTION__
))
;
3944
3945 if (bw->current_content != NULL((void*)0)) {
3946 return content_get_title(bw->current_content);
3947 }
3948
3949 /* no content so return about:blank */
3950 return nsurl_access(corestring_nsurl_about_blank);
3951}
3952
3953
3954/* Exported interface, documented in netsurf/browser_window.h */
3955struct history * browser_window_get_history(struct browser_window *bw)
3956{
3957 assert(bw != NULL)((bw != ((void*)0)) ? (void) (0) : __assert_fail ("bw != NULL"
, "desktop/browser_window.c", 3957, __extension__ __PRETTY_FUNCTION__
))
;
3958
3959 return bw->history;
3960}
3961
3962
3963/* Exported interface, documented in netsurf/browser_window.h */
3964bool_Bool browser_window_has_content(struct browser_window *bw)
3965{
3966 assert(bw != NULL)((bw != ((void*)0)) ? (void) (0) : __assert_fail ("bw != NULL"
, "desktop/browser_window.c", 3966, __extension__ __PRETTY_FUNCTION__
))
;
3967
3968 if (bw->current_content == NULL((void*)0)) {
3969 return false0;
3970 }
3971
3972 return true1;
3973}
3974
3975
3976/* Exported interface, documented in netsurf/browser_window.h */
3977struct hlcache_handle *browser_window_get_content(struct browser_window *bw)
3978{
3979 return bw->current_content;
3980}
3981
3982
3983/* Exported interface, documented in netsurf/browser_window.h */
3984nserror browser_window_get_extents(struct browser_window *bw, bool_Bool scaled,
3985 int *width, int *height)
3986{
3987 assert(bw != NULL)((bw != ((void*)0)) ? (void) (0) : __assert_fail ("bw != NULL"
, "desktop/browser_window.c", 3987, __extension__ __PRETTY_FUNCTION__
))
;
3988
3989 if (bw->current_content == NULL((void*)0)) {
3990 *width = 0;
3991 *height = 0;
3992 return NSERROR_BAD_CONTENT;
3993 }
3994
3995 *width = content_get_width(bw->current_content);
3996 *height = content_get_height(bw->current_content);
3997
3998 if (scaled) {
3999 *width *= bw->scale;
4000 *height *= bw->scale;
4001 }
4002
4003 return NSERROR_OK;
4004}
4005
4006
4007/* exported internal interface, documented in desktop/browser_private.h */
4008nserror
4009browser_window_get_dimensions(struct browser_window *bw,
4010 int *width,
4011 int *height)
4012{
4013 nserror res;
4014 assert(bw)((bw) ? (void) (0) : __assert_fail ("bw", "desktop/browser_window.c"
, 4014, __extension__ __PRETTY_FUNCTION__))
;
4015
4016 if (bw->window == NULL((void*)0)) {
4017 /* Core managed browser window */
4018 *width = bw->width;
4019 *height = bw->height;
4020 res = NSERROR_OK;
4021 } else {
4022 /* Front end window */
4023 res = guit->window->get_dimensions(bw->window, width, height);
4024 }
4025 return res;
4026}
4027
4028
4029/* Exported interface, documented in netsurf/browser_window.h */
4030void
4031browser_window_set_dimensions(struct browser_window *bw, int width, int height)
4032{
4033 assert(bw)((bw) ? (void) (0) : __assert_fail ("bw", "desktop/browser_window.c"
, 4033, __extension__ __PRETTY_FUNCTION__))
;
4034
4035 if (bw->window == NULL((void*)0)) {
4036 /* Core managed browser window */
4037 bw->width = width;
4038 bw->height = height;
4039 } else {
4040 NSLOG(netsurf, INFO,do { if (NSLOG_LEVEL_INFO >= NSLOG_LEVEL_VERBOSE) { static
nslog_entry_context_t _nslog_ctx = { &__nslog_category_netsurf
, NSLOG_LEVEL_INFO, "desktop/browser_window.c", sizeof("desktop/browser_window.c"
) - 1, __PRETTY_FUNCTION__, sizeof(__PRETTY_FUNCTION__) - 1, 4041
, }; nslog__log(&_nslog_ctx, "Asked to set dimensions of front end window."
); } } while(0)
4041 "Asked to set dimensions of front end window.")do { if (NSLOG_LEVEL_INFO >= NSLOG_LEVEL_VERBOSE) { static
nslog_entry_context_t _nslog_ctx = { &__nslog_category_netsurf
, NSLOG_LEVEL_INFO, "desktop/browser_window.c", sizeof("desktop/browser_window.c"
) - 1, __PRETTY_FUNCTION__, sizeof(__PRETTY_FUNCTION__) - 1, 4041
, }; nslog__log(&_nslog_ctx, "Asked to set dimensions of front end window."
); } } while(0)
;
4042 assert(0)((0) ? (void) (0) : __assert_fail ("0", "desktop/browser_window.c"
, 4042, __extension__ __PRETTY_FUNCTION__))
;
4043 }
4044}
4045
4046
4047/* Exported interface, documented in browser/browser_private.h */
4048nserror
4049browser_window_invalidate_rect(struct browser_window *bw, struct rect *rect)
4050{
4051 int pos_x;
4052 int pos_y;
4053 struct browser_window *top = bw;
4054
4055 assert(bw)((bw) ? (void) (0) : __assert_fail ("bw", "desktop/browser_window.c"
, 4055, __extension__ __PRETTY_FUNCTION__))
;
4056
4057 if (bw->window == NULL((void*)0)) {
4058 /* Core managed browser window */
4059 browser_window_get_position(bw, true1, &pos_x, &pos_y);
4060
4061 top = browser_window_get_root(bw);
4062
4063 rect->x0 += pos_x / bw->scale;
4064 rect->y0 += pos_y / bw->scale;
4065 rect->x1 += pos_x / bw->scale;
4066 rect->y1 += pos_y / bw->scale;
4067 }
4068
4069 rect->x0 *= top->scale;
4070 rect->y0 *= top->scale;
4071 rect->x1 *= top->scale;
4072 rect->y1 *= top->scale;
4073
4074 return guit->window->invalidate(top->window, rect);
4075}
4076
4077
4078/* Exported interface, documented in netsurf/browser_window.h */
4079void browser_window_stop(struct browser_window *bw)
4080{
4081 int children, index;
4082
4083 if (bw->loading_content != NULL((void*)0)) {
4084 hlcache_handle_abort(bw->loading_content);
4085 hlcache_handle_release(bw->loading_content);
4086 bw->loading_content = NULL((void*)0);
4087 }
4088
4089 if (bw->current_content != NULL((void*)0) &&
4090 content_get_status(bw->current_content) != CONTENT_STATUS_DONE) {
4091 nserror error;
4092 assert(content_get_status(bw->current_content) ==((content_get_status(bw->current_content) == CONTENT_STATUS_READY
) ? (void) (0) : __assert_fail ("content_get_status(bw->current_content) == CONTENT_STATUS_READY"
, "desktop/browser_window.c", 4093, __extension__ __PRETTY_FUNCTION__
))
4093 CONTENT_STATUS_READY)((content_get_status(bw->current_content) == CONTENT_STATUS_READY
) ? (void) (0) : __assert_fail ("content_get_status(bw->current_content) == CONTENT_STATUS_READY"
, "desktop/browser_window.c", 4093, __extension__ __PRETTY_FUNCTION__
))
;
4094 error = hlcache_handle_abort(bw->current_content);
4095 assert(error == NSERROR_OK)((error == NSERROR_OK) ? (void) (0) : __assert_fail ("error == NSERROR_OK"
, "desktop/browser_window.c", 4095, __extension__ __PRETTY_FUNCTION__
))
;
4096 }
4097
4098 guit->misc->schedule(-1, browser_window_refresh, bw);
4099
4100 if (bw->children) {
4101 children = bw->rows * bw->cols;
4102 for (index = 0; index < children; index++)
4103 browser_window_stop(&bw->children[index]);
4104 }
4105 if (bw->iframes) {
4106 children = bw->iframe_count;
4107 for (index = 0; index < children; index++)
4108 browser_window_stop(&bw->iframes[index]);
4109 }
4110
4111 if (bw->current_content != NULL((void*)0)) {
4112 browser_window_refresh_url_bar(bw);
4113 }
4114
4115 browser_window_stop_throbber(bw);
4116}
4117
4118
4119/* Exported interface, documented in netsurf/browser_window.h */
4120nserror browser_window_reload(struct browser_window *bw, bool_Bool all)
4121{
4122 hlcache_handle *c;
4123 unsigned int i;
4124 struct nsurl *reload_url;
4125
4126 if ((bw->current_content) == NULL((void*)0) ||
4127 (bw->loading_content) != NULL((void*)0)) {
4128 return NSERROR_INVALID;
4129 }
4130
4131 if (all && content_get_type(bw->current_content) == CONTENT_HTML) {
4132 struct html_stylesheet *sheets;
4133 struct content_html_object *object;
4134 unsigned int count;
4135
4136 c = bw->current_content;
4137
4138 /* invalidate objects */
4139 object = html_get_objects(c, &count);
4140
4141 for (; object != NULL((void*)0); object = object->next) {
4142 if (object->content != NULL((void*)0))
4143 content_invalidate_reuse_data(object->content);
4144 }
4145
4146 /* invalidate stylesheets */
4147 sheets = html_get_stylesheets(c, &count);
4148
4149 for (i = STYLESHEET_START4; i != count; i++) {
4150 if (sheets[i].sheet != NULL((void*)0)) {
4151 content_invalidate_reuse_data(sheets[i].sheet);
4152 }
4153 }
4154 }
4155
4156 content_invalidate_reuse_data(bw->current_content);
4157
4158 reload_url = hlcache_handle_get_url(bw->current_content);
4159
4160 return browser_window_navigate(bw,
4161 reload_url,
4162 NULL((void*)0),
4163 BW_NAVIGATE_NONE,
4164 NULL((void*)0),
4165 NULL((void*)0),
4166 NULL((void*)0));
4167}
4168
4169
4170/* Exported interface, documented in netsurf/browser_window.h */
4171void browser_window_set_status(struct browser_window *bw, const char *text)
4172{
4173 int text_len;
4174 /* find topmost window */
4175 while (bw->parent)
4176 bw = bw->parent;
4177
4178 if ((bw->status.text != NULL((void*)0)) &&
4179 (strcmp(text, bw->status.text) == 0)) {
4180 /* status text is unchanged */
4181 bw->status.match++;
4182 return;
4183 }
4184
4185 /* status text is changed */
4186
4187 text_len = strlen(text);
4188
4189 if ((bw->status.text == NULL((void*)0)) || (bw->status.text_len < text_len)) {
4190 /* no current string allocation or it is not long enough */
4191 free(bw->status.text);
4192 bw->status.text = strdup(text);
4193 bw->status.text_len = text_len;
4194 } else {
4195 /* current allocation has enough space */
4196 memcpy(bw->status.text, text, text_len + 1);
4197 }
4198
4199 bw->status.miss++;
4200 guit->window->set_status(bw->window, bw->status.text);
4201}
4202
4203
4204/* Exported interface, documented in netsurf/browser_window.h */
4205void browser_window_set_pointer(struct browser_window *bw,
4206 browser_pointer_shape shape)
4207{
4208 struct browser_window *root = browser_window_get_root(bw);
4209 gui_pointer_shape gui_shape;
4210 bool_Bool loading;
4211 uint64_t ms_now;
4212
4213 assert(root)((root) ? (void) (0) : __assert_fail ("root", "desktop/browser_window.c"
, 4213, __extension__ __PRETTY_FUNCTION__))
;
4214 assert(root->window)((root->window) ? (void) (0) : __assert_fail ("root->window"
, "desktop/browser_window.c", 4214, __extension__ __PRETTY_FUNCTION__
))
;
4215
4216 loading = ((bw->loading_content != NULL((void*)0)) ||
4217 ((bw->current_content != NULL((void*)0)) &&
4218 (content_get_status(bw->current_content) == CONTENT_STATUS_READY)));
4219
4220 nsu_getmonotonic_ms(&ms_now);
4221
4222 if (loading && ((ms_now - bw->last_action) < 1000)) {
4223 /* If loading and less than 1 second since last link followed,
4224 * force progress indicator pointer */
4225 gui_shape = GUI_POINTER_PROGRESS;
4226
4227 } else if (shape == BROWSER_POINTER_AUTO) {
4228 /* Up to browser window to decide */
4229 if (loading) {
4230 gui_shape = GUI_POINTER_PROGRESS;
4231 } else {
4232 gui_shape = GUI_POINTER_DEFAULT;
4233 }
4234
4235 } else {
4236 /* Use what we were told */
4237 gui_shape = (gui_pointer_shape)shape;
4238 }
4239
4240 guit->window->set_pointer(root->window, gui_shape);
4241}
4242
4243
4244/* exported function documented in netsurf/browser_window.h */
4245nserror browser_window_schedule_reformat(struct browser_window *bw)
4246{
4247 if (bw->window == NULL((void*)0)) {
4248 return NSERROR_BAD_PARAMETER;
4249 }
4250
4251 return guit->misc->schedule(0, scheduled_reformat, bw);
4252}
4253
4254
4255/* exported function documented in netsurf/browser_window.h */
4256void
4257browser_window_reformat(struct browser_window *bw,
4258 bool_Bool background,
4259 int width,
4260 int height)
4261{
4262 hlcache_handle *c = bw->current_content;
4263
4264 if (c == NULL((void*)0))
4265 return;
4266
4267 if (bw->browser_window_type != BROWSER_WINDOW_IFRAME) {
4268 /* Iframe dimensions are already scaled in parent's layout */
4269 width /= bw->scale;
4270 height /= bw->scale;
4271 }
4272
4273 if (bw->window == NULL((void*)0)) {
4274 /* Core managed browser window; subtract scrollbar width */
4275 width -= bw->scroll_y ? SCROLLBAR_WIDTH16 : 0;
4276 height -= bw->scroll_x ? SCROLLBAR_WIDTH16 : 0;
4277
4278 width = width > 0 ? width : 0;
4279 height = height > 0 ? height : 0;
4280 }
4281
4282 content_reformat(c, background, width, height);
4283}
4284
4285
4286/* exported interface documented in netsurf/browser_window.h */
4287nserror
4288browser_window_set_scale(struct browser_window *bw, float scale, bool_Bool absolute)
4289{
4290 nserror res;
4291
4292 /* get top browser window */
4293 while (bw->parent) {
4294 bw = bw->parent;
4295 }
4296
4297 if (!absolute) {
4298 /* snap small values around 1.0 */
4299 if ((scale + bw->scale) > (1.01 - scale) &&
4300 (scale + bw->scale) < (0.99 + scale)) {
4301 scale = 1.0;
4302 } else {
4303 scale += bw->scale;
4304 }
4305 }
4306
4307 /* clamp range between 0.1 and 10 (10% and 1000%) */
4308 if (scale < SCALE_MINIMUM0.2) {
4309 scale = SCALE_MINIMUM0.2;
4310 } else if (scale > SCALE_MAXIMUM10.0) {
4311 scale = SCALE_MAXIMUM10.0;
4312 }
4313
4314 res = browser_window_set_scale_internal(bw, scale);
4315 if (res == NSERROR_OK) {
4316 browser_window_recalculate_frameset(bw);
4317 }
4318
4319 return res;
4320}
4321
4322
4323/* exported interface documented in netsurf/browser_window.h */
4324float browser_window_get_scale(struct browser_window *bw)
4325{
4326 if (bw == NULL((void*)0)) {
4327 return 1.0;
4328 }
4329
4330 return bw->scale;
4331}
4332
4333
4334/* exported interface documented in netsurf/browser_window.h */
4335struct browser_window *
4336browser_window_find_target(struct browser_window *bw,
4337 const char *target,
4338 browser_mouse_state mouse)
4339{
4340 struct browser_window *bw_target;
4341 struct browser_window *top;
4342 hlcache_handle *c;
4343 int rdepth;
4344 nserror error;
4345 int flags = BW_CREATE_HISTORY | BW_CREATE_CLONE;
4346
4347 if (nsoption_bool(foreground_new)(nsoptions[NSOPTION_foreground_new].value.b))
4348 flags |= BW_CREATE_FOREGROUND;
4349
4350 /* use the base target if we don't have one */
4351 c = bw->current_content;
4352 if (target == NULL((void*)0) &&
4353 c != NULL((void*)0) &&
4354 content_get_type(c) == CONTENT_HTML) {
4355 target = html_get_base_target(c);
4356 }
4357 if (target == NULL((void*)0)) {
4358 target = "_self";
4359 }
4360
4361 /* allow the simple case of target="_blank" to be ignored if requested
4362 */
4363 if ((!(mouse & BROWSER_MOUSE_CLICK_2)) &&
4364 (!((mouse & BROWSER_MOUSE_CLICK_2) &&
4365 (mouse & BROWSER_MOUSE_MOD_2))) &&
4366 (!nsoption_bool(target_blank)(nsoptions[NSOPTION_target_blank].value.b))) {
4367 /* not a mouse button 2 click
4368 * not a mouse button 1 click with ctrl pressed
4369 * configured to ignore target="_blank" */
4370 if (!strcasecmp(target, "_blank"))
4371 return bw;
4372 }
4373
4374 /* handle reserved keywords */
4375 if (((nsoption_bool(button_2_tab)(nsoptions[NSOPTION_button_2_tab].value.b)) &&
4376 (mouse & BROWSER_MOUSE_CLICK_2))||
4377 ((!nsoption_bool(button_2_tab)(nsoptions[NSOPTION_button_2_tab].value.b)) &&
4378 ((mouse & BROWSER_MOUSE_CLICK_1) &&
4379 (mouse & BROWSER_MOUSE_MOD_2))) ||
4380 ((nsoption_bool(button_2_tab)(nsoptions[NSOPTION_button_2_tab].value.b)) &&
4381 (!strcasecmp(target, "_blank")))) {
4382 /* open in new tab if:
4383 * - button_2 opens in new tab and button_2 was pressed
4384 * OR
4385 * - button_2 doesn't open in new tabs and button_1 was
4386 * pressed with ctrl held
4387 * OR
4388 * - button_2 opens in new tab and the link target is "_blank"
4389 */
4390 flags |= BW_CREATE_TAB;
4391 error = browser_window_create(flags, NULL((void*)0), NULL((void*)0), bw, &bw_target);
4392 if (error != NSERROR_OK) {
4393 return bw;
4394 }
4395 return bw_target;
4396 } else if (((!nsoption_bool(button_2_tab)(nsoptions[NSOPTION_button_2_tab].value.b)) &&
4397 (mouse & BROWSER_MOUSE_CLICK_2)) ||
4398 ((nsoption_bool(button_2_tab)(nsoptions[NSOPTION_button_2_tab].value.b)) &&
4399 ((mouse & BROWSER_MOUSE_CLICK_1) &&
4400 (mouse & BROWSER_MOUSE_MOD_2))) ||
4401 ((!nsoption_bool(button_2_tab)(nsoptions[NSOPTION_button_2_tab].value.b)) &&
4402 (!strcasecmp(target, "_blank")))) {
4403 /* open in new window if:
4404 * - button_2 doesn't open in new tabs and button_2 was pressed
4405 * OR
4406 * - button_2 opens in new tab and button_1 was pressed with
4407 * ctrl held
4408 * OR
4409 * - button_2 doesn't open in new tabs and the link target is
4410 * "_blank"
4411 */
4412 error = browser_window_create(flags, NULL((void*)0), NULL((void*)0), bw, &bw_target);
4413 if (error != NSERROR_OK) {
4414 return bw;
4415 }
4416 return bw_target;
4417 } else if (!strcasecmp(target, "_self")) {
4418 return bw;
4419 } else if (!strcasecmp(target, "_parent")) {
4420 if (bw->parent)
4421 return bw->parent;
4422 return bw;
4423 } else if (!strcasecmp(target, "_top")) {
4424 while (bw->parent)
4425 bw = bw->parent;
4426 return bw;
4427 }
4428
4429 /* find frame according to B.8, ie using the following priorities:
4430 *
4431 * 1) current frame
4432 * 2) closest to front
4433 */
4434 rdepth = -1;
4435 bw_target = NULL((void*)0);
4436 for (top = bw; top->parent; top = top->parent);
4437 browser_window_find_target_internal(top, target, 0, bw, &rdepth,
4438 &bw_target);
4439 if (bw_target)
4440 return bw_target;
4441
4442 /* we require a new window using the target name */
4443 if (!nsoption_bool(target_blank)(nsoptions[NSOPTION_target_blank].value.b))
4444 return bw;
4445
4446 error = browser_window_create(flags, NULL((void*)0), NULL((void*)0), bw, &bw_target);
4447 if (error != NSERROR_OK) {
4448 return bw;
4449 }
4450
4451 /* frame names should begin with an alphabetic character (a-z,A-Z),
4452 * however in practice you get things such as '_new' and '2left'. The
4453 * only real effect this has is when giving out names as it can be
4454 * assumed that an author intended '_new' to create a new nameless
4455 * window (ie '_blank') whereas in the case of '2left' the intention
4456 * was for a new named window. As such we merely special case windows
4457 * that begin with an underscore. */
4458 if (target[0] != '_') {
4459 bw_target->name = strdup(target);
4460 }
4461 return bw_target;
4462}
4463
4464
4465/* exported interface documented in netsurf/browser_window.h */
4466void
4467browser_window_mouse_track(struct browser_window *bw,
4468 browser_mouse_state mouse,
4469 int x, int y)
4470{
4471 browser_window_mouse_track_internal(bw,
4472 mouse,
4473 x / bw->scale,
4474 y / bw->scale);
4475}
4476
4477/* exported interface documented in netsurf/browser_window.h */
4478void
4479browser_window_mouse_click(struct browser_window *bw,
4480 browser_mouse_state mouse,
4481 int x, int y)
4482{
4483 browser_window_mouse_click_internal(bw,
4484 mouse,
4485 x / bw->scale,
4486 y / bw->scale);
4487}
4488
4489
4490/* exported interface documented in netsurf/browser_window.h */
4491void browser_window_page_drag_start(struct browser_window *bw, int x, int y)
4492{
4493 assert(bw != NULL)((bw != ((void*)0)) ? (void) (0) : __assert_fail ("bw != NULL"
, "desktop/browser_window.c", 4493, __extension__ __PRETTY_FUNCTION__
))
;
4494
4495 browser_window_set_drag_type(bw, DRAGGING_PAGE_SCROLL, NULL((void*)0));
4496
4497 bw->drag.start_x = x;
4498 bw->drag.start_y = y;
4499
4500 if (bw->window != NULL((void*)0)) {
4501 /* Front end window */
4502 guit->window->get_scroll(bw->window,
4503 &bw->drag.start_scroll_x,
4504 &bw->drag.start_scroll_y);
4505
4506 guit->window->event(bw->window, GW_EVENT_SCROLL_START);
4507 } else {
4508 /* Core managed browser window */
4509 bw->drag.start_scroll_x = scrollbar_get_offset(bw->scroll_x);
4510 bw->drag.start_scroll_y = scrollbar_get_offset(bw->scroll_y);
4511 }
4512}
4513
4514
4515/* exported interface documented in netsurf/browser_window.h */
4516bool_Bool browser_window_back_available(struct browser_window *bw)
4517{
4518 if (bw != NULL((void*)0) && bw->internal_nav) {
4519 /* Internal nav, back is possible */
4520 return true1;
4521 }
4522 return (bw && bw->history && browser_window_history_back_available(bw));
4523}
4524
4525
4526/* exported interface documented in netsurf/browser_window.h */
4527bool_Bool browser_window_forward_available(struct browser_window *bw)
4528{
4529 return (bw && bw->history && browser_window_history_forward_available(bw));
4530}
4531
4532/* exported interface documented in netsurf/browser_window.h */
4533bool_Bool browser_window_reload_available(struct browser_window *bw)
4534{
4535 return (bw && bw->current_content && !bw->loading_content);
4536}
4537
4538
4539/* exported interface documented in netsurf/browser_window.h */
4540bool_Bool browser_window_stop_available(struct browser_window *bw)
4541{
4542 return (bw && (bw->loading_content ||
4543 (bw->current_content &&
4544 (content_get_status(bw->current_content) !=
4545 CONTENT_STATUS_DONE))));
4546}
4547
4548/* exported interface documented in netsurf/browser_window.h */
4549bool_Bool
4550browser_window_exec(struct browser_window *bw, const char *src, size_t srclen)
4551{
4552 assert(bw != NULL)((bw != ((void*)0)) ? (void) (0) : __assert_fail ("bw != NULL"
, "desktop/browser_window.c", 4552, __extension__ __PRETTY_FUNCTION__
))
;
4553
4554 if (!bw->current_content) {
4555 NSLOG(netsurf, DEEPDEBUG, "Unable to exec, no content")do { if (NSLOG_LEVEL_DEEPDEBUG >= NSLOG_LEVEL_VERBOSE) { static
nslog_entry_context_t _nslog_ctx = { &__nslog_category_netsurf
, NSLOG_LEVEL_DEEPDEBUG, "desktop/browser_window.c", sizeof("desktop/browser_window.c"
) - 1, __PRETTY_FUNCTION__, sizeof(__PRETTY_FUNCTION__) - 1, 4555
, }; nslog__log(&_nslog_ctx, "Unable to exec, no content"
); } } while(0)
;
4556 return false0;
4557 }
4558
4559 if (content_get_status(bw->current_content) != CONTENT_STATUS_DONE) {
4560 NSLOG(netsurf, DEEPDEBUG, "Unable to exec, content not done")do { if (NSLOG_LEVEL_DEEPDEBUG >= NSLOG_LEVEL_VERBOSE) { static
nslog_entry_context_t _nslog_ctx = { &__nslog_category_netsurf
, NSLOG_LEVEL_DEEPDEBUG, "desktop/browser_window.c", sizeof("desktop/browser_window.c"
) - 1, __PRETTY_FUNCTION__, sizeof(__PRETTY_FUNCTION__) - 1, 4560
, }; nslog__log(&_nslog_ctx, "Unable to exec, content not done"
); } } while(0)
;
4561 return false0;
4562 }
4563
4564 /* Okay it should be safe, forward the request through to the content
4565 * itself. Only HTML contents currently support executing code
4566 */
4567 return content_exec(bw->current_content, src, srclen);
4568}
4569
4570
4571/* exported interface documented in browser_window.h */
4572nserror
4573browser_window_console_log(struct browser_window *bw,
4574 browser_window_console_source src,
4575 const char *msg,
4576 size_t msglen,
4577 browser_window_console_flags flags)
4578{
4579 browser_window_console_flags log_level = flags & BW_CS_FLAG_LEVEL_MASK;
4580 struct browser_window *root = browser_window_get_root(bw);
4581
4582 assert(msg != NULL)((msg != ((void*)0)) ? (void) (0) : __assert_fail ("msg != NULL"
, "desktop/browser_window.c", 4582, __extension__ __PRETTY_FUNCTION__
))
;
4583 /* We don't assert msglen > 0, if someone wants to log a real empty
4584 * string then we won't stop them. It does sometimes happen from
4585 * JavaScript for example.
4586 */
4587
4588 /* bw is the target of the log, but root is where we log it */
4589
4590 NSLOG(netsurf, DEEPDEBUG, "Logging message in %p targetted at %p", root, bw)do { if (NSLOG_LEVEL_DEEPDEBUG >= NSLOG_LEVEL_VERBOSE) { static
nslog_entry_context_t _nslog_ctx = { &__nslog_category_netsurf
, NSLOG_LEVEL_DEEPDEBUG, "desktop/browser_window.c", sizeof("desktop/browser_window.c"
) - 1, __PRETTY_FUNCTION__, sizeof(__PRETTY_FUNCTION__) - 1, 4590
, }; nslog__log(&_nslog_ctx, "Logging message in %p targetted at %p"
, root, bw); } } while(0)
;
4591 NSLOG(netsurf, DEEPDEBUG, "Log came from %s",do { if (NSLOG_LEVEL_DEEPDEBUG >= NSLOG_LEVEL_VERBOSE) { static
nslog_entry_context_t _nslog_ctx = { &__nslog_category_netsurf
, NSLOG_LEVEL_DEEPDEBUG, "desktop/browser_window.c", sizeof("desktop/browser_window.c"
) - 1, __PRETTY_FUNCTION__, sizeof(__PRETTY_FUNCTION__) - 1, 4595
, }; nslog__log(&_nslog_ctx, "Log came from %s", ((src ==
BW_CS_INPUT) ? "user input" : (src == BW_CS_SCRIPT_ERROR) ? "script error"
: (src == BW_CS_SCRIPT_CONSOLE) ? "script console" : "unknown input location"
)); } } while(0)
4592 ((src == BW_CS_INPUT) ? "user input" :do { if (NSLOG_LEVEL_DEEPDEBUG >= NSLOG_LEVEL_VERBOSE) { static
nslog_entry_context_t _nslog_ctx = { &__nslog_category_netsurf
, NSLOG_LEVEL_DEEPDEBUG, "desktop/browser_window.c", sizeof("desktop/browser_window.c"
) - 1, __PRETTY_FUNCTION__, sizeof(__PRETTY_FUNCTION__) - 1, 4595
, }; nslog__log(&_nslog_ctx, "Log came from %s", ((src ==
BW_CS_INPUT) ? "user input" : (src == BW_CS_SCRIPT_ERROR) ? "script error"
: (src == BW_CS_SCRIPT_CONSOLE) ? "script console" : "unknown input location"
)); } } while(0)
4593 (src == BW_CS_SCRIPT_ERROR) ? "script error" :do { if (NSLOG_LEVEL_DEEPDEBUG >= NSLOG_LEVEL_VERBOSE) { static
nslog_entry_context_t _nslog_ctx = { &__nslog_category_netsurf
, NSLOG_LEVEL_DEEPDEBUG, "desktop/browser_window.c", sizeof("desktop/browser_window.c"
) - 1, __PRETTY_FUNCTION__, sizeof(__PRETTY_FUNCTION__) - 1, 4595
, }; nslog__log(&_nslog_ctx, "Log came from %s", ((src ==
BW_CS_INPUT) ? "user input" : (src == BW_CS_SCRIPT_ERROR) ? "script error"
: (src == BW_CS_SCRIPT_CONSOLE) ? "script console" : "unknown input location"
)); } } while(0)
4594 (src == BW_CS_SCRIPT_CONSOLE) ? "script console" :do { if (NSLOG_LEVEL_DEEPDEBUG >= NSLOG_LEVEL_VERBOSE) { static
nslog_entry_context_t _nslog_ctx = { &__nslog_category_netsurf
, NSLOG_LEVEL_DEEPDEBUG, "desktop/browser_window.c", sizeof("desktop/browser_window.c"
) - 1, __PRETTY_FUNCTION__, sizeof(__PRETTY_FUNCTION__) - 1, 4595
, }; nslog__log(&_nslog_ctx, "Log came from %s", ((src ==
BW_CS_INPUT) ? "user input" : (src == BW_CS_SCRIPT_ERROR) ? "script error"
: (src == BW_CS_SCRIPT_CONSOLE) ? "script console" : "unknown input location"
)); } } while(0)
4595 "unknown input location"))do { if (NSLOG_LEVEL_DEEPDEBUG >= NSLOG_LEVEL_VERBOSE) { static
nslog_entry_context_t _nslog_ctx = { &__nslog_category_netsurf
, NSLOG_LEVEL_DEEPDEBUG, "desktop/browser_window.c", sizeof("desktop/browser_window.c"
) - 1, __PRETTY_FUNCTION__, sizeof(__PRETTY_FUNCTION__) - 1, 4595
, }; nslog__log(&_nslog_ctx, "Log came from %s", ((src ==
BW_CS_INPUT) ? "user input" : (src == BW_CS_SCRIPT_ERROR) ? "script error"
: (src == BW_CS_SCRIPT_CONSOLE) ? "script console" : "unknown input location"
)); } } while(0)
;
4596
4597 switch (log_level) {
4598 case BW_CS_FLAG_LEVEL_DEBUG:
4599 NSLOG(netsurf, DEBUG, "%.*s", (int)msglen, msg)do { if (NSLOG_LEVEL_DEBUG >= NSLOG_LEVEL_VERBOSE) { static
nslog_entry_context_t _nslog_ctx = { &__nslog_category_netsurf
, NSLOG_LEVEL_DEBUG, "desktop/browser_window.c", sizeof("desktop/browser_window.c"
) - 1, __PRETTY_FUNCTION__, sizeof(__PRETTY_FUNCTION__) - 1, 4599
, }; nslog__log(&_nslog_ctx, "%.*s", (int)msglen, msg); }
} while(0)
;
4600 break;
4601 case BW_CS_FLAG_LEVEL_LOG:
4602 NSLOG(netsurf, VERBOSE, "%.*s", (int)msglen, msg)do { if (NSLOG_LEVEL_VERBOSE >= NSLOG_LEVEL_VERBOSE) { static
nslog_entry_context_t _nslog_ctx = { &__nslog_category_netsurf
, NSLOG_LEVEL_VERBOSE, "desktop/browser_window.c", sizeof("desktop/browser_window.c"
) - 1, __PRETTY_FUNCTION__, sizeof(__PRETTY_FUNCTION__) - 1, 4602
, }; nslog__log(&_nslog_ctx, "%.*s", (int)msglen, msg); }
} while(0)
;
4603 break;
4604 case BW_CS_FLAG_LEVEL_INFO:
4605 NSLOG(netsurf, INFO, "%.*s", (int)msglen, msg)do { if (NSLOG_LEVEL_INFO >= NSLOG_LEVEL_VERBOSE) { static
nslog_entry_context_t _nslog_ctx = { &__nslog_category_netsurf
, NSLOG_LEVEL_INFO, "desktop/browser_window.c", sizeof("desktop/browser_window.c"
) - 1, __PRETTY_FUNCTION__, sizeof(__PRETTY_FUNCTION__) - 1, 4605
, }; nslog__log(&_nslog_ctx, "%.*s", (int)msglen, msg); }
} while(0)
;
4606 break;
4607 case BW_CS_FLAG_LEVEL_WARN:
4608 NSLOG(netsurf, WARNING, "%.*s", (int)msglen, msg)do { if (NSLOG_LEVEL_WARNING >= NSLOG_LEVEL_VERBOSE) { static
nslog_entry_context_t _nslog_ctx = { &__nslog_category_netsurf
, NSLOG_LEVEL_WARNING, "desktop/browser_window.c", sizeof("desktop/browser_window.c"
) - 1, __PRETTY_FUNCTION__, sizeof(__PRETTY_FUNCTION__) - 1, 4608
, }; nslog__log(&_nslog_ctx, "%.*s", (int)msglen, msg); }
} while(0)
;
4609 break;
4610 case BW_CS_FLAG_LEVEL_ERROR:
4611 NSLOG(netsurf, ERROR, "%.*s", (int)msglen, msg)do { if (NSLOG_LEVEL_ERROR >= NSLOG_LEVEL_VERBOSE) { static
nslog_entry_context_t _nslog_ctx = { &__nslog_category_netsurf
, NSLOG_LEVEL_ERROR, "desktop/browser_window.c", sizeof("desktop/browser_window.c"
) - 1, __PRETTY_FUNCTION__, sizeof(__PRETTY_FUNCTION__) - 1, 4611
, }; nslog__log(&_nslog_ctx, "%.*s", (int)msglen, msg); }
} while(0)
;
4612 break;
4613 default:
4614 /* Unreachable */
4615 break;
4616 }
4617
4618 guit->window->console_log(root->window, src, msg, msglen, flags);
4619
4620 return NSERROR_OK;
4621}
4622
4623
4624/* Exported interface, documented in browser_private.h */
4625nserror
4626browser_window__reload_current_parameters(struct browser_window *bw)
4627{
4628 assert(bw != NULL)((bw != ((void*)0)) ? (void) (0) : __assert_fail ("bw != NULL"
, "desktop/browser_window.c", 4628, __extension__ __PRETTY_FUNCTION__
))
;
4629
4630 if (bw->current_parameters.post_urlenc != NULL((void*)0)) {
4631 free(bw->current_parameters.post_urlenc);
4632 bw->current_parameters.post_urlenc = NULL((void*)0);
4633 }
4634
4635 if (bw->current_parameters.post_multipart != NULL((void*)0)) {
4636 fetch_multipart_data_destroy(bw->current_parameters.post_multipart);
4637 bw->current_parameters.post_multipart = NULL((void*)0);
4638 }
4639
4640 if (bw->current_parameters.url == NULL((void*)0)) {
4641 /* We have never navigated so go to about:blank */
4642 bw->current_parameters.url = nsurl_ref(corestring_nsurl_about_blank);
4643 }
4644
4645 bw->current_parameters.flags &= ~BW_NAVIGATE_HISTORY;
4646 bw->internal_nav = false0;
4647
4648 browser_window__free_fetch_parameters(&bw->loading_parameters);
4649 memcpy(&bw->loading_parameters, &bw->current_parameters, sizeof(bw->loading_parameters));
4650 memset(&bw->current_parameters, 0, sizeof(bw->current_parameters));
4651 return browser_window__navigate_internal(bw, &bw->loading_parameters);
4652}
4653
4654/* Exported interface, documented in browser_window.h */
4655browser_window_page_info_state browser_window_get_page_info_state(
4656 const struct browser_window *bw)
4657{
4658 lwc_string *scheme;
4659 bool_Bool match;
4660
4661 assert(bw != NULL)((bw != ((void*)0)) ? (void) (0) : __assert_fail ("bw != NULL"
, "desktop/browser_window.c", 4661, __extension__ __PRETTY_FUNCTION__
))
;
4662
4663 /* Do we have any content? If not -- UNKNOWN */
4664 if (bw->current_content == NULL((void*)0)) {
4665 return PAGE_STATE_UNKNOWN;
4666 }
4667
4668 scheme = nsurl_get_component(
4669 hlcache_handle_get_url(bw->current_content), NSURL_SCHEME);
4670
4671 /* Is this an internal scheme? */
4672 if ((lwc_string_isequal(scheme, corestring_lwc_about,((*(&match) = ((scheme) == (corestring_lwc_about))), lwc_error_ok
)
4673 &match)((*(&match) = ((scheme) == (corestring_lwc_about))), lwc_error_ok
)
== lwc_error_ok &&
4674 (match == true1)) ||
4675 (lwc_string_isequal(scheme, corestring_lwc_data,((*(&match) = ((scheme) == (corestring_lwc_data))), lwc_error_ok
)
4676 &match)((*(&match) = ((scheme) == (corestring_lwc_data))), lwc_error_ok
)
== lwc_error_ok &&
4677 (match == true1)) ||
4678 (lwc_string_isequal(scheme, corestring_lwc_resource,((*(&match) = ((scheme) == (corestring_lwc_resource))), lwc_error_ok
)
4679 &match)((*(&match) = ((scheme) == (corestring_lwc_resource))), lwc_error_ok
)
== lwc_error_ok &&
4680 (match == true1))) {
4681 lwc_string_unref(scheme){ lwc_string *__lwc_s = (scheme); ((__lwc_s != ((void*)0)) ? (
void) (0) : __assert_fail ("__lwc_s != NULL", "desktop/browser_window.c"
, 4681, __extension__ __PRETTY_FUNCTION__)); __lwc_s->refcnt
--; if ((__lwc_s->refcnt == 0) || ((__lwc_s->refcnt == 1
) && (__lwc_s->insensitive == __lwc_s))) lwc_string_destroy
(__lwc_s); }
;
4682 return PAGE_STATE_INTERNAL;
4683 }
4684
4685 /* Is this file:/// ? */
4686 if (lwc_string_isequal(scheme, corestring_lwc_file,((*(&match) = ((scheme) == (corestring_lwc_file))), lwc_error_ok
)
4687 &match)((*(&match) = ((scheme) == (corestring_lwc_file))), lwc_error_ok
)
== lwc_error_ok &&
4688 match == true1) {
4689 lwc_string_unref(scheme){ lwc_string *__lwc_s = (scheme); ((__lwc_s != ((void*)0)) ? (
void) (0) : __assert_fail ("__lwc_s != NULL", "desktop/browser_window.c"
, 4689, __extension__ __PRETTY_FUNCTION__)); __lwc_s->refcnt
--; if ((__lwc_s->refcnt == 0) || ((__lwc_s->refcnt == 1
) && (__lwc_s->insensitive == __lwc_s))) lwc_string_destroy
(__lwc_s); }
;
4690 return PAGE_STATE_LOCAL;
4691 }
4692
4693 /* If not https, from here on down that'd be insecure */
4694 if ((lwc_string_isequal(scheme, corestring_lwc_https,((*(&match) = ((scheme) == (corestring_lwc_https))), lwc_error_ok
)
4695 &match)((*(&match) = ((scheme) == (corestring_lwc_https))), lwc_error_ok
)
== lwc_error_ok &&
4696 (match == false0))) {
4697 /* Some remote content, not https, therefore insecure */
4698 lwc_string_unref(scheme){ lwc_string *__lwc_s = (scheme); ((__lwc_s != ((void*)0)) ? (
void) (0) : __assert_fail ("__lwc_s != NULL", "desktop/browser_window.c"
, 4698, __extension__ __PRETTY_FUNCTION__)); __lwc_s->refcnt
--; if ((__lwc_s->refcnt == 0) || ((__lwc_s->refcnt == 1
) && (__lwc_s->insensitive == __lwc_s))) lwc_string_destroy
(__lwc_s); }
;
4699 return PAGE_STATE_INSECURE;
4700 }
4701
4702 lwc_string_unref(scheme){ lwc_string *__lwc_s = (scheme); ((__lwc_s != ((void*)0)) ? (
void) (0) : __assert_fail ("__lwc_s != NULL", "desktop/browser_window.c"
, 4702, __extension__ __PRETTY_FUNCTION__)); __lwc_s->refcnt
--; if ((__lwc_s->refcnt == 0) || ((__lwc_s->refcnt == 1
) && (__lwc_s->insensitive == __lwc_s))) lwc_string_destroy
(__lwc_s); }
;
4703
4704 /* Did we have to override this SSL setting? */
4705 if (urldb_get_cert_permissions(hlcache_handle_get_url(bw->current_content))) {
4706 return PAGE_STATE_SECURE_OVERRIDE;
4707 }
4708
4709 /* If we've seen insecure content internally then we need to say so */
4710 if (content_saw_insecure_objects(bw->current_content)) {
4711 return PAGE_STATE_SECURE_ISSUES;
4712 }
4713
4714 /* All is well, return secure state */
4715 return PAGE_STATE_SECURE;
4716}
4717
4718/* Exported interface, documented in browser_window.h */
4719nserror
4720browser_window_get_ssl_chain(struct browser_window *bw,
4721 struct cert_chain **chain)
4722{
4723 assert(bw != NULL)((bw != ((void*)0)) ? (void) (0) : __assert_fail ("bw != NULL"
, "desktop/browser_window.c", 4723, __extension__ __PRETTY_FUNCTION__
))
;
4724
4725 if (bw->current_cert_chain == NULL((void*)0)) {
4726 return NSERROR_NOT_FOUND;
4727 }
4728
4729 *chain = bw->current_cert_chain;
4730
4731 return NSERROR_OK;
4732}
4733
4734/* Exported interface, documented in browser_window.h */
4735int browser_window_get_cookie_count(
4736 const struct browser_window *bw)
4737{
4738 int count = 0;
4739 char *cookies = urldb_get_cookie(browser_window_access_url(bw), true1);
4740 if (cookies == NULL((void*)0)) {
4741 return 0;
4742 }
4743
4744 for (char *c = cookies; *c != '\0'; c++) {
4745 if (*c == ';')
4746 count++;
4747 }
4748
4749 free(cookies);
4750
4751 return count;
4752}
4753
4754/* Exported interface, documented in browser_window.h */
4755nserror browser_window_show_cookies(
4756 const struct browser_window *bw)
4757{
4758 nserror err;
4759 nsurl *url = browser_window_access_url(bw);
4760 lwc_string *host = nsurl_get_component(url, NSURL_HOST);
4761 const char *string = (host != NULL((void*)0)) ? lwc_string_data(host)({((host != ((void*)0)) ? (void) (0) : __assert_fail ("host != NULL"
, "desktop/browser_window.c", 4761, __extension__ __PRETTY_FUNCTION__
)); (const char *)((host)+1);})
: NULL((void*)0);
4762
4763 err = guit->misc->present_cookies(string);
4764
4765 if (host != NULL((void*)0)) {
4766 lwc_string_unref(host){ lwc_string *__lwc_s = (host); ((__lwc_s != ((void*)0)) ? (void
) (0) : __assert_fail ("__lwc_s != NULL", "desktop/browser_window.c"
, 4766, __extension__ __PRETTY_FUNCTION__)); __lwc_s->refcnt
--; if ((__lwc_s->refcnt == 0) || ((__lwc_s->refcnt == 1
) && (__lwc_s->insensitive == __lwc_s))) lwc_string_destroy
(__lwc_s); }
;
4767 }
4768 return err;
4769}
4770
4771/* Exported interface, documented in browser_window.h */
4772nserror browser_window_show_certificates(struct browser_window *bw)
4773{
4774 nserror res;
4775 nsurl *url;
4776
4777 if (bw->current_cert_chain == NULL((void*)0)) {
4778 return NSERROR_NOT_FOUND;
4779 }
4780
4781 res = cert_chain_to_query(bw->current_cert_chain, &url);
4782 if (res == NSERROR_OK) {
4783 res = browser_window_create(BW_CREATE_HISTORY |
4784 BW_CREATE_FOREGROUND |
4785 BW_CREATE_TAB,
4786 url,
4787 NULL((void*)0),
4788 bw,
4789 NULL((void*)0));
4790
4791 nsurl_unref(url);
4792 }
4793
4794 return res;
4795}