484 lines
12 KiB
C
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;
|
||
|
}
|