1 /* 2 * RichEdit - Basic operations on double linked lists. 3 * 4 * Copyright 2004 by Krzysztof Foltman 5 * 6 * This library is free software; you can redistribute it and/or 7 * modify it under the terms of the GNU Lesser General Public 8 * License as published by the Free Software Foundation; either 9 * version 2.1 of the License, or (at your option) any later version. 10 * 11 * This library is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 * Lesser General Public License for more details. 15 * 16 * You should have received a copy of the GNU Lesser General Public 17 * License along with this library; if not, write to the Free Software 18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 19 */ 20 21 22 #include "editor.h" 23 24 WINE_DEFAULT_DEBUG_CHANNEL(richedit_lists); 25 26 void ME_InsertBefore(ME_DisplayItem *diWhere, ME_DisplayItem *diWhat) 27 { 28 diWhat->next = diWhere; 29 diWhat->prev = diWhere->prev; 30 31 diWhere->prev->next = diWhat; 32 diWhat->next->prev = diWhat; 33 } 34 35 void ME_Remove(ME_DisplayItem *diWhere) 36 { 37 ME_DisplayItem *diNext = diWhere->next; 38 ME_DisplayItem *diPrev = diWhere->prev; 39 assert(diNext); 40 assert(diPrev); 41 diPrev->next = diNext; 42 diNext->prev = diPrev; 43 } 44 45 static BOOL ME_DITypesEqual(ME_DIType type, ME_DIType nTypeOrClass) 46 { 47 switch (nTypeOrClass) 48 { 49 case diRunOrParagraph: 50 return type == diRun || type == diParagraph; 51 case diRunOrStartRow: 52 return type == diRun || type == diStartRow; 53 case diParagraphOrEnd: 54 return type == diTextEnd || type == diParagraph; 55 case diStartRowOrParagraph: 56 return type == diStartRow || type == diParagraph; 57 case diStartRowOrParagraphOrEnd: 58 return type == diStartRow || type == diParagraph || type == diTextEnd; 59 case diRunOrParagraphOrEnd: 60 return type == diRun || type == diParagraph || type == diTextEnd; 61 default: 62 return type == nTypeOrClass; 63 } 64 } 65 66 /* Modifies run pointer to point to the next run. 67 * If all_para is FALSE constrain the search to the current para, 68 * otherwise modify the paragraph pointer if moving into the next paragraph. 69 * 70 * Returns TRUE if next run is found, otherwise returns FALSE. */ 71 BOOL ME_NextRun(ME_DisplayItem **para, ME_DisplayItem **run, BOOL all_para) 72 { 73 ME_DisplayItem *p = (*run)->next; 74 while (p->type != diTextEnd) 75 { 76 if (p->type == diParagraph) { 77 if (!all_para) return FALSE; 78 *para = p; 79 } else if (p->type == diRun) { 80 *run = p; 81 return TRUE; 82 } 83 p = p->next; 84 } 85 return FALSE; 86 } 87 88 /* Modifies run pointer to point to the previous run. 89 * If all_para is FALSE constrain the search to the current para, 90 * otherwise modify the paragraph pointer if moving into the previous paragraph. 91 * 92 * Returns TRUE if previous run is found, otherwise returns FALSE. */ 93 BOOL ME_PrevRun(ME_DisplayItem **para, ME_DisplayItem **run, BOOL all_para) 94 { 95 ME_DisplayItem *p = (*run)->prev; 96 while (p->type != diTextStart) 97 { 98 if (p->type == diParagraph) { 99 if (!all_para) return FALSE; 100 if (para && p->member.para.prev_para->type == diParagraph) 101 *para = p->member.para.prev_para; 102 } else if (p->type == diRun) { 103 *run = p; 104 return TRUE; 105 } 106 p = p->prev; 107 } 108 return FALSE; 109 } 110 111 ME_DisplayItem *ME_FindItemBack(ME_DisplayItem *di, ME_DIType nTypeOrClass) 112 { 113 if (!di) 114 return NULL; 115 di = di->prev; 116 while(di!=NULL) { 117 if (ME_DITypesEqual(di->type, nTypeOrClass)) 118 return di; 119 di = di->prev; 120 } 121 return NULL; 122 } 123 124 ME_DisplayItem *ME_FindItemBackOrHere(ME_DisplayItem *di, ME_DIType nTypeOrClass) 125 { 126 while(di!=NULL) { 127 if (ME_DITypesEqual(di->type, nTypeOrClass)) 128 return di; 129 di = di->prev; 130 } 131 return NULL; 132 } 133 134 ME_DisplayItem *ME_FindItemFwd(ME_DisplayItem *di, ME_DIType nTypeOrClass) 135 { 136 if (!di) return NULL; 137 di = di->next; 138 while(di!=NULL) { 139 if (ME_DITypesEqual(di->type, nTypeOrClass)) 140 return di; 141 di = di->next; 142 } 143 return NULL; 144 } 145 146 static const char *ME_GetDITypeName(ME_DIType type) 147 { 148 switch(type) 149 { 150 case diParagraph: return "diParagraph"; 151 case diRun: return "diRun"; 152 case diCell: return "diCell"; 153 case diTextStart: return "diTextStart"; 154 case diTextEnd: return "diTextEnd"; 155 case diStartRow: return "diStartRow"; 156 default: return "?"; 157 } 158 } 159 160 void ME_DestroyDisplayItem(ME_DisplayItem *item) 161 { 162 if (0) 163 TRACE("type=%s\n", ME_GetDITypeName(item->type)); 164 if (item->type==diParagraph) 165 { 166 ME_DestroyString(item->member.para.text); 167 para_num_clear( &item->member.para.para_num ); 168 } 169 170 if (item->type==diRun) 171 { 172 if (item->member.run.reobj) 173 { 174 list_remove(&item->member.run.reobj->entry); 175 ME_DeleteReObject(item->member.run.reobj); 176 } 177 heap_free( item->member.run.glyphs ); 178 heap_free( item->member.run.clusters ); 179 ME_ReleaseStyle(item->member.run.style); 180 } 181 heap_free(item); 182 } 183 184 ME_DisplayItem *ME_MakeDI(ME_DIType type) 185 { 186 ME_DisplayItem *item = heap_alloc_zero(sizeof(*item)); 187 188 item->type = type; 189 item->prev = item->next = NULL; 190 return item; 191 } 192 193 void ME_DumpDocument(ME_TextBuffer *buffer) 194 { 195 /* FIXME this is useless, */ 196 ME_DisplayItem *pItem = buffer->pFirst; 197 TRACE("DOCUMENT DUMP START\n"); 198 while(pItem) { 199 switch(pItem->type) 200 { 201 case diTextStart: 202 TRACE("Start\n"); 203 break; 204 case diCell: 205 TRACE("Cell(level=%d%s)\n", pItem->member.cell.nNestingLevel, 206 !pItem->member.cell.next_cell ? ", END" : 207 (!pItem->member.cell.prev_cell ? ", START" :"")); 208 break; 209 case diParagraph: 210 TRACE("Paragraph(ofs=%d)\n", pItem->member.para.nCharOfs); 211 if (pItem->member.para.nFlags & MEPF_ROWSTART) 212 TRACE(" - (Table Row Start)\n"); 213 if (pItem->member.para.nFlags & MEPF_ROWEND) 214 TRACE(" - (Table Row End)\n"); 215 break; 216 case diStartRow: 217 TRACE(" - StartRow\n"); 218 break; 219 case diRun: 220 TRACE(" - Run(%s, %d, flags=%x)\n", debugstr_run( &pItem->member.run ), 221 pItem->member.run.nCharOfs, pItem->member.run.nFlags); 222 break; 223 case diTextEnd: 224 TRACE("End(ofs=%d)\n", pItem->member.para.nCharOfs); 225 break; 226 default: 227 break; 228 } 229 pItem = pItem->next; 230 } 231 TRACE("DOCUMENT DUMP END\n"); 232 } 233