Milán Major

netscape-revival

1 branch
Code

lib/xlate/print.c

/*
** This file is mis-named.  It is the main body of code for
** dealing with PostScript translation.  It was originally
** written by Michael Toy, but now that you have read this
** comment, all bugs in this code will be automatically
** assigned to you.
*/

#if 1 /* kill 'em all */
# undef X_PLUGINS
#endif /* 1 -- kill 'em all */


#include "xlate_i.h"
#ifdef X_PLUGINS
#include "np.h"
#endif /* X_PLUGINS */
#include <libi18n.h>

PRIVATE void
default_completion(PrintSetup *p)
{
  XP_FileClose(p->out);
  p->out = NULL;
}

typedef struct {
    int32	start;
    int32	end;
    float	scale;
} InterestingPRE;

static int small_sizes[7] = { 6, 8, 10, 12, 14, 18, 24 };
static int medium_sizes[7] = { 8, 10, 12, 14, 18, 24, 36 };
static int large_sizes[7] = { 10, 12, 14, 18, 24, 36, 48 };
static int huge_sizes[7] = { 12, 14, 18, 24, 36, 48, 72 };

MODULE_PRIVATE int
scale_factor(MWContext *cx, int size, int fontmask)
{
  int bigness;

  size--;
  if (size >= 7)
    size = 6;
  if (size < 0)
    size = 0;
  if (cx->prSetup->sizes)
    return cx->prSetup->sizes[size];
  bigness = cx->prSetup->bigger;
  if (fontmask & LO_FONT_FIXED)
    bigness--;
  switch (bigness)
    {
    case -2: return small_sizes[size];
    case -1: return small_sizes[size];
    case 0: return medium_sizes[size];
    case 1: return large_sizes[size];
    case 2: return huge_sizes[size];
    }
  return 12;
}

MODULE_PRIVATE void
PSFE_SetCallNetlibAllTheTime(MWContext *cx)
{
  if (cx->prInfo->scnatt)
    (*cx->prInfo->scnatt)(NULL);
}

MODULE_PRIVATE void
PSFE_ClearCallNetlibAllTheTime(MWContext *cx)
{
  if (cx->prInfo->ccnatt)
    (*cx->prInfo->ccnatt)(NULL);
}

PUBLIC void
XL_InitializePrintSetup(PrintSetup *p)
{
    XP_BZERO(p, sizeof *p);
    p->right = p->left = .75 * 72;
    p->bottom = p->top = 72;

    p->width = 72 * 8.5;
    p->height = 72 * 11;

    p->reverse = FALSE;
    p->color = TRUE;
    p->landscape = FALSE;
    p->n_up = 1;
    p->bigger = 0;
    p->completion = default_completion;
    p->dpi = 96.0;
    p->underline = TRUE;
    p->scale_pre = TRUE;
    p->scale_images = TRUE;
    p->rules = 1.0;
}

/*
** Default completion routine for process started with NET_GetURL.
** Just save the status.  We will be called again when all connections
** associated wiht this context chut down, and there is where the
** status variable is used.
*/
PRIVATE void
ps_alldone(URL_Struct *URL_s, int status, MWContext *window_id)
{
    window_id->prSetup->status = status;
}

/*
** Called when everything is done and the whole doc has been fetched
** successfully. It draws the document one page at a time, in the order
** specified by the user.
**
** XXX Problems
**	If items fetched properly the first time, but not the second,
**	that fact is never ever passed back to the user.  This might
**	occur if, for example the doc and all it's images were bigger than
**	the caches, and the host machine went down between the first
**	and second passes.
*/
PRIVATE void xl_generate_postscript(MWContext *cx)
{
    int pn;

    /*
    ** This actually makes a second pass through the document, finding
    ** the appropriate page breaks.
    */
    XP_LayoutForPrint(cx, cx->prInfo->doc_height);

    /*
    ** Pass 3.  For each page, generate the matching postscript.
    */
    cx->prInfo->phase = XL_DRAW_PHASE;
    xl_begin_document(cx);
    for (pn = 0; pn < cx->prInfo->n_pages; pn++) {
	int page;
 	if (cx->prSetup->reverse)
	    page = cx->prInfo->n_pages - pn - 1;
	else
	    page = pn;
	xl_begin_page(cx, page);
	XP_DrawForPrint(cx, page);
	xl_end_page(cx,page);
    }
    xl_end_document(cx);
}
 
