[2/8] richedit: Use ME_Cursor instead of offsets for ME_UpdateLinkAttribute.
Dylan Smith
dylan.ah.smith at gmail.com
Thu Aug 13 07:44:02 CDT 2009
---
dlls/riched20/editor.c | 213 +++++++++++++++++++++++++-----------------------
1 files changed, 111 insertions(+), 102 deletions(-)
-------------- next part --------------
diff --git a/dlls/riched20/editor.c b/dlls/riched20/editor.c
index e9da20b..685e0f1 100644
--- a/dlls/riched20/editor.c
+++ b/dlls/riched20/editor.c
@@ -241,7 +241,7 @@
WINE_DEFAULT_DEBUG_CHANNEL(richedit);
static BOOL ME_RegisterEditorClass(HINSTANCE);
-static BOOL ME_UpdateLinkAttribute(ME_TextEditor *editor, int sel_min, int sel_max);
+static BOOL ME_UpdateLinkAttribute(ME_TextEditor *editor, ME_Cursor *start, int nChars);
static const WCHAR REListBox20W[] = {'R','E','L','i','s','t','B','o','x','2','0','W', 0};
static const WCHAR REComboBox20W[] = {'R','E','C','o','m','b','o','B','o','x','2','0','W', 0};
@@ -2047,6 +2047,8 @@ static void ME_UpdateSelectionLinkAttribute(ME_TextEditor *editor)
ME_DisplayItem *startPara, *endPara;
ME_DisplayItem *prev_para;
ME_Cursor *from, *to;
+ ME_Cursor start;
+ int nChars;
if (!editor->AutoURLDetect_bEnable) return;
@@ -2060,9 +2062,12 @@ static void ME_UpdateSelectionLinkAttribute(ME_TextEditor *editor)
/* Find paragraph that contains end cursor */
endPara = to->pPara->member.para.next_para;
- ME_UpdateLinkAttribute(editor,
- startPara->member.para.nCharOfs,
- endPara->member.para.nCharOfs);
+ start.pPara = startPara;
+ start.pRun = ME_FindItemFwd(startPara, diRun);
+ start.nOffset = 0;
+ nChars = endPara->member.para.nCharOfs - startPara->member.para.nCharOfs;
+
+ ME_UpdateLinkAttribute(editor, &start, nChars);
}
static BOOL
@@ -3239,8 +3244,10 @@ LRESULT ME_HandleMessage(ME_TextEditor *editor, UINT msg, WPARAM wParam,
ME_ReleaseStyle(style);
ME_UpdateSelectionLinkAttribute(editor);
} else {
+ ME_Cursor cursor;
len = 1;
- ME_UpdateLinkAttribute(editor, 0, -1);
+ ME_SetCursorToStart(editor, &cursor);
+ ME_UpdateLinkAttribute(editor, &cursor, INT_MAX);
}
ME_CommitUndo(editor);
if (!(pStruct->flags & ST_KEEPUNDO))
@@ -3471,6 +3478,7 @@ LRESULT ME_HandleMessage(ME_TextEditor *editor, UINT msg, WPARAM wParam,
}
case WM_SETTEXT:
{
+ ME_Cursor updateLinksStart;
ME_InternalDeleteText(editor, 0, ME_GetTextLength(editor), FALSE);
if (lParam)
{
@@ -3505,7 +3513,8 @@ LRESULT ME_HandleMessage(ME_TextEditor *editor, UINT msg, WPARAM wParam,
}
else
TRACE("WM_SETTEXT - NULL\n");
- ME_UpdateLinkAttribute(editor, 0, -1);
+ ME_SetCursorToStart(editor, &updateLinksStart);
+ ME_UpdateLinkAttribute(editor, &updateLinksStart, INT_MAX);
ME_SetSelection(editor, 0, 0);
editor->nModifyStep = 0;
ME_CommitUndo(editor);
@@ -4671,93 +4680,97 @@ static BOOL isurlspecial(WCHAR c)
* or one of the following special characters: *|/\+%#@ and must consist entirely
* of the characters allowed to start the URL, plus : (colon) which may occur
* at most once, and not at either end.
- *
- * sel_max == -1 indicates scan to end of text.
*/
-static BOOL ME_FindNextURLCandidate(ME_TextEditor *editor, int sel_min, int sel_max,
- int * candidate_min, int * candidate_max)
+static BOOL ME_FindNextURLCandidate(ME_TextEditor *editor,
+ const ME_Cursor *start,
+ int nChars,
+ ME_Cursor *candidate_min,
+ ME_Cursor *candidate_max)
{
- ME_DisplayItem * item;
- ME_DisplayItem * para;
- int nStart;
+ ME_Cursor cursor = *start;
BOOL foundColon = FALSE;
+ BOOL candidateStarted = FALSE;
WCHAR lastAcceptedChar = '\0';
- TRACE("sel_min = %d sel_max = %d\n", sel_min, sel_max);
-
- *candidate_min = *candidate_max = -1;
- ME_RunOfsFromCharOfs(editor, sel_min, ¶, &item, &nStart);
- TRACE("nStart = %d\n", nStart);
- if (sel_max == -1) sel_max = ME_GetTextLength(editor);
- while (item && para->member.para.nCharOfs + item->member.run.nCharOfs + nStart < sel_max)
+ while (nChars > 0)
{
- if (!(item->member.run.nFlags & MERF_ENDPARA)) {
+ WCHAR *strStart = cursor.pRun->member.run.strText->szData;
+ WCHAR *str = strStart + cursor.nOffset;
+ int nLen = cursor.pRun->member.run.strText->nLen - cursor.nOffset;
+ nChars -= nLen;
+
+ if (~cursor.pRun->member.run.nFlags & MERF_ENDPARA)
+ {
/* Find start of candidate */
- if (*candidate_min == -1) {
- while (nStart < item->member.run.strText->nLen &&
- !(isalnumW(item->member.run.strText->szData[nStart]) ||
- isurlspecial(item->member.run.strText->szData[nStart]))) {
- nStart++;
- }
- if (nStart < item->member.run.strText->nLen &&
- (isalnumW(item->member.run.strText->szData[nStart]) ||
- isurlspecial(item->member.run.strText->szData[nStart]))) {
- *candidate_min = para->member.para.nCharOfs + item->member.run.nCharOfs + nStart;
- lastAcceptedChar = item->member.run.strText->szData[nStart];
- nStart++;
+ if (!candidateStarted)
+ {
+ while (nLen)
+ {
+ nLen--;
+ if (isalnumW(*str) || isurlspecial(*str))
+ {
+ cursor.nOffset = str - strStart;
+ *candidate_min = cursor;
+ candidateStarted = TRUE;
+ lastAcceptedChar = *str++;
+ break;
+ }
+ str++;
}
}
/* Find end of candidate */
- if (*candidate_min >= 0) {
- while (nStart < item->member.run.strText->nLen &&
- (isalnumW(item->member.run.strText->szData[nStart]) ||
- isurlspecial(item->member.run.strText->szData[nStart]) ||
- (!foundColon && item->member.run.strText->szData[nStart] == ':') )) {
- if (item->member.run.strText->szData[nStart] == ':') foundColon = TRUE;
- lastAcceptedChar = item->member.run.strText->szData[nStart];
- nStart++;
- }
- if (nStart < item->member.run.strText->nLen &&
- !(isalnumW(item->member.run.strText->szData[nStart]) ||
- isurlspecial(item->member.run.strText->szData[nStart]) )) {
- *candidate_max = para->member.para.nCharOfs + item->member.run.nCharOfs + nStart;
- nStart++;
- if (lastAcceptedChar == ':') (*candidate_max)--;
- return TRUE;
+ if (candidateStarted) {
+ while (nLen)
+ {
+ nLen--;
+ if (*str == ':' && !foundColon) {
+ foundColon = TRUE;
+ } else if (!isalnumW(*str) && !isurlspecial(*str)) {
+ cursor.nOffset = str - strStart;
+ if (lastAcceptedChar == ':')
+ ME_MoveCursorChars(editor, &cursor, -1);
+ *candidate_max = cursor;
+ return TRUE;
+ }
+ lastAcceptedChar = *str++;
}
}
} else {
/* End of paragraph: skip it if before candidate span, or terminates
current active span */
- if (*candidate_min >= 0) {
- *candidate_max = para->member.para.nCharOfs + item->member.run.nCharOfs;
- if (lastAcceptedChar == ':') (*candidate_max)--;
+ if (candidateStarted) {
+ if (lastAcceptedChar == ':')
+ ME_MoveCursorChars(editor, &cursor, -1);
+ *candidate_max = cursor;
return TRUE;
}
}
/* Reaching this point means no span was found, so get next span */
- if (!ME_NextRun(¶, &item)) {
- if (*candidate_min >= 0) {
+ if (!ME_NextRun(&cursor.pPara, &cursor.pRun)) {
+ if (candidateStarted) {
/* There are no further runs, so take end of text as end of candidate */
- *candidate_max = para->member.para.nCharOfs + item->member.run.nCharOfs + nStart;
- if (lastAcceptedChar == ':') (*candidate_max)--;
+ cursor.nOffset = str - strStart;
+ if (lastAcceptedChar == ':')
+ ME_MoveCursorChars(editor, &cursor, -1);
+ *candidate_max = cursor;
return TRUE;
}
+ *candidate_max = *candidate_min = cursor;
return FALSE;
}
- nStart = 0;
+ cursor.nOffset = 0;
}
- if (item) {
- if (*candidate_min >= 0) {
- /* There are no further runs, so take end of text as end of candidate */
- *candidate_max = para->member.para.nCharOfs + item->member.run.nCharOfs + nStart;
- if (lastAcceptedChar == ':') (*candidate_max)--;
- return TRUE;
- }
+ if (candidateStarted) {
+ /* There are no further runs, so take end of text as end of candidate */
+ if (lastAcceptedChar == ':')
+ ME_MoveCursorChars(editor, &cursor, -1);
+ *candidate_max = cursor;
+ return TRUE;
}
+ *candidate_max = *candidate_min = cursor;
return FALSE;
}
@@ -4804,59 +4817,48 @@ static BOOL ME_IsCandidateAnURL(ME_TextEditor *editor, const ME_Cursor *start, i
* their proper CFE_LINK attributes set or unset. If the CFE_LINK attribute is
* not what it is supposed to be, this proc sets or unsets it as appropriate.
*
+ * Since this function can cause runs to be split, do not depend on the value
+ * of the start cursor at the end of the function.
+ *
+ * nChars may be set to INT_MAX to update to the end of the text.
+ *
* Returns TRUE if at least one section was modified.
*/
-static BOOL ME_UpdateLinkAttribute(ME_TextEditor *editor, int sel_min, int sel_max)
+static BOOL ME_UpdateLinkAttribute(ME_TextEditor *editor, ME_Cursor *start, int nChars)
{
BOOL modified = FALSE;
- int cMin, cMax;
+ ME_Cursor startCur = *start;
if (!editor->AutoURLDetect_bEnable) return FALSE;
- if (sel_max == -1) sel_max = ME_GetTextLength(editor);
do
{
- int beforeURL[2];
- int inURL[2];
CHARFORMAT2W link;
+ ME_Cursor candidateStart, candidateEnd;
- if (ME_FindNextURLCandidate(editor, sel_min, sel_max, &cMin, &cMax))
+ if (ME_FindNextURLCandidate(editor, &startCur, nChars,
+ &candidateStart, &candidateEnd))
{
- ME_Cursor candidateStart;
/* Section before candidate is not an URL */
- beforeURL[0] = sel_min;
- beforeURL[1] = cMin;
+ int cMin = ME_GetCursorOfs(&candidateStart);
+ int cMax = ME_GetCursorOfs(&candidateEnd);
- ME_CursorFromCharOfs(editor, cMin, &candidateStart);
- if (ME_IsCandidateAnURL(editor, &candidateStart,
- (cMax == -1 ? INT_MAX : cMax) - cMin))
- {
- inURL[0] = cMin; inURL[1] = cMax;
- }
- else
- {
- beforeURL[1] = cMax;
- inURL[0] = inURL[1] = -1;
- }
- sel_min = cMax;
+ if (!ME_IsCandidateAnURL(editor, &candidateStart, cMax - cMin))
+ candidateStart = candidateEnd;
+ nChars -= cMax - ME_GetCursorOfs(&startCur);
}
else
{
/* No more candidates until end of selection */
- beforeURL[0] = sel_min;
- beforeURL[1] = sel_max;
- inURL[0] = inURL[1] = -1;
- sel_min = sel_max;
+ nChars = 0;
}
- if (beforeURL[0] < beforeURL[1])
+ if (startCur.pRun != candidateStart.pRun ||
+ startCur.nOffset != candidateStart.nOffset)
{
- ME_Cursor from, to;
- ME_CursorFromCharOfs(editor, beforeURL[0], &from);
- ME_CursorFromCharOfs(editor, beforeURL[1], &to);
/* CFE_LINK effect should be consistently unset */
link.cbSize = sizeof(link);
- ME_GetCharFormat(editor, &from, &to, &link);
+ ME_GetCharFormat(editor, &startCur, &candidateStart, &link);
if (!(link.dwMask & CFM_LINK) || (link.dwEffects & CFE_LINK))
{
/* CFE_LINK must be unset from this range */
@@ -4864,18 +4866,24 @@ static BOOL ME_UpdateLinkAttribute(ME_TextEditor *editor, int sel_min, int sel_m
link.cbSize = sizeof(link);
link.dwMask = CFM_LINK;
link.dwEffects = 0;
- ME_SetCharFormat(editor, &from, &to, &link);
+ ME_SetCharFormat(editor, &startCur, &candidateStart, &link);
+ /* Update candidateEnd since setting character formats may split
+ * runs, which can cause a cursor to be at an invalid offset within
+ * a split run. */
+ while (candidateEnd.nOffset >= candidateEnd.pRun->member.run.strText->nLen)
+ {
+ candidateEnd.nOffset -= candidateEnd.pRun->member.run.strText->nLen;
+ candidateEnd.pRun = ME_FindItemFwd(candidateEnd.pRun, diRun);
+ }
modified = TRUE;
}
}
- if (inURL[0] < inURL[1])
+ if (candidateStart.pRun != candidateEnd.pRun ||
+ candidateStart.nOffset != candidateEnd.nOffset)
{
- ME_Cursor from, to;
- ME_CursorFromCharOfs(editor, inURL[0], &from);
- ME_CursorFromCharOfs(editor, inURL[1], &to);
/* CFE_LINK effect should be consistently set */
link.cbSize = sizeof(link);
- ME_GetCharFormat(editor, &from, &to, &link);
+ ME_GetCharFormat(editor, &candidateStart, &candidateEnd, &link);
if (!(link.dwMask & CFM_LINK) || !(link.dwEffects & CFE_LINK))
{
/* CFE_LINK must be set on this range */
@@ -4883,10 +4891,11 @@ static BOOL ME_UpdateLinkAttribute(ME_TextEditor *editor, int sel_min, int sel_m
link.cbSize = sizeof(link);
link.dwMask = CFM_LINK;
link.dwEffects = CFE_LINK;
- ME_SetCharFormat(editor, &from, &to, &link);
+ ME_SetCharFormat(editor, &candidateStart, &candidateEnd, &link);
modified = TRUE;
}
}
- } while (sel_min < sel_max);
+ startCur = candidateEnd;
+ } while (nChars > 0);
return modified;
}
More information about the wine-patches
mailing list