diff options
Diffstat (limited to 'desktop')
-rw-r--r-- | desktop/browser.c | 800 | ||||
-rw-r--r-- | desktop/browser.h | 148 | ||||
-rw-r--r-- | desktop/fetch.c | 344 | ||||
-rw-r--r-- | desktop/fetch.h | 49 | ||||
-rw-r--r-- | desktop/gui.h | 45 | ||||
-rw-r--r-- | desktop/netsurf.c | 50 | ||||
-rw-r--r-- | desktop/netsurf.h | 35 |
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 |