summaryrefslogtreecommitdiff
path: root/render
diff options
context:
space:
mode:
authorVincent Sanders <vince@netsurf-browser.org>2018-05-10 11:34:26 +0100
committerVincent Sanders <vince@kyllikki.org>2018-05-10 13:37:02 +0100
commit2a03ea30490892ac52b3da325ab78e1aa888f83e (patch)
treed041e4a2aab3b224ad41612d47ea2119895e27ac /render
parent1b892391d7859398c212b9fda5b532308fa6e8fd (diff)
downloadnetsurf-2a03ea30490892ac52b3da325ab78e1aa888f83e.tar.gz
netsurf-2a03ea30490892ac52b3da325ab78e1aa888f83e.tar.bz2
move html and text content handlers where they belong
Diffstat (limited to 'render')
-rw-r--r--render/Makefile10
-rw-r--r--render/box.c1242
-rw-r--r--render/box.h368
-rw-r--r--render/box_construct.c3137
-rw-r--r--render/box_normalise.c1046
-rw-r--r--render/box_textarea.c350
-rw-r--r--render/box_textarea.h55
-rw-r--r--render/font.c163
-rw-r--r--render/font.h44
-rw-r--r--render/form.c1895
-rw-r--r--render/form_internal.h277
-rw-r--r--render/html.c2467
-rw-r--r--render/html.h197
-rw-r--r--render/html_css.c713
-rw-r--r--render/html_css_fetcher.c321
-rw-r--r--render/html_forms.c575
-rw-r--r--render/html_interaction.c1434
-rw-r--r--render/html_internal.h410
-rw-r--r--render/html_object.c729
-rw-r--r--render/html_redraw.c1951
-rw-r--r--render/html_redraw_border.c928
-rw-r--r--render/html_script.c603
-rw-r--r--render/imagemap.c801
-rw-r--r--render/imagemap.h37
-rw-r--r--render/layout.c5432
-rw-r--r--render/layout.h45
-rw-r--r--render/search.c656
-rw-r--r--render/search.h81
-rw-r--r--render/table.c1080
-rw-r--r--render/table.h38
-rw-r--r--render/textplain.c1351
-rw-r--r--render/textplain.h139
32 files changed, 0 insertions, 28575 deletions
diff --git a/render/Makefile b/render/Makefile
deleted file mode 100644
index dc2e31c9e..000000000
--- a/render/Makefile
+++ /dev/null
@@ -1,10 +0,0 @@
-# Render sources
-
-S_RENDER := box.c box_construct.c box_normalise.c box_textarea.c \
- font.c form.c imagemap.c layout.c search.c table.c textplain.c \
- html.c html_css.c html_css_fetcher.c html_script.c \
- html_interaction.c html_redraw.c html_redraw_border.c \
- html_forms.c html_object.c
-
-
-S_RENDER := $(addprefix render/,$(S_RENDER))
diff --git a/render/box.c b/render/box.c
deleted file mode 100644
index c97e8982b..000000000
--- a/render/box.c
+++ /dev/null
@@ -1,1242 +0,0 @@
-/*
- * Copyright 2005-2007 James Bursa <bursa@users.sourceforge.net>
- * Copyright 2003 Phil Mellor <monkeyson@users.sourceforge.net>
- * Copyright 2005 John M Bell <jmb202@ecs.soton.ac.uk>
- * Copyright 2008 Michael Drake <tlsa@netsurf-browser.org>
- *
- * This file is part of NetSurf, http://www.netsurf-browser.org/
- *
- * NetSurf is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * NetSurf is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-/**
- * \file
- * implementation of box tree manipulation.
- */
-
-#include <assert.h>
-#include <stdbool.h>
-#include <stdio.h>
-#include <string.h>
-#include <dom/dom.h>
-
-#include "utils/nsoption.h"
-#include "utils/log.h"
-#include "utils/talloc.h"
-#include "netsurf/misc.h"
-#include "netsurf/content.h"
-#include "netsurf/mouse.h"
-#include "css/utils.h"
-#include "css/dump.h"
-#include "desktop/scrollbar.h"
-#include "desktop/gui_internal.h"
-
-#include "render/box.h"
-#include "render/form_internal.h"
-#include "render/html_internal.h"
-
-#define box_is_float(box) (box->type == BOX_FLOAT_LEFT || \
- box->type == BOX_FLOAT_RIGHT)
-
-/**
- * Destructor for box nodes which own styles
- *
- * \param b The box being destroyed.
- * \return 0 to allow talloc to continue destroying the tree.
- */
-static int box_talloc_destructor(struct box *b)
-{
- struct html_scrollbar_data *data;
-
- if ((b->flags & STYLE_OWNED) && b->style != NULL) {
- css_computed_style_destroy(b->style);
- b->style = NULL;
- }
-
- if (b->styles != NULL) {
- css_select_results_destroy(b->styles);
- b->styles = NULL;
- }
-
- if (b->href != NULL)
- nsurl_unref(b->href);
-
- if (b->id != NULL) {
- lwc_string_unref(b->id);
- }
-
- if (b->node != NULL) {
- dom_node_unref(b->node);
- }
-
- if (b->scroll_x != NULL) {
- data = scrollbar_get_data(b->scroll_x);
- scrollbar_destroy(b->scroll_x);
- free(data);
- }
-
- if (b->scroll_y != NULL) {
- data = scrollbar_get_data(b->scroll_y);
- scrollbar_destroy(b->scroll_y);
- free(data);
- }
-
- return 0;
-}
-
-/**
- * Create a box tree node.
- *
- * \param styles selection results for the box, or NULL
- * \param style computed style for the box (not copied), or 0
- * \param style_owned whether style is owned by this box
- * \param href href for the box (copied), or 0
- * \param target target for the box (not copied), or 0
- * \param title title for the box (not copied), or 0
- * \param id id for the box (not copied), or 0
- * \param context context for allocations
- * \return allocated and initialised box, or 0 on memory exhaustion
- *
- * styles is always owned by the box, if it is set.
- * style is only owned by the box in the case of implied boxes.
- */
-
-struct box * box_create(css_select_results *styles, css_computed_style *style,
- bool style_owned, nsurl *href, const char *target,
- const char *title, lwc_string *id, void *context)
-{
- unsigned int i;
- struct box *box;
-
- box = talloc(context, struct box);
- if (!box) {
- return 0;
- }
-
- talloc_set_destructor(box, box_talloc_destructor);
-
- box->type = BOX_INLINE;
- box->flags = 0;
- box->flags = style_owned ? (box->flags | STYLE_OWNED) : box->flags;
- box->styles = styles;
- box->style = style;
- box->x = box->y = 0;
- box->width = UNKNOWN_WIDTH;
- box->height = 0;
- box->descendant_x0 = box->descendant_y0 = 0;
- box->descendant_x1 = box->descendant_y1 = 0;
- for (i = 0; i != 4; i++)
- box->margin[i] = box->padding[i] = box->border[i].width = 0;
- box->scroll_x = box->scroll_y = NULL;
- box->min_width = 0;
- box->max_width = UNKNOWN_MAX_WIDTH;
- box->byte_offset = 0;
- box->text = NULL;
- box->length = 0;
- box->space = 0;
- box->href = (href == NULL) ? NULL : nsurl_ref(href);
- box->target = target;
- box->title = title;
- box->columns = 1;
- box->rows = 1;
- box->start_column = 0;
- box->next = NULL;
- box->prev = NULL;
- box->children = NULL;
- box->last = NULL;
- box->parent = NULL;
- box->inline_end = NULL;
- box->float_children = NULL;
- box->float_container = NULL;
- box->next_float = NULL;
- box->cached_place_below_level = 0;
- box->list_marker = NULL;
- box->col = NULL;
- box->gadget = NULL;
- box->usemap = NULL;
- box->id = id;
- box->background = NULL;
- box->object = NULL;
- box->object_params = NULL;
- box->iframe = NULL;
- box->node = NULL;
-
- return box;
-}
-
-/**
- * Add a child to a box tree node.
- *
- * \param parent box giving birth
- * \param child box to link as last child of parent
- */
-
-void box_add_child(struct box *parent, struct box *child)
-{
- assert(parent);
- assert(child);
-
- if (parent->children != 0) { /* has children already */
- parent->last->next = child;
- child->prev = parent->last;
- } else { /* this is the first child */
- parent->children = child;
- child->prev = 0;
- }
-
- parent->last = child;
- child->parent = parent;
-}
-
-
-/**
- * Insert a new box as a sibling to a box in a tree.
- *
- * \param box box already in tree
- * \param new_box box to link into tree as next sibling
- */
-
-void box_insert_sibling(struct box *box, struct box *new_box)
-{
- new_box->parent = box->parent;
- new_box->prev = box;
- new_box->next = box->next;
- box->next = new_box;
- if (new_box->next)
- new_box->next->prev = new_box;
- else if (new_box->parent)
- new_box->parent->last = new_box;
-}
-
-
-/**
- * Unlink a box from the box tree and then free it recursively.
- *
- * \param box box to unlink and free recursively.
- */
-
-void box_unlink_and_free(struct box *box)
-{
- struct box *parent = box->parent;
- struct box *next = box->next;
- struct box *prev = box->prev;
-
- if (parent) {
- if (parent->children == box)
- parent->children = next;
- if (parent->last == box)
- parent->last = next ? next : prev;
- }
-
- if (prev)
- prev->next = next;
- if (next)
- next->prev = prev;
-
- box_free(box);
-}
-
-
-/**
- * Free a box tree recursively.
- *
- * \param box box to free recursively
- *
- * The box and all its children is freed.
- */
-
-void box_free(struct box *box)
-{
- struct box *child, *next;
-
- /* free children first */
- for (child = box->children; child; child = next) {
- next = child->next;
- box_free(child);
- }
-
- /* last this box */
- box_free_box(box);
-}
-
-
-/**
- * Free the data in a single box structure.
- *
- * \param box box to free
- */
-
-void box_free_box(struct box *box)
-{
- if (!(box->flags & CLONE)) {
- if (box->gadget)
- form_free_control(box->gadget);
- if (box->scroll_x != NULL)
- scrollbar_destroy(box->scroll_x);
- if (box->scroll_y != NULL)
- scrollbar_destroy(box->scroll_y);
- if (box->styles != NULL)
- css_select_results_destroy(box->styles);
- }
-
- talloc_free(box);
-}
-
-
-/**
- * Find the absolute coordinates of a box.
- *
- * \param box the box to calculate coordinates of
- * \param x updated to x coordinate
- * \param y updated to y coordinate
- */
-
-void box_coords(struct box *box, int *x, int *y)
-{
- *x = box->x;
- *y = box->y;
- while (box->parent) {
- if (box_is_float(box)) {
- do {
- box = box->parent;
- } while (!box->float_children);
- } else
- box = box->parent;
- *x += box->x - scrollbar_get_offset(box->scroll_x);
- *y += box->y - scrollbar_get_offset(box->scroll_y);
- }
-}
-
-
-/**
- * Find the bounds of a box.
- *
- * \param box the box to calculate bounds of
- * \param r receives bounds
- */
-
-void box_bounds(struct box *box, struct rect *r)
-{
- int width, height;
-
- box_coords(box, &r->x0, &r->y0);
-
- width = box->padding[LEFT] + box->width + box->padding[RIGHT];
- height = box->padding[TOP] + box->height + box->padding[BOTTOM];
-
- r->x1 = r->x0 + width;
- r->y1 = r->y0 + height;
-}
-
-
-/**
- * Determine if a point lies within a box.
- *
- * \param[in] len_ctx CSS length conversion context to use.
- * \param[in] box Box to consider
- * \param[in] x Coordinate relative to box
- * \param[in] y Coordinate relative to box
- * \param[out] physically If function returning true, physically is set true
- * iff point is within the box's physical dimensions and
- * false if the point is not within the box's physical
- * dimensions but is in the area defined by the box's
- * descendants. If function returns false, physically
- * is undefined.
- * \return true if the point is within the box or a descendant box
- *
- * This is a helper function for box_at_point().
- */
-
-static bool box_contains_point(
- const nscss_len_ctx *len_ctx,
- const struct box *box,
- int x,
- int y,
- bool *physically)
-{
- css_computed_clip_rect css_rect;
-
- if (box->style != NULL &&
- css_computed_position(box->style) ==
- CSS_POSITION_ABSOLUTE &&
- css_computed_clip(box->style, &css_rect) ==
- CSS_CLIP_RECT) {
- /* We have an absolutly positioned box with a clip rect */
- struct rect r = {
- .x0 = box->border[LEFT].width,
- .y0 = box->border[TOP].width,
- .x1 = box->padding[LEFT] + box->width +
- box->border[RIGHT].width +
- box->padding[RIGHT],
- .y1 = box->padding[TOP] + box->height +
- box->border[BOTTOM].width +
- box->padding[BOTTOM]
- };
- if (x >= r.x0 && x < r.x1 && y >= r.y0 && y < r.y1)
- *physically = true;
- else
- *physically = false;
-
- /* Adjust rect to css clip region */
- if (css_rect.left_auto == false) {
- r.x0 += FIXTOINT(nscss_len2px(len_ctx,
- css_rect.left, css_rect.lunit,
- box->style));
- }
- if (css_rect.top_auto == false) {
- r.y0 += FIXTOINT(nscss_len2px(len_ctx,
- css_rect.top, css_rect.tunit,
- box->style));
- }
- if (css_rect.right_auto == false) {
- r.x1 = box->border[LEFT].width +
- FIXTOINT(nscss_len2px(len_ctx,
- css_rect.right,
- css_rect.runit,
- box->style));
- }
- if (css_rect.bottom_auto == false) {
- r.y1 = box->border[TOP].width +
- FIXTOINT(nscss_len2px(len_ctx,
- css_rect.bottom,
- css_rect.bunit,
- box->style));
- }
-
- /* Test if point is in clipped box */
- if (x >= r.x0 && x < r.x1 && y >= r.y0 && y < r.y1) {
- /* inside clip area */
- return true;
- }
-
- /* Not inside clip area */
- return false;
- }
- if (x >= -box->border[LEFT].width &&
- x < box->padding[LEFT] + box->width +
- box->padding[RIGHT] + box->border[RIGHT].width &&
- y >= -box->border[TOP].width &&
- y < box->padding[TOP] + box->height +
- box->padding[BOTTOM] + box->border[BOTTOM].width) {
- *physically = true;
- return true;
- }
- if (box->list_marker && box->list_marker->x - box->x <= x +
- box->list_marker->border[LEFT].width &&
- x < box->list_marker->x - box->x +
- box->list_marker->padding[LEFT] +
- box->list_marker->width +
- box->list_marker->border[RIGHT].width +
- box->list_marker->padding[RIGHT] &&
- box->list_marker->y - box->y <= y +
- box->list_marker->border[TOP].width &&
- y < box->list_marker->y - box->y +
- box->list_marker->padding[TOP] +
- box->list_marker->height +
- box->list_marker->border[BOTTOM].width +
- box->list_marker->padding[BOTTOM]) {
- *physically = true;
- return true;
- }
- if ((box->style && css_computed_overflow_x(box->style) ==
- CSS_OVERFLOW_VISIBLE) || !box->style) {
- if (box->descendant_x0 <= x &&
- x < box->descendant_x1) {
- *physically = false;
- return true;
- }
- }
- if ((box->style && css_computed_overflow_y(box->style) ==
- CSS_OVERFLOW_VISIBLE) || !box->style) {
- if (box->descendant_y0 <= y &&
- y < box->descendant_y1) {
- *physically = false;
- return true;
- }
- }
- return false;
-}
-
-
-/** Direction to move in a box-tree walk */
-enum box_walk_dir {
- BOX_WALK_CHILDREN,
- BOX_WALK_PARENT,
- BOX_WALK_NEXT_SIBLING,
- BOX_WALK_FLOAT_CHILDREN,
- BOX_WALK_NEXT_FLOAT_SIBLING,
- BOX_WALK_FLOAT_CONTAINER
-};
-
-
-/**
- * Move from box to next box in given direction, adjusting for box coord change
- *
- * \param b box to move from from
- * \param dir direction to move in
- * \param x box's global x-coord, updated to position of next box
- * \param y box's global y-coord, updated to position of next box
- *
- * If no box can be found in given direction, NULL is returned.
- */
-static inline struct box *box_move_xy(struct box *b, enum box_walk_dir dir,
- int *x, int *y)
-{
- struct box *rb = NULL;
-
- switch (dir) {
- case BOX_WALK_CHILDREN:
- b = b->children;
- if (b == NULL)
- break;
- *x += b->x;
- *y += b->y;
- if (!box_is_float(b)) {
- rb = b;
- break;
- }
- /* Fall through */
-
- case BOX_WALK_NEXT_SIBLING:
- do {
- *x -= b->x;
- *y -= b->y;
- b = b->next;
- if (b == NULL)
- break;
- *x += b->x;
- *y += b->y;
- } while (box_is_float(b));
- rb = b;
- break;
-
- case BOX_WALK_PARENT:
- *x -= b->x;
- *y -= b->y;
- rb = b->parent;
- break;
-
- case BOX_WALK_FLOAT_CHILDREN:
- b = b->float_children;
- if (b == NULL)
- break;
- *x += b->x;
- *y += b->y;
- rb = b;
- break;
-
- case BOX_WALK_NEXT_FLOAT_SIBLING:
- *x -= b->x;
- *y -= b->y;
- b = b->next_float;
- if (b == NULL)
- break;
- *x += b->x;
- *y += b->y;
- rb = b;
- break;
-
- case BOX_WALK_FLOAT_CONTAINER:
- *x -= b->x;
- *y -= b->y;
- rb = b->float_container;
- break;
-
- default:
- assert(0 && "Bad box walk type.");
- }
-
- return rb;
-}
-
-
-/**
- * Itterator for walking to next box in interaction order
- *
- * \param b box to find next box from
- * \param x box's global x-coord, updated to position of next box
- * \param y box's global y-coord, updated to position of next box
- * \param skip_children whether to skip box's children
- *
- * This walks to a boxes float children before its children. When walking
- * children, floating boxes are skipped.
- */
-static inline struct box *box_next_xy(struct box *b, int *x, int *y,
- bool skip_children)
-{
- struct box *n;
- int tx, ty;
-
- assert(b != NULL);
-
- if (skip_children) {
- /* Caller is not interested in any kind of children */
- goto skip_children;
- }
-
- tx = *x; ty = *y;
- n = box_move_xy(b, BOX_WALK_FLOAT_CHILDREN, &tx, &ty);
- if (n) {
- /* Next node is float child */
- *x = tx;
- *y = ty;
- return n;
- }
-done_float_children:
-
- tx = *x; ty = *y;
- n = box_move_xy(b, BOX_WALK_CHILDREN, &tx, &ty);
- if (n) {
- /* Next node is child */
- *x = tx;
- *y = ty;
- return n;
- }
-
-skip_children:
- tx = *x; ty = *y;
- n = box_move_xy(b, BOX_WALK_NEXT_FLOAT_SIBLING, &tx, &ty);
- if (n) {
- /* Go to next float sibling */
- *x = tx;
- *y = ty;
- return n;
- }
-
- if (box_is_float(b)) {
- /* Done floats, but the float container may have children,
- * or siblings, or ansestors with siblings. Change to
- * float container and move past handling its float children.
- */
- b = box_move_xy(b, BOX_WALK_FLOAT_CONTAINER, x, y);
- goto done_float_children;
- }
-
- /* Go to next sibling, or nearest ancestor with next sibling. */
- while (b) {
- while (!b->next && b->parent) {
- b = box_move_xy(b, BOX_WALK_PARENT, x, y);
- if (box_is_float(b)) {
- /* Go on to next float, if there is one */
- goto skip_children;
- }
- }
- if (!b->next) {
- /* No more boxes */
- return NULL;
- }
-
- tx = *x; ty = *y;
- n = box_move_xy(b, BOX_WALK_NEXT_SIBLING, &tx, &ty);
- if (n) {
- /* Go to non-float (ancestor) sibling */
- *x = tx;
- *y = ty;
- return n;
-
- } else if (b->parent) {
- b = box_move_xy(b, BOX_WALK_PARENT, x, y);
- if (box_is_float(b)) {
- /* Go on to next float, if there is one */
- goto skip_children;
- }
-
- } else {
- /* No more boxes */
- return NULL;
- }
- }
-
- assert(b != NULL);
- return NULL;
-}
-
-
-
-/**
- * Find the boxes at a point.
- *
- * \param len_ctx CSS length conversion context for document.
- * \param box box to search children of
- * \param x point to find, in global document coordinates
- * \param y point to find, in global document coordinates
- * \param box_x position of box, in global document coordinates, updated
- * to position of returned box, if any
- * \param box_y position of box, in global document coordinates, updated
- * to position of returned box, if any
- * \return box at given point, or 0 if none found
- *
- * To find all the boxes in the hierarchy at a certain point, use code like
- * this:
- * \code
- * struct box *box = top_of_document_to_search;
- * int box_x = 0, box_y = 0;
- *
- * while ((box = box_at_point(len_ctx, box, x, y, &box_x, &box_y))) {
- * // process box
- * }
- * \endcode
- */
-
-struct box *box_at_point(const nscss_len_ctx *len_ctx,
- struct box *box, const int x, const int y,
- int *box_x, int *box_y)
-{
- bool skip_children;
- bool physically;
-
- assert(box);
-
- skip_children = false;
- while ((box = box_next_xy(box, box_x, box_y, skip_children))) {
- if (box_contains_point(len_ctx, box, x - *box_x, y - *box_y,
- &physically)) {
- *box_x -= scrollbar_get_offset(box->scroll_x);
- *box_y -= scrollbar_get_offset(box->scroll_y);
-
- if (physically)
- return box;
-
- skip_children = false;
- } else {
- skip_children = true;
- }
- }
-
- return NULL;
-}
-
-
-/**
- * Check whether box is nearer mouse coordinates than current nearest box
- *
- * \param box box to test
- * \param bx position of box, in global document coordinates
- * \param by position of box, in global document coordinates
- * \param x mouse point, in global document coordinates
- * \param y mouse point, in global document coordinates
- * \param dir direction in which to search (-1 = above-left,
- * +1 = below-right)
- * \param nearest nearest text box found, or NULL if none
- * updated if box is nearer than existing nearest
- * \param tx position of text_box, in global document coordinates
- * updated if box is nearer than existing nearest
- * \param ty position of text_box, in global document coordinates
- * updated if box is nearer than existing nearest
- * \param nr_xd distance to nearest text box found
- * updated if box is nearer than existing nearest
- * \param nr_yd distance to nearest text box found
- * updated if box is nearer than existing nearest
- * \return true if mouse point is inside box
- */
-
-static bool box_nearer_text_box(struct box *box, int bx, int by,
- int x, int y, int dir, struct box **nearest, int *tx, int *ty,
- int *nr_xd, int *nr_yd)
-{
- int w = box->padding[LEFT] + box->width + box->padding[RIGHT];
- int h = box->padding[TOP] + box->height + box->padding[BOTTOM];
- int y1 = by + h;
- int x1 = bx + w;
- int yd = INT_MAX;
- int xd = INT_MAX;
-
- if (x >= bx && x1 > x && y >= by && y1 > y) {
- *nearest = box;
- *tx = bx;
- *ty = by;
- return true;
- }
-
- if (box->parent->list_marker != box) {
- if (dir < 0) {
- /* consider only those children (partly) above-left */
- if (by <= y && bx < x) {
- yd = y <= y1 ? 0 : y - y1;
- xd = x <= x1 ? 0 : x - x1;
- }
- } else {
- /* consider only those children (partly) below-right */
- if (y1 > y && x1 > x) {
- yd = y > by ? 0 : by - y;
- xd = x > bx ? 0 : bx - x;
- }
- }
-
- /* give y displacement precedence over x */
- if (yd < *nr_yd || (yd == *nr_yd && xd <= *nr_xd)) {
- *nr_yd = yd;
- *nr_xd = xd;
- *nearest = box;
- *tx = bx;
- *ty = by;
- }
- }
- return false;
-}
-
-
-/**
- * Pick the text box child of 'box' that is closest to and above-left
- * (dir -ve) or below-right (dir +ve) of the point 'x,y'
- *
- * \param box parent box
- * \param bx position of box, in global document coordinates
- * \param by position of box, in global document coordinates
- * \param fx position of float parent, in global document coordinates
- * \param fy position of float parent, in global document coordinates
- * \param x mouse point, in global document coordinates
- * \param y mouse point, in global document coordinates
- * \param dir direction in which to search (-1 = above-left,
- * +1 = below-right)
- * \param nearest nearest text box found, or NULL if none
- * updated if a descendant of box is nearer than old nearest
- * \param tx position of nearest, in global document coordinates
- * updated if a descendant of box is nearer than old nearest
- * \param ty position of nearest, in global document coordinates
- * updated if a descendant of box is nearer than old nearest
- * \param nr_xd distance to nearest text box found
- * updated if a descendant of box is nearer than old nearest
- * \param nr_yd distance to nearest text box found
- * updated if a descendant of box is nearer than old nearest
- * \return true if mouse point is inside text_box
- */
-
-static bool box_nearest_text_box(struct box *box, int bx, int by,
- int fx, int fy, int x, int y, int dir, struct box **nearest,
- int *tx, int *ty, int *nr_xd, int *nr_yd)
-{
- struct box *child = box->children;
- int c_bx, c_by;
- int c_fx, c_fy;
- bool in_box = false;
-
- if (*nearest == NULL) {
- *nr_xd = INT_MAX / 2; /* displacement of 'nearest so far' */
- *nr_yd = INT_MAX / 2;
- }
- if (box->type == BOX_INLINE_CONTAINER) {
- int bw = box->padding[LEFT] + box->width + box->padding[RIGHT];
- int bh = box->padding[TOP] + box->height + box->padding[BOTTOM];
- int b_y1 = by + bh;
- int b_x1 = bx + bw;
- if (x >= bx && b_x1 > x && y >= by && b_y1 > y) {
- in_box = true;
- }
- }
-
- while (child) {
- if (child->type == BOX_FLOAT_LEFT ||
- child->type == BOX_FLOAT_RIGHT) {
- c_bx = fx + child->x -
- scrollbar_get_offset(child->scroll_x);
- c_by = fy + child->y -
- scrollbar_get_offset(child->scroll_y);
- } else {
- c_bx = bx + child->x -
- scrollbar_get_offset(child->scroll_x);
- c_by = by + child->y -
- scrollbar_get_offset(child->scroll_y);
- }
- if (child->float_children) {
- c_fx = c_bx;
- c_fy = c_by;
- } else {
- c_fx = fx;
- c_fy = fy;
- }
- if (in_box && child->text && !child->object) {
- if (box_nearer_text_box(child,
- c_bx, c_by, x, y, dir, nearest,
- tx, ty, nr_xd, nr_yd))
- return true;
- } else {
- if (child->list_marker) {
- if (box_nearer_text_box(
- child->list_marker,
- c_bx + child->list_marker->x,
- c_by + child->list_marker->y,
- x, y, dir, nearest,
- tx, ty, nr_xd, nr_yd))
- return true;
- }
- if (box_nearest_text_box(child, c_bx, c_by,
- c_fx, c_fy, x, y, dir, nearest, tx, ty,
- nr_xd, nr_yd))
- return true;
- }
- child = child->next;
- }
-
- return false;
-}
-
-
-/**
- * Peform pick text on browser window contents to locate the box under
- * the mouse pointer, or nearest in the given direction if the pointer is
- * not over a text box.
- *
- * \param html an HTML content
- * \param x coordinate of mouse
- * \param y coordinate of mouse
- * \param dir direction to search (-1 = above-left, +1 = below-right)
- * \param dx receives x ordinate of mouse relative to text box
- * \param dy receives y ordinate of mouse relative to text box
- */
-
-struct box *box_pick_text_box(struct html_content *html,
- int x, int y, int dir, int *dx, int *dy)
-{
- struct box *text_box = NULL;
- struct box *box;
- int nr_xd, nr_yd;
- int bx, by;
- int fx, fy;
- int tx, ty;
-
- if (html == NULL)
- return NULL;
-
- box = html->layout;
- bx = box->margin[LEFT];
- by = box->margin[TOP];
- fx = bx;
- fy = by;
-
- if (!box_nearest_text_box(box, bx, by, fx, fy, x, y,
- dir, &text_box, &tx, &ty, &nr_xd, &nr_yd)) {
- if (text_box && text_box->text && !text_box->object) {
- int w = (text_box->padding[LEFT] +
- text_box->width +
- text_box->padding[RIGHT]);
- int h = (text_box->padding[TOP] +
- text_box->height +
- text_box->padding[BOTTOM]);
- int x1, y1;
-
- y1 = ty + h;
- x1 = tx + w;
-
- /* ensure point lies within the text box */
- if (x < tx) x = tx;
- if (y < ty) y = ty;
- if (y > y1) y = y1;
- if (x > x1) x = x1;
- }
- }
-
- /* return coordinates relative to box */
- *dx = x - tx;
- *dy = y - ty;
-
- return text_box;
-}
-
-
-/**
- * Find a box based upon its id attribute.
- *
- * \param box box tree to search
- * \param id id to look for
- * \return the box or 0 if not found
- */
-
-struct box *box_find_by_id(struct box *box, lwc_string *id)
-{
- struct box *a, *b;
- bool m;
-
- if (box->id != NULL &&
- lwc_string_isequal(id, box->id, &m) == lwc_error_ok &&
- m == true)
- return box;
-
- for (a = box->children; a; a = a->next) {
- if ((b = box_find_by_id(a, id)) != NULL)
- return b;
- }
-
- return NULL;
-}
-
-
-/**
- * Determine if a box is visible when the tree is rendered.
- *
- * \param box box to check
- * \return true iff the box is rendered
- */
-
-bool box_visible(struct box *box)
-{
- /* visibility: hidden */
- if (box->style && css_computed_visibility(box->style) ==
- CSS_VISIBILITY_HIDDEN)
- return false;
-
- return true;
-}
-
-
-/**
- * Print a box tree to a file.
- */
-
-void box_dump(FILE *stream, struct box *box, unsigned int depth, bool style)
-{
- unsigned int i;
- struct box *c, *prev;
-
- for (i = 0; i != depth; i++)
- fprintf(stream, " ");
-
- fprintf(stream, "%p ", box);
- fprintf(stream, "x%i y%i w%i h%i ", box->x, box->y,
- box->width, box->height);
- if (box->max_width != UNKNOWN_MAX_WIDTH)
- fprintf(stream, "min%i max%i ", box->min_width, box->max_width);
- fprintf(stream, "(%i %i %i %i) ",
- box->descendant_x0, box->descendant_y0,
- box->descendant_x1, box->descendant_y1);
-
- fprintf(stream, "m(%i %i %i %i) ",
- box->margin[TOP], box->margin[LEFT],
- box->margin[BOTTOM], box->margin[RIGHT]);
-
- switch (box->type) {
- case BOX_BLOCK: fprintf(stream, "BLOCK "); break;
- case BOX_INLINE_CONTAINER: fprintf(stream, "INLINE_CONTAINER "); break;
- case BOX_INLINE: fprintf(stream, "INLINE "); break;
- case BOX_INLINE_END: fprintf(stream, "INLINE_END "); break;
- case BOX_INLINE_BLOCK: fprintf(stream, "INLINE_BLOCK "); break;
- case BOX_TABLE: fprintf(stream, "TABLE [columns %i] ",
- box->columns); break;
- case BOX_TABLE_ROW: fprintf(stream, "TABLE_ROW "); break;
- case BOX_TABLE_CELL: fprintf(stream, "TABLE_CELL [columns %i, "
- "start %i, rows %i] ", box->columns,
- box->start_column, box->rows); break;
- case BOX_TABLE_ROW_GROUP: fprintf(stream, "TABLE_ROW_GROUP "); break;
- case BOX_FLOAT_LEFT: fprintf(stream, "FLOAT_LEFT "); break;
- case BOX_FLOAT_RIGHT: fprintf(stream, "FLOAT_RIGHT "); break;
- case BOX_BR: fprintf(stream, "BR "); break;
- case BOX_TEXT: fprintf(stream, "TEXT "); break;
- default: fprintf(stream, "Unknown box type ");
- }
-
- if (box->text)
- fprintf(stream, "%li '%.*s' ", (unsigned long) box->byte_offset,
- (int) box->length, box->text);
- if (box->space)
- fprintf(stream, "space ");
- if (box->object) {
- fprintf(stream, "(object '%s') ",
- nsurl_access(hlcache_handle_get_url(box->object)));
- }
- if (box->iframe) {
- fprintf(stream, "(iframe) ");
- }
- if (box->gadget)
- fprintf(stream, "(gadget) ");
- if (style && box->style)
- nscss_dump_computed_style(stream, box->style);
- if (box->href)
- fprintf(stream, " -> '%s'", nsurl_access(box->href));
- if (box->target)
- fprintf(stream, " |%s|", box->target);
- if (box->title)
- fprintf(stream, " [%s]", box->title);
- if (box->id)
- fprintf(stream, " ID:%s", lwc_string_data(box->id));
- if (box->type == BOX_INLINE || box->type == BOX_INLINE_END)
- fprintf(stream, " inline_end %p", box->inline_end);
- if (box->float_children)
- fprintf(stream, " float_children %p", box->float_children);
- if (box->next_float)
- fprintf(stream, " next_float %p", box->next_float);
- if (box->float_container)
- fprintf(stream, " float_container %p", box->float_container);
- if (box->col) {
- fprintf(stream, " (columns");
- for (i = 0; i != box->columns; i++)
- fprintf(stream, " (%s %s %i %i %i)",
- ((const char *[]) {"UNKNOWN", "FIXED",
- "AUTO", "PERCENT", "RELATIVE"})
- [box->col[i].type],
- ((const char *[]) {"normal",
- "positioned"})
- [box->col[i].positioned],
- box->col[i].width,
- box->col[i].min, box->col[i].max);
- fprintf(stream, ")");
- }
- if (box->node != NULL) {
- dom_string *name;
- if (dom_node_get_node_name(box->node, &name) == DOM_NO_ERR) {
- fprintf(stream, " <%s>", dom_string_data(name));
- dom_string_unref(name);
- }
- }
- fprintf(stream, "\n");
-
- if (box->list_marker) {
- for (i = 0; i != depth; i++)
- fprintf(stream, " ");
- fprintf(stream, "list_marker:\n");
- box_dump(stream, box->list_marker, depth + 1, style);
- }
-
- for (c = box->children; c && c->next; c = c->next)
- ;
- if (box->last != c)
- fprintf(stream, "warning: box->last %p (should be %p) "
- "(box %p)\n", box->last, c, box);
- for (prev = 0, c = box->children; c; prev = c, c = c->next) {
- if (c->parent != box)
- fprintf(stream, "warning: box->parent %p (should be "
- "%p) (box on next line)\n",
- c->parent, box);
- if (c->prev != prev)
- fprintf(stream, "warning: box->prev %p (should be "
- "%p) (box on next line)\n",
- c->prev, prev);
- box_dump(stream, c, depth + 1, style);
- }
-}
-
-/**
- * Applies the given scroll setup to a box. This includes scroll
- * creation/deletion as well as scroll dimension updates.
- *
- * \param c content in which the box is located
- * \param box the box to handle the scrolls for
- * \param bottom whether the horizontal scrollbar should be present
- * \param right whether the vertical scrollbar should be present
- * \return true on success false otherwise
- */
-bool box_handle_scrollbars(struct content *c, struct box *box,
- bool bottom, bool right)
-{
- struct html_scrollbar_data *data;
- int visible_width, visible_height;
- int full_width, full_height;
-
- if (!bottom && box->scroll_x != NULL) {
- data = scrollbar_get_data(box->scroll_x);
- scrollbar_destroy(box->scroll_x);
- free(data);
- box->scroll_x = NULL;
- }
-
- if (!right && box->scroll_y != NULL) {
- data = scrollbar_get_data(box->scroll_y);
- scrollbar_destroy(box->scroll_y);
- free(data);
- box->scroll_y = NULL;
- }
-
- if (!bottom && !right)
- return true;
-
- visible_width = box->width + box->padding[RIGHT] + box->padding[LEFT];
- visible_height = box->height + box->padding[TOP] + box->padding[BOTTOM];
-
- full_width = ((box->descendant_x1 - box->border[RIGHT].width) >
- visible_width) ?
- box->descendant_x1 + box->padding[RIGHT] :
- visible_width;
- full_height = ((box->descendant_y1 - box->border[BOTTOM].width) >
- visible_height) ?
- box->descendant_y1 + box->padding[BOTTOM] :
- visible_height;
-
- if (right) {
- if (box->scroll_y == NULL) {
- data = malloc(sizeof(struct html_scrollbar_data));
- if (data == NULL) {
- NSLOG(netsurf, INFO, "malloc failed");
- guit->misc->warning("NoMemory", 0);
- return false;
- }
- data->c = c;
- data->box = box;
- if (scrollbar_create(false, visible_height,
- full_height, visible_height,
- data, html_overflow_scroll_callback,
- &(box->scroll_y)) != NSERROR_OK) {
- return false;
- }
- } else {
- scrollbar_set_extents(box->scroll_y, visible_height,
- visible_height, full_height);
- }
- }
- if (bottom) {
- if (box->scroll_x == NULL) {
- data = malloc(sizeof(struct html_scrollbar_data));
- if (data == NULL) {
- NSLOG(netsurf, INFO, "malloc failed");
- guit->misc->warning("NoMemory", 0);
- return false;
- }
- data->c = c;
- data->box = box;
- if (scrollbar_create(true,
- visible_width -
- (right ? SCROLLBAR_WIDTH : 0),
- full_width, visible_width,
- data, html_overflow_scroll_callback,
- &box->scroll_x) != NSERROR_OK) {
- return false;
- }
- } else {
- scrollbar_set_extents(box->scroll_x,
- visible_width -
- (right ? SCROLLBAR_WIDTH : 0),
- visible_width, full_width);
- }
- }
-
- if (right && bottom)
- scrollbar_make_pair(box->scroll_x, box->scroll_y);
-
- return true;
-}
-
-/**
- * Determine if a box has a vertical scrollbar.
- *
- * \param box scrolling box
- * \return the box has a vertical scrollbar
- */
-
-bool box_vscrollbar_present(const struct box * const box)
-{
- return box->padding[TOP] + box->height + box->padding[BOTTOM] +
- box->border[BOTTOM].width < box->descendant_y1;
-}
-
-
-/**
- * Determine if a box has a horizontal scrollbar.
- *
- * \param box scrolling box
- * \return the box has a horizontal scrollbar
- */
-
-bool box_hscrollbar_present(const struct box * const box)
-{
- return box->padding[LEFT] + box->width + box->padding[RIGHT] +
- box->border[RIGHT].width < box->descendant_x1;
-}
-
diff --git a/render/box.h b/render/box.h
deleted file mode 100644
index 1af0a8b73..000000000
--- a/render/box.h
+++ /dev/null
@@ -1,368 +0,0 @@
-/*
- * Copyright 2005 James Bursa <bursa@users.sourceforge.net>
- * Copyright 2003 Phil Mellor <monkeyson@users.sourceforge.net>
- *
- * This file is part of NetSurf, http://www.netsurf-browser.org/
- *
- * NetSurf is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * NetSurf is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-/** \file
- * Box tree construction and manipulation (interface).
- *
- * This stage of rendering converts a tree of dom_nodes (produced by libdom)
- * to a tree of struct box. The box tree represents the structure of the
- * document as given by the CSS display and float properties.
- *
- * For example, consider the following HTML:
- * \code
- * <h1>Example Heading</h1>
- * <p>Example paragraph <em>with emphasised text</em> etc.</p> \endcode
- *
- * This would produce approximately the following box tree with default CSS
- * rules:
- * \code
- * BOX_BLOCK (corresponds to h1)
- * BOX_INLINE_CONTAINER
- * BOX_INLINE "Example Heading"
- * BOX_BLOCK (p)
- * BOX_INLINE_CONTAINER
- * BOX_INLINE "Example paragraph "
- * BOX_INLINE "with emphasised text" (em)
- * BOX_INLINE "etc." \endcode
- *
- * Note that the em has been collapsed into the INLINE_CONTAINER.
- *
- * If these CSS rules were applied:
- * \code
- * h1 { display: table-cell }
- * p { display: table-cell }
- * em { float: left; width: 5em } \endcode
- *
- * then the box tree would instead look like this:
- * \code
- * BOX_TABLE
- * BOX_TABLE_ROW_GROUP
- * BOX_TABLE_ROW
- * BOX_TABLE_CELL (h1)
- * BOX_INLINE_CONTAINER
- * BOX_INLINE "Example Heading"
- * BOX_TABLE_CELL (p)
- * BOX_INLINE_CONTAINER
- * BOX_INLINE "Example paragraph "
- * BOX_FLOAT_LEFT (em)
- * BOX_BLOCK
- * BOX_INLINE_CONTAINER
- * BOX_INLINE "with emphasised text"
- * BOX_INLINE "etc." \endcode
- *
- * Here implied boxes have been added and a float is present.
- *
- * A box tree is "normalized" if the following is satisfied:
- * \code
- * parent permitted child nodes
- * BLOCK, INLINE_BLOCK BLOCK, INLINE_CONTAINER, TABLE
- * INLINE_CONTAINER INLINE, INLINE_BLOCK, FLOAT_LEFT, FLOAT_RIGHT, BR, TEXT,
- * INLINE_END
- * INLINE none
- * TABLE at least 1 TABLE_ROW_GROUP
- * TABLE_ROW_GROUP at least 1 TABLE_ROW
- * TABLE_ROW at least 1 TABLE_CELL
- * TABLE_CELL BLOCK, INLINE_CONTAINER, TABLE (same as BLOCK)
- * FLOAT_(LEFT|RIGHT) exactly 1 BLOCK or TABLE
- * \endcode
- */
-
-#ifndef _NETSURF_RENDER_BOX_H_
-#define _NETSURF_RENDER_BOX_H_
-
-#include <limits.h>
-#include <stdbool.h>
-#include <stdio.h>
-#include <libcss/libcss.h>
-
-#include "content/handlers/css/utils.h"
-
-struct content;
-struct box;
-struct browser_window;
-struct column;
-struct object_params;
-struct object_param;
-struct html_content;
-struct nsurl;
-struct dom_node;
-struct dom_string;
-struct rect;
-
-#define UNKNOWN_WIDTH INT_MAX
-#define UNKNOWN_MAX_WIDTH INT_MAX
-
-typedef void (*box_construct_complete_cb)(struct html_content *c, bool success);
-
-/** Type of a struct box. */
-typedef enum {
- BOX_BLOCK, BOX_INLINE_CONTAINER, BOX_INLINE,
- BOX_TABLE, BOX_TABLE_ROW, BOX_TABLE_CELL,
- BOX_TABLE_ROW_GROUP,
- BOX_FLOAT_LEFT, BOX_FLOAT_RIGHT,
- BOX_INLINE_BLOCK, BOX_BR, BOX_TEXT,
- BOX_INLINE_END, BOX_NONE
-} box_type;
-
-
-/** Flags for a struct box. */
-typedef enum {
- NEW_LINE = 1 << 0, /* first inline on a new line */
- STYLE_OWNED = 1 << 1, /* style is owned by this box */
- PRINTED = 1 << 2, /* box has already been printed */
- PRE_STRIP = 1 << 3, /* PRE tag needing leading newline stripped */
- CLONE = 1 << 4, /* continuation of previous box from wrapping */
- MEASURED = 1 << 5, /* text box width has been measured */
- 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 */
- IFRAME = 1 << 10, /* box contains an iframe */
- CONVERT_CHILDREN = 1 << 11, /* wanted children converting */
- IS_REPLACED = 1 << 12 /* box is a replaced element */
-} box_flags;
-
-/* Sides of a box */
-enum box_side { TOP, RIGHT, BOTTOM, LEFT };
-
-/**
- * Container for box border details
- */
-struct box_border {
- enum css_border_style_e style; /**< border-style */
- css_color c; /**< border-color value */
- int width; /**< border-width (pixels) */
-};
-
-/** Node in box tree. All dimensions are in pixels. */
-struct box {
- /** Type of box. */
- box_type type;
-
- /** Box flags */
- box_flags flags;
-
- /** Computed styles for elements and their pseudo elements. NULL on
- * non-element boxes. */
- css_select_results *styles;
-
- /** Style for this box. 0 for INLINE_CONTAINER and FLOAT_*. Pointer into
- * a box's 'styles' select results, except for implied boxes, where it
- * is a pointer to an owned computed style. */
- css_computed_style *style;
-
- /** Coordinate of left padding edge relative to parent box, or relative
- * to ancestor that contains this box in float_children for FLOAT_. */
- int x;
- /** Coordinate of top padding edge, relative as for x. */
- int y;
-
- int width; /**< Width of content box (excluding padding etc.). */
- int height; /**< Height of content box (excluding padding etc.). */
-
- /* These four variables determine the maximum extent of a box's
- * descendants. They are relative to the x,y coordinates of the box.
- *
- * Their use depends on the overflow CSS property:
- *
- * Overflow: Usage:
- * visible The content of the box is displayed within these
- * dimensions.
- * hidden These are ignored. Content is plotted within the box
- * dimensions.
- * scroll These are used to determine the extent of the
- * scrollable area.
- * auto As "scroll".
- */
- int descendant_x0; /**< left edge of descendants */
- int descendant_y0; /**< top edge of descendants */
- int descendant_x1; /**< right edge of descendants */
- int descendant_y1; /**< bottom edge of descendants */
-
- int margin[4]; /**< Margin: TOP, RIGHT, BOTTOM, LEFT. */
- int padding[4]; /**< Padding: TOP, RIGHT, BOTTOM, LEFT. */
- struct box_border border[4]; /**< Border: TOP, RIGHT, BOTTOM, LEFT. */
-
- struct scrollbar *scroll_x; /**< Horizontal scroll. */
- struct scrollbar *scroll_y; /**< Vertical scroll. */
-
- /** Width of box taking all line breaks (including margins etc). Must
- * be non-negative. */
- int min_width;
- /** Width that would be taken with no line breaks. Must be
- * non-negative. */
- int max_width;
-
- /**< Byte offset within a textual representation of this content. */
- size_t byte_offset;
-
- char *text; /**< Text, or 0 if none. Unterminated. */
- size_t length; /**< Length of text. */
-
- /** Width of space after current text (depends on font and size). */
- int space;
-
- struct nsurl *href; /**< Link, or 0. */
- const char *target; /**< Link target, or 0. */
- const char *title; /**< Title, or 0. */
-
- unsigned int columns; /**< Number of columns for TABLE / TABLE_CELL. */
- unsigned int rows; /**< Number of rows for TABLE only. */
- unsigned int start_column; /**< Start column for TABLE_CELL only. */
-
- struct box *next; /**< Next sibling box, or 0. */
- struct box *prev; /**< Previous sibling box, or 0. */
- struct box *children; /**< First child box, or 0. */
- struct box *last; /**< Last child box, or 0. */
- struct box *parent; /**< Parent box, or 0. */
- /** INLINE_END box corresponding to this INLINE box, or INLINE box
- * corresponding to this INLINE_END box. */
- struct box *inline_end;
-
- /** First float child box, or 0. Float boxes are in the tree twice, in
- * this list for the block box which defines the area for floats, and
- * also in the standard tree given by children, next, prev, etc. */
- struct box *float_children;
- /** Next sibling float box. */
- struct box *next_float;
- /** If box is a float, points to box's containing block */
- struct box *float_container;
- /** Level below which subsequent floats must be cleared.
- * This is used only for boxes with float_children */
- int clear_level;
-
- /* Level below which floats have been placed. */
- int cached_place_below_level;
-
- /** List marker box if this is a list-item, or 0. */
- struct box *list_marker;
-
- struct column *col; /**< Array of table column data for TABLE only. */
-
- /** Form control data, or 0 if not a form control. */
- struct form_control* gadget;
-
- char *usemap; /** (Image)map to use with this object, or 0 if none */
- lwc_string *id; /**< value of id attribute (or name for anchors) */
-
- /** Background image for this box, or 0 if none */
- struct hlcache_handle *background;
-
- /** Object in this box (usually an image), or 0 if none. */
- 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;
-
- struct dom_node *node; /**< DOM node that generated this box or NULL */
-};
-
-/** Table column data. */
-struct column {
- /** Type of column. */
- enum { COLUMN_WIDTH_UNKNOWN, COLUMN_WIDTH_FIXED,
- COLUMN_WIDTH_AUTO, COLUMN_WIDTH_PERCENT,
- COLUMN_WIDTH_RELATIVE } type;
- /** Preferred width of column. Pixels for FIXED, percentage for PERCENT,
- * relative units for RELATIVE, unused for AUTO. */
- int width;
- /** Minimum width of content. */
- int min;
- /** Maximum width of content. */
- int max;
- /** Whether all of column's cells are css positioned. */
- bool positioned;
-};
-
-/** Parameters for object element and similar elements. */
-struct object_params {
- struct nsurl *data;
- char *type;
- char *codetype;
- struct nsurl *codebase;
- struct nsurl *classid;
- struct object_param *params;
-};
-
-/** Linked list of object element parameters. */
-struct object_param {
- char *name;
- char *value;
- char *type;
- char *valuetype;
- struct object_param *next;
-};
-
-/** Frame target names (constant pointers to save duplicating the strings many
- * times). We convert _blank to _top for user-friendliness. */
-extern const char *TARGET_SELF;
-extern const char *TARGET_PARENT;
-extern const char *TARGET_TOP;
-extern const char *TARGET_BLANK;
-
-
-
-struct box * box_create(css_select_results *styles, css_computed_style *style,
- bool style_owned, struct nsurl *href, const char *target,
- const char *title, lwc_string *id, void *context);
-void box_add_child(struct box *parent, struct box *child);
-void box_insert_sibling(struct box *box, struct box *new_box);
-void box_unlink_and_free(struct box *box);
-void box_free(struct box *box);
-void box_free_box(struct box *box);
-void box_bounds(struct box *box, struct rect *r);
-void box_coords(struct box *box, int *x, int *y);
-struct box *box_at_point(
- const nscss_len_ctx *len_ctx,
- struct box *box, const int x, const int y,
- int *box_x, int *box_y);
-struct box *box_pick_text_box(struct html_content *html,
- int x, int y, int dir, int *dx, int *dy);
-struct box *box_find_by_id(struct box *box, lwc_string *id);
-bool box_visible(struct box *box);
-void box_dump(FILE *stream, struct box *box, unsigned int depth, bool style);
-
-/**
- * Extract a URL from a relative link, handling junk like whitespace and
- * attempting to read a real URL from "javascript:" links.
- *
- * \param content html content
- * \param dsrel relative URL text taken from page
- * \param base base for relative URLs
- * \param result updated to target URL on heap, unchanged if extract failed
- * \return true on success, false on memory exhaustion
- */
-bool box_extract_link(const struct html_content *content, const struct dom_string *dsrel, struct nsurl *base, struct nsurl **result);
-
-bool box_handle_scrollbars(struct content *c, struct box *box,
- bool bottom, bool right);
-bool box_vscrollbar_present(const struct box *box);
-bool box_hscrollbar_present(const struct box *box);
-
-nserror dom_to_box(struct dom_node *n, struct html_content *c,
- box_construct_complete_cb cb);
-
-bool box_normalise_block(
- struct box *block,
- const struct box *root,
- struct html_content *c);
-
-#endif
diff --git a/render/box_construct.c b/render/box_construct.c
deleted file mode 100644
index 1aa99e2d1..000000000
--- a/render/box_construct.c
+++ /dev/null
@@ -1,3137 +0,0 @@
-/*
- * Copyright 2005 James Bursa <bursa@users.sourceforge.net>
- * Copyright 2003 Phil Mellor <monkeyson@users.sourceforge.net>
- * Copyright 2005 John M Bell <jmb202@ecs.soton.ac.uk>
- * Copyright 2006 Richard Wilson <info@tinct.net>
- * Copyright 2008 Michael Drake <tlsa@netsurf-browser.org>
- *
- * This file is part of NetSurf, http://www.netsurf-browser.org/
- *
- * NetSurf is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * NetSurf is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-/**
- * \file
- * Implementation of conversion from DOM tree to box tree.
- */
-
-#include <assert.h>
-#include <stdio.h>
-#include <stdbool.h>
-#include <stdlib.h>
-#include <string.h>
-#include <strings.h>
-
-#include "utils/config.h"
-#include "utils/nsoption.h"
-#include "utils/corestrings.h"
-#include "utils/log.h"
-#include "utils/messages.h"
-#include "utils/talloc.h"
-#include "utils/string.h"
-#include "utils/ascii.h"
-#include "netsurf/css.h"
-#include "netsurf/misc.h"
-#include "netsurf/plot_style.h"
-#include "content/content_protected.h"
-#include "css/hints.h"
-#include "css/select.h"
-#include "css/utils.h"
-#include "desktop/gui_internal.h"
-
-#include "render/box.h"
-#include "render/box_textarea.h"
-#include "render/form_internal.h"
-#include "render/html_internal.h"
-
-/**
- * Context for box tree construction
- */
-struct box_construct_ctx {
- html_content *content; /**< Content we're constructing for */
-
- dom_node *n; /**< Current node to process */
-
- struct box *root_box; /**< Root box in the tree */
-
- box_construct_complete_cb cb; /**< Callback to invoke on completion */
-
- int *bctx; /**< talloc context */
-};
-
-/**
- * Transient properties for construction of current node
- */
-struct box_construct_props {
- /** Style from which to inherit, or NULL if none */
- const css_computed_style *parent_style;
- /** Current link target, or NULL if none */
- nsurl *href;
- /** Current frame target, or NULL if none */
- const char *target;
- /** Current title attribute, or NULL if none */
- const char *title;
- /** Identity of the current block-level container */
- struct box *containing_block;
- /** Current container for inlines, or NULL if none
- * \note If non-NULL, will be the last child of containing_block */
- struct box *inline_container;
- /** Whether the current node is the root of the DOM tree */
- bool node_is_root;
-};
-
-static const content_type image_types = CONTENT_IMAGE;
-
-/* the strings are not important, since we just compare the pointers */
-const char *TARGET_SELF = "_self";
-const char *TARGET_PARENT = "_parent";
-const char *TARGET_TOP = "_top";
-const char *TARGET_BLANK = "_blank";
-
-static void convert_xml_to_box(struct box_construct_ctx *ctx);
-static bool box_construct_element(struct box_construct_ctx *ctx,
- bool *convert_children);
-static void box_construct_element_after(dom_node *n, html_content *content);
-static bool box_construct_text(struct box_construct_ctx *ctx);
-static css_select_results * box_get_style(html_content *c,
- const css_computed_style *parent_style,
- const css_computed_style *root_style, dom_node *n);
-static void box_text_transform(char *s, unsigned int len,
- enum css_text_transform_e tt);
-#define BOX_SPECIAL_PARAMS dom_node *n, html_content *content, \
- struct box *box, bool *convert_children
-static bool box_a(BOX_SPECIAL_PARAMS);
-static bool box_body(BOX_SPECIAL_PARAMS);
-static bool box_br(BOX_SPECIAL_PARAMS);
-static bool box_image(BOX_SPECIAL_PARAMS);
-static bool box_textarea(BOX_SPECIAL_PARAMS);
-static bool box_select(BOX_SPECIAL_PARAMS);
-static bool box_input(BOX_SPECIAL_PARAMS);
-static bool box_button(BOX_SPECIAL_PARAMS);
-static bool box_frameset(BOX_SPECIAL_PARAMS);
-static bool box_create_frameset(struct content_html_frames *f, dom_node *n,
- html_content *content);
-static bool box_select_add_option(struct form_control *control, dom_node *n);
-static bool box_noscript(BOX_SPECIAL_PARAMS);
-static bool box_object(BOX_SPECIAL_PARAMS);
-static bool box_embed(BOX_SPECIAL_PARAMS);
-static bool box_pre(BOX_SPECIAL_PARAMS);
-static bool box_iframe(BOX_SPECIAL_PARAMS);
-static bool box_get_attribute(dom_node *n, const char *attribute,
- void *context, char **value);
-
-/* element_table must be sorted by name */
-struct element_entry {
- char name[10]; /* element type */
- bool (*convert)(BOX_SPECIAL_PARAMS);
-};
-static const struct element_entry element_table[] = {
- {"a", box_a},
- {"body", box_body},
- {"br", box_br},
- {"button", box_button},
- {"embed", box_embed},
- {"frameset", box_frameset},
- {"iframe", box_iframe},
- {"image", box_image},
- {"img", box_image},
- {"input", box_input},
- {"noscript", box_noscript},
- {"object", box_object},
- {"pre", box_pre},
- {"select", box_select},
- {"textarea", box_textarea}
-};
-#define ELEMENT_TABLE_COUNT (sizeof(element_table) / sizeof(element_table[0]))
-
-/**
- * Construct a box tree from an xml tree and stylesheets.
- *
- * \param n xml tree
- * \param c content of type CONTENT_HTML to construct box tree in
- * \param cb callback to report conversion completion
- * \return netsurf error code indicating status of call
- */
-
-nserror dom_to_box(dom_node *n, html_content *c, box_construct_complete_cb cb)
-{
- struct box_construct_ctx *ctx;
-
- if (c->bctx == NULL) {
- /* create a context allocation for this box tree */
- c->bctx = talloc_zero(0, int);
- if (c->bctx == NULL) {
- return NSERROR_NOMEM;
- }
- }
-
- ctx = malloc(sizeof(*ctx));
- if (ctx == NULL) {
- return NSERROR_NOMEM;
- }
-
- ctx->content = c;
- ctx->n = dom_node_ref(n);
- ctx->root_box = NULL;
- ctx->cb = cb;
- ctx->bctx = c->bctx;
-
- return guit->misc->schedule(0, (void *)convert_xml_to_box, ctx);
-}
-
-/* mapping from CSS display to box type
- * this table must be in sync with libcss' css_display enum */
-static const box_type box_map[] = {
- 0, /*CSS_DISPLAY_INHERIT,*/
- BOX_INLINE, /*CSS_DISPLAY_INLINE,*/
- BOX_BLOCK, /*CSS_DISPLAY_BLOCK,*/
- BOX_BLOCK, /*CSS_DISPLAY_LIST_ITEM,*/
- BOX_INLINE, /*CSS_DISPLAY_RUN_IN,*/
- BOX_INLINE_BLOCK, /*CSS_DISPLAY_INLINE_BLOCK,*/
- BOX_TABLE, /*CSS_DISPLAY_TABLE,*/
- BOX_TABLE, /*CSS_DISPLAY_INLINE_TABLE,*/
- BOX_TABLE_ROW_GROUP, /*CSS_DISPLAY_TABLE_ROW_GROUP,*/
- BOX_TABLE_ROW_GROUP, /*CSS_DISPLAY_TABLE_HEADER_GROUP,*/
- BOX_TABLE_ROW_GROUP, /*CSS_DISPLAY_TABLE_FOOTER_GROUP,*/
- BOX_TABLE_ROW, /*CSS_DISPLAY_TABLE_ROW,*/
- BOX_NONE, /*CSS_DISPLAY_TABLE_COLUMN_GROUP,*/
- BOX_NONE, /*CSS_DISPLAY_TABLE_COLUMN,*/
- BOX_TABLE_CELL, /*CSS_DISPLAY_TABLE_CELL,*/
- BOX_INLINE, /*CSS_DISPLAY_TABLE_CAPTION,*/
- BOX_NONE /*CSS_DISPLAY_NONE*/
-};
-
-static inline struct box *box_for_node(dom_node *n)
-{
- struct box *box = NULL;
- dom_exception err;
-
- err = dom_node_get_user_data(n, corestring_dom___ns_key_box_node_data,
- (void *) &box);
- if (err != DOM_NO_ERR)
- return NULL;
-
- return box;
-}
-
-static inline bool box_is_root(dom_node *n)
-{
- dom_node *parent;
- dom_node_type type;
- dom_exception err;
-
- err = dom_node_get_parent_node(n, &parent);
- if (err != DOM_NO_ERR)
- return false;
-
- if (parent != NULL) {
- err = dom_node_get_node_type(parent, &type);
-
- dom_node_unref(parent);
-
- if (err != DOM_NO_ERR)
- return false;
-
- if (type != DOM_DOCUMENT_NODE)
- return false;
- }
-
- return true;
-}
-
-/**
- * Find the next node in the DOM tree, completing
- * element construction where appropriate.
- *
- * \param n Current node
- * \param content Containing content
- * \param convert_children Whether to consider children of \a n
- * \return Next node to process, or NULL if complete
- *
- * \note \a n will be unreferenced
- */
-static dom_node *next_node(dom_node *n, html_content *content,
- bool convert_children)
-{
- dom_node *next = NULL;
- bool has_children;
- dom_exception err;
-
- err = dom_node_has_child_nodes(n, &has_children);
- if (err != DOM_NO_ERR) {
- dom_node_unref(n);
- return NULL;
- }
-
- if (convert_children && has_children) {
- err = dom_node_get_first_child(n, &next);
- if (err != DOM_NO_ERR) {
- dom_node_unref(n);
- return NULL;
- }
- dom_node_unref(n);
- } else {
- err = dom_node_get_next_sibling(n, &next);
- if (err != DOM_NO_ERR) {
- dom_node_unref(n);
- return NULL;
- }
-
- if (next != NULL) {
- if (box_for_node(n) != NULL)
- box_construct_element_after(n, content);
- dom_node_unref(n);
- } else {
- if (box_for_node(n) != NULL)
- box_construct_element_after(n, content);
-
- while (box_is_root(n) == false) {
- dom_node *parent = NULL;
- dom_node *parent_next = NULL;
-
- err = dom_node_get_parent_node(n, &parent);
- if (err != DOM_NO_ERR) {
- dom_node_unref(n);
- return NULL;
- }
-
- assert(parent != NULL);
-
- err = dom_node_get_next_sibling(parent,
- &parent_next);
- if (err != DOM_NO_ERR) {
- dom_node_unref(parent);
- dom_node_unref(n);
- return NULL;
- }
-
- if (parent_next != NULL) {
- dom_node_unref(parent_next);
- dom_node_unref(parent);
- break;
- }
-
- dom_node_unref(n);
- n = parent;
- parent = NULL;
-
- if (box_for_node(n) != NULL) {
- box_construct_element_after(
- n, content);
- }
- }
-
- if (box_is_root(n) == false) {
- dom_node *parent = NULL;
-
- err = dom_node_get_parent_node(n, &parent);
- if (err != DOM_NO_ERR) {
- dom_node_unref(n);
- return NULL;
- }
-
- assert(parent != NULL);
-
- err = dom_node_get_next_sibling(parent, &next);
- if (err != DOM_NO_ERR) {
- dom_node_unref(parent);
- dom_node_unref(n);
- return NULL;
- }
-
- if (box_for_node(parent) != NULL) {
- box_construct_element_after(parent,
- content);
- }
-
- dom_node_unref(parent);
- }
-
- dom_node_unref(n);
- }
- }
-
- return next;
-}
-
-/**
- * Convert an ELEMENT node to a box tree fragment,
- * then schedule conversion of the next ELEMENT node
- */
-void convert_xml_to_box(struct box_construct_ctx *ctx)
-{
- dom_node *next;
- bool convert_children;
- uint32_t num_processed = 0;
- const uint32_t max_processed_before_yield = 10;
-
- do {
- convert_children = true;
-
- assert(ctx->n != NULL);
-
- if (box_construct_element(ctx, &convert_children) == false) {
- ctx->cb(ctx->content, false);
- dom_node_unref(ctx->n);
- free(ctx);
- return;
- }
-
- /* Find next element to process, converting text nodes as we go */
- next = next_node(ctx->n, ctx->content, convert_children);
- while (next != NULL) {
- dom_node_type type;
- dom_exception err;
-
- err = dom_node_get_node_type(next, &type);
- if (err != DOM_NO_ERR) {
- ctx->cb(ctx->content, false);
- dom_node_unref(next);
- free(ctx);
- return;
- }
-
- if (type == DOM_ELEMENT_NODE)
- break;
-
- if (type == DOM_TEXT_NODE) {
- ctx->n = next;
- if (box_construct_text(ctx) == false) {
- ctx->cb(ctx->content, false);
- dom_node_unref(ctx->n);
- free(ctx);
- return;
- }
- }
-
- next = next_node(next, ctx->content, true);
- }
-
- ctx->n = next;
-
- if (next == NULL) {
- /* Conversion complete */
- struct box root;
-
- memset(&root, 0, sizeof(root));
-
- root.type = BOX_BLOCK;
- root.children = root.last = ctx->root_box;
- root.children->parent = &root;
-
- /** \todo Remove box_normalise_block */
- if (box_normalise_block(&root, ctx->root_box,
- ctx->content) == false) {
- ctx->cb(ctx->content, false);
- } else {
- ctx->content->layout = root.children;
- ctx->content->layout->parent = NULL;
-
- ctx->cb(ctx->content, true);
- }
-
- assert(ctx->n == NULL);
-
- free(ctx);
- return;
- }
- } while (++num_processed < max_processed_before_yield);
-
- /* More work to do: schedule a continuation */
- guit->misc->schedule(0, (void *)convert_xml_to_box, ctx);
-}
-
-/**
- * Construct a list marker box
- *
- * \param box Box to attach marker to
- * \param title Current title attribute
- * \param ctx Box construction context
- * \param parent Current block-level container
- * \return true on success, false on memory exhaustion
- */
-static bool box_construct_marker(struct box *box, const char *title,
- struct box_construct_ctx *ctx, struct box *parent)
-{
- lwc_string *image_uri;
- struct box *marker;
-
- marker = box_create(NULL, box->style, false, NULL, NULL, title,
- NULL, ctx->bctx);
- if (marker == false)
- return false;
-
- marker->type = BOX_BLOCK;
-
- /** \todo marker content (list-style-type) */
- switch (css_computed_list_style_type(box->style)) {
- case CSS_LIST_STYLE_TYPE_DISC:
- /* 2022 BULLET */
- marker->text = (char *) "\342\200\242";
- marker->length = 3;
- break;
- case CSS_LIST_STYLE_TYPE_CIRCLE:
- /* 25CB WHITE CIRCLE */
- marker->text = (char *) "\342\227\213";
- marker->length = 3;
- break;
- case CSS_LIST_STYLE_TYPE_SQUARE:
- /* 25AA BLACK SMALL SQUARE */
- marker->text = (char *) "\342\226\252";
- marker->length = 3;
- break;
- case CSS_LIST_STYLE_TYPE_DECIMAL:
- case CSS_LIST_STYLE_TYPE_LOWER_ALPHA:
- case CSS_LIST_STYLE_TYPE_LOWER_ROMAN:
- case CSS_LIST_STYLE_TYPE_UPPER_ALPHA:
- case CSS_LIST_STYLE_TYPE_UPPER_ROMAN:
- default:
- if (parent->last) {
- struct box *last = parent->last;
-
- /* Drill down into last child of parent
- * to find the list marker (if any)
- *
- * Floated list boxes end up as:
- *
- * parent
- * BOX_INLINE_CONTAINER
- * BOX_FLOAT_{LEFT,RIGHT}
- * BOX_BLOCK <-- list box
- * ...
- */
- while (last != NULL && last->list_marker == NULL) {
- struct box *last_inner = last;
-
- while (last_inner != NULL) {
- if (last_inner->list_marker != NULL)
- break;
- if (last_inner->type ==
- BOX_INLINE_CONTAINER ||
- last_inner->type ==
- BOX_FLOAT_LEFT ||
- last_inner->type ==
- BOX_FLOAT_RIGHT) {
- last_inner = last_inner->last;
- } else {
- last_inner = NULL;
- }
- }
- if (last_inner != NULL) {
- last = last_inner;
- } else {
- last = last->prev;
- }
- }
-
- if (last && last->list_marker) {
- marker->rows = last->list_marker->rows + 1;
- }
- }
-
- marker->text = talloc_array(ctx->bctx, char, 20);
- if (marker->text == NULL)
- return false;
-
- snprintf(marker->text, 20, "%u.", marker->rows);
- marker->length = strlen(marker->text);
- break;
- case CSS_LIST_STYLE_TYPE_NONE:
- marker->text = 0;
- marker->length = 0;
- break;
- }
-
- if (css_computed_list_style_image(box->style, &image_uri) == CSS_LIST_STYLE_IMAGE_URI &&
- (image_uri != NULL) &&
- (nsoption_bool(foreground_images) == true)) {
- nsurl *url;
- nserror error;
-
- /* TODO: we get a url out of libcss as a lwc string, but
- * earlier we already had it as a nsurl after we
- * nsurl_joined it. Can this be improved?
- * For now, just making another nsurl. */
- error = nsurl_create(lwc_string_data(image_uri), &url);
- if (error != NSERROR_OK)
- return false;
-
- if (html_fetch_object(ctx->content, url, marker, image_types,
- ctx->content->base.available_width, 1000, false) ==
- false) {
- nsurl_unref(url);
- return false;
- }
- nsurl_unref(url);
- }
-
- box->list_marker = marker;
- marker->parent = box;
-
- return true;
-}
-
-/**
- * Construct the box required for a generated element.
- *
- * \param n XML node of type XML_ELEMENT_NODE
- * \param content Content of type CONTENT_HTML that is being processed
- * \param box Box which may have generated content
- * \param style Complete computed style for pseudo element, or NULL
- *
- * TODO:
- * This is currently incomplete. It just does enough to support the clearfix
- * hack. ( http://www.positioniseverything.net/easyclearing.html )
- */
-static void box_construct_generate(dom_node *n, html_content *content,
- struct box *box, const css_computed_style *style)
-{
- struct box *gen = NULL;
- enum css_display_e computed_display;
- const css_computed_content_item *c_item;
-
- /* Nothing to generate if the parent box is not a block */
- if (box->type != BOX_BLOCK)
- return;
-
- /* To determine if an element has a pseudo element, we select
- * for it and test to see if the returned style's content
- * property is set to normal. */
- if (style == NULL ||
- css_computed_content(style, &c_item) ==
- CSS_CONTENT_NORMAL) {
- /* No pseudo element */
- return;
- }
-
- /* create box for this element */
- computed_display = ns_computed_display(style, box_is_root(n));
- if (computed_display == CSS_DISPLAY_BLOCK ||
- computed_display == CSS_DISPLAY_TABLE) {
- /* currently only support block level boxes */
-
- /** \todo Not wise to drop const from the computed style */
- gen = box_create(NULL, (css_computed_style *) style,
- false, NULL, NULL, NULL, NULL, content->bctx);
- if (gen == NULL) {
- return;
- }
-
- /* set box type from computed display */
- gen->type = box_map[ns_computed_display(
- style, box_is_root(n))];
-
- box_add_child(box, gen);
- }
-}
-
-/**
- * Extract transient construction properties
- *
- * \param n Current DOM node to convert
- * \param props Property object to populate
- */
-static void box_extract_properties(dom_node *n,
- struct box_construct_props *props)
-{
- memset(props, 0, sizeof(*props));
-
- props->node_is_root = box_is_root(n);
-
- /* Extract properties from containing DOM node */
- if (props->node_is_root == false) {
- dom_node *current_node = n;
- dom_node *parent_node = NULL;
- struct box *parent_box;
- dom_exception err;
-
- /* Find ancestor node containing parent box */
- while (true) {
- err = dom_node_get_parent_node(current_node,
- &parent_node);
- if (err != DOM_NO_ERR || parent_node == NULL)
- break;
-
- parent_box = box_for_node(parent_node);
-
- if (parent_box != NULL) {
- props->parent_style = parent_box->style;
- props->href = parent_box->href;
- props->target = parent_box->target;
- props->title = parent_box->title;
-
- dom_node_unref(parent_node);
- break;
- } else {
- if (current_node != n)
- dom_node_unref(current_node);
- current_node = parent_node;
- parent_node = NULL;
- }
- }
-
- /* Find containing block (may be parent) */
- while (true) {
- struct box *b;
-
- err = dom_node_get_parent_node(current_node,
- &parent_node);
- if (err != DOM_NO_ERR || parent_node == NULL) {
- if (current_node != n)
- dom_node_unref(current_node);
- break;
- }
-
- if (current_node != n)
- dom_node_unref(current_node);
-
- b = box_for_node(parent_node);
-
- /* Children of nodes that created an inline box
- * will generate boxes which are attached as
- * _siblings_ of the box generated for their
- * parent node. Note, however, that we'll still
- * use the parent node's styling as the parent
- * style, above. */
- if (b != NULL && b->type != BOX_INLINE &&
- b->type != BOX_BR) {
- props->containing_block = b;
-
- dom_node_unref(parent_node);
- break;
- } else {
- current_node = parent_node;
- parent_node = NULL;
- }
- }
- }
-
- /* Compute current inline container, if any */
- if (props->containing_block != NULL &&
- props->containing_block->last != NULL &&
- props->containing_block->last->type ==
- BOX_INLINE_CONTAINER)
- props->inline_container = props->containing_block->last;
-}
-
-/**
- * Construct the box tree for an XML element.
- *
- * \param ctx Tree construction context
- * \param convert_children Whether to convert children
- * \return true on success, false on memory exhaustion
- */
-
-bool box_construct_element(struct box_construct_ctx *ctx,
- bool *convert_children)
-{
- dom_string *title0, *s;
- lwc_string *id = NULL;
- struct box *box = NULL, *old_box;
- css_select_results *styles = NULL;
- struct element_entry *element;
- lwc_string *bgimage_uri;
- dom_exception err;
- struct box_construct_props props;
- const css_computed_style *root_style = NULL;
-
- assert(ctx->n != NULL);
-
- box_extract_properties(ctx->n, &props);
-
- if (props.containing_block != NULL) {
- /* In case the containing block is a pre block, we clear
- * the PRE_STRIP flag since it is not used if we follow
- * the pre with a tag */
- props.containing_block->flags &= ~PRE_STRIP;
- }
-
- if (props.node_is_root == false) {
- root_style = ctx->root_box->style;
- }
-
- styles = box_get_style(ctx->content, props.parent_style, root_style,
- ctx->n);
- if (styles == NULL)
- return false;
-
- /* Extract title attribute, if present */
- err = dom_element_get_attribute(ctx->n, corestring_dom_title, &title0);
- if (err != DOM_NO_ERR)
- return false;
-
- if (title0 != NULL) {
- char *t = squash_whitespace(dom_string_data(title0));
-
- dom_string_unref(title0);
-
- if (t == NULL)
- return false;
-
- props.title = talloc_strdup(ctx->bctx, t);
-
- free(t);
-
- if (props.title == NULL)
- return false;
- }
-
- /* Extract id attribute, if present */
- err = dom_element_get_attribute(ctx->n, corestring_dom_id, &s);
- if (err != DOM_NO_ERR)
- return false;
-
- if (s != NULL) {
- err = dom_string_intern(s, &id);
- if (err != DOM_NO_ERR)
- id = NULL;
-
- dom_string_unref(s);
- }
-
- box = box_create(styles, styles->styles[CSS_PSEUDO_ELEMENT_NONE], false,
- props.href, props.target, props.title, id,
- ctx->bctx);
- if (box == NULL)
- return false;
-
- /* If this is the root box, add it to the context */
- if (props.node_is_root)
- ctx->root_box = box;
-
- /* Deal with colspan/rowspan */
- err = dom_element_get_attribute(ctx->n, corestring_dom_colspan, &s);
- if (err != DOM_NO_ERR)
- return false;
-
- if (s != NULL) {
- const char *val = dom_string_data(s);
-
- if ('0' <= val[0] && val[0] <= '9')
- box->columns = strtol(val, NULL, 10);
-
- dom_string_unref(s);
- }
-
- err = dom_element_get_attribute(ctx->n, corestring_dom_rowspan, &s);
- if (err != DOM_NO_ERR)
- return false;
-
- if (s != NULL) {
- const char *val = dom_string_data(s);
-
- if ('0' <= val[0] && val[0] <= '9')
- box->rows = strtol(val, NULL, 10);
-
- dom_string_unref(s);
- }
-
- /* Set box type from computed display */
- if ((css_computed_position(box->style) == CSS_POSITION_ABSOLUTE ||
- css_computed_position(box->style) ==
- CSS_POSITION_FIXED) &&
- (ns_computed_display_static(box->style) ==
- CSS_DISPLAY_INLINE ||
- ns_computed_display_static(box->style) ==
- CSS_DISPLAY_INLINE_BLOCK ||
- ns_computed_display_static(box->style) ==
- CSS_DISPLAY_INLINE_TABLE)) {
- /* Special case for absolute positioning: make absolute inlines
- * into inline block so that the boxes are constructed in an
- * inline container as if they were not absolutely positioned.
- * Layout expects and handles this. */
- box->type = box_map[CSS_DISPLAY_INLINE_BLOCK];
- } else if (props.node_is_root) {
- /* Special case for root element: force it to BLOCK, or the
- * rest of the layout will break. */
- box->type = BOX_BLOCK;
- } else {
- /* Normal mapping */
- box->type = box_map[ns_computed_display(box->style,
- props.node_is_root)];
- }
-
- err = dom_node_get_node_name(ctx->n, &s);
- if (err != DOM_NO_ERR || s == NULL)
- return false;
-
- /* Special elements */
- element = bsearch(dom_string_data(s), element_table,
- ELEMENT_TABLE_COUNT, sizeof(element_table[0]),
- (int (*)(const void *, const void *)) strcasecmp);
-
- dom_string_unref(s);
-
- if (element != NULL) {
- /* A special convert function exists for this element */
- if (element->convert(ctx->n, ctx->content, box,
- convert_children) == false)
- return false;
- }
-
- /* Handle the :before pseudo element */
- if (!(box->flags & IS_REPLACED)) {
- box_construct_generate(ctx->n, ctx->content, box,
- box->styles->styles[CSS_PSEUDO_ELEMENT_BEFORE]);
- }
-
- if (box->type == BOX_NONE || (ns_computed_display(box->style,
- props.node_is_root) == CSS_DISPLAY_NONE &&
- props.node_is_root == false)) {
- css_select_results_destroy(styles);
- box->styles = NULL;
- box->style = NULL;
-
- /* Invalidate associated gadget, if any */
- if (box->gadget != NULL) {
- box->gadget->box = NULL;
- box->gadget = NULL;
- }
-
- /* Can't do this, because the lifetimes of boxes and gadgets
- * are inextricably linked. Fortunately, talloc will save us
- * (for now) */
- /* box_free_box(box); */
-
- *convert_children = false;
-
- return true;
- }
-
- /* Attach DOM node to box */
- err = dom_node_set_user_data(ctx->n,
- corestring_dom___ns_key_box_node_data, box, NULL,
- (void *) &old_box);
- if (err != DOM_NO_ERR)
- return false;
-
- /* Attach box to DOM node */
- box->node = dom_node_ref(ctx->n);
-
- if (props.inline_container == NULL &&
- (box->type == BOX_INLINE ||
- box->type == BOX_BR ||
- box->type == BOX_INLINE_BLOCK ||
- css_computed_float(box->style) == CSS_FLOAT_LEFT ||
- css_computed_float(box->style) == CSS_FLOAT_RIGHT) &&
- props.node_is_root == false) {
- /* Found an inline child of a block without a current container
- * (i.e. this box is the first child of its parent, or was
- * preceded by block-level siblings) */
- assert(props.containing_block != NULL &&
- "Box must have containing block.");
-
- props.inline_container = box_create(NULL, NULL, false, NULL,
- NULL, NULL, NULL, ctx->bctx);
- if (props.inline_container == NULL)
- return false;
-
- props.inline_container->type = BOX_INLINE_CONTAINER;
-
- box_add_child(props.containing_block, props.inline_container);
- }
-
- /* Kick off fetch for any background image */
- if (css_computed_background_image(box->style, &bgimage_uri) ==
- CSS_BACKGROUND_IMAGE_IMAGE && bgimage_uri != NULL &&
- nsoption_bool(background_images) == true) {
- nsurl *url;
- nserror error;
-
- /* TODO: we get a url out of libcss as a lwc string, but
- * earlier we already had it as a nsurl after we
- * nsurl_joined it. Can this be improved?
- * For now, just making another nsurl. */
- error = nsurl_create(lwc_string_data(bgimage_uri), &url);
- if (error == NSERROR_OK) {
- /* Fetch image if we got a valid URL */
- if (html_fetch_object(ctx->content, url, box,
- image_types,
- ctx->content->base.available_width,
- 1000, true) == false) {
- nsurl_unref(url);
- return false;
- }
- nsurl_unref(url);
- }
- }
-
- if (*convert_children)
- box->flags |= CONVERT_CHILDREN;
-
- if (box->type == BOX_INLINE || box->type == BOX_BR ||
- box->type == BOX_INLINE_BLOCK) {
- /* Inline container must exist, as we'll have
- * created it above if it didn't */
- assert(props.inline_container != NULL);
-
- box_add_child(props.inline_container, box);
- } else {
- if (ns_computed_display(box->style, props.node_is_root) ==
- CSS_DISPLAY_LIST_ITEM) {
- /* List item: compute marker */
- if (box_construct_marker(box, props.title, ctx,
- props.containing_block) == false)
- return false;
- }
-
- if (props.node_is_root == false &&
- (css_computed_float(box->style) ==
- CSS_FLOAT_LEFT ||
- css_computed_float(box->style) ==
- CSS_FLOAT_RIGHT)) {
- /* Float: insert a float between the parent and box. */
- struct box *flt = box_create(NULL, NULL, false,
- props.href, props.target, props.title,
- NULL, ctx->bctx);
- if (flt == NULL)
- return false;
-
- if (css_computed_float(box->style) == CSS_FLOAT_LEFT)
- flt->type = BOX_FLOAT_LEFT;
- else
- flt->type = BOX_FLOAT_RIGHT;
-
- box_add_child(props.inline_container, flt);
- box_add_child(flt, box);
- } else {
- /* Non-floated block-level box: add to containing block
- * if there is one. If we're the root box, then there
- * won't be. */
- if (props.containing_block != NULL)
- box_add_child(props.containing_block, box);
- }
- }
-
- return true;
-}
-
-/**
- * Complete construction of the box tree for an element.
- *
- * \param n DOM node to construct for
- * \param content Containing document
- *
- * This will be called after all children of an element have been processed
- */
-void box_construct_element_after(dom_node *n, html_content *content)
-{
- struct box_construct_props props;
- struct box *box = box_for_node(n);
-
- assert(box != NULL);
-
- box_extract_properties(n, &props);
-
- if (box->type == BOX_INLINE || box->type == BOX_BR) {
- /* Insert INLINE_END into containing block */
- struct box *inline_end;
- bool has_children;
- dom_exception err;
-
- err = dom_node_has_child_nodes(n, &has_children);
- if (err != DOM_NO_ERR)
- return;
-
- if (has_children == false ||
- (box->flags & CONVERT_CHILDREN) == 0) {
- /* No children, or didn't want children converted */
- return;
- }
-
- if (props.inline_container == NULL) {
- /* Create inline container if we don't have one */
- props.inline_container = box_create(NULL, NULL, false,
- NULL, NULL, NULL, NULL, content->bctx);
- if (props.inline_container == NULL)
- return;
-
- props.inline_container->type = BOX_INLINE_CONTAINER;
-
- box_add_child(props.containing_block,
- props.inline_container);
- }
-
- inline_end = box_create(NULL, box->style, false,
- box->href, box->target, box->title,
- box->id == NULL ? NULL :
- lwc_string_ref(box->id), content->bctx);
- if (inline_end != NULL) {
- inline_end->type = BOX_INLINE_END;
-
- assert(props.inline_container != NULL);
-
- box_add_child(props.inline_container, inline_end);
-
- box->inline_end = inline_end;
- inline_end->inline_end = box;
- }
- } else if (!(box->flags & IS_REPLACED)) {
- /* Handle the :after pseudo element */
- box_construct_generate(n, content, box,
- box->styles->styles[CSS_PSEUDO_ELEMENT_AFTER]);
- }
-}
-
-/**
- * Construct the box tree for an XML text node.
- *
- * \param ctx Tree construction context
- * \return true on success, false on memory exhaustion
- */
-
-bool box_construct_text(struct box_construct_ctx *ctx)
-{
- struct box_construct_props props;
- struct box *box = NULL;
- dom_string *content;
- dom_exception err;
-
- assert(ctx->n != NULL);
-
- box_extract_properties(ctx->n, &props);
-
- assert(props.containing_block != NULL);
-
- err = dom_characterdata_get_data(ctx->n, &content);
- if (err != DOM_NO_ERR || content == NULL)
- return false;
-
- if (css_computed_white_space(props.parent_style) ==
- CSS_WHITE_SPACE_NORMAL ||
- css_computed_white_space(props.parent_style) ==
- CSS_WHITE_SPACE_NOWRAP) {
- char *text;
-
- text = squash_whitespace(dom_string_data(content));
-
- dom_string_unref(content);
-
- if (text == NULL)
- return false;
-
- /* if the text is just a space, combine it with the preceding
- * text node, if any */
- if (text[0] == ' ' && text[1] == 0) {
- if (props.inline_container != NULL) {
- assert(props.inline_container->last != NULL);
-
- props.inline_container->last->space =
- UNKNOWN_WIDTH;
- }
-
- free(text);
-
- return true;
- }
-
- if (props.inline_container == NULL) {
- /* Child of a block without a current container
- * (i.e. this box is the first child of its parent, or
- * was preceded by block-level siblings) */
- props.inline_container = box_create(NULL, NULL, false,
- NULL, NULL, NULL, NULL, ctx->bctx);
- if (props.inline_container == NULL) {
- free(text);
- return false;
- }
-
- props.inline_container->type = BOX_INLINE_CONTAINER;
-
- box_add_child(props.containing_block,
- props.inline_container);
- }
-
- /** \todo Dropping const here is not clever */
- box = box_create(NULL,
- (css_computed_style *) props.parent_style,
- false, props.href, props.target, props.title,
- NULL, ctx->bctx);
- if (box == NULL) {
- free(text);
- return false;
- }
-
- box->type = BOX_TEXT;
-
- box->text = talloc_strdup(ctx->bctx, text);
- free(text);
- if (box->text == NULL)
- return false;
-
- box->length = strlen(box->text);
-
- /* strip ending space char off */
- if (box->length > 1 && box->text[box->length - 1] == ' ') {
- box->space = UNKNOWN_WIDTH;
- box->length--;
- }
-
- if (css_computed_text_transform(props.parent_style) !=
- CSS_TEXT_TRANSFORM_NONE)
- box_text_transform(box->text, box->length,
- css_computed_text_transform(
- props.parent_style));
-
- box_add_child(props.inline_container, box);
-
- if (box->text[0] == ' ') {
- box->length--;
-
- memmove(box->text, &box->text[1], box->length);
-
- if (box->prev != NULL)
- box->prev->space = UNKNOWN_WIDTH;
- }
- } else {
- /* white-space: pre */
- char *text;
- size_t text_len = dom_string_byte_length(content);
- size_t i;
- char *current;
- enum css_white_space_e white_space =
- css_computed_white_space(props.parent_style);
-
- /* note: pre-wrap/pre-line are unimplemented */
- assert(white_space == CSS_WHITE_SPACE_PRE ||
- white_space == CSS_WHITE_SPACE_PRE_LINE ||
- white_space == CSS_WHITE_SPACE_PRE_WRAP);
-
- text = malloc(text_len + 1);
- dom_string_unref(content);
-
- if (text == NULL)
- return false;
-
- memcpy(text, dom_string_data(content), text_len);
- text[text_len] = '\0';
-
- /* TODO: Handle tabs properly */
- for (i = 0; i < text_len; i++)
- if (text[i] == '\t')
- text[i] = ' ';
-
- if (css_computed_text_transform(props.parent_style) !=
- CSS_TEXT_TRANSFORM_NONE)
- box_text_transform(text, strlen(text),
- css_computed_text_transform(
- props.parent_style));
-
- current = text;
-
- /* swallow a single leading new line */
- if (props.containing_block->flags & PRE_STRIP) {
- switch (*current) {
- case '\n':
- current++;
- break;
- case '\r':
- current++;
- if (*current == '\n')
- current++;
- break;
- }
- props.containing_block->flags &= ~PRE_STRIP;
- }
-
- do {
- size_t len = strcspn(current, "\r\n");
-
- char old = current[len];
-
- current[len] = 0;
-
- if (props.inline_container == NULL) {
- /* Child of a block without a current container
- * (i.e. this box is the first child of its
- * parent, or was preceded by block-level
- * siblings) */
- props.inline_container = box_create(NULL, NULL,
- false, NULL, NULL, NULL, NULL,
- ctx->bctx);
- if (props.inline_container == NULL) {
- free(text);
- return false;
- }
-
- props.inline_container->type =
- BOX_INLINE_CONTAINER;
-
- box_add_child(props.containing_block,
- props.inline_container);
- }
-
- /** \todo Dropping const isn't clever */
- box = box_create(NULL,
- (css_computed_style *) props.parent_style,
- false, props.href, props.target, props.title,
- NULL, ctx->bctx);
- if (box == NULL) {
- free(text);
- return false;
- }
-
- box->type = BOX_TEXT;
-
- box->text = talloc_strdup(ctx->bctx, current);
- if (box->text == NULL) {
- free(text);
- return false;
- }
-
- box->length = strlen(box->text);
-
- box_add_child(props.inline_container, box);
-
- current[len] = old;
-
- current += len;
-
- if (current[0] != '\0') {
- /* Linebreak: create new inline container */
- props.inline_container = box_create(NULL, NULL,
- false, NULL, NULL, NULL, NULL,
- ctx->bctx);
- if (props.inline_container == NULL) {
- free(text);
- return false;
- }
-
- props.inline_container->type =
- BOX_INLINE_CONTAINER;
-
- box_add_child(props.containing_block,
- props.inline_container);
-
- if (current[0] == '\r' && current[1] == '\n')
- current += 2;
- else
- current++;
- }
- } while (*current);
-
- free(text);
- }
-
- return true;
-}
-
-/**
- * Get the style for an element.
- *
- * \param c content of type CONTENT_HTML that is being processed
- * \param parent_style style at this point in xml tree, or NULL for root
- * \param root_style root node's style, or NULL for root
- * \param n node in xml tree
- * \return the new style, or NULL on memory exhaustion
- */
-css_select_results *box_get_style(html_content *c,
- const css_computed_style *parent_style,
- const css_computed_style *root_style, dom_node *n)
-{
- dom_string *s;
- dom_exception err;
- css_stylesheet *inline_style = NULL;
- css_select_results *styles;
- nscss_select_ctx ctx;
-
- /* Firstly, construct inline stylesheet, if any */
- err = dom_element_get_attribute(n, corestring_dom_style, &s);
- if (err != DOM_NO_ERR)
- return NULL;
-
- if (s != NULL) {
- inline_style = nscss_create_inline_style(
- (const uint8_t *) dom_string_data(s),
- dom_string_byte_length(s),
- c->encoding,
- nsurl_access(c->base_url),
- c->quirks != DOM_DOCUMENT_QUIRKS_MODE_NONE);
-
- dom_string_unref(s);
-
- if (inline_style == NULL)
- return NULL;
- }
-
- /* Populate selection context */
- ctx.ctx = c->select_ctx;
- ctx.quirks = (c->quirks == DOM_DOCUMENT_QUIRKS_MODE_FULL);
- ctx.base_url = c->base_url;
- ctx.universal = c->universal;
- ctx.root_style = root_style;
- ctx.parent_style = parent_style;
-
- /* Select style for element */
- styles = nscss_get_style(&ctx, n, CSS_MEDIA_SCREEN, inline_style);
-
- /* No longer need inline style */
- if (inline_style != NULL)
- css_stylesheet_destroy(inline_style);
-
- return styles;
-}
-
-
-/**
- * Apply the CSS text-transform property to given text for its ASCII chars.
- *
- * \param s string to transform
- * \param len length of s
- * \param tt transform type
- */
-
-void box_text_transform(char *s, unsigned int len, enum css_text_transform_e tt)
-{
- unsigned int i;
- if (len == 0)
- return;
- switch (tt) {
- case CSS_TEXT_TRANSFORM_UPPERCASE:
- for (i = 0; i < len; ++i)
- if ((unsigned char) s[i] < 0x80)
- s[i] = toupper(s[i]);
- break;
- case CSS_TEXT_TRANSFORM_LOWERCASE:
- for (i = 0; i < len; ++i)
- if ((unsigned char) s[i] < 0x80)
- s[i] = tolower(s[i]);
- break;
- case CSS_TEXT_TRANSFORM_CAPITALIZE:
- if ((unsigned char) s[0] < 0x80)
- s[0] = toupper(s[0]);
- for (i = 1; i < len; ++i)
- if ((unsigned char) s[i] < 0x80 &&
- isspace(s[i - 1]))
- s[i] = toupper(s[i]);
- break;
- default:
- break;
- }
-}
-
-
-/**
- * \name Special case element handlers
- *
- * These functions are called by box_construct_element() when an element is
- * being converted, according to the entries in element_table.
- *
- * The parameters are the xmlNode, the content for the document, and a partly
- * filled in box structure for the element.
- *
- * Return true on success, false on memory exhaustion. Set *convert_children
- * to false if children of this element in the XML tree should be skipped (for
- * example, if they have been processed in some special way already).
- *
- * Elements ordered as in the HTML 4.01 specification. Section numbers in
- * brackets [] refer to the spec.
- *
- * \{
- */
-
-/**
- * Document body [7.5.1].
- */
-
-bool box_body(BOX_SPECIAL_PARAMS)
-{
- css_color color;
-
- css_computed_background_color(box->style, &color);
- if (nscss_color_is_transparent(color))
- content->background_colour = NS_TRANSPARENT;
- else
- content->background_colour = nscss_color_to_ns(color);
-
- return true;
-}
-
-
-/**
- * Forced line break [9.3.2].
- */
-
-bool box_br(BOX_SPECIAL_PARAMS)
-{
- box->type = BOX_BR;
- return true;
-}
-
-/**
- * Preformatted text [9.3.4].
- */
-
-bool box_pre(BOX_SPECIAL_PARAMS)
-{
- box->flags |= PRE_STRIP;
- return true;
-}
-
-/**
- * Anchor [12.2].
- */
-
-bool box_a(BOX_SPECIAL_PARAMS)
-{
- bool ok;
- nsurl *url;
- dom_string *s;
- dom_exception err;
-
- err = dom_element_get_attribute(n, corestring_dom_href, &s);
- if (err == DOM_NO_ERR && s != NULL) {
- ok = box_extract_link(content, s, content->base_url, &url);
- dom_string_unref(s);
- if (!ok)
- return false;
- if (url) {
- if (box->href != NULL)
- nsurl_unref(box->href);
- box->href = url;
- }
- }
-
- /* name and id share the same namespace */
- err = dom_element_get_attribute(n, corestring_dom_name, &s);
- if (err == DOM_NO_ERR && s != NULL) {
- lwc_string *lwc_name;
-
- err = dom_string_intern(s, &lwc_name);
-
- dom_string_unref(s);
-
- if (err == DOM_NO_ERR) {
- /* name replaces existing id
- * TODO: really? */
- if (box->id != NULL)
- lwc_string_unref(box->id);
-
- box->id = lwc_name;
- }
- }
-
- /* target frame [16.3] */
- err = dom_element_get_attribute(n, corestring_dom_target, &s);
- if (err == DOM_NO_ERR && s != NULL) {
- if (dom_string_caseless_lwc_isequal(s,
- corestring_lwc__blank))
- box->target = TARGET_BLANK;
- else if (dom_string_caseless_lwc_isequal(s,
- corestring_lwc__top))
- box->target = TARGET_TOP;
- else if (dom_string_caseless_lwc_isequal(s,
- corestring_lwc__parent))
- box->target = TARGET_PARENT;
- else if (dom_string_caseless_lwc_isequal(s,
- corestring_lwc__self))
- /* the default may have been overridden by a
- * <base target=...>, so this is different to 0 */
- box->target = TARGET_SELF;
- else {
- /* 6.16 says that frame names must begin with [a-zA-Z]
- * This doesn't match reality, so just take anything */
- box->target = talloc_strdup(content->bctx,
- dom_string_data(s));
- if (!box->target) {
- dom_string_unref(s);
- return false;
- }
- }
- dom_string_unref(s);
- }
-
- return true;
-}
-
-
-/**
- * Embedded image [13.2].
- */
-
-bool box_image(BOX_SPECIAL_PARAMS)
-{
- bool ok;
- dom_string *s;
- dom_exception err;
- nsurl *url;
- enum css_width_e wtype;
- enum css_height_e htype;
- css_fixed value = 0;
- css_unit wunit = CSS_UNIT_PX;
- css_unit hunit = CSS_UNIT_PX;
-
- if (box->style && ns_computed_display(box->style,
- box_is_root(n)) == CSS_DISPLAY_NONE)
- return true;
-
- /* handle alt text */
- err = dom_element_get_attribute(n, corestring_dom_alt, &s);
- if (err == DOM_NO_ERR && s != NULL) {
- char *alt = squash_whitespace(dom_string_data(s));
- dom_string_unref(s);
- if (alt == NULL)
- return false;
- box->text = talloc_strdup(content->bctx, alt);
- free(alt);
- if (box->text == NULL)
- return false;
- box->length = strlen(box->text);
- }
-
- if (nsoption_bool(foreground_images) == false) {
- return true;
- }
-
- /* imagemap associated with this image */
- if (!box_get_attribute(n, "usemap", content->bctx, &box->usemap))
- return false;
- if (box->usemap && box->usemap[0] == '#')
- box->usemap++;
-
- /* get image URL */
- err = dom_element_get_attribute(n, corestring_dom_src, &s);
- if (err != DOM_NO_ERR || s == NULL)
- return true;
-
- if (box_extract_link(content, s, content->base_url, &url) == false) {
- dom_string_unref(s);
- return false;
- }
-
- dom_string_unref(s);
-
- if (url == NULL)
- return true;
-
- /* start fetch */
- box->flags |= IS_REPLACED;
- ok = html_fetch_object(content, url, box, image_types,
- content->base.available_width, 1000, false);
- nsurl_unref(url);
-
- wtype = css_computed_width(box->style, &value, &wunit);
- htype = css_computed_height(box->style, &value, &hunit);
-
- if (wtype == CSS_WIDTH_SET && wunit != CSS_UNIT_PCT &&
- htype == CSS_HEIGHT_SET && hunit != CSS_UNIT_PCT) {
- /* We know the dimensions the image will be shown at before it's
- * fetched. */
- box->flags |= REPLACE_DIM;
- }
-
- return ok;
-}
-
-
-/**
- * Noscript element
- */
-
-bool box_noscript(BOX_SPECIAL_PARAMS)
-{
- /* If scripting is enabled, do not display the contents of noscript */
- if (content->enable_scripting)
- *convert_children = false;
-
- return true;
-}
-
-
-/**
- * Destructor for object_params, for &lt;object&gt; elements
- *
- * \param o The object params being destroyed.
- * \return 0 to allow talloc to continue destroying the tree.
- */
-static int box_object_talloc_destructor(struct object_params *o)
-{
- if (o->codebase != NULL)
- nsurl_unref(o->codebase);
- if (o->classid != NULL)
- nsurl_unref(o->classid);
- if (o->data != NULL)
- nsurl_unref(o->data);
-
- return 0;
-}
-
-/**
- * Generic embedded object [13.3].
- */
-
-bool box_object(BOX_SPECIAL_PARAMS)
-{
- struct object_params *params;
- struct object_param *param;
- dom_string *codebase, *classid, *data;
- dom_node *c;
- dom_exception err;
-
- if (box->style && ns_computed_display(box->style,
- box_is_root(n)) == CSS_DISPLAY_NONE)
- return true;
-
- if (box_get_attribute(n, "usemap", content->bctx, &box->usemap) ==
- false)
- return false;
- if (box->usemap && box->usemap[0] == '#')
- box->usemap++;
-
- params = talloc(content->bctx, struct object_params);
- if (params == NULL)
- return false;
-
- talloc_set_destructor(params, box_object_talloc_destructor);
-
- params->data = NULL;
- params->type = NULL;
- params->codetype = NULL;
- params->codebase = NULL;
- params->classid = NULL;
- params->params = NULL;
-
- /* codebase, classid, and data are URLs
- * (codebase is the base for the other two) */
- err = dom_element_get_attribute(n, corestring_dom_codebase, &codebase);
- if (err == DOM_NO_ERR && codebase != NULL) {
- if (box_extract_link(content, codebase, content->base_url,
- &params->codebase) == false) {
- dom_string_unref(codebase);
- return false;
- }
- dom_string_unref(codebase);
- }
- if (params->codebase == NULL)
- params->codebase = nsurl_ref(content->base_url);
-
- err = dom_element_get_attribute(n, corestring_dom_classid, &classid);
- if (err == DOM_NO_ERR && classid != NULL) {
- if (box_extract_link(content, classid,
- params->codebase, &params->classid) == false) {
- dom_string_unref(classid);
- return false;
- }
- dom_string_unref(classid);
- }
-
- err = dom_element_get_attribute(n, corestring_dom_data, &data);
- if (err == DOM_NO_ERR && data != NULL) {
- if (box_extract_link(content, data,
- params->codebase, &params->data) == false) {
- dom_string_unref(data);
- return false;
- }
- dom_string_unref(data);
- }
-
- if (params->classid == NULL && params->data == NULL)
- /* nothing to embed; ignore */
- return true;
-
- /* Don't include ourself */
- if (params->classid != NULL && nsurl_compare(content->base_url,
- params->classid, NSURL_COMPLETE))
- return true;
-
- if (params->data != NULL && nsurl_compare(content->base_url,
- params->data, NSURL_COMPLETE))
- return true;
-
- /* codetype and type are MIME types */
- if (box_get_attribute(n, "codetype", params,
- &params->codetype) == false)
- return false;
- if (box_get_attribute(n, "type", params, &params->type) == false)
- return false;
-
- /* classid && !data => classid is used (consult codetype)
- * (classid || !classid) && data => data is used (consult type)
- * !classid && !data => invalid; ignored */
-
- if (params->classid != NULL && params->data == NULL &&
- params->codetype != NULL) {
- lwc_string *icodetype;
- lwc_error lerror;
-
- lerror = lwc_intern_string(params->codetype,
- strlen(params->codetype), &icodetype);
- if (lerror != lwc_error_ok)
- return false;
-
- if (content_factory_type_from_mime_type(icodetype) ==
- CONTENT_NONE) {
- /* can't handle this MIME type */
- lwc_string_unref(icodetype);
- return true;
- }
-
- lwc_string_unref(icodetype);
- }
-
- if (params->data != NULL && params->type != NULL) {
- lwc_string *itype;
- lwc_error lerror;
-
- lerror = lwc_intern_string(params->type, strlen(params->type),
- &itype);
- if (lerror != lwc_error_ok)
- return false;
-
- if (content_factory_type_from_mime_type(itype) ==
- CONTENT_NONE) {
- /* can't handle this MIME type */
- lwc_string_unref(itype);
- return true;
- }
-
- lwc_string_unref(itype);
- }
-
- /* add parameters to linked list */
- err = dom_node_get_first_child(n, &c);
- if (err != DOM_NO_ERR)
- return false;
-
- while (c != NULL) {
- dom_node *next;
- dom_node_type type;
-
- err = dom_node_get_node_type(c, &type);
- if (err != DOM_NO_ERR) {
- dom_node_unref(c);
- return false;
- }
-
- if (type == DOM_ELEMENT_NODE) {
- dom_string *name;
-
- err = dom_node_get_node_name(c, &name);
- if (err != DOM_NO_ERR) {
- dom_node_unref(c);
- return false;
- }
-
- if (!dom_string_caseless_lwc_isequal(name,
- corestring_lwc_param)) {
- /* The first non-param child is the start of
- * the alt html. Therefore, we should break
- * out of this loop. */
- dom_node_unref(c);
- break;
- }
-
- param = talloc(params, struct object_param);
- if (param == NULL) {
- dom_node_unref(c);
- return false;
- }
- param->name = NULL;
- param->value = NULL;
- param->type = NULL;
- param->valuetype = NULL;
- param->next = NULL;
-
- if (box_get_attribute(c, "name", param,
- &param->name) == false) {
- dom_node_unref(c);
- return false;
- }
-
- if (box_get_attribute(c, "value", param,
- &param->value) == false) {
- dom_node_unref(c);
- return false;
- }
-
- if (box_get_attribute(c, "type", param,
- &param->type) == false) {
- dom_node_unref(c);
- return false;
- }
-
- if (box_get_attribute(c, "valuetype", param,
- &param->valuetype) == false) {
- dom_node_unref(c);
- return false;
- }
-
- if (param->valuetype == NULL) {
- param->valuetype = talloc_strdup(param, "data");
- if (param->valuetype == NULL) {
- dom_node_unref(c);
- return false;
- }
- }
-
- param->next = params->params;
- params->params = param;
- }
-
- err = dom_node_get_next_sibling(c, &next);
- if (err != DOM_NO_ERR) {
- dom_node_unref(c);
- return false;
- }
-
- dom_node_unref(c);
- c = next;
- }
-
- box->object_params = params;
-
- /* start fetch (MIME type is ok or not specified) */
- box->flags |= IS_REPLACED;
- if (!html_fetch_object(content,
- params->data ? params->data : params->classid,
- box, CONTENT_ANY, content->base.available_width, 1000,
- false))
- return false;
-
- *convert_children = false;
- return true;
-}
-
-
-/**
- * Window subdivision [16.2.1].
- */
-
-bool box_frameset(BOX_SPECIAL_PARAMS)
-{
- bool ok;
-
- if (content->frameset) {
- NSLOG(netsurf, INFO, "Error: multiple framesets in document.");
- /* Don't convert children */
- if (convert_children)
- *convert_children = false;
- /* And ignore this spurious frameset */
- box->type = BOX_NONE;
- return true;
- }
-
- content->frameset = talloc_zero(content->bctx, struct content_html_frames);
- if (!content->frameset)
- return false;
-
- ok = box_create_frameset(content->frameset, n, content);
- if (ok)
- box->type = BOX_NONE;
-
- if (convert_children)
- *convert_children = false;
- return ok;
-}
-
-
-/**
- * Destructor for content_html_frames, for frame elements
- *
- * \param f The frame params being destroyed.
- * \return 0 to allow talloc to continue destroying the tree.
- */
-static int box_frames_talloc_destructor(struct content_html_frames *f)
-{
- if (f->url != NULL) {
- nsurl_unref(f->url);
- f->url = NULL;
- }
-
- return 0;
-}
-
-
-/**
- * Parse a multi-length-list, as defined by HTML 4.01.
- *
- * \param ds dom string to parse
- * \param count updated to number of entries
- * \return array of struct box_multi_length, or 0 on memory exhaustion
- */
-static struct frame_dimension *
-box_parse_multi_lengths(const dom_string *ds, unsigned int *count)
-{
- char *end;
- unsigned int i, n;
- struct frame_dimension *length;
- const char *s;
-
- s = dom_string_data(ds);
-
- for (i = 0, n = 1; s[i]; i++)
- if (s[i] == ',')
- n++;
-
- length = calloc(n, sizeof(struct frame_dimension));
- if (!length)
- return NULL;
-
- for (i = 0; i != n; i++) {
- while (ascii_is_space(*s)) {
- s++;
- }
- length[i].value = strtof(s, &end);
- if (length[i].value <= 0) {
- length[i].value = 1;
- }
- s = end;
- switch (*s) {
- case '%':
- length[i].unit = FRAME_DIMENSION_PERCENT;
- break;
- case '*':
- length[i].unit = FRAME_DIMENSION_RELATIVE;
- break;
- default:
- length[i].unit = FRAME_DIMENSION_PIXELS;
- break;
- }
- while (*s && *s != ',') {
- s++;
- }
- if (*s == ',') {
- s++;
- }
- }
-
- *count = n;
- return length;
-}
-
-
-bool box_create_frameset(struct content_html_frames *f, dom_node *n,
- html_content *content) {
- unsigned int row, col, index, i;
- unsigned int rows = 1, cols = 1;
- dom_string *s;
- dom_exception err;
- nsurl *url;
- struct frame_dimension *row_height = 0, *col_width = 0;
- dom_node *c, *next;
- struct content_html_frames *frame;
- bool default_border = true;
- colour default_border_colour = 0x000000;
-
- /* parse rows and columns */
- err = dom_element_get_attribute(n, corestring_dom_rows, &s);
- if (err == DOM_NO_ERR && s != NULL) {
- row_height = box_parse_multi_lengths(s, &rows);
- dom_string_unref(s);
- if (row_height == NULL)
- return false;
- } else {
- row_height = calloc(1, sizeof(struct frame_dimension));
- if (row_height == NULL)
- return false;
- row_height->value = 100;
- row_height->unit = FRAME_DIMENSION_PERCENT;
- }
-
- err = dom_element_get_attribute(n, corestring_dom_cols, &s);
- if (err == DOM_NO_ERR && s != NULL) {
- col_width = box_parse_multi_lengths(s, &cols);
- dom_string_unref(s);
- if (col_width == NULL) {
- free(row_height);
- return false;
- }
- } else {
- col_width = calloc(1, sizeof(struct frame_dimension));
- if (col_width == NULL) {
- free(row_height);
- return false;
- }
- col_width->value = 100;
- col_width->unit = FRAME_DIMENSION_PERCENT;
- }
-
- /* common extension: border="0|1" to control all children */
- err = dom_element_get_attribute(n, corestring_dom_border, &s);
- if (err == DOM_NO_ERR && s != NULL) {
- if ((dom_string_data(s)[0] == '0') &&
- (dom_string_data(s)[1] == '\0'))
- default_border = false;
- dom_string_unref(s);
- }
-
- /* common extension: frameborder="yes|no" to control all children */
- err = dom_element_get_attribute(n, corestring_dom_frameborder, &s);
- if (err == DOM_NO_ERR && s != NULL) {
- if (dom_string_caseless_lwc_isequal(s,
- corestring_lwc_no) == 0)
- default_border = false;
- dom_string_unref(s);
- }
-
- /* common extension: bordercolor="#RRGGBB|<named colour>" to control
- *all children */
- err = dom_element_get_attribute(n, corestring_dom_bordercolor, &s);
- if (err == DOM_NO_ERR && s != NULL) {
- css_color color;
-
- if (nscss_parse_colour(dom_string_data(s), &color))
- default_border_colour = nscss_color_to_ns(color);
-
- dom_string_unref(s);
- }
-
- /* update frameset and create default children */
- f->cols = cols;
- f->rows = rows;
- f->scrolling = BW_SCROLLING_NO;
- f->children = talloc_array(content->bctx, struct content_html_frames,
- (rows * cols));
-
- talloc_set_destructor(f->children, box_frames_talloc_destructor);
-
- for (row = 0; row < rows; row++) {
- for (col = 0; col < cols; col++) {
- index = (row * cols) + col;
- frame = &f->children[index];
- frame->cols = 0;
- frame->rows = 0;
- frame->width = col_width[col];
- frame->height = row_height[row];
- frame->margin_width = 0;
- frame->margin_height = 0;
- frame->name = NULL;
- frame->url = NULL;
- frame->no_resize = false;
- frame->scrolling = BW_SCROLLING_AUTO;
- frame->border = default_border;
- frame->border_colour = default_border_colour;
- frame->children = NULL;
- }
- }
- free(col_width);
- free(row_height);
-
- /* create the frameset windows */
- err = dom_node_get_first_child(n, &c);
- if (err != DOM_NO_ERR)
- return false;
-
- for (row = 0; c != NULL && row < rows; row++) {
- for (col = 0; c != NULL && col < cols; col++) {
- while (c != NULL) {
- dom_node_type type;
- dom_string *name;
-
- err = dom_node_get_node_type(c, &type);
- if (err != DOM_NO_ERR) {
- dom_node_unref(c);
- return false;
- }
-
- err = dom_node_get_node_name(c, &name);
- if (err != DOM_NO_ERR) {
- dom_node_unref(c);
- return false;
- }
-
- if (type != DOM_ELEMENT_NODE ||
- (!dom_string_caseless_lwc_isequal(
- name,
- corestring_lwc_frame) &&
- !dom_string_caseless_lwc_isequal(
- name,
- corestring_lwc_frameset
- ))) {
- err = dom_node_get_next_sibling(c,
- &next);
- if (err != DOM_NO_ERR) {
- dom_string_unref(name);
- dom_node_unref(c);
- return false;
- }
-
- dom_string_unref(name);
- dom_node_unref(c);
- c = next;
- } else {
- /* Got a FRAME or FRAMESET element */
- dom_string_unref(name);
- break;
- }
- }
-
- if (c == NULL)
- break;
-
- /* get current frame */
- index = (row * cols) + col;
- frame = &f->children[index];
-
- /* nest framesets */
- err = dom_node_get_node_name(c, &s);
- if (err != DOM_NO_ERR) {
- dom_node_unref(c);
- return false;
- }
-
- if (dom_string_caseless_lwc_isequal(s,
- corestring_lwc_frameset)) {
- dom_string_unref(s);
- frame->border = 0;
- if (box_create_frameset(frame, c,
- content) == false) {
- dom_node_unref(c);
- return false;
- }
-
- err = dom_node_get_next_sibling(c, &next);
- if (err != DOM_NO_ERR) {
- dom_node_unref(c);
- return false;
- }
-
- dom_node_unref(c);
- c = next;
- continue;
- }
-
- dom_string_unref(s);
-
- /* get frame URL (not required) */
- url = NULL;
- err = dom_element_get_attribute(c, corestring_dom_src, &s);
- if (err == DOM_NO_ERR && s != NULL) {
- box_extract_link(content, s, content->base_url,
- &url);
- dom_string_unref(s);
- }
-
- /* copy url */
- if (url != NULL) {
- /* no self-references */
- if (nsurl_compare(content->base_url, url,
- NSURL_COMPLETE) == false)
- frame->url = url;
- url = NULL;
- }
-
- /* fill in specified values */
- err = dom_element_get_attribute(c, corestring_dom_name, &s);
- if (err == DOM_NO_ERR && s != NULL) {
- frame->name = talloc_strdup(content->bctx,
- dom_string_data(s));
- dom_string_unref(s);
- }
-
- dom_element_has_attribute(c, corestring_dom_noresize,
- &frame->no_resize);
-
- err = dom_element_get_attribute(c, corestring_dom_frameborder,
- &s);
- if (err == DOM_NO_ERR && s != NULL) {
- i = atoi(dom_string_data(s));
- frame->border = (i != 0);
- dom_string_unref(s);
- }
-
- err = dom_element_get_attribute(c, corestring_dom_scrolling, &s);
- if (err == DOM_NO_ERR && s != NULL) {
- if (dom_string_caseless_lwc_isequal(s,
- corestring_lwc_yes))
- frame->scrolling = BW_SCROLLING_YES;
- else if (dom_string_caseless_lwc_isequal(s,
- corestring_lwc_no))
- frame->scrolling = BW_SCROLLING_NO;
- dom_string_unref(s);
- }
-
- err = dom_element_get_attribute(c, corestring_dom_marginwidth,
- &s);
- if (err == DOM_NO_ERR && s != NULL) {
- frame->margin_width = atoi(dom_string_data(s));
- dom_string_unref(s);
- }
-
- err = dom_element_get_attribute(c, corestring_dom_marginheight,
- &s);
- if (err == DOM_NO_ERR && s != NULL) {
- frame->margin_height = atoi(dom_string_data(s));
- dom_string_unref(s);
- }
-
- err = dom_element_get_attribute(c, corestring_dom_bordercolor,
- &s);
- if (err == DOM_NO_ERR && s != NULL) {
- css_color color;
-
- if (nscss_parse_colour(dom_string_data(s),
- &color))
- frame->border_colour =
- nscss_color_to_ns(color);
-
- dom_string_unref(s);
- }
-
- /* advance */
- err = dom_node_get_next_sibling(c, &next);
- if (err != DOM_NO_ERR) {
- dom_node_unref(c);
- return false;
- }
-
- dom_node_unref(c);
- c = next;
- }
- }
-
- /* If the last child wasn't a frame, we still need to unref it */
- if (c != NULL) {
- dom_node_unref(c);
- }
-
- return true;
-}
-
-
-/**
- * Destructor for content_html_iframe, for &lt;iframe&gt; elements
- *
- * \param f The iframe params being destroyed.
- * \return 0 to allow talloc to continue destroying the tree.
- */
-static int box_iframes_talloc_destructor(struct content_html_iframe *f)
-{
- if (f->url != NULL) {
- nsurl_unref(f->url);
- f->url = NULL;
- }
-
- return 0;
-}
-
-
-/**
- * Inline subwindow [16.5].
- */
-
-bool box_iframe(BOX_SPECIAL_PARAMS)
-{
- nsurl *url;
- dom_string *s;
- dom_exception err;
- struct content_html_iframe *iframe;
- int i;
-
- if (box->style && ns_computed_display(box->style,
- box_is_root(n)) == CSS_DISPLAY_NONE)
- return true;
-
- if (box->style && css_computed_visibility(box->style) ==
- CSS_VISIBILITY_HIDDEN)
- /* Don't create iframe discriptors for invisible iframes
- * TODO: handle hidden iframes at browser_window generation
- * time instead? */
- return true;
-
- /* get frame URL */
- err = dom_element_get_attribute(n, corestring_dom_src, &s);
- if (err != DOM_NO_ERR || s == NULL)
- return true;
- if (box_extract_link(content, s, content->base_url, &url) == false) {
- dom_string_unref(s);
- return false;
- }
- dom_string_unref(s);
- if (url == NULL)
- return true;
-
- /* don't include ourself */
- if (nsurl_compare(content->base_url, url, NSURL_COMPLETE)) {
- nsurl_unref(url);
- return true;
- }
-
- /* create a new iframe */
- iframe = talloc(content->bctx, struct content_html_iframe);
- if (iframe == NULL) {
- nsurl_unref(url);
- return false;
- }
-
- talloc_set_destructor(iframe, box_iframes_talloc_destructor);
-
- iframe->box = box;
- iframe->margin_width = 0;
- iframe->margin_height = 0;
- iframe->name = NULL;
- iframe->url = url;
- iframe->scrolling = BW_SCROLLING_AUTO;
- iframe->border = true;
-
- /* Add this iframe to the linked list of iframes */
- iframe->next = content->iframe;
- content->iframe = iframe;
-
- /* fill in specified values */
- err = dom_element_get_attribute(n, corestring_dom_name, &s);
- if (err == DOM_NO_ERR && s != NULL) {
- iframe->name = talloc_strdup(content->bctx, dom_string_data(s));
- dom_string_unref(s);
- }
-
- err = dom_element_get_attribute(n, corestring_dom_frameborder, &s);
- if (err == DOM_NO_ERR && s != NULL) {
- i = atoi(dom_string_data(s));
- iframe->border = (i != 0);
- dom_string_unref(s);
- }
-
- err = dom_element_get_attribute(n, corestring_dom_bordercolor, &s);
- if (err == DOM_NO_ERR && s != NULL) {
- css_color color;
-
- if (nscss_parse_colour(dom_string_data(s), &color))
- iframe->border_colour = nscss_color_to_ns(color);
-
- dom_string_unref(s);
- }
-
- err = dom_element_get_attribute(n, corestring_dom_scrolling, &s);
- if (err == DOM_NO_ERR && s != NULL) {
- if (dom_string_caseless_lwc_isequal(s,
- corestring_lwc_yes))
- iframe->scrolling = BW_SCROLLING_YES;
- else if (dom_string_caseless_lwc_isequal(s,
- corestring_lwc_no))
- iframe->scrolling = BW_SCROLLING_NO;
- dom_string_unref(s);
- }
-
- err = dom_element_get_attribute(n, corestring_dom_marginwidth, &s);
- if (err == DOM_NO_ERR && s != NULL) {
- iframe->margin_width = atoi(dom_string_data(s));
- dom_string_unref(s);
- }
-
- err = dom_element_get_attribute(n, corestring_dom_marginheight, &s);
- if (err == DOM_NO_ERR && s != NULL) {
- iframe->margin_height = atoi(dom_string_data(s));
- dom_string_unref(s);
- }
-
- /* box */
- assert(box->style);
- box->flags |= IFRAME;
- box->flags |= IS_REPLACED;
-
- /* Showing iframe, so don't show alternate content */
- if (convert_children)
- *convert_children = false;
- return true;
-}
-
-
-/**
- * Helper function for adding textarea widget to box.
- *
- * This is a load of hacks to ensure boxes replaced with textareas
- * can be handled by the layout code.
- */
-
-static bool box_input_text(html_content *html, struct box *box,
- struct dom_node *node)
-{
- struct box *inline_container, *inline_box;
-
- box->type = BOX_INLINE_BLOCK;
-
- inline_container = box_create(NULL, 0, false, 0, 0, 0, 0, html->bctx);
- if (!inline_container)
- return false;
- inline_container->type = BOX_INLINE_CONTAINER;
- inline_box = box_create(NULL, box->style, false, 0, 0, box->title, 0,
- html->bctx);
- if (!inline_box)
- return false;
- inline_box->type = BOX_TEXT;
- inline_box->text = talloc_strdup(html->bctx, "");
-
- box_add_child(inline_container, inline_box);
- box_add_child(box, inline_container);
-
- return box_textarea_create_textarea(html, box, node);
-}
-
-
-/**
- * Form control [17.4].
- */
-
-bool box_input(BOX_SPECIAL_PARAMS)
-{
- struct form_control *gadget = NULL;
- dom_string *type = NULL;
- dom_exception err;
- nsurl *url;
- nserror error;
-
- dom_element_get_attribute(n, corestring_dom_type, &type);
-
- gadget = html_forms_get_control_for_node(content->forms, n);
- if (gadget == NULL)
- goto no_memory;
- box->gadget = gadget;
- box->flags |= IS_REPLACED;
- gadget->box = box;
- gadget->html = content;
-
- if (type && dom_string_caseless_lwc_isequal(type,
- corestring_lwc_password)) {
- if (box_input_text(content, box, n) == false)
- goto no_memory;
-
- } else if (type && dom_string_caseless_lwc_isequal(type,
- corestring_lwc_file)) {
- box->type = BOX_INLINE_BLOCK;
-
- } else if (type && dom_string_caseless_lwc_isequal(type,
- corestring_lwc_hidden)) {
- /* no box for hidden inputs */
- box->type = BOX_NONE;
-
- } else if (type &&
- (dom_string_caseless_lwc_isequal(type,
- corestring_lwc_checkbox) ||
- dom_string_caseless_lwc_isequal(type,
- corestring_lwc_radio))) {
-
- } else if (type &&
- (dom_string_caseless_lwc_isequal(type,
- corestring_lwc_submit) ||
- dom_string_caseless_lwc_isequal(type,
- corestring_lwc_reset) ||
- dom_string_caseless_lwc_isequal(type,
- corestring_lwc_button))) {
- struct box *inline_container, *inline_box;
-
- if (box_button(n, content, box, 0) == false)
- goto no_memory;
-
- inline_container = box_create(NULL, 0, false, 0, 0, 0, 0,
- content->bctx);
- if (inline_container == NULL)
- goto no_memory;
-
- inline_container->type = BOX_INLINE_CONTAINER;
-
- inline_box = box_create(NULL, box->style, false, 0, 0,
- box->title, 0, content->bctx);
- if (inline_box == NULL)
- goto no_memory;
-
- inline_box->type = BOX_TEXT;
-
- if (box->gadget->value != NULL)
- inline_box->text = talloc_strdup(content->bctx,
- box->gadget->value);
- else if (box->gadget->type == GADGET_SUBMIT)
- inline_box->text = talloc_strdup(content->bctx,
- messages_get("Form_Submit"));
- else if (box->gadget->type == GADGET_RESET)
- inline_box->text = talloc_strdup(content->bctx,
- messages_get("Form_Reset"));
- else
- inline_box->text = talloc_strdup(content->bctx,
- "Button");
-
- if (inline_box->text == NULL)
- goto no_memory;
-
- inline_box->length = strlen(inline_box->text);
-
- box_add_child(inline_container, inline_box);
-
- box_add_child(box, inline_container);
-
- } else if (type && dom_string_caseless_lwc_isequal(type,
- corestring_lwc_image)) {
- gadget->type = GADGET_IMAGE;
-
- if (box->style && ns_computed_display(box->style,
- box_is_root(n)) != CSS_DISPLAY_NONE &&
- nsoption_bool(foreground_images) == true) {
- dom_string *s;
-
- err = dom_element_get_attribute(n, corestring_dom_src, &s);
- if (err == DOM_NO_ERR && s != NULL) {
- error = nsurl_join(content->base_url,
- dom_string_data(s), &url);
- dom_string_unref(s);
- if (error != NSERROR_OK)
- goto no_memory;
-
- /* if url is equivalent to the parent's url,
- * we've got infinite inclusion. stop it here
- */
- if (nsurl_compare(url, content->base_url,
- NSURL_COMPLETE) == false) {
- if (!html_fetch_object(content, url,
- box, image_types,
- content->base.
- available_width,
- 1000, false)) {
- nsurl_unref(url);
- goto no_memory;
- }
- }
- nsurl_unref(url);
- }
- }
- } else {
- /* the default type is "text" */
- if (box_input_text(content, box, n) == false)
- goto no_memory;
- }
-
- if (type)
- dom_string_unref(type);
-
- *convert_children = false;
- return true;
-
-no_memory:
- if (type)
- dom_string_unref(type);
-
- return false;
-}
-
-
-/**
- * Push button [17.5].
- */
-
-bool box_button(BOX_SPECIAL_PARAMS)
-{
- struct form_control *gadget;
-
- gadget = html_forms_get_control_for_node(content->forms, n);
- if (!gadget)
- return false;
-
- gadget->html = content;
- box->gadget = gadget;
- box->flags |= IS_REPLACED;
- gadget->box = box;
-
- box->type = BOX_INLINE_BLOCK;
-
- /* Just render the contents */
-
- return true;
-}
-
-
-/**
- * Option selector [17.6].
- */
-
-bool box_select(BOX_SPECIAL_PARAMS)
-{
- struct box *inline_container;
- struct box *inline_box;
- struct form_control *gadget;
- dom_node *c, *c2;
- dom_node *next, *next2;
- dom_exception err;
-
- gadget = html_forms_get_control_for_node(content->forms, n);
- if (gadget == NULL)
- return false;
-
- gadget->html = content;
- err = dom_node_get_first_child(n, &c);
- if (err != DOM_NO_ERR) {
- form_free_control(gadget);
- return false;
- }
-
- while (c != NULL) {
- dom_string *name;
-
- err = dom_node_get_node_name(c, &name);
- if (err != DOM_NO_ERR) {
- dom_node_unref(c);
- form_free_control(gadget);
- return false;
- }
-
- if (dom_string_caseless_lwc_isequal(name,
- corestring_lwc_option)) {
- dom_string_unref(name);
-
- if (box_select_add_option(gadget, c) == false) {
- dom_node_unref(c);
- form_free_control(gadget);
- return false;
- }
- } else if (dom_string_caseless_lwc_isequal(name,
- corestring_lwc_optgroup)) {
- dom_string_unref(name);
-
- err = dom_node_get_first_child(c, &c2);
- if (err != DOM_NO_ERR) {
- dom_node_unref(c);
- form_free_control(gadget);
- return false;
- }
-
- while (c2 != NULL) {
- dom_string *c2_name;
-
- err = dom_node_get_node_name(c2, &c2_name);
- if (err != DOM_NO_ERR) {
- dom_node_unref(c2);
- dom_node_unref(c);
- form_free_control(gadget);
- return false;
- }
-
- if (dom_string_caseless_lwc_isequal(c2_name,
- corestring_lwc_option)) {
- dom_string_unref(c2_name);
-
- if (box_select_add_option(gadget,
- c2) == false) {
- dom_node_unref(c2);
- dom_node_unref(c);
- return false;
- }
- } else {
- dom_string_unref(c2_name);
- }
-
- err = dom_node_get_next_sibling(c2, &next2);
- if (err != DOM_NO_ERR) {
- dom_node_unref(c2);
- dom_node_unref(c);
- return false;
- }
-
- dom_node_unref(c2);
- c2 = next2;
- }
- } else {
- dom_string_unref(name);
- }
-
- err = dom_node_get_next_sibling(c, &next);
- if (err != DOM_NO_ERR) {
- dom_node_unref(c);
- form_free_control(gadget);
- return false;
- }
-
- dom_node_unref(c);
- c = next;
- }
-
- if (gadget->data.select.num_items == 0) {
- /* no options: ignore entire select */
- form_free_control(gadget);
- return true;
- }
-
- box->type = BOX_INLINE_BLOCK;
- box->gadget = gadget;
- box->flags |= IS_REPLACED;
- gadget->box = box;
-
- inline_container = box_create(NULL, 0, false, 0, 0, 0, 0, content->bctx);
- if (inline_container == NULL)
- goto no_memory;
- inline_container->type = BOX_INLINE_CONTAINER;
- inline_box = box_create(NULL, box->style, false, 0, 0, box->title, 0,
- content->bctx);
- if (inline_box == NULL)
- goto no_memory;
- inline_box->type = BOX_TEXT;
- box_add_child(inline_container, inline_box);
- box_add_child(box, inline_container);
-
- if (gadget->data.select.multiple == false &&
- gadget->data.select.num_selected == 0) {
- gadget->data.select.current = gadget->data.select.items;
- gadget->data.select.current->initial_selected =
- gadget->data.select.current->selected = true;
- gadget->data.select.num_selected = 1;
- dom_html_option_element_set_selected(
- gadget->data.select.current->node, true);
- }
-
- if (gadget->data.select.num_selected == 0)
- inline_box->text = talloc_strdup(content->bctx,
- messages_get("Form_None"));
- else if (gadget->data.select.num_selected == 1)
- inline_box->text = talloc_strdup(content->bctx,
- gadget->data.select.current->text);
- else
- inline_box->text = talloc_strdup(content->bctx,
- messages_get("Form_Many"));
- if (inline_box->text == NULL)
- goto no_memory;
-
- inline_box->length = strlen(inline_box->text);
-
- *convert_children = false;
- return true;
-
-no_memory:
- return false;
-}
-
-
-/**
- * Add an option to a form select control (helper function for box_select()).
- *
- * \param control select containing the &lt;option&gt;
- * \param n xml element node for &lt;option&gt;
- * \return true on success, false on memory exhaustion
- */
-
-bool box_select_add_option(struct form_control *control, dom_node *n)
-{
- char *value = NULL;
- char *text = NULL;
- char *text_nowrap = NULL;
- bool selected;
- dom_string *content, *s;
- dom_exception err;
-
- err = dom_node_get_text_content(n, &content);
- if (err != DOM_NO_ERR)
- return false;
-
- if (content != NULL) {
- text = squash_whitespace(dom_string_data(content));
- dom_string_unref(content);
- } else {
- text = strdup("");
- }
-
- if (text == NULL)
- goto no_memory;
-
- err = dom_element_get_attribute(n, corestring_dom_value, &s);
- if (err == DOM_NO_ERR && s != NULL) {
- value = strdup(dom_string_data(s));
- dom_string_unref(s);
- } else {
- value = strdup(text);
- }
-
- if (value == NULL)
- goto no_memory;
-
- dom_element_has_attribute(n, corestring_dom_selected, &selected);
-
- /* replace spaces/TABs with hard spaces to prevent line wrapping */
- text_nowrap = cnv_space2nbsp(text);
- if (text_nowrap == NULL)
- goto no_memory;
-
- if (form_add_option(control, value, text_nowrap, selected, n) == false)
- goto no_memory;
-
- free(text);
-
- return true;
-
-no_memory:
- free(value);
- free(text);
- free(text_nowrap);
- return false;
-}
-
-
-/**
- * Multi-line text field [17.7].
- */
-
-bool box_textarea(BOX_SPECIAL_PARAMS)
-{
- /* Get the form_control for the DOM node */
- box->gadget = html_forms_get_control_for_node(content->forms, n);
- if (box->gadget == NULL)
- return false;
-
- box->flags |= IS_REPLACED;
- box->gadget->html = content;
- box->gadget->box = box;
-
- if (!box_input_text(content, box, n))
- return false;
-
- *convert_children = false;
- return true;
-}
-
-
-/**
- * Embedded object (not in any HTML specification:
- * see http://wp.netscape.com/assist/net_sites/new_html3_prop.html )
- */
-
-bool box_embed(BOX_SPECIAL_PARAMS)
-{
- struct object_params *params;
- struct object_param *param;
- dom_namednodemap *attrs;
- unsigned long idx;
- uint32_t num_attrs;
- dom_string *src;
- dom_exception err;
-
- if (box->style && ns_computed_display(box->style,
- box_is_root(n)) == CSS_DISPLAY_NONE)
- return true;
-
- params = talloc(content->bctx, struct object_params);
- if (params == NULL)
- return false;
-
- talloc_set_destructor(params, box_object_talloc_destructor);
-
- params->data = NULL;
- params->type = NULL;
- params->codetype = NULL;
- params->codebase = NULL;
- params->classid = NULL;
- params->params = NULL;
-
- /* src is a URL */
- err = dom_element_get_attribute(n, corestring_dom_src, &src);
- if (err != DOM_NO_ERR || src == NULL)
- return true;
- if (box_extract_link(content, src, content->base_url,
- &params->data) == false) {
- dom_string_unref(src);
- return false;
- }
-
- dom_string_unref(src);
-
- if (params->data == NULL)
- return true;
-
- /* Don't include ourself */
- if (nsurl_compare(content->base_url, params->data, NSURL_COMPLETE))
- return true;
-
- /* add attributes as parameters to linked list */
- err = dom_node_get_attributes(n, &attrs);
- if (err != DOM_NO_ERR)
- return false;
-
- err = dom_namednodemap_get_length(attrs, &num_attrs);
- if (err != DOM_NO_ERR) {
- dom_namednodemap_unref(attrs);
- return false;
- }
-
- for (idx = 0; idx < num_attrs; idx++) {
- dom_attr *attr;
- dom_string *name, *value;
-
- err = dom_namednodemap_item(attrs, idx, (void *) &attr);
- if (err != DOM_NO_ERR) {
- dom_namednodemap_unref(attrs);
- return false;
- }
-
- err = dom_attr_get_name(attr, &name);
- if (err != DOM_NO_ERR) {
- dom_namednodemap_unref(attrs);
- return false;
- }
-
- if (dom_string_caseless_lwc_isequal(name, corestring_lwc_src)) {
- dom_string_unref(name);
- continue;
- }
-
- err = dom_attr_get_value(attr, &value);
- if (err != DOM_NO_ERR) {
- dom_string_unref(name);
- dom_namednodemap_unref(attrs);
- return false;
- }
-
- param = talloc(content->bctx, struct object_param);
- if (param == NULL) {
- dom_string_unref(value);
- dom_string_unref(name);
- dom_namednodemap_unref(attrs);
- return false;
- }
-
- param->name = talloc_strdup(content->bctx, dom_string_data(name));
- param->value = talloc_strdup(content->bctx, dom_string_data(value));
- param->type = NULL;
- param->valuetype = talloc_strdup(content->bctx, "data");
- param->next = NULL;
-
- dom_string_unref(value);
- dom_string_unref(name);
-
- if (param->name == NULL || param->value == NULL ||
- param->valuetype == NULL) {
- dom_namednodemap_unref(attrs);
- return false;
- }
-
- param->next = params->params;
- params->params = param;
- }
-
- dom_namednodemap_unref(attrs);
-
- box->object_params = params;
-
- /* start fetch */
- box->flags |= IS_REPLACED;
- return html_fetch_object(content, params->data, box, CONTENT_ANY,
- content->base.available_width, 1000, false);
-}
-
-/**
- * \}
- */
-
-
-/**
- * Get the value of an XML element's attribute.
- *
- * \param n xmlNode, of type XML_ELEMENT_NODE
- * \param attribute name of attribute
- * \param context talloc context for result buffer
- * \param value updated to value, if the attribute is present
- * \return true on success, false if attribute present but memory exhausted
- *
- * Note that returning true does not imply that the attribute was found. If the
- * attribute was not found, *value will be unchanged.
- */
-
-bool box_get_attribute(dom_node *n, const char *attribute,
- void *context, char **value)
-{
- char *result;
- dom_string *attr, *attr_name;
- dom_exception err;
-
- err = dom_string_create_interned((const uint8_t *) attribute,
- strlen(attribute), &attr_name);
- if (err != DOM_NO_ERR)
- return false;
-
- err = dom_element_get_attribute(n, attr_name, &attr);
- if (err != DOM_NO_ERR) {
- dom_string_unref(attr_name);
- return false;
- }
-
- dom_string_unref(attr_name);
-
- if (attr != NULL) {
- result = talloc_strdup(context, dom_string_data(attr));
-
- dom_string_unref(attr);
-
- if (result == NULL)
- return false;
-
- *value = result;
- }
-
- return true;
-}
-
-
-/* exported function documented in render/box.h */
-bool
-box_extract_link(const html_content *content,
- const dom_string *dsrel,
- nsurl *base,
- nsurl **result)
-{
- char *s, *s1, *apos0 = 0, *apos1 = 0, *quot0 = 0, *quot1 = 0;
- unsigned int i, j, end;
- nserror error;
- const char *rel;
-
- rel = dom_string_data(dsrel);
-
- s1 = s = malloc(3 * strlen(rel) + 1);
- if (!s)
- return false;
-
- /* copy to s, removing white space and control characters */
- for (i = 0; rel[i] && ascii_is_space(rel[i]); i++)
- ;
- for (end = strlen(rel);
- (end != i) && ascii_is_space(rel[end - 1]);
- end--)
- ;
- for (j = 0; i != end; i++) {
- if ((unsigned char) rel[i] < 0x20) {
- ; /* skip control characters */
- } else if (rel[i] == ' ') {
- s[j++] = '%';
- s[j++] = '2';
- s[j++] = '0';
- } else {
- s[j++] = rel[i];
- }
- }
- s[j] = 0;
-
- if (content->enable_scripting == false) {
- /* extract first quoted string out of "javascript:" link */
- if (strncmp(s, "javascript:", 11) == 0) {
- apos0 = strchr(s, '\'');
- if (apos0)
- apos1 = strchr(apos0 + 1, '\'');
- quot0 = strchr(s, '"');
- if (quot0)
- quot1 = strchr(quot0 + 1, '"');
- if (apos0 && apos1 &&
- (!quot0 || !quot1 || apos0 < quot0)) {
- *apos1 = 0;
- s1 = apos0 + 1;
- } else if (quot0 && quot1) {
- *quot1 = 0;
- s1 = quot0 + 1;
- }
- }
- }
-
- /* construct absolute URL */
- error = nsurl_join(base, s1, result);
- free(s);
- if (error != NSERROR_OK) {
- *result = NULL;
- return false;
- }
-
- return true;
-}
-
-
-
diff --git a/render/box_normalise.c b/render/box_normalise.c
deleted file mode 100644
index 8da245754..000000000
--- a/render/box_normalise.c
+++ /dev/null
@@ -1,1046 +0,0 @@
-/*
- * Copyright 2005 James Bursa <bursa@users.sourceforge.net>
- * Copyright 2003 Phil Mellor <monkeyson@users.sourceforge.net>
- * Copyright 2005 John M Bell <jmb202@ecs.soton.ac.uk>
- * Copyright 2004 Kevin Bagust <kevin.bagust@ntlworld.com>
- *
- * This file is part of NetSurf, http://www.netsurf-browser.org/
- *
- * NetSurf is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * NetSurf is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-/** \file
- * Box tree normalisation (implementation).
- */
-
-#include <assert.h>
-#include <stdbool.h>
-#include <string.h>
-
-#include "utils/log.h"
-#include "utils/errors.h"
-#include "css/select.h"
-
-#include "render/box.h"
-#include "render/html_internal.h"
-#include "render/table.h"
-
-/* Define to enable box normalise debug */
-#undef BOX_NORMALISE_DEBUG
-
-/**
- * Row spanning information for a cell
- */
-struct span_info {
- /** Number of rows this cell spans */
- unsigned int row_span;
- /** Row group of cell */
- struct box *rg;
- /** The cell in this column spans all rows until the end of the table */
- bool auto_row;
-};
-
-/**
- * Column record for a table
- */
-struct columns {
- /** Current column index */
- unsigned int current_column;
- /** Number of columns in main part of table 1..max columns */
- unsigned int num_columns;
- /** Information about columns in main table, array [0, num_columns) */
- struct span_info *spans;
- /** Number of rows in table */
- unsigned int num_rows;
-};
-
-
-static bool box_normalise_table(
- struct box *table,
- const struct box *root,
- html_content *c);
-static bool box_normalise_table_spans(
- struct box *table,
- const struct box *root,
- struct span_info *spans,
- html_content *c);
-static bool box_normalise_table_row_group(
- struct box *row_group,
- const struct box *root,
- struct columns *col_info,
- html_content *c);
-static bool box_normalise_table_row(
- struct box *row,
- const struct box *root,
- struct columns *col_info,
- html_content *c);
-static bool calculate_table_row(struct columns *col_info,
- unsigned int col_span, unsigned int row_span,
- unsigned int *start_column, struct box *cell);
-static bool box_normalise_inline_container(
- struct box *cont,
- const struct box *root,
- html_content *c);
-
-/**
- * Ensure the box tree is correctly nested by adding and removing nodes.
- *
- * \param block box of type BLOCK, INLINE_BLOCK, or TABLE_CELL
- * \param root root box of document
- * \param c content of boxes
- * \return true on success, false on memory exhaustion
- *
- * The tree is modified to satisfy the following:
- * \code
- * parent permitted child nodes
- * BLOCK, INLINE_BLOCK BLOCK, INLINE_CONTAINER, TABLE
- * INLINE_CONTAINER INLINE, INLINE_BLOCK, FLOAT_LEFT, FLOAT_RIGHT, BR, TEXT
- * INLINE, TEXT none
- * TABLE at least 1 TABLE_ROW_GROUP
- * TABLE_ROW_GROUP at least 1 TABLE_ROW
- * TABLE_ROW at least 1 TABLE_CELL
- * TABLE_CELL BLOCK, INLINE_CONTAINER, TABLE (same as BLOCK)
- * FLOAT_(LEFT|RIGHT) exactly 1 BLOCK or TABLE
- * \endcode
- */
-
-bool box_normalise_block(
- struct box *block,
- const struct box *root,
- html_content *c)
-{
- struct box *child;
- struct box *next_child;
- struct box *table;
- css_computed_style *style;
- nscss_select_ctx ctx;
-
- assert(block != NULL);
- assert(root != NULL);
-
- ctx.root_style = root->style;
-
-#ifdef BOX_NORMALISE_DEBUG
- NSLOG(netsurf, INFO, "block %p, block->type %u", block, block->type);
-#endif
-
- assert(block->type == BOX_BLOCK || block->type == BOX_INLINE_BLOCK ||
- block->type == BOX_TABLE_CELL);
-
- for (child = block->children; child != NULL; child = next_child) {
-#ifdef BOX_NORMALISE_DEBUG
- NSLOG(netsurf, INFO, "child %p, child->type = %d", child,
- child->type);
-#endif
-
- next_child = child->next; /* child may be destroyed */
-
- switch (child->type) {
- case BOX_BLOCK:
- /* ok */
- if (box_normalise_block(child, root, c) == false)
- return false;
- break;
- case BOX_INLINE_CONTAINER:
- if (box_normalise_inline_container(child, root, c) == false)
- return false;
- break;
- case BOX_TABLE:
- if (box_normalise_table(child, root, c) == false)
- return false;
- break;
- case BOX_INLINE:
- case BOX_INLINE_END:
- case BOX_INLINE_BLOCK:
- case BOX_FLOAT_LEFT:
- case BOX_FLOAT_RIGHT:
- case BOX_BR:
- case BOX_TEXT:
- /* should have been wrapped in inline
- container by convert_xml_to_box() */
- assert(0);
- break;
- case BOX_TABLE_ROW_GROUP:
- case BOX_TABLE_ROW:
- case BOX_TABLE_CELL:
- /* insert implied table */
- assert(block->style != NULL);
-
- ctx.ctx = c->select_ctx;
- ctx.quirks = (c->quirks == DOM_DOCUMENT_QUIRKS_MODE_FULL);
- ctx.base_url = c->base_url;
- ctx.universal = c->universal;
-
- style = nscss_get_blank_style(&ctx, block->style);
- if (style == NULL)
- return false;
-
- table = box_create(NULL, style, true, block->href,
- block->target, NULL, NULL, c->bctx);
- if (table == NULL) {
- css_computed_style_destroy(style);
- return false;
- }
- table->type = BOX_TABLE;
-
- if (child->prev == NULL)
- block->children = table;
- else
- child->prev->next = table;
-
- table->prev = child->prev;
-
- while (child != NULL && (
- child->type == BOX_TABLE_ROW_GROUP ||
- child->type == BOX_TABLE_ROW ||
- child->type == BOX_TABLE_CELL)) {
- box_add_child(table, child);
-
- next_child = child->next;
- child->next = NULL;
- child = next_child;
- }
-
- table->last->next = NULL;
- table->next = next_child = child;
- if (table->next != NULL)
- table->next->prev = table;
- else
- block->last = table;
- table->parent = block;
-
- if (box_normalise_table(table, root, c) == false)
- return false;
- break;
- default:
- assert(0);
- }
- }
-
- return true;
-}
-
-
-bool box_normalise_table(
- struct box *table,
- const struct box *root,
- html_content * c)
-{
- struct box *child;
- struct box *next_child;
- struct box *row_group;
- css_computed_style *style;
- struct columns col_info;
- nscss_select_ctx ctx;
-
- assert(table != NULL);
- assert(table->type == BOX_TABLE);
-
- ctx.root_style = root->style;
-
-#ifdef BOX_NORMALISE_DEBUG
- NSLOG(netsurf, INFO, "table %p", table);
-#endif
-
- col_info.num_columns = 1;
- col_info.current_column = 0;
- col_info.spans = malloc(2 * sizeof *col_info.spans);
- if (col_info.spans == NULL)
- return false;
-
- col_info.spans[0].row_span = col_info.spans[1].row_span = 0;
- col_info.spans[0].auto_row = false;
- col_info.spans[1].auto_row = false;
- col_info.num_rows = 0;
-
- for (child = table->children; child != NULL; child = next_child) {
- next_child = child->next;
- switch (child->type) {
- case BOX_TABLE_ROW_GROUP:
- /* ok */
- if (box_normalise_table_row_group(child, root,
- &col_info, c) == false) {
- free(col_info.spans);
- return false;
- }
- break;
- case BOX_BLOCK:
- case BOX_INLINE_CONTAINER:
- case BOX_TABLE:
- case BOX_TABLE_ROW:
- case BOX_TABLE_CELL:
- /* insert implied table row group */
- assert(table->style != NULL);
-
- ctx.ctx = c->select_ctx;
- ctx.quirks = (c->quirks == DOM_DOCUMENT_QUIRKS_MODE_FULL);
- ctx.base_url = c->base_url;
- ctx.universal = c->universal;
-
- style = nscss_get_blank_style(&ctx, table->style);
- if (style == NULL) {
- free(col_info.spans);
- return false;
- }
-
- row_group = box_create(NULL, style, true, table->href,
- table->target, NULL, NULL, c->bctx);
- if (row_group == NULL) {
- css_computed_style_destroy(style);
- free(col_info.spans);
- return false;
- }
-
- row_group->type = BOX_TABLE_ROW_GROUP;
-
- if (child->prev == NULL)
- table->children = row_group;
- else
- child->prev->next = row_group;
-
- row_group->prev = child->prev;
-
- while (child != NULL && (
- child->type == BOX_BLOCK ||
- child->type == BOX_INLINE_CONTAINER ||
- child->type == BOX_TABLE ||
- child->type == BOX_TABLE_ROW ||
- child->type == BOX_TABLE_CELL)) {
- box_add_child(row_group, child);
-
- next_child = child->next;
- child->next = NULL;
- child = next_child;
- }
-
- assert(row_group->last != NULL);
-
- row_group->last->next = NULL;
- row_group->next = next_child = child;
- if (row_group->next != NULL)
- row_group->next->prev = row_group;
- else
- table->last = row_group;
- row_group->parent = table;
-
- if (box_normalise_table_row_group(row_group, root,
- &col_info, c) == false) {
- free(col_info.spans);
- return false;
- }
- break;
- case BOX_INLINE:
- case BOX_INLINE_END:
- case BOX_INLINE_BLOCK:
- case BOX_FLOAT_LEFT:
- case BOX_FLOAT_RIGHT:
- case BOX_BR:
- case BOX_TEXT:
- /* should have been wrapped in inline
- container by convert_xml_to_box() */
- assert(0);
- break;
- default:
- fprintf(stderr, "%i\n", child->type);
- assert(0);
- }
- }
-
- table->columns = col_info.num_columns;
- table->rows = col_info.num_rows;
-
- if (table->children == NULL) {
- struct box *row;
-
-#ifdef BOX_NORMALISE_DEBUG
- NSLOG(netsurf, INFO,
- "table->children == 0, creating implied row");
-#endif
-
- assert(table->style != NULL);
-
- ctx.ctx = c->select_ctx;
- ctx.quirks = (c->quirks == DOM_DOCUMENT_QUIRKS_MODE_FULL);
- ctx.base_url = c->base_url;
- ctx.universal = c->universal;
-
- style = nscss_get_blank_style(&ctx, table->style);
- if (style == NULL) {
- free(col_info.spans);
- return false;
- }
-
- row_group = box_create(NULL, style, true, table->href,
- table->target, NULL, NULL, c->bctx);
- if (row_group == NULL) {
- css_computed_style_destroy(style);
- free(col_info.spans);
- return false;
- }
- row_group->type = BOX_TABLE_ROW_GROUP;
-
- style = nscss_get_blank_style(&ctx, row_group->style);
- if (style == NULL) {
- box_free(row_group);
- free(col_info.spans);
- return false;
- }
-
- row = box_create(NULL, style, true, row_group->href,
- row_group->target, NULL, NULL, c->bctx);
- if (row == NULL) {
- css_computed_style_destroy(style);
- box_free(row_group);
- free(col_info.spans);
- return false;
- }
- row->type = BOX_TABLE_ROW;
-
- row->parent = row_group;
- row_group->children = row_group->last = row;
-
- row_group->parent = table;
- table->children = table->last = row_group;
-
- table->rows = 1;
- }
-
- if (box_normalise_table_spans(table, root, col_info.spans, c) == false) {
- free(col_info.spans);
- return false;
- }
-
- free(col_info.spans);
-
-#ifdef BOX_NORMALISE_DEBUG
- NSLOG(netsurf, INFO, "table %p done", table);
-#endif
-
- return true;
-}
-
-
-/**
- * Normalise table cell column/row counts for colspan/rowspan = 0.
- * Additionally, generate empty cells.
- *
- * \param table Table to process
- * \param root root box of document
- * \param spans Array of length table->columns for use in empty cell detection
- * \param c Content containing table
- * \return True on success, false on memory exhaustion.
- */
-
-bool box_normalise_table_spans(
- struct box *table,
- const struct box *root,
- struct span_info *spans,
- html_content *c)
-{
- struct box *table_row_group;
- struct box *table_row;
- struct box *table_cell;
- unsigned int rows_left = table->rows;
- unsigned int group_rows_left;
- unsigned int col;
- nscss_select_ctx ctx;
-
- ctx.root_style = root->style;
-
- /* Clear span data */
- memset(spans, 0, table->columns * sizeof(struct span_info));
-
- /* Scan table, filling in width and height of table cells with
- * colspan = 0 and rowspan = 0. Also generate empty cells */
- for (table_row_group = table->children;
- table_row_group != NULL;
- table_row_group = table_row_group->next) {
-
- group_rows_left = table_row_group->rows;
-
- for (table_row = table_row_group->children;
- table_row != NULL;
- table_row = table_row->next) {
-
- for (table_cell = table_row->children;
- table_cell != NULL;
- table_cell = table_cell->next) {
-
- /* colspan = 0 -> colspan = 1 */
- if (table_cell->columns == 0) {
- table_cell->columns = 1;
- }
-
- /* if rowspan is 0 it is expanded to
- * the number of rows left in the row
- * group
- */
- if (table_cell->rows == 0) {
- table_cell->rows = group_rows_left;
- }
-
- /* limit rowspans within group */
- if (table_cell->rows > group_rows_left) {
- table_cell->rows = group_rows_left;
- }
-
- /* Record span information */
- for (col = table_cell->start_column;
- col < table_cell->start_column +
- table_cell->columns; col++) {
- spans[col].row_span = table_cell->rows;
- }
- }
-
- /* Reduce span count of each column */
- for (col = 0; col < table->columns; col++) {
- if (spans[col].row_span == 0) {
- unsigned int start = col;
- css_computed_style *style;
- struct box *cell, *prev;
-
- /* If it's already zero, then we need
- * to generate an empty cell for the
- * gap in the row that spans as many
- * columns as remain blank.
- */
- assert(table_row->style != NULL);
-
- /* Find width of gap */
- while (col < table->columns &&
- spans[col].row_span ==
- 0) {
- col++;
- }
-
- ctx.ctx = c->select_ctx;
- ctx.quirks = (c->quirks ==
- DOM_DOCUMENT_QUIRKS_MODE_FULL);
- ctx.base_url = c->base_url;
- ctx.universal = c->universal;
-
- style = nscss_get_blank_style(&ctx,
- table_row->style);
- if (style == NULL)
- return false;
-
- cell = box_create(NULL, style, true,
- table_row->href,
- table_row->target,
- NULL, NULL, c->bctx);
- if (cell == NULL) {
- css_computed_style_destroy(
- style);
- return false;
- }
- cell->type = BOX_TABLE_CELL;
-
- cell->rows = 1;
- cell->columns = col - start;
- cell->start_column = start;
-
- /* Find place to insert cell */
- for (prev = table_row->children;
- prev != NULL;
- prev = prev->next) {
- if (prev->start_column +
- prev->columns ==
- start)
- break;
- if (prev->next == NULL)
- break;
- }
-
- /* Insert it */
- if (prev == NULL) {
- if (table_row->children != NULL)
- table_row->children->
- prev = cell;
- else
- table_row->last = cell;
-
- cell->next =
- table_row->children;
- table_row->children = cell;
- } else {
- if (prev->next != NULL)
- prev->next->prev = cell;
- else
- table_row->last = cell;
-
- cell->next = prev->next;
- prev->next = cell;
- cell->prev = prev;
- }
- cell->parent = table_row;
- } else {
- spans[col].row_span--;
- }
- }
-
- assert(rows_left > 0);
-
- rows_left--;
- }
-
- group_rows_left--;
- }
-
- return true;
-}
-
-
-bool box_normalise_table_row_group(
- struct box *row_group,
- const struct box *root,
- struct columns *col_info,
- html_content * c)
-{
- struct box *child;
- struct box *next_child;
- struct box *row;
- css_computed_style *style;
- nscss_select_ctx ctx;
- unsigned int group_row_count = 0;
-
- assert(row_group != 0);
- assert(row_group->type == BOX_TABLE_ROW_GROUP);
-
- ctx.root_style = root->style;
-
-#ifdef BOX_NORMALISE_DEBUG
- NSLOG(netsurf, INFO, "row_group %p", row_group);
-#endif
-
- for (child = row_group->children; child != NULL; child = next_child) {
- next_child = child->next;
-
- switch (child->type) {
- case BOX_TABLE_ROW:
- /* ok */
- group_row_count++;
- if (box_normalise_table_row(child, root, col_info,
- c) == false)
- return false;
- break;
- case BOX_BLOCK:
- case BOX_INLINE_CONTAINER:
- case BOX_TABLE:
- case BOX_TABLE_ROW_GROUP:
- case BOX_TABLE_CELL:
- /* insert implied table row */
- assert(row_group->style != NULL);
-
- ctx.ctx = c->select_ctx;
- ctx.quirks = (c->quirks == DOM_DOCUMENT_QUIRKS_MODE_FULL);
- ctx.base_url = c->base_url;
- ctx.universal = c->universal;
-
- style = nscss_get_blank_style(&ctx, row_group->style);
- if (style == NULL)
- return false;
-
- row = box_create(NULL, style, true, row_group->href,
- row_group->target, NULL, NULL, c->bctx);
- if (row == NULL) {
- css_computed_style_destroy(style);
- return false;
- }
- row->type = BOX_TABLE_ROW;
-
- if (child->prev == NULL)
- row_group->children = row;
- else
- child->prev->next = row;
-
- row->prev = child->prev;
-
- while (child != NULL && (
- child->type == BOX_BLOCK ||
- child->type == BOX_INLINE_CONTAINER ||
- child->type == BOX_TABLE ||
- child->type == BOX_TABLE_ROW_GROUP ||
- child->type == BOX_TABLE_CELL)) {
- box_add_child(row, child);
-
- next_child = child->next;
- child->next = NULL;
- child = next_child;
- }
-
- assert(row->last != NULL);
-
- row->last->next = NULL;
- row->next = next_child = child;
- if (row->next != NULL)
- row->next->prev = row;
- else
- row_group->last = row;
- row->parent = row_group;
-
- group_row_count++;
- if (box_normalise_table_row(row, root, col_info,
- c) == false)
- return false;
- break;
- case BOX_INLINE:
- case BOX_INLINE_END:
- case BOX_INLINE_BLOCK:
- case BOX_FLOAT_LEFT:
- case BOX_FLOAT_RIGHT:
- case BOX_BR:
- case BOX_TEXT:
- /* should have been wrapped in inline
- container by convert_xml_to_box() */
- assert(0);
- break;
- default:
- assert(0);
- }
- }
-
- if (row_group->children == NULL) {
-#ifdef BOX_NORMALISE_DEBUG
- NSLOG(netsurf, INFO,
- "row_group->children == 0, inserting implied row");
-#endif
-
- assert(row_group->style != NULL);
-
- ctx.ctx = c->select_ctx;
- ctx.quirks = (c->quirks == DOM_DOCUMENT_QUIRKS_MODE_FULL);
- ctx.base_url = c->base_url;
- ctx.universal = c->universal;
-
- style = nscss_get_blank_style(&ctx, row_group->style);
- if (style == NULL) {
- return false;
- }
-
- row = box_create(NULL, style, true, row_group->href,
- row_group->target, NULL, NULL, c->bctx);
- if (row == NULL) {
- css_computed_style_destroy(style);
- return false;
- }
- row->type = BOX_TABLE_ROW;
-
- row->parent = row_group;
- row_group->children = row_group->last = row;
-
- group_row_count = 1;
-
- /* Keep table's row count in sync */
- col_info->num_rows++;
- }
-
- row_group->rows = group_row_count;
-
-#ifdef BOX_NORMALISE_DEBUG
- NSLOG(netsurf, INFO, "row_group %p done", row_group);
-#endif
-
- return true;
-}
-
-
-bool box_normalise_table_row(
- struct box *row,
- const struct box *root,
- struct columns *col_info,
- html_content * c)
-{
- struct box *child;
- struct box *next_child;
- struct box *cell = NULL;
- css_computed_style *style;
- unsigned int i;
- nscss_select_ctx ctx;
-
- assert(row != NULL);
- assert(row->type == BOX_TABLE_ROW);
-
- ctx.root_style = root->style;
-
-#ifdef BOX_NORMALISE_DEBUG
- NSLOG(netsurf, INFO, "row %p", row);
-#endif
-
- for (child = row->children; child != NULL; child = next_child) {
- next_child = child->next;
-
- switch (child->type) {
- case BOX_TABLE_CELL:
- /* ok */
- if (box_normalise_block(child, root, c) == false)
- return false;
- cell = child;
- break;
- case BOX_BLOCK:
- case BOX_INLINE_CONTAINER:
- case BOX_TABLE:
- case BOX_TABLE_ROW_GROUP:
- case BOX_TABLE_ROW:
- /* insert implied table cell */
- assert(row->style != NULL);
-
- ctx.ctx = c->select_ctx;
- ctx.quirks = (c->quirks == DOM_DOCUMENT_QUIRKS_MODE_FULL);
- ctx.base_url = c->base_url;
- ctx.universal = c->universal;
-
- style = nscss_get_blank_style(&ctx, row->style);
- if (style == NULL)
- return false;
-
- cell = box_create(NULL, style, true, row->href,
- row->target, NULL, NULL, c->bctx);
- if (cell == NULL) {
- css_computed_style_destroy(style);
- return false;
- }
- cell->type = BOX_TABLE_CELL;
-
- if (child->prev == NULL)
- row->children = cell;
- else
- child->prev->next = cell;
-
- cell->prev = child->prev;
-
- while (child != NULL && (
- child->type == BOX_BLOCK ||
- child->type == BOX_INLINE_CONTAINER ||
- child->type == BOX_TABLE ||
- child->type == BOX_TABLE_ROW_GROUP ||
- child->type == BOX_TABLE_ROW)) {
- box_add_child(cell, child);
-
- next_child = child->next;
- child->next = NULL;
- child = next_child;
- }
-
- assert(cell->last != NULL);
-
- cell->last->next = NULL;
- cell->next = next_child = child;
- if (cell->next != NULL)
- cell->next->prev = cell;
- else
- row->last = cell;
- cell->parent = row;
-
- if (box_normalise_block(cell, root, c) == false)
- return false;
- break;
- case BOX_INLINE:
- case BOX_INLINE_END:
- case BOX_INLINE_BLOCK:
- case BOX_FLOAT_LEFT:
- case BOX_FLOAT_RIGHT:
- case BOX_BR:
- case BOX_TEXT:
- /* should have been wrapped in inline
- container by convert_xml_to_box() */
- assert(0);
- break;
- default:
- assert(0);
- }
-
- if (calculate_table_row(col_info, cell->columns, cell->rows,
- &cell->start_column, cell) == false)
- return false;
- }
-
-
- /* Update row spanning details for all columns */
- for (i = 0; i < col_info->num_columns; i++) {
- if (col_info->spans[i].row_span != 0 &&
- col_info->spans[i].auto_row == false) {
- /* This cell spans rows, and is not an auto row.
- * Reduce number of rows left to span */
- col_info->spans[i].row_span--;
- }
- }
-
- /* Reset current column for next row */
- col_info->current_column = 0;
-
- /* Increment row counter */
- col_info->num_rows++;
-
-#ifdef BOX_NORMALISE_DEBUG
- NSLOG(netsurf, INFO, "row %p done", row);
-#endif
-
- return true;
-}
-
-
-/**
- * Compute the column index at which the current cell begins.
- * Additionally, update the column record to reflect row spanning.
- *
- * \param col_info Column record
- * \param col_span Number of columns that current cell spans
- * \param row_span Number of rows that current cell spans
- * \param start_column Pointer to location to receive column index
- * \param cell Box for current table cell
- * \return true on success, false on memory exhaustion
- */
-
-bool calculate_table_row(struct columns *col_info,
- unsigned int col_span, unsigned int row_span,
- unsigned int *start_column, struct box *cell)
-{
- unsigned int cell_start_col = col_info->current_column;
- unsigned int cell_end_col;
- unsigned int i;
- struct span_info *spans;
- struct box *rg = cell->parent->parent; /* Cell's row group */
-
- /* Skip columns with cells spanning from above */
- /* TODO: Need to ignore cells spanning from above that belong to
- * different row group. We don't have that info here. */
- while (col_info->spans[cell_start_col].row_span != 0 &&
- col_info->spans[cell_start_col].rg == rg) {
- cell_start_col++;
- }
-
- /* Update current column with calculated start */
- col_info->current_column = cell_start_col;
-
- /* If this cell has a colspan of 0, then assume 1.
- * No other browser supports colspan=0, anyway. */
- if (col_span == 0)
- col_span = 1;
-
- cell_end_col = cell_start_col + col_span;
-
- if (col_info->num_columns < cell_end_col) {
- /* It appears that this row has more columns than
- * the maximum recorded for the table so far.
- * Allocate more span records. */
- spans = realloc(col_info->spans,
- sizeof *spans * (cell_end_col + 1));
- if (spans == NULL)
- return false;
-
- col_info->spans = spans;
- col_info->num_columns = cell_end_col;
-
- /* Mark new final column as sentinel */
- col_info->spans[cell_end_col].row_span = 0;
- col_info->spans[cell_end_col].auto_row = false;
- }
-
- /* This cell may span multiple columns. If it also wants to span
- * multiple rows, temporarily assume it spans 1 row only. This will
- * be fixed up in box_normalise_table_spans() */
- for (i = cell_start_col; i < cell_end_col; i++) {
- col_info->spans[i].row_span = (row_span == 0) ? 1 : row_span;
- col_info->spans[i].auto_row = (row_span == 0);
- col_info->spans[i].rg = rg;
- }
-
- /* Update current column with calculated end. */
- col_info->current_column = cell_end_col;
-
- *start_column = cell_start_col;
-
- return true;
-}
-
-
-bool box_normalise_inline_container(
- struct box *cont,
- const struct box *root,
- html_content * c)
-{
- struct box *child;
- struct box *next_child;
-
- assert(cont != NULL);
- assert(cont->type == BOX_INLINE_CONTAINER);
-
-#ifdef BOX_NORMALISE_DEBUG
- NSLOG(netsurf, INFO, "cont %p", cont);
-#endif
-
- for (child = cont->children; child != NULL; child = next_child) {
- next_child = child->next;
- switch (child->type) {
- case BOX_INLINE:
- case BOX_INLINE_END:
- case BOX_BR:
- case BOX_TEXT:
- /* ok */
- break;
- case BOX_INLINE_BLOCK:
- /* ok */
- if (box_normalise_block(child, root, c) == false)
- return false;
- break;
- case BOX_FLOAT_LEFT:
- case BOX_FLOAT_RIGHT:
- /* ok */
- assert(child->children != NULL);
-
- switch (child->children->type) {
- case BOX_BLOCK:
- if (box_normalise_block(child->children, root,
- c) == false)
- return false;
- break;
- case BOX_TABLE:
- if (box_normalise_table(child->children, root,
- c) == false)
- return false;
- break;
- default:
- assert(0);
- }
-
- if (child->children == NULL) {
- /* the child has destroyed itself: remove float */
- if (child->prev == NULL)
- child->parent->children = child->next;
- else
- child->prev->next = child->next;
- if (child->next != NULL)
- child->next->prev = child->prev;
- else
- child->parent->last = child->prev;
-
- box_free(child);
- }
- break;
- case BOX_BLOCK:
- case BOX_INLINE_CONTAINER:
- case BOX_TABLE:
- case BOX_TABLE_ROW_GROUP:
- case BOX_TABLE_ROW:
- case BOX_TABLE_CELL:
- default:
- assert(0);
- }
- }
-
-#ifdef BOX_NORMALISE_DEBUG
- NSLOG(netsurf, INFO, "cont %p done", cont);
-#endif
-
- return true;
-}
diff --git a/render/box_textarea.c b/render/box_textarea.c
deleted file mode 100644
index a60984235..000000000
--- a/render/box_textarea.c
+++ /dev/null
@@ -1,350 +0,0 @@
-/*
- * Copyright 2013 Michael Drake <tlsa@netsurf-browser.org>
- *
- * This file is part of NetSurf, http://www.netsurf-browser.org/
- *
- * NetSurf is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * NetSurf is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-/** \file
- * Box tree treeview box replacement (implementation).
- */
-
-#include <dom/dom.h>
-
-#include "utils/config.h"
-#include "utils/log.h"
-#include "netsurf/keypress.h"
-#include "desktop/textarea.h"
-
-#include "render/box_textarea.h"
-#include "render/font.h"
-#include "render/form_internal.h"
-
-
-bool box_textarea_keypress(html_content *html, struct box *box, uint32_t key)
-{
- struct form_control *gadget = box->gadget;
- struct textarea *ta = gadget->data.text.ta;
- struct form* form = box->gadget->form;
- struct content *c = (struct content *) html;
-
- assert(ta != NULL);
-
- if (gadget->type != GADGET_TEXTAREA) {
- switch (key) {
- case NS_KEY_NL:
- case NS_KEY_CR:
- if (form)
- form_submit(content_get_url(c), html->bw,
- form, 0);
- return true;
-
- case NS_KEY_TAB:
- {
- struct form_control *next_input;
- /* Find next text entry field that is actually
- * displayed (i.e. has an associated box) */
- for (next_input = gadget->next;
- next_input &&
- ((next_input->type != GADGET_TEXTBOX &&
- next_input->type != GADGET_TEXTAREA &&
- next_input->type != GADGET_PASSWORD) ||
- !next_input->box);
- next_input = next_input->next)
- ;
- if (!next_input)
- return true;
-
- textarea_set_caret(ta, -1);
- textarea_set_caret(next_input->data.text.ta, 0);
- }
- return true;
-
- case NS_KEY_SHIFT_TAB:
- {
- struct form_control *prev_input;
- /* Find previous text entry field that is actually
- * displayed (i.e. has an associated box) */
- for (prev_input = gadget->prev;
- prev_input &&
- ((prev_input->type != GADGET_TEXTBOX &&
- prev_input->type != GADGET_TEXTAREA &&
- prev_input->type != GADGET_PASSWORD) ||
- !prev_input->box);
- prev_input = prev_input->prev)
- ;
- if (!prev_input)
- return true;
-
- textarea_set_caret(ta, -1);
- textarea_set_caret(prev_input->data.text.ta, 0);
- }
- return true;
-
- default:
- /* Pass to textarea widget */
- break;
- }
- }
-
- return textarea_keypress(ta, key);
-}
-
-
-/**
- * Callback for html form textareas.
- */
-static void box_textarea_callback(void *data, struct textarea_msg *msg)
-{
- struct form_textarea_data *d = data;
- struct form_control *gadget = d->gadget;
- struct html_content *html = d->gadget->html;
- struct box *box = gadget->box;
-
- switch (msg->type) {
- case TEXTAREA_MSG_DRAG_REPORT:
- if (msg->data.drag == TEXTAREA_DRAG_NONE) {
- /* Textarea drag finished */
- html_drag_type drag_type = HTML_DRAG_NONE;
- union html_drag_owner drag_owner;
- drag_owner.no_owner = true;
-
- html_set_drag_type(html, drag_type, drag_owner,
- NULL);
- } else {
- /* Textarea drag started */
- struct rect rect = {
- .x0 = INT_MIN,
- .y0 = INT_MIN,
- .x1 = INT_MAX,
- .y1 = INT_MAX
- };
- union html_drag_owner drag_owner;
- drag_owner.textarea = box;
-
- switch (msg->data.drag) {
- case TEXTAREA_DRAG_SCROLLBAR:
- html_set_drag_type(html,
- HTML_DRAG_TEXTAREA_SCROLLBAR,
- drag_owner,
- &rect);
- break;
-
- case TEXTAREA_DRAG_SELECTION:
- html_set_drag_type(html,
- HTML_DRAG_TEXTAREA_SELECTION,
- drag_owner,
- &rect);
- break;
-
- default:
- NSLOG(netsurf, INFO,
- "Drag type %d not handled.",
- msg->data.drag);
- /* This is a logic faliure in the
- * front end code so abort.
- */
- assert(0);
- break;
- }
- }
- break;
-
- case TEXTAREA_MSG_REDRAW_REQUEST:
- {
- /* Request redraw of the required textarea rectangle */
- int x, y;
-
- if (html->reflowing == true) {
- /* Can't redraw during layout, and it will
- * be redrawn after layout anyway. */
- break;
- }
-
- box_coords(box, &x, &y);
-
- content__request_redraw((struct content *)html,
- x + msg->data.redraw.x0,
- y + msg->data.redraw.y0,
- msg->data.redraw.x1 - msg->data.redraw.x0,
- msg->data.redraw.y1 - msg->data.redraw.y0);
- }
- break;
-
- case TEXTAREA_MSG_SELECTION_REPORT:
- if (msg->data.selection.have_selection) {
- /* Textarea now has a selection */
- union html_selection_owner sel_owner;
- sel_owner.textarea = box;
-
- html_set_selection(html, HTML_SELECTION_TEXTAREA,
- sel_owner,
- msg->data.selection.read_only);
- } else {
- /* The textarea now has no selection */
- union html_selection_owner sel_owner;
- sel_owner.none = true;
-
- html_set_selection(html, HTML_SELECTION_NONE,
- sel_owner, true);
- }
- break;
-
- case TEXTAREA_MSG_CARET_UPDATE:
- if (html->bw == NULL)
- break;
-
- if (msg->data.caret.type == TEXTAREA_CARET_HIDE) {
- union html_focus_owner focus_owner;
- focus_owner.textarea = box;
- html_set_focus(html, HTML_FOCUS_TEXTAREA,
- focus_owner, true, 0, 0, 0, NULL);
- } else {
- union html_focus_owner focus_owner;
- focus_owner.textarea = box;
- html_set_focus(html, HTML_FOCUS_TEXTAREA,
- focus_owner, false,
- msg->data.caret.pos.x,
- msg->data.caret.pos.y,
- msg->data.caret.pos.height,
- msg->data.caret.pos.clip);
- }
- break;
-
- case TEXTAREA_MSG_TEXT_MODIFIED:
- form_gadget_update_value(gadget,
- strndup(msg->data.modified.text,
- msg->data.modified.len));
- break;
- }
-}
-
-
-/* Exported interface, documented in box_textarea.h */
-bool box_textarea_create_textarea(html_content *html,
- struct box *box, struct dom_node *node)
-{
- dom_string *dom_text = NULL;
- dom_exception err;
- textarea_setup ta_setup;
- textarea_flags ta_flags;
- plot_font_style_t fstyle = {
- .family = PLOT_FONT_FAMILY_SANS_SERIF,
- .size = 10 * FONT_SIZE_SCALE,
- .weight = 400,
- .flags = FONTF_NONE,
- .background = 0,
- .foreground = 0,
- };
- bool read_only = false;
- bool disabled = false;
- struct form_control *gadget = box->gadget;
- const char *text;
-
- assert(gadget != NULL);
- assert(gadget->type == GADGET_TEXTAREA ||
- gadget->type == GADGET_TEXTBOX ||
- gadget->type == GADGET_PASSWORD);
-
- if (gadget->type == GADGET_TEXTAREA) {
- dom_html_text_area_element *textarea =
- (dom_html_text_area_element *) node;
- ta_flags = TEXTAREA_MULTILINE;
-
- err = dom_html_text_area_element_get_read_only(
- textarea, &read_only);
- if (err != DOM_NO_ERR)
- return false;
-
- err = dom_html_text_area_element_get_disabled(
- textarea, &disabled);
- if (err != DOM_NO_ERR)
- return false;
-
- /* Get the textarea's initial content */
- err = dom_html_text_area_element_get_value(textarea, &dom_text);
- if (err != DOM_NO_ERR)
- return false;
-
- } else {
- dom_html_input_element *input = (dom_html_input_element *) node;
-
- err = dom_html_input_element_get_read_only(
- input, &read_only);
- if (err != DOM_NO_ERR)
- return false;
-
- err = dom_html_input_element_get_disabled(
- input, &disabled);
- if (err != DOM_NO_ERR)
- return false;
-
- if (gadget->type == GADGET_PASSWORD)
- ta_flags = TEXTAREA_PASSWORD;
- else
- ta_flags = TEXTAREA_DEFAULT;
-
- /* Get initial text */
- err = dom_html_input_element_get_value(input, &dom_text);
- if (err != DOM_NO_ERR)
- return false;
- }
-
- if (dom_text != NULL) {
- text = dom_string_data(dom_text);
- } else {
- /* No initial text, or failed reading it;
- * use a blank string */
- text = "";
- }
-
- if (read_only || disabled)
- ta_flags |= TEXTAREA_READONLY;
-
- gadget->data.text.data.gadget = gadget;
-
- /* Reset to correct values by layout */
- ta_setup.width = 200;
- ta_setup.height = 20;
- ta_setup.pad_top = 4;
- ta_setup.pad_right = 4;
- ta_setup.pad_bottom = 4;
- ta_setup.pad_left = 4;
-
- /* Set remaining data */
- ta_setup.border_width = 0;
- ta_setup.border_col = 0x000000;
- ta_setup.text = fstyle;
- ta_setup.text.background = NS_TRANSPARENT;
- /* Make selected text either black or white, as gives greatest contrast
- * with background colour. */
- ta_setup.selected_bg = fstyle.foreground;
- ta_setup.selected_text = colour_to_bw_furthest(ta_setup.selected_bg);
-
- /* Hand reference to dom text over to gadget */
- gadget->data.text.initial = dom_text;
-
- gadget->data.text.ta = textarea_create(ta_flags, &ta_setup,
- box_textarea_callback, &gadget->data.text.data);
-
- if (gadget->data.text.ta == NULL) {
- return false;
- }
-
- if (!textarea_set_text(gadget->data.text.ta, text))
- return false;
-
- return true;
-}
-
diff --git a/render/box_textarea.h b/render/box_textarea.h
deleted file mode 100644
index a7a377076..000000000
--- a/render/box_textarea.h
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * Copyright 2013 Michael Drake <tlsa@netsurf-browser.org>
- *
- * This file is part of NetSurf, http://www.netsurf-browser.org/
- *
- * NetSurf is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * NetSurf is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-/** \file
- * Box tree treeview box replacement (interface).
- */
-
-
-
-#ifndef _NETSURF_RENDER_BOX_TEXTAREA_H_
-#define _NETSURF_RENDER_BOX_TEXTAREA_H_
-
-
-#include "render/box.h"
-#include "render/html_internal.h"
-
-struct dom_node;
-
-/**
- * Create textarea widget for a form element
- *
- * \param html html content object
- * \param box box with gadget to be given textarea widget
- * \param node DOM node for form element
- */
-bool box_textarea_create_textarea(html_content *html,
- struct box *box, struct dom_node *node);
-
-
-/**
- * Handle form textarea keypress input
- *
- * \param html html content object
- * \param box box with textarea widget
- * \param key keypress
- * \return true iff keypress handled
- */
-bool box_textarea_keypress(html_content *html, struct box *box, uint32_t key);
-
-#endif
diff --git a/render/font.c b/render/font.c
deleted file mode 100644
index a769b476f..000000000
--- a/render/font.c
+++ /dev/null
@@ -1,163 +0,0 @@
-/*
- * Copyright 2009 John-Mark Bell <jmb@netsurf-browser.org>
- *
- * This file is part of NetSurf, http://www.netsurf-browser.org/
- *
- * NetSurf is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * NetSurf is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-/**
- * \file
- *
- * Renderer internal font handling implementation.
- */
-
-#include "utils/nsoption.h"
-#include "netsurf/plot_style.h"
-#include "css/utils.h"
-
-#include "render/font.h"
-
-/**
- * Map a generic CSS font family to a generic plot font family
- *
- * \param css Generic CSS font family
- * \return Plot font family
- */
-static plot_font_generic_family_t plot_font_generic_family(
- enum css_font_family_e css)
-{
- plot_font_generic_family_t plot;
-
- switch (css) {
- case CSS_FONT_FAMILY_SERIF:
- plot = PLOT_FONT_FAMILY_SERIF;
- break;
- case CSS_FONT_FAMILY_MONOSPACE:
- plot = PLOT_FONT_FAMILY_MONOSPACE;
- break;
- case CSS_FONT_FAMILY_CURSIVE:
- plot = PLOT_FONT_FAMILY_CURSIVE;
- break;
- case CSS_FONT_FAMILY_FANTASY:
- plot = PLOT_FONT_FAMILY_FANTASY;
- break;
- case CSS_FONT_FAMILY_SANS_SERIF:
- default:
- plot = PLOT_FONT_FAMILY_SANS_SERIF;
- break;
- }
-
- return plot;
-}
-
-/**
- * Map a CSS font weight to a plot weight value
- *
- * \param css CSS font weight
- * \return Plot weight
- */
-static int plot_font_weight(enum css_font_weight_e css)
-{
- int weight;
-
- switch (css) {
- case CSS_FONT_WEIGHT_100:
- weight = 100;
- break;
- case CSS_FONT_WEIGHT_200:
- weight = 200;
- break;
- case CSS_FONT_WEIGHT_300:
- weight = 300;
- break;
- case CSS_FONT_WEIGHT_400:
- case CSS_FONT_WEIGHT_NORMAL:
- default:
- weight = 400;
- break;
- case CSS_FONT_WEIGHT_500:
- weight = 500;
- break;
- case CSS_FONT_WEIGHT_600:
- weight = 600;
- break;
- case CSS_FONT_WEIGHT_700:
- case CSS_FONT_WEIGHT_BOLD:
- weight = 700;
- break;
- case CSS_FONT_WEIGHT_800:
- weight = 800;
- break;
- case CSS_FONT_WEIGHT_900:
- weight = 900;
- break;
- }
-
- return weight;
-}
-
-/**
- * Map a CSS font style and font variant to plot font flags
- *
- * \param style CSS font style
- * \param variant CSS font variant
- * \return Computed plot flags
- */
-static plot_font_flags_t plot_font_flags(enum css_font_style_e style,
- enum css_font_variant_e variant)
-{
- plot_font_flags_t flags = FONTF_NONE;
-
- if (style == CSS_FONT_STYLE_ITALIC)
- flags |= FONTF_ITALIC;
- else if (style == CSS_FONT_STYLE_OBLIQUE)
- flags |= FONTF_OBLIQUE;
-
- if (variant == CSS_FONT_VARIANT_SMALL_CAPS)
- flags |= FONTF_SMALLCAPS;
-
- return flags;
-}
-
-
-/* exported function documented in render/font.h */
-void font_plot_style_from_css(
- const nscss_len_ctx *len_ctx,
- const css_computed_style *css,
- plot_font_style_t *fstyle)
-{
- lwc_string **families;
- css_fixed length = 0;
- css_unit unit = CSS_UNIT_PX;
- css_color col;
-
- fstyle->family = plot_font_generic_family(
- css_computed_font_family(css, &families));
-
- css_computed_font_size(css, &length, &unit);
- fstyle->size = FIXTOINT(FMUL(nscss_len2pt(len_ctx, length, unit),
- INTTOFIX(FONT_SIZE_SCALE)));
-
- /* Clamp font size to configured minimum */
- if (fstyle->size < (nsoption_int(font_min_size) * FONT_SIZE_SCALE) / 10)
- fstyle->size = (nsoption_int(font_min_size) * FONT_SIZE_SCALE) / 10;
-
- fstyle->weight = plot_font_weight(css_computed_font_weight(css));
- fstyle->flags = plot_font_flags(css_computed_font_style(css),
- css_computed_font_variant(css));
-
- css_computed_color(css, &col);
- fstyle->foreground = nscss_color_to_ns(col);
- fstyle->background = 0;
-}
diff --git a/render/font.h b/render/font.h
deleted file mode 100644
index 52f5a62c2..000000000
--- a/render/font.h
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * Copyright 2014 Vincent Sanders <vince@netsurf-browser.org>
- *
- * This file is part of NetSurf, http://www.netsurf-browser.org/
- *
- * NetSurf is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * NetSurf is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-/** \file
- *
- * Internal font handling interfaces.
- *
- * These functions provide font related services. They all work on
- * UTF-8 strings with lengths given.
- */
-
-#ifndef _NETSURF_RENDER_FONT_H_
-#define _NETSURF_RENDER_FONT_H_
-
-struct plot_font_style;
-
-/**
- * Populate a font style using data from a computed CSS style
- *
- * \param len_ctx Length conversion context
- * \param css Computed style to consider
- * \param fstyle Font style to populate
- */
-void font_plot_style_from_css(
- const nscss_len_ctx *len_ctx,
- const css_computed_style *css,
- struct plot_font_style *fstyle);
-
-#endif
diff --git a/render/form.c b/render/form.c
deleted file mode 100644
index 432002564..000000000
--- a/render/form.c
+++ /dev/null
@@ -1,1895 +0,0 @@
-/*
- * Copyright 2004 James Bursa <bursa@users.sourceforge.net>
- * Copyright 2003 Phil Mellor <monkeyson@users.sourceforge.net>
- * Copyright 2004 John Tytgat <joty@netsurf-browser.org>
- * Copyright 2005-9 John-Mark Bell <jmb@netsurf-browser.org>
- * Copyright 2009 Paul Blokus <paul_pl@users.sourceforge.net>
- * Copyright 2010 Michael Drake <tlsa@netsurf-browser.org>
- *
- * This file is part of NetSurf, http://www.netsurf-browser.org/
- *
- * NetSurf is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * NetSurf is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-/**
- * \file
- * Form handling functions (implementation).
- */
-
-#include <assert.h>
-#include <limits.h>
-#include <stdbool.h>
-#include <stdio.h>
-#include <string.h>
-#include <dom/dom.h>
-
-#include "utils/corestrings.h"
-#include "utils/log.h"
-#include "utils/messages.h"
-#include "utils/talloc.h"
-#include "utils/url.h"
-#include "utils/utf8.h"
-#include "utils/ascii.h"
-#include "netsurf/browser_window.h"
-#include "netsurf/mouse.h"
-#include "netsurf/plotters.h"
-#include "netsurf/misc.h"
-#include "content/fetch.h"
-#include "content/hlcache.h"
-#include "css/utils.h"
-#include "desktop/knockout.h"
-#include "desktop/scrollbar.h"
-#include "desktop/textarea.h"
-#include "desktop/gui_internal.h"
-
-#include "render/box.h"
-#include "render/font.h"
-#include "render/form_internal.h"
-#include "render/html.h"
-#include "render/html_internal.h"
-#include "render/layout.h"
-
-#define MAX_SELECT_HEIGHT 210
-#define SELECT_LINE_SPACING 0.2
-#define SELECT_BORDER_WIDTH 1
-#define SELECT_SELECTED_COLOUR 0xDB9370
-
-struct form_select_menu {
- int line_height;
- int width, height;
- struct scrollbar *scrollbar;
- int f_size;
- bool scroll_capture;
- select_menu_redraw_callback callback;
- void *client_data;
- struct content *c;
-};
-
-static plot_style_t plot_style_fill_selected = {
- .fill_type = PLOT_OP_TYPE_SOLID,
- .fill_colour = SELECT_SELECTED_COLOUR,
-};
-
-static plot_font_style_t plot_fstyle_entry = {
- .family = PLOT_FONT_FAMILY_SANS_SERIF,
- .weight = 400,
- .flags = FONTF_NONE,
- .background = 0xffffff,
- .foreground = 0x000000,
-};
-
-static char *form_acceptable_charset(struct form *form);
-static char *form_encode_item(const char *item, uint32_t len, const char *charset,
- const char *fallback);
-static void form_select_menu_clicked(struct form_control *control,
- int x, int y);
-static void form_select_menu_scroll_callback(void *client_data,
- struct scrollbar_msg_data *scrollbar_data);
-
-/* exported interface documented in render/form_internal.h */
-struct form *form_new(void *node, const char *action, const char *target,
- form_method method, const char *charset,
- const char *doc_charset)
-{
- struct form *form;
-
- form = calloc(1, sizeof *form);
- if (!form)
- return NULL;
-
- form->action = strdup(action != NULL ? action : "");
- if (form->action == NULL) {
- free(form);
- return NULL;
- }
-
- form->target = target != NULL ? strdup(target) : NULL;
- if (target != NULL && form->target == NULL) {
- free(form->action);
- free(form);
- return NULL;
- }
-
- form->method = method;
-
- form->accept_charsets = charset != NULL ? strdup(charset) : NULL;
- if (charset != NULL && form->accept_charsets == NULL) {
- free(form->target);
- free(form->action);
- free(form);
- return NULL;
- }
-
- form->document_charset = doc_charset != NULL ? strdup(doc_charset)
- : NULL;
- if (doc_charset && form->document_charset == NULL) {
- free(form->accept_charsets);
- free(form->target);
- free(form->action);
- free(form);
- return NULL;
- }
-
- form->node = node;
-
- return form;
-}
-
-
-/* exported interface documented in render/form_internal.h */
-void form_free(struct form *form)
-{
- struct form_control *c, *d;
-
- for (c = form->controls; c != NULL; c = d) {
- d = c->next;
-
- form_free_control(c);
- }
-
- free(form->action);
- free(form->target);
- free(form->accept_charsets);
- free(form->document_charset);
-
- free(form);
-}
-
-/* exported interface documented in render/form_internal.h */
-struct form_control *form_new_control(void *node, form_control_type type)
-{
- struct form_control *control;
-
- control = calloc(1, sizeof *control);
- if (control == NULL)
- return NULL;
-
- control->node = node;
- control->type = type;
-
- return control;
-}
-
-
-/**
- * Add a control to the list of controls in a form.
- *
- * \param form The form to add the control to
- * \param control The control to add
- */
-void form_add_control(struct form *form, struct form_control *control)
-{
- if (form == NULL) {
- return;
- }
-
- control->form = form;
-
- if (form->controls != NULL) {
- assert(form->last_control);
-
- form->last_control->next = control;
- control->prev = form->last_control;
- control->next = NULL;
- form->last_control = control;
- } else {
- form->controls = form->last_control = control;
- }
-}
-
-
-/**
- * Free a struct form_control.
- *
- * \param control structure to free
- */
-void form_free_control(struct form_control *control)
-{
- struct form_control *c;
- assert(control != NULL);
-
- NSLOG(netsurf, INFO, "Control:%p name:%p value:%p initial:%p",
- control, control->name, control->value, control->initial_value);
- free(control->name);
- free(control->value);
- free(control->initial_value);
-
- if (control->type == GADGET_SELECT) {
- struct form_option *option, *next;
-
- for (option = control->data.select.items; option;
- option = next) {
- next = option->next;
- NSLOG(netsurf, INFO,
- "select option:%p text:%p value:%p", option,
- option->text, option->value);
- free(option->text);
- free(option->value);
- free(option);
- }
- if (control->data.select.menu != NULL) {
- form_free_select_menu(control);
- }
- }
-
- if (control->type == GADGET_TEXTAREA ||
- control->type == GADGET_TEXTBOX ||
- control->type == GADGET_PASSWORD) {
-
- if (control->data.text.initial != NULL) {
- dom_string_unref(control->data.text.initial);
- }
-
- if (control->data.text.ta != NULL) {
- textarea_destroy(control->data.text.ta);
- }
- }
-
- /* unlink the control from the form */
- if (control->form != NULL) {
- for (c = control->form->controls; c != NULL; c = c->next) {
- if (c->next == control) {
- c->next = control->next;
- if (control->form->last_control == control)
- control->form->last_control = c;
- break;
- }
- if (c == control) {
- /* can only happen if control was first control */
- control->form->controls = control->next;
- if (control->form->last_control == control)
- control->form->controls =
- control->form->last_control = NULL;
- break;
- }
- }
- }
-
- free(control);
-}
-
-
-/**
- * Add an option to a form select control.
- *
- * \param control form control of type GADGET_SELECT
- * \param value value of option, used directly (not copied)
- * \param text text for option, used directly (not copied)
- * \param selected this option is selected
- * \param node the DOM node this option is associated with
- * \return true on success, false on memory exhaustion
- */
-bool form_add_option(struct form_control *control, char *value, char *text,
- bool selected, void *node)
-{
- struct form_option *option;
-
- assert(control);
- assert(control->type == GADGET_SELECT);
-
- option = calloc(1, sizeof *option);
- if (!option)
- return false;
-
- option->value = value;
- option->text = text;
-
- /* add to linked list */
- if (control->data.select.items == 0)
- control->data.select.items = option;
- else
- control->data.select.last_item->next = option;
- control->data.select.last_item = option;
-
- /* set selected */
- if (selected && (control->data.select.num_selected == 0 ||
- control->data.select.multiple)) {
- option->selected = option->initial_selected = true;
- control->data.select.num_selected++;
- control->data.select.current = option;
- }
-
- control->data.select.num_items++;
-
- option->node = node;
-
- return true;
-}
-
-
-/* exported interface documented in render/form_internal.h */
-bool form_successful_controls_dom(struct form *_form,
- struct form_control *_submit_button,
- struct fetch_multipart_data **successful_controls)
-{
- dom_html_form_element *form = _form->node;
- dom_html_element *submit_button = (_submit_button != NULL) ? _submit_button->node : NULL;
- dom_html_collection *form_elements = NULL;
- dom_html_options_collection *options = NULL;
- dom_node *form_element = NULL, *option_element = NULL;
- dom_exception err;
- dom_string *nodename = NULL, *inputname = NULL, *inputvalue = NULL, *inputtype = NULL;
- struct fetch_multipart_data sentinel, *last_success, *success_new;
- bool had_submit = false, element_disabled, checked;
- char *charset, *rawfile_temp = NULL, *basename;
- uint32_t index, element_count;
- struct image_input_coords *coords;
-
- last_success = &sentinel;
- sentinel.next = NULL;
-
- /** \todo Replace this call with something DOMish */
- charset = form_acceptable_charset(_form);
- if (charset == NULL) {
- NSLOG(netsurf, INFO, "failed to find charset");
- return false;
- }
-
-#define ENCODE_ITEM(i) (((i) == NULL) ? ( \
- form_encode_item("", 0, charset, _form->document_charset) \
- ):( \
- form_encode_item(dom_string_data(i), dom_string_byte_length(i), \
- charset, _form->document_charset) \
- ))
-
- err = dom_html_form_element_get_elements(form, &form_elements);
-
- if (err != DOM_NO_ERR) {
- NSLOG(netsurf, INFO, "Could not get form elements");
- goto dom_no_memory;
- }
-
-
- err = dom_html_collection_get_length(form_elements, &element_count);
-
- if (err != DOM_NO_ERR) {
- NSLOG(netsurf, INFO, "Could not get form element count");
- goto dom_no_memory;
- }
-
- for (index = 0; index < element_count; index++) {
- if (form_element != NULL) {
- dom_node_unref(form_element);
- form_element = NULL;
- }
- if (nodename != NULL) {
- dom_string_unref(nodename);
- nodename = NULL;
- }
- if (inputname != NULL) {
- dom_string_unref(inputname);
- inputname = NULL;
- }
- if (inputvalue != NULL) {
- dom_string_unref(inputvalue);
- inputvalue = NULL;
- }
- if (inputtype != NULL) {
- dom_string_unref(inputtype);
- inputtype = NULL;
- }
- if (options != NULL) {
- dom_html_options_collection_unref(options);
- options = NULL;
- }
- err = dom_html_collection_item(form_elements,
- index, &form_element);
- if (err != DOM_NO_ERR) {
- NSLOG(netsurf, INFO,
- "Could not retrieve form element %d", index);
- goto dom_no_memory;
- }
-
- /* Form elements are one of:
- * HTMLButtonElement
- * HTMLInputElement
- * HTMLTextAreaElement
- * HTMLSelectElement
- */
- err = dom_node_get_node_name(form_element, &nodename);
- if (err != DOM_NO_ERR) {
- NSLOG(netsurf, INFO, "Could not get node name");
- goto dom_no_memory;
- }
-
- if (dom_string_isequal(nodename, corestring_dom_TEXTAREA)) {
- err = dom_html_text_area_element_get_disabled(
- (dom_html_text_area_element *)form_element,
- &element_disabled);
- if (err != DOM_NO_ERR) {
- NSLOG(netsurf, INFO,
- "Could not get text area disabled property");
- goto dom_no_memory;
- }
- err = dom_html_text_area_element_get_name(
- (dom_html_text_area_element *)form_element,
- &inputname);
- if (err != DOM_NO_ERR) {
- NSLOG(netsurf, INFO,
- "Could not get text area name property");
- goto dom_no_memory;
- }
- } else if (dom_string_isequal(nodename, corestring_dom_SELECT)) {
- err = dom_html_select_element_get_disabled(
- (dom_html_select_element *)form_element,
- &element_disabled);
- if (err != DOM_NO_ERR) {
- NSLOG(netsurf, INFO,
- "Could not get select disabled property");
- goto dom_no_memory;
- }
- err = dom_html_select_element_get_name(
- (dom_html_select_element *)form_element,
- &inputname);
- if (err != DOM_NO_ERR) {
- NSLOG(netsurf, INFO,
- "Could not get select name property");
- goto dom_no_memory;
- }
- } else if (dom_string_isequal(nodename, corestring_dom_INPUT)) {
- err = dom_html_input_element_get_disabled(
- (dom_html_input_element *)form_element,
- &element_disabled);
- if (err != DOM_NO_ERR) {
- NSLOG(netsurf, INFO,
- "Could not get input disabled property");
- goto dom_no_memory;
- }
- err = dom_html_input_element_get_name(
- (dom_html_input_element *)form_element,
- &inputname);
- if (err != DOM_NO_ERR) {
- NSLOG(netsurf, INFO,
- "Could not get input name property");
- goto dom_no_memory;
- }
- } else if (dom_string_isequal(nodename, corestring_dom_BUTTON)) {
- err = dom_html_button_element_get_disabled(
- (dom_html_button_element *)form_element,
- &element_disabled);
- if (err != DOM_NO_ERR) {
- NSLOG(netsurf, INFO,
- "Could not get button disabled property");
- goto dom_no_memory;
- }
- err = dom_html_button_element_get_name(
- (dom_html_button_element *)form_element,
- &inputname);
- if (err != DOM_NO_ERR) {
- NSLOG(netsurf, INFO,
- "Could not get button name property");
- goto dom_no_memory;
- }
- } else {
- /* Unknown element type came through! */
- NSLOG(netsurf, INFO, "Unknown element type: %*s",
- (int)dom_string_byte_length(nodename),
- dom_string_data(nodename));
- goto dom_no_memory;
- }
- if (element_disabled)
- continue;
- if (inputname == NULL)
- continue;
-
- if (dom_string_isequal(nodename, corestring_dom_TEXTAREA)) {
- err = dom_html_text_area_element_get_value(
- (dom_html_text_area_element *)form_element,
- &inputvalue);
- if (err != DOM_NO_ERR) {
- NSLOG(netsurf, INFO,
- "Could not get text area content");
- goto dom_no_memory;
- }
- } else if (dom_string_isequal(nodename, corestring_dom_SELECT)) {
- uint32_t options_count, option_index;
- err = dom_html_select_element_get_options(
- (dom_html_select_element *)form_element,
- &options);
- if (err != DOM_NO_ERR) {
- NSLOG(netsurf, INFO,
- "Could not get select options collection");
- goto dom_no_memory;
- }
- err = dom_html_options_collection_get_length(
- options, &options_count);
- if (err != DOM_NO_ERR) {
- NSLOG(netsurf, INFO,
- "Could not get select options collection length");
- goto dom_no_memory;
- }
- for(option_index = 0; option_index < options_count;
- ++option_index) {
- bool selected;
- if (option_element != NULL) {
- dom_node_unref(option_element);
- option_element = NULL;
- }
- if (inputvalue != NULL) {
- dom_string_unref(inputvalue);
- inputvalue = NULL;
- }
- err = dom_html_options_collection_item(
- options, option_index, &option_element);
- if (err != DOM_NO_ERR) {
- NSLOG(netsurf, INFO,
- "Could not get options item %d",
- option_index);
- goto dom_no_memory;
- }
- err = dom_html_option_element_get_selected(
- (dom_html_option_element *)option_element,
- &selected);
- if (err != DOM_NO_ERR) {
- NSLOG(netsurf, INFO,
- "Could not get option selected property");
- goto dom_no_memory;
- }
- if (!selected)
- continue;
- err = dom_html_option_element_get_value(
- (dom_html_option_element *)option_element,
- &inputvalue);
- if (err != DOM_NO_ERR) {
- NSLOG(netsurf, INFO,
- "Could not get option value");
- goto dom_no_memory;
- }
-
- success_new = calloc(1, sizeof(*success_new));
- if (success_new == NULL) {
- NSLOG(netsurf, INFO,
- "Could not allocate data for option");
- goto dom_no_memory;
- }
-
- last_success->next = success_new;
- last_success = success_new;
-
- success_new->name = ENCODE_ITEM(inputname);
- if (success_new->name == NULL) {
- NSLOG(netsurf, INFO,
- "Could not encode name for option");
- goto dom_no_memory;
- }
- success_new->value = ENCODE_ITEM(inputvalue);
- if (success_new->value == NULL) {
- NSLOG(netsurf, INFO,
- "Could not encode value for option");
- goto dom_no_memory;
- }
- }
- continue;
- } else if (dom_string_isequal(nodename, corestring_dom_BUTTON)) {
- err = dom_html_button_element_get_type(
- (dom_html_button_element *) form_element,
- &inputtype);
- if (err != DOM_NO_ERR) {
- NSLOG(netsurf, INFO,
- "Could not get button element type");
- goto dom_no_memory;
- }
- if (dom_string_caseless_isequal(
- inputtype, corestring_dom_submit)) {
-
- if (submit_button == NULL && !had_submit) {
- /* no button used, and first submit
- * node found, so use it
- */
- had_submit = true;
- } else if ((dom_node *)submit_button !=
- (dom_node *)form_element) {
- continue;
- }
-
- err = dom_html_button_element_get_value(
- (dom_html_button_element *)form_element,
- &inputvalue);
- if (err != DOM_NO_ERR) {
- NSLOG(netsurf, INFO,
- "Could not get submit button value");
- goto dom_no_memory;
- }
- /* Drop through to report successful button */
- } else {
- continue;
- }
- } else if (dom_string_isequal(nodename, corestring_dom_INPUT)) {
- /* Things to consider here */
- /* Buttons -- only if the successful control */
- /* radio and checkbox -- only if selected */
- /* file -- also get the rawfile */
- /* everything else -- just value */
- err = dom_html_input_element_get_type(
- (dom_html_input_element *) form_element,
- &inputtype);
- if (err != DOM_NO_ERR) {
- NSLOG(netsurf, INFO,
- "Could not get input element type");
- goto dom_no_memory;
- }
- if (dom_string_caseless_isequal(
- inputtype, corestring_dom_submit)) {
-
- if (submit_button == NULL && !had_submit) {
- /* no button used, and first submit
- * node found, so use it
- */
- had_submit = true;
- } else if ((dom_node *)submit_button !=
- (dom_node *)form_element) {
- continue;
- }
-
- err = dom_html_input_element_get_value(
- (dom_html_input_element *)form_element,
- &inputvalue);
- if (err != DOM_NO_ERR) {
- NSLOG(netsurf, INFO,
- "Could not get submit button value");
- goto dom_no_memory;
- }
- /* Drop through to report the successful button */
- } else if (dom_string_caseless_isequal(
- inputtype, corestring_dom_image)) {
- /* We *ONLY* use an image input if it was the
- * thing which activated us
- */
- if ((dom_node *)submit_button !=
- (dom_node *)form_element)
- continue;
-
- err = dom_node_get_user_data(
- form_element,
- corestring_dom___ns_key_image_coords_node_data,
- &coords);
- if (err != DOM_NO_ERR) {
- NSLOG(netsurf, INFO,
- "Could not get image XY data");
- goto dom_no_memory;
- }
- if (coords == NULL) {
- NSLOG(netsurf, INFO,
- "No XY data on the image input");
- goto dom_no_memory;
- }
-
- basename = ENCODE_ITEM(inputname);
-
- success_new = calloc(1, sizeof(*success_new));
- if (success_new == NULL) {
- free(basename);
- NSLOG(netsurf, INFO,
- "Could not allocate data for image.x");
- goto dom_no_memory;
- }
-
- last_success->next = success_new;
- last_success = success_new;
-
- success_new->name = malloc(strlen(basename) + 3);
- if (success_new->name == NULL) {
- free(basename);
- NSLOG(netsurf, INFO,
- "Could not allocate name for image.x");
- goto dom_no_memory;
- }
- success_new->value = malloc(20);
- if (success_new->value == NULL) {
- free(basename);
- NSLOG(netsurf, INFO,
- "Could not allocate value for image.x");
- goto dom_no_memory;
- }
- sprintf(success_new->name, "%s.x", basename);
- sprintf(success_new->value, "%d", coords->x);
-
- success_new = calloc(1, sizeof(*success_new));
- if (success_new == NULL) {
- free(basename);
- NSLOG(netsurf, INFO,
- "Could not allocate data for image.y");
- goto dom_no_memory;
- }
-
- last_success->next = success_new;
- last_success = success_new;
-
- success_new->name = malloc(strlen(basename) + 3);
- if (success_new->name == NULL) {
- free(basename);
- NSLOG(netsurf, INFO,
- "Could not allocate name for image.y");
- goto dom_no_memory;
- }
- success_new->value = malloc(20);
- if (success_new->value == NULL) {
- free(basename);
- NSLOG(netsurf, INFO,
- "Could not allocate value for image.y");
- goto dom_no_memory;
- }
- sprintf(success_new->name, "%s.y", basename);
- sprintf(success_new->value, "%d", coords->y);
- free(basename);
- continue;
- } else if (dom_string_caseless_isequal(
- inputtype, corestring_dom_radio) ||
- dom_string_caseless_isequal(
- inputtype, corestring_dom_checkbox)) {
- err = dom_html_input_element_get_checked(
- (dom_html_input_element *)form_element,
- &checked);
- if (err != DOM_NO_ERR) {
- NSLOG(netsurf, INFO,
- "Could not get input element checked");
- goto dom_no_memory;
- }
- if (!checked)
- continue;
- err = dom_html_input_element_get_value(
- (dom_html_input_element *)form_element,
- &inputvalue);
- if (err != DOM_NO_ERR) {
- NSLOG(netsurf, INFO,
- "Could not get input element value");
- goto dom_no_memory;
- }
- if (inputvalue == NULL) {
- inputvalue = dom_string_ref(
- corestring_dom_on);
- }
- /* Fall through to simple allocation */
- } else if (dom_string_caseless_isequal(
- inputtype, corestring_dom_file)) {
-
- err = dom_html_input_element_get_value(
- (dom_html_input_element *)form_element,
- &inputvalue);
- if (err != DOM_NO_ERR) {
- NSLOG(netsurf, INFO,
- "Could not get file value");
- goto dom_no_memory;
- }
- err = dom_node_get_user_data(
- form_element,
- corestring_dom___ns_key_file_name_node_data,
- &rawfile_temp);
- if (err != DOM_NO_ERR) {
- NSLOG(netsurf, INFO,
- "Could not get file rawname");
- goto dom_no_memory;
- }
- rawfile_temp = strdup(rawfile_temp != NULL ?
- rawfile_temp :
- "");
- if (rawfile_temp == NULL) {
- NSLOG(netsurf, INFO,
- "Could not copy file rawname");
- goto dom_no_memory;
- }
- /* Fall out to the allocation */
- } else if (dom_string_caseless_isequal(
- inputtype, corestring_dom_reset) ||
- dom_string_caseless_isequal(
- inputtype, corestring_dom_button)) {
- /* Skip these */
- NSLOG(netsurf, INFO,
- "Skipping RESET and BUTTON");
- continue;
- } else {
- /* Everything else is treated as text values */
- err = dom_html_input_element_get_value(
- (dom_html_input_element *)form_element,
- &inputvalue);
- if (err != DOM_NO_ERR) {
- NSLOG(netsurf, INFO,
- "Could not get input value");
- goto dom_no_memory;
- }
- /* Fall out to the allocation */
- }
- }
-
- success_new = calloc(1, sizeof(*success_new));
- if (success_new == NULL) {
- NSLOG(netsurf, INFO,
- "Could not allocate data for generic");
- goto dom_no_memory;
- }
-
- last_success->next = success_new;
- last_success = success_new;
-
- success_new->name = ENCODE_ITEM(inputname);
- if (success_new->name == NULL) {
- NSLOG(netsurf, INFO,
- "Could not encode name for generic");
- goto dom_no_memory;
- }
- success_new->value = ENCODE_ITEM(inputvalue);
- if (success_new->value == NULL) {
- NSLOG(netsurf, INFO,
- "Could not encode value for generic");
- goto dom_no_memory;
- }
- if (rawfile_temp != NULL) {
- success_new->file = true;
- success_new->rawfile = rawfile_temp;
- rawfile_temp = NULL;
- }
- }
-
- free(charset);
-
- if (form_element != NULL) {
- dom_node_unref(form_element);
- }
-
- if (form_elements != NULL) {
- dom_html_collection_unref(form_elements);
- }
-
- if (nodename != NULL) {
- dom_string_unref(nodename);
- }
-
- if (inputname != NULL) {
- dom_string_unref(inputname);
- }
-
- if (inputvalue != NULL) {
- dom_string_unref(inputvalue);
- }
-
- if (options != NULL) {
- dom_html_options_collection_unref(options);
- }
-
- if (option_element != NULL) {
- dom_node_unref(option_element);
- }
-
- if (inputtype != NULL) {
- dom_string_unref(inputtype);
- }
-
- if (rawfile_temp != NULL) {
- free(rawfile_temp);
- }
-
- *successful_controls = sentinel.next;
-
- return true;
-
-dom_no_memory:
- free(charset);
- fetch_multipart_data_destroy(sentinel.next);
-
- if (form_elements != NULL)
- dom_html_collection_unref(form_elements);
- if (form_element != NULL)
- dom_node_unref(form_element);
- if (nodename != NULL)
- dom_string_unref(nodename);
- if (inputname != NULL)
- dom_string_unref(inputname);
- if (inputvalue != NULL)
- dom_string_unref(inputvalue);
- if (options != NULL)
- dom_html_options_collection_unref(options);
- if (option_element != NULL)
- dom_node_unref(option_element);
- if (inputtype != NULL)
- dom_string_unref(inputtype);
- if (rawfile_temp != NULL)
- free(rawfile_temp);
-
- return false;
-}
-#undef ENCODE_ITEM
-
-/**
- * Encode controls using application/x-www-form-urlencoded.
- *
- * \param form form to which successful controls relate
- * \param control linked list of fetch_multipart_data
- * \param query_string iff true add '?' to the start of returned data
- * \return URL-encoded form, or 0 on memory exhaustion
- */
-
-static char *form_url_encode(struct form *form,
- struct fetch_multipart_data *control,
- bool query_string)
-{
- char *name, *value;
- char *s, *s2;
- unsigned int len, len1, len_init;
- nserror url_err;
-
- if (query_string)
- s = malloc(2);
- else
- s = malloc(1);
-
- if (s == NULL)
- return NULL;
-
- if (query_string) {
- s[0] = '?';
- s[1] = '\0';
- len_init = len = 1;
- } else {
- s[0] = '\0';
- len_init = len = 0;
- }
-
- for (; control; control = control->next) {
- url_err = url_escape(control->name, true, NULL, &name);
- if (url_err == NSERROR_NOMEM) {
- free(s);
- return NULL;
- }
-
- assert(url_err == NSERROR_OK);
-
- url_err = url_escape(control->value, true, NULL, &value);
- if (url_err == NSERROR_NOMEM) {
- free(name);
- free(s);
- return NULL;
- }
-
- assert(url_err == NSERROR_OK);
-
- len1 = len + strlen(name) + strlen(value) + 2;
- s2 = realloc(s, len1 + 1);
- if (!s2) {
- free(value);
- free(name);
- free(s);
- return NULL;
- }
- s = s2;
- sprintf(s + len, "%s=%s&", name, value);
- len = len1;
- free(name);
- free(value);
- }
-
- if (len > len_init) {
- /* Replace trailing '&' */
- s[len - 1] = '\0';
- }
- return s;
-}
-
-/**
- * Find an acceptable character set encoding with which to submit the form
- *
- * \param form The form
- * \return Pointer to charset name (on heap, caller should free) or NULL
- */
-char *form_acceptable_charset(struct form *form)
-{
- char *temp, *c;
-
- if (!form)
- return NULL;
-
- if (!form->accept_charsets) {
- /* no accept-charsets attribute for this form */
- if (form->document_charset)
- /* document charset present, so use it */
- return strdup(form->document_charset);
- else
- /* no document charset, so default to 8859-1 */
- return strdup("ISO-8859-1");
- }
-
- /* make temporary copy of accept-charsets attribute */
- temp = strdup(form->accept_charsets);
- if (!temp)
- return NULL;
-
- /* make it upper case */
- for (c = temp; *c; c++) {
- *c = ascii_to_upper(*c);
- }
-
- /* is UTF-8 specified? */
- c = strstr(temp, "UTF-8");
- if (c) {
- free(temp);
- return strdup("UTF-8");
- }
-
- /* dispense with temporary copy */
- free(temp);
-
- /* according to RFC2070, the accept-charsets attribute of the
- * form element contains a space and/or comma separated list */
- c = form->accept_charsets;
-
- /** \todo an improvement would be to choose an encoding
- * acceptable to the server which covers as much of the input
- * values as possible. Additionally, we need to handle the
- * case where none of the acceptable encodings cover all the
- * textual input values. For now, we just extract the first
- * element of the charset list
- */
- while (*c && !ascii_is_space(*c)) {
- if (*c == ',')
- break;
- c++;
- }
-
- return strndup(form->accept_charsets, c - form->accept_charsets);
-}
-
-/**
- * Convert a string from UTF-8 to the specified charset
- * As a final fallback, this will attempt to convert to ISO-8859-1.
- *
- * \todo Return charset used?
- *
- * \param item String to convert
- * \param len Length of string to convert
- * \param charset Destination charset
- * \param fallback Fallback charset (may be NULL),
- * used iff converting to charset fails
- * \return Pointer to converted string (on heap, caller frees), or NULL
- */
-char *form_encode_item(const char *item, uint32_t len, const char *charset,
- const char *fallback)
-{
- nserror err;
- char *ret = NULL;
- char cset[256];
-
- if (!item || !charset)
- return NULL;
-
- snprintf(cset, sizeof cset, "%s//TRANSLIT", charset);
-
- err = utf8_to_enc(item, cset, 0, &ret);
- if (err == NSERROR_BAD_ENCODING) {
- /* charset not understood, try without transliteration */
- snprintf(cset, sizeof cset, "%s", charset);
- err = utf8_to_enc(item, cset, len, &ret);
-
- if (err == NSERROR_BAD_ENCODING) {
- /* nope, try fallback charset (if any) */
- if (fallback) {
- snprintf(cset, sizeof cset,
- "%s//TRANSLIT", fallback);
- err = utf8_to_enc(item, cset, 0, &ret);
-
- if (err == NSERROR_BAD_ENCODING) {
- /* and without transliteration */
- snprintf(cset, sizeof cset,
- "%s", fallback);
- err = utf8_to_enc(item, cset, 0, &ret);
- }
- }
-
- if (err == NSERROR_BAD_ENCODING) {
- /* that also failed, use 8859-1 */
- err = utf8_to_enc(item, "ISO-8859-1//TRANSLIT",
- 0, &ret);
- if (err == NSERROR_BAD_ENCODING) {
- /* and without transliteration */
- err = utf8_to_enc(item, "ISO-8859-1",
- 0, &ret);
- }
- }
- }
- }
- if (err == NSERROR_NOMEM) {
- return NULL;
- }
-
- return ret;
-}
-
-/* exported interface documented in render/form_internal.h */
-bool form_open_select_menu(void *client_data,
- struct form_control *control,
- select_menu_redraw_callback callback,
- struct content *c)
-{
- int line_height_with_spacing;
- struct box *box;
- plot_font_style_t fstyle;
- int total_height;
- struct form_select_menu *menu;
- html_content *html = (html_content *)c;
-
-
- /* if the menu is opened for the first time */
- if (control->data.select.menu == NULL) {
-
- menu = calloc(1, sizeof (struct form_select_menu));
- if (menu == NULL) {
- guit->misc->warning("NoMemory", 0);
- return false;
- }
-
- control->data.select.menu = menu;
-
- box = control->box;
-
- menu->width = box->width +
- box->border[RIGHT].width +
- box->border[LEFT].width +
- box->padding[RIGHT] + box->padding[LEFT];
-
- font_plot_style_from_css(&html->len_ctx, control->box->style,
- &fstyle);
- menu->f_size = fstyle.size;
-
- menu->line_height = FIXTOINT(FDIV((FMUL(FLTTOFIX(1.2),
- FMUL(nscss_screen_dpi,
- INTTOFIX(fstyle.size / FONT_SIZE_SCALE)))),
- F_72));
-
- line_height_with_spacing = menu->line_height +
- menu->line_height *
- SELECT_LINE_SPACING;
-
- total_height = control->data.select.num_items *
- line_height_with_spacing;
- menu->height = total_height;
-
- if (menu->height > MAX_SELECT_HEIGHT) {
-
- menu->height = MAX_SELECT_HEIGHT;
- }
- menu->client_data = client_data;
- menu->callback = callback;
- if (scrollbar_create(false,
- menu->height,
- total_height,
- menu->height,
- control,
- form_select_menu_scroll_callback,
- &(menu->scrollbar)) != NSERROR_OK) {
- free(menu);
- return false;
- }
- menu->c = c;
- }
- else menu = control->data.select.menu;
-
- menu->callback(client_data, 0, 0, menu->width, menu->height);
-
- return true;
-}
-
-
-/* exported interface documented in render/form_internal.h */
-void form_free_select_menu(struct form_control *control)
-{
- if (control->data.select.menu->scrollbar != NULL)
- scrollbar_destroy(control->data.select.menu->scrollbar);
- free(control->data.select.menu);
- control->data.select.menu = NULL;
-}
-
-
-/* exported interface documented in render/form_internal.h */
-bool form_redraw_select_menu(struct form_control *control, int x, int y,
- float scale, const struct rect *clip,
- const struct redraw_context *ctx)
-{
- struct box *box;
- struct form_select_menu *menu = control->data.select.menu;
- struct form_option *option;
- int line_height, line_height_with_spacing;
- int width, height;
- int x0, y0, x1, scrollbar_x, y1, y2, y3;
- int item_y;
- int text_pos_offset, text_x;
- int scrollbar_width = SCROLLBAR_WIDTH;
- int i;
- int scroll;
- int x_cp, y_cp;
- struct rect r;
- struct rect rect;
- nserror res;
-
- box = control->box;
-
- x_cp = x;
- y_cp = y;
- width = menu->width;
- height = menu->height;
- line_height = menu->line_height;
-
- line_height_with_spacing = line_height +
- line_height * SELECT_LINE_SPACING;
- scroll = scrollbar_get_offset(menu->scrollbar);
-
- if (scale != 1.0) {
- x *= scale;
- y *= scale;
- width *= scale;
- height *= scale;
- scrollbar_width *= scale;
-
- i = scroll / line_height_with_spacing;
- scroll -= i * line_height_with_spacing;
- line_height *= scale;
- line_height_with_spacing *= scale;
- scroll *= scale;
- scroll += i * line_height_with_spacing;
- }
-
-
- x0 = x;
- y0 = y;
- x1 = x + width - 1;
- y1 = y + height - 1;
- scrollbar_x = x1 - scrollbar_width;
-
- r.x0 = x0;
- r.y0 = y0;
- r.x1 = x1 + 1;
- r.y1 = y1 + 1;
- res = ctx->plot->clip(ctx, &r);
- if (res != NSERROR_OK) {
- return false;
- }
-
- rect.x0 = x0;
- rect.y0 = y0;
- rect.x1 = x1;
- rect.y1 = y1;
- res = ctx->plot->rectangle(ctx, plot_style_stroke_darkwbasec, &rect);
- if (res != NSERROR_OK) {
- return false;
- }
-
- x0 = x0 + SELECT_BORDER_WIDTH;
- y0 = y0 + SELECT_BORDER_WIDTH;
- x1 = x1 - SELECT_BORDER_WIDTH;
- y1 = y1 - SELECT_BORDER_WIDTH;
- height = height - 2 * SELECT_BORDER_WIDTH;
-
- r.x0 = x0;
- r.y0 = y0;
- r.x1 = x1 + 1;
- r.y1 = y1 + 1;
- res = ctx->plot->clip(ctx, &r);
- if (res != NSERROR_OK) {
- return false;
- }
-
- res = ctx->plot->rectangle(ctx, plot_style_fill_lightwbasec, &r);
- if (res != NSERROR_OK) {
- return false;
- }
-
- option = control->data.select.items;
- item_y = line_height_with_spacing;
-
- while (item_y < scroll) {
- option = option->next;
- item_y += line_height_with_spacing;
- }
- item_y -= line_height_with_spacing;
- text_pos_offset = y - scroll +
- (int) (line_height * (0.75 + SELECT_LINE_SPACING));
- text_x = x + (box->border[LEFT].width + box->padding[LEFT]) * scale;
-
- plot_fstyle_entry.size = menu->f_size;
-
- while (option && item_y - scroll < height) {
-
- if (option->selected) {
- y2 = y + item_y - scroll;
- y3 = y + item_y + line_height_with_spacing - scroll;
-
- rect.x0 = x0;
- rect.y0 = y0 > y2 ? y0 : y2;
- rect.x1 = scrollbar_x + 1;
- rect.y1 = y3 < y1 + 1 ? y3 : y1 + 1;
- res = ctx->plot->rectangle(ctx, &plot_style_fill_selected, &rect);
- if (res != NSERROR_OK) {
- return false;
- }
- }
-
- y2 = text_pos_offset + item_y;
- res = ctx->plot->text(ctx,
- &plot_fstyle_entry,
- text_x, y2,
- option->text, strlen(option->text));
- if (res != NSERROR_OK) {
- return false;
- }
-
- item_y += line_height_with_spacing;
- option = option->next;
- }
-
- res = scrollbar_redraw(menu->scrollbar,
- x_cp + menu->width - SCROLLBAR_WIDTH,
- y_cp,
- clip, scale, ctx);
- if (res != NSERROR_OK) {
- return false;
- }
-
- return true;
-}
-
-/**
- * Check whether a clipping rectangle is completely contained in the
- * select menu.
- *
- * \param control the select menu to check the clipping rectangle for
- * \param scale the current browser window scale
- * \param clip the clipping rectangle
- * \return true if inside false otherwise
- */
-bool form_clip_inside_select_menu(struct form_control *control, float scale,
- const struct rect *clip)
-{
- struct form_select_menu *menu = control->data.select.menu;
- int width, height;
-
-
- width = menu->width;
- height = menu->height;
-
- if (scale != 1.0) {
- width *= scale;
- height *= scale;
- }
-
- if (clip->x0 >= 0 && clip->x1 <= width &&
- clip->y0 >= 0 && clip->y1 <= height)
- return true;
-
- return false;
-}
-
-
-/**
- * Process a selection from a form select menu.
- *
- * \param html The html content handle for the form
- * \param control form control with menu
- * \param item index of item selected from the menu
- * \return NSERROR_OK or appropriate error code.
- */
-static nserror form__select_process_selection(html_content *html,
- struct form_control *control, int item)
-{
- struct box *inline_box;
- struct form_option *o;
- int count;
- nserror ret = NSERROR_OK;
-
- assert(control != NULL);
- assert(html != NULL);
-
- /** \todo Even though the form code is effectively part of the html
- * content handler, poking around inside contents is not good
- */
-
- inline_box = control->box->children->children;
-
- for (count = 0, o = control->data.select.items;
- o != NULL;
- count++, o = o->next) {
- if (!control->data.select.multiple && o->selected) {
- o->selected = false;
- dom_html_option_element_set_selected(o->node, false);
- }
-
- if (count == item) {
- if (control->data.select.multiple) {
- if (o->selected) {
- o->selected = false;
- dom_html_option_element_set_selected(
- o->node, false);
- control->data.select.num_selected--;
- } else {
- o->selected = true;
- dom_html_option_element_set_selected(
- o->node, true);
- control->data.select.num_selected++;
- }
- } else {
- dom_html_option_element_set_selected(
- o->node, true);
- o->selected = true;
- }
- }
-
- if (o->selected) {
- control->data.select.current = o;
- }
- }
-
- talloc_free(inline_box->text);
- inline_box->text = 0;
-
- if (control->data.select.num_selected == 0) {
- inline_box->text = talloc_strdup(html->bctx,
- messages_get("Form_None"));
- } else if (control->data.select.num_selected == 1) {
- inline_box->text = talloc_strdup(html->bctx,
- control->data.select.current->text);
- } else {
- inline_box->text = talloc_strdup(html->bctx,
- messages_get("Form_Many"));
- }
-
- if (!inline_box->text) {
- ret = NSERROR_NOMEM;
- inline_box->length = 0;
- } else {
- inline_box->length = strlen(inline_box->text);
- }
- inline_box->width = control->box->width;
-
- html__redraw_a_box(html, control->box);
-
- return ret;
-}
-
-/* exported interface documented in netsurf/form.h */
-nserror form_select_process_selection(struct form_control *control, int item)
-{
- assert(control != NULL);
-
- return form__select_process_selection(control->html, control, item);
-}
-
-/* exported interface documented in netsurf/form.h */
-struct form_option *
-form_select_get_option(struct form_control *control, int item)
-{
- struct form_option *opt;
-
- opt = control->data.select.items;
- while ((opt != NULL) && (item > 0)) {
- opt = opt->next;
- item--;
- }
- return opt;
-}
-
-/* exported interface documented in netsurf/form.h */
-char *form_control_get_name(struct form_control *control)
-{
- return control->name;
-}
-
-/* exported interface documented in netsurf/form.h */
-nserror form_control_bounding_rect(struct form_control *control, struct rect *r)
-{
- box_bounds( control->box, r );
- return NSERROR_OK;
-}
-
-
-/**
- * Handle a click on the area of the currently opened select menu.
- *
- * \param control the select menu which received the click
- * \param x X coordinate of click
- * \param y Y coordinate of click
- */
-void form_select_menu_clicked(struct form_control *control, int x, int y)
-{
- struct form_select_menu *menu = control->data.select.menu;
- struct form_option *option;
- html_content *html = (html_content *)menu->c;
- int line_height, line_height_with_spacing;
- int item_bottom_y;
- int scroll, i;
-
- scroll = scrollbar_get_offset(menu->scrollbar);
-
- line_height = menu->line_height;
- line_height_with_spacing = line_height +
- line_height * SELECT_LINE_SPACING;
-
- option = control->data.select.items;
- item_bottom_y = line_height_with_spacing;
- i = 0;
- while (option && item_bottom_y < scroll + y) {
- item_bottom_y += line_height_with_spacing;
- option = option->next;
- i++;
- }
-
- if (option != NULL) {
- form__select_process_selection(html, control, i);
- }
-
- menu->callback(menu->client_data, 0, 0, menu->width, menu->height);
-}
-
-/**
- * Handle mouse action for the currently opened select menu.
- *
- * \param control the select menu which received the mouse action
- * \param mouse current mouse state
- * \param x X coordinate of click
- * \param y Y coordinate of click
- * \return text for the browser status bar or NULL if the menu has
- * to be closed
- */
-const char *form_select_mouse_action(struct form_control *control,
- browser_mouse_state mouse, int x, int y)
-{
- struct form_select_menu *menu = control->data.select.menu;
- int x0, y0, x1, y1, scrollbar_x;
- const char *status = NULL;
- bool multiple = control->data.select.multiple;
-
- x0 = 0;
- y0 = 0;
- x1 = menu->width;
- y1 = menu->height;
- scrollbar_x = x1 - SCROLLBAR_WIDTH;
-
- if (menu->scroll_capture ||
- (x > scrollbar_x && x < x1 && y > y0 && y < y1)) {
- /* The scroll is currently capturing all events or the mouse
- * event is taking place on the scrollbar widget area
- */
- x -= scrollbar_x;
- return scrollbar_mouse_status_to_message(
- scrollbar_mouse_action(menu->scrollbar,
- mouse, x, y));
- }
-
-
- if (x > x0 && x < scrollbar_x && y > y0 && y < y1) {
- /* over option area */
-
- if (mouse & (BROWSER_MOUSE_CLICK_1 | BROWSER_MOUSE_CLICK_2))
- /* button 1 or 2 click */
- form_select_menu_clicked(control, x, y);
-
- if (!(mouse & BROWSER_MOUSE_CLICK_1 && !multiple))
- /* anything but a button 1 click over a single select
- menu */
- status = messages_get(control->data.select.multiple ?
- "SelectMClick" : "SelectClick");
-
- } else if (!(mouse & (BROWSER_MOUSE_CLICK_1 | BROWSER_MOUSE_CLICK_2)))
- /* if not a button 1 or 2 click*/
- status = messages_get("SelectClose");
-
- return status;
-}
-
-/**
- * Handle mouse drag end for the currently opened select menu.
- *
- * \param control the select menu which received the mouse drag end
- * \param mouse current mouse state
- * \param x X coordinate of drag end
- * \param y Y coordinate of drag end
- */
-void form_select_mouse_drag_end(struct form_control *control,
- browser_mouse_state mouse, int x, int y)
-{
- int x0, y0, x1, y1;
- int box_x, box_y;
- struct box *box;
- struct form_select_menu *menu = control->data.select.menu;
-
- box = control->box;
-
- /* Get global coords of scrollbar */
- box_coords(box, &box_x, &box_y);
- box_x -= box->border[LEFT].width;
- box_y += box->height + box->border[BOTTOM].width +
- box->padding[BOTTOM] + box->padding[TOP];
-
- /* Get drag end coords relative to scrollbar */
- x = x - box_x;
- y = y - box_y;
-
- if (menu->scroll_capture) {
- x -= menu->width - SCROLLBAR_WIDTH;
- scrollbar_mouse_drag_end(menu->scrollbar, mouse, x, y);
- return;
- }
-
- x0 = 0;
- y0 = 0;
- x1 = menu->width;
- y1 = menu->height;
-
-
- if (x > x0 && x < x1 - SCROLLBAR_WIDTH && y > y0 && y < y1)
- /* handle drag end above the option area like a regular click */
- form_select_menu_clicked(control, x, y);
-}
-
-/**
- * Callback for the select menus scroll
- */
-void form_select_menu_scroll_callback(void *client_data,
- struct scrollbar_msg_data *scrollbar_data)
-{
- struct form_control *control = client_data;
- struct form_select_menu *menu = control->data.select.menu;
- html_content *html = (html_content *)menu->c;
-
- switch (scrollbar_data->msg) {
- case SCROLLBAR_MSG_MOVED:
- menu->callback(menu->client_data,
- 0, 0,
- menu->width,
- menu->height);
- break;
- case SCROLLBAR_MSG_SCROLL_START:
- {
- struct rect rect = {
- .x0 = scrollbar_data->x0,
- .y0 = scrollbar_data->y0,
- .x1 = scrollbar_data->x1,
- .y1 = scrollbar_data->y1
- };
-
- browser_window_set_drag_type(html->bw,
- DRAGGING_CONTENT_SCROLLBAR, &rect);
-
- menu->scroll_capture = true;
- }
- break;
- case SCROLLBAR_MSG_SCROLL_FINISHED:
- menu->scroll_capture = false;
-
- browser_window_set_drag_type(html->bw,
- DRAGGING_NONE, NULL);
- break;
- default:
- break;
- }
-}
-
-/**
- * Get the dimensions of a select menu.
- *
- * \param control the select menu to get the dimensions of
- * \param width gets updated to menu width
- * \param height gets updated to menu height
- */
-void form_select_get_dimensions(struct form_control *control,
- int *width, int *height)
-{
- *width = control->data.select.menu->width;
- *height = control->data.select.menu->height;
-}
-
-/**
- * Callback for the core select menu.
- */
-void form_select_menu_callback(void *client_data,
- int x, int y, int width, int height)
-{
- html_content *html = client_data;
- int menu_x, menu_y;
- struct box *box;
-
- box = html->visible_select_menu->box;
- box_coords(box, &menu_x, &menu_y);
-
- menu_x -= box->border[LEFT].width;
- menu_y += box->height + box->border[BOTTOM].width +
- box->padding[BOTTOM] +
- box->padding[TOP];
- content__request_redraw((struct content *)html, menu_x + x, menu_y + y,
- width, height);
-}
-
-
-/**
- * Set a radio form control and clear the others in the group.
- *
- * \param radio form control of type GADGET_RADIO
- */
-
-void form_radio_set(struct form_control *radio)
-{
- struct form_control *control;
-
- assert(radio);
- if (!radio->form)
- return;
-
- if (radio->selected)
- return;
-
- for (control = radio->form->controls; control;
- control = control->next) {
- if (control->type != GADGET_RADIO)
- continue;
- if (control == radio)
- continue;
- if (strcmp(control->name, radio->name) != 0)
- continue;
-
- if (control->selected) {
- control->selected = false;
- dom_html_input_element_set_checked(control->node, false);
- html__redraw_a_box(radio->html, control->box);
- }
- }
-
- radio->selected = true;
- dom_html_input_element_set_checked(radio->node, true);
- html__redraw_a_box(radio->html, radio->box);
-}
-
-
-/**
- * Collect controls and submit a form.
- */
-
-void form_submit(nsurl *page_url, struct browser_window *target,
- struct form *form, struct form_control *submit_button)
-{
- char *data = NULL;
- struct fetch_multipart_data *success;
- nsurl *action_url;
- nsurl *action_query;
- nserror error;
-
- assert(form != NULL);
-
- if (form_successful_controls_dom(form, submit_button, &success) == false) {
- guit->misc->warning("NoMemory", 0);
- return;
- }
-
- /* Decompose action */
- if (nsurl_create(form->action, &action_url) != NSERROR_OK) {
- free(data);
- fetch_multipart_data_destroy(success);
- guit->misc->warning("NoMemory", 0);
- return;
- }
-
- switch (form->method) {
- case method_GET:
- data = form_url_encode(form, success, true);
- if (data == NULL) {
- fetch_multipart_data_destroy(success);
- guit->misc->warning("NoMemory", 0);
- return;
- }
-
- /* Replace query segment */
- error = nsurl_replace_query(action_url, data, &action_query);
- if (error != NSERROR_OK) {
- nsurl_unref(action_query);
- free(data);
- fetch_multipart_data_destroy(success);
- guit->misc->warning(messages_get_errorcode(error), 0);
- return;
- }
-
- /* Construct submit url */
- browser_window_navigate(target,
- action_query,
- page_url,
- BW_NAVIGATE_HISTORY,
- NULL,
- NULL,
- NULL);
-
- nsurl_unref(action_query);
- break;
-
- case method_POST_URLENC:
- data = form_url_encode(form, success, false);
- if (data == NULL) {
- fetch_multipart_data_destroy(success);
- guit->misc->warning("NoMemory", 0);
- nsurl_unref(action_url);
- return;
- }
-
- browser_window_navigate(target,
- action_url,
- page_url,
- BW_NAVIGATE_HISTORY,
- data,
- NULL,
- NULL);
- break;
-
- case method_POST_MULTIPART:
- browser_window_navigate(target,
- action_url,
- page_url,
- BW_NAVIGATE_HISTORY,
- NULL,
- success,
- NULL);
-
- break;
- }
-
- nsurl_unref(action_url);
- fetch_multipart_data_destroy(success);
- free(data);
-}
-
-void form_gadget_update_value(struct form_control *control, char *value)
-{
- switch (control->type) {
- case GADGET_HIDDEN:
- case GADGET_TEXTBOX:
- case GADGET_TEXTAREA:
- case GADGET_PASSWORD:
- case GADGET_FILE:
- if (control->value != NULL) {
- free(control->value);
- }
- control->value = value;
- if (control->node != NULL) {
- dom_exception err;
- dom_string *str;
- err = dom_string_create((uint8_t *)value,
- strlen(value), &str);
- if (err == DOM_NO_ERR) {
- if (control->type == GADGET_TEXTAREA)
- err = dom_html_text_area_element_set_value(
- (dom_html_text_area_element *)(control->node),
- str);
- else
- err = dom_html_input_element_set_value(
- (dom_html_input_element *)(control->node),
- str);
- dom_string_unref(str);
- }
- }
- break;
- default:
- /* Do nothing */
- break;
- }
-}
diff --git a/render/form_internal.h b/render/form_internal.h
deleted file mode 100644
index 0ffb6b46c..000000000
--- a/render/form_internal.h
+++ /dev/null
@@ -1,277 +0,0 @@
-/*
- * Copyright 2014 Vincent Sanders <vince@netsurf-browser.org>
- *
- * This file is part of NetSurf, http://www.netsurf-browser.org/
- *
- * NetSurf is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * NetSurf is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-/**
- * \file
- * Interface to form handling functions internal to render.
- */
-
-#ifndef _NETSURF_RENDER_FORM_INTERNAL_H_
-#define _NETSURF_RENDER_FORM_INTERNAL_H_
-
-#include <stdbool.h>
-
-#include "netsurf/form.h"
-
-struct box;
-struct form_control;
-struct form_option;
-struct form_select_menu;
-struct form;
-struct html_content;
-struct dom_string;
-struct content;
-struct nsurl;
-struct fetch_multipart_data;
-struct redraw_context;
-struct browser_window;
-
-enum browser_mouse_state;
-
-/** Type of a struct form_control. */
-typedef enum {
- GADGET_HIDDEN,
- GADGET_TEXTBOX,
- GADGET_RADIO,
- GADGET_CHECKBOX,
- GADGET_SELECT,
- GADGET_TEXTAREA,
- GADGET_IMAGE,
- GADGET_PASSWORD,
- GADGET_SUBMIT,
- GADGET_RESET,
- GADGET_FILE,
- GADGET_BUTTON
-} form_control_type;
-
-/** Data for textarea */
-struct form_textarea_data {
- struct form_control *gadget;
-};
-
-struct image_input_coords {
- int x;
- int y;
-};
-
-/** Form control. */
-struct form_control {
- void *node; /**< Corresponding DOM node */
- struct html_content *html; /**< HTML content containing control */
-
- form_control_type type; /**< Type of control */
-
- struct form *form; /**< Containing form */
-
- char *name; /**< Control name */
- char *value; /**< Current value of control */
- char *initial_value; /**< Initial value of control */
- bool disabled; /**< Whether control is disabled */
-
- struct box *box; /**< Box for control */
-
- unsigned int length; /**< Number of characters in control */
- unsigned int maxlength; /**< Maximum characters permitted */
-
- bool selected; /**< Whether control is selected */
-
- union {
- struct {
- int mx, my;
- } image;
- struct {
- int num_items;
- struct form_option *items, *last_item;
- bool multiple;
- int num_selected;
- /** Currently selected item, if num_selected == 1. */
- struct form_option *current;
- struct form_select_menu *menu;
- } select;
- struct {
- struct textarea *ta;
- struct dom_string *initial;
- struct form_textarea_data data;
- } text; /**< input type=text or textarea */
- } data;
-
- struct form_control *prev; /**< Previous control in this form */
- struct form_control *next; /**< Next control in this form. */
-};
-
-/** Form submit method. */
-typedef enum {
- method_GET, /**< GET, always url encoded. */
- method_POST_URLENC, /**< POST, url encoded. */
- method_POST_MULTIPART /**< POST, multipart/form-data. */
-} form_method;
-
-/** HTML form. */
-struct form {
- void *node; /**< Corresponding DOM node */
-
- char *action; /**< Absolute URL to submit to. */
- char *target; /**< Target to submit to. */
- form_method method; /**< Method and enctype. */
- char *accept_charsets; /**< Charset to submit form in */
- char *document_charset; /**< Charset of document containing form */
- struct form_control *controls; /**< Linked list of controls. */
- struct form_control *last_control; /**< Last control in list. */
-
- struct form *prev; /**< Previous form in doc. */
-};
-
-/**
- * Called by the select menu when it wants an area to be redrawn. The
- * coordinates are menu origin relative.
- *
- * \param client_data data which was passed to form_open_select_menu
- * \param x X coordinate of redraw rectangle
- * \param y Y coordinate of redraw rectangle
- * \param width width of redraw rectangle
- * \param height height of redraw rectangle
- */
-typedef void(*select_menu_redraw_callback)(void *client_data,
- int x, int y, int width, int height);
-
-/**
- * Create a struct form.
- *
- * \param node DOM node associated with form
- * \param action URL to submit form to, or NULL for default
- * \param target Target frame of form, or NULL for default
- * \param method method and enctype
- * \param charset acceptable encodings for form submission, or NULL
- * \param doc_charset encoding of containing document, or NULL
- * \return A new form or NULL on memory exhaustion
- */
-struct form *form_new(void *node, const char *action, const char *target,
- form_method method, const char *charset,
- const char *doc_charset);
-
-/**
- * Free a form and any controls it owns.
- *
- * \note There may exist controls attached to box tree nodes which are not
- * associated with any form. These will leak at present. Ideally, they will
- * be cleaned up when the box tree is destroyed. As that currently happens
- * via talloc, this won't happen. These controls are distinguishable, as their
- * form field will be NULL.
- *
- * \param form The form to free
- */
-void form_free(struct form *form);
-
-/**
- * Create a struct form_control.
- *
- * \param node Associated DOM node
- * \param type control type
- * \return a new structure, or NULL on memory exhaustion
- */
-struct form_control *form_new_control(void *node, form_control_type type);
-
-void form_add_control(struct form *form, struct form_control *control);
-void form_free_control(struct form_control *control);
-bool form_add_option(struct form_control *control, char *value, char *text,
- bool selected, void *node);
-bool form_successful_controls(struct form *form,
- struct form_control *submit_button,
- struct fetch_multipart_data **successful_controls);
-
-/**
- * Identify 'successful' controls via the DOM.
- *
- * All text strings in the successful controls list will be in the charset most
- * appropriate for submission. Therefore, no utf8_to_* processing should be
- * performed upon them.
- *
- * \todo The chosen charset needs to be made available such that it can be
- * included in the submission request (e.g. in the fetch's Content-Type header)
- *
- * See HTML 4.01 section 17.13.2.
- *
- * \param[in] form form to search for successful controls
- * \param[in] submit_button control used to submit the form, if any
- * \param[out] successful_controls updated to point to linked list of
- * fetch_multipart_data, 0 if no controls
- * \return true on success, false on memory exhaustion
- */
-bool form_successful_controls_dom(struct form *form,
- struct form_control *submit_button,
- struct fetch_multipart_data **successful_controls);
-
-
-/**
- * Open a select menu for a select form control, creating it if necessary.
- *
- * \param client_data data passed to the redraw callback
- * \param control The select form control for which the menu is being opened
- * \param redraw_callback The callback to redraw the select menu.
- * \param c The content the select menu is opening for.
- * \return false on memory exhaustion, true otherwise
- */
-bool form_open_select_menu(void *client_data,
- struct form_control *control,
- select_menu_redraw_callback redraw_callback,
- struct content *c);
-
-
-void form_select_menu_callback(void *client_data,
- int x, int y, int width, int height);
-
-
-/**
- * Destroy a select menu and free allocated memory.
- *
- * \param control the select form control owning the select menu being
- * destroyed.
- */
-void form_free_select_menu(struct form_control *control);
-
-
-/**
- * Redraw an opened select menu.
- *
- * \param control the select menu being redrawn
- * \param x the X coordinate to draw the menu at
- * \param y the Y coordinate to draw the menu at
- * \param scale current redraw scale
- * \param clip clipping rectangle
- * \param ctx current redraw context
- * \return true on success, false otherwise
- */
-bool form_redraw_select_menu(struct form_control *control, int x, int y,
- float scale, const struct rect *clip,
- const struct redraw_context *ctx);
-
-bool form_clip_inside_select_menu(struct form_control *control, float scale,
- const struct rect *clip);
-const char *form_select_mouse_action(struct form_control *control,
- enum browser_mouse_state mouse, int x, int y);
-void form_select_mouse_drag_end(struct form_control *control,
- enum browser_mouse_state mouse, int x, int y);
-void form_select_get_dimensions(struct form_control *control,
- int *width, int *height);
-void form_submit(struct nsurl *page_url, struct browser_window *target,
- struct form *form, struct form_control *submit_button);
-void form_radio_set(struct form_control *radio);
-
-void form_gadget_update_value(struct form_control *control, char *value);
-
-#endif
diff --git a/render/html.c b/render/html.c
deleted file mode 100644
index b7d7aa313..000000000
--- a/render/html.c
+++ /dev/null
@@ -1,2467 +0,0 @@
-/*
- * Copyright 2007 James Bursa <bursa@users.sourceforge.net>
- * Copyright 2010 Michael Drake <tlsa@netsurf-browser.org>
- *
- * This file is part of NetSurf, http://www.netsurf-browser.org/
- *
- * NetSurf is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * NetSurf is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-/**
- * \file
- * Content for text/html (implementation).
- */
-
-#include <assert.h>
-#include <stdint.h>
-#include <string.h>
-#include <strings.h>
-#include <stdlib.h>
-#include <nsutils/time.h>
-
-#include "utils/utils.h"
-#include "utils/config.h"
-#include "utils/corestrings.h"
-#include "utils/http.h"
-#include "utils/libdom.h"
-#include "utils/log.h"
-#include "utils/messages.h"
-#include "utils/talloc.h"
-#include "utils/utf8.h"
-#include "utils/nsoption.h"
-#include "utils/string.h"
-#include "utils/ascii.h"
-#include "netsurf/content.h"
-#include "netsurf/browser_window.h"
-#include "netsurf/utf8.h"
-#include "netsurf/layout.h"
-#include "netsurf/misc.h"
-#include "content/hlcache.h"
-#include "desktop/selection.h"
-#include "desktop/scrollbar.h"
-#include "desktop/textarea.h"
-#include "netsurf/bitmap.h"
-#include "javascript/js.h"
-#include "desktop/gui_internal.h"
-
-#include "render/box.h"
-#include "render/form_internal.h"
-#include "render/html_internal.h"
-#include "render/imagemap.h"
-#include "render/layout.h"
-#include "render/search.h"
-
-#define CHUNK 4096
-
-/* Change these to 1 to cause a dump to stderr of the frameset or box
- * when the trees have been built.
- */
-#define ALWAYS_DUMP_FRAMESET 0
-#define ALWAYS_DUMP_BOX 0
-
-static const char *html_types[] = {
- "application/xhtml+xml",
- "text/html"
-};
-
-/* Exported interface, see html_internal.h */
-bool fire_dom_event(dom_string *type, dom_node *target,
- bool bubbles, bool cancelable)
-{
- dom_exception exc;
- dom_event *evt;
- bool result;
-
- exc = dom_event_create(&evt);
- if (exc != DOM_NO_ERR) return false;
- exc = dom_event_init(evt, type, bubbles, cancelable);
- if (exc != DOM_NO_ERR) {
- dom_event_unref(evt);
- return false;
- }
- NSLOG(netsurf, INFO, "Dispatching '%*s' against %p",
- dom_string_length(type), dom_string_data(type), target);
- exc = dom_event_target_dispatch_event(target, evt, &result);
- if (exc != DOM_NO_ERR) {
- result = false;
- }
- dom_event_unref(evt);
- return result;
-}
-
-/**
- * Perform post-box-creation conversion of a document
- *
- * \param c HTML content to complete conversion of
- * \param success Whether box tree construction was successful
- */
-static void html_box_convert_done(html_content *c, bool success)
-{
- nserror err;
- dom_exception exc; /* returned by libdom functions */
- dom_node *html;
-
- NSLOG(netsurf, INFO, "Done XML to box (%p)", c);
-
- /* Clean up and report error if unsuccessful or aborted */
- if ((success == false) || (c->aborted)) {
- html_object_free_objects(c);
-
- if (success == false) {
- content_broadcast_errorcode(&c->base, NSERROR_BOX_CONVERT);
- } else {
- content_broadcast_errorcode(&c->base, NSERROR_STOPPED);
- }
-
- content_set_error(&c->base);
- return;
- }
-
-
-#if ALWAYS_DUMP_BOX
- box_dump(stderr, c->layout->children, 0, true);
-#endif
-#if ALWAYS_DUMP_FRAMESET
- if (c->frameset)
- html_dump_frameset(c->frameset, 0);
-#endif
-
- exc = dom_document_get_document_element(c->document, (void *) &html);
- if ((exc != DOM_NO_ERR) || (html == NULL)) {
- /** @todo should this call html_object_free_objects(c);
- * like the other error paths
- */
- NSLOG(netsurf, INFO, "error retrieving html element from dom");
- content_broadcast_errorcode(&c->base, NSERROR_DOM);
- content_set_error(&c->base);
- return;
- }
-
- /* extract image maps - can't do this sensibly in dom_to_box */
- err = imagemap_extract(c);
- if (err != NSERROR_OK) {
- NSLOG(netsurf, INFO, "imagemap extraction failed");
- html_object_free_objects(c);
- content_broadcast_errorcode(&c->base, err);
- content_set_error(&c->base);
- dom_node_unref(html);
- return;
- }
- /*imagemap_dump(c);*/
-
- /* Destroy the parser binding */
- dom_hubbub_parser_destroy(c->parser);
- c->parser = NULL;
-
- content_set_ready(&c->base);
-
- if (c->base.active == 0) {
- content_set_done(&c->base);
- }
-
- dom_node_unref(html);
-}
-
-
-/** process link node */
-static bool html_process_link(html_content *c, dom_node *node)
-{
- struct content_rfc5988_link link; /* the link added to the content */
- dom_exception exc; /* returned by libdom functions */
- dom_string *atr_string;
- nserror error;
-
- memset(&link, 0, sizeof(struct content_rfc5988_link));
-
- /* check that the relation exists - w3c spec says must be present */
- exc = dom_element_get_attribute(node, corestring_dom_rel, &atr_string);
- if ((exc != DOM_NO_ERR) || (atr_string == NULL)) {
- return false;
- }
- /* get a lwc string containing the link relation */
- exc = dom_string_intern(atr_string, &link.rel);
- dom_string_unref(atr_string);
- if (exc != DOM_NO_ERR) {
- return false;
- }
-
- /* check that the href exists - w3c spec says must be present */
- exc = dom_element_get_attribute(node, corestring_dom_href, &atr_string);
- if ((exc != DOM_NO_ERR) || (atr_string == NULL)) {
- lwc_string_unref(link.rel);
- return false;
- }
-
- /* get nsurl */
- error = nsurl_join(c->base_url, dom_string_data(atr_string),
- &link.href);
- dom_string_unref(atr_string);
- if (error != NSERROR_OK) {
- lwc_string_unref(link.rel);
- return false;
- }
-
- /* look for optional properties -- we don't care if internment fails */
-
- exc = dom_element_get_attribute(node,
- corestring_dom_hreflang, &atr_string);
- if ((exc == DOM_NO_ERR) && (atr_string != NULL)) {
- /* get a lwc string containing the href lang */
- exc = dom_string_intern(atr_string, &link.hreflang);
- dom_string_unref(atr_string);
- }
-
- exc = dom_element_get_attribute(node,
- corestring_dom_type, &atr_string);
- if ((exc == DOM_NO_ERR) && (atr_string != NULL)) {
- /* get a lwc string containing the type */
- exc = dom_string_intern(atr_string, &link.type);
- dom_string_unref(atr_string);
- }
-
- exc = dom_element_get_attribute(node,
- corestring_dom_media, &atr_string);
- if ((exc == DOM_NO_ERR) && (atr_string != NULL)) {
- /* get a lwc string containing the media */
- exc = dom_string_intern(atr_string, &link.media);
- dom_string_unref(atr_string);
- }
-
- exc = dom_element_get_attribute(node,
- corestring_dom_sizes, &atr_string);
- if ((exc == DOM_NO_ERR) && (atr_string != NULL)) {
- /* get a lwc string containing the sizes */
- exc = dom_string_intern(atr_string, &link.sizes);
- dom_string_unref(atr_string);
- }
-
- /* add to content */
- content__add_rfc5988_link(&c->base, &link);
-
- if (link.sizes != NULL)
- lwc_string_unref(link.sizes);
- if (link.media != NULL)
- lwc_string_unref(link.media);
- if (link.type != NULL)
- lwc_string_unref(link.type);
- if (link.hreflang != NULL)
- lwc_string_unref(link.hreflang);
-
- nsurl_unref(link.href);
- lwc_string_unref(link.rel);
-
- return true;
-}
-
-/** process title node */
-static bool html_process_title(html_content *c, dom_node *node)
-{
- dom_exception exc; /* returned by libdom functions */
- dom_string *title;
- char *title_str;
- bool success;
-
- exc = dom_node_get_text_content(node, &title);
- if ((exc != DOM_NO_ERR) || (title == NULL)) {
- return false;
- }
-
- title_str = squash_whitespace(dom_string_data(title));
- dom_string_unref(title);
-
- if (title_str == NULL) {
- return false;
- }
-
- success = content__set_title(&c->base, title_str);
-
- free(title_str);
-
- return success;
-}
-
-static bool html_process_base(html_content *c, dom_node *node)
-{
- dom_exception exc; /* returned by libdom functions */
- dom_string *atr_string;
-
- /* get href attribute if present */
- exc = dom_element_get_attribute(node,
- corestring_dom_href, &atr_string);
- if ((exc == DOM_NO_ERR) && (atr_string != NULL)) {
- nsurl *url;
- nserror error;
-
- /* get url from string */
- error = nsurl_create(dom_string_data(atr_string), &url);
- dom_string_unref(atr_string);
- if (error == NSERROR_OK) {
- if (c->base_url != NULL)
- nsurl_unref(c->base_url);
- c->base_url = url;
- }
- }
-
-
- /* get target attribute if present and not already set */
- if (c->base_target != NULL) {
- return true;
- }
-
- exc = dom_element_get_attribute(node,
- corestring_dom_target, &atr_string);
- if ((exc == DOM_NO_ERR) && (atr_string != NULL)) {
- /* Validation rules from the HTML5 spec for the base element:
- * The target must be one of _blank, _self, _parent, or
- * _top or any identifier which does not begin with an
- * underscore
- */
- if (*dom_string_data(atr_string) != '_' ||
- dom_string_caseless_lwc_isequal(atr_string,
- corestring_lwc__blank) ||
- dom_string_caseless_lwc_isequal(atr_string,
- corestring_lwc__self) ||
- dom_string_caseless_lwc_isequal(atr_string,
- corestring_lwc__parent) ||
- dom_string_caseless_lwc_isequal(atr_string,
- corestring_lwc__top)) {
- c->base_target = strdup(dom_string_data(atr_string));
- }
- dom_string_unref(atr_string);
- }
-
- return true;
-}
-
-static nserror html_meta_refresh_process_element(html_content *c, dom_node *n)
-{
- union content_msg_data msg_data;
- const char *url, *end, *refresh = NULL;
- char *new_url;
- char quote = '\0';
- dom_string *equiv, *content;
- dom_exception exc;
- nsurl *nsurl;
- nserror error = NSERROR_OK;
-
- exc = dom_element_get_attribute(n, corestring_dom_http_equiv, &equiv);
- if (exc != DOM_NO_ERR) {
- return NSERROR_DOM;
- }
-
- if (equiv == NULL) {
- return NSERROR_OK;
- }
-
- if (!dom_string_caseless_lwc_isequal(equiv, corestring_lwc_refresh)) {
- dom_string_unref(equiv);
- return NSERROR_OK;
- }
-
- dom_string_unref(equiv);
-
- exc = dom_element_get_attribute(n, corestring_dom_content, &content);
- if (exc != DOM_NO_ERR) {
- return NSERROR_DOM;
- }
-
- if (content == NULL) {
- return NSERROR_OK;
- }
-
- end = dom_string_data(content) + dom_string_byte_length(content);
-
- /* content := *LWS intpart fracpart? *LWS [';' *LWS *1url *LWS]
- * intpart := 1*DIGIT
- * fracpart := 1*('.' | DIGIT)
- * url := "url" *LWS '=' *LWS (url-nq | url-sq | url-dq)
- * url-nq := *urlchar
- * url-sq := "'" *(urlchar | '"') "'"
- * url-dq := '"' *(urlchar | "'") '"'
- * urlchar := [#x9#x21#x23-#x26#x28-#x7E] | nonascii
- * nonascii := [#x80-#xD7FF#xE000-#xFFFD#x10000-#x10FFFF]
- */
-
- url = dom_string_data(content);
-
- /* *LWS */
- while (url < end && ascii_is_space(*url)) {
- url++;
- }
-
- /* intpart */
- if (url == end || (*url < '0' || '9' < *url)) {
- /* Empty content, or invalid timeval */
- dom_string_unref(content);
- return NSERROR_OK;
- }
-
- msg_data.delay = (int) strtol(url, &new_url, 10);
- /* a very small delay and self-referencing URL can cause a loop
- * that grinds machines to a halt. To prevent this we set a
- * minimum refresh delay of 1s. */
- if (msg_data.delay < 1) {
- msg_data.delay = 1;
- }
-
- url = new_url;
-
- /* fracpart? (ignored, as delay is integer only) */
- while (url < end && (('0' <= *url && *url <= '9') ||
- *url == '.')) {
- url++;
- }
-
- /* *LWS */
- while (url < end && ascii_is_space(*url)) {
- url++;
- }
-
- /* ';' */
- if (url < end && *url == ';')
- url++;
-
- /* *LWS */
- while (url < end && ascii_is_space(*url)) {
- url++;
- }
-
- if (url == end) {
- /* Just delay specified, so refresh current page */
- dom_string_unref(content);
-
- c->base.refresh = nsurl_ref(
- content_get_url(&c->base));
-
- content_broadcast(&c->base, CONTENT_MSG_REFRESH, &msg_data);
-
- return NSERROR_OK;
- }
-
- /* "url" */
- if (url <= end - 3) {
- if (strncasecmp(url, "url", 3) == 0) {
- url += 3;
- } else {
- /* Unexpected input, ignore this header */
- dom_string_unref(content);
- return NSERROR_OK;
- }
- } else {
- /* Insufficient input, ignore this header */
- dom_string_unref(content);
- return NSERROR_OK;
- }
-
- /* *LWS */
- while (url < end && ascii_is_space(*url)) {
- url++;
- }
-
- /* '=' */
- if (url < end) {
- if (*url == '=') {
- url++;
- } else {
- /* Unexpected input, ignore this header */
- dom_string_unref(content);
- return NSERROR_OK;
- }
- } else {
- /* Insufficient input, ignore this header */
- dom_string_unref(content);
- return NSERROR_OK;
- }
-
- /* *LWS */
- while (url < end && ascii_is_space(*url)) {
- url++;
- }
-
- /* '"' or "'" */
- if (url < end && (*url == '"' || *url == '\'')) {
- quote = *url;
- url++;
- }
-
- /* Start of URL */
- refresh = url;
-
- if (quote != 0) {
- /* url-sq | url-dq */
- while (url < end && *url != quote)
- url++;
- } else {
- /* url-nq */
- while (url < end && !ascii_is_space(*url))
- url++;
- }
-
- /* '"' or "'" or *LWS (we don't care) */
- if (url > refresh) {
- /* There's a URL */
- new_url = strndup(refresh, url - refresh);
- if (new_url == NULL) {
- dom_string_unref(content);
- return NSERROR_NOMEM;
- }
-
- error = nsurl_join(c->base_url, new_url, &nsurl);
- if (error == NSERROR_OK) {
- /* broadcast valid refresh url */
-
- c->base.refresh = nsurl;
-
- content_broadcast(&c->base, CONTENT_MSG_REFRESH,
- &msg_data);
- c->refresh = true;
- }
-
- free(new_url);
-
- }
-
- dom_string_unref(content);
-
- return error;
-}
-
-static bool html_process_img(html_content *c, dom_node *node)
-{
- dom_string *src;
- nsurl *url;
- nserror err;
- dom_exception exc;
- bool success;
-
- /* Do nothing if foreground images are disabled */
- if (nsoption_bool(foreground_images) == false) {
- return true;
- }
-
- exc = dom_element_get_attribute(node, corestring_dom_src, &src);
- if (exc != DOM_NO_ERR || src == NULL) {
- return true;
- }
-
- err = nsurl_join(c->base_url, dom_string_data(src), &url);
- if (err != NSERROR_OK) {
- dom_string_unref(src);
- return false;
- }
- dom_string_unref(src);
-
- /* Speculatively fetch the image */
- success = html_fetch_object(c, url, NULL, CONTENT_IMAGE, 0, 0, false);
- nsurl_unref(url);
-
- return success;
-}
-
-/* exported function documented in render/html_internal.h */
-void html_finish_conversion(html_content *htmlc)
-{
- union content_msg_data msg_data;
- dom_exception exc; /* returned by libdom functions */
- dom_node *html;
- nserror error;
-
- /* Bail out if we've been aborted */
- if (htmlc->aborted) {
- content_broadcast_errorcode(&htmlc->base, NSERROR_STOPPED);
- content_set_error(&htmlc->base);
- return;
- }
-
- /* create new css selection context */
- error = html_css_new_selection_context(htmlc, &htmlc->select_ctx);
- if (error != NSERROR_OK) {
- content_broadcast_errorcode(&htmlc->base, error);
- content_set_error(&htmlc->base);
- return;
- }
-
-
- /* fire a simple event named load at the Document's Window
- * object, but with its target set to the Document object (and
- * the currentTarget set to the Window object)
- */
- if (htmlc->jscontext != NULL) {
- js_fire_event(htmlc->jscontext, "load", htmlc->document, NULL);
- }
-
- /* convert dom tree to box tree */
- NSLOG(netsurf, INFO, "DOM to box (%p)", htmlc);
- content_set_status(&htmlc->base, messages_get("Processing"));
- msg_data.explicit_status_text = NULL;
- content_broadcast(&htmlc->base, CONTENT_MSG_STATUS, &msg_data);
-
- exc = dom_document_get_document_element(htmlc->document, (void *) &html);
- if ((exc != DOM_NO_ERR) || (html == NULL)) {
- NSLOG(netsurf, INFO, "error retrieving html element from dom");
- content_broadcast_errorcode(&htmlc->base, NSERROR_DOM);
- content_set_error(&htmlc->base);
- return;
- }
-
- error = dom_to_box(html, htmlc, html_box_convert_done);
- if (error != NSERROR_OK) {
- NSLOG(netsurf, INFO, "box conversion failed");
- dom_node_unref(html);
- html_object_free_objects(htmlc);
- content_broadcast_errorcode(&htmlc->base, error);
- content_set_error(&htmlc->base);
- return;
- }
-
- dom_node_unref(html);
-}
-
-/* callback for DOMNodeInserted end type */
-static void
-dom_default_action_DOMNodeInserted_cb(struct dom_event *evt, void *pw)
-{
- dom_event_target *node;
- dom_node_type type;
- dom_exception exc;
- html_content *htmlc = pw;
-
- exc = dom_event_get_target(evt, &node);
- if ((exc == DOM_NO_ERR) && (node != NULL)) {
- exc = dom_node_get_node_type(node, &type);
- if ((exc == DOM_NO_ERR) && (type == DOM_ELEMENT_NODE)) {
- /* an element node has been inserted */
- dom_html_element_type tag_type;
-
- exc = dom_html_element_get_tag_type(node, &tag_type);
- if (exc != DOM_NO_ERR) {
- tag_type = DOM_HTML_ELEMENT_TYPE__UNKNOWN;
- }
-
- switch (tag_type) {
- case DOM_HTML_ELEMENT_TYPE_LINK:
- /* Handle stylesheet loading */
- html_css_process_link(htmlc, (dom_node *)node);
- /* Generic link handling */
- html_process_link(htmlc, (dom_node *)node);
- break;
- case DOM_HTML_ELEMENT_TYPE_META:
- if (htmlc->refresh)
- break;
- html_meta_refresh_process_element(htmlc,
- (dom_node *)node);
- break;
- case DOM_HTML_ELEMENT_TYPE_TITLE:
- if (htmlc->title != NULL)
- break;
- htmlc->title = dom_node_ref(node);
- break;
- case DOM_HTML_ELEMENT_TYPE_BASE:
- html_process_base(htmlc, (dom_node *)node);
- break;
- case DOM_HTML_ELEMENT_TYPE_IMG:
- html_process_img(htmlc, (dom_node *) node);
- break;
- case DOM_HTML_ELEMENT_TYPE_STYLE:
- html_css_process_style(htmlc, (dom_node *) node);
- break;
- default:
- break;
- }
- if (htmlc->enable_scripting) {
- /* ensure javascript context is available */
- if (htmlc->jscontext == NULL) {
- union content_msg_data msg_data;
-
- msg_data.jscontext = &htmlc->jscontext;
- content_broadcast(&htmlc->base,
- CONTENT_MSG_GETCTX,
- &msg_data);
- NSLOG(netsurf, INFO,
- "javascript context: %p (htmlc: %p)",
- htmlc->jscontext,
- htmlc);
- }
- if (htmlc->jscontext != NULL) {
- js_handle_new_element(htmlc->jscontext,
- (dom_element *) node);
- }
- }
- }
- dom_node_unref(node);
- }
-}
-
-/* callback for DOMNodeInserted end type */
-static void
-dom_default_action_DOMSubtreeModified_cb(struct dom_event *evt, void *pw)
-{
- dom_event_target *node;
- dom_node_type type;
- dom_exception exc;
- html_content *htmlc = pw;
-
- exc = dom_event_get_target(evt, &node);
- if ((exc == DOM_NO_ERR) && (node != NULL)) {
- if (htmlc->title == (dom_node *)node) {
- /* Node is our title node */
- html_process_title(htmlc, (dom_node *)node);
- dom_node_unref(node);
- return;
- }
-
- exc = dom_node_get_node_type(node, &type);
- if ((exc == DOM_NO_ERR) && (type == DOM_ELEMENT_NODE)) {
- /* an element node has been modified */
- dom_html_element_type tag_type;
-
- exc = dom_html_element_get_tag_type(node, &tag_type);
- if (exc != DOM_NO_ERR) {
- tag_type = DOM_HTML_ELEMENT_TYPE__UNKNOWN;
- }
-
- switch (tag_type) {
- case DOM_HTML_ELEMENT_TYPE_STYLE:
- html_css_update_style(htmlc, (dom_node *)node);
- break;
- default:
- break;
- }
- }
- dom_node_unref(node);
- }
-}
-
-static void
-dom_default_action_finished_cb(struct dom_event *evt, void *pw)
-{
- html_content *htmlc = pw;
-
- if (htmlc->jscontext != NULL)
- js_event_cleanup(htmlc->jscontext, evt);
-}
-
-/* callback function selector
- *
- * selects a callback function for libdom to call based on the type and phase.
- * dom_default_action_phase from events/document_event.h
- *
- * The principle events are:
- * DOMSubtreeModified
- * DOMAttrModified
- * DOMNodeInserted
- * DOMNodeInsertedIntoDocument
- *
- * @return callback function pointer or NULL for none
- */
-static dom_default_action_callback
-dom_event_fetcher(dom_string *type,
- dom_default_action_phase phase,
- void **pw)
-{
- NSLOG(netsurf, DEEPDEBUG, "type:%s", dom_string_data(type));
-
- if (phase == DOM_DEFAULT_ACTION_END) {
- if (dom_string_isequal(type, corestring_dom_DOMNodeInserted)) {
- return dom_default_action_DOMNodeInserted_cb;
- } else if (dom_string_isequal(type, corestring_dom_DOMSubtreeModified)) {
- return dom_default_action_DOMSubtreeModified_cb;
- }
- } else if (phase == DOM_DEFAULT_ACTION_FINISHED) {
- return dom_default_action_finished_cb;
- }
- return NULL;
-}
-
-static void
-html_document_user_data_handler(dom_node_operation operation,
- dom_string *key, void *data,
- struct dom_node *src,
- struct dom_node *dst)
-{
- if (dom_string_isequal(corestring_dom___ns_key_html_content_data,
- key) == false || data == NULL) {
- return;
- }
-
- switch (operation) {
- case DOM_NODE_CLONED:
- NSLOG(netsurf, INFO, "Cloned");
- break;
- case DOM_NODE_RENAMED:
- NSLOG(netsurf, INFO, "Renamed");
- break;
- case DOM_NODE_IMPORTED:
- NSLOG(netsurf, INFO, "imported");
- break;
- case DOM_NODE_ADOPTED:
- NSLOG(netsurf, INFO, "Adopted");
- break;
- case DOM_NODE_DELETED:
- /* This is the only path I expect */
- break;
- default:
- NSLOG(netsurf, INFO, "User data operation not handled.");
- assert(0);
- }
-}
-
-
-static nserror
-html_create_html_data(html_content *c, const http_parameter *params)
-{
- lwc_string *charset;
- nserror nerror;
- dom_hubbub_parser_params parse_params;
- dom_hubbub_error error;
- dom_exception err;
- void *old_node_data;
-
- c->parser = NULL;
- c->parse_completed = false;
- c->document = NULL;
- c->quirks = DOM_DOCUMENT_QUIRKS_MODE_NONE;
- c->encoding = NULL;
- c->base_url = nsurl_ref(content_get_url(&c->base));
- c->base_target = NULL;
- c->aborted = false;
- c->refresh = false;
- c->reflowing = false;
- c->title = NULL;
- c->bctx = NULL;
- c->layout = NULL;
- c->background_colour = NS_TRANSPARENT;
- c->stylesheet_count = 0;
- c->stylesheets = NULL;
- c->select_ctx = NULL;
- c->universal = NULL;
- c->num_objects = 0;
- c->object_list = NULL;
- c->forms = NULL;
- c->imagemaps = NULL;
- c->bw = NULL;
- c->frameset = NULL;
- c->iframe = NULL;
- c->page = NULL;
- c->font_func = guit->layout;
- c->drag_type = HTML_DRAG_NONE;
- c->drag_owner.no_owner = true;
- c->selection_type = HTML_SELECTION_NONE;
- c->selection_owner.none = true;
- c->focus_type = HTML_FOCUS_SELF;
- c->focus_owner.self = true;
- c->search = NULL;
- c->search_string = NULL;
- c->scripts_count = 0;
- c->scripts = NULL;
- c->jscontext = NULL;
-
- c->enable_scripting = nsoption_bool(enable_javascript);
- c->base.active = 1; /* The html content itself is active */
-
- if (lwc_intern_string("*", SLEN("*"), &c->universal) != lwc_error_ok) {
- return NSERROR_NOMEM;
- }
-
- selection_prepare(&c->sel, (struct content *)c, true);
-
- nerror = http_parameter_list_find_item(params, corestring_lwc_charset, &charset);
- if (nerror == NSERROR_OK) {
- c->encoding = strdup(lwc_string_data(charset));
-
- lwc_string_unref(charset);
-
- if (c->encoding == NULL) {
- lwc_string_unref(c->universal);
- c->universal = NULL;
- return NSERROR_NOMEM;
-
- }
- c->encoding_source = DOM_HUBBUB_ENCODING_SOURCE_HEADER;
- }
-
- /* Create the parser binding */
- parse_params.enc = c->encoding;
- parse_params.fix_enc = true;
- parse_params.enable_script = c->enable_scripting;
- parse_params.msg = NULL;
- parse_params.script = html_process_script;
- parse_params.ctx = c;
- parse_params.daf = dom_event_fetcher;
-
- error = dom_hubbub_parser_create(&parse_params,
- &c->parser,
- &c->document);
- if ((error != DOM_HUBBUB_OK) && (c->encoding != NULL)) {
- /* Ok, we don't support the declared encoding. Bailing out
- * isn't exactly user-friendly, so fall back to autodetect */
- free(c->encoding);
- c->encoding = NULL;
-
- parse_params.enc = c->encoding;
-
- error = dom_hubbub_parser_create(&parse_params,
- &c->parser,
- &c->document);
- }
- if (error != DOM_HUBBUB_OK) {
- nsurl_unref(c->base_url);
- c->base_url = NULL;
-
- lwc_string_unref(c->universal);
- c->universal = NULL;
-
- return libdom_hubbub_error_to_nserror(error);
- }
-
- err = dom_node_set_user_data(c->document,
- corestring_dom___ns_key_html_content_data,
- c, html_document_user_data_handler,
- (void *) &old_node_data);
- if (err != DOM_NO_ERR) {
- dom_hubbub_parser_destroy(c->parser);
- nsurl_unref(c->base_url);
- c->base_url = NULL;
-
- lwc_string_unref(c->universal);
- c->universal = NULL;
-
- NSLOG(netsurf, INFO, "Unable to set user data.");
- return NSERROR_DOM;
- }
-
- assert(old_node_data == NULL);
-
- return NSERROR_OK;
-
-}
-
-/**
- * Create a CONTENT_HTML.
- *
- * The content_html_data structure is initialized and the HTML parser is
- * created.
- */
-
-static nserror
-html_create(const content_handler *handler,
- lwc_string *imime_type,
- const http_parameter *params,
- llcache_handle *llcache,
- const char *fallback_charset,
- bool quirks,
- struct content **c)
-{
- html_content *html;
- nserror error;
-
- html = calloc(1, sizeof(html_content));
- if (html == NULL)
- return NSERROR_NOMEM;
-
- error = content__init(&html->base, handler, imime_type, params,
- llcache, fallback_charset, quirks);
- if (error != NSERROR_OK) {
- free(html);
- return error;
- }
-
- error = html_create_html_data(html, params);
- if (error != NSERROR_OK) {
- content_broadcast_errorcode(&html->base, error);
- free(html);
- return error;
- }
-
- error = html_css_new_stylesheets(html);
- if (error != NSERROR_OK) {
- content_broadcast_errorcode(&html->base, error);
- free(html);
- return error;
- }
-
- *c = (struct content *) html;
-
- return NSERROR_OK;
-}
-
-
-
-static nserror
-html_process_encoding_change(struct content *c,
- const char *data,
- unsigned int size)
-{
- html_content *html = (html_content *) c;
- dom_hubbub_parser_params parse_params;
- dom_hubbub_error error;
- const char *encoding;
- const char *source_data;
- unsigned long source_size;
-
- /* Retrieve new encoding */
- encoding = dom_hubbub_parser_get_encoding(html->parser,
- &html->encoding_source);
- if (encoding == NULL) {
- return NSERROR_NOMEM;
- }
-
- if (html->encoding != NULL) {
- free(html->encoding);
- html->encoding = NULL;
- }
-
- html->encoding = strdup(encoding);
- if (html->encoding == NULL) {
- return NSERROR_NOMEM;
- }
-
- /* Destroy binding */
- dom_hubbub_parser_destroy(html->parser);
- html->parser = NULL;
-
- if (html->document != NULL) {
- dom_node_unref(html->document);
- }
-
- parse_params.enc = html->encoding;
- parse_params.fix_enc = true;
- parse_params.enable_script = html->enable_scripting;
- parse_params.msg = NULL;
- parse_params.script = html_process_script;
- parse_params.ctx = html;
- parse_params.daf = dom_event_fetcher;
-
- /* Create new binding, using the new encoding */
- error = dom_hubbub_parser_create(&parse_params,
- &html->parser,
- &html->document);
- if (error != DOM_HUBBUB_OK) {
- /* Ok, we don't support the declared encoding. Bailing out
- * isn't exactly user-friendly, so fall back to Windows-1252 */
- free(html->encoding);
- html->encoding = strdup("Windows-1252");
- if (html->encoding == NULL) {
- return NSERROR_NOMEM;
- }
- parse_params.enc = html->encoding;
-
- error = dom_hubbub_parser_create(&parse_params,
- &html->parser,
- &html->document);
-
- if (error != DOM_HUBBUB_OK) {
- return libdom_hubbub_error_to_nserror(error);
- }
-
- }
-
- source_data = content__get_source_data(c, &source_size);
-
- /* Reprocess all the data. This is safe because
- * the encoding is now specified at parser start which means
- * it cannot be changed again.
- */
- error = dom_hubbub_parser_parse_chunk(html->parser,
- (const uint8_t *)source_data,
- source_size);
-
- return libdom_hubbub_error_to_nserror(error);
-}
-
-
-/**
- * Process data for CONTENT_HTML.
- */
-
-static bool
-html_process_data(struct content *c, const char *data, unsigned int size)
-{
- html_content *html = (html_content *) c;
- dom_hubbub_error dom_ret;
- nserror err = NSERROR_OK; /* assume its all going to be ok */
-
- dom_ret = dom_hubbub_parser_parse_chunk(html->parser,
- (const uint8_t *) data,
- size);
-
- err = libdom_hubbub_error_to_nserror(dom_ret);
-
- /* deal with encoding change */
- if (err == NSERROR_ENCODING_CHANGE) {
- err = html_process_encoding_change(c, data, size);
- }
-
- /* broadcast the error if necessary */
- if (err != NSERROR_OK) {
- content_broadcast_errorcode(c, err);
- return false;
- }
-
- return true;
-}
-
-
-/**
- * Convert a CONTENT_HTML for display.
- *
- * The following steps are carried out in order:
- *
- * - parsing to an XML tree is completed
- * - stylesheets are fetched
- * - the XML tree is converted to a box tree and object fetches are started
- *
- * On exit, the content status will be either CONTENT_STATUS_DONE if the
- * document is completely loaded or CONTENT_STATUS_READY if objects are still
- * being fetched.
- */
-
-static bool html_convert(struct content *c)
-{
- html_content *htmlc = (html_content *) c;
- dom_exception exc; /* returned by libdom functions */
-
- /* The quirk check and associated stylesheet fetch is "safe"
- * once the root node has been inserted into the document
- * which must have happened by this point in the parse.
- *
- * faliure to retrive the quirk mode or to start the
- * stylesheet fetch is non fatal as this "only" affects the
- * render and it would annoy the user to fail the entire
- * render for want of a quirks stylesheet.
- */
- exc = dom_document_get_quirks_mode(htmlc->document, &htmlc->quirks);
- if (exc == DOM_NO_ERR) {
- html_css_quirks_stylesheets(htmlc);
- NSLOG(netsurf, INFO, "quirks set to %d", htmlc->quirks);
- }
-
- htmlc->base.active--; /* the html fetch is no longer active */
- NSLOG(netsurf, INFO, "%d fetches active (%p)", htmlc->base.active, c);
-
- /* The parse cannot be completed here because it may be paused
- * untill all the resources being fetched have completed.
- */
-
- /* if there are no active fetches in progress no scripts are
- * being fetched or they completed already.
- */
- if (html_can_begin_conversion(htmlc)) {
- return html_begin_conversion(htmlc);
- }
- return true;
-}
-
-/* Exported interface documented in html_internal.h */
-bool html_can_begin_conversion(html_content *htmlc)
-{
- unsigned int i;
-
- if (htmlc->base.active != 0)
- return false;
-
- for (i = 0; i != htmlc->stylesheet_count; i++) {
- if (htmlc->stylesheets[i].modified)
- return false;
- }
-
- return true;
-}
-
-bool
-html_begin_conversion(html_content *htmlc)
-{
- dom_node *html;
- nserror ns_error;
- struct form *f;
- dom_exception exc; /* returned by libdom functions */
- dom_string *node_name = NULL;
- dom_hubbub_error error;
-
- /* The act of completing the parse can result in additional data
- * being flushed through the parser. This may result in new style or
- * script nodes, upon which the conversion depends. Thus, once we
- * have completed the parse, we must check again to see if we can
- * begin the conversion. If we can't, we must stop and wait for the
- * new styles/scripts to be processed. Once they have been processed,
- * we will be called again to begin the conversion for real. Thus,
- * we must also ensure that we don't attempt to complete the parse
- * multiple times, so store a flag to indicate that parsing is
- * complete to avoid repeating the completion pointlessly.
- */
- if (htmlc->parse_completed == false) {
- NSLOG(netsurf, INFO, "Completing parse (%p)", htmlc);
- /* complete parsing */
- error = dom_hubbub_parser_completed(htmlc->parser);
- if (error != DOM_HUBBUB_OK) {
- NSLOG(netsurf, INFO, "Parsing failed");
-
- content_broadcast_errorcode(&htmlc->base,
- libdom_hubbub_error_to_nserror(error));
-
- return false;
- }
- htmlc->parse_completed = true;
- }
-
- if (html_can_begin_conversion(htmlc) == false) {
- NSLOG(netsurf, INFO, "Can't begin conversion (%p)", htmlc);
- /* We can't proceed (see commentary above) */
- return true;
- }
-
- /* Give up processing if we've been aborted */
- if (htmlc->aborted) {
- NSLOG(netsurf, INFO, "Conversion aborted (%p) (active: %u)",
- htmlc, htmlc->base.active);
- content_set_error(&htmlc->base);
- content_broadcast_errorcode(&htmlc->base, NSERROR_STOPPED);
- return false;
- }
-
- /* complete script execution */
- html_script_exec(htmlc);
-
- /* fire a simple event that bubbles named DOMContentLoaded at
- * the Document.
- */
-
- /* get encoding */
- if (htmlc->encoding == NULL) {
- const char *encoding;
-
- encoding = dom_hubbub_parser_get_encoding(htmlc->parser,
- &htmlc->encoding_source);
- if (encoding == NULL) {
- content_broadcast_errorcode(&htmlc->base,
- NSERROR_NOMEM);
- return false;
- }
-
- htmlc->encoding = strdup(encoding);
- if (htmlc->encoding == NULL) {
- content_broadcast_errorcode(&htmlc->base,
- NSERROR_NOMEM);
- return false;
- }
- }
-
- /* locate root element and ensure it is html */
- exc = dom_document_get_document_element(htmlc->document, (void *) &html);
- if ((exc != DOM_NO_ERR) || (html == NULL)) {
- NSLOG(netsurf, INFO, "error retrieving html element from dom");
- content_broadcast_errorcode(&htmlc->base, NSERROR_DOM);
- return false;
- }
-
- exc = dom_node_get_node_name(html, &node_name);
- if ((exc != DOM_NO_ERR) ||
- (node_name == NULL) ||
- (!dom_string_caseless_lwc_isequal(node_name,
- corestring_lwc_html))) {
- NSLOG(netsurf, INFO, "root element not html");
- content_broadcast_errorcode(&htmlc->base, NSERROR_DOM);
- dom_node_unref(html);
- return false;
- }
- dom_string_unref(node_name);
-
- /* Retrieve forms from parser */
- htmlc->forms = html_forms_get_forms(htmlc->encoding,
- (dom_html_document *) htmlc->document);
- for (f = htmlc->forms; f != NULL; f = f->prev) {
- nsurl *action;
-
- /* Make all actions absolute */
- if (f->action == NULL || f->action[0] == '\0') {
- /* HTML5 4.10.22.3 step 9 */
- nsurl *doc_addr = content_get_url(&htmlc->base);
- ns_error = nsurl_join(htmlc->base_url,
- nsurl_access(doc_addr),
- &action);
- } else {
- ns_error = nsurl_join(htmlc->base_url,
- f->action,
- &action);
- }
-
- if (ns_error != NSERROR_OK) {
- content_broadcast_errorcode(&htmlc->base, ns_error);
-
- dom_node_unref(html);
- return false;
- }
-
- free(f->action);
- f->action = strdup(nsurl_access(action));
- nsurl_unref(action);
- if (f->action == NULL) {
- content_broadcast_errorcode(&htmlc->base,
- NSERROR_NOMEM);
-
- dom_node_unref(html);
- return false;
- }
-
- /* Ensure each form has a document encoding */
- if (f->document_charset == NULL) {
- f->document_charset = strdup(htmlc->encoding);
- if (f->document_charset == NULL) {
- content_broadcast_errorcode(&htmlc->base,
- NSERROR_NOMEM);
- dom_node_unref(html);
- return false;
- }
- }
- }
-
- dom_node_unref(html);
-
- if (htmlc->base.active == 0) {
- html_finish_conversion(htmlc);
- }
-
- return true;
-}
-
-
-/**
- * Stop loading a CONTENT_HTML.
- *
- * called when the content is aborted. This must clean up any state
- * created during the fetch.
- */
-
-static void html_stop(struct content *c)
-{
- html_content *htmlc = (html_content *) c;
-
- /* invalidate the html content reference to the javascript context
- * as it is about to become invalid and must not be used any
- * more.
- */
- html_script_invalidate_ctx(htmlc);
-
- switch (c->status) {
- case CONTENT_STATUS_LOADING:
- /* Still loading; simply flag that we've been aborted
- * html_convert/html_finish_conversion will do the rest */
- htmlc->aborted = true;
- break;
-
- case CONTENT_STATUS_READY:
- html_object_abort_objects(htmlc);
-
- /* If there are no further active fetches and we're still
- * in the READY state, transition to the DONE state. */
- if (c->status == CONTENT_STATUS_READY && c->active == 0) {
- content_set_done(c);
- }
-
- break;
-
- case CONTENT_STATUS_DONE:
- /* Nothing to do */
- break;
-
- default:
- NSLOG(netsurf, INFO, "Unexpected status %d (%p)", c->status,
- c);
- assert(0);
- }
-}
-
-
-/**
- * Reformat a CONTENT_HTML to a new width.
- */
-
-static void html_reformat(struct content *c, int width, int height)
-{
- html_content *htmlc = (html_content *) c;
- struct box *layout;
- uint64_t ms_before;
- uint64_t ms_after;
- uint64_t ms_interval;
-
- nsu_getmonotonic_ms(&ms_before);
-
- htmlc->reflowing = true;
-
- htmlc->len_ctx.vw = width;
- htmlc->len_ctx.vh = height;
- htmlc->len_ctx.root_style = htmlc->layout->style;
-
- layout_document(htmlc, width, height);
- layout = htmlc->layout;
-
- /* width and height are at least margin box of document */
- c->width = layout->x + layout->padding[LEFT] + layout->width +
- layout->padding[RIGHT] + layout->border[RIGHT].width +
- layout->margin[RIGHT];
- c->height = layout->y + layout->padding[TOP] + layout->height +
- layout->padding[BOTTOM] + layout->border[BOTTOM].width +
- layout->margin[BOTTOM];
-
- /* if boxes overflow right or bottom edge, expand to contain it */
- if (c->width < layout->x + layout->descendant_x1)
- c->width = layout->x + layout->descendant_x1;
- if (c->height < layout->y + layout->descendant_y1)
- c->height = layout->y + layout->descendant_y1;
-
- selection_reinit(&htmlc->sel, htmlc->layout);
-
- htmlc->reflowing = false;
-
- /* calculate next reflow time at three times what it took to reflow */
- nsu_getmonotonic_ms(&ms_after);
-
- ms_interval = (ms_before - ms_after) * 3;
- if (ms_interval < (nsoption_uint(min_reflow_period) * 10)) {
- ms_interval = nsoption_uint(min_reflow_period) * 10;
- }
- c->reformat_time = ms_after + ms_interval;
-}
-
-
-/**
- * Redraw a box.
- *
- * \param h content containing the box, of type CONTENT_HTML
- * \param box box to redraw
- */
-
-void html_redraw_a_box(hlcache_handle *h, struct box *box)
-{
- int x, y;
-
- box_coords(box, &x, &y);
-
- content_request_redraw(h, x, y,
- box->padding[LEFT] + box->width + box->padding[RIGHT],
- box->padding[TOP] + box->height + box->padding[BOTTOM]);
-}
-
-
-/**
- * Redraw a box.
- *
- * \param html content containing the box, of type CONTENT_HTML
- * \param box box to redraw.
- */
-
-void html__redraw_a_box(struct html_content *html, struct box *box)
-{
- int x, y;
-
- box_coords(box, &x, &y);
-
- content__request_redraw((struct content *)html, x, y,
- box->padding[LEFT] + box->width + box->padding[RIGHT],
- box->padding[TOP] + box->height + box->padding[BOTTOM]);
-}
-
-static void html_destroy_frameset(struct content_html_frames *frameset)
-{
- int i;
-
- if (frameset->name) {
- talloc_free(frameset->name);
- frameset->name = NULL;
- }
- if (frameset->url) {
- talloc_free(frameset->url);
- frameset->url = NULL;
- }
- if (frameset->children) {
- for (i = 0; i < (frameset->rows * frameset->cols); i++) {
- if (frameset->children[i].name) {
- talloc_free(frameset->children[i].name);
- frameset->children[i].name = NULL;
- }
- if (frameset->children[i].url) {
- nsurl_unref(frameset->children[i].url);
- frameset->children[i].url = NULL;
- }
- if (frameset->children[i].children)
- html_destroy_frameset(&frameset->children[i]);
- }
- talloc_free(frameset->children);
- frameset->children = NULL;
- }
-}
-
-static void html_destroy_iframe(struct content_html_iframe *iframe)
-{
- struct content_html_iframe *next;
- next = iframe;
- while ((iframe = next) != NULL) {
- next = iframe->next;
- if (iframe->name)
- talloc_free(iframe->name);
- if (iframe->url) {
- nsurl_unref(iframe->url);
- iframe->url = NULL;
- }
- talloc_free(iframe);
- }
-}
-
-
-static void html_free_layout(html_content *htmlc)
-{
- if (htmlc->bctx != NULL) {
- /* freeing talloc context should let the entire box
- * set be destroyed
- */
- talloc_free(htmlc->bctx);
- }
-}
-
-/**
- * Destroy a CONTENT_HTML and free all resources it owns.
- */
-
-static void html_destroy(struct content *c)
-{
- html_content *html = (html_content *) c;
- struct form *f, *g;
-
- NSLOG(netsurf, INFO, "content %p", c);
-
- /* Destroy forms */
- for (f = html->forms; f != NULL; f = g) {
- g = f->prev;
-
- form_free(f);
- }
-
- imagemap_destroy(html);
-
- if (c->refresh)
- nsurl_unref(c->refresh);
-
- if (html->base_url)
- nsurl_unref(html->base_url);
-
- if (html->parser != NULL) {
- dom_hubbub_parser_destroy(html->parser);
- html->parser = NULL;
- }
-
- if (html->document != NULL) {
- dom_node_unref(html->document);
- html->document = NULL;
- }
-
- if (html->title != NULL) {
- dom_node_unref(html->title);
- html->title = NULL;
- }
-
- /* Free encoding */
- if (html->encoding != NULL) {
- free(html->encoding);
- html->encoding = NULL;
- }
-
- /* Free base target */
- if (html->base_target != NULL) {
- free(html->base_target);
- html->base_target = NULL;
- }
-
- /* Free frameset */
- if (html->frameset != NULL) {
- html_destroy_frameset(html->frameset);
- talloc_free(html->frameset);
- html->frameset = NULL;
- }
-
- /* Free iframes */
- if (html->iframe != NULL) {
- html_destroy_iframe(html->iframe);
- html->iframe = NULL;
- }
-
- /* Destroy selection context */
- if (html->select_ctx != NULL) {
- css_select_ctx_destroy(html->select_ctx);
- html->select_ctx = NULL;
- }
-
- if (html->universal != NULL) {
- lwc_string_unref(html->universal);
- html->universal = NULL;
- }
-
- /* Free stylesheets */
- html_css_free_stylesheets(html);
-
- /* Free scripts */
- html_script_free(html);
-
- /* Free objects */
- html_object_free_objects(html);
-
- /* free layout */
- html_free_layout(html);
-}
-
-
-static nserror html_clone(const struct content *old, struct content **newc)
-{
- /** \todo Clone HTML specifics */
-
- /* In the meantime, we should never be called, as HTML contents
- * cannot be shared and we're not intending to fix printing's
- * cloning of documents. */
- assert(0 && "html_clone should never be called");
-
- return true;
-}
-
-
-/**
- * Handle a window containing a CONTENT_HTML being opened.
- */
-
-static void
-html_open(struct content *c,
- struct browser_window *bw,
- struct content *page,
- struct object_params *params)
-{
- html_content *html = (html_content *) c;
-
- html->bw = bw;
- html->page = (html_content *) page;
-
- html->drag_type = HTML_DRAG_NONE;
- html->drag_owner.no_owner = true;
-
- /* text selection */
- selection_init(&html->sel, html->layout, &html->len_ctx);
- html->selection_type = HTML_SELECTION_NONE;
- html->selection_owner.none = true;
-
- html_object_open_objects(html, bw);
-}
-
-
-/**
- * Handle a window containing a CONTENT_HTML being closed.
- */
-
-static void html_close(struct content *c)
-{
- html_content *htmlc = (html_content *) c;
-
- selection_clear(&htmlc->sel, false);
-
- if (htmlc->search != NULL) {
- search_destroy_context(htmlc->search);
- }
-
- /* clear the html content reference to the browser window */
- htmlc->bw = NULL;
-
- /* invalidate the html content reference to the javascript context
- * as it is about to become invalid and must not be used any
- * more.
- */
- html_script_invalidate_ctx(htmlc);
-
- /* remove all object references from the html content */
- html_object_close_objects(htmlc);
-}
-
-
-/**
- * Return an HTML content's selection context
- */
-
-static void html_clear_selection(struct content *c)
-{
- html_content *html = (html_content *) c;
-
- switch (html->selection_type) {
- case HTML_SELECTION_NONE:
- /* Nothing to do */
- assert(html->selection_owner.none == true);
- break;
- case HTML_SELECTION_TEXTAREA:
- textarea_clear_selection(html->selection_owner.textarea->
- gadget->data.text.ta);
- break;
- case HTML_SELECTION_SELF:
- assert(html->selection_owner.none == false);
- selection_clear(&html->sel, true);
- break;
- case HTML_SELECTION_CONTENT:
- content_clear_selection(html->selection_owner.content->object);
- break;
- default:
- break;
- }
-
- /* There is no selection now. */
- html->selection_type = HTML_SELECTION_NONE;
- html->selection_owner.none = true;
-}
-
-
-/**
- * Return an HTML content's selection context
- */
-
-static char *html_get_selection(struct content *c)
-{
- html_content *html = (html_content *) c;
-
- switch (html->selection_type) {
- case HTML_SELECTION_TEXTAREA:
- return textarea_get_selection(html->selection_owner.textarea->
- gadget->data.text.ta);
- case HTML_SELECTION_SELF:
- assert(html->selection_owner.none == false);
- return selection_get_copy(&html->sel);
- case HTML_SELECTION_CONTENT:
- return content_get_selection(
- html->selection_owner.content->object);
- case HTML_SELECTION_NONE:
- /* Nothing to do */
- assert(html->selection_owner.none == true);
- break;
- default:
- break;
- }
-
- return NULL;
-}
-
-
-/**
- * Get access to any content, link URLs and objects (images) currently
- * at the given (x, y) coordinates.
- *
- * \param[in] c html content to look inside
- * \param[in] x x-coordinate of point of interest
- * \param[in] y y-coordinate of point of interest
- * \param[out] data Positional features struct to be updated with any
- * relevent content, or set to NULL if none.
- * \return NSERROR_OK on success else appropriate error code.
- */
-static nserror
-html_get_contextual_content(struct content *c, int x, int y,
- struct browser_window_features *data)
-{
- html_content *html = (html_content *) c;
-
- struct box *box = html->layout;
- struct box *next;
- int box_x = 0, box_y = 0;
-
- while ((next = box_at_point(&html->len_ctx, box, x, y,
- &box_x, &box_y)) != NULL) {
- box = next;
-
- /* hidden boxes are ignored */
- if ((box->style != NULL) &&
- css_computed_visibility(box->style) == CSS_VISIBILITY_HIDDEN) {
- continue;
- }
-
- if (box->iframe) {
- browser_window_get_features(box->iframe,
- x - box_x, y - box_y, data);
- }
-
- if (box->object)
- content_get_contextual_content(box->object,
- x - box_x, y - box_y, data);
-
- if (box->object)
- data->object = box->object;
-
- if (box->href)
- data->link = box->href;
-
- if (box->usemap) {
- const char *target = NULL;
- nsurl *url = imagemap_get(html, box->usemap, box_x,
- box_y, x, y, &target);
- /* Box might have imagemap, but no actual link area
- * at point */
- if (url != NULL)
- data->link = url;
- }
- if (box->gadget) {
- switch (box->gadget->type) {
- case GADGET_TEXTBOX:
- case GADGET_TEXTAREA:
- case GADGET_PASSWORD:
- data->form_features = CTX_FORM_TEXT;
- break;
-
- case GADGET_FILE:
- data->form_features = CTX_FORM_FILE;
- break;
-
- default:
- data->form_features = CTX_FORM_NONE;
- break;
- }
- }
- }
- return NSERROR_OK;
-}
-
-
-/**
- * Scroll deepest thing within the content which can be scrolled at given point
- *
- * \param c html content to look inside
- * \param x x-coordinate of point of interest
- * \param y y-coordinate of point of interest
- * \param scrx number of px try to scroll something in x direction
- * \param scry number of px try to scroll something in y direction
- * \return true iff scroll was consumed by something in the content
- */
-static bool
-html_scroll_at_point(struct content *c, int x, int y, int scrx, int scry)
-{
- html_content *html = (html_content *) c;
-
- struct box *box = html->layout;
- struct box *next;
- int box_x = 0, box_y = 0;
- bool handled_scroll = false;
-
- /* TODO: invert order; visit deepest box first */
-
- while ((next = box_at_point(&html->len_ctx, box, x, y,
- &box_x, &box_y)) != NULL) {
- box = next;
-
- if (box->style && css_computed_visibility(box->style) ==
- CSS_VISIBILITY_HIDDEN)
- continue;
-
- /* Pass into iframe */
- if (box->iframe && browser_window_scroll_at_point(box->iframe,
- x - box_x, y - box_y, scrx, scry) == true)
- return true;
-
- /* Pass into textarea widget */
- if (box->gadget && (box->gadget->type == GADGET_TEXTAREA ||
- box->gadget->type == GADGET_PASSWORD ||
- box->gadget->type == GADGET_TEXTBOX) &&
- textarea_scroll(box->gadget->data.text.ta,
- scrx, scry) == true)
- return true;
-
- /* Pass into object */
- if (box->object != NULL && content_scroll_at_point(
- box->object, x - box_x, y - box_y,
- scrx, scry) == true)
- return true;
-
- /* Handle box scrollbars */
- if (box->scroll_y && scrollbar_scroll(box->scroll_y, scry))
- handled_scroll = true;
-
- if (box->scroll_x && scrollbar_scroll(box->scroll_x, scrx))
- handled_scroll = true;
-
- if (handled_scroll == true)
- return true;
- }
-
- return false;
-}
-
-/** Helper for file gadgets to store their filename unencoded on the
- * dom node associated with the gadget.
- *
- * \todo Get rid of this crap eventually
- */
-static void html__dom_user_data_handler(dom_node_operation operation,
- dom_string *key, void *_data, struct dom_node *src,
- struct dom_node *dst)
-{
- char *oldfile;
- char *data = (char *)_data;
-
- if (!dom_string_isequal(corestring_dom___ns_key_file_name_node_data,
- key) || data == NULL) {
- return;
- }
-
- switch (operation) {
- case DOM_NODE_CLONED:
- if (dom_node_set_user_data(dst,
- corestring_dom___ns_key_file_name_node_data,
- strdup(data), html__dom_user_data_handler,
- &oldfile) == DOM_NO_ERR) {
- if (oldfile != NULL)
- free(oldfile);
- }
- break;
-
- case DOM_NODE_RENAMED:
- case DOM_NODE_IMPORTED:
- case DOM_NODE_ADOPTED:
- break;
-
- case DOM_NODE_DELETED:
- free(data);
- break;
- default:
- NSLOG(netsurf, INFO, "User data operation not handled.");
- assert(0);
- }
-}
-
-static void html__set_file_gadget_filename(struct content *c,
- struct form_control *gadget, const char *fn)
-{
- nserror ret;
- char *utf8_fn, *oldfile = NULL;
- html_content *html = (html_content *)c;
- struct box *file_box = gadget->box;
-
- ret = guit->utf8->local_to_utf8(fn, 0, &utf8_fn);
- if (ret != NSERROR_OK) {
- assert(ret != NSERROR_BAD_ENCODING);
- NSLOG(netsurf, INFO,
- "utf8 to local encoding conversion failed");
- /* Load was for us - just no memory */
- return;
- }
-
- form_gadget_update_value(gadget, utf8_fn);
-
- /* corestring_dom___ns_key_file_name_node_data */
- if (dom_node_set_user_data((dom_node *)file_box->gadget->node,
- corestring_dom___ns_key_file_name_node_data,
- strdup(fn), html__dom_user_data_handler,
- &oldfile) == DOM_NO_ERR) {
- if (oldfile != NULL)
- free(oldfile);
- }
-
- /* Redraw box. */
- html__redraw_a_box(html, file_box);
-}
-
-void html_set_file_gadget_filename(struct hlcache_handle *hl,
- struct form_control *gadget, const char *fn)
-{
- return html__set_file_gadget_filename(hlcache_handle_get_content(hl),
- gadget, fn);
-}
-
-/**
- * Drop a file onto a content at a particular point, or determine if a file
- * may be dropped onto the content at given point.
- *
- * \param c html content to look inside
- * \param x x-coordinate of point of interest
- * \param y y-coordinate of point of interest
- * \param file path to file to be dropped, or NULL to know if drop allowed
- * \return true iff file drop has been handled, or if drop possible (NULL file)
- */
-static bool html_drop_file_at_point(struct content *c, int x, int y, char *file)
-{
- html_content *html = (html_content *) c;
-
- struct box *box = html->layout;
- struct box *next;
- struct box *file_box = NULL;
- struct box *text_box = NULL;
- int box_x = 0, box_y = 0;
-
- /* Scan box tree for boxes that can handle drop */
- while ((next = box_at_point(&html->len_ctx, box, x, y,
- &box_x, &box_y)) != NULL) {
- box = next;
-
- if (box->style && css_computed_visibility(box->style) ==
- CSS_VISIBILITY_HIDDEN)
- continue;
-
- if (box->iframe)
- return browser_window_drop_file_at_point(box->iframe,
- x - box_x, y - box_y, file);
-
- if (box->object && content_drop_file_at_point(box->object,
- x - box_x, y - box_y, file) == true)
- return true;
-
- if (box->gadget) {
- switch (box->gadget->type) {
- case GADGET_FILE:
- file_box = box;
- break;
-
- case GADGET_TEXTBOX:
- case GADGET_TEXTAREA:
- case GADGET_PASSWORD:
- text_box = box;
- break;
-
- default: /* appease compiler */
- break;
- }
- }
- }
-
- if (!file_box && !text_box)
- /* No box capable of handling drop */
- return false;
-
- if (file == NULL)
- /* There is a box capable of handling drop here */
- return true;
-
- /* Handle the drop */
- if (file_box) {
- /* File dropped on file input */
- html__set_file_gadget_filename(c, file_box->gadget, file);
-
- } else {
- /* File dropped on text input */
-
- size_t file_len;
- FILE *fp = NULL;
- char *buffer;
- char *utf8_buff;
- nserror ret;
- unsigned int size;
- int bx, by;
-
- /* Open file */
- fp = fopen(file, "rb");
- if (fp == NULL) {
- /* Couldn't open file, but drop was for us */
- return true;
- }
-
- /* Get filesize */
- fseek(fp, 0, SEEK_END);
- file_len = ftell(fp);
- fseek(fp, 0, SEEK_SET);
-
- if ((long)file_len == -1) {
- /* unable to get file length, but drop was for us */
- fclose(fp);
- return true;
- }
-
- /* Allocate buffer for file data */
- buffer = malloc(file_len + 1);
- if (buffer == NULL) {
- /* No memory, but drop was for us */
- fclose(fp);
- return true;
- }
-
- /* Stick file into buffer */
- if (file_len != fread(buffer, 1, file_len, fp)) {
- /* Failed, but drop was for us */
- free(buffer);
- fclose(fp);
- return true;
- }
-
- /* Done with file */
- fclose(fp);
-
- /* Ensure buffer's string termination */
- buffer[file_len] = '\0';
-
- /* TODO: Sniff for text? */
-
- /* Convert to UTF-8 */
- ret = guit->utf8->local_to_utf8(buffer, file_len, &utf8_buff);
- if (ret != NSERROR_OK) {
- /* bad encoding shouldn't happen */
- assert(ret != NSERROR_BAD_ENCODING);
- NSLOG(netsurf, INFO, "local to utf8 encoding failed");
- free(buffer);
- guit->misc->warning("NoMemory", NULL);
- return true;
- }
-
- /* Done with buffer */
- free(buffer);
-
- /* Get new length */
- size = strlen(utf8_buff);
-
- /* Simulate a click over the input box, to place caret */
- box_coords(text_box, &bx, &by);
- textarea_mouse_action(text_box->gadget->data.text.ta,
- BROWSER_MOUSE_PRESS_1, x - bx, y - by);
-
- /* Paste the file as text */
- textarea_drop_text(text_box->gadget->data.text.ta,
- utf8_buff, size);
-
- free(utf8_buff);
- }
-
- return true;
-}
-
-
-/**
- * set debug status.
- *
- * \param c The content to debug
- * \param op The debug operation type
- */
-static nserror
-html_debug(struct content *c, enum content_debug op)
-{
- html_redraw_debug = !html_redraw_debug;
-
- return NSERROR_OK;
-}
-
-
-/**
- * Dump debug info concerning the html_content
- *
- * \param c The content to debug
- * \param f The file to dump to
- * \param op The debug dump type
- */
-static nserror
-html_debug_dump(struct content *c, FILE *f, enum content_debug op)
-{
- html_content *htmlc = (html_content *)c;
- dom_node *html;
- dom_exception exc; /* returned by libdom functions */
- nserror ret;
-
- assert(htmlc != NULL);
-
- if (op == CONTENT_DEBUG_RENDER) {
- assert(htmlc->layout != NULL);
- box_dump(f, htmlc->layout, 0, true);
- ret = NSERROR_OK;
- } else {
- if (htmlc->document == NULL) {
- NSLOG(netsurf, INFO, "No document to dump");
- return NSERROR_DOM;
- }
-
- exc = dom_document_get_document_element(htmlc->document, (void *) &html);
- if ((exc != DOM_NO_ERR) || (html == NULL)) {
- NSLOG(netsurf, INFO, "Unable to obtain root node");
- return NSERROR_DOM;
- }
-
- ret = libdom_dump_structure(html, f, 0);
-
- NSLOG(netsurf, INFO, "DOM structure dump returning %d", ret);
-
- dom_node_unref(html);
- }
-
- return ret;
-}
-
-
-#if ALWAYS_DUMP_FRAMESET
-/**
- * Print a frameset tree to stderr.
- */
-
-static void
-html_dump_frameset(struct content_html_frames *frame, unsigned int depth)
-{
- unsigned int i;
- int row, col, index;
- const char *unit[] = {"px", "%", "*"};
- const char *scrolling[] = {"auto", "yes", "no"};
-
- assert(frame);
-
- fprintf(stderr, "%p ", frame);
-
- fprintf(stderr, "(%i %i) ", frame->rows, frame->cols);
-
- fprintf(stderr, "w%g%s ", frame->width.value, unit[frame->width.unit]);
- fprintf(stderr, "h%g%s ", frame->height.value,unit[frame->height.unit]);
- fprintf(stderr, "(margin w%i h%i) ",
- frame->margin_width, frame->margin_height);
-
- if (frame->name)
- fprintf(stderr, "'%s' ", frame->name);
- if (frame->url)
- fprintf(stderr, "<%s> ", frame->url);
-
- if (frame->no_resize)
- fprintf(stderr, "noresize ");
- fprintf(stderr, "(scrolling %s) ", scrolling[frame->scrolling]);
- if (frame->border)
- fprintf(stderr, "border %x ",
- (unsigned int) frame->border_colour);
-
- fprintf(stderr, "\n");
-
- if (frame->children) {
- for (row = 0; row != frame->rows; row++) {
- for (col = 0; col != frame->cols; col++) {
- for (i = 0; i != depth; i++)
- fprintf(stderr, " ");
- fprintf(stderr, "(%i %i): ", row, col);
- index = (row * frame->cols) + col;
- html_dump_frameset(&frame->children[index],
- depth + 1);
- }
- }
- }
-}
-
-#endif
-
-/**
- * Retrieve HTML document tree
- *
- * \param h HTML content to retrieve document tree from
- * \return Pointer to document tree
- */
-dom_document *html_get_document(hlcache_handle *h)
-{
- html_content *c = (html_content *) hlcache_handle_get_content(h);
-
- assert(c != NULL);
-
- return c->document;
-}
-
-/**
- * Retrieve box tree
- *
- * \param h HTML content to retrieve tree from
- * \return Pointer to box tree
- *
- * \todo This API must die, as must all use of the box tree outside render/
- */
-struct box *html_get_box_tree(hlcache_handle *h)
-{
- html_content *c = (html_content *) hlcache_handle_get_content(h);
-
- assert(c != NULL);
-
- return c->layout;
-}
-
-/**
- * Retrieve the charset of an HTML document
- *
- * \param c Content to retrieve charset from
- * \param op The content encoding operation to perform.
- * \return Pointer to charset, or NULL
- */
-static const char *html_encoding(const struct content *c, enum content_encoding_type op)
-{
- html_content *html = (html_content *) c;
- static char enc_token[10] = "Encoding0";
-
- assert(html != NULL);
-
- if (op == CONTENT_ENCODING_SOURCE) {
- enc_token[8] = '0' + html->encoding_source;
- return messages_get(enc_token);
- }
-
- return html->encoding;
-}
-
-
-/**
- * Retrieve framesets used in an HTML document
- *
- * \param h Content to inspect
- * \return Pointer to framesets, or NULL if none
- */
-struct content_html_frames *html_get_frameset(hlcache_handle *h)
-{
- html_content *c = (html_content *) hlcache_handle_get_content(h);
-
- assert(c != NULL);
-
- return c->frameset;
-}
-
-/**
- * Retrieve iframes used in an HTML document
- *
- * \param h Content to inspect
- * \return Pointer to iframes, or NULL if none
- */
-struct content_html_iframe *html_get_iframe(hlcache_handle *h)
-{
- html_content *c = (html_content *) hlcache_handle_get_content(h);
-
- assert(c != NULL);
-
- return c->iframe;
-}
-
-/**
- * Retrieve an HTML content's base URL
- *
- * \param h Content to retrieve base target from
- * \return Pointer to URL
- */
-nsurl *html_get_base_url(hlcache_handle *h)
-{
- html_content *c = (html_content *) hlcache_handle_get_content(h);
-
- assert(c != NULL);
-
- return c->base_url;
-}
-
-/**
- * Retrieve an HTML content's base target
- *
- * \param h Content to retrieve base target from
- * \return Pointer to target, or NULL if none
- */
-const char *html_get_base_target(hlcache_handle *h)
-{
- html_content *c = (html_content *) hlcache_handle_get_content(h);
-
- assert(c != NULL);
-
- return c->base_target;
-}
-
-
-/**
- * Retrieve layout coordinates of box with given id
- *
- * \param h HTML document to search
- * \param frag_id String containing an element id
- * \param x Updated to global x coord iff id found
- * \param y Updated to global y coord iff id found
- * \return true iff id found
- */
-bool html_get_id_offset(hlcache_handle *h, lwc_string *frag_id, int *x, int *y)
-{
- struct box *pos;
- struct box *layout;
-
- if (content_get_type(h) != CONTENT_HTML)
- return false;
-
- layout = html_get_box_tree(h);
-
- if ((pos = box_find_by_id(layout, frag_id)) != 0) {
- box_coords(pos, x, y);
- return true;
- }
- return false;
-}
-
-/**
- * Compute the type of a content
- *
- * \return CONTENT_HTML
- */
-static content_type html_content_type(void)
-{
- return CONTENT_HTML;
-}
-
-
-static void html_fini(void)
-{
- html_css_fini();
-}
-
-static const content_handler html_content_handler = {
- .fini = html_fini,
- .create = html_create,
- .process_data = html_process_data,
- .data_complete = html_convert,
- .reformat = html_reformat,
- .destroy = html_destroy,
- .stop = html_stop,
- .mouse_track = html_mouse_track,
- .mouse_action = html_mouse_action,
- .keypress = html_keypress,
- .redraw = html_redraw,
- .open = html_open,
- .close = html_close,
- .get_selection = html_get_selection,
- .clear_selection = html_clear_selection,
- .get_contextual_content = html_get_contextual_content,
- .scroll_at_point = html_scroll_at_point,
- .drop_file_at_point = html_drop_file_at_point,
- .search = html_search,
- .search_clear = html_search_clear,
- .debug_dump = html_debug_dump,
- .debug = html_debug,
- .clone = html_clone,
- .get_encoding = html_encoding,
- .type = html_content_type,
- .no_share = true,
-};
-
-nserror html_init(void)
-{
- uint32_t i;
- nserror error;
-
- error = html_css_init();
- if (error != NSERROR_OK)
- goto error;
-
- for (i = 0; i < NOF_ELEMENTS(html_types); i++) {
- error = content_factory_register_handler(html_types[i],
- &html_content_handler);
- if (error != NSERROR_OK)
- goto error;
- }
-
- return NSERROR_OK;
-
-error:
- html_fini();
-
- return error;
-}
-
-/**
- * Get the browser window containing an HTML content
- *
- * \param c HTML content
- * \return the browser window
- */
-struct browser_window *html_get_browser_window(struct content *c)
-{
- html_content *html = (html_content *) c;
-
- assert(c != NULL);
- assert(c->handler == &html_content_handler);
-
- return html->bw;
-}
diff --git a/render/html.h b/render/html.h
deleted file mode 100644
index 30219a3bd..000000000
--- a/render/html.h
+++ /dev/null
@@ -1,197 +0,0 @@
-/*
- * Copyright 2004 James Bursa <bursa@users.sourceforge.net>
- *
- * This file is part of NetSurf, http://www.netsurf-browser.org/
- *
- * NetSurf is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * NetSurf is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-/** \file
- * Content for text/html (interface).
- *
- * These functions should in general be called via the content interface.
- */
-
-#ifndef _NETSURF_RENDER_HTML_H_
-#define _NETSURF_RENDER_HTML_H_
-
-#include <stdbool.h>
-
-#include <dom/dom.h>
-#include <dom/bindings/hubbub/parser.h>
-
-#include "netsurf/types.h"
-#include "netsurf/content_type.h"
-#include "netsurf/browser_window.h"
-#include "netsurf/mouse.h"
-#include "desktop/frame_types.h"
-
-struct fetch_multipart_data;
-struct box;
-struct rect;
-struct browser_window;
-struct content;
-struct hlcache_handle;
-struct http_parameter;
-struct imagemap;
-struct object_params;
-struct plotters;
-struct textarea;
-struct scrollbar;
-struct scrollbar_msg_data;
-struct search_context;
-struct selection;
-struct nsurl;
-struct plot_font_style;
-
-/**
- * Container for stylesheets used by an HTML document
- */
-struct html_stylesheet {
- struct dom_node *node; /**< dom node associated with sheet */
- struct hlcache_handle *sheet;
- bool modified;
- bool unused;
-};
-
-/**
- * Container for scripts used by an HTML document
- */
-struct html_script {
- /** Type of script */
- enum html_script_type { HTML_SCRIPT_INLINE,
- HTML_SCRIPT_SYNC,
- HTML_SCRIPT_DEFER,
- HTML_SCRIPT_ASYNC } type;
- union {
- struct hlcache_handle *handle;
- struct dom_string *string;
- } data; /**< Script data */
- struct dom_string *mimetype;
- struct dom_string *encoding;
- bool already_started;
- bool parser_inserted;
- bool force_async;
- bool ready_exec;
- bool async;
- bool defer;
-};
-
-
-/** An object (img, object, etc. tag) in a CONTENT_HTML document. */
-struct content_html_object {
- struct content *parent; /**< Parent document */
- struct content_html_object *next; /**< Next in chain */
-
- struct hlcache_handle *content; /**< Content, or 0. */
- struct box *box; /**< Node in box tree containing it. */
- /** Bitmap of acceptable content types */
- content_type permitted_types;
- bool background; /**< This object is a background image. */
-};
-
-struct html_scrollbar_data {
- struct content *c;
- struct box *box;
-};
-
-/** Frame tree (frameset or frame tag) */
-struct content_html_frames {
- int cols; /** number of columns in frameset */
- int rows; /** number of rows in frameset */
-
- struct frame_dimension width; /** frame width */
- struct frame_dimension height; /** frame width */
- int margin_width; /** frame margin width */
- int margin_height; /** frame margin height */
-
- char *name; /** frame name (for targetting) */
- struct nsurl *url; /** frame url */
-
- bool no_resize; /** frame is not resizable */
- browser_scrolling scrolling; /** scrolling characteristics */
- bool border; /** frame has a border */
- colour border_colour; /** frame border colour */
-
- struct content_html_frames *children; /** [cols * rows] children */
-};
-
-/** Inline frame list (iframe tag) */
-struct content_html_iframe {
- struct box *box;
-
- int margin_width; /** frame margin width */
- int margin_height; /** frame margin height */
-
- char *name; /** frame name (for targetting) */
- struct nsurl *url; /** frame url */
-
- browser_scrolling scrolling; /** scrolling characteristics */
- bool border; /** frame has a border */
- colour border_colour; /** frame border colour */
-
- struct content_html_iframe *next;
-};
-
-/* entries in stylesheet_content */
-#define STYLESHEET_BASE 0 /* base style sheet */
-#define STYLESHEET_QUIRKS 1 /* quirks mode stylesheet */
-#define STYLESHEET_ADBLOCK 2 /* adblocking stylesheet */
-#define STYLESHEET_USER 3 /* user stylesheet */
-#define STYLESHEET_START 4 /* start of document stylesheets */
-
-nserror html_init(void);
-
-void html_redraw_a_box(struct hlcache_handle *h, struct box *box);
-
-void html_overflow_scroll_drag_end(struct scrollbar *scrollbar,
- browser_mouse_state mouse, int x, int y);
-
-bool text_redraw(const char *utf8_text, size_t utf8_len,
- size_t offset, int space,
- const struct plot_font_style *fstyle,
- int x, int y,
- const struct rect *clip,
- int height,
- float scale,
- bool excluded,
- struct content *c,
- const struct selection *sel,
- struct search_context *search,
- const struct redraw_context *ctx);
-
-dom_document *html_get_document(struct hlcache_handle *h);
-struct box *html_get_box_tree(struct hlcache_handle *h);
-struct content_html_frames *html_get_frameset(struct hlcache_handle *h);
-struct content_html_iframe *html_get_iframe(struct hlcache_handle *h);
-struct nsurl *html_get_base_url(struct hlcache_handle *h);
-const char *html_get_base_target(struct hlcache_handle *h);
-void html_set_file_gadget_filename(struct hlcache_handle *hl,
- struct form_control *gadget, const char *fn);
-
-/**
- * Retrieve stylesheets used by HTML document
- *
- * \param h Content to retrieve stylesheets from
- * \param n Pointer to location to receive number of sheets
- * \return Pointer to array of stylesheets
- */
-struct html_stylesheet *html_get_stylesheets(struct hlcache_handle *h,
- unsigned int *n);
-
-struct content_html_object *html_get_objects(struct hlcache_handle *h,
- unsigned int *n);
-bool html_get_id_offset(struct hlcache_handle *h, lwc_string *frag_id,
- int *x, int *y);
-
-#endif
diff --git a/render/html_css.c b/render/html_css.c
deleted file mode 100644
index 45bc16f56..000000000
--- a/render/html_css.c
+++ /dev/null
@@ -1,713 +0,0 @@
-/*
- * Copyright 2013 Vincent Sanders <vince@netsurf-browser.org>
- *
- * This file is part of NetSurf, http://www.netsurf-browser.org/
- *
- * NetSurf is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * NetSurf is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-/** \file
- * Processing for html content css operations.
- */
-
-#include <assert.h>
-#include <ctype.h>
-#include <stdint.h>
-#include <string.h>
-#include <strings.h>
-#include <stdlib.h>
-
-#include "utils/nsoption.h"
-#include "utils/corestrings.h"
-#include "utils/config.h"
-#include "utils/log.h"
-#include "netsurf/misc.h"
-#include "netsurf/content.h"
-#include "content/hlcache.h"
-#include "css/css.h"
-#include "desktop/gui_internal.h"
-
-#include "render/html_internal.h"
-
-static nsurl *html_default_stylesheet_url;
-static nsurl *html_adblock_stylesheet_url;
-static nsurl *html_quirks_stylesheet_url;
-static nsurl *html_user_stylesheet_url;
-
-static nserror css_error_to_nserror(css_error error)
-{
- switch (error) {
- case CSS_OK:
- return NSERROR_OK;
-
- case CSS_NOMEM:
- return NSERROR_NOMEM;
-
- case CSS_BADPARM:
- return NSERROR_BAD_PARAMETER;
-
- case CSS_INVALID:
- return NSERROR_INVALID;
-
- case CSS_FILENOTFOUND:
- return NSERROR_NOT_FOUND;
-
- case CSS_NEEDDATA:
- return NSERROR_NEED_DATA;
-
- case CSS_BADCHARSET:
- return NSERROR_BAD_ENCODING;
-
- case CSS_EOF:
- case CSS_IMPORTS_PENDING:
- case CSS_PROPERTY_NOT_SET:
- default:
- break;
- }
- return NSERROR_CSS;
-}
-
-/**
- * Callback for fetchcache() for stylesheets.
- */
-
-static nserror
-html_convert_css_callback(hlcache_handle *css,
- const hlcache_event *event,
- void *pw)
-{
- html_content *parent = pw;
- unsigned int i;
- struct html_stylesheet *s;
-
- /* Find sheet */
- for (i = 0, s = parent->stylesheets;
- i != parent->stylesheet_count;
- i++, s++) {
- if (s->sheet == css)
- break;
- }
-
- assert(i != parent->stylesheet_count);
-
- switch (event->type) {
-
- case CONTENT_MSG_DONE:
- NSLOG(netsurf, INFO, "done stylesheet slot %d '%s'", i,
- nsurl_access(hlcache_handle_get_url(css)));
- parent->base.active--;
- NSLOG(netsurf, INFO, "%d fetches active", parent->base.active);
- break;
-
- case CONTENT_MSG_ERROR:
- NSLOG(netsurf, INFO, "stylesheet %s failed: %s",
- nsurl_access(hlcache_handle_get_url(css)),
- event->data.error);
- /* fall through */
-
- case CONTENT_MSG_ERRORCODE:
- hlcache_handle_release(css);
- s->sheet = NULL;
- parent->base.active--;
- NSLOG(netsurf, INFO, "%d fetches active", parent->base.active);
- content_add_error(&parent->base, "?", 0);
- break;
-
- case CONTENT_MSG_POINTER:
- /* Really don't want this to continue after the switch */
- return NSERROR_OK;
-
- default:
- break;
- }
-
- if (html_can_begin_conversion(parent)) {
- html_begin_conversion(parent);
- }
-
- return NSERROR_OK;
-}
-
-static nserror
-html_stylesheet_from_domnode(html_content *c,
- dom_node *node,
- hlcache_handle **sheet)
-{
- hlcache_child_context child;
- dom_string *style;
- nsurl *url;
- dom_exception exc;
- nserror error;
- uint32_t key;
- char urlbuf[64];
-
- child.charset = c->encoding;
- child.quirks = c->base.quirks;
-
- exc = dom_node_get_text_content(node, &style);
- if ((exc != DOM_NO_ERR) || (style == NULL)) {
- NSLOG(netsurf, INFO, "No text content");
- return NSERROR_OK;
- }
-
- error = html_css_fetcher_add_item(style, c->base_url, &key);
- if (error != NSERROR_OK) {
- dom_string_unref(style);
- return error;
- }
-
- dom_string_unref(style);
-
- snprintf(urlbuf, sizeof(urlbuf), "x-ns-css:%u", key);
-
- error = nsurl_create(urlbuf, &url);
- if (error != NSERROR_OK) {
- return error;
- }
-
- error = hlcache_handle_retrieve(url, 0,
- content_get_url(&c->base), NULL,
- html_convert_css_callback, c, &child, CONTENT_CSS,
- sheet);
- if (error != NSERROR_OK) {
- nsurl_unref(url);
- return error;
- }
-
- nsurl_unref(url);
-
- c->base.active++;
- NSLOG(netsurf, INFO, "%d fetches active", c->base.active);
-
- return NSERROR_OK;
-}
-
-/**
- * Process an inline stylesheet in the document.
- *
- * \param c content structure
- * \param style xml node of style element
- * \return true on success, false if an error occurred
- */
-
-static struct html_stylesheet *
-html_create_style_element(html_content *c, dom_node *style)
-{
- dom_string *val;
- dom_exception exc;
- struct html_stylesheet *stylesheets;
-
- /* type='text/css', or not present (invalid but common) */
- exc = dom_element_get_attribute(style, corestring_dom_type, &val);
- if (exc == DOM_NO_ERR && val != NULL) {
- if (!dom_string_caseless_lwc_isequal(val,
- corestring_lwc_text_css)) {
- dom_string_unref(val);
- return NULL;
- }
- dom_string_unref(val);
- }
-
- /* media contains 'screen' or 'all' or not present */
- exc = dom_element_get_attribute(style, corestring_dom_media, &val);
- if (exc == DOM_NO_ERR && val != NULL) {
- if (strcasestr(dom_string_data(val), "screen") == NULL &&
- strcasestr(dom_string_data(val),
- "all") == NULL) {
- dom_string_unref(val);
- return NULL;
- }
- dom_string_unref(val);
- }
-
- /* Extend array */
- stylesheets = realloc(c->stylesheets,
- sizeof(struct html_stylesheet) *
- (c->stylesheet_count + 1));
- if (stylesheets == NULL) {
-
- content_broadcast_errorcode(&c->base, NSERROR_NOMEM);
- return false;
-
- }
- c->stylesheets = stylesheets;
-
- c->stylesheets[c->stylesheet_count].node = dom_node_ref(style);
- c->stylesheets[c->stylesheet_count].sheet = NULL;
- c->stylesheets[c->stylesheet_count].modified = false;
- c->stylesheets[c->stylesheet_count].unused = false;
- c->stylesheet_count++;
-
- return c->stylesheets + (c->stylesheet_count - 1);
-}
-
-static bool html_css_process_modified_style(html_content *c,
- struct html_stylesheet *s)
-{
- hlcache_handle *sheet = NULL;
- nserror error;
-
- error = html_stylesheet_from_domnode(c, s->node, &sheet);
- if (error != NSERROR_OK) {
- NSLOG(netsurf, INFO, "Failed to update sheet");
- content_broadcast_errorcode(&c->base, error);
- return false;
- }
-
- if (sheet != NULL) {
- NSLOG(netsurf, INFO, "Updating sheet %p with %p", s->sheet,
- sheet);
-
- if (s->sheet != NULL) {
- switch (content_get_status(s->sheet)) {
- case CONTENT_STATUS_DONE:
- break;
- default:
- hlcache_handle_abort(s->sheet);
- c->base.active--;
- NSLOG(netsurf, INFO, "%d fetches active",
- c->base.active);
- }
- hlcache_handle_release(s->sheet);
- }
- s->sheet = sheet;
- }
-
- s->modified = false;
-
- return true;
-}
-
-static void html_css_process_modified_styles(void *pw)
-{
- html_content *c = pw;
- struct html_stylesheet *s;
- unsigned int i;
- bool all_done = true;
-
- for (i = 0, s = c->stylesheets; i != c->stylesheet_count; i++, s++) {
- if (c->stylesheets[i].modified) {
- all_done &= html_css_process_modified_style(c, s);
- }
- }
-
- /* If we failed to process any sheet, schedule a retry */
- if (all_done == false) {
- guit->misc->schedule(1000, html_css_process_modified_styles, c);
- }
-}
-
-bool html_css_update_style(html_content *c, dom_node *style)
-{
- unsigned int i;
- struct html_stylesheet *s;
-
- /* Find sheet */
- for (i = 0, s = c->stylesheets; i != c->stylesheet_count; i++, s++) {
- if (s->node == style)
- break;
- }
- if (i == c->stylesheet_count) {
- s = html_create_style_element(c, style);
- }
- if (s == NULL) {
- NSLOG(netsurf, INFO,
- "Could not find or create inline stylesheet for %p",
- style);
- return false;
- }
-
- s->modified = true;
-
- guit->misc->schedule(0, html_css_process_modified_styles, c);
-
- return true;
-}
-
-bool html_css_process_style(html_content *c, dom_node *node)
-{
- unsigned int i;
- dom_string *val;
- dom_exception exc;
- struct html_stylesheet *s;
-
- /* Find sheet */
- for (i = 0, s = c->stylesheets; i != c->stylesheet_count; i++, s++) {
- if (s->node == node)
- break;
- }
-
- /* Should already exist */
- if (i == c->stylesheet_count) {
- return false;
- }
-
- exc = dom_element_get_attribute(node, corestring_dom_media, &val);
- if (exc == DOM_NO_ERR && val != NULL) {
- if (strcasestr(dom_string_data(val), "screen") == NULL &&
- strcasestr(dom_string_data(val),
- "all") == NULL) {
- s->unused = true;
- }
- dom_string_unref(val);
- }
-
- return true;
-}
-
-bool html_css_process_link(html_content *htmlc, dom_node *node)
-{
- dom_string *rel, *type_attr, *media, *href;
- struct html_stylesheet *stylesheets;
- nsurl *joined;
- dom_exception exc;
- nserror ns_error;
- hlcache_child_context child;
-
- /* rel=<space separated list, including 'stylesheet'> */
- exc = dom_element_get_attribute(node, corestring_dom_rel, &rel);
- if (exc != DOM_NO_ERR || rel == NULL)
- return true;
-
- if (strcasestr(dom_string_data(rel), "stylesheet") == 0) {
- dom_string_unref(rel);
- return true;
- } else if (strcasestr(dom_string_data(rel), "alternate") != 0) {
- /* Ignore alternate stylesheets */
- dom_string_unref(rel);
- return true;
- }
- dom_string_unref(rel);
-
- /* type='text/css' or not present */
- exc = dom_element_get_attribute(node, corestring_dom_type, &type_attr);
- if (exc == DOM_NO_ERR && type_attr != NULL) {
- if (!dom_string_caseless_lwc_isequal(type_attr,
- corestring_lwc_text_css)) {
- dom_string_unref(type_attr);
- return true;
- }
- dom_string_unref(type_attr);
- }
-
- /* media contains 'screen' or 'all' or not present */
- exc = dom_element_get_attribute(node, corestring_dom_media, &media);
- if (exc == DOM_NO_ERR && media != NULL) {
- if (strcasestr(dom_string_data(media), "screen") == NULL &&
- strcasestr(dom_string_data(media), "all") == NULL) {
- dom_string_unref(media);
- return true;
- }
- dom_string_unref(media);
- }
-
- /* href='...' */
- exc = dom_element_get_attribute(node, corestring_dom_href, &href);
- if (exc != DOM_NO_ERR || href == NULL)
- return true;
-
- /* TODO: only the first preferred stylesheets (ie.
- * those with a title attribute) should be loaded
- * (see HTML4 14.3) */
-
- ns_error = nsurl_join(htmlc->base_url, dom_string_data(href), &joined);
- if (ns_error != NSERROR_OK) {
- dom_string_unref(href);
- goto no_memory;
- }
- dom_string_unref(href);
-
- NSLOG(netsurf, INFO, "linked stylesheet %i '%s'",
- htmlc->stylesheet_count, nsurl_access(joined));
-
- /* extend stylesheets array to allow for new sheet */
- stylesheets = realloc(htmlc->stylesheets,
- sizeof(struct html_stylesheet) *
- (htmlc->stylesheet_count + 1));
- if (stylesheets == NULL) {
- nsurl_unref(joined);
- ns_error = NSERROR_NOMEM;
- goto no_memory;
- }
-
- htmlc->stylesheets = stylesheets;
- htmlc->stylesheets[htmlc->stylesheet_count].node = NULL;
- htmlc->stylesheets[htmlc->stylesheet_count].modified = false;
- htmlc->stylesheets[htmlc->stylesheet_count].unused = false;
-
- /* start fetch */
- child.charset = htmlc->encoding;
- child.quirks = htmlc->base.quirks;
-
- ns_error = hlcache_handle_retrieve(joined, 0,
- content_get_url(&htmlc->base),
- NULL, html_convert_css_callback,
- htmlc, &child, CONTENT_CSS,
- &htmlc->stylesheets[htmlc->stylesheet_count].sheet);
-
- nsurl_unref(joined);
-
- if (ns_error != NSERROR_OK)
- goto no_memory;
-
- htmlc->stylesheet_count++;
-
- htmlc->base.active++;
- NSLOG(netsurf, INFO, "%d fetches active", htmlc->base.active);
-
- return true;
-
-no_memory:
- content_broadcast_errorcode(&htmlc->base, ns_error);
- return false;
-}
-
-/* exported interface documented in render/html.h */
-struct html_stylesheet *html_get_stylesheets(hlcache_handle *h, unsigned int *n)
-{
- html_content *c = (html_content *) hlcache_handle_get_content(h);
-
- assert(c != NULL);
- assert(n != NULL);
-
- *n = c->stylesheet_count;
-
- return c->stylesheets;
-}
-
-
-/* exported interface documented in render/html_internal.h */
-nserror html_css_free_stylesheets(html_content *html)
-{
- unsigned int i;
-
- guit->misc->schedule(-1, html_css_process_modified_styles, html);
-
- for (i = 0; i != html->stylesheet_count; i++) {
- if (html->stylesheets[i].sheet != NULL) {
- hlcache_handle_release(html->stylesheets[i].sheet);
- }
- if (html->stylesheets[i].node != NULL) {
- dom_node_unref(html->stylesheets[i].node);
- }
- }
- free(html->stylesheets);
-
- return NSERROR_OK;
-}
-
-/* exported interface documented in render/html_internal.h */
-nserror html_css_quirks_stylesheets(html_content *c)
-{
- nserror ns_error = NSERROR_OK;
- hlcache_child_context child;
-
- assert(c->stylesheets != NULL);
-
- if (c->quirks == DOM_DOCUMENT_QUIRKS_MODE_FULL) {
- child.charset = c->encoding;
- child.quirks = c->base.quirks;
-
- ns_error = hlcache_handle_retrieve(html_quirks_stylesheet_url,
- 0, content_get_url(&c->base), NULL,
- html_convert_css_callback, c, &child,
- CONTENT_CSS,
- &c->stylesheets[STYLESHEET_QUIRKS].sheet);
- if (ns_error != NSERROR_OK) {
- return ns_error;
- }
-
- c->base.active++;
- NSLOG(netsurf, INFO, "%d fetches active", c->base.active);
- }
-
- return ns_error;
-}
-
-/* exported interface documented in render/html_internal.h */
-nserror html_css_new_stylesheets(html_content *c)
-{
- nserror ns_error;
- hlcache_child_context child;
-
- if (c->stylesheets != NULL) {
- return NSERROR_OK; /* already initialised */
- }
-
- /* stylesheet 0 is the base style sheet,
- * stylesheet 1 is the quirks mode style sheet,
- * stylesheet 2 is the adblocking stylesheet,
- * stylesheet 3 is the user stylesheet */
- c->stylesheets = calloc(STYLESHEET_START,
- sizeof(struct html_stylesheet));
- if (c->stylesheets == NULL) {
- return NSERROR_NOMEM;
- }
-
- c->stylesheets[STYLESHEET_BASE].sheet = NULL;
- c->stylesheets[STYLESHEET_QUIRKS].sheet = NULL;
- c->stylesheets[STYLESHEET_ADBLOCK].sheet = NULL;
- c->stylesheets[STYLESHEET_USER].sheet = NULL;
- c->stylesheet_count = STYLESHEET_START;
-
- child.charset = c->encoding;
- child.quirks = c->base.quirks;
-
- ns_error = hlcache_handle_retrieve(html_default_stylesheet_url, 0,
- content_get_url(&c->base), NULL,
- html_convert_css_callback, c, &child, CONTENT_CSS,
- &c->stylesheets[STYLESHEET_BASE].sheet);
- if (ns_error != NSERROR_OK) {
- return ns_error;
- }
-
- c->base.active++;
- NSLOG(netsurf, INFO, "%d fetches active", c->base.active);
-
-
- if (nsoption_bool(block_advertisements)) {
- ns_error = hlcache_handle_retrieve(html_adblock_stylesheet_url,
- 0, content_get_url(&c->base), NULL,
- html_convert_css_callback,
- c, &child, CONTENT_CSS,
- &c->stylesheets[STYLESHEET_ADBLOCK].sheet);
- if (ns_error != NSERROR_OK) {
- return ns_error;
- }
-
- c->base.active++;
- NSLOG(netsurf, INFO, "%d fetches active", c->base.active);
-
- }
-
- ns_error = hlcache_handle_retrieve(html_user_stylesheet_url, 0,
- content_get_url(&c->base), NULL,
- html_convert_css_callback, c, &child, CONTENT_CSS,
- &c->stylesheets[STYLESHEET_USER].sheet);
- if (ns_error != NSERROR_OK) {
- return ns_error;
- }
-
- c->base.active++;
- NSLOG(netsurf, INFO, "%d fetches active", c->base.active);
-
- return ns_error;
-}
-
-nserror
-html_css_new_selection_context(html_content *c, css_select_ctx **ret_select_ctx)
-{
- uint32_t i;
- css_error css_ret;
- css_select_ctx *select_ctx;
-
- /* check that the base stylesheet loaded; layout fails without it */
- if (c->stylesheets[STYLESHEET_BASE].sheet == NULL) {
- return NSERROR_CSS_BASE;
- }
-
- /* Create selection context */
- css_ret = css_select_ctx_create(&select_ctx);
- if (css_ret != CSS_OK) {
- return css_error_to_nserror(css_ret);
- }
-
- /* Add sheets to it */
- for (i = STYLESHEET_BASE; i != c->stylesheet_count; i++) {
- const struct html_stylesheet *hsheet = &c->stylesheets[i];
- css_stylesheet *sheet = NULL;
- css_origin origin = CSS_ORIGIN_AUTHOR;
-
- /* Filter out stylesheets for non-screen media. */
- if (hsheet->unused) {
- continue;
- }
-
- if (i < STYLESHEET_USER) {
- origin = CSS_ORIGIN_UA;
- } else if (i < STYLESHEET_START) {
- origin = CSS_ORIGIN_USER;
- }
-
- if (hsheet->sheet != NULL) {
- sheet = nscss_get_stylesheet(hsheet->sheet);
- }
-
- if (sheet != NULL) {
- css_ret = css_select_ctx_append_sheet(select_ctx,
- sheet,
- origin,
- CSS_MEDIA_SCREEN);
- if (css_ret != CSS_OK) {
- css_select_ctx_destroy(select_ctx);
- return css_error_to_nserror(css_ret);
- }
- }
- }
-
- /* return new selection context to caller */
- *ret_select_ctx = select_ctx;
- return NSERROR_OK;
-}
-
-nserror html_css_init(void)
-{
- nserror error;
-
- error = html_css_fetcher_register();
- if (error != NSERROR_OK)
- return error;
-
- error = nsurl_create("resource:default.css",
- &html_default_stylesheet_url);
- if (error != NSERROR_OK)
- return error;
-
- error = nsurl_create("resource:adblock.css",
- &html_adblock_stylesheet_url);
- if (error != NSERROR_OK)
- return error;
-
- error = nsurl_create("resource:quirks.css",
- &html_quirks_stylesheet_url);
- if (error != NSERROR_OK)
- return error;
-
- error = nsurl_create("resource:user.css",
- &html_user_stylesheet_url);
-
- return error;
-}
-
-void html_css_fini(void)
-{
- if (html_user_stylesheet_url != NULL) {
- nsurl_unref(html_user_stylesheet_url);
- html_user_stylesheet_url = NULL;
- }
-
- if (html_quirks_stylesheet_url != NULL) {
- nsurl_unref(html_quirks_stylesheet_url);
- html_quirks_stylesheet_url = NULL;
- }
-
- if (html_adblock_stylesheet_url != NULL) {
- nsurl_unref(html_adblock_stylesheet_url);
- html_adblock_stylesheet_url = NULL;
- }
-
- if (html_default_stylesheet_url != NULL) {
- nsurl_unref(html_default_stylesheet_url);
- html_default_stylesheet_url = NULL;
- }
-}
diff --git a/render/html_css_fetcher.c b/render/html_css_fetcher.c
deleted file mode 100644
index 0f8809a42..000000000
--- a/render/html_css_fetcher.c
+++ /dev/null
@@ -1,321 +0,0 @@
-/*
- * Copyright 2008 Rob Kendrick <rjek@netsurf-browser.org>
- * Copyright 2013 John-Mark Bell <jmb@netsurf-browser.org>
- *
- * This file is part of NetSurf.
- *
- * NetSurf is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * NetSurf is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include <assert.h>
-#include <stdbool.h>
-#include <stdlib.h>
-#include <string.h>
-#include <dom/dom.h>
-#include <libwapcaplet/libwapcaplet.h>
-
-#include "netsurf/inttypes.h"
-#include "utils/config.h"
-#include "utils/log.h"
-#include "utils/ring.h"
-#include "utils/nsurl.h"
-#include "utils/utils.h"
-#include "content/fetch.h"
-#include "content/fetchers.h"
-
-#include "render/html_internal.h"
-
-typedef struct html_css_fetcher_item {
- uint32_t key;
- dom_string *data;
- nsurl *base_url;
-
- struct html_css_fetcher_item *r_next, *r_prev;
-} html_css_fetcher_item;
-
-typedef struct html_css_fetcher_context {
- struct fetch *parent_fetch;
-
- nsurl *url;
- html_css_fetcher_item *item;
-
- bool aborted;
- bool locked;
-
- struct html_css_fetcher_context *r_next, *r_prev;
-} html_css_fetcher_context;
-
-static uint32_t current_key = 0;
-static html_css_fetcher_item *items = NULL;
-static html_css_fetcher_context *ring = NULL;
-
-static bool html_css_fetcher_initialise(lwc_string *scheme)
-{
- NSLOG(netsurf, INFO, "html_css_fetcher_initialise called for %s",
- lwc_string_data(scheme));
- return true;
-}
-
-static void html_css_fetcher_finalise(lwc_string *scheme)
-{
- NSLOG(netsurf, INFO, "html_css_fetcher_finalise called for %s",
- lwc_string_data(scheme));
-}
-
-static bool html_css_fetcher_can_fetch(const nsurl *url)
-{
- return true;
-}
-
-static void *html_css_fetcher_setup(struct fetch *parent_fetch, nsurl *url,
- bool only_2xx, bool downgrade_tls, const char *post_urlenc,
- const struct fetch_multipart_data *post_multipart,
- const char **headers)
-{
- html_css_fetcher_context *ctx;
- lwc_string *path;
- uint32_t key;
- html_css_fetcher_item *item, *found = NULL;
-
- /* format of a x-ns-css URL is:
- * x-ns-url:<key>
- * Where key is an unsigned 32bit integer
- */
-
- path = nsurl_get_component(url, NSURL_PATH);
- /* The path must exist */
- if (path == NULL) {
- return NULL;
- }
-
- key = strtoul(lwc_string_data(path), NULL, 10);
-
- lwc_string_unref(path);
-
- /* There must be at least one item */
- if (items == NULL) {
- return NULL;
- }
-
- item = items;
- do {
- if (item->key == key) {
- found = item;
- break;
- }
-
- item = item->r_next;
- } while (item != items);
-
- /* We must have found the item */
- if (found == NULL) {
- return NULL;
- }
-
- ctx = calloc(1, sizeof(*ctx));
- if (ctx == NULL)
- return NULL;
-
- ctx->parent_fetch = parent_fetch;
- ctx->url = nsurl_ref(url);
- ctx->item = found;
-
- RING_INSERT(ring, ctx);
-
- return ctx;
-}
-
-static bool html_css_fetcher_start(void *ctx)
-{
- return true;
-}
-
-static void html_css_fetcher_free(void *ctx)
-{
- html_css_fetcher_context *c = ctx;
-
- nsurl_unref(c->url);
- if (c->item != NULL) {
- nsurl_unref(c->item->base_url);
- dom_string_unref(c->item->data);
- RING_REMOVE(items, c->item);
- free(c->item);
- }
- RING_REMOVE(ring, c);
- free(ctx);
-}
-
-static void html_css_fetcher_abort(void *ctx)
-{
- html_css_fetcher_context *c = ctx;
-
- /* To avoid the poll loop having to deal with the fetch context
- * disappearing from under it, we simply flag the abort here.
- * The poll loop itself will perform the appropriate cleanup.
- */
- c->aborted = true;
-}
-
-static void html_css_fetcher_send_callback(const fetch_msg *msg,
- html_css_fetcher_context *c)
-{
- c->locked = true;
- fetch_send_callback(msg, c->parent_fetch);
- c->locked = false;
-}
-
-static void html_css_fetcher_poll(lwc_string *scheme)
-{
- fetch_msg msg;
- html_css_fetcher_context *c, *next;
-
- if (ring == NULL) return;
-
- /* Iterate over ring, processing each pending fetch */
- c = ring;
- do {
- /* Ignore fetches that have been flagged as locked.
- * This allows safe re-entrant calls to this function.
- * Re-entrancy can occur if, as a result of a callback,
- * the interested party causes fetch_poll() to be called
- * again.
- */
- if (c->locked == true) {
- next = c->r_next;
- continue;
- }
-
- /* Only process non-aborted fetches */
- if (c->aborted) {
- /* Nothing to do */
- assert(c->locked == false);
- } else if (c->item != NULL) {
- char header[4096];
-
- fetch_set_http_code(c->parent_fetch, 200);
-
- /* Any callback can result in the fetch being aborted.
- * Therefore, we _must_ check for this after _every_
- * call to html_css_fetcher_send_callback().
- */
- snprintf(header, sizeof header,
- "Content-Type: text/css; charset=utf-8");
- msg.type = FETCH_HEADER;
- msg.data.header_or_data.buf = (const uint8_t *) header;
- msg.data.header_or_data.len = strlen(header);
- html_css_fetcher_send_callback(&msg, c);
-
- if (c->aborted == false) {
- snprintf(header, sizeof header,
- "Content-Length: %"PRIsizet,
- dom_string_byte_length(c->item->data));
- msg.type = FETCH_HEADER;
- msg.data.header_or_data.buf =
- (const uint8_t *) header;
- msg.data.header_or_data.len = strlen(header);
- html_css_fetcher_send_callback(&msg, c);
- }
-
- if (c->aborted == false) {
- snprintf(header, sizeof header,
- "X-NS-Base: %.*s",
- (int) nsurl_length(c->item->base_url),
- nsurl_access(c->item->base_url));
- msg.type = FETCH_HEADER;
- msg.data.header_or_data.buf =
- (const uint8_t *) header;
- msg.data.header_or_data.len = strlen(header);
- html_css_fetcher_send_callback(&msg, c);
- }
-
- if (c->aborted == false) {
- msg.type = FETCH_DATA;
- msg.data.header_or_data.buf =
- (const uint8_t *)
- dom_string_data(c->item->data);
- msg.data.header_or_data.len =
- dom_string_byte_length(c->item->data);
- html_css_fetcher_send_callback(&msg, c);
- }
-
- if (c->aborted == false) {
- msg.type = FETCH_FINISHED;
- html_css_fetcher_send_callback(&msg, c);
- }
- } else {
- NSLOG(netsurf, INFO, "Processing of %s failed!",
- nsurl_access(c->url));
-
- /* Ensure that we're unlocked here. If we aren't,
- * then html_css_fetcher_process() is broken.
- */
- assert(c->locked == false);
- }
-
- /* Compute next fetch item at the last possible moment as
- * processing this item may have added to the ring.
- */
- next = c->r_next;
-
- fetch_remove_from_queues(c->parent_fetch);
- fetch_free(c->parent_fetch);
-
- /* Advance to next ring entry, exiting if we've reached
- * the start of the ring or the ring has become empty
- */
- } while ( (c = next) != ring && ring != NULL);
-}
-
-/* exported interface documented in html_internal.h */
-nserror html_css_fetcher_register(void)
-{
- lwc_string *scheme;
- const struct fetcher_operation_table html_css_fetcher_ops = {
- .initialise = html_css_fetcher_initialise,
- .acceptable = html_css_fetcher_can_fetch,
- .setup = html_css_fetcher_setup,
- .start = html_css_fetcher_start,
- .abort = html_css_fetcher_abort,
- .free = html_css_fetcher_free,
- .poll = html_css_fetcher_poll,
- .finalise = html_css_fetcher_finalise
- };
-
- if (lwc_intern_string("x-ns-css", SLEN("x-ns-css"),
- &scheme) != lwc_error_ok) {
- NSLOG(netsurf, INFO, "could not intern \"x-ns-css\".");
- return NSERROR_INIT_FAILED;
- }
-
- return fetcher_add(scheme, &html_css_fetcher_ops);
-}
-
-/* exported interface documented in html_internal.h */
-nserror
-html_css_fetcher_add_item(dom_string *data, nsurl *base_url, uint32_t *key)
-{
- html_css_fetcher_item *item = malloc(sizeof(*item));
-
- if (item == NULL) {
- return NSERROR_NOMEM;
- }
-
- *key = item->key = current_key++;
- item->data = dom_string_ref(data);
- item->base_url = nsurl_ref(base_url);
-
- RING_INSERT(items, item);
-
- return NSERROR_OK;
-}
-
diff --git a/render/html_forms.c b/render/html_forms.c
deleted file mode 100644
index 39bc690d9..000000000
--- a/render/html_forms.c
+++ /dev/null
@@ -1,575 +0,0 @@
-/*
- * Copyright 2011 Vincent Sanders <vince@netsurf-browser.org>
- *
- * This file is part of NetSurf, http://www.netsurf-browser.org/
- *
- * NetSurf is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * NetSurf is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "utils/config.h"
-#include "utils/corestrings.h"
-#include "utils/log.h"
-
-#include "render/form_internal.h"
-#include "render/html_internal.h"
-
-/**
- * process form element from dom
- */
-static struct form *
-parse_form_element(const char *docenc, dom_node *node)
-{
- dom_string *ds_action = NULL;
- dom_string *ds_charset = NULL;
- dom_string *ds_target = NULL;
- dom_string *ds_method = NULL;
- dom_string *ds_enctype = NULL;
- char *action = NULL, *charset = NULL, *target = NULL;
- form_method method;
- dom_html_form_element *formele = (dom_html_form_element *)(node);
- struct form * ret = NULL;
-
- /* Retrieve the attributes from the node */
- if (dom_html_form_element_get_action(formele,
- &ds_action) != DOM_NO_ERR)
- goto out;
-
- if (dom_html_form_element_get_accept_charset(formele,
- &ds_charset) != DOM_NO_ERR)
- goto out;
-
- if (dom_html_form_element_get_target(formele,
- &ds_target) != DOM_NO_ERR)
- goto out;
-
- if (dom_html_form_element_get_method(formele,
- &ds_method) != DOM_NO_ERR)
- goto out;
-
- if (dom_html_form_element_get_enctype(formele,
- &ds_enctype) != DOM_NO_ERR)
- goto out;
-
- /* Extract the plain attributes ready for use. We have to do this
- * because we cannot guarantee that the dom_strings are NULL terminated
- * and thus we copy them.
- */
- if (ds_action != NULL)
- action = strndup(dom_string_data(ds_action),
- dom_string_byte_length(ds_action));
-
- if (ds_charset != NULL)
- charset = strndup(dom_string_data(ds_charset),
- dom_string_byte_length(ds_charset));
-
- if (ds_target != NULL)
- target = strndup(dom_string_data(ds_target),
- dom_string_byte_length(ds_target));
-
- /* Determine the method */
- method = method_GET;
- if (ds_method != NULL) {
- if (dom_string_caseless_lwc_isequal(ds_method,
- corestring_lwc_post)) {
- method = method_POST_URLENC;
- if (ds_enctype != NULL) {
- if (dom_string_caseless_lwc_isequal(ds_enctype,
- corestring_lwc_multipart_form_data)) {
-
- method = method_POST_MULTIPART;
- }
- }
- }
- }
-
- /* Construct the form object */
- ret = form_new(node, action, target, method, charset, docenc);
-
-out:
- if (ds_action != NULL)
- dom_string_unref(ds_action);
- if (ds_charset != NULL)
- dom_string_unref(ds_charset);
- if (ds_target != NULL)
- dom_string_unref(ds_target);
- if (ds_method != NULL)
- dom_string_unref(ds_method);
- if (ds_enctype != NULL)
- dom_string_unref(ds_enctype);
- if (action != NULL)
- free(action);
- if (charset != NULL)
- free(charset);
- if (target != NULL)
- free(target);
- return ret;
-}
-
-/* documented in html_internal.h */
-struct form *html_forms_get_forms(const char *docenc, dom_html_document *doc)
-{
- dom_html_collection *forms;
- struct form *ret = NULL, *newf;
- dom_node *node;
- unsigned long n;
- uint32_t nforms;
-
- if (doc == NULL)
- return NULL;
-
- /* Attempt to build a set of all the forms */
- if (dom_html_document_get_forms(doc, &forms) != DOM_NO_ERR)
- return NULL;
-
- /* Count the number of forms so we can iterate */
- if (dom_html_collection_get_length(forms, &nforms) != DOM_NO_ERR)
- goto out;
-
- /* Iterate the forms collection, making form structs for returning */
- for (n = 0; n < nforms; ++n) {
- if (dom_html_collection_item(forms, n, &node) != DOM_NO_ERR) {
- goto out;
- }
- newf = parse_form_element(docenc, node);
- dom_node_unref(node);
- if (newf == NULL) {
- goto err;
- }
- newf->prev = ret;
- ret = newf;
- }
-
- /* All went well */
- goto out;
-err:
- while (ret != NULL) {
- struct form *prev = ret->prev;
- /* Destroy ret */
- free(ret);
- ret = prev;
- }
-out:
- /* Finished with the collection, return it */
- dom_html_collection_unref(forms);
-
- return ret;
-}
-
-static struct form *
-find_form(struct form *forms, dom_html_form_element *form)
-{
- while (forms != NULL) {
- if (forms->node == form)
- break;
- forms = forms->prev;
- }
-
- return forms;
-}
-
-static struct form_control *
-parse_button_element(struct form *forms, dom_html_button_element *button)
-{
- struct form_control *control = NULL;
- dom_exception err;
- dom_html_form_element *form = NULL;
- dom_string *ds_type = NULL;
- dom_string *ds_value = NULL;
- dom_string *ds_name = NULL;
-
- err = dom_html_button_element_get_form(button, &form);
- if (err != DOM_NO_ERR)
- goto out;
-
- err = dom_html_button_element_get_type(button, &ds_type);
- if (err != DOM_NO_ERR)
- goto out;
-
- if (ds_type == NULL) {
- control = form_new_control(button, GADGET_SUBMIT);
- } else {
- if (dom_string_caseless_lwc_isequal(ds_type,
- corestring_lwc_submit)) {
- control = form_new_control(button, GADGET_SUBMIT);
- } else if (dom_string_caseless_lwc_isequal(ds_type,
- corestring_lwc_reset)) {
- control = form_new_control(button, GADGET_RESET);
- } else {
- control = form_new_control(button, GADGET_BUTTON);
- }
- }
-
- if (control == NULL)
- goto out;
-
- err = dom_html_button_element_get_value(button, &ds_value);
- if (err != DOM_NO_ERR)
- goto out;
- err = dom_html_button_element_get_name(button, &ds_name);
- if (err != DOM_NO_ERR)
- goto out;
-
- if (ds_value != NULL) {
- control->value = strndup(
- dom_string_data(ds_value),
- dom_string_byte_length(ds_value));
-
- if (control->value == NULL) {
- form_free_control(control);
- control = NULL;
- goto out;
- }
- }
-
- if (ds_name != NULL) {
- control->name = strndup(
- dom_string_data(ds_name),
- dom_string_byte_length(ds_name));
-
- if (control->name == NULL) {
- form_free_control(control);
- control = NULL;
- goto out;
- }
- }
-
- if (form != NULL && control != NULL)
- form_add_control(find_form(forms, form), control);
-
-out:
- if (form != NULL)
- dom_node_unref(form);
- if (ds_type != NULL)
- dom_string_unref(ds_type);
- if (ds_value != NULL)
- dom_string_unref(ds_value);
- if (ds_name != NULL)
- dom_string_unref(ds_name);
-
- return control;
-}
-
-static struct form_control *
-parse_input_element(struct form *forms, dom_html_input_element *input)
-{
- struct form_control *control = NULL;
- dom_html_form_element *form = NULL;
- dom_string *ds_type = NULL;
- dom_string *ds_name = NULL;
- dom_string *ds_value = NULL;
-
- char *name = NULL;
-
- if (dom_html_input_element_get_form(input, &form) != DOM_NO_ERR)
- goto out;
-
- if (dom_html_input_element_get_type(input, &ds_type) != DOM_NO_ERR)
- goto out;
-
- if (dom_html_input_element_get_name(input, &ds_name) != DOM_NO_ERR)
- goto out;
-
- if (ds_name != NULL)
- name = strndup(dom_string_data(ds_name),
- dom_string_byte_length(ds_name));
-
- if (ds_type != NULL && dom_string_caseless_lwc_isequal(ds_type,
- corestring_lwc_password)) {
- control = form_new_control(input, GADGET_PASSWORD);
- } else if (ds_type != NULL && dom_string_caseless_lwc_isequal(ds_type,
- corestring_lwc_file)) {
- control = form_new_control(input, GADGET_FILE);
- } else if (ds_type != NULL && dom_string_caseless_lwc_isequal(ds_type,
- corestring_lwc_hidden)) {
- control = form_new_control(input, GADGET_HIDDEN);
- } else if (ds_type != NULL && dom_string_caseless_lwc_isequal(ds_type,
- corestring_lwc_checkbox)) {
- control = form_new_control(input, GADGET_CHECKBOX);
- } else if (ds_type != NULL && dom_string_caseless_lwc_isequal(ds_type,
- corestring_lwc_radio)) {
- control = form_new_control(input, GADGET_RADIO);
- } else if (ds_type != NULL && dom_string_caseless_lwc_isequal(ds_type,
- corestring_lwc_submit)) {
- control = form_new_control(input, GADGET_SUBMIT);
- } else if (ds_type != NULL && dom_string_caseless_lwc_isequal(ds_type,
- corestring_lwc_reset)) {
- control = form_new_control(input, GADGET_RESET);
- } else if (ds_type != NULL && dom_string_caseless_lwc_isequal(ds_type,
- corestring_lwc_button)) {
- control = form_new_control(input, GADGET_BUTTON);
- } else if (ds_type != NULL && dom_string_caseless_lwc_isequal(ds_type,
- corestring_lwc_image)) {
- control = form_new_control(input, GADGET_IMAGE);
- } else {
- control = form_new_control(input, GADGET_TEXTBOX);
- }
-
- if (control == NULL)
- goto out;
-
- if (name != NULL) {
- /* Hand the name string over */
- control->name = name;
- name = NULL;
- }
-
- if (control->type == GADGET_CHECKBOX || control->type == GADGET_RADIO) {
- bool selected;
- if (dom_html_input_element_get_checked(
- input, &selected) == DOM_NO_ERR) {
- control->selected = selected;
- }
- }
-
- if (control->type == GADGET_PASSWORD ||
- control->type == GADGET_TEXTBOX) {
- int32_t maxlength;
- if (dom_html_input_element_get_max_length(
- input, &maxlength) != DOM_NO_ERR) {
- maxlength = -1;
- }
-
- if (maxlength >= 0) {
- /* Got valid maxlength */
- control->maxlength = maxlength;
- } else {
- /* Input has no maxlength attr, or
- * dom_html_input_element_get_max_length failed.
- *
- * Set it to something insane. */
- control->maxlength = UINT_MAX;
- }
- }
-
- if (control->type != GADGET_FILE && control->type != GADGET_IMAGE) {
- if (dom_html_input_element_get_value(
- input, &ds_value) == DOM_NO_ERR) {
- if (ds_value != NULL) {
- control->value = strndup(
- dom_string_data(ds_value),
- dom_string_byte_length(ds_value));
- if (control->value == NULL) {
- form_free_control(control);
- control = NULL;
- goto out;
- }
- control->length = strlen(control->value);
- }
- }
-
- if (control->type == GADGET_TEXTBOX ||
- control->type == GADGET_PASSWORD) {
- if (control->value == NULL) {
- control->value = strdup("");
- if (control->value == NULL) {
- form_free_control(control);
- control = NULL;
- goto out;
- }
-
- control->length = 0;
- }
-
- control->initial_value = strdup(control->value);
- if (control->initial_value == NULL) {
- form_free_control(control);
- control = NULL;
- goto out;
- }
- }
- }
-
- if (form != NULL && control != NULL)
- form_add_control(find_form(forms, form), control);
-
-out:
- if (form != NULL)
- dom_node_unref(form);
- if (ds_type != NULL)
- dom_string_unref(ds_type);
- if (ds_name != NULL)
- dom_string_unref(ds_name);
- if (ds_value != NULL)
- dom_string_unref(ds_value);
-
- if (name != NULL)
- free(name);
-
- return control;
-}
-
-static struct form_control *
-parse_textarea_element(struct form *forms, dom_html_text_area_element *ta)
-{
- struct form_control *control = NULL;
- dom_html_form_element *form = NULL;
- dom_string *ds_name = NULL;
-
- char *name = NULL;
-
- if (dom_html_text_area_element_get_form(ta, &form) != DOM_NO_ERR)
- goto out;
-
- if (dom_html_text_area_element_get_name(ta, &ds_name) != DOM_NO_ERR)
- goto out;
-
- if (ds_name != NULL)
- name = strndup(dom_string_data(ds_name),
- dom_string_byte_length(ds_name));
-
- control = form_new_control(ta, GADGET_TEXTAREA);
-
- if (control == NULL)
- goto out;
-
- if (name != NULL) {
- /* Hand the name string over */
- control->name = name;
- name = NULL;
- }
-
- if (form != NULL && control != NULL)
- form_add_control(find_form(forms, form), control);
-
-out:
- if (form != NULL)
- dom_node_unref(form);
- if (ds_name != NULL)
- dom_string_unref(ds_name);
-
- if (name != NULL)
- free(name);
-
-
- return control;
-}
-
-static struct form_control *
-parse_select_element(struct form *forms, dom_html_select_element *select)
-{
- struct form_control *control = NULL;
- dom_html_form_element *form = NULL;
- dom_string *ds_name = NULL;
-
- char *name = NULL;
-
- if (dom_html_select_element_get_form(select, &form) != DOM_NO_ERR)
- goto out;
-
- if (dom_html_select_element_get_name(select, &ds_name) != DOM_NO_ERR)
- goto out;
-
- if (ds_name != NULL)
- name = strndup(dom_string_data(ds_name),
- dom_string_byte_length(ds_name));
-
- control = form_new_control(select, GADGET_SELECT);
-
- if (control == NULL)
- goto out;
-
- if (name != NULL) {
- /* Hand the name string over */
- control->name = name;
- name = NULL;
- }
-
- dom_html_select_element_get_multiple(select,
- &(control->data.select.multiple));
-
- if (form != NULL && control != NULL)
- form_add_control(find_form(forms, form), control);
-
-out:
- if (form != NULL)
- dom_node_unref(form);
- if (ds_name != NULL)
- dom_string_unref(ds_name);
-
- if (name != NULL)
- free(name);
-
-
- return control;
-}
-
-
-static struct form_control *
-invent_fake_gadget(dom_node *node)
-{
- struct form_control *ctl = form_new_control(node, GADGET_HIDDEN);
- if (ctl != NULL) {
- ctl->value = strdup("");
- ctl->initial_value = strdup("");
- ctl->name = strdup("foo");
-
- if (ctl->value == NULL || ctl->initial_value == NULL ||
- ctl->name == NULL) {
- form_free_control(ctl);
- ctl = NULL;
- }
- }
- return ctl;
-}
-
-/* documented in html_internal.h */
-struct form_control *html_forms_get_control_for_node(struct form *forms,
- dom_node *node)
-{
- struct form *f;
- struct form_control *ctl = NULL;
- dom_exception err;
- dom_string *ds_name = NULL;
-
- /* Step one, see if we already have a control */
- for (f = forms; f != NULL; f = f->prev) {
- for (ctl = f->controls; ctl != NULL; ctl = ctl->next) {
- if (ctl->node == node)
- return ctl;
- }
- }
-
- /* Step two, extract the node's name so we can construct a gadget. */
- err = dom_element_get_tag_name(node, &ds_name);
- if (err == DOM_NO_ERR && ds_name != NULL) {
-
- /* Step three, attempt to work out what gadget to make */
- if (dom_string_caseless_lwc_isequal(ds_name,
- corestring_lwc_button)) {
- ctl = parse_button_element(forms,
- (dom_html_button_element *) node);
- } else if (dom_string_caseless_lwc_isequal(ds_name,
- corestring_lwc_input)) {
- ctl = parse_input_element(forms,
- (dom_html_input_element *) node);
- } else if (dom_string_caseless_lwc_isequal(ds_name,
- corestring_lwc_textarea)) {
- ctl = parse_textarea_element(forms,
- (dom_html_text_area_element *) node);
- } else if (dom_string_caseless_lwc_isequal(ds_name,
- corestring_lwc_select)) {
- ctl = parse_select_element(forms,
- (dom_html_select_element *) node);
- }
- }
-
- /* If all else fails, fake gadget time */
- if (ctl == NULL)
- ctl = invent_fake_gadget(node);
-
- if (ds_name != NULL)
- dom_string_unref(ds_name);
-
- return ctl;
-}
-
diff --git a/render/html_interaction.c b/render/html_interaction.c
deleted file mode 100644
index 2d14ed2ae..000000000
--- a/render/html_interaction.c
+++ /dev/null
@@ -1,1434 +0,0 @@
-/*
- * Copyright 2006 James Bursa <bursa@users.sourceforge.net>
- * Copyright 2006 Richard Wilson <info@tinct.net>
- * Copyright 2008 Michael Drake <tlsa@netsurf-browser.org>
- * Copyright 2009 Paul Blokus <paul_pl@users.sourceforge.net>
- *
- * This file is part of NetSurf, http://www.netsurf-browser.org/
- *
- * NetSurf is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * NetSurf is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-/**
- * \file
- * User interaction with a CONTENT_HTML (implementation).
- */
-
-#include <assert.h>
-#include <stdbool.h>
-
-#include <dom/dom.h>
-
-#include "utils/corestrings.h"
-#include "utils/messages.h"
-#include "utils/utils.h"
-#include "utils/log.h"
-#include "utils/nsoption.h"
-#include "netsurf/content.h"
-#include "netsurf/browser_window.h"
-#include "netsurf/mouse.h"
-#include "netsurf/misc.h"
-#include "netsurf/layout.h"
-#include "netsurf/keypress.h"
-#include "content/hlcache.h"
-#include "desktop/frames.h"
-#include "desktop/scrollbar.h"
-#include "desktop/selection.h"
-#include "desktop/textarea.h"
-#include "javascript/js.h"
-#include "desktop/gui_internal.h"
-
-#include "render/box.h"
-#include "render/box_textarea.h"
-#include "render/font.h"
-#include "render/form_internal.h"
-#include "render/html_internal.h"
-#include "render/imagemap.h"
-#include "render/search.h"
-
-/**
- * Get pointer shape for given box
- *
- * \param box box in question
- * \param imagemap whether an imagemap applies to the box
- */
-
-static browser_pointer_shape get_pointer_shape(struct box *box, bool imagemap)
-{
- browser_pointer_shape pointer;
- css_computed_style *style;
- enum css_cursor_e cursor;
- lwc_string **cursor_uris;
-
- if (box->type == BOX_FLOAT_LEFT || box->type == BOX_FLOAT_RIGHT)
- style = box->children->style;
- else
- style = box->style;
-
- if (style == NULL)
- return BROWSER_POINTER_DEFAULT;
-
- cursor = css_computed_cursor(style, &cursor_uris);
-
- switch (cursor) {
- case CSS_CURSOR_AUTO:
- if (box->href || (box->gadget &&
- (box->gadget->type == GADGET_IMAGE ||
- box->gadget->type == GADGET_SUBMIT)) ||
- imagemap) {
- /* link */
- pointer = BROWSER_POINTER_POINT;
- } else if (box->gadget &&
- (box->gadget->type == GADGET_TEXTBOX ||
- box->gadget->type == GADGET_PASSWORD ||
- box->gadget->type == GADGET_TEXTAREA)) {
- /* text input */
- pointer = BROWSER_POINTER_CARET;
- } else {
- /* html content doesn't mind */
- pointer = BROWSER_POINTER_AUTO;
- }
- break;
- case CSS_CURSOR_CROSSHAIR:
- pointer = BROWSER_POINTER_CROSS;
- break;
- case CSS_CURSOR_POINTER:
- pointer = BROWSER_POINTER_POINT;
- break;
- case CSS_CURSOR_MOVE:
- pointer = BROWSER_POINTER_MOVE;
- break;
- case CSS_CURSOR_E_RESIZE:
- pointer = BROWSER_POINTER_RIGHT;
- break;
- case CSS_CURSOR_W_RESIZE:
- pointer = BROWSER_POINTER_LEFT;
- break;
- case CSS_CURSOR_N_RESIZE:
- pointer = BROWSER_POINTER_UP;
- break;
- case CSS_CURSOR_S_RESIZE:
- pointer = BROWSER_POINTER_DOWN;
- break;
- case CSS_CURSOR_NE_RESIZE:
- pointer = BROWSER_POINTER_RU;
- break;
- case CSS_CURSOR_SW_RESIZE:
- pointer = BROWSER_POINTER_LD;
- break;
- case CSS_CURSOR_SE_RESIZE:
- pointer = BROWSER_POINTER_RD;
- break;
- case CSS_CURSOR_NW_RESIZE:
- pointer = BROWSER_POINTER_LU;
- break;
- case CSS_CURSOR_TEXT:
- pointer = BROWSER_POINTER_CARET;
- break;
- case CSS_CURSOR_WAIT:
- pointer = BROWSER_POINTER_WAIT;
- break;
- case CSS_CURSOR_PROGRESS:
- pointer = BROWSER_POINTER_PROGRESS;
- break;
- case CSS_CURSOR_HELP:
- pointer = BROWSER_POINTER_HELP;
- break;
- default:
- pointer = BROWSER_POINTER_DEFAULT;
- break;
- }
-
- return pointer;
-}
-
-
-/**
- * Start drag scrolling the contents of a box
- *
- * \param box the box to be scrolled
- * \param x x ordinate of initial mouse position
- * \param y y ordinate
- */
-
-static void html_box_drag_start(struct box *box, int x, int y)
-{
- int box_x, box_y;
- int scroll_mouse_x, scroll_mouse_y;
-
- box_coords(box, &box_x, &box_y);
-
- if (box->scroll_x != NULL) {
- scroll_mouse_x = x - box_x ;
- scroll_mouse_y = y - (box_y + box->padding[TOP] +
- box->height + box->padding[BOTTOM] -
- SCROLLBAR_WIDTH);
- scrollbar_start_content_drag(box->scroll_x,
- scroll_mouse_x, scroll_mouse_y);
- } else if (box->scroll_y != NULL) {
- scroll_mouse_x = x - (box_x + box->padding[LEFT] +
- box->width + box->padding[RIGHT] -
- SCROLLBAR_WIDTH);
- scroll_mouse_y = y - box_y;
-
- scrollbar_start_content_drag(box->scroll_y,
- scroll_mouse_x, scroll_mouse_y);
- }
-}
-
-
-/**
- * End overflow scroll scrollbar drags
- *
- * \param html html content
- * \param mouse state of mouse buttons and modifier keys
- * \param x coordinate of mouse
- * \param y coordinate of mouse
- * \param dir Direction of drag
- */
-static size_t html_selection_drag_end(struct html_content *html,
- browser_mouse_state mouse, int x, int y, int dir)
-{
- int pixel_offset;
- struct box *box;
- int dx, dy;
- size_t idx = 0;
-
- box = box_pick_text_box(html, x, y, dir, &dx, &dy);
- if (box) {
- plot_font_style_t fstyle;
-
- font_plot_style_from_css(&html->len_ctx, box->style, &fstyle);
-
- guit->layout->position(&fstyle, box->text, box->length,
- dx, &idx, &pixel_offset);
-
- idx += box->byte_offset;
- }
-
- return idx;
-}
-
-
-/**
- * Handle mouse tracking (including drags) in an HTML content window.
- *
- * \param c content of type html
- * \param bw browser window
- * \param mouse state of mouse buttons and modifier keys
- * \param x coordinate of mouse
- * \param y coordinate of mouse
- */
-
-void html_mouse_track(struct content *c, struct browser_window *bw,
- browser_mouse_state mouse, int x, int y)
-{
- html_mouse_action(c, bw, mouse, x, y);
-}
-
-/**
- * Helper for file gadgets to store their filename.
- *
- * Stores the filename unencoded on the dom node associated with the
- * gadget.
- *
- * \todo Get rid of this crap eventually
- *
- * \param operation DOM operation
- * \param key DOM node key being considerd
- * \param _data The data assocated with the key
- * \param src The source DOM node.
- * \param dst The destination DOM node.
- */
-static void
-html__image_coords_dom_user_data_handler(dom_node_operation operation,
- dom_string *key,
- void *_data,
- struct dom_node *src,
- struct dom_node *dst)
-{
- struct image_input_coords *oldcoords, *coords = _data, *newcoords;
-
- if (!dom_string_isequal(corestring_dom___ns_key_image_coords_node_data,
- key) || coords == NULL) {
- return;
- }
-
- switch (operation) {
- case DOM_NODE_CLONED:
- newcoords = calloc(1, sizeof(*newcoords));
- if (newcoords != NULL) {
- *newcoords = *coords;
- if (dom_node_set_user_data(dst,
- corestring_dom___ns_key_image_coords_node_data,
- newcoords,
- html__image_coords_dom_user_data_handler,
- &oldcoords) == DOM_NO_ERR) {
- free(oldcoords);
- }
- }
- break;
-
- case DOM_NODE_DELETED:
- free(coords);
- break;
-
- case DOM_NODE_RENAMED:
- case DOM_NODE_IMPORTED:
- case DOM_NODE_ADOPTED:
- break;
-
- default:
- NSLOG(netsurf, INFO, "User data operation not handled.");
- assert(0);
- }
-}
-
-/**
- * Handle mouse clicks and movements in an HTML content window.
- *
- * \param c content of type html
- * \param bw browser window
- * \param mouse state of mouse buttons and modifier keys
- * \param x coordinate of mouse
- * \param y coordinate of mouse
- *
- * This function handles both hovering and clicking. It is important that the
- * code path is identical (except that hovering doesn't carry out the action),
- * so that the status bar reflects exactly what will happen. Having separate
- * code paths opens the possibility that an attacker will make the status bar
- * show some harmless action where clicking will be harmful.
- */
-
-void html_mouse_action(struct content *c, struct browser_window *bw,
- browser_mouse_state mouse, int x, int y)
-{
- html_content *html = (html_content *) c;
- enum { ACTION_NONE, ACTION_SUBMIT, ACTION_GO } action = ACTION_NONE;
- const char *title = 0;
- nsurl *url = 0;
- char *url_s = NULL;
- size_t url_l = 0;
- const char *target = 0;
- char status_buffer[200];
- const char *status = 0;
- browser_pointer_shape pointer = BROWSER_POINTER_DEFAULT;
- bool imagemap = false;
- int box_x = 0, box_y = 0;
- int gadget_box_x = 0, gadget_box_y = 0;
- int html_object_pos_x = 0, html_object_pos_y = 0;
- int text_box_x = 0;
- struct box *url_box = 0;
- struct box *gadget_box = 0;
- struct box *text_box = 0;
- struct box *box;
- struct form_control *gadget = 0;
- hlcache_handle *object = NULL;
- struct box *html_object_box = NULL;
- struct browser_window *iframe = NULL;
- struct box *drag_candidate = NULL;
- struct scrollbar *scrollbar = NULL;
- plot_font_style_t fstyle;
- int scroll_mouse_x = 0, scroll_mouse_y = 0;
- int padding_left, padding_right, padding_top, padding_bottom;
- browser_drag_type drag_type = browser_window_get_drag_type(bw);
- union content_msg_data msg_data;
- struct dom_node *node = NULL;
- union html_drag_owner drag_owner;
- union html_selection_owner sel_owner;
- bool click = mouse & (BROWSER_MOUSE_PRESS_1 | BROWSER_MOUSE_PRESS_2 |
- BROWSER_MOUSE_CLICK_1 | BROWSER_MOUSE_CLICK_2 |
- BROWSER_MOUSE_DRAG_1 | BROWSER_MOUSE_DRAG_2);
-
- if (drag_type != DRAGGING_NONE && !mouse &&
- html->visible_select_menu != NULL) {
- /* drag end: select menu */
- form_select_mouse_drag_end(html->visible_select_menu,
- mouse, x, y);
- }
-
- if (html->visible_select_menu != NULL) {
- box = html->visible_select_menu->box;
- box_coords(box, &box_x, &box_y);
-
- box_x -= box->border[LEFT].width;
- box_y += box->height + box->border[BOTTOM].width +
- box->padding[BOTTOM] + box->padding[TOP];
- status = form_select_mouse_action(html->visible_select_menu,
- mouse, x - box_x, y - box_y);
- if (status != NULL) {
- msg_data.explicit_status_text = status;
- content_broadcast(c, CONTENT_MSG_STATUS, &msg_data);
- } else {
- int width, height;
- form_select_get_dimensions(html->visible_select_menu,
- &width, &height);
- html->visible_select_menu = NULL;
- browser_window_redraw_rect(bw, box_x, box_y,
- width, height);
- }
- return;
- }
-
- if (html->drag_type == HTML_DRAG_SELECTION) {
- /* Selection drag */
- struct box *box;
- int dir = -1;
- int dx, dy;
-
- if (!mouse) {
- /* End of selection drag */
- int dir = -1;
- size_t idx;
-
- if (selection_dragging_start(&html->sel))
- dir = 1;
-
- idx = html_selection_drag_end(html, mouse, x, y, dir);
-
- if (idx != 0)
- selection_track(&html->sel, mouse, idx);
-
- drag_owner.no_owner = true;
- html_set_drag_type(html, HTML_DRAG_NONE,
- drag_owner, NULL);
- return;
- }
-
- if (selection_dragging_start(&html->sel))
- dir = 1;
-
- box = box_pick_text_box(html, x, y, dir, &dx, &dy);
-
- if (box != NULL) {
- int pixel_offset;
- size_t idx;
- plot_font_style_t fstyle;
-
- font_plot_style_from_css(&html->len_ctx,
- box->style, &fstyle);
-
- guit->layout->position(&fstyle,
- box->text, box->length,
- dx, &idx, &pixel_offset);
-
- selection_track(&html->sel, mouse,
- box->byte_offset + idx);
- }
- return;
- }
-
- if (html->drag_type == HTML_DRAG_SCROLLBAR) {
- struct scrollbar *scr = html->drag_owner.scrollbar;
- struct html_scrollbar_data *data = scrollbar_get_data(scr);
-
- if (!mouse) {
- /* drag end: scrollbar */
- html_overflow_scroll_drag_end(scr, mouse, x, y);
- }
-
- box = data->box;
- box_coords(box, &box_x, &box_y);
- if (scrollbar_is_horizontal(scr)) {
- scroll_mouse_x = x - box_x ;
- scroll_mouse_y = y - (box_y + box->padding[TOP] +
- box->height + box->padding[BOTTOM] -
- SCROLLBAR_WIDTH);
- status = scrollbar_mouse_status_to_message(
- scrollbar_mouse_action(scr, mouse,
- scroll_mouse_x,
- scroll_mouse_y));
- } else {
- scroll_mouse_x = x - (box_x + box->padding[LEFT] +
- box->width + box->padding[RIGHT] -
- SCROLLBAR_WIDTH);
- scroll_mouse_y = y - box_y;
- status = scrollbar_mouse_status_to_message(
- scrollbar_mouse_action(scr, mouse,
- scroll_mouse_x,
- scroll_mouse_y));
- }
-
- msg_data.explicit_status_text = status;
- content_broadcast(c, CONTENT_MSG_STATUS, &msg_data);
- return;
- }
-
- if (html->drag_type == HTML_DRAG_TEXTAREA_SELECTION ||
- html->drag_type == HTML_DRAG_TEXTAREA_SCROLLBAR) {
- box = html->drag_owner.textarea;
- assert(box->gadget != NULL);
- assert(box->gadget->type == GADGET_TEXTAREA ||
- box->gadget->type == GADGET_PASSWORD ||
- box->gadget->type == GADGET_TEXTBOX);
-
- box_coords(box, &box_x, &box_y);
- textarea_mouse_action(box->gadget->data.text.ta, mouse,
- x - box_x, y - box_y);
-
- /* TODO: Set appropriate statusbar message */
- return;
- }
-
- if (html->drag_type == HTML_DRAG_CONTENT_SELECTION ||
- html->drag_type == HTML_DRAG_CONTENT_SCROLL) {
- box = html->drag_owner.content;
- assert(box->object != NULL);
-
- box_coords(box, &box_x, &box_y);
- content_mouse_track(box->object, bw, mouse,
- x - box_x, y - box_y);
- return;
- }
-
- if (html->drag_type == HTML_DRAG_CONTENT_SELECTION) {
- box = html->drag_owner.content;
- assert(box->object != NULL);
-
- box_coords(box, &box_x, &box_y);
- content_mouse_track(box->object, bw, mouse,
- x - box_x, y - box_y);
- return;
- }
-
- /* Content related drags handled by now */
- assert(html->drag_type == HTML_DRAG_NONE);
-
- /* search the box tree for a link, imagemap, form control, or
- * box with scrollbars
- */
-
- box = html->layout;
-
- /* Consider the margins of the html page now */
- box_x = box->margin[LEFT];
- box_y = box->margin[TOP];
-
- /* descend through visible boxes setting more specific values for:
- * box - deepest box at point
- * html_object_box - html object
- * html_object_pos_x - html object
- * html_object_pos_y - html object
- * object - non html object
- * iframe - iframe
- * url - href or imagemap
- * target - href or imagemap or gadget
- * url_box - href or imagemap
- * imagemap - imagemap
- * gadget - gadget
- * gadget_box - gadget
- * gadget_box_x - gadget
- * gadget_box_y - gadget
- * title - title
- * pointer
- *
- * drag_candidate - first box with scroll
- * padding_left - box with scroll
- * padding_right
- * padding_top
- * padding_bottom
- * scrollbar - inside padding box stops decent
- * scroll_mouse_x - inside padding box stops decent
- * scroll_mouse_y - inside padding box stops decent
- *
- * text_box - text box
- * text_box_x - text_box
- */
- do {
- if ((box->style != NULL) &&
- (css_computed_visibility(box->style) ==
- CSS_VISIBILITY_HIDDEN)) {
- continue;
- }
-
- if (box->node != NULL) {
- node = box->node;
- }
-
- if (box->object) {
- if (content_get_type(box->object) == CONTENT_HTML) {
- html_object_box = box;
- html_object_pos_x = box_x;
- html_object_pos_y = box_y;
- } else {
- object = box->object;
- }
- }
-
- if (box->iframe) {
- iframe = box->iframe;
- }
-
- if (box->href) {
- url = box->href;
- target = box->target;
- url_box = box;
- }
-
- if (box->usemap) {
- url = imagemap_get(html, box->usemap,
- box_x, box_y, x, y, &target);
- if (url) {
- imagemap = true;
- url_box = box;
- }
- }
-
- if (box->gadget) {
- gadget = box->gadget;
- gadget_box = box;
- gadget_box_x = box_x;
- gadget_box_y = box_y;
- if (gadget->form)
- target = gadget->form->target;
- }
-
- if (box->title) {
- title = box->title;
- }
-
- pointer = get_pointer_shape(box, false);
-
- if ((box->scroll_x != NULL) ||
- (box->scroll_y != NULL)) {
-
- if (drag_candidate == NULL) {
- drag_candidate = box;
- }
-
- padding_left = box_x +
- scrollbar_get_offset(box->scroll_x);
- padding_right = padding_left + box->padding[LEFT] +
- box->width + box->padding[RIGHT];
- padding_top = box_y +
- scrollbar_get_offset(box->scroll_y);
- padding_bottom = padding_top + box->padding[TOP] +
- box->height + box->padding[BOTTOM];
-
- if ((x > padding_left) &&
- (x < padding_right) &&
- (y > padding_top) &&
- (y < padding_bottom)) {
- /* mouse inside padding box */
-
- if ((box->scroll_y != NULL) &&
- (x > (padding_right -
- SCROLLBAR_WIDTH))) {
- /* mouse above vertical box scroll */
-
- scrollbar = box->scroll_y;
- scroll_mouse_x = x - (padding_right -
- SCROLLBAR_WIDTH);
- scroll_mouse_y = y - padding_top;
- break;
-
- } else if ((box->scroll_x != NULL) &&
- (y > (padding_bottom -
- SCROLLBAR_WIDTH))) {
- /* mouse above horizontal box scroll */
-
- scrollbar = box->scroll_x;
- scroll_mouse_x = x - padding_left;
- scroll_mouse_y = y - (padding_bottom -
- SCROLLBAR_WIDTH);
- break;
- }
- }
- }
-
- if (box->text && !box->object) {
- text_box = box;
- text_box_x = box_x;
- }
- } while ((box = box_at_point(&html->len_ctx, box, x, y,
- &box_x, &box_y)) != NULL);
-
- /* use of box_x, box_y, or content below this point is probably a
- * mistake; they will refer to the last box returned by box_at_point */
- assert(node != NULL);
-
- if (scrollbar) {
- status = scrollbar_mouse_status_to_message(
- scrollbar_mouse_action(scrollbar, mouse,
- scroll_mouse_x,
- scroll_mouse_y));
- pointer = BROWSER_POINTER_DEFAULT;
- } else if (gadget) {
- textarea_mouse_status ta_status;
-
- switch (gadget->type) {
- case GADGET_SELECT:
- status = messages_get("FormSelect");
- pointer = BROWSER_POINTER_MENU;
- if (mouse & BROWSER_MOUSE_CLICK_1 &&
- nsoption_bool(core_select_menu)) {
- html->visible_select_menu = gadget;
- form_open_select_menu(c, gadget,
- form_select_menu_callback,
- c);
- pointer = BROWSER_POINTER_DEFAULT;
- } else if (mouse & BROWSER_MOUSE_CLICK_1) {
- msg_data.select_menu.gadget = gadget;
- content_broadcast(c, CONTENT_MSG_SELECTMENU,
- &msg_data);
- }
- break;
- case GADGET_CHECKBOX:
- status = messages_get("FormCheckbox");
- if (mouse & BROWSER_MOUSE_CLICK_1) {
- gadget->selected = !gadget->selected;
- dom_html_input_element_set_checked(
- (dom_html_input_element *)(gadget->node),
- gadget->selected);
- html__redraw_a_box(html, gadget_box);
- }
- break;
- case GADGET_RADIO:
- status = messages_get("FormRadio");
- if (mouse & BROWSER_MOUSE_CLICK_1)
- form_radio_set(gadget);
- break;
- case GADGET_IMAGE:
- /* This falls through to SUBMIT */
- if (mouse & BROWSER_MOUSE_CLICK_1) {
- struct image_input_coords *coords, *oldcoords;
- /** \todo Find a way to not ignore errors */
- coords = calloc(1, sizeof(*coords));
- if (coords == NULL) {
- return;
- }
- coords->x = x - gadget_box_x;
- coords->y = y - gadget_box_y;
- if (dom_node_set_user_data(
- gadget->node,
- corestring_dom___ns_key_image_coords_node_data,
- coords, html__image_coords_dom_user_data_handler,
- &oldcoords) != DOM_NO_ERR)
- return;
- free(oldcoords);
- }
- /* Fall through */
- case GADGET_SUBMIT:
- if (gadget->form) {
- snprintf(status_buffer, sizeof status_buffer,
- messages_get("FormSubmit"),
- gadget->form->action);
- status = status_buffer;
- pointer = get_pointer_shape(gadget_box, false);
- if (mouse & (BROWSER_MOUSE_CLICK_1 |
- BROWSER_MOUSE_CLICK_2))
- action = ACTION_SUBMIT;
- } else {
- status = messages_get("FormBadSubmit");
- }
- break;
- case GADGET_TEXTBOX:
- case GADGET_PASSWORD:
- case GADGET_TEXTAREA:
- if (gadget->type == GADGET_TEXTAREA)
- status = messages_get("FormTextarea");
- else
- status = messages_get("FormTextbox");
-
- if (click && (html->selection_type !=
- HTML_SELECTION_TEXTAREA ||
- html->selection_owner.textarea !=
- gadget_box)) {
- sel_owner.none = true;
- html_set_selection(html, HTML_SELECTION_NONE,
- sel_owner, true);
- }
-
- ta_status = textarea_mouse_action(gadget->data.text.ta,
- mouse, x - gadget_box_x,
- y - gadget_box_y);
-
- if (ta_status & TEXTAREA_MOUSE_EDITOR) {
- pointer = get_pointer_shape(gadget_box, false);
- } else {
- pointer = BROWSER_POINTER_DEFAULT;
- status = scrollbar_mouse_status_to_message(
- ta_status >> 3);
- }
- break;
- case GADGET_HIDDEN:
- /* not possible: no box generated */
- break;
- case GADGET_RESET:
- status = messages_get("FormReset");
- break;
- case GADGET_FILE:
- status = messages_get("FormFile");
- if (mouse & BROWSER_MOUSE_CLICK_1) {
- msg_data.gadget_click.gadget = gadget;
- content_broadcast(c, CONTENT_MSG_GADGETCLICK,
- &msg_data);
- }
- break;
- case GADGET_BUTTON:
- /* This gadget cannot be activated */
- status = messages_get("FormButton");
- break;
- }
-
- } else if (object && (mouse & BROWSER_MOUSE_MOD_2)) {
-
- if (mouse & BROWSER_MOUSE_DRAG_2) {
- msg_data.dragsave.type = CONTENT_SAVE_NATIVE;
- msg_data.dragsave.content = object;
- content_broadcast(c, CONTENT_MSG_DRAGSAVE, &msg_data);
-
- } else if (mouse & BROWSER_MOUSE_DRAG_1) {
- msg_data.dragsave.type = CONTENT_SAVE_ORIG;
- msg_data.dragsave.content = object;
- content_broadcast(c, CONTENT_MSG_DRAGSAVE, &msg_data);
- }
-
- /* \todo should have a drag-saving object msg */
-
- } else if (iframe) {
- int pos_x, pos_y;
- float scale = browser_window_get_scale(bw);
-
- browser_window_get_position(iframe, false, &pos_x, &pos_y);
-
- pos_x /= scale;
- pos_y /= scale;
-
- 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 (html_object_box) {
-
- if (click && (html->selection_type != HTML_SELECTION_CONTENT ||
- html->selection_owner.content !=
- html_object_box)) {
- sel_owner.none = true;
- html_set_selection(html, HTML_SELECTION_NONE,
- sel_owner, true);
- }
- if (mouse & BROWSER_MOUSE_CLICK_1 ||
- mouse & BROWSER_MOUSE_CLICK_2) {
- content_mouse_action(html_object_box->object,
- bw, mouse,
- x - html_object_pos_x,
- y - html_object_pos_y);
- } else {
- content_mouse_track(html_object_box->object,
- bw, mouse,
- x - html_object_pos_x,
- y - html_object_pos_y);
- }
- } else if (url) {
- if (nsoption_bool(display_decoded_idn) == true) {
- if (nsurl_get_utf8(url, &url_s, &url_l) != NSERROR_OK) {
- /* Unable to obtain a decoded IDN. This is not a fatal error.
- * Ensure the string pointer is NULL so we use the encoded version. */
- url_s = NULL;
- }
- }
-
- if (title) {
- snprintf(status_buffer, sizeof status_buffer, "%s: %s",
- url_s ? url_s : nsurl_access(url), title);
- } else {
- snprintf(status_buffer, sizeof status_buffer, "%s",
- url_s ? url_s : nsurl_access(url));
- }
-
- status = status_buffer;
-
- if (url_s != NULL)
- free(url_s);
-
- pointer = get_pointer_shape(url_box, imagemap);
-
- if (mouse & BROWSER_MOUSE_CLICK_1 &&
- mouse & BROWSER_MOUSE_MOD_1) {
- /* force download of link */
- browser_window_navigate(bw,
- url,
- content_get_url(c),
- BW_NAVIGATE_DOWNLOAD,
- NULL,
- NULL,
- NULL);
-
- } else if (mouse & BROWSER_MOUSE_CLICK_2 &&
- mouse & BROWSER_MOUSE_MOD_1) {
- msg_data.savelink.url = url;
- msg_data.savelink.title = title;
- content_broadcast(c, CONTENT_MSG_SAVELINK, &msg_data);
-
- } else if (mouse & (BROWSER_MOUSE_CLICK_1 |
- BROWSER_MOUSE_CLICK_2))
- action = ACTION_GO;
- } else {
- bool done = false;
-
- /* frame resizing */
- if (browser_window_frame_resize_start(bw, mouse, x, y,
- &pointer)) {
- if (mouse & (BROWSER_MOUSE_DRAG_1 |
- BROWSER_MOUSE_DRAG_2)) {
- status = messages_get("FrameDrag");
- }
- done = true;
- }
-
- /* if clicking in the main page, remove the selection from any
- * text areas */
- if (!done) {
-
- if (click && html->focus_type != HTML_FOCUS_SELF) {
- union html_focus_owner fo;
- fo.self = true;
- html_set_focus(html, HTML_FOCUS_SELF, fo,
- true, 0, 0, 0, NULL);
- }
- if (click && html->selection_type !=
- HTML_SELECTION_SELF) {
- sel_owner.none = true;
- html_set_selection(html, HTML_SELECTION_NONE,
- sel_owner, true);
- }
-
- if (text_box) {
- int pixel_offset;
- size_t idx;
-
- font_plot_style_from_css(&html->len_ctx,
- text_box->style, &fstyle);
-
- guit->layout->position(&fstyle,
- text_box->text,
- text_box->length,
- x - text_box_x,
- &idx,
- &pixel_offset);
-
- if (selection_click(&html->sel, mouse,
- text_box->byte_offset + idx)) {
- /* key presses must be directed at the
- * main browser window, paste text
- * operations ignored */
- html_drag_type drag_type;
- union html_drag_owner drag_owner;
-
- if (selection_dragging(&html->sel)) {
- drag_type = HTML_DRAG_SELECTION;
- drag_owner.no_owner = true;
- html_set_drag_type(html,
- drag_type,
- drag_owner,
- NULL);
- status = messages_get(
- "Selecting");
- }
-
- done = true;
- }
-
- } else if (mouse & BROWSER_MOUSE_PRESS_1) {
- sel_owner.none = true;
- selection_clear(&html->sel, true);
- }
-
- if (selection_defined(&html->sel)) {
- sel_owner.none = false;
- html_set_selection(html, HTML_SELECTION_SELF,
- sel_owner, true);
- } else if (click && html->selection_type !=
- HTML_SELECTION_NONE) {
- sel_owner.none = true;
- html_set_selection(html, HTML_SELECTION_NONE,
- sel_owner, true);
- }
- }
-
- if (!done) {
- if (title)
- status = title;
-
- if (mouse & BROWSER_MOUSE_DRAG_1) {
- if (mouse & BROWSER_MOUSE_MOD_2) {
- msg_data.dragsave.type =
- CONTENT_SAVE_COMPLETE;
- msg_data.dragsave.content = NULL;
- content_broadcast(c,
- CONTENT_MSG_DRAGSAVE,
- &msg_data);
- } else {
- if (drag_candidate == NULL) {
- browser_window_page_drag_start(
- bw, x, y);
- } else {
- html_box_drag_start(
- drag_candidate,
- x, y);
- }
- pointer = BROWSER_POINTER_MOVE;
- }
- }
- else if (mouse & BROWSER_MOUSE_DRAG_2) {
- if (mouse & BROWSER_MOUSE_MOD_2) {
- msg_data.dragsave.type =
- CONTENT_SAVE_SOURCE;
- msg_data.dragsave.content = NULL;
- content_broadcast(c,
- CONTENT_MSG_DRAGSAVE,
- &msg_data);
- } else {
- if (drag_candidate == NULL) {
- browser_window_page_drag_start(
- bw, x, y);
- } else {
- html_box_drag_start(
- drag_candidate,
- x, y);
- }
- pointer = BROWSER_POINTER_MOVE;
- }
- }
- }
- if (mouse && mouse < BROWSER_MOUSE_MOD_1) {
- /* ensure key presses still act on the browser window */
- union html_focus_owner fo;
- fo.self = true;
- html_set_focus(html, HTML_FOCUS_SELF, fo,
- true, 0, 0, 0, NULL);
- }
- }
-
- if (!iframe && !html_object_box) {
- msg_data.explicit_status_text = status;
- content_broadcast(c, CONTENT_MSG_STATUS, &msg_data);
-
- msg_data.pointer = pointer;
- content_broadcast(c, CONTENT_MSG_POINTER, &msg_data);
- }
-
- /* fire dom click event */
- if (mouse & BROWSER_MOUSE_CLICK_1) {
- fire_dom_event(corestring_dom_click, node, true, true);
- }
-
- /* deferred actions that can cause this browser_window to be destroyed
- * and must therefore be done after set_status/pointer
- */
- switch (action) {
- case ACTION_SUBMIT:
- form_submit(content_get_url(c),
- browser_window_find_target(bw, target, mouse),
- gadget->form, gadget);
- break;
- case ACTION_GO:
- browser_window_navigate(browser_window_find_target(bw, target, mouse),
- url,
- content_get_url(c),
- BW_NAVIGATE_HISTORY,
- NULL,
- NULL,
- NULL);
- break;
- case ACTION_NONE:
- break;
- }
-}
-
-
-/**
- * Handle keypresses.
- *
- * \param c content of type HTML
- * \param key The UCS4 character codepoint
- * \return true if key handled, false otherwise
- */
-
-bool html_keypress(struct content *c, uint32_t key)
-{
- html_content *html = (html_content *) c;
- struct selection *sel = &html->sel;
- struct box *box;
-
- switch (html->focus_type) {
- case HTML_FOCUS_CONTENT:
- box = html->focus_owner.content;
- return content_keypress(box->object, key);
-
- case HTML_FOCUS_TEXTAREA:
- box = html->focus_owner.textarea;
- return box_textarea_keypress(html, box, key);
-
- default:
- /* Deal with it below */
- break;
- }
-
- switch (key) {
- case NS_KEY_COPY_SELECTION:
- selection_copy_to_clipboard(sel);
- return true;
-
- case NS_KEY_CLEAR_SELECTION:
- selection_clear(sel, true);
- return true;
-
- case NS_KEY_SELECT_ALL:
- selection_select_all(sel);
- return true;
-
- case NS_KEY_ESCAPE:
- if (selection_defined(sel)) {
- selection_clear(sel, true);
- return true;
- }
-
- /* if there's no selection, leave Escape for the caller */
- return false;
- }
-
- return false;
-}
-
-
-/**
- * Handle search.
- *
- * \param c content of type HTML
- * \param context front end private data
- * \param flags search flags
- * \param string search string
- */
-void html_search(struct content *c, void *context,
- search_flags_t flags, const char *string)
-{
- html_content *html = (html_content *)c;
-
- assert(c != NULL);
-
- if (string != NULL && html->search_string != NULL &&
- strcmp(string, html->search_string) == 0 &&
- html->search != NULL) {
- /* Continue prev. search */
- search_step(html->search, flags, string);
-
- } else if (string != NULL) {
- /* New search */
- free(html->search_string);
- html->search_string = strdup(string);
- if (html->search_string == NULL)
- return;
-
- if (html->search != NULL) {
- search_destroy_context(html->search);
- html->search = NULL;
- }
-
- html->search = search_create_context(c, CONTENT_HTML, context);
-
- if (html->search == NULL)
- return;
-
- search_step(html->search, flags, string);
-
- } else {
- /* Clear search */
- html_search_clear(c);
-
- free(html->search_string);
- html->search_string = NULL;
- }
-}
-
-
-/**
- * Terminate a search.
- *
- * \param c content of type HTML
- */
-void html_search_clear(struct content *c)
-{
- html_content *html = (html_content *)c;
-
- assert(c != NULL);
-
- free(html->search_string);
- html->search_string = NULL;
-
- if (html->search != NULL) {
- search_destroy_context(html->search);
- }
- html->search = NULL;
-}
-
-
-/**
- * Callback for in-page scrollbars.
- */
-void html_overflow_scroll_callback(void *client_data,
- struct scrollbar_msg_data *scrollbar_data)
-{
- struct html_scrollbar_data *data = client_data;
- html_content *html = (html_content *)data->c;
- struct box *box = data->box;
- union content_msg_data msg_data;
- html_drag_type drag_type;
- union html_drag_owner drag_owner;
-
- switch(scrollbar_data->msg) {
- case SCROLLBAR_MSG_MOVED:
-
- if (html->reflowing == true) {
- /* Can't redraw during layout, and it will
- * be redrawn after layout anyway. */
- break;
- }
-
- html__redraw_a_box(html, box);
- break;
- case SCROLLBAR_MSG_SCROLL_START:
- {
- struct rect rect = {
- .x0 = scrollbar_data->x0,
- .y0 = scrollbar_data->y0,
- .x1 = scrollbar_data->x1,
- .y1 = scrollbar_data->y1
- };
- drag_type = HTML_DRAG_SCROLLBAR;
- drag_owner.scrollbar = scrollbar_data->scrollbar;
- html_set_drag_type(html, drag_type, drag_owner, &rect);
- }
- break;
- case SCROLLBAR_MSG_SCROLL_FINISHED:
- drag_type = HTML_DRAG_NONE;
- drag_owner.no_owner = true;
- html_set_drag_type(html, drag_type, drag_owner, NULL);
-
- msg_data.pointer = BROWSER_POINTER_AUTO;
- content_broadcast(data->c, CONTENT_MSG_POINTER, &msg_data);
- break;
- }
-}
-
-
-/**
- * End overflow scroll scrollbar drags
- *
- * \param scrollbar scrollbar widget
- * \param mouse state of mouse buttons and modifier keys
- * \param x coordinate of mouse
- * \param y coordinate of mouse
- */
-void html_overflow_scroll_drag_end(struct scrollbar *scrollbar,
- browser_mouse_state mouse, int x, int y)
-{
- int scroll_mouse_x, scroll_mouse_y, box_x, box_y;
- struct html_scrollbar_data *data = scrollbar_get_data(scrollbar);
- struct box *box;
-
- box = data->box;
- box_coords(box, &box_x, &box_y);
-
- if (scrollbar_is_horizontal(scrollbar)) {
- scroll_mouse_x = x - box_x;
- scroll_mouse_y = y - (box_y + box->padding[TOP] +
- box->height + box->padding[BOTTOM] -
- SCROLLBAR_WIDTH);
- scrollbar_mouse_drag_end(scrollbar, mouse,
- scroll_mouse_x, scroll_mouse_y);
- } else {
- scroll_mouse_x = x - (box_x + box->padding[LEFT] +
- box->width + box->padding[RIGHT] -
- SCROLLBAR_WIDTH);
- scroll_mouse_y = y - box_y;
- scrollbar_mouse_drag_end(scrollbar, mouse,
- scroll_mouse_x, scroll_mouse_y);
- }
-}
-
-/* Documented in html_internal.h */
-void html_set_drag_type(html_content *html, html_drag_type drag_type,
- union html_drag_owner drag_owner, const struct rect *rect)
-{
- union content_msg_data msg_data;
-
- assert(html != NULL);
-
- html->drag_type = drag_type;
- html->drag_owner = drag_owner;
-
- switch (drag_type) {
- case HTML_DRAG_NONE:
- assert(drag_owner.no_owner == true);
- msg_data.drag.type = CONTENT_DRAG_NONE;
- break;
-
- case HTML_DRAG_SCROLLBAR:
- case HTML_DRAG_TEXTAREA_SCROLLBAR:
- case HTML_DRAG_CONTENT_SCROLL:
- msg_data.drag.type = CONTENT_DRAG_SCROLL;
- break;
-
- case HTML_DRAG_SELECTION:
- assert(drag_owner.no_owner == true);
- /* Fall through */
- case HTML_DRAG_TEXTAREA_SELECTION:
- case HTML_DRAG_CONTENT_SELECTION:
- msg_data.drag.type = CONTENT_DRAG_SELECTION;
- break;
- }
- msg_data.drag.rect = rect;
-
- /* Inform of the content's drag status change */
- content_broadcast((struct content *)html, CONTENT_MSG_DRAG, &msg_data);
-}
-
-/* Documented in html_internal.h */
-void html_set_focus(html_content *html, html_focus_type focus_type,
- union html_focus_owner focus_owner, bool hide_caret,
- int x, int y, int height, const struct rect *clip)
-{
- union content_msg_data msg_data;
- int x_off = 0;
- int y_off = 0;
- struct rect cr;
- bool textarea_lost_focus = html->focus_type == HTML_FOCUS_TEXTAREA &&
- focus_type != HTML_FOCUS_TEXTAREA;
-
- assert(html != NULL);
-
- switch (focus_type) {
- case HTML_FOCUS_SELF:
- assert(focus_owner.self == true);
- if (html->focus_type == HTML_FOCUS_SELF)
- /* Don't need to tell anyone anything */
- return;
- break;
-
- case HTML_FOCUS_CONTENT:
- box_coords(focus_owner.content, &x_off, &y_off);
- break;
-
- case HTML_FOCUS_TEXTAREA:
- box_coords(focus_owner.textarea, &x_off, &y_off);
- break;
- }
-
- html->focus_type = focus_type;
- html->focus_owner = focus_owner;
-
- if (textarea_lost_focus) {
- msg_data.caret.type = CONTENT_CARET_REMOVE;
- } else if (focus_type != HTML_FOCUS_SELF && hide_caret) {
- msg_data.caret.type = CONTENT_CARET_HIDE;
- } else {
- if (clip != NULL) {
- cr = *clip;
- cr.x0 += x_off;
- cr.y0 += y_off;
- cr.x1 += x_off;
- cr.y1 += y_off;
- }
-
- msg_data.caret.type = CONTENT_CARET_SET_POS;
- msg_data.caret.pos.x = x + x_off;
- msg_data.caret.pos.y = y + y_off;
- msg_data.caret.pos.height = height;
- msg_data.caret.pos.clip = (clip == NULL) ? NULL : &cr;
- }
-
- /* Inform of the content's drag status change */
- content_broadcast((struct content *)html, CONTENT_MSG_CARET, &msg_data);
-}
-
-/* Documented in html_internal.h */
-void html_set_selection(html_content *html, html_selection_type selection_type,
- union html_selection_owner selection_owner, bool read_only)
-{
- union content_msg_data msg_data;
- struct box *box;
- bool changed = false;
- bool same_type = html->selection_type == selection_type;
-
- assert(html != NULL);
-
- if ((selection_type == HTML_SELECTION_NONE &&
- html->selection_type != HTML_SELECTION_NONE) ||
- (selection_type != HTML_SELECTION_NONE &&
- html->selection_type == HTML_SELECTION_NONE))
- /* Existance of selection has changed, and we'll need to
- * inform our owner */
- changed = true;
-
- /* Clear any existing selection */
- if (html->selection_type != HTML_SELECTION_NONE) {
- switch (html->selection_type) {
- case HTML_SELECTION_SELF:
- if (same_type)
- break;
- selection_clear(&html->sel, true);
- break;
- case HTML_SELECTION_TEXTAREA:
- if (same_type && html->selection_owner.textarea ==
- selection_owner.textarea)
- break;
- box = html->selection_owner.textarea;
- textarea_clear_selection(box->gadget->data.text.ta);
- break;
- case HTML_SELECTION_CONTENT:
- if (same_type && html->selection_owner.content ==
- selection_owner.content)
- break;
- box = html->selection_owner.content;
- content_clear_selection(box->object);
- break;
- default:
- break;
- }
- }
-
- html->selection_type = selection_type;
- html->selection_owner = selection_owner;
-
- if (!changed)
- /* Don't need to report lack of change to owner */
- return;
-
- /* Prepare msg */
- switch (selection_type) {
- case HTML_SELECTION_NONE:
- assert(selection_owner.none == true);
- msg_data.selection.selection = false;
- break;
- case HTML_SELECTION_SELF:
- assert(selection_owner.none == false);
- /* fall through */
- case HTML_SELECTION_TEXTAREA:
- case HTML_SELECTION_CONTENT:
- msg_data.selection.selection = true;
- break;
- default:
- break;
- }
- msg_data.selection.read_only = read_only;
-
- /* Inform of the content's selection status change */
- content_broadcast((struct content *)html, CONTENT_MSG_SELECTION,
- &msg_data);
-}
diff --git a/render/html_internal.h b/render/html_internal.h
deleted file mode 100644
index 66ecb2b36..000000000
--- a/render/html_internal.h
+++ /dev/null
@@ -1,410 +0,0 @@
-/*
- * Copyright 2004 James Bursa <bursa@users.sourceforge.net>
- *
- * This file is part of NetSurf, http://www.netsurf-browser.org/
- *
- * NetSurf is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * NetSurf is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-/**
- * \file
- * Content for text/html (private data).
- */
-
-#ifndef NETSURF_RENDER_HTML_INTERNAL_H_
-#define NETSURF_RENDER_HTML_INTERNAL_H_
-
-#include <libcss/libcss.h>
-
-#include "content/handlers/css/utils.h"
-#include "content/content_protected.h"
-#include "desktop/selection.h"
-#include "render/html.h"
-
-struct gui_layout_table;
-
-typedef enum {
- HTML_DRAG_NONE, /** No drag */
- HTML_DRAG_SELECTION, /** Own; Text selection */
- HTML_DRAG_SCROLLBAR, /** Not own; drag in scrollbar widget */
- HTML_DRAG_TEXTAREA_SELECTION, /** Not own; drag in textarea widget */
- HTML_DRAG_TEXTAREA_SCROLLBAR, /** Not own; drag in textarea widget */
- HTML_DRAG_CONTENT_SELECTION, /** Not own; drag in child content */
- HTML_DRAG_CONTENT_SCROLL /** Not own; drag in child content */
-} html_drag_type;
-
-union html_drag_owner {
- bool no_owner;
- struct box *content;
- struct scrollbar *scrollbar;
- struct box *textarea;
-}; /**< For drags we don't own */
-
-typedef enum {
- HTML_SELECTION_NONE, /** No selection */
- HTML_SELECTION_TEXTAREA, /** Selection in one of our textareas */
- HTML_SELECTION_SELF, /** Selection in this html content */
- HTML_SELECTION_CONTENT /** Selection in child content */
-} html_selection_type;
-union html_selection_owner {
- bool none;
- struct box *textarea;
- struct box *content;
-}; /**< For getting at selections in this content or things in this content */
-
-typedef enum {
- HTML_FOCUS_SELF, /** Focus is our own */
- HTML_FOCUS_CONTENT, /** Focus belongs to child content */
- HTML_FOCUS_TEXTAREA /** Focus belongs to textarea */
-} html_focus_type;
-union html_focus_owner {
- bool self;
- struct box *textarea;
- struct box *content;
-}; /**< For directing input */
-
-/** Data specific to CONTENT_HTML. */
-typedef struct html_content {
- struct content base;
-
- dom_hubbub_parser *parser; /**< Parser object handle */
- bool parse_completed; /**< Whether the parse has been completed */
-
- /** Document tree */
- dom_document *document;
- /** Quirkyness of document */
- dom_document_quirks_mode quirks;
-
- /** Encoding of source, NULL if unknown. */
- char *encoding;
- /** Source of encoding information. */
- dom_hubbub_encoding_source encoding_source;
-
- /** Base URL (may be a copy of content->url). */
- nsurl *base_url;
- /** Base target */
- char *base_target;
-
- /** CSS length conversion context for document. */
- nscss_len_ctx len_ctx;
-
- /** Content has been aborted in the LOADING state */
- bool aborted;
-
- /** Whether a meta refresh has been handled */
- bool refresh;
-
- /** Whether a layout (reflow) is in progress */
- bool reflowing;
-
- /** Whether scripts are enabled for this content */
- bool enable_scripting;
-
- /* Title element node */
- dom_node *title;
-
- /** A talloc context purely for the render box tree */
- int *bctx;
- /** Box tree, or NULL. */
- struct box *layout;
- /** Document background colour. */
- colour background_colour;
-
- /** Font callback table */
- const struct gui_layout_table *font_func;
-
- /** Number of entries in scripts */
- unsigned int scripts_count;
- /** Scripts */
- struct html_script *scripts;
- /** javascript context */
- struct jscontext *jscontext;
-
- /** Number of entries in stylesheet_content. */
- unsigned int stylesheet_count;
- /** Stylesheets. Each may be NULL. */
- struct html_stylesheet *stylesheets;
- /**< Style selection context */
- css_select_ctx *select_ctx;
- /**< Universal selector */
- lwc_string *universal;
-
- /** Number of entries in object_list. */
- unsigned int num_objects;
- /** List of objects. */
- struct content_html_object *object_list;
- /** Forms, in reverse order to document. */
- struct form *forms;
- /** Hash table of imagemaps. */
- struct imagemap **imagemaps;
-
- /** Browser window containing this document, or NULL if not open. */
- struct browser_window *bw;
-
- /** Frameset information */
- struct content_html_frames *frameset;
-
- /** Inline frame information */
- struct content_html_iframe *iframe;
-
- /** Content of type CONTENT_HTML containing this, or NULL if not an
- * object within a page. */
- struct html_content *page;
-
- /** Current drag type */
- html_drag_type drag_type;
- /** Widget capturing all mouse events */
- union html_drag_owner drag_owner;
-
- /** Current selection state */
- html_selection_type selection_type;
- /** Current selection owner */
- union html_selection_owner selection_owner;
-
- /** Current input focus target type */
- html_focus_type focus_type;
- /** Current input focus target */
- union html_focus_owner focus_owner;
-
- /** HTML content's own text selection object */
- struct selection sel;
-
- /** Open core-handled form SELECT menu,
- * or NULL if none currently open. */
- struct form_control *visible_select_menu;
-
- /** Context for free text search, or NULL if none */
- struct search_context *search;
- /** Search string or NULL */
- char *search_string;
-
-} html_content;
-
-/** Render padding and margin box outlines in html_redraw(). */
-extern bool html_redraw_debug;
-
-void html__redraw_a_box(html_content *html, struct box *box);
-
-/**
- * Set our drag status, and inform whatever owns the content
- *
- * \param html HTML content
- * \param drag_type Type of drag
- * \param drag_owner What owns the drag
- * \param rect Pointer movement bounds
- */
-void html_set_drag_type(html_content *html, html_drag_type drag_type,
- union html_drag_owner drag_owner, const struct rect *rect);
-
-/**
- * Set our selection status, and inform whatever owns the content
- *
- * \param html HTML content
- * \param selection_type Type of selection
- * \param selection_owner What owns the selection
- * \param read_only True iff selection is read only
- */
-void html_set_selection(html_content *html, html_selection_type selection_type,
- union html_selection_owner selection_owner, bool read_only);
-
-/**
- * Set our input focus, and inform whatever owns the content
- *
- * \param html HTML content
- * \param focus_type Type of input focus
- * \param focus_owner What owns the focus
- * \param hide_caret True iff caret to be hidden
- * \param x Carret x-coord rel to owner
- * \param y Carret y-coord rel to owner
- * \param height Carret height
- * \param clip Carret clip rect
- */
-void html_set_focus(html_content *html, html_focus_type focus_type,
- union html_focus_owner focus_owner, bool hide_caret,
- int x, int y, int height, const struct rect *clip);
-
-
-struct browser_window *html_get_browser_window(struct content *c);
-
-/**
- * Complete conversion of an HTML document
- *
- * \param htmlc Content to convert
- */
-void html_finish_conversion(html_content *htmlc);
-
-/**
- * Test if an HTML content conversion can begin
- *
- * \param htmlc html content to test
- * \return true iff the html content conversion can begin
- */
-bool html_can_begin_conversion(html_content *htmlc);
-
-/**
- * Begin conversion of an HTML document
- *
- * \param htmlc Content to convert
- */
-bool html_begin_conversion(html_content *htmlc);
-
-/* in render/html_redraw.c */
-bool html_redraw(struct content *c, struct content_redraw_data *data,
- const struct rect *clip, const struct redraw_context *ctx);
-
-/* in render/html_redraw_border.c */
-bool html_redraw_borders(struct box *box, int x_parent, int y_parent,
- int p_width, int p_height, const struct rect *clip, float scale,
- const struct redraw_context *ctx);
-
-bool html_redraw_inline_borders(struct box *box, struct rect b,
- const struct rect *clip, float scale, bool first, bool last,
- const struct redraw_context *ctx);
-
-/* in render/html_interaction.c */
-void html_mouse_track(struct content *c, struct browser_window *bw,
- browser_mouse_state mouse, int x, int y);
-void html_mouse_action(struct content *c, struct browser_window *bw,
- browser_mouse_state mouse, int x, int y);
-bool html_keypress(struct content *c, uint32_t key);
-void html_overflow_scroll_callback(void *client_data,
- struct scrollbar_msg_data *scrollbar_data);
-void html_search(struct content *c, void *context,
- search_flags_t flags, const char *string);
-void html_search_clear(struct content *c);
-
-
-/* in render/html_script.c */
-dom_hubbub_error html_process_script(void *ctx, dom_node *node);
-
-/**
- * Attempt script execution for defer and async scripts
- *
- * execute scripts using algorithm found in:
- * http://www.whatwg.org/specs/web-apps/current-work/multipage/scripting-1.html#the-script-element
- *
- * \param htmlc html content.
- * \return NSERROR_OK error code.
- */
-nserror html_script_exec(html_content *htmlc);
-
-/**
- * Free all script resources and references for a html content.
- *
- * \param htmlc html content.
- * \return NSERROR_OK or error code.
- */
-nserror html_script_free(html_content *htmlc);
-
-/**
- * Ensure the html content javascript context is invalidated.
- *
- * \param htmlc html content.
- * \return NSERROR_OK or error code.
- */
-nserror html_script_invalidate_ctx(html_content *htmlc);
-
-/* in render/html_forms.c */
-struct form *html_forms_get_forms(const char *docenc, dom_html_document *doc);
-struct form_control *html_forms_get_control_for_node(struct form *forms,
- dom_node *node);
-
-/* in render/html_css.c */
-nserror html_css_init(void);
-void html_css_fini(void);
-
-/**
- * Initialise core stylesheets for a content
- *
- * \param c content structure to update
- * \return nserror
- */
-nserror html_css_new_stylesheets(html_content *c);
-nserror html_css_quirks_stylesheets(html_content *c);
-nserror html_css_free_stylesheets(html_content *html);
-
-bool html_css_process_link(html_content *htmlc, dom_node *node);
-bool html_css_process_style(html_content *htmlc, dom_node *node);
-bool html_css_update_style(html_content *c, dom_node *style);
-
-nserror html_css_new_selection_context(html_content *c,
- css_select_ctx **ret_select_ctx);
-
-/* in render/html_css_fetcher.c */
-/**
- * Register the fetcher for the pseudo x-ns-css scheme.
- *
- * \return NSERROR_OK on successful registration or error code on failure.
- */
-nserror html_css_fetcher_register(void);
-nserror html_css_fetcher_add_item(dom_string *data, nsurl *base_url,
- uint32_t *key);
-
-/* in render/html_object.c */
-
-/**
- * Start a fetch for an object required by a page.
- *
- * \param c content of type CONTENT_HTML
- * \param url URL of object to fetch (copied)
- * \param box box that will contain the object
- * \param permitted_types bitmap of acceptable types
- * \param available_width estimate of width of object
- * \param available_height estimate of height of object
- * \param background this is a background image
- * \return true on success, false on memory exhaustion
- */
-bool html_fetch_object(html_content *c, nsurl *url, struct box *box,
- content_type permitted_types,
- int available_width, int available_height,
- bool background);
-
-nserror html_object_free_objects(html_content *html);
-nserror html_object_close_objects(html_content *html);
-nserror html_object_open_objects(html_content *html, struct browser_window *bw);
-nserror html_object_abort_objects(html_content *html);
-
-/* Events */
-/**
- * Construct an event and fire it at the DOM
- *
- */
-bool fire_dom_event(dom_string *type, dom_node *target,
- bool bubbles, bool cancelable);
-
-/* Useful dom_string pointers */
-struct dom_string;
-
-extern struct dom_string *html_dom_string_map;
-extern struct dom_string *html_dom_string_id;
-extern struct dom_string *html_dom_string_name;
-extern struct dom_string *html_dom_string_area;
-extern struct dom_string *html_dom_string_a;
-extern struct dom_string *html_dom_string_nohref;
-extern struct dom_string *html_dom_string_href;
-extern struct dom_string *html_dom_string_target;
-extern struct dom_string *html_dom_string_shape;
-extern struct dom_string *html_dom_string_default;
-extern struct dom_string *html_dom_string_rect;
-extern struct dom_string *html_dom_string_rectangle;
-extern struct dom_string *html_dom_string_coords;
-extern struct dom_string *html_dom_string_circle;
-extern struct dom_string *html_dom_string_poly;
-extern struct dom_string *html_dom_string_polygon;
-extern struct dom_string *html_dom_string_text_javascript;
-extern struct dom_string *html_dom_string_type;
-extern struct dom_string *html_dom_string_src;
-
-#endif
-
-
diff --git a/render/html_object.c b/render/html_object.c
deleted file mode 100644
index 74e4bf0f3..000000000
--- a/render/html_object.c
+++ /dev/null
@@ -1,729 +0,0 @@
-/*
- * Copyright 2013 Vincent Sanders <vince@netsurf-browser.org>
- *
- * This file is part of NetSurf, http://www.netsurf-browser.org/
- *
- * NetSurf is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * NetSurf is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-/** \file
- * Processing for html content object operations.
- */
-
-#include <assert.h>
-#include <ctype.h>
-#include <stdint.h>
-#include <string.h>
-#include <strings.h>
-#include <stdlib.h>
-#include <nsutils/time.h>
-
-#include "utils/corestrings.h"
-#include "utils/config.h"
-#include "utils/log.h"
-#include "utils/nsoption.h"
-#include "netsurf/content.h"
-#include "netsurf/misc.h"
-#include "content/hlcache.h"
-#include "css/utils.h"
-#include "desktop/scrollbar.h"
-#include "desktop/gui_internal.h"
-
-#include "render/box.h"
-#include "render/html_internal.h"
-
-/* break reference loop */
-static void html_object_refresh(void *p);
-
-/**
- * Retrieve objects used by HTML document
- *
- * \param h Content to retrieve objects from
- * \param n Pointer to location to receive number of objects
- * \return Pointer to list of objects
- */
-struct content_html_object *html_get_objects(hlcache_handle *h, unsigned int *n)
-{
- html_content *c = (html_content *) hlcache_handle_get_content(h);
-
- assert(c != NULL);
- assert(n != NULL);
-
- *n = c->num_objects;
-
- return c->object_list;
-}
-
-/**
- * Handle object fetching or loading failure.
- *
- * \param box box containing object which failed to load
- * \param content document of type CONTENT_HTML
- * \param background the object was the background image for the box
- */
-
-static void
-html_object_failed(struct box *box, html_content *content, bool background)
-{
- /* Nothing to do */
- return;
-}
-
-/**
- * Update a box whose content has completed rendering.
- */
-
-static void
-html_object_done(struct box *box,
- hlcache_handle *object,
- bool background)
-{
- struct box *b;
-
- if (background) {
- box->background = object;
- return;
- }
-
- box->object = object;
-
- /* Normalise the box type, now it has been replaced. */
- switch (box->type) {
- case BOX_TABLE:
- box->type = BOX_BLOCK;
- break;
- default:
- /* TODO: Any other box types need mapping? */
- break;
- }
-
- if (!(box->flags & REPLACE_DIM)) {
- /* invalidate parent min, max widths */
- for (b = box; b; b = b->parent)
- b->max_width = UNKNOWN_MAX_WIDTH;
-
- /* delete any clones of this box */
- while (box->next && (box->next->flags & CLONE)) {
- /* box_free_box(box->next); */
- box->next = box->next->next;
- }
- }
-}
-
-/**
- * Callback for hlcache_handle_retrieve() for objects.
- */
-
-static nserror
-html_object_callback(hlcache_handle *object,
- const hlcache_event *event,
- void *pw)
-{
- struct content_html_object *o = pw;
- html_content *c = (html_content *) o->parent;
- int x, y;
- struct box *box;
-
- box = o->box;
- if (box == NULL &&
- event->type != CONTENT_MSG_ERROR &&
- event->type != CONTENT_MSG_ERRORCODE) {
- return NSERROR_OK;
- }
-
- switch (event->type) {
- case CONTENT_MSG_LOADING:
- if (c->base.status != CONTENT_STATUS_LOADING && c->bw != NULL)
- content_open(object,
- c->bw, &c->base,
- box->object_params);
- break;
-
- case CONTENT_MSG_READY:
- if (content_can_reformat(object)) {
- /* TODO: avoid knowledge of box internals here */
- content_reformat(object, false,
- box->max_width != UNKNOWN_MAX_WIDTH ?
- box->width : 0,
- box->max_width != UNKNOWN_MAX_WIDTH ?
- box->height : 0);
-
- /* Adjust parent content for new object size */
- html_object_done(box, object, o->background);
- if (c->base.status == CONTENT_STATUS_READY ||
- c->base.status == CONTENT_STATUS_DONE)
- content__reformat(&c->base, false,
- c->base.available_width,
- c->base.height);
- }
- break;
-
- case CONTENT_MSG_DONE:
- c->base.active--;
- NSLOG(netsurf, INFO, "%d fetches active", c->base.active);
-
- html_object_done(box, object, o->background);
-
- if (c->base.status != CONTENT_STATUS_LOADING &&
- box->flags & REPLACE_DIM) {
- union content_msg_data data;
-
- if (!box_visible(box))
- break;
-
- box_coords(box, &x, &y);
-
- data.redraw.x = x + box->padding[LEFT];
- data.redraw.y = y + box->padding[TOP];
- data.redraw.width = box->width;
- data.redraw.height = box->height;
- data.redraw.full_redraw = true;
-
- content_broadcast(&c->base, CONTENT_MSG_REDRAW, &data);
- }
- break;
-
- case CONTENT_MSG_ERRORCODE:
- case CONTENT_MSG_ERROR:
- hlcache_handle_release(object);
-
- o->content = NULL;
-
- if (box != NULL) {
- c->base.active--;
- NSLOG(netsurf, INFO, "%d fetches active",
- c->base.active);
-
- content_add_error(&c->base, "?", 0);
- html_object_failed(box, c, o->background);
- }
- break;
-
- case CONTENT_MSG_REDRAW:
- if (c->base.status != CONTENT_STATUS_LOADING) {
- union content_msg_data data = event->data;
-
- if (!box_visible(box))
- break;
-
- box_coords(box, &x, &y);
-
- if (object == box->background) {
- /* Redraw request is for background */
- css_fixed hpos = 0, vpos = 0;
- css_unit hunit = CSS_UNIT_PX;
- css_unit vunit = CSS_UNIT_PX;
- int width = box->padding[LEFT] + box->width +
- box->padding[RIGHT];
- int height = box->padding[TOP] + box->height +
- box->padding[BOTTOM];
- int t, h, l, w;
-
- /* Need to know background-position */
- css_computed_background_position(box->style,
- &hpos, &hunit, &vpos, &vunit);
-
- w = content_get_width(box->background);
- if (hunit == CSS_UNIT_PCT) {
- l = (width - w) * hpos / INTTOFIX(100);
- } else {
- l = FIXTOINT(nscss_len2px(&c->len_ctx,
- hpos, hunit,
- box->style));
- }
-
- h = content_get_height(box->background);
- if (vunit == CSS_UNIT_PCT) {
- t = (height - h) * vpos / INTTOFIX(100);
- } else {
- t = FIXTOINT(nscss_len2px(&c->len_ctx,
- vpos, vunit,
- box->style));
- }
-
- /* Redraw area depends on background-repeat */
- switch (css_computed_background_repeat(
- box->style)) {
- case CSS_BACKGROUND_REPEAT_REPEAT:
- data.redraw.x = 0;
- data.redraw.y = 0;
- data.redraw.width = box->width;
- data.redraw.height = box->height;
- break;
-
- case CSS_BACKGROUND_REPEAT_REPEAT_X:
- data.redraw.x = 0;
- data.redraw.y += t;
- data.redraw.width = box->width;
- break;
-
- case CSS_BACKGROUND_REPEAT_REPEAT_Y:
- data.redraw.x += l;
- data.redraw.y = 0;
- data.redraw.height = box->height;
- break;
-
- case CSS_BACKGROUND_REPEAT_NO_REPEAT:
- data.redraw.x += l;
- data.redraw.y += t;
- break;
-
- default:
- break;
- }
-
- data.redraw.object_width = box->width;
- data.redraw.object_height = box->height;
-
- /* Add offset to box */
- data.redraw.x += x;
- data.redraw.y += y;
- data.redraw.object_x += x;
- data.redraw.object_y += y;
-
- content_broadcast(&c->base,
- CONTENT_MSG_REDRAW, &data);
- break;
-
- } else {
- /* Non-background case */
- if (hlcache_handle_get_content(object) ==
- event->data.redraw.object) {
-
- int w = content_get_width(object);
- int h = content_get_height(object);
-
- if (w != 0) {
- data.redraw.x =
- data.redraw.x *
- box->width / w;
- data.redraw.width =
- data.redraw.width *
- box->width / w;
- }
-
- if (h != 0) {
- data.redraw.y =
- data.redraw.y *
- box->height / h;
- data.redraw.height =
- data.redraw.height *
- box->height / h;
- }
-
- data.redraw.object_width = box->width;
- data.redraw.object_height = box->height;
- }
-
- data.redraw.x += x + box->padding[LEFT];
- data.redraw.y += y + box->padding[TOP];
- data.redraw.object_x += x + box->padding[LEFT];
- data.redraw.object_y += y + box->padding[TOP];
- }
-
- content_broadcast(&c->base, CONTENT_MSG_REDRAW, &data);
- }
- break;
-
- case CONTENT_MSG_REFRESH:
- if (content_get_type(object) == CONTENT_HTML) {
- /* only for HTML objects */
- guit->misc->schedule(event->data.delay * 1000,
- html_object_refresh, o);
- }
-
- break;
-
- case CONTENT_MSG_LINK:
- /* Don't care about favicons that aren't on top level content */
- break;
-
- case CONTENT_MSG_GETCTX:
- *(event->data.jscontext) = NULL;
- break;
-
- case CONTENT_MSG_SCROLL:
- if (box->scroll_x != NULL)
- scrollbar_set(box->scroll_x, event->data.scroll.x0,
- false);
- if (box->scroll_y != NULL)
- scrollbar_set(box->scroll_y, event->data.scroll.y0,
- false);
- break;
-
- case CONTENT_MSG_DRAGSAVE:
- {
- union content_msg_data msg_data;
- if (event->data.dragsave.content == NULL)
- msg_data.dragsave.content = object;
- else
- msg_data.dragsave.content =
- event->data.dragsave.content;
-
- content_broadcast(&c->base, CONTENT_MSG_DRAGSAVE, &msg_data);
- }
- break;
-
- case CONTENT_MSG_SAVELINK:
- case CONTENT_MSG_POINTER:
- case CONTENT_MSG_SELECTMENU:
- case CONTENT_MSG_GADGETCLICK:
- /* These messages are for browser window layer.
- * we're not interested, so pass them on. */
- content_broadcast(&c->base, event->type, &event->data);
- break;
-
- case CONTENT_MSG_CARET:
- {
- union html_focus_owner focus_owner;
- focus_owner.content = box;
-
- switch (event->data.caret.type) {
- case CONTENT_CARET_REMOVE:
- case CONTENT_CARET_HIDE:
- html_set_focus(c, HTML_FOCUS_CONTENT, focus_owner,
- true, 0, 0, 0, NULL);
- break;
- case CONTENT_CARET_SET_POS:
- html_set_focus(c, HTML_FOCUS_CONTENT, focus_owner,
- false, event->data.caret.pos.x,
- event->data.caret.pos.y,
- event->data.caret.pos.height,
- event->data.caret.pos.clip);
- break;
- }
- }
- break;
-
- case CONTENT_MSG_DRAG:
- {
- html_drag_type drag_type = HTML_DRAG_NONE;
- union html_drag_owner drag_owner;
- drag_owner.content = box;
-
- switch (event->data.drag.type) {
- case CONTENT_DRAG_NONE:
- drag_type = HTML_DRAG_NONE;
- drag_owner.no_owner = true;
- break;
- case CONTENT_DRAG_SCROLL:
- drag_type = HTML_DRAG_CONTENT_SCROLL;
- break;
- case CONTENT_DRAG_SELECTION:
- drag_type = HTML_DRAG_CONTENT_SELECTION;
- break;
- }
- html_set_drag_type(c, drag_type, drag_owner,
- event->data.drag.rect);
- }
- break;
-
- case CONTENT_MSG_SELECTION:
- {
- html_selection_type sel_type;
- union html_selection_owner sel_owner;
-
- if (event->data.selection.selection) {
- sel_type = HTML_SELECTION_CONTENT;
- sel_owner.content = box;
- } else {
- sel_type = HTML_SELECTION_NONE;
- sel_owner.none = true;
- }
- html_set_selection(c, sel_type, sel_owner,
- event->data.selection.read_only);
- }
- break;
-
- default:
- break;
- }
-
- if (c->base.status == CONTENT_STATUS_READY &&
- c->base.active == 0 &&
- (event->type == CONTENT_MSG_LOADING ||
- event->type == CONTENT_MSG_DONE ||
- event->type == CONTENT_MSG_ERROR ||
- event->type == CONTENT_MSG_ERRORCODE)) {
- /* all objects have arrived */
- content__reformat(&c->base, false, c->base.available_width,
- c->base.height);
- content_set_done(&c->base);
- } else if (nsoption_bool(incremental_reflow) &&
- event->type == CONTENT_MSG_DONE &&
- box != NULL &&
- !(box->flags & REPLACE_DIM) &&
- (c->base.status == CONTENT_STATUS_READY ||
- c->base.status == CONTENT_STATUS_DONE)) {
- /* 1) the configuration option to reflow pages while
- * objects are fetched is set
- * 2) an object is newly fetched & converted,
- * 3) the box's dimensions need to change due to being replaced
- * 4) the object's parent HTML is ready for reformat,
- */
- uint64_t ms_now;
- nsu_getmonotonic_ms(&ms_now);
- if (ms_now > c->base.reformat_time) {
- /* The time since the previous reformat is
- * more than the configured minimum time
- * between reformats so reformat the page to
- * display newly fetched objects
- */
- content__reformat(&c->base,
- false,
- c->base.available_width,
- c->base.height);
- }
- }
-
- return NSERROR_OK;
-}
-
-/**
- * Start a fetch for an object required by a page, replacing an existing object.
- *
- * \param object Object to replace
- * \param url URL of object to fetch (copied)
- * \return true on success, false on memory exhaustion
- */
-
-static bool html_replace_object(struct content_html_object *object, nsurl *url)
-{
- html_content *c;
- hlcache_child_context child;
- html_content *page;
- nserror error;
-
- assert(object != NULL);
- assert(object->box != NULL);
-
- c = (html_content *) object->parent;
-
- child.charset = c->encoding;
- child.quirks = c->base.quirks;
-
- if (object->content != NULL) {
- /* remove existing object */
- if (content_get_status(object->content) != CONTENT_STATUS_DONE) {
- c->base.active--;
- NSLOG(netsurf, INFO, "%d fetches active",
- c->base.active);
- }
-
- hlcache_handle_release(object->content);
- object->content = NULL;
-
- object->box->object = NULL;
- }
-
- /* initialise fetch */
- error = hlcache_handle_retrieve(url, HLCACHE_RETRIEVE_SNIFF_TYPE,
- content_get_url(&c->base), NULL,
- html_object_callback, object, &child,
- object->permitted_types,
- &object->content);
-
- if (error != NSERROR_OK)
- return false;
-
- for (page = c; page != NULL; page = page->page) {
- page->base.active++;
- NSLOG(netsurf, INFO, "%d fetches active", c->base.active);
-
- page->base.status = CONTENT_STATUS_READY;
- }
-
- return true;
-}
-
-/**
- * schedule callback for object refresh
- */
-
-static void html_object_refresh(void *p)
-{
- struct content_html_object *object = p;
- nsurl *refresh_url;
-
- assert(content_get_type(object->content) == CONTENT_HTML);
-
- refresh_url = content_get_refresh_url(object->content);
-
- /* Ignore if refresh URL has gone
- * (may happen if fetch errored) */
- if (refresh_url == NULL)
- return;
-
- content_invalidate_reuse_data(object->content);
-
- if (!html_replace_object(object, refresh_url)) {
- /** \todo handle memory exhaustion */
- }
-}
-
-nserror html_object_open_objects(html_content *html, struct browser_window *bw)
-{
- struct content_html_object *object, *next;
-
- for (object = html->object_list; object != NULL; object = next) {
- next = object->next;
-
- if (object->content == NULL || object->box == NULL)
- continue;
-
- if (content_get_type(object->content) == CONTENT_NONE)
- continue;
-
- content_open(object->content,
- bw,
- &html->base,
- object->box->object_params);
- }
- return NSERROR_OK;
-}
-
-nserror html_object_abort_objects(html_content *htmlc)
-{
- struct content_html_object *object;
-
- for (object = htmlc->object_list;
- object != NULL;
- object = object->next) {
- if (object->content == NULL)
- continue;
-
- switch (content_get_status(object->content)) {
- case CONTENT_STATUS_DONE:
- /* already loaded: do nothing */
- break;
-
- case CONTENT_STATUS_READY:
- hlcache_handle_abort(object->content);
- /* Active count will be updated when
- * html_object_callback receives
- * CONTENT_MSG_DONE from this object
- */
- break;
-
- default:
- hlcache_handle_abort(object->content);
- hlcache_handle_release(object->content);
- object->content = NULL;
- if (object->box != NULL) {
- htmlc->base.active--;
- NSLOG(netsurf, INFO, "%d fetches active",
- htmlc->base.active);
- }
- break;
-
- }
- }
-
- return NSERROR_OK;
-}
-
-nserror html_object_close_objects(html_content *html)
-{
- struct content_html_object *object, *next;
-
- for (object = html->object_list; object != NULL; object = next) {
- next = object->next;
-
- if (object->content == NULL || object->box == NULL)
- continue;
-
- if (content_get_type(object->content) == CONTENT_NONE)
- continue;
-
- if (content_get_type(object->content) == CONTENT_HTML) {
- guit->misc->schedule(-1, html_object_refresh, object);
- }
-
- content_close(object->content);
- }
- return NSERROR_OK;
-}
-
-nserror html_object_free_objects(html_content *html)
-{
- while (html->object_list != NULL) {
- struct content_html_object *victim = html->object_list;
-
- if (victim->content != NULL) {
- NSLOG(netsurf, INFO, "object %p", victim->content);
-
- if (content_get_type(victim->content) == CONTENT_HTML) {
- guit->misc->schedule(-1, html_object_refresh, victim);
- }
- hlcache_handle_release(victim->content);
- }
-
- html->object_list = victim->next;
- free(victim);
- }
- return NSERROR_OK;
-}
-
-
-
-/* exported interface documented in render/html_internal.h */
-bool html_fetch_object(html_content *c, nsurl *url, struct box *box,
- content_type permitted_types,
- int available_width, int available_height,
- bool background)
-{
- struct content_html_object *object;
- hlcache_child_context child;
- nserror error;
-
- /* If we've already been aborted, don't bother attempting the fetch */
- if (c->aborted)
- return true;
-
- child.charset = c->encoding;
- child.quirks = c->base.quirks;
-
- object = calloc(1, sizeof(struct content_html_object));
- if (object == NULL) {
- return false;
- }
-
- object->parent = (struct content *) c;
- object->next = NULL;
- object->content = NULL;
- object->box = box;
- object->permitted_types = permitted_types;
- object->background = background;
-
- error = hlcache_handle_retrieve(url,
- HLCACHE_RETRIEVE_SNIFF_TYPE,
- content_get_url(&c->base), NULL,
- html_object_callback, object, &child,
- object->permitted_types, &object->content);
- if (error != NSERROR_OK) {
- free(object);
- return error != NSERROR_NOMEM;
- }
-
- /* add to content object list */
- object->next = c->object_list;
- c->object_list = object;
-
- c->num_objects++;
- if (box != NULL) {
- c->base.active++;
- NSLOG(netsurf, INFO, "%d fetches active", c->base.active);
- }
-
- return true;
-}
diff --git a/render/html_redraw.c b/render/html_redraw.c
deleted file mode 100644
index 9a97e5ec5..000000000
--- a/render/html_redraw.c
+++ /dev/null
@@ -1,1951 +0,0 @@
-/*
- * Copyright 2004-2008 James Bursa <bursa@users.sourceforge.net>
- * Copyright 2004-2007 John M Bell <jmb202@ecs.soton.ac.uk>
- * Copyright 2004-2007 Richard Wilson <info@tinct.net>
- * Copyright 2005-2006 Adrian Lees <adrianl@users.sourceforge.net>
- * Copyright 2006 Rob Kendrick <rjek@netsurf-browser.org>
- * Copyright 2008 Michael Drake <tlsa@netsurf-browser.org>
- * Copyright 2009 Paul Blokus <paul_pl@users.sourceforge.net>
- *
- * This file is part of NetSurf, http://www.netsurf-browser.org/
- *
- * NetSurf is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * NetSurf is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-/**
- * \file
- *
- * Redrawing CONTENT_HTML implementation.
- */
-
-#include "utils/config.h"
-#include <assert.h>
-#include <stdbool.h>
-#include <stdlib.h>
-#include <string.h>
-#include <math.h>
-#include <dom/dom.h>
-
-#include "utils/log.h"
-#include "utils/messages.h"
-#include "utils/utils.h"
-#include "utils/nsoption.h"
-#include "netsurf/content.h"
-#include "netsurf/browser_window.h"
-#include "netsurf/plotters.h"
-#include "netsurf/bitmap.h"
-#include "netsurf/layout.h"
-#include "content/content_protected.h"
-#include "css/utils.h"
-#include "desktop/selection.h"
-#include "desktop/print.h"
-#include "desktop/scrollbar.h"
-#include "desktop/textarea.h"
-#include "desktop/gui_internal.h"
-
-#include "render/box.h"
-#include "render/font.h"
-#include "render/form_internal.h"
-#include "render/html_internal.h"
-#include "render/layout.h"
-#include "render/search.h"
-
-
-bool html_redraw_debug = false;
-
-/**
- * Determine if a box has a background that needs drawing
- *
- * \param box Box to consider
- * \return True if box has a background, false otherwise.
- */
-static bool html_redraw_box_has_background(struct box *box)
-{
- if (box->background != NULL)
- return true;
-
- if (box->style != NULL) {
- css_color colour;
-
- css_computed_background_color(box->style, &colour);
-
- if (nscss_color_is_transparent(colour) == false)
- return true;
- }
-
- return false;
-}
-
-/**
- * Find the background box for a box
- *
- * \param box Box to find background box for
- * \return Pointer to background box, or NULL if there is none
- */
-static struct box *html_redraw_find_bg_box(struct box *box)
-{
- /* Thanks to backwards compatibility, CSS defines the following:
- *
- * + If the box is for the root element and it has a background,
- * use that (and then process the body box with no special case)
- * + If the box is for the root element and it has no background,
- * then use the background (if any) from the body element as if
- * it were specified on the root. Then, when the box for the body
- * element is processed, ignore the background.
- * + For any other box, just use its own styling.
- */
- if (box->parent == NULL) {
- /* Root box */
- if (html_redraw_box_has_background(box))
- return box;
-
- /* No background on root box: consider body box, if any */
- if (box->children != NULL) {
- if (html_redraw_box_has_background(box->children))
- return box->children;
- }
- } else if (box->parent != NULL && box->parent->parent == NULL) {
- /* Body box: only render background if root has its own */
- if (html_redraw_box_has_background(box) &&
- html_redraw_box_has_background(box->parent))
- return box;
- } else {
- /* Any other box */
- if (html_redraw_box_has_background(box))
- return box;
- }
-
- return NULL;
-}
-
-/**
- * Redraw a short text string, complete with highlighting
- * (for selection/search)
- *
- * \param utf8_text pointer to UTF-8 text string
- * \param utf8_len length of string, in bytes
- * \param offset byte offset within textual representation
- * \param space width of space that follows string (0 = no space)
- * \param fstyle text style to use (pass text size unscaled)
- * \param x x ordinate at which to plot text
- * \param y y ordinate at which to plot text
- * \param clip pointer to current clip rectangle
- * \param height height of text string
- * \param scale current display scale (1.0 = 100%)
- * \param excluded exclude this text string from the selection
- * \param c Content being redrawn.
- * \param sel Selection context
- * \param search Search context
- * \param ctx current redraw context
- * \return true iff successful and redraw should proceed
- */
-
-bool
-text_redraw(const char *utf8_text,
- size_t utf8_len,
- size_t offset,
- int space,
- const plot_font_style_t *fstyle,
- int x,
- int y,
- const struct rect *clip,
- int height,
- float scale,
- bool excluded,
- struct content *c,
- const struct selection *sel,
- struct search_context *search,
- const struct redraw_context *ctx)
-{
- bool highlighted = false;
- plot_font_style_t plot_fstyle = *fstyle;
- nserror res;
-
- /* Need scaled text size to pass to plotters */
- plot_fstyle.size *= scale;
-
- /* is this box part of a selection? */
- if (!excluded && ctx->interactive == true) {
- unsigned len = utf8_len + (space ? 1 : 0);
- unsigned start_idx;
- unsigned end_idx;
-
- /* first try the browser window's current selection */
- if (selection_defined(sel) && selection_highlighted(sel,
- offset, offset + len,
- &start_idx, &end_idx)) {
- highlighted = true;
- }
-
- /* what about the current search operation, if any? */
- if (!highlighted && (search != NULL) &&
- search_term_highlighted(c,
- offset, offset + len,
- &start_idx, &end_idx,
- search)) {
- highlighted = true;
- }
-
- /* \todo make search terms visible within selected text */
- if (highlighted) {
- struct rect r;
- unsigned endtxt_idx = end_idx;
- bool clip_changed = false;
- bool text_visible = true;
- int startx, endx;
- plot_style_t pstyle_fill_hback = *plot_style_fill_white;
- plot_font_style_t fstyle_hback = plot_fstyle;
-
- if (end_idx > utf8_len) {
- /* adjust for trailing space, not present in
- * utf8_text */
- assert(end_idx == utf8_len + 1);
- endtxt_idx = utf8_len;
- }
-
- res = guit->layout->width(fstyle,
- utf8_text, start_idx,
- &startx);
- if (res != NSERROR_OK) {
- startx = 0;
- }
-
- res = guit->layout->width(fstyle,
- utf8_text, endtxt_idx,
- &endx);
- if (res != NSERROR_OK) {
- endx = 0;
- }
-
- /* is there a trailing space that should be highlighted
- * as well? */
- if (end_idx > utf8_len) {
- endx += space;
- }
-
- if (scale != 1.0) {
- startx *= scale;
- endx *= scale;
- }
-
- /* draw any text preceding highlighted portion */
- if ((start_idx > 0) &&
- (ctx->plot->text(ctx,
- &plot_fstyle,
- x,
- y + (int)(height * 0.75 * scale),
- utf8_text,
- start_idx) != NSERROR_OK))
- return false;
-
- pstyle_fill_hback.fill_colour = fstyle->foreground;
-
- /* highlighted portion */
- r.x0 = x + startx;
- r.y0 = y;
- r.x1 = x + endx;
- r.y1 = y + height * scale;
- res = ctx->plot->rectangle(ctx, &pstyle_fill_hback, &r);
- if (res != NSERROR_OK) {
- return false;
- }
-
- if (start_idx > 0) {
- int px0 = max(x + startx, clip->x0);
- int px1 = min(x + endx, clip->x1);
-
- if (px0 < px1) {
- r.x0 = px0;
- r.y0 = clip->y0;
- r.x1 = px1;
- r.y1 = clip->y1;
- res = ctx->plot->clip(ctx, &r);
- if (res != NSERROR_OK) {
- return false;
- }
-
- clip_changed = true;
- } else {
- text_visible = false;
- }
- }
-
- fstyle_hback.background =
- pstyle_fill_hback.fill_colour;
- fstyle_hback.foreground = colour_to_bw_furthest(
- pstyle_fill_hback.fill_colour);
-
- if (text_visible &&
- (ctx->plot->text(ctx,
- &fstyle_hback,
- x,
- y + (int)(height * 0.75 * scale),
- utf8_text,
- endtxt_idx) != NSERROR_OK)) {
- return false;
- }
-
- /* draw any text succeeding highlighted portion */
- if (endtxt_idx < utf8_len) {
- int px0 = max(x + endx, clip->x0);
- if (px0 < clip->x1) {
-
- r.x0 = px0;
- r.y0 = clip->y0;
- r.x1 = clip->x1;
- r.y1 = clip->y1;
- res = ctx->plot->clip(ctx, &r);
- if (res != NSERROR_OK) {
- return false;
- }
-
- clip_changed = true;
-
- res = ctx->plot->text(ctx,
- &plot_fstyle,
- x,
- y + (int)(height * 0.75 * scale),
- utf8_text,
- utf8_len);
- if (res != NSERROR_OK) {
- return false;
- }
- }
- }
-
- if (clip_changed &&
- (ctx->plot->clip(ctx, clip) != NSERROR_OK)) {
- return false;
- }
- }
- }
-
- if (!highlighted) {
- res = ctx->plot->text(ctx,
- &plot_fstyle,
- x,
- y + (int) (height * 0.75 * scale),
- utf8_text,
- utf8_len);
- if (res != NSERROR_OK) {
- return false;
- }
- }
- return true;
-}
-
-
-/**
- * Plot a checkbox.
- *
- * \param x left coordinate
- * \param y top coordinate
- * \param width dimensions of checkbox
- * \param height dimensions of checkbox
- * \param selected the checkbox is selected
- * \param ctx current redraw context
- * \return true if successful, false otherwise
- */
-
-static bool html_redraw_checkbox(int x, int y, int width, int height,
- bool selected, const struct redraw_context *ctx)
-{
- double z;
- nserror res;
- struct rect rect;
-
- z = width * 0.15;
- if (z == 0) {
- z = 1;
- }
-
- rect.x0 = x;
- rect.y0 = y ;
- rect.x1 = x + width;
- rect.y1 = y + height;
- res = ctx->plot->rectangle(ctx, plot_style_fill_wbasec, &rect);
- if (res != NSERROR_OK) {
- return false;
- }
-
- /* dark line across top */
- rect.y1 = y;
- res = ctx->plot->line(ctx, plot_style_stroke_darkwbasec, &rect);
- if (res != NSERROR_OK) {
- return false;
- }
-
- /* dark line across left */
- rect.x1 = x;
- rect.y1 = y + height;
- res = ctx->plot->line(ctx, plot_style_stroke_darkwbasec, &rect);
- if (res != NSERROR_OK) {
- return false;
- }
-
- /* light line across right */
- rect.x0 = x + width;
- rect.x1 = x + width;
- res = ctx->plot->line(ctx, plot_style_stroke_lightwbasec, &rect);
- if (res != NSERROR_OK) {
- return false;
- }
-
- /* light line across bottom */
- rect.x0 = x;
- rect.y0 = y + height;
- res = ctx->plot->line(ctx, plot_style_stroke_lightwbasec, &rect);
- if (res != NSERROR_OK) {
- return false;
- }
-
- if (selected) {
- if (width < 12 || height < 12) {
- /* render a solid box instead of a tick */
- rect.x0 = x + z + z;
- rect.y0 = y + z + z;
- rect.x1 = x + width - z;
- rect.y1 = y + height - z;
- res = ctx->plot->rectangle(ctx, plot_style_fill_wblobc, &rect);
- if (res != NSERROR_OK) {
- return false;
- }
- } else {
- /* render a tick, as it'll fit comfortably */
- rect.x0 = x + width - z;
- rect.y0 = y + z;
- rect.x1 = x + (z * 3);
- rect.y1 = y + height - z;
- res = ctx->plot->line(ctx, plot_style_stroke_wblobc, &rect);
- if (res != NSERROR_OK) {
- return false;
- }
-
- rect.x0 = x + (z * 3);
- rect.y0 = y + height - z;
- rect.x1 = x + z + z;
- rect.y1 = y + (height / 2);
- res = ctx->plot->line(ctx, plot_style_stroke_wblobc, &rect);
- if (res != NSERROR_OK) {
- return false;
- }
- }
- }
- return true;
-}
-
-
-/**
- * Plot a radio icon.
- *
- * \param x left coordinate
- * \param y top coordinate
- * \param width dimensions of radio icon
- * \param height dimensions of radio icon
- * \param selected the radio icon is selected
- * \param ctx current redraw context
- * \return true if successful, false otherwise
- */
-static bool html_redraw_radio(int x, int y, int width, int height,
- bool selected, const struct redraw_context *ctx)
-{
- nserror res;
-
- /* plot background of radio button */
- res = ctx->plot->disc(ctx,
- plot_style_fill_wbasec,
- x + width * 0.5,
- y + height * 0.5,
- width * 0.5 - 1);
- if (res != NSERROR_OK) {
- return false;
- }
-
- /* plot dark arc */
- res = ctx->plot->arc(ctx,
- plot_style_fill_darkwbasec,
- x + width * 0.5,
- y + height * 0.5,
- width * 0.5 - 1,
- 45,
- 225);
- if (res != NSERROR_OK) {
- return false;
- }
-
- /* plot light arc */
- res = ctx->plot->arc(ctx,
- plot_style_fill_lightwbasec,
- x + width * 0.5,
- y + height * 0.5,
- width * 0.5 - 1,
- 225,
- 45);
- if (res != NSERROR_OK) {
- return false;
- }
-
- if (selected) {
- /* plot selection blob */
- res = ctx->plot->disc(ctx,
- plot_style_fill_wblobc,
- x + width * 0.5,
- y + height * 0.5,
- width * 0.3 - 1);
- if (res != NSERROR_OK) {
- return false;
- }
- }
-
- return true;
-}
-
-
-/**
- * Plot a file upload input.
- *
- * \param x left coordinate
- * \param y top coordinate
- * \param width dimensions of input
- * \param height dimensions of input
- * \param box box of input
- * \param scale scale for redraw
- * \param background_colour current background colour
- * \param len_ctx Length conversion context
- * \param ctx current redraw context
- * \return true if successful, false otherwise
- */
-
-static bool html_redraw_file(int x, int y, int width, int height,
- struct box *box, float scale, colour background_colour,
- const nscss_len_ctx *len_ctx,
- const struct redraw_context *ctx)
-{
- int text_width;
- const char *text;
- size_t length;
- plot_font_style_t fstyle;
- nserror res;
-
- font_plot_style_from_css(len_ctx, box->style, &fstyle);
- fstyle.background = background_colour;
-
- if (box->gadget->value) {
- text = box->gadget->value;
- } else {
- text = messages_get("Form_Drop");
- }
- length = strlen(text);
-
- res = guit->layout->width(&fstyle, text, length, &text_width);
- if (res != NSERROR_OK) {
- return false;
- }
- text_width *= scale;
- if (width < text_width + 8) {
- x = x + width - text_width - 4;
- } else {
- x = x + 4;
- }
-
- res = ctx->plot->text(ctx, &fstyle, x, y + height * 0.75, text, length);
- if (res != NSERROR_OK) {
- return false;
- }
- return true;
-}
-
-
-/**
- * Plot background images.
- *
- * The reason for the presence of \a background is the backwards compatibility
- * mess that is backgrounds on &lt;body&gt;. The background will be drawn relative
- * to \a box, using the background information contained within \a background.
- *
- * \param x coordinate of box
- * \param y coordinate of box
- * \param box box to draw background image of
- * \param scale scale for redraw
- * \param clip current clip rectangle
- * \param background_colour current background colour
- * \param background box containing background details (usually \a box)
- * \param len_ctx Length conversion context
- * \param ctx current redraw context
- * \return true if successful, false otherwise
- */
-
-static bool html_redraw_background(int x, int y, struct box *box, float scale,
- const struct rect *clip, colour *background_colour,
- struct box *background,
- const nscss_len_ctx *len_ctx,
- const struct redraw_context *ctx)
-{
- bool repeat_x = false;
- bool repeat_y = false;
- bool plot_colour = true;
- bool plot_content;
- bool clip_to_children = false;
- struct box *clip_box = box;
- int ox = x, oy = y;
- int width, height;
- css_fixed hpos = 0, vpos = 0;
- css_unit hunit = CSS_UNIT_PX, vunit = CSS_UNIT_PX;
- struct box *parent;
- struct rect r = *clip;
- css_color bgcol;
- plot_style_t pstyle_fill_bg = {
- .fill_type = PLOT_OP_TYPE_SOLID,
- .fill_colour = *background_colour,
- };
- nserror res;
-
- if (ctx->background_images == false)
- return true;
-
- plot_content = (background->background != NULL);
-
- if (plot_content) {
- if (!box->parent) {
- /* Root element, special case:
- * background origin calc. is based on margin box */
- x -= box->margin[LEFT] * scale;
- y -= box->margin[TOP] * scale;
- width = box->margin[LEFT] + box->padding[LEFT] +
- box->width + box->padding[RIGHT] +
- box->margin[RIGHT];
- height = box->margin[TOP] + box->padding[TOP] +
- box->height + box->padding[BOTTOM] +
- box->margin[BOTTOM];
- } else {
- width = box->padding[LEFT] + box->width +
- box->padding[RIGHT];
- height = box->padding[TOP] + box->height +
- box->padding[BOTTOM];
- }
- /* handle background-repeat */
- switch (css_computed_background_repeat(background->style)) {
- case CSS_BACKGROUND_REPEAT_REPEAT:
- repeat_x = repeat_y = true;
- /* optimisation: only plot the colour if
- * bitmap is not opaque */
- plot_colour = !content_get_opaque(background->background);
- break;
-
- case CSS_BACKGROUND_REPEAT_REPEAT_X:
- repeat_x = true;
- break;
-
- case CSS_BACKGROUND_REPEAT_REPEAT_Y:
- repeat_y = true;
- break;
-
- case CSS_BACKGROUND_REPEAT_NO_REPEAT:
- break;
-
- default:
- break;
- }
-
- /* handle background-position */
- css_computed_background_position(background->style,
- &hpos, &hunit, &vpos, &vunit);
- if (hunit == CSS_UNIT_PCT) {
- x += (width -
- content_get_width(background->background)) *
- scale * FIXTOFLT(hpos) / 100.;
- } else {
- x += (int) (FIXTOFLT(nscss_len2px(len_ctx, hpos, hunit,
- background->style)) * scale);
- }
-
- if (vunit == CSS_UNIT_PCT) {
- y += (height -
- content_get_height(background->background)) *
- scale * FIXTOFLT(vpos) / 100.;
- } else {
- y += (int) (FIXTOFLT(nscss_len2px(len_ctx, vpos, vunit,
- background->style)) * scale);
- }
- }
-
- /* special case for table rows as their background needs
- * to be clipped to all the cells */
- if (box->type == BOX_TABLE_ROW) {
- css_fixed h = 0, v = 0;
- css_unit hu = CSS_UNIT_PX, vu = CSS_UNIT_PX;
-
- for (parent = box->parent;
- ((parent) && (parent->type != BOX_TABLE));
- parent = parent->parent);
- assert(parent && (parent->style));
-
- css_computed_border_spacing(parent->style, &h, &hu, &v, &vu);
-
- clip_to_children = (h > 0) || (v > 0);
-
- if (clip_to_children)
- clip_box = box->children;
- }
-
- for (; clip_box; clip_box = clip_box->next) {
- /* clip to child boxes if needed */
- if (clip_to_children) {
- assert(clip_box->type == BOX_TABLE_CELL);
-
- /* update clip.* to the child cell */
- r.x0 = ox + (clip_box->x * scale);
- r.y0 = oy + (clip_box->y * scale);
- r.x1 = r.x0 + (clip_box->padding[LEFT] +
- clip_box->width +
- clip_box->padding[RIGHT]) * scale;
- r.y1 = r.y0 + (clip_box->padding[TOP] +
- clip_box->height +
- clip_box->padding[BOTTOM]) * scale;
-
- if (r.x0 < clip->x0) r.x0 = clip->x0;
- if (r.y0 < clip->y0) r.y0 = clip->y0;
- if (r.x1 > clip->x1) r.x1 = clip->x1;
- if (r.y1 > clip->y1) r.y1 = clip->y1;
-
- css_computed_background_color(clip_box->style, &bgcol);
-
- /* <td> attributes override <tr> */
- /* if the background content is opaque there
- * is no need to plot underneath it.
- */
- if ((r.x0 >= r.x1) ||
- (r.y0 >= r.y1) ||
- (nscss_color_is_transparent(bgcol) == false) ||
- ((clip_box->background != NULL) &&
- content_get_opaque(clip_box->background)))
- continue;
- }
-
- /* plot the background colour */
- css_computed_background_color(background->style, &bgcol);
-
- if (nscss_color_is_transparent(bgcol) == false) {
- *background_colour = nscss_color_to_ns(bgcol);
- pstyle_fill_bg.fill_colour = *background_colour;
- if (plot_colour) {
- res = ctx->plot->rectangle(ctx, &pstyle_fill_bg, &r);
- if (res != NSERROR_OK) {
- return false;
- }
- }
- }
- /* and plot the image */
- if (plot_content) {
- width = content_get_width(background->background);
- height = content_get_height(background->background);
-
- /* ensure clip area only as large as required */
- if (!repeat_x) {
- if (r.x0 < x)
- r.x0 = x;
- if (r.x1 > x + width * scale)
- r.x1 = x + width * scale;
- }
- if (!repeat_y) {
- if (r.y0 < y)
- r.y0 = y;
- if (r.y1 > y + height * scale)
- r.y1 = y + height * scale;
- }
- /* valid clipping rectangles only */
- if ((r.x0 < r.x1) && (r.y0 < r.y1)) {
- struct content_redraw_data bg_data;
-
- res = ctx->plot->clip(ctx, &r);
- if (res != NSERROR_OK) {
- return false;
- }
-
- bg_data.x = x;
- bg_data.y = y;
- bg_data.width = ceilf(width * scale);
- bg_data.height = ceilf(height * scale);
- bg_data.background_colour = *background_colour;
- bg_data.scale = scale;
- bg_data.repeat_x = repeat_x;
- bg_data.repeat_y = repeat_y;
-
- /* We just continue if redraw fails */
- content_redraw(background->background,
- &bg_data, &r, ctx);
- }
- }
-
- /* only <tr> rows being clipped to child boxes loop */
- if (!clip_to_children)
- return true;
- }
- return true;
-}
-
-
-/**
- * Plot an inline's background and/or background image.
- *
- * \param x coordinate of box
- * \param y coordinate of box
- * \param box BOX_INLINE which created the background
- * \param scale scale for redraw
- * \param clip coordinates of clip rectangle
- * \param b coordinates of border edge rectangle
- * \param first true if this is the first rectangle associated with the inline
- * \param last true if this is the last rectangle associated with the inline
- * \param background_colour updated to current background colour if plotted
- * \param len_ctx Length conversion context
- * \param ctx current redraw context
- * \return true if successful, false otherwise
- */
-
-static bool html_redraw_inline_background(int x, int y, struct box *box,
- float scale, const struct rect *clip, struct rect b,
- bool first, bool last, colour *background_colour,
- const nscss_len_ctx *len_ctx,
- const struct redraw_context *ctx)
-{
- struct rect r = *clip;
- bool repeat_x = false;
- bool repeat_y = false;
- bool plot_colour = true;
- bool plot_content;
- css_fixed hpos = 0, vpos = 0;
- css_unit hunit = CSS_UNIT_PX, vunit = CSS_UNIT_PX;
- css_color bgcol;
- plot_style_t pstyle_fill_bg = {
- .fill_type = PLOT_OP_TYPE_SOLID,
- .fill_colour = *background_colour,
- };
- nserror res;
-
- plot_content = (box->background != NULL);
-
- if (html_redraw_printing && nsoption_bool(remove_backgrounds))
- return true;
-
- if (plot_content) {
- /* handle background-repeat */
- switch (css_computed_background_repeat(box->style)) {
- case CSS_BACKGROUND_REPEAT_REPEAT:
- repeat_x = repeat_y = true;
- /* optimisation: only plot the colour if
- * bitmap is not opaque
- */
- plot_colour = !content_get_opaque(box->background);
- break;
-
- case CSS_BACKGROUND_REPEAT_REPEAT_X:
- repeat_x = true;
- break;
-
- case CSS_BACKGROUND_REPEAT_REPEAT_Y:
- repeat_y = true;
- break;
-
- case CSS_BACKGROUND_REPEAT_NO_REPEAT:
- break;
-
- default:
- break;
- }
-
- /* handle background-position */
- css_computed_background_position(box->style,
- &hpos, &hunit, &vpos, &vunit);
- if (hunit == CSS_UNIT_PCT) {
- x += (b.x1 - b.x0 -
- content_get_width(box->background) *
- scale) * FIXTOFLT(hpos) / 100.;
-
- if (!repeat_x && ((hpos < 2 && !first) ||
- (hpos > 98 && !last))){
- plot_content = false;
- }
- } else {
- x += (int) (FIXTOFLT(nscss_len2px(len_ctx, hpos, hunit,
- box->style)) * scale);
- }
-
- if (vunit == CSS_UNIT_PCT) {
- y += (b.y1 - b.y0 -
- content_get_height(box->background) *
- scale) * FIXTOFLT(vpos) / 100.;
- } else {
- y += (int) (FIXTOFLT(nscss_len2px(len_ctx, vpos, vunit,
- box->style)) * scale);
- }
- }
-
- /* plot the background colour */
- css_computed_background_color(box->style, &bgcol);
-
- if (nscss_color_is_transparent(bgcol) == false) {
- *background_colour = nscss_color_to_ns(bgcol);
- pstyle_fill_bg.fill_colour = *background_colour;
-
- if (plot_colour) {
- res = ctx->plot->rectangle(ctx, &pstyle_fill_bg, &r);
- if (res != NSERROR_OK) {
- return false;
- }
- }
- }
- /* and plot the image */
- if (plot_content) {
- int width = content_get_width(box->background);
- int height = content_get_height(box->background);
-
- if (!repeat_x) {
- if (r.x0 < x)
- r.x0 = x;
- if (r.x1 > x + width * scale)
- r.x1 = x + width * scale;
- }
- if (!repeat_y) {
- if (r.y0 < y)
- r.y0 = y;
- if (r.y1 > y + height * scale)
- r.y1 = y + height * scale;
- }
- /* valid clipping rectangles only */
- if ((r.x0 < r.x1) && (r.y0 < r.y1)) {
- struct content_redraw_data bg_data;
-
- res = ctx->plot->clip(ctx, &r);
- if (res != NSERROR_OK) {
- return false;
- }
-
- bg_data.x = x;
- bg_data.y = y;
- bg_data.width = ceilf(width * scale);
- bg_data.height = ceilf(height * scale);
- bg_data.background_colour = *background_colour;
- bg_data.scale = scale;
- bg_data.repeat_x = repeat_x;
- bg_data.repeat_y = repeat_y;
-
- /* We just continue if redraw fails */
- content_redraw(box->background, &bg_data, &r, ctx);
- }
- }
-
- return true;
-}
-
-
-/**
- * Plot text decoration for an inline box.
- *
- * \param box box to plot decorations for, of type BOX_INLINE
- * \param x x coordinate of parent of box
- * \param y y coordinate of parent of box
- * \param scale scale for redraw
- * \param colour colour for decorations
- * \param ratio position of line as a ratio of line height
- * \param ctx current redraw context
- * \return true if successful, false otherwise
- */
-
-static bool
-html_redraw_text_decoration_inline(struct box *box,
- int x, int y,
- float scale,
- colour colour,
- float ratio,
- const struct redraw_context *ctx)
-{
- struct box *c;
- plot_style_t plot_style_box = {
- .stroke_type = PLOT_OP_TYPE_SOLID,
- .stroke_colour = colour,
- };
- nserror res;
- struct rect rect;
-
- for (c = box->next;
- c && c != box->inline_end;
- c = c->next) {
- if (c->type != BOX_TEXT) {
- continue;
- }
- rect.x0 = (x + c->x) * scale;
- rect.y0 = (y + c->y + c->height * ratio) * scale;
- rect.x1 = (x + c->x + c->width) * scale;
- rect.y1 = (y + c->y + c->height * ratio) * scale;
- res = ctx->plot->line(ctx, &plot_style_box, &rect);
- if (res != NSERROR_OK) {
- return false;
- }
- }
- return true;
-}
-
-
-/**
- * Plot text decoration for an non-inline box.
- *
- * \param box box to plot decorations for, of type other than BOX_INLINE
- * \param x x coordinate of box
- * \param y y coordinate of box
- * \param scale scale for redraw
- * \param colour colour for decorations
- * \param ratio position of line as a ratio of line height
- * \param ctx current redraw context
- * \return true if successful, false otherwise
- */
-
-static bool
-html_redraw_text_decoration_block(struct box *box,
- int x, int y,
- float scale,
- colour colour,
- float ratio,
- const struct redraw_context *ctx)
-{
- struct box *c;
- plot_style_t plot_style_box = {
- .stroke_type = PLOT_OP_TYPE_SOLID,
- .stroke_colour = colour,
- };
- nserror res;
- struct rect rect;
-
- /* draw through text descendants */
- for (c = box->children; c; c = c->next) {
- if (c->type == BOX_TEXT) {
- rect.x0 = (x + c->x) * scale;
- rect.y0 = (y + c->y + c->height * ratio) * scale;
- rect.x1 = (x + c->x + c->width) * scale;
- rect.y1 = (y + c->y + c->height * ratio) * scale;
- res = ctx->plot->line(ctx, &plot_style_box, &rect);
- if (res != NSERROR_OK) {
- return false;
- }
- } else if ((c->type == BOX_INLINE_CONTAINER) || (c->type == BOX_BLOCK)) {
- if (!html_redraw_text_decoration_block(c,
- x + c->x, y + c->y,
- scale, colour, ratio, ctx))
- return false;
- }
- }
- return true;
-}
-
-
-/**
- * Plot text decoration for a box.
- *
- * \param box box to plot decorations for
- * \param x_parent x coordinate of parent of box
- * \param y_parent y coordinate of parent of box
- * \param scale scale for redraw
- * \param background_colour current background colour
- * \param ctx current redraw context
- * \return true if successful, false otherwise
- */
-
-static bool html_redraw_text_decoration(struct box *box,
- int x_parent, int y_parent, float scale,
- colour background_colour, const struct redraw_context *ctx)
-{
- static const enum css_text_decoration_e decoration[] = {
- CSS_TEXT_DECORATION_UNDERLINE, CSS_TEXT_DECORATION_OVERLINE,
- CSS_TEXT_DECORATION_LINE_THROUGH };
- static const float line_ratio[] = { 0.9, 0.1, 0.5 };
- colour fgcol;
- unsigned int i;
- css_color col;
-
- css_computed_color(box->style, &col);
- fgcol = nscss_color_to_ns(col);
-
- /* antialias colour for under/overline */
- if (html_redraw_printing == false)
- fgcol = blend_colour(background_colour, fgcol);
-
- if (box->type == BOX_INLINE) {
- if (!box->inline_end)
- return true;
- for (i = 0; i != NOF_ELEMENTS(decoration); i++)
- if (css_computed_text_decoration(box->style) &
- decoration[i])
- if (!html_redraw_text_decoration_inline(box,
- x_parent, y_parent, scale,
- fgcol, line_ratio[i], ctx))
- return false;
- } else {
- for (i = 0; i != NOF_ELEMENTS(decoration); i++)
- if (css_computed_text_decoration(box->style) &
- decoration[i])
- if (!html_redraw_text_decoration_block(box,
- x_parent + box->x,
- y_parent + box->y,
- scale,
- fgcol, line_ratio[i], ctx))
- return false;
- }
-
- return true;
-}
-
-
-/**
- * Redraw the text content of a box, possibly partially highlighted
- * because the text has been selected, or matches a search operation.
- *
- * \param html The html content to redraw text within.
- * \param box box with text content
- * \param x x co-ord of box
- * \param y y co-ord of box
- * \param clip current clip rectangle
- * \param scale current scale setting (1.0 = 100%)
- * \param current_background_color
- * \param ctx current redraw context
- * \return true iff successful and redraw should proceed
- */
-
-static bool html_redraw_text_box(const html_content *html, struct box *box,
- int x, int y, const struct rect *clip, float scale,
- colour current_background_color,
- const struct redraw_context *ctx)
-{
- bool excluded = (box->object != NULL);
- plot_font_style_t fstyle;
-
- font_plot_style_from_css(&html->len_ctx, box->style, &fstyle);
- fstyle.background = current_background_color;
-
- if (!text_redraw(box->text, box->length, box->byte_offset,
- box->space, &fstyle, x, y,
- clip, box->height, scale, excluded,
- (struct content *)html, &html->sel,
- html->search, ctx))
- return false;
-
- return true;
-}
-
-bool html_redraw_box(const html_content *html, struct box *box,
- int x_parent, int y_parent,
- const struct rect *clip, float scale,
- colour current_background_color,
- const struct redraw_context *ctx);
-
-/**
- * Draw the various children of a box.
- *
- * \param html html content
- * \param box box to draw children of
- * \param x_parent coordinate of parent box
- * \param y_parent coordinate of parent box
- * \param clip clip rectangle
- * \param scale scale for redraw
- * \param current_background_color background colour under this box
- * \param ctx current redraw context
- * \return true if successful, false otherwise
- */
-
-static bool html_redraw_box_children(const html_content *html, struct box *box,
- int x_parent, int y_parent,
- const struct rect *clip, float scale,
- colour current_background_color,
- const struct redraw_context *ctx)
-{
- struct box *c;
-
- for (c = box->children; c; c = c->next) {
-
- if (c->type != BOX_FLOAT_LEFT && c->type != BOX_FLOAT_RIGHT)
- if (!html_redraw_box(html, c,
- x_parent + box->x -
- scrollbar_get_offset(box->scroll_x),
- y_parent + box->y -
- scrollbar_get_offset(box->scroll_y),
- clip, scale, current_background_color,
- ctx))
- return false;
- }
- for (c = box->float_children; c; c = c->next_float)
- if (!html_redraw_box(html, c,
- x_parent + box->x -
- scrollbar_get_offset(box->scroll_x),
- y_parent + box->y -
- scrollbar_get_offset(box->scroll_y),
- clip, scale, current_background_color,
- ctx))
- return false;
-
- return true;
-}
-
-/**
- * Recursively draw a box.
- *
- * \param html html content
- * \param box box to draw
- * \param x_parent coordinate of parent box
- * \param y_parent coordinate of parent box
- * \param clip clip rectangle
- * \param scale scale for redraw
- * \param current_background_color background colour under this box
- * \param ctx current redraw context
- * \return true if successful, false otherwise
- *
- * x, y, clip_[xy][01] are in target coordinates.
- */
-
-bool html_redraw_box(const html_content *html, struct box *box,
- int x_parent, int y_parent,
- const struct rect *clip, const float scale,
- colour current_background_color,
- const struct redraw_context *ctx)
-{
- const struct plotter_table *plot = ctx->plot;
- int x, y;
- int width, height;
- int padding_left, padding_top, padding_width, padding_height;
- int border_left, border_top, border_right, border_bottom;
- struct rect r;
- struct rect rect;
- int x_scrolled, y_scrolled;
- struct box *bg_box = NULL;
- bool has_x_scroll, has_y_scroll;
- css_computed_clip_rect css_rect;
- enum css_overflow_e overflow_x = CSS_OVERFLOW_VISIBLE;
- enum css_overflow_e overflow_y = CSS_OVERFLOW_VISIBLE;
-
- if (html_redraw_printing && (box->flags & PRINTED))
- return true;
-
- if (box->style != NULL) {
- overflow_x = css_computed_overflow_x(box->style);
- overflow_y = css_computed_overflow_y(box->style);
- }
-
- /* avoid trivial FP maths */
- if (scale == 1.0) {
- x = x_parent + box->x;
- y = y_parent + box->y;
- width = box->width;
- height = box->height;
- padding_left = box->padding[LEFT];
- padding_top = box->padding[TOP];
- padding_width = padding_left + box->width + box->padding[RIGHT];
- padding_height = padding_top + box->height +
- box->padding[BOTTOM];
- border_left = box->border[LEFT].width;
- border_top = box->border[TOP].width;
- border_right = box->border[RIGHT].width;
- border_bottom = box->border[BOTTOM].width;
- } else {
- x = (x_parent + box->x) * scale;
- y = (y_parent + box->y) * scale;
- width = box->width * scale;
- height = box->height * scale;
- /* left and top padding values are normally zero,
- * so avoid trivial FP maths */
- padding_left = box->padding[LEFT] ? box->padding[LEFT] * scale
- : 0;
- padding_top = box->padding[TOP] ? box->padding[TOP] * scale
- : 0;
- padding_width = (box->padding[LEFT] + box->width +
- box->padding[RIGHT]) * scale;
- padding_height = (box->padding[TOP] + box->height +
- box->padding[BOTTOM]) * scale;
- border_left = box->border[LEFT].width * scale;
- border_top = box->border[TOP].width * scale;
- border_right = box->border[RIGHT].width * scale;
- border_bottom = box->border[BOTTOM].width * scale;
- }
-
- /* calculate rectangle covering this box and descendants */
- if (box->style && overflow_x != CSS_OVERFLOW_VISIBLE &&
- box->parent != NULL) {
- /* box contents clipped to box size */
- r.x0 = x - border_left;
- r.x1 = x + padding_width + border_right;
- } else {
- /* box contents can hang out of the box; use descendant box */
- if (scale == 1.0) {
- r.x0 = x + box->descendant_x0;
- r.x1 = x + box->descendant_x1 + 1;
- } else {
- r.x0 = x + box->descendant_x0 * scale;
- r.x1 = x + box->descendant_x1 * scale + 1;
- }
- if (!box->parent) {
- /* root element */
- int margin_left, margin_right;
- if (scale == 1.0) {
- margin_left = box->margin[LEFT];
- margin_right = box->margin[RIGHT];
- } else {
- margin_left = box->margin[LEFT] * scale;
- margin_right = box->margin[RIGHT] * scale;
- }
- r.x0 = x - border_left - margin_left < r.x0 ?
- x - border_left - margin_left : r.x0;
- r.x1 = x + padding_width + border_right +
- margin_right > r.x1 ?
- x + padding_width + border_right +
- margin_right : r.x1;
- }
- }
-
- /* calculate rectangle covering this box and descendants */
- if (box->style && overflow_y != CSS_OVERFLOW_VISIBLE &&
- box->parent != NULL) {
- /* box contents clipped to box size */
- r.y0 = y - border_top;
- r.y1 = y + padding_height + border_bottom;
- } else {
- /* box contents can hang out of the box; use descendant box */
- if (scale == 1.0) {
- r.y0 = y + box->descendant_y0;
- r.y1 = y + box->descendant_y1 + 1;
- } else {
- r.y0 = y + box->descendant_y0 * scale;
- r.y1 = y + box->descendant_y1 * scale + 1;
- }
- if (!box->parent) {
- /* root element */
- int margin_top, margin_bottom;
- if (scale == 1.0) {
- margin_top = box->margin[TOP];
- margin_bottom = box->margin[BOTTOM];
- } else {
- margin_top = box->margin[TOP] * scale;
- margin_bottom = box->margin[BOTTOM] * scale;
- }
- r.y0 = y - border_top - margin_top < r.y0 ?
- y - border_top - margin_top : r.y0;
- r.y1 = y + padding_height + border_bottom +
- margin_bottom > r.y1 ?
- y + padding_height + border_bottom +
- margin_bottom : r.y1;
- }
- }
-
- /* return if the rectangle is completely outside the clip rectangle */
- if (clip->y1 < r.y0 || r.y1 < clip->y0 ||
- clip->x1 < r.x0 || r.x1 < clip->x0)
- return true;
-
- /*if the rectangle is under the page bottom but it can fit in a page,
- don't print it now*/
- if (html_redraw_printing) {
- if (r.y1 > html_redraw_printing_border) {
- if (r.y1 - r.y0 <= html_redraw_printing_border &&
- (box->type == BOX_TEXT ||
- box->type == BOX_TABLE_CELL
- || box->object || box->gadget)) {
- /*remember the highest of all points from the
- not printed elements*/
- if (r.y0 < html_redraw_printing_top_cropped)
- html_redraw_printing_top_cropped = r.y0;
- return true;
- }
- }
- else box->flags |= PRINTED; /*it won't be printed anymore*/
- }
-
- /* if visibility is hidden render children only */
- if (box->style && css_computed_visibility(box->style) ==
- CSS_VISIBILITY_HIDDEN) {
- if ((ctx->plot->group_start) &&
- (ctx->plot->group_start(ctx, "hidden box") != NSERROR_OK))
- return false;
- if (!html_redraw_box_children(html, box, x_parent, y_parent,
- &r, scale, current_background_color, ctx))
- return false;
- return ((!ctx->plot->group_end) || (ctx->plot->group_end(ctx) == NSERROR_OK));
- }
-
- if ((ctx->plot->group_start) &&
- (ctx->plot->group_start(ctx,"vis box") != NSERROR_OK)) {
- return false;
- }
-
- if (box->style != NULL &&
- css_computed_position(box->style) ==
- CSS_POSITION_ABSOLUTE &&
- css_computed_clip(box->style, &css_rect) ==
- CSS_CLIP_RECT) {
- /* We have an absolutly positioned box with a clip rect */
- if (css_rect.left_auto == false)
- r.x0 = x - border_left + FIXTOINT(nscss_len2px(
- &html->len_ctx,
- css_rect.left, css_rect.lunit,
- box->style));
-
- if (css_rect.top_auto == false)
- r.y0 = y - border_top + FIXTOINT(nscss_len2px(
- &html->len_ctx,
- css_rect.top, css_rect.tunit,
- box->style));
-
- if (css_rect.right_auto == false)
- r.x1 = x - border_left + FIXTOINT(nscss_len2px(
- &html->len_ctx,
- css_rect.right, css_rect.runit,
- box->style));
-
- if (css_rect.bottom_auto == false)
- r.y1 = y - border_top + FIXTOINT(nscss_len2px(
- &html->len_ctx,
- css_rect.bottom, css_rect.bunit,
- box->style));
-
- /* find intersection of clip rectangle and box */
- if (r.x0 < clip->x0) r.x0 = clip->x0;
- if (r.y0 < clip->y0) r.y0 = clip->y0;
- if (clip->x1 < r.x1) r.x1 = clip->x1;
- if (clip->y1 < r.y1) r.y1 = clip->y1;
- /* Nothing to do for invalid rectangles */
- if (r.x0 >= r.x1 || r.y0 >= r.y1)
- /* not an error */
- return ((!ctx->plot->group_end) ||
- (ctx->plot->group_end(ctx) == NSERROR_OK));
- /* clip to it */
- if (ctx->plot->clip(ctx, &r) != NSERROR_OK)
- return false;
-
- } else if (box->type == BOX_BLOCK || box->type == BOX_INLINE_BLOCK ||
- box->type == BOX_TABLE_CELL || box->object) {
- /* find intersection of clip rectangle and box */
- if (r.x0 < clip->x0) r.x0 = clip->x0;
- if (r.y0 < clip->y0) r.y0 = clip->y0;
- if (clip->x1 < r.x1) r.x1 = clip->x1;
- if (clip->y1 < r.y1) r.y1 = clip->y1;
- /* no point trying to draw 0-width/height boxes */
- if (r.x0 == r.x1 || r.y0 == r.y1)
- /* not an error */
- return ((!ctx->plot->group_end) ||
- (ctx->plot->group_end(ctx) == NSERROR_OK));
- /* clip to it */
- if (ctx->plot->clip(ctx, &r) != NSERROR_OK)
- return false;
- } else {
- /* clip box is fine, clip to it */
- r = *clip;
- if (ctx->plot->clip(ctx, &r) != NSERROR_OK)
- return false;
- }
-
- /* background colour and image for block level content and replaced
- * inlines */
-
- bg_box = html_redraw_find_bg_box(box);
-
- /* bg_box == NULL implies that this box should not have
- * its background rendered. Otherwise filter out linebreaks,
- * optimize away non-differing inlines, only plot background
- * for BOX_TEXT it's in an inline */
- if (bg_box && bg_box->type != BOX_BR &&
- bg_box->type != BOX_TEXT &&
- bg_box->type != BOX_INLINE_END &&
- (bg_box->type != BOX_INLINE || bg_box->object ||
- bg_box->flags & IFRAME || box->flags & REPLACE_DIM ||
- (bg_box->gadget != NULL &&
- (bg_box->gadget->type == GADGET_TEXTAREA ||
- bg_box->gadget->type == GADGET_TEXTBOX ||
- bg_box->gadget->type == GADGET_PASSWORD)))) {
- /* find intersection of clip box and border edge */
- struct rect p;
- p.x0 = x - border_left < r.x0 ? r.x0 : x - border_left;
- p.y0 = y - border_top < r.y0 ? r.y0 : y - border_top;
- p.x1 = x + padding_width + border_right < r.x1 ?
- x + padding_width + border_right : r.x1;
- p.y1 = y + padding_height + border_bottom < r.y1 ?
- y + padding_height + border_bottom : r.y1;
- if (!box->parent) {
- /* Root element, special case:
- * background covers margins too */
- int m_left, m_top, m_right, m_bottom;
- if (scale == 1.0) {
- m_left = box->margin[LEFT];
- m_top = box->margin[TOP];
- m_right = box->margin[RIGHT];
- m_bottom = box->margin[BOTTOM];
- } else {
- m_left = box->margin[LEFT] * scale;
- m_top = box->margin[TOP] * scale;
- m_right = box->margin[RIGHT] * scale;
- m_bottom = box->margin[BOTTOM] * scale;
- }
- p.x0 = p.x0 - m_left < r.x0 ? r.x0 : p.x0 - m_left;
- p.y0 = p.y0 - m_top < r.y0 ? r.y0 : p.y0 - m_top;
- p.x1 = p.x1 + m_right < r.x1 ? p.x1 + m_right : r.x1;
- p.y1 = p.y1 + m_bottom < r.y1 ? p.y1 + m_bottom : r.y1;
- }
- /* valid clipping rectangles only */
- if ((p.x0 < p.x1) && (p.y0 < p.y1)) {
- /* plot background */
- if (!html_redraw_background(x, y, box, scale, &p,
- &current_background_color, bg_box,
- &html->len_ctx, ctx))
- return false;
- /* restore previous graphics window */
- if (ctx->plot->clip(ctx, &r) != NSERROR_OK)
- return false;
- }
- }
-
- /* borders for block level content and replaced inlines */
- if (box->style &&
- box->type != BOX_TEXT &&
- box->type != BOX_INLINE_END &&
- (box->type != BOX_INLINE || box->object ||
- box->flags & IFRAME || box->flags & REPLACE_DIM ||
- (box->gadget != NULL &&
- (box->gadget->type == GADGET_TEXTAREA ||
- box->gadget->type == GADGET_TEXTBOX ||
- box->gadget->type == GADGET_PASSWORD))) &&
- (border_top || border_right || border_bottom || border_left)) {
- if (!html_redraw_borders(box, x_parent, y_parent,
- padding_width, padding_height, &r,
- scale, ctx))
- return false;
- }
-
- /* backgrounds and borders for non-replaced inlines */
- if (box->style && box->type == BOX_INLINE && box->inline_end &&
- (html_redraw_box_has_background(box) ||
- border_top || border_right ||
- border_bottom || border_left)) {
- /* inline backgrounds and borders span other boxes and may
- * wrap onto separate lines */
- struct box *ib;
- struct rect b; /* border edge rectangle */
- struct rect p; /* clipped rect */
- bool first = true;
- int ib_x;
- int ib_y = y;
- int ib_p_width;
- int ib_b_left, ib_b_right;
-
- b.x0 = x - border_left;
- b.x1 = x + padding_width + border_right;
- b.y0 = y - border_top;
- b.y1 = y + padding_height + border_bottom;
-
- p.x0 = b.x0 < r.x0 ? r.x0 : b.x0;
- p.x1 = b.x1 < r.x1 ? b.x1 : r.x1;
- p.y0 = b.y0 < r.y0 ? r.y0 : b.y0;
- p.y1 = b.y1 < r.y1 ? b.y1 : r.y1;
- for (ib = box; ib; ib = ib->next) {
- /* to get extents of rectangle(s) associated with
- * inline, cycle though all boxes in inline, skipping
- * over floats */
- if (ib->type == BOX_FLOAT_LEFT ||
- ib->type == BOX_FLOAT_RIGHT)
- continue;
- if (scale == 1.0) {
- ib_x = x_parent + ib->x;
- ib_y = y_parent + ib->y;
- ib_p_width = ib->padding[LEFT] + ib->width +
- ib->padding[RIGHT];
- ib_b_left = ib->border[LEFT].width;
- ib_b_right = ib->border[RIGHT].width;
- } else {
- ib_x = (x_parent + ib->x) * scale;
- ib_y = (y_parent + ib->y) * scale;
- ib_p_width = (ib->padding[LEFT] + ib->width +
- ib->padding[RIGHT]) * scale;
- ib_b_left = ib->border[LEFT].width * scale;
- ib_b_right = ib->border[RIGHT].width * scale;
- }
-
- if ((ib->flags & NEW_LINE) && ib != box) {
- /* inline element has wrapped, plot background
- * and borders */
- if (!html_redraw_inline_background(
- x, y, box, scale, &p, b,
- first, false,
- &current_background_color,
- &html->len_ctx, ctx))
- return false;
- /* restore previous graphics window */
- if (ctx->plot->clip(ctx, &r) != NSERROR_OK)
- return false;
- if (!html_redraw_inline_borders(box, b, &r,
- scale, first, false, ctx))
- return false;
- /* reset coords */
- b.x0 = ib_x - ib_b_left;
- b.y0 = ib_y - border_top - padding_top;
- b.y1 = ib_y + padding_height - padding_top +
- border_bottom;
-
- p.x0 = b.x0 < r.x0 ? r.x0 : b.x0;
- p.y0 = b.y0 < r.y0 ? r.y0 : b.y0;
- p.y1 = b.y1 < r.y1 ? b.y1 : r.y1;
-
- first = false;
- }
-
- /* increase width for current box */
- b.x1 = ib_x + ib_p_width + ib_b_right;
- p.x1 = b.x1 < r.x1 ? b.x1 : r.x1;
-
- if (ib == box->inline_end)
- /* reached end of BOX_INLINE span */
- break;
- }
- /* plot background and borders for last rectangle of
- * the inline */
- if (!html_redraw_inline_background(x, ib_y, box, scale, &p, b,
- first, true, &current_background_color,
- &html->len_ctx, ctx))
- return false;
- /* restore previous graphics window */
- if (ctx->plot->clip(ctx, &r) != NSERROR_OK)
- return false;
- if (!html_redraw_inline_borders(box, b, &r, scale, first, true,
- ctx))
- return false;
-
- }
-
- /* Debug outlines */
- if (html_redraw_debug) {
- int margin_left, margin_right;
- int margin_top, margin_bottom;
- if (scale == 1.0) {
- /* avoid trivial fp maths */
- margin_left = box->margin[LEFT];
- margin_top = box->margin[TOP];
- margin_right = box->margin[RIGHT];
- margin_bottom = box->margin[BOTTOM];
- } else {
- margin_left = box->margin[LEFT] * scale;
- margin_top = box->margin[TOP] * scale;
- margin_right = box->margin[RIGHT] * scale;
- margin_bottom = box->margin[BOTTOM] * scale;
- }
- /* Content edge -- blue */
- rect.x0 = x + padding_left;
- rect.y0 = y + padding_top;
- rect.x1 = x + padding_left + width;
- rect.y1 = y + padding_top + height;
- if (ctx->plot->rectangle(ctx, plot_style_content_edge, &rect) != NSERROR_OK)
- return false;
-
- /* Padding edge -- red */
- rect.x0 = x;
- rect.y0 = y;
- rect.x1 = x + padding_width;
- rect.y1 = y + padding_height;
- if (ctx->plot->rectangle(ctx, plot_style_padding_edge, &rect) != NSERROR_OK)
- return false;
-
- /* Margin edge -- yellow */
- rect.x0 = x - border_left - margin_left;
- rect.y0 = y - border_top - margin_top;
- rect.x1 = x + padding_width + border_right + margin_right;
- rect.y1 = y + padding_height + border_bottom + margin_bottom;
- if (ctx->plot->rectangle(ctx, plot_style_margin_edge, &rect) != NSERROR_OK)
- return false;
- }
-
- /* clip to the padding edge for objects, or boxes with overflow hidden
- * or scroll, unless it's the root element */
- if (box->parent != NULL) {
- bool need_clip = false;
- if (box->object || box->flags & IFRAME ||
- (overflow_x != CSS_OVERFLOW_VISIBLE &&
- overflow_y != CSS_OVERFLOW_VISIBLE)) {
- r.x0 = x;
- r.y0 = y;
- r.x1 = x + padding_width;
- r.y1 = y + padding_height;
- if (r.x0 < clip->x0) r.x0 = clip->x0;
- if (r.y0 < clip->y0) r.y0 = clip->y0;
- if (clip->x1 < r.x1) r.x1 = clip->x1;
- if (clip->y1 < r.y1) r.y1 = clip->y1;
- if (r.x1 <= r.x0 || r.y1 <= r.y0) {
- return (!ctx->plot->group_end ||
- (ctx->plot->group_end(ctx) == NSERROR_OK));
- }
- need_clip = true;
-
- } else if (overflow_x != CSS_OVERFLOW_VISIBLE) {
- r.x0 = x;
- r.y0 = clip->y0;
- r.x1 = x + padding_width;
- r.y1 = clip->y1;
- if (r.x0 < clip->x0) r.x0 = clip->x0;
- if (clip->x1 < r.x1) r.x1 = clip->x1;
- if (r.x1 <= r.x0) {
- return (!ctx->plot->group_end ||
- (ctx->plot->group_end(ctx) == NSERROR_OK));
- }
- need_clip = true;
-
- } else if (overflow_y != CSS_OVERFLOW_VISIBLE) {
- r.x0 = clip->x0;
- r.y0 = y;
- r.x1 = clip->x1;
- r.y1 = y + padding_height;
- if (r.y0 < clip->y0) r.y0 = clip->y0;
- if (clip->y1 < r.y1) r.y1 = clip->y1;
- if (r.y1 <= r.y0) {
- return (!ctx->plot->group_end ||
- (ctx->plot->group_end(ctx) == NSERROR_OK));
- }
- need_clip = true;
- }
-
- if (need_clip &&
- (box->type == BOX_BLOCK ||
- box->type == BOX_INLINE_BLOCK ||
- box->type == BOX_TABLE_CELL || box->object)) {
- if (ctx->plot->clip(ctx, &r) != NSERROR_OK)
- return false;
- }
- }
-
- /* text decoration */
- if ((box->type != BOX_TEXT) &&
- box->style &&
- css_computed_text_decoration(box->style) != CSS_TEXT_DECORATION_NONE) {
- if (!html_redraw_text_decoration(box, x_parent, y_parent,
- scale, current_background_color, ctx))
- return false;
- }
-
- if (box->object && width != 0 && height != 0) {
- struct content_redraw_data obj_data;
-
- x_scrolled = x - scrollbar_get_offset(box->scroll_x) * scale;
- y_scrolled = y - scrollbar_get_offset(box->scroll_y) * scale;
-
- obj_data.x = x_scrolled + padding_left;
- obj_data.y = y_scrolled + padding_top;
- obj_data.width = width;
- obj_data.height = height;
- obj_data.background_colour = current_background_color;
- obj_data.scale = scale;
- obj_data.repeat_x = false;
- obj_data.repeat_y = false;
-
- if (content_get_type(box->object) == CONTENT_HTML) {
- obj_data.x /= scale;
- obj_data.y /= scale;
- }
-
- if (!content_redraw(box->object, &obj_data, &r, ctx)) {
- /* Show image fail */
- /* Unicode (U+FFFC) 'OBJECT REPLACEMENT CHARACTER' */
- const char *obj = "\xef\xbf\xbc";
- int obj_width;
- int obj_x = x + padding_left;
- nserror res;
-
- rect.x0 = x + padding_left;
- rect.y0 = y + padding_top;
- rect.x1 = x + padding_left + width - 1;
- rect.y1 = y + padding_top + height - 1;
- res = ctx->plot->rectangle(ctx, plot_style_broken_object, &rect);
- if (res != NSERROR_OK) {
- return false;
- }
-
- res = guit->layout->width(plot_fstyle_broken_object,
- obj,
- sizeof(obj) - 1,
- &obj_width);
- if (res != NSERROR_OK) {
- obj_x += 1;
- } else {
- obj_x += width / 2 - obj_width / 2;
- }
-
- if (ctx->plot->text(ctx,
- plot_fstyle_broken_object,
- obj_x, y + padding_top + (int)(height * 0.75),
- obj, sizeof(obj) - 1) != NSERROR_OK)
- return false;
- }
-
- } else if (box->iframe) {
- /* Offset is passed to browser window redraw unscaled */
- browser_window_redraw(box->iframe,
- (x + padding_left) / scale,
- (y + padding_top) / scale, &r, ctx);
-
- } else if (box->gadget && box->gadget->type == GADGET_CHECKBOX) {
- if (!html_redraw_checkbox(x + padding_left, y + padding_top,
- width, height, box->gadget->selected, ctx))
- return false;
-
- } else if (box->gadget && box->gadget->type == GADGET_RADIO) {
- if (!html_redraw_radio(x + padding_left, y + padding_top,
- width, height, box->gadget->selected, ctx))
- return false;
-
- } else if (box->gadget && box->gadget->type == GADGET_FILE) {
- if (!html_redraw_file(x + padding_left, y + padding_top,
- width, height, box, scale,
- current_background_color, &html->len_ctx, ctx))
- return false;
-
- } else if (box->gadget &&
- (box->gadget->type == GADGET_TEXTAREA ||
- box->gadget->type == GADGET_PASSWORD ||
- box->gadget->type == GADGET_TEXTBOX)) {
- textarea_redraw(box->gadget->data.text.ta, x, y,
- current_background_color, scale, &r, ctx);
-
- } else if (box->text) {
- if (!html_redraw_text_box(html, box, x, y, &r, scale,
- current_background_color, ctx))
- return false;
-
- } else {
- if (!html_redraw_box_children(html, box, x_parent, y_parent, &r,
- scale, current_background_color, ctx))
- return false;
- }
-
- if (box->type == BOX_BLOCK || box->type == BOX_INLINE_BLOCK ||
- box->type == BOX_TABLE_CELL || box->type == BOX_INLINE)
- if (ctx->plot->clip(ctx, clip) != NSERROR_OK)
- return false;
-
- /* list marker */
- if (box->list_marker) {
- if (!html_redraw_box(html, box->list_marker,
- x_parent + box->x -
- scrollbar_get_offset(box->scroll_x),
- y_parent + box->y -
- scrollbar_get_offset(box->scroll_y),
- clip, scale, current_background_color, ctx))
- return false;
- }
-
- /* scrollbars */
- if (((box->style && box->type != BOX_BR &&
- box->type != BOX_TABLE && box->type != BOX_INLINE &&
- (overflow_x == CSS_OVERFLOW_SCROLL ||
- overflow_x == CSS_OVERFLOW_AUTO ||
- overflow_y == CSS_OVERFLOW_SCROLL ||
- overflow_y == CSS_OVERFLOW_AUTO)) ||
- (box->object && content_get_type(box->object) ==
- CONTENT_HTML)) && box->parent != NULL) {
-
- has_x_scroll = box_hscrollbar_present(box);
- has_y_scroll = box_vscrollbar_present(box);
-
- if (!box_handle_scrollbars((struct content *)html,
- box, has_x_scroll, has_y_scroll))
- return false;
-
- if (box->scroll_x != NULL)
- scrollbar_redraw(box->scroll_x,
- x_parent + box->x,
- y_parent + box->y + box->padding[TOP] +
- box->height + box->padding[BOTTOM] -
- SCROLLBAR_WIDTH, clip, scale, ctx);
- if (box->scroll_y != NULL)
- scrollbar_redraw(box->scroll_y,
- x_parent + box->x + box->padding[LEFT] +
- box->width + box->padding[RIGHT] -
- SCROLLBAR_WIDTH,
- y_parent + box->y, clip, scale, ctx);
- }
-
- if (box->type == BOX_BLOCK || box->type == BOX_INLINE_BLOCK ||
- box->type == BOX_TABLE_CELL || box->type == BOX_INLINE) {
- if (ctx->plot->clip(ctx, clip) != NSERROR_OK)
- return false;
- }
-
- return ((!plot->group_end) || (ctx->plot->group_end(ctx) == NSERROR_OK));
-}
-
-/**
- * Draw a CONTENT_HTML using the current set of plotters (plot).
- *
- * \param c content of type CONTENT_HTML
- * \param data redraw data for this content redraw
- * \param clip current clip region
- * \param ctx current redraw context
- * \return true if successful, false otherwise
- *
- * x, y, clip_[xy][01] are in target coordinates.
- */
-
-bool html_redraw(struct content *c, struct content_redraw_data *data,
- const struct rect *clip, const struct redraw_context *ctx)
-{
- html_content *html = (html_content *) c;
- struct box *box;
- bool result = true;
- bool select, select_only;
- plot_style_t pstyle_fill_bg = {
- .fill_type = PLOT_OP_TYPE_SOLID,
- .fill_colour = data->background_colour,
- };
-
- box = html->layout;
- assert(box);
-
- /* The select menu needs special treating because, when opened, it
- * reaches beyond its layout box.
- */
- select = false;
- select_only = false;
- if (ctx->interactive && html->visible_select_menu != NULL) {
- struct form_control *control = html->visible_select_menu;
- select = true;
- /* check if the redraw rectangle is completely inside of the
- select menu */
- select_only = form_clip_inside_select_menu(control,
- data->scale, clip);
- }
-
- if (!select_only) {
- /* clear to background colour */
- result = (ctx->plot->clip(ctx, clip) == NSERROR_OK);
-
- if (html->background_colour != NS_TRANSPARENT)
- pstyle_fill_bg.fill_colour = html->background_colour;
-
- result &= (ctx->plot->rectangle(ctx, &pstyle_fill_bg, clip) == NSERROR_OK);
-
- result &= html_redraw_box(html, box, data->x, data->y, clip,
- data->scale, pstyle_fill_bg.fill_colour, ctx);
- }
-
- if (select) {
- int menu_x, menu_y;
- box = html->visible_select_menu->box;
- box_coords(box, &menu_x, &menu_y);
-
- menu_x -= box->border[LEFT].width;
- menu_y += box->height + box->border[BOTTOM].width +
- box->padding[BOTTOM] + box->padding[TOP];
- result &= form_redraw_select_menu(html->visible_select_menu,
- data->x + menu_x, data->y + menu_y,
- data->scale, clip, ctx);
- }
-
- return result;
-
-}
diff --git a/render/html_redraw_border.c b/render/html_redraw_border.c
deleted file mode 100644
index 07c503c41..000000000
--- a/render/html_redraw_border.c
+++ /dev/null
@@ -1,928 +0,0 @@
-/*
- * Copyright 2017 Vincent Sanders <vince@netsurf-browser.org>
- *
- * This file is part of NetSurf, http://www.netsurf-browser.org/
- *
- * NetSurf is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * NetSurf is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-/**
- * \file
- *
- * Redrawing CONTENT_HTML borders implementation.
- */
-
-#include <stdbool.h>
-#include <stdlib.h>
-
-#include "utils/log.h"
-#include "netsurf/plotters.h"
-#include "netsurf/css.h"
-
-#include "render/box.h"
-#include "render/html_internal.h"
-
-
-static plot_style_t plot_style_bdr = {
- .stroke_type = PLOT_OP_TYPE_DASH,
-};
-static plot_style_t plot_style_fillbdr = {
- .fill_type = PLOT_OP_TYPE_SOLID,
-};
-static plot_style_t plot_style_fillbdr_dark = {
- .fill_type = PLOT_OP_TYPE_SOLID,
-};
-static plot_style_t plot_style_fillbdr_light = {
- .fill_type = PLOT_OP_TYPE_SOLID,
-};
-static plot_style_t plot_style_fillbdr_ddark = {
- .fill_type = PLOT_OP_TYPE_SOLID,
-};
-static plot_style_t plot_style_fillbdr_dlight = {
- .fill_type = PLOT_OP_TYPE_SOLID,
-};
-
-
-static inline nserror
-plot_clipped_rectangle(const struct redraw_context *ctx,
- const plot_style_t *style,
- const struct rect *clip,
- struct rect *rect)
-{
- nserror res;
-
- rect->x0 = (clip->x0 > rect->x0) ? clip->x0 : rect->x0;
- rect->y0 = (clip->y0 > rect->y0) ? clip->y0 : rect->y0;
- rect->x1 = (clip->x1 < rect->x1) ? clip->x1 : rect->x1;
- rect->y1 = (clip->y1 < rect->y1) ? clip->y1 : rect->y1;
- if ((rect->x0 < rect->x1) && (rect->y0 < rect->y1)) {
- /* valid clip rectangles only */
- res = ctx->plot->rectangle(ctx, style, rect);
- } else {
- res = NSERROR_OK;
- }
- return res;
-}
-
-
-/**
- * Draw one border.
- *
- * \param side index of border side (TOP, RIGHT, BOTTOM, LEFT)
- * \param p array of precomputed border vertices
- * \param c colour for border
- * \param style border line style
- * \param thickness border thickness
- * \param rectangular whether border is rectangular
- * \param clip cliping area for redrawing border.
- * \param ctx current redraw context
- * \return NSERROR_OK if successful otherwise appropriate error code
- */
-static nserror
-html_redraw_border_plot(const int side,
- const int *p,
- colour c,
- enum css_border_style_e style,
- int thickness,
- bool rectangular,
- const struct rect *clip,
- const struct redraw_context *ctx)
-{
- int z[8]; /* Vertices of border part */
- unsigned int light = side;
- plot_style_t *plot_style_bdr_in;
- plot_style_t *plot_style_bdr_out;
- nserror res = NSERROR_OK;
- struct rect rect;
-
- if (c == NS_TRANSPARENT) {
- return res;
- }
-
- plot_style_bdr.stroke_type = PLOT_OP_TYPE_DASH;
- plot_style_bdr.stroke_colour = c;
- plot_style_bdr.stroke_width = thickness;
- plot_style_fillbdr.fill_colour = c;
- plot_style_fillbdr_dark.fill_colour = darken_colour(c);
- plot_style_fillbdr_light.fill_colour = lighten_colour(c);
- plot_style_fillbdr_ddark.fill_colour = double_darken_colour(c);
- plot_style_fillbdr_dlight.fill_colour = double_lighten_colour(c);
-
- switch (style) {
- case CSS_BORDER_STYLE_DOTTED:
- plot_style_bdr.stroke_type = PLOT_OP_TYPE_DOT;
- /* fall through */
- case CSS_BORDER_STYLE_DASHED:
- rect.x0 = (p[0] + p[2]) / 2;
- rect.y0 = (p[1] + p[3]) / 2;
- rect.x1 = (p[4] + p[6]) / 2;
- rect.y1 = (p[5] + p[7]) / 2;
- res = ctx->plot->line(ctx, &plot_style_bdr, &rect);
- break;
-
- case CSS_BORDER_STYLE_SOLID:
- /* fall through to default */
- default:
- if (rectangular || thickness == 1) {
-
- if (side == TOP || side == RIGHT) {
- rect.x0 = p[2];
- rect.y0 = p[3];
- if ((side == TOP) &&
- (p[4] - p[6] != 0)) {
- rect.x1 = p[4];
- } else {
- rect.x1 = p[6];
- }
- rect.y1 = p[7];
- } else {
- rect.x0 = p[6];
- rect.y0 = p[7];
- rect.x1 = p[2];
- if ((side == LEFT) &&
- (p[1] - p[3] != 0)) {
- rect.y1 = p[1];
- } else {
- rect.y1 = p[3];
- }
- }
- res = plot_clipped_rectangle(ctx,
- &plot_style_fillbdr,
- clip,
- &rect);
- } else {
- res = ctx->plot->polygon(ctx, &plot_style_fillbdr, p, 4);
- }
- break;
-
- case CSS_BORDER_STYLE_DOUBLE:
- z[0] = p[0];
- z[1] = p[1];
- z[2] = (p[0] * 2 + p[2]) / 3;
- z[3] = (p[1] * 2 + p[3]) / 3;
- z[4] = (p[6] * 2 + p[4]) / 3;
- z[5] = (p[7] * 2 + p[5]) / 3;
- z[6] = p[6];
- z[7] = p[7];
- res = ctx->plot->polygon(ctx, &plot_style_fillbdr, z, 4);
- if (res == NSERROR_OK) {
- z[0] = p[2];
- z[1] = p[3];
- z[2] = (p[2] * 2 + p[0]) / 3;
- z[3] = (p[3] * 2 + p[1]) / 3;
- z[4] = (p[4] * 2 + p[6]) / 3;
- z[5] = (p[5] * 2 + p[7]) / 3;
- z[6] = p[4];
- z[7] = p[5];
- res = ctx->plot->polygon(ctx, &plot_style_fillbdr, z, 4);
- }
- break;
-
- case CSS_BORDER_STYLE_GROOVE:
- light = 3 - light;
- /* fall through */
- case CSS_BORDER_STYLE_RIDGE:
- /* choose correct colours for each part of the border line */
- if (light <= 1) {
- plot_style_bdr_in = &plot_style_fillbdr_dark;
- plot_style_bdr_out = &plot_style_fillbdr_light;
- } else {
- plot_style_bdr_in = &plot_style_fillbdr_light;
- plot_style_bdr_out = &plot_style_fillbdr_dark;
- }
-
- /* Render border */
- if ((rectangular || thickness == 2) && thickness != 1) {
- /* Border made up from two parts and can be
- * plotted with rectangles
- */
-
- /* First part */
- if (side == TOP || side == RIGHT) {
- rect.x0 = (p[0] + p[2]) / 2;
- rect.y0 = (p[1] + p[3]) / 2;
- rect.x1 = p[6];
- rect.y1 = p[7];
- } else {
- rect.x0 = p[6];
- rect.y0 = p[7];
- rect.x1 = (p[0] + p[2]) / 2;
- rect.y1 = (p[1] + p[3]) / 2;
- }
- res = plot_clipped_rectangle(ctx,
- plot_style_bdr_in,
- clip,
- &rect);
- if (res != NSERROR_OK) {
- return res;
- }
-
- /* Second part */
- if (side == TOP || side == RIGHT) {
- rect.x0 = p[2];
- rect.y0 = p[3];
- rect.x1 = (p[6] + p[4]) / 2;
- rect.y1 = (p[7] + p[5]) / 2;
- } else {
- rect.x0 = (p[6] + p[4]) / 2;
- rect.y0 = (p[7] + p[5]) / 2;
- rect.x1 = p[2];
- rect.y1 = p[3];
- }
- res = plot_clipped_rectangle(ctx,
- plot_style_bdr_out,
- clip,
- &rect);
- } else if (thickness == 1) {
- /* Border made up from one part which can be
- * plotted as a rectangle
- */
-
- if (side == TOP || side == RIGHT) {
- rect.x0 = p[2];
- rect.y0 = p[3];
- rect.x1 = p[6];
- rect.y1 = p[7];
- rect.x1 = ((side == TOP) && (p[4] - p[6] != 0)) ?
- rect.x1 + p[4] - p[6] : rect.x1;
-
- res = plot_clipped_rectangle(ctx,
- plot_style_bdr_in,
- clip,
- &rect);
- } else {
- rect.x0 = p[6];
- rect.y0 = p[7];
- rect.x1 = p[2];
- rect.y1 = p[3];
- rect.y1 = ((side == LEFT) && (p[1] - p[3] != 0)) ?
- rect.y1 + p[1] - p[3] : rect.y1;
- res = plot_clipped_rectangle(ctx,
- plot_style_bdr_out,
- clip,
- &rect);
- }
- } else {
- /* Border made up from two parts and can't be
- * plotted with rectangles
- */
- z[0] = p[0];
- z[1] = p[1];
- z[2] = (p[0] + p[2]) / 2;
- z[3] = (p[1] + p[3]) / 2;
- z[4] = (p[6] + p[4]) / 2;
- z[5] = (p[7] + p[5]) / 2;
- z[6] = p[6];
- z[7] = p[7];
- res = ctx->plot->polygon(ctx, plot_style_bdr_in, z, 4);
- if (res == NSERROR_OK) {
- z[0] = p[2];
- z[1] = p[3];
- z[6] = p[4];
- z[7] = p[5];
- res = ctx->plot->polygon(ctx,
- plot_style_bdr_out,
- z,
- 4);
- }
- }
- break;
-
- case CSS_BORDER_STYLE_INSET:
- light = (light + 2) % 4;
- /* fall through */
- case CSS_BORDER_STYLE_OUTSET:
- /* choose correct colours for each part of the border line */
- switch (light) {
- case 0:
- plot_style_bdr_in = &plot_style_fillbdr_light;
- plot_style_bdr_out = &plot_style_fillbdr_dlight;
- break;
- case 1:
- plot_style_bdr_in = &plot_style_fillbdr_ddark;
- plot_style_bdr_out = &plot_style_fillbdr_dark;
- break;
- case 2:
- plot_style_bdr_in = &plot_style_fillbdr_dark;
- plot_style_bdr_out = &plot_style_fillbdr_ddark;
- break;
- case 3:
- plot_style_bdr_in = &plot_style_fillbdr_dlight;
- plot_style_bdr_out = &plot_style_fillbdr_light;
- break;
- default:
- plot_style_bdr_in = &plot_style_fillbdr;
- plot_style_bdr_out = &plot_style_fillbdr;
- break;
- }
-
- /* Render border */
- if ((rectangular || thickness == 2) && thickness != 1) {
- /* Border made up from two parts and can be
- * plotted with rectangles
- */
-
- /* First part */
- if (side == TOP || side == RIGHT) {
- rect.x0 = (p[0] + p[2]) / 2;
- rect.y0 = (p[1] + p[3]) / 2;
- rect.x1 = p[6];
- rect.y1 = p[7];
- } else {
- rect.x0 = p[6];
- rect.y0 = p[7];
- rect.x1 = (p[0] + p[2]) / 2;
- rect.y1 = (p[1] + p[3]) / 2;
- }
- res = plot_clipped_rectangle(ctx,
- plot_style_bdr_in,
- clip,
- &rect);
- if (res != NSERROR_OK) {
- return res;
- }
-
- /* Second part */
- if (side == TOP || side == RIGHT) {
- rect.x0 = p[2];
- rect.y0 = p[3];
- rect.x1 = (p[6] + p[4]) / 2;
- rect.y1 = (p[7] + p[5]) / 2;
- } else {
- rect.x0 = (p[6] + p[4]) / 2;
- rect.y0 = (p[7] + p[5]) / 2;
- rect.x1 = p[2];
- rect.y1 = p[3];
- }
- res = plot_clipped_rectangle(ctx,
- plot_style_bdr_out,
- clip,
- &rect);
- } else if (thickness == 1) {
- /* Border made up from one part which can be
- * plotted as a rectangle
- */
-
- if (side == TOP || side == RIGHT) {
- rect.x0 = p[2];
- rect.y0 = p[3];
- rect.x1 = p[6];
- rect.y1 = p[7];
- rect.x1 = ((side == TOP) && (p[4] - p[6] != 0)) ?
- rect.x1 + p[4] - p[6] : rect.x1;
- res = plot_clipped_rectangle(ctx,
- plot_style_bdr_in,
- clip,
- &rect);
- } else {
- rect.x0 = p[6];
- rect.y0 = p[7];
- rect.x1 = p[2];
- rect.y1 = p[3];
- rect.y1 = ((side == LEFT) && (p[1] - p[3] != 0)) ?
- rect.y1 + p[1] - p[3] : rect.y1;
- res = plot_clipped_rectangle(ctx,
- plot_style_bdr_out,
- clip,
- &rect);
- }
- } else {
- /* Border made up from two parts and can't be
- * plotted with rectangles
- */
-
- z[0] = p[0];
- z[1] = p[1];
- z[2] = (p[0] + p[2]) / 2;
- z[3] = (p[1] + p[3]) / 2;
- z[4] = (p[6] + p[4]) / 2;
- z[5] = (p[7] + p[5]) / 2;
- z[6] = p[6];
- z[7] = p[7];
- res = ctx->plot->polygon(ctx, plot_style_bdr_in, z, 4);
- if (res != NSERROR_OK) {
- return res;
- }
- z[0] = p[2];
- z[1] = p[3];
- z[6] = p[4];
- z[7] = p[5];
- res = ctx->plot->polygon(ctx, plot_style_bdr_out, z, 4);
- }
- break;
- }
-
- return res;
-}
-
-
-/**
- * Draw borders for a box.
- *
- * \param box box to draw
- * \param x_parent coordinate of left padding edge of parent of box
- * \param y_parent coordinate of top padding edge of parent of box
- * \param p_width width of padding box
- * \param p_height height of padding box
- * \param clip cliping area for redrawing border.
- * \param scale scale for redraw
- * \param ctx current redraw context
- * \return true if successful, false otherwise
- */
-bool
-html_redraw_borders(struct box *box,
- int x_parent,
- int y_parent,
- int p_width,
- int p_height,
- const struct rect *clip,
- float scale,
- const struct redraw_context *ctx)
-{
- unsigned int sides[] = { LEFT, RIGHT, TOP, BOTTOM };
- int top = box->border[TOP].width;
- int right = box->border[RIGHT].width;
- int bottom = box->border[BOTTOM].width;
- int left = box->border[LEFT].width;
- int x, y;
- unsigned int i, side;
- int p[8]; /* Box border vertices */
- int z[8]; /* Border vertices */
- bool square_end_1 = false;
- bool square_end_2 = false;
- nserror res;
-
- x = x_parent + box->x;
- y = y_parent + box->y;
-
- if (scale != 1.0) {
- top *= scale;
- right *= scale;
- bottom *= scale;
- left *= scale;
- x *= scale;
- y *= scale;
- }
-
- assert(box->style);
-
- /* Calculate border vertices
- *
- * A----------------------+
- * | \ / |
- * | B--------------+ |
- * | | | |
- * | +--------------C |
- * | / \ |
- * +----------------------D
- */
- p[0] = x - left; p[1] = y - top; /* A */
- p[2] = x; p[3] = y; /* B */
- p[4] = x + p_width; p[5] = y + p_height; /* C */
- p[6] = x + p_width + right; p[7] = y + p_height + bottom; /* D */
-
- for (i = 0; i != 4; i++) {
- colour col = 0;
- side = sides[i]; /* plot order */
-
- if (box->border[side].width == 0 ||
- nscss_color_is_transparent(box->border[side].c)) {
- continue;
- }
-
- switch (side) {
- case LEFT:
- square_end_1 = (top == 0);
- square_end_2 = (bottom == 0);
-
- z[0] = p[0]; z[1] = p[7];
- z[2] = p[2]; z[3] = p[5];
- z[4] = p[2]; z[5] = p[3];
- z[6] = p[0]; z[7] = p[1];
-
- if (nscss_color_is_transparent(box->border[TOP].c) == false &&
- box->border[TOP].style != CSS_BORDER_STYLE_DOUBLE) {
- /* make border overhang top corner fully,
- * if top border is opaque
- */
- z[5] -= top;
- square_end_1 = true;
- }
- if (nscss_color_is_transparent(box->border[BOTTOM].c) == false &&
- box->border[BOTTOM].style != CSS_BORDER_STYLE_DOUBLE) {
- /* make border overhang bottom corner fully,
- * if bottom border is opaque
- */
- z[3] += bottom;
- square_end_2 = true;
- }
-
- col = nscss_color_to_ns(box->border[side].c);
-
- res = html_redraw_border_plot(side,
- z,
- col,
- box->border[side].style,
- box->border[side].width * scale,
- square_end_1 && square_end_2,
- clip,
- ctx);
- if (res != NSERROR_OK) {
- return false;
- }
- break;
-
- case RIGHT:
- square_end_1 = (top == 0);
- square_end_2 = (bottom == 0);
-
- z[0] = p[6]; z[1] = p[1];
- z[2] = p[4]; z[3] = p[3];
- z[4] = p[4]; z[5] = p[5];
- z[6] = p[6]; z[7] = p[7];
-
- if (nscss_color_is_transparent(box->border[TOP].c) == false &&
- box->border[TOP].style != CSS_BORDER_STYLE_DOUBLE) {
- /* make border overhang top corner fully,
- * if top border is opaque
- */
- z[3] -= top;
- square_end_1 = true;
- }
- if (nscss_color_is_transparent(box->border[BOTTOM].c) == false &&
- box->border[BOTTOM].style != CSS_BORDER_STYLE_DOUBLE) {
- /* make border overhang bottom corner fully,
- * if bottom border is opaque
- */
- z[5] += bottom;
- square_end_2 = true;
- }
-
- col = nscss_color_to_ns(box->border[side].c);
-
- res = html_redraw_border_plot(side,
- z,
- col,
- box->border[side].style,
- box->border[side].width * scale,
- square_end_1 && square_end_2,
- clip,
- ctx);
- if (res != NSERROR_OK) {
- return false;
- }
- break;
-
- case TOP:
- if (clip->y0 > p[3]) {
- /* clip rectangle is below border; nothing to
- * plot
- */
- continue;
- }
-
- square_end_1 = (left == 0);
- square_end_2 = (right == 0);
-
- z[0] = p[2]; z[1] = p[3];
- z[2] = p[0]; z[3] = p[1];
- z[4] = p[6]; z[5] = p[1];
- z[6] = p[4]; z[7] = p[3];
-
- if (box->border[TOP].style == CSS_BORDER_STYLE_SOLID &&
- box->border[TOP].c == box->border[LEFT].c) {
- /* don't bother overlapping left corner if
- * it's the same colour anyway
- */
- z[2] += left;
- square_end_1 = true;
- }
- if (box->border[TOP].style == CSS_BORDER_STYLE_SOLID &&
- box->border[TOP].c == box->border[RIGHT].c) {
- /* don't bother overlapping right corner if
- * it's the same colour anyway
- */
- z[4] -= right;
- square_end_2 = true;
- }
-
- col = nscss_color_to_ns(box->border[side].c);
-
- res = html_redraw_border_plot(side,
- z,
- col,
- box->border[side].style,
- box->border[side].width * scale,
- square_end_1 && square_end_2,
- clip,
- ctx);
- if (res != NSERROR_OK) {
- return false;
- }
- break;
-
- case BOTTOM:
- if (clip->y1 < p[5]) {
- /* clip rectangle is above border; nothing to
- * plot
- */
- continue;
- }
-
- square_end_1 = (left == 0);
- square_end_2 = (right == 0);
-
- z[0] = p[4]; z[1] = p[5];
- z[2] = p[6]; z[3] = p[7];
- z[4] = p[0]; z[5] = p[7];
- z[6] = p[2]; z[7] = p[5];
-
- if (box->border[BOTTOM].style == CSS_BORDER_STYLE_SOLID &&
- box->border[BOTTOM].c == box->border[LEFT].c) {
- /* don't bother overlapping left corner if
- * it's the same colour anyway
- */
- z[4] += left;
- square_end_1 = true;
- }
- if (box->border[BOTTOM].style == CSS_BORDER_STYLE_SOLID &&
- box->border[BOTTOM].c == box->border[RIGHT].c) {
- /* don't bother overlapping right corner if
- * it's the same colour anyway
- */
- z[2] -= right;
- square_end_2 = true;
- }
-
- col = nscss_color_to_ns(box->border[side].c);
-
- res = html_redraw_border_plot(side,
- z,
- col,
- box->border[side].style,
- box->border[side].width * scale,
- square_end_1 && square_end_2,
- clip,
- ctx);
- if (res != NSERROR_OK) {
- return false;
- }
- break;
-
- default:
- assert(side == TOP || side == BOTTOM ||
- side == LEFT || side == RIGHT);
- break;
- }
- }
-
- return true;
-}
-
-
-/**
- * Draw an inline's borders.
- *
- * \param box BOX_INLINE which created the border
- * \param b coordinates of border edge rectangle
- * \param clip cliping area for redrawing border.
- * \param scale scale for redraw
- * \param first true if this is the first rectangle associated with the inline
- * \param last true if this is the last rectangle associated with the inline
- * \param ctx current redraw context
- * \return true if successful, false otherwise
- */
-bool
-html_redraw_inline_borders(struct box *box,
- struct rect b,
- const struct rect *clip,
- float scale,
- bool first,
- bool last,
- const struct redraw_context *ctx)
-{
- int top = box->border[TOP].width;
- int right = box->border[RIGHT].width;
- int bottom = box->border[BOTTOM].width;
- int left = box->border[LEFT].width;
- colour col;
- int p[8]; /* Box border vertices */
- int z[8]; /* Border vertices */
- bool square_end_1;
- bool square_end_2;
- nserror res;
-
- if (scale != 1.0) {
- top *= scale;
- right *= scale;
- bottom *= scale;
- left *= scale;
- }
-
- /* Calculate border vertices
- *
- * A----------------------+
- * | \ / |
- * | B--------------+ |
- * | | | |
- * | +--------------C |
- * | / \ |
- * +----------------------D
- */
- p[0] = b.x0; p[1] = b.y0; /* A */
- p[2] = first ? b.x0 + left : b.x0; p[3] = b.y0 + top; /* B */
- p[4] = last ? b.x1 - right : b.x1; p[5] = b.y1 - bottom; /* C */
- p[6] = b.x1; p[7] = b.y1; /* D */
-
- assert(box->style);
-
- /* Left */
- square_end_1 = (top == 0);
- square_end_2 = (bottom == 0);
- if (left != 0 &&
- first &&
- nscss_color_is_transparent(box->border[LEFT].c) == false) {
- col = nscss_color_to_ns(box->border[LEFT].c);
-
- z[0] = p[0]; z[1] = p[7];
- z[2] = p[2]; z[3] = p[5];
- z[4] = p[2]; z[5] = p[3];
- z[6] = p[0]; z[7] = p[1];
-
- if (nscss_color_is_transparent(box->border[TOP].c) == false &&
- box->border[TOP].style != CSS_BORDER_STYLE_DOUBLE) {
- /* make border overhang top corner fully,
- * if top border is opaque
- */
- z[5] -= top;
- square_end_1 = true;
- }
-
- if (nscss_color_is_transparent(box->border[BOTTOM].c) == false &&
- box->border[BOTTOM].style != CSS_BORDER_STYLE_DOUBLE) {
- /* make border overhang bottom corner fully,
- * if bottom border is opaque
- */
- z[3] += bottom;
- square_end_2 = true;
- }
-
- res = html_redraw_border_plot(LEFT,
- z,
- col,
- box->border[LEFT].style,
- left,
- square_end_1 && square_end_2,
- clip,
- ctx);
- if (res != NSERROR_OK) {
- return false;
- }
- }
-
- /* Right */
- square_end_1 = (top == 0);
- square_end_2 = (bottom == 0);
- if (right != 0 &&
- last &&
- nscss_color_is_transparent(box->border[RIGHT].c) == false) {
- col = nscss_color_to_ns(box->border[RIGHT].c);
-
- z[0] = p[6]; z[1] = p[1];
- z[2] = p[4]; z[3] = p[3];
- z[4] = p[4]; z[5] = p[5];
- z[6] = p[6]; z[7] = p[7];
-
- if (nscss_color_is_transparent(box->border[TOP].c) == false &&
- box->border[TOP].style != CSS_BORDER_STYLE_DOUBLE) {
- /* make border overhang top corner fully,
- * if top border is opaque
- */
- z[3] -= top;
- square_end_1 = true;
- }
-
- if (nscss_color_is_transparent(box->border[BOTTOM].c) == false &&
- box->border[BOTTOM].style != CSS_BORDER_STYLE_DOUBLE) {
- /* make border overhang bottom corner fully,
- * if bottom border is opaque
- */
- z[5] += bottom;
- square_end_2 = true;
- }
-
- res = html_redraw_border_plot(RIGHT,
- z,
- col,
- box->border[RIGHT].style,
- right,
- square_end_1 && square_end_2,
- clip,
- ctx);
- if (res != NSERROR_OK) {
- return false;
- }
- }
-
- /* Top */
- square_end_1 = (left == 0);
- square_end_2 = (right == 0);
- if (top != 0 &&
- nscss_color_is_transparent(box->border[TOP].c) == false) {
- col = nscss_color_to_ns(box->border[TOP].c);
-
- z[0] = p[2]; z[1] = p[3];
- z[2] = p[0]; z[3] = p[1];
- z[4] = p[6]; z[5] = p[1];
- z[6] = p[4]; z[7] = p[3];
-
- if (first &&
- box->border[TOP].style == CSS_BORDER_STYLE_SOLID &&
- box->border[TOP].c == box->border[LEFT].c) {
- /* don't bother overlapping left corner if
- * it's the same colour anyway
- */
- z[2] += left;
- square_end_1 = true;
- }
-
- if (last &&
- box->border[TOP].style == CSS_BORDER_STYLE_SOLID &&
- box->border[TOP].c == box->border[RIGHT].c) {
- /* don't bother overlapping right corner if
- * it's the same colour anyway
- */
- z[4] -= right;
- square_end_2 = true;
- }
-
- res = html_redraw_border_plot(TOP,
- z,
- col,
- box->border[TOP].style,
- top,
- square_end_1 && square_end_2,
- clip,
- ctx);
- if (res != NSERROR_OK) {
- return false;
- }
- }
-
- /* Bottom */
- square_end_1 = (left == 0);
- square_end_2 = (right == 0);
- if (bottom != 0 &&
- nscss_color_is_transparent(box->border[BOTTOM].c) == false) {
- col = nscss_color_to_ns(box->border[BOTTOM].c);
-
- z[0] = p[4]; z[1] = p[5];
- z[2] = p[6]; z[3] = p[7];
- z[4] = p[0]; z[5] = p[7];
- z[6] = p[2]; z[7] = p[5];
-
- if (first &&
- box->border[BOTTOM].style == CSS_BORDER_STYLE_SOLID &&
- box->border[BOTTOM].c == box->border[LEFT].c) {
- /* don't bother overlapping left corner if
- * it's the same colour anyway
- */
- z[4] += left;
- square_end_1 = true;
- }
-
- if (last &&
- box->border[BOTTOM].style == CSS_BORDER_STYLE_SOLID &&
- box->border[BOTTOM].c == box->border[RIGHT].c) {
- /* don't bother overlapping right corner if
- * it's the same colour anyway
- */
- z[2] -= right;
- square_end_2 = true;
- }
-
- res = html_redraw_border_plot(BOTTOM,
- z,
- col,
- box->border[BOTTOM].style,
- bottom,
- square_end_1 && square_end_2,
- clip,
- ctx);
- if (res != NSERROR_OK) {
- return false;
- }
- }
-
- return true;
-}
diff --git a/render/html_script.c b/render/html_script.c
deleted file mode 100644
index c73a4806d..000000000
--- a/render/html_script.c
+++ /dev/null
@@ -1,603 +0,0 @@
-/*
- * Copyright 2012 Vincent Sanders <vince@netsurf-browser.org>
- *
- * This file is part of NetSurf, http://www.netsurf-browser.org/
- *
- * NetSurf is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * NetSurf is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-/** \file
- * Content for text/html scripts (implementation).
- */
-
-#include <assert.h>
-#include <ctype.h>
-#include <stdint.h>
-#include <stdbool.h>
-#include <string.h>
-#include <strings.h>
-#include <stdlib.h>
-
-#include "utils/config.h"
-#include "utils/corestrings.h"
-#include "utils/log.h"
-#include "utils/messages.h"
-#include "netsurf/content.h"
-#include "javascript/js.h"
-#include "content/content_protected.h"
-#include "content/fetch.h"
-#include "content/hlcache.h"
-
-#include "render/html_internal.h"
-
-typedef bool (script_handler_t)(struct jscontext *jscontext, const char *data, size_t size) ;
-
-
-static script_handler_t *select_script_handler(content_type ctype)
-{
- if (ctype == CONTENT_JS) {
- return js_exec;
- }
- return NULL;
-}
-
-
-/* exported internal interface documented in render/html_internal.h */
-nserror html_script_exec(html_content *c)
-{
- unsigned int i;
- struct html_script *s;
- script_handler_t *script_handler;
-
- if (c->jscontext == NULL) {
- return NSERROR_BAD_PARAMETER;
- }
-
- for (i = 0, s = c->scripts; i != c->scripts_count; i++, s++) {
- if (s->already_started) {
- continue;
- }
-
- if ((s->type == HTML_SCRIPT_ASYNC) ||
- (s->type == HTML_SCRIPT_DEFER)) {
- /* ensure script content is present */
- if (s->data.handle == NULL)
- continue;
-
- /* ensure script content fetch status is not an error */
- if (content_get_status(s->data.handle) ==
- CONTENT_STATUS_ERROR)
- continue;
-
- /* ensure script handler for content type */
- script_handler = select_script_handler(
- content_get_type(s->data.handle));
- if (script_handler == NULL)
- continue; /* unsupported type */
-
- if (content_get_status(s->data.handle) ==
- CONTENT_STATUS_DONE) {
- /* external script is now available */
- const char *data;
- unsigned long size;
- data = content_get_source_data(
- s->data.handle, &size );
- script_handler(c->jscontext, data, size);
-
- s->already_started = true;
-
- }
- }
- }
-
- return NSERROR_OK;
-}
-
-/* create new html script entry */
-static struct html_script *
-html_process_new_script(html_content *c,
- dom_string *mimetype,
- enum html_script_type type)
-{
- struct html_script *nscript;
- /* add space for new script entry */
- nscript = realloc(c->scripts,
- sizeof(struct html_script) * (c->scripts_count + 1));
- if (nscript == NULL) {
- return NULL;
- }
-
- c->scripts = nscript;
-
- /* increment script entry count */
- nscript = &c->scripts[c->scripts_count];
- c->scripts_count++;
-
- nscript->already_started = false;
- nscript->parser_inserted = false;
- nscript->force_async = true;
- nscript->ready_exec = false;
- nscript->async = false;
- nscript->defer = false;
-
- nscript->type = type;
-
- nscript->mimetype = dom_string_ref(mimetype); /* reference mimetype */
-
- return nscript;
-}
-
-/**
- * Callback for asyncronous scripts
- */
-static nserror
-convert_script_async_cb(hlcache_handle *script,
- const hlcache_event *event,
- void *pw)
-{
- html_content *parent = pw;
- unsigned int i;
- struct html_script *s;
-
- /* Find script */
- for (i = 0, s = parent->scripts; i != parent->scripts_count; i++, s++) {
- if (s->type == HTML_SCRIPT_ASYNC && s->data.handle == script)
- break;
- }
-
- assert(i != parent->scripts_count);
-
- switch (event->type) {
- case CONTENT_MSG_LOADING:
- break;
-
- case CONTENT_MSG_READY:
- break;
-
- case CONTENT_MSG_DONE:
- NSLOG(netsurf, INFO, "script %d done '%s'", i,
- nsurl_access(hlcache_handle_get_url(script)));
- parent->base.active--;
- NSLOG(netsurf, INFO, "%d fetches active", parent->base.active);
-
- break;
-
- case CONTENT_MSG_ERROR:
- NSLOG(netsurf, INFO, "script %s failed: %s",
- nsurl_access(hlcache_handle_get_url(script)),
- event->data.error);
- /* fall through */
-
- case CONTENT_MSG_ERRORCODE:
- hlcache_handle_release(script);
- s->data.handle = NULL;
- parent->base.active--;
- NSLOG(netsurf, INFO, "%d fetches active", parent->base.active);
- content_add_error(&parent->base, "?", 0);
-
- break;
-
- default:
- break;
- }
-
- /* if there are no active fetches remaining begin post parse
- * conversion
- */
- if (html_can_begin_conversion(parent)) {
- html_begin_conversion(parent);
- }
-
- return NSERROR_OK;
-}
-
-/**
- * Callback for defer scripts
- */
-static nserror
-convert_script_defer_cb(hlcache_handle *script,
- const hlcache_event *event,
- void *pw)
-{
- html_content *parent = pw;
- unsigned int i;
- struct html_script *s;
-
- /* Find script */
- for (i = 0, s = parent->scripts; i != parent->scripts_count; i++, s++) {
- if (s->type == HTML_SCRIPT_DEFER && s->data.handle == script)
- break;
- }
-
- assert(i != parent->scripts_count);
-
- switch (event->type) {
-
- case CONTENT_MSG_DONE:
- NSLOG(netsurf, INFO, "script %d done '%s'", i,
- nsurl_access(hlcache_handle_get_url(script)));
- parent->base.active--;
- NSLOG(netsurf, INFO, "%d fetches active", parent->base.active);
-
- break;
-
- case CONTENT_MSG_ERROR:
- NSLOG(netsurf, INFO, "script %s failed: %s",
- nsurl_access(hlcache_handle_get_url(script)),
- event->data.error);
- /* fall through */
-
- case CONTENT_MSG_ERRORCODE:
- hlcache_handle_release(script);
- s->data.handle = NULL;
- parent->base.active--;
- NSLOG(netsurf, INFO, "%d fetches active", parent->base.active);
- content_add_error(&parent->base, "?", 0);
-
- break;
-
- default:
- break;
- }
-
- /* if there are no active fetches remaining begin post parse
- * conversion
- */
- if (html_can_begin_conversion(parent)) {
- html_begin_conversion(parent);
- }
-
- return NSERROR_OK;
-}
-
-/**
- * Callback for syncronous scripts
- */
-static nserror
-convert_script_sync_cb(hlcache_handle *script,
- const hlcache_event *event,
- void *pw)
-{
- html_content *parent = pw;
- unsigned int i;
- struct html_script *s;
- script_handler_t *script_handler;
- dom_hubbub_error err;
-
- /* Find script */
- for (i = 0, s = parent->scripts; i != parent->scripts_count; i++, s++) {
- if (s->type == HTML_SCRIPT_SYNC && s->data.handle == script)
- break;
- }
-
- assert(i != parent->scripts_count);
-
- switch (event->type) {
- case CONTENT_MSG_DONE:
- NSLOG(netsurf, INFO, "script %d done '%s'", i,
- nsurl_access(hlcache_handle_get_url(script)));
- parent->base.active--;
- NSLOG(netsurf, INFO, "%d fetches active", parent->base.active);
-
- s->already_started = true;
-
- /* attempt to execute script */
- script_handler = select_script_handler(content_get_type(s->data.handle));
- if (script_handler != NULL && parent->jscontext != NULL) {
- /* script has a handler */
- const char *data;
- unsigned long size;
- data = content_get_source_data(s->data.handle, &size );
- script_handler(parent->jscontext, data, size);
- }
-
- /* continue parse */
- err = dom_hubbub_parser_pause(parent->parser, false);
- if (err != DOM_HUBBUB_OK) {
- NSLOG(netsurf, INFO, "unpause returned 0x%x", err);
- }
-
- break;
-
- case CONTENT_MSG_ERROR:
- NSLOG(netsurf, INFO, "script %s failed: %s",
- nsurl_access(hlcache_handle_get_url(script)),
- event->data.error);
- /* fall through */
-
- case CONTENT_MSG_ERRORCODE:
- hlcache_handle_release(script);
- s->data.handle = NULL;
- parent->base.active--;
-
- NSLOG(netsurf, INFO, "%d fetches active", parent->base.active);
- content_add_error(&parent->base, "?", 0);
-
- s->already_started = true;
-
- /* continue parse */
- err = dom_hubbub_parser_pause(parent->parser, false);
- if (err != DOM_HUBBUB_OK) {
- NSLOG(netsurf, INFO, "unpause returned 0x%x", err);
- }
-
- break;
-
- default:
- break;
- }
-
- /* if there are no active fetches remaining begin post parse
- * conversion
- */
- if (html_can_begin_conversion(parent)) {
- html_begin_conversion(parent);
- }
-
- return NSERROR_OK;
-}
-
-/**
- * process a script with a src tag
- */
-static dom_hubbub_error
-exec_src_script(html_content *c,
- dom_node *node,
- dom_string *mimetype,
- dom_string *src)
-{
- nserror ns_error;
- nsurl *joined;
- hlcache_child_context child;
- struct html_script *nscript;
- bool async;
- bool defer;
- enum html_script_type script_type;
- hlcache_handle_callback script_cb;
- dom_hubbub_error ret = DOM_HUBBUB_OK;
- dom_exception exc; /* returned by libdom functions */
-
- /* src url */
- ns_error = nsurl_join(c->base_url, dom_string_data(src), &joined);
- if (ns_error != NSERROR_OK) {
- content_broadcast_errorcode(&c->base, NSERROR_NOMEM);
- return DOM_HUBBUB_NOMEM;
- }
-
- NSLOG(netsurf, INFO, "script %i '%s'", c->scripts_count,
- nsurl_access(joined));
-
- /* there are three ways to process the script tag at this point:
- *
- * Syncronously pause the parent parse and continue after
- * the script has downloaded and executed. (default)
- * Async Start the script downloading and execute it when it
- * becomes available.
- * Defered Start the script downloading and execute it when
- * the page has completed parsing, may be set along
- * with async where it is ignored.
- */
-
- /* we interpret the presence of the async and defer attribute
- * as true and ignore its value, technically only the empty
- * value or the attribute name itself are valid. However
- * various browsers interpret this in various ways the most
- * compatible approach is to be liberal and accept any
- * value. Note setting the values to "false" still makes them true!
- */
- exc = dom_element_has_attribute(node, corestring_dom_async, &async);
- if (exc != DOM_NO_ERR) {
- return DOM_HUBBUB_OK; /* dom error */
- }
-
- if (async) {
- /* asyncronous script */
- script_type = HTML_SCRIPT_ASYNC;
- script_cb = convert_script_async_cb;
-
- } else {
- exc = dom_element_has_attribute(node,
- corestring_dom_defer, &defer);
- if (exc != DOM_NO_ERR) {
- return DOM_HUBBUB_OK; /* dom error */
- }
-
- if (defer) {
- /* defered script */
- script_type = HTML_SCRIPT_DEFER;
- script_cb = convert_script_defer_cb;
- } else {
- /* syncronous script */
- script_type = HTML_SCRIPT_SYNC;
- script_cb = convert_script_sync_cb;
- }
- }
-
- nscript = html_process_new_script(c, mimetype, script_type);
- if (nscript == NULL) {
- nsurl_unref(joined);
- content_broadcast_errorcode(&c->base, NSERROR_NOMEM);
- return DOM_HUBBUB_NOMEM;
- }
-
- /* set up child fetch encoding and quirks */
- child.charset = c->encoding;
- child.quirks = c->base.quirks;
-
- ns_error = hlcache_handle_retrieve(joined,
- 0,
- content_get_url(&c->base),
- NULL,
- script_cb,
- c,
- &child,
- CONTENT_SCRIPT,
- &nscript->data.handle);
-
-
- nsurl_unref(joined);
-
- if (ns_error != NSERROR_OK) {
- /* @todo Deal with fetch error better. currently assume
- * fetch never became active
- */
- /* mark duff script fetch as already started */
- nscript->already_started = true;
- NSLOG(netsurf, INFO, "Fetch failed with error %d", ns_error);
- } else {
- /* update base content active fetch count */
- c->base.active++;
- NSLOG(netsurf, INFO, "%d fetches active", c->base.active);
-
- switch (script_type) {
- case HTML_SCRIPT_SYNC:
- ret = DOM_HUBBUB_HUBBUB_ERR | HUBBUB_PAUSED;
-
- case HTML_SCRIPT_ASYNC:
- break;
-
- case HTML_SCRIPT_DEFER:
- break;
-
- default:
- assert(0);
- }
- }
-
- return ret;
-}
-
-static dom_hubbub_error
-exec_inline_script(html_content *c, dom_node *node, dom_string *mimetype)
-{
- dom_string *script;
- dom_exception exc; /* returned by libdom functions */
- struct lwc_string_s *lwcmimetype;
- script_handler_t *script_handler;
- struct html_script *nscript;
-
- /* does not appear to be a src so script is inline content */
- exc = dom_node_get_text_content(node, &script);
- if ((exc != DOM_NO_ERR) || (script == NULL)) {
- return DOM_HUBBUB_OK; /* no contents, skip */
- }
-
- nscript = html_process_new_script(c, mimetype, HTML_SCRIPT_INLINE);
- if (nscript == NULL) {
- dom_string_unref(script);
-
- content_broadcast_errorcode(&c->base, NSERROR_NOMEM);
- return DOM_HUBBUB_NOMEM;
-
- }
-
- nscript->data.string = script;
- nscript->already_started = true;
-
- /* ensure script handler for content type */
- dom_string_intern(mimetype, &lwcmimetype);
- script_handler = select_script_handler(content_factory_type_from_mime_type(lwcmimetype));
- lwc_string_unref(lwcmimetype);
-
- if (script_handler != NULL) {
- script_handler(c->jscontext,
- dom_string_data(script),
- dom_string_byte_length(script));
- }
- return DOM_HUBBUB_OK;
-}
-
-
-/**
- * process script node parser callback
- *
- *
- */
-dom_hubbub_error
-html_process_script(void *ctx, dom_node *node)
-{
- html_content *c = (html_content *)ctx;
- dom_exception exc; /* returned by libdom functions */
- dom_string *src, *mimetype;
- dom_hubbub_error err = DOM_HUBBUB_OK;
-
- /* ensure javascript context is available */
- /* We should only ever be here if scripting was enabled for this
- * content so it's correct to make a javascript context if there
- * isn't one already. */
- if (c->jscontext == NULL) {
- union content_msg_data msg_data;
-
- msg_data.jscontext = &c->jscontext;
- content_broadcast(&c->base, CONTENT_MSG_GETCTX, &msg_data);
- NSLOG(netsurf, INFO, "javascript context %p ", c->jscontext);
- if (c->jscontext == NULL) {
- /* no context and it could not be created, abort */
- return DOM_HUBBUB_OK;
- }
- }
-
- NSLOG(netsurf, INFO, "content %p parser %p node %p", c, c->parser,
- node);
-
- exc = dom_element_get_attribute(node, corestring_dom_type, &mimetype);
- if (exc != DOM_NO_ERR || mimetype == NULL) {
- mimetype = dom_string_ref(corestring_dom_text_javascript);
- }
-
- exc = dom_element_get_attribute(node, corestring_dom_src, &src);
- if (exc != DOM_NO_ERR || src == NULL) {
- err = exec_inline_script(c, node, mimetype);
- } else {
- err = exec_src_script(c, node, mimetype, src);
- dom_string_unref(src);
- }
-
- dom_string_unref(mimetype);
-
- return err;
-}
-
-/* exported internal interface documented in render/html_internal.h */
-nserror html_script_free(html_content *html)
-{
- unsigned int i;
-
- for (i = 0; i != html->scripts_count; i++) {
- if (html->scripts[i].mimetype != NULL) {
- dom_string_unref(html->scripts[i].mimetype);
- }
-
- if ((html->scripts[i].type == HTML_SCRIPT_INLINE) &&
- (html->scripts[i].data.string != NULL)) {
-
- dom_string_unref(html->scripts[i].data.string);
-
- } else if ((html->scripts[i].type == HTML_SCRIPT_SYNC) &&
- (html->scripts[i].data.handle != NULL)) {
-
- hlcache_handle_release(html->scripts[i].data.handle);
-
- }
- }
- free(html->scripts);
-
- return NSERROR_OK;
-}
-
-/* exported internal interface documented in render/html_internal.h */
-nserror html_script_invalidate_ctx(html_content *htmlc)
-{
- htmlc->jscontext = NULL;
- return NSERROR_OK;
-}
diff --git a/render/imagemap.c b/render/imagemap.c
deleted file mode 100644
index 0d3b42a1b..000000000
--- a/render/imagemap.c
+++ /dev/null
@@ -1,801 +0,0 @@
-/*
- * Copyright 2004 John M Bell <jmb202@ecs.soton.ac.uk>
- *
- * This file is part of NetSurf, http://www.netsurf-browser.org/
- *
- * NetSurf is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * NetSurf is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-/*
- * Much of this shamelessly copied from utils/messages.c
- */
-
-#include <assert.h>
-#include <stdbool.h>
-#include <string.h>
-#include <strings.h>
-
-#include <dom/dom.h>
-
-#include "utils/log.h"
-#include "utils/corestrings.h"
-#include "content/content_protected.h"
-#include "content/hlcache.h"
-
-#include "render/box.h"
-#include "render/html_internal.h"
-#include "render/imagemap.h"
-
-#define HASH_SIZE 31 /* fixed size hash table */
-
-typedef enum {
- IMAGEMAP_DEFAULT,
- IMAGEMAP_RECT,
- IMAGEMAP_CIRCLE,
- IMAGEMAP_POLY
-} imagemap_entry_type;
-
-struct mapentry {
- imagemap_entry_type type; /**< type of shape */
- nsurl *url; /**< absolute url to go to */
- char *target; /**< target frame (if any) */
- union {
- struct {
- int x; /**< x coordinate of centre */
- int y; /**< y coordinate of center */
- int r; /**< radius of circle */
- } circle;
- struct {
- int x0; /**< left hand edge */
- int y0; /**< top edge */
- int x1; /**< right hand edge */
- int y1; /**< bottom edge */
- } rect;
- struct {
- int num; /**< number of points */
- float *xcoords; /**< x coordinates */
- float *ycoords; /**< y coordinates */
- } poly;
- } bounds;
- struct mapentry *next; /**< next entry in list */
-};
-
-struct imagemap {
- char *key; /**< key for this entry */
- struct mapentry *list; /**< pointer to linked list of entries */
- struct imagemap *next; /**< next entry in this hash chain */
-};
-
-/**
- * Create hashtable of imagemaps
- *
- * \param c The containing content
- * \return true on success, false otherwise
- */
-static bool imagemap_create(html_content *c)
-{
- assert(c != NULL);
-
- if (c->imagemaps == NULL) {
- c->imagemaps = calloc(HASH_SIZE, sizeof(struct imagemap *));
- if (c->imagemaps == NULL) {
- return false;
- }
- }
-
- return true;
-}
-
-/**
- * Hash function.
- *
- * \param key The key to hash.
- * \return The hashed value.
- */
-static unsigned int imagemap_hash(const char *key)
-{
- unsigned int z = 0;
-
- if (key == 0) return 0;
-
- for (; *key != 0; key++) {
- z += *key & 0x1f;
- }
-
- return (z % (HASH_SIZE - 1)) + 1;
-}
-
-/**
- * Add an imagemap to the hashtable, creating it if it doesn't exist
- *
- * \param c The containing content
- * \param key The name of the imagemap
- * \param list List of map regions
- * \return true on succes, false otherwise
- */
-static bool
-imagemap_add(html_content *c, dom_string *key, struct mapentry *list)
-{
- struct imagemap *map;
- unsigned int slot;
-
- assert(c != NULL);
- assert(key != NULL);
- assert(list != NULL);
-
- if (imagemap_create(c) == false)
- return false;
-
- map = calloc(1, sizeof(*map));
- if (map == NULL)
- return false;
-
- /* \todo Stop relying on NULL termination of dom_string */
- map->key = strdup(dom_string_data(key));
- if (map->key == NULL) {
- free(map);
- return false;
- }
-
- map->list = list;
-
- slot = imagemap_hash(map->key);
-
- map->next = c->imagemaps[slot];
- c->imagemaps[slot] = map;
-
- return true;
-}
-
-/**
- * Free list of imagemap entries
- *
- * \param list Pointer to head of list
- */
-static void imagemap_freelist(struct mapentry *list)
-{
- struct mapentry *entry, *prev;
-
- assert(list != NULL);
-
- entry = list;
-
- while (entry != NULL) {
- prev = entry;
-
- nsurl_unref(entry->url);
-
- if (entry->target)
- free(entry->target);
-
- if (entry->type == IMAGEMAP_POLY) {
- free(entry->bounds.poly.xcoords);
- free(entry->bounds.poly.ycoords);
- }
-
- entry = entry->next;
- free(prev);
- }
-}
-
-/**
- * Destroy hashtable of imagemaps
- *
- * \param c The containing content
- */
-void imagemap_destroy(html_content *c)
-{
- unsigned int i;
-
- assert(c != NULL);
-
- /* no imagemaps -> return */
- if (c->imagemaps == NULL)
- return;
-
- for (i = 0; i != HASH_SIZE; i++) {
- struct imagemap *map, *next;
-
- map = c->imagemaps[i];
- while (map != NULL) {
- next = map->next;
- imagemap_freelist(map->list);
- free(map->key);
- free(map);
- map = next;
- }
- }
-
- free(c->imagemaps);
-}
-
-/**
- * Dump imagemap data to the log
- *
- * \param c The containing content
- */
-void imagemap_dump(html_content *c)
-{
- unsigned int i;
-
- int j;
-
- assert(c != NULL);
-
- if (c->imagemaps == NULL)
- return;
-
- for (i = 0; i != HASH_SIZE; i++) {
- struct imagemap *map;
- struct mapentry *entry;
-
- map = c->imagemaps[i];
- while (map != NULL) {
- NSLOG(netsurf, INFO, "Imagemap: %s", map->key);
-
- for (entry = map->list; entry; entry = entry->next) {
- switch (entry->type) {
- case IMAGEMAP_DEFAULT:
- NSLOG(netsurf, INFO, "\tDefault: %s",
- nsurl_access(entry->url));
- break;
- case IMAGEMAP_RECT:
- NSLOG(netsurf, INFO,
- "\tRectangle: %s: [(%d,%d),(%d,%d)]",
- nsurl_access(entry->url),
- entry->bounds.rect.x0,
- entry->bounds.rect.y0,
- entry->bounds.rect.x1,
- entry->bounds.rect.y1);
- break;
- case IMAGEMAP_CIRCLE:
- NSLOG(netsurf, INFO,
- "\tCircle: %s: [(%d,%d),%d]",
- nsurl_access(entry->url),
- entry->bounds.circle.x,
- entry->bounds.circle.y,
- entry->bounds.circle.r);
- break;
- case IMAGEMAP_POLY:
- NSLOG(netsurf, INFO,
- "\tPolygon: %s:",
- nsurl_access(entry->url));
- for (j = 0; j != entry->bounds.poly.num;
- j++) {
- fprintf(stderr, "(%d,%d) ",
- (int)entry->bounds.poly.xcoords[j],
- (int)entry->bounds.poly.ycoords[j]);
- }
- fprintf(stderr,"\n");
- break;
- }
- }
- map = map->next;
- }
- }
-}
-
-/**
- * Adds an imagemap entry to the list
- *
- * \param c The html content that the imagemap belongs to
- * \param n The xmlNode representing the entry to add
- * \param base_url Base URL for resolving relative URLs
- * \param entry Pointer to list of entries
- * \param tagtype The type of tag
- * \return false on memory exhaustion, true otherwise
- */
-static bool
-imagemap_addtolist(const struct html_content *c, dom_node *n, nsurl *base_url,
- struct mapentry **entry, dom_string *tagtype)
-{
- dom_exception exc;
- dom_string *href = NULL, *target = NULL, *shape = NULL;
- dom_string *coords = NULL;
- struct mapentry *new_map, *temp;
- bool ret = true;
-
- if (dom_string_caseless_isequal(tagtype, corestring_dom_area)) {
- bool nohref = false;
- exc = dom_element_has_attribute(n,
- corestring_dom_nohref, &nohref);
- if ((exc != DOM_NO_ERR) || nohref)
- /* Skip <area nohref="anything" /> */
- goto ok_out;
- }
-
- exc = dom_element_get_attribute(n, corestring_dom_href, &href);
- if (exc != DOM_NO_ERR || href == NULL) {
- /* No href="" attribute, skip this element */
- goto ok_out;
- }
-
- exc = dom_element_get_attribute(n, corestring_dom_target, &target);
- if (exc != DOM_NO_ERR) {
- goto ok_out;
- }
-
- exc = dom_element_get_attribute(n, corestring_dom_shape, &shape);
- if (exc != DOM_NO_ERR) {
- goto ok_out;
- }
-
- /* If there's no shape, we default to rectangles */
- if (shape == NULL)
- shape = dom_string_ref(corestring_dom_rect);
-
- if (!dom_string_caseless_lwc_isequal(shape, corestring_lwc_default)) {
- /* If not 'default' and there's no 'coords' give up */
- exc = dom_element_get_attribute(n, corestring_dom_coords,
- &coords);
- if (exc != DOM_NO_ERR || coords == NULL) {
- goto ok_out;
- }
- }
-
- new_map = calloc(1, sizeof(*new_map));
- if (new_map == NULL) {
- goto bad_out;
- }
-
- if (dom_string_caseless_lwc_isequal(shape, corestring_lwc_rect) ||
- dom_string_caseless_lwc_isequal(shape, corestring_lwc_rectangle))
- new_map->type = IMAGEMAP_RECT;
- else if (dom_string_caseless_lwc_isequal(shape, corestring_lwc_circle))
- new_map->type = IMAGEMAP_CIRCLE;
- else if (dom_string_caseless_lwc_isequal(shape, corestring_lwc_poly) ||
- dom_string_caseless_lwc_isequal(shape, corestring_lwc_polygon))
- new_map->type = IMAGEMAP_POLY;
- else if (dom_string_caseless_lwc_isequal(shape, corestring_lwc_default))
- new_map->type = IMAGEMAP_DEFAULT;
- else
- goto bad_out;
-
- if (box_extract_link(c, href, base_url, &new_map->url) == false)
- goto bad_out;
-
- if (new_map->url == NULL) {
- /* non-fatal error -> ignore this */
- goto ok_free_map_out;
- }
-
- if (target != NULL) {
- /* Copy target into the map */
- new_map->target = malloc(dom_string_byte_length(target) + 1);
- if (new_map->target == NULL)
- goto bad_out;
- /* Safe, but relies on dom_strings being NULL terminated */
- /* \todo Do this better */
- strcpy(new_map->target, dom_string_data(target));
- }
-
- if (new_map->type != IMAGEMAP_DEFAULT) {
- int x, y;
- float *xcoords, *ycoords;
- /* coordinates are a comma-separated list of values */
- char *val = strtok((char *)dom_string_data(coords), ",");
- int num = 1;
-
- switch (new_map->type) {
- case IMAGEMAP_RECT:
- /* (left, top, right, bottom) */
- while (val != NULL && num <= 4) {
- switch (num) {
- case 1:
- new_map->bounds.rect.x0 = atoi(val);
- break;
- case 2:
- new_map->bounds.rect.y0 = atoi(val);
- break;
- case 3:
- new_map->bounds.rect.x1 = atoi(val);
- break;
- case 4:
- new_map->bounds.rect.y1 = atoi(val);
- break;
- }
-
- num++;
- val = strtok(NULL, ",");
- }
- break;
- case IMAGEMAP_CIRCLE:
- /* (x, y, radius ) */
- while (val != NULL && num <= 3) {
- switch (num) {
- case 1:
- new_map->bounds.circle.x = atoi(val);
- break;
- case 2:
- new_map->bounds.circle.y = atoi(val);
- break;
- case 3:
- new_map->bounds.circle.r = atoi(val);
- break;
- }
-
- num++;
- val = strtok(NULL, ",");
- }
- break;
- case IMAGEMAP_POLY:
- new_map->bounds.poly.xcoords = NULL;
- new_map->bounds.poly.ycoords = NULL;
-
- while (val != NULL) {
- x = atoi(val);
-
- val = strtok(NULL, ",");
- if (val == NULL)
- break;
-
- y = atoi(val);
-
- xcoords = realloc(new_map->bounds.poly.xcoords,
- num * sizeof(float));
- if (xcoords == NULL) {
- goto bad_out;
- }
- new_map->bounds.poly.xcoords = xcoords;
-
- ycoords = realloc(new_map->bounds.poly.ycoords,
- num * sizeof(float));
- if (ycoords == NULL) {
- goto bad_out;
- }
- new_map->bounds.poly.ycoords = ycoords;
-
- new_map->bounds.poly.xcoords[num - 1] = x;
- new_map->bounds.poly.ycoords[num - 1] = y;
-
- num++;
- val = strtok(NULL, ",");
- }
-
- new_map->bounds.poly.num = num - 1;
-
- break;
- default:
- break;
- }
- }
-
- new_map->next = NULL;
-
- if (*entry) {
- /* add to END of list */
- for (temp = (*entry); temp->next != NULL; temp = temp->next)
- ;
- temp->next = new_map;
- } else {
- (*entry) = new_map;
- }
-
- /* All good, linked in, let's clean up */
- goto ok_out;
-
-bad_out:
- ret = false;
-ok_free_map_out:
- if (new_map != NULL) {
- if (new_map->url != NULL)
- nsurl_unref(new_map->url);
- if (new_map->type == IMAGEMAP_POLY &&
- new_map->bounds.poly.ycoords != NULL)
- free(new_map->bounds.poly.ycoords);
- if (new_map->type == IMAGEMAP_POLY &&
- new_map->bounds.poly.xcoords != NULL)
- free(new_map->bounds.poly.xcoords);
- if (new_map->target != NULL)
- free(new_map->target);
-
- free(new_map);
- }
-ok_out:
- if (href != NULL)
- dom_string_unref(href);
- if (target != NULL)
- dom_string_unref(target);
- if (shape != NULL)
- dom_string_unref(shape);
- if (coords != NULL)
- dom_string_unref(coords);
-
- return ret;
-}
-
-/**
- * Extract an imagemap from html source
- *
- * \param node XML node containing map
- * \param c Content containing document
- * \param entry List of map entries
- * \param tname The sub-tags to consider on this pass
- * \return false on memory exhaustion, true otherwise
- */
-static bool
-imagemap_extract_map_entries(dom_node *node, html_content *c,
- struct mapentry **entry, dom_string *tname)
-{
- dom_nodelist *nlist;
- dom_exception exc;
- unsigned long ent;
- uint32_t tag_count;
-
- exc = dom_element_get_elements_by_tag_name(node, tname, &nlist);
- if (exc != DOM_NO_ERR) {
- return false;
- }
-
- exc = dom_nodelist_get_length(nlist, &tag_count);
- if (exc != DOM_NO_ERR) {
- dom_nodelist_unref(nlist);
- return false;
- }
-
- for (ent = 0; ent < tag_count; ++ent) {
- dom_node *subnode;
-
- exc = dom_nodelist_item(nlist, ent, &subnode);
- if (exc != DOM_NO_ERR) {
- dom_nodelist_unref(nlist);
- return false;
- }
- if (imagemap_addtolist(c, subnode, c->base_url,
- entry, tname) == false) {
- dom_node_unref(subnode);
- dom_nodelist_unref(nlist);
- return false;
- }
- dom_node_unref(subnode);
- }
-
- dom_nodelist_unref(nlist);
-
- return true;
-}
-
-/**
- * Extract an imagemap from html source
- *
- * \param node XML node containing map
- * \param c Content containing document
- * \param entry List of map entries
- * \return false on memory exhaustion, true otherwise
- */
-static bool imagemap_extract_map(dom_node *node, html_content *c,
- struct mapentry **entry)
-{
- if (imagemap_extract_map_entries(node, c, entry,
- corestring_dom_area) == false)
- return false;
- return imagemap_extract_map_entries(node, c, entry,
- corestring_dom_a);
-}
-
-/**
- * Extract all imagemaps from a document tree
- *
- * \param c The content to extract imagemaps from.
- * \return false on memory exhaustion, true otherwise
- */
-nserror
-imagemap_extract(html_content *c)
-{
- dom_nodelist *nlist;
- dom_exception exc;
- unsigned long mapnr;
- uint32_t maybe_maps;
- nserror ret = NSERROR_OK;
-
- exc = dom_document_get_elements_by_tag_name(c->document,
- corestring_dom_map,
- &nlist);
- if (exc != DOM_NO_ERR) {
- return NSERROR_DOM;
- }
-
- exc = dom_nodelist_get_length(nlist, &maybe_maps);
- if (exc != DOM_NO_ERR) {
- ret = NSERROR_DOM;
- goto out_nlist;
- }
-
- for (mapnr = 0; mapnr < maybe_maps; ++mapnr) {
- dom_node *node;
- dom_string *name;
- exc = dom_nodelist_item(nlist, mapnr, &node);
- if (exc != DOM_NO_ERR) {
- ret = NSERROR_DOM;
- goto out_nlist;
- }
-
- exc = dom_element_get_attribute(node, corestring_dom_id,
- &name);
- if (exc != DOM_NO_ERR) {
- dom_node_unref(node);
- ret = NSERROR_DOM;
- goto out_nlist;
- }
-
- if (name == NULL) {
- exc = dom_element_get_attribute(node,
- corestring_dom_name,
- &name);
- if (exc != DOM_NO_ERR) {
- dom_node_unref(node);
- ret = NSERROR_DOM;
- goto out_nlist;
- }
- }
-
- if (name != NULL) {
- struct mapentry *entry = NULL;
- if (imagemap_extract_map(node, c, &entry) == false) {
- if (entry != NULL) {
- imagemap_freelist(entry);
- }
-
- dom_string_unref(name);
- dom_node_unref(node);
- ret = NSERROR_NOMEM; /** @todo check this */
- goto out_nlist;
- }
-
- /* imagemap_extract_map may not extract anything,
- * so entry can still be NULL here. This isn't an
- * error as it just means that we've encountered
- * an incorrectly defined <map>...</map> block
- */
- if ((entry != NULL) &&
- (imagemap_add(c, name, entry) == false)) {
- imagemap_freelist(entry);
-
- dom_string_unref(name);
- dom_node_unref(node);
- ret = NSERROR_NOMEM; /** @todo check this */
- goto out_nlist;
- }
- }
-
- dom_string_unref(name);
- dom_node_unref(node);
- }
-
-out_nlist:
-
- dom_nodelist_unref(nlist);
-
- return ret;
-}
-
-/**
- * Test if a point lies within an arbitrary polygon
- * Modified from comp.graphics.algorithms FAQ 2.03
- *
- * \param num Number of vertices
- * \param xpt Array of x coordinates
- * \param ypt Array of y coordinates
- * \param x Left hand edge of containing box
- * \param y Top edge of containing box
- * \param click_x X coordinate of click
- * \param click_y Y coordinate of click
- * \return 1 if point is in polygon, 0 if outside. 0 or 1 if on boundary
- */
-static int
-imagemap_point_in_poly(int num, float *xpt, float *ypt, unsigned long x,
- unsigned long y, unsigned long click_x, unsigned long click_y)
-{
- int i, j, c = 0;
-
- assert(xpt != NULL);
- assert(ypt != NULL);
-
- for (i = 0, j = num - 1; i < num; j = i++) {
- if ((((ypt[i] + y <= click_y) && (click_y < ypt[j] + y)) ||
- ((ypt[j] + y <= click_y) && (click_y < ypt[i] + y))) &&
- (click_x < (xpt[j] - xpt[i]) *
- (click_y - (ypt[i] + y)) / (ypt[j] - ypt[i]) + xpt[i] + x))
- c = !c;
- }
-
- return c;
-}
-
-/**
- * Retrieve url associated with imagemap entry
- *
- * \param c The containing content
- * \param key The map name to search for
- * \param x The left edge of the containing box
- * \param y The top edge of the containing box
- * \param click_x The horizontal location of the click
- * \param click_y The vertical location of the click
- * \param target Pointer to location to receive target pointer (if any)
- * \return The url associated with this area, or NULL if not found
- */
-nsurl *imagemap_get(struct html_content *c, const char *key,
- unsigned long x, unsigned long y,
- unsigned long click_x, unsigned long click_y,
- const char **target)
-{
- unsigned int slot = 0;
- struct imagemap *map;
- struct mapentry *entry;
- unsigned long cx, cy;
-
- assert(c != NULL);
-
- if (key == NULL)
- return NULL;
-
- if (c->imagemaps == NULL)
- return NULL;
-
- slot = imagemap_hash(key);
-
- for (map = c->imagemaps[slot]; map != NULL; map = map->next) {
- if (map->key != NULL && strcasecmp(map->key, key) == 0)
- break;
- }
-
- if (map == NULL || map->list == NULL)
- return NULL;
-
- for (entry = map->list; entry; entry = entry->next) {
- switch (entry->type) {
- case IMAGEMAP_DEFAULT:
- /* just return the URL. no checks required */
- if (target)
- *target = entry->target;
- return entry->url;
- break;
- case IMAGEMAP_RECT:
- if (click_x >= x + entry->bounds.rect.x0 &&
- click_x <= x + entry->bounds.rect.x1 &&
- click_y >= y + entry->bounds.rect.y0 &&
- click_y <= y + entry->bounds.rect.y1) {
- if (target)
- *target = entry->target;
- return entry->url;
- }
- break;
- case IMAGEMAP_CIRCLE:
- cx = x + entry->bounds.circle.x - click_x;
- cy = y + entry->bounds.circle.y - click_y;
- if ((cx * cx + cy * cy) <=
- (unsigned long) (entry->bounds.circle.r *
- entry->bounds.circle.r)) {
- if (target)
- *target = entry->target;
- return entry->url;
- }
- break;
- case IMAGEMAP_POLY:
- if (imagemap_point_in_poly(entry->bounds.poly.num,
- entry->bounds.poly.xcoords,
- entry->bounds.poly.ycoords, x, y,
- click_x, click_y)) {
- if (target)
- *target = entry->target;
- return entry->url;
- }
- break;
- }
- }
-
- if (target)
- *target = NULL;
-
- return NULL;
-}
diff --git a/render/imagemap.h b/render/imagemap.h
deleted file mode 100644
index 3ae6819da..000000000
--- a/render/imagemap.h
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * Copyright 2004 John M Bell <jmb202@ecs.soton.ac.uk>
- *
- * This file is part of NetSurf, http://www.netsurf-browser.org/
- *
- * NetSurf is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * NetSurf is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef _NETSURF_RENDER_IMAGEMAP_H_
-#define _NETSURF_RENDER_IMAGEMAP_H_
-
-#include <dom/dom.h>
-
-struct html_content;
-struct hlcache_handle;
-struct nsurl;
-
-void imagemap_destroy(struct html_content *c);
-void imagemap_dump(struct html_content *c);
-nserror imagemap_extract(struct html_content *c);
-
-struct nsurl *imagemap_get(struct html_content *c, const char *key,
- unsigned long x, unsigned long y,
- unsigned long click_x, unsigned long click_y,
- const char **target);
-
-#endif
diff --git a/render/layout.c b/render/layout.c
deleted file mode 100644
index 121137adc..000000000
--- a/render/layout.c
+++ /dev/null
@@ -1,5432 +0,0 @@
-/*
- * Copyright 2005 Richard Wilson <info@tinct.net>
- * Copyright 2006 James Bursa <bursa@users.sourceforge.net>
- * Copyright 2008 Michael Drake <tlsa@netsurf-browser.org>
- * Copyright 2003 Phil Mellor <monkeyson@users.sourceforge.net>
- *
- * This file is part of NetSurf, http://www.netsurf-browser.org/
- *
- * NetSurf is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * NetSurf is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-/**
- * \file
- * HTML layout implementation.
- *
- * Layout is carried out in two stages:
- *
- * 1. + calculation of minimum / maximum box widths, and
- * + determination of whether block level boxes will have >zero height
- *
- * 2. + layout (position and dimensions)
- *
- * In most cases the functions for the two stages are a corresponding pair
- * layout_minmax_X() and layout_X().
- */
-
-#include <assert.h>
-#include <limits.h>
-#include <stdbool.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <math.h>
-#include <dom/dom.h>
-
-#include "utils/log.h"
-#include "utils/talloc.h"
-#include "utils/utils.h"
-#include "utils/nsoption.h"
-#include "netsurf/inttypes.h"
-#include "netsurf/content.h"
-#include "netsurf/browser_window.h"
-#include "netsurf/layout.h"
-#include "content/content_protected.h"
-#include "css/utils.h"
-#include "desktop/scrollbar.h"
-#include "desktop/textarea.h"
-
-#include "render/box.h"
-#include "render/font.h"
-#include "render/form_internal.h"
-#include "render/html_internal.h"
-#include "render/layout.h"
-#include "render/table.h"
-
-#define AUTO INT_MIN
-
-/* Fixed point percentage (a) of an integer (b), to an integer */
-#define FPCT_OF_INT_TOINT(a, b) (FIXTOINT(FDIV((a * b), F_100)))
-
-typedef uint8_t (*css_len_func)(
- const css_computed_style *style,
- css_fixed *length, css_unit *unit);
-typedef uint8_t (*css_border_style_func)(
- const css_computed_style *style);
-typedef uint8_t (*css_border_color_func)(
- const css_computed_style *style,
- css_color *color);
-
-/** Array of per-side access functions for computed style margins. */
-static const css_len_func margin_funcs[4] = {
- [TOP] = css_computed_margin_top,
- [RIGHT] = css_computed_margin_right,
- [BOTTOM] = css_computed_margin_bottom,
- [LEFT] = css_computed_margin_left,
-};
-
-/** Array of per-side access functions for computed style paddings. */
-static const css_len_func padding_funcs[4] = {
- [TOP] = css_computed_padding_top,
- [RIGHT] = css_computed_padding_right,
- [BOTTOM] = css_computed_padding_bottom,
- [LEFT] = css_computed_padding_left,
-};
-
-/** Array of per-side access functions for computed style border_widths. */
-static const css_len_func border_width_funcs[4] = {
- [TOP] = css_computed_border_top_width,
- [RIGHT] = css_computed_border_right_width,
- [BOTTOM] = css_computed_border_bottom_width,
- [LEFT] = css_computed_border_left_width,
-};
-
-/** Array of per-side access functions for computed style border styles. */
-static const css_border_style_func border_style_funcs[4] = {
- [TOP] = css_computed_border_top_style,
- [RIGHT] = css_computed_border_right_style,
- [BOTTOM] = css_computed_border_bottom_style,
- [LEFT] = css_computed_border_left_style,
-};
-
-/** Array of per-side access functions for computed style border colors. */
-static const css_border_color_func border_color_funcs[4] = {
- [TOP] = css_computed_border_top_color,
- [RIGHT] = css_computed_border_right_color,
- [BOTTOM] = css_computed_border_bottom_color,
- [LEFT] = css_computed_border_left_color,
-};
-
-/* forward declaration to break cycles */
-static bool layout_block_context(
- struct box *block,
- int viewport_height,
- html_content *content);
-static void layout_minmax_block(
- struct box *block,
- const struct gui_layout_table *font_func,
- const html_content *content);
-
-
-/**
- * Compute the size of replaced boxes with auto dimensions, according to
- * content.
- *
- * \param box Box with object
- * \param width Width value in px or AUTO. If AUTO, updated to value in px.
- * \param height Height value in px or AUTO. If AUTO, updated to value in px.
- * \param min_width Box's min width, as given by layout_find_dimensions.
- * \param max_width Box's max width, as given by layout_find_dimensions.
- * \param min_height Box's min height, as given by layout_find_dimensions.
- * \param max_height Box's max height, as given by layout_find_dimensions.
- *
- * See CSS 2.1 sections 10.3 and 10.6.
- */
-static void
-layout_get_object_dimensions(struct box *box,
- int *width, int *height,
- int min_width, int max_width,
- int min_height, int max_height)
-{
- assert(box->object != NULL);
- assert(width != NULL && height != NULL);
-
- if (*width == AUTO && *height == AUTO) {
- /* No given dimensions */
-
- bool scaled = false;
- int intrinsic_width = content_get_width(box->object);
- int intrinsic_height = content_get_height(box->object);
-
- /* use intrinsic dimensions */
- *width = intrinsic_width;
- *height = intrinsic_height;
-
- /* Deal with min/max-width first */
- if (min_width > 0 && min_width > *width) {
- *width = min_width;
- scaled = true;
- }
- if (max_width >= 0 && max_width < *width) {
- *width = max_width;
- scaled = true;
- }
-
- if (scaled && (intrinsic_width != 0)) {
- /* Update height */
- *height = (*width * intrinsic_height) /
- intrinsic_width;
- }
-
- scaled = false;
- /* Deal with min/max-height */
- if (min_height > 0 && min_height > *height) {
- *height = min_height;
- scaled = true;
- }
- if (max_height >= 0 && max_height < *height) {
- *height = max_height;
- scaled = true;
- }
-
- if (scaled && (intrinsic_height != 0)) {
- /* Update width */
- *width = (*height * intrinsic_width) /
- intrinsic_height;
- }
-
- } else if (*width == AUTO) {
- /* Have given height; width is calculated from the given height
- * and ratio of intrinsic dimensions */
- int intrinsic_width = content_get_width(box->object);
- int intrinsic_height = content_get_height(box->object);
-
- if (intrinsic_height != 0)
- *width = (*height * intrinsic_width) /
- intrinsic_height;
- else
- *width = intrinsic_width;
-
- if (min_width > 0 && min_width > *width)
- *width = min_width;
- if (max_width >= 0 && max_width < *width)
- *width = max_width;
-
- } else if (*height == AUTO) {
- /* Have given width; height is calculated from the given width
- * and ratio of intrinsic dimensions */
- int intrinsic_width = content_get_width(box->object);
- int intrinsic_height = content_get_height(box->object);
-
- if (intrinsic_width != 0)
- *height = (*width * intrinsic_height) /
- intrinsic_width;
- else
- *height = intrinsic_height;
- }
-}
-
-
-/**
- * Calculate the text-indent length.
- *
- * \param style style of block
- * \param width width of containing block
- * \return length of indent
- */
-static int layout_text_indent(
- const nscss_len_ctx *len_ctx,
- const css_computed_style *style, int width)
-{
- css_fixed value = 0;
- css_unit unit = CSS_UNIT_PX;
-
- css_computed_text_indent(style, &value, &unit);
-
- if (unit == CSS_UNIT_PCT) {
- return FPCT_OF_INT_TOINT(value, width);
- } else {
- return FIXTOINT(nscss_len2px(len_ctx, value, unit, style));
- }
-}
-
-
-/**
- * Determine width of margin, borders, and padding on one side of a box.
- *
- * \param len_ctx CSS length conversion context for document
- * \param style style to measure
- * \param side side of box to measure
- * \param margin whether margin width is required
- * \param border whether border width is required
- * \param padding whether padding width is required
- * \param fixed increased by sum of fixed margin, border, and padding
- * \param frac increased by sum of fractional margin and padding
- */
-static void
-calculate_mbp_width(const nscss_len_ctx *len_ctx,
- const css_computed_style *style,
- unsigned int side,
- bool margin,
- bool border,
- bool padding,
- int *fixed,
- float *frac)
-{
- css_fixed value = 0;
- css_unit unit = CSS_UNIT_PX;
-
- assert(style);
-
- /* margin */
- if (margin) {
- enum css_margin_e type;
-
- type = margin_funcs[side](style, &value, &unit);
- if (type == CSS_MARGIN_SET) {
- if (unit == CSS_UNIT_PCT) {
- *frac += FIXTOINT(FDIV(value, F_100));
- } else {
- *fixed += FIXTOINT(nscss_len2px(len_ctx,
- value, unit, style));
- }
- }
- }
-
- /* border */
- if (border) {
- if (border_style_funcs[side](style) !=
- CSS_BORDER_STYLE_NONE) {
- border_width_funcs[side](style, &value, &unit);
-
- *fixed += FIXTOINT(nscss_len2px(len_ctx,
- value, unit, style));
- }
- }
-
- /* padding */
- if (padding) {
- padding_funcs[side](style, &value, &unit);
- if (unit == CSS_UNIT_PCT) {
- *frac += FIXTOINT(FDIV(value, F_100));
- } else {
- *fixed += FIXTOINT(nscss_len2px(len_ctx,
- value, unit, style));
- }
- }
-}
-
-
-/**
- * Calculate minimum and maximum width of a table.
- *
- * \param table box of type TABLE
- * \param font_func Font functions
- * \param content The HTML content we are laying out.
- * \post table->min_width and table->max_width filled in,
- * 0 <= table->min_width <= table->max_width
- */
-static void layout_minmax_table(struct box *table,
- const struct gui_layout_table *font_func,
- const html_content *content)
-{
- unsigned int i, j;
- int border_spacing_h = 0;
- int table_min = 0, table_max = 0;
- int extra_fixed = 0;
- float extra_frac = 0;
- struct column *col;
- struct box *row_group, *row, *cell;
- enum css_width_e wtype;
- css_fixed value = 0;
- css_unit unit = CSS_UNIT_PX;
-
- /* check if the widths have already been calculated */
- if (table->max_width != UNKNOWN_MAX_WIDTH)
- return;
-
- if (table_calculate_column_types(&content->len_ctx, table) == false) {
- NSLOG(netsurf, WARNING,
- "Could not establish table column types.");
- return;
- }
- col = table->col;
-
- /* start with 0 except for fixed-width columns */
- for (i = 0; i != table->columns; i++) {
- if (col[i].type == COLUMN_WIDTH_FIXED)
- col[i].min = col[i].max = col[i].width;
- else
- col[i].min = col[i].max = 0;
- }
-
- /* border-spacing is used in the separated borders model */
- if (css_computed_border_collapse(table->style) ==
- CSS_BORDER_COLLAPSE_SEPARATE) {
- css_fixed h = 0, v = 0;
- css_unit hu = CSS_UNIT_PX, vu = CSS_UNIT_PX;
-
- css_computed_border_spacing(table->style, &h, &hu, &v, &vu);
-
- border_spacing_h = FIXTOINT(nscss_len2px(&content->len_ctx,
- h, hu, table->style));
- }
-
- /* 1st pass: consider cells with colspan 1 only */
- for (row_group = table->children; row_group; row_group =row_group->next)
- for (row = row_group->children; row; row = row->next)
- for (cell = row->children; cell; cell = cell->next) {
- assert(cell->type == BOX_TABLE_CELL);
- assert(cell->style);
- /** TODO: Handle colspan="0" correctly.
- * It's currently converted to 1 in box normaisation */
- assert(cell->columns != 0);
-
- if (cell->columns != 1)
- continue;
-
- layout_minmax_block(cell, font_func, content);
- i = cell->start_column;
-
- if (col[i].positioned)
- continue;
-
- /* update column min, max widths using cell widths */
- if (col[i].min < cell->min_width)
- col[i].min = cell->min_width;
- if (col[i].max < cell->max_width)
- col[i].max = cell->max_width;
- }
-
- /* 2nd pass: cells which span multiple columns */
- for (row_group = table->children; row_group; row_group =row_group->next)
- for (row = row_group->children; row; row = row->next)
- for (cell = row->children; cell; cell = cell->next) {
- unsigned int flexible_columns = 0;
- int min = 0, max = 0, fixed_width = 0, extra;
-
- if (cell->columns == 1)
- continue;
-
- layout_minmax_block(cell, font_func, content);
- i = cell->start_column;
-
- /* find min width so far of spanned columns, and count
- * number of non-fixed spanned columns and total fixed width */
- for (j = 0; j != cell->columns; j++) {
- min += col[i + j].min;
- if (col[i + j].type == COLUMN_WIDTH_FIXED)
- fixed_width += col[i + j].width;
- else
- flexible_columns++;
- }
- min += (cell->columns - 1) * border_spacing_h;
-
- /* distribute extra min to spanned columns */
- if (min < cell->min_width) {
- if (flexible_columns == 0) {
- extra = 1 + (cell->min_width - min) /
- cell->columns;
- for (j = 0; j != cell->columns; j++) {
- col[i + j].min += extra;
- if (col[i + j].max < col[i + j].min)
- col[i + j].max = col[i + j].min;
- }
- } else {
- extra = 1 + (cell->min_width - min) /
- flexible_columns;
- for (j = 0; j != cell->columns; j++) {
- if (col[i + j].type !=
- COLUMN_WIDTH_FIXED) {
- col[i + j].min += extra;
- if (col[i + j].max <
- col[i + j].min)
- col[i + j].max =
- col[i + j].min;
- }
- }
- }
- }
-
- /* find max width so far of spanned columns */
- for (j = 0; j != cell->columns; j++)
- max += col[i + j].max;
- max += (cell->columns - 1) * border_spacing_h;
-
- /* distribute extra max to spanned columns */
- if (max < cell->max_width && flexible_columns) {
- extra = 1 + (cell->max_width - max) / flexible_columns;
- for (j = 0; j != cell->columns; j++)
- if (col[i + j].type != COLUMN_WIDTH_FIXED)
- col[i + j].max += extra;
- }
- }
-
- for (i = 0; i != table->columns; i++) {
- if (col[i].max < col[i].min) {
- box_dump(stderr, table, 0, true);
- assert(0);
- }
- table_min += col[i].min;
- table_max += col[i].max;
- }
-
- /* fixed width takes priority, unless it is too narrow */
- wtype = css_computed_width(table->style, &value, &unit);
- if (wtype == CSS_WIDTH_SET && unit != CSS_UNIT_PCT) {
- int width = FIXTOINT(nscss_len2px(&content->len_ctx,
- value, unit, table->style));
- if (table_min < width)
- table_min = width;
- if (table_max < width)
- table_max = width;
- }
-
- /* add margins, border, padding to min, max widths */
- calculate_mbp_width(&content->len_ctx,
- table->style, LEFT, true, true, true,
- &extra_fixed, &extra_frac);
- calculate_mbp_width(&content->len_ctx,
- table->style, RIGHT, true, true, true,
- &extra_fixed, &extra_frac);
- if (extra_fixed < 0)
- extra_fixed = 0;
- if (extra_frac < 0)
- extra_frac = 0;
- if (1.0 <= extra_frac)
- extra_frac = 0.9;
- table->min_width = (table_min + extra_fixed) / (1.0 - extra_frac);
- table->max_width = (table_max + extra_fixed) / (1.0 - extra_frac);
- table->min_width += (table->columns + 1) * border_spacing_h;
- table->max_width += (table->columns + 1) * border_spacing_h;
-
- assert(0 <= table->min_width && table->min_width <= table->max_width);
-}
-
-/**
- * Helper to check if a box has percentage max width.
- *
- * \param[in] b Box to check.
- * \return true iff box has percnetage max width.
- */
-static inline bool box_has_percentage_max_width(struct box *b)
-{
- css_unit unit = CSS_UNIT_PX;
- enum css_max_width_e type;
- css_fixed value = 0;
-
- assert(b != NULL);
-
- type = css_computed_max_width(b->style, &value, &unit);
- return ((type == CSS_MAX_WIDTH_SET) && (unit == CSS_UNIT_PCT));
-}
-
-/**
- * Calculate minimum and maximum width of a line.
- *
- * \param first a box in an inline container
- * \param line_min updated to minimum width of line starting at first
- * \param line_max updated to maximum width of line starting at first
- * \param first_line true iff this is the first line in the inline container
- * \param line_has_height updated to true or false, depending on line
- * \param font_func Font functions.
- * \return first box in next line, or 0 if no more lines
- * \post 0 <= *line_min <= *line_max
- */
-static struct box *
-layout_minmax_line(struct box *first,
- int *line_min,
- int *line_max,
- bool first_line,
- bool *line_has_height,
- const struct gui_layout_table *font_func,
- const html_content *content)
-{
- int min = 0, max = 0, width, height, fixed;
- float frac;
- size_t i, j;
- struct box *b;
- struct box *block;
- plot_font_style_t fstyle;
- bool no_wrap;
-
- assert(first->parent);
- assert(first->parent->parent);
- assert(first->parent->parent->style);
-
- block = first->parent->parent;
- no_wrap = (css_computed_white_space(block->style) ==
- CSS_WHITE_SPACE_NOWRAP ||
- css_computed_white_space(block->style) ==
- CSS_WHITE_SPACE_PRE);
-
- *line_has_height = false;
-
- /* corresponds to the pass 1 loop in layout_line() */
- for (b = first; b; b = b->next) {
- enum css_width_e wtype;
- enum css_height_e htype;
- enum css_box_sizing_e bs;
- css_fixed value = 0;
- css_unit unit = CSS_UNIT_PX;
-
- assert(b->type == BOX_INLINE || b->type == BOX_INLINE_BLOCK ||
- b->type == BOX_FLOAT_LEFT ||
- b->type == BOX_FLOAT_RIGHT ||
- b->type == BOX_BR || b->type == BOX_TEXT ||
- b->type == BOX_INLINE_END);
-
- NSLOG(layout, DEBUG, "%p: min %i, max %i", b, min, max);
-
- if (b->type == BOX_BR) {
- b = b->next;
- break;
- }
-
- if (b->type == BOX_FLOAT_LEFT || b->type == BOX_FLOAT_RIGHT) {
- assert(b->children);
- if (b->children->type == BOX_BLOCK)
- layout_minmax_block(b->children, font_func,
- content);
- else
- layout_minmax_table(b->children, font_func,
- content);
- b->min_width = b->children->min_width;
- b->max_width = b->children->max_width;
- if (min < b->min_width)
- min = b->min_width;
- max += b->max_width;
- continue;
- }
-
- if (b->type == BOX_INLINE_BLOCK) {
- layout_minmax_block(b, font_func, content);
- if (min < b->min_width)
- min = b->min_width;
- max += b->max_width;
-
- if (b->flags & HAS_HEIGHT)
- *line_has_height = true;
- continue;
- }
-
- assert(b->style);
- font_plot_style_from_css(&content->len_ctx, b->style, &fstyle);
-
- if (b->type == BOX_INLINE && !b->object &&
- !(b->flags & REPLACE_DIM) &&
- !(b->flags & IFRAME)) {
- fixed = frac = 0;
- calculate_mbp_width(&content->len_ctx,
- b->style, LEFT, true, true, true,
- &fixed, &frac);
- if (!b->inline_end)
- calculate_mbp_width(&content->len_ctx,
- b->style, RIGHT,
- true, true, true,
- &fixed, &frac);
- if (0 < fixed)
- max += fixed;
- *line_has_height = true;
- /* \todo update min width, consider fractional extra */
- } else if (b->type == BOX_INLINE_END) {
- fixed = frac = 0;
- calculate_mbp_width(&content->len_ctx,
- b->inline_end->style, RIGHT,
- true, true, true,
- &fixed, &frac);
- if (0 < fixed)
- max += fixed;
-
- if (b->next) {
- if (b->space == UNKNOWN_WIDTH) {
- font_func->width(&fstyle, " ", 1,
- &b->space);
- }
- max += b->space;
- }
-
- *line_has_height = true;
- continue;
- }
-
- if (!b->object && !(b->flags & IFRAME) && !b->gadget &&
- !(b->flags & REPLACE_DIM)) {
- /* inline non-replaced, 10.3.1 and 10.6.1 */
- bool no_wrap_box;
- if (!b->text)
- continue;
-
- no_wrap_box = (css_computed_white_space(b->style) ==
- CSS_WHITE_SPACE_NOWRAP ||
- css_computed_white_space(b->style) ==
- CSS_WHITE_SPACE_PRE);
-
- if (b->width == UNKNOWN_WIDTH) {
- /** \todo handle errors */
-
- /* If it's a select element, we must use the
- * width of the widest option text */
- if (b->parent->parent->gadget &&
- b->parent->parent->gadget->type
- == GADGET_SELECT) {
- int opt_maxwidth = 0;
- struct form_option *o;
-
- for (o = b->parent->parent->gadget->
- data.select.items; o;
- o = o->next) {
- int opt_width;
- font_func->width(&fstyle,
- o->text,
- strlen(o->text),
- &opt_width);
-
- if (opt_maxwidth < opt_width)
- opt_maxwidth =opt_width;
- }
-
- b->width = opt_maxwidth;
- if (nsoption_bool(core_select_menu))
- b->width += SCROLLBAR_WIDTH;
-
- } else {
- font_func->width(&fstyle, b->text,
- b->length, &b->width);
- b->flags |= MEASURED;
- }
- }
- max += b->width;
- if (b->next) {
- if (b->space == UNKNOWN_WIDTH) {
- font_func->width(&fstyle, " ", 1,
- &b->space);
- }
- max += b->space;
- }
-
- if (no_wrap) {
- /* Don't wrap due to block style,
- * so min is the same as max */
- min = max;
-
- } else if (no_wrap_box) {
- /* This inline box can't be wrapped,
- * for min, consider box's width */
- if (min < b->width)
- min = b->width;
-
- } else if (b->parent->flags & NEED_MIN) {
- /* If we care what the minimum width is,
- * calculate it. (It's only needed if we're
- * shrinking-to-fit.) */
- /* min = widest single word */
- i = 0;
- do {
- for (j = i; j != b->length &&
- b->text[j] != ' '; j++)
- ;
- font_func->width(&fstyle, b->text + i,
- j - i, &width);
- if (min < width)
- min = width;
- i = j + 1;
- } while (j != b->length);
- }
-
- *line_has_height = true;
-
- continue;
- }
-
- /* inline replaced, 10.3.2 and 10.6.2 */
- assert(b->style);
-
- /* calculate box width */
- wtype = css_computed_width(b->style, &value, &unit);
- bs = css_computed_box_sizing(block->style);
- if (wtype == CSS_WIDTH_SET) {
- if (unit == CSS_UNIT_PCT) {
- width = AUTO;
- } else {
- width = FIXTOINT(nscss_len2px(&content->len_ctx,
- value, unit, b->style));
-
- if (bs == CSS_BOX_SIZING_BORDER_BOX) {
- fixed = frac = 0;
- calculate_mbp_width(&content->len_ctx,
- block->style, LEFT,
- false, true, true,
- &fixed, &frac);
- calculate_mbp_width(&content->len_ctx,
- block->style, RIGHT,
- false, true, true,
- &fixed, &frac);
- if (width < fixed) {
- width = fixed;
- }
- }
- if (width < 0)
- width = 0;
- }
- } else {
- width = AUTO;
- }
-
- /* height */
- htype = css_computed_height(b->style, &value, &unit);
- if (htype == CSS_HEIGHT_SET) {
- height = FIXTOINT(nscss_len2px(&content->len_ctx,
- value, unit, b->style));
- } else {
- height = AUTO;
- }
-
- if (b->object || (b->flags & REPLACE_DIM)) {
- if (b->object) {
- int temp_height = height;
- layout_get_object_dimensions(b,
- &width, &temp_height,
- INT_MIN, INT_MAX,
- INT_MIN, INT_MAX);
- }
-
- fixed = frac = 0;
- if (bs == CSS_BOX_SIZING_BORDER_BOX) {
- calculate_mbp_width(&content->len_ctx,
- b->style, LEFT,
- true, false, false,
- &fixed, &frac);
- calculate_mbp_width(&content->len_ctx,
- b->style, RIGHT,
- true, false, false,
- &fixed, &frac);
- } else {
- calculate_mbp_width(&content->len_ctx,
- b->style, LEFT,
- true, true, true,
- &fixed, &frac);
- calculate_mbp_width(&content->len_ctx,
- b->style, RIGHT,
- true, true, true,
- &fixed, &frac);
- }
- if (0 < width + fixed)
- width += fixed;
- } else if (b->flags & IFRAME) {
- /* TODO: handle percentage widths properly */
- if (width == AUTO)
- width = 400;
-
- fixed = frac = 0;
- if (bs == CSS_BOX_SIZING_BORDER_BOX) {
- calculate_mbp_width(&content->len_ctx,
- b->style, LEFT,
- true, false, false,
- &fixed, &frac);
- calculate_mbp_width(&content->len_ctx,
- b->style, RIGHT,
- true, false, false,
- &fixed, &frac);
- } else {
- calculate_mbp_width(&content->len_ctx,
- b->style, LEFT,
- true, true, true,
- &fixed, &frac);
- calculate_mbp_width(&content->len_ctx,
- b->style, RIGHT,
- true, true, true,
- &fixed, &frac);
- }
-
- if (0 < width + fixed)
- width += fixed;
-
- } else {
- /* form control with no object */
- if (width == AUTO)
- width = FIXTOINT(nscss_len2px(
- &content->len_ctx,
- INTTOFIX(1), CSS_UNIT_EM,
- b->style));
- }
-
- if (min < width && !box_has_percentage_max_width(b))
- min = width;
- if (width > 0)
- max += width;
-
- *line_has_height = true;
- }
-
- if (first_line) {
- /* todo: handle percentage values properly */
- /* todo: handle text-indent interaction with floats */
- int text_indent = layout_text_indent(&content->len_ctx,
- first->parent->parent->style, 100);
- min = (min + text_indent < 0) ? 0 : min + text_indent;
- max = (max + text_indent < 0) ? 0 : max + text_indent;
- }
-
- *line_min = min;
- *line_max = max;
-
- NSLOG(layout, DEBUG, "line_min %i, line_max %i", min, max);
-
- assert(b != first);
- assert(0 <= *line_min);
- assert(*line_min <= *line_max);
- return b;
-}
-
-
-/**
- * Calculate minimum and maximum width of an inline container.
- *
- * \param inline_container box of type INLINE_CONTAINER
- * \param[out] has_height set to true if container has height
- * \param font_func Font functions.
- * \post inline_container->min_width and inline_container->max_width filled in,
- * 0 <= inline_container->min_width <= inline_container->max_width
- */
-static void
-layout_minmax_inline_container(struct box *inline_container,
- bool *has_height,
- const struct gui_layout_table *font_func,
- const html_content *content)
-{
- struct box *child;
- int line_min = 0, line_max = 0;
- int min = 0, max = 0;
- bool first_line = true;
- bool line_has_height;
-
- assert(inline_container->type == BOX_INLINE_CONTAINER);
-
- /* check if the widths have already been calculated */
- if (inline_container->max_width != UNKNOWN_MAX_WIDTH)
- return;
-
- *has_height = false;
-
- for (child = inline_container->children; child; ) {
- child = layout_minmax_line(child, &line_min, &line_max,
- first_line, &line_has_height, font_func,
- content);
- if (min < line_min)
- min = line_min;
- if (max < line_max)
- max = line_max;
- first_line = false;
- *has_height |= line_has_height;
- }
-
- inline_container->min_width = min;
- inline_container->max_width = max;
-
- assert(0 <= inline_container->min_width &&
- inline_container->min_width <=
- inline_container->max_width);
-}
-
-
-/**
- * Calculate minimum and maximum width of a block.
- *
- * \param block box of type BLOCK, INLINE_BLOCK, or TABLE_CELL
- * \param font_func font functions
- * \param content The HTML content being layed out.
- * \post block->min_width and block->max_width filled in,
- * 0 <= block->min_width <= block->max_width
- */
-static void layout_minmax_block(
- struct box *block,
- const struct gui_layout_table *font_func,
- const html_content *content)
-{
- struct box *child;
- int min = 0, max = 0;
- int extra_fixed = 0;
- float extra_frac = 0;
- enum css_width_e wtype = CSS_WIDTH_AUTO;
- css_fixed width = 0;
- css_unit wunit = CSS_UNIT_PX;
- enum css_height_e htype = CSS_HEIGHT_AUTO;
- css_fixed height = 0;
- css_unit hunit = CSS_UNIT_PX;
- enum css_box_sizing_e bs = CSS_BOX_SIZING_CONTENT_BOX;
- bool child_has_height = false;
-
- assert(block->type == BOX_BLOCK ||
- block->type == BOX_INLINE_BLOCK ||
- block->type == BOX_TABLE_CELL);
-
- /* check if the widths have already been calculated */
- if (block->max_width != UNKNOWN_MAX_WIDTH)
- return;
-
- if (block->style != NULL) {
- wtype = css_computed_width(block->style, &width, &wunit);
- htype = css_computed_height(block->style, &height, &hunit);
- bs = css_computed_box_sizing(block->style);
- }
-
- /* set whether the minimum width is of any interest for this box */
- if (((block->parent && (block->parent->type == BOX_FLOAT_LEFT ||
- block->parent->type == BOX_FLOAT_RIGHT)) ||
- block->type == BOX_INLINE_BLOCK) &&
- wtype != CSS_WIDTH_SET) {
- /* box shrinks to fit; need minimum width */
- block->flags |= NEED_MIN;
- } else if (block->type == BOX_TABLE_CELL) {
- /* box shrinks to fit; need minimum width */
- block->flags |= NEED_MIN;
- } else if (block->parent && (block->parent->flags & NEED_MIN) &&
- wtype != CSS_WIDTH_SET) {
- /* box inside shrink-to-fit context; need minimum width */
- block->flags |= NEED_MIN;
- }
-
- if (block->gadget && (block->gadget->type == GADGET_TEXTBOX ||
- block->gadget->type == GADGET_PASSWORD ||
- block->gadget->type == GADGET_FILE ||
- block->gadget->type == GADGET_TEXTAREA) &&
- block->style && wtype == CSS_WIDTH_AUTO) {
- css_fixed size = INTTOFIX(10);
- css_unit unit = CSS_UNIT_EM;
-
- min = max = FIXTOINT(nscss_len2px(&content->len_ctx,
- size, unit, block->style));
-
- block->flags |= HAS_HEIGHT;
- }
-
- if (block->gadget && (block->gadget->type == GADGET_RADIO ||
- block->gadget->type == GADGET_CHECKBOX) &&
- block->style && wtype == CSS_WIDTH_AUTO) {
- css_fixed size = INTTOFIX(1);
- css_unit unit = CSS_UNIT_EM;
-
- /* form checkbox or radio button
- * if width is AUTO, set it to 1em */
- min = max = FIXTOINT(nscss_len2px(&content->len_ctx,
- size, unit, block->style));
-
- block->flags |= HAS_HEIGHT;
- }
-
- if (block->object) {
- if (content_get_type(block->object) == CONTENT_HTML) {
- layout_minmax_block(html_get_box_tree(block->object),
- font_func, content);
- min = html_get_box_tree(block->object)->min_width;
- max = html_get_box_tree(block->object)->max_width;
- } else {
- min = max = content_get_width(block->object);
- }
-
- 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) {
- switch (child->type) {
- case BOX_BLOCK:
- layout_minmax_block(child, font_func,
- content);
- if (child->flags & HAS_HEIGHT)
- child_has_height = true;
- break;
- case BOX_INLINE_CONTAINER:
- if (block->flags & NEED_MIN)
- child->flags |= NEED_MIN;
-
- layout_minmax_inline_container(child,
- &child_has_height, font_func,
- content);
- if (child_has_height &&
- child ==
- child->parent->children) {
- block->flags |= MAKE_HEIGHT;
- }
- break;
- case BOX_TABLE:
- layout_minmax_table(child, font_func,
- content);
- /* todo: fix for zero height tables */
- child_has_height = true;
- child->flags |= MAKE_HEIGHT;
- break;
- default:
- assert(0);
- }
- assert(child->max_width != UNKNOWN_MAX_WIDTH);
-
- if (child->style &&
- (css_computed_position(child->style) ==
- CSS_POSITION_ABSOLUTE ||
- css_computed_position(child->style) ==
- CSS_POSITION_FIXED)) {
- /* This child is positioned out of normal flow,
- * so it will have no affect on width */
- continue;
- }
-
- if (min < child->min_width)
- min = child->min_width;
- if (max < child->max_width)
- max = child->max_width;
-
- if (child_has_height)
- block->flags |= HAS_HEIGHT;
- }
- }
-
- if (max < min) {
- box_dump(stderr, block, 0, true);
- assert(0);
- }
-
- /* fixed width takes priority */
- if (block->type != BOX_TABLE_CELL && wtype == CSS_WIDTH_SET &&
- wunit != CSS_UNIT_PCT) {
- min = max = FIXTOINT(nscss_len2px(&content->len_ctx,
- width, wunit, block->style));
- if (bs == CSS_BOX_SIZING_BORDER_BOX) {
- int border_box_fixed = 0;
- float border_box_frac = 0;
- calculate_mbp_width(&content->len_ctx,
- block->style, LEFT,
- false, true, true,
- &border_box_fixed, &border_box_frac);
- calculate_mbp_width(&content->len_ctx,
- block->style, RIGHT,
- false, true, true,
- &border_box_fixed, &border_box_frac);
- if (min < border_box_fixed) {
- min = max = border_box_fixed;
- }
- }
- }
-
- if (htype == CSS_HEIGHT_SET && hunit != CSS_UNIT_PCT &&
- height > INTTOFIX(0)) {
- block->flags |= MAKE_HEIGHT;
- block->flags |= HAS_HEIGHT;
- }
-
- /* add margins, border, padding to min, max widths */
- /* Note: we don't know available width here so percentage margin
- * and paddings are wrong. */
- if (bs == CSS_BOX_SIZING_BORDER_BOX && wtype == CSS_WIDTH_SET) {
- /* Border and padding included in width, so just get margin */
- calculate_mbp_width(&content->len_ctx,
- block->style, LEFT, true, false, false,
- &extra_fixed, &extra_frac);
- calculate_mbp_width(&content->len_ctx,
- block->style, RIGHT, true, false, false,
- &extra_fixed, &extra_frac);
- } else {
- calculate_mbp_width(&content->len_ctx,
- block->style, LEFT, true, true, true,
- &extra_fixed, &extra_frac);
- calculate_mbp_width(&content->len_ctx,
- block->style, RIGHT, true, true, true,
- &extra_fixed, &extra_frac);
- }
- if (extra_fixed < 0)
- extra_fixed = 0;
- if (extra_frac < 0)
- extra_frac = 0;
- if (1.0 <= extra_frac)
- extra_frac = 0.9;
- if (block->style != NULL &&
- (css_computed_float(block->style) == CSS_FLOAT_LEFT ||
- css_computed_float(block->style) == CSS_FLOAT_RIGHT)) {
- /* floated boxs */
- block->min_width = min + extra_fixed;
- block->max_width = max + extra_fixed;
- } else {
- /* not floated */
- block->min_width = (min + extra_fixed) / (1.0 - extra_frac);
- block->max_width = (max + extra_fixed) / (1.0 - extra_frac);
- }
-
- assert(0 <= block->min_width && block->min_width <= block->max_width);
-}
-
-
-/**
- * Adjust a specified width or height for the box-sizing property.
- *
- * This turns the specified dimension into a content-box dimension.
- *
- * \param len_ctx Length conversion context
- * \param box gadget to adjust dimensions of
- * \param available_width width of containing block
- * \param setwidth set true if the dimension to be tweaked is a width,
- * else set false for a height
- * \param dimension current value for given width/height dimension.
- * updated to new value after consideration of
- * gadget properties.
- */
-static void layout_handle_box_sizing(
- const nscss_len_ctx *len_ctx,
- struct box *box,
- int available_width,
- bool setwidth,
- int *dimension)
-{
- enum css_box_sizing_e bs;
-
- assert(box && box->style);
-
- bs = css_computed_box_sizing(box->style);
-
- if (bs == CSS_BOX_SIZING_BORDER_BOX) {
- int orig = *dimension;
- int fixed = 0;
- float frac = 0;
-
- calculate_mbp_width(len_ctx, box->style,
- setwidth ? LEFT : TOP,
- false, true, true, &fixed, &frac);
- calculate_mbp_width(len_ctx, box->style,
- setwidth ? RIGHT : BOTTOM,
- false, true, true, &fixed, &frac);
- orig -= frac * available_width + fixed;
- *dimension = orig > 0 ? orig : 0;
- }
-}
-
-
-/**
- * Calculate width, height, and thickness of margins, paddings, and borders.
- *
- * \param len_ctx Length conversion context
- * \param available_width width of containing block
- * \param viewport_height height of viewport in pixels or -ve if unknown
- * \param box current box
- * \param style style giving width, height, margins, paddings,
- * and borders
- * \param width updated to width, may be NULL
- * \param height updated to height, may be NULL
- * \param max_width updated to max-width, may be NULL
- * \param min_width updated to min-width, may be NULL
- * \param max_height updated to max-height, may be NULL
- * \param min_height updated to min-height, may be NULL
- * \param margin filled with margins, may be NULL
- * \param padding filled with paddings, may be NULL
- * \param border filled with border widths, may be NULL
- */
-static void
-layout_find_dimensions(const nscss_len_ctx *len_ctx,
- int available_width,
- int viewport_height,
- struct box *box,
- const css_computed_style *style,
- int *width,
- int *height,
- int *max_width,
- int *min_width,
- int *max_height,
- int *min_height,
- int margin[4],
- int padding[4],
- struct box_border border[4])
-{
- struct box *containing_block = NULL;
- unsigned int i;
-
- if (width) {
- enum css_width_e wtype;
- css_fixed value = 0;
- css_unit unit = CSS_UNIT_PX;
-
- wtype = css_computed_width(style, &value, &unit);
-
- if (wtype == CSS_WIDTH_SET) {
- if (unit == CSS_UNIT_PCT) {
- *width = FPCT_OF_INT_TOINT(
- value, available_width);
- } else {
- *width = FIXTOINT(nscss_len2px(len_ctx,
- value, unit, style));
- }
- } else {
- *width = AUTO;
- }
-
- if (*width != AUTO) {
- layout_handle_box_sizing(len_ctx, box, available_width,
- true, width);
- }
- }
-
- if (height) {
- enum css_height_e htype;
- css_fixed value = 0;
- css_unit unit = CSS_UNIT_PX;
-
- htype = css_computed_height(style, &value, &unit);
-
- if (htype == CSS_HEIGHT_SET) {
- if (unit == CSS_UNIT_PCT) {
- enum css_height_e cbhtype;
-
- if (css_computed_position(box->style) ==
- CSS_POSITION_ABSOLUTE &&
- box->parent) {
- /* Box is absolutely positioned */
- assert(box->float_container);
- containing_block = box->float_container;
- } else if (box->float_container &&
- css_computed_position(box->style) !=
- CSS_POSITION_ABSOLUTE &&
- (css_computed_float(box->style) ==
- CSS_FLOAT_LEFT ||
- css_computed_float(box->style) ==
- CSS_FLOAT_RIGHT)) {
- /* Box is a float */
- assert(box->parent &&
- box->parent->parent &&
- box->parent->parent->parent);
-
- containing_block =
- box->parent->parent->parent;
- } else if (box->parent && box->parent->type !=
- BOX_INLINE_CONTAINER) {
- /* Box is a block level element */
- containing_block = box->parent;
- } else if (box->parent && box->parent->type ==
- BOX_INLINE_CONTAINER) {
- /* Box is an inline block */
- assert(box->parent->parent);
- containing_block = box->parent->parent;
- }
-
- if (containing_block) {
- css_fixed f = 0;
- css_unit u = CSS_UNIT_PX;
-
- cbhtype = css_computed_height(
- containing_block->style,
- &f, &u);
- }
-
- if (containing_block &&
- containing_block->height != AUTO &&
- (css_computed_position(box->style) ==
- CSS_POSITION_ABSOLUTE ||
- cbhtype == CSS_HEIGHT_SET)) {
- /* Box is absolutely positioned or its
- * containing block has a valid
- * specified height.
- * (CSS 2.1 Section 10.5) */
- *height = FPCT_OF_INT_TOINT(value,
- containing_block->height);
- } else if ((!box->parent ||
- !box->parent->parent) &&
- viewport_height >= 0) {
- /* If root element or it's child
- * (HTML or BODY) */
- *height = FPCT_OF_INT_TOINT(value,
- viewport_height);
- } else {
- /* precentage height not permissible
- * treat height as auto */
- *height = AUTO;
- }
- } else {
- *height = FIXTOINT(nscss_len2px(len_ctx,
- value, unit, style));
- }
- } else {
- *height = AUTO;
- }
-
- if (*height != AUTO) {
- layout_handle_box_sizing(len_ctx, box, available_width,
- false, height);
- }
- }
-
- if (max_width) {
- enum css_max_width_e type;
- css_fixed value = 0;
- css_unit unit = CSS_UNIT_PX;
-
- type = css_computed_max_width(style, &value, &unit);
-
- if (type == CSS_MAX_WIDTH_SET) {
- if (unit == CSS_UNIT_PCT) {
- *max_width = FPCT_OF_INT_TOINT(value,
- available_width);
- } else {
- *max_width = FIXTOINT(nscss_len2px(len_ctx,
- value, unit, style));
- }
- } else {
- /* Inadmissible */
- *max_width = -1;
- }
-
- if (*max_width != -1) {
- layout_handle_box_sizing(len_ctx, box, available_width,
- true, max_width);
- }
- }
-
- if (min_width) {
- enum css_min_width_e type;
- css_fixed value = 0;
- css_unit unit = CSS_UNIT_PX;
-
- type = ns_computed_min_width(style, &value, &unit);
-
- if (type == CSS_MIN_WIDTH_SET) {
- if (unit == CSS_UNIT_PCT) {
- *min_width = FPCT_OF_INT_TOINT(value,
- available_width);
- } else {
- *min_width = FIXTOINT(nscss_len2px(len_ctx,
- value, unit, style));
- }
- } else {
- /* Inadmissible */
- *min_width = 0;
- }
-
- if (*min_width != 0) {
- layout_handle_box_sizing(len_ctx, box, available_width,
- true, min_width);
- }
- }
-
- if (max_height) {
- enum css_max_height_e type;
- css_fixed value = 0;
- css_unit unit = CSS_UNIT_PX;
-
- type = css_computed_max_height(style, &value, &unit);
-
- if (type == CSS_MAX_HEIGHT_SET) {
- if (unit == CSS_UNIT_PCT) {
- /* TODO: handle percentage */
- *max_height = -1;
- } else {
- *max_height = FIXTOINT(nscss_len2px(len_ctx,
- value, unit, style));
- }
- } else {
- /* Inadmissible */
- *max_height = -1;
- }
- }
-
- if (min_height) {
- enum css_min_height_e type;
- css_fixed value = 0;
- css_unit unit = CSS_UNIT_PX;
-
- type = ns_computed_min_height(style, &value, &unit);
-
- if (type == CSS_MIN_HEIGHT_SET) {
- if (unit == CSS_UNIT_PCT) {
- /* TODO: handle percentage */
- *min_height = 0;
- } else {
- *min_height = FIXTOINT(nscss_len2px(len_ctx,
- value, unit, style));
- }
- } else {
- /* Inadmissible */
- *min_height = 0;
- }
- }
-
- for (i = 0; i != 4; i++) {
- if (margin) {
- enum css_margin_e type = CSS_MARGIN_AUTO;
- css_fixed value = 0;
- css_unit unit = CSS_UNIT_PX;
-
- type = margin_funcs[i](style, &value, &unit);
-
- if (type == CSS_MARGIN_SET) {
- if (unit == CSS_UNIT_PCT) {
- margin[i] = FPCT_OF_INT_TOINT(value,
- available_width);
- } else {
- margin[i] = FIXTOINT(nscss_len2px(
- len_ctx,
- value, unit, style));
- }
- } else {
- margin[i] = AUTO;
- }
- }
-
- if (padding) {
- css_fixed value = 0;
- css_unit unit = CSS_UNIT_PX;
-
- padding_funcs[i](style, &value, &unit);
-
- if (unit == CSS_UNIT_PCT) {
- padding[i] = FPCT_OF_INT_TOINT(value,
- available_width);
- } else {
- padding[i] = FIXTOINT(nscss_len2px(len_ctx,
- value, unit, style));
- }
- }
-
- /* Table cell borders are populated in table.c */
- if (border && box->type != BOX_TABLE_CELL) {
- enum css_border_style_e bstyle = CSS_BORDER_STYLE_NONE;
- css_color color = 0;
- css_fixed value = 0;
- css_unit unit = CSS_UNIT_PX;
-
- border_width_funcs[i](style, &value, &unit);
- bstyle = border_style_funcs[i](style);
- border_color_funcs[i](style, &color);
-
- border[i].style = bstyle;
- border[i].c = color;
-
- if (bstyle == CSS_BORDER_STYLE_HIDDEN ||
- bstyle == CSS_BORDER_STYLE_NONE)
- /* spec unclear: following Mozilla */
- border[i].width = 0;
- else
- border[i].width = FIXTOINT(nscss_len2px(len_ctx,
- value, unit, style));
-
- /* Special case for border-collapse: make all borders
- * on table/table-row-group/table-row zero width. */
- if (css_computed_border_collapse(style) ==
- CSS_BORDER_COLLAPSE_COLLAPSE &&
- (box->type == BOX_TABLE ||
- box->type == BOX_TABLE_ROW_GROUP ||
- box->type == BOX_TABLE_ROW))
- border[i].width = 0;
- }
- }
-}
-
-
-/**
- * Find next block that current margin collapses to.
- *
- * \param len_ctx Length conversion context
- * \param box box to start tree-order search from (top margin is included)
- * \param block box responsible for current block fromatting context
- * \param viewport_height height of viewport in px
- * \param max_pos_margin updated to to maximum positive margin encountered
- * \param max_neg_margin updated to to maximum negative margin encountered
- * \return next box that current margin collapses to, or NULL if none.
- */
-static struct box*
-layout_next_margin_block(const nscss_len_ctx *len_ctx,
- struct box *box,
- struct box *block,
- int viewport_height,
- int *max_pos_margin,
- int *max_neg_margin)
-{
- assert(block != NULL);
-
- while (box != NULL) {
-
- if (box->type == BOX_INLINE_CONTAINER || (box->style &&
- (css_computed_position(box->style) !=
- CSS_POSITION_ABSOLUTE &&
- css_computed_position(box->style) !=
- CSS_POSITION_FIXED))) {
- /* Not positioned */
-
- /* Get margins */
- if (box->style) {
- layout_find_dimensions(len_ctx,
- box->parent->width,
- viewport_height, box,
- box->style,
- NULL, NULL, NULL, NULL,
- NULL, NULL, box->margin,
- box->padding, box->border);
-
- /* Apply top margin */
- if (*max_pos_margin < box->margin[TOP])
- *max_pos_margin = box->margin[TOP];
- else if (*max_neg_margin < -box->margin[TOP])
- *max_neg_margin = -box->margin[TOP];
- }
-
- /* Check whether box is the box current margin collapses
- * to */
- if (box->flags & MAKE_HEIGHT ||
- box->border[TOP].width ||
- box->padding[TOP] ||
- (box->style &&
- css_computed_overflow_y(box->style) !=
- CSS_OVERFLOW_VISIBLE) ||
- (box->type == BOX_INLINE_CONTAINER &&
- box != box->parent->children)) {
- /* Collapse to this box; return it */
- return box;
- }
- }
-
-
- /* Find next box */
- if (box->type == BOX_BLOCK && !box->object && box->children &&
- box->style &&
- css_computed_overflow_y(box->style) ==
- CSS_OVERFLOW_VISIBLE) {
- /* Down into children. */
- box = box->children;
- } else {
- if (!box->next) {
- /* No more siblings:
- * Go up to first ancestor with a sibling. */
- do {
- /* Apply bottom margin */
- if (*max_pos_margin <
- box->margin[BOTTOM])
- *max_pos_margin =
- box->margin[BOTTOM];
- else if (*max_neg_margin <
- -box->margin[BOTTOM])
- *max_neg_margin =
- -box->margin[BOTTOM];
-
- box = box->parent;
- } while (box != block && !box->next);
-
- if (box == block) {
- /* Margins don't collapse with stuff
- * outside the block formatting context
- */
- return block;
- }
- }
-
- /* Apply bottom margin */
- if (*max_pos_margin < box->margin[BOTTOM])
- *max_pos_margin = box->margin[BOTTOM];
- else if (*max_neg_margin < -box->margin[BOTTOM])
- *max_neg_margin = -box->margin[BOTTOM];
-
- /* To next sibling. */
- box = box->next;
-
- /* Get margins */
- if (box->style) {
- layout_find_dimensions(len_ctx,
- box->parent->width,
- viewport_height, box,
- box->style,
- NULL, NULL, NULL, NULL,
- NULL, NULL, box->margin,
- box->padding, box->border);
- }
- }
- }
-
- return NULL;
-}
-
-
-/**
- * Find y coordinate which clears all floats on left and/or right.
- *
- * \param fl first float in float list
- * \param clear type of clear
- * \return y coordinate relative to ancestor box for floats
- */
-static int layout_clear(struct box *fl, enum css_clear_e clear)
-{
- int y = 0;
- for (; fl; fl = fl->next_float) {
- if ((clear == CSS_CLEAR_LEFT || clear == CSS_CLEAR_BOTH) &&
- fl->type == BOX_FLOAT_LEFT)
- if (y < fl->y + fl->height)
- y = fl->y + fl->height;
- if ((clear == CSS_CLEAR_RIGHT || clear == CSS_CLEAR_BOTH) &&
- fl->type == BOX_FLOAT_RIGHT)
- if (y < fl->y + fl->height)
- y = fl->y + fl->height;
- }
- return y;
-}
-
-
-/**
- * Find left and right edges in a vertical range.
- *
- * \param fl first float in float list
- * \param y0 start of y range to search
- * \param y1 end of y range to search
- * \param x0 start left edge, updated to available left edge
- * \param x1 start right edge, updated to available right edge
- * \param left returns float on left if present
- * \param right returns float on right if present
- */
-static void
-find_sides(struct box *fl,
- int y0, int y1,
- int *x0, int *x1,
- struct box **left,
- struct box **right)
-{
- int fy0, fy1, fx0, fx1;
-
- NSLOG(layout, DEBUG, "y0 %i, y1 %i, x0 %i, x1 %i", y0, y1, *x0, *x1);
-
- *left = *right = 0;
- for (; fl; fl = fl->next_float) {
- fy1 = fl->y + fl->height;
- if (fy1 < y0) {
- /* Floats are sorted in order of decreasing bottom pos.
- * Past here, all floats will be too high to concern us.
- */
- return;
- }
- fy0 = fl->y;
- if (y0 < fy1 && fy0 <= y1) {
- if (fl->type == BOX_FLOAT_LEFT) {
- fx1 = fl->x + fl->width;
- if (*x0 < fx1) {
- *x0 = fx1;
- *left = fl;
- }
- } else {
- fx0 = fl->x;
- if (fx0 < *x1) {
- *x1 = fx0;
- *right = fl;
- }
- }
- }
- }
-
- NSLOG(layout, DEBUG, "x0 %i, x1 %i, left %p, right %p", *x0, *x1,
- *left, *right);
-}
-
-
-
-
-/**
- * Solve the width constraint as given in CSS 2.1 section 10.3.3.
- *
- * \param box Box to solve constraint for
- * \param available_width Max width available in pixels
- * \param width Current box width
- * \param lm Min left margin required to avoid floats in px.
- * zero if not applicable
- * \param rm Min right margin required to avoid floats in px.
- * zero if not applicable
- * \param max_width Box max-width ( -ve means no max-width to apply)
- * \param min_width Box min-width ( <=0 means no min-width to apply)
- * \return New box width
- *
- * \post \a box's left/right margins will be updated.
- */
-static int
-layout_solve_width(struct box *box,
- int available_width,
- int width,
- int lm,
- int rm,
- int max_width,
- int min_width)
-{
- bool auto_width = false;
-
- /* Increase specified left/right margins */
- if (box->margin[LEFT] != AUTO && box->margin[LEFT] < lm &&
- box->margin[LEFT] >= 0)
- box->margin[LEFT] = lm;
- if (box->margin[RIGHT] != AUTO && box->margin[RIGHT] < rm &&
- box->margin[RIGHT] >= 0)
- box->margin[RIGHT] = rm;
-
- /* Find width */
- if (width == AUTO) {
- int margin_left = box->margin[LEFT];
- int margin_right = box->margin[RIGHT];
-
- if (margin_left == AUTO) {
- margin_left = lm;
- }
- if (margin_right == AUTO) {
- margin_right = rm;
- }
-
- width = available_width -
- (margin_left + box->border[LEFT].width +
- box->padding[LEFT] + box->padding[RIGHT] +
- box->border[RIGHT].width + margin_right);
- width = width < 0 ? 0 : width;
- auto_width = true;
- }
-
- if (max_width >= 0 && width > max_width) {
- /* max-width is admissable and width exceeds max-width */
- width = max_width;
- auto_width = false;
- }
-
- if (min_width > 0 && width < min_width) {
- /* min-width is admissable and width is less than max-width */
- width = min_width;
- auto_width = false;
- }
-
- /* Width was auto, and unconstrained by min/max width, so we're done */
- if (auto_width) {
- /* any other 'auto' become 0 or the minimum required values */
- if (box->margin[LEFT] == AUTO) {
- box->margin[LEFT] = lm;
- }
- if (box->margin[RIGHT] == AUTO) {
- box->margin[RIGHT] = rm;
- }
- return width;
- }
-
- /* Width was not auto, or was constrained by min/max width
- * Need to compute left/right margins */
-
- /* HTML alignment (only applies to over-constrained boxes) */
- if (box->margin[LEFT] != AUTO && box->margin[RIGHT] != AUTO &&
- box->parent != NULL && box->parent->style != NULL) {
- switch (css_computed_text_align(box->parent->style)) {
- case CSS_TEXT_ALIGN_LIBCSS_RIGHT:
- box->margin[LEFT] = AUTO;
- box->margin[RIGHT] = 0;
- break;
- case CSS_TEXT_ALIGN_LIBCSS_CENTER:
- box->margin[LEFT] = box->margin[RIGHT] = AUTO;
- break;
- case CSS_TEXT_ALIGN_LIBCSS_LEFT:
- box->margin[LEFT] = 0;
- box->margin[RIGHT] = AUTO;
- break;
- default:
- /* Leave it alone; no HTML alignment */
- break;
- }
- }
-
- if (box->margin[LEFT] == AUTO && box->margin[RIGHT] == AUTO) {
- /* make the margins equal, centering the element */
- box->margin[LEFT] = box->margin[RIGHT] =
- (available_width - lm - rm -
- (box->border[LEFT].width + box->padding[LEFT] +
- width + box->padding[RIGHT] +
- box->border[RIGHT].width)) / 2;
-
- if (box->margin[LEFT] < 0) {
- box->margin[RIGHT] += box->margin[LEFT];
- box->margin[LEFT] = 0;
- }
-
- box->margin[LEFT] += lm;
-
- } else if (box->margin[LEFT] == AUTO) {
- box->margin[LEFT] = available_width - lm -
- (box->border[LEFT].width + box->padding[LEFT] +
- width + box->padding[RIGHT] +
- box->border[RIGHT].width + box->margin[RIGHT]);
- box->margin[LEFT] = box->margin[LEFT] < lm
- ? lm : box->margin[LEFT];
- } else {
- /* margin-right auto or "over-constrained" */
- box->margin[RIGHT] = available_width - rm -
- (box->margin[LEFT] + box->border[LEFT].width +
- box->padding[LEFT] + width +
- box->padding[RIGHT] +
- box->border[RIGHT].width);
- }
-
- return width;
-}
-
-
-/**
- * Compute dimensions of box, margins, paddings, and borders for a block-level
- * element.
- *
- * \param len_ctx Length conversion context
- * \param available_width Max width available in pixels
- * \param viewport_height Height of viewport in pixels or -ve if unknown
- * \param lm min left margin required to avoid floats in px.
- * zero if not applicable
- * \param rm min right margin required to avoid floats in px.
- * zero if not applicable
- * \param box box to find dimensions of. updated with new width,
- * height, margins, borders and paddings
- *
- * See CSS 2.1 10.3.3, 10.3.4, 10.6.2, and 10.6.3.
- */
-static void
-layout_block_find_dimensions(const nscss_len_ctx *len_ctx,
- int available_width,
- int viewport_height,
- int lm,
- int rm,
- struct box *box)
-{
- int width, max_width, min_width;
- int height, max_height, min_height;
- int *margin = box->margin;
- int *padding = box->padding;
- struct box_border *border = box->border;
- const css_computed_style *style = box->style;
-
- layout_find_dimensions(len_ctx, available_width, viewport_height, box,
- style, &width, &height, &max_width, &min_width,
- &max_height, &min_height, margin, padding, border);
-
- if (box->object && !(box->flags & REPLACE_DIM) &&
- content_get_type(box->object) != CONTENT_HTML) {
- /* block-level replaced element, see 10.3.4 and 10.6.2 */
- layout_get_object_dimensions(box, &width, &height,
- min_width, max_width, min_height, max_height);
- }
-
- box->width = layout_solve_width(box, available_width, width, lm, rm,
- max_width, min_width);
- box->height = height;
-
- if (margin[TOP] == AUTO)
- margin[TOP] = 0;
- if (margin[BOTTOM] == AUTO)
- margin[BOTTOM] = 0;
-}
-
-
-/**
- * Manipulate a block's [RB]padding/height/width to accommodate scrollbars
- *
- * \param box Box to apply scrollbar space too. Must be BOX_BLOCK.
- * \param which Which scrollbar to make space for. Must be RIGHT or BOTTOM.
- */
-static void layout_block_add_scrollbar(struct box *box, int which)
-{
- enum css_overflow_e overflow_x, overflow_y;
-
- assert(box->type == BOX_BLOCK && (which == RIGHT || which == BOTTOM));
-
- if (box->style == NULL)
- return;
-
- overflow_x = css_computed_overflow_x(box->style);
- overflow_y = css_computed_overflow_y(box->style);
-
- if (which == BOTTOM &&
- (overflow_x == CSS_OVERFLOW_SCROLL ||
- overflow_x == CSS_OVERFLOW_AUTO ||
- (box->object &&
- content_get_type(box->object) == CONTENT_HTML))) {
- /* make space for scrollbar, unless height is AUTO */
- if (box->height != AUTO &&
- (overflow_x == CSS_OVERFLOW_SCROLL ||
- box_hscrollbar_present(box))) {
- box->padding[BOTTOM] += SCROLLBAR_WIDTH;
- }
-
- } else if (which == RIGHT &&
- (overflow_y == CSS_OVERFLOW_SCROLL ||
- overflow_y == CSS_OVERFLOW_AUTO ||
- (box->object &&
- content_get_type(box->object) == CONTENT_HTML))) {
- /* make space for scrollbars, unless width is AUTO */
- enum css_height_e htype;
- css_fixed height = 0;
- css_unit hunit = CSS_UNIT_PX;
- htype = css_computed_height(box->style, &height, &hunit);
-
- if (which == RIGHT && box->width != AUTO &&
- htype == CSS_HEIGHT_SET &&
- (overflow_y == CSS_OVERFLOW_SCROLL ||
- box_vscrollbar_present(box))) {
- box->width -= SCROLLBAR_WIDTH;
- box->padding[RIGHT] += SCROLLBAR_WIDTH;
- }
- }
-}
-
-
-/**
- * Moves the children of a box by a specified amount
- *
- * \param box top of tree of boxes
- * \param x the amount to move children by horizontally
- * \param y the amount to move children by vertically
- */
-static void layout_move_children(struct box *box, int x, int y)
-{
- assert(box);
-
- for (box = box->children; box; box = box->next) {
- box->x += x;
- box->y += y;
- }
-}
-
-
-/**
- * Layout a table.
- *
- * \param table table to layout
- * \param available_width width of containing block
- * \param content memory pool for any new boxes
- * \return true on success, false on memory exhaustion
- */
-static bool layout_table(struct box *table, int available_width,
- html_content *content)
-{
- unsigned int columns = table->columns; /* total columns */
- unsigned int i;
- unsigned int *row_span;
- int *excess_y;
- int table_width, min_width = 0, max_width = 0;
- int required_width = 0;
- int x, remainder = 0, count = 0;
- int table_height = 0;
- int min_height = 0;
- int *xs; /* array of column x positions */
- int auto_width;
- int spare_width;
- int relative_sum = 0;
- int border_spacing_h = 0, border_spacing_v = 0;
- int spare_height;
- int positioned_columns = 0;
- struct box *containing_block = NULL;
- struct box *c;
- struct box *row;
- struct box *row_group;
- struct box **row_span_cell;
- struct column *col;
- const css_computed_style *style = table->style;
- enum css_width_e wtype;
- enum css_height_e htype;
- css_fixed value = 0;
- css_unit unit = CSS_UNIT_PX;
-
- assert(table->type == BOX_TABLE);
- assert(style);
- assert(table->children && table->children->children);
- assert(columns);
-
- /* allocate working buffers */
- col = malloc(columns * sizeof col[0]);
- excess_y = malloc(columns * sizeof excess_y[0]);
- row_span = malloc(columns * sizeof row_span[0]);
- row_span_cell = malloc(columns * sizeof row_span_cell[0]);
- xs = malloc((columns + 1) * sizeof xs[0]);
- if (!col || !xs || !row_span || !excess_y || !row_span_cell) {
- free(col);
- free(excess_y);
- free(row_span);
- free(row_span_cell);
- free(xs);
- return false;
- }
-
- memcpy(col, table->col, sizeof(col[0]) * columns);
-
- /* find margins, paddings, and borders for table and cells */
- layout_find_dimensions(&content->len_ctx, available_width, -1, table,
- style, 0, 0, 0, 0, 0, 0, table->margin, table->padding,
- table->border);
- for (row_group = table->children; row_group;
- row_group = row_group->next) {
- for (row = row_group->children; row; row = row->next) {
- for (c = row->children; c; c = c->next) {
- enum css_overflow_e overflow_x;
- enum css_overflow_e overflow_y;
-
- assert(c->style);
- table_used_border_for_cell(
- &content->len_ctx, c);
- layout_find_dimensions(&content->len_ctx,
- available_width, -1, c,
- c->style, 0, 0, 0, 0, 0, 0,
- 0, c->padding, c->border);
-
- overflow_x = css_computed_overflow_x(c->style);
- overflow_y = css_computed_overflow_y(c->style);
-
- if (overflow_x == CSS_OVERFLOW_SCROLL ||
- overflow_x ==
- CSS_OVERFLOW_AUTO) {
- c->padding[BOTTOM] += SCROLLBAR_WIDTH;
- }
- if (overflow_y == CSS_OVERFLOW_SCROLL ||
- overflow_y ==
- CSS_OVERFLOW_AUTO) {
- c->padding[RIGHT] += SCROLLBAR_WIDTH;
- }
- }
- }
- }
-
- /* border-spacing is used in the separated borders model */
- if (css_computed_border_collapse(style) ==
- CSS_BORDER_COLLAPSE_SEPARATE) {
- css_fixed h = 0, v = 0;
- css_unit hu = CSS_UNIT_PX, vu = CSS_UNIT_PX;
-
- css_computed_border_spacing(style, &h, &hu, &v, &vu);
-
- border_spacing_h = FIXTOINT(nscss_len2px(&content->len_ctx,
- h, hu, style));
- border_spacing_v = FIXTOINT(nscss_len2px(&content->len_ctx,
- v, vu, style));
- }
-
- /* find specified table width, or available width if auto-width */
- wtype = css_computed_width(style, &value, &unit);
- if (wtype == CSS_WIDTH_SET) {
- if (unit == CSS_UNIT_PCT) {
- table_width = FPCT_OF_INT_TOINT(value, available_width);
- } else {
- table_width =
- FIXTOINT(nscss_len2px(&content->len_ctx,
- value, unit, style));
- }
-
- /* specified width includes border */
- table_width -= table->border[LEFT].width +
- table->border[RIGHT].width;
- table_width = table_width < 0 ? 0 : table_width;
-
- auto_width = table_width;
- } else {
- table_width = AUTO;
- auto_width = available_width -
- ((table->margin[LEFT] == AUTO ? 0 :
- table->margin[LEFT]) +
- table->border[LEFT].width +
- table->padding[LEFT] +
- table->padding[RIGHT] +
- table->border[RIGHT].width +
- (table->margin[RIGHT] == AUTO ? 0 :
- table->margin[RIGHT]));
- }
-
- /* Find any table height specified within CSS/HTML */
- htype = css_computed_height(style, &value, &unit);
- if (htype == CSS_HEIGHT_SET) {
- if (unit == CSS_UNIT_PCT) {
- /* This is the minimum height for the table
- * (see 17.5.3) */
- if (css_computed_position(table->style) ==
- CSS_POSITION_ABSOLUTE) {
- /* Table is absolutely positioned */
- assert(table->float_container);
- containing_block = table->float_container;
- } else if (table->float_container &&
- css_computed_position(table->style) !=
- CSS_POSITION_ABSOLUTE &&
- (css_computed_float(table->style) ==
- CSS_FLOAT_LEFT ||
- css_computed_float(table->style) ==
- CSS_FLOAT_RIGHT)) {
- /* Table is a float */
- assert(table->parent && table->parent->parent &&
- table->parent->parent->parent);
- containing_block =
- table->parent->parent->parent;
- } else if (table->parent && table->parent->type !=
- BOX_INLINE_CONTAINER) {
- /* Table is a block level element */
- containing_block = table->parent;
- } else if (table->parent && table->parent->type ==
- BOX_INLINE_CONTAINER) {
- /* Table is an inline block */
- assert(table->parent->parent);
- containing_block = table->parent->parent;
- }
-
- if (containing_block) {
- css_fixed ignored = 0;
-
- htype = css_computed_height(
- containing_block->style,
- &ignored, &unit);
- }
-
- if (containing_block &&
- containing_block->height != AUTO &&
- (css_computed_position(table->style) ==
- CSS_POSITION_ABSOLUTE ||
- htype == CSS_HEIGHT_SET)) {
- /* Table is absolutely positioned or its
- * containing block has a valid specified
- * height. (CSS 2.1 Section 10.5) */
- min_height = FPCT_OF_INT_TOINT(value,
- containing_block->height);
- }
- } else {
- /* This is the minimum height for the table
- * (see 17.5.3) */
- min_height = FIXTOINT(nscss_len2px(&content->len_ctx,
- value, unit, style));
- }
- }
-
- /* calculate width required by cells */
- for (i = 0; i != columns; i++) {
-
- NSLOG(layout, DEBUG,
- "table %p, column %u: type %s, width %i, min %i, max %i",
- table,
- i,
- ((const char *[]){
- "UNKNOWN",
- "FIXED",
- "AUTO",
- "PERCENT",
- "RELATIVE",
- })[col[i].type],
- col[i].width,
- col[i].min,
- col[i].max);
-
-
- if (col[i].positioned) {
- positioned_columns++;
- continue;
- } else if (col[i].type == COLUMN_WIDTH_FIXED) {
- if (col[i].width < col[i].min)
- col[i].width = col[i].max = col[i].min;
- else
- col[i].min = col[i].max = col[i].width;
- required_width += col[i].width;
- } else if (col[i].type == COLUMN_WIDTH_PERCENT) {
- int width = col[i].width * auto_width / 100;
- required_width += col[i].min < width ? width :
- col[i].min;
- } else
- required_width += col[i].min;
-
- NSLOG(layout, DEBUG, "required_width %i", required_width);
- }
- required_width += (columns + 1 - positioned_columns) *
- border_spacing_h;
-
- NSLOG(layout, DEBUG,
- "width %i, min %i, max %i, auto %i, required %i", table_width,
- table->min_width, table->max_width, auto_width, required_width);
-
- if (auto_width < required_width) {
- /* table narrower than required width for columns:
- * treat percentage widths as maximums */
- for (i = 0; i != columns; i++) {
- if (col[i].type == COLUMN_WIDTH_RELATIVE)
- continue;
- if (col[i].type == COLUMN_WIDTH_PERCENT) {
- col[i].max = auto_width * col[i].width / 100;
- if (col[i].max < col[i].min)
- col[i].max = col[i].min;
- }
- min_width += col[i].min;
- max_width += col[i].max;
- }
- } else {
- /* take percentages exactly */
- for (i = 0; i != columns; i++) {
- if (col[i].type == COLUMN_WIDTH_RELATIVE)
- continue;
- if (col[i].type == COLUMN_WIDTH_PERCENT) {
- int width = auto_width * col[i].width / 100;
- if (width < col[i].min)
- width = col[i].min;
- col[i].min = col[i].width = col[i].max = width;
- col[i].type = COLUMN_WIDTH_FIXED;
- }
- min_width += col[i].min;
- max_width += col[i].max;
- }
- }
-
- /* allocate relative widths */
- spare_width = auto_width;
- for (i = 0; i != columns; i++) {
- if (col[i].type == COLUMN_WIDTH_RELATIVE)
- relative_sum += col[i].width;
- else if (col[i].type == COLUMN_WIDTH_FIXED)
- spare_width -= col[i].width;
- else
- spare_width -= col[i].min;
- }
- spare_width -= (columns + 1) * border_spacing_h;
- if (relative_sum != 0) {
- if (spare_width < 0)
- spare_width = 0;
- for (i = 0; i != columns; i++) {
- if (col[i].type == COLUMN_WIDTH_RELATIVE) {
- col[i].min = ceil(col[i].max =
- (float) spare_width
- * (float) col[i].width
- / relative_sum);
- min_width += col[i].min;
- max_width += col[i].max;
- }
- }
- }
- min_width += (columns + 1) * border_spacing_h;
- max_width += (columns + 1) * border_spacing_h;
-
- if (auto_width <= min_width) {
- /* not enough space: minimise column widths */
- for (i = 0; i < columns; i++) {
- col[i].width = col[i].min;
- }
- table_width = min_width;
- } else if (max_width <= auto_width) {
- /* more space than maximum width */
- if (table_width == AUTO) {
- /* for auto-width tables, make columns max width */
- for (i = 0; i < columns; i++) {
- col[i].width = col[i].max;
- }
- table_width = max_width;
- } else {
- /* for fixed-width tables, distribute the extra space
- * too */
- unsigned int flexible_columns = 0;
- for (i = 0; i != columns; i++)
- if (col[i].type != COLUMN_WIDTH_FIXED)
- flexible_columns++;
- if (flexible_columns == 0) {
- int extra = (table_width - max_width) / columns;
- remainder = (table_width - max_width) -
- (extra * columns);
- for (i = 0; i != columns; i++) {
- col[i].width = col[i].max + extra;
- count -= remainder;
- if (count < 0) {
- col[i].width++;
- count += columns;
- }
- }
-
- } else {
- int extra = (table_width - max_width) /
- flexible_columns;
- remainder = (table_width - max_width) -
- (extra * flexible_columns);
- for (i = 0; i != columns; i++)
- if (col[i].type != COLUMN_WIDTH_FIXED) {
- col[i].width = col[i].max +
- extra;
- count -= remainder;
- if (count < 0) {
- col[i].width++;
- count += flexible_columns;
- }
- }
- }
- }
- } else {
- /* space between min and max: fill it exactly */
- float scale = (float) (auto_width - min_width) /
- (float) (max_width - min_width);
- /* fprintf(stderr, "filling, scale %f\n", scale); */
- for (i = 0; i < columns; i++) {
- col[i].width = col[i].min + (int) (0.5 +
- (col[i].max - col[i].min) * scale);
- }
- table_width = auto_width;
- }
-
- xs[0] = x = border_spacing_h;
- for (i = 0; i != columns; i++) {
- if (!col[i].positioned)
- x += col[i].width + border_spacing_h;
- xs[i + 1] = x;
- row_span[i] = 0;
- excess_y[i] = 0;
- row_span_cell[i] = 0;
- }
-
- /* position cells */
- table_height = border_spacing_v;
- for (row_group = table->children; row_group;
- row_group = row_group->next) {
- int row_group_height = 0;
- for (row = row_group->children; row; row = row->next) {
- int row_height = 0;
-
- htype = css_computed_height(row->style, &value, &unit);
- if (htype == CSS_HEIGHT_SET && unit != CSS_UNIT_PCT) {
- row_height = FIXTOINT(nscss_len2px(
- &content->len_ctx,
- value, unit, row->style));
- }
- for (c = row->children; c; c = c->next) {
- assert(c->style);
- c->width = xs[c->start_column + c->columns] -
- xs[c->start_column] -
- border_spacing_h -
- c->border[LEFT].width -
- c->padding[LEFT] -
- c->padding[RIGHT] -
- c->border[RIGHT].width;
- c->float_children = 0;
- c->cached_place_below_level = 0;
-
- c->height = AUTO;
- if (!layout_block_context(c, -1, content)) {
- free(col);
- free(excess_y);
- free(row_span);
- free(row_span_cell);
- free(xs);
- return false;
- }
- /* warning: c->descendant_y0 and
- * c->descendant_y1 used as temporary storage
- * until after vertical alignment is complete */
- c->descendant_y0 = c->height;
- c->descendant_y1 = c->padding[BOTTOM];
-
- htype = css_computed_height(c->style,
- &value, &unit);
-
- if (htype == CSS_HEIGHT_SET &&
- unit != CSS_UNIT_PCT) {
- /* some sites use height="1" or similar
- * to attempt to make cells as small as
- * possible, so treat it as a minimum */
- int h = FIXTOINT(nscss_len2px(
- &content->len_ctx,
- value, unit, c->style));
- if (c->height < h)
- c->height = h;
- }
- /* specified row height is treated as a minimum
- */
- if (c->height < row_height)
- c->height = row_height;
- c->x = xs[c->start_column] +
- c->border[LEFT].width;
- c->y = c->border[TOP].width;
- for (i = 0; i != c->columns; i++) {
- row_span[c->start_column + i] = c->rows;
- excess_y[c->start_column + i] =
- c->border[TOP].width +
- c->padding[TOP] +
- c->height +
- c->padding[BOTTOM] +
- c->border[BOTTOM].width;
- row_span_cell[c->start_column + i] = 0;
- }
- row_span_cell[c->start_column] = c;
- c->padding[BOTTOM] = -border_spacing_v -
- c->border[TOP].width -
- c->padding[TOP] -
- c->height -
- c->border[BOTTOM].width;
- }
- for (i = 0; i != columns; i++)
- if (row_span[i] != 0)
- row_span[i]--;
- else
- row_span_cell[i] = 0;
- if (row->next || row_group->next) {
- /* row height is greatest excess of a cell
- * which ends in this row */
- for (i = 0; i != columns; i++)
- if (row_span[i] == 0 && row_height <
- excess_y[i])
- row_height = excess_y[i];
- } else {
- /* except in the last row */
- for (i = 0; i != columns; i++)
- if (row_height < excess_y[i])
- row_height = excess_y[i];
- }
- for (i = 0; i != columns; i++) {
- if (row_height < excess_y[i])
- excess_y[i] -= row_height;
- else
- excess_y[i] = 0;
- if (row_span_cell[i] != 0)
- row_span_cell[i]->padding[BOTTOM] +=
- row_height +
- border_spacing_v;
- }
-
- row->x = 0;
- row->y = row_group_height;
- row->width = table_width;
- row->height = row_height;
- row_group_height += row_height + border_spacing_v;
- }
- row_group->x = 0;
- row_group->y = table_height;
- row_group->width = table_width;
- row_group->height = row_group_height;
- table_height += row_group_height;
- }
- /* Table height is either the height of the contents, or specified
- * height if greater */
- table_height = max(table_height, min_height);
- /** \todo distribute spare height over the row groups / rows / cells */
-
- /* perform vertical alignment */
- for (row_group = table->children; row_group;
- row_group = row_group->next) {
- for (row = row_group->children; row; row = row->next) {
- for (c = row->children; c; c = c->next) {
- enum css_vertical_align_e vertical_align;
-
- /* unextended bottom padding is in
- * c->descendant_y1, and unextended
- * cell height is in c->descendant_y0 */
- spare_height = (c->padding[BOTTOM] -
- c->descendant_y1) +
- (c->height - c->descendant_y0);
-
- vertical_align = css_computed_vertical_align(
- c->style, &value, &unit);
-
- switch (vertical_align) {
- case CSS_VERTICAL_ALIGN_SUB:
- case CSS_VERTICAL_ALIGN_SUPER:
- case CSS_VERTICAL_ALIGN_TEXT_TOP:
- case CSS_VERTICAL_ALIGN_TEXT_BOTTOM:
- case CSS_VERTICAL_ALIGN_SET:
- case CSS_VERTICAL_ALIGN_BASELINE:
- /* todo: baseline alignment, for now
- * just use ALIGN_TOP */
- case CSS_VERTICAL_ALIGN_TOP:
- break;
- case CSS_VERTICAL_ALIGN_MIDDLE:
- c->padding[TOP] += spare_height / 2;
- c->padding[BOTTOM] -= spare_height / 2;
- layout_move_children(c, 0,
- spare_height / 2);
- break;
- case CSS_VERTICAL_ALIGN_BOTTOM:
- c->padding[TOP] += spare_height;
- c->padding[BOTTOM] -= spare_height;
- layout_move_children(c, 0,
- spare_height);
- break;
- case CSS_VERTICAL_ALIGN_INHERIT:
- assert(0);
- break;
- }
- }
- }
- }
-
- /* Top and bottom margins of 'auto' are set to 0. CSS2.1 10.6.3 */
- if (table->margin[TOP] == AUTO)
- table->margin[TOP] = 0;
- if (table->margin[BOTTOM] == AUTO)
- table->margin[BOTTOM] = 0;
-
- free(col);
- free(excess_y);
- free(row_span);
- free(row_span_cell);
- free(xs);
-
- table->width = table_width;
- table->height = table_height;
-
- return true;
-}
-
-
-/**
- * Manimpulate box height according to CSS min-height and max-height properties
- *
- * \param len_ctx CSS length conversion context for document.
- * \param box block to modify with any min-height or max-height
- * \param container containing block for absolutely positioned elements, or
- * NULL for non absolutely positioned elements.
- * \return whether the height has been changed
- */
-static bool layout_apply_minmax_height(
- const nscss_len_ctx *len_ctx,
- struct box *box,
- struct box *container)
-{
- int h;
- struct box *containing_block = NULL;
- bool updated = false;
-
- /* Find containing block for percentage heights */
- if (box->style != NULL && css_computed_position(box->style) ==
- CSS_POSITION_ABSOLUTE) {
- /* Box is absolutely positioned */
- assert(container);
- containing_block = container;
- } else if (box->float_container && box->style != NULL &&
- (css_computed_float(box->style) == CSS_FLOAT_LEFT ||
- css_computed_float(box->style) == CSS_FLOAT_RIGHT)) {
- /* Box is a float */
- assert(box->parent && box->parent->parent &&
- box->parent->parent->parent);
- containing_block = box->parent->parent->parent;
- } else if (box->parent && box->parent->type != BOX_INLINE_CONTAINER) {
- /* Box is a block level element */
- containing_block = box->parent;
- } else if (box->parent && box->parent->type == BOX_INLINE_CONTAINER) {
- /* Box is an inline block */
- assert(box->parent->parent);
- containing_block = box->parent->parent;
- }
-
- if (box->style) {
- enum css_height_e htype = CSS_HEIGHT_AUTO;
- css_fixed value = 0;
- css_unit unit = CSS_UNIT_PX;
-
- if (containing_block) {
- htype = css_computed_height(containing_block->style,
- &value, &unit);
- }
-
- /* max-height */
- if (css_computed_max_height(box->style, &value, &unit) ==
- CSS_MAX_HEIGHT_SET) {
- if (unit == CSS_UNIT_PCT) {
- if (containing_block &&
- containing_block->height != AUTO &&
- (css_computed_position(box->style) ==
- CSS_POSITION_ABSOLUTE ||
- htype == CSS_HEIGHT_SET)) {
- /* Box is absolutely positioned or its
- * containing block has a valid
- * specified height. (CSS 2.1
- * Section 10.5) */
- h = FPCT_OF_INT_TOINT(value,
- containing_block->height);
- if (h < box->height) {
- box->height = h;
- updated = true;
- }
- }
- } else {
- h = FIXTOINT(nscss_len2px(len_ctx,
- value, unit, box->style));
- if (h < box->height) {
- box->height = h;
- updated = true;
- }
- }
- }
-
- /* min-height */
- if (ns_computed_min_height(box->style, &value, &unit) ==
- CSS_MIN_HEIGHT_SET) {
- if (unit == CSS_UNIT_PCT) {
- if (containing_block &&
- containing_block->height != AUTO &&
- (css_computed_position(box->style) ==
- CSS_POSITION_ABSOLUTE ||
- htype == CSS_HEIGHT_SET)) {
- /* Box is absolutely positioned or its
- * containing block has a valid
- * specified height. (CSS 2.1
- * Section 10.5) */
- h = FPCT_OF_INT_TOINT(value,
- containing_block->height);
- if (h > box->height) {
- box->height = h;
- updated = true;
- }
- }
- } else {
- h = FIXTOINT(nscss_len2px(len_ctx,
- value, unit, box->style));
- if (h > box->height) {
- box->height = h;
- updated = true;
- }
- }
- }
- }
- return updated;
-}
-
-
-/**
- * Layout a block which contains an object.
- *
- * \param block box of type BLOCK, INLINE_BLOCK, TABLE, or TABLE_CELL
- * \return true on success, false on memory exhaustion
- */
-static bool layout_block_object(struct box *block)
-{
- assert(block);
- assert(block->type == BOX_BLOCK ||
- block->type == BOX_INLINE_BLOCK ||
- block->type == BOX_TABLE ||
- block->type == BOX_TABLE_CELL);
- assert(block->object);
-
- NSLOG(layout, DEBUG, "block %p, object %p, width %i", block,
- hlcache_handle_get_url(block->object), block->width);
-
- if (content_get_type(block->object) == CONTENT_HTML) {
- content_reformat(block->object, false, block->width, 1);
- } else {
- /* Non-HTML objects */
- /* this case handled already in
- * layout_block_find_dimensions() */
- }
-
- return true;
-}
-
-
-/**
- * Insert a float into a container.
- *
- * \param cont block formatting context block, used to contain float
- * \param b box to add to float
- *
- * This sorts floats in order of descending bottom edges.
- */
-static void add_float_to_container(struct box *cont, struct box *b)
-{
- struct box *box = cont->float_children;
- int b_bottom = b->y + b->height;
-
- assert(b->type == BOX_FLOAT_LEFT || b->type == BOX_FLOAT_RIGHT);
-
- if (box == NULL) {
- /* No other float children */
- b->next_float = NULL;
- cont->float_children = b;
- return;
- } else if (b_bottom >= box->y + box->height) {
- /* Goes at start of list */
- b->next_float = cont->float_children;
- cont->float_children = b;
- } else {
- struct box *prev = NULL;
- while (box != NULL && b_bottom < box->y + box->height) {
- prev = box;
- box = box->next_float;
- }
- if (prev != NULL) {
- b->next_float = prev->next_float;
- prev->next_float = b;
- }
- }
-}
-
-
-/**
- * Split a text box.
- *
- * \param content memory pool for any new boxes
- * \param fstyle style for text in text box
- * \param split_box box with text to split
- * \param new_length new length for text in split_box, after splitting
- * \param new_width new width for text in split_box, after splitting
- * \return true on success, false on memory exhaustion
- *
- * A new box is created and inserted into the box tree after split_box,
- * containing the text after new_length excluding the initial space character.
- */
-static bool
-layout_text_box_split(html_content *content,
- plot_font_style_t *fstyle,
- struct box *split_box,
- size_t new_length,
- int new_width)
-{
- int space_width = split_box->space;
- struct box *c2;
- const struct gui_layout_table *font_func = content->font_func;
- bool space = (split_box->text[new_length] == ' ');
- int used_length = new_length + (space ? 1 : 0);
-
- if ((space && space_width == 0) || space_width == UNKNOWN_WIDTH) {
- /* We're need to add a space, and we don't know how big
- * it's to be, OR we have a space of unknown width anyway;
- * Calculate space width */
- font_func->width(fstyle, " ", 1, &space_width);
- }
-
- if (split_box->space == UNKNOWN_WIDTH)
- split_box->space = space_width;
- if (!space)
- space_width = 0;
-
- /* Create clone of split_box, c2 */
- c2 = talloc_memdup(content->bctx, split_box, sizeof *c2);
- if (!c2)
- return false;
- c2->flags |= CLONE;
-
- /* Set remaining text in c2 */
- c2->text += used_length;
-
- /* Set c2 according to the remaining text */
- c2->width -= new_width + space_width;
- c2->flags &= ~MEASURED; /* width has been estimated */
- c2->length = split_box->length - used_length;
-
- /* Update split_box for its reduced text */
- split_box->width = new_width;
- split_box->flags |= MEASURED;
- split_box->length = new_length;
- split_box->space = space_width;
-
- /* Insert c2 into box list */
- c2->next = split_box->next;
- split_box->next = c2;
- c2->prev = split_box;
- if (c2->next)
- c2->next->prev = c2;
- else
- c2->parent->last = c2;
-
- NSLOG(layout, DEBUG,
- "split_box %p len: %" PRIsizet " \"%.*s\"",
- split_box,
- split_box->length,
- (int)split_box->length,
- split_box->text);
- NSLOG(layout, DEBUG,
- " new_box %p len: %" PRIsizet " \"%.*s\"",
- c2,
- c2->length,
- (int)c2->length,
- c2->text);
-
- return true;
-}
-
-
-/**
- * Compute dimensions of box, margins, paddings, and borders for a floating
- * element using shrink-to-fit. Also used for inline-blocks.
- *
- * \param len_ctx CSS length conversion context for document.
- * \param available_width Max width available in pixels
- * \param style Box's style
- * \param box Box for which to find dimensions
- * Box margins, borders, paddings, width and
- * height are updated.
- */
-static void
-layout_float_find_dimensions(
- const nscss_len_ctx *len_ctx,
- int available_width,
- const css_computed_style *style,
- struct box *box)
-{
- int width, height, max_width, min_width, max_height, min_height;
- int *margin = box->margin;
- int *padding = box->padding;
- struct box_border *border = box->border;
- enum css_overflow_e overflow_x = css_computed_overflow_x(style);
- enum css_overflow_e overflow_y = css_computed_overflow_y(style);
- int scrollbar_width_x =
- (overflow_x == CSS_OVERFLOW_SCROLL ||
- overflow_x == CSS_OVERFLOW_AUTO) ?
- SCROLLBAR_WIDTH : 0;
- int scrollbar_width_y =
- (overflow_y == CSS_OVERFLOW_SCROLL ||
- overflow_y == CSS_OVERFLOW_AUTO) ?
- SCROLLBAR_WIDTH : 0;
-
- layout_find_dimensions(len_ctx, available_width, -1, box, style,
- &width, &height, &max_width, &min_width,
- &max_height, &min_height, margin, padding, border);
-
- if (margin[LEFT] == AUTO)
- margin[LEFT] = 0;
- if (margin[RIGHT] == AUTO)
- margin[RIGHT] = 0;
-
- if (box->gadget == NULL) {
- padding[RIGHT] += scrollbar_width_y;
- padding[BOTTOM] += scrollbar_width_x;
- }
-
- if (box->object && !(box->flags & REPLACE_DIM) &&
- content_get_type(box->object) != CONTENT_HTML) {
- /* Floating replaced element, with intrinsic width or height.
- * See 10.3.6 and 10.6.2 */
- layout_get_object_dimensions(box, &width, &height,
- min_width, max_width, min_height, max_height);
- } else if (box->gadget && (box->gadget->type == GADGET_TEXTBOX ||
- box->gadget->type == GADGET_PASSWORD ||
- box->gadget->type == GADGET_FILE ||
- box->gadget->type == GADGET_TEXTAREA)) {
- css_fixed size = 0;
- css_unit unit = CSS_UNIT_EM;
-
- /* Give sensible dimensions to gadgets, with auto width/height,
- * that don't shrink to fit contained text. */
- assert(box->style);
-
- if (box->gadget->type == GADGET_TEXTBOX ||
- box->gadget->type == GADGET_PASSWORD ||
- box->gadget->type == GADGET_FILE) {
- if (width == AUTO) {
- size = INTTOFIX(10);
- width = FIXTOINT(nscss_len2px(len_ctx,
- size, unit, box->style));
- }
- if (box->gadget->type == GADGET_FILE &&
- height == AUTO) {
- size = FLTTOFIX(1.5);
- height = FIXTOINT(nscss_len2px(len_ctx,
- size, unit, box->style));
- }
- }
- if (box->gadget->type == GADGET_TEXTAREA) {
- if (width == AUTO) {
- size = INTTOFIX(10);
- width = FIXTOINT(nscss_len2px(len_ctx,
- size, unit, box->style));
- }
- if (height == AUTO) {
- size = INTTOFIX(4);
- height = FIXTOINT(nscss_len2px(len_ctx,
- size, unit, box->style));
- }
- }
- } else if (width == AUTO) {
- /* CSS 2.1 section 10.3.5 */
- width = min(max(box->min_width, available_width),
- box->max_width);
-
- /* width includes margin, borders and padding */
- if (width == available_width) {
- width -= box->margin[LEFT] + box->border[LEFT].width +
- box->padding[LEFT] +
- box->padding[RIGHT] +
- box->border[RIGHT].width +
- box->margin[RIGHT];
- } else {
- /* width was obtained from a min_width or max_width
- * value, so need to use the same method for calculating
- * mbp as was used in layout_minmax_block() */
- int fixed = 0;
- float frac = 0;
- calculate_mbp_width(len_ctx, box->style, LEFT,
- true, true, true, &fixed, &frac);
- calculate_mbp_width(len_ctx, box->style, RIGHT,
- true, true, true, &fixed, &frac);
- if (fixed < 0)
- fixed = 0;
-
- width -= fixed;
- }
-
- if (max_width >= 0 && width > max_width) width = max_width;
- if (min_width > 0 && width < min_width) width = min_width;
-
- } else {
- if (max_width >= 0 && width > max_width) width = max_width;
- if (min_width > 0 && width < min_width) width = min_width;
- width -= scrollbar_width_y;
- }
-
- box->width = width;
- box->height = height;
-
- if (margin[TOP] == AUTO)
- margin[TOP] = 0;
- if (margin[BOTTOM] == AUTO)
- margin[BOTTOM] = 0;
-}
-
-
-/**
- * Layout the contents of a float or inline block.
- *
- * \param b float or inline block box
- * \param width available width
- * \param content memory pool for any new boxes
- * \return true on success, false on memory exhaustion
- */
-static bool layout_float(struct box *b, int width, html_content *content)
-{
- assert(b->type == BOX_TABLE || b->type == BOX_BLOCK ||
- b->type == BOX_INLINE_BLOCK);
- layout_float_find_dimensions(&content->len_ctx, width, b->style, b);
- if (b->type == BOX_TABLE) {
- if (!layout_table(b, width, content))
- return false;
- if (b->margin[LEFT] == AUTO)
- b->margin[LEFT] = 0;
- if (b->margin[RIGHT] == AUTO)
- b->margin[RIGHT] = 0;
- if (b->margin[TOP] == AUTO)
- b->margin[TOP] = 0;
- if (b->margin[BOTTOM] == AUTO)
- b->margin[BOTTOM] = 0;
- } else
- return layout_block_context(b, -1, content);
- return true;
-}
-
-
-/**
- * Position a float in the first available space.
- *
- * \param c float box to position
- * \param width available width
- * \param cx x coordinate relative to cont to place float right of
- * \param y y coordinate relative to cont to place float below
- * \param cont ancestor box which defines horizontal space, for floats
- */
-static void
-place_float_below(struct box *c, int width, int cx, int y, struct box *cont)
-{
- int x0, x1, yy;
- struct box *left;
- struct box *right;
-
- yy = y > cont->cached_place_below_level ?
- y : cont->cached_place_below_level;
-
- NSLOG(layout, DEBUG,
- "c %p, width %i, cx %i, y %i, cont %p", c,
- width, cx, y, cont);
-
- do {
- y = yy;
- x0 = cx;
- x1 = cx + width;
- find_sides(cont->float_children, y, y + c->height, &x0, &x1,
- &left, &right);
- if (left != 0 && right != 0) {
- yy = (left->y + left->height <
- right->y + right->height ?
- left->y + left->height :
- right->y + right->height);
- } else if (left == 0 && right != 0) {
- yy = right->y + right->height;
- } else if (left != 0 && right == 0) {
- yy = left->y + left->height;
- }
- } while ((left != 0 || right != 0) && (c->width > x1 - x0));
-
- if (c->type == BOX_FLOAT_LEFT) {
- c->x = x0;
- } else {
- c->x = x1 - c->width;
- }
- c->y = y;
- cont->cached_place_below_level = y;
-}
-
-
-/**
- * Calculate line height from a style.
- */
-static int line_height(
- const nscss_len_ctx *len_ctx,
- const css_computed_style *style)
-{
- enum css_line_height_e lhtype;
- css_fixed lhvalue = 0;
- css_unit lhunit = CSS_UNIT_PX;
- css_fixed line_height;
-
- assert(style);
-
- lhtype = css_computed_line_height(style, &lhvalue, &lhunit);
- if (lhtype == CSS_LINE_HEIGHT_NORMAL) {
- /* Normal => use a constant of 1.3 * font-size */
- lhvalue = FLTTOFIX(1.3);
- lhtype = CSS_LINE_HEIGHT_NUMBER;
- }
-
- if (lhtype == CSS_LINE_HEIGHT_NUMBER ||
- lhunit == CSS_UNIT_PCT) {
- line_height = nscss_len2px(len_ctx,
- lhvalue, CSS_UNIT_EM, style);
-
- if (lhtype != CSS_LINE_HEIGHT_NUMBER)
- line_height = FDIV(line_height, F_100);
- } else {
- assert(lhunit != CSS_UNIT_PCT);
-
- line_height = nscss_len2px(len_ctx,
- lhvalue, lhunit, style);
- }
-
- return FIXTOINT(line_height);
-}
-
-
-/**
- * Position a line of boxes in inline formatting context.
- *
- * \param first box at start of line
- * \param width available width on input, updated with actual width on output
- * (may be incorrect if the line gets split?)
- * \param y coordinate of top of line, updated on exit to bottom
- * \param cx coordinate of left of line relative to cont
- * \param cy coordinate of top of line relative to cont
- * \param cont ancestor box which defines horizontal space, for floats
- * \param indent apply any first-line indent
- * \param has_text_children at least one TEXT in the inline_container
- * \param next_box updated to first box for next line, or 0 at end
- * \param content memory pool for any new boxes
- * \return true on success, false on memory exhaustion
- */
-static bool
-layout_line(struct box *first,
- int *width,
- int *y,
- int cx,
- int cy,
- struct box *cont,
- bool indent,
- bool has_text_children,
- html_content *content,
- struct box **next_box)
-{
- int height, used_height;
- int x0 = 0;
- int x1 = *width;
- int x, h, x_previous;
- int fy = cy;
- struct box *left;
- struct box *right;
- struct box *b;
- struct box *split_box = 0;
- struct box *d;
- struct box *br_box = 0;
- bool move_y = false;
- bool place_below = false;
- int space_before = 0, space_after = 0;
- unsigned int inline_count = 0;
- unsigned int i;
- const struct gui_layout_table *font_func = content->font_func;
- plot_font_style_t fstyle;
-
- NSLOG(layout, DEBUG,
- "first %p, first->text '%.*s', width %i, y %i, cx %i, cy %i",
- first,
- (int)first->length,
- first->text,
- *width,
- *y,
- cx,
- cy);
-
- /* find sides at top of line */
- x0 += cx;
- x1 += cx;
- find_sides(cont->float_children, cy, cy, &x0, &x1, &left, &right);
- x0 -= cx;
- x1 -= cx;
-
- if (indent)
- x0 += layout_text_indent(&content->len_ctx,
- first->parent->parent->style, *width);
-
- if (x1 < x0)
- x1 = x0;
-
- /* get minimum line height from containing block.
- * this is the line-height if there are text children and also in the
- * case of an initially empty text input */
- if (has_text_children || first->parent->parent->gadget)
- used_height = height = line_height(&content->len_ctx,
- first->parent->parent->style);
- else
- /* inline containers with no text are usually for layout and
- * look better with no minimum line-height */
- used_height = height = 0;
-
- /* pass 1: find height of line assuming sides at top of line: loop
- * body executed at least once
- * keep in sync with the loop in layout_minmax_line() */
-
- NSLOG(layout, DEBUG, "x0 %i, x1 %i, x1 - x0 %i", x0, x1, x1 - x0);
-
-
- for (x = 0, b = first; x <= x1 - x0 && b != 0; b = b->next) {
- int min_width, max_width, min_height, max_height;
-
- assert(b->type == BOX_INLINE || b->type == BOX_INLINE_BLOCK ||
- b->type == BOX_FLOAT_LEFT ||
- b->type == BOX_FLOAT_RIGHT ||
- b->type == BOX_BR || b->type == BOX_TEXT ||
- b->type == BOX_INLINE_END);
-
-
- NSLOG(layout, DEBUG, "pass 1: b %p, x %i", b, x);
-
-
- if (b->type == BOX_BR)
- break;
-
- if (b->type == BOX_FLOAT_LEFT || b->type == BOX_FLOAT_RIGHT)
- continue;
- if (b->type == BOX_INLINE_BLOCK &&
- (css_computed_position(b->style) ==
- CSS_POSITION_ABSOLUTE ||
- css_computed_position(b->style) ==
- CSS_POSITION_FIXED))
- continue;
-
- assert(b->style != NULL);
- font_plot_style_from_css(&content->len_ctx, b->style, &fstyle);
-
- x += space_after;
-
- if (b->type == BOX_INLINE_BLOCK) {
- if (b->max_width != UNKNOWN_WIDTH)
- if (!layout_float(b, *width, content))
- return false;
- h = b->border[TOP].width + b->padding[TOP] + b->height +
- b->padding[BOTTOM] +
- b->border[BOTTOM].width;
- if (height < h)
- height = h;
- x += b->margin[LEFT] + b->border[LEFT].width +
- b->padding[LEFT] + b->width +
- b->padding[RIGHT] +
- b->border[RIGHT].width +
- b->margin[RIGHT];
- space_after = 0;
- continue;
- }
-
- if (b->type == BOX_INLINE) {
- /* calculate borders, margins, and padding */
- layout_find_dimensions(&content->len_ctx,
- *width, -1, b, b->style, 0, 0, 0, 0,
- 0, 0, b->margin, b->padding, b->border);
- for (i = 0; i != 4; i++)
- if (b->margin[i] == AUTO)
- b->margin[i] = 0;
- x += b->margin[LEFT] + b->border[LEFT].width +
- b->padding[LEFT];
- if (b->inline_end) {
- b->inline_end->margin[RIGHT] = b->margin[RIGHT];
- b->inline_end->padding[RIGHT] =
- b->padding[RIGHT];
- b->inline_end->border[RIGHT] =
- b->border[RIGHT];
- } else {
- x += b->padding[RIGHT] +
- b->border[RIGHT].width +
- b->margin[RIGHT];
- }
- } else if (b->type == BOX_INLINE_END) {
- b->width = 0;
- if (b->space == UNKNOWN_WIDTH) {
- font_func->width(&fstyle, " ", 1, &b->space);
- /** \todo handle errors */
- }
- space_after = b->space;
-
- x += b->padding[RIGHT] + b->border[RIGHT].width +
- b->margin[RIGHT];
- continue;
- }
-
- 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(&content->len_ctx,
- b->style ? b->style :
- b->parent->parent->style);
- if (height < b->height)
- height = b->height;
-
- if (!b->text) {
- b->width = 0;
- space_after = 0;
- continue;
- }
-
- if (b->width == UNKNOWN_WIDTH) {
- /** \todo handle errors */
-
- /* If it's a select element, we must use the
- * width of the widest option text */
- if (b->parent->parent->gadget &&
- b->parent->parent->gadget->type
- == GADGET_SELECT) {
- int opt_maxwidth = 0;
- struct form_option *o;
-
- for (o = b->parent->parent->gadget->
- data.select.items; o;
- o = o->next) {
- int opt_width;
- font_func->width(&fstyle,
- o->text,
- strlen(o->text),
- &opt_width);
-
- if (opt_maxwidth < opt_width)
- opt_maxwidth =opt_width;
- }
- b->width = opt_maxwidth;
- if (nsoption_bool(core_select_menu))
- b->width += SCROLLBAR_WIDTH;
- } else {
- font_func->width(&fstyle, b->text,
- b->length, &b->width);
- b->flags |= MEASURED;
- }
- }
-
- /* If the current text has not been measured (i.e. its
- * width was estimated after splitting), and it fits on
- * the line, measure it properly, so next box is placed
- * correctly. */
- if (b->text && (x + b->width < x1 - x0) &&
- !(b->flags & MEASURED) &&
- b->next) {
- font_func->width(&fstyle, b->text,
- b->length, &b->width);
- b->flags |= MEASURED;
- }
-
- x += b->width;
- if (b->space == UNKNOWN_WIDTH) {
- font_func->width(&fstyle, " ", 1, &b->space);
- /** \todo handle errors */
- }
- space_after = b->space;
- continue;
- }
-
- space_after = 0;
-
- /* inline replaced, 10.3.2 and 10.6.2 */
- assert(b->style);
-
- layout_find_dimensions(&content->len_ctx,
- *width, -1, b, b->style,
- &b->width, &b->height,
- &max_width, &min_width,
- &max_height, &min_height,
- NULL, NULL, NULL);
-
- if (b->object && !(b->flags & REPLACE_DIM)) {
- layout_get_object_dimensions(b, &b->width, &b->height,
- min_width, max_width,
- min_height, max_height);
- } 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;
-
- /* We reformat the iframe browser window to new
- * dimensions in pass 2 */
- } else {
- /* form control with no object */
- if (b->width == AUTO)
- b->width = FIXTOINT(nscss_len2px(
- &content->len_ctx, INTTOFIX(1),
- CSS_UNIT_EM, b->style));
- if (b->height == AUTO)
- b->height = FIXTOINT(nscss_len2px(
- &content->len_ctx, INTTOFIX(1),
- 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)) {
- css_fixed value = 0;
- css_unit unit = CSS_UNIT_PX;
- enum css_height_e htype = css_computed_height(b->style,
- &value, &unit);
-
- content_reformat(b->object, false, b->width, b->height);
-
- if (htype == CSS_HEIGHT_AUTO)
- b->height = content_get_height(b->object);
- }
-
- if (height < b->height)
- height = b->height;
-
- x += b->width;
- }
-
- /* find new sides using this height */
- x0 = cx;
- x1 = cx + *width;
- find_sides(cont->float_children, cy, cy + height, &x0, &x1,
- &left, &right);
- x0 -= cx;
- x1 -= cx;
-
- if (indent)
- x0 += layout_text_indent(&content->len_ctx,
- first->parent->parent->style, *width);
-
- if (x1 < x0)
- x1 = x0;
-
- space_after = space_before = 0;
-
- /* pass 2: place boxes in line: loop body executed at least once */
-
- NSLOG(layout, DEBUG, "x0 %i, x1 %i, x1 - x0 %i", x0, x1, x1 - x0);
-
- for (x = x_previous = 0, b = first; x <= x1 - x0 && b; b = b->next) {
-
- NSLOG(layout, DEBUG, "pass 2: b %p, x %i", b, x);
-
- if (b->type == BOX_INLINE_BLOCK &&
- (css_computed_position(b->style) ==
- CSS_POSITION_ABSOLUTE ||
- css_computed_position(b->style) ==
- CSS_POSITION_FIXED)) {
- b->x = x + space_after;
-
- } else if (b->type == BOX_INLINE ||
- b->type == BOX_INLINE_BLOCK ||
- b->type == BOX_TEXT ||
- b->type == BOX_INLINE_END) {
- assert(b->width != UNKNOWN_WIDTH);
-
- x_previous = x;
- x += space_after;
- b->x = x;
-
- if ((b->type == BOX_INLINE && !b->inline_end) ||
- b->type == BOX_INLINE_BLOCK) {
- b->x += b->margin[LEFT] + b->border[LEFT].width;
- x = b->x + b->padding[LEFT] + b->width +
- b->padding[RIGHT] +
- b->border[RIGHT].width +
- b->margin[RIGHT];
- } else if (b->type == BOX_INLINE) {
- b->x += b->margin[LEFT] + b->border[LEFT].width;
- x = b->x + b->padding[LEFT] + b->width;
- } else if (b->type == BOX_INLINE_END) {
- b->height = b->inline_end->height;
- x += b->padding[RIGHT] +
- b->border[RIGHT].width +
- b->margin[RIGHT];
- } else {
- x += b->width;
- }
-
- space_before = space_after;
- 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) {
- font_plot_style_from_css(
- &content->len_ctx,
- b->style, &fstyle);
- /** \todo handle errors */
- font_func->width(&fstyle, " ", 1,
- &b->space);
- }
- space_after = b->space;
- } else {
- space_after = 0;
- }
- split_box = b;
- move_y = true;
- inline_count++;
- } else if (b->type == BOX_BR) {
- b->x = x;
- b->width = 0;
- br_box = b;
- b = b->next;
- split_box = 0;
- move_y = true;
- break;
-
- } else {
- /* float */
- NSLOG(layout, DEBUG, "float %p", b);
-
- d = b->children;
- d->float_children = 0;
- d->cached_place_below_level = 0;
- b->float_container = d->float_container = cont;
-
- if (!layout_float(d, *width, content))
- return false;
-
- NSLOG(layout, DEBUG,
- "%p : %d %d",
- d,
- d->margin[TOP],
- d->border[TOP].width);
-
- d->x = d->margin[LEFT] + d->border[LEFT].width;
- d->y = d->margin[TOP] + d->border[TOP].width;
- b->width = d->margin[LEFT] + d->border[LEFT].width +
- d->padding[LEFT] + d->width +
- d->padding[RIGHT] +
- d->border[RIGHT].width +
- d->margin[RIGHT];
- b->height = d->margin[TOP] + d->border[TOP].width +
- d->padding[TOP] + d->height +
- d->padding[BOTTOM] +
- d->border[BOTTOM].width +
- d->margin[BOTTOM];
-
- if (b->width > (x1 - x0) - x)
- place_below = true;
- if (d->style && (css_computed_clear(d->style) ==
- CSS_CLEAR_NONE ||
- (css_computed_clear(d->style) ==
- CSS_CLEAR_LEFT && left == 0) ||
- (css_computed_clear(d->style) ==
- CSS_CLEAR_RIGHT &&
- right == 0) ||
- (css_computed_clear(d->style) ==
- CSS_CLEAR_BOTH &&
- left == 0 && right == 0)) &&
- (!place_below ||
- (left == 0 && right == 0 && x == 0)) &&
- cy >= cont->clear_level &&
- cy >= cont->cached_place_below_level) {
- /* + not cleared or,
- * cleared and there are no floats to clear
- * + fits without needing to be placed below or,
- * this line is empty with no floats
- * + current y, cy, is below the clear level
- *
- * Float affects current line */
- if (b->type == BOX_FLOAT_LEFT) {
- b->x = cx + x0;
- if (b->width > 0)
- x0 += b->width;
- left = b;
- } else {
- b->x = cx + x1 - b->width;
- if (b->width > 0)
- x1 -= b->width;
- right = b;
- }
- b->y = cy;
- } else {
- /* cleared or doesn't fit on line */
- /* place below into next available space */
- int fcy = (cy > cont->clear_level) ? cy :
- cont->clear_level;
- fcy = (fcy > cont->cached_place_below_level) ?
- fcy :
- cont->cached_place_below_level;
- fy = (fy > fcy) ? fy : fcy;
- fy = (fy == cy) ? fy + height : fy;
-
- place_float_below(b, *width, cx, fy, cont);
- fy = b->y;
- if (d->style && (
- (css_computed_clear(d->style) ==
- CSS_CLEAR_LEFT && left != 0) ||
- (css_computed_clear(d->style) ==
- CSS_CLEAR_RIGHT &&
- right != 0) ||
- (css_computed_clear(d->style) ==
- CSS_CLEAR_BOTH &&
- (left != 0 || right != 0)))) {
- /* to be cleared below existing
- * floats */
- if (b->type == BOX_FLOAT_LEFT)
- b->x = cx;
- else
- b->x = cx + *width - b->width;
-
- fcy = layout_clear(cont->float_children,
- css_computed_clear(d->style));
- if (fcy > cont->clear_level)
- cont->clear_level = fcy;
- if (b->y < fcy)
- b->y = fcy;
- }
- if (b->type == BOX_FLOAT_LEFT)
- left = b;
- else
- right = b;
- }
- add_float_to_container(cont, b);
-
- split_box = 0;
- }
- }
-
- if (x1 - x0 < x && split_box) {
- /* the last box went over the end */
- size_t split = 0;
- int w;
- bool no_wrap = css_computed_white_space(
- split_box->style) == CSS_WHITE_SPACE_NOWRAP ||
- css_computed_white_space(
- split_box->style) == CSS_WHITE_SPACE_PRE;
-
- x = x_previous;
-
- if (!no_wrap &&
- (split_box->type == BOX_INLINE ||
- split_box->type == BOX_TEXT) &&
- !split_box->object &&
- !(split_box->flags & REPLACE_DIM) &&
- !(split_box->flags & IFRAME) &&
- !split_box->gadget && split_box->text) {
-
- font_plot_style_from_css(&content->len_ctx,
- split_box->style, &fstyle);
- /** \todo handle errors */
- font_func->split(&fstyle,
- split_box->text,
- split_box->length,
- x1 - x0 - x - space_before,
- &split,
- &w);
- }
-
- /* split == 0 implies that text can't be split */
-
- if (split == 0)
- w = split_box->width;
-
-
- NSLOG(layout, DEBUG,
- "splitting: split_box %p \"%.*s\", spilt %zu, w %i, "
- "left %p, right %p, inline_count %u",
- split_box,
- (int)split_box->length,
- split_box->text,
- split,
- w,
- left,
- right,
- inline_count);
-
- if ((split == 0 || x1 - x0 <= x + space_before + w) &&
- !left && !right && inline_count == 1) {
- /* first word of box doesn't fit, but no floats and
- * first box on line so force in */
- if (split == 0 || split == split_box->length) {
- /* only one word in this box, or not text
- * or white-space:nowrap */
- b = split_box->next;
- } else {
- /* cut off first word for this line */
- if (!layout_text_box_split(content, &fstyle,
- split_box, split, w))
- return false;
- b = split_box->next;
- }
- x += space_before + w;
-
- NSLOG(layout, DEBUG, "forcing");
-
- } else if ((split == 0 || x1 - x0 <= x + space_before + w) &&
- inline_count == 1) {
- /* first word of first box doesn't fit, but a float is
- * taking some of the width so move below it */
- assert(left || right);
- used_height = 0;
- if (left) {
-
- NSLOG(layout, DEBUG,
- "cy %i, left->y %i, left->height %i",
- cy,
- left->y,
- left->height);
-
- used_height = left->y + left->height - cy + 1;
-
- NSLOG(layout, DEBUG, "used_height %i",
- used_height);
-
- }
- if (right && used_height <
- right->y + right->height - cy + 1)
- used_height = right->y + right->height - cy + 1;
-
- if (used_height < 0)
- used_height = 0;
-
- b = split_box;
-
- NSLOG(layout, DEBUG, "moving below float");
-
- } else if (split == 0 || x1 - x0 <= x + space_before + w) {
- /* first word of box doesn't fit so leave box for next
- * line */
- b = split_box;
-
- NSLOG(layout, DEBUG, "leaving for next line");
-
- } else {
- /* fit as many words as possible */
- assert(split != 0);
-
- NSLOG(layout, DEBUG, "'%.*s' %i %zu %i",
- (int)split_box->length, split_box->text,
- x1 - x0, split, w);
-
- if (split != split_box->length) {
- if (!layout_text_box_split(content, &fstyle,
- split_box, split, w))
- return false;
- b = split_box->next;
- }
- x += space_before + w;
-
- NSLOG(layout, DEBUG, "fitting words");
-
- }
- move_y = true;
- }
-
- /* set positions */
- switch (css_computed_text_align(first->parent->parent->style)) {
- case CSS_TEXT_ALIGN_RIGHT:
- case CSS_TEXT_ALIGN_LIBCSS_RIGHT:
- x0 = x1 - x;
- break;
- case CSS_TEXT_ALIGN_CENTER:
- case CSS_TEXT_ALIGN_LIBCSS_CENTER:
- x0 = (x0 + (x1 - x)) / 2;
- break;
- case CSS_TEXT_ALIGN_LEFT:
- case CSS_TEXT_ALIGN_LIBCSS_LEFT:
- case CSS_TEXT_ALIGN_JUSTIFY:
- /* leave on left */
- break;
- case CSS_TEXT_ALIGN_DEFAULT:
- /* None; consider text direction */
- switch (css_computed_direction(first->parent->parent->style)) {
- case CSS_DIRECTION_LTR:
- /* leave on left */
- break;
- case CSS_DIRECTION_RTL:
- x0 = x1 - x;
- break;
- }
- break;
- }
-
- for (d = first; d != b; d = d->next) {
- d->flags &= ~NEW_LINE;
-
- if (d->type == BOX_INLINE_BLOCK &&
- (css_computed_position(d->style) ==
- CSS_POSITION_ABSOLUTE ||
- css_computed_position(d->style) ==
- CSS_POSITION_FIXED)) {
- /* positioned inline-blocks:
- * set static position (x,y) only, rest of positioning
- * is handled later */
- d->x += x0;
- d->y = *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 ||
- d->type == BOX_INLINE_END) {
- /* regular (non-replaced) inlines */
- d->x += x0;
- d->y = *y - d->padding[TOP];
-
- if (d->type == BOX_TEXT && d->height > used_height) {
- /* text */
- used_height = d->height;
- }
- } else if ((d->type == BOX_INLINE) ||
- d->type == BOX_INLINE_BLOCK) {
- /* replaced inlines and inline-blocks */
- d->x += x0;
- d->y = *y + d->border[TOP].width + d->margin[TOP];
- h = d->margin[TOP] + d->border[TOP].width +
- d->padding[TOP] + d->height +
- d->padding[BOTTOM] +
- d->border[BOTTOM].width +
- d->margin[BOTTOM];
- if (used_height < h)
- used_height = h;
- }
- }
-
- first->flags |= NEW_LINE;
-
- assert(b != first || (move_y && 0 < used_height && (left || right)));
-
- /* handle vertical-align by adjusting box y values */
- /** \todo proper vertical alignment handling */
- for (d = first; d != b; d = d->next) {
- if ((d->type == BOX_INLINE && d->inline_end) ||
- d->type == BOX_BR ||
- d->type == BOX_TEXT ||
- d->type == BOX_INLINE_END) {
- css_fixed value = 0;
- css_unit unit = CSS_UNIT_PX;
- switch (css_computed_vertical_align(d->style, &value,
- &unit)) {
- case CSS_VERTICAL_ALIGN_SUPER:
- case CSS_VERTICAL_ALIGN_TOP:
- case CSS_VERTICAL_ALIGN_TEXT_TOP:
- /* already at top */
- break;
- case CSS_VERTICAL_ALIGN_SUB:
- case CSS_VERTICAL_ALIGN_BOTTOM:
- case CSS_VERTICAL_ALIGN_TEXT_BOTTOM:
- d->y += used_height - d->height;
- break;
- default:
- case CSS_VERTICAL_ALIGN_BASELINE:
- d->y += 0.75 * (used_height - d->height);
- break;
- }
- }
- }
-
- /* handle clearance for br */
- if (br_box && css_computed_clear(br_box->style) != CSS_CLEAR_NONE) {
- int clear_y = layout_clear(cont->float_children,
- css_computed_clear(br_box->style));
- if (used_height < clear_y - cy)
- used_height = clear_y - cy;
- }
-
- if (move_y)
- *y += used_height;
- *next_box = b;
- *width = x; /* return actual width */
- return true;
-}
-
-
-/**
- * Layout lines of text or inline boxes with floats.
- *
- * \param box inline container box
- * \param width horizontal space available
- * \param cont ancestor box which defines horizontal space, for floats
- * \param cx box position relative to cont
- * \param cy box position relative to cont
- * \param content memory pool for any new boxes
- * \return true on success, false on memory exhaustion
- */
-static bool layout_inline_container(struct box *inline_container, int width,
- struct box *cont, int cx, int cy, html_content *content)
-{
- bool first_line = true;
- bool has_text_children;
- struct box *c, *next;
- int y = 0;
- int curwidth,maxwidth = width;
-
- assert(inline_container->type == BOX_INLINE_CONTAINER);
-
- NSLOG(layout, DEBUG,
- "inline_container %p, width %i, cont %p, cx %i, cy %i",
- inline_container,
- width,
- cont,
- cx,
- cy);
-
-
- has_text_children = false;
- for (c = inline_container->children; c; c = c->next) {
- bool is_pre = false;
-
- if (c->style) {
- enum css_white_space_e whitespace;
-
- whitespace = css_computed_white_space(c->style);
-
- is_pre = (whitespace == CSS_WHITE_SPACE_PRE ||
- whitespace == CSS_WHITE_SPACE_PRE_LINE ||
- whitespace == CSS_WHITE_SPACE_PRE_WRAP);
- }
-
- if ((!c->object && !(c->flags & REPLACE_DIM) &&
- !(c->flags & IFRAME) &&
- c->text && (c->length || is_pre)) ||
- c->type == BOX_BR)
- has_text_children = true;
- }
-
- /** \todo fix wrapping so that a box with horizontal scrollbar will
- * shrink back to 'width' if no word is wider than 'width' (Or just set
- * curwidth = width and have the multiword lines wrap to the min width)
- */
- for (c = inline_container->children; c; ) {
-
- NSLOG(layout, DEBUG, "c %p", c);
-
- curwidth = inline_container->width;
- if (!layout_line(c, &curwidth, &y, cx, cy + y, cont, first_line,
- has_text_children, content, &next))
- return false;
- maxwidth = max(maxwidth,curwidth);
- c = next;
- first_line = false;
- }
-
- inline_container->width = maxwidth;
- inline_container->height = y;
-
- return true;
-}
-
-
-/**
- * Layout a block formatting context.
- *
- * \param block BLOCK, INLINE_BLOCK, or TABLE_CELL to layout
- * \param viewport_height Height of viewport in pixels or -ve if unknown
- * \param content Memory pool for any new boxes
- * \return true on success, false on memory exhaustion
- *
- * This function carries out layout of a block and its children, as described
- * in CSS 2.1 9.4.1.
- */
-static bool
-layout_block_context(struct box *block,
- int viewport_height,
- html_content *content)
-{
- struct box *box;
- int cx, cy; /**< current coordinates */
- int max_pos_margin = 0;
- int max_neg_margin = 0;
- int y = 0;
- int lm, rm;
- struct box *margin_collapse = NULL;
- bool in_margin = false;
- css_fixed gadget_size;
- css_unit gadget_unit; /* Checkbox / radio buttons */
-
- assert(block->type == BOX_BLOCK ||
- block->type == BOX_INLINE_BLOCK ||
- block->type == BOX_TABLE_CELL);
- assert(block->width != UNKNOWN_WIDTH);
- assert(block->width != AUTO);
-
- block->float_children = NULL;
- block->cached_place_below_level = 0;
- block->clear_level = 0;
-
- /* special case if the block contains an object */
- if (block->object) {
- int temp_width = block->width;
- if (!layout_block_object(block))
- return false;
- layout_get_object_dimensions(block, &temp_width,
- &block->height, INT_MIN, INT_MAX,
- INT_MIN, INT_MAX);
- return true;
- } else if (block->flags & REPLACE_DIM) {
- return true;
- }
-
- /* special case if the block contains an radio button or checkbox */
- if (block->gadget && (block->gadget->type == GADGET_RADIO ||
- block->gadget->type == GADGET_CHECKBOX)) {
- /* form checkbox or radio button
- * if width or height is AUTO, set it to 1em */
- gadget_unit = CSS_UNIT_EM;
- gadget_size = INTTOFIX(1);
- if (block->height == AUTO)
- block->height = FIXTOINT(nscss_len2px(
- &content->len_ctx, gadget_size,
- gadget_unit, block->style));
- }
-
- box = block->children;
- /* set current coordinates to top-left of the block */
- cx = 0;
- y = cy = block->padding[TOP];
- if (box)
- box->y = block->padding[TOP];
-
- /* Step through the descendants of the block in depth-first order, but
- * not into the children of boxes which aren't blocks. For example, if
- * the tree passed to this function looks like this (box->type shown):
- *
- * block -> BOX_BLOCK
- * BOX_BLOCK * (1)
- * BOX_INLINE_CONTAINER * (2)
- * BOX_INLINE
- * BOX_TEXT
- * ...
- * BOX_BLOCK * (3)
- * BOX_TABLE * (4)
- * BOX_TABLE_ROW
- * BOX_TABLE_CELL
- * ...
- * BOX_TABLE_CELL
- * ...
- * BOX_BLOCK * (5)
- * BOX_INLINE_CONTAINER * (6)
- * BOX_TEXT
- * ...
- * then the while loop will visit each box marked with *, setting box
- * to each in the order shown. */
- while (box) {
- enum css_overflow_e overflow_x = CSS_OVERFLOW_VISIBLE;
- enum css_overflow_e overflow_y = CSS_OVERFLOW_VISIBLE;
-
- assert(box->type == BOX_BLOCK || box->type == BOX_TABLE ||
- box->type == BOX_INLINE_CONTAINER);
-
- /* Tables are laid out before being positioned, because the
- * position depends on the width which is calculated in
- * table layout. Blocks and inline containers are positioned
- * before being laid out, because width is not dependent on
- * content, and the position is required during layout for
- * correct handling of floats.
- */
-
- if (box->style &&
- (css_computed_position(box->style) ==
- CSS_POSITION_ABSOLUTE ||
- css_computed_position(box->style) ==
- CSS_POSITION_FIXED)) {
- box->x = box->parent->padding[LEFT];
- /* absolute positioned; this element will establish
- * its own block context when it gets laid out later,
- * so no need to look at its children now. */
- goto advance_to_next_box;
- }
-
- /* If we don't know which box the current margin collapses
- * through to, find out. Update the pos/neg margin values. */
- if (margin_collapse == NULL) {
- margin_collapse = layout_next_margin_block(
- &content->len_ctx, box, block,
- viewport_height,
- &max_pos_margin, &max_neg_margin);
- /* We have a margin that has not yet been applied. */
- in_margin = true;
- }
-
- /* Clearance. */
- y = 0;
- if (box->style && css_computed_clear(box->style) !=
- CSS_CLEAR_NONE)
- y = layout_clear(block->float_children,
- css_computed_clear(box->style));
-
- /* Find box's overflow properties */
- if (box->style) {
- overflow_x = css_computed_overflow_x(box->style);
- overflow_y = css_computed_overflow_y(box->style);
- }
-
- /* Blocks establishing a block formatting context get minimum
- * left and right margins to avoid any floats. */
- lm = rm = 0;
-
- if (box->type == BOX_BLOCK || box->flags & IFRAME) {
- if (!box->object && !(box->flags & IFRAME) &&
- !(box->flags & REPLACE_DIM) &&
- box->style &&
- (overflow_x != CSS_OVERFLOW_VISIBLE ||
- overflow_y != CSS_OVERFLOW_VISIBLE)) {
- /* box establishes new block formatting context
- * so available width may be diminished due to
- * floats. */
- int x0, x1, top;
- struct box *left, *right;
- top = cy + max_pos_margin - max_neg_margin;
- top = (top > y) ? top : y;
- x0 = cx;
- x1 = cx + box->parent->width -
- box->parent->padding[LEFT] -
- box->parent->padding[RIGHT];
- find_sides(block->float_children, top, top,
- &x0, &x1, &left, &right);
- /* calculate min required left & right margins
- * needed to avoid floats */
- lm = x0 - cx;
- rm = cx + box->parent->width -
- box->parent->padding[LEFT] -
- box->parent->padding[RIGHT] -
- x1;
- }
- layout_block_find_dimensions(&content->len_ctx,
- box->parent->width,
- viewport_height, lm, rm, box);
- if (box->type == BOX_BLOCK && !(box->flags & IFRAME)) {
- layout_block_add_scrollbar(box, RIGHT);
- layout_block_add_scrollbar(box, BOTTOM);
- }
- } else if (box->type == BOX_TABLE) {
- if (box->style != NULL) {
- enum css_width_e wtype;
- css_fixed width = 0;
- css_unit unit = CSS_UNIT_PX;
-
- wtype = css_computed_width(box->style, &width,
- &unit);
-
- if (wtype == CSS_WIDTH_AUTO) {
- /* max available width may be
- * diminished due to floats. */
- int x0, x1, top;
- struct box *left, *right;
- top = cy + max_pos_margin -
- max_neg_margin;
- top = (top > y) ? top : y;
- x0 = cx;
- x1 = cx + box->parent->width -
- box->parent->padding[LEFT] -
- box->parent->padding[RIGHT];
- find_sides(block->float_children,
- top, top, &x0, &x1,
- &left, &right);
- /* calculate min required left & right
- * margins needed to avoid floats */
- lm = x0 - cx;
- rm = cx + box->parent->width -
- box->parent->padding[LEFT] -
- box->parent->padding[RIGHT] -
- x1;
- }
- }
- if (!layout_table(box, box->parent->width - lm - rm,
- content))
- return false;
- layout_solve_width(box, box->parent->width, box->width,
- lm, rm, -1, -1);
- }
-
- /* Position box: horizontal. */
- box->x = box->parent->padding[LEFT] + box->margin[LEFT] +
- box->border[LEFT].width;
- cx += box->x;
-
- /* Position box: vertical. */
- if (box->border[TOP].width) {
- box->y += box->border[TOP].width;
- cy += box->border[TOP].width;
- }
-
- /* Vertical margin */
- if (((box->type == BOX_BLOCK &&
- (box->flags & HAS_HEIGHT)) ||
- box->type == BOX_TABLE ||
- (box->type == BOX_INLINE_CONTAINER &&
- box != box->parent->children) ||
- margin_collapse == box) &&
- in_margin == true) {
- /* Margin goes above this box. */
- cy += max_pos_margin - max_neg_margin;
- box->y += max_pos_margin - max_neg_margin;
-
- /* Current margin has been applied. */
- in_margin = false;
- max_pos_margin = max_neg_margin = 0;
- }
-
- /* Handle clearance */
- if (box->type != BOX_INLINE_CONTAINER &&
- (y > 0) && (cy < y)) {
- /* box clears something*/
- box->y += y - cy;
- cy = y;
- }
-
- /* Unless the box has an overflow style of visible, the box
- * establishes a new block context. */
- if (box->type == BOX_BLOCK && box->style &&
- (overflow_x != CSS_OVERFLOW_VISIBLE ||
- overflow_y != CSS_OVERFLOW_VISIBLE)) {
-
- layout_block_context(box, viewport_height, content);
-
- cy += box->padding[TOP];
-
- if (box->height == AUTO) {
- box->height = 0;
- layout_block_add_scrollbar(box, BOTTOM);
- }
-
- cx -= box->x;
- cy += box->height + box->padding[BOTTOM] +
- box->border[BOTTOM].width;
- y = box->y + box->padding[TOP] + box->height +
- box->padding[BOTTOM] +
- box->border[BOTTOM].width;
-
- /* Skip children, because they are done in the new
- * block context */
- goto advance_to_next_box;
- }
-
- NSLOG(layout, DEBUG, "box %p, cx %i, cy %i", box, cx, cy);
-
- /* Layout (except tables). */
- if (box->object) {
- if (!layout_block_object(box))
- return false;
-
- } 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;
- struct box *left, *right;
- y = cy;
- while (1) {
- enum css_width_e wtype;
- css_fixed width = 0;
- css_unit unit = CSS_UNIT_PX;
-
- wtype = css_computed_width(box->style,
- &width, &unit);
-
- x0 = cx;
- x1 = cx + box->parent->width;
- find_sides(block->float_children, y,
- y + box->height,
- &x0, &x1, &left, &right);
- if (wtype == CSS_WIDTH_AUTO)
- break;
- if (box->width <= x1 - x0)
- break;
- if (!left && !right)
- break;
- else if (!left)
- y = right->y + right->height + 1;
- else if (!right)
- y = left->y + left->height + 1;
- else if (left->y + left->height <
- right->y + right->height)
- y = left->y + left->height + 1;
- else
- y = right->y + right->height + 1;
- }
- box->x += x0 - cx;
- cx = x0;
- box->y += y - cy;
- cy = y;
- }
-
- /* Advance to next box. */
- if (box->type == BOX_BLOCK && !box->object && !(box->iframe) &&
- box->children) {
- /* Down into children. */
-
- if (box == margin_collapse) {
- /* Current margin collapsed though to this box.
- * Unset margin_collapse. */
- margin_collapse = NULL;
- }
-
- y = box->padding[TOP];
- box = box->children;
- box->y = y;
- cy += y;
- continue;
- } else if (box->type == BOX_BLOCK || box->object ||
- box->flags & IFRAME)
- cy += box->padding[TOP];
-
- if (box->type == BOX_BLOCK && box->height == AUTO) {
- box->height = 0;
- layout_block_add_scrollbar(box, BOTTOM);
- }
-
- cy += box->height + box->padding[BOTTOM] +
- box->border[BOTTOM].width;
- cx -= box->x;
- y = box->y + box->padding[TOP] + box->height +
- box->padding[BOTTOM] +
- box->border[BOTTOM].width;
-
- advance_to_next_box:
- if (!box->next) {
- /* No more siblings:
- * up to first ancestor with a sibling. */
-
- do {
- if (box == margin_collapse) {
- /* Current margin collapsed though to
- * this box. Unset margin_collapse. */
- margin_collapse = NULL;
- }
-
- /* Apply bottom margin */
- if (max_pos_margin < box->margin[BOTTOM])
- max_pos_margin = box->margin[BOTTOM];
- else if (max_neg_margin < -box->margin[BOTTOM])
- max_neg_margin = -box->margin[BOTTOM];
-
- box = box->parent;
- if (box == block)
- break;
-
- /* Margin is invalidated if this is a box
- * margins can't collapse through. */
- if (box->type == BOX_BLOCK &&
- box->flags & MAKE_HEIGHT) {
- margin_collapse = NULL;
- in_margin = false;
- max_pos_margin = max_neg_margin = 0;
- }
-
- if (box->height == AUTO) {
- box->height = y - box->padding[TOP];
-
- if (box->type == BOX_BLOCK)
- layout_block_add_scrollbar(box,
- BOTTOM);
- } else
- cy += box->height -
- (y - box->padding[TOP]);
-
- /* Apply any min-height and max-height to
- * boxes in normal flow */
- if (box->style &&
- css_computed_position(box->style) !=
- CSS_POSITION_ABSOLUTE &&
- layout_apply_minmax_height(
- &content->len_ctx,
- box, NULL)) {
- /* Height altered */
- /* Set current cy */
- cy += box->height -
- (y - box->padding[TOP]);
- }
-
- cy += box->padding[BOTTOM] +
- box->border[BOTTOM].width;
- cx -= box->x;
- y = box->y + box->padding[TOP] + box->height +
- box->padding[BOTTOM] +
- box->border[BOTTOM].width;
-
- } while (box->next == NULL);
- if (box == block)
- break;
- }
-
- /* To next sibling. */
-
- if (box == margin_collapse) {
- /* Current margin collapsed though to this box.
- * Unset margin_collapse. */
- margin_collapse = NULL;
- }
-
- if (max_pos_margin < box->margin[BOTTOM])
- max_pos_margin = box->margin[BOTTOM];
- else if (max_neg_margin < -box->margin[BOTTOM])
- max_neg_margin = -box->margin[BOTTOM];
-
- box = box->next;
- box->y = y;
- }
-
- /* Account for bottom margin of last contained block */
- cy += max_pos_margin - max_neg_margin;
-
- /* Increase height to contain any floats inside (CSS 2.1 10.6.7). */
- for (box = block->float_children; box; box = box->next_float) {
- y = box->y + box->height + box->padding[BOTTOM] +
- box->border[BOTTOM].width + box->margin[BOTTOM];
- if (cy < y)
- cy = y;
- }
-
- if (block->height == AUTO) {
- block->height = cy - block->padding[TOP];
- if (block->type == BOX_BLOCK)
- layout_block_add_scrollbar(block, BOTTOM);
- }
-
- if (block->style && css_computed_position(block->style) !=
- CSS_POSITION_ABSOLUTE) {
- /* Block is in normal flow */
- layout_apply_minmax_height(&content->len_ctx, block, NULL);
- }
-
- if (block->gadget &&
- (block->gadget->type == GADGET_TEXTAREA ||
- block->gadget->type == GADGET_PASSWORD ||
- block->gadget->type == GADGET_TEXTBOX)) {
- plot_font_style_t fstyle;
- int ta_width = block->padding[LEFT] + block->width +
- block->padding[RIGHT];
- int ta_height = block->padding[TOP] + block->height +
- block->padding[BOTTOM];
- font_plot_style_from_css(&content->len_ctx,
- block->style, &fstyle);
- fstyle.background = NS_TRANSPARENT;
- textarea_set_layout(block->gadget->data.text.ta,
- &fstyle, ta_width, ta_height,
- block->padding[TOP], block->padding[RIGHT],
- block->padding[BOTTOM], block->padding[LEFT]);
- }
-
- return true;
-}
-
-
-/**
- * Layout list markers.
- */
-static void
-layout_lists(struct box *box,
- const struct gui_layout_table *font_func,
- const nscss_len_ctx *len_ctx)
-{
- struct box *child;
- struct box *marker;
- plot_font_style_t fstyle;
-
- for (child = box->children; child; child = child->next) {
- if (child->list_marker) {
- marker = child->list_marker;
- if (marker->object) {
- marker->width =
- content_get_width(marker->object);
- marker->x = -marker->width;
- marker->height =
- content_get_height(marker->object);
- marker->y = (line_height(len_ctx,
- marker->style) -
- marker->height) / 2;
- } else if (marker->text) {
- if (marker->width == UNKNOWN_WIDTH) {
- font_plot_style_from_css(len_ctx,
- marker->style, &fstyle);
- font_func->width(&fstyle,
- marker->text,
- marker->length,
- &marker->width);
- marker->flags |= MEASURED;
- }
- marker->x = -marker->width;
- marker->y = 0;
- marker->height = line_height(len_ctx,
- marker->style);
- } else {
- marker->x = 0;
- marker->y = 0;
- marker->width = 0;
- marker->height = 0;
- }
- /* Gap between marker and content */
- marker->x -= 4;
- }
- layout_lists(child, font_func, len_ctx);
- }
-}
-
-
-/**
- * Compute box offsets for a relatively or absolutely positioned box with
- * respect to a box.
- *
- * \param len_ctx Length conversion context
- * \param box box to compute offsets for
- * \param containing_block box to compute percentages with respect to
- * \param top updated to top offset, or AUTO
- * \param right updated to right offset, or AUTO
- * \param bottom updated to bottom offset, or AUTO
- * \param left updated to left offset, or AUTO
- *
- * See CSS 2.1 9.3.2. containing_block must have width and height.
- */
-static void
-layout_compute_offsets(const nscss_len_ctx *len_ctx,
- struct box *box,
- struct box *containing_block,
- int *top,
- int *right,
- int *bottom,
- int *left)
-{
- uint32_t type;
- css_fixed value = 0;
- css_unit unit = CSS_UNIT_PX;
-
- assert(containing_block->width != UNKNOWN_WIDTH &&
- containing_block->width != AUTO &&
- containing_block->height != AUTO);
-
- /* left */
- type = css_computed_left(box->style, &value, &unit);
- if (type == CSS_LEFT_SET) {
- if (unit == CSS_UNIT_PCT) {
- *left = FPCT_OF_INT_TOINT(value,
- containing_block->width);
- } else {
- *left = FIXTOINT(nscss_len2px(len_ctx,
- value, unit, box->style));
- }
- } else {
- *left = AUTO;
- }
-
- /* right */
- type = css_computed_right(box->style, &value, &unit);
- if (type == CSS_RIGHT_SET) {
- if (unit == CSS_UNIT_PCT) {
- *right = FPCT_OF_INT_TOINT(value,
- containing_block->width);
- } else {
- *right = FIXTOINT(nscss_len2px(len_ctx,
- value, unit, box->style));
- }
- } else {
- *right = AUTO;
- }
-
- /* top */
- type = css_computed_top(box->style, &value, &unit);
- if (type == CSS_TOP_SET) {
- if (unit == CSS_UNIT_PCT) {
- *top = FPCT_OF_INT_TOINT(value,
- containing_block->height);
- } else {
- *top = FIXTOINT(nscss_len2px(len_ctx,
- value, unit, box->style));
- }
- } else {
- *top = AUTO;
- }
-
- /* bottom */
- type = css_computed_bottom(box->style, &value, &unit);
- if (type == CSS_BOTTOM_SET) {
- if (unit == CSS_UNIT_PCT) {
- *bottom = FPCT_OF_INT_TOINT(value,
- containing_block->height);
- } else {
- *bottom = FIXTOINT(nscss_len2px(len_ctx,
- value, unit, box->style));
- }
- } else {
- *bottom = AUTO;
- }
-}
-
-
-/**
- * Layout and position an absolutely positioned box.
- *
- * \param box absolute box to layout and position
- * \param containing_block containing block
- * \param cx position of box relative to containing_block
- * \param cy position of box relative to containing_block
- * \param content memory pool for any new boxes
- * \return true on success, false on memory exhaustion
- */
-static bool
-layout_absolute(struct box *box,
- struct box *containing_block,
- int cx, int cy,
- html_content *content)
-{
- int static_left, static_top; /* static position */
- int top, right, bottom, left;
- int width, height, max_width, min_width;
- int *margin = box->margin;
- int *padding = box->padding;
- struct box_border *border = box->border;
- int available_width = containing_block->width;
- int space;
-
- assert(box->type == BOX_BLOCK || box->type == BOX_TABLE ||
- box->type == BOX_INLINE_BLOCK);
-
- /* The static position is where the box would be if it was not
- * absolutely positioned. The x and y are filled in by
- * layout_block_context(). */
- static_left = cx + box->x;
- static_top = cy + box->y;
-
- if (containing_block->type == BOX_BLOCK ||
- containing_block->type == BOX_INLINE_BLOCK ||
- containing_block->type == BOX_TABLE_CELL) {
- /* Block level container => temporarily increase containing
- * block dimensions to include padding (we restore this
- * again at the end) */
- containing_block->width += containing_block->padding[LEFT] +
- containing_block->padding[RIGHT];
- containing_block->height += containing_block->padding[TOP] +
- containing_block->padding[BOTTOM];
- } else {
- /** \todo inline containers */
- }
-
- layout_compute_offsets(&content->len_ctx, box, containing_block,
- &top, &right, &bottom, &left);
-
- /* Pass containing block into layout_find_dimensions via the float
- * containing block box member. This is unused for absolutely positioned
- * boxes because a box can't be floated and absolutely positioned. */
- box->float_container = containing_block;
- layout_find_dimensions(&content->len_ctx, available_width, -1,
- box, box->style, &width, &height,
- &max_width, &min_width, 0, 0,
- margin, padding, border);
- box->float_container = NULL;
-
- /* 10.3.7 */
- NSLOG(layout, DEBUG,
- "%i + %i + %i + %i + %i + %i + %i + %i + %i = %i",
- left, margin[LEFT], border[LEFT].width, padding[LEFT], width,
- padding[RIGHT], border[RIGHT].width, margin[RIGHT], right,
- containing_block->width);
-
-
- if (left == AUTO && width == AUTO && right == AUTO) {
- if (margin[LEFT] == AUTO)
- margin[LEFT] = 0;
- if (margin[RIGHT] == AUTO)
- margin[RIGHT] = 0;
- left = static_left;
-
- width = min(max(box->min_width, available_width),
- box->max_width);
- width -= box->margin[LEFT] + box->border[LEFT].width +
- box->padding[LEFT] + box->padding[RIGHT] +
- box->border[RIGHT].width + box->margin[RIGHT];
-
- /* Adjust for {min|max}-width */
- if (max_width >= 0 && width > max_width) width = max_width;
- if (width < min_width) width = min_width;
-
- right = containing_block->width -
- left -
- margin[LEFT] - border[LEFT].width - padding[LEFT] -
- width -
- padding[RIGHT] - border[RIGHT].width - margin[RIGHT];
- } else if (left != AUTO && width != AUTO && right != AUTO) {
-
- /* Adjust for {min|max}-width */
- if (max_width >= 0 && width > max_width) width = max_width;
- if (min_width > 0 && width < min_width) width = min_width;
-
- if (margin[LEFT] == AUTO && margin[RIGHT] == AUTO) {
- space = containing_block->width -
- left - border[LEFT].width -
- padding[LEFT] - width - padding[RIGHT] -
- border[RIGHT].width - right;
- if (space < 0) {
- margin[LEFT] = 0;
- margin[RIGHT] = space;
- } else {
- margin[LEFT] = margin[RIGHT] = space / 2;
- }
- } else if (margin[LEFT] == AUTO) {
- margin[LEFT] = containing_block->width -
- left - border[LEFT].width -
- padding[LEFT] - width - padding[RIGHT] -
- border[RIGHT].width - margin[RIGHT] -
- right;
- } else if (margin[RIGHT] == AUTO) {
- margin[RIGHT] = containing_block->width -
- left - margin[LEFT] -
- border[LEFT].width -
- padding[LEFT] - width - padding[RIGHT] -
- border[RIGHT].width - right;
- } else {
- right = containing_block->width -
- left - margin[LEFT] -
- border[LEFT].width -
- padding[LEFT] - width - padding[RIGHT] -
- border[RIGHT].width - margin[RIGHT];
- }
- } else {
- if (margin[LEFT] == AUTO)
- margin[LEFT] = 0;
- if (margin[RIGHT] == AUTO)
- margin[RIGHT] = 0;
-
- if (left == AUTO && width == AUTO && right != AUTO) {
- available_width -= right;
-
- width = min(max(box->min_width, available_width),
- box->max_width);
- width -= box->margin[LEFT] + box->border[LEFT].width +
- box->padding[LEFT] + box->padding[RIGHT] +
- box->border[RIGHT].width + box->margin[RIGHT];
-
- /* Adjust for {min|max}-width */
- if (max_width >= 0 && width > max_width)
- width = max_width;
- if (width < min_width)
- width = min_width;
-
- left = containing_block->width -
- margin[LEFT] - border[LEFT].width -
- padding[LEFT] - width - padding[RIGHT] -
- border[RIGHT].width - margin[RIGHT] -
- right;
- } else if (left == AUTO && width != AUTO && right == AUTO) {
-
- /* Adjust for {min|max}-width */
- if (max_width >= 0 && width > max_width)
- width = max_width;
- if (min_width > 0 && width < min_width)
- width = min_width;
-
- left = static_left;
- right = containing_block->width -
- left - margin[LEFT] -
- border[LEFT].width -
- padding[LEFT] - width - padding[RIGHT] -
- border[RIGHT].width - margin[RIGHT];
- } else if (left != AUTO && width == AUTO && right == AUTO) {
- available_width -= left;
-
- width = min(max(box->min_width, available_width),
- box->max_width);
- width -= box->margin[LEFT] + box->border[LEFT].width +
- box->padding[LEFT] + box->padding[RIGHT] +
- box->border[RIGHT].width + box->margin[RIGHT];
-
- /* Adjust for {min|max}-width */
- if (max_width >= 0 && width > max_width)
- width = max_width;
- if (width < min_width)
- width = min_width;
-
- right = containing_block->width -
- left - margin[LEFT] -
- border[LEFT].width -
- padding[LEFT] - width - padding[RIGHT] -
- border[RIGHT].width - margin[RIGHT];
- } else if (left == AUTO && width != AUTO && right != AUTO) {
-
- /* Adjust for {min|max}-width */
- if (max_width >= 0 && width > max_width)
- width = max_width;
- if (width < min_width)
- width = min_width;
-
- left = containing_block->width -
- margin[LEFT] - border[LEFT].width -
- padding[LEFT] - width - padding[RIGHT] -
- border[RIGHT].width - margin[RIGHT] -
- right;
- } else if (left != AUTO && width == AUTO && right != AUTO) {
- width = containing_block->width -
- left - margin[LEFT] -
- border[LEFT].width -
- padding[LEFT] - padding[RIGHT] -
- border[RIGHT].width - margin[RIGHT] -
- right;
-
- /* Adjust for {min|max}-width */
- if (max_width >= 0 && width > max_width)
- width = max_width;
- if (width < min_width)
- width = min_width;
-
- } else if (left != AUTO && width != AUTO && right == AUTO) {
-
- /* Adjust for {min|max}-width */
- if (max_width >= 0 && width > max_width)
- width = max_width;
- if (width < min_width)
- width = min_width;
-
- right = containing_block->width -
- left - margin[LEFT] -
- border[LEFT].width -
- padding[LEFT] - width - padding[RIGHT] -
- border[RIGHT].width - margin[RIGHT];
- }
- }
-
- NSLOG(layout, DEBUG,
- "%i + %i + %i + %i + %i + %i + %i + %i + %i = %i",
- left, margin[LEFT], border[LEFT].width, padding[LEFT], width,
- padding[RIGHT], border[RIGHT].width, margin[RIGHT], right,
- containing_block->width);
-
- box->x = left + margin[LEFT] + border[LEFT].width - cx;
- if (containing_block->type == BOX_BLOCK ||
- containing_block->type == BOX_INLINE_BLOCK ||
- containing_block->type == BOX_TABLE_CELL) {
- /* Block-level ancestor => reset container's width */
- containing_block->width -= containing_block->padding[LEFT] +
- containing_block->padding[RIGHT];
- } else {
- /** \todo inline ancestors */
- }
- box->width = width;
- box->height = height;
-
- if (box->type == BOX_BLOCK || box->type == BOX_INLINE_BLOCK ||
- box->object || box->flags & IFRAME) {
- if (!layout_block_context(box, -1, content))
- return false;
- } else if (box->type == BOX_TABLE) {
- /* layout_table also expects the containing block to be
- * stored in the float_container field */
- box->float_container = containing_block;
- /* \todo layout_table considers margins etc. again */
- if (!layout_table(box, width, content))
- return false;
- box->float_container = NULL;
- layout_solve_width(box, box->parent->width, box->width, 0, 0,
- -1, -1);
- }
-
- /* 10.6.4 */
- NSLOG(layout, DEBUG,
- "%i + %i + %i + %i + %i + %i + %i + %i + %i = %i",
- top, margin[TOP], border[TOP].width, padding[TOP], height,
- padding[BOTTOM], border[BOTTOM].width, margin[BOTTOM], bottom,
- containing_block->height);
-
- if (top == AUTO && height == AUTO && bottom == AUTO) {
- top = static_top;
- height = box->height;
- if (margin[TOP] == AUTO)
- margin[TOP] = 0;
- if (margin[BOTTOM] == AUTO)
- margin[BOTTOM] = 0;
- bottom = containing_block->height -
- top - margin[TOP] - border[TOP].width -
- padding[TOP] - height - padding[BOTTOM] -
- border[BOTTOM].width - margin[BOTTOM];
- } else if (top != AUTO && height != AUTO && bottom != AUTO) {
- if (margin[TOP] == AUTO && margin[BOTTOM] == AUTO) {
- space = containing_block->height -
- top - border[TOP].width - padding[TOP] -
- height - padding[BOTTOM] -
- border[BOTTOM].width - bottom;
- margin[TOP] = margin[BOTTOM] = space / 2;
- } else if (margin[TOP] == AUTO) {
- margin[TOP] = containing_block->height -
- top - border[TOP].width - padding[TOP] -
- height - padding[BOTTOM] -
- border[BOTTOM].width - margin[BOTTOM] -
- bottom;
- } else if (margin[BOTTOM] == AUTO) {
- margin[BOTTOM] = containing_block->height -
- top - margin[TOP] - border[TOP].width -
- padding[TOP] - height -
- padding[BOTTOM] - border[BOTTOM].width -
- bottom;
- } else {
- bottom = containing_block->height -
- top - margin[TOP] - border[TOP].width -
- padding[TOP] - height -
- padding[BOTTOM] - border[BOTTOM].width -
- margin[BOTTOM];
- }
- } else {
- if (margin[TOP] == AUTO)
- margin[TOP] = 0;
- if (margin[BOTTOM] == AUTO)
- margin[BOTTOM] = 0;
- if (top == AUTO && height == AUTO && bottom != AUTO) {
- height = box->height;
- top = containing_block->height -
- margin[TOP] - border[TOP].width -
- padding[TOP] - height -
- padding[BOTTOM] - border[BOTTOM].width -
- margin[BOTTOM] - bottom;
- } else if (top == AUTO && height != AUTO && bottom == AUTO) {
- top = static_top;
- bottom = containing_block->height -
- top - margin[TOP] - border[TOP].width -
- padding[TOP] - height -
- padding[BOTTOM] - border[BOTTOM].width -
- margin[BOTTOM];
- } else if (top != AUTO && height == AUTO && bottom == AUTO) {
- height = box->height;
- bottom = containing_block->height -
- top - margin[TOP] - border[TOP].width -
- padding[TOP] - height -
- padding[BOTTOM] - border[BOTTOM].width -
- margin[BOTTOM];
- } else if (top == AUTO && height != AUTO && bottom != AUTO) {
- top = containing_block->height -
- margin[TOP] - border[TOP].width -
- padding[TOP] - height -
- padding[BOTTOM] - border[BOTTOM].width -
- margin[BOTTOM] - bottom;
- } else if (top != AUTO && height == AUTO && bottom != AUTO) {
- height = containing_block->height -
- top - margin[TOP] - border[TOP].width -
- padding[TOP] - padding[BOTTOM] -
- border[BOTTOM].width - margin[BOTTOM] -
- bottom;
- } else if (top != AUTO && height != AUTO && bottom == AUTO) {
- bottom = containing_block->height -
- top - margin[TOP] - border[TOP].width -
- padding[TOP] - height -
- padding[BOTTOM] - border[BOTTOM].width -
- margin[BOTTOM];
- }
- }
-
- NSLOG(layout, DEBUG,
- "%i + %i + %i + %i + %i + %i + %i + %i + %i = %i",
- top, margin[TOP], border[TOP].width, padding[TOP], height,
- padding[BOTTOM], border[BOTTOM].width, margin[BOTTOM], bottom,
- containing_block->height);
-
- box->y = top + margin[TOP] + border[TOP].width - cy;
- if (containing_block->type == BOX_BLOCK ||
- containing_block->type == BOX_INLINE_BLOCK ||
- containing_block->type == BOX_TABLE_CELL) {
- /* Block-level ancestor => reset container's height */
- containing_block->height -= containing_block->padding[TOP] +
- containing_block->padding[BOTTOM];
- } else {
- /** \todo Inline ancestors */
- }
- box->height = height;
- layout_apply_minmax_height(&content->len_ctx, box, containing_block);
-
- return true;
-}
-
-
-/**
- * Recursively layout and position absolutely positioned boxes.
- *
- * \param box tree of boxes to layout
- * \param containing_block current containing block
- * \param cx position of box relative to containing_block
- * \param cy position of box relative to containing_block
- * \param content memory pool for any new boxes
- * \return true on success, false on memory exhaustion
- */
-static bool
-layout_position_absolute(struct box *box,
- struct box *containing_block,
- int cx, int cy,
- html_content *content)
-{
- struct box *c;
-
- for (c = box->children; c; c = c->next) {
- if ((c->type == BOX_BLOCK || c->type == BOX_TABLE ||
- c->type == BOX_INLINE_BLOCK) &&
- (css_computed_position(c->style) ==
- CSS_POSITION_ABSOLUTE ||
- css_computed_position(c->style) ==
- CSS_POSITION_FIXED)) {
- if (!layout_absolute(c, containing_block,
- cx, cy, content))
- return false;
- if (!layout_position_absolute(c, c, 0, 0, content))
- return false;
- } else if (c->style && css_computed_position(c->style) ==
- CSS_POSITION_RELATIVE) {
- if (!layout_position_absolute(c, c, 0, 0, content))
- return false;
- } else {
- int px, py;
- if (c->style && (css_computed_float(c->style) ==
- CSS_FLOAT_LEFT ||
- css_computed_float(c->style) ==
- CSS_FLOAT_RIGHT)) {
- /* Float x/y coords are relative to nearest
- * ansestor with float_children, rather than
- * relative to parent. Need to get x/y relative
- * to parent */
- struct box *p;
- px = c->x;
- py = c->y;
- for (p = box->parent; p && !p->float_children;
- p = p->parent) {
- px -= p->x;
- py -= p->y;
- }
- } else {
- /* Not a float, so box x/y coords are relative
- * to parent */
- px = c->x;
- py = c->y;
- }
- if (!layout_position_absolute(c, containing_block,
- cx + px, cy + py, content))
- return false;
- }
- }
-
- return true;
-}
-
-
-/**
- * Compute a box's relative offset as per CSS 2.1 9.4.3
- *
- * \param len_ctx Length conversion context
- * \param box Box to compute relative offsets for.
- * \param x Receives relative offset in x.
- * \param y Receives relative offset in y.
- */
-static void layout_compute_relative_offset(
- const nscss_len_ctx *len_ctx,
- struct box *box,
- int *x,
- int *y)
-{
- int left, right, top, bottom;
- struct box *containing_block;
-
- assert(box && box->parent && box->style &&
- css_computed_position(box->style) ==
- CSS_POSITION_RELATIVE);
-
- if (box->float_container &&
- (css_computed_float(box->style) == CSS_FLOAT_LEFT ||
- css_computed_float(box->style) == CSS_FLOAT_RIGHT)) {
- containing_block = box->float_container;
- } else {
- containing_block = box->parent;
- }
-
- layout_compute_offsets(len_ctx, box, containing_block,
- &top, &right, &bottom, &left);
-
- if (left == AUTO && right == AUTO)
- left = right = 0;
- else if (left == AUTO)
- /* left is auto => computed = -right */
- left = -right;
- else if (right == AUTO)
- /* right is auto => computed = -left */
- right = -left;
- else {
- /* over constrained => examine direction property
- * of containing block */
- if (containing_block->style &&
- css_computed_direction(
- containing_block->style) ==
- CSS_DIRECTION_RTL) {
- /* right wins */
- left = -right;
- } else {
- /* assume LTR in all other cases */
- right = -left;
- }
- }
-
- assert(left == -right);
-
- if (top == AUTO && bottom == AUTO) {
- top = bottom = 0;
- } else if (top == AUTO) {
- top = -bottom;
- } else {
- /* bottom is AUTO, or neither are AUTO */
- bottom = -top;
- }
-
- NSLOG(layout, DEBUG, "left %i, right %i, top %i, bottom %i", left,
- right, top, bottom);
-
- *x = left;
- *y = top;
-}
-
-
-/**
- * Adjust positions of relatively positioned boxes.
- *
- * \param len_ctx Length conversion context
- * \param root box to adjust the position of
- * \param fp box which forms the block formatting context for children of
- * "root" which are floats
- * \param fx x offset due to intervening relatively positioned boxes
- * between current box, "root", and the block formatting context
- * box, "fp", for float children of "root"
- * \param fy y offset due to intervening relatively positioned boxes
- * between current box, "root", and the block formatting context
- * box, "fp", for float children of "root"
- */
-static void
-layout_position_relative(
- const nscss_len_ctx *len_ctx,
- struct box *root,
- struct box *fp,
- int fx,
- int fy)
-{
- struct box *box; /* for children of "root" */
- struct box *fn; /* for block formatting context box for children of
- * "box" */
- struct box *fc; /* for float children of the block formatting context,
- * "fp" */
- int x, y; /* for the offsets resulting from any relative
- * positioning on the current block */
- int fnx, fny; /* for affsets which apply to flat children of "box" */
-
- /**\todo ensure containing box is large enough after moving boxes */
-
- assert(root);
-
- /* Normal children */
- for (box = root->children; box; box = box->next) {
-
- if (box->type == BOX_TEXT)
- continue;
-
- /* If relatively positioned, get offsets */
- if (box->style && css_computed_position(box->style) ==
- CSS_POSITION_RELATIVE)
- layout_compute_relative_offset(
- len_ctx, box, &x, &y);
- else
- x = y = 0;
-
- /* Adjust float coordinates.
- * (note float x and y are relative to their block formatting
- * context box and not their parent) */
- if (box->style && (css_computed_float(box->style) ==
- CSS_FLOAT_LEFT ||
- css_computed_float(box->style) ==
- CSS_FLOAT_RIGHT) &&
- (fx != 0 || fy != 0)) {
- /* box is a float and there is a float offset to
- * apply */
- for (fc = fp->float_children; fc; fc = fc->next_float) {
- if (box == fc->children) {
- /* Box is floated in the block
- * formatting context block, fp.
- * Apply float offsets. */
- box->x += fx;
- box->y += fy;
- fx = fy = 0;
- }
- }
- }
-
- if (box->float_children) {
- fn = box;
- fnx = fny = 0;
- } else {
- fn = fp;
- fnx = fx + x;
- fny = fy + y;
- }
-
- /* recurse first */
- layout_position_relative(len_ctx, box, fn, fnx, fny);
-
- /* Ignore things we're not interested in. */
- if (!box->style || (box->style &&
- css_computed_position(box->style) !=
- CSS_POSITION_RELATIVE))
- continue;
-
- box->x += x;
- box->y += y;
-
- /* Handle INLINEs - their "children" are in fact
- * the sibling boxes between the INLINE and
- * INLINE_END boxes */
- if (box->type == BOX_INLINE && box->inline_end) {
- struct box *b;
- for (b = box->next; b && b != box->inline_end;
- b = b->next) {
- b->x += x;
- b->y += y;
- }
- }
- }
-}
-
-
-/**
- * Find a box's bounding box relative to itself, i.e. the box's border edge box
- *
- * \param len_ctx Length conversion context
- * \param box box find bounding box of
- * \param desc_x0 updated to left of box's bbox
- * \param desc_y0 updated to top of box's bbox
- * \param desc_x1 updated to right of box's bbox
- * \param desc_y1 updated to bottom of box's bbox
- */
-static void
-layout_get_box_bbox(
- const nscss_len_ctx *len_ctx,
- struct box *box,
- int *desc_x0, int *desc_y0,
- int *desc_x1, int *desc_y1)
-{
- *desc_x0 = -box->border[LEFT].width;
- *desc_y0 = -box->border[TOP].width;
- *desc_x1 = box->padding[LEFT] + box->width + box->padding[RIGHT] +
- box->border[RIGHT].width;
- *desc_y1 = box->padding[TOP] + box->height + box->padding[BOTTOM] +
- box->border[BOTTOM].width;
-
- /* To stop the top of text getting clipped when css line-height is
- * reduced, we increase the top of the descendant bbox. */
- if (box->type == BOX_BLOCK && box->style != NULL &&
- css_computed_overflow_y(box->style) ==
- CSS_OVERFLOW_VISIBLE &&
- box->object == NULL) {
- css_fixed font_size = 0;
- css_unit font_unit = CSS_UNIT_PT;
- int text_height;
-
- css_computed_font_size(box->style, &font_size, &font_unit);
- text_height = nscss_len2px(len_ctx, font_size, font_unit,
- box->style);
- text_height = FIXTOINT(text_height * 3 / 4);
- *desc_y0 = (*desc_y0 < -text_height) ? *desc_y0 : -text_height;
- }
-}
-
-
-/**
- * Apply changes to box descendant_[xy][01] values due to given child.
- *
- * \param len_ctx Length conversion context
- * \param box box to update
- * \param child a box, which may affect box's descendant bbox
- * \param off_x offset to apply to child->x coord to treat as child of box
- * \param off_y offset to apply to child->y coord to treat as child of box
- */
-static void
-layout_update_descendant_bbox(
- const nscss_len_ctx *len_ctx,
- struct box *box,
- struct box *child,
- int off_x,
- int off_y)
-{
- int child_desc_x0, child_desc_y0, child_desc_x1, child_desc_y1;
-
- /* get coordinates of child relative to box */
- int child_x = child->x - off_x;
- int child_y = child->y - off_y;
-
- bool html_object = (child->object &&
- content_get_type(child->object) == CONTENT_HTML);
-
- enum css_overflow_e overflow_x = CSS_OVERFLOW_VISIBLE;
- enum css_overflow_e overflow_y = CSS_OVERFLOW_VISIBLE;
-
- if (child->style != NULL) {
- overflow_x = css_computed_overflow_x(child->style);
- overflow_y = css_computed_overflow_y(child->style);
- }
-
- /* Get child's border edge */
- layout_get_box_bbox(len_ctx, child,
- &child_desc_x0, &child_desc_y0,
- &child_desc_x1, &child_desc_y1);
-
- if (overflow_x == CSS_OVERFLOW_VISIBLE &&
- html_object == false) {
- /* get child's descendant bbox relative to box */
- child_desc_x0 = child->descendant_x0;
- child_desc_x1 = child->descendant_x1;
- }
- if (overflow_y == CSS_OVERFLOW_VISIBLE &&
- html_object == false) {
- /* get child's descendant bbox relative to box */
- child_desc_y0 = child->descendant_y0;
- child_desc_y1 = child->descendant_y1;
- }
-
- child_desc_x0 += child_x;
- child_desc_y0 += child_y;
- child_desc_x1 += child_x;
- child_desc_y1 += child_y;
-
- /* increase box's descendant bbox to contain descendants */
- if (child_desc_x0 < box->descendant_x0)
- box->descendant_x0 = child_desc_x0;
- if (child_desc_y0 < box->descendant_y0)
- box->descendant_y0 = child_desc_y0;
- if (box->descendant_x1 < child_desc_x1)
- box->descendant_x1 = child_desc_x1;
- if (box->descendant_y1 < child_desc_y1)
- box->descendant_y1 = child_desc_y1;
-}
-
-
-/**
- * Recursively calculate the descendant_[xy][01] values for a laid-out box tree
- * and inform iframe browser windows of their size and position.
- *
- * \param len_ctx Length conversion context
- * \param box tree of boxes to update
- */
-static void layout_calculate_descendant_bboxes(
- const nscss_len_ctx *len_ctx,
- struct box *box)
-{
- struct box *child;
-
- assert(box->width != UNKNOWN_WIDTH);
- assert(box->height != AUTO);
- /* assert((box->width >= 0) && (box->height >= 0)); */
-
- /* Initialise box's descendant box to border edge box */
- layout_get_box_bbox(len_ctx, box,
- &box->descendant_x0, &box->descendant_y0,
- &box->descendant_x1, &box->descendant_y1);
-
- /* Extend it to contain HTML contents if box is replaced */
- if (box->object && content_get_type(box->object) == CONTENT_HTML) {
- if (box->descendant_x1 < content_get_width(box->object))
- box->descendant_x1 = content_get_width(box->object);
- if (box->descendant_y1 < content_get_height(box->object))
- box->descendant_y1 = content_get_height(box->object);
- }
-
- if (box->iframe != NULL) {
- int x, y;
- box_coords(box, &x, &y);
-
- browser_window_set_position(box->iframe, x, y);
- browser_window_set_dimensions(box->iframe,
- box->width, box->height);
- browser_window_reformat(box->iframe, true,
- box->width, box->height);
- }
-
- if (box->type == BOX_INLINE || box->type == BOX_TEXT)
- return;
-
- if (box->type == BOX_INLINE_END) {
- box = box->inline_end;
- for (child = box->next; child;
- child = child->next) {
- if (child->type == BOX_FLOAT_LEFT ||
- child->type == BOX_FLOAT_RIGHT)
- continue;
-
- layout_update_descendant_bbox(len_ctx, box, child,
- box->x, box->y);
-
- if (child == box->inline_end)
- break;
- }
- return;
- }
-
- if (box->flags & REPLACE_DIM)
- /* Box's children aren't displayed if the box is replaced */
- return;
-
- for (child = box->children; child; child = child->next) {
- if (child->type == BOX_FLOAT_LEFT ||
- child->type == BOX_FLOAT_RIGHT)
- continue;
-
- layout_calculate_descendant_bboxes(len_ctx, child);
-
- if (box->style && css_computed_overflow_x(box->style) ==
- CSS_OVERFLOW_HIDDEN &&
- css_computed_overflow_y(box->style) ==
- CSS_OVERFLOW_HIDDEN)
- continue;
-
- layout_update_descendant_bbox(len_ctx, box, child, 0, 0);
- }
-
- for (child = box->float_children; child; child = child->next_float) {
- assert(child->type == BOX_FLOAT_LEFT ||
- child->type == BOX_FLOAT_RIGHT);
-
- layout_calculate_descendant_bboxes(len_ctx, child);
-
- layout_update_descendant_bbox(len_ctx, box, child, 0, 0);
- }
-
- if (box->list_marker) {
- child = box->list_marker;
- layout_calculate_descendant_bboxes(len_ctx, child);
-
- layout_update_descendant_bbox(len_ctx, box, child, 0, 0);
- }
-}
-
-
-/* exported function documented in render/layout.h */
-bool layout_document(html_content *content, int width, int height)
-{
- bool ret;
- struct box *doc = content->layout;
- const struct gui_layout_table *font_func = content->font_func;
-
- layout_minmax_block(doc, font_func, content);
-
- layout_block_find_dimensions(&content->len_ctx,
- width, height, 0, 0, doc);
- doc->x = doc->margin[LEFT] + doc->border[LEFT].width;
- doc->y = doc->margin[TOP] + doc->border[TOP].width;
- width -= doc->margin[LEFT] + doc->border[LEFT].width +
- doc->padding[LEFT] + doc->padding[RIGHT] +
- doc->border[RIGHT].width + doc->margin[RIGHT];
- if (width < 0) {
- width = 0;
- }
- doc->width = width;
-
- ret = layout_block_context(doc, height, content);
-
- /* make <html> and <body> fill available height */
- if (doc->y + doc->padding[TOP] + doc->height + doc->padding[BOTTOM] +
- doc->border[BOTTOM].width + doc->margin[BOTTOM] <
- height) {
- doc->height = height - (doc->y + doc->padding[TOP] +
- doc->padding[BOTTOM] +
- doc->border[BOTTOM].width +
- doc->margin[BOTTOM]);
- if (doc->children)
- doc->children->height = doc->height -
- (doc->children->margin[TOP] +
- doc->children->border[TOP].width +
- doc->children->padding[TOP] +
- doc->children->padding[BOTTOM] +
- doc->children->border[BOTTOM].width +
- doc->children->margin[BOTTOM]);
- }
-
- layout_lists(doc, font_func, &content->len_ctx);
- layout_position_absolute(doc, doc, 0, 0, content);
- layout_position_relative(&content->len_ctx, doc, doc, 0, 0);
-
- layout_calculate_descendant_bboxes(&content->len_ctx, doc);
-
- return ret;
-}
diff --git a/render/layout.h b/render/layout.h
deleted file mode 100644
index cd5ddd77f..000000000
--- a/render/layout.h
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * Copyright 2003 James Bursa <bursa@users.sourceforge.net>
- *
- * This file is part of NetSurf, http://www.netsurf-browser.org/
- *
- * NetSurf is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * NetSurf is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-/**
- * \file
- * HTML layout (interface).
- *
- * The main interface to the layout code is layout_document(), which takes a
- * normalized box tree and assigns coordinates and dimensions to the boxes, and
- * also adds boxes to the tree (eg. when formatting lines of text).
- */
-
-#ifndef _NETSURF_RENDER_LAYOUT_H_
-#define _NETSURF_RENDER_LAYOUT_H_
-
-struct box;
-struct html_content;
-struct gui_layout_table;
-
-/**
- * Calculate positions of boxes in a document.
- *
- * \param content content of type CONTENT_HTML
- * \param width available width
- * \param height available height
- * \return true on success, false on memory exhaustion
- */
-bool layout_document(struct html_content *content, int width, int height);
-
-#endif
diff --git a/render/search.c b/render/search.c
deleted file mode 100644
index ca9520165..000000000
--- a/render/search.c
+++ /dev/null
@@ -1,656 +0,0 @@
-/*
- * Copyright 2004 John M Bell <jmb202@ecs.soton.ac.uk>
- * Copyright 2005 Adrian Lees <adrianl@users.sourceforge.net>
- * Copyright 2009 Mark Benjamin <netsurf-browser.org.MarkBenjamin@dfgh.net>
- *
- * This file is part of NetSurf, http://www.netsurf-browser.org/
- *
- * NetSurf is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * NetSurf is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-/**
- * \file
- * Free text search (core)
- */
-
-#include <ctype.h>
-#include <string.h>
-#include <dom/dom.h>
-
-#include "utils/config.h"
-#include "utils/log.h"
-#include "utils/messages.h"
-#include "utils/utils.h"
-#include "content/content.h"
-#include "content/hlcache.h"
-#include "desktop/selection.h"
-#include "netsurf/search.h"
-#include "netsurf/misc.h"
-#include "desktop/gui_internal.h"
-
-#include "render/box.h"
-#include "render/html.h"
-#include "render/html_internal.h"
-#include "render/search.h"
-#include "render/textplain.h"
-
-#ifndef NOF_ELEMENTS
-#define NOF_ELEMENTS(array) (sizeof(array)/sizeof(*(array)))
-#endif
-
-
-struct list_entry {
- unsigned start_idx; /* start position of match */
- unsigned end_idx; /* end of match */
-
- struct box *start_box; /* used only for html contents */
- struct box *end_box;
-
- struct selection *sel;
-
- struct list_entry *prev;
- struct list_entry *next;
-};
-
-struct search_context {
- void *gui_p;
- struct content *c;
- struct list_entry *found;
- struct list_entry *current; /* first for select all */
- char *string;
- bool prev_case_sens;
- bool newsearch;
- bool is_html;
-};
-
-
-/* Exported function documented in search.h */
-struct search_context * search_create_context(struct content *c,
- content_type type, void *gui_data)
-{
- struct search_context *context;
- struct list_entry *search_head;
-
- if (type != CONTENT_HTML && type != CONTENT_TEXTPLAIN) {
- return NULL;
- }
-
- context = malloc(sizeof(struct search_context));
- if (context == NULL) {
- guit->misc->warning("NoMemory", 0);
- return NULL;
- }
-
- search_head = malloc(sizeof(struct list_entry));
- if (search_head == NULL) {
- guit->misc->warning("NoMemory", 0);
- free(context);
- return NULL;
- }
-
- search_head->start_idx = 0;
- search_head->end_idx = 0;
- search_head->start_box = NULL;
- search_head->end_box = NULL;
- search_head->sel = NULL;
- search_head->prev = NULL;
- search_head->next = NULL;
-
- context->found = search_head;
- context->current = NULL;
- context->string = NULL;
- context->prev_case_sens = false;
- context->newsearch = true;
- context->c = c;
- context->is_html = (type == CONTENT_HTML) ? true : false;
- context->gui_p = gui_data;
-
- return context;
-}
-
-
-/**
- * Release the memory used by the list of matches,
- * deleting selection objects too
- */
-
-static void free_matches(struct search_context *context)
-{
- struct list_entry *a;
- struct list_entry *b;
-
- a = context->found->next;
-
- /* empty the list before clearing and deleting the
- * selections because the the clearing updates the
- * screen immediately, causing nested accesses to the list */
-
- context->found->prev = NULL;
- context->found->next = NULL;
-
- for (; a; a = b) {
- b = a->next;
- if (a->sel) {
- selection_clear(a->sel, true);
- selection_destroy(a->sel);
- }
- free(a);
- }
-}
-
-
-/**
- * Find the first occurrence of 'match' in 'string' and return its index
- *
- * \param string the string to be searched (unterminated)
- * \param s_len length of the string to be searched
- * \param pattern the pattern for which we are searching (unterminated)
- * \param p_len length of pattern
- * \param case_sens true iff case sensitive match required
- * \param m_len accepts length of match in bytes
- * \return pointer to first match, NULL if none
- */
-
-static const char *find_pattern(const char *string, int s_len,
- const char *pattern, int p_len, bool case_sens,
- unsigned int *m_len)
-{
- struct { const char *ss, *s, *p; bool first; } context[16];
- const char *ep = pattern + p_len;
- const char *es = string + s_len;
- const char *p = pattern - 1; /* a virtual '*' before the pattern */
- const char *ss = string;
- const char *s = string;
- bool first = true;
- int top = 0;
-
- while (p < ep) {
- bool matches;
- if (p < pattern || *p == '*') {
- char ch;
-
- /* skip any further asterisks; one is the same as many
- */
- do p++; while (p < ep && *p == '*');
-
- /* if we're at the end of the pattern, yes, it matches
- */
- if (p >= ep) break;
-
- /* anything matches a # so continue matching from
- here, and stack a context that will try to match
- the wildcard against the next character */
-
- ch = *p;
- if (ch != '#') {
- /* scan forwards until we find a match for
- this char */
- if (!case_sens) ch = toupper(ch);
- while (s < es) {
- if (case_sens) {
- if (*s == ch) break;
- } else if (toupper(*s) == ch)
- break;
- s++;
- }
- }
-
- if (s < es) {
- /* remember where we are in case the match
- fails; we may then resume */
- if (top < (int)NOF_ELEMENTS(context)) {
- context[top].ss = ss;
- context[top].s = s + 1;
- context[top].p = p - 1;
- /* ptr to last asterisk */
- context[top].first = first;
- top++;
- }
-
- if (first) {
- ss = s;
- /* remember first non-'*' char */
- first = false;
- }
-
- matches = true;
- } else {
- matches = false;
- }
-
- } else if (s < es) {
- char ch = *p;
- if (ch == '#')
- matches = true;
- else {
- if (case_sens)
- matches = (*s == ch);
- else
- matches = (toupper(*s) == toupper(ch));
- }
- if (matches && first) {
- ss = s; /* remember first non-'*' char */
- first = false;
- }
- } else {
- matches = false;
- }
-
- if (matches) {
- p++; s++;
- } else {
- /* doesn't match,
- * resume with stacked context if we have one */
- if (--top < 0)
- return NULL; /* no match, give up */
-
- ss = context[top].ss;
- s = context[top].s;
- p = context[top].p;
- first = context[top].first;
- }
- }
-
- /* end of pattern reached */
- *m_len = max(s - ss, 1);
- return ss;
-}
-
-
-/**
- * Add a new entry to the list of matches
- *
- * \param start_idx Offset of match start within textual representation
- * \param end_idx Offset of match end
- * \param context The search context to add the entry to.
- * \return Pointer to added entry, NULL iff failed.
- */
-
-static struct list_entry *add_entry(unsigned start_idx, unsigned end_idx,
- struct search_context *context)
-{
- struct list_entry *entry;
-
- /* found string in box => add to list */
- entry = calloc(1, sizeof(*entry));
- if (!entry) {
- guit->misc->warning("NoMemory", 0);
- return NULL;
- }
-
- entry->start_idx = start_idx;
- entry->end_idx = end_idx;
- entry->sel = NULL;
-
- entry->next = 0;
- entry->prev = context->found->prev;
-
- if (context->found->prev == NULL)
- context->found->next = entry;
- else
- context->found->prev->next = entry;
-
- context->found->prev = entry;
-
- return entry;
-}
-
-
-/**
- * Finds all occurrences of a given string in the html box tree
- *
- * \param pattern the string pattern to search for
- * \param p_len pattern length
- * \param cur pointer to the current box
- * \param case_sens whether to perform a case sensitive search
- * \param context The search context to add the entry to.
- * \return true on success, false on memory allocation failure
- */
-static bool find_occurrences_html(const char *pattern, int p_len,
- struct box *cur, bool case_sens,
- struct search_context *context)
-{
- struct box *a;
-
- /* ignore this box, if there's no visible text */
- if (!cur->object && cur->text) {
- const char *text = cur->text;
- unsigned length = cur->length;
-
- while (length > 0) {
- struct list_entry *entry;
- unsigned match_length;
- unsigned match_offset;
- const char *new_text;
- const char *pos = find_pattern(text, length,
- pattern, p_len, case_sens,
- &match_length);
- if (!pos)
- break;
-
- /* found string in box => add to list */
- match_offset = pos - cur->text;
-
- entry = add_entry(cur->byte_offset + match_offset,
- cur->byte_offset +
- match_offset +
- match_length, context);
- if (!entry)
- return false;
-
- entry->start_box = cur;
- entry->end_box = cur;
-
- new_text = pos + match_length;
- length -= (new_text - text);
- text = new_text;
- }
- }
-
- /* and recurse */
- for (a = cur->children; a; a = a->next) {
- if (!find_occurrences_html(pattern, p_len, a, case_sens,
- context))
- return false;
- }
-
- return true;
-}
-
-
-/**
- * Finds all occurrences of a given string in a textplain content
- *
- * \param pattern the string pattern to search for
- * \param p_len pattern length
- * \param c the content to be searched
- * \param case_sens whether to perform a case sensitive search
- * \param context The search context to add the entry to.
- * \return true on success, false on memory allocation failure
- */
-
-static bool find_occurrences_text(const char *pattern, int p_len,
- struct content *c, bool case_sens,
- struct search_context *context)
-{
- int nlines = textplain_line_count(c);
- int line;
-
- for(line = 0; line < nlines; line++) {
- size_t offset, length;
- const char *text = textplain_get_line(c, line,
- &offset, &length);
- if (text) {
- while (length > 0) {
- struct list_entry *entry;
- unsigned match_length;
- size_t start_idx;
- const char *new_text;
- const char *pos = find_pattern(text, length,
- pattern, p_len, case_sens,
- &match_length);
- if (!pos)
- break;
-
- /* found string in line => add to list */
- start_idx = offset + (pos - text);
- entry = add_entry(start_idx, start_idx +
- match_length, context);
- if (!entry)
- return false;
-
- new_text = pos + match_length;
- offset += (new_text - text);
- length -= (new_text - text);
- text = new_text;
- }
- }
- }
-
- return true;
-}
-
-
-/**
- * Search for a string in the box tree
- *
- * \param string the string to search for
- * \param string_len length of search string
- * \param context The search context to add the entry to.
- * \param flags flags to control the search.
- */
-static void search_text(const char *string, int string_len,
- struct search_context *context, search_flags_t flags)
-{
- struct rect bounds;
- struct box *box = NULL;
- union content_msg_data msg_data;
- bool case_sensitive, forwards, showall;
-
- case_sensitive = ((flags & SEARCH_FLAG_CASE_SENSITIVE) != 0) ?
- true : false;
- forwards = ((flags & SEARCH_FLAG_FORWARDS) != 0) ? true : false;
- showall = ((flags & SEARCH_FLAG_SHOWALL) != 0) ? true : false;
-
- if (context->c == NULL)
- return;
-
- if (context->is_html == true) {
- html_content *html = (html_content *)context->c;
-
- box = html->layout;
-
- if (!box)
- return;
- }
-
-
- /* check if we need to start a new search or continue an old one */
- if (context->newsearch) {
- bool res;
-
- if (context->string != NULL)
- free(context->string);
-
- context->current = NULL;
- free_matches(context);
-
- context->string = malloc(string_len + 1);
- if (context->string != NULL) {
- memcpy(context->string, string, string_len);
- context->string[string_len] = '\0';
- }
-
- guit->search->hourglass(true, context->gui_p);
-
- if (context->is_html == true) {
- res = find_occurrences_html(string, string_len,
- box, case_sensitive, context);
- } else {
- res = find_occurrences_text(string, string_len,
- context->c, case_sensitive, context);
- }
-
- if (!res) {
- free_matches(context);
- guit->search->hourglass(false, context->gui_p);
- return;
- }
- guit->search->hourglass(false, context->gui_p);
-
- context->prev_case_sens = case_sensitive;
-
- /* new search, beginning at the top of the page */
- context->current = context->found->next;
- context->newsearch = false;
-
- } else if (context->current != NULL) {
- /* continued search in the direction specified */
- if (forwards) {
- if (context->current->next)
- context->current = context->current->next;
- } else {
- if (context->current->prev)
- context->current = context->current->prev;
- }
- }
-
- guit->search->status((context->current != NULL), context->gui_p);
-
- search_show_all(showall, context);
-
- guit->search->back_state((context->current != NULL) &&
- (context->current->prev != NULL),
- context->gui_p);
- guit->search->forward_state((context->current != NULL) &&
- (context->current->next != NULL),
- context->gui_p);
-
- if (context->current == NULL)
- return;
-
- if (context->is_html == true) {
- /* get box position and jump to it */
- box_coords(context->current->start_box, &bounds.x0, &bounds.y0);
- /* \todo: move x0 in by correct idx */
- box_coords(context->current->end_box, &bounds.x1, &bounds.y1);
- /* \todo: move x1 in by correct idx */
- bounds.x1 += context->current->end_box->width;
- bounds.y1 += context->current->end_box->height;
- } else {
- textplain_coords_from_range(context->c,
- context->current->start_idx,
- context->current->end_idx, &bounds);
- }
-
- msg_data.scroll.area = true;
- msg_data.scroll.x0 = bounds.x0;
- msg_data.scroll.y0 = bounds.y0;
- msg_data.scroll.x1 = bounds.x1;
- msg_data.scroll.y1 = bounds.y1;
- content_broadcast(context->c, CONTENT_MSG_SCROLL, &msg_data);
-}
-
-
-/* Exported function documented in search.h */
-void search_step(struct search_context *context, search_flags_t flags,
- const char *string)
-{
- int string_len;
- int i = 0;
-
- if (context == NULL) {
- guit->misc->warning("SearchError", 0);
- return;
- }
-
- guit->search->add_recent(string, context->gui_p);
-
- string_len = strlen(string);
- for (i = 0; i < string_len; i++)
- if (string[i] != '#' && string[i] != '*')
- break;
- if (i >= string_len) {
- union content_msg_data msg_data;
- free_matches(context);
-
- guit->search->status(true, context->gui_p);
- guit->search->back_state(false, context->gui_p);
- guit->search->forward_state(false, context->gui_p);
-
- msg_data.scroll.area = false;
- msg_data.scroll.x0 = 0;
- msg_data.scroll.y0 = 0;
- content_broadcast(context->c, CONTENT_MSG_SCROLL, &msg_data);
- return;
- }
- search_text(string, string_len, context, flags);
-}
-
-
-/* Exported function documented in search.h */
-bool search_term_highlighted(struct content *c,
- unsigned start_offset, unsigned end_offset,
- unsigned *start_idx, unsigned *end_idx,
- struct search_context *context)
-{
- if (c == context->c) {
- struct list_entry *a;
- for (a = context->found->next; a; a = a->next)
- if (a->sel && selection_defined(a->sel) &&
- selection_highlighted(a->sel,
- start_offset, end_offset,
- start_idx, end_idx))
- return true;
- }
-
- return false;
-}
-
-
-/* Exported function documented in search.h */
-void search_show_all(bool all, struct search_context *context)
-{
- struct list_entry *a;
-
- for (a = context->found->next; a; a = a->next) {
- bool add = true;
- if (!all && a != context->current) {
- add = false;
- if (a->sel) {
- selection_clear(a->sel, true);
- selection_destroy(a->sel);
- a->sel = NULL;
- }
- }
- if (add && !a->sel) {
-
- if (context->is_html == true) {
- html_content *html = (html_content *)context->c;
- a->sel = selection_create(context->c, true);
- if (!a->sel)
- continue;
-
- selection_init(a->sel, html->layout,
- &html->len_ctx);
- } else {
- a->sel = selection_create(context->c, false);
- if (!a->sel)
- continue;
-
- selection_init(a->sel, NULL, NULL);
- }
-
- selection_set_start(a->sel, a->start_idx);
- selection_set_end(a->sel, a->end_idx);
- }
- }
-}
-
-
-/* Exported function documented in search.h */
-void search_destroy_context(struct search_context *context)
-{
- assert(context != NULL);
-
- if (context->string != NULL) {
- guit->search->add_recent(context->string, context->gui_p);
- free(context->string);
- }
-
- guit->search->forward_state(true, context->gui_p);
- guit->search->back_state(true, context->gui_p);
-
- free_matches(context);
- free(context);
-}
diff --git a/render/search.h b/render/search.h
deleted file mode 100644
index 79d1ee3d3..000000000
--- a/render/search.h
+++ /dev/null
@@ -1,81 +0,0 @@
-/*
- * Copyright 2009 Mark Benjamin <netsurf-browser.org.MarkBenjamin@dfgh.net>
- *
- * This file is part of NetSurf, http://www.netsurf-browser.org/
- *
- * NetSurf is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * NetSurf is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef _NETSURF_RENDER_SEARCH_H_
-#define _NETSURF_RENDER_SEARCH_H_
-
-#include <ctype.h>
-#include <string.h>
-
-#include "desktop/search.h"
-
-struct search_context;
-
-/**
- * create a search_context
- *
- * \param c The content the search_context is connected to
- * \param type The content type of c
- * \param context A context pointer passed to the provider routines.
- * \return A new search context or NULL on error.
- */
-struct search_context *search_create_context(struct content *c,
- content_type type, void *context);
-
-/**
- * Ends the search process, invalidating all state
- * freeing the list of found boxes
- */
-void search_destroy_context(struct search_context *context);
-
-/**
- * Begins/continues the search process
- *
- * \note that this may be called many times for a single search.
- *
- * \param context The search context in use.
- * \param flags The flags forward/back etc
- * \param string The string to match
- */
-void search_step(struct search_context *context, search_flags_t flags,
- const char * string);
-
-/**
- * Specifies whether all matches or just the current match should
- * be highlighted in the search text.
- */
-void search_show_all(bool all, struct search_context *context);
-
-/**
- * Determines whether any portion of the given text box should be
- * selected because it matches the current search string.
- *
- * \param c The content to hilight within.
- * \param start_offset byte offset within text of string to be checked
- * \param end_offset byte offset within text
- * \param start_idx byte offset within string of highlight start
- * \param end_idx byte offset of highlight end
- * \param context The search context to hilight entries from.
- * \return true iff part of the box should be highlighted
- */
-bool search_term_highlighted(struct content *c,
- unsigned start_offset, unsigned end_offset,
- unsigned *start_idx, unsigned *end_idx,
- struct search_context *context);
-
-#endif
diff --git a/render/table.c b/render/table.c
deleted file mode 100644
index 08a2e805c..000000000
--- a/render/table.c
+++ /dev/null
@@ -1,1080 +0,0 @@
-/*
- * Copyright 2005 James Bursa <bursa@users.sourceforge.net>
- * Copyright 2005 Richard Wilson <info@tinct.net>
- *
- * This file is part of NetSurf, http://www.netsurf-browser.org/
- *
- * NetSurf is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * NetSurf is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-/** \file
- * Table processing and layout (implementation).
- */
-
-#include <assert.h>
-#include <dom/dom.h>
-
-#include "utils/log.h"
-#include "utils/talloc.h"
-#include "css/utils.h"
-
-#include "render/box.h"
-#include "render/table.h"
-
-/* Define to enable verbose table debug */
-#undef TABLE_DEBUG
-
-/**
- * Container for border values during table border calculations
- */
-struct border {
- enum css_border_style_e style; /**< border-style */
- enum css_border_color_e color; /**< border-color type */
- css_color c; /**< border-color value */
- css_fixed width; /**< border-width length */
- css_unit unit; /**< border-width units */
-};
-
-static void table_used_left_border_for_cell(
- const nscss_len_ctx *len_ctx,
- struct box *cell);
-static void table_used_top_border_for_cell(
- const nscss_len_ctx *len_ctx,
- struct box *cell);
-static void table_used_right_border_for_cell(
- const nscss_len_ctx *len_ctx,
- struct box *cell);
-static void table_used_bottom_border_for_cell(
- const nscss_len_ctx *len_ctx,
- struct box *cell);
-static bool table_border_is_more_eyecatching(
- const nscss_len_ctx *len_ctx,
- const struct border *a,
- box_type a_src,
- const struct border *b,
- box_type b_src);
-static void table_cell_top_process_table(
- const nscss_len_ctx *len_ctx,
- struct box *table,
- struct border *a,
- box_type *a_src);
-static bool table_cell_top_process_group(
- const nscss_len_ctx *len_ctx,
- struct box *cell,
- struct box *group,
- struct border *a,
- box_type *a_src);
-static bool table_cell_top_process_row(
- const nscss_len_ctx *len_ctx,
- struct box *cell,
- struct box *row,
- struct border *a,
- box_type *a_src);
-
-
-/**
- * Determine the column width types for a table.
- *
- * \param len_ctx Length conversion context
- * \param table box of type BOX_TABLE
- * \return true on success, false on memory exhaustion
- *
- * The table->col array is allocated and type and width are filled in for each
- * column.
- */
-
-bool table_calculate_column_types(
- const nscss_len_ctx *len_ctx,
- struct box *table)
-{
- unsigned int i, j;
- struct column *col;
- struct box *row_group, *row, *cell;
-
- if (table->col)
- /* table->col already constructed, for example frameset table */
- return true;
-
- table->col = col = talloc_array(table, struct column, table->columns);
- if (!col)
- return false;
-
- for (i = 0; i != table->columns; i++) {
- col[i].type = COLUMN_WIDTH_UNKNOWN;
- col[i].width = 0;
- col[i].positioned = true;
- }
-
- /* 1st pass: cells with colspan 1 only */
- for (row_group = table->children; row_group; row_group =row_group->next)
- for (row = row_group->children; row; row = row->next)
- for (cell = row->children; cell; cell = cell->next) {
- enum css_width_e type;
- css_fixed value = 0;
- css_unit unit = CSS_UNIT_PX;
-
- assert(cell->type == BOX_TABLE_CELL);
- assert(cell->style);
-
- if (cell->columns != 1)
- continue;
- i = cell->start_column;
-
- if (css_computed_position(cell->style) !=
- CSS_POSITION_ABSOLUTE &&
- css_computed_position(cell->style) !=
- CSS_POSITION_FIXED) {
- col[i].positioned = false;
- }
-
- type = css_computed_width(cell->style, &value, &unit);
-
- /* fixed width takes priority over any other width type */
- if (col[i].type != COLUMN_WIDTH_FIXED &&
- type == CSS_WIDTH_SET && unit != CSS_UNIT_PCT) {
- col[i].type = COLUMN_WIDTH_FIXED;
- col[i].width = FIXTOINT(nscss_len2px(len_ctx,
- value, unit, cell->style));
- if (col[i].width < 0)
- col[i].width = 0;
- continue;
- }
-
- if (col[i].type != COLUMN_WIDTH_UNKNOWN)
- continue;
-
- if (type == CSS_WIDTH_SET && unit == CSS_UNIT_PCT) {
- col[i].type = COLUMN_WIDTH_PERCENT;
- col[i].width = FIXTOINT(value);
- if (col[i].width < 0)
- col[i].width = 0;
- } else if (type == CSS_WIDTH_AUTO) {
- col[i].type = COLUMN_WIDTH_AUTO;
- }
- }
-
- /* 2nd pass: cells which span multiple columns */
- for (row_group = table->children; row_group; row_group =row_group->next)
- for (row = row_group->children; row; row = row->next)
- for (cell = row->children; cell; cell = cell->next) {
- unsigned int fixed_columns = 0, percent_columns = 0,
- auto_columns = 0, unknown_columns = 0;
- int fixed_width = 0, percent_width = 0;
- enum css_width_e type;
- css_fixed value = 0;
- css_unit unit = CSS_UNIT_PX;
-
- if (cell->columns == 1)
- continue;
- i = cell->start_column;
-
- for (j = i; j < i + cell->columns; j++) {
- col[j].positioned = false;
- }
-
- /* count column types in spanned cells */
- for (j = 0; j != cell->columns; j++) {
- if (col[i + j].type == COLUMN_WIDTH_FIXED) {
- fixed_width += col[i + j].width;
- fixed_columns++;
- } else if (col[i + j].type == COLUMN_WIDTH_PERCENT) {
- percent_width += col[i + j].width;
- percent_columns++;
- } else if (col[i + j].type == COLUMN_WIDTH_AUTO) {
- auto_columns++;
- } else {
- unknown_columns++;
- }
- }
-
- if (!unknown_columns)
- continue;
-
- type = css_computed_width(cell->style, &value, &unit);
-
- /* if cell is fixed width, and all spanned columns are fixed
- * or unknown width, split extra width among unknown columns */
- if (type == CSS_WIDTH_SET && unit != CSS_UNIT_PCT &&
- fixed_columns + unknown_columns ==
- cell->columns) {
- int width = (FIXTOFLT(nscss_len2px(len_ctx, value, unit,
- cell->style)) - fixed_width) /
- unknown_columns;
- if (width < 0)
- width = 0;
- for (j = 0; j != cell->columns; j++) {
- if (col[i + j].type == COLUMN_WIDTH_UNKNOWN) {
- col[i + j].type = COLUMN_WIDTH_FIXED;
- col[i + j].width = width;
- }
- }
- }
-
- /* as above for percentage width */
- if (type == CSS_WIDTH_SET && unit == CSS_UNIT_PCT &&
- percent_columns + unknown_columns ==
- cell->columns) {
- int width = (FIXTOFLT(value) -
- percent_width) / unknown_columns;
- if (width < 0)
- width = 0;
- for (j = 0; j != cell->columns; j++) {
- if (col[i + j].type == COLUMN_WIDTH_UNKNOWN) {
- col[i + j].type = COLUMN_WIDTH_PERCENT;
- col[i + j].width = width;
- }
- }
- }
- }
-
- /* use AUTO if no width type was specified */
- for (i = 0; i != table->columns; i++) {
- if (col[i].type == COLUMN_WIDTH_UNKNOWN)
- col[i].type = COLUMN_WIDTH_AUTO;
- }
-
-#ifdef TABLE_DEBUG
- for (i = 0; i != table->columns; i++)
- NSLOG(netsurf, INFO,
- "table %p, column %u: type %s, width %i", table, i, ((const char *[]){
- "UNKNOWN",
- "FIXED",
- "AUTO",
- "PERCENT",
- "RELATIVE",
- })[col[i].type], col[i].width);
-#endif
-
- return true;
-}
-
-/**
- * Calculate used values of border-{trbl}-{style,color,width} for table cells.
- *
- * \param len_ctx Length conversion context
- * \param cell Table cell to consider
- *
- * \post \a cell's border array is populated
- */
-void table_used_border_for_cell(
- const nscss_len_ctx *len_ctx,
- struct box *cell)
-{
- int side;
-
- assert(cell->type == BOX_TABLE_CELL);
-
- if (css_computed_border_collapse(cell->style) ==
- CSS_BORDER_COLLAPSE_SEPARATE) {
- css_fixed width = 0;
- css_unit unit = CSS_UNIT_PX;
-
- /* Left border */
- cell->border[LEFT].style =
- css_computed_border_left_style(cell->style);
- css_computed_border_left_color(cell->style,
- &cell->border[LEFT].c);
- css_computed_border_left_width(cell->style, &width, &unit);
- cell->border[LEFT].width =
- FIXTOINT(nscss_len2px(len_ctx,
- width, unit, cell->style));
-
- /* Top border */
- cell->border[TOP].style =
- css_computed_border_top_style(cell->style);
- css_computed_border_top_color(cell->style,
- &cell->border[TOP].c);
- css_computed_border_top_width(cell->style, &width, &unit);
- cell->border[TOP].width =
- FIXTOINT(nscss_len2px(len_ctx,
- width, unit, cell->style));
-
- /* Right border */
- cell->border[RIGHT].style =
- css_computed_border_right_style(cell->style);
- css_computed_border_right_color(cell->style,
- &cell->border[RIGHT].c);
- css_computed_border_right_width(cell->style, &width, &unit);
- cell->border[RIGHT].width =
- FIXTOINT(nscss_len2px(len_ctx,
- width, unit, cell->style));
-
- /* Bottom border */
- cell->border[BOTTOM].style =
- css_computed_border_bottom_style(cell->style);
- css_computed_border_bottom_color(cell->style,
- &cell->border[BOTTOM].c);
- css_computed_border_bottom_width(cell->style, &width, &unit);
- cell->border[BOTTOM].width =
- FIXTOINT(nscss_len2px(len_ctx,
- width, unit, cell->style));
- } else {
- /* Left border */
- table_used_left_border_for_cell(len_ctx, cell);
-
- /* Top border */
- table_used_top_border_for_cell(len_ctx, cell);
-
- /* Right border */
- table_used_right_border_for_cell(len_ctx, cell);
-
- /* Bottom border */
- table_used_bottom_border_for_cell(len_ctx, cell);
- }
-
- /* Finally, ensure that any borders configured as
- * hidden or none have zero width. (c.f. layout_find_dimensions) */
- for (side = 0; side != 4; side++) {
- if (cell->border[side].style == CSS_BORDER_STYLE_HIDDEN ||
- cell->border[side].style ==
- CSS_BORDER_STYLE_NONE)
- cell->border[side].width = 0;
- }
-}
-
-/******************************************************************************
- * Helpers for used border calculations *
- ******************************************************************************/
-
-/**
- * Calculate used values of border-left-{style,color,width}
- *
- * \param len_ctx Length conversion context
- * \param cell Table cell to consider
- */
-void table_used_left_border_for_cell(
- const nscss_len_ctx *len_ctx,
- struct box *cell)
-{
- struct border a, b;
- box_type a_src, b_src;
-
- /** \todo Need column and column_group, too */
-
- /* Initialise to computed left border for cell */
- a.style = css_computed_border_left_style(cell->style);
- a.color = css_computed_border_left_color(cell->style, &a.c);
- css_computed_border_left_width(cell->style, &a.width, &a.unit);
- a.width = nscss_len2px(len_ctx, a.width, a.unit, cell->style);
- a.unit = CSS_UNIT_PX;
- a_src = BOX_TABLE_CELL;
-
- if (cell->prev != NULL || cell->start_column != 0) {
- /* Cell to the left -- consider its right border */
- struct box *prev = NULL;
-
- if (cell->prev == NULL) {
- struct box *row;
-
- /* Spanned from a previous row in current row group */
- for (row = cell->parent; row != NULL; row = row->prev) {
- for (prev = row->children; prev != NULL;
- prev = prev->next) {
- if (prev->start_column +
- prev->columns ==
- cell->start_column)
- break;
- }
-
- if (prev != NULL)
- break;
- }
-
- assert(prev != NULL);
- } else {
- prev = cell->prev;
- }
-
- b.style = css_computed_border_right_style(prev->style);
- b.color = css_computed_border_right_color(prev->style, &b.c);
- css_computed_border_right_width(prev->style, &b.width, &b.unit);
- b.width = nscss_len2px(len_ctx, b.width, b.unit, prev->style);
- b.unit = CSS_UNIT_PX;
- b_src = BOX_TABLE_CELL;
-
- if (table_border_is_more_eyecatching(len_ctx,
- &a, a_src, &b, b_src)) {
- a = b;
- a_src = b_src;
- }
- } else {
- /* First cell in row, so consider rows and row group */
- struct box *row = cell->parent;
- struct box *group = row->parent;
- struct box *table = group->parent;
- unsigned int rows = cell->rows;
-
- while (rows-- > 0 && row != NULL) {
- /* Spanned rows -- consider their left border */
- b.style = css_computed_border_left_style(row->style);
- b.color = css_computed_border_left_color(
- row->style, &b.c);
- css_computed_border_left_width(
- row->style, &b.width, &b.unit);
- b.width = nscss_len2px(len_ctx,
- b.width, b.unit, row->style);
- b.unit = CSS_UNIT_PX;
- b_src = BOX_TABLE_ROW;
-
- if (table_border_is_more_eyecatching(len_ctx,
- &a, a_src, &b, b_src)) {
- a = b;
- a_src = b_src;
- }
-
- row = row->next;
- }
-
- /** \todo can cells span row groups? */
-
- /* Row group -- consider its left border */
- b.style = css_computed_border_left_style(group->style);
- b.color = css_computed_border_left_color(group->style, &b.c);
- css_computed_border_left_width(group->style, &b.width, &b.unit);
- b.width = nscss_len2px(len_ctx, b.width, b.unit, group->style);
- b.unit = CSS_UNIT_PX;
- b_src = BOX_TABLE_ROW_GROUP;
-
- if (table_border_is_more_eyecatching(len_ctx,
- &a, a_src, &b, b_src)) {
- a = b;
- a_src = b_src;
- }
-
- /* The table itself -- consider its left border */
- b.style = css_computed_border_left_style(table->style);
- b.color = css_computed_border_left_color(table->style, &b.c);
- css_computed_border_left_width(table->style, &b.width, &b.unit);
- b.width = nscss_len2px(len_ctx, b.width, b.unit, table->style);
- b.unit = CSS_UNIT_PX;
- b_src = BOX_TABLE;
-
- if (table_border_is_more_eyecatching(len_ctx,
- &a, a_src, &b, b_src)) {
- a = b;
- a_src = b_src;
- }
- }
-
- /* a now contains the used left border for the cell */
- cell->border[LEFT].style = a.style;
- cell->border[LEFT].c = a.c;
- cell->border[LEFT].width = FIXTOINT(nscss_len2px(len_ctx,
- a.width, a.unit, cell->style));
-}
-
-/**
- * Calculate used values of border-top-{style,color,width}
- *
- * \param len_ctx Length conversion context
- * \param cell Table cell to consider
- */
-void table_used_top_border_for_cell(
- const nscss_len_ctx *len_ctx,
- struct box *cell)
-{
- struct border a, b;
- box_type a_src, b_src;
- struct box *row = cell->parent;
- bool process_group = false;
-
- /* Initialise to computed top border for cell */
- a.style = css_computed_border_top_style(cell->style);
- css_computed_border_top_color(cell->style, &a.c);
- css_computed_border_top_width(cell->style, &a.width, &a.unit);
- a.width = nscss_len2px(len_ctx, a.width, a.unit, cell->style);
- a.unit = CSS_UNIT_PX;
- a_src = BOX_TABLE_CELL;
-
- /* Top border of row */
- b.style = css_computed_border_top_style(row->style);
- css_computed_border_top_color(row->style, &b.c);
- css_computed_border_top_width(row->style, &b.width, &b.unit);
- b.width = nscss_len2px(len_ctx, b.width, b.unit, row->style);
- b.unit = CSS_UNIT_PX;
- b_src = BOX_TABLE_ROW;
-
- if (table_border_is_more_eyecatching(len_ctx, &a, a_src, &b, b_src)) {
- a = b;
- a_src = b_src;
- }
-
- if (row->prev != NULL) {
- /* Consider row(s) above */
- while (table_cell_top_process_row(len_ctx, cell, row->prev,
- &a, &a_src) == false) {
- if (row->prev->prev == NULL) {
- /* Consider row group */
- process_group = true;
- break;
- } else {
- row = row->prev;
- }
- }
- } else {
- process_group = true;
- }
-
- if (process_group) {
- struct box *group = row->parent;
-
- /* Top border of row group */
- b.style = css_computed_border_top_style(group->style);
- b.color = css_computed_border_top_color(group->style, &b.c);
- css_computed_border_top_width(group->style, &b.width, &b.unit);
- b.width = nscss_len2px(len_ctx, b.width, b.unit, group->style);
- b.unit = CSS_UNIT_PX;
- b_src = BOX_TABLE_ROW_GROUP;
-
- if (table_border_is_more_eyecatching(len_ctx,
- &a, a_src, &b, b_src)) {
- a = b;
- a_src = b_src;
- }
-
- if (group->prev == NULL) {
- /* Top border of table */
- table_cell_top_process_table(len_ctx,
- group->parent, &a, &a_src);
- } else {
- /* Process previous group(s) */
- while (table_cell_top_process_group(len_ctx,
- cell, group->prev,
- &a, &a_src) == false) {
- if (group->prev->prev == NULL) {
- /* Top border of table */
- table_cell_top_process_table(len_ctx,
- group->parent,
- &a, &a_src);
- break;
- } else {
- group = group->prev;
- }
- }
- }
- }
-
- /* a now contains the used top border for the cell */
- cell->border[TOP].style = a.style;
- cell->border[TOP].c = a.c;
- cell->border[TOP].width = FIXTOINT(nscss_len2px(len_ctx,
- a.width, a.unit, cell->style));
-}
-
-/**
- * Calculate used values of border-right-{style,color,width}
- *
- * \param len_ctx Length conversion context
- * \param cell Table cell to consider
- */
-void table_used_right_border_for_cell(
- const nscss_len_ctx *len_ctx,
- struct box *cell)
-{
- struct border a, b;
- box_type a_src, b_src;
-
- /** \todo Need column and column_group, too */
-
- /* Initialise to computed right border for cell */
- a.style = css_computed_border_right_style(cell->style);
- css_computed_border_right_color(cell->style, &a.c);
- css_computed_border_right_width(cell->style, &a.width, &a.unit);
- a.width = nscss_len2px(len_ctx, a.width, a.unit, cell->style);
- a.unit = CSS_UNIT_PX;
- a_src = BOX_TABLE_CELL;
-
- if (cell->next != NULL || cell->start_column + cell->columns !=
- cell->parent->parent->parent->columns) {
- /* Cell is not at right edge of table -- no right border */
- a.style = CSS_BORDER_STYLE_NONE;
- a.width = 0;
- a.unit = CSS_UNIT_PX;
- } else {
- /* Last cell in row, so consider rows and row group */
- struct box *row = cell->parent;
- struct box *group = row->parent;
- struct box *table = group->parent;
- unsigned int rows = cell->rows;
-
- while (rows-- > 0 && row != NULL) {
- /* Spanned rows -- consider their right border */
- b.style = css_computed_border_right_style(row->style);
- b.color = css_computed_border_right_color(
- row->style, &b.c);
- css_computed_border_right_width(
- row->style, &b.width, &b.unit);
- b.width = nscss_len2px(len_ctx,
- b.width, b.unit, row->style);
- b.unit = CSS_UNIT_PX;
- b_src = BOX_TABLE_ROW;
-
- if (table_border_is_more_eyecatching(len_ctx,
- &a, a_src, &b, b_src)) {
- a = b;
- a_src = b_src;
- }
-
- row = row->next;
- }
-
- /** \todo can cells span row groups? */
-
- /* Row group -- consider its right border */
- b.style = css_computed_border_right_style(group->style);
- b.color = css_computed_border_right_color(group->style, &b.c);
- css_computed_border_right_width(group->style,
- &b.width, &b.unit);
- b.width = nscss_len2px(len_ctx, b.width, b.unit, group->style);
- b.unit = CSS_UNIT_PX;
- b_src = BOX_TABLE_ROW_GROUP;
-
- if (table_border_is_more_eyecatching(len_ctx,
- &a, a_src, &b, b_src)) {
- a = b;
- a_src = b_src;
- }
-
- /* The table itself -- consider its right border */
- b.style = css_computed_border_right_style(table->style);
- b.color = css_computed_border_right_color(table->style, &b.c);
- css_computed_border_right_width(table->style,
- &b.width, &b.unit);
- b.width = nscss_len2px(len_ctx, b.width, b.unit, table->style);
- b.unit = CSS_UNIT_PX;
- b_src = BOX_TABLE;
-
- if (table_border_is_more_eyecatching(len_ctx,
- &a, a_src, &b, b_src)) {
- a = b;
- a_src = b_src;
- }
- }
-
- /* a now contains the used right border for the cell */
- cell->border[RIGHT].style = a.style;
- cell->border[RIGHT].c = a.c;
- cell->border[RIGHT].width = FIXTOINT(nscss_len2px(len_ctx,
- a.width, a.unit, cell->style));
-}
-
-/**
- * Calculate used values of border-bottom-{style,color,width}
- *
- * \param len_ctx Length conversion context
- * \param cell Table cell to consider
- */
-void table_used_bottom_border_for_cell(
- const nscss_len_ctx *len_ctx,
- struct box *cell)
-{
- struct border a, b;
- box_type a_src, b_src;
- struct box *row = cell->parent;
- unsigned int rows = cell->rows;
-
- /* Initialise to computed bottom border for cell */
- a.style = css_computed_border_bottom_style(cell->style);
- css_computed_border_bottom_color(cell->style, &a.c);
- css_computed_border_bottom_width(cell->style, &a.width, &a.unit);
- a.width = nscss_len2px(len_ctx, a.width, a.unit, cell->style);
- a.unit = CSS_UNIT_PX;
- a_src = BOX_TABLE_CELL;
-
- while (rows-- > 0 && row != NULL)
- row = row->next;
-
- /** \todo Can cells span row groups? */
-
- if (row != NULL) {
- /* Cell is not at bottom edge of table -- no bottom border */
- a.style = CSS_BORDER_STYLE_NONE;
- a.width = 0;
- a.unit = CSS_UNIT_PX;
- } else {
- /* Cell at bottom of table, so consider row and row group */
- struct box *row = cell->parent;
- struct box *group = row->parent;
- struct box *table = group->parent;
-
- /* Bottom border of row */
- b.style = css_computed_border_bottom_style(row->style);
- b.color = css_computed_border_bottom_color(row->style, &b.c);
- css_computed_border_bottom_width(row->style, &b.width, &b.unit);
- b.width = nscss_len2px(len_ctx, b.width, b.unit, row->style);
- b.unit = CSS_UNIT_PX;
- b_src = BOX_TABLE_ROW;
-
- if (table_border_is_more_eyecatching(len_ctx,
- &a, a_src, &b, b_src)) {
- a = b;
- a_src = b_src;
- }
-
- /* Row group -- consider its bottom border */
- b.style = css_computed_border_bottom_style(group->style);
- b.color = css_computed_border_bottom_color(group->style, &b.c);
- css_computed_border_bottom_width(group->style,
- &b.width, &b.unit);
- b.width = nscss_len2px(len_ctx, b.width, b.unit, group->style);
- b.unit = CSS_UNIT_PX;
- b_src = BOX_TABLE_ROW_GROUP;
-
- if (table_border_is_more_eyecatching(len_ctx,
- &a, a_src, &b, b_src)) {
- a = b;
- a_src = b_src;
- }
-
- /* The table itself -- consider its bottom border */
- b.style = css_computed_border_bottom_style(table->style);
- b.color = css_computed_border_bottom_color(table->style, &b.c);
- css_computed_border_bottom_width(table->style,
- &b.width, &b.unit);
- b.width = nscss_len2px(len_ctx, b.width, b.unit, table->style);
- b.unit = CSS_UNIT_PX;
- b_src = BOX_TABLE;
-
- if (table_border_is_more_eyecatching(len_ctx,
- &a, a_src, &b, b_src)) {
- a = b;
- }
- }
-
- /* a now contains the used bottom border for the cell */
- cell->border[BOTTOM].style = a.style;
- cell->border[BOTTOM].c = a.c;
- cell->border[BOTTOM].width = FIXTOINT(nscss_len2px(len_ctx,
- a.width, a.unit, cell->style));
-}
-
-/**
- * Determine if a border style is more eyecatching than another
- *
- * \param len_ctx Length conversion context
- * \param a Reference border style
- * \param a_src Source of \a a
- * \param b Candidate border style
- * \param b_src Source of \a b
- * \return True if \a b is more eyecatching than \a a
- */
-bool table_border_is_more_eyecatching(
- const nscss_len_ctx *len_ctx,
- const struct border *a,
- box_type a_src,
- const struct border *b,
- box_type b_src)
-{
- css_fixed awidth, bwidth;
- int impact = 0;
-
- /* See CSS 2.1 $17.6.2.1 */
-
- /* 1 + 2 -- hidden beats everything, none beats nothing */
- if (a->style == CSS_BORDER_STYLE_HIDDEN ||
- b->style == CSS_BORDER_STYLE_NONE)
- return false;
-
- if (b->style == CSS_BORDER_STYLE_HIDDEN ||
- a->style == CSS_BORDER_STYLE_NONE)
- return true;
-
- /* 3a -- wider borders beat narrow ones */
- /* The widths must be absolute, which will be the case
- * if they've come from a computed style. */
- assert(a->unit != CSS_UNIT_EM && a->unit != CSS_UNIT_EX);
- assert(b->unit != CSS_UNIT_EM && b->unit != CSS_UNIT_EX);
- awidth = nscss_len2px(len_ctx, a->width, a->unit, NULL);
- bwidth = nscss_len2px(len_ctx, b->width, b->unit, NULL);
-
- if (awidth < bwidth)
- return true;
- else if (bwidth < awidth)
- return false;
-
- /* 3b -- sort by style */
- switch (a->style) {
- case CSS_BORDER_STYLE_DOUBLE: impact++; /* Fall through */
- case CSS_BORDER_STYLE_SOLID: impact++; /* Fall through */
- case CSS_BORDER_STYLE_DASHED: impact++; /* Fall through */
- case CSS_BORDER_STYLE_DOTTED: impact++; /* Fall through */
- case CSS_BORDER_STYLE_RIDGE: impact++; /* Fall through */
- case CSS_BORDER_STYLE_OUTSET: impact++; /* Fall through */
- case CSS_BORDER_STYLE_GROOVE: impact++; /* Fall through */
- case CSS_BORDER_STYLE_INSET: impact++; /* Fall through */
- default:
- break;
- }
-
- switch (b->style) {
- case CSS_BORDER_STYLE_DOUBLE: impact--; /* Fall through */
- case CSS_BORDER_STYLE_SOLID: impact--; /* Fall through */
- case CSS_BORDER_STYLE_DASHED: impact--; /* Fall through */
- case CSS_BORDER_STYLE_DOTTED: impact--; /* Fall through */
- case CSS_BORDER_STYLE_RIDGE: impact--; /* Fall through */
- case CSS_BORDER_STYLE_OUTSET: impact--; /* Fall through */
- case CSS_BORDER_STYLE_GROOVE: impact--; /* Fall through */
- case CSS_BORDER_STYLE_INSET: impact--; /* Fall through */
- default:
- break;
- }
-
- if (impact < 0)
- return true;
- else if (impact > 0)
- return false;
-
- /* 4a -- sort by origin */
- impact = 0;
-
- /** \todo COL/COL_GROUP */
- switch (a_src) {
- case BOX_TABLE_CELL: impact++; /* Fall through */
- case BOX_TABLE_ROW: impact++; /* Fall through */
- case BOX_TABLE_ROW_GROUP: impact++; /* Fall through */
- case BOX_TABLE: impact++; /* Fall through */
- default:
- break;
- }
-
- /** \todo COL/COL_GROUP */
- switch (b_src) {
- case BOX_TABLE_CELL: impact--; /* Fall through */
- case BOX_TABLE_ROW: impact--; /* Fall through */
- case BOX_TABLE_ROW_GROUP: impact--; /* Fall through */
- case BOX_TABLE: impact--; /* Fall through */
- default:
- break;
- }
-
- if (impact < 0)
- return true;
- else if (impact > 0)
- return false;
-
- /* 4b -- furthest left (if direction: ltr) and towards top wins */
- /** \todo Currently assumes b satisifies this */
- return true;
-}
-
-/******************************************************************************
- * Helpers for top border collapsing *
- ******************************************************************************/
-
-/**
- * Process a table
- *
- * \param len_ctx Length conversion context
- * \param table Table to process
- * \param a Current border style for cell
- * \param a_src Source of \a a
- *
- * \post \a a will be updated with most eyecatching style
- * \post \a a_src will be updated also
- */
-void table_cell_top_process_table(
- const nscss_len_ctx *len_ctx,
- struct box *table,
- struct border *a,
- box_type *a_src)
-{
- struct border b;
- box_type b_src;
-
- /* Top border of table */
- b.style = css_computed_border_top_style(table->style);
- b.color = css_computed_border_top_color(table->style, &b.c);
- css_computed_border_top_width(table->style, &b.width, &b.unit);
- b.width = nscss_len2px(len_ctx, b.width, b.unit, table->style);
- b.unit = CSS_UNIT_PX;
- b_src = BOX_TABLE;
-
- if (table_border_is_more_eyecatching(len_ctx, a, *a_src, &b, b_src)) {
- *a = b;
- *a_src = b_src;
- }
-}
-
-/**
- * Process a group
- *
- * \param len_ctx Length conversion context
- * \param cell Cell being considered
- * \param group Group to process
- * \param a Current border style for cell
- * \param a_src Source of \a a
- * \return true if group has non-empty rows, false otherwise
- *
- * \post \a a will be updated with most eyecatching style
- * \post \a a_src will be updated also
- */
-bool table_cell_top_process_group(
- const nscss_len_ctx *len_ctx,
- struct box *cell,
- struct box *group,
- struct border *a,
- box_type *a_src)
-{
- struct border b;
- box_type b_src;
-
- /* Bottom border of group */
- b.style = css_computed_border_bottom_style(group->style);
- b.color = css_computed_border_bottom_color(group->style, &b.c);
- css_computed_border_bottom_width(group->style, &b.width, &b.unit);
- b.width = nscss_len2px(len_ctx, b.width, b.unit, group->style);
- b.unit = CSS_UNIT_PX;
- b_src = BOX_TABLE_ROW_GROUP;
-
- if (table_border_is_more_eyecatching(len_ctx, a, *a_src, &b, b_src)) {
- *a = b;
- *a_src = b_src;
- }
-
- if (group->last != NULL) {
- /* Process rows in group, starting with last */
- struct box *row = group->last;
-
- while (table_cell_top_process_row(len_ctx, cell, row,
- a, a_src) == false) {
- if (row->prev == NULL) {
- return false;
- } else {
- row = row->prev;
- }
- }
- } else {
- /* Group is empty, so consider its top border */
- b.style = css_computed_border_top_style(group->style);
- b.color = css_computed_border_top_color(group->style, &b.c);
- css_computed_border_top_width(group->style, &b.width, &b.unit);
- b.width = nscss_len2px(len_ctx, b.width, b.unit, group->style);
- b.unit = CSS_UNIT_PX;
- b_src = BOX_TABLE_ROW_GROUP;
-
- if (table_border_is_more_eyecatching(len_ctx,
- a, *a_src, &b, b_src)) {
- *a = b;
- *a_src = b_src;
- }
-
- return false;
- }
-
- return true;
-}
-
-/**
- * Process a row
- *
- * \param len_ctx Length conversion context
- * \param cell Cell being considered
- * \param row Row to process
- * \param a Current border style for cell
- * \param a_src Source of \a a
- * \return true if row has cells, false otherwise
- *
- * \post \a a will be updated with most eyecatching style
- * \post \a a_src will be updated also
- */
-bool table_cell_top_process_row(
- const nscss_len_ctx *len_ctx,
- struct box *cell,
- struct box *row,
- struct border *a,
- box_type *a_src)
-{
- struct border b;
- box_type b_src;
-
- /* Bottom border of row */
- b.style = css_computed_border_bottom_style(row->style);
- b.color = css_computed_border_bottom_color(row->style, &b.c);
- css_computed_border_bottom_width(row->style, &b.width, &b.unit);
- b.width = nscss_len2px(len_ctx, b.width, b.unit, row->style);
- b.unit = CSS_UNIT_PX;
- b_src = BOX_TABLE_ROW;
-
- if (table_border_is_more_eyecatching(len_ctx, a, *a_src, &b, b_src)) {
- *a = b;
- *a_src = b_src;
- }
-
- if (row->children == NULL) {
- /* Row is empty, so consider its top border */
- b.style = css_computed_border_top_style(row->style);
- b.color = css_computed_border_top_color(row->style, &b.c);
- css_computed_border_top_width(row->style, &b.width, &b.unit);
- b.width = nscss_len2px(len_ctx, b.width, b.unit, row->style);
- b.unit = CSS_UNIT_PX;
- b_src = BOX_TABLE_ROW;
-
- if (table_border_is_more_eyecatching(len_ctx,
- a, *a_src, &b, b_src)) {
- *a = b;
- *a_src = b_src;
- }
-
- return false;
- } else {
- /* Process cells that are directly above the cell being
- * considered. They may not be in this row, but in one of the
- * rows above it in the case where rowspan > 1. */
- struct box *c;
- bool processed = false;
-
- while (processed == false) {
- for (c = row->children; c != NULL; c = c->next) {
- /* Ignore cells to the left */
- if (c->start_column + c->columns - 1 <
- cell->start_column)
- continue;
- /* Ignore cells to the right */
- if (c->start_column > cell->start_column +
- cell->columns - 1)
- continue;
-
- /* Flag that we've processed a cell */
- processed = true;
-
- /* Consider bottom border */
- b.style = css_computed_border_bottom_style(
- c->style);
- b.color = css_computed_border_bottom_color(
- c->style, &b.c);
- css_computed_border_bottom_width(c->style,
- &b.width, &b.unit);
- b.width = nscss_len2px(len_ctx,
- b.width, b.unit, c->style);
- b.unit = CSS_UNIT_PX;
- b_src = BOX_TABLE_CELL;
-
- if (table_border_is_more_eyecatching(len_ctx,
- a, *a_src, &b, b_src)) {
- *a = b;
- *a_src = b_src;
- }
- }
-
- if (processed == false) {
- /* There must be a preceding row */
- assert(row->prev != NULL);
-
- row = row->prev;
- }
- }
- }
-
- return true;
-}
-
diff --git a/render/table.h b/render/table.h
deleted file mode 100644
index 2eeffe699..000000000
--- a/render/table.h
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * Copyright 2005 James Bursa <bursa@users.sourceforge.net>
- * Copyright 2005 Richard Wilson <info@tinct.net>
- *
- * This file is part of NetSurf, http://www.netsurf-browser.org/
- *
- * NetSurf is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * NetSurf is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-/** \file
- * Table processing and layout (interface).
- */
-
-#ifndef _NETSURF_RENDER_TABLE_H_
-#define _NETSURF_RENDER_TABLE_H_
-
-#include <stdbool.h>
-
-struct box;
-
-bool table_calculate_column_types(
- const nscss_len_ctx *len_ctx,
- struct box *table);
-void table_used_border_for_cell(
- const nscss_len_ctx *len_ctx,
- struct box *cell);
-
-#endif
diff --git a/render/textplain.c b/render/textplain.c
deleted file mode 100644
index 0036eb5c0..000000000
--- a/render/textplain.c
+++ /dev/null
@@ -1,1351 +0,0 @@
-/*
- * Copyright 2006 James Bursa <bursa@users.sourceforge.net>
- * Copyright 2006 Adrian Lees <adrianl@users.sourceforge.net>
- *
- * This file is part of NetSurf, http://www.netsurf-browser.org/
- *
- * NetSurf is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * NetSurf is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-/**
- * \file
- *
- * plain text content handling implementation.
- */
-
-#include <assert.h>
-#include <errno.h>
-#include <stddef.h>
-#include <string.h>
-#include <strings.h>
-#include <math.h>
-
-#include <parserutils/input/inputstream.h>
-#include <parserutils/charset/utf8.h>
-
-#include "utils/corestrings.h"
-#include "utils/http.h"
-#include "utils/log.h"
-#include "utils/messages.h"
-#include "utils/utils.h"
-#include "utils/utf8.h"
-#include "netsurf/content.h"
-#include "netsurf/keypress.h"
-#include "netsurf/browser_window.h"
-#include "netsurf/plotters.h"
-#include "netsurf/layout.h"
-#include "content/content_protected.h"
-#include "content/hlcache.h"
-#include "css/utils.h"
-#include "utils/nsoption.h"
-#include "desktop/search.h"
-#include "desktop/selection.h"
-#include "desktop/gui_internal.h"
-
-#include "render/search.h"
-#include "render/textplain.h"
-#include "render/html.h"
-#include "render/search.h"
-
-struct textplain_line {
- size_t start;
- size_t length;
-};
-
-typedef struct textplain_content {
- struct content base;
-
- lwc_string *encoding;
- void *inputstream;
- char *utf8_data;
- size_t utf8_data_size;
- size_t utf8_data_allocated;
- unsigned long physical_line_count;
- struct textplain_line *physical_line;
- int formatted_width;
- struct browser_window *bw;
-
- struct selection sel; /** Selection state */
-
- /** Context for free text search, or NULL if none */
- struct search_context *search;
- /** Current search string, or NULL if none */
- char *search_string;
-} textplain_content;
-
-
-#define CHUNK 32768 /* Must be a power of 2 */
-#define MARGIN 4
-
-#define TAB_WIDTH 8 /* must be power of 2 currently */
-#define TEXT_SIZE 10 * FONT_SIZE_SCALE /* Unscaled text size in pt */
-
-static plot_font_style_t textplain_style = {
- .family = PLOT_FONT_FAMILY_MONOSPACE,
- .size = TEXT_SIZE,
- .weight = 400,
- .flags = FONTF_NONE,
- .background = 0xffffff,
- .foreground = 0x000000,
-};
-
-static int textplain_tab_width = 256; /* try for a sensible default */
-
-static lwc_string *textplain_default_charset;
-
-
-/**
- * Clean up after the text content handler
- */
-static void textplain_fini(void)
-{
- if (textplain_default_charset != NULL) {
- lwc_string_unref(textplain_default_charset);
- textplain_default_charset = NULL;
- }
-}
-
-
-/**
- * Work around feature in libparserutils
- *
- * if the client provides an encoding up front, but does not provide a
- * charset detection callback, then libparserutils will replace the
- * provided encoding with UTF-8. This breaks our input handling.
- *
- * Avoid this by providing a callback that does precisely nothing,
- * thus preserving whatever charset information we decided on in
- * textplain_create.
- */
-static parserutils_error
-textplain_charset_hack(const uint8_t *data,
- size_t len,
- uint16_t *mibenum,
- uint32_t *source)
-{
- return PARSERUTILS_OK;
-}
-
-
-/**
- * setup plain text render.
- *
- * \param[in] c content object.
- * \param[in] encoding the encoding of the content.
- * \return NSERROR_OK else appropriate error code.
- */
-static nserror
-textplain_create_internal(textplain_content *c, lwc_string *encoding)
-{
- char *utf8_data;
- parserutils_inputstream *stream;
- parserutils_error error;
-
- textplain_style.size = (nsoption_int(font_size) * FONT_SIZE_SCALE) / 10;
-
- utf8_data = malloc(CHUNK);
- if (utf8_data == NULL)
- goto no_memory;
-
- error = parserutils_inputstream_create(lwc_string_data(encoding), 0,
- textplain_charset_hack, &stream);
- if (error == PARSERUTILS_BADENCODING) {
- /* Fall back to Windows-1252 */
- error = parserutils_inputstream_create("Windows-1252", 0,
- textplain_charset_hack, &stream);
- }
- if (error != PARSERUTILS_OK) {
- free(utf8_data);
- goto no_memory;
- }
-
- c->encoding = lwc_string_ref(encoding);
- c->inputstream = stream;
- c->utf8_data = utf8_data;
- c->utf8_data_size = 0;
- c->utf8_data_allocated = CHUNK;
- c->physical_line = 0;
- c->physical_line_count = 0;
- c->formatted_width = 0;
- c->bw = NULL;
-
- selection_prepare(&c->sel, (struct content *)c, false);
-
- return NSERROR_OK;
-
-no_memory:
- content_broadcast_errorcode(&c->base, NSERROR_NOMEM);
-
- return NSERROR_NOMEM;
-}
-
-
-/**
- * Create a CONTENT_TEXTPLAIN.
- */
-static nserror
-textplain_create(const content_handler *handler,
- lwc_string *imime_type,
- const http_parameter *params,
- llcache_handle *llcache,
- const char *fallback_charset,
- bool quirks,
- struct content **c)
-{
- textplain_content *text;
- nserror error;
- lwc_string *encoding;
-
- text = calloc(1, sizeof(textplain_content));
- if (text == NULL) {
- return NSERROR_NOMEM;
- }
-
- error = content__init(&text->base, handler, imime_type, params,
- llcache, fallback_charset, quirks);
- if (error != NSERROR_OK) {
- free(text);
- return error;
- }
-
- error = http_parameter_list_find_item(params, corestring_lwc_charset,
- &encoding);
- if (error != NSERROR_OK) {
- encoding = lwc_string_ref(textplain_default_charset);
- }
-
- error = textplain_create_internal(text, encoding);
- if (error != NSERROR_OK) {
- lwc_string_unref(encoding);
- free(text);
- return error;
- }
-
- lwc_string_unref(encoding);
-
- *c = (struct content *) text;
-
- return NSERROR_OK;
-}
-
-
-/**
- * copy utf8 encoded data
- */
-static bool
-textplain_copy_utf8_data(textplain_content *c, const uint8_t *buf, size_t len)
-{
- if (c->utf8_data_size + len >= c->utf8_data_allocated) {
- /* Compute next multiple of chunk above the required space */
- size_t allocated;
- char *utf8_data;
-
- allocated = (c->utf8_data_size + len + CHUNK - 1) & ~(CHUNK - 1);
- utf8_data = realloc(c->utf8_data, allocated);
- if (utf8_data == NULL)
- return false;
-
- c->utf8_data = utf8_data;
- c->utf8_data_allocated = allocated;
- }
-
- memcpy(c->utf8_data + c->utf8_data_size, buf, len);
- c->utf8_data_size += len;
-
- return true;
-}
-
-
-/**
- * drain input
- */
-static bool
-textplain_drain_input(textplain_content *c,
- parserutils_inputstream *stream,
- parserutils_error terminator)
-{
- static const uint8_t *u_fffd = (const uint8_t *) "\xef\xbf\xfd";
- const uint8_t *ch;
- size_t chlen, offset = 0;
-
- while (parserutils_inputstream_peek(stream, offset, &ch, &chlen) !=
- terminator) {
- /* Replace all instances of NUL with U+FFFD */
- if (chlen == 1 && *ch == 0) {
- if (offset > 0) {
- /* Obtain pointer to start of input data */
- parserutils_inputstream_peek(stream, 0,
- &ch, &chlen);
- /* Copy from it up to the start of the NUL */
- if (textplain_copy_utf8_data(c, ch,
- offset) == false)
- return false;
- }
-
- /* Emit U+FFFD */
- if (textplain_copy_utf8_data(c, u_fffd, 3) == false)
- return false;
-
- /* Advance inputstream past the NUL we just read */
- parserutils_inputstream_advance(stream, offset + 1);
- /* Reset the read offset */
- offset = 0;
- } else {
- /* Accumulate input */
- offset += chlen;
-
- if (offset > CHUNK) {
- /* Obtain pointer to start of input data */
- parserutils_inputstream_peek(stream, 0,
- &ch, &chlen);
-
- /* Emit the data we've read */
- if (textplain_copy_utf8_data(c, ch,
- offset) == false)
- return false;
-
- /* Advance the inputstream */
- parserutils_inputstream_advance(stream, offset);
- /* Reset the read offset */
- offset = 0;
- }
- }
- }
-
- if (offset > 0) {
- /* Obtain pointer to start of input data */
- parserutils_inputstream_peek(stream, 0, &ch, &chlen);
- /* Emit any data remaining */
- if (textplain_copy_utf8_data(c, ch, offset) == false)
- return false;
-
- /* Advance the inputstream past the data we've read */
- parserutils_inputstream_advance(stream, offset);
- }
-
- return true;
-}
-
-
-/**
- * Process data for CONTENT_TEXTPLAIN.
- */
-static bool
-textplain_process_data(struct content *c, const char *data, unsigned int size)
-{
- textplain_content *text = (textplain_content *) c;
- parserutils_inputstream *stream = text->inputstream;
- parserutils_error error;
-
- error = parserutils_inputstream_append(stream,
- (const uint8_t *) data, size);
- if (error != PARSERUTILS_OK) {
- goto no_memory;
- }
-
- if (textplain_drain_input(text, stream, PARSERUTILS_NEEDDATA) == false)
- goto no_memory;
-
- return true;
-
-no_memory:
- content_broadcast_errorcode(c, NSERROR_NOMEM);
- return false;
-}
-
-
-/**
- * Convert a CONTENT_TEXTPLAIN for display.
- */
-static bool textplain_convert(struct content *c)
-{
- textplain_content *text = (textplain_content *) c;
- parserutils_inputstream *stream = text->inputstream;
- parserutils_error error;
-
- error = parserutils_inputstream_append(stream, NULL, 0);
- if (error != PARSERUTILS_OK) {
- return false;
- }
-
- if (textplain_drain_input(text, stream, PARSERUTILS_EOF) == false)
- return false;
-
- parserutils_inputstream_destroy(stream);
- text->inputstream = NULL;
-
- content_set_ready(c);
- content_set_done(c);
- content_set_status(c, messages_get("Done"));
-
- return true;
-}
-
-
-/**
- * Calculate the line height, in pixels
- *
- * \return Line height, in pixels
- */
-static float textplain_line_height(void)
-{
- /* Size is in points, so convert to pixels.
- * Then use a constant line height of 1.2 x font size.
- */
- return FIXTOFLT(FDIV((FMUL(FLTTOFIX(1.2), FMUL(nscss_screen_dpi, INTTOFIX((textplain_style.size / FONT_SIZE_SCALE))))), F_72));
-}
-
-
-/**
- * Reformat a CONTENT_TEXTPLAIN to a new width.
- */
-static void textplain_reformat(struct content *c, int width, int height)
-{
- textplain_content *text = (textplain_content *) c;
- char *utf8_data = text->utf8_data;
- size_t utf8_data_size = text->utf8_data_size;
- unsigned long line_count = 0;
- struct textplain_line *line = text->physical_line;
- struct textplain_line *line1;
- size_t i, space, col;
- size_t columns = 80;
- int character_width;
- size_t line_start;
- nserror res;
-
- NSLOG(netsurf, INFO, "content %p w:%d h:%d", c, width, height);
-
- /* compute available columns (assuming monospaced font) - use 8
- * characters for better accuracy
- */
- res = guit->layout->width(&textplain_style,
- "ABCDEFGH", 8,
- &character_width);
- if (res != NSERROR_OK) {
- return;
- }
-
- columns = (width - MARGIN - MARGIN) * 8 / character_width;
- textplain_tab_width = (TAB_WIDTH * character_width) / 8;
-
- text->formatted_width = width;
-
- text->physical_line_count = 0;
-
- if (!line) {
- text->physical_line = line =
- malloc(sizeof(struct textplain_line) * (1024 + 3));
- if (!line)
- goto no_memory;
- }
-
- line[line_count++].start = line_start = 0;
- space = 0;
- i = 0;
- col = 0;
- while (i < utf8_data_size) {
- size_t csize; /* number of bytes in character */
- uint32_t chr;
- bool term;
- size_t next_col;
- parserutils_error perror;
-
- perror = parserutils_charset_utf8_to_ucs4((const uint8_t *)utf8_data + i, utf8_data_size - i, &chr, &csize);
- if (perror != PARSERUTILS_OK) {
- chr = 0xfffd;
- }
-
- term = (chr == '\n' || chr == '\r');
-
- next_col = col + 1;
-
- if (chr == '\t') {
- next_col = (next_col + TAB_WIDTH - 1) & ~(TAB_WIDTH - 1);
- }
-
- if (term || next_col >= columns) {
- if (line_count % 1024 == 0) {
- line1 = realloc(line,
- sizeof(struct textplain_line) *
- (line_count + 1024 + 3));
- if (!line1)
- goto no_memory;
- text->physical_line = line = line1;
- }
-
- if (term) {
- line[line_count-1].length = i - line_start;
-
- /* skip second char of CR/LF or LF/CR pair */
- if (i + 1 < utf8_data_size &&
- utf8_data[i+1] != utf8_data[i] &&
- (utf8_data[i+1] == '\n' ||
- utf8_data[i+1] == '\r')) {
- i++;
- }
- } else {
- if (space) {
- /* break at last space in line */
- i = space;
- line[line_count-1].length = (i + 1) - line_start;
- } else
- line[line_count-1].length = i - line_start;
- }
-
- line[line_count++].start = line_start = i + 1;
- col = 0;
- space = 0;
- } else {
- col++;
- if (chr == ' ')
- space = i;
- }
- i += csize;
- }
- line[line_count-1].length = i - line[line_count-1].start;
- line[line_count].start = utf8_data_size;
-
- text->physical_line_count = line_count;
- c->width = width;
- c->height = line_count * textplain_line_height() + MARGIN + MARGIN;
-
- return;
-
-no_memory:
- NSLOG(netsurf, INFO, "out of memory (line_count %lu)", line_count);
- return;
-}
-
-
-/**
- * Destroy a CONTENT_TEXTPLAIN and free all resources it owns.
- */
-
-static void textplain_destroy(struct content *c)
-{
- textplain_content *text = (textplain_content *) c;
-
- lwc_string_unref(text->encoding);
-
- if (text->inputstream != NULL) {
- parserutils_inputstream_destroy(text->inputstream);
- }
-
- if (text->physical_line != NULL) {
- free(text->physical_line);
- }
-
- if (text->utf8_data != NULL) {
- free(text->utf8_data);
- }
-}
-
-
-static nserror textplain_clone(const struct content *old, struct content **newc)
-{
- const textplain_content *old_text = (textplain_content *) old;
- textplain_content *text;
- nserror error;
- const char *data;
- unsigned long size;
-
- text = calloc(1, sizeof(textplain_content));
- if (text == NULL)
- return NSERROR_NOMEM;
-
- error = content__clone(old, &text->base);
- if (error != NSERROR_OK) {
- content_destroy(&text->base);
- return error;
- }
-
- /* Simply replay create/process/convert */
- error = textplain_create_internal(text, old_text->encoding);
- if (error != NSERROR_OK) {
- content_destroy(&text->base);
- return error;
- }
-
- data = content__get_source_data(&text->base, &size);
- if (size > 0) {
- if (textplain_process_data(&text->base, data, size) == false) {
- content_destroy(&text->base);
- return NSERROR_NOMEM;
- }
- }
-
- if (old->status == CONTENT_STATUS_READY ||
- old->status == CONTENT_STATUS_DONE) {
- if (textplain_convert(&text->base) == false) {
- content_destroy(&text->base);
- return NSERROR_CLONE_FAILED;
- }
- }
-
- return NSERROR_OK;
-}
-
-
-static content_type textplain_content_type(void)
-{
- return CONTENT_TEXTPLAIN;
-}
-
-
-/**
- * Handle mouse clicks and movements in a TEXTPLAIN content window.
- *
- * \param c content of type textplain
- * \param bw browser window
- * \param mouse mouse state on action
- * \param x coordinate of mouse
- * \param y coordinate of mouse
- */
-static void
-textplain_mouse_action(struct content *c,
- struct browser_window *bw,
- browser_mouse_state mouse,
- int x, int y)
-{
- textplain_content *text = (textplain_content *) c;
- browser_pointer_shape pointer = BROWSER_POINTER_DEFAULT;
- union content_msg_data msg_data;
- const char *status = 0;
- size_t idx;
- int dir = 0;
-
- browser_window_set_drag_type(bw, DRAGGING_NONE, NULL);
-
- idx = textplain_offset_from_coords(c, x, y, dir);
- if (selection_click(&text->sel, mouse, idx)) {
-
- if (selection_dragging(&text->sel)) {
- browser_window_set_drag_type(bw,
- DRAGGING_SELECTION, NULL);
- status = messages_get("Selecting");
- }
-
- } else {
- if (mouse & (BROWSER_MOUSE_DRAG_1 | BROWSER_MOUSE_DRAG_2)) {
- browser_window_page_drag_start(bw, x, y);
- pointer = BROWSER_POINTER_MOVE;
- }
- }
-
- msg_data.explicit_status_text = status;
- content_broadcast(c, CONTENT_MSG_STATUS, &msg_data);
-
- msg_data.pointer = pointer;
- content_broadcast(c, CONTENT_MSG_POINTER, &msg_data);
-}
-
-
-/**
- * Handle mouse tracking (including drags) in a TEXTPLAIN content window.
- *
- * \param c content of type textplain
- * \param bw browser window
- * \param mouse state of mouse buttons and modifier keys
- * \param x coordinate of mouse
- * \param y coordinate of mouse
- */
-static void
-textplain_mouse_track(struct content *c,
- struct browser_window *bw,
- browser_mouse_state mouse,
- int x, int y)
-{
- textplain_content *text = (textplain_content *) c;
-
- if (browser_window_get_drag_type(bw) == DRAGGING_SELECTION && !mouse) {
- int dir = -1;
- size_t idx;
-
- if (selection_dragging_start(&text->sel))
- dir = 1;
-
- idx = textplain_offset_from_coords(c, x, y, dir);
- selection_track(&text->sel, mouse, idx);
-
- browser_window_set_drag_type(bw, DRAGGING_NONE, NULL);
- }
-
- switch (browser_window_get_drag_type(bw)) {
-
- case DRAGGING_SELECTION: {
- int dir = -1;
- size_t idx;
-
- if (selection_dragging_start(&text->sel)) dir = 1;
-
- idx = textplain_offset_from_coords(c, x, y, dir);
- selection_track(&text->sel, mouse, idx);
- }
- break;
-
- default:
- textplain_mouse_action(c, bw, mouse, x, y);
- break;
- }
-}
-
-
-/**
- * Handle keypresses.
- *
- * \param c content of type CONTENT_TEXTPLAIN
- * \param key The UCS4 character codepoint
- * \return true if key handled, false otherwise
- */
-static bool textplain_keypress(struct content *c, uint32_t key)
-{
- textplain_content *text = (textplain_content *) c;
- struct selection *sel = &text->sel;
-
- switch (key) {
- case NS_KEY_COPY_SELECTION:
- selection_copy_to_clipboard(sel);
- return true;
-
- case NS_KEY_CLEAR_SELECTION:
- selection_clear(sel, true);
- return true;
-
- case NS_KEY_SELECT_ALL:
- selection_select_all(sel);
- return true;
-
- case NS_KEY_ESCAPE:
- if (selection_defined(sel)) {
- selection_clear(sel, true);
- return true;
- }
-
- /* if there's no selection, leave Escape for the caller */
- return false;
- }
-
- return false;
-}
-
-
-/**
- * Terminate a search.
- *
- * \param c content of type text
- */
-static void textplain_search_clear(struct content *c)
-{
- textplain_content *text = (textplain_content *) c;
-
- assert(c != NULL);
-
- free(text->search_string);
- text->search_string = NULL;
-
- if (text->search != NULL) {
- search_destroy_context(text->search);
- }
- text->search = NULL;
-}
-
-
-/**
- * Handle search.
- *
- * \param c content of type text
- * \param gui_data front end private data
- * \param flags search flags
- * \param string search string
- */
-static void textplain_search(struct content *c, void *gui_data,
- search_flags_t flags, const char *string)
-{
- textplain_content *text = (textplain_content *) c;
-
- assert(c != NULL);
-
- if (string != NULL && text->search_string != NULL &&
- strcmp(string, text->search_string) == 0 &&
- text->search != NULL) {
- /* Continue prev. search */
- search_step(text->search, flags, string);
-
- } else if (string != NULL) {
- /* New search */
- free(text->search_string);
- text->search_string = strdup(string);
- if (text->search_string == NULL)
- return;
-
- if (text->search != NULL) {
- search_destroy_context(text->search);
- text->search = NULL;
- }
-
- text->search = search_create_context(c, CONTENT_TEXTPLAIN,
- gui_data);
-
- if (text->search == NULL)
- return;
-
- search_step(text->search, flags, string);
-
- } else {
- /* Clear search */
- textplain_search_clear(c);
-
- free(text->search_string);
- text->search_string = NULL;
- }
-}
-
-
-/**
- * Draw a CONTENT_TEXTPLAIN using the current set of plotters (plot).
- *
- * x, y, clip_[xy][01] are in target coordinates.
- *
- * \param c content of type CONTENT_TEXTPLAIN
- * \param data redraw data for this content redraw
- * \param clip current clip region
- * \param ctx current redraw context
- * \return true if successful, false otherwise
- */
-static bool
-textplain_redraw(struct content *c,
- struct content_redraw_data *data,
- const struct rect *clip,
- const struct redraw_context *ctx)
-{
- textplain_content *text = (textplain_content *) c;
- struct browser_window *bw = text->bw;
- char *utf8_data = text->utf8_data;
- long lineno;
- int x = data->x;
- int y = data->y;
- unsigned long line_count = text->physical_line_count;
- float line_height = textplain_line_height();
- float scaled_line_height = line_height * data->scale;
- long line0 = (clip->y0 - y * data->scale) / scaled_line_height - 1;
- long line1 = (clip->y1 - y * data->scale) / scaled_line_height + 1;
- struct textplain_line *line = text->physical_line;
- size_t length;
- plot_style_t *plot_style_highlight;
- nserror res;
-
- if (line0 < 0)
- line0 = 0;
- if (line1 < 0)
- line1 = 0;
- if (line_count < (unsigned long) line0)
- line0 = line_count;
- if (line_count < (unsigned long) line1)
- line1 = line_count;
- if (line1 < line0)
- line1 = line0;
-
- res = ctx->plot->rectangle(ctx, plot_style_fill_white, clip);
- if (res != NSERROR_OK) {
- return false;
- }
-
- if (!line)
- return true;
-
- /* choose a suitable background colour for any highlighted text */
- if ((data->background_colour & 0x808080) == 0x808080)
- plot_style_highlight = plot_style_fill_black;
- else
- plot_style_highlight = plot_style_fill_white;
-
- /* Set up font plot style */
- textplain_style.background = data->background_colour;
-
- x = (x + MARGIN) * data->scale;
- y = (y + MARGIN) * data->scale;
- for (lineno = line0; lineno != line1; lineno++) {
- const char *text_d = utf8_data + line[lineno].start;
- int tab_width = textplain_tab_width * data->scale;
- size_t offset = 0;
- int tx = x;
-
- if (!tab_width) tab_width = 1;
-
- length = line[lineno].length;
- if (!length)
- continue;
-
- while (offset < length) {
- size_t next_offset = offset;
- int width;
- int ntx;
- nserror res;
-
- while (next_offset < length && text_d[next_offset] != '\t')
- next_offset = utf8_next(text_d, length, next_offset);
-
- if (!text_redraw(text_d + offset, next_offset - offset,
- line[lineno].start + offset, 0,
- &textplain_style,
- tx, y + (lineno * scaled_line_height),
- clip, line_height, data->scale, false,
- (struct content *)text, &text->sel,
- text->search, ctx))
- return false;
-
- if (next_offset >= length)
- break;
-
- res = guit->layout->width(&textplain_style,
- &text_d[offset],
- next_offset - offset,
- &width);
- /* locate end of string and align to next tab position */
- if (res == NSERROR_OK) {
- tx += (int)(width * data->scale);
- }
-
- ntx = x + ((1 + (tx - x) / tab_width) * tab_width);
-
- /* if the tab character lies within the
- * selection, if any, then we must draw it as
- * a filled rectangle so that it's consistent
- * with background of the selected text
- */
-
- if (bw) {
- unsigned tab_ofst = line[lineno].start + next_offset;
- struct selection *sel = &text->sel;
- bool highlighted = false;
-
- if (selection_defined(sel)) {
- unsigned start_idx, end_idx;
- if (selection_highlighted(sel,
- tab_ofst,
- tab_ofst + 1,
- &start_idx,
- &end_idx))
- highlighted = true;
- }
-
- if (!highlighted && (text->search != NULL)) {
- unsigned start_idx, end_idx;
- if (search_term_highlighted(c,
- tab_ofst,
- tab_ofst + 1,
- &start_idx,
- &end_idx,
- text->search))
- highlighted = true;
- }
-
- if (highlighted) {
- struct rect rect;
- rect.x0 = tx;
- rect.y0 = y + (lineno * scaled_line_height);
- rect.x1 = ntx;
- rect.y1 = rect.y0 + scaled_line_height;
- res = ctx->plot->rectangle(ctx,
- plot_style_highlight,
- &rect);
- if (res != NSERROR_OK) {
- return false;
- }
- }
- }
-
- offset = next_offset + 1;
- tx = ntx;
- }
- }
-
- return true;
-}
-
-
-/**
- * Handle a window containing a CONTENT_TEXTPLAIN being opened.
- */
-static void
-textplain_open(struct content *c,
- struct browser_window *bw,
- struct content *page,
- struct object_params *params)
-{
- textplain_content *text = (textplain_content *) c;
-
- text->bw = bw;
-
- /* text selection */
- selection_init(&text->sel, NULL, NULL);
-}
-
-
-/**
- * Handle a window containing a CONTENT_TEXTPLAIN being closed.
- */
-static void textplain_close(struct content *c)
-{
- textplain_content *text = (textplain_content *) c;
-
- if (text->search != NULL) {
- search_destroy_context(text->search);
- }
-
- text->bw = NULL;
-}
-
-
-/**
- * Return an textplain content's selection context
- */
-static char *textplain_get_selection(struct content *c)
-{
- textplain_content *text = (textplain_content *) c;
-
- return selection_get_copy(&text->sel);
-}
-
-
-/**
- * Convert a character offset within a line of text into the
- * horizontal co-ordinate
- *
- * The conversion takes into account the font being used and any tabs
- * in the text
- *
- * \param text line of text
- * \param offset char offset within text
- * \param length line length
- * \return x ordinate
- */
-static int
-textplain_coord_from_offset(const char *text, size_t offset, size_t length)
-{
- int x = 0;
-
- while (offset > 0) {
- size_t next_offset = 0;
- int tx;
-
- while (next_offset < offset && text[next_offset] != '\t') {
- next_offset = utf8_next(text, length, next_offset);
- }
-
- guit->layout->width(&textplain_style, text, next_offset, &tx);
-
- x += tx;
-
- if (next_offset >= offset)
- break;
-
- /* align to next tab boundary */
- next_offset++;
- x = (1 + (x / textplain_tab_width)) * textplain_tab_width;
- offset -= next_offset;
- text += next_offset;
- length -= next_offset;
- }
-
- return x;
-}
-
-
-/**
- * plain text content handler table
- */
-static const content_handler textplain_content_handler = {
- .fini = textplain_fini,
- .create = textplain_create,
- .process_data = textplain_process_data,
- .data_complete = textplain_convert,
- .reformat = textplain_reformat,
- .destroy = textplain_destroy,
- .mouse_track = textplain_mouse_track,
- .mouse_action = textplain_mouse_action,
- .keypress = textplain_keypress,
- .search = textplain_search,
- .search_clear = textplain_search_clear,
- .redraw = textplain_redraw,
- .open = textplain_open,
- .close = textplain_close,
- .get_selection = textplain_get_selection,
- .clone = textplain_clone,
- .type = textplain_content_type,
- .no_share = true,
-};
-
-
-/* exported interface documented in render/textplain.h */
-nserror textplain_init(void)
-{
- lwc_error lerror;
- nserror error;
-
- lerror = lwc_intern_string("Windows-1252",
- SLEN("Windows-1252"),
- &textplain_default_charset);
- if (lerror != lwc_error_ok) {
- return NSERROR_NOMEM;
- }
-
- error = content_factory_register_handler("text/plain",
- &textplain_content_handler);
- if (error != NSERROR_OK) {
- lwc_string_unref(textplain_default_charset);
- }
-
- return error;
-}
-
-
-/* exported interface documented in render/textplain.h */
-unsigned long textplain_line_count(struct content *c)
-{
- textplain_content *text = (textplain_content *) c;
-
- assert(c != NULL);
-
- return text->physical_line_count;
-}
-
-
-/* exported interface documented in render/textplain.h */
-size_t textplain_size(struct content *c)
-{
- textplain_content *text = (textplain_content *) c;
-
- assert(c != NULL);
-
- return text->utf8_data_size;
-}
-
-
-/* exported interface documented in render/textplain.h */
-size_t textplain_offset_from_coords(struct content *c, int x, int y, int dir)
-{
- textplain_content *textc = (textplain_content *) c;
- float line_height = textplain_line_height();
- struct textplain_line *line;
- const char *text;
- unsigned nlines;
- size_t length;
- int idx;
-
- assert(c != NULL);
-
- y = (int)((float)(y - MARGIN) / line_height);
- x -= MARGIN;
-
- nlines = textc->physical_line_count;
- if (!nlines)
- return 0;
-
- if (y <= 0) y = 0;
- else if ((unsigned)y >= nlines)
- y = nlines - 1;
-
- line = &textc->physical_line[y];
- text = textc->utf8_data + line->start;
- length = line->length;
- idx = 0;
-
- while (x > 0) {
- size_t next_offset = 0;
- int width = INT_MAX;
-
- while (next_offset < length && text[next_offset] != '\t') {
- next_offset = utf8_next(text, length, next_offset);
- }
-
- if (next_offset < length) {
- guit->layout->width(&textplain_style,
- text,
- next_offset,
- &width);
- }
-
- if (x <= width) {
- int pixel_offset;
- size_t char_offset;
-
- guit->layout->position(&textplain_style,
- text, next_offset, x,
- &char_offset, &pixel_offset);
-
- idx += char_offset;
- break;
- }
-
- x -= width;
- length -= next_offset;
- text += next_offset;
- idx += next_offset;
-
- /* check if it's within the tab */
- width = textplain_tab_width - (width % textplain_tab_width);
- if (x <= width) break;
-
- x -= width;
- length--;
- text++;
- idx++;
- }
-
- return line->start + idx;
-}
-
-
-/* exported interface documented in render/textplain.h */
-void
-textplain_coords_from_range(struct content *c,
- unsigned start,
- unsigned end,
- struct rect *r)
-{
- textplain_content *text = (textplain_content *) c;
- float line_height = textplain_line_height();
- char *utf8_data;
- struct textplain_line *line;
- unsigned lineno = 0;
- unsigned nlines;
-
- assert(c != NULL);
- assert(start <= end);
- assert(end <= text->utf8_data_size);
-
- utf8_data = text->utf8_data;
- nlines = text->physical_line_count;
- line = text->physical_line;
-
- /* find start */
- lineno = textplain_find_line(c, start);
-
- r->y0 = (int)(MARGIN + lineno * line_height);
-
- if (lineno + 1 <= nlines || line[lineno + 1].start >= end) {
- /* \todo - it may actually be more efficient just to
- * run forwards most of the time
- */
-
- /* find end */
- lineno = textplain_find_line(c, end);
-
- r->x0 = 0;
- r->x1 = text->formatted_width;
- } else {
- /* single line */
- const char *text = utf8_data + line[lineno].start;
-
- r->x0 = textplain_coord_from_offset(text,
- start - line[lineno].start,
- line[lineno].length);
-
- r->x1 = textplain_coord_from_offset(text,
- end - line[lineno].start,
- line[lineno].length);
- }
-
- r->y1 = (int)(MARGIN + (lineno + 1) * line_height);
-}
-
-
-/* exported interface documented in render/textplain.h */
-char *
-textplain_get_line(struct content *c,
- unsigned lineno,
- size_t *poffset,
- size_t *plen)
-{
- textplain_content *text = (textplain_content *) c;
- struct textplain_line *line;
-
- assert(c != NULL);
-
- if (lineno >= text->physical_line_count)
- return NULL;
- line = &text->physical_line[lineno];
-
- *poffset = line->start;
- *plen = line->length;
- return text->utf8_data + line->start;
-}
-
-
-/* exported interface documented in render/textplain.h */
-int textplain_find_line(struct content *c, unsigned offset)
-{
- textplain_content *text = (textplain_content *) c;
- struct textplain_line *line;
- int nlines;
- int lineno = 0;
-
- assert(c != NULL);
-
- line = text->physical_line;
- nlines = text->physical_line_count;
-
- if (offset > text->utf8_data_size) {
- return -1;
- }
-
-/* \todo - implement binary search here */
- while (lineno < nlines && line[lineno].start < offset) {
- lineno++;
- }
- if (line[lineno].start > offset) {
- lineno--;
- }
-
- return lineno;
-}
-
-
-/* exported interface documented in render/textplain.h */
-char *
-textplain_get_raw_data(struct content *c,
- unsigned start,
- unsigned end,
- size_t *plen)
-{
- textplain_content *text = (textplain_content *) c;
- size_t utf8_size;
-
- assert(c != NULL);
-
- utf8_size = text->utf8_data_size;
-
- /* any text at all? */
- if (!utf8_size) return NULL;
-
- /* clamp to valid offset range */
- if (start >= utf8_size) start = utf8_size;
- if (end >= utf8_size) end = utf8_size;
-
- *plen = end - start;
-
- return text->utf8_data + start;
-}
-
-
-/* exported interface documented in render/textplain.h */
-struct browser_window *textplain_get_browser_window(struct content *c)
-{
- textplain_content *text = (textplain_content *) c;
-
- assert(c != NULL);
- assert(c->handler == &textplain_content_handler);
-
- return text->bw;
-}
diff --git a/render/textplain.h b/render/textplain.h
deleted file mode 100644
index 0f0128e56..000000000
--- a/render/textplain.h
+++ /dev/null
@@ -1,139 +0,0 @@
-/*
- * Copyright 2006 James Bursa <bursa@users.sourceforge.net>
- * Copyright 2006 Adrian Lees <adrianl@users.sourceforge.net>
- *
- * This file is part of NetSurf, http://www.netsurf-browser.org/
- *
- * NetSurf is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * NetSurf is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-/**
- * \file
- *
- * Interface to content handler for plain text.
- */
-
-#ifndef NETSURF_RENDER_TEXTPLAIN_H
-#define NETSURF_RENDER_TEXTPLAIN_H
-
-#include <stddef.h>
-#include "netsurf/mouse.h"
-
-struct content;
-struct hlcache_handle;
-struct http_parameter;
-struct rect;
-
-/**
- * Initialise the text content handler
- *
- * \return NSERROR_OK on success else appropriate error code.
- */
-nserror textplain_init(void);
-
-
-/**
- * Retrieve number of lines in content
- *
- * \param[in] c Content to retrieve line count from
- * \return Number of lines
- */
-unsigned long textplain_line_count(struct content *c);
-
-
-/**
- * Retrieve the size (in bytes) of text data
- *
- * \param[in] c Content to retrieve size of
- * \return Size, in bytes, of data
- */
-size_t textplain_size(struct content *c);
-
-
-/**
- * Return byte offset within UTF8 textplain content.
- *
- * given the co-ordinates of a point within a textplain content. 'dir'
- * specifies the direction in which to search (-1 = above-left, +1 =
- * below-right) if the co-ordinates are not contained within a line.
- *
- * \param[in] c content of type CONTENT_TEXTPLAIN
- * \param[in] x x ordinate of point
- * \param[in] y y ordinate of point
- * \param[in] dir direction of search if not within line
- * \return byte offset of character containing (or nearest to) point
- */
-size_t textplain_offset_from_coords(struct content *c, int x, int y, int dir);
-
-
-/**
- * Given a range of byte offsets within a UTF8 textplain content,
- * return a box that fully encloses the text
- *
- * \param[in] c content of type CONTENT_TEXTPLAIN
- * \param[in] start byte offset of start of text range
- * \param[in] end byte offset of end
- * \param[out] r rectangle to be completed
- */
-void textplain_coords_from_range(struct content *c,
- unsigned start, unsigned end, struct rect *r);
-
-/**
- * Return a pointer to the requested line of text.
- *
- * \param[in] c content of type CONTENT_TEXTPLAIN
- * \param[in] lineno line number
- * \param[out] poffset receives byte offset of line start within text
- * \param[out] plen receives length of returned line
- * \return pointer to text, or NULL if invalid line number
- */
-char *textplain_get_line(struct content *c, unsigned lineno,
- size_t *poffset, size_t *plen);
-
-
-/**
- * Find line number of byte in text
- *
- * Given a byte offset within the text, return the line number
- * of the line containing that offset.
- *
- * \param[in] c content of type CONTENT_TEXTPLAIN
- * \param[in] offset byte offset within textual representation
- * \return line number, or -1 if offset invalid (larger than size)
- */
-int textplain_find_line(struct content *c, unsigned offset);
-
-
-/**
- * Return a pointer to the raw UTF-8 data, as opposed to the reformatted
- * text to fit the window width. Thus only hard newlines are preserved
- * in the saved/copied text of a selection.
- *
- * \param[in] c content of type CONTENT_TEXTPLAIN
- * \param[in] start starting byte offset within UTF-8 text
- * \param[in] end ending byte offset
- * \param[out] plen receives validated length
- * \return pointer to text, or NULL if no text
- */
-char *textplain_get_raw_data(struct content *c, unsigned start, unsigned end, size_t *plen);
-
-
-/**
- * Get the browser window containing a textplain content
- *
- * \param[in] c text/plain content
- * \return the browser window
- */
-struct browser_window *textplain_get_browser_window(struct content *c);
-
-#endif