From 98ccc9fe1836c59f7eff43f45ac2323798ee785a Mon Sep 17 00:00:00 2001 From: Vincent Sanders Date: Sat, 4 Feb 2017 11:45:44 +0000 Subject: Update plotter API to pass context --- include/netsurf/plotters.h | 292 ++++++++++++++++++++++++++++++++------------- 1 file changed, 208 insertions(+), 84 deletions(-) diff --git a/include/netsurf/plotters.h b/include/netsurf/plotters.h index 88cbbe560..87fbd9a74 100644 --- a/include/netsurf/plotters.h +++ b/include/netsurf/plotters.h @@ -31,6 +31,7 @@ struct bitmap; struct rect; +struct plotter_table; typedef unsigned long bitmap_flags_t; #define BITMAPF_NONE 0 @@ -44,50 +45,45 @@ enum path_command { PLOTTER_PATH_BEZIER, }; -/** Set of target specific plotting functions. - * - * The functions are: - * arc - Plots an arc, around (x,y), from anticlockwise from angle1 to - * angle2. Angles are measured anticlockwise from horizontal, in - * degrees. - * disc - Plots a circle, centered on (x,y), which is optionally filled. - * line - Plots a line from (x0,y0) to (x1,y1). Coordinates are at - * centre of line width/thickness. - * path - Plots a path consisting of cubic Bezier curves. Line colour is - * given by c and fill colour is given by fill. - * polygon - Plots a filled polygon with straight lines between points. - * The lines around the edge of the ploygon are not plotted. The - * polygon is filled with the non-zero winding rule. - * rectangle - Plots a rectangle outline. The line can be solid, dotted or - * dashed. Top left corner at (x0,y0) and rectangle has given - * width and height. - * fill - Plots a filled rectangle. Top left corner at (x0,y0), bottom - * right corner at (x1,y1). Note: (x0,y0) is inside filled area, - * but (x1,y1) is below and to the right. See diagram below. - * clip - Sets a clip rectangle for subsequent plots. - * text - Plots text. (x,y) is the coordinate of the left hand side of - * the text's baseline. The text is UTF-8 encoded. The colour, c, - * is the colour of the text. Background colour, bg, may be used - * optionally to attempt to provide anti-aliased text without - * screen reads. Font information is provided in the style. - * bitmap - Tiled plot of a bitmap image. (x,y) gives the top left - * coordinate of an explicitly placed tile. From this tile the - * image can repeat in all four directions -- up, down, left and - * right -- to the extents given by the current clip rectangle. - * The bitmap_flags say whether to tile in the x and y - * directions. If not tiling in x or y directions, the single - * image is plotted. The width and height give the dimensions - * the image is to be scaled to. - * group_start - Start of a group of objects. Used when plotter implements - * export to a vector graphics file format. (Optional.) - * group_end - End of the most recently started group. (Optional.) - * flush - Only used internally by the knockout code. Should be NULL in - * any front end display plotters or export plotters. - * - * Plotter options: - * option_knockout - Optimisation particularly for unaccelerated screen - * redraw. It tries to avoid plotting to the same area - * more than once. See desktop/knockout.c +/** + * Redraw context + */ +struct redraw_context { + /** + * Redraw to show interactive features. + * + * Active features include selections etc. + * + * \note Should be off for printing. + */ + bool interactive; + + /** + * Render background images. + * + * \note May want it off for printing. + */ + bool background_images; + + /** + * Current plot operation table + * + * \warning must be assigned before use. + */ + const struct plotter_table *plot; + + /** + * Private context. + * + * Private context allows callers to pass context through to + * plot operations without using a global. + */ + void *priv; +}; + + +/** + * Plotter operations table. * * Coordinates are from top left of canvas and (0,0) is the top left grid * denomination. If a "fill" is drawn from (0,0) to (4,3), the result is: @@ -101,61 +97,189 @@ enum path_command { * 2 |#|#|#|#| | * +-+-+-+-+-+- * 3 | | | | | | + * */ struct plotter_table { - /* clipping operations */ - bool (*clip)(const struct rect *clip); + /** + * \brief Sets a clip rectangle for subsequent plot operations. + * + * \param ctx The current redraw context. + * \param clip The rectangle to limit all subsequent plot + * operations within. + * \return NSERROR_OK on success else error code. + */ + nserror (*clip)(const struct redraw_context *ctx, const struct rect *clip); + + /** + * Plots an arc + * + * plot an arc segment around (x,y), anticlockwise from angle1 + * to angle2. Angles are measured anticlockwise from + * horizontal, in degrees. + * + * \param ctx The current redraw context. + * \param pstyle Style controlling the arc plot. + * \param x The x coordinate of the arc. + * \param y The y coordinate of the arc. + * \param radius The radius of the arc. + * \param angle1 The start angle of the arc. + * \param angle2 The finish angle of the arc. + * \return NSERROR_OK on success else error code. + */ + nserror (*arc)(const struct redraw_context *ctx, const plot_style_t *pstyle, int x, int y, int radius, int angle1, int angle2); + + /** + * Plots a circle + * + * Plot a circle centered on (x,y), which is optionally filled. + * + * \param ctx The current redraw context. + * \param pstyle Style controlling the circle plot. + * \param x The x coordinate of the circle. + * \param y The y coordinate of the circle. + * \param radius The radius of the circle. + * \return NSERROR_OK on success else error code. + */ + nserror (*disc)(const struct redraw_context *ctx, const plot_style_t *pstyle, int x, int y, int radius); - /* shape primatives */ - bool (*arc)(int x, int y, int radius, int angle1, int angle2, const plot_style_t *pstyle); - bool (*disc)(int x, int y, int radius, const plot_style_t *pstyle); - bool (*line)(int x0, int y0, int x1, int y1, const plot_style_t *pstyle); - bool (*rectangle)(int x0, int y0, int x1, int y1, const plot_style_t *pstyle); - bool (*polygon)(const int *p, unsigned int n, const plot_style_t *pstyle); + /** + * Plots a line + * + * plot a line from (x0,y0) to (x1,y1). Coordinates are at + * centre of line width/thickness. + * + * \param ctx The current redraw context. + * \param pstyle Style controlling the line plot. + * \param line A rectangle defining the line to be drawn + * \return NSERROR_OK on success else error code. + */ + nserror (*line)(const struct redraw_context *ctx, const plot_style_t *pstyle, const struct rect *line); - /* complex path (for SVG) */ - bool (*path)(const float *p, unsigned int n, colour fill, float width, - colour c, const float transform[6]); + /** + * Plots a rectangle. + * + * The rectangle can be filled an outline or both controlled + * by the plot style The line can be solid, dotted or + * dashed. Top left corner at (x0,y0) and rectangle has given + * width and height. + * + * \param ctx The current redraw context. + * \param pstyle Style controlling the rectangle plot. + * \param rect A rectangle defining the line to be drawn + * \return NSERROR_OK on success else error code. + */ + nserror (*rectangle)(const struct redraw_context *ctx, const plot_style_t *pstyle, const struct rect *rectangle); - /* Image */ - bool (*bitmap)(int x, int y, int width, int height, - struct bitmap *bitmap, colour bg, - bitmap_flags_t flags); + /** + * Plot a polygon + * + * Plots a filled polygon with straight lines between + * points. The lines around the edge of the ploygon are not + * plotted. The polygon is filled with the non-zero winding + * rule. + * + * \param ctx The current redraw context. + * \param pstyle Style controlling the polygon plot. + * \param p verticies of polygon + * \param n number of verticies. + * \return NSERROR_OK on success else error code. + */ + nserror (*polygon)(const struct redraw_context *ctx, const plot_style_t *pstyle, const int *p, unsigned int n); /** - * Text. + * Plots a path. + * + * Path plot consisting of cubic Bezier curves. Line and fill colour is + * controlled by the plot style. * - * \param x x coordinate - * \param y y coordinate - * \param text UTF-8 string to plot - * \param length length of string, in bytes - * \param fstyle plot style for this text - * \return true on success, false on error and error reported + * \param ctx The current redraw context. + * \param pstyle Style controlling the path plot. + * \param p elements of path + * \param n nunber of elements on path + * \param width The width of the path + * \param transform A transform to apply to the path. + * \return NSERROR_OK on success else error code. */ - bool (*text)(int x, int y, const char *text, size_t length, - const plot_font_style_t *fstyle); + nserror (*path)(const struct redraw_context *ctx, const plot_style_t *pstyle, const float *p, unsigned int n, float width, const float transform[6]); - /* optional callbacks */ - bool (*group_start)(const char *name); /**< optional, may be NULL */ - bool (*group_end)(void); /**< optional, may be NULL */ - bool (*flush)(void); /**< optional, may be NULL */ + /** + * Plot a bitmap + * + * Tiled plot of a bitmap image. (x,y) gives the top left + * coordinate of an explicitly placed tile. From this tile the + * image can repeat in all four directions -- up, down, left + * and right -- to the extents given by the current clip + * rectangle. + * + * The bitmap_flags say whether to tile in the x and y + * directions. If not tiling in x or y directions, the single + * image is plotted. The width and height give the dimensions + * the image is to be scaled to. + * + * \param ctx The current redraw context. + * \param bitmap The bitmap to plot + * \param x The x coordinate to plot the bitmap + * \param y The y coordiante to plot the bitmap + * \param width The width of area to plot the bitmap into + * \param height The height of area to plot the bitmap into + * \param bg the background colour to alpha blend into + * \param flags the flags controlling the type of plot operation + * \return NSERROR_OK on success else error code. + */ + nserror (*bitmap)(const struct redraw_context *ctx, struct bitmap *bitmap, int x, int y, int width, int height, colour bg, bitmap_flags_t flags); - /* flags */ - bool option_knockout; /**< set if knockout rendering is required */ -}; + /** + * Text plotting. + * + * \param ctx The current redraw context. + * \param fstyle plot style for this text + * \param x x coordinate + * \param y y coordinate + * \param text UTF-8 string to plot + * \param length length of string, in bytes + * \return NSERROR_OK on success else error code. + */ + nserror (*text)(const struct redraw_context *ctx, const plot_font_style_t *fstyle, int x, int y, const char *text, size_t length); + /** + * Start of a group of objects. + * + * optional, may be NULL. Used when plotter implements export + * to a vector graphics file format. + * + * \param ctx The current redraw context. + * \return NSERROR_OK on success else error code. + */ + nserror (*group_start)(const struct redraw_context *ctx, const char *name); -/* Redraw context */ -struct redraw_context { - /** Redraw to show interactive features, such as active selections - * etc. Should be off for printing. */ - bool interactive; + /** + * End of the most recently started group. + * + * optional, may be NULL + * + * \param ctx The current redraw context. + * \return NSERROR_OK on success else error code. + */ + nserror (*group_end)(const struct redraw_context *ctx); - /** Render background images. May want it off for printing. */ - bool background_images; + /** + * Only used internally by the knockout code. Must be NULL in + * any front end display plotters or export plotters. + * + * \param ctx The current redraw context. + * \return NSERROR_OK on success else error code. + */ + nserror (*flush)(const struct redraw_context *ctx); - /** Current plotters, must be assigned before use. */ - const struct plotter_table *plot; + /* flags */ + /** + * flag to enable knockout rendering. + * + * Optimisation particularly for unaccelerated screen + * redraw. It tries to avoid plotting to the same area more + * than once. See desktop/knockout.c + */ + bool option_knockout; }; #endif -- cgit v1.2.3 From 3722ff8d867db506c68e5467bbcdb6012e384fc8 Mon Sep 17 00:00:00 2001 From: Vincent Sanders Date: Sat, 11 Feb 2017 13:54:08 +0000 Subject: Update all core use of plotters to new API --- content/content.c | 8 +- content/handlers/image/bmp.c | 8 +- content/handlers/image/image.c | 14 +- content/handlers/image/nssprite.c | 27 +- content/handlers/image/rsvg.c | 13 +- content/handlers/image/svg.c | 51 ++- desktop/browser.c | 33 +- desktop/browser_history.c | 85 ++-- desktop/scrollbar.c | 399 +++++++++++------- desktop/textarea.c | 73 ++-- desktop/treeview.c | 95 +++-- render/form.c | 62 ++- render/html_redraw.c | 825 ++++++++++++++++++++++---------------- render/textplain.c | 21 +- 14 files changed, 1027 insertions(+), 687 deletions(-) diff --git a/content/content.c b/content/content.c index 2eb035cdf..2719db851 100644 --- a/content/content.c +++ b/content/content.c @@ -600,12 +600,12 @@ bool content_scaled_redraw(struct hlcache_handle *h, clip.x1 = width; clip.y1 = height; - new_ctx.plot->clip(&clip); + new_ctx.plot->clip(&new_ctx, &clip); /* Plot white background */ - plot_ok &= new_ctx.plot->rectangle(clip.x0, clip.y0, clip.x1, clip.y1, - plot_style_fill_white); - + plot_ok &= (new_ctx.plot->rectangle(&new_ctx, + plot_style_fill_white, + &clip) == NSERROR_OK); /* Set up content redraw data */ data.x = 0; diff --git a/content/handlers/image/bmp.c b/content/handlers/image/bmp.c index 5970f8b16..271787449 100644 --- a/content/handlers/image/bmp.c +++ b/content/handlers/image/bmp.c @@ -199,8 +199,12 @@ static bool nsbmp_redraw(struct content *c, struct content_redraw_data *data, if (data->repeat_y) flags |= BITMAPF_REPEAT_Y; - return ctx->plot->bitmap(data->x, data->y, data->width, data->height, - bmp->bitmap, data->background_colour, flags); + return (ctx->plot->bitmap(ctx, + bmp->bitmap, + data->x, data->y, + data->width, data->height, + data->background_colour, + flags) == NSERROR_OK); } diff --git a/content/handlers/image/image.c b/content/handlers/image/image.c index e7cc9218f..675fdd691 100644 --- a/content/handlers/image/image.c +++ b/content/handlers/image/image.c @@ -137,9 +137,9 @@ bool image_bitmap_plot(struct bitmap *bitmap, fill_style.stroke_type = PLOT_OP_TYPE_NONE; fill_style.fill_type = PLOT_OP_TYPE_SOLID; - return ctx->plot->rectangle(area.x0, area.y0, - area.x1, area.y1, - &fill_style); + return (ctx->plot->rectangle(ctx, + &fill_style, + &area) == NSERROR_OK); } else if ((fill_style.fill_colour & 0xff000000) == 0) { /* transparent pixel used as spacer, skip it */ @@ -154,6 +154,10 @@ bool image_bitmap_plot(struct bitmap *bitmap, if (data->repeat_y) flags |= BITMAPF_REPEAT_Y; - return ctx->plot->bitmap(data->x, data->y, data->width, data->height, - bitmap, data->background_colour, flags); + return (ctx->plot->bitmap(ctx, + bitmap, + data->x, data->y, + data->width, data->height, + data->background_colour, + flags) == NSERROR_OK); } diff --git a/content/handlers/image/nssprite.c b/content/handlers/image/nssprite.c index c902fc3e2..247574aa4 100644 --- a/content/handlers/image/nssprite.c +++ b/content/handlers/image/nssprite.c @@ -16,9 +16,9 @@ * along with this program. If not, see . */ -/** \file - * Content for image/x-riscos-sprite (librosprite implementation). - * +/** + * \file + * librosprite implementation for content image/x-riscos-sprite */ #include @@ -185,19 +185,28 @@ static void nssprite_destroy(struct content *c) * Redraw a CONTENT_SPRITE. */ -static bool nssprite_redraw(struct content *c, struct content_redraw_data *data, - const struct rect *clip, const struct redraw_context *ctx) +static bool +nssprite_redraw(struct content *c, + struct content_redraw_data *data, + const struct rect *clip, + const struct redraw_context *ctx) { nssprite_content *nssprite = (nssprite_content *) c; bitmap_flags_t flags = BITMAPF_NONE; - if (data->repeat_x) + if (data->repeat_x) { flags |= BITMAPF_REPEAT_X; - if (data->repeat_y) + } + if (data->repeat_y) { flags |= BITMAPF_REPEAT_Y; + } - return ctx->plot->bitmap(data->x, data->y, data->width, data->height, - nssprite->bitmap, data->background_colour, flags); + return (ctx->plot->bitmap(ctx, + nssprite->bitmap, + data->x, data->y, + data->width, data->height, + data->background_colour, + flags) == NSERROR_OK); } diff --git a/content/handlers/image/rsvg.c b/content/handlers/image/rsvg.c index 1bf4b4403..0665f217f 100644 --- a/content/handlers/image/rsvg.c +++ b/content/handlers/image/rsvg.c @@ -16,8 +16,9 @@ * along with this program. If not, see . */ -/** \file - * Content handler for image/svg using librsvg (implementation). +/** + * \file + * implementation of content handler for image/svg using librsvg. * * SVG files are rendered to a NetSurf bitmap by creating a Cairo rendering * surface (content_rsvg_data.cs) over the bitmap's data, creating a Cairo @@ -234,8 +235,12 @@ static bool rsvg_redraw(struct content *c, struct content_redraw_data *data, if (data->repeat_y) flags |= BITMAPF_REPEAT_Y; - return ctx->plot->bitmap(data->x, data->y, data->width, data->height, - rsvgcontent->bitmap, data->background_colour, flags); + return (ctx->plot->bitmap(ctx, + rsvgcontent->bitmap, + data->x, data->y, + data->width, data->height, + data->background_colour, + flags) == NSERROR_OK); } static void rsvg_destroy(struct content *c) diff --git a/content/handlers/image/svg.c b/content/handlers/image/svg.c index 94c485822..b34c6b7bb 100644 --- a/content/handlers/image/svg.c +++ b/content/handlers/image/svg.c @@ -16,8 +16,9 @@ * along with this program. If not, see . */ -/** \file - * Content for image/svg (implementation). +/** + * \file + * implementation of content for image/svg using libsvgtiny. */ #include @@ -154,18 +155,25 @@ static void svg_reformat(struct content *c, int width, int height) * Redraw a CONTENT_SVG. */ -static bool svg_redraw_internal(struct content *c, int x, int y, - int width, int height, const struct rect *clip, - const struct redraw_context *ctx, float scale, - colour background_colour) +static bool +svg_redraw_internal(struct content *c, + int x, + int y, + int width, + int height, + const struct rect *clip, + const struct redraw_context *ctx, + float scale, + colour background_colour) { svg_content *svg = (svg_content *) c; float transform[6]; struct svgtiny_diagram *diagram = svg->diagram; - bool ok; int px, py; unsigned int i; plot_font_style_t fstyle = *plot_style_font; + plot_style_t pstyle; + nserror res; assert(diagram); @@ -183,14 +191,17 @@ static bool svg_redraw_internal(struct content *c, int x, int y, for (i = 0; i != diagram->shape_count; i++) { if (diagram->shape[i].path) { - ok = ctx->plot->path(diagram->shape[i].path, - diagram->shape[i].path_length, - BGR(diagram->shape[i].fill), - diagram->shape[i].stroke_width, - BGR(diagram->shape[i].stroke), - transform); - if (!ok) + pstyle.stroke_colour = BGR(diagram->shape[i].stroke); + pstyle.fill_colour = BGR(diagram->shape[i].fill); + res = ctx->plot->path(ctx, + &pstyle, + diagram->shape[i].path, + diagram->shape[i].path_length, + diagram->shape[i].stroke_width, + transform); + if (res != NSERROR_OK) { return false; + } } else if (diagram->shape[i].text) { px = transform[0] * diagram->shape[i].text_x + @@ -204,12 +215,14 @@ static bool svg_redraw_internal(struct content *c, int x, int y, fstyle.foreground = 0x000000; fstyle.size = (8 * FONT_SIZE_SCALE) * scale; - ok = ctx->plot->text(px, py, - diagram->shape[i].text, - strlen(diagram->shape[i].text), - &fstyle); - if (!ok) + res = ctx->plot->text(ctx, + &fstyle, + px, py, + diagram->shape[i].text, + strlen(diagram->shape[i].text)); + if (res != NSERROR_OK) { return false; + } } } diff --git a/desktop/browser.c b/desktop/browser.c index d3648d76a..442208c1b 100644 --- a/desktop/browser.c +++ b/desktop/browser.c @@ -170,23 +170,21 @@ bool browser_window_redraw(struct browser_window *bw, int x, int y, return false; } - if (bw->current_content == NULL && bw->children == NULL) { + if ((bw->current_content == NULL) && + (bw->children == NULL)) { /* Browser window has no content, render blank fill */ - ctx->plot->clip(clip); - return ctx->plot->rectangle(clip->x0, clip->y0, - clip->x1, clip->y1, - plot_style_fill_white); + ctx->plot->clip(ctx, clip); + return (ctx->plot->rectangle(ctx, plot_style_fill_white, clip) == NSERROR_OK); } /* Browser window has content OR children (frames) */ - if ((bw->window != NULL) && (ctx->plot->option_knockout)) { /* Root browser window: start knockout */ knockout_plot_start(ctx, &new_ctx); } - new_ctx.plot->clip(clip); + new_ctx.plot->clip(ctx, clip); /* Handle redraw of any browser window children */ if (bw->children) { @@ -194,11 +192,12 @@ bool browser_window_redraw(struct browser_window *bw, int x, int y, int cur_child; int children = bw->rows * bw->cols; - if (bw->window != NULL) + if (bw->window != NULL) { /* Root browser window; start with blank fill */ - plot_ok &= new_ctx.plot->rectangle(clip->x0, clip->y0, - clip->x1, clip->y1, - plot_style_fill_white); + plot_ok &= (new_ctx.plot->rectangle(ctx, + plot_style_fill_white, + clip) == NSERROR_OK); + } /* Loop through all children of bw */ for (cur_child = 0; cur_child < children; cur_child++) { @@ -225,7 +224,7 @@ bool browser_window_redraw(struct browser_window *bw, int x, int y, /* Skip this frame if it lies outside clip rectangle */ if (content_clip.x0 >= content_clip.x1 || - content_clip.y0 >= content_clip.y1) + content_clip.y0 >= content_clip.y1) continue; /* Redraw frame */ @@ -235,7 +234,8 @@ bool browser_window_redraw(struct browser_window *bw, int x, int y, } /* Nothing else to redraw for browser windows with children; - * cleanup and return */ + * cleanup and return + */ if (bw->window != NULL && ctx->plot->option_knockout) { /* Root browser window: knockout end */ knockout_plot_end(); @@ -254,8 +254,9 @@ bool browser_window_redraw(struct browser_window *bw, int x, int y, /* Non-HTML may not fill viewport to extents, so plot white * background fill */ - plot_ok &= new_ctx.plot->rectangle(clip->x0, clip->y0, - clip->x1, clip->y1, plot_style_fill_white); + plot_ok &= (new_ctx.plot->rectangle(&new_ctx, + plot_style_fill_white, + clip) == NSERROR_OK); } /* Set up content redraw data */ @@ -290,7 +291,7 @@ bool browser_window_redraw(struct browser_window *bw, int x, int y, &content_clip, &new_ctx); /* Back to full clip rect */ - new_ctx.plot->clip(clip); + new_ctx.plot->clip(&new_ctx, clip); if (!bw->window) { /* Render scrollbars */ diff --git a/desktop/browser_history.c b/desktop/browser_history.c index d21c5bc25..10154b780 100644 --- a/desktop/browser_history.c +++ b/desktop/browser_history.c @@ -287,7 +287,7 @@ static plot_font_style_t pfstyle_node_sel = { * \param x window x offset * \param y window y offset * \param clip clip redraw - * \param ctx current redraw context + * \param ctx current redraw context */ static bool browser_window_history__redraw_entry(struct history *history, @@ -296,7 +296,6 @@ browser_window_history__redraw_entry(struct history *history, int x, int y, bool clip, const struct redraw_context *ctx) { - const struct plotter_table *plot = ctx->plot; size_t char_offset; int actual_x; struct history_entry *child; @@ -306,7 +305,7 @@ browser_window_history__redraw_entry(struct history *history, plot_style_t *pstyle; plot_font_style_t *pfstyle; - + struct rect rect; nserror res; /* setup plot styles */ @@ -320,31 +319,36 @@ browser_window_history__redraw_entry(struct history *history, /* setup clip area */ if (clip) { - struct rect rect; rect.x0 = x0 + xoffset; rect.y0 = y0 + yoffset; rect.x1 = x1 + xoffset; rect.y1 = y1 + yoffset; - if (!plot->clip(&rect)) { + res = ctx->plot->clip(ctx, &rect); + if (res != NSERROR_OK) { return false; } } /* Only attempt to plot bitmap if it is present */ if (entry->bitmap != NULL) { - plot->bitmap(entry->x + xoffset, - entry->y + yoffset, - WIDTH, HEIGHT, - entry->bitmap, - 0xffffff, - 0); + res = ctx->plot->bitmap(ctx, + entry->bitmap, + entry->x + xoffset, + entry->y + yoffset, + WIDTH, HEIGHT, + 0xffffff, + 0); + if (res != NSERROR_OK) { + return false; + } } - if (!plot->rectangle(entry->x - 1 + xoffset, - entry->y - 1 + yoffset, - entry->x + xoffset + WIDTH, - entry->y + yoffset + HEIGHT, - pstyle)) { + rect.x0 = entry->x - 1 + xoffset; + rect.y0 = entry->y - 1 + yoffset; + rect.x1 = entry->x + xoffset + WIDTH; + rect.y1 = entry->y + yoffset + HEIGHT; + res = ctx->plot->rectangle(ctx, pstyle, &rect); + if (res != NSERROR_OK) { return false; } @@ -355,38 +359,45 @@ browser_window_history__redraw_entry(struct history *history, return false; } - - if (!plot->text(entry->x + xoffset, - entry->y + HEIGHT + 12 + yoffset, - entry->page.title, - char_offset, - pfstyle)) { + res = ctx->plot->text(ctx, + pfstyle, + entry->x + xoffset, + entry->y + HEIGHT + 12 + yoffset, + entry->page.title, + char_offset); + if (res != NSERROR_OK) { return false; } /* for each child node draw a line and recurse redraw into it */ for (child = entry->forward; child; child = child->next) { - if (!plot->line(entry->x + WIDTH + xoffset, - entry->y + HEIGHT / 2 + yoffset, - entry->x + WIDTH + tailsize + xoffset, - entry->y + HEIGHT / 2 + yoffset, - &pstyle_line)) { + rect.x0 = entry->x + WIDTH + xoffset; + rect.y0 = entry->y + HEIGHT / 2 + yoffset; + rect.x1 = entry->x + WIDTH + tailsize + xoffset; + rect.y1 = entry->y + HEIGHT / 2 + yoffset; + res = ctx->plot->line(ctx, &pstyle_line, &rect); + if (res != NSERROR_OK) { return false; } - if (!plot->line(entry->x + WIDTH + tailsize + xoffset, - entry->y + HEIGHT / 2 + yoffset, - child->x - tailsize +xoffset, - child->y + HEIGHT / 2 + yoffset, - &pstyle_line)) { + + rect.x0 = entry->x + WIDTH + tailsize + xoffset; + rect.y0 = entry->y + HEIGHT / 2 + yoffset; + rect.x1 = child->x - tailsize + xoffset; + rect.y1 = child->y + HEIGHT / 2 + yoffset; + res = ctx->plot->line(ctx, &pstyle_line, &rect); + if (res != NSERROR_OK) { return false; } - if (!plot->line(child->x - tailsize + xoffset, - child->y + HEIGHT / 2 + yoffset, - child->x + xoffset, child->y + - HEIGHT / 2 + yoffset, - &pstyle_line)) { + + rect.x0 = child->x - tailsize + xoffset; + rect.y0 = child->y + HEIGHT / 2 + yoffset; + rect.x1 = child->x + xoffset; + rect.y1 = child->y + HEIGHT / 2 + yoffset; + res = ctx->plot->line(ctx, &pstyle_line, &rect); + if (res != NSERROR_OK) { return false; } + if (!browser_window_history__redraw_entry(history, child, x0, y0, x1, y1, x, y, clip, ctx)) { return false; diff --git a/desktop/scrollbar.c b/desktop/scrollbar.c index 9a4d70fe4..3709af8b4 100644 --- a/desktop/scrollbar.c +++ b/desktop/scrollbar.c @@ -18,8 +18,9 @@ * along with this program. If not, see . */ -/** \file - * Scrollbar widget (implementation). +/** + * \file + * implementation of scrollbar widget. */ #include @@ -36,10 +37,14 @@ #include "desktop/system_colour.h" #include "desktop/scrollbar.h" +/** + * Scrollbar context + */ struct scrollbar { - bool horizontal; /* Horizontal scrollbar if true, else vertical - */ - int length; /* Length of the scrollbar widget */ + /** Horizontal scrollbar if true, else vertical */ + bool horizontal; + /** Length of the scrollbar widget */ + int length; int full_size; /* Length of the full scrollable area */ int visible_size; /* Length visible part of the scrollable area */ @@ -121,24 +126,27 @@ void scrollbar_destroy(struct scrollbar *s) /** - * Draw an outline rectangle common to a several scrollbar elements. + * Draw an outline rectangle common to several scrollbar elements. * * \param x0 left border of the outline * \param y0 top border of the outline * \param x1 right border of the outline * \param y1 bottom border of the outline * \param c base colour of the outline, the other colours are created by - * lightening or darkening this one + * lightening or darkening this one * \param ctx current redraw context * \param inset true for inset outline, false for an outset one * \return */ -static inline bool scrollbar_redraw_scrollbar_rectangle(int x0, int y0, - int x1, int y1, colour c, bool inset, - const struct redraw_context *ctx) +static inline nserror +scrollbar_rectangle(const struct redraw_context *ctx, + struct rect *area, + colour c, + bool inset) { - const struct plotter_table *plot = ctx->plot; + struct rect line; + nserror res; static plot_style_t c0 = { .stroke_type = PLOT_OP_TYPE_SOLID, @@ -165,29 +173,63 @@ static inline bool scrollbar_redraw_scrollbar_rectangle(int x0, int y0, c2.stroke_colour = blend_colour(c0.stroke_colour, c1.stroke_colour); /* Plot the outline */ - if (!plot->line(x0, y0, x1, y0, &c0)) return false; - if (!plot->line(x1, y0, x1, y1 + 1, &c1)) return false; - if (!plot->line(x1, y0, x1, y0 + 1, &c2)) return false; - if (!plot->line(x1, y1, x0, y1, &c1)) return false; - if (!plot->line(x0, y1, x0, y0, &c0)) return false; - if (!plot->line(x0, y1, x0, y1 + 1, &c2)) return false; - return true; + line.x0 = area->x0; line.y0 = area->y0; + line.x1 = area->x1; line.y1 = area->y0; + res = ctx->plot->line(ctx, &c0, &line); + if (res != NSERROR_OK) { + return res; + } + + line.x0 = area->x1; line.y0 = area->y0; + line.x1 = area->x1; line.y1 = area->y1 + 1; + res = ctx->plot->line(ctx, &c1, &line); + if (res != NSERROR_OK) { + return res; + } + + line.x0 = area->x1; line.y0 = area->y0; + line.x1 = area->x1; line.y1 = area->y0 + 1; + res = ctx->plot->line(ctx, &c2, &line); + if (res != NSERROR_OK) { + return res; + } + + line.x0 = area->x1; line.y0 = area->y1; + line.x1 = area->x0; line.y1 = area->y1; + res = ctx->plot->line(ctx, &c1, &line); + if (res != NSERROR_OK) { + return res; + } + + line.x0 = area->x0; line.y0 = area->y1; + line.x1 = area->x0; line.y1 = area->y0; + res = ctx->plot->line(ctx, &c0, &line); + if (res != NSERROR_OK) { + return res; + } + + line.x0 = area->x0; line.y0 = area->y1; + line.x1 = area->x0; line.y1 = area->y1 + 1; + res = ctx->plot->line(ctx, &c2, &line); + + return res; } /* * Exported function. Documented in scrollbar.h */ -bool scrollbar_redraw(struct scrollbar *s, int x, int y, +bool scrollbar_redraw(struct scrollbar *s, int x, int y, const struct rect *clip, float scale, const struct redraw_context *ctx) { - const struct plotter_table *plot = ctx->plot; int w = SCROLLBAR_WIDTH; int bar_pos, bar_c0, bar_c1; int v[6]; /* array of triangle vertices */ - int x0, y0, x1, y1; + struct rect area; + struct rect rect; + nserror res; colour bg_fill_colour = ns_system_colour_char("Scrollbar"); colour fg_fill_colour = ns_system_colour_char("ButtonFace"); @@ -206,176 +248,236 @@ bool scrollbar_redraw(struct scrollbar *s, int x, int y, .fill_colour = arrow_fill_colour }; - x0 = x; - y0 = y; - x1 = x + (s->horizontal ? s->length : SCROLLBAR_WIDTH) - 1; - y1 = y + (s->horizontal ? SCROLLBAR_WIDTH : s->length) - 1; + area.x0 = x; + area.y0 = y; + area.x1 = x + (s->horizontal ? s->length : SCROLLBAR_WIDTH) - 1; + area.y1 = y + (s->horizontal ? SCROLLBAR_WIDTH : s->length) - 1; bar_pos = s->bar_pos; - bar_c1 = (s->horizontal ? x0 : y0) + SCROLLBAR_WIDTH + + bar_c1 = (s->horizontal ? area.x0 : area.y0) + SCROLLBAR_WIDTH + s->bar_pos + s->bar_len - 1; if (scale != 1.0) { w *= scale; - x0 *= scale; - y0 *= scale; - x1 *= scale; - y1 *= scale; + area.x0 *= scale; + area.y0 *= scale; + area.x1 *= scale; + area.y1 *= scale; bar_pos *= scale; bar_c1 *= scale; } - bar_c0 = (s->horizontal ? x0 : y0) + w + bar_pos; + bar_c0 = (s->horizontal ? area.x0 : area.y0) + w + bar_pos; - if (x1 < clip->x0 || y1 < clip->y0 || clip->x1 < x0 || clip->y1 < y0) - /* scrollbar is outside the clipping rectangle, nothing to - * render */ + /* if scrollbar is outside the clipping rectangle, nothing to render */ + if ((area.x1 < clip->x0) || + (area.y1 < clip->y0) || + (clip->x1 < area.x0) || + (clip->y1 < area.y0)) { return true; + } - if (s->horizontal) { /* scrollbar is horizontal */ - + /* scrollbar outline */ - if (!scrollbar_redraw_scrollbar_rectangle(x0, y0, x1, y1, - bg_fill_colour, true, ctx)) + res = scrollbar_rectangle(ctx, &area, bg_fill_colour, true); + if (res != NSERROR_OK) { return false; + } + /* left arrow icon border */ - if (!scrollbar_redraw_scrollbar_rectangle(x0 + 1, - y0 + 1, - x0 + w - 2, - y1 - 1, - fg_fill_colour, false, ctx)) + rect.x0 = area.x0 + 1; + rect.y0 = area.y0 + 1; + rect.x1 = area.x0 + w - 2; + rect.y1 = area.y1 - 1; + res = scrollbar_rectangle(ctx, &rect, fg_fill_colour, false); + if (res != NSERROR_OK) { return false; + } + /* left arrow icon background */ - if (!plot->rectangle(x0 + 2, - y0 + 2, - x0 + w - 2, - y1 - 1, - &fg_fill_style)) + rect.x0 = area.x0 + 2; + rect.y0 = area.y0 + 2; + rect.x1 = area.x0 + w - 2; + rect.y1 = area.y1 - 1; + res = ctx->plot->rectangle(ctx, &fg_fill_style, &rect); + if (res != NSERROR_OK) { return false; + } + /* left arrow */ - v[0] = x0 + w / 4; - v[1] = y0 + w / 2; - v[2] = x0 + w * 3 / 4; - v[3] = y0 + w / 4; - v[4] = x0 + w * 3 / 4; - v[5] = y0 + w * 3 / 4; - if (!plot->polygon(v, 3, &arrow_fill_style)) + v[0] = area.x0 + w / 4; + v[1] = area.y0 + w / 2; + v[2] = area.x0 + w * 3 / 4; + v[3] = area.y0 + w / 4; + v[4] = area.x0 + w * 3 / 4; + v[5] = area.y0 + w * 3 / 4; + res = ctx->plot->polygon(ctx, &arrow_fill_style, v, 3); + if (res != NSERROR_OK) { return false; + } + /* scrollbar well background */ - if (!plot->rectangle(x0 + w - 1, - y0 + 1, - x1 - w + 2, - y1, - &bg_fill_style)) + rect.x0 = area.x0 + w - 1; + rect.y0 = area.y0 + 1; + rect.x1 = area.x1 - w + 2; + rect.y1 = area.y1; + res = ctx->plot->rectangle(ctx, &bg_fill_style, &rect); + if (res != NSERROR_OK) { return false; + } + /* scrollbar position indicator bar */ - if (!scrollbar_redraw_scrollbar_rectangle(bar_c0, - y0 + 1, - bar_c1, - y1 - 1, - fg_fill_colour, false, ctx)) + rect.x0 = bar_c0; + rect.y0 = area.y0 + 1; + rect.x1 = bar_c1; + rect.y1 = area.y1 - 1; + res = scrollbar_rectangle(ctx, &rect, fg_fill_colour, false); + if (res != NSERROR_OK) { return false; - if (!plot->rectangle(bar_c0 + 1, - y0 + 2, - bar_c1, - y1 - 1, - &fg_fill_style)) + } + + rect.x0 = bar_c0 + 1; + rect.y0 = area.y0 + 2; + rect.x1 = bar_c1; + rect.y1 = area.y1 - 1; + res = ctx->plot->rectangle(ctx, &fg_fill_style, &rect); + if (res != NSERROR_OK) { return false; + } + /* right arrow icon border */ - if (!scrollbar_redraw_scrollbar_rectangle(x1 - w + 2, - y0 + 1, - x1 - 1, - y1 - 1, - fg_fill_colour, false, ctx)) + rect.x0 = area.x1 - w + 2; + rect.y0 = area.y0 + 1; + rect.x1 = area.x1 - 1; + rect.y1 = area.y1 - 1; + res = scrollbar_rectangle(ctx, &rect, fg_fill_colour, false); + if (res != NSERROR_OK) { return false; + } + /* right arrow icon background */ - if (!plot->rectangle(x1 - w + 3, - y0 + 2, - x1 - 1, - y1 - 1, - &fg_fill_style)) + rect.x0 = area.x1 - w + 3; + rect.y0 = area.y0 + 2; + rect.x1 = area.x1 - 1; + rect.y1 = area.y1 - 1; + res = ctx->plot->rectangle(ctx, &fg_fill_style, &rect); + if (res != NSERROR_OK) { return false; + } + /* right arrow */ - v[0] = x1 - w / 4 + 1; - v[1] = y0 + w / 2; - v[2] = x1 - w * 3 / 4 + 1; - v[3] = y0 + w / 4; - v[4] = x1 - w * 3 / 4 + 1; - v[5] = y0 + w * 3 / 4; - if (!plot->polygon(v, 3, &arrow_fill_style)) + v[0] = rect.x1 - w / 4 + 1; + v[1] = rect.y0 + w / 2; + v[2] = rect.x1 - w * 3 / 4 + 1; + v[3] = rect.y0 + w / 4; + v[4] = rect.x1 - w * 3 / 4 + 1; + v[5] = rect.y0 + w * 3 / 4; + res = ctx->plot->polygon(ctx, &arrow_fill_style, v, 3); + if (res != NSERROR_OK) { return false; + } } else { /* scrollbar is vertical */ - + /* outline */ - if (!scrollbar_redraw_scrollbar_rectangle(x0, y0, x1, y1, - bg_fill_colour, true, ctx)) + res = scrollbar_rectangle(ctx, &area, bg_fill_colour, true); + if (res != NSERROR_OK) { return false; - /* top arrow background */ - if (!scrollbar_redraw_scrollbar_rectangle(x0 + 1, - y0 + 1, - x1 - 1, - y0 + w - 2, - fg_fill_colour, false, ctx)) + } + + /* top arrow border */ + rect.x0 = area.x0 + 1; + rect.y0 = area.y0 + 1; + rect.x1 = area.x1 - 1; + rect.y1 = area.y0 + w - 2; + res = scrollbar_rectangle(ctx, &rect, fg_fill_colour, false); + if (res != NSERROR_OK) { return false; - if (!plot->rectangle(x0 + 2, - y0 + 2, - x1 - 1, - y0 + w - 2, - &fg_fill_style)) + } + + /* top arrow background */ + rect.x0 = area.x0 + 2; + rect.y0 = area.y0 + 2; + rect.x1 = area.x1 - 1; + rect.y1 = area.y0 + w - 2; + res = ctx->plot->rectangle(ctx, &fg_fill_style, &rect); + if (res != NSERROR_OK) { return false; + } + /* up arrow */ - v[0] = x0 + w / 2; - v[1] = y0 + w / 4; - v[2] = x0 + w / 4; - v[3] = y0 + w * 3 / 4; - v[4] = x0 + w * 3 / 4; - v[5] = y0 + w * 3 / 4; - if (!plot->polygon(v, 3, &arrow_fill_style)) + v[0] = area.x0 + w / 2; + v[1] = area.y0 + w / 4; + v[2] = area.x0 + w / 4; + v[3] = area.y0 + w * 3 / 4; + v[4] = area.x0 + w * 3 / 4; + v[5] = area.y0 + w * 3 / 4; + res = ctx->plot->polygon(ctx, &arrow_fill_style, v, 3); + if (res != NSERROR_OK) { return false; + } + /* scrollbar well background */ - if (!plot->rectangle(x0 + 1, - y0 + w - 1, - x1, - y1 - w + 2, - &bg_fill_style)) + rect.x0 = area.x0 + 1; + rect.y0 = area.y0 + w - 1; + rect.x1 = area.x1; + rect.y1 = area.y1 - w + 2; + res = ctx->plot->rectangle(ctx, &bg_fill_style, &rect); + if (res != NSERROR_OK) { return false; + } + /* scrollbar position indicator bar */ - if (!scrollbar_redraw_scrollbar_rectangle(x0 + 1, - bar_c0, - x1 - 1, - bar_c1, - fg_fill_colour, false, ctx)) + rect.x0 = area.x0 + 1; + rect.y0 = bar_c0; + rect.x1 = area.x1 - 1; + rect.y1 = bar_c1; + res = scrollbar_rectangle(ctx, &rect, fg_fill_colour, false); + if (res != NSERROR_OK) { return false; - if (!plot->rectangle(x0 + 2, - bar_c0 + 1, - x1 - 1, - bar_c1, - &fg_fill_style)) + } + + rect.x0 = area.x0 + 2; + rect.y0 = bar_c0 + 1; + rect.x1 = area.x1 - 1; + rect.y1 = bar_c1; + res = ctx->plot->rectangle(ctx, &fg_fill_style, &rect); + if (res != NSERROR_OK) { return false; - /* bottom arrow background */ - if (!scrollbar_redraw_scrollbar_rectangle(x0 + 1, - y1 - w + 2, - x1 - 1, - y1 - 1, - fg_fill_colour, false, ctx)) + } + + /* down arrow icon border */ + rect.x0 = area.x0 + 1; + rect.y0 = area.y1 - w + 2; + rect.x1 = area.x1 - 1; + rect.y1 = area.y1 - 1; + res = scrollbar_rectangle(ctx, &rect, fg_fill_colour, false); + if (res != NSERROR_OK) { return false; - if (!plot->rectangle(x0 + 2, - y1 - w + 3, - x1 - 1, - y1 - 1, - &fg_fill_style)) + } + + /* down arrow icon background */ + rect.x0 = area.x0 + 2; + rect.y0 = area.y1 - w + 3; + rect.x1 = area.x1 - 1; + rect.y1 = area.y1 - 1; + res = ctx->plot->rectangle(ctx, &fg_fill_style, &rect); + if (res != NSERROR_OK) { return false; + } + /* down arrow */ - v[0] = x0 + w / 2; - v[1] = y1 - w / 4 + 1; - v[2] = x0 + w / 4; - v[3] = y1 - w * 3 / 4 + 1; - v[4] = x0 + w * 3 / 4; - v[5] = y1 - w * 3 / 4 + 1; - if (!plot->polygon(v, 3, &arrow_fill_style)) + v[0] = area.x0 + w / 2; + v[1] = area.y1 - w / 4 + 1; + v[2] = area.x0 + w / 4; + v[3] = area.y1 - w * 3 / 4 + 1; + v[4] = area.x0 + w * 3 / 4; + v[5] = area.y1 - w * 3 / 4 + 1; + res = ctx->plot->polygon(ctx, &arrow_fill_style, v, 3); + if (res != NSERROR_OK) { return false; + } } return true; @@ -568,7 +670,7 @@ bool scrollbar_is_horizontal(struct scrollbar *s) * \param x the X coordinate of the drag start * \param y the Y coordinate of the drag start * \param content_drag whether this should be a reverse drag (used when the - * user drags the content area, rather than the scrollbar) + * user drags the content area, rather than the scrollbar) * \param pair whether the drag is a '2D' scroll */ @@ -682,7 +784,7 @@ scrollbar_mouse_status scrollbar_mouse_action(struct scrollbar *s, if (val < SCROLLBAR_WIDTH) { /* left/up arrow */ - + status = h ? SCROLLBAR_MOUSE_LFT : SCROLLBAR_MOUSE_UP; if (but1) scrollbar_set(s, s->offset - SCROLLBAR_WIDTH, false); @@ -721,15 +823,15 @@ scrollbar_mouse_status scrollbar_mouse_action(struct scrollbar *s, } else { /* scrollbar position indication bar */ - + status = h ? SCROLLBAR_MOUSE_HRZ : SCROLLBAR_MOUSE_VRT; } - + if (mouse & (BROWSER_MOUSE_DRAG_1 | BROWSER_MOUSE_DRAG_2) && - (val >= SCROLLBAR_WIDTH + s->bar_pos - && val < SCROLLBAR_WIDTH + s->bar_pos + - s->bar_len)) + (val >= SCROLLBAR_WIDTH + s->bar_pos + && val < SCROLLBAR_WIDTH + s->bar_pos + + s->bar_len)) /* The mouse event is a drag start on the scrollbar position * indication bar. */ scrollbar_drag_start_internal(s, x, y, false, @@ -857,4 +959,3 @@ void *scrollbar_get_data(struct scrollbar *s) { return s->client_data; } - diff --git a/desktop/textarea.c b/desktop/textarea.c index 203c28e93..af1cd80be 100644 --- a/desktop/textarea.c +++ b/desktop/textarea.c @@ -2095,13 +2095,13 @@ bool textarea_set_caret(struct textarea *ta, int caret) void textarea_redraw(struct textarea *ta, int x, int y, colour bg, float scale, const struct rect *clip, const struct redraw_context *ctx) { - const struct plotter_table *plot = ctx->plot; int line0, line1, line, left, right, line_y; int text_y_offset, text_y_offset_baseline; unsigned int b_pos, b_len, b_len_part, b_end; unsigned int sel_start, sel_end; char *line_text; struct rect r, s; + struct rect rect; bool selected = false; plot_font_style_t fstyle; int fsize = ta->fstyle.size; @@ -2162,20 +2162,24 @@ void textarea_redraw(struct textarea *ta, int x, int y, colour bg, float scale, r.y1 = y + ta->vis_height * scale; } - plot->clip(&r); + ctx->plot->clip(ctx, &r); if (ta->border_col != NS_TRANSPARENT && ta->border_width > 0) { /* Plot border */ - plot->rectangle(x, y, x + ta->vis_width, y + ta->vis_height, - &plot_style_fill_bg); + rect.x0 = x; + rect.y0 = y; + rect.x1 = x + ta->vis_width; + rect.y1 = y + ta->vis_height; + ctx->plot->rectangle(ctx, &plot_style_fill_bg, &rect); } if (ta->fstyle.background != NS_TRANSPARENT) { /* Plot background */ plot_style_fill_bg.fill_colour = ta->fstyle.background; - plot->rectangle(x + ta->border_width, y + ta->border_width, - x + ta->vis_width - ta->border_width, - y + ta->vis_height - ta->border_width, - &plot_style_fill_bg); + rect.x0 = x + ta->border_width; + rect.y0 = y + ta->border_width; + rect.x1 = x + ta->vis_width - ta->border_width; + rect.y1 = y + ta->vis_height - ta->border_width; + ctx->plot->rectangle(ctx, &plot_style_fill_bg, &rect); } if (scale == 1.0) { @@ -2223,16 +2227,16 @@ void textarea_redraw(struct textarea *ta, int x, int y, colour bg, float scale, plot_style_fill_bg.fill_colour = ta->sel_fstyle.background; - for (line = line0; (line <= line1) && - (y + line * ta->line_height <= r.y1 + ta->scroll_y); - line++) { + for (line = line0; + (line <= line1) && (y + line * ta->line_height <= r.y1 + ta->scroll_y); + line++) { if (ta->lines[line].b_length == 0) { b_pos++; continue; } /* reset clip rectangle */ - plot->clip(&r); + ctx->plot->clip(ctx, &r); b_len = ta->lines[line].b_length; @@ -2256,12 +2260,12 @@ void textarea_redraw(struct textarea *ta, int x, int y, colour bg, float scale, fstyle = ta->fstyle; fstyle.size = fsize; - plot->text(x + ta->border_width + ta->pad_left - - ta->scroll_x, + ctx->plot->text(ctx, + &fstyle, + x + ta->border_width + ta->pad_left - ta->scroll_x, y + line_y + text_y_offset_baseline, - ta->show->data + - ta->lines[line].b_start, - ta->lines[line].b_length, &fstyle); + ta->show->data + ta->lines[line].b_start, + ta->lines[line].b_length); b_pos += b_len; @@ -2338,24 +2342,24 @@ void textarea_redraw(struct textarea *ta, int x, int y, colour bg, float scale, continue; } - plot->clip(&s); + ctx->plot->clip(ctx, &s); if (selected) { /* draw selection fill */ - plot->rectangle(s.x0, y + line_y + - text_y_offset, - s.x1, y + line_y + line_height + - text_y_offset, - &plot_style_fill_bg); + rect.x0 = s.x0; + rect.y0 = y + line_y + text_y_offset; + rect.x1 = s.x1; + rect.y1 = y + line_y + line_height + text_y_offset; + ctx->plot->rectangle(ctx, &plot_style_fill_bg, &rect); } /* draw text */ - plot->text(x + ta->border_width + ta->pad_left - - ta->scroll_x, + ctx->plot->text(ctx, + &fstyle, + x + ta->border_width + ta->pad_left - ta->scroll_x, y + line_y + text_y_offset_baseline, - ta->show->data + - ta->lines[line].b_start, - ta->lines[line].b_length, &fstyle); + ta->show->data + ta->lines[line].b_start, + ta->lines[line].b_length); b_pos += b_len_part; b_len -= b_len_part; @@ -2376,16 +2380,17 @@ void textarea_redraw(struct textarea *ta, int x, int y, colour bg, float scale, /* No native caret, there is no selection, and caret visible */ int caret_y = y - ta->scroll_y + ta->caret_y; - plot->clip(&r); + ctx->plot->clip(ctx, &r); /* Render our own caret */ - plot->line(x - ta->scroll_x + ta->caret_x, caret_y, - x - ta->scroll_x + ta->caret_x, - caret_y + ta->line_height, - &pstyle_stroke_caret); + rect.x0 = x - ta->scroll_x + ta->caret_x; + rect.y0 = caret_y; + rect.x1 = x - ta->scroll_x + ta->caret_x; + rect.y1 = caret_y + ta->line_height; + ctx->plot->line(ctx, &pstyle_stroke_caret, &rect); } - plot->clip(clip); + ctx->plot->clip(ctx, clip); if (ta->bar_x != NULL) scrollbar_redraw(ta->bar_x, diff --git a/desktop/treeview.c b/desktop/treeview.c index 4d8fbaaeb..541852d86 100644 --- a/desktop/treeview.c +++ b/desktop/treeview.c @@ -1798,10 +1798,11 @@ void treeview_redraw(treeview *tree, const int x, const int y, struct treeview_node_style *style = &plot_style_odd; struct content_redraw_data data; struct rect r; + struct rect rect; uint32_t count = 0; int render_y = y; int inset; - int x0, y0, y1; + int x0; int baseline = (tree_g.line_height * 3 + 2) / 4; enum treeview_resource_id res = TREE_RES_CONTENT; plot_style_t *bg_style; @@ -1833,7 +1834,7 @@ void treeview_redraw(treeview *tree, const int x, const int y, r.y0 = clip->y0 + y; r.x1 = clip->x1 + x; r.y1 = clip->y1 + y; - new_ctx.plot->clip(&r); + new_ctx.plot->clip(&new_ctx, &r); /* Draw the tree */ node = root = tree->root; @@ -1912,24 +1913,30 @@ void treeview_redraw(treeview *tree, const int x, const int y, } /* Render background */ - y0 = render_y; - y1 = render_y + height; - new_ctx.plot->rectangle(r.x0, y0, r.x1, y1, bg_style); + rect.x0 = r.x0; + rect.y0 = render_y; + rect.x1 = r.x1; + rect.y1 = render_y + height; + new_ctx.plot->rectangle(&new_ctx, bg_style, &rect); /* Render toggle */ - new_ctx.plot->bitmap(inset, render_y + tree_g.line_height / 4, - style->furn[TREE_FURN_EXPAND].size, - style->furn[TREE_FURN_EXPAND].size, - furniture, - bg_style->fill_colour, BITMAPF_NONE); + new_ctx.plot->bitmap(&new_ctx, + furniture, + inset, + render_y + tree_g.line_height / 4, + style->furn[TREE_FURN_EXPAND].size, + style->furn[TREE_FURN_EXPAND].size, + bg_style->fill_colour, + BITMAPF_NONE); /* Render icon */ - if (node->type == TREE_NODE_ENTRY) + if (node->type == TREE_NODE_ENTRY) { res = TREE_RES_CONTENT; - else if (node->flags & TV_NFLAGS_SPECIAL) + } else if (node->flags & TV_NFLAGS_SPECIAL) { res = TREE_RES_FOLDER_SPECIAL; - else + } else { res = TREE_RES_FOLDER; + } if (treeview_res[res].ready) { /* Icon resource is available */ @@ -1944,9 +1951,11 @@ void treeview_redraw(treeview *tree, const int x, const int y, /* Render text */ x0 = inset + tree_g.step_width + tree_g.icon_step; - new_ctx.plot->text(x0, render_y + baseline, - node->text.data, node->text.len, - text_style); + new_ctx.plot->text(&new_ctx, + text_style, + x0, render_y + baseline, + node->text.data, + node->text.len); /* Rendered the node */ render_y += tree_g.line_height; @@ -1970,25 +1979,25 @@ void treeview_redraw(treeview *tree, const int x, const int y, if (ef->flags & TREE_FLAG_SHOW_NAME) { int max_width = tree->field_width; - new_ctx.plot->text(x0 + max_width - - ef->value.width - - tree_g.step_width, - render_y + baseline, - ef->value.data, - ef->value.len, - infotext_style); - - new_ctx.plot->text(x0 + max_width, - render_y + baseline, - entry->fields[i].value.data, - entry->fields[i].value.len, - infotext_style); + new_ctx.plot->text(&new_ctx, + infotext_style, + x0 + max_width - ef->value.width - tree_g.step_width, + render_y + baseline, + ef->value.data, + ef->value.len); + + new_ctx.plot->text(&new_ctx, + infotext_style, + x0 + max_width, + render_y + baseline, + entry->fields[i].value.data, + entry->fields[i].value.len); } else { - new_ctx.plot->text(x0, render_y + baseline, - entry->fields[i].value.data, - entry->fields[i].value.len, - infotext_style); - + new_ctx.plot->text(&new_ctx, + infotext_style, + x0, render_y + baseline, + entry->fields[i].value.data, + entry->fields[i].value.len); } /* Rendered the expanded entry field */ @@ -2006,21 +2015,22 @@ void treeview_redraw(treeview *tree, const int x, const int y, if (render_y < r.y1) { /* Fill the blank area at the bottom */ - y0 = render_y; - new_ctx.plot->rectangle(r.x0, y0, r.x1, r.y1, - &plot_style_even.bg); + rect.x0 = r.x0; + rect.y0 = render_y; + rect.x1 = r.x1; + rect.y1 = r.y1; + new_ctx.plot->rectangle(&new_ctx, &plot_style_even.bg, &rect); } /* All normal treeview rendering is done; render any overlays */ - if (tree->move.target_pos != TV_TARGET_NONE && - treeview_res[TREE_RES_ARROW].ready) { + if ((tree->move.target_pos != TV_TARGET_NONE) && + (treeview_res[TREE_RES_ARROW].ready)) { /* Got a MOVE drag; render move indicator arrow */ data.x = tree->move.target_area.x0 + x; data.y = tree->move.target_area.y0 + y; data.background_colour = plot_style_even.bg.fill_colour; - content_redraw(treeview_res[TREE_RES_ARROW].c, - &data, &r, &new_ctx); + content_redraw(treeview_res[TREE_RES_ARROW].c, &data, &r, &new_ctx); } else if (tree->edit.textarea != NULL) { /* Edit in progress; render textarea */ @@ -2031,8 +2041,9 @@ void treeview_redraw(treeview *tree, const int x, const int y, } /* Rendering complete */ - if (ctx->plot->option_knockout) + if (ctx->plot->option_knockout) { knockout_plot_end(); + } } struct treeview_selection_walk_data { diff --git a/render/form.c b/render/form.c index 6eb1b80b8..be07e80f0 100644 --- a/render/form.c +++ b/render/form.c @@ -1167,7 +1167,6 @@ bool form_redraw_select_menu(struct form_control *control, int x, int y, float scale, const struct rect *clip, const struct redraw_context *ctx) { - const struct plotter_table *plot = ctx->plot; struct box *box; struct form_select_menu *menu = control->data.select.menu; struct form_option *option; @@ -1181,7 +1180,9 @@ bool form_redraw_select_menu(struct form_control *control, int x, int y, int scroll; int x_cp, y_cp; struct rect r; - + struct rect rect; + nserror res; + box = control->box; x_cp = x; @@ -1220,12 +1221,20 @@ bool form_redraw_select_menu(struct form_control *control, int x, int y, r.y0 = y0; r.x1 = x1 + 1; r.y1 = y1 + 1; - if (!plot->clip(&r)) + res = ctx->plot->clip(ctx, &r); + if (res != NSERROR_OK) { return false; - if (!plot->rectangle(x0, y0, x1, y1 ,plot_style_stroke_darkwbasec)) + } + + 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; @@ -1236,11 +1245,16 @@ bool form_redraw_select_menu(struct form_control *control, int x, int y, r.y0 = y0; r.x1 = x1 + 1; r.y1 = y1 + 1; - if (!plot->clip(&r)) + res = ctx->plot->clip(ctx, &r); + if (res != NSERROR_OK) { return false; - if (!plot->rectangle(x0, y0, x1 + 1, y1 + 1, - plot_style_fill_lightwbasec)) + } + + 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; @@ -1256,32 +1270,40 @@ bool form_redraw_select_menu(struct form_control *control, int x, int y, 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; - if (!plot->rectangle(x0, (y0 > y2 ? y0 : y2), - scrollbar_x + 1, - (y3 < y1 + 1 ? y3 : y1 + 1), - &plot_style_fill_selected)) + + 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; - if (!plot->text(text_x, y2, option->text, - strlen(option->text), &plot_fstyle_entry)) + 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; } - + if (!scrollbar_redraw(menu->scrollbar, x_cp + menu->width - SCROLLBAR_WIDTH, y_cp, clip, scale, ctx)) return false; - + return true; } diff --git a/render/html_redraw.c b/render/html_redraw.c index ae8675671..dd6362820 100644 --- a/render/html_redraw.c +++ b/render/html_redraw.c @@ -150,16 +150,26 @@ static struct box *html_redraw_find_bg_box(struct box *box) * \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 +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) { - const struct plotter_table *plot = ctx->plot; bool highlighted = false; plot_font_style_t plot_fstyle = *fstyle; + nserror res; /* Need scaled text size to pass to plotters */ plot_fstyle.size *= scale; @@ -195,7 +205,6 @@ bool text_redraw(const char *utf8_text, size_t utf8_len, int startx, endx; plot_style_t pstyle_fill_hback = *plot_style_fill_white; plot_font_style_t fstyle_hback = plot_fstyle; - nserror res; if (end_idx > utf8_len) { /* adjust for trailing space, not present in @@ -230,19 +239,26 @@ bool text_redraw(const char *utf8_text, size_t utf8_len, } /* draw any text preceding highlighted portion */ - if (start_idx > 0 && - !plot->text(x, y + (int)(height * 0.75 * scale), - utf8_text, start_idx, - &plot_fstyle)) + 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 */ - if (!plot->rectangle(x + startx, y, x + endx, - y + height * scale, - &pstyle_fill_hback)) + 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); @@ -253,8 +269,11 @@ bool text_redraw(const char *utf8_text, size_t utf8_len, r.y0 = clip->y0; r.x1 = px1; r.y1 = clip->y1; - if (!plot->clip(&r)) + res = ctx->plot->clip(ctx, &r); + if (res != NSERROR_OK) { return false; + } + clip_changed = true; } else { text_visible = false; @@ -267,10 +286,14 @@ bool text_redraw(const char *utf8_text, size_t utf8_len, pstyle_fill_hback.fill_colour); if (text_visible && - !plot->text(x, y + (int)(height * 0.75 * scale), - utf8_text, endtxt_idx, - &fstyle_hback)) + (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) { @@ -281,30 +304,42 @@ bool text_redraw(const char *utf8_text, size_t utf8_len, r.y0 = clip->y0; r.x1 = clip->x1; r.y1 = clip->y1; - if (!plot->clip(&r)) + res = ctx->plot->clip(ctx, &r); + if (res != NSERROR_OK) { return false; + } clip_changed = true; - if (!plot->text(x, y + (int) - (height * 0.75 * scale), - utf8_text, utf8_len, - &plot_fstyle)) + 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 && - !plot->clip(clip)) + (ctx->plot->clip(ctx, clip) != NSERROR_OK)) { return false; + } } } if (!highlighted) { - if (!plot->text(x, y + (int) (height * 0.75 * scale), - utf8_text, utf8_len, - &plot_fstyle)) + 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; } @@ -328,6 +363,27 @@ 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. * @@ -342,15 +398,22 @@ static plot_style_t plot_style_fillbdr_dlight = { * \return true if successful, false otherwise */ -static bool 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) +static bool +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) { - const struct plotter_table *plot = ctx->plot; 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; + struct rect rect; if (c == NS_TRANSPARENT) return true; @@ -369,44 +432,51 @@ static bool html_redraw_border_plot(const int side, const int *p, colour c, plot_style_bdr.stroke_type = PLOT_OP_TYPE_DOT; /* fall through */ case CSS_BORDER_STYLE_DASHED: - if (!plot->line((p[0] + p[2]) / 2, - (p[1] + p[3]) / 2, - (p[4] + p[6]) / 2, - (p[5] + p[7]) / 2, - &plot_style_bdr)) + 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); + if (res != NSERROR_OK) { return false; + } break; case CSS_BORDER_STYLE_SOLID: /* fall through to default */ default: if (rectangular || thickness == 1) { - int x0, y0, x1, y1; + if (side == TOP || side == RIGHT) { - x0 = p[2]; y0 = p[3]; - x1 = p[6]; y1 = p[7]; - x1 = ((side == TOP) && (p[4] - p[6] != 0)) ? - x1 + p[4] - p[6] : x1; + 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 { - x0 = p[6]; y0 = p[7]; - x1 = p[2]; y1 = p[3]; - y1 = ((side == LEFT) && (p[1] - p[3] != 0)) ? - y1 + p[1] - p[3] : y1; + 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]; + } } - /* find intersection of clip rectangle and border */ - x0 = (clip->x0 > x0) ? clip->x0 : x0; - y0 = (clip->y0 > y0) ? clip->y0 : y0; - x1 = (clip->x1 < x1) ? clip->x1 : x1; - y1 = (clip->y1 < y1) ? clip->y1 : y1; - if ((x0 < x1) && (y0 < y1)) { - /* valid clip rectangles only */ - if (!plot->rectangle(x0, y0, x1, y1, - &plot_style_fillbdr)) - return false; + res = plot_clipped_rectangle(ctx, &plot_style_fillbdr, clip, &rect); + if (res != NSERROR_OK) { + return false; } } else { - if (!plot->polygon(p, 4, &plot_style_fillbdr)) + res = ctx->plot->polygon(ctx, &plot_style_fillbdr, p, 4); + if (res != NSERROR_OK) { return false; + } } break; @@ -419,8 +489,10 @@ static bool html_redraw_border_plot(const int side, const int *p, colour c, z[5] = (p[7] * 2 + p[5]) / 3; z[6] = p[6]; z[7] = p[7]; - if (!plot->polygon(z, 4, &plot_style_fillbdr)) + res = ctx->plot->polygon(ctx, &plot_style_fillbdr, z, 4); + if (res != NSERROR_OK) { return false; + } z[0] = p[2]; z[1] = p[3]; z[2] = (p[2] * 2 + p[0]) / 3; @@ -429,13 +501,16 @@ static bool html_redraw_border_plot(const int side, const int *p, colour c, z[5] = (p[5] * 2 + p[7]) / 3; z[6] = p[4]; z[7] = p[5]; - if (!plot->polygon(z, 4, &plot_style_fillbdr)) + res = ctx->plot->polygon(ctx, &plot_style_fillbdr, z, 4); + if (res != NSERROR_OK) { return false; + } 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) { @@ -449,90 +524,74 @@ static bool html_redraw_border_plot(const int side, const int *p, colour c, /* Render border */ if ((rectangular || thickness == 2) && thickness != 1) { /* Border made up from two parts and can be plotted - * with rectangles */ - int x0, y0, x1, y1; + * with rectangles + */ /* First part */ if (side == TOP || side == RIGHT) { - x0 = (p[0] + p[2]) / 2; y0 = (p[1] + p[3]) / 2; - x1 = p[6]; y1 = p[7]; + rect.x0 = (p[0] + p[2]) / 2; + rect.y0 = (p[1] + p[3]) / 2; + rect.x1 = p[6]; + rect.y1 = p[7]; } else { - x0 = p[6]; y0 = p[7]; - x1 = (p[0] + p[2]) / 2; y1 = (p[1] + p[3]) / 2; + rect.x0 = p[6]; + rect.y0 = p[7]; + rect.x1 = (p[0] + p[2]) / 2; + rect.y1 = (p[1] + p[3]) / 2; } - /* find intersection of clip rectangle and border */ - x0 = (clip->x0 > x0) ? clip->x0 : x0; - y0 = (clip->y0 > y0) ? clip->y0 : y0; - x1 = (clip->x1 < x1) ? clip->x1 : x1; - y1 = (clip->y1 < y1) ? clip->y1 : y1; - if ((x0 < x1) && (y0 < y1)) { - /* valid clip rectangles only */ - if (!plot->rectangle(x0, y0, x1, y1, - plot_style_bdr_in)) - return false; + res = plot_clipped_rectangle(ctx, plot_style_bdr_in, clip, &rect); + if (res != NSERROR_OK) { + return false; } /* Second part */ if (side == TOP || side == RIGHT) { - x0 = p[2]; y0 = p[3]; - x1 = (p[6] + p[4]) / 2; y1 = (p[7] + p[5]) / 2; + rect.x0 = p[2]; + rect.y0 = p[3]; + rect.x1 = (p[6] + p[4]) / 2; + rect.y1 = (p[7] + p[5]) / 2; } else { - x0 = (p[6] + p[4]) / 2; y0 = (p[7] + p[5]) / 2; - x1 = p[2]; y1 = p[3]; + rect.x0 = (p[6] + p[4]) / 2; + rect.y0 = (p[7] + p[5]) / 2; + rect.x1 = p[2]; + rect.y1 = p[3]; } - /* find intersection of clip rectangle and border */ - x0 = (clip->x0 > x0) ? clip->x0 : x0; - y0 = (clip->y0 > y0) ? clip->y0 : y0; - x1 = (clip->x1 < x1) ? clip->x1 : x1; - y1 = (clip->y1 < y1) ? clip->y1 : y1; - if ((x0 < x1) && (y0 < y1)) { - /* valid clip rectangles only */ - if (!plot->rectangle(x0, y0, x1, y1, - plot_style_bdr_out)) - return false; + res = plot_clipped_rectangle(ctx, plot_style_bdr_out, clip, &rect); + if (res != NSERROR_OK) { + return false; } } else if (thickness == 1) { /* Border made up from one part which can be plotted * as a rectangle */ - int x0, y0, x1, y1; + if (side == TOP || side == RIGHT) { - x0 = p[2]; y0 = p[3]; - x1 = p[6]; y1 = p[7]; - x1 = ((side == TOP) && (p[4] - p[6] != 0)) ? - x1 + p[4] - p[6] : x1; - /* find intersection of clip rectangle and - * border */ - x0 = (clip->x0 > x0) ? clip->x0 : x0; - y0 = (clip->y0 > y0) ? clip->y0 : y0; - x1 = (clip->x1 < x1) ? clip->x1 : x1; - y1 = (clip->y1 < y1) ? clip->y1 : y1; - if ((x0 < x1) && (y0 < y1)) { - /* valid clip rectangles only */ - if (!plot->rectangle(x0, y0, x1, y1, - plot_style_bdr_in)) - return false; + 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); + if (res != NSERROR_OK) { + return false; } } else { - x0 = p[6]; y0 = p[7]; - x1 = p[2]; y1 = p[3]; - y1 = ((side == LEFT) && (p[1] - p[3] != 0)) ? - y1 + p[1] - p[3] : y1; - /* find intersection of clip rectangle and - * border */ - x0 = (clip->x0 > x0) ? clip->x0 : x0; - y0 = (clip->y0 > y0) ? clip->y0 : y0; - x1 = (clip->x1 < x1) ? clip->x1 : x1; - y1 = (clip->y1 < y1) ? clip->y1 : y1; - if ((x0 < x1) && (y0 < y1)) { - /* valid clip rectangles only */ - if (!plot->rectangle(x0, y0, x1, y1, - plot_style_bdr_out)) - return false; + 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); + if (res != NSERROR_OK) { + return false; } } } else { /* Border made up from two parts and can't be plotted - * with rectangles */ + * with rectangles + */ z[0] = p[0]; z[1] = p[1]; z[2] = (p[0] + p[2]) / 2; @@ -541,14 +600,18 @@ static bool html_redraw_border_plot(const int side, const int *p, colour c, z[5] = (p[7] + p[5]) / 2; z[6] = p[6]; z[7] = p[7]; - if (!plot->polygon(z, 4, plot_style_bdr_in)) + res = ctx->plot->polygon(ctx, plot_style_bdr_in, z, 4); + if (res != NSERROR_OK) { return false; + } z[0] = p[2]; z[1] = p[3]; z[6] = p[4]; z[7] = p[5]; - if (!plot->polygon(z, 4, plot_style_bdr_out)) + res = ctx->plot->polygon(ctx, plot_style_bdr_out, z, 4); + if (res != NSERROR_OK) { return false; + } } break; @@ -583,90 +646,73 @@ static bool html_redraw_border_plot(const int side, const int *p, colour c, /* Render border */ if ((rectangular || thickness == 2) && thickness != 1) { /* Border made up from two parts and can be plotted - * with rectangles */ - int x0, y0, x1, y1; + * with rectangles + */ /* First part */ if (side == TOP || side == RIGHT) { - x0 = (p[0] + p[2]) / 2; y0 = (p[1] + p[3]) / 2; - x1 = p[6]; y1 = p[7]; + rect.x0 = (p[0] + p[2]) / 2; + rect.y0 = (p[1] + p[3]) / 2; + rect.x1 = p[6]; + rect.y1 = p[7]; } else { - x0 = p[6]; y0 = p[7]; - x1 = (p[0] + p[2]) / 2; y1 = (p[1] + p[3]) / 2; + rect.x0 = p[6]; + rect.y0 = p[7]; + rect.x1 = (p[0] + p[2]) / 2; + rect.y1 = (p[1] + p[3]) / 2; } - /* find intersection of clip rectangle and border */ - x0 = (clip->x0 > x0) ? clip->x0 : x0; - y0 = (clip->y0 > y0) ? clip->y0 : y0; - x1 = (clip->x1 < x1) ? clip->x1 : x1; - y1 = (clip->y1 < y1) ? clip->y1 : y1; - if ((x0 < x1) && (y0 < y1)) { - /* valid clip rectangles only */ - if (!plot->rectangle(x0, y0, x1, y1, - plot_style_bdr_in)) - return false; + res = plot_clipped_rectangle(ctx, plot_style_bdr_in, clip, &rect); + if (res != NSERROR_OK) { + return false; } /* Second part */ if (side == TOP || side == RIGHT) { - x0 = p[2]; y0 = p[3]; - x1 = (p[6] + p[4]) / 2; y1 = (p[7] + p[5]) / 2; + rect.x0 = p[2]; + rect.y0 = p[3]; + rect.x1 = (p[6] + p[4]) / 2; + rect.y1 = (p[7] + p[5]) / 2; } else { - x0 = (p[6] + p[4]) / 2; y0 = (p[7] + p[5]) / 2; - x1 = p[2]; y1 = p[3]; + rect.x0 = (p[6] + p[4]) / 2; + rect.y0 = (p[7] + p[5]) / 2; + rect.x1 = p[2]; + rect.y1 = p[3]; } - /* find intersection of clip rectangle and border */ - x0 = (clip->x0 > x0) ? clip->x0 : x0; - y0 = (clip->y0 > y0) ? clip->y0 : y0; - x1 = (clip->x1 < x1) ? clip->x1 : x1; - y1 = (clip->y1 < y1) ? clip->y1 : y1; - if ((x0 < x1) && (y0 < y1)) { - /* valid clip rectangles only */ - if (!plot->rectangle(x0, y0, x1, y1, - plot_style_bdr_out)) - return false; + res = plot_clipped_rectangle(ctx, plot_style_bdr_out, clip, &rect); + if (res != NSERROR_OK) { + return false; } } else if (thickness == 1) { /* Border made up from one part which can be plotted * as a rectangle */ - int x0, y0, x1, y1; + if (side == TOP || side == RIGHT) { - x0 = p[2]; y0 = p[3]; - x1 = p[6]; y1 = p[7]; - x1 = ((side == TOP) && (p[4] - p[6] != 0)) ? - x1 + p[4] - p[6] : x1; - /* find intersection of clip rectangle and - * border */ - x0 = (clip->x0 > x0) ? clip->x0 : x0; - y0 = (clip->y0 > y0) ? clip->y0 : y0; - x1 = (clip->x1 < x1) ? clip->x1 : x1; - y1 = (clip->y1 < y1) ? clip->y1 : y1; - if ((x0 < x1) && (y0 < y1)) { - /* valid clip rectangles only */ - if (!plot->rectangle(x0, y0, x1, y1, - plot_style_bdr_in)) - return false; + 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); + if (res != NSERROR_OK) { + return false; } } else { - x0 = p[6]; y0 = p[7]; - x1 = p[2]; y1 = p[3]; - y1 = ((side == LEFT) && (p[1] - p[3] != 0)) ? - y1 + p[1] - p[3] : y1; - /* find intersection of clip rectangle and - * border */ - x0 = (clip->x0 > x0) ? clip->x0 : x0; - y0 = (clip->y0 > y0) ? clip->y0 : y0; - x1 = (clip->x1 < x1) ? clip->x1 : x1; - y1 = (clip->y1 < y1) ? clip->y1 : y1; - if ((x0 < x1) && (y0 < y1)) { - /* valid clip rectangles only */ - if (!plot->rectangle(x0, y0, x1, y1, - plot_style_bdr_out)) - return false; + 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); + if (res != NSERROR_OK) { + return false; } } } else { /* Border made up from two parts and can't be plotted - * with rectangles */ + * with rectangles + */ z[0] = p[0]; z[1] = p[1]; z[2] = (p[0] + p[2]) / 2; @@ -675,14 +721,18 @@ static bool html_redraw_border_plot(const int side, const int *p, colour c, z[5] = (p[7] + p[5]) / 2; z[6] = p[6]; z[7] = p[7]; - if (!plot->polygon(z, 4, plot_style_bdr_in)) + res = ctx->plot->polygon(ctx, plot_style_bdr_in, z, 4); + if (res != NSERROR_OK) { return false; + } z[0] = p[2]; z[1] = p[3]; z[6] = p[4]; z[7] = p[5]; - if (!plot->polygon(z, 4, plot_style_bdr_out)) + res = ctx->plot->polygon(ctx, plot_style_bdr_out, z, 4); + if (res != NSERROR_OK) { return false; + } } break; } @@ -1152,42 +1202,85 @@ static bool html_redraw_inline_borders(struct box *box, struct rect b, static bool html_redraw_checkbox(int x, int y, int width, int height, bool selected, const struct redraw_context *ctx) { - const struct plotter_table *plot = ctx->plot; - double z = width * 0.15; - if (z == 0) + double z; + nserror res; + struct rect rect; + + z = width * 0.15; + if (z == 0) { z = 1; + } - if (!(plot->rectangle(x, y, x + width, y + height, - plot_style_fill_wbasec) && - plot->line(x, y, x + width, y, plot_style_stroke_darkwbasec) && - plot->line(x, y, x, y + height, plot_style_stroke_darkwbasec) && - plot->line(x + width, y, x + width, y + height, - plot_style_stroke_lightwbasec) && - plot->line(x, y + height, x + width, y + height, - plot_style_stroke_lightwbasec))) + 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 */ - if (!plot->rectangle(x + z + z, y + z + z, - x + width - z, y + height - z, - plot_style_fill_wblobc)) + 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 */ - if (!(plot->line(x + width - z, - y + z, - x + (z * 3), - y + height - z, - plot_style_stroke_wblobc) && - - plot->line(x + (z * 3), - y + height - z, - x + z + z, - y + (height / 2), - plot_style_stroke_wblobc))) + 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; @@ -1208,40 +1301,52 @@ static bool html_redraw_checkbox(int x, int y, int width, int height, static bool html_redraw_radio(int x, int y, int width, int height, bool selected, const struct redraw_context *ctx) { - const struct plotter_table *plot = ctx->plot; + nserror res; /* plot background of radio button */ - if (!plot->disc(x + width * 0.5, - y + height * 0.5, - width * 0.5 - 1, - plot_style_fill_wbasec)) + 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 */ - if (!plot->arc(x + width * 0.5, - y + height * 0.5, - width * 0.5 - 1, - 45, - 225, - plot_style_fill_darkwbasec)) + 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 */ - if (!plot->arc(x + width * 0.5, - y + height * 0.5, - width * 0.5 - 1, - 225, - 45, - plot_style_fill_lightwbasec)) + 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 */ - if (!plot->disc(x + width * 0.5, - y + height * 0.5, - width * 0.3 - 1, - plot_style_fill_wblobc)) + 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; @@ -1275,10 +1380,11 @@ static bool html_redraw_file(int x, int y, int width, int height, font_plot_style_from_css(box->style, &fstyle); fstyle.background = background_colour; - if (box->gadget->value) + if (box->gadget->value) { text = box->gadget->value; - else + } else { text = messages_get("Form_Drop"); + } length = strlen(text); res = guit->layout->width(&fstyle, text, length, &text_width); @@ -1292,7 +1398,11 @@ static bool html_redraw_file(int x, int y, int width, int height, x = x + 4; } - return ctx->plot->text(x, y + height * 0.75, text, length, &fstyle); + res = ctx->plot->text(ctx, &fstyle, x, y + height * 0.75, text, length); + if (res != NSERROR_OK) { + return false; + } + return true; } @@ -1318,7 +1428,6 @@ 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 struct redraw_context *ctx) { - const struct plotter_table *plot = ctx->plot; bool repeat_x = false; bool repeat_y = false; bool plot_colour = true; @@ -1336,6 +1445,7 @@ static bool html_redraw_background(int x, int y, struct box *box, float scale, .fill_type = PLOT_OP_TYPE_SOLID, .fill_colour = *background_colour, }; + nserror res; if (ctx->background_images == false) return true; @@ -1465,10 +1575,12 @@ static bool html_redraw_background(int x, int y, struct box *box, float scale, if (nscss_color_is_transparent(bgcol) == false) { *background_colour = nscss_color_to_ns(bgcol); pstyle_fill_bg.fill_colour = *background_colour; - if (plot_colour) - if (!plot->rectangle(r.x0, r.y0, r.x1, r.y1, - &pstyle_fill_bg)) + 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) { @@ -1492,8 +1604,10 @@ static bool html_redraw_background(int x, int y, struct box *box, float scale, if ((r.x0 < r.x1) && (r.y0 < r.y1)) { struct content_redraw_data bg_data; - if (!plot->clip(&r)) + res = ctx->plot->clip(ctx, &r); + if (res != NSERROR_OK) { return false; + } bg_data.x = x; bg_data.y = y; @@ -1539,7 +1653,6 @@ static bool html_redraw_inline_background(int x, int y, struct box *box, bool first, bool last, colour *background_colour, const struct redraw_context *ctx) { - const struct plotter_table *plot = ctx->plot; struct rect r = *clip; bool repeat_x = false; bool repeat_y = false; @@ -1552,6 +1665,7 @@ static bool html_redraw_inline_background(int x, int y, struct box *box, .fill_type = PLOT_OP_TYPE_SOLID, .fill_colour = *background_colour, }; + nserror res; plot_content = (box->background != NULL); @@ -1618,10 +1732,12 @@ static bool html_redraw_inline_background(int x, int y, struct box *box, *background_colour = nscss_color_to_ns(bgcol); pstyle_fill_bg.fill_colour = *background_colour; - if (plot_colour) - if (!plot->rectangle(r.x0, r.y0, r.x1, r.y1, - &pstyle_fill_bg)) + 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) { @@ -1644,8 +1760,10 @@ static bool html_redraw_inline_background(int x, int y, struct box *box, if ((r.x0 < r.x1) && (r.y0 < r.y1)) { struct content_redraw_data bg_data; - if (!plot->clip(&r)) + res = ctx->plot->clip(ctx, &r); + if (res != NSERROR_OK) { return false; + } bg_data.x = x; bg_data.y = y; @@ -1678,28 +1796,36 @@ static bool html_redraw_inline_background(int x, int y, struct box *box, * \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) +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) { - const struct plotter_table *plot = ctx->plot; 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) + c && c != box->inline_end; + c = c->next) { + if (c->type != BOX_TEXT) { continue; - if (!plot->line((x + c->x) * scale, - (y + c->y + c->height * ratio) * scale, - (x + c->x + c->width) * scale, - (y + c->y + c->height * ratio) * scale, - &plot_style_box)) + } + 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; } @@ -1718,28 +1844,34 @@ static bool html_redraw_text_decoration_inline(struct box *box, int x, int y, * \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) +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) { - const struct plotter_table *plot = ctx->plot; 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) { - if (!plot->line((x + c->x) * scale, - (y + c->y + c->height * ratio) * scale, - (x + c->x + c->width) * scale, - (y + c->y + c->height * ratio) * scale, - &plot_style_box)) + 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) { + } + } 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)) @@ -1924,6 +2056,7 @@ bool html_redraw_box(const html_content *html, struct box *box, 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; @@ -2069,17 +2202,19 @@ bool html_redraw_box(const html_content *html, struct box *box, /* if visibility is hidden render children only */ if (box->style && css_computed_visibility(box->style) == CSS_VISIBILITY_HIDDEN) { - if ((plot->group_start) && (!plot->group_start("hidden box"))) + 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 ((!plot->group_end) || (plot->group_end())); + return ((!ctx->plot->group_end) || (ctx->plot->group_end(ctx) == NSERROR_OK)); } - if ((plot->group_start) && (!plot->group_start("vis box"))) + 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) == @@ -2115,9 +2250,10 @@ bool html_redraw_box(const html_content *html, struct box *box, /* Nothing to do for invalid rectangles */ if (r.x0 >= r.x1 || r.y0 >= r.y1) /* not an error */ - return ((!plot->group_end) || (plot->group_end())); + return ((!ctx->plot->group_end) || + (ctx->plot->group_end(ctx) == NSERROR_OK)); /* clip to it */ - if (!plot->clip(&r)) + if (ctx->plot->clip(ctx, &r) != NSERROR_OK) return false; } else if (box->type == BOX_BLOCK || box->type == BOX_INLINE_BLOCK || @@ -2130,14 +2266,15 @@ bool html_redraw_box(const html_content *html, struct box *box, /* no point trying to draw 0-width/height boxes */ if (r.x0 == r.x1 || r.y0 == r.y1) /* not an error */ - return ((!plot->group_end) || (plot->group_end())); + return ((!ctx->plot->group_end) || + (ctx->plot->group_end(ctx) == NSERROR_OK)); /* clip to it */ - if (!plot->clip(&r)) + if (ctx->plot->clip(ctx, &r) != NSERROR_OK) return false; } else { /* clip box is fine, clip to it */ r = *clip; - if (!plot->clip(&r)) + if (ctx->plot->clip(ctx, &r) != NSERROR_OK) return false; } @@ -2194,22 +2331,22 @@ bool html_redraw_box(const html_content *html, struct box *box, ¤t_background_color, bg_box, ctx)) return false; /* restore previous graphics window */ - if (!plot->clip(&r)) + 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 (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)) @@ -2273,7 +2410,7 @@ bool html_redraw_box(const html_content *html, struct box *box, ¤t_background_color, ctx)) return false; /* restore previous graphics window */ - if (!plot->clip(&r)) + if (ctx->plot->clip(ctx, &r) != NSERROR_OK) return false; if (!html_redraw_inline_borders(box, b, &r, scale, first, false, ctx)) @@ -2305,7 +2442,7 @@ bool html_redraw_box(const html_content *html, struct box *box, first, true, ¤t_background_color, ctx)) return false; /* restore previous graphics window */ - if (!plot->clip(&r)) + if (ctx->plot->clip(ctx, &r) != NSERROR_OK) return false; if (!html_redraw_inline_borders(box, b, &r, scale, first, true, ctx)) @@ -2330,26 +2467,27 @@ bool html_redraw_box(const html_content *html, struct box *box, margin_bottom = box->margin[BOTTOM] * scale; } /* Content edge -- blue */ - if (!plot->rectangle(x + padding_left, - y + padding_top, - x + padding_left + width, - y + padding_top + height, - plot_style_content_edge)) + 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 */ - if (!plot->rectangle(x, y, - x + padding_width, y + padding_height, - plot_style_padding_edge)) + 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 */ - if (!plot->rectangle( - x - border_left - margin_left, - y - border_top - margin_top, - x + padding_width + border_right + - margin_right, - y + padding_height + border_bottom + - margin_bottom, - plot_style_margin_edge)) + 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; } @@ -2368,8 +2506,10 @@ bool html_redraw_box(const html_content *html, struct box *box, 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 (!plot->group_end || plot->group_end()); + 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) { @@ -2379,8 +2519,10 @@ bool html_redraw_box(const html_content *html, struct box *box, 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 (!plot->group_end || plot->group_end()); + 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) { @@ -2390,26 +2532,30 @@ bool html_redraw_box(const html_content *html, struct box *box, 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 (!plot->group_end || plot->group_end()); + 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 (!plot->clip(&r)) + 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 ((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; @@ -2439,11 +2585,12 @@ bool html_redraw_box(const html_content *html, struct box *box, int obj_x = x + padding_left; nserror res; - if (!plot->rectangle(x + padding_left, - y + padding_top, - x + padding_left + width - 1, - y + padding_top + height - 1, - plot_style_broken_object)) { + 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; } @@ -2457,10 +2604,10 @@ bool html_redraw_box(const html_content *html, struct box *box, obj_x += width / 2 - obj_width / 2; } - if (!plot->text(obj_x, y + padding_top + (int) - (height * 0.75), - obj, sizeof(obj) - 1, - plot_fstyle_broken_object)) + 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; } @@ -2507,11 +2654,11 @@ bool html_redraw_box(const html_content *html, struct box *box, if (box->type == BOX_BLOCK || box->type == BOX_INLINE_BLOCK || box->type == BOX_TABLE_CELL || box->type == BOX_INLINE) - if (!plot->clip(clip)) + if (ctx->plot->clip(ctx, clip) != NSERROR_OK) return false; /* list marker */ - if (box->list_marker) + if (box->list_marker) { if (!html_redraw_box(html, box->list_marker, x_parent + box->x - scrollbar_get_offset(box->scroll_x), @@ -2519,6 +2666,7 @@ bool html_redraw_box(const html_content *html, struct box *box, scrollbar_get_offset(box->scroll_y), clip, scale, current_background_color, ctx)) return false; + } /* scrollbars */ if (((box->style && box->type != BOX_BR && @@ -2552,11 +2700,12 @@ bool html_redraw_box(const html_content *html, struct box *box, } if (box->type == BOX_BLOCK || box->type == BOX_INLINE_BLOCK || - box->type == BOX_TABLE_CELL || box->type == BOX_INLINE) - if (!plot->clip(clip)) + box->type == BOX_TABLE_CELL || box->type == BOX_INLINE) { + if (ctx->plot->clip(ctx, clip) != NSERROR_OK) return false; + } - return ((!plot->group_end) || (plot->group_end())); + return ((!plot->group_end) || (ctx->plot->group_end(ctx) == NSERROR_OK)); } /** @@ -2602,14 +2751,12 @@ bool html_redraw(struct content *c, struct content_redraw_data *data, if (!select_only) { /* clear to background colour */ - result = ctx->plot->clip(clip); + 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(clip->x0, clip->y0, - clip->x1, clip->y1, - &pstyle_fill_bg); + + 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); diff --git a/render/textplain.c b/render/textplain.c index ae148697e..d3768889d 100644 --- a/render/textplain.c +++ b/render/textplain.c @@ -865,7 +865,6 @@ bool textplain_redraw(struct content *c, struct content_redraw_data *data, { textplain_content *text = (textplain_content *) c; struct browser_window *bw = text->bw; - const struct plotter_table *plot = ctx->plot; char *utf8_data = text->utf8_data; long lineno; int x = data->x; @@ -878,6 +877,7 @@ bool textplain_redraw(struct content *c, struct content_redraw_data *data, struct textplain_line *line = text->physical_line; size_t length; plot_style_t *plot_style_highlight; + nserror res; if (line0 < 0) line0 = 0; @@ -890,9 +890,10 @@ bool textplain_redraw(struct content *c, struct content_redraw_data *data, if (line1 < line0) line1 = line0; - if (!plot->rectangle(clip->x0, clip->y0, clip->x1, clip->y1, - plot_style_fill_white)) + res = ctx->plot->rectangle(ctx, plot_style_fill_white, clip); + if (res != NSERROR_OK) { return false; + } if (!line) return true; @@ -979,11 +980,17 @@ bool textplain_redraw(struct content *c, struct content_redraw_data *data, } if (highlighted) { - int sy = y + (lineno * scaled_line_height); - if (!plot->rectangle(tx, sy, - ntx, sy + scaled_line_height, - plot_style_highlight)) + 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; + } } } -- cgit v1.2.3 From 30df27c3babe188cc553df77e84a36b4db84bd47 Mon Sep 17 00:00:00 2001 From: Vincent Sanders Date: Mon, 6 Feb 2017 15:44:11 +0000 Subject: simplify html redraw border plotting error handling --- render/html_redraw.c | 202 ++++++++++++++++++++++++++------------------------- 1 file changed, 103 insertions(+), 99 deletions(-) diff --git a/render/html_redraw.c b/render/html_redraw.c index dd6362820..e58918d81 100644 --- a/render/html_redraw.c +++ b/render/html_redraw.c @@ -398,7 +398,7 @@ plot_clipped_rectangle(const struct redraw_context *ctx, * \return true if successful, false otherwise */ -static bool +static nserror html_redraw_border_plot(const int side, const int *p, colour c, @@ -412,11 +412,12 @@ html_redraw_border_plot(const int side, unsigned int light = side; plot_style_t *plot_style_bdr_in; plot_style_t *plot_style_bdr_out; - nserror res; + nserror res = NSERROR_OK; struct rect rect; - if (c == NS_TRANSPARENT) - return true; + if (c == NS_TRANSPARENT) { + return res; + } plot_style_bdr.stroke_type = PLOT_OP_TYPE_DASH; plot_style_bdr.stroke_colour = c; @@ -437,9 +438,6 @@ html_redraw_border_plot(const int side, rect.x1 = (p[4] + p[6]) / 2; rect.y1 = (p[5] + p[7]) / 2; res = ctx->plot->line(ctx, &plot_style_bdr, &rect); - if (res != NSERROR_OK) { - return false; - } break; case CSS_BORDER_STYLE_SOLID: @@ -469,14 +467,8 @@ html_redraw_border_plot(const int side, } } res = plot_clipped_rectangle(ctx, &plot_style_fillbdr, clip, &rect); - if (res != NSERROR_OK) { - return false; - } } else { res = ctx->plot->polygon(ctx, &plot_style_fillbdr, p, 4); - if (res != NSERROR_OK) { - return false; - } } break; @@ -490,27 +482,22 @@ html_redraw_border_plot(const int side, z[6] = p[6]; z[7] = p[7]; res = ctx->plot->polygon(ctx, &plot_style_fillbdr, z, 4); - if (res != NSERROR_OK) { - return false; - } - 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); - if (res != NSERROR_OK) { - return false; + 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) { @@ -523,8 +510,8 @@ html_redraw_border_plot(const int side, /* Render border */ if ((rectangular || thickness == 2) && thickness != 1) { - /* Border made up from two parts and can be plotted - * with rectangles + /* Border made up from two parts and can be + * plotted with rectangles */ /* First part */ @@ -541,7 +528,7 @@ html_redraw_border_plot(const int side, } res = plot_clipped_rectangle(ctx, plot_style_bdr_in, clip, &rect); if (res != NSERROR_OK) { - return false; + return res; } /* Second part */ @@ -557,12 +544,10 @@ html_redraw_border_plot(const int side, rect.y1 = p[3]; } res = plot_clipped_rectangle(ctx, plot_style_bdr_out, clip, &rect); - if (res != NSERROR_OK) { - return false; - } } else if (thickness == 1) { - /* Border made up from one part which can be plotted - * as a rectangle */ + /* Border made up from one part which can be + * plotted as a rectangle + */ if (side == TOP || side == RIGHT) { rect.x0 = p[2]; @@ -573,9 +558,6 @@ html_redraw_border_plot(const int side, rect.x1 + p[4] - p[6] : rect.x1; res = plot_clipped_rectangle(ctx, plot_style_bdr_in, clip, &rect); - if (res != NSERROR_OK) { - return false; - } } else { rect.x0 = p[6]; rect.y0 = p[7]; @@ -584,13 +566,10 @@ html_redraw_border_plot(const int side, 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); - if (res != NSERROR_OK) { - return false; - } } } else { - /* Border made up from two parts and can't be plotted - * with rectangles + /* Border made up from two parts and can't be + * plotted with rectangles */ z[0] = p[0]; z[1] = p[1]; @@ -602,16 +581,13 @@ html_redraw_border_plot(const int side, z[7] = p[7]; res = ctx->plot->polygon(ctx, plot_style_bdr_in, z, 4); if (res != NSERROR_OK) { - return false; + 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); - if (res != NSERROR_OK) { - return false; - } } break; @@ -645,8 +621,8 @@ html_redraw_border_plot(const int side, /* Render border */ if ((rectangular || thickness == 2) && thickness != 1) { - /* Border made up from two parts and can be plotted - * with rectangles + /* Border made up from two parts and can be + * plotted with rectangles */ /* First part */ @@ -663,7 +639,7 @@ html_redraw_border_plot(const int side, } res = plot_clipped_rectangle(ctx, plot_style_bdr_in, clip, &rect); if (res != NSERROR_OK) { - return false; + return res; } /* Second part */ @@ -679,12 +655,10 @@ html_redraw_border_plot(const int side, rect.y1 = p[3]; } res = plot_clipped_rectangle(ctx, plot_style_bdr_out, clip, &rect); - if (res != NSERROR_OK) { - return false; - } } else if (thickness == 1) { - /* Border made up from one part which can be plotted - * as a rectangle */ + /* Border made up from one part which can be + * plotted as a rectangle + */ if (side == TOP || side == RIGHT) { rect.x0 = p[2]; @@ -694,9 +668,6 @@ html_redraw_border_plot(const int side, 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); - if (res != NSERROR_OK) { - return false; - } } else { rect.x0 = p[6]; rect.y0 = p[7]; @@ -705,14 +676,12 @@ html_redraw_border_plot(const int side, 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); - if (res != NSERROR_OK) { - return false; - } } } else { - /* Border made up from two parts and can't be plotted - * with rectangles + /* 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; @@ -723,21 +692,18 @@ html_redraw_border_plot(const int side, z[7] = p[7]; res = ctx->plot->polygon(ctx, plot_style_bdr_in, z, 4); if (res != NSERROR_OK) { - return false; + 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); - if (res != NSERROR_OK) { - return false; - } } break; } - return true; + return res; } @@ -770,6 +736,7 @@ static bool html_redraw_borders(struct box *box, int x_parent, int y_parent, 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; @@ -839,13 +806,19 @@ static bool html_redraw_borders(struct box *box, int x_parent, int y_parent, col = nscss_color_to_ns(box->border[side].c); - if (!html_redraw_border_plot(side, z, col, - box->border[side].style, - box->border[side].width * scale, - square_end_1 && square_end_2, - clip, ctx)) + 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); @@ -876,13 +849,19 @@ static bool html_redraw_borders(struct box *box, int x_parent, int y_parent, col = nscss_color_to_ns(box->border[side].c); - if (!html_redraw_border_plot(side, z, col, - box->border[side].style, - box->border[side].width * scale, - square_end_1 && square_end_2, - clip, ctx)) + 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 @@ -918,13 +897,19 @@ static bool html_redraw_borders(struct box *box, int x_parent, int y_parent, col = nscss_color_to_ns(box->border[side].c); - if (!html_redraw_border_plot(side, z, col, - box->border[side].style, - box->border[side].width * scale, - square_end_1 && square_end_2, - clip, ctx)) + 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 @@ -960,13 +945,19 @@ static bool html_redraw_borders(struct box *box, int x_parent, int y_parent, col = nscss_color_to_ns(box->border[side].c); - if (!html_redraw_border_plot(side, z, col, - box->border[side].style, - box->border[side].width * scale, - square_end_1 && square_end_2, - clip, ctx)) + 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); @@ -1004,6 +995,7 @@ static bool html_redraw_inline_borders(struct box *box, struct rect b, int z[8]; /* Border vertices */ bool square_end_1; bool square_end_2; + nserror res; if (scale != 1.0) { top *= scale; @@ -1060,11 +1052,17 @@ static bool html_redraw_inline_borders(struct box *box, struct rect b, square_end_2 = true; } - if (!html_redraw_border_plot(LEFT, z, col, - box->border[LEFT].style, - left, square_end_1 && square_end_2, - clip, ctx)) + 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 */ @@ -1098,11 +1096,13 @@ static bool html_redraw_inline_borders(struct box *box, struct rect b, square_end_2 = true; } - if (!html_redraw_border_plot(RIGHT, z, col, + res = html_redraw_border_plot(RIGHT, z, col, box->border[RIGHT].style, right, square_end_1 && square_end_2, - clip, ctx)) + clip, ctx); + if (res != NSERROR_OK) { return false; + } } /* Top */ @@ -1137,11 +1137,13 @@ static bool html_redraw_inline_borders(struct box *box, struct rect b, square_end_2 = true; } - if (!html_redraw_border_plot(TOP, z, col, + res = html_redraw_border_plot(TOP, z, col, box->border[TOP].style, top, square_end_1 && square_end_2, - clip, ctx)) + clip, ctx); + if (res != NSERROR_OK) { return false; + } } /* Bottom */ @@ -1176,11 +1178,13 @@ static bool html_redraw_inline_borders(struct box *box, struct rect b, square_end_2 = true; } - if (!html_redraw_border_plot(BOTTOM, z, col, + res = html_redraw_border_plot(BOTTOM, z, col, box->border[BOTTOM].style, bottom, square_end_1 && square_end_2, - clip, ctx)) + clip, ctx); + if (res != NSERROR_OK) { return false; + } } return true; -- cgit v1.2.3 From 18abdadac83789019ae1a36a1e1cad2e98601efa Mon Sep 17 00:00:00 2001 From: Vincent Sanders Date: Mon, 6 Feb 2017 18:17:39 +0000 Subject: split border drawing out of html redraw --- render/Makefile | 3 +- render/html_internal.h | 9 + render/html_redraw.c | 846 ---------------------------------------- render/html_redraw_border.c | 928 ++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 939 insertions(+), 847 deletions(-) create mode 100644 render/html_redraw_border.c diff --git a/render/Makefile b/render/Makefile index 148c2c39d..dc2e31c9e 100644 --- a/render/Makefile +++ b/render/Makefile @@ -3,7 +3,8 @@ 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_forms.c html_object.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/html_internal.h b/render/html_internal.h index fd65707ce..2f84cf869 100644 --- a/render/html_internal.h +++ b/render/html_internal.h @@ -258,6 +258,15 @@ bool html_begin_conversion(html_content *htmlc); 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); diff --git a/render/html_redraw.c b/render/html_redraw.c index e58918d81..598e613ca 100644 --- a/render/html_redraw.c +++ b/render/html_redraw.c @@ -344,852 +344,6 @@ text_redraw(const char *utf8_text, return true; } -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 true if successful, false otherwise - */ - -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) { - 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; - - 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 - */ - -static 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 - */ - -static 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; -} - /** * Plot a checkbox. diff --git a/render/html_redraw_border.c b/render/html_redraw_border.c new file mode 100644 index 000000000..07c503c41 --- /dev/null +++ b/render/html_redraw_border.c @@ -0,0 +1,928 @@ +/* + * Copyright 2017 Vincent Sanders + * + * 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 . + */ + +/** + * \file + * + * Redrawing CONTENT_HTML borders implementation. + */ + +#include +#include + +#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; +} -- cgit v1.2.3 From 7d660561cc9562731429ca06904b5e5711e90e27 Mon Sep 17 00:00:00 2001 From: Vincent Sanders Date: Sat, 11 Feb 2017 13:47:39 +0000 Subject: Update knockout plotter to use new API --- content/content.c | 2 +- desktop/browser.c | 4 +- desktop/knockout.c | 745 ++++++++++++++++++++++++++++++++--------------------- desktop/knockout.h | 14 +- desktop/treeview.c | 2 +- 5 files changed, 475 insertions(+), 292 deletions(-) diff --git a/content/content.c b/content/content.c index 2719db851..70df87e14 100644 --- a/content/content.c +++ b/content/content.c @@ -628,7 +628,7 @@ bool content_scaled_redraw(struct hlcache_handle *h, plot_ok &= c->handler->redraw(c, &data, &clip, &new_ctx); if (ctx->plot->option_knockout) { - knockout_plot_end(); + knockout_plot_end(ctx); } return plot_ok; diff --git a/desktop/browser.c b/desktop/browser.c index 442208c1b..3a7ac0ecc 100644 --- a/desktop/browser.c +++ b/desktop/browser.c @@ -238,7 +238,7 @@ bool browser_window_redraw(struct browser_window *bw, int x, int y, */ if (bw->window != NULL && ctx->plot->option_knockout) { /* Root browser window: knockout end */ - knockout_plot_end(); + knockout_plot_end(ctx); } return plot_ok; @@ -314,7 +314,7 @@ bool browser_window_redraw(struct browser_window *bw, int x, int y, if (bw->window != NULL && ctx->plot->option_knockout) { /* Root browser window: end knockout */ - knockout_plot_end(); + knockout_plot_end(ctx); } return plot_ok; diff --git a/desktop/knockout.c b/desktop/knockout.c index bcfc272eb..96e7b1a45 100644 --- a/desktop/knockout.c +++ b/desktop/knockout.c @@ -16,8 +16,9 @@ * along with this program. If not, see . */ -/** \file - * Knockout rendering (implementation). +/** + * \file + * Knockout rendering implementation. * * Knockout rendering is an optimisation which is particularly for * unaccelerated screen redraw. It tries to avoid plotting the same area more @@ -86,47 +87,6 @@ struct knockout_box; struct knockout_entry; - -static void knockout_calculate(int x0, int y0, int x1, int y1, struct knockout_box *box); -static bool knockout_plot_fill_recursive(struct knockout_box *box, plot_style_t *plot_style); -static bool knockout_plot_bitmap_recursive(struct knockout_box *box, - struct knockout_entry *entry); - -static bool knockout_plot_line(int x0, int y0, int x1, int y1, const plot_style_t *pstyle); -static bool knockout_plot_polygon(const int *p, unsigned int n, const plot_style_t *pstyle); -static bool knockout_plot_rectangle(int x0, int y0, int x1, int y1, const plot_style_t *plot_style); -static bool knockout_plot_clip(const struct rect *clip); -static bool knockout_plot_text(int x, int y, const char *text, size_t length, - const plot_font_style_t *fstyle); -static bool knockout_plot_disc(int x, int y, int radius, const plot_style_t *pstyle); -static bool knockout_plot_arc(int x, int y, int radius, int angle1, int angle2, const plot_style_t *pstyle); -static bool knockout_plot_bitmap(int x, int y, int width, int height, - struct bitmap *bitmap, colour bg, - bitmap_flags_t flags); -static bool knockout_plot_flush(void); -static bool knockout_plot_group_start(const char *name); -static bool knockout_plot_group_end(void); -static bool knockout_plot_path(const float *p, unsigned int n, colour fill, - float width, colour c, const float transform[6]); - - -const struct plotter_table knockout_plotters = { - .rectangle = knockout_plot_rectangle, - .line = knockout_plot_line, - .polygon = knockout_plot_polygon, - .clip = knockout_plot_clip, - .text = knockout_plot_text, - .disc = knockout_plot_disc, - .arc = knockout_plot_arc, - .bitmap = knockout_plot_bitmap, - .group_start = knockout_plot_group_start, - .group_end = knockout_plot_group_end, - .flush = knockout_plot_flush, - .path = knockout_plot_path, - .option_knockout = true, -}; - - typedef enum { KNOCKOUT_PLOT_RECTANGLE, KNOCKOUT_PLOT_LINE, @@ -155,17 +115,11 @@ struct knockout_entry { struct knockout_box *box; /* relating series of knockout clips */ union { struct { - int x0; - int y0; - int x1; - int y1; + struct rect r; plot_style_t plot_style; } rectangle; struct { - int x0; - int y0; - int x1; - int y1; + struct rect l; plot_style_t plot_style; } line; struct { @@ -174,10 +128,7 @@ struct knockout_entry { plot_style_t plot_style; } polygon; struct { - int x0; - int y0; - int x1; - int y1; + struct rect r; plot_style_t plot_style; } fill; struct rect clip; @@ -231,64 +182,88 @@ static struct plotter_table real_plot; static struct rect clip_cur; static int nested_depth = 0; + /** - * Start a knockout plotting session - * - * \param ctx the redraw context with real plotter table - * \param knk_ctx updated to copy of ctx, with plotter table replaced - * \return true on success, false otherwise + * fill an area recursively */ -bool knockout_plot_start(const struct redraw_context *ctx, - struct redraw_context *knk_ctx) +static nserror +knockout_plot_fill_recursive(const struct redraw_context *ctx, + struct knockout_box *box, + plot_style_t *plot_style) { - /* check if we're recursing */ - if (nested_depth++ > 0) { - /* we should already have the knockout renderer as default */ - assert(ctx->plot->rectangle == knockout_plotters.rectangle); - *knk_ctx = *ctx; - return true; - } - - /* end any previous sessions */ - if (knockout_entry_cur > 0) - knockout_plot_end(); - - /* get copy of real plotter table */ - real_plot = *(ctx->plot); + struct knockout_box *parent; + nserror res; + nserror ffres = NSERROR_OK; /* first failing result */ - /* set up knockout rendering context */ - *knk_ctx = *ctx; - knk_ctx->plot = &knockout_plotters; - return true; + for (parent = box; parent; parent = parent->next) { + if (parent->deleted) + continue; + if (parent->child) { + res = knockout_plot_fill_recursive(ctx, + parent->child, + plot_style); + } else { + res = real_plot.rectangle(ctx, plot_style, &parent->bbox); + } + /* remember the first error */ + if ((res != NSERROR_OK) && (ffres == NSERROR_OK)) { + ffres = res; + } + } + return ffres; } /** - * End a knockout plotting session - * - * \return true on success, false otherwise + * bitmap plot recusivley */ -bool knockout_plot_end(void) +static nserror +knockout_plot_bitmap_recursive(const struct redraw_context *ctx, + struct knockout_box *box, + struct knockout_entry *entry) { - /* only output when we've finished any nesting */ - if (--nested_depth == 0) - return knockout_plot_flush(); + nserror res; + nserror ffres = NSERROR_OK; /* first failing result */ + struct knockout_box *parent; - assert(nested_depth > 0); - return true; -} + for (parent = box; parent; parent = parent->next) { + if (parent->deleted) + continue; + if (parent->child) { + res = knockout_plot_bitmap_recursive(ctx, + parent->child, + entry); + } else { + real_plot.clip(ctx, &parent->bbox); + res = real_plot.bitmap(ctx, + entry->data.bitmap.bitmap, + entry->data.bitmap.x, + entry->data.bitmap.y, + entry->data.bitmap.width, + entry->data.bitmap.height, + entry->data.bitmap.bg, + entry->data.bitmap.flags); + } + /* remember the first error */ + if ((res != NSERROR_OK) && (ffres == NSERROR_OK)) { + ffres = res; + } + } + return ffres; +} /** * Flush the current knockout session to empty the buffers * * \return true on success, false otherwise */ -bool knockout_plot_flush(void) +static nserror knockout_plot_flush(const struct redraw_context *ctx) { int i; - bool success = true; struct knockout_box *box; + nserror res; /* operation result */ + nserror ffres = NSERROR_OK; /* first failing result */ /* debugging information */ #ifdef KNOCKOUT_DEBUG @@ -298,99 +273,100 @@ bool knockout_plot_flush(void) for (i = 0; i < knockout_entry_cur; i++) { switch (knockout_entries[i].type) { case KNOCKOUT_PLOT_RECTANGLE: - success &= real_plot.rectangle( - knockout_entries[i].data.rectangle.x0, - knockout_entries[i].data.rectangle.y0, - knockout_entries[i].data.rectangle.x1, - knockout_entries[i].data.rectangle.y1, - &knockout_entries[i].data.rectangle.plot_style); + res = real_plot.rectangle(ctx, + &knockout_entries[i].data.rectangle.plot_style, + &knockout_entries[i].data.rectangle.r); break; + case KNOCKOUT_PLOT_LINE: - success &= real_plot.line( - knockout_entries[i].data.line.x0, - knockout_entries[i].data.line.y0, - knockout_entries[i].data.line.x1, - knockout_entries[i].data.line.y1, - &knockout_entries[i].data.line.plot_style); + res = real_plot.line(ctx, + &knockout_entries[i].data.line.plot_style, + &knockout_entries[i].data.line.l); break; + case KNOCKOUT_PLOT_POLYGON: - success &= real_plot.polygon( - knockout_entries[i].data.polygon.p, - knockout_entries[i].data.polygon.n, - &knockout_entries[i].data.polygon.plot_style); + res = real_plot.polygon(ctx, + &knockout_entries[i].data.polygon.plot_style, + knockout_entries[i].data.polygon.p, + knockout_entries[i].data.polygon.n); break; + case KNOCKOUT_PLOT_FILL: box = knockout_entries[i].box->child; - if (box) - success &= knockout_plot_fill_recursive(box, - &knockout_entries[i].data.fill.plot_style); - else if (!knockout_entries[i].box->deleted) - success &= real_plot.rectangle( - knockout_entries[i].data.fill.x0, - knockout_entries[i].data.fill.y0, - knockout_entries[i].data.fill.x1, - knockout_entries[i].data.fill.y1, - &knockout_entries[i].data.fill.plot_style); + if (box) { + res = knockout_plot_fill_recursive(ctx, + box, + &knockout_entries[i].data.fill.plot_style); + } else if (!knockout_entries[i].box->deleted) { + res = real_plot.rectangle(ctx, + &knockout_entries[i].data.fill.plot_style, + &knockout_entries[i].data.fill.r); + } break; + case KNOCKOUT_PLOT_CLIP: - success &= real_plot.clip( - &knockout_entries[i].data.clip); + res = real_plot.clip(ctx, &knockout_entries[i].data.clip); break; + case KNOCKOUT_PLOT_TEXT: - success &= real_plot.text( + res = real_plot.text(ctx, + &knockout_entries[i].data.text.font_style, knockout_entries[i].data.text.x, knockout_entries[i].data.text.y, knockout_entries[i].data.text.text, - knockout_entries[i].data.text.length, - &knockout_entries[i].data.text.font_style); + knockout_entries[i].data.text.length); break; + case KNOCKOUT_PLOT_DISC: - success &= real_plot.disc( + res = real_plot.disc(ctx, + &knockout_entries[i].data.disc.plot_style, knockout_entries[i].data.disc.x, knockout_entries[i].data.disc.y, - knockout_entries[i].data.disc.radius, - &knockout_entries[i].data.disc.plot_style); + knockout_entries[i].data.disc.radius); break; + case KNOCKOUT_PLOT_ARC: - success &= real_plot.arc( + res = real_plot.arc(ctx, + &knockout_entries[i].data.arc.plot_style, knockout_entries[i].data.arc.x, knockout_entries[i].data.arc.y, knockout_entries[i].data.arc.radius, knockout_entries[i].data.arc.angle1, - knockout_entries[i].data.arc.angle2, - &knockout_entries[i].data.arc.plot_style); + knockout_entries[i].data.arc.angle2); break; + case KNOCKOUT_PLOT_BITMAP: box = knockout_entries[i].box->child; if (box) { - success &= knockout_plot_bitmap_recursive(box, + res = knockout_plot_bitmap_recursive(ctx, + box, &knockout_entries[i]); } else if (!knockout_entries[i].box->deleted) { - success &= real_plot.bitmap( - knockout_entries[i].data. - bitmap.x, - knockout_entries[i].data. - bitmap.y, - knockout_entries[i].data. - bitmap.width, - knockout_entries[i].data. - bitmap.height, - knockout_entries[i].data. - bitmap.bitmap, - knockout_entries[i].data. - bitmap.bg, - knockout_entries[i].data. - bitmap.flags); + res = real_plot.bitmap(ctx, + knockout_entries[i].data.bitmap.bitmap, + knockout_entries[i].data.bitmap.x, + knockout_entries[i].data.bitmap.y, + knockout_entries[i].data.bitmap.width, + knockout_entries[i].data.bitmap.height, + knockout_entries[i].data.bitmap.bg, + knockout_entries[i].data.bitmap.flags); } break; + case KNOCKOUT_PLOT_GROUP_START: - success &= real_plot.group_start( - knockout_entries[i].data.group_start.name); + res = real_plot.group_start(ctx, + knockout_entries[i].data.group_start.name); break; + case KNOCKOUT_PLOT_GROUP_END: - success &= real_plot.group_end(); + res = real_plot.group_end(ctx); break; } + + /* remember the first error */ + if ((res != NSERROR_OK) && (ffres == NSERROR_OK)) { + ffres = res; + } } knockout_entry_cur = 0; @@ -398,7 +374,7 @@ bool knockout_plot_flush(void) knockout_polygon_cur = 0; knockout_list = NULL; - return success; + return ffres; } @@ -410,8 +386,11 @@ bool knockout_plot_flush(void) * \param x1 The right edge of the removal box * \param y1 The top edge of the removal box * \param owner The parent box set to consider, or NULL for top level -*/ -void knockout_calculate(int x0, int y0, int x1, int y1, struct knockout_box *owner) + */ +static void +knockout_calculate(const struct redraw_context *ctx, + int x0, int y0, int x1, int y1, + struct knockout_box *owner) { struct knockout_box *box; struct knockout_box *parent; @@ -464,11 +443,11 @@ void knockout_calculate(int x0, int y0, int x1, int y1, struct knockout_box *own /* has the box been replaced by children? */ if (parent->child) { - knockout_calculate(x0, y0, x1, y1, parent); + knockout_calculate(ctx, x0, y0, x1, y1, parent); } else { /* we need a maximum of 4 child boxes */ if (knockout_box_cur + 4 >= KNOCKOUT_BOXES) { - knockout_plot_flush(); + knockout_plot_flush(ctx); return; } @@ -527,136 +506,134 @@ void knockout_calculate(int x0, int y0, int x1, int y1, struct knockout_box *own } -bool knockout_plot_fill_recursive(struct knockout_box *box, plot_style_t *plot_style) -{ - bool success = true; - struct knockout_box *parent; - - for (parent = box; parent; parent = parent->next) { - if (parent->deleted) - continue; - if (parent->child) - knockout_plot_fill_recursive(parent->child, plot_style); - else - success &= real_plot.rectangle(parent->bbox.x0, - parent->bbox.y0, - parent->bbox.x1, - parent->bbox.y1, - plot_style); - } - return success; -} - - -bool knockout_plot_bitmap_recursive(struct knockout_box *box, - struct knockout_entry *entry) -{ - bool success = true; - struct knockout_box *parent; - - for (parent = box; parent; parent = parent->next) { - if (parent->deleted) - continue; - if (parent->child) - knockout_plot_bitmap_recursive(parent->child, entry); - else { - success &= real_plot.clip(&parent->bbox); - success &= real_plot.bitmap(entry->data.bitmap.x, - entry->data.bitmap.y, - entry->data.bitmap.width, - entry->data.bitmap.height, - entry->data.bitmap.bitmap, - entry->data.bitmap.bg, - entry->data.bitmap.flags); - } - } - return success; -} - -bool knockout_plot_rectangle(int x0, int y0, int x1, int y1, const plot_style_t *pstyle) +/** + * knockout rectangle plotting. + * + * The rectangle can be filled an outline or both controlled + * by the plot style The line can be solid, dotted or + * dashed. Top left corner at (x0,y0) and rectangle has given + * width and height. + * + * \param ctx The current redraw context. + * \param pstyle Style controlling the rectangle plot. + * \return NSERROR_OK on success else error code. + */ +static nserror +knockout_plot_rectangle(const struct redraw_context *ctx, + const plot_style_t *pstyle, + const struct rect *rect) { int kx0, ky0, kx1, ky1; + nserror res = NSERROR_OK; - if (pstyle->fill_type != PLOT_OP_TYPE_NONE) { + if (pstyle->fill_type != PLOT_OP_TYPE_NONE) { /* filled draw */ /* get our bounds */ - kx0 = (x0 > clip_cur.x0) ? x0 : clip_cur.x0; - ky0 = (y0 > clip_cur.y0) ? y0 : clip_cur.y0; - kx1 = (x1 < clip_cur.x1) ? x1 : clip_cur.x1; - ky1 = (y1 < clip_cur.y1) ? y1 : clip_cur.y1; + kx0 = (rect->x0 > clip_cur.x0) ? rect->x0 : clip_cur.x0; + ky0 = (rect->y0 > clip_cur.y0) ? rect->y0 : clip_cur.y0; + kx1 = (rect->x1 < clip_cur.x1) ? rect->x1 : clip_cur.x1; + ky1 = (rect->y1 < clip_cur.y1) ? rect->y1 : clip_cur.y1; if ((kx0 > clip_cur.x1) || (kx1 < clip_cur.x0) || - (ky0 > clip_cur.y1) || (ky1 < clip_cur.y0)) - return true; + (ky0 > clip_cur.y1) || (ky1 < clip_cur.y0)) { + return NSERROR_OK; + } /* fills both knock out and get knocked out */ - knockout_calculate(kx0, ky0, kx1, ky1, NULL); - knockout_boxes[knockout_box_cur].bbox.x0 = x0; - knockout_boxes[knockout_box_cur].bbox.y0 = y0; - knockout_boxes[knockout_box_cur].bbox.x1 = x1; - knockout_boxes[knockout_box_cur].bbox.y1 = y1; + knockout_calculate(ctx, kx0, ky0, kx1, ky1, NULL); + knockout_boxes[knockout_box_cur].bbox = *rect; knockout_boxes[knockout_box_cur].deleted = false; knockout_boxes[knockout_box_cur].child = NULL; knockout_boxes[knockout_box_cur].next = knockout_list; knockout_list = &knockout_boxes[knockout_box_cur]; knockout_entries[knockout_entry_cur].box = &knockout_boxes[knockout_box_cur]; - knockout_entries[knockout_entry_cur].data.fill.x0 = x0; - knockout_entries[knockout_entry_cur].data.fill.y0 = y0; - knockout_entries[knockout_entry_cur].data.fill.x1 = x1; - knockout_entries[knockout_entry_cur].data.fill.y1 = y1; + knockout_entries[knockout_entry_cur].data.fill.r = *rect; knockout_entries[knockout_entry_cur].data.fill.plot_style = *pstyle; knockout_entries[knockout_entry_cur].data.fill.plot_style.stroke_type = PLOT_OP_TYPE_NONE; /* ensure we only plot the fill */ knockout_entries[knockout_entry_cur].type = KNOCKOUT_PLOT_FILL; if ((++knockout_entry_cur >= KNOCKOUT_ENTRIES) || - (++knockout_box_cur >= KNOCKOUT_BOXES)) - knockout_plot_flush(); - } + (++knockout_box_cur >= KNOCKOUT_BOXES)) { + res = knockout_plot_flush(ctx); + } + } if (pstyle->stroke_type != PLOT_OP_TYPE_NONE) { /* draw outline */ - knockout_entries[knockout_entry_cur].data.rectangle.x0 = x0; - knockout_entries[knockout_entry_cur].data.rectangle.y0 = y0; - knockout_entries[knockout_entry_cur].data.rectangle.x1 = x1; - knockout_entries[knockout_entry_cur].data.rectangle.y1 = y1; + knockout_entries[knockout_entry_cur].data.rectangle.r = *rect; knockout_entries[knockout_entry_cur].data.fill.plot_style = *pstyle; knockout_entries[knockout_entry_cur].data.fill.plot_style.fill_type = PLOT_OP_TYPE_NONE; /* ensure we only plot the outline */ knockout_entries[knockout_entry_cur].type = KNOCKOUT_PLOT_RECTANGLE; - if (++knockout_entry_cur >= KNOCKOUT_ENTRIES) - knockout_plot_flush(); - } - return true; + if (++knockout_entry_cur >= KNOCKOUT_ENTRIES) { + res = knockout_plot_flush(ctx); + } + } + return res; } -bool knockout_plot_line(int x0, int y0, int x1, int y1, const plot_style_t *pstyle) + +/** + * Knockout line plotting. + * + * plot a line from (x0,y0) to (x1,y1). Coordinates are at centre of + * line width/thickness. + * + * \param ctx The current redraw context. + * \param pstyle Style controlling the line plot. + * \return NSERROR_OK on success else error code. + */ +static nserror +knockout_plot_line(const struct redraw_context *ctx, + const plot_style_t *pstyle, + const struct rect *line) { - knockout_entries[knockout_entry_cur].data.line.x0 = x0; - knockout_entries[knockout_entry_cur].data.line.y0 = y0; - knockout_entries[knockout_entry_cur].data.line.x1 = x1; - knockout_entries[knockout_entry_cur].data.line.y1 = y1; + knockout_entries[knockout_entry_cur].data.line.l = *line; knockout_entries[knockout_entry_cur].data.line.plot_style = *pstyle; knockout_entries[knockout_entry_cur].type = KNOCKOUT_PLOT_LINE; - if (++knockout_entry_cur >= KNOCKOUT_ENTRIES) - knockout_plot_flush(); - return true; + if (++knockout_entry_cur >= KNOCKOUT_ENTRIES) { + return knockout_plot_flush(ctx); + } + return NSERROR_OK; } -bool knockout_plot_polygon(const int *p, unsigned int n, const plot_style_t *pstyle) +/** + * Knockout polygon plotting. + * + * Plots a filled polygon with straight lines between + * points. The lines around the edge of the ploygon are not + * plotted. The polygon is filled with the non-zero winding + * rule. + * + * \param ctx The current redraw context. + * \param pstyle Style controlling the polygon plot. + * \return NSERROR_OK on success else error code. + */ +static nserror +knockout_plot_polygon(const struct redraw_context *ctx, + const plot_style_t *pstyle, + const int *p, + unsigned int n) { - bool success = true; int *dest; + nserror res; + nserror ffres = NSERROR_OK; /* ensure we have sufficient room even when flushed */ if (n * 2 >= KNOCKOUT_POLYGONS) { - knockout_plot_flush(); - success = real_plot.polygon(p, n, pstyle); - return success; + ffres = knockout_plot_flush(ctx); + res = real_plot.polygon(ctx, pstyle, p, n); + /* return the first error */ + if ((res != NSERROR_OK) && (ffres == NSERROR_OK)) { + ffres = res; + } + return ffres; } /* ensure we have enough room right now */ - if (knockout_polygon_cur + n * 2 >= KNOCKOUT_POLYGONS) - knockout_plot_flush(); + if (knockout_polygon_cur + n * 2 >= KNOCKOUT_POLYGONS) { + ffres = knockout_plot_flush(ctx); + } /* copy our data */ dest = &(knockout_polygons[knockout_polygon_cur]); @@ -666,27 +643,64 @@ bool knockout_plot_polygon(const int *p, unsigned int n, const plot_style_t *pst knockout_entries[knockout_entry_cur].data.polygon.n = n; knockout_entries[knockout_entry_cur].data.polygon.plot_style = *pstyle; knockout_entries[knockout_entry_cur].type = KNOCKOUT_PLOT_POLYGON; - if (++knockout_entry_cur >= KNOCKOUT_ENTRIES) - knockout_plot_flush(); - return true; + if (++knockout_entry_cur >= KNOCKOUT_ENTRIES) { + res = knockout_plot_flush(ctx); + } + /* return the first error */ + if ((res != NSERROR_OK) && (ffres == NSERROR_OK)) { + ffres = res; + } + return ffres; } -bool knockout_plot_path(const float *p, unsigned int n, colour fill, - float width, colour c, const float transform[6]) +/** + * knockout path plotting. + * + * The knockout implementation simply flushes the queue and plots the path + * directly using real plotter. + * + * \param ctx The current redraw context. + * \param pstyle Style controlling the path plot. + * \param p elements of path + * \param n nunber of elements on path + * \param width The width of the path + * \param transform A transform to apply to the path. + * \return NSERROR_OK on success else error code. + */ +static nserror +knockout_plot_path(const struct redraw_context *ctx, + const plot_style_t *pstyle, + const float *p, + unsigned int n, + float width, + const float transform[6]) { - knockout_plot_flush(); - return real_plot.path(p, n, fill, width, c, transform); + nserror res; + nserror ffres; + + ffres = knockout_plot_flush(ctx); + res = real_plot.path(ctx, pstyle, p, n, width, transform); + + /* return the first error */ + if ((res != NSERROR_OK) && (ffres == NSERROR_OK)) { + ffres = res; + } + return ffres; } -bool knockout_plot_clip(const struct rect *clip) +static nserror +knockout_plot_clip(const struct redraw_context *ctx, const struct rect *clip) { + nserror res = NSERROR_OK; + if (clip->x1 < clip->x0 || clip->y0 > clip->y1) { #ifdef KNOCKOUT_DEBUG - LOG("bad clip rectangle %i %i %i %i", clip->x0, clip->y0, clip->x1, clip->y1); + LOG("bad clip rectangle %i %i %i %i", + clip->x0, clip->y0, clip->x1, clip->y1); #endif - return false; + return NSERROR_BAD_SIZE; } /* memorise clip for bitmap tiling */ @@ -694,41 +708,97 @@ bool knockout_plot_clip(const struct rect *clip) knockout_entries[knockout_entry_cur].data.clip = *clip; knockout_entries[knockout_entry_cur].type = KNOCKOUT_PLOT_CLIP; - if (++knockout_entry_cur >= KNOCKOUT_ENTRIES) - knockout_plot_flush(); - return true; + if (++knockout_entry_cur >= KNOCKOUT_ENTRIES) { + res = knockout_plot_flush(ctx); + } + return res; } -bool knockout_plot_text(int x, int y, const char *text, size_t length, - const plot_font_style_t *fstyle) +/** + * Text plotting. + * + * \param ctx The current redraw context. + * \param fstyle plot style for this text + * \param x x coordinate + * \param y y coordinate + * \param text UTF-8 string to plot + * \param length length of string, in bytes + * \return NSERROR_OK on success else error code. + */ +static nserror +knockout_plot_text(const struct redraw_context *ctx, + const plot_font_style_t *fstyle, + int x, + int y, + const char *text, + size_t length) { + nserror res = NSERROR_OK; + knockout_entries[knockout_entry_cur].data.text.x = x; knockout_entries[knockout_entry_cur].data.text.y = y; knockout_entries[knockout_entry_cur].data.text.text = text; knockout_entries[knockout_entry_cur].data.text.length = length; knockout_entries[knockout_entry_cur].data.text.font_style = *fstyle; knockout_entries[knockout_entry_cur].type = KNOCKOUT_PLOT_TEXT; - if (++knockout_entry_cur >= KNOCKOUT_ENTRIES) - knockout_plot_flush(); - return true; + if (++knockout_entry_cur >= KNOCKOUT_ENTRIES) { + res = knockout_plot_flush(ctx); + } + return res; } -bool knockout_plot_disc(int x, int y, int radius, const plot_style_t *pstyle) +/** + * Plots a circle + * + * Plot a circle centered on (x,y), which is optionally filled. + * + * \param ctx The current redraw context. + * \return NSERROR_OK on success else error code. + */ +static nserror +knockout_plot_disc(const struct redraw_context *ctx, + const plot_style_t *pstyle, + int x, + int y, + int radius) { + nserror res = NSERROR_OK; + knockout_entries[knockout_entry_cur].data.disc.x = x; knockout_entries[knockout_entry_cur].data.disc.y = y; knockout_entries[knockout_entry_cur].data.disc.radius = radius; knockout_entries[knockout_entry_cur].data.disc.plot_style = *pstyle; knockout_entries[knockout_entry_cur].type = KNOCKOUT_PLOT_DISC; - if (++knockout_entry_cur >= KNOCKOUT_ENTRIES) - knockout_plot_flush(); - return true; + if (++knockout_entry_cur >= KNOCKOUT_ENTRIES) { + res = knockout_plot_flush(ctx); + } + return res; } -bool knockout_plot_arc(int x, int y, int radius, int angle1, int angle2, const plot_style_t *pstyle) + +/** + * Plots an arc + * + * plot an arc segment around (x,y), anticlockwise from angle1 + * to angle2. Angles are measured anticlockwise from + * horizontal, in degrees. + * + * \param ctx The current redraw context. + * \return NSERROR_OK on success else error code. + */ +static nserror +knockout_plot_arc(const struct redraw_context *ctx, + const plot_style_t *pstyle, + int x, + int y, + int radius, + int angle1, + int angle2) { + nserror res = NSERROR_OK; + knockout_entries[knockout_entry_cur].data.arc.x = x; knockout_entries[knockout_entry_cur].data.arc.y = y; knockout_entries[knockout_entry_cur].data.arc.radius = radius; @@ -736,18 +806,41 @@ bool knockout_plot_arc(int x, int y, int radius, int angle1, int angle2, const p knockout_entries[knockout_entry_cur].data.arc.angle2 = angle2; knockout_entries[knockout_entry_cur].data.arc.plot_style = *pstyle; knockout_entries[knockout_entry_cur].type = KNOCKOUT_PLOT_ARC; - if (++knockout_entry_cur >= KNOCKOUT_ENTRIES) - knockout_plot_flush(); - return true; + if (++knockout_entry_cur >= KNOCKOUT_ENTRIES) { + res = knockout_plot_flush(ctx); + } + return res; } - -bool knockout_plot_bitmap(int x, int y, int width, int height, - struct bitmap *bitmap, colour bg, - bitmap_flags_t flags) +/** + * knockout bitmap plotting. + * + * Tiled plot of a bitmap image. (x,y) gives the top left + * coordinate of an explicitly placed tile. From this tile the + * image can repeat in all four directions -- up, down, left + * and right -- to the extents given by the current clip + * rectangle. + * + * The bitmap_flags say whether to tile in the x and y + * directions. If not tiling in x or y directions, the single + * image is plotted. The width and height give the dimensions + * the image is to be scaled to. + * + * \param ctx The current redraw context. + * \return NSERROR_OK on success else error code. + */ +static nserror +knockout_plot_bitmap(const struct redraw_context *ctx, + struct bitmap *bitmap, + int x, int y, + int width, int height, + colour bg, + bitmap_flags_t flags) { int kx0, ky0, kx1, ky1; + nserror res; + nserror ffres = NSERROR_OK; /* get our bounds */ kx0 = clip_cur.x0; @@ -760,7 +853,7 @@ bool knockout_plot_bitmap(int x, int y, int width, int height, if (x + width < kx1) kx1 = x + width; if ((kx0 > clip_cur.x1) || (kx1 < clip_cur.x0)) - return true; + return NSERROR_OK; } if (!(flags & BITMAPF_REPEAT_Y)) { if (y > ky0) @@ -768,12 +861,12 @@ bool knockout_plot_bitmap(int x, int y, int width, int height, if (y + height < ky1) ky1 = y + height; if ((ky0 > clip_cur.y1) || (ky1 < clip_cur.y0)) - return true; + return NSERROR_OK; } /* tiled bitmaps both knock out and get knocked out */ if (guit->bitmap->get_opaque(bitmap)) { - knockout_calculate(kx0, ky0, kx1, ky1, NULL); + knockout_calculate(ctx, kx0, ky0, kx1, ky1, NULL); } knockout_boxes[knockout_box_cur].bbox.x0 = kx0; knockout_boxes[knockout_box_cur].bbox.y0 = ky0; @@ -792,33 +885,111 @@ bool knockout_plot_bitmap(int x, int y, int width, int height, knockout_entries[knockout_entry_cur].data.bitmap.bg = bg; knockout_entries[knockout_entry_cur].data.bitmap.flags = flags; knockout_entries[knockout_entry_cur].type = KNOCKOUT_PLOT_BITMAP; + if ((++knockout_entry_cur >= KNOCKOUT_ENTRIES) || - (++knockout_box_cur >= KNOCKOUT_BOXES)) - knockout_plot_flush(); - return knockout_plot_clip(&clip_cur); + (++knockout_box_cur >= KNOCKOUT_BOXES)) { + ffres = knockout_plot_flush(ctx); + } + res = knockout_plot_clip(ctx, &clip_cur); + /* return the first error */ + if ((res != NSERROR_OK) && (ffres == NSERROR_OK)) { + ffres = res; + } + return ffres; } -bool knockout_plot_group_start(const char *name) + +/** + * Start of a group of objects. + * + * Used when plotter implements export to a vector graphics file format. + * + * \param ctx The current redraw context. + * \return NSERROR_OK on success else error code. + */ +static nserror +knockout_plot_group_start(const struct redraw_context *ctx, const char *name) { if (real_plot.group_start == NULL) { - return true; + return NSERROR_OK; } knockout_entries[knockout_entry_cur].data.group_start.name = name; knockout_entries[knockout_entry_cur].type = KNOCKOUT_PLOT_GROUP_START; - if (++knockout_entry_cur >= KNOCKOUT_ENTRIES) - knockout_plot_flush(); - return true; + if (++knockout_entry_cur >= KNOCKOUT_ENTRIES) { + return knockout_plot_flush(ctx); + } + return NSERROR_OK; } -bool knockout_plot_group_end(void) + +static nserror knockout_plot_group_end(const struct redraw_context *ctx) { if (real_plot.group_end == NULL) { - return true; + return NSERROR_OK; } knockout_entries[knockout_entry_cur].type = KNOCKOUT_PLOT_GROUP_END; - if (++knockout_entry_cur >= KNOCKOUT_ENTRIES) - knockout_plot_flush(); + if (++knockout_entry_cur >= KNOCKOUT_ENTRIES) { + return knockout_plot_flush(ctx); + } + return NSERROR_OK; +} + +/* exported functions documented in desktop/knockout.h */ +bool knockout_plot_start(const struct redraw_context *ctx, + struct redraw_context *knk_ctx) +{ + /* check if we're recursing */ + if (nested_depth++ > 0) { + /* we should already have the knockout renderer as default */ + assert(ctx->plot->rectangle == knockout_plotters.rectangle); + *knk_ctx = *ctx; + return true; + } + + /* end any previous sessions */ + if (knockout_entry_cur > 0) + knockout_plot_end(ctx); + + /* get copy of real plotter table */ + real_plot = *(ctx->plot); + + /* set up knockout rendering context */ + *knk_ctx = *ctx; + knk_ctx->plot = &knockout_plotters; return true; } + + +/* exported functions documented in desktop/knockout.h */ +bool knockout_plot_end(const struct redraw_context *ctx) +{ + /* only output when we've finished any nesting */ + if (--nested_depth == 0) { + return knockout_plot_flush(ctx); + } + + assert(nested_depth > 0); + return true; +} + + +/** + * knockout plotter operation table + */ +const struct plotter_table knockout_plotters = { + .rectangle = knockout_plot_rectangle, + .line = knockout_plot_line, + .polygon = knockout_plot_polygon, + .clip = knockout_plot_clip, + .text = knockout_plot_text, + .disc = knockout_plot_disc, + .arc = knockout_plot_arc, + .bitmap = knockout_plot_bitmap, + .group_start = knockout_plot_group_start, + .group_end = knockout_plot_group_end, + .flush = knockout_plot_flush, + .path = knockout_plot_path, + .option_knockout = true, +}; diff --git a/desktop/knockout.h b/desktop/knockout.h index c4f1245fc..f7ff04553 100644 --- a/desktop/knockout.h +++ b/desktop/knockout.h @@ -26,9 +26,21 @@ #include "netsurf/plotters.h" +/** + * Start a knockout plotting session + * + * \param ctx the redraw context with real plotter table + * \param knk_ctx updated to copy of ctx, with plotter table replaced + * \return true on success, false otherwise + */ bool knockout_plot_start(const struct redraw_context *ctx, struct redraw_context *knk_ctx); -bool knockout_plot_end(void); +/** + * End a knockout plotting session + * + * \return true on success, false otherwise + */ +bool knockout_plot_end(const struct redraw_context *ctx); extern const struct plotter_table knockout_plotters; diff --git a/desktop/treeview.c b/desktop/treeview.c index 541852d86..75e5c93e0 100644 --- a/desktop/treeview.c +++ b/desktop/treeview.c @@ -2042,7 +2042,7 @@ void treeview_redraw(treeview *tree, const int x, const int y, /* Rendering complete */ if (ctx->plot->option_knockout) { - knockout_plot_end(); + knockout_plot_end(ctx); } } -- cgit v1.2.3 From 78d601eb76c796c038f42c2b9f10e4e591272271 Mon Sep 17 00:00:00 2001 From: Vincent Sanders Date: Mon, 6 Feb 2017 00:37:08 +0000 Subject: Update GTK plotters to use new API --- frontends/gtk/layout_pango.c | 6 +- frontends/gtk/layout_pango.h | 2 +- frontends/gtk/plotters.c | 409 ++++++++++++++++++++++++++++++------------- frontends/gtk/print.c | 197 +++++++++++++++++---- frontends/gtk/scaffolding.c | 2 +- 5 files changed, 457 insertions(+), 159 deletions(-) diff --git a/frontends/gtk/layout_pango.c b/frontends/gtk/layout_pango.c index 7c7190982..bad57d684 100644 --- a/frontends/gtk/layout_pango.c +++ b/frontends/gtk/layout_pango.c @@ -222,7 +222,7 @@ nsfont_split(const plot_font_style_t *fstyle, * \param fstyle plot style for this text * \return true on success, false on error and error reported */ -bool nsfont_paint(int x, int y, const char *string, size_t length, +nserror nsfont_paint(int x, int y, const char *string, size_t length, const plot_font_style_t *fstyle) { PangoFontDescription *desc; @@ -230,7 +230,7 @@ bool nsfont_paint(int x, int y, const char *string, size_t length, PangoLayoutLine *line; if (length == 0) - return true; + return NSERROR_OK; layout = pango_cairo_create_layout(current_cr); @@ -247,7 +247,7 @@ bool nsfont_paint(int x, int y, const char *string, size_t length, g_object_unref(layout); - return true; + return NSERROR_OK; } diff --git a/frontends/gtk/layout_pango.h b/frontends/gtk/layout_pango.h index 137cebe68..7ce107a5d 100644 --- a/frontends/gtk/layout_pango.h +++ b/frontends/gtk/layout_pango.h @@ -30,7 +30,7 @@ struct plot_font_style; extern struct gui_layout_table *nsgtk_layout_table; -bool nsfont_paint(int x, int y, const char *string, size_t length, const struct plot_font_style *fstyle); +nserror nsfont_paint(int x, int y, const char *string, size_t length, const struct plot_font_style *fstyle); /** * Convert a plot style to a PangoFontDescription. diff --git a/frontends/gtk/plotters.c b/frontends/gtk/plotters.c index 817b72808..54b3a896c 100644 --- a/frontends/gtk/plotters.c +++ b/frontends/gtk/plotters.c @@ -77,8 +77,17 @@ static inline void nsgtk_set_dashed(void) cairo_set_dash(current_cr, cdashes, 2, 0); } -/** Set clipping area for subsequent plot operations. */ -static bool nsgtk_plot_clip(const struct rect *clip) + +/** + * \brief Sets a clip rectangle for subsequent plot operations. + * + * \param ctx The current redraw context. + * \param clip The rectangle to limit all subsequent plot + * operations within. + * \return NSERROR_OK on success else error code. + */ +static nserror +nsgtk_plot_clip(const struct redraw_context *ctx, const struct rect *clip) { cairo_reset_clip(current_cr); cairo_rectangle(current_cr, clip->x0, clip->y0, @@ -90,11 +99,30 @@ static bool nsgtk_plot_clip(const struct rect *clip) cliprect.width = clip->x1 - clip->x0; cliprect.height = clip->y1 - clip->y0; - return true; + return NSERROR_OK; } -static bool nsgtk_plot_arc(int x, int y, int radius, int angle1, int angle2, const plot_style_t *style) +/** + * Plots an arc + * + * plot an arc segment around (x,y), anticlockwise from angle1 + * to angle2. Angles are measured anticlockwise from + * horizontal, in degrees. + * + * \param ctx The current redraw context. + * \param pstyle Style controlling the arc plot. + * \param x The x coordinate of the arc. + * \param y The y coordinate of the arc. + * \param radius The radius of the arc. + * \param angle1 The start angle of the arc. + * \param angle2 The finish angle of the arc. + * \return NSERROR_OK on success else error code. + */ +static nserror +nsgtk_plot_arc(const struct redraw_context *ctx, + const plot_style_t *style, + int x, int y, int radius, int angle1, int angle2) { nsgtk_set_colour(style->fill_colour); nsgtk_set_solid(); @@ -105,10 +133,26 @@ static bool nsgtk_plot_arc(int x, int y, int radius, int angle1, int angle2, con (angle2 + 90) * (M_PI / 180)); cairo_stroke(current_cr); - return true; + return NSERROR_OK; } -static bool nsgtk_plot_disc(int x, int y, int radius, const plot_style_t *style) + +/** + * Plots a circle + * + * Plot a circle centered on (x,y), which is optionally filled. + * + * \param ctx The current redraw context. + * \param pstyle Style controlling the circle plot. + * \param x x coordinate of circle centre. + * \param y y coordinate of circle centre. + * \param radius circle radius. + * \return NSERROR_OK on success else error code. + */ +static nserror +nsgtk_plot_disc(const struct redraw_context *ctx, + const plot_style_t *style, + int x, int y, int radius) { if (style->fill_type != PLOT_OP_TYPE_NONE) { nsgtk_set_colour(style->fill_colour); @@ -147,11 +191,25 @@ static bool nsgtk_plot_disc(int x, int y, int radius, const plot_style_t *style) cairo_stroke(current_cr); } - return true; + return NSERROR_OK; } -static bool -nsgtk_plot_line(int x0, int y0, int x1, int y1, const plot_style_t *style) + +/** + * Plots a line + * + * plot a line from (x0,y0) to (x1,y1). Coordinates are at + * centre of line width/thickness. + * + * \param ctx The current redraw context. + * \param pstyle Style controlling the line plot. + * \param line A rectangle defining the line to be drawn + * \return NSERROR_OK on success else error code. + */ +static nserror +nsgtk_plot_line(const struct redraw_context *ctx, + const plot_style_t *style, + const struct rect *line) { nsgtk_set_colour(style->stroke_colour); @@ -180,17 +238,22 @@ nsgtk_plot_line(int x0, int y0, int x1, int y1, const plot_style_t *style) cairo_set_line_width(current_cr, style->stroke_width); /* core expects horizontal and vertical lines to be on pixels, not - * between pixels */ - cairo_move_to(current_cr, (x0 == x1) ? x0 + 0.5 : x0, - (y0 == y1) ? y0 + 0.5 : y0); - cairo_line_to(current_cr, (x0 == x1) ? x1 + 0.5 : x1, - (y0 == y1) ? y1 + 0.5 : y1); + * between pixels + */ + cairo_move_to(current_cr, + (line->x0 == line->x1) ? line->x0 + 0.5 : line->x0, + (line->y0 == line->y1) ? line->y0 + 0.5 : line->y0); + cairo_line_to(current_cr, + (line->x0 == line->x1) ? line->x1 + 0.5 : line->x1, + (line->y0 == line->y1) ? line->y1 + 0.5 : line->y1); cairo_stroke(current_cr); - return true; + return NSERROR_OK; } -/** Plot a caret. + +/** + * Plot a caret. * * @note It is assumed that the plotters have been set up. */ @@ -207,14 +270,35 @@ void nsgtk_plot_caret(int x, int y, int h) cairo_stroke(current_cr); } -static bool nsgtk_plot_rectangle(int x0, int y0, int x1, int y1, const plot_style_t *style) + +/** + * Plots a rectangle. + * + * The rectangle can be filled an outline or both controlled + * by the plot style The line can be solid, dotted or + * dashed. Top left corner at (x0,y0) and rectangle has given + * width and height. + * + * \param ctx The current redraw context. + * \param pstyle Style controlling the rectangle plot. + * \param rect A rectangle defining the line to be drawn + * \return NSERROR_OK on success else error code. + */ +static nserror +nsgtk_plot_rectangle(const struct redraw_context *ctx, + const plot_style_t *style, + const struct rect *rect) { if (style->fill_type != PLOT_OP_TYPE_NONE) { nsgtk_set_colour(style->fill_colour); nsgtk_set_solid(); cairo_set_line_width(current_cr, 0); - cairo_rectangle(current_cr, x0, y0, x1 - x0, y1 - y0); + cairo_rectangle(current_cr, + rect->x0, + rect->y0, + rect->x1 - rect->x0, + rect->y1 - rect->y0); cairo_fill(current_cr); cairo_stroke(current_cr); } @@ -242,13 +326,36 @@ static bool nsgtk_plot_rectangle(int x0, int y0, int x1, int y1, const plot_styl else cairo_set_line_width(current_cr, style->stroke_width); - cairo_rectangle(current_cr, x0 + 0.5, y0 + 0.5, x1 - x0, y1 - y0); + cairo_rectangle(current_cr, + rect->x0 + 0.5, + rect->y0 + 0.5, + rect->x1 - rect->x0, + rect->y1 - rect->y0); cairo_stroke(current_cr); } - return true; + return NSERROR_OK; } -static bool nsgtk_plot_polygon(const int *p, unsigned int n, const plot_style_t *style) + +/** + * Plot a polygon + * + * Plots a filled polygon with straight lines between + * points. The lines around the edge of the ploygon are not + * plotted. The polygon is filled with the non-zero winding + * rule. + * + * \param ctx The current redraw context. + * \param pstyle Style controlling the polygon plot. + * \param p verticies of polygon + * \param n number of verticies. + * \return NSERROR_OK on success else error code. + */ +static nserror +nsgtk_plot_polygon(const struct redraw_context *ctx, + const plot_style_t *style, + const int *p, + unsigned int n) { unsigned int i; @@ -263,22 +370,116 @@ static bool nsgtk_plot_polygon(const int *p, unsigned int n, const plot_style_t cairo_fill(current_cr); cairo_stroke(current_cr); - return true; + return NSERROR_OK; } +/** + * Plots a path. + * + * Path plot consisting of cubic Bezier curves. Line and fill colour is + * controlled by the plot style. + * + * \param ctx The current redraw context. + * \param pstyle Style controlling the path plot. + * \param p elements of path + * \param n nunber of elements on path + * \param width The width of the path + * \param transform A transform to apply to the path. + * \return NSERROR_OK on success else error code. + */ +static nserror +nsgtk_plot_path(const struct redraw_context *ctx, + const plot_style_t *pstyle, + const float *p, + unsigned int n, + float width, + const float transform[6]) +{ + unsigned int i; + cairo_matrix_t old_ctm, n_ctm; + if (n == 0) + return NSERROR_OK; -static bool nsgtk_plot_text(int x, int y, const char *text, size_t length, - const struct plot_font_style *fstyle) -{ - return nsfont_paint(x, y, text, length, fstyle); -} + if (p[0] != PLOTTER_PATH_MOVE) { + LOG("Path does not start with move"); + return NSERROR_INVALID; + } + /* Save CTM */ + cairo_get_matrix(current_cr, &old_ctm); + /* Set up line style and width */ + cairo_set_line_width(current_cr, 1); + nsgtk_set_solid(); + + /* Load new CTM */ + n_ctm.xx = transform[0]; + n_ctm.yx = transform[1]; + n_ctm.xy = transform[2]; + n_ctm.yy = transform[3]; + n_ctm.x0 = transform[4]; + n_ctm.y0 = transform[5]; + + cairo_set_matrix(current_cr, &n_ctm); + + /* Construct path */ + for (i = 0; i < n; ) { + if (p[i] == PLOTTER_PATH_MOVE) { + cairo_move_to(current_cr, p[i+1], p[i+2]); + i += 3; + } else if (p[i] == PLOTTER_PATH_CLOSE) { + cairo_close_path(current_cr); + i++; + } else if (p[i] == PLOTTER_PATH_LINE) { + cairo_line_to(current_cr, p[i+1], p[i+2]); + i += 3; + } else if (p[i] == PLOTTER_PATH_BEZIER) { + cairo_curve_to(current_cr, p[i+1], p[i+2], + p[i+3], p[i+4], + p[i+5], p[i+6]); + i += 7; + } else { + LOG("bad path command %f", p[i]); + /* Reset matrix for safety */ + cairo_set_matrix(current_cr, &old_ctm); + return NSERROR_INVALID; + } + } + + /* Restore original CTM */ + cairo_set_matrix(current_cr, &old_ctm); + + /* Now draw path */ + if (pstyle->fill_colour != NS_TRANSPARENT) { + nsgtk_set_colour(pstyle->fill_colour); -static bool nsgtk_plot_pixbuf(int x, int y, int width, int height, - struct bitmap *bitmap, colour bg) + if (pstyle->stroke_colour != NS_TRANSPARENT) { + /* Fill & Stroke */ + cairo_fill_preserve(current_cr); + nsgtk_set_colour(pstyle->stroke_colour); + cairo_stroke(current_cr); + } else { + /* Fill only */ + cairo_fill(current_cr); + } + } else if (pstyle->stroke_colour != NS_TRANSPARENT) { + /* Stroke only */ + nsgtk_set_colour(pstyle->stroke_colour); + cairo_stroke(current_cr); + } + + return NSERROR_OK; +} + + +/** + * plot a pixbuf + */ +static nserror +nsgtk_plot_pixbuf(int x, int y, int width, int height, + struct bitmap *bitmap, colour bg) { int x0, y0, x1, y1; int dsrcx, dsrcy, dwidth, dheight; @@ -289,13 +490,13 @@ static bool nsgtk_plot_pixbuf(int x, int y, int width, int height, /* Bail early if we can */ if (width == 0 || height == 0) /* Nothing to plot */ - return true; + return NSERROR_OK; if ((x > (cliprect.x + cliprect.width)) || ((x + width) < cliprect.x) || (y > (cliprect.y + cliprect.height)) || ((y + height) < cliprect.y)) { /* Image completely outside clip region */ - return true; + return NSERROR_OK; } /* Get clip rectangle / image rectangle edge differences */ @@ -332,7 +533,7 @@ static bool nsgtk_plot_pixbuf(int x, int y, int width, int height, if (dwidth == 0 || dheight == 0) /* Nothing to plot */ - return true; + return NSERROR_OK; bmwidth = cairo_image_surface_get_width(bmsurface); bmheight = cairo_image_surface_get_height(bmsurface); @@ -388,12 +589,42 @@ static bool nsgtk_plot_pixbuf(int x, int y, int width, int height, } - return true; + return NSERROR_OK; } -static bool nsgtk_plot_bitmap(int x, int y, int width, int height, - struct bitmap *bitmap, colour bg, - bitmap_flags_t flags) + +/** + * Plot a bitmap + * + * Tiled plot of a bitmap image. (x,y) gives the top left + * coordinate of an explicitly placed tile. From this tile the + * image can repeat in all four directions -- up, down, left + * and right -- to the extents given by the current clip + * rectangle. + * + * The bitmap_flags say whether to tile in the x and y + * directions. If not tiling in x or y directions, the single + * image is plotted. The width and height give the dimensions + * the image is to be scaled to. + * + * \param ctx The current redraw context. + * \param bitmap The bitmap to plot + * \param x The x coordinate to plot the bitmap + * \param y The y coordiante to plot the bitmap + * \param width The width of area to plot the bitmap into + * \param height The height of area to plot the bitmap into + * \param bg the background colour to alpha blend into + * \param flags the flags controlling the type of plot operation + * \return NSERROR_OK on success else error code. + */ +static nserror +nsgtk_plot_bitmap(const struct redraw_context *ctx, + struct bitmap *bitmap, + int x, int y, + int width, + int height, + colour bg, + bitmap_flags_t flags) { int doneheight = 0, donewidth = 0; bool repeat_x = (flags & BITMAPF_REPEAT_X); @@ -402,7 +633,7 @@ static bool nsgtk_plot_bitmap(int x, int y, int width, int height, /* Bail early if we can */ if (width == 0 || height == 0) /* Nothing to plot */ - return true; + return NSERROR_OK; if (!(repeat_x || repeat_y)) { /* Not repeating at all, so just pass it on */ @@ -435,90 +666,33 @@ static bool nsgtk_plot_bitmap(int x, int y, int width, int height, break; } - return true; + return NSERROR_OK; } -static bool nsgtk_plot_path(const float *p, unsigned int n, colour fill, float width, - colour c, const float transform[6]) -{ - unsigned int i; - cairo_matrix_t old_ctm, n_ctm; - - if (n == 0) - return true; - - if (p[0] != PLOTTER_PATH_MOVE) { - LOG("Path does not start with move"); - return false; - } - - - /* Save CTM */ - cairo_get_matrix(current_cr, &old_ctm); - - /* Set up line style and width */ - cairo_set_line_width(current_cr, 1); - nsgtk_set_solid(); - - /* Load new CTM */ - n_ctm.xx = transform[0]; - n_ctm.yx = transform[1]; - n_ctm.xy = transform[2]; - n_ctm.yy = transform[3]; - n_ctm.x0 = transform[4]; - n_ctm.y0 = transform[5]; - - cairo_set_matrix(current_cr, &n_ctm); - - /* Construct path */ - for (i = 0; i < n; ) { - if (p[i] == PLOTTER_PATH_MOVE) { - cairo_move_to(current_cr, p[i+1], p[i+2]); - i += 3; - } else if (p[i] == PLOTTER_PATH_CLOSE) { - cairo_close_path(current_cr); - i++; - } else if (p[i] == PLOTTER_PATH_LINE) { - cairo_line_to(current_cr, p[i+1], p[i+2]); - i += 3; - } else if (p[i] == PLOTTER_PATH_BEZIER) { - cairo_curve_to(current_cr, p[i+1], p[i+2], - p[i+3], p[i+4], - p[i+5], p[i+6]); - i += 7; - } else { - LOG("bad path command %f", p[i]); - /* Reset matrix for safety */ - cairo_set_matrix(current_cr, &old_ctm); - return false; - } - } - - /* Restore original CTM */ - cairo_set_matrix(current_cr, &old_ctm); - - /* Now draw path */ - if (fill != NS_TRANSPARENT) { - nsgtk_set_colour(fill); - if (c != NS_TRANSPARENT) { - /* Fill & Stroke */ - cairo_fill_preserve(current_cr); - nsgtk_set_colour(c); - cairo_stroke(current_cr); - } else { - /* Fill only */ - cairo_fill(current_cr); - } - } else if (c != NS_TRANSPARENT) { - /* Stroke only */ - nsgtk_set_colour(c); - cairo_stroke(current_cr); - } - - return true; +/** + * Text plotting. + * + * \param ctx The current redraw context. + * \param fstyle plot style for this text + * \param x x coordinate + * \param y y coordinate + * \param text UTF-8 string to plot + * \param length length of string, in bytes + * \return NSERROR_OK on success else error code. + */ +static nserror +nsgtk_plot_text(const struct redraw_context *ctx, + const struct plot_font_style *fstyle, + int x, + int y, + const char *text, + size_t length) +{ + return nsfont_paint(x, y, text, length, fstyle); } + /** GTK plotter table */ const struct plotter_table nsgtk_plotters = { .clip = nsgtk_plot_clip, @@ -532,6 +706,3 @@ const struct plotter_table nsgtk_plotters = { .text = nsgtk_plot_text, .option_knockout = true }; - - - diff --git a/frontends/gtk/print.c b/frontends/gtk/print.c index 55dcf6390..4f3408166 100644 --- a/frontends/gtk/print.c +++ b/frontends/gtk/print.c @@ -17,8 +17,10 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - /** \file - * GTK printing (implementation). + +/** + * \file + * GTK printing implementation. * All the functions and structures necessary for printing( signal handlers, * plotters, printer) are here. * Most of the plotters have been copied from the gtk_plotters.c file. @@ -71,7 +73,7 @@ static inline void nsgtk_print_set_colour(colour c) -static bool gtk_print_font_paint(int x, int y, +static nserror gtk_print_font_paint(int x, int y, const char *string, size_t length, const plot_font_style_t *fstyle) { @@ -81,7 +83,7 @@ static bool gtk_print_font_paint(int x, int y, PangoLayoutLine *line; if (length == 0) - return true; + return NSERROR_OK; desc = nsfont_style_to_description(fstyle); size = (gint) ((double) pango_font_description_get_size(desc) * @@ -106,7 +108,7 @@ static bool gtk_print_font_paint(int x, int y, g_object_unref(layout); pango_font_description_free(desc); - return true; + return NSERROR_OK; } @@ -131,10 +133,20 @@ static inline void nsgtk_print_set_dashed(void) cairo_set_dash(gtk_print_current_cr, cdashes, 1, 0); } -/** Set clipping area for subsequent plot operations. */ -static bool nsgtk_print_plot_clip(const struct rect *clip) + +/** + * \brief Sets a clip rectangle for subsequent plot operations. + * + * \param ctx The current redraw context. + * \param clip The rectangle to limit all subsequent plot + * operations within. + * \return NSERROR_OK on success else error code. + */ +static nserror +nsgtk_print_plot_clip(const struct redraw_context *ctx, const struct rect *clip) { - LOG("Clipping. x0: %i ;\t y0: %i ;\t x1: %i ;\t y1: %i", clip->x0, clip->y0, clip->x1, clip->y1); + LOG("Clipping. x0: %i ;\t y0: %i ;\t x1: %i ;\t y1: %i", + clip->x0, clip->y0, clip->x1, clip->y1); /* Normalize cllipping area - to prevent overflows. * See comment in pdf_plot_fill. */ @@ -153,10 +165,24 @@ static bool nsgtk_print_plot_clip(const struct rect *clip) cliprect.width = clip_x1 - clip_x0; cliprect.height = clip_y1 - clip_y0; - return true; + return NSERROR_OK; } -static bool nsgtk_print_plot_arc(int x, int y, int radius, int angle1, int angle2, const plot_style_t *style) + +/** + * Plots an arc + * + * plot an arc segment around (x,y), anticlockwise from angle1 + * to angle2. Angles are measured anticlockwise from + * horizontal, in degrees. + * + * \param ctx The current redraw context. + * \return NSERROR_OK on success else error code. + */ +static nserror +nsgtk_print_plot_arc(const struct redraw_context *ctx, + const plot_style_t *style, + int x, int y, int radius, int angle1, int angle2) { nsgtk_print_set_colour(style->fill_colour); nsgtk_print_set_solid(); @@ -167,10 +193,23 @@ static bool nsgtk_print_plot_arc(int x, int y, int radius, int angle1, int angle (angle2 + 90) * (M_PI / 180)); cairo_stroke(gtk_print_current_cr); - return true; + return NSERROR_OK; } -static bool nsgtk_print_plot_disc(int x, int y, int radius, const plot_style_t *style) + +/** + * Plots a circle + * + * Plot a circle centered on (x,y), which is optionally filled. + * + * \param ctx The current redraw context. + * \param pstyle Style controlling the circle plot. + * \return NSERROR_OK on success else error code. + */ +static nserror +nsgtk_print_plot_disc(const struct redraw_context *ctx, + const plot_style_t *style, + int x, int y, int radius) { if (style->fill_type != PLOT_OP_TYPE_NONE) { nsgtk_print_set_colour(style->fill_colour); @@ -208,10 +247,25 @@ static bool nsgtk_print_plot_disc(int x, int y, int radius, const plot_style_t * cairo_stroke(gtk_print_current_cr); } - return true; + return NSERROR_OK; } -static bool nsgtk_print_plot_line(int x0, int y0, int x1, int y1, const plot_style_t *style) + +/** + * Plots a line + * + * plot a line from (x0,y0) to (x1,y1). Coordinates are at + * centre of line width/thickness. + * + * \param ctx The current redraw context. + * \param pstyle Style controlling the line plot. + * \param line A rectangle defining the line to be drawn + * \return NSERROR_OK on success else error code. + */ +static nserror +nsgtk_print_plot_line(const struct redraw_context *ctx, + const plot_style_t *style, + const struct rect *line) { nsgtk_print_set_colour(style->stroke_colour); @@ -235,16 +289,35 @@ static bool nsgtk_print_plot_line(int x0, int y0, int x1, int y1, const plot_sty else cairo_set_line_width(gtk_print_current_cr, style->stroke_width); - cairo_move_to(gtk_print_current_cr, x0 + 0.5, y0 + 0.5); - cairo_line_to(gtk_print_current_cr, x1 + 0.5, y1 + 0.5); + cairo_move_to(gtk_print_current_cr, line->x0 + 0.5, line->y0 + 0.5); + cairo_line_to(gtk_print_current_cr, line->x1 + 0.5, line->y1 + 0.5); cairo_stroke(gtk_print_current_cr); - return true; + return NSERROR_OK; } -static bool nsgtk_print_plot_rectangle(int x0, int y0, int x1, int y1, const plot_style_t *style) + +/** + * Plots a rectangle. + * + * The rectangle can be filled an outline or both controlled + * by the plot style The line can be solid, dotted or + * dashed. Top left corner at (x0,y0) and rectangle has given + * width and height. + * + * \param ctx The current redraw context. + * \param pstyle Style controlling the rectangle plot. + * \param rect A rectangle defining the line to be drawn + * \return NSERROR_OK on success else error code. + */ +static nserror +nsgtk_print_plot_rectangle(const struct redraw_context *ctx, + const plot_style_t *style, + const struct rect *rect) { - LOG("x0: %i ;\t y0: %i ;\t x1: %i ;\t y1: %i", x0, y0, x1, y1); + int x0,y0,x1,y1; + LOG("x0: %i ;\t y0: %i ;\t x1: %i ;\t y1: %i", + rect->x0, rect->y0, rect->x1, rect->y1); if (style->fill_type != PLOT_OP_TYPE_NONE) { @@ -253,13 +326,15 @@ static bool nsgtk_print_plot_rectangle(int x0, int y0, int x1, int y1, const plo /* Normalize boundaries of the area - to prevent overflows. * See comment in pdf_plot_fill. */ - x0 = min(max(x0, 0), settings->page_width); - y0 = min(max(y0, 0), settings->page_height); - x1 = min(max(x1, 0), settings->page_width); - y1 = min(max(y1, 0), settings->page_height); + x0 = min(max(rect->x0, 0), settings->page_width); + y0 = min(max(rect->y0, 0), settings->page_height); + x1 = min(max(rect->x1, 0), settings->page_width); + y1 = min(max(rect->y1, 0), settings->page_height); cairo_set_line_width(gtk_print_current_cr, 0); - cairo_rectangle(gtk_print_current_cr, x0, y0, x1 - x0, y1 - y0); + cairo_rectangle(gtk_print_current_cr, + x0, y0, + x1 - x0, y1 - y0); cairo_fill(gtk_print_current_cr); cairo_stroke(gtk_print_current_cr); } @@ -291,10 +366,15 @@ static bool nsgtk_print_plot_rectangle(int x0, int y0, int x1, int y1, const plo cairo_stroke(gtk_print_current_cr); } - return true; + return NSERROR_OK; } -static bool nsgtk_print_plot_polygon(const int *p, unsigned int n, const plot_style_t *style) + +static nserror +nsgtk_print_plot_polygon(const struct redraw_context *ctx, + const plot_style_t *style, + const int *p, + unsigned int n) { unsigned int i; @@ -316,18 +396,37 @@ static bool nsgtk_print_plot_polygon(const int *p, unsigned int n, const plot_st cairo_fill(gtk_print_current_cr); cairo_stroke(gtk_print_current_cr); - return true; + return NSERROR_OK; } -static bool nsgtk_print_plot_path(const float *p, unsigned int n, colour fill, - float width, colour c, const float transform[6]) +/** + * Plots a path. + * + * Path plot consisting of cubic Bezier curves. Line and fill colour is + * controlled by the plot style. + * + * \param ctx The current redraw context. + * \param pstyle Style controlling the path plot. + * \param p elements of path + * \param n nunber of elements on path + * \param width The width of the path + * \param transform A transform to apply to the path. + * \return NSERROR_OK on success else error code. + */ +static nserror +nsgtk_print_plot_path(const struct redraw_context *ctx, + const plot_style_t *pstyle, + const float *p, + unsigned int n, + float width, + const float transform[6]) { /* Only the internal SVG renderer uses this plot call currently, * and the GTK version uses librsvg. Thus, we ignore this complexity, * and just return true obliviously. */ - return true; + return NSERROR_OK; } @@ -445,9 +544,30 @@ static bool nsgtk_print_plot_pixbuf(int x, int y, int width, int height, } -static bool nsgtk_print_plot_bitmap(int x, int y, int width, int height, - struct bitmap *bitmap, colour bg, - bitmap_flags_t flags) +/** + * Plot a bitmap + * + * Tiled plot of a bitmap image. (x,y) gives the top left + * coordinate of an explicitly placed tile. From this tile the + * image can repeat in all four directions -- up, down, left + * and right -- to the extents given by the current clip + * rectangle. + * + * The bitmap_flags say whether to tile in the x and y + * directions. If not tiling in x or y directions, the single + * image is plotted. The width and height give the dimensions + * the image is to be scaled to. + * + * \param ctx The current redraw context. + * \return NSERROR_OK on success else error code. + */ +static nserror +nsgtk_print_plot_bitmap(const struct redraw_context *ctx, + struct bitmap *bitmap, + int x, int y, + int width, int height, + colour bg, + bitmap_flags_t flags) { int doneheight = 0, donewidth = 0; bool repeat_x = (flags & BITMAPF_REPEAT_X); @@ -495,12 +615,19 @@ static bool nsgtk_print_plot_bitmap(int x, int y, int width, int height, return true; } -static bool nsgtk_print_plot_text(int x, int y, const char *text, size_t length, - const plot_font_style_t *fstyle) + +static nserror +nsgtk_print_plot_text(const struct redraw_context *ctx, + const struct plot_font_style *fstyle, + int x, + int y, + const char *text, + size_t length) { return gtk_print_font_paint(x, y, text, length, fstyle); } + /** GTK print plotter table */ static const struct plotter_table nsgtk_print_plotters = { .clip = nsgtk_print_plot_clip, diff --git a/frontends/gtk/scaffolding.c b/frontends/gtk/scaffolding.c index bbc568e15..06b51decc 100644 --- a/frontends/gtk/scaffolding.c +++ b/frontends/gtk/scaffolding.c @@ -1706,7 +1706,7 @@ nsgtk_history_draw_event(GtkWidget *widget, GdkEventExpose *event, gpointer g) clip.y0 = event->area.y; clip.x1 = event->area.x + event->area.width; clip.y1 = event->area.y + event->area.height; - ctx.plot->clip(&clip); + ctx.plot->clip(&ctx, &clip); browser_window_history_redraw(bw, &ctx); -- cgit v1.2.3 From 3ea137ca3d9b0f996493bb33289d9ab3fc2881bc Mon Sep 17 00:00:00 2001 From: Vincent Sanders Date: Wed, 8 Feb 2017 09:22:42 +0000 Subject: update RISC OS plotters to new API --- frontends/riscos/content-handlers/artworks.c | 2 +- frontends/riscos/content-handlers/draw.c | 2 +- frontends/riscos/content-handlers/sprite.c | 2 +- frontends/riscos/gui/progress_bar.c | 15 +- frontends/riscos/gui/status_bar.c | 25 +- frontends/riscos/plotters.c | 784 ++++++++++++++++----------- frontends/riscos/print.c | 242 +++++---- frontends/riscos/save_draw.c | 633 +++++++++++++-------- frontends/riscos/save_draw.h | 7 + 9 files changed, 1055 insertions(+), 657 deletions(-) diff --git a/frontends/riscos/content-handlers/artworks.c b/frontends/riscos/content-handlers/artworks.c index f70b10ac7..7a7d79cb7 100644 --- a/frontends/riscos/content-handlers/artworks.c +++ b/frontends/riscos/content-handlers/artworks.c @@ -317,7 +317,7 @@ bool artworks_redraw(struct content *c, struct content_redraw_data *data, int clip_x1 = clip->x1; int clip_y1 = clip->y1; - if (ctx->plot->flush && !ctx->plot->flush()) + if (ctx->plot->flush && (ctx->plot->flush(ctx) != NSERROR_OK)) return false; /* pick up render addresses again in case they've changed diff --git a/frontends/riscos/content-handlers/draw.c b/frontends/riscos/content-handlers/draw.c index 9dff75736..0c84de866 100644 --- a/frontends/riscos/content-handlers/draw.c +++ b/frontends/riscos/content-handlers/draw.c @@ -184,7 +184,7 @@ bool draw_redraw(struct content *c, struct content_redraw_data *data, const void *src_data; os_error *error; - if (ctx->plot->flush && !ctx->plot->flush()) + if (ctx->plot->flush && (ctx->plot->flush(ctx) != NSERROR_OK)) return false; if (!c->width || !c->height) diff --git a/frontends/riscos/content-handlers/sprite.c b/frontends/riscos/content-handlers/sprite.c index ed06110ec..02976e48e 100644 --- a/frontends/riscos/content-handlers/sprite.c +++ b/frontends/riscos/content-handlers/sprite.c @@ -180,7 +180,7 @@ bool sprite_redraw(struct content *c, struct content_redraw_data *data, { sprite_content *sprite = (sprite_content *) c; - if (ctx->plot->flush && !ctx->plot->flush()) + if (ctx->plot->flush && (ctx->plot->flush(ctx) != NSERROR_OK)) return false; return image_redraw(sprite->data, diff --git a/frontends/riscos/gui/progress_bar.c b/frontends/riscos/gui/progress_bar.c index c26b46c84..c47c2af7d 100644 --- a/frontends/riscos/gui/progress_bar.c +++ b/frontends/riscos/gui/progress_bar.c @@ -30,9 +30,9 @@ #include "oslib/wimp.h" #include "oslib/wimpspriteop.h" -#include "netsurf/plotters.h" #include "utils/log.h" #include "utils/utils.h" +#include "netsurf/plotters.h" #include "riscos/gui.h" #include "riscos/tinct.h" @@ -482,6 +482,11 @@ void ro_gui_progress_bar_redraw_window(wimp_draw *redraw, osbool more = true; struct rect clip; int progress_ymid; + struct redraw_context ctx = { + .interactive = true, + .background_images = true, + .plot = &ro_plotters + }; /* initialise the plotters */ ro_plot_origin_x = 0; @@ -513,16 +518,16 @@ void ro_gui_progress_bar_redraw_window(wimp_draw *redraw, redraw->box.y0 + pb->visible.y0) >> 1; if ((clip.x0 < clip.x1) && (clip.y0 < clip.y1)) { if (progress_icon) { - ro_plotters.clip(&clip); + ctx.plot->clip(&ctx, &clip); _swix(Tinct_Plot, _IN(2) | _IN(3) | _IN(4) | _IN(7), progress_icon, redraw->box.x0 - pb->offset, progress_ymid - progress_height, tinct_FILL_HORIZONTALLY); } else { - ro_plotters.rectangle(clip.x0, clip.y0, - clip.x1, clip.y1, - plot_style_fill_red); + ctx.plot->rectangle(&ctx, + plot_style_fill_red, + &clip); } } } diff --git a/frontends/riscos/gui/status_bar.c b/frontends/riscos/gui/status_bar.c index 9d1bada91..bcaf3baf9 100644 --- a/frontends/riscos/gui/status_bar.c +++ b/frontends/riscos/gui/status_bar.c @@ -28,9 +28,10 @@ #include "oslib/os.h" #include "oslib/wimp.h" #include "oslib/wimpspriteop.h" -#include "netsurf/plotters.h" + #include "utils/log.h" #include "utils/utils.h" +#include "netsurf/plotters.h" #include "riscos/gui.h" #include "riscos/wimp.h" @@ -436,6 +437,12 @@ void ro_gui_status_bar_redraw(wimp_draw *redraw) os_error *error; osbool more; rufl_code code; + struct redraw_context ctx = { + .interactive = true, + .background_images = true, + .plot = &ro_plotters + }; + struct rect rect; sb = (struct status_bar *)ro_gui_wimp_event_get_user_data(redraw->w); assert(sb); @@ -467,18 +474,22 @@ void ro_gui_status_bar_redraw(wimp_draw *redraw) rufl_BLEND_FONT); if (code != rufl_OK) { if (code == rufl_FONT_MANAGER_ERROR) - LOG("rufl_FONT_MANAGER_ERROR: 0x%x: %s", rufl_fm_error->errnum, rufl_fm_error->errmess); + LOG("rufl_FONT_MANAGER_ERROR: 0x%x: %s", + rufl_fm_error->errnum, rufl_fm_error->errmess); else LOG("rufl_paint: 0x%x", code); } } + rect.x0 = (redraw->box.x0 + sb->width - WIDGET_WIDTH - 2) >> 1; + rect.y0 = -redraw->box.y0 >> 1; + rect.x1 = (redraw->box.x0 + sb->width - WIDGET_WIDTH) >> 1; + rect.y1 = -redraw->box.y1 >> 1; + /* separate the widget from the text with a line */ - ro_plotters.rectangle((redraw->box.x0 + sb->width - WIDGET_WIDTH - 2) >> 1, - -redraw->box.y0 >> 1, - (redraw->box.x0 + sb->width - WIDGET_WIDTH) >> 1, - -redraw->box.y1 >> 1, - plot_style_fill_black); + ctx.plot->rectangle(&ctx, + plot_style_fill_black, + &rect); error = xwimp_get_rectangle(redraw, &more); if (error) { diff --git a/frontends/riscos/plotters.c b/frontends/riscos/plotters.c index 06e732d99..b12d6c403 100644 --- a/frontends/riscos/plotters.c +++ b/frontends/riscos/plotters.c @@ -16,8 +16,9 @@ * along with this program. If not, see . */ -/** \file - * Target independent plotting (RISC OS screen implementation). +/** + * \file + * RISC OS screen plotter implementation. */ #include @@ -35,38 +36,6 @@ #include "riscos/font.h" #include "riscos/oslib_pre7.h" -static bool ro_plot_rectangle(int x0, int y0, int x1, int y1, const plot_style_t *style); -static bool ro_plot_line(int x0, int y0, int x1, int y1, const plot_style_t *style); -static bool ro_plot_draw_path(const draw_path * const path, int width, - colour c, bool dotted, bool dashed); -static bool ro_plot_polygon(const int *p, unsigned int n, const plot_style_t *style); -static bool ro_plot_path(const float *p, unsigned int n, colour fill, float width, - colour c, const float transform[6]); -static bool ro_plot_clip(const struct rect *clip); -static bool ro_plot_text(int x, int y, const char *text, size_t length, - const plot_font_style_t *fstyle); -static bool ro_plot_disc(int x, int y, int radius, const plot_style_t *style); -static bool ro_plot_arc(int x, int y, int radius, int angle1, int angle2, - const plot_style_t *style); -static bool ro_plot_bitmap(int x, int y, int width, int height, - struct bitmap *bitmap, colour bg, - bitmap_flags_t flags); - - -struct plotter_table plot; - -const struct plotter_table ro_plotters = { - .rectangle = ro_plot_rectangle, - .line = ro_plot_line, - .polygon = ro_plot_polygon, - .clip = ro_plot_clip, - .text = ro_plot_text, - .disc = ro_plot_disc, - .arc = ro_plot_arc, - .bitmap = ro_plot_bitmap, - .path = ro_plot_path, - .option_knockout = true, -}; int ro_plot_origin_x = 0; int ro_plot_origin_y = 0; @@ -74,143 +43,387 @@ int ro_plot_origin_y = 0; /** One version of the A9home OS is incapable of drawing patterned lines */ bool ro_plot_patterned_lines = true; +/** + * plot a path on RISC OS + */ +static nserror +ro_plot_draw_path(const draw_path * const path, + int width, + colour c, + bool dotted, + bool dashed) +{ + static const draw_line_style line_style = { + draw_JOIN_MITRED, + draw_CAP_BUTT, + draw_CAP_BUTT, + 0, 0x7fffffff, + 0, 0, 0, 0 + }; + draw_dash_pattern dash = { 0, 1, { 512 } }; + const draw_dash_pattern *dash_pattern = 0; + os_error *error; + + if (width < 1) + width = 1; + + if (ro_plot_patterned_lines) { + if (dotted) { + dash.elements[0] = 512 * width; + dash_pattern = ‐ + } else if (dashed) { + dash.elements[0] = 1536 * width; + dash_pattern = ‐ + } + } + + error = xcolourtrans_set_gcol(c << 8, 0, os_ACTION_OVERWRITE, 0, 0); + if (error) { + LOG("xcolourtrans_set_gcol: 0x%x: %s", + error->errnum, error->errmess); + return NSERROR_INVALID; + } + + error = xdraw_stroke(path, 0, 0, 0, width * 2 * 256, + &line_style, dash_pattern); + if (error) { + LOG("xdraw_stroke: 0x%x: %s", error->errnum, error->errmess); + return NSERROR_INVALID; + } + + return NSERROR_OK; +} + + +/** + * \brief Sets a clip rectangle for subsequent plot operations. + * + * \param ctx The current redraw context. + * \param clip The rectangle to limit all subsequent plot + * operations within. + * \return NSERROR_OK on success else error code. + */ +static nserror +ro_plot_clip(const struct redraw_context *ctx, const struct rect *clip) +{ + os_error *error; + char buf[12]; + + int clip_x0 = ro_plot_origin_x + clip->x0 * 2; + int clip_y0 = ro_plot_origin_y - clip->y0 * 2 - 1; + int clip_x1 = ro_plot_origin_x + clip->x1 * 2 - 1; + int clip_y1 = ro_plot_origin_y - clip->y1 * 2; + + if (clip_x1 < clip_x0 || clip_y0 < clip_y1) { + LOG("bad clip rectangle %i %i %i %i", + clip_x0, clip_y0, clip_x1, clip_y1); + return NSERROR_BAD_SIZE; + } + + buf[0] = os_VDU_SET_GRAPHICS_WINDOW; + buf[1] = clip_x0; + buf[2] = clip_x0 >> 8; + buf[3] = clip_y1; + buf[4] = clip_y1 >> 8; + buf[5] = clip_x1; + buf[6] = clip_x1 >> 8; + buf[7] = clip_y0; + buf[8] = clip_y0 >> 8; + + error = xos_writen(buf, 9); + if (error) { + LOG("xos_writen: 0x%x: %s", error->errnum, error->errmess); + return NSERROR_INVALID; + } + + return NSERROR_OK; +} + + +/** + * Plots an arc + * + * plot an arc segment around (x,y), anticlockwise from angle1 + * to angle2. Angles are measured anticlockwise from + * horizontal, in degrees. + * + * \param ctx The current redraw context. + * \param pstyle Style controlling the arc plot. + * \param x The x coordinate of the arc. + * \param y The y coordinate of the arc. + * \param radius The radius of the arc. + * \param angle1 The start angle of the arc. + * \param angle2 The finish angle of the arc. + * \return NSERROR_OK on success else error code. + */ +static nserror +ro_plot_arc(const struct redraw_context *ctx, + const plot_style_t *style, + int x, int y, int radius, int angle1, int angle2) +{ + os_error *error; + int sx, sy, ex, ey; + double t; + + x = ro_plot_origin_x + x * 2; + y = ro_plot_origin_y - y * 2; + radius <<= 1; + + error = xcolourtrans_set_gcol(style->fill_colour << 8, 0, + os_ACTION_OVERWRITE, 0, 0); + + if (error) { + LOG("xcolourtrans_set_gcol: 0x%x: %s", + error->errnum, error->errmess); + return NSERROR_INVALID; + } + + t = ((double)angle1 * M_PI) / 180.0; + sx = (x + (int)(radius * cos(t))); + sy = (y + (int)(radius * sin(t))); + t = ((double)angle2 * M_PI) / 180.0; + ex = (x + (int)(radius * cos(t))); + ey = (y + (int)(radius * sin(t))); -bool ro_plot_rectangle(int x0, int y0, int x1, int y1, const plot_style_t *style) + error = xos_plot(os_MOVE_TO, x, y); /* move to centre */ + if (error) { + LOG("xos_plot: 0x%x: %s", error->errnum, error->errmess); + return NSERROR_INVALID; + } + + error = xos_plot(os_MOVE_TO, sx, sy); /* move to start */ + if (error) { + LOG("xos_plot: 0x%x: %s", error->errnum, error->errmess); + return NSERROR_INVALID; + } + + error = xos_plot(os_PLOT_ARC | os_PLOT_TO, ex, ey); /* arc to end */ + if (error) { + LOG("xos_plot: 0x%x: %s", error->errnum, error->errmess); + return NSERROR_INVALID; + } + + return NSERROR_OK; +} + + +/** + * Plots a circle + * + * Plot a circle centered on (x,y), which is optionally filled. + * + * \param ctx The current redraw context. + * \param pstyle Style controlling the circle plot. + * \param x The x coordinate of the circle. + * \param y The y coordinate of the circle. + * \param radius The radius of the circle. + * \return NSERROR_OK on success else error code. + */ +static nserror +ro_plot_disc(const struct redraw_context *ctx, + const plot_style_t *style, + int x, int y, int radius) { + os_error *error; if (style->fill_type != PLOT_OP_TYPE_NONE) { - os_error *error; - error = xcolourtrans_set_gcol(style->fill_colour << 8, - colourtrans_USE_ECFS_GCOL, - os_ACTION_OVERWRITE, 0, 0); + error = xcolourtrans_set_gcol(style->fill_colour << 8, 0, + os_ACTION_OVERWRITE, 0, 0); if (error) { - LOG("xcolourtrans_set_gcol: 0x%x: %s", error->errnum, error->errmess); - return false; + LOG("xcolourtrans_set_gcol: 0x%x: %s", + error->errnum, error->errmess); + return NSERROR_INVALID; } - error = xos_plot(os_MOVE_TO, - ro_plot_origin_x + x0 * 2, - ro_plot_origin_y - y0 * 2 - 1); + ro_plot_origin_x + x * 2, + ro_plot_origin_y - y * 2); if (error) { LOG("xos_plot: 0x%x: %s", error->errnum, error->errmess); - return false; + return NSERROR_INVALID; } - - error = xos_plot(os_PLOT_RECTANGLE | os_PLOT_TO, - ro_plot_origin_x + x1 * 2 - 1, - ro_plot_origin_y - y1 * 2); + error = xos_plot(os_PLOT_CIRCLE | os_PLOT_BY, radius * 2, 0); if (error) { LOG("xos_plot: 0x%x: %s", error->errnum, error->errmess); - return false; + return NSERROR_INVALID; } } if (style->stroke_type != PLOT_OP_TYPE_NONE) { - bool dotted = false; - bool dashed = false; - - const int path[] = { draw_MOVE_TO, - (ro_plot_origin_x + x0 * 2) * 256, - (ro_plot_origin_y - y0 * 2 - 1) * 256, - draw_LINE_TO, - (ro_plot_origin_x + (x1) * 2) * 256, - (ro_plot_origin_y - y0 * 2 - 1) * 256, - draw_LINE_TO, - (ro_plot_origin_x + (x1) * 2) * 256, - (ro_plot_origin_y - (y1) * 2 - 1) * 256, - draw_LINE_TO, - (ro_plot_origin_x + x0 * 2) * 256, - (ro_plot_origin_y - (y1) * 2 - 1) * 256, - draw_CLOSE_LINE, - (ro_plot_origin_x + x0 * 2) * 256, - (ro_plot_origin_y - y0 * 2 - 1) * 256, - draw_END_PATH }; - - if (style->stroke_type == PLOT_OP_TYPE_DOT) - dotted = true; - if (style->stroke_type == PLOT_OP_TYPE_DASH) - dashed = true; + error = xcolourtrans_set_gcol(style->stroke_colour << 8, 0, + os_ACTION_OVERWRITE, 0, 0); + if (error) { + LOG("xcolourtrans_set_gcol: 0x%x: %s", + error->errnum, error->errmess); + return NSERROR_INVALID; + } + error = xos_plot(os_MOVE_TO, + ro_plot_origin_x + x * 2, + ro_plot_origin_y - y * 2); + if (error) { + LOG("xos_plot: 0x%x: %s", error->errnum, error->errmess); + return NSERROR_INVALID; + } + error = xos_plot(os_PLOT_CIRCLE_OUTLINE | os_PLOT_BY, + radius * 2, 0); - ro_plot_draw_path((const draw_path *)path, - style->stroke_width, - style->stroke_colour, - dotted, dashed); + if (error) { + LOG("xos_plot: 0x%x: %s", error->errnum, error->errmess); + return NSERROR_INVALID; + } } - - return true; + return NSERROR_OK; } -bool ro_plot_line(int x0, int y0, int x1, int y1, const plot_style_t *style) +/** + * Plots a line + * + * plot a line from (x0,y0) to (x1,y1). Coordinates are at + * centre of line width/thickness. + * + * \param ctx The current redraw context. + * \param pstyle Style controlling the line plot. + * \param line A rectangle defining the line to be drawn + * \return NSERROR_OK on success else error code. + */ +static nserror +ro_plot_line(const struct redraw_context *ctx, + const plot_style_t *style, + const struct rect *line) { if (style->stroke_type != PLOT_OP_TYPE_NONE) { - const int path[] = { draw_MOVE_TO, - (ro_plot_origin_x + x0 * 2) * 256, - (ro_plot_origin_y - y0 * 2 - 1) * 256, - draw_LINE_TO, - (ro_plot_origin_x + x1 * 2) * 256, - (ro_plot_origin_y - y1 * 2 - 1) * 256, - draw_END_PATH }; - bool dotted = false; + const int path[] = { + draw_MOVE_TO, + (ro_plot_origin_x + line->x0 * 2) * 256, + (ro_plot_origin_y - line->y0 * 2 - 1) * 256, + draw_LINE_TO, + (ro_plot_origin_x + line->x1 * 2) * 256, + (ro_plot_origin_y - line->y1 * 2 - 1) * 256, + draw_END_PATH }; + bool dotted = false; bool dashed = false; - if (style->stroke_type == PLOT_OP_TYPE_DOT) + if (style->stroke_type == PLOT_OP_TYPE_DOT) dotted = true; - if (style->stroke_type == PLOT_OP_TYPE_DASH) + if (style->stroke_type == PLOT_OP_TYPE_DASH) dashed = true; - return ro_plot_draw_path((const draw_path *)path, - style->stroke_width, - style->stroke_colour, + return ro_plot_draw_path((const draw_path *)path, + style->stroke_width, + style->stroke_colour, dotted, dashed); } - return true; + return NSERROR_OK; } -bool ro_plot_draw_path(const draw_path * const path, int width, - colour c, bool dotted, bool dashed) +/** + * Plots a rectangle. + * + * The rectangle can be filled an outline or both controlled + * by the plot style The line can be solid, dotted or + * dashed. Top left corner at (x0,y0) and rectangle has given + * width and height. + * + * \param ctx The current redraw context. + * \param pstyle Style controlling the rectangle plot. + * \param rect A rectangle defining the line to be drawn + * \return NSERROR_OK on success else error code. + */ +static nserror +ro_plot_rectangle(const struct redraw_context *ctx, + const plot_style_t *style, + const struct rect *rect) { - static const draw_line_style line_style = { draw_JOIN_MITRED, - draw_CAP_BUTT, draw_CAP_BUTT, 0, 0x7fffffff, - 0, 0, 0, 0 }; - draw_dash_pattern dash = { 0, 1, { 512 } }; - const draw_dash_pattern *dash_pattern = 0; - os_error *error; + if (style->fill_type != PLOT_OP_TYPE_NONE) { + os_error *error; + error = xcolourtrans_set_gcol(style->fill_colour << 8, + colourtrans_USE_ECFS_GCOL, + os_ACTION_OVERWRITE, 0, 0); + if (error) { + LOG("xcolourtrans_set_gcol: 0x%x: %s", + error->errnum, error->errmess); + return NSERROR_INVALID; + } - if (width < 1) - width = 1; + error = xos_plot(os_MOVE_TO, + ro_plot_origin_x + rect->x0 * 2, + ro_plot_origin_y - rect->y0 * 2 - 1); + if (error) { + LOG("xos_plot: 0x%x: %s", error->errnum, error->errmess); + return NSERROR_INVALID; + } - if (ro_plot_patterned_lines) { - if (dotted) { - dash.elements[0] = 512 * width; - dash_pattern = ‐ - } else if (dashed) { - dash.elements[0] = 1536 * width; - dash_pattern = ‐ + error = xos_plot(os_PLOT_RECTANGLE | os_PLOT_TO, + ro_plot_origin_x + rect->x1 * 2 - 1, + ro_plot_origin_y - rect->y1 * 2); + if (error) { + LOG("xos_plot: 0x%x: %s", error->errnum, error->errmess); + return NSERROR_INVALID; } } - error = xcolourtrans_set_gcol(c << 8, 0, os_ACTION_OVERWRITE, 0, 0); - if (error) { - LOG("xcolourtrans_set_gcol: 0x%x: %s", error->errnum, error->errmess); - return false; - } + if (style->stroke_type != PLOT_OP_TYPE_NONE) { + bool dotted = false; + bool dashed = false; - error = xdraw_stroke(path, 0, 0, 0, width * 2 * 256, - &line_style, dash_pattern); - if (error) { - LOG("xdraw_stroke: 0x%x: %s", error->errnum, error->errmess); - return false; + const int path[] = { + draw_MOVE_TO, + (ro_plot_origin_x + rect->x0 * 2) * 256, + (ro_plot_origin_y - rect->y0 * 2 - 1) * 256, + draw_LINE_TO, + (ro_plot_origin_x + (rect->x1) * 2) * 256, + (ro_plot_origin_y - rect->y0 * 2 - 1) * 256, + draw_LINE_TO, + (ro_plot_origin_x + (rect->x1) * 2) * 256, + (ro_plot_origin_y - (rect->y1) * 2 - 1) * 256, + draw_LINE_TO, + (ro_plot_origin_x + rect->x0 * 2) * 256, + (ro_plot_origin_y - (rect->y1) * 2 - 1) * 256, + draw_CLOSE_LINE, + (ro_plot_origin_x + rect->x0 * 2) * 256, + (ro_plot_origin_y - rect->y0 * 2 - 1) * 256, + draw_END_PATH + }; + + if (style->stroke_type == PLOT_OP_TYPE_DOT) + dotted = true; + + if (style->stroke_type == PLOT_OP_TYPE_DASH) + dashed = true; + + ro_plot_draw_path((const draw_path *)path, + style->stroke_width, + style->stroke_colour, + dotted, + dashed); } - return true; + return NSERROR_OK; } -bool ro_plot_polygon(const int *p, unsigned int n, const plot_style_t *style) +/** + * Plot a polygon + * + * Plots a filled polygon with straight lines between + * points. The lines around the edge of the ploygon are not + * plotted. The polygon is filled with the non-zero winding + * rule. + * + * \param ctx The current redraw context. + * \param pstyle Style controlling the polygon plot. + * \param p verticies of polygon + * \param n number of verticies. + * \return NSERROR_OK on success else error code. + */ +static nserror +ro_plot_polygon(const struct redraw_context *ctx, + const plot_style_t *style, + const int *p, + unsigned int n) { int path[n * 3 + 2]; unsigned int i; @@ -225,34 +438,60 @@ bool ro_plot_polygon(const int *p, unsigned int n, const plot_style_t *style) path[n * 3] = draw_END_PATH; path[n * 3 + 1] = 0; - error = xcolourtrans_set_gcol(style->fill_colour << 8, 0, os_ACTION_OVERWRITE, 0, 0); + error = xcolourtrans_set_gcol(style->fill_colour << 8, + 0, os_ACTION_OVERWRITE, 0, 0); if (error) { - LOG("xcolourtrans_set_gcol: 0x%x: %s", error->errnum, error->errmess); - return false; + LOG("xcolourtrans_set_gcol: 0x%x: %s", + error->errnum, error->errmess); + return NSERROR_INVALID; } error = xdraw_fill((draw_path *) path, 0, 0, 0); if (error) { LOG("xdraw_fill: 0x%x: %s", error->errnum, error->errmess); - return false; + return NSERROR_INVALID; } - return true; + return NSERROR_OK; } -bool ro_plot_path(const float *p, unsigned int n, colour fill, float width, - colour c, const float transform[6]) +/** + * Plots a path. + * + * Path plot consisting of cubic Bezier curves. Line and fill colour is + * controlled by the plot style. + * + * \param ctx The current redraw context. + * \param pstyle Style controlling the path plot. + * \param p elements of path + * \param n nunber of elements on path + * \param width The width of the path + * \param transform A transform to apply to the path. + * \return NSERROR_OK on success else error code. + */ +static nserror +ro_plot_path(const struct redraw_context *ctx, + const plot_style_t *pstyle, + const float *p, + unsigned int n, + float width, + const float transform[6]) { - static const draw_line_style line_style = { draw_JOIN_MITRED, - draw_CAP_BUTT, draw_CAP_BUTT, 0, 0x7fffffff, - 0, 0, 0, 0 }; + static const draw_line_style line_style = { + draw_JOIN_MITRED, + draw_CAP_BUTT, + draw_CAP_BUTT, + 0, 0x7fffffff, + 0, 0, 0, 0 + }; int *path = 0; unsigned int i; os_trfm trfm; os_error *error; - if (n == 0) - return true; + if (n == 0) { + return NSERROR_OK; + } if (p[0] != PLOTTER_PATH_MOVE) { LOG("path doesn't start with a move"); @@ -303,222 +542,159 @@ bool ro_plot_path(const float *p, unsigned int n, colour fill, float width, trfm.entries[2][0] = (ro_plot_origin_x + transform[4] * 2) * 256; trfm.entries[2][1] = (ro_plot_origin_y - transform[5] * 2) * 256; - if (fill != NS_TRANSPARENT) { - error = xcolourtrans_set_gcol(fill << 8, 0, + if (pstyle->fill_colour != NS_TRANSPARENT) { + error = xcolourtrans_set_gcol(pstyle->fill_colour << 8, 0, os_ACTION_OVERWRITE, 0, 0); if (error) { - LOG("xcolourtrans_set_gcol: 0x%x: %s", error->errnum, error->errmess); + LOG("xcolourtrans_set_gcol: 0x%x: %s", + error->errnum, error->errmess); goto error; } error = xdraw_fill((draw_path *) path, 0, &trfm, 0); if (error) { - LOG("xdraw_stroke: 0x%x: %s", error->errnum, error->errmess); + LOG("xdraw_stroke: 0x%x: %s", + error->errnum, error->errmess); goto error; } } - if (c != NS_TRANSPARENT) { - error = xcolourtrans_set_gcol(c << 8, 0, + if (pstyle->stroke_colour != NS_TRANSPARENT) { + error = xcolourtrans_set_gcol(pstyle->stroke_colour << 8, 0, os_ACTION_OVERWRITE, 0, 0); if (error) { - LOG("xcolourtrans_set_gcol: 0x%x: %s", error->errnum, error->errmess); + LOG("xcolourtrans_set_gcol: 0x%x: %s", + error->errnum, error->errmess); goto error; } error = xdraw_stroke((draw_path *) path, 0, &trfm, 0, width * 2 * 256, &line_style, 0); if (error) { - LOG("xdraw_stroke: 0x%x: %s", error->errnum, error->errmess); + LOG("xdraw_stroke: 0x%x: %s", + error->errnum, error->errmess); goto error; } } free(path); - return true; + return NSERROR_OK; error: free(path); - return false; + return NSERROR_INVALID; } - - -bool ro_plot_clip(const struct rect *clip) +/** + * Plot a bitmap + * + * Tiled plot of a bitmap image. (x,y) gives the top left + * coordinate of an explicitly placed tile. From this tile the + * image can repeat in all four directions -- up, down, left + * and right -- to the extents given by the current clip + * rectangle. + * + * The bitmap_flags say whether to tile in the x and y + * directions. If not tiling in x or y directions, the single + * image is plotted. The width and height give the dimensions + * the image is to be scaled to. + * + * \param ctx The current redraw context. + * \param bitmap The bitmap to plot + * \param x The x coordinate to plot the bitmap + * \param y The y coordiante to plot the bitmap + * \param width The width of area to plot the bitmap into + * \param height The height of area to plot the bitmap into + * \param bg the background colour to alpha blend into + * \param flags the flags controlling the type of plot operation + * \return NSERROR_OK on success else error code. + */ +static nserror +ro_plot_bitmap(const struct redraw_context *ctx, + struct bitmap *bitmap, + int x, int y, + int width, + int height, + colour bg, + bitmap_flags_t flags) { - os_error *error; - char buf[12]; - - int clip_x0 = ro_plot_origin_x + clip->x0 * 2; - int clip_y0 = ro_plot_origin_y - clip->y0 * 2 - 1; - int clip_x1 = ro_plot_origin_x + clip->x1 * 2 - 1; - int clip_y1 = ro_plot_origin_y - clip->y1 * 2; + const uint8_t *buffer; - if (clip_x1 < clip_x0 || clip_y0 < clip_y1) { - LOG("bad clip rectangle %i %i %i %i", clip_x0, clip_y0, clip_x1, clip_y1); - return false; + buffer = riscos_bitmap_get_buffer(bitmap); + if (!buffer) { + LOG("bitmap_get_buffer failed"); + return NSERROR_INVALID; } - buf[0] = os_VDU_SET_GRAPHICS_WINDOW; - buf[1] = clip_x0; - buf[2] = clip_x0 >> 8; - buf[3] = clip_y1; - buf[4] = clip_y1 >> 8; - buf[5] = clip_x1; - buf[6] = clip_x1 >> 8; - buf[7] = clip_y0; - buf[8] = clip_y0 >> 8; - - error = xos_writen(buf, 9); - if (error) { - LOG("xos_writen: 0x%x: %s", error->errnum, error->errmess); - return false; + if (!image_redraw(bitmap->sprite_area, + ro_plot_origin_x + x * 2, + ro_plot_origin_y - y * 2, + width, height, + bitmap->width, + bitmap->height, + bg, + flags & BITMAPF_REPEAT_X, flags & BITMAPF_REPEAT_Y, + flags & BITMAPF_REPEAT_X || flags & BITMAPF_REPEAT_Y, + riscos_bitmap_get_opaque(bitmap) ? IMAGE_PLOT_TINCT_OPAQUE : + IMAGE_PLOT_TINCT_ALPHA)) { + return NSERROR_INVALID; } - - return true; + return NSERROR_OK; } -bool ro_plot_text(int x, int y, const char *text, size_t length, - const plot_font_style_t *fstyle) +/** + * Text plotting. + * + * \param ctx The current redraw context. + * \param fstyle plot style for this text + * \param x x coordinate + * \param y y coordinate + * \param text UTF-8 string to plot + * \param length length of string, in bytes + * \return NSERROR_OK on success else error code. + */ +static nserror +ro_plot_text(const struct redraw_context *ctx, + const struct plot_font_style *fstyle, + int x, + int y, + const char *text, + size_t length) { os_error *error; error = xcolourtrans_set_font_colours(font_CURRENT, - fstyle->background << 8, fstyle->foreground << 8, + fstyle->background << 8, fstyle->foreground << 8, 14, 0, 0, 0); if (error) { - LOG("xcolourtrans_set_font_colours: 0x%x: %s", error->errnum, error->errmess); - return false; + LOG("xcolourtrans_set_font_colours: 0x%x: %s", + error->errnum, error->errmess); + return NSERROR_INVALID; } - return nsfont_paint(fstyle, text, length, + if (!nsfont_paint(fstyle, text, length, ro_plot_origin_x + x * 2, - ro_plot_origin_y - y * 2); -} - - -bool ro_plot_disc(int x, int y, int radius, const plot_style_t *style) -{ - os_error *error; - if (style->fill_type != PLOT_OP_TYPE_NONE) { - error = xcolourtrans_set_gcol(style->fill_colour << 8, 0, - os_ACTION_OVERWRITE, 0, 0); - if (error) { - LOG("xcolourtrans_set_gcol: 0x%x: %s", error->errnum, error->errmess); - return false; - } - error = xos_plot(os_MOVE_TO, - ro_plot_origin_x + x * 2, - ro_plot_origin_y - y * 2); - if (error) { - LOG("xos_plot: 0x%x: %s", error->errnum, error->errmess); - return false; - } - error = xos_plot(os_PLOT_CIRCLE | os_PLOT_BY, radius * 2, 0); - if (error) { - LOG("xos_plot: 0x%x: %s", error->errnum, error->errmess); - return false; - } - } - - if (style->stroke_type != PLOT_OP_TYPE_NONE) { - - error = xcolourtrans_set_gcol(style->stroke_colour << 8, 0, - os_ACTION_OVERWRITE, 0, 0); - if (error) { - LOG("xcolourtrans_set_gcol: 0x%x: %s", error->errnum, error->errmess); - return false; - } - error = xos_plot(os_MOVE_TO, - ro_plot_origin_x + x * 2, - ro_plot_origin_y - y * 2); - if (error) { - LOG("xos_plot: 0x%x: %s", error->errnum, error->errmess); - return false; - } - error = xos_plot(os_PLOT_CIRCLE_OUTLINE | os_PLOT_BY, - radius * 2, 0); - - if (error) { - LOG("xos_plot: 0x%x: %s", error->errnum, error->errmess); - return false; - } - } - return true; -} - -bool ro_plot_arc(int x, int y, int radius, int angle1, int angle2, const plot_style_t *style) -{ - os_error *error; - int sx, sy, ex, ey; - double t; - - x = ro_plot_origin_x + x * 2; - y = ro_plot_origin_y - y * 2; - radius <<= 1; - - error = xcolourtrans_set_gcol(style->fill_colour << 8, 0, - os_ACTION_OVERWRITE, 0, 0); - - if (error) { - LOG("xcolourtrans_set_gcol: 0x%x: %s", error->errnum, error->errmess); - return false; - } - - t = ((double)angle1 * M_PI) / 180.0; - sx = (x + (int)(radius * cos(t))); - sy = (y + (int)(radius * sin(t))); - - t = ((double)angle2 * M_PI) / 180.0; - ex = (x + (int)(radius * cos(t))); - ey = (y + (int)(radius * sin(t))); - - error = xos_plot(os_MOVE_TO, x, y); /* move to centre */ - if (error) { - LOG("xos_plot: 0x%x: %s", error->errnum, error->errmess); - return false; - } - - error = xos_plot(os_MOVE_TO, sx, sy); /* move to start */ - if (error) { - LOG("xos_plot: 0x%x: %s", error->errnum, error->errmess); - return false; - } - - error = xos_plot(os_PLOT_ARC | os_PLOT_TO, ex, ey); /* arc to end */ - if (error) { - LOG("xos_plot: 0x%x: %s", error->errnum, error->errmess); - return false; + ro_plot_origin_y - y * 2)) { + return NSERROR_INVALID; } - - return true; + return NSERROR_OK; } - -bool ro_plot_bitmap(int x, int y, int width, int height, - struct bitmap *bitmap, colour bg, - bitmap_flags_t flags) -{ - const uint8_t *buffer; - - buffer = riscos_bitmap_get_buffer(bitmap); - if (!buffer) { - LOG("bitmap_get_buffer failed"); - return false; - } - - return image_redraw(bitmap->sprite_area, - ro_plot_origin_x + x * 2, - ro_plot_origin_y - y * 2, - width, height, - bitmap->width, - bitmap->height, - bg, - flags & BITMAPF_REPEAT_X, flags & BITMAPF_REPEAT_Y, - flags & BITMAPF_REPEAT_X || flags & BITMAPF_REPEAT_Y, - riscos_bitmap_get_opaque(bitmap) ? IMAGE_PLOT_TINCT_OPAQUE : - IMAGE_PLOT_TINCT_ALPHA); -} +/** + * RISC OS plotter operation table + */ +const struct plotter_table ro_plotters = { + .rectangle = ro_plot_rectangle, + .line = ro_plot_line, + .polygon = ro_plot_polygon, + .clip = ro_plot_clip, + .text = ro_plot_text, + .disc = ro_plot_disc, + .arc = ro_plot_arc, + .bitmap = ro_plot_bitmap, + .path = ro_plot_path, + .option_knockout = true, +}; diff --git a/frontends/riscos/print.c b/frontends/riscos/print.c index 465627eea..1ccfc7f74 100644 --- a/frontends/riscos/print.c +++ b/frontends/riscos/print.c @@ -104,39 +104,12 @@ static void print_send_printsave(struct hlcache_handle *h); static bool print_send_printtypeknown(wimp_message *m); static bool print_document(struct gui_window *g, const char *filename); static const char *print_declare_fonts(struct hlcache_handle *h); -static bool print_fonts_plot_rectangle(int x0, int y0, int x1, int y1, const plot_style_t *style); -static bool print_fonts_plot_line(int x0, int y0, int x1, int y1, const plot_style_t *style); -static bool print_fonts_plot_polygon(const int *p, unsigned int n, const plot_style_t *style); -static bool print_fonts_plot_clip(const struct rect *clip); -static bool print_fonts_plot_text(int x, int y, const char *text, size_t length, - const plot_font_style_t *fstyle); -static bool print_fonts_plot_disc(int x, int y, int radius, const plot_style_t *style); -static bool print_fonts_plot_arc(int x, int y, int radius, int angle1, int angle2, const plot_style_t *style); -static bool print_fonts_plot_bitmap(int x, int y, int width, int height, - struct bitmap *bitmap, colour bg, - bitmap_flags_t flags); -static bool print_fonts_plot_path(const float *p, unsigned int n, colour fill, float width, - colour c, const float transform[6]); static void print_fonts_callback(void *context, const char *font_name, unsigned int font_size, const char *s8, unsigned short *s16, unsigned int n, int x, int y); -/** Plotter for print_declare_fonts(). All the functions do nothing except for - * print_fonts_plot_text, which records the fonts used. */ -static const struct plotter_table print_fonts_plotters = { - .rectangle = print_fonts_plot_rectangle, - .line = print_fonts_plot_line, - .polygon = print_fonts_plot_polygon, - .clip = print_fonts_plot_clip, - .text = print_fonts_plot_text, - .disc = print_fonts_plot_disc, - .arc = print_fonts_plot_arc, - .bitmap = print_fonts_plot_bitmap, - .path = print_fonts_plot_path, - .option_knockout = false, -}; /** @@ -780,6 +753,143 @@ error: } + + +static nserror +print_fonts_plot_clip(const struct redraw_context *ctx, const struct rect *clip) +{ + return NSERROR_OK; +} + +static nserror +print_fonts_plot_arc(const struct redraw_context *ctx, + const plot_style_t *style, + int x, int y, int radius, int angle1, int angle2) +{ + return NSERROR_OK; +} + +static nserror +print_fonts_plot_disc(const struct redraw_context *ctx, + const plot_style_t *style, + int x, int y, int radius) +{ + return NSERROR_OK; +} + +static nserror +print_fonts_plot_line(const struct redraw_context *ctx, + const plot_style_t *style, + const struct rect *line) +{ + return NSERROR_OK; +} + +static nserror +print_fonts_plot_rectangle(const struct redraw_context *ctx, + const plot_style_t *style, + const struct rect *rect) +{ + return NSERROR_OK; +} + +static nserror +print_fonts_plot_polygon(const struct redraw_context *ctx, + const plot_style_t *style, + const int *p, + unsigned int n) +{ + return NSERROR_OK; +} + +static nserror +print_fonts_plot_path(const struct redraw_context *ctx, + const plot_style_t *pstyle, + const float *p, + unsigned int n, + float width, + const float transform[6]) +{ + return NSERROR_OK; +} + +static nserror +print_fonts_plot_bitmap(const struct redraw_context *ctx, + struct bitmap *bitmap, + int x, int y, + int width, + int height, + colour bg, + bitmap_flags_t flags) +{ + return NSERROR_OK; +} + +/** + * text plotting during RO print font listing. + * + * \param ctx The current redraw context. + * \param fstyle plot style for this text + * \param x x coordinate + * \param y y coordinate + * \param text UTF-8 string to plot + * \param length length of string, in bytes + * \return NSERROR_OK on success else error code. + */ +static nserror +print_fonts_plot_text(const struct redraw_context *ctx, + const struct plot_font_style *fstyle, + int x, + int y, + const char *text, + size_t length) +{ + const char *font_family; + unsigned int font_size; + rufl_style font_style; + rufl_code code; + + nsfont_read_style(fstyle, &font_family, &font_size, &font_style); + + code = rufl_paint_callback(font_family, font_style, font_size, + text, length, 0, 0, print_fonts_callback, 0); + if (code != rufl_OK) { + if (code == rufl_FONT_MANAGER_ERROR) { + LOG("rufl_paint_callback: rufl_FONT_MANAGER_ERROR: ""0x%x: %s", + rufl_fm_error->errnum, rufl_fm_error->errmess); + print_fonts_error = rufl_fm_error->errmess; + } else { + LOG("rufl_paint_callback: 0x%x", code); + } + return NSERROR_INVALID; + } + if (print_fonts_error) + return NSERROR_INVALID; + + return NSERROR_OK; +} + + +/** + * Plotter table for print_declare_fonts(). + * + * All the functions do nothing except for print_fonts_plot_text, + * which records the fonts used. +*/ +static const struct plotter_table print_fonts_plotters = { + .rectangle = print_fonts_plot_rectangle, + .line = print_fonts_plot_line, + .polygon = print_fonts_plot_polygon, + .clip = print_fonts_plot_clip, + .text = print_fonts_plot_text, + .disc = print_fonts_plot_disc, + .arc = print_fonts_plot_arc, + .bitmap = print_fonts_plot_bitmap, + .path = print_fonts_plot_path, + .option_knockout = false, +}; + + /** * Declare fonts to the printer driver. * @@ -850,84 +960,6 @@ end: } -bool print_fonts_plot_rectangle(int x0, int y0, int x1, int y1, const plot_style_t *style) -{ - return true; -} - - -bool print_fonts_plot_line(int x0, int y0, int x1, int y1, const plot_style_t *style) -{ - return true; -} - -bool print_fonts_plot_polygon(const int *p, unsigned int n, const plot_style_t *style) -{ - return true; -} - - -bool print_fonts_plot_clip(const struct rect *clip) -{ - return true; -} - -bool print_fonts_plot_disc(int x, int y, int radius, const plot_style_t *style) -{ - return true; -} - -bool print_fonts_plot_arc(int x, int y, int radius, int angle1, int angle2, - const plot_style_t *style) -{ - return true; -} - -bool print_fonts_plot_bitmap(int x, int y, int width, int height, - struct bitmap *bitmap, colour bg, bitmap_flags_t flags) -{ - return true; -} - -bool print_fonts_plot_path(const float *p, unsigned int n, colour fill, float width, - colour c, const float transform[6]) -{ - return true; -} - - -/** - * Plotter for text plotting during font listing. - */ - -bool print_fonts_plot_text(int x, int y, const char *text, size_t length, - const plot_font_style_t *fstyle) -{ - const char *font_family; - unsigned int font_size; - rufl_style font_style; - rufl_code code; - - nsfont_read_style(fstyle, &font_family, &font_size, &font_style); - - code = rufl_paint_callback(font_family, font_style, font_size, - text, length, 0, 0, print_fonts_callback, 0); - if (code != rufl_OK) { - if (code == rufl_FONT_MANAGER_ERROR) { - LOG("rufl_paint_callback: rufl_FONT_MANAGER_ERROR: ""0x%x: %s", rufl_fm_error->errnum, rufl_fm_error->errmess); - print_fonts_error = rufl_fm_error->errmess; - } else { - LOG("rufl_paint_callback: 0x%x", code); - } - return false; - } - if (print_fonts_error) - return false; - - return true; -} - - /** * Callback for print_fonts_plot_text(). * diff --git a/frontends/riscos/save_draw.c b/frontends/riscos/save_draw.c index 7e6c9462e..1e0bc1ec6 100644 --- a/frontends/riscos/save_draw.c +++ b/frontends/riscos/save_draw.c @@ -18,7 +18,8 @@ * along with this program. If not, see . */ -/** \file +/** + * \file * Export a content as a DrawFile (implementation). */ @@ -39,38 +40,6 @@ #include "riscos/save_draw.h" #include "riscos/font.h" -static bool ro_save_draw_rectangle(int x0, int y0, int x1, int y1, const plot_style_t *style); -static bool ro_save_draw_line(int x0, int y0, int x1, int y1, const plot_style_t *style); -static bool ro_save_draw_polygon(const int *p, unsigned int n, const plot_style_t *style); -static bool ro_save_draw_path(const float *p, unsigned int n, colour fill, - float width, colour c, const float transform[6]); -static bool ro_save_draw_clip(const struct rect *clip); -static bool ro_save_draw_text(int x, int y, const char *text, size_t length, - const plot_font_style_t *fstyle); -static bool ro_save_draw_disc(int x, int y, int radius, const plot_style_t *style); -static bool ro_save_draw_arc(int x, int y, int radius, int angle1, int angle2, - const plot_style_t *style); -static bool ro_save_draw_bitmap(int x, int y, int width, int height, - struct bitmap *bitmap, colour bg, bitmap_flags_t flags); -static bool ro_save_draw_group_start(const char *name); -static bool ro_save_draw_group_end(void); -static bool ro_save_draw_error(pencil_code code); - - -static const struct plotter_table ro_save_draw_plotters = { - .rectangle = ro_save_draw_rectangle, - .line = ro_save_draw_line, - .polygon = ro_save_draw_polygon, - .clip = ro_save_draw_clip, - .text = ro_save_draw_text, - .disc = ro_save_draw_disc, - .arc = ro_save_draw_arc, - .bitmap = ro_save_draw_bitmap, - .group_start = ro_save_draw_group_start, - .group_end = ro_save_draw_group_end, - .path = ro_save_draw_path, - .option_knockout = false, -}; static struct pencil_diagram *ro_save_draw_diagram; static int ro_save_draw_width; @@ -78,157 +47,229 @@ static int ro_save_draw_height; /** - * Export a content as a DrawFile. + * Report an error from pencil. * - * \param h content to export - * \param path path to save DrawFile as - * \return true on success, false on error and error reported + * \param code error code + * \return false */ - -bool save_as_draw(struct hlcache_handle *h, const char *path) +static nserror ro_save_draw_error(pencil_code code) { - pencil_code code; - char *drawfile_buffer; - struct rect clip; - struct content_redraw_data data; - size_t drawfile_size; - os_error *error; - struct redraw_context ctx = { - .interactive = false, - .background_images = true, - .plot = &ro_save_draw_plotters - }; + LOG("code %i", code); - ro_save_draw_diagram = pencil_create(); - if (!ro_save_draw_diagram) { + switch (code) { + case pencil_OK: + assert(0); + break; + + case pencil_OUT_OF_MEMORY: ro_warn_user("NoMemory", 0); - return false; + break; + + case pencil_FONT_MANAGER_ERROR: + ro_warn_user("SaveError", rufl_fm_error->errmess); + break; + + case pencil_FONT_NOT_FOUND: + case pencil_IO_ERROR: + case pencil_IO_EOF: + ro_warn_user("SaveError", "generating the DrawFile failed"); + break; } - ro_save_draw_width = content_get_width(h); - ro_save_draw_height = content_get_height(h); + return NSERROR_INVALID; +} - clip.x0 = clip.y0 = INT_MIN; - clip.x1 = clip.y1 = INT_MAX; +/** + * \brief Sets a clip rectangle for subsequent plot operations. + * + * \param ctx The current redraw context. + * \param clip The rectangle to limit all subsequent plot + * operations within. + * \return NSERROR_OK on success else error code. + */ +static nserror +ro_save_draw_clip(const struct redraw_context *ctx, const struct rect *clip) +{ + return NSERROR_OK; +} - data.x = 0; - data.y = -ro_save_draw_height; - data.width = ro_save_draw_width; - data.height = ro_save_draw_height; - data.background_colour = 0xFFFFFF; - data.scale = 1; - data.repeat_x = false; - data.repeat_y = false; - if (!content_redraw(h, &data, &clip, &ctx)) { - pencil_free(ro_save_draw_diagram); - return false; - } +/** + * Plots an arc + * + * plot an arc segment around (x,y), anticlockwise from angle1 + * to angle2. Angles are measured anticlockwise from + * horizontal, in degrees. + * + * \param ctx The current redraw context. + * \param pstyle Style controlling the arc plot. + * \param x The x coordinate of the arc. + * \param y The y coordinate of the arc. + * \param radius The radius of the arc. + * \param angle1 The start angle of the arc. + * \param angle2 The finish angle of the arc. + * \return NSERROR_OK on success else error code. + */ +static nserror +ro_save_draw_arc(const struct redraw_context *ctx, + const plot_style_t *style, + int x, int y, int radius, int angle1, int angle2) +{ + return NSERROR_OK; +} - /*pencil_dump(ro_save_draw_diagram);*/ - code = pencil_save_drawfile(ro_save_draw_diagram, "NetSurf", - &drawfile_buffer, &drawfile_size); - if (code != pencil_OK) { - ro_warn_user("SaveError", 0); - pencil_free(ro_save_draw_diagram); - return false; - } - assert(drawfile_buffer); +/** + * Plots a circle + * + * Plot a circle centered on (x,y), which is optionally filled. + * + * \param ctx The current redraw context. + * \param pstyle Style controlling the circle plot. + * \param x The x coordinate of the circle. + * \param y The y coordinate of the circle. + * \param radius The radius of the circle. + * \return NSERROR_OK on success else error code. + */ +static nserror +ro_save_draw_disc(const struct redraw_context *ctx, + const plot_style_t *style, + int x, int y, int radius) +{ + return NSERROR_OK; +} - error = xosfile_save_stamped(path, osfile_TYPE_DRAW, - (byte *) drawfile_buffer, - (byte *) drawfile_buffer + drawfile_size); - if (error) { - LOG("xosfile_save_stamped failed: 0x%x: %s", error->errnum, error->errmess); - ro_warn_user("SaveError", error->errmess); - pencil_free(ro_save_draw_diagram); - return false; - } - pencil_free(ro_save_draw_diagram); +/** + * Plots a line + * + * plot a line from (x0,y0) to (x1,y1). Coordinates are at + * centre of line width/thickness. + * + * \param ctx The current redraw context. + * \param pstyle Style controlling the line plot. + * \param line A rectangle defining the line to be drawn + * \return NSERROR_OK on success else error code. + */ +static nserror +ro_save_draw_line(const struct redraw_context *ctx, + const plot_style_t *style, + const struct rect *line) +{ + pencil_code code; + const int path[] = { + draw_MOVE_TO, line->x0 * 2, -line->y0 * 2 - 1, + draw_LINE_TO, line->x1 * 2, -line->y1 * 2 - 1, + draw_END_PATH + }; - return true; + code = pencil_path(ro_save_draw_diagram, + path, + sizeof path / sizeof path[0], + pencil_TRANSPARENT, + style->stroke_colour << 8, + style->stroke_width, + pencil_JOIN_MITRED, + pencil_CAP_BUTT, + pencil_CAP_BUTT, + 0, 0, false, + pencil_SOLID); + if (code != pencil_OK) + return ro_save_draw_error(code); + + return NSERROR_OK; } -bool ro_save_draw_rectangle(int x0, int y0, int x1, int y1, const plot_style_t *style) + +/** + * Plots a rectangle. + * + * The rectangle can be filled an outline or both controlled + * by the plot style The line can be solid, dotted or + * dashed. Top left corner at (x0,y0) and rectangle has given + * width and height. + * + * \param ctx The current redraw context. + * \param pstyle Style controlling the rectangle plot. + * \param rect A rectangle defining the line to be drawn + * \return NSERROR_OK on success else error code. + */ +static nserror +ro_save_draw_rectangle(const struct redraw_context *ctx, + const plot_style_t *style, + const struct rect *rect) { pencil_code code; - const int path[] = { draw_MOVE_TO, x0 * 2, -y0 * 2 - 1, - draw_LINE_TO, x1 * 2, -y0 * 2 - 1, - draw_LINE_TO, x1 * 2, -y1 * 2 - 1, - draw_LINE_TO, x0 * 2, -y1 * 2 - 1, - draw_CLOSE_LINE, - draw_END_PATH }; + const int path[] = { + draw_MOVE_TO, rect->x0 * 2, -rect->y0 * 2 - 1, + draw_LINE_TO, rect->x1 * 2, -rect->y0 * 2 - 1, + draw_LINE_TO, rect->x1 * 2, -rect->y1 * 2 - 1, + draw_LINE_TO, rect->x0 * 2, -rect->y1 * 2 - 1, + draw_CLOSE_LINE, + draw_END_PATH + }; - if (style->fill_type != PLOT_OP_TYPE_NONE) { + if (style->fill_type != PLOT_OP_TYPE_NONE) { - code = pencil_path(ro_save_draw_diagram, + code = pencil_path(ro_save_draw_diagram, path, sizeof path / sizeof path[0], - style->fill_colour << 8, - pencil_TRANSPARENT, - 0, + style->fill_colour << 8, + pencil_TRANSPARENT, + 0, pencil_JOIN_MITRED, - pencil_CAP_BUTT, - pencil_CAP_BUTT, - 0, - 0, + pencil_CAP_BUTT, + pencil_CAP_BUTT, + 0, + 0, false, pencil_SOLID); if (code != pencil_OK) return ro_save_draw_error(code); } - if (style->stroke_type != PLOT_OP_TYPE_NONE) { + if (style->stroke_type != PLOT_OP_TYPE_NONE) { - code = pencil_path(ro_save_draw_diagram, + code = pencil_path(ro_save_draw_diagram, path, sizeof path / sizeof path[0], - pencil_TRANSPARENT, - style->stroke_colour << 8, - style->stroke_width, + pencil_TRANSPARENT, + style->stroke_colour << 8, + style->stroke_width, pencil_JOIN_MITRED, - pencil_CAP_BUTT, - pencil_CAP_BUTT, - 0, - 0, + pencil_CAP_BUTT, + pencil_CAP_BUTT, + 0, + 0, false, pencil_SOLID); if (code != pencil_OK) return ro_save_draw_error(code); } - return true; -} - - -bool ro_save_draw_line(int x0, int y0, int x1, int y1, const plot_style_t *style) -{ - pencil_code code; - const int path[] = { draw_MOVE_TO, x0 * 2, -y0 * 2 - 1, - draw_LINE_TO, x1 * 2, -y1 * 2 - 1, - draw_END_PATH }; - - code = pencil_path(ro_save_draw_diagram, - path, - sizeof path / sizeof path[0], - pencil_TRANSPARENT, - style->stroke_colour << 8, - style->stroke_width, - pencil_JOIN_MITRED, - pencil_CAP_BUTT, - pencil_CAP_BUTT, - 0, 0, false, - pencil_SOLID); - if (code != pencil_OK) - return ro_save_draw_error(code); - - return true; + return NSERROR_OK; } -bool ro_save_draw_polygon(const int *p, unsigned int n, const plot_style_t *style) +/** + * Plot a polygon + * + * Plots a filled polygon with straight lines between + * points. The lines around the edge of the ploygon are not + * plotted. The polygon is filled with the non-zero winding + * rule. + * + * \param ctx The current redraw context. + * \param pstyle Style controlling the polygon plot. + * \param p verticies of polygon + * \param n number of verticies. + * \return NSERROR_OK on success else error code. + */ +static nserror +ro_save_draw_polygon(const struct redraw_context *ctx, + const plot_style_t *style, + const int *p, + unsigned int n) { pencil_code code; int path[n * 3 + 1]; @@ -242,44 +283,66 @@ bool ro_save_draw_polygon(const int *p, unsigned int n, const plot_style_t *styl path[0] = draw_MOVE_TO; path[n * 3] = draw_END_PATH; - code = pencil_path(ro_save_draw_diagram, + code = pencil_path(ro_save_draw_diagram, path, n * 3 + 1, - style->fill_colour << 8, - pencil_TRANSPARENT, - 0, + style->fill_colour << 8, + pencil_TRANSPARENT, + 0, pencil_JOIN_MITRED, - pencil_CAP_BUTT, - pencil_CAP_BUTT, - 0, - 0, + pencil_CAP_BUTT, + pencil_CAP_BUTT, + 0, + 0, false, pencil_SOLID); if (code != pencil_OK) return ro_save_draw_error(code); - return true; + return NSERROR_OK; } -bool ro_save_draw_path(const float *p, unsigned int n, colour fill, - float width, colour c, const float transform[6]) +/** + * Plots a path. + * + * Path plot consisting of cubic Bezier curves. Line and fill colour is + * controlled by the plot style. + * + * \param ctx The current redraw context. + * \param pstyle Style controlling the path plot. + * \param p elements of path + * \param n nunber of elements on path + * \param width The width of the path + * \param transform A transform to apply to the path. + * \return NSERROR_OK on success else error code. + */ +static nserror +ro_save_draw_path(const struct redraw_context *ctx, + const plot_style_t *pstyle, + const float *p, + unsigned int n, + float width, + const float transform[6]) { + pencil_code code; + int *path; + unsigned int i; + bool empty_path = true; + if (n == 0) - return true; + return NSERROR_OK; if (p[0] != PLOTTER_PATH_MOVE) { LOG("path doesn't start with a move"); - return false; + return NSERROR_INVALID; } - int *path = malloc(sizeof *path * (n + 10)); + path = malloc(sizeof *path * (n + 10)); if (!path) { LOG("out of memory"); - return false; + return NSERROR_INVALID; } - unsigned int i; - bool empty_path = true; for (i = 0; i < n; ) { if (p[i] == PLOTTER_PATH_MOVE) { path[i] = draw_MOVE_TO; @@ -328,40 +391,111 @@ bool ro_save_draw_path(const float *p, unsigned int n, colour fill, } else { LOG("bad path command %f", p[i]); free(path); - return false; + return NSERROR_INVALID; } } path[i] = draw_END_PATH; if (empty_path) { free(path); - return true; + return NSERROR_OK; } - pencil_code code = pencil_path(ro_save_draw_diagram, path, i + 1, - fill == NS_TRANSPARENT ? pencil_TRANSPARENT : fill << 8, - c == NS_TRANSPARENT ? pencil_TRANSPARENT : c << 8, - width, pencil_JOIN_MITRED, - pencil_CAP_BUTT, pencil_CAP_BUTT, 0, 0, false, - pencil_SOLID); + code = pencil_path(ro_save_draw_diagram, + path, i + 1, + pstyle->fill_colour == NS_TRANSPARENT ? + pencil_TRANSPARENT : + pstyle->fill_colour << 8, + pstyle->stroke_colour == NS_TRANSPARENT ? + pencil_TRANSPARENT : + pstyle->stroke_colour << 8, + width, pencil_JOIN_MITRED, + pencil_CAP_BUTT, + pencil_CAP_BUTT, + 0, + 0, + false, + pencil_SOLID); free(path); if (code != pencil_OK) return ro_save_draw_error(code); - return true; + return NSERROR_OK; } +/** + * Plot a bitmap + * + * Tiled plot of a bitmap image. (x,y) gives the top left + * coordinate of an explicitly placed tile. From this tile the + * image can repeat in all four directions -- up, down, left + * and right -- to the extents given by the current clip + * rectangle. + * + * The bitmap_flags say whether to tile in the x and y + * directions. If not tiling in x or y directions, the single + * image is plotted. The width and height give the dimensions + * the image is to be scaled to. + * + * \param ctx The current redraw context. + * \param bitmap The bitmap to plot + * \param x The x coordinate to plot the bitmap + * \param y The y coordiante to plot the bitmap + * \param width The width of area to plot the bitmap into + * \param height The height of area to plot the bitmap into + * \param bg the background colour to alpha blend into + * \param flags the flags controlling the type of plot operation + * \return NSERROR_OK on success else error code. + */ +static nserror +ro_save_draw_bitmap(const struct redraw_context *ctx, + struct bitmap *bitmap, + int x, int y, + int width, + int height, + colour bg, + bitmap_flags_t flags) +{ + pencil_code code; + const uint8_t *buffer; + buffer = riscos_bitmap_get_buffer(bitmap); + if (!buffer) { + ro_warn_user("NoMemory", 0); + return NSERROR_INVALID; + } -bool ro_save_draw_clip(const struct rect *clip) -{ - return true; + code = pencil_sprite(ro_save_draw_diagram, + x * 2, (-y - height) * 2, + width * 2, height * 2, + ((char *) bitmap->sprite_area) + + bitmap->sprite_area->first); + if (code != pencil_OK) + return ro_save_draw_error(code); + + return NSERROR_OK; } -bool ro_save_draw_text(int x, int y, const char *text, size_t length, - const plot_font_style_t *fstyle) +/** + * Text plotting. + * + * \param ctx The current redraw context. + * \param fstyle plot style for this text + * \param x x coordinate + * \param y y coordinate + * \param text UTF-8 string to plot + * \param length length of string, in bytes + * \return NSERROR_OK on success else error code. + */ +static nserror +ro_save_draw_text(const struct redraw_context *ctx, + const struct plot_font_style *fstyle, + int x, + int y, + const char *text, + size_t length) { pencil_code code; const char *font_family; @@ -371,102 +505,135 @@ bool ro_save_draw_text(int x, int y, const char *text, size_t length, nsfont_read_style(fstyle, &font_family, &font_size, &font_style); code = pencil_text(ro_save_draw_diagram, x * 2, -y * 2, font_family, - font_style, font_size, text, length, + font_style, font_size, text, length, fstyle->foreground << 8); if (code != pencil_OK) return ro_save_draw_error(code); - return true; + return NSERROR_OK; } -bool ro_save_draw_disc(int x, int y, int radius, const plot_style_t *style) -{ - return true; -} - -bool ro_save_draw_arc(int x, int y, int radius, int angle1, int angle2, - const plot_style_t *style) -{ - return true; -} - -bool ro_save_draw_bitmap(int x, int y, int width, int height, - struct bitmap *bitmap, colour bg, bitmap_flags_t flags) +/** + * Start of a group of objects. + * + * \param ctx The current redraw context. + * \return NSERROR_OK on success else error code. + */ +static nserror +ro_save_draw_group_start(const struct redraw_context *ctx, const char *name) { pencil_code code; - const uint8_t *buffer; - - buffer = riscos_bitmap_get_buffer(bitmap); - if (!buffer) { - ro_warn_user("NoMemory", 0); - return false; - } - code = pencil_sprite(ro_save_draw_diagram, x * 2, (-y - height) * 2, - width * 2, height * 2, - ((char *) bitmap->sprite_area) + - bitmap->sprite_area->first); + code = pencil_group_start(ro_save_draw_diagram, name); if (code != pencil_OK) return ro_save_draw_error(code); - return true; + return NSERROR_OK; } -bool ro_save_draw_group_start(const char *name) +/** + * End of the most recently started group. + * + * \param ctx The current redraw context. + * \return NSERROR_OK on success else error code. + */ +static nserror +ro_save_draw_group_end(const struct redraw_context *ctx) { pencil_code code; - code = pencil_group_start(ro_save_draw_diagram, name); + code = pencil_group_end(ro_save_draw_diagram); if (code != pencil_OK) return ro_save_draw_error(code); - return true; + return NSERROR_OK; } -bool ro_save_draw_group_end(void) +static const struct plotter_table ro_save_draw_plotters = { + .rectangle = ro_save_draw_rectangle, + .line = ro_save_draw_line, + .polygon = ro_save_draw_polygon, + .clip = ro_save_draw_clip, + .text = ro_save_draw_text, + .disc = ro_save_draw_disc, + .arc = ro_save_draw_arc, + .bitmap = ro_save_draw_bitmap, + .group_start = ro_save_draw_group_start, + .group_end = ro_save_draw_group_end, + .path = ro_save_draw_path, + .option_knockout = false, +}; + + +/* exported interface documented in save_draw.h */ +bool save_as_draw(struct hlcache_handle *h, const char *path) { pencil_code code; + char *drawfile_buffer; + struct rect clip; + struct content_redraw_data data; + size_t drawfile_size; + os_error *error; + struct redraw_context ctx = { + .interactive = false, + .background_images = true, + .plot = &ro_save_draw_plotters + }; - code = pencil_group_end(ro_save_draw_diagram); - if (code != pencil_OK) - return ro_save_draw_error(code); + ro_save_draw_diagram = pencil_create(); + if (!ro_save_draw_diagram) { + ro_warn_user("NoMemory", 0); + return false; + } - return true; -} + ro_save_draw_width = content_get_width(h); + ro_save_draw_height = content_get_height(h); + clip.x0 = clip.y0 = INT_MIN; + clip.x1 = clip.y1 = INT_MAX; -/** - * Report an error from pencil. - * - * \param code error code - * \return false - */ + data.x = 0; + data.y = -ro_save_draw_height; + data.width = ro_save_draw_width; + data.height = ro_save_draw_height; + data.background_colour = 0xFFFFFF; + data.scale = 1; + data.repeat_x = false; + data.repeat_y = false; -bool ro_save_draw_error(pencil_code code) -{ - LOG("code %i", code); + if (!content_redraw(h, &data, &clip, &ctx)) { + pencil_free(ro_save_draw_diagram); + return false; + } - switch (code) { - case pencil_OK: - assert(0); - break; - case pencil_OUT_OF_MEMORY: - ro_warn_user("NoMemory", 0); - break; - case pencil_FONT_MANAGER_ERROR: - ro_warn_user("SaveError", rufl_fm_error->errmess); - break; - case pencil_FONT_NOT_FOUND: - case pencil_IO_ERROR: - case pencil_IO_EOF: - ro_warn_user("SaveError", "generating the DrawFile failed"); - break; + /*pencil_dump(ro_save_draw_diagram);*/ + + code = pencil_save_drawfile(ro_save_draw_diagram, "NetSurf", + &drawfile_buffer, &drawfile_size); + if (code != pencil_OK) { + ro_warn_user("SaveError", 0); + pencil_free(ro_save_draw_diagram); + return false; } + assert(drawfile_buffer); - return false; + error = xosfile_save_stamped(path, osfile_TYPE_DRAW, + (byte *) drawfile_buffer, + (byte *) drawfile_buffer + drawfile_size); + if (error) { + LOG("xosfile_save_stamped failed: 0x%x: %s", + error->errnum, error->errmess); + ro_warn_user("SaveError", error->errmess); + pencil_free(ro_save_draw_diagram); + return false; + } + + pencil_free(ro_save_draw_diagram); + + return true; } #endif diff --git a/frontends/riscos/save_draw.h b/frontends/riscos/save_draw.h index 7ae447790..99662e371 100644 --- a/frontends/riscos/save_draw.h +++ b/frontends/riscos/save_draw.h @@ -24,6 +24,13 @@ #include struct hlcache_handle; +/** + * Export a content as a DrawFile. + * + * \param h content to export + * \param path path to save DrawFile as + * \return true on success, false on error and error reported + */ bool save_as_draw(struct hlcache_handle *h, const char *path); #endif -- cgit v1.2.3 From 0f43b2327063af238ab1eb5f94c3235f4c9347f6 Mon Sep 17 00:00:00 2001 From: Vincent Sanders Date: Thu, 9 Feb 2017 09:56:37 +0000 Subject: update monkey plotters to new API --- frontends/monkey/plot.c | 258 +++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 213 insertions(+), 45 deletions(-) diff --git a/frontends/monkey/plot.c b/frontends/monkey/plot.c index bd94e7551..9eb40acba 100644 --- a/frontends/monkey/plot.c +++ b/frontends/monkey/plot.c @@ -19,82 +19,250 @@ #include #include "utils/utils.h" +#include "utils/errors.h" #include "netsurf/plotters.h" -static bool -monkey_plot_disc(int x, int y, int radius, const plot_style_t *style) +/** + * \brief Sets a clip rectangle for subsequent plot operations. + * + * \param ctx The current redraw context. + * \param clip The rectangle to limit all subsequent plot + * operations within. + * \return NSERROR_OK on success else error code. + */ +static nserror +monkey_plot_clip(const struct redraw_context *ctx, const struct rect *clip) { - return true; + fprintf(stdout, + "PLOT CLIP X0 %d Y0 %d X1 %d Y1 %d\n", + clip->x0, clip->y0, clip->x1, clip->y1); + return NSERROR_OK; } -static bool -monkey_plot_arc(int x, int y, int radius, int angle1, int angle2, const plot_style_t *style) + +/** + * Plots an arc + * + * plot an arc segment around (x,y), anticlockwise from angle1 + * to angle2. Angles are measured anticlockwise from + * horizontal, in degrees. + * + * \param ctx The current redraw context. + * \param pstyle Style controlling the arc plot. + * \param x The x coordinate of the arc. + * \param y The y coordinate of the arc. + * \param radius The radius of the arc. + * \param angle1 The start angle of the arc. + * \param angle2 The finish angle of the arc. + * \return NSERROR_OK on success else error code. + */ +static nserror +monkey_plot_arc(const struct redraw_context *ctx, + const plot_style_t *style, + int x, int y, int radius, int angle1, int angle2) { - return true; + fprintf(stdout, + "PLOT ARC X %d Y %d RADIUS %d ANGLE1 %d ANGLE2 %d\n", + x, y, radius, angle1, angle2); + return NSERROR_OK; } -static bool -monkey_plot_polygon(const int *p, unsigned int n, const plot_style_t *style) + +/** + * Plots a circle + * + * Plot a circle centered on (x,y), which is optionally filled. + * + * \param ctx The current redraw context. + * \param pstyle Style controlling the circle plot. + * \param x x coordinate of circle centre. + * \param y y coordinate of circle centre. + * \param radius circle radius. + * \return NSERROR_OK on success else error code. + */ +static nserror +monkey_plot_disc(const struct redraw_context *ctx, + const plot_style_t *style, + int x, int y, int radius) { - return true; + fprintf(stdout, + "PLOT DISC X %d Y %d RADIUS %d\n", + x, y, radius); + return NSERROR_OK; } -static bool -monkey_plot_text(int x, int y, const char *text, size_t length, - const plot_font_style_t *fstyle) +/** + * Plots a line + * + * plot a line from (x0,y0) to (x1,y1). Coordinates are at + * centre of line width/thickness. + * + * \param ctx The current redraw context. + * \param pstyle Style controlling the line plot. + * \param line A rectangle defining the line to be drawn + * \return NSERROR_OK on success else error code. + */ +static nserror +monkey_plot_line(const struct redraw_context *ctx, + const plot_style_t *style, + const struct rect *line) { - fprintf(stdout, "PLOT TEXT X %d Y %d STR %*s\n", x, y, (int)length, text); - return true; + fprintf(stdout, + "PLOT LINE X0 %d Y0 %d X1 %d Y1 %d\n", + line->x0, line->y0, line->x1, line->y1); + return NSERROR_OK; } -static bool -monkey_plot_bitmap(int x, int y, - int width, int height, - struct bitmap *bitmap, colour bg, - bitmap_flags_t flags) + +/** + * Plots a rectangle. + * + * The rectangle can be filled an outline or both controlled + * by the plot style The line can be solid, dotted or + * dashed. Top left corner at (x0,y0) and rectangle has given + * width and height. + * + * \param ctx The current redraw context. + * \param pstyle Style controlling the rectangle plot. + * \param rect A rectangle defining the line to be drawn + * \return NSERROR_OK on success else error code. + */ +static nserror +monkey_plot_rectangle(const struct redraw_context *ctx, + const plot_style_t *style, + const struct rect *rect) { - fprintf(stdout, "PLOT BITMAP X %d Y %d WIDTH %d HEIGHT %d\n", - x, y, width, height); - return true; + fprintf(stdout, + "PLOT RECT X0 %d Y0 %d X1 %d Y1 %d\n", + rect->x0, rect->y0, rect->x1, rect->y1); + return NSERROR_OK; } -static bool -monkey_plot_rectangle(int x0, int y0, int x1, int y1, const plot_style_t *style) + +/** + * Plot a polygon + * + * Plots a filled polygon with straight lines between + * points. The lines around the edge of the ploygon are not + * plotted. The polygon is filled with the non-zero winding + * rule. + * + * \param ctx The current redraw context. + * \param pstyle Style controlling the polygon plot. + * \param p verticies of polygon + * \param n number of verticies. + * \return NSERROR_OK on success else error code. + */ +static nserror +monkey_plot_polygon(const struct redraw_context *ctx, + const plot_style_t *style, + const int *p, + unsigned int n) { - fprintf(stdout, "PLOT RECT X0 %d Y0 %d X1 %d Y1 %d\n", - x0, y0, x1, y1); - return true; + fprintf(stdout, + "PLOT POLYGON VERTICIES %d\n", + n); + return NSERROR_OK; } -static bool -monkey_plot_line(int x0, int y0, int x1, int y1, const plot_style_t *style) + +/** + * Plots a path. + * + * Path plot consisting of cubic Bezier curves. Line and fill colour is + * controlled by the plot style. + * + * \param ctx The current redraw context. + * \param pstyle Style controlling the path plot. + * \param p elements of path + * \param n nunber of elements on path + * \param width The width of the path + * \param transform A transform to apply to the path. + * \return NSERROR_OK on success else error code. + */ +static nserror +monkey_plot_path(const struct redraw_context *ctx, + const plot_style_t *pstyle, + const float *p, + unsigned int n, + float width, + const float transform[6]) { - fprintf(stdout, "PLOT LINE X0 %d Y0 %d X1 %d Y1 %d\n", - x0, y0, x1, y1); - return true; + fprintf(stdout, + "PLOT PATH VERTICIES %d WIDTH %f\n", + n, width); + return NSERROR_OK; } -static bool -monkey_plot_path(const float *p, - unsigned int n, - colour fill, - float width, - colour c, - const float transform[6]) +/** + * Plot a bitmap + * + * Tiled plot of a bitmap image. (x,y) gives the top left + * coordinate of an explicitly placed tile. From this tile the + * image can repeat in all four directions -- up, down, left + * and right -- to the extents given by the current clip + * rectangle. + * + * The bitmap_flags say whether to tile in the x and y + * directions. If not tiling in x or y directions, the single + * image is plotted. The width and height give the dimensions + * the image is to be scaled to. + * + * \param ctx The current redraw context. + * \param bitmap The bitmap to plot + * \param x The x coordinate to plot the bitmap + * \param y The y coordiante to plot the bitmap + * \param width The width of area to plot the bitmap into + * \param height The height of area to plot the bitmap into + * \param bg the background colour to alpha blend into + * \param flags the flags controlling the type of plot operation + * \return NSERROR_OK on success else error code. + */ +static nserror +monkey_plot_bitmap(const struct redraw_context *ctx, + struct bitmap *bitmap, + int x, int y, + int width, + int height, + colour bg, + bitmap_flags_t flags) { - return true; + fprintf(stdout, + "PLOT BITMAP X %d Y %d WIDTH %d HEIGHT %d\n", + x, y, width, height); + return NSERROR_OK; } -static bool -monkey_plot_clip(const struct rect *clip) + +/** + * Text plotting. + * + * \param ctx The current redraw context. + * \param fstyle plot style for this text + * \param x x coordinate + * \param y y coordinate + * \param text UTF-8 string to plot + * \param length length of string, in bytes + * \return NSERROR_OK on success else error code. + */ +static nserror +monkey_plot_text(const struct redraw_context *ctx, + const struct plot_font_style *fstyle, + int x, + int y, + const char *text, + size_t length) { - fprintf(stdout, "PLOT CLIP X0 %d Y0 %d X1 %d Y1 %d\n", - clip->x0, clip->y0, clip->x1, clip->y1); - return true; + fprintf(stdout, + "PLOT TEXT X %d Y %d STR %*s\n", + x, y, (int)length, text); + return NSERROR_OK; } + +/** monkey plotter operations table */ static const struct plotter_table plotters = { .clip = monkey_plot_clip, .arc = monkey_plot_arc, -- cgit v1.2.3 From 386951ecfc220748b81c53f3c736f2fc08686b78 Mon Sep 17 00:00:00 2001 From: Vincent Sanders Date: Thu, 9 Feb 2017 12:02:28 +0000 Subject: update framebuffer to new plotter API --- frontends/framebuffer/fbtk/text.c | 28 +- frontends/framebuffer/framebuffer.c | 606 +++++++++++++++++++++++------------- 2 files changed, 416 insertions(+), 218 deletions(-) diff --git a/frontends/framebuffer/fbtk/text.c b/frontends/framebuffer/fbtk/text.c index 00dcba491..31417c2e0 100644 --- a/frontends/framebuffer/fbtk/text.c +++ b/frontends/framebuffer/fbtk/text.c @@ -98,6 +98,11 @@ fb_redraw_text(fbtk_widget_t *widget, fbtk_callback_info *cbi ) int padding; int scroll = 0; bool caret = false; + struct redraw_context ctx = { + .interactive = true, + .background_images = true, + .plot = &fb_plotters + }; fb_text_font_style(widget, &fh, &padding, &font_style); @@ -142,8 +147,11 @@ fb_redraw_text(fbtk_widget_t *widget, fbtk_callback_info *cbi ) } /* Call the fb text plotting, baseline is 3/4 down the font */ - fb_plotters.text(x, y, widget->u.text.text, - widget->u.text.len, &font_style); + ctx.plot->text(&ctx, + &font_style, + x, y, + widget->u.text.text, + widget->u.text.len); } if (caret) { @@ -209,6 +217,11 @@ fb_redraw_text_button(fbtk_widget_t *widget, fbtk_callback_info *cbi ) int fh; int border; fbtk_widget_t *root = fbtk_get_root_widget(widget); + struct redraw_context ctx = { + .interactive = true, + .background_images = true, + .plot = &fb_plotters + }; fb_text_font_style(widget, &fh, &border, &font_style); @@ -256,11 +269,12 @@ fb_redraw_text_button(fbtk_widget_t *widget, fbtk_callback_info *cbi ) if (widget->u.text.text != NULL) { /* Call the fb text plotting, baseline is 3/4 down the font */ - fb_plotters.text(bbox.x0 + border, - bbox.y0 + ((fh * 3) / 4) + border, - widget->u.text.text, - widget->u.text.len, - &font_style); + ctx.plot->text(&ctx, + &font_style, + bbox.x0 + border, + bbox.y0 + ((fh * 3) / 4) + border, + widget->u.text.text, + widget->u.text.len); } nsfb_update(root->u.root.fb, &bbox); diff --git a/frontends/framebuffer/framebuffer.c b/frontends/framebuffer/framebuffer.c index 74c72fe71..7b8ee917f 100644 --- a/frontends/framebuffer/framebuffer.c +++ b/frontends/framebuffer/framebuffer.c @@ -45,139 +45,274 @@ static nsfb_t *nsfb; -static bool -framebuffer_plot_disc(int x, int y, int radius, const plot_style_t *style) +/** + * \brief Sets a clip rectangle for subsequent plot operations. + * + * \param ctx The current redraw context. + * \param clip The rectangle to limit all subsequent plot + * operations within. + * \return NSERROR_OK on success else error code. + */ +static nserror +framebuffer_plot_clip(const struct redraw_context *ctx, const struct rect *clip) { - nsfb_bbox_t ellipse; - ellipse.x0 = x - radius; - ellipse.y0 = y - radius; - ellipse.x1 = x + radius; - ellipse.y1 = y + radius; - - if (style->fill_type != PLOT_OP_TYPE_NONE) { - nsfb_plot_ellipse_fill(nsfb, &ellipse, style->fill_colour); - } - - if (style->stroke_type != PLOT_OP_TYPE_NONE) { - nsfb_plot_ellipse(nsfb, &ellipse, style->stroke_colour); - } - return true; + nsfb_bbox_t nsfb_clip; + nsfb_clip.x0 = clip->x0; + nsfb_clip.y0 = clip->y0; + nsfb_clip.x1 = clip->x1; + nsfb_clip.y1 = clip->y1; + + if (!nsfb_plot_set_clip(nsfb, &nsfb_clip)) { + return NSERROR_INVALID; + } + return NSERROR_OK; } -static bool -framebuffer_plot_arc(int x, int y, int radius, int angle1, int angle2, const plot_style_t *style) + +/** + * Plots an arc + * + * plot an arc segment around (x,y), anticlockwise from angle1 + * to angle2. Angles are measured anticlockwise from + * horizontal, in degrees. + * + * \param ctx The current redraw context. + * \param pstyle Style controlling the arc plot. + * \param x The x coordinate of the arc. + * \param y The y coordinate of the arc. + * \param radius The radius of the arc. + * \param angle1 The start angle of the arc. + * \param angle2 The finish angle of the arc. + * \return NSERROR_OK on success else error code. + */ +static nserror +framebuffer_plot_arc(const struct redraw_context *ctx, + const plot_style_t *style, + int x, int y, int radius, int angle1, int angle2) { - return nsfb_plot_arc(nsfb, x, y, radius, angle1, angle2, style->fill_colour); + if (!nsfb_plot_arc(nsfb, x, y, radius, angle1, angle2, style->fill_colour)) { + return NSERROR_INVALID; + } + return NSERROR_OK; } -static bool -framebuffer_plot_polygon(const int *p, unsigned int n, const plot_style_t *style) + +/** + * Plots a circle + * + * Plot a circle centered on (x,y), which is optionally filled. + * + * \param ctx The current redraw context. + * \param pstyle Style controlling the circle plot. + * \param x x coordinate of circle centre. + * \param y y coordinate of circle centre. + * \param radius circle radius. + * \return NSERROR_OK on success else error code. + */ +static nserror +framebuffer_plot_disc(const struct redraw_context *ctx, + const plot_style_t *style, + int x, int y, int radius) { - return nsfb_plot_polygon(nsfb, p, n, style->fill_colour); + nsfb_bbox_t ellipse; + ellipse.x0 = x - radius; + ellipse.y0 = y - radius; + ellipse.x1 = x + radius; + ellipse.y1 = y + radius; + + if (style->fill_type != PLOT_OP_TYPE_NONE) { + nsfb_plot_ellipse_fill(nsfb, &ellipse, style->fill_colour); + } + + if (style->stroke_type != PLOT_OP_TYPE_NONE) { + nsfb_plot_ellipse(nsfb, &ellipse, style->stroke_colour); + } + return NSERROR_OK; } -#ifdef FB_USE_FREETYPE -static bool -framebuffer_plot_text(int x, int y, const char *text, size_t length, - const plot_font_style_t *fstyle) +/** + * Plots a line + * + * plot a line from (x0,y0) to (x1,y1). Coordinates are at + * centre of line width/thickness. + * + * \param ctx The current redraw context. + * \param pstyle Style controlling the line plot. + * \param line A rectangle defining the line to be drawn + * \return NSERROR_OK on success else error code. + */ +static nserror +framebuffer_plot_line(const struct redraw_context *ctx, + const plot_style_t *style, + const struct rect *line) { - uint32_t ucs4; - size_t nxtchr = 0; - FT_Glyph glyph; - FT_BitmapGlyph bglyph; - nsfb_bbox_t loc; - - while (nxtchr < length) { - ucs4 = utf8_to_ucs4(text + nxtchr, length - nxtchr); - nxtchr = utf8_next(text, length, nxtchr); - - glyph = fb_getglyph(fstyle, ucs4); - if (glyph == NULL) - continue; - - if (glyph->format == FT_GLYPH_FORMAT_BITMAP) { - bglyph = (FT_BitmapGlyph)glyph; - - loc.x0 = x + bglyph->left; - loc.y0 = y - bglyph->top; - loc.x1 = loc.x0 + bglyph->bitmap.width; - loc.y1 = loc.y0 + bglyph->bitmap.rows; - - /* now, draw to our target surface */ - if (bglyph->bitmap.pixel_mode == FT_PIXEL_MODE_MONO) { - nsfb_plot_glyph1(nsfb, - &loc, - bglyph->bitmap.buffer, - bglyph->bitmap.pitch, - fstyle->foreground); - } else { - nsfb_plot_glyph8(nsfb, - &loc, - bglyph->bitmap.buffer, - bglyph->bitmap.pitch, - fstyle->foreground); - } - } - x += glyph->advance.x >> 16; - - } - return true; + nsfb_bbox_t rect; + nsfb_plot_pen_t pen; + rect.x0 = line->x0; + rect.y0 = line->y0; + rect.x1 = line->x1; + rect.y1 = line->y1; + + if (style->stroke_type != PLOT_OP_TYPE_NONE) { + + if (style->stroke_type == PLOT_OP_TYPE_DOT) { + pen.stroke_type = NFSB_PLOT_OPTYPE_PATTERN; + pen.stroke_pattern = 0xAAAAAAAA; + } else if (style->stroke_type == PLOT_OP_TYPE_DASH) { + pen.stroke_type = NFSB_PLOT_OPTYPE_PATTERN; + pen.stroke_pattern = 0xF0F0F0F0; + } else { + pen.stroke_type = NFSB_PLOT_OPTYPE_SOLID; + } + + pen.stroke_colour = style->stroke_colour; + pen.stroke_width = style->stroke_width; + nsfb_plot_line(nsfb, &rect, &pen); + } + + return NSERROR_OK; } -#else -static bool framebuffer_plot_text(int x, int y, const char *text, size_t length, - const plot_font_style_t *fstyle) + + +/** + * Plots a rectangle. + * + * The rectangle can be filled an outline or both controlled + * by the plot style The line can be solid, dotted or + * dashed. Top left corner at (x0,y0) and rectangle has given + * width and height. + * + * \param ctx The current redraw context. + * \param pstyle Style controlling the rectangle plot. + * \param nsrect A rectangle defining the line to be drawn + * \return NSERROR_OK on success else error code. + */ +static nserror +framebuffer_plot_rectangle(const struct redraw_context *ctx, + const plot_style_t *style, + const struct rect *nsrect) { - enum fb_font_style style = fb_get_font_style(fstyle); - int size = fb_get_font_size(fstyle); - const uint8_t *chrp; - size_t nxtchr = 0; - nsfb_bbox_t loc; - uint32_t ucs4; - int p = FB_FONT_PITCH * size; - int w = FB_FONT_WIDTH * size; - int h = FB_FONT_HEIGHT * size; + nsfb_bbox_t rect; + bool dotted = false; + bool dashed = false; - y -= ((h * 3) / 4); - /* the coord is the bottom-left of the pixels offset by 1 to make - * it work since fb coords are the top-left of pixels */ - y += 1; + rect.x0 = nsrect->x0; + rect.y0 = nsrect->y0; + rect.x1 = nsrect->x1; + rect.y1 = nsrect->y1; - while (nxtchr < length) { - ucs4 = utf8_to_ucs4(text + nxtchr, length - nxtchr); - nxtchr = utf8_next(text, length, nxtchr); + if (style->fill_type != PLOT_OP_TYPE_NONE) { + nsfb_plot_rectangle_fill(nsfb, &rect, style->fill_colour); + } - if (!codepoint_displayable(ucs4)) - continue; + if (style->stroke_type != PLOT_OP_TYPE_NONE) { + if (style->stroke_type == PLOT_OP_TYPE_DOT) { + dotted = true; + } - loc.x0 = x; - loc.y0 = y; - loc.x1 = loc.x0 + w; - loc.y1 = loc.y0 + h; + if (style->stroke_type == PLOT_OP_TYPE_DASH) { + dashed = true; + } - chrp = fb_get_glyph(ucs4, style, size); - nsfb_plot_glyph1(nsfb, &loc, chrp, p, fstyle->foreground); + nsfb_plot_rectangle(nsfb, &rect, style->stroke_width, style->stroke_colour, dotted, dashed); + } + return NSERROR_OK; +} - x += w; - } +/** + * Plot a polygon + * + * Plots a filled polygon with straight lines between + * points. The lines around the edge of the ploygon are not + * plotted. The polygon is filled with the non-zero winding + * rule. + * + * \param ctx The current redraw context. + * \param pstyle Style controlling the polygon plot. + * \param p verticies of polygon + * \param n number of verticies. + * \return NSERROR_OK on success else error code. + */ +static nserror +framebuffer_plot_polygon(const struct redraw_context *ctx, + const plot_style_t *style, + const int *p, + unsigned int n) +{ + if (!nsfb_plot_polygon(nsfb, p, n, style->fill_colour)) { + return NSERROR_INVALID; + } + return NSERROR_OK; +} - return true; + +/** + * Plots a path. + * + * Path plot consisting of cubic Bezier curves. Line and fill colour is + * controlled by the plot style. + * + * \param ctx The current redraw context. + * \param pstyle Style controlling the path plot. + * \param p elements of path + * \param n nunber of elements on path + * \param width The width of the path + * \param transform A transform to apply to the path. + * \return NSERROR_OK on success else error code. + */ +static nserror +framebuffer_plot_path(const struct redraw_context *ctx, + const plot_style_t *pstyle, + const float *p, + unsigned int n, + float width, + const float transform[6]) +{ + LOG("path unimplemented"); + return NSERROR_OK; } -#endif -static bool -framebuffer_plot_bitmap(int x, int y, - int width, int height, - struct bitmap *bitmap, colour bg, - bitmap_flags_t flags) +/** + * Plot a bitmap + * + * Tiled plot of a bitmap image. (x,y) gives the top left + * coordinate of an explicitly placed tile. From this tile the + * image can repeat in all four directions -- up, down, left + * and right -- to the extents given by the current clip + * rectangle. + * + * The bitmap_flags say whether to tile in the x and y + * directions. If not tiling in x or y directions, the single + * image is plotted. The width and height give the dimensions + * the image is to be scaled to. + * + * \param ctx The current redraw context. + * \param bitmap The bitmap to plot + * \param x The x coordinate to plot the bitmap + * \param y The y coordiante to plot the bitmap + * \param width The width of area to plot the bitmap into + * \param height The height of area to plot the bitmap into + * \param bg the background colour to alpha blend into + * \param flags the flags controlling the type of plot operation + * \return NSERROR_OK on success else error code. + */ +static nserror +framebuffer_plot_bitmap(const struct redraw_context *ctx, + struct bitmap *bitmap, + int x, int y, + int width, + int height, + colour bg, + bitmap_flags_t flags) { - nsfb_bbox_t loc; - nsfb_bbox_t clipbox; - bool repeat_x = (flags & BITMAPF_REPEAT_X); - bool repeat_y = (flags & BITMAPF_REPEAT_Y); + nsfb_bbox_t loc; + nsfb_bbox_t clipbox; + bool repeat_x = (flags & BITMAPF_REPEAT_X); + bool repeat_y = (flags & BITMAPF_REPEAT_Y); int bmwidth; int bmheight; int bmstride; @@ -193,15 +328,15 @@ framebuffer_plot_bitmap(int x, int y, if (!(repeat_x || repeat_y)) { /* Not repeating at all, so just plot it */ - loc.x0 = x; - loc.y0 = y; - loc.x1 = loc.x0 + width; - loc.y1 = loc.y0 + height; + loc.x0 = x; + loc.y0 = y; + loc.x1 = loc.x0 + width; + loc.y1 = loc.y0 + height; - return nsfb_plot_copy(bm, NULL, nsfb, &loc); + return nsfb_plot_copy(bm, NULL, nsfb, &loc); } - nsfb_plot_get_clip(nsfb, &clipbox); + nsfb_plot_get_clip(nsfb, &clipbox); nsfb_get_geometry(bm, &bmwidth, &bmheight, &bmformat); nsfb_get_buffer(bm, &bmptr, &bmstride); @@ -209,8 +344,11 @@ framebuffer_plot_bitmap(int x, int y, * of the area. Can only be done when image is fully opaque. */ if ((bmwidth == 1) && (bmheight == 1)) { if ((*(nsfb_colour_t *)bmptr & 0xff000000) != 0) { - return nsfb_plot_rectangle_fill(nsfb, &clipbox, - *(nsfb_colour_t *)bmptr); + if (!nsfb_plot_rectangle_fill(nsfb, &clipbox, + *(nsfb_colour_t *)bmptr)) { + return NSERROR_INVALID; + } + return NSERROR_OK; } } @@ -221,24 +359,29 @@ framebuffer_plot_bitmap(int x, int y, if (framebuffer_bitmap_get_opaque(bm)) { /** TODO: Currently using top left pixel. Maybe centre * pixel or average value would be better. */ - return nsfb_plot_rectangle_fill(nsfb, &clipbox, - *(nsfb_colour_t *)bmptr); + if (!nsfb_plot_rectangle_fill(nsfb, &clipbox, + *(nsfb_colour_t *)bmptr)) { + return NSERROR_INVALID; + } + return NSERROR_OK; } } /* get left most tile position */ - if (repeat_x) + if (repeat_x) { for (; x > clipbox.x0; x -= width); + } /* get top most tile position */ - if (repeat_y) + if (repeat_y) { for (; y > clipbox.y0; y -= height); + } /* set up top left tile location */ - loc.x0 = x; - loc.y0 = y; - loc.x1 = loc.x0 + width; - loc.y1 = loc.y0 + height; + loc.x0 = x; + loc.y0 = y; + loc.x1 = loc.x0 + width; + loc.y1 = loc.y0 + height; /* plot tiling across and down to extents */ nsfb_plot_bitmap_tiles(nsfb, &loc, @@ -247,94 +390,135 @@ framebuffer_plot_bitmap(int x, int y, (nsfb_colour_t *)bmptr, bmwidth, bmheight, bmstride * 8 / 32, bmformat == NSFB_FMT_ABGR8888); - return true; + return NSERROR_OK; } -static bool -framebuffer_plot_rectangle(int x0, int y0, int x1, int y1, const plot_style_t *style) -{ - nsfb_bbox_t rect; - bool dotted = false; - bool dashed = false; - - rect.x0 = x0; - rect.y0 = y0; - rect.x1 = x1; - rect.y1 = y1; - if (style->fill_type != PLOT_OP_TYPE_NONE) { - nsfb_plot_rectangle_fill(nsfb, &rect, style->fill_colour); - } - - if (style->stroke_type != PLOT_OP_TYPE_NONE) { - if (style->stroke_type == PLOT_OP_TYPE_DOT) - dotted = true; - - if (style->stroke_type == PLOT_OP_TYPE_DASH) - dashed = true; +#ifdef FB_USE_FREETYPE +/** + * Text plotting. + * + * \param ctx The current redraw context. + * \param fstyle plot style for this text + * \param x x coordinate + * \param y y coordinate + * \param text UTF-8 string to plot + * \param length length of string, in bytes + * \return NSERROR_OK on success else error code. + */ +static nserror +framebuffer_plot_text(const struct redraw_context *ctx, + const struct plot_font_style *fstyle, + int x, + int y, + const char *text, + size_t length) +{ + uint32_t ucs4; + size_t nxtchr = 0; + FT_Glyph glyph; + FT_BitmapGlyph bglyph; + nsfb_bbox_t loc; + + while (nxtchr < length) { + ucs4 = utf8_to_ucs4(text + nxtchr, length - nxtchr); + nxtchr = utf8_next(text, length, nxtchr); + + glyph = fb_getglyph(fstyle, ucs4); + if (glyph == NULL) + continue; + + if (glyph->format == FT_GLYPH_FORMAT_BITMAP) { + bglyph = (FT_BitmapGlyph)glyph; + + loc.x0 = x + bglyph->left; + loc.y0 = y - bglyph->top; + loc.x1 = loc.x0 + bglyph->bitmap.width; + loc.y1 = loc.y0 + bglyph->bitmap.rows; + + /* now, draw to our target surface */ + if (bglyph->bitmap.pixel_mode == FT_PIXEL_MODE_MONO) { + nsfb_plot_glyph1(nsfb, + &loc, + bglyph->bitmap.buffer, + bglyph->bitmap.pitch, + fstyle->foreground); + } else { + nsfb_plot_glyph8(nsfb, + &loc, + bglyph->bitmap.buffer, + bglyph->bitmap.pitch, + fstyle->foreground); + } + } + x += glyph->advance.x >> 16; - nsfb_plot_rectangle(nsfb, &rect, style->stroke_width, style->stroke_colour, dotted, dashed); } + return NSERROR_OK; - return true; } -static bool -framebuffer_plot_line(int x0, int y0, int x1, int y1, const plot_style_t *style) +#else + +/** + * Text plotting. + * + * \param ctx The current redraw context. + * \param fstyle plot style for this text + * \param x x coordinate + * \param y y coordinate + * \param text UTF-8 string to plot + * \param length length of string, in bytes + * \return NSERROR_OK on success else error code. + */ +static nserror +framebuffer_plot_text(const struct redraw_context *ctx, + const struct plot_font_style *fstyle, + int x, + int y, + const char *text, + size_t length) { - nsfb_bbox_t rect; - nsfb_plot_pen_t pen; + enum fb_font_style style = fb_get_font_style(fstyle); + int size = fb_get_font_size(fstyle); + const uint8_t *chrp; + size_t nxtchr = 0; + nsfb_bbox_t loc; + uint32_t ucs4; + int p = FB_FONT_PITCH * size; + int w = FB_FONT_WIDTH * size; + int h = FB_FONT_HEIGHT * size; - rect.x0 = x0; - rect.y0 = y0; - rect.x1 = x1; - rect.y1 = y1; - - if (style->stroke_type != PLOT_OP_TYPE_NONE) { + y -= ((h * 3) / 4); + /* the coord is the bottom-left of the pixels offset by 1 to make + * it work since fb coords are the top-left of pixels */ + y += 1; - if (style->stroke_type == PLOT_OP_TYPE_DOT) { - pen.stroke_type = NFSB_PLOT_OPTYPE_PATTERN; - pen.stroke_pattern = 0xAAAAAAAA; - } else if (style->stroke_type == PLOT_OP_TYPE_DASH) { - pen.stroke_type = NFSB_PLOT_OPTYPE_PATTERN; - pen.stroke_pattern = 0xF0F0F0F0; - } else { - pen.stroke_type = NFSB_PLOT_OPTYPE_SOLID; - } + while (nxtchr < length) { + ucs4 = utf8_to_ucs4(text + nxtchr, length - nxtchr); + nxtchr = utf8_next(text, length, nxtchr); - pen.stroke_colour = style->stroke_colour; - pen.stroke_width = style->stroke_width; - nsfb_plot_line(nsfb, &rect, &pen); - } + if (!codepoint_displayable(ucs4)) + continue; - return true; -} + loc.x0 = x; + loc.y0 = y; + loc.x1 = loc.x0 + w; + loc.y1 = loc.y0 + h; + chrp = fb_get_glyph(ucs4, style, size); + nsfb_plot_glyph1(nsfb, &loc, chrp, p, fstyle->foreground); -static bool -framebuffer_plot_path(const float *p, - unsigned int n, - colour fill, - float width, - colour c, - const float transform[6]) -{ - LOG("path unimplemented"); - return true; -} + x += w; -static bool -framebuffer_plot_clip(const struct rect *clip) -{ - nsfb_bbox_t nsfb_clip; - nsfb_clip.x0 = clip->x0; - nsfb_clip.y0 = clip->y0; - nsfb_clip.x1 = clip->x1; - nsfb_clip.y1 = clip->y1; + } - return nsfb_plot_set_clip(nsfb, &nsfb_clip); + return NSERROR_OK; } +#endif + +/** framebuffer plot operation table */ const struct plotter_table fb_plotters = { .clip = framebuffer_plot_clip, .arc = framebuffer_plot_arc, @@ -345,7 +529,7 @@ const struct plotter_table fb_plotters = { .path = framebuffer_plot_path, .bitmap = framebuffer_plot_bitmap, .text = framebuffer_plot_text, - .option_knockout = true, + .option_knockout = true, }; @@ -394,33 +578,33 @@ framebuffer_initialise(const char *fename, int width, int height, int bpp) /* bpp is a proxy for the framebuffer format */ if (framebuffer_format_from_bpp(bpp, &fbfmt) == false) { - return NULL; + return NULL; } fbtype = nsfb_type_from_name(fename); if (fbtype == NSFB_SURFACE_NONE) { - LOG("The %s surface is not available from libnsfb\n", fename); - return NULL; + LOG("The %s surface is not available from libnsfb\n", fename); + return NULL; } nsfb = nsfb_new(fbtype); if (nsfb == NULL) { - LOG("Unable to create %s fb surface\n", fename); - return NULL; + LOG("Unable to create %s fb surface\n", fename); + return NULL; } - + if (nsfb_set_geometry(nsfb, width, height, fbfmt) == -1) { - LOG("Unable to set surface geometry\n"); - nsfb_free(nsfb); - return NULL; + LOG("Unable to set surface geometry\n"); + nsfb_free(nsfb); + return NULL; } nsfb_cursor_init(nsfb); - + if (nsfb_init(nsfb) == -1) { - LOG("Unable to initialise nsfb surface\n"); - nsfb_free(nsfb); - return NULL; + LOG("Unable to initialise nsfb surface\n"); + nsfb_free(nsfb); + return NULL; } return nsfb; @@ -434,12 +618,12 @@ framebuffer_resize(nsfb_t *nsfb, int width, int height, int bpp) /* bpp is a proxy for the framebuffer format */ if (framebuffer_format_from_bpp(bpp, &fbfmt) == false) { - return false; + return false; } if (nsfb_set_geometry(nsfb, width, height, fbfmt) == -1) { - LOG("Unable to change surface geometry\n"); - return false; + LOG("Unable to change surface geometry\n"); + return false; } return true; @@ -449,14 +633,14 @@ framebuffer_resize(nsfb_t *nsfb, int width, int height, int bpp) void framebuffer_finalise(void) { - nsfb_free(nsfb); + nsfb_free(nsfb); } bool framebuffer_set_cursor(struct fbtk_bitmap *bm) { return nsfb_cursor_set(nsfb, (nsfb_colour_t *)bm->pixdata, bm->width, bm->height, bm->width, bm->hot_x, bm->hot_y); -} +} nsfb_t *framebuffer_set_surface(nsfb_t *new_nsfb) { -- cgit v1.2.3 From 320c0e1a75106a74280410ce23db8a308f44193b Mon Sep 17 00:00:00 2001 From: Vincent Sanders Date: Fri, 10 Feb 2017 09:38:31 +0000 Subject: update windows plotters to new API --- frontends/windows/plot.c | 1176 ++++++++++++++++++++++++++-------------------- 1 file changed, 668 insertions(+), 508 deletions(-) diff --git a/frontends/windows/plot.c b/frontends/windows/plot.c index fd2961957..5b7648ef1 100644 --- a/frontends/windows/plot.c +++ b/frontends/windows/plot.c @@ -50,341 +50,331 @@ HDC plot_hdc; static RECT plot_clip; /* currently set clipping rectangle */ -static bool clip(const struct rect *clip) -{ - PLOT_LOG("clip %d,%d to %d,%d", clip->x0, clip->y0, clip->x1, clip->y1); - - plot_clip.left = clip->x0; - plot_clip.top = clip->y0; - plot_clip.right = clip->x1 + 1; /* co-ordinates are exclusive */ - plot_clip.bottom = clip->y1 + 1; /* co-ordinates are exclusive */ - - return true; -} -static bool line(int x0, int y0, int x1, int y1, const plot_style_t *style) +/** + * bitmap helper to plot a solid block of colour + * + * \param col colour to plot with + * \param x the x coordinate to plot at + * \param y the y coordinate to plot at + * \param width the width of block to plot + * \param height the height to plot + * \return NSERROR_OK on sucess else error code. + */ +static nserror +plot_block(COLORREF col, int x, int y, int width, int height) { - PLOT_LOG("from %d,%d to %d,%d", x0, y0, x1, y1); + HRGN clipregion; + HGDIOBJ original = NULL; + + /* Bail early if we can */ + if ((x >= plot_clip.right) || + ((x + width) < plot_clip.left) || + (y >= plot_clip.bottom) || + ((y + height) < plot_clip.top)) { + /* Image completely outside clip region */ + return NSERROR_OK; + } /* ensure the plot HDC is set */ if (plot_hdc == NULL) { LOG("HDC not set on call to plotters"); - return false; + return NSERROR_INVALID; } - HRGN clipregion = CreateRectRgnIndirect(&plot_clip); + clipregion = CreateRectRgnIndirect(&plot_clip); if (clipregion == NULL) { - return false; + return NSERROR_INVALID; } - COLORREF col = (DWORD)(style->stroke_colour & 0x00FFFFFF); - /* windows 0x00bbggrr */ - DWORD penstyle = PS_GEOMETRIC | ((style->stroke_type == - PLOT_OP_TYPE_DOT) ? PS_DOT : - (style->stroke_type == PLOT_OP_TYPE_DASH) ? PS_DASH: - 0); - LOGBRUSH lb = {BS_SOLID, col, 0}; - HPEN pen = ExtCreatePen(penstyle, style->stroke_width, &lb, 0, NULL); - if (pen == NULL) { - DeleteObject(clipregion); - return false; - } - HGDIOBJ bak = SelectObject(plot_hdc, (HGDIOBJ) pen); - if (bak == NULL) { - DeleteObject(pen); - DeleteObject(clipregion); - return false; - } -/* - RECT r; - r.left = x0; - r.top = y0; - r.right = x1; - r.bottom = y1; -*/ SelectClipRgn(plot_hdc, clipregion); - MoveToEx(plot_hdc, x0, y0, (LPPOINT) NULL); + /* Saving the original pen object */ + original = SelectObject(plot_hdc,GetStockObject(DC_PEN)); - LineTo(plot_hdc, x1, y1); + SelectObject(plot_hdc, GetStockObject(DC_PEN)); + SelectObject(plot_hdc, GetStockObject(DC_BRUSH)); + SetDCPenColor(plot_hdc, col); + SetDCBrushColor(plot_hdc, col); + Rectangle(plot_hdc, x, y, width, height); - SelectClipRgn(plot_hdc, NULL); - pen = SelectObject(plot_hdc, bak); + SelectObject(plot_hdc,original); /* Restoring the original pen object */ - DeleteObject(pen); DeleteObject(clipregion); - return true; + return NSERROR_OK; + } -static bool rectangle(int x0, int y0, int x1, int y1, const plot_style_t *style) -{ - PLOT_LOG("rectangle from %d,%d to %d,%d", x0, y0, x1, y1); - /* ensure the plot HDC is set */ - if (plot_hdc == NULL) { - LOG("HDC not set on call to plotters"); - return false; - } - - HRGN clipregion = CreateRectRgnIndirect(&plot_clip); - if (clipregion == NULL) { - return false; +/** + * plot an alpha blended bitmap + * + * blunt force truma way of achiving alpha blended plotting + */ +static nserror +plot_alpha_bitmap(HDC hdc, + struct bitmap *bitmap, + int x, int y, + int width, int height) +{ +#ifdef WINDOWS_GDI_ALPHA_WORKED + BLENDFUNCTION blnd = { AC_SRC_OVER, 0, 0xff, AC_SRC_ALPHA }; + HDC bmihdc; + bool bltres; + bmihdc = CreateCompatibleDC(hdc); + SelectObject(bmihdc, bitmap->windib); + bltres = AlphaBlend(hdc, + x, y, + width, height, + bmihdc, + 0, 0, + bitmap->width, bitmap->height, + blnd); + DeleteDC(bmihdc); + if (!bltres) { + return NSERROR_INVALID; } +#else + HDC Memhdc; + BITMAPINFOHEADER bmih; + int v, vv, vi, h, hh, width4, transparency; + unsigned char alpha; + bool isscaled = false; /* set if the scaled bitmap requires freeing */ + BITMAP MemBM; + BITMAPINFO *bmi; + HBITMAP MemBMh; - x1++; - y1++; - - COLORREF pencol = (DWORD)(style->stroke_colour & 0x00FFFFFF); - DWORD penstyle = PS_GEOMETRIC | - (style->stroke_type == PLOT_OP_TYPE_DOT ? PS_DOT : - (style->stroke_type == PLOT_OP_TYPE_DASH ? PS_DASH : - (style->stroke_type == PLOT_OP_TYPE_NONE ? PS_NULL : - 0))); - LOGBRUSH lb = {BS_SOLID, pencol, 0}; - LOGBRUSH lb1 = {BS_SOLID, style->fill_colour, 0}; - if (style->fill_type == PLOT_OP_TYPE_NONE) - lb1.lbStyle = BS_HOLLOW; + PLOT_LOG("%p bitmap %d,%d width %d height %d", bitmap, x, y, width, height); + PLOT_LOG("clipped %ld,%ld to %ld,%ld",plot_clip.left, plot_clip.top, plot_clip.right, plot_clip.bottom); - HPEN pen = ExtCreatePen(penstyle, style->stroke_width, &lb, 0, NULL); - if (pen == NULL) { - return false; - } - HGDIOBJ penbak = SelectObject(plot_hdc, (HGDIOBJ) pen); - if (penbak == NULL) { - DeleteObject(pen); - return false; - } - HBRUSH brush = CreateBrushIndirect(&lb1); - if (brush == NULL) { - SelectObject(plot_hdc, penbak); - DeleteObject(pen); - return false; - } - HGDIOBJ brushbak = SelectObject(plot_hdc, (HGDIOBJ) brush); - if (brushbak == NULL) { - SelectObject(plot_hdc, penbak); - DeleteObject(pen); - DeleteObject(brush); - return false; + Memhdc = CreateCompatibleDC(hdc); + if (Memhdc == NULL) { + return NSERROR_INVALID; } - SelectClipRgn(plot_hdc, clipregion); - - Rectangle(plot_hdc, x0, y0, x1, y1); + if ((bitmap->width != width) || + (bitmap->height != height)) { + PLOT_LOG("scaling from %d,%d to %d,%d", + bitmap->width, bitmap->height, width, height); + bitmap = bitmap_scale(bitmap, width, height); + if (bitmap == NULL) { + return NSERROR_INVALID; + } + isscaled = true; + } - pen = SelectObject(plot_hdc, penbak); - brush = SelectObject(plot_hdc, brushbak); - SelectClipRgn(plot_hdc, NULL); - DeleteObject(pen); - DeleteObject(brush); - DeleteObject(clipregion); + bmi = (BITMAPINFO *) malloc(sizeof(BITMAPINFOHEADER) + + (bitmap->width * bitmap->height * 4)); + if (bmi == NULL) { + DeleteDC(Memhdc); + return NSERROR_INVALID; + } - return true; -} + MemBMh = CreateCompatibleBitmap(hdc, bitmap->width, bitmap->height); + if (MemBMh == NULL){ + free(bmi); + DeleteDC(Memhdc); + return NSERROR_INVALID; + } + /* save 'background' data for alpha channel work */ + SelectObject(Memhdc, MemBMh); + BitBlt(Memhdc, 0, 0, bitmap->width, bitmap->height, hdc, x, y, SRCCOPY); + GetObject(MemBMh, sizeof(BITMAP), &MemBM); -static bool polygon(const int *p, unsigned int n, const plot_style_t *style) -{ - PLOT_LOG("polygon %d points", n); + bmih.biSize = sizeof(bmih); + bmih.biWidth = bitmap->width; + bmih.biHeight = bitmap->height; + bmih.biPlanes = 1; + bmih.biBitCount = 32; + bmih.biCompression = BI_RGB; + bmih.biSizeImage = 4 * bitmap->height * bitmap->width; + bmih.biXPelsPerMeter = 3600; /* 100 dpi */ + bmih.biYPelsPerMeter = 3600; + bmih.biClrUsed = 0; + bmih.biClrImportant = 0; + bmi->bmiHeader = bmih; - /* ensure the plot HDC is set */ - if (plot_hdc == NULL) { - LOG("HDC not set on call to plotters"); - return false; - } + GetDIBits(hdc, MemBMh, 0, bitmap->height, bmi->bmiColors, bmi, + DIB_RGB_COLORS); - POINT points[n]; - unsigned int i; - HRGN clipregion = CreateRectRgnIndirect(&plot_clip); - if (clipregion == NULL) { - return false; - } + /* then load 'foreground' bits from bitmap->pixdata */ - COLORREF pencol = (DWORD)(style->fill_colour & 0x00FFFFFF); - COLORREF brushcol = (DWORD)(style->fill_colour & 0x00FFFFFF); - HPEN pen = CreatePen(PS_GEOMETRIC | PS_NULL, 1, pencol); - if (pen == NULL) { - DeleteObject(clipregion); - return false; - } - HPEN penbak = SelectObject(plot_hdc, pen); - if (penbak == NULL) { - DeleteObject(clipregion); - DeleteObject(pen); - return false; - } - HBRUSH brush = CreateSolidBrush(brushcol); - if (brush == NULL) { - DeleteObject(clipregion); - SelectObject(plot_hdc, penbak); - DeleteObject(pen); - return false; - } - HBRUSH brushbak = SelectObject(plot_hdc, brush); - if (brushbak == NULL) { - DeleteObject(clipregion); - SelectObject(plot_hdc, penbak); - DeleteObject(pen); - DeleteObject(brush); - return false; + width4 = bitmap->width * 4; + for (v = 0, vv = 0, vi = (bitmap->height - 1) * width4; + v < bitmap->height; + v++, vv += bitmap->width, vi -= width4) { + for (h = 0, hh = 0; h < bitmap->width; h++, hh += 4) { + alpha = bitmap->pixdata[vi + hh + 3]; +/* multiplication of alpha value; subject to profiling could be optional */ + if (alpha == 0xFF) { + bmi->bmiColors[vv + h].rgbBlue = + bitmap->pixdata[vi + hh + 2]; + bmi->bmiColors[vv + h].rgbGreen = + bitmap->pixdata[vi + hh + 1]; + bmi->bmiColors[vv + h].rgbRed = + bitmap->pixdata[vi + hh]; + } else if (alpha > 0) { + transparency = 0x100 - alpha; + bmi->bmiColors[vv + h].rgbBlue = + (bmi->bmiColors[vv + h].rgbBlue + * transparency + + (bitmap->pixdata[vi + hh + 2]) * + alpha) >> 8; + bmi->bmiColors[vv + h].rgbGreen = + (bmi->bmiColors[vv + h]. + rgbGreen + * transparency + + (bitmap->pixdata[vi + hh + 1]) * + alpha) >> 8; + bmi->bmiColors[vv + h].rgbRed = + (bmi->bmiColors[vv + h].rgbRed + * transparency + + bitmap->pixdata[vi + hh] + * alpha) >> 8; + } + } } - SetPolyFillMode(plot_hdc, WINDING); - for (i = 0; i < n; i++) { - points[i].x = (long) p[2 * i]; - points[i].y = (long) p[2 * i + 1]; + SetDIBitsToDevice(hdc, x, y, bitmap->width, bitmap->height, + 0, 0, 0, bitmap->height, + (const void *) bmi->bmiColors, + bmi, DIB_RGB_COLORS); - PLOT_LOG("%ld,%ld ", points[i].x, points[i].y); + if (isscaled && bitmap && bitmap->pixdata) { + free(bitmap->pixdata); + free(bitmap); } - SelectClipRgn(plot_hdc, clipregion); - - if (n >= 2) - Polygon(plot_hdc, points, n); - - SelectClipRgn(plot_hdc, NULL); - - pen = SelectObject(plot_hdc, penbak); - brush = SelectObject(plot_hdc, brushbak); - DeleteObject(clipregion); - DeleteObject(pen); - DeleteObject(brush); + free(bmi); + DeleteObject(MemBMh); + DeleteDC(Memhdc); +#endif - return true; + return NSERROR_OK; } -static bool text(int x, int y, const char *text, size_t length, - const plot_font_style_t *style) +/** + */ +static nserror +plot_bitmap(struct bitmap *bitmap, int x, int y, int width, int height) { - PLOT_LOG("words %s at %d,%d", text, x, y); + HRGN clipregion; + nserror res = NSERROR_OK; + + /* Bail early if we can */ + if ((x >= plot_clip.right) || + ((x + width) < plot_clip.left) || + (y >= plot_clip.bottom) || + ((y + height) < plot_clip.top)) { + /* Image completely outside clip region */ + return NSERROR_OK; + } /* ensure the plot HDC is set */ if (plot_hdc == NULL) { LOG("HDC not set on call to plotters"); - return false; + return NSERROR_INVALID; } - HRGN clipregion = CreateRectRgnIndirect(&plot_clip); + clipregion = CreateRectRgnIndirect(&plot_clip); if (clipregion == NULL) { - return false; - } - - HFONT fontbak, font = get_font(style); - if (font == NULL) { - DeleteObject(clipregion); - return false; + return NSERROR_INVALID; } - int wlen; - SIZE s; - LPWSTR wstring; - fontbak = (HFONT) SelectObject(plot_hdc, font); - GetTextExtentPoint(plot_hdc, text, length, &s); -/* - RECT r; - r.left = x; - r.top = y - (3 * s.cy) / 4; - r.right = x + s.cx; - r.bottom = y + s.cy / 4; -*/ SelectClipRgn(plot_hdc, clipregion); - SetTextAlign(plot_hdc, TA_BASELINE | TA_LEFT); - if ((style->background & 0xFF000000) != 0x01000000) - /* 100% alpha */ - SetBkColor(plot_hdc, (DWORD) (style->background & 0x00FFFFFF)); - SetBkMode(plot_hdc, TRANSPARENT); - SetTextColor(plot_hdc, (DWORD) (style->foreground & 0x00FFFFFF)); + if (bitmap->opaque) { + int bltres; + /* opaque bitmap */ + if ((bitmap->width == width) && + (bitmap->height == height)) { + /* unscaled */ + bltres = SetDIBitsToDevice(plot_hdc, + x, y, + width, height, + 0, 0, + 0, + height, + bitmap->pixdata, + (BITMAPINFO *)bitmap->pbmi, + DIB_RGB_COLORS); + } else { + /* scaled */ + SetStretchBltMode(plot_hdc, COLORONCOLOR); + bltres = StretchDIBits(plot_hdc, + x, y, + width, height, + 0, 0, + bitmap->width, bitmap->height, + bitmap->pixdata, + (BITMAPINFO *)bitmap->pbmi, + DIB_RGB_COLORS, + SRCCOPY); - wlen = MultiByteToWideChar(CP_UTF8, 0, text, length, NULL, 0); - wstring = malloc(2 * (wlen + 1)); - if (wstring == NULL) { - return false; + + } + /* check to see if GDI operation failed */ + if (bltres == 0) { + res = NSERROR_INVALID; + } + PLOT_LOG("bltres = %d", bltres); + } else { + /* Bitmap with alpha.*/ + res = plot_alpha_bitmap(plot_hdc, bitmap, x, y, width, height); } - MultiByteToWideChar(CP_UTF8, 0, text, length, wstring, wlen); - TextOutW(plot_hdc, x, y, wstring, wlen); - SelectClipRgn(plot_hdc, NULL); - free(wstring); - font = SelectObject(plot_hdc, fontbak); DeleteObject(clipregion); - DeleteObject(font); - return true; + return res; } -static bool disc(int x, int y, int radius, const plot_style_t *style) -{ - PLOT_LOG("disc at %d,%d radius %d", x, y, radius); - /* ensure the plot HDC is set */ - if (plot_hdc == NULL) { - LOG("HDC not set on call to plotters"); - return false; - } - HRGN clipregion = CreateRectRgnIndirect(&plot_clip); - if (clipregion == NULL) { - return false; - } - COLORREF col = (DWORD)((style->fill_colour | style->stroke_colour) - & 0x00FFFFFF); - HPEN pen = CreatePen(PS_GEOMETRIC | PS_SOLID, 1, col); - if (pen == NULL) { - DeleteObject(clipregion); - return false; - } - HGDIOBJ penbak = SelectObject(plot_hdc, (HGDIOBJ) pen); - if (penbak == NULL) { - DeleteObject(clipregion); - DeleteObject(pen); - return false; - } - HBRUSH brush = CreateSolidBrush(col); - if (brush == NULL) { - DeleteObject(clipregion); - SelectObject(plot_hdc, penbak); - DeleteObject(pen); - return false; - } - HGDIOBJ brushbak = SelectObject(plot_hdc, (HGDIOBJ) brush); - if (brushbak == NULL) { - DeleteObject(clipregion); - SelectObject(plot_hdc, penbak); - DeleteObject(pen); - DeleteObject(brush); - return false; - } -/* - RECT r; - r.left = x - radius; - r.top = y - radius; - r.right = x + radius; - r.bottom = y + radius; -*/ - SelectClipRgn(plot_hdc, clipregion); - - if (style->fill_type == PLOT_OP_TYPE_NONE) - Arc(plot_hdc, x - radius, y - radius, x + radius, y + radius, - x - radius, y - radius, - x - radius, y - radius); - else - Ellipse(plot_hdc, x - radius, y - radius, x + radius, y + radius); +/** + * \brief Sets a clip rectangle for subsequent plot operations. + * + * \param ctx The current redraw context. + * \param clip The rectangle to limit all subsequent plot + * operations within. + * \return NSERROR_OK on success else error code. + */ +static nserror clip(const struct redraw_context *ctx, const struct rect *clip) +{ + PLOT_LOG("clip %d,%d to %d,%d", clip->x0, clip->y0, clip->x1, clip->y1); - SelectClipRgn(plot_hdc, NULL); - pen = SelectObject(plot_hdc, penbak); - brush = SelectObject(plot_hdc, brushbak); - DeleteObject(clipregion); - DeleteObject(pen); - DeleteObject(brush); + plot_clip.left = clip->x0; + plot_clip.top = clip->y0; + plot_clip.right = clip->x1 + 1; /* co-ordinates are exclusive */ + plot_clip.bottom = clip->y1 + 1; /* co-ordinates are exclusive */ - return true; + return NSERROR_OK; } -static bool arc(int x, int y, int radius, int angle1, int angle2, - const plot_style_t *style) + +/** + * Plots an arc + * + * plot an arc segment around (x,y), anticlockwise from angle1 + * to angle2. Angles are measured anticlockwise from + * horizontal, in degrees. + * + * \param ctx The current redraw context. + * \param pstyle Style controlling the arc plot. + * \param x The x coordinate of the arc. + * \param y The y coordinate of the arc. + * \param radius The radius of the arc. + * \param angle1 The start angle of the arc. + * \param angle2 The finish angle of the arc. + * \return NSERROR_OK on success else error code. + */ +static nserror +arc(const struct redraw_context *ctx, + const plot_style_t *style, + int x, int y, + int radius, int angle1, int angle2) { PLOT_LOG("arc centre %d,%d radius %d from %d to %d", x, y, radius, angle1, angle2); @@ -392,25 +382,25 @@ static bool arc(int x, int y, int radius, int angle1, int angle2, /* ensure the plot HDC is set */ if (plot_hdc == NULL) { LOG("HDC not set on call to plotters"); - return false; + return NSERROR_INVALID; } HRGN clipregion = CreateRectRgnIndirect(&plot_clip); if (clipregion == NULL) { - return false; + return NSERROR_INVALID; } COLORREF col = (DWORD)(style->stroke_colour & 0x00FFFFFF); HPEN pen = CreatePen(PS_GEOMETRIC | PS_SOLID, 1, col); if (pen == NULL) { DeleteObject(clipregion); - return false; + return NSERROR_INVALID; } HGDIOBJ penbak = SelectObject(plot_hdc, (HGDIOBJ) pen); if (penbak == NULL) { DeleteObject(clipregion); DeleteObject(pen); - return false; + return NSERROR_INVALID; } int q1, q2; @@ -466,13 +456,6 @@ static bool arc(int x, int y, int radius, int angle1, int angle2, break; } -/* - RECT r; - r.left = x - radius; - r.top = y - radius; - r.right = x + radius; - r.bottom = y + radius; -*/ SelectClipRgn(plot_hdc, clipregion); Arc(plot_hdc, x - radius, y - radius, x + radius, y + radius, @@ -484,269 +467,384 @@ static bool arc(int x, int y, int radius, int angle1, int angle2, DeleteObject(clipregion); DeleteObject(pen); - return true; + return NSERROR_OK; } -static bool -plot_block(COLORREF col, int x, int y, int width, int height) -{ - HRGN clipregion; - HGDIOBJ original = NULL; - /* Bail early if we can */ - if ((x >= plot_clip.right) || - ((x + width) < plot_clip.left) || - (y >= plot_clip.bottom) || - ((y + height) < plot_clip.top)) { - /* Image completely outside clip region */ - return true; - } +/** + * Plots a circle + * + * Plot a circle centered on (x,y), which is optionally filled. + * + * \param ctx The current redraw context. + * \param pstyle Style controlling the circle plot. + * \param x x coordinate of circle centre. + * \param y y coordinate of circle centre. + * \param radius circle radius. + * \return NSERROR_OK on success else error code. + */ +static nserror +disc(const struct redraw_context *ctx, + const plot_style_t *style, + int x, int y, int radius) +{ + PLOT_LOG("disc at %d,%d radius %d", x, y, radius); /* ensure the plot HDC is set */ if (plot_hdc == NULL) { LOG("HDC not set on call to plotters"); - return false; + return NSERROR_INVALID; } - clipregion = CreateRectRgnIndirect(&plot_clip); + HRGN clipregion = CreateRectRgnIndirect(&plot_clip); if (clipregion == NULL) { - return false; + return NSERROR_INVALID; } - SelectClipRgn(plot_hdc, clipregion); - - /* Saving the original pen object */ - original = SelectObject(plot_hdc,GetStockObject(DC_PEN)); + COLORREF col = (DWORD)((style->fill_colour | style->stroke_colour) + & 0x00FFFFFF); + HPEN pen = CreatePen(PS_GEOMETRIC | PS_SOLID, 1, col); + if (pen == NULL) { + DeleteObject(clipregion); + return NSERROR_INVALID; + } + HGDIOBJ penbak = SelectObject(plot_hdc, (HGDIOBJ) pen); + if (penbak == NULL) { + DeleteObject(clipregion); + DeleteObject(pen); + return NSERROR_INVALID; + } + HBRUSH brush = CreateSolidBrush(col); + if (brush == NULL) { + DeleteObject(clipregion); + SelectObject(plot_hdc, penbak); + DeleteObject(pen); + return NSERROR_INVALID; + } + HGDIOBJ brushbak = SelectObject(plot_hdc, (HGDIOBJ) brush); + if (brushbak == NULL) { + DeleteObject(clipregion); + SelectObject(plot_hdc, penbak); + DeleteObject(pen); + DeleteObject(brush); + return NSERROR_INVALID; + } - SelectObject(plot_hdc, GetStockObject(DC_PEN)); - SelectObject(plot_hdc, GetStockObject(DC_BRUSH)); - SetDCPenColor(plot_hdc, col); - SetDCBrushColor(plot_hdc, col); - Rectangle(plot_hdc, x, y, width, height); + SelectClipRgn(plot_hdc, clipregion); - SelectObject(plot_hdc,original); /* Restoring the original pen object */ + if (style->fill_type == PLOT_OP_TYPE_NONE) { + Arc(plot_hdc, x - radius, y - radius, x + radius, y + radius, + x - radius, y - radius, + x - radius, y - radius); + } else { + Ellipse(plot_hdc, x - radius, y - radius, x + radius, y + radius); + } + SelectClipRgn(plot_hdc, NULL); + pen = SelectObject(plot_hdc, penbak); + brush = SelectObject(plot_hdc, brushbak); DeleteObject(clipregion); + DeleteObject(pen); + DeleteObject(brush); - return true; - + return NSERROR_OK; } -/* blunt force truma way of achiving alpha blended plotting */ -static bool -plot_alpha_bitmap(HDC hdc, - struct bitmap *bitmap, - int x, int y, - int width, int height) -{ -#ifdef WINDOWS_GDI_ALPHA_WORKED - BLENDFUNCTION blnd = { AC_SRC_OVER, 0, 0xff, AC_SRC_ALPHA }; - HDC bmihdc; - bool bltres; - bmihdc = CreateCompatibleDC(hdc); - SelectObject(bmihdc, bitmap->windib); - bltres = AlphaBlend(hdc, - x, y, - width, height, - bmihdc, - 0, 0, - bitmap->width, bitmap->height, - blnd); - DeleteDC(bmihdc); - return bltres; -#else - HDC Memhdc; - BITMAPINFOHEADER bmih; - int v, vv, vi, h, hh, width4, transparency; - unsigned char alpha; - bool isscaled = false; /* set if the scaled bitmap requires freeing */ - BITMAP MemBM; - BITMAPINFO *bmi; - HBITMAP MemBMh; - PLOT_LOG("%p bitmap %d,%d width %d height %d", bitmap, x, y, width, height); - PLOT_LOG("clipped %ld,%ld to %ld,%ld",plot_clip.left, plot_clip.top, plot_clip.right, plot_clip.bottom); +/** + * Plots a line + * + * plot a line from (x0,y0) to (x1,y1). Coordinates are at + * centre of line width/thickness. + * + * \param ctx The current redraw context. + * \param pstyle Style controlling the line plot. + * \param line A rectangle defining the line to be drawn + * \return NSERROR_OK on success else error code. + */ +static nserror +line(const struct redraw_context *ctx, + const plot_style_t *style, + const struct rect *line) +{ + PLOT_LOG("from %d,%d to %d,%d", x0, y0, x1, y1); - Memhdc = CreateCompatibleDC(hdc); - if (Memhdc == NULL) { - return false; + /* ensure the plot HDC is set */ + if (plot_hdc == NULL) { + LOG("HDC not set on call to plotters"); + return NSERROR_INVALID; } - if ((bitmap->width != width) || - (bitmap->height != height)) { - PLOT_LOG("scaling from %d,%d to %d,%d", - bitmap->width, bitmap->height, width, height); - bitmap = bitmap_scale(bitmap, width, height); - if (bitmap == NULL) - return false; - isscaled = true; + HRGN clipregion = CreateRectRgnIndirect(&plot_clip); + if (clipregion == NULL) { + return NSERROR_INVALID; } - bmi = (BITMAPINFO *) malloc(sizeof(BITMAPINFOHEADER) + - (bitmap->width * bitmap->height * 4)); - if (bmi == NULL) { - DeleteDC(Memhdc); - return false; + COLORREF col = (DWORD)(style->stroke_colour & 0x00FFFFFF); + /* windows 0x00bbggrr */ + DWORD penstyle = PS_GEOMETRIC | ((style->stroke_type == + PLOT_OP_TYPE_DOT) ? PS_DOT : + (style->stroke_type == PLOT_OP_TYPE_DASH) ? PS_DASH: + 0); + LOGBRUSH lb = {BS_SOLID, col, 0}; + HPEN pen = ExtCreatePen(penstyle, style->stroke_width, &lb, 0, NULL); + if (pen == NULL) { + DeleteObject(clipregion); + return NSERROR_INVALID; + } + HGDIOBJ bak = SelectObject(plot_hdc, (HGDIOBJ) pen); + if (bak == NULL) { + DeleteObject(pen); + DeleteObject(clipregion); + return NSERROR_INVALID; } - MemBMh = CreateCompatibleBitmap(hdc, bitmap->width, bitmap->height); - if (MemBMh == NULL){ - free(bmi); - DeleteDC(Memhdc); - return false; - } + SelectClipRgn(plot_hdc, clipregion); + + MoveToEx(plot_hdc, line->x0, line->y0, (LPPOINT) NULL); + + LineTo(plot_hdc, line->x1, line->y1); + + SelectClipRgn(plot_hdc, NULL); + pen = SelectObject(plot_hdc, bak); + + DeleteObject(pen); + DeleteObject(clipregion); - /* save 'background' data for alpha channel work */ - SelectObject(Memhdc, MemBMh); - BitBlt(Memhdc, 0, 0, bitmap->width, bitmap->height, hdc, x, y, SRCCOPY); - GetObject(MemBMh, sizeof(BITMAP), &MemBM); + return NSERROR_OK; +} - bmih.biSize = sizeof(bmih); - bmih.biWidth = bitmap->width; - bmih.biHeight = bitmap->height; - bmih.biPlanes = 1; - bmih.biBitCount = 32; - bmih.biCompression = BI_RGB; - bmih.biSizeImage = 4 * bitmap->height * bitmap->width; - bmih.biXPelsPerMeter = 3600; /* 100 dpi */ - bmih.biYPelsPerMeter = 3600; - bmih.biClrUsed = 0; - bmih.biClrImportant = 0; - bmi->bmiHeader = bmih; - GetDIBits(hdc, MemBMh, 0, bitmap->height, bmi->bmiColors, bmi, - DIB_RGB_COLORS); +/** + * Plots a rectangle. + * + * The rectangle can be filled an outline or both controlled + * by the plot style The line can be solid, dotted or + * dashed. Top left corner at (x0,y0) and rectangle has given + * width and height. + * + * \param ctx The current redraw context. + * \param pstyle Style controlling the rectangle plot. + * \param rect A rectangle defining the line to be drawn + * \return NSERROR_OK on success else error code. + */ +static nserror +rectangle(const struct redraw_context *ctx, + const plot_style_t *style, + const struct rect *rect) +{ + PLOT_LOG("rectangle from %d,%d to %d,%d", + rect->x0, rect->y0, rect->x1, rect->y1); - /* then load 'foreground' bits from bitmap->pixdata */ + /* ensure the plot HDC is set */ + if (plot_hdc == NULL) { + LOG("HDC not set on call to plotters"); + return NSERROR_INVALID; + } - width4 = bitmap->width * 4; - for (v = 0, vv = 0, vi = (bitmap->height - 1) * width4; - v < bitmap->height; - v++, vv += bitmap->width, vi -= width4) { - for (h = 0, hh = 0; h < bitmap->width; h++, hh += 4) { - alpha = bitmap->pixdata[vi + hh + 3]; -/* multiplication of alpha value; subject to profiling could be optional */ - if (alpha == 0xFF) { - bmi->bmiColors[vv + h].rgbBlue = - bitmap->pixdata[vi + hh + 2]; - bmi->bmiColors[vv + h].rgbGreen = - bitmap->pixdata[vi + hh + 1]; - bmi->bmiColors[vv + h].rgbRed = - bitmap->pixdata[vi + hh]; - } else if (alpha > 0) { - transparency = 0x100 - alpha; - bmi->bmiColors[vv + h].rgbBlue = - (bmi->bmiColors[vv + h].rgbBlue - * transparency + - (bitmap->pixdata[vi + hh + 2]) * - alpha) >> 8; - bmi->bmiColors[vv + h].rgbGreen = - (bmi->bmiColors[vv + h]. - rgbGreen - * transparency + - (bitmap->pixdata[vi + hh + 1]) * - alpha) >> 8; - bmi->bmiColors[vv + h].rgbRed = - (bmi->bmiColors[vv + h].rgbRed - * transparency + - bitmap->pixdata[vi + hh] - * alpha) >> 8; - } - } + HRGN clipregion = CreateRectRgnIndirect(&plot_clip); + if (clipregion == NULL) { + return NSERROR_INVALID; } - SetDIBitsToDevice(hdc, x, y, bitmap->width, bitmap->height, - 0, 0, 0, bitmap->height, - (const void *) bmi->bmiColors, - bmi, DIB_RGB_COLORS); - if (isscaled && bitmap && bitmap->pixdata) { - free(bitmap->pixdata); - free(bitmap); + COLORREF pencol = (DWORD)(style->stroke_colour & 0x00FFFFFF); + DWORD penstyle = PS_GEOMETRIC | + (style->stroke_type == PLOT_OP_TYPE_DOT ? PS_DOT : + (style->stroke_type == PLOT_OP_TYPE_DASH ? PS_DASH : + (style->stroke_type == PLOT_OP_TYPE_NONE ? PS_NULL : + 0))); + LOGBRUSH lb = {BS_SOLID, pencol, 0}; + LOGBRUSH lb1 = {BS_SOLID, style->fill_colour, 0}; + if (style->fill_type == PLOT_OP_TYPE_NONE) + lb1.lbStyle = BS_HOLLOW; + + HPEN pen = ExtCreatePen(penstyle, style->stroke_width, &lb, 0, NULL); + if (pen == NULL) { + return NSERROR_INVALID; + } + HGDIOBJ penbak = SelectObject(plot_hdc, (HGDIOBJ) pen); + if (penbak == NULL) { + DeleteObject(pen); + return NSERROR_INVALID; + } + HBRUSH brush = CreateBrushIndirect(&lb1); + if (brush == NULL) { + SelectObject(plot_hdc, penbak); + DeleteObject(pen); + return NSERROR_INVALID; + } + HGDIOBJ brushbak = SelectObject(plot_hdc, (HGDIOBJ) brush); + if (brushbak == NULL) { + SelectObject(plot_hdc, penbak); + DeleteObject(pen); + DeleteObject(brush); + return NSERROR_INVALID; } - free(bmi); - DeleteObject(MemBMh); - DeleteDC(Memhdc); - return true; -#endif + SelectClipRgn(plot_hdc, clipregion); + + /* windows GDI call coordinates are inclusive */ + Rectangle(plot_hdc, rect->x0, rect->y0, rect->x1 + 1, rect->y1 + 1); + + pen = SelectObject(plot_hdc, penbak); + brush = SelectObject(plot_hdc, brushbak); + SelectClipRgn(plot_hdc, NULL); + DeleteObject(pen); + DeleteObject(brush); + DeleteObject(clipregion); + + return NSERROR_OK; } -static bool -plot_bitmap(struct bitmap *bitmap, int x, int y, int width, int height) +/** + * Plot a polygon + * + * Plots a filled polygon with straight lines between + * points. The lines around the edge of the ploygon are not + * plotted. The polygon is filled with the non-zero winding + * rule. + * + * \param ctx The current redraw context. + * \param pstyle Style controlling the polygon plot. + * \param p verticies of polygon + * \param n number of verticies. + * \return NSERROR_OK on success else error code. + */ +static nserror +polygon(const struct redraw_context *ctx, + const plot_style_t *style, + const int *p, + unsigned int n) { - int bltres; - HRGN clipregion; - - /* Bail early if we can */ - if ((x >= plot_clip.right) || - ((x + width) < plot_clip.left) || - (y >= plot_clip.bottom) || - ((y + height) < plot_clip.top)) { - /* Image completely outside clip region */ - return true; - } + PLOT_LOG("polygon %d points", n); /* ensure the plot HDC is set */ if (plot_hdc == NULL) { LOG("HDC not set on call to plotters"); - return false; + return NSERROR_INVALID; } - clipregion = CreateRectRgnIndirect(&plot_clip); + POINT points[n]; + unsigned int i; + HRGN clipregion = CreateRectRgnIndirect(&plot_clip); if (clipregion == NULL) { - return false; + return NSERROR_INVALID; } - SelectClipRgn(plot_hdc, clipregion); + COLORREF pencol = (DWORD)(style->fill_colour & 0x00FFFFFF); + COLORREF brushcol = (DWORD)(style->fill_colour & 0x00FFFFFF); + HPEN pen = CreatePen(PS_GEOMETRIC | PS_NULL, 1, pencol); + if (pen == NULL) { + DeleteObject(clipregion); + return NSERROR_INVALID; + } + HPEN penbak = SelectObject(plot_hdc, pen); + if (penbak == NULL) { + DeleteObject(clipregion); + DeleteObject(pen); + return NSERROR_INVALID; + } + HBRUSH brush = CreateSolidBrush(brushcol); + if (brush == NULL) { + DeleteObject(clipregion); + SelectObject(plot_hdc, penbak); + DeleteObject(pen); + return NSERROR_INVALID; + } + HBRUSH brushbak = SelectObject(plot_hdc, brush); + if (brushbak == NULL) { + DeleteObject(clipregion); + SelectObject(plot_hdc, penbak); + DeleteObject(pen); + DeleteObject(brush); + return NSERROR_INVALID; + } + SetPolyFillMode(plot_hdc, WINDING); + for (i = 0; i < n; i++) { + points[i].x = (long) p[2 * i]; + points[i].y = (long) p[2 * i + 1]; - if (bitmap->opaque) { - /* opaque bitmap */ - if ((bitmap->width == width) && - (bitmap->height == height)) { - /* unscaled */ - bltres = SetDIBitsToDevice(plot_hdc, - x, y, - width, height, - 0, 0, - 0, - height, - bitmap->pixdata, - (BITMAPINFO *)bitmap->pbmi, - DIB_RGB_COLORS); - } else { - /* scaled */ - SetStretchBltMode(plot_hdc, COLORONCOLOR); - bltres = StretchDIBits(plot_hdc, - x, y, - width, height, - 0, 0, - bitmap->width, bitmap->height, - bitmap->pixdata, - (BITMAPINFO *)bitmap->pbmi, - DIB_RGB_COLORS, - SRCCOPY); + PLOT_LOG("%ld,%ld ", points[i].x, points[i].y); + } + SelectClipRgn(plot_hdc, clipregion); - } - } else { - /* Bitmap with alpha.*/ - bltres = plot_alpha_bitmap(plot_hdc, bitmap, x, y, width, height); + if (n >= 2) { + Polygon(plot_hdc, points, n); } - PLOT_LOG("bltres = %d", bltres); + SelectClipRgn(plot_hdc, NULL); + pen = SelectObject(plot_hdc, penbak); + brush = SelectObject(plot_hdc, brushbak); DeleteObject(clipregion); + DeleteObject(pen); + DeleteObject(brush); + + return NSERROR_OK; +} - return true; +/** + * Plots a path. + * + * Path plot consisting of cubic Bezier curves. Line and fill colour is + * controlled by the plot style. + * + * \param ctx The current redraw context. + * \param pstyle Style controlling the path plot. + * \param p elements of path + * \param n nunber of elements on path + * \param width The width of the path + * \param transform A transform to apply to the path. + * \return NSERROR_OK on success else error code. + */ +static nserror +path(const struct redraw_context *ctx, + const plot_style_t *pstyle, + const float *p, + unsigned int n, + float width, + const float transform[6]) +{ + PLOT_LOG("path unimplemented"); + return NSERROR_OK; } -static bool -windows_plot_bitmap(int x, int y, - int width, int height, - struct bitmap *bitmap, colour bg, - bitmap_flags_t flags) + +/** + * Plot a bitmap + * + * Tiled plot of a bitmap image. (x,y) gives the top left + * coordinate of an explicitly placed tile. From this tile the + * image can repeat in all four directions -- up, down, left + * and right -- to the extents given by the current clip + * rectangle. + * + * The bitmap_flags say whether to tile in the x and y + * directions. If not tiling in x or y directions, the single + * image is plotted. The width and height give the dimensions + * the image is to be scaled to. + * + * \param ctx The current redraw context. + * \param bitmap The bitmap to plot + * \param x The x coordinate to plot the bitmap + * \param y The y coordiante to plot the bitmap + * \param width The width of area to plot the bitmap into + * \param height The height of area to plot the bitmap into + * \param bg the background colour to alpha blend into + * \param flags the flags controlling the type of plot operation + * \return NSERROR_OK on success else error code. + */ +static nserror +bitmap(const struct redraw_context *ctx, + struct bitmap *bitmap, + int x, int y, + int width, + int height, + colour bg, + bitmap_flags_t flags) { int xf,yf; bool repeat_x = (flags & BITMAPF_REPEAT_X); @@ -758,12 +856,12 @@ windows_plot_bitmap(int x, int y, if (bitmap == NULL) { LOG("Passed null bitmap!"); - return true; + return NSERROR_OK; } /* check if nothing to plot */ if (width == 0 || height == 0) - return true; + return NSERROR_OK; /* x and y define coordinate of top left of of the initial explicitly * placed tile. The width and height are the image scaling and the @@ -775,7 +873,7 @@ windows_plot_bitmap(int x, int y, /* Not repeating at all, so just plot it */ if ((bitmap->width == 1) && (bitmap->height == 1)) { if ((*(bitmap->pixdata + 3) & 0xff) == 0) { - return true; + return NSERROR_OK; } return plot_block((*(COLORREF *)bitmap->pixdata) & 0xffffff, x, y, x + width, y + height); @@ -788,10 +886,10 @@ windows_plot_bitmap(int x, int y, * of the area. Can only be done when image is fully opaque. */ if ((bitmap->width == 1) && (bitmap->height == 1)) { if ((*(COLORREF *)bitmap->pixdata & 0xff000000) != 0) { - return plot_block((*(COLORREF *)bitmap->pixdata) & 0xffffff, - plot_clip.left, - plot_clip.top, - plot_clip.right, + return plot_block((*(COLORREF *)bitmap->pixdata) & 0xffffff, + plot_clip.left, + plot_clip.top, + plot_clip.right, plot_clip.bottom); } } @@ -803,10 +901,10 @@ windows_plot_bitmap(int x, int y, if (bitmap->opaque) { /** TODO: Currently using top left pixel. Maybe centre * pixel or average value would be better. */ - return plot_block((*(COLORREF *)bitmap->pixdata) & 0xffffff, - plot_clip.left, - plot_clip.top, - plot_clip.right, + return plot_block((*(COLORREF *)bitmap->pixdata) & 0xffffff, + plot_clip.left, + plot_clip.top, + plot_clip.right, plot_clip.bottom); } } @@ -815,12 +913,14 @@ windows_plot_bitmap(int x, int y, PLOT_LOG("clipped %ld,%ld to %ld,%ld",plot_clip.left, plot_clip.top, plot_clip.right, plot_clip.bottom); /* get left most tile position */ - if (repeat_x) + if (repeat_x) { for (; x > plot_clip.left; x -= width); + } /* get top most tile position */ - if (repeat_y) + if (repeat_y) { for (; y > plot_clip.top; y -= height); + } PLOT_LOG("repeat from %d,%d to %ld,%ld", x, y, plot_clip.right, plot_clip.bottom); @@ -833,25 +933,86 @@ windows_plot_bitmap(int x, int y, break; } if (!repeat_x) - break; + break; } - return true; + return NSERROR_OK; } -static bool flush(void) +/** + * Text plotting. + * + * \param ctx The current redraw context. + * \param fstyle plot style for this text + * \param x x coordinate + * \param y y coordinate + * \param text UTF-8 string to plot + * \param length length of string, in bytes + * \return NSERROR_OK on success else error code. + */ +static nserror +text(const struct redraw_context *ctx, + const struct plot_font_style *fstyle, + int x, + int y, + const char *text, + size_t length) { - PLOT_LOG("flush unimplemented"); - return true; -} + PLOT_LOG("words %s at %d,%d", text, x, y); -static bool path(const float *p, unsigned int n, colour fill, float width, - colour c, const float transform[6]) -{ - PLOT_LOG("path unimplemented"); - return true; + /* ensure the plot HDC is set */ + if (plot_hdc == NULL) { + LOG("HDC not set on call to plotters"); + return NSERROR_INVALID; + } + + HRGN clipregion = CreateRectRgnIndirect(&plot_clip); + if (clipregion == NULL) { + return NSERROR_INVALID; + } + + HFONT fontbak, font = get_font(fstyle); + if (font == NULL) { + DeleteObject(clipregion); + return NSERROR_INVALID; + } + int wlen; + SIZE s; + LPWSTR wstring; + fontbak = (HFONT) SelectObject(plot_hdc, font); + GetTextExtentPoint(plot_hdc, text, length, &s); + + SelectClipRgn(plot_hdc, clipregion); + + SetTextAlign(plot_hdc, TA_BASELINE | TA_LEFT); + if ((fstyle->background & 0xFF000000) != 0x01000000) { + /* 100% alpha */ + SetBkColor(plot_hdc, (DWORD) (fstyle->background & 0x00FFFFFF)); + } + SetBkMode(plot_hdc, TRANSPARENT); + SetTextColor(plot_hdc, (DWORD) (fstyle->foreground & 0x00FFFFFF)); + + wlen = MultiByteToWideChar(CP_UTF8, 0, text, length, NULL, 0); + wstring = malloc(2 * (wlen + 1)); + if (wstring == NULL) { + return NSERROR_INVALID; + } + MultiByteToWideChar(CP_UTF8, 0, text, length, wstring, wlen); + TextOutW(plot_hdc, x, y, wstring, wlen); + + SelectClipRgn(plot_hdc, NULL); + free(wstring); + font = SelectObject(plot_hdc, fontbak); + DeleteObject(clipregion); + DeleteObject(font); + + return NSERROR_OK; } + +/** + * win32 API plot operation table + */ const struct plotter_table win_plotters = { .rectangle = rectangle, .line = line, @@ -860,8 +1021,7 @@ const struct plotter_table win_plotters = { .text = text, .disc = disc, .arc = arc, - .bitmap = windows_plot_bitmap, - .flush = flush, + .bitmap = bitmap, .path = path, .option_knockout = true, }; -- cgit v1.2.3 From a3a7cbf06a1d841dd6dee415fb196040c453567a Mon Sep 17 00:00:00 2001 From: Vincent Sanders Date: Fri, 10 Feb 2017 15:26:59 +0000 Subject: update amiga plot API --- frontends/amiga/dt_anim.c | 7 +- frontends/amiga/dt_sound.c | 19 +- frontends/amiga/icon.c | 13 +- frontends/amiga/plotters.c | 852 +++++++++++++++++++++++++----------------- frontends/amiga/plugin_hack.c | 23 +- 5 files changed, 557 insertions(+), 357 deletions(-) diff --git a/frontends/amiga/dt_anim.c b/frontends/amiga/dt_anim.c index a48633403..2f998d299 100644 --- a/frontends/amiga/dt_anim.c +++ b/frontends/amiga/dt_anim.c @@ -270,8 +270,11 @@ bool amiga_dt_anim_redraw(struct content *c, if (data->repeat_y) flags |= BITMAPF_REPEAT_Y; - return ctx->plot->bitmap(data->x, data->y, data->width, data->height, - plugin->bitmap, data->background_colour, flags); + return (ctx->plot->bitmap(ctx, plugin->bitmap, + data->x, data->y, + data->width, data->height, + data->background_colour, + flags) == NSERROR_OK); } /** diff --git a/frontends/amiga/dt_sound.c b/frontends/amiga/dt_sound.c index 55fc60d61..eda60edc1 100644 --- a/frontends/amiga/dt_sound.c +++ b/frontends/amiga/dt_sound.c @@ -197,18 +197,25 @@ bool amiga_dt_sound_redraw(struct content *c, .stroke_colour = 0x000000, .stroke_width = 1, }; + struct rect rect; LOG("amiga_dt_sound_redraw"); + rect.x0 = data->x; + rect.y0 = data->y; + rect.x1 = data->x + data->width; + rect.y1 = data->y + data->height; + /* this should be some sort of play/stop control */ - ctx->plot->rectangle(data->x, data->y, data->x + data->width, - data->y + data->height, &pstyle); + ctx->plot->rectangle(ctx, &pstyle, &rect); - return ctx->plot->text(data->x, data->y+20, - lwc_string_data(content__get_mime_type(c)), - lwc_string_length(content__get_mime_type(c)), - plot_style_font); + return (ctx->plot->text(ctx, + plot_style_font, + data->x, + data->y+20, + lwc_string_data(content__get_mime_type(c)), + lwc_string_length(content__get_mime_type(c))) == NSERROR_OK); } diff --git a/frontends/amiga/icon.c b/frontends/amiga/icon.c index 3f597a1ba..a92b8674c 100644 --- a/frontends/amiga/icon.c +++ b/frontends/amiga/icon.c @@ -16,7 +16,8 @@ * along with this program. If not, see . */ -/** \file +/** + * \file * Content for image/x-amiga-icon (icon.library implementation). * */ @@ -273,8 +274,14 @@ bool amiga_icon_redraw(struct content *c, if (data->repeat_y) flags |= BITMAPF_REPEAT_Y; - return ctx->plot->bitmap(data->x, data->y, data->width, data->height, - icon_c->bitmap, data->background_colour, flags); + return (ctx->plot->bitmap(ctx, + icon_c->bitmap, + data->x, + data->y, + data->width, + data->height, + data->background_colour, + flags) == NSERROR_OK); } diff --git a/frontends/amiga/plotters.c b/frontends/amiga/plotters.c index 6bae6346a..e87171551 100644 --- a/frontends/amiga/plotters.c +++ b/frontends/amiga/plotters.c @@ -51,8 +51,15 @@ #include "amiga/rtg.h" #include "amiga/utf8.h" +/* set AMI_PLOTTER_DEBUG to 0 for no debugging, 1 for debugging */ //#define AMI_PLOTTER_DEBUG 1 +#ifdef AMI_PLOTTER_DEBUG +#define PLOT_LOG(x...) LOG(x) +#else +#define PLOT_LOG(x...) ((void) 0) +#endif + HOOKF(void, ami_bitmap_tile_hook, struct RastPort *, rp, struct BackFillMessage *); struct bfbitmap { @@ -336,171 +343,6 @@ void ami_plot_clear_bbox(struct RastPort *rp, struct IBox *bbox) } -static bool ami_rectangle(int x0, int y0, int x1, int y1, const plot_style_t *style) -{ - #ifdef AMI_PLOTTER_DEBUG - LOG("[ami_plotter] Entered ami_rectangle()"); - #endif - - if (style->fill_type != PLOT_OP_TYPE_NONE) { - ami_plot_setapen(glob->rp, style->fill_colour); - RectFill(glob->rp, x0, y0, x1-1, y1-1); - } - - if (style->stroke_type != PLOT_OP_TYPE_NONE) { - glob->rp->PenWidth = style->stroke_width; - glob->rp->PenHeight = style->stroke_width; - - switch (style->stroke_type) { - case PLOT_OP_TYPE_SOLID: /**< Solid colour */ - default: - glob->rp->LinePtrn = PATT_LINE; - break; - - case PLOT_OP_TYPE_DOT: /**< Dotted plot */ - glob->rp->LinePtrn = PATT_DOT; - break; - - case PLOT_OP_TYPE_DASH: /**< dashed plot */ - glob->rp->LinePtrn = PATT_DASH; - break; - } - - ami_plot_setapen(glob->rp, style->stroke_colour); - Move(glob->rp, x0,y0); - Draw(glob->rp, x1, y0); - Draw(glob->rp, x1, y1); - Draw(glob->rp, x0, y1); - Draw(glob->rp, x0, y0); - - glob->rp->PenWidth = 1; - glob->rp->PenHeight = 1; - glob->rp->LinePtrn = PATT_LINE; - } - - return true; -} - -static bool ami_line(int x0, int y0, int x1, int y1, const plot_style_t *style) -{ - #ifdef AMI_PLOTTER_DEBUG - LOG("[ami_plotter] Entered ami_line()"); - #endif - - glob->rp->PenWidth = style->stroke_width; - glob->rp->PenHeight = style->stroke_width; - - switch (style->stroke_type) { - case PLOT_OP_TYPE_SOLID: /**< Solid colour */ - default: - glob->rp->LinePtrn = PATT_LINE; - break; - - case PLOT_OP_TYPE_DOT: /**< Doted plot */ - glob->rp->LinePtrn = PATT_DOT; - break; - - case PLOT_OP_TYPE_DASH: /**< dashed plot */ - glob->rp->LinePtrn = PATT_DASH; - break; - } - - ami_plot_setapen(glob->rp, style->stroke_colour); - Move(glob->rp,x0,y0); - Draw(glob->rp,x1,y1); - - glob->rp->PenWidth = 1; - glob->rp->PenHeight = 1; - glob->rp->LinePtrn = PATT_LINE; - - return true; -} - -static bool ami_polygon(const int *p, unsigned int n, const plot_style_t *style) -{ - #ifdef AMI_PLOTTER_DEBUG - LOG("[ami_plotter] Entered ami_polygon()"); - #endif - - ami_plot_setapen(glob->rp, style->fill_colour); - - if(AreaMove(glob->rp,p[0],p[1]) == -1) - LOG("AreaMove: vector list full"); - - for(uint32 k = 1; k < n; k++) { - if(AreaDraw(glob->rp,p[k*2],p[(k*2)+1]) == -1) - LOG("AreaDraw: vector list full"); - } - - if(AreaEnd(glob->rp) == -1) - LOG("AreaEnd: error"); - - return true; -} - - -static bool ami_clip(const struct rect *clip) -{ - #ifdef AMI_PLOTTER_DEBUG - LOG("[ami_plotter] Entered ami_clip()"); - #endif - - struct Region *reg = NULL; - - if(glob->rp->Layer) - { - reg = NewRegion(); - - glob->rect.MinX = clip->x0; - glob->rect.MinY = clip->y0; - glob->rect.MaxX = clip->x1-1; - glob->rect.MaxY = clip->y1-1; - - OrRectRegion(reg,&glob->rect); - - reg = InstallClipRegion(glob->rp->Layer,reg); - - if(reg) DisposeRegion(reg); - } - - return true; -} - -static bool ami_text(int x, int y, const char *text, size_t length, - const plot_font_style_t *fstyle) -{ - #ifdef AMI_PLOTTER_DEBUG - LOG("[ami_plotter] Entered ami_text()"); - #endif - - if(__builtin_expect(ami_nsfont == NULL, 0)) return false; - - ami_plot_setapen(glob->rp, fstyle->foreground); - ami_nsfont->text(glob->rp, text, length, fstyle, x, y, nsoption_bool(font_antialiasing)); - - return true; -} - -static bool ami_disc(int x, int y, int radius, const plot_style_t *style) -{ - #ifdef AMI_PLOTTER_DEBUG - LOG("[ami_plotter] Entered ami_disc()"); - #endif - - if (style->fill_type != PLOT_OP_TYPE_NONE) { - ami_plot_setapen(glob->rp, style->fill_colour); - AreaCircle(glob->rp,x,y,radius); - AreaEnd(glob->rp); - } - - if (style->stroke_type != PLOT_OP_TYPE_NONE) { - ami_plot_setapen(glob->rp, style->stroke_colour); - DrawEllipse(glob->rp,x,y,radius,radius); - } - - return true; -} - static void ami_arc_gfxlib(int x, int y, int radius, int angle1, int angle2) { double angle1_r = (double)(angle1) * (M_PI / 180.0); @@ -526,46 +368,37 @@ static void ami_arc_gfxlib(int x, int y, int radius, int angle1, int angle2) } } -static bool ami_arc(int x, int y, int radius, int angle1, int angle2, const plot_style_t *style) -{ - #ifdef AMI_PLOTTER_DEBUG - LOG("[ami_plotter] Entered ami_arc()"); - #endif - - if (angle2 < angle1) angle2 += 360; - - ami_plot_setapen(glob->rp, style->fill_colour); - ami_arc_gfxlib(x, y, radius, angle1, angle2); - - return true; -} - -static bool ami_bitmap(int x, int y, int width, int height, struct bitmap *bitmap) +/** + */ +static nserror +ami_bitmap(int x, int y, int width, int height, struct bitmap *bitmap) { - #ifdef AMI_PLOTTER_DEBUG - LOG("[ami_plotter] Entered ami_bitmap()"); - #endif + PLOT_LOG("[ami_plotter] Entered ami_bitmap()"); struct BitMap *tbm; - if(!width || !height) return true; + if (!width || !height) { + return NSERROR_OK; + } - if(((x + width) < glob->rect.MinX) || - ((y + height) < glob->rect.MinY) || - (x > glob->rect.MaxX) || - (y > glob->rect.MaxY)) - return true; + if (((x + width) < glob->rect.MinX) || + ((y + height) < glob->rect.MinY) || + (x > glob->rect.MaxX) || + (y > glob->rect.MaxY)) { + return NSERROR_OK; + } tbm = ami_bitmap_get_native(bitmap, width, height, glob->rp->BitMap); - if(!tbm) return true; + if (!tbm) { + return NSERROR_OK; + } - #ifdef AMI_PLOTTER_DEBUG - LOG("[ami_plotter] ami_bitmap() got native bitmap"); - #endif + PLOT_LOG("[ami_plotter] ami_bitmap() got native bitmap"); #ifdef __amigaos4__ - if(__builtin_expect((GfxBase->LibNode.lib_Version >= 53) && (glob->palette_mapped == false) && - (nsoption_bool(direct_render) == false), 1)) { + if (__builtin_expect((GfxBase->LibNode.lib_Version >= 53) && + (glob->palette_mapped == false) && + (nsoption_bool(direct_render) == false), 1)) { uint32 comptype = COMPOSITE_Src_Over_Dest; uint32 compflags = COMPFLAG_IgnoreDestAlpha; if(amiga_bitmap_get_opaque(bitmap)) { @@ -585,19 +418,18 @@ static bool ami_bitmap(int x, int y, int width, int height, struct bitmap *bitma COMPTAG_OffsetY,y, COMPTAG_FriendBitMap, scrn->RastPort.BitMap, TAG_DONE); - } - else + } else #endif { ULONG tag, tag_data, minterm = 0xc0; - if(glob->palette_mapped == false) { + if (glob->palette_mapped == false) { tag = BLITA_UseSrcAlpha; tag_data = !amiga_bitmap_get_opaque(bitmap); minterm = 0xc0; } else { tag = BLITA_MaskPlane; - if((tag_data = (ULONG)ami_bitmap_get_mask(bitmap, width, height, tbm))) + if ((tag_data = (ULONG)ami_bitmap_get_mask(bitmap, width, height, tbm))) minterm = MINTERM_SRCMASK; } #ifdef __amigaos4__ @@ -613,7 +445,7 @@ static bool ami_bitmap(int x, int y, int width, int height, struct bitmap *bitma tag, tag_data, TAG_DONE); #else - if(tag_data) { + if (tag_data) { BltMaskBitMapRastPort(tbm, 0, 0, glob->rp, x, y, width, height, minterm, tag_data); } else { BltBitMapRastPort(tbm, 0, 0, glob->rp, x, y, width, height, 0xc0); @@ -621,118 +453,13 @@ static bool ami_bitmap(int x, int y, int width, int height, struct bitmap *bitma #endif } - if((ami_bitmap_is_nativebm(bitmap, tbm) == false)) { + if ((ami_bitmap_is_nativebm(bitmap, tbm) == false)) { ami_rtg_freebitmap(tbm); } - return true; + return NSERROR_OK; } -static bool ami_bitmap_tile(int x, int y, int width, int height, - struct bitmap *bitmap, colour bg, - bitmap_flags_t flags) -{ - #ifdef AMI_PLOTTER_DEBUG - LOG("[ami_plotter] Entered ami_bitmap_tile()"); - #endif - - int xf,yf,xm,ym,oy,ox; - struct BitMap *tbm = NULL; - struct Hook *bfh = NULL; - struct bfbitmap bfbm; - bool repeat_x = (flags & BITMAPF_REPEAT_X); - bool repeat_y = (flags & BITMAPF_REPEAT_Y); - - if((width == 0) || (height == 0)) return true; - - if(!(repeat_x || repeat_y)) - return ami_bitmap(x, y, width, height, bitmap); - - /* If it is a one pixel transparent image, we are wasting our time */ - if((amiga_bitmap_get_opaque(bitmap) == false) && - (bitmap_get_width(bitmap) == 1) && (bitmap_get_height(bitmap) == 1)) - return true; - - tbm = ami_bitmap_get_native(bitmap,width,height,glob->rp->BitMap); - if(!tbm) return true; - - ox = x; - oy = y; - - /* get left most tile position */ - for (; ox > 0; ox -= width) - ; - - /* get top most tile position */ - for (; oy > 0; oy -= height) - ; - - if(ox<0) ox = -ox; - if(oy<0) oy = -oy; - - if(repeat_x) - { - xf = glob->rect.MaxX; - xm = glob->rect.MinX; - } - else - { - xf = x + width; - xm = x; - } - - if(repeat_y) - { - yf = glob->rect.MaxY; - ym = glob->rect.MinY; - } - else - { - yf = y + height; - ym = y; - } -#ifdef __amigaos4__ - if(amiga_bitmap_get_opaque(bitmap)) - { - bfh = CreateBackFillHook(BFHA_BitMap,tbm, - BFHA_Width,width, - BFHA_Height,height, - BFHA_OffsetX,ox, - BFHA_OffsetY,oy, - TAG_DONE); - } - else -#endif - { - bfbm.bm = tbm; - bfbm.width = width; - bfbm.height = height; - bfbm.offsetx = ox; - bfbm.offsety = oy; - bfbm.mask = ami_bitmap_get_mask(bitmap, width, height, tbm); - bfh = calloc(1, sizeof(struct Hook)); - bfh->h_Entry = (HOOKFUNC)ami_bitmap_tile_hook; - bfh->h_SubEntry = 0; - bfh->h_Data = &bfbm; - } - - InstallLayerHook(glob->rp->Layer,bfh); - EraseRect(glob->rp,xm,ym,xf,yf); - InstallLayerHook(glob->rp->Layer,LAYERS_NOBACKFILL); - -#ifdef __amigaos4__ - if(amiga_bitmap_get_opaque(bitmap)) DeleteBackFillHook(bfh); - else -#endif - free(bfh); - - if((ami_bitmap_is_nativebm(bitmap, tbm) == false)) { - /**\todo is this logic logical? */ - ami_rtg_freebitmap(tbm); - } - - return true; -} HOOKF(void, ami_bitmap_tile_hook, struct RastPort *, rp, struct BackFillMessage *) { @@ -757,8 +484,7 @@ HOOKF(void, ami_bitmap_tile_hook, struct RastPort *, rp, struct BackFillMessage COMPTAG_OffsetY, yf, COMPTAG_FriendBitMap, scrn->RastPort.BitMap, TAG_DONE); - } - else + } else #endif { ULONG tag, tag_data, minterm = 0xc0; @@ -805,42 +531,323 @@ static void ami_bezier(struct bez_point *restrict a, struct bez_point *restrict p->y = pow((1 - t), 3) * a->y + 3 * t * pow((1 -t), 2) * b->y + 3 * (1-t) * pow(t, 2)* c->y + pow (t, 3)* d->y; } -static bool ami_path(const float *p, unsigned int n, colour fill, float width, - colour c, const float transform[6]) + +bool ami_plot_screen_is_palettemapped(void) +{ + return glob->palette_mapped; +} + + +/** + * \brief Sets a clip rectangle for subsequent plot operations. + * + * \param ctx The current redraw context. + * \param clip The rectangle to limit all subsequent plot + * operations within. + * \return NSERROR_OK on success else error code. + */ +static nserror +ami_clip(const struct redraw_context *ctx, const struct rect *clip) +{ + struct Region *reg = NULL; + + PLOT_LOG("[ami_plotter] Entered ami_clip()"); + + if (glob->rp->Layer) { + reg = NewRegion(); + + glob->rect.MinX = clip->x0; + glob->rect.MinY = clip->y0; + glob->rect.MaxX = clip->x1-1; + glob->rect.MaxY = clip->y1-1; + + OrRectRegion(reg,&glob->rect); + + reg = InstallClipRegion(glob->rp->Layer,reg); + + if(reg) { + DisposeRegion(reg); + } + } + + return NSERROR_OK; +} + + +/** + * Plots an arc + * + * plot an arc segment around (x,y), anticlockwise from angle1 + * to angle2. Angles are measured anticlockwise from + * horizontal, in degrees. + * + * \param ctx The current redraw context. + * \param pstyle Style controlling the arc plot. + * \param x The x coordinate of the arc. + * \param y The y coordinate of the arc. + * \param radius The radius of the arc. + * \param angle1 The start angle of the arc. + * \param angle2 The finish angle of the arc. + * \return NSERROR_OK on success else error code. + */ +static nserror +ami_arc(const struct redraw_context *ctx, + const plot_style_t *style, + int x, int y, int radius, int angle1, int angle2) +{ + PLOT_LOG("[ami_plotter] Entered ami_arc()"); + + if (angle2 < angle1) { + angle2 += 360; + } + + ami_plot_setapen(glob->rp, style->fill_colour); + ami_arc_gfxlib(x, y, radius, angle1, angle2); + + return NSERROR_OK; +} + + +/** + * Plots a circle + * + * Plot a circle centered on (x,y), which is optionally filled. + * + * \param ctx The current redraw context. + * \param pstyle Style controlling the circle plot. + * \param x x coordinate of circle centre. + * \param y y coordinate of circle centre. + * \param radius circle radius. + * \return NSERROR_OK on success else error code. + */ +static nserror +ami_disc(const struct redraw_context *ctx, + const plot_style_t *style, + int x, int y, int radius) +{ + PLOT_LOG("[ami_plotter] Entered ami_disc()"); + + if (style->fill_type != PLOT_OP_TYPE_NONE) { + ami_plot_setapen(glob->rp, style->fill_colour); + AreaCircle(glob->rp,x,y,radius); + AreaEnd(glob->rp); + } + + if (style->stroke_type != PLOT_OP_TYPE_NONE) { + ami_plot_setapen(glob->rp, style->stroke_colour); + DrawEllipse(glob->rp,x,y,radius,radius); + } + + return NSERROR_OK; +} + + +/** + * Plots a line + * + * plot a line from (x0,y0) to (x1,y1). Coordinates are at + * centre of line width/thickness. + * + * \param ctx The current redraw context. + * \param pstyle Style controlling the line plot. + * \param line A rectangle defining the line to be drawn + * \return NSERROR_OK on success else error code. + */ +static nserror +ami_line(const struct redraw_context *ctx, + const plot_style_t *style, + const struct rect *line) +{ + PLOT_LOG("[ami_plotter] Entered ami_line()"); + + glob->rp->PenWidth = style->stroke_width; + glob->rp->PenHeight = style->stroke_width; + + switch (style->stroke_type) { + case PLOT_OP_TYPE_SOLID: /**< Solid colour */ + default: + glob->rp->LinePtrn = PATT_LINE; + break; + + case PLOT_OP_TYPE_DOT: /**< Doted plot */ + glob->rp->LinePtrn = PATT_DOT; + break; + + case PLOT_OP_TYPE_DASH: /**< dashed plot */ + glob->rp->LinePtrn = PATT_DASH; + break; + } + + ami_plot_setapen(glob->rp, style->stroke_colour); + Move(glob->rp, line->x0, line->y0); + Draw(glob->rp, line->x1, line->y1); + + glob->rp->PenWidth = 1; + glob->rp->PenHeight = 1; + glob->rp->LinePtrn = PATT_LINE; + + return NSERROR_OK; +} + + +/** + * Plots a rectangle. + * + * The rectangle can be filled an outline or both controlled + * by the plot style The line can be solid, dotted or + * dashed. Top left corner at (x0,y0) and rectangle has given + * width and height. + * + * \param ctx The current redraw context. + * \param pstyle Style controlling the rectangle plot. + * \param rect A rectangle defining the line to be drawn + * \return NSERROR_OK on success else error code. + */ +static nserror +ami_rectangle(const struct redraw_context *ctx, + const plot_style_t *style, + const struct rect *rect) +{ + PLOT_LOG("[ami_plotter] Entered ami_rectangle()"); + + if (style->fill_type != PLOT_OP_TYPE_NONE) { + ami_plot_setapen(glob->rp, style->fill_colour); + RectFill(glob->rp, rect->x0, rect->y0, rect->x1- 1 , rect->y1 - 1); + } + + if (style->stroke_type != PLOT_OP_TYPE_NONE) { + glob->rp->PenWidth = style->stroke_width; + glob->rp->PenHeight = style->stroke_width; + + switch (style->stroke_type) { + case PLOT_OP_TYPE_SOLID: /**< Solid colour */ + default: + glob->rp->LinePtrn = PATT_LINE; + break; + + case PLOT_OP_TYPE_DOT: /**< Dotted plot */ + glob->rp->LinePtrn = PATT_DOT; + break; + + case PLOT_OP_TYPE_DASH: /**< dashed plot */ + glob->rp->LinePtrn = PATT_DASH; + break; + } + + ami_plot_setapen(glob->rp, style->stroke_colour); + Move(glob->rp, rect->x0, rect->y0); + Draw(glob->rp, rect->x1, rect->y0); + Draw(glob->rp, rect->x1, rect->y1); + Draw(glob->rp, rect->x0, rect->y1); + Draw(glob->rp, rect->x0, rect->y0); + + glob->rp->PenWidth = 1; + glob->rp->PenHeight = 1; + glob->rp->LinePtrn = PATT_LINE; + } + + return NSERROR_OK; +} + + +/** + * Plot a polygon + * + * Plots a filled polygon with straight lines between + * points. The lines around the edge of the ploygon are not + * plotted. The polygon is filled with the non-zero winding + * rule. + * + * \param ctx The current redraw context. + * \param pstyle Style controlling the polygon plot. + * \param p verticies of polygon + * \param n number of verticies. + * \return NSERROR_OK on success else error code. + */ +static nserror +ami_polygon(const struct redraw_context *ctx, + const plot_style_t *style, + const int *p, + unsigned int n) +{ + PLOT_LOG("[ami_plotter] Entered ami_polygon()"); + + ami_plot_setapen(glob->rp, style->fill_colour); + + if (AreaMove(glob->rp,p[0],p[1]) == -1) { + LOG("AreaMove: vector list full"); + } + + for (uint32 k = 1; k < n; k++) { + if (AreaDraw(glob->rp,p[k*2],p[(k*2)+1]) == -1) { + LOG("AreaDraw: vector list full"); + } + } + + if (AreaEnd(glob->rp) == -1) { + LOG("AreaEnd: error"); + } + + return NSERROR_OK; +} + + +/** + * Plots a path. + * + * Path plot consisting of cubic Bezier curves. Line and fill colour is + * controlled by the plot style. + * + * \param ctx The current redraw context. + * \param pstyle Style controlling the path plot. + * \param p elements of path + * \param n nunber of elements on path + * \param width The width of the path + * \param transform A transform to apply to the path. + * \return NSERROR_OK on success else error code. + */ +static nserror +ami_path(const struct redraw_context *ctx, + const plot_style_t *pstyle, + const float *p, + unsigned int n, + float width, + const float transform[6]) { unsigned int i; struct bez_point start_p = {0, 0}, cur_p = {0, 0}, p_a, p_b, p_c, p_r; - #ifdef AMI_PLOTTER_DEBUG - LOG("[ami_plotter] Entered ami_path()"); - #endif + PLOT_LOG("[ami_plotter] Entered ami_path()"); - if (n == 0) - return true; + if (n == 0) { + return NSERROR_OK; + } if (p[0] != PLOTTER_PATH_MOVE) { LOG("Path does not start with move"); - return false; + return NSERROR_INVALID; } - if (fill != NS_TRANSPARENT) { - ami_plot_setapen(glob->rp, fill); - if (c != NS_TRANSPARENT) - ami_plot_setopen(glob->rp, c); + if (pstyle->fill_colour != NS_TRANSPARENT) { + ami_plot_setapen(glob->rp, pstyle->fill_colour); + if (pstyle->stroke_colour != NS_TRANSPARENT) { + ami_plot_setopen(glob->rp, pstyle->stroke_colour); + } } else { - if (c != NS_TRANSPARENT) { - ami_plot_setapen(glob->rp, c); + if (pstyle->stroke_colour != NS_TRANSPARENT) { + ami_plot_setapen(glob->rp, pstyle->stroke_colour); } else { - return true; /* wholly transparent */ + return NSERROR_OK; /* wholly transparent */ } } /* Construct path */ for (i = 0; i < n; ) { if (p[i] == PLOTTER_PATH_MOVE) { - if (fill != NS_TRANSPARENT) { - if(AreaMove(glob->rp, p[i+1], p[i+2]) == -1) + if (pstyle->fill_colour != NS_TRANSPARENT) { + if (AreaMove(glob->rp, p[i+1], p[i+2]) == -1) { LOG("AreaMove: vector list full"); + } } else { Move(glob->rp, p[i+1], p[i+2]); } @@ -851,17 +858,19 @@ static bool ami_path(const float *p, unsigned int n, colour fill, float width, cur_p.y = start_p.y; i += 3; } else if (p[i] == PLOTTER_PATH_CLOSE) { - if (fill != NS_TRANSPARENT) { - if(AreaEnd(glob->rp) == -1) + if (pstyle->fill_colour != NS_TRANSPARENT) { + if (AreaEnd(glob->rp) == -1) { LOG("AreaEnd: error"); + } } else { Draw(glob->rp, start_p.x, start_p.y); } i++; } else if (p[i] == PLOTTER_PATH_LINE) { - if (fill != NS_TRANSPARENT) { - if(AreaDraw(glob->rp, p[i+1], p[i+2]) == -1) + if (pstyle->fill_colour != NS_TRANSPARENT) { + if (AreaDraw(glob->rp, p[i+1], p[i+2]) == -1) { LOG("AreaDraw: vector list full"); + } } else { Draw(glob->rp, p[i+1], p[i+2]); } @@ -876,11 +885,12 @@ static bool ami_path(const float *p, unsigned int n, colour fill, float width, p_c.x = p[i+5]; p_c.y = p[i+6]; - for(double t = 0.0; t <= 1.0; t += 0.1) { + for (double t = 0.0; t <= 1.0; t += 0.1) { ami_bezier(&cur_p, &p_a, &p_b, &p_c, t, &p_r); - if (fill != NS_TRANSPARENT) { - if(AreaDraw(glob->rp, p_r.x, p_r.y) == -1) + if (pstyle->fill_colour != NS_TRANSPARENT) { + if (AreaDraw(glob->rp, p_r.x, p_r.y) == -1) { LOG("AreaDraw: vector list full"); + } } else { Draw(glob->rp, p_r.x, p_r.y); } @@ -891,25 +901,187 @@ static bool ami_path(const float *p, unsigned int n, colour fill, float width, } else { LOG("bad path command %f", p[i]); /* End path for safety if using Area commands */ - if (fill != NS_TRANSPARENT) { + if (pstyle->fill_colour != NS_TRANSPARENT) { AreaEnd(glob->rp); BNDRYOFF(glob->rp); } - return false; + return NSERROR_INVALID; } } - if (fill != NS_TRANSPARENT) + if (pstyle->fill_colour != NS_TRANSPARENT) { BNDRYOFF(glob->rp); + } - return true; + return NSERROR_OK; } -bool ami_plot_screen_is_palettemapped(void) + +/** + * Plot a bitmap + * + * Tiled plot of a bitmap image. (x,y) gives the top left + * coordinate of an explicitly placed tile. From this tile the + * image can repeat in all four directions -- up, down, left + * and right -- to the extents given by the current clip + * rectangle. + * + * The bitmap_flags say whether to tile in the x and y + * directions. If not tiling in x or y directions, the single + * image is plotted. The width and height give the dimensions + * the image is to be scaled to. + * + * \param ctx The current redraw context. + * \param bitmap The bitmap to plot + * \param x The x coordinate to plot the bitmap + * \param y The y coordiante to plot the bitmap + * \param width The width of area to plot the bitmap into + * \param height The height of area to plot the bitmap into + * \param bg the background colour to alpha blend into + * \param flags the flags controlling the type of plot operation + * \return NSERROR_OK on success else error code. + */ +static nserror +ami_bitmap_tile(const struct redraw_context *ctx, + struct bitmap *bitmap, + int x, int y, + int width, + int height, + colour bg, + bitmap_flags_t flags) { - return glob->palette_mapped; + int xf,yf,xm,ym,oy,ox; + struct BitMap *tbm = NULL; + struct Hook *bfh = NULL; + struct bfbitmap bfbm; + bool repeat_x = (flags & BITMAPF_REPEAT_X); + bool repeat_y = (flags & BITMAPF_REPEAT_Y); + + PLOT_LOG("[ami_plotter] Entered ami_bitmap_tile()"); + + if ((width == 0) || (height == 0)) { + return NSERROR_OK; + } + + if (!(repeat_x || repeat_y)) { + return ami_bitmap(x, y, width, height, bitmap); + } + + /* If it is a one pixel transparent image, we are wasting our time */ + if ((amiga_bitmap_get_opaque(bitmap) == false) && + (bitmap_get_width(bitmap) == 1) && + (bitmap_get_height(bitmap) == 1)) { + return NSERROR_OK; + } + + tbm = ami_bitmap_get_native(bitmap,width,height,glob->rp->BitMap); + if (!tbm) { + return NSERROR_OK; + } + + ox = x; + oy = y; + + /* get left most tile position */ + for (; ox > 0; ox -= width) + + /* get top most tile position */ + for (; oy > 0; oy -= height); + + if (ox < 0) { + ox = -ox; + } + if (oy < 0) { + oy = -oy; + } + if (repeat_x) { + xf = glob->rect.MaxX; + xm = glob->rect.MinX; + } else { + xf = x + width; + xm = x; + } + + if (repeat_y) { + yf = glob->rect.MaxY; + ym = glob->rect.MinY; + } else { + yf = y + height; + ym = y; + } +#ifdef __amigaos4__ + if(amiga_bitmap_get_opaque(bitmap)) { + bfh = CreateBackFillHook(BFHA_BitMap,tbm, + BFHA_Width,width, + BFHA_Height,height, + BFHA_OffsetX,ox, + BFHA_OffsetY,oy, + TAG_DONE); + } else +#endif + { + bfbm.bm = tbm; + bfbm.width = width; + bfbm.height = height; + bfbm.offsetx = ox; + bfbm.offsety = oy; + bfbm.mask = ami_bitmap_get_mask(bitmap, width, height, tbm); + bfh = calloc(1, sizeof(struct Hook)); + bfh->h_Entry = (HOOKFUNC)ami_bitmap_tile_hook; + bfh->h_SubEntry = 0; + bfh->h_Data = &bfbm; + } + + InstallLayerHook(glob->rp->Layer,bfh); + EraseRect(glob->rp,xm,ym,xf,yf); + InstallLayerHook(glob->rp->Layer,LAYERS_NOBACKFILL); + +#ifdef __amigaos4__ + if (amiga_bitmap_get_opaque(bitmap)) { + DeleteBackFillHook(bfh); + } else +#endif + free(bfh); + + if ((ami_bitmap_is_nativebm(bitmap, tbm) == false)) { + /**\todo is this logic logical? */ + ami_rtg_freebitmap(tbm); + } + + return NSERROR_OK; +} + + +/** + * Text plotting. + * + * \param ctx The current redraw context. + * \param fstyle plot style for this text + * \param x x coordinate + * \param y y coordinate + * \param text UTF-8 string to plot + * \param length length of string, in bytes + * \return NSERROR_OK on success else error code. + */ +static nserror +ami_text(const struct redraw_context *ctx, + const struct plot_font_style *fstyle, + int x, + int y, + const char *text, + size_t length) +{ + PLOT_LOG("[ami_plotter] Entered ami_text()"); + + if (__builtin_expect(ami_nsfont == NULL, 0)) { + return NSERROR_OK; + } + ami_plot_setapen(glob->rp, fstyle->foreground); + ami_nsfont->text(glob->rp, text, length, fstyle, x, y, nsoption_bool(font_antialiasing)); + + return NSERROR_OK; } -struct plotter_table plot; + const struct plotter_table amiplot = { .rectangle = ami_rectangle, .line = ami_line, diff --git a/frontends/amiga/plugin_hack.c b/frontends/amiga/plugin_hack.c index 7fe78b9b0..2327f9190 100644 --- a/frontends/amiga/plugin_hack.c +++ b/frontends/amiga/plugin_hack.c @@ -152,16 +152,27 @@ bool amiga_plugin_hack_redraw(struct content *c, .stroke_colour = 0x000000, .stroke_width = 1, }; + struct rect rect; + nserror res; LOG("amiga_plugin_hack_redraw"); - ctx->plot->rectangle(data->x, data->y, data->x + data->width, - data->y + data->height, &pstyle); + rect.x0 = data->x; + rect.y0 = data->y; + rect.x1 = data->x + data->width; + rect.y1 = data->y + data->height; - return ctx->plot->text(data->x, data->y+20, - lwc_string_data(content__get_mime_type(c)), - lwc_string_length(content__get_mime_type(c)), - plot_style_font); + ctx->plot->rectangle(ctx, &pstyle, &rect); + + res = ctx->plot->text(ctx, + plot_style_font, + data->x, data->y+20, + lwc_string_data(content__get_mime_type(c)), + lwc_string_length(content__get_mime_type(c))); + if (res != NSERROR_OK) { + return false; + } + return true; } /** -- cgit v1.2.3 From 4361bfeace6f3f184e871f5598138f3f36994e99 Mon Sep 17 00:00:00 2001 From: Vincent Sanders Date: Sun, 12 Feb 2017 18:01:46 +0000 Subject: update atari plotters to new API --- frontends/atari/gui.c | 8 +- frontends/atari/plot/plot.c | 2270 ++++++++++++++++++++++++------------------- frontends/atari/plot/plot.h | 26 +- frontends/atari/rootwin.c | 22 +- frontends/atari/toolbar.c | 2 +- frontends/atari/treeview.c | 6 +- 6 files changed, 1313 insertions(+), 1021 deletions(-) diff --git a/frontends/atari/gui.c b/frontends/atari/gui.c index d4a6915cd..1287b4715 100644 --- a/frontends/atari/gui.c +++ b/frontends/atari/gui.c @@ -39,6 +39,7 @@ #include "netsurf/content.h" #include "netsurf/cookie_db.h" #include "netsurf/url_db.h" +#include "netsurf/plotters.h" #include "content/backing_store.h" #include "atari/gemtk/gemtk.h" @@ -1019,7 +1020,12 @@ static void gui_init(int argc, char** argv) nkc_init(); LOG("Initializing plotters..."); - plot_init(nsoption_charp(atari_font_driver)); + struct redraw_context ctx = { + .interactive = true, + .background_images = true, + .plot = &atari_plotters + }; + plot_init(&ctx, nsoption_charp(atari_font_driver)); aes_event_in.emi_m1leave = MO_LEAVE; aes_event_in.emi_m1.g_w = 1; diff --git a/frontends/atari/plot/plot.c b/frontends/atari/plot/plot.c index 0a0d7a494..09174287c 100644 --- a/frontends/atari/plot/plot.c +++ b/frontends/atari/plot/plot.c @@ -45,38 +45,31 @@ void vq_scrninfo(VdiHdl handle, short *work_out); struct s_view { - short x; /* drawing (screen) offset x */ - short y; /* drawing (screen) offset y */ - short w; /* width of buffer, not in sync with vis_w */ - short h; /* height of buffer, not in sync with vis_w */ - short vis_x; /* visible rectangle of the screen buffer */ - short vis_y; /* coords are relative to plot location */ - short vis_w; /* clipped to screen dimensions */ - short vis_h; /* visible width */ - struct rect abs_clipping; /* The toplevel clipping rectangle */ - struct rect clipping; /* actual clipping rectangle */ + short x; /**< drawing (screen) offset x */ + short y; /**< drawing (screen) offset y */ + short w; /**< width of buffer, not in sync with vis_w */ + short h; /**< height of buffer, not in sync with vis_w */ + short vis_x; /**< visible rectangle of the screen buffer */ + short vis_y; /**< coords are relative to plot location */ + short vis_w; /**< clipped to screen dimensions */ + short vis_h; /**< visible width */ + struct rect abs_clipping; /**< The toplevel clipping rectangle */ + struct rect clipping; /**< actual clipping rectangle */ float scale; }; -/* - * Capture the screen at x,y location - * param self instance - * param x absolute screen coords - * param y absolute screen coords - * param w width - * param h height - * - * This creates an snapshot in RGBA format (NetSurf's native format) +/** + * Garbage collection of the snapshot routine * + * this should be called after you are done with the data returned by + * snapshot_create don't access the screenshot after you called this + * function */ -static struct bitmap * snapshot_create(int x, int y, int w, int h); - -/* Garbage collection of the snapshot routine */ -/* this should be called after you are done with the data returned by snapshot_create */ -/* don't access the screenshot after you called this function */ static void snapshot_suspend(void); -/* destroy memory used by screenshot */ +/** + * destroy memory used by screenshot + */ static void snapshot_destroy(void); #ifdef WITH_8BPP_SUPPORT @@ -86,42 +79,78 @@ static char rgb_lookup[256][4]; short web_std_colors[6] = {0, 51, 102, 153, 204, 255}; unsigned short vdi_web_pal[216][3] = { - {0x000,0x000,0x000}, {0x0c8,0x000,0x000}, {0x190,0x000,0x000}, {0x258,0x000,0x000}, {0x320,0x000,0x000}, {0x3e8,0x000,0x000}, - {0x000,0x0c8,0x000}, {0x0c8,0x0c8,0x000}, {0x190,0x0c8,0x000}, {0x258,0x0c8,0x000}, {0x320,0x0c8,0x000}, {0x3e8,0x0c8,0x000}, - {0x000,0x190,0x000}, {0x0c8,0x190,0x000}, {0x190,0x190,0x000}, {0x258,0x190,0x000}, {0x320,0x190,0x000}, {0x3e8,0x190,0x000}, - {0x000,0x258,0x000}, {0x0c8,0x258,0x000}, {0x190,0x258,0x000}, {0x258,0x258,0x000}, {0x320,0x258,0x000}, {0x3e8,0x258,0x000}, - {0x000,0x320,0x000}, {0x0c8,0x320,0x000}, {0x190,0x320,0x000}, {0x258,0x320,0x000}, {0x320,0x320,0x000}, {0x3e8,0x320,0x000}, - {0x000,0x3e8,0x000}, {0x0c8,0x3e8,0x000}, {0x190,0x3e8,0x000}, {0x258,0x3e8,0x000}, {0x320,0x3e8,0x000}, {0x3e8,0x3e8,0x000}, - {0x000,0x000,0x0c8}, {0x0c8,0x000,0x0c8}, {0x190,0x000,0x0c8}, {0x258,0x000,0x0c8}, {0x320,0x000,0x0c8}, {0x3e8,0x000,0x0c8}, - {0x000,0x0c8,0x0c8}, {0x0c8,0x0c8,0x0c8}, {0x190,0x0c8,0x0c8}, {0x258,0x0c8,0x0c8}, {0x320,0x0c8,0x0c8}, {0x3e8,0x0c8,0x0c8}, - {0x000,0x190,0x0c8}, {0x0c8,0x190,0x0c8}, {0x190,0x190,0x0c8}, {0x258,0x190,0x0c8}, {0x320,0x190,0x0c8}, {0x3e8,0x190,0x0c8}, - {0x000,0x258,0x0c8}, {0x0c8,0x258,0x0c8}, {0x190,0x258,0x0c8}, {0x258,0x258,0x0c8}, {0x320,0x258,0x0c8}, {0x3e8,0x258,0x0c8}, - {0x000,0x320,0x0c8}, {0x0c8,0x320,0x0c8}, {0x190,0x320,0x0c8}, {0x258,0x320,0x0c8}, {0x320,0x320,0x0c8}, {0x3e8,0x320,0x0c8}, - {0x000,0x3e8,0x0c8}, {0x0c8,0x3e8,0x0c8}, {0x190,0x3e8,0x0c8}, {0x258,0x3e8,0x0c8}, {0x320,0x3e8,0x0c8}, {0x3e8,0x3e8,0x0c8}, - {0x000,0x000,0x190}, {0x0c8,0x000,0x190}, {0x190,0x000,0x190}, {0x258,0x000,0x190}, {0x320,0x000,0x190}, {0x3e8,0x000,0x190}, - {0x000,0x0c8,0x190}, {0x0c8,0x0c8,0x190}, {0x190,0x0c8,0x190}, {0x258,0x0c8,0x190}, {0x320,0x0c8,0x190}, {0x3e8,0x0c8,0x190}, - {0x000,0x190,0x190}, {0x0c8,0x190,0x190}, {0x190,0x190,0x190}, {0x258,0x190,0x190}, {0x320,0x190,0x190}, {0x3e8,0x190,0x190}, - {0x000,0x258,0x190}, {0x0c8,0x258,0x190}, {0x190,0x258,0x190}, {0x258,0x258,0x190}, {0x320,0x258,0x190}, {0x3e8,0x258,0x190}, - {0x000,0x320,0x190}, {0x0c8,0x320,0x190}, {0x190,0x320,0x190}, {0x258,0x320,0x190}, {0x320,0x320,0x190}, {0x3e8,0x320,0x190}, - {0x000,0x3e8,0x190}, {0x0c8,0x3e8,0x190}, {0x190,0x3e8,0x190}, {0x258,0x3e8,0x190}, {0x320,0x3e8,0x190}, {0x3e8,0x3e8,0x190}, - {0x000,0x000,0x258}, {0x0c8,0x000,0x258}, {0x190,0x000,0x258}, {0x258,0x000,0x258}, {0x320,0x000,0x258}, {0x3e8,0x000,0x258}, - {0x000,0x0c8,0x258}, {0x0c8,0x0c8,0x258}, {0x190,0x0c8,0x258}, {0x258,0x0c8,0x258}, {0x320,0x0c8,0x258}, {0x3e8,0x0c8,0x258}, - {0x000,0x190,0x258}, {0x0c8,0x190,0x258}, {0x190,0x190,0x258}, {0x258,0x190,0x258}, {0x320,0x190,0x258}, {0x3e8,0x190,0x258}, - {0x000,0x258,0x258}, {0x0c8,0x258,0x258}, {0x190,0x258,0x258}, {0x258,0x258,0x258}, {0x320,0x258,0x258}, {0x3e8,0x258,0x258}, - {0x000,0x320,0x258}, {0x0c8,0x320,0x258}, {0x190,0x320,0x258}, {0x258,0x320,0x258}, {0x320,0x320,0x258}, {0x3e8,0x320,0x258}, - {0x000,0x3e8,0x258}, {0x0c8,0x3e8,0x258}, {0x190,0x3e8,0x258}, {0x258,0x3e8,0x258}, {0x320,0x3e8,0x258}, {0x3e8,0x3e8,0x258}, - {0x000,0x000,0x320}, {0x0c8,0x000,0x320}, {0x190,0x000,0x320}, {0x258,0x000,0x320}, {0x320,0x000,0x320}, {0x3e8,0x000,0x320}, - {0x000,0x0c8,0x320}, {0x0c8,0x0c8,0x320}, {0x190,0x0c8,0x320}, {0x258,0x0c8,0x320}, {0x320,0x0c8,0x320}, {0x3e8,0x0c8,0x320}, - {0x000,0x190,0x320}, {0x0c8,0x190,0x320}, {0x190,0x190,0x320}, {0x258,0x190,0x320}, {0x320,0x190,0x320}, {0x3e8,0x190,0x320}, - {0x000,0x258,0x320}, {0x0c8,0x258,0x320}, {0x190,0x258,0x320}, {0x258,0x258,0x320}, {0x320,0x258,0x320}, {0x3e8,0x258,0x320}, - {0x000,0x320,0x320}, {0x0c8,0x320,0x320}, {0x190,0x320,0x320}, {0x258,0x320,0x320}, {0x320,0x320,0x320}, {0x3e8,0x320,0x320}, - {0x000,0x3e8,0x320}, {0x0c8,0x3e8,0x320}, {0x190,0x3e8,0x320}, {0x258,0x3e8,0x320}, {0x320,0x3e8,0x320}, {0x3e8,0x3e8,0x320}, - {0x000,0x000,0x3e8}, {0x0c8,0x000,0x3e8}, {0x190,0x000,0x3e8}, {0x258,0x000,0x3e8}, {0x320,0x000,0x3e8}, {0x3e8,0x000,0x3e8}, - {0x000,0x0c8,0x3e8}, {0x0c8,0x0c8,0x3e8}, {0x190,0x0c8,0x3e8}, {0x258,0x0c8,0x3e8}, {0x320,0x0c8,0x3e8}, {0x3e8,0x0c8,0x3e8}, - {0x000,0x190,0x3e8}, {0x0c8,0x190,0x3e8}, {0x190,0x190,0x3e8}, {0x258,0x190,0x3e8}, {0x320,0x190,0x3e8}, {0x3e8,0x190,0x3e8}, - {0x000,0x258,0x3e8}, {0x0c8,0x258,0x3e8}, {0x190,0x258,0x3e8}, {0x258,0x258,0x3e8}, {0x320,0x258,0x3e8}, {0x3e8,0x258,0x3e8}, - {0x000,0x320,0x3e8}, {0x0c8,0x320,0x3e8}, {0x190,0x320,0x3e8}, {0x258,0x320,0x3e8}, {0x320,0x320,0x3e8}, {0x3e8,0x320,0x3e8}, - {0x000,0x3e8,0x3e8}, {0x0c8,0x3e8,0x3e8}, {0x190,0x3e8,0x3e8}, {0x258,0x3e8,0x3e8}, {0x320,0x3e8,0x3e8}, {0x3e8,0x3e8,0x3e8} + {0x000,0x000,0x000}, {0x0c8,0x000,0x000}, {0x190,0x000,0x000}, + {0x258,0x000,0x000}, {0x320,0x000,0x000}, {0x3e8,0x000,0x000}, + {0x000,0x0c8,0x000}, {0x0c8,0x0c8,0x000}, {0x190,0x0c8,0x000}, + {0x258,0x0c8,0x000}, {0x320,0x0c8,0x000}, {0x3e8,0x0c8,0x000}, + {0x000,0x190,0x000}, {0x0c8,0x190,0x000}, {0x190,0x190,0x000}, + {0x258,0x190,0x000}, {0x320,0x190,0x000}, {0x3e8,0x190,0x000}, + {0x000,0x258,0x000}, {0x0c8,0x258,0x000}, {0x190,0x258,0x000}, + {0x258,0x258,0x000}, {0x320,0x258,0x000}, {0x3e8,0x258,0x000}, + {0x000,0x320,0x000}, {0x0c8,0x320,0x000}, {0x190,0x320,0x000}, + {0x258,0x320,0x000}, {0x320,0x320,0x000}, {0x3e8,0x320,0x000}, + {0x000,0x3e8,0x000}, {0x0c8,0x3e8,0x000}, {0x190,0x3e8,0x000}, + {0x258,0x3e8,0x000}, {0x320,0x3e8,0x000}, {0x3e8,0x3e8,0x000}, + {0x000,0x000,0x0c8}, {0x0c8,0x000,0x0c8}, {0x190,0x000,0x0c8}, + {0x258,0x000,0x0c8}, {0x320,0x000,0x0c8}, {0x3e8,0x000,0x0c8}, + {0x000,0x0c8,0x0c8}, {0x0c8,0x0c8,0x0c8}, {0x190,0x0c8,0x0c8}, + {0x258,0x0c8,0x0c8}, {0x320,0x0c8,0x0c8}, {0x3e8,0x0c8,0x0c8}, + {0x000,0x190,0x0c8}, {0x0c8,0x190,0x0c8}, {0x190,0x190,0x0c8}, + {0x258,0x190,0x0c8}, {0x320,0x190,0x0c8}, {0x3e8,0x190,0x0c8}, + {0x000,0x258,0x0c8}, {0x0c8,0x258,0x0c8}, {0x190,0x258,0x0c8}, + {0x258,0x258,0x0c8}, {0x320,0x258,0x0c8}, {0x3e8,0x258,0x0c8}, + {0x000,0x320,0x0c8}, {0x0c8,0x320,0x0c8}, {0x190,0x320,0x0c8}, + {0x258,0x320,0x0c8}, {0x320,0x320,0x0c8}, {0x3e8,0x320,0x0c8}, + {0x000,0x3e8,0x0c8}, {0x0c8,0x3e8,0x0c8}, {0x190,0x3e8,0x0c8}, + {0x258,0x3e8,0x0c8}, {0x320,0x3e8,0x0c8}, {0x3e8,0x3e8,0x0c8}, + {0x000,0x000,0x190}, {0x0c8,0x000,0x190}, {0x190,0x000,0x190}, + {0x258,0x000,0x190}, {0x320,0x000,0x190}, {0x3e8,0x000,0x190}, + {0x000,0x0c8,0x190}, {0x0c8,0x0c8,0x190}, {0x190,0x0c8,0x190}, + {0x258,0x0c8,0x190}, {0x320,0x0c8,0x190}, {0x3e8,0x0c8,0x190}, + {0x000,0x190,0x190}, {0x0c8,0x190,0x190}, {0x190,0x190,0x190}, + {0x258,0x190,0x190}, {0x320,0x190,0x190}, {0x3e8,0x190,0x190}, + {0x000,0x258,0x190}, {0x0c8,0x258,0x190}, {0x190,0x258,0x190}, + {0x258,0x258,0x190}, {0x320,0x258,0x190}, {0x3e8,0x258,0x190}, + {0x000,0x320,0x190}, {0x0c8,0x320,0x190}, {0x190,0x320,0x190}, + {0x258,0x320,0x190}, {0x320,0x320,0x190}, {0x3e8,0x320,0x190}, + {0x000,0x3e8,0x190}, {0x0c8,0x3e8,0x190}, {0x190,0x3e8,0x190}, + {0x258,0x3e8,0x190}, {0x320,0x3e8,0x190}, {0x3e8,0x3e8,0x190}, + {0x000,0x000,0x258}, {0x0c8,0x000,0x258}, {0x190,0x000,0x258}, + {0x258,0x000,0x258}, {0x320,0x000,0x258}, {0x3e8,0x000,0x258}, + {0x000,0x0c8,0x258}, {0x0c8,0x0c8,0x258}, {0x190,0x0c8,0x258}, + {0x258,0x0c8,0x258}, {0x320,0x0c8,0x258}, {0x3e8,0x0c8,0x258}, + {0x000,0x190,0x258}, {0x0c8,0x190,0x258}, {0x190,0x190,0x258}, + {0x258,0x190,0x258}, {0x320,0x190,0x258}, {0x3e8,0x190,0x258}, + {0x000,0x258,0x258}, {0x0c8,0x258,0x258}, {0x190,0x258,0x258}, + {0x258,0x258,0x258}, {0x320,0x258,0x258}, {0x3e8,0x258,0x258}, + {0x000,0x320,0x258}, {0x0c8,0x320,0x258}, {0x190,0x320,0x258}, + {0x258,0x320,0x258}, {0x320,0x320,0x258}, {0x3e8,0x320,0x258}, + {0x000,0x3e8,0x258}, {0x0c8,0x3e8,0x258}, {0x190,0x3e8,0x258}, + {0x258,0x3e8,0x258}, {0x320,0x3e8,0x258}, {0x3e8,0x3e8,0x258}, + {0x000,0x000,0x320}, {0x0c8,0x000,0x320}, {0x190,0x000,0x320}, + {0x258,0x000,0x320}, {0x320,0x000,0x320}, {0x3e8,0x000,0x320}, + {0x000,0x0c8,0x320}, {0x0c8,0x0c8,0x320}, {0x190,0x0c8,0x320}, + {0x258,0x0c8,0x320}, {0x320,0x0c8,0x320}, {0x3e8,0x0c8,0x320}, + {0x000,0x190,0x320}, {0x0c8,0x190,0x320}, {0x190,0x190,0x320}, + {0x258,0x190,0x320}, {0x320,0x190,0x320}, {0x3e8,0x190,0x320}, + {0x000,0x258,0x320}, {0x0c8,0x258,0x320}, {0x190,0x258,0x320}, + {0x258,0x258,0x320}, {0x320,0x258,0x320}, {0x3e8,0x258,0x320}, + {0x000,0x320,0x320}, {0x0c8,0x320,0x320}, {0x190,0x320,0x320}, + {0x258,0x320,0x320}, {0x320,0x320,0x320}, {0x3e8,0x320,0x320}, + {0x000,0x3e8,0x320}, {0x0c8,0x3e8,0x320}, {0x190,0x3e8,0x320}, + {0x258,0x3e8,0x320}, {0x320,0x3e8,0x320}, {0x3e8,0x3e8,0x320}, + {0x000,0x000,0x3e8}, {0x0c8,0x000,0x3e8}, {0x190,0x000,0x3e8}, + {0x258,0x000,0x3e8}, {0x320,0x000,0x3e8}, {0x3e8,0x000,0x3e8}, + {0x000,0x0c8,0x3e8}, {0x0c8,0x0c8,0x3e8}, {0x190,0x0c8,0x3e8}, + {0x258,0x0c8,0x3e8}, {0x320,0x0c8,0x3e8}, {0x3e8,0x0c8,0x3e8}, + {0x000,0x190,0x3e8}, {0x0c8,0x190,0x3e8}, {0x190,0x190,0x3e8}, + {0x258,0x190,0x3e8}, {0x320,0x190,0x3e8}, {0x3e8,0x190,0x3e8}, + {0x000,0x258,0x3e8}, {0x0c8,0x258,0x3e8}, {0x190,0x258,0x3e8}, + {0x258,0x258,0x3e8}, {0x320,0x258,0x3e8}, {0x3e8,0x258,0x3e8}, + {0x000,0x320,0x3e8}, {0x0c8,0x320,0x3e8}, {0x190,0x320,0x3e8}, + {0x258,0x320,0x3e8}, {0x320,0x320,0x3e8}, {0x3e8,0x320,0x3e8}, + {0x000,0x3e8,0x3e8}, {0x0c8,0x3e8,0x3e8}, {0x190,0x3e8,0x3e8}, + {0x258,0x3e8,0x3e8}, {0x320,0x3e8,0x3e8}, {0x3e8,0x3e8,0x3e8} }; #endif @@ -180,15 +209,16 @@ VdiHdl atari_plot_vdi_handle = -1; unsigned long atari_plot_flags; unsigned long atari_font_flags; -typedef bool (*bitmap_convert_fnc)( struct bitmap * img, int x, int y, - GRECT * clip, uint32_t bg, uint32_t flags, MFDB *out ); +typedef bool (*bitmap_convert_fnc)(struct bitmap * img, int x, int y, GRECT * clip, uint32_t bg, uint32_t flags, MFDB *out ); static bitmap_convert_fnc bitmap_convert; +/* exported interface documented in atari/plot.h */ const char* plot_err_str(int i) { - return(plot_error_codes[abs(i)]); + return (plot_error_codes[abs(i)]); } + /** * Set line drawing color by passing netsurf XBGR "colour" type. * @@ -200,21 +230,22 @@ inline static void vsl_rgbcolor(short vdih, colour cin) #ifdef WITH_8BPP_SUPPORT if( vdi_sysinfo.scr_bpp > 8 ) { #endif - RGB1000 c; /* a struct with three (RGB) shorts */ - rgb_to_vdi1000( (unsigned char*)&cin, &c); - vs_color(vdih, OFFSET_CUSTOM_COLOR, (short *)&c); - vsl_color(vdih, OFFSET_CUSTOM_COLOR); + RGB1000 c; /* a struct with three (RGB) shorts */ + rgb_to_vdi1000( (unsigned char*)&cin, &c); + vs_color(vdih, OFFSET_CUSTOM_COLOR, (short *)&c); + vsl_color(vdih, OFFSET_CUSTOM_COLOR); #ifdef WITH_8BPP_SUPPORT } else { - if( vdi_sysinfo.scr_bpp >= 4 ){ - vsl_color(vdih, RGB_TO_VDI(cin)); - } - else - vsl_color(vdih, BLACK); + if( vdi_sysinfo.scr_bpp >= 4 ){ + vsl_color(vdih, RGB_TO_VDI(cin)); + } + else + vsl_color(vdih, BLACK); } #endif } + /** * Set fill color by passing netsurf XBGR "colour" type. * @@ -226,23 +257,22 @@ inline static void vsf_rgbcolor(short vdih, colour cin) #ifdef WITH_8BPP_SUPPORT if( vdi_sysinfo.scr_bpp > 8 ) { #endif - RGB1000 c; /* a struct with three (RGB) shorts */ - rgb_to_vdi1000( (unsigned char*)&cin, &c); - vs_color( vdih, OFFSET_CUSTOM_COLOR, (short *)&c); - vsf_color( vdih, OFFSET_CUSTOM_COLOR ); + RGB1000 c; /* a struct with three (RGB) shorts */ + rgb_to_vdi1000( (unsigned char*)&cin, &c); + vs_color( vdih, OFFSET_CUSTOM_COLOR, (short *)&c); + vsf_color( vdih, OFFSET_CUSTOM_COLOR ); #ifdef WITH_8BPP_SUPPORT } else { - if( vdi_sysinfo.scr_bpp >= 4 ){ - vsf_color( vdih, RGB_TO_VDI(cin) ); - } - else - vsf_color( vdih, WHITE ); + if( vdi_sysinfo.scr_bpp >= 4 ){ + vsf_color( vdih, RGB_TO_VDI(cin) ); + } + else + vsf_color( vdih, WHITE ); } #endif } - /** * Get current visible coords */ @@ -255,7 +285,6 @@ inline static void plot_get_visible_grect(GRECT * out) } - /* calculate visible area of framebuffer in coords relative to framebuffer */ /* position */ /* result: */ @@ -280,24 +309,29 @@ inline static void update_visible_rect(void) common.g_h = frame.g_h = view.h; if (rc_intersect(&screen, &common)) { - view.vis_w = common.g_w; - view.vis_h = common.g_h; - if (view.x < screen.g_x) - view.vis_x = frame.g_w - common.g_w; - else - view.vis_x = 0; - if (view.y vdi_handle = vdih; if ( tos_getcookie(C_EdDI, (long *)&cookie_EdDI) == C_NOTFOUND ) { - info->EdDiVersion = 0; + info->EdDiVersion = 0; } else { - info->EdDiVersion = EdDI_version( (void *)cookie_EdDI ); + info->EdDiVersion = EdDI_version( (void *)cookie_EdDI ); } memset( &out, 0, sizeof(short)*300 ); @@ -408,10 +448,10 @@ static void read_vdi_sysinfo(short vdih, struct s_vdi_sysinfo * info) { info->scr_w = out[0]+1; info->scr_h = out[1]+1; if( out[39] == 2 ) { - info->scr_bpp = 1; - info->colors = out[39]; + info->scr_bpp = 1; + info->colors = out[39]; } else { - info->colors = out[39]; + info->colors = out[39]; } memset( &out, 0, sizeof(short)*300 ); @@ -420,31 +460,31 @@ static void read_vdi_sysinfo(short vdih, struct s_vdi_sysinfo * info) { info->maxpolycoords = out[14]; info->maxintin = out[15]; if( out[30] & 1 ) { - info->rasterscale = true; + info->rasterscale = true; } else { - info->rasterscale = false; + info->rasterscale = false; } switch( info->scr_bpp ) { case 8: - info->pixelsize=1; - break; + info->pixelsize=1; + break; case 15: case 16: - info->pixelsize=2; - break; + info->pixelsize=2; + break; case 24: - info->pixelsize=3; - break; + info->pixelsize=3; + break; case 32: - info->pixelsize=4; - break; + info->pixelsize=4; + break; case 64: - info->pixelsize=8; - break; + info->pixelsize=8; + break; default: - info->pixelsize=1; - break; + info->pixelsize=1; + break; } info->pitch = info->scr_w * info->pixelsize; @@ -452,75 +492,75 @@ static void read_vdi_sysinfo(short vdih, struct s_vdi_sysinfo * info) { info->screensize = ( info->scr_w * info->pixelsize ) * info->scr_h; if( info->EdDiVersion >= EDDI_10 ) { - memset( &out, 0, sizeof(short)*300 ); - vq_scrninfo(vdih, (short*)&out); - info->vdiformat = out[0]; - info->clut = out[1]; - info->scr_bpp = out[2]; - info->hicolors = *((unsigned long*) &out[3]); - if( info->EdDiVersion >= EDDI_11 ) { - info->pitch = out[5]; - info->screen = (void *) *((unsigned long *) &out[6]); - } - - switch( info->clut ) { - - case VDI_CLUT_HARDWARE: { - - } - break; - - case VDI_CLUT_SOFTWARE: { - int component; /* red, green, blue, alpha, overlay */ - int num_bit; - unsigned short *tmp_p; - - /* We can build masks with info here */ - tmp_p = (unsigned short *) &out[16]; - for (component=0; component<5; component++) { - for (num_bit=0; num_bit<16; num_bit++) { - unsigned short val; - - val = *tmp_p++; - - if (val == 0xffff) { - continue; - } - - switch(component) { - case 0: - info->mask_r |= 1<< val; - break; - case 1: - info->mask_g |= 1<< val; - break; - case 2: - info->mask_b |= 1<< val; - break; - case 3: - info->mask_a |= 1<< val; - break; - } - } - } - } - - /* Remove lower green bits for Intel endian screen */ - if ((info->mask_g == ((7<<13)|3)) || (info->mask_g == ((7<<13)|7))) { - info->mask_g &= ~(7<<13); - } - break; - - case VDI_CLUT_NONE: - break; - } + memset( &out, 0, sizeof(short)*300 ); + vq_scrninfo(vdih, (short*)&out); + info->vdiformat = out[0]; + info->clut = out[1]; + info->scr_bpp = out[2]; + info->hicolors = *((unsigned long*) &out[3]); + if( info->EdDiVersion >= EDDI_11 ) { + info->pitch = out[5]; + info->screen = (void *) *((unsigned long *) &out[6]); + } + + switch( info->clut ) { + + case VDI_CLUT_HARDWARE: + break; + + case VDI_CLUT_SOFTWARE: + { + int component; /* red, green, blue, alpha, overlay */ + int num_bit; + unsigned short *tmp_p; + + /* We can build masks with info here */ + tmp_p = (unsigned short *) &out[16]; + for (component=0; component<5; component++) { + for (num_bit=0; num_bit<16; num_bit++) { + unsigned short val; + + val = *tmp_p++; + + if (val == 0xffff) { + continue; + } + + switch(component) { + case 0: + info->mask_r |= 1<< val; + break; + case 1: + info->mask_g |= 1<< val; + break; + case 2: + info->mask_b |= 1<< val; + break; + case 3: + info->mask_a |= 1<< val; + break; + } + } + } + } + + /* Remove lower green bits for Intel endian screen */ + if ((info->mask_g == ((7<<13)|3)) || + (info->mask_g == ((7<<13)|7))) { + info->mask_g &= ~(7<<13); + } + break; + + case VDI_CLUT_NONE: + break; + } } } -/* - Convert an RGB color to an VDI Color -*/ +/** + * Convert an RGB color to an VDI Color + */ inline void rgb_to_vdi1000(unsigned char * in, RGB1000 *out) { double r = ((double)in[3]/255); /* prozentsatz red */ @@ -532,6 +572,7 @@ inline void rgb_to_vdi1000(unsigned char * in, RGB1000 *out) return; } + inline void vdi1000_to_rgb(unsigned short * in, unsigned char * out) { double r = ((double)in[0]/1000); /* prozentsatz red */ @@ -548,7 +589,8 @@ inline void vdi1000_to_rgb(unsigned short * in, unsigned char * out) /** * Set pixel within an 8 bit VDI standard bitmap. */ -inline static void set_stdpx( MFDB * dst, int wdplanesz, int x, int y, unsigned char val ) +inline static void +set_stdpx( MFDB * dst, int wdplanesz, int x, int y, unsigned char val ) { short * buf; short whichbit = (1<<(15-(x%16))); @@ -580,6 +622,7 @@ inline static void set_stdpx( MFDB * dst, int wdplanesz, int x, int y, unsigned *buf = (val&(1<<7)) ? ((*buf)|(whichbit)) : ((*buf)&~(whichbit)); } + /** * Read pixel from an 8 bit VDI standard bitmap. */ @@ -593,42 +636,42 @@ inline static unsigned char get_stdpx(MFDB * dst, int wdplanesz, int x, int y) buf += ((dst->fd_wdwidth*(y))+(x>>4)); if( *buf & whichbit ) - ret |= 1; + ret |= 1; buf += wdplanesz; if( *buf & whichbit ) - ret |= 2; + ret |= 2; buf += wdplanesz; if( *buf & whichbit ) - ret |= 4; + ret |= 4; buf += wdplanesz; if( *buf & whichbit ) - ret |= 8; + ret |= 8; buf += wdplanesz; if( *buf & whichbit ) - ret |= 16; + ret |= 16; buf += wdplanesz; if( *buf & whichbit ) - ret |= 32; + ret |= 32; buf += wdplanesz; if( *buf & whichbit ) - ret |= 64; + ret |= 64; buf += wdplanesz; if( *buf & whichbit ) - ret |= 128; + ret |= 128; return( ret ); } -/* - Convert an RGB color into an index into the 216 colors web pallette -*/ +/** + * Convert an RGB color into an index into the 216 colors web pallette + */ inline short rgb_to_666_index(unsigned char r, unsigned char g, unsigned char b) { short i; @@ -640,24 +683,24 @@ inline short rgb_to_666_index(unsigned char r, unsigned char g, unsigned char b) diff_b = abs(r-b); diff_c = abs(r-b); if( diff_a < 2 && diff_b < 2 && diff_c < 2 ) { - if( (r!=0XFF) && (g!=0XFF) && (b!=0XFF) ) { - if( ((r&0xF0)>>4) != 0 ) - //printf("conv gray: %x -> %d\n", ((r&0xF0)>>4) , (OFFSET_CUST_PAL) + ((r&0xF0)>>4) ); - return( (OFFSET_CUST_PAL - OFFSET_WEB_PAL) + ((r&0xF0)>>4) ); - } + if( (r!=0XFF) && (g!=0XFF) && (b!=0XFF) ) { + if( ((r&0xF0)>>4) != 0 ) + //printf("conv gray: %x -> %d\n", ((r&0xF0)>>4) , (OFFSET_CUST_PAL) + ((r&0xF0)>>4) ); + return( (OFFSET_CUST_PAL - OFFSET_WEB_PAL) + ((r&0xF0)>>4) ); + } } /* convert each 8bit color to 6bit web color: */ for( i=0; i<3; i++) { - if(0 == rgb[i] % web_std_colors[1] ) { - tval[i] = rgb[i] / web_std_colors[1]; - } else { - int pos = ((short)rgb[i] / web_std_colors[1]); - if( abs(rgb[i] - web_std_colors[pos]) > abs(rgb[i] - web_std_colors[pos+1]) ) - tval[i] = pos+1; - else - tval[i] = pos; - } + if(0 == rgb[i] % web_std_colors[1] ) { + tval[i] = rgb[i] / web_std_colors[1]; + } else { + int pos = ((short)rgb[i] / web_std_colors[1]); + if( abs(rgb[i] - web_std_colors[pos]) > abs(rgb[i] - web_std_colors[pos+1]) ) + tval[i] = pos+1; + else + tval[i] = pos; + } } return(tval[2]*36+tval[1]*6+tval[0]); } @@ -692,6 +735,7 @@ static void dump_vdi_info(short vdih) printf("};\n"); } + /** * Create an snapshot of the screen image in device format. */ @@ -702,29 +746,29 @@ static MFDB * snapshot_create_native_mfdb(int x, int y, int w, int h) /* allocate memory for the snapshot */ { - int scr_stride = MFDB_STRIDE( w ); - int scr_size = ( ((scr_stride >> 3) * h) * vdi_sysinfo.scr_bpp ); - if(size_buf_scr == 0 ){ - /* init screen mfdb */ - buf_scr.fd_addr = malloc( scr_size ); - size_buf_scr = scr_size; - } else { - if( scr_size >size_buf_scr ) { - buf_scr.fd_addr = realloc( - buf_scr.fd_addr, scr_size - ); - size_buf_scr = scr_size; - } - } - if(buf_scr.fd_addr == NULL ) { - size_buf_scr = 0; - return( NULL ); - } - buf_scr.fd_nplanes = vdi_sysinfo.scr_bpp; - buf_scr.fd_w = scr_stride; - buf_scr.fd_h = h; - buf_scr.fd_wdwidth = scr_stride >> 4; - assert(buf_scr.fd_addr != NULL ); + int scr_stride = MFDB_STRIDE( w ); + int scr_size = ( ((scr_stride >> 3) * h) * vdi_sysinfo.scr_bpp ); + if(size_buf_scr == 0 ){ + /* init screen mfdb */ + buf_scr.fd_addr = malloc( scr_size ); + size_buf_scr = scr_size; + } else { + if( scr_size >size_buf_scr ) { + buf_scr.fd_addr = realloc( + buf_scr.fd_addr, scr_size + ); + size_buf_scr = scr_size; + } + } + if(buf_scr.fd_addr == NULL ) { + size_buf_scr = 0; + return( NULL ); + } + buf_scr.fd_nplanes = vdi_sysinfo.scr_bpp; + buf_scr.fd_w = scr_stride; + buf_scr.fd_h = h; + buf_scr.fd_wdwidth = scr_stride >> 4; + assert(buf_scr.fd_addr != NULL ); } init_mfdb( 0, w, h, 0, &scr ); pxy[0] = x; @@ -736,18 +780,27 @@ static MFDB * snapshot_create_native_mfdb(int x, int y, int w, int h) pxy[6] = w-1; pxy[7] = h-1; vro_cpyfm( - atari_plot_vdi_handle, S_ONLY, (short*)&pxy, - &scr, &buf_scr - ); + atari_plot_vdi_handle, S_ONLY, (short*)&pxy, + &scr, &buf_scr + ); return( &buf_scr ); } -/* +/** * Create an snapshot of the screen in netsurf ABGR format + * + * This creates an snapshot in RGBA format (NetSurf's native format) + * + * Capture the screen at x,y location + * \param self instance + * \param x absolute screen coords + * \param y absolute screen coords + * \param w width + * \param h height */ -static struct bitmap * snapshot_create(int x, int y, int w, int h) +static struct bitmap *snapshot_create(int x, int y, int w, int h) { int err; MFDB * native; @@ -764,37 +817,37 @@ static struct bitmap * snapshot_create(int x, int y, int w, int h) native = snapshot_create_native_mfdb(x, y, w, h ); if(vfmt.bits == 32 ) - goto no_copy; + goto no_copy; /* allocate buffer for result bitmap: */ if(buf_scr_compat == NULL ) { - buf_scr_compat = atari_bitmap_create(w, h, 0); + buf_scr_compat = atari_bitmap_create(w, h, 0); } else { - buf_scr_compat = atari_bitmap_realloc( w, h, - buf_scr_compat->bpp, - w *buf_scr_compat->bpp, - BITMAP_GROW, - buf_scr_compat ); + buf_scr_compat = atari_bitmap_realloc( w, h, + buf_scr_compat->bpp, + w *buf_scr_compat->bpp, + BITMAP_GROW, + buf_scr_compat ); } /* convert screen buffer to ns format: */ err = Hermes_ConverterRequest( hermes_cnv_h, - &vfmt, - &nsfmt - ); + &vfmt, + &nsfmt + ); assert( err != 0 ); err = Hermes_ConverterCopy( hermes_cnv_h, - native->fd_addr, - 0, /* x src coord of top left in pixel coords */ - 0, /* y src coord of top left in pixel coords */ - w, h, - native->fd_w * vdi_sysinfo.pixelsize, /* stride as bytes */ - buf_scr_compat->pixdata, - 0, /* x dst coord of top left in pixel coords */ - 0, /* y dst coord of top left in pixel coords */ - w, h, - atari_bitmap_get_rowstride(buf_scr_compat) /* stride as bytes */ - ); + native->fd_addr, + 0, /* x src coord of top left in pixel coords */ + 0, /* y src coord of top left in pixel coords */ + w, h, + native->fd_w * vdi_sysinfo.pixelsize, /* stride as bytes */ + buf_scr_compat->pixdata, + 0, /* x dst coord of top left in pixel coords */ + 0, /* y dst coord of top left in pixel coords */ + w, h, + atari_bitmap_get_rowstride(buf_scr_compat) /* stride as bytes */ + ); assert( err != 0 ); return( (struct bitmap * )buf_scr_compat ); @@ -808,59 +861,61 @@ no_copy: uint32_t row, col; for (row = 0; row<(uint32_t)h; row++) { - // fd_w matches stride! - uint32_t *rowptr = ((uint32_t*)native->fd_addr + ((row*native->fd_w))); - for (col=0; col<(uint32_t)w; col++) { - *(rowptr+col) = (*(rowptr+col)<<8); - } + // fd_w matches stride! + uint32_t *rowptr = ((uint32_t*)native->fd_addr + ((row*native->fd_w))); + for (col=0; col<(uint32_t)w; col++) { + *(rowptr+col) = (*(rowptr+col)<<8); + } } return( &snapshot ); } + /** * Notify the snapshot interface that the last snapshot is no longer in use. */ static void snapshot_suspend(void) { if(size_buf_scr > CONV_KEEP_LIMIT ) { - buf_scr.fd_addr = realloc( - buf_scr.fd_addr, CONV_KEEP_LIMIT - ); - if(buf_scr.fd_addr != NULL ) { - size_buf_scr = CONV_KEEP_LIMIT; - } else { - size_buf_scr = 0; - } + buf_scr.fd_addr = realloc( + buf_scr.fd_addr, CONV_KEEP_LIMIT + ); + if(buf_scr.fd_addr != NULL ) { + size_buf_scr = CONV_KEEP_LIMIT; + } else { + size_buf_scr = 0; + } } #ifdef WITH_8BPP_SUPPORT if(size_buf_std > CONV_KEEP_LIMIT ) { - buf_std.fd_addr = realloc( - buf_std.fd_addr, CONV_KEEP_LIMIT - ); - if(buf_std.fd_addr != NULL ) { - size_buf_std = CONV_KEEP_LIMIT; - } else { - size_buf_std = 0; - } + buf_std.fd_addr = realloc( + buf_std.fd_addr, CONV_KEEP_LIMIT + ); + if(buf_std.fd_addr != NULL ) { + size_buf_std = CONV_KEEP_LIMIT; + } else { + size_buf_std = 0; + } } #endif if(buf_scr_compat != NULL ) { - size_t bs = atari_bitmap_buffer_size(buf_scr_compat ); - if( bs > CONV_KEEP_LIMIT ) { - int w = 0; - int h = 1; - w = (CONV_KEEP_LIMIT /buf_scr_compat->bpp); - assert( CONV_KEEP_LIMIT == w*buf_scr_compat->bpp ); - buf_scr_compat = atari_bitmap_realloc( w, h, - buf_scr_compat->bpp, - CONV_KEEP_LIMIT, BITMAP_SHRINK,buf_scr_compat - ); - } + size_t bs = atari_bitmap_buffer_size(buf_scr_compat ); + if( bs > CONV_KEEP_LIMIT ) { + int w = 0; + int h = 1; + w = (CONV_KEEP_LIMIT /buf_scr_compat->bpp); + assert( CONV_KEEP_LIMIT == w*buf_scr_compat->bpp ); + buf_scr_compat = atari_bitmap_realloc( w, h, + buf_scr_compat->bpp, + CONV_KEEP_LIMIT, BITMAP_SHRINK,buf_scr_compat + ); + } } } + /** * Shut down the snapshot interface. */ @@ -869,7 +924,7 @@ static void snapshot_destroy(void) free(buf_scr.fd_addr); if( buf_scr_compat != NULL) { - atari_bitmap_destroy(buf_scr_compat); + atari_bitmap_destroy(buf_scr_compat); } buf_scr.fd_addr = NULL; @@ -890,17 +945,19 @@ inline static uint32_t ablend(uint32_t pixel, uint32_t scrpixel) pixel >>= 8; scrpixel >>= 8; rb = ((pixel & 0xFF00FF) * opacity + - (scrpixel & 0xFF00FF) * transp) >> 8; + (scrpixel & 0xFF00FF) * transp) >> 8; g = ((pixel & 0x00FF00) * opacity + - (scrpixel & 0x00FF00) * transp) >> 8; + (scrpixel & 0x00FF00) * transp) >> 8; return ((rb & 0xFF00FF) | (g & 0xFF00)) << 8; } -/* - Alpha blends an image, using one pixel as the background. - The bitmap receives the result. -*/ + +/** + * Alpha blends an image, using one pixel as the background. + * + * The bitmap receives the result. + */ inline static bool ablend_pixel(struct bitmap * img, uint32_t bg, GRECT * clip) { uint32_t * imgrow; @@ -909,22 +966,25 @@ inline static bool ablend_pixel(struct bitmap * img, uint32_t bg, GRECT * clip) img_stride= atari_bitmap_get_rowstride(img); for( img_y = 0; img_y < clip->g_h; img_y++) { - imgrow = (uint32_t *)(img->pixdata + (img_stride * img_y)); - for( img_x = 0; img_x < clip->g_w; img_x++ ) { - imgrow[img_x] = ablend( imgrow[img_x], bg ); - } + imgrow = (uint32_t *)(img->pixdata + (img_stride * img_y)); + for( img_x = 0; img_x < clip->g_w; img_x++ ) { + imgrow[img_x] = ablend( imgrow[img_x], bg ); + } } return(true); } -/* - Aplha blends the foreground image (img) onto the - background images (bg). The background receives the blended - image pixels. -*/ -inline static bool ablend_bitmap( struct bitmap * img, struct bitmap * bg, - GRECT * img_clip, GRECT * bg_clip ) +/** + * Aplha blends the foreground image onto thebackground images. + * + * The background receives the blended image pixels. + */ +inline static bool +ablend_bitmap(struct bitmap *img, + struct bitmap *bg, + GRECT *img_clip, + GRECT * bg_clip ) { uint32_t * imgrow; uint32_t * screenrow; @@ -935,29 +995,29 @@ inline static bool ablend_bitmap( struct bitmap * img, struct bitmap * bg, bg_stride = atari_bitmap_get_rowstride(bg); for( img_y = img_clip->g_y, bg_y = 0; bg_y < img_clip->g_h; bg_y++, img_y++) { - imgrow = (uint32_t *)(img->pixdata + (img_stride * img_y)); - screenrow = (uint32_t *)(bg->pixdata + (bg_stride * bg_y)); - for( img_x = img_clip->g_x, bg_x = 0; bg_x < img_clip->g_w; bg_x++, img_x++ ) { - - // when the pixel isn't fully transparent,...: - if( (imgrow[img_x] & 0x0FF) != 0 ){ - screenrow[bg_x] = ablend( imgrow[img_x], screenrow[bg_x]); - } - - // FIXME, maybe this loop would be faster??: - // --- - //if( (imgrow[img_x] & 0x0FF) != 0xFF ){ - // imgrow[bg_x] = ablend( imgrow[img_x], screenrow[bg_x]); - //} - - // or maybe even this??? - // --- - //if( (imgrow[img_x] & 0x0FF) == 0xFF ){ - // screenrow[bg_x] = imgrow[img_x]; - //} else if( (imgrow[img_x] & 0x0FF) != 0x00 ) { - // screenrow[bg_x] = ablend( imgrow[img_x], screenrow[bg_x]); - //} - } + imgrow = (uint32_t *)(img->pixdata + (img_stride * img_y)); + screenrow = (uint32_t *)(bg->pixdata + (bg_stride * bg_y)); + for( img_x = img_clip->g_x, bg_x = 0; bg_x < img_clip->g_w; bg_x++, img_x++ ) { + + // when the pixel isn't fully transparent,...: + if( (imgrow[img_x] & 0x0FF) != 0 ){ + screenrow[bg_x] = ablend( imgrow[img_x], screenrow[bg_x]); + } + + // FIXME, maybe this loop would be faster??: + // --- + //if( (imgrow[img_x] & 0x0FF) != 0xFF ){ + // imgrow[bg_x] = ablend( imgrow[img_x], screenrow[bg_x]); + //} + + // or maybe even this??? + // --- + //if( (imgrow[img_x] & 0x0FF) == 0xFF ){ + // screenrow[bg_x] = imgrow[img_x]; + //} else if( (imgrow[img_x] & 0x0FF) != 0x00 ) { + // screenrow[bg_x] = ablend( imgrow[img_x], screenrow[bg_x]); + //} + } } return(false); } @@ -972,30 +1032,30 @@ static MFDB * snapshot_create_std_mfdb(int x, int y, int w, int h) { /* allocate memory for the snapshot */ { - int scr_stride = MFDB_STRIDE( w ); - int scr_size = ( ((scr_stride >> 3) * h) * vdi_sysinfo.scr_bpp ); - if(size_buf_std == 0 ){ - /* init screen mfdb */ - buf_std.fd_addr = malloc( scr_size ); - size_buf_std = scr_size; - } else { - if( scr_size >size_buf_std ) { - buf_std.fd_addr = realloc( - buf_std.fd_addr, scr_size - ); - size_buf_std = scr_size; - } - } - if(buf_std.fd_addr == NULL ) { - size_buf_std = 0; - return( NULL ); - } - buf_std.fd_nplanes = 8; - buf_std.fd_w = scr_stride; - buf_std.fd_h = h; - buf_std.fd_stand = 1; - buf_std.fd_wdwidth = scr_stride >> 4; - assert(buf_std.fd_addr != NULL ); + int scr_stride = MFDB_STRIDE( w ); + int scr_size = ( ((scr_stride >> 3) * h) * vdi_sysinfo.scr_bpp ); + if(size_buf_std == 0 ){ + /* init screen mfdb */ + buf_std.fd_addr = malloc( scr_size ); + size_buf_std = scr_size; + } else { + if( scr_size >size_buf_std ) { + buf_std.fd_addr = realloc( + buf_std.fd_addr, scr_size + ); + size_buf_std = scr_size; + } + } + if(buf_std.fd_addr == NULL ) { + size_buf_std = 0; + return( NULL ); + } + buf_std.fd_nplanes = 8; + buf_std.fd_w = scr_stride; + buf_std.fd_h = h; + buf_std.fd_stand = 1; + buf_std.fd_wdwidth = scr_stride >> 4; + assert(buf_std.fd_addr != NULL ); } MFDB * native = snapshot_create_native_mfdb(x,y,w,h ); assert( native ); @@ -1004,6 +1064,7 @@ static MFDB * snapshot_create_std_mfdb(int x, int y, int w, int h) return( &buf_std ); } + /** * Convert an bitmap to an 8 bit device dependant MFDB * \param img the bitmap (only tested with 32bit bitmaps) @@ -1015,9 +1076,14 @@ static MFDB * snapshot_create_std_mfdb(int x, int y, int w, int h) * \param out receives the converted bitmap (still owned by the plot API) * */ -static bool bitmap_convert_8(struct bitmap * img, int x, - int y, GRECT * clip, uint32_t bg, uint32_t flags, - MFDB *out ) +static bool +bitmap_convert_8(struct bitmap *img, + int x, + int y, + GRECT *clip, + uint32_t bg, + uint32_t flags, + MFDB *out) { MFDB native; MFDB stdform; @@ -1029,11 +1095,11 @@ static bool bitmap_convert_8(struct bitmap * img, int x, bool opaque = atari_bitmap_get_opaque( img ); if( opaque == false ){ - if( ( (atari_plot_flags & PLOT_FLAG_TRANS) == 0) - && - ((flags & (BITMAPF_MONOGLYPH|BITMAPF_BUFFER_NATIVE))==0) ){ - opaque = true; - } + if( ( (atari_plot_flags & PLOT_FLAG_TRANS) == 0) + && + ((flags & (BITMAPF_MONOGLYPH|BITMAPF_BUFFER_NATIVE))==0) ){ + opaque = true; + } } assert( clip->g_h > 0 ); @@ -1046,53 +1112,53 @@ static bool bitmap_convert_8(struct bitmap * img, int x, // the bitmap is fully opaque if( (opaque == true) || (flags & BITMAPF_BUFFER_NATIVE ) ){ - if( img->converted == true ){ - *out = img->native; - return( 0 ); - } - if( ( flags & BITMAPF_MONOGLYPH ) == 0 ){ - cache = true; - } + if( img->converted == true ){ + *out = img->native; + return( 0 ); + } + if( ( flags & BITMAPF_MONOGLYPH ) == 0 ){ + cache = true; + } } if( ( flags & BITMAPF_MONOGLYPH ) != 0 ){ - assert(cache == false); + assert(cache == false); } /* (re)allocate buffer for out image: */ /* altough the buffer is named "buf_packed" on 8bit systems */ /* it's not... */ if( cache == false ){ - // the size of the output will match the size of the clipping: - dststride = MFDB_STRIDE( clip->g_w ); - dstsize = ( ((dststride >> 3) * clip->g_h) * atari_plot_bpp_virt); - if (dstsize > size_buf_packed) { - int blocks = (dstsize / (CONV_BLOCK_SIZE-1))+1; - void *buf; - if (buf_packed == NULL) { - buf = malloc( blocks * CONV_BLOCK_SIZE); - } else { - buf = realloc(buf_packed, blocks * CONV_BLOCK_SIZE); - } - if (buf == NULL) { - return( 0-ERR_NO_MEM ); - } - buf_packed = buf; - size_buf_packed = blocks * CONV_BLOCK_SIZE; - } - native.fd_addr = buf_packed; + // the size of the output will match the size of the clipping: + dststride = MFDB_STRIDE( clip->g_w ); + dstsize = ( ((dststride >> 3) * clip->g_h) * atari_plot_bpp_virt); + if (dstsize > size_buf_packed) { + int blocks = (dstsize / (CONV_BLOCK_SIZE-1))+1; + void *buf; + if (buf_packed == NULL) { + buf = malloc( blocks * CONV_BLOCK_SIZE); + } else { + buf = realloc(buf_packed, blocks * CONV_BLOCK_SIZE); + } + if (buf == NULL) { + return( 0-ERR_NO_MEM ); + } + buf_packed = buf; + size_buf_packed = blocks * CONV_BLOCK_SIZE; + } + native.fd_addr = buf_packed; } else { - // the output image will be completly saved, so size of the output - // image will match the input image size. - dststride = MFDB_STRIDE( bw ); - dstsize = ( ((dststride >> 3) * bh) * atari_plot_bpp_virt); - assert( out->fd_addr == NULL ); - native.fd_addr = malloc( dstsize ); - if (native.fd_addr == NULL){ - if (scrbuf != NULL) - atari_bitmap_destroy(scrbuf); - return( 0-ERR_NO_MEM ); - } + // the output image will be completly saved, so size of the output + // image will match the input image size. + dststride = MFDB_STRIDE( bw ); + dstsize = ( ((dststride >> 3) * bh) * atari_plot_bpp_virt); + assert( out->fd_addr == NULL ); + native.fd_addr = malloc( dstsize ); + if (native.fd_addr == NULL){ + if (scrbuf != NULL) + atari_bitmap_destroy(scrbuf); + return( 0-ERR_NO_MEM ); + } } @@ -1103,29 +1169,29 @@ static bool bitmap_convert_8(struct bitmap * img, int x, */ // realloc mem for stdform if( opaque == false ){ - // point image to snapshot buffer, otherwise allocate mem - MFDB * bg = snapshot_create_std_mfdb(x, y, clip->g_w, clip->g_h); - stdform.fd_addr = bg->fd_addr; - bh = clip->g_h; + // point image to snapshot buffer, otherwise allocate mem + MFDB * bg = snapshot_create_std_mfdb(x, y, clip->g_w, clip->g_h); + stdform.fd_addr = bg->fd_addr; + bh = clip->g_h; } else { - if (dstsize > size_buf_planar) { - int blocks = (dstsize / (CONV_BLOCK_SIZE-1))+1; - void *buf; - if (buf_planar == NULL) { - buf = malloc(blocks * CONV_BLOCK_SIZE); - } else { - buf = realloc(buf_planar, blocks * CONV_BLOCK_SIZE); - } - if (buf == NULL ) { - if (cache) { - free(native.fd_addr); - } - return( 0-ERR_NO_MEM ); - } - buf_planar = buf; - size_buf_planar = blocks * CONV_BLOCK_SIZE; - } - stdform.fd_addr = buf_planar; + if (dstsize > size_buf_planar) { + int blocks = (dstsize / (CONV_BLOCK_SIZE-1))+1; + void *buf; + if (buf_planar == NULL) { + buf = malloc(blocks * CONV_BLOCK_SIZE); + } else { + buf = realloc(buf_planar, blocks * CONV_BLOCK_SIZE); + } + if (buf == NULL ) { + if (cache) { + free(native.fd_addr); + } + return( 0-ERR_NO_MEM ); + } + buf_planar = buf; + size_buf_planar = blocks * CONV_BLOCK_SIZE; + } + stdform.fd_addr = buf_planar; } stdform.fd_w = dststride; stdform.fd_h = bh; @@ -1143,67 +1209,67 @@ static bool bitmap_convert_8(struct bitmap * img, int x, int wdplanesize = stdform.fd_wdwidth*stdform.fd_h; if( opaque == false ){ - // apply transparency and convert to vdi std format - unsigned long bgcol = 0; - unsigned char prev_col = 0; - for( y=0; yg_h; y++ ){ - row = (uint32_t *)(img->pixdata + (img_stride * (y+clip->g_y))); - for( x=0; xg_w; x++ ){ - pixel = row[x+clip->g_x]; - if( (pixel&0xFF) == 0 ){ - continue; - } - if( (pixel&0xFF) < 0xF0 ){ - col = get_stdpx( &stdform, wdplanesize,x,y ); - if( (col != prev_col) || (y == 0) ) - bgcol = (((rgb_lookup[col][2] << 16) | (rgb_lookup[col][1] << 8) | (rgb_lookup[col][0]))<<8); - if( prev_col != col || prev_pixel != pixel ){ - prev_col = col; - pixel = ablend( pixel, bgcol ); - prev_pixel = pixel; - pixel = pixel >> 8; - /* convert pixel value to vdi color index: */ - col = ( ((pixel&0xFF)<<16) - | (pixel&0xFF00) - | ((pixel&0xFF0000)>>16) ); - val = RGB_TO_VDI( col ); - } - set_stdpx( &stdform, wdplanesize, x, y, val ); - } else { - if( pixel != prev_pixel ){ - /* convert pixel value to vdi color index: */ - pixel = pixel >> 8; - col = ( ((pixel&0xFF)<<16) - | (pixel&0xFF00) - | ((pixel&0xFF0000)>>16) ); - val = RGB_TO_VDI( col ); - prev_pixel = pixel; - } - set_stdpx( &stdform, wdplanesize, x, y, val ); - } - } - } - // adjust output position: - clip->g_x = 0; - clip->g_y = 0; + // apply transparency and convert to vdi std format + unsigned long bgcol = 0; + unsigned char prev_col = 0; + for( y=0; yg_h; y++ ){ + row = (uint32_t *)(img->pixdata + (img_stride * (y+clip->g_y))); + for( x=0; xg_w; x++ ){ + pixel = row[x+clip->g_x]; + if( (pixel&0xFF) == 0 ){ + continue; + } + if( (pixel&0xFF) < 0xF0 ){ + col = get_stdpx( &stdform, wdplanesize,x,y ); + if( (col != prev_col) || (y == 0) ) + bgcol = (((rgb_lookup[col][2] << 16) | (rgb_lookup[col][1] << 8) | (rgb_lookup[col][0]))<<8); + if( prev_col != col || prev_pixel != pixel ){ + prev_col = col; + pixel = ablend( pixel, bgcol ); + prev_pixel = pixel; + pixel = pixel >> 8; + /* convert pixel value to vdi color index: */ + col = ( ((pixel&0xFF)<<16) + | (pixel&0xFF00) + | ((pixel&0xFF0000)>>16) ); + val = RGB_TO_VDI( col ); + } + set_stdpx( &stdform, wdplanesize, x, y, val ); + } else { + if( pixel != prev_pixel ){ + /* convert pixel value to vdi color index: */ + pixel = pixel >> 8; + col = ( ((pixel&0xFF)<<16) + | (pixel&0xFF00) + | ((pixel&0xFF0000)>>16) ); + val = RGB_TO_VDI( col ); + prev_pixel = pixel; + } + set_stdpx( &stdform, wdplanesize, x, y, val ); + } + } + } + // adjust output position: + clip->g_x = 0; + clip->g_y = 0; } else { - // convert the whole image data to vdi std format. - for( y=0; y < bh; y++ ){ - row = (uint32_t *)(img->pixdata + (img_stride * y)); - for( x=0; x < bw; x++ ){ - pixel = row[x]; - if( pixel != prev_pixel ){ - /* convert pixel value to vdi color index: */ - pixel = pixel >> 8; - col = ( ((pixel&0xFF)<<16) - | (pixel&0xFF00) - | ((pixel&0xFF0000)>>16) ); - val = RGB_TO_VDI( col ); - prev_pixel = pixel; - } - set_stdpx( &stdform, wdplanesize, x, y, val ); - } - } + // convert the whole image data to vdi std format. + for( y=0; y < bh; y++ ){ + row = (uint32_t *)(img->pixdata + (img_stride * y)); + for( x=0; x < bw; x++ ){ + pixel = row[x]; + if( pixel != prev_pixel ){ + /* convert pixel value to vdi color index: */ + pixel = pixel >> 8; + col = ( ((pixel&0xFF)<<16) + | (pixel&0xFF00) + | ((pixel&0xFF0000)>>16) ); + val = RGB_TO_VDI( col ); + prev_pixel = pixel; + } + set_stdpx( &stdform, wdplanesize, x, y, val ); + } + } } // convert into native format: @@ -1216,8 +1282,8 @@ static bool bitmap_convert_8(struct bitmap * img, int x, vr_trnfm(atari_plot_vdi_handle, &stdform, &native ); *out = native; if( cache == true ){ - img->native = native; - img->converted = true; + img->native = native; + img->converted = true; } return(0); @@ -1225,24 +1291,30 @@ static bool bitmap_convert_8(struct bitmap * img, int x, #endif -/* - * +/** * Convert bitmap to the native screen format - * img: the bitmap - * x: coordinate where the bitmap REGION (described in clip) + * + * \param img the bitmap + * \param x coordinate where the bitmap REGION (described in clip) * shall be drawn (screen coords) - * y: coordinate where the bitmap REGION (described in clip) + * \param y coordinate where the bitmap REGION (described in clip) * shall be drawn (screen coords) - * clip: which area of the bitmap shall be drawn - * bg: background color - * flags: blit flags - * out: the result MFDB + * \param clip which area of the bitmap shall be drawn + * \param bg background color + * \param flags blit flags + * \param out the result MFDB */ -static bool bitmap_convert_tc(struct bitmap * img, int x, int y, - GRECT * clip, uint32_t bg, uint32_t flags, MFDB *out ) +static bool +bitmap_convert_tc(struct bitmap *img, + int x, + int y, + GRECT *clip, + uint32_t bg, + uint32_t flags, + MFDB *out) { - int dststride; /* stride of dest. image */ - int dstsize; /* size of dest. in byte */ + int dststride; /* stride of dest. image */ + int dstsize; /* size of dest. in byte */ int err; int bw, bh; struct bitmap * scrbuf = NULL; @@ -1250,15 +1322,14 @@ static bool bitmap_convert_tc(struct bitmap * img, int x, int y, bool cache = ( flags & BITMAPF_BUFFER_NATIVE ); bool opaque = atari_bitmap_get_opaque( img ); - if( opaque == false ){ - if( ( (atari_plot_flags & PLOT_FLAG_TRANS) == 0) - && - ((flags & (BITMAPF_MONOGLYPH|BITMAPF_BUFFER_NATIVE))==0) ){ - opaque = true; - } + if (opaque == false ) { + if( ( (atari_plot_flags & PLOT_FLAG_TRANS) == 0) + && + ((flags & (BITMAPF_MONOGLYPH|BITMAPF_BUFFER_NATIVE))==0) ){ + opaque = true; + } } - assert( clip->g_h > 0 ); assert( clip->g_w > 0 ); @@ -1277,80 +1348,80 @@ static bool bitmap_convert_tc(struct bitmap * img, int x, int y, // toolbar buttons right now. if( (opaque == true) || (flags & BITMAPF_BUFFER_NATIVE ) ){ - if( img->converted == true ){ - *out = img->native; - return( 0 ); - } - if( ( flags & BITMAPF_MONOGLYPH ) == 0 ){ - cache = true; - } + if( img->converted == true ){ + *out = img->native; + return( 0 ); + } + if( ( flags & BITMAPF_MONOGLYPH ) == 0 ){ + cache = true; + } } /* rem. if eddi xy is installed, we could directly access the screen! */ /* apply transparency to the image: */ if (( opaque == false )) { - /* copy the screen to an temp buffer: */ - if ((flags & BITMAPF_BUFFER_NATIVE) == 0) { - scrbuf = snapshot_create(x, y, clip->g_w, clip->g_h); - if( scrbuf != NULL ) { - - assert( clip->g_w <= bw ); - assert( clip->g_h <= bh ); - - // copy blended pixels to the screen buffer: - ablend_bitmap( img, scrbuf, clip, NULL ); - /* adjust size which gets converted: */ - bw = clip->g_w; - bh = clip->g_h; - /* adjust output position: */ - clip->g_x = 0; - clip->g_y = 0; - /* set the source of conversion: */ - source = scrbuf; - } - } else { - /* - The whole bitmap can be transformed to an mfdb - (and get's cached) - */ - GRECT region = { 0, 0, bw, bh }; - ablend_pixel( img, bg, ®ion ); - source = img; - } + /* copy the screen to an temp buffer: */ + if ((flags & BITMAPF_BUFFER_NATIVE) == 0) { + scrbuf = snapshot_create(x, y, clip->g_w, clip->g_h); + if( scrbuf != NULL ) { + + assert( clip->g_w <= bw ); + assert( clip->g_h <= bh ); + + // copy blended pixels to the screen buffer: + ablend_bitmap( img, scrbuf, clip, NULL ); + /* adjust size which gets converted: */ + bw = clip->g_w; + bh = clip->g_h; + /* adjust output position: */ + clip->g_x = 0; + clip->g_y = 0; + /* set the source of conversion: */ + source = scrbuf; + } + } else { + /* + The whole bitmap can be transformed to an mfdb + (and get's cached) + */ + GRECT region = { 0, 0, bw, bh }; + ablend_pixel( img, bg, ®ion ); + source = img; + } } else { - source = img; + source = img; } /* (re)allocate buffer for converted image: */ dststride = MFDB_STRIDE(bw); dstsize = ( ((dststride >> 3) * bh) * atari_plot_bpp_virt ); if (cache == false) { - /* ensure cache buffer is large enough */ - if (dstsize > size_buf_packed) { - int blocks = (dstsize / (CONV_BLOCK_SIZE-1))+1; - void *buf; - if (buf_packed == NULL) { - buf = malloc(blocks * CONV_BLOCK_SIZE); - } else { - buf = realloc(buf_packed, blocks * CONV_BLOCK_SIZE); - } - if (buf == NULL ) { - if (scrbuf != NULL) { - atari_bitmap_destroy(scrbuf); - } - return( 0-ERR_NO_MEM ); - } - buf_packed = buf; - size_buf_packed = blocks * CONV_BLOCK_SIZE; - } - out->fd_addr = buf_packed; + /* ensure cache buffer is large enough */ + if (dstsize > size_buf_packed) { + int blocks = (dstsize / (CONV_BLOCK_SIZE-1))+1; + void *buf; + if (buf_packed == NULL) { + buf = malloc(blocks * CONV_BLOCK_SIZE); + } else { + buf = realloc(buf_packed, blocks * CONV_BLOCK_SIZE); + } + if (buf == NULL ) { + if (scrbuf != NULL) { + atari_bitmap_destroy(scrbuf); + } + return( 0-ERR_NO_MEM ); + } + buf_packed = buf; + size_buf_packed = blocks * CONV_BLOCK_SIZE; + } + out->fd_addr = buf_packed; } else { - assert( out->fd_addr == NULL ); - out->fd_addr = (void*)malloc( dstsize ); - if( out->fd_addr == NULL ){ - if( scrbuf != NULL ) - atari_bitmap_destroy( scrbuf ); - return( 0-ERR_NO_MEM ); - } + assert( out->fd_addr == NULL ); + out->fd_addr = (void*)malloc( dstsize ); + if( out->fd_addr == NULL ){ + if( scrbuf != NULL ) + atari_bitmap_destroy( scrbuf ); + return( 0-ERR_NO_MEM ); + } } out->fd_w = dststride; @@ -1361,10 +1432,10 @@ static bool bitmap_convert_tc(struct bitmap * img, int x, int y, out->fd_r1 = out->fd_r2 = out->fd_r3 = 0; err = Hermes_ConverterRequest( - hermes_cnv_h, - &nsfmt, - &vfmt - ); + hermes_cnv_h, + &nsfmt, + &vfmt + ); assert( err != 0 ); // FIXME: here we can use the same optimization which is used for @@ -1372,43 +1443,44 @@ static bool bitmap_convert_tc(struct bitmap * img, int x, int y, /* convert image to virtual format: */ err = Hermes_ConverterCopy( hermes_cnv_h, - source->pixdata, - 0, /* x src coord of top left in pixel coords */ - 0, /* y src coord of top left in pixel coords */ - bw, bh, - source->rowstride, /* stride as bytes */ - out->fd_addr, - 0, /* x dst coord of top left in pixel coords */ - 0, /* y dst coord of top left in pixel coords */ - bw, bh, - (dststride >> 3) * atari_plot_bpp_virt /* stride as bytes */ - ); + source->pixdata, + 0, /* x src coord of top left in pixel coords */ + 0, /* y src coord of top left in pixel coords */ + bw, bh, + source->rowstride, /* stride as bytes */ + out->fd_addr, + 0, /* x dst coord of top left in pixel coords */ + 0,/* y dst coord of top left in pixel coords */ + bw, bh, + (dststride >> 3) * atari_plot_bpp_virt /* stride as bytes */ + ); assert( err != 0 ); if( cache == true ){ - img->native = *out; - img->converted = true; + img->native = *out; + img->converted = true; } return( 0 ); } + inline static void convert_bitmap_done(void) { if (size_buf_packed > CONV_KEEP_LIMIT) { - void *buf; - /* free the mem if it was an large allocation ... */ - buf = realloc(buf_packed, CONV_KEEP_LIMIT); - if (buf != NULL) { - buf_packed = buf; - size_buf_packed = CONV_KEEP_LIMIT; - } + void *buf; + /* free the mem if it was an large allocation ... */ + buf = realloc(buf_packed, CONV_KEEP_LIMIT); + if (buf != NULL) { + buf_packed = buf; + size_buf_packed = CONV_KEEP_LIMIT; + } } } bool plot_blit_bitmap(struct bitmap * bmp, int x, int y, - unsigned long bg, unsigned long flags ) + unsigned long bg, unsigned long flags ) { MFDB src_mf; MFDB scrmf; @@ -1431,7 +1503,7 @@ bool plot_blit_bitmap(struct bitmap * bmp, int x, int y, clip.g_h = view.clipping.y1 - view.clipping.y0; if( !rc_intersect( &clip, &off) ) { - return(true); + return(true); } // clip the visible rectangle of the plot area @@ -1439,7 +1511,7 @@ bool plot_blit_bitmap(struct bitmap * bmp, int x, int y, // screen region: plot_get_visible_grect(&vis); if( !rc_intersect( &vis, &off) ) { - return(true); + return(true); } screen_x = view.x + off.g_x; @@ -1453,8 +1525,8 @@ bool plot_blit_bitmap(struct bitmap * bmp, int x, int y, /* Convert the Bitmap to native screen format - ready for output. */ /* This includes blending transparent pixels: */ if (bitmap_convert(bmp, screen_x, screen_y, &off, bg, flags, &src_mf) - != 0 ) { - return(true); + != 0 ) { + return(true); } // setup the src region: @@ -1475,8 +1547,9 @@ bool plot_blit_bitmap(struct bitmap * bmp, int x, int y, return(true); } + bool plot_blit_mfdb(GRECT * loc, MFDB * insrc, short fgcolor, - uint32_t flags) + uint32_t flags) { MFDB screen; // MFDB tran; @@ -1487,7 +1560,7 @@ bool plot_blit_mfdb(GRECT * loc, MFDB * insrc, short fgcolor, plot_get_clip_grect(&off); if( rc_intersect(loc, &off) == 0 ){ - return( 1 ); + return( 1 ); } init_mfdb( 0, loc->g_w, loc->g_h, 0, &screen ); @@ -1527,53 +1600,48 @@ bool plot_blit_mfdb(GRECT * loc, MFDB * insrc, short fgcolor, if( flags & PLOT_FLAG_TRANS && src->fd_nplanes == 1){ - vrt_cpyfm(atari_plot_vdi_handle, MD_REPLACE/*MD_TRANS*/, (short*)pxy, src, &screen, (short*)&c); + vrt_cpyfm(atari_plot_vdi_handle, MD_REPLACE/*MD_TRANS*/, (short*)pxy, src, &screen, (short*)&c); } else { - /* this method only plots transparent bitmaps, right now... */ + /* this method only plots transparent bitmaps, right now... */ } return( 1 ); } -/* - Init screen and font driver objects. - Returns non-zero value > -1 when the objects could be succesfully created. - Returns value < 0 to indicate an error -*/ -int plot_init(char * fdrvrname) +/* exported interface documented in atari/plot.h */ +int plot_init(const struct redraw_context *ctx, char *fdrvrname) { - - GRECT loc_pos= {0,0,360,400}; + GRECT loc_pos = { 0, 0, 360, 400 }; int err=0; if( nsoption_int(atari_dither) == 1) - atari_plot_flags |= PLOT_FLAG_DITHER; + atari_plot_flags |= PLOT_FLAG_DITHER; if( nsoption_int(atari_transparency) == 1 ) - atari_plot_flags |= PLOT_FLAG_TRANS; + atari_plot_flags |= PLOT_FLAG_TRANS; if( nsoption_int(atari_font_monochrom) == 1 ) - atari_font_flags |= FONTPLOT_FLAG_MONOGLYPH; + atari_font_flags |= FONTPLOT_FLAG_MONOGLYPH; - if(atari_plot_vdi_handle == -1) { + if (atari_plot_vdi_handle == -1) { - short dummy; - short work_in[12] = {Getrez()+2,1,1,1,1,1,1,1,1,1,2,1}; - short work_out[57]; - atari_plot_vdi_handle=graf_handle(&dummy, &dummy, &dummy, &dummy); - v_opnvwk(work_in, &atari_plot_vdi_handle, work_out); - LOG("Plot VDI handle: %d", atari_plot_vdi_handle); + short dummy; + short work_in[12] = {Getrez()+2,1,1,1,1,1,1,1,1,1,2,1}; + short work_out[57]; + atari_plot_vdi_handle=graf_handle(&dummy, &dummy, &dummy, &dummy); + v_opnvwk(work_in, &atari_plot_vdi_handle, work_out); + LOG("Plot VDI handle: %d", atari_plot_vdi_handle); } read_vdi_sysinfo(atari_plot_vdi_handle, &vdi_sysinfo); if(verbose_log) { - dump_vdi_info(atari_plot_vdi_handle) ; - dump_font_drivers(); + dump_vdi_info(atari_plot_vdi_handle) ; + dump_font_drivers(); } fplotter = new_font_plotter(atari_plot_vdi_handle, fdrvrname, - atari_font_flags, &err); - if(err) { - const char * desc = plot_err_str(err); - LOG("Unable to load font plotter %s -> %s", fdrvrname, desc ); - die("font plotter"); + atari_font_flags, &err); + if (err) { + const char * desc = plot_err_str(err); + LOG("Unable to load font plotter %s -> %s", fdrvrname, desc ); + die("font plotter"); } memset(&view, 0, sizeof(struct s_view)); @@ -1587,9 +1655,9 @@ int plot_init(char * fdrvrname) buf_packed = NULL; buf_planar = NULL; if( vdi_sysinfo.vdiformat == VDI_FORMAT_PACK ) { - atari_plot_bpp_virt = vdi_sysinfo.scr_bpp; + atari_plot_bpp_virt = vdi_sysinfo.scr_bpp; } else { - atari_plot_bpp_virt = 8; + atari_plot_bpp_virt = 8; } plot_set_scale(1.0); @@ -1600,7 +1668,7 @@ int plot_init(char * fdrvrname) clip.y0 = 0; clip.x1 = view.w; clip.y1 = view.h; - plot_clip(&clip); + ctx->plot->clip(ctx, &clip); assert(Hermes_Init()); @@ -1610,38 +1678,38 @@ int plot_init(char * fdrvrname) /* Setup color lookup tables and palette */ unsigned char rgbcol[4]; if( vdi_sysinfo.scr_bpp <= 8 ){ - unsigned char graytone=0; - int i; - for( i=0; i<=255; i++ ) { - - // get the current color and save it for restore: - vq_color(atari_plot_vdi_handle, i, 1, (unsigned short*)&sys_pal[i][0] ); - if( i= 8 ) { - if ( i < OFFSET_CUST_PAL ){ - pal[i][0] = vdi_web_pal[i-OFFSET_WEB_PAL][0]; - pal[i][1] = vdi_web_pal[i-OFFSET_WEB_PAL][1]; - pal[i][2] = vdi_web_pal[i-OFFSET_WEB_PAL][2]; - //set the new palette color to websafe value: - vs_color(atari_plot_vdi_handle, i, &pal[i][0]); - } - if( i >= OFFSET_CUST_PAL && i= 8 ) { + if ( i < OFFSET_CUST_PAL ){ + pal[i][0] = vdi_web_pal[i-OFFSET_WEB_PAL][0]; + pal[i][1] = vdi_web_pal[i-OFFSET_WEB_PAL][1]; + pal[i][2] = vdi_web_pal[i-OFFSET_WEB_PAL][2]; + //set the new palette color to websafe value: + vs_color(atari_plot_vdi_handle, i, &pal[i][0]); + } + if( i >= OFFSET_CUST_PAL && istroke_width; - uint32_t lt; - - /* current canvas clip: */ - rclip.g_x = view.clipping.x0; - rclip.g_y = view.clipping.y0; - rclip.g_w = view.clipping.x1 - view.clipping.x0; - rclip.g_h = view.clipping.y1 - view.clipping.y0; - - /* physical clipping: */ - sclip.g_x = rclip.g_x; - sclip.g_y = rclip.g_y; - sclip.g_w = view.vis_w; - sclip.g_h = view.vis_h; - - rc_intersect(&sclip, &rclip); - r.g_x = x0; - r.g_y = y0; - r.g_w = x1 - x0; - r.g_h = y1 - y0; - - if (!rc_intersect( &rclip, &r )) { - return(true); - } - if (pstyle->stroke_type != PLOT_OP_TYPE_NONE) { - /* - manually draw the line, because we do not need vdi clipping - for vertical / horizontal line draws. - */ - if( sw == 0) - sw = 1; - - NSLT2VDI(lt, pstyle); - vsl_type(atari_plot_vdi_handle, (lt&0x0F)); - /* - if the line style is not available within VDI system, - define own style: - */ - if( (lt&0x0F) == 7 ){ - vsl_udsty(atari_plot_vdi_handle, ((lt&0xFFFF00) >> 8)); - } - vsl_width(atari_plot_vdi_handle, (short)sw ); - vsl_rgbcolor(atari_plot_vdi_handle, pstyle->stroke_colour); - /* top border: */ - if( r.g_y == y0){ - pxy[0] = view.x + r.g_x; - pxy[1] = view.y + r.g_y ; - pxy[2] = view.x + r.g_x + r.g_w; - pxy[3] = view.y + r.g_y; - v_pline(atari_plot_vdi_handle, 2, (short *)&pxy); - } - - /* right border: */ - if( r.g_x + r.g_w == x1 ){ - pxy[0] = view.x + r.g_x + r.g_w; - pxy[1] = view.y + r.g_y; - pxy[2] = view.x + r.g_x + r.g_w; - pxy[3] = view.y + r.g_y + r.g_h; - v_pline(atari_plot_vdi_handle, 2, (short *)&pxy); - } - - /* bottom border: */ - if( r.g_y+r.g_h == y1 ){ - pxy[0] = view.x + r.g_x; - pxy[1] = view.y + r.g_y+r.g_h; - pxy[2] = view.x + r.g_x+r.g_w; - pxy[3] = view.y + r.g_y+r.g_h; - v_pline(atari_plot_vdi_handle, 2, (short *)&pxy); - } - - /* left border: */ - if( r.g_x == x0 ){ - pxy[0] = view.x + r.g_x; - pxy[1] = view.y + r.g_y; - pxy[2] = view.x + r.g_x; - pxy[3] = view.y + r.g_y + r.g_h; - v_pline(atari_plot_vdi_handle, 2, (short *)&pxy); - } - } - - if( pstyle->fill_type != PLOT_OP_TYPE_NONE ){ - short stroke_width = (short)(pstyle->stroke_type != PLOT_OP_TYPE_NONE) ? - pstyle->stroke_width : 0; - - vsf_rgbcolor(atari_plot_vdi_handle, pstyle->fill_colour); - vsf_perimeter(atari_plot_vdi_handle, 0); - vsf_interior(atari_plot_vdi_handle, FIS_SOLID); - - - pxy[0] = view.x + r.g_x + stroke_width; - pxy[1] = view.y + r.g_y + stroke_width; - pxy[2] = view.x + r.g_x + r.g_w -1 - stroke_width; - pxy[3] = view.y + r.g_y + r.g_h -1 - stroke_width; - - vsf_style(atari_plot_vdi_handle, 1); - v_bar(atari_plot_vdi_handle, (short*)&pxy); - } - return (true); -} - -bool plot_line(int x0, int y0, int x1, int y1, - const plot_style_t *pstyle ) -{ - short pxy[4]; - uint32_t lt; - int sw = pstyle->stroke_width; - - if((x0 < 0 && x1 < 0) || (y0 < 0 && y1 < 0)){ - return(true); - } - - pxy[0] = view.x + MAX(0,x0); - pxy[1] = view.y + MAX(0,y0); - pxy[2] = view.x + MAX(0,x1); - pxy[3] = view.y + MAX(0,y1); - - if((y0 > view.h-1) && (y1 > view.h-1)) - return(true); - - //printf("view: %d,%d,%d,%d\n", view.x, view.y, view.w, view.h); - //printf("line: %d,%d,%d,%d\n", x0, y0, x1, y1); - - - //plot_vdi_clip(true); - if( sw == 0) - sw = 1; - NSLT2VDI(lt, pstyle) - vsl_type(atari_plot_vdi_handle, (lt&0x0F)); - /* if the line style is not available within VDI system,define own style: */ - if( (lt&0x0F) == 7 ){ - vsl_udsty(atari_plot_vdi_handle, ((lt&0xFFFF00) >> 8)); - } - vsl_width(atari_plot_vdi_handle, (short)sw); - vsl_rgbcolor(atari_plot_vdi_handle, pstyle->stroke_colour); - v_pline(atari_plot_vdi_handle, 2, (short *)&pxy ); - //plot_vdi_clip(false); - return (true); -} -static bool plot_polygon(const int *p, unsigned int n, - const plot_style_t *pstyle) -{ - short pxy[n*2]; - unsigned int i=0; - if (vdi_sysinfo.maxpolycoords > 0) - assert( (signed int)n < vdi_sysinfo.maxpolycoords); - - vsf_interior(atari_plot_vdi_handle, FIS_SOLID); - vsf_style(atari_plot_vdi_handle, 1); - for (i = 0; ifill_type == PLOT_OP_TYPE_SOLID) { - vsf_rgbcolor(atari_plot_vdi_handle, pstyle->fill_colour); - v_fillarea(atari_plot_vdi_handle, n, (short*)&pxy); - } else { - pxy[n*2]=pxy[0]; - pxy[n*2+1]=pxy[1]; - vsl_rgbcolor(atari_plot_vdi_handle, pstyle->stroke_colour); - v_pline(atari_plot_vdi_handle, n+1, (short *)&pxy); - } - - return ( true ); -} - -/*** - * Set plot origin and canvas size - * \param x the x origin - * \param y the y origin - * \param w the width of the plot area - * \param h the height of the plot area - */ -bool plot_set_dimensions(int x, int y, int w, int h) +/* exported interface documented in atari/plot.h */ +bool +plot_set_dimensions(const struct redraw_context *ctx, int x, int y, int w, int h) { bool doupdate = false; struct rect newclip = {0, 0, w, h}; GRECT absclip = {x, y, w, h}; if (!(w == view.w && h == view.h)) { - view.w = (short)w; - view.h = (short)h; - doupdate = true; + view.w = (short)w; + view.h = (short)h; + doupdate = true; } if (!(x == view.x && y == view.y)) { - view.x = (short)x; - view.y = (short)y; - doupdate = true; + view.x = (short)x; + view.y = (short)y; + doupdate = true; } if (doupdate==true) - update_visible_rect(); + update_visible_rect(); //dbg_rect("plot_set_dimensions", &newclip); plot_set_abs_clipping(&absclip); - plot_clip(&newclip); + ctx->plot->clip(ctx, &newclip); return(true); } -/*** + +/** * Get current canvas size - * \param dst the GRECT * which receives the canvas size * + * \param dst the GRECT * which receives the canvas size */ bool plot_get_dimensions(GRECT *dst) { @@ -1946,6 +1843,7 @@ bool plot_get_dimensions(GRECT *dst) return(true); } + /** * set scale of plotter. * \param scale the new scale value @@ -1961,6 +1859,7 @@ float plot_set_scale(float scale) return(ret); } + float plot_get_scale(void) { return(view.scale); @@ -1968,10 +1867,9 @@ float plot_get_scale(void) /** - * * Subsequent calls to plot_clip will be clipped by the absolute clip. - * \param area the maximum clipping rectangle (absolute screen coords) * + * \param area the maximum clipping rectangle (absolute screen coords) */ void plot_set_abs_clipping(const GRECT *area) { @@ -1980,21 +1878,20 @@ void plot_set_abs_clipping(const GRECT *area) plot_get_dimensions(&canvas); if(!rc_intersect(area, &canvas)){ - view.abs_clipping.x0 = 0; - view.abs_clipping.x1 = 0; - view.abs_clipping.y0 = 0; - view.abs_clipping.y1 = 0; - } - else { - view.abs_clipping.x0 = area->g_x; - view.abs_clipping.x1 = area->g_x + area->g_w; - view.abs_clipping.y0 = area->g_y; - view.abs_clipping.y1 = area->g_y + area->g_h; + view.abs_clipping.x0 = 0; + view.abs_clipping.x1 = 0; + view.abs_clipping.y0 = 0; + view.abs_clipping.y1 = 0; + } else { + view.abs_clipping.x0 = area->g_x; + view.abs_clipping.x1 = area->g_x + area->g_w; + view.abs_clipping.y0 = area->g_y; + view.abs_clipping.y1 = area->g_y + area->g_h; } } -/*** +/** * Get the maximum clip extent, in absolute screen coords * \param dst the structure that receives the absolute clipping */ @@ -2004,7 +1901,7 @@ void plot_get_abs_clipping(struct rect *dst) } -/*** +/** * Get the maximum clip extent, in absolute screen coords * \param dst the structure that receives the absolute clipping */ @@ -2016,7 +1913,64 @@ void plot_get_abs_clipping_grect(GRECT *dst) dst->g_h = view.abs_clipping.y1 - view.abs_clipping.y0; } -bool plot_clip(const struct rect *clip) + +VdiHdl plot_get_vdi_handle(void) +{ + return(atari_plot_vdi_handle); +} + + +long plot_get_flags(void) +{ + return(atari_plot_flags); +} + + +bool plot_get_clip(struct rect * out) +{ + out->x0 = view.clipping.x0; + out->y0 = view.clipping.y0; + out->x1 = view.clipping.x1; + out->y1 = view.clipping.y1; + return( true ); +} + + +void plot_get_clip_grect(GRECT * out) +{ + struct rect clip={0,0,0,0}; + + plot_get_clip(&clip); + + out->g_x = clip.x0; + out->g_y = clip.y0; + out->g_w = clip.x1 - clip.x0; + out->g_h = clip.y1 - clip.y0; +} + + +FONT_PLOTTER plot_get_text_plotter() +{ + return(fplotter); +} + + +void plot_set_text_plotter(FONT_PLOTTER font_plotter) +{ + fplotter = font_plotter; +} + + +/** + * \brief Sets a clip rectangle for subsequent plot operations. + * + * \param ctx The current redraw context. + * \param clip The rectangle to limit all subsequent plot + * operations within. + * \return NSERROR_OK on success else error code. + */ +static nserror +plot_clip(const struct redraw_context *ctx, const struct rect *clip) { GRECT canvas, screen, gclip, maxclip; short pxy[4]; @@ -2041,14 +1995,14 @@ bool plot_clip(const struct rect *clip) rc_intersect(&canvas, &gclip); if(gclip.g_h < 0){ - gclip.g_h = 0; + gclip.g_h = 0; } if (!rc_intersect(&screen, &gclip)) { - //dbg_rect("cliprect: ", &view.clipping); - //dbg_grect("screen: ", &canvas); - //dbg_grect("canvas clipped: ", &gclip); - //assert(1 == 0); + //dbg_rect("cliprect: ", &view.clipping); + //dbg_grect("screen: ", &canvas); + //dbg_grect("canvas clipped: ", &gclip); + //assert(1 == 0); } // When setting VDI clipping, obey to maximum cliping rectangle: @@ -2064,106 +2018,379 @@ bool plot_clip(const struct rect *clip) vs_clip(atari_plot_vdi_handle, 1, (short*)&pxy); - return ( true ); + return NSERROR_OK; } -VdiHdl plot_get_vdi_handle(void) -{ - return(atari_plot_vdi_handle); -} -long plot_get_flags(void) +/** + * Plots an arc + * + * plot an arc segment around (x,y), anticlockwise from angle1 + * to angle2. Angles are measured anticlockwise from + * horizontal, in degrees. + * + * \param ctx The current redraw context. + * \param pstyle Style controlling the arc plot. + * \param x The x coordinate of the arc. + * \param y The y coordinate of the arc. + * \param radius The radius of the arc. + * \param angle1 The start angle of the arc. + * \param angle2 The finish angle of the arc. + * \return NSERROR_OK on success else error code. + */ +static nserror +plot_arc(const struct redraw_context *ctx, + const plot_style_t *pstyle, + int x, int y, int radius, int angle1, int angle2) { - return(atari_plot_flags); + vswr_mode(atari_plot_vdi_handle, MD_REPLACE); + if (pstyle->fill_type == PLOT_OP_TYPE_NONE) { + return NSERROR_OK; + } + + if (pstyle->fill_type != PLOT_OP_TYPE_SOLID) { + vsl_rgbcolor(atari_plot_vdi_handle, pstyle->stroke_colour); + vsf_perimeter(atari_plot_vdi_handle, 1); + vsf_interior(atari_plot_vdi_handle, 1 ); + v_arc(atari_plot_vdi_handle, + view.x + x, + view.y + y, + radius, + angle1 * 10, + angle2 * 10); + } else { + vsf_rgbcolor(atari_plot_vdi_handle, pstyle->fill_colour); + vsl_width(atari_plot_vdi_handle, 1); + vsf_perimeter(atari_plot_vdi_handle, 1); + v_arc(atari_plot_vdi_handle, + view.x + x, + view.y + y, radius, + angle1 * 10, + angle2 * 10); + } + + return NSERROR_OK; } -bool plot_get_clip(struct rect * out) +/** + * Plots a circle + * + * Plot a circle centered on (x,y), which is optionally filled. + * + * \param ctx The current redraw context. + * \param pstyle Style controlling the circle plot. + * \param x x coordinate of circle centre. + * \param y y coordinate of circle centre. + * \param radius circle radius. + * \return NSERROR_OK on success else error code. + */ +static nserror +plot_disc(const struct redraw_context *ctx, + const plot_style_t *pstyle, + int x, int y, int radius) { - out->x0 = view.clipping.x0; - out->y0 = view.clipping.y0; - out->x1 = view.clipping.x1; - out->y1 = view.clipping.y1; - return( true ); + if (pstyle->fill_type != PLOT_OP_TYPE_SOLID) { + vsf_rgbcolor(atari_plot_vdi_handle, pstyle->stroke_colour); + vsf_perimeter(atari_plot_vdi_handle, 1); + vsf_interior(atari_plot_vdi_handle, 0); + v_circle(atari_plot_vdi_handle, view.x + x, view.y + y, radius); + } else { + vsf_rgbcolor(atari_plot_vdi_handle, pstyle->fill_colour); + vsf_perimeter(atari_plot_vdi_handle, 0); + vsf_interior(atari_plot_vdi_handle, FIS_SOLID); + v_circle(atari_plot_vdi_handle, view.x + x, view.y + y, radius); + } + return NSERROR_OK; } -void plot_get_clip_grect(GRECT * out) + +/** + * Plots a line + * + * plot a line from (x0,y0) to (x1,y1). Coordinates are at + * centre of line width/thickness. + * + * \param ctx The current redraw context. + * \param pstyle Style controlling the line plot. + * \param line A rectangle defining the line to be drawn + * \return NSERROR_OK on success else error code. + */ +static nserror +plot_line(const struct redraw_context *ctx, + const plot_style_t *pstyle, + const struct rect *line) { - struct rect clip={0,0,0,0}; + short pxy[4]; + uint32_t lt; + int sw = pstyle->stroke_width; - plot_get_clip(&clip); + if (((line->x0 < 0) && (line->x1 < 0)) || + ((line->y0 < 0) && (line->y1 < 0))) { + return NSERROR_OK; + } - out->g_x = clip.x0; - out->g_y = clip.y0; - out->g_w = clip.x1 - clip.x0; - out->g_h = clip.y1 - clip.y0; -} + pxy[0] = view.x + MAX(0, line->x0); + pxy[1] = view.y + MAX(0, line->y0); + pxy[2] = view.x + MAX(0, line->x1); + pxy[3] = view.y + MAX(0, line->y1); -FONT_PLOTTER plot_get_text_plotter() -{ - return(fplotter); -} + if ((line->y0 > view.h-1) && (line->y1 > view.h-1)) { + return NSERROR_OK; + } -void plot_set_text_plotter(FONT_PLOTTER font_plotter) -{ - fplotter = font_plotter; -} + //printf("view: %d,%d,%d,%d\n", view.x, view.y, view.w, view.h); + //printf("line: %d,%d,%d,%d\n", x0, y0, x1, y1); -static bool plot_text(int x, int y, const char *text, size_t length, const plot_font_style_t *fstyle ) -{ - if (view.scale != 1.0) { - plot_font_style_t newstyle = *fstyle; - newstyle.size = (int)((float)fstyle->size*view.scale); - fplotter->text(fplotter, x, y, text, length, &newstyle); - } else { - fplotter->text(fplotter, x, y, text, length, fstyle); + //plot_vdi_clip(true); + + if (sw == 0) { + sw = 1; } + NSLT2VDI(lt, pstyle) + vsl_type(atari_plot_vdi_handle, (lt&0x0F)); + /* if the line style is not available within VDI system,define own style: */ + if ((lt&0x0F) == 7 ) { + vsl_udsty(atari_plot_vdi_handle, ((lt&0xFFFF00) >> 8)); + } + vsl_width(atari_plot_vdi_handle, (short)sw); + vsl_rgbcolor(atari_plot_vdi_handle, pstyle->stroke_colour); + v_pline(atari_plot_vdi_handle, 2, (short *)&pxy ); + //plot_vdi_clip(false); - return ( true ); + return NSERROR_OK; } -static bool plot_disc(int x, int y, int radius, const plot_style_t *pstyle) + +/** + * Plots a rectangle. + * + * The rectangle can be filled an outline or both controlled + * by the plot style The line can be solid, dotted or + * dashed. Top left corner at (x0,y0) and rectangle has given + * width and height. + * + * \param ctx The current redraw context. + * \param pstyle Style controlling the rectangle plot. + * \param rect A rectangle defining the line to be drawn + * \return NSERROR_OK on success else error code. + */ +static nserror +plot_rectangle(const struct redraw_context *ctx, + const plot_style_t *pstyle, + const struct rect *rect) { - if (pstyle->fill_type != PLOT_OP_TYPE_SOLID) { - vsf_rgbcolor(atari_plot_vdi_handle, pstyle->stroke_colour); - vsf_perimeter(atari_plot_vdi_handle, 1); - vsf_interior(atari_plot_vdi_handle, 0); - v_circle(atari_plot_vdi_handle, view.x + x, view.y + y, radius); - } else { - vsf_rgbcolor(atari_plot_vdi_handle, pstyle->fill_colour); - vsf_perimeter(atari_plot_vdi_handle, 0); - vsf_interior(atari_plot_vdi_handle, FIS_SOLID); - v_circle(atari_plot_vdi_handle, view.x + x, view.y + y, radius); + short pxy[4]; + GRECT r, rclip, sclip; + int sw = pstyle->stroke_width; + uint32_t lt; + + /* current canvas clip: */ + rclip.g_x = view.clipping.x0; + rclip.g_y = view.clipping.y0; + rclip.g_w = view.clipping.x1 - view.clipping.x0; + rclip.g_h = view.clipping.y1 - view.clipping.y0; + + /* physical clipping: */ + sclip.g_x = rclip.g_x; + sclip.g_y = rclip.g_y; + sclip.g_w = view.vis_w; + sclip.g_h = view.vis_h; + + rc_intersect(&sclip, &rclip); + r.g_x = rect->x0; + r.g_y = rect->y0; + r.g_w = rect->x1 - rect->x0; + r.g_h = rect->y1 - rect->y0; + + if (!rc_intersect(&rclip, &r)) { + return NSERROR_OK; } - return(true); + if (pstyle->stroke_type != PLOT_OP_TYPE_NONE) { + /* + manually draw the line, because we do not need vdi clipping + for vertical / horizontal line draws. + */ + if (sw == 0) + sw = 1; + + NSLT2VDI(lt, pstyle); + vsl_type(atari_plot_vdi_handle, (lt&0x0F)); + /* + if the line style is not available within VDI system, + define own style: + */ + if ((lt&0x0F) == 7 ) { + vsl_udsty(atari_plot_vdi_handle, ((lt&0xFFFF00) >> 8)); + } + vsl_width(atari_plot_vdi_handle, (short)sw ); + vsl_rgbcolor(atari_plot_vdi_handle, pstyle->stroke_colour); + /* top border: */ + if (r.g_y == rect->y0) { + pxy[0] = view.x + r.g_x; + pxy[1] = view.y + r.g_y ; + pxy[2] = view.x + r.g_x + r.g_w; + pxy[3] = view.y + r.g_y; + v_pline(atari_plot_vdi_handle, 2, (short *)&pxy); + } + + /* right border: */ + if (r.g_x + r.g_w == rect->x1 ) { + pxy[0] = view.x + r.g_x + r.g_w; + pxy[1] = view.y + r.g_y; + pxy[2] = view.x + r.g_x + r.g_w; + pxy[3] = view.y + r.g_y + r.g_h; + v_pline(atari_plot_vdi_handle, 2, (short *)&pxy); + } + + /* bottom border: */ + if ( r.g_y+r.g_h == rect->y1 ) { + pxy[0] = view.x + r.g_x; + pxy[1] = view.y + r.g_y+r.g_h; + pxy[2] = view.x + r.g_x+r.g_w; + pxy[3] = view.y + r.g_y+r.g_h; + v_pline(atari_plot_vdi_handle, 2, (short *)&pxy); + } + + /* left border: */ + if ( r.g_x == rect->x0 ) { + pxy[0] = view.x + r.g_x; + pxy[1] = view.y + r.g_y; + pxy[2] = view.x + r.g_x; + pxy[3] = view.y + r.g_y + r.g_h; + v_pline(atari_plot_vdi_handle, 2, (short *)&pxy); + } + } + + if (pstyle->fill_type != PLOT_OP_TYPE_NONE ) { + short stroke_width = (short)(pstyle->stroke_type != PLOT_OP_TYPE_NONE) ? + pstyle->stroke_width : 0; + + vsf_rgbcolor(atari_plot_vdi_handle, pstyle->fill_colour); + vsf_perimeter(atari_plot_vdi_handle, 0); + vsf_interior(atari_plot_vdi_handle, FIS_SOLID); + + + pxy[0] = view.x + r.g_x + stroke_width; + pxy[1] = view.y + r.g_y + stroke_width; + pxy[2] = view.x + r.g_x + r.g_w -1 - stroke_width; + pxy[3] = view.y + r.g_y + r.g_h -1 - stroke_width; + + vsf_style(atari_plot_vdi_handle, 1); + v_bar(atari_plot_vdi_handle, (short*)&pxy); + } + + return NSERROR_OK; } -static bool plot_arc(int x, int y, int radius, int angle1, int angle2, - const plot_style_t *pstyle) + +/** + * Plot a polygon + * + * Plots a filled polygon with straight lines between + * points. The lines around the edge of the ploygon are not + * plotted. The polygon is filled with the non-zero winding + * rule. + * + * \param ctx The current redraw context. + * \param pstyle Style controlling the polygon plot. + * \param p verticies of polygon + * \param n number of verticies. + * \return NSERROR_OK on success else error code. + */ +static nserror +plot_polygon(const struct redraw_context *ctx, + const plot_style_t *pstyle, + const int *p, + unsigned int n) { + short pxy[n*2]; + unsigned int i = 0; - vswr_mode(atari_plot_vdi_handle, MD_REPLACE ); - if (pstyle->fill_type == PLOT_OP_TYPE_NONE) - return(true); - if ( pstyle->fill_type != PLOT_OP_TYPE_SOLID) { - vsl_rgbcolor(atari_plot_vdi_handle, pstyle->stroke_colour); - vsf_perimeter(atari_plot_vdi_handle, 1); - vsf_interior(atari_plot_vdi_handle, 1 ); - v_arc(atari_plot_vdi_handle, view.x + x, view.y + y, radius, angle1*10, angle2*10); + if (vdi_sysinfo.maxpolycoords > 0) + assert( (signed int)n < vdi_sysinfo.maxpolycoords); + + vsf_interior(atari_plot_vdi_handle, FIS_SOLID); + vsf_style(atari_plot_vdi_handle, 1); + for (i = 0; ifill_type == PLOT_OP_TYPE_SOLID) { + vsf_rgbcolor(atari_plot_vdi_handle, pstyle->fill_colour); + v_fillarea(atari_plot_vdi_handle, n, (short*)&pxy); } else { - vsf_rgbcolor(atari_plot_vdi_handle, pstyle->fill_colour); - vsl_width(atari_plot_vdi_handle, 1 ); - vsf_perimeter(atari_plot_vdi_handle, 1); - v_arc(atari_plot_vdi_handle, view.x + x, view.y + y, radius, angle1*10, angle2*10); + pxy[n*2]=pxy[0]; + pxy[n*2+1]=pxy[1]; + vsl_rgbcolor(atari_plot_vdi_handle, pstyle->stroke_colour); + v_pline(atari_plot_vdi_handle, n+1, (short *)&pxy); } - return (true); + return NSERROR_OK; } -static bool plot_bitmap(int x, int y, int width, int height, - struct bitmap *bitmap, colour bg, - bitmap_flags_t flags) + +/** + * Plots a path. + * + * Path plot consisting of cubic Bezier curves. Line and fill colour is + * controlled by the plot style. + * + * \param ctx The current redraw context. + * \param pstyle Style controlling the path plot. + * \param p elements of path + * \param n nunber of elements on path + * \param width The width of the path + * \param transform A transform to apply to the path. + * \return NSERROR_OK on success else error code. + */ +static nserror +plot_path(const struct redraw_context *ctx, + const plot_style_t *pstyle, + const float *p, + unsigned int n, + float width, + const float transform[6]) +{ + /** \todo Implement atari path plot */ + return NSERROR_OK; +} + + +/** + * Plot a bitmap + * + * Tiled plot of a bitmap image. (x,y) gives the top left + * coordinate of an explicitly placed tile. From this tile the + * image can repeat in all four directions -- up, down, left + * and right -- to the extents given by the current clip + * rectangle. + * + * The bitmap_flags say whether to tile in the x and y + * directions. If not tiling in x or y directions, the single + * image is plotted. The width and height give the dimensions + * the image is to be scaled to. + * + * \param ctx The current redraw context. + * \param bitmap The bitmap to plot + * \param x The x coordinate to plot the bitmap + * \param y The y coordiante to plot the bitmap + * \param width The width of area to plot the bitmap into + * \param height The height of area to plot the bitmap into + * \param bg the background colour to alpha blend into + * \param flags the flags controlling the type of plot operation + * \return NSERROR_OK on success else error code. + */ +static nserror +plot_bitmap(const struct redraw_context *ctx, + struct bitmap *bitmap, + int x, int y, + int width, + int height, + colour bg, + bitmap_flags_t flags) { struct bitmap * bm = NULL; bool repeat_x = (flags & BITMAPF_REPEAT_X); @@ -2175,78 +2402,109 @@ static bool plot_bitmap(int x, int y, int width, int height, bmph = atari_bitmap_get_height(bitmap); if(view.scale != 1.0){ - width = (int)(((float)width)*view.scale); - height = (int)(((float)height)*view.scale); + width = (int)(((float)width)*view.scale); + height = (int)(((float)height)*view.scale); } if ( repeat_x || repeat_y ) { - plot_get_clip(&clip); - if( repeat_x && width == 1 && repeat_y && height == 1 ) { - width = MAX( width, clip.x1 - x ); - height = MAX( height, clip.y1 - y ); - } else if( repeat_x && width == 1 ) { - width = MAX( width, clip.x1 - x); - } else if( repeat_y && height == 1) { - height = MAX( height, clip.y1 - y ); - } - } - - if( width != bmpw || height != bmph ) { - atari_bitmap_resize(bitmap, hermes_res_h, &nsfmt, width, height ); - if( bitmap->resized ) - bm = bitmap->resized; - else - bm = bitmap; + plot_get_clip(&clip); + if (repeat_x && width == 1 && repeat_y && height == 1 ) { + width = MAX( width, clip.x1 - x ); + height = MAX( height, clip.y1 - y ); + } else if (repeat_x && width == 1 ) { + width = MAX( width, clip.x1 - x); + } else if (repeat_y && height == 1) { + height = MAX( height, clip.y1 - y ); + } + } + + if (width != bmpw || height != bmph) { + atari_bitmap_resize(bitmap, hermes_res_h, &nsfmt, width, height ); + if (bitmap->resized) { + bm = bitmap->resized; + } else { + bm = bitmap; + } } else { - bm = bitmap; + bm = bitmap; } /* out of memory? */ - if( bm == NULL ) { - printf("plot: out of memory! bmp: %p, bmpres: %p\n", bitmap, bitmap->resized ); - return( true ); + if (bm == NULL) { + printf("plot: out of memory! bmp: %p, bmpres: %p\n", + bitmap, bitmap->resized ); + return NSERROR_NOMEM; } if (!(repeat_x || repeat_y) ) { - plot_blit_bitmap(bm, x, y, bg, flags ); + plot_blit_bitmap(bm, x, y, bg, flags); } else { - int xf,yf; - int xoff = x; - int yoff = y; - - if (yoff > clip.y0 ) - yoff = (clip.y0 - height) + ((yoff - clip.y0) % height); - if (xoff > clip.x0 ) - xoff = (clip.x0 - width) + ((xoff - clip.x0) % width); - /* for now, repeating just works in the rigth / down direction */ - /* - if( repeat_x == true ) - xoff = clip.x0; - if(repeat_y == true ) - yoff = clip.y0; - */ - - for( xf = xoff; xf < clip.x1; xf += width ) { - for( yf = yoff; yf < clip.y1; yf += height ) { - plot_blit_bitmap(bm, xf, yf, bg, flags ); - if (!repeat_y) - break; - } - if (!repeat_x) - break; - } - } - return ( true ); + int xf,yf; + int xoff = x; + int yoff = y; + + if (yoff > clip.y0) { + yoff = (clip.y0 - height) + ((yoff - clip.y0) % height); + } + if (xoff > clip.x0) { + xoff = (clip.x0 - width) + ((xoff - clip.x0) % width); + } + /* for now, repeating just works in the rigth / down direction */ + /* + if( repeat_x == true ) + xoff = clip.x0; + if(repeat_y == true ) + yoff = clip.y0; + */ + + for (xf = xoff; xf < clip.x1; xf += width ) { + for (yf = yoff; yf < clip.y1; yf += height ) { + plot_blit_bitmap(bm, xf, yf, bg, flags ); + if (!repeat_y) { + break; + } + } + if (!repeat_x) { + break; + } + } + } + + return NSERROR_OK; } -static bool plot_path(const float *p, unsigned int n, colour fill, float width, - colour c, const float transform[6]) -{ - return ( true ); -} +/** + * Text plotting. + * + * \param ctx The current redraw context. + * \param fstyle plot style for this text + * \param x x coordinate + * \param y y coordinate + * \param text UTF-8 string to plot + * \param length length of string, in bytes + * \return NSERROR_OK on success else error code. + */ +static nserror +plot_text(const struct redraw_context *ctx, + const struct plot_font_style *fstyle, + int x, + int y, + const char *text, + size_t length) +{ + if (view.scale != 1.0) { + plot_font_style_t newstyle = *fstyle; + newstyle.size = (int)((float)fstyle->size*view.scale); + fplotter->text(fplotter, x, y, text, length, &newstyle); + } else { + fplotter->text(fplotter, x, y, text, length, fstyle); + } + return NSERROR_OK; +} +/** atari plottr operation table */ const struct plotter_table atari_plotters = { .rectangle = plot_rectangle, .line = plot_line, diff --git a/frontends/atari/plot/plot.h b/frontends/atari/plot/plot.h index fd73a8c33..c8bf9157c 100644 --- a/frontends/atari/plot/plot.h +++ b/frontends/atari/plot/plot.h @@ -55,6 +55,7 @@ #define ERR_PLOTTER_NOT_AVAILABLE 3 /* invalid plotter driver name passed */ struct plot_style_s; +struct redraw_context; struct s_vdi_sysinfo { short vdi_handle; /**< vdi handle */ @@ -83,7 +84,15 @@ struct rect; extern const struct plotter_table atari_plotters; -int plot_init(char *); +/** + * Init screen and font driver objects. + * + * \param fdrvrname font driver name. + * \return value > 1 when the objects could be succesfully created or + * <= 0 to indicate an error. + */ +int plot_init(const struct redraw_context *ctx, char *fdrvrname); + int plot_finalise(void); /** @@ -93,7 +102,15 @@ const char* plot_err_str(int i) ; bool plot_lock(void); bool plot_unlock(void); -bool plot_set_dimensions( int x, int y, int w, int h ); + +/** + * Set plot origin and canvas size + * \param x the x origin + * \param y the y origin + * \param w the width of the plot area + * \param h the height of the plot area + */ +bool plot_set_dimensions(const struct redraw_context *ctx, int x, int y, int w, int h ); bool plot_get_dimensions(GRECT *dst); float plot_get_scale(void); float plot_set_scale(float); @@ -101,13 +118,10 @@ void plot_set_abs_clipping(const GRECT *area); void plot_get_abs_clipping(struct rect *dst); void plot_get_abs_clipping_grect(GRECT *dst); bool plot_get_clip(struct rect * out); -/* Get clipping for current framebuffer as GRECT */ +/** Get clipping for current framebuffer as GRECT */ void plot_get_clip_grect(GRECT * out); -bool plot_clip(const struct rect *clip); VdiHdl plot_get_vdi_handle(void); long plot_get_flags(void); -bool plot_rectangle( int x0, int y0, int x1, int y1,const struct plot_style_s *style ); -bool plot_line( int x0, int y0, int x1, int y1, const struct plot_style_s *style ); bool plot_blit_bitmap(struct bitmap * bmp, int x, int y, unsigned long bg, unsigned long flags); bool plot_blit_mfdb(GRECT * loc, MFDB * insrc, short fgcolor, uint32_t flags); diff --git a/frontends/atari/rootwin.c b/frontends/atari/rootwin.c index aa8e08047..0b77cbba5 100644 --- a/frontends/atari/rootwin.c +++ b/frontends/atari/rootwin.c @@ -758,8 +758,11 @@ void window_redraw_favicon(ROOTWIN *rootwin, GRECT *clip_ro) xoff = ((work.g_w-work.g_h)/2); work.g_w = work.g_h; } - plot_set_dimensions( work.g_x+xoff, work.g_y, work.g_w, - work.g_h); + plot_set_dimensions(&rootwin_rdrw_ctx, + work.g_x+xoff, + work.g_y, + work.g_w, + work.g_h); wind_get_grect(rootwin->aes_handle, WF_FIRSTXYWH, &visible); while (visible.g_h > 0 && visible.g_w > 0) { @@ -776,8 +779,14 @@ void window_redraw_favicon(ROOTWIN *rootwin, GRECT *clip_ro) vs_clip(plot_vdi_handle, 1, (short*)&pxy); //dbg_pxy("vdi clip", (short*)&pxy); - atari_plotters.bitmap(0, 0, work.g_w, work.g_h, - rootwin->icon, 0xffffff, 0); + rootwin_rdrw_ctx.plot->bitmap(&rootwin_rdrw_ctx, + rootwin->icon, + 0, + 0, + work.g_w, + work.g_h, + 0xffffff, + 0); } else { //dbg_grect("redraw vis area outside", &visible); } @@ -822,7 +831,8 @@ static void window_redraw_content(ROOTWIN *rootwin, GRECT *content_area, //dbg_grect("browser redraw, content area", content_area); //dbg_grect("browser redraw, content clip", clip); - plot_set_dimensions(content_area->g_x, content_area->g_y, + plot_set_dimensions(&rootwin_rdrw_ctx, + content_area->g_x, content_area->g_y, content_area->g_w, content_area->g_h); oldscale = plot_set_scale(browser_window_get_scale(rootwin->active_gui_window->browser->bw)); @@ -849,7 +859,7 @@ static void window_redraw_content(ROOTWIN *rootwin, GRECT *content_area, redraw_area.x1 = content_area_rel.g_x + content_area_rel.g_w; redraw_area.y1 = content_area_rel.g_y + content_area_rel.g_h; - plot_clip(&redraw_area); + rootwin_rdrw_ctx.plot->clip(&rootwin_rdrw_ctx, &redraw_area); //dbg_rect("rdrw area", &redraw_area); diff --git a/frontends/atari/toolbar.c b/frontends/atari/toolbar.c index 9ed87849c..1b9371763 100644 --- a/frontends/atari/toolbar.c +++ b/frontends/atari/toolbar.c @@ -435,7 +435,7 @@ void toolbar_redraw(struct s_toolbar *tb, GRECT *clip) if (rc_intersect(clip, &area)) { float old_scale; - plot_set_dimensions(area_ro.g_x, area_ro.g_y, area_ro.g_w, area_ro.g_h); + plot_set_dimensions(&toolbar_rdrw_ctx, area_ro.g_x, area_ro.g_y, area_ro.g_w, area_ro.g_h); struct rect r = { .x0 = MAX(0,area.g_x - area_ro.g_x), .y0 = MAX(0,area.g_y - area_ro.g_y), diff --git a/frontends/atari/treeview.c b/frontends/atari/treeview.c index 93aef6eb6..8e9834ec3 100644 --- a/frontends/atari/treeview.c +++ b/frontends/atari/treeview.c @@ -223,7 +223,11 @@ void atari_treeview_redraw(struct core_window *cw) .background_images = true, .plot = &atari_plotters }; - plot_set_dimensions(work.g_x, work.g_y, work.g_w, work.g_h); + plot_set_dimensions(&ctx, + work.g_x, + work.g_y, + work.g_w, + work.g_h); if (plot_lock() == false) return; -- cgit v1.2.3 From 513366a7a22dfeafc6a79814701ba62210ad5040 Mon Sep 17 00:00:00 2001 From: Vincent Sanders Date: Sun, 12 Feb 2017 19:56:09 +0000 Subject: update beos to new plotter API --- frontends/beos/plotters.cpp | 1126 +++++++++++++++++++++++++------------------ 1 file changed, 649 insertions(+), 477 deletions(-) diff --git a/frontends/beos/plotters.cpp b/frontends/beos/plotters.cpp index 5ba3fbbcb..6544d63bd 100644 --- a/frontends/beos/plotters.cpp +++ b/frontends/beos/plotters.cpp @@ -18,7 +18,8 @@ * along with this program. If not, see . */ -/** \file +/** + * \file * Target independent plotting (BeOS/Haiku implementation). */ @@ -50,581 +51,753 @@ extern "C" { * the right-bottom pixel is actually part of the BRect! */ -static bool nsbeos_plot_rectangle(int x0, int y0, int x1, int y1, const plot_style_t *style); -static bool nsbeos_plot_line(int x0, int y0, int x1, int y1, const plot_style_t *style); -static bool nsbeos_plot_polygon(const int *p, unsigned int n, const plot_style_t *style); -static bool nsbeos_plot_path(const float *p, unsigned int n, colour fill, float width, - colour c, const float transform[6]); -static bool nsbeos_plot_clip(const struct rect *ns_clip); -static bool nsbeos_plot_text(int x, int y, const char *text, size_t length, - const plot_font_style_t *fstyle); -static bool nsbeos_plot_disc(int x, int y, int radius, const plot_style_t *style); -static bool nsbeos_plot_arc(int x, int y, int radius, int angle1, int angle2, - const plot_style_t *style); -static bool nsbeos_plot_bitmap(int x, int y, int width, int height, - struct bitmap *bitmap, colour bg, - bitmap_flags_t flags); - - #warning make patterns nicer -static const pattern kDottedPattern = { 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa }; -static const pattern kDashedPattern = { 0xcc, 0xcc, 0x33, 0x33, 0xcc, 0xcc, 0x33, 0x33 }; - -static const rgb_color kBlackColor = { 0, 0, 0, 255 }; - -struct plotter_table plot; +static const pattern kDottedPattern = { + 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa +}; +static const pattern kDashedPattern = { + 0xcc, 0xcc, 0x33, 0x33, 0xcc, 0xcc, 0x33, 0x33 +}; -const struct plotter_table nsbeos_plotters = { - nsbeos_plot_clip, - nsbeos_plot_arc, - nsbeos_plot_disc, - nsbeos_plot_line, - nsbeos_plot_rectangle, - nsbeos_plot_polygon, - nsbeos_plot_path, - nsbeos_plot_bitmap, - nsbeos_plot_text, - NULL, // Group Start - NULL, // Group End - NULL, // Flush - true // option_knockout +static const rgb_color kBlackColor = { + 0, 0, 0, 255 }; +//struct plotter_table plot; // #pragma mark - implementation - BView *nsbeos_current_gc(void) { - return current_view; + return current_view; } + BView *nsbeos_current_gc_lock(void) { - BView *view = current_view; - if (view && view->LockLooper()) - return view; - return NULL; + BView *view = current_view; + if (view && view->LockLooper()) + return view; + return NULL; } + void nsbeos_current_gc_unlock(void) { - if (current_view) - current_view->UnlockLooper(); + if (current_view) { + current_view->UnlockLooper(); + } } + void nsbeos_current_gc_set(BView *view) { - // XXX: (un)lock previous ? - current_view = view; + // XXX: (un)lock previous ? + current_view = view; } -bool nsbeos_plot_rectangle(int x0, int y0, int x1, int y1, const plot_style_t *style) + +static nserror +nsbeos_plot_bbitmap(int x, int y, int width, int height, BBitmap *b, colour bg) { - if (style->fill_type != PLOT_OP_TYPE_NONE) { - BView *view; + /* XXX: This currently ignores the background colour supplied. + * Does this matter? + */ + + if (width == 0 || height == 0) { + return NSERROR_OK; + } + + BView *view; + + view = nsbeos_current_gc/*_lock*/(); + if (view == NULL) { + beos_warn_user("No GC", 0); + return NSERROR_INVALID; + } + + drawing_mode oldmode = view->DrawingMode(); + source_alpha alpha; + alpha_function func; + view->GetBlendingMode(&alpha, &func); + //view->SetDrawingMode(B_OP_OVER); + view->SetDrawingMode(B_OP_ALPHA); + view->SetBlendingMode(B_PIXEL_ALPHA, B_ALPHA_OVERLAY); + + // XXX DrawBitmap() resamples if rect doesn't match, + // but doesn't do any filtering + // XXX: use Zeta API if available ? + + BRect rect(x, y, x + width - 1, y + height - 1); + /* + rgb_color old = view->LowColor(); + if (bg != NS_TRANSPARENT) { + view->SetLowColor(nsbeos_rgb_colour(bg)); + view->FillRect(rect, B_SOLID_LOW); + } + */ + view->DrawBitmap(b, rect); + // maybe not needed? + //view->SetLowColor(old); + view->SetBlendingMode(alpha, func); + view->SetDrawingMode(oldmode); + + //nsbeos_current_gc_unlock(); + + return NSERROR_OK; +} - view = nsbeos_current_gc/*_lock*/(); - if (view == NULL) { - beos_warn_user("No GC", 0); - return false; - } - nsbeos_set_colour(style->fill_colour); +static BPoint transform_pt(float x, float y, const float transform[6]) +{ +#warning XXX: verify + //return BPoint(x, y); + BPoint pt; + pt.x = x * transform[0] + y * transform[1] + transform[4]; + pt.y = x * transform[2] + y * transform[3] + transform[5]; + /* + printf("TR: {%f, %f} { %f, %f, %f, %f, %f, %f} = { %f, %f }\n", + x, y, + transform[0], transform[1], transform[2], + transform[3], transform[4], transform[5], + pt.x, pt.y); + */ + return pt; +} - BRect rect(x0, y0, x1 - 1, y1 - 1); - view->FillRect(rect); - //nsbeos_current_gc_unlock(); +rgb_color nsbeos_rgb_colour(colour c) +{ + rgb_color color; + if (c == NS_TRANSPARENT) + return B_TRANSPARENT_32_BIT; + color.red = c & 0x0000ff; + color.green = (c & 0x00ff00) >> 8; + color.blue = (c & 0xff0000) >> 16; + return color; +} - } - if (style->stroke_type != PLOT_OP_TYPE_NONE) { - pattern pat; - BView *view; +void nsbeos_set_colour(colour c) +{ + rgb_color color = nsbeos_rgb_colour(c); + BView *view = nsbeos_current_gc(); + view->SetHighColor(color); +} - switch (style->stroke_type) { - case PLOT_OP_TYPE_SOLID: /**< Solid colour */ - default: - pat = B_SOLID_HIGH; - break; - case PLOT_OP_TYPE_DOT: /**< Doted plot */ - pat = kDottedPattern; - break; +/** + * Plot a caret. + * + * It is assumed that the plotters have been set up. + */ +void nsbeos_plot_caret(int x, int y, int h) +{ + BView *view; - case PLOT_OP_TYPE_DASH: /**< dashed plot */ - pat = kDashedPattern; - break; - } + view = nsbeos_current_gc/*_lock*/(); + if (view == NULL) + /* TODO: report an error here */ + return; - view = nsbeos_current_gc/*_lock*/(); - if (view == NULL) { - beos_warn_user("No GC", 0); - return false; - } + BPoint start(x, y); + BPoint end(x, y + h - 1); +#if defined(__HAIKU__) || defined(B_BEOS_VERSION_DANO) + view->SetHighColor(ui_color(B_DOCUMENT_TEXT_COLOR)); +#else + view->SetHighColor(kBlackColor); +#endif + view->StrokeLine(start, end); - nsbeos_set_colour(style->stroke_colour); + //nsbeos_current_gc_unlock(); +} - float pensize = view->PenSize(); - view->SetPenSize(style->stroke_width); - BRect rect(x0, y0, x1, y1); - view->StrokeRect(rect, pat); +/** + * \brief Sets a clip rectangle for subsequent plot operations. + * + * \param ctx The current redraw context. + * \param ns_clip The rectangle to limit all subsequent plot + * operations within. + * \return NSERROR_OK on success else error code. + */ +static nserror +nsbeos_plot_clip(const struct redraw_context *ctx, const struct rect *ns_clip) +{ + BView *view; + //fprintf(stderr, "%s(%d, %d, %d, %d)\n", __FUNCTION__, clip_x0, clip_y0, clip_x1, clip_y1); - view->SetPenSize(pensize); + view = nsbeos_current_gc/*_lock*/(); + if (view == NULL) { + beos_warn_user("No GC", 0); + return NSERROR_INVALID; + } - //nsbeos_current_gc_unlock(); + BRect rect(ns_clip->x0, ns_clip->y0, ns_clip->x1 - 1, ns_clip->y1 - 1); + BRegion clip(rect); + view->ConstrainClippingRegion(NULL); + if (view->Bounds() != rect) { + view->ConstrainClippingRegion(&clip); + } - } + //nsbeos_current_gc_unlock(); - return true; + return NSERROR_OK; } - -bool nsbeos_plot_line(int x0, int y0, int x1, int y1, const plot_style_t *style) +/** + * Plots an arc + * + * plot an arc segment around (x,y), anticlockwise from angle1 + * to angle2. Angles are measured anticlockwise from + * horizontal, in degrees. + * + * \param ctx The current redraw context. + * \param pstyle Style controlling the arc plot. + * \param x The x coordinate of the arc. + * \param y The y coordinate of the arc. + * \param radius The radius of the arc. + * \param angle1 The start angle of the arc. + * \param angle2 The finish angle of the arc. + * \return NSERROR_OK on success else error code. + */ +static nserror +nsbeos_plot_arc(const struct redraw_context *ctx, + const plot_style_t *style, + int x, int y, int radius, int angle1, int angle2) { - pattern pat; - BView *view; + BView *view; + + view = nsbeos_current_gc/*_lock*/(); + if (view == NULL) { + beos_warn_user("No GC", 0); + return NSERROR_INVALID; + } - switch (style->stroke_type) { - case PLOT_OP_TYPE_SOLID: /**< Solid colour */ - default: - pat = B_SOLID_HIGH; - break; + nsbeos_set_colour(style->fill_colour); - case PLOT_OP_TYPE_DOT: /**< Doted plot */ - pat = kDottedPattern; - break; + BPoint center(x, y); + float angle = angle1; // in degree + float span = angle2 - angle1; // in degree + view->StrokeArc(center, radius, radius, angle, span); - case PLOT_OP_TYPE_DASH: /**< dashed plot */ - pat = kDashedPattern; - break; - } + //nsbeos_current_gc_unlock(); + + return NSERROR_OK; +} - view = nsbeos_current_gc/*_lock*/(); - if (view == NULL) { - beos_warn_user("No GC", 0); - return false; - } - nsbeos_set_colour(style->stroke_colour); +/** + * Plots a circle + * + * Plot a circle centered on (x,y), which is optionally filled. + * + * \param ctx The current redraw context. + * \param pstyle Style controlling the circle plot. + * \param x x coordinate of circle centre. + * \param y y coordinate of circle centre. + * \param radius circle radius. + * \return NSERROR_OK on success else error code. + */ +static nserror +nsbeos_plot_disc(const struct redraw_context *ctx, + const plot_style_t *style, + int x, int y, int radius) +{ + BView *view; - float pensize = view->PenSize(); - view->SetPenSize(style->stroke_width); + view = nsbeos_current_gc/*_lock*/(); + if (view == NULL) { + beos_warn_user("No GC", 0); + return NSERROR_INVALID; + } - BPoint start(x0, y0); - BPoint end(x1, y1); - view->StrokeLine(start, end, pat); + nsbeos_set_colour(style->fill_colour); - view->SetPenSize(pensize); + BPoint center(x, y); + if (style->fill_type != PLOT_OP_TYPE_NONE) + view->FillEllipse(center, radius, radius); + else + view->StrokeEllipse(center, radius, radius); - //nsbeos_current_gc_unlock(); + //nsbeos_current_gc_unlock(); - return true; + return NSERROR_OK; } -bool nsbeos_plot_polygon(const int *p, unsigned int n, const plot_style_t *style) +/** + * Plots a line + * + * plot a line from (x0,y0) to (x1,y1). Coordinates are at + * centre of line width/thickness. + * + * \param ctx The current redraw context. + * \param pstyle Style controlling the line plot. + * \param line A rectangle defining the line to be drawn + * \return NSERROR_OK on success else error code. + */ +static nserror +nsbeos_plot_line(const struct redraw_context *ctx, + const plot_style_t *style, + const struct rect *line) { - unsigned int i; - BView *view; + pattern pat; + BView *view; - view = nsbeos_current_gc/*_lock*/(); - if (view == NULL) { - beos_warn_user("No GC", 0); - return false; - } + switch (style->stroke_type) { + case PLOT_OP_TYPE_SOLID: /**< Solid colour */ + default: + pat = B_SOLID_HIGH; + break; - nsbeos_set_colour(style->fill_colour); + case PLOT_OP_TYPE_DOT: /**< Doted plot */ + pat = kDottedPattern; + break; - BPoint points[n]; - - for (i = 0; i < n; i++) { - points[i] = BPoint(p[2 * i] - 0.5, p[2 * i + 1] - 0.5); - } + case PLOT_OP_TYPE_DASH: /**< dashed plot */ + pat = kDashedPattern; + break; + } - if (style->fill_colour == NS_TRANSPARENT) - view->StrokePolygon(points, (int32)n); - else - view->FillPolygon(points, (int32)n); + view = nsbeos_current_gc/*_lock*/(); + if (view == NULL) { + beos_warn_user("No GC", 0); + return NSERROR_OK; + } - return true; -} + nsbeos_set_colour(style->stroke_colour); + float pensize = view->PenSize(); + view->SetPenSize(style->stroke_width); + BPoint start(line->x0, line->y0); + BPoint end(line->x1, line->y1); + view->StrokeLine(start, end, pat); + view->SetPenSize(pensize); -bool nsbeos_plot_clip(const struct rect *ns_clip) -{ - BView *view; - //fprintf(stderr, "%s(%d, %d, %d, %d)\n", __FUNCTION__, clip_x0, clip_y0, clip_x1, clip_y1); - - view = nsbeos_current_gc/*_lock*/(); - if (view == NULL) { - beos_warn_user("No GC", 0); - return false; - } - - BRect rect(ns_clip->x0, ns_clip->y0, ns_clip->x1 - 1, - ns_clip->y1 - 1); - BRegion clip(rect); - view->ConstrainClippingRegion(NULL); - if (view->Bounds() != rect) - view->ConstrainClippingRegion(&clip); - - - //nsbeos_current_gc_unlock(); - - return true; + //nsbeos_current_gc_unlock(); + + return NSERROR_OK; } -bool nsbeos_plot_text(int x, int y, const char *text, size_t length, - const plot_font_style_t *fstyle) +/** + * Plots a rectangle. + * + * The rectangle can be filled an outline or both controlled + * by the plot style The line can be solid, dotted or + * dashed. Top left corner at (x0,y0) and rectangle has given + * width and height. + * + * \param ctx The current redraw context. + * \param pstyle Style controlling the rectangle plot. + * \param rect A rectangle defining the line to be drawn + * \return NSERROR_OK on success else error code. + */ +static nserror +nsbeos_plot_rectangle(const struct redraw_context *ctx, + const plot_style_t *style, + const struct rect *rect) { - return nsfont_paint(fstyle, text, length, x, y); -} + if (style->fill_type != PLOT_OP_TYPE_NONE) { + BView *view; + view = nsbeos_current_gc/*_lock*/(); + if (view == NULL) { + beos_warn_user("No GC", 0); + return NSERROR_INVALID; + } -bool nsbeos_plot_disc(int x, int y, int radius, const plot_style_t *style) -{ - BView *view; + nsbeos_set_colour(style->fill_colour); + + BRect rect(rect->x0, rect->y0, rect->x1 - 1, rect->y1 - 1); + view->FillRect(rect); - view = nsbeos_current_gc/*_lock*/(); - if (view == NULL) { - beos_warn_user("No GC", 0); - return false; - } + //nsbeos_current_gc_unlock(); + } - nsbeos_set_colour(style->fill_colour); + if (style->stroke_type != PLOT_OP_TYPE_NONE) { + pattern pat; + BView *view; + + switch (style->stroke_type) { + case PLOT_OP_TYPE_SOLID: /**< Solid colour */ + default: + pat = B_SOLID_HIGH; + break; - BPoint center(x, y); - if (style->fill_type != PLOT_OP_TYPE_NONE) - view->FillEllipse(center, radius, radius); - else - view->StrokeEllipse(center, radius, radius); + case PLOT_OP_TYPE_DOT: /**< Doted plot */ + pat = kDottedPattern; + break; + + case PLOT_OP_TYPE_DASH: /**< dashed plot */ + pat = kDashedPattern; + break; + } + + view = nsbeos_current_gc/*_lock*/(); + if (view == NULL) { + beos_warn_user("No GC", 0); + return NSERROR_INVALID; + } - //nsbeos_current_gc_unlock(); + nsbeos_set_colour(style->stroke_colour); - return true; + float pensize = view->PenSize(); + view->SetPenSize(style->stroke_width); + + BRect rect(rect->x0, rect->y0, rect->x1, rect->y1); + view->StrokeRect(rect, pat); + + view->SetPenSize(pensize); + + //nsbeos_current_gc_unlock(); + } + + return NSERROR_OK; } -bool nsbeos_plot_arc(int x, int y, int radius, int angle1, int angle2, const plot_style_t *style) + +/** + * Plot a polygon + * + * Plots a filled polygon with straight lines between + * points. The lines around the edge of the ploygon are not + * plotted. The polygon is filled with the non-zero winding + * rule. + * + * \param ctx The current redraw context. + * \param pstyle Style controlling the polygon plot. + * \param p verticies of polygon + * \param n number of verticies. + * \return NSERROR_OK on success else error code. + */ +static nserror +nsbeos_plot_polygon(const struct redraw_context *ctx, + const plot_style_t *style, + const int *p, + unsigned int n) { - BView *view; + unsigned int i; + BView *view; - view = nsbeos_current_gc/*_lock*/(); - if (view == NULL) { - beos_warn_user("No GC", 0); - return false; - } + view = nsbeos_current_gc/*_lock*/(); + if (view == NULL) { + beos_warn_user("No GC", 0); + return NSERROR_INVALID; + } - nsbeos_set_colour(style->fill_colour); + nsbeos_set_colour(style->fill_colour); - BPoint center(x, y); - float angle = angle1; // in degree - float span = angle2 - angle1; // in degree - view->StrokeArc(center, radius, radius, angle, span); + BPoint points[n]; - //nsbeos_current_gc_unlock(); + for (i = 0; i < n; i++) { + points[i] = BPoint(p[2 * i] - 0.5, p[2 * i + 1] - 0.5); + } - return true; + if (style->fill_colour == NS_TRANSPARENT) { + view->StrokePolygon(points, (int32)n); + } else { + view->FillPolygon(points, (int32)n); + } + + return NSERROR_OK; } -static bool nsbeos_plot_bbitmap(int x, int y, int width, int height, - BBitmap *b, colour bg) + +/** + * Plots a path. + * + * Path plot consisting of cubic Bezier curves. Line and fill colour is + * controlled by the plot style. + * + * \param ctx The current redraw context. + * \param pstyle Style controlling the path plot. + * \param p elements of path + * \param n nunber of elements on path + * \param width The width of the path + * \param transform A transform to apply to the path. + * \return NSERROR_OK on success else error code. + */ +static nserror +nsbeos_plot_path(const struct redraw_context *ctx, + const plot_style_t *pstyle, + const float *p, + unsigned int n, + float width, + const float transform[6]) { - /* XXX: This currently ignores the background colour supplied. - * Does this matter? - */ - - if (width == 0 || height == 0) - return true; - - BView *view; - - view = nsbeos_current_gc/*_lock*/(); - if (view == NULL) { - beos_warn_user("No GC", 0); - return false; - } - - drawing_mode oldmode = view->DrawingMode(); - source_alpha alpha; - alpha_function func; - view->GetBlendingMode(&alpha, &func); - //view->SetDrawingMode(B_OP_OVER); - view->SetDrawingMode(B_OP_ALPHA); - view->SetBlendingMode(B_PIXEL_ALPHA, B_ALPHA_OVERLAY); - - // XXX DrawBitmap() resamples if rect doesn't match, - // but doesn't do any filtering - // XXX: use Zeta API if available ? - - BRect rect(x, y, x + width - 1, y + height - 1); - /* - rgb_color old = view->LowColor(); - if (bg != NS_TRANSPARENT) { - view->SetLowColor(nsbeos_rgb_colour(bg)); - view->FillRect(rect, B_SOLID_LOW); - } - */ - view->DrawBitmap(b, rect); - // maybe not needed? - //view->SetLowColor(old); - view->SetBlendingMode(alpha, func); - view->SetDrawingMode(oldmode); - - //nsbeos_current_gc_unlock(); - - return true; + unsigned int i; + BShape shape; + + if (n == 0) { + return NSERROR_OK; + } + + if (p[0] != PLOTTER_PATH_MOVE) { + LOG("path doesn't start with a move"); + return NSERROR_INVALID; + } + + for (i = 0; i < n; ) { + if (p[i] == PLOTTER_PATH_MOVE) { + BPoint pt(transform_pt(p[i + 1], p[i + 2], transform)); + shape.MoveTo(pt); + i += 3; + } else if (p[i] == PLOTTER_PATH_CLOSE) { + shape.Close(); + i++; + } else if (p[i] == PLOTTER_PATH_LINE) { + BPoint pt(transform_pt(p[i + 1], p[i + 2], transform)); + shape.LineTo(pt); + i += 3; + } else if (p[i] == PLOTTER_PATH_BEZIER) { + BPoint pt[3] = { + transform_pt(p[i + 1], p[i + 2], transform), + transform_pt(p[i + 3], p[i + 4], transform), + transform_pt(p[i + 5], p[i + 6], transform) + }; + shape.BezierTo(pt); + i += 7; + } else { + LOG("bad path command %f", p[i]); + return NSERROR_INVALID; + } + } + shape.Close(); + + BView *view; + + view = nsbeos_current_gc/*_lock*/(); + if (view == NULL) { + return NSERROR_INVALID; + } + + rgb_color old_high = view->HighColor(); + float old_pen = view->PenSize(); + view->SetPenSize(width); + view->MovePenTo(0, 0); + if (pstyle->fill_colour != NS_TRANSPARENT) { + view->SetHighColor(nsbeos_rgb_colour(pstyle->fill_colour)); + view->FillShape(&shape); + } + if (pstyle->stroke_colour != NS_TRANSPARENT) { + view->SetHighColor(nsbeos_rgb_colour(pstyle->stroke_colour)); + view->StrokeShape(&shape); + } + // restore + view->SetPenSize(old_pen); + view->SetHighColor(old_high); + + //nsbeos_current_gc_unlock(); + + return NSERROR_OK; } -bool nsbeos_plot_bitmap(int x, int y, int width, int height, - struct bitmap *bitmap, colour bg, - bitmap_flags_t flags) +/** + * Plot a bitmap + * + * Tiled plot of a bitmap image. (x,y) gives the top left + * coordinate of an explicitly placed tile. From this tile the + * image can repeat in all four directions -- up, down, left + * and right -- to the extents given by the current clip + * rectangle. + * + * The bitmap_flags say whether to tile in the x and y + * directions. If not tiling in x or y directions, the single + * image is plotted. The width and height give the dimensions + * the image is to be scaled to. + * + * \param ctx The current redraw context. + * \param bitmap The bitmap to plot + * \param x The x coordinate to plot the bitmap + * \param y The y coordiante to plot the bitmap + * \param width The width of area to plot the bitmap into + * \param height The height of area to plot the bitmap into + * \param bg the background colour to alpha blend into + * \param flags the flags controlling the type of plot operation + * \return NSERROR_OK on success else error code. + */ +static nserror +nsbeos_plot_bitmap(const struct redraw_context *ctx, + struct bitmap *bitmap, + int x, int y, + int width, + int height, + colour bg, + bitmap_flags_t flags) { - int doneheight = 0, donewidth = 0; - BBitmap *primary; - BBitmap *pretiled; + int doneheight = 0, donewidth = 0; + BBitmap *primary; + BBitmap *pretiled; bool repeat_x = (flags & BITMAPF_REPEAT_X); bool repeat_y = (flags & BITMAPF_REPEAT_Y); - if (!(repeat_x || repeat_y)) { - /* Not repeating at all, so just plot it */ + if (!(repeat_x || repeat_y)) { + /* Not repeating at all, so just plot it */ primary = nsbeos_bitmap_get_primary(bitmap); return nsbeos_plot_bbitmap(x, y, width, height, primary, bg); - } - - if (repeat_x && !repeat_y) - pretiled = nsbeos_bitmap_get_pretile_x(bitmap); - if (repeat_x && repeat_y) - pretiled = nsbeos_bitmap_get_pretile_xy(bitmap); - if (!repeat_x && repeat_y) - pretiled = nsbeos_bitmap_get_pretile_y(bitmap); - primary = nsbeos_bitmap_get_primary(bitmap); - - /* use the primary and pretiled widths to scale the w/h provided */ - width *= pretiled->Bounds().Width() + 1; - width /= primary->Bounds().Width() + 1; - height *= pretiled->Bounds().Height() + 1; - height /= primary->Bounds().Height() + 1; - - BView *view; - - view = nsbeos_current_gc/*_lock*/(); - if (view == NULL) { - beos_warn_user("No GC", 0); - return false; - } - - // XXX: do we really need to use clipping reg ? - // I guess it's faster to not draw clipped out stuff... - - BRect cliprect; - BRegion clipreg; - view->GetClippingRegion(&clipreg); - cliprect = clipreg.Frame(); - - //XXX: FIXME - - if (y > cliprect.top) - doneheight = ((int)cliprect.top - height) + ((y - (int)cliprect.top) % height); - else - doneheight = y; - - while (doneheight < ((int)cliprect.bottom)) { - if (x > cliprect.left) - donewidth = ((int)cliprect.left - width) + ((x - (int)cliprect.left) % width); - else - donewidth = x; - while (donewidth < (cliprect.right)) { - nsbeos_plot_bbitmap(donewidth, doneheight, - width, height, pretiled, bg); - donewidth += width; - if (!repeat_x) break; - } - doneheight += height; - if (!repeat_y) break; - } + } + + if (repeat_x && !repeat_y) + pretiled = nsbeos_bitmap_get_pretile_x(bitmap); + if (repeat_x && repeat_y) + pretiled = nsbeos_bitmap_get_pretile_xy(bitmap); + if (!repeat_x && repeat_y) + pretiled = nsbeos_bitmap_get_pretile_y(bitmap); + primary = nsbeos_bitmap_get_primary(bitmap); + + /* use the primary and pretiled widths to scale the w/h provided */ + width *= pretiled->Bounds().Width() + 1; + width /= primary->Bounds().Width() + 1; + height *= pretiled->Bounds().Height() + 1; + height /= primary->Bounds().Height() + 1; + + BView *view; + + view = nsbeos_current_gc/*_lock*/(); + if (view == NULL) { + beos_warn_user("No GC", 0); + return NSERROR_INVALID; + } + + // XXX: do we really need to use clipping reg ? + // I guess it's faster to not draw clipped out stuff... + + BRect cliprect; + BRegion clipreg; + view->GetClippingRegion(&clipreg); + cliprect = clipreg.Frame(); + + //XXX: FIXME + + if (y > cliprect.top) { + doneheight = ((int)cliprect.top - height) + ((y - (int)cliprect.top) % height); + } else { + doneheight = y; + } + + while (doneheight < ((int)cliprect.bottom)) { + if (x > cliprect.left) { + donewidth = ((int)cliprect.left - width) + ((x - (int)cliprect.left) % width); + } else { + donewidth = x; + } + + while (donewidth < (cliprect.right)) { + nsbeos_plot_bbitmap(donewidth, doneheight, + width, height, pretiled, bg); + donewidth += width; + if (!repeat_x) { + break; + } + } + doneheight += height; + if (!repeat_y) { + break; + } + } #warning WRITEME - return true; -} -static BPoint transform_pt(float x, float y, const float transform[6]) -{ -#warning XXX: verify - //return BPoint(x, y); - BPoint pt; - pt.x = x * transform[0] + y * transform[1] + transform[4]; - pt.y = x * transform[2] + y * transform[3] + transform[5]; - /* - printf("TR: {%f, %f} { %f, %f, %f, %f, %f, %f} = { %f, %f }\n", - x, y, - transform[0], transform[1], transform[2], - transform[3], transform[4], transform[5], - pt.x, pt.y); - */ - return pt; + return NSERROR_OK; } -bool nsbeos_plot_path(const float *p, unsigned int n, colour fill, float width, - colour c, const float transform[6]) -{ - unsigned int i; - - if (n == 0) - return true; - - if (p[0] != PLOTTER_PATH_MOVE) { - LOG("path doesn't start with a move"); - return false; - } - - BShape shape; - - for (i = 0; i < n; ) { - if (p[i] == PLOTTER_PATH_MOVE) { - BPoint pt(transform_pt(p[i + 1], p[i + 2], transform)); - shape.MoveTo(pt); - i += 3; - } else if (p[i] == PLOTTER_PATH_CLOSE) { - shape.Close(); - i++; - } else if (p[i] == PLOTTER_PATH_LINE) { - BPoint pt(transform_pt(p[i + 1], p[i + 2], transform)); - shape.LineTo(pt); - i += 3; - } else if (p[i] == PLOTTER_PATH_BEZIER) { - BPoint pt[3] = { - transform_pt(p[i + 1], p[i + 2], transform), - transform_pt(p[i + 3], p[i + 4], transform), - transform_pt(p[i + 5], p[i + 6], transform) - }; - shape.BezierTo(pt); - i += 7; - } else { - LOG("bad path command %f", p[i]); - return false; - } - } - shape.Close(); - - BView *view; - - view = nsbeos_current_gc/*_lock*/(); - if (view == NULL) - return false; - - rgb_color old_high = view->HighColor(); - float old_pen = view->PenSize(); - view->SetPenSize(width); - view->MovePenTo(0, 0); - if (fill != NS_TRANSPARENT) { - view->SetHighColor(nsbeos_rgb_colour(fill)); - view->FillShape(&shape); - } - if (c != NS_TRANSPARENT) { - view->SetHighColor(nsbeos_rgb_colour(c)); - view->StrokeShape(&shape); - } - // restore - view->SetPenSize(old_pen); - view->SetHighColor(old_high); - - //nsbeos_current_gc_unlock(); - - return true; -} -rgb_color nsbeos_rgb_colour(colour c) +/** + * Text plotting. + * + * \param ctx The current redraw context. + * \param fstyle plot style for this text + * \param x x coordinate + * \param y y coordinate + * \param text UTF-8 string to plot + * \param length length of string, in bytes + * \return NSERROR_OK on success else error code. + */ +static nserror +nsbeos_plot_text(const struct redraw_context *ctx, + const struct plot_font_style *fstyle, + int x, + int y, + const char *text, + size_t length) { - rgb_color color; - if (c == NS_TRANSPARENT) - return B_TRANSPARENT_32_BIT; - color.red = c & 0x0000ff; - color.green = (c & 0x00ff00) >> 8; - color.blue = (c & 0xff0000) >> 16; - return color; -} + if (!nsfont_paint(fstyle, text, length, x, y)) { + return NSERROR_INVALID; + } -void nsbeos_set_colour(colour c) -{ - rgb_color color = nsbeos_rgb_colour(c); - BView *view = nsbeos_current_gc(); - view->SetHighColor(color); + return NSERROR_OK; } -/** Plot a caret. It is assumed that the plotters have been set up. */ -void nsbeos_plot_caret(int x, int y, int h) -{ - BView *view; - - view = nsbeos_current_gc/*_lock*/(); - if (view == NULL) - /* TODO: report an error here */ - return; - - BPoint start(x, y); - BPoint end(x, y + h - 1); -#if defined(__HAIKU__) || defined(B_BEOS_VERSION_DANO) - view->SetHighColor(ui_color(B_DOCUMENT_TEXT_COLOR)); -#else - view->SetHighColor(kBlackColor); -#endif - view->StrokeLine(start, end); - //nsbeos_current_gc_unlock(); +/** + * beos plotter operation table + */ +const struct plotter_table nsbeos_plotters = { + nsbeos_plot_clip, + nsbeos_plot_arc, + nsbeos_plot_disc, + nsbeos_plot_line, + nsbeos_plot_rectangle, + nsbeos_plot_polygon, + nsbeos_plot_path, + nsbeos_plot_bitmap, + nsbeos_plot_text, + NULL, // Group Start + NULL, // Group End + NULL, // Flush + true // option_knockout +}; -} #ifdef TEST_PLOTTERS // static void test_plotters(void) { - int x0, y0; - int x1, y1; - struct rect r; - - x0 = 5; - y0 = 5; - x1 = 35; - y1 = 6; - - plot.line(x0, y0, x1, y1, 1, 0x0000ff00, false, false); - y0+=2; y1+=2; - plot.line(x0, y0, x1, y1, 1, 0x0000ff00, true, false); - y0+=2; y1+=2; - plot.line(x0, y0, x1, y1, 1, 0x0000ff00, false, true); - y0+=2; y1+=2; - plot.line(x0, y0, x1, y1, 1, 0x0000ff00, true, true); - y0+=10; y1+=20; - - plot.fill(x0, y0, x1, y1, 0x00ff0000); - plot.rectangle(x0+10, y0+10, x1-x0+1, y1-y0+1, 2, 0x00ffff00, true, false); - y0+=30; y1+=30; - - r.x0 = x0 + 2; - r.y0 = y0 + 2; - r.x1 = x1 - 2; - r.y1 = y1 - 2; - plot.clip(&r); - - plot.fill(x0, y0, x1, y1, 0x00000000); - plot.disc(x1, y1, 8, 0x000000ff, false); - - r.x0 = 0; - r.y0 = 0; - r.x1 = 300; - r.y1 = 300; - plot.clip(&r); - - y0+=30; y1+=30; - + int x0, y0; + int x1, y1; + struct rect r; + + x0 = 5; + y0 = 5; + x1 = 35; + y1 = 6; + + plot.line(x0, y0, x1, y1, 1, 0x0000ff00, false, false); + y0+=2; y1+=2; + plot.line(x0, y0, x1, y1, 1, 0x0000ff00, true, false); + y0+=2; y1+=2; + plot.line(x0, y0, x1, y1, 1, 0x0000ff00, false, true); + y0+=2; y1+=2; + plot.line(x0, y0, x1, y1, 1, 0x0000ff00, true, true); + y0+=10; y1+=20; + + plot.fill(x0, y0, x1, y1, 0x00ff0000); + plot.rectangle(x0+10, y0+10, x1-x0+1, y1-y0+1, 2, 0x00ffff00, true, false); + y0+=30; y1+=30; + + r.x0 = x0 + 2; + r.y0 = y0 + 2; + r.x1 = x1 - 2; + r.y1 = y1 - 2; + plot.clip(&r); + + plot.fill(x0, y0, x1, y1, 0x00000000); + plot.disc(x1, y1, 8, 0x000000ff, false); + + r.x0 = 0; + r.y0 = 0; + r.x1 = 300; + r.y1 = 300; + plot.clip(&r); + + y0+=30; y1+=30; + } #include @@ -632,28 +805,27 @@ static void test_plotters(void) #include class PTView : public BView { public: - PTView(BRect frame) : BView(frame, "view", B_FOLLOW_NONE, B_WILL_DRAW) {}; - virtual ~PTView() {}; - virtual void Draw(BRect update) - { - test_plotters(); - }; + PTView(BRect frame) : BView(frame, "view", B_FOLLOW_NONE, B_WILL_DRAW) {}; + virtual ~PTView() {}; + virtual void Draw(BRect update) + { + test_plotters(); + }; }; extern "C" void test_plotters_main(void); void test_plotters_main(void) { - BApplication app("application/x-vnd.NetSurf"); - memcpy(&plot, &nsbeos_plotters, sizeof(plot)); - BRect frame(0,0,300,300); - PTView *view = new PTView(frame); - frame.OffsetBySelf(100,100); - BWindow *win = new BWindow(frame, "NetSurfPlotterTest", B_TITLED_WINDOW, B_QUIT_ON_WINDOW_CLOSE); - win->AddChild(view); - nsbeos_current_gc_set(view); - win->Show(); - app.Run(); + BApplication app("application/x-vnd.NetSurf"); + memcpy(&plot, &nsbeos_plotters, sizeof(plot)); + BRect frame(0,0,300,300); + PTView *view = new PTView(frame); + frame.OffsetBySelf(100,100); + BWindow *win = new BWindow(frame, "NetSurfPlotterTest", B_TITLED_WINDOW, B_QUIT_ON_WINDOW_CLOSE); + win->AddChild(view); + nsbeos_current_gc_set(view); + win->Show(); + app.Run(); } #endif /* TEST_PLOTTERS */ - -- cgit v1.2.3