2005-05-05 19:00:49 +00:00
|
|
|
/*
|
|
|
|
* RichEdit - RTF writer module
|
|
|
|
*
|
|
|
|
* Copyright 2005 by Phil Krylov
|
|
|
|
*
|
|
|
|
* This library is free software; you can redistribute it and/or
|
|
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
|
|
* License as published by the Free Software Foundation; either
|
|
|
|
* version 2.1 of the License, or (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This library is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
* Lesser General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
|
|
* License along with this library; if not, write to the Free Software
|
2007-04-20 11:26:32 +00:00
|
|
|
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
|
2005-05-05 19:00:49 +00:00
|
|
|
*/
|
|
|
|
|
|
|
|
#include "editor.h"
|
|
|
|
#include "rtf.h"
|
|
|
|
|
|
|
|
WINE_DEFAULT_DEBUG_CHANNEL(richedit);
|
|
|
|
|
2016-11-17 23:04:08 +00:00
|
|
|
#define STREAMOUT_BUFFER_SIZE 4096
|
|
|
|
#define STREAMOUT_FONTTBL_SIZE 8192
|
|
|
|
#define STREAMOUT_COLORTBL_SIZE 1024
|
|
|
|
|
|
|
|
typedef struct tagME_OutStream
|
|
|
|
{
|
|
|
|
EDITSTREAM *stream;
|
|
|
|
char buffer[STREAMOUT_BUFFER_SIZE];
|
|
|
|
UINT pos, written;
|
|
|
|
UINT nCodePage;
|
|
|
|
UINT nFontTblLen;
|
|
|
|
ME_FontTableItem fonttbl[STREAMOUT_FONTTBL_SIZE];
|
|
|
|
UINT nColorTblLen;
|
|
|
|
COLORREF colortbl[STREAMOUT_COLORTBL_SIZE];
|
|
|
|
UINT nDefaultFont;
|
|
|
|
UINT nDefaultCodePage;
|
|
|
|
/* nNestingLevel = 0 means we aren't in a cell, 1 means we are in a cell,
|
|
|
|
* an greater numbers mean we are in a cell nested within a cell. */
|
|
|
|
UINT nNestingLevel;
|
|
|
|
CHARFORMAT2W cur_fmt; /* current character format */
|
|
|
|
} ME_OutStream;
|
2014-04-26 16:54:06 +00:00
|
|
|
|
2005-05-05 19:00:49 +00:00
|
|
|
static BOOL
|
2007-11-29 11:12:33 +00:00
|
|
|
ME_StreamOutRTFText(ME_OutStream *pStream, const WCHAR *text, LONG nChars);
|
2005-05-05 19:00:49 +00:00
|
|
|
|
|
|
|
|
2007-04-20 11:26:32 +00:00
|
|
|
static ME_OutStream*
|
2005-05-05 19:00:49 +00:00
|
|
|
ME_StreamOutInit(ME_TextEditor *editor, EDITSTREAM *stream)
|
|
|
|
{
|
2007-04-20 11:26:32 +00:00
|
|
|
ME_OutStream *pStream = ALLOC_OBJ(ME_OutStream);
|
|
|
|
pStream->stream = stream;
|
|
|
|
pStream->stream->dwError = 0;
|
|
|
|
pStream->pos = 0;
|
|
|
|
pStream->written = 0;
|
|
|
|
pStream->nFontTblLen = 0;
|
|
|
|
pStream->nColorTblLen = 1;
|
2008-08-28 10:43:26 +00:00
|
|
|
pStream->nNestingLevel = 0;
|
2016-11-17 23:04:08 +00:00
|
|
|
memset(&pStream->cur_fmt, 0, sizeof(pStream->cur_fmt));
|
|
|
|
pStream->cur_fmt.dwEffects = CFE_AUTOCOLOR | CFE_AUTOBACKCOLOR;
|
|
|
|
pStream->cur_fmt.bUnderlineType = CFU_UNDERLINE;
|
2007-04-20 11:26:32 +00:00
|
|
|
return pStream;
|
2005-05-05 19:00:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static BOOL
|
2007-04-20 11:26:32 +00:00
|
|
|
ME_StreamOutFlush(ME_OutStream *pStream)
|
2005-05-05 19:00:49 +00:00
|
|
|
{
|
|
|
|
LONG nWritten = 0;
|
2007-04-20 11:26:32 +00:00
|
|
|
EDITSTREAM *stream = pStream->stream;
|
2005-05-05 19:00:49 +00:00
|
|
|
|
2015-07-20 22:53:23 +00:00
|
|
|
if (pStream->pos) {
|
|
|
|
TRACE("sending %u bytes\n", pStream->pos);
|
|
|
|
nWritten = pStream->pos;
|
|
|
|
stream->dwError = stream->pfnCallback(stream->dwCookie, (LPBYTE)pStream->buffer,
|
|
|
|
pStream->pos, &nWritten);
|
2007-04-20 11:26:32 +00:00
|
|
|
TRACE("error=%u written=%u\n", stream->dwError, nWritten);
|
2005-05-05 19:00:49 +00:00
|
|
|
if (nWritten == 0 || stream->dwError)
|
|
|
|
return FALSE;
|
2015-07-20 22:53:23 +00:00
|
|
|
/* Don't resend partial chunks if nWritten < pStream->pos */
|
2012-01-29 23:23:23 +00:00
|
|
|
}
|
2015-11-23 09:36:58 +00:00
|
|
|
if (nWritten == pStream->pos)
|
|
|
|
pStream->written += nWritten;
|
2007-04-20 11:26:32 +00:00
|
|
|
pStream->pos = 0;
|
2005-05-05 19:00:49 +00:00
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static LONG
|
2007-04-20 11:26:32 +00:00
|
|
|
ME_StreamOutFree(ME_OutStream *pStream)
|
2005-05-05 19:00:49 +00:00
|
|
|
{
|
2007-04-20 11:26:32 +00:00
|
|
|
LONG written = pStream->written;
|
|
|
|
TRACE("total length = %u\n", written);
|
2005-05-05 19:00:49 +00:00
|
|
|
|
2007-04-20 11:26:32 +00:00
|
|
|
FREE_OBJ(pStream);
|
2005-05-05 19:00:49 +00:00
|
|
|
return written;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static BOOL
|
2007-04-20 11:26:32 +00:00
|
|
|
ME_StreamOutMove(ME_OutStream *pStream, const char *buffer, int len)
|
2005-05-05 19:00:49 +00:00
|
|
|
{
|
|
|
|
while (len) {
|
|
|
|
int space = STREAMOUT_BUFFER_SIZE - pStream->pos;
|
|
|
|
int fit = min(space, len);
|
|
|
|
|
2007-11-29 11:12:33 +00:00
|
|
|
TRACE("%u:%u:%s\n", pStream->pos, fit, debugstr_an(buffer,fit));
|
2005-05-05 19:00:49 +00:00
|
|
|
memmove(pStream->buffer + pStream->pos, buffer, fit);
|
|
|
|
len -= fit;
|
|
|
|
buffer += fit;
|
|
|
|
pStream->pos += fit;
|
|
|
|
if (pStream->pos == STREAMOUT_BUFFER_SIZE) {
|
2007-04-20 11:26:32 +00:00
|
|
|
if (!ME_StreamOutFlush(pStream))
|
2005-05-05 19:00:49 +00:00
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static BOOL
|
2007-04-20 11:26:32 +00:00
|
|
|
ME_StreamOutPrint(ME_OutStream *pStream, const char *format, ...)
|
2005-05-05 19:00:49 +00:00
|
|
|
{
|
|
|
|
char string[STREAMOUT_BUFFER_SIZE]; /* This is going to be enough */
|
|
|
|
int len;
|
|
|
|
va_list valist;
|
|
|
|
|
|
|
|
va_start(valist, format);
|
2007-04-20 11:26:32 +00:00
|
|
|
len = vsnprintf(string, sizeof(string), format, valist);
|
2005-05-05 19:00:49 +00:00
|
|
|
va_end(valist);
|
2007-11-29 11:12:33 +00:00
|
|
|
|
2007-04-20 11:26:32 +00:00
|
|
|
return ME_StreamOutMove(pStream, string, len);
|
2005-05-05 19:00:49 +00:00
|
|
|
}
|
|
|
|
|
2016-08-18 10:40:37 +00:00
|
|
|
#define HEX_BYTES_PER_LINE 40
|
|
|
|
|
|
|
|
static BOOL
|
|
|
|
ME_StreamOutHexData(ME_OutStream *stream, const BYTE *data, UINT len)
|
|
|
|
{
|
|
|
|
|
|
|
|
char line[HEX_BYTES_PER_LINE * 2 + 1];
|
|
|
|
UINT size, i;
|
|
|
|
static const char hex[] = "0123456789abcdef";
|
|
|
|
|
|
|
|
while (len)
|
|
|
|
{
|
|
|
|
size = min( len, HEX_BYTES_PER_LINE );
|
|
|
|
for (i = 0; i < size; i++)
|
|
|
|
{
|
|
|
|
line[i * 2] = hex[(*data >> 4) & 0xf];
|
|
|
|
line[i * 2 + 1] = hex[*data & 0xf];
|
|
|
|
data++;
|
|
|
|
}
|
|
|
|
line[size * 2] = '\n';
|
|
|
|
if (!ME_StreamOutMove( stream, line, size * 2 + 1 ))
|
|
|
|
return FALSE;
|
|
|
|
len -= size;
|
|
|
|
}
|
|
|
|
return TRUE;
|
|
|
|
}
|
2005-05-05 19:00:49 +00:00
|
|
|
|
|
|
|
static BOOL
|
2007-04-20 11:26:32 +00:00
|
|
|
ME_StreamOutRTFHeader(ME_OutStream *pStream, int dwFormat)
|
2005-05-05 19:00:49 +00:00
|
|
|
{
|
2005-08-12 17:41:40 +00:00
|
|
|
const char *cCharSet = NULL;
|
2005-05-05 19:00:49 +00:00
|
|
|
UINT nCodePage;
|
|
|
|
LANGID language;
|
|
|
|
BOOL success;
|
2007-11-29 11:12:33 +00:00
|
|
|
|
2005-05-05 19:00:49 +00:00
|
|
|
if (dwFormat & SF_USECODEPAGE) {
|
|
|
|
CPINFOEXW info;
|
2007-11-29 11:12:33 +00:00
|
|
|
|
2005-05-05 19:00:49 +00:00
|
|
|
switch (HIWORD(dwFormat)) {
|
|
|
|
case CP_ACP:
|
|
|
|
cCharSet = "ansi";
|
|
|
|
nCodePage = GetACP();
|
|
|
|
break;
|
|
|
|
case CP_OEMCP:
|
|
|
|
nCodePage = GetOEMCP();
|
|
|
|
if (nCodePage == 437)
|
|
|
|
cCharSet = "pc";
|
|
|
|
else if (nCodePage == 850)
|
|
|
|
cCharSet = "pca";
|
|
|
|
else
|
|
|
|
cCharSet = "ansi";
|
|
|
|
break;
|
|
|
|
case CP_UTF8:
|
|
|
|
nCodePage = CP_UTF8;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
if (HIWORD(dwFormat) == CP_MACCP) {
|
|
|
|
cCharSet = "mac";
|
|
|
|
nCodePage = 10000; /* MacRoman */
|
|
|
|
} else {
|
|
|
|
cCharSet = "ansi";
|
|
|
|
nCodePage = 1252; /* Latin-1 */
|
|
|
|
}
|
|
|
|
if (GetCPInfoExW(HIWORD(dwFormat), 0, &info))
|
|
|
|
nCodePage = info.CodePage;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
cCharSet = "ansi";
|
|
|
|
/* TODO: If the original document contained an \ansicpg value, retain it.
|
|
|
|
* Otherwise, M$ richedit emits a codepage number determined from the
|
|
|
|
* charset of the default font here. Anyway, this value is not used by
|
|
|
|
* the reader... */
|
|
|
|
nCodePage = GetACP();
|
|
|
|
}
|
|
|
|
if (nCodePage == CP_UTF8)
|
2007-04-20 11:26:32 +00:00
|
|
|
success = ME_StreamOutPrint(pStream, "{\\urtf");
|
2005-05-05 19:00:49 +00:00
|
|
|
else
|
2007-04-20 11:26:32 +00:00
|
|
|
success = ME_StreamOutPrint(pStream, "{\\rtf1\\%s\\ansicpg%u\\uc1", cCharSet, nCodePage);
|
2005-05-05 19:00:49 +00:00
|
|
|
|
|
|
|
if (!success)
|
|
|
|
return FALSE;
|
|
|
|
|
2007-04-20 11:26:32 +00:00
|
|
|
pStream->nDefaultCodePage = nCodePage;
|
2007-11-29 11:12:33 +00:00
|
|
|
|
2005-05-05 19:00:49 +00:00
|
|
|
/* FIXME: This should be a document property */
|
|
|
|
/* TODO: handle SFF_PLAINRTF */
|
2007-11-29 11:12:33 +00:00
|
|
|
language = GetUserDefaultLangID();
|
2007-04-20 11:26:32 +00:00
|
|
|
if (!ME_StreamOutPrint(pStream, "\\deff0\\deflang%u\\deflangfe%u", language, language))
|
2005-05-05 19:00:49 +00:00
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
/* FIXME: This should be a document property */
|
2007-04-20 11:26:32 +00:00
|
|
|
pStream->nDefaultFont = 0;
|
2005-05-05 19:00:49 +00:00
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
2016-11-17 23:04:08 +00:00
|
|
|
static void add_font_to_fonttbl( ME_OutStream *stream, ME_Style *style )
|
|
|
|
{
|
|
|
|
ME_FontTableItem *table = stream->fonttbl;
|
|
|
|
CHARFORMAT2W *fmt = &style->fmt;
|
|
|
|
WCHAR *face = fmt->szFaceName;
|
|
|
|
BYTE charset = (fmt->dwMask & CFM_CHARSET) ? fmt->bCharSet : DEFAULT_CHARSET;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
if (fmt->dwMask & CFM_FACE)
|
|
|
|
{
|
|
|
|
for (i = 0; i < stream->nFontTblLen; i++)
|
|
|
|
if (table[i].bCharSet == charset
|
|
|
|
&& (table[i].szFaceName == face || !lstrcmpW(table[i].szFaceName, face)))
|
|
|
|
break;
|
|
|
|
|
|
|
|
if (i == stream->nFontTblLen && i < STREAMOUT_FONTTBL_SIZE)
|
|
|
|
{
|
|
|
|
table[i].bCharSet = charset;
|
|
|
|
table[i].szFaceName = face;
|
|
|
|
stream->nFontTblLen++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static BOOL find_font_in_fonttbl( ME_OutStream *stream, CHARFORMAT2W *fmt, unsigned int *idx )
|
|
|
|
{
|
|
|
|
WCHAR *facename;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
*idx = 0;
|
|
|
|
if (fmt->dwMask & CFM_FACE)
|
|
|
|
facename = fmt->szFaceName;
|
|
|
|
else
|
|
|
|
facename = stream->fonttbl[0].szFaceName;
|
|
|
|
for (i = 0; i < stream->nFontTblLen; i++)
|
|
|
|
{
|
|
|
|
if (facename == stream->fonttbl[i].szFaceName
|
|
|
|
|| !lstrcmpW(facename, stream->fonttbl[i].szFaceName))
|
|
|
|
if (!(fmt->dwMask & CFM_CHARSET)
|
|
|
|
|| fmt->bCharSet == stream->fonttbl[i].bCharSet)
|
|
|
|
{
|
|
|
|
*idx = i;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return i < stream->nFontTblLen;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void add_color_to_colortbl( ME_OutStream *stream, COLORREF color )
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = 1; i < stream->nColorTblLen; i++)
|
|
|
|
if (stream->colortbl[i] == color)
|
|
|
|
break;
|
|
|
|
|
|
|
|
if (i == stream->nColorTblLen && i < STREAMOUT_COLORTBL_SIZE)
|
|
|
|
{
|
|
|
|
stream->colortbl[i] = color;
|
|
|
|
stream->nColorTblLen++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static BOOL find_color_in_colortbl( ME_OutStream *stream, COLORREF color, unsigned int *idx )
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
*idx = 0;
|
|
|
|
for (i = 1; i < stream->nColorTblLen; i++)
|
|
|
|
{
|
|
|
|
if (stream->colortbl[i] == color)
|
|
|
|
{
|
|
|
|
*idx = i;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return i < stream->nFontTblLen;
|
|
|
|
}
|
2005-05-05 19:00:49 +00:00
|
|
|
|
|
|
|
static BOOL
|
2008-10-27 08:10:25 +00:00
|
|
|
ME_StreamOutRTFFontAndColorTbl(ME_OutStream *pStream, ME_DisplayItem *pFirstRun,
|
|
|
|
ME_DisplayItem *pLastRun)
|
2005-05-05 19:00:49 +00:00
|
|
|
{
|
|
|
|
ME_DisplayItem *item = pFirstRun;
|
2007-04-20 11:26:32 +00:00
|
|
|
ME_FontTableItem *table = pStream->fonttbl;
|
2008-12-27 08:49:35 +00:00
|
|
|
unsigned int i;
|
2008-10-27 08:10:25 +00:00
|
|
|
ME_DisplayItem *pCell = NULL;
|
2016-11-17 23:04:08 +00:00
|
|
|
ME_Paragraph *prev_para = NULL;
|
|
|
|
|
2005-05-05 19:00:49 +00:00
|
|
|
do {
|
|
|
|
CHARFORMAT2W *fmt = &item->member.run.style->fmt;
|
|
|
|
|
2016-11-17 23:04:08 +00:00
|
|
|
add_font_to_fonttbl( pStream, item->member.run.style );
|
2005-05-05 19:00:49 +00:00
|
|
|
|
2016-11-17 23:04:08 +00:00
|
|
|
if (fmt->dwMask & CFM_COLOR && !(fmt->dwEffects & CFE_AUTOCOLOR))
|
|
|
|
add_color_to_colortbl( pStream, fmt->crTextColor );
|
|
|
|
if (fmt->dwMask & CFM_BACKCOLOR && !(fmt->dwEffects & CFE_AUTOBACKCOLOR))
|
|
|
|
add_color_to_colortbl( pStream, fmt->crBackColor );
|
|
|
|
|
|
|
|
if (item->member.run.para != prev_para)
|
2008-10-27 08:10:25 +00:00
|
|
|
{
|
2016-11-17 23:04:08 +00:00
|
|
|
/* check for any para numbering text */
|
|
|
|
if (item->member.run.para->fmt.wNumbering)
|
|
|
|
add_font_to_fonttbl( pStream, item->member.run.para->para_num.style );
|
|
|
|
|
|
|
|
if ((pCell = item->member.para.pCell))
|
|
|
|
{
|
2008-10-27 08:10:25 +00:00
|
|
|
ME_Border* borders[4] = { &pCell->member.cell.border.top,
|
|
|
|
&pCell->member.cell.border.left,
|
|
|
|
&pCell->member.cell.border.bottom,
|
|
|
|
&pCell->member.cell.border.right };
|
|
|
|
for (i = 0; i < 4; i++)
|
|
|
|
if (borders[i]->width > 0)
|
2016-11-17 23:04:08 +00:00
|
|
|
add_color_to_colortbl( pStream, borders[i]->colorRef );
|
|
|
|
}
|
|
|
|
|
|
|
|
prev_para = item->member.run.para;
|
2008-10-27 08:10:25 +00:00
|
|
|
}
|
2016-11-17 23:04:08 +00:00
|
|
|
|
|
|
|
if (item == pLastRun)
|
2008-10-27 08:10:25 +00:00
|
|
|
break;
|
2016-11-17 23:04:08 +00:00
|
|
|
item = ME_FindItemFwd(item, diRun);
|
2008-10-27 08:10:25 +00:00
|
|
|
} while (item);
|
2016-11-17 23:04:08 +00:00
|
|
|
|
2007-04-20 11:26:32 +00:00
|
|
|
if (!ME_StreamOutPrint(pStream, "{\\fonttbl"))
|
2005-05-05 19:00:49 +00:00
|
|
|
return FALSE;
|
2007-11-29 11:12:33 +00:00
|
|
|
|
2007-04-20 11:26:32 +00:00
|
|
|
for (i = 0; i < pStream->nFontTblLen; i++) {
|
2005-05-05 19:00:49 +00:00
|
|
|
if (table[i].bCharSet != DEFAULT_CHARSET) {
|
2007-04-20 11:26:32 +00:00
|
|
|
if (!ME_StreamOutPrint(pStream, "{\\f%u\\fcharset%u ", i, table[i].bCharSet))
|
2005-05-05 19:00:49 +00:00
|
|
|
return FALSE;
|
|
|
|
} else {
|
2007-04-20 11:26:32 +00:00
|
|
|
if (!ME_StreamOutPrint(pStream, "{\\f%u ", i))
|
2005-05-05 19:00:49 +00:00
|
|
|
return FALSE;
|
|
|
|
}
|
2007-04-20 11:26:32 +00:00
|
|
|
if (!ME_StreamOutRTFText(pStream, table[i].szFaceName, -1))
|
2005-05-05 19:00:49 +00:00
|
|
|
return FALSE;
|
2009-05-09 09:35:46 +00:00
|
|
|
if (!ME_StreamOutPrint(pStream, ";}"))
|
2005-05-05 19:00:49 +00:00
|
|
|
return FALSE;
|
|
|
|
}
|
2009-05-09 09:35:46 +00:00
|
|
|
if (!ME_StreamOutPrint(pStream, "}\r\n"))
|
2005-05-05 19:00:49 +00:00
|
|
|
return FALSE;
|
|
|
|
|
2013-09-26 16:32:14 +00:00
|
|
|
/* Output the color table */
|
|
|
|
if (!ME_StreamOutPrint(pStream, "{\\colortbl;")) return FALSE; /* first entry is auto-color */
|
|
|
|
for (i = 1; i < pStream->nColorTblLen; i++)
|
|
|
|
{
|
|
|
|
if (!ME_StreamOutPrint(pStream, "\\red%u\\green%u\\blue%u;", pStream->colortbl[i] & 0xFF,
|
|
|
|
(pStream->colortbl[i] >> 8) & 0xFF, (pStream->colortbl[i] >> 16) & 0xFF))
|
2005-05-05 19:00:49 +00:00
|
|
|
return FALSE;
|
|
|
|
}
|
2017-06-03 22:36:44 +00:00
|
|
|
if (!ME_StreamOutPrint(pStream, "}\r\n")) return FALSE;
|
2005-05-05 19:00:49 +00:00
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static BOOL
|
2008-08-28 10:43:26 +00:00
|
|
|
ME_StreamOutRTFTableProps(ME_TextEditor *editor, ME_OutStream *pStream,
|
2008-10-27 08:10:25 +00:00
|
|
|
ME_DisplayItem *para)
|
2005-05-05 19:00:49 +00:00
|
|
|
{
|
2008-08-28 10:43:26 +00:00
|
|
|
ME_DisplayItem *cell;
|
2005-05-05 19:00:49 +00:00
|
|
|
char props[STREAMOUT_BUFFER_SIZE] = "";
|
2008-10-27 08:10:25 +00:00
|
|
|
int i;
|
|
|
|
const char sideChar[4] = {'t','l','b','r'};
|
2005-05-05 19:00:49 +00:00
|
|
|
|
2008-08-28 10:43:26 +00:00
|
|
|
if (!ME_StreamOutPrint(pStream, "\\trowd"))
|
|
|
|
return FALSE;
|
|
|
|
if (!editor->bEmulateVersion10) { /* v4.1 */
|
2016-11-17 23:04:08 +00:00
|
|
|
PARAFORMAT2 *pFmt = &ME_GetTableRowEnd(para)->member.para.fmt;
|
2008-10-27 08:10:25 +00:00
|
|
|
para = ME_GetTableRowStart(para);
|
2008-08-28 10:43:26 +00:00
|
|
|
cell = para->member.para.next_para->member.para.pCell;
|
|
|
|
assert(cell);
|
2008-10-27 08:10:25 +00:00
|
|
|
if (pFmt->dxOffset)
|
|
|
|
sprintf(props + strlen(props), "\\trgaph%d", pFmt->dxOffset);
|
|
|
|
if (pFmt->dxStartIndent)
|
|
|
|
sprintf(props + strlen(props), "\\trleft%d", pFmt->dxStartIndent);
|
2007-04-20 11:26:32 +00:00
|
|
|
do {
|
2008-10-27 08:10:25 +00:00
|
|
|
ME_Border* borders[4] = { &cell->member.cell.border.top,
|
|
|
|
&cell->member.cell.border.left,
|
|
|
|
&cell->member.cell.border.bottom,
|
|
|
|
&cell->member.cell.border.right };
|
|
|
|
for (i = 0; i < 4; i++)
|
|
|
|
{
|
|
|
|
if (borders[i]->width)
|
|
|
|
{
|
2016-11-17 23:04:08 +00:00
|
|
|
unsigned int idx;
|
2008-10-27 08:10:25 +00:00
|
|
|
COLORREF crColor = borders[i]->colorRef;
|
|
|
|
sprintf(props + strlen(props), "\\clbrdr%c", sideChar[i]);
|
|
|
|
sprintf(props + strlen(props), "\\brdrs");
|
|
|
|
sprintf(props + strlen(props), "\\brdrw%d", borders[i]->width);
|
2016-11-17 23:04:08 +00:00
|
|
|
if (find_color_in_colortbl( pStream, crColor, &idx ))
|
|
|
|
sprintf(props + strlen(props), "\\brdrcf%u", idx);
|
2008-10-27 08:10:25 +00:00
|
|
|
}
|
|
|
|
}
|
2008-08-28 10:43:26 +00:00
|
|
|
sprintf(props + strlen(props), "\\cellx%d", cell->member.cell.nRightBoundary);
|
|
|
|
cell = cell->member.cell.next_cell;
|
|
|
|
} while (cell->member.cell.next_cell);
|
|
|
|
} else { /* v1.0 - 3.0 */
|
2008-10-27 08:10:25 +00:00
|
|
|
const ME_Border* borders[4] = { ¶->member.para.border.top,
|
|
|
|
¶->member.para.border.left,
|
|
|
|
¶->member.para.border.bottom,
|
|
|
|
¶->member.para.border.right };
|
2016-11-17 23:04:08 +00:00
|
|
|
PARAFORMAT2 *pFmt = ¶->member.para.fmt;
|
2008-08-28 10:43:26 +00:00
|
|
|
|
|
|
|
assert(!(para->member.para.nFlags & (MEPF_ROWSTART|MEPF_ROWEND|MEPF_CELL)));
|
|
|
|
if (pFmt->dxOffset)
|
|
|
|
sprintf(props + strlen(props), "\\trgaph%d", pFmt->dxOffset);
|
|
|
|
if (pFmt->dxStartIndent)
|
|
|
|
sprintf(props + strlen(props), "\\trleft%d", pFmt->dxStartIndent);
|
2008-10-27 08:10:25 +00:00
|
|
|
for (i = 0; i < 4; i++)
|
|
|
|
{
|
|
|
|
if (borders[i]->width)
|
|
|
|
{
|
2016-11-17 23:04:08 +00:00
|
|
|
unsigned int idx;
|
2008-10-27 08:10:25 +00:00
|
|
|
COLORREF crColor = borders[i]->colorRef;
|
|
|
|
sprintf(props + strlen(props), "\\trbrdr%c", sideChar[i]);
|
|
|
|
sprintf(props + strlen(props), "\\brdrs");
|
|
|
|
sprintf(props + strlen(props), "\\brdrw%d", borders[i]->width);
|
2016-11-17 23:04:08 +00:00
|
|
|
if (find_color_in_colortbl( pStream, crColor, &idx ))
|
|
|
|
sprintf(props + strlen(props), "\\brdrcf%u", idx);
|
2008-10-27 08:10:25 +00:00
|
|
|
}
|
|
|
|
}
|
2008-08-28 10:43:26 +00:00
|
|
|
for (i = 0; i < pFmt->cTabCount; i++)
|
|
|
|
{
|
|
|
|
sprintf(props + strlen(props), "\\cellx%d", pFmt->rgxTabs[i] & 0x00FFFFFF);
|
|
|
|
}
|
2007-04-20 11:26:32 +00:00
|
|
|
}
|
2008-08-28 10:43:26 +00:00
|
|
|
if (!ME_StreamOutPrint(pStream, props))
|
|
|
|
return FALSE;
|
|
|
|
props[0] = '\0';
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
2016-11-17 23:04:08 +00:00
|
|
|
static BOOL stream_out_para_num( ME_OutStream *stream, ME_Paragraph *para, BOOL pn_dest )
|
|
|
|
{
|
|
|
|
static const char fmt_label[] = "{\\*\\pn\\pnlvlbody\\pnf%u\\pnindent%d\\pnstart%d%s%s}";
|
|
|
|
static const char fmt_bullet[] = "{\\*\\pn\\pnlvlblt\\pnf%u\\pnindent%d{\\pntxtb\\'b7}}";
|
|
|
|
static const char dec[] = "\\pndec";
|
|
|
|
static const char lcltr[] = "\\pnlcltr";
|
|
|
|
static const char ucltr[] = "\\pnucltr";
|
|
|
|
static const char lcrm[] = "\\pnlcrm";
|
|
|
|
static const char ucrm[] = "\\pnucrm";
|
|
|
|
static const char period[] = "{\\pntxta.}";
|
|
|
|
static const char paren[] = "{\\pntxta)}";
|
|
|
|
static const char parens[] = "{\\pntxtb(}{\\pntxta)}";
|
|
|
|
const char *type, *style = "";
|
|
|
|
unsigned int idx;
|
|
|
|
|
|
|
|
find_font_in_fonttbl( stream, ¶->para_num.style->fmt, &idx );
|
|
|
|
|
|
|
|
if (!ME_StreamOutPrint( stream, "{\\pntext\\f%u ", idx )) return FALSE;
|
|
|
|
if (!ME_StreamOutRTFText( stream, para->para_num.text->szData, para->para_num.text->nLen ))
|
|
|
|
return FALSE;
|
|
|
|
if (!ME_StreamOutPrint( stream, "\\tab}" )) return FALSE;
|
|
|
|
|
|
|
|
if (!pn_dest) return TRUE;
|
|
|
|
|
|
|
|
if (para->fmt.wNumbering == PFN_BULLET)
|
|
|
|
{
|
|
|
|
if (!ME_StreamOutPrint( stream, fmt_bullet, idx, para->fmt.wNumberingTab ))
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
switch (para->fmt.wNumbering)
|
|
|
|
{
|
|
|
|
case PFN_ARABIC:
|
|
|
|
default:
|
|
|
|
type = dec;
|
|
|
|
break;
|
|
|
|
case PFN_LCLETTER:
|
|
|
|
type = lcltr;
|
|
|
|
break;
|
|
|
|
case PFN_UCLETTER:
|
|
|
|
type = ucltr;
|
|
|
|
break;
|
|
|
|
case PFN_LCROMAN:
|
|
|
|
type = lcrm;
|
|
|
|
break;
|
|
|
|
case PFN_UCROMAN:
|
|
|
|
type = ucrm;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
switch (para->fmt.wNumberingStyle & 0xf00)
|
|
|
|
{
|
|
|
|
case PFNS_PERIOD:
|
|
|
|
style = period;
|
|
|
|
break;
|
|
|
|
case PFNS_PAREN:
|
|
|
|
style = paren;
|
|
|
|
break;
|
|
|
|
case PFNS_PARENS:
|
|
|
|
style = parens;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!ME_StreamOutPrint( stream, fmt_label, idx, para->fmt.wNumberingTab,
|
|
|
|
para->fmt.wNumberingStart, type, style ))
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
2008-08-28 10:43:26 +00:00
|
|
|
static BOOL
|
|
|
|
ME_StreamOutRTFParaProps(ME_TextEditor *editor, ME_OutStream *pStream,
|
Finish the Wine sync. These components are not just rc file changes
atl, comctl32, comdlg32, dwmapi, fusion, gdiplus, jscript, mpr, mshtml, msi, msimtf, msxml3, ole32, oleaut32, riched20, shdocvw, shlwapi, urlmon, usp10, version and windowscodecs
Seems to build and boot. /me hides
svn path=/trunk/; revision=48273
2010-07-26 02:26:04 +00:00
|
|
|
ME_DisplayItem *para)
|
2008-08-28 10:43:26 +00:00
|
|
|
{
|
2016-11-17 23:04:08 +00:00
|
|
|
PARAFORMAT2 *fmt = ¶->member.para.fmt;
|
2008-08-28 10:43:26 +00:00
|
|
|
char props[STREAMOUT_BUFFER_SIZE] = "";
|
|
|
|
int i;
|
2016-11-17 23:04:08 +00:00
|
|
|
ME_Paragraph *prev_para = NULL;
|
|
|
|
|
|
|
|
if (para->member.para.prev_para->type == diParagraph)
|
|
|
|
prev_para = ¶->member.para.prev_para->member.para;
|
Finish the Wine sync. These components are not just rc file changes
atl, comctl32, comdlg32, dwmapi, fusion, gdiplus, jscript, mpr, mshtml, msi, msimtf, msxml3, ole32, oleaut32, riched20, shdocvw, shlwapi, urlmon, usp10, version and windowscodecs
Seems to build and boot. /me hides
svn path=/trunk/; revision=48273
2010-07-26 02:26:04 +00:00
|
|
|
|
|
|
|
if (!editor->bEmulateVersion10) { /* v4.1 */
|
|
|
|
if (para->member.para.nFlags & MEPF_ROWSTART) {
|
|
|
|
pStream->nNestingLevel++;
|
|
|
|
if (pStream->nNestingLevel == 1) {
|
|
|
|
if (!ME_StreamOutRTFTableProps(editor, pStream, para))
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
return TRUE;
|
|
|
|
} else if (para->member.para.nFlags & MEPF_ROWEND) {
|
|
|
|
pStream->nNestingLevel--;
|
|
|
|
if (pStream->nNestingLevel >= 1) {
|
|
|
|
if (!ME_StreamOutPrint(pStream, "{\\*\\nesttableprops"))
|
|
|
|
return FALSE;
|
|
|
|
if (!ME_StreamOutRTFTableProps(editor, pStream, para))
|
|
|
|
return FALSE;
|
|
|
|
if (!ME_StreamOutPrint(pStream, "\\nestrow}{\\nonesttables\\par}\r\n"))
|
|
|
|
return FALSE;
|
|
|
|
} else {
|
2016-11-17 23:04:08 +00:00
|
|
|
if (!ME_StreamOutPrint(pStream, "\\row\r\n"))
|
Finish the Wine sync. These components are not just rc file changes
atl, comctl32, comdlg32, dwmapi, fusion, gdiplus, jscript, mpr, mshtml, msi, msimtf, msxml3, ole32, oleaut32, riched20, shdocvw, shlwapi, urlmon, usp10, version and windowscodecs
Seems to build and boot. /me hides
svn path=/trunk/; revision=48273
2010-07-26 02:26:04 +00:00
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
} else { /* v1.0 - 3.0 */
|
2016-11-17 23:04:08 +00:00
|
|
|
if (para->member.para.fmt.dwMask & PFM_TABLE &&
|
|
|
|
para->member.para.fmt.wEffects & PFE_TABLE)
|
Finish the Wine sync. These components are not just rc file changes
atl, comctl32, comdlg32, dwmapi, fusion, gdiplus, jscript, mpr, mshtml, msi, msimtf, msxml3, ole32, oleaut32, riched20, shdocvw, shlwapi, urlmon, usp10, version and windowscodecs
Seems to build and boot. /me hides
svn path=/trunk/; revision=48273
2010-07-26 02:26:04 +00:00
|
|
|
{
|
|
|
|
if (!ME_StreamOutRTFTableProps(editor, pStream, para))
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-11-17 23:04:08 +00:00
|
|
|
if (prev_para && !memcmp( fmt, &prev_para->fmt, sizeof(*fmt) ))
|
|
|
|
{
|
|
|
|
if (fmt->wNumbering)
|
|
|
|
return stream_out_para_num( pStream, ¶->member.para, FALSE );
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
2007-04-20 11:26:32 +00:00
|
|
|
if (!ME_StreamOutPrint(pStream, "\\pard"))
|
2005-05-05 19:00:49 +00:00
|
|
|
return FALSE;
|
2007-04-20 11:26:32 +00:00
|
|
|
|
2016-11-17 23:04:08 +00:00
|
|
|
if (fmt->wNumbering)
|
|
|
|
if (!stream_out_para_num( pStream, ¶->member.para, TRUE )) return FALSE;
|
|
|
|
|
2008-08-28 10:43:26 +00:00
|
|
|
if (!editor->bEmulateVersion10) { /* v4.1 */
|
|
|
|
if (pStream->nNestingLevel > 0)
|
|
|
|
strcat(props, "\\intbl");
|
|
|
|
if (pStream->nNestingLevel > 1)
|
|
|
|
sprintf(props + strlen(props), "\\itap%d", pStream->nNestingLevel);
|
|
|
|
} else { /* v1.0 - 3.0 */
|
|
|
|
if (fmt->dwMask & PFM_TABLE && fmt->wEffects & PFE_TABLE)
|
|
|
|
strcat(props, "\\intbl");
|
|
|
|
}
|
2016-11-17 23:04:08 +00:00
|
|
|
|
2005-05-05 19:00:49 +00:00
|
|
|
/* TODO: PFM_BORDER. M$ does not emit any keywords for these properties, and
|
|
|
|
* when streaming border keywords in, PFM_BORDER is set, but wBorder field is
|
|
|
|
* set very different from the documentation.
|
|
|
|
* (Tested with RichEdit 5.50.25.0601) */
|
2007-11-29 11:12:33 +00:00
|
|
|
|
2005-05-05 19:00:49 +00:00
|
|
|
if (fmt->dwMask & PFM_ALIGNMENT) {
|
|
|
|
switch (fmt->wAlignment) {
|
|
|
|
case PFA_LEFT:
|
|
|
|
/* Default alignment: not emitted */
|
|
|
|
break;
|
|
|
|
case PFA_RIGHT:
|
|
|
|
strcat(props, "\\qr");
|
|
|
|
break;
|
|
|
|
case PFA_CENTER:
|
|
|
|
strcat(props, "\\qc");
|
|
|
|
break;
|
|
|
|
case PFA_JUSTIFY:
|
|
|
|
strcat(props, "\\qj");
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2007-11-29 11:12:33 +00:00
|
|
|
|
2005-05-05 19:00:49 +00:00
|
|
|
if (fmt->dwMask & PFM_LINESPACING) {
|
|
|
|
/* FIXME: MSDN says that the bLineSpacingRule field is controlled by the
|
|
|
|
* PFM_SPACEAFTER flag. Is that true? I don't believe so. */
|
|
|
|
switch (fmt->bLineSpacingRule) {
|
|
|
|
case 0: /* Single spacing */
|
|
|
|
strcat(props, "\\sl-240\\slmult1");
|
|
|
|
break;
|
|
|
|
case 1: /* 1.5 spacing */
|
|
|
|
strcat(props, "\\sl-360\\slmult1");
|
|
|
|
break;
|
|
|
|
case 2: /* Double spacing */
|
|
|
|
strcat(props, "\\sl-480\\slmult1");
|
|
|
|
break;
|
|
|
|
case 3:
|
2007-04-20 11:26:32 +00:00
|
|
|
sprintf(props + strlen(props), "\\sl%d\\slmult0", fmt->dyLineSpacing);
|
2005-05-05 19:00:49 +00:00
|
|
|
break;
|
|
|
|
case 4:
|
2007-04-20 11:26:32 +00:00
|
|
|
sprintf(props + strlen(props), "\\sl-%d\\slmult0", fmt->dyLineSpacing);
|
2005-05-05 19:00:49 +00:00
|
|
|
break;
|
|
|
|
case 5:
|
2007-04-20 11:26:32 +00:00
|
|
|
sprintf(props + strlen(props), "\\sl-%d\\slmult1", fmt->dyLineSpacing * 240 / 20);
|
2005-05-05 19:00:49 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (fmt->dwMask & PFM_DONOTHYPHEN && fmt->wEffects & PFE_DONOTHYPHEN)
|
|
|
|
strcat(props, "\\hyph0");
|
|
|
|
if (fmt->dwMask & PFM_KEEP && fmt->wEffects & PFE_KEEP)
|
|
|
|
strcat(props, "\\keep");
|
|
|
|
if (fmt->dwMask & PFM_KEEPNEXT && fmt->wEffects & PFE_KEEPNEXT)
|
|
|
|
strcat(props, "\\keepn");
|
|
|
|
if (fmt->dwMask & PFM_NOLINENUMBER && fmt->wEffects & PFE_NOLINENUMBER)
|
|
|
|
strcat(props, "\\noline");
|
|
|
|
if (fmt->dwMask & PFM_NOWIDOWCONTROL && fmt->wEffects & PFE_NOWIDOWCONTROL)
|
|
|
|
strcat(props, "\\nowidctlpar");
|
|
|
|
if (fmt->dwMask & PFM_PAGEBREAKBEFORE && fmt->wEffects & PFE_PAGEBREAKBEFORE)
|
|
|
|
strcat(props, "\\pagebb");
|
|
|
|
if (fmt->dwMask & PFM_RTLPARA && fmt->wEffects & PFE_RTLPARA)
|
|
|
|
strcat(props, "\\rtlpar");
|
|
|
|
if (fmt->dwMask & PFM_SIDEBYSIDE && fmt->wEffects & PFE_SIDEBYSIDE)
|
|
|
|
strcat(props, "\\sbys");
|
2007-11-29 11:12:33 +00:00
|
|
|
|
2008-08-28 10:43:26 +00:00
|
|
|
if (!(editor->bEmulateVersion10 && /* v1.0 - 3.0 */
|
|
|
|
fmt->dwMask & PFM_TABLE && fmt->wEffects & PFE_TABLE))
|
|
|
|
{
|
2016-11-17 23:04:08 +00:00
|
|
|
if (fmt->dxOffset)
|
2008-08-28 10:43:26 +00:00
|
|
|
sprintf(props + strlen(props), "\\li%d", fmt->dxOffset);
|
2016-11-17 23:04:08 +00:00
|
|
|
if (fmt->dxStartIndent)
|
2008-08-28 10:43:26 +00:00
|
|
|
sprintf(props + strlen(props), "\\fi%d", fmt->dxStartIndent);
|
2016-11-17 23:04:08 +00:00
|
|
|
if (fmt->dxRightIndent)
|
2008-08-28 10:43:26 +00:00
|
|
|
sprintf(props + strlen(props), "\\ri%d", fmt->dxRightIndent);
|
|
|
|
if (fmt->dwMask & PFM_TABSTOPS) {
|
|
|
|
static const char * const leader[6] = { "", "\\tldot", "\\tlhyph", "\\tlul", "\\tlth", "\\tleq" };
|
|
|
|
|
|
|
|
for (i = 0; i < fmt->cTabCount; i++) {
|
|
|
|
switch ((fmt->rgxTabs[i] >> 24) & 0xF) {
|
|
|
|
case 1:
|
|
|
|
strcat(props, "\\tqc");
|
|
|
|
break;
|
|
|
|
case 2:
|
|
|
|
strcat(props, "\\tqr");
|
|
|
|
break;
|
|
|
|
case 3:
|
|
|
|
strcat(props, "\\tqdec");
|
|
|
|
break;
|
|
|
|
case 4:
|
|
|
|
/* Word bar tab (vertical bar). Handled below */
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (fmt->rgxTabs[i] >> 28 <= 5)
|
|
|
|
strcat(props, leader[fmt->rgxTabs[i] >> 28]);
|
|
|
|
sprintf(props+strlen(props), "\\tx%d", fmt->rgxTabs[i]&0x00FFFFFF);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2016-11-17 23:04:08 +00:00
|
|
|
if (fmt->dySpaceAfter)
|
2007-04-20 11:26:32 +00:00
|
|
|
sprintf(props + strlen(props), "\\sa%d", fmt->dySpaceAfter);
|
2016-11-17 23:04:08 +00:00
|
|
|
if (fmt->dySpaceBefore)
|
2007-04-20 11:26:32 +00:00
|
|
|
sprintf(props + strlen(props), "\\sb%d", fmt->dySpaceBefore);
|
2016-11-17 23:04:08 +00:00
|
|
|
if (fmt->sStyle != -1)
|
2005-05-05 19:00:49 +00:00
|
|
|
sprintf(props + strlen(props), "\\s%d", fmt->sStyle);
|
2007-11-29 11:12:33 +00:00
|
|
|
|
2005-05-05 19:00:49 +00:00
|
|
|
if (fmt->dwMask & PFM_SHADING) {
|
2007-04-20 11:26:32 +00:00
|
|
|
static const char * const style[16] = { "", "\\bgdkhoriz", "\\bgdkvert", "\\bgdkfdiag",
|
2005-05-05 19:00:49 +00:00
|
|
|
"\\bgdkbdiag", "\\bgdkcross", "\\bgdkdcross",
|
|
|
|
"\\bghoriz", "\\bgvert", "\\bgfdiag",
|
|
|
|
"\\bgbdiag", "\\bgcross", "\\bgdcross",
|
|
|
|
"", "", "" };
|
|
|
|
if (fmt->wShadingWeight)
|
|
|
|
sprintf(props + strlen(props), "\\shading%d", fmt->wShadingWeight);
|
|
|
|
if (fmt->wShadingStyle & 0xF)
|
|
|
|
strcat(props, style[fmt->wShadingStyle & 0xF]);
|
2017-06-03 22:36:44 +00:00
|
|
|
if ((fmt->wShadingStyle >> 4) & 0xf)
|
|
|
|
sprintf(props + strlen(props), "\\cfpat%d", (fmt->wShadingStyle >> 4) & 0xf);
|
|
|
|
if ((fmt->wShadingStyle >> 8) & 0xf)
|
|
|
|
sprintf(props + strlen(props), "\\cbpat%d", (fmt->wShadingStyle >> 8) & 0xf);
|
2005-05-05 19:00:49 +00:00
|
|
|
}
|
2016-11-17 23:04:08 +00:00
|
|
|
if (*props)
|
|
|
|
strcat(props, " ");
|
2007-11-29 11:12:33 +00:00
|
|
|
|
2007-04-20 11:26:32 +00:00
|
|
|
if (*props && !ME_StreamOutPrint(pStream, props))
|
2005-05-05 19:00:49 +00:00
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static BOOL
|
2007-04-20 11:26:32 +00:00
|
|
|
ME_StreamOutRTFCharProps(ME_OutStream *pStream, CHARFORMAT2W *fmt)
|
2005-05-05 19:00:49 +00:00
|
|
|
{
|
|
|
|
char props[STREAMOUT_BUFFER_SIZE] = "";
|
2008-12-27 08:49:35 +00:00
|
|
|
unsigned int i;
|
2016-11-17 23:04:08 +00:00
|
|
|
CHARFORMAT2W *old_fmt = &pStream->cur_fmt;
|
|
|
|
static const struct
|
|
|
|
{
|
|
|
|
DWORD effect;
|
|
|
|
const char *on, *off;
|
|
|
|
} effects[] =
|
|
|
|
{
|
|
|
|
{ CFE_ALLCAPS, "\\caps", "\\caps0" },
|
|
|
|
{ CFE_BOLD, "\\b", "\\b0" },
|
|
|
|
{ CFE_DISABLED, "\\disabled", "\\disabled0" },
|
|
|
|
{ CFE_EMBOSS, "\\embo", "\\embo0" },
|
|
|
|
{ CFE_HIDDEN, "\\v", "\\v0" },
|
|
|
|
{ CFE_IMPRINT, "\\impr", "\\impr0" },
|
|
|
|
{ CFE_ITALIC, "\\i", "\\i0" },
|
|
|
|
{ CFE_OUTLINE, "\\outl", "\\outl0" },
|
|
|
|
{ CFE_PROTECTED, "\\protect", "\\protect0" },
|
|
|
|
{ CFE_SHADOW, "\\shad", "\\shad0" },
|
|
|
|
{ CFE_SMALLCAPS, "\\scaps", "\\scaps0" },
|
|
|
|
{ CFE_STRIKEOUT, "\\strike", "\\strike0" },
|
|
|
|
};
|
|
|
|
|
|
|
|
for (i = 0; i < sizeof(effects) / sizeof(effects[0]); i++)
|
|
|
|
{
|
|
|
|
if ((old_fmt->dwEffects ^ fmt->dwEffects) & effects[i].effect)
|
|
|
|
strcat( props, fmt->dwEffects & effects[i].effect ? effects[i].on : effects[i].off );
|
|
|
|
}
|
2005-05-05 19:00:49 +00:00
|
|
|
|
2016-11-17 23:04:08 +00:00
|
|
|
if ((old_fmt->dwEffects ^ fmt->dwEffects) & CFE_AUTOBACKCOLOR ||
|
2017-06-03 22:36:44 +00:00
|
|
|
(!(fmt->dwEffects & CFE_AUTOBACKCOLOR) && old_fmt->crBackColor != fmt->crBackColor))
|
2016-11-17 23:04:08 +00:00
|
|
|
{
|
|
|
|
if (fmt->dwEffects & CFE_AUTOBACKCOLOR) i = 0;
|
|
|
|
else find_color_in_colortbl( pStream, fmt->crBackColor, &i );
|
2017-09-17 22:57:18 +00:00
|
|
|
sprintf(props + strlen(props), "\\highlight%u", i);
|
2005-05-05 19:00:49 +00:00
|
|
|
}
|
2016-11-17 23:04:08 +00:00
|
|
|
if ((old_fmt->dwEffects ^ fmt->dwEffects) & CFE_AUTOCOLOR ||
|
2017-06-03 22:36:44 +00:00
|
|
|
(!(fmt->dwEffects & CFE_AUTOCOLOR) && old_fmt->crTextColor != fmt->crTextColor))
|
2016-11-17 23:04:08 +00:00
|
|
|
{
|
|
|
|
if (fmt->dwEffects & CFE_AUTOCOLOR) i = 0;
|
|
|
|
else find_color_in_colortbl( pStream, fmt->crTextColor, &i );
|
|
|
|
sprintf(props + strlen(props), "\\cf%u", i);
|
2005-05-05 19:00:49 +00:00
|
|
|
}
|
2016-11-17 23:04:08 +00:00
|
|
|
|
|
|
|
if (old_fmt->bAnimation != fmt->bAnimation)
|
|
|
|
sprintf(props + strlen(props), "\\animtext%u", fmt->bAnimation);
|
|
|
|
if (old_fmt->wKerning != fmt->wKerning)
|
2005-05-05 19:00:49 +00:00
|
|
|
sprintf(props + strlen(props), "\\kerning%u", fmt->wKerning);
|
2016-11-17 23:04:08 +00:00
|
|
|
|
|
|
|
if (old_fmt->lcid != fmt->lcid)
|
|
|
|
{
|
2005-05-05 19:00:49 +00:00
|
|
|
/* TODO: handle SFF_PLAINRTF */
|
|
|
|
if (LOWORD(fmt->lcid) == 1024)
|
|
|
|
strcat(props, "\\noproof\\lang1024\\langnp1024\\langfe1024\\langfenp1024");
|
|
|
|
else
|
|
|
|
sprintf(props + strlen(props), "\\lang%u", LOWORD(fmt->lcid));
|
|
|
|
}
|
2016-11-17 23:04:08 +00:00
|
|
|
|
|
|
|
if (old_fmt->yOffset != fmt->yOffset)
|
|
|
|
{
|
2005-05-05 19:00:49 +00:00
|
|
|
if (fmt->yOffset >= 0)
|
2007-04-20 11:26:32 +00:00
|
|
|
sprintf(props + strlen(props), "\\up%d", fmt->yOffset);
|
2005-05-05 19:00:49 +00:00
|
|
|
else
|
2007-04-20 11:26:32 +00:00
|
|
|
sprintf(props + strlen(props), "\\dn%d", -fmt->yOffset);
|
2005-05-05 19:00:49 +00:00
|
|
|
}
|
2016-11-17 23:04:08 +00:00
|
|
|
if (old_fmt->yHeight != fmt->yHeight)
|
2007-04-20 11:26:32 +00:00
|
|
|
sprintf(props + strlen(props), "\\fs%d", fmt->yHeight / 10);
|
2016-11-17 23:04:08 +00:00
|
|
|
if (old_fmt->sSpacing != fmt->sSpacing)
|
2005-05-05 19:00:49 +00:00
|
|
|
sprintf(props + strlen(props), "\\expnd%u\\expndtw%u", fmt->sSpacing / 5, fmt->sSpacing);
|
2016-11-17 23:04:08 +00:00
|
|
|
if ((old_fmt->dwEffects ^ fmt->dwEffects) & (CFM_SUBSCRIPT | CFM_SUPERSCRIPT))
|
|
|
|
{
|
2005-05-05 19:00:49 +00:00
|
|
|
if (fmt->dwEffects & CFE_SUBSCRIPT)
|
|
|
|
strcat(props, "\\sub");
|
|
|
|
else if (fmt->dwEffects & CFE_SUPERSCRIPT)
|
|
|
|
strcat(props, "\\super");
|
2016-11-17 23:04:08 +00:00
|
|
|
else
|
|
|
|
strcat(props, "\\nosupersub");
|
2005-05-05 19:00:49 +00:00
|
|
|
}
|
2016-11-17 23:04:08 +00:00
|
|
|
if ((old_fmt->dwEffects ^ fmt->dwEffects) & CFE_UNDERLINE ||
|
|
|
|
old_fmt->bUnderlineType != fmt->bUnderlineType)
|
|
|
|
{
|
|
|
|
BYTE type = (fmt->dwEffects & CFE_UNDERLINE) ? fmt->bUnderlineType : CFU_UNDERLINENONE;
|
|
|
|
switch (type)
|
|
|
|
{
|
|
|
|
case CFU_UNDERLINE:
|
2005-05-05 19:00:49 +00:00
|
|
|
strcat(props, "\\ul");
|
|
|
|
break;
|
2016-11-17 23:04:08 +00:00
|
|
|
case CFU_UNDERLINEDOTTED:
|
2005-05-05 19:00:49 +00:00
|
|
|
strcat(props, "\\uld");
|
|
|
|
break;
|
2016-11-17 23:04:08 +00:00
|
|
|
case CFU_UNDERLINEDOUBLE:
|
2005-05-05 19:00:49 +00:00
|
|
|
strcat(props, "\\uldb");
|
|
|
|
break;
|
2016-11-17 23:04:08 +00:00
|
|
|
case CFU_UNDERLINEWORD:
|
2005-05-05 19:00:49 +00:00
|
|
|
strcat(props, "\\ulw");
|
|
|
|
break;
|
2016-11-17 23:04:08 +00:00
|
|
|
case CFU_CF1UNDERLINE:
|
|
|
|
case CFU_UNDERLINENONE:
|
|
|
|
default:
|
2013-09-26 16:32:14 +00:00
|
|
|
strcat(props, "\\ulnone");
|
2005-05-05 19:00:49 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2007-11-29 11:12:33 +00:00
|
|
|
|
2016-11-17 23:04:08 +00:00
|
|
|
if (strcmpW(old_fmt->szFaceName, fmt->szFaceName) ||
|
|
|
|
old_fmt->bCharSet != fmt->bCharSet)
|
|
|
|
{
|
|
|
|
if (find_font_in_fonttbl( pStream, fmt, &i ))
|
2005-05-05 19:00:49 +00:00
|
|
|
{
|
2016-11-17 23:04:08 +00:00
|
|
|
sprintf(props + strlen(props), "\\f%u", i);
|
2005-05-05 19:00:49 +00:00
|
|
|
|
|
|
|
/* In UTF-8 mode, charsets/codepages are not used */
|
2007-04-20 11:26:32 +00:00
|
|
|
if (pStream->nDefaultCodePage != CP_UTF8)
|
2005-05-05 19:00:49 +00:00
|
|
|
{
|
2007-04-20 11:26:32 +00:00
|
|
|
if (pStream->fonttbl[i].bCharSet == DEFAULT_CHARSET)
|
|
|
|
pStream->nCodePage = pStream->nDefaultCodePage;
|
2005-05-05 19:00:49 +00:00
|
|
|
else
|
2007-04-20 11:26:32 +00:00
|
|
|
pStream->nCodePage = RTFCharSetToCodePage(NULL, pStream->fonttbl[i].bCharSet);
|
2005-05-05 19:00:49 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (*props)
|
|
|
|
strcat(props, " ");
|
2007-04-20 11:26:32 +00:00
|
|
|
if (!ME_StreamOutPrint(pStream, props))
|
2005-05-05 19:00:49 +00:00
|
|
|
return FALSE;
|
2016-11-17 23:04:08 +00:00
|
|
|
*old_fmt = *fmt;
|
2005-05-05 19:00:49 +00:00
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static BOOL
|
2007-11-29 11:12:33 +00:00
|
|
|
ME_StreamOutRTFText(ME_OutStream *pStream, const WCHAR *text, LONG nChars)
|
2005-05-05 19:00:49 +00:00
|
|
|
{
|
|
|
|
char buffer[STREAMOUT_BUFFER_SIZE];
|
|
|
|
int pos = 0;
|
2005-08-12 17:41:40 +00:00
|
|
|
int fit, nBytes, i;
|
2005-05-05 19:00:49 +00:00
|
|
|
|
|
|
|
if (nChars == -1)
|
|
|
|
nChars = lstrlenW(text);
|
2007-11-29 11:12:33 +00:00
|
|
|
|
2005-05-05 19:00:49 +00:00
|
|
|
while (nChars) {
|
|
|
|
/* In UTF-8 mode, font charsets are not used. */
|
2007-04-20 11:26:32 +00:00
|
|
|
if (pStream->nDefaultCodePage == CP_UTF8) {
|
2005-05-05 19:00:49 +00:00
|
|
|
/* 6 is the maximum character length in UTF-8 */
|
|
|
|
fit = min(nChars, STREAMOUT_BUFFER_SIZE / 6);
|
2005-08-12 17:41:40 +00:00
|
|
|
nBytes = WideCharToMultiByte(CP_UTF8, 0, text, fit, buffer,
|
|
|
|
STREAMOUT_BUFFER_SIZE, NULL, NULL);
|
2005-05-05 19:00:49 +00:00
|
|
|
nChars -= fit;
|
|
|
|
text += fit;
|
2005-08-12 17:41:40 +00:00
|
|
|
for (i = 0; i < nBytes; i++)
|
2005-05-05 19:00:49 +00:00
|
|
|
if (buffer[i] == '{' || buffer[i] == '}' || buffer[i] == '\\') {
|
2007-04-20 11:26:32 +00:00
|
|
|
if (!ME_StreamOutPrint(pStream, "%.*s\\", i - pos, buffer + pos))
|
2005-05-05 19:00:49 +00:00
|
|
|
return FALSE;
|
|
|
|
pos = i;
|
|
|
|
}
|
2005-09-05 22:07:52 +00:00
|
|
|
if (pos < nBytes)
|
2007-04-20 11:26:32 +00:00
|
|
|
if (!ME_StreamOutMove(pStream, buffer + pos, nBytes - pos))
|
2005-05-05 19:00:49 +00:00
|
|
|
return FALSE;
|
|
|
|
pos = 0;
|
|
|
|
} else if (*text < 128) {
|
|
|
|
if (*text == '{' || *text == '}' || *text == '\\')
|
|
|
|
buffer[pos++] = '\\';
|
|
|
|
buffer[pos++] = (char)(*text++);
|
|
|
|
nChars--;
|
|
|
|
} else {
|
|
|
|
BOOL unknown = FALSE;
|
2005-10-08 17:17:27 +00:00
|
|
|
char letter[3];
|
|
|
|
|
2005-05-05 19:00:49 +00:00
|
|
|
/* FIXME: In the MS docs for WideCharToMultiByte there is a big list of
|
|
|
|
* codepages including CP_SYMBOL for which the last parameter must be set
|
|
|
|
* to NULL for the function to succeed. But in Wine we need to care only
|
|
|
|
* about CP_SYMBOL */
|
2007-04-20 11:26:32 +00:00
|
|
|
nBytes = WideCharToMultiByte(pStream->nCodePage, 0, text, 1,
|
2005-05-05 19:00:49 +00:00
|
|
|
letter, 3, NULL,
|
2007-04-20 11:26:32 +00:00
|
|
|
(pStream->nCodePage == CP_SYMBOL) ? NULL : &unknown);
|
2005-05-05 19:00:49 +00:00
|
|
|
if (unknown)
|
|
|
|
pos += sprintf(buffer + pos, "\\u%d?", (short)*text);
|
2005-10-08 17:17:27 +00:00
|
|
|
else if ((BYTE)*letter < 128) {
|
2005-05-05 19:00:49 +00:00
|
|
|
if (*letter == '{' || *letter == '}' || *letter == '\\')
|
|
|
|
buffer[pos++] = '\\';
|
|
|
|
buffer[pos++] = *letter;
|
|
|
|
} else {
|
|
|
|
for (i = 0; i < nBytes; i++)
|
2005-11-02 20:03:07 +00:00
|
|
|
pos += sprintf(buffer + pos, "\\'%02x", (BYTE)letter[i]);
|
2005-05-05 19:00:49 +00:00
|
|
|
}
|
|
|
|
text++;
|
|
|
|
nChars--;
|
|
|
|
}
|
|
|
|
if (pos >= STREAMOUT_BUFFER_SIZE - 11) {
|
2007-04-20 11:26:32 +00:00
|
|
|
if (!ME_StreamOutMove(pStream, buffer, pos))
|
2005-05-05 19:00:49 +00:00
|
|
|
return FALSE;
|
|
|
|
pos = 0;
|
|
|
|
}
|
|
|
|
}
|
2007-04-20 11:26:32 +00:00
|
|
|
return ME_StreamOutMove(pStream, buffer, pos);
|
2005-05-05 19:00:49 +00:00
|
|
|
}
|
|
|
|
|
2016-08-18 10:40:37 +00:00
|
|
|
static BOOL stream_out_graphics( ME_TextEditor *editor, ME_OutStream *stream,
|
|
|
|
ME_Run *run )
|
|
|
|
{
|
|
|
|
IDataObject *data;
|
|
|
|
HRESULT hr;
|
|
|
|
FORMATETC fmt = { CF_ENHMETAFILE, NULL, DVASPECT_CONTENT, -1, TYMED_ENHMF };
|
|
|
|
STGMEDIUM med = { TYMED_NULL };
|
|
|
|
BOOL ret = FALSE;
|
|
|
|
ENHMETAHEADER *emf_bits = NULL;
|
|
|
|
UINT size;
|
|
|
|
SIZE goal, pic;
|
|
|
|
ME_Context c;
|
|
|
|
|
|
|
|
hr = IOleObject_QueryInterface( run->ole_obj->poleobj, &IID_IDataObject, (void **)&data );
|
|
|
|
if (FAILED(hr)) return FALSE;
|
|
|
|
|
|
|
|
ME_InitContext( &c, editor, ITextHost_TxGetDC( editor->texthost ) );
|
|
|
|
hr = IDataObject_QueryGetData( data, &fmt );
|
|
|
|
if (hr != S_OK) goto done;
|
|
|
|
|
|
|
|
hr = IDataObject_GetData( data, &fmt, &med );
|
|
|
|
if (FAILED(hr)) goto done;
|
|
|
|
if (med.tymed != TYMED_ENHMF) goto done;
|
|
|
|
|
|
|
|
size = GetEnhMetaFileBits( med.u.hEnhMetaFile, 0, NULL );
|
|
|
|
if (size < FIELD_OFFSET(ENHMETAHEADER, cbPixelFormat)) goto done;
|
|
|
|
|
|
|
|
emf_bits = HeapAlloc( GetProcessHeap(), 0, size );
|
|
|
|
if (!emf_bits) goto done;
|
|
|
|
|
|
|
|
size = GetEnhMetaFileBits( med.u.hEnhMetaFile, size, (BYTE *)emf_bits );
|
|
|
|
if (size < FIELD_OFFSET(ENHMETAHEADER, cbPixelFormat)) goto done;
|
|
|
|
|
|
|
|
/* size_in_pixels = (frame_size / 100) * szlDevice / szlMillimeters
|
|
|
|
pic = size_in_pixels * 2540 / dpi */
|
|
|
|
pic.cx = MulDiv( emf_bits->rclFrame.right - emf_bits->rclFrame.left, emf_bits->szlDevice.cx * 254,
|
|
|
|
emf_bits->szlMillimeters.cx * c.dpi.cx * 10 );
|
|
|
|
pic.cy = MulDiv( emf_bits->rclFrame.bottom - emf_bits->rclFrame.top, emf_bits->szlDevice.cy * 254,
|
|
|
|
emf_bits->szlMillimeters.cy * c.dpi.cy * 10 );
|
|
|
|
|
|
|
|
/* convert goal size to twips */
|
|
|
|
goal.cx = MulDiv( run->ole_obj->sizel.cx, 144, 254 );
|
|
|
|
goal.cy = MulDiv( run->ole_obj->sizel.cy, 144, 254 );
|
|
|
|
|
|
|
|
if (!ME_StreamOutPrint( stream, "{\\*\\shppict{\\pict\\emfblip\\picw%d\\pich%d\\picwgoal%d\\pichgoal%d\n",
|
|
|
|
pic.cx, pic.cy, goal.cx, goal.cy ))
|
|
|
|
goto done;
|
|
|
|
|
|
|
|
if (!ME_StreamOutHexData( stream, (BYTE *)emf_bits, size ))
|
|
|
|
goto done;
|
|
|
|
|
|
|
|
if (!ME_StreamOutPrint( stream, "}}\n" ))
|
|
|
|
goto done;
|
|
|
|
|
|
|
|
ret = TRUE;
|
|
|
|
|
|
|
|
done:
|
|
|
|
ME_DestroyContext( &c );
|
|
|
|
HeapFree( GetProcessHeap(), 0, emf_bits );
|
|
|
|
ReleaseStgMedium( &med );
|
|
|
|
IDataObject_Release( data );
|
|
|
|
return ret;
|
|
|
|
}
|
2005-05-05 19:00:49 +00:00
|
|
|
|
2010-03-21 22:44:26 +00:00
|
|
|
static BOOL ME_StreamOutRTF(ME_TextEditor *editor, ME_OutStream *pStream,
|
|
|
|
const ME_Cursor *start, int nChars, int dwFormat)
|
2005-05-05 19:00:49 +00:00
|
|
|
{
|
2010-03-21 22:44:26 +00:00
|
|
|
ME_Cursor cursor = *start;
|
2016-11-17 23:04:08 +00:00
|
|
|
ME_DisplayItem *prev_para = NULL;
|
2010-03-21 22:44:26 +00:00
|
|
|
ME_Cursor endCur = cursor;
|
2009-04-16 17:49:22 +00:00
|
|
|
|
2016-11-17 23:04:08 +00:00
|
|
|
ME_MoveCursorChars(editor, &endCur, nChars, TRUE);
|
2009-04-16 17:49:22 +00:00
|
|
|
|
2007-04-20 11:26:32 +00:00
|
|
|
if (!ME_StreamOutRTFHeader(pStream, dwFormat))
|
2005-05-05 19:00:49 +00:00
|
|
|
return FALSE;
|
|
|
|
|
2010-03-21 22:44:26 +00:00
|
|
|
if (!ME_StreamOutRTFFontAndColorTbl(pStream, cursor.pRun, endCur.pRun))
|
2005-05-05 19:00:49 +00:00
|
|
|
return FALSE;
|
2010-03-21 22:44:26 +00:00
|
|
|
|
2005-05-05 19:00:49 +00:00
|
|
|
/* TODO: stylesheet table */
|
2010-03-21 22:44:26 +00:00
|
|
|
|
2017-06-03 22:36:44 +00:00
|
|
|
if (!ME_StreamOutPrint(pStream, "{\\*\\generator Wine Riched20 2.0;}\r\n"))
|
2005-05-05 19:00:49 +00:00
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
/* TODO: information group */
|
|
|
|
|
|
|
|
/* TODO: document formatting properties */
|
|
|
|
|
|
|
|
/* FIXME: We have only one document section */
|
|
|
|
|
|
|
|
/* TODO: section formatting properties */
|
|
|
|
|
2010-03-21 22:44:26 +00:00
|
|
|
do {
|
|
|
|
if (cursor.pPara != prev_para)
|
2005-05-05 19:00:49 +00:00
|
|
|
{
|
2010-03-21 22:44:26 +00:00
|
|
|
prev_para = cursor.pPara;
|
Finish the Wine sync. These components are not just rc file changes
atl, comctl32, comdlg32, dwmapi, fusion, gdiplus, jscript, mpr, mshtml, msi, msimtf, msxml3, ole32, oleaut32, riched20, shdocvw, shlwapi, urlmon, usp10, version and windowscodecs
Seems to build and boot. /me hides
svn path=/trunk/; revision=48273
2010-07-26 02:26:04 +00:00
|
|
|
if (!ME_StreamOutRTFParaProps(editor, pStream, cursor.pPara))
|
|
|
|
return FALSE;
|
2005-05-05 19:00:49 +00:00
|
|
|
}
|
2010-03-21 22:44:26 +00:00
|
|
|
|
|
|
|
if (cursor.pRun == endCur.pRun && !endCur.nOffset)
|
2005-05-05 19:00:49 +00:00
|
|
|
break;
|
2010-03-21 22:44:26 +00:00
|
|
|
TRACE("flags %xh\n", cursor.pRun->member.run.nFlags);
|
|
|
|
/* TODO: emit embedded objects */
|
|
|
|
if (cursor.pPara->member.para.nFlags & (MEPF_ROWSTART|MEPF_ROWEND))
|
Finish the Wine sync. These components are not just rc file changes
atl, comctl32, comdlg32, dwmapi, fusion, gdiplus, jscript, mpr, mshtml, msi, msimtf, msxml3, ole32, oleaut32, riched20, shdocvw, shlwapi, urlmon, usp10, version and windowscodecs
Seems to build and boot. /me hides
svn path=/trunk/; revision=48273
2010-07-26 02:26:04 +00:00
|
|
|
continue;
|
2010-03-21 22:44:26 +00:00
|
|
|
if (cursor.pRun->member.run.nFlags & MERF_GRAPHICS) {
|
2016-08-18 10:40:37 +00:00
|
|
|
if (!stream_out_graphics(editor, pStream, &cursor.pRun->member.run))
|
|
|
|
return FALSE;
|
2010-03-21 22:44:26 +00:00
|
|
|
} else if (cursor.pRun->member.run.nFlags & MERF_TAB) {
|
|
|
|
if (editor->bEmulateVersion10 && /* v1.0 - 3.0 */
|
2016-11-17 23:04:08 +00:00
|
|
|
cursor.pPara->member.para.fmt.dwMask & PFM_TABLE &&
|
|
|
|
cursor.pPara->member.para.fmt.wEffects & PFE_TABLE)
|
2010-03-21 22:44:26 +00:00
|
|
|
{
|
|
|
|
if (!ME_StreamOutPrint(pStream, "\\cell "))
|
|
|
|
return FALSE;
|
|
|
|
} else {
|
|
|
|
if (!ME_StreamOutPrint(pStream, "\\tab "))
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
} else if (cursor.pRun->member.run.nFlags & MERF_ENDCELL) {
|
|
|
|
if (pStream->nNestingLevel > 1) {
|
|
|
|
if (!ME_StreamOutPrint(pStream, "\\nestcell "))
|
|
|
|
return FALSE;
|
|
|
|
} else {
|
|
|
|
if (!ME_StreamOutPrint(pStream, "\\cell "))
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
nChars--;
|
|
|
|
} else if (cursor.pRun->member.run.nFlags & MERF_ENDPARA) {
|
2017-06-03 22:36:44 +00:00
|
|
|
if (!ME_StreamOutRTFCharProps(pStream, &cursor.pRun->member.run.style->fmt))
|
|
|
|
return FALSE;
|
|
|
|
|
2016-11-17 23:04:08 +00:00
|
|
|
if (cursor.pPara->member.para.fmt.dwMask & PFM_TABLE &&
|
|
|
|
cursor.pPara->member.para.fmt.wEffects & PFE_TABLE &&
|
2010-03-21 22:44:26 +00:00
|
|
|
!(cursor.pPara->member.para.nFlags & (MEPF_ROWSTART|MEPF_ROWEND|MEPF_CELL)))
|
|
|
|
{
|
2016-11-17 23:04:08 +00:00
|
|
|
if (!ME_StreamOutPrint(pStream, "\\row\r\n"))
|
2010-03-21 22:44:26 +00:00
|
|
|
return FALSE;
|
|
|
|
} else {
|
2016-11-17 23:04:08 +00:00
|
|
|
if (!ME_StreamOutPrint(pStream, "\\par\r\n"))
|
2010-03-21 22:44:26 +00:00
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
/* Skip as many characters as required by current line break */
|
2013-09-26 16:32:14 +00:00
|
|
|
nChars = max(0, nChars - cursor.pRun->member.run.len);
|
2010-03-21 22:44:26 +00:00
|
|
|
} else if (cursor.pRun->member.run.nFlags & MERF_ENDROW) {
|
2016-11-17 23:04:08 +00:00
|
|
|
if (!ME_StreamOutPrint(pStream, "\\line\r\n"))
|
2010-03-21 22:44:26 +00:00
|
|
|
return FALSE;
|
|
|
|
nChars--;
|
|
|
|
} else {
|
|
|
|
int nEnd;
|
|
|
|
|
|
|
|
TRACE("style %p\n", cursor.pRun->member.run.style);
|
|
|
|
if (!ME_StreamOutRTFCharProps(pStream, &cursor.pRun->member.run.style->fmt))
|
|
|
|
return FALSE;
|
|
|
|
|
2013-09-26 16:32:14 +00:00
|
|
|
nEnd = (cursor.pRun == endCur.pRun) ? endCur.nOffset : cursor.pRun->member.run.len;
|
|
|
|
if (!ME_StreamOutRTFText(pStream, get_text( &cursor.pRun->member.run, cursor.nOffset ),
|
2010-03-21 22:44:26 +00:00
|
|
|
nEnd - cursor.nOffset))
|
|
|
|
return FALSE;
|
|
|
|
cursor.nOffset = 0;
|
|
|
|
}
|
2016-08-18 10:40:37 +00:00
|
|
|
} while (cursor.pRun != endCur.pRun && ME_NextRun(&cursor.pPara, &cursor.pRun, TRUE));
|
2010-03-21 22:44:26 +00:00
|
|
|
|
2009-05-09 09:35:46 +00:00
|
|
|
if (!ME_StreamOutMove(pStream, "}\0", 2))
|
2005-05-05 19:00:49 +00:00
|
|
|
return FALSE;
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2010-03-21 22:44:26 +00:00
|
|
|
static BOOL ME_StreamOutText(ME_TextEditor *editor, ME_OutStream *pStream,
|
|
|
|
const ME_Cursor *start, int nChars, DWORD dwFormat)
|
2005-05-05 19:00:49 +00:00
|
|
|
{
|
2010-03-21 22:44:26 +00:00
|
|
|
ME_Cursor cursor = *start;
|
2005-05-05 19:00:49 +00:00
|
|
|
int nLen;
|
|
|
|
UINT nCodePage = CP_ACP;
|
2005-10-08 17:17:27 +00:00
|
|
|
char *buffer = NULL;
|
2005-05-05 19:00:49 +00:00
|
|
|
int nBufLen = 0;
|
|
|
|
BOOL success = TRUE;
|
|
|
|
|
2010-03-21 22:44:26 +00:00
|
|
|
if (!cursor.pRun)
|
2005-05-05 19:00:49 +00:00
|
|
|
return FALSE;
|
2009-01-31 12:10:24 +00:00
|
|
|
|
2005-05-05 19:00:49 +00:00
|
|
|
if (dwFormat & SF_USECODEPAGE)
|
|
|
|
nCodePage = HIWORD(dwFormat);
|
|
|
|
|
|
|
|
/* TODO: Handle SF_TEXTIZED */
|
2009-01-31 12:10:24 +00:00
|
|
|
|
2010-03-21 22:44:26 +00:00
|
|
|
while (success && nChars && cursor.pRun) {
|
2013-09-26 16:32:14 +00:00
|
|
|
nLen = min(nChars, cursor.pRun->member.run.len - cursor.nOffset);
|
2005-05-05 19:00:49 +00:00
|
|
|
|
2010-03-21 22:44:26 +00:00
|
|
|
if (!editor->bEmulateVersion10 && cursor.pRun->member.run.nFlags & MERF_ENDPARA)
|
2009-01-31 12:10:24 +00:00
|
|
|
{
|
2012-01-29 23:23:23 +00:00
|
|
|
static const WCHAR szEOL[] = { '\r', '\n' };
|
2009-01-31 12:10:24 +00:00
|
|
|
|
|
|
|
/* richedit 2.0 - all line breaks are \r\n */
|
|
|
|
if (dwFormat & SF_UNICODE)
|
|
|
|
success = ME_StreamOutMove(pStream, (const char *)szEOL, sizeof(szEOL));
|
|
|
|
else
|
|
|
|
success = ME_StreamOutMove(pStream, "\r\n", 2);
|
2005-05-05 19:00:49 +00:00
|
|
|
} else {
|
|
|
|
if (dwFormat & SF_UNICODE)
|
2013-09-26 16:32:14 +00:00
|
|
|
success = ME_StreamOutMove(pStream, (const char *)(get_text( &cursor.pRun->member.run, cursor.nOffset )),
|
2005-05-05 19:00:49 +00:00
|
|
|
sizeof(WCHAR) * nLen);
|
|
|
|
else {
|
|
|
|
int nSize;
|
|
|
|
|
2013-09-26 16:32:14 +00:00
|
|
|
nSize = WideCharToMultiByte(nCodePage, 0, get_text( &cursor.pRun->member.run, cursor.nOffset ),
|
2005-05-05 19:00:49 +00:00
|
|
|
nLen, NULL, 0, NULL, NULL);
|
|
|
|
if (nSize > nBufLen) {
|
2007-04-20 11:26:32 +00:00
|
|
|
FREE_OBJ(buffer);
|
2005-10-08 17:17:27 +00:00
|
|
|
buffer = ALLOC_N_OBJ(char, nSize);
|
2005-05-05 19:00:49 +00:00
|
|
|
nBufLen = nSize;
|
|
|
|
}
|
2013-09-26 16:32:14 +00:00
|
|
|
WideCharToMultiByte(nCodePage, 0, get_text( &cursor.pRun->member.run, cursor.nOffset ),
|
2005-05-05 19:00:49 +00:00
|
|
|
nLen, buffer, nSize, NULL, NULL);
|
2007-04-20 11:26:32 +00:00
|
|
|
success = ME_StreamOutMove(pStream, buffer, nSize);
|
2005-05-05 19:00:49 +00:00
|
|
|
}
|
|
|
|
}
|
2009-01-31 12:10:24 +00:00
|
|
|
|
2005-05-05 19:00:49 +00:00
|
|
|
nChars -= nLen;
|
2010-03-21 22:44:26 +00:00
|
|
|
cursor.nOffset = 0;
|
|
|
|
cursor.pRun = ME_FindItemFwd(cursor.pRun, diRun);
|
2005-05-05 19:00:49 +00:00
|
|
|
}
|
2009-01-31 12:10:24 +00:00
|
|
|
|
2007-04-20 11:26:32 +00:00
|
|
|
FREE_OBJ(buffer);
|
2005-05-05 19:00:49 +00:00
|
|
|
return success;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2010-03-21 22:44:26 +00:00
|
|
|
LRESULT ME_StreamOutRange(ME_TextEditor *editor, DWORD dwFormat,
|
|
|
|
const ME_Cursor *start,
|
|
|
|
int nChars, EDITSTREAM *stream)
|
2005-05-05 19:00:49 +00:00
|
|
|
{
|
2007-04-20 11:26:32 +00:00
|
|
|
ME_OutStream *pStream = ME_StreamOutInit(editor, stream);
|
2005-05-05 19:00:49 +00:00
|
|
|
|
2005-08-12 17:41:40 +00:00
|
|
|
if (dwFormat & SF_RTF)
|
2010-03-21 22:44:26 +00:00
|
|
|
ME_StreamOutRTF(editor, pStream, start, nChars, dwFormat);
|
2005-05-05 19:00:49 +00:00
|
|
|
else if (dwFormat & SF_TEXT || dwFormat & SF_TEXTIZED)
|
2010-03-21 22:44:26 +00:00
|
|
|
ME_StreamOutText(editor, pStream, start, nChars, dwFormat);
|
2007-04-20 11:26:32 +00:00
|
|
|
if (!pStream->stream->dwError)
|
|
|
|
ME_StreamOutFlush(pStream);
|
|
|
|
return ME_StreamOutFree(pStream);
|
|
|
|
}
|
|
|
|
|
|
|
|
LRESULT
|
|
|
|
ME_StreamOut(ME_TextEditor *editor, DWORD dwFormat, EDITSTREAM *stream)
|
|
|
|
{
|
2010-03-21 22:44:26 +00:00
|
|
|
ME_Cursor start;
|
|
|
|
int nChars;
|
2007-04-20 11:26:32 +00:00
|
|
|
|
2010-03-21 22:44:26 +00:00
|
|
|
if (dwFormat & SFF_SELECTION) {
|
|
|
|
int nStart, nTo;
|
|
|
|
start = editor->pCursors[ME_GetSelectionOfs(editor, &nStart, &nTo)];
|
|
|
|
nChars = nTo - nStart;
|
|
|
|
} else {
|
|
|
|
ME_SetCursorToStart(editor, &start);
|
|
|
|
nChars = ME_GetTextLength(editor);
|
|
|
|
/* Generate an end-of-paragraph at the end of SCF_ALL RTF output */
|
|
|
|
if (dwFormat & SF_RTF)
|
|
|
|
nChars++;
|
2007-04-20 11:26:32 +00:00
|
|
|
}
|
2010-03-21 22:44:26 +00:00
|
|
|
return ME_StreamOutRange(editor, dwFormat, &start, nChars, stream);
|
2005-05-05 19:00:49 +00:00
|
|
|
}
|