diff options
Diffstat (limited to 'desktop')
38 files changed, 3227 insertions, 2250 deletions
diff --git a/desktop/Makefile b/desktop/Makefile index 0d88b2bc9..5e190275d 100644 --- a/desktop/Makefile +++ b/desktop/Makefile @@ -2,8 +2,8 @@ S_DESKTOP := cookie_manager.c knockout.c hotlist.c mouse.c \ plot_style.c print.c search.c searchweb.c scrollbar.c \ - sslcert_viewer.c textarea.c version.c system_colour.c \ - local_history.c global_history.c treeview.c + textarea.c version.c system_colour.c \ + local_history.c global_history.c treeview.c page-info.c S_DESKTOP := $(addprefix desktop/,$(S_DESKTOP)) @@ -12,7 +12,7 @@ desktop/version.c: testament $(OBJROOT)/testament.h # S_BROWSER are sources related to full browsers but are common # between RISC OS, GTK, BeOS and AmigaOS builds -S_BROWSER := browser.c browser_window.c browser_history.c \ +S_BROWSER := bitmap.c browser.c browser_window.c browser_history.c \ download.c frames.c netsurf.c cw_helper.c \ save_complete.c save_text.c selection.c textinput.c gui_factory.c \ save_pdf.c font_haru.c diff --git a/desktop/bitmap.c b/desktop/bitmap.c new file mode 100644 index 000000000..0602773ca --- /dev/null +++ b/desktop/bitmap.c @@ -0,0 +1,338 @@ +/* + * Copyright 2022 Michael Drake <tlsa@netsurf-browser.org> + * + * This file is part of NetSurf, http://www.netsurf-browser.org/ + * + * NetSurf is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * NetSurf is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +/** \file + * Internal core bitmap interface. + */ + +#include <stddef.h> +#include <stdint.h> +#include <stdbool.h> + +#include "utils/log.h" +#include "utils/errors.h" + +#include "desktop/bitmap.h" +#include "desktop/gui_internal.h" + +/** The client bitmap format. */ +bitmap_fmt_t bitmap_fmt; + +/** The client bitmap colour channel layout. */ +struct bitmap_colour_layout bitmap_layout = { + .r = 0, + .g = 1, + .b = 2, + .a = 3, +}; + +/** + * Get the colour layout for the given bitmap format. + * + * \param[in] fmt Pixel format to get channel layout for, + * \return channel layout structure. + */ +static struct bitmap_colour_layout bitmap__get_colour_layout( + const bitmap_fmt_t *fmt) +{ + switch (fmt->layout) { + default: + /* Fall through. */ + case BITMAP_LAYOUT_R8G8B8A8: + return (struct bitmap_colour_layout) { + .r = 0, + .g = 1, + .b = 2, + .a = 3, + }; + + case BITMAP_LAYOUT_B8G8R8A8: + return (struct bitmap_colour_layout) { + .b = 0, + .g = 1, + .r = 2, + .a = 3, + }; + + case BITMAP_LAYOUT_A8R8G8B8: + return (struct bitmap_colour_layout) { + .a = 0, + .r = 1, + .g = 2, + .b = 3, + }; + + case BITMAP_LAYOUT_A8B8G8R8: + return (struct bitmap_colour_layout) { + .a = 0, + .b = 1, + .g = 2, + .r = 3, + }; + } +} + +/** + * Get string for given pixel layout. + * + * \param[in] layout The pixel layout to get string for, + * \return String for given layout. + */ +static const char *bitmap__layout_to_str(enum bitmap_layout layout) +{ + const char *const str[] = { + [BITMAP_LAYOUT_R8G8B8A8] = "Byte-wise RGBA", + [BITMAP_LAYOUT_B8G8R8A8] = "Byte-wise BGRA", + [BITMAP_LAYOUT_A8R8G8B8] = "Byte-wise ARGB", + [BITMAP_LAYOUT_A8B8G8R8] = "Byte-wise ABGR", + [BITMAP_LAYOUT_RGBA8888] = "0xRRGGBBAA (native endian)", + [BITMAP_LAYOUT_BGRA8888] = "0xBBGGRRAA (native endian)", + [BITMAP_LAYOUT_ARGB8888] = "0xAARRGGBB (native endian)", + [BITMAP_LAYOUT_ABGR8888] = "0xAABBGGRR (native endian)", + }; + + if ((size_t)layout >= (sizeof(str)) / sizeof(*str) || + str[layout] == NULL) { + return "Unknown"; + } + + return str[layout]; +} + +/* Exported function, documented in include/netsurf/bitmap.h */ +void bitmap_set_format(const bitmap_fmt_t *bitmap_format) +{ + bitmap_fmt = *bitmap_format; + + NSLOG(netsurf, INFO, "Setting core bitmap format to: %s%s", + bitmap__layout_to_str(bitmap_format->layout), + bitmap_format->pma ? " pre multiplied alpha" : ""); + + bitmap_fmt.layout = bitmap_sanitise_bitmap_layout(bitmap_fmt.layout); + + if (bitmap_format->layout != bitmap_fmt.layout) { + NSLOG(netsurf, INFO, "Sanitised layout to: %s", + bitmap__layout_to_str(bitmap_fmt.layout)); + } + + bitmap_layout = bitmap__get_colour_layout(&bitmap_fmt); +} + +/** + * Swap colour component order. + * + * \param[in] width Bitmap width in pixels. + * \param[in] height Bitmap height in pixels. + * \param[in] buffer Pixel buffer. + * \param[in] rowstride Pixel buffer row stride in bytes. + * \param[in] to Pixel layout to convert to. + * \param[in] from Pixel layout to convert from. + */ +static inline void bitmap__format_convert( + int width, + int height, + uint8_t *buffer, + size_t rowstride, + struct bitmap_colour_layout to, + struct bitmap_colour_layout from) +{ + /* Just swapping the components around */ + for (int y = 0; y < height; y++) { + uint8_t *row = buffer; + + for (int x = 0; x < width; x++) { + const uint32_t px = *((uint32_t *)(void *) row); + + row[to.r] = ((const uint8_t *) &px)[from.r]; + row[to.g] = ((const uint8_t *) &px)[from.g]; + row[to.b] = ((const uint8_t *) &px)[from.b]; + row[to.a] = ((const uint8_t *) &px)[from.a]; + + row += sizeof(uint32_t); + } + + buffer += rowstride; + } +} + +/** + * Convert plain alpha to premultiplied alpha. + * + * \param[in] width Bitmap width in pixels. + * \param[in] height Bitmap height in pixels. + * \param[in] buffer Pixel buffer. + * \param[in] rowstride Pixel buffer row stride in bytes. + * \param[in] to Pixel layout to convert to. + * \param[in] from Pixel layout to convert from. + */ +static inline void bitmap__format_convert_to_pma( + int width, + int height, + uint8_t *buffer, + size_t rowstride, + struct bitmap_colour_layout to, + struct bitmap_colour_layout from) +{ + for (int y = 0; y < height; y++) { + uint8_t *row = buffer; + + for (int x = 0; x < width; x++) { + const uint32_t px = *((uint32_t *)(void *) row); + uint32_t a, r, g, b; + + r = ((const uint8_t *) &px)[from.r]; + g = ((const uint8_t *) &px)[from.g]; + b = ((const uint8_t *) &px)[from.b]; + a = ((const uint8_t *) &px)[from.a]; + + if (a != 0) { + r = ((r * (a + 1)) >> 8) & 0xff; + g = ((g * (a + 1)) >> 8) & 0xff; + b = ((b * (a + 1)) >> 8) & 0xff; + } else { + r = g = b = 0; + } + + row[to.r] = r; + row[to.g] = g; + row[to.b] = b; + row[to.a] = a; + + row += sizeof(uint32_t); + } + + buffer += rowstride; + } +} + +/** + * Convert from premultiplied alpha to plain alpha. + * + * \param[in] width Bitmap width in pixels. + * \param[in] height Bitmap height in pixels. + * \param[in] buffer Pixel buffer. + * \param[in] rowstride Pixel buffer row stride in bytes. + * \param[in] to Pixel layout to convert to. + * \param[in] from Pixel layout to convert from. + */ +static inline void bitmap__format_convert_from_pma( + int width, + int height, + uint8_t *buffer, + size_t rowstride, + struct bitmap_colour_layout to, + struct bitmap_colour_layout from) +{ + for (int y = 0; y < height; y++) { + uint8_t *row = buffer; + + for (int x = 0; x < width; x++) { + const uint32_t px = *((uint32_t *)(void *) row); + uint32_t a, r, g, b; + + r = ((const uint8_t *) &px)[from.r]; + g = ((const uint8_t *) &px)[from.g]; + b = ((const uint8_t *) &px)[from.b]; + a = ((const uint8_t *) &px)[from.a]; + + if (a != 0) { + r = (r << 8) / a; + g = (g << 8) / a; + b = (b << 8) / a; + + r = (r > 255) ? 255 : r; + g = (g > 255) ? 255 : g; + b = (b > 255) ? 255 : b; + } else { + r = g = b = 0; + } + + row[to.r] = r; + row[to.g] = g; + row[to.b] = b; + row[to.a] = a; + + row += sizeof(uint32_t); + } + + buffer += rowstride; + } +} + +/* Exported function, documented in desktop/bitmap.h */ +void bitmap_format_convert(void *bitmap, + const bitmap_fmt_t *fmt_from, + const bitmap_fmt_t *fmt_to) +{ + int width = guit->bitmap->get_width(bitmap); + int height = guit->bitmap->get_height(bitmap); + bool opaque = guit->bitmap->get_opaque(bitmap); + uint8_t *buffer = guit->bitmap->get_buffer(bitmap); + size_t rowstride = guit->bitmap->get_rowstride(bitmap); + struct bitmap_colour_layout to = bitmap__get_colour_layout(fmt_to); + struct bitmap_colour_layout from = bitmap__get_colour_layout(fmt_from); + + NSLOG(netsurf, DEEPDEBUG, "%p: format conversion (%u%s --> %u%s)", + bitmap, + fmt_from->layout, fmt_from->pma ? " pma" : "", + fmt_to->layout, fmt_to->pma ? " pma" : ""); + + if (fmt_from->pma == fmt_to->pma) { + /* Just component order to switch. */ + bitmap__format_convert( + width, height, buffer, + rowstride, to, from); + + } else if (opaque == false) { + /* Need to do conversion to/from premultiplied alpha. */ + if (fmt_to->pma) { + bitmap__format_convert_to_pma( + width, height, buffer, + rowstride, to, from); + } else { + bitmap__format_convert_from_pma( + width, height, buffer, + rowstride, to, from); + } + } +} + +/* Exported function, documented in desktop/bitmap.h */ +bool bitmap_test_opaque(void *bitmap) +{ + int width = guit->bitmap->get_width(bitmap); + int height = guit->bitmap->get_height(bitmap); + size_t rowstride = guit->bitmap->get_rowstride(bitmap); + const uint8_t *buffer = guit->bitmap->get_buffer(bitmap); + + width *= sizeof(uint32_t); + + for (int y = 0; y < height; y++) { + const uint8_t *row = buffer; + + for (int x = bitmap_layout.a; x < width; x += 4) { + if (row[x] != 0xff) { + return false; + } + } + + buffer += rowstride; + } + + return true; +} diff --git a/desktop/bitmap.h b/desktop/bitmap.h new file mode 100644 index 000000000..51ce2c908 --- /dev/null +++ b/desktop/bitmap.h @@ -0,0 +1,147 @@ +/* + * Copyright 2022 Michael Drake <tlsa@nesturf-browser.org> + * + * This file is part of NetSurf, http://www.netsurf-browser.org/ + * + * NetSurf is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * NetSurf is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +/** \file + * Internal core bitmap interface. + */ + +#ifndef _NETSURF_DESKTOP_BITMAP_H_ +#define _NETSURF_DESKTOP_BITMAP_H_ + +#include <nsutils/endian.h> + +#include "netsurf/types.h" +#include "netsurf/bitmap.h" + +/** Pixel format: colour component order. */ +struct bitmap_colour_layout { + uint8_t r; /**< Byte offset within pixel to red component. */ + uint8_t g; /**< Byte offset within pixel to green component. */ + uint8_t b; /**< Byte offset within pixel to blue component. */ + uint8_t a; /**< Byte offset within pixel to alpha component. */ +}; + +/** The client bitmap format. */ +extern bitmap_fmt_t bitmap_fmt; + +/** The client bitmap colour channel layout. */ +extern struct bitmap_colour_layout bitmap_layout; + +/** + * Convert a bitmap pixel to a NetSurf colour (0xAARRGGBB). + * + * The bitmap must be in the client format. + * + * \param[in] Pointer to a pixel in the bitmap's pixel data. + * \return The corresponding NetSurf colour. + */ +static inline colour bitmap_pixel_to_colour(const uint8_t *pixel) +{ + return (pixel[bitmap_layout.r] << 0) | + (pixel[bitmap_layout.g] << 8) | + (pixel[bitmap_layout.b] << 16) | + (pixel[bitmap_layout.a] << 24); +} + +/** + * Sanitise bitmap pixel component layout. + * + * Map endian-dependant layouts to byte-wise layout for the host. + * + * \param[in] layout Layout to convert. + * \return sanitised layout. + */ +static inline enum bitmap_layout bitmap_sanitise_bitmap_layout( + enum bitmap_layout layout) +{ + bool le = endian_host_is_le(); + + switch (layout) { + case BITMAP_LAYOUT_RGBA8888: + layout = (le) ? BITMAP_LAYOUT_A8B8G8R8 + : BITMAP_LAYOUT_R8G8B8A8; + break; + case BITMAP_LAYOUT_BGRA8888: + layout = (le) ? BITMAP_LAYOUT_A8R8G8B8 + : BITMAP_LAYOUT_B8G8R8A8; + break; + case BITMAP_LAYOUT_ARGB8888: + layout = (le) ? BITMAP_LAYOUT_B8G8R8A8 + : BITMAP_LAYOUT_A8R8G8B8; + break; + case BITMAP_LAYOUT_ABGR8888: + layout = (le) ? BITMAP_LAYOUT_R8G8B8A8 + : BITMAP_LAYOUT_A8B8G8R8; + break; + default: + break; + } + + return layout; +} + +/** + * Convert bitmap from one format to another. + * + * Note that both formats should be sanitised. + * + * \param[in] bitmap The bitmap to convert. + * \param[in] from The current bitmap format specifier. + * \param[in] to The bitmap format to convert to. + */ +void bitmap_format_convert(void *bitmap, + const bitmap_fmt_t *from, + const bitmap_fmt_t *to); + +/** + * Convert a bitmap to the client bitmap format. + * + * \param[in] bitmap The bitmap to convert. + * \param[in] current_fmt The current bitmap format specifier. + */ +static inline void bitmap_format_to_client( + void *bitmap, + const bitmap_fmt_t *current_fmt) +{ + bitmap_fmt_t from = *current_fmt; + + from.layout = bitmap_sanitise_bitmap_layout(from.layout); + if (from.layout != bitmap_fmt.layout || from.pma != bitmap_fmt.pma) { + bitmap_format_convert(bitmap, &from, &bitmap_fmt); + } +} + +/** + * Convert a bitmap to the client bitmap format. + * + * \param[in] bitmap The bitmap to convert. + * \param[in] target_fmt The target bitmap format specifier. + */ +static inline void bitmap_format_from_client( + void *bitmap, + const bitmap_fmt_t *target_fmt) +{ + bitmap_fmt_t to = *target_fmt; + + to.layout = bitmap_sanitise_bitmap_layout(to.layout); + if (to.layout != bitmap_fmt.layout || to.pma != bitmap_fmt.pma) { + bitmap_format_convert(bitmap, &bitmap_fmt, &to); + } +} + +#endif diff --git a/desktop/browser.c b/desktop/browser.c index c04488063..6968bf21b 100644 --- a/desktop/browser.c +++ b/desktop/browser.c @@ -23,12 +23,19 @@ */ #include "utils/errors.h" +#include "utils/log.h" +#include "utils/utils.h" #include "netsurf/browser.h" #include "css/utils.h" /* exported interface documented in netsurf/browser.h */ nserror browser_set_dpi(int dpi) { + if (dpi < 72 || dpi > 250) { + int bad = dpi; + dpi = min(max(dpi, 72), 250); + NSLOG(netsurf, INFO, "Clamping invalid DPI %d to %d", bad, dpi); + } nscss_screen_dpi = INTTOFIX(dpi); return NSERROR_OK; diff --git a/desktop/browser_history.c b/desktop/browser_history.c index 5b44670c1..ce9821af8 100644 --- a/desktop/browser_history.c +++ b/desktop/browser_history.c @@ -41,6 +41,7 @@ #include "desktop/gui_internal.h" #include "desktop/browser_private.h" +#include "desktop/local_history_private.h" #include "desktop/browser_history.h" /** @@ -105,7 +106,7 @@ browser_window_history__clone_entry(struct history *history, new_entry->page.bitmap = guit->bitmap->create( LOCAL_HISTORY_WIDTH, LOCAL_HISTORY_HEIGHT, - BITMAP_NEW | BITMAP_OPAQUE); + BITMAP_OPAQUE); if (new_entry->page.bitmap != NULL) { bmsrc_data = guit->bitmap->get_buffer(entry->page.bitmap); @@ -387,7 +388,7 @@ browser_window_history_add(struct browser_window *bw, entry->page.bitmap = guit->bitmap->create( LOCAL_HISTORY_WIDTH, LOCAL_HISTORY_HEIGHT, - BITMAP_NEW | BITMAP_CLEAR_MEMORY | BITMAP_OPAQUE); + BITMAP_CLEAR | BITMAP_OPAQUE); if (entry->page.bitmap != NULL) { ret = guit->bitmap->render(entry->page.bitmap, content); if (ret != NSERROR_OK) { @@ -434,9 +435,7 @@ nserror browser_window_history_update(struct browser_window *bw, history = bw->history; - if (!history || - !history->current || - !history->current->page.bitmap) { + if ((history == NULL) || (history->current == NULL)) { return NSERROR_INVALID; } @@ -455,7 +454,7 @@ nserror browser_window_history_update(struct browser_window *bw, guit->bitmap->render(history->current->page.bitmap, content); } - if (bw->window != NULL && + if ((bw->window != NULL) && guit->window->get_scroll(bw->window, &sx, &sy)) { int content_height = content_get_height(content); int content_width = content_get_width(content); @@ -489,9 +488,7 @@ browser_window_history_get_scroll(struct browser_window *bw, history = bw->history; - if (!history || - !history->current || - !history->current->page.bitmap) { + if ((history== NULL) || (history->current == NULL)) { return NSERROR_INVALID; } diff --git a/desktop/browser_history.h b/desktop/browser_history.h index 06041ebf4..9b6f1fd42 100644 --- a/desktop/browser_history.h +++ b/desktop/browser_history.h @@ -35,17 +35,6 @@ #include "utils/errors.h" -#include "content/handlers/css/utils.h" - -#define LOCAL_HISTORY_WIDTH \ - (FIXTOINT(nscss_pixels_css_to_physical(INTTOFIX(116)))) -#define LOCAL_HISTORY_HEIGHT \ - (FIXTOINT(nscss_pixels_css_to_physical(INTTOFIX(100)))) -#define LOCAL_HISTORY_RIGHT_MARGIN \ - (FIXTOINT(nscss_pixels_css_to_physical(INTTOFIX(50)))) -#define LOCAL_HISTORY_BOTTOM_MARGIN \ - (FIXTOINT(nscss_pixels_css_to_physical(INTTOFIX(30)))) - struct browser_window; struct history_entry; struct bitmap; diff --git a/desktop/browser_private.h b/desktop/browser_private.h index 6e45052d7..40c3b43ce 100644 --- a/desktop/browser_private.h +++ b/desktop/browser_private.h @@ -89,13 +89,6 @@ struct browser_fetch_parameters { bool parent_quirks; /**< Optional parent quirks */ }; -/** - * The SSL context for a fetch, as provided by the fetchers - */ -struct browser_ssl_info { - struct ssl_cert_info certs[MAX_SSL_CERTS]; /**< The certificate chain */ - size_t num; /**< The number of certificates in the chain */ -}; /** * Browser window data. @@ -113,9 +106,9 @@ struct browser_window { struct browser_fetch_parameters current_parameters; /** - * The SSL information for the current content + * The certificate chain for the current content */ - struct browser_ssl_info current_ssl_info; + struct cert_chain *current_cert_chain; /** * Content handle of page in process of being loaded or NULL @@ -129,9 +122,9 @@ struct browser_window { struct browser_fetch_parameters loading_parameters; /** - * The SSL information for the loading content + * The certificate chain for the loading content */ - struct browser_ssl_info loading_ssl_info; + struct cert_chain *loading_cert_chain; /** * Favicon @@ -270,7 +263,7 @@ struct browser_window { bool can_edit; /** current javascript context */ - struct jscontext *jsctx; + struct jsheap *jsheap; /** cache of the currently displayed status text. */ struct { @@ -290,8 +283,16 @@ struct browser_window { * \param existing The existing window if cloning, else NULL */ nserror browser_window_initialise_common(enum browser_window_create_flags flags, - struct browser_window *bw, struct browser_window *existing); + struct browser_window *bw, + const struct browser_window *existing); + +/** + * Release all memory associated with a browser window. + * + * \param bw browser window + */ +nserror browser_window_destroy_internal(struct browser_window *bw); /** * Get the dimensions of the area a browser window occupies @@ -315,12 +316,12 @@ void browser_window_update_extent(struct browser_window *bw); /** - * update an area of a browser window. + * Cause an area of a browser window to be marked invalid and hence redrawn. * * \param bw The browser window to update. * \param rect The area to redraw */ -void browser_window_update_box(struct browser_window *bw, struct rect *rect); +nserror browser_window_invalidate_rect(struct browser_window *bw, struct rect *rect); /** @@ -338,7 +339,8 @@ void browser_window_set_status(struct browser_window *bw, const char *text); * \param bw browser window to set the type of the current drag for * \return root browser window */ -struct browser_window * browser_window_get_root(struct browser_window *bw); +struct browser_window * browser_window_get_root( + struct browser_window *bw); /** diff --git a/desktop/browser_window.c b/desktop/browser_window.c index 1e776c141..c70db7cf1 100644 --- a/desktop/browser_window.c +++ b/desktop/browser_window.c @@ -1,7 +1,7 @@ /* * Copyright 2008 Michael Drake <tlsa@netsurf-browser.org> * Copyright 2010 Daniel Silverstone <dsilvers@digital-scurf.org> - * Copyright 2010 Vincent Sanders <vince@netsurf-browser.org> + * Copyright 2010-2020 Vincent Sanders <vince@netsurf-browser.org> * * This file is part of NetSurf, http://www.netsurf-browser.org/ * @@ -26,49 +26,47 @@ #include "utils/config.h" -#include <assert.h> -#include <limits.h> -#include <stdbool.h> -#include <stdint.h> #include <stdlib.h> #include <string.h> -#include <strings.h> #include <math.h> #include <nsutils/time.h> -#include "utils/corestrings.h" +#include "utils/errors.h" #include "utils/log.h" +#include "utils/corestrings.h" #include "utils/messages.h" -#include "utils/nsurl.h" -#include "utils/utils.h" -#include "utils/utf8.h" #include "utils/nsoption.h" -#include "netsurf/misc.h" +#include "netsurf/types.h" +#include "netsurf/browser_window.h" #include "netsurf/window.h" +#include "netsurf/misc.h" #include "netsurf/content.h" +#include "netsurf/search.h" #include "netsurf/plotters.h" -#include "content/content_debug.h" -#include "content/fetch.h" +#include "content/content.h" #include "content/hlcache.h" #include "content/urldb.h" -#include "css/utils.h" -#include "html/form_internal.h" +#include "content/content_debug.h" + #include "html/html.h" -#include "html/box.h" +#include "html/form_internal.h" #include "javascript/js.h" -#include "desktop/browser_history.h" #include "desktop/browser_private.h" +#include "desktop/scrollbar.h" +#include "desktop/gui_internal.h" #include "desktop/download.h" #include "desktop/frames.h" #include "desktop/global_history.h" +#include "desktop/textinput.h" #include "desktop/hotlist.h" #include "desktop/knockout.h" -#include "desktop/scrollbar.h" -#include "desktop/selection.h" +#include "desktop/browser_history.h" #include "desktop/theme.h" -#include "desktop/gui_internal.h" -#include "desktop/textinput.h" + +#ifdef WITH_THEME_INSTALL +#include "desktop/theme.h" +#endif /** * smallest scale that can be applied to a browser window @@ -85,9 +83,6 @@ */ #define FRAME_DEPTH 8 -/* Have to forward declare browser_window_destroy_internal */ -static void browser_window_destroy_internal(struct browser_window *bw); - /* Forward declare internal navigation function */ static nserror browser_window__navigate_internal( struct browser_window *bw, struct browser_fetch_parameters *params); @@ -111,14 +106,6 @@ static void browser_window_destroy_children(struct browser_window *bw) bw->rows = 0; bw->cols = 0; } - if (bw->iframes) { - for (i = 0; i < bw->iframe_count; i++) { - browser_window_destroy_internal(&bw->iframes[i]); - } - free(bw->iframes); - bw->iframes = NULL; - bw->iframe_count = 0; - } } @@ -328,22 +315,6 @@ browser_window__get_contextual_content(struct browser_window *bw, /** - * slow script handler - */ -static bool slow_script(void *ctx) -{ - static int count = 0; - NSLOG(netsurf, INFO, "Continuing execution %d", count); - count++; - if (count > 1) { - count = 0; - return false; - } - return true; -} - - -/** * implements the download operation of a window navigate */ static nserror @@ -722,6 +693,130 @@ browser_window_convert_to_download(struct browser_window *bw, /** + * scroll to a fragment if present + * + * \param bw browser window + * \return true if the scroll was sucessful + */ +static bool frag_scroll(struct browser_window *bw) +{ + struct rect rect; + + if (bw->frag_id == NULL) { + return false; + } + + if (!html_get_id_offset(bw->current_content, + bw->frag_id, + &rect.x0, + &rect.y0)) { + return false; + } + + rect.x1 = rect.x0; + rect.y1 = rect.y0; + if (browser_window_set_scroll(bw, &rect) == NSERROR_OK) { + if (bw->current_content != NULL && + bw->history != NULL && + bw->history->current != NULL) { + browser_window_history_update(bw, bw->current_content); + } + return true; + } + return false; +} + + +/** + * Redraw browser window, set extent to content, and update title. + * + * \param bw browser_window + * \param scroll_to_top move view to top of page + */ +static void browser_window_update(struct browser_window *bw, bool scroll_to_top) +{ + static const struct rect zrect = { + .x0 = 0, + .y0 = 0, + .x1 = 0, + .y1 = 0 + }; + + if (bw->current_content == NULL) { + return; + } + + switch (bw->browser_window_type) { + + case BROWSER_WINDOW_NORMAL: + /* Root browser window, constituting a front end window/tab */ + guit->window->set_title(bw->window, + content_get_title(bw->current_content)); + + browser_window_update_extent(bw); + + /* if frag_id exists, then try to scroll to it */ + /** @todo don't do this if the user has scrolled */ + if (!frag_scroll(bw)) { + if (scroll_to_top) { + browser_window_set_scroll(bw, &zrect); + } + } + + guit->window->invalidate(bw->window, NULL); + + break; + + case BROWSER_WINDOW_IFRAME: + /* Internal iframe browser window */ + assert(bw->parent != NULL); + assert(bw->parent->current_content != NULL); + + browser_window_update_extent(bw); + + if (scroll_to_top) { + browser_window_set_scroll(bw, &zrect); + } + + /* if frag_id exists, then try to scroll to it */ + /** @todo don't do this if the user has scrolled */ + frag_scroll(bw); + + browser_window_invalidate_iframe(bw); + + break; + + case BROWSER_WINDOW_FRAME: + { + struct rect rect; + browser_window_update_extent(bw); + + if (scroll_to_top) { + browser_window_set_scroll(bw, &zrect); + } + + /* if frag_id exists, then try to scroll to it */ + /** @todo don't do this if the user has scrolled */ + frag_scroll(bw); + + rect.x0 = scrollbar_get_offset(bw->scroll_x); + rect.y0 = scrollbar_get_offset(bw->scroll_y); + rect.x1 = rect.x0 + bw->width; + rect.y1 = rect.y0 + bw->height; + + browser_window_invalidate_rect(bw, &rect); + } + break; + + default: + case BROWSER_WINDOW_FRAMESET: + /* Nothing to do */ + break; + } +} + + +/** * handle message for content ready on browser window */ static nserror browser_window_content_ready(struct browser_window *bw) @@ -743,9 +838,10 @@ static nserror browser_window_content_ready(struct browser_window *bw) browser_window__free_fetch_parameters(&bw->current_parameters); bw->current_parameters = bw->loading_parameters; memset(&bw->loading_parameters, 0, sizeof(bw->loading_parameters)); - /* Transfer the SSL info */ - bw->current_ssl_info = bw->loading_ssl_info; - bw->loading_ssl_info.num = 0; + /* Transfer the certificate chain */ + cert_chain_free(bw->current_cert_chain); + bw->current_cert_chain = bw->loading_cert_chain; + bw->loading_cert_chain = NULL; } /* Format the new content to the correct dimensions */ @@ -808,14 +904,15 @@ static nserror browser_window_content_ready(struct browser_window *bw) browser_window_set_status(bw, content_get_status_message(bw->current_content)); /* frames */ - if ((content_get_type(bw->current_content) == CONTENT_HTML) && - (html_get_frameset(bw->current_content) != NULL)) { - res = browser_window_create_frameset(bw, html_get_frameset(bw->current_content)); - } + res = browser_window_create_frameset(bw); + + /* iframes */ + res = browser_window_create_iframes(bw); - if (content_get_type(bw->current_content) == CONTENT_HTML && - html_get_iframe(bw->current_content) != NULL) { - browser_window_create_iframes(bw, html_get_iframe(bw->current_content)); + /* Indicate page status may have changed */ + if (res == NSERROR_OK) { + struct browser_window *root = browser_window_get_root(bw); + res = guit->window->event(root->window, GW_EVENT_PAGE_INFO_CHANGE); } return res; @@ -887,6 +984,7 @@ browser_window__handle_ssl_query_response(bool proceed, void *pw) browser_window_stop(bw); browser_window_remove_caret(bw, false); browser_window_destroy_children(bw); + browser_window_destroy_iframes(bw); } if (!proceed) { @@ -1032,6 +1130,7 @@ browser_window__handle_userpass_response(nsurl *url, browser_window_stop(bw); browser_window_remove_caret(bw, false); browser_window_destroy_children(bw); + browser_window_destroy_iframes(bw); } bw->internal_nav = false; return browser_window__navigate_internal(bw, &bw->loading_parameters); @@ -1130,11 +1229,14 @@ browser_window__handle_bad_certs(struct browser_window *bw, nserror err; /* Initially we don't know WHY the SSL cert was bad */ const char *reason = messages_get_sslcode(SSL_CERT_ERR_UNKNOWN); - size_t n; + size_t depth; + nsurl *chainurl = NULL; memset(¶ms, 0, sizeof(params)); params.url = nsurl_ref(corestring_nsurl_about_query_ssl); + params.referrer = nsurl_ref(url); + params.flags = BW_NAVIGATE_HISTORY | BW_NAVIGATE_NO_TERMINAL_HISTORY_UPDATE | BW_NAVIGATE_INTERNAL; err = fetch_multipart_data_new_kv(¶ms.post_multipart, "siteurl", @@ -1143,12 +1245,26 @@ browser_window__handle_bad_certs(struct browser_window *bw, goto out; } - for (n = 0; n < bw->loading_ssl_info.num; ++n) { - size_t idx = bw->loading_ssl_info.num - (n + 1); - ssl_cert_err err = bw->loading_ssl_info.certs[idx].err; - if (err != SSL_CERT_ERR_OK) { - reason = messages_get_sslcode(err); - break; + if (bw->loading_cert_chain != NULL) { + for (depth = 0; depth < bw->loading_cert_chain->depth; ++depth) { + size_t idx = bw->loading_cert_chain->depth - (depth + 1); + ssl_cert_err err = bw->loading_cert_chain->certs[idx].err; + if (err != SSL_CERT_ERR_OK) { + reason = messages_get_sslcode(err); + break; + } + } + + err = cert_chain_to_query(bw->loading_cert_chain, &chainurl); + if (err != NSERROR_OK) { + goto out; + } + + err = fetch_multipart_data_new_kv(¶ms.post_multipart, + "chainurl", + nsurl_access(chainurl)); + if (err != NSERROR_OK) { + goto out; } } @@ -1166,17 +1282,10 @@ browser_window__handle_bad_certs(struct browser_window *bw, goto out; } - err = guit->misc->cert_verify(url, - bw->loading_ssl_info.certs, - bw->loading_ssl_info.num, - browser_window__handle_ssl_query_response, - bw); - - if (err == NSERROR_NOT_IMPLEMENTED) { - err = NSERROR_OK; - } out: browser_window__free_fetch_parameters(¶ms); + if (chainurl != NULL) + nsurl_unref(chainurl); return err; } @@ -1278,6 +1387,8 @@ browser_window__handle_error(struct browser_window *bw, if (message == NULL) { message = messages_get_errorcode(code); + } else { + message = messages_get(message); } if (c == bw->loading_content) { @@ -1307,9 +1418,28 @@ browser_window__handle_error(struct browser_window *bw, break; } - browser_window_stop_throbber(bw); + return res; +} - return NSERROR_OK; + +/** + * Update URL bar for a given browser window to given URL + * + * \param bw Browser window to update URL bar for. + * \param url URL for content displayed by bw including any fragment. + */ +static inline nserror +browser_window_refresh_url_bar_internal(struct browser_window *bw, nsurl *url) +{ + assert(bw); + assert(url); + + if ((bw->parent != NULL) || (bw->window == NULL)) { + /* Not root window or no gui window so do not set a URL */ + return NSERROR_OK; + } + + return guit->window->set_url(bw->window, url); } @@ -1325,11 +1455,8 @@ browser_window_callback(hlcache_handle *c, const hlcache_event *event, void *pw) switch (event->type) { case CONTENT_MSG_SSL_CERTS: /* SSL certificate information has arrived, store it */ - assert(event->data.certs.num < MAX_SSL_CERTS); - memcpy(&bw->loading_ssl_info.certs[0], - event->data.certs.certs, - sizeof(struct ssl_cert_info) * event->data.certs.num); - bw->loading_ssl_info.num = event->data.certs.num; + cert_chain_free(bw->loading_cert_chain); + cert_chain_dup(event->data.chain, &bw->loading_cert_chain); break; case CONTENT_MSG_LOG: @@ -1387,6 +1514,7 @@ browser_window_callback(hlcache_handle *c, const hlcache_event *event, void *pw) if (urldb_add_url(event->data.redirect.from)) { urldb_update_url_visit_data(event->data.redirect.from); } + browser_window_refresh_url_bar_internal(bw, event->data.redirect.to); break; case CONTENT_MSG_STATUS: @@ -1414,14 +1542,12 @@ browser_window_callback(hlcache_handle *c, const hlcache_event *event, void *pw) break; case CONTENT_MSG_REFORMAT: - if (c == bw->current_content && - content_get_type(c) == CONTENT_HTML) { - /* reposition frames */ - if (html_get_frameset(c) != NULL) - browser_window_recalculate_frameset(bw); - /* reflow iframe positions */ - if (html_get_iframe(c) != NULL) - browser_window_recalculate_iframes(bw); + if (c == bw->current_content) { + /* recompute frameset */ + browser_window_recalculate_frameset(bw); + + /* recompute iframe positions, sizes and scrollbars */ + browser_window_recalculate_iframes(bw); } /* Hide any caret, but don't remove it */ @@ -1442,7 +1568,7 @@ browser_window_callback(hlcache_handle *c, const hlcache_event *event, void *pw) .y1 = event->data.redraw.y + event->data.redraw.height }; - browser_window_update_box(bw, &rect); + browser_window_invalidate_rect(bw, &rect); } break; @@ -1470,15 +1596,24 @@ browser_window_callback(hlcache_handle *c, const hlcache_event *event, void *pw) } break; - case CONTENT_MSG_GETCTX: - /* only the content object created by the browser - * window requires a new global compartment object - */ - assert(bw->loading_content == c); - if (js_newcompartment(bw->jsctx, - bw, - hlcache_handle_get_content(c)) != NULL) { - *(event->data.jscontext) = bw->jsctx; + case CONTENT_MSG_GETTHREAD: + { + /* only the content object created by the browser + * window requires a new javascript thread object + */ + jsthread *thread; + assert(bw->loading_content == c); + + if (js_newthread(bw->jsheap, + bw, + hlcache_handle_get_content(c), + &thread) == NSERROR_OK) { + /* The content which is requesting the thread + * is required to keep hold of it and + * to destroy it when it is finished with it. + */ + *(event->data.jsthread) = thread; + } } break; @@ -1634,6 +1769,37 @@ browser_window_callback(hlcache_handle *c, const hlcache_event *event, void *pw) break; + + case CONTENT_MSG_TEXTSEARCH: + switch (event->data.textsearch.type) { + case CONTENT_TEXTSEARCH_FIND: + guit->search->hourglass(event->data.textsearch.state, + event->data.textsearch.ctx); + break; + + case CONTENT_TEXTSEARCH_MATCH: + guit->search->status(event->data.textsearch.state, + event->data.textsearch.ctx); + break; + + case CONTENT_TEXTSEARCH_BACK: + guit->search->back_state(event->data.textsearch.state, + event->data.textsearch.ctx); + break; + + case CONTENT_TEXTSEARCH_FORWARD: + guit->search->forward_state(event->data.textsearch.state, + event->data.textsearch.ctx); + break; + + case CONTENT_TEXTSEARCH_RECENT: + guit->search->add_recent(event->data.textsearch.string, + event->data.textsearch.ctx); + + break; + } + break; + default: break; } @@ -1662,21 +1828,13 @@ static void scheduled_reformat(void *vbw) } } - -/** - * Release all memory associated with a browser window. - * - * \param bw browser window - */ -static void browser_window_destroy_internal(struct browser_window *bw) +/* exported interface documented in desktop/browser_private.h */ +nserror browser_window_destroy_internal(struct browser_window *bw) { assert(bw); - NSLOG(netsurf, INFO, "Destroying window"); - - if (bw->children != NULL || bw->iframes != NULL) { - browser_window_destroy_children(bw); - } + browser_window_destroy_children(bw); + browser_window_destroy_iframes(bw); /* Destroy scrollbars */ if (bw->scroll_x != NULL) { @@ -1740,13 +1898,9 @@ static void browser_window_destroy_internal(struct browser_window *bw) bw->favicon.current = NULL; } - if (bw->box != NULL) { - bw->box->iframe = NULL; - bw->box = NULL; - } - - if (bw->jsctx != NULL) { - js_destroycontext(bw->jsctx); + if (bw->jsheap != NULL) { + js_destroyheap(bw->jsheap); + bw->jsheap = NULL; } /* These simply free memory, so are safe here */ @@ -1757,6 +1911,11 @@ static void browser_window_destroy_internal(struct browser_window *bw) browser_window_history_destroy(bw); + cert_chain_free(bw->current_cert_chain); + cert_chain_free(bw->loading_cert_chain); + bw->current_cert_chain = NULL; + bw->loading_cert_chain = NULL; + free(bw->name); free(bw->status.text); bw->status.text = NULL; @@ -1764,62 +1923,8 @@ static void browser_window_destroy_internal(struct browser_window *bw) browser_window__free_fetch_parameters(&bw->loading_parameters); NSLOG(netsurf, INFO, "Status text cache match:miss %d:%d", bw->status.match, bw->status.miss); -} - - -/** - * Update URL bar for a given browser window to given URL - * - * \param bw Browser window to update URL bar for. - * \param url URL for content displayed by bw including any fragment. - */ -static inline nserror -browser_window_refresh_url_bar_internal(struct browser_window *bw, nsurl *url) -{ - assert(bw); - assert(url); - - if ((bw->parent != NULL) || (bw->window == NULL)) { - /* Not root window or no gui window so do not set a URL */ - return NSERROR_OK; - } - - return guit->window->set_url(bw->window, url); -} - -/** - * scroll to a fragment if present - * - * \param bw browser window - * \return true if the scroll was sucessful - */ -static bool frag_scroll(struct browser_window *bw) -{ - struct rect rect; - - if (bw->frag_id == NULL) { - return false; - } - - if (!html_get_id_offset(bw->current_content, - bw->frag_id, - &rect.x0, - &rect.y0)) { - return false; - } - - rect.x1 = rect.x0; - rect.y1 = rect.y0; - if (browser_window_set_scroll(bw, &rect) == NSERROR_OK) { - if (bw->current_content != NULL && - bw->history != NULL && - bw->history->current != NULL) { - browser_window_history_update(bw, bw->current_content); - } - return true; - } - return false; + return NSERROR_OK; } @@ -1855,7 +1960,7 @@ browser_window_set_scale_internal(struct browser_window *bw, float scale) res = browser_window_set_scale_internal(&bw->children[i], scale); } - /* sale iframes */ + /* scale iframes */ for (i = 0; i < bw->iframe_count; i++) { res = browser_window_set_scale_internal(&bw->iframes[i], scale); } @@ -2499,14 +2604,14 @@ browser_window_redraw(struct browser_window *bw, struct rect content_clip; nserror res; - x /= bw->scale; - y /= bw->scale; - if (bw == NULL) { NSLOG(netsurf, INFO, "NULL browser window"); return false; } + x /= bw->scale; + y /= bw->scale; + if ((bw->current_content == NULL) && (bw->children == NULL)) { /* Browser window has no content, render blank fill */ @@ -2541,7 +2646,7 @@ browser_window_redraw(struct browser_window *bw, /* Set current child */ child = &bw->children[cur_child]; - /* Get frame edge box in global coordinates */ + /* Get frame edge area in global coordinates */ content_clip.x0 = (x + child->x) * child->scale; content_clip.y0 = (y + child->y) * child->scale; content_clip.x1 = content_clip.x0 + @@ -3036,6 +3141,10 @@ browser_window_create(enum browser_window_create_flags flags, gw_flags |= GW_CREATE_TAB; if (flags & BW_CREATE_CLONE) gw_flags |= GW_CREATE_CLONE; + if (flags & BW_CREATE_FOREGROUND) + gw_flags |= GW_CREATE_FOREGROUND; + if (flags & BW_CREATE_FOCUS_LOCATION) + gw_flags |= GW_CREATE_FOCUS_LOCATION; ret->window = guit->window->create(ret, (existing != NULL) ? existing->window : NULL, @@ -3076,14 +3185,13 @@ browser_window_create(enum browser_window_create_flags flags, nserror browser_window_initialise_common(enum browser_window_create_flags flags, struct browser_window *bw, - struct browser_window *existing) + const struct browser_window *existing) { nserror err; assert(bw); /* new javascript context for each window/(i)frame */ - err = js_newcontext(nsoption_int(script_timeout), - slow_script, NULL, &bw->jsctx); + err = js_newheap(nsoption_int(script_timeout), &bw->jsheap); if (err != NSERROR_OK) return err; @@ -3155,15 +3263,9 @@ nserror browser_window_refresh_url_bar(struct browser_window *bw) /* no content so return about:blank */ ret = browser_window_refresh_url_bar_internal(bw, corestring_nsurl_about_blank); - } else if (bw->throbbing) { - /* We're throbbing, so show the loading parameters url, - * or if there isn't one, the current parameters url - */ - if (bw->loading_parameters.url != NULL) { - url = bw->loading_parameters.url; - } else { - url = bw->current_parameters.url; - } + } else if (bw->throbbing && bw->loading_parameters.url != NULL) { + /* Throbbing and we have loading parameters, use those */ + url = bw->loading_parameters.url; ret = browser_window_refresh_url_bar_internal(bw, url); } else if (bw->frag_id == NULL) { if (bw->internal_nav) { @@ -3354,6 +3456,7 @@ browser_window_navigate(struct browser_window *bw, browser_window_stop(bw); browser_window_remove_caret(bw, false); browser_window_destroy_children(bw); + browser_window_destroy_iframes(bw); /* Set up the fetch parameters */ memset(¶ms, 0, sizeof(params)); @@ -3426,7 +3529,8 @@ navigate_internal_real(struct browser_window *bw, fetch_is_post = (params->post_urlenc != NULL || params->post_multipart != NULL); /* Clear SSL info for load */ - bw->loading_ssl_info.num = 0; + cert_chain_free(bw->loading_cert_chain); + bw->loading_cert_chain = NULL; /* Set up retrieval parameters */ if (!(params->flags & BW_NAVIGATE_UNVERIFIABLE)) { @@ -3585,17 +3689,28 @@ navigate_internal_query_ssl(struct browser_window *bw, struct browser_fetch_parameters *params) { bool is_proceed = false, is_back = false; + const char *siteurl = NULL; + nsurl *siteurl_ns; assert(params->post_multipart != NULL); is_proceed = fetch_multipart_data_find(params->post_multipart, "proceed") != NULL; is_back = fetch_multipart_data_find(params->post_multipart, "back") != NULL; + siteurl = fetch_multipart_data_find(params->post_multipart, "siteurl"); - if (!(is_proceed || is_back)) { + if (!(is_proceed || is_back) || siteurl == NULL) { /* This is a request, so pass it on */ return navigate_internal_real(bw, params); } + if (nsurl_create(siteurl, &siteurl_ns) != NSERROR_OK) { + NSLOG(netsurf, ERROR, "Unable to reset ssl loading parameters"); + } else { + /* In order that we may proceed, replace the loading parameters */ + nsurl_unref(bw->loading_parameters.url); + bw->loading_parameters.url = siteurl_ns; + } + return browser_window__handle_ssl_query_response(is_proceed, bw); } @@ -3714,7 +3829,9 @@ browser_window__navigate_internal(struct browser_window *bw, lwc_string_unref(path); return navigate_internal_query_fetcherror(bw, params); } - lwc_string_unref(path); + if (path != NULL) { + lwc_string_unref(path); + } /* Fall through to a normal about: fetch */ @@ -3783,7 +3900,7 @@ nserror browser_window_navigate_up(struct browser_window *bw, bool new_window) /* Exported interface, documented in include/netsurf/browser_window.h */ -nsurl* browser_window_access_url(struct browser_window *bw) +nsurl* browser_window_access_url(const struct browser_window *bw) { assert(bw != NULL); @@ -3935,91 +4052,9 @@ browser_window_set_dimensions(struct browser_window *bw, int width, int height) } -/* Exported interface, documented in netsurf/browser_window.h */ -void browser_window_update(struct browser_window *bw, bool scroll_to_top) -{ - static const struct rect zrect = { - .x0 = 0, - .y0 = 0, - .x1 = 0, - .y1 = 0 - }; - - if (bw->current_content == NULL) { - return; - } - - switch (bw->browser_window_type) { - - case BROWSER_WINDOW_NORMAL: - /* Root browser window, constituting a front end window/tab */ - guit->window->set_title(bw->window, - content_get_title(bw->current_content)); - - browser_window_update_extent(bw); - - /* if frag_id exists, then try to scroll to it */ - /** @todo don't do this if the user has scrolled */ - if (!frag_scroll(bw)) { - if (scroll_to_top) { - browser_window_set_scroll(bw, &zrect); - } - } - - guit->window->invalidate(bw->window, NULL); - - break; - - case BROWSER_WINDOW_IFRAME: - /* Internal iframe browser window */ - assert(bw->parent != NULL); - assert(bw->parent->current_content != NULL); - - browser_window_update_extent(bw); - - if (scroll_to_top) { - browser_window_set_scroll(bw, &zrect); - } - - /* if frag_id exists, then try to scroll to it */ - /** @todo don't do this if the user has scrolled */ - frag_scroll(bw); - - html_redraw_a_box(bw->parent->current_content, bw->box); - break; - - case BROWSER_WINDOW_FRAME: - { - struct rect rect; - browser_window_update_extent(bw); - - if (scroll_to_top) { - browser_window_set_scroll(bw, &zrect); - } - - /* if frag_id exists, then try to scroll to it */ - /** @todo don't do this if the user has scrolled */ - frag_scroll(bw); - - rect.x0 = scrollbar_get_offset(bw->scroll_x); - rect.y0 = scrollbar_get_offset(bw->scroll_y); - rect.x1 = rect.x0 + bw->width; - rect.y1 = rect.y0 + bw->height; - - browser_window_update_box(bw, &rect); - } - break; - - default: - case BROWSER_WINDOW_FRAMESET: - /* Nothing to do */ - break; - } -} - - -/* Exported interface, documented in netsurf/browser_window.h */ -void browser_window_update_box(struct browser_window *bw, struct rect *rect) +/* Exported interface, documented in browser/browser_private.h */ +nserror +browser_window_invalidate_rect(struct browser_window *bw, struct rect *rect) { int pos_x; int pos_y; @@ -4044,7 +4079,7 @@ void browser_window_update_box(struct browser_window *bw, struct rect *rect) rect->x1 *= top->scale; rect->y1 *= top->scale; - guit->window->invalidate(top->window, rect); + return guit->window->invalidate(top->window, rect); } @@ -4324,7 +4359,7 @@ browser_window_find_target(struct browser_window *bw, target = html_get_base_target(c); } if (target == NULL) { - target = TARGET_SELF; + target = "_self"; } /* allow the simple case of target="_blank" to be ignored if requested @@ -4336,7 +4371,7 @@ browser_window_find_target(struct browser_window *bw, /* not a mouse button 2 click * not a mouse button 1 click with ctrl pressed * configured to ignore target="_blank" */ - if ((target == TARGET_BLANK) || (!strcasecmp(target, "_blank"))) + if (!strcasecmp(target, "_blank")) return bw; } @@ -4347,8 +4382,7 @@ browser_window_find_target(struct browser_window *bw, ((mouse & BROWSER_MOUSE_CLICK_1) && (mouse & BROWSER_MOUSE_MOD_2))) || ((nsoption_bool(button_2_tab)) && - ((target == TARGET_BLANK) || - (!strcasecmp(target, "_blank"))))) { + (!strcasecmp(target, "_blank")))) { /* open in new tab if: * - button_2 opens in new tab and button_2 was pressed * OR @@ -4374,8 +4408,7 @@ browser_window_find_target(struct browser_window *bw, ((mouse & BROWSER_MOUSE_CLICK_1) && (mouse & BROWSER_MOUSE_MOD_2))) || ((!nsoption_bool(button_2_tab)) && - ((target == TARGET_BLANK) || - (!strcasecmp(target, "_blank"))))) { + (!strcasecmp(target, "_blank")))) { /* open in new window if: * - button_2 doesn't open in new tabs and button_2 was pressed * OR @@ -4395,14 +4428,13 @@ browser_window_find_target(struct browser_window *bw, return bw; } return bw_target; - } else if ((target == TARGET_SELF) || (!strcasecmp(target, "_self"))) { + } else if (!strcasecmp(target, "_self")) { return bw; - } else if ((target == TARGET_PARENT) || - (!strcasecmp(target, "_parent"))) { + } else if (!strcasecmp(target, "_parent")) { if (bw->parent) return bw->parent; return bw; - } else if ((target == TARGET_TOP) || (!strcasecmp(target, "_top"))) { + } else if (!strcasecmp(target, "_top")) { while (bw->parent) bw = bw->parent; return bw; @@ -4636,3 +4668,146 @@ browser_window__reload_current_parameters(struct browser_window *bw) memset(&bw->current_parameters, 0, sizeof(bw->current_parameters)); return browser_window__navigate_internal(bw, &bw->loading_parameters); } + +/* Exported interface, documented in browser_window.h */ +browser_window_page_info_state browser_window_get_page_info_state( + const struct browser_window *bw) +{ + lwc_string *scheme; + bool match; + + assert(bw != NULL); + + /* Do we have any content? If not -- UNKNOWN */ + if (bw->current_content == NULL) { + return PAGE_STATE_UNKNOWN; + } + + scheme = nsurl_get_component( + hlcache_handle_get_url(bw->current_content), NSURL_SCHEME); + + /* Is this an internal scheme? */ + if ((lwc_string_isequal(scheme, corestring_lwc_about, + &match) == lwc_error_ok && + (match == true)) || + (lwc_string_isequal(scheme, corestring_lwc_data, + &match) == lwc_error_ok && + (match == true)) || + (lwc_string_isequal(scheme, corestring_lwc_resource, + &match) == lwc_error_ok && + (match == true))) { + lwc_string_unref(scheme); + return PAGE_STATE_INTERNAL; + } + + /* Is this file:/// ? */ + if (lwc_string_isequal(scheme, corestring_lwc_file, + &match) == lwc_error_ok && + match == true) { + lwc_string_unref(scheme); + return PAGE_STATE_LOCAL; + } + + /* If not https, from here on down that'd be insecure */ + if ((lwc_string_isequal(scheme, corestring_lwc_https, + &match) == lwc_error_ok && + (match == false))) { + /* Some remote content, not https, therefore insecure */ + lwc_string_unref(scheme); + return PAGE_STATE_INSECURE; + } + + lwc_string_unref(scheme); + + /* Did we have to override this SSL setting? */ + if (urldb_get_cert_permissions(hlcache_handle_get_url(bw->current_content))) { + return PAGE_STATE_SECURE_OVERRIDE; + } + + /* If we've seen insecure content internally then we need to say so */ + if (content_saw_insecure_objects(bw->current_content)) { + return PAGE_STATE_SECURE_ISSUES; + } + + /* All is well, return secure state */ + return PAGE_STATE_SECURE; +} + +/* Exported interface, documented in browser_window.h */ +nserror +browser_window_get_ssl_chain(struct browser_window *bw, + struct cert_chain **chain) +{ + assert(bw != NULL); + + if (bw->current_cert_chain == NULL) { + return NSERROR_NOT_FOUND; + } + + *chain = bw->current_cert_chain; + + return NSERROR_OK; +} + +/* Exported interface, documented in browser_window.h */ +int browser_window_get_cookie_count( + const struct browser_window *bw) +{ + int count = 0; + char *cookies = urldb_get_cookie(browser_window_access_url(bw), true); + if (cookies == NULL) { + return 0; + } + + for (char *c = cookies; *c != '\0'; c++) { + if (*c == ';') + count++; + } + + free(cookies); + + return count; +} + +/* Exported interface, documented in browser_window.h */ +nserror browser_window_show_cookies( + const struct browser_window *bw) +{ + nserror err; + nsurl *url = browser_window_access_url(bw); + lwc_string *host = nsurl_get_component(url, NSURL_HOST); + const char *string = (host != NULL) ? lwc_string_data(host) : NULL; + + err = guit->misc->present_cookies(string); + + if (host != NULL) { + lwc_string_unref(host); + } + return err; +} + +/* Exported interface, documented in browser_window.h */ +nserror browser_window_show_certificates(struct browser_window *bw) +{ + nserror res; + nsurl *url; + + if (bw->current_cert_chain == NULL) { + return NSERROR_NOT_FOUND; + } + + res = cert_chain_to_query(bw->current_cert_chain, &url); + if (res == NSERROR_OK) { + res = browser_window_create(BW_CREATE_HISTORY | + BW_CREATE_FOREGROUND | + BW_CREATE_TAB, + url, + NULL, + bw, + NULL); + + nsurl_unref(url); + } + + return res; +} diff --git a/desktop/cookie_manager.c b/desktop/cookie_manager.c index a2aab8e9f..b5ec89618 100644 --- a/desktop/cookie_manager.c +++ b/desktop/cookie_manager.c @@ -232,10 +232,6 @@ cookie_manager_field_builder(enum cookie_manager_field field, * * The time should be converted to text in the users locacle * - * \todo This should probably generate the user text using localtime - * and strftime with the c format specifier. Currently ctime will - * always generate output in the C locale. - * * \param field Cookie manager treeview field to build * \param fdata Cookie manager entry field data to set * \param value Time to show in field @@ -246,22 +242,20 @@ cookie_manager_field_builder_time(enum cookie_manager_field field, struct treeview_field_data *fdata, const time_t *value) { - const char *date; - char *date2; + struct tm *ftime; fdata->field = cm_ctx.fields[field].field; - - date = ctime(value); - date2 = strdup(date); - if (date2 == NULL) { - fdata->value = NULL; - fdata->value_len = 0; - } else { - assert(date2[24] == '\n'); - date2[24] = '\0'; - - fdata->value = date2; - fdata->value_len = strlen(date2); + fdata->value = NULL; + fdata->value_len = 0; + + if ((ftime = localtime(value)) != NULL) { + const size_t vsize = 256; + char *value = malloc(vsize); + if (value != NULL) { + fdata->value = value; + fdata->value_len = strftime(value, vsize, + "%a %b %e %H:%M:%S %Y", ftime); + } } return NSERROR_OK; @@ -545,6 +539,19 @@ void cookie_manager_remove(const struct cookie_data *data) } +/* exported interface documented in cookie_manager.h */ +nserror cookie_manager_set_search_string( + const char *string) +{ + /* If we don't have a cookie manager at the moment, just return */ + if (cm_ctx.tree == NULL) { + return NSERROR_NOT_FOUND; + } + + return treeview_set_search_string(cm_ctx.tree, string); +} + + /** * Initialise the treeview entry feilds * diff --git a/desktop/cookie_manager.h b/desktop/cookie_manager.h index 4ae74a25f..11d03252e 100644 --- a/desktop/cookie_manager.h +++ b/desktop/cookie_manager.h @@ -76,6 +76,15 @@ bool cookie_manager_add(const struct cookie_data *data); void cookie_manager_remove(const struct cookie_data *data); /** + * Set the cookie manager search string. + * + * \param string Sering to set as search string. + * \return NSERROR_OK on success, appropriate error otherwise + */ +nserror cookie_manager_set_search_string( + const char *string); + +/** * Redraw the cookies manager. * * \param x X coordinate to render treeview at diff --git a/desktop/frames.c b/desktop/frames.c index 1ed114540..85f18793e 100644 --- a/desktop/frames.c +++ b/desktop/frames.c @@ -35,6 +35,7 @@ #include "content/hlcache.h" #include "html/html.h" #include "html/box.h" +#include "html/box_inspect.h" #include "desktop/browser_private.h" #include "desktop/frames.h" @@ -68,7 +69,7 @@ void browser_window_scroll_callback(void *client_data, rect.x1 = rect.x0 + bw->width; rect.y1 = rect.y0 + bw->height; - browser_window_update_box(bw, &rect); + browser_window_invalidate_rect(bw, &rect); } break; case SCROLLBAR_MSG_SCROLL_START: @@ -180,20 +181,35 @@ void browser_window_handle_scrollbars(struct browser_window *bw) scrollbar_make_pair(bw->scroll_x, bw->scroll_y); } +/* exported function documented in desktop/frames.h */ +nserror browser_window_invalidate_iframe(struct browser_window *bw) +{ + html_redraw_a_box(bw->parent->current_content, bw->box); + return NSERROR_OK; +} /* exported function documented in desktop/frames.h */ -nserror browser_window_create_iframes(struct browser_window *bw, - struct content_html_iframe *iframe) +nserror browser_window_create_iframes(struct browser_window *bw) { + nserror ret = NSERROR_OK; struct browser_window *window; struct content_html_iframe *cur; struct rect rect; int iframes = 0; int index; - nserror ret = NSERROR_OK; + struct content_html_iframe *iframe; + + bw->iframe_count = 0; + + /* only html contents can have iframes */ + if (content_get_type(bw->current_content) != CONTENT_HTML) { + return NSERROR_OK; + } + /* obtain the iframes for this content */ + iframe = html_get_iframe(bw->current_content); if (iframe == NULL) { - return NSERROR_BAD_PARAMETER; + return NSERROR_OK; } /* Count iframe list and allocate enough space within the @@ -271,12 +287,7 @@ nserror browser_window_create_iframes(struct browser_window *bw, } -/** - * Recalculate iframe positions following a resize. - * - * \param bw The browser window to reposition iframes for - */ - +/* exported function documented in desktop/frames.h */ void browser_window_recalculate_iframes(struct browser_window *bw) { struct browser_window *window; @@ -292,123 +303,23 @@ void browser_window_recalculate_iframes(struct browser_window *bw) } -/* exported interface documented in desktop/frames.h */ -nserror browser_window_create_frameset(struct browser_window *bw, - struct content_html_frames *frameset) +/* exported function documented in desktop/frames.h */ +nserror browser_window_destroy_iframes(struct browser_window *bw) { - int row, col, index; - struct content_html_frames *frame; - struct browser_window *window; - hlcache_handle *parent; - - assert(bw && frameset); - - /* 1. Create children */ - assert(bw->children == NULL); - assert(frameset->cols + frameset->rows != 0); - - bw->children = calloc((frameset->cols * frameset->rows), sizeof(*bw)); - if (!bw->children) { - return NSERROR_NOMEM; - } - - bw->cols = frameset->cols; - bw->rows = frameset->rows; - for (row = 0; row < bw->rows; row++) { - for (col = 0; col < bw->cols; col++) { - index = (row * bw->cols) + col; - frame = &frameset->children[index]; - window = &bw->children[index]; - - /* Initialise common parts */ - browser_window_initialise_common(BW_CREATE_NONE, - window, NULL); + int i; - /* window characteristics */ - if (frame->children) - window->browser_window_type = - BROWSER_WINDOW_FRAMESET; - else - window->browser_window_type = - BROWSER_WINDOW_FRAME; - window->scrolling = frame->scrolling; - window->border = frame->border; - window->border_colour = frame->border_colour; - window->no_resize = frame->no_resize; - window->frame_width = frame->width; - window->frame_height = frame->height; - window->margin_width = frame->margin_width; - window->margin_height = frame->margin_height; - if (frame->name) { - window->name = strdup(frame->name); - if (!window->name) { - free(bw->children); - bw->children = NULL; - return NSERROR_NOMEM; - } + if (bw->iframes != NULL) { + for (i = 0; i < bw->iframe_count; i++) { + if (bw->iframes[i].box != NULL) { + bw->iframes[i].box->iframe = NULL; + bw->iframes[i].box = NULL; } - - window->scale = bw->scale; - - /* linking */ - window->parent = bw; - - if (window->name) - NSLOG(netsurf, INFO, "Created frame '%s'", - window->name); - else - NSLOG(netsurf, INFO, - "Created frame (unnamed)"); - } - } - - /* 2. Calculate dimensions */ - browser_window_update_extent(bw); - browser_window_recalculate_frameset(bw); - - /* 3. Recurse for grandchildren */ - for (row = 0; row < bw->rows; row++) { - for (col = 0; col < bw->cols; col++) { - index = (row * bw->cols) + col; - frame = &frameset->children[index]; - window = &bw->children[index]; - - if (frame->children) - browser_window_create_frameset(window, frame); + browser_window_destroy_internal(&bw->iframes[i]); } + free(bw->iframes); + bw->iframes = NULL; + bw->iframe_count = 0; } - - /* Use the URL of the first ancestor window containing html content - * as the referer */ - for (window = bw; window->parent; window = window->parent) { - if (window->current_content && - content_get_type(window->current_content) == - CONTENT_HTML) - break; - } - - parent = window->current_content; - - /* 4. Launch content */ - for (row = 0; row < bw->rows; row++) { - for (col = 0; col < bw->cols; col++) { - index = (row * bw->cols) + col; - frame = &frameset->children[index]; - window = &bw->children[index]; - - if (frame->url) { - browser_window_navigate(window, - frame->url, - hlcache_handle_get_url(parent), - BW_NAVIGATE_HISTORY | - BW_NAVIGATE_UNVERIFIABLE, - NULL, - NULL, - parent); - } - } - } - return NSERROR_OK; } @@ -416,10 +327,9 @@ nserror browser_window_create_frameset(struct browser_window *bw, /** * Recalculate frameset positions following a resize. * - * \param bw The browser window to reposition framesets for + * \param bw The browser window to reposition framesets for */ - -void browser_window_recalculate_frameset(struct browser_window *bw) +static void browser_window_recalculate_frameset_internal(struct browser_window *bw) { int widths[bw->cols][bw->rows]; int heights[bw->cols][bw->rows]; @@ -645,9 +555,177 @@ void browser_window_recalculate_frameset(struct browser_window *bw) x += widths[col][row]; if (window->children) - browser_window_recalculate_frameset(window); + browser_window_recalculate_frameset_internal(window); + } + } +} + + +/** + * Create and open a frameset for a browser window. + * + * \param[in,out] bw The browser window to create the frameset for + * \param[in] frameset The frameset to create + * \return NSERROR_OK or error code on faliure + */ +static nserror +browser_window_create_frameset_internal(struct browser_window *bw, + struct content_html_frames *frameset) +{ + int row, col, index; + struct content_html_frames *frame; + struct browser_window *window; + hlcache_handle *parent; + + assert(bw && frameset); + + /* 1. Create children */ + assert(bw->children == NULL); + assert(frameset->cols + frameset->rows != 0); + + bw->children = calloc((frameset->cols * frameset->rows), sizeof(*bw)); + if (!bw->children) { + return NSERROR_NOMEM; + } + + bw->cols = frameset->cols; + bw->rows = frameset->rows; + for (row = 0; row < bw->rows; row++) { + for (col = 0; col < bw->cols; col++) { + index = (row * bw->cols) + col; + frame = &frameset->children[index]; + window = &bw->children[index]; + + /* Initialise common parts */ + browser_window_initialise_common(BW_CREATE_NONE, + window, NULL); + + /* window characteristics */ + if (frame->children) + window->browser_window_type = + BROWSER_WINDOW_FRAMESET; + else + window->browser_window_type = + BROWSER_WINDOW_FRAME; + window->scrolling = frame->scrolling; + window->border = frame->border; + window->border_colour = frame->border_colour; + window->no_resize = frame->no_resize; + window->frame_width = frame->width; + window->frame_height = frame->height; + window->margin_width = frame->margin_width; + window->margin_height = frame->margin_height; + if (frame->name) { + window->name = strdup(frame->name); + if (!window->name) { + free(bw->children); + bw->children = NULL; + return NSERROR_NOMEM; + } + } + + window->scale = bw->scale; + + /* linking */ + window->parent = bw; + + if (window->name) + NSLOG(netsurf, INFO, "Created frame '%s'", + window->name); + else + NSLOG(netsurf, INFO, + "Created frame (unnamed)"); } } + + /* 2. Calculate dimensions */ + browser_window_update_extent(bw); + browser_window_recalculate_frameset_internal(bw); + + /* 3. Recurse for grandchildren */ + for (row = 0; row < bw->rows; row++) { + for (col = 0; col < bw->cols; col++) { + index = (row * bw->cols) + col; + frame = &frameset->children[index]; + window = &bw->children[index]; + + if (frame->children) + browser_window_create_frameset_internal(window, frame); + } + } + + /* Use the URL of the first ancestor window containing html content + * as the referer */ + for (window = bw; window->parent; window = window->parent) { + if (window->current_content && + content_get_type(window->current_content) == + CONTENT_HTML) + break; + } + + parent = window->current_content; + + /* 4. Launch content */ + for (row = 0; row < bw->rows; row++) { + for (col = 0; col < bw->cols; col++) { + index = (row * bw->cols) + col; + frame = &frameset->children[index]; + window = &bw->children[index]; + + if (frame->url) { + browser_window_navigate(window, + frame->url, + hlcache_handle_get_url(parent), + BW_NAVIGATE_HISTORY | + BW_NAVIGATE_UNVERIFIABLE, + NULL, + NULL, + parent); + } + } + } + + return NSERROR_OK; +} + + +/* exported interface documented in desktop/frames.h */ +nserror browser_window_create_frameset(struct browser_window *bw) +{ + struct content_html_frames *frameset; + + if (content_get_type(bw->current_content) != CONTENT_HTML) { + return NSERROR_OK; + } + + frameset = html_get_frameset(bw->current_content); + if (frameset == NULL) { + return NSERROR_OK; + } + + return browser_window_create_frameset_internal(bw, frameset); +} + + + + +/** + * Recalculate frameset positions following a resize. + * + * \param bw The browser window to reposition framesets for + */ + +void browser_window_recalculate_frameset(struct browser_window *bw) +{ + if (content_get_type(bw->current_content) != CONTENT_HTML) { + return; + } + + if (html_get_frameset(bw->current_content) == NULL) { + return; + } + + browser_window_recalculate_frameset_internal(bw); } @@ -702,7 +780,7 @@ void browser_window_resize_frame(struct browser_window *bw, int x, int y) } if (change) { - browser_window_recalculate_frameset(parent); + browser_window_recalculate_frameset_internal(parent); } } diff --git a/desktop/frames.h b/desktop/frames.h index 063e2c558..dda31824b 100644 --- a/desktop/frames.h +++ b/desktop/frames.h @@ -16,12 +16,13 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ -/** \file +/** + * \file * Frame and frameset creation and manipulation (interface). */ -#ifndef _NETSURF_DESKTOP_FRAMES_H_ -#define _NETSURF_DESKTOP_FRAMES_H_ +#ifndef NETSURF_DESKTOP_FRAMES_H_ +#define NETSURF_DESKTOP_FRAMES_H_ struct scrollbar_msg_data; struct content_html_iframe; @@ -30,23 +31,40 @@ struct content_html_frames; /** * Create and open iframes for a browser window. * - * \param bw The browser window to create iframes for. - * \param iframe The iframes to create from. + * \param bw The browser window to create iframes for. * \return NSERROR_OK or error code on faliure. */ -nserror browser_window_create_iframes(struct browser_window *bw, - struct content_html_iframe *iframe); +nserror browser_window_create_iframes(struct browser_window *bw); + +/** + * Recalculate iframe positions following a resize. + * + * \param bw The browser window to reposition iframes for + */ void browser_window_recalculate_iframes(struct browser_window *bw); /** + * Invalidate an iframe causing a redraw. + * + * \param bw The browser window to invalidate + */ +nserror browser_window_invalidate_iframe(struct browser_window *bw); + +/** + * Destroy iframes opened in browser_window_create_iframes() + * + * \param bw The browser window to destroy iframes for. + * \return NSERROR_OK + */ +nserror browser_window_destroy_iframes(struct browser_window *bw); + +/** * Create and open a frameset for a browser window. * * \param[in,out] bw The browser window to create the frameset for - * \param[in] frameset The frameset to create * \return NSERROR_OK or error code on faliure */ -nserror browser_window_create_frameset(struct browser_window *bw, - struct content_html_frames *frameset); +nserror browser_window_create_frameset(struct browser_window *bw); void browser_window_recalculate_frameset(struct browser_window *bw); bool browser_window_frame_resize_start(struct browser_window *bw, diff --git a/desktop/global_history.c b/desktop/global_history.c index ad39a3e41..e98e4cb29 100644 --- a/desktop/global_history.c +++ b/desktop/global_history.c @@ -266,9 +266,9 @@ static nserror global_history_create_treeview_field_data( const char *title = (data->title != NULL) ? data->title : messages_get("NoTitle"); char buffer[16]; - const char *last_visited; - char *last_visited2; - int len; + struct tm *lvtime; + char *last_visited = NULL; + size_t len = 0; e->data[GH_TITLE].field = gh_ctx.fields[GH_TITLE].field; e->data[GH_TITLE].value = strdup(title); @@ -279,16 +279,18 @@ static nserror global_history_create_treeview_field_data( e->data[GH_URL].value = nsurl_access(e->url); e->data[GH_URL].value_len = nsurl_length(e->url); - last_visited = ctime(&data->last_visit); - last_visited2 = strdup(last_visited); - if (last_visited2 != NULL) { - assert(last_visited2[24] == '\n'); - last_visited2[24] = '\0'; + if ((lvtime = localtime(&data->last_visit)) != NULL) { + const size_t lvsize = 256; + last_visited = malloc(lvsize); + if (last_visited != NULL) { + len = strftime(last_visited, lvsize, + "%a %b %e %H:%M:%S %Y", lvtime); + } } e->data[GH_LAST_VISIT].field = gh_ctx.fields[GH_LAST_VISIT].field; - e->data[GH_LAST_VISIT].value = last_visited2; - e->data[GH_LAST_VISIT].value_len = (last_visited2 != NULL) ? 24 : 0; + e->data[GH_LAST_VISIT].value = last_visited; + e->data[GH_LAST_VISIT].value_len = len; len = snprintf(buffer, 16, "%u", data->visits); if (len == 16) { diff --git a/desktop/gui_factory.c b/desktop/gui_factory.c index 8b52e5469..0d4d9a904 100644 --- a/desktop/gui_factory.c +++ b/desktop/gui_factory.c @@ -19,10 +19,13 @@ #include <stdlib.h> #include <stdint.h> #include <stdbool.h> +#include <string.h> +#include <unistd.h> #include "utils/config.h" #include "utils/errors.h" #include "utils/file.h" +#include "utils/inet.h" #include "netsurf/bitmap.h" #include "content/hlcache.h" #include "content/backing_store.h" @@ -471,6 +474,16 @@ static char *gui_default_mimetype(const char *path) return strdup(guit->fetch->filetype(path)); } +static int gui_default_socket_open(int domain, int type, int protocol) +{ + return (int) socket(domain, type, protocol); +} + +static int gui_default_socket_close(int fd) +{ + return (int) ns_close_socket(fd); +} + /** verify fetch table is valid */ static nserror verify_fetch_register(struct gui_fetch_table *gft) { @@ -497,6 +510,12 @@ static nserror verify_fetch_register(struct gui_fetch_table *gft) if (gft->mimetype == NULL) { gft->mimetype = gui_default_mimetype; } + if (gft->socket_open == NULL) { + gft->socket_open = gui_default_socket_open; + } + if (gft->socket_close == NULL) { + gft->socket_close = gui_default_socket_close; + } return NSERROR_OK; } @@ -559,10 +578,6 @@ static nserror verify_bitmap_register(struct gui_bitmap_table *gbt) return NSERROR_BAD_PARAMETER; } - if (gbt->test_opaque == NULL) { - return NSERROR_BAD_PARAMETER; - } - if (gbt->get_buffer == NULL) { return NSERROR_BAD_PARAMETER; } @@ -579,14 +594,6 @@ static nserror verify_bitmap_register(struct gui_bitmap_table *gbt) return NSERROR_BAD_PARAMETER; } - if (gbt->get_bpp == NULL) { - return NSERROR_BAD_PARAMETER; - } - - if (gbt->save == NULL) { - return NSERROR_BAD_PARAMETER; - } - if (gbt->modified == NULL) { return NSERROR_BAD_PARAMETER; } @@ -638,15 +645,6 @@ static nserror gui_default_launch_url(struct nsurl *url) } -static nserror gui_default_cert_verify(nsurl *url, - const struct ssl_cert_info *certs, - unsigned long num, - nserror (*cb)(bool proceed, void *pw), - void *cbpw) -{ - return NSERROR_NOT_IMPLEMENTED; -} - static nserror gui_default_401login_open( nsurl *url, const char *realm, const char *username, const char *password, @@ -666,6 +664,12 @@ gui_default_pdf_password(char **owner_pass, char **user_pass, char *path) save_pdf(path); } +static nserror +gui_default_present_cookies(const char *search_term) +{ + return NSERROR_NOT_IMPLEMENTED; +} + /** verify misc table is valid */ static nserror verify_misc_register(struct gui_misc_table *gmt) { @@ -686,15 +690,15 @@ static nserror verify_misc_register(struct gui_misc_table *gmt) if (gmt->launch_url == NULL) { gmt->launch_url = gui_default_launch_url; } - if (gmt->cert_verify == NULL) { - gmt->cert_verify = gui_default_cert_verify; - } if (gmt->login == NULL) { gmt->login = gui_default_401login_open; } if (gmt->pdf_password == NULL) { gmt->pdf_password = gui_default_pdf_password; } + if (gmt->present_cookies == NULL) { + gmt->present_cookies = gui_default_present_cookies; + } return NSERROR_OK; } diff --git a/desktop/hotlist.c b/desktop/hotlist.c index 4daaaed71..20c0890a1 100644 --- a/desktop/hotlist.c +++ b/desktop/hotlist.c @@ -193,29 +193,32 @@ static nserror hotlist_create_treeview_field_visits_data( struct hotlist_entry *e, const struct url_data *data) { char buffer[16]; - const char *last_visited; - char *last_visited2; - int len; + char *last_visited = NULL; + size_t len = 0; /* Last visited */ if (data->visits != 0) { - last_visited = ctime(&data->last_visit); - last_visited2 = strdup(last_visited); - len = 24; + const size_t lvsize = 256; + struct tm *lvtime; + + if ((lvtime = localtime(&data->last_visit)) != NULL) { + last_visited = malloc(lvsize); + if (last_visited != NULL) { + len = strftime(last_visited, lvsize, + "%a %b %e %H:%M:%S %Y", + lvtime); + } + } } else { - last_visited2 = strdup("-"); + last_visited = strdup("-"); len = 1; } - if (last_visited2 == NULL) { + if (last_visited == NULL) { return NSERROR_NOMEM; - - } else if (len == 24) { - assert(last_visited2[24] == '\n'); - last_visited2[24] = '\0'; } e->data[HL_LAST_VISIT].field = hl_ctx.fields[HL_LAST_VISIT].field; - e->data[HL_LAST_VISIT].value = last_visited2; + e->data[HL_LAST_VISIT].value = last_visited; e->data[HL_LAST_VISIT].value_len = len; /* Visits */ @@ -968,13 +971,13 @@ static nserror hotlist_generate(void) const char *url; const char *msg_key; } default_entries[] = { - { "http://www.netsurf-browser.org/", + { "https://www.netsurf-browser.org/", "HotlistHomepage" }, - { "http://www.netsurf-browser.org/downloads/", + { "https://www.netsurf-browser.org/downloads/", "HotlistDownloads" }, - { "http://www.netsurf-browser.org/documentation", + { "https://www.netsurf-browser.org/documentation", "HotlistDocumentation" }, - { "http://www.netsurf-browser.org/contact", + { "https://www.netsurf-browser.org/contact", "HotlistContact" } }; const int n_entries = sizeof(default_entries) / @@ -1403,6 +1406,9 @@ nserror hotlist_fini(void) /* Destroy the hotlist treeview */ err = treeview_destroy(hl_ctx.tree); + if (err != NSERROR_OK) { + NSLOG(netsurf, INFO, "Problem destroying the hotlist treeview."); + } hl_ctx.built = false; /* Free hotlist treeview entry fields */ @@ -1623,7 +1629,7 @@ nserror hotlist_add_entry(nsurl *url, const char *title, bool at_y, int y) enum treeview_relationship rel; if (url == NULL) { - err = nsurl_create("http://netsurf-browser.org/", &url); + err = nsurl_create("https://netsurf-browser.org/", &url); if (err != NSERROR_OK) { return err; } diff --git a/desktop/local_history.c b/desktop/local_history.c index aa70ebb42..5227c97e1 100644 --- a/desktop/local_history.c +++ b/desktop/local_history.c @@ -24,8 +24,9 @@ #include <stdlib.h> #include <string.h> -#include "utils/errors.h" #include "utils/nsurl.h" +#include "utils/errors.h" + #include "netsurf/types.h" #include "netsurf/layout.h" #include "netsurf/browser_window.h" @@ -33,11 +34,14 @@ #include "netsurf/plotters.h" #include "netsurf/keypress.h" +#include "utils/nscolour.h" + #include "desktop/cw_helper.h" #include "desktop/gui_internal.h" #include "desktop/system_colour.h" #include "desktop/browser_private.h" #include "desktop/browser_history.h" +#include "desktop/local_history_private.h" #include "desktop/local_history.h" /** @@ -173,17 +177,20 @@ redraw_entry(struct history *history, rect.y0 = entry->y - 1 + y; rect.x1 = entry->x + x + LOCAL_HISTORY_WIDTH; rect.y1 = entry->y + y + LOCAL_HISTORY_HEIGHT; - res = ctx->plot->rectangle(ctx, pstyle, &rect); - if (res != NSERROR_OK) { - return res; - } - /* If this is the cursor, show that */ - if (entry == cursor) { + /* Border */ + if (entry != cursor) { + /* Not cursor position */ + res = ctx->plot->rectangle(ctx, pstyle, &rect); + if (res != NSERROR_OK) { + return res; + } + } else { + /* Cursor position */ rect.x0 -= 1; rect.y0 -= 1; - rect.x1 += 2; - rect.y1 += 2; + rect.x1 += 1; + rect.y1 += 1; ctx->plot->rectangle(ctx, &pstyle_rect_cursor, &rect); } @@ -307,33 +314,19 @@ local_history_init(struct core_window_callback_table *cw_t, struct browser_window *bw, struct local_history_session **session) { - nserror res; struct local_history_session *nses; - res = ns_system_colour_char("Window", &pstyle_bg.fill_colour); - if (res != NSERROR_OK) { - return res; - } - pfstyle_node.background = pstyle_bg.fill_colour; - pfstyle_node_sel.background = pstyle_bg.fill_colour; + pstyle_bg.fill_colour = nscolours[NSCOLOUR_WIN_EVEN_BG]; + pstyle_line.stroke_colour = nscolours[NSCOLOUR_WIN_EVEN_BORDER]; - res = ns_system_colour_char("GrayText", &pstyle_line.stroke_colour); - if (res != NSERROR_OK) { - return res; - } pstyle_rect.stroke_colour = pstyle_line.stroke_colour; - pfstyle_node.foreground = pstyle_line.stroke_colour; - - res = ns_system_colour_char("ButtonText", &pstyle_rect_sel.stroke_colour); - if (res != NSERROR_OK) { - return res; - } - pfstyle_node_sel.foreground = pstyle_rect_sel.stroke_colour; + pstyle_rect_sel.stroke_colour = nscolours[NSCOLOUR_WIN_EVEN_BORDER]; + pstyle_rect_cursor.stroke_colour = nscolours[NSCOLOUR_SEL_BG]; - res = ns_system_colour_char("Highlight", &pstyle_rect_cursor.stroke_colour); - if (res != NSERROR_OK) { - return res; - } + pfstyle_node.foreground = nscolours[NSCOLOUR_WIN_EVEN_FG]; + pfstyle_node.background = nscolours[NSCOLOUR_WIN_EVEN_BG]; + pfstyle_node_sel.foreground = nscolours[NSCOLOUR_WIN_EVEN_FG]; + pfstyle_node_sel.background = nscolours[NSCOLOUR_WIN_EVEN_BG]; nses = calloc(1, sizeof(struct local_history_session)); if (nses == NULL) { diff --git a/desktop/local_history_private.h b/desktop/local_history_private.h new file mode 100644 index 000000000..fd25ab4d3 --- /dev/null +++ b/desktop/local_history_private.h @@ -0,0 +1,38 @@ +/* + * Copyright 2006 James Bursa <bursa@users.sourceforge.net> + * + * This file is part of NetSurf, http://www.netsurf-browser.org/ + * + * NetSurf is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * NetSurf is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +/** + * \file + * Interface to browser history private operations + */ + +#ifndef NETSURF_DESKTOP_BROWSER_HISTORY_PRIVATE_H +#define NETSURF_DESKTOP_BROWSER_HISTORY_PRIVATE_H + +#include "content/handlers/css/utils.h" + +#define LOCAL_HISTORY_WIDTH \ + (FIXTOINT(css_unit_css2device_px(INTTOFIX(116), nscss_screen_dpi))) +#define LOCAL_HISTORY_HEIGHT \ + (FIXTOINT(css_unit_css2device_px(INTTOFIX(100), nscss_screen_dpi))) +#define LOCAL_HISTORY_RIGHT_MARGIN \ + (FIXTOINT(css_unit_css2device_px(INTTOFIX( 50), nscss_screen_dpi))) +#define LOCAL_HISTORY_BOTTOM_MARGIN \ + (FIXTOINT(css_unit_css2device_px(INTTOFIX( 30), nscss_screen_dpi))) + +#endif diff --git a/desktop/netsurf.c b/desktop/netsurf.c index e3babd864..bd785898f 100644 --- a/desktop/netsurf.c +++ b/desktop/netsurf.c @@ -28,6 +28,8 @@ #include "netsurf/inttypes.h" #include "utils/config.h" +#include "utils/errors.h" +#include "utils/nscolour.h" #include "utils/nsoption.h" #include "utils/corestrings.h" #include "utils/log.h" @@ -49,6 +51,7 @@ #include "netsurf/browser_window.h" #include "desktop/system_colour.h" +#include "desktop/page-info.h" #include "desktop/searchweb.h" #include "netsurf/misc.h" #include "desktop/gui_internal.h" @@ -96,7 +99,7 @@ static void netsurf_lwc_iterator(lwc_string *str, void *pw) { - NSLOG(netsurf, WARNING, "[%3u] %.*s", str->refcnt, + NSLOG(netsurf, WARNING, "[%3"PRIu32"] %.*s", str->refcnt, (int)lwc_string_length(str), lwc_string_data(str)); } @@ -134,6 +137,10 @@ nserror netsurf_init(const char *store_path) if (ret != NSERROR_OK) return ret; + ret = nscolour_update(); + if (ret != NSERROR_OK) + return ret; + /* set up cache limits based on the memory cache size option */ hlcache_parameters.llcache.limit = nsoption_int(memory_cache_size); @@ -148,10 +155,10 @@ nserror netsurf_init(const char *store_path) hlcache_parameters.llcache.fetch_attempts = nsoption_uint(max_retried_fetches); /* image cache is 25% of total memory cache size */ - image_cache_parameters.limit = (hlcache_parameters.llcache.limit * 25) / 100; + image_cache_parameters.limit = hlcache_parameters.llcache.limit / 4; /* image cache hysteresis is 20% of the image cache size */ - image_cache_parameters.hysteresis = (image_cache_parameters.limit * 20) / 100; + image_cache_parameters.hysteresis = image_cache_parameters.limit / 5; /* account for image cache use from total */ hlcache_parameters.llcache.limit -= image_cache_parameters.limit; @@ -160,10 +167,13 @@ nserror netsurf_init(const char *store_path) hlcache_parameters.llcache.store.limit = nsoption_uint(disc_cache_size); /* set backing store hysterissi to 20% */ - hlcache_parameters.llcache.store.hysteresis = (hlcache_parameters.llcache.store.limit * 20) / 100;; + hlcache_parameters.llcache.store.hysteresis = hlcache_parameters.llcache.store.limit / 5; /* set the path to the backing store */ - hlcache_parameters.llcache.store.path = store_path; + hlcache_parameters.llcache.store.path = + nsoption_charp(disc_cache_path) ? + nsoption_charp(disc_cache_path) : + store_path; /* image handler bitmap cache */ ret = image_cache_init(&image_cache_parameters); @@ -206,6 +216,11 @@ nserror netsurf_init(const char *store_path) js_initialise(); + ret = page_info_init(); + if (ret != NSERROR_OK) { + return ret; + } + return NSERROR_OK; } @@ -220,7 +235,10 @@ void netsurf_exit(void) NSLOG(netsurf, INFO, "Closing GUI"); guit->misc->quit(); - + + NSLOG(netsurf, INFO, "Finalising page-info module"); + page_info_fini(); + NSLOG(netsurf, INFO, "Finalising JavaScript"); js_finalise(); diff --git a/desktop/options.h b/desktop/options.h index 9ae2b5ebb..b74fab829 100644 --- a/desktop/options.h +++ b/desktop/options.h @@ -16,7 +16,8 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ -/** \file +/** + * \file * Option available on all platforms * * Non-platform specific options can be added by editing this file @@ -27,8 +28,8 @@ * with different macro definitions so there is no guard */ -#ifndef _NETSURF_DESKTOP_OPTIONS_H_ -#define _NETSURF_DESKTOP_OPTIONS_H_ +#ifndef NETSURF_DESKTOP_OPTIONS_H_ +#define NETSURF_DESKTOP_OPTIONS_H_ #include "netsurf/types.h" @@ -91,6 +92,9 @@ NSOPTION_STRING(accept_charset, NULL) /** Preferred maximum size of memory cache / bytes. */ NSOPTION_INTEGER(memory_cache_size, 12 * 1024 * 1024) +/** Preferred location of disc cache, or NULL for system provided location */ +NSOPTION_STRING(disc_cache_path, NULL) + /** Preferred expiry size of disc cache / bytes. */ NSOPTION_UINT(disc_cache_size, 1024 * 1024 * 1024) @@ -104,9 +108,6 @@ NSOPTION_BOOL(block_advertisements, false) * http://www.w3.org/Submission/2011/SUBM-web-tracking-protection-20110224/#dnt-uas */ NSOPTION_BOOL(do_not_track, false) -/** Minimum GIF animation delay */ -NSOPTION_INTEGER(minimum_gif_delay, 10) - /** Whether to send the referer HTTP header */ NSOPTION_BOOL(send_referer, true) @@ -122,6 +123,9 @@ NSOPTION_BOOL(animate_images, true) /** Whether to execute javascript */ NSOPTION_BOOL(enable_javascript, false) +/** Whether to allow Author level CSS. */ +NSOPTION_BOOL(author_level_css, true) + /** Maximum time (in seconds) to wait for a script to run */ NSOPTION_INTEGER(script_timeout, 10) @@ -167,12 +171,6 @@ NSOPTION_INTEGER(window_width, 0) /** default height of new windows */ NSOPTION_INTEGER(window_height, 0) -/** width of screen when above options were saved */ -NSOPTION_INTEGER(window_screen_width, 0) - -/** height of screen when above options were saved */ -NSOPTION_INTEGER(window_screen_height, 0) - /** default size of status bar vs. h scroll bar */ NSOPTION_INTEGER(toolbar_status_size, 6667) @@ -260,6 +258,9 @@ NSOPTION_BOOL(enable_PDF_compression, true) /** setting a password and encoding PDF documents */ NSOPTION_BOOL(enable_PDF_password, false) +/** whether to prefer dark mode (light on dark) */ +NSOPTION_BOOL(prefer_dark_mode, false) + /******** System colours ********/ NSOPTION_COLOUR(sys_colour_ActiveBorder, 0x00d3d3d3) NSOPTION_COLOUR(sys_colour_ActiveCaption, 0x00f1f1f1) diff --git a/desktop/page-info.c b/desktop/page-info.c new file mode 100644 index 000000000..0991d071b --- /dev/null +++ b/desktop/page-info.c @@ -0,0 +1,836 @@ +/* + * Copyright 2020 Michael Drake <tlsa@netsurf-browser.org> + * + * This file is part of NetSurf, http://www.netsurf-browser.org/ + * + * NetSurf is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * NetSurf is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +/** + * \file + * Pave info viewer window implementation + */ + +#include <stdlib.h> +#include <string.h> + +#include "css/utils.h" + +#include "utils/nsurl.h" +#include "utils/nscolour.h" + +#include "netsurf/mouse.h" +#include "netsurf/layout.h" +#include "netsurf/keypress.h" +#include "netsurf/plotters.h" +#include "netsurf/core_window.h" +#include "netsurf/browser_window.h" + +#include "desktop/knockout.h" +#include "desktop/page-info.h" +#include "desktop/gui_internal.h" +#include "desktop/system_colour.h" + +/** + * Plot style for heading font. + */ +static plot_font_style_t pi__heading[PAGE_STATE__COUNT] = { + [PAGE_STATE_UNKNOWN] = { + .family = PLOT_FONT_FAMILY_SANS_SERIF, + .size = 14 * PLOT_STYLE_SCALE, + .flags = FONTF_NONE, + .weight = 400, + }, + [PAGE_STATE_INTERNAL] = { + .family = PLOT_FONT_FAMILY_SANS_SERIF, + .size = 14 * PLOT_STYLE_SCALE, + .flags = FONTF_NONE, + .weight = 400, + }, + [PAGE_STATE_LOCAL] = { + .family = PLOT_FONT_FAMILY_SANS_SERIF, + .size = 14 * PLOT_STYLE_SCALE, + .flags = FONTF_NONE, + .weight = 400, + }, + [PAGE_STATE_INSECURE] = { + .family = PLOT_FONT_FAMILY_SANS_SERIF, + .size = 14 * PLOT_STYLE_SCALE, + .flags = FONTF_NONE, + .weight = 400, + }, + [PAGE_STATE_SECURE_OVERRIDE] = { + .family = PLOT_FONT_FAMILY_SANS_SERIF, + .size = 14 * PLOT_STYLE_SCALE, + .flags = FONTF_NONE, + .weight = 400, + }, + [PAGE_STATE_SECURE_ISSUES] = { + .family = PLOT_FONT_FAMILY_SANS_SERIF, + .size = 14 * PLOT_STYLE_SCALE, + .flags = FONTF_NONE, + .weight = 400, + }, + [PAGE_STATE_SECURE] = { + .family = PLOT_FONT_FAMILY_SANS_SERIF, + .size = 14 * PLOT_STYLE_SCALE, + .flags = FONTF_NONE, + .weight = 400, + }, +}; + +/** + * Plot style for domain font. + */ +static plot_font_style_t pi__domain = { + .family = PLOT_FONT_FAMILY_SANS_SERIF, + .size = 8 * PLOT_STYLE_SCALE, + .flags = FONTF_NONE, + .weight = 700, +}; + +/** + * Plot style for item font. + */ +static plot_font_style_t pi__item = { + .family = PLOT_FONT_FAMILY_SANS_SERIF, + .size = 11 * PLOT_STYLE_SCALE, + .flags = FONTF_NONE, + .weight = 400, +}; + +/** + * Plot style for item detail font. + */ +static plot_font_style_t pi__item_detail = { + .family = PLOT_FONT_FAMILY_SANS_SERIF, + .size = 11 * PLOT_STYLE_SCALE, + .flags = FONTF_NONE, + .weight = 400, +}; + +/** + * Plot style for window background. + */ +static plot_style_t pi__bg = { + .fill_type = PLOT_OP_TYPE_SOLID, +}; + +/** + * Plot style for hover background. + */ +static plot_style_t pi__hover = { + .fill_type = PLOT_OP_TYPE_SOLID, +}; + +/** + * An "text" type page info entry. + */ +struct page_info_text { + const char *text; + const plot_font_style_t *style; + int width; + int height; + int padding_bottom; +}; + +/** + * An "item" type page info entry. + */ +struct page_info_item { + struct page_info_text item; + struct page_info_text detail; + const plot_style_t *hover_bg; + int padding_bottom; + int padding_top; + bool hover; +}; + +/** + * List of page info window entries. + */ +enum pi_entry { + PI_ENTRY_HEADER, + PI_ENTRY_DOMAIN, + PI_ENTRY_CERT, + PI_ENTRY_COOKIES, + PI_ENTRY__COUNT, +}; + +/** + * An entry on a page info window. + */ +struct page_info_entry { + /** + * List of page info entry types. + */ + enum page_info_entry_type { + PAGE_INFO_ENTRY_TYPE_TEXT, + PAGE_INFO_ENTRY_TYPE_ITEM, + } type; + /** + * Type-specific page info entry data. + */ + union { + struct page_info_text text; + struct page_info_item item; + } u; +}; + +/** + * The default page info window data. + */ +struct page_info_entry pi__entries[PI_ENTRY__COUNT] = { + [PI_ENTRY_HEADER] = { + .type = PAGE_INFO_ENTRY_TYPE_TEXT, + }, + [PI_ENTRY_DOMAIN] = { + .type = PAGE_INFO_ENTRY_TYPE_TEXT, + .u = { + .text = { + .style = &pi__domain, + }, + }, + }, + [PI_ENTRY_CERT] = { + .type = PAGE_INFO_ENTRY_TYPE_ITEM, + .u = { + .item = { + .item = { + .style = &pi__item, + }, + .detail = { + .style = &pi__item_detail, + }, + .hover_bg = &pi__hover, + }, + }, + }, + [PI_ENTRY_COOKIES] = { + .type = PAGE_INFO_ENTRY_TYPE_ITEM, + .u = { + .item = { + .item = { + .style = &pi__item, + }, + .detail = { + .style = &pi__item_detail, + }, + .hover_bg = &pi__hover, + }, + }, + }, +}; + +/** + * The page info window structure. + */ +struct page_info { + const struct core_window_callback_table *cw_t; + struct core_window *cw_h; + + struct browser_window *bw; + lwc_string *domain; + enum nsurl_scheme_type scheme; + + browser_window_page_info_state state; + unsigned cookies; + + char cookie_text[64]; + struct page_info_entry entries[PI_ENTRY__COUNT]; + + int width; + int height; + + int window_padding; +}; + +/* Exported interface documented in desktop/page_info.h */ +nserror page_info_init(void) +{ + pi__bg.fill_colour = nscolours[NSCOLOUR_WIN_EVEN_BG]; + pi__hover.fill_colour = nscolours[NSCOLOUR_WIN_EVEN_BG_HOVER]; + + pi__domain.background = nscolours[NSCOLOUR_WIN_EVEN_BG]; + pi__domain.foreground = nscolours[NSCOLOUR_WIN_EVEN_FG]; + + pi__item.background = nscolours[NSCOLOUR_WIN_EVEN_BG]; + pi__item.foreground = nscolours[NSCOLOUR_WIN_EVEN_FG]; + + pi__item_detail.background = nscolours[NSCOLOUR_WIN_EVEN_BG]; + pi__item_detail.foreground = nscolours[NSCOLOUR_WIN_EVEN_FG_FADED]; + + pi__heading[PAGE_STATE_UNKNOWN].background = nscolours[NSCOLOUR_WIN_EVEN_BG]; + pi__heading[PAGE_STATE_UNKNOWN].foreground = nscolours[NSCOLOUR_WIN_EVEN_FG_BAD]; + pi__heading[PAGE_STATE_INTERNAL].background = nscolours[NSCOLOUR_WIN_EVEN_BG]; + pi__heading[PAGE_STATE_INTERNAL].foreground = nscolours[NSCOLOUR_WIN_EVEN_FG]; + pi__heading[PAGE_STATE_LOCAL].background = nscolours[NSCOLOUR_WIN_EVEN_BG]; + pi__heading[PAGE_STATE_LOCAL].foreground = nscolours[NSCOLOUR_WIN_EVEN_FG]; + pi__heading[PAGE_STATE_INSECURE].background = nscolours[NSCOLOUR_WIN_EVEN_BG]; + pi__heading[PAGE_STATE_INSECURE].foreground = nscolours[NSCOLOUR_WIN_EVEN_FG_BAD]; + pi__heading[PAGE_STATE_SECURE_OVERRIDE].background = nscolours[NSCOLOUR_WIN_EVEN_BG]; + pi__heading[PAGE_STATE_SECURE_OVERRIDE].foreground = nscolours[NSCOLOUR_WIN_EVEN_FG_BAD]; + pi__heading[PAGE_STATE_SECURE_ISSUES].background = nscolours[NSCOLOUR_WIN_EVEN_BG]; + pi__heading[PAGE_STATE_SECURE_ISSUES].foreground = nscolours[NSCOLOUR_WIN_EVEN_FG_BAD]; + pi__heading[PAGE_STATE_SECURE].background = nscolours[NSCOLOUR_WIN_EVEN_BG]; + pi__heading[PAGE_STATE_SECURE].foreground = nscolours[NSCOLOUR_WIN_EVEN_FG_GOOD]; + + return NSERROR_OK; +} + +/* Exported interface documented in desktop/page_info.h */ +nserror page_info_fini(void) +{ + return NSERROR_OK; +} + +/** + * Measure the text in the page_info window. + * + * \param[in] pi The page info window handle. + * \return NSERROR_OK on success, appropriate error code otherwise. + */ +static nserror page_info__measure_text_entry( + struct page_info_text *pit) +{ + nserror err; + int height_px; + + err = guit->layout->width(pit->style, + pit->text, strlen(pit->text), + &pit->width); + if (err != NSERROR_OK) { + return err; + } + + /* \todo: This needs to be a helper in plot style or in nscss. */ + height_px = ((pit->style->size / PLOT_STYLE_SCALE) * + FIXTOINT(nscss_screen_dpi) + 36) / 72; + + pit->height = (height_px * 8 + 3) / 6; + + return NSERROR_OK; +} + +/** + * Measure the text in the page_info window. + * + * \param[in] pi The page info window handle. + * \return NSERROR_OK on success, appropriate error code otherwise. + */ +static nserror page_info__measure_text( + struct page_info *pi) +{ + nserror err; + + for (unsigned i = 0; i < PI_ENTRY__COUNT; i++) { + struct page_info_entry *entry = pi->entries + i; + int padding; + + switch (entry->type) { + case PAGE_INFO_ENTRY_TYPE_TEXT: + err = page_info__measure_text_entry( + &entry->u.text); + if (err != NSERROR_OK) { + return err; + } + if (i == PI_ENTRY_DOMAIN) { + entry->u.text.padding_bottom = + entry->u.text.height * 3 / 2; + } + break; + + case PAGE_INFO_ENTRY_TYPE_ITEM: + err = page_info__measure_text_entry( + &entry->u.item.item); + if (err != NSERROR_OK) { + return err; + } + err = page_info__measure_text_entry( + &entry->u.item.detail); + if (err != NSERROR_OK) { + return err; + } + padding = entry->u.item.item.height / 4; + entry->u.item.padding_top = padding; + entry->u.item.padding_bottom = padding; + + break; + } + } + + pi->window_padding = pi->entries[PI_ENTRY_DOMAIN] + .u.item.item.height / 2; + + return NSERROR_OK; +} + +/** + * Set the text for the page_info window. + * + * \todo Use messages for internationalisation. + * + * \param[in] pi The page info window handle. + * \return NSERROR_OK on success, appropriate error code otherwise. + */ +static nserror page_info__set_text( + struct page_info *pi) +{ + int printed; + static const char *header[PAGE_STATE__COUNT] = { + [PAGE_STATE_UNKNOWN] = "Provenance unknown", + [PAGE_STATE_INTERNAL] = "NetSurf data", + [PAGE_STATE_LOCAL] = "Local data", + [PAGE_STATE_INSECURE] = "Connection not secure", + [PAGE_STATE_SECURE_OVERRIDE] = "Connection not secure", + [PAGE_STATE_SECURE_ISSUES] = "Connection not secure", + [PAGE_STATE_SECURE] = "Connection is secure", + }; + static const char *certificate[PAGE_STATE__COUNT] = { + [PAGE_STATE_UNKNOWN] = "Missing", + [PAGE_STATE_INTERNAL] = "None", + [PAGE_STATE_LOCAL] = "None", + [PAGE_STATE_INSECURE] = "Not valid", + [PAGE_STATE_SECURE_OVERRIDE] = "Not valid", + [PAGE_STATE_SECURE_ISSUES] = "Not valid", + [PAGE_STATE_SECURE] = "Valid", + }; + + assert(pi != NULL); + assert(pi->state < PAGE_STATE__COUNT); + + pi->entries[PI_ENTRY_HEADER].u.text.style = &pi__heading[pi->state]; + pi->entries[PI_ENTRY_HEADER].u.text.text = header[pi->state]; + pi->entries[PI_ENTRY_DOMAIN].u.text.text = (pi->domain) ? + lwc_string_data(pi->domain) : "<No domain>"; + + pi->entries[PI_ENTRY_CERT].u.item.item.text = "Certificate: "; + pi->entries[PI_ENTRY_CERT].u.item.detail.text = certificate[pi->state]; + + printed = snprintf(pi->cookie_text, sizeof(pi->cookie_text), + "(%u in use)", pi->cookies); + if (printed < 0) { + return NSERROR_UNKNOWN; + + } else if ((unsigned) printed >= sizeof(pi->cookie_text)) { + return NSERROR_NOSPACE; + } + pi->entries[PI_ENTRY_COOKIES].u.item.item.text = "Cookies: "; + pi->entries[PI_ENTRY_COOKIES].u.item.detail.text = pi->cookie_text; + + return page_info__measure_text(pi); +} + +/** + * Create page info from a browser window. + * + * \param[in] pi The page info window handle. + * \param[in] bw Browser window to show page info for. + * \return NSERROR_OK on success, appropriate error code otherwise. + */ +static nserror page_info__create_from_bw( + struct page_info *pi, + struct browser_window *bw) +{ + nsurl *url = browser_window_access_url(bw); + + pi->bw = bw; + pi->state = browser_window_get_page_info_state(bw); + pi->cookies = browser_window_get_cookie_count(bw); + pi->domain = nsurl_get_component(url, NSURL_HOST); + pi->scheme = nsurl_get_scheme_type(url); + + return page_info__set_text(pi); +} + +/** + * Check whether an entry is relevant. + * + * \param[in] entry The page info entry to consider. + * \param[in] scheme URL scheme that the page info is for. + * \return true if the entry should be hidden, otherwise false. + */ +static inline bool page_info__hide_entry( + enum pi_entry entry, + enum nsurl_scheme_type scheme) +{ + switch (entry) { + case PI_ENTRY_CERT: + if (scheme != NSURL_SCHEME_HTTPS) { + return true; + } + break; + case PI_ENTRY_COOKIES: + if (scheme != NSURL_SCHEME_HTTP && + scheme != NSURL_SCHEME_HTTPS) { + return true; + } + break; + default: + break; + } + + return false; +} + +/** + * Lay out the page info window. + * + * \param[in] pi The page info window handle. + * \return NSERROR_OK on success, appropriate error code otherwise. + */ +static nserror page_info__layout( + struct page_info *pi) +{ + int cur_y = 0; + int max_x = 0; + + cur_y += pi->window_padding; + for (unsigned i = 0; i < PI_ENTRY__COUNT; i++) { + struct page_info_entry *entry = pi->entries + i; + + if (page_info__hide_entry(i, pi->scheme)) { + continue; + } + + switch (entry->type) { + case PAGE_INFO_ENTRY_TYPE_TEXT: + cur_y += entry->u.text.height; + if (max_x < entry->u.text.width) { + max_x = entry->u.text.width; + } + cur_y += entry->u.text.padding_bottom; + break; + + case PAGE_INFO_ENTRY_TYPE_ITEM: + { + int full_width = entry->u.item.item.width + + entry->u.item.detail.width; + cur_y += entry->u.item.padding_top; + cur_y += entry->u.item.item.height; + if (max_x < full_width) { + max_x = full_width; + } + cur_y += entry->u.item.padding_bottom; + } + break; + } + } + cur_y += pi->window_padding; + max_x += pi->window_padding * 2; + + pi->width = max_x; + pi->height = cur_y; + return pi->cw_t->update_size(pi->cw_h, max_x, cur_y); +} + +/* Exported interface documented in desktop/page_info.h */ +nserror page_info_create( + const struct core_window_callback_table *cw_t, + struct core_window *cw_h, + struct browser_window *bw, + struct page_info **pi_out) +{ + struct page_info *pi; + nserror err; + + pi = calloc(1, sizeof(*pi)); + if (pi == NULL) { + return NSERROR_NOMEM; + } + + pi->cw_t = cw_t; + pi->cw_h = cw_h; + + memcpy(pi->entries, pi__entries, sizeof(pi__entries)); + + err = page_info__create_from_bw(pi, bw); + if (err != NSERROR_OK) { + page_info_destroy(pi); + return err; + } + + err = page_info__layout(pi); + if (err != NSERROR_OK) { + page_info_destroy(pi); + return err; + } + + *pi_out = pi; + return NSERROR_OK; +} + +/* Exported interface documented in desktop/page_info.h */ +nserror page_info_destroy(struct page_info *pi) +{ + if (pi->domain != NULL) { + lwc_string_unref(pi->domain); + } + free(pi); + return NSERROR_OK; +} + +/* Exported interface documented in desktop/page_info.h */ +nserror page_info_set(struct page_info *pgi, struct browser_window *bw) +{ + nserror res; + + if (pgi->domain != NULL) { + lwc_string_unref(pgi->domain); + } + + res = page_info__create_from_bw(pgi, bw); + if (res == NSERROR_OK) { + res = page_info__layout(pgi); + } + + return res; +} + +/** + * Render a text entry. + * + * \param[in] pit The page info window handle. + * \param[in] x X-coordinate to plot at. + * \param[in] y Y-coordinate to plot at. + * \param[in] ctx Current redraw context. + * \return NSERROR_OK on success, appropriate error code otherwise. + */ +static nserror page_info__redraw_text_entry( + const struct page_info_text *pit, + int x, + int y, + const struct redraw_context *ctx) +{ + int baseline = (pit->height * 3 + 2) / 4; + + ctx->plot->text(ctx, pit->style, x, y + baseline, + pit->text, strlen(pit->text)); + + return NSERROR_OK; +} + +/* Exported interface documented in desktop/page_info.h */ +nserror page_info_redraw( + const struct page_info *pi, + int x, + int y, + const struct rect *clip, + const struct redraw_context *ctx) +{ + struct redraw_context new_ctx = *ctx; + struct rect r = { + .x0 = clip->x0 + x, + .y0 = clip->y0 + y, + .x1 = clip->x1 + x, + .y1 = clip->y1 + y, + }; + int cur_y = y; + nserror err; + + /* Start knockout rendering if it's available for this plotter. */ + if (ctx->plot->option_knockout) { + bool res = knockout_plot_start(ctx, &new_ctx); + if (res == false) { + return NSERROR_UNKNOWN; + } + } + + /* Set up clip rectangle and draw background. */ + new_ctx.plot->clip(&new_ctx, &r); + new_ctx.plot->rectangle(&new_ctx, &pi__bg, &r); + + cur_y += pi->window_padding; + for (unsigned i = 0; i < PI_ENTRY__COUNT; i++) { + const struct page_info_entry *entry = pi->entries + i; + int cur_x = x + pi->window_padding; + + if (page_info__hide_entry(i, pi->scheme)) { + continue; + } + + switch (entry->type) { + case PAGE_INFO_ENTRY_TYPE_TEXT: + err = page_info__redraw_text_entry( + &entry->u.text, + cur_x, cur_y, + &new_ctx); + if (err != NSERROR_OK) { + goto cleanup; + } + cur_y += entry->u.text.height; + cur_y += entry->u.text.padding_bottom; + break; + + case PAGE_INFO_ENTRY_TYPE_ITEM: + if (entry->u.item.hover) { + r.y0 = cur_y; + r.y1 = cur_y + entry->u.item.padding_top + + entry->u.item.item.height + + entry->u.item.padding_bottom; + new_ctx.plot->rectangle(&new_ctx, + &pi__hover, &r); + } + cur_y += entry->u.item.padding_top; + err = page_info__redraw_text_entry( + &entry->u.item.item, + cur_x, cur_y, + &new_ctx); + if (err != NSERROR_OK) { + goto cleanup; + } + cur_x += entry->u.item.item.width; + err = page_info__redraw_text_entry( + &entry->u.item.detail, + cur_x, cur_y, + &new_ctx); + if (err != NSERROR_OK) { + goto cleanup; + } + cur_y += entry->u.item.item.height; + cur_y += entry->u.item.padding_bottom; + break; + } + } + +cleanup: + /* Rendering complete */ + if (ctx->plot->option_knockout) { + bool res = knockout_plot_end(ctx); + if (res == false) { + return NSERROR_UNKNOWN; + } + } + + return NSERROR_OK; +} + +/** + * Handle any clicks on an item. + * + * \param[in] pi The page info window handle. + * \param[in] mouse The current mouse state. + * \param[in] clicked The page info window entry to consider clicks on. + * \param[out] did_something Set to true if this click did something + * \return NSERROR_OK on success, appropriate error code otherwise. + */ +static nserror page_info__handle_item_click( + struct page_info *pi, + enum browser_mouse_state mouse, + enum pi_entry clicked, + bool *did_something) +{ + nserror err; + + if (!(mouse & BROWSER_MOUSE_CLICK_1)) { + return NSERROR_OK; + } + + switch (clicked) { + case PI_ENTRY_CERT: + err = browser_window_show_certificates(pi->bw); + *did_something = true; + break; + case PI_ENTRY_COOKIES: + err = browser_window_show_cookies(pi->bw); + *did_something = true; + break; + default: + err = NSERROR_OK; + break; + } + + return err; +} + +/* Exported interface documented in desktop/page_info.h */ +nserror page_info_mouse_action( + struct page_info *pi, + enum browser_mouse_state mouse, + int x, + int y, + bool *did_something) +{ + int cur_y = 0; + nserror err; + + cur_y += pi->window_padding; + for (unsigned i = 0; i < PI_ENTRY__COUNT; i++) { + struct page_info_entry *entry = pi->entries + i; + bool hovering = false; + int height; + + if (page_info__hide_entry(i, pi->scheme)) { + continue; + } + + switch (entry->type) { + case PAGE_INFO_ENTRY_TYPE_TEXT: + cur_y += entry->u.text.height; + cur_y += entry->u.text.padding_bottom; + break; + + case PAGE_INFO_ENTRY_TYPE_ITEM: + height = entry->u.item.padding_top + + entry->u.item.item.height + + entry->u.item.padding_bottom; + + if (y >= cur_y && y < cur_y + height) { + hovering = true; + err = page_info__handle_item_click( + pi, mouse, i, did_something); + if (err != NSERROR_OK) { + return err; + } + } + if (entry->u.item.hover != hovering) { + int w, h; + struct rect r = { + .x0 = 0, + .y0 = cur_y, + .y1 = cur_y + height, + }; + pi->cw_t->get_window_dimensions( + pi->cw_h, &w, &h); + r.x1 = (pi->width > w) ? pi->width : w; + + pi->cw_t->invalidate(pi->cw_h, &r); + } + entry->u.item.hover = hovering; + cur_y += height; + break; + } + } + + return NSERROR_OK; +} + +/* Exported interface documented in desktop/page_info.h */ +bool page_info_keypress( + struct page_info *pi, + int32_t key) +{ + return NSERROR_OK; +} + +/* Exported interface documented in desktop/page_info.h */ +nserror page_info_get_size( + struct page_info *pi, + int *width, + int *height) +{ + *width = pi->width; + *height = pi->height; + + return NSERROR_OK; +} diff --git a/desktop/page-info.h b/desktop/page-info.h new file mode 100644 index 000000000..152a88496 --- /dev/null +++ b/desktop/page-info.h @@ -0,0 +1,151 @@ +/* + * Copyright 2020 Michael Drake <tlsa@netsurf-browser.org> + * + * This file is part of NetSurf, http://www.netsurf-browser.org/ + * + * NetSurf is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * NetSurf is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +/** + * \file + * Pave info viewer window interface + */ + +#ifndef NETSURF_DESKTOP_PAGE_INFO_H +#define NETSURF_DESKTOP_PAGE_INFO_H + +#include <stdint.h> +#include <stdbool.h> + +#include "utils/errors.h" +#include "netsurf/mouse.h" + +struct rect; +struct nsurl; +struct page_info; +struct core_window; +struct browser_window; +struct redraw_context; +struct core_window_callback_table; + +/** + * Initialise the page_info module. + * + * \return NSERROR_OK on success, appropriate error code otherwise. + */ +nserror page_info_init(void); + +/** + * Finalise the page_info module. + * + * \return NSERROR_OK on success, appropriate error code otherwise. + */ +nserror page_info_fini(void); + +/** + * Create a page info corewindow. + * + * The page info window is opened for a particular browser window. + * It can be destroyed before the browser window is destroyed by calling + * \ref page_info_destroy. + * + * \param[in] cw_t Callback table for the containing core_window. + * \param[in] cw_h Handle for the containing core_window. + * \param[in] bw Browser window to show page info for. + * \param[out] pi_out The created page info window handle. + * \return NSERROR_OK on success, appropriate error code otherwise. + */ +nserror page_info_create( + const struct core_window_callback_table *cw_t, + struct core_window *cw_h, + struct browser_window *bw, + struct page_info **pi_out); + +/** + * Destroy a page info corewindow. + * + * \param[in] pi The page info window handle. + */ +nserror page_info_destroy(struct page_info *pi); + +/** + * change the browser window the page information refers to + * + * \param[in] pgi The page info window context + * \param[in] bw The new browser window + * \return NSERROR_OK on sucess else error code. + */ +nserror page_info_set(struct page_info *pgi, struct browser_window *bw); + +/** + * Redraw the page info window. + * + * Causes the page info window to issue plot operations to redraw + * the specified area of the viewport. + * + * \param[in] pi The page info window handle. + * \param[in] x X coordinate to render page_info at. + * \param[in] y Y coordinate to render page_info at. + * \param[in] clip Current clip rectangle. + * \param[in] ctx Current redraw context. + * \return NSERROR_OK on success, appropriate error code otherwise. + */ +nserror page_info_redraw( + const struct page_info *pi, + int x, + int y, + const struct rect *clip, + const struct redraw_context *ctx); + +/** + * Mouse action handling. + * + * \param[in] pi The page info window handle. + * \param[in] mouse The current mouse state + * \param[in] x The current mouse X coordinate + * \param[in] y The current mouse Y coordinate + * \param[out] did_something Set to true if this resulted in some action + * \return NSERROR_OK on success, appropriate error code otherwise. + */ +nserror page_info_mouse_action( + struct page_info *pi, + enum browser_mouse_state mouse, + int x, + int y, + bool *did_something); + +/** + * Key press handling. + * + * \param[in] pi The page info window handle. + * \param[in] key The ucs4 character codepoint. + * \return true if the keypress is dealt with, false otherwise. + */ +bool page_info_keypress( + struct page_info *pi, + int32_t key); + +/** + * Get size of page info content area. + * + * \param[in] pi The page info window handle. + * \param[out] width On success, return the page info content width. + * \param[out] height On success, return the page info content height. + * \return NSERROR_OK on success, appropriate error code otherwise. + */ +nserror page_info_get_size( + struct page_info *pi, + int *width, + int *height); + +#endif diff --git a/desktop/print.c b/desktop/print.c index de579dcf2..e90e322ac 100644 --- a/desktop/print.c +++ b/desktop/print.c @@ -257,9 +257,9 @@ struct print_settings *print_make_settings(print_configuration configuration, struct print_settings *settings; css_fixed length = 0; css_unit unit = CSS_UNIT_MM; - nscss_len_ctx len_ctx = { - .vw = DEFAULT_PAGE_WIDTH, - .vh = DEFAULT_PAGE_HEIGHT, + css_unit_ctx unit_len_ctx = { + .viewport_width = DEFAULT_PAGE_WIDTH, + .viewport_height = DEFAULT_PAGE_HEIGHT, .root_style = NULL, }; @@ -277,17 +277,17 @@ struct print_settings *print_make_settings(print_configuration configuration, settings->scale = DEFAULT_EXPORT_SCALE; length = INTTOFIX(DEFAULT_MARGIN_LEFT_MM); - settings->margins[MARGINLEFT] = nscss_len2px( - &len_ctx, length, unit, NULL); + settings->margins[MARGINLEFT] = css_unit_len2device_px( + NULL, &unit_len_ctx, length, unit); length = INTTOFIX(DEFAULT_MARGIN_RIGHT_MM); - settings->margins[MARGINRIGHT] = nscss_len2px( - &len_ctx, length, unit, NULL); + settings->margins[MARGINRIGHT] = css_unit_len2device_px( + NULL, &unit_len_ctx, length, unit); length = INTTOFIX(DEFAULT_MARGIN_TOP_MM); - settings->margins[MARGINTOP] = nscss_len2px( - &len_ctx, length, unit, NULL); + settings->margins[MARGINTOP] = css_unit_len2device_px( + NULL, &unit_len_ctx, length, unit); length = INTTOFIX(DEFAULT_MARGIN_BOTTOM_MM); - settings->margins[MARGINBOTTOM] = nscss_len2px( - &len_ctx, length, unit, NULL); + settings->margins[MARGINBOTTOM] = css_unit_len2device_px( + NULL, &unit_len_ctx, length, unit); break; /* use settings from the Export options tab */ case PRINT_OPTIONS: @@ -303,17 +303,17 @@ struct print_settings *print_make_settings(print_configuration configuration, settings->scale = (float)nsoption_int(export_scale) / 100; length = INTTOFIX(nsoption_int(margin_left)); - settings->margins[MARGINLEFT] = nscss_len2px( - &len_ctx, length, unit, NULL); + settings->margins[MARGINLEFT] = css_unit_len2device_px( + NULL, &unit_len_ctx, length, unit); length = INTTOFIX(nsoption_int(margin_right)); - settings->margins[MARGINRIGHT] = nscss_len2px( - &len_ctx, length, unit, NULL); + settings->margins[MARGINRIGHT] = css_unit_len2device_px( + NULL, &unit_len_ctx, length, unit); length = INTTOFIX(nsoption_int(margin_top)); - settings->margins[MARGINTOP] = nscss_len2px( - &len_ctx, length, unit, NULL); + settings->margins[MARGINTOP] = css_unit_len2device_px( + NULL, &unit_len_ctx, length, unit); length = INTTOFIX(nsoption_int(margin_bottom)); - settings->margins[MARGINBOTTOM] = nscss_len2px( - &len_ctx, length, unit, NULL); + settings->margins[MARGINBOTTOM] = css_unit_len2device_px( + NULL, &unit_len_ctx, length, unit); break; default: return NULL; diff --git a/desktop/save_complete.c b/desktop/save_complete.c index 24c188145..e4fadd274 100644 --- a/desktop/save_complete.c +++ b/desktop/save_complete.c @@ -51,7 +51,7 @@ #include "desktop/gui_internal.h" #include "desktop/save_complete.h" -regex_t save_complete_import_re; +static regex_t save_complete_import_re; /** An entry in save_complete_list. */ typedef struct save_complete_entry { @@ -196,7 +196,7 @@ save_complete_save_buffer(save_complete_ctx *ctx, * perform a posix regexec on a string without a null terminator */ static int -snregexec(const regex_t *preg, +snregexec(regex_t *preg, const char *string, size_t stringlen, size_t nmatch, diff --git a/desktop/scrollbar.c b/desktop/scrollbar.c index af5536ba4..90ea924cc 100644 --- a/desktop/scrollbar.c +++ b/desktop/scrollbar.c @@ -29,6 +29,7 @@ #include "utils/log.h" #include "utils/messages.h" #include "utils/utils.h" +#include "utils/nscolour.h" #include "utils/nsoption.h" #include "netsurf/browser_window.h" #include "netsurf/mouse.h" @@ -250,29 +251,17 @@ scrollbar_redraw(struct scrollbar *s, plot_style_t bg_fill_style = { .fill_type = PLOT_OP_TYPE_SOLID, + .fill_colour = nscolours[NSCOLOUR_SCROLL_WELL], }; plot_style_t fg_fill_style = { .fill_type = PLOT_OP_TYPE_SOLID, + .fill_colour = nscolours[NSCOLOUR_BUTTON_BG], }; plot_style_t arrow_fill_style = { .fill_type = PLOT_OP_TYPE_SOLID, + .fill_colour = nscolours[NSCOLOUR_BUTTON_FG], }; - res = ns_system_colour_char("Scrollbar", &bg_fill_style.fill_colour); - if (res != NSERROR_OK) { - return res; - } - - res = ns_system_colour_char("ButtonFace", &fg_fill_style.fill_colour); - if (res != NSERROR_OK) { - return res; - } - - res = ns_system_colour_char("ButtonText", &arrow_fill_style.fill_colour); - if (res != NSERROR_OK) { - return res; - } - area.x0 = x; area.y0 = y; area.x1 = x + (s->horizontal ? s->length : SCROLLBAR_WIDTH) - 1; diff --git a/desktop/scrollbar.h b/desktop/scrollbar.h index fa5e167f2..796520724 100644 --- a/desktop/scrollbar.h +++ b/desktop/scrollbar.h @@ -38,6 +38,7 @@ #define SCROLL_BOTTOM INT_MAX struct scrollbar; +struct redraw_context; /** * scrollbar message types diff --git a/desktop/search.c b/desktop/search.c index 3d3e7704f..e21f520a6 100644 --- a/desktop/search.c +++ b/desktop/search.c @@ -23,7 +23,10 @@ * Free text search (core) */ -#include "content/content.h" +#include <stdbool.h> + +#include "utils/errors.h" +#include "content/textsearch.h" #include "netsurf/types.h" #include "netsurf/browser_window.h" @@ -36,7 +39,7 @@ void browser_window_search(struct browser_window *bw, void *context, { if ((bw != NULL) && (bw->current_content != NULL)) { - content_search(bw->current_content, context, flags, string); + content_textsearch(bw->current_content, context, flags, string); } } @@ -45,6 +48,6 @@ void browser_window_search_clear(struct browser_window *bw) { if ((bw != NULL) && (bw->current_content != NULL)) { - content_search_clear(bw->current_content); + content_textsearch_clear(bw->current_content); } } diff --git a/desktop/search.h b/desktop/search.h index baf382e77..c39d1d8a3 100644 --- a/desktop/search.h +++ b/desktop/search.h @@ -16,11 +16,13 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ -#ifndef _NETSURF_DESKTOP_SEARCH_H_ -#define _NETSURF_DESKTOP_SEARCH_H_ +/** + * \file + * Browseing window text search interface + */ -#include <ctype.h> -#include <string.h> +#ifndef NETSURF_DESKTOP_SEARCH_H_ +#define NETSURF_DESKTOP_SEARCH_H_ struct browser_window; diff --git a/desktop/searchweb.c b/desktop/searchweb.c index 2c0873de5..361860190 100644 --- a/desktop/searchweb.c +++ b/desktop/searchweb.c @@ -22,6 +22,7 @@ */ #include <stdlib.h> +#include <string.h> #include "utils/utils.h" #include "utils/log.h" @@ -52,7 +53,7 @@ static struct search_web_ctx_s { } search_web_ctx; -static const char *default_providers = "Google|www.google.com|http://www.google.com/search?q=%s|http://www.google.com/favicon.ico|\n"; +static const char *default_providers = "Google|www.google.com|https://www.google.com/search?q=%s|https://www.google.com/favicon.ico|\n"; static const char *default_search_icon_url = "resource:icons/search.png"; @@ -332,11 +333,11 @@ search_web_omni(const char *term, } /* try with adding default scheme */ - eterm = malloc(strlen(term) + SLEN("http://") + 1); + eterm = malloc(strlen(term) + SLEN("https://") + 1); if (eterm == NULL) { return NSERROR_NOMEM; } - sprintf(eterm, "http://%s", term); + sprintf(eterm, "https://%s", term); ret = nsurl_create(eterm, &url); free(eterm); if (ret == NSERROR_OK) { diff --git a/desktop/searchweb.h b/desktop/searchweb.h index 69748b6d6..0712de9fe 100644 --- a/desktop/searchweb.h +++ b/desktop/searchweb.h @@ -62,7 +62,7 @@ enum search_web_omni_flags { * term. The flags allow control over the operation. By default the * operations are: * - interpret the \a term as a url - * - if missing a scheme as a http: url + * - if missing a scheme as a https: url * - combined with the search providers url into a url for that provider. * * \param term The search term. diff --git a/desktop/selection.c b/desktop/selection.c index c8edda7b1..8b1f127c4 100644 --- a/desktop/selection.c +++ b/desktop/selection.c @@ -17,49 +17,25 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ -/** \file - * Text selection within browser windows (implementation). - */ +/** + * \file + * implementation of text selection within browser windows. + */ -#include <assert.h> -#include <stdio.h> #include <stdlib.h> -#include <stdbool.h> #include <string.h> -#include <dom/dom.h> -#include "utils/log.h" -#include "utils/utf8.h" -#include "utils/utils.h" -#include "netsurf/form.h" -#include "html/box.h" -#include "html/html_internal.h" -#include "html/font.h" -#include "text/textplain.h" +#include "netsurf/clipboard.h" #include "netsurf/browser_window.h" +#include "netsurf/window.h" +#include "utils/utils.h" +#include "content/content_protected.h" -#include "netsurf/mouse.h" #include "desktop/browser_private.h" -#include "netsurf/plotters.h" -#include "desktop/save_text.h" -#include "desktop/selection.h" -#include "netsurf/clipboard.h" -#include "netsurf/window.h" #include "desktop/gui_internal.h" - -/** - * Text selection works by labelling each node in the box tree with its - * start index in the textual representation of the tree's content. - */ - -#define SPACE_LEN(b) ((b->space == 0) ? 0 : 1) +#include "desktop/selection.h" -struct rdw_info { - bool inited; - struct rect r; -}; - struct selection_string { char *buffer; size_t buffer_len; @@ -70,750 +46,414 @@ struct selection_string { }; -typedef bool (*seln_traverse_handler)(const char *text, size_t length, - struct box *box, const nscss_len_ctx *len_ctx, void *handle, - const char *whitespace_text, size_t whitespace_length); +typedef enum { + DRAG_NONE, + DRAG_START, + DRAG_END +} seln_drag_state; +struct selection { + struct content *c; -static bool redraw_handler(const char *text, size_t length, - struct box *box, const nscss_len_ctx *len_ctx, - void *handle, const char *whitespace_text, - size_t whitespace_length); -static void selection_redraw(struct selection *s, unsigned start_idx, - unsigned end_idx); -static bool selected_part(struct box *box, unsigned start_idx, unsigned end_idx, - unsigned *start_offset, unsigned *end_offset); -static bool traverse_tree(struct box *box, const nscss_len_ctx *len_ctx, - unsigned start_idx, unsigned end_idx, - seln_traverse_handler handler, - void *handle, save_text_whitespace *before, bool *first, - bool do_marker); -static unsigned selection_label_subtree(struct box *box, unsigned idx); + unsigned max_idx; /* total bytes in text representation */ -/** - * Get the browser window containing the content a selection object belongs to. - * - * \param s selection object - * \return the browser window - */ -static struct browser_window * selection_get_browser_window(struct selection *s) -{ - if (s->is_html) - return html_get_browser_window(s->c); - else - return textplain_get_browser_window(s->c); -} + unsigned start_idx; /* offset in bytes within text representation */ + unsigned end_idx; + + bool defined; + seln_drag_state drag_state; +}; /** - * Creates a new selection object associated with a browser window. + * Redraws the given range of text. * - * \return new selection context + * \param s selection object + * \param start_idx start offset (bytes) within the textual representation + * \param end_idx end offset (bytes) within the textual representation */ - -struct selection *selection_create(struct content *c, bool is_html) +static nserror +selection_redraw(struct selection *s, unsigned start_idx, unsigned end_idx) { - struct selection *s = calloc(1, sizeof(struct selection)); - if (s) { - selection_prepare(s, c, is_html); + nserror res; + + if (s->c->handler->textselection_redraw != NULL) { + res = s->c->handler->textselection_redraw(s->c, + start_idx, + end_idx); + } else { + res = NSERROR_NOT_IMPLEMENTED; } - return s; + return res; } + /** - * Prepare a newly created selection object for use. + * Set the start position of the current selection, updating the screen. * - * \param s selection object - * \param c content - * \param is_html true if content is html false if content is textplain + * \param s selection object + * \param offset byte offset within textual representation */ - -void selection_prepare(struct selection *s, struct content *c, bool is_html) +static void selection_set_start(struct selection *s, unsigned offset) { - if (s) { - s->c = c; - s->is_html = is_html; - s->root = NULL; - s->drag_state = DRAG_NONE; - s->max_idx = 0; - selection_clear(s, false); - } -} + bool was_defined; + unsigned old_start; + old_start = s->start_idx; + s->start_idx = offset; -/** - * Destroys a selection object, without updating the - * owning window (caller should call selection_clear() - * first if update is desired) - * - * \param s selection object - */ + was_defined = s->defined; + s->defined = (s->start_idx < s->end_idx); -void selection_destroy(struct selection *s) -{ - if (s != NULL) - free(s); + if (was_defined) { + if (offset < old_start) { + selection_redraw(s, s->start_idx, old_start); + } else { + selection_redraw(s, old_start, s->start_idx); + } + } else if (s->defined) { + selection_redraw(s, s->start_idx, s->end_idx); + } } /** - * Initialise the selection object to use the given box subtree as its root, - * ie. selections are confined to that subtree, whilst maintaining the current - * selection whenever possible because, for example, it's just the page being - * resized causing the layout to change. + * Set the end position of the current selection, updating the screen. * - * \param s selection object - * \param root the root box for html document or NULL for text/plain + * \param s selection object + * \param offset byte offset within textual representation */ - -void selection_reinit(struct selection *s, struct box *root) +static void selection_set_end(struct selection *s, unsigned offset) { - unsigned root_idx; - - assert(s); + bool was_defined; + unsigned old_end; - root_idx = 0; + old_end = s->end_idx; + s->end_idx = offset; - s->root = root; - if (root) { - s->max_idx = selection_label_subtree(root, root_idx); - } else { - if (s->is_html == false) - s->max_idx = textplain_size(s->c); - else - s->max_idx = 0; - } + was_defined = s->defined; + s->defined = (s->start_idx < s->end_idx); - if (s->defined) { - if (s->end_idx > s->max_idx) s->end_idx = s->max_idx; - if (s->start_idx > s->max_idx) s->start_idx = s->max_idx; - s->defined = (s->end_idx > s->start_idx); + if (was_defined) { + if (offset < old_end) { + selection_redraw(s, s->end_idx, old_end); + } else { + selection_redraw(s, old_end, s->end_idx); + } + } else if (s->defined) { + selection_redraw(s, s->start_idx, s->end_idx); } } /** - * Initialise the selection object to use the given box subtree as its root, - * ie. selections are confined to that subtree. + * Traverse the current selection, calling the handler function (with its + * handle) for all boxes that lie (partially) within the given range * - * \param s selection object - * \param root the root box for html document or NULL for text/plain + * \param s The selection context. + * \param handler handler function to call + * \param handle handle to pass + * \return false iff traversal abandoned part-way through */ - -void selection_init( - struct selection *s, - struct box *root, - const nscss_len_ctx *len_ctx) +static bool +selection_copy(struct selection *s, struct selection_string *selstr) { - if (s->defined) - selection_clear(s, true); + nserror res; - s->defined = false; - s->start_idx = 0; - s->end_idx = 0; - s->drag_state = DRAG_NONE; - if (len_ctx != NULL) { - s->len_ctx = *len_ctx; + if (s->c->handler->textselection_copy != NULL) { + res = s->c->handler->textselection_copy(s->c, + s->start_idx, + s->end_idx, + selstr); } else { - s->len_ctx.vw = 0; - s->len_ctx.vh = 0; - s->len_ctx.root_style = NULL; + res = NSERROR_NOT_IMPLEMENTED; } - selection_reinit(s, root); -} - - -/** - * Label each text box in the given box subtree with its position - * in a textual representation of the content. - * - * \param box The box at root of subtree - * \param idx current position within textual representation - * \return updated position - */ - -unsigned selection_label_subtree(struct box *box, unsigned idx) -{ - struct box *child = box->children; - - box->byte_offset = idx; - - if (box->text) - idx += box->length + SPACE_LEN(box); - - while (child) { - if (child->list_marker) - idx = selection_label_subtree(child->list_marker, idx); - - idx = selection_label_subtree(child, idx); - child = child->next; + if (res != NSERROR_OK) { + return false; } - - return idx; + return true; } /** - * Handles mouse clicks (including drag starts) in or near a selection - * - * \param s selection object - * \param mouse state of mouse buttons and modifier keys - * \param idx byte offset within textual representation + * Append text to selection string. * - * \return true iff the click has been handled by the selection code + * \param text text to be added + * \param length length of text in bytes + * \param space indicates whether a trailing space should be appended + * \param style The font style to use. + * \param sel_string string to append to, may be resized + * \return true iff successful */ - -bool selection_click(struct selection *s, browser_mouse_state mouse, - unsigned idx) +bool +selection_string_append(const char *text, + size_t length, + bool space, + plot_font_style_t *style, + struct selection_string *sel_string) { - browser_mouse_state modkeys = - (mouse & (BROWSER_MOUSE_MOD_1 | BROWSER_MOUSE_MOD_2)); - int pos = -1; /* 0 = inside selection, 1 = after it */ - struct browser_window *top = selection_get_browser_window(s); - top = browser_window_get_root(top); - - if (selection_defined(s)) { - if (idx > s->start_idx) { - if (idx <= s->end_idx) - pos = 0; - else - pos = 1; - } - } - - if (!pos && - ((mouse & BROWSER_MOUSE_DRAG_1) || - (modkeys && (mouse & BROWSER_MOUSE_DRAG_2)))) { - /* drag-saving selection */ - char *sel = selection_get_copy(s); - guit->window->drag_save_selection(top->window, sel); - free(sel); - } - else if (!modkeys) { - if (pos && (mouse & BROWSER_MOUSE_PRESS_1)) { - /* Clear the selection if mouse is pressed outside the - * selection, Otherwise clear on release (to allow for drags) */ - - selection_clear(s, true); - } else if (mouse & BROWSER_MOUSE_DRAG_1) { - /* start new selection drag */ + size_t new_length = sel_string->length + length + (space ? 1 : 0) + 1; - selection_clear(s, true); - - selection_set_start(s, idx); - selection_set_end(s, idx); + if (style != NULL) { + /* Add text run style */ + nsclipboard_styles *new_styles; - s->drag_state = DRAG_END; + if (sel_string->n_styles == 0) { + assert(sel_string->length == 0); + } - guit->window->event(top->window, GW_EVENT_START_SELECTION); + new_styles = realloc(sel_string->styles, + (sel_string->n_styles + 1) * + sizeof(nsclipboard_styles)); + if (new_styles == NULL) { + return false; } - else if (mouse & BROWSER_MOUSE_DRAG_2) { - /* adjust selection, but only if there is one */ - if (!selection_defined(s)) - return false; /* ignore Adjust drags */ + sel_string->styles = new_styles; - if (pos >= 0) { - selection_set_end(s, idx); + sel_string->styles[sel_string->n_styles].style = *style; + sel_string->styles[sel_string->n_styles].start = + sel_string->length; - s->drag_state = DRAG_END; - } - else { - selection_set_start(s, idx); + sel_string->n_styles++; + } - s->drag_state = DRAG_START; - } + if (new_length > sel_string->buffer_len) { + /* Need to extend buffer */ + size_t new_alloc = new_length + (new_length / 4); + char *new_buff; - guit->window->event(top->window, GW_EVENT_START_SELECTION); + new_buff = realloc(sel_string->buffer, new_alloc); + if (new_buff == NULL) { + return false; } - else if (mouse & BROWSER_MOUSE_CLICK_2) { - - /* ignore Adjust clicks when there's no selection */ - if (!selection_defined(s)) - return false; - if (pos >= 0) - selection_set_end(s, idx); - else - selection_set_start(s, idx); - s->drag_state = DRAG_NONE; - } - else - return false; - } - else { - /* not our problem */ - return false; + sel_string->buffer = new_buff; + sel_string->buffer_len = new_alloc; } - /* this mouse click is selection-related */ - return true; -} - - -/** - * Handles movements related to the selection, eg. dragging of start and - * end points. - * - * \param s selection object - * \param mouse state of mouse buttons and modifier keys - * \param idx byte offset within text representation - */ + /* Copy text onto end of existing text in buffer */ + memcpy(sel_string->buffer + sel_string->length, text, length); + sel_string->length += length; -void selection_track(struct selection *s, browser_mouse_state mouse, - unsigned idx) -{ - if (!mouse) { - s->drag_state = DRAG_NONE; + if (space) { + sel_string->buffer[sel_string->length++] = ' '; } - switch (s->drag_state) { - - case DRAG_START: - if (idx > s->end_idx) { - unsigned old_end = s->end_idx; - selection_set_end(s, idx); - selection_set_start(s, old_end); - s->drag_state = DRAG_END; - } - else - selection_set_start(s, idx); - break; - - case DRAG_END: - if (idx < s->start_idx) { - unsigned old_start = s->start_idx; - selection_set_start(s, idx); - selection_set_end(s, old_start); - s->drag_state = DRAG_START; - } - else - selection_set_end(s, idx); - break; + /* Ensure NULL termination */ + sel_string->buffer[sel_string->length] = '\0'; - default: - break; - } + return true; } -/** - * Tests whether a text box lies partially within the given range of - * byte offsets, returning the start and end indexes of the bytes - * that are enclosed. - * - * \param box box to be tested - * \param start_idx byte offset of start of range - * \param end_idx byte offset of end of range - * \param start_offset receives the start offset of the selected part - * \param end_offset receives the end offset of the selected part - * \return true iff the range encloses at least part of the box - */ - -bool selected_part(struct box *box, unsigned start_idx, unsigned end_idx, - unsigned *start_offset, unsigned *end_offset) +/* exported interface documented in desktop/selection.h */ +struct selection *selection_create(struct content *c) { - size_t box_length = box->length + SPACE_LEN(box); - - if (box_length > 0) { - if (box->byte_offset >= start_idx && - box->byte_offset + box_length <= end_idx) { - - /* fully enclosed */ - *start_offset = 0; - *end_offset = box_length; - return true; - } - else if (box->byte_offset + box_length > start_idx && - box->byte_offset < end_idx) { - /* partly enclosed */ - int offset = 0; - int len; - - if (box->byte_offset < start_idx) - offset = start_idx - box->byte_offset; - - len = box_length - offset; - - if (box->byte_offset + box_length > end_idx) - len = end_idx - (box->byte_offset + offset); - - *start_offset = offset; - *end_offset = offset + len; - - return true; - } + struct selection *sel; + sel = calloc(1, sizeof(struct selection)); + if (sel) { + sel->c = c; + sel->drag_state = DRAG_NONE; + sel->max_idx = 0; + selection_clear(sel, false); } - return false; + + return sel; } -/** - * Traverse the given box subtree, calling the handler function (with its handle) - * for all boxes that lie (partially) within the given range - * - * \param box box subtree - * \param len_ctx Length conversion context. - * \param start_idx start of range within textual representation (bytes) - * \param end_idx end of range - * \param handler handler function to call - * \param handle handle to pass - * \param before type of whitespace to place before next encountered text - * \param first whether this is the first box with text - * \param do_marker whether deal enter any marker box - * \return false iff traversal abandoned part-way through - */ - -bool traverse_tree( - struct box *box, const nscss_len_ctx *len_ctx, - unsigned start_idx, unsigned end_idx, - seln_traverse_handler handler, - void *handle, save_text_whitespace *before, bool *first, - bool do_marker) +/* exported interface documented in desktop/selection.h */ +void selection_destroy(struct selection *s) { - struct box *child; - const char *whitespace_text = ""; - size_t whitespace_length = 0; - - assert(box); - - /* If selection starts inside marker */ - if (box->parent && box->parent->list_marker == box && !do_marker) { - /* set box to main list element */ - box = box->parent; + if (s == NULL) { + return; } - /* If box has a list marker */ - if (box->list_marker) { - /* do the marker box before continuing with the rest of the - * list element */ - if (!traverse_tree(box->list_marker, len_ctx, - start_idx, end_idx, handler, handle, - before, first, true)) - return false; - } + selection_clear(s, true); + free(s); +} - /* we can prune this subtree, it's after the selection */ - if (box->byte_offset >= end_idx) - return true; - /* read before calling the handler in case it modifies the tree */ - child = box->children; +/* exported interface documented in desktop/selection.h */ +void selection_reinit(struct selection *s) +{ + s->max_idx = 0; - /* If nicely formatted output of the selected text is required, work - * out what whitespace should be placed before the next bit of text */ - if (before) { - save_text_solve_whitespace(box, first, before, &whitespace_text, - &whitespace_length); - } - else { - whitespace_text = NULL; - } - if (box->type != BOX_BR && - !((box->type == BOX_FLOAT_LEFT || - box->type == BOX_FLOAT_RIGHT) && - !box->text)) { - unsigned start_offset; - unsigned end_offset; - - if (selected_part(box, start_idx, end_idx, &start_offset, - &end_offset)) { - if (!handler(box->text + start_offset, min(box->length, - end_offset) - start_offset, - box, len_ctx, handle, whitespace_text, - whitespace_length)) - return false; - if (before) { - *first = false; - *before = WHITESPACE_NONE; - } - } + if (s->c->handler->textselection_get_end != NULL) { + s->c->handler->textselection_get_end(s->c, &s->max_idx); } - /* find the first child that could lie partially within the selection; - * this is important at the top-levels of the tree for pruning subtrees - * that lie entirely before the selection */ - - if (child) { - struct box *next = child->next; - - while (next && next->byte_offset < start_idx) { - child = next; - next = child->next; + if (s->defined) { + if (s->end_idx > s->max_idx) { + s->end_idx = s->max_idx; } - - while (child) { - /* read before calling the handler in case it modifies - * the tree */ - struct box *next = child->next; - - if (!traverse_tree(child, len_ctx, start_idx, end_idx, - handler, handle, before, first, false)) - return false; - - child = next; + if (s->start_idx > s->max_idx) { + s->start_idx = s->max_idx; } + s->defined = (s->end_idx > s->start_idx); } - - return true; } -/** - * Traverse the current selection, calling the handler function (with its - * handle) for all boxes that lie (partially) within the given range - * - * \param s The selection context. - * \param handler handler function to call - * \param handle handle to pass - * \return false iff traversal abandoned part-way through - */ - -static bool selection_traverse(struct selection *s, - seln_traverse_handler handler, void *handle) +/* exported interface documented in desktop/selection.h */ +void selection_init(struct selection *s) { - save_text_whitespace before = WHITESPACE_NONE; - bool first = true; - const char *text; - size_t length; - - if (!selection_defined(s)) - return true; /* easy case, nothing to do */ - - if (s->root) { - /* HTML */ - return traverse_tree(s->root, &s->len_ctx, - s->start_idx, s->end_idx, - handler, handle, - &before, &first, false); + if (s->defined) { + selection_clear(s, true); } - /* Text */ - text = textplain_get_raw_data(s->c, s->start_idx, s->end_idx, &length); - - if (text && !handler(text, length, NULL, NULL, handle, NULL, 0)) - return false; + s->defined = false; + s->start_idx = 0; + s->end_idx = 0; + s->drag_state = DRAG_NONE; - return true; + selection_reinit(s); } -/** - * Selection traversal handler for redrawing the screen when the selection - * has been altered. - * - * \param text pointer to text string - * \param length length of text to be appended (bytes) - * \param box pointer to text box being (partially) added - * \param handle unused handle, we don't need one - * \param whitespace_text whitespace to place before text for formatting - * may be NULL - * \param whitespace_length length of whitespace_text - * \return true iff successful and traversal should continue - */ - -bool redraw_handler(const char *text, size_t length, struct box *box, - const nscss_len_ctx *len_ctx, void *handle, - const char *whitespace_text, size_t whitespace_length) +/* exported interface documented in desktop/selection.h */ +bool +selection_click(struct selection *s, + struct browser_window *top, + browser_mouse_state mouse, + unsigned idx) { - if (box) { - struct rdw_info *r = (struct rdw_info*)handle; - int width, height; - int x, y; - plot_font_style_t fstyle; - - font_plot_style_from_css(len_ctx, box->style, &fstyle); - - /* \todo - it should be possible to reduce the redrawn area by - * considering the 'text', 'length' and 'space' parameters */ - box_coords(box, &x, &y); + browser_mouse_state modkeys; + int pos = -1; /* 0 = inside selection, 1 = after it */ - width = box->padding[LEFT] + box->width + box->padding[RIGHT]; - height = box->padding[TOP] + box->height + box->padding[BOTTOM]; + modkeys = (mouse & (BROWSER_MOUSE_MOD_1 | BROWSER_MOUSE_MOD_2)); - if (box->type == BOX_TEXT && box->space != 0) - width += box->space; + top = browser_window_get_root(top); - if (r->inited) { - if (x < r->r.x0) r->r.x0 = x; - if (y < r->r.y0) r->r.y0 = y; - if (x + width > r->r.x1) r->r.x1 = x + width; - if (y + height > r->r.y1) r->r.y1 = y + height; - } - else { - r->inited = true; - r->r.x0 = x; - r->r.y0 = y; - r->r.x1 = x + width; - r->r.y1 = y + height; + if (s->defined) { + if (idx > s->start_idx) { + if (idx <= s->end_idx) { + pos = 0; + } else { + pos = 1; + } } } - return true; -} + if (!pos && + ((mouse & BROWSER_MOUSE_DRAG_1) || + (modkeys && (mouse & BROWSER_MOUSE_DRAG_2)))) { + /* drag-saving selection */ + char *sel = selection_get_copy(s); + guit->window->drag_save_selection(top->window, sel); + free(sel); + } else if (!modkeys) { + if (pos && (mouse & BROWSER_MOUSE_PRESS_1)) { + /* Clear the selection if mouse is pressed + * outside the selection, Otherwise clear on + * release (to allow for drags) + */ -/** - * Redraws the given range of text. - * - * \param s selection object - * \param start_idx start offset (bytes) within the textual representation - * \param end_idx end offset (bytes) within the textual representation - */ + selection_clear(s, true); -void selection_redraw(struct selection *s, unsigned start_idx, unsigned end_idx) -{ - struct rdw_info rdw; + } else if (mouse & BROWSER_MOUSE_DRAG_1) { + /* start new selection drag */ - assert(end_idx >= start_idx); - rdw.inited = false; + selection_clear(s, true); - if (s->root) { - if (!traverse_tree(s->root, &s->len_ctx, start_idx, end_idx, - redraw_handler, &rdw, - NULL, NULL, false)) - return; - } - else { - if (s->is_html == false && end_idx > start_idx) { - textplain_coords_from_range(s->c, start_idx, - end_idx, &rdw.r); - rdw.inited = true; - } - } + selection_set_start(s, idx); + selection_set_end(s, idx); - if (rdw.inited) - content__request_redraw(s->c, rdw.r.x0, rdw.r.y0, - rdw.r.x1 - rdw.r.x0, rdw.r.y1 - rdw.r.y0); -} + s->drag_state = DRAG_END; + guit->window->event(top->window, + GW_EVENT_START_SELECTION); -/** - * Append text to selection string. - * - * \param text text to be added - * \param length length of text in bytes - * \param space indicates whether a trailing space should be appended - * \param style The font style to use. - * \param sel_string string to append to, may be resized - * \return true iff successful - */ + } else if (mouse & BROWSER_MOUSE_DRAG_2) { -static bool selection_string_append(const char *text, size_t length, bool space, - plot_font_style_t *style, struct selection_string *sel_string) -{ - size_t new_length = sel_string->length + length + (space ? 1 : 0) + 1; + /* adjust selection, but only if there is one */ + if (!s->defined) { + return false; /* ignore Adjust drags */ + } - if (style != NULL) { - /* Add text run style */ - nsclipboard_styles *new_styles; + if (pos >= 0) { + selection_set_end(s, idx); - if (sel_string->n_styles == 0) - assert(sel_string->length == 0); + s->drag_state = DRAG_END; + } else { + selection_set_start(s, idx); - new_styles = realloc(sel_string->styles, - (sel_string->n_styles + 1) * - sizeof(nsclipboard_styles)); - if (new_styles == NULL) - return false; + s->drag_state = DRAG_START; + } - sel_string->styles = new_styles; + guit->window->event(top->window, + GW_EVENT_START_SELECTION); - sel_string->styles[sel_string->n_styles].style = *style; - sel_string->styles[sel_string->n_styles].start = - sel_string->length; + } else if (mouse & BROWSER_MOUSE_CLICK_2) { - sel_string->n_styles++; - } + /* ignore Adjust clicks when there's no selection */ + if (!s->defined) { + return false; + } - if (new_length > sel_string->buffer_len) { - /* Need to extend buffer */ - size_t new_alloc = new_length + (new_length / 4); - char *new_buff; + if (pos >= 0) { + selection_set_end(s, idx); + } else { + selection_set_start(s, idx); + } + s->drag_state = DRAG_NONE; - new_buff = realloc(sel_string->buffer, new_alloc); - if (new_buff == NULL) + } else { return false; + } - sel_string->buffer = new_buff; - sel_string->buffer_len = new_alloc; + } else { + /* not our problem */ + return false; } - /* Copy text onto end of existing text in buffer */ - memcpy(sel_string->buffer + sel_string->length, text, length); - sel_string->length += length; - - if (space) - sel_string->buffer[sel_string->length++] = ' '; - - /* Ensure NULL termination */ - sel_string->buffer[sel_string->length] = '\0'; - + /* this mouse click is selection-related */ return true; } -/** - * Selection traversal routine for appending text to a string - * - * \param text pointer to text being added, or NULL for newline - * \param length length of text to be appended (bytes) - * \param box pointer to text box, or NULL if from textplain - * \param len_ctx Length conversion context - * \param handle selection string to append to - * \param whitespace_text whitespace to place before text for formatting - * may be NULL - * \param whitespace_length length of whitespace_text - * \return true iff successful and traversal should continue - */ - -static bool selection_copy_handler(const char *text, size_t length, - struct box *box, const nscss_len_ctx *len_ctx, - void *handle, const char *whitespace_text, - size_t whitespace_length) +/* exported interface documented in desktop/selection.h */ +void +selection_track(struct selection *s, browser_mouse_state mouse, unsigned idx) { - bool add_space = false; - plot_font_style_t style; - plot_font_style_t *pstyle = NULL; - - /* add any whitespace which precedes the text from this box */ - if (whitespace_text != NULL && whitespace_length > 0) { - if (!selection_string_append(whitespace_text, - whitespace_length, false, pstyle, handle)) { - return false; - } + if (!mouse) { + s->drag_state = DRAG_NONE; } - if (box != NULL) { - /* HTML */ - add_space = (box->space != 0); + switch (s->drag_state) { - if (box->style != NULL) { - /* Override default font style */ - font_plot_style_from_css(len_ctx, box->style, &style); - pstyle = &style; + case DRAG_START: + if (idx > s->end_idx) { + unsigned old_end = s->end_idx; + selection_set_end(s, idx); + selection_set_start(s, old_end); + s->drag_state = DRAG_END; } else { - /* If there's no style, there must be no text */ - assert(box->text == NULL); + selection_set_start(s, idx); } - } + break; - /* add the text from this box */ - if (!selection_string_append(text, length, add_space, pstyle, handle)) - return false; + case DRAG_END: + if (idx < s->start_idx) { + unsigned old_start = s->start_idx; + selection_set_start(s, idx); + selection_set_end(s, old_start); + s->drag_state = DRAG_START; + } else { + selection_set_end(s, idx); + } + break; - return true; + default: + break; + } } -/** - * Get copy of selection as string - * - * \param s selection - * \return string of selected text, or NULL. Ownership passed to caller. - */ - +/* exported interface documented in desktop/selection.h */ char *selection_get_copy(struct selection *s) { struct selection_string sel_string = { @@ -828,7 +468,7 @@ char *selection_get_copy(struct selection *s) if (s == NULL || !s->defined) return NULL; - if (!selection_traverse(s, selection_copy_handler, &sel_string)) { + if (!selection_copy(s, &sel_string)) { free(sel_string.buffer); free(sel_string.styles); return NULL; @@ -840,13 +480,7 @@ char *selection_get_copy(struct selection *s) } - -/** - * Copy the selected contents to the clipboard - * - * \param s selection - * \return true iff successful - */ +/* exported interface documented in desktop/selection.h */ bool selection_copy_to_clipboard(struct selection *s) { struct selection_string sel_string = { @@ -858,17 +492,20 @@ bool selection_copy_to_clipboard(struct selection *s) .styles = NULL }; - if (s == NULL || !s->defined) + if (s == NULL || !s->defined) { return false; + } - if (!selection_traverse(s, selection_copy_handler, &sel_string)) { + if (!selection_copy(s, &sel_string)) { free(sel_string.buffer); free(sel_string.styles); return false; } - guit->clipboard->set(sel_string.buffer, sel_string.length, - sel_string.styles, sel_string.n_styles); + guit->clipboard->set(sel_string.buffer, + sel_string.length, + sel_string.styles, + sel_string.n_styles); free(sel_string.buffer); free(sel_string.styles); @@ -877,21 +514,15 @@ bool selection_copy_to_clipboard(struct selection *s) } -/** - * Clears the current selection, optionally causing the screen to be updated. - * - * \param s selection object - * \param redraw true iff the previously selected region of the browser - * window should be redrawn - */ - -void selection_clear(struct selection *s, bool redraw) +/* exported interface documented in desktop/selection.h */ +bool selection_clear(struct selection *s, bool redraw) { int old_start, old_end; bool was_defined; assert(s); - was_defined = selection_defined(s); + + was_defined = s->defined; old_start = s->start_idx; old_end = s->end_idx; @@ -899,106 +530,75 @@ void selection_clear(struct selection *s, bool redraw) s->start_idx = 0; s->end_idx = 0; - if (redraw && was_defined) + if (redraw && was_defined) { selection_redraw(s, old_start, old_end); -} + } + return was_defined; +} -/** - * Selects all the text within the box subtree controlled by - * this selection object, updating the screen accordingly. - * - * \param s selection object - */ +/* exported interface documented in desktop/selection.h */ void selection_select_all(struct selection *s) { assert(s); s->defined = true; - + selection_set_start(s, 0); selection_set_end(s, s->max_idx); } -/** - * Set the start position of the current selection, updating the screen. - * - * \param s selection object - * \param offset byte offset within textual representation - */ - -void selection_set_start(struct selection *s, unsigned offset) +/* exported interface documented in desktop/selection.h */ +void selection_set_position(struct selection *s, unsigned start, unsigned end) { - bool was_defined = selection_defined(s); - unsigned old_start = s->start_idx; - - s->start_idx = offset; - s->defined = (s->start_idx < s->end_idx); - - if (was_defined) { - if (offset < old_start) - selection_redraw(s, s->start_idx, old_start); - else - selection_redraw(s, old_start, s->start_idx); - } - else if (selection_defined(s)) - selection_redraw(s, s->start_idx, s->end_idx); + selection_set_start(s, start); + selection_set_end(s, end); } -/** - * Set the end position of the current selection, updating the screen. - * - * \param s selection object - * \param offset byte offset within textual representation - */ - -void selection_set_end(struct selection *s, unsigned offset) +/* exported interface documented in desktop/selection.h */ +bool +selection_highlighted(const struct selection *s, + unsigned start, + unsigned end, + unsigned *start_idx, + unsigned *end_idx) { - bool was_defined = selection_defined(s); - unsigned old_end = s->end_idx; + assert(s); - s->end_idx = offset; - s->defined = (s->start_idx < s->end_idx); + if (!s->defined) { + return false; + } - if (was_defined) { - if (offset < old_end) - selection_redraw(s, s->end_idx, old_end); - else - selection_redraw(s, old_end, s->end_idx); + if ((end <= s->start_idx) || + (start >= s->end_idx)) { + return false; } - else if (selection_defined(s)) - selection_redraw(s, s->start_idx, s->end_idx); -} + *start_idx = (s->start_idx >= start) ? (s->start_idx - start) : 0; + *end_idx = min(end, s->end_idx) - start; -/** - * Tests whether a text range lies partially within the selection, if there is - * a selection defined, returning the start and end indexes of the bytes - * that should be selected. - * - * \param s the selection object - * \param start byte offset of start of text - * \param end byte offset of end of text - * \param start_idx receives the start index (in bytes) of the highlighted portion - * \param end_idx receives the end index (in bytes) - * \return true iff part of the given box lies within the selection - */ + return true; +} -bool selection_highlighted(const struct selection *s, - unsigned start, unsigned end, - unsigned *start_idx, unsigned *end_idx) +/* exported interface documented in desktop/selection.h */ +bool selection_active(struct selection *s) { - /* caller should have checked first for efficiency */ - assert(s); - assert(selection_defined(s)); + return s->defined; +} - if (end <= s->start_idx || start >= s->end_idx) - return false; +bool selection_dragging(struct selection *s) +{ + return s->drag_state != DRAG_NONE; +} - *start_idx = (s->start_idx >= start) ? (s->start_idx - start) : 0; - *end_idx = min(end, s->end_idx) - start; +bool selection_dragging_start(struct selection *s) +{ + return s->drag_state == DRAG_START; +} - return true; +void selection_drag_end(struct selection *s) +{ + s->drag_state = DRAG_NONE; } diff --git a/desktop/selection.h b/desktop/selection.h index 2f3f6dcfe..8cd523fd8 100644 --- a/desktop/selection.h +++ b/desktop/selection.h @@ -20,86 +20,172 @@ * Text selection within browser windows (interface). */ -#ifndef _NETSURF_DESKTOP_SELECTION_H_ -#define _NETSURF_DESKTOP_SELECTION_H_ +#ifndef NETSURF_DESKTOP_SELECTION_H_ +#define NETSURF_DESKTOP_SELECTION_H_ #include <stdbool.h> #include "netsurf/mouse.h" -#include "content/handlers/css/utils.h" struct box; +struct browser_window; +struct plot_font_style; +struct selection_string; +struct selection; +struct content; + +/** + * determine if a selecion is active + */ +bool selection_active(struct selection *s); -typedef enum { - DRAG_NONE, - DRAG_START, - DRAG_END -} seln_drag_state; - - -/* this structure should be treated as opaque outside selection.c - (it's defined here to accelerate selection_defined(s) for reduced - impact on redraw code) */ - -struct selection -{ - struct content *c; - struct box *root; - nscss_len_ctx len_ctx; - - unsigned max_idx; /* total bytes in text representation */ - - unsigned start_idx; /* offset in bytes within text representation */ - unsigned end_idx; +bool selection_dragging(struct selection *s); - bool defined; - bool is_html; +bool selection_dragging_start(struct selection *s); - seln_drag_state drag_state; -}; +/** + * Handles completion of a drag operation + */ +void selection_drag_end(struct selection *s); +/** + * Creates a new selection object associated with a browser window. + * + * Used from text and html content handlers + * + * \return new selection context + */ +struct selection *selection_create(struct content *c); -struct selection *selection_create(struct content *c, bool is_html); -void selection_prepare(struct selection *s, struct content *c, bool is_html); +/** + * Destroys a selection object clearing it if nesessary + * + * Used from content textsearch + * + * \param s selection object + */ void selection_destroy(struct selection *s); -void selection_init( - struct selection *s, - struct box *root, - const nscss_len_ctx *len_ctx); -void selection_reinit(struct selection *s, struct box *root); - -/* struct box *selection_root(struct selection *s); */ -#define selection_root(s) ((s)->root) - -/* bool selection_defined(struct selection *s); */ -#define selection_defined(s) ((s)->defined) +/** + * Initialise the selection object to use the given box subtree as its root, + * ie. selections are confined to that subtree. + * + * Used from text and html content handlers + * + * \param s selection object + */ +void selection_init(struct selection *s); -/* bool selection_dragging(struct selection *s); */ -#define selection_dragging(s) ((s)->drag_state != DRAG_NONE) +/** + * Initialise the selection object to use the given box subtree as its root, + * ie. selections are confined to that subtree, whilst maintaining the current + * selection whenever possible because, for example, it's just the page being + * resized causing the layout to change. + * + * Used from html content handler + * + * \param s selection object + */ +void selection_reinit(struct selection *s); -/* bool selection_dragging_start(struct selection *s); */ -#define selection_dragging_start(s) ((s)->drag_state == DRAG_START) +/** + * Clears the current selection, optionally causing the screen to be updated. + * + * Used from text and html content handlers + * + * \param s selection object + * \param redraw true iff the previously selected region of the browser + * window should be redrawn + * \return true if selection was cleared false if not + */ +bool selection_clear(struct selection *s, bool redraw); -void selection_clear(struct selection *s, bool redraw); +/** + * Selects all the text within the box subtree controlled by + * this selection object, updating the screen accordingly. + * + * Used from text and html content handlers + * + * \param s selection object + */ void selection_select_all(struct selection *s); -void selection_set_start(struct selection *s, unsigned idx); -void selection_set_end(struct selection *s, unsigned idx); +/** + * Set the position of the current selection, updating the screen. + * + * Used from content textsearch + * + * \param s selection object + * \param start byte offset within textual representation + * \param end byte offset within textual representation + */ +void selection_set_position(struct selection *s, unsigned start, unsigned end); -bool selection_click(struct selection *s, browser_mouse_state mouse, - unsigned idx); -void selection_track(struct selection *s, browser_mouse_state mouse, - unsigned idx); +/** + * Handles mouse clicks (including drag starts) in or near a selection + * + * Used from text and html content handlers + * + * \param s selection object + * \param mouse state of mouse buttons and modifier keys + * \param idx byte offset within textual representation + * \return true iff the click has been handled by the selection code + */ +bool selection_click(struct selection *s, struct browser_window *top, browser_mouse_state mouse, unsigned idx); +/** + * Handles movements related to the selection, eg. dragging of start and + * end points. + * + * Used from text and html content handlers + * + * \param s selection object + * \param mouse state of mouse buttons and modifier keys + * \param idx byte offset within text representation + */ +void selection_track(struct selection *s, browser_mouse_state mouse, unsigned idx); + +/** + * Copy the selected contents to the clipboard + * + * Used from text and html content handlers + * + * \param s selection + * \return true iff successful + */ bool selection_copy_to_clipboard(struct selection *s); -char * selection_get_copy(struct selection *s); -/** Handles completion of a drag operation */ -/* void selection_drag_end(struct selection *s); */ -#define selection_drag_end(s) ((s)->drag_state = DRAG_NONE) +/** + * Get copy of selection as string + * + * Used from text and html content handlers + * + * \param s selection + * \return string of selected text, or NULL. Ownership passed to caller. + */ +char *selection_get_copy(struct selection *s); + -bool selection_highlighted(const struct selection *s, - unsigned start, unsigned end, - unsigned *start_idx, unsigned *end_idx); +/** + * Tests whether a text range lies partially within the selection, if there is + * a selection defined, returning the start and end indexes of the bytes + * that should be selected. + * + * Used from text and html content handlers, content textsearch + * + * \param s the selection object + * \param start byte offset of start of text + * \param end byte offset of end of text + * \param start_idx receives the start index (in bytes) of the highlighted portion + * \param end_idx receives the end index (in bytes) + * \return true iff part of the given box lies within the selection + */ +bool selection_highlighted(const struct selection *s, unsigned start, unsigned end, unsigned *start_idx, unsigned *end_idx); + +bool +selection_string_append(const char *text, + size_t length, + bool space, + struct plot_font_style *style, + struct selection_string *sel_string); #endif diff --git a/desktop/sslcert_viewer.c b/desktop/sslcert_viewer.c deleted file mode 100644 index 4d8725757..000000000 --- a/desktop/sslcert_viewer.c +++ /dev/null @@ -1,570 +0,0 @@ -/* - * Copyright 2009 Paul Blokus <paul_pl@users.sourceforge.net> - * Copyright 2013 Michael Drake <tlsa@netsurf-browser.org> - * - * This file is part of NetSurf, http://www.netsurf-browser.org/ - * - * NetSurf is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * NetSurf is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - */ - -/** - * \file - * SSL Certificate verification UI implementation - */ - -#include <assert.h> -#include <stdlib.h> - -#include "content/fetch.h" -#include "content/urldb.h" -#include "content/hlcache.h" -#include "desktop/sslcert_viewer.h" -#include "desktop/treeview.h" -#include "utils/messages.h" -#include "utils/log.h" -#include "utils/utils.h" - -/** - * ssl certificate viewer data fields - */ -enum sslcert_viewer_field { - SSLCERT_V_SUBJECT, - SSLCERT_V_SERIAL, - SSLCERT_V_TYPE, - SSLCERT_V_VALID_UNTIL, - SSLCERT_V_VALID_FROM, - SSLCERT_V_VERSION, - SSLCERT_V_ISSUER, - SSLCERT_V_CERTIFICATES, - SSLCERT_V_N_FIELDS -}; - -typedef nserror (*response_cb)(bool proceed, void *pw); - -/** - * ssl certificate verification context. - */ -struct sslcert_session_data { - struct ssl_cert_info *certs; /**< Certificates */ - unsigned long num; /**< Number of certificates in chain */ - nsurl *url; /**< The url of the certificate */ - response_cb cb; /**< Cert accept/reject callback */ - void *cbpw; /**< Context passed to callback */ - - treeview *tree; /**< The treeview object */ - struct treeview_field_desc fields[SSLCERT_V_N_FIELDS]; -}; - - -/** - * ssl certificate tree entry - */ -struct sslcert_entry { - treeview_node *entry; - char version[24]; - char type[24]; - struct treeview_field_data data[SSLCERT_V_N_FIELDS - 1]; -}; - - -/** - * Free a ssl certificate viewer entry's treeview field data. - * - * \param e Entry to free data from - */ -static void sslcert_viewer_free_treeview_field_data(struct sslcert_entry *e) -{ -} - - -/** - * Build a sslcert viewer treeview field from given text - * - * \param field SSL certificate treeview field to build - * \param data SSL certificate entry field data to set - * \param value Text to set in field, ownership yielded - * \param ssl_d SSL certificate session data - * \return NSERROR_OK on success, appropriate error otherwise - */ -static inline nserror -sslcert_viewer_field_builder(enum sslcert_viewer_field field, - struct treeview_field_data *data, - const char *value, - struct sslcert_session_data *ssl_d) -{ - data->field = ssl_d->fields[field].field; - data->value = value; - data->value_len = (value != NULL) ? strlen(value) : 0; - - return NSERROR_OK; -} - - -/** - * Set a sslcert viewer entry's data from the certificate. - * - * \param e Entry to set up - * \param cert Data associated with entry's certificate - * \param ssl_d SSL certificate session data - * \return NSERROR_OK on success, appropriate error otherwise - */ -static nserror -sslcert_viewer_set_treeview_field_data(struct sslcert_entry *e, - const struct ssl_cert_info *cert, - struct sslcert_session_data *ssl_d) -{ - unsigned int written; - - assert(e != NULL); - assert(cert != NULL); - assert(ssl_d != NULL); - - /* Set the fields up */ - sslcert_viewer_field_builder(SSLCERT_V_SUBJECT, - &e->data[SSLCERT_V_SUBJECT], - cert->subject, ssl_d); - - sslcert_viewer_field_builder(SSLCERT_V_SERIAL, - &e->data[SSLCERT_V_SERIAL], - cert->serialnum, ssl_d); - - written = snprintf(e->type, sizeof(e->type), "%i", cert->cert_type); - assert(written < sizeof(e->type)); - sslcert_viewer_field_builder(SSLCERT_V_TYPE, - &e->data[SSLCERT_V_TYPE], - e->type, ssl_d); - - sslcert_viewer_field_builder(SSLCERT_V_VALID_UNTIL, - &e->data[SSLCERT_V_VALID_UNTIL], - cert->not_after, ssl_d); - - sslcert_viewer_field_builder(SSLCERT_V_VALID_FROM, - &e->data[SSLCERT_V_VALID_FROM], - cert->not_before, ssl_d); - - written = snprintf(e->version, sizeof(e->version), - "%li", cert->version); - assert(written < sizeof(e->version)); - sslcert_viewer_field_builder(SSLCERT_V_VERSION, - &e->data[SSLCERT_V_VERSION], - e->version, ssl_d); - - sslcert_viewer_field_builder(SSLCERT_V_ISSUER, - &e->data[SSLCERT_V_ISSUER], - cert->issuer, ssl_d); - - return NSERROR_OK; -} - - -/** - * Create a treeview node for a certificate - * - * \param ssl_d SSL certificate session data - * \param n Number of SSL certificate in chain, to make node for - * \return NSERROR_OK on success otherwise error code. - */ -static nserror -sslcert_viewer_create_node(struct sslcert_session_data *ssl_d, int n) -{ - struct sslcert_entry *e; - const struct ssl_cert_info *cert = &(ssl_d->certs[n]); - nserror err; - - /* Create new certificate viewer entry */ - e = malloc(sizeof(struct sslcert_entry)); - if (e == NULL) { - return NSERROR_NOMEM; - } - - err = sslcert_viewer_set_treeview_field_data(e, cert, ssl_d); - if (err != NSERROR_OK) { - free(e); - return err; - } - - /* Create the new treeview node */ - err = treeview_create_node_entry(ssl_d->tree, &(e->entry), - NULL, TREE_REL_FIRST_CHILD, - e->data, e, TREE_OPTION_NONE); - if (err != NSERROR_OK) { - sslcert_viewer_free_treeview_field_data(e); - free(e); - return err; - } - - return NSERROR_OK; -} - - -/** - * Initialise the treeview entry fields - * - * \param ssl_d SSL certificate session data - * \return NSERROR_OK on success otherwise error code. - */ -static nserror sslcert_init_entry_fields(struct sslcert_session_data *ssl_d) -{ - int i; - const char *label; - - for (i = 0; i < SSLCERT_V_N_FIELDS; i++) - ssl_d->fields[i].field = NULL; - - ssl_d->fields[SSLCERT_V_SUBJECT].flags = TREE_FLAG_DEFAULT; - label = "TreeviewLabelSubject"; - label = messages_get(label); - if (lwc_intern_string(label, strlen(label), - &ssl_d->fields[SSLCERT_V_SUBJECT].field) != - lwc_error_ok) { - goto error; - } - - ssl_d->fields[SSLCERT_V_SERIAL].flags = TREE_FLAG_SHOW_NAME; - label = "TreeviewLabelSerial"; - label = messages_get(label); - if (lwc_intern_string(label, strlen(label), - &ssl_d->fields[SSLCERT_V_SERIAL].field) != - lwc_error_ok) { - goto error; - } - - ssl_d->fields[SSLCERT_V_TYPE].flags = TREE_FLAG_SHOW_NAME; - label = "TreeviewLabelType"; - label = messages_get(label); - if (lwc_intern_string(label, strlen(label), - &ssl_d->fields[SSLCERT_V_TYPE].field) != - lwc_error_ok) { - goto error; - } - - ssl_d->fields[SSLCERT_V_VALID_UNTIL].flags = TREE_FLAG_SHOW_NAME; - label = "TreeviewLabelValidUntil"; - label = messages_get(label); - if (lwc_intern_string(label, strlen(label), - &ssl_d->fields[SSLCERT_V_VALID_UNTIL].field) != - lwc_error_ok) { - goto error; - } - - ssl_d->fields[SSLCERT_V_VALID_FROM].flags = TREE_FLAG_SHOW_NAME; - label = "TreeviewLabelValidFrom"; - label = messages_get(label); - if (lwc_intern_string(label, strlen(label), - &ssl_d->fields[SSLCERT_V_VALID_FROM].field) != - lwc_error_ok) { - goto error; - } - - ssl_d->fields[SSLCERT_V_VERSION].flags = TREE_FLAG_SHOW_NAME; - label = "TreeviewLabelVersion"; - label = messages_get(label); - if (lwc_intern_string(label, strlen(label), - &ssl_d->fields[SSLCERT_V_VERSION].field) != - lwc_error_ok) { - goto error; - } - - ssl_d->fields[SSLCERT_V_ISSUER].flags = TREE_FLAG_SHOW_NAME; - label = "TreeviewLabelIssuer"; - label = messages_get(label); - if (lwc_intern_string(label, strlen(label), - &ssl_d->fields[SSLCERT_V_ISSUER].field) != - lwc_error_ok) { - goto error; - } - - ssl_d->fields[SSLCERT_V_CERTIFICATES].flags = TREE_FLAG_DEFAULT; - label = "TreeviewLabelCertificates"; - label = messages_get(label); - if (lwc_intern_string(label, strlen(label), - &ssl_d->fields[SSLCERT_V_CERTIFICATES].field) != - lwc_error_ok) { - return false; - } - - return NSERROR_OK; - -error: - for (i = 0; i < SSLCERT_V_N_FIELDS; i++) - if (ssl_d->fields[i].field != NULL) - lwc_string_unref(ssl_d->fields[i].field); - - return NSERROR_UNKNOWN; -} - - -/** - * Delete ssl certificate viewer entries - * - * \param e Entry to delete. - */ -static void sslcert_viewer_delete_entry(struct sslcert_entry *e) -{ - sslcert_viewer_free_treeview_field_data(e); - free(e); -} - - -/** - * folder operation callback - * - * \param msg treeview message - * \param data message context - * \return NSERROR_OK on success - */ -static nserror -sslcert_viewer_tree_node_folder_cb(struct treeview_node_msg msg, void *data) -{ - switch (msg.msg) { - case TREE_MSG_NODE_DELETE: - case TREE_MSG_NODE_EDIT: - case TREE_MSG_NODE_LAUNCH: - break; - } - - return NSERROR_OK; -} - - -/** - * node entry callback - * - * \param msg treeview message - * \param data message context - * \return NSERROR_OK on success - */ -static nserror -sslcert_viewer_tree_node_entry_cb(struct treeview_node_msg msg, void *data) -{ - struct sslcert_entry *e = data; - - switch (msg.msg) { - case TREE_MSG_NODE_DELETE: - e->entry = NULL; - sslcert_viewer_delete_entry(e); - break; - - case TREE_MSG_NODE_EDIT: - case TREE_MSG_NODE_LAUNCH: - break; - } - - return NSERROR_OK; -} - - -/** - * ssl certificate treeview callbacks - */ -struct treeview_callback_table sslv_tree_cb_t = { - .folder = sslcert_viewer_tree_node_folder_cb, - .entry = sslcert_viewer_tree_node_entry_cb -}; - - -/* Exported interface, documented in sslcert_viewer.h */ -nserror -sslcert_viewer_init(struct core_window_callback_table *cw_t, - void *core_window_handle, - struct sslcert_session_data *ssl_d) -{ - nserror err; - int cert_loop; - - assert(ssl_d != NULL); - - err = treeview_init(); - if (err != NSERROR_OK) { - return err; - } - - NSLOG(netsurf, INFO, "Building certificate viewer"); - - /* Init. certificate chain treeview entry fields */ - err = sslcert_init_entry_fields(ssl_d); - if (err != NSERROR_OK) { - ssl_d->tree = NULL; - return err; - } - - /* Create the certificate treeview */ - err = treeview_create(&ssl_d->tree, &sslv_tree_cb_t, - SSLCERT_V_N_FIELDS, ssl_d->fields, - cw_t, core_window_handle, TREEVIEW_READ_ONLY); - if (err != NSERROR_OK) { - ssl_d->tree = NULL; - return err; - } - - /* Build treeview nodes from certificate chain */ - for (cert_loop = ssl_d->num - 1; cert_loop >= 0; cert_loop--) { - err = sslcert_viewer_create_node(ssl_d, cert_loop); - if (err != NSERROR_OK) { - return err; - } - } - - NSLOG(netsurf, INFO, "Built certificate viewer"); - - return NSERROR_OK; -} - - -/** - * Free SSL certificate session data - * - * \param ssl_d SSL certificate session data - */ -static void sslcert_cleanup_session(struct sslcert_session_data *ssl_d) -{ - assert(ssl_d != NULL); - - if (ssl_d->url) { - nsurl_unref(ssl_d->url); - ssl_d->url = NULL; - } - - if (ssl_d->certs) { - free(ssl_d->certs); - ssl_d->certs = NULL; - } - - free(ssl_d); -} - - -/* Exported interface, documented in sslcert_viewer.h */ -nserror sslcert_viewer_fini(struct sslcert_session_data *ssl_d) -{ - int i; - nserror err; - - NSLOG(netsurf, INFO, "Finalising ssl certificate viewer"); - - /* Destroy the treeview */ - err = treeview_destroy(ssl_d->tree); - - /* Free treeview entry fields */ - for (i = 0; i < SSLCERT_V_N_FIELDS; i++) - if (ssl_d->fields[i].field != NULL) - lwc_string_unref(ssl_d->fields[i].field); - - /* Destroy the sslcert_session_data */ - sslcert_cleanup_session(ssl_d); - - err = treeview_fini(); - if (err != NSERROR_OK) { - return err; - } - - NSLOG(netsurf, INFO, "Finalised ssl certificate viewer"); - - return err; -} - - -/* Exported interface, documented in sslcert_viewer.h */ -nserror -sslcert_viewer_create_session_data(unsigned long num, - struct nsurl *url, - nserror (*cb)(bool proceed, void *pw), - void *cbpw, - const struct ssl_cert_info *certs, - struct sslcert_session_data **ssl_d) -{ - struct sslcert_session_data *data; - - assert(url != NULL); - assert(certs != NULL); - - data = malloc(sizeof(struct sslcert_session_data)); - if (data == NULL) { - *ssl_d = NULL; - return NSERROR_NOMEM; - } - - /* copy certificate data */ - data->certs = malloc(num * sizeof(struct ssl_cert_info)); - if (data->certs == NULL) { - free(data); - *ssl_d = NULL; - return NSERROR_NOMEM; - } - memcpy(data->certs, certs, num * sizeof(struct ssl_cert_info)); - - data->url = nsurl_ref(url); - data->num = num; - data->cb = cb; - data->cbpw = cbpw; - - data->tree = NULL; - - *ssl_d = data; - return NSERROR_OK; -} - - -/* Exported interface, documented in sslcert_viewer.h */ -nserror sslcert_viewer_reject(struct sslcert_session_data *ssl_d) -{ - assert(ssl_d != NULL); - - ssl_d->cb(false, ssl_d->cbpw); - - return NSERROR_OK; -} - - -/* Exported interface, documented in sslcert_viewer.h */ -nserror sslcert_viewer_accept(struct sslcert_session_data *ssl_d) -{ - assert(ssl_d != NULL); - - urldb_set_cert_permissions(ssl_d->url, true); - - ssl_d->cb(true, ssl_d->cbpw); - - return NSERROR_OK; -} - - -/* Exported interface, documented in sslcert_viewer.h */ -void -sslcert_viewer_redraw(struct sslcert_session_data *ssl_d, - int x, int y, - struct rect *clip, - const struct redraw_context *ctx) -{ - assert(ssl_d != NULL && - "sslcert_viewer_redraw() given bad session data"); - - treeview_redraw(ssl_d->tree, x, y, clip, ctx); -} - - -/* Exported interface, documented in sslcert_viewer.h */ -void -sslcert_viewer_mouse_action(struct sslcert_session_data *ssl_d, - browser_mouse_state mouse, - int x, int y) -{ - treeview_mouse_action(ssl_d->tree, mouse, x, y); -} - - -/* Exported interface, documented in sslcert_viewer.h */ -bool sslcert_viewer_keypress(struct sslcert_session_data *ssl_d, uint32_t key) -{ - return treeview_keypress(ssl_d->tree, key); -} diff --git a/desktop/sslcert_viewer.h b/desktop/sslcert_viewer.h deleted file mode 100644 index 6955e0167..000000000 --- a/desktop/sslcert_viewer.h +++ /dev/null @@ -1,136 +0,0 @@ -/* - * Copyright 2009 Paul Blokus <paul_pl@users.sourceforge.net> - * Copyright 2013 Michael Drake <tlsa@netsurf-browser.org> - * - * This file is part of NetSurf, http://www.netsurf-browser.org/ - * - * NetSurf is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * NetSurf is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - */ - -/** - * \file - * SSL Certificate verification UI interface - */ - -#ifndef NETSURF_DESKTOP_SSLCERT_VIEWER_H -#define NETSURF_DESKTOP_SSLCERT_VIEWER_H - -#include "netsurf/mouse.h" - -struct sslcert_session_data; -struct redraw_context; -struct core_window_callback_table; -struct rect; -struct nsurl; -struct ssl_cert_info; - -/** - * Create ssl certificate viewer session data. - * - * \param num The number of certificates in the chain - * \param url Address of the page we're inspecting certificates of - * \param cb Low level cache callback - * \param cbpw Low level cache private data - * \param certs The SSL certificates - * \param ssl_d Updated to SSL certificate session data - * \return NSERROR_OK on success, appropriate error otherwise - * - * Pass the session data to sslcert_viewer_init. - * sslcert_viewer_fini destroys the session data. - */ -nserror sslcert_viewer_create_session_data( - unsigned long num, struct nsurl *url, nserror (*cb)(bool proceed, void *pw), - void *cbpw, const struct ssl_cert_info *certs, - struct sslcert_session_data **ssl_d); - - -/** - * Initialise a ssl certificate viewer from session data. - * - * This iterates through the certificates, building a treeview. - * - * \param cw_t Callback table for cert viewer's core_window - * \param core_window_handle The core_window in which the cert viewer is shown - * \param ssl_d SSL certificate session data - * \return NSERROR_OK on success, appropriate error otherwise - */ -nserror sslcert_viewer_init(struct core_window_callback_table *cw_t, - void *core_window_handle, struct sslcert_session_data *ssl_d); - - -/** - * Finalise a ssl certificate viewer. - * - * This destroys the certificate treeview and the certificate viewer module's - * session data. - * - * \param ssl_d SSL certificate session data - * \return NSERROR_OK on success, appropriate error otherwise - */ -nserror sslcert_viewer_fini(struct sslcert_session_data *ssl_d); - - -/** - * Reject a certificate chain. - * - * \param ssl_d SSL certificate session data - * \return NSERROR_OK on success, appropriate error otherwise - */ -nserror sslcert_viewer_reject(struct sslcert_session_data *ssl_d); - - -/** - * Accept a certificate chain. - * - * \param ssl_d SSL certificate session data - * \return NSERROR_OK on success, appropriate error otherwise - */ -nserror sslcert_viewer_accept(struct sslcert_session_data *ssl_d); - - -/** - * Redraw the ssl certificate viewer. - * - * \param ssl_d SSL certificate session data - * \param x X coordinate to render treeview at - * \param y Y coordinate to render treeview at - * \param clip Current clip rectangle (wrt tree origin) - * \param ctx Current redraw context - */ -void sslcert_viewer_redraw(struct sslcert_session_data *ssl_d, - int x, int y, struct rect *clip, - const struct redraw_context *ctx); - - -/** - * Handles all kinds of mouse action - * - * \param ssl_d SSL certificate session data - * \param mouse The current mouse state - * \param x X coordinate - * \param y Y coordinate - */ -void sslcert_viewer_mouse_action(struct sslcert_session_data *ssl_d, - browser_mouse_state mouse, int x, int y); - - -/** - * Key press handling. - * - * \param ssl_d SSL certificate session data - * \param key The ucs4 character codepoint - * \return true if the keypress is dealt with, false otherwise. - */ -bool sslcert_viewer_keypress(struct sslcert_session_data *ssl_d, uint32_t key); - -#endif diff --git a/desktop/textarea.c b/desktop/textarea.c index 5bae27a5c..e0e87444c 100644 --- a/desktop/textarea.c +++ b/desktop/textarea.c @@ -58,7 +58,7 @@ struct line_info { struct textarea_drag { textarea_drag_type type; union { - struct scrollbar* scrollbar; + struct scrollbar *scrollbar; } data; }; @@ -625,7 +625,7 @@ static bool textarea_select(struct textarea *ta, int b_start, int b_end, * \param ta Text area * \return True on success, false otherwise */ -static bool textarea_select_fragment(struct textarea * ta) +static bool textarea_select_fragment(struct textarea *ta) { int caret_pos; size_t sel_start, sel_end; @@ -676,7 +676,7 @@ static bool textarea_select_fragment(struct textarea * ta) * \param ta textarea widget * \return True on success, false otherwise */ -static bool textarea_select_paragraph(struct textarea * ta) +static bool textarea_select_paragraph(struct textarea *ta) { int caret_pos; size_t sel_start, sel_end; @@ -1607,7 +1607,7 @@ static bool textarea_copy_to_undo_buffer(struct textarea *ta, * \param b_end End byte index of replaced section (exclusive) * \param rep Replacement UTF-8 text to insert * \param rep_len Byte length of replacement UTF-8 text - * \param add_to_clipboard True iff replaced text to be added to clipboard + * \param add_to_clipboard True if replaced text to be added to clipboard * \param byte_delta Updated to change in byte count in textarea (ta->show) * \param r Updated to area where redraw is required * \return false on memory exhaustion, true otherwise @@ -2452,7 +2452,7 @@ bool textarea_keypress(struct textarea *ta, uint32_t key) struct textarea_msg msg; struct rect r; /**< Redraw rectangle */ char utf8[6]; - unsigned int caret, length, b_off, b_len; + unsigned int caret, caret_copy, length, b_off, b_len; int h_extent = ta->h_extent; int v_extent = ta->v_extent; int line; @@ -2466,7 +2466,7 @@ bool textarea_keypress(struct textarea *ta, uint32_t key) /* Word separators */ static const char *sep = " .\n"; - caret = textarea_get_caret(ta); + caret = caret_copy = textarea_get_caret(ta); line = ta->caret_pos.line; readonly = (ta->flags & TEXTAREA_READONLY ? true : false); @@ -2743,6 +2743,9 @@ bool textarea_keypress(struct textarea *ta, uint32_t key) case NS_KEY_WORD_LEFT: if (readonly) break; + if (ta->sel_start != -1) { + textarea_clear_selection(ta); + } if (caret == 0) break; caret--; @@ -2756,13 +2759,59 @@ bool textarea_keypress(struct textarea *ta, uint32_t key) break; } } + break; + case NS_KEY_DELETE_WORD_LEFT: + if (readonly) + break; + + /* If there is a selection, remove the selected + * characters */ if (ta->sel_start != -1) { + if (!textarea_replace_text(ta, ta->sel_start, + ta->sel_end, "", 0, false, + &byte_delta, &r)) + return false; + caret = ta->sel_start; textarea_clear_selection(ta); + redraw = true; + break; + } + + if (caret == 0) + break; + + /* caret goes left until a non-separator is + * encountered */ + caret--; + while (strchr(sep, ta->show->data[caret]) != NULL && + caret > 0) + caret--; + + /* caret goes left until a separator is encountered */ + for (; caret > 0; caret--) { + if (strchr(sep, ta->show->data[caret]) != + NULL) { + caret++; + break; + } } + + /* Remove the characters from new caret position to + * original caret position */ + if (!textarea_replace_text(ta, caret, caret_copy, + "", 0, false, &byte_delta, &r)) + return false; + + redraw = true; break; case NS_KEY_WORD_RIGHT: if (readonly) break; + if (ta->sel_start != -1) { + textarea_clear_selection(ta); + } + if (caret == ta->show->len - 1) + break; if (strchr(sep, ta->show->data[caret]) != NULL && caret < ta->show->len - 1) { while (strchr(sep, ta->show->data[caret]) != @@ -2779,9 +2828,49 @@ bool textarea_keypress(struct textarea *ta, uint32_t key) while (strchr(sep, ta->show->data[caret]) != NULL && caret < ta->show->len - 1) caret++; + break; + case NS_KEY_DELETE_WORD_RIGHT: + if (readonly) + break; + + /* If there is a selection, remove the selected + * characters */ if (ta->sel_start != -1) { + if (!textarea_replace_text(ta, ta->sel_start, + ta->sel_end, "", 0, false, + &byte_delta, &r)) + return false; + caret = ta->sel_start; textarea_clear_selection(ta); + redraw = true; + break; } + + if (caret == ta->show->len - 1) + break; + + /* caret_copy goes right until a non-separator is + * encountered */ + while (strchr(sep, ta->show->data[caret_copy]) != NULL + && caret_copy < ta->show->len - 1) + caret_copy++; + + /* caret_copy goes right until a separator is + * encountered */ + for (; caret_copy < ta->show->len - 1; caret_copy++) { + if (strchr(sep, ta->show->data[caret_copy]) != + NULL) { + break; + } + } + + /* Remove all the characters from original caret + * position to caret_copy */ + if (!textarea_replace_text(ta, caret, caret_copy, + "", 0, false, &byte_delta, &r)) + return false; + + redraw = true; break; case NS_KEY_DELETE_LINE: if (readonly) diff --git a/desktop/textinput.c b/desktop/textinput.c index f8da3d86b..b8dced689 100644 --- a/desktop/textinput.c +++ b/desktop/textinput.c @@ -33,14 +33,13 @@ #include "utils/talloc.h" #include "utils/utf8.h" #include "utils/utils.h" +#include "netsurf/types.h" #include "netsurf/mouse.h" #include "netsurf/form.h" #include "netsurf/window.h" #include "netsurf/browser_window.h" #include "netsurf/keypress.h" -#include "html/box.h" -#include "html/html_internal.h" -#include "html/layout.h" +#include "content/content.h" #include "desktop/browser_private.h" #include "desktop/textinput.h" diff --git a/desktop/treeview.c b/desktop/treeview.c index e8b4a14c8..a65a37e72 100644 --- a/desktop/treeview.c +++ b/desktop/treeview.c @@ -22,14 +22,14 @@ * Treeview handling implementation. */ -#define _GNU_SOURCE /* strcasestr needs this for string.h */ +#include "utils/config.h" #include <string.h> -#include "utils/config.h" #include "utils/utils.h" #include "utils/log.h" #include "utils/nsurl.h" +#include "utils/nscolour.h" #include "utils/nsoption.h" #include "netsurf/bitmap.h" #include "netsurf/content.h" @@ -41,6 +41,7 @@ #include "content/hlcache.h" #include "css/utils.h" +#include "desktop/bitmap.h" #include "desktop/knockout.h" #include "desktop/textarea.h" #include "desktop/treeview.h" @@ -361,6 +362,26 @@ static inline void treeview__cw_invalidate_area( /** + * Corewindow callback wrapper: Request a full redraw of the window + * + * \param[in] tree The treeview to request redraw on. + */ +static inline void treeview__cw_full_redraw( + const struct treeview *tree) +{ + if (tree->cw_t != NULL) { + static const struct rect r = { + .x0 = 0, + .y0 = 0, + .x1 = REDRAW_MAX, + .y1 = REDRAW_MAX, + }; + tree->cw_t->invalidate(tree->cw_h, &r); + } +} + + +/** * Get height used by treeview's search bar (or 0 if not present). * * \param tree Treeview object to check. @@ -915,6 +936,12 @@ static void treeview__search_cancel(treeview *tree, bool drop_focus) return; } + if (textarea_get_text(tree->search.textarea, NULL, 0) == 1) { + // If there's no text in the search box, we drop focus on a + // cancel. Note '1' because it includes the trailing \0 + drop_focus = true; + } + if (drop_focus) { tree->search.active = false; textarea_set_caret(tree->search.textarea, -1); @@ -926,6 +953,34 @@ static void treeview__search_cancel(treeview *tree, bool drop_focus) treeview__cw_invalidate_area(tree, &r); } +/** + * Convert from treeview drag to core window drag type. + * + * \param[in] tree A treeview. + * \return Core window drag type. + */ +static core_window_drag_status treeview__get_cw_drag_type( + const treeview *tree) +{ + assert(tree != NULL); + + switch (tree->drag.type) { + case TV_DRAG_NONE: + return CORE_WINDOW_DRAG_NONE; + + case TV_DRAG_SELECTION: + return CORE_WINDOW_DRAG_SELECTION; + + case TV_DRAG_TEXTAREA: /* Fall through.*/ + case TV_DRAG_SEARCH: + return CORE_WINDOW_DRAG_TEXT_SELECTION; + + case TV_DRAG_MOVE: + return CORE_WINDOW_DRAG_MOVE; + } + + return CORE_WINDOW_DRAG_NONE; +} /** * Callback for textarea_create, in desktop/treeview.h @@ -952,7 +1007,8 @@ static void treeview_textarea_search_callback(void *data, /* Textarea drag started */ tree->drag.type = TV_DRAG_SEARCH; } - treeview__cw_drag_status(tree, tree->drag.type); + treeview__cw_drag_status(tree, + treeview__get_cw_drag_type(tree)); break; case TEXTAREA_MSG_REDRAW_REQUEST: @@ -2044,9 +2100,9 @@ treeview_create(treeview **tree, if (flags & TREEVIEW_SEARCHABLE) { (*tree)->search.textarea = treeview__create_textarea( *tree, 600, tree_g.line_height, - plot_style_even.text.background, - plot_style_even.text.background, - plot_style_even.text.foreground, + nscolours[NSCOLOUR_TEXT_INPUT_BG], + nscolours[NSCOLOUR_TEXT_INPUT_BG], + nscolours[NSCOLOUR_TEXT_INPUT_FG], plot_style_odd.text, treeview_textarea_search_callback); if ((*tree)->search.textarea == NULL) { @@ -2143,7 +2199,8 @@ treeview_node_expand_internal(treeview *tree, treeview_node *node) { treeview_node *child; struct treeview_node_entry *e; - int additional_height = 0; + int additional_height_folders = 0; + int additional_height_entries = 0; int i; assert(tree != NULL); @@ -2171,7 +2228,7 @@ treeview_node_expand_internal(treeview *tree, treeview_node *node) &(child->text.width)); } - additional_height += child->height; + additional_height_folders += child->height; child = child->next_sib; } while (child != NULL); @@ -2193,7 +2250,7 @@ treeview_node_expand_internal(treeview *tree, treeview_node *node) } /* Add height for field */ - additional_height += tree_g.line_height; + additional_height_entries += tree_g.line_height; } break; @@ -2212,17 +2269,18 @@ treeview_node_expand_internal(treeview *tree, treeview_node *node) for (struct treeview_node *n = node; (n != NULL) && (n->flags & TV_NFLAGS_EXPANDED); n = n->parent) { - n->height += additional_height; + n->height += additional_height_entries + + additional_height_folders; } if (tree->search.search && node->type == TREE_NODE_ENTRY && node->flags & TV_NFLAGS_MATCHED) { - tree->search.height += additional_height; + tree->search.height += additional_height_entries; } /* Inform front end of change in dimensions */ - if (additional_height != 0) { + if (additional_height_entries + additional_height_folders != 0) { treeview__cw_update_size(tree, -1, treeview__get_display_height(tree)); } @@ -2268,7 +2326,8 @@ struct treeview_contract_data { static nserror treeview_node_contract_cb(treeview_node *n, void *ctx, bool *end) { struct treeview_contract_data *data = ctx; - int h_reduction; + int h_reduction_folder = 0; + int h_reduction_entry = 0; assert(n != NULL); assert(n->type != TREE_NODE_ROOT); @@ -2281,17 +2340,30 @@ static nserror treeview_node_contract_cb(treeview_node *n, void *ctx, bool *end) return NSERROR_OK; } - h_reduction = n->height - tree_g.line_height; - assert(h_reduction >= 0); + switch (n->type) { + case TREE_NODE_FOLDER: + h_reduction_folder = n->height - tree_g.line_height; + break; + + case TREE_NODE_ENTRY: + h_reduction_entry = n->height - tree_g.line_height; + break; + + default: + break; + } + + + assert(h_reduction_folder + h_reduction_entry >= 0); for (struct treeview_node *node = n; (node != NULL) && (node->flags & TV_NFLAGS_EXPANDED); node = node->parent) { - node->height -= h_reduction; + node->height -= h_reduction_folder + h_reduction_entry; } if (data->tree->search.search) { - data->tree->search.height -= h_reduction; + data->tree->search.height -= h_reduction_entry; } n->flags ^= TV_NFLAGS_EXPANDED; @@ -2497,7 +2569,7 @@ static void treeview_redraw_tree( const int x, const int y, int *render_y_in_out, - struct rect *r, + const struct rect *r, struct content_redraw_data *data, const struct redraw_context *ctx) { @@ -2716,7 +2788,7 @@ static void treeview_redraw_search( const int x, const int y, int *render_y_in_out, - struct rect *r, + const struct rect *r, struct content_redraw_data *data, const struct redraw_context *ctx) { @@ -4175,7 +4247,8 @@ static void treeview_textarea_callback(void *data, struct textarea_msg *msg) /* Textarea drag started */ tree->drag.type = TV_DRAG_TEXTAREA; } - treeview__cw_drag_status(tree, tree->drag.type); + treeview__cw_drag_status(tree, + treeview__get_cw_drag_type(tree)); break; case TEXTAREA_MSG_REDRAW_REQUEST: @@ -4668,9 +4741,7 @@ treeview_mouse_action(treeview *tree, browser_mouse_state mouse, int x, int y) textarea_mouse_action(tree->edit.textarea, mouse, x - tree->edit.x, y - tree->edit.y); return; - } else if (tree->drag.type == TV_DRAG_SEARCH || - (y < search_height && - tree->drag.type == TV_DRAG_NONE)) { + } else if (tree->drag.type == TV_DRAG_SEARCH) { if (tree->search.active == false) { tree->search.active = true; if (treeview_clear_selection(tree, &r)) { @@ -4682,6 +4753,16 @@ treeview_mouse_action(treeview *tree, browser_mouse_state mouse, int x, int y) y); return; } else if (mouse & (BROWSER_MOUSE_PRESS_1 | BROWSER_MOUSE_PRESS_2) && + y < search_height && tree->search.active == false) { + tree->search.active = true; + if (treeview_clear_selection(tree, &r)) { + treeview__cw_invalidate_area(tree, &r); + } + textarea_mouse_action(tree->search.textarea, mouse, + x - tree_g.window_padding - tree_g.icon_size, + y); + return; + } else if (mouse & (BROWSER_MOUSE_PRESS_1 | BROWSER_MOUSE_PRESS_2) && tree->search.active == true) { tree->search.active = false; @@ -4839,6 +4920,31 @@ int treeview_get_height(treeview *tree) return height + search_height; } +/* Exported interface, documented in treeview.h */ +nserror treeview_set_search_string( + treeview *tree, + const char *string) +{ + if (!(tree->flags & TREEVIEW_SEARCHABLE)) { + return NSERROR_BAD_PARAMETER; + } + + if (string == NULL || strlen(string) == 0) { + tree->search.active = false; + tree->search.search = false; + return treeview__search(tree, "", 0); + } + + tree->search.active = true; + tree->search.search = true; + if (!textarea_set_text(tree->search.textarea, string)) { + return NSERROR_UNKNOWN; + } + + treeview__cw_full_redraw(tree); + + return NSERROR_OK; +} /** * Initialise the plot styles from CSS system colour values. @@ -4848,75 +4954,45 @@ int treeview_get_height(treeview *tree) */ static nserror treeview_init_plot_styles(int font_pt_size) { - nserror res; - /* Background colour */ plot_style_even.bg.stroke_type = PLOT_OP_TYPE_NONE; plot_style_even.bg.stroke_width = 0; plot_style_even.bg.stroke_colour = 0; plot_style_even.bg.fill_type = PLOT_OP_TYPE_SOLID; - res = ns_system_colour_char("Window", &plot_style_even.bg.fill_colour); - if (res != NSERROR_OK) { - return res; - } + plot_style_even.bg.fill_colour = nscolours[NSCOLOUR_WIN_EVEN_BG]; /* Text colour */ plot_style_even.text.family = PLOT_FONT_FAMILY_SANS_SERIF; plot_style_even.text.size = font_pt_size; plot_style_even.text.weight = 400; plot_style_even.text.flags = FONTF_NONE; - res = ns_system_colour_char("WindowText", &plot_style_even.text.foreground); - if (res != NSERROR_OK) { - return res; - } - res = ns_system_colour_char("Window", &plot_style_even.text.background); - if (res != NSERROR_OK) { - return res; - } + plot_style_even.text.foreground = nscolours[NSCOLOUR_WIN_EVEN_FG]; + plot_style_even.text.background = nscolours[NSCOLOUR_WIN_EVEN_BG]; /* Entry field text colour */ plot_style_even.itext = plot_style_even.text; - plot_style_even.itext.foreground = mix_colour( - plot_style_even.text.foreground, - plot_style_even.text.background, - 255 * 10 / 16); + plot_style_even.itext.foreground = nscolours[NSCOLOUR_WIN_EVEN_FG_FADED]; /* Selected background colour */ plot_style_even.sbg = plot_style_even.bg; - res = ns_system_colour_char("Highlight", &plot_style_even.sbg.fill_colour); - if (res != NSERROR_OK) { - return res; - } + plot_style_even.sbg.fill_colour = nscolours[NSCOLOUR_SEL_BG]; /* Selected text colour */ plot_style_even.stext = plot_style_even.text; - res = ns_system_colour_char("HighlightText", &plot_style_even.stext.foreground); - if (res != NSERROR_OK) { - return res; - } - res = ns_system_colour_char("Highlight", &plot_style_even.stext.background); - if (res != NSERROR_OK) { - return res; - } + plot_style_even.stext.foreground = nscolours[NSCOLOUR_SEL_FG]; + plot_style_even.stext.background = nscolours[NSCOLOUR_SEL_BG]; /* Selected entry field text colour */ plot_style_even.sitext = plot_style_even.stext; - plot_style_even.sitext.foreground = mix_colour( - plot_style_even.stext.foreground, - plot_style_even.stext.background, - 255 * 25 / 32); + plot_style_even.sitext.foreground = nscolours[NSCOLOUR_SEL_FG_SUBTLE]; /* Odd numbered node styles */ plot_style_odd.bg = plot_style_even.bg; - plot_style_odd.bg.fill_colour = mix_colour( - plot_style_even.bg.fill_colour, - plot_style_even.text.foreground, 255 * 15 / 16); + plot_style_odd.bg.fill_colour = nscolours[NSCOLOUR_WIN_ODD_BG]; plot_style_odd.text = plot_style_even.text; plot_style_odd.text.background = plot_style_odd.bg.fill_colour; plot_style_odd.itext = plot_style_odd.text; - plot_style_odd.itext.foreground = mix_colour( - plot_style_odd.text.foreground, - plot_style_odd.text.background, 255 * 10 / 16); + plot_style_odd.itext.foreground = nscolours[NSCOLOUR_WIN_EVEN_FG_FADED]; plot_style_odd.sbg = plot_style_even.sbg; plot_style_odd.stext = plot_style_even.stext; @@ -5002,7 +5078,7 @@ treeview_generate_triangle_bitmap(colour bg, colour fg, int size) colour colour4 = fg; /* Create the bitmap */ - b = guit->bitmap->create(size, size, BITMAP_NEW | BITMAP_OPAQUE); + b = guit->bitmap->create(size, size, BITMAP_OPAQUE); if (b == NULL) return NULL; @@ -5016,58 +5092,68 @@ treeview_generate_triangle_bitmap(colour bg, colour fg, int size) if (y < size / 2) { /* Top half */ for (x = 0; x < y * 2; x++) { - *(pos++) = red_from_colour(colour4); - *(pos++) = green_from_colour(colour4); - *(pos++) = blue_from_colour(colour4); - *(pos++) = 0xff; + pos[bitmap_layout.r] = red_from_colour(colour4); + pos[bitmap_layout.g] = green_from_colour(colour4); + pos[bitmap_layout.b] = blue_from_colour(colour4); + pos[bitmap_layout.a] = 0xff; + pos += 4; } - *(pos++) = red_from_colour(colour3); - *(pos++) = green_from_colour(colour3); - *(pos++) = blue_from_colour(colour3); - *(pos++) = 0xff; - *(pos++) = red_from_colour(colour1); - *(pos++) = green_from_colour(colour1); - *(pos++) = blue_from_colour(colour1); - *(pos++) = 0xff; + pos[bitmap_layout.r] = red_from_colour(colour3); + pos[bitmap_layout.g] = green_from_colour(colour3); + pos[bitmap_layout.b] = blue_from_colour(colour3); + pos[bitmap_layout.a] = 0xff; + pos += 4; + pos[bitmap_layout.r] = red_from_colour(colour1); + pos[bitmap_layout.g] = green_from_colour(colour1); + pos[bitmap_layout.b] = blue_from_colour(colour1); + pos[bitmap_layout.a] = 0xff; + pos += 4; for (x = y * 2 + 2; x < size ; x++) { - *(pos++) = red_from_colour(colour0); - *(pos++) = green_from_colour(colour0); - *(pos++) = blue_from_colour(colour0); - *(pos++) = 0xff; + pos[bitmap_layout.r] = red_from_colour(colour0); + pos[bitmap_layout.g] = green_from_colour(colour0); + pos[bitmap_layout.b] = blue_from_colour(colour0); + pos[bitmap_layout.a] = 0xff; + pos += 4; } } else if ((y == size / 2) && (size & 0x1)) { /* Middle row */ for (x = 0; x < size - 1; x++) { - *(pos++) = red_from_colour(colour4); - *(pos++) = green_from_colour(colour4); - *(pos++) = blue_from_colour(colour4); - *(pos++) = 0xff; + pos[bitmap_layout.r] = red_from_colour(colour4); + pos[bitmap_layout.g] = green_from_colour(colour4); + pos[bitmap_layout.b] = blue_from_colour(colour4); + pos[bitmap_layout.a] = 0xff; + pos += 4; } - *(pos++) = red_from_colour(colour2); - *(pos++) = green_from_colour(colour2); - *(pos++) = blue_from_colour(colour2); - *(pos++) = 0xff; + pos[bitmap_layout.r] = red_from_colour(colour2); + pos[bitmap_layout.g] = green_from_colour(colour2); + pos[bitmap_layout.b] = blue_from_colour(colour2); + pos[bitmap_layout.a] = 0xff; + pos += 4; } else { /* Bottom half */ for (x = 0; x < (size - y - 1) * 2; x++) { - *(pos++) = red_from_colour(colour4); - *(pos++) = green_from_colour(colour4); - *(pos++) = blue_from_colour(colour4); - *(pos++) = 0xff; + pos[bitmap_layout.r] = red_from_colour(colour4); + pos[bitmap_layout.g] = green_from_colour(colour4); + pos[bitmap_layout.b] = blue_from_colour(colour4); + pos[bitmap_layout.a] = 0xff; + pos += 4; } - *(pos++) = red_from_colour(colour3); - *(pos++) = green_from_colour(colour3); - *(pos++) = blue_from_colour(colour3); - *(pos++) = 0xff; - *(pos++) = red_from_colour(colour1); - *(pos++) = green_from_colour(colour1); - *(pos++) = blue_from_colour(colour1); - *(pos++) = 0xff; + pos[bitmap_layout.r] = red_from_colour(colour3); + pos[bitmap_layout.g] = green_from_colour(colour3); + pos[bitmap_layout.b] = blue_from_colour(colour3); + pos[bitmap_layout.a] = 0xff; + pos += 4; + pos[bitmap_layout.r] = red_from_colour(colour1); + pos[bitmap_layout.g] = green_from_colour(colour1); + pos[bitmap_layout.b] = blue_from_colour(colour1); + pos[bitmap_layout.a] = 0xff; + pos += 4; for (x = (size - y) * 2; x < size ; x++) { - *(pos++) = red_from_colour(colour0); - *(pos++) = green_from_colour(colour0); - *(pos++) = blue_from_colour(colour0); - *(pos++) = 0xff; + pos[bitmap_layout.r] = red_from_colour(colour0); + pos[bitmap_layout.g] = green_from_colour(colour0); + pos[bitmap_layout.b] = blue_from_colour(colour0); + pos[bitmap_layout.a] = 0xff; + pos += 4; } } @@ -5101,7 +5187,7 @@ treeview_generate_copy_bitmap(struct bitmap *orig, int size) assert(size == guit->bitmap->get_height(orig)); /* Create the bitmap */ - b = guit->bitmap->create(size, size, BITMAP_NEW | BITMAP_OPAQUE); + b = guit->bitmap->create(size, size, BITMAP_OPAQUE); if (b == NULL) return NULL; @@ -5149,7 +5235,7 @@ treeview_generate_rotate_bitmap(struct bitmap *orig, int size) assert(size == guit->bitmap->get_height(orig)); /* Create the bitmap */ - b = guit->bitmap->create(size, size, BITMAP_NEW | BITMAP_OPAQUE); + b = guit->bitmap->create(size, size, BITMAP_OPAQUE); if (b == NULL) return NULL; diff --git a/desktop/treeview.h b/desktop/treeview.h index a8cf29ac5..df9b4fb26 100644 --- a/desktop/treeview.h +++ b/desktop/treeview.h @@ -495,4 +495,15 @@ void treeview_edit_selection(treeview *tree); */ int treeview_get_height(treeview *tree); + +/** + * Set the search string for a treeview with \ref TREEVIEW_SEARCHABLE + * + * \param tree Tree to set the search string for. + * \return NSERROR_OK on success, appropriate error otherwise + */ +nserror treeview_set_search_string( + treeview *tree, + const char *string); + #endif diff --git a/desktop/version.c b/desktop/version.c index 92240cd07..91a7532f4 100644 --- a/desktop/version.c +++ b/desktop/version.c @@ -20,11 +20,11 @@ #include "desktop/version.h" -const char * const netsurf_version = "3.10 (Dev" +const char * const netsurf_version = "3.12 (Dev" #if defined(CI_BUILD) " CI #" CI_BUILD #endif ")" ; const int netsurf_version_major = 3; -const int netsurf_version_minor = 10; +const int netsurf_version_minor = 12; |