Add ability to copy SVGs to the clipboard and save in IFF DR2D format.

svn path=/trunk/netsurf/; revision=7523
This commit is contained in:
Chris Young 2009-05-19 07:23:56 +00:00
parent efe2151c9a
commit 6f120338ed
9 changed files with 577 additions and 13 deletions

View File

@ -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

View File

@ -30,6 +30,7 @@
#include <datatypes/pictureclass.h>
#include <proto/datatypes.h>
#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;
}

View File

@ -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

View File

@ -33,6 +33,7 @@
#include <proto/asl.h>
#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);
}

View File

@ -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;
}

View File

@ -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);

395
amiga/iff_dr2d.c Normal file
View File

@ -0,0 +1,395 @@
/*
* Copyright 2009 Chris Young <chris@unsatisfactorysoftware.co.uk>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
* NetSurf is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* NetSurf is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifdef WITH_NS_SVG
#include <stdio.h>
#include <svgtiny.h>
#include <proto/exec.h>
#include <string.h>
#include "iff_dr2d.h"
#include <proto/dos.h>
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;i<numcols;i++)
{
if((cm[i].red == red) && (cm[i].green == grn) && (cm[i].blue == blu))
colour = i;
}
return colour;
}
void addcolour(ULONG newcol)
{
int i;
ULONG colour;
UBYTE red,grn,blu;
colour = findcolour(newcol);
if(colour == 0xFFFFFFFF)
{
cm[numcols].red = svgtiny_RED(newcol);
cm[numcols].green = svgtiny_GREEN(newcol);
cm[numcols].blue = svgtiny_BLUE(newcol);
numcols++;
}
}
bool ami_svg_to_dr2d(struct IFFHandle *iffh,char *buffer, uint32 size, char *url)
{
struct svgtiny_diagram *diagram;
svgtiny_code code;
unsigned int i;
unsigned int j;
BOOL fons_written = FALSE;
struct fons_struct *fons;
struct stxt_struct *stxt;
struct attr_struct *attr;
/* create svgtiny object */
diagram = svgtiny_create();
if (!diagram) {
fprintf(stderr, "svgtiny_create failed\n");
return 1;
}
/* parse */
code = svgtiny_parse(diagram, buffer, size, url, 1000, 1000);
if (code != svgtiny_OK) {
fprintf(stderr, "svgtiny_parse failed: ");
switch (code) {
case svgtiny_OUT_OF_MEMORY:
fprintf(stderr, "svgtiny_OUT_OF_MEMORY");
break;
case svgtiny_LIBXML_ERROR:
fprintf(stderr, "svgtiny_LIBXML_ERROR");
break;
case svgtiny_NOT_SVG:
fprintf(stderr, "svgtiny_NOT_SVG");
break;
case svgtiny_SVG_ERROR:
fprintf(stderr, "svgtiny_SVG_ERROR: line %i: %s",
diagram->error_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

105
amiga/iff_dr2d.h Normal file
View File

@ -0,0 +1,105 @@
/*
* Copyright 2009 Chris Young <chris@unsatisfactorysoftware.co.uk>
*
* This file is part of NetSurf, http://www.netsurf-browser.org/
*
* NetSurf is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 of the License.
*
* NetSurf is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifdef WITH_NS_SVG
#ifndef AMIGA_IFF_DR2D_H
#define AMIGA_IFF_DR2D_H
#include <proto/iffparse.h>
#include <datatypes/pictureclass.h>
#include <stdbool.h>
#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

View File

@ -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