/*
** XL_TranslatePostscript:
** 	This is the main routine for postscript translation.
**
**	context - Front end context containing a function pointer table funcs,
**		   used to learn how to bonk the netlib when appropriate.
**	url - This is the URL that is to be printed.
**	pi - This is a structure describing all the options for controlling
**	     the translation process.
**
** XXX This routine should check for errors (like malloc failing) and have
** a return value which indicates whether or not a translation was actually
** going to happen.
**
** The completion routine in "pi" is called when the translation is complete.
** The value passed to the completion routine is the status code passed by
** netlib when the docuement and it's associated files are all fetched.
*/

PUBLIC void
XL_TranslatePostscript(MWContext *context, URL_Struct *url_struct, PrintSetup *pi)
{
    int nfd;
    MWContext* print_context = XP_NEW_ZAP(MWContext);
    IL_IRGB tp;
    ContextFuncs *cx_funcs = context->funcs;

    XP_BZERO(print_context, sizeof (MWContext));

    print_context->type = MWContextPostScript;

    /* inherit character set */
    print_context->doc_csid = INTL_DefaultDocCharSetID(context);
    print_context->win_csid = INTL_DocToWinCharSetID(print_context->doc_csid);

    print_context->funcs = XP_NEW(ContextFuncs);
#define MAKE_FE_FUNCS_PREFIX(f) PSFE_##f
#define MAKE_FE_FUNCS_ASSIGN print_context->funcs->
#include "mk_cx_fn.h"

    /*
    ** Coordinate space is 720 units to the inch.  Space we are converting
    ** from is "screen" coordinates, which we will assume for the sake of
    ** argument to be 72 dpi.  This is just a misguided attempt to account
    ** for fractional character placement to give more pleasing text layout.
    */
    print_context->convertPixX = INCH_TO_PAGE(1) / pi->dpi;
    print_context->convertPixY = INCH_TO_PAGE(1) / pi->dpi;
    xl_initialize_translation(print_context, pi);
    pi = print_context->prSetup;
    XP_InitializePrintInfo(print_context);
    /* Bail out if we cannot get memory for print info */
    if (print_context->prInfo == NULL)
	return;
    print_context->prInfo->phase = XL_LOADING_PHASE;
    print_context->prInfo->page_width = (pi->width - pi->left - pi->right);
    print_context->prInfo->page_height = (pi->height - pi->top - pi->bottom);
    print_context->prInfo->page_break = print_context->prInfo->page_height;
    print_context->prInfo->doc_title = XP_STRDUP(url_struct->address);
#ifdef LATER
    print_context->prInfo->interesting = NULL;
    print_context->prInfo->in_pre = FALSE;
#endif
    if (cx_funcs) {
	print_context->prInfo->scnatt = cx_funcs->SetCallNetlibAllTheTime;
	print_context->prInfo->ccnatt = cx_funcs->ClearCallNetlibAllTheTime;
    }
    
    tp.red = tp.green = tp.blue = 0xff;
    if (pi->color && pi->deep_color)
	IL_EnableTrueColor (print_context, 32, 16, 8, 0, 8, 8, 8, &tp, FALSE);
    else
	IL_EnableTrueColor (print_context, 16, 8, 4, 0, 4, 4, 4, &tp, FALSE);
    IL_DisableLowSrc (print_context);
    print_context->prSetup->url = url_struct;
    print_context->prSetup->status = -1;
    url_struct->position_tag = 0;

	/* strip off any named anchor information so that we don't
	 * truncate the document when quoting or saving
	 */
	if(url_struct->address)
		XP_STRTOK(url_struct->address, "#");

    nfd = NET_GetURL (url_struct,
	      FO_SAVE_AS_POSTSCRIPT,
	      print_context,
	      ps_alldone);
}

