diff --git a/Makefile.sources b/Makefile.sources index 458f06a80..ae2047d22 100644 --- a/Makefile.sources +++ b/Makefile.sources @@ -83,7 +83,7 @@ S_AMIGA := compat.c gui.c tree.c history.c hotlist.c schedule.c \ plotters.c object.c menu.c save_pdf.c arexx.c version.c \ cookies.c context_menu.c clipboard.c save_complete.c \ fetch_file.c fetch_mailto.c search.c history_local.c \ - download.c + download.c iff_dr2d.c S_AMIGA := $(addprefix amiga/,$(S_AMIGA)) # S_FRAMEBUFFER are sources purely for the framebuffer build diff --git a/amiga/clipboard.c b/amiga/clipboard.c index 51b8e3100..fd4289d06 100755 --- a/amiga/clipboard.c +++ b/amiga/clipboard.c @@ -30,6 +30,7 @@ #include #include #include "amiga/bitmap.h" +#include "amiga/iff_dr2d.h" struct IFFHandle *iffh = NULL; @@ -245,3 +246,16 @@ bool ami_easy_clipboard_bitmap(struct bitmap *bitmap) DisposeDTObject(dto); } } + +bool ami_easy_clipboard_svg(struct content *c) +{ + if(c->type != CONTENT_SVG) return false; + + if(!(OpenIFF(iffh,IFFF_WRITE))) + { + ami_svg_to_dr2d(iffh,c->source_data,c->source_size,c->url); + CloseIFF(iffh); + } + + return true; +} diff --git a/amiga/clipboard.h b/amiga/clipboard.h index 806420566..9fccf01d0 100755 --- a/amiga/clipboard.h +++ b/amiga/clipboard.h @@ -23,4 +23,5 @@ void ami_clipboard_init(void); void ami_clipboard_free(void); bool ami_easy_clipboard(char *text); bool ami_easy_clipboard_bitmap(struct bitmap *bitmap); +bool ami_easy_clipboard_svg(struct content *c); #endif diff --git a/amiga/context_menu.c b/amiga/context_menu.c index b5f02f0da..7f60d4963 100755 --- a/amiga/context_menu.c +++ b/amiga/context_menu.c @@ -33,6 +33,7 @@ #include #include "desktop/textinput.h" #include "amiga/bitmap.h" +#include "amiga/iff_dr2d.h" uint32 ami_context_menu_hook(struct Hook *hook,Object *item,APTR reserved); @@ -280,9 +281,18 @@ uint32 ami_context_menu_hook(struct Hook *hook,Object *item,APTR reserved) case CMID_CLIPOBJ: object = (struct content *)userdata; - object->bitmap->url = object->url; - object->bitmap->title = object->title; - ami_easy_clipboard_bitmap(object->bitmap); + if(object->bitmap) + { + object->bitmap->url = object->url; + object->bitmap->title = object->title; + ami_easy_clipboard_bitmap(object->bitmap); + } +#ifdef WITH_NS_SVG + else if(object->type == CONTENT_SVG) + { + ami_easy_clipboard_svg(object); + } +#endif break; case CMID_SAVEOBJ: @@ -322,9 +332,18 @@ uint32 ami_context_menu_hook(struct Hook *hook,Object *item,APTR reserved) char fname[1024]; strlcpy(&fname,savereq->fr_Drawer,1024); AddPart(fname,savereq->fr_File,1024); - object->bitmap->url = object->url; - object->bitmap->title = object->title; - bitmap_save(object->bitmap,fname,0); + if(object->bitmap) + { + object->bitmap->url = object->url; + object->bitmap->title = object->title; + bitmap_save(object->bitmap,fname,0); + } +#ifdef WITH_NS_SVG + else if(object->type == CONTENT_SVG) + { + ami_save_svg(object,fname); + } +#endif SetComment(fname,object->url); ami_update_pointer(gwin->win,GUI_POINTER_DEFAULT); } diff --git a/amiga/download.c b/amiga/download.c index fe9f370f5..5eeeccab1 100644 --- a/amiga/download.c +++ b/amiga/download.c @@ -31,6 +31,7 @@ #include "amiga/options.h" #include "amiga/save_complete.h" #include "amiga/bitmap.h" +#include "amiga/iff_dr2d.h" #include "content/fetch.h" @@ -368,10 +369,19 @@ void ami_drag_save(struct Window *win) case GUI_SAVE_OBJECT_NATIVE: { struct content *c = drag_save_data; - c->bitmap->url = c->url; - c->bitmap->title = c->title; AddPart(path,c->title,1024); - bitmap_save(c->bitmap,path,0); + if(c->bitmap) + { + c->bitmap->url = c->url; + c->bitmap->title = c->title; + bitmap_save(c->bitmap,path,0); + } +#ifdef WITH_NS_SVG + else if(c->type == CONTENT_SVG) + { + ami_save_svg(c,path); + } +#endif } break; } diff --git a/amiga/gui.c b/amiga/gui.c index e8b3743f2..6526811d4 100755 --- a/amiga/gui.c +++ b/amiga/gui.c @@ -2797,7 +2797,11 @@ void gui_window_new_content(struct gui_window *g) OffMenu(g->shared->win,AMI_MENU_CLEAR); OffMenu(g->shared->win,AMI_MENU_FIND); +#ifdef WITH_NS_SVG + if(c->bitmap || c->type == CONTENT_SVG) +#else if(c->bitmap) +#endif { OnMenu(g->shared->win,AMI_MENU_COPY); OnMenu(g->shared->win,AMI_MENU_SAVEAS_IFF); diff --git a/amiga/iff_dr2d.c b/amiga/iff_dr2d.c new file mode 100644 index 000000000..4779e3241 --- /dev/null +++ b/amiga/iff_dr2d.c @@ -0,0 +1,395 @@ +/* + * Copyright 2009 Chris Young + * + * 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 . + */ + +#ifdef WITH_NS_SVG + +#include +#include +#include +#include +#include "iff_dr2d.h" +#include + +struct ColorRegister cm[1000]; +ULONG numcols; + +ULONG findcolour(ULONG newcol) +{ + ULONG i; + ULONG colour = 0xFFFFFFFF; + UBYTE red,grn,blu; + + red = svgtiny_RED(newcol); + grn = svgtiny_GREEN(newcol); + blu = svgtiny_BLUE(newcol); + + for(i=0;ierror_line, + diagram->error_message); + break; + default: + fprintf(stderr, "unknown svgtiny_code %i", code); + break; + } + fprintf(stderr, "\n"); + } + + if(!(PushChunk(iffh,ID_DR2D,ID_FORM,IFFSIZE_UNKNOWN))) + { + if(!(PushChunk(iffh,0,ID_NAME,IFFSIZE_UNKNOWN))) + { + WriteChunkBytes(iffh,url,strlen(url)); + PopChunk(iffh); + } + + if(!(PushChunk(iffh,0,ID_ANNO,18))) + { + WriteChunkBytes(iffh,"Created by NetSurf",18); + PopChunk(iffh); + } + + if(!(PushChunk(iffh,0,ID_DRHD,16))) + { + struct drhd_struct drhd; + drhd.XLeft = (float) 0.0; + drhd.YTop = (float) 0.0; + drhd.XRight = (float) diagram->width; + drhd.YBot = (float) diagram->height; + + WriteChunkBytes(iffh,&drhd,16); + PopChunk(iffh); + } + + if(!(PushChunk(iffh,0,ID_DASH,IFFSIZE_UNKNOWN))) + { + struct dash_struct dash; + dash.DashID = 1; + dash.NumDashes = 0; + + WriteChunkBytes(iffh,&dash,sizeof(struct dash_struct)); + PopChunk(iffh); + } + + if(!(PushChunk(iffh,0,ID_CMAP,IFFSIZE_UNKNOWN))) + { + for (i = 0; i != diagram->shape_count; i++) { + if(diagram->shape[i].fill != svgtiny_TRANSPARENT) + { + addcolour(diagram->shape[i].fill); + } + + if(diagram->shape[i].stroke != svgtiny_TRANSPARENT) + { + addcolour(diagram->shape[i].stroke); + } + } + + WriteChunkBytes(iffh,cm,3*numcols); + PopChunk(iffh); + } + + for (i = 0; i != diagram->shape_count; i++) { + attr = AllocVec(sizeof(struct attr_struct),MEMF_CLEAR | MEMF_PRIVATE); + if (diagram->shape[i].fill == svgtiny_TRANSPARENT) + attr->FillType = FT_NONE; + else + { + attr->FillType = FT_COLOR; + attr->FillValue = findcolour(diagram->shape[i].fill); + } + if (diagram->shape[i].stroke == svgtiny_TRANSPARENT) + attr->DashPattern = 0; + else + { + attr->DashPattern = 1; + attr->EdgeValue = findcolour(diagram->shape[i].stroke); + } + attr->EdgeThick = (float) diagram->shape[i].stroke_width; + + if(!(PushChunk(iffh,0,ID_ATTR,IFFSIZE_UNKNOWN))) + { + WriteChunkBytes(iffh,attr,14); + PopChunk(iffh); + } + FreeVec(attr); + + if (diagram->shape[i].path) { + union { + float PolyPoints; + ULONG val; + } poly[(diagram->shape[i].path_length)*2]; + + USHORT NumPoints; + long type; + float curx,cury; + + curx = 0.0; + cury = 0.0; + NumPoints = 0; + type = ID_OPLY; + + for (j = 0; + j != diagram->shape[i].path_length; ) { + switch ((int) diagram->shape[i].path[j]) { + case svgtiny_PATH_MOVE: + if(j != 0) + { + poly[NumPoints*2].val = INDICATOR; + poly[(NumPoints*2)+1].val = IND_MOVETO; + NumPoints++; + } + poly[(NumPoints*2)].PolyPoints = diagram->shape[i].path[j + 1]; + poly[(NumPoints*2)+1].PolyPoints = diagram->shape[i].path[j + 2]; + NumPoints++; + curx = (float) diagram->shape[i].path[j + 1]; + cury = (float) diagram->shape[i].path[j + 2]; + + j += 3; + break; + case svgtiny_PATH_CLOSE: + type = ID_CPLY; + j += 1; + break; + case svgtiny_PATH_LINE: + poly[(NumPoints*2)].PolyPoints = (float) diagram->shape[i].path[j + 1]; + poly[(NumPoints*2)+1].PolyPoints = (float) diagram->shape[i].path[j + 2]; + NumPoints++; + curx = (float) diagram->shape[i].path[j + 1]; + cury = (float) diagram->shape[i].path[j + 2]; + j += 3; + break; + case svgtiny_PATH_BEZIER: + poly[NumPoints*2].val = INDICATOR; + poly[(NumPoints*2)+1].val = IND_CURVE; + NumPoints++; + poly[(NumPoints*2)].PolyPoints = curx; + poly[(NumPoints*2)+1].PolyPoints = cury; + NumPoints++; + poly[(NumPoints*2)].PolyPoints = (float) diagram->shape[i].path[j + 1]; + poly[(NumPoints*2)+1].PolyPoints = (float) diagram->shape[i].path[j + 2]; + NumPoints++; + poly[(NumPoints*2)].PolyPoints = (float) diagram->shape[i].path[j + 3]; + poly[(NumPoints*2)+1].PolyPoints = (float) diagram->shape[i].path[j + 4]; + NumPoints++; + poly[(NumPoints*2)].PolyPoints = (float) diagram->shape[i].path[j + 5]; + poly[(NumPoints*2)+1].PolyPoints = (float) diagram->shape[i].path[j + 6]; + curx = poly[(NumPoints*2)].PolyPoints; + cury = poly[(NumPoints*2)+1].PolyPoints; + NumPoints++; + j += 7; + break; + default: + printf("error\n"); + j += 1; + } + } + if(!(PushChunk(iffh,0,type,IFFSIZE_UNKNOWN))) + { + WriteChunkBytes(iffh,&NumPoints,sizeof(USHORT)); + WriteChunkBytes(iffh,poly,NumPoints*2*4); + PopChunk(iffh); + } + } else if (diagram->shape[i].text) { + stxt = AllocVec(sizeof(struct stxt_struct),MEMF_CLEAR); + stxt->BaseX = diagram->shape[i].text_x; + stxt->BaseY = diagram->shape[i].text_y; + stxt->NumChars = strlen(diagram->shape[i].text); + if(!fons_written) + { + fons = AllocVec(sizeof(struct fons_struct),MEMF_CLEAR); + if(!(PushChunk(iffh,0,ID_FONS,IFFSIZE_UNKNOWN))) + { + WriteChunkBytes(iffh,fons,sizeof(struct fons_struct)); + WriteChunkBytes(iffh,"Topaz",5); + PopChunk(iffh); + } + FreeVec(fons); + fons_written = TRUE; + } + + if(!(PushChunk(iffh,0,ID_STXT,IFFSIZE_UNKNOWN))) + { + WriteChunkBytes(iffh,stxt,26); + WriteChunkBytes(iffh,diagram->shape[i].text,strlen(diagram->shape[i].text)); + PopChunk(iffh); + } + FreeVec(stxt); + } + } + + PopChunk(iffh); + } + + svgtiny_free(diagram); + + return 0; +} + +#ifndef AMIGA_DR2D_STANDALONE +bool ami_save_svg(struct content *c,char *filename) +{ + struct IFFHandle *iffh; + + if(iffh = AllocIFF()) + { + if(iffh->iff_Stream = Open(filename,MODE_NEWFILE)) + { + InitIFFasDOS(iffh); + } + else return false; + } + + if((OpenIFF(iffh,IFFF_WRITE))) return false; + + ami_svg_to_dr2d(iffh,c->source_data,c->source_size,c->url); + + if(iffh) CloseIFF(iffh); + if(iffh->iff_Stream) Close((BPTR)iffh->iff_Stream); + if(iffh) FreeIFF(iffh); + +} +#else +/* + * This code can be compiled as a standalone program for testing etc. + * Use something like the following line: + * gcc -o svg2dr2d iff_dr2d.c -lauto -lsvgtiny -lxml2 -lpthread -lz -use-dynld + * -DWITH_NS_SVG -DAMIGA_DR2D_STANDALONE -D__USE_INLINE__ + */ +const char USED ver[] = "\0$VER: svg2dr2d 1.1 (18.05.2009)\0"; + +int main(int argc, char **argv) +{ + BPTR fh = 0; + char *buffer; + size_t n; + struct IFFHandle *iffh = NULL; + int64 size; + LONG rarray[] = {0,0}; + struct RDArgs *args; + STRPTR template = "SVG=INPUT/A,DR2D=OUTPUT/A"; + enum + { + A_SVG, + A_DR2D + }; + + args = ReadArgs(template,rarray,NULL); + + if(!args) + { + printf("Required argument missing\n"); + return 20; + } + + if(fh = Open((char *)rarray[A_SVG],MODE_OLDFILE)) + { + size = GetFileSize(fh); + + buffer = AllocVec((uint32)size,MEMF_PRIVATE); + + Read(fh,buffer,(uint32)size); + Close(fh); + } + else + { + printf("Unable to open file\n"); + return 20; + } + FreeVec(buffer); + + if(iffh = AllocIFF()) + { + if(iffh->iff_Stream = Open((char *)rarray[A_DR2D],MODE_NEWFILE)) + { + InitIFFasDOS(iffh); + } + else return 20; + } + + if((OpenIFF(iffh,IFFF_WRITE))) return 20; + + ami_svg_to_dr2d(iffh,buffer,size,(char *)rarray[A_SVG]); + + if(iffh) CloseIFF(iffh); + if(iffh->iff_Stream) Close((BPTR)iffh->iff_Stream); + if(iffh) FreeIFF(iffh); + FreeArgs(args); +} + +#endif // AMIGA_DR2D_STANDALONE +#endif // WITH_NS_SVG diff --git a/amiga/iff_dr2d.h b/amiga/iff_dr2d.h new file mode 100644 index 000000000..19286a62b --- /dev/null +++ b/amiga/iff_dr2d.h @@ -0,0 +1,105 @@ +/* + * Copyright 2009 Chris Young + * + * 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 . + */ + +#ifdef WITH_NS_SVG +#ifndef AMIGA_IFF_DR2D_H +#define AMIGA_IFF_DR2D_H +#include +#include +#include +#ifndef AMIGA_DR2D_STANDALONE +#include "content/content.h" +#endif + +#define ID_DR2D MAKE_ID('D','R','2','D') +#define ID_DRHD MAKE_ID('D','R','H','D') +#define ID_ATTR MAKE_ID('A','T','T','R') +#define ID_CPLY MAKE_ID('C','P','L','Y') +#define ID_OPLY MAKE_ID('O','P','L','Y') +#define ID_STXT MAKE_ID('S','T','X','T') +#define ID_DASH MAKE_ID('D','A','S','H') +//#define ID_CMAP MAKE_ID('C','M','A','P') in dt/pictureclass +//#define ID_NAME MAKE_ID('N','A','M','E') in dt/datatypes +#define ID_ANNO MAKE_ID('A','N','N','O') +#define ID_FONS MAKE_ID('F','O','N','S') + +struct drhd_struct { + float XLeft, YTop, XRight, YBot; +}; + +struct poly_struct { + USHORT NumPoints; +// float PolyPoints[]; // 2*numpoints +}; + +#define INDICATOR 0xFFFFFFFF +#define IND_SPLINE 0x00000001 +#define IND_MOVETO 0x00000002 +#define IND_CURVE 0x00000001 + +struct fons_struct { + UBYTE FontID; /* ID the font is referenced by */ + UBYTE Pad1; /* Always 0 */ + UBYTE Proportional; /* Is it proportional? */ + UBYTE Serif; /* does it have serifs? */ +}; + +struct stxt_struct { + UBYTE Pad0; /* Always 0 (for future expansion) */ + UBYTE WhichFont; /* Which font to use */ + float CharW, CharH, /* W/H of an individual char */ + BaseX, BaseY, /* Start of baseline */ + Rotation; /* Angle of text (in degrees) */ + uint16 NumChars; + //char TextChars[NumChars]; +}; + +/* Various fill types */ +#define FT_NONE 0 /* No fill */ +#define FT_COLOR 1 /* Fill with color from palette */ +#define FT_OBJECTS 2 /* Fill with tiled objects */ + +struct attr_struct { + UBYTE FillType; /* One of FT_*, above */ + UBYTE JoinType; /* One of JT_*, below */ + UBYTE DashPattern; /* ID of edge dash pattern */ + UBYTE ArrowHead; /* ID of arrowhead to use */ + USHORT FillValue; /* Color or object with which to fill */ + USHORT EdgeValue; /* Edge color index */ + USHORT WhichLayer; /* ID of layer it's in */ + float EdgeThick; /* Line width */ +}; + +/* Join types */ +#define JT_NONE 0 /* Don't do line joins */ +#define JT_MITER 1 /* Mitered join */ +#define JT_BEVEL 2 /* Beveled join */ +#define JT_ROUND 3 /* Round join */ + +struct dash_struct { + USHORT DashID; /* ID of the dash pattern */ + USHORT NumDashes; /* Should always be even */ +// IEEE Dashes[NumDashes]; /* On-off pattern */ +}; + +bool ami_svg_to_dr2d(struct IFFHandle *iffh,char *buffer, uint32 size, char *url); +#ifndef AMIGA_DR2D_STANDALONE +bool ami_save_svg(struct content *c,char *filename); +#endif +#endif // AMIGA_IFF_DR2D_H +#endif // WITH_NS_SVG diff --git a/amiga/menu.c b/amiga/menu.c index b25c861ea..b96321372 100755 --- a/amiga/menu.c +++ b/amiga/menu.c @@ -43,6 +43,7 @@ #include "amiga/search.h" #include "amiga/history_local.h" #include "amiga/bitmap.h" +#include "amiga/iff_dr2d.h" #include "amiga/clipboard.h" #include "content/fetch.h" @@ -526,9 +527,18 @@ void ami_menupick(ULONG code,struct gui_window_2 *gwin,struct MenuItem *item) strlcpy(&fname,savereq->fr_Drawer,1024); AddPart(fname,savereq->fr_File,1024); ami_update_pointer(gwin->win,GUI_POINTER_WAIT); - gwin->bw->current_content->bitmap->url = gwin->bw->current_content->url; - gwin->bw->current_content->bitmap->title = gwin->bw->current_content->title; - bitmap_save(gwin->bw->current_content->bitmap,fname,0); + if(gwin->bw->current_content->bitmap) + { + gwin->bw->current_content->bitmap->url = gwin->bw->current_content->url; + gwin->bw->current_content->bitmap->title = gwin->bw->current_content->title; + bitmap_save(gwin->bw->current_content->bitmap,fname,0); + } +#ifdef WITH_NS_SVG + else if(gwin->bw->current_content->type == CONTENT_SVG) + { + ami_save_svg(gwin->bw->current_content,fname); + } +#endif SetComment(fname,gwin->bw->current_content->url); ami_update_pointer(gwin->win,GUI_POINTER_DEFAULT); } @@ -587,6 +597,12 @@ void ami_menupick(ULONG code,struct gui_window_2 *gwin,struct MenuItem *item) gwin->bw->current_content->bitmap->title = gwin->bw->current_content->title; ami_easy_clipboard_bitmap(gwin->bw->current_content->bitmap); } +#ifdef WITH_NS_SVG + else if(gwin->bw->current_content->type == CONTENT_SVG) + { + ami_easy_clipboard_svg(gwin->bw->current_content); + } +#endif break; case 1: // paste