diff options
Diffstat (limited to 'frontends/amiga/plotters.c')
-rw-r--r-- | frontends/amiga/plotters.c | 1004 |
1 files changed, 625 insertions, 379 deletions
diff --git a/frontends/amiga/plotters.c b/frontends/amiga/plotters.c index 6bae6346a..4623afad2 100644 --- a/frontends/amiga/plotters.c +++ b/frontends/amiga/plotters.c @@ -20,6 +20,8 @@ #include <proto/exec.h> #include <proto/intuition.h> +#include <proto/layers.h> +#include <proto/graphics.h> #include <intuition/intuition.h> #include <graphics/rpattr.h> @@ -51,8 +53,6 @@ #include "amiga/rtg.h" #include "amiga/utf8.h" -//#define AMI_PLOTTER_DEBUG 1 - HOOKF(void, ami_bitmap_tile_hook, struct RastPort *, rp, struct BackFillMessage *); struct bfbitmap { @@ -62,6 +62,7 @@ struct bfbitmap { int offsetx; int offsety; APTR mask; + bool palette_mapped; }; struct ami_plot_pen { @@ -74,10 +75,27 @@ struct bez_point { float y; }; -struct gui_globals *glob; +struct gui_globals { + struct BitMap *bm; + struct RastPort *rp; + struct Layer_Info *layerinfo; + APTR areabuf; + APTR tmprasbuf; + struct Rectangle rect; + struct MinList *shared_pens; + bool managed_pen_list; + bool palette_mapped; + ULONG apen; + ULONG open; + LONG apen_num; + LONG open_num; + int width; /* size of bm and */ + int height; /* associated memory */ +}; static int init_layers_count = 0; static APTR pool_pens = NULL; +static bool palette_mapped = true; /* palette-mapped state for the screen */ #ifndef M_PI /* For some reason we don't always get this from math.h */ #define M_PI 3.14159265358979323846 @@ -92,26 +110,24 @@ static APTR pool_pens = NULL; */ #define AREA_SIZE 25000 -/* Define the below to get additional debug */ -#undef AMI_PLOTTER_DEBUG - -void ami_init_layers(struct gui_globals *gg, ULONG width, ULONG height, bool force32bit) +struct gui_globals *ami_plot_ra_alloc(ULONG width, ULONG height, bool force32bit, bool alloc_pen_list) { - /* init shared bitmaps * - * Height is set to screen width to give enough space for thumbnails * - * Also applies to the further gfx/layers functions and memory below */ - - int depth = 32; + /* init shared bitmaps */ + int depth = 32; struct BitMap *friend = NULL; + struct gui_globals *gg = malloc(sizeof(struct gui_globals)); + if(force32bit == false) depth = GetBitMapAttr(scrn->RastPort.BitMap, BMA_DEPTH); - LOG("Screen depth = %d", depth); + NSLOG(netsurf, INFO, "Screen depth = %d", depth); #ifdef __amigaos4__ if(depth < 16) { gg->palette_mapped = true; + if(force32bit == false) palette_mapped = true; } else { gg->palette_mapped = false; + if(force32bit == false) palette_mapped = false; } #else /* Friend BitMaps are weird. @@ -135,6 +151,7 @@ void ami_init_layers(struct gui_globals *gg, ULONG width, ULONG height, bool for */ #warning OS3 locked to palette-mapped modes gg->palette_mapped = true; + palette_mapped = true; if(depth > 8) depth = 8; #endif @@ -192,8 +209,18 @@ void ami_init_layers(struct gui_globals *gg, ULONG width, ULONG height, bool for InitTmpRas(gg->rp->TmpRas, gg->tmprasbuf, width*height); - if((gg->palette_mapped == true) && (pool_pens == NULL)) { - pool_pens = ami_memory_itempool_create(sizeof(struct ami_plot_pen)); + gg->shared_pens = NULL; + gg->managed_pen_list = false; + + if(gg->palette_mapped == true) { + if(pool_pens == NULL) { + pool_pens = ami_memory_itempool_create(sizeof(struct ami_plot_pen)); + } + + if(alloc_pen_list == true) { + gg->shared_pens = ami_AllocMinList(); + gg->managed_pen_list = true; + } } gg->apen = 0x00000000; @@ -202,20 +229,25 @@ void ami_init_layers(struct gui_globals *gg, ULONG width, ULONG height, bool for gg->open_num = -1; init_layers_count++; - LOG("Layer initialised (total: %d)", init_layers_count); + NSLOG(netsurf, INFO, "Layer initialised (total: %d)", + init_layers_count); + + return gg; } -void ami_free_layers(struct gui_globals *gg) +void ami_plot_ra_free(struct gui_globals *gg) { init_layers_count--; + if(init_layers_count < 0) return; + if((init_layers_count == 0) && (pool_pens != NULL)) { ami_memory_itempool_delete(pool_pens); pool_pens = NULL; } if(gg->rp) { - DeleteLayer(0,gg->rp->Layer); + if(gg->rp->Layer != NULL) DeleteLayer(0, gg->rp->Layer); free(gg->rp->TmpRas); free(gg->rp->AreaInfo); free(gg->rp); @@ -229,6 +261,35 @@ void ami_free_layers(struct gui_globals *gg) } else { if(gg->bm) FreeBitMap(gg->bm); } + + if(gg->managed_pen_list == true) { + ami_plot_release_pens(gg->shared_pens); + free(gg->shared_pens); + gg->shared_pens = NULL; + } + + free(gg); +} + +struct RastPort *ami_plot_ra_get_rastport(struct gui_globals *gg) +{ + return gg->rp; +} + +struct BitMap *ami_plot_ra_get_bitmap(struct gui_globals *gg) +{ + return gg->bm; +} + +void ami_plot_ra_get_size(struct gui_globals *gg, int *width, int *height) +{ + *width = gg->width; + *height = gg->height; +} + +void ami_plot_ra_set_pen_list(struct gui_globals *gg, struct MinList *pen_list) +{ + gg->shared_pens = pen_list; } void ami_clearclipreg(struct gui_globals *gg) @@ -242,6 +303,11 @@ void ami_clearclipreg(struct gui_globals *gg) gg->rect.MinY = 0; gg->rect.MaxX = scrn->Width-1; gg->rect.MaxY = scrn->Height-1; + + gg->apen = 0x00000000; + gg->open = 0x00000000; + gg->apen_num = -1; + gg->open_num = -1; } static ULONG ami_plot_obtain_pen(struct MinList *shared_pens, ULONG colr) @@ -253,7 +319,8 @@ static ULONG ami_plot_obtain_pen(struct MinList *shared_pens, ULONG colr) (colr & 0x00ff0000) << 8, NULL); - if(pen == -1) LOG("WARNING: Cannot allocate pen for ABGR:%lx", colr); + if(pen == -1) NSLOG(netsurf, INFO, + "WARNING: Cannot allocate pen for ABGR:%lx", colr); if((shared_pens != NULL) && (pool_pens != NULL)) { if((node = (struct ami_plot_pen *)ami_memory_itempool_alloc(pool_pens, sizeof(struct ami_plot_pen)))) { @@ -282,14 +349,9 @@ void ami_plot_release_pens(struct MinList *shared_pens) Remove((struct Node *)node); ami_memory_itempool_free(pool_pens, node, sizeof(struct ami_plot_pen)); } while((node = nnode)); - - glob->apen = 0x00000000; - glob->open = 0x00000000; - glob->apen_num = -1; - glob->open_num = -1; } -static void ami_plot_setapen(struct RastPort *rp, ULONG colr) +static void ami_plot_setapen(struct gui_globals *glob, struct RastPort *rp, ULONG colr) { if(glob->apen == colr) return; @@ -308,7 +370,7 @@ static void ami_plot_setapen(struct RastPort *rp, ULONG colr) glob->apen = colr; } -static void ami_plot_setopen(struct RastPort *rp, ULONG colr) +static void ami_plot_setopen(struct gui_globals *glob, struct RastPort *rp, ULONG colr) { if(glob->open == colr) return; @@ -336,172 +398,7 @@ 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) +static void ami_arc_gfxlib(struct RastPort *rp, int x, int y, int radius, int angle1, int angle2) { double angle1_r = (double)(angle1) * (M_PI / 180.0); double angle2_r = (double)(angle2) * (M_PI / 180.0); @@ -517,55 +414,45 @@ static void ami_arc_gfxlib(int x, int y, int radius, int angle1, int angle2) x1 = (int)(cos(b) * (double)radius); y1 = (int)(sin(b) * (double)radius); - Move(glob->rp, x0 + x1, y0 - y1); + Move(rp, x0 + x1, y0 - y1); for(angle = (b + step); angle <= c; angle += step) { x1 = (int)(cos(angle) * (double)radius); y1 = (int)(sin(angle) * (double)radius); - Draw(glob->rp, x0 + x1, y0 - y1); + Draw(rp, x0 + x1, y0 - y1); } } -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(struct gui_globals *glob, int x, int y, int width, int height, struct bitmap *bitmap) { - #ifdef AMI_PLOTTER_DEBUG - LOG("[ami_plotter] Entered ami_bitmap()"); - #endif + NSLOG(plot, DEEPDEBUG, "[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; + tbm = ami_bitmap_get_native(bitmap, width, height, glob->palette_mapped, glob->rp->BitMap); + if (!tbm) { + return NSERROR_OK; + } - #ifdef AMI_PLOTTER_DEBUG - LOG("[ami_plotter] ami_bitmap() got native bitmap"); - #endif + NSLOG(plot, DEEPDEBUG, "[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), 1)) { uint32 comptype = COMPOSITE_Src_Over_Dest; uint32 compflags = COMPFLAG_IgnoreDestAlpha; if(amiga_bitmap_get_opaque(bitmap)) { @@ -585,19 +472,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 +499,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 +507,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 *) { @@ -744,7 +525,7 @@ HOOKF(void, ami_bitmap_tile_hook, struct RastPort *, rp, struct BackFillMessage for (yf = -bfbm->offsety; yf < msg->Bounds.MaxY; yf += bfbm->height) { #ifdef __amigaos4__ if(__builtin_expect((GfxBase->LibNode.lib_Version >= 53) && - (glob->palette_mapped == false), 1)) { + (bfbm->palette_mapped == false), 1)) { CompositeTags(COMPOSITE_Src_Over_Dest, bfbm->bm, rp->BitMap, COMPTAG_Flags, COMPFLAG_IgnoreDestAlpha, COMPTAG_DestX, msg->Bounds.MinX, @@ -757,13 +538,12 @@ 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; - if(glob->palette_mapped == false) { + if(bfbm->palette_mapped == false) { tag = BLITA_UseSrcAlpha; tag_data = TRUE; minterm = 0xc0; @@ -805,42 +585,336 @@ 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) +{ + /* This may not be entirely correct - previously we returned the state of the current BitMap */ + return 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 gui_globals *glob = (struct gui_globals *)ctx->priv; + struct Region *reg = NULL; + + NSLOG(plot, DEEPDEBUG, "[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 style 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) +{ + NSLOG(plot, DEEPDEBUG, "[ami_plotter] Entered ami_arc()"); + + struct gui_globals *glob = (struct gui_globals *)ctx->priv; + + if (angle2 < angle1) { + angle2 += 360; + } + + ami_plot_setapen(glob, glob->rp, style->fill_colour); + ami_arc_gfxlib(glob->rp, 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 style 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) +{ + NSLOG(plot, DEEPDEBUG, "[ami_plotter] Entered ami_disc()"); + + struct gui_globals *glob = (struct gui_globals *)ctx->priv; + + if (style->fill_type != PLOT_OP_TYPE_NONE) { + ami_plot_setapen(glob, 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, 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 style 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) +{ + NSLOG(plot, DEEPDEBUG, "[ami_plotter] Entered ami_line()"); + + struct gui_globals *glob = (struct gui_globals *)ctx->priv; + + glob->rp->PenWidth = plot_style_fixed_to_int(style->stroke_width); + glob->rp->PenHeight = plot_style_fixed_to_int(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, 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 style 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) +{ + NSLOG(plot, DEEPDEBUG, "[ami_plotter] Entered ami_rectangle()"); + + struct gui_globals *glob = (struct gui_globals *)ctx->priv; + + if (style->fill_type != PLOT_OP_TYPE_NONE) { + ami_plot_setapen(glob, 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 = plot_style_fixed_to_int(style->stroke_width); + glob->rp->PenHeight = plot_style_fixed_to_int(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, 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 style 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) +{ + NSLOG(plot, DEEPDEBUG, "[ami_plotter] Entered ami_polygon()"); + + struct gui_globals *glob = (struct gui_globals *)ctx->priv; + + ami_plot_setapen(glob, glob->rp, style->fill_colour); + + if (AreaMove(glob->rp,p[0],p[1]) == -1) { + NSLOG(netsurf, INFO, "AreaMove: vector list full"); + } + + for (uint32 k = 1; k < n; k++) { + if (AreaDraw(glob->rp,p[k*2],p[(k*2)+1]) == -1) { + NSLOG(netsurf, INFO, "AreaDraw: vector list full"); + } + } + + if (AreaEnd(glob->rp) == -1) { + NSLOG(netsurf, INFO, "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 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, + 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 - if (n == 0) - return true; + NSLOG(plot, DEEPDEBUG, "[ami_plotter] Entered ami_path()"); + + struct gui_globals *glob = (struct gui_globals *)ctx->priv; + + if (n == 0) { + return NSERROR_OK; + } if (p[0] != PLOTTER_PATH_MOVE) { - LOG("Path does not start with move"); - return false; + NSLOG(netsurf, INFO, "Path does not start with move"); + 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, glob->rp, pstyle->fill_colour); + if (pstyle->stroke_colour != NS_TRANSPARENT) { + ami_plot_setopen(glob, 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, 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) - LOG("AreaMove: vector list full"); + if (pstyle->fill_colour != NS_TRANSPARENT) { + if (AreaMove(glob->rp, p[i+1], p[i+2]) == -1) { + NSLOG(netsurf, INFO, + "AreaMove: vector list full"); + } } else { Move(glob->rp, p[i+1], p[i+2]); } @@ -851,17 +925,20 @@ 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) - LOG("AreaEnd: error"); + if (pstyle->fill_colour != NS_TRANSPARENT) { + if (AreaEnd(glob->rp) == -1) { + NSLOG(netsurf, INFO, "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) - LOG("AreaDraw: vector list full"); + if (pstyle->fill_colour != NS_TRANSPARENT) { + if (AreaDraw(glob->rp, p[i+1], p[i+2]) == -1) { + NSLOG(netsurf, INFO, + "AreaDraw: vector list full"); + } } else { Draw(glob->rp, p[i+1], p[i+2]); } @@ -876,11 +953,13 @@ 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) - LOG("AreaDraw: vector list full"); + if (pstyle->fill_colour != NS_TRANSPARENT) { + if (AreaDraw(glob->rp, p_r.x, p_r.y) == -1) { + NSLOG(netsurf, INFO, + "AreaDraw: vector list full"); + } } else { Draw(glob->rp, p_r.x, p_r.y); } @@ -889,27 +968,194 @@ static bool ami_path(const float *p, unsigned int n, colour fill, float width, cur_p.y = p_c.y; i += 7; } else { - LOG("bad path command %f", p[i]); + NSLOG(netsurf, INFO, "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) +{ + 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); + + NSLOG(plot, DEEPDEBUG, "[ami_plotter] Entered ami_bitmap_tile()"); + + struct gui_globals *glob = (struct gui_globals *)ctx->priv; + + if ((width == 0) || (height == 0)) { + return NSERROR_OK; + } + + if (!(repeat_x || repeat_y)) { + return ami_bitmap(glob, 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->palette_mapped, 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); + bfbm.palette_mapped = glob->palette_mapped; + 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) { - return glob->palette_mapped; + NSLOG(plot, DEEPDEBUG, "[ami_plotter] Entered ami_text()"); + + struct gui_globals *glob = (struct gui_globals *)ctx->priv; + + if (__builtin_expect(ami_nsfont == NULL, 0)) { + return NSERROR_OK; + } + ami_plot_setapen(glob, 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, |