From 21af6f7fda78586936405538e97e02ffa198f0e8 Mon Sep 17 00:00:00 2001 From: James Bursa Date: Sun, 26 Nov 2006 20:11:20 +0000 Subject: Move frames-related code out of browser.c into a new file. Remove some browser_window calls from html.c. svn path=/trunk/netsurf/; revision=3070 --- desktop/browser.c | 1101 ++++++++++++----------------------------------------- desktop/browser.h | 10 +- desktop/frames.c | 662 ++++++++++++++++++++++++++++++++ desktop/frames.h | 30 ++ render/html.c | 5 - 5 files changed, 937 insertions(+), 871 deletions(-) create mode 100644 desktop/frames.c create mode 100644 desktop/frames.h diff --git a/desktop/browser.c b/desktop/browser.c index c948c2117..2b28f87c7 100644 --- a/desktop/browser.c +++ b/desktop/browser.c @@ -3,9 +3,10 @@ * Licensed under the GNU General Public License, * http://www.opensource.org/licenses/gpl-license * Copyright 2003 Phil Mellor - * Copyright 2005 James Bursa + * Copyright 2006 James Bursa * Copyright 2004 Andrew Timmins * Copyright 2004 John Tytgat + * Copyright 2006 Richard Wilson */ /** \file @@ -30,6 +31,7 @@ #include "netsurf/desktop/401login.h" #endif #include "netsurf/desktop/browser.h" +#include "netsurf/desktop/frames.h" #include "netsurf/desktop/history_core.h" #include "netsurf/desktop/gui.h" #include "netsurf/desktop/options.h" @@ -49,22 +51,15 @@ #include "netsurf/utils/utils.h" #include "netsurf/utils/utf8.h" -/** maximum frame resize margin */ -#define FRAME_RESIZE 6 - -/** maximum frame depth */ -#define FRAME_DEPTH 8 - /** browser window which is being redrawn. Valid only during redraw. */ struct browser_window *current_redraw_browser; /** fake content for being saved as a link */ struct content browser_window_href_content; -static void browser_window_set_scale_internal(struct browser_window *bw, float scale); -static void browser_window_resize_frame(struct browser_window *bw, int x, int y); -static bool browser_window_resolve_frame_dimension(struct browser_window *bw, - struct browser_window *sibling, int x, int y, bool width, bool height); +/** maximum frame depth */ +#define FRAME_DEPTH 8 + static void browser_window_callback(content_msg msg, struct content *c, intptr_t p1, intptr_t p2, union content_msg_data data); static void browser_window_refresh(void *p); @@ -74,18 +69,21 @@ static void browser_window_start_throbber(struct browser_window *bw); static void browser_window_stop_throbber(struct browser_window *bw); static void browser_window_set_status(struct browser_window *bw, const char *text); -static void browser_window_set_pointer(struct gui_window *g, gui_pointer_shape shape); +static void browser_window_set_pointer(struct gui_window *g, + gui_pointer_shape shape); static void download_window_callback(fetch_msg msg, void *p, const void *data, unsigned long size); static void browser_window_destroy_children(struct browser_window *bw); static void browser_window_destroy_internal(struct browser_window *bw); -static struct browser_window *browser_window_find_target(struct browser_window *bw, const char *target); -static void browser_window_find_target_internal(struct browser_window *bw, const char *target, - int depth, struct browser_window *page, int *rdepth, struct browser_window **bw_target); +static void browser_window_set_scale_internal(struct browser_window *bw, + float scale); +static struct browser_window *browser_window_find_target( + struct browser_window *bw, const char *target); +static void browser_window_find_target_internal(struct browser_window *bw, + const char *target, int depth, struct browser_window *page, + int *rdepth, struct browser_window **bw_target); static void browser_window_mouse_action_html(struct browser_window *bw, browser_mouse_state mouse, int x, int y); -static bool browser_window_resize_frames(struct browser_window *bw, browser_mouse_state mouse, - int x, int y, gui_pointer_shape *pointer, const char **status, bool *action); static void browser_window_mouse_action_text(struct browser_window *bw, browser_mouse_state mouse, int x, int y); static void browser_window_mouse_track_html(struct browser_window *bw, @@ -117,7 +115,8 @@ static void browser_window_scroll_box(struct browser_window *bw, * \param referer The referring uri */ -struct browser_window *browser_window_create(const char *url, struct browser_window *clone, +struct browser_window *browser_window_create(const char *url, + struct browser_window *clone, char *referer, bool history_add) { struct browser_window *bw; @@ -159,582 +158,6 @@ struct browser_window *browser_window_create(const char *url, struct browser_win } -/** - * Returns the browser window that is responsible for the child. - * - * \param bw The browser window to find the owner of - * \return the browser window's owner - */ - -struct browser_window *browser_window_owner(struct browser_window *bw) { - /* an iframe's parent is just the parent window */ - if (bw->browser_window_type == BROWSER_WINDOW_IFRAME) - return bw->parent; - - /* the parent of a frameset is either a NORMAL window or an IFRAME */ - while (bw->parent) { - switch (bw->browser_window_type) { - case BROWSER_WINDOW_NORMAL: - case BROWSER_WINDOW_IFRAME: - return bw; - case BROWSER_WINDOW_FRAME: - case BROWSER_WINDOW_FRAMESET: - bw = bw->parent; - break; - } - } - return bw; -} - - -/** - * Create and open a iframes for a browser window. - * - * \param bw The browser window to create iframes for - * \param iframe The iframes to create - */ - -void browser_window_create_iframes(struct browser_window *bw, - struct content_html_iframe *iframe) { - struct browser_window *window; - struct content_html_iframe *cur; - int iframes = 0; - int index; - - for (cur = iframe; cur; cur = cur->next) - iframes++; - bw->iframes = calloc(iframes, sizeof(*bw)); - if (!bw->iframes) - return; - bw->iframe_count = iframes; - - index = 0; - for (cur = iframe; cur; cur = cur->next) { - window = &(bw->iframes[index++]); - - /* content */ - window->history = history_create(); - window->sel = selection_create(window); - window->refresh_interval = -1; - - /* window characteristics */ - window->drag_type = DRAGGING_NONE; - window->browser_window_type = BROWSER_WINDOW_IFRAME; - window->scrolling = cur->scrolling; - window->border = cur->border; - window->border_colour = cur->border_colour; - window->no_resize = true; - window->margin_width = cur->margin_width; - window->margin_height = cur->margin_height; - if (cur->name) - window->name = strdup(cur->name); - - /* linking */ - window->box = cur->box; - window->parent = bw; - - /* gui window */ - window->window = gui_create_browser_window(window, bw); - } - - /* calculate dimensions */ - gui_window_update_extent(bw->window); - browser_window_recalculate_iframes(bw); - - index = 0; - for (cur = iframe; cur; cur = cur->next) { - window = &(bw->iframes[index++]); - if (cur->url) - browser_window_go(window, cur->url, NULL, true); - } -} - - -/** - * Recalculate iframe positions following a resize. - * - * \param bw The browser window to reposition iframes for - */ - -void browser_window_recalculate_iframes(struct browser_window *bw) { - struct browser_window *window; - struct rect rect; - int bw_width, bw_height; - int index; - - assert(bw); - - /* update window dimensions */ - gui_window_get_dimensions(bw->window, &bw_width, &bw_height, false); - if (!bw->parent) { - bw->x0 = 0; - bw->y0 = 0; - bw->x1 = bw_width; - bw->y1 = bw_height; - } - - for (index = 0; index < bw->iframe_count; index++) { - window = &(bw->iframes[index]); - box_bounds(window->box, &rect); - gui_window_position_frame(window->window, rect.x0, rect.y0, - rect.x1, rect.y1); - } -} - - -/** - * Create and open aframeset for a browser window. - * - * \param bw The browser window to create the frameset for - * \param iframe The frameset to create - */ - -void browser_window_create_frameset(struct browser_window *bw, - struct content_html_frames *frameset) { - int row, col, index; - struct content_html_frames *frame; - struct browser_window *window; - - /* we use a 3 stage approach such that the content is initially formatted to the - * correct frameset dimensions */ - assert(bw && frameset); - - /* 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; - 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]; - - /* content */ - window->history = history_create(); - window->sel = selection_create(window); - window->refresh_interval = -1; - - /* window characteristics */ - window->drag_type = DRAGGING_NONE; - 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); - - /* linking */ - window->parent = bw; - - /* gui window */ - window->window = gui_create_browser_window(window, bw); - if (frame->children) - browser_window_create_frameset(window, frame); - } - } - - /* calculate dimensions */ - gui_window_update_extent(bw->window); - browser_window_recalculate_frameset(bw); - - /* 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_go(window, frame->url, NULL, true); - } - } -} - - -/** - * Recalculate frameset positions following a resize. - * - * \param bw The browser window to reposition framesets for - */ - -void browser_window_recalculate_frameset(struct browser_window *bw) { - int widths[bw->cols][bw->rows]; - int heights[bw->cols][bw->rows]; - int bw_width, bw_height; - int avail_width, avail_height; - int row, row2, col, index; - struct browser_window *window; - float relative; - int size, extent; - int x, y; - - assert(bw); - - /* window dimensions */ - if (!bw->parent) { - gui_window_get_dimensions(bw->window, &bw_width, &bw_height, false); - bw->x0 = 0; - bw->y0 = 0; - bw->x1 = bw_width; - bw->y1 = bw_height; - } else { - bw_width = bw->x1 - bw->x0; - bw_height = bw->y1 - bw->y0; - } - bw_width++; - bw_height++; - - /* widths */ - for (row = 0; row < bw->rows; row++) { - avail_width = bw_width; - relative = 0; - for (col = 0; col < bw->cols; col++) { - index = (row * bw->cols) + col; - window = &bw->children[index]; - - switch (window->frame_width.unit) { - case FRAME_DIMENSION_PIXELS: - widths[col][row] = window->frame_width.value * - gui_window_get_scale(window->window); - if (window->border) { - if (col != 0) - widths[col][row] += 1; - if (col != bw->cols - 1) - widths[col][row] += 1; - } - break; - case FRAME_DIMENSION_PERCENT: - widths[col][row] = bw_width * window->frame_width.value / 100; - break; - case FRAME_DIMENSION_RELATIVE: - widths[col][row] = 0; - relative += window->frame_width.value; - break; - } - avail_width -= widths[col][row]; - } - - /* try to distribute remainder to relative values in preference */ - if ((relative > 0) && (avail_width > 0)) { - for (col = 0; col < bw->cols; col++) { - index = (row * bw->cols) + col; - window = &bw->children[index]; - - if (window->frame_width.unit == FRAME_DIMENSION_RELATIVE) { - size = avail_width * window->frame_width.value / relative; - avail_width -= size; - relative -= window->frame_width.value; - widths[col][row] += size; - } - } - } else if (bw_width != avail_width) { - /* proportionally distribute error */ - extent = bw_width - avail_width; - for (col = 0; col < bw->cols; col++) { - index = (row * bw->cols) + col; - window = &bw->children[index]; - - if (col == bw->cols - 1) { - widths[col][row] = bw_width; - } else { - size = bw_width * widths[col][row] / extent; - bw_width -= size; - extent -= widths[col][row]; - widths[col][row] = size; - } - } - } - } - - /* heights */ - for (col = 0; col < bw->cols; col++) { - avail_height = bw_height; - relative = 0; - for (row = 0; row < bw->rows; row++) { - index = (row * bw->cols) + col; - window = &bw->children[index]; - - switch (window->frame_height.unit) { - case FRAME_DIMENSION_PIXELS: - heights[col][row] = window->frame_height.value * - gui_window_get_scale(window->window); - if (window->border) { - if (row != 0) - heights[col][row] += 1; - if (row != bw->rows - 1) - heights[col][row] += 1; - } - break; - case FRAME_DIMENSION_PERCENT: - heights[col][row] = bw_height * - window->frame_height.value / 100; - break; - case FRAME_DIMENSION_RELATIVE: - heights[col][row] = 0; - relative += window->frame_height.value; - break; - } - avail_height -= heights[col][row]; - } - - if (avail_height == 0) - continue; - - /* try to distribute remainder to relative values in preference */ - if ((relative > 0) && (avail_height > 0)) { - for (row = 0; row < bw->rows; row++) { - index = (row * bw->cols) + col; - window = &bw->children[index]; - - if (window->frame_height.unit == FRAME_DIMENSION_RELATIVE) { - size = avail_height * window->frame_height.value / relative; - avail_height -= size; - relative -= window->frame_height.value; - heights[col][row] += size; - } - } - } else if (bw_height != avail_height) { - /* proportionally distribute error */ - extent = bw_height - avail_height; - for (row = 0; row < bw->rows; row++) { - index = (row * bw->cols) + col; - window = &bw->children[index]; - - if (row == bw->rows - 1) { - heights[col][row] = bw_height; - } else { - size = bw_height * heights[col][row] / extent; - bw_height -= size; - extent -= heights[col][row]; - heights[col][row] = size; - } - } - } - } - - /* position frames and calculate children */ - for (row = 0; row < bw->rows; row++) { - x = 0; - for (col = 0; col < bw->cols; col++) { - index = (row * bw->cols) + col; - window = &bw->children[index]; - - y = 0; - for (row2 = 0; row2 < row; row2++) - y+= heights[col][row2]; - gui_window_position_frame(window->window, x, y, - x + widths[col][row] - 1, - y + heights[col][row] - 1); - x += widths[col][row]; - if (window->children) - browser_window_recalculate_frameset(window); - } - } -} - - -/** - * Sets the scale of a browser window - * - * \param bw The browser window to scale - * \param scale The new scale - * \param all Scale all windows in the tree (ie work up aswell as down) - */ -void browser_window_set_scale(struct browser_window *bw, float scale, bool all) { - while (bw->parent && all) - bw = bw->parent; - browser_window_set_scale_internal(bw, scale); - if (bw->parent) - bw = bw->parent; - browser_window_recalculate_frameset(bw); -} - -void browser_window_set_scale_internal(struct browser_window *bw, float scale) { - int i; - - gui_window_set_scale(bw->window, scale); - - for (i = 0; i < (bw->cols * bw->rows); i++) - browser_window_set_scale_internal(&bw->children[i], scale); - for (i = 0; i < bw->iframe_count; i++) - browser_window_set_scale_internal(&bw->iframes[i], scale); -} - - -/** - * Resize a browser window that is a frame. - * - * \param bw The browser window to resize - */ - -void browser_window_resize_frame(struct browser_window *bw, int x, int y) { - struct browser_window *parent; - struct browser_window *sibling; - int col = -1, row = -1, i; - bool change = false; - - parent = bw->parent; - assert(parent); - - /* get frame location */ - for (i = 0; i < (parent->cols * parent->rows); i++) { - if (&parent->children[i] == bw) { - col = i % parent->cols; - row = i / parent->cols; - } - } - assert((col >= 0) && (row >= 0)); - - sibling = NULL; - if (bw->drag_resize_left) - sibling = &parent->children[row * parent->cols + (col - 1)]; - else if (bw->drag_resize_right) - sibling = &parent->children[row * parent->cols + (col + 1)]; - if (sibling) - change |= browser_window_resolve_frame_dimension(bw, sibling, x, y, true, false); - - sibling = NULL; - if (bw->drag_resize_up) - sibling = &parent->children[(row - 1) * parent->cols + col]; - else if (bw->drag_resize_down) - sibling = &parent->children[(row + 1) * parent->cols + col]; - if (sibling) - change |= browser_window_resolve_frame_dimension(bw, sibling, x, y, false, true); - - if (change) - browser_window_recalculate_frameset(parent); -} - - -bool browser_window_resolve_frame_dimension(struct browser_window *bw, struct browser_window *sibling, - int x, int y, bool width, bool height) { - int bw_dimension, sibling_dimension; - int bw_pixels, sibling_pixels; - struct frame_dimension *bw_d, *sibling_d; - float total_new; - int frame_size; - - assert(!(width && height)); - - /* extend/shrink the box to the pointer */ - if (width) { - if (bw->drag_resize_left) - bw_dimension = bw->x1 - x; - else - bw_dimension = x - bw->x0; - bw_pixels = (bw->x1 - bw->x0); - sibling_pixels = (sibling->x1 - sibling->x0); - bw_d = &bw->frame_width; - sibling_d = &sibling->frame_width; - frame_size = bw->parent->x1 - bw->parent->x0; - } else { - if (bw->drag_resize_up) - bw_dimension = bw->y1 - y; - else - bw_dimension = y - bw->y0; - bw_pixels = (bw->y1 - bw->y0); - sibling_pixels = (sibling->y1 - sibling->y0); - bw_d = &bw->frame_height; - sibling_d = &sibling->frame_height; - frame_size = bw->parent->y1 - bw->parent->y0; - } - sibling_dimension = bw_pixels + sibling_pixels - bw_dimension; - - /* check for no change or no frame size*/ - if ((bw_dimension == bw_pixels) || (frame_size == 0)) - return false; - /* check for both being 0 */ - total_new = bw_dimension + sibling_dimension; - if ((bw_dimension + sibling_dimension) == 0) - return false; - - /* our frame dimensions are now known to be: - * - * <-- frame_size --> [VISIBLE PIXELS] - * |<-- bw_pixels -->|<-- sibling_pixels -->| [VISIBLE PIXELS, BEFORE RESIZE] - * |<-- bw_d->value-->|<-- sibling_d->value-->| [SPECIFIED UNITS, BEFORE RESIZE] - * |<--bw_dimension-->|<--sibling_dimension-->| [VISIBLE PIXELS, AFTER RESIZE] - * |<-- total_new -->| [VISIBLE PIXELS, AFTER RESIZE] - * - * when we resize, we must retain the original unit specification such that any - * subsequent resizing of the parent window will recalculate the page as the - * author specified. - * - * if the units of both frames are the same then we can resize the values simply - * by updating the values to be a percentage of the original widths. - */ - if (bw_d->unit == sibling_d->unit) { - float total_specified = bw_d->value + sibling_d->value; - bw_d->value = (total_specified * bw_dimension) / total_new; - sibling_d->value = total_specified - bw_d->value; - return true; - } - - /* if one of the sizes is relative then we don't alter the relative width and - * just let it reflow across. the non-relative (pixel/percentage) value can - * simply be resolved to the specified width that will result in the required - * dimension. - */ - if (bw_d->unit == FRAME_DIMENSION_RELATIVE) { - if ((sibling_pixels == 0) && (bw_dimension == 0)) - return false; - if (sibling_d->value == 0) - bw_d->value = 1; - if (sibling_pixels == 0) - sibling_d->value = (sibling_d->value * bw_pixels) / bw_dimension; - else - sibling_d->value = - (sibling_d->value * sibling_dimension) / sibling_pixels; - - /* todo: the availble resize may have changed, update the drag box */ - return true; - } else if (sibling_d->unit == FRAME_DIMENSION_RELATIVE) { - if ((bw_pixels == 0) && (sibling_dimension == 0)) - return false; - if (bw_d->value == 0) - bw_d->value = 1; - if (bw_pixels == 0) - bw_d->value = (bw_d->value * sibling_pixels) / sibling_dimension; - else - bw_d->value = (bw_d->value * bw_dimension) / bw_pixels; - - /* todo: the availble resize may have changed, update the drag box */ - return true; - } - - /* finally we have a pixel/percentage mix. unlike relative values, percentages - * can easily be backwards-calculated as they can simply be scaled like pixel - * values - */ - if (bw_d->unit == FRAME_DIMENSION_PIXELS) { - float total_specified = bw_d->value + frame_size * sibling_d->value / 100; - bw_d->value = (total_specified * bw_dimension) / total_new; - sibling_d->value = (total_specified - bw_d->value) * 100 / frame_size; - return true; - } else if (sibling_d->unit == FRAME_DIMENSION_PIXELS) { - float total_specified = bw_d->value * frame_size / 100 + sibling_d->value; - sibling_d->value = (total_specified * sibling_dimension) / total_new; - bw_d->value = (total_specified - sibling_d->value) * 100 / frame_size; - return true; - } - assert(!"Invalid frame dimension unit"); - return false; -} - - /** * Start fetching a page in a browser window. * @@ -901,196 +324,201 @@ void browser_window_callback(content_msg msg, struct content *c, switch (msg) { - case CONTENT_MSG_LOADING: - assert(bw->loading_content == c); + case CONTENT_MSG_LOADING: + assert(bw->loading_content == c); - if (c->type == CONTENT_OTHER) - browser_window_convert_to_download(bw); + if (c->type == CONTENT_OTHER) + browser_window_convert_to_download(bw); #ifdef WITH_THEME_INSTALL - else if (c->type == CONTENT_THEME) { - theme_install_start(c); - bw->loading_content = 0; - content_remove_user(c, browser_window_callback, - (intptr_t) bw, 0); - browser_window_stop_throbber(bw); - } + else if (c->type == CONTENT_THEME) { + theme_install_start(c); + bw->loading_content = 0; + content_remove_user(c, browser_window_callback, + (intptr_t) bw, 0); + browser_window_stop_throbber(bw); + } #endif - else { - if (bw->frag_id) - snprintf(url, sizeof url, "%s#%s", - c->url, bw->frag_id); - else - snprintf(url, sizeof url, "%s", - c->url); - url[sizeof url - 1] = 0; - gui_window_set_url(bw->window, url); - bw->refresh_interval = -1; - } - break; - - case CONTENT_MSG_READY: - assert(bw->loading_content == c); - - if (bw->current_content) { - if (bw->current_content->status == - CONTENT_STATUS_READY || - bw->current_content->status == - CONTENT_STATUS_DONE) - content_close(bw->current_content); - content_remove_user(bw->current_content, - browser_window_callback, - (intptr_t) bw, 0); - } - bw->current_content = c; - bw->loading_content = NULL; - browser_window_remove_caret(bw); - bw->scrolling_box = NULL; - gui_window_new_content(bw->window); + else { if (bw->frag_id) snprintf(url, sizeof url, "%s#%s", - c->url, bw->frag_id); + c->url, bw->frag_id); else snprintf(url, sizeof url, "%s", c->url); url[sizeof url - 1] = 0; gui_window_set_url(bw->window, url); - browser_window_update(bw, true); - content_open(c, bw, 0, 0, 0, 0); - browser_window_set_status(bw, c->status_message); - if ((bw->history_add) && (bw->history)) { - history_add(bw->history, c, bw->frag_id); - if (urldb_add_url(c->url)) { - urldb_set_url_title(c->url, - c->title ? c->title : c->url); - urldb_update_url_visit_data(c->url); - urldb_set_url_content_type(c->url, - c->type); - /* This is safe as we've just - * added the URL */ - global_history_add( - urldb_get_url(c->url)); - } - } - switch (c->type) { - case CONTENT_HTML: - selection_init(bw->sel, bw->current_content->data.html.layout); - break; - case CONTENT_TEXTPLAIN: - selection_init(bw->sel, NULL); - break; - default: - break; + bw->refresh_interval = -1; + } + break; + + case CONTENT_MSG_READY: + assert(bw->loading_content == c); + + if (bw->current_content) { + if (bw->current_content->status == + CONTENT_STATUS_READY || + bw->current_content->status == + CONTENT_STATUS_DONE) + content_close(bw->current_content); + content_remove_user(bw->current_content, + browser_window_callback, + (intptr_t) bw, 0); + } + bw->current_content = c; + bw->loading_content = NULL; + browser_window_remove_caret(bw); + bw->scrolling_box = NULL; + gui_window_new_content(bw->window); + if (bw->frag_id) + snprintf(url, sizeof url, "%s#%s", c->url, bw->frag_id); + else + snprintf(url, sizeof url, "%s", c->url); + url[sizeof url - 1] = 0; + gui_window_set_url(bw->window, url); + browser_window_update(bw, true); + content_open(c, bw, 0, 0, 0, 0); + browser_window_set_status(bw, c->status_message); + + /* history */ + if (bw->history_add && bw->history) { + history_add(bw->history, c, bw->frag_id); + if (urldb_add_url(c->url)) { + urldb_set_url_title(c->url, + c->title ? c->title : c->url); + urldb_update_url_visit_data(c->url); + urldb_set_url_content_type(c->url, + c->type); + /* This is safe as we've just + * added the URL */ + global_history_add( + urldb_get_url(c->url)); } - break; + } - case CONTENT_MSG_DONE: - assert(bw->current_content == c); + /* text selection */ + if (c->type == CONTENT_HTML) + selection_init(bw->sel, + bw->current_content->data.html.layout); + if (c->type == CONTENT_TEXTPLAIN) + selection_init(bw->sel, NULL); - browser_window_update(bw, false); - sprintf(status, messages_get("Complete"), - ((float) (clock() - bw->time0)) / - CLOCKS_PER_SEC); - browser_window_set_status(bw, status); - browser_window_stop_throbber(bw); - history_update(bw->history, c); - hotlist_visited(c); - free(bw->referer); - bw->referer = 0; - if (bw->refresh_interval != -1) - schedule(bw->refresh_interval, - browser_window_refresh, bw); - break; + /* frames */ + if (c->type == CONTENT_HTML && c->data.html.frameset) + browser_window_create_frameset(bw, + c->data.html.frameset); + if (c->type == CONTENT_HTML && c->data.html.iframe) + browser_window_create_iframes(bw, c->data.html.iframe); - case CONTENT_MSG_ERROR: - browser_window_set_status(bw, data.error); - warn_user(data.error, 0); - if (c == bw->loading_content) - bw->loading_content = 0; - else if (c == bw->current_content) { - bw->current_content = 0; - browser_window_remove_caret(bw); - bw->scrolling_box = NULL; - selection_init(bw->sel, NULL); - } - browser_window_stop_throbber(bw); - free(bw->referer); - bw->referer = 0; - break; + break; - case CONTENT_MSG_STATUS: - browser_window_set_status(bw, c->status_message); - break; + case CONTENT_MSG_DONE: + assert(bw->current_content == c); + + browser_window_update(bw, false); + sprintf(status, messages_get("Complete"), + ((float) (clock() - bw->time0)) / + CLOCKS_PER_SEC); + browser_window_set_status(bw, status); + browser_window_stop_throbber(bw); + history_update(bw->history, c); + hotlist_visited(c); + free(bw->referer); + bw->referer = 0; + if (bw->refresh_interval != -1) + schedule(bw->refresh_interval, + browser_window_refresh, bw); + break; - case CONTENT_MSG_REDIRECT: + case CONTENT_MSG_ERROR: + browser_window_set_status(bw, data.error); + warn_user(data.error, 0); + if (c == bw->loading_content) bw->loading_content = 0; - browser_window_set_status(bw, - messages_get("Redirecting")); - /* the spec says nothing about referrers and - * redirects => follow Mozilla and preserve the - * referer across the redirect */ - browser_window_go_post(bw, data.redirect, 0, 0, - bw->history_add, bw->referer, - bw->download); - break; + else if (c == bw->current_content) { + bw->current_content = 0; + browser_window_remove_caret(bw); + bw->scrolling_box = NULL; + selection_init(bw->sel, NULL); + } + browser_window_stop_throbber(bw); + free(bw->referer); + bw->referer = 0; + break; - case CONTENT_MSG_REFORMAT: - if (c == bw->current_content && - c->type == CONTENT_HTML) { - /* box tree may have changed, need to relabel */ - selection_reinit(bw->sel, c->data.html.layout); - } - if (bw->move_callback) - bw->move_callback(bw, bw->caret_p); - browser_window_update(bw, false); - break; + case CONTENT_MSG_STATUS: + browser_window_set_status(bw, c->status_message); + break; - case CONTENT_MSG_REDRAW: - gui_window_update_box(bw->window, &data); - break; + case CONTENT_MSG_REDIRECT: + bw->loading_content = 0; + browser_window_set_status(bw, + messages_get("Redirecting")); + /* the spec says nothing about referrers and + * redirects => follow Mozilla and preserve the + * referer across the redirect */ + browser_window_go_post(bw, data.redirect, 0, 0, + bw->history_add, bw->referer, + bw->download); + break; - case CONTENT_MSG_NEWPTR: - bw->loading_content = c; - break; + case CONTENT_MSG_REFORMAT: + if (c == bw->current_content && + c->type == CONTENT_HTML) { + /* box tree may have changed, need to relabel */ + selection_reinit(bw->sel, c->data.html.layout); + } + if (bw->move_callback) + bw->move_callback(bw, bw->caret_p); + browser_window_update(bw, false); + break; + + case CONTENT_MSG_REDRAW: + gui_window_update_box(bw->window, &data); + break; + + case CONTENT_MSG_NEWPTR: + bw->loading_content = c; + break; #ifdef WITH_AUTH - case CONTENT_MSG_AUTH: - gui_401login_open(bw, c, data.auth_realm); - if (c == bw->loading_content) - bw->loading_content = 0; - else if (c == bw->current_content) { - bw->current_content = 0; - browser_window_remove_caret(bw); - bw->scrolling_box = NULL; - selection_init(bw->sel, NULL); - } - browser_window_stop_throbber(bw); - free(bw->referer); - bw->referer = 0; - break; + case CONTENT_MSG_AUTH: + gui_401login_open(bw, c, data.auth_realm); + if (c == bw->loading_content) + bw->loading_content = 0; + else if (c == bw->current_content) { + bw->current_content = 0; + browser_window_remove_caret(bw); + bw->scrolling_box = NULL; + selection_init(bw->sel, NULL); + } + browser_window_stop_throbber(bw); + free(bw->referer); + bw->referer = 0; + break; #endif #ifdef WITH_SSL - case CONTENT_MSG_SSL: - gui_cert_verify(bw, c, data.ssl.certs, data.ssl.num); - if (c == bw->loading_content) - bw->loading_content = 0; - else if (c == bw->current_content) { - bw->current_content = 0; - browser_window_remove_caret(bw); - bw->scrolling_box = NULL; - selection_init(bw->sel, NULL); - } - browser_window_stop_throbber(bw); - free(bw->referer); - bw->referer = 0; - break; + case CONTENT_MSG_SSL: + gui_cert_verify(bw, c, data.ssl.certs, data.ssl.num); + if (c == bw->loading_content) + bw->loading_content = 0; + else if (c == bw->current_content) { + bw->current_content = 0; + browser_window_remove_caret(bw); + bw->scrolling_box = NULL; + selection_init(bw->sel, NULL); + } + browser_window_stop_throbber(bw); + free(bw->referer); + bw->referer = 0; + break; #endif - case CONTENT_MSG_REFRESH: - bw->refresh_interval = data.delay * 100; - break; + case CONTENT_MSG_REFRESH: + bw->refresh_interval = data.delay * 100; + break; - default: - assert(0); + default: + assert(0); } } @@ -1440,6 +868,64 @@ void browser_window_destroy_internal(struct browser_window *bw) } +/** + * Returns the browser window that is responsible for the child. + * + * \param bw The browser window to find the owner of + * \return the browser window's owner + */ + +struct browser_window *browser_window_owner(struct browser_window *bw) +{ + /* an iframe's parent is just the parent window */ + if (bw->browser_window_type == BROWSER_WINDOW_IFRAME) + return bw->parent; + + /* the parent of a frameset is either a NORMAL window or an IFRAME */ + while (bw->parent) { + switch (bw->browser_window_type) { + case BROWSER_WINDOW_NORMAL: + case BROWSER_WINDOW_IFRAME: + return bw; + case BROWSER_WINDOW_FRAME: + case BROWSER_WINDOW_FRAMESET: + bw = bw->parent; + break; + } + } + return bw; +} + + +/** + * Sets the scale of a browser window + * + * \param bw The browser window to scale + * \param scale The new scale + * \param all Scale all windows in the tree (ie work up aswell as down) + */ + +void browser_window_set_scale(struct browser_window *bw, float scale, bool all) { + while (bw->parent && all) + bw = bw->parent; + browser_window_set_scale_internal(bw, scale); + if (bw->parent) + bw = bw->parent; + browser_window_recalculate_frameset(bw); +} + +void browser_window_set_scale_internal(struct browser_window *bw, float scale) { + int i; + + gui_window_set_scale(bw->window, scale); + + for (i = 0; i < (bw->cols * bw->rows); i++) + browser_window_set_scale_internal(&bw->children[i], scale); + for (i = 0; i < bw->iframe_count; i++) + browser_window_set_scale_internal(&bw->iframes[i], scale); +} + + /** * Locate a browser window in the specified stack according. * @@ -1990,107 +1476,6 @@ void browser_window_mouse_action_html(struct browser_window *bw, browser_window_set_pointer(bw->window, pointer); } -bool browser_window_resize_frames(struct browser_window *bw, browser_mouse_state mouse, int x, int y, - gui_pointer_shape *pointer, const char **status, bool *action) { - bool left, right, up, down; - int i, resize_margin; - - if ((x < bw->x0) || (x > bw->x1) || (y < bw->y0) || (y > bw->y1)) - return false; - - if ((!bw->no_resize) && (bw->parent)) { - resize_margin = FRAME_RESIZE; - if (resize_margin * 2 > (bw->x1 - bw->x0)) - resize_margin = (bw->x1 - bw->x0) / 2; - left = (x < bw->x0 + resize_margin); - right = (x > bw->x1 - resize_margin); - resize_margin = FRAME_RESIZE; - if (resize_margin * 2 > (bw->y1 - bw->y0)) - resize_margin = (bw->y1 - bw->y0) / 2; - up = (y < bw->y0 + resize_margin); - down = (y > bw->y1 - resize_margin); - - /* check if the edges can actually be moved */ - if (left || right || up || down) { - int row = -1, col = -1; - switch (bw->browser_window_type) { - case BROWSER_WINDOW_NORMAL: - case BROWSER_WINDOW_IFRAME: - assert(0); - break; - case BROWSER_WINDOW_FRAME: - case BROWSER_WINDOW_FRAMESET: - assert(bw->parent); - break; - } - for (i = 0; i < (bw->parent->cols * bw->parent->rows); i++) { - if (&bw->parent->children[i] == bw) { - col = i % bw->parent->cols; - row = i / bw->parent->cols; - } - } - assert((row >= 0) && (col >= 0)); - - left &= (col > 0); - right &= (col < bw->parent->cols - 1) & (!left); - up &= (row > 0); - down &= (row < bw->parent->rows - 1) & (!up); - } - - if (left || right || up || down) { - if (left) { - if (down) - *pointer = GUI_POINTER_LD; - else if (up) - *pointer = GUI_POINTER_LU; - else - *pointer = GUI_POINTER_LEFT; - } else if (right) { - if (down) - *pointer = GUI_POINTER_RD; - else if (up) - *pointer = GUI_POINTER_RU; - else - *pointer = GUI_POINTER_RIGHT; - } else if (up) { - *pointer = GUI_POINTER_UP; - } else { - *pointer = GUI_POINTER_DOWN; - } - if (mouse & (BROWSER_MOUSE_DRAG_1 | BROWSER_MOUSE_DRAG_2)) { - bw->drag_type = DRAGGING_FRAME; - bw->drag_start_x = x; - bw->drag_start_y = y; - bw->drag_resize_left = left; - bw->drag_resize_right = right; - bw->drag_resize_up = up; - bw->drag_resize_down = down; - gui_window_frame_resize_start(bw->window); - - *status = messages_get("FrameDrag"); - *action = true; - } - return true; - } - } - - if (bw->children) { - for (i = 0; i < (bw->cols * bw->rows); i++) - if (browser_window_resize_frames(&bw->children[i], mouse, x, y, pointer, status, - action)) - return true; - } - if (bw->iframes) { - for (i = 0; i < bw->iframe_count; i++) - if (browser_window_resize_frames(&bw->iframes[i], mouse, x, y, pointer, status, - action)) - return true; - } - return false; -} - - - /** * Handle mouse clicks and movements in a TEXTPLAIN content window. diff --git a/desktop/browser.h b/desktop/browser.h index f85fb03bc..41519652a 100644 --- a/desktop/browser.h +++ b/desktop/browser.h @@ -182,23 +182,17 @@ extern struct browser_window *current_redraw_browser; struct browser_window * browser_window_create(const char *url, struct browser_window *clone, char *referer, bool history_add); -struct browser_window * browser_window_owner(struct browser_window *bw); void browser_window_go(struct browser_window *bw, const char *url, char *referer, bool history_add); void browser_window_go_post(struct browser_window *bw, const char *url, char *post_urlenc, struct form_successful_control *post_multipart, bool history_add, char *referer, bool download); +void browser_window_update(struct browser_window *bw, bool scroll_to_top); void browser_window_stop(struct browser_window *bw); void browser_window_reload(struct browser_window *bw, bool all); void browser_window_destroy(struct browser_window *bw); -void browser_window_update(struct browser_window *bw, bool scroll_to_top); -void browser_window_create_iframes(struct browser_window *bw, - struct content_html_iframe *iframe); -void browser_window_recalculate_iframes(struct browser_window *bw); -void browser_window_create_frameset(struct browser_window *bw, - struct content_html_frames *frameset); -void browser_window_recalculate_frameset(struct browser_window *bw); +struct browser_window * browser_window_owner(struct browser_window *bw); void browser_window_set_scale(struct browser_window *bw, float scale, bool all); void browser_window_mouse_click(struct browser_window *bw, diff --git a/desktop/frames.c b/desktop/frames.c new file mode 100644 index 000000000..77876efb4 --- /dev/null +++ b/desktop/frames.c @@ -0,0 +1,662 @@ +/* + * This file is part of NetSurf, http://netsurf.sourceforge.net/ + * Licensed under the GNU General Public License, + * http://www.opensource.org/licenses/gpl-license + * Copyright 2006 Richard Wilson + */ + +/** \file + * Frame and frameset creation and manipulation (implementation). + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include "netsurf/utils/config.h" +#include "netsurf/desktop/browser.h" +#include "netsurf/desktop/frames.h" +#include "netsurf/desktop/history_core.h" +#include "netsurf/desktop/gui.h" +#include "netsurf/desktop/selection.h" +#include "netsurf/utils/log.h" +#include "netsurf/utils/messages.h" +#include "netsurf/utils/utils.h" + +/** maximum frame resize margin */ +#define FRAME_RESIZE 6 + +/** browser window which is being redrawn. Valid only during redraw. */ +struct browser_window *current_redraw_browser; + +/** fake content for being saved as a link */ +struct content browser_window_href_content; + +static bool browser_window_resolve_frame_dimension(struct browser_window *bw, + struct browser_window *sibling, int x, int y, bool width, + bool height); + + +/** + * Create and open a iframes for a browser window. + * + * \param bw The browser window to create iframes for + * \param iframe The iframes to create + */ + +void browser_window_create_iframes(struct browser_window *bw, + struct content_html_iframe *iframe) { + struct browser_window *window; + struct content_html_iframe *cur; + int iframes = 0; + int index; + + for (cur = iframe; cur; cur = cur->next) + iframes++; + bw->iframes = calloc(iframes, sizeof(*bw)); + if (!bw->iframes) + return; + bw->iframe_count = iframes; + + index = 0; + for (cur = iframe; cur; cur = cur->next) { + window = &(bw->iframes[index++]); + + /* content */ + window->history = history_create(); + window->sel = selection_create(window); + window->refresh_interval = -1; + + /* window characteristics */ + window->drag_type = DRAGGING_NONE; + window->browser_window_type = BROWSER_WINDOW_IFRAME; + window->scrolling = cur->scrolling; + window->border = cur->border; + window->border_colour = cur->border_colour; + window->no_resize = true; + window->margin_width = cur->margin_width; + window->margin_height = cur->margin_height; + if (cur->name) + window->name = strdup(cur->name); + + /* linking */ + window->box = cur->box; + window->parent = bw; + + /* gui window */ + window->window = gui_create_browser_window(window, bw); + } + + /* calculate dimensions */ + gui_window_update_extent(bw->window); + browser_window_recalculate_iframes(bw); + + index = 0; + for (cur = iframe; cur; cur = cur->next) { + window = &(bw->iframes[index++]); + if (cur->url) + browser_window_go(window, cur->url, NULL, true); + } +} + + +/** + * Recalculate iframe positions following a resize. + * + * \param bw The browser window to reposition iframes for + */ + +void browser_window_recalculate_iframes(struct browser_window *bw) { + struct browser_window *window; + struct rect rect; + int bw_width, bw_height; + int index; + + assert(bw); + + /* update window dimensions */ + gui_window_get_dimensions(bw->window, &bw_width, &bw_height, false); + if (!bw->parent) { + bw->x0 = 0; + bw->y0 = 0; + bw->x1 = bw_width; + bw->y1 = bw_height; + } + + for (index = 0; index < bw->iframe_count; index++) { + window = &(bw->iframes[index]); + box_bounds(window->box, &rect); + gui_window_position_frame(window->window, rect.x0, rect.y0, + rect.x1, rect.y1); + } +} + + +/** + * Create and open a frameset for a browser window. + * + * \param bw The browser window to create the frameset for + * \param iframe The frameset to create + */ + +void browser_window_create_frameset(struct browser_window *bw, + struct content_html_frames *frameset) { + int row, col, index; + struct content_html_frames *frame; + struct browser_window *window; + + /* we use a 3 stage approach such that the content is initially formatted to the + * correct frameset dimensions */ + assert(bw && frameset); + + /* 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; + 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]; + + /* content */ + window->history = history_create(); + window->sel = selection_create(window); + window->refresh_interval = -1; + + /* window characteristics */ + window->drag_type = DRAGGING_NONE; + 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); + + /* linking */ + window->parent = bw; + + /* gui window */ + window->window = gui_create_browser_window(window, bw); + if (frame->children) + browser_window_create_frameset(window, frame); + } + } + + /* calculate dimensions */ + gui_window_update_extent(bw->window); + browser_window_recalculate_frameset(bw); + + /* 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_go(window, frame->url, NULL, true); + } + } +} + + +/** + * Recalculate frameset positions following a resize. + * + * \param bw The browser window to reposition framesets for + */ + +void browser_window_recalculate_frameset(struct browser_window *bw) { + int widths[bw->cols][bw->rows]; + int heights[bw->cols][bw->rows]; + int bw_width, bw_height; + int avail_width, avail_height; + int row, row2, col, index; + struct browser_window *window; + float relative; + int size, extent; + int x, y; + + assert(bw); + + /* window dimensions */ + if (!bw->parent) { + gui_window_get_dimensions(bw->window, &bw_width, &bw_height, false); + bw->x0 = 0; + bw->y0 = 0; + bw->x1 = bw_width; + bw->y1 = bw_height; + } else { + bw_width = bw->x1 - bw->x0; + bw_height = bw->y1 - bw->y0; + } + bw_width++; + bw_height++; + + /* widths */ + for (row = 0; row < bw->rows; row++) { + avail_width = bw_width; + relative = 0; + for (col = 0; col < bw->cols; col++) { + index = (row * bw->cols) + col; + window = &bw->children[index]; + + switch (window->frame_width.unit) { + case FRAME_DIMENSION_PIXELS: + widths[col][row] = window->frame_width.value * + gui_window_get_scale(window->window); + if (window->border) { + if (col != 0) + widths[col][row] += 1; + if (col != bw->cols - 1) + widths[col][row] += 1; + } + break; + case FRAME_DIMENSION_PERCENT: + widths[col][row] = bw_width * window->frame_width.value / 100; + break; + case FRAME_DIMENSION_RELATIVE: + widths[col][row] = 0; + relative += window->frame_width.value; + break; + } + avail_width -= widths[col][row]; + } + + /* try to distribute remainder to relative values in preference */ + if ((relative > 0) && (avail_width > 0)) { + for (col = 0; col < bw->cols; col++) { + index = (row * bw->cols) + col; + window = &bw->children[index]; + + if (window->frame_width.unit == FRAME_DIMENSION_RELATIVE) { + size = avail_width * window->frame_width.value / relative; + avail_width -= size; + relative -= window->frame_width.value; + widths[col][row] += size; + } + } + } else if (bw_width != avail_width) { + /* proportionally distribute error */ + extent = bw_width - avail_width; + for (col = 0; col < bw->cols; col++) { + index = (row * bw->cols) + col; + window = &bw->children[index]; + + if (col == bw->cols - 1) { + widths[col][row] = bw_width; + } else { + size = bw_width * widths[col][row] / extent; + bw_width -= size; + extent -= widths[col][row]; + widths[col][row] = size; + } + } + } + } + + /* heights */ + for (col = 0; col < bw->cols; col++) { + avail_height = bw_height; + relative = 0; + for (row = 0; row < bw->rows; row++) { + index = (row * bw->cols) + col; + window = &bw->children[index]; + + switch (window->frame_height.unit) { + case FRAME_DIMENSION_PIXELS: + heights[col][row] = window->frame_height.value * + gui_window_get_scale(window->window); + if (window->border) { + if (row != 0) + heights[col][row] += 1; + if (row != bw->rows - 1) + heights[col][row] += 1; + } + break; + case FRAME_DIMENSION_PERCENT: + heights[col][row] = bw_height * + window->frame_height.value / 100; + break; + case FRAME_DIMENSION_RELATIVE: + heights[col][row] = 0; + relative += window->frame_height.value; + break; + } + avail_height -= heights[col][row]; + } + + if (avail_height == 0) + continue; + + /* try to distribute remainder to relative values in preference */ + if ((relative > 0) && (avail_height > 0)) { + for (row = 0; row < bw->rows; row++) { + index = (row * bw->cols) + col; + window = &bw->children[index]; + + if (window->frame_height.unit == FRAME_DIMENSION_RELATIVE) { + size = avail_height * window->frame_height.value / relative; + avail_height -= size; + relative -= window->frame_height.value; + heights[col][row] += size; + } + } + } else if (bw_height != avail_height) { + /* proportionally distribute error */ + extent = bw_height - avail_height; + for (row = 0; row < bw->rows; row++) { + index = (row * bw->cols) + col; + window = &bw->children[index]; + + if (row == bw->rows - 1) { + heights[col][row] = bw_height; + } else { + size = bw_height * heights[col][row] / extent; + bw_height -= size; + extent -= heights[col][row]; + heights[col][row] = size; + } + } + } + } + + /* position frames and calculate children */ + for (row = 0; row < bw->rows; row++) { + x = 0; + for (col = 0; col < bw->cols; col++) { + index = (row * bw->cols) + col; + window = &bw->children[index]; + + y = 0; + for (row2 = 0; row2 < row; row2++) + y+= heights[col][row2]; + gui_window_position_frame(window->window, x, y, + x + widths[col][row] - 1, + y + heights[col][row] - 1); + x += widths[col][row]; + if (window->children) + browser_window_recalculate_frameset(window); + } + } +} + + +/** + * Resize a browser window that is a frame. + * + * \param bw The browser window to resize + */ + +void browser_window_resize_frame(struct browser_window *bw, int x, int y) { + struct browser_window *parent; + struct browser_window *sibling; + int col = -1, row = -1, i; + bool change = false; + + parent = bw->parent; + assert(parent); + + /* get frame location */ + for (i = 0; i < (parent->cols * parent->rows); i++) { + if (&parent->children[i] == bw) { + col = i % parent->cols; + row = i / parent->cols; + } + } + assert((col >= 0) && (row >= 0)); + + sibling = NULL; + if (bw->drag_resize_left) + sibling = &parent->children[row * parent->cols + (col - 1)]; + else if (bw->drag_resize_right) + sibling = &parent->children[row * parent->cols + (col + 1)]; + if (sibling) + change |= browser_window_resolve_frame_dimension(bw, sibling, x, y, true, false); + + sibling = NULL; + if (bw->drag_resize_up) + sibling = &parent->children[(row - 1) * parent->cols + col]; + else if (bw->drag_resize_down) + sibling = &parent->children[(row + 1) * parent->cols + col]; + if (sibling) + change |= browser_window_resolve_frame_dimension(bw, sibling, x, y, false, true); + + if (change) + browser_window_recalculate_frameset(parent); +} + + +bool browser_window_resolve_frame_dimension(struct browser_window *bw, struct browser_window *sibling, + int x, int y, bool width, bool height) { + int bw_dimension, sibling_dimension; + int bw_pixels, sibling_pixels; + struct frame_dimension *bw_d, *sibling_d; + float total_new; + int frame_size; + + assert(!(width && height)); + + /* extend/shrink the box to the pointer */ + if (width) { + if (bw->drag_resize_left) + bw_dimension = bw->x1 - x; + else + bw_dimension = x - bw->x0; + bw_pixels = (bw->x1 - bw->x0); + sibling_pixels = (sibling->x1 - sibling->x0); + bw_d = &bw->frame_width; + sibling_d = &sibling->frame_width; + frame_size = bw->parent->x1 - bw->parent->x0; + } else { + if (bw->drag_resize_up) + bw_dimension = bw->y1 - y; + else + bw_dimension = y - bw->y0; + bw_pixels = (bw->y1 - bw->y0); + sibling_pixels = (sibling->y1 - sibling->y0); + bw_d = &bw->frame_height; + sibling_d = &sibling->frame_height; + frame_size = bw->parent->y1 - bw->parent->y0; + } + sibling_dimension = bw_pixels + sibling_pixels - bw_dimension; + + /* check for no change or no frame size*/ + if ((bw_dimension == bw_pixels) || (frame_size == 0)) + return false; + /* check for both being 0 */ + total_new = bw_dimension + sibling_dimension; + if ((bw_dimension + sibling_dimension) == 0) + return false; + + /* our frame dimensions are now known to be: + * + * <-- frame_size --> [VISIBLE PIXELS] + * |<-- bw_pixels -->|<-- sibling_pixels -->| [VISIBLE PIXELS, BEFORE RESIZE] + * |<-- bw_d->value-->|<-- sibling_d->value-->| [SPECIFIED UNITS, BEFORE RESIZE] + * |<--bw_dimension-->|<--sibling_dimension-->| [VISIBLE PIXELS, AFTER RESIZE] + * |<-- total_new -->| [VISIBLE PIXELS, AFTER RESIZE] + * + * when we resize, we must retain the original unit specification such that any + * subsequent resizing of the parent window will recalculate the page as the + * author specified. + * + * if the units of both frames are the same then we can resize the values simply + * by updating the values to be a percentage of the original widths. + */ + if (bw_d->unit == sibling_d->unit) { + float total_specified = bw_d->value + sibling_d->value; + bw_d->value = (total_specified * bw_dimension) / total_new; + sibling_d->value = total_specified - bw_d->value; + return true; + } + + /* if one of the sizes is relative then we don't alter the relative width and + * just let it reflow across. the non-relative (pixel/percentage) value can + * simply be resolved to the specified width that will result in the required + * dimension. + */ + if (bw_d->unit == FRAME_DIMENSION_RELATIVE) { + if ((sibling_pixels == 0) && (bw_dimension == 0)) + return false; + if (sibling_d->value == 0) + bw_d->value = 1; + if (sibling_pixels == 0) + sibling_d->value = (sibling_d->value * bw_pixels) / bw_dimension; + else + sibling_d->value = + (sibling_d->value * sibling_dimension) / sibling_pixels; + + /* todo: the availble resize may have changed, update the drag box */ + return true; + } else if (sibling_d->unit == FRAME_DIMENSION_RELATIVE) { + if ((bw_pixels == 0) && (sibling_dimension == 0)) + return false; + if (bw_d->value == 0) + bw_d->value = 1; + if (bw_pixels == 0) + bw_d->value = (bw_d->value * sibling_pixels) / sibling_dimension; + else + bw_d->value = (bw_d->value * bw_dimension) / bw_pixels; + + /* todo: the availble resize may have changed, update the drag box */ + return true; + } + + /* finally we have a pixel/percentage mix. unlike relative values, percentages + * can easily be backwards-calculated as they can simply be scaled like pixel + * values + */ + if (bw_d->unit == FRAME_DIMENSION_PIXELS) { + float total_specified = bw_d->value + frame_size * sibling_d->value / 100; + bw_d->value = (total_specified * bw_dimension) / total_new; + sibling_d->value = (total_specified - bw_d->value) * 100 / frame_size; + return true; + } else if (sibling_d->unit == FRAME_DIMENSION_PIXELS) { + float total_specified = bw_d->value * frame_size / 100 + sibling_d->value; + sibling_d->value = (total_specified * sibling_dimension) / total_new; + bw_d->value = (total_specified - sibling_d->value) * 100 / frame_size; + return true; + } + assert(!"Invalid frame dimension unit"); + return false; +} + + +bool browser_window_resize_frames(struct browser_window *bw, browser_mouse_state mouse, int x, int y, + gui_pointer_shape *pointer, const char **status, bool *action) { + bool left, right, up, down; + int i, resize_margin; + + if ((x < bw->x0) || (x > bw->x1) || (y < bw->y0) || (y > bw->y1)) + return false; + + if ((!bw->no_resize) && (bw->parent)) { + resize_margin = FRAME_RESIZE; + if (resize_margin * 2 > (bw->x1 - bw->x0)) + resize_margin = (bw->x1 - bw->x0) / 2; + left = (x < bw->x0 + resize_margin); + right = (x > bw->x1 - resize_margin); + resize_margin = FRAME_RESIZE; + if (resize_margin * 2 > (bw->y1 - bw->y0)) + resize_margin = (bw->y1 - bw->y0) / 2; + up = (y < bw->y0 + resize_margin); + down = (y > bw->y1 - resize_margin); + + /* check if the edges can actually be moved */ + if (left || right || up || down) { + int row = -1, col = -1; + switch (bw->browser_window_type) { + case BROWSER_WINDOW_NORMAL: + case BROWSER_WINDOW_IFRAME: + assert(0); + break; + case BROWSER_WINDOW_FRAME: + case BROWSER_WINDOW_FRAMESET: + assert(bw->parent); + break; + } + for (i = 0; i < (bw->parent->cols * bw->parent->rows); i++) { + if (&bw->parent->children[i] == bw) { + col = i % bw->parent->cols; + row = i / bw->parent->cols; + } + } + assert((row >= 0) && (col >= 0)); + + left &= (col > 0); + right &= (col < bw->parent->cols - 1) & (!left); + up &= (row > 0); + down &= (row < bw->parent->rows - 1) & (!up); + } + + if (left || right || up || down) { + if (left) { + if (down) + *pointer = GUI_POINTER_LD; + else if (up) + *pointer = GUI_POINTER_LU; + else + *pointer = GUI_POINTER_LEFT; + } else if (right) { + if (down) + *pointer = GUI_POINTER_RD; + else if (up) + *pointer = GUI_POINTER_RU; + else + *pointer = GUI_POINTER_RIGHT; + } else if (up) { + *pointer = GUI_POINTER_UP; + } else { + *pointer = GUI_POINTER_DOWN; + } + if (mouse & (BROWSER_MOUSE_DRAG_1 | BROWSER_MOUSE_DRAG_2)) { + bw->drag_type = DRAGGING_FRAME; + bw->drag_start_x = x; + bw->drag_start_y = y; + bw->drag_resize_left = left; + bw->drag_resize_right = right; + bw->drag_resize_up = up; + bw->drag_resize_down = down; + gui_window_frame_resize_start(bw->window); + + *status = messages_get("FrameDrag"); + *action = true; + } + return true; + } + } + + if (bw->children) { + for (i = 0; i < (bw->cols * bw->rows); i++) + if (browser_window_resize_frames(&bw->children[i], mouse, x, y, pointer, status, + action)) + return true; + } + if (bw->iframes) { + for (i = 0; i < bw->iframe_count; i++) + if (browser_window_resize_frames(&bw->iframes[i], mouse, x, y, pointer, status, + action)) + return true; + } + return false; +} + diff --git a/desktop/frames.h b/desktop/frames.h new file mode 100644 index 000000000..404af179d --- /dev/null +++ b/desktop/frames.h @@ -0,0 +1,30 @@ +/* + * This file is part of NetSurf, http://netsurf.sourceforge.net/ + * Licensed under the GNU General Public License, + * http://www.opensource.org/licenses/gpl-license + * Copyright 2006 Richard Wilson + */ + +/** \file + * Frame and frameset creation and manipulation (interface). + */ + +#ifndef _NETSURF_DESKTOP_FRAMES_H_ +#define _NETSURF_DESKTOP_FRAMES_H_ + +#include "netsurf/desktop/browser.h" +#include "netsurf/desktop/gui.h" + + +void browser_window_create_iframes(struct browser_window *bw, + struct content_html_iframe *iframe); +void browser_window_recalculate_iframes(struct browser_window *bw); +void browser_window_create_frameset(struct browser_window *bw, + struct content_html_frames *frameset); +void browser_window_recalculate_frameset(struct browser_window *bw); +bool browser_window_resize_frames(struct browser_window *bw, + browser_mouse_state mouse, int x, int y, + gui_pointer_shape *pointer, const char **status, bool *action); +void browser_window_resize_frame(struct browser_window *bw, int x, int y); + +#endif diff --git a/render/html.c b/render/html.c index e9caf06e6..42800c09e 100644 --- a/render/html.c +++ b/render/html.c @@ -1563,11 +1563,6 @@ void html_open(struct content *c, struct browser_window *bw, c->data.html.object[i].box, c->data.html.object[i].box->object_params); } - - if (c->data.html.frameset) - browser_window_create_frameset(bw, c->data.html.frameset); - if (c->data.html.iframe) - browser_window_create_iframes(bw, c->data.html.iframe); } -- cgit v1.2.3