summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--desktop/browser.c296
-rw-r--r--desktop/browser.h32
-rw-r--r--desktop/frames.c51
-rw-r--r--desktop/search.c3
-rw-r--r--desktop/selection.c57
-rw-r--r--desktop/selection.h5
-rw-r--r--desktop/textinput.c53
-rw-r--r--render/box.c4
-rw-r--r--render/box.h6
-rw-r--r--render/box_construct.c2
-rw-r--r--render/html_interaction.c22
-rw-r--r--render/html_redraw.c13
-rw-r--r--render/layout.c73
-rw-r--r--render/textplain.c2
14 files changed, 507 insertions, 112 deletions
diff --git a/desktop/browser.c b/desktop/browser.c
index a7126a64b..fa2d1bcbb 100644
--- a/desktop/browser.c
+++ b/desktop/browser.c
@@ -112,7 +112,8 @@ bool browser_window_redraw(struct browser_window *bw, int x, int y,
}
/* Browser window has content */
- if (plot.option_knockout)
+ if (bw->browser_window_type != BROWSER_WINDOW_IFRAME &&
+ plot.option_knockout)
knockout_plot_start(&plot);
plot.clip(clip);
@@ -133,7 +134,8 @@ bool browser_window_redraw(struct browser_window *bw, int x, int y,
plot_ok &= content_redraw(bw->current_content, x, y, width, height,
clip, bw->scale, 0xFFFFFF, false, false);
- if (plot.option_knockout)
+ if (bw->browser_window_type != BROWSER_WINDOW_IFRAME &&
+ plot.option_knockout)
knockout_plot_end();
return plot_ok;
@@ -153,8 +155,60 @@ bool browser_window_redraw_ready(struct browser_window *bw)
return true;
}
+/* exported interface, documented in browser.h */
+void browser_window_update_extent(struct browser_window *bw)
+{
+ switch (bw->browser_window_type) {
+ default:
+ /* Fall through until core frame(set)s are implemented */
+ case BROWSER_WINDOW_NORMAL:
+ gui_window_update_extent(bw->window);
+ break;
+ case BROWSER_WINDOW_IFRAME:
+ /* TODO */
+ break;
+ }
+}
+
+/* exported interface, documented in browser.h */
+void browser_window_get_position(struct browser_window *bw, bool root,
+ int *pos_x, int *pos_y)
+{
+ int x, y;
+ *pos_x = 0;
+ *pos_y = 0;
+
+ assert(bw != NULL);
+
+ while (bw) {
+ switch (bw->browser_window_type) {
+ default:
+ /* fall through to NORMAL until frame(set)s are handled
+ * in the core */
+ case BROWSER_WINDOW_NORMAL:
+ /* There is no offset to the root browser window */
+ break;
+ case BROWSER_WINDOW_IFRAME:
+ /* offset comes from its box position in parent bw */
+ box_coords(bw->box, &x, &y);
+
+ *pos_x += x;
+ *pos_y += y;
+ break;
+ }
+
+ bw = bw->parent;
+
+ if (!root) {
+ /* return if we just wanted the position in the parent
+ * browser window. */
+ return;
+ }
+ }
+}
+
/**
- * Create and open a new browser window with the given page.
+ * Create and open a new root browser window with the given page.
*
* \param url URL to start fetching in the new window (copied)
* \param clone The browser window to clone
@@ -166,6 +220,7 @@ struct browser_window *browser_window_create(const char *url,
const char *referer, bool history_add, bool new_tab)
{
struct browser_window *bw;
+ struct browser_window *top;
assert(clone || history_add);
@@ -183,10 +238,18 @@ struct browser_window *browser_window_create(const char *url,
bw->border = true;
bw->no_resize = true;
bw->last_action = wallclock();
-
- bw->window = gui_create_browser_window(bw, clone, new_tab);
+ bw->sel = selection_create();
/* gui window */
+ /* from the front end's pov, it clones the top level browser window,
+ * so find that. */
+ top = clone;
+ while (top && !top->window && top->parent) {
+ top = top->parent;
+ }
+
+ bw->window = gui_create_browser_window(bw, top, new_tab);
+
if (bw->window == NULL) {
browser_window_destroy(bw);
return NULL;
@@ -217,13 +280,15 @@ void browser_window_initialise_common(struct browser_window *bw,
bw->history = history_clone(clone->history);
/* window characteristics */
- bw->sel = selection_create(bw);
+ bw->sel = NULL;
bw->refresh_interval = -1;
bw->reformat_pending = false;
bw->drag_type = DRAGGING_NONE;
bw->scale = (float) option_scale / 100.0;
+ bw->focus = NULL;
+
/* initialise status text cache */
bw->status_text = NULL;
bw->status_text_len = 0;
@@ -534,7 +599,7 @@ nserror browser_window_callback(hlcache_handle *c,
bw->loading_content = NULL;
/* Format the new content to the correct dimensions */
- gui_window_get_dimensions(bw->window, &width, &height, true);
+ browser_window_get_dimensions(bw, &width, &height, true);
content_reformat(c, width, height);
browser_window_remove_caret(bw);
@@ -568,9 +633,11 @@ nserror browser_window_callback(hlcache_handle *c,
}
/* favicon preload */
- if (content_get_type(c) == CONTENT_HTML)
+ if (bw->browser_window_type == BROWSER_WINDOW_NORMAL &&
+ content_get_type(c) == CONTENT_HTML) {
gui_window_set_icon(bw->window,
- html_get_favicon(bw->current_content));
+ html_get_favicon(bw->current_content));
+ }
/* text selection */
if (content_get_type(c) == CONTENT_HTML)
@@ -651,7 +718,7 @@ nserror browser_window_callback(hlcache_handle *c,
break;
case CONTENT_MSG_REDRAW:
- gui_window_update_box(bw->window, &event->data);
+ browser_window_update_box(bw, &event->data);
break;
case CONTENT_MSG_REFRESH:
@@ -660,7 +727,10 @@ nserror browser_window_callback(hlcache_handle *c,
case CONTENT_MSG_FAVICON_REFRESH:
/* Cause the GUI to update */
- gui_window_set_icon(bw->window, html_get_favicon(bw->current_content));
+ if (bw->browser_window_type == BROWSER_WINDOW_NORMAL) {
+ gui_window_set_icon(bw->window,
+ html_get_favicon(bw->current_content));
+ }
break;
default:
@@ -671,6 +741,41 @@ nserror browser_window_callback(hlcache_handle *c,
}
+/*
+ * Get the dimensions of the area a browser window occupies
+ *
+ * \param bw The browser window to get dimensions of
+ * \param width Updated to the browser window viewport width
+ * \param height Updated to the browser window viewport height
+ * \param scaled Whether we want the height with scale applied
+ */
+
+void browser_window_get_dimensions(struct browser_window *bw,
+ int *width, int *height, bool scaled)
+{
+ struct rect rect;
+
+ switch (bw->browser_window_type) {
+ case BROWSER_WINDOW_IFRAME:
+ /* browser window is size of associated box */
+ box_bounds(bw->box, &rect);
+ /* TODO: Handle scale */
+ *width = rect.x1 - rect.x0;
+ *height = rect.y1 - rect.y0;
+ break;
+
+ case BROWSER_WINDOW_FRAME:
+ case BROWSER_WINDOW_FRAMESET:
+ case BROWSER_WINDOW_NORMAL:
+ /* root window (or frame(set), currently); browser window is
+ * size of gui window viewport */
+ assert(bw->window);
+ gui_window_get_dimensions(bw->window, width, height, scaled);
+ break;
+ }
+}
+
+
/**
* Transfer the loading_content to a new download window.
*/
@@ -833,22 +938,75 @@ void browser_window_update(struct browser_window *bw, bool scroll_to_top)
if (bw->current_content == NULL)
return;
- gui_window_set_title(bw->window,
- content_get_title(bw->current_content));
+ switch (bw->browser_window_type) {
+ default:
+ /* Fall through to normal
+ * (frame(set)s aren't handled by the core yet) */
+ case BROWSER_WINDOW_NORMAL:
+ /* Root browser window, constituting a front end window/tab */
+ gui_window_set_title(bw->window,
+ content_get_title(bw->current_content));
+
+ browser_window_update_extent(bw);
+
+ if (scroll_to_top)
+ gui_window_set_scroll(bw->window, 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);
+ }
- gui_window_update_extent(bw->window);
+ gui_window_redraw_window(bw->window);
- if (scroll_to_top)
- gui_window_set_scroll(bw->window, 0, 0);
+ break;
+ case BROWSER_WINDOW_IFRAME:
+ /* Internal iframe browser window */
+
+ /** \TODO handle scrollbar extents, scroll offset */
- /** \todo don't do this if the user has scrolled */
- /* if frag_id exists, then try to scroll to it */
- if (bw->frag_id && html_get_id_offset(bw->current_content, bw->frag_id,
- &x, &y)) {
- gui_window_set_scroll(bw->window, x, y);
+ html_redraw_a_box(bw->parent->current_content, bw->box);
+ break;
}
+}
+
+
+void browser_window_update_box(struct browser_window *bw,
+ const union content_msg_data *data)
+{
+ int pos_x;
+ int pos_y;
+ union content_msg_data data_copy = *data;
+ struct browser_window *top;
+
+ switch (bw->browser_window_type) {
+ default:
+ /* fall through for frame(set)s,
+ * until they are handled by core */
+ case BROWSER_WINDOW_NORMAL:
+ gui_window_update_box(bw->window, data);
+ break;
+
+ case BROWSER_WINDOW_IFRAME:
+ browser_window_get_position(bw, true, &pos_x, &pos_y);
- gui_window_redraw_window(bw->window);
+ top = bw;
+ while (top && !top->window && top->parent) {
+ top = top->parent;
+ }
+
+ /* TODO: update gui_window_update_box so it takes a struct rect
+ * instead of msg data. */
+ data_copy.redraw.x += pos_x;
+ data_copy.redraw.y += pos_y;
+ data_copy.redraw.object_x += pos_x;
+ data_copy.redraw.object_y += pos_y;
+
+ gui_window_update_box(top->window, &data_copy);
+ break;
+ }
}
@@ -993,9 +1151,19 @@ void browser_window_set_status(struct browser_window *bw, const char *text)
* \param shape shape to use
*/
-void browser_window_set_pointer(struct gui_window *g, gui_pointer_shape shape)
+void browser_window_set_pointer(struct browser_window *bw,
+ gui_pointer_shape shape)
{
- gui_window_set_pointer(g, shape);
+ struct browser_window *root = bw;
+
+ while (root && !root->window && root->parent) {
+ root = root->parent;
+ }
+
+ assert(root);
+ assert(root->window);
+
+ gui_window_set_pointer(root->window, shape);
}
@@ -1061,12 +1229,27 @@ void browser_window_destroy_internal(struct browser_window *bw)
schedule_remove(browser_window_refresh, bw);
+ /* If this brower window is not the root window, and has focus, unset
+ * the root browser window's focus pointer. */
+ if (!bw->window) {
+ struct browser_window *top = bw;
+
+ while (top && !top->window && top->parent)
+ top = top->parent;
+
+ if (top->focus == bw)
+ top->focus = NULL;
+ }
+
/* Destruction order is important: we must ensure that the frontend
* destroys any window(s) associated with this browser window before
* we attempt any destructive cleanup.
*/
- gui_window_destroy(bw->window);
+ if (bw->window) {
+ /* Only the root window has a GUI window */
+ gui_window_destroy(bw->window);
+ }
if (bw->loading_content != NULL) {
hlcache_handle_release(bw->loading_content);
@@ -1083,8 +1266,18 @@ void browser_window_destroy_internal(struct browser_window *bw)
bw->current_content = NULL;
}
+ if (bw->box != NULL) {
+ bw->box->iframe = NULL;
+ bw->box = NULL;
+ }
+
+ /* TODO: After core FRAMES are done, should be
+ * if (bw->browser_window_type == BROWSER_WINDOW_NORMAL) */
+ if (bw->browser_window_type != BROWSER_WINDOW_IFRAME) {
+ selection_destroy(bw->sel);
+ }
+
/* These simply free memory, so are safe here */
- selection_destroy(bw->sel);
history_destroy(bw->history);
free(bw->name);
@@ -1212,6 +1405,11 @@ void browser_window_refresh_url_bar(struct browser_window *bw, const char *url,
bw->visible_select_menu = NULL;
+ if (bw->parent != NULL) {
+ /* Not root window; don't set a URL in GUI URL bar */
+ return;
+ }
+
if (frag == NULL) {
/* With no fragment, we may as well pass url straight through
* saving a malloc, copy, free cycle.
@@ -1425,6 +1623,10 @@ void browser_window_mouse_track(struct browser_window *bw,
browser_window_mouse_drag_end(bw, mouse, x, y);
}
+ if (bw->drag_type != DRAGGING_NONE) {
+ selection_set_browser_window(bw->sel, bw);
+ }
+
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) {
@@ -1439,7 +1641,17 @@ void browser_window_mouse_track(struct browser_window *bw,
bw->drag_start_scroll_x = scrollx;
bw->drag_start_scroll_y = scrolly;
- gui_window_set_scroll(bw->window, scrollx, 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;
+ }
} else {
assert(c != NULL);
content_mouse_track(c, bw, mouse, x, y);
@@ -1460,10 +1672,19 @@ void browser_window_mouse_click(struct browser_window *bw,
browser_mouse_state mouse, int x, int y)
{
hlcache_handle *c = bw->current_content;
+ struct browser_window *top;
if (!c)
return;
+ /* Set focus browser window */
+ top = bw;
+ while (top && !top->window && top->parent)
+ top = top->parent;
+ top->focus = bw;
+
+ selection_set_browser_window(bw->sel, bw);
+
switch (content_get_type(c)) {
case CONTENT_HTML:
case CONTENT_TEXTPLAIN:
@@ -1481,7 +1702,7 @@ void browser_window_mouse_click(struct browser_window *bw,
else if (mouse & (BROWSER_MOUSE_DRAG_1 |
BROWSER_MOUSE_DRAG_2)) {
browser_window_page_drag_start(bw, x, y);
- browser_window_set_pointer(bw->window, GUI_POINTER_MOVE);
+ browser_window_set_pointer(bw, GUI_POINTER_MOVE);
}
break;
}
@@ -1495,10 +1716,10 @@ void browser_window_mouse_click(struct browser_window *bw,
* \param mouse state of mouse buttons and modifier keys
* \param x coordinate of mouse
* \param y coordinate of mouse
+ *
+ * TODO: MOVE content specific stuff out
*/
-// TODO: MOVE content specific stuff out
-
void browser_window_mouse_drag_end(struct browser_window *bw,
browser_mouse_state mouse, int x, int y)
{
@@ -1581,10 +1802,19 @@ void browser_window_page_drag_start(struct browser_window *bw, int x, int y)
bw->drag_start_x = x;
bw->drag_start_y = y;
- gui_window_get_scroll(bw->window, &bw->drag_start_scroll_x,
- &bw->drag_start_scroll_y);
+ switch (bw->browser_window_type) {
+ default:
+ /* fall through until frame(set)s are handled in core */
+ case BROWSER_WINDOW_NORMAL:
+ gui_window_get_scroll(bw->window, &bw->drag_start_scroll_x,
+ &bw->drag_start_scroll_y);
- gui_window_scroll_start(bw->window);
+ gui_window_scroll_start(bw->window);
+ break;
+ case BROWSER_WINDOW_IFRAME:
+ /* TODO */
+ break;
+ }
}
diff --git a/desktop/browser.h b/desktop/browser.h
index b8961447e..cb9b5abde 100644
--- a/desktop/browser.h
+++ b/desktop/browser.h
@@ -28,6 +28,7 @@
#include <stdbool.h>
#include <time.h>
+#include "content/content.h"
#include "desktop/gui.h"
#include "desktop/mouse.h"
#include "desktop/shape.h"
@@ -169,6 +170,9 @@ struct browser_window {
int iframe_count;
struct browser_window *iframes;
+ /** browser window child of root browser window which has input focus */
+ struct browser_window *focus;
+
/** Last time a link was followed in this window */
unsigned int last_action;
@@ -207,9 +211,13 @@ void browser_window_go_post(struct browser_window *bw,
void browser_window_go_unverifiable(struct browser_window *bw,
const char *url, const char *referrer, bool history_add,
struct hlcache_handle *parent);
+void browser_window_get_dimensions(struct browser_window *bw,
+ int *width, int *height, bool scaled);
void browser_window_download(struct browser_window *bw,
const char *url, const char *referrer);
void browser_window_update(struct browser_window *bw, bool scroll_to_top);
+void browser_window_update_box(struct browser_window *bw,
+ const union content_msg_data *data);
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);
@@ -244,7 +252,8 @@ void browser_window_redraw_rect(struct browser_window *bw, int x, int y,
int width, int height);
void browser_window_set_status(struct browser_window *bw, const char *text);
-void browser_window_set_pointer(struct gui_window *g, gui_pointer_shape shape);
+void browser_window_set_pointer(struct browser_window *bw,
+ gui_pointer_shape shape);
void browser_window_page_drag_start(struct browser_window *bw, int x, int y);
bool browser_window_back_available(struct browser_window *bw);
@@ -283,6 +292,27 @@ bool browser_window_redraw(struct browser_window *bw, int x, int y,
*/
bool browser_window_redraw_ready(struct browser_window *bw);
+/*
+ * Update the extent of the inside of a browser window to that of the current
+ * content
+ *
+ * \param bw browser_window to update the extent of
+ */
+void browser_window_update_extent(struct browser_window *bw);
+
+/*
+ * Get the position of the current browser window with respect to the root or
+ * parent browser window
+ *
+ * \param bw browser window to get the position of
+ * \param root true if we want position wrt root bw, false if wrt parent bw
+ * \param pos_x updated to x position of bw
+ * \param pos_y updated to y position of bw
+ */
+void browser_window_get_position(struct browser_window *bw, bool root,
+ int *pos_x, int *pos_y);
+
+
/* In platform specific hotlist.c. */
void hotlist_visited(struct hlcache_handle *c);
diff --git a/desktop/frames.c b/desktop/frames.c
index 3d97f4235..39d841754 100644
--- a/desktop/frames.c
+++ b/desktop/frames.c
@@ -83,6 +83,7 @@ void browser_window_create_iframes(struct browser_window *bw,
window->no_resize = true;
window->margin_width = cur->margin_width;
window->margin_height = cur->margin_height;
+ window->sel = bw->sel;
if (cur->name) {
window->name = strdup(cur->name);
if (!window->name)
@@ -92,22 +93,22 @@ void browser_window_create_iframes(struct browser_window *bw,
/* linking */
window->box = cur->box;
window->parent = bw;
-
- /* gui window */
- window->window = gui_create_browser_window(window, bw, false);
+ window->box->iframe = window;
}
/* calculate dimensions */
- gui_window_update_extent(bw->window);
+ browser_window_update_extent(bw);
browser_window_recalculate_iframes(bw);
index = 0;
for (cur = iframe; cur; cur = cur->next) {
window = &(bw->iframes[index++]);
- if (cur->url)
+ if (cur->url) {
+ /* fetch iframe's content */
browser_window_go_unverifiable(window, cur->url,
content_get_url(bw->current_content),
false, bw->current_content);
+ }
}
}
@@ -118,36 +119,10 @@ void browser_window_create_iframes(struct browser_window *bw,
* \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 index;
-
-#ifdef nsamiga
- /* In the Amiga frontend we can switch off IFrames because they
- * turn into pop-up hell due to broken frames implementation.
- * This stops NetSurf asserting in this specific instance.
- */
- if(bw && bw->window == NULL) return;
-#endif
-
- assert(bw != NULL);
- assert(bw->window != NULL);
-
- /* update window dimensions */
- for (index = 0; index < bw->iframe_count; index++) {
- window = &(bw->iframes[index]);
-
- if ((window != NULL) && (window->box != NULL)) {
- box_bounds(window->box, &rect);
- gui_window_position_frame(window->window,
- rect.x0, rect.y0,
- rect.x1, rect.y1);
- } else {
- LOG(("Bad IFrame window=%p, box=%p", window,
- window != NULL ? window->box : NULL));
- }
- }
+void browser_window_recalculate_iframes(struct browser_window *bw)
+{
+ /* TODO: decide if this is still needed after scrollbars are
+ * implemented */
}
@@ -206,6 +181,10 @@ void browser_window_create_frameset(struct browser_window *bw,
warn_user("NoMemory", 0);
}
+ /* TODO: when framesets are handled in the core, remove
+ * the following line. */
+ window->sel = selection_create();
+
/* linking */
window->parent = bw;
@@ -220,7 +199,7 @@ void browser_window_create_frameset(struct browser_window *bw,
}
/* 2. Calculate dimensions */
- gui_window_update_extent(bw->window);
+ browser_window_update_extent(bw);
browser_window_recalculate_frameset(bw);
/* 3. Recurse for grandchildren */
diff --git a/desktop/search.c b/desktop/search.c
index 4598e60f7..790f3d4a0 100644
--- a/desktop/search.c
+++ b/desktop/search.c
@@ -644,7 +644,8 @@ void search_show_all(bool all, struct search_context *context)
}
}
if (add && !a->sel) {
- a->sel = selection_create(context->bw);
+ a->sel = selection_create();
+ selection_set_browser_window(a->sel, context->bw);
if (a->sel) {
hlcache_handle *c = context->bw->
current_content;
diff --git a/desktop/selection.c b/desktop/selection.c
index 9bc594bdd..c86432f6a 100644
--- a/desktop/selection.c
+++ b/desktop/selection.c
@@ -90,14 +90,30 @@ static struct box *get_box(struct box *b, unsigned offset, size_t *pidx);
/**
* Creates a new selection object associated with a browser window.
*
+ * \param s selection object
* \param bw browser window
*/
-struct selection *selection_create(struct browser_window *bw)
+void selection_set_browser_window(struct selection *s,
+ struct browser_window *bw)
+{
+ assert(s);
+
+ s->bw = bw;
+}
+
+/**
+ * Set the browser window that contains the selection within a selection
+ * object.
+ *
+ * \param bw browser window
+ */
+
+struct selection *selection_create(void)
{
struct selection *s = calloc(1, sizeof(struct selection));
if (s) {
- s->bw = bw;
+ s->bw = NULL;
s->root = NULL;
s->drag_state = DRAG_NONE;
selection_clear(s, false);
@@ -116,7 +132,8 @@ struct selection *selection_create(struct browser_window *bw)
void selection_destroy(struct selection *s)
{
- free(s);
+ if (s != NULL)
+ free(s);
}
@@ -260,6 +277,7 @@ bool selection_click(struct selection *s, browser_mouse_state mouse,
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 *bw;
if (!SAME_SPACE(s, idx))
return false; /* not our problem */
@@ -278,7 +296,12 @@ bool selection_click(struct selection *s, browser_mouse_state mouse,
(modkeys && (mouse & BROWSER_MOUSE_DRAG_2)))) {
/* drag-saving selection */
assert(s->bw);
- gui_drag_save_selection(s, s->bw->window);
+
+ bw = s->bw;
+ while (bw && !bw->window && bw->parent)
+ bw = bw->parent;
+
+ gui_drag_save_selection(s, bw->window);
}
else if (!modkeys) {
if (pos && (mouse & BROWSER_MOUSE_PRESS_1))
@@ -294,7 +317,11 @@ bool selection_click(struct selection *s, browser_mouse_state mouse,
s->drag_state = DRAG_END;
- gui_start_selection(s->bw->window);
+ bw = s->bw;
+ while (bw && !bw->window && bw->parent)
+ bw = bw->parent;
+
+ gui_start_selection(bw->window);
}
else if (mouse & BROWSER_MOUSE_DRAG_2) {
@@ -312,7 +339,12 @@ bool selection_click(struct selection *s, browser_mouse_state mouse,
s->drag_state = DRAG_START;
}
- gui_start_selection(s->bw->window);
+
+ bw = s->bw;
+ while (bw && !bw->window && bw->parent)
+ bw = bw->parent;
+
+ gui_start_selection(bw->window);
}
/* Selection should be cleared when button is released but in
* the RO interface click is the same as press */
@@ -675,10 +707,11 @@ void selection_redraw(struct selection *s, unsigned start_idx, unsigned end_idx)
rdw.inited = true;
}
}
+ LOG(("browser window type: %s", s->bw->browser_window_type == BROWSER_WINDOW_NORMAL ? "NORMAL" : "IFRAME"));
if (rdw.inited)
browser_window_redraw_rect(s->bw, rdw.r.x0, rdw.r.y0,
- rdw.r.x1 - rdw.r.x0, rdw.r.y1 - rdw.r.y0);
+ rdw.r.x1 - rdw.r.x0, rdw.r.y1 - rdw.r.y0);
}
@@ -694,6 +727,7 @@ void selection_clear(struct selection *s, bool redraw)
{
int old_start, old_end;
bool was_defined;
+ struct browser_window *bw;
assert(s);
was_defined = selection_defined(s);
@@ -704,7 +738,14 @@ void selection_clear(struct selection *s, bool redraw)
s->start_idx = 0;
s->end_idx = 0;
- gui_clear_selection(s->bw->window);
+ if (!s->bw)
+ return;
+
+ bw = s->bw;
+ while (bw && !bw->window && bw->parent)
+ bw = bw->parent;
+
+ gui_clear_selection(bw->window);
if (redraw && was_defined)
selection_redraw(s, old_start, old_end);
diff --git a/desktop/selection.h b/desktop/selection.h
index 7eafb2c7d..8dc3ce103 100644
--- a/desktop/selection.h
+++ b/desktop/selection.h
@@ -59,12 +59,15 @@ typedef bool (*seln_traverse_handler)(const char *text, size_t length,
size_t whitespace_length);
-struct selection *selection_create(struct browser_window *bw);
+struct selection *selection_create(void);
void selection_destroy(struct selection *s);
void selection_init(struct selection *s, struct box *root);
void selection_reinit(struct selection *s, struct box *root);
+void selection_set_browser_window(struct selection *s,
+ struct browser_window *bw);
+
/* struct box *selection_root(struct selection *s); */
#define selection_root(s) ((s)->root)
diff --git a/desktop/textinput.c b/desktop/textinput.c
index 0a33e545c..f114067f0 100644
--- a/desktop/textinput.c
+++ b/desktop/textinput.c
@@ -1173,7 +1173,29 @@ void browser_window_place_caret(struct browser_window *bw,
browser_move_callback move_cb,
void *p)
{
- gui_window_place_caret(bw->window, x, y, height);
+ struct browser_window *root_bw;
+ int pos_x = 0;
+ int pos_y = 0;
+
+ /* Find top level browser window */
+ root_bw = bw;
+ while (root_bw && !root_bw->window && root_bw->parent) {
+ switch (root_bw->browser_window_type) {
+ default:
+ /* TODO: Frame(set)s */
+ case BROWSER_WINDOW_NORMAL:
+ break;
+ case BROWSER_WINDOW_IFRAME:
+ box_coords(root_bw->box, &pos_x, &pos_y);
+ x += pos_x;
+ y += pos_y;
+ break;
+ }
+
+ root_bw = root_bw->parent;
+ }
+
+ gui_window_place_caret(root_bw->window, x, y, height);
bw->caret_callback = caret_cb;
bw->paste_callback = paste_cb;
bw->move_callback = move_cb;
@@ -1188,7 +1210,16 @@ void browser_window_place_caret(struct browser_window *bw,
*/
void browser_window_remove_caret(struct browser_window *bw)
{
- gui_window_remove_caret(bw->window);
+ struct browser_window *root_bw;
+
+ /* Find top level browser window */
+ root_bw = bw;
+ while (root_bw && !root_bw->window && root_bw->parent) {
+ root_bw = root_bw->parent;
+ }
+
+ gui_window_remove_caret(root_bw->window);
+
bw->caret_callback = NULL;
bw->paste_callback = NULL;
bw->move_callback = NULL;
@@ -1245,29 +1276,31 @@ size_t get_form_offset(struct box* input, struct box* text_box,
/**
* Handle key presses in a browser window.
*
- * \param bw The browser window with input focus
+ * \param bw The root browser window
* \param key The UCS4 character codepoint
* \return true if key handled, false otherwise
*/
bool browser_window_key_press(struct browser_window *bw, uint32_t key)
{
+ struct browser_window *focus = bw->focus;
+
/* keys that take effect wherever the caret is positioned */
switch (key) {
case KEY_SELECT_ALL:
- selection_select_all(bw->sel);
+ selection_select_all(focus->sel);
return true;
case KEY_COPY_SELECTION:
- gui_copy_to_clipboard(bw->sel);
+ gui_copy_to_clipboard(focus->sel);
return true;
case KEY_CLEAR_SELECTION:
- selection_clear(bw->sel, true);
+ selection_clear(focus->sel, true);
return true;
case KEY_ESCAPE:
- if (selection_defined(bw->sel)) {
- selection_clear(bw->sel, true);
+ if (selection_defined(focus->sel)) {
+ selection_clear(focus->sel, true);
return true;
}
/* if there's no selection,
@@ -1276,10 +1309,10 @@ bool browser_window_key_press(struct browser_window *bw, uint32_t key)
}
/* pass on to the appropriate field */
- if (!bw->caret_callback)
+ if (!focus->caret_callback)
return false;
- return bw->caret_callback(bw, key, bw->caret_p);
+ return focus->caret_callback(focus, key, focus->caret_p);
}
diff --git a/render/box.c b/render/box.c
index bd5f3daa1..60b5b9381 100644
--- a/render/box.c
+++ b/render/box.c
@@ -165,6 +165,7 @@ struct box * box_create(css_select_results *styles, css_computed_style *style,
box->background = NULL;
box->object = NULL;
box->object_params = NULL;
+ box->iframe = NULL;
return box;
}
@@ -932,6 +933,9 @@ void box_dump(FILE *stream, struct box *box, unsigned int depth)
fprintf(stream, "(object '%s') ",
content_get_url(box->object));
}
+ if (box->iframe) {
+ fprintf(stream, "(iframe) ");
+ }
if (box->gadget)
fprintf(stream, "(gadget) ");
if (box->style)
diff --git a/render/box.h b/render/box.h
index 936c57337..99f67ee1f 100644
--- a/render/box.h
+++ b/render/box.h
@@ -127,7 +127,8 @@ typedef enum {
HAS_HEIGHT = 1 << 6, /* box has height (perhaps due to children) */
MAKE_HEIGHT = 1 << 7, /* box causes its own height */
NEED_MIN = 1 << 8, /* minimum width is required for layout */
- REPLACE_DIM = 1 << 9 /* replaced element has given dimensions */
+ REPLACE_DIM = 1 << 9, /* replaced element has given dimensions */
+ IFRAME = 1 << 10 /* box contains an iframe */
} box_flags;
/* Sides of a box */
@@ -257,6 +258,9 @@ struct box {
struct hlcache_handle* object;
/** Parameters for the object, or 0. */
struct object_params *object_params;
+
+ /** Iframe's browser_window, or NULL if none */
+ struct browser_window *iframe;
};
/** Table column data. */
diff --git a/render/box_construct.c b/render/box_construct.c
index 34cd77b04..5fdb23b5a 100644
--- a/render/box_construct.c
+++ b/render/box_construct.c
@@ -1631,8 +1631,8 @@ bool box_iframe(BOX_SPECIAL_PARAMS)
free(url);
/* box */
- box->type = BOX_INLINE_BLOCK;
assert(box->style);
+ box->flags |= IFRAME;
/* Showing iframe, so don't show alternate content */
if (convert_children)
diff --git a/render/html_interaction.c b/render/html_interaction.c
index cd4caa488..91f8cb39c 100644
--- a/render/html_interaction.c
+++ b/render/html_interaction.c
@@ -135,6 +135,7 @@ void html_mouse_action(struct content *c, struct browser_window *bw,
hlcache_handle *gadget_content = h;
struct form_control *gadget = 0;
hlcache_handle *object = NULL;
+ struct browser_window *iframe = NULL;
struct box *next_box;
struct box *drag_candidate = NULL;
struct scrollbar *scrollbar = NULL;
@@ -214,6 +215,9 @@ void html_mouse_action(struct content *c, struct browser_window *bw,
if (box->object)
object = box->object;
+ if (box->iframe)
+ iframe = box->iframe;
+
if (box->href) {
url = box->href;
target = box->target;
@@ -464,6 +468,18 @@ void html_mouse_action(struct content *c, struct browser_window *bw,
/* \todo should have a drag-saving object msg */
status = content_get_status_message(h);
+ } else if (iframe) {
+ int pos_x, pos_y;
+ browser_window_get_position(iframe, false, &pos_x, &pos_y);
+
+ if (mouse & BROWSER_MOUSE_CLICK_1 ||
+ mouse & BROWSER_MOUSE_CLICK_2) {
+ browser_window_mouse_click(iframe, mouse,
+ x - pos_x, y - pos_y);
+ } else {
+ browser_window_mouse_track(iframe, mouse,
+ x - pos_x, y - pos_y);
+ }
} else if (url) {
if (title) {
snprintf(status_buffer, sizeof status_buffer, "%s: %s",
@@ -601,7 +617,8 @@ void html_mouse_action(struct content *c, struct browser_window *bw,
if (status != NULL)
browser_window_set_status(bw, status);
- browser_window_set_pointer(bw->window, pointer);
+ if (!iframe)
+ browser_window_set_pointer(bw, pointer);
/* deferred actions that can cause this browser_window to be destroyed
* and must therefore be done after set_status/pointer
@@ -778,8 +795,7 @@ void html_overflow_scroll_callback(void *client_data,
case SCROLLBAR_MSG_SCROLL_FINISHED:
bw->scrollbar = NULL;
- browser_window_set_pointer(bw->window,
- GUI_POINTER_DEFAULT);
+ browser_window_set_pointer(bw, GUI_POINTER_DEFAULT);
break;
}
}
diff --git a/render/html_redraw.c b/render/html_redraw.c
index cc80bde81..1bc32607f 100644
--- a/render/html_redraw.c
+++ b/render/html_redraw.c
@@ -430,7 +430,7 @@ bool html_redraw_box(struct box *box, int x_parent, int y_parent,
bg_box->type != BOX_TEXT &&
bg_box->type != BOX_INLINE_END &&
(bg_box->type != BOX_INLINE || bg_box->object ||
- box->flags & REPLACE_DIM)) {
+ bg_box->flags & IFRAME || box->flags & REPLACE_DIM)) {
/* find intersection of clip box and border edge */
struct rect p;
p.x0 = x - border_left < r.x0 ? r.x0 : x - border_left;
@@ -475,7 +475,7 @@ bool html_redraw_box(struct box *box, int x_parent, int y_parent,
if (box->style && box->type != BOX_TEXT &&
box->type != BOX_INLINE_END &&
(box->type != BOX_INLINE || box->object ||
- box->flags & REPLACE_DIM) &&
+ box->flags & IFRAME || box->flags & REPLACE_DIM) &&
(border_top || border_right ||
border_bottom || border_left)) {
if (!html_redraw_borders(box, x_parent, y_parent,
@@ -622,8 +622,9 @@ bool html_redraw_box(struct box *box, int x_parent, int y_parent,
/* clip to the padding edge for objects, or boxes with overflow hidden
* or scroll */
- if (box->object || (box->style && css_computed_overflow(box->style) !=
- CSS_OVERFLOW_VISIBLE)) {
+ if ((box->style && css_computed_overflow(box->style) !=
+ CSS_OVERFLOW_VISIBLE) || box->object ||
+ box->flags & IFRAME) {
r.x0 = x;
r.y0 = y;
r.x1 = x + padding_width;
@@ -660,6 +661,10 @@ bool html_redraw_box(struct box *box, int x_parent, int y_parent,
false, false))
return false;
+ } else if (box->flags & IFRAME) {
+ browser_window_redraw(box->iframe,
+ x + padding_left, y + padding_top, &r);
+
} else if (box->gadget && box->gadget->type == GADGET_CHECKBOX) {
if (!html_redraw_checkbox(x + padding_left, y + padding_top,
width, height,
diff --git a/render/layout.c b/render/layout.c
index 60ad8baa9..711eb5c71 100644
--- a/render/layout.c
+++ b/render/layout.c
@@ -273,6 +273,12 @@ bool layout_block_context(struct box *block, int viewport_height,
return true;
}
+ /* special case if the block contains an iframe */
+ if (block->iframe) {
+ browser_window_reformat(block->iframe, block->width,
+ block->height == AUTO ? 0 : block->height);
+ }
+
/* special case if the block contains an radio button or checkbox */
if (block->gadget && (block->gadget->type == GADGET_RADIO ||
block->gadget->type == GADGET_CHECKBOX)) {
@@ -360,8 +366,10 @@ bool layout_block_context(struct box *block, int viewport_height,
* left and right margins to avoid any floats. */
lm = rm = 0;
- if (box->type == BOX_BLOCK || box->object) {
- if (!box->object && !(box->flags & REPLACE_DIM) &&
+ if (box->type == BOX_BLOCK || box->object ||
+ box->flags & IFRAME) {
+ if (!box->object && !(box->flags & IFRAME) &&
+ !(box->flags & REPLACE_DIM) &&
box->style &&
css_computed_overflow(box->style) !=
CSS_OVERFLOW_VISIBLE) {
@@ -388,7 +396,7 @@ bool layout_block_context(struct box *block, int viewport_height,
}
layout_block_find_dimensions(box->parent->width,
viewport_height, lm, rm, box);
- if (box->type == BOX_BLOCK) {
+ if (box->type == BOX_BLOCK && !(box->flags & IFRAME)) {
layout_block_add_scrollbar(box, RIGHT);
layout_block_add_scrollbar(box, BOTTOM);
}
@@ -503,11 +511,18 @@ bool layout_block_context(struct box *block, int viewport_height,
if (box->object) {
if (!layout_block_object(box))
return false;
+
+ } else if (box->iframe) {
+ browser_window_reformat(box->iframe, box->width,
+ box->height == AUTO ?
+ 0 : box->height);
+
} else if (box->type == BOX_INLINE_CONTAINER) {
box->width = box->parent->width;
if (!layout_inline_container(box, box->width, block,
cx, cy, content))
return false;
+
} else if (box->type == BOX_TABLE) {
/* Move down to avoid floats if necessary. */
int x0, x1;
@@ -549,7 +564,8 @@ bool layout_block_context(struct box *block, int viewport_height,
}
/* Advance to next box. */
- if (box->type == BOX_BLOCK && !box->object && box->children) {
+ if (box->type == BOX_BLOCK && !box->object && !(box->iframe) &&
+ box->children) {
/* Down into children. */
if (box == margin_collapse) {
@@ -563,7 +579,8 @@ bool layout_block_context(struct box *block, int viewport_height,
box->y = y;
cy += y;
continue;
- } else if (box->type == BOX_BLOCK || box->object)
+ } else if (box->type == BOX_BLOCK || box->object ||
+ box->flags & IFRAME)
cy += box->padding[TOP];
if (box->type == BOX_BLOCK && box->height == AUTO) {
@@ -777,6 +794,10 @@ void layout_minmax_block(struct box *block,
}
block->flags |= HAS_HEIGHT;
+ } else if (block->flags & IFRAME) {
+ /** TODO: do we need to know the min/max width of the iframe's
+ * content? */
+ block->flags |= HAS_HEIGHT;
} else {
/* recurse through children */
for (child = block->children; child; child = child->next) {
@@ -2016,8 +2037,9 @@ bool layout_inline_container(struct box *inline_container, int width,
whitespace == CSS_WHITE_SPACE_PRE_WRAP);
}
- if ((!c->object && !(c->flags & REPLACE_DIM) && c->text &&
- (c->length || is_pre)) ||
+ if ((!c->object && !(c->flags & REPLACE_DIM) &&
+ !(c->flags & IFRAME) &&
+ c->text && (c->length || is_pre)) ||
c->type == BOX_BR)
has_text_children = true;
}
@@ -2369,7 +2391,7 @@ bool layout_line(struct box *first, int *width, int *y,
continue;
}
- if (!b->object && !b->gadget &&
+ if (!b->object && !(b->flags & IFRAME) && !b->gadget &&
!(b->flags & REPLACE_DIM)) {
/* inline non-replaced, 10.3.1 and 10.6.1 */
b->height = line_height(b->style ? b->style :
@@ -2468,6 +2490,19 @@ bool layout_line(struct box *first, int *width, int *y,
if (b->object && !(b->flags & REPLACE_DIM)) {
layout_get_object_dimensions(b, &b->width, &b->height,
true, true);
+ } else if (b->flags & IFRAME) {
+ /* TODO: should we look at the content dimensions? */
+ if (b->width == AUTO)
+ b->width = 400;
+ if (b->height == AUTO)
+ b->height = 300;
+
+ /* If the iframe's bw is in place, reformat it to the
+ * new box size */
+ if (b->iframe) {
+ browser_window_reformat(b->iframe,
+ b->width, b->height);
+ }
} else {
/* form control with no object */
if (b->width == AUTO)
@@ -2478,6 +2513,7 @@ bool layout_line(struct box *first, int *width, int *y,
CSS_UNIT_EM, b->style));
}
+ /* Reformat object to new box size */
if (b->object && content_get_type(b->object) == CONTENT_HTML &&
b->width !=
content_get_available_width(b->object)) {
@@ -2558,7 +2594,8 @@ bool layout_line(struct box *first, int *width, int *y,
}
space_before = space_after;
- if (b->object || b->flags & REPLACE_DIM)
+ if (b->object || b->flags & REPLACE_DIM ||
+ b->flags & IFRAME)
space_after = 0;
else if (b->text || b->type == BOX_INLINE_END) {
if (b->space == UNKNOWN_WIDTH) {
@@ -2713,6 +2750,7 @@ bool layout_line(struct box *first, int *width, int *y,
split_box->type == BOX_TEXT) &&
!split_box->object &&
!(split_box->flags & REPLACE_DIM) &&
+ !(split_box->flags & IFRAME) &&
!split_box->gadget && split_box->text) {
/* skip leading spaces, otherwise code gets fooled into
* thinking it's all one long word */
@@ -2867,6 +2905,7 @@ bool layout_line(struct box *first, int *width, int *y,
continue;
} else if ((d->type == BOX_INLINE &&
((d->object || d->gadget) == false) &&
+ !(d->flags & IFRAME) &&
!(d->flags & REPLACE_DIM)) ||
d->type == BOX_BR ||
d->type == BOX_TEXT ||
@@ -3022,7 +3061,8 @@ struct box *layout_minmax_line(struct box *first,
font_plot_style_from_css(b->style, &fstyle);
if (b->type == BOX_INLINE && !b->object &&
- !(b->flags & REPLACE_DIM)) {
+ !(b->flags & REPLACE_DIM) &&
+ !(b->flags & IFRAME)) {
fixed = frac = 0;
calculate_mbp_width(b->style, LEFT, true, true, true,
&fixed, &frac);
@@ -3050,7 +3090,7 @@ struct box *layout_minmax_line(struct box *first,
continue;
}
- if (!b->object && !b->gadget &&
+ if (!b->object && !(b->flags & IFRAME) && !b->gadget &&
!(b->flags & REPLACE_DIM)) {
/* inline non-replaced, 10.3.1 and 10.6.1 */
if (!b->text)
@@ -3165,6 +3205,15 @@ struct box *layout_minmax_line(struct box *first,
if (0 < width + fixed)
width += fixed;
+ } else if (b->flags & IFRAME) {
+ fixed = frac = 0;
+ calculate_mbp_width(b->style, LEFT, true, true, true,
+ &fixed, &frac);
+ calculate_mbp_width(b->style, RIGHT, true, true, true,
+ &fixed, &frac);
+
+ if (0 < width + fixed)
+ width += fixed;
} else {
/* form control with no object */
if (width == AUTO)
@@ -4668,7 +4717,7 @@ bool layout_absolute(struct box *box, struct box *containing_block,
box->height = height;
if (box->type == BOX_BLOCK || box->type == BOX_INLINE_BLOCK ||
- box->object) {
+ box->object || box->flags & IFRAME) {
if (!layout_block_context(box, -1, content))
return false;
} else if (box->type == BOX_TABLE) {
diff --git a/render/textplain.c b/render/textplain.c
index f498869de..8a1bdc88a 100644
--- a/render/textplain.c
+++ b/render/textplain.c
@@ -661,7 +661,7 @@ void textplain_mouse_action(struct content *c, struct browser_window *bw,
if (status != NULL)
browser_window_set_status(bw, status);
- browser_window_set_pointer(bw->window, pointer);
+ browser_window_set_pointer(bw, pointer);
}