/* * 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; }