Sync to Wine-20050419:

Krzysztof Foltman <wdev@foltman.com>
- removed trailing spaces from some files
- tab support
- indent support
- PageUp key support.
- Support for "normal" scroll bar functionality (line and page
  scrolling).
- made string operations consistent wrt whitespace handling (which
  should greatly improve stability of the wrap code and eliminate
  regressions of the most recent versions)
- completely new scrollbar handling (much more reliable) and related
  redraw fixes
- Page Down handler (no Page Up yet, fixing wrap/redraw/scrollbar bugs
  was of higher priority)
- RTF reader doesn't use RichEdit messages anymore (which saves on
  unnecessary repaints)
- added unicode character support to RTF import (like: \u12345 ?)
- small fixes
- fixed whitespace identification bug
- removed drawing of paragraph marks
- improved stub implementations for IRichEditOle
- Unknown destinations are now correctly skipped (so loading an RTF
  file generated by, for example, OpenOffice doesn't produce lots of
  garbage anymore).
- Format stack for RTF groups (so that RTF reader can correctly read
  what RTF writer wrote :) )
- EM_STREAMIN can now deal with undo in a reasonable manner (no
  multiple undo actions in one EM_STREAMIN).
- Related changes to undo code (umIgnore mode is now handled
  correctly).
- Numerous improvements in the RTF reader: it reads some character
  attributes now (you will have proper small print in license agreements
  now).
- Fixed a memory overwrite bug in conversion from CHARFORMAT2A to
  CHARFORMAT2W.
- Optimized repaint of the area below the text.
- ME_JoinRuns didn't mark the paragraph for rewrapping, fixed.
- Removed PostQuitMessage(0) from WM_DESTROY handler (duh!).
- Use of EM_GETOLEINTERFACE is reported with FIXME instead of TRACE
  (any app using this message is likely to encounter major problems).
- WM_COPY (and WM_CUT) can now put both Unicode and RTF format (thanks
  to Phil Krylov's RTF generator code).
- New message implemented - WM_PASTE.
- RTF reader: rtfPlain implemented (kind of).
- RTF writer: rewritten main loop (the old one crashed in some
  circumstances when SFF_SELECTION was used).
- The meaning of the rewrap flag got inverted (MEPF_REWRAP instead of
  MEPF_WRAPPED) for consistency.
- Major code cleanups in rewrap/repaint code, leading to "smarter"
  behaviour wrt repainting selections.
- Old font management replaced by the cache-based one, which keeps
  maximum of 10 HFONTs at once, instead of one per a couple of runs.
- EM_CANPASTE implemented
- updated TODO list (including list of (un)implemented messages)
- fixed WM_PASTE (the previous version might not close the clipboard
  if it didn't contain a usable format)
- scrollbar operations (like clicking on arrows) should update
  scrollbar's current position
Gerald Pfeifer <gerald@pfeifer.com>
- Make ME_ArrowLeft() return a value in every case.
Phil Krylov <phil@newstar.rinet.ru>
- Make RTF reader fall back to simple text if a correct RTF header is
  not detected. This should fix some installers.
- Made RTF reader and writer handle codepages mostly similar to the
  original riched20.dll.
- Fixed support for RTF documents using ANSI charset and added support
  for multibyte charsets, so that BIG5 and UTF-8 RTF documents are
  working now.
- Replaced slow and outdated character set handling in RTF reader by
  Unicode/codepages support. Added charset->codepage conversion.
- Implemented hash table lookup for RTF keywords in RTF reader.
- Added "generator" RTF destination handling.
- Initial implementation of EM_STREAMOUT and RTF writer.
- Fixed \u keyword to output signed 16-bit values. Also fixed CP_SYMBOL
  conversion and the detection of the default font's codepage.
- Improved RTF export.
Mike McCormack <mike@codeweavers.com>
- Remove casts and unused code.
Hannu Valtonen <Hannu.Valtonen@hut.fi>
- Added mousewheel support.
Vincent Beron <vberon@mecano.gme.usherb.ca>
- Use "" for Windows includes in dlls, instead of <>.
Jakob Eriksson <jakov@vmlinux.org>
- Get rid of HeapAlloc casts.
Jason Edmeades <us@the-edmeades.demon.co.uk>
- Correct memory allocation macro.

svn path=/trunk/; revision=15014
This commit is contained in:
Gé van Geldorp 2005-05-05 19:00:49 +00:00
parent f71087e736
commit e14533d20a
17 changed files with 2399 additions and 2272 deletions

View file

@ -20,7 +20,8 @@ C_SRCS = \
string.c \
style.c \
undo.c \
wrap.c
wrap.c \
writer.c
@MAKE_DLL_RULES@

View file

@ -104,15 +104,15 @@ void ME_MoveCaret(ME_TextEditor *editor)
{
row = ME_FindItemBack(tmp, diStartRow);
pSizeRun = run = tmp;
sz = ME_GetRunSize(&c, &run->member.run, ME_StrLen(run->member.run.strText));
sz = ME_GetRunSize(&c, &para->member.para, &run->member.run, ME_StrLen(run->member.run.strText));
}
}
if (pCursor->nOffset && !(run->member.run.nFlags & MERF_SKIPPED)) {
sz = ME_GetRunSize(&c, &run->member.run, pCursor->nOffset);
sz = ME_GetRunSize(&c, &para->member.para, &run->member.run, pCursor->nOffset);
}
CreateCaret(editor->hWnd, NULL, 0, pSizeRun->member.run.nAscent+pSizeRun->member.run.nDescent);
SetCaretPos(run->member.run.pt.x+sz.cx,
para->member.para.nYPos+row->member.row.nBaseline+pSizeRun->member.run.pt.y-pSizeRun->member.run.nAscent-GetScrollPos(editor->hWnd, SB_VERT));
para->member.para.nYPos+row->member.row.nBaseline+pSizeRun->member.run.pt.y-pSizeRun->member.run.nAscent-ME_GetYScrollPos(editor));
} else {
assert(0 == "Wrapped paragraph run without a row?");
CreateCaret(editor->hWnd, NULL, 0, 10);
@ -300,12 +300,6 @@ void ME_InsertTextFromCursor(ME_TextEditor *editor, int nCursor,
assert(style);
editor->bCaretAtEnd = FALSE;
/*
if (!style)
style = ME_GetInsertStyle(editor, nCursor);
else
ME_AddRefStyle(style);
*/
ME_AddRefStyle(style);
/* FIXME really HERE ? */
@ -317,10 +311,30 @@ void ME_InsertTextFromCursor(ME_TextEditor *editor, int nCursor,
len = lstrlenW(str);
pos = str;
/* FIXME this sucks - no respect for unicode (what else can be a line separator in unicode?) */
while(pos-str < len && *pos != '\r' && *pos != '\n')
while(pos-str < len && *pos != '\r' && *pos != '\n' && *pos != '\t')
pos++;
/* handle EOLs */
if (pos-str < len) {
if (pos-str < len && *pos == '\t') { /* handle tabs */
ME_DisplayItem *pNewRun = NULL;
WCHAR tab = '\t';
if (pos!=str)
ME_InsertTextFromCursor(editor, nCursor, str, pos-str, style);
p = &editor->pCursors[nCursor];
assert(style);
assert(p->pRun->type == diRun);
pNewRun = ME_MakeRun(style, ME_MakeStringN(&tab, 1), MERF_TAB); /* addrefs style */
ME_InsertRun(editor, ME_CharOfsFromRunOfs(editor, p->pRun, p->nOffset), pNewRun);
ME_DestroyDisplayItem(pNewRun);
ME_ReleaseStyle(style);
pos++;
if(pos-str < len) {
ME_InsertTextFromCursor(editor, nCursor, pos, len-(pos-str), style);
}
return;
}
if (pos-str < len) { /* handle EOLs */
ME_DisplayItem *tp, *end_run;
ME_Paragraph *para;
ME_Style *tmp_style;
@ -404,6 +418,7 @@ BOOL ME_ArrowLeft(ME_TextEditor *editor, ME_Cursor *p)
}
assert(0);
}
return FALSE;
}
BOOL ME_ArrowRight(ME_TextEditor *editor, ME_Cursor *p)
@ -537,7 +552,7 @@ void ME_LButtonDown(ME_TextEditor *editor, int x, int y)
editor->nUDArrowX = -1;
y += GetScrollPos(editor->hWnd, SB_VERT);
y += ME_GetYScrollPos(editor);
tmp_cursor = editor->pCursors[0];
is_selection = ME_IsSelection(editor);
@ -568,7 +583,7 @@ void ME_MouseMove(ME_TextEditor *editor, int x, int y)
{
ME_Cursor tmp_cursor;
y += GetScrollPos(editor->hWnd, SB_VERT);
y += ME_GetYScrollPos(editor);
tmp_cursor = editor->pCursors[0];
if (!ME_FindPixelPos(editor, x, y, &editor->pCursors[0], &editor->bCaretAtEnd))
@ -702,6 +717,109 @@ void ME_ArrowDown(ME_TextEditor *editor, ME_Cursor *pCursor)
assert(pCursor->pRun->type == diRun);
}
void ME_ArrowPageUp(ME_TextEditor *editor, ME_Cursor *pCursor)
{
ME_DisplayItem *pRun = pCursor->pRun;
ME_DisplayItem *pLast, *p;
int x, y, ys, yd, yp, yprev;
ME_Cursor tmp_curs = *pCursor;
x = ME_GetXForArrow(editor, pCursor);
if (!pCursor->nOffset && editor->bCaretAtEnd)
pRun = ME_FindItemBack(pRun, diRun);
p = ME_FindItemBack(pRun, diStartRowOrParagraph);
assert(p->type == diStartRow);
yp = ME_FindItemBack(p, diParagraph)->member.para.nYPos;
yprev = ys = y = yp + p->member.row.nYPos;
yd = y - editor->sizeWindow.cy;
pLast = p;
do {
p = ME_FindItemBack(p, diStartRowOrParagraph);
if (!p)
break;
if (p->type == diParagraph) { /* crossing paragraphs */
if (p->member.para.prev_para == NULL)
break;
yp = p->member.para.prev_para->member.para.nYPos;
continue;
}
y = yp + p->member.row.nYPos;
if (y < yd)
break;
pLast = p;
yprev = y;
} while(1);
pCursor->pRun = ME_FindRunInRow(editor, pLast, x, &pCursor->nOffset, &editor->bCaretAtEnd);
ME_UpdateSelection(editor, &tmp_curs);
if (yprev < editor->sizeWindow.cy)
{
ME_EnsureVisible(editor, ME_FindItemFwd(editor->pBuffer->pFirst, diRun));
ME_Repaint(editor);
}
else {
ME_Scroll(editor, 0, ys-yprev);
ME_Repaint(editor);
}
assert(pCursor->pRun);
assert(pCursor->pRun->type == diRun);
}
/* FIXME: in the original RICHEDIT, PageDown always scrolls by the same amount
of pixels, even if it makes the scroll bar position exceed its normal maximum.
In such a situation, clicking the scrollbar restores its position back to the
normal range (ie. sets it to (doclength-screenheight)). */
void ME_ArrowPageDown(ME_TextEditor *editor, ME_Cursor *pCursor)
{
ME_DisplayItem *pRun = pCursor->pRun;
ME_DisplayItem *pLast, *p;
int x, y, ys, yd, yp, yprev;
ME_Cursor tmp_curs = *pCursor;
x = ME_GetXForArrow(editor, pCursor);
if (!pCursor->nOffset && editor->bCaretAtEnd)
pRun = ME_FindItemBack(pRun, diRun);
p = ME_FindItemBack(pRun, diStartRowOrParagraph);
assert(p->type == diStartRow);
yp = ME_FindItemBack(p, diParagraph)->member.para.nYPos;
yprev = ys = y = yp + p->member.row.nYPos;
yd = y + editor->sizeWindow.cy;
pLast = p;
do {
p = ME_FindItemFwd(p, diStartRowOrParagraph);
if (!p)
break;
if (p->type == diParagraph) {
yp = p->member.para.nYPos;
continue;
}
y = yp + p->member.row.nYPos;
if (y >= yd)
break;
pLast = p;
yprev = y;
} while(1);
pCursor->pRun = ME_FindRunInRow(editor, pLast, x, &pCursor->nOffset, &editor->bCaretAtEnd);
ME_UpdateSelection(editor, &tmp_curs);
if (yprev >= editor->nTotalLength-editor->sizeWindow.cy)
{
ME_EnsureVisible(editor, ME_FindItemBack(editor->pBuffer->pLast, diRun));
ME_Repaint(editor);
}
else {
ME_Scroll(editor, 0, ys-yprev);
ME_Repaint(editor);
}
assert(pCursor->pRun);
assert(pCursor->pRun->type == diRun);
}
void ME_ArrowHome(ME_TextEditor *editor, ME_Cursor *pCursor)
{
ME_DisplayItem *pRow = ME_FindItemBack(pCursor->pRun, diStartRow);
@ -799,43 +917,42 @@ BOOL ME_CancelSelection(ME_TextEditor *editor, int dir)
editor->pCursors[1] = editor->pCursors[0];
else
editor->pCursors[0] = editor->pCursors[1];
/* FIXME optimize */
ME_MarkAllForWrapping(editor);
ME_Repaint(editor);
return TRUE;
}
void ME_RepaintSelection(ME_TextEditor *editor, ME_Cursor *pTempCursor)
BOOL ME_UpdateSelection(ME_TextEditor *editor, ME_Cursor *pTempCursor)
{
ME_Cursor old_anchor = editor->pCursors[1];
BOOL bRedraw = FALSE;
bRedraw = memcmp(&editor->pCursors[0], &editor->pCursors[1], sizeof(ME_Cursor));
if (bRedraw)
{
/* FIXME optimize */
ME_MarkAllForWrapping(editor);
}
if (GetKeyState(VK_SHIFT)>=0) /* cancelling selection */
{
/* any selection was present ? if so, it's no more, repaint ! */
editor->pCursors[1] = editor->pCursors[0];
if (memcmp(pTempCursor, &old_anchor, sizeof(ME_Cursor))) {
ME_Repaint(editor);
return;
return TRUE;
}
return;
return FALSE;
}
else
{
if (!memcmp(pTempCursor, &editor->pCursors[1], sizeof(ME_Cursor))) /* starting selection */
{
editor->pCursors[1] = *pTempCursor;
return TRUE;
}
}
ME_Repaint(editor);
return TRUE;
}
void ME_RepaintSelection(ME_TextEditor *editor, ME_Cursor *pTempCursor)
{
if (ME_UpdateSelection(editor, pTempCursor)) {
ME_EnsureVisible(editor, editor->pCursors[0].pRun);
ME_Repaint(editor);
}
}
void ME_DeleteSelection(ME_TextEditor *editor)
@ -898,6 +1015,16 @@ BOOL ME_ArrowKey(ME_TextEditor *editor, int nVKey, int nCtrl)
ME_RepaintSelection(editor, &tmp_curs);
ME_SendSelChange(editor);
return TRUE;
case VK_PRIOR:
ME_ArrowPageUp(editor, p);
ME_ClearTempStyle(editor);
ME_SendSelChange(editor);
return TRUE;
case VK_NEXT:
ME_ArrowPageDown(editor, p);
ME_ClearTempStyle(editor);
ME_SendSelChange(editor);
return TRUE;
}
editor->nUDArrowX = -1;
@ -914,6 +1041,7 @@ BOOL ME_ArrowKey(ME_TextEditor *editor, int nVKey, int nCtrl)
}
if (ME_ArrowLeft(editor, p)) {
editor->bCaretAtEnd = FALSE; /* FIXME or maybe not */
ME_ClearTempStyle(editor);
ME_MoveCaret(editor);
ME_DeleteTextAtCursor(editor, nCursor, 1);
ME_UpdateRepaint(editor);
@ -927,10 +1055,12 @@ BOOL ME_ArrowKey(ME_TextEditor *editor, int nVKey, int nCtrl)
if (ME_IsSelection(editor))
{
ME_DeleteSelection(editor);
ME_ClearTempStyle(editor);
ME_UpdateRepaint(editor);
return TRUE;
}
ME_DeleteTextAtCursor(editor, nCursor, 1);
ME_ClearTempStyle(editor);
ME_UpdateRepaint(editor);
return TRUE;
}

View file

