reactos/dll/win32/riched20/list.c

233 lines
6.2 KiB
C
Raw Normal View History

/*
* RichEdit - Basic operations on double linked lists.
*
* Copyright 2004 by Krzysztof Foltman
*
* 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
#include "editor.h"
Sync to Wine-0_9: Phil Krylov <phil@newstar.rinet.ru> - Fixed encoding of non-ASCII chars. Krzysztof Foltman <wdev@foltman.com> - Bugfix in EM_GETTEXTEX - Additional traces helpful in diagnosing similar (text retrieval-related) bugs. - Fix unnecessary (and harmful) repeated statement. - Removed buffer overrun error (incrementing output pointer one time too much in non-CRLF mode) making KeyNote fail to install. - Style trace information is written to different debug channel (it's not very useful anymore, reference counting looks correct for now). - The document dump contains the character position of the end-of-text mark. - The previous implementation was a workaround for off-by-one bug in ME_RunOfsFromCharOfs, this one relies on correct behavior of that function introduced by the previous patch. - Send verbose info to different debug channels (richedit_check for output from offset checker, richedit_lists for the document list dumps). - Fix a bug in 1.0 emulation mode in EM_LINELENGTH (which broke PTE installer). - Fixed EOL detection in ME_RunOfsFromCharOfs in 1.0 emulation mode (necessary for a non-workaround version of EM_POSFROMCHAR). - Fix 1.0 emulation mode in ME_GetTextW. - Remove another potential sources of infinite loops caused by EOF in the middle of the font and color tables. - Closing brace on text level is treated as EOF (effectively protecting the control from trash after the end of RTF). - Removed misleading comment about incomplete buffers (I was definitely wrong). - Implemented EM_GETFIRSTVISIBLELINE and EM_POSFROMCHAR (basic suboptimal implementation, can be optimized to skip whole paragraphs later if it's useful at all). - Fixed another case of misunderstanding MSDN wrt StreamInProc, causing license text to be truncated in Picasa installer (as well as some other programs, especially those that display long texts with NSIS). svn path=/trunk/; revision=18955
2005-11-02 20:03:07 +00:00
WINE_DEFAULT_DEBUG_CHANNEL(richedit_lists);
void ME_InsertBefore(ME_DisplayItem *diWhere, ME_DisplayItem *diWhat)
{
diWhat->next = diWhere;
diWhat->prev = diWhere->prev;
diWhere->prev->next = diWhat;
diWhat->next->prev = diWhat;
}
void ME_Remove(ME_DisplayItem *diWhere)
{
ME_DisplayItem *diNext = diWhere->next;
ME_DisplayItem *diPrev = diWhere->prev;
assert(diNext);
assert(diPrev);
diPrev->next = diNext;
diNext->prev = diPrev;
}
static BOOL ME_DITypesEqual(ME_DIType type, ME_DIType nTypeOrClass)
{
switch (nTypeOrClass)
{
case diRunOrParagraph:
return type == diRun || type == diParagraph;
case diRunOrStartRow:
return type == diRun || type == diStartRow;
case diParagraphOrEnd:
return type == diTextEnd || type == diParagraph;
case diStartRowOrParagraph:
return type == diStartRow || type == diParagraph;
case diStartRowOrParagraphOrEnd:
return type == diStartRow || type == diParagraph || type == diTextEnd;
case diRunOrParagraphOrEnd:
return type == diRun || type == diParagraph || type == diTextEnd;
default:
return type == nTypeOrClass;
}
}
/* Modifies run pointer to point to the next run.
* If all_para is FALSE constrain the search to the current para,
* otherwise modify the paragraph pointer if moving into the next paragraph.
*
* Returns TRUE if next run is found, otherwise returns FALSE. */
BOOL ME_NextRun(ME_DisplayItem **para, ME_DisplayItem **run, BOOL all_para)
{
ME_DisplayItem *p = (*run)->next;
while (p->type != diTextEnd)
{
if (p->type == diParagraph) {
if (!all_para) return FALSE;
*para = p;
} else if (p->type == diRun) {
*run = p;
return TRUE;
}
p = p->next;
}
return FALSE;
}
/* Modifies run pointer to point to the previous run.
* If all_para is FALSE constrain the search to the current para,
* otherwise modify the paragraph pointer if moving into the previous paragraph.
*
* Returns TRUE if previous run is found, otherwise returns FALSE. */
BOOL ME_PrevRun(ME_DisplayItem **para, ME_DisplayItem **run, BOOL all_para)
{
ME_DisplayItem *p = (*run)->prev;
while (p->type != diTextStart)
{
if (p->type == diParagraph) {
if (!all_para) return FALSE;
if (para && p->member.para.prev_para->type == diParagraph)
*para = p->member.para.prev_para;
} else if (p->type == diRun) {
*run = p;
return TRUE;
}
p = p->prev;
}
return FALSE;
}
ME_DisplayItem *ME_FindItemBack(ME_DisplayItem *di, ME_DIType nTypeOrClass)
{
if (!di)
return NULL;
di = di->prev;
while(di!=NULL) {
if (ME_DITypesEqual(di->type, nTypeOrClass))
return di;
di = di->prev;
}
return NULL;
}
ME_DisplayItem *ME_FindItemBackOrHere(ME_DisplayItem *di, ME_DIType nTypeOrClass)
{
while(di!=NULL) {
if (ME_DITypesEqual(di->type, nTypeOrClass))
return di;
di = di->prev;
}
return NULL;
}
ME_DisplayItem *ME_FindItemFwd(ME_DisplayItem *di, ME_DIType nTypeOrClass)
{
if (!di) return NULL;
di = di->next;
while(di!=NULL) {
if (ME_DITypesEqual(di->type, nTypeOrClass))
return di;
di = di->next;
}
return NULL;
}
static const char *ME_GetDITypeName(ME_DIType type)
{
switch(type)
{
case diParagraph: return "diParagraph";
case diRun: return "diRun";
case diCell: return "diCell";
case diTextStart: return "diTextStart";
case diTextEnd: return "diTextEnd";
case diStartRow: return "diStartRow";
default: return "?";
}
}
void ME_DestroyDisplayItem(ME_DisplayItem *item)
{
if (0)
TRACE("type=%s\n", ME_GetDITypeName(item->type));
if (item->type==diParagraph)
{
ME_DestroyString(item->member.para.text);
para_num_clear( &item->member.para.para_num );
}
if (item->type==diRun)
{
if (item->member.run.reobj)
{
list_remove(&item->member.run.reobj->entry);
ME_DeleteReObject(item->member.run.reobj);
}
heap_free( item->member.run.glyphs );
heap_free( item->member.run.clusters );
ME_ReleaseStyle(item->member.run.style);
}
heap_free(item);
}
ME_DisplayItem *ME_MakeDI(ME_DIType type)
{
ME_DisplayItem *item = heap_alloc_zero(sizeof(*item));
item->type = type;
item->prev = item->next = NULL;
return item;
}
void ME_DumpDocument(ME_TextBuffer *buffer)
{
/* FIXME this is useless, */
ME_DisplayItem *pItem = buffer->pFirst;
TRACE("DOCUMENT DUMP START\n");
while(pItem) {
switch(pItem->type)
{
case diTextStart:
TRACE("Start\n");
break;
case diCell:
TRACE("Cell(level=%d%s)\n", pItem->member.cell.nNestingLevel,
!pItem->member.cell.next_cell ? ", END" :
(!pItem->member.cell.prev_cell ? ", START" :""));
break;
case diParagraph:
TRACE("Paragraph(ofs=%d)\n", pItem->member.para.nCharOfs);
if (pItem->member.para.nFlags & MEPF_ROWSTART)
TRACE(" - (Table Row Start)\n");
if (pItem->member.para.nFlags & MEPF_ROWEND)
TRACE(" - (Table Row End)\n");
break;
case diStartRow:
TRACE(" - StartRow\n");
break;
case diRun:
TRACE(" - Run(%s, %d, flags=%x)\n", debugstr_run( &pItem->member.run ),
pItem->member.run.nCharOfs, pItem->member.run.nFlags);
break;
case diTextEnd:
TRACE("End(ofs=%d)\n", pItem->member.para.nCharOfs);
break;
default:
break;
}
pItem = pItem->next;
}
TRACE("DOCUMENT DUMP END\n");
}