home *** CD-ROM | disk | FTP | other *** search
/ Tools / WinSN5.0Ver.iso / NETSCAP.50 / WIN1998.ZIP / ns / lib / xlate / print.c < prev    next >
Encoding:
C/C++ Source or Header  |  1998-04-08  |  55.4 KB  |  2,020 lines

  1. /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
  2.  *
  3.  * The contents of this file are subject to the Netscape Public License
  4.  * Version 1.0 (the "NPL"); you may not use this file except in
  5.  * compliance with the NPL.  You may obtain a copy of the NPL at
  6.  * http://www.mozilla.org/NPL/
  7.  *
  8.  * Software distributed under the NPL is distributed on an "AS IS" basis,
  9.  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
  10.  * for the specific language governing rights and limitations under the
  11.  * NPL.
  12.  *
  13.  * The Initial Developer of this code under the NPL is Netscape
  14.  * Communications Corporation.  Portions created by Netscape are
  15.  * Copyright (C) 1998 Netscape Communications Corporation.  All Rights
  16.  * Reserved.
  17.  */
  18. /*
  19. ** This file is mis-named.  It is the main body of code for
  20. ** dealing with PostScript translation.  It was originally
  21. ** written by Michael Toy, but now that you have read this
  22. ** comment, all bugs in this code will be automatically
  23. ** assigned to you.
  24. */
  25.  
  26. #include "xlate_i.h"
  27. #include "xplocale.h"
  28. #include "libimg.h"             /* Image Library public API. */
  29.  
  30. #ifdef X_PLUGINS
  31. #include "np.h"
  32. #endif /* X_PLUGINS */
  33. #include <libi18n.h>
  34. #include "il_util.h"
  35. #include "intl_csi.h"
  36.  
  37. #ifdef JAVA
  38. #include "java.h"
  39. #endif
  40.  
  41. #define THICK_LINE_THICKNESS    10
  42. #define THIN_LINE_THICKNESS     5
  43.  
  44. #define LIGHTER_GREY            10
  45. #define LIGHT_GREY              8
  46. #define GREY                    5
  47. #define DARK_GREY               2
  48. #define DARKER_GREY             0
  49.  
  50. PRIVATE void
  51. default_completion(PrintSetup *p)
  52. {
  53.   XP_FileClose(p->out);
  54.   p->out = NULL;
  55. }
  56.  
  57. typedef struct {
  58.     int32    start;
  59.     int32    end;
  60.     float    scale;
  61. } InterestingPRE;
  62.  
  63. static int small_sizes[7] = { 6, 8, 10, 12, 14, 18, 24 };
  64. static int medium_sizes[7] = { 8, 10, 12, 14, 18, 24, 36 };
  65. static int large_sizes[7] = { 10, 12, 14, 18, 24, 36, 48 };
  66. static int huge_sizes[7] = { 12, 14, 18, 24, 36, 48, 72 };
  67.  
  68. MODULE_PRIVATE int
  69. scale_factor(MWContext *cx, int size, int fontmask)
  70. {
  71.   int bigness;
  72.  
  73.   size--;
  74.   if (size >= 7)
  75.     size = 6;
  76.   if (size < 0)
  77.     size = 0;
  78.   if (cx->prSetup->sizes)
  79.     return cx->prSetup->sizes[size];
  80.   bigness = cx->prSetup->bigger;
  81.   if (fontmask & LO_FONT_FIXED)
  82.     bigness--;
  83.   switch (bigness)
  84.     {
  85.     case -2: return small_sizes[size];
  86.     case -1: return small_sizes[size];
  87.     case 0: return medium_sizes[size];
  88.     case 1: return large_sizes[size];
  89.     case 2: return huge_sizes[size];
  90.     }
  91.   return 12;
  92. }
  93.  
  94. MODULE_PRIVATE void
  95. PSFE_SetCallNetlibAllTheTime(MWContext *cx)
  96. {
  97.   if (cx->prInfo->scnatt)
  98.     (*cx->prInfo->scnatt)(NULL);
  99. }
  100.  
  101. MODULE_PRIVATE void
  102. PSFE_ClearCallNetlibAllTheTime(MWContext *cx)
  103. {
  104.   if (cx->prInfo->ccnatt)
  105.     (*cx->prInfo->ccnatt)(NULL);
  106. }
  107.  
  108. PUBLIC void
  109. XL_InitializePrintSetup(PrintSetup *p)
  110. {
  111.     XP_BZERO(p, sizeof *p);
  112.     p->right = p->left = .75 * 72;
  113.     p->bottom = p->top = 72;
  114.  
  115.     p->width = 72 * 8.5;
  116.     p->height = 72 * 11;
  117.  
  118.     p->reverse = FALSE;
  119.     p->color = TRUE;
  120.     p->landscape = FALSE;
  121.     p->n_up = 1;
  122.     p->bigger = 0;
  123.     p->completion = default_completion;
  124.     p->dpi = 96.0;
  125.     p->underline = TRUE;
  126.     p->scale_pre = TRUE;
  127.     p->scale_images = TRUE;
  128.     p->rules = 1.0;
  129.     p->header = "%t%r%u";
  130.     p->footer = "%p%r%d";
  131. }
  132.  
  133. /*
  134. ** Default completion routine for process started with NET_GetURL.
  135. ** Just save the status.  We will be called again when all connections
  136. ** associated wiht this context chut down, and there is where the
  137. ** status variable is used.
  138. */
  139. PRIVATE void
  140. ps_alldone(URL_Struct *URL_s, int status, MWContext *window_id)
  141. {
  142.     window_id->prSetup->status = status;
  143. }
  144.  
  145. /*
  146. ** Called when everything is done and the whole doc has been fetched
  147. ** successfully. It draws the document one page at a time, in the order
  148. ** specified by the user.
  149. **
  150. ** XXX Problems
  151. **    If items fetched properly the first time, but not the second,
  152. **    that fact is never ever passed back to the user.  This might
  153. **    occur if, for example the doc and all it's images were bigger than
  154. **    the caches, and the host machine went down between the first
  155. **    and second passes.
  156. */
  157. PRIVATE void xl_generate_postscript(MWContext *cx)
  158. {
  159.     int pn;
  160.  
  161.     /*
  162.     ** This actually makes a second pass through the document, finding
  163.     ** the appropriate page breaks.
  164.     */
  165.     XP_LayoutForPrint(cx, cx->prInfo->doc_height);
  166.  
  167.     /*
  168.     ** Pass 3.  For each page, generate the matching postscript.
  169.     */
  170.     cx->prInfo->phase = XL_DRAW_PHASE;
  171.     xl_begin_document(cx);
  172.     for (pn = 0; pn < cx->prInfo->n_pages; pn++) {
  173.     int page;
  174.      if (cx->prSetup->reverse)
  175.         page = cx->prInfo->n_pages - pn - 1;
  176.     else
  177.         page = pn;
  178.     xl_begin_page(cx, page);
  179.     XP_DrawForPrint(cx, page);
  180.     xl_end_page(cx,page);
  181.     }
  182.     xl_end_document(cx);
  183. }
  184.  
  185. /*
  186. ** XL_TranslatePostscript:
  187. **     This is the main routine for postscript translation.
  188. **
  189. **    context - Front end context containing a function pointer table funcs,
  190. **           used to learn how to bonk the netlib when appropriate.
  191. **    url - This is the URL that is to be printed.
  192. **    pi - This is a structure describing all the options for controlling
  193. **         the translation process.
  194. **
  195. ** XXX This routine should check for errors (like malloc failing) and have
  196. ** a return value which indicates whether or not a translation was actually
  197. ** going to happen.
  198. **
  199. ** The completion routine in "pi" is called when the translation is complete.
  200. ** The value passed to the completion routine is the status code passed by
  201. ** netlib when the docuement and it's associated files are all fetched.
  202. */
  203.  
  204. PUBLIC void
  205. XL_TranslatePostscript(MWContext *context, URL_Struct *url_struct, SHIST_SavedData *saved_data, PrintSetup *pi)
  206. {
  207.     int nfd;
  208.     MWContext* print_context = XP_NewContext();
  209.     uint32 display_prefs;
  210.     IL_DisplayData dpy_data;
  211.     ContextFuncs *cx_funcs = context->funcs;
  212.     int16 print_doc_csid;
  213.     INTL_CharSetInfo print_csi = LO_GetDocumentCharacterSetInfo(print_context);
  214.  
  215.     print_context->type = MWContextPostScript;
  216.  
  217.     /* inherit character set */
  218.     print_doc_csid = INTL_DefaultDocCharSetID(context);
  219.     INTL_SetCSIDocCSID(print_csi, print_doc_csid);
  220.     INTL_SetCSIWinCSID(print_csi, INTL_DocToWinCharSetID(print_doc_csid));
  221.  
  222.     print_context->funcs = XP_NEW(ContextFuncs);
  223. #define MAKE_FE_FUNCS_PREFIX(f) PSFE_##f
  224. #define MAKE_FE_FUNCS_ASSIGN print_context->funcs->
  225. #include "mk_cx_fn.h"
  226.  
  227.     /* Copy the form data into the URL struct. */
  228.     if (saved_data->FormList)
  229.         LO_CloneFormData(saved_data, print_context, url_struct);
  230.   
  231.     /*
  232.     ** Coordinate space is 720 units to the inch.  Space we are converting
  233.     ** from is "screen" coordinates, which we will assume for the sake of
  234.     ** argument to be 72 dpi.  This is just a misguided attempt to account
  235.     ** for fractional character placement to give more pleasing text layout.
  236.     */
  237.     print_context->convertPixX = INCH_TO_PAGE(1) / pi->dpi;
  238.     print_context->convertPixY = INCH_TO_PAGE(1) / pi->dpi;
  239.     xl_initialize_translation(print_context, pi);
  240.     pi = print_context->prSetup;
  241.     XP_InitializePrintInfo(print_context);
  242.     /* Bail out if we cannot get memory for print info */
  243.     if (print_context->prInfo == NULL)
  244.     return;
  245.     print_context->prInfo->phase = XL_LOADING_PHASE;
  246.     print_context->prInfo->page_width = (pi->width - pi->left - pi->right);
  247.     print_context->prInfo->page_height = (pi->height - pi->top - pi->bottom);
  248.     print_context->prInfo->page_break = print_context->prInfo->page_height;
  249.     print_context->prInfo->doc_title = XP_STRDUP(url_struct->address);
  250. #ifdef LATER
  251.     print_context->prInfo->interesting = NULL;
  252.     print_context->prInfo->in_pre = FALSE;
  253. #endif
  254.     if (cx_funcs) {
  255.     print_context->prInfo->scnatt = cx_funcs->SetCallNetlibAllTheTime;
  256.     print_context->prInfo->ccnatt = cx_funcs->ClearCallNetlibAllTheTime;
  257.     }
  258.     
  259.     if (pi->color && pi->deep_color) {
  260.         IL_RGBBits rgb;
  261.  
  262.         rgb.red_bits = 8;
  263.         rgb.red_shift = 16;
  264.         rgb.green_bits = 8;
  265.         rgb.green_shift = 8;
  266.         rgb.blue_bits = 8;
  267.         rgb.blue_shift = 0;
  268.         if (!print_context->color_space)
  269.             print_context->color_space = IL_CreateTrueColorSpace(&rgb, 32);
  270.     }
  271.     else {
  272.         IL_RGBBits rgb;
  273.  
  274.         rgb.red_bits = 4;
  275.         rgb.red_shift = 8;
  276.         rgb.green_bits = 4;
  277.         rgb.green_shift = 4;
  278.         rgb.blue_bits = 4;
  279.         rgb.blue_shift = 0;
  280.         if (!print_context->color_space)
  281.             print_context->color_space = IL_CreateTrueColorSpace(&rgb, 16);
  282.     }
  283.  
  284.     /* Create and initialize the Image Library JMC callback interface.
  285.        Also create an IL_GroupContext for the current context. */
  286.     if (!psfe_init_image_callbacks(print_context)) {
  287.         /* This can only happen if we are out of memory.  Abort printing
  288.            and return. */
  289.         XP_FREE(print_context->prInfo->doc_title);
  290.         XP_CleanupPrintInfo(print_context);
  291.         xl_finalize_translation(print_context);
  292.         IL_ReleaseColorSpace(print_context->color_space);
  293.         XP_DELETE(print_context->funcs);
  294.         XP_DELETE(print_context);
  295.         return;
  296.     }
  297.  
  298.     dpy_data.color_space = print_context->color_space;
  299.     dpy_data.progressive_display = FALSE;
  300.     display_prefs = IL_COLOR_SPACE | IL_PROGRESSIVE_DISPLAY;
  301.     IL_SetDisplayMode (print_context->img_cx, display_prefs, &dpy_data);
  302.  
  303. #ifndef M12N                    /* XXXM12N Obsolete */
  304.     IL_DisableLowSrc (print_context);
  305. #endif /* M12N */
  306.     print_context->prSetup->url = url_struct;
  307.     print_context->prSetup->status = -1;
  308.     url_struct->position_tag = 0;
  309.  
  310.     /* strip off any named anchor information so that we don't
  311.      * truncate the document when quoting or saving
  312.      */
  313.     if(url_struct->address)
  314.         XP_STRTOK(url_struct->address, "#");
  315.  
  316.     nfd = NET_GetURL (url_struct,
  317.           FO_SAVE_AS_POSTSCRIPT,
  318.           print_context,
  319.           ps_alldone);
  320. }
  321.  
  322. #ifndef max
  323. #define max(a,b) ((a)>(b)?(a):(b))
  324. #endif
  325. #ifndef min
  326. #define min(a,b) ((a)<(b)?(a):(b))
  327. #endif
  328.  
  329. static void
  330. measure_non_latin1_text(MWContext *cx, PS_FontInfo *f, unsigned char *cp,
  331.     int start, int last, float sf, LO_TextInfo *text_info)
  332. {
  333.     int    charSize;
  334.     int    height;
  335.     int    i;
  336.     int    left;
  337.     int    right;
  338.     int    square;
  339.     int    width;
  340.     int    x;
  341.     int    y;
  342.     INTL_CharSetInfo csi = LO_GetDocumentCharacterSetInfo(cx);
  343.     int16 win_csid = INTL_GetCSIWinCSID(csi);
  344.  
  345.     width = height = left = right = x = y = 0;
  346.  
  347.     square = cx->prSetup->otherFontWidth;
  348.     text_info->ascent = max(f->fontBBox.ury, cx->prSetup->otherFontAscent) * sf;
  349.  
  350.     i = start;
  351.     while (i <= last)
  352.     {
  353.         if ((*cp) & 0x80)
  354.         {
  355.             while ((i <= last) && ((*cp) & 0x80))
  356.             {
  357.                 if (INTL_IsHalfWidth(win_csid, cp))
  358.                 {
  359.                     width = x + square/2;
  360.                     right = max(right, x + square*45/100);
  361.                     x += square/2;
  362.                 }
  363.                 else
  364.                 {
  365.                     width = x + square;
  366.                     right = max(right, x + square*9/10);
  367.                     x += square;
  368.                 }
  369.                 height = max(height, y + square*7/10);
  370.                 left = min(left, x + square/25);
  371.                 charSize = INTL_CharLen(win_csid, cp);
  372.                 i += charSize;
  373.                 cp += charSize;
  374.             }
  375.         }
  376.         else
  377.         {
  378.             while ((i <= last) && (!((*cp) & 0x80)))
  379.             {
  380.                 PS_CharInfo *temp;
  381.     
  382.                 temp = f->chars + *cp;
  383.                 width = max(width, x + temp->wx);
  384.                 height = max(height, y + temp->charBBox.ury);
  385.                 left = min(left, x + temp->charBBox.llx);
  386.                 right = max(right, x + temp->charBBox.urx);
  387.                 x += temp->wx;
  388.                 y += temp->wy;
  389.                 i++;
  390.                 cp++;
  391.             }
  392.         }
  393.     }
  394.     /*
  395.     text_info->max_height = height * sf;
  396.     */
  397.     text_info->max_width = width * sf;
  398.     text_info->lbearing = left * sf;
  399.     text_info->rbearing = right * sf;
  400. }
  401.  
  402.  
  403. PRIVATE void
  404. ps_measure_text(MWContext *cx, LO_TextStruct *text,
  405.         LO_TextInfo *text_info, int start, int last)
  406. {
  407.     PS_FontInfo *f;
  408.     float sf;
  409.     int x, y, left, right, height, width;
  410.     int i;
  411.     unsigned char *cp;
  412.  
  413.     assert(text->text_attr->fontmask >= 0 && text->text_attr->fontmask < N_FONTS);
  414.     f = PSFE_MaskToFI[text->text_attr->fontmask];
  415.     assert(f != NULL);
  416.     /*
  417.     ** Font info is scale by 1000, I want everything to be in points*10,
  418.     ** so the scale factor is 1000/10 =>100
  419.     */
  420.     sf = scale_factor(cx, text->text_attr->size, text->text_attr->fontmask) / 100.0;
  421.  
  422.     text_info->ascent = (f->fontBBox.ury * sf);
  423.     text_info->descent = -(f->fontBBox.lly * sf);
  424.  
  425.     width = height = left = right = x = y = 0.0;
  426.     cp = ((unsigned char*) text->text)+start;
  427.  
  428.     if (cx->prSetup->otherFontName) {
  429.     measure_non_latin1_text(cx, f, cp, start, last, sf, text_info);
  430.     return;
  431.     }
  432.  
  433.  
  434.     for (i = start; i <= last; cp++, i++) {
  435.     PS_CharInfo *temp;
  436.  
  437.     temp = f->chars + *cp;
  438.     width = max(width, x + temp->wx);
  439.     height = max(height, y + temp->charBBox.ury);
  440.     left = min(left, x + temp->charBBox.llx);
  441.     right = max(right, x + temp->charBBox.urx);
  442.     x += temp->wx;
  443.     y += temp->wy;
  444.     }
  445.     text_info->max_width = width * sf;
  446.     text_info->lbearing = left * sf;
  447.     text_info->rbearing = right * sf;
  448. }
  449.  
  450. /*
  451. ** Here's a lovely hack.  This routine draws the header or footer for a page.
  452. */
  453.  
  454. void
  455. xl_annotate_page(MWContext *cx, char *template, int y, int delta_dir, int pn)
  456. {
  457.   float sf;
  458.   int as, dc, ty;
  459.   char left[300], middle[300], right[300], *bp, *fence;
  460.  
  461.   if (template == NULL)
  462.     return;
  463.  
  464.   sf = scale_factor(cx, 1, LO_FONT_NORMAL) / 10.0;
  465.   as = PSFE_MaskToFI[LO_FONT_NORMAL]->fontBBox.ury * sf;
  466.   dc = -PSFE_MaskToFI[LO_FONT_NORMAL]->fontBBox.lly * sf;
  467.  
  468. #if 0
  469.   y += cx->prInfo->page_break;
  470. #endif
  471.   ty = y;
  472.   y += cx->prInfo->page_topy;
  473.   if (delta_dir == 1)
  474.   {
  475.     y += (dc * delta_dir);
  476. #if 0
  477.     ty = y + as + dc;
  478. #endif
  479.   } else {
  480.     y -= (as + dc);
  481. #if 0
  482.     ty = y - (dc + dc);
  483. #endif
  484.   }
  485.  
  486.   bp = left;
  487.   fence = left + sizeof left - 1;  
  488.   *left = *middle = *right = '\0';
  489.   while (*template != '\0')
  490.   {
  491.     int useit;
  492.     int my_pn;
  493.     
  494.     useit = 1;
  495.     
  496.     my_pn = pn;
  497.     if (*template == '%')
  498.     {
  499.       useit = 0;
  500.       switch (*++template)
  501.       {
  502.       default:
  503.     useit = 1;
  504.     break;
  505.       case '\0':
  506.     break;
  507.       case 'u': case 'U':
  508.       {
  509.     char *up;
  510.     up = cx->prSetup->url->address;
  511.     while (*up != '\0' && bp < fence)
  512.       *bp++ = *up++;
  513.     break;
  514.       }
  515.       case 't': case 'T':
  516.       {
  517.     char *tp;
  518.     tp = cx->prInfo->doc_title;
  519.     while (*tp != '\0' && bp < fence)
  520.       *bp++ = *tp++;
  521.     break;
  522.       }
  523.       case 'm': case 'M':
  524.     *bp = '\0';
  525.     bp = middle;
  526.     fence = middle + sizeof middle - 1;
  527.     break;
  528.       case 'r': case 'R':
  529.     *bp = '\0';
  530.     bp = right;
  531.     fence = right + sizeof right - 1;
  532.     break;
  533.       case 's': case 'S':
  534.     xl_moveto(cx, 0, y);
  535.     xl_box(cx, cx->prInfo->page_width, POINT_TO_PAGE(1));
  536.     xl_fill(cx);
  537.     break;
  538.       case 'n': case 'N':
  539.     my_pn = cx->prInfo->n_pages;
  540.       case 'p': case 'P':
  541.       {
  542.   
  543.     char bf[20], *pp;
  544.     sprintf(bf, "%d of %d", my_pn+1, cx->prInfo->n_pages);
  545.     pp = bf;
  546.     while (*pp && bp < fence)
  547.       *bp++ = *pp++;
  548.     break;
  549.       }    
  550.  
  551.       case 'd':
  552.       case 'D':
  553.       {
  554.     time_t now;
  555.     struct tm *tp;
  556.     char bf[50], *dp;
  557.     
  558.     now = time(NULL);
  559.     tp = localtime(&now);
  560.     FE_StrfTime(cx, bf, 50, XP_DATE_TIME_FORMAT, tp);
  561.  
  562.     dp = bf;
  563.     while (*dp && bp < fence)
  564.       *bp++ = *dp++;
  565.       }
  566.       }
  567.       if (useit == 0 && *template != '\0')
  568.     template++;
  569.     }
  570.     if (useit && bp < fence)
  571.       *bp++ = *template++;
  572.   }
  573.   *bp = '\0';
  574.   
  575.   XP_FilePrintf(cx->prSetup->out, "%d f0 ", scale_factor(cx, 1, LO_FONT_NORMAL));
  576.   if (*left != '\0')
  577.   {
  578.     xl_moveto_loc(cx, cx->prSetup->left/2, ty);
  579.     xl_show(cx, left, strlen(left), "");
  580.   }
  581.   if (*middle != '\0') 
  582.   {
  583.     xl_moveto_loc(cx, cx->prInfo->page_width / 2, ty);
  584.     xl_show(cx, middle, strlen(middle), "c");
  585.   }
  586.   if (*right != '\0')
  587.   {
  588.     xl_moveto_loc(cx, cx->prInfo->page_width+cx->prSetup->left+cx->prSetup->right/2, ty);
  589.     xl_show(cx, right, strlen(right), "r");
  590.   }
  591. }
  592.  
  593. MODULE_PRIVATE int
  594. PSFE_GetTextInfo(MWContext *cx, LO_TextStruct *text, LO_TextInfo *text_info)
  595. {
  596.     ps_measure_text(cx, text, text_info, 0, text->text_len-1);
  597.     return 0;
  598. }
  599.  
  600. MODULE_PRIVATE void
  601. PSFE_LayoutNewDocument(MWContext *cx, URL_Struct *url, int32 *w, int32 *h, int32 *mw, int32* mh)
  602. {
  603.     *w = cx->prInfo->page_width;
  604.     *h = cx->prInfo->page_height;
  605.     *mw = *mh = 0;
  606. }
  607.  
  608. MODULE_PRIVATE void
  609. PSFE_FinishedLayout(MWContext *cx)
  610. {
  611. }
  612.  
  613. static void
  614. display_non_latin1_multibyte_text(MWContext *cx, unsigned char *str, int len, int sf,
  615.     int fontmask)
  616. {
  617.     int        charSize;
  618.     int        convert;
  619.     XP_File        f;
  620.     unsigned char    *freeThis;
  621.     CCCDataObject    obj;
  622.     unsigned char    *out;
  623.     int        outlen;
  624.     unsigned char    *start;
  625.     INTL_CharSetInfo csi = LO_GetDocumentCharacterSetInfo(cx);
  626.     int16 win_csid = INTL_GetCSIWinCSID(csi);
  627.  
  628.     obj = INTL_CreateCharCodeConverter();
  629.     if (!obj)
  630.     {
  631.         return;
  632.     }
  633.     if (win_csid != cx->prSetup->otherFontCharSetID)
  634.     {
  635.         convert = INTL_GetCharCodeConverter(win_csid,
  636.             cx->prSetup->otherFontCharSetID, obj);
  637.     }
  638.     else
  639.     {
  640.         convert = 0;
  641.     }
  642.  
  643.     f = cx->prSetup->out;
  644.     freeThis = NULL;
  645.  
  646.     while (len > 0)
  647.     {
  648.         if ((*str) & 0x80)
  649.         {
  650.             start = str;
  651.             while ((len > 0) && ((*str) & 0x80))
  652.             {
  653.                 charSize = INTL_CharLen(win_csid, str);
  654.                 len -= charSize;
  655.                 str += charSize;
  656.             }
  657.             XP_FilePrintf(f, "%d of\n", sf);
  658.             if (convert)
  659.             {
  660.                 out = INTL_CallCharCodeConverter(obj, start,
  661.                     str - start);
  662.                 outlen = strlen(out);
  663.                 freeThis = out;
  664.             }
  665.             else
  666.             {
  667.                 out = start;
  668.                 outlen = str - start;
  669.             }
  670.             XP_FilePrintf(f, "<");
  671.             while (outlen > 0)
  672.             {
  673.                 XP_FilePrintf(f, "%02x", *out);
  674.                 outlen--;
  675.                 out++;
  676.             }
  677.             XP_FilePrintf(f, "> show\n");
  678.             if (freeThis)
  679.             {
  680.                 free(freeThis);
  681.                 freeThis = NULL;
  682.             }
  683.         }
  684.         else
  685.         {
  686.             start = str;
  687.             while ((len > 0) && (!((*str) & 0x80)))
  688.             {
  689.                 len--;
  690.                 str++;
  691.             }
  692.             XP_FilePrintf(f, "%d f%d\n", sf, fontmask);
  693.             xl_show(cx, (char *) start, str - start, "");
  694.         }
  695.     }
  696.  
  697.     INTL_DestroyCharCodeConverter(obj);
  698. }
  699.  
  700.  
  701. static void
  702. display_non_latin1_singlebyte_text(MWContext *cx, unsigned char *str, int len, int sf,
  703.     int fontmask)
  704. {
  705.     int        charSize;
  706.     int        convert;
  707.     XP_File        f;
  708.     unsigned char    *freeThis;
  709.     CCCDataObject    obj;
  710.     unsigned char    *out;
  711.     int        outlen;
  712.     unsigned char    *start;
  713.     INTL_CharSetInfo csi = LO_GetDocumentCharacterSetInfo(cx);
  714.     int16 win_csid = INTL_GetCSIWinCSID(csi);
  715.  
  716.     obj = INTL_CreateCharCodeConverter();
  717.     if (!obj)
  718.     {
  719.         return;
  720.     }
  721.     if (win_csid != cx->prSetup->otherFontCharSetID)
  722.     {
  723.         convert = INTL_GetCharCodeConverter(win_csid,
  724.             cx->prSetup->otherFontCharSetID, obj);
  725.     }
  726.     else
  727.     {
  728.         convert = 0;
  729.     }
  730.  
  731.     f = cx->prSetup->out;
  732.     freeThis = NULL;
  733.     while (len > 0)
  734.     {
  735.         if ((*str) & 0x80)
  736.         {
  737.         start = str;
  738.         while ((len > 0) && ((*str) & 0x80))
  739.         {
  740.             charSize = INTL_CharLen(win_csid, str);
  741.             len -= charSize;
  742.             str += charSize;
  743.         }
  744.             XP_FilePrintf(f, "%d of\n", sf);
  745.             if (convert)
  746.             {
  747.                 out = INTL_CallCharCodeConverter(obj, start,
  748.                     str - start);
  749.                 outlen = strlen(out);
  750.                 freeThis = out;
  751.             }
  752.             else
  753.             {
  754.                 out = start;
  755.                 outlen = str - start;
  756.             }
  757.             XP_FilePrintf(f, "<");
  758.             while (outlen > 0)
  759.             {
  760.                 XP_FilePrintf(f, "%02x", *out);
  761.                 outlen--;
  762.                 out++;
  763.             }
  764.             XP_FilePrintf(f, "> show\n");
  765.             
  766.             if (freeThis)
  767.             {
  768.                 free(freeThis);
  769.                 freeThis = NULL;
  770.             }
  771.         }
  772.         else
  773.         {
  774.             start = str;
  775.             while ((len > 0) && (!((*str) & 0x80)))
  776.             {
  777.                 len--;
  778.                 str++;
  779.             }
  780.             XP_FilePrintf(f, "%d of\n", sf);
  781.             xl_show(cx, (char *) start, str - start, "");
  782.         }
  783.     }
  784.     INTL_DestroyCharCodeConverter(obj);
  785. }
  786.  
  787. MODULE_PRIVATE void
  788. PSFE_DisplaySubtext(MWContext *cx, int iLocation, LO_TextStruct *text,
  789.             int32 start_pos, int32 end_pos, XP_Bool notused)
  790. {
  791.   int x, y, x2, top, height;
  792.   LO_TextInfo ti;
  793.   int sf;
  794.   INTL_CharSetInfo csi = LO_GetDocumentCharacterSetInfo(cx);
  795.   int16 win_csid = INTL_GetCSIWinCSID(csi);
  796.  
  797.   x = text->x + text->x_offset;
  798.   y = text->y + text->y_offset;
  799.   top = y;
  800.   height = text->height;
  801.   ps_measure_text(cx, text, &ti, 0, start_pos-1);
  802.   y += ti.ascent;        /* Move to baseline */
  803.   x += ti.max_width;        /* Skip over un-displayed text */
  804.   if (!XP_CheckElementSpan(cx, top, height))
  805.     return;
  806.  
  807.   sf = scale_factor(cx, text->text_attr->size, text->text_attr->fontmask);
  808.   xl_moveto(cx, x, y);
  809.   if (cx->prSetup->otherFontName) {
  810.            if (win_csid & MULTIBYTE) 
  811.              display_non_latin1_multibyte_text(cx, 
  812.                     ((unsigned char *) (text->text)) + start_pos,
  813.                     end_pos - start_pos + 1, sf,
  814.                     (int) text->text_attr->fontmask);
  815.     else display_non_latin1_singlebyte_text(cx,
  816.                 ((unsigned char *) (text->text)) + start_pos,
  817.                     end_pos - start_pos + 1, sf,
  818.                     (int) text->text_attr->fontmask);
  819.         return;
  820.   }
  821.   XP_FilePrintf(cx->prSetup->out, "%d f%d\n", sf,
  822.         (int) text->text_attr->fontmask);
  823.   xl_show(cx, ((char*) text->text) + start_pos, end_pos - start_pos + 1,"");
  824.  
  825.   /* Underline the text? */
  826.  
  827.   if (text->text_attr->attrmask & LO_ATTR_UNDERLINE) {
  828.       y = text->y + text->y_offset + ti.ascent + ti.descent/2;
  829.       x2 = x + text->width - 1;
  830.       xl_line(cx, x, y, x2, y, THIN_LINE_THICKNESS);
  831.   }
  832.  
  833.   /* Strikeout? */
  834.  
  835.   if (text->text_attr->attrmask & LO_ATTR_STRIKEOUT) {
  836.       y = text->y + text->y_offset + height/2;
  837.       x2 = x + text->width - 1;
  838.       xl_line(cx, x, y, x2, y, THIN_LINE_THICKNESS);
  839.   }
  840.  
  841. }
  842.  
  843. MODULE_PRIVATE void
  844. PSFE_DisplayText(MWContext *cx, int iLocation, LO_TextStruct *text, XP_Bool b)
  845. {
  846.     (cx->funcs->DisplaySubtext)(cx, iLocation, text, 0, text->text_len-1, b);
  847. }
  848.  
  849. /*
  850. ** Called at the end of each "Line" which could be a tiny line-section
  851. ** inside of a table cell or subdoc.
  852. */
  853. MODULE_PRIVATE void
  854. PSFE_DisplayLineFeed(MWContext *cx, int iLocation, LO_LinefeedStruct *line_feed,
  855.              XP_Bool b)
  856. {
  857. #ifdef NOT_THIS_TIME
  858.     if (cx->prInfo->layout_phase) {
  859.     if (cx->prInfo->in_pre) {
  860.         if (cx->prInfo->pre_start == -1)
  861.         cx->prInfo->pre_start = line_feed->y;
  862.         cx->prInfo->pre_end = line_feed->y+line_feed->line_height;
  863.     }
  864.     emit_y(cx, line_feed->y, line_feed->y+line_feed->line_height);
  865.     } else if (cx->prInfo->interesting != NULL) {
  866.     InterestingPRE *p;
  867.     p = (InterestingPRE *) XP_ListPeekTopObject(cx->prInfo->interesting);
  868.     if (p == NULL) {
  869.         XP_DELETE(cx->prInfo->interesting);
  870.         cx->prInfo->interesting = NULL;
  871.     } else if (line_feed->y + line_feed->line_height >= p->end) {
  872.         (void) XP_ListRemoveTopObject(cx->prInfo->interesting);
  873.         XP_DELETE(p);
  874.     }
  875.     }
  876. #endif
  877. }
  878.  
  879. MODULE_PRIVATE void
  880. PSFE_DisplayHR(MWContext *cx, int iLocation , LO_HorizRuleStruct *HR)
  881. {
  882.   int delta;
  883.   int top, bottom, height;
  884.  
  885.   top = HR->y + HR->y_offset;
  886.   height = HR->height;
  887.   if (!XP_CheckElementSpan(cx, top, height))
  888.     return;
  889.   delta = (height - height*cx->prSetup->rules) / 2;
  890.   top += delta;
  891.   bottom = top + height*cx->prSetup->rules;
  892.  
  893.   xl_moveto(cx, HR->x+HR->x_offset, top);
  894.   xl_box(cx, HR->width, height*cx->prSetup->rules);
  895.   xl_fill(cx);
  896. }
  897.  
  898. MODULE_PRIVATE void
  899. PSFE_DisplayBullet(MWContext *cx, int iLocation, LO_BullettStruct *bullet)
  900. {
  901.   int top, height;
  902.  
  903.   top = bullet->y + bullet->y_offset;
  904.   height = bullet->height;
  905.   if (!XP_CheckElementSpan(cx, top, height))
  906.     return;
  907.  
  908.   switch (bullet->bullet_type) {
  909.     case BULLET_ROUND:
  910.       xl_moveto(cx,
  911.          bullet->x+bullet->x_offset+height/2,
  912.          top+height/2);
  913.       xl_circle(cx, bullet->width, height);
  914.       xl_stroke(cx);
  915.       break;
  916.     case BULLET_BASIC:
  917.       xl_moveto(cx,
  918.          bullet->x+bullet->x_offset+height/2,
  919.          top+height/2);
  920.       xl_circle(cx, bullet->width, height);
  921.       xl_fill(cx);
  922.       break;
  923.     case BULLET_MQUOTE:
  924.     case BULLET_SQUARE:
  925.       xl_moveto(cx, bullet->x+bullet->x_offset, top);
  926.       xl_box(cx, bullet->width, height);
  927.       xl_fill(cx);
  928.       break;
  929. #ifdef DEBUG
  930.       default:
  931.       XP_Trace("Strange bullet type %d", bullet->bullet_type);
  932. #endif
  933.   }
  934. }
  935.  
  936. MODULE_PRIVATE void
  937. PSFE_DisplayBorder(MWContext *context, int iLocation, int x, int y, int width,
  938.                    int height, int bw, LO_Color *color, LO_LineStyle style)
  939. {
  940.     /* XXXM12N Implement me. */
  941. }
  942.  
  943. MODULE_PRIVATE void
  944. PSFE_DisplayFeedback(MWContext *context, int iLocation, LO_Element *element)
  945. {
  946. }
  947.  
  948. PUBLIC void PSFE_AllConnectionsComplete(MWContext *cx) 
  949. {
  950.       /*
  951.       ** All done, time to let everything go.
  952.       */
  953.   if (cx->prSetup->status >= 0)
  954.     xl_generate_postscript(cx);
  955.   (*cx->prSetup->completion)(cx->prSetup);
  956.   LO_DiscardDocument(cx);
  957.   xl_finalize_translation(cx);
  958.   XP_FREE(cx->prInfo->doc_title);
  959.   XP_CleanupPrintInfo(cx);
  960.   XP_DELETE(cx->funcs);
  961.  
  962.   /* Release the color space. */
  963.   if (cx->color_space) {
  964.       IL_ReleaseColorSpace(cx->color_space);
  965.       cx->color_space = NULL;
  966.   }
  967.  
  968.   /* Destroy the image group context. */
  969.   IL_DestroyGroupContext(cx->img_cx);
  970.   cx->img_cx = NULL;
  971.  
  972.   XP_DELETE(cx);
  973. }
  974.  
  975.  
  976. /* The code below provides very basic support for printing the current text
  977.    associated with form elements in the absence of a comprehensive solution
  978.    for 4.0.  The code does not display the form elements themselves, and
  979.    the form element margins still need to be tweaked to get the alignment
  980.    right.  If you found the time to read this, then you are the right person
  981.    to fix the bugs in this code. */
  982. #define FORM_LEFT_MARGIN       0
  983. #define FORM_RIGHT_MARGIN      0
  984. #define FORM_TOP_MARGIN        10
  985. #define FORM_BOTTOM_MARGIN     10
  986.  
  987. #define FORM_BOX_THICKNESS     12
  988. #define FORM_BOX_LEFT_MARGIN   24
  989. #define FORM_BOX_RIGHT_MARGIN  24
  990. #define FORM_BOX_TOP_MARGIN    10
  991. #define FORM_BOX_BOTTOM_MARGIN 10
  992.  
  993. #define RADIOBOX_THICKNESS     20
  994. #define RADIOBOX_WIDTH         100
  995. #define RADIOBOX_HEIGHT        100
  996. #define RADIOBOX_LEFT_MARGIN   0
  997. #define RADIOBOX_RIGHT_MARGIN  20
  998.  
  999. #define CHECKBOX_THICKNESS     20
  1000. #define CHECKBOX_WIDTH         100
  1001. #define CHECKBOX_HEIGHT        100
  1002. #define CHECKBOX_LEFT_MARGIN   0
  1003. #define CHECKBOX_RIGHT_MARGIN  20
  1004.  
  1005. #define SCROLLBAR_THICKNESS         12
  1006. #define SCROLLBAR_ARROW_WIDTH       66
  1007. #define SCROLLBAR_ARROW_HEIGHT      66
  1008. #define SCROLLBAR_ARROW_THICKNESS   12
  1009. #define SCROLLBAR_SLIDER_MARGIN     6
  1010. #define SCROLLBAR_SLIDER_THICKNESS  12
  1011. #define SCROLLBAR_MIN_SLIDER_LENGTH 36
  1012. #define SCROLLBAR_MIN_HEIGHT        (2*SCROLLBAR_THICKNESS+2*SCROLLBAR_ARROW_HEIGHT+2*SCROLLBAR_SLIDER_MARGIN+SCROLLBAR_MIN_SLIDER_LENGTH)
  1013. #define SCROLLBAR_WIDTH             (2*SCROLLBAR_THICKNESS+SCROLLBAR_ARROW_WIDTH)
  1014.  
  1015. #define COMBOBOX_ARROW_THICKNESS    16
  1016. #define COMBOBOX_ARROW_WIDTH        80
  1017. #define COMBOBOX_ARROW_MARGIN       24
  1018.  
  1019. typedef struct {
  1020.     int size;
  1021.     LO_TextStruct **text;
  1022. } TextArray;
  1023.  
  1024.  /* Determine length of string, excluding any blank space at the end. */
  1025. static int
  1026. reduce_length(char *str) 
  1027. {
  1028.     int i;
  1029.  
  1030.     i = XP_STRLEN(str) - 1;
  1031.     while (str[i] == ' ')
  1032.         i--;
  1033.     str[i+1] = '\0';
  1034.     return (i + 1);
  1035. }
  1036.  
  1037. /* Free the text array. */
  1038. static void
  1039. free_text_array(TextArray *text_array)
  1040. {
  1041.     int i;
  1042.     
  1043.     for (i = 0; i < text_array->size; i++) {
  1044.         if (text_array->text[i]) {
  1045.             XP_FREE(text_array->text[i]);
  1046.             text_array->text[i] = NULL;
  1047.         }
  1048.     }
  1049.     text_array->size = 0;
  1050.     XP_FREE(text_array->text);
  1051.     XP_FREE(text_array);
  1052. }
  1053.  
  1054. /* Returns the next line pointed to by ptr. Each line should have maximum cols characters */
  1055. static char *
  1056. get_next_line(char **pptr, int cols) 
  1057. {
  1058.     char *cr = NULL;
  1059.     char *ptr = *pptr;
  1060.     char *line = NULL;
  1061.     char *bptr = NULL;
  1062.     int   len = 0;
  1063.  
  1064.     if (*ptr == '\0') {
  1065.         line = XP_CALLOC(1, sizeof(char));
  1066.         line[0] = '\0';
  1067.         return line;
  1068.     }
  1069.  
  1070.     /* check if there is a newline character */
  1071.  
  1072.     cr = XP_STRCHR(ptr, '\n');
  1073.     if (cr) {
  1074.         /* line length is less than max cols */
  1075.         len = (int)(cr - ptr);
  1076.         if (len <= cols) {
  1077.             line = XP_CALLOC(len+1, sizeof(char));
  1078.             XP_MEMCPY(line, ptr, len);
  1079.             line[len] = '\0';
  1080.             *pptr = cr+1;
  1081.             return line;
  1082.         }
  1083.     }
  1084.  
  1085.     /* if there is no new line character, see if buffer length
  1086.      * is less than cols 
  1087.      */
  1088.  
  1089.     len = XP_STRLEN(ptr);
  1090.     if (len <= cols) {
  1091.         line = XP_CALLOC(len+1, sizeof(char));
  1092.         XP_MEMCPY(line, ptr, len);
  1093.         line[len] = '\0';
  1094.         *pptr = ptr + len;
  1095.         return line;
  1096.     }
  1097.     
  1098.     /* now we have to get to the delimiter before the max length */
  1099.     
  1100.     bptr = ptr + cols - 1;
  1101.     while (bptr != ptr) {
  1102.         if ((*bptr == ' ') || (*bptr == '\t')) {
  1103.             break;
  1104.         }
  1105.         bptr--;
  1106.     }
  1107.  
  1108.     if (bptr == ptr) {
  1109.         line = XP_CALLOC(1, sizeof(char));
  1110.         line[0] = '\0';
  1111.         return line;
  1112.     }
  1113.     else {
  1114.         len = (int)(bptr - ptr + 1);
  1115.         line = XP_CALLOC(len+1, sizeof(char));
  1116.         XP_MEMCPY(line, ptr, len);
  1117.         line[len] = '\0';
  1118.         *pptr = ptr + len;
  1119.         return line;
  1120.     }
  1121. }
  1122.  
  1123. /* Make a temporary text element to be used to display form elements which
  1124.    have a text field.  */
  1125. static TextArray *
  1126. make_text_array(MWContext *cx, LO_FormElementStruct *form)
  1127. {
  1128.     LO_TextStruct *text;
  1129.     TextArray *text_array;
  1130.     
  1131.     if (form->element_data == NULL)
  1132.         return NULL;
  1133.  
  1134.     text_array = XP_NEW_ZAP(TextArray);
  1135.     if(!text_array)
  1136.         return NULL;
  1137.  
  1138.     switch (form->element_data->type) {
  1139.     case FORM_TYPE_FILE:
  1140.     case FORM_TYPE_TEXT:
  1141.     case FORM_TYPE_PASSWORD:
  1142.     case FORM_TYPE_SUBMIT:
  1143.     case FORM_TYPE_RESET:
  1144.     case FORM_TYPE_BUTTON:
  1145.     case FORM_TYPE_SELECT_ONE:
  1146.         text_array->size = 1;
  1147.         text_array->text =
  1148.             (LO_TextStruct**)XP_CALLOC(1, sizeof(LO_TextStruct*));
  1149.         if (!text_array->text) {
  1150.             free_text_array(text_array);
  1151.             return NULL;
  1152.         }
  1153.  
  1154.         text = XP_NEW_ZAP(LO_TextStruct);
  1155.         if (!text) {
  1156.             free_text_array(text_array);
  1157.             return NULL;
  1158.         }
  1159.  
  1160.         switch (form->element_data->type) {
  1161.         case FORM_TYPE_FILE:
  1162.         case FORM_TYPE_TEXT:
  1163.         case FORM_TYPE_PASSWORD:
  1164.             text->text = form->element_data->ele_text.current_text;
  1165.             if (!text->text)
  1166.                 text->text = form->element_data->ele_text.default_text;
  1167.             break;
  1168.             
  1169.         case FORM_TYPE_SUBMIT:
  1170.         case FORM_TYPE_RESET:
  1171.         case FORM_TYPE_BUTTON:
  1172.             text->text = form->element_data->ele_minimal.value;
  1173.             break;
  1174.  
  1175.         case FORM_TYPE_SELECT_ONE:
  1176.             if (form->element_data->ele_select.option_cnt > 0) {
  1177.  
  1178.                 int option_cnt = form->element_data->ele_select.option_cnt;
  1179.                 lo_FormElementOptionData* options =
  1180.                     (lo_FormElementOptionData*)
  1181.                     form->element_data->ele_select.options;
  1182.                 int selected = -1;
  1183.                 int def_selected = -1;
  1184.                 int i;
  1185.  
  1186.                 for (i = 0; i < option_cnt; i++) {
  1187.                     if (options[i].selected) {
  1188.                         selected = i;
  1189.                         break;
  1190.                     } else if (options[i].def_selected) {
  1191.                         def_selected = i;
  1192.                     }
  1193.                 }
  1194.                 
  1195.                 if (selected == -1) {
  1196.                    if (def_selected != -1)
  1197.                        selected = def_selected;
  1198.                    else
  1199.                        selected = 0;
  1200.                 }
  1201.                 
  1202.                 text->text = options[selected].text_value;
  1203.             }
  1204.             break;
  1205.  
  1206.         default:
  1207.             XP_ASSERT(0);
  1208.             break;
  1209.         }
  1210.         
  1211.         if (!text->text) {
  1212.             free_text_array(text_array);
  1213.             XP_FREE(text);
  1214.             return NULL;
  1215.         }
  1216.         text->text_len = reduce_length((char*)text->text);
  1217.         text->text_attr = form->text_attr;
  1218.  
  1219.         text_array->text[0] = text;
  1220.         break;
  1221.     
  1222.     case FORM_TYPE_TEXTAREA:
  1223.         {
  1224.             char *string = (char *)form->element_data->ele_textarea.current_text;
  1225.             int columns = form->element_data->ele_textarea.cols;
  1226.             int rows = form->element_data->ele_textarea.rows;
  1227.             char *string_ptr;
  1228.             int i;
  1229.  
  1230.             if (!string)
  1231.                 string = (char *)form->element_data->ele_textarea.default_text;
  1232.  
  1233.             text_array->size = rows;
  1234.             text_array->text = (LO_TextStruct**)XP_CALLOC(text_array->size,
  1235.                                                           sizeof(LO_TextStruct*));
  1236.             if (!text_array->text) {
  1237.                 free_text_array(text_array);
  1238.                 return NULL;
  1239.             }
  1240.  
  1241.             for (string_ptr = &string[0], i = 0; i < text_array->size; i++) {
  1242.  
  1243.                 char *line = get_next_line(&string_ptr, columns);
  1244.  
  1245.                 text = XP_NEW_ZAP(LO_TextStruct);
  1246.                 if (!text) {
  1247.                     free_text_array(text_array);
  1248.                     return NULL;
  1249.                 }
  1250.  
  1251.                 text->text = (PA_Block)line;
  1252.                 if (!text->text) {
  1253.                     free_text_array(text_array);
  1254.                     XP_FREE(text);
  1255.                     return NULL;
  1256.                 }
  1257.  
  1258.                 text->text_len = reduce_length((char*)text->text);
  1259.                 text->text_attr = form->text_attr;
  1260.  
  1261.                 text_array->text[i] = text;
  1262.             }
  1263.         }
  1264.         break;
  1265.  
  1266.     case FORM_TYPE_SELECT_MULT:
  1267.     {
  1268.         int i;
  1269.         lo_FormElementOptionData *options;
  1270.         int size = form->element_data->ele_select.size;
  1271.         int option_cnt = form->element_data->ele_select.option_cnt;
  1272.  
  1273.         /*
  1274.          *    Try to use size, unless it's bogus or less than option_cnt
  1275.          *    There is a small bug here: when a multi list has a size
  1276.          *    greater than the number of elements, we won't show the
  1277.          *    blanks at the end of the list, the display FEs do.
  1278.          */
  1279.         if (size < 1 || size > option_cnt)
  1280.             size = option_cnt;
  1281.  
  1282.         if (size < 1) { /* paranoia: just in case option_cnt is bogus */
  1283.             free_text_array(text_array);
  1284.             return NULL;
  1285.         }
  1286.  
  1287.         text_array->size = size;
  1288.         text_array->text = (LO_TextStruct**)XP_CALLOC(text_array->size,
  1289.                                                       sizeof(LO_TextStruct*));
  1290.         if (!text_array->text) {
  1291.             free_text_array(text_array);
  1292.             return NULL;
  1293.         }
  1294.  
  1295.         options =
  1296.             (lo_FormElementOptionData *)form->element_data->ele_select.options;
  1297.  
  1298.         for (i = 0; i < text_array->size; i++) {
  1299.  
  1300.             text = XP_NEW_ZAP(LO_TextStruct);
  1301.             if (!text) {
  1302.                 free_text_array(text_array);
  1303.                 return NULL;
  1304.             }
  1305.  
  1306.             text->text = options[i].text_value;
  1307.             if (!text->text) {
  1308.                 free_text_array(text_array);
  1309.                 XP_FREE(text);
  1310.                 return NULL;
  1311.             }
  1312.  
  1313.             text->text_len = reduce_length((char*)text->text);
  1314.             text->text_attr = form->text_attr;
  1315.  
  1316.             text_array->text[i] = text;
  1317.         }
  1318.     }
  1319.     break;
  1320.         
  1321.     default:
  1322.         break;
  1323.     }
  1324.  
  1325.     return text_array;
  1326. }
  1327.  
  1328. MODULE_PRIVATE void
  1329. PSFE_GetFormElementInfo(MWContext *cx, LO_FormElementStruct *form)
  1330. {
  1331.     INTL_CharSetInfo csi = LO_GetDocumentCharacterSetInfo(cx);
  1332.     int16 win_csid = INTL_GetCSIWinCSID(csi);
  1333.  
  1334.     if (form->element_data == NULL)
  1335.         return;
  1336.  
  1337.     switch (form->element_data->type) {
  1338.  
  1339.     case FORM_TYPE_FILE:
  1340.     case FORM_TYPE_TEXT:
  1341.     case FORM_TYPE_PASSWORD:
  1342.     case FORM_TYPE_TEXTAREA:
  1343.     case FORM_TYPE_SELECT_ONE:
  1344.     case FORM_TYPE_SELECT_MULT:
  1345.     case FORM_TYPE_SUBMIT:
  1346.     case FORM_TYPE_RESET:
  1347.     case FORM_TYPE_BUTTON:
  1348.     {
  1349.         int i, width, height;
  1350.         LO_TextInfo text_info;
  1351.         TextArray *text_array;
  1352.         int descent = 0;
  1353.         int bottom_margin = 0;
  1354.         int shadow_thickness = 0;
  1355.  
  1356.         text_array = make_text_array(cx, form);
  1357.         if (!text_array)
  1358.             return;
  1359.  
  1360.         width = 0;
  1361.         height = 0;
  1362.         for (i = 0; i < text_array->size; i++) {
  1363.             PSFE_GetTextInfo(cx, text_array->text[i], &text_info);
  1364.  
  1365.             if ((form->element_data->type == FORM_TYPE_TEXT) ||
  1366.                 (form->element_data->type == FORM_TYPE_PASSWORD) ||
  1367.                 (form->element_data->type == FORM_TYPE_TEXTAREA)) {
  1368.  
  1369.                 /* For empty text fields, we should calculate width using 
  1370.                  * form->element_data->ele_text.size
  1371.                  * For non-empty text fields, we should make sure that the
  1372.                  * bonding box is bigger than the text
  1373.                  */
  1374.                 
  1375.                 LO_TextInfo    temp_info;
  1376.                 TextArray     *temp_text_array = NULL;
  1377.                 LO_TextStruct *text = NULL;
  1378.                 int            columns = 0;
  1379.  
  1380.                 temp_text_array = XP_NEW_ZAP(TextArray);
  1381.                 temp_text_array->size = 1;
  1382.                 temp_text_array->text = (LO_TextStruct**)XP_CALLOC(1, sizeof(LO_TextStruct*));
  1383.                 text = XP_NEW_ZAP(LO_TextStruct);
  1384.                 text->text = (PA_Block)" ";
  1385.                 text->text_len = 1;
  1386.                 text->text_attr = text_array->text[i]->text_attr;
  1387.                 temp_text_array->text[0] = text;
  1388.  
  1389.                 PSFE_GetTextInfo(cx, temp_text_array->text[0], &temp_info);                
  1390.                 if (form->element_data->type == FORM_TYPE_TEXTAREA) {
  1391.                     lo_FormElementTextareaData *data = &form->element_data->ele_textarea;
  1392.                     columns = ((win_csid & MULTIBYTE) ? (data->cols + 1) / 2 : data->cols);
  1393.                     text_info.max_width =
  1394.                         MAX(text_info.max_width, temp_info.max_width * columns);
  1395.                 }
  1396.                 else {
  1397.                     lo_FormElementTextData *data = &form->element_data->ele_text;
  1398.                     columns = ((win_csid & MULTIBYTE) ? (data->size + 1) / 2 : data->size);
  1399.                     text_info.max_width =
  1400.                         MAX(text_info.max_width, temp_info.max_width * columns);
  1401.                 }
  1402.  
  1403.                 free_text_array(temp_text_array);
  1404.             }
  1405.  
  1406.             width = MAX(width, text_info.max_width +
  1407.                         FORM_LEFT_MARGIN + FORM_RIGHT_MARGIN);
  1408.             height = MAX(height, text_info.ascent + text_info.descent +
  1409.                          FORM_TOP_MARGIN + FORM_BOTTOM_MARGIN);
  1410.         }
  1411.  
  1412.         /* adjust height */
  1413.  
  1414.         if (form->element_data->type == FORM_TYPE_TEXTAREA)
  1415.             height *= form->element_data->ele_textarea.rows;
  1416.         else
  1417.             height *= text_array->size;
  1418.  
  1419.         bottom_margin = FORM_BOTTOM_MARGIN;
  1420.         descent = text_info.descent;
  1421.  
  1422.         if (form->element_data->type == FORM_TYPE_SELECT_ONE) {
  1423.             /* leave space for bonding box and down arrow */
  1424.             height = height + 2 * FORM_BOX_THICKNESS +
  1425.                 FORM_BOX_TOP_MARGIN + FORM_BOX_BOTTOM_MARGIN;
  1426.             width = width + 2 * FORM_BOX_THICKNESS + 
  1427.                 FORM_BOX_LEFT_MARGIN + FORM_BOX_RIGHT_MARGIN + 
  1428.                 1 * COMBOBOX_ARROW_MARGIN + COMBOBOX_ARROW_WIDTH;
  1429.             shadow_thickness += FORM_BOX_THICKNESS;
  1430.             bottom_margin += FORM_BOX_BOTTOM_MARGIN;
  1431.         }
  1432.  
  1433.         if ((form->element_data->type == FORM_TYPE_SUBMIT) ||
  1434.             (form->element_data->type == FORM_TYPE_RESET) ||
  1435.             (form->element_data->type == FORM_TYPE_BUTTON) ||
  1436.             (form->element_data->type == FORM_TYPE_TEXT) ||
  1437.             (form->element_data->type == FORM_TYPE_TEXTAREA) ||
  1438.             (form->element_data->type == FORM_TYPE_PASSWORD) ||
  1439.             (form->element_data->type == FORM_TYPE_SELECT_MULT)) {
  1440.             /* leave space for bonding box */
  1441.             width = width + 2 * FORM_BOX_THICKNESS + 
  1442.                 FORM_BOX_LEFT_MARGIN + FORM_BOX_RIGHT_MARGIN;
  1443.             height = height + 2 * FORM_BOX_THICKNESS +
  1444.                 FORM_BOX_TOP_MARGIN + FORM_BOX_BOTTOM_MARGIN;;
  1445.  
  1446.             shadow_thickness += FORM_BOX_THICKNESS;
  1447.             bottom_margin += FORM_BOX_BOTTOM_MARGIN;
  1448.         }
  1449.  
  1450.         /* leave space for scrollbar */
  1451.         if ((form->element_data->type == FORM_TYPE_SELECT_MULT) &&
  1452.             (height >= SCROLLBAR_MIN_HEIGHT)) {
  1453.             /* no need to provide scrollbar if the list/text is not long enough */
  1454.             width += SCROLLBAR_WIDTH;
  1455.         }
  1456.  
  1457.         if (!form->width)
  1458.             form->width = width;
  1459.         if (!form->height)
  1460.             form->height = height;
  1461.  
  1462.         /* readjust the baseline for the form element */
  1463.         form->baseline = form->height - (descent + bottom_margin + shadow_thickness);
  1464.  
  1465.         free_text_array(text_array);
  1466.     }
  1467.     break;
  1468.     
  1469.     case FORM_TYPE_RADIO:
  1470.     {
  1471.         form->width = RADIOBOX_WIDTH + RADIOBOX_LEFT_MARGIN + RADIOBOX_RIGHT_MARGIN;
  1472.         form->height = RADIOBOX_HEIGHT;
  1473.     }
  1474.     break;
  1475.  
  1476.     case FORM_TYPE_CHECKBOX:
  1477.     {
  1478.         form->width = CHECKBOX_WIDTH + CHECKBOX_LEFT_MARGIN + CHECKBOX_RIGHT_MARGIN;
  1479.         form->height = CHECKBOX_HEIGHT;
  1480.     }
  1481.     break;
  1482.  
  1483.     default:
  1484.         /* Other types of form element are unsupported. */
  1485.         XP_TRACE(("PSFE_GetFormElementInfo: unsupported form element type."));
  1486.         break;
  1487.         
  1488.     }
  1489. }
  1490.  
  1491. MODULE_PRIVATE void
  1492. PSFE_DisplayFormElement(MWContext *cx, int loc, LO_FormElementStruct *form)
  1493. {
  1494.     if (form->element_data == NULL)
  1495.         return;
  1496.     switch (form->element_data->type) {
  1497.     case FORM_TYPE_FILE:
  1498.     case FORM_TYPE_TEXT:
  1499.     case FORM_TYPE_PASSWORD:
  1500.     case FORM_TYPE_SELECT_MULT:
  1501.     case FORM_TYPE_TEXTAREA:
  1502.     case FORM_TYPE_SUBMIT:
  1503.     case FORM_TYPE_RESET:
  1504.     case FORM_TYPE_BUTTON:
  1505.     {
  1506.         int i, x, y, text_width, text_height, delta_height;
  1507.         TextArray *text_array;
  1508.         LO_TextStruct *text;
  1509.         
  1510.         text_array = make_text_array(cx, form);
  1511.         if (!text_array)
  1512.             return;
  1513.  
  1514.         x = form->x + form->x_offset + FORM_LEFT_MARGIN;
  1515.         y = form->y + form->y_offset + FORM_TOP_MARGIN;
  1516.  
  1517.         if (!XP_CheckElementSpan(cx, y, form->height))
  1518.             return;
  1519.  
  1520.         /* draw scrollbar if necessary */
  1521.  
  1522.         if ((form->element_data->type == FORM_TYPE_SELECT_MULT) &&
  1523.             (form->height >= SCROLLBAR_MIN_HEIGHT)) {
  1524.             /* no need to provide scrollbar if the list/text is not long enough */
  1525.  
  1526.             int scrollbar_x, scrollbar_y;
  1527.             int arrow_x, arrow_y;
  1528.  
  1529.             scrollbar_x = form->x + form->width - SCROLLBAR_WIDTH;
  1530.             scrollbar_y = form->y + form->y_offset + FORM_TOP_MARGIN;
  1531.  
  1532.             xl_draw_3d_border(cx, scrollbar_x, scrollbar_y,
  1533.                               SCROLLBAR_WIDTH,
  1534.                               form->height-FORM_TOP_MARGIN-FORM_BOTTOM_MARGIN, 
  1535.                               SCROLLBAR_THICKNESS, 
  1536.                               DARK_GREY, LIGHT_GREY);
  1537.  
  1538.             form->width -= SCROLLBAR_WIDTH;
  1539.  
  1540.             /* draw arrows */
  1541.  
  1542.             arrow_x = scrollbar_x + SCROLLBAR_THICKNESS;
  1543.             arrow_y = scrollbar_y + SCROLLBAR_THICKNESS;
  1544.  
  1545.             xl_draw_3d_arrow(cx, 
  1546.                              arrow_x, arrow_y,
  1547.                              SCROLLBAR_ARROW_THICKNESS,
  1548.                              SCROLLBAR_ARROW_WIDTH,
  1549.                              SCROLLBAR_ARROW_HEIGHT,
  1550.                              TRUE, /* up arrow */
  1551.                              LIGHT_GREY, /* left */
  1552.                              DARK_GREY,  /* right */
  1553.                              DARK_GREY   /* base */);
  1554.  
  1555.             arrow_x = scrollbar_x + SCROLLBAR_THICKNESS;
  1556.             arrow_y = form->y + form->y_offset + form->height - FORM_BOTTOM_MARGIN-
  1557.                 SCROLLBAR_ARROW_THICKNESS - SCROLLBAR_ARROW_HEIGHT;
  1558.  
  1559.             xl_draw_3d_arrow(cx, 
  1560.                              arrow_x, arrow_y,
  1561.                              SCROLLBAR_ARROW_THICKNESS,
  1562.                              SCROLLBAR_ARROW_WIDTH,
  1563.                              SCROLLBAR_ARROW_HEIGHT,
  1564.                              FALSE, /* down arrow */
  1565.                              LIGHT_GREY, /* left */
  1566.                              DARK_GREY,  /* right */
  1567.                              LIGHT_GREY   /* base */);
  1568.  
  1569.             /* draw slider */
  1570.  
  1571.         }
  1572.  
  1573.         /* if there is a bonding box, create the bonding box first */
  1574.  
  1575.         if ((form->element_data->type == FORM_TYPE_SUBMIT) ||
  1576.             (form->element_data->type == FORM_TYPE_RESET) ||
  1577.             (form->element_data->type == FORM_TYPE_BUTTON) ||
  1578.             (form->element_data->type == FORM_TYPE_TEXT) ||
  1579.             (form->element_data->type == FORM_TYPE_TEXTAREA) ||
  1580.             (form->element_data->type == FORM_TYPE_PASSWORD) ||
  1581.             (form->element_data->type == FORM_TYPE_SELECT_MULT)) {
  1582.  
  1583.             XP_Bool stick_out = FALSE;
  1584.             if ((form->element_data->type == FORM_TYPE_SUBMIT) ||
  1585.                 (form->element_data->type == FORM_TYPE_RESET) ||
  1586.                 (form->element_data->type == FORM_TYPE_BUTTON))
  1587.                 stick_out = TRUE;
  1588.                 
  1589.             xl_draw_3d_border(cx, x, y,
  1590.                               form->width-FORM_LEFT_MARGIN-FORM_RIGHT_MARGIN,
  1591.                               form->height-FORM_TOP_MARGIN-FORM_BOTTOM_MARGIN, 
  1592.                               FORM_BOX_THICKNESS, 
  1593.                               stick_out ? LIGHT_GREY : DARK_GREY,
  1594.                               stick_out ? DARK_GREY : LIGHT_GREY);
  1595.  
  1596.             /* readjust the origin and dimensions */
  1597.  
  1598.             form->width = form->width - 2 * FORM_BOX_THICKNESS - 
  1599.                 FORM_BOX_LEFT_MARGIN - FORM_BOX_RIGHT_MARGIN;
  1600.             form->height = form->height - 2 * FORM_BOX_THICKNESS -
  1601.                 FORM_BOX_TOP_MARGIN - FORM_BOX_BOTTOM_MARGIN;
  1602.             x = x + FORM_BOX_THICKNESS + FORM_BOX_LEFT_MARGIN;
  1603.             y = y + FORM_BOX_THICKNESS + FORM_BOX_TOP_MARGIN;
  1604.         }
  1605.  
  1606.         delta_height = form->height / text_array->size;
  1607.         text_height = delta_height - (FORM_TOP_MARGIN + FORM_BOTTOM_MARGIN);
  1608.         text_width = form->width;
  1609.         
  1610.         for (i = 0; i < text_array->size; i++) {
  1611.             PA_Block text_save;
  1612.  
  1613.             text = text_array->text[i];
  1614.             text->x = x;
  1615.             text->y = y;
  1616.             text->width = text_width;
  1617.             text->height = text_height;
  1618.  
  1619.             /* Avoid revealing users' passwords */
  1620.             if (form->element_data->type == FORM_TYPE_PASSWORD) {
  1621.               char *ptr;
  1622.  
  1623.               text_save = text->text;
  1624.               text->text = XP_ALLOC_BLOCK(text->text_len + 1);
  1625.               ptr = (char *)text->text;
  1626.               for (i = 0; i < text->text_len; i++) {
  1627.                 *ptr++ = '*';
  1628.               }
  1629.               *ptr = '\0';
  1630.             }
  1631.  
  1632.             PSFE_DisplayText(cx, FE_VIEW, text, FALSE);
  1633.             y += delta_height;
  1634.  
  1635.             /* Restore password to readable form */
  1636.             if (form->element_data->type == FORM_TYPE_PASSWORD) {
  1637.               XP_FREE_BLOCK(text->text);
  1638.               text->text = text_save;
  1639.             }
  1640.         }
  1641.         
  1642.         free_text_array(text_array);
  1643.     }
  1644.     break;
  1645.  
  1646.     case FORM_TYPE_SELECT_ONE:
  1647.     {
  1648.         int i, x, y, text_width, text_height, delta_height;
  1649.         TextArray *text_array;
  1650.         LO_TextStruct *text;
  1651.         int arrow_x, arrow_y;
  1652.         int arrow_height;
  1653.         
  1654.         text_array = make_text_array(cx, form);
  1655.         if (!text_array)
  1656.             return;
  1657.  
  1658.         x = form->x + form->x_offset + FORM_LEFT_MARGIN;
  1659.         y = form->y + form->y_offset + FORM_TOP_MARGIN;
  1660.  
  1661.         if (!XP_CheckElementSpan(cx, y, form->height))
  1662.             return;
  1663.  
  1664.         /* create the bonding box first */
  1665.  
  1666.         xl_draw_3d_border(cx, x, y,
  1667.                           form->width-FORM_LEFT_MARGIN-FORM_RIGHT_MARGIN,
  1668.                           form->height-FORM_TOP_MARGIN-FORM_BOTTOM_MARGIN, 
  1669.                           FORM_BOX_THICKNESS, 
  1670.                           LIGHT_GREY, DARK_GREY);
  1671.  
  1672.         /* draw arrows */
  1673.  
  1674.         arrow_x = form->x + form->x_offset + form->width - FORM_RIGHT_MARGIN -
  1675.             COMBOBOX_ARROW_MARGIN - FORM_BOX_THICKNESS - COMBOBOX_ARROW_WIDTH;
  1676.         arrow_height = form->height - FORM_TOP_MARGIN - FORM_BOTTOM_MARGIN 
  1677.             - 2*FORM_BOX_THICKNESS - FORM_BOX_TOP_MARGIN - FORM_BOX_BOTTOM_MARGIN -
  1678.             2 * COMBOBOX_ARROW_MARGIN;
  1679.         arrow_y = form->y + form->y_offset + FORM_TOP_MARGIN +
  1680.             FORM_BOX_THICKNESS + FORM_BOX_TOP_MARGIN + COMBOBOX_ARROW_MARGIN;
  1681.         if (arrow_height < 0) {
  1682.             arrow_height = form->height - FORM_TOP_MARGIN - FORM_BOTTOM_MARGIN 
  1683.                 - 2*FORM_BOX_THICKNESS - FORM_BOX_TOP_MARGIN - FORM_BOX_BOTTOM_MARGIN;
  1684.             arrow_y = form->y + form->y_offset + FORM_TOP_MARGIN +
  1685.                 FORM_BOX_THICKNESS + FORM_BOX_TOP_MARGIN;
  1686.         }
  1687.  
  1688.         xl_draw_3d_arrow(cx, 
  1689.                          arrow_x, arrow_y,
  1690.                          COMBOBOX_ARROW_THICKNESS,
  1691.                          COMBOBOX_ARROW_WIDTH, arrow_height,
  1692.                          FALSE, /* down arrow */
  1693.                          LIGHT_GREY, /* left */
  1694.                          DARK_GREY,  /* right */
  1695.                          LIGHT_GREY   /* base */);
  1696.  
  1697.         /* readjust the origin and dimensions */
  1698.  
  1699.         form->width = form->width - 3*FORM_BOX_THICKNESS - FORM_BOX_LEFT_MARGIN -
  1700.             FORM_BOX_RIGHT_MARGIN - COMBOBOX_ARROW_WIDTH - 2*COMBOBOX_ARROW_MARGIN;
  1701.         form->height = form->height - 2 * FORM_BOX_THICKNESS -
  1702.             FORM_BOX_TOP_MARGIN - FORM_BOX_BOTTOM_MARGIN;
  1703.         x = x + FORM_BOX_THICKNESS + FORM_BOX_LEFT_MARGIN;
  1704.         y = y + FORM_BOX_THICKNESS + FORM_BOX_TOP_MARGIN;
  1705.  
  1706.         delta_height = form->height / text_array->size;
  1707.         text_height = delta_height - (FORM_TOP_MARGIN + FORM_BOTTOM_MARGIN);
  1708.         text_width = form->width;
  1709.         
  1710.         for (i = 0; i < text_array->size; i++) {
  1711.             text = text_array->text[i];
  1712.             text->x = x;
  1713.             text->y = y;
  1714.             text->width = text_width;
  1715.             text->height = text_height;
  1716.             PSFE_DisplayText(cx, FE_VIEW, text, FALSE);
  1717.             y += delta_height;
  1718.         }
  1719.         
  1720.         free_text_array(text_array);
  1721.     }
  1722.     break;
  1723.  
  1724.     case FORM_TYPE_RADIO:
  1725.     {
  1726.         lo_FormElementToggleData *data = &form->element_data->ele_toggle;
  1727.         XP_Bool                   selected = data->toggled;
  1728.         int                       x, y;
  1729.  
  1730.         x = form->x + form->x_offset + RADIOBOX_LEFT_MARGIN;
  1731.         y = form->y + form->y_offset;
  1732.  
  1733.         if (!XP_CheckElementSpan(cx, y, form->height))
  1734.             return;
  1735.         
  1736.         xl_draw_3d_radiobox(cx, x, y,
  1737.                             RADIOBOX_WIDTH, RADIOBOX_HEIGHT, RADIOBOX_THICKNESS,
  1738.                             selected ? DARK_GREY : LIGHT_GREY,
  1739.                             selected ? LIGHT_GREY : DARK_GREY,
  1740.                             selected ? GREY : LIGHTER_GREY);
  1741.     }
  1742.     break;
  1743.  
  1744.     case FORM_TYPE_CHECKBOX:
  1745.     {
  1746.         lo_FormElementToggleData *data = &form->element_data->ele_toggle;
  1747.         XP_Bool                   selected = data->toggled;
  1748.         int                       x, y;
  1749.  
  1750.         x = form->x + form->x_offset + CHECKBOX_LEFT_MARGIN;
  1751.         y = form->y + form->y_offset;
  1752.  
  1753.         if (!XP_CheckElementSpan(cx, y, form->height))
  1754.             return;
  1755.         
  1756.         xl_draw_3d_checkbox(cx, x, y,
  1757.                             CHECKBOX_WIDTH, CHECKBOX_HEIGHT, CHECKBOX_THICKNESS,
  1758.                             selected ? DARK_GREY : LIGHT_GREY,
  1759.                             selected ? LIGHT_GREY : DARK_GREY,
  1760.                             selected ? GREY : LIGHTER_GREY);
  1761.     }
  1762.     break;
  1763.  
  1764.     default:
  1765.         /* Other types of form element are unsupported. */
  1766.         XP_TRACE(("PSFE_DisplayFormElement: unsupported form element type."));
  1767.         break;
  1768.     }
  1769. }
  1770.  
  1771. MODULE_PRIVATE void
  1772. PSFE_SetDocDimension(MWContext *cx, int iloc, int32 iWidth, int32 iLength)
  1773. {
  1774.   cx->prInfo->doc_width = iWidth;
  1775.   cx->prInfo->doc_height = iLength;
  1776. }
  1777.  
  1778. MODULE_PRIVATE void
  1779. PSFE_SetDocTitle(MWContext * cx, char * title)
  1780. {
  1781.     XP_FREE(cx->prInfo->doc_title);
  1782.     cx->prInfo->doc_title = XP_STRDUP(title);
  1783. }
  1784.  
  1785. MODULE_PRIVATE char *
  1786. PSFE_TranslateISOText(MWContext *cx, int charset, char *ISO_Text)
  1787. {
  1788.     return ISO_Text;
  1789. }
  1790.  
  1791. MODULE_PRIVATE void
  1792. PSFE_BeginPreSection(MWContext* cx)
  1793. {
  1794. #ifdef LATER
  1795.     cx->prInfo->scale = 1.0;
  1796.     cx->prInfo->in_pre = TRUE;
  1797.     cx->prInfo->pre_start = -1;
  1798. #endif
  1799. }
  1800.  
  1801. MODULE_PRIVATE void
  1802. PSFE_EndPreSection(MWContext* cx)
  1803. {
  1804. #ifdef LATER
  1805.     if (cx->prInfo->layout_phase && cx->prInfo->scale != 1.0) {
  1806.     InterestingPRE *p = XP_NEW(InterestingPRE);
  1807.     p->start = cx->prInfo->pre_start;
  1808.     p->end = cx->prInfo->pre_end;
  1809.     p->scale = max(cx->prInfo->scale, 0.25);
  1810.     if (cx->prInfo->interesting == NULL)
  1811.         cx->prInfo->interesting = XP_ListNew();
  1812.     XP_ListAddObjectToEnd(cx->prInfo->interesting, p);
  1813.     }
  1814.     cx->prInfo->in_pre = FALSE;
  1815. #endif
  1816. }
  1817.  
  1818. void PSFE_DisplayTable(MWContext *cx, int iLoc, LO_TableStruct *table)
  1819. {
  1820.     int top, height;
  1821.     
  1822.     top = table->y+table->y_offset;
  1823.     height = table->height;
  1824.   
  1825.     if (table->border_width != 0 && XP_CheckElementSpan(cx, top, height)) {
  1826.         xl_draw_border(cx, table->x+table->x_offset, top,
  1827.                        table->width, height, table->border_width);
  1828.     }
  1829. }
  1830.  
  1831. void PSFE_DisplayCell(MWContext *cx, int iLoc,LO_CellStruct *cell)
  1832. {
  1833.     int top, height;
  1834.     
  1835.     top = cell->y+cell->y_offset;
  1836.     height = cell->height;
  1837.   
  1838.     if (cell->border_width != 0 && XP_CheckElementSpan(cx, top, height)) {
  1839.         xl_draw_border(cx, cell->x+cell->x_offset, top,
  1840.                        cell->width, height, cell->border_width);
  1841.   }
  1842. }
  1843.  
  1844. MODULE_PRIVATE char *
  1845. PSFE_PromptPassword(MWContext *cx, const char *msg)
  1846. {
  1847.   MWContext *wincx = cx->prSetup->cx;
  1848.   /* If we don't have a context, go find one. This is really a hack, we may
  1849.    * attach to some random window, but at least the print/saveas/etc will
  1850.    * still work. Our caller can prevent this by actually setting cx->prSetup->cx
  1851.    * to something that will really stay around until the save or print is
  1852.    * complete */
  1853.   if (wincx == NULL) {
  1854.     wincx = XP_FindSomeContext();
  1855.   }
  1856.  
  1857.   if (wincx != NULL)
  1858.     return FE_PromptPassword(wincx, msg);
  1859.  
  1860.   return NULL;
  1861. }
  1862.  
  1863.  
  1864. /***************************
  1865.  * Plugin printing support *
  1866.  ***************************/
  1867. #ifndef X_PLUGINS
  1868. /* Plugins are disabled */
  1869. void PSFE_GetEmbedSize(MWContext *context, LO_EmbedStruct *embed_struct, NET_ReloadMethod force_reload) {}
  1870. void PSFE_FreeEmbedElement(MWContext *context, LO_EmbedStruct *embed_struct) {}
  1871. void PSFE_CreateEmbedWindow(MWContext *context, NPEmbeddedApp *app) {}
  1872. void PSFE_SaveEmbedWindow(MWContext *context, NPEmbeddedApp *app) {}
  1873. void PSFE_RestoreEmbedWindow(MWContext *context, NPEmbeddedApp *app) {}
  1874. void PSFE_DestroyEmbedWindow(MWContext *context, NPEmbeddedApp *app) {}
  1875. void PSFE_DisplayEmbed(MWContext *context, int iLocation, LO_EmbedStruct *embed_struct) {}
  1876. #else
  1877. void
  1878. PSFE_FreeEmbedElement (MWContext *context, LO_EmbedStruct *embed_struct)
  1879. {
  1880.     NPL_EmbedDelete(context, embed_struct);
  1881.     embed_struct->FE_Data = 0;
  1882. }
  1883.  
  1884. void
  1885. PSFE_CreateEmbedWindow(MWContext *context, NPEmbeddedApp *app)
  1886. {
  1887.     /* This will be called from NPL_EmbedCreate. Since we don't have
  1888.        any widgets that needs to be saved, this is just a stub. */
  1889. }
  1890.  
  1891. void
  1892. PSFE_SaveEmbedWindow(MWContext *context, NPEmbeddedApp *app)
  1893. {
  1894.     /* This will be called from NPL_EmbedDelete. Since we don't have
  1895.        any widgets that needs to be saved, this is just a stub. */
  1896. }
  1897.  
  1898. void
  1899. PSFE_RestoreEmbedWindow(MWContext *context, NPEmbeddedApp *app)
  1900. {
  1901.     /* This will be called from NPL_EmbedCreate. Since we don't have
  1902.        any widgets that needs to be saved, this is just a stub. */
  1903. }
  1904.  
  1905. void
  1906. PSFE_DestroyEmbedWindow(MWContext *context, NPEmbeddedApp *App)
  1907. {
  1908.     /* This will be called from NPL_EmbedDelete and/or
  1909.        NPL_FreeSessionData. Since we don't have any widgets that need
  1910.        to be destroyed, this is just a stub. */
  1911. }
  1912.  
  1913. void
  1914. PSFE_DisplayEmbed (MWContext *context,
  1915.           int iLocation, LO_EmbedStruct *embed_struct)
  1916. {
  1917.     NPPrintCallbackStruct npPrintInfo;
  1918.     NPEmbeddedApp *eApp;
  1919.     NPPrint npprint;
  1920.  
  1921.     if (!embed_struct) return;
  1922.     eApp = (NPEmbeddedApp *)embed_struct->FE_Data;
  1923.     if (!eApp) return;
  1924.  
  1925.     npprint.mode = NP_EMBED;
  1926.     npprint.print.embedPrint.platformPrint = NULL;
  1927.     npprint.print.embedPrint.window.window = NULL;
  1928.     npprint.print.embedPrint.window.x =
  1929.       embed_struct->x + embed_struct->x_offset;
  1930.     npprint.print.embedPrint.window.y =
  1931.       embed_struct->y + embed_struct->y_offset;
  1932.     npprint.print.embedPrint.window.width = embed_struct->width;
  1933.     npprint.print.embedPrint.window.height = embed_struct->height;
  1934.     
  1935.     npPrintInfo.type = NP_PRINT;
  1936.     npPrintInfo.fp = context->prSetup->out;
  1937.     npprint.print.embedPrint.platformPrint = (void *) &npPrintInfo;
  1938.  
  1939.     NPL_Print(eApp, &npprint);    
  1940. }
  1941.  
  1942. void
  1943. PSFE_GetEmbedSize (MWContext *context, LO_EmbedStruct *embed_struct,
  1944.           NET_ReloadMethod force_reload)
  1945. {
  1946.   NPEmbeddedApp *eApp = (NPEmbeddedApp *)embed_struct->FE_Data;
  1947.   
  1948.   if(eApp) return;
  1949.  
  1950.   /* attempt to make a plugin */
  1951.   if(!(eApp = NPL_EmbedCreate(context, embed_struct)) ||
  1952.      (embed_struct->ele_attrmask & LO_ELE_HIDDEN)) {
  1953.     return;
  1954.   }
  1955.  
  1956.   /* Determine if this is a fullpage plugin */
  1957.   if ((embed_struct->attribute_cnt > 0) &&
  1958.       (!strcmp(embed_struct->attribute_list[0], "src")) &&
  1959.       (!strcmp(embed_struct->value_list[0], "internal-external-plugin")))
  1960.     {
  1961.       embed_struct->width = context->prInfo->page_width;
  1962.       embed_struct->height = context->prInfo->page_height;
  1963.     }
  1964.  
  1965.   embed_struct->FE_Data = (void *)eApp;
  1966.  
  1967.   if (NPL_EmbedStart(context, embed_struct, eApp) != NPERR_NO_ERROR) {
  1968.     /* Spoil sport! */
  1969.     embed_struct->FE_Data = NULL;
  1970.     return;
  1971.   }
  1972. }
  1973. #endif /* !X_PLUGINS */
  1974.  
  1975. void PSFE_DisplayJavaApp(MWContext *context, int iLocation,
  1976.              LO_JavaAppStruct *java_app)
  1977. {
  1978. #ifdef JAVA
  1979.  
  1980.   int x, y;
  1981.   float w, h, tw, th;
  1982.   LJAppletData *ad = (LJAppletData *)java_app->session_data;
  1983.  
  1984.   if (!XP_CheckElementSpan(context,
  1985.               java_app->x + java_app->x_offset, java_app->height))
  1986.     return;
  1987.  
  1988.   /* Calculate (x,y) coordinate of bottom left corner. */
  1989.   x = java_app->x + java_app->x_offset;
  1990.   y = java_app->y + java_app->y_offset + java_app->height;
  1991.  
  1992.   w =  PAGE_TO_POINT_F(java_app->width);
  1993.   h =  PAGE_TO_POINT_F(java_app->height);
  1994.  
  1995.   tw = (float)java_app->width  / context->convertPixX;
  1996.   th = (float)java_app->height / context->convertPixY;
  1997.  
  1998.   XP_FilePrintf(context->prSetup->out, "BeginEPSF\n");
  1999.  
  2000.   /* Clip to the applet's bounding box */
  2001.   xl_moveto(context, java_app->x, java_app->y);
  2002.   xl_box(context, java_app->width, java_app->height);
  2003.   XP_FilePrintf(context->prSetup->out, "clip\n");
  2004.  
  2005.   xl_translate(context, x, y);
  2006.   XP_FilePrintf(context->prSetup->out, "%g %g scale\n", w/tw, h/th);
  2007.  
  2008.   XP_FilePrintf(context->prSetup->out, "%%%%BeginDocument: JavaApplet\n");
  2009.  
  2010.   ad->context = context;
  2011.  
  2012.   LJ_Applet_print(ad, (void *)context->prSetup->out);
  2013.  
  2014.   XP_FilePrintf(context->prSetup->out, "%%%%EndDocument\n");
  2015.   XP_FilePrintf(context->prSetup->out, "EndEPSF\n");
  2016.  
  2017. #endif /* JAVA */
  2018. }
  2019.  
  2020.