summaryrefslogtreecommitdiff
path: root/desktop
diff options
context:
space:
mode:
Diffstat (limited to 'desktop')
-rw-r--r--desktop/browser.c800
-rw-r--r--desktop/browser.h148
-rw-r--r--desktop/fetch.c344
-rw-r--r--desktop/fetch.h49
-rw-r--r--desktop/gui.h45
-rw-r--r--desktop/netsurf.c50
-rw-r--r--desktop/netsurf.h35
7 files changed, 1471 insertions, 0 deletions
diff --git a/desktop/browser.c b/desktop/browser.c
new file mode 100644
index 000000000..f21008abb
--- /dev/null
+++ b/desktop/browser.c
@@ -0,0 +1,800 @@
+/**
+ * $Id: browser.c,v 1.1 2002/09/11 14:24:02 monkeyson Exp $
+ */
+
+#include "netsurf/riscos/font.h"
+#include "netsurf/render/box.h"
+#include "netsurf/render/layout.h"
+#include "netsurf/render/css.h"
+#include "netsurf/desktop/browser.h"
+#include "netsurf/render/utils.h"
+#include <string.h>
+#include <stdlib.h>
+#include <assert.h>
+#include <limits.h>
+
+struct box_selection
+{
+ struct box* box;
+ int actual_x;
+ int actual_y;
+ int plot_index;
+};
+
+void browser_window_text_selection(struct browser_window* bw, int click_x, int click_y, int click_type);
+void browser_window_clear_text_selection(struct browser_window* bw);
+void browser_window_change_text_selection(struct browser_window* bw, struct box_position* new_start, struct box_position* new_end);
+void browser_window_redraw_boxes(struct browser_window* bw, struct box_position* start, struct box_position* end);
+void browser_window_follow_link(struct browser_window* bw,
+ int click_x, int click_y, int click_type);
+
+void box_under_area(struct box* box, int x, int y, int ox, int oy, struct box_selection** found, int* count, int* plot_index);
+
+
+void content_destroy(struct content* c)
+{
+ if (c == NULL)
+ return;
+
+ switch (c->type)
+ {
+ case CONTENT_HTML:
+ /* free other memory here */
+ break;
+ default:
+ break;
+ }
+
+ c->main_fetch = fetch_cancel(c->main_fetch);
+ xfree(c);
+
+ return;
+}
+
+size_t content_html_receive_data(struct content* c, void* data, size_t size, size_t nmemb)
+{
+ size_t amount = nmemb;
+ int offset = 0;
+ size_t numInChunk = 2048 / size; /* process in 2k chunks */
+
+ if (numInChunk > nmemb)
+ numInChunk = nmemb;
+ else if (numInChunk <= (size_t)0)
+ numInChunk = 1;
+
+ while (amount > 0)
+ {
+ htmlParseChunk(c->data.html.parser, (char*)data + (offset * size), numInChunk, 0);
+ offset += numInChunk;
+ amount -= numInChunk;
+ if (amount < numInChunk)
+ numInChunk = amount;
+ gui_multitask();
+ }
+
+ return size * nmemb;
+}
+
+void set_content_html(struct content* c)
+{
+ c->type = CONTENT_HTML;
+ c->data.html.parser = htmlCreatePushParserCtxt(0, 0, "", 0, 0, XML_CHAR_ENCODING_8859_1);
+ c->data.html.document = NULL;
+ c->data.html.markup = NULL;
+ c->data.html.layout = NULL;
+ c->data.html.stylesheet = NULL;
+ c->data.html.style = NULL;
+ return;
+}
+
+void content_html_reformat(struct content* c, int width)
+{
+ char* file;
+ struct css_selector* selector = xcalloc(1, sizeof(struct css_selector));
+
+ Log("content_html_reformat", "Starting stuff");
+ c->data.html.layout = NULL; /* should be a freeing operation here */
+ /* free other things too... */
+
+ Log("content_html_reformat", "Setting document to myDoc");
+ c->data.html.document = c->data.html.parser->myDoc;
+
+ /* skip to start of html */
+ Log("content_html_reformat", "Skipping to html");
+ if (c->data.html.document == NULL)
+ {
+ Log("content_html_reformat", "There is no document!");
+ return;
+ }
+ for (c->data.html.markup = c->data.html.document->children;
+ c->data.html.markup != 0 &&
+ c->data.html.markup->type != XML_ELEMENT_NODE;
+ c->data.html.markup = c->data.html.markup->next)
+ ;
+
+ if (c->data.html.markup == 0)
+ {
+ Log("content_html_reformat", "No markup");
+ return;
+ }
+ if (strcmp((const char *) c->data.html.markup->name, "html"))
+ {
+ Log("content_html_reformat", "Not html");
+ return;
+ }
+
+ Log("content_html_reformat", "Loading CSS");
+ file = load("<NetSurf$Dir>.Resources.CSS"); /*!!! not portable! !!!*/
+ c->data.html.stylesheet = css_new_stylesheet();
+ Log("content_html_reformat", "Parsing stylesheet");
+ css_parse_stylesheet(c->data.html.stylesheet, file);
+
+ Log("content_html_reformat", "Copying base style");
+ c->data.html.style = xcalloc(1, sizeof(struct css_style));
+ memcpy(c->data.html.style, &css_base_style, sizeof(struct css_style));
+
+ Log("content_html_reformat", "Creating box");
+ c->data.html.layout = xcalloc(1, sizeof(struct box));
+ c->data.html.layout->type = BOX_BLOCK;
+ c->data.html.layout->node = c->data.html.markup;
+
+ Log("content_html_reformat", "XML to box");
+ xml_to_box(c->data.html.markup, c->data.html.style, c->data.html.stylesheet, &selector, 0, c->data.html.layout, 0, 0);
+ Log("content_html_reformat", "Layout document");
+ layout_document(c->data.html.layout->children, (unsigned long)width);
+
+ /* can tidy up memory here? */
+
+ return;
+}
+
+void browser_window_reformat(struct browser_window* bw)
+{
+ Log("browser_window_reformat", "Entering...");
+ if (bw == NULL)
+ return;
+ if (bw->current_content == NULL)
+ return;
+
+ switch (bw->current_content->type)
+ {
+ case CONTENT_HTML:
+ Log("browser_window_reformat", "HTML content.");
+ browser_window_set_status(bw, "Formatting page...");
+ content_html_reformat(bw->current_content, bw->format_width);
+ Log("browser_window_reformat", "Content reformatted");
+ if (bw->current_content->data.html.layout != NULL)
+ {
+ Log("browser_window_reformat", "Setting extent");
+ gui_window_set_extent(bw->window, bw->current_content->data.html.layout->children->width, bw->current_content->data.html.layout->children->height);
+ Log("browser_window_reformat", "Setting scroll");
+ gui_window_set_scroll(bw->window, 0, 0);
+ Log("browser_window_reformat", "Redraw window");
+ gui_window_redraw_window(bw->window);
+ Log("browser_window_reformat", "Complete");
+ browser_window_set_status(bw, "Format complete.");
+ }
+ else
+ {
+ Log("browser_window_reformat", "This isn't html");
+ browser_window_set_status(bw, "This is not HTML!");
+ content_destroy(bw->current_content);
+ bw->current_content = NULL;
+ }
+ break;
+ default:
+ Log("browser_window_reformat", "Unknown content type");
+ break;
+ }
+}
+
+/* create a new history item */
+struct history* history_create(char* desc, char* url)
+{
+ struct history* h = xcalloc(1, sizeof(struct history));
+ h->description = xstrdup(desc);
+ h->url = xstrdup(url);
+ return h;
+}
+
+/* remember a new page after the current one. anything remembered after the
+ current page is forgotten. */
+void history_remember(struct history* current, char* desc, char* url)
+{
+ struct history* h;
+ assert(current != NULL);
+
+ /* forget later history items */
+ h = current->later;
+ while (h != NULL)
+ {
+ struct history* hh;
+ hh = h;
+ h = h->later;
+
+ if (hh->description != NULL)
+ xfree(hh->description);
+ if (hh->url != NULL)
+ xfree(hh->url);
+
+ xfree(hh);
+ }
+
+ current->later = history_create(desc, url);
+ return;
+}
+
+
+struct browser_window* create_browser_window(int flags, int width, int height)
+{
+ struct browser_window* bw;
+ bw = (struct browser_window*) xcalloc(1, sizeof(struct browser_window));
+
+ bw->flags = flags;
+ bw->format_width = width;
+ bw->format_height = height;
+
+ bw->scale.mult = 1;
+ bw->scale.div = 1;
+
+ bw->current_content = NULL;
+ bw->future_content = NULL;
+ bw->history = NULL;
+
+ bw->url = NULL;
+ bw->title = xstrdup("NetSurf");
+
+ bw->window = create_gui_browser_window(bw);
+
+ return bw;
+}
+
+void browser_window_set_status(struct browser_window* bw, char* text)
+{
+ if (bw->window != NULL)
+ gui_window_set_status(bw->window, text);
+}
+
+void browser_window_destroy(struct browser_window* bw)
+{
+ if (bw == NULL)
+ return;
+
+ content_destroy(bw->current_content);
+ content_destroy(bw->future_content);
+
+ if (bw->history != NULL)
+ {
+ struct history* current;
+
+ while (current->earlier != NULL)
+ current = current->earlier;
+
+ while (current != NULL)
+ {
+ struct history* hh;
+ hh = current;
+ current = current->later;
+
+ if (hh->description != NULL)
+ xfree(hh->description);
+ if (hh->url != NULL)
+ xfree(hh->url);
+
+ xfree(hh);
+ }
+ }
+
+ xfree(bw->url);
+ xfree(bw->title);
+
+ gui_window_destroy(bw->window);
+
+ xfree(bw);
+
+ return;
+}
+
+void browser_window_open_location(struct browser_window* bw, char* url)
+{
+ struct fetch_request* req;
+
+ if (bw == NULL)
+ return;
+
+ if (bw->future_content != NULL)
+ content_destroy(bw->future_content);
+
+ req = xcalloc(1, sizeof(struct fetch_request));
+ req->type = REQUEST_FROM_BROWSER;
+ req->requestor.browser = bw;
+
+ bw->future_content = (struct content*) xcalloc(1, sizeof(struct content));
+ bw->future_content->main_fetch = create_fetch(url, bw->url, 0, req);
+
+ return;
+}
+
+int browser_window_message(struct browser_window* bw, struct browser_message* msg)
+{
+ gui_safety previous_safety;
+
+ switch (msg->type)
+ {
+ case msg_FETCH_SENDING:
+ browser_window_set_status(bw, "Sending request...");
+ break;
+
+ case msg_FETCH_WAITING:
+ browser_window_set_status(bw, "Waiting for reply...");
+ break;
+
+ case msg_FETCH_FETCH_INFO:
+ browser_window_set_status(bw, "Request received...");
+ if (msg->f == bw->future_content->main_fetch)
+ {
+ switch (msg->data.fetch_info.type)
+ {
+ case type_HTML:
+ set_content_html(bw->future_content);
+ break;
+ default:
+ return 1;
+ }
+ }
+ break;
+
+ case msg_FETCH_DATA:
+ browser_window_set_status(bw, "Data received...");
+ if (msg->f == bw->future_content->main_fetch)
+ content_html_receive_data(bw->future_content, msg->data.fetch_data.block, sizeof(char), msg->data.fetch_data.block_size);
+ break;
+
+ case msg_FETCH_ABORT:
+ browser_window_set_status(bw, "Request failed.");
+ if (msg->f == bw->future_content->main_fetch)
+ {
+ bw->future_content->main_fetch = NULL;
+ content_destroy(bw->future_content);
+ bw->future_content = NULL;
+ }
+ break;
+
+ case msg_FETCH_FINISHED:
+ browser_window_set_status(bw, "Request complete.");
+ if (msg->f == bw->future_content->main_fetch)
+ {
+ struct gui_message gmsg;
+ if (bw->future_content->main_fetch->location != NULL)
+ xfree(bw->url);
+ bw->url = xstrdup(bw->future_content->main_fetch->location);
+
+ gmsg.type = msg_SET_URL;
+ gmsg.data.set_url.url = bw->url;
+ gui_window_message(bw->window, &gmsg);
+
+ htmlParseChunk(bw->future_content->data.html.parser, "", 0, 1);
+ bw->future_content->main_fetch = NULL;
+ previous_safety = gui_window_set_redraw_safety(bw->window, UNSAFE);
+ content_destroy(bw->current_content);
+ bw->current_content = bw->future_content;
+ bw->future_content = NULL;
+ browser_window_reformat(bw);
+ gui_window_set_redraw_safety(bw->window, previous_safety);
+ }
+ break;
+
+ default:
+ browser_window_set_status(bw, "???");
+ break;
+ }
+
+ return 0;
+}
+
+int browser_window_action(struct browser_window* bw, struct browser_action* act)
+{
+ switch (act->type)
+ {
+ case act_MOUSE_AT:
+ browser_window_follow_link(bw, act->data.mouse.x, act->data.mouse.y, 0);
+ break;
+ case act_MOUSE_CLICK:
+ break;
+ case act_CLEAR_SELECTION:
+ browser_window_text_selection(bw, act->data.mouse.x, act->data.mouse.y, 0);
+ break;
+ case act_START_NEW_SELECTION:
+ browser_window_text_selection(bw, act->data.mouse.x, act->data.mouse.y, 1);
+ break;
+ case act_ALTER_SELECTION:
+ browser_window_text_selection(bw, act->data.mouse.x, act->data.mouse.y, 2);
+ break;
+ case act_FOLLOW_LINK:
+ browser_window_follow_link(bw, act->data.mouse.x, act->data.mouse.y, 1);
+ break;
+ case act_FOLLOW_LINK_NEW_WINDOW:
+ browser_window_follow_link(bw, act->data.mouse.x, act->data.mouse.y, 2);
+ break;
+ default:
+ break;
+ }
+ return 0;
+}
+
+void box_under_area(struct box* box, int x, int y, int ox, int oy,
+ struct box_selection** found, int* count, int* plot_index)
+{
+ struct box* c;
+
+ if (box == NULL)
+ return;
+
+ *plot_index = *plot_index + 1;
+
+ if (x >= box->x + ox && x <= box->x + ox + box->width &&
+ y >= box->y + oy && y <= box->y + oy + box->height)
+ {
+ *found = xrealloc(*found, sizeof(struct box_selection) * (*count + 1));
+ (*found)[*count].box = box;
+ (*found)[*count].actual_x = box->x + ox;
+ (*found)[*count].actual_y = box->y + oy;
+ (*found)[*count].plot_index = *plot_index;
+ *count = *count + 1;
+ }
+
+ for (c = box->children; c != 0; c = c->next)
+ if (c->type != BOX_FLOAT_LEFT && c->type != BOX_FLOAT_RIGHT)
+ box_under_area(c, x, y, box->x + ox, box->y + oy, found, count, plot_index);
+
+ for (c = box->float_children; c != 0; c = c->next_float)
+ box_under_area(c, x, y, box->x + ox, box->y + oy, found, count, plot_index);
+
+ return;
+}
+
+void browser_window_follow_link(struct browser_window* bw,
+ int click_x, int click_y, int click_type)
+{
+ struct box_selection* click_boxes;
+ int found, plot_index;
+ int i;
+ int done = 0;
+
+ found = 0;
+ click_boxes = NULL;
+ plot_index = 0;
+
+ box_under_area(bw->current_content->data.html.layout->children,
+ click_x, click_y, 0, 0, &click_boxes, &found, &plot_index);
+
+ if (found == 0)
+ return;
+
+ for (i = found - 1; i >= 0; i--)
+ {
+ if (click_boxes[i].box->href != NULL)
+ {
+ if (click_type == 1)
+ browser_window_open_location(bw, (char*) click_boxes[i].box->href);
+ else if (click_type == 2)
+ {
+ struct browser_window* bw_new;
+ bw_new = create_browser_window(browser_TITLE | browser_TOOLBAR
+ | browser_SCROLL_X_NONE | browser_SCROLL_Y_ALWAYS, 640, 480);
+ gui_window_show(bw_new->window);
+ if (bw->url != NULL)
+ bw_new->url = xstrdup(bw->url);
+ browser_window_open_location(bw_new, (char*) click_boxes[i].box->href);
+ }
+ else if (click_type == 0)
+ {
+ browser_window_set_status(bw, (char*) click_boxes[i].box->href);
+ done = 1;
+ }
+ i = -1;
+ }
+ }
+
+ if (click_type == 0 && done == 0)
+ browser_window_set_status(bw, "");
+
+ free(click_boxes);
+
+ return;
+}
+
+void browser_window_text_selection(struct browser_window* bw,
+ int click_x, int click_y, int click_type)
+{
+ struct box_selection* click_boxes;
+ int found, plot_index;
+ int i;
+
+ if (click_type == 0 /* click_CLEAR_SELECTION */ )
+ {
+ browser_window_clear_text_selection(bw);
+ return;
+ }
+
+ found = 0;
+ click_boxes = NULL;
+ plot_index = 0;
+
+ box_under_area(bw->current_content->data.html.layout->children,
+ click_x, click_y, 0, 0, &click_boxes, &found, &plot_index);
+
+ if (found == 0)
+ return;
+
+ for (i = found - 1; i >= 0; i--)
+ {
+ if (click_boxes[i].box->type == BOX_INLINE)
+ {
+ struct box_position new_pos;
+ struct box_position* start;
+ struct box_position* end;
+ int click_char_offset, click_pixel_offset;
+
+ /* shortcuts */
+ start = &(bw->current_content->data.html.text_selection.start);
+ end = &(bw->current_content->data.html.text_selection.end);
+
+ font_position_in_string(click_boxes[i].box->text,
+ click_boxes[i].box->style, click_boxes[i].box->length,
+ click_x - click_boxes[i].actual_x,
+ &click_char_offset, &click_pixel_offset);
+
+ new_pos.box = click_boxes[i].box;
+ new_pos.actual_box_x = click_boxes[i].actual_x;
+ new_pos.actual_box_y = click_boxes[i].actual_y;
+ new_pos.plot_index = click_boxes[i].plot_index;
+ new_pos.char_offset = click_char_offset;
+ new_pos.pixel_offset = click_pixel_offset;
+
+ if (click_type == 1 /* click_START_SELECTION */ )
+ {
+ /* update both start and end */
+ browser_window_clear_text_selection(bw);
+ bw->current_content->data.html.text_selection.altering = alter_UNKNOWN;
+ bw->current_content->data.html.text_selection.selected = 1;
+ memcpy(start, &new_pos, sizeof(struct box_position));
+ memcpy(end, &new_pos, sizeof(struct box_position));
+ i = -1;
+ }
+ else if (bw->current_content->data.html.text_selection.selected == 1 &&
+ click_type == 2 /* click_ALTER_SELECTION */)
+ {
+ /* alter selection */
+
+ if (bw->current_content->data.html.text_selection.altering
+ != alter_UNKNOWN)
+ {
+ if (bw->current_content->data.html.text_selection.altering
+ == alter_START)
+ {
+ if (box_position_gt(&new_pos,end))
+ {
+ bw->current_content->data.html.text_selection.altering
+ = alter_END;
+ browser_window_change_text_selection(bw, end, &new_pos);
+ }
+ else
+ browser_window_change_text_selection(bw, &new_pos, end);
+ }
+ else
+ {
+ if (box_position_lt(&new_pos,start))
+ {
+ bw->current_content->data.html.text_selection.altering
+ = alter_START;
+ browser_window_change_text_selection(bw, &new_pos, start);
+ }
+ else
+ browser_window_change_text_selection(bw, start, &new_pos);
+ }
+ i = -1;
+ }
+ else
+ {
+ /* work out whether the start or end is being dragged */
+
+ int click_start_distance = 0;
+ int click_end_distance = 0;
+
+ int inside_block = 0;
+ int before_start = 0;
+ int after_end = 0;
+
+ if (box_position_lt(&new_pos, start))
+ before_start = 1;
+
+ if (box_position_gt(&new_pos, end))
+ after_end = 1;
+
+ if (!box_position_lt(&new_pos, start)
+ && !box_position_gt(&new_pos, end))
+ inside_block = 1;
+
+ if (inside_block == 1)
+ {
+ click_start_distance = box_position_distance(start, &new_pos);
+ click_end_distance = box_position_distance(end, &new_pos);
+ }
+
+ if (before_start == 1
+ || (after_end == 0 && inside_block == 1
+ && click_start_distance < click_end_distance))
+ {
+ /* alter the start position */
+ bw->current_content->data.html.text_selection.altering
+ = alter_START;
+ browser_window_change_text_selection(bw, &new_pos, end);
+ i = -1;
+ }
+ else if (after_end == 1
+ || (before_start == 0 && inside_block == 1
+ && click_start_distance >= click_end_distance))
+ {
+ /* alter the end position */
+ bw->current_content->data.html.text_selection.altering = alter_END;
+ browser_window_change_text_selection(bw, start, &new_pos);
+ i = -1;
+ }
+ }
+ }
+ }
+ }
+
+ free(click_boxes);
+
+ return;
+}
+
+void browser_window_clear_text_selection(struct browser_window* bw)
+{
+ struct box_position* old_start;
+ struct box_position* old_end;
+
+ old_start = &(bw->current_content->data.html.text_selection.start);
+ old_end = &(bw->current_content->data.html.text_selection.end);
+
+ if (bw->current_content->data.html.text_selection.selected == 1)
+ {
+ bw->current_content->data.html.text_selection.selected = 0;
+ browser_window_redraw_boxes(bw, old_start, old_end);
+ }
+
+ bw->current_content->data.html.text_selection.altering = alter_UNKNOWN;
+}
+
+void browser_window_change_text_selection(struct browser_window* bw,
+ struct box_position* new_start, struct box_position* new_end)
+{
+ struct box_position start;
+ struct box_position end;
+
+ memcpy(&start, &(bw->current_content->data.html.text_selection.start), sizeof(struct box_position));
+ memcpy(&end, &(bw->current_content->data.html.text_selection.end), sizeof(struct box_position));
+
+ if (!box_position_eq(new_start, &start))
+ {
+ if (box_position_lt(new_start, &start))
+ browser_window_redraw_boxes(bw, new_start, &start);
+ else
+ browser_window_redraw_boxes(bw, &start, new_start);
+ memcpy(&start, new_start, sizeof(struct box_position));
+ }
+
+ if (!box_position_eq(new_end, &end))
+ {
+ if (box_position_lt(new_end, &end))
+ browser_window_redraw_boxes(bw, new_end, &end);
+ else
+ browser_window_redraw_boxes(bw, &end, new_end);
+ memcpy(&end, new_end, sizeof(struct box_position));
+ }
+
+ memcpy(&(bw->current_content->data.html.text_selection.start), &start, sizeof(struct box_position));
+ memcpy(&(bw->current_content->data.html.text_selection.end), &end, sizeof(struct box_position));
+
+ bw->current_content->data.html.text_selection.selected = 1;
+}
+
+
+int box_position_lt(struct box_position* x, struct box_position* y)
+{
+ return (x->plot_index < y->plot_index ||
+ (x->plot_index == y->plot_index && x->char_offset < y->char_offset));
+}
+
+int box_position_gt(struct box_position* x, struct box_position* y)
+{
+ return (x->plot_index > y->plot_index ||
+ (x->plot_index == y->plot_index && x->char_offset > y->char_offset));
+}
+
+int box_position_eq(struct box_position* x, struct box_position* y)
+{
+ return (x->plot_index == y->plot_index && x->char_offset == y->char_offset);
+}
+
+int box_position_distance(struct box_position* x, struct box_position* y)
+{
+ int dx = (y->actual_box_x + y->pixel_offset)
+ - (x->actual_box_x + x->pixel_offset);
+ int dy = (y->actual_box_y + y->box->height / 2)
+ - (x->actual_box_y + x->box->height / 2);
+ return dx*dx + dy*dy;
+}
+
+int redraw_min_x = INT_MAX;
+int redraw_min_y = INT_MAX;
+int redraw_max_x = INT_MIN;
+int redraw_max_y = INT_MIN;
+
+int redraw_box_list(struct browser_window* bw, struct box* current,
+ int x, int y, struct box_position* start, struct box_position* end,
+ int* plot)
+{
+
+ struct box* c;
+
+ if (current == start->box)
+ *plot = 1;
+
+ if (*plot >= 1 && current->type == BOX_INLINE)
+ {
+ int minx = x + current->x;
+ int miny = y + current->y;
+ int maxx = x + current->x + current->width;
+ int maxy = y + current->y + current->height;
+
+ if (minx < redraw_min_x)
+ redraw_min_x = minx;
+ if (miny < redraw_min_y)
+ redraw_min_y = miny;
+ if (maxx > redraw_max_x)
+ redraw_max_x = maxx;
+ if (maxy > redraw_max_y)
+ redraw_max_y = maxy;
+
+ *plot = 2;
+ }
+
+ if (current == end->box)
+ return 1;
+
+ for (c = current->children; c != 0; c = c->next)
+ if (c->type != BOX_FLOAT_LEFT && c->type != BOX_FLOAT_RIGHT)
+ if (redraw_box_list(bw, c, x + current->x, y + current->y,
+ start, end, plot) == 1)
+ return 1;
+
+ for (c = current->float_children; c != 0; c = c->next_float)
+ if (redraw_box_list(bw, c, x + current->x, y + current->y,
+ start, end, plot) == 1)
+ return 1;
+
+ return 0;
+}
+
+void browser_window_redraw_boxes(struct browser_window* bw, struct box_position* start, struct box_position* end)
+{
+ int plot = 0;
+
+ if (box_position_eq(start, end))
+ return;
+
+ redraw_min_x = INT_MAX;
+ redraw_min_y = INT_MAX;
+ redraw_max_x = INT_MIN;
+ redraw_max_y = INT_MIN;
+
+ redraw_box_list(bw, bw->current_content->data.html.layout,
+ 0,0, start, end, &plot);
+
+ if (plot == 2)
+ gui_window_redraw(bw->window, redraw_min_x, redraw_min_y,
+ redraw_max_x, redraw_max_y);
+}
diff --git a/desktop/browser.h b/desktop/browser.h
new file mode 100644
index 000000000..1e158b3a8
--- /dev/null
+++ b/desktop/browser.h
@@ -0,0 +1,148 @@
+/**
+ * $Id: browser.h,v 1.1 2002/09/11 14:24:02 monkeyson Exp $
+ */
+
+#ifndef _NETSURF_DESKTOP_BROWSER_H_
+#define _NETSURF_DESKTOP_BROWSER_H_
+
+#include "libxml/HTMLparser.h"
+#include "netsurf/render/css.h"
+#include "netsurf/render/box.h"
+#include "netsurf/desktop/gui.h"
+#include "netsurf/desktop/fetch.h"
+
+typedef int browser_window_flags;
+#define browser_TOOLBAR ((browser_window_flags) 1)
+#define browser_TITLE ((browser_window_flags) 2)
+#define browser_SCROLL_X_NONE ((browser_window_flags) 4)
+#define browser_SCROLL_X_AUTO ((browser_window_flags) 8)
+#define browser_SCROLL_X_ALWAYS ((browser_window_flags) 16)
+#define browser_SCROLL_Y_NONE ((browser_window_flags) 32)
+#define browser_SCROLL_Y_AUTO ((browser_window_flags) 64)
+#define browser_SCROLL_Y_ALWAYS ((browser_window_flags) 128)
+
+typedef int action_buttons;
+#define act_BUTTON_NORMAL ((action_buttons) 4)
+#define act_BUTTON_ALTERNATIVE ((action_buttons) 1)
+#define act_BUTTON_CONTEXT_MENU ((action_buttons) 2)
+
+
+
+struct box_position
+{
+ struct box* box;
+ int actual_box_x;
+ int actual_box_y;
+ int plot_index;
+ int pixel_offset;
+ int char_offset;
+};
+
+struct content
+{
+ enum {CONTENT_UNKNOWN, CONTENT_HTML, CONTENT_IMAGE} type;
+
+ union
+ {
+ struct
+ {
+ htmlParserCtxt* parser;
+ xmlDoc* document;
+ xmlNode* markup;
+ struct box* layout;
+ struct css_stylesheet* stylesheet;
+ struct css_style* style;
+ struct {
+ struct box_position start;
+ struct box_position end;
+ enum {alter_UNKNOWN, alter_START, alter_END} altering;
+ int selected; /* 0 = unselected, 1 = selected */
+ } text_selection;
+ } html;
+ } data;
+ struct fetch* main_fetch;
+};
+
+
+struct history
+{
+ struct history* earlier;
+ struct history* later;
+ char* description;
+ char* url;
+};
+
+struct history* history_create(char* desc, char* url);
+void history_remember(struct history* current, char* desc, char* url);
+
+
+struct browser_window
+{
+ int format_width;
+ int format_height;
+ struct { int mult; int div; } scale;
+
+ struct content* current_content;
+ struct content* future_content;
+ struct history* history;
+
+ char* url;
+
+ browser_window_flags flags;
+ char* title;
+ gui_window* window;
+};
+
+
+struct browser_message
+{
+ enum { msg_UNKNOWN,
+ msg_FETCH_SENDING, msg_FETCH_WAITING, msg_FETCH_ABORT,
+ msg_FETCH_FETCH_INFO, msg_FETCH_DATA, msg_FETCH_FINISHED
+ } type;
+ struct fetch* f;
+ union {
+ struct {
+ enum { type_UNKNOWN, type_HTML } type; /* should be a MIME type ? */
+ int total_size; /* -1 == unknown size */
+ } fetch_info;
+ struct {
+ char* block;
+ int block_size;
+ } fetch_data;
+ } data;
+};
+
+
+struct browser_action
+{
+ enum { act_UNKNOWN,
+ act_MOUSE_AT, act_MOUSE_CLICK, act_START_NEW_SELECTION,
+ act_ALTER_SELECTION, act_CLEAR_SELECTION,
+ act_FOLLOW_LINK, act_FOLLOW_LINK_NEW_WINDOW
+ } type;
+ union {
+ struct {
+ int x;
+ int y;
+ action_buttons buttons;
+ } mouse;
+ } data;
+};
+
+/* public functions */
+
+struct browser_window* create_browser_window(int flags, int width, int height);
+void browser_window_destroy(struct browser_window* bw);
+void browser_window_open_location(struct browser_window* bw, char* url);
+int browser_window_message(struct browser_window* bw, struct browser_message* msg);
+int browser_window_action(struct browser_window* bw, struct browser_action* act);
+void browser_window_set_status(struct browser_window* bw, char* text);
+
+int box_position_lt(struct box_position* x, struct box_position* y);
+int box_position_gt(struct box_position* x, struct box_position* y);
+int box_position_eq(struct box_position* x, struct box_position* y);
+int box_position_distance(struct box_position* x, struct box_position* y);
+
+
+#endif
diff --git a/desktop/fetch.c b/desktop/fetch.c
new file mode 100644
index 000000000..a7881fcc2
--- /dev/null
+++ b/desktop/fetch.c
@@ -0,0 +1,344 @@
+/**
+ * $Id: fetch.c,v 1.1 2002/09/11 14:24:02 monkeyson Exp $
+ */
+
+#include "libxml/HTMLparser.h"
+#include "netsurf/render/box.h"
+#include "netsurf/render/css.h"
+#include "netsurf/desktop/browser.h"
+#include "netsurf/desktop/netsurf.h"
+#include "netsurf/desktop/fetch.h"
+#include "netsurf/render/utils.h"
+#include "curl/curl.h"
+#include <time.h>
+#include <string.h>
+#include <stdio.h>
+
+void fetch_identify_location(struct fetch* f, char* location, char* previous)
+{
+ FILE* ff = fopen("identify", "a");
+ fprintf(ff, "identify: '%s' '%s'", location, previous);
+ if (f->location != NULL)
+ fprintf(ff, " '%s'\n", f->location);
+ else
+ fprintf(ff, "\n");
+ fclose(ff);
+
+ if (f->location != NULL)
+ xfree(f->location);
+
+ if (strspn(location, "http://") == strlen("http://"))
+ {
+ f->location = xstrdup(location);
+ f->type = fetch_CURL;
+ return;
+ }
+ else if (strspn(location, "file:/") == strlen("file:/"))
+ {
+ f->location = xstrdup(location);
+ f->type = fetch_FILE;
+ return;
+ }
+ else if (previous != NULL)
+ {
+ char* ext = strrchr(previous, '/');
+
+ if (ext != NULL && ext != previous)
+ {
+ int len = (int)(ext - previous) + strlen(location) + 2;
+ char* combined = xcalloc(len, sizeof(char));
+ strncpy(combined, previous, (int)(ext - previous));
+ strcpy(combined + (ext - previous), "/");
+ strcpy(combined + (ext - previous) + 1, location);
+ fetch_identify_location(f, combined, NULL);
+ xfree(combined);
+ return;
+ }
+ }
+
+ f->location = xcalloc(strlen(location) + strlen("http://") + 1, sizeof(char));
+ sprintf(f->location, "http://%s", location);
+ f->type = fetch_CURL;
+ return;
+}
+
+struct fetch* create_fetch(char* location, char* previous, fetch_flags f, struct fetch_request* r)
+{
+ struct fetch* fetch = (struct fetch*) xcalloc(1, sizeof(struct fetch));
+
+ fetch_identify_location(fetch, location, previous);
+
+ fetch->flags = f;
+
+ fetch->status = fetch_STATUS_WAIT;
+ fetch->bytes_fetched = 0;
+ fetch->bytes_total = -1;
+
+ fetch->request = r;
+
+ fetch->start_time = time(&fetch->start_time);
+
+ fetch->next = netsurf_fetches;
+ netsurf_fetches = fetch;
+
+ return fetch;
+}
+
+void fetch_destroy(struct fetch* f)
+{
+ if (f == NULL)
+ return;
+
+ if (netsurf_fetches == f)
+ netsurf_fetches = f->next;
+ else
+ {
+ struct fetch* ff = netsurf_fetches;
+ while (ff->next != f && ff->next != NULL)
+ ff = ff->next;
+ if (ff->next == f)
+ ff->next = f->next;
+ }
+
+ xfree(f->location);
+ xfree(f->request);
+ xfree(f);
+}
+
+struct fetch* fetch_cancel(struct fetch* f)
+{
+ if (f == NULL)
+ return NULL;
+
+ /* may need to contact server here */
+
+ f->status = fetch_DELETED;
+ /* fetch may not necessarily be destroyed if the cancelling can't be done
+ instantly */
+ return f;
+}
+
+void fetch_receive(struct fetch* f, int amount, char* bytes)
+{
+ struct browser_message msg;
+
+ f->bytes_fetched = f->bytes_fetched + amount;
+
+ switch (f->request->type)
+ {
+ case REQUEST_FROM_BROWSER:
+ msg.type = msg_FETCH_DATA;
+ msg.f = f;
+ msg.data.fetch_data.block = bytes;
+ msg.data.fetch_data.block_size = amount;
+ if (browser_window_message(f->request->requestor.browser, &msg) != 0)
+ {
+ fetch_cancel(f);
+ return;
+ }
+ break;
+ default:
+ break;
+ }
+
+ if (f->bytes_fetched >= f->bytes_total && f->bytes_total != -1)
+ {
+ msg.type = msg_FETCH_FINISHED;
+ msg.f = f;
+ browser_window_message(f->request->requestor.browser, &msg);
+ fetch_destroy(f);
+ }
+
+ return;
+}
+
+size_t fetch_curl_data(void * data, size_t size, size_t nmemb, struct fetch* f)
+{
+ struct browser_message msg;
+ msg.type = msg_FETCH_DATA;
+ msg.f = f;
+ msg.data.fetch_data.block = data;
+ msg.data.fetch_data.block_size = size * nmemb;
+ Log("fetch_poll","sending curl's FETCH_DATA to browser");
+ browser_window_message(f->request->requestor.browser, &msg);
+ return size * nmemb;
+}
+
+struct fetch* fetch_poll(struct fetch* f)
+{
+ struct fetch* ret = f;
+
+ Log("fetch_poll","polling...");
+
+ if (f == NULL)
+ {
+ Log("fetch_poll","null fetch; returning");
+ return f;
+ }
+
+ if (f->type == fetch_DELETED)
+ {
+ ret = f->next;
+ Log("fetch_poll", "deleting marked fetch");
+ fetch_destroy(f);
+ Log("fetch_poll", "moving on...");
+ return fetch_poll(ret);
+ }
+ else if (f->type == fetch_CURL && f->status == fetch_STATUS_WAIT)
+ {
+ struct browser_message msg;
+ CURL* curl;
+
+ Log("fetch_poll","init curl");
+ curl = curl_easy_init();
+ Log("fetch_poll","init curl returned");
+ if (curl != 0)
+ {
+ Log("fetch_poll","init curl OK");
+ /* shouldn't assume this! somehow work it out instead. */
+ msg.type = msg_FETCH_FETCH_INFO;
+ msg.f = f;
+ msg.data.fetch_info.type = type_HTML;
+ msg.data.fetch_info.total_size = -1;
+
+ if (browser_window_message(f->request->requestor.browser, &msg) == 0)
+ {
+ Log("fetch_poll","about to set options");
+ curl_easy_setopt(curl, CURLOPT_URL, f->location);
+ curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, fetch_curl_data);
+ curl_easy_setopt(curl, CURLOPT_WRITEDATA, f);
+ Log("fetch_poll","about to perform");
+ curl_easy_perform(curl);
+ Log("fetch_poll","about to cleanup");
+ curl_easy_cleanup(curl);
+
+ Log("fetch_poll","cleanup finished");
+ msg.type = msg_FETCH_FINISHED;
+ msg.f = f;
+ Log("fetch_poll","sending FETCH_FINISHED to browser");
+ browser_window_message(f->request->requestor.browser, &msg);
+ Log("fetch_poll","FETCH_FINISHED accepted");
+
+ ret = f->next;
+ Log("fetch_poll","Destroying f");
+ fetch_destroy(f);
+ Log("fetch_poll","Moving on...");
+ return fetch_poll(ret);
+ }
+ Log("fetch_poll","about to cleanup since requestor went funny");
+ curl_easy_cleanup(curl);
+
+ Log("fetch_poll","Requesting browser didn't like something");
+ ret = f->next;
+ Log("fetch_poll","Cancelling fetch");
+ f = fetch_cancel(f);
+ return fetch_poll(ret);
+ }
+
+ Log("fetch_poll","we are aborting the mission");
+ msg.type = msg_FETCH_ABORT;
+ msg.f = f;
+ browser_window_message(f->request->requestor.browser, &msg);
+ Log("fetch_poll","ABORT message sent to browser");
+
+ ret = f->next;
+ fetch_destroy(f);
+ return fetch_poll(ret); /* carry on polling */
+ }
+ else if (f->type == fetch_FILE && f->status == fetch_STATUS_WAIT)
+ {
+ struct browser_message msg;
+ char actual_filename[1024];
+ FILE* in;
+
+ gui_file_to_filename(f->location, actual_filename, 1024);
+ in = fopen("files","a");
+ fprintf(in, "%s\n%s\n\n",f->location, actual_filename);
+ fclose(in);
+ in = fopen(actual_filename, "r");
+
+ if (in == NULL)
+ {
+ /* can't open file -- send abort to requestor, then destroy */
+ Log("fetch_poll","can't open file");
+ msg.type = msg_FETCH_ABORT;
+ msg.f = f;
+ browser_window_message(f->request->requestor.browser, &msg);
+ Log("fetch_poll","ABORT message sent to browser");
+
+ ret = f->next;
+ fetch_destroy(f);
+ Log("fetch_poll","destroyed f; moving on");
+
+ return fetch_poll(ret); /* carry on polling */
+ }
+ else
+ {
+ /* file opened successfully. now to send size and type to requestor,
+ then the data, then finish. */
+ int size;
+
+ /* calculate size */
+ Log("fetch_poll","calculating file size");
+ fseek(in, 0, SEEK_END);
+ size = (int) ftell(in);
+ fclose(in);
+
+ /* send file info. (assuming HTML at the mo, but should work out
+ what it is, somehow) */
+ msg.type = msg_FETCH_FETCH_INFO;
+ msg.f = f;
+ msg.data.fetch_info.type = type_HTML;
+ msg.data.fetch_info.total_size = size;
+
+ Log("fetch_poll","sending FETCH_INFO to browser");
+ if (browser_window_message(f->request->requestor.browser, &msg) == 0)
+ {
+ /* file info accepted. can now load the data and send it */
+ Log("fetch_poll","FETCH_INFO accepted");
+ f->status = fetch_STATUS_FETCH;
+
+ /* load and send data */
+ msg.type = msg_FETCH_DATA;
+ msg.f = f;
+ msg.data.fetch_data.block = load(actual_filename);
+ msg.data.fetch_data.block_size = size;
+ Log("fetch_poll","sending FETCH_DATA to browser");
+ if (browser_window_message(f->request->requestor.browser, &msg) == 0)
+ {
+ xfree(msg.data.fetch_data.block);
+ /* data accepted. no more data, so finish */
+ Log("fetch_poll","FETCH_DATA accepted");
+ f->status = fetch_STATUS_FINISH;
+
+ /* send finish */
+ msg.type = msg_FETCH_FINISHED;
+ msg.f = f;
+ Log("fetch_poll","sending FETCH_FINISHED to browser");
+ browser_window_message(f->request->requestor.browser, &msg);
+ Log("fetch_poll","FETCH_FINISHED accepted");
+
+ ret = f->next;
+ Log("fetch_poll","Destroying f");
+ fetch_destroy(f);
+ Log("fetch_poll","Moving on...");
+ return fetch_poll(ret);
+ /* destroy this fetch, then move on to next fetch to poll */
+ }
+ xfree(msg.data.fetch_data.block);
+ }
+
+ /* requestor didn't like something, and wants the fetch cancelled */
+ Log("fetch_poll","Requesting browser didn't like something");
+ ret = f->next;
+ Log("fetch_poll","Cancelling fetch");
+ f = fetch_cancel(f);
+ return fetch_poll(ret);
+ }
+ }
+
+ Log("fetch_poll","Moving on (at end of function with f->next)");
+ f->next = fetch_poll(f->next);
+ return f;
+}
+
diff --git a/desktop/fetch.h b/desktop/fetch.h
new file mode 100644
index 000000000..c0c2c06ac
--- /dev/null
+++ b/desktop/fetch.h
@@ -0,0 +1,49 @@
+/**
+ * $Id: fetch.h,v 1.1 2002/09/11 14:24:02 monkeyson Exp $
+ */
+
+#ifndef _NETSURF_DESKTOP_FETCH_H_
+#define _NETSURF_DESKTOP_FETCH_H_
+
+#include "libxml/HTMLparser.h"
+#include "netsurf/render/box.h"
+#include "netsurf/render/css.h"
+#include "netsurf/desktop/browser.h"
+#include <time.h>
+
+typedef enum {fetch_FILE, fetch_CURL} fetch_type;
+typedef enum {fetch_STATUS_SEND, fetch_STATUS_WAIT, fetch_STATUS_FETCH, fetch_STATUS_FINISH, fetch_DELETED} fetch_status;
+
+typedef int fetch_flags;
+#define fetch_DO_NOT_CHECK_CACHE ((fetch_flags) 1);
+#define fetch_DO_NOT_STORE_IN_CACHE ((fetch_flags) 2);
+
+struct fetch_request {
+ enum {REQUEST_FROM_BROWSER} type;
+ union {struct browser_window* browser;} requestor;
+};
+
+struct fetch
+{
+ char* location;
+ fetch_type type;
+ fetch_flags flags;
+
+ fetch_status status;
+ int bytes_fetched;
+ int bytes_total;
+
+ struct fetch_request* request;
+
+ time_t start_time;
+
+ struct fetch* next;
+};
+
+struct fetch* create_fetch(char* location, char* previous, fetch_flags f, struct fetch_request* r);
+void fetch_destroy(struct fetch* f);
+struct fetch* fetch_cancel(struct fetch* f);
+void fetch_receive(struct fetch* f, int amount, char* bytes);
+struct fetch* fetch_poll(struct fetch* f);
+
+#endif
diff --git a/desktop/gui.h b/desktop/gui.h
new file mode 100644
index 000000000..5d5607065
--- /dev/null
+++ b/desktop/gui.h
@@ -0,0 +1,45 @@
+/**
+ * $Id: gui.h,v 1.1 2002/09/11 14:24:02 monkeyson Exp $
+ */
+
+#ifndef _NETSURF_DESKTOP_GUI_H_
+#define _NETSURF_DESKTOP_GUI_H_
+
+typedef enum { GUI_BROWSER_WINDOW } gui_window_type;
+typedef enum { SAFE, UNSAFE } gui_safety;
+
+#include "netsurf/riscos/gui.h"
+#include "netsurf/desktop/browser.h"
+
+struct gui_message
+{
+ enum { msg_SET_URL } type;
+ union {
+ struct {
+ char* url;
+ } set_url;
+ } data;
+};
+
+typedef struct gui_message gui_message;
+
+gui_window* create_gui_browser_window(struct browser_window* bw);
+void gui_window_destroy(gui_window* g);
+void gui_window_show(gui_window* g);
+void gui_window_hide(gui_window* g);
+void gui_window_redraw(gui_window* g, int x0, int y0, int x1, int y1);
+void gui_window_redraw_window(gui_window* g);
+void gui_window_set_scroll(gui_window* g, int sx, int sy);
+void gui_window_set_extent(gui_window* g, int width, int height);
+void gui_window_set_status(gui_window* g, char* text);
+
+void gui_window_message(gui_window* g, gui_message* msg);
+
+void gui_init(int argc, char** argv);
+void gui_multitask(void);
+void gui_poll(void);
+
+gui_safety gui_window_set_redraw_safety(gui_window* g, gui_safety s);
+int gui_file_to_filename(char* location, char* actual_filename, int size);
+
+#endif
diff --git a/desktop/netsurf.c b/desktop/netsurf.c
new file mode 100644
index 000000000..cc53acc05
--- /dev/null
+++ b/desktop/netsurf.c
@@ -0,0 +1,50 @@
+/**
+ * $Id: netsurf.c,v 1.1 2002/09/11 14:24:02 monkeyson Exp $
+ */
+
+#include "netsurf/desktop/netsurf.h"
+#include "netsurf/desktop/fetch.h"
+#include "netsurf/desktop/browser.h"
+#include "netsurf/desktop/gui.h"
+#include <stdlib.h>
+
+int netsurf_quit = 0;
+gui_window* netsurf_gui_windows = NULL;
+struct fetch* netsurf_fetches = NULL;
+
+
+void netsurf_poll(void)
+{
+ gui_poll();
+ netsurf_fetches = fetch_poll(netsurf_fetches);
+}
+
+
+void netsurf_init(int argc, char** argv)
+{
+ gui_init(argc, argv);
+}
+
+
+int main(int argc, char** argv)
+{
+ netsurf_init(argc, argv);
+
+ while (netsurf_quit == 0)
+ netsurf_poll();
+
+ return 0;
+}
+
+
+void Log(char* func, char* msg)
+{
+#ifdef NETSURF_DUMP
+ FILE* logfile = NULL;
+ logfile = fopen("logfile","a");
+ if (logfile == NULL)
+ die("can't open logfile");
+ fprintf(logfile, "%s: %s\n", func, msg);
+ fclose(logfile);
+#endif
+}
diff --git a/desktop/netsurf.h b/desktop/netsurf.h
new file mode 100644
index 000000000..1ebdf9d88
--- /dev/null
+++ b/desktop/netsurf.h
@@ -0,0 +1,35 @@
+/**
+ * $Id: netsurf.h,v 1.1 2002/09/11 14:24:02 monkeyson Exp $
+ */
+
+#ifndef _NETSURF_DESKTOP_NETSURF_H_
+#define _NETSURF_DESKTOP_NETSURF_H_
+
+#include "netsurf/desktop/fetch.h"
+#include "netsurf/desktop/browser.h"
+
+extern struct fetch* netsurf_fetches;
+extern gui_window* netsurf_gui_windows;
+
+extern int netsurf_quit;
+
+void netsurf_poll(void);
+void Log(char* func, char* msg);
+
+#endif
+
+#ifndef _NETSURF_DESKTOP_NETSURF_H_
+#define _NETSURF_DESKTOP_NETSURF_H_
+
+#include "netsurf/desktop/fetch.h"
+#include "netsurf/desktop/browser.h"
+
+extern struct fetch* netsurf_fetches;
+extern gui_window* netsurf_gui_windows;
+
+extern int netsurf_quit;
+
+void netsurf_poll(void);
+void Log(char* func, char* msg);
+
+#endif