#ifndef max
#define max(a,b) ((a)>(b)?(a):(b))
#endif
#ifndef min
#define min(a,b) ((a)<(b)?(a):(b))
#endif

static void
measure_non_latin1_text(MWContext *cx, PS_FontInfo *f, unsigned char *cp,
	int start, int last, float sf, LO_TextInfo *text_info)
{
	int	charSize;
	int	height;
	int	i;
	int	left;
	int	right;
	int	square;
	int	width;
	int	x;
	int	y;

	width = height = left = right = x = y = 0;

	square = cx->prSetup->otherFontWidth;

	i = start;
	while (i <= last)
	{
		if ((*cp) & 0x80)
		{
			while ((i <= last) && ((*cp) & 0x80))
			{
				if (INTL_IsHalfWidth(cx, cp))
				{
					width = x + square/2;
					right = max(right, x + square*45/100);
					x += square/2;
				}
				else
				{
					width = x + square;
					right = max(right, x + square*9/10);
					x += square;
				}
				height = max(height, y + square*7/10);
				left = min(left, x + square/25);
				charSize = INTL_CharLen(cx->win_csid, cp);
				i += charSize;
				cp += charSize;
			}
		}
		else
		{
			while ((i <= last) && (!((*cp) & 0x80)))
			{
				PS_CharInfo *temp;
	
				temp = f->chars + *cp;
				width = max(width, x + temp->wx);
				height = max(height, y + temp->charBBox.ury);
				left = min(left, x + temp->charBBox.llx);
				right = max(right, x + temp->charBBox.urx);
				x += temp->wx;
				y += temp->wy;
				i++;
				cp++;
			}
		}
	}
	/*
	text_info->max_height = height * sf;
	*/
	text_info->max_width = width * sf;
	text_info->lbearing = left * sf;
	text_info->rbearing = right * sf;
}

PRIVATE void
ps_measure_text(MWContext *cx, LO_TextStruct *text,
		LO_TextInfo *text_info, int start, int last)
{
    PS_FontInfo *f;
    float sf;
    int x, y, left, right, height, width;
    int i;
    unsigned char *cp;

    assert(text->text_attr->fontmask >= 0 && text->text_attr->fontmask < N_FONTS);
    f = PSFE_MaskToFI[text->text_attr->fontmask];
    assert(f != NULL);
    /*
    ** Font info is scale by 1000, I want everything to be in points*10,
    ** so the scale factor is 1000/10 =>100
    */
    sf = scale_factor(cx, text->text_attr->size, text->text_attr->fontmask) / 100.0;

    text_info->ascent = (f->fontBBox.ury * sf);
    text_info->descent = -(f->fontBBox.lly * sf);

    width = height = left = right = x = y = 0.0;
    cp = ((unsigned char*) text->text)+start;
    if (cx->prSetup->otherFontName) {
	measure_non_latin1_text(cx, f, cp, start, last, sf, text_info);
	return;
    }
    for (i = start; i <= last; cp++, i++) {
	PS_CharInfo *temp;

	temp = f->chars + *cp;
	width = max(width, x + temp->wx);
	height = max(height, y + temp->charBBox.ury);
	left = min(left, x + temp->charBBox.llx);
	right = max(right, x + temp->charBBox.urx);
	x += temp->wx;
	y += temp->wy;
    }
    text_info->max_width = width * sf;
    text_info->lbearing = left * sf;
    text_info->rbearing = right * sf;
}

