#include "cmPrefix.h" #include "cmGlobal.h" #include "cmFloatTypes.h" #include "cmRpt.h" #include "cmErr.h" #include "cmCtx.h" #include "cmMem.h" #include "cmMallocDebug.h" #include "cmLinkedHeap.h" #include "cmTime.h" #include "cmText.h" #include "cmFile.h" #include "cmSvgWriter.h" enum { kRectSvgId, kLineSvgId, kTextSvgId }; typedef struct cmSvgEle_str { unsigned id; double x0; double y0; double x1; double y1; cmChar_t* text; cmChar_t* cssClass; struct cmSvgEle_str* link; } cmSvgEle_t; typedef struct cmSvg_str { cmErr_t err; cmLHeapH_t lhH; cmSvgEle_t* elist; cmSvgEle_t* eol; } cmSvg_t; cmSvgH_t cmSvgNullHandle = cmSTATIC_NULL_HANDLE; cmSvg_t* _cmSvgHandleToPtr( cmSvgH_t h ) { cmSvg_t* p = (cmSvg_t*)h.h; assert(p != NULL ); return p; } cmSvgRC_t _cmSvgInsertEle( cmSvg_t* p, unsigned id, double x0, double y0, double x1, double y1, const cmChar_t* text, const cmChar_t* class ) { cmSvgEle_t* e = cmLhAllocZ(p->lhH,cmSvgEle_t,1); e->id = id; e->x0 = x0; e->y0 = y0; e->x1 = x1; e->y1 = y1; e->text = text==NULL ? "" : cmLhAllocStr(p->lhH,text); e->cssClass = cmLhAllocStr(p->lhH,class); if( p->eol == NULL ) p->elist = p->eol = e; else p->eol->link = e; p->eol = e; return kOkSvgRC; } cmSvgRC_t _cmSvgWriterFree( cmSvg_t* p ) { cmLHeapDestroy(&p->lhH); cmMemFree(p); return kOkSvgRC; } cmSvgRC_t cmSvgWriterAlloc( cmCtx_t* ctx, cmSvgH_t* hp ) { cmSvgRC_t rc; if((rc = cmSvgWriterFree(hp)) != kOkSvgRC ) return rc; cmSvg_t* p = cmMemAllocZ(cmSvg_t,1); cmErrSetup(&p->err,&ctx->rpt,"SVG Writer"); // create a local linked heap if( cmLHeapIsValid( p->lhH = cmLHeapCreate(8196,ctx)) == false ) { rc = cmErrMsg(&p->err,kLHeapFailSvgRC,"Lheap create failed."); goto errLabel; } hp->h = p; errLabel: if( rc != kOkSvgRC ) _cmSvgWriterFree(p); return rc; } cmSvgRC_t cmSvgWriterFree( cmSvgH_t* hp ) { cmSvgRC_t rc = kOkSvgRC; if( hp==NULL || cmSvgWriterIsValid(*hp)==false ) return kOkSvgRC; cmSvg_t* p = _cmSvgHandleToPtr(*hp); if((rc = _cmSvgWriterFree(p)) != kOkSvgRC ) return rc; hp->h = NULL; return rc; } bool cmSvgWriterIsValid( cmSvgH_t h ) { return h.h != NULL; } cmSvgRC_t cmSvgWriterRect( cmSvgH_t h, double x, double y, double ww, double hh, const cmChar_t* cssClassLabel ) { cmSvg_t* p = _cmSvgHandleToPtr(h); return _cmSvgInsertEle( p, kRectSvgId, x, y, x+ww, y+hh, NULL, cssClassLabel==NULL?"rectclass":cssClassLabel ); } cmSvgRC_t cmSvgWriterLine( cmSvgH_t h, double x0, double y0, double x1, double y1, const cmChar_t* cssClassLabel ) { cmSvg_t* p = _cmSvgHandleToPtr(h); return _cmSvgInsertEle( p, kLineSvgId, x0, y0, x1, y1, NULL, cssClassLabel==NULL?"lineclass":cssClassLabel ); } cmSvgRC_t cmSvgWriterText( cmSvgH_t h, double x, double y, const cmChar_t* text, const cmChar_t* cssClassLabel ) { cmSvg_t* p = _cmSvgHandleToPtr(h); return _cmSvgInsertEle( p, kTextSvgId, x, y, 0, 0, text==NULL?"":text, cssClassLabel==NULL?"textclass":cssClassLabel ); } void _cmSvgSize( cmSvg_t* p, double* widthRef, double* heightRef ) { *widthRef = 0; *heightRef = 0; if( p->elist == NULL ) return; cmSvgEle_t* e = p->elist; double min_x = cmMin(e->x0,e->x1); double max_x = cmMax(e->x0,e->x1); double min_y = cmMin(e->y0,e->y1); double max_y = cmMax(e->y0,e->y1); for(e=e->link; e!=NULL; e=e->link) { min_x = cmMin(cmMin(min_x,e->x0),e->x1); max_x = cmMax(cmMax(max_x,e->x0),e->x1); min_y = cmMin(cmMin(min_y,e->y0),e->y1); max_y = cmMax(cmMax(max_y,e->y0),e->y1); } *widthRef = max_x - min_x; *heightRef = max_y - min_y; } cmSvgRC_t cmSvgWriterWrite( cmSvgH_t h, const cmChar_t* cssFn, const cmChar_t* outFn ) { cmSvgRC_t rc = kOkSvgRC; cmSvg_t* p = _cmSvgHandleToPtr(h); double svgWidth = 0; double svgHeight = 0; cmSvgEle_t* e = p->elist; cmFileH_t fH = cmFileNullHandle; _cmSvgSize(p, &svgWidth, &svgHeight ); if( cmFileOpen(&fH,outFn,kWriteFileFl,p->err.rpt) != kOkFileRC ) return cmErrMsg(&p->err,kFileFailSvgRC,"SVG file create failed for '%s'.",cmStringNullGuard(outFn)); if( cmFilePrintf(fH,"\n\n\n\n",svgWidth,svgHeight,cssFn) != kOkFileRC ) { rc = cmErrMsg(&p->err,kFileFailSvgRC,"File prefix write failed."); goto errLabel; } for(; e!=NULL; e=e->link) { switch( e->id ) { case kRectSvgId: if( cmFilePrintf(fH,"\n",e->x0,e->y0,e->x1-e->x0,e->y1-e->y0,e->cssClass) != kOkFileRC ) rc = kFileFailSvgRC; break; case kLineSvgId: if( cmFilePrintf(fH,"\n",e->x0,e->y0,e->x1,e->y1,e->cssClass) != kOkFileRC ) rc = kFileFailSvgRC; break; case kTextSvgId: if( cmFilePrintf(fH,"%s\n",e->x0,e->y0,e->cssClass,e->text) != kOkFileRC ) rc = kFileFailSvgRC; break; default: { assert(0); } } if( rc != kOkSvgRC ) { rc = cmErrMsg(&p->err,kFileFailSvgRC,"Element write failed."); break; } } if( cmFilePrint(fH,"\n\n\n") != kOkFileRC ) { rc = cmErrMsg(&p->err,kFileFailSvgRC,"File suffix write failed."); goto errLabel; } errLabel: cmFileClose(&fH); return rc; }