summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael Drake <tlsa@netsurf-browser.org>2011-07-05 20:13:28 +0000
committerMichael Drake <tlsa@netsurf-browser.org>2011-07-05 20:13:28 +0000
commit9f2ea3be4c50f0e30153fc648f3219b5bd7f3fa3 (patch)
tree60fd512f5e4d78697342ecf0891f31c2367abeea
parent1f9b970f57d50f5fe3f812c7ada63fe3f66478b5 (diff)
downloadnetsurf-9f2ea3be4c50f0e30153fc648f3219b5bd7f3fa3.tar.gz
netsurf-9f2ea3be4c50f0e30153fc648f3219b5bd7f3fa3.tar.bz2
Iframe scrollbars.
svn path=/trunk/netsurf/; revision=12571
-rw-r--r--desktop/browser.c278
-rw-r--r--desktop/browser.h5
-rw-r--r--desktop/frames.c131
-rw-r--r--desktop/frames.h11
4 files changed, 401 insertions, 24 deletions
diff --git a/desktop/browser.c b/desktop/browser.c
index fd2e28ebc..8b7741ca2 100644
--- a/desktop/browser.c
+++ b/desktop/browser.c
@@ -50,6 +50,7 @@
#include "desktop/gui.h"
#include "desktop/knockout.h"
#include "desktop/options.h"
+#include "desktop/scrollbar.h"
#include "desktop/selection.h"
#include "desktop/textinput.h"
#include "desktop/plotters.h"
@@ -92,6 +93,46 @@ static void browser_window_find_target_internal(struct browser_window *bw,
static void browser_window_mouse_drag_end(struct browser_window *bw,
browser_mouse_state mouse, int x, int y);
+
+/**
+ * Get position of scrollbar widget within browser window.
+ *
+ * \param bw The browser window
+ * \param horizontal Whether to get position of horizontal scrollbar
+ * \param x Updated to x-coord of top left of scrollbar widget
+ * \param y Updated to y-coord of top left of scrollbar widget
+ */
+
+static inline void browser_window_get_scrollbar_pos(struct browser_window *bw,
+ bool horizontal, int *x, int *y)
+{
+ if (horizontal) {
+ *x = 0;
+ *y = bw->height - SCROLLBAR_WIDTH;
+ } else {
+ *x = bw->width - SCROLLBAR_WIDTH;
+ *y = 0;
+ }
+}
+
+
+/**
+ * Get browser window scrollbar widget length
+ *
+ * \param bw The browser window
+ * \param horizontal Whether to get length of horizontal scrollbar
+ * \return the scrollbar's length
+ */
+
+static inline int browser_window_get_scrollbar_len(struct browser_window *bw,
+ bool horizontal)
+{
+ if (horizontal)
+ return bw->width - (bw->scroll_y != NULL ? SCROLLBAR_WIDTH : 0);
+ else
+ return bw->height;
+}
+
/* exported interface, documented in browser.h */
bool browser_window_redraw(struct browser_window *bw, int x, int y,
const struct rect *clip, const struct redraw_context *ctx)
@@ -102,6 +143,7 @@ bool browser_window_redraw(struct browser_window *bw, int x, int y,
bool plot_ok = true;
content_type content_type;
struct content_redraw_data data;
+ struct rect content_clip;
if (bw == NULL) {
LOG(("NULL browser window"));
@@ -138,8 +180,8 @@ bool browser_window_redraw(struct browser_window *bw, int x, int y,
}
/* Set up content redraw data */
- data.x = x;
- data.y = y;
+ data.x = x - scrollbar_get_offset(bw->scroll_x);
+ data.y = y - scrollbar_get_offset(bw->scroll_y);
data.width = width;
data.height = height;
@@ -147,9 +189,48 @@ bool browser_window_redraw(struct browser_window *bw, int x, int y,
data.scale = bw->scale;
data.repeat_x = false;
data.repeat_y = false;
+
+ content_clip = *clip;
+
+ if (!bw->window) {
+ int x0 = x * bw->scale;
+ int y0 = y * bw->scale;
+ int x1 = (x + bw->width - ((bw->scroll_y != NULL) ?
+ SCROLLBAR_WIDTH : 0)) * bw->scale;
+ int y1 = (y + bw->height - ((bw->scroll_x != NULL) ?
+ SCROLLBAR_WIDTH : 0)) * bw->scale;
+
+ if (content_clip.x0 < x0) content_clip.x0 = x0;
+ if (content_clip.y0 < y0) content_clip.y0 = y0;
+ if (x1 < content_clip.x1) content_clip.x1 = x1;
+ if (y1 < content_clip.y1) content_clip.y1 = y1;
+ }
/* Render the content */
- plot_ok &= content_redraw(bw->current_content, &data, clip, &new_ctx);
+ plot_ok &= content_redraw(bw->current_content, &data,
+ &content_clip, &new_ctx);
+
+ /* Back to full clip rect */
+ new_ctx.plot->clip(clip);
+
+ if (!bw->window) {
+ /* Render scrollbars */
+ int off_x, off_y;
+ if (bw->scroll_x != NULL) {
+ browser_window_get_scrollbar_pos(bw, true,
+ &off_x, &off_y);
+ plot_ok &= scrollbar_redraw(bw->scroll_x,
+ x + off_x, y + off_y, clip,
+ bw->scale, &new_ctx);
+ }
+ if (bw->scroll_y != NULL) {
+ browser_window_get_scrollbar_pos(bw, false,
+ &off_x, &off_y);
+ plot_ok &= scrollbar_redraw(bw->scroll_y,
+ x + off_x, y + off_y, clip,
+ bw->scale, &new_ctx);
+ }
+ }
if (bw->browser_window_type != BROWSER_WINDOW_IFRAME &&
ctx->plot->option_knockout) {
@@ -183,7 +264,7 @@ void browser_window_update_extent(struct browser_window *bw)
gui_window_update_extent(bw->window);
break;
case BROWSER_WINDOW_IFRAME:
- /* TODO */
+ browser_window_handle_scrollbars(bw);
break;
}
}
@@ -207,8 +288,8 @@ void browser_window_get_position(struct browser_window *bw, bool root,
break;
case BROWSER_WINDOW_IFRAME:
- *pos_x += bw->x * bw->scale;
- *pos_y += bw->y * bw->scale;
+ *pos_x += (bw->x - scrollbar_get_offset(bw->scroll_x)) * bw->scale;
+ *pos_y += (bw->y - scrollbar_get_offset(bw->scroll_y)) * bw->scale;
break;
}
@@ -257,6 +338,7 @@ struct browser_window * browser_window_get_root(struct browser_window *bw)
}
return bw;
}
+
/* exported interface, documented in browser.h */
bool browser_window_has_selection(struct browser_window *bw)
{
@@ -273,6 +355,26 @@ bool browser_window_has_selection(struct browser_window *bw)
}
/**
+ * Set scroll offsets for a browser window.
+ *
+ * \param bw The browser window
+ * \param x The x scroll offset to set
+ * \param y The y scroll offset to set
+ */
+
+static void browser_window_set_scroll(struct browser_window *bw, int x, int y)
+{
+ if (bw->window != NULL) {
+ gui_window_set_scroll(bw->window, x, y);
+ } else {
+ if (bw->scroll_x != NULL)
+ scrollbar_set(bw->scroll_x, x, false);
+ if (bw->scroll_y != NULL)
+ scrollbar_set(bw->scroll_y, y, false);
+ }
+}
+
+/**
* Create and open a new root browser window with the given page.
*
* \param url URL to start fetching in the new window (copied)
@@ -351,6 +453,9 @@ void browser_window_initialise_common(struct browser_window *bw,
bw->drag_type = DRAGGING_NONE;
bw->scale = (float) option_scale / 100.0;
+ bw->scroll_x = NULL;
+ bw->scroll_y = NULL;
+
bw->focus = NULL;
/* initialise status text cache */
@@ -716,6 +821,14 @@ nserror browser_window_callback(hlcache_handle *c,
case CONTENT_MSG_DONE:
assert(bw->current_content == c);
+ if (bw->window == NULL) {
+ /* Updated browser window's scrollbars.
+ * TODO: do this before CONTENT_MSG_DONE */
+ browser_window_reformat(bw, true,
+ bw->width, bw->height);
+ browser_window_handle_scrollbars(bw);
+ }
+
browser_window_update(bw, false);
browser_window_set_status(bw, content_get_status_message(c));
browser_window_stop_throbber(bw);
@@ -1033,13 +1146,13 @@ void browser_window_update(struct browser_window *bw, bool scroll_to_top)
browser_window_update_extent(bw);
if (scroll_to_top)
- gui_window_set_scroll(bw->window, 0, 0);
+ browser_window_set_scroll(bw, 0, 0);
/* if frag_id exists, then try to scroll to it */
/** \TODO don't do this if the user has scrolled */
if (bw->frag_id && html_get_id_offset(bw->current_content,
bw->frag_id, &x, &y)) {
- gui_window_set_scroll(bw->window, x, y);
+ browser_window_set_scroll(bw, x, y);
}
gui_window_redraw_window(bw->window);
@@ -1048,7 +1161,17 @@ void browser_window_update(struct browser_window *bw, bool scroll_to_top)
case BROWSER_WINDOW_IFRAME:
/* Internal iframe browser window */
- /** \TODO handle scrollbar extents, scroll offset */
+ browser_window_update_extent(bw);
+
+ if (scroll_to_top)
+ browser_window_set_scroll(bw, 0, 0);
+
+ /* if frag_id exists, then try to scroll to it */
+ /** \TODO don't do this if the user has scrolled */
+ if (bw->frag_id && html_get_id_offset(bw->current_content,
+ bw->frag_id, &x, &y)) {
+ browser_window_set_scroll(bw, x, y);
+ }
html_redraw_a_box(bw->parent->current_content, bw->box);
break;
@@ -1409,8 +1532,14 @@ void browser_window_reformat(struct browser_window *bw, bool background,
if (bw->browser_window_type != BROWSER_WINDOW_IFRAME) {
/* Iframe dimensions are already scaled in parent's layout */
- width /= bw->scale;
+ width /= bw->scale;
height /= bw->scale;
+ } else {
+ width -= bw->scroll_y ? SCROLLBAR_WIDTH : 0;
+ height -= bw->scroll_x ? SCROLLBAR_WIDTH : 0;
+
+ width = width > 0 ? width : 0;
+ height = height > 0 ? height : 0;
}
content_reformat(c, background, width, height);
@@ -1688,6 +1817,8 @@ void browser_window_mouse_track(struct browser_window *bw,
browser_mouse_state mouse, int x, int y)
{
hlcache_handle *c = bw->current_content;
+ const char *status = NULL;
+ gui_pointer_shape pointer = GUI_POINTER_DEFAULT;
if (c == NULL && bw->drag_type != DRAGGING_FRAME)
return;
@@ -1696,6 +1827,51 @@ void browser_window_mouse_track(struct browser_window *bw,
browser_window_mouse_drag_end(bw, mouse, x, y);
}
+ if (bw->scroll_x != NULL) {
+ int scr_x, scr_y;
+ browser_window_get_scrollbar_pos(bw, true, &scr_x, &scr_y);
+ scr_x = x - scr_x - scrollbar_get_offset(bw->scroll_x);
+ scr_y = y - scr_y - scrollbar_get_offset(bw->scroll_y);
+
+ if ((scr_x > 0 && scr_x < browser_window_get_scrollbar_len(bw,
+ true) &&
+ scr_y > 0 && scr_y < SCROLLBAR_WIDTH) ||
+ bw->drag_type == DRAGGING_SCR_X) {
+ status = scrollbar_mouse_action(bw->scroll_x, mouse,
+ scr_x, scr_y);
+ pointer = GUI_POINTER_DEFAULT;
+
+ if (status != NULL)
+ browser_window_set_status(bw, status);
+
+ browser_window_set_pointer(bw, pointer);
+ return;
+ }
+ }
+
+ if (bw->scroll_y != NULL) {
+ int scr_x, scr_y;
+ browser_window_get_scrollbar_pos(bw, false, &scr_x, &scr_y);
+ scr_x = x - scr_x - scrollbar_get_offset(bw->scroll_x);
+ scr_y = y - scr_y - scrollbar_get_offset(bw->scroll_y);
+
+ if ((scr_y > 0 && scr_y < browser_window_get_scrollbar_len(bw,
+ false) &&
+ scr_x > 0 && scr_x < SCROLLBAR_WIDTH) ||
+ bw->drag_type == DRAGGING_SCR_Y) {
+
+ status = scrollbar_mouse_action(bw->scroll_y, mouse,
+ scr_x, scr_y);
+ pointer = GUI_POINTER_DEFAULT;
+
+ if (status != NULL)
+ browser_window_set_status(bw, status);
+
+ browser_window_set_pointer(bw, pointer);
+ return;
+ }
+ }
+
if (bw->drag_type == DRAGGING_FRAME) {
browser_window_resize_frame(bw, bw->x0 + x, bw->y0 + y);
} else if (bw->drag_type == DRAGGING_PAGE_SCROLL) {
@@ -1710,17 +1886,7 @@ void browser_window_mouse_track(struct browser_window *bw,
bw->drag_start_scroll_x = scrollx;
bw->drag_start_scroll_y = scrolly;
- switch (bw->browser_window_type) {
- default:
- /* Fall through to normal, until frame(set)s are
- * handled in the core */
- case BROWSER_WINDOW_NORMAL:
- gui_window_set_scroll(bw->window, scrollx, scrolly);
- break;
- case BROWSER_WINDOW_IFRAME:
- /* TODO */
- break;
- }
+ browser_window_set_scroll(bw, scrollx, scrolly);
} else {
assert(c != NULL);
content_mouse_track(c, bw, mouse, x, y);
@@ -1741,10 +1907,54 @@ void browser_window_mouse_click(struct browser_window *bw,
browser_mouse_state mouse, int x, int y)
{
hlcache_handle *c = bw->current_content;
+ const char *status = NULL;
+ gui_pointer_shape pointer = GUI_POINTER_DEFAULT;
if (!c)
return;
+ if (bw->scroll_x != NULL) {
+ int scr_x, scr_y;
+ browser_window_get_scrollbar_pos(bw, true, &scr_x, &scr_y);
+ scr_x = x - scr_x;
+ scr_y = y - scr_y;
+
+ if (scr_x > 0 && scr_x < browser_window_get_scrollbar_len(bw,
+ true) &&
+ scr_y > 0 && scr_y < SCROLLBAR_WIDTH) {
+ status = scrollbar_mouse_action(bw->scroll_x, mouse,
+ scr_x, scr_y);
+ pointer = GUI_POINTER_DEFAULT;
+
+ if (status != NULL)
+ browser_window_set_status(bw, status);
+
+ browser_window_set_pointer(bw, pointer);
+ return;
+ }
+ }
+
+ if (bw->scroll_y != NULL) {
+ int scr_x, scr_y;
+ browser_window_get_scrollbar_pos(bw, false, &scr_x, &scr_y);
+ scr_x = x - scr_x;
+ scr_y = y - scr_y;
+
+ if (scr_y > 0 && scr_y < browser_window_get_scrollbar_len(bw,
+ false) &&
+ scr_x > 0 && scr_x < SCROLLBAR_WIDTH) {
+ status = scrollbar_mouse_action(bw->scroll_y, mouse,
+ scr_x, scr_y);
+ pointer = GUI_POINTER_DEFAULT;
+
+ if (status != NULL)
+ browser_window_set_status(bw, status);
+
+ browser_window_set_pointer(bw, pointer);
+ return;
+ }
+ }
+
switch (content_get_type(c)) {
case CONTENT_HTML:
case CONTENT_TEXTPLAIN:
@@ -1784,6 +1994,8 @@ void browser_window_mouse_click(struct browser_window *bw,
void browser_window_mouse_drag_end(struct browser_window *bw,
browser_mouse_state mouse, int x, int y)
{
+ int scr_x, scr_y;
+
switch (bw->drag_type) {
case DRAGGING_SELECTION:
{
@@ -1817,6 +2029,30 @@ void browser_window_mouse_drag_end(struct browser_window *bw,
/* Drag handled by content handler */
break;
+ case DRAGGING_SCR_X:
+
+ browser_window_get_scrollbar_pos(bw, true, &scr_x, &scr_y);
+
+ scr_x = x - scr_x - scrollbar_get_offset(bw->scroll_x);
+ scr_y = y - scr_y - scrollbar_get_offset(bw->scroll_y);
+
+ scrollbar_mouse_drag_end(bw->scroll_x, mouse, scr_x, scr_y);
+
+ bw->drag_type = DRAGGING_NONE;
+ break;
+
+ case DRAGGING_SCR_Y:
+
+ browser_window_get_scrollbar_pos(bw, false, &scr_x, &scr_y);
+
+ scr_x = x - scr_x - scrollbar_get_offset(bw->scroll_x);
+ scr_y = y - scr_y - scrollbar_get_offset(bw->scroll_y);
+
+ scrollbar_mouse_drag_end(bw->scroll_y, mouse, scr_x, scr_y);
+
+ bw->drag_type = DRAGGING_NONE;
+ break;
+
default:
bw->drag_type = DRAGGING_NONE;
break;
diff --git a/desktop/browser.h b/desktop/browser.h
index 0949e856e..ced12af49 100644
--- a/desktop/browser.h
+++ b/desktop/browser.h
@@ -60,6 +60,8 @@ typedef enum {
DRAGGING_SELECTION,
DRAGGING_PAGE_SCROLL,
DRAGGING_FRAME,
+ DRAGGING_SCR_X,
+ DRAGGING_SCR_Y,
DRAGGING_OTHER
} browser_drag_type;
@@ -135,6 +137,9 @@ struct browser_window {
int width;
int height;
+ struct scrollbar *scroll_x; /**< Horizontal scroll. */
+ struct scrollbar *scroll_y; /**< Vertical scroll. */
+
/** scale of window contents */
float scale;
diff --git a/desktop/frames.c b/desktop/frames.c
index d8e2c992b..afcd84e01 100644
--- a/desktop/frames.c
+++ b/desktop/frames.c
@@ -34,6 +34,7 @@
#include "desktop/frames.h"
#include "desktop/history_core.h"
#include "desktop/gui.h"
+#include "desktop/scrollbar.h"
#include "desktop/selection.h"
#include "utils/log.h"
#include "utils/messages.h"
@@ -48,6 +49,121 @@ static bool browser_window_resolve_frame_dimension(struct browser_window *bw,
/**
+ * Callback for (i)frame scrollbars.
+ */
+void browser_window_scroll_callback(void *client_data,
+ struct scrollbar_msg_data *scrollbar_data)
+{
+ struct browser_window *bw = client_data;
+
+ switch(scrollbar_data->msg) {
+ case SCROLLBAR_MSG_REDRAW:
+ /* TODO: Is this needed? */
+ break;
+ case SCROLLBAR_MSG_MOVED:
+ html_redraw_a_box(bw->parent->current_content, bw->box);
+ break;
+ case SCROLLBAR_MSG_SCROLL_START:
+ if (scrollbar_is_horizontal(scrollbar_data->scrollbar))
+ browser_window_set_drag_type(bw, DRAGGING_SCR_X);
+ else
+ browser_window_set_drag_type(bw, DRAGGING_SCR_Y);
+
+ break;
+ case SCROLLBAR_MSG_SCROLL_FINISHED:
+ browser_window_set_drag_type(bw, DRAGGING_NONE);
+
+ browser_window_set_pointer(bw, GUI_POINTER_DEFAULT);
+ break;
+ }
+}
+
+/* exported interface, documented in browser.h */
+void browser_window_handle_scrollbars(struct browser_window *bw)
+{
+ hlcache_handle *h = bw->current_content;
+ bool scroll_x;
+ bool scroll_y;
+ int c_width = 0;
+ int c_height = 0;
+
+ assert(!bw->window); /* Core-handled windows only */
+
+ if (h != NULL) {
+ c_width = content_get_width(h);
+ c_height = content_get_height(h);
+ }
+
+ if (bw->scrolling == SCROLLING_YES) {
+ scroll_x = true;
+ scroll_y = true;
+ } else if (bw->scrolling == SCROLLING_AUTO &&
+ bw->current_content) {
+ int bw_width = bw->width;
+ int bw_height = bw->height;
+
+ /* subtract existing scrollbar width */
+ bw_width -= bw->scroll_y ? SCROLLBAR_WIDTH : 0;
+ bw_height -= bw->scroll_x ? SCROLLBAR_WIDTH : 0;
+
+ scroll_y = (c_height > bw_height) ? true : false;
+ scroll_x = (c_width > bw_width) ? true : false;
+ } else {
+ /* No scrollbars */
+ scroll_x = false;
+ scroll_y = false;
+ }
+
+ if (!scroll_x && bw->scroll_x != NULL) {
+ scrollbar_destroy(bw->scroll_x);
+ bw->scroll_x = NULL;
+ }
+
+ if (!scroll_y && bw->scroll_y != NULL) {
+ scrollbar_destroy(bw->scroll_y);
+ bw->scroll_y = NULL;
+ }
+
+ if (scroll_y) {
+ int length = bw->height;
+ int visible = bw->height - (scroll_x ? SCROLLBAR_WIDTH : 0);
+
+ if (bw->scroll_y == NULL) {
+ /* create vertical scrollbar */
+ if (!scrollbar_create(false, length, c_height, visible,
+ bw, browser_window_scroll_callback,
+ &(bw->scroll_y)))
+ return;
+ } else {
+ /* update vertical scrollbar */
+ scrollbar_set_extents(bw->scroll_y, length,
+ visible, c_height);
+ }
+ }
+
+ if (scroll_x) {
+ int length = bw->width - (scroll_y ? SCROLLBAR_WIDTH : 0);
+ int visible = length;
+
+ if (bw->scroll_x == NULL) {
+ /* create horizontal scrollbar */
+ if (!scrollbar_create(true, length, c_width, visible,
+ bw, browser_window_scroll_callback,
+ &(bw->scroll_x)))
+ return;
+ } else {
+ /* update horizontal scrollbar */
+ scrollbar_set_extents(bw->scroll_x, length,
+ visible, c_width);
+ }
+ }
+
+ if (scroll_x && scroll_y)
+ scrollbar_make_pair(bw->scroll_x, bw->scroll_y);
+}
+
+
+/**
* Create and open a iframes for a browser window.
*
* \param bw The browser window to create iframes for
@@ -55,7 +171,8 @@ static bool browser_window_resolve_frame_dimension(struct browser_window *bw,
*/
void browser_window_create_iframes(struct browser_window *bw,
- struct content_html_iframe *iframe) {
+ struct content_html_iframe *iframe)
+{
struct browser_window *window;
struct content_html_iframe *cur;
struct rect rect;
@@ -130,8 +247,16 @@ void browser_window_create_iframes(struct browser_window *bw,
void browser_window_recalculate_iframes(struct browser_window *bw)
{
- /* TODO: decide if this is still needed after scrollbars are
- * implemented */
+ struct browser_window *window;
+ int index;
+
+ for (index = 0; index < bw->iframe_count; index++) {
+ window = &(bw->iframes[index]);
+
+ if (window != NULL) {
+ browser_window_handle_scrollbars(window);
+ }
+ }
}
diff --git a/desktop/frames.h b/desktop/frames.h
index bb50b56e2..11fbcea2f 100644
--- a/desktop/frames.h
+++ b/desktop/frames.h
@@ -38,4 +38,15 @@ bool browser_window_resize_frames(struct browser_window *bw,
gui_pointer_shape *pointer, const char **status, bool *action);
void browser_window_resize_frame(struct browser_window *bw, int x, int y);
+void browser_window_scroll_callback(void *client_data,
+ struct scrollbar_msg_data *scrollbar_data);
+
+
+/**
+ * Create, remove, and update browser window scrollbars
+ *
+ * \param bw The browser window
+ */
+void browser_window_handle_scrollbars(struct browser_window *bw);
+
#endif