diff --git a/.gitignore b/.gitignore index cbfe20f1d..52647cd21 100644 --- a/.gitignore +++ b/.gitignore @@ -62,3 +62,5 @@ perf.data.old .idea/ .vscode/ centrallix-os/tmp/* +compile_commands.json +.cache/ diff --git a/centrallix-sysdoc/HTMLReportOutput.md b/centrallix-sysdoc/HTMLReportOutput.md new file mode 100644 index 000000000..1c44db0cd --- /dev/null +++ b/centrallix-sysdoc/HTMLReportOutput.md @@ -0,0 +1,123 @@ +## 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). There is also a type-specific struct that stores additional data for each data type. These are found in the same folder as prtmgmt_v3.h as "prtmgmt_v3_lm_(type).h" for the text, table, and col types. + +### 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. + +## 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. diff --git a/centrallix/include/prtmgmt_v3.h b/centrallix/include/prtmgmt_v3.h deleted file mode 100644 index 1bfa7bb6a..000000000 --- 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 40103a3a9..cf2632028 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_table.h b/centrallix/include/prtmgmt_v3/prtmgmt_v3_lm_table.h index 472bf67d0..891892b8d 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/include/prtmgmt_v3/prtmgmt_v3_lm_text.h b/centrallix/include/prtmgmt_v3/prtmgmt_v3_lm_text.h index 280b41beb..819dd42fd 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 36262e3f2..16987f2a1 100644 --- a/centrallix/report/prtmgmt_v3_fm_html.c +++ b/centrallix/report/prtmgmt_v3_fm_html.c @@ -4,19 +4,17 @@ #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 "prtmgmt_v3/prtmgmt_v3_lm_text.h" +#include +#include +#include /************************************************************************/ /* Centrallix Application Server System */ @@ -62,7 +60,7 @@ /*** Document header ***/ -#define PRT_HTMLFM_HEADER "\n" \ +#define PRT_HTMLFM_HEADER "\n" \ "\n" \ "\n" \ " Centrallix HTML Document\n" \ @@ -157,6 +155,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. @@ -388,13 +396,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; @@ -408,9 +428,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; @@ -447,7 +464,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); @@ -461,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. @@ -587,167 +614,274 @@ 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; + if (imgBuf->size + len > imgBuf->capacity) { + return -1; // Buffer overflow + } + memcpy(imgBuf->buffer + imgBuf->size, data, len); + imgBuf->size += len; + return len; +} + -/*** prt_htmlfm_Generate_r() - recursive worker routine to do the bulk - *** of page generation. +/** 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; + + 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() - 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) - { - char* path; - void* arg; - int w,h; - unsigned long id; - int rval; - - /** Check recursion **/ - if (thExcessiveRecursion()) - { +prt_htmlfm_Generate_r(pPrtHTMLfmInf context, pPrtObjStream obj) { + // 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) - { + switch(obj->ObjType->TypeID) { case PRT_OBJ_T_STRING: - prt_htmlfm_SetStyle(context, &(obj->TextStyle)); - 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 (obj->URL && !strchr(obj->URL, '"')) - { - prt_htmlfm_Output(context, "", 4); - } - break; + if (strlen((const char*)obj->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, "
", + prt_htmlfm_GetFont(&obj->TextStyle), obj->TextStyle.Color, (int) obj->TextStyle.FontSize, obj->LineHeight); + prt_htmlfm_Output(context, stylebuf, -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); + } + + 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; + /* + * 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 + * 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)))) { + + 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); + 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; + } 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, "", + prt_htmlfm_GetFont(&obj->TextStyle), obj->TextStyle.Color, (int) obj->TextStyle.FontSize, obj->LineHeight); + prt_htmlfm_Output(context, stylebuf, -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); + } + } + + 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); + } + + prt_htmlfm_Output(context, "", -1); + + prt_htmlfm_Output(context, "
", -1); + } + if (obj->URL && !strchr(obj->URL, '"')) { + prt_htmlfm_Output(context, "
", 4); + } + 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; - - 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); - } - } - 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; - 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); + case PRT_OBJ_T_IMAGE: + case PRT_OBJ_T_SVG: + if (context->Session->ImageOpenFn) { + int w = obj->Width * PRT_HTMLFM_XPIXEL; + int h = obj->Height * PRT_HTMLFM_YPIXEL; + 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"); + return -1; + } + + // Capture image to buffer + 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"); + 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); + } + + // 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); + } + + // lifetime end: img + nmFree(base64Image, strlen(base64Image)); } - prt_htmlfm_OutputPrintf(context, "", - context->Session->ImageExtDir, id, w, h); - if (obj->URL && !strchr(obj->URL, '"')) - { - prt_htmlfm_Output(context, "", 4); - } - } - break; + 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, @@ -756,149 +890,150 @@ 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 cur_row, cur_col; - 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 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)); - - /** 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. - **/ - 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; + } + + /** 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)); + + // 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 (found != -1) { + for(int i = n_cols-1 ; i >= found; i--) colpos[i+1] = colpos[i]; + colpos[found] = subobj->X; + n_cols++; + } } - if (subobj->X < colpos[i]) - { - found=i; - 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 (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_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 (subobj->Y < rowpos[i]) - { - found=i; - break; + + /** Write the layout table **/ + prt_htmlfm_Output(context, "\n", -1); + 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; } - } - if (found != -1) - { - for(i=n_rows-1;i>=found;i--) rowpos[i+1] = rowpos[i]; - rowpos[found] = subobj->Y; - n_rows++; - } + prt_htmlfm_OutputPrintf(context, "\n", w); } - } - - /** 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; - 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) - { - i++; - cur_col++; + /** 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(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]) { + 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 **/ + 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_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); - + prt_htmlfm_Output(context, "
\n", 14); + } else { + double cur_row = -1; + for(pPrtObjStream subobj=page_obj; subobj; subobj=subobj->YNext) { + if (subobj->Parent == page_obj) { + // 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); + } + prt_htmlfm_Output(context, "
", -1); + cur_row = subobj->Y; + } + + // No need to worry about columns because of flexbox. + prt_htmlfm_Generate_r(context, subobj); + } + } + } /** Write the page footer **/ - prt_htmlfm_OutputPrintf(context, "\n", - (int)((page_obj->MarginBottom+0.001)*PRT_HTMLFM_YPIXEL)); - if (context->Flags & PRT_HTMLFM_F_PAGINATED) + prt_htmlfm_Output(context, "
", -1); + if (context->Flags & PRT_HTMLFM_F_PAGINATED) { prt_htmlfm_Output(context, PRT_HTMLFM_PAGEFOOTER, -1); + } return 0; - } +} int @@ -958,6 +1093,4 @@ prt_htmlfm_Initialize() } return 0; - } - - + } \ No newline at end of file diff --git a/centrallix/report/prtmgmt_v3_fm_html_lm_table.c b/centrallix/report/prtmgmt_v3_fm_html_lm_table.c index 05ba15bf5..d28e39f90 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 */ @@ -62,7 +52,22 @@ prt_htmlfm_GenerateTable(pPrtHTMLfmInf context, pPrtObjStream table) /** Write the table prologue **/ prt_htmlfm_SaveStyle(context, &oldstyle); - prt_htmlfm_Output(context,"\n", -1); + prt_htmlfm_OutputPrintf(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;\">", + 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), "", -1); /** Loop through the subobjects, generating the rows **/ for(row = table->ContentHead; row; row=row->Next) @@ -74,15 +79,49 @@ 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,"\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 +182,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,"
", - (int)(cell->Width*PRT_HTMLFM_XPIXEL), - cell->BGColor); - prt_htmlfm_InitStyle(context, &(cell->TextStyle)); + 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) { prt_htmlfm_Generate_r(context, subobj); @@ -97,7 +136,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 0ecc93aa0..27416dced 100644 --- a/centrallix/report/prtmgmt_v3_fm_html_lm_text.c +++ b/centrallix/report/prtmgmt_v3_fm_html_lm_text.c @@ -4,48 +4,40 @@ #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 */ -/* 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 +46,84 @@ *** 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) { + pPrtObjStream scan; + PrtTextStyle oldstyle; + pPrtTextLMData lm_inf = (pPrtTextLMData)(area->LMData); + + prt_htmlfm_SaveStyle(context, &oldstyle); + + 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); + continue; + } + + 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)); + } + + prt_htmlfm_Generate_r(context, scan); + + pPrtObjStream firstObj = scan; + // 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 + && scan->Justification == scan->Next->Justification + && !(scan->Next->Flags & (PRT_OBJ_F_XSET | PRT_OBJ_F_YSET)) + && (!(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; + } + } + + prt_htmlfm_Output(context, "
", -1); + prt_htmlfm_Output(context, "
", -1); + prt_htmlfm_Output(context, "
", -1); + + 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 @@ -73,23 +131,23 @@ 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 (scan = area->ContentHead; scan; scan = scan->Next) { - 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)) + if (scan->Flags & PRT_OBJ_F_XSET) { - for(j=n_xset;j>i;j--) xset[j] = xset[j-1]; - xset[i] = scan->X; - n_xset++; - break; + 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); @@ -100,23 +158,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", -1); prt_htmlfm_EndBorder(context, &(lm_inf->AreaBorder), area); prt_htmlfm_ResetStyle(context, &oldstyle); - return 0; - } + return 0; + }