From e713b548160b3a05be3a65d85ac35c016afd739f Mon Sep 17 00:00:00 2001 From: LMaster765 Date: Tue, 4 Mar 2025 10:00:49 -0700 Subject: [PATCH 01/28] Update page margin --- centrallix/report/prtmgmt_v3_fm_html.c | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/centrallix/report/prtmgmt_v3_fm_html.c b/centrallix/report/prtmgmt_v3_fm_html.c index 36262e3f..3204fc30 100644 --- a/centrallix/report/prtmgmt_v3_fm_html.c +++ b/centrallix/report/prtmgmt_v3_fm_html.c @@ -774,12 +774,9 @@ prt_htmlfm_Generate(void* context_v, pPrtObjStream page_obj) prt_htmlfm_OutputPrintf(context, PRT_HTMLFM_PAGEHEADER, (int)(page_obj->Width*PRT_HTMLFM_XPIXEL+0.001)+34); /** Write a table to handle page margins **/ - prt_htmlfm_Output(context, "\n", -1); - prt_htmlfm_OutputPrintf(context, "\n", (int)(page_obj->MarginLeft*PRT_HTMLFM_XPIXEL+0.001)); - prt_htmlfm_OutputPrintf(context, "\n", (int)((page_obj->Width - page_obj->MarginLeft - page_obj->MarginRight+0.001)*PRT_HTMLFM_XPIXEL)); - prt_htmlfm_OutputPrintf(context, "\n", (int)(page_obj->MarginRight*PRT_HTMLFM_XPIXEL+0.001)); - prt_htmlfm_OutputPrintf(context, "
\n", - (int)((page_obj->MarginTop+0.001)*PRT_HTMLFM_YPIXEL)); + prt_htmlfm_OutputPrintf(context, "
\n", (int)(page_obj->Width*PRT_HTMLFM_XPIXEL+0.001), + (int)((page_obj->MarginTop+0.001)*PRT_HTMLFM_YPIXEL), (int)((page_obj->MarginRight+0.001)*PRT_HTMLFM_YPIXEL), + (int)((page_obj->MarginBottom+0.001)*PRT_HTMLFM_YPIXEL), (int)((page_obj->MarginLeft+0.001)*PRT_HTMLFM_YPIXEL)); /** We need to scan the absolute-positioned content to figure out how many ** "columns" and "rows" we need to put in the "table" used for layout @@ -892,8 +889,7 @@ prt_htmlfm_Generate(void* context_v, pPrtObjStream page_obj) /** Write the page footer **/ - prt_htmlfm_OutputPrintf(context, "
\n", - (int)((page_obj->MarginBottom+0.001)*PRT_HTMLFM_YPIXEL)); + prt_htmlfm_Output(context, "", -1); if (context->Flags & PRT_HTMLFM_F_PAGINATED) prt_htmlfm_Output(context, PRT_HTMLFM_PAGEFOOTER, -1); From aedcb30358afc5f3a668660090ece590daae76c8 Mon Sep 17 00:00:00 2001 From: Brennen Puth - Kardia Date: Tue, 4 Mar 2025 11:15:28 -0700 Subject: [PATCH 02/28] Add compile commands (clang LSP) to gitignore --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index cbfe20f1..c77d5715 100644 --- a/.gitignore +++ b/.gitignore @@ -62,3 +62,4 @@ perf.data.old .idea/ .vscode/ centrallix-os/tmp/* +compile_commands.json From ea4fcffd292e041812c366ce5883f5f824ffdca5 Mon Sep 17 00:00:00 2001 From: Brennen Puth - Kardia Date: Tue, 4 Mar 2025 11:22:44 -0700 Subject: [PATCH 03/28] Added clang cache to gitignore --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index c77d5715..23564ec2 100644 --- a/.gitignore +++ b/.gitignore @@ -63,3 +63,4 @@ perf.data.old .vscode/ centrallix-os/tmp/* compile_commands.json +.cache/* From b27d224555a8832a167a0869ca43d9fd8083c244 Mon Sep 17 00:00:00 2001 From: Brennen Puth - Kardia Date: Tue, 4 Mar 2025 11:24:53 -0700 Subject: [PATCH 04/28] fix previous commit --- .gitignore | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 23564ec2..52647cd2 100644 --- a/.gitignore +++ b/.gitignore @@ -63,4 +63,4 @@ perf.data.old .vscode/ centrallix-os/tmp/* compile_commands.json -.cache/* +.cache/ From 59d3bf605aae03e07aa0368f71aa2ae9c4fce4ef Mon Sep 17 00:00:00 2001 From: Brennen Puth - Kardia Date: Tue, 4 Mar 2025 14:44:04 -0700 Subject: [PATCH 05/28] Remove legacy statement from DOCTYPE header --- centrallix/report/prtmgmt_v3_fm_html.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/centrallix/report/prtmgmt_v3_fm_html.c b/centrallix/report/prtmgmt_v3_fm_html.c index 3204fc30..ba4f7fd2 100644 --- a/centrallix/report/prtmgmt_v3_fm_html.c +++ b/centrallix/report/prtmgmt_v3_fm_html.c @@ -62,7 +62,7 @@ /*** Document header ***/ -#define PRT_HTMLFM_HEADER "\n" \ +#define PRT_HTMLFM_HEADER "\n" \ "\n" \ "\n" \ " Centrallix HTML Document\n" \ From 8392d0c36c9fc172e0e973de12922f4ce437b1d0 Mon Sep 17 00:00:00 2001 From: "Kai D." Date: Tue, 4 Mar 2025 15:15:42 -0700 Subject: [PATCH 06/28] Changed the images to work from base64 encoded strings --- centrallix/report/prtmgmt_v3_fm_html.c | 143 ++++++++++++++++--------- 1 file changed, 90 insertions(+), 53 deletions(-) diff --git a/centrallix/report/prtmgmt_v3_fm_html.c b/centrallix/report/prtmgmt_v3_fm_html.c index 3204fc30..496ba1bf 100644 --- a/centrallix/report/prtmgmt_v3_fm_html.c +++ b/centrallix/report/prtmgmt_v3_fm_html.c @@ -4,19 +4,16 @@ #include #include #include -#include "barcode.h" -#include "report.h" -#include "cxlib/mtask.h" -#include "cxlib/magic.h" -#include "cxlib/xarray.h" #include "cxlib/xstring.h" #include "prtmgmt_v3/prtmgmt_v3.h" #include "prtmgmt_v3/prtmgmt_v3_fm_html.h" #include "prtmgmt_v3/ht_font_metrics.h" -#include "htmlparse.h" #include "cxlib/mtsession.h" #include "centrallix.h" #include "double.h" +#include +#include +#include /************************************************************************/ /* Centrallix Application Server System */ @@ -157,6 +154,16 @@ struct _PSFI }; +#define MAX_IMAGE_SIZE (10 * 1024 * 1024) // 10 MB for image buffer + +/*** Struct that holds a raw file and its size + ***/ +typedef struct { + char *buffer; + size_t size; + size_t capacity; +} ImageBuffer; + /*** prt_htmlfm_Output() - outputs a string of text into the HTML *** document. @@ -588,6 +595,39 @@ prt_htmlfm_EndBorder(pPrtHTMLfmInf context, pPrtBorder border, pPrtObjStream obj } + + +/** Gets size of image file */ +int ImageWriteFn(void *arg, const void *data, size_t len) { + ImageBuffer *imgBuf = (ImageBuffer *)arg; + if (imgBuf->size + len > imgBuf->capacity) { + return -1; // Buffer overflow + } + memcpy(imgBuf->buffer + imgBuf->size, data, len); + imgBuf->size += len; + return len; +} + +const char b64_table[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + +/** Encodes a char* input to base64 */ +char *base64_encode(const unsigned char *input, size_t len) { + size_t out_len = 4 * ((len + 2) / 3); + char *output = (char *)nmMalloc(out_len + 1); + if (!output) return NULL; + + char *p = output; + for (size_t i = 0; i < len; i += 3) { + int val = (input[i] << 16) | ((i + 1 < len ? input[i + 1] : 0) << 8) | (i + 2 < len ? input[i + 2] : 0); + *p++ = b64_table[(val >> 18) & 0x3F]; + *p++ = b64_table[(val >> 12) & 0x3F]; + *p++ = (i + 1 < len) ? b64_table[(val >> 6) & 0x3F] : '='; + *p++ = (i + 2 < len) ? b64_table[val & 0x3F] : '='; + } + *p = '\0'; + return output; +} + /*** prt_htmlfm_Generate_r() - recursive worker routine to do the bulk *** of page generation. ***/ @@ -647,52 +687,49 @@ prt_htmlfm_Generate_r(pPrtHTMLfmInf context, pPrtObjStream obj) } break; - case PRT_OBJ_T_IMAGE: - /** We need an image store location in order to handle these **/ - if (context->Session->ImageOpenFn) - { - id = PRT_HTMLFM.ImageID++; - w = obj->Width*PRT_HTMLFM_XPIXEL; - h = obj->Height*PRT_HTMLFM_YPIXEL; - if (w <= 0) w = 1; - if (h <= 0) h = 1; - path = (char*)nmMalloc(OBJSYS_MAX_PATH); - if (!path) - { - mssError(1, "PRT", "nmMalloc() failed\n"); - return -1; - } - rval = snprintf(path, OBJSYS_MAX_PATH, "%sprt_htmlfm_%8.8lX.png", context->Session->ImageSysDir, id); - if (rval < 0 || rval >= OBJSYS_MAX_PATH) - { - mssError(1, "PRT", "Internal representation exceeded for image pathname\n"); - nmFree(path, OBJSYS_MAX_PATH); - return -1; - } - arg = context->Session->ImageOpenFn(context->Session->ImageContext, path, O_CREAT | O_WRONLY | O_TRUNC, 0600, "image/png"); - if (!arg) - { - mssError(0,"PRT","Failed to open new linked image '%s'",path); - nmFree(path, OBJSYS_MAX_PATH); - return -1; - } - prt_internal_WriteImageToPNG(context->Session->ImageWriteFn, arg, (pPrtImage)(obj->Content), w, h); - context->Session->ImageCloseFn(arg); - nmFree(path, OBJSYS_MAX_PATH); - if (obj->URL && !strchr(obj->URL, '"')) - { - prt_htmlfm_Output(context, "URL, -1); - prt_htmlfm_Output(context, "\">", 2); - } - prt_htmlfm_OutputPrintf(context, "", - context->Session->ImageExtDir, id, w, h); - if (obj->URL && !strchr(obj->URL, '"')) - { - prt_htmlfm_Output(context, "", 4); + /* Encodes image to base64 and writes to HTML */ + case PRT_OBJ_T_IMAGE: + if (context->Session->ImageOpenFn) { + w = obj->Width * PRT_HTMLFM_XPIXEL; + h = obj->Height * PRT_HTMLFM_YPIXEL; + if (w <= 0) w = 1; + if (h <= 0) h = 1; + + ImageBuffer imgBuf = { (char *)nmMalloc(MAX_IMAGE_SIZE), 0, MAX_IMAGE_SIZE }; + if (!imgBuf.buffer) { + mssError(1, "PRT", "nmMalloc() failed\n"); + return -1; + } + + // Capture image to buffer + prt_internal_WriteImageToPNG(ImageWriteFn, &imgBuf, (pPrtImage)(obj->Content), w, h); + + // Encode image to base64 + char *base64Image = base64_encode((unsigned char *)imgBuf.buffer, imgBuf.size); + nmFree(imgBuf.buffer, MAX_IMAGE_SIZE); + if (!base64Image) { + mssError(1, "PRT", "Base64 encoding failed\n"); + return -1; + } + + // Output the image as a base64 Data URL + if (obj->URL && !strchr(obj->URL, '"')) { + prt_htmlfm_Output(context, "URL, -1); + prt_htmlfm_Output(context, "\">", 2); + } + + prt_htmlfm_OutputPrintf(context, "", + base64Image, w, h); + + if (obj->URL && !strchr(obj->URL, '"')) { + prt_htmlfm_Output(context, "", 4); + } + + nmFree(base64Image, strlen(base64Image) + 1); } - } - break; + break; + case PRT_OBJ_T_SVG: /** We need an image store location in order to handle these **/ @@ -836,12 +873,12 @@ prt_htmlfm_Generate(void* context_v, pPrtObjStream page_obj) /** Write the layout table **/ prt_htmlfm_Output(context, "\n", -1); - for(i=0;iWidth - page_obj->MarginLeft - page_obj->MarginRight - colpos[i])*PRT_HTMLFM_XPIXEL; else - w = (colpos[i+1] - colpos[i])*PRT_HTMLFM_XPIXEL; + w = (colpos[i+1] - colpos[i]) * PRT_HTMLFM_XPIXEL; prt_htmlfm_OutputPrintf(context, "\n", w); } From b75c79c9353fbeab6611ca5c0a40cb996cb7faad Mon Sep 17 00:00:00 2001 From: LMaster765 Date: Tue, 4 Mar 2025 15:26:48 -0700 Subject: [PATCH 07/28] Update area and string generation --- centrallix/include/prtmgmt_v3.h | 499 ------------------ centrallix/include/prtmgmt_v3/prtmgmt_v3.h | 1 + .../include/prtmgmt_v3/prtmgmt_v3_lm_text.h | 1 + centrallix/report/prtmgmt_v3_fm_html.c | 29 +- .../report/prtmgmt_v3_fm_html_lm_text.c | 277 +++++----- 5 files changed, 168 insertions(+), 639 deletions(-) delete mode 100644 centrallix/include/prtmgmt_v3.h diff --git a/centrallix/include/prtmgmt_v3.h b/centrallix/include/prtmgmt_v3.h deleted file mode 100644 index 1bfa7bb6..00000000 --- a/centrallix/include/prtmgmt_v3.h +++ /dev/null @@ -1,499 +0,0 @@ -#ifndef _PRTMGMT_V3_H -#define _PRTMGMT_V3_H -#error "this file is no longer used." - -/************************************************************************/ -/* Centrallix Application Server System */ -/* Centrallix Core */ -/* */ -/* Copyright (C) 2001 LightSys Technology Services, Inc. */ -/* */ -/* This program 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; either version 2 of the License, or */ -/* (at your option) any later version. */ -/* */ -/* This program 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, write to the Free Software */ -/* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA */ -/* 02111-1307 USA */ -/* */ -/* A copy of the GNU General Public License has been included in this */ -/* distribution in the file "COPYING". */ -/* */ -/* Module: prtmgmt.c,prtmgmt.h */ -/* Author: Greg Beeley (GRB) */ -/* Date: December 12, 2001 */ -/* */ -/* Description: This module provides the Version-3 printmanagement */ -/* subsystem functionality. */ -/************************************************************************/ - - -#include "cxlib/xarray.h" -#include "cxlib/xhash.h" - - -#define PRT_XY_CORRECTION_FACTOR (72.0/120.0) - - -/*** Layout Manager Structure ***/ -typedef struct _PLM - { - int Magic; - char Name[32]; - int (*AddObject)(); /* adds a child object to a parent */ - int (*ChildResizeReq)(); /* can we resize the child object in this container? */ - int (*ChildResized)(); /* child object in this container *was* resized. */ - int (*InitContainer)(); /* init a newly created container */ - int (*DeinitContainer)(); /* de-init a container (before deallocation) */ - int (*Break)(); /* request a break on this container (e.g., pagebreak) */ - int (*ChildBreakReq)(); /* child object is requesting this container to break */ - int (*Resize)(); /* request a resize on this container */ - int (*SetValue)(); /* set a layout manager specific setting on the object */ - int (*Reflow)(); /* called by parent object's layout mgr to indicate that - child geom or overlays have changed, and child should - reflow the layout, including LinkNext'd layout areas */ - int (*Finalize)(); /* this is the layout manager's chance to make any last- - milllisecond changes to the container before the page - is generated. The changes may NOT affect the container's - geometry */ - } - PrtLayoutMgr, *pPrtLayoutMgr; - - -/*** Print Object Type structure ***/ -typedef struct _POT - { - int Magic; - int TypeID; /* PRT_OBJ_T_xxx */ - char TypeName[32]; - pPrtLayoutMgr PrefLayoutMgr; - } - PrtObjType, *pPrtObjType; - - -/*** Text style definition ***/ -typedef struct _PTS - { - int FontID; /* ID from PRTMGMT.FontList mapping */ - int FontSize; /* point size of font */ - int Attr; /* PRT_OBJ_A_xxx */ - int Color; /* 0x00RRGGBB */ - } - PrtTextStyle, *pPrtTextStyle; - - -/*** Print Object Stream structure ***/ -typedef struct _POS - { - int Magic; - struct _POS* Next; /* next sequentially in stream */ - struct _POS* Prev; /* previous sequentially in stream */ - struct _POS* ContentHead; /* Contents of this container */ - struct _POS* ContentTail; - struct _POS* Parent; /* Container of this object */ - struct _POS* LinkNext; /* Pointer to object where content should continue */ - struct _POS* LinkPrev; /* Pointer to object where content continued from */ - struct _POS* YNext; - struct _POS* YPrev; - pPrtObjType ObjType; - pPrtLayoutMgr LayoutMgr; - void* Session; /* pPrtObjSession */ - void* LMData; /* layout manager instance-specific data */ - int nOpens; /* total open subcontainers + container */ - int Flags; /* PRT_OBJ_F_xxx */ - int BGColor; /* 0x00RRGGBB */ - int FGColor; /* 0x00RRGGBB */ - int ObjID; /* such as page number for PAGE objects */ - PrtTextStyle TextStyle; - int Justification; /* PRT_JUST_T_xxx */ - double PageX; - double PageY; - double X; /* Relative X position to container origin */ - double Y; /* Relative Y position to container origin */ - double YBase; /* Relative Y baseline to the object's Y position */ - double Width; /* Width of object */ - double Height; /* Height of object */ - double ConfigWidth; /* initially configured width of object */ - double ConfigHeight; /* initially configured height of object */ - double MarginLeft; - double MarginRight; - double MarginTop; - double MarginBottom; - double LineHeight; /* Height of lines... */ - unsigned char* Content; /* Text content or image bitmap */ - int ContentSize; /* total memory allocated for the content */ - } - PrtObjStream, *pPrtObjStream; - -#define PRTSESSION(x) ((pPrtSession)((x)->Session)) - - -/*** Units-of-measure conversion data ***/ -typedef struct _PU - { - char Name[32]; - double AdjX; - double AdjY; - } - PrtUnits, *pPrtUnits; - - -/*** Font ID descriptor ***/ -typedef struct _PFN - { - int FontID; - char FontName[40]; - } - PrtFontDesc, *pPrtFontDesc; - - -/*** Resolution definition structure ***/ -typedef struct _PRE - { - int Xres; - int Yres; - int Colors; /* PRT_COLOR_T_xxx */ - } - PrtResolution, *pPrtResolution; - - -/*** Formatter structure ***/ -typedef struct _PFM - { - int Magic; - char Name[32]; - int Priority; - void* (*Probe)(); - int (*Generate)(); - int (*GetNearestFontSize)(); - double (*GetCharacterMetric)(); - double (*GetCharacterBaseline)(); - int (*Close)(); - } - PrtFormatter, *pPrtFormatter; - - -/*** Output Driver structure ***/ -typedef struct _PD - { - int Magic; - char Name[32]; - char ContentType[64]; - void* (*Open)(); - int (*Close)(); - pXArray (*GetResolutions)(); - int (*SetResolution)(); - int (*SetTextStyle)(); - int (*GetNearestFontSize)(); - double (*GetCharacterMetric)(); - double (*GetCharacterBaseline)(); - int (*SetHPos)(); - int (*SetVPos)(); - int (*WriteText)(); - double (*WriteRasterData)(); - int (*WriteFF)(); - double (*WriteRect)(); - } - PrtOutputDriver, *pPrtOutputDriver; - - -/*** Scheduled event structure ***/ -typedef struct _PE - { - struct _PE* Next; - int EventType; - pPrtObjStream TargetObject; - void* Parameter; - } - PrtEvent, *pPrtEvent; - - -/*** Print Session structure ***/ -typedef struct _PS - { - int Magic; - pPrtObjStream StreamHead; - double PageWidth; - double PageHeight; - pPrtUnits Units; - int (*WriteFn)(); - void* WriteArg; - pPrtFormatter Formatter; - int ResolutionX; /* in DPI, always */ - int ResolutionY; /* in DPI, always */ - void* FormatterData; - int FocusHandle; - pPrtEvent PendingEvents; - } - PrtSession, *pPrtSession; - - -/*** Print Object Handle structure ***/ -typedef struct _PHD - { - int Magic; - int HandleID; - union - { - pPrtObjStream Object; - pPrtSession Session; - void* Generic; - } - Ptr; - } - PrtHandle, *pPrtHandle; - - -#define PRT_MAXBDR 2 - -/*** border line data, such as for tables, etc. ***/ -typedef struct _PBD - { - double Width[PRT_MAXBDR]; /* width/thickness of border lines in X units (0.1in / 7.2pt) */ - double Sep; /* separation between border lines, if two */ - double Pad; /* padding before lines start */ - double TotalWidth; /* total width of border */ - int nLines; /* number of border lines */ - int Color[PRT_MAXBDR]; /* color of border lines */ - } - PrtBorder, *pPrtBorder; - - -/*** image data header structure ***/ -typedef struct _PIH - { - int Width; /* raster data width in pixels */ - int Height; /* raster data height in pixels */ - int ColorMode; /* PRT_COLOR_T_xxx; mono=1bpp, grey=8bpp, color=32bpp */ - int DataLength; /* length of raster data in bytes */ - double YOffset; /* offset into image next printed area is. Used by output drv. */ - } - PrtImageHdr, *pPrtImageHdr; - -typedef struct _PIM - { - PrtImageHdr Hdr; - union - { - unsigned char Byte[1]; /* content in byte-addressing */ - unsigned int Word[1]; /* content in word (32bit) addressing */ - } - Data; - } - PrtImage, *pPrtImage; - - -/*** Print management global structure ***/ -typedef struct _PG - { - XArray UnitsList; - XArray TypeList; - XArray LayoutMgrList; - XArray FormatterList; - XArray FormatDriverList; - XArray FontList; - XHashTable HandleTable; - XHashTable HandleTableByPtr; - int NextHandleID; - } - PrtGlobals, *pPrtGlobals; - -extern PrtGlobals PRTMGMT; - - -#define PRT_OBJ_F_FLOWAROUND 1 /* multiple lines can flow around this */ -#define PRT_OBJ_F_NOLINESEQ 2 /* do not honor sequence within the line */ -#define PRT_OBJ_F_OPEN 4 /* container is open for writing */ -#define PRT_OBJ_F_NEWLINE 8 /* object starts a new line (for textflow) */ -#define PRT_OBJ_F_SOFTNEWLINE 16 /* object starts a soft new line (from wordwrapping) */ -#define PRT_OBJ_F_ALLOWHARDBREAK 32 /* allow object to be broken for pagination via WriteFF */ -#define PRT_OBJ_F_REPEAT 64 /* object repeats *verbatim* on subsequent pages */ -#define PRT_OBJ_F_CALLBACK 128 /* do an API callback to get the object's content */ -#define PRT_OBJ_F_FIXEDSIZE 256 /* object's size cannot be resized */ -#define PRT_OBJ_F_REQCOMPLETE 512 /* require completion of content before emitting the page */ -#define PRT_OBJ_F_XSET 1024 /* X location is pre-set. */ -#define PRT_OBJ_F_YSET 2048 /* Y location is pre-set. */ -#define PRT_OBJ_F_ALLOWSOFTBREAK 4096 /* allow break for pagination via wrapping or newlines */ -#define PRT_OBJ_F_ALLOWBREAK (PRT_OBJ_F_ALLOWSOFTBREAK | PRT_OBJ_F_ALLOWHARDBREAK) -#define PRT_OBJ_F_SYNCBREAK 8192 /* container will break when another on the page does */ -#define PRT_OBJ_F_LMFLAG1 16384 /* layout-manager specific flag */ -#define PRT_OBJ_F_LMFLAG2 32768 /* layout-manager specific flag */ -#define PRT_OBJ_F_LMFLAG3 65536 /* layout-manager specific flag */ -#define PRT_OBJ_F_PERMANENT 131072 /* object is permanent - don't remove it to reflow */ -#define PRT_OBJ_F_MARGINRELEASE 262144 /* object is not subject to container's margins */ - -/** these flags can be used by the api caller **/ -#define PRT_OBJ_U_FLOWAROUND PRT_OBJ_F_FLOWAROUND -#define PRT_OBJ_U_NOLINESEQ PRT_OBJ_F_NOLINESEQ -#define PRT_OBJ_U_ALLOWBREAK PRT_OBJ_F_ALLOWBREAK -#define PRT_OBJ_U_ALLOWHARDBREAK PRT_OBJ_F_ALLOWHARDBREAK -#define PRT_OBJ_U_ALLOWSOFTBREAK PRT_OBJ_F_ALLOWSOFTBREAK -#define PRT_OBJ_U_REPEAT PRT_OBJ_F_REPEAT -#define PRT_OBJ_U_FIXEDSIZE PRT_OBJ_F_FIXEDSIZE -#define PRT_OBJ_U_REQCOMPLETE PRT_OBJ_F_REQCOMPLETE -#define PRT_OBJ_U_XSET PRT_OBJ_F_XSET -#define PRT_OBJ_U_YSET PRT_OBJ_F_YSET -#define PRT_OBJ_U_SYNCBREAK PRT_OBJ_F_SYNCBREAK - -#define PRT_OBJ_UFLAGMASK (PRT_OBJ_U_FLOWAROUND | PRT_OBJ_U_NOLINESEQ | PRT_OBJ_U_ALLOWBREAK | PRT_OBJ_U_REPEAT | PRT_OBJ_U_FIXEDSIZE | PRT_OBJ_U_REQCOMPLETE | PRT_OBJ_U_XSET | PRT_OBJ_U_YSET | PRT_OBJ_U_SYNCBREAK) - -#define PRT_OBJ_A_BOLD 1 -#define PRT_OBJ_A_ITALIC 2 -#define PRT_OBJ_A_UNDERLINE 4 - -#define PRT_OBJ_T_DOCUMENT 1 /* whole document */ -#define PRT_OBJ_T_PAGE 2 /* one page of the document */ -#define PRT_OBJ_T_AREA 3 /* a textflow-managed area */ -#define PRT_OBJ_T_STRING 4 /* a string of text content */ -#define PRT_OBJ_T_IMAGE 5 /* an image/picture */ -#define PRT_OBJ_T_RECT 6 /* rectangle, solid color */ -#define PRT_OBJ_T_TABLE 7 /* tabular-data */ -#define PRT_OBJ_T_TABLEROW 8 /* table row */ -#define PRT_OBJ_T_TABLECELL 9 /* table cell */ -#define PRT_OBJ_T_SECTION 10 /* columnar section */ -#define PRT_OBJ_T_SECTCOL 11 /* one column in a section. */ - -#define PRT_COLOR_T_MONO 1 /* black/white only image, 1 bit per pixel */ -#define PRT_COLOR_T_GREY 2 /* greyscale image, 1 byte per pixel */ -#define PRT_COLOR_T_FULL 3 /* RGB color image, 1 int (32bit) per pixel */ - -#define PRT_FONT_T_MONOSPACE 1 /* typically courier */ -#define PRT_FONT_T_SANSSERIF 2 /* typically helvetica */ -#define PRT_FONT_T_SERIF 3 /* typically times */ -#define PRT_FONT_T_USBARCODE 4 /* u.s.a. postal barcode */ - -#define PRT_JUST_T_LEFT 0 -#define PRT_JUST_T_RIGHT 1 -#define PRT_JUST_T_CENTER 2 -#define PRT_JUST_T_FULL 3 - -#define PRT_EVENT_T_REFLOW 0 /* reflow the contents of a container */ - - -/*** MakeBorder flags ***/ -#define PRT_MKBDR_F_TOP 1 /* border is 'top' */ -#define PRT_MKBDR_F_BOTTOM 2 -#define PRT_MKBDR_F_LEFT 4 -#define PRT_MKBDR_F_RIGHT 8 -#define PRT_MKBDR_DIRFLAGS (PRT_MKBDR_F_TOP | PRT_MKBDR_F_BOTTOM | PRT_MKBDR_F_LEFT | PRT_MKBDR_F_RIGHT) -#define PRT_MKBDR_F_MARGINRELEASE 16 - - -/*** System functions ***/ -int prtInitialize(); -int prtRegisterUnits(char* units_name, double x_adj, double y_adj); -pPrtObjType prtAllocType(); -int prtRegisterType(pPrtObjType type); -pPrtLayoutMgr prtAllocLayoutMgr(); -int prtRegisterLayoutMgr(pPrtLayoutMgr layout_mgr); -pPrtLayoutMgr prtLookupLayoutMgr(char* layout_mgr); -pPrtUnits prtLookupUnits(char* units_name); -int prtRegisterFont(char* font_name, int font_id); -int prtLookupFont(char* font_name); -char* prtLookupFontName(int font_id); -int prtAllocHandle(void* ptr); -void* prtHandlePtr(int handle_id); -int prtUpdateHandle(int handle_id, void* ptr); -int prtUpdateHandleByPtr(void* old_ptr, void* ptr); -int prtFreeHandle(int handle_id); -int prtLookupHandle(void* ptr); -pPrtFormatter prtAllocFormatter(); -int prtRegisterFormatter(pPrtFormatter fmt); - -/*** Session-level functions ***/ -pPrtSession prtOpenSession(char* output_type, int (*write_fn)(), void* write_arg, int page_flags); -int prtCloseSession(pPrtSession s); -int prtSetPageGeometry(pPrtSession s, double width, double height); -int prtGetPageGeometry(pPrtSession s, double *width, double *height); -int prtSetUnits(pPrtSession s, char* units_name); -char* prtGetUnits(pPrtSession s); -int prtSetResolution(pPrtSession s, int dpi); - -/** Internal management functions **/ -pPrtObjStream prt_internal_AllocObj(char* type); -pPrtObjStream prt_internal_AllocObjByID(int type_id); -int prt_internal_FreeObj(pPrtObjStream obj); -int prt_internal_Add(pPrtObjStream parent, pPrtObjStream new_child); -int prt_internal_CopyAttrs(pPrtObjStream src, pPrtObjStream dst); -int prt_internal_CopyGeom(pPrtObjStream src, pPrtObjStream dst); -double prt_internal_GetFontHeight(pPrtObjStream obj); -double prt_internal_GetFontBaseline(pPrtObjStream obj); -double prt_internal_GetStringWidth(pPrtObjStream obj, char* str, int n); -pPrtObjStream prt_internal_YSort(pPrtObjStream obj); -int prt_internal_AddYSorted(pPrtObjStream obj, pPrtObjStream newobj); -int prt_internal_FreeTree(pPrtObjStream obj); -int prt_internal_GeneratePage(pPrtSession s, pPrtObjStream page); -pPrtObjStream prt_internal_GetPage(pPrtObjStream obj); -pPrtObjStream prt_internal_AddEmptyObj(pPrtObjStream container); -pPrtObjStream prt_internal_CreateEmptyObj(pPrtObjStream container); -int prt_internal_Dump(pPrtObjStream obj); -pPrtObjStream prt_internal_Duplicate(pPrtObjStream obj, int with_content); -int prt_internal_AdjustOpenCount(pPrtObjStream obj, int adjustment); -int prt_internal_Reflow(pPrtObjStream obj); -int prt_internal_ScheduleEvent(pPrtSession s, pPrtObjStream target, int type, void* param); -int prt_internal_DispatchEvents(pPrtSession s); -int prt_internal_MakeBorder(pPrtObjStream parent, double x, double y, double len, int flags, pPrtBorder b, pPrtBorder sb, pPrtBorder eb); -int prt_internal_GetPixel(pPrtImage img, double xoffset, double yoffset); - -/** Strict-formatter to output-driver interfacing **/ -pPrtOutputDriver prt_strictfm_AllocDriver(); -int prt_strictfm_RegisterDriver(pPrtOutputDriver drv); - -/** These macros are used for units conversion **/ -#define prtUnitX(s,x) ((x)*(((pPrtSession)(s))->Units->AdjX)) -#define prtUnitY(s,y) ((y)*(((pPrtSession)(s))->Units->AdjY)) -#define prtUsrUnitX(s,x) ((x)/(((pPrtSession)(s))->Units->AdjX)) -#define prtUsrUnitY(s,y) ((y)/(((pPrtSession)(s))->Units->AdjY)) - -/*** General Printing Functions ***/ -int prtGetPageRef(pPrtSession s); -int prtSetFocus(pPrtSession s, int handle_id); -int prtSetPageNumber(int handle_id, int new_pagenum); -int prtGetPageNumber(int handle_id); - -/*** Formatting functions ***/ -int prtSetJustification(int handle_id, int just_mode); /* PRT_JUST_T_xxx */ -int prtGetJustification(int handle_id); -int prtSetLineHeight(int handle_id,double line_height); -double prtGetLineHeight(int handle_id); -int prtSetTextStyle(int handle_id, pPrtTextStyle style); -int prtGetTextStyle(int handle_id, pPrtTextStyle *style); -int prtSetAttr(int handle_id, int attrs); /* PRT_OBJ_A_xxx */ -int prtGetAttr(int handle_id); -int prtSetFont(int handle_id, char* fontname); -char* prtGetFont(int handle_id); -int prtSetFontSize(int handle_id, int pt_size); -int prtGetFontSize(int handle_id); -int prtSetColor(int handle_id, int font_color); -int prtGetColor(int handle_id); -int prtSetHPos(int handle_id, double x); -int prtSetVPos(int handle_id, double y); -int prtSetValue(int handle_id, char* attrname, ...); -int prtSetMargins(int handle_id, double t, double b, double l, double r); -pPrtBorder prtAllocBorder(int n_lines, double sep, double pad, ...); -int prtFreeBorder(pPrtBorder b); -pPrtImage prtCreateImageFromPNG(int (*read_fn)(), void* read_arg); -int prtFreeImage(pPrtImage i); -int prtImageSize(pPrtImage i); - -/*** Printing content functions ***/ -int prtWriteImage(int handle_id, pPrtImage imgdata, double x, double y, double width, double height, int flags); -int prtWriteString(int handle_id, char* str); -int prtWriteNL(int handle_id); -int prtWriteFF(int handle_id); - -/*** Print object creation functions ***/ -int prtAddObject(int handle_id, int obj_type, double x, double y, double width, double height, int flags, ...); -int prtSetObjectCallback(int handle_id, void* (*callback_fn)(), int is_pre); -int prtEndObject(int handle_id); - - -#endif /* defined _PRTMGMT_V3_H */ - diff --git a/centrallix/include/prtmgmt_v3/prtmgmt_v3.h b/centrallix/include/prtmgmt_v3/prtmgmt_v3.h index 40103a3a..cf263202 100644 --- a/centrallix/include/prtmgmt_v3/prtmgmt_v3.h +++ b/centrallix/include/prtmgmt_v3/prtmgmt_v3.h @@ -36,6 +36,7 @@ #include "cxlib/xarray.h" #include "cxlib/xhash.h" +#include "cxlib/xstring.h" #define PRT_XY_CORRECTION_FACTOR (72.0/120.0) diff --git a/centrallix/include/prtmgmt_v3/prtmgmt_v3_lm_text.h b/centrallix/include/prtmgmt_v3/prtmgmt_v3_lm_text.h index 280b41be..819dd42f 100644 --- a/centrallix/include/prtmgmt_v3/prtmgmt_v3_lm_text.h +++ b/centrallix/include/prtmgmt_v3/prtmgmt_v3_lm_text.h @@ -35,6 +35,7 @@ +#include "prtmgmt_v3/prtmgmt_v3.h" #define PRT_TEXTLM_F_RMSPACE PRT_OBJ_F_LMFLAG1 /* space was removed at end */ diff --git a/centrallix/report/prtmgmt_v3_fm_html.c b/centrallix/report/prtmgmt_v3_fm_html.c index 3204fc30..560c64e7 100644 --- a/centrallix/report/prtmgmt_v3_fm_html.c +++ b/centrallix/report/prtmgmt_v3_fm_html.c @@ -611,14 +611,31 @@ prt_htmlfm_Generate_r(pPrtHTMLfmInf context, pPrtObjStream obj) switch(obj->ObjType->TypeID) { case PRT_OBJ_T_STRING: + // don't print needless empty strings + if (strlen((char*)obj->Content) == 0) break; + prt_htmlfm_SetStyle(context, &(obj->TextStyle)); - if (obj->URL && !strchr(obj->URL, '"')) - { + if (obj->URL && !strchr(obj->URL, '"')) { prt_htmlfm_Output(context, "URL, -1); prt_htmlfm_Output(context, "\">", 2); - } - prt_htmlfm_OutputEncoded(context, (char*)obj->Content, -1); + } + if (context->Flags & PRT_HTMLFM_F_PAGINATED) { + prt_htmlfm_OutputEncoded(context, (char*)obj->Content, -1); + } else { + switch (obj->Justification) { + default: prt_htmlfm_OutputPrintf(context, "
"); + break; + case 1: prt_htmlfm_OutputPrintf(context, "
"); + break; + case 2: prt_htmlfm_OutputPrintf(context, "
"); + break; + case 3: prt_htmlfm_OutputPrintf(context, "
"); + break; + } + prt_htmlfm_Output(context, (char*)obj->Content, -1); + prt_htmlfm_Output(context, "
", -1); + } if (obj->URL && !strchr(obj->URL, '"')) { prt_htmlfm_Output(context, "
", 4); @@ -773,8 +790,8 @@ prt_htmlfm_Generate(void* context_v, pPrtObjStream page_obj) if (context->Flags & PRT_HTMLFM_F_PAGINATED) prt_htmlfm_OutputPrintf(context, PRT_HTMLFM_PAGEHEADER, (int)(page_obj->Width*PRT_HTMLFM_XPIXEL+0.001)+34); - /** Write a table to handle page margins **/ - prt_htmlfm_OutputPrintf(context, "
\n", (int)(page_obj->Width*PRT_HTMLFM_XPIXEL+0.001), + /** Write div to handle page margins **/ + prt_htmlfm_OutputPrintf(context, "
\n", (int)(page_obj->Width*PRT_HTMLFM_XPIXEL+0.001), (int)((page_obj->MarginTop+0.001)*PRT_HTMLFM_YPIXEL), (int)((page_obj->MarginRight+0.001)*PRT_HTMLFM_YPIXEL), (int)((page_obj->MarginBottom+0.001)*PRT_HTMLFM_YPIXEL), (int)((page_obj->MarginLeft+0.001)*PRT_HTMLFM_YPIXEL)); diff --git a/centrallix/report/prtmgmt_v3_fm_html_lm_text.c b/centrallix/report/prtmgmt_v3_fm_html_lm_text.c index 0ecc93aa..9bcacc2c 100644 --- a/centrallix/report/prtmgmt_v3_fm_html_lm_text.c +++ b/centrallix/report/prtmgmt_v3_fm_html_lm_text.c @@ -17,35 +17,35 @@ #include "cxlib/mtsession.h" /************************************************************************/ -/* Centrallix Application Server System */ -/* Centrallix Core */ -/* */ -/* Copyright (C) 1998-2003 LightSys Technology Services, Inc. */ -/* */ +/* Centrallix Application Server System */ +/* Centrallix Core */ +/* */ +/* Copyright (C) 1998-2003 LightSys Technology Services, Inc. */ +/* */ /* This program 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; either version 2 of the License, or */ -/* (at your option) any later version. */ -/* */ -/* This program 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. */ -/* */ +/* (at your option) any later version. */ +/* */ +/* This program 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, write to the Free Software */ -/* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA */ -/* 02111-1307 USA */ -/* */ +/* along with this program; if not, write to the Free Software */ +/* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA */ +/* 02111-1307 USA */ +/* */ /* A copy of the GNU General Public License has been included in this */ -/* distribution in the file "COPYING". */ -/* */ -/* Module: prtmgmt_v3_fm_html_lm_text.c */ -/* Author: Greg Beeley */ -/* Date: April 9th, 2003 */ -/* */ +/* distribution in the file "COPYING". */ +/* */ +/* Module: prtmgmt_v3_fm_html_lm_text.c */ +/* Author: Greg Beeley */ +/* Date: April 9th, 2003 */ +/* */ /* Description: This is the component of the HTML formatter which has */ -/* intelligence about textflow layout areas. */ +/* intelligence about textflow layout areas. */ /************************************************************************/ @@ -54,18 +54,17 @@ *** textflow area. ***/ int -prt_htmlfm_GenerateArea(pPrtHTMLfmInf context, pPrtObjStream area) - { - int n_xset; - double xset[PRT_HTMLFM_MAX_TABSTOP]; - double widths[PRT_HTMLFM_MAX_TABSTOP]; - pPrtObjStream scan, linetail, next_xset_obj; - int i,j,cur_xset,next_xset; - double w; - int last_needed_cols, cur_needs_cols, need_new_row, in_td, in_tr; - PrtTextStyle oldstyle; - char* justifytypes[] = { "left", "right", "center", "justify" }; - pPrtTextLMData lm_inf = (pPrtTextLMData)(area->LMData); +prt_htmlfm_GenerateArea(pPrtHTMLfmInf context, pPrtObjStream area) { + int n_xset; + double xset[PRT_HTMLFM_MAX_TABSTOP]; + double widths[PRT_HTMLFM_MAX_TABSTOP]; + pPrtObjStream scan, linetail, next_xset_obj; + int i,j,cur_xset,next_xset; + double w; + int last_needed_cols, cur_needs_cols, need_new_row, in_td, in_tr; + PrtTextStyle oldstyle; + char* justifytypes[] = { "left", "right", "center", "justify" }; + pPrtTextLMData lm_inf = (pPrtTextLMData)(area->LMData); /** First we need to scan the area looking for objects which ** were positioned with PRT_OBJ_F_XSET, so we can build a table @@ -73,23 +72,33 @@ prt_htmlfm_GenerateArea(pPrtHTMLfmInf context, pPrtObjStream area) **/ xset[0] = 0.0; n_xset = 1; - for(scan=area->ContentHead;scan;scan=scan->Next) - { - if (scan->Flags & PRT_OBJ_F_XSET) - { - for(i=0;i<=n_xset;i++) - { - if (i!=n_xset && xset[i] == scan->X) break; - if (n_xset < PRT_HTMLFM_MAX_TABSTOP && (i==n_xset || xset[i] > scan->X)) - { - for(j=n_xset;j>i;j--) xset[j] = xset[j-1]; - xset[i] = scan->X; - n_xset++; - break; + for (scan = area->ContentHead; scan; scan = scan->Next) { + if (scan->Flags & PRT_OBJ_F_XSET) { + for (i = 0; i <= n_xset; i++) { + if (i!=n_xset && xset[i] == scan->X) break; + if (n_xset < PRT_HTMLFM_MAX_TABSTOP && (i == n_xset || xset[i] > scan->X)) { + for (j = n_xset; j > i; j--) xset[j] = xset[j - 1]; + xset[i] = scan->X; + n_xset++; + break; + } } - } } - } + } + + prt_htmlfm_SaveStyle(context, &oldstyle); + + prt_htmlfm_OutputPrintf(context, "
", lm_inf->AreaBorder.Width[0], lm_inf->AreaBorder.Color[0]); + + for (scan = area->ContentHead; scan != NULL; scan = scan->Next) { + prt_htmlfm_Generate_r(context, scan); + } + + prt_htmlfm_Output(context, "
", -1); + + prt_htmlfm_ResetStyle(context, &oldstyle); + + return 0; /** Output the area prologue **/ prt_htmlfm_SaveStyle(context, &oldstyle); @@ -100,23 +109,23 @@ prt_htmlfm_GenerateArea(pPrtHTMLfmInf context, pPrtObjStream area) /** Issue column width info **/ for(i=0;iWidth - area->MarginLeft - area->MarginRight - xset[i]; - else + else widths[i] = xset[i+1] - xset[i]; - /** We could use relative 'n*' formatting; older browsers will interpret as pixel - ** width, newer ones as relative width, but doesn't seem to work right - ** with newer browsers. - **/ - prt_htmlfm_OutputPrintf(context,"
\n",(int)(widths[i]*PRT_HTMLFM_XPIXEL+0.0001)); - } + /** We could use relative 'n*' formatting; older browsers will interpret as pixel + ** width, newer ones as relative width, but doesn't seem to work right + ** with newer browsers. + **/ + prt_htmlfm_OutputPrintf(context,"\n",(int)(widths[i]*PRT_HTMLFM_XPIXEL+0.0001)); + } prt_htmlfm_Output(context,"",4); for(i=0;i",(int)(widths[i]*PRT_HTMLFM_XPIXEL+0.0001)); - } + { + prt_htmlfm_OutputPrintf(context,"",(int)(widths[i]*PRT_HTMLFM_XPIXEL+0.0001)); + } prt_htmlfm_Output(context,"\n",6); /** Walk the area's content **/ @@ -124,135 +133,135 @@ prt_htmlfm_GenerateArea(pPrtHTMLfmInf context, pPrtObjStream area) last_needed_cols = 0; in_tr = 0; while(scan) - { - /** Find the tail of this line, and figure out if we need to use columns **/ - cur_xset = 0; - linetail = scan; - cur_needs_cols = 0; - while(1) + { + /** Find the tail of this line, and figure out if we need to use columns **/ + cur_xset = 0; + linetail = scan; + cur_needs_cols = 0; + while(1) { if (linetail->Flags & PRT_OBJ_F_XSET) cur_needs_cols = 1; if ((linetail->Flags & (PRT_OBJ_F_SOFTNEWLINE | PRT_OBJ_F_NEWLINE)) || !linetail->Next) break; linetail = linetail->Next; } - need_new_row = (cur_needs_cols || last_needed_cols || scan->Justification != PRT_JUST_T_LEFT); - if (need_new_row) + need_new_row = (cur_needs_cols || last_needed_cols || scan->Justification != PRT_JUST_T_LEFT); + if (need_new_row) { if (in_td) - { - prt_htmlfm_EndStyle(context); - prt_htmlfm_Output(context,"", 5); - in_td = 0; - } + { + prt_htmlfm_EndStyle(context); + prt_htmlfm_Output(context,"", 5); + in_td = 0; + } if (in_tr) - { - prt_htmlfm_Output(context,"\n", 6); - in_tr = 0; - } + { + prt_htmlfm_Output(context,"\n", 6); + in_tr = 0; + } } - if (!in_tr) + if (!in_tr) { prt_htmlfm_Output(context,"", 4); in_tr = 1; } - /** Need to advance to first column/tabstop being used? **/ - if (cur_needs_cols && (scan->Flags & PRT_OBJ_F_XSET)) + /** Need to advance to first column/tabstop being used? **/ + if (cur_needs_cols && (scan->Flags & PRT_OBJ_F_XSET)) { for(cur_xset=0;cur_xsetX;) cur_xset++; if (cur_xset != 0) - { - if (in_tr && !in_td) + { + if (in_tr && !in_td) { prt_htmlfm_OutputPrintf(context, "", cur_xset, (int)(widths[cur_xset]*PRT_HTMLFM_XPIXEL+0.001)); } - } + } } - /** Ok, scan through the line now **/ - while(scan != linetail->Next) + /** Ok, scan through the line now **/ + while(scan != linetail->Next) { /** Find next xset location **/ if (cur_needs_cols) - { - next_xset_obj = scan->Next; - while(next_xset_obj != linetail->Next && !(next_xset_obj->Flags & PRT_OBJ_F_XSET)) next_xset_obj=next_xset_obj->Next; - if (next_xset_obj == linetail->Next) + { + next_xset_obj = scan->Next; + while(next_xset_obj != linetail->Next && !(next_xset_obj->Flags & PRT_OBJ_F_XSET)) next_xset_obj=next_xset_obj->Next; + if (next_xset_obj == linetail->Next) { next_xset_obj = NULL; next_xset = n_xset; } - else + else { for(next_xset=cur_xset;next_xsetX;) next_xset++; } - } + } else - { - next_xset_obj = NULL; - next_xset = n_xset; - } + { + next_xset_obj = NULL; + next_xset = n_xset; + } if (!in_td) - { - for(w=0.0,i=cur_xset;i", - justifytypes[scan->Justification], next_xset - cur_xset, - (int)(w*PRT_HTMLFM_XPIXEL+0.001)); - prt_htmlfm_InitStyle(context, &(scan->TextStyle)); - in_td = 1; - } + { + for(w=0.0,i=cur_xset;i", + justifytypes[scan->Justification], next_xset - cur_xset, + (int)(w*PRT_HTMLFM_XPIXEL+0.001)); + prt_htmlfm_InitStyle(context, &(scan->TextStyle)); + in_td = 1; + } /** print the child objects **/ w = 0.0; while((!next_xset_obj || scan != next_xset_obj->Next) && scan != linetail->Next) - { - prt_htmlfm_Generate_r(context, scan); - w += scan->Width; - scan = scan->Next; - } + { + prt_htmlfm_Generate_r(context, scan); + w += scan->Width; + scan = scan->Next; + } /** Nothing printed? **/ if (w == 0.0) - { - prt_htmlfm_Output(context, " ", 6); - } + { + prt_htmlfm_Output(context, " ", 6); + } /** Emit the closing td? **/ if (cur_needs_cols && in_td) - { - prt_htmlfm_EndStyle(context); - prt_htmlfm_Output(context, "", 5); - in_td = 0; - } + { + prt_htmlfm_EndStyle(context); + prt_htmlfm_Output(context, "", 5); + in_td = 0; + } else if (in_td && scan) - { - prt_htmlfm_Output(context,"
\n",5); - } + { + prt_htmlfm_Output(context,"
\n",5); + } cur_xset = next_xset; } - last_needed_cols = cur_needs_cols; - } + last_needed_cols = cur_needs_cols; + } /** Close the td and tr? **/ if (in_td) - { - prt_htmlfm_EndStyle(context); - prt_htmlfm_Output(context, "", 5); - in_td = 0; - } + { + prt_htmlfm_EndStyle(context); + prt_htmlfm_Output(context, "", 5); + in_td = 0; + } if (in_tr) - { - prt_htmlfm_Output(context,"
\n", 6); - in_tr = 0; - } + { + prt_htmlfm_Output(context,"\n", 6); + in_tr = 0; + } /** Output the area epilogue **/ prt_htmlfm_Output(context,"
 
\n", -1); prt_htmlfm_EndBorder(context, &(lm_inf->AreaBorder), area); prt_htmlfm_ResetStyle(context, &oldstyle); - return 0; - } + return 0; + } From bfe7c0b25b91d6e43b20b3aa1777f88770878580 Mon Sep 17 00:00:00 2001 From: "Kai D." Date: Tue, 4 Mar 2025 16:00:46 -0700 Subject: [PATCH 08/28] I don't know if this works, but it is based on the other image code that does work so it probably does work. --- centrallix/report/prtmgmt_v3_fm_html.c | 87 +++++++++++++------------- 1 file changed, 42 insertions(+), 45 deletions(-) diff --git a/centrallix/report/prtmgmt_v3_fm_html.c b/centrallix/report/prtmgmt_v3_fm_html.c index f38bf15f..9a1ac8fb 100644 --- a/centrallix/report/prtmgmt_v3_fm_html.c +++ b/centrallix/report/prtmgmt_v3_fm_html.c @@ -731,52 +731,49 @@ prt_htmlfm_Generate_r(pPrtHTMLfmInf context, pPrtObjStream obj) break; - case PRT_OBJ_T_SVG: - /** We need an image store location in order to handle these **/ - if (context->Session->ImageOpenFn) - { - id = PRT_HTMLFM.ImageID++; - w = obj->Width*PRT_HTMLFM_XPIXEL; - h = obj->Height*PRT_HTMLFM_YPIXEL; - if (w <= 0) w = 1; - if (h <= 0) h = 1; - path = (char*)nmMalloc(OBJSYS_MAX_PATH); - if (!path) - { - mssError(1, "PRT", "nmMalloc() failed\n"); - return -1; - } - rval = snprintf(path, OBJSYS_MAX_PATH, "%sprt_htmlfm_%8.8lX.svg", context->Session->ImageSysDir, id); - if (rval < 0 || rval >= OBJSYS_MAX_PATH) - { - mssError(1, "PRT", "Internal representation exceeded for image pathname\n"); - nmFree(path, OBJSYS_MAX_PATH); - return -1; - } - arg = context->Session->ImageOpenFn(context->Session->ImageContext, path, O_CREAT | O_WRONLY | O_TRUNC, 0600, "image/svg+xml"); - if (!arg) - { - mssError(0,"PRT","Failed to open new linked image '%s'",path); - nmFree(path, OBJSYS_MAX_PATH); - return -1; - } - prt_internal_WriteSvgToFile(context->Session->ImageWriteFn, arg, (pPrtSvg)(obj->Content), w, h); - context->Session->ImageCloseFn(arg); - nmFree(path, OBJSYS_MAX_PATH); - if (obj->URL && !strchr(obj->URL, '"')) - { - prt_htmlfm_Output(context, "URL, -1); - prt_htmlfm_Output(context, "\">", 2); - } - prt_htmlfm_OutputPrintf(context, "", - context->Session->ImageExtDir, id, w, h); - if (obj->URL && !strchr(obj->URL, '"')) - { - prt_htmlfm_Output(context, "", 4); + case PRT_OBJ_T_SVG: + if (context->Session->ImageOpenFn) { + w = obj->Width * PRT_HTMLFM_XPIXEL; + h = obj->Height * PRT_HTMLFM_YPIXEL; + if (w <= 0) w = 1; + if (h <= 0) h = 1; + + ImageBuffer imgBuf = { (char *)nmMalloc(MAX_IMAGE_SIZE), 0, MAX_IMAGE_SIZE }; + if (!imgBuf.buffer) { + mssError(1, "PRT", "nmMalloc() failed\n"); + return -1; + } + + // Capture SVG image into the buffer + prt_internal_WriteSvgToFile(ImageWriteFn, &imgBuf, (pPrtSvg)(obj->Content), w, h); + + // Encode SVG to Base64 + char *base64Image = base64_encode((unsigned char *)imgBuf.buffer, imgBuf.size); + nmFree(imgBuf.buffer, MAX_IMAGE_SIZE); + if (!base64Image) { + mssError(1, "PRT", "Base64 encoding failed\n"); + return -1; + } + + // Output the image as an embedded base64 SVG + if (obj->URL && !strchr(obj->URL, '"')) { + prt_htmlfm_Output(context, "URL, -1); + prt_htmlfm_Output(context, "\">", 2); + } + + prt_htmlfm_OutputPrintf(context, + "", + base64Image, w, h); + + if (obj->URL && !strchr(obj->URL, '"')) { + prt_htmlfm_Output(context, "", 4); + } + + nmFree(base64Image, strlen(base64Image) + 1); } - } - break; + break; + case PRT_OBJ_T_TABLE: prt_htmlfm_GenerateTable(context, obj); From 53b6a8a268540d0f13a92721e90c6ad2b19cc70e Mon Sep 17 00:00:00 2001 From: Brennen Puth - Kardia Date: Tue, 4 Mar 2025 17:42:13 -0700 Subject: [PATCH 09/28] Make the top level a div instead of a table --- centrallix/report/prtmgmt_v3_fm_html.c | 135 ++++++++++++++++--------- 1 file changed, 87 insertions(+), 48 deletions(-) diff --git a/centrallix/report/prtmgmt_v3_fm_html.c b/centrallix/report/prtmgmt_v3_fm_html.c index 44ed01d4..ac214ef1 100644 --- a/centrallix/report/prtmgmt_v3_fm_html.c +++ b/centrallix/report/prtmgmt_v3_fm_html.c @@ -885,58 +885,97 @@ prt_htmlfm_Generate(void* context_v, pPrtObjStream page_obj) } } - /** Write the layout table **/ - prt_htmlfm_Output(context, "\n", -1); - for(i = 0; i < n_cols; i++) - { - if (i == n_cols-1) - w = (page_obj->Width - page_obj->MarginLeft - page_obj->MarginRight - colpos[i])*PRT_HTMLFM_XPIXEL; - else - w = (colpos[i+1] - colpos[i]) * PRT_HTMLFM_XPIXEL; - prt_htmlfm_OutputPrintf(context, "\n", w); - } - - /** Generate the body of the page, by selectively walking the YPrev/YNext chain **/ - cur_row = 0; - cur_col = 0; - prt_htmlfm_Output(context, "", 4); - for(subobj=page_obj; subobj; subobj=subobj->YNext) - { - if (subobj->Parent == page_obj) - { - /** Next row? **/ - if (subobj->Y > rowpos[cur_row]) - { - while(subobj->Y > (rowpos[cur_row]+0.001) && cur_row < PRT_HTMLFM_MAXROWS-1) cur_row++; - prt_htmlfm_Output(context, "\n", 10); - cur_col = 0; - } - - /** Skip cols? **/ - if (subobj->X > colpos[cur_col]) - { - i=0; - while(subobj->X > (colpos[cur_col]+0.001) && cur_col < PRT_HTMLFM_MAXCOLS-1) + if(context->Flags & PRT_HTMLFM_F_PAGINATED) { + /** Write the layout table **/ + prt_htmlfm_Output(context, "
\n", -1); + for(i = 0; i < n_cols; i++) { - i++; - cur_col++; + if (i == n_cols-1) + w = (page_obj->Width - page_obj->MarginLeft - page_obj->MarginRight - colpos[i])*PRT_HTMLFM_XPIXEL; + else + w = (colpos[i+1] - colpos[i]) * PRT_HTMLFM_XPIXEL; + prt_htmlfm_OutputPrintf(context, "\n", w); } - prt_htmlfm_OutputPrintf(context, "", i); - } - /** Figure rowspan and colspan **/ - cs=1; - while(cur_col+cs < n_cols && (colpos[cur_col+cs]+0.001) < subobj->X + subobj->Width) cs++; - rs=1; - while(cur_row+rs < n_rows && (rowpos[cur_row+rs]+0.001) < subobj->Y + subobj->Height) rs++; - prt_htmlfm_OutputPrintf(context, "", 5); - cur_col += cs; - if (cur_col >= n_cols) cur_col = n_cols-1; + /** Generate the body of the page, by selectively walking the YPrev/YNext chain **/ + cur_row = 0; + cur_col = 0; + prt_htmlfm_Output(context, "", 4); + for(subobj=page_obj; subobj; subobj=subobj->YNext) + { + if (subobj->Parent == page_obj) + { + /** Next row? **/ + if (subobj->Y > rowpos[cur_row]) + { + while(subobj->Y > (rowpos[cur_row]+0.001) && cur_row < PRT_HTMLFM_MAXROWS-1) cur_row++; + prt_htmlfm_Output(context, "\n", 10); + cur_col = 0; + } + + /** Skip cols? **/ + if (subobj->X > colpos[cur_col]) + { + i=0; + while(subobj->X > (colpos[cur_col]+0.001) && cur_col < PRT_HTMLFM_MAXCOLS-1) + { + i++; + cur_col++; + } + prt_htmlfm_OutputPrintf(context, "", i); + } + + /** Figure rowspan and colspan **/ + cs=1; + while(cur_col+cs < n_cols && (colpos[cur_col+cs]+0.001) < subobj->X + subobj->Width) cs++; + rs=1; + while(cur_row+rs < n_rows && (rowpos[cur_row+rs]+0.001) < subobj->Y + subobj->Height) rs++; + prt_htmlfm_OutputPrintf(context, "", 5); + cur_col += cs; + if (cur_col >= n_cols) cur_col = n_cols-1; + } + } + prt_htmlfm_Output(context, "
 ", cs, rs); - prt_htmlfm_Generate_r(context, subobj); - prt_htmlfm_Output(context, "
 ", cs, rs); + prt_htmlfm_Generate_r(context, subobj); + prt_htmlfm_Output(context, "
\n", 14); + } else { + /** Write the layout table **/ + prt_htmlfm_Output(context, "
", -1); + + /** Generate the body of the page, by selectively walking the YPrev/YNext chain **/ + cur_row = 0; + cur_col = 0; + char* divFormat = "
"; + prt_htmlfm_Output(context, divFormat, -1); + for(subobj=page_obj; subobj; subobj=subobj->YNext) { + if (subobj->Parent == page_obj) { + /** Next row? **/ + if (subobj->Y > rowpos[cur_row]) { + while(subobj->Y > (rowpos[cur_row]+0.001) && cur_row < PRT_HTMLFM_MAXROWS-1) cur_row++; + prt_htmlfm_Output(context, "
\n", -1); + prt_htmlfm_Output(context, divFormat, -1); + cur_col = 0; + } + + /** Skip cols? **/ + if (subobj->X > colpos[cur_col]) { + prt_htmlfm_OutputPrintf(context, "

 

"); + } + + /** Figure rowspan and colspan **/ + cs = 1; + while(cur_col+cs < n_cols && (colpos[cur_col+cs]+0.001) < subobj->X + subobj->Width) cs++; + rs = 1; + while(cur_row+rs < n_rows && (rowpos[cur_row+rs]+0.001) < subobj->Y + subobj->Height) rs++; + prt_htmlfm_Generate_r(context, subobj); + cur_col += cs; + if (cur_col >= n_cols) { + cur_col = n_cols-1; + } + } } - } - prt_htmlfm_Output(context, "\n", 14); + prt_htmlfm_Output(context, "
\n", 14); + } /** Write the page footer **/ From 5e3ce45847bc5ffb7ee06c7dac3aae6b87f7b3f6 Mon Sep 17 00:00:00 2001 From: LMaster765 Date: Tue, 4 Mar 2025 17:43:16 -0700 Subject: [PATCH 10/28] Improve string generation --- centrallix/report/prtmgmt_v3_fm_html.c | 31 +++++++++++++++++-- .../report/prtmgmt_v3_fm_html_lm_text.c | 17 +++++++++- 2 files changed, 45 insertions(+), 3 deletions(-) diff --git a/centrallix/report/prtmgmt_v3_fm_html.c b/centrallix/report/prtmgmt_v3_fm_html.c index 5b36c81d..5b4c5222 100644 --- a/centrallix/report/prtmgmt_v3_fm_html.c +++ b/centrallix/report/prtmgmt_v3_fm_html.c @@ -640,6 +640,13 @@ prt_htmlfm_Generate_r(pPrtHTMLfmInf context, pPrtObjStream obj) unsigned long id; int rval; + printf("Generate_r: %s\n", obj->ObjType->TypeName); + if (obj->ObjType->TypeID == PRT_OBJ_T_STRING) { + printf(" C: \"%s\"\n", obj->Content); + printf(" LF: \"%d\"\n", obj->Flags & (PRT_OBJ_F_NEWLINE | PRT_OBJ_F_SOFTNEWLINE)); + } + + /** Check recursion **/ if (thExcessiveRecursion()) { @@ -652,7 +659,9 @@ prt_htmlfm_Generate_r(pPrtHTMLfmInf context, pPrtObjStream obj) { case PRT_OBJ_T_STRING: // don't print needless empty strings - if (strlen((char*)obj->Content) == 0) break; + // if (strlen((char*)obj->Content) == 0) { + // break; + // } prt_htmlfm_SetStyle(context, &(obj->TextStyle)); if (obj->URL && !strchr(obj->URL, '"')) { @@ -673,7 +682,25 @@ prt_htmlfm_Generate_r(pPrtHTMLfmInf context, pPrtObjStream obj) case 3: prt_htmlfm_OutputPrintf(context, "
"); break; } + // printf("TEST: %s\n", (char*)obj->Content); prt_htmlfm_Output(context, (char*)obj->Content, -1); + + if (obj->Justification == 3) { + while (obj->Next && obj->Next->ObjType->TypeID == PRT_OBJ_T_STRING && obj->Next->Justification == 3) { + + if (obj->Flags & PRT_OBJ_F_SOFTNEWLINE) { + prt_htmlfm_Output(context, " ", -1); + } + + if (obj->Flags & PRT_OBJ_F_NEWLINE) { + prt_htmlfm_Output(context, "
", -1); + } + + obj = obj->Next; + prt_htmlfm_Output(context, (char*)obj->Content, -1); + } + } + prt_htmlfm_Output(context, "
", -1); } if (obj->URL && !strchr(obj->URL, '"')) @@ -828,7 +855,7 @@ prt_htmlfm_Generate(void* context_v, pPrtObjStream page_obj) prt_htmlfm_OutputPrintf(context, PRT_HTMLFM_PAGEHEADER, (int)(page_obj->Width*PRT_HTMLFM_XPIXEL+0.001)+34); /** Write div to handle page margins **/ - prt_htmlfm_OutputPrintf(context, "
\n", (int)(page_obj->Width*PRT_HTMLFM_XPIXEL+0.001), + prt_htmlfm_OutputPrintf(context, "
\n", (int)(page_obj->Width*PRT_HTMLFM_XPIXEL+0.001), (int)((page_obj->MarginTop+0.001)*PRT_HTMLFM_YPIXEL), (int)((page_obj->MarginRight+0.001)*PRT_HTMLFM_YPIXEL), (int)((page_obj->MarginBottom+0.001)*PRT_HTMLFM_YPIXEL), (int)((page_obj->MarginLeft+0.001)*PRT_HTMLFM_YPIXEL)); diff --git a/centrallix/report/prtmgmt_v3_fm_html_lm_text.c b/centrallix/report/prtmgmt_v3_fm_html_lm_text.c index 9bcacc2c..9a15317f 100644 --- a/centrallix/report/prtmgmt_v3_fm_html_lm_text.c +++ b/centrallix/report/prtmgmt_v3_fm_html_lm_text.c @@ -91,7 +91,22 @@ prt_htmlfm_GenerateArea(pPrtHTMLfmInf context, pPrtObjStream area) { prt_htmlfm_OutputPrintf(context, "
", lm_inf->AreaBorder.Width[0], lm_inf->AreaBorder.Color[0]); for (scan = area->ContentHead; scan != NULL; scan = scan->Next) { - prt_htmlfm_Generate_r(context, scan); + + prt_htmlfm_Output(context, "
", -1); + + prt_htmlfm_Generate_r(context, scan); + + // justified text is split into individual objects... skip to next actual object + while (scan->ObjType->TypeID == PRT_OBJ_T_STRING + && scan->Justification == 3 + && scan->Next + && scan->Next->ObjType->TypeID == PRT_OBJ_T_STRING + && scan->Next->Justification == 3) { + scan = scan->Next; + } + + prt_htmlfm_Output(context, "
", -1); + } prt_htmlfm_Output(context, "
", -1); From 06d3ebc98b9cf4322f0c5313c471c4a792f584b3 Mon Sep 17 00:00:00 2001 From: LMaster765 Date: Tue, 4 Mar 2025 18:16:56 -0700 Subject: [PATCH 11/28] Fix BOLD --- centrallix/report/prtmgmt_v3_fm_html.c | 6 +++--- centrallix/report/prtmgmt_v3_fm_html_lm_text.c | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/centrallix/report/prtmgmt_v3_fm_html.c b/centrallix/report/prtmgmt_v3_fm_html.c index dd96a9cc..4a15e94f 100644 --- a/centrallix/report/prtmgmt_v3_fm_html.c +++ b/centrallix/report/prtmgmt_v3_fm_html.c @@ -707,6 +707,7 @@ prt_htmlfm_Generate_r(pPrtHTMLfmInf context, pPrtObjStream obj) { prt_htmlfm_Output(context, "", 4); } + prt_htmlfm_EndStyle(context); break; case PRT_OBJ_T_AREA: @@ -852,7 +853,7 @@ prt_htmlfm_Generate(void* context_v, pPrtObjStream page_obj) prt_htmlfm_OutputPrintf(context, PRT_HTMLFM_PAGEHEADER, (int)(page_obj->Width*PRT_HTMLFM_XPIXEL+0.001)+34); /** Write div to handle page margins **/ - prt_htmlfm_OutputPrintf(context, "
\n", (int)(page_obj->Width*PRT_HTMLFM_XPIXEL+0.001), + prt_htmlfm_OutputPrintf(context, "
\n", (int)(page_obj->Width*PRT_HTMLFM_XPIXEL+0.001), (int)((page_obj->MarginTop+0.001)*PRT_HTMLFM_YPIXEL), (int)((page_obj->MarginRight+0.001)*PRT_HTMLFM_YPIXEL), (int)((page_obj->MarginBottom+0.001)*PRT_HTMLFM_YPIXEL), (int)((page_obj->MarginLeft+0.001)*PRT_HTMLFM_YPIXEL)); @@ -967,7 +968,6 @@ prt_htmlfm_Generate(void* context_v, pPrtObjStream page_obj) prt_htmlfm_Output(context, "\n", 14); } else { /** Write the layout table **/ - prt_htmlfm_Output(context, "
", -1); /** Generate the body of the page, by selectively walking the YPrev/YNext chain **/ cur_row = 0; @@ -1001,7 +1001,7 @@ prt_htmlfm_Generate(void* context_v, pPrtObjStream page_obj) } } } - prt_htmlfm_Output(context, "
\n", 14); + prt_htmlfm_Output(context, "
\n", -1); } diff --git a/centrallix/report/prtmgmt_v3_fm_html_lm_text.c b/centrallix/report/prtmgmt_v3_fm_html_lm_text.c index 9a15317f..ce8f8030 100644 --- a/centrallix/report/prtmgmt_v3_fm_html_lm_text.c +++ b/centrallix/report/prtmgmt_v3_fm_html_lm_text.c @@ -92,7 +92,7 @@ prt_htmlfm_GenerateArea(pPrtHTMLfmInf context, pPrtObjStream area) { for (scan = area->ContentHead; scan != NULL; scan = scan->Next) { - prt_htmlfm_Output(context, "
", -1); + // prt_htmlfm_Output(context, "
", -1); prt_htmlfm_Generate_r(context, scan); @@ -105,7 +105,7 @@ prt_htmlfm_GenerateArea(pPrtHTMLfmInf context, pPrtObjStream area) { scan = scan->Next; } - prt_htmlfm_Output(context, "
", -1); + // prt_htmlfm_Output(context, "
", -1); } From fafbbbc1fcfe117e10060083f27e283d2b2aef96 Mon Sep 17 00:00:00 2001 From: brennenputh Date: Thu, 6 Mar 2025 10:24:03 -0700 Subject: [PATCH 12/28] Clean up root div formatting logic --- centrallix/report/prtmgmt_v3_fm_html.c | 40 +++++++------------------- 1 file changed, 11 insertions(+), 29 deletions(-) diff --git a/centrallix/report/prtmgmt_v3_fm_html.c b/centrallix/report/prtmgmt_v3_fm_html.c index 4a15e94f..adfec3c1 100644 --- a/centrallix/report/prtmgmt_v3_fm_html.c +++ b/centrallix/report/prtmgmt_v3_fm_html.c @@ -845,7 +845,6 @@ prt_htmlfm_Generate(void* context_v, pPrtObjStream page_obj) int found; int i; int w; - int cur_row, cur_col; int rs,cs; /** Write the page header **/ @@ -926,8 +925,8 @@ prt_htmlfm_Generate(void* context_v, pPrtObjStream page_obj) } /** Generate the body of the page, by selectively walking the YPrev/YNext chain **/ - cur_row = 0; - cur_col = 0; + int cur_row = 0; + int cur_col = 0; prt_htmlfm_Output(context, "", 4); for(subobj=page_obj; subobj; subobj=subobj->YNext) { @@ -967,41 +966,24 @@ prt_htmlfm_Generate(void* context_v, pPrtObjStream page_obj) } prt_htmlfm_Output(context, "\n", 14); } else { - /** Write the layout table **/ - - /** Generate the body of the page, by selectively walking the YPrev/YNext chain **/ - cur_row = 0; - cur_col = 0; + double cur_row = -1; char* divFormat = "
"; - prt_htmlfm_Output(context, divFormat, -1); for(subobj=page_obj; subobj; subobj=subobj->YNext) { if (subobj->Parent == page_obj) { - /** Next row? **/ - if (subobj->Y > rowpos[cur_row]) { - while(subobj->Y > (rowpos[cur_row]+0.001) && cur_row < PRT_HTMLFM_MAXROWS-1) cur_row++; - prt_htmlfm_Output(context, "
\n", -1); + // Move to next row. + if (subobj->Y > cur_row) { + // Only put in a div ender if this is a new div. + if(cur_row != -1) { + prt_htmlfm_Output(context, "
\n", -1); + } prt_htmlfm_Output(context, divFormat, -1); - cur_col = 0; + cur_row = subobj->Y; } - /** Skip cols? **/ - if (subobj->X > colpos[cur_col]) { - prt_htmlfm_OutputPrintf(context, "

 

"); - } - - /** Figure rowspan and colspan **/ - cs = 1; - while(cur_col+cs < n_cols && (colpos[cur_col+cs]+0.001) < subobj->X + subobj->Width) cs++; - rs = 1; - while(cur_row+rs < n_rows && (rowpos[cur_row+rs]+0.001) < subobj->Y + subobj->Height) rs++; + // No need to worry about columns because of flexbox. prt_htmlfm_Generate_r(context, subobj); - cur_col += cs; - if (cur_col >= n_cols) { - cur_col = n_cols-1; - } } } - prt_htmlfm_Output(context, "
\n", -1); } From 871b9bc2ec13337d8aa5e27589176d476a373995 Mon Sep 17 00:00:00 2001 From: LMaster765 Date: Thu, 6 Mar 2025 10:51:07 -0700 Subject: [PATCH 13/28] Add getfont method to html formatting --- centrallix/report/prtmgmt_v3_fm_html.c | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/centrallix/report/prtmgmt_v3_fm_html.c b/centrallix/report/prtmgmt_v3_fm_html.c index adfec3c1..3323e937 100644 --- a/centrallix/report/prtmgmt_v3_fm_html.c +++ b/centrallix/report/prtmgmt_v3_fm_html.c @@ -395,13 +395,25 @@ prt_htmlfm_Close(void* context_v) } +/*** prt_htmlfm_GetFont() - get the text style's font + ***/ +const char * +prt_htmlfm_GetFont(pPrtTextStyle style) { + const char* fonts[3] = { "Courier New,Courier,fixed", "Arial,Helvetica,MS Sans Serif", "Times New Roman,Times,MS Serif"}; + + /*htmlfontsize = style->FontSize - PRT_HTMLFM_FONTSIZE_DEFAULT + PRT_HTMLFM_FONTSIZE_OFFSET;*/ + int fontid = style->FontID - 1; + if (fontid < 0 || fontid > 2) fontid = 0; + return fonts[fontid]; +} + + /*** prt_htmlfm_SetStyle() - output the html to change the text style ***/ int prt_htmlfm_SetStyle(pPrtHTMLfmInf context, pPrtTextStyle style) { - char* fonts[3] = { "Courier New,Courier,fixed", "Arial,Helvetica,MS Sans Serif", "Times New Roman,Times,MS Serif"}; - int htmlfontsize, fontid; + int htmlfontsize; char stylebuf[128]; int boldchanged, italicchanged, underlinechanged, fontchanged; int i; @@ -415,9 +427,6 @@ prt_htmlfm_SetStyle(pPrtHTMLfmInf context, pPrtTextStyle style) break; } } - /*htmlfontsize = style->FontSize - PRT_HTMLFM_FONTSIZE_DEFAULT + PRT_HTMLFM_FONTSIZE_OFFSET;*/ - fontid = style->FontID - 1; - if (fontid < 0 || fontid > 2) fontid = 0; /** Close out current style settings? **/ boldchanged = (style->Attr ^ context->CurStyle.Attr) & PRT_OBJ_A_BOLD; @@ -454,7 +463,7 @@ prt_htmlfm_SetStyle(pPrtHTMLfmInf context, pPrtTextStyle style) if (context->InitStyle || fontchanged) { snprintf(stylebuf, sizeof(stylebuf), "", - fonts[fontid], style->Color, htmlfontsize); + prt_htmlfm_GetFont(style), style->Color, htmlfontsize); prt_htmlfm_Output(context, stylebuf, -1); } if (style->Attr & PRT_OBJ_A_UNDERLINE) prt_htmlfm_Output(context, "", 3); From b5fb520dd1a113b128fbafcaacac97e484e1253f Mon Sep 17 00:00:00 2001 From: LMaster765 Date: Thu, 6 Mar 2025 10:58:30 -0700 Subject: [PATCH 14/28] Improve Area object structure for html --- centrallix/report/prtmgmt_v3_fm_html.c | 45 +++++++++++++++---- .../report/prtmgmt_v3_fm_html_lm_text.c | 23 ++++++++-- 2 files changed, 57 insertions(+), 11 deletions(-) diff --git a/centrallix/report/prtmgmt_v3_fm_html.c b/centrallix/report/prtmgmt_v3_fm_html.c index 3323e937..60c79c39 100644 --- a/centrallix/report/prtmgmt_v3_fm_html.c +++ b/centrallix/report/prtmgmt_v3_fm_html.c @@ -652,8 +652,8 @@ prt_htmlfm_Generate_r(pPrtHTMLfmInf context, pPrtObjStream obj) printf("Generate_r: %s\n", obj->ObjType->TypeName); if (obj->ObjType->TypeID == PRT_OBJ_T_STRING) { printf(" C: \"%s\"\n", obj->Content); - printf(" LF: \"%d\"\n", obj->Flags & (PRT_OBJ_F_NEWLINE | PRT_OBJ_F_SOFTNEWLINE)); } + printf(" Font: \"%d\"\n", obj->TextStyle.FontID); /** Check recursion **/ @@ -672,7 +672,7 @@ prt_htmlfm_Generate_r(pPrtHTMLfmInf context, pPrtObjStream obj) // break; // } - prt_htmlfm_SetStyle(context, &(obj->TextStyle)); + // prt_htmlfm_SetStyle(context, &(obj->TextStyle)); if (obj->URL && !strchr(obj->URL, '"')) { prt_htmlfm_Output(context, "URL, -1); @@ -682,18 +682,37 @@ prt_htmlfm_Generate_r(pPrtHTMLfmInf context, pPrtObjStream obj) prt_htmlfm_OutputEncoded(context, (char*)obj->Content, -1); } else { switch (obj->Justification) { - default: prt_htmlfm_OutputPrintf(context, "
"); + default: prt_htmlfm_Output(context, "
"); + case 1: prt_htmlfm_Output(context, "
"); + case 2: prt_htmlfm_Output(context, "
"); + case 3: prt_htmlfm_Output(context, "
TextStyle), obj->TextStyle.Color, (int) obj->TextStyle.FontSize); + prt_htmlfm_Output(context, stylebuf, -1); + prt_htmlfm_Output(context, " white-space: pre-wrap;\">", -1); + + int attr = obj->TextStyle.Attr; + + if (attr & PRT_OBJ_A_BOLD) { + prt_htmlfm_Output(context, "", -1); + } + if (attr & PRT_OBJ_A_ITALIC) { + prt_htmlfm_Output(context, "", -1); + } + if (attr & PRT_OBJ_A_UNDERLINE) { + prt_htmlfm_Output(context, "", -1); + } + // printf("TEST: %s\n", (char*)obj->Content); prt_htmlfm_Output(context, (char*)obj->Content, -1); - + if (obj->Justification == 3) { while (obj->Next && obj->Next->ObjType->TypeID == PRT_OBJ_T_STRING && obj->Next->Justification == 3) { @@ -710,13 +729,23 @@ prt_htmlfm_Generate_r(pPrtHTMLfmInf context, pPrtObjStream obj) } } + if (attr & PRT_OBJ_A_UNDERLINE) { + prt_htmlfm_Output(context, "", -1); + } + if (attr & PRT_OBJ_A_ITALIC) { + prt_htmlfm_Output(context, "", -1); + } + if (attr & PRT_OBJ_A_BOLD) { + prt_htmlfm_Output(context, "", -1); + } + prt_htmlfm_Output(context, "
", -1); } if (obj->URL && !strchr(obj->URL, '"')) { prt_htmlfm_Output(context, "
", 4); } - prt_htmlfm_EndStyle(context); + // prt_htmlfm_EndStyle(context); break; case PRT_OBJ_T_AREA: diff --git a/centrallix/report/prtmgmt_v3_fm_html_lm_text.c b/centrallix/report/prtmgmt_v3_fm_html_lm_text.c index ce8f8030..b8de6bd7 100644 --- a/centrallix/report/prtmgmt_v3_fm_html_lm_text.c +++ b/centrallix/report/prtmgmt_v3_fm_html_lm_text.c @@ -90,10 +90,28 @@ prt_htmlfm_GenerateArea(pPrtHTMLfmInf context, pPrtObjStream area) { prt_htmlfm_OutputPrintf(context, "
", lm_inf->AreaBorder.Width[0], lm_inf->AreaBorder.Color[0]); + prt_htmlfm_Output(context, "
", -1); + + prt_htmlfm_Output(context, "
", -1); + + for (scan = area->ContentHead; scan != NULL; scan = scan->Next) { + + if (scan->Flags & PRT_OBJ_F_NEWLINE) { + prt_htmlfm_Output(context, "
", -1); + prt_htmlfm_Output(context, "
", -1); + prt_htmlfm_Output(context, "
", -1); + prt_htmlfm_Output(context, "
", -1); + } // prt_htmlfm_Output(context, "
", -1); + if (scan->Flags & PRT_OBJ_F_XSET && scan->X) { + prt_htmlfm_Output(context, "
", -1); + prt_htmlfm_OutputPrintf(context, "
", + (int)(scan->X * PRT_HTMLFM_XPIXEL + 0.0001), (int)(scan->Y * PRT_HTMLFM_YPIXEL + 0.0001)); + } + prt_htmlfm_Generate_r(context, scan); // justified text is split into individual objects... skip to next actual object @@ -104,11 +122,10 @@ prt_htmlfm_GenerateArea(pPrtHTMLfmInf context, pPrtObjStream area) { && scan->Next->Justification == 3) { scan = scan->Next; } - - // prt_htmlfm_Output(context, "
", -1); - } + prt_htmlfm_Output(context, "
", -1); + prt_htmlfm_Output(context, "
", -1); prt_htmlfm_Output(context, "
", -1); prt_htmlfm_ResetStyle(context, &oldstyle); From 30582d01199f9b94d6b52d3e06e0ef1a7f8b6b46 Mon Sep 17 00:00:00 2001 From: brennenputh Date: Thu, 6 Mar 2025 11:30:32 -0700 Subject: [PATCH 15/28] Clean up formatting and move variables to be locally declared --- centrallix/report/prtmgmt_v3_fm_html.c | 304 ++++++++++--------------- 1 file changed, 116 insertions(+), 188 deletions(-) diff --git a/centrallix/report/prtmgmt_v3_fm_html.c b/centrallix/report/prtmgmt_v3_fm_html.c index adfec3c1..cf1bee89 100644 --- a/centrallix/report/prtmgmt_v3_fm_html.c +++ b/centrallix/report/prtmgmt_v3_fm_html.c @@ -594,9 +594,6 @@ prt_htmlfm_EndBorder(pPrtHTMLfmInf context, pPrtBorder border, pPrtObjStream obj return 0; } - - - /** Gets size of image file */ int ImageWriteFn(void *arg, const void *data, size_t len) { ImageBuffer *imgBuf = (ImageBuffer *)arg; @@ -608,10 +605,10 @@ int ImageWriteFn(void *arg, const void *data, size_t len) { return len; } -const char b64_table[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; /** Encodes a char* input to base64 */ char *base64_encode(const unsigned char *input, size_t len) { + const char b64_table[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; size_t out_len = 4 * ((len + 2) / 3); char *output = (char *)nmMalloc(out_len + 1); if (!output) return NULL; @@ -632,31 +629,21 @@ char *base64_encode(const unsigned char *input, size_t len) { *** of page generation. ***/ int -prt_htmlfm_Generate_r(pPrtHTMLfmInf context, pPrtObjStream obj) - { - char* path; - void* arg; - int w,h; - unsigned long id; - int rval; - +prt_htmlfm_Generate_r(pPrtHTMLfmInf context, pPrtObjStream obj) { printf("Generate_r: %s\n", obj->ObjType->TypeName); if (obj->ObjType->TypeID == PRT_OBJ_T_STRING) { printf(" C: \"%s\"\n", obj->Content); printf(" LF: \"%d\"\n", obj->Flags & (PRT_OBJ_F_NEWLINE | PRT_OBJ_F_SOFTNEWLINE)); } - /** Check recursion **/ - if (thExcessiveRecursion()) - { + if (thExcessiveRecursion()) { mssError(1,"PRT","Could not generate page: resource exhaustion occurred"); return -1; - } + } /** Select the type of object we're formatting **/ - switch(obj->ObjType->TypeID) - { + switch(obj->ObjType->TypeID) { case PRT_OBJ_T_STRING: // don't print needless empty strings // if (strlen((char*)obj->Content) == 0) { @@ -711,32 +698,33 @@ prt_htmlfm_Generate_r(pPrtHTMLfmInf context, pPrtObjStream obj) break; case PRT_OBJ_T_AREA: - prt_htmlfm_GenerateArea(context, obj); - break; + prt_htmlfm_GenerateArea(context, obj); + break; case PRT_OBJ_T_SECTION: - prt_htmlfm_GenerateMultiCol(context, obj); - break; + prt_htmlfm_GenerateMultiCol(context, obj); + break; case PRT_OBJ_T_RECT: - /** Don't output rectangles that are container decorations added - ** by finalize routines in the layout managers. We really need a - ** better way to tell this than the conditional below. - **/ - if (obj->Parent && obj->Parent->ObjType->TypeID != PRT_OBJ_T_SECTION && !(obj->Flags & PRT_OBJ_F_MARGINRELEASE)) - { - w = obj->Width*PRT_HTMLFM_XPIXEL; - h = obj->Height*PRT_HTMLFM_YPIXEL; - prt_htmlfm_OutputPrintf(context, "
\n", - obj->TextStyle.Color, w, h); - } - break; + /** Don't output rectangles that are container decorations added + ** by finalize routines in the layout managers. We really need a + ** better way to tell this than the conditional below. + **/ + if (obj->Parent && obj->Parent->ObjType->TypeID != PRT_OBJ_T_SECTION && !(obj->Flags & PRT_OBJ_F_MARGINRELEASE)) + { + int w = obj->Width*PRT_HTMLFM_XPIXEL; + int h = obj->Height*PRT_HTMLFM_YPIXEL; + prt_htmlfm_OutputPrintf(context, "
\n", + obj->TextStyle.Color, w, h); + } + break; /* Encodes image to base64 and writes to HTML */ case PRT_OBJ_T_IMAGE: + case PRT_OBJ_T_SVG: if (context->Session->ImageOpenFn) { - w = obj->Width * PRT_HTMLFM_XPIXEL; - h = obj->Height * PRT_HTMLFM_YPIXEL; + int w = obj->Width * PRT_HTMLFM_XPIXEL; + int h = obj->Height * PRT_HTMLFM_YPIXEL; if (w <= 0) w = 1; if (h <= 0) h = 1; @@ -764,8 +752,15 @@ prt_htmlfm_Generate_r(pPrtHTMLfmInf context, pPrtObjStream obj) prt_htmlfm_Output(context, "\">", 2); } - prt_htmlfm_OutputPrintf(context, "", - base64Image, w, h); + // Justification: All cases in which it is not an image, it is a SVG. + if(obj->ObjType->TypeID == PRT_OBJ_T_IMAGE) { + prt_htmlfm_OutputPrintf(context, "", + base64Image, w, h); + } else { + prt_htmlfm_OutputPrintf(context, + "", + base64Image, w, h); + } if (obj->URL && !strchr(obj->URL, '"')) { prt_htmlfm_Output(context, "", 4); @@ -775,58 +770,13 @@ prt_htmlfm_Generate_r(pPrtHTMLfmInf context, pPrtObjStream obj) } break; - - case PRT_OBJ_T_SVG: - if (context->Session->ImageOpenFn) { - w = obj->Width * PRT_HTMLFM_XPIXEL; - h = obj->Height * PRT_HTMLFM_YPIXEL; - if (w <= 0) w = 1; - if (h <= 0) h = 1; - - ImageBuffer imgBuf = { (char *)nmMalloc(MAX_IMAGE_SIZE), 0, MAX_IMAGE_SIZE }; - if (!imgBuf.buffer) { - mssError(1, "PRT", "nmMalloc() failed\n"); - return -1; - } - - // Capture SVG image into the buffer - prt_internal_WriteSvgToFile(ImageWriteFn, &imgBuf, (pPrtSvg)(obj->Content), w, h); - - // Encode SVG to Base64 - char *base64Image = base64_encode((unsigned char *)imgBuf.buffer, imgBuf.size); - nmFree(imgBuf.buffer, MAX_IMAGE_SIZE); - if (!base64Image) { - mssError(1, "PRT", "Base64 encoding failed\n"); - return -1; - } - - // Output the image as an embedded base64 SVG - if (obj->URL && !strchr(obj->URL, '"')) { - prt_htmlfm_Output(context, "URL, -1); - prt_htmlfm_Output(context, "\">", 2); - } - - prt_htmlfm_OutputPrintf(context, - "", - base64Image, w, h); - - if (obj->URL && !strchr(obj->URL, '"')) { - prt_htmlfm_Output(context, "", 4); - } - - nmFree(base64Image, strlen(base64Image) + 1); - } - break; - - case PRT_OBJ_T_TABLE: - prt_htmlfm_GenerateTable(context, obj); - break; - } + prt_htmlfm_GenerateTable(context, obj); + break; + } return 0; - } +} /*** prt_htmlfm_Generate() - generate the html for the page. Basically, @@ -835,21 +785,15 @@ prt_htmlfm_Generate_r(pPrtHTMLfmInf context, pPrtObjStream obj) *** overlapping objects on a page. ***/ int -prt_htmlfm_Generate(void* context_v, pPrtObjStream page_obj) - { +prt_htmlfm_Generate(void* context_v, pPrtObjStream page_obj) { pPrtHTMLfmInf context = (pPrtHTMLfmInf)context_v; - pPrtObjStream subobj; double colpos[PRT_HTMLFM_MAXCOLS]; double rowpos[PRT_HTMLFM_MAXROWS]; - int n_cols=0, n_rows=0; - int found; - int i; - int w; - int rs,cs; /** Write the page header **/ - if (context->Flags & PRT_HTMLFM_F_PAGINATED) + if (context->Flags & PRT_HTMLFM_F_PAGINATED) { prt_htmlfm_OutputPrintf(context, PRT_HTMLFM_PAGEHEADER, (int)(page_obj->Width*PRT_HTMLFM_XPIXEL+0.001)+34); + } /** Write div to handle page margins **/ prt_htmlfm_OutputPrintf(context, "
\n", (int)(page_obj->Width*PRT_HTMLFM_XPIXEL+0.001), @@ -860,115 +804,101 @@ prt_htmlfm_Generate(void* context_v, pPrtObjStream page_obj) ** "columns" and "rows" we need to put in the "table" used for layout ** purposes. **/ - for(subobj=page_obj->ContentHead; subobj; subobj=subobj->Next) - { - if (n_cols < PRT_HTMLFM_MAXCOLS) - { - /** Search for the X position in the 'colpos' list **/ - found = n_cols; - for(i=0;iX == colpos[i]) - { - found = -1; - break; + int n_cols=0, n_rows=0; + for(pPrtObjStream subobj=page_obj->ContentHead; subobj; subobj=subobj->Next) { + if (n_cols < PRT_HTMLFM_MAXCOLS) { + /** Search for the X position in the 'colpos' list **/ + int found = n_cols; + for(int i = 0; i < n_cols; i++) { + if (subobj->X == colpos[i]) { + found = -1; + break; + } + if (subobj->X < colpos[i]) { + found=i; + break; + } } - if (subobj->X < colpos[i]) - { - found=i; - break; + if (found != -1) { + for(int i = n_cols-1 ; i >= found; i--) colpos[i+1] = colpos[i]; + colpos[found] = subobj->X; + n_cols++; } - } - if (found != -1) - { - for(i=n_cols-1;i>=found;i--) colpos[i+1] = colpos[i]; - colpos[found] = subobj->X; - n_cols++; - } } - if (n_rows < PRT_HTMLFM_MAXROWS) - { - /** Search for the Y position in the 'rowpos' list **/ - found = n_rows; - for(i=0;iY == rowpos[i]) - { - found = -1; - break; + + if (n_rows < PRT_HTMLFM_MAXROWS) { + /** Search for the Y position in the 'rowpos' list **/ + int found = n_rows; + for(int i = 0; i < n_rows; i++) { + if (subobj->Y == rowpos[i]) { + found = -1; + break; + } + if (subobj->Y < rowpos[i]) { + found=i; + break; + } } - if (subobj->Y < rowpos[i]) - { - found=i; - break; + if (found != -1) { + for(int i = n_rows-1; i>=found; i--) rowpos[i+1] = rowpos[i]; + rowpos[found] = subobj->Y; + n_rows++; } - } - if (found != -1) - { - for(i=n_rows-1;i>=found;i--) rowpos[i+1] = rowpos[i]; - rowpos[found] = subobj->Y; - n_rows++; - } } - } + } if(context->Flags & PRT_HTMLFM_F_PAGINATED) { /** Write the layout table **/ prt_htmlfm_Output(context, "\n", -1); - for(i = 0; i < n_cols; i++) - { - if (i == n_cols-1) - w = (page_obj->Width - page_obj->MarginLeft - page_obj->MarginRight - colpos[i])*PRT_HTMLFM_XPIXEL; - else - w = (colpos[i+1] - colpos[i]) * PRT_HTMLFM_XPIXEL; - prt_htmlfm_OutputPrintf(context, "\n", w); + for(int i = 0; i < n_cols; i++) { + int w; + if (i == n_cols-1) { + w = (page_obj->Width - page_obj->MarginLeft - page_obj->MarginRight - colpos[i])*PRT_HTMLFM_XPIXEL; + } else { + w = (colpos[i+1] - colpos[i]) * PRT_HTMLFM_XPIXEL; } + prt_htmlfm_OutputPrintf(context, "\n", w); + } /** Generate the body of the page, by selectively walking the YPrev/YNext chain **/ int cur_row = 0; int cur_col = 0; prt_htmlfm_Output(context, "", 4); - for(subobj=page_obj; subobj; subobj=subobj->YNext) - { - if (subobj->Parent == page_obj) - { - /** Next row? **/ - if (subobj->Y > rowpos[cur_row]) - { - while(subobj->Y > (rowpos[cur_row]+0.001) && cur_row < PRT_HTMLFM_MAXROWS-1) cur_row++; - prt_htmlfm_Output(context, "\n", 10); - cur_col = 0; + for(pPrtObjStream subobj=page_obj; subobj; subobj=subobj->YNext) { + if (subobj->Parent == page_obj) { + /** Next row? **/ + if (subobj->Y > rowpos[cur_row]) { + while(subobj->Y > (rowpos[cur_row]+0.001) && cur_row < PRT_HTMLFM_MAXROWS-1) cur_row++; + prt_htmlfm_Output(context, "\n", 10); + cur_col = 0; } - /** Skip cols? **/ - if (subobj->X > colpos[cur_col]) - { - i=0; - while(subobj->X > (colpos[cur_col]+0.001) && cur_col < PRT_HTMLFM_MAXCOLS-1) - { - i++; - cur_col++; - } - prt_htmlfm_OutputPrintf(context, "", i); + /** Skip cols? **/ + if (subobj->X > colpos[cur_col]) { + int i=0; + while(subobj->X > (colpos[cur_col]+0.001) && cur_col < PRT_HTMLFM_MAXCOLS-1) { + i++; + cur_col++; + } + prt_htmlfm_OutputPrintf(context, "", i); } - /** Figure rowspan and colspan **/ - cs=1; - while(cur_col+cs < n_cols && (colpos[cur_col+cs]+0.001) < subobj->X + subobj->Width) cs++; - rs=1; - while(cur_row+rs < n_rows && (rowpos[cur_row+rs]+0.001) < subobj->Y + subobj->Height) rs++; - prt_htmlfm_OutputPrintf(context, "", 5); - cur_col += cs; - if (cur_col >= n_cols) cur_col = n_cols-1; - } + /** Figure rowspan and colspan **/ + int cs=1; + while(cur_col+cs < n_cols && (colpos[cur_col+cs]+0.001) < subobj->X + subobj->Width) cs++; + int rs=1; + while(cur_row+rs < n_rows && (rowpos[cur_row+rs]+0.001) < subobj->Y + subobj->Height) rs++; + prt_htmlfm_OutputPrintf(context, "", 5); + cur_col += cs; + if (cur_col >= n_cols) cur_col = n_cols-1; } + } prt_htmlfm_Output(context, "
  ", cs, rs); - prt_htmlfm_Generate_r(context, subobj); - prt_htmlfm_Output(context, "", cs, rs); + prt_htmlfm_Generate_r(context, subobj); + prt_htmlfm_Output(context, "