static char *months[12] =	{
  "January", "February", "March", "April", "May", "June", "July", "August",
  "September", "October", "November", "December"
};

/*
** Here's a lovely hack.  This routine draws the header or footer for a page.
*/

void
xl_annotate_page(MWContext *cx, char *template, int y, int delta_dir, int pn)
{
  float sf;
  int as, dc, ty;
  char left[300], middle[300], right[300], *bp, *fence;

#ifdef DEBUG_jwz
  int top_ink_margin = cx->prSetup->top / 2;
  int bottom_ink_margin = cx->prSetup->bottom / 2;
#endif /* !DEBUG_jwz */


  if (template == NULL)
    return;

  sf = scale_factor(cx, 1, LO_FONT_NORMAL) / 10.0;
#ifdef DEBUG_jwz
  sf /= 10.0;  /* this was WRONG!  It's 100x, not 10x! */
#endif /* !DEBUG_jwz */

  as = PSFE_MaskToFI[LO_FONT_NORMAL]->fontBBox.ury * sf;
  dc = -PSFE_MaskToFI[LO_FONT_NORMAL]->fontBBox.lly * sf;

#ifdef DEBUG_jwz
  y = cx->prInfo->page_topy;		/* move to this page's top origin */

  if (delta_dir == -1)			/* if at top, move back over tmargin */
    y -= cx->prSetup->top - top_ink_margin;
  else					/* else move over body and bmargin */
    y += cx->prInfo->page_height + cx->prSetup->bottom - bottom_ink_margin;

  ty = y;
  ty -= (as + dc) * delta_dir;		/* position bottom of font */

  y = ty - ((as + dc) * delta_dir);	/* reposition y for <HR> */
  if (delta_dir == -1) y -= as;

#else  /* !DEBUG_jwz */
  y += cx->prInfo->page_break;

  ty = y;
  if (delta_dir == 1)
  {
    y += (dc * delta_dir);
    ty = y + as + dc;
  } else {
    y -= (as + dc);
    ty = y - (dc + dc);
  }
#endif /* !DEBUG_jwz */

  bp = left;
  fence = left + sizeof left - 1;  
  *left = *middle = *right = '\0';
  while (*template != '\0')
  {
    int useit;
    int my_pn;
    
    useit = 1;
    
    my_pn = pn;
    if (*template == '%')
    {
      useit = 0;
      switch (*++template)
      {
      default:
	useit = 1;
	break;
      case '\0':
	break;
      case 'u': case 'U':
      {
	char *up;
	up = cx->prSetup->url->address;
#ifdef DEBUG_jwz
        if (!strncasecmp (up, "file:", 5))
          {
            char *s = strrchr (up, '/');
            if (!s) s = strrchr (up, '\\');
            if (!s) s = strrchr (up, ':');
            if (s) up = s+1;
          }
        else if (!strncasecmp (up, "mailbox:", 8))
          up = "";

#endif /* DEBUG_jwz */
	while (*up != '\0' && bp < fence)
	  *bp++ = *up++;
	break;
      }
      case 't': case 'T':
      {
	char *tp;
	tp = cx->prInfo->doc_title;
#ifdef DEBUG_jwz
        if (!tp || !*tp || !strcmp (tp, cx->prSetup->url->address))
          tp = "Untitled";
        else if (!strncasecmp (cx->prSetup->url->address, "mailbox:", 8))
          tp = "";
#endif /* DEBUG_jwz */
	while (*tp != '\0' && bp < fence)
	  *bp++ = *tp++;
	break;
      }
      case 'm': case 'M':
	*bp = '\0';
	bp = middle;
	fence = middle + sizeof middle - 1;
	break;
      case 'r': case 'R':
	*bp = '\0';
	bp = right;
	fence = right + sizeof right - 1;
	break;
      case 's': case 'S':
	xl_moveto(cx, 0, y);
	xl_box(cx, cx->prInfo->page_width, POINT_TO_PAGE(1));
	xl_fill(cx);
	break;
      case 'n': case 'N':
	my_pn = cx->prInfo->n_pages - 1;
      case 'p': case 'P':
      {
  
	char bf[20], *pp;
	sprintf(bf, "%d", my_pn+1);
	pp = bf;
	while (*pp && bp < fence)
	  *bp++ = *pp++;
	break;
      }	

      case 'd':
      case 'D':
      {
	time_t now;
	struct tm *tp;
	char bf[50], *dp;
	
	now = time(NULL);
	tp = localtime(&now);
#ifdef DEBUG_jwz	    /* I like a different date format than mtoy... */
	sprintf(bf, "%d-%c%c%c-%04d",
                tp->tm_mday,
		months[tp->tm_mon][0],
                months[tp->tm_mon][1],
                months[tp->tm_mon][2],
                (1900 + tp->tm_year));
#else  /* !DEBUG_jwz */
	sprintf(bf, "%s %d, %d",
		months[tp->tm_mon], tp->tm_mday, tp->tm_year+1900);
#endif /* !DEBUG_jwz */
	dp = bf;
	while (*dp && bp < fence)
	  *bp++ = *dp++;
      }
      }
      if (useit == 0 && *template != '\0')
	template++;
    }
    if (useit && bp < fence)
      *bp++ = *template++;
  }
  *bp = '\0';
  
  XP_FilePrintf(cx->prSetup->out, "%d f0 ", scale_factor(cx, 1, LO_FONT_NORMAL));
  if (*left != '\0')
  {
    xl_moveto(cx, 0, ty);
    xl_show(cx, left, strlen(left), "");
  }
  if (*middle != '\0') 
  {
    xl_moveto(cx, cx->prInfo->page_width / 2, ty);
    xl_show(cx, middle, strlen(middle), "c");
  }
  if (*right != '\0')
  {
    xl_moveto(cx, cx->prInfo->page_width, ty);
    xl_show(cx, right, strlen(right), "r");
  }
}


