windows-nt/Source/XPSP1/NT/windows/richedit/lssrc/lsstring.c
2020-09-26 16:20:57 +08:00

685 lines
19 KiB
C

#include "lsmem.h"
#include <limits.h>
#include "lsstring.h"
#include "txtils.h"
#include "txtln.h"
#include "txtobj.h"
/* Internal Functions prototypes */
static LSERR CheckReallocCharArrays(PLNOBJ plnobj, long cwch, long iwchLocalStart, long *cwchCorrect);
static LSERR CheckReallocSpacesArrays(PILSOBJ pobj, long cwSpaces);
static LSERR CopyCharsSpacesToDispList(PLNOBJ plnobj, WCHAR* rgwch, long cwch,
long* rgwSpaces, long cwSpaces);
static LSERR CopySpacesToDispList(PLNOBJ plnobj, long iNumOfSpaces, long durSpace);
/* Export Functions implementations */
/*----------------------------------------------------------------------------
%%Function: GetWidth
%%Contact: sergeyge
Fetches widths until end of run or right margin
Uses cache to improve performance
----------------------------------------------------------------------------*/
LSERR GetWidths(PLNOBJ plnobj, PLSRUN plsrun, long iwchStart, LPWSTR lpwch, LSCP cpFirst, long dcp, long durWidthExceed,
LSTFLOW lstflow, long* pcwchFetched, long* pdurWidth)
{
LSERR lserr;
PILSOBJ pilsobj;
long durWidth;
long cwch;
long iwchDur;
long cwchCorrect;
long cwchIter;
long durWidthIter;
BOOL fNothingReturned = fTrue;
pilsobj = plnobj->pilsobj;
durWidth = 0;
cwch = 0;
iwchDur = iwchStart;
*pcwchFetched = 0;
*pdurWidth = 0;
if (pilsobj->dcpFetchedWidth != 0 && cpFirst == pilsobj->cpFirstFetchedWidth &&
iwchStart == pilsobj->iwchFetchedWidth && lpwch[0] == pilsobj->wchFetchedWidthFirst)
{
Assert(dcp >= pilsobj->dcpFetchedWidth);
cwch = pilsobj->dcpFetchedWidth;
durWidth = pilsobj->durFetchedWidth;
/* FormatRegular assumes that First character exceeding right margin will stop GetCharWidth loop;
Special character could change situation---fix it.
*/
if (durWidth > durWidthExceed)
{
while(cwch > 1 && durWidth - durWidthExceed > pilsobj->pdur[iwchStart + cwch - 1])
{
cwch--;
durWidth -= pilsobj->pdur[iwchStart + cwch];
}
}
dcp -= cwch;
durWidthExceed -= durWidth;
iwchDur += cwch;
fNothingReturned = fFalse;
}
while (fNothingReturned || dcp > 0 && durWidthExceed >= 0)
{
lserr = CheckReallocCharArrays(plnobj, dcp, iwchDur, &cwchCorrect);
if (lserr != lserrNone) return lserr;
lserr = (*pilsobj->plscbk->pfnGetRunCharWidths)(pilsobj->pols, plsrun, lsdevReference,
&lpwch[cwch], cwchCorrect, (int)durWidthExceed,
lstflow, (int*)&pilsobj->pdur[iwchDur], &durWidthIter, &cwchIter);
if (lserr != lserrNone) return lserr;
Assert(durWidthIter >= 0);
Assert(durWidthIter <= uLsInfiniteRM);
Assert (durWidthIter <= uLsInfiniteRM - durWidth);
if (durWidthIter > uLsInfiniteRM - durWidth)
return lserrTooLongParagraph;
durWidth += durWidthIter;
durWidthExceed -= durWidthIter;
iwchDur += cwchIter;
cwch += cwchIter;
dcp -= cwchIter;
fNothingReturned = fFalse;
}
*pcwchFetched = cwch;
*pdurWidth = durWidth;
pilsobj->iwchFetchedWidth = iwchStart;
pilsobj->cpFirstFetchedWidth = cpFirst;
pilsobj->dcpFetchedWidth = cwch;
pilsobj->durFetchedWidth = durWidth;
return lserrNone;
}
/* F O R M A T S T R I N G */
/*----------------------------------------------------------------------------
%%Function: FormatString
%%Contact: sergeyge
Formats the local run
----------------------------------------------------------------------------*/
LSERR FormatString(PLNOBJ plnobj, PTXTOBJ pdobjText, WCHAR* rgwch, long cwch,
long* rgwSpaces, long cwSpaces, long durWidth)
{
LSERR lserr;
PILSOBJ pilsobj;
pilsobj = plnobj->pilsobj;
lserr = CopyCharsSpacesToDispList(plnobj, rgwch, cwch, rgwSpaces, cwSpaces);
if (lserr != lserrNone) return lserr;
/* fill out all related members from strils and output parameters */
pdobjText->iwchLim = pdobjText->iwchLim + cwch;
pdobjText->u.reg.iwSpacesLim = pdobjText->u.reg.iwSpacesLim + cwSpaces;
/* Fix Width Fetching state */
Assert((long)pilsobj->dcpFetchedWidth >= cwch);
Assert(pilsobj->durFetchedWidth >= durWidth);
pilsobj->iwchFetchedWidth = pilsobj->iwchFetchedWidth + cwch;
pilsobj->cpFirstFetchedWidth += cwch;
pilsobj->dcpFetchedWidth -= cwch;
pilsobj->durFetchedWidth -= durWidth;
return lserrNone;
}
/* F I L L R E G U L A R P R E S W I D T H S */
/*----------------------------------------------------------------------------
%%Function: MeasureStringFirst
%%Contact: sergeyge
Calculates dur of one character.
----------------------------------------------------------------------------*/
LSERR FillRegularPresWidths(PLNOBJ plnobj, PLSRUN plsrun, LSTFLOW lstflow, PTXTOBJ pdobjText)
{
LSERR lserr;
PILSOBJ pilsobj;
int* rgDup;
long dupJunk;
long limDupJunk;
pilsobj = plnobj->pilsobj;
if (pilsobj->fDisplay)
{
rgDup = (int *)&plnobj->pdup[pdobjText->iwchFirst];
if (!pilsobj->fPresEqualRef)
{
lserr = (*pilsobj->plscbk->pfnGetRunCharWidths)(pilsobj->pols, plsrun, lsdevPres,
&pilsobj->pwchOrig[pdobjText->iwchFirst], pdobjText->iwchLim - pdobjText->iwchFirst,
LONG_MAX, lstflow, rgDup, &dupJunk, &limDupJunk);
if (lserr != lserrNone) return lserr;
}
else /* fPresEqualRef */
{
memcpy(rgDup, &pilsobj->pdur[pdobjText->iwchFirst], sizeof(long) * (pdobjText->iwchLim - pdobjText->iwchFirst));
}
}
return lserrNone;
}
/* G E T O N E C H A R D U P */
/*----------------------------------------------------------------------------
%%Function: MeasureStringFirst
%%Contact: sergeyge
Calculates dur of one character.
----------------------------------------------------------------------------*/
LSERR GetOneCharDur(PILSOBJ pilsobj, PLSRUN plsrun, WCHAR wch, LSTFLOW lstflow, long* pdur)
{
LSERR lserr;
long durSumJunk;
long limDurJunk;
lserr = (*pilsobj->plscbk->pfnGetRunCharWidths)(pilsobj->pols, plsrun, lsdevReference, &wch, 1, LONG_MAX, lstflow,
(int*)pdur, &durSumJunk, &limDurJunk);
if (lserr != lserrNone) return lserr;
return lserrNone;
}
/* G E T O N E C H A R D U P */
/*----------------------------------------------------------------------------
%%Function: GetOneCharDup
%%Contact: sergeyge
Calculates dup of one character
----------------------------------------------------------------------------*/
LSERR GetOneCharDup(PILSOBJ pilsobj, PLSRUN plsrun, WCHAR wch, LSTFLOW lstflow, long dur, long* pdup)
{
LSERR lserr;
long dupSumJunk;
long limDupJunk;
*pdup = 0;
if (pilsobj->fDisplay)
{
if (!pilsobj->fPresEqualRef)
{
lserr = (*pilsobj->plscbk->pfnGetRunCharWidths)(pilsobj->pols, plsrun, lsdevPres, &wch, 1,
LONG_MAX, lstflow, (int*)pdup, &dupSumJunk, &limDupJunk);
if (lserr != lserrNone) return lserr;
}
else
{
*pdup = dur;
}
}
return lserrNone;
}
/* G E T V I S I D U P */
/*----------------------------------------------------------------------------
%%Function: GetVisiDup
%%Contact: sergeyge
Calculates dup of visi character character
----------------------------------------------------------------------------*/
LSERR GetVisiCharDup(PILSOBJ pilsobj, PLSRUN plsrun, WCHAR wch, LSTFLOW lstflow, long* pdup)
{
LSERR lserr;
long dupSumJunk;
long limDupJunk;
*pdup = 0;
if (pilsobj->fDisplay)
{
lserr = (*pilsobj->plscbk->pfnGetRunCharWidths)(pilsobj->pols, plsrun, lsdevPres, &wch, 1,
LONG_MAX, lstflow, (int*)pdup, &dupSumJunk, &limDupJunk);
if (lserr != lserrNone) return lserr;
}
return lserrNone;
}
/* A D D C H A R A C T E R W I T H W I D T H */
/*----------------------------------------------------------------------------
%%Function: AddCharacterWithWidth
%%Contact: sergeyge
Writes character code and its width in wchOrig, wch, dup, dur arrays.
Stores character code (in the VISI situation it can be different from wch)
in pilsobj->wchPrev.
----------------------------------------------------------------------------*/
LSERR AddCharacterWithWidth(PLNOBJ plnobj, PTXTOBJ pdobjText, WCHAR wchOrig, long durWidth, WCHAR wch, long dupWidth)
{
LSERR lserr;
PILSOBJ pilsobj;
long iwchLocalStart;
long cjunk;
pilsobj = plnobj->pilsobj;
iwchLocalStart = pilsobj->wchMac;
lserr = CheckReallocCharArrays(plnobj, 1, iwchLocalStart, &cjunk);
if (lserr != lserrNone) return lserr;
/* Fix cached width information before width in the pdur array is overwritten by durWidth.
Theoretically durWidth can be different from the cached value */
if (pilsobj->dcpFetchedWidth > 0)
{
pilsobj->iwchFetchedWidth ++;
pilsobj->cpFirstFetchedWidth ++;
pilsobj->dcpFetchedWidth --;
pilsobj->durFetchedWidth -= pilsobj->pdur[iwchLocalStart];
}
pilsobj->pwchOrig[iwchLocalStart] = wchOrig;
pilsobj->pdur[iwchLocalStart] = durWidth;
if (pilsobj->fDisplay)
{
plnobj->pwch[iwchLocalStart] = wch;
plnobj->pdup[iwchLocalStart] = dupWidth;
}
pilsobj->wchMac++;
pdobjText->iwchLim++;
Assert(pilsobj->wchMac == pdobjText->iwchLim);
return lserrNone;
}
/* F I X S P A C E S */
/*----------------------------------------------------------------------------
%%Function: FixSpaces
%%Contact: sergeyge
Fixes space character code for the Visi Spaces situation
----------------------------------------------------------------------------*/
void FixSpaces(PLNOBJ plnobj, PTXTOBJ pdobjText, WCHAR wch)
{
PILSOBJ pilsobj;
long i;
pilsobj = plnobj->pilsobj;
if (pilsobj->fDisplay)
{
for (i = pdobjText->u.reg.iwSpacesFirst; i < pdobjText->u.reg.iwSpacesLim; i++)
{
plnobj->pwch[pilsobj->pwSpaces[i]] = wch;
}
}
}
/* A D D S P A C E S */
/*----------------------------------------------------------------------------
%%Function: AddTrailingSpaces
%%Contact: sergeyge
Adds trailing/bordered spaces to the disp list
----------------------------------------------------------------------------*/
LSERR AddSpaces(PLNOBJ plnobj, PTXTOBJ pdobjText, long durSpace, long iNumOfSpaces)
{
LSERR lserr;
lserr = CopySpacesToDispList(plnobj, iNumOfSpaces, durSpace);
if (lserr != lserrNone) return lserr;
pdobjText->iwchLim = pdobjText->iwchLim + iNumOfSpaces;
pdobjText->u.reg.iwSpacesLim = pdobjText->u.reg.iwSpacesLim + iNumOfSpaces;
/* Fix Fetched Widths part. For non-bordered case, this procedure is activated for
trailing spaces only, so this state should also be filled with 0s, but
for bordered case it must be flushed
*/
FlushStringState(plnobj->pilsobj);
return lserrNone;
}
/* I N C R E A S E W C H M A C B Y @ */
/*----------------------------------------------------------------------------
%%Function: IncreaseWchMacBy2
%%Contact: sergeyge
----------------------------------------------------------------------------*/
LSERR IncreaseWchMacBy2(PLNOBJ plnobj)
{
LSERR lserr;
long cwch;
lserr = CheckReallocCharArrays(plnobj, 2, plnobj->pilsobj->wchMac, &cwch);
if (lserr != lserrNone) return lserr;
Assert(cwch <= 2 && cwch > 0);
if (cwch == 1)
{
lserr = CheckReallocCharArrays(plnobj, 1, plnobj->pilsobj->wchMac + 1, &cwch);
if (lserr != lserrNone) return lserr;
Assert(cwch == 1);
}
plnobj->pilsobj->wchMac += 2;
return lserrNone;
}
/* Internal Functions Implementation */
/* C H E C K R E A L L O C C H A R A R R A Y S */
/*----------------------------------------------------------------------------
%%Function: ReallocCharArrays
%%Contact: sergeyge
Reallocates character based arrays, increasing them by delta
----------------------------------------------------------------------------*/
static LSERR CheckReallocCharArrays(PLNOBJ plnobj, long cwch, long iwchLocalStart, long *cwchCorrect)
{
PILSOBJ pilsobj;
WCHAR* pwch;
long* pdup;
long* pdur;
GMAP* pgmap;
TXTINF* ptxtinf;
long delta;
pilsobj = plnobj->pilsobj;
/* pdupPen was made equal to pdup at the CreateLnObj time;
it can be changed to pdupPenAlloc at Adjust time only */
Assert(plnobj->pdup == plnobj->pdupPen);
/* Constant 2 is not random. We need to have 2 extra places for characters
for breaking with AutoHyphen and YSR which adds one charcter and hyphen.
*/
if (iwchLocalStart + cwch <= (long)pilsobj->wchMax - 2)
{
*cwchCorrect = cwch;
}
else if (iwchLocalStart < (long)pilsobj->wchMax - 2)
{
*cwchCorrect = pilsobj->wchMax - 2 - iwchLocalStart;
}
else
{
Assert (iwchLocalStart == (long)pilsobj->wchMax - 2);
delta = wchAddM;
pwch = (*pilsobj->plscbk->pfnReallocPtr)(pilsobj->pols, pilsobj->pwchOrig, (pilsobj->wchMax + delta) * sizeof(WCHAR) );
if (pwch == NULL)
{
return lserrOutOfMemory;
}
pilsobj->pwchOrig = pwch;
pwch = (*pilsobj->plscbk->pfnReallocPtr)(pilsobj->pols, plnobj->pwch, (pilsobj->wchMax + delta) * sizeof(WCHAR) );
if (pwch == NULL)
{
return lserrOutOfMemory;
}
plnobj->pwch = pwch;
pdur = (*pilsobj->plscbk->pfnReallocPtr)(pilsobj->pols, pilsobj->pdur, (pilsobj->wchMax + delta) * sizeof(long) );
if (pdur == NULL)
{
return lserrOutOfMemory;
}
pilsobj->pdur = pdur;
pdup = (*pilsobj->plscbk->pfnReallocPtr)(pilsobj->pols, plnobj->pdup, (pilsobj->wchMax + delta) * sizeof(long) );
if (pdup == NULL)
{
return lserrOutOfMemory;
}
plnobj->pdup = pdup;
if (plnobj->pdupPenAlloc != NULL)
{
pdup = (*pilsobj->plscbk->pfnReallocPtr)(pilsobj->pols, plnobj->pdupPenAlloc, (pilsobj->wchMax + delta) * sizeof(long) );
if (pdup == NULL)
{
return lserrOutOfMemory;
}
plnobj->pdupPenAlloc = pdup;
}
if (plnobj->pgmap != NULL)
{
pgmap = (*pilsobj->plscbk->pfnReallocPtr)(pilsobj->pols, plnobj->pgmap, (pilsobj->wchMax + delta) * sizeof(GMAP) );
if (pgmap == NULL)
{
return lserrOutOfMemory;
}
plnobj->pgmap = pgmap;
}
if (pilsobj->pdurLeft != NULL)
{
pdur = (*pilsobj->plscbk->pfnReallocPtr)(pilsobj->pols, pilsobj->pdurLeft, (pilsobj->wchMax + delta) * sizeof(long) );
if (pdur == NULL)
{
return lserrOutOfMemory;
}
pilsobj->pdurLeft = pdur;
memset(&pilsobj->pdurLeft[pilsobj->wchMax], 0, sizeof(long) * delta );
}
if (pilsobj->pdurRight != NULL)
{
pdur = (*pilsobj->plscbk->pfnReallocPtr)(pilsobj->pols, pilsobj->pdurRight, (pilsobj->wchMax + delta) * sizeof(long) );
if (pdur == NULL)
{
return lserrOutOfMemory;
}
pilsobj->pdurRight = pdur;
memset(&pilsobj->pdurRight[pilsobj->wchMax], 0, sizeof(long) * delta);
}
if (pilsobj->pduAdjust != NULL)
{
pdur = (*pilsobj->plscbk->pfnReallocPtr)(pilsobj->pols, pilsobj->pduAdjust, (pilsobj->wchMax + delta) * sizeof(long) );
if (pdur == NULL)
{
return lserrOutOfMemory;
}
pilsobj->pduAdjust = pdur;
}
if (pilsobj->ptxtinf != NULL)
{
ptxtinf = (*pilsobj->plscbk->pfnReallocPtr)(pilsobj->pols, pilsobj->ptxtinf, (pilsobj->wchMax + delta) * sizeof(TXTINF) );
if (ptxtinf == NULL)
{
return lserrOutOfMemory;
}
pilsobj->ptxtinf = ptxtinf;
memset(&pilsobj->ptxtinf[pilsobj->wchMax], 0, sizeof(TXTINF) * delta);
}
pilsobj->wchMax += delta;
plnobj->wchMax = pilsobj->wchMax;
*cwchCorrect = delta;
if (cwch < delta)
*cwchCorrect = cwch;
}
/* see comment and Assert at the beginning of the file */
plnobj->pdupPen = plnobj->pdup;
return lserrNone;
}
/* C H E C K R E A L L O C S P A C E S A R R A Y S */
/*----------------------------------------------------------------------------
%%Function: CheckReallocSpacesArrays
%%Contact: sergeyge
Checks that there is enough space wSpaces
to accomodate characters & spaces from the current local run.
Reallocates these arrays if it is needed.
----------------------------------------------------------------------------*/
static LSERR CheckReallocSpacesArrays(PILSOBJ pilsobj, long cwSpaces)
{
long iwSpacesLocalStart;
long delta;
long* pwSpaces;
iwSpacesLocalStart = pilsobj->wSpacesMac;
/* check that there is enough space for spaces in pwSpaces */
if (iwSpacesLocalStart + cwSpaces > pilsobj->wSpacesMax)
{
delta = wchAddM;
if (delta < iwSpacesLocalStart + cwSpaces - pilsobj->wSpacesMax)
{
delta = iwSpacesLocalStart + cwSpaces - pilsobj->wSpacesMax;
}
pwSpaces = (*pilsobj->plscbk->pfnReallocPtr)(pilsobj->pols, pilsobj->pwSpaces, (pilsobj->wSpacesMax + delta) * sizeof(long) );
if (pwSpaces == NULL)
{
return lserrOutOfMemory;
}
pilsobj->pwSpaces = pwSpaces;
pilsobj->wSpacesMax += delta;
}
return lserrNone;
}
/* C O P Y C H A R S S P A C E S T O D I S P L I S T */
/*----------------------------------------------------------------------------
%%Function: CopyCharsSpacesToDispList
%%Contact: sergeyge
Fills wch, dur and wSpaces arrays
----------------------------------------------------------------------------*/
static LSERR CopyCharsSpacesToDispList(PLNOBJ plnobj, WCHAR* rgwch, long cwch,
long* rgwSpaces, long cwSpaces)
{
LSERR lserr;
PILSOBJ pilsobj;
long iwchLocalStart;
long iwSpacesLocalStart;
long i;
pilsobj = plnobj->pilsobj;
iwchLocalStart = pilsobj->wchMac;
iwSpacesLocalStart = pilsobj->wSpacesMac;
/* check that there is enough space for characters and their widths in pwch and pdup arrays */
lserr = CheckReallocSpacesArrays(pilsobj, cwSpaces);
if (lserr != lserrNone) return lserr;
/* fill pwch array */
memcpy(&pilsobj->pwchOrig[iwchLocalStart], rgwch, sizeof(rgwch[0]) * cwch);
memcpy(&plnobj->pwch[iwchLocalStart], rgwch, sizeof(rgwch[0]) * cwch);
pilsobj->wchMac += cwch;
/* fill pwSpaces array, note that spaces with idexes greater than cwch should not be copied */
for (i=0; i < cwSpaces && rgwSpaces[i] < cwch; i++)
{
pilsobj->pwSpaces[iwSpacesLocalStart + i] = iwchLocalStart + rgwSpaces[i];
}
pilsobj->wSpacesMac += i;
return lserrNone;
}
/* C O P Y S P A C E S T O D I S P L I S T */
/*----------------------------------------------------------------------------
%%Function: CopyTrailingSpacesToDispList
%%Contact: sergeyge
Fills wch, dur, dup, wSpaces arrays with the trailing spaces info
----------------------------------------------------------------------------*/
static LSERR CopySpacesToDispList(PLNOBJ plnobj, long iNumOfSpaces, long durSpace)
{
LSERR lserr;
PILSOBJ pilsobj;
long iwchLocalStart;
long iwSpacesLocalStart;
long i;
long cwch;
long iwchStartCheck;
long cwchCorrect;
pilsobj = plnobj->pilsobj;
iwchLocalStart = pilsobj->wchMac;
iwSpacesLocalStart = pilsobj->wSpacesMac;
cwch = iNumOfSpaces;
iwchStartCheck = iwchLocalStart;
while (cwch > 0)
{
lserr = CheckReallocCharArrays(plnobj, cwch, iwchStartCheck, &cwchCorrect);
if (lserr != lserrNone) return lserr;
iwchStartCheck += cwchCorrect;
cwch -= cwchCorrect;
}
lserr = CheckReallocSpacesArrays(pilsobj, iNumOfSpaces);
if (lserr != lserrNone) return lserr;
for (i=0; i < iNumOfSpaces; i++)
{
plnobj->pwch[iwchLocalStart + i] = pilsobj->wchSpace;
pilsobj->pwchOrig[iwchLocalStart + i] = pilsobj->wchSpace;
pilsobj->pdur[iwchLocalStart + i] = durSpace;
pilsobj->pwSpaces[iwSpacesLocalStart + i] = iwchLocalStart + i;
}
pilsobj->wchMac += iNumOfSpaces;
pilsobj->wSpacesMac += iNumOfSpaces;
return lserrNone;
}
/* F L A S H S T R I N G S T A T E */
/*----------------------------------------------------------------------------
%%Function: FlashStringState
%%Contact: sergeyge
----------------------------------------------------------------------------*/
void FlushStringState(PILSOBJ pilsobj)
{
pilsobj->iwchFetchedWidth = 0;
pilsobj->cpFirstFetchedWidth = 0;
pilsobj->dcpFetchedWidth = 0;
pilsobj->durFetchedWidth = 0;
}