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

  1. /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
  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. #include "xlate_i.h"
  20. #include "ctxtfunc.h"
  21. #include "net.h"
  22. #include "libi18n.h"
  23. #include "fe_proto.h"
  24. #include "prefapi.h"
  25. #include "intl_csi.h"
  26.  
  27. #define LLOYD_HACK    1
  28.  
  29. /*
  30. ** This code is sometimes called "The Text Front End", because it is a set
  31. ** of front end routines that deal with conversion of HTML to text, but it
  32. ** is more accurately the "Plain Text Converter".  IMHO a "Text Front End"
  33. ** is something like Lynx.
  34. **
  35. ** The basic strategy for the text front end is to collect bits in an internal
  36. ** buffer until it is known that no more data will be written into the area
  37. ** covered by that buffer, and at that point, output all the characters in
  38. ** the buffer.
  39. **
  40. ** So far this file is almost entirely Michael Toy's fault.  Eventually
  41. ** someone else will have to own this code, since Michael is showing
  42. ** signs of having been lobotomized.
  43. */
  44.  
  45. /*
  46. ** 11-20-96 pchen
  47. **
  48. ** Added some XP_MAC's because we need construction of our new front end
  49. ** context object.
  50. **
  51. ** ****************** NOTE! ******************
  52. ** If we ever override more context functions (i.e. implement stubbed
  53. ** out TXFE_* functions in stubs.c), you need to let a MacFE person
  54. ** know about the changes.
  55. **
  56. */
  57.  
  58. #ifdef __cplusplus
  59. extern "C" {
  60. #endif
  61.  
  62. #ifdef XP_MAC
  63. /* MacFE callbacks */
  64. extern MWContext* CreatePlainTextConversionContext(MWContext* inUIContext);
  65. extern void DisposePlainTextConversionContext(MWContext* inContext);
  66. #endif /* XP_MAC */
  67.  
  68. /*
  69. ** This is the structure used to cache previously written on lines until
  70. ** such a time as it looks like they are needed.
  71. */
  72. struct LineRecord_struct {
  73.   struct LineRecord_struct *next;
  74.   char *buffer;
  75.   int  buffer_size;
  76.   int y_top;
  77. };
  78.  
  79. /*
  80. ** prepare_to_render
  81. **    This routine makes sure that that rendering at "y" can be done
  82. **    by simply ignoring y and writing wherever the x value says to.
  83. **
  84. **    What it does is build a singly linked list of LineRec's,
  85. **    and sets the cs->prInfo->line to point to the buffer field
  86. **    of the appropriate LineRecord.
  87. */
  88. PRIVATE void
  89. prepare_to_render(MWContext* cx, int y)
  90. {
  91.   LineRecord *cur, *lr, *last;
  92.  
  93.   /*
  94.   ** Search for a line which covers this area already
  95.   */
  96.   last = cur = NULL;
  97.   for (lr = cx->prInfo->saved_lines; lr != NULL; lr = lr->next) {
  98.     if (y+TEXT_HEIGHT/2 >= lr->y_top && y+TEXT_HEIGHT/2 < lr->y_top+TEXT_HEIGHT)
  99.     {
  100.       cur = lr;
  101.       break;
  102.     }
  103.     if (y+TEXT_HEIGHT/2 < lr->y_top)
  104.       break;
  105.     last = lr;
  106.   }
  107.   
  108.   if (cur == NULL) {
  109.     /*
  110.     ** Need to add a new line structure which covers the area spanned
  111.     ** by this item.
  112.     */
  113.     if ((cur = XP_NEW(LineRecord)) == NULL) {
  114.       cx->prInfo->line = NULL;
  115.       return;
  116.     }
  117.  
  118.     cur->y_top = y;
  119.     if ((cur->buffer = (char *) XP_ALLOC(LINE_WIDTH)) == NULL) {
  120.       XP_DELETE(cur);
  121.       cx->prInfo->line = NULL;
  122.       return;
  123.     }
  124.  
  125.     cur->next = NULL;
  126.     XP_MEMSET(cur->buffer, ' ', LINE_WIDTH);
  127.     cur->buffer_size = LINE_WIDTH;
  128.  
  129.     if (last == NULL) {
  130.       cur->next = cx->prInfo->saved_lines;
  131.       cx->prInfo->saved_lines = cur;
  132.     } else {
  133.       cur->next = last->next;
  134.       last->next = cur;
  135.     }
  136.   }
  137.   
  138.   /*
  139.   ** In either case, "cur" now points to the LineRecord for the
  140.   ** current item.
  141.   */
  142.   cx->prInfo->line = cur->buffer;
  143. }
  144.  
  145. PRIVATE void
  146. default_completion(PrintSetup* p)
  147. {
  148.   XP_FileClose(p->out);
  149. }
  150.  
  151. PRIVATE void
  152. tx_alldone(URL_Struct *URL_s, int status, MWContext *window_id)
  153. {
  154.   window_id->prSetup->status = status;
  155. }
  156.  
  157. PUBLIC void
  158. XL_InitializeTextSetup(PrintSetup *p)
  159. {
  160.   XP_BZERO(p, sizeof *p);
  161.   p->width = 76;  /* don't use 79 here, or adding ">" makes it wrap. -jwz */
  162.   p->prefix = "";
  163.   p->eol = LINEBREAK;
  164.   p->completion = default_completion;
  165. }
  166.  
  167. PRIVATE void
  168. real_discard_translation_context(void *vcx)
  169. {
  170.   MWContext *cx = (MWContext *)vcx;
  171.  
  172.   if (cx) {
  173.     if (cx->prInfo) {
  174.       XP_DELETE(cx->prInfo);
  175.     }
  176.     if (cx->prSetup) XP_DELETE(cx->prSetup);
  177. #ifndef XP_MAC
  178.     if (cx->funcs) XP_DELETE(cx->funcs);
  179.     XP_DELETE(cx);
  180. #else
  181.     DisposePlainTextConversionContext(cx);
  182. #endif /* ndef XP_MAC */
  183.   }
  184. }
  185.  
  186. /*
  187.  *  Hack alert.
  188.  *  06-21-96 GAB 3.0 Beta 5 Critical Bug #23283
  189.  *
  190.  *  When translating text in the composition window (quoting a
  191.  *      message) and the window is closed, this context is
  192.  *      interrupted.  On interruption, AllConnectionsComplete
  193.  *      gets called, which in turn calls this function.
  194.  *  Previous incantation deleted the context and it's data; upon
  195.  *      return to NET_InterruptWindow, the netlib attempts to
  196.  *      reference the context (now freed), and we have an
  197.  *      access violation.
  198.  *  In order to avoid to problem, we set a timeout to delete
  199.  *      ourselves at a later time (2 seconds later).
  200.  */
  201. PRIVATE void
  202. discard_translation_context(MWContext *cx)
  203. {
  204.   FE_SetTimeout(real_discard_translation_context, (void *)cx, 2000);
  205. }
  206.  
  207. PUBLIC void TXFE_AllConnectionsComplete(MWContext *cx) 
  208. {
  209.   (*cx->prSetup->completion)(cx->prSetup);
  210.   LO_DiscardDocument(cx);
  211.   discard_translation_context(cx);
  212. }
  213.  
  214. MODULE_PRIVATE void
  215. TXFE_SetCallNetlibAllTheTime(MWContext *cx)
  216. {
  217.   (*cx->prInfo->scnatt)(NULL);
  218. }
  219.  
  220. MODULE_PRIVATE void
  221. TXFE_ClearCallNetlibAllTheTime(MWContext *cx)
  222. {
  223.   (*cx->prInfo->ccnatt)(NULL);
  224. }
  225.  
  226. PUBLIC void
  227. XL_AbortTextTranslation(XL_TextTranslation tt)
  228. {
  229.   MWContext* cx = (MWContext*) tt;
  230.   NET_InterruptStream(cx->prSetup->url);
  231. }
  232.  
  233. PUBLIC XL_TextTranslation
  234. XL_TranslateText(MWContext* cx, URL_Struct *url_struct, PrintSetup* pi)
  235. {
  236.   int nfd;
  237. #ifndef XP_MAC
  238.   MWContext *text_context = XP_NewContext();
  239. #else
  240.   MWContext *text_context = CreatePlainTextConversionContext(cx);
  241. #endif /* ndef XP_MAC */
  242.   XP_Bool citation_p;
  243.   INTL_CharSetInfo text_csi;
  244.  
  245.   if (text_context == NULL || pi == NULL || pi->out == NULL)
  246.     return NULL;
  247.  
  248.   text_csi = LO_GetDocumentCharacterSetInfo(text_context);
  249.   text_context->type = MWContextText;
  250.   text_context->prInfo = XP_NEW(PrintInfo);
  251. #ifndef XP_MAC
  252.   text_context->funcs = XP_NEW(ContextFuncs);
  253. #endif /* ndef XP_MAC */
  254.   text_context->prSetup = XP_NEW(PrintSetup);
  255.   if (text_context->funcs == NULL || text_context->prSetup == NULL
  256.       || text_context->prInfo == NULL)
  257.   {
  258.     discard_translation_context(text_context);
  259.     return NULL;
  260.   }
  261.  
  262. #ifndef XP_MAC
  263. #define MAKE_FE_FUNCS_PREFIX(f) TXFE_##f
  264. #define MAKE_FE_FUNCS_ASSIGN text_context->funcs->
  265. #include "mk_cx_fn.h"
  266. #endif /* ndef XP_MAC */
  267.  
  268.   text_context->convertPixX = 1;
  269.   text_context->convertPixY = 1;
  270.   text_context->prInfo->page_width = pi->width * TEXT_WIDTH;
  271.   if (cx && cx->funcs) {
  272.     text_context->prInfo->scnatt = cx->funcs->SetCallNetlibAllTheTime;
  273.     text_context->prInfo->ccnatt = cx->funcs->ClearCallNetlibAllTheTime;
  274.   }
  275.   *text_context->prSetup = *pi;
  276.   text_context->prInfo->page_break = 0;
  277. #ifdef LLOYD_HACK
  278.   text_context->prInfo->in_table = TRUE;
  279. #else
  280.   text_context->prInfo->in_table = FALSE;
  281. #endif
  282.   text_context->prInfo->first_line_p = TRUE;
  283.   text_context->prInfo->saved_lines = NULL;
  284.   text_context->prInfo->line = NULL;
  285.   text_context->prInfo->last_y = 0;
  286.  
  287.   text_context->prSetup->url = url_struct;
  288.  
  289. #ifndef XP_MAC
  290.   INTL_SetCSIDocCSID(text_csi, INTL_DefaultDocCharSetID(cx));    /* For char code conversion    */
  291.   INTL_SetCSIWinCSID(text_csi, INTL_DefaultWinCharSetID(cx));    /* For char code conversion    */
  292. #endif /* ndef XP_MAC */
  293.  
  294.   url_struct->position_tag = 0;
  295.  
  296.   /* Assume this is a news or mail citation if there is a prefix string.
  297.      We use a different format-out in this case so that mknews.c can be
  298.      more clever about this sort of thing. */
  299.   citation_p = pi->prefix && *pi->prefix;
  300.  
  301.   /* strip off any named anchor information so that we don't
  302.    * truncate the document when quoting or saving
  303.    */
  304.   if(url_struct->address)
  305.       XP_STRTOK(url_struct->address, "#");
  306.   nfd = NET_GetURL (url_struct,
  307.             (citation_p ? FO_QUOTE_MESSAGE : FO_SAVE_AS_TEXT),
  308.             text_context,
  309.             tx_alldone);
  310.  
  311.   /* 5-31-96 jefft -- bug # 21519
  312.    * If for some reason we failed on getting URL return NULL.
  313.    * At this point text_context has been free'd somewhere down the
  314.    * chain through discard_translation_context(cx). text_context
  315.    * became invalid.
  316.    */
  317.   if ( nfd < 0 ) return NULL;
  318.  
  319.   return text_context;
  320. }
  321.  
  322. PRIVATE void
  323. measure_text(LO_TextStruct *text, LO_TextInfo *text_info, int start, int end)
  324. {
  325.     text_info->ascent = TEXT_HEIGHT/2;
  326.     text_info->descent = TEXT_HEIGHT - text_info->ascent;
  327.     text_info->max_width = TEXT_WIDTH*(end-start+1);
  328.     text_info->lbearing = 0;
  329.     text_info->rbearing = 0;
  330. }
  331.  
  332. MODULE_PRIVATE int
  333. TXFE_GetTextInfo(MWContext *cx, LO_TextStruct *text, LO_TextInfo *text_info)
  334. {
  335.     measure_text(text, text_info, 0, text->text_len-1);
  336.     return 0;
  337. }
  338.  
  339. MODULE_PRIVATE void
  340. TXFE_LayoutNewDocument(MWContext *cx, URL_Struct *url, int32 *w, int32 *h, int32* mw, int32* mh)
  341. {
  342.     *w = cx->prInfo->page_width;
  343.     *h = 0;
  344.     *mw = *mh = 0;
  345. }
  346.  
  347. PRIVATE void
  348. text_at(MWContext *cx, int x, char *str, int len)
  349. {
  350.   int line_width =  LINE_WIDTH;
  351.  
  352.     if (cx->prInfo->line == NULL) {
  353.       /*
  354.       ** Something is wrong, either prepare_to_render wasn't called,
  355.       ** which is a bug, or prepare_to_render failed to malloc enough
  356.       ** space for the line buffer.
  357.       */
  358.       return;
  359.     }
  360.  
  361.     /* x counts for number of bytes previously wrote to the line */
  362.     x = (x + TEXT_WIDTH/2) / TEXT_WIDTH;
  363.  
  364.     /***** 5/26/96 jefft -- bug# 21360
  365.      * if the len is >= to the default LINE_WIDTH we have to
  366.      * reallocate the line buffer. Otherwise, we will end up truncating
  367.      * the message. That would be really bad.
  368.      */
  369.     if ( len + x >= LINE_WIDTH ) {
  370.       register LineRecord *cur = NULL;
  371.  
  372.       line_width = len + x;
  373.  
  374.       for ( cur = cx->prInfo->saved_lines; cur; cur = cur->next ) {
  375.         if ( cur->buffer == cx->prInfo->line ) break;
  376.       }
  377.  
  378.       XP_ASSERT (cur);
  379.       /* don't really know this is right */
  380.       if ( !cur) return;
  381.       /* plus one accounts for the null character at the end */
  382.       cx->prInfo->line = XP_REALLOC (cx->prInfo->line, line_width+1);
  383.       if ( cx->prInfo->line == NULL ) return;
  384.       /* starts with +x; we don't want to wipe out the previously wrote
  385.        * strings, i.e. "< " quote strings
  386.        */
  387.       XP_MEMSET ( cx->prInfo->line+x, ' ', len+1 );
  388.       cur->buffer = cx->prInfo->line;
  389.       cur->buffer_size = line_width+1;
  390.     }
  391.     
  392.     while (x < line_width && len > 0) {
  393.     cx->prInfo->line[x] = *str++;
  394.     x++;
  395.     len--;
  396.     }
  397. }
  398.  
  399. MODULE_PRIVATE void
  400. TXFE_DisplaySubtext(MWContext *cx, int iLocation, LO_TextStruct *text,
  401.             int32 start_pos, int32 end_pos, XP_Bool notused)
  402. {
  403.     int x;
  404.     LO_TextInfo i;
  405.     x = text->x + text->x_offset;
  406.     measure_text(text, &i, 0, start_pos-1);    /* XXX too much work */
  407.     if (start_pos) {
  408.     x += i.max_width;
  409.     }
  410.     prepare_to_render(cx, text->y);
  411.     text_at(cx, x, (char*) text->text, end_pos - start_pos + 1);
  412. }
  413.  
  414. MODULE_PRIVATE void
  415. TXFE_DisplayText(MWContext *cx, int iLocation, LO_TextStruct *text, XP_Bool needbg)
  416. {
  417.     (cx->funcs->DisplaySubtext)(cx, iLocation, text, 0, text->text_len-1, needbg);
  418. }
  419.  
  420. MODULE_PRIVATE void
  421. TXFE_DisplaySubDoc(MWContext *cx, int iLocation, LO_SubDocStruct *subdoc_struct)
  422. {
  423.     return;
  424. }
  425.  
  426. /*
  427. ** writeln
  428. **    Evidence that I once programmed in Pascal :).  This routine
  429. **    writes out the passed buffer, prepending the correct prefix,
  430. **    stripping trailing spaces, and appending the correct line
  431. **    termination;
  432. */
  433. PRIVATE void
  434. writeln(MWContext *cx, char* s, int line_width)
  435. {
  436.   char *buf = NULL;
  437.   char *cp;
  438.   char *prefix = cx->prSetup->prefix;
  439.   INTL_CharSetInfo csi = LO_GetDocumentCharacterSetInfo(cx);
  440.   int16 win_csid = INTL_GetCSIWinCSID(csi);
  441.  
  442. #ifdef USE_LINE_WIDTH
  443.   assert(cx->prSetup->prefix==NULL || strlen(cx->prSetup->prefix)<=LINE_WIDTH);
  444. #else
  445.   assert(cx->prSetup->prefix==NULL || strlen(cx->prSetup->prefix)<=line_width); 
  446. #endif
  447.  
  448.   buf = (char *) XP_ALLOC ( line_width << 1 );
  449.  
  450.   /* If this is the first line, and the document is of type message/rfc822,
  451.      and there is a prefix, then we are in the ``Quote Document'' code for
  452.      a news or mail message.  This means that the message/rfc822 converter
  453.      is going to emit a line like ``In <blah> foo@bar.com wrote:'' and we
  454.      should not prepend that line with "> ".
  455.    */
  456.   if (cx->prInfo->first_line_p)
  457.     {
  458.       if (cx->prSetup->url &&
  459.       (!strcasecomp (cx->prSetup->url->content_type, MESSAGE_RFC822) ||
  460.        !strcasecomp (cx->prSetup->url->content_type, MESSAGE_NEWS)))
  461.     prefix = 0;
  462.       cx->prInfo->first_line_p = FALSE;
  463.     }
  464.  
  465.   if (s != NULL) {
  466.     for (cp = s+line_width-2; cp >= s; cp--)
  467.       if (*cp != ' ') {
  468.     cp[1] = '\0';
  469.     break;
  470.       }
  471.   }
  472.   if (prefix)
  473.     XP_STRCPY(buf, prefix);
  474.   else
  475.     *buf = 0;
  476.   if (s != NULL && cp >= s)
  477.     XP_STRCAT(buf, s);
  478.   XP_STRCAT(buf, cx->prSetup->eol);
  479.  
  480.   /* Convert nobreakspace to space.
  481.      Maybe this is wrong... */
  482. /*
  483.     <ftang>
  484.     Answer: Yes, this is wrong.
  485.         \240 (0xA0) is not nobreakspace in many encoding.
  486.         It could be 
  487.         DAGGER in MacRoman
  488.         LATIN CAPITAL LETTER YACUTE in MacRoman Icelandic and Faroese variations
  489.         characters in any other Macintosh character set.
  490.         The second byte of ShiftJIS characters
  491.  
  492.         See Bug # 6640
  493.         
  494.   for (s = buf; *s; s++)
  495.     if (*((unsigned char *) s) == '\240')
  496.       *s = ' ';
  497. */
  498. /* 
  499. void INTL_StripNBSP(int16 csid, char* buf)
  500. */
  501.  if (CS_USER_DEFINED_ENCODING != win_csid)
  502.  { /* strip out NBSP */
  503.       const char* nbsp = INTL_NonBreakingSpace(win_csid);
  504.       int nbsplen = XP_STRLEN(nbsp);
  505.       char* out;
  506.       char* next;
  507.       char* boundary = buf + XP_STRLEN(buf) - nbsplen;
  508.       XP_ASSERT((win_csid != CS_DEFAULT) && (win_csid != CS_UNKNOWN));
  509.     for (s = out = buf; *s;)
  510.     {
  511.         char* next = INTL_NextChar(win_csid, s);
  512.         if( (s <= boundary)  && (0 == XP_STRNCMP(s, nbsp, nbsplen)))
  513.         { /* if it is nbsp, replace it with space and advance the pointer */
  514.             *out = ' ';
  515.             out++;
  516.             s = next;
  517.         }
  518.         else
  519.         { /* if it is not nbsp, copy it */
  520.             for( ;s < next; s++, out++)
  521.                 *out = *s;
  522.         }
  523.     }
  524.     *out = '\0'; /* NULL terminate it*/
  525.   }
  526.   XP_FileWrite(buf, XP_STRLEN(buf), cx->prSetup->out);
  527.  
  528.   XP_FREE (buf);
  529. }
  530.  
  531. /*
  532. ** expire_lines
  533. **    Write out data from the cache.  If expire_all is TRUE
  534. **    then that is the secret code to dump the entire cache (at the end
  535. **    of the document.
  536. */
  537. PRIVATE void
  538. expire_lines(MWContext *cx, int bottom, XP_Bool expire_all)
  539. {
  540.   LineRecord *cur, *next;
  541.  
  542.   for (cur = (LineRecord *)cx->prInfo->saved_lines; cur != NULL; cur = next) {
  543.     if (!expire_all && cur->y_top > bottom)
  544.       return;
  545.     cx->prInfo->saved_lines = (LineRecord *)cur->next;
  546.     next = cur->next;
  547.     if ((cur->y_top - cx->prInfo->last_y) > TEXT_HEIGHT/2)
  548.       writeln(cx, NULL, LINE_WIDTH);
  549.     writeln(cx, cur->buffer, cur->buffer_size);
  550.     cx->prInfo->last_y = cur->y_top + TEXT_HEIGHT;
  551.     XP_FREE(cur->buffer);
  552.     XP_FREE(cur);
  553.   }
  554. }
  555.  
  556. /*
  557. ** TXFE_DisplayTable
  558. **    This routine arranges that lines will be cached for the entire
  559. **    span of the table, since table data is not drawn from top
  560. **    top bottom.
  561. **
  562. **    It is SUPPOSED to draw borders, but doesn't, mostly because
  563. **    there is no way to tell the layout engine that borders are
  564. **    the thickness of a character.
  565. */
  566.  
  567. MODULE_PRIVATE
  568. void TXFE_DisplayTable(MWContext *cx, int iLoc, LO_TableStruct *table)
  569. {
  570.   if (cx->prInfo->in_table)
  571.     return;
  572.   cx->prInfo->table_top = table->y;
  573.   cx->prInfo->table_bottom = table->y + table->line_height;
  574. #ifndef LLOYD_HACK
  575.   cx->prInfo->in_table = TRUE;
  576. #endif
  577. }
  578.  
  579. /*
  580. ** TXFE_DisplayLineFeed
  581. **    Here it is that text actually gets emitted from the translation.
  582. **     If there is reason to believe that some of the old cached lines are
  583. **    'finished', those lines are written out and wiped from the cache.
  584. */
  585.  
  586. MODULE_PRIVATE void
  587. TXFE_DisplayLineFeed(MWContext *cx, int iLocation, LO_LinefeedStruct *line_feed, XP_Bool notused)
  588. {
  589.   int my_bottom = line_feed->y + line_feed->line_height;
  590.   if (cx->prInfo->in_table) {
  591. #ifndef LLOYD_HACK
  592.     if (line_feed->y >= cx->prInfo->table_bottom)
  593.     {
  594.       expire_lines(cx, cx->prInfo->table_bottom, FALSE);
  595.       cx->prInfo->in_table = FALSE;
  596.     }
  597. #endif
  598.   } else {
  599.     expire_lines(cx, my_bottom, FALSE);
  600.   }
  601. }
  602.  
  603. /*
  604. ** TXFE_DisplayHR
  605. **    XXX I want this routine to use "=" if the HR is a "thick" one.
  606. **
  607. */
  608. MODULE_PRIVATE void
  609. TXFE_DisplayHR(MWContext *cx, int iLocation , LO_HorizRuleStruct *HR)
  610. {
  611.   int x, left;
  612.   int32 width = 72;
  613.  
  614.   /*
  615.   ** jefft -- You may say this is a hack. Indeed, it is a hack. In order
  616.   ** to preserve the plain text line format when quoting we set the print->width
  617.   ** with a extreme large number 998 so that we won't have long/short wrapping
  618.   ** pattern (refer to lib/libmsg/msgcpane.cpp MSG_CompositionPane::QuoteMessage())
  619.   ** This causes problem when quoting a multipart/mixed text/plain message + 
  620.   ** text/plain attachment. It creates an extremely long line of separator. 
  621.   ** It seems reasonable to do some adjustment here to limit the width of 
  622.   ** the separator to the setting of current wrap long line length.
  623.   **/
  624.   PREF_GetIntPref("mailnews.wraplength", &width);
  625.  
  626.   width *= TEXT_WIDTH; /* in pixel */
  627.   left = x = (TEXT_WIDTH << 1) + HR->x_offset;
  628.  
  629.   if (HR->width < width) {
  630.       /* BUG 83737 -- since the line separator has been centered within
  631.       ** the window's coordinate we might as well adjust the start of the
  632.       ** x.
  633.       */
  634.       width = HR->width;
  635.       left = x = HR->x + HR->x_offset;
  636.   }
  637.  
  638.   prepare_to_render(cx, HR->y);
  639.   for (; x < left + width; x += TEXT_WIDTH)
  640.     text_at(cx, x, "-", 1);
  641. }
  642.  
  643. /*
  644. ** TXFE_TranslateISOText
  645. **    This assumes the text is already ISO.  This is wrong, it should call
  646. **    the correct front end translation routine.  I have some vague memory
  647. **    that perhaps the Mac front end patches out this function pointer
  648. **    but it is something which should be looked into
  649. */
  650.  
  651. MODULE_PRIVATE char *
  652. TXFE_TranslateISOText(MWContext *cx, int charset, char *ISO_Text)
  653. {
  654.     return ISO_Text;
  655. }
  656.  
  657. /*
  658. ** XL_DisplayTextImage
  659. **    Just display the alt text.  It currently displays in the upper left
  660. **    of the image rectangle.  Perhaps in future it should try and center
  661. **    the alt text in the image.
  662. */
  663. PUBLIC void
  664. XL_DisplayTextImage(MWContext *cx, int iLocation, LO_ImageStruct *img)
  665. {
  666.     int x = img->x + img->x_offset;
  667.     char *p;
  668.  
  669.     prepare_to_render(cx, img->y);
  670.     if (img->alt_len > 0) {
  671.       PA_LOCK(p, char*, img->alt);
  672.       if (*p != '[')
  673.     text_at(cx, x, "[", 1);
  674.       text_at(cx, x+TEXT_WIDTH, p, img->alt_len);
  675.       if (p[img->alt_len-1] != ']')
  676.     text_at(cx, x+TEXT_WIDTH*(img->alt_len+1), "]", 1);
  677.       PA_UNLOCK(img->alt);
  678.     }
  679. }
  680.  
  681. /*
  682. ** XL_GetTextImage
  683. **    All images are ignored in the text front end.  This routine is
  684. **    just here to insure that layout doesn't block and that all images
  685. **    at least have the default ALT tag text.
  686. */
  687. PRIVATE char img[] = "Image";
  688. PUBLIC void
  689. XL_GetTextImage(LO_ImageStruct *image)
  690. {
  691.     if (image->alt_len == 0)
  692.       if (image->alt == NULL)
  693.       {
  694.     /*
  695.     ** No ALT tag specified, insert  make it appear as [Image]
  696.     */
  697.     char *p;
  698.     if ((image->alt = PA_ALLOC((sizeof img) - 1)) == NULL) {
  699.         image->width = 1;
  700.         image->height = 1;
  701.         return;
  702.     }
  703.     image->alt_len = (sizeof img) - 1;
  704.     p = PA_LOCK(p, char*, image->alt);
  705.     XP_MEMMOVE(p, img, (sizeof img) - 1);
  706.     PA_UNLOCK(image->alt);
  707.       }
  708.       else
  709.       {
  710.     image->width = 1;
  711.     image->height = 1;
  712.       }
  713.     image->width = TEXT_WIDTH*(2+image->alt_len);
  714.     image->height = TEXT_HEIGHT;
  715. }
  716.  
  717. /*
  718. ** TXFE_DisplayBullet
  719. **
  720. **    The only magic here is the calculation about how far to back up
  721. **    in order to get the bullet at the correct location.  The calculation
  722. **    is based on reading the layout code for bulleted lists.
  723. */
  724. MODULE_PRIVATE void
  725. TXFE_DisplayBullet(MWContext *cx, int iLocation, LO_BullettStruct *bullet)
  726. {
  727.   int x = bullet->x + bullet->x_offset;
  728.  
  729.   prepare_to_render(cx, bullet->y);
  730.   x += 2*bullet->width;
  731.   x -= 2*TEXT_WIDTH;
  732.   switch (bullet->bullet_type) {
  733.     case BULLET_ROUND:
  734.       text_at(cx, x, "o", 1);
  735.       break;
  736.     case BULLET_BASIC:
  737.       text_at(cx, x, "*", 1);
  738.       break;
  739.     case BULLET_SQUARE:
  740.       text_at(cx, x, "+", 1);
  741.       break;
  742.     case BULLET_MQUOTE:
  743.       text_at(cx, x, ">", 1);
  744.       break;
  745.   }
  746. }
  747.  
  748. MODULE_PRIVATE void
  749. TXFE_DisplayBorder(MWContext *context, int iLocation, int x, int y, int width,
  750.                    int height, int bw, LO_Color *color, LO_LineStyle style)
  751. {
  752. }
  753.  
  754.  
  755. MODULE_PRIVATE void
  756. TXFE_DisplayFeedback(MWContext *context, int iLocation, LO_Element *element)
  757. {
  758. }
  759.  
  760. MODULE_PRIVATE void
  761. TXFE_FinishedLayout(MWContext *cx)
  762. {
  763.   expire_lines(cx, 0, TRUE);
  764. }
  765.  
  766. MODULE_PRIVATE char *
  767. TXFE_PromptPassword(MWContext *cx, const char *msg)
  768. {
  769.   MWContext *wincx = cx->prSetup->cx;
  770.   /* If we don't have a context, go find one. This is really a hack, we may
  771.    * attach to some random window, but at least the print/saveas/etc will
  772.    * still work. Our caller can prevent this by actually setting cx->prSetup->cx
  773.    * to something that will really stay around until the save or print is
  774.    * complete */
  775.   if (wincx == NULL) {
  776.     wincx = XP_FindSomeContext();
  777.   }
  778.  
  779.   if (wincx != NULL)
  780.     return FE_PromptPassword(wincx, msg);
  781.  
  782.   return NULL;
  783. }
  784.  
  785. #ifdef __cplusplus
  786. }
  787. #endif
  788.