MODULE_PRIVATE int
PSFE_GetTextInfo(MWContext *cx, LO_TextStruct *text, LO_TextInfo *text_info)
{
    ps_measure_text(cx, text, text_info, 0, text->text_len-1);
    return 0;
}

MODULE_PRIVATE void
PSFE_LayoutNewDocument(MWContext *cx, URL_Struct *url, int32 *w, int32 *h, int32 *mw, int32* mh)
{
    *w = cx->prInfo->page_width;
    *h = cx->prInfo->page_height;
    *mw = *mh = 0;
}

MODULE_PRIVATE void
PSFE_FinishedLayout(MWContext *cx)
{
  IL_EndPage(cx);
}

static void
display_non_latin1_text(MWContext *cx, unsigned char *str, int len, int sf,
	int fontmask)
{
	int		charSize;
	int		convert;
	XP_File		f;
	unsigned char	*freeThis;
	CCCDataObject	*obj;
	unsigned char	*out;
	int		outlen;
	unsigned char	*start;

	obj = INTL_CreateCharCodeConverter();
	if (!obj)
	{
		return;
	}
	if (cx->win_csid != cx->prSetup->otherFontCharSetID)
	{
		convert = INTL_GetCharCodeConverter(cx->win_csid,
			cx->prSetup->otherFontCharSetID, obj);
	}
	else
	{
		convert = 0;
	}

	f = cx->prSetup->out;
	freeThis = NULL;

	while (len > 0)
	{
		if ((*str) & 0x80)
		{
			start = str;
			while ((len > 0) && ((*str) & 0x80))
			{
				charSize = INTL_CharLen(cx->win_csid, str);
				len -= charSize;
				str += charSize;
			}
			XP_FilePrintf(f, "%d of\n", sf);
			if (convert)
			{
				out = INTL_CallCharCodeConverter(obj, start,
					str - start);
				outlen = strlen(out);
				freeThis = out;
			}
			else
			{
				out = start;
				outlen = str - start;
			}
			XP_FilePrintf(f, "<");
			while (outlen > 0)
			{
				XP_FilePrintf(f, "%02x", *out);
				outlen--;
				out++;
			}
			XP_FilePrintf(f, "> show\n");
			if (freeThis)
			{
				free(freeThis);
				freeThis = NULL;
			}
		}
		else
		{
			start = str;
			while ((len > 0) && (!((*str) & 0x80)))
			{
				len--;
				str++;
			}
			XP_FilePrintf(f, "%d f%d\n", sf, fontmask);
			xl_show(cx, (char *) start, str - start, "");
		}
	}

	INTL_DestroyCharCodeConverter(obj);
}


