From 2551f96c4652be256bc2480e4fcc05c7065f6665 Mon Sep 17 00:00:00 2001 From: vincentdarley Date: Sat, 8 Nov 2003 17:22:45 +0000 Subject: elide tag handling, once more --- ChangeLog | 11 ++++ generic/tkText.h | 17 ++--- generic/tkTextBTree.c | 25 ++++++-- generic/tkTextDisp.c | 57 ++++++++++++----- generic/tkTextIndex.c | 171 +++++++++++++++++++++++++++++++++++--------------- tests/text.test | 26 +++++++- tests/textDisp.test | 16 ++++- 7 files changed, 241 insertions(+), 82 deletions(-) diff --git a/ChangeLog b/ChangeLog index cbc26a8..83bbd55 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,14 @@ +2003-11-08 Vince Darley + + * tests/textDisp.test: + * tests/text.test: + * generic/tkText.h: + * generic/tkTextIndex.c: + * generic/tkTextBTree.c: + * generic/tkTextDisp.c: fix to another version of [Bug 833627] + (crash in tkchat), adding more tests. I believe the handling of + nested elide tags of all types is now correct! + 2003-11-07 Vince Darley * tests/textDisp.test: diff --git a/generic/tkText.h b/generic/tkText.h index 89e4f7b..16e617a 100644 --- a/generic/tkText.h +++ b/generic/tkText.h @@ -10,7 +10,7 @@ * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tkText.h,v 1.18 2003/11/07 15:36:26 vincentdarley Exp $ + * RCS: @(#) $Id: tkText.h,v 1.19 2003/11/08 17:22:46 vincentdarley Exp $ */ #ifndef _TKTEXT @@ -827,13 +827,16 @@ typedef int TkTextCountType; #define LOTSA_TAGS 1000 typedef struct TkTextElideInfo { - int numTags; - int elide; - int elidePriority; - int deftagCnts[LOTSA_TAGS]; + int numTags; /* Total tags in widget */ + int elide; /* Is the state currently elided */ + int elidePriority; /* Tag priority controlling elide state */ + TkTextSegment *segPtr; /* Segment to look at next */ + int deftagCnts[LOTSA_TAGS]; TkTextTag *deftagPtrs[LOTSA_TAGS]; - int *tagCnts; - TkTextTag **tagPtrs; + int *tagCnts; /* 0 or 1 depending if the tag with + * that priority is on or off */ + TkTextTag **tagPtrs; /* Only filled with a tagPtr if the + * corresponding tagCnt is 1 */ } TkTextElideInfo; /* diff --git a/generic/tkTextBTree.c b/generic/tkTextBTree.c index 7be9e7d..22d91c7 100644 --- a/generic/tkTextBTree.c +++ b/generic/tkTextBTree.c @@ -11,7 +11,7 @@ * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tkTextBTree.c,v 1.9 2003/11/07 15:36:26 vincentdarley Exp $ + * RCS: @(#) $Id: tkTextBTree.c,v 1.10 2003/11/08 17:22:46 vincentdarley Exp $ */ #include "tkInt.h" @@ -2682,13 +2682,22 @@ TkBTreeGetTags(indexPtr, numTagsPtr) * TkTextIsElided -- * * Special case to just return information about elided attribute. - * Specialized from TkBTreeGetTags(indexPtr, numTagsPtr) - * and GetStyle(textPtr, indexPtr). - * Just need to keep track of invisibility settings for each priority, - * pick highest one active at end + * Specialized from TkBTreeGetTags(indexPtr, numTagsPtr) and + * GetStyle(textPtr, indexPtr). Just need to keep track of + * invisibility settings for each priority, pick highest one active + * at end. + * + * Note that this returns all elide information up to and including + * the given index (quite obviously). However, this does mean that + * indexPtr is a line-start and one then iterates from the beginning + * of that line forwards, one will actually revisit the segPtrs of + * size zero (for tag toggling, for example) which have already been + * seen here. * * Results: * Returns whether this text should be elided or not. + * + * Optionally returns more detailed information in elideInfo. * * Side effects: * None. @@ -2754,6 +2763,11 @@ TkTextIsElided(textPtr, indexPtr, elideInfo) } } } + /* + * Store the first segPtr we haven't examined completely + * so that our caller knows where to start. + */ + infoPtr->segPtr = segPtr; /* * Record toggles for tags in lines that are predecessors of @@ -2817,6 +2831,7 @@ TkTextIsElided(textPtr, indexPtr, elideInfo) } #endif infoPtr->elide = infoPtr->tagPtrs[i]->elide; + /* Note: i == infoPtr->tagPtrs[i]->priority */ infoPtr->elidePriority = i; break; } diff --git a/generic/tkTextDisp.c b/generic/tkTextDisp.c index 324b3ab..85a160d 100644 --- a/generic/tkTextDisp.c +++ b/generic/tkTextDisp.c @@ -13,7 +13,7 @@ * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tkTextDisp.c,v 1.24 2003/11/07 15:36:26 vincentdarley Exp $ + * RCS: @(#) $Id: tkTextDisp.c,v 1.25 2003/11/08 17:22:46 vincentdarley Exp $ */ #include "tkPort.h" @@ -957,9 +957,7 @@ LayoutDLine(textPtr, indexPtr) elide = TkTextIsElided(textPtr, indexPtr, &info); if (elide && indexPtr->byteIndex==0) { maxBytes = 0; - for (segPtr = indexPtr->linePtr->segPtr; - segPtr != NULL; - segPtr = segPtr->nextPtr) { + for (segPtr = info.segPtr; segPtr != NULL; segPtr = segPtr->nextPtr) { if (segPtr->size > 0) { if (elide == 0) { /* @@ -977,19 +975,45 @@ LayoutDLine(textPtr, indexPtr) } else if ((segPtr->typePtr == &tkTextToggleOffType) || (segPtr->typePtr == &tkTextToggleOnType)) { TkTextTag *tagPtr = segPtr->body.toggle.tagPtr; - if (tagPtr->elideString != NULL - && (tagPtr->priority >= info.elidePriority)) { - elide = ((segPtr->typePtr == &tkTextToggleOffType) - ^ tagPtr->elide); - if (!elide && tagPtr->priority == info.elidePriority) { - /* Find previous elide tag, if any */ - while (--info.elidePriority > 0) { - if (info.tagCnts[info.elidePriority] & 1) { - break; + /* + * The elide state only changes if this tag is + * either the current highest priority tag + * (and is therefore being toggled off), or it's + * a new tag with higher priority. + */ + if (tagPtr->elideString != NULL) { + info.tagCnts[tagPtr->priority]++; + if (info.tagCnts[tagPtr->priority] & 1) { + info.tagPtrs[tagPtr->priority] = tagPtr; + } + if (tagPtr->priority >= info.elidePriority) { + if (segPtr->typePtr == &tkTextToggleOffType) { + /* + * If it is being toggled off, and it has + * an elide string, it must actually be the + * current highest priority tag, so this + * check is redundant: + */ + if (tagPtr->priority != info.elidePriority) { + panic("Bad tag priority being toggled off"); + } + + /* + * Find previous elide tag, if any (if not + * then elide will be zero, of course). + */ + elide = 0; + while (--info.elidePriority > 0) { + if (info.tagCnts[info.elidePriority] & 1) { + elide = info.tagPtrs[info.elidePriority] + ->elide; + break; + } } + } else { + elide = tagPtr->elide; + info.elidePriority = tagPtr->priority; } - } else { - info.elidePriority = tagPtr->priority; } } } @@ -5223,7 +5247,8 @@ GetXView(interp, textPtr, report) dInfoPtr->xScrollLast = last; if (textPtr->xScrollCmd != NULL) { listObj = Tcl_NewStringObj(textPtr->xScrollCmd, -1); - code = Tcl_ListObjAppendElement(interp, listObj, Tcl_NewDoubleObj(first)); + code = Tcl_ListObjAppendElement(interp, listObj, + Tcl_NewDoubleObj(first)); if (code == TCL_OK) { Tcl_ListObjAppendElement(interp, listObj, Tcl_NewDoubleObj(last)); code = Tcl_EvalObjEx(interp, listObj, diff --git a/generic/tkTextIndex.c b/generic/tkTextIndex.c index 123fb01..c5ef481 100644 --- a/generic/tkTextIndex.c +++ b/generic/tkTextIndex.c @@ -10,7 +10,7 @@ * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tkTextIndex.c,v 1.10 2003/11/07 15:36:26 vincentdarley Exp $ + * RCS: @(#) $Id: tkTextIndex.c,v 1.11 2003/11/08 17:22:46 vincentdarley Exp $ */ #include "default.h" @@ -1385,25 +1385,46 @@ TkTextIndexForwChars(textPtr, srcPtr, charCount, dstPtr, type) if ((segPtr->typePtr == &tkTextToggleOffType) || (segPtr->typePtr == &tkTextToggleOnType)) { TkTextTag *tagPtr = segPtr->body.toggle.tagPtr; - if (tagPtr->elideString != NULL - && (tagPtr->priority >= infoPtr->elidePriority)) { - if (elide) { - elide = ((segPtr->typePtr == &tkTextToggleOffType) - & !tagPtr->elide); - } else { - elide = ((segPtr->typePtr == &tkTextToggleOnType) - & tagPtr->elide); + /* + * The elide state only changes if this tag is + * either the current highest priority tag + * (and is therefore being toggled off), or it's + * a new tag with higher priority. + */ + if (tagPtr->elideString != NULL) { + infoPtr->tagCnts[tagPtr->priority]++; + if (infoPtr->tagCnts[tagPtr->priority] & 1) { + infoPtr->tagPtrs[tagPtr->priority] = tagPtr; } - if (!elide && tagPtr->priority - == infoPtr->elidePriority) { - /* Find previous elide tag, if any */ - while (--infoPtr->elidePriority > 0) { - if (infoPtr->tagCnts[infoPtr->elidePriority] & 1) { - break; + if (tagPtr->priority >= infoPtr->elidePriority) { + if (segPtr->typePtr == &tkTextToggleOffType) { + /* + * If it is being toggled off, and it has + * an elide string, it must actually be the + * current highest priority tag, so this + * check is redundant: + */ + if (tagPtr->priority != infoPtr->elidePriority) { + panic("Bad tag priority being toggled off"); + } + + /* + * Find previous elide tag, if any (if not + * then elide will be zero, of course). + */ + elide = 0; + while (--infoPtr->elidePriority > 0) { + if (infoPtr->tagCnts[infoPtr->elidePriority] + & 1) { + elide = infoPtr->tagPtrs + [infoPtr->elidePriority]->elide; + break; + } } + } else { + elide = tagPtr->elide; + infoPtr->elidePriority = tagPtr->priority; } - } else { - infoPtr->elidePriority = tagPtr->priority; } } } @@ -1529,33 +1550,54 @@ TkTextIndexCount(textPtr, indexPtr1, indexPtr2, type) */ if (checkElided) { if ((segPtr->typePtr == &tkTextToggleOffType) - || (segPtr->typePtr == &tkTextToggleOnType)) { + || (segPtr->typePtr == &tkTextToggleOnType)) { TkTextTag *tagPtr = segPtr->body.toggle.tagPtr; - if (tagPtr->elideString != NULL - && (tagPtr->priority >= infoPtr->elidePriority)) { - if (elide) { - elide = ((segPtr->typePtr == &tkTextToggleOffType) - & !tagPtr->elide); - } else { - elide = ((segPtr->typePtr == &tkTextToggleOnType) - & tagPtr->elide); + /* + * The elide state only changes if this tag is + * either the current highest priority tag + * (and is therefore being toggled off), or it's + * a new tag with higher priority. + */ + if (tagPtr->elideString != NULL) { + infoPtr->tagCnts[tagPtr->priority]++; + if (infoPtr->tagCnts[tagPtr->priority] & 1) { + infoPtr->tagPtrs[tagPtr->priority] = tagPtr; } - if (!elide && tagPtr->priority - == infoPtr->elidePriority) { - /* Find previous elide tag, if any */ - while (--infoPtr->elidePriority > 0) { - if (infoPtr->tagCnts[infoPtr->elidePriority] & 1) { - break; + if (tagPtr->priority >= infoPtr->elidePriority) { + if (segPtr->typePtr == &tkTextToggleOffType) { + /* + * If it is being toggled off, and it has + * an elide string, it must actually be the + * current highest priority tag, so this + * check is redundant: + */ + if (tagPtr->priority != infoPtr->elidePriority) { + panic("Bad tag priority being toggled off"); + } + + /* + * Find previous elide tag, if any (if not + * then elide will be zero, of course). + */ + elide = 0; + while (--infoPtr->elidePriority > 0) { + if (infoPtr->tagCnts[infoPtr->elidePriority] + & 1) { + elide = infoPtr->tagPtrs + [infoPtr->elidePriority]->elide; + break; + } } + } else { + elide = tagPtr->elide; + infoPtr->elidePriority = tagPtr->priority; } - } else { - infoPtr->elidePriority = tagPtr->priority; } } } if (elide) { if (segPtr == seg2Ptr) { - return count; + goto countDone; } byteOffset = 0; continue; @@ -1601,7 +1643,7 @@ TkTextIndexCount(textPtr, indexPtr1, indexPtr2, type) } } if (segPtr == seg2Ptr) { - return count; + goto countDone; } byteOffset = 0; } @@ -1618,6 +1660,11 @@ TkTextIndexCount(textPtr, indexPtr1, indexPtr2, type) } segPtr = linePtr1->segPtr; } + countDone: + if (infoPtr != NULL) { + ckfree((char*) infoPtr); + } + return count; } /* @@ -1761,25 +1808,45 @@ TkTextIndexBackChars(textPtr, srcPtr, charCount, dstPtr, type) if ((segPtr->typePtr == &tkTextToggleOffType) || (segPtr->typePtr == &tkTextToggleOnType)) { TkTextTag *tagPtr = segPtr->body.toggle.tagPtr; - if (tagPtr->elideString != NULL - && (tagPtr->priority >= infoPtr->elidePriority)) { - if (elide) { - elide = ((segPtr->typePtr == &tkTextToggleOnType) - & !tagPtr->elide); - } else { - elide = ((segPtr->typePtr == &tkTextToggleOffType) - & tagPtr->elide); + /* + * The elide state only changes if this tag is + * either the current highest priority tag + * (and is therefore being toggled off), or it's + * a new tag with higher priority. + */ + if (tagPtr->elideString != NULL) { + infoPtr->tagCnts[tagPtr->priority]++; + if (infoPtr->tagCnts[tagPtr->priority] & 1) { + infoPtr->tagPtrs[tagPtr->priority] = tagPtr; } - if (!elide && tagPtr->priority - == infoPtr->elidePriority) { - /* Find previous elide tag, if any */ - while (--infoPtr->elidePriority > 0) { - if (infoPtr->tagCnts[infoPtr->elidePriority] & 1) { - break; + if (tagPtr->priority >= infoPtr->elidePriority) { + if (segPtr->typePtr == &tkTextToggleOnType) { + /* + * If it is being toggled on, and it has + * an elide string, it must actually be the + * current highest priority tag, so this + * check is redundant: + */ + if (tagPtr->priority != infoPtr->elidePriority) { + panic("Bad tag priority being toggled on"); } + + /* + * Find previous elide tag, if any (if not + * then elide will be zero, of course). + */ + elide = 0; + while (--infoPtr->elidePriority > 0) { + if (infoPtr->tagCnts[infoPtr->elidePriority] & 1) { + elide = infoPtr->tagPtrs + [infoPtr->elidePriority]->elide; + break; + } + } + } else { + elide = tagPtr->elide; + infoPtr->elidePriority = tagPtr->priority; } - } else { - infoPtr->elidePriority = tagPtr->priority; } } } diff --git a/tests/text.test b/tests/text.test index 6e32ffd..9e85c8b 100644 --- a/tests/text.test +++ b/tests/text.test @@ -6,7 +6,7 @@ # Copyright (c) 1998-1999 by Scriptics Corporation. # All rights reserved. # -# RCS: @(#) $Id: text.test,v 1.24 2003/11/07 15:36:27 vincentdarley Exp $ +# RCS: @(#) $Id: text.test,v 1.25 2003/11/08 17:22:46 vincentdarley Exp $ package require tcltest 2.1 eval tcltest::configure $argv @@ -706,6 +706,30 @@ test text-0.2.50 {counting with tag priority eliding} { lappend res [.t count -displaychars 1.2 1.5] lappend res [.t count -displaychars 1.3 1.5] } {0 0 0 0 3 2 1 1} +test text-0.2.51 {counting with tag priority eliding} { + set res {} + .t delete 1.0 end + .t tag configure WELCOME -elide 1 + .t tag configure SYSTEM -elide 0 + .t tag configure TRAFFIC -elide 1 + .t insert end "\n" {SYSTEM TRAFFIC} + .t insert end "\n" WELCOME + lappend res [.t count -displaychars 1.0 end] + lappend res [.t count -displaychars 1.0 end-1c] + lappend res [.t count -displaychars 1.0 1.2] + lappend res [.t count -displaychars 2.0 end] + lappend res [.t count -displaychars 2.0 end-1c] + lappend res [.t index "1.0 +1 indices"] + lappend res [.t index "1.0 +1 display indices"] + lappend res [.t index "1.0 +1 display chars"] + lappend res [.t index end] + lappend res [.t index "end -1 indices"] + lappend res [.t index "end -1 display indices"] + lappend res [.t index "end -1 display chars"] + lappend res [.t index "end -2 indices"] + lappend res [.t index "end -2 display indices"] + lappend res [.t index "end -2 display chars"] +} {1 0 0 1 0 2.0 4.0 4.0 4.0 3.0 3.0 3.0 2.0 1.0 1.0} .t delete 1.0 end .t insert end $current diff --git a/tests/textDisp.test b/tests/textDisp.test index abf1d2a..61ba27a 100644 --- a/tests/textDisp.test +++ b/tests/textDisp.test @@ -6,7 +6,7 @@ # Copyright (c) 1998-1999 by Scriptics Corporation. # All rights reserved. # -# RCS: @(#) $Id: textDisp.test,v 1.15 2003/11/07 12:06:47 vincentdarley Exp $ +# RCS: @(#) $Id: textDisp.test,v 1.16 2003/11/08 17:22:46 vincentdarley Exp $ package require tcltest 2.1 eval tcltest::configure $argv @@ -186,6 +186,20 @@ test textDisp-0.4 {double tag elide transition} { destroy .txt } {} +test textDisp-0.5 {double tag elide transition} { + catch {destroy .txt} + pack [text .txt] + .txt tag configure WELCOME -elide 1 + .txt tag configure SYSTEM -elide 0 + .txt tag configure TRAFFIC -elide 1 + + .txt insert end "\n" {SYSTEM TRAFFIC} + .txt insert end "\n" WELCOME + # Crash was here. + update + destroy .txt +} {} + test textDisp-1.1 {GetStyle procedure, priorities and tab stops} { .t delete 1.0 end .t insert 1.0 "x\ty" -- cgit v0.12