410 lines
11 KiB
C
410 lines
11 KiB
C
|
/*
|
||
|
* Contains Display and CalcPres methods of display object
|
||
|
*/
|
||
|
|
||
|
#include "disptext.h"
|
||
|
#include "dispmisc.h"
|
||
|
#include "lsdevice.h"
|
||
|
#include "lstfset.h"
|
||
|
#include "lstxtmap.h"
|
||
|
#include "dispi.h"
|
||
|
#include "txtobj.h"
|
||
|
#include "txtln.h"
|
||
|
#include "txtils.h"
|
||
|
#include "lschp.h"
|
||
|
|
||
|
#define TABBUFSIZE 32
|
||
|
|
||
|
static LSERR DisplayGlyphs(PTXTOBJ ptxtobj, PCDISPIN pdispin);
|
||
|
static LSERR DisplayTabLeader(PCDISPIN pdispin, PILSOBJ pilsobj, WCHAR wchtl);
|
||
|
|
||
|
// %%Function: DisplayText
|
||
|
// %%Contact: victork
|
||
|
//
|
||
|
LSERR WINAPI DisplayText(PDOBJ pdo, PCDISPIN pdispin)
|
||
|
{
|
||
|
LSERR lserr;
|
||
|
PTXTOBJ ptxtobj;
|
||
|
WCHAR wchSave;
|
||
|
WCHAR* pwch;
|
||
|
int iwch;
|
||
|
int cwch;
|
||
|
PILSOBJ pilsobj;
|
||
|
POINT ptOrg, ptExtTextOut;
|
||
|
POINTUV ptLeftCut;
|
||
|
|
||
|
long dupStart;
|
||
|
long dupPenStart;
|
||
|
long* pdup;
|
||
|
long* pdupPen;
|
||
|
long* rgdupLeftCut;
|
||
|
int i;
|
||
|
void* (WINAPI* pfnNewPtr)(POLS, DWORD);
|
||
|
void (WINAPI* pfnDisposePtr)(POLS, void*);
|
||
|
|
||
|
|
||
|
ptxtobj = (PTXTOBJ) pdo;
|
||
|
pilsobj = ptxtobj->plnobj->pilsobj;
|
||
|
|
||
|
Assert(ptxtobj->txtkind == txtkindRegular ||
|
||
|
ptxtobj->txtkind == txtkindHardHyphen ||
|
||
|
ptxtobj->txtkind == txtkindTab ||
|
||
|
ptxtobj->txtkind == txtkindNonReqHyphen ||
|
||
|
ptxtobj->txtkind == txtkindYsrChar ||
|
||
|
ptxtobj->txtkind == txtkindNonBreakSpace ||
|
||
|
ptxtobj->txtkind == txtkindNonBreakHyphen ||
|
||
|
ptxtobj->txtkind == txtkindOptNonBreak ||
|
||
|
ptxtobj->txtkind == txtkindSpecSpace ||
|
||
|
ptxtobj->txtkind == txtkindOptBreak ||
|
||
|
ptxtobj->txtkind == txtkindEOL );
|
||
|
|
||
|
if (ptxtobj->txtkind == txtkindTab)
|
||
|
{
|
||
|
Assert(ptxtobj->dupBefore == 0);
|
||
|
|
||
|
if (pdispin->dup <= 0) /* do nothing for zero-length tab */
|
||
|
{
|
||
|
return lserrNone;
|
||
|
}
|
||
|
|
||
|
// Draw tab only if it is visi case
|
||
|
|
||
|
if (ptxtobj->txtf&txtfVisi)
|
||
|
{
|
||
|
lserr = (*pilsobj->plscbk->pfnDrawTextRun)(pilsobj->pols, pdispin->plsrun,
|
||
|
FALSE, FALSE, /* Tab leader will take care of UL */
|
||
|
&(pdispin->ptPen), &(pilsobj->wchVisiTab),
|
||
|
(const int*) &(pdispin->dup), 1,
|
||
|
pdispin->lstflow, (const) pdispin->kDispMode,
|
||
|
&(pdispin->ptPen), &(pdispin->heightsPres), pdispin->dup,
|
||
|
pdispin->dupLimUnderline, pdispin->prcClip);
|
||
|
if (lserr != lserrNone) return lserr;
|
||
|
}
|
||
|
|
||
|
if (ptxtobj->u.tab.wchTabLeader == pilsobj->wchSpace)
|
||
|
{
|
||
|
|
||
|
// it is OK to draw the space in one take
|
||
|
|
||
|
lserr = (*pilsobj->plscbk->pfnDrawTextRun)(pilsobj->pols, pdispin->plsrun,
|
||
|
pdispin->fDrawStrikethrough, pdispin->fDrawUnderline,
|
||
|
&(pdispin->ptPen), &(pilsobj->wchSpace),
|
||
|
(const int*) &(pdispin->dup), 1,
|
||
|
pdispin->lstflow, (const) pdispin->kDispMode,
|
||
|
&(pdispin->ptPen), &(pdispin->heightsPres), pdispin->dup,
|
||
|
pdispin->dupLimUnderline, pdispin->prcClip);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
|
||
|
// we should apply tab leader alingment logic
|
||
|
|
||
|
lserr = DisplayTabLeader(pdispin, pilsobj, ptxtobj->u.tab.wchTabLeader);
|
||
|
}
|
||
|
|
||
|
return lserr;
|
||
|
}
|
||
|
|
||
|
if (ptxtobj->txtf & txtfGlyphBased)
|
||
|
{
|
||
|
return DisplayGlyphs(ptxtobj, pdispin);
|
||
|
}
|
||
|
|
||
|
iwch = ptxtobj->iwchFirst;
|
||
|
pwch = ptxtobj->plnobj->pwch + iwch;
|
||
|
cwch = ptxtobj->iwchLim - iwch;
|
||
|
|
||
|
if (cwch == 0) // nothing to display
|
||
|
{
|
||
|
return lserrNone;
|
||
|
}
|
||
|
|
||
|
Assert(ptxtobj->plnobj->pdupPen == ptxtobj->plnobj->pdup || ptxtobj->plnobj->pdupPen == ptxtobj->plnobj->pdupPenAlloc);
|
||
|
|
||
|
pdupPen = ptxtobj->plnobj->pdupPen + iwch;
|
||
|
|
||
|
ptOrg = pdispin->ptPen;
|
||
|
|
||
|
if (ptxtobj->dupBefore == 0)
|
||
|
{
|
||
|
ptExtTextOut = ptOrg;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
ptLeftCut.u = -ptxtobj->dupBefore;
|
||
|
ptLeftCut.v = 0;
|
||
|
LsPointXYFromPointUV(&(ptOrg), pdispin->lstflow, &ptLeftCut, &ptExtTextOut);
|
||
|
}
|
||
|
|
||
|
// Have to deal with special spaces before DrawTextRun
|
||
|
|
||
|
if (ptxtobj->txtkind == txtkindSpecSpace && !(ptxtobj->txtf&txtfVisi))
|
||
|
{
|
||
|
wchSave = *pwch; // remember actual code
|
||
|
|
||
|
for (i = 0; i < cwch; i++)
|
||
|
{
|
||
|
pwch[i] = pilsobj->wchSpace; // replace special spaces with the normal space
|
||
|
}
|
||
|
|
||
|
lserr = (*pilsobj->plscbk->pfnDrawTextRun)(pilsobj->pols, pdispin->plsrun,
|
||
|
pdispin->fDrawStrikethrough, pdispin->fDrawUnderline,
|
||
|
&ptExtTextOut, pwch, (const int*) pdupPen, cwch,
|
||
|
pdispin->lstflow, pdispin->kDispMode,
|
||
|
&ptOrg, &(pdispin->heightsPres),
|
||
|
pdispin->dup, pdispin->dupLimUnderline, pdispin->prcClip);
|
||
|
if (lserr != lserrNone) return lserr;
|
||
|
|
||
|
for (i = 0; i < cwch; i++)
|
||
|
{
|
||
|
pwch[i] = wchSave; // restore special spaces
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
lserr = (*pilsobj->plscbk->pfnDrawTextRun)(pilsobj->pols, pdispin->plsrun,
|
||
|
pdispin->fDrawStrikethrough, pdispin->fDrawUnderline,
|
||
|
&ptExtTextOut, pwch, (const int*) pdupPen, cwch,
|
||
|
pdispin->lstflow, pdispin->kDispMode,
|
||
|
&ptOrg, &(pdispin->heightsPres),
|
||
|
pdispin->dup, pdispin->dupLimUnderline, pdispin->prcClip);
|
||
|
if (lserr != lserrNone) return lserr;
|
||
|
}
|
||
|
|
||
|
|
||
|
if (pdispin->plschp->EffectsFlags)
|
||
|
{
|
||
|
pfnNewPtr = pilsobj->plscbk->pfnNewPtr;
|
||
|
pfnDisposePtr = pilsobj->plscbk->pfnDisposePtr;
|
||
|
|
||
|
/* create array for LeftCut info */
|
||
|
rgdupLeftCut = pfnNewPtr(pilsobj->pols, cwch * sizeof(*rgdupLeftCut));
|
||
|
if (rgdupLeftCut == NULL)
|
||
|
return lserrOutOfMemory;
|
||
|
|
||
|
/* fill LeftCut info array */
|
||
|
pdup = ptxtobj->plnobj->pdup + iwch;
|
||
|
dupStart = pdup[0]; /* the beginning of char */
|
||
|
dupPenStart = pdupPen[0]; /* starting position for drawing char */
|
||
|
|
||
|
for (i = 1; i < cwch; i++)
|
||
|
{
|
||
|
rgdupLeftCut[i] = dupStart - dupPenStart;
|
||
|
dupStart += pdup[i];
|
||
|
dupPenStart += pdupPen[i];
|
||
|
}
|
||
|
|
||
|
rgdupLeftCut[0] = ptxtobj->dupBefore;
|
||
|
|
||
|
lserr = (*pilsobj->plscbk->pfnDrawEffects)(pilsobj->pols, pdispin->plsrun, pdispin->plschp->EffectsFlags,
|
||
|
&(ptOrg), pwch, (const int*) pdup, (const int*) rgdupLeftCut,
|
||
|
ptxtobj->iwchLim - iwch,
|
||
|
pdispin->lstflow, pdispin->kDispMode, &(pdispin->heightsPres),
|
||
|
pdispin->dup, pdispin->dupLimUnderline, pdispin->prcClip);
|
||
|
|
||
|
/* dispose of the array for LeftCut info */
|
||
|
pfnDisposePtr(pilsobj->pols, rgdupLeftCut);
|
||
|
}
|
||
|
|
||
|
return lserr;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
// %%Function: DisplayTabLeader
|
||
|
// %%Contact: victork
|
||
|
//
|
||
|
static LSERR DisplayTabLeader(PCDISPIN pdispin, PILSOBJ pilsobj, WCHAR wchtl)
|
||
|
{
|
||
|
LSTFLOW lstflow = pdispin->lstflow;
|
||
|
LONG dupSum, dupCh, dupAdj, z, zOnGrid;
|
||
|
BOOL fGrow;
|
||
|
WCHAR rgwch[TABBUFSIZE];
|
||
|
LONG rgdup[TABBUFSIZE];
|
||
|
LONG dupbuf;
|
||
|
int i = 0, cwch, cwchout;
|
||
|
LSERR lserr;
|
||
|
POINT pt;
|
||
|
POINTUV ptAdj = {0,0};
|
||
|
|
||
|
lserr = (*pilsobj->plscbk->pfnGetRunCharWidths)(pilsobj->pols, pdispin->plsrun,
|
||
|
lsdevPres, (LPCWSTR) &wchtl, 1,
|
||
|
pdispin->dup, lstflow, (int*) &dupCh, &dupSum, (LONG*) &i);
|
||
|
|
||
|
if (lserr != lserrNone) return lserr;
|
||
|
|
||
|
if (i == 0 || dupCh <= 0) dupCh = 1;
|
||
|
|
||
|
for (i = 0; i < TABBUFSIZE; ++i)
|
||
|
{
|
||
|
rgwch[i] = wchtl;
|
||
|
rgdup[i] = dupCh;
|
||
|
}
|
||
|
|
||
|
/* advance to next multiple of dupCh
|
||
|
|
||
|
dupAdj is the distance between "pt.z" and the next integral multiple of dupch.
|
||
|
I.e. dupAdj = N * dupCh - "pt.x" where N is the smallest integer such that
|
||
|
N * dupCh is not less than "pt.x" in Latin case.
|
||
|
The starting pen position will be "rounded" to this "dupCh stop" by the assignment
|
||
|
"pt.z += dupAdj" in the code below.
|
||
|
|
||
|
Complications are:
|
||
|
|
||
|
depending on lstflow "z" can be either x or y;
|
||
|
depending on lstflow next can be bigger (Grow) or smaller;
|
||
|
Simple formula dupAdj = (ptPen.x + dupCh - 1) / dupCh * dupCh - ptPen.x does not
|
||
|
necessarily work if ptPen.x is negative;
|
||
|
*/
|
||
|
|
||
|
if (lstflow & fUVertical)
|
||
|
{
|
||
|
z = pdispin->ptPen.y;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
z = pdispin->ptPen.x;
|
||
|
}
|
||
|
|
||
|
if (lstflow & fUDirection)
|
||
|
{
|
||
|
fGrow = fFalse;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
fGrow = fTrue;
|
||
|
}
|
||
|
|
||
|
zOnGrid = (z / dupCh) * dupCh;
|
||
|
|
||
|
// zOnGrid is on grid, but maybe from the wrong side
|
||
|
|
||
|
if (zOnGrid == z)
|
||
|
{
|
||
|
dupAdj = 0;
|
||
|
}
|
||
|
else if (zOnGrid > z)
|
||
|
{
|
||
|
if (fGrow)
|
||
|
{
|
||
|
dupAdj = zOnGrid - z; // zOnGrid is the point we want
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
dupAdj = dupCh - (zOnGrid - z); // zOnGrid is on the wrong side
|
||
|
}
|
||
|
}
|
||
|
else // zOnGrid < z
|
||
|
{
|
||
|
if (!fGrow)
|
||
|
{
|
||
|
dupAdj = z - zOnGrid; // zOnGrid is the point we want
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
dupAdj = dupCh - (z - zOnGrid); // zOnGrid is on the wrong side
|
||
|
}
|
||
|
}
|
||
|
|
||
|
cwch = (pdispin->dup - dupAdj) / dupCh; /* always round down */
|
||
|
dupbuf = dupCh * TABBUFSIZE;
|
||
|
|
||
|
#ifdef NEVER // We've decided to kill rcClip optimization for now.
|
||
|
while (cwch > 0 && up <= pdispin->rcClip.right && lserr == lserrNone)
|
||
|
#endif /* NEVER */
|
||
|
|
||
|
while (cwch > 0 && lserr == lserrNone)
|
||
|
{
|
||
|
cwchout = cwch < TABBUFSIZE ? cwch : TABBUFSIZE;
|
||
|
|
||
|
ptAdj.u = dupAdj;
|
||
|
LsPointXYFromPointUV(&(pdispin->ptPen), lstflow, &ptAdj, &(pt));
|
||
|
|
||
|
lserr = (*pilsobj->plscbk->pfnDrawTextRun)(pilsobj->pols, pdispin->plsrun,
|
||
|
pdispin->fDrawStrikethrough, pdispin->fDrawUnderline,
|
||
|
&pt, rgwch, (const int*) rgdup, cwchout,
|
||
|
lstflow, pdispin->kDispMode, &pt, &(pdispin->heightsPres),
|
||
|
dupCh * cwchout, pdispin->dupLimUnderline, pdispin->prcClip);
|
||
|
cwch -= cwchout;
|
||
|
dupAdj += dupbuf;
|
||
|
}
|
||
|
return lserr;
|
||
|
}
|
||
|
|
||
|
|
||
|
// %%Function: DisplayGlyphs
|
||
|
// %%Contact: victork
|
||
|
//
|
||
|
static LSERR DisplayGlyphs(PTXTOBJ ptxtobj, PCDISPIN pdispin)
|
||
|
{
|
||
|
LSERR lserr;
|
||
|
PLNOBJ plnobj = ptxtobj->plnobj;
|
||
|
PILSOBJ pilsobj = plnobj->pilsobj;
|
||
|
|
||
|
WCHAR* pwch;
|
||
|
int iwch;
|
||
|
int cwch;
|
||
|
|
||
|
if (plnobj->fDrawInCharCodes)
|
||
|
{
|
||
|
// for meta-file output we call pfnDrawTextRun without widths
|
||
|
|
||
|
iwch = ptxtobj->iwchFirst;
|
||
|
pwch = ptxtobj->plnobj->pwch + iwch;
|
||
|
cwch = ptxtobj->iwchLim - iwch;
|
||
|
|
||
|
lserr = (*pilsobj->plscbk->pfnDrawTextRun)(pilsobj->pols, pdispin->plsrun,
|
||
|
pdispin->fDrawStrikethrough, pdispin->fDrawUnderline,
|
||
|
&(pdispin->ptPen), pwch, NULL, cwch,
|
||
|
pdispin->lstflow, pdispin->kDispMode,
|
||
|
&(pdispin->ptPen), &(pdispin->heightsPres),
|
||
|
pdispin->dup, pdispin->dupLimUnderline, pdispin->prcClip);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
lserr = (*pilsobj->plscbk->pfnDrawGlyphs)(pilsobj->pols, pdispin->plsrun,
|
||
|
pdispin->fDrawStrikethrough, pdispin->fDrawUnderline,
|
||
|
&plnobj->pgind[ptxtobj->igindFirst],
|
||
|
(const int*)&plnobj->pdupGind[ptxtobj->igindFirst],
|
||
|
(const int*)&plnobj->pdupBeforeJust[ptxtobj->igindFirst],
|
||
|
&plnobj->pgoffs[ptxtobj->igindFirst],
|
||
|
&plnobj->pgprop[ptxtobj->igindFirst],
|
||
|
&plnobj->pexpt[ptxtobj->igindFirst],
|
||
|
ptxtobj->igindLim - ptxtobj->igindFirst,
|
||
|
pdispin->lstflow, pdispin->kDispMode,
|
||
|
&(pdispin->ptPen), &(pdispin->heightsPres),
|
||
|
pdispin->dup, pdispin->dupLimUnderline, pdispin->prcClip);
|
||
|
}
|
||
|
|
||
|
return lserr;
|
||
|
|
||
|
}
|
||
|
|
||
|
|
||
|
// %%Function: CalcPresentationText
|
||
|
// %%Contact: victork
|
||
|
//
|
||
|
/*
|
||
|
* CalcPres for text is called only for the dnode between autonumbering dnode and main text.
|
||
|
* The dnode should contain one character (space).
|
||
|
*/
|
||
|
|
||
|
LSERR WINAPI CalcPresentationText(PDOBJ pdobj, long dup, LSKJUST lskj, BOOL fLastOnLine)
|
||
|
{
|
||
|
|
||
|
PTXTOBJ ptxtobj = (PTXTOBJ)pdobj;
|
||
|
|
||
|
Unreferenced(lskj);
|
||
|
Unreferenced(fLastOnLine);
|
||
|
|
||
|
Assert(ptxtobj->txtkind == txtkindRegular);
|
||
|
Assert(ptxtobj->iwchFirst + 1 == ptxtobj->iwchLim);
|
||
|
|
||
|
(ptxtobj->plnobj->pdup)[ptxtobj->iwchFirst] = dup;
|
||
|
|
||
|
return lserrNone;
|
||
|
}
|
||
|
|
||
|
|