MODULE_PRIVATE void
PSFE_DisplaySubtext(MWContext *cx, int iLocation, LO_TextStruct *text,
		    int32 start_pos, int32 end_pos, XP_Bool notused)
{
  int x, y;
  LO_TextInfo ti;
  int sf;

  x = text->x + text->x_offset;
  y = text->y + text->y_offset;
  ps_measure_text(cx, text, &ti, 0, start_pos-1);
  y += ti.ascent;		/* Move to baseline */
  x += ti.max_width;		/* Skip over un-displayed text */
  if (!XP_CheckElementSpan(cx, (LO_Any*) text))
    return;

  sf = scale_factor(cx, text->text_attr->size, text->text_attr->fontmask);
  xl_moveto(cx, x, y);
  if (cx->prSetup->otherFontName) {
    display_non_latin1_text(cx, ((unsigned char *) (text->text)) + start_pos,
			    end_pos - start_pos + 1, sf,
			    (int) text->text_attr->fontmask);
    return;
  }
  XP_FilePrintf(cx->prSetup->out, "%d f%d\n", sf,
		(int) text->text_attr->fontmask);
  xl_show(cx, ((char*) text->text) + start_pos, end_pos - start_pos + 1,"");
}

MODULE_PRIVATE void
PSFE_DisplayText(MWContext *cx, int iLocation, LO_TextStruct *text, XP_Bool b)
{
    (cx->funcs->DisplaySubtext)(cx, iLocation, text, 0, text->text_len-1, b);
}

/*
** Called at the end of each "Line" which could be a tiny line-section
** inside of a table cell or subdoc.
*/
MODULE_PRIVATE void
PSFE_DisplayLineFeed(MWContext *cx, int iLocation, LO_LinefeedStruct *line_feed,
		     XP_Bool b)
{
#ifdef NOT_THIS_TIME
    if (cx->prInfo->layout_phase) {
	if (cx->prInfo->in_pre) {
	    if (cx->prInfo->pre_start == -1)
		cx->prInfo->pre_start = line_feed->y;
	    cx->prInfo->pre_end = line_feed->y+line_feed->line_height;
	}
	emit_y(cx, line_feed->y, line_feed->y+line_feed->line_height);
    } else if (cx->prInfo->interesting != NULL) {
	InterestingPRE *p;
	p = (InterestingPRE *) XP_ListPeekTopObject(cx->prInfo->interesting);
	if (p == NULL) {
	    XP_DELETE(cx->prInfo->interesting);
	    cx->prInfo->interesting = NULL;
	} else if (line_feed->y + line_feed->line_height >= p->end) {
	    (void) XP_ListRemoveTopObject(cx->prInfo->interesting);
	    XP_DELETE(p);
	}
    }
#endif
}

MODULE_PRIVATE void
PSFE_DisplayHR(MWContext *cx, int iLocation , LO_HorizRuleStruct *HR)
{
  int delta;
  int top, bottom;

  if (!XP_CheckElementSpan(cx, (LO_Any*) HR))
    return;
  delta = (HR->height - HR->height*cx->prSetup->rules) / 2;
  top = HR->y + HR->y_offset + delta;
  bottom = top + HR->height*cx->prSetup->rules;


  xl_moveto(cx, HR->x+HR->x_offset, top);
  xl_box(cx, HR->width, HR->height*cx->prSetup->rules);
  xl_fill(cx);
}

