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

484 lines
12 KiB
C

#include "lsmem.h"
#include "lstxtqry.h"
#include "txtils.h"
#include "txtln.h"
#include "txtobj.h"
#include "lsqin.h"
#include "lsqout.h"
typedef struct celldimensions
{
long iwchFirst, iwchLim;
long igindFirst, igindLim;
long dup;
long dcp; // number of cps in cell - different from iwchLim - iwchFirst
// if hyphenation added a character
// filled just before calling AddHyphenationToCell
} CELL;
typedef CELL* PCELL;
static const POINTUV ptZero = {0,0};
// %%Function: GetCellDimensions
// %%Contact: victork
//
// Input: iwchFirst and igindFirst in CELL structure
// Output: the rest of the structure
static void GetCellDimensions(PTXTOBJ ptxtobj, PCELL pcell)
{
PLNOBJ plnobj = ptxtobj->plnobj;
long* rgdup = plnobj->pdupGind; // widths of glyphs
GMAP* pgmap = plnobj->pgmap; // first glyph in a cell with given character
// 0 <= i <= wchMax (wchMax in lnobj)
// 0 <= pgmap[i] <= "glyphs in a shape" (not igindMax)
long i, dupCell;
GMAP iShapeGindFirstInCell; // iShape means index from gmap, not index to rgdup
// Assert that pcell->iwchFirst is really the cell boundary
// Notice that ptxtinf (and everything in ilsobj) is not valid in query time)
Assert(pcell->iwchFirst == ptxtobj->iwchFirst || pgmap[pcell->iwchFirst] != pgmap[pcell->iwchFirst-1]);
// Assert that pcell->igindFirst corresponds to pcell->iwchFirst
Assert(ptxtobj->igindFirst + pgmap[pcell->iwchFirst] - pgmap [ptxtobj->iwchFirst] == pcell->igindFirst);
// find out dimentions of the cell - all characters have the same gmap value
iShapeGindFirstInCell = pgmap[pcell->iwchFirst];
// "infinite" loop will stop when pcell->iwchLim is found
Assert(pcell->iwchFirst < ptxtobj->iwchLim); // ensure loop ends
for (i = pcell->iwchFirst + 1; ; i++)
{
if (i == ptxtobj->iwchLim)
{
pcell->iwchLim = ptxtobj->iwchLim;
pcell->igindLim = ptxtobj->igindLim;
break;
}
else if (pgmap[i] != iShapeGindFirstInCell)
{
pcell->iwchLim = i;
pcell->igindLim = pcell->igindFirst + pgmap[i] - iShapeGindFirstInCell;
break;
}
}
for (i = pcell->igindFirst, dupCell = 0; i < pcell->igindLim; i++)
{
dupCell += rgdup[i];
}
pcell->dup = dupCell;
}
// %%Function: AddHyphenationToCell
// %%Contact: victork
//
static void AddHyphenationToCell(PTXTOBJ ptxtobj, PCELL pcell)
{
long* rgdup;
long i;
long dwch = ptxtobj->plnobj->dwchYsr - 1; /* number of chars to add */
if (ptxtobj->txtf&txtfGlyphBased)
{
rgdup = ptxtobj->plnobj->pdupGind;
i = pcell->igindLim;
while (dwch > 0)
{
pcell->dup += rgdup[i];
pcell->iwchLim ++;
pcell->igindLim ++; // there are no ligatures amongst added characters
dwch--;
i++;
}
}
else
{
rgdup = ptxtobj->plnobj->pdup;
i = pcell->iwchLim;
while (dwch > 0)
{
pcell->dup += rgdup[i];
pcell->iwchLim ++;
dwch--;
i++;
}
}
Assert(pcell->iwchLim == (long) ptxtobj->iwchLim);
}
// %%Function: QueryDcpPcell
// %%Contact: victork
//
static void QueryDcpPcell(PTXTOBJ ptxtobj, LSDCP dcp, PCELL pcell, long* pupStartCell)
{
PLNOBJ plnobj = ptxtobj->plnobj;
long iwchLim = (long) ptxtobj->iwchLim;
long* rgdup;
long i;
CELL cell = {0,0,0,0,0,0};
long iwchQuery;
long upStartCell;
BOOL fHyphenationPresent = fFalse;
if (ptxtobj == plnobj->pdobjHyphen)
{
fHyphenationPresent = fTrue;
iwchLim -= (plnobj->dwchYsr - 1); /* exclude additional Ysr characters */
}
iwchQuery = ptxtobj->iwchFirst + dcp;
Assert(iwchQuery < iwchLim);
if (ptxtobj->txtf&txtfGlyphBased)
{
// initialize loop variables to describe non-existent previous cell
upStartCell = 0;
cell.iwchLim = ptxtobj->iwchFirst;
cell.igindLim = ptxtobj->igindFirst;
cell.dup = 0;
// loop does cell after cell until the cell containing iwchQuery is found
while (cell.iwchLim <= iwchQuery)
{
// start filling info about current cell
upStartCell += cell.dup;
cell.iwchFirst = cell.iwchLim;
cell.igindFirst = cell.igindLim;
// get the rest
GetCellDimensions(ptxtobj, &cell);
}
}
else
{
rgdup = plnobj->pdup;
i = ptxtobj->iwchFirst;
upStartCell = 0;
while (dcp > 0)
{
upStartCell += rgdup[i];
dcp--;
i++;
}
Assert(i < iwchLim); /* I'm given dcp inside */
// put the info into cell structure
cell.dup = rgdup[i];
cell.iwchFirst = i;
cell.iwchLim = i+1;
// these two are irrelevant, but for the sake of convenience...
cell.igindFirst = i;
cell.igindLim = i;
}
cell.dcp = cell.iwchLim - cell.iwchFirst; // hyphenation can change that
// YSR can extend the last cell
if (fHyphenationPresent && cell.iwchLim == iwchLim)
{
// the cell is up to the YSR sequence - let's include it
AddHyphenationToCell(ptxtobj, &cell);
}
*pcell = cell;
*pupStartCell = upStartCell;
}
// %%Function: QueryCpPpointText
// %%Contact: victork
//
/* Input is dcp and dnode dimensions
* Output is point where character begins (on baseline of dnode, so v is always zero),
* dimensions of the character - only width is calculated
*/
LSERR WINAPI QueryCpPpointText(PDOBJ pdobj, LSDCP dcp, PCLSQIN plsqin, PLSQOUT plsqout)
{
PTXTOBJ ptxtobj = (PTXTOBJ)pdobj;
CELL cell;
long upStartCell;
plsqout->pointUvStartObj = ptZero;
plsqout->heightsPresObj = plsqin->heightsPresRun;
plsqout->dupObj = plsqin->dupRun;
plsqout->plssubl = NULL;
plsqout->pointUvStartSubline = ptZero;
plsqout->lstextcell.pointUvStartCell = ptZero; // u can be changed later
if (ptxtobj->txtkind == txtkindTab)
{
// A tab is always in a separate dnode and is treated differently
Assert(dcp == 0);
plsqout->lstextcell.cpStartCell = plsqin->cpFirstRun;
plsqout->lstextcell.cpEndCell = plsqin->cpFirstRun;
plsqout->lstextcell.dupCell = plsqin->dupRun;
plsqout->lstextcell.cCharsInCell = 1;
plsqout->lstextcell.cGlyphsInCell = 0;
return lserrNone;
}
if (ptxtobj->iwchFirst == ptxtobj->iwchLim)
{
// empty dobj (for NonReqHyphen, OptBreak, or NonBreak characters)
Assert(dcp == 0);
Assert(plsqin->dupRun == 0);
Assert(ptxtobj->txtkind == txtkindNonReqHyphen || ptxtobj->txtkind == txtkindOptBreak ||
ptxtobj->txtkind == txtkindOptNonBreak);
plsqout->lstextcell.cpStartCell = plsqin->cpFirstRun;
plsqout->lstextcell.cpEndCell = plsqin->cpFirstRun;
plsqout->lstextcell.dupCell = 0;
plsqout->lstextcell.cCharsInCell = 0;
plsqout->lstextcell.cGlyphsInCell = 0;
return lserrNone;
}
// Find the cell - common with QueryTextCellDetails
QueryDcpPcell(ptxtobj, dcp, &cell, &upStartCell);
plsqout->lstextcell.cpStartCell = plsqin->cpFirstRun + cell.iwchFirst - ptxtobj->iwchFirst;
plsqout->lstextcell.cpEndCell = plsqout->lstextcell.cpStartCell + cell.dcp - 1;
plsqout->lstextcell.pointUvStartCell.u = upStartCell;
plsqout->lstextcell.dupCell = cell.dup;
plsqout->lstextcell.cCharsInCell = cell.iwchLim - cell.iwchFirst;
plsqout->lstextcell.cGlyphsInCell = cell.igindLim - cell.igindFirst;
return lserrNone;
}
// %%Function: QueryPointPcpText
// %%Contact: victork
//
LSERR WINAPI QueryPointPcpText(PDOBJ pdobj, PCPOINTUV pptIn, PCLSQIN plsqin, PLSQOUT plsqout)
{
PTXTOBJ ptxtobj = (PTXTOBJ)pdobj;
PLNOBJ plnobj = ptxtobj->plnobj;
long iwchLim = (long) ptxtobj->iwchLim;
BOOL fHyphenationPresent = fFalse;
long* rgdup;
long i;
long upQuery, upStartCell, upLimCell;
CELL cell = {0,0,0,0,0,0}; // init'ed to get rid of assert
plsqout->pointUvStartObj = ptZero;
plsqout->heightsPresObj = plsqin->heightsPresRun;
plsqout->dupObj = plsqin->dupRun;
plsqout->plssubl = NULL;
plsqout->pointUvStartSubline = ptZero;
plsqout->lstextcell.pointUvStartCell = ptZero; // u can change later
if (ptxtobj->txtkind == txtkindTab)
{
// A tab is always in a separate dnode and is treated differently
plsqout->lstextcell.cpStartCell = plsqin->cpFirstRun;
plsqout->lstextcell.cpEndCell = plsqin->cpFirstRun;
plsqout->lstextcell.dupCell = plsqin->dupRun;
plsqout->lstextcell.cCharsInCell = 1;
plsqout->lstextcell.cGlyphsInCell = 0;
return lserrNone;
}
if (ptxtobj == plnobj->pdobjHyphen)
{
fHyphenationPresent = fTrue;
iwchLim -= (plnobj->dwchYsr - 1); /* exclude additional Ysr characters */
}
upQuery = pptIn->u;
if (upQuery < 0)
{
upQuery = 0; // return leftmost when clicked outside left
}
upStartCell = 0;
if (ptxtobj->txtf&txtfGlyphBased)
{
// initialize loop variables to describe non-existent previous cell
upLimCell = 0;
cell.iwchLim = ptxtobj->iwchFirst;
cell.igindLim = ptxtobj->igindFirst;
cell.dup = 0;
// loop does cell after cell until the last cell or the cell containing upQuery
while (cell.iwchLim < iwchLim && upLimCell <= upQuery)
{
// start filling info about current cell
upStartCell = upLimCell;
cell.iwchFirst = cell.iwchLim;
cell.igindFirst = cell.igindLim;
// get the rest
GetCellDimensions(ptxtobj, &cell);
upLimCell = upStartCell + cell.dup;
}
}
else
{
rgdup = plnobj->pdup;
i = ptxtobj->iwchFirst;
upLimCell = 0;
while (upLimCell <= upQuery && i < iwchLim)
{
upStartCell = upLimCell;
upLimCell += rgdup[i];
i++;
}
// put the info into cell structure
cell.dup = rgdup[i - 1];
cell.iwchFirst = i - 1;
cell.iwchLim = i;
// these two are irrelevant, but for the sake of convenience...
cell.igindFirst = i - 1;
cell.igindLim = i - 1;
}
cell.dcp = cell.iwchLim - cell.iwchFirst; // hyphenation can change that
// YSR can extend the last cell
if (fHyphenationPresent && cell.iwchLim == iwchLim)
{
// the cell is up to the YSR sequence - let's include it
AddHyphenationToCell(ptxtobj, &cell);
}
plsqout->lstextcell.cpStartCell = plsqin->cpFirstRun + cell.iwchFirst - ptxtobj->iwchFirst;
plsqout->lstextcell.cpEndCell = plsqout->lstextcell.cpStartCell + cell.dcp - 1;
plsqout->lstextcell.pointUvStartCell.u = upStartCell;
plsqout->lstextcell.dupCell = cell.dup;
plsqout->lstextcell.cCharsInCell = cell.iwchLim - cell.iwchFirst;
plsqout->lstextcell.cGlyphsInCell = cell.igindLim - cell.igindFirst;
return lserrNone;
}
// %%Function: QueryTextCellDetails
// %%Contact: victork
//
LSERR WINAPI QueryTextCellDetails(
PDOBJ pdobj,
LSDCP dcp, /* IN: dcpStartCell */
DWORD cChars, /* IN: cCharsInCell */
DWORD cGlyphs, /* IN: cGlyphsInCell */
LPWSTR pwchOut, /* OUT: pointer array[cChars] of char codes */
PGINDEX pgindex, /* OUT: pointer array[cGlyphs] of glyph indices */
long* pdup, /* OUT: pointer array[cGlyphs] of glyph widths */
PGOFFSET pgoffset, /* OUT: pointer array[cGlyphs] of glyph offsets */
PGPROP pgprop) /* OUT: pointer array[cGlyphs] of glyph handles */
{
PTXTOBJ ptxtobj = (PTXTOBJ)pdobj;
PLNOBJ plnobj = ptxtobj->plnobj;
CELL cell;
long upDummy;
Unreferenced(cGlyphs);
Unreferenced(cChars); // used only in an assert
if (ptxtobj->txtkind == txtkindTab)
{
// Tab is in a separate dnode always and is treated differently
Assert(dcp == 0);
Assert(cChars == 1);
*pwchOut = ptxtobj->u.tab.wch;
*pdup = (ptxtobj->plnobj->pdup)[ptxtobj->iwchFirst];
return lserrNone;
}
if (ptxtobj->iwchFirst == ptxtobj->iwchLim)
{
// empty dobj (for NonReqHyphen, OptBreak, or NonBreak characters)
Assert(dcp == 0);
Assert(cChars == 0);
Assert(cGlyphs == 0);
return lserrNone;
}
// Find the cell - common with QueryCpPpointText
QueryDcpPcell(ptxtobj, dcp, &cell, &upDummy);
Assert(cell.iwchLim - cell.iwchFirst == (long) cChars);
memcpy(pwchOut, &plnobj->pwch[cell.iwchFirst], sizeof(long) * cChars);
if (ptxtobj->txtf&txtfGlyphBased)
{
Assert(cell.igindLim - cell.igindFirst == (long) cGlyphs);
memcpy(pdup, &plnobj->pdupGind[cell.igindFirst], sizeof(long) * cGlyphs);
memcpy(pgindex, &plnobj->pgind[cell.igindFirst], sizeof(long) * cGlyphs);
memcpy(pgoffset, &plnobj->pgoffs[cell.igindFirst], sizeof(long) * cGlyphs);
memcpy(pgprop, &plnobj->pgprop[cell.igindFirst], sizeof(long) * cGlyphs);
}
else
{
memcpy(pdup, &plnobj->pdup[cell.iwchFirst], sizeof(long) * cChars);
}
return lserrNone;
}