@ -23,7 +23,7 @@
Messages (ANSI versions not done yet)
- EM_AUTOURLDETECT 2.0
- EM_CANPASTE
+ EM_CANPASTE
+ EM_CANREDO 2.0
+ EM_CANUNDO
- EM_CHARFROMPOS
@ -73,7 +73,7 @@
- EM_LINESCROLL
- EM_PASTESPECIAL
- EM_POSFROMCHARS
- EM_REDO 2.0
+ EM_REDO 2.0
- EM_REQUESTRESIZE
+ EM_REPLACESEL (proper style?) ANSI&Unicode
- EM_SCROLL
@ -102,17 +102,17 @@
- EM_SETWORDBREAKPROCEX
- EM_SETWORDWRAPMODE 1.0asian
- EM_STOPGROUPTYPING 2.0
- EM_STREAMIN
- EM_STREAMOUT
- EM_UNDO
+ EM_STREAMIN (can't fall back to text when the RTF isn't really RTF)
+ EM_STREAMOUT
+ EM_UNDO
+ WM_CHAR
+ WM_CLEAR
- WM_COPY (lame implementation, no RTF support)
- WM_CUT (lame implementation, no RTF support)
+ WM_COPY
+ WM_CUT
+ WM_GETDLGCODE (the current implementation is incomplete)
+ WM_GETTEXT (ANSI&Unicode)
+ WM_GETTEXTLENGTH (ANSI version sucks)
- WM_PASTE
+ WM_PASTE
- WM_SETFONT
+ WM_SETTEXT (resets undo stack !) (proper style?) ANSI&Unicode
- WM_STYLECHANGING
@ -166,30 +166,25 @@
/*
* RICHED20 TODO (incomplete):
*
* - font caching
* - messages/styles/notifications listed above
* - Undo coalescing
* - add remaining CHARFORMAT/PARAFORMAT fields
* - right/center align should strip spaces from the beginning
* - more advanced navigation (Ctrl-arrows, PageUp/PageDn)
* - more advanced navigation (Ctrl-arrows)
* - tabs
* - pictures (not just smiling faces that lack API support ;-) )
* - OLE objects
* - pictures/OLE objects (not just smiling faces that lack API support ;-) )
* - COM interface (looks like a major pain in the TODO list)
* - calculate heights of pictures (half-done)
* - EM_STREAMIN/EM_STREAMOUT
* - horizontal scrolling (not even started)
* - fix scrollbars and refresh (it sucks bigtime)
* - hysteresis during wrapping (related to scrollbars appearing/disappearing)
* - should remember maximum row width for wrap hysteresis
* - find/replace
* - how to implement EM_FORMATRANGE and EM_DISPLAYBAND ? (Mission Impossible)
* - italic cursor with italic fonts
* - italic caret with italic fonts
* - IME
* - most notifications aren't sent at all (the most important ones are)
* - when should EN_SELCHANGE be sent after text change ? (before/after EN_UPDATE?)
* - WM_SETTEXT may use wrong style (but I'm 80% sure it's OK)
* - EM_GETCHARFORMAT with SCF_SELECTION may not behave 100% like in original (but very close)
* - bugs in end-of-text handling (the gray bar) could get me in jail ;-)
* - determination of row size
* - end-of-paragraph marks should be of reasonable size
*
* Bugs that are probably fixed, but not so easy to verify:
* - EN_UPDATE/EN_CHANGE are handled very incorrectly (should be OK now)
@ -203,11 +198,11 @@
*/
#include "editor.h"
#include <ole2.h>
#include <richole.h>
#include <winreg.h>
#include "ole2.h"
#include "richole.h"
#include "winreg.h"
#define NO_SHLWAPI_STREAM
#include <shlwapi.h>
#include "shlwapi.h"
#include "rtf.h"
@ -238,91 +233,388 @@ ME_TextBuffer *ME_MakeText() {
return buf;
}
#define STREAMIN_BUFFER_SIZE 4096 /* M$ compatibility */
static LRESULT ME_StreamInText(ME_TextEditor *editor, DWORD dwFormat, EDITSTREAM *stream, ME_Style *style)
static LRESULT ME_StreamInText(ME_TextEditor *editor, DWORD dwFormat, ME_InStream *stream, ME_Style *style)
{
BYTE buffer[STREAMIN_BUFFER_SIZE+1];
WCHAR wszText[STREAMIN_BUFFER_SIZE+1];
WCHAR *pText;
TRACE("%08lx %p\n", dwFormat, stream);
stream->dwError = 0;
do {
long nDataSize = 0, nWideChars = 0;
stream->dwError = stream->pfnCallback(stream->dwCookie,
(dwFormat & SF_UNICODE ? (BYTE *)wszText : buffer),
STREAMIN_BUFFER_SIZE, &nDataSize);
if (stream->dwError)
break;
if (!nDataSize)
break;
long nWideChars = 0;
if (!stream->dwSize)
{
ME_StreamInFill(stream);
if (stream->editstream->dwError)
break;
if (!stream->dwSize)
break;
}
if (!(dwFormat & SF_UNICODE))
{
/* FIXME? this is doomed to fail on true MBCS like UTF-8, luckily they're unlikely to be used as CP_ACP */
nWideChars = MultiByteToWideChar(CP_ACP, 0, buffer, nDataSize, wszText, STREAMIN_BUFFER_SIZE);
nWideChars = MultiByteToWideChar(CP_ACP, 0, stream->buffer, stream->dwSize, wszText, STREAMIN_BUFFER_SIZE);
pText = wszText;
}
else
nWideChars = nDataSize>>1;
ME_InsertTextFromCursor(editor, 0, wszText, nWideChars, style);
if (nDataSize<STREAMIN_BUFFER_SIZE)
{
nWideChars = stream->dwSize >> 1;
pText = (WCHAR *)stream->buffer;
}
ME_InsertTextFromCursor(editor, 0, pText, nWideChars, style);
if (stream->dwSize < STREAMIN_BUFFER_SIZE)
break;
} while(1);
ME_CommitUndo(editor);
ME_CommitUndo(editor);
ME_Repaint(editor);
return 0;
}
void ME_RTFCharAttrHook(RTF_Info *info)
{
CHARFORMAT2W fmt;
fmt.cbSize = sizeof(fmt);
fmt.dwMask = 0;
switch(info->rtfMinor)
{
case rtfPlain:
/* FIXME add more flags once they're implemented */
fmt.dwMask = CFM_BOLD | CFM_ITALIC | CFM_UNDERLINE | CFM_STRIKEOUT | CFM_COLOR | CFM_BACKCOLOR | CFM_SIZE | CFM_WEIGHT;
fmt.dwEffects = CFE_AUTOCOLOR | CFE_AUTOBACKCOLOR;
fmt.yHeight = 12*20; /* 12pt */
fmt.wWeight = 400;
break;
case rtfBold:
fmt.dwMask = CFM_BOLD;
fmt.dwEffects = info->rtfParam ? fmt.dwMask : 0;
break;
case rtfItalic:
fmt.dwMask = CFM_ITALIC;
fmt.dwEffects = info->rtfParam ? fmt.dwMask : 0;
break;
case rtfUnderline:
fmt.dwMask = CFM_UNDERLINE;
fmt.dwEffects = info->rtfParam ? fmt.dwMask : 0;
break;
case rtfStrikeThru:
fmt.dwMask = CFM_STRIKEOUT;
fmt.dwEffects = info->rtfParam ? fmt.dwMask : 0;
break;
case rtfBackColor:
fmt.dwMask = CFM_BACKCOLOR;
fmt.dwEffects = 0;
if (info->rtfParam == 0)
fmt.dwEffects = CFE_AUTOBACKCOLOR;
else if (info->rtfParam != rtfNoParam)
{
RTFColor *c = RTFGetColor(info, info->rtfParam);
fmt.crTextColor = (c->rtfCBlue<<16)|(c->rtfCGreen<<8)|(c->rtfCRed);
}
break;
case rtfForeColor:
fmt.dwMask = CFM_COLOR;
fmt.dwEffects = 0;
if (info->rtfParam == 0)
fmt.dwEffects = CFE_AUTOCOLOR;
else if (info->rtfParam != rtfNoParam)
{
RTFColor *c = RTFGetColor(info, info->rtfParam);
fmt.crTextColor = (c->rtfCBlue<<16)|(c->rtfCGreen<<8)|(c->rtfCRed);
}
break;
case rtfFontNum:
if (info->rtfParam != rtfNoParam)
{
RTFFont *f = RTFGetFont(info, info->rtfParam);
if (f)
{
MultiByteToWideChar(CP_ACP, 0, f->rtfFName, -1, fmt.szFaceName, sizeof(fmt.szFaceName)/sizeof(WCHAR));
fmt.szFaceName[sizeof(fmt.szFaceName)/sizeof(WCHAR)-1] = '\0';
fmt.bCharSet = f->rtfFCharSet;
fmt.dwMask = CFM_FACE | CFM_CHARSET;
}
}
break;
case rtfFontSize:
fmt.dwMask = CFM_SIZE;
if (info->rtfParam != rtfNoParam)
fmt.yHeight = info->rtfParam*10;
break;
}
if (fmt.dwMask) {
ME_Style *style2;
RTFFlushOutputBuffer(info);
/* FIXME too slow ? how come ? */
style2 = ME_ApplyStyle(info->style, &fmt);
ME_ReleaseStyle(info->style);
info->style = style2;
}
}
/* FIXME this function doesn't get any information about context of the RTF tag, which is very bad,
the same tags mean different things in different contexts */
void ME_RTFParAttrHook(RTF_Info *info)
{
PARAFORMAT2 fmt;
fmt.cbSize = sizeof(fmt);
fmt.dwMask = 0;
switch(info->rtfMinor)
{
case rtfParDef: /* I'm not 100% sure what does it do, but I guess it restores default paragraph attributes */
fmt.dwMask = PFM_ALIGNMENT | PFM_TABSTOPS | PFM_OFFSET | PFM_STARTINDENT;
fmt.wAlignment = PFA_LEFT;
fmt.cTabCount = 0;
fmt.dxOffset = fmt.dxStartIndent = 0;
break;
case rtfFirstIndent:
ME_GetSelectionParaFormat(info->editor, &fmt);
fmt.dwMask = PFM_STARTINDENT;
fmt.dxStartIndent = info->rtfParam + fmt.dxOffset;
break;
case rtfLeftIndent:
{
int first, left;
ME_GetSelectionParaFormat(info->editor, &fmt);
first = fmt.dxStartIndent;
left = info->rtfParam;
fmt.dwMask = PFM_STARTINDENT|PFM_OFFSET;
fmt.dxStartIndent = first + left;
fmt.dxOffset = -first;
break;
}
case rtfRightIndent:
fmt.dwMask = PFM_RIGHTINDENT;
fmt.dxRightIndent = info->rtfParam;
break;
case rtfQuadLeft:
case rtfQuadJust:
fmt.dwMask = PFM_ALIGNMENT;
fmt.wAlignment = PFA_LEFT;
break;
case rtfQuadRight:
fmt.dwMask = PFM_ALIGNMENT;
fmt.wAlignment = PFA_RIGHT;
break;
case rtfQuadCenter:
fmt.dwMask = PFM_ALIGNMENT;
fmt.wAlignment = PFA_CENTER;
break;
case rtfTabPos:
ME_GetSelectionParaFormat(info->editor, &fmt);
if (!(fmt.dwMask & PFM_TABSTOPS))
{
fmt.dwMask |= PFM_TABSTOPS;
fmt.cTabCount = 0;
}
if (fmt.cTabCount < MAX_TAB_STOPS)
fmt.rgxTabs[fmt.cTabCount++] = info->rtfParam;
break;
}
if (fmt.dwMask) {
RTFFlushOutputBuffer(info);
/* FIXME too slow ? how come ?*/
ME_SetSelectionParaFormat(info->editor, &fmt);
}
}
void ME_RTFReadHook(RTF_Info *info) {
switch(info->rtfClass)
{
case rtfGroup:
switch(info->rtfMajor)
{
case rtfBeginGroup:
if (info->stackTop < maxStack) {
memcpy(&info->stack[info->stackTop].fmt, &info->style->fmt, sizeof(CHARFORMAT2W));
info->stack[info->stackTop].codePage = info->codePage;
info->stack[info->stackTop].unicodeLength = info->unicodeLength;
}
info->stackTop++;
break;
case rtfEndGroup:
{
ME_Style *s;
RTFFlushOutputBuffer(info);
info->stackTop--;
/* FIXME too slow ? how come ? */
s = ME_ApplyStyle(info->style, &info->stack[info->stackTop].fmt);
ME_ReleaseStyle(info->style);
info->style = s;
info->codePage = info->stack[info->stackTop].codePage;
info->unicodeLength = info->stack[info->stackTop].unicodeLength;
break;
}
}
break;
case rtfControl:
switch(info->rtfMajor)
{
case rtfCharAttr:
ME_RTFCharAttrHook(info);
break;
case rtfParAttr:
ME_RTFParAttrHook(info);
break;
}
break;
}
}
void
ME_StreamInFill(ME_InStream *stream)
{
stream->editstream->dwError = stream->editstream->pfnCallback(stream->editstream->dwCookie,
stream->buffer,
sizeof(stream->buffer),
&stream->dwSize);
stream->dwUsed = 0;
}
static LRESULT ME_StreamIn(ME_TextEditor *editor, DWORD format, EDITSTREAM *stream)
{
RTF_Info parser;
ME_Style *style;
int from, to, to2, nUndoMode;
ME_UndoItem *pUI;
int nEventMask = editor->nEventMask;
ME_InStream inStream;
TRACE("%p %p\n", stream, editor->hWnd);
editor->nEventMask = 0;
ME_GetSelection(editor, &from, &to);
if (format & SFF_SELECTION) {
style = ME_GetSelectionInsertStyle(editor);
SendMessageW(editor->hWnd, WM_CLEAR, 0, 0);
ME_InternalDeleteText(editor, from, to-from);
}
else {
style = editor->pBuffer->pDefaultStyle;
ME_AddRefStyle(style);
SendMessageA(editor->hWnd, EM_SETSEL, 0, 0);
SetWindowTextA(editor->hWnd, "");
ME_InternalDeleteText(editor, 0, ME_GetTextLength(editor));
from = to = 0;
ME_ClearTempStyle(editor);
/* FIXME restore default paragraph formatting ! */
}
nUndoMode = editor->nUndoMode;
editor->nUndoMode = umIgnore;
inStream.editstream = stream;
inStream.editstream->dwError = 0;
inStream.dwSize = 0;
inStream.dwUsed = 0;
if (format & SF_RTF)
{
/* Check if it's really RTF, and if it is not, use plain text */
ME_StreamInFill(&inStream);
if (!inStream.editstream->dwError)
{
if (strncmp(inStream.buffer, "{\\rtf1", 6) && strncmp(inStream.buffer, "{\\urtf", 6))
{
format &= ~SF_RTF;
format |= SF_TEXT;
}
}
}
if (format & SF_RTF) {
/* setup the RTF parser */
memset(&parser, 0, sizeof parser);
RTFSetEditStream(&parser, stream);
parser.rtfFormat = format&(SF_TEXT|SF_RTF);
parser.hwndEdit = editor->hWnd;
WriterInit(&parser);
RTFInit(&parser);
BeginFile(&parser);
/* do the parsing */
RTFRead(&parser);
RTFFlushOutputBuffer(&parser);
}
else if (format & SF_TEXT)
ME_StreamInText(editor, format, stream, style);
else
ERR("EM_STREAMIN without SF_TEXT or SF_RTF\n");
/* put the cursor at the top */
if (!(format & SFF_SELECTION))
SendMessageA(editor->hWnd, EM_SETSEL, 0, 0);
else
if (!inStream.editstream->dwError)
{
/* FIXME where to put cursor now ? */
if (format & SF_RTF) {
/* setup the RTF parser */
memset(&parser, 0, sizeof parser);
RTFSetEditStream(&parser, &inStream);
parser.rtfFormat = format&(SF_TEXT|SF_RTF);
parser.hwndEdit = editor->hWnd;
parser.editor = editor;
parser.style = style;
WriterInit(&parser);
RTFInit(&parser);
RTFSetReadHook(&parser, ME_RTFReadHook);
BeginFile(&parser);
/* do the parsing */
RTFRead(&parser);
RTFFlushOutputBuffer(&parser);
RTFDestroy(&parser);
style = parser.style;
}
else if (format & SF_TEXT)
ME_StreamInText(editor, format, &inStream, style);
else
ERR("EM_STREAMIN without SF_TEXT or SF_RTF\n");
ME_GetSelection(editor, &to, &to2);
/* put the cursor at the top */
if (!(format & SFF_SELECTION))
SendMessageA(editor->hWnd, EM_SETSEL, 0, 0);
else
{
/* FIXME where to put cursor now ? */
}
}
ME_ReleaseStyle(style);
editor->nUndoMode = nUndoMode;
pUI = ME_AddUndoItem(editor, diUndoDeleteRun, NULL);
TRACE("from %d to %d\n", from, to);
if (pUI && from < to)
{
pUI->nStart = from;
pUI->nLen = to-from;
}
ME_CommitUndo(editor);
ME_ReleaseStyle(style);
editor->nEventMask = nEventMask;
InvalidateRect(editor->hWnd, NULL, TRUE);
ME_UpdateRepaint(editor);
if (!(format & SFF_SELECTION)) {
ME_ClearTempStyle(editor);
}
ME_MoveCaret(editor);
ME_SendSelChange(editor);
return 0;
}
ME_DisplayItem *
ME_FindItemAtOffset(ME_TextEditor *editor, ME_DIType nItemType, int nOffset, int *nItemOffset)
{
ME_DisplayItem *item = ME_FindItemFwd(editor->pBuffer->pFirst, diParagraph);
while (item && item->member.para.next_para->member.para.nCharOfs <= nOffset)
item = ME_FindItemFwd(item, diParagraph);
if (!item)
return item;
nOffset -= item->member.para.nCharOfs;
if (nItemType == diParagraph) {
if (nItemOffset)
*nItemOffset = nOffset;
return item;
}
do {
item = ME_FindItemFwd(item, diRun);
} while (item && (item->member.run.nCharOfs + ME_StrLen(item->member.run.strText) <= nOffset));
if (item) {
nOffset -= item->member.run.nCharOfs;
if (nItemOffset)
*nItemOffset = nOffset;
}
return item;
}
ME_TextEditor *ME_MakeEditor(HWND hWnd) {
ME_TextEditor *ed = ALLOC_OBJ(ME_TextEditor);
HDC hDC;
@ -340,7 +632,6 @@ ME_TextEditor *ME_MakeEditor(HWND hWnd) {
ed->pCursors[1].pRun = ME_FindItemFwd(ed->pBuffer->pFirst, diRun);
ed->pCursors[1].nOffset = 0;
ed->nLastTotalLength = ed->nTotalLength = 0;
ed->nScrollPos = 0;
ed->nUDArrowX = -1;
ed->nSequence = 0;
ed->rgbBackColor = -1;
@ -351,6 +642,7 @@ ME_TextEditor *ME_MakeEditor(HWND hWnd) {
ed->nUndoMode = umAddToUndo;
ed->nParagraphs = 1;
ed->nLastSelStart = ed->nLastSelEnd = 0;
ed->nScrollPosY = 0;
for (i=0; i<HFONT_CACHE_SIZE; i++)
{
ed->pFontCache[i].nRefs = 0;
@ -361,6 +653,70 @@ ME_TextEditor *ME_MakeEditor(HWND hWnd) {
return ed;
}
typedef struct tagME_GlobalDestStruct
{
HGLOBAL hData;
int nLength;
} ME_GlobalDestStruct;
static DWORD CALLBACK ME_AppendToHGLOBAL(DWORD_PTR dwCookie, LPBYTE lpBuff, LONG cb, LONG *pcb)
{
ME_GlobalDestStruct *pData = (ME_GlobalDestStruct *)dwCookie;
int nMaxSize;
BYTE *pDest;
nMaxSize = GlobalSize(pData->hData);
if (pData->nLength+cb+1 >= cb)
{
/* round up to 2^17 */
int nNewSize = (((nMaxSize+cb+1)|0x1FFFF)+1) & 0xFFFE0000;
pData->hData = GlobalReAlloc(pData->hData, nNewSize, 0);
}
pDest = (BYTE *)GlobalLock(pData->hData);
memcpy(pDest + pData->nLength, lpBuff, cb);
pData->nLength += cb;
pDest[pData->nLength] = '\0';
GlobalUnlock(pData->hData);
*pcb = cb;
return 0;
}
static DWORD CALLBACK ME_ReadFromHGLOBALUnicode(DWORD_PTR dwCookie, LPBYTE lpBuff, LONG cb, LONG *pcb)
{
ME_GlobalDestStruct *pData = (ME_GlobalDestStruct *)dwCookie;
int i;
WORD *pSrc, *pDest;
cb = cb >> 1;
pDest = (WORD *)lpBuff;
pSrc = (WORD *)GlobalLock(pData->hData);
for (i = 0; i<cb && pSrc[pData->nLength+i]; i++) {
pDest[i] = pSrc[pData->nLength+i];
}
pData->nLength += i;
*pcb = 2*i;
GlobalUnlock(pData->hData);
return 0;
}
static DWORD CALLBACK ME_ReadFromHGLOBALRTF(DWORD_PTR dwCookie, LPBYTE lpBuff, LONG cb, LONG *pcb)
{
ME_GlobalDestStruct *pData = (ME_GlobalDestStruct *)dwCookie;
int i;
BYTE *pSrc, *pDest;
pDest = lpBuff;
pSrc = (BYTE *)GlobalLock(pData->hData);
for (i = 0; i<cb && pSrc[pData->nLength+i]; i++) {
pDest[i] = pSrc[pData->nLength+i];
}
pData->nLength += i;
*pcb = i;
GlobalUnlock(pData->hData);
return 0;
}
void ME_DestroyEditor(ME_TextEditor *editor)
{
ME_DisplayItem *pFirst = editor->pBuffer->pFirst;
@ -401,7 +757,6 @@ LRESULT WINAPI RichEditANSIWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lP
switch(msg) {
UNSUPPORTED_MSG(EM_AUTOURLDETECT)
UNSUPPORTED_MSG(EM_CANPASTE)
UNSUPPORTED_MSG(EM_CHARFROMPOS)
UNSUPPORTED_MSG(EM_DISPLAYBAND)
UNSUPPORTED_MSG(EM_EXLIMITTEXT)
@ -448,9 +803,7 @@ LRESULT WINAPI RichEditANSIWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lP
UNSUPPORTED_MSG(EM_SETUNDOLIMIT)
UNSUPPORTED_MSG(EM_SETWORDBREAKPROC)
UNSUPPORTED_MSG(EM_SETWORDBREAKPROCEX)
UNSUPPORTED_MSG(EM_STREAMOUT)
UNSUPPORTED_MSG(WM_SETFONT)
UNSUPPORTED_MSG(WM_PASTE)
UNSUPPORTED_MSG(WM_STYLECHANGING)
UNSUPPORTED_MSG(WM_STYLECHANGED)
/* UNSUPPORTED_MSG(WM_UNICHAR) FIXME missing in Wine headers */
@ -459,6 +812,8 @@ LRESULT WINAPI RichEditANSIWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lP
case EM_STREAMIN:
return ME_StreamIn(editor, wParam, (EDITSTREAM*)lParam);
case EM_STREAMOUT:
return ME_StreamOut(editor, wParam, (EDITSTREAM *)lParam);
case WM_GETDLGCODE:
{
UINT code = DLGC_WANTCHARS|DLGC_WANTARROWS;
@ -557,6 +912,7 @@ LRESULT WINAPI RichEditANSIWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lP
case EM_SETCHARFORMAT:
{
CHARFORMAT2W buf, *p;
BOOL bRepaint = TRUE;
p = ME_ToCF2W(&buf, (CHARFORMAT2W *)lParam);
if (!wParam)
ME_SetDefaultCharFormat(editor, p);
@ -564,10 +920,15 @@ LRESULT WINAPI RichEditANSIWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lP
FIXME("word selection not supported\n");
else if (wParam == SCF_ALL)
ME_SetCharFormat(editor, 0, ME_GetTextLength(editor), p);
else
else {
int from, to;
ME_GetSelection(editor, &from, &to);
bRepaint = (from != to);
ME_SetSelectionCharFormat(editor, p);
}
ME_CommitUndo(editor);
ME_UpdateRepaint(editor);
if (bRepaint)
ME_UpdateRepaint(editor);
return 0;
}
case EM_GETCHARFORMAT:
@ -583,6 +944,7 @@ LRESULT WINAPI RichEditANSIWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lP
}
case EM_SETPARAFORMAT:
ME_SetSelectionParaFormat(editor, (PARAFORMAT2 *)lParam);
ME_UpdateRepaint(editor);
ME_CommitUndo(editor);
return 0;
case EM_GETPARAFORMAT:
@ -635,12 +997,49 @@ LRESULT WINAPI RichEditANSIWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lP
ME_UpdateRepaint(editor);
return 0;
}
case EM_CANPASTE:
{
UINT nRTFFormat = RegisterClipboardFormatA("Rich Text Format");
if (IsClipboardFormatAvailable(nRTFFormat))
return TRUE;
if (IsClipboardFormatAvailable(CF_UNICODETEXT))
return TRUE;
return FALSE;
}
case WM_PASTE:
{
DWORD dwFormat = 0;
EDITSTREAM es;
ME_GlobalDestStruct gds;
UINT nRTFFormat = RegisterClipboardFormatA("Rich Text Format");
UINT cf = 0;
if (IsClipboardFormatAvailable(nRTFFormat))
cf = nRTFFormat, dwFormat = SF_RTF;
else if (IsClipboardFormatAvailable(CF_UNICODETEXT))
cf = CF_UNICODETEXT, dwFormat = SF_TEXT|SF_UNICODE;
else
return 0;
if (!OpenClipboard(hWnd))
return 0;
gds.hData = GetClipboardData(cf);
gds.nLength = 0;
es.dwCookie = (DWORD)&gds;
es.pfnCallback = dwFormat == SF_RTF ? ME_ReadFromHGLOBALRTF : ME_ReadFromHGLOBALUnicode;
SendMessageW(hWnd, EM_STREAMIN, dwFormat|SFF_SELECTION, (LPARAM)&es);
CloseClipboard();
return 0;
}
case WM_CUT:
case WM_COPY:
{
int from, to, pars;
WCHAR *data;
HANDLE hData;
EDITSTREAM es;
ME_GlobalDestStruct gds;
if (!OpenClipboard(hWnd))
return 0;
@ -652,7 +1051,17 @@ LRESULT WINAPI RichEditANSIWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lP
data = (WCHAR *)GlobalLock(hData);
ME_GetTextW(editor, data, from, to-from, TRUE);
GlobalUnlock(hData);
SetClipboardData(CF_UNICODETEXT, hData);
gds.hData = GlobalAlloc(GMEM_MOVEABLE, 0);
gds.nLength = 0;
es.dwCookie = (DWORD)&gds;
es.pfnCallback = ME_AppendToHGLOBAL;
SendMessageW(hWnd, EM_STREAMOUT, SFF_SELECTION|SF_RTF, (LPARAM)&es);
GlobalReAlloc(gds.hData, gds.nLength+1, 0);
SetClipboardData(CF_UNICODETEXT, hData);
SetClipboardData(RegisterClipboardFormatA("Rich Text Format"), gds.hData);
CloseClipboard();
if (msg == WM_CUT)
{
@ -785,7 +1194,7 @@ LRESULT WINAPI RichEditANSIWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lP
return 0; /* FIXME really 0 ? */
}
wstr = LOWORD(wParam);
if (((unsigned)wstr)>=' ' || wstr=='\r') {
if (((unsigned)wstr)>=' ' || wstr=='\r' || wstr=='\t') {
/* FIXME maybe it would make sense to call EM_REPLACESEL instead ? */
ME_Style *style = ME_GetInsertStyle(editor, 0);
ME_SaveTempStyle(editor);
@ -798,22 +1207,69 @@ LRESULT WINAPI RichEditANSIWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lP
}
case WM_VSCROLL:
{
int nPos = editor->nScrollPosY;
si.cbSize = sizeof(SCROLLINFO);
si.fMask = SIF_PAGE|SIF_POS|SIF_RANGE|SIF_TRACKPOS;
GetScrollInfo(hWnd, SB_VERT, &si);
switch(LOWORD(wParam)) {
case SB_THUMBTRACK:
SetScrollPos(hWnd, SB_VERT, si.nTrackPos, FALSE);
ScrollWindow(hWnd, 0, si.nPos-si.nTrackPos, NULL, NULL);
/* InvalidateRect(hWnd, NULL, TRUE); */
UpdateWindow(hWnd);
case SB_LINEUP:
nPos -= 24; /* FIXME follow the original */
if (nPos<0) nPos = 0;
break;
case SB_LINEDOWN:
{
int nEnd = editor->nTotalLength - editor->sizeWindow.cy;
nPos += 24; /* FIXME follow the original */
if (nPos>=nEnd) nPos = nEnd;
break;
}
case SB_PAGEUP:
nPos -= editor->sizeWindow.cy;
if (nPos<0) nPos = 0;
break;
case SB_PAGEDOWN:
nPos += editor->sizeWindow.cy;
if (nPos>=editor->nTotalLength) nPos = editor->nTotalLength-1;
break;
case SB_THUMBTRACK:
case SB_THUMBPOSITION:
nPos = si.nTrackPos;
break;
}
if (nPos != editor->nScrollPosY) {
ScrollWindow(hWnd, 0, editor->nScrollPosY-nPos, NULL, NULL);
editor->nScrollPosY = nPos;
SetScrollPos(hWnd, SB_VERT, nPos, TRUE);
UpdateWindow(hWnd);
}
break;
}
case WM_MOUSEWHEEL:
{
int gcWheelDelta = 0, nPos = editor->nScrollPosY;
UINT pulScrollLines;
SystemParametersInfoW(SPI_GETWHEELSCROLLLINES,0, &pulScrollLines, 0);
gcWheelDelta -= GET_WHEEL_DELTA_WPARAM(wParam);
if (abs(gcWheelDelta) >= WHEEL_DELTA && pulScrollLines)
nPos += pulScrollLines * (gcWheelDelta / WHEEL_DELTA) * 8;
if(nPos>=editor->nTotalLength)
nPos = editor->nTotalLength - 1;
if (nPos<0)
nPos = 0;
if (nPos != editor->nScrollPosY) {
ScrollWindow(hWnd, 0, editor->nScrollPosY-nPos, NULL, NULL);
editor->nScrollPosY = nPos;
SetScrollPos(hWnd, SB_VERT, nPos, TRUE);
UpdateWindow(hWnd);
}
break;
}
case WM_SIZE:
{
ME_MarkAllForWrapping(editor);
ME_WrapMarkedParagraphs(editor);
ME_UpdateScrollBar(editor);
ME_Repaint(editor);
return DefWindowProcW(hWnd, msg, wParam, lParam);
}
@ -861,26 +1317,18 @@ int ME_CountParagraphsBetween(ME_TextEditor *editor, int from, int to)
return i;
}
int ME_GetTextW(ME_TextEditor *editor, WCHAR *buffer, int nStart, int nChars, int bCRLF)
{
ME_DisplayItem *item = ME_FindItemFwd(editor->pBuffer->pFirst, diParagraph);
ME_DisplayItem *item = ME_FindItemAtOffset(editor, diRun, nStart, &nStart);
int nWritten = 0;
while(item && item->member.para.next_para->member.para.nCharOfs <= nStart)
item = ME_FindItemFwd(item, diParagraph);
if (!item) {
*buffer = L'\0';
return 0;
}
nStart -= item->member.para.nCharOfs;
do {
item = ME_FindItemFwd(item, diRun);
} while(item && (item->member.run.nCharOfs + ME_StrLen(item->member.run.strText) <= nStart));
assert(item);
nStart -= item->member.run.nCharOfs;
if (nStart)
{
int nLen = ME_StrLen(item->member.run.strText) - nStart;

View file

@ -20,8 +20,8 @@
#include "editstr.h"
#define ALLOC_OBJ(type) (type *)HeapAlloc(me_heap, 0, sizeof(type))
#define ALLOC_N_OBJ(type, count) (type *)HeapAlloc(me_heap, 0, count*sizeof(type))
#define ALLOC_OBJ(type) HeapAlloc(me_heap, 0, sizeof(type))
#define ALLOC_N_OBJ(type, count) HeapAlloc(me_heap, 0, (count)*sizeof(type))
#define FREE_OBJ(ptr) HeapFree(me_heap, 0, ptr)
/* style.c */
@ -85,6 +85,10 @@ void ME_EndToUnicode(HWND hWnd, LPVOID psz);
LPSTR ME_ToAnsi(HWND hWnd, LPVOID psz);
void ME_EndToAnsi(HWND hWnd, LPVOID psz);
static inline int ME_IsWSpace(WCHAR ch)
{
return ch > '\0' && ch <= ' ';
}
/* note: those two really return the first matching offset (starting from EOS)+1
* in other words, an offset of the first trailing white/black */
@ -104,7 +108,7 @@ ME_DisplayItem *ME_InsertRun(ME_TextEditor *editor, int nCharOfs, ME_DisplayItem
void ME_CheckCharOffsets(ME_TextEditor *editor);
void ME_PropagateCharOffset(ME_DisplayItem *p, int shift);
void ME_GetGraphicsSize(ME_TextEditor *editor, ME_Run *run, SIZE *pSize);
int ME_CharFromPoint(ME_TextEditor *editor, int cx, ME_Run *run);
int ME_CharFromPoint(ME_TextEditor *editor, int cx, ME_Paragraph *para, ME_Run *run);
/* this one accounts for 1/2 char tolerance */
int ME_CharFromPointCursor(ME_TextEditor *editor, int cx, ME_Run *run);
int ME_PointFromChar(ME_TextEditor *editor, ME_Run *pRun, int nOffset);
@ -116,8 +120,8 @@ ME_DisplayItem *ME_SplitRunSimple(ME_TextEditor *editor, ME_DisplayItem *item, i
int ME_FindSplitPoint(ME_Context *c, POINT *pt, ME_Run *run, int desperate);
void ME_UpdateRunFlags(ME_TextEditor *editor, ME_Run *run);
ME_DisplayItem *ME_SplitFurther(ME_TextEditor *editor, ME_DisplayItem *run);
void ME_CalcRunExtent(ME_Context *c, ME_Run *run);
SIZE ME_GetRunSize(ME_Context *c, ME_Run *run, int nLen);
void ME_CalcRunExtent(ME_Context *c, ME_Paragraph *para, ME_Run *run);
SIZE ME_GetRunSize(ME_Context *c, ME_Paragraph *para, ME_Run *run, int nLen);
void ME_CursorFromCharOfs(ME_TextEditor *editor, int nCharOfs, ME_Cursor *pCursor);
void ME_RunOfsFromCharOfs(ME_TextEditor *editor, int nCharOfs, ME_DisplayItem **ppRun, int *pOfs);
int ME_CharOfsFromRunOfs(ME_TextEditor *editor, ME_DisplayItem *pRun, int nOfs);
@ -157,13 +161,14 @@ void ME_InsertGraphicsFromCursor(ME_TextEditor *editor, int nCursor);
void ME_InternalDeleteText(ME_TextEditor *editor, int nOfs, int nChars);
int ME_GetTextLength(ME_TextEditor *editor);
ME_Style *ME_GetSelectionInsertStyle(ME_TextEditor *editor);
BOOL ME_UpdateSelection(ME_TextEditor *editor, ME_Cursor *pTempCursor);
/* wrap.c */
void ME_PrepareParagraphForWrapping(ME_Context *c, ME_DisplayItem *tp);
ME_DisplayItem *ME_MakeRow(int height, int baseline, int width);
void ME_InsertRowStart(ME_WrapContext *wc, ME_DisplayItem *pEnd);
void ME_WrapTextParagraph(ME_Context *c, ME_DisplayItem *tp);
void ME_WrapMarkedParagraphs(ME_TextEditor *editor);
BOOL ME_WrapMarkedParagraphs(ME_TextEditor *editor);
/* para.c */
ME_DisplayItem *ME_GetParagraph(ME_DisplayItem *run);
@ -185,10 +190,11 @@ void ME_PaintContent(ME_TextEditor *editor, HDC hDC, BOOL bOnlyNew, RECT *rcUpda
void ME_Repaint(ME_TextEditor *editor);
void ME_UpdateRepaint(ME_TextEditor *editor);
void ME_DrawParagraph(ME_Context *c, ME_DisplayItem *paragraph);
void ME_UpdateScrollBar(ME_TextEditor *editor, int ypos);
int ME_GetScrollPos(ME_TextEditor *editor);
void ME_UpdateScrollBar(ME_TextEditor *editor);
int ME_GetYScrollPos(ME_TextEditor *editor);
void ME_EnsureVisible(ME_TextEditor *editor, ME_DisplayItem *pRun);
COLORREF ME_GetBackColor(ME_TextEditor *editor);
void ME_Scroll(ME_TextEditor *editor, int cx, int cy);
/* richole.c */
extern LRESULT CreateIRichEditOle(LPVOID *);
@ -206,7 +212,12 @@ void ME_Undo(ME_TextEditor *editor);
void ME_Redo(ME_TextEditor *editor);
void ME_EmptyUndoStack(ME_TextEditor *editor);
int ME_GetTextW(ME_TextEditor *editor, WCHAR *buffer, int nStart, int nChars, BOOL bCRLF);
ME_DisplayItem *ME_FindItemAtOffset(ME_TextEditor *editor, ME_DIType nItemType, int nOffset, int *nItemOffset);
void ME_StreamInFill(ME_InStream *stream);
extern int me_debug;
extern HANDLE me_heap;
extern void DoWrap(ME_TextEditor *editor);
/* writer.c */
LRESULT ME_StreamOut(ME_TextEditor *editor, DWORD dwFormat, EDITSTREAM *stream);

View file

@ -86,6 +86,8 @@ typedef enum {
#define MERF_STYLEFLAGS 0x0FFF
/* run contains non-text content, which has its own rules for wrapping, sizing etc */
#define MERF_GRAPHICS 1
/* run is a tab (or, in future, any kind of content whose size is dependent on run position) */
#define MERF_TAB 2
/* run is splittable (contains white spaces in the middle or end) */
#define MERF_SPLITTABLE 0x001000
@ -102,6 +104,11 @@ typedef enum {
/* the "end of paragraph" run, contains 1 character */
#define MERF_ENDPARA 0x100000
/* runs with any of these flags set cannot be joined */
#define MERF_NOJOIN (MERF_GRAPHICS|MERF_TAB|MERF_ENDPARA)
/* runs that don't contain real text */
#define MERF_NOTEXT (MERF_GRAPHICS|MERF_TAB|MERF_ENDPARA)
/* those flags are kept when the row is split */
#define MERF_SPLITMASK (~(0))
@ -192,6 +199,40 @@ typedef enum {
umAddBackToUndo
} ME_UndoMode;
typedef struct tagME_FontTableItem {
BYTE bCharSet;
WCHAR *szFaceName;
} ME_FontTableItem;
#define STREAMIN_BUFFER_SIZE 4096 /* M$ compatibility */
struct tagME_InStream {
EDITSTREAM *editstream;
DWORD dwSize;
DWORD dwUsed;
BYTE buffer[STREAMIN_BUFFER_SIZE];
};
typedef struct tagME_InStream ME_InStream;
#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;
} ME_OutStream;
typedef struct tagME_FontCacheItem
{
LOGFONTW lfSpecs;
@ -210,7 +251,6 @@ typedef struct tagME_TextEditor
ME_Cursor *pCursors;
int nCursors;
SIZE sizeWindow;
int nScrollPos;
int nTotalLength, nLastTotalLength;
int nUDArrowX;
int nSequence;
@ -224,6 +264,9 @@ typedef struct tagME_TextEditor
int nParagraphs;
int nLastSelStart, nLastSelEnd;
ME_FontCacheItem pFontCache[HFONT_CACHE_SIZE];
ME_OutStream *pStream;
BOOL bScrollX, bScrollY;
int nScrollPosY;
} ME_TextEditor;
typedef struct tagME_Context

View file

@ -28,14 +28,16 @@ void ME_PaintContent(ME_TextEditor *editor, HDC hDC, BOOL bOnlyNew, RECT *rcUpda
int yoffset;
editor->nSequence++;
yoffset = GetScrollPos(editor->hWnd, SB_VERT);
yoffset = ME_GetYScrollPos(editor);
ME_InitContext(&c, editor, hDC);
SetBkMode(hDC, TRANSPARENT);
ME_MoveCaret(editor);
item = editor->pBuffer->pFirst->next;
c.pt.y -= yoffset;
while(item != editor->pBuffer->pLast) {
int ye;
assert(item->type == diParagraph);
ye = c.pt.y + item->member.para.nHeight;
if (!bOnlyNew || (item->member.para.nFlags & MEPF_REPAINT))
{
BOOL bPaint = (rcUpdate == NULL);
@ -45,10 +47,11 @@ void ME_PaintContent(ME_TextEditor *editor, HDC hDC, BOOL bOnlyNew, RECT *rcUpda
if (bPaint)
{
ME_DrawParagraph(&c, item);
item->member.para.nFlags &= ~MEPF_REPAINT;
if (!rcUpdate || (rcUpdate->top<=c.pt.y && rcUpdate->bottom>=ye))
item->member.para.nFlags &= ~MEPF_REPAINT;
}
}
c.pt.y += item->member.para.nHeight;
c.pt.y = ye;
item = item->member.para.next_para;
}
if (c.pt.y<c.rcView.bottom) {
@ -146,18 +149,21 @@ void ME_Repaint(ME_TextEditor *editor)
ME_DisplayItem *pRun = NULL;
int nOffset = -1;
HDC hDC;
int nCharOfs = ME_CharOfsFromRunOfs(editor, pCursor->pRun, pCursor->nOffset);
ME_RunOfsFromCharOfs(editor, nCharOfs, &pRun, &nOffset);
assert(pRun == pCursor->pRun);
assert(nOffset == pCursor->nOffset);
ME_MarkSelectionForRepaint(editor);
ME_WrapMarkedParagraphs(editor);
if (ME_WrapMarkedParagraphs(editor)) {
ME_UpdateScrollBar(editor);
}
hDC = GetDC(editor->hWnd);
ME_HideCaret(editor);
ME_PaintContent(editor, hDC, TRUE, NULL);
ReleaseDC(editor->hWnd, hDC);
ME_ShowCaret(editor);
ME_EnsureVisible(editor, pCursor->pRun);
}
void ME_UpdateRepaint(ME_TextEditor *editor)
@ -244,6 +250,9 @@ void ME_DrawRun(ME_Context *c, int x, int y, ME_DisplayItem *rundi, ME_Paragraph
ME_Run *run = &rundi->member.run;
int runofs = run->nCharOfs+para->nCharOfs;
/* you can always comment it out if you need visible paragraph marks */
if (run->nFlags & (MERF_ENDPARA|MERF_TAB))
return;
if (run->nFlags & MERF_GRAPHICS) {
int blfrom, blto;
ME_GetSelection(c->editor, &blfrom, &blto);
@ -302,19 +311,19 @@ void ME_DrawParagraph(ME_Context *c, ME_DisplayItem *paragraph) {
visible = RectVisible(c->hDC, &rcPara);
if (visible) {
HBRUSH hbr;
hbr = CreateSolidBrush(ME_GetBackColor(c->editor));
/* left margin */
rc.left = c->rcView.left;
rc.right = c->rcView.left+nMargWidth;
rc.top = y;
rc.bottom = y+p->member.row.nHeight;
FillRect(c->hDC, &rc, c->hbrMargin);
FillRect(c->hDC, &rc, hbr/* c->hbrMargin */);
/* right margin */
rc.left = xe;
rc.right = c->rcView.right;
FillRect(c->hDC, &rc, c->hbrMargin);
rc.left = c->rcView.left+para->nLeftMargin;
FillRect(c->hDC, &rc, hbr/* c->hbrMargin */);
rc.left = c->rcView.left+nMargWidth;
rc.right = xe;
hbr = CreateSolidBrush(ME_GetBackColor(c->editor));
FillRect(c->hDC, &rc, hbr);
DeleteObject(hbr);
}
@ -369,62 +378,103 @@ void ME_DrawParagraph(ME_Context *c, ME_DisplayItem *paragraph) {
SetTextAlign(c->hDC, align);
}
void ME_UpdateScrollBar(ME_TextEditor *editor, int ypos)
void ME_Scroll(ME_TextEditor *editor, int cx, int cy)
{
float perc = 0.0;
SCROLLINFO si;
HWND hWnd = editor->hWnd;
int overflow = editor->nTotalLength - editor->sizeWindow.cy;
si.cbSize = sizeof(SCROLLINFO);
si.fMask = SIF_PAGE|SIF_POS|SIF_RANGE|SIF_TRACKPOS;
GetScrollInfo(hWnd, SB_VERT, &si);
if (ypos < 0) {
if (si.nMax<1) si.nMax = 1;
perc = 1.0*si.nPos/si.nMax;
ypos = perc*overflow;
}
if (ypos >= overflow && overflow > 0)
ypos = overflow - 1;
if (overflow > 0) {
EnableScrollBar(hWnd, SB_VERT, ESB_ENABLE_BOTH);
SetScrollRange(hWnd, SB_VERT, 0, overflow, FALSE);
SetScrollPos(hWnd, SB_VERT, ypos, TRUE);
} else {
EnableScrollBar(hWnd, SB_VERT, ESB_DISABLE_BOTH);
SetScrollRange(hWnd, SB_VERT, 0, 0, FALSE);
SetScrollPos(hWnd, SB_VERT, 0, TRUE);
}
if (ypos != si.nPos)
si.cbSize = sizeof(SCROLLINFO);
si.fMask = SIF_POS;
GetScrollInfo(hWnd, SB_VERT, &si);
si.nPos = editor->nScrollPosY -= cy;
SetScrollInfo(hWnd, SB_VERT, &si, TRUE);
if (abs(cy) > editor->sizeWindow.cy)
InvalidateRect(editor->hWnd, NULL, TRUE);
else
ScrollWindowEx(hWnd, cx, cy, NULL, NULL, NULL, NULL, SW_ERASE|SW_INVALIDATE);
}
void ME_UpdateScrollBar(ME_TextEditor *editor)
{
HWND hWnd = editor->hWnd;
SCROLLINFO si;
int nOldLen = editor->nTotalLength;
BOOL bScrollY = (editor->nTotalLength > editor->sizeWindow.cy);
BOOL bUpdateScrollBars;
si.cbSize = sizeof(si);
si.fMask = SIF_POS | SIF_RANGE;
GetScrollInfo(hWnd, SB_VERT, &si);
bUpdateScrollBars = (bScrollY || editor->bScrollY)&& ((si.nMax != nOldLen) || (si.nPage != editor->sizeWindow.cy));
if (bScrollY != editor->bScrollY)
{
TRACE("ScrollWindow(%d, %d, %d, %0.4f)\n", si.nPos, si.nMax, ypos, perc);
ScrollWindow(hWnd, 0, si.nPos - ypos, NULL, NULL);
UpdateWindow(hWnd);
si.fMask = SIF_RANGE | SIF_PAGE;
si.nMin = 0;
si.nPage = editor->sizeWindow.cy;
if (bScrollY) {
si.nMax = editor->nTotalLength;
} else {
si.nMax = 0;
}
SetScrollInfo(hWnd, SB_VERT, &si, FALSE);
ME_MarkAllForWrapping(editor);
editor->bScrollY = bScrollY;
ME_WrapMarkedParagraphs(editor);
bUpdateScrollBars = TRUE;
}
if (bUpdateScrollBars) {
int nScroll = 0;
si.fMask = SIF_PAGE | SIF_RANGE | SIF_POS;
if (editor->nTotalLength > editor->sizeWindow.cy) {
si.nMax = editor->nTotalLength;
si.nPage = editor->sizeWindow.cy;
if (si.nPos > si.nMax-si.nPage) {
nScroll = (si.nMax-si.nPage)-si.nPos;
si.nPos = si.nMax-si.nPage;
}
}
else {
si.nMax = 0;
si.nPage = 0;
si.nPos = 0;
}
TRACE("min=%d max=%d page=%d pos=%d shift=%d\n", si.nMin, si.nMax, si.nPage, si.nPos, nScroll);
editor->nScrollPosY = si.nPos;
SetScrollInfo(hWnd, SB_VERT, &si, TRUE);
if (nScroll)
ScrollWindow(hWnd, 0, -nScroll, NULL, NULL);
}
}
int ME_GetScrollPos(ME_TextEditor *editor)
int ME_GetYScrollPos(ME_TextEditor *editor)
{
return GetScrollPos(editor->hWnd, SB_VERT);
return editor->nScrollPosY;
}
void ME_EnsureVisible(ME_TextEditor *editor, ME_DisplayItem *pRun)
{
ME_DisplayItem *pRow = ME_FindItemBack(pRun, diStartRow);
ME_DisplayItem *pPara = ME_FindItemBack(pRun, diParagraph);
int y, yrel, yheight;
int y, yrel, yheight, yold;
HWND hWnd = editor->hWnd;
assert(pRow);
assert(pPara);
y = pPara->member.para.nYPos+pRow->member.row.nYPos;
yheight = pRow->member.row.nHeight;
yrel = y - ME_GetScrollPos(editor);
if (yrel < 0)
ME_UpdateScrollBar(editor, y);
else if (yrel + yheight > editor->sizeWindow.cy)
{
ME_UpdateScrollBar(editor, y + yheight - editor->sizeWindow.cy);
yold = ME_GetYScrollPos(editor);
yrel = y - yold;
if (yrel < 0) {
editor->nScrollPosY = y;
SetScrollPos(hWnd, SB_VERT, y, TRUE);
ScrollWindow(hWnd, 0, -yrel, NULL, NULL);
UpdateWindow(hWnd);
} else if (yrel + yheight > editor->sizeWindow.cy) {
int newy = y+yheight-editor->sizeWindow.cy;
editor->nScrollPosY = newy;
SetScrollPos(hWnd, SB_VERT, newy, TRUE);
ScrollWindow(hWnd, 0, -(newy-yold), NULL, NULL);
UpdateWindow(hWnd);
}
}

View file

@ -57,7 +57,7 @@ void ME_MakeFirstParagraph(HDC hDC, ME_TextBuffer *text)
ZeroMemory(&fmt, sizeof(fmt));
fmt.cbSize = sizeof(fmt);
fmt.dwMask = PFM_ALIGNMENT | PFM_OFFSET | PFM_STARTINDENT | PFM_RIGHTINDENT;
fmt.dwMask = PFM_ALIGNMENT | PFM_OFFSET | PFM_STARTINDENT | PFM_RIGHTINDENT | PFM_TABSTOPS;
CopyMemory(para->member.para.pFmt, &fmt, sizeof(PARAFORMAT2));
@ -282,6 +282,18 @@ void ME_SetParaFormat(ME_TextEditor *editor, ME_DisplayItem *para, PARAFORMAT2 *
if (pFmt->dwMask & PFM_ALIGNMENT)
para->member.para.pFmt->wAlignment = pFmt->wAlignment;
if (pFmt->dwMask & PFM_STARTINDENT)
para->member.para.pFmt->dxStartIndent = pFmt->dxStartIndent;
if (pFmt->dwMask & PFM_OFFSET)
para->member.para.pFmt->dxOffset = pFmt->dxOffset;
if (pFmt->dwMask & PFM_OFFSETINDENT)
para->member.para.pFmt->dxStartIndent += pFmt->dxStartIndent;
if (pFmt->dwMask & PFM_TABSTOPS)
{
para->member.para.pFmt->cTabCount = pFmt->cTabCount;
memcpy(para->member.para.pFmt->rgxTabs, pFmt->rgxTabs, pFmt->cTabCount*sizeof(int));
}
/* FIXME to be continued (indents, bulleting and such) */
@ -310,7 +322,6 @@ void ME_SetSelectionParaFormat(ME_TextEditor *editor, PARAFORMAT2 *pFmt)
break;
para = para->member.para.next_para;
} while(1);
ME_Repaint(editor);
}
void ME_GetParaFormat(ME_TextEditor *editor, ME_DisplayItem *para, PARAFORMAT2 *pFmt)
@ -346,11 +357,28 @@ void ME_GetSelectionParaFormat(ME_TextEditor *editor, PARAFORMAT2 *pFmt)
ZeroMemory(&tmp, sizeof(tmp));
tmp.cbSize = sizeof(tmp);
ME_GetParaFormat(editor, para, &tmp);
assert(tmp.dwMask & PFM_ALIGNMENT);
assert(tmp.dwMask & PFM_ALIGNMENT);
if (pFmt->wAlignment != tmp.wAlignment)
pFmt->dwMask &= ~PFM_ALIGNMENT;
assert(tmp.dwMask & PFM_STARTINDENT);
if (pFmt->dxStartIndent != tmp.dxStartIndent)
pFmt->dwMask &= ~PFM_STARTINDENT;
assert(tmp.dwMask & PFM_OFFSET);
if (pFmt->dxOffset != tmp.dxOffset)
pFmt->dwMask &= ~PFM_OFFSET;
assert(tmp.dwMask & PFM_TABSTOPS);
if (pFmt->dwMask & PFM_TABSTOPS) {
if (pFmt->cTabCount != tmp.cTabCount)
pFmt->dwMask &= ~PFM_TABSTOPS;
else
if (memcmp(pFmt->rgxTabs, tmp.rgxTabs, tmp.cTabCount*sizeof(int)))
pFmt->dwMask &= ~PFM_TABSTOPS;
}
if (para == para_end)
return;
para = para->member.para.next_para;

File diff suppressed because it is too large Load diff

View file

@ -64,6 +64,7 @@ IRichEditOle_fnQueryInterface(IRichEditOle *me, REFIID riid, LPVOID *ppvObj)
*ppvObj = (LPVOID) This;
return S_OK;
}
FIXME("%p: unhandled interface %s\n", This, debugstr_guid(riid) );
return E_NOINTERFACE;
}
@ -215,7 +216,7 @@ static HRESULT WINAPI IRichEditOle_fnSetHostNames(IRichEditOle *me,
LPCSTR lpstrContainerApp, LPCSTR lpstrContainerObj)
{
IRichEditOleImpl *This = (IRichEditOleImpl *)me;
FIXME("stub %p\n",This);
FIXME("stub %p %s %s\n",This, lpstrContainerApp, lpstrContainerObj);
return E_NOTIMPL;
}

View file

@ -11,365 +11,6 @@
#include "richedit.h"
/* The following defines are automatically generated. Do not edit. */
/* These must be sequential beginning from zero */
#define rtfSC_nothing 0
#define rtfSC_space 1
#define rtfSC_exclam 2
#define rtfSC_quotedbl 3
#define rtfSC_numbersign 4
#define rtfSC_dollar 5
#define rtfSC_percent 6
#define rtfSC_ampersand 7
#define rtfSC_quoteright 8
#define rtfSC_parenleft 9
#define rtfSC_parenright 10
#define rtfSC_asterisk 11
#define rtfSC_plus 12
#define rtfSC_comma 13
#define rtfSC_hyphen 14
#define rtfSC_period 15
#define rtfSC_slash 16
#define rtfSC_zero 17
#define rtfSC_one 18
#define rtfSC_two 19
#define rtfSC_three 20
#define rtfSC_four 21
#define rtfSC_five 22
#define rtfSC_six 23
#define rtfSC_seven 24
#define rtfSC_eight 25
#define rtfSC_nine 26
#define rtfSC_colon 27
#define rtfSC_semicolon 28
#define rtfSC_less 29
#define rtfSC_equal 30
#define rtfSC_greater 31
#define rtfSC_question 32
#define rtfSC_at 33
#define rtfSC_A 34
#define rtfSC_B 35
#define rtfSC_C 36
#define rtfSC_D 37
#define rtfSC_E 38
#define rtfSC_F 39
#define rtfSC_G 40
#define rtfSC_H 41
#define rtfSC_I 42
#define rtfSC_J 43
#define rtfSC_K 44
#define rtfSC_L 45
#define rtfSC_M 46
#define rtfSC_N 47
#define rtfSC_O 48
#define rtfSC_P 49
#define rtfSC_Q 50
#define rtfSC_R 51
#define rtfSC_S 52
#define rtfSC_T 53
#define rtfSC_U 54
#define rtfSC_V 55
#define rtfSC_W 56
#define rtfSC_X 57
#define rtfSC_Y 58
#define rtfSC_Z 59
#define rtfSC_bracketleft 60
#define rtfSC_backslash 61
#define rtfSC_bracketright 62
#define rtfSC_asciicircum 63
#define rtfSC_underscore 64
#define rtfSC_quoteleft 65
#define rtfSC_a 66
#define rtfSC_b 67
#define rtfSC_c 68
#define rtfSC_d 69
#define rtfSC_e 70
#define rtfSC_f 71
#define rtfSC_g 72
#define rtfSC_h 73
#define rtfSC_i 74
#define rtfSC_j 75
#define rtfSC_k 76
#define rtfSC_l 77
#define rtfSC_m 78
#define rtfSC_n 79
#define rtfSC_o 80
#define rtfSC_p 81
#define rtfSC_q 82
#define rtfSC_r 83
#define rtfSC_s 84
#define rtfSC_t 85
#define rtfSC_u 86
#define rtfSC_v 87
#define rtfSC_w 88
#define rtfSC_x 89
#define rtfSC_y 90
#define rtfSC_z 91
#define rtfSC_braceleft 92
#define rtfSC_bar 93
#define rtfSC_braceright 94
#define rtfSC_asciitilde 95
#define rtfSC_exclamdown 96
#define rtfSC_cent 97
#define rtfSC_sterling 98
#define rtfSC_fraction 99
#define rtfSC_yen 100
#define rtfSC_florin 101
#define rtfSC_section 102
#define rtfSC_currency 103
#define rtfSC_quotedblleft 104
#define rtfSC_guillemotleft 105
#define rtfSC_guilsinglleft 106
#define rtfSC_guilsinglright 107
#define rtfSC_fi 108
#define rtfSC_fl 109
#define rtfSC_endash 110
#define rtfSC_dagger 111
#define rtfSC_daggerdbl 112
#define rtfSC_periodcentered 113
#define rtfSC_paragraph 114
#define rtfSC_bullet 115
#define rtfSC_quotesinglbase 116
#define rtfSC_quotedblbase 117
#define rtfSC_quotedblright 118
#define rtfSC_guillemotright 119
#define rtfSC_ellipsis 120
#define rtfSC_perthousand 121
#define rtfSC_questiondown 122
#define rtfSC_grave 123
#define rtfSC_acute 124
#define rtfSC_circumflex 125
#define rtfSC_tilde 126
#define rtfSC_macron 127
#define rtfSC_breve 128
#define rtfSC_dotaccent 129
#define rtfSC_dieresis 130
#define rtfSC_ring 131
#define rtfSC_cedilla 132
#define rtfSC_hungarumlaut 133
#define rtfSC_ogonek 134
#define rtfSC_caron 135
#define rtfSC_emdash 136
#define rtfSC_AE 137
#define rtfSC_ordfeminine 138
#define rtfSC_Lslash 139
#define rtfSC_Oslash 140
#define rtfSC_OE 141
#define rtfSC_ordmasculine 142
#define rtfSC_ae 143
#define rtfSC_dotlessi 144
#define rtfSC_lslash 145
#define rtfSC_oslash 146
#define rtfSC_oe 147
#define rtfSC_germandbls 148
#define rtfSC_Aacute 149
#define rtfSC_Acircumflex 150
#define rtfSC_Adieresis 151
#define rtfSC_Agrave 152
#define rtfSC_Aring 153
#define rtfSC_Atilde 154
#define rtfSC_Ccedilla 155
#define rtfSC_Eacute 156
#define rtfSC_Ecircumflex 157
#define rtfSC_Edieresis 158
#define rtfSC_Egrave 159
#define rtfSC_Eth 160
#define rtfSC_Iacute 161
#define rtfSC_Icircumflex 162
#define rtfSC_Idieresis 163
#define rtfSC_Igrave 164
#define rtfSC_Ntilde 165
#define rtfSC_Oacute 166
#define rtfSC_Ocircumflex 167
#define rtfSC_Odieresis 168
#define rtfSC_Ograve 169
#define rtfSC_Otilde 170
#define rtfSC_Scaron 171
#define rtfSC_Thorn 172
#define rtfSC_Uacute 173
#define rtfSC_Ucircumflex 174
#define rtfSC_Udieresis 175
#define rtfSC_Ugrave 176
#define rtfSC_Yacute 177
#define rtfSC_Ydieresis 178
#define rtfSC_aacute 179
#define rtfSC_acircumflex 180
#define rtfSC_adieresis 181
#define rtfSC_agrave 182
#define rtfSC_aring 183
#define rtfSC_atilde 184
#define rtfSC_brokenbar 185
#define rtfSC_ccedilla 186
#define rtfSC_copyright 187
#define rtfSC_degree 188
#define rtfSC_divide 189
#define rtfSC_eacute 190
#define rtfSC_ecircumflex 191
#define rtfSC_edieresis 192
#define rtfSC_egrave 193
#define rtfSC_eth 194
#define rtfSC_iacute 195
#define rtfSC_icircumflex 196
#define rtfSC_idieresis 197
#define rtfSC_igrave 198
#define rtfSC_logicalnot 199
#define rtfSC_minus 200
#define rtfSC_multiply 201
#define rtfSC_ntilde 202
#define rtfSC_oacute 203
#define rtfSC_ocircumflex 204
#define rtfSC_odieresis 205
#define rtfSC_ograve 206
#define rtfSC_onehalf 207
#define rtfSC_onequarter 208
#define rtfSC_onesuperior 209
#define rtfSC_otilde 210
#define rtfSC_plusminus 211
#define rtfSC_registered 212
#define rtfSC_thorn 213
#define rtfSC_threequarters 214
#define rtfSC_threesuperior 215
#define rtfSC_trademark 216
#define rtfSC_twosuperior 217
#define rtfSC_uacute 218
#define rtfSC_ucircumflex 219
#define rtfSC_udieresis 220
#define rtfSC_ugrave 221
#define rtfSC_yacute 222
#define rtfSC_ydieresis 223
#define rtfSC_Alpha 224
#define rtfSC_Beta 225
#define rtfSC_Chi 226
#define rtfSC_Delta 227
#define rtfSC_Epsilon 228
#define rtfSC_Phi 229
#define rtfSC_Gamma 230
#define rtfSC_Eta 231
#define rtfSC_Iota 232
#define rtfSC_Kappa 233
#define rtfSC_Lambda 234
#define rtfSC_Mu 235
#define rtfSC_Nu 236
#define rtfSC_Omicron 237
#define rtfSC_Pi 238
#define rtfSC_Theta 239
#define rtfSC_Rho 240
#define rtfSC_Sigma 241
#define rtfSC_Tau 242
#define rtfSC_Upsilon 243
#define rtfSC_varUpsilon 244
#define rtfSC_Omega 245
#define rtfSC_Xi 246
#define rtfSC_Psi 247
#define rtfSC_Zeta 248
#define rtfSC_alpha 249
#define rtfSC_beta 250
#define rtfSC_chi 251
#define rtfSC_delta 252
#define rtfSC_epsilon 253
#define rtfSC_phi 254
#define rtfSC_varphi 255
#define rtfSC_gamma 256
#define rtfSC_eta 257
#define rtfSC_iota 258
#define rtfSC_kappa 259
#define rtfSC_lambda 260
#define rtfSC_mu 261
#define rtfSC_nu 262
#define rtfSC_omicron 263
#define rtfSC_pi 264
#define rtfSC_varpi 265
#define rtfSC_theta 266
#define rtfSC_vartheta 267
#define rtfSC_rho 268
#define rtfSC_sigma 269
#define rtfSC_varsigma 270
#define rtfSC_tau 271
#define rtfSC_upsilon 272
#define rtfSC_omega 273
#define rtfSC_xi 274
#define rtfSC_psi 275
#define rtfSC_zeta 276
#define rtfSC_nobrkspace 277
#define rtfSC_nobrkhyphen 278
#define rtfSC_lessequal 279
#define rtfSC_greaterequal 280
#define rtfSC_infinity 281
#define rtfSC_integral 282
#define rtfSC_notequal 283
#define rtfSC_radical 284
#define rtfSC_radicalex 285
#define rtfSC_approxequal 286
#define rtfSC_apple 287
#define rtfSC_partialdiff 288
#define rtfSC_opthyphen 289
#define rtfSC_formula 290
#define rtfSC_lozenge 291
#define rtfSC_universal 292
#define rtfSC_existential 293
#define rtfSC_suchthat 294
#define rtfSC_congruent 295
#define rtfSC_therefore 296
#define rtfSC_perpendicular 297
#define rtfSC_minute 298
#define rtfSC_club 299
#define rtfSC_diamond 300
#define rtfSC_heart 301
#define rtfSC_spade 302
#define rtfSC_arrowboth 303
#define rtfSC_arrowleft 304
#define rtfSC_arrowup 305
#define rtfSC_arrowright 306
#define rtfSC_arrowdown 307
#define rtfSC_second 308
#define rtfSC_proportional 309
#define rtfSC_equivalence 310
#define rtfSC_arrowvertex 311
#define rtfSC_arrowhorizex 312
#define rtfSC_carriagereturn 313
#define rtfSC_aleph 314
#define rtfSC_Ifraktur 315
#define rtfSC_Rfraktur 316
#define rtfSC_weierstrass 317
#define rtfSC_circlemultiply 318
#define rtfSC_circleplus 319
#define rtfSC_emptyset 320
#define rtfSC_intersection 321
#define rtfSC_union 322
#define rtfSC_propersuperset 323
#define rtfSC_reflexsuperset 324
#define rtfSC_notsubset 325
#define rtfSC_propersubset 326
#define rtfSC_reflexsubset 327
#define rtfSC_element 328
#define rtfSC_notelement 329
#define rtfSC_angle 330
#define rtfSC_gradient 331
#define rtfSC_product 332
#define rtfSC_logicaland 333
#define rtfSC_logicalor 334
#define rtfSC_arrowdblboth 335
#define rtfSC_arrowdblleft 336
#define rtfSC_arrowdblup 337
#define rtfSC_arrowdblright 338
#define rtfSC_arrowdbldown 339
#define rtfSC_angleleft 340
#define rtfSC_registersans 341
#define rtfSC_copyrightsans 342
#define rtfSC_trademarksans 343
#define rtfSC_angleright 344
#define rtfSC_mathplus 345
#define rtfSC_mathminus 346
#define rtfSC_mathasterisk 347
#define rtfSC_mathnumbersign 348
#define rtfSC_dotmath 349
#define rtfSC_mathequal 350
#define rtfSC_mathtilde 351
#define rtfSC_MaxChar 352
/*
* rtf.h - RTF document processing stuff. Release 1.10.
*/
@ -418,13 +59,7 @@
*/
# ifdef THINK_C
# define rtfNoParam (-32768) /* 16-bit max. neg. value */
# endif
# ifndef rtfNoParam
# define rtfNoParam (-1000000)
# endif
@ -546,7 +181,8 @@
# define rtfIndexRange 71
# define rtfTOC 72
# define rtfNeXTGraphic 73
# define rtfMaxDestination 74 /* highest dest + 1 */
# define rtfGenerator 74
# define rtfMaxDestination 75 /* highest dest + 1 */
# define rtfFontFamily 4
# define rtfFFNil 0
@ -624,6 +260,7 @@
# define rtfNoWidthNonJoiner 56 /* new in 1.10 */
# define rtfCurHeadPict 57 /* valid? */
/*# define rtfCurAnnot 58*/ /* apparently not used */
# define rtfUnicode 58 /* no better category*/
# define rtfStyleAttr 7
# define rtfAdditive 0 /* new in 1.10 */
@ -709,6 +346,8 @@
# define rtfAnnotProtected 75 /* new in 1.10 */
# define rtfRTLDoc 76 /* new in 1.10 */
# define rtfLTRDoc 77 /* new in 1.10 */
# define rtfAnsiCodePage 78
# define rtfUTF8RTF 79
# define rtfSectAttr 9
# define rtfSectDef 0
@ -950,6 +589,7 @@
# define rtfCharCharSet 33 /* new in 1.10 */
# define rtfLanguage 34
# define rtfGray 35
# define rtfUnicodeLength 36
# define rtfPictAttr 13
# define rtfMacQD 0
@ -1287,20 +927,6 @@
# define rtfLangTurkish 0x041f
# define rtfLangUrdu 0x0420
/*
* CharSet indices
*/
# define rtfCSGeneral 0 /* general (default) charset */
# define rtfCSSymbol 1 /* symbol charset */
/*
* Flags for auto-charset-processing. Both are on by default.
*/
# define rtfReadCharSet 0x01 /* auto-read charset files */
# define rtfSwitchCharSet 0x02 /* auto-switch charset maps */
/*
* Style types
*/
@ -1381,20 +1007,25 @@ struct RTFStyleElt
# define New(t) ((t *) RTFAlloc ((int) sizeof (t)))
/* maximum number of character values representable in a byte */
# define charSetSize 256
/* charset stack size */
# define maxCSStack 10
/* Parser stack size */
# define maxStack 32
struct _RTF_Info;
typedef struct _RTF_Info RTF_Info;
typedef void (*RTFFuncPtr) (RTF_Info *); /* generic function pointer */
/* RTF parser stack element */
struct tagRTFState {
CHARFORMAT2W fmt;
int codePage;
int unicodeLength;
};
typedef struct tagRTFState RTFState;
struct _RTF_Info {
/*
* Public variables (listed in rtf.h)
@ -1434,55 +1065,26 @@ struct _RTF_Info {
int prevChar;
int bumpLine;
/* Document-wide attributes */
RTFFont *fontList; /* these lists MUST be */
RTFColor *colorList; /* initialized to NULL */
RTFStyle *styleList;
int ansiCodePage; /* ANSI codepage used in conversion to Unicode */
/* Character attributes */
int unicodeLength; /* The length of ANSI representation of Unicode characters */
int codePage; /* Current codepage for text conversion */
char *inputName;
char *outputName;
EDITSTREAM editstream;
char InputBuffer[0x1000];
DWORD dwInputSize;
DWORD dwInputUsed;
ME_InStream *stream;
/* edit window to output to */
HWND hwndEdit;
/*
* These arrays are used to map RTF input character values onto the standard
* character names represented by the values. Input character values are
* used as indices into the arrays to produce standard character codes.
*/
char *genCharSetFile ;
int genCharCode[charSetSize]; /* general */
int haveGenCharSet;
char *symCharSetFile;
int symCharCode[charSetSize]; /* symbol */
int haveSymCharSet;
int curCharSet;
int *curCharCode;
/*
* By default, the reader is configured to handle charset mapping invisibly,
* including reading the charset files and switching charset maps as necessary
* for Symbol font.
*/
int autoCharSetFlags;
/*
* Stack for keeping track of charset map on group begin/end. This is
* necessary because group termination reverts the font to the previous
* value, which may implicitly change it.
*/
int csStack[maxCSStack];
int csTop;
ME_TextEditor *editor;
ME_Style *style;
RTFFuncPtr ccb[rtfMaxClass]; /* class callbacks */
@ -1492,12 +1094,15 @@ struct _RTF_Info {
RTFFuncPtr panicProc;
FILE *(*libFileOpen) ();
char *outMap[rtfSC_MaxChar];
DWORD dwOutputCount;
char OutputBuffer[0x1000];
WCHAR OutputBuffer[0x1000];
DWORD dwCPOutputCount;
DWORD dwMaxCPOutputCount;
char *cpOutputBuffer;
RTFState stack[maxStack];
int stackTop;
};
@ -1506,6 +1111,7 @@ struct _RTF_Info {
*/
void RTFInit (RTF_Info *);
void RTFDestroy(RTF_Info *info);
void RTFSetInputName (RTF_Info *, char *);
char *RTFGetInputName (RTF_Info *);
void RTFSetOutputName (RTF_Info *, char *);
@ -1530,10 +1136,6 @@ int RTFCheckMM (RTF_Info *, int, int);
RTFFont *RTFGetFont (RTF_Info *, int);
RTFColor *RTFGetColor (RTF_Info *, int);
RTFStyle *RTFGetStyle (RTF_Info *, int);
# define RTFAlloc(size) _RTFAlloc ((int) size)
char *_RTFAlloc (int);
char *RTFStrSave (char *);
void RTFFree (char *);
int RTFCharToHex ( char);
int RTFHexToChar ( int );
void RTFSetMsgProc ( RTFFuncPtr );
@ -1549,22 +1151,12 @@ void RTFSetPanicProc ( RTF_Info *, RTFFuncPtr);
void RTFMsg (RTF_Info *, const char *fmt, ...);
void RTFPanic (RTF_Info *, const char *fmt, ...);
int RTFReadOutputMap ( RTF_Info *, char *[], int);
int RTFReadCharSetMap ( RTF_Info *, int);
void RTFSetCharSetMap ( RTF_Info *, char *, int);
int RTFStdCharCode ( RTF_Info *, const char *);
const char *RTFStdCharName ( RTF_Info *, int);
int RTFMapChar ( RTF_Info *, int);
int RTFGetCharSet( RTF_Info * );
void RTFSetCharSet( RTF_Info *, int);
void RTFSetOpenLibFileProc ( RTF_Info *, FILE *(*)());
FILE *RTFOpenLibFile ( RTF_Info *, char *, char *);
void RTFFlushOutputBuffer( RTF_Info *info );
void RTFSetEditStream(RTF_Info *, EDITSTREAM *es);
void RTFSetEditStream(RTF_Info *info, ME_InStream *stream);
void WriterInit (RTF_Info *);
int BeginFile (RTF_Info *);
int RTFCharSetToCodePage(RTF_Info *info, int charset);
#endif

View file

@ -26,7 +26,7 @@ WINE_DEFAULT_DEBUG_CHANNEL(richedit);
int ME_CanJoinRuns(ME_Run *run1, ME_Run *run2)
{
if ((run1->nFlags | run2->nFlags) & (MERF_ENDPARA | MERF_GRAPHICS))
if ((run1->nFlags | run2->nFlags) & MERF_NOJOIN)
return 0;
if (run1->style != run2->style)
return 0;
@ -91,8 +91,8 @@ void ME_CheckCharOffsets(ME_TextEditor *editor)
ofs = 0;
break;
case diRun:
TRACE("run, real ofs = %d (+ofsp = %d), counted = %d, len = %d, txt = \"%s\", flags=%08x, fx&mask = %08lx\n",
p->member.run.nCharOfs, p->member.run.nCharOfs+ofsp, ofsp+ofs,
TRACE("run, real ofs = %d (+ofsp = %d), counted = %d, len = %d, txt = \"%s\", flags=%08x, fx&mask = %08lx\n",
p->member.run.nCharOfs, p->member.run.nCharOfs+ofsp, ofsp+ofs,
p->member.run.strText->nLen, debugstr_w(p->member.run.strText->szData),
p->member.run.nFlags,
p->member.run.style->fmt.dwMask & p->member.run.style->fmt.dwEffects);
@ -108,14 +108,14 @@ void ME_CheckCharOffsets(ME_TextEditor *editor)
int ME_CharOfsFromRunOfs(ME_TextEditor *editor, ME_DisplayItem *pRun, int nOfs)
{
ME_DisplayItem *pPara;
assert(pRun->type == diRun);
assert(pRun->member.run.nCharOfs != -1);
pPara = ME_FindItemBack(pRun, diParagraph);
assert(pPara);
assert(pPara->type==diParagraph);
return pPara->member.para.nCharOfs + pRun->member.run.nCharOfs
return pPara->member.para.nCharOfs + pRun->member.run.nCharOfs
+ ME_VPosToPos(pRun->member.run.strText, nOfs);
}
@ -128,7 +128,7 @@ void ME_RunOfsFromCharOfs(ME_TextEditor *editor, int nCharOfs, ME_DisplayItem **
{
ME_DisplayItem *pPara;
int nParaOfs;
pPara = editor->pBuffer->pFirst->member.para.next_para;
assert(pPara);
assert(ppRun);
@ -137,18 +137,18 @@ void ME_RunOfsFromCharOfs(ME_TextEditor *editor, int nCharOfs, ME_DisplayItem **
{
nParaOfs = pPara->member.para.nCharOfs;
assert(nCharOfs >= nParaOfs);
if (nCharOfs < pPara->member.para.next_para->member.para.nCharOfs)
{
*ppRun = ME_FindItemFwd(pPara, diRun);
assert(*ppRun);
assert(*ppRun);
while (!((*ppRun)->member.run.nFlags & MERF_ENDPARA))
{
ME_DisplayItem *pNext = ME_FindItemFwd(*ppRun, diRun);
assert(pNext);
assert(pNext->type == diRun);
if (nCharOfs < nParaOfs + pNext->member.run.nCharOfs) {
*pOfs = ME_PosToVPos((*ppRun)->member.run.strText,
*pOfs = ME_PosToVPos((*ppRun)->member.run.strText,
nCharOfs - nParaOfs - (*ppRun)->member.run.nCharOfs);
return;
}
@ -157,12 +157,12 @@ void ME_RunOfsFromCharOfs(ME_TextEditor *editor, int nCharOfs, ME_DisplayItem **
if (nCharOfs == nParaOfs + (*ppRun)->member.run.nCharOfs) {
*pOfs = 0;
return;
}
}
}
pPara = pPara->member.para.next_para;
}
*ppRun = ME_FindItemBack(editor->pBuffer->pLast, diRun);
*pOfs = 0;
*pOfs = 0;
assert((*ppRun)->member.run.nFlags & MERF_ENDPARA);
}
@ -174,13 +174,15 @@ void ME_JoinRuns(ME_TextEditor *editor, ME_DisplayItem *p)
assert(p->member.run.nCharOfs != -1);
ME_GetParagraph(p)->member.para.nFlags |= MEPF_REWRAP;
if (editor->bCaretAtEnd && editor->pCursors[0].pRun == pNext)
editor->bCaretAtEnd = FALSE;
for (i=0; i<editor->nCursors; i++) {
if (editor->pCursors[i].pRun == pNext) {
editor->pCursors[i].pRun = p;
editor->pCursors[i].nOffset += ME_StrVLen(p->member.run.strText);
}
}
ME_AppendString(p->member.run.strText, pNext->member.run.strText);
ME_Remove(pNext);
ME_DestroyDisplayItem(pNext);
@ -198,7 +200,8 @@ ME_DisplayItem *ME_SplitRun(ME_Context *c, ME_DisplayItem *item, int nVChar)
ME_TextEditor *editor = c->editor;
ME_DisplayItem *item2 = NULL;
ME_Run *run, *run2;
ME_Paragraph *para = &ME_GetParagraph(item)->member.para;
assert(item->member.run.nCharOfs != -1);
if(TRACE_ON(richedit))
{
@ -213,28 +216,28 @@ ME_DisplayItem *ME_SplitRun(ME_Context *c, ME_DisplayItem *item, int nVChar)
run->pt.x, run->pt.y);
item2 = ME_SplitRunSimple(editor, item, nVChar);
run2 = &item2->member.run;
ME_CalcRunExtent(c, run);
ME_CalcRunExtent(c, run2);
ME_CalcRunExtent(c, para, run);
ME_CalcRunExtent(c, para, run2);
run2->pt.x = run->pt.x+run->nWidth;
run2->pt.y = run->pt.y;
if(TRACE_ON(richedit))
{
TRACE("Before check after split\n");
ME_CheckCharOffsets(editor);
TRACE("After check after split\n");
TRACE("After split: %s(%ld, %ld), %s(%ld, %ld)\n",
TRACE("After split: %s(%ld, %ld), %s(%ld, %ld)\n",
debugstr_w(run->strText->szData), run->pt.x, run->pt.y,
debugstr_w(run2->strText->szData), run2->pt.x, run2->pt.y);
}
return item2;
}
/* split a run starting from voffset */
ME_DisplayItem *ME_SplitRunSimple(ME_TextEditor *editor, ME_DisplayItem *item, int nVChar)
{
@ -244,22 +247,22 @@ ME_DisplayItem *ME_SplitRunSimple(ME_TextEditor *editor, ME_DisplayItem *item, i
int i;
assert(nVChar > 0 && nVChar < ME_StrVLen(run->strText));
assert(item->type == diRun);
assert(!(item->member.run.nFlags & MERF_GRAPHICS));
assert(!(item->member.run.nFlags & (MERF_GRAPHICS | MERF_TAB)));
assert(item->member.run.nCharOfs != -1);
item2 = ME_MakeRun(run->style,
item2 = ME_MakeRun(run->style,
ME_VSplitString(run->strText, nVChar), run->nFlags&MERF_SPLITMASK);
item2->member.run.nCharOfs = item->member.run.nCharOfs+
ME_VPosToPos(item->member.run.strText, nVChar);
run2 = &item2->member.run;
ME_InsertBefore(item->next, item2);
ME_UpdateRunFlags(editor, run);
ME_UpdateRunFlags(editor, run2);
for (i=0; i<editor->nCursors; i++) {
if (editor->pCursors[i].pRun == item &&
if (editor->pCursors[i].pRun == item &&
editor->pCursors[i].nOffset >= nVChar) {
assert(item2->type == diRun);
editor->pCursors[i].pRun = item2;
@ -270,18 +273,6 @@ ME_DisplayItem *ME_SplitRunSimple(ME_TextEditor *editor, ME_DisplayItem *item, i
return item2;
}
/* split the start and final whitespace into separate runs */
/* returns the last run added */
/*
ME_DisplayItem *ME_SplitFurther(ME_TextEditor *editor, ME_DisplayItem *item)
{
int i, nVLen, nChanged;
assert(item->type == diRun);
assert(!(item->member.run.nFlags & MERF_GRAPHICS));
return item;
}
*/
ME_DisplayItem *ME_MakeRun(ME_Style *s, ME_String *strData, int nFlags)
{
ME_DisplayItem *item = ME_MakeDI(diRun);
@ -298,12 +289,14 @@ ME_DisplayItem *ME_InsertRun(ME_TextEditor *editor, int nCharOfs, ME_DisplayItem
ME_Cursor tmp;
ME_DisplayItem *pDI;
ME_UndoItem *pUI;
assert(pItem->type == diRun || pItem->type == diUndoInsertRun);
pUI = ME_AddUndoItem(editor, diUndoDeleteRun, NULL);
pUI->nStart = nCharOfs;
pUI->nLen = pItem->member.run.strText->nLen;
if (pUI) {
pUI->nStart = nCharOfs;
pUI->nLen = pItem->member.run.strText->nLen;
}
ME_CursorFromCharOfs(editor, nCharOfs, &tmp);
if (tmp.nOffset) {
tmp.pRun = ME_SplitRunSimple(editor, tmp.pRun, tmp.nOffset);
@ -315,13 +308,8 @@ ME_DisplayItem *ME_InsertRun(ME_TextEditor *editor, int nCharOfs, ME_DisplayItem
TRACE("Shift length:%d\n", pDI->member.run.strText->nLen);
ME_PropagateCharOffset(tmp.pRun, pDI->member.run.strText->nLen);
ME_GetParagraph(tmp.pRun)->member.para.nFlags |= MEPF_REWRAP;
return pDI;
}
static inline int ME_IsWSpace(WCHAR ch)
{
return ch <= ' ';
return pDI;
}
void ME_UpdateRunFlags(ME_TextEditor *editor, ME_Run *run)
@ -331,19 +319,19 @@ void ME_UpdateRunFlags(ME_TextEditor *editor, ME_Run *run)
run->nFlags |= MERF_SPLITTABLE;
else
run->nFlags &= ~MERF_SPLITTABLE;
if (!(run->nFlags & MERF_GRAPHICS)) {
if (!(run->nFlags & MERF_NOTEXT)) {
if (ME_IsWhitespaces(run->strText))
run->nFlags |= MERF_WHITESPACE | MERF_STARTWHITE | MERF_ENDWHITE;
else
{
run->nFlags &= ~MERF_WHITESPACE;
if (ME_IsWSpace(ME_GetCharFwd(run->strText,0)))
run->nFlags |= MERF_STARTWHITE;
else
run->nFlags &= ~MERF_STARTWHITE;
if (ME_IsWSpace(ME_GetCharBack(run->strText,0)))
run->nFlags |= MERF_ENDWHITE;
else
@ -361,7 +349,7 @@ void ME_GetGraphicsSize(ME_TextEditor *editor, ME_Run *run, SIZE *pSize)
pSize->cy = 64;
}
int ME_CharFromPoint(ME_TextEditor *editor, int cx, ME_Run *run)
int ME_CharFromPoint(ME_TextEditor *editor, int cx, ME_Paragraph *para, ME_Run *run)
{
int fit = 0;
HGDIOBJ hOldFont;
@ -370,6 +358,12 @@ int ME_CharFromPoint(ME_TextEditor *editor, int cx, ME_Run *run)
if (!run->strText->nLen)
return 0;
if (run->nFlags & MERF_TAB)
{
if (cx < run->nWidth/2)
return 0;
return 1;
}
if (run->nFlags & MERF_GRAPHICS)
{
SIZE sz;
@ -380,9 +374,9 @@ int ME_CharFromPoint(ME_TextEditor *editor, int cx, ME_Run *run)
}
hDC = GetDC(editor->hWnd);
hOldFont = ME_SelectStyleFont(editor, hDC, run->style);
GetTextExtentExPointW(hDC, run->strText->szData, run->strText->nLen,
GetTextExtentExPointW(hDC, run->strText->szData, run->strText->nLen,
cx, &fit, NULL, &sz);
ME_UnselectStyleFont(editor, hDC, run->style, hOldFont);
ME_UnselectStyleFont(editor, hDC, run->style, hOldFont);
ReleaseDC(editor->hWnd, hDC);
return fit;
}
@ -396,6 +390,12 @@ int ME_CharFromPointCursor(ME_TextEditor *editor, int cx, ME_Run *run)
if (!run->strText->nLen)
return 0;
if (run->nFlags & MERF_TAB)
{
if (cx < run->nWidth/2)
return 0;
return 1;
}
if (run->nFlags & MERF_GRAPHICS)
{
SIZE sz;
@ -407,19 +407,19 @@ int ME_CharFromPointCursor(ME_TextEditor *editor, int cx, ME_Run *run)
hDC = GetDC(editor->hWnd);
hOldFont = ME_SelectStyleFont(editor, hDC, run->style);
GetTextExtentExPointW(hDC, run->strText->szData, run->strText->nLen,
GetTextExtentExPointW(hDC, run->strText->szData, run->strText->nLen,
cx, &fit, NULL, &sz);
if (fit != run->strText->nLen)
{
int chars = 1;
GetTextExtentPoint32W(hDC, run->strText->szData, fit, &sz2);
fit1 = ME_StrRelPos(run->strText, fit, &chars);
GetTextExtentPoint32W(hDC, run->strText->szData, fit1, &sz3);
if (cx >= (sz2.cx+sz3.cx)/2)
fit = fit1;
}
ME_UnselectStyleFont(editor, hDC, run->style, hOldFont);
ME_UnselectStyleFont(editor, hDC, run->style, hOldFont);
ReleaseDC(editor->hWnd, hDC);
return fit;
}
@ -429,7 +429,7 @@ int ME_PointFromChar(ME_TextEditor *editor, ME_Run *pRun, int nOffset)
SIZE size;
HDC hDC = GetDC(editor->hWnd);
HGDIOBJ hOldFont;
if (pRun->nFlags & MERF_GRAPHICS)
{
if (!nOffset) return 0;
@ -438,56 +438,88 @@ int ME_PointFromChar(ME_TextEditor *editor, ME_Run *pRun, int nOffset)
}
hOldFont = ME_SelectStyleFont(editor, hDC, pRun->style);
GetTextExtentPoint32W(hDC, pRun->strText->szData, nOffset, &size);
ME_UnselectStyleFont(editor, hDC, pRun->style, hOldFont);
ME_UnselectStyleFont(editor, hDC, pRun->style, hOldFont);
ReleaseDC(editor->hWnd, hDC);
return size.cx;
}
void ME_GetTextExtent(ME_Context *c, LPCWSTR szText, int nChars, ME_Style *s,
void ME_GetTextExtent(ME_Context *c, LPCWSTR szText, int nChars, ME_Style *s,
SIZE *size)
{
HDC hDC = c->hDC;
HGDIOBJ hOldFont;
hOldFont = ME_SelectStyleFont(c->editor, hDC, s);
GetTextExtentPoint32W(hDC, szText, nChars, size);
ME_UnselectStyleFont(c->editor, hDC, s, hOldFont);
ME_UnselectStyleFont(c->editor, hDC, s, hOldFont);
}
SIZE ME_GetRunSize(ME_Context *c, ME_Run *run, int nLen)
SIZE ME_GetRunSizeCommon(ME_Context *c, ME_Paragraph *para, ME_Run *run, int nLen, int *pAscent, int *pDescent)
{
SIZE size;
int nMaxLen = ME_StrVLen(run->strText);
if (nLen>nMaxLen)
nLen = nMaxLen;
/* FIXME the following call also ensures that TEXTMETRIC structure is filled
* this is wasteful for graphics and TAB runs, but that shouldn't matter
* in practice
*/
ME_GetTextExtent(c, run->strText->szData, nLen, run->style, &size);
assert(run->style->tm.tmAscent>0);
assert(run->style->tm.tmDescent>0);
*pAscent = run->style->tm.tmAscent;
*pDescent = run->style->tm.tmDescent;
size.cy = *pAscent + *pDescent;
if (run->nFlags & MERF_TAB)
{
int pos = 0, i = 0, ppos;
int lpsx = GetDeviceCaps(c->hDC, LOGPIXELSX);
PARAFORMAT2 *pFmt = para->pFmt;
do {
if (i < pFmt->cTabCount)
{
pos = pFmt->rgxTabs[i]&0x00FFFFFF;
i++;
}
else
{
pos += 720-(pos%720);
}
ppos = pos*lpsx/1440;
if (ppos>run->pt.x) {
size.cx = ppos - run->pt.x;
break;
}
} while(1);
size.cy = *pAscent + *pDescent;
return size;
}
if (run->nFlags & MERF_GRAPHICS)
{
ME_GetGraphicsSize(c->editor, run, &size);
if (size.cy > *pAscent)
*pAscent = size.cy;
/* descent is unchanged */
return size;
}
ME_GetTextExtent(c, run->strText->szData, nLen, run->style, &size);
return size;
}
void ME_CalcRunExtent(ME_Context *c, ME_Run *run)
SIZE ME_GetRunSize(ME_Context *c, ME_Paragraph *para, ME_Run *run, int nLen)
{
int asc, desc;
return ME_GetRunSizeCommon(c, para, run, nLen, &asc, &desc);
}
void ME_CalcRunExtent(ME_Context *c, ME_Paragraph *para, ME_Run *run)
{
SIZE size;
int nEnd = ME_StrVLen(run->strText);
if (run->nFlags & MERF_GRAPHICS) {
ME_GetGraphicsSize(c->editor, run, &size);
run->nWidth = size.cx;
run->nAscent = size.cy;
run->nDescent = 0;
return;
}
ME_GetTextExtent(c, run->strText->szData, nEnd, run->style, &size);
SIZE size = ME_GetRunSizeCommon(c, para, run, nEnd, &run->nAscent, &run->nDescent);
run->nWidth = size.cx;
run->nAscent = run->style->tm.tmAscent;
run->nDescent = run->style->tm.tmDescent;
assert(size.cx);
}
void ME_MustBeWrapped(ME_Context *c, ME_DisplayItem *para)
@ -517,7 +549,7 @@ void ME_SetCharFormat(ME_TextEditor *editor, int nOfs, int nChars, CHARFORMAT2W
{
ME_Cursor tmp, tmp2;
ME_DisplayItem *para;
ME_CursorFromCharOfs(editor, nOfs, &tmp);
if (tmp.nOffset)
tmp.pRun = ME_SplitRunSimple(editor, tmp.pRun, tmp.nOffset);
@ -528,7 +560,7 @@ void ME_SetCharFormat(ME_TextEditor *editor, int nOfs, int nChars, CHARFORMAT2W
para = ME_GetParagraph(tmp.pRun);
para->member.para.nFlags |= MEPF_REWRAP;
while(tmp.pRun != tmp2.pRun)
{
ME_UndoItem *undo = NULL;
@ -559,9 +591,9 @@ void ME_SetCharFormat(ME_TextEditor *editor, int nOfs, int nChars, CHARFORMAT2W
void ME_SetDefaultCharFormat(ME_TextEditor *editor, CHARFORMAT2W *mod)
{
ME_Style *style;
ME_Style *style;
ME_UndoItem *undo;
assert(mod->cbSize == sizeof(CHARFORMAT2W));
undo = ME_AddUndoItem(editor, diUndoSetDefaultCharFormat, NULL);
if (undo) {
@ -607,10 +639,10 @@ void ME_GetCharFormat(ME_TextEditor *editor, int nFrom, int nTo, CHARFORMAT2W *p
ME_DisplayItem *run, *run_end;
int nOffset, nOffset2;
CHARFORMAT2W tmp;
if (nTo>nFrom) /* selection consists of chars from nFrom up to nTo-1 */
nTo--;
ME_RunOfsFromCharOfs(editor, nFrom, &run, &nOffset);
if (nFrom == nTo) /* special case - if selection is empty, take previous char's formatting */
{
@ -626,22 +658,22 @@ void ME_GetCharFormat(ME_TextEditor *editor, int nFrom, int nTo, CHARFORMAT2W *p
return;
}
ME_RunOfsFromCharOfs(editor, nTo, &run_end, &nOffset2);
ME_GetRunCharFormat(editor, run, pFmt);
if (run == run_end) return;
do {
/* FIXME add more style feature comparisons */
int nAttribs = CFM_SIZE | CFM_FACE | CFM_COLOR;
int nEffects = CFM_BOLD | CFM_ITALIC | CFM_UNDERLINE;
run = ME_FindItemFwd(run, diRun);
ZeroMemory(&tmp, sizeof(tmp));
tmp.cbSize = sizeof(tmp);
ME_GetRunCharFormat(editor, run, &tmp);
assert((tmp.dwMask & nAttribs) == nAttribs);
assert((tmp.dwMask & nEffects) == nEffects);
/* reset flags that differ */
@ -665,8 +697,8 @@ void ME_GetCharFormat(ME_TextEditor *editor, int nFrom, int nTo, CHARFORMAT2W *p
pFmt->dwMask &= ~CFM_COLOR;
}
}
pFmt->dwMask &= ~((pFmt->dwEffects ^ tmp.dwEffects) & nEffects);
} while(run != run_end);
}

View file

@ -112,7 +112,7 @@ int ME_IsWhitespaces(ME_String *s)
{
/* FIXME multibyte */
WCHAR *pos = s->szData;
while(*pos++ == ' ')
while(ME_IsWSpace(*pos++))
;
pos--;
if (*pos)
@ -123,15 +123,14 @@ int ME_IsWhitespaces(ME_String *s)
int ME_IsSplitable(ME_String *s)
{
/* FIXME multibyte */
WCHAR *pos = s->szData;
WCHAR ch;
while(*pos++ == L' ')
while(ME_IsWSpace(*pos++))
;
pos--;
while((ch = *pos++) != 0)
{
if (ch == L' ')
if (ME_IsWSpace(ch))
return 1;
}
return 0;
@ -255,7 +254,7 @@ int ME_GetCharBack(ME_String *s, int nPos)
int ME_FindNonWhitespaceV(ME_String *s, int nVChar) {
int i;
for (i = nVChar; isspace(s->szData[i]) && i<s->nLen; i++)
for (i = nVChar; i<s->nLen && ME_IsWSpace(s->szData[i]); i++)
;
return i;
@ -264,7 +263,7 @@ int ME_FindNonWhitespaceV(ME_String *s, int nVChar) {
/* note: returns offset of the first trailing whitespace */
int ME_ReverseFindNonWhitespaceV(ME_String *s, int nVChar) {
int i;
for (i = nVChar; i>0 && isspace(s->szData[i-1]); i--)
for (i = nVChar; i>0 && ME_IsWSpace(s->szData[i-1]); i--)
;
return i;
@ -273,7 +272,7 @@ int ME_ReverseFindNonWhitespaceV(ME_String *s, int nVChar) {
/* note: returns offset of the first trailing nonwhitespace */
int ME_ReverseFindWhitespaceV(ME_String *s, int nVChar) {
int i;
for (i = nVChar; i>0 && !isspace(s->szData[i-1]); i--)
for (i = nVChar; i>0 && !ME_IsWSpace(s->szData[i-1]); i--)
;
return i;

View file

@ -54,7 +54,7 @@ CHARFORMAT2W *ME_ToCF2W(CHARFORMAT2W *to, CHARFORMAT2W *from)
if (f->dwMask & CFM_FACE)
MultiByteToWideChar(0, 0, f->szFaceName, -1, to->szFaceName, sizeof(to->szFaceName));
/* copy the rest of the 2A structure to 2W */
CopyMemory(1+((CHARFORMATW *)from), f+1, sizeof(CHARFORMAT2A)-sizeof(CHARFORMATA));
CopyMemory(1+((CHARFORMATW *)to), f+1, sizeof(CHARFORMAT2A)-sizeof(CHARFORMATA));
to->cbSize = sizeof(CHARFORMAT2W);
return to;
}
@ -124,6 +124,7 @@ ME_Style *ME_MakeStyle(CHARFORMAT2W *style) {
s->nSequence = -2;
s->nRefs = 1;
s->hFont = NULL;
s->tm.tmAscent = -1;
all_refs++;
return s;
}

View file

@ -26,6 +26,9 @@ void ME_EmptyUndoStack(ME_TextEditor *editor)
{
ME_DisplayItem *p, *pNext;
if (editor->nUndoMode == umIgnore)
return;
TRACE("Emptying undo stack\n");
p = editor->pUndoStack;
@ -121,6 +124,10 @@ ME_UndoItem *ME_AddUndoItem(ME_TextEditor *editor, ME_DIType type, ME_DisplayIte
}
void ME_CommitUndo(ME_TextEditor *editor) {
if (editor->nUndoMode == umIgnore)
return;
assert(editor->nUndoMode == umAddToUndo);
/* no transactions, no need to commit */
@ -140,6 +147,8 @@ void ME_PlayUndoItem(ME_TextEditor *editor, ME_DisplayItem *pItem)
{
ME_UndoItem *pUItem = (ME_UndoItem *)pItem;
if (editor->nUndoMode == umIgnore)
return;
TRACE("Playing undo/redo item, id=%s\n", ME_GetDITypeName(pItem->type));
switch(pItem->type)
@ -202,6 +211,8 @@ void ME_Undo(ME_TextEditor *editor) {
ME_DisplayItem *p;
ME_UndoMode nMode = editor->nUndoMode;
if (editor->nUndoMode == umIgnore)
return;
assert(nMode == umAddToUndo || nMode == umIgnore);
/* no undo items ? */
@ -235,6 +246,8 @@ void ME_Redo(ME_TextEditor *editor) {
assert(nMode == umAddToUndo || nMode == umIgnore);
if (editor->nUndoMode == umIgnore)
return;
/* no redo items ? */
if (!editor->pRedoStack)
return;

View file

@ -26,16 +26,16 @@ WINE_DEFAULT_DEBUG_CHANNEL(richedit);
/*
* Unsolved problems:
*
*
* - center and right align in WordPad omits all spaces at the start, we don't
* - objects/images are not handled yet
* - no tabs
*/
* - no tabs
*/
ME_DisplayItem *ME_MakeRow(int height, int baseline, int width)
{
ME_DisplayItem *item = ME_MakeDI(diStartRow);
item->member.row.nHeight = height;
item->member.row.nBaseline = baseline;
item->member.row.nWidth = width;
@ -49,7 +49,7 @@ void ME_BeginRow(ME_WrapContext *wc)
wc->pLastSplittableRun = NULL;
wc->nAvailWidth = wc->nTotalWidth - (wc->nRow ? wc->nLeftMargin : wc->nFirstMargin) - wc->nRightMargin;
wc->pt.x = 0;
}
}
void ME_InsertRowStart(ME_WrapContext *wc, ME_DisplayItem *pEnd)
{
@ -95,7 +95,7 @@ void ME_WrapEndParagraph(ME_WrapContext *wc, ME_DisplayItem *p)
{
if (wc->pRowStart)
ME_InsertRowStart(wc, p->next);
/*
p = p->member.para.prev_para->next;
while(p) {
@ -109,15 +109,15 @@ void ME_WrapEndParagraph(ME_WrapContext *wc, ME_DisplayItem *p)
p = p->next;
}
*/
}
}
void ME_WrapSizeRun(ME_WrapContext *wc, ME_DisplayItem *p)
{
/* FIXME compose style (out of character and paragraph styles) here */
ME_UpdateRunFlags(wc->context->editor, &p->member.run);
ME_CalcRunExtent(wc->context, &p->member.run);
ME_CalcRunExtent(wc->context, &ME_GetParagraph(p)->member.para, &p->member.run);
}
ME_DisplayItem *ME_MaximizeSplit(ME_WrapContext *wc, ME_DisplayItem *p, int i)
@ -139,7 +139,7 @@ ME_DisplayItem *ME_MaximizeSplit(ME_WrapContext *wc, ME_DisplayItem *p, int i)
while(piter != wc->pRowStart)
{
piter = ME_FindItemBack(piter, diRun);
if (piter->member.run.nFlags & MERF_WHITESPACE)
if (piter->member.run.nFlags & MERF_WHITESPACE)
{
pp = piter;
continue;
@ -167,8 +167,8 @@ ME_DisplayItem *ME_SplitByBacktracking(ME_WrapContext *wc, ME_DisplayItem *p, in
ME_DisplayItem *piter = p, *pp;
int i, idesp, len;
ME_Run *run = &p->member.run;
idesp = i = ME_CharFromPoint(wc->context->editor, loc, run);
idesp = i = ME_CharFromPoint(wc->context->editor, loc, &ME_GetParagraph(p)->member.para, run);
len = ME_StrVLen(run->strText);
assert(len>0);
assert(i<len);
@ -182,7 +182,7 @@ ME_DisplayItem *ME_SplitByBacktracking(ME_WrapContext *wc, ME_DisplayItem *p, in
TRACE("Must backtrack to split at: %s\n", debugstr_w(p->member.run.strText->szData));
if (wc->pLastSplittableRun)
{
if (wc->pLastSplittableRun->member.run.nFlags & MERF_GRAPHICS)
if (wc->pLastSplittableRun->member.run.nFlags & (MERF_GRAPHICS|MERF_TAB))
{
wc->pt = wc->ptLastSplittableRun;
return wc->pLastSplittableRun;
@ -193,7 +193,7 @@ ME_DisplayItem *ME_SplitByBacktracking(ME_WrapContext *wc, ME_DisplayItem *p, in
they serve no other purpose */
ME_UpdateRunFlags(wc->context->editor, run);
assert((wc->pLastSplittableRun->member.run.nFlags & MERF_SPLITTABLE));
piter = wc->pLastSplittableRun;
run = &piter->member.run;
len = ME_StrVLen(run->strText);
@ -201,7 +201,7 @@ ME_DisplayItem *ME_SplitByBacktracking(ME_WrapContext *wc, ME_DisplayItem *p, in
i = ME_ReverseFindWhitespaceV(run->strText, len);
if (i == len)
i = ME_ReverseFindNonWhitespaceV(run->strText, len);
if (i) {
if (i) {
ME_DisplayItem *piter2 = ME_SplitRun(wc->context, piter, i);
wc->pt = piter2->member.run.pt;
return piter2;
@ -239,7 +239,7 @@ ME_DisplayItem *ME_SplitByBacktracking(ME_WrapContext *wc, ME_DisplayItem *p, in
}
/* the run is one char, can't split it */
return piter;
}
}
}
ME_DisplayItem *ME_WrapHandleRun(ME_WrapContext *wc, ME_DisplayItem *p)
@ -248,24 +248,24 @@ ME_DisplayItem *ME_WrapHandleRun(ME_WrapContext *wc, ME_DisplayItem *p)
ME_Run *run;
int len;
assert(p->type == diRun);
assert(p->type == diRun);
if (!wc->pRowStart)
wc->pRowStart = p;
ME_WrapSizeRun(wc, p);
run = &p->member.run;
run->pt.x = wc->pt.x;
run->pt.y = wc->pt.y;
len = ME_StrVLen(run->strText);
ME_WrapSizeRun(wc, p);
len = ME_StrVLen(run->strText);
if (wc->bOverflown) /* just skipping final whitespaces */
{
if (run->nFlags & MERF_WHITESPACE) {
{
if (run->nFlags & (MERF_WHITESPACE|MERF_TAB)) {
p->member.run.nFlags |= MERF_SKIPPED;
/* wc->pt.x += run->nWidth; */
/* skip runs consisting of only whitespaces */
return p->next;
}
if (run->nFlags & MERF_STARTWHITE) {
/* try to split the run at the first non-white char */
int black;
@ -274,10 +274,6 @@ ME_DisplayItem *ME_WrapHandleRun(ME_WrapContext *wc, ME_DisplayItem *p)
wc->bOverflown = FALSE;
pp = ME_SplitRun(wc->context, p, black);
p->member.run.nFlags |= MERF_SKIPPED;
/*
run->pt = wc->pt;
wc->pt.x += run->nWidth;
*/
ME_InsertRowStart(wc, pp);
return pp;
}
@ -290,15 +286,15 @@ ME_DisplayItem *ME_WrapHandleRun(ME_WrapContext *wc, ME_DisplayItem *p)
/* will current run fit? */
if (wc->pt.x + run->nWidth > wc->nAvailWidth)
{
int loc = wc->nAvailWidth - wc->pt.x;
int loc = wc->nAvailWidth - wc->pt.x;
/* total white run ? */
if (run->nFlags & MERF_WHITESPACE) {
/* let the overflow logic handle it */
wc->bOverflown = TRUE;
return p;
}
/* graphics - we can split before */
if (run->nFlags & MERF_GRAPHICS) {
/* graphics or TAB - we can split before */
if (run->nFlags & (MERF_GRAPHICS|MERF_TAB)) {
wc->bOverflown = TRUE;
return p;
}
@ -330,8 +326,8 @@ ME_DisplayItem *ME_WrapHandleRun(ME_WrapContext *wc, ME_DisplayItem *p)
ERR("failure!\n");
/* not found anything - writing over margins is the only option left */
}
if ((run->nFlags & (MERF_SPLITTABLE | MERF_STARTWHITE))
|| ((run->nFlags & MERF_GRAPHICS) && (p != wc->pRowStart)))
if ((run->nFlags & (MERF_SPLITTABLE | MERF_STARTWHITE))
|| ((run->nFlags & (MERF_GRAPHICS|MERF_TAB)) && (p != wc->pRowStart)))
{
wc->pLastSplittableRun = p;
wc->ptLastSplittableRun = wc->pt;
@ -339,20 +335,24 @@ ME_DisplayItem *ME_WrapHandleRun(ME_WrapContext *wc, ME_DisplayItem *p)
wc->pt.x += run->nWidth;
return p->next;
}
void ME_WrapTextParagraph(ME_Context *c, ME_DisplayItem *tp) {
ME_DisplayItem *p;
ME_WrapContext wc;
int dpi = GetDeviceCaps(c->hDC, LOGPIXELSX);
assert(tp->type == diParagraph);
assert(tp->type == diParagraph);
if (!(tp->member.para.nFlags & MEPF_REWRAP)) {
return;
}
ME_PrepareParagraphForWrapping(c, tp);
wc.context = c;
/* wc.para_style = tp->member.para.style; */
wc.style = NULL;
tp->member.para.nRightMargin = tp->member.para.pFmt->dxRightIndent*dpi/1440;
tp->member.para.nFirstMargin = tp->member.para.pFmt->dxStartIndent*dpi/1440;
tp->member.para.nLeftMargin = (tp->member.para.pFmt->dxStartIndent+tp->member.para.pFmt->dxOffset)*dpi/1440;
wc.nFirstMargin = tp->member.para.nFirstMargin;
wc.nLeftMargin = tp->member.para.nLeftMargin;
wc.nRightMargin = tp->member.para.nRightMargin;
@ -362,7 +362,7 @@ void ME_WrapTextParagraph(ME_Context *c, ME_DisplayItem *tp) {
wc.nTotalWidth = c->rcView.right - c->rcView.left;
wc.nAvailWidth = wc.nTotalWidth - wc.nFirstMargin - wc.nRightMargin;
wc.pRowStart = NULL;
ME_BeginRow(&wc);
for (p = tp->next; p!=tp->member.para.next_para; ) {
assert(p->type != diStartRow);
@ -413,37 +413,41 @@ void ME_PrepareParagraphForWrapping(ME_Context *c, ME_DisplayItem *tp) {
}
}
void ME_WrapMarkedParagraphs(ME_TextEditor *editor) {
BOOL ME_WrapMarkedParagraphs(ME_TextEditor *editor) {
HWND hWnd = editor->hWnd;
HDC hDC = GetDC(hWnd);
ME_DisplayItem *item;
ME_Context c;
BOOL bModified = FALSE;
ME_InitContext(&c, editor, hDC);
c.pt.x = 0;
c.pt.y = 0;
item = editor->pBuffer->pFirst->next;
while(item != editor->pBuffer->pLast) {
BOOL bRedraw = FALSE;
assert(item->type == diParagraph);
if ((item->member.para.nFlags & MEPF_REWRAP)
|| (item->member.para.nYPos != c.pt.y))
bRedraw = TRUE;
item->member.para.nYPos = c.pt.y;
ME_WrapTextParagraph(&c, item);
if (bRedraw)
item->member.para.nFlags |= MEPF_REPAINT;
bModified = bModified | bRedraw;
c.pt.y += item->member.para.nHeight;
item = item->member.para.next_para;
}
editor->sizeWindow.cx = c.rcView.right-c.rcView.left;
editor->sizeWindow.cy = c.rcView.bottom-c.rcView.top;
editor->nTotalLength = c.pt.y;
ME_DestroyContext(&c);
ReleaseDC(hWnd, hDC);
return bModified;
}

View file

@ -0,0 +1,787 @@
/*
* 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
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "editor.h"
#include "rtf.h"
WINE_DEFAULT_DEBUG_CHANNEL(richedit);
static BOOL
ME_StreamOutRTFText(ME_TextEditor *editor, WCHAR *text, LONG nChars);
static void
ME_StreamOutInit(ME_TextEditor *editor, EDITSTREAM *stream)
{
editor->pStream = ALLOC_OBJ(ME_OutStream);
editor->pStream->stream = stream;
editor->pStream->pos = 0;
editor->pStream->written = 0;
editor->pStream->nFontTblLen = 0;
editor->pStream->nColorTblLen = 1;
}
static BOOL
ME_StreamOutFlush(ME_TextEditor *editor)
{
LONG nStart = 0;
LONG nWritten = 0;
EDITSTREAM *stream = editor->pStream->stream;
do {
stream->dwError = stream->pfnCallback(stream->dwCookie, editor->pStream->buffer + nStart,
editor->pStream->pos - nStart, &nWritten);
if (nWritten == 0 || stream->dwError)
return FALSE;
editor->pStream->written += nWritten;
nStart += nWritten;
} while (nStart < editor->pStream->pos);
editor->pStream->pos = 0;
return TRUE;
}
static LONG
ME_StreamOutFree(ME_TextEditor *editor)
{
LONG written = editor->pStream->written;
FREE_OBJ(editor->pStream);
editor->pStream = NULL;
return written;
}
static BOOL
ME_StreamOutMove(ME_TextEditor *editor, BYTE *buffer, int len)
{
ME_OutStream *pStream = editor->pStream;
while (len) {
int space = STREAMOUT_BUFFER_SIZE - pStream->pos;
int fit = min(space, len);
TRACE("%u:%u:%.*s\n", pStream->pos, fit, fit, buffer);
memmove(pStream->buffer + pStream->pos, buffer, fit);
len -= fit;
buffer += fit;
pStream->pos += fit;
if (pStream->pos == STREAMOUT_BUFFER_SIZE) {
if (!ME_StreamOutFlush(editor))
return FALSE;
}
}
return TRUE;
}
static BOOL
ME_StreamOutPrint(ME_TextEditor *editor, char *format, ...)
{
char string[STREAMOUT_BUFFER_SIZE]; /* This is going to be enough */
int len;
va_list valist;
va_start(valist, format);
len = vsnprintf(string, sizeof(string), format, valist);
va_end(valist);
return ME_StreamOutMove(editor, string, len);
}
static BOOL
ME_StreamOutRTFHeader(ME_TextEditor *editor, int dwFormat)
{
char *cCharSet = NULL;
UINT nCodePage;
LANGID language;
BOOL success;
if (dwFormat & SF_USECODEPAGE) {
CPINFOEXW info;
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)
success = ME_StreamOutPrint(editor, "{\\urtf");
else
success = ME_StreamOutPrint(editor, "{\\rtf1\\%s\\ansicpg%u\\uc1", cCharSet, nCodePage);
if (!success)
return FALSE;
editor->pStream->nDefaultCodePage = nCodePage;
/* FIXME: This should be a document property */
/* TODO: handle SFF_PLAINRTF */
language = GetUserDefaultLangID();
if (!ME_StreamOutPrint(editor, "\\deff0\\deflang%u\\deflangfe%u", language, language))
return FALSE;
/* FIXME: This should be a document property */
editor->pStream->nDefaultFont = 0;
return TRUE;
}
static BOOL
ME_StreamOutRTFFontAndColorTbl(ME_TextEditor *editor, ME_DisplayItem *pFirstRun, ME_DisplayItem *pLastRun)
{
ME_DisplayItem *item = pFirstRun;
ME_FontTableItem *table = editor->pStream->fonttbl;
int i;
do {
CHARFORMAT2W *fmt = &item->member.run.style->fmt;
COLORREF crColor;
if (fmt->dwMask & CFM_FACE) {
WCHAR *face = fmt->szFaceName;
BYTE bCharSet = (fmt->dwMask & CFM_CHARSET) ? fmt->bCharSet : DEFAULT_CHARSET;
for (i = 0; i < editor->pStream->nFontTblLen; i++)
if (table[i].bCharSet == bCharSet
&& (table[i].szFaceName == face || !lstrcmpW(table[i].szFaceName, face)))
break;
if (i == editor->pStream->nFontTblLen) {
table[i].bCharSet = bCharSet;
table[i].szFaceName = face;
editor->pStream->nFontTblLen++;
}
}
if (fmt->dwMask & CFM_COLOR && !(fmt->dwEffects & CFE_AUTOCOLOR)) {
crColor = fmt->crTextColor;
for (i = 1; i < editor->pStream->nColorTblLen; i++)
if (editor->pStream->colortbl[i] == crColor)
break;
if (i == editor->pStream->nColorTblLen) {
editor->pStream->colortbl[i] = crColor;
editor->pStream->nColorTblLen++;
}
}
if (fmt->dwMask & CFM_BACKCOLOR && !(fmt->dwEffects & CFE_AUTOBACKCOLOR)) {
crColor = fmt->crBackColor;
for (i = 1; i < editor->pStream->nColorTblLen; i++)
if (editor->pStream->colortbl[i] == crColor)
break;
if (i == editor->pStream->nColorTblLen) {
editor->pStream->colortbl[i] = crColor;
editor->pStream->nColorTblLen++;
}
}
if (item == pLastRun)
break;
item = ME_FindItemFwd(item, diRun);
} while (item);
if (!ME_StreamOutPrint(editor, "{\\fonttbl"))
return FALSE;
for (i = 0; i < editor->pStream->nFontTblLen; i++) {
if (table[i].bCharSet != DEFAULT_CHARSET) {
if (!ME_StreamOutPrint(editor, "{\\f%u\\fcharset%u ", i, table[i].bCharSet))
return FALSE;
} else {
if (!ME_StreamOutPrint(editor, "{\\f%u ", i))
return FALSE;
}
if (!ME_StreamOutRTFText(editor, table[i].szFaceName, -1))
return FALSE;
if (!ME_StreamOutPrint(editor, ";}\r\n"))
return FALSE;
}
if (!ME_StreamOutPrint(editor, "}"))
return FALSE;
/* Output colors table if not empty */
if (editor->pStream->nColorTblLen > 1) {
if (!ME_StreamOutPrint(editor, "{\\colortbl;"))
return FALSE;
for (i = 1; i < editor->pStream->nColorTblLen; i++) {
if (!ME_StreamOutPrint(editor, "\\red%u\\green%u\\blue%u;",
editor->pStream->colortbl[i] & 0xFF,
(editor->pStream->colortbl[i] >> 8) & 0xFF,
(editor->pStream->colortbl[i] >> 16) & 0xFF))
return FALSE;
}
if (!ME_StreamOutPrint(editor, "}"))
return FALSE;
}
return TRUE;
}
static BOOL
ME_StreamOutRTFParaProps(ME_TextEditor *editor, ME_DisplayItem *para)
{
PARAFORMAT2 *fmt = para->member.para.pFmt;
char props[STREAMOUT_BUFFER_SIZE] = "";
int i;
/* TODO: Don't emit anything if the last PARAFORMAT2 is inherited */
if (!ME_StreamOutPrint(editor, "\\pard"))
return FALSE;
/* 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) */
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;
}
}
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:
sprintf(props + strlen(props), "\\sl%ld\\slmult0", fmt->dyLineSpacing);
break;
case 4:
sprintf(props + strlen(props), "\\sl-%ld\\slmult0", fmt->dyLineSpacing);
break;
case 5:
sprintf(props + strlen(props), "\\sl-%ld\\slmult1", fmt->dyLineSpacing * 240 / 20);
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");
if (fmt->dwMask & PFM_TABLE && fmt->dwMask & PFE_TABLE)
strcat(props, "\\intbl");
if (fmt->dwMask & PFM_OFFSET)
sprintf(props + strlen(props), "\\li%ld", fmt->dxOffset);
if (fmt->dwMask & PFM_OFFSETINDENT || fmt->dwMask & PFM_STARTINDENT)
sprintf(props + strlen(props), "\\fi%ld", fmt->dxStartIndent);
if (fmt->dwMask & PFM_RIGHTINDENT)
sprintf(props + strlen(props), "\\ri%ld", fmt->dxRightIndent);
if (fmt->dwMask & PFM_SPACEAFTER)
sprintf(props + strlen(props), "\\sa%ld", fmt->dySpaceAfter);
if (fmt->dwMask & PFM_SPACEBEFORE)
sprintf(props + strlen(props), "\\sb%ld", fmt->dySpaceBefore);
if (fmt->dwMask & PFM_STYLE)
sprintf(props + strlen(props), "\\s%d", fmt->sStyle);
if (fmt->dwMask & PFM_TABSTOPS) {
static const char *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]);
}
}
if (fmt->dwMask & PFM_SHADING) {
static const char *style[16] = { "", "\\bgdkhoriz", "\\bgdkvert", "\\bgdkfdiag",
"\\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]);
sprintf(props + strlen(props), "\\cfpat%d\\cbpat%d",
(fmt->wShadingStyle >> 4) & 0xF, (fmt->wShadingStyle >> 8) & 0xF);
}
if (*props && !ME_StreamOutPrint(editor, props))
return FALSE;
return TRUE;
}
static BOOL
ME_StreamOutRTFCharProps(ME_TextEditor *editor, CHARFORMAT2W *fmt)
{
char props[STREAMOUT_BUFFER_SIZE] = "";
int i;
if (fmt->dwMask & CFM_ALLCAPS && fmt->dwEffects & CFE_ALLCAPS)
strcat(props, "\\caps");
if (fmt->dwMask & CFM_ANIMATION)
sprintf(props + strlen(props), "\\animtext%u", fmt->bAnimation);
if (fmt->dwMask & CFM_BACKCOLOR) {
if (!(fmt->dwEffects & CFE_AUTOBACKCOLOR)) {
for (i = 1; i < editor->pStream->nColorTblLen; i++)
if (editor->pStream->colortbl[i] == fmt->crBackColor) {
sprintf(props + strlen(props), "\\cb%u", i);
break;
}
}
}
if (fmt->dwMask & CFM_BOLD && fmt->dwEffects & CFE_BOLD)
strcat(props, "\\b");
if (fmt->dwMask & CFM_COLOR) {
if (!(fmt->dwEffects & CFE_AUTOCOLOR)) {
for (i = 1; i < editor->pStream->nColorTblLen; i++)
if (editor->pStream->colortbl[i] == fmt->crTextColor) {
sprintf(props + strlen(props), "\\cf%u", i);
break;
}
}
}
/* TODO: CFM_DISABLED */
if (fmt->dwMask & CFM_EMBOSS && fmt->dwEffects & CFE_EMBOSS)
strcat(props, "\\embo");
if (fmt->dwMask & CFM_HIDDEN && fmt->dwEffects & CFE_HIDDEN)
strcat(props, "\\v");
if (fmt->dwMask & CFM_IMPRINT && fmt->dwEffects & CFE_IMPRINT)
strcat(props, "\\impr");
if (fmt->dwMask & CFM_ITALIC && fmt->dwEffects & CFE_ITALIC)
strcat(props, "\\i");
if (fmt->dwMask & CFM_KERNING)
sprintf(props + strlen(props), "\\kerning%u", fmt->wKerning);
if (fmt->dwMask & CFM_LCID) {
/* 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));
}
/* CFM_LINK is not streamed out by M$ */
if (fmt->dwMask & CFM_OFFSET) {
if (fmt->yOffset >= 0)
sprintf(props + strlen(props), "\\up%ld", fmt->yOffset);
else
sprintf(props + strlen(props), "\\dn%ld", -fmt->yOffset);
}
if (fmt->dwMask & CFM_OUTLINE && fmt->dwEffects & CFE_OUTLINE)
strcat(props, "\\outl");
if (fmt->dwMask & CFM_PROTECTED && fmt->dwEffects & CFE_PROTECTED)
strcat(props, "\\protect");
/* TODO: CFM_REVISED CFM_REVAUTHOR - probably using rsidtbl? */
if (fmt->dwMask & CFM_SHADOW && fmt->dwEffects & CFE_SHADOW)
strcat(props, "\\shad");
if (fmt->dwMask & CFM_SIZE)
sprintf(props + strlen(props), "\\fs%ld", fmt->yHeight / 10);
if (fmt->dwMask & CFM_SMALLCAPS && fmt->dwEffects & CFE_SMALLCAPS)
strcat(props, "\\scaps");
if (fmt->dwMask & CFM_SPACING)
sprintf(props + strlen(props), "\\expnd%u\\expndtw%u", fmt->sSpacing / 5, fmt->sSpacing);
if (fmt->dwMask & CFM_STRIKEOUT && fmt->dwEffects & CFE_STRIKEOUT)
strcat(props, "\\strike");
if (fmt->dwMask & CFM_STYLE) {
sprintf(props + strlen(props), "\\cs%u", fmt->sStyle);
/* TODO: emit style contents here */
}
if (fmt->dwMask & (CFM_SUBSCRIPT | CFM_SUPERSCRIPT)) {
if (fmt->dwEffects & CFE_SUBSCRIPT)
strcat(props, "\\sub");
else if (fmt->dwEffects & CFE_SUPERSCRIPT)
strcat(props, "\\super");
}
if (fmt->dwMask & CFM_UNDERLINE || fmt->dwMask & CFM_UNDERLINETYPE) {
if (fmt->dwMask & CFM_UNDERLINETYPE)
switch (fmt->bUnderlineType) {
case CFU_CF1UNDERLINE:
case CFU_UNDERLINE:
strcat(props, "\\ul");
break;
case CFU_UNDERLINEDOTTED:
strcat(props, "\\uld");
break;
case CFU_UNDERLINEDOUBLE:
strcat(props, "\\uldb");
break;
case CFU_UNDERLINEWORD:
strcat(props, "\\ulw");
break;
case CFU_UNDERLINENONE:
default:
strcat(props, "\\ul0");
break;
}
else if (fmt->dwEffects & CFE_UNDERLINE)
strcat(props, "\\ul");
}
/* FIXME: How to emit CFM_WEIGHT? */
if (fmt->dwMask & CFM_FACE || fmt->dwMask & CFM_CHARSET) {
WCHAR *szFaceName;
if (fmt->dwMask & CFM_FACE)
szFaceName = fmt->szFaceName;
else
szFaceName = editor->pStream->fonttbl[0].szFaceName;
for (i = 0; i < editor->pStream->nFontTblLen; i++) {
if (szFaceName == editor->pStream->fonttbl[i].szFaceName
|| !lstrcmpW(szFaceName, editor->pStream->fonttbl[i].szFaceName))
if (!(fmt->dwMask & CFM_CHARSET)
|| fmt->bCharSet == editor->pStream->fonttbl[i].bCharSet)
break;
}
if (i < editor->pStream->nFontTblLen)
{
if (i != editor->pStream->nDefaultFont)
sprintf(props + strlen(props), "\\f%u", i);
/* In UTF-8 mode, charsets/codepages are not used */
if (editor->pStream->nDefaultCodePage != CP_UTF8)
{
if (editor->pStream->fonttbl[i].bCharSet == DEFAULT_CHARSET)
editor->pStream->nCodePage = editor->pStream->nDefaultCodePage;
else
editor->pStream->nCodePage = RTFCharSetToCodePage(NULL,
editor->pStream->fonttbl[i].bCharSet);
}
}
}
if (*props)
strcat(props, " ");
if (!ME_StreamOutPrint(editor, props))
return FALSE;
return TRUE;
}
static BOOL
ME_StreamOutRTFText(ME_TextEditor *editor, WCHAR *text, LONG nChars)
{
char buffer[STREAMOUT_BUFFER_SIZE];
int pos = 0;
int fit, i;
if (nChars == -1)
nChars = lstrlenW(text);
while (nChars) {
/* In UTF-8 mode, font charsets are not used. */
if (editor->pStream->nDefaultCodePage == CP_UTF8) {
/* 6 is the maximum character length in UTF-8 */
fit = min(nChars, STREAMOUT_BUFFER_SIZE / 6);
WideCharToMultiByte(CP_UTF8, 0, text, fit, buffer, STREAMOUT_BUFFER_SIZE,
NULL, NULL);
nChars -= fit;
text += fit;
for (i = 0; buffer[i]; i++)
if (buffer[i] == '{' || buffer[i] == '}' || buffer[i] == '\\') {
if (!ME_StreamOutPrint(editor, "%.*s\\", i - pos, buffer + pos))
return FALSE;
pos = i;
}
if (!pos)
if (!ME_StreamOutPrint(editor, "%s", buffer + pos))
return FALSE;
pos = 0;
} else if (*text < 128) {
if (*text == '{' || *text == '}' || *text == '\\')
buffer[pos++] = '\\';
buffer[pos++] = (char)(*text++);
nChars--;
} else {
BOOL unknown = FALSE;
BYTE letter[3];
int nBytes, i;
/* 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 */
nBytes = WideCharToMultiByte(editor->pStream->nCodePage, 0, text, 1,
letter, 3, NULL,
(editor->pStream->nCodePage == CP_SYMBOL) ? NULL : &unknown);
if (unknown)
pos += sprintf(buffer + pos, "\\u%d?", (short)*text);
else if (*letter < 128) {
if (*letter == '{' || *letter == '}' || *letter == '\\')
buffer[pos++] = '\\';
buffer[pos++] = *letter;
} else {
for (i = 0; i < nBytes; i++)
pos += sprintf(buffer + pos, "\\'%02x", letter[i]);
}
text++;
nChars--;
}
if (pos >= STREAMOUT_BUFFER_SIZE - 11) {
if (!ME_StreamOutMove(editor, buffer, pos))
return FALSE;
pos = 0;
}
}
return ME_StreamOutMove(editor, buffer, pos);
}
static BOOL
ME_StreamOutRTF(ME_TextEditor *editor, int nStart, int nChars, int dwFormat)
{
ME_DisplayItem *p, *pEnd;
int nOffset, nEndLen;
ME_RunOfsFromCharOfs(editor, nStart, &p, &nOffset);
ME_RunOfsFromCharOfs(editor, nStart+nChars, &pEnd, &nEndLen);
if (!ME_StreamOutRTFHeader(editor, dwFormat))
return FALSE;
if (!ME_StreamOutRTFFontAndColorTbl(editor, p, pEnd))
return FALSE;
/* TODO: stylesheet table */
/* FIXME: maybe emit something smarter for the generator? */
if (!ME_StreamOutPrint(editor, "{\\*\\generator Wine Riched20 2.0.????;}"))
return FALSE;
/* TODO: information group */
/* TODO: document formatting properties */
/* FIXME: We have only one document section */
/* TODO: section formatting properties */
if (!ME_StreamOutRTFParaProps(editor, ME_GetParagraph(p)))
return FALSE;
while(1)
{
switch(p->type)
{
case diParagraph:
if (!ME_StreamOutRTFParaProps(editor, p))
return FALSE;
break;
case diRun:
if (p == pEnd && !nEndLen)
break;
TRACE("flags %xh\n", p->member.run.nFlags);
/* TODO: emit embedded objects */
if (p->member.run.nFlags & MERF_GRAPHICS)
FIXME("embedded objects are not handled\n");
if (p->member.run.nFlags & MERF_ENDPARA) {
if (!ME_StreamOutPrint(editor, "\r\n\\par"))
return FALSE;
nChars--;
} else {
int nEnd;
if (!ME_StreamOutPrint(editor, "{"))
return FALSE;
TRACE("style %p\n", p->member.run.style);
if (!ME_StreamOutRTFCharProps(editor, &p->member.run.style->fmt))
return FALSE;
nEnd = (p == pEnd) ? nEndLen : ME_StrLen(p->member.run.strText);
if (!ME_StreamOutRTFText(editor, p->member.run.strText->szData + nOffset, nEnd - nOffset))
return FALSE;
nOffset = 0;
if (!ME_StreamOutPrint(editor, "}"))
return FALSE;
}
break;
default: /* we missed the last item */
assert(0);
}
if (p == pEnd)
break;
p = ME_FindItemFwd(p, diRunOrParagraphOrEnd);
}
if (!ME_StreamOutPrint(editor, "}"))
return FALSE;
return TRUE;
}
static BOOL
ME_StreamOutText(ME_TextEditor *editor, int nStart, int nChars, DWORD dwFormat)
{
/* FIXME: use ME_RunOfsFromCharOfs */
ME_DisplayItem *item = ME_FindItemAtOffset(editor, diRun, nStart, &nStart);
int nLen;
UINT nCodePage = CP_ACP;
BYTE *buffer = NULL;
int nBufLen = 0;
BOOL success = TRUE;
if (!item)
return FALSE;
if (dwFormat & SF_USECODEPAGE)
nCodePage = HIWORD(dwFormat);
/* TODO: Handle SF_TEXTIZED */
while (success && nChars && item) {
nLen = ME_StrLen(item->member.run.strText) - nStart;
if (nLen > nChars)
nLen = nChars;
if (item->member.run.nFlags & MERF_ENDPARA) {
WCHAR szEOL[] = { '\r', '\n' };
if (dwFormat & SF_UNICODE)
success = ME_StreamOutMove(editor, (BYTE *)szEOL, 4);
else
success = ME_StreamOutMove(editor, "\r\n", 2);
} else {
if (dwFormat & SF_UNICODE)
success = ME_StreamOutMove(editor, (BYTE *)(item->member.run.strText->szData + nStart),
sizeof(WCHAR) * nLen);
else {
int nSize;
nSize = WideCharToMultiByte(nCodePage, 0, item->member.run.strText->szData + nStart,
nLen, NULL, 0, NULL, NULL);
if (nSize > nBufLen) {
if (buffer)
FREE_OBJ(buffer);
buffer = ALLOC_N_OBJ(BYTE, nSize);
nBufLen = nSize;
}
WideCharToMultiByte(nCodePage, 0, item->member.run.strText->szData + nStart,
nLen, buffer, nSize, NULL, NULL);
success = ME_StreamOutMove(editor, buffer, nSize - 1);
}
}
nChars -= nLen;
nStart = 0;
item = ME_FindItemFwd(item, diRun);
}
if (buffer)
FREE_OBJ(buffer);
return success;
}
LRESULT
ME_StreamOut(ME_TextEditor *editor, DWORD dwFormat, EDITSTREAM *stream)
{
int nStart, nTo;
ME_StreamOutInit(editor, stream);
if (dwFormat & SFF_SELECTION)
ME_GetSelection(editor, &nStart, &nTo);
else {
nStart = 0;
nTo = -1;
}
if (nTo == -1)
nTo = ME_GetTextLength(editor);
TRACE("from %d to %d\n", nStart, nTo);
if (dwFormat & SF_RTF || dwFormat & SF_RTFNOOBJS)
ME_StreamOutRTF(editor, nStart, nTo - nStart, dwFormat);
else if (dwFormat & SF_TEXT || dwFormat & SF_TEXTIZED)
ME_StreamOutText(editor, nStart, nTo - nStart, dwFormat);
ME_StreamOutFlush(editor);
return ME_StreamOutFree(editor);
}

View file

@ -59,6 +59,19 @@ extern "C" {
#define CFE_AUTOBACKCOLOR 0x04000000
#define CFE_SUBSCRIPT 0x00010000
#define CFE_SUPERSCRIPT 0x00020000
#define CFE_ALLCAPS CFM_ALLCAPS
#define CFE_EMBOSS CFM_EMBOSS
#define CFE_HIDDEN CFM_HIDDEN
#define CFE_IMPRINT CFM_IMPRINT
#define CFE_OUTLINE CFM_OUTLINE
#define CFE_SHADOW CFM_SHADOW
#define CFE_SMALLCAPS CFM_SMALLCAPS
#define CFU_CF1UNDERLINE 0xff
#define CFU_UNDERLINENONE 0
#define CFU_UNDERLINE 1
#define CFU_UNDERLINEWORD 2
#define CFU_UNDERLINEDOUBLE 3
#define CFU_UNDERLINEDOTTED 4
#define IMF_FORCENONE 1
#define IMF_FORCEENABLE 2
#define IMF_FORCEDISABLE 4
@ -453,7 +466,7 @@ typedef struct _paraformat2 {
LONG dySpaceBefore;
LONG dySpaceAfter;
LONG dyLineSpacing;
SHORT sStype;
SHORT sStyle;
BYTE bLineSpacingRule;
BYTE bOutlineLevel;
WORD wShadingWeight;