MODULE_PRIVATE void
PSFE_DisplayBullet(MWContext *cx, int iLocation, LO_BullettStruct *bullet)
{
  int top;

  if (!XP_CheckElementSpan(cx, (LO_Any*) bullet))
    return;
  top = bullet->y + bullet->y_offset;

  switch (bullet->bullet_type) {
    case BULLET_ROUND:
      xl_moveto(cx,
		 bullet->x+bullet->x_offset+bullet->height/2,
		 top+bullet->height/2);
      xl_circle(cx, bullet->width, bullet->height);
      xl_stroke(cx);
      break;
    case BULLET_BASIC:
      xl_moveto(cx,
		 bullet->x+bullet->x_offset+bullet->height/2,
		 top+bullet->height/2);
      xl_circle(cx, bullet->width, bullet->height);
      xl_fill(cx);
      break;
    case BULLET_SQUARE:
      xl_moveto(cx, bullet->x+bullet->x_offset, top);
      xl_box(cx, bullet->width, bullet->height);
      xl_fill(cx);
      break;
#ifdef DEBUG
      default:
	  XP_Trace("Strange bullet type %d", bullet->bullet_type);
#endif
  }
}

PUBLIC void PSFE_AllConnectionsComplete(MWContext *cx) 
{
      /*
      ** All done, time to let everything go.
      */
  if (cx->prSetup->status >= 0)
    xl_generate_postscript(cx);
  (*cx->prSetup->completion)(cx->prSetup);
  LO_DiscardDocument(cx);
  IL_DeleteImages(cx);
  xl_finalize_translation(cx);
  XP_FREE(cx->prInfo->doc_title);
  XP_CleanupPrintInfo(cx);
  XP_DELETE(cx->funcs);
  XP_DELETE(cx);
}

MODULE_PRIVATE void
PSFE_DisplayFormElement(MWContext *cx, int loc,LO_FormElementStruct *element)
{
}

MODULE_PRIVATE void
PSFE_SetDocDimension(MWContext *cx, int iloc, int32 iWidth, int32 iLength)
{
  cx->prInfo->doc_width = iWidth;
  cx->prInfo->doc_height = iLength;
}

MODULE_PRIVATE void
PSFE_SetDocTitle(MWContext * cx, char * title)
{
    XP_FREE(cx->prInfo->doc_title);
    cx->prInfo->doc_title = XP_STRDUP(title);
}

MODULE_PRIVATE char *
PSFE_TranslateISOText(MWContext *cx, int charset, char *ISO_Text)
{
    return ISO_Text;
}

MODULE_PRIVATE void
PSFE_BeginPreSection(MWContext* cx)
{
#ifdef LATER
    cx->prInfo->scale = 1.0;
    cx->prInfo->in_pre = TRUE;
    cx->prInfo->pre_start = -1;
#endif
}

MODULE_PRIVATE void
PSFE_EndPreSection(MWContext* cx)
{
#ifdef LATER
    if (cx->prInfo->layout_phase && cx->prInfo->scale != 1.0) {
	InterestingPRE *p = XP_NEW(InterestingPRE);
	p->start = cx->prInfo->pre_start;
	p->end = cx->prInfo->pre_end;
	p->scale = max(cx->prInfo->scale, 0.25);
	if (cx->prInfo->interesting == NULL)
	    cx->prInfo->interesting = XP_ListNew();
	XP_ListAddObjectToEnd(cx->prInfo->interesting, p);
    }
    cx->prInfo->in_pre = FALSE;
#endif
}