\n", 14); } else { double cur_row = -1; - char* divFormat = "
"; - for(subobj=page_obj; subobj; subobj=subobj->YNext) { + for(pPrtObjStream subobj=page_obj; subobj; subobj=subobj->YNext) { if (subobj->Parent == page_obj) { // Move to next row. if (subobj->Y > cur_row) { @@ -976,7 +906,7 @@ prt_htmlfm_Generate(void* context_v, pPrtObjStream page_obj) if(cur_row != -1) { prt_htmlfm_Output(context, "
\n", -1); } - prt_htmlfm_Output(context, divFormat, -1); + prt_htmlfm_Output(context, "
", -1); cur_row = subobj->Y; } @@ -986,14 +916,14 @@ prt_htmlfm_Generate(void* context_v, pPrtObjStream page_obj) } } - /** Write the page footer **/ prt_htmlfm_Output(context, "
", -1); - if (context->Flags & PRT_HTMLFM_F_PAGINATED) + if (context->Flags & PRT_HTMLFM_F_PAGINATED) { prt_htmlfm_Output(context, PRT_HTMLFM_PAGEFOOTER, -1); + } return 0; - } +} int @@ -1053,6 +983,4 @@ prt_htmlfm_Initialize() } return 0; - } - - + } \ No newline at end of file From 02ef6c2bdb4e2632143beb233a0e8721bb5437cf Mon Sep 17 00:00:00 2001 From: LMaster765 Date: Thu, 6 Mar 2025 16:05:33 -0700 Subject: [PATCH 16/28] Update strings --- centrallix/report/prtmgmt_v3_fm_html.c | 4 ++++ centrallix/report/prtmgmt_v3_fm_html_lm_text.c | 6 +++++- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/centrallix/report/prtmgmt_v3_fm_html.c b/centrallix/report/prtmgmt_v3_fm_html.c index 1916e864..8d6f9e07 100644 --- a/centrallix/report/prtmgmt_v3_fm_html.c +++ b/centrallix/report/prtmgmt_v3_fm_html.c @@ -658,6 +658,10 @@ prt_htmlfm_Generate_r(pPrtHTMLfmInf context, pPrtObjStream obj) { // if (strlen((char*)obj->Content) == 0) { // break; // } + + if (strlen((const char*)obj->Content) == 0 && obj->Flags & PRT_OBJ_F_NEWLINE) { + prt_htmlfm_Output(context, "
", -1); + } // prt_htmlfm_SetStyle(context, &(obj->TextStyle)); if (obj->URL && !strchr(obj->URL, '"')) { diff --git a/centrallix/report/prtmgmt_v3_fm_html_lm_text.c b/centrallix/report/prtmgmt_v3_fm_html_lm_text.c index b8de6bd7..6e2d558d 100644 --- a/centrallix/report/prtmgmt_v3_fm_html_lm_text.c +++ b/centrallix/report/prtmgmt_v3_fm_html_lm_text.c @@ -88,7 +88,10 @@ prt_htmlfm_GenerateArea(pPrtHTMLfmInf context, pPrtObjStream area) { prt_htmlfm_SaveStyle(context, &oldstyle); - prt_htmlfm_OutputPrintf(context, "
", lm_inf->AreaBorder.Width[0], lm_inf->AreaBorder.Color[0]); + + printf("%.2f -> %d, %.2f -> %d", area->Height, (int)(area->Height * PRT_HTMLFM_YPIXEL + 0.0001), area->ConfigHeight, (int)(area->ConfigHeight * PRT_HTMLFM_YPIXEL + 0.0001)); + prt_htmlfm_OutputPrintf(context, "
", + lm_inf->AreaBorder.Width[0], lm_inf->AreaBorder.Color[0], (int)(area->Height * PRT_HTMLFM_YPIXEL + 0.0001)); prt_htmlfm_Output(context, "
", -1); @@ -102,6 +105,7 @@ prt_htmlfm_GenerateArea(pPrtHTMLfmInf context, pPrtObjStream area) { prt_htmlfm_Output(context, "
", -1); prt_htmlfm_Output(context, "
", -1); prt_htmlfm_Output(context, "
", -1); + continue; } // prt_htmlfm_Output(context, "
", -1); From 34ce9bfea58f96aa6e3a981c7189d72cf6850ed7 Mon Sep 17 00:00:00 2001 From: LMaster765 Date: Thu, 6 Mar 2025 16:38:31 -0700 Subject: [PATCH 17/28] Add table borders --- .../include/prtmgmt_v3/prtmgmt_v3_lm_table.h | 1 + .../report/prtmgmt_v3_fm_html_lm_table.c | 18 ++++++++++++++++-- 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/centrallix/include/prtmgmt_v3/prtmgmt_v3_lm_table.h b/centrallix/include/prtmgmt_v3/prtmgmt_v3_lm_table.h index 472bf67d..891892b8 100644 --- a/centrallix/include/prtmgmt_v3/prtmgmt_v3_lm_table.h +++ b/centrallix/include/prtmgmt_v3/prtmgmt_v3_lm_table.h @@ -35,6 +35,7 @@ +#include "prtmgmt_v3/prtmgmt_v3.h" #define PRT_TABLM_MAXCOLS 256 /* maximum columns in a table */ #define PRT_TABLM_F_ISHEADER 1 /* row is a header that repeats */ diff --git a/centrallix/report/prtmgmt_v3_fm_html_lm_table.c b/centrallix/report/prtmgmt_v3_fm_html_lm_table.c index 05ba15bf..63f4e534 100644 --- a/centrallix/report/prtmgmt_v3_fm_html_lm_table.c +++ b/centrallix/report/prtmgmt_v3_fm_html_lm_table.c @@ -62,7 +62,20 @@ prt_htmlfm_GenerateTable(pPrtHTMLfmInf context, pPrtObjStream table) /** Write the table prologue **/ prt_htmlfm_SaveStyle(context, &oldstyle); - prt_htmlfm_Output(context,"\n", -1); + prt_htmlfm_Output(context,"
", + lm_data->TopBorder.Width[0] * PRT_HTMLFM_XPIXEL, lm_data->TopBorder.Color[0], + lm_data->RightBorder.Width[0] * PRT_HTMLFM_XPIXEL, lm_data->RightBorder.Color[0], + lm_data->BottomBorder.Width[0] * PRT_HTMLFM_XPIXEL, lm_data->BottomBorder.Color[0], + lm_data->LeftBorder.Width[0] * PRT_HTMLFM_XPIXEL, lm_data->LeftBorder.Color[0]); + prt_htmlfm_Output(context, borderbuf, -1); + + snprintf(borderbuf, sizeof(borderbuf), "", + lm_data->InnerBorder.Width[0] * PRT_HTMLFM_XPIXEL, lm_data->InnerBorder.Color[0], + lm_data->InnerBorder.Width[0] * PRT_HTMLFM_XPIXEL, lm_data->InnerBorder.Color[0]); + prt_htmlfm_Output(context, borderbuf, -1); /** Loop through the subobjects, generating the rows **/ for(row = table->ContentHead; row; row=row->Next) @@ -82,7 +95,8 @@ prt_htmlfm_GenerateTable(pPrtHTMLfmInf context, pPrtObjStream table) prt_htmlfm_OutputPrintf(context,"
", (int)(cell->Width*PRT_HTMLFM_XPIXEL), cell->BGColor); - prt_htmlfm_InitStyle(context, &(cell->TextStyle)); + + // prt_htmlfm_InitStyle(context, &(cell->TextStyle)); for(subobj=cell->ContentHead;subobj;subobj=subobj->Next) { prt_htmlfm_Generate_r(context, subobj); From e9924a8dd553bf29f4a26b5ea0b4245452a90950 Mon Sep 17 00:00:00 2001 From: LMaster765 Date: Thu, 6 Mar 2025 17:02:38 -0700 Subject: [PATCH 18/28] Improve table borders --- centrallix/report/prtmgmt_v3_fm_html.c | 2 +- centrallix/report/prtmgmt_v3_fm_html_lm_table.c | 6 ++++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/centrallix/report/prtmgmt_v3_fm_html.c b/centrallix/report/prtmgmt_v3_fm_html.c index 8d6f9e07..9817da15 100644 --- a/centrallix/report/prtmgmt_v3_fm_html.c +++ b/centrallix/report/prtmgmt_v3_fm_html.c @@ -948,7 +948,7 @@ prt_htmlfm_Generate(void* context_v, pPrtObjStream page_obj) { if(cur_row != -1) { prt_htmlfm_Output(context, "\n", -1); } - prt_htmlfm_Output(context, "
", -1); + prt_htmlfm_Output(context, "
", -1); cur_row = subobj->Y; } diff --git a/centrallix/report/prtmgmt_v3_fm_html_lm_table.c b/centrallix/report/prtmgmt_v3_fm_html_lm_table.c index 63f4e534..1e06f427 100644 --- a/centrallix/report/prtmgmt_v3_fm_html_lm_table.c +++ b/centrallix/report/prtmgmt_v3_fm_html_lm_table.c @@ -62,7 +62,8 @@ prt_htmlfm_GenerateTable(pPrtHTMLfmInf context, pPrtObjStream table) /** Write the table prologue **/ prt_htmlfm_SaveStyle(context, &oldstyle); - prt_htmlfm_Output(context,"Height * PRT_HTMLFM_YPIXEL); char borderbuf[256]; snprintf(borderbuf, sizeof(borderbuf), " style=\"border-top: %fpx solid #%6.6X; border-right: %fpx solid #%6.6X; border-bottom: %fpx solid #%6.6X; border-left: %fpx solid #%6.6X;\">", @@ -72,10 +73,11 @@ prt_htmlfm_GenerateTable(pPrtHTMLfmInf context, pPrtObjStream table) lm_data->LeftBorder.Width[0] * PRT_HTMLFM_XPIXEL, lm_data->LeftBorder.Color[0]); prt_htmlfm_Output(context, borderbuf, -1); - snprintf(borderbuf, sizeof(borderbuf), "", + snprintf(borderbuf, sizeof(borderbuf), "", -1); /** Loop through the subobjects, generating the rows **/ for(row = table->ContentHead; row; row=row->Next) From a2fcf4909f02f854088bbe5c9a92da4413fa72a6 Mon Sep 17 00:00:00 2001 From: brennenputh Date: Thu, 6 Mar 2025 17:02:38 -0700 Subject: [PATCH 19/28] Finish cleaning up and commenting new code --- centrallix/report/prtmgmt_v3_fm_html.c | 261 ++++++++++++------------- 1 file changed, 130 insertions(+), 131 deletions(-) diff --git a/centrallix/report/prtmgmt_v3_fm_html.c b/centrallix/report/prtmgmt_v3_fm_html.c index 8d6f9e07..1df4e97f 100644 --- a/centrallix/report/prtmgmt_v3_fm_html.c +++ b/centrallix/report/prtmgmt_v3_fm_html.c @@ -634,110 +634,100 @@ char *base64_encode(const unsigned char *input, size_t len) { return output; } -/*** prt_htmlfm_Generate_r() - recursive worker routine to do the bulk - *** of page generation. +/*** prt_htmlfm_Generate_r() - recurses through the document tree printing its + *** output to context + *** Programmer's note: Recursion happens in each of the methods this method + *** calls. ***/ int prt_htmlfm_Generate_r(pPrtHTMLfmInf context, pPrtObjStream obj) { - printf("Generate_r: %s\n", obj->ObjType->TypeName); - if (obj->ObjType->TypeID == PRT_OBJ_T_STRING) { - printf(" C: \"%s\"\n", obj->Content); - } - printf(" Font: \"%d\"\n", obj->TextStyle.FontID); - - /** Check recursion **/ + // Check that the recursion on this method isn't too deep. if (thExcessiveRecursion()) { mssError(1,"PRT","Could not generate page: resource exhaustion occurred"); return -1; } - /** Select the type of object we're formatting **/ switch(obj->ObjType->TypeID) { case PRT_OBJ_T_STRING: - // don't print needless empty strings - // if (strlen((char*)obj->Content) == 0) { - // break; - // } - - if (strlen((const char*)obj->Content) == 0 && obj->Flags & PRT_OBJ_F_NEWLINE) { - prt_htmlfm_Output(context, "
", -1); - } - - // prt_htmlfm_SetStyle(context, &(obj->TextStyle)); - if (obj->URL && !strchr(obj->URL, '"')) { - prt_htmlfm_Output(context, "URL, -1); - prt_htmlfm_Output(context, "\">", 2); - } - if (context->Flags & PRT_HTMLFM_F_PAGINATED) { - prt_htmlfm_OutputEncoded(context, (char*)obj->Content, -1); - } else { - switch (obj->Justification) { - default: prt_htmlfm_Output(context, "
Content) == 0 && obj->Flags & PRT_OBJ_F_NEWLINE) { + prt_htmlfm_Output(context, "
", -1); } + + if (obj->URL && !strchr(obj->URL, '"')) { + prt_htmlfm_Output(context, "
URL, -1); + prt_htmlfm_Output(context, "\">", 2); + } + if (context->Flags & PRT_HTMLFM_F_PAGINATED) { + prt_htmlfm_OutputEncoded(context, (char*)obj->Content, -1); + } else { + switch (obj->Justification) { + default: + prt_htmlfm_Output(context, "
TextStyle), obj->TextStyle.Color, (int) obj->TextStyle.FontSize); - prt_htmlfm_Output(context, stylebuf, -1); - prt_htmlfm_Output(context, " white-space: pre-wrap;\">", -1); + char stylebuf[128]; + snprintf(stylebuf, sizeof(stylebuf), " font-family:%s; color:#%6.6X; font-size:%dpx;", + prt_htmlfm_GetFont(&obj->TextStyle), obj->TextStyle.Color, (int) obj->TextStyle.FontSize); + prt_htmlfm_Output(context, stylebuf, -1); + prt_htmlfm_Output(context, " white-space: pre-wrap;\">", -1); - int attr = obj->TextStyle.Attr; + int attr = obj->TextStyle.Attr; - if (attr & PRT_OBJ_A_BOLD) { - prt_htmlfm_Output(context, "", -1); - } - if (attr & PRT_OBJ_A_ITALIC) { - prt_htmlfm_Output(context, "", -1); - } - if (attr & PRT_OBJ_A_UNDERLINE) { - prt_htmlfm_Output(context, "", -1); - } + if (attr & PRT_OBJ_A_BOLD) { + prt_htmlfm_Output(context, "", -1); + } + if (attr & PRT_OBJ_A_ITALIC) { + prt_htmlfm_Output(context, "", -1); + } + if (attr & PRT_OBJ_A_UNDERLINE) { + prt_htmlfm_Output(context, "", -1); + } + + prt_htmlfm_Output(context, (char*)obj->Content, -1); + + if (obj->Justification == 3) { + while (obj->Next && obj->Next->ObjType->TypeID == PRT_OBJ_T_STRING && obj->Next->Justification == 3) { - // printf("TEST: %s\n", (char*)obj->Content); - prt_htmlfm_Output(context, (char*)obj->Content, -1); + if (obj->Flags & PRT_OBJ_F_SOFTNEWLINE) { + prt_htmlfm_Output(context, " ", -1); + } - if (obj->Justification == 3) { - while (obj->Next && obj->Next->ObjType->TypeID == PRT_OBJ_T_STRING && obj->Next->Justification == 3) { + if (obj->Flags & PRT_OBJ_F_NEWLINE) { + prt_htmlfm_Output(context, "
", -1); + } - if (obj->Flags & PRT_OBJ_F_SOFTNEWLINE) { - prt_htmlfm_Output(context, " ", -1); - } - - if (obj->Flags & PRT_OBJ_F_NEWLINE) { - prt_htmlfm_Output(context, "
", -1); + obj = obj->Next; + prt_htmlfm_Output(context, (char*)obj->Content, -1); } + } - obj = obj->Next; - prt_htmlfm_Output(context, (char*)obj->Content, -1); + if (attr & PRT_OBJ_A_UNDERLINE) { + prt_htmlfm_Output(context, "
", -1); + } + if (attr & PRT_OBJ_A_ITALIC) { + prt_htmlfm_Output(context, "
", -1); + } + if (attr & PRT_OBJ_A_BOLD) { + prt_htmlfm_Output(context, "
", -1); } - } - if (attr & PRT_OBJ_A_UNDERLINE) { - prt_htmlfm_Output(context, "
", -1); - } - if (attr & PRT_OBJ_A_ITALIC) { - prt_htmlfm_Output(context, "
", -1); + prt_htmlfm_Output(context, "
", -1); } - if (attr & PRT_OBJ_A_BOLD) { - prt_htmlfm_Output(context, "", -1); + if (obj->URL && !strchr(obj->URL, '"')) { + prt_htmlfm_Output(context, "
", 4); } - - prt_htmlfm_Output(context, "
", -1); - } - if (obj->URL && !strchr(obj->URL, '"')) - { - prt_htmlfm_Output(context, "", 4); - } - // prt_htmlfm_EndStyle(context); - break; + break; case PRT_OBJ_T_AREA: prt_htmlfm_GenerateArea(context, obj); @@ -761,7 +751,6 @@ prt_htmlfm_Generate_r(pPrtHTMLfmInf context, pPrtObjStream obj) { } break; - /* Encodes image to base64 and writes to HTML */ case PRT_OBJ_T_IMAGE: case PRT_OBJ_T_SVG: if (context->Session->ImageOpenFn) { @@ -770,6 +759,7 @@ prt_htmlfm_Generate_r(pPrtHTMLfmInf context, pPrtObjStream obj) { if (w <= 0) w = 1; if (h <= 0) h = 1; + // lifetime start: buf ImageBuffer imgBuf = { (char *)nmMalloc(MAX_IMAGE_SIZE), 0, MAX_IMAGE_SIZE }; if (!imgBuf.buffer) { mssError(1, "PRT", "nmMalloc() failed\n"); @@ -780,7 +770,9 @@ prt_htmlfm_Generate_r(pPrtHTMLfmInf context, pPrtObjStream obj) { prt_internal_WriteImageToPNG(ImageWriteFn, &imgBuf, (pPrtImage)(obj->Content), w, h); // Encode image to base64 + // copy out of lifetime: buf into img char *base64Image = base64_encode((unsigned char *)imgBuf.buffer, imgBuf.size); + // lifetime end: buf nmFree(imgBuf.buffer, MAX_IMAGE_SIZE); if (!base64Image) { mssError(1, "PRT", "Base64 encoding failed\n"); @@ -796,11 +788,12 @@ prt_htmlfm_Generate_r(pPrtHTMLfmInf context, pPrtObjStream obj) { // Justification: All cases in which it is not an image, it is a SVG. if(obj->ObjType->TypeID == PRT_OBJ_T_IMAGE) { - prt_htmlfm_OutputPrintf(context, "", + prt_htmlfm_OutputPrintf(context, + "", base64Image, w, h); } else { prt_htmlfm_OutputPrintf(context, - "", + "", base64Image, w, h); } @@ -808,6 +801,7 @@ prt_htmlfm_Generate_r(pPrtHTMLfmInf context, pPrtObjStream obj) { prt_htmlfm_Output(context, "", 4); } + // lifetime end: img nmFree(base64Image, strlen(base64Image) + 1); } break; @@ -829,8 +823,6 @@ prt_htmlfm_Generate_r(pPrtHTMLfmInf context, pPrtObjStream obj) { int prt_htmlfm_Generate(void* context_v, pPrtObjStream page_obj) { pPrtHTMLfmInf context = (pPrtHTMLfmInf)context_v; - double colpos[PRT_HTMLFM_MAXCOLS]; - double rowpos[PRT_HTMLFM_MAXROWS]; /** Write the page header **/ if (context->Flags & PRT_HTMLFM_F_PAGINATED) { @@ -838,58 +830,65 @@ prt_htmlfm_Generate(void* context_v, pPrtObjStream page_obj) { } /** Write div to handle page margins **/ - prt_htmlfm_OutputPrintf(context, "
\n", (int)(page_obj->Width*PRT_HTMLFM_XPIXEL+0.001), - (int)((page_obj->MarginTop+0.001)*PRT_HTMLFM_YPIXEL), (int)((page_obj->MarginRight+0.001)*PRT_HTMLFM_YPIXEL), - (int)((page_obj->MarginBottom+0.001)*PRT_HTMLFM_YPIXEL), (int)((page_obj->MarginLeft+0.001)*PRT_HTMLFM_YPIXEL)); - - /** We need to scan the absolute-positioned content to figure out how many - ** "columns" and "rows" we need to put in the "table" used for layout - ** purposes. - **/ - int n_cols=0, n_rows=0; - for(pPrtObjStream subobj=page_obj->ContentHead; subobj; subobj=subobj->Next) { - if (n_cols < PRT_HTMLFM_MAXCOLS) { - /** Search for the X position in the 'colpos' list **/ - int found = n_cols; - for(int i = 0; i < n_cols; i++) { - if (subobj->X == colpos[i]) { - found = -1; - break; + prt_htmlfm_OutputPrintf(context, "
\n", + (int)(page_obj->Width*PRT_HTMLFM_XPIXEL+0.001), + (int)((page_obj->MarginTop+0.001)*PRT_HTMLFM_YPIXEL), + (int)((page_obj->MarginRight+0.001)*PRT_HTMLFM_YPIXEL), + (int)((page_obj->MarginBottom+0.001)*PRT_HTMLFM_YPIXEL), + (int)((page_obj->MarginLeft+0.001)*PRT_HTMLFM_YPIXEL)); + + // Paginated mode is older and less responsive - generally not recommended. + // If at all possible, eventually replace with proper HTML formatting. + if(context->Flags & PRT_HTMLFM_F_PAGINATED) { + /** We need to scan the absolute-positioned content to figure out how many + ** "columns" and "rows" we need to put in the "table" used for layout + ** purposes. + **/ + int n_cols=0, n_rows=0; + double colpos[PRT_HTMLFM_MAXCOLS]; + double rowpos[PRT_HTMLFM_MAXROWS]; + for(pPrtObjStream subobj=page_obj->ContentHead; subobj; subobj=subobj->Next) { + if (n_cols < PRT_HTMLFM_MAXCOLS) { + /** Search for the X position in the 'colpos' list **/ + int found = n_cols; + for(int i = 0; i < n_cols; i++) { + if (subobj->X == colpos[i]) { + found = -1; + break; + } + if (subobj->X < colpos[i]) { + found=i; + break; + } } - if (subobj->X < colpos[i]) { - found=i; - break; + if (found != -1) { + for(int i = n_cols-1 ; i >= found; i--) colpos[i+1] = colpos[i]; + colpos[found] = subobj->X; + n_cols++; } } - if (found != -1) { - for(int i = n_cols-1 ; i >= found; i--) colpos[i+1] = colpos[i]; - colpos[found] = subobj->X; - n_cols++; - } - } - if (n_rows < PRT_HTMLFM_MAXROWS) { - /** Search for the Y position in the 'rowpos' list **/ - int found = n_rows; - for(int i = 0; i < n_rows; i++) { - if (subobj->Y == rowpos[i]) { - found = -1; - break; + if (n_rows < PRT_HTMLFM_MAXROWS) { + /** Search for the Y position in the 'rowpos' list **/ + int found = n_rows; + for(int i = 0; i < n_rows; i++) { + if (subobj->Y == rowpos[i]) { + found = -1; + break; + } + if (subobj->Y < rowpos[i]) { + found=i; + break; + } } - if (subobj->Y < rowpos[i]) { - found=i; - break; + if (found != -1) { + for(int i = n_rows-1; i>=found; i--) rowpos[i+1] = rowpos[i]; + rowpos[found] = subobj->Y; + n_rows++; } } - if (found != -1) { - for(int i = n_rows-1; i>=found; i--) rowpos[i+1] = rowpos[i]; - rowpos[found] = subobj->Y; - n_rows++; - } } - } - if(context->Flags & PRT_HTMLFM_F_PAGINATED) { /** Write the layout table **/ prt_htmlfm_Output(context, "
\n", -1); for(int i = 0; i < n_cols; i++) { @@ -942,8 +941,8 @@ prt_htmlfm_Generate(void* context_v, pPrtObjStream page_obj) { double cur_row = -1; for(pPrtObjStream subobj=page_obj; subobj; subobj=subobj->YNext) { if (subobj->Parent == page_obj) { - // Move to next row. - if (subobj->Y > cur_row) { + // Move to next row if next item is greater than 10 pixels away. + if ((subobj->Y-cur_row) * 12 > 10) { // Only put in a div ender if this is a new div. if(cur_row != -1) { prt_htmlfm_Output(context, "\n", -1); From 2847859cd9cf9c2efe1985b1d6c0c01906fa4eee Mon Sep 17 00:00:00 2001 From: brennenputh Date: Thu, 6 Mar 2025 17:46:01 -0700 Subject: [PATCH 20/28] Make the absolute text have a relative div which specifies its height --- centrallix/report/prtmgmt_v3_fm_html_lm_text.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/centrallix/report/prtmgmt_v3_fm_html_lm_text.c b/centrallix/report/prtmgmt_v3_fm_html_lm_text.c index 6e2d558d..bb1a692a 100644 --- a/centrallix/report/prtmgmt_v3_fm_html_lm_text.c +++ b/centrallix/report/prtmgmt_v3_fm_html_lm_text.c @@ -112,6 +112,9 @@ prt_htmlfm_GenerateArea(pPrtHTMLfmInf context, pPrtObjStream area) { if (scan->Flags & PRT_OBJ_F_XSET && scan->X) { prt_htmlfm_Output(context, "", -1); + prt_htmlfm_OutputPrintf(context, "
", + (int)(scan->Height * 2.455011 + 0.0001)); // My favorite magic constant. None of us know why this specific constant works, but it does. + prt_htmlfm_Output(context, "
", -1); prt_htmlfm_OutputPrintf(context, "
", (int)(scan->X * PRT_HTMLFM_XPIXEL + 0.0001), (int)(scan->Y * PRT_HTMLFM_YPIXEL + 0.0001)); } From 851d46b3cb59165a812a35d0aa794137b089fec9 Mon Sep 17 00:00:00 2001 From: LMaster765 Date: Thu, 6 Mar 2025 20:00:14 -0700 Subject: [PATCH 21/28] Pusing for Brennen. Fixed some formatting --- centrallix/report/prtmgmt_v3_fm_html.c | 43 ++++++++++++------ .../report/prtmgmt_v3_fm_html_lm_table.c | 45 ++++++++++++++++--- .../report/prtmgmt_v3_fm_html_lm_text.c | 7 ++- 3 files changed, 72 insertions(+), 23 deletions(-) diff --git a/centrallix/report/prtmgmt_v3_fm_html.c b/centrallix/report/prtmgmt_v3_fm_html.c index acc6334d..8315f693 100644 --- a/centrallix/report/prtmgmt_v3_fm_html.c +++ b/centrallix/report/prtmgmt_v3_fm_html.c @@ -11,6 +11,7 @@ #include "cxlib/mtsession.h" #include "centrallix.h" #include "double.h" +#include "prtmgmt_v3/prtmgmt_v3_lm_text.h" #include #include #include @@ -650,7 +651,7 @@ prt_htmlfm_Generate_r(pPrtHTMLfmInf context, pPrtObjStream obj) { switch(obj->ObjType->TypeID) { case PRT_OBJ_T_STRING: if (strlen((const char*)obj->Content) == 0 && obj->Flags & PRT_OBJ_F_NEWLINE) { - prt_htmlfm_Output(context, "
", -1); + prt_htmlfm_Output(context, "
", -1); } if (obj->URL && !strchr(obj->URL, '"')) { @@ -696,20 +697,36 @@ prt_htmlfm_Generate_r(pPrtHTMLfmInf context, pPrtObjStream obj) { prt_htmlfm_Output(context, (char*)obj->Content, -1); - if (obj->Justification == 3) { - while (obj->Next && obj->Next->ObjType->TypeID == PRT_OBJ_T_STRING && obj->Next->Justification == 3) { - if (obj->Flags & PRT_OBJ_F_SOFTNEWLINE) { - prt_htmlfm_Output(context, " ", -1); - } - - if (obj->Flags & PRT_OBJ_F_NEWLINE) { - prt_htmlfm_Output(context, "
", -1); - } - - obj = obj->Next; - prt_htmlfm_Output(context, (char*)obj->Content, -1); + printf("%s: %d\n", (char*)obj->Content, (obj->Flags & (PRT_OBJ_F_XSET | PRT_OBJ_F_YSET))); + + pPrtObjStream firstObj = obj; + /* + * 1. don't append if there is no next + * 2. only append if next is a string + * 3. only append if next string has the same justification + * 4. don't append if next string has absolute positioning + * 5. don't append if next string has new line and first string was absolutely positioned + */ + while (obj->Next + && obj->Next->ObjType->TypeID == PRT_OBJ_T_STRING + && obj->Next->Justification == obj->Justification + && !(obj->Next->Flags & (PRT_OBJ_F_XSET | PRT_OBJ_F_YSET)) + && !(obj->Next->Flags & (PRT_OBJ_F_NEWLINE)) + && !(firstObj->Flags & (PRT_OBJ_F_XSET | PRT_OBJ_F_YSET))) { + + printf("%s: %d\n", (char*)obj->Content, (obj->Flags & (PRT_OBJ_F_XSET | PRT_OBJ_F_YSET))); + + if (obj->Flags & PRT_OBJ_F_SOFTNEWLINE && obj->Flags & PRT_TEXTLM_F_RMSPACE) { + prt_htmlfm_Output(context, " ", -1); } + + if (obj->Flags & PRT_OBJ_F_NEWLINE) { + prt_htmlfm_Output(context, "
", -1); + } + + obj = obj->Next; + prt_htmlfm_Output(context, (char*)obj->Content, -1); } if (attr & PRT_OBJ_A_UNDERLINE) { diff --git a/centrallix/report/prtmgmt_v3_fm_html_lm_table.c b/centrallix/report/prtmgmt_v3_fm_html_lm_table.c index 1e06f427..820d4319 100644 --- a/centrallix/report/prtmgmt_v3_fm_html_lm_table.c +++ b/centrallix/report/prtmgmt_v3_fm_html_lm_table.c @@ -62,7 +62,7 @@ prt_htmlfm_GenerateTable(pPrtHTMLfmInf context, pPrtObjStream table) /** Write the table prologue **/ prt_htmlfm_SaveStyle(context, &oldstyle); - prt_htmlfm_OutputPrintf(context,"
Height * PRT_HTMLFM_YPIXEL); char borderbuf[256]; @@ -89,14 +89,47 @@ prt_htmlfm_GenerateTable(pPrtHTMLfmInf context, pPrtObjStream table) if (cell && cell->ObjType->TypeID == PRT_OBJ_T_TABLECELL) { /** Got a cell. Emit list of cells in the row **/ - prt_htmlfm_Output(context, "", 4); + prt_htmlfm_Output(context, "", -1); + while(cell) { if (cell->ObjType->TypeID == PRT_OBJ_T_TABLECELL) { - prt_htmlfm_OutputPrintf(context,"
", - (int)(cell->Width*PRT_HTMLFM_XPIXEL), - cell->BGColor); + prt_htmlfm_OutputPrintf(context,"Width*PRT_HTMLFM_XPIXEL), + cell->BGColor); + + if (cell->BorderTop != 0 || row->BorderTop != 0) { + if (cell->BorderTop != 0) { + snprintf(borderbuf, sizeof(borderbuf), " border-top: %fpx solid;", cell->BorderTop * PRT_HTMLFM_XPIXEL); + prt_htmlfm_Output(context, borderbuf, -1); + } else { + snprintf(borderbuf, sizeof(borderbuf), " border-top: %fpx solid;", row->BorderTop * PRT_HTMLFM_XPIXEL); + prt_htmlfm_Output(context, borderbuf, -1); + } + } + + if (cell->BorderRight != 0) { + snprintf(borderbuf, sizeof(borderbuf), " border-right: %fpx solid;", cell->BorderRight * PRT_HTMLFM_XPIXEL); + prt_htmlfm_Output(context, borderbuf, -1); + } + + if (cell->BorderBottom != 0 || row->BorderBottom != 0) { + if (cell->BorderBottom != 0) { + snprintf(borderbuf, sizeof(borderbuf), " border-bottom: %fpx solid;", cell->BorderBottom * PRT_HTMLFM_XPIXEL); + prt_htmlfm_Output(context, borderbuf, -1); + } else { + snprintf(borderbuf, sizeof(borderbuf), " border-bottom: %fpx solid;", row->BorderBottom * PRT_HTMLFM_XPIXEL); + prt_htmlfm_Output(context, borderbuf, -1); + } + } + + if (cell->BorderLeft != 0) { + snprintf(borderbuf, sizeof(borderbuf), " border-left: %fpx solid;", cell->BorderLeft * PRT_HTMLFM_XPIXEL); + prt_htmlfm_Output(context, borderbuf, -1); + } + + prt_htmlfm_Output(context, "\">", -1); // prt_htmlfm_InitStyle(context, &(cell->TextStyle)); for(subobj=cell->ContentHead;subobj;subobj=subobj->Next) @@ -113,7 +146,7 @@ prt_htmlfm_GenerateTable(pPrtHTMLfmInf context, pPrtObjStream table) else { /** Row containing arbitrary stuff. Emit entire row **/ - prt_htmlfm_OutputPrintf(context, "
", + prt_htmlfm_OutputPrintf(context, "
", (int)(row->Width*PRT_HTMLFM_XPIXEL), lm_data->nColumns, row->BGColor); diff --git a/centrallix/report/prtmgmt_v3_fm_html_lm_text.c b/centrallix/report/prtmgmt_v3_fm_html_lm_text.c index bb1a692a..2886c778 100644 --- a/centrallix/report/prtmgmt_v3_fm_html_lm_text.c +++ b/centrallix/report/prtmgmt_v3_fm_html_lm_text.c @@ -88,8 +88,6 @@ prt_htmlfm_GenerateArea(pPrtHTMLfmInf context, pPrtObjStream area) { prt_htmlfm_SaveStyle(context, &oldstyle); - - printf("%.2f -> %d, %.2f -> %d", area->Height, (int)(area->Height * PRT_HTMLFM_YPIXEL + 0.0001), area->ConfigHeight, (int)(area->ConfigHeight * PRT_HTMLFM_YPIXEL + 0.0001)); prt_htmlfm_OutputPrintf(context, "
", lm_inf->AreaBorder.Width[0], lm_inf->AreaBorder.Color[0], (int)(area->Height * PRT_HTMLFM_YPIXEL + 0.0001)); @@ -123,10 +121,11 @@ prt_htmlfm_GenerateArea(pPrtHTMLfmInf context, pPrtObjStream area) { // justified text is split into individual objects... skip to next actual object while (scan->ObjType->TypeID == PRT_OBJ_T_STRING - && scan->Justification == 3 && scan->Next && scan->Next->ObjType->TypeID == PRT_OBJ_T_STRING - && scan->Next->Justification == 3) { + && scan->Justification == scan->Next->Justification + && !(scan->Next->Flags & (PRT_OBJ_F_XSET | PRT_OBJ_F_YSET)) + && !(scan->Next->Flags & (PRT_OBJ_F_NEWLINE))) { scan = scan->Next; } } From 2109770cbb6866ad72fa76ce48ab0c5bb904605e Mon Sep 17 00:00:00 2001 From: LMaster765 Date: Thu, 6 Mar 2025 21:20:37 -0700 Subject: [PATCH 22/28] Continue to improve (?) formatting --- centrallix/report/prtmgmt_v3_fm_html.c | 73 ++++++++++++++++--- .../report/prtmgmt_v3_fm_html_lm_text.c | 14 +++- 2 files changed, 74 insertions(+), 13 deletions(-) diff --git a/centrallix/report/prtmgmt_v3_fm_html.c b/centrallix/report/prtmgmt_v3_fm_html.c index 8315f693..ee686485 100644 --- a/centrallix/report/prtmgmt_v3_fm_html.c +++ b/centrallix/report/prtmgmt_v3_fm_html.c @@ -478,6 +478,16 @@ prt_htmlfm_SetStyle(pPrtHTMLfmInf context, pPrtTextStyle style) return 0; } +/*** prt_htmlfm_CompareStyles() - compares two text styles for equality + ***/ +int +prt_htmlfm_CompareStyles(pPrtTextStyle style1, pPrtTextStyle style2) { + return style1->Attr == style2->Attr + && style1->Color == style2->Color + && style1->FontID == style2->FontID + && style1->FontSize == style2->FontSize; +} + /*** prt_htmlfm_InitStyle() - initialize style settings, as if we are *** entering a new subcontainer. @@ -677,11 +687,13 @@ prt_htmlfm_Generate_r(pPrtHTMLfmInf context, pPrtObjStream obj) { break; } + prt_htmlfm_Output(context, " line-height: 0.6;\">TextStyle), obj->TextStyle.Color, (int) obj->TextStyle.FontSize); + prt_htmlfm_GetFont(&obj->TextStyle), obj->TextStyle.Color, (int) obj->TextStyle.FontSize); prt_htmlfm_Output(context, stylebuf, -1); - prt_htmlfm_Output(context, " white-space: pre-wrap;\">", -1); + prt_htmlfm_Output(context, "\">", -1); int attr = obj->TextStyle.Attr; @@ -712,10 +724,7 @@ prt_htmlfm_Generate_r(pPrtHTMLfmInf context, pPrtObjStream obj) { && obj->Next->ObjType->TypeID == PRT_OBJ_T_STRING && obj->Next->Justification == obj->Justification && !(obj->Next->Flags & (PRT_OBJ_F_XSET | PRT_OBJ_F_YSET)) - && !(obj->Next->Flags & (PRT_OBJ_F_NEWLINE)) - && !(firstObj->Flags & (PRT_OBJ_F_XSET | PRT_OBJ_F_YSET))) { - - printf("%s: %d\n", (char*)obj->Content, (obj->Flags & (PRT_OBJ_F_XSET | PRT_OBJ_F_YSET))); + && (!(obj->Next->Flags & (PRT_OBJ_F_NEWLINE)) || !(firstObj->Flags & (PRT_OBJ_F_XSET | PRT_OBJ_F_YSET)))) { if (obj->Flags & PRT_OBJ_F_SOFTNEWLINE && obj->Flags & PRT_TEXTLM_F_RMSPACE) { prt_htmlfm_Output(context, " ", -1); @@ -723,9 +732,51 @@ prt_htmlfm_Generate_r(pPrtHTMLfmInf context, pPrtObjStream obj) { if (obj->Flags & PRT_OBJ_F_NEWLINE) { prt_htmlfm_Output(context, "
", -1); + if (strlen((const char *)obj->Content) == 0) { + break; + } + } + + if (prt_htmlfm_CompareStyles(&obj->TextStyle, &obj->Next->TextStyle)) { + // same style, no need to change div + obj = obj->Next; + } else { + // new style! + if (attr & PRT_OBJ_A_UNDERLINE) { + prt_htmlfm_Output(context, "", -1); + } + if (attr & PRT_OBJ_A_ITALIC) { + prt_htmlfm_Output(context, "", -1); + } + if (attr & PRT_OBJ_A_BOLD) { + prt_htmlfm_Output(context, "", -1); + } + + prt_htmlfm_Output(context, "
", -1); + + obj = obj->Next; + + prt_htmlfm_Output(context, "TextStyle), obj->TextStyle.Color, (int) obj->TextStyle.FontSize); + prt_htmlfm_Output(context, stylebuf, -1); + prt_htmlfm_Output(context, "\">", -1); + + attr = obj->TextStyle.Attr; + + if (attr & PRT_OBJ_A_BOLD) { + prt_htmlfm_Output(context, "", -1); + } + if (attr & PRT_OBJ_A_ITALIC) { + prt_htmlfm_Output(context, "", -1); + } + if (attr & PRT_OBJ_A_UNDERLINE) { + prt_htmlfm_Output(context, "", -1); + } } - obj = obj->Next; prt_htmlfm_Output(context, (char*)obj->Content, -1); } @@ -738,6 +789,8 @@ prt_htmlfm_Generate_r(pPrtHTMLfmInf context, pPrtObjStream obj) { if (attr & PRT_OBJ_A_BOLD) { prt_htmlfm_Output(context, "", -1); } + + prt_htmlfm_Output(context, "", -1); prt_htmlfm_Output(context, "
", -1); } @@ -806,11 +859,11 @@ prt_htmlfm_Generate_r(pPrtHTMLfmInf context, pPrtObjStream obj) { // Justification: All cases in which it is not an image, it is a SVG. if(obj->ObjType->TypeID == PRT_OBJ_T_IMAGE) { prt_htmlfm_OutputPrintf(context, - "", + "", base64Image, w, h); } else { prt_htmlfm_OutputPrintf(context, - "", + "", base64Image, w, h); } @@ -819,7 +872,7 @@ prt_htmlfm_Generate_r(pPrtHTMLfmInf context, pPrtObjStream obj) { } // lifetime end: img - nmFree(base64Image, strlen(base64Image) + 1); + nmFree(base64Image, strlen(base64Image)); } break; diff --git a/centrallix/report/prtmgmt_v3_fm_html_lm_text.c b/centrallix/report/prtmgmt_v3_fm_html_lm_text.c index 2886c778..715b349e 100644 --- a/centrallix/report/prtmgmt_v3_fm_html_lm_text.c +++ b/centrallix/report/prtmgmt_v3_fm_html_lm_text.c @@ -111,21 +111,29 @@ prt_htmlfm_GenerateArea(pPrtHTMLfmInf context, pPrtObjStream area) { if (scan->Flags & PRT_OBJ_F_XSET && scan->X) { prt_htmlfm_Output(context, "", -1); prt_htmlfm_OutputPrintf(context, "
", - (int)(scan->Height * 2.455011 + 0.0001)); // My favorite magic constant. None of us know why this specific constant works, but it does. + (int)(scan->Height * 2.455011 + 0.0001)); // My favorite magic constant. None of us know why this specific constant works, but it does. prt_htmlfm_Output(context, "
", -1); prt_htmlfm_OutputPrintf(context, "
", - (int)(scan->X * PRT_HTMLFM_XPIXEL + 0.0001), (int)(scan->Y * PRT_HTMLFM_YPIXEL + 0.0001)); + (int)(scan->X * PRT_HTMLFM_XPIXEL + 0.0001), (int)(scan->Y * PRT_HTMLFM_YPIXEL + 0.0001)); } prt_htmlfm_Generate_r(context, scan); + pPrtObjStream firstObj = scan; // justified text is split into individual objects... skip to next actual object while (scan->ObjType->TypeID == PRT_OBJ_T_STRING && scan->Next && scan->Next->ObjType->TypeID == PRT_OBJ_T_STRING && scan->Justification == scan->Next->Justification && !(scan->Next->Flags & (PRT_OBJ_F_XSET | PRT_OBJ_F_YSET)) - && !(scan->Next->Flags & (PRT_OBJ_F_NEWLINE))) { + && (!(scan->Next->Flags & (PRT_OBJ_F_NEWLINE)) || !(firstObj->Flags & (PRT_OBJ_F_XSET | PRT_OBJ_F_YSET)))) { + if (scan->Flags & PRT_OBJ_F_NEWLINE && strlen((const char *)scan->Content) == 0) { + prt_htmlfm_Output(context, "
", -1); + prt_htmlfm_Output(context, "", -1); + prt_htmlfm_Output(context, "
", -1); + prt_htmlfm_Output(context, "
", -1); + break; + } scan = scan->Next; } } From e8ee839ff9c765e4be5e20567577e4b3c40c958c Mon Sep 17 00:00:00 2001 From: LMaster765 Date: Fri, 7 Mar 2025 10:15:00 -0700 Subject: [PATCH 23/28] Improve code commenting and formatting --- centrallix/report/prtmgmt_v3_fm_html.c | 25 ++-- .../report/prtmgmt_v3_fm_html_lm_table.c | 10 -- .../report/prtmgmt_v3_fm_html_lm_text.c | 107 +++++++++--------- 3 files changed, 67 insertions(+), 75 deletions(-) diff --git a/centrallix/report/prtmgmt_v3_fm_html.c b/centrallix/report/prtmgmt_v3_fm_html.c index ee686485..16987f2a 100644 --- a/centrallix/report/prtmgmt_v3_fm_html.c +++ b/centrallix/report/prtmgmt_v3_fm_html.c @@ -661,7 +661,7 @@ prt_htmlfm_Generate_r(pPrtHTMLfmInf context, pPrtObjStream obj) { switch(obj->ObjType->TypeID) { case PRT_OBJ_T_STRING: if (strlen((const char*)obj->Content) == 0 && obj->Flags & PRT_OBJ_F_NEWLINE) { - prt_htmlfm_Output(context, "
", -1); + prt_htmlfm_Output(context, "
", -1); } if (obj->URL && !strchr(obj->URL, '"')) { @@ -674,26 +674,25 @@ prt_htmlfm_Generate_r(pPrtHTMLfmInf context, pPrtObjStream obj) { } else { switch (obj->Justification) { default: - prt_htmlfm_Output(context, "
TextStyle), obj->TextStyle.Color, (int) obj->TextStyle.FontSize); + snprintf(stylebuf, sizeof(stylebuf), " font-family: %s; color: #%6.6X; font-size: %dpx; line-height: %f;\">", + prt_htmlfm_GetFont(&obj->TextStyle), obj->TextStyle.Color, (int) obj->TextStyle.FontSize, obj->LineHeight); prt_htmlfm_Output(context, stylebuf, -1); - prt_htmlfm_Output(context, "\">", -1); int attr = obj->TextStyle.Attr; @@ -714,6 +713,7 @@ prt_htmlfm_Generate_r(pPrtHTMLfmInf context, pPrtObjStream obj) { pPrtObjStream firstObj = obj; /* + * Logic for appending other string objects to the current one: * 1. don't append if there is no next * 2. only append if next is a string * 3. only append if next string has the same justification @@ -731,12 +731,13 @@ prt_htmlfm_Generate_r(pPrtHTMLfmInf context, pPrtObjStream obj) { } if (obj->Flags & PRT_OBJ_F_NEWLINE) { - prt_htmlfm_Output(context, "
", -1); + prt_htmlfm_Output(context, "
", -1); if (strlen((const char *)obj->Content) == 0) { break; } } + // compare text styles to see if there was a change if (prt_htmlfm_CompareStyles(&obj->TextStyle, &obj->Next->TextStyle)) { // same style, no need to change div obj = obj->Next; @@ -758,11 +759,9 @@ prt_htmlfm_Generate_r(pPrtHTMLfmInf context, pPrtObjStream obj) { prt_htmlfm_Output(context, "TextStyle), obj->TextStyle.Color, (int) obj->TextStyle.FontSize); + snprintf(stylebuf, sizeof(stylebuf), " font-family: %s; color: #%6.6X; font-size: %dpx; line-height: %f;\">", + prt_htmlfm_GetFont(&obj->TextStyle), obj->TextStyle.Color, (int) obj->TextStyle.FontSize, obj->LineHeight); prt_htmlfm_Output(context, stylebuf, -1); - prt_htmlfm_Output(context, "\">", -1); attr = obj->TextStyle.Attr; diff --git a/centrallix/report/prtmgmt_v3_fm_html_lm_table.c b/centrallix/report/prtmgmt_v3_fm_html_lm_table.c index 820d4319..d28e39f9 100644 --- a/centrallix/report/prtmgmt_v3_fm_html_lm_table.c +++ b/centrallix/report/prtmgmt_v3_fm_html_lm_table.c @@ -1,20 +1,10 @@ #include -#include #include #include -#include #include -#include "barcode.h" -#include "report.h" -#include "cxlib/mtask.h" -#include "cxlib/magic.h" -#include "cxlib/xarray.h" -#include "cxlib/xstring.h" #include "prtmgmt_v3/prtmgmt_v3.h" #include "prtmgmt_v3/prtmgmt_v3_fm_html.h" #include "prtmgmt_v3/prtmgmt_v3_lm_table.h" -#include "htmlparse.h" -#include "cxlib/mtsession.h" /************************************************************************/ /* Centrallix Application Server System */ diff --git a/centrallix/report/prtmgmt_v3_fm_html_lm_text.c b/centrallix/report/prtmgmt_v3_fm_html_lm_text.c index 715b349e..27416dce 100644 --- a/centrallix/report/prtmgmt_v3_fm_html_lm_text.c +++ b/centrallix/report/prtmgmt_v3_fm_html_lm_text.c @@ -4,17 +4,9 @@ #include #include #include -#include "barcode.h" -#include "report.h" -#include "cxlib/mtask.h" -#include "cxlib/magic.h" -#include "cxlib/xarray.h" -#include "cxlib/xstring.h" #include "prtmgmt_v3/prtmgmt_v3.h" #include "prtmgmt_v3/prtmgmt_v3_fm_html.h" #include "prtmgmt_v3/prtmgmt_v3_lm_text.h" -#include "htmlparse.h" -#include "cxlib/mtsession.h" /************************************************************************/ /* Centrallix Application Server System */ @@ -55,72 +47,40 @@ ***/ int prt_htmlfm_GenerateArea(pPrtHTMLfmInf context, pPrtObjStream area) { - int n_xset; - double xset[PRT_HTMLFM_MAX_TABSTOP]; - double widths[PRT_HTMLFM_MAX_TABSTOP]; - pPrtObjStream scan, linetail, next_xset_obj; - int i,j,cur_xset,next_xset; - double w; - int last_needed_cols, cur_needs_cols, need_new_row, in_td, in_tr; + pPrtObjStream scan; PrtTextStyle oldstyle; - char* justifytypes[] = { "left", "right", "center", "justify" }; pPrtTextLMData lm_inf = (pPrtTextLMData)(area->LMData); - /** First we need to scan the area looking for objects which - ** were positioned with PRT_OBJ_F_XSET, so we can build a table - ** of sorted 'tabstops'. - **/ - xset[0] = 0.0; - n_xset = 1; - for (scan = area->ContentHead; scan; scan = scan->Next) { - if (scan->Flags & PRT_OBJ_F_XSET) { - for (i = 0; i <= n_xset; i++) { - if (i!=n_xset && xset[i] == scan->X) break; - if (n_xset < PRT_HTMLFM_MAX_TABSTOP && (i == n_xset || xset[i] > scan->X)) { - for (j = n_xset; j > i; j--) xset[j] = xset[j - 1]; - xset[i] = scan->X; - n_xset++; - break; - } - } - } - } - prt_htmlfm_SaveStyle(context, &oldstyle); - prt_htmlfm_OutputPrintf(context, "
", - lm_inf->AreaBorder.Width[0], lm_inf->AreaBorder.Color[0], (int)(area->Height * PRT_HTMLFM_YPIXEL + 0.0001)); - - prt_htmlfm_Output(context, "
", -1); - - prt_htmlfm_Output(context, "
", -1); - + prt_htmlfm_OutputPrintf(context, "
", + lm_inf->AreaBorder.Width[0], lm_inf->AreaBorder.Color[0]); + prt_htmlfm_Output(context, "
", -1); + prt_htmlfm_Output(context, "
", -1); for (scan = area->ContentHead; scan != NULL; scan = scan->Next) { if (scan->Flags & PRT_OBJ_F_NEWLINE) { prt_htmlfm_Output(context, "
", -1); prt_htmlfm_Output(context, "
", -1); - prt_htmlfm_Output(context, "
", -1); - prt_htmlfm_Output(context, "
", -1); + prt_htmlfm_Output(context, "
", -1); + prt_htmlfm_Output(context, "
", -1); continue; } - // prt_htmlfm_Output(context, "
", -1); - if (scan->Flags & PRT_OBJ_F_XSET && scan->X) { prt_htmlfm_Output(context, "
", -1); - prt_htmlfm_OutputPrintf(context, "
", + prt_htmlfm_OutputPrintf(context, "
", (int)(scan->Height * 2.455011 + 0.0001)); // My favorite magic constant. None of us know why this specific constant works, but it does. prt_htmlfm_Output(context, "
", -1); - prt_htmlfm_OutputPrintf(context, "
", + prt_htmlfm_OutputPrintf(context, "
", (int)(scan->X * PRT_HTMLFM_XPIXEL + 0.0001), (int)(scan->Y * PRT_HTMLFM_YPIXEL + 0.0001)); } prt_htmlfm_Generate_r(context, scan); pPrtObjStream firstObj = scan; - // justified text is split into individual objects... skip to next actual object + // some strings are combined in prt_htmlfm_Generate_r(), so we need to account for that while (scan->ObjType->TypeID == PRT_OBJ_T_STRING && scan->Next && scan->Next->ObjType->TypeID == PRT_OBJ_T_STRING @@ -130,8 +90,8 @@ prt_htmlfm_GenerateArea(pPrtHTMLfmInf context, pPrtObjStream area) { if (scan->Flags & PRT_OBJ_F_NEWLINE && strlen((const char *)scan->Content) == 0) { prt_htmlfm_Output(context, "
", -1); prt_htmlfm_Output(context, "
", -1); - prt_htmlfm_Output(context, "
", -1); - prt_htmlfm_Output(context, "
", -1); + prt_htmlfm_Output(context, "
", -1); + prt_htmlfm_Output(context, "
", -1); break; } scan = scan->Next; @@ -145,6 +105,49 @@ prt_htmlfm_GenerateArea(pPrtHTMLfmInf context, pPrtObjStream area) { prt_htmlfm_ResetStyle(context, &oldstyle); return 0; +} + + +/*** prt_htmlfm_GenerateAreaPaginated() - generates the html to represent a + *** textflow area using the older paginated style. + ***/ + int + prt_htmlfm_GenerateAreaPaginated(pPrtHTMLfmInf context, pPrtObjStream area) + { + int n_xset; + double xset[PRT_HTMLFM_MAX_TABSTOP]; + double widths[PRT_HTMLFM_MAX_TABSTOP]; + pPrtObjStream scan, linetail, next_xset_obj; + int i,j,cur_xset,next_xset; + double w; + int last_needed_cols, cur_needs_cols, need_new_row, in_td, in_tr; + PrtTextStyle oldstyle; + char* justifytypes[] = { "left", "right", "center", "justify" }; + pPrtTextLMData lm_inf = (pPrtTextLMData)(area->LMData); + + /** First we need to scan the area looking for objects which + ** were positioned with PRT_OBJ_F_XSET, so we can build a table + ** of sorted 'tabstops'. + **/ + xset[0] = 0.0; + n_xset = 1; + for (scan = area->ContentHead; scan; scan = scan->Next) + { + if (scan->Flags & PRT_OBJ_F_XSET) + { + for (i = 0; i <= n_xset; i++) + { + if (i!=n_xset && xset[i] == scan->X) break; + if (n_xset < PRT_HTMLFM_MAX_TABSTOP && (i == n_xset || xset[i] > scan->X)) + { + for (j = n_xset; j > i; j--) xset[j] = xset[j - 1]; + xset[i] = scan->X; + n_xset++; + break; + } + } + } + } /** Output the area prologue **/ prt_htmlfm_SaveStyle(context, &oldstyle); From c4e60ab7f942f40efc090eb84641c406f9fe7af2 Mon Sep 17 00:00:00 2001 From: brennenputh Date: Fri, 7 Mar 2025 10:17:42 -0700 Subject: [PATCH 24/28] Add sysdoc document for HTML report project --- centrallix-sysdoc/HTMLReportOutput.md | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 centrallix-sysdoc/HTMLReportOutput.md diff --git a/centrallix-sysdoc/HTMLReportOutput.md b/centrallix-sysdoc/HTMLReportOutput.md new file mode 100644 index 00000000..e5b5a89a --- /dev/null +++ b/centrallix-sysdoc/HTMLReportOutput.md @@ -0,0 +1,4 @@ +## Generating a Report + +To generate a report, open up the Kardia/Centrallix instance running on your firewall. The ports will be shown on the Kardia interface. +There is no specific path to generating a report, From 2f134090abf583804b5c24a33e65f42b0fbe8309 Mon Sep 17 00:00:00 2001 From: LMaster765 Date: Fri, 7 Mar 2025 10:39:43 -0700 Subject: [PATCH 25/28] Start flag documentation --- centrallix-sysdoc/HTMLReportOutput.md | 38 +++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/centrallix-sysdoc/HTMLReportOutput.md b/centrallix-sysdoc/HTMLReportOutput.md index e5b5a89a..cb49f63a 100644 --- a/centrallix-sysdoc/HTMLReportOutput.md +++ b/centrallix-sysdoc/HTMLReportOutput.md @@ -2,3 +2,41 @@ To generate a report, open up the Kardia/Centrallix instance running on your firewall. The ports will be shown on the Kardia interface. There is no specific path to generating a report, + +## PrtObjStream and pPrtObjStream + +The `PrtObjStream` struct and pointer (`pPrtObjStream`) store all of the information about the data being printed. The struct definition can be found in [prtmgmt_v3.h](../centrallix/include/prtmgmt_v3/prtmgmt_v3.h). + +### Special Flags + +There are a variety of useful flags in the `PrtObjStream` struct scattered throughout the project. We have documented most of the ones we have found below. Most of the flags are defined in the same file as the `PrtObjStream` flag. + +#### PRT_OBJ_F_NEWLINE + +- **Location**: [prtmgmt_v3.h](../centrallix/include/prtmgmt_v3/prtmgmt_v3.h) + +- **Description**: Indicates that the object begins with a newline (typically for string flow). + +#### PRT_OBJ_F_SOFTNEWLINE + +- **Location**: [prtmgmt_v3.h](../centrallix/include/prtmgmt_v3/prtmgmt_v3.h) + +- **Description**: Indicates that the object begins with a soft newline (typically for string flow). Soft newlines are inserted when the PrtObjStream is created to define breakpoints for the PDF generator; they are not defined in the .rpt files. + +#### PRT_OBJ_F_XSET + +- **Location**: [prtmgmt_v3.h](../centrallix/include/prtmgmt_v3/prtmgmt_v3.h) + +- **Description**: Indicates that the object has an abosulute x-position defined by the .rpt file. + +#### PRT_OBJ_F_YSET + +- **Location**: [prtmgmt_v3.h](../centrallix/include/prtmgmt_v3/prtmgmt_v3.h) + +- **Description**: Indicates that the object has an abosulute y-position defined by the .rpt file. + +#### PRT_TEXTLM_F_RMSPACE + +- **Location**: [prtmgmt_v3_lm_text.h](../centrallix/include/prtmgmt_v3/prtmgmt_v3_lm_text.h) + +- **Description**: Indicates that the string object replaced a space character with a soft newline. Useful for deciding whether or not to insert a space character when a soft newline is found. \ No newline at end of file From 5b5489ed1e433546d570c0d086f3c7e01e6fb2ba Mon Sep 17 00:00:00 2001 From: brennenputh Date: Fri, 7 Mar 2025 10:47:33 -0700 Subject: [PATCH 26/28] Merge --- centrallix-sysdoc/HTMLReportOutput.md | 68 ++++++++++++++++++++++++++- 1 file changed, 66 insertions(+), 2 deletions(-) diff --git a/centrallix-sysdoc/HTMLReportOutput.md b/centrallix-sysdoc/HTMLReportOutput.md index cb49f63a..29d12d8d 100644 --- a/centrallix-sysdoc/HTMLReportOutput.md +++ b/centrallix-sysdoc/HTMLReportOutput.md @@ -1,8 +1,71 @@ -## Generating a Report +## Tooling To generate a report, open up the Kardia/Centrallix instance running on your firewall. The ports will be shown on the Kardia interface. There is no specific path to generating a report, +### Generating Compile Commands + +Install compiledb with `sudo python3 -m pip install compiledb`. +Generate the compile_commands.json with the following commands (starting at root). + +```sh +cd centrallix +compiledb make all +``` + +The reason for creating this is to use a tool such as [clangd](https://clangd.llvm.org/). +There is a VSCode extension which supports using it, even on servers which do not support clangd. +`clangd` will allow for LSP usage within the project, adding helpful multi-file errors and jump to definition. +Perhaps it may be wise to at some point go over the entire project and resolve its warnings and errors as possible. + +## Process + +### Generating a Report + +To generate a report, open up the Kardia/Centrallix instance running on your firewall. The ports will be shown on the Kardia interface. +There is no specific path to generating a report, it depends on which sort of report you would like to generate. +Ask Greg which reports he would like you to work on. + +### Sending an HTML Email + +This requires the use of a Mutt client on a Linux machine for simplicity. +The configuration used ([source](https://mritunjaysharma394.medium.com/how-to-set-up-mutt-text-based-mail-client-with-gmail-993ae40b0003)) is specific to GMail clients. +The template configuration for Mutt using a GMail account can be found below. +You will need to generate an app password with the instructions [here](https://support.google.com/accounts/answer/185833?hl=en), and use that as your password. + +``` +# ================ IMAP ==================== +set imap_user = @gmail.com +set imap_pass = +set spoolfile = imaps://imap.gmail.com/INBOX +set folder = imaps://imap.gmail.com/ +set record="imaps://imap.gmail.com/[Gmail]/Sent Mail" +set postponed="imaps://imap.gmail.com/[Gmail]/Drafts" +set mbox="imaps://imap.gmail.com/[Gmail]/All Mail" +set header_cache = "~/.mutt/cache/headers" +set message_cachedir = "~/.mutt/cache/bodies" +set certificate_file = "~/.mutt/certificates" +# ================ SMTP ==================== +set smtp_url = "smtp://@smtp.gmail.com:587/" +set smtp_pass = $imap_pass +set ssl_force_tls = yes # Require encrypted connection +# ================ Composition ==================== +set editor = "nvim" # Set your favourite editor. +set edit_headers = yes # See the headers when editing +set charset = UTF-8 # value of $LANG; also fallback for send_charset +# Sender, email address, and sign-off line must match +unset use_domain +set realname = "" +set from = "@gmail.com" +set use_from = yes +``` + +Once Mutt has been set up, use the following command to send the HTML email from your GMail account. +It is indeed totally valid to use your own email address as the target email. +``` +mutt -e "set content_type=text/html" -s "" < +``` + ## PrtObjStream and pPrtObjStream The `PrtObjStream` struct and pointer (`pPrtObjStream`) store all of the information about the data being printed. The struct definition can be found in [prtmgmt_v3.h](../centrallix/include/prtmgmt_v3/prtmgmt_v3.h). @@ -39,4 +102,5 @@ There are a variety of useful flags in the `PrtObjStream` struct scattered throu - **Location**: [prtmgmt_v3_lm_text.h](../centrallix/include/prtmgmt_v3/prtmgmt_v3_lm_text.h) -- **Description**: Indicates that the string object replaced a space character with a soft newline. Useful for deciding whether or not to insert a space character when a soft newline is found. \ No newline at end of file +- **Description**: Indicates that the string object replaced a space character with a soft newline. Useful for deciding whether or not to insert a space character when a soft newline is found. + From 2f6aa14305fdfca10395b454abee107b94e989bc Mon Sep 17 00:00:00 2001 From: LMaster765 Date: Fri, 7 Mar 2025 11:38:59 -0700 Subject: [PATCH 27/28] Add more documentation --- centrallix-sysdoc/HTMLReportOutput.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/centrallix-sysdoc/HTMLReportOutput.md b/centrallix-sysdoc/HTMLReportOutput.md index 29d12d8d..da077d3f 100644 --- a/centrallix-sysdoc/HTMLReportOutput.md +++ b/centrallix-sysdoc/HTMLReportOutput.md @@ -68,7 +68,7 @@ mutt -e "set content_type=text/html" -s "" < Date: Fri, 7 Mar 2025 14:43:12 -0700 Subject: [PATCH 28/28] Add next steps to post-sprint documentation --- centrallix-sysdoc/HTMLReportOutput.md | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/centrallix-sysdoc/HTMLReportOutput.md b/centrallix-sysdoc/HTMLReportOutput.md index da077d3f..1c44db0c 100644 --- a/centrallix-sysdoc/HTMLReportOutput.md +++ b/centrallix-sysdoc/HTMLReportOutput.md @@ -104,3 +104,20 @@ There are a variety of useful flags in the `PrtObjStream` struct scattered throu - **Description**: Indicates that the string object replaced a space character with a soft newline. Useful for deciding whether or not to insert a space character when a soft newline is found. +## Next Steps + +### Sending in email + +We found that some of the design goals (encoding the images in the file with base 64 and using flexbox designs instead of a tabular system) may not be compatible with sending the HTML via email. Further research into the issue is needed along with some potential redesigning of the HTML generator. + +### Table spacing + +We hard-coded padding values inside of table cells to match the receipt report file that we were given. However, this value was not quite right for the donation detail report. We could not find a cell padding value in the `PrtObjStream` struct, but there may be something we missed. Some of the vertical sizing of the tables is also not consistent with the PDF output, but we did not see any cell height info the struct. + +### Absolute positioning + +Not all absolute position rules are honored. For example, the "pls_retain" and "rcpt_summary" areas defined in the receipt report have no spacing between them, but there should be one y unit between them. + +### Image positioning issues + +The receipt report has a Centrallix icon in the lower right corner that was moved to the middle of the page. We did not have an opportunity to look into this issue.