зеркало из https://github.com/mozilla/gecko-dev.git
792 строки
21 KiB
C
792 строки
21 KiB
C
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
|
*
|
|
* The contents of this file are subject to the Netscape Public
|
|
* License Version 1.1 (the "License"); you may not use this file
|
|
* except in compliance with the License. You may obtain a copy of
|
|
* the License at http://www.mozilla.org/NPL/
|
|
*
|
|
* Software distributed under the License is distributed on an "AS
|
|
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
|
|
* implied. See the License for the specific language governing
|
|
* rights and limitations under the License.
|
|
*
|
|
* The Original Code is mozilla.org code.
|
|
*
|
|
* The Initial Developer of the Original Code is Netscape
|
|
* Communications Corporation. Portions created by Netscape are
|
|
* Copyright (C) 1998 Netscape Communications Corporation. All
|
|
* Rights Reserved.
|
|
*
|
|
* Contributor(s):
|
|
*/
|
|
|
|
#include "xlate_i.h"
|
|
#include "ctxtfunc.h"
|
|
#include "net.h"
|
|
#include "libi18n.h"
|
|
#include "fe_proto.h"
|
|
#include "prefapi.h"
|
|
#include "intl_csi.h"
|
|
|
|
#define LLOYD_HACK 1
|
|
|
|
/*
|
|
** This code is sometimes called "The Text Front End", because it is a set
|
|
** of front end routines that deal with conversion of HTML to text, but it
|
|
** is more accurately the "Plain Text Converter". IMHO a "Text Front End"
|
|
** is something like Lynx.
|
|
**
|
|
** The basic strategy for the text front end is to collect bits in an internal
|
|
** buffer until it is known that no more data will be written into the area
|
|
** covered by that buffer, and at that point, output all the characters in
|
|
** the buffer.
|
|
**
|
|
** So far this file is almost entirely Michael Toy's fault. Eventually
|
|
** someone else will have to own this code, since Michael is showing
|
|
** signs of having been lobotomized.
|
|
*/
|
|
|
|
/*
|
|
** 11-20-96 pchen
|
|
**
|
|
** Added some XP_MAC's because we need construction of our new front end
|
|
** context object.
|
|
**
|
|
** ****************** NOTE! ******************
|
|
** If we ever override more context functions (i.e. implement stubbed
|
|
** out TXFE_* functions in stubs.c), you need to let a MacFE person
|
|
** know about the changes.
|
|
**
|
|
*/
|
|
|
|
#ifdef __cplusplus
|
|
extern "C" {
|
|
#endif
|
|
|
|
#ifdef XP_MAC
|
|
/* MacFE callbacks */
|
|
extern MWContext* CreatePlainTextConversionContext(MWContext* inUIContext);
|
|
extern void DisposePlainTextConversionContext(MWContext* inContext);
|
|
#endif /* XP_MAC */
|
|
|
|
/*
|
|
** This is the structure used to cache previously written on lines until
|
|
** such a time as it looks like they are needed.
|
|
*/
|
|
struct LineRecord_struct {
|
|
struct LineRecord_struct *next;
|
|
char *buffer;
|
|
int buffer_size;
|
|
int y_top;
|
|
};
|
|
|
|
/*
|
|
** prepare_to_render
|
|
** This routine makes sure that that rendering at "y" can be done
|
|
** by simply ignoring y and writing wherever the x value says to.
|
|
**
|
|
** What it does is build a singly linked list of LineRec's,
|
|
** and sets the cs->prInfo->line to point to the buffer field
|
|
** of the appropriate LineRecord.
|
|
*/
|
|
PRIVATE void
|
|
prepare_to_render(MWContext* cx, int y)
|
|
{
|
|
LineRecord *cur, *lr, *last;
|
|
|
|
/*
|
|
** Search for a line which covers this area already
|
|
*/
|
|
last = cur = NULL;
|
|
for (lr = cx->prInfo->saved_lines; lr != NULL; lr = lr->next) {
|
|
if (y+TEXT_HEIGHT/2 >= lr->y_top && y+TEXT_HEIGHT/2 < lr->y_top+TEXT_HEIGHT)
|
|
{
|
|
cur = lr;
|
|
break;
|
|
}
|
|
if (y+TEXT_HEIGHT/2 < lr->y_top)
|
|
break;
|
|
last = lr;
|
|
}
|
|
|
|
if (cur == NULL) {
|
|
/*
|
|
** Need to add a new line structure which covers the area spanned
|
|
** by this item.
|
|
*/
|
|
if ((cur = XP_NEW(LineRecord)) == NULL) {
|
|
cx->prInfo->line = NULL;
|
|
return;
|
|
}
|
|
|
|
cur->y_top = y;
|
|
if ((cur->buffer = (char *) XP_ALLOC(LINE_WIDTH)) == NULL) {
|
|
XP_DELETE(cur);
|
|
cx->prInfo->line = NULL;
|
|
return;
|
|
}
|
|
|
|
cur->next = NULL;
|
|
XP_MEMSET(cur->buffer, ' ', LINE_WIDTH);
|
|
cur->buffer_size = LINE_WIDTH;
|
|
|
|
if (last == NULL) {
|
|
cur->next = cx->prInfo->saved_lines;
|
|
cx->prInfo->saved_lines = cur;
|
|
} else {
|
|
cur->next = last->next;
|
|
last->next = cur;
|
|
}
|
|
}
|
|
|
|
/*
|
|
** In either case, "cur" now points to the LineRecord for the
|
|
** current item.
|
|
*/
|
|
cx->prInfo->line = cur->buffer;
|
|
}
|
|
|
|
PRIVATE void
|
|
default_completion(PrintSetup* p)
|
|
{
|
|
XP_FileClose(p->out);
|
|
}
|
|
|
|
PRIVATE void
|
|
tx_alldone(URL_Struct *URL_s, int status, MWContext *window_id)
|
|
{
|
|
window_id->prSetup->status = status;
|
|
}
|
|
|
|
PUBLIC void
|
|
XL_InitializeTextSetup(PrintSetup *p)
|
|
{
|
|
XP_BZERO(p, sizeof *p);
|
|
p->width = 76; /* don't use 79 here, or adding ">" makes it wrap. -jwz */
|
|
p->prefix = "";
|
|
p->eol = LINEBREAK;
|
|
p->completion = default_completion;
|
|
}
|
|
|
|
PRIVATE void
|
|
real_discard_translation_context(void *vcx)
|
|
{
|
|
MWContext *cx = (MWContext *)vcx;
|
|
|
|
if (cx) {
|
|
if (cx->prInfo) {
|
|
XP_DELETE(cx->prInfo);
|
|
}
|
|
if (cx->prSetup) XP_DELETE(cx->prSetup);
|
|
#ifndef XP_MAC
|
|
if (cx->funcs) XP_DELETE(cx->funcs);
|
|
XP_DELETE(cx);
|
|
#else
|
|
DisposePlainTextConversionContext(cx);
|
|
#endif /* ndef XP_MAC */
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Hack alert.
|
|
* 06-21-96 GAB 3.0 Beta 5 Critical Bug #23283
|
|
*
|
|
* When translating text in the composition window (quoting a
|
|
* message) and the window is closed, this context is
|
|
* interrupted. On interruption, AllConnectionsComplete
|
|
* gets called, which in turn calls this function.
|
|
* Previous incantation deleted the context and it's data; upon
|
|
* return to NET_InterruptWindow, the netlib attempts to
|
|
* reference the context (now freed), and we have an
|
|
* access violation.
|
|
* In order to avoid to problem, we set a timeout to delete
|
|
* ourselves at a later time (2 seconds later).
|
|
*/
|
|
PRIVATE void
|
|
discard_translation_context(MWContext *cx)
|
|
{
|
|
FE_SetTimeout(real_discard_translation_context, (void *)cx, 2000);
|
|
}
|
|
|
|
PUBLIC void TXFE_AllConnectionsComplete(MWContext *cx)
|
|
{
|
|
(*cx->prSetup->completion)(cx->prSetup);
|
|
LO_DiscardDocument(cx);
|
|
discard_translation_context(cx);
|
|
}
|
|
|
|
MODULE_PRIVATE void
|
|
TXFE_SetCallNetlibAllTheTime(MWContext *cx)
|
|
{
|
|
(*cx->prInfo->scnatt)(NULL);
|
|
}
|
|
|
|
MODULE_PRIVATE void
|
|
TXFE_ClearCallNetlibAllTheTime(MWContext *cx)
|
|
{
|
|
(*cx->prInfo->ccnatt)(NULL);
|
|
}
|
|
|
|
PUBLIC void
|
|
XL_AbortTextTranslation(XL_TextTranslation tt)
|
|
{
|
|
MWContext* cx = (MWContext*) tt;
|
|
NET_InterruptStream(cx->prSetup->url);
|
|
}
|
|
|
|
PUBLIC XL_TextTranslation
|
|
XL_TranslateText(MWContext* cx, URL_Struct *url_struct, PrintSetup* pi)
|
|
{
|
|
int nfd;
|
|
#ifndef XP_MAC
|
|
MWContext *text_context = XP_NewContext();
|
|
#else
|
|
MWContext *text_context = CreatePlainTextConversionContext(cx);
|
|
#endif /* ndef XP_MAC */
|
|
XP_Bool citation_p;
|
|
INTL_CharSetInfo text_csi;
|
|
|
|
if (text_context == NULL || pi == NULL || pi->out == NULL)
|
|
return NULL;
|
|
|
|
text_csi = LO_GetDocumentCharacterSetInfo(text_context);
|
|
text_context->type = MWContextText;
|
|
text_context->prInfo = XP_NEW(PrintInfo);
|
|
#ifndef XP_MAC
|
|
text_context->funcs = XP_NEW(ContextFuncs);
|
|
#endif /* ndef XP_MAC */
|
|
text_context->prSetup = XP_NEW(PrintSetup);
|
|
if (text_context->funcs == NULL || text_context->prSetup == NULL
|
|
|| text_context->prInfo == NULL)
|
|
{
|
|
discard_translation_context(text_context);
|
|
return NULL;
|
|
}
|
|
|
|
#ifndef XP_MAC
|
|
#define MAKE_FE_FUNCS_PREFIX(f) TXFE_##f
|
|
#define MAKE_FE_FUNCS_ASSIGN text_context->funcs->
|
|
#include "mk_cx_fn.h"
|
|
#endif /* ndef XP_MAC */
|
|
|
|
text_context->convertPixX = 1;
|
|
text_context->convertPixY = 1;
|
|
text_context->prInfo->page_width = pi->width * TEXT_WIDTH;
|
|
if (cx && cx->funcs) {
|
|
text_context->prInfo->scnatt = cx->funcs->SetCallNetlibAllTheTime;
|
|
text_context->prInfo->ccnatt = cx->funcs->ClearCallNetlibAllTheTime;
|
|
}
|
|
*text_context->prSetup = *pi;
|
|
text_context->prInfo->page_break = 0;
|
|
#ifdef LLOYD_HACK
|
|
text_context->prInfo->in_table = TRUE;
|
|
#else
|
|
text_context->prInfo->in_table = FALSE;
|
|
#endif
|
|
text_context->prInfo->first_line_p = TRUE;
|
|
text_context->prInfo->saved_lines = NULL;
|
|
text_context->prInfo->line = NULL;
|
|
text_context->prInfo->last_y = 0;
|
|
|
|
text_context->prSetup->url = url_struct;
|
|
|
|
#ifndef XP_MAC
|
|
INTL_SetCSIDocCSID(text_csi, INTL_DefaultDocCharSetID(cx)); /* For char code conversion */
|
|
INTL_SetCSIWinCSID(text_csi, INTL_DefaultWinCharSetID(cx)); /* For char code conversion */
|
|
#endif /* ndef XP_MAC */
|
|
|
|
url_struct->position_tag = 0;
|
|
|
|
/* Assume this is a news or mail citation if there is a prefix string.
|
|
We use a different format-out in this case so that mknews.c can be
|
|
more clever about this sort of thing. */
|
|
citation_p = pi->prefix && *pi->prefix;
|
|
|
|
/* strip off any named anchor information so that we don't
|
|
* truncate the document when quoting or saving
|
|
*/
|
|
if(url_struct->address)
|
|
XP_STRTOK(url_struct->address, "#");
|
|
nfd = NET_GetURL (url_struct,
|
|
(citation_p ? FO_QUOTE_MESSAGE : FO_SAVE_AS_TEXT),
|
|
text_context,
|
|
tx_alldone);
|
|
|
|
/* 5-31-96 jefft -- bug # 21519
|
|
* If for some reason we failed on getting URL return NULL.
|
|
* At this point text_context has been free'd somewhere down the
|
|
* chain through discard_translation_context(cx). text_context
|
|
* became invalid.
|
|
*/
|
|
if ( nfd < 0 ) return NULL;
|
|
|
|
return text_context;
|
|
}
|
|
|
|
PRIVATE void
|
|
measure_text(LO_TextStruct *text, LO_TextInfo *text_info, int start, int end)
|
|
{
|
|
text_info->ascent = TEXT_HEIGHT/2;
|
|
text_info->descent = TEXT_HEIGHT - text_info->ascent;
|
|
text_info->max_width = TEXT_WIDTH*(end-start+1);
|
|
text_info->lbearing = 0;
|
|
text_info->rbearing = 0;
|
|
}
|
|
|
|
MODULE_PRIVATE int
|
|
TXFE_GetTextInfo(MWContext *cx, LO_TextStruct *text, LO_TextInfo *text_info)
|
|
{
|
|
measure_text(text, text_info, 0, text->text_len-1);
|
|
return 0;
|
|
}
|
|
|
|
MODULE_PRIVATE void
|
|
TXFE_LayoutNewDocument(MWContext *cx, URL_Struct *url, int32 *w, int32 *h, int32* mw, int32* mh)
|
|
{
|
|
*w = cx->prInfo->page_width;
|
|
*h = 0;
|
|
*mw = *mh = 0;
|
|
}
|
|
|
|
PRIVATE void
|
|
text_at(MWContext *cx, int x, char *str, int len)
|
|
{
|
|
int line_width = LINE_WIDTH;
|
|
|
|
if (cx->prInfo->line == NULL) {
|
|
/*
|
|
** Something is wrong, either prepare_to_render wasn't called,
|
|
** which is a bug, or prepare_to_render failed to malloc enough
|
|
** space for the line buffer.
|
|
*/
|
|
return;
|
|
}
|
|
|
|
/* x counts for number of bytes previously wrote to the line */
|
|
x = (x + TEXT_WIDTH/2) / TEXT_WIDTH;
|
|
|
|
/***** 5/26/96 jefft -- bug# 21360
|
|
* if the len is >= to the default LINE_WIDTH we have to
|
|
* reallocate the line buffer. Otherwise, we will end up truncating
|
|
* the message. That would be really bad.
|
|
*/
|
|
if ( len + x >= LINE_WIDTH ) {
|
|
register LineRecord *cur = NULL;
|
|
|
|
line_width = len + x;
|
|
|
|
for ( cur = cx->prInfo->saved_lines; cur; cur = cur->next ) {
|
|
if ( cur->buffer == cx->prInfo->line ) break;
|
|
}
|
|
|
|
XP_ASSERT (cur);
|
|
/* don't really know this is right */
|
|
if ( !cur) return;
|
|
/* plus one accounts for the null character at the end */
|
|
cx->prInfo->line = XP_REALLOC (cx->prInfo->line, line_width+1);
|
|
if ( cx->prInfo->line == NULL ) return;
|
|
/* starts with +x; we don't want to wipe out the previously wrote
|
|
* strings, i.e. "< " quote strings
|
|
*/
|
|
XP_MEMSET ( cx->prInfo->line+x, ' ', len+1 );
|
|
cur->buffer = cx->prInfo->line;
|
|
cur->buffer_size = line_width+1;
|
|
}
|
|
|
|
while (x < line_width && len > 0) {
|
|
cx->prInfo->line[x] = *str++;
|
|
x++;
|
|
len--;
|
|
}
|
|
}
|
|
|
|
MODULE_PRIVATE void
|
|
TXFE_DisplaySubtext(MWContext *cx, int iLocation, LO_TextStruct *text,
|
|
int32 start_pos, int32 end_pos, XP_Bool notused)
|
|
{
|
|
int x;
|
|
LO_TextInfo i;
|
|
x = text->x + text->x_offset;
|
|
measure_text(text, &i, 0, start_pos-1); /* XXX too much work */
|
|
if (start_pos) {
|
|
x += i.max_width;
|
|
}
|
|
prepare_to_render(cx, text->y);
|
|
text_at(cx, x, (char*) text->text, end_pos - start_pos + 1);
|
|
}
|
|
|
|
MODULE_PRIVATE void
|
|
TXFE_DisplayText(MWContext *cx, int iLocation, LO_TextStruct *text, XP_Bool needbg)
|
|
{
|
|
(cx->funcs->DisplaySubtext)(cx, iLocation, text, 0, text->text_len-1, needbg);
|
|
}
|
|
|
|
MODULE_PRIVATE void
|
|
TXFE_DisplaySubDoc(MWContext *cx, int iLocation, LO_SubDocStruct *subdoc_struct)
|
|
{
|
|
return;
|
|
}
|
|
|
|
/*
|
|
** writeln
|
|
** Evidence that I once programmed in Pascal :). This routine
|
|
** writes out the passed buffer, prepending the correct prefix,
|
|
** stripping trailing spaces, and appending the correct line
|
|
** termination;
|
|
*/
|
|
PRIVATE void
|
|
writeln(MWContext *cx, char* s, int line_width)
|
|
{
|
|
char *buf = NULL;
|
|
char *cp=NULL;
|
|
char *prefix = cx->prSetup->prefix;
|
|
INTL_CharSetInfo csi = LO_GetDocumentCharacterSetInfo(cx);
|
|
int16 win_csid = INTL_GetCSIWinCSID(csi);
|
|
|
|
#ifdef USE_LINE_WIDTH
|
|
assert(cx->prSetup->prefix==NULL || strlen(cx->prSetup->prefix)<=LINE_WIDTH);
|
|
#else
|
|
assert(cx->prSetup->prefix==NULL || strlen(cx->prSetup->prefix)<=line_width);
|
|
#endif
|
|
|
|
buf = (char *) XP_ALLOC ( line_width << 1 );
|
|
|
|
/* If this is the first line, and the document is of type message/rfc822,
|
|
and there is a prefix, then we are in the ``Quote Document'' code for
|
|
a news or mail message. This means that the message/rfc822 converter
|
|
is going to emit a line like ``In <blah> foo@bar.com wrote:'' and we
|
|
should not prepend that line with "> ".
|
|
*/
|
|
if (cx->prInfo->first_line_p)
|
|
{
|
|
if (cx->prSetup->url &&
|
|
(!strcasecomp (cx->prSetup->url->content_type, MESSAGE_RFC822) ||
|
|
!strcasecomp (cx->prSetup->url->content_type, MESSAGE_NEWS)))
|
|
prefix = 0;
|
|
cx->prInfo->first_line_p = FALSE;
|
|
}
|
|
|
|
if (s != NULL) {
|
|
for (cp = s+line_width-2; cp >= s; cp--)
|
|
if (*cp != ' ') {
|
|
cp[1] = '\0';
|
|
break;
|
|
}
|
|
}
|
|
if (prefix)
|
|
XP_STRCPY(buf, prefix);
|
|
else
|
|
*buf = 0;
|
|
if (s != NULL && cp >= s)
|
|
XP_STRCAT(buf, s);
|
|
XP_STRCAT(buf, cx->prSetup->eol);
|
|
|
|
/* Convert nobreakspace to space.
|
|
Maybe this is wrong... */
|
|
/*
|
|
<ftang>
|
|
Answer: Yes, this is wrong.
|
|
\240 (0xA0) is not nobreakspace in many encoding.
|
|
It could be
|
|
DAGGER in MacRoman
|
|
LATIN CAPITAL LETTER YACUTE in MacRoman Icelandic and Faroese variations
|
|
characters in any other Macintosh character set.
|
|
The second byte of ShiftJIS characters
|
|
|
|
See Bug # 6640
|
|
|
|
for (s = buf; *s; s++)
|
|
if (*((unsigned char *) s) == '\240')
|
|
*s = ' ';
|
|
*/
|
|
/*
|
|
void INTL_StripNBSP(int16 csid, char* buf)
|
|
*/
|
|
if (CS_USER_DEFINED_ENCODING != win_csid)
|
|
{ /* strip out NBSP */
|
|
const char* nbsp = INTL_NonBreakingSpace(win_csid);
|
|
int nbsplen = XP_STRLEN(nbsp);
|
|
char* out;
|
|
char* next;
|
|
char* boundary = buf + XP_STRLEN(buf) - nbsplen;
|
|
XP_ASSERT((win_csid != CS_DEFAULT) && (win_csid != CS_UNKNOWN));
|
|
for (s = out = buf; *s;)
|
|
{
|
|
char* next = INTL_NextChar(win_csid, s);
|
|
if( (s <= boundary) && (0 == XP_STRNCMP(s, nbsp, nbsplen)))
|
|
{ /* if it is nbsp, replace it with space and advance the pointer */
|
|
*out = ' ';
|
|
out++;
|
|
s = next;
|
|
}
|
|
else
|
|
{ /* if it is not nbsp, copy it */
|
|
for( ;s < next; s++, out++)
|
|
*out = *s;
|
|
}
|
|
}
|
|
*out = '\0'; /* NULL terminate it*/
|
|
}
|
|
XP_FileWrite(buf, XP_STRLEN(buf), cx->prSetup->out);
|
|
|
|
XP_FREE (buf);
|
|
}
|
|
|
|
/*
|
|
** expire_lines
|
|
** Write out data from the cache. If expire_all is TRUE
|
|
** then that is the secret code to dump the entire cache (at the end
|
|
** of the document.
|
|
*/
|
|
PRIVATE void
|
|
expire_lines(MWContext *cx, int bottom, XP_Bool expire_all)
|
|
{
|
|
LineRecord *cur, *next;
|
|
|
|
for (cur = (LineRecord *)cx->prInfo->saved_lines; cur != NULL; cur = next) {
|
|
if (!expire_all && cur->y_top > bottom)
|
|
return;
|
|
cx->prInfo->saved_lines = (LineRecord *)cur->next;
|
|
next = cur->next;
|
|
if ((cur->y_top - cx->prInfo->last_y) > TEXT_HEIGHT/2)
|
|
writeln(cx, NULL, LINE_WIDTH);
|
|
writeln(cx, cur->buffer, cur->buffer_size);
|
|
cx->prInfo->last_y = cur->y_top + TEXT_HEIGHT;
|
|
XP_FREE(cur->buffer);
|
|
XP_FREE(cur);
|
|
}
|
|
}
|
|
|
|
/*
|
|
** TXFE_DisplayTable
|
|
** This routine arranges that lines will be cached for the entire
|
|
** span of the table, since table data is not drawn from top
|
|
** top bottom.
|
|
**
|
|
** It is SUPPOSED to draw borders, but doesn't, mostly because
|
|
** there is no way to tell the layout engine that borders are
|
|
** the thickness of a character.
|
|
*/
|
|
|
|
MODULE_PRIVATE
|
|
void TXFE_DisplayTable(MWContext *cx, int iLoc, LO_TableStruct *table)
|
|
{
|
|
if (cx->prInfo->in_table)
|
|
return;
|
|
cx->prInfo->table_top = table->y;
|
|
cx->prInfo->table_bottom = table->y + table->line_height;
|
|
#ifndef LLOYD_HACK
|
|
cx->prInfo->in_table = TRUE;
|
|
#endif
|
|
}
|
|
|
|
/*
|
|
** TXFE_DisplayLineFeed
|
|
** Here it is that text actually gets emitted from the translation.
|
|
** If there is reason to believe that some of the old cached lines are
|
|
** 'finished', those lines are written out and wiped from the cache.
|
|
*/
|
|
|
|
MODULE_PRIVATE void
|
|
TXFE_DisplayLineFeed(MWContext *cx, int iLocation, LO_LinefeedStruct *line_feed, XP_Bool notused)
|
|
{
|
|
int my_bottom = line_feed->y + line_feed->line_height;
|
|
if (cx->prInfo->in_table) {
|
|
#ifndef LLOYD_HACK
|
|
if (line_feed->y >= cx->prInfo->table_bottom)
|
|
{
|
|
expire_lines(cx, cx->prInfo->table_bottom, FALSE);
|
|
cx->prInfo->in_table = FALSE;
|
|
}
|
|
#endif
|
|
} else {
|
|
expire_lines(cx, my_bottom, FALSE);
|
|
}
|
|
}
|
|
|
|
/*
|
|
** TXFE_DisplayHR
|
|
** XXX I want this routine to use "=" if the HR is a "thick" one.
|
|
**
|
|
*/
|
|
MODULE_PRIVATE void
|
|
TXFE_DisplayHR(MWContext *cx, int iLocation , LO_HorizRuleStruct *HR)
|
|
{
|
|
int x, left;
|
|
int32 width = 72;
|
|
|
|
/*
|
|
** jefft -- You may say this is a hack. Indeed, it is a hack. In order
|
|
** to preserve the plain text line format when quoting we set the print->width
|
|
** with a extreme large number 998 so that we won't have long/short wrapping
|
|
** pattern (refer to lib/libmsg/msgcpane.cpp MSG_CompositionPane::QuoteMessage())
|
|
** This causes problem when quoting a multipart/mixed text/plain message +
|
|
** text/plain attachment. It creates an extremely long line of separator.
|
|
** It seems reasonable to do some adjustment here to limit the width of
|
|
** the separator to the setting of current wrap long line length.
|
|
**/
|
|
PREF_GetIntPref("mailnews.wraplength", &width);
|
|
|
|
width *= TEXT_WIDTH; /* in pixel */
|
|
left = x = (TEXT_WIDTH << 1) + HR->x_offset;
|
|
|
|
if (HR->width < width) {
|
|
/* BUG 83737 -- since the line separator has been centered within
|
|
** the window's coordinate we might as well adjust the start of the
|
|
** x.
|
|
*/
|
|
width = HR->width;
|
|
left = x = HR->x + HR->x_offset;
|
|
}
|
|
|
|
prepare_to_render(cx, HR->y);
|
|
for (; x < left + width; x += TEXT_WIDTH)
|
|
text_at(cx, x, "-", 1);
|
|
}
|
|
|
|
/*
|
|
** TXFE_TranslateISOText
|
|
** This assumes the text is already ISO. This is wrong, it should call
|
|
** the correct front end translation routine. I have some vague memory
|
|
** that perhaps the Mac front end patches out this function pointer
|
|
** but it is something which should be looked into
|
|
*/
|
|
|
|
MODULE_PRIVATE char *
|
|
TXFE_TranslateISOText(MWContext *cx, int charset, char *ISO_Text)
|
|
{
|
|
return ISO_Text;
|
|
}
|
|
|
|
/*
|
|
** XL_DisplayTextImage
|
|
** Just display the alt text. It currently displays in the upper left
|
|
** of the image rectangle. Perhaps in future it should try and center
|
|
** the alt text in the image.
|
|
*/
|
|
PUBLIC void
|
|
XL_DisplayTextImage(MWContext *cx, int iLocation, LO_ImageStruct *img)
|
|
{
|
|
int x = img->x + img->x_offset;
|
|
char *p;
|
|
|
|
prepare_to_render(cx, img->y);
|
|
if (img->alt_len > 0) {
|
|
PA_LOCK(p, char*, img->alt);
|
|
if (*p != '[')
|
|
text_at(cx, x, "[", 1);
|
|
text_at(cx, x+TEXT_WIDTH, p, img->alt_len);
|
|
if (p[img->alt_len-1] != ']')
|
|
text_at(cx, x+TEXT_WIDTH*(img->alt_len+1), "]", 1);
|
|
PA_UNLOCK(img->alt);
|
|
}
|
|
}
|
|
|
|
/*
|
|
** XL_GetTextImage
|
|
** All images are ignored in the text front end. This routine is
|
|
** just here to insure that layout doesn't block and that all images
|
|
** at least have the default ALT tag text.
|
|
*/
|
|
PRIVATE char img[] = "Image";
|
|
PUBLIC void
|
|
XL_GetTextImage(LO_ImageStruct *image)
|
|
{
|
|
if (image->alt_len == 0)
|
|
if (image->alt == NULL)
|
|
{
|
|
/*
|
|
** No ALT tag specified, insert make it appear as [Image]
|
|
*/
|
|
char *p;
|
|
if ((image->alt = PA_ALLOC((sizeof img) - 1)) == NULL) {
|
|
image->width = 1;
|
|
image->height = 1;
|
|
return;
|
|
}
|
|
image->alt_len = (sizeof img) - 1;
|
|
p = PA_LOCK(p, char*, image->alt);
|
|
XP_MEMMOVE(p, img, (sizeof img) - 1);
|
|
PA_UNLOCK(image->alt);
|
|
}
|
|
else
|
|
{
|
|
image->width = 1;
|
|
image->height = 1;
|
|
}
|
|
image->width = TEXT_WIDTH*(2+image->alt_len);
|
|
image->height = TEXT_HEIGHT;
|
|
}
|
|
|
|
/*
|
|
** TXFE_DisplayBullet
|
|
**
|
|
** The only magic here is the calculation about how far to back up
|
|
** in order to get the bullet at the correct location. The calculation
|
|
** is based on reading the layout code for bulleted lists.
|
|
*/
|
|
MODULE_PRIVATE void
|
|
TXFE_DisplayBullet(MWContext *cx, int iLocation, LO_BullettStruct *bullet)
|
|
{
|
|
int x = bullet->x + bullet->x_offset;
|
|
|
|
prepare_to_render(cx, bullet->y);
|
|
x += 2*bullet->width;
|
|
x -= 2*TEXT_WIDTH;
|
|
switch (bullet->bullet_type) {
|
|
case BULLET_ROUND:
|
|
text_at(cx, x, "o", 1);
|
|
break;
|
|
case BULLET_BASIC:
|
|
text_at(cx, x, "*", 1);
|
|
break;
|
|
case BULLET_SQUARE:
|
|
text_at(cx, x, "+", 1);
|
|
break;
|
|
case BULLET_MQUOTE:
|
|
text_at(cx, x, ">", 1);
|
|
break;
|
|
}
|
|
}
|
|
|
|
MODULE_PRIVATE void
|
|
TXFE_DisplayBorder(MWContext *context, int iLocation, int x, int y, int width,
|
|
int height, int bw, LO_Color *color, LO_LineStyle style)
|
|
{
|
|
}
|
|
|
|
|
|
MODULE_PRIVATE void
|
|
TXFE_DisplayFeedback(MWContext *context, int iLocation, LO_Element *element)
|
|
{
|
|
}
|
|
|
|
MODULE_PRIVATE void
|
|
TXFE_FinishedLayout(MWContext *cx)
|
|
{
|
|
expire_lines(cx, 0, TRUE);
|
|
}
|
|
|
|
MODULE_PRIVATE char *
|
|
TXFE_PromptPassword(MWContext *cx, const char *msg)
|
|
{
|
|
MWContext *wincx = cx->prSetup->cx;
|
|
/* If we don't have a context, go find one. This is really a hack, we may
|
|
* attach to some random window, but at least the print/saveas/etc will
|
|
* still work. Our caller can prevent this by actually setting cx->prSetup->cx
|
|
* to something that will really stay around until the save or print is
|
|
* complete */
|
|
if (wincx == NULL) {
|
|
wincx = XP_FindSomeContext();
|
|
}
|
|
|
|
if (wincx != NULL)
|
|
return FE_PromptPassword(wincx, msg);
|
|
|
|
return NULL;
|
|
}
|
|
|
|
#ifdef __cplusplus
|
|
}
|
|
#endif
|