void PSFE_DisplayTable(MWContext *cx, int iLoc, LO_TableStruct *table)
{
  if (table->border_width != 0 && XP_CheckElementSpan(cx, (LO_Any*) table)) {
    int y = table->y+table->y_offset;
    xl_draw_border(cx, table->x+table->x_offset, y,
		    table->width, table->height, table->border_width);
  }
}

void PSFE_DisplayCell(MWContext *cx, int iLoc,LO_CellStruct *cell)
{
  if (cell->border_width != 0 && XP_CheckElementSpan(cx, (LO_Any*) cell)) {
    int y = cell->y+cell->y_offset;
    xl_draw_border(cx, cell->x+cell->x_offset, y,
		    cell->width, cell->height, cell->border_width);
  }
}

MODULE_PRIVATE char *
PSFE_PromptPassword(MWContext *cx, const char *msg)
{
  if (cx->prSetup->cx != NULL)
    return FE_PromptPassword(cx->prSetup->cx, msg);

  return NULL;
}


/***************************
 * Plugin printing support *
 ***************************/
#ifndef X_PLUGINS
/* Plugins are disabled */
void PSFE_GetEmbedSize(MWContext *context, LO_EmbedStruct *embed_struct, NET_ReloadMethod force_reload) {}
void PSFE_FreeEmbedElement(MWContext *context, LO_EmbedStruct *embed_struct) {}
void PSFE_DisplayEmbed(MWContext *context, int iLocation, LO_EmbedStruct *embed_struct) {}
#else
void
PSFE_FreeEmbedElement (MWContext *context, LO_EmbedStruct *embed_struct)
{
    NPL_EmbedDelete(context, embed_struct);
    embed_struct->FE_Data = 0;
}

void
PSFE_DisplayEmbed (MWContext *context,
		  int iLocation, LO_EmbedStruct *embed_struct)
{
    NPPrintCallbackStruct npPrintInfo;
    NPEmbeddedApp *eApp;
    NPPrint npprint;

    if (!embed_struct) return;
    eApp = (NPEmbeddedApp *)embed_struct->FE_Data;
    if (!eApp) return;

    npprint.mode = NP_EMBED;
    npprint.print.embedPrint.platformPrint = NULL;
    npprint.print.embedPrint.window.window = NULL;
    npprint.print.embedPrint.window.x =
      embed_struct->x + embed_struct->x_offset;
    npprint.print.embedPrint.window.y =
      embed_struct->y + embed_struct->y_offset;
    npprint.print.embedPrint.window.width = embed_struct->width;
    npprint.print.embedPrint.window.height = embed_struct->height;
    
    npPrintInfo.type = NP_PRINT;
    npPrintInfo.fp = context->prSetup->out;
    npprint.print.embedPrint.platformPrint = (void *) &npPrintInfo;

    NPL_Print(eApp, &npprint);	
}

void
PSFE_GetEmbedSize (MWContext *context, LO_EmbedStruct *embed_struct,
		  NET_ReloadMethod force_reload)
{
  NPEmbeddedApp *eApp = (NPEmbeddedApp *)embed_struct->FE_Data;
  
  if(eApp) return;

  /* attempt to make a plugin */
  if(!(eApp = NPL_EmbedCreate(context, embed_struct)) ||
     (embed_struct->extra_attrmask & LO_ELE_HIDDEN)) {
    return;
  }

  /* Determine if this is a fullpage plugin */
  if ((embed_struct->attribute_cnt > 0) &&
      (!strcmp(embed_struct->attribute_list[0], "src")) &&
      (!strcmp(embed_struct->value_list[0], "internal-external-plugin")))
    {
      embed_struct->width = context->prInfo->page_width;
      embed_struct->height = context->prInfo->page_height;
    }

  embed_struct->FE_Data = (void *)eApp;

  if (NPL_EmbedStart(context, embed_struct, eApp) != NPERR_NO_ERROR) {
    /* Spoil sport! */
    embed_struct->FE_Data = NULL;
    return;
  }
}
#endif /* !X_PLUGINS */