Windows NT 4.0 source code leak
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

2076 lines
60 KiB

/*****************************************************************************
*
* frparagp.c
* Copyright (C) Microsoft Corporation 1990.
* All Rights reserved.
*
*****************************************************************************/
#include "help.h"
#pragma hdrstop
#include "inc\frstuff.h"
#include "inc\fontlyr.h"
INLINE int STDCALL WInsertWord(QDE qde, QPLY qply, QLIN qlin);
INLINE static int STDCALL WGetNextWord(QDE, QLIN, QPLY, int);
INLINE void STDCALL PtAnnoLim(HWND hwnd, HDC hdc, POINT* ppt);
static BOOL STDCALL DisplaySplText(QDE qde, LPSTR qchBuf, int iIdx, int iAttr, int fSelected, int iCount, int ix, int iy);
#ifdef DBCS
#define DBCS_WRAP
static const PBYTE txtJapanKinsokuChars = "、。,.?!)]}》】』」〉゜゛";
static const PBYTE txtTaiwanKinsokuChars = "。A。B。C。D。E。F。G。H。I。J。K。L。M。N。O。P。Q。R。S。T。^。b。f。j。n。r。v。z。~。「。、。ヲ。ィ。ェ。ャ";
static const PBYTE txtHanKinsokuChars = "。「[{(<";
static const PBYTE txtOiKinsokuChars = "^?A^?B^?C^?D^?H^?I^?j^?l^?n^?p^?r^?r^?t^?v^?x^?z^?J^?K^?F^?G^?^?^?^?^?^?^?^?^?^?^?^?^?^?^?^?^?^?^?^?^?@^?B^?D^?F^?H^?b^?^?^?^?^?^?";
static const PBYTE txtHanOiKinsokuChars = ",.。?!、>」)]}ァィゥェォャュョッ゙゚'%:;";
static int STDCALL IsSecondBytePtr(PCSTR ptr, PCSTR ptrtop);
#endif
#define StoreNewParaFrame(qde, qlin) StoreParaFrame(qde, qlin, bFrTypeExportNewPara)
#define StoreEndOfTextFrame(qde, qlin) StoreParaFrame(qde, qlin, bFrTypeExportEndOfText)
#define StoreTabFrame(qde, qlin) StoreParaFrame(qde, qlin, bFrTypeExportTab)
#define wSplTextNormal 1
#define wSplTextHilite 2
#define wSplTextErase 3
#define wHitFindStart 0
#define wHitFindEnd 1
HBITMAP hbitLine; // handle to the line used to underline notes*/
/* While technically private to frame, this global has layered access
* via the FGetMatchState and FSetMatchState macros.
* When set True, we are highlighting full text search hits.
*/
BOOL fHiliteMatches;
static BOOL FMatchVisible(QDE, QFCM, QLSM);
INLINE static VOID DrawMatchFrames(QDE, QFCM, QLSM, POINT, const LPRECT, int, int, BOOL);
INLINE static VOID DrawMatchRect(QDE, POINT, LPRECT, BOOL, BOOL, BOOL);
static RECT RctFrameHit(QDE, QFR, LPSTR, OBJRG, OBJRG);
static void STDCALL StoreTextFrame(QDE, QLIN);
INLINE static void STDCALL CalcTextMatchRect(QDE qde, LPSTR qch, QFR qfr, OBJRG objrgFirst, OBJRG objrgLast, RECT *qrct);
INLINE static int STDCALL WProcessCommand(QDE qde, QLIN qlin, QPLY qply);
INLINE static int STDCALL WBreakOutLine(QDE, QLIN, QPLY);
INLINE BOOL STDCALL FIsSecondaryQde(QDE qde);
static int STDCALL DxFrameTextWidth(QDE, QFR, LPSTR, int);
static int STDCALL FindSplTextWidth(QDE qde, LPSTR qchBuf, int iIdx, int iCount, int iAttr);
/* Start ugly bug #1173 hack */
/* State of results buttons
* RESULTSNIL if we aren't messing with buttons because no search is active.
* RESULTSDISABLED if the button should be disabled. 0 is significant
* RESULTSENABLED if the button should be enabled. bit 1 is significant
* RESULTSON if it should be enabled no matter what. bit 2 is significant
* 0 is also FALSE, 1 and 2 are both !FALSE and therefore are TRUE. It's
* relevent that they are different bits. We mask the RESULTSENABLED bit
* off to make a button disabled although if RESULTSON is also set, the
* button will still be enabled even if the first or last search hit is
* seen.
*/
#define RESULTSNIL -1
#define RESULTSDISABLED 0x0000
#define RESULTSENABLED 0x0001
#define RESULTSON 0x0002
static int fMorePrevMatches;
static int fMoreNextMatches;
// Location of first match
static DWORD dwRUFirst;
static DWORD dwaddrFirst;
static WORD wextFirst;
// Location of last match
static DWORD dwRULast;
static DWORD dwaddrLast;
static WORD wextLast;
// End ugly bug #1173 hack
/*-------------------------------------------------------------------------
| LayoutParaGroup(qde, qfcm, qbObj, qchText, xWidth, qolr) |
| |
| Purpose: Lays out a paragraph group, and fills the qolr corresponding |
| to it. |
| Method: 1) Set up the PLY |
| 2) Call WLayoutPara repeatedly to lay out the individual |
| paragraphs in the group. |
| 3) Fill out the OLR. Note that because of needing to leave |
| space underneath the paragraph, we fill out the OLR rather |
| than letting the object handler take care of it for us. |
-------------------------------------------------------------------------*/
void STDCALL LayoutParaGroup(QDE qde, QFCM qfcm, PBYTE qbObj, PSTR qchText,
int xWidth, QOLR qolr)
{
MOPG mopg;
QFR qfr;
QB qb, qbCom;
int ifrFirst, ifr, dxSize;
PLY ply;
MOBJ mobj;
#ifdef _X86_
qb = qbObj + CbUnpackMOBJ((QMOBJ)&mobj, qbObj);
qbCom = qb + CbUnpackMOPG(qde, (QMOPG)&mopg, qb);
#else
qb = qbObj + CbUnpackMOBJ((QMOBJ)&mobj, qbObj, QDE_ISDFFTOPIC(qde));
qbCom = qb + CbUnpackMOPG(qde, (QMOPG)&mopg, qb, QDE_ISDFFTOPIC(qde));
#endif
ifrFirst = qolr->ifrFirst;
ply.qmopg = (QMOPG)&mopg;
ply.qfcm = qfcm;
ply.qchText = qchText;
ply.fWrapObject = FALSE;
ply.kl.wStyle = qfcm->wStyle;
// (kevynct) Fix for H3.5 716: We do not print the annotation bitmap.
if (FVAHasAnnoQde(qde, VaFromHfc(qfcm->hfc), qolr->objrgFirst)
&& qde->deType != dePrint)
ply.kl.wInsertWord = wInsWordAnno;
else
ply.kl.wInsertWord = wInsWordNil;
ply.kl.yPos = 0;
ply.kl.lich = mopg.libText;
ply.kl.libHotBinding = libHotNil;
ply.kl.ifr = ifrFirst;
ply.kl.qbCommand = qbCom;
ply.kl.objrgMax = qolr->objrgFirst;
ply.kl.objrgFront = qolr->objrgFront;
AccessMR(((QMR)&qde->mrTWS));
while (WLayoutPara(qde, &ply, xWidth) != wLayStatusEndText)
;
DeAccessMR(((QMR)&qde->mrTWS));
dxSize = 0;
for (ifr = qolr->ifrFirst; ifr < ply.kl.ifr; ifr++) {
qfr = (QFR) QFooInMR((QMR)&qde->mrFr, sizeof(FR), ifr);
if (qfr->xPos + qfr->dxSize > dxSize)
dxSize = qfr->xPos + qfr->dxSize;
qfr->xPos += qolr->xPos;
qfr->yPos += qolr->yPos;
}
qolr->dxSize = dxSize;
qolr->dySize = ply.kl.yPos;
qolr->ifrMax = ply.kl.ifr;
qolr->objrgMax = ply.kl.objrgMax;
qfcm->wStyle = ply.kl.wStyle;
}
/*-------------------------------------------------------------------------
| WLayoutPara(qde, qply, xWidth) |
| |
| Purpose: This lays out a paragraph, and positions it in the current FC.|
| It calls WLayoutLine to lay out the individual lines in the |
| paragraph. |
| Method: Loop until we reach the end of the paragraph and have no more |
| wrapped objects on the stack. Each pass through the loop, we |
| pop a wrapped object off the stack if appropriate, and lay out|
| a line of text. |
-------------------------------------------------------------------------*/
int STDCALL WLayoutPara(QDE qde, QPLY qply, int xWidth)
{
BOOL fFirstLine = TRUE;
int wStatus, yPosSav, ifr, ifrFirst, xMax, yMax;
QFR qfr;
#if defined(BIDI)
BOOL fSecondLine = FALSE;
#endif
/* Fix for bug 1610 (kevynct)
* If we are about to read a bEnd command, don't begin layout, since this
* will cause space before, box attributes, etc. to be added before the
* next paragraph.
*/
if(*(qply->qchText + qply->kl.lich) == chCommand &&
*qply->kl.qbCommand == bEnd)
{
/* REVIEW: In this case, we do not add a mark frame for the End; we
* just bump the object region counter. The preceding New Paragraph
* command will be assigned a mark frame.
*/
qply->kl.objrgMax++;
qply->kl.qbCommand++;
qply->kl.lich++;
/* REVIEW: More code to accomodate this bogus case.
* Duplicate the code to append an EndOfText frame for text export
*/
if (qply->qfcm->fExport) {
FR fr;
fr.bType = bFrTypeExportEndOfText;
fr.yAscent = fr.dySize = 0;
*((QFR) QFooInMR((QMR)&qde->mrFr, sizeof(FR), qply->kl.ifr)) = fr;
AppendMR((QMR)&qde->mrFr, sizeof(FR));
qply->kl.ifr++;
}
return(wLayStatusEndText);
}
ASSERT(!qply->fWrapObject);
ifrFirst = qply->kl.ifr;
qply->kl.yPos += qply->qmopg->ySpaceOver;
yPosSav = qply->kl.yPos;
if (qply->qmopg->fBoxed)
qply->kl.yPos += DxBoxBorder(qply->qmopg, wLineTop);
qply->xRight = xWidth - qply->qmopg->xRightIndent;
if (qply->qmopg->fBoxed)
qply->xRight -= DxBoxBorder(qply->qmopg, wLineRight);
wStatus = wLayStatusInWord;
while (wStatus < wLayStatusParaBrk || CFooInMR(((QMR) &qde->mrTWS)) > 0)
{
if (!qply->fWrapObject && CFooInMR(((QMR) &qde->mrTWS)) > 0) {
qply->twsWrap = *((QTWS) QFooInMR(((QMR) &qde->mrTWS), sizeof(TWS), 0));
TruncateMRFront(((QMR) &qde->mrTWS), sizeof(TWS));
qply->fWrapObject = TRUE;
/* Fix for bug 1524: (kevynct)
* If the object which the text wraps around does not fit in the
* window, force it to be LeftAligned, so that the left edge is
* the visible edge. Note that qply->twsWrap.olr.xPos
* is reset in this case, after the fall-thru.
*/
if (!qply->twsWrap.fLeftAligned) {
qply->twsWrap.olr.xPos = qply->xRight - qply->twsWrap.olr.dxSize;
if (qply->twsWrap.olr.xPos < 10)
qply->twsWrap.fLeftAligned = TRUE; // Force Left Alignment
else
qply->xRight = qply->twsWrap.olr.xPos - 10;
}
if (qply->twsWrap.fLeftAligned) // And fall thru here
{
qply->twsWrap.olr.xPos = qply->qmopg->xLeftIndent;
if (qply->qmopg->xFirstIndent < 0)
qply->twsWrap.olr.xPos += qply->qmopg->xFirstIndent;
if (qply->qmopg->fBoxed)
qply->twsWrap.olr.xPos += DxBoxBorder(qply->qmopg, wLineLeft);
}
qply->twsWrap.olr.yPos = qply->kl.yPos;
for (ifr = qply->twsWrap.olr.ifrFirst;
ifr < qply->twsWrap.olr.ifrMax; ifr++) {
qfr = ((QFR) QFooInMR((QMR) &qde->mrFr, sizeof(FR), ifr));
qfr->xPos += qply->twsWrap.olr.xPos;
qfr->yPos += qply->twsWrap.olr.yPos;
}
}
qply->fForceText = !qply->fWrapObject;
qply->xLeft = qply->qmopg->xLeftIndent;
if (qply->qmopg->fBoxed)
qply->xLeft += DxBoxBorder(qply->qmopg, wLineLeft);
if (qply->fWrapObject && qply->twsWrap.fLeftAligned) {
qply->xLeft += qply->twsWrap.olr.dxSize + 10;
}
if (fFirstLine) {
/* Fix for bug 55 (kevynct)
* Force first line to left edge of window if indent
* causes it to begin left of the left edge.
*
* WARNING: (90/01/08) Forcing removed.
*/
#if defined(BIDI)
if (qply->qmopg->wRtlReading) {
qply->xRight -= qply->qmopg->xFirstIndent;
fSecondLine = TRUE;
}
else
#endif
qply->xLeft = qply->xLeft + qply->qmopg->xFirstIndent;
fFirstLine = FALSE;
}
#if defined(BIDI)
else if (fSecondLine && qply->qmopg->wRtlReading) {
qply->xRight += qply->qmopg->xFirstIndent;
fSecondLine = FALSE;
}
#endif
if (wStatus != wLayStatusParaBrk && wStatus != wLayStatusEndText)
wStatus = WLayoutLine(qde, qply);
if (qply->fWrapObject
&& ((wStatus == wLayStatusParaBrk || wStatus == wLayStatusEndText)
|| qply->kl.yPos > qply->twsWrap.olr.yPos + qply->twsWrap.olr.dySize))
{
qply->fWrapObject = FALSE;
qply->xRight = xWidth - qply->qmopg->xRightIndent;
if (qply->qmopg->fBoxed)
qply->xRight -= DxBoxBorder(qply->qmopg, wLineRight);
qply->kl.yPos = max(qply->kl.yPos,
qply->twsWrap.olr.yPos + qply->twsWrap.olr.dySize);
}
}
if (qply->kl.yPos == yPosSav && wStatus != wLayStatusEndText) {
// (kevynct) Fix to get proper font used for empty paragraphs
if (qply->kl.wStyle == wStyleNil)
qply->kl.wStyle = 0;
if (qde->wStyleTM != qply->kl.wStyle) {
SelFont(qde, qply->kl.wStyle);
GetFontInfo(qde, (QTM) &qde->tm);
/* (kevynct)(WLayoutPara)
* Also sets de.wStyleDraw, since we called SelFont
*/
qde->wStyleTM = qde->wStyleDraw = qply->kl.wStyle;
}
qply->kl.yPos += (qde->tm.tmHeight + qde->tm.tmExternalLeading);
}
yMax = 0;
for (qfr = (QFR) QFooInMR((QMR) &qde->mrFr, sizeof(FR), ifrFirst);
qfr < (QFR) QFooInMR((QMR) &qde->mrFr, sizeof(FR), qply->kl.ifr); qfr++)
yMax = max(yMax, qfr->yPos + qfr->dySize);
qply->kl.yPos = max(qply->kl.yPos, yMax);
if (qply->qmopg->fBoxed) {
xMax = 0;
for (qfr = (QFR) QFooInMR((QMR) &qde->mrFr, sizeof(FR), ifrFirst);
qfr < (QFR) QFooInMR((QMR) &qde->mrFr, sizeof(FR), qply->kl.ifr); qfr++)
xMax = max(xMax, qfr->xPos + qfr->dxSize);
qfr = (QFR) QFooInMR((QMR) &qde->mrFr, sizeof(FR), qply->kl.ifr);
qfr->bType = bFrTypeBox;
qfr->rgf.fHot = FALSE;
qfr->rgf.fWithLine = TRUE;
qfr->xPos = min(qply->qmopg->xLeftIndent, qply->qmopg->xLeftIndent
+ qply->qmopg->xFirstIndent);
qfr->yPos = yPosSav;
qfr->dxSize = max(xMax, qply->xRight) - qfr->xPos
+ DxBoxBorder(qply->qmopg, wLineRight);
qply->kl.yPos += DxBoxBorder(qply->qmopg, wLineBottom);
qfr->dySize = qply->kl.yPos - yPosSav;
qfr->u.frf.mbox = qply->qmopg->mbox;
AppendMR((QMR) &qde->mrFr, sizeof(FR));
qply->kl.ifr++;
}
qply->kl.yPos += qply->qmopg->ySpaceUnder;
return(wStatus);
}
#if defined(BIDI) // jgross
/***********************************************************************\
* static INT isbidilang ( QDE qde, QFR qfr ) *
* *
* Purpose: determine if the frame's language is a BIDI language or *
* a LATIN language. *
* Returns: TRUE if BIDI language *
* FALSE if LATIN language *
\***********************************************************************/
static BOOL isbidilang(QDE qde, QFR qfr)
{
if (qde->wStyleDraw != qfr->u.frt.wStyle) {
SelFont(qde,qfr->u.frt.wStyle);
qde->wStyleDraw = qfr->u.frt.wStyle;
}
return ((qde->tm.tmCharSet == HEBREW_CHARSET) ||
#if 1 // 06-Jun-1995 [ralphw] This is the only Arabic charset in wingdi.h
(qde->tm.tmCharSet == ARABIC_CHARSET));
#else
(qde->tm.tmCharSet == ARABIC_SIMP_CHARSET) ||
(qde->tm.tmCharSet == ARABIC_TRAD_CHARSET) ||
(qde->tm.tmCharSet == ARABIC_USER_CHARSET));
#endif
}
#endif // BIDI
/*-------------------------------------------------------------------------
| WLayoutLine(qde, qply) |
| |
| Purpose: This handles the actual alignment of a line of text within |
| the paragraph. It relies upon WBreakOutLine to actually |
| determine the contents of the line. |
| Method: 1) Set up the LIN data structure. |
| 2) Call WBreakOutLine to fill the line. |
| 3) Align all frames in the line upon the same baseline. |
| 4) Space the line. |
| 5) Justify the line, if necessary. |
| 6) If necessary, add a blank line after the line. |
-------------------------------------------------------------------------*/
int STDCALL WLayoutLine(QDE qde, QPLY qply)
{
LIN lin;
int ifrFirst, dxJustify, ySav, yAscentMost, yDescentMost;
int wStatus, cch, dxOld;
QFR qfrFirst, qfr, qfrMax;
LPSTR qchBase, qch;
lin.kl = qply->kl;
lin.xPos = qply->xLeft;
lin.dxSize = 0;
lin.lichFirst = lichNil;
lin.cWrapObj = 0;
lin.yBlankLine = 0;
lin.chTLast = chTNil;
lin.wFirstWord = wInFirstWord;
lin.wTabType = wTypeNil;
lin.bFrTypeMark = bFrTypeMarkNil;
ifrFirst = lin.kl.ifr;
ySav = lin.kl.yPos;
wStatus = WBreakOutLine(qde, &lin, qply);
qfrFirst = (QFR) QFooInMR((QMR)&qde->mrFr, sizeof(FR), ifrFirst);
qfrMax = (QFR) QFooInMR((QMR)&qde->mrFr, sizeof(FR), lin.kl.ifr);
yAscentMost = yDescentMost = 0;
for (qfr = qfrFirst; qfr < qfrMax; qfr++) {
if (qfr->rgf.fWithLine) {
yAscentMost = max(yAscentMost, qfr->yAscent);
yDescentMost = max(yDescentMost, qfr->dySize - qfr->yAscent);
}
}
for (qfr = qfrFirst; qfr < qfrMax; qfr++) {
if (qfr->rgf.fWithLine)
qfr->yPos = lin.kl.yPos + yAscentMost - qfr->yAscent;
}
if (qply->qmopg->yLineSpacing >= 0)
{
lin.kl.yPos += max(qply->qmopg->yLineSpacing,
yAscentMost + yDescentMost + lin.yBlankLine);
}
else
lin.kl.yPos += -qply->qmopg->yLineSpacing;
if (qply->qmopg->wJustify != wJustifyLeft) {
/* Fix for bug 1496: (kevynct)
* To get correct right justification, we must:
* 1. Look at the last frame of this line.
* 2. If it is a text frame, eat trailing whitespace and
* reset values of:
* fr.frt.cchSize, fr.dxSize, lin.xPos
*/
if (lin.kl.ifr > 0) {
// The Last Frame
qfr = (QFR) QFooInMR((QMR)&qde->mrFr, sizeof(FR), lin.kl.ifr - 1);
if (qfr->bType == bFrTypeText)
{
qchBase = qply->qchText + qfr->u.frt.lichFirst;
for (cch = qfr->u.frt.cchSize, qch = qchBase + cch; cch > 0; --cch)
if (*--qch != chSpace)
break;
dxOld = qfr->dxSize;
qfr->u.frt.cchSize = cch;
#if defined(BIDI_MULT) // jgross - me thinks this is a US bug!
// make sure proper font is loaded!
if (qde->wStyleDraw != qfr->u.frt.wStyle) {
SelFont(qde, qfr->u.frt.wStyle);
qde->wStyleDraw = qfr->u.frt.wStyle;
}
#endif
qfr->dxSize = FindTextWidth(qde->hdc, qchBase, 0, cch);
lin.xPos -= dxOld - qfr->dxSize;
}
}
dxJustify = qply->xRight - lin.xPos;
if (dxJustify >= 0) {
if (qply->qmopg->wJustify == wJustifyCenter)
dxJustify = dxJustify / 2;
qfr = (QFR) QFooInMR((QMR) &qde->mrFr, sizeof(FR), ifrFirst);
qfrMax = (QFR) QFooInMR((QMR) &qde->mrFr, sizeof(FR), lin.kl.ifr);
for (; qfr < qfrMax; qfr++) {
/* (kevynct)
* Fix for Help 3.5 bug 567 (was also in Help 3.0)
* We do not want to justify wrap-object frames yet
* (only frames which live on the current line).
*
* WARNING: If mark frames can ever appear inside wrap-objects
* we need to include those types in the test.
*/
if (qfr->bType != bFrTypeAnno && qfr->rgf.fWithLine)
qfr->xPos += dxJustify;
}
}
}
if (lin.kl.yPos == ySav && wStatus != wLayStatusEndText
&& !(!qply->fWrapObject && CFooInMR(((QMR) &qde->mrTWS)) > 0)) {
// (kevynct) Fix to get proper font used for empty paragraphs
if (lin.kl.wStyle == wStyleNil)
lin.kl.wStyle = 0;
if (qde->wStyleTM != lin.kl.wStyle) {
SelFont(qde, lin.kl.wStyle);
GetFontInfo(qde, (QTM) &qde->tm);
/* (kevynct)(WLayoutLine)
* Also sets de.wStyleDraw, since we called SelFont
*/
qde->wStyleTM = qde->wStyleDraw = lin.kl.wStyle;
}
lin.kl.yPos += (qde->tm.tmHeight + qde->tm.tmExternalLeading);
}
qply->kl = lin.kl;
#if defined(BIDI) // jgross - rewrote
{
INT xEnd, xDelta, xNext, xHold;
QFR firstrun, lastrun; // first and last QFR in a run
if (qply->qmopg->wRtlReading && (lin.kl.ifr > 0)) { // line in a RTL paragraph
//
// If this is an RtoL paragraph, we need to turn all the language bits
// around. This will be done by finding the rightmost location on the line
// and subtracting the values from there for the first frame onward.
//
// we need to also check the language, if two or more frame of the same
// language appear together, then they should be moved together.
//
// --------------------
// jgross
//
// correction: if two or more frames of LATIN appear together, then they should
// be moved together. BIDI frames should still be reversed.
//
// --------------------
//
// The Last Frame - get it's final position
//
qfr = (QFR) QFooInMR((QMR)&qde->mrFr, sizeof(FR), lin.kl.ifr - 1);
xEnd = min(qfr->xPos + qfr->dxSize,qply->xRight);
xDelta = 0;
for (qfr = qfrFirst; qfr < qfrMax; ++qfr) {
firstrun = lastrun = qfr;
if ((firstrun->u.frt.wStyle >= 0) &&
!isbidilang(qde,firstrun)) // only need this for LATIN langs
while (((lastrun + 1) < qfrMax) && // find end of run
((lastrun + 1)->u.frt.wStyle >= 0) &&
(!isbidilang(qde,lastrun + 1)))
++lastrun;
xHold = lastrun->xPos + lastrun->dxSize; // x pos of end of run
for (qfr = lastrun; qfr != firstrun; --qfr) { // move all but first in run
xNext = qfr->xPos - (qfr - 1)->xPos - (qfr - 1)->dxSize; // space btwn frames
qfr->xPos = xEnd - qfr->dxSize - xDelta; // new frame pos
xDelta = 0; // clear for within the run
xEnd = qfr->xPos - xNext; // new end for next frame
}
firstrun->xPos = xEnd - firstrun->dxSize - xDelta; // move first run
xEnd = firstrun->xPos; // new end for next frame
if ((lastrun + 1) < qfrMax) {
if (firstrun->bType == bFrTypeAnno) // special case for annotation mark
xDelta = 2;
else
xDelta = (lastrun + 1)->xPos - xHold; // space between frames for next run
}
qfr = lastrun;
}
}
else if (lin.kl.ifr > 0) { // line in a LTR paragraph
for (qfr = qfrFirst; qfr < qfrMax; ++qfr) {
firstrun = lastrun = qfr;
if ((firstrun->u.frt.wStyle >= 0) &&
isbidilang(qde,firstrun)) // only need this for BIDI langs
while (((lastrun + 1) < qfrMax) && // find end of run
((lastrun + 1)->u.frt.wStyle >= 0) &&
(isbidilang(qde,lastrun + 1)))
++lastrun;
if (firstrun != lastrun) { // only need to reverse on consecutive BIDI frames
xEnd = lastrun->xPos + lastrun->dxSize; // x pos of end of run
xDelta = 0;
for (qfr = firstrun; qfr <= lastrun; ++qfr) {
xNext = qfr->xPos + qfr->dxSize;
qfr->xPos = xEnd - qfr->dxSize - xDelta;
xEnd = qfr->xPos;
if ((qfr+1) < lastrun)
xDelta = (qfr + 1)->xPos - xNext;
}
}
qfr = lastrun;
}
}
}
#endif // BIDI
return(wStatus);
}
/*-------------------------------------------------------------------------
| WBreakOutLine(qde, qlin, qply) |
| |
| Purpose: This creates a series of frames which correspond to the |
| line currently being laid out. We lay out until we encounter |
| a line break (line feed, end of text, etc.), or until we have |
| filled the available space. |
| Method: We cycle through an infinite loop, adding zero or more frames |
| each pass. Each pass consists of two stages: |
| Stage 1: Add new frames. We add frames from one of: |
| - Insert new object (if already queued) |
| - Process a command |
| - Break out one frame of text |
| Stage 2: DoStatus. We evaluate our current status: |
| - If linebreaking (line break, para break, or EOT),|
| we clean up and return. |
| - Otherwise, we either save our state if we fit on |
| the line, or restore the last state that did fit |
| and return. |
| See the LIN data structure in frparagp.h for more details. |
-------------------------------------------------------------------------*/
INLINE static int STDCALL WBreakOutLine(QDE qde, QLIN qlin, QPLY qply)
{
LPSTR qch;
int wStatus, cchStep, fBinary;
int lichGoal;
LIN linSav, linT;
int RightAdjust = 0;
#ifdef DBCS_WRAP1
char *p;
int fLastIsKanji, fKinsoku;
#endif
linSav = *qlin;
for (;;) {
if (qlin->kl.wInsertWord != wInsWordNil) {
wStatus = WInsertWord(qde, qply, qlin);
goto DoStatus;
}
qch = qply->qchText + qlin->kl.lich;
if (*qch == chCommand) {
wStatus = WProcessCommand(qde, qlin, qply);
if (CFooInMR(((QMR) &qde->mrTWS)) > 0 && !qply->fWrapObject
&& qlin->xPos == qply->xLeft)
wStatus = wLayStatusLineBrk;
++qlin->kl.lich;
goto DoStatus;
}
ASSERT(qlin->lichFirst == lichNil);
qlin->lichFirst = qlin->kl.lich;
linT = *qlin;
cchStep = 32;
lichGoal = qlin->lichFirst + 32;
fBinary = FALSE;
for (;;) {
*qlin = linT;
wStatus = WGetNextWord(qde, qlin, qply, lichGoal);
#ifdef DBCS_WRAP1
if (defcharset == SHIFTJIS_CHARSET ||
defcharset == CHINESEBIG5_CHARSET) {
qch = qply->qchText + qlin->lichFirst + qlin->cchSize -1;
fKinsoku = 0;
fLastIsKanji = 0;
if (IsSecondBytePtr(qch, qply->qchText + qlin->lichFirst)) {
fLastIsKanji = -1;
if (defcharset == SHIFTJIS_CHARSET)
p = txtJapanKinsokuChars;
// REVIEW: right charset for taiwan?
else if (defcharset == CHINESEBIG5_CHARSET)
p = txtTaiwanKinsokuChars;
for (; *p; p +=2 ) {
if (*(qch-1) == p[0] && *qch == p[1]) {
fKinsoku = -1;
break;
}
}
}
if (fLastIsKanji && !fKinsoku)
RightAdjust = FindTextWidth(qde,
qply->qchText + qlin->lichFirst, qlin->cchSize - 2, 2);
else
RightAdjust = 0;
}
#endif
if (qlin->xPos + qlin->dxSize > qply->xRight - RightAdjust
&& !qply->qmopg->fSingleLine
&& !(qlin->wFirstWord != wInNextWord && qply->fForceText))
{
fBinary = TRUE;
if (cchStep == 0)
goto DoStatus;
}
else {
linSav = *qlin;
linT = linSav;
if (wStatus == wLayStatusInWord)
goto DoStatus;
if (cchStep == 0)
{
wStatus = wLayStatusLineBrk;
goto DoStatus;
}
}
if (fBinary)
cchStep = cchStep >> 1;
lichGoal = linT.kl.lich + cchStep;
}
DoStatus:
switch (wStatus) {
case wLayStatusInWord:
case wLayStatusWordBrk:
if (qlin->xPos + qlin->dxSize > qply->xRight - RightAdjust
&& !(qlin->wFirstWord != wInNextWord && qply->fForceText)
&& !qply->qmopg->fSingleLine)
{
/* REVIEW: If we've just inserted frames, throw them away.
* (kevynct) 91/05/15
*
* We now discard all unused frames here. We used to just
* check for inserted object frames.
*/
if (linSav.kl.ifr < qlin->kl.ifr)
{
DiscardFrames(qde,
((QFR) QFooInMR((QMR)&qde->mrFr, sizeof(FR), linSav.kl.ifr)),
((QFR) QFooInMR((QMR)&qde->mrFr, sizeof(FR), qlin->kl.ifr)));
}
/* REVIEW: If we've just inserted wrap-objects, throw away those
* which were beyond the end of the best-fit line (linSav).
*
* (91/05/15) We used to DiscardFrames here, but this is
* taken care of now by the above code. All we need to do is
* delete the unused mrTWS entries.
*/
for (; qlin->cWrapObj > linSav.cWrapObj; qlin->cWrapObj--) {
TruncateMRBack((QMR)&qde->mrTWS);
}
*qlin = linSav;
StoreTextFrame(qde, qlin);
ResolveTabs(qde, qlin, qply);
if (qply->qfcm->fExport)
StoreNewParaFrame(qde, qlin);
/* If qlin->bFrTypeMark is non-nil, then there is
* a mark frame pending which now needs to be stored.
* DANGER: We must always complete a StoreTextFrame
* by this point to ensure that the current object region
* counter has been updated.
*/
if (qlin->bFrTypeMark != bFrTypeMarkNil)
StoreMarkFrame(qde, qlin, qlin->bFrTypeMark);
return(wStatus);
}
if (wStatus == wLayStatusWordBrk) {
qlin->wFirstWord = wInNextWord;
qlin->chTLast = chTNil;
linSav = *qlin;
}
continue;
case wLayStatusLineBrk:
case wLayStatusParaBrk:
case wLayStatusEndText:
StoreTextFrame(qde, qlin);
ResolveTabs(qde, qlin, qply);
if (qply->qfcm->fExport) {
if (wStatus == wLayStatusEndText)
StoreEndOfTextFrame(qde, qlin);
// Note: MMViewer exports paragraphs as entire lines.
else if ((wStatus != wLayStatusLineBrk))
StoreNewParaFrame(qde, qlin);
}
/*
* If qlin->bFrTypeMark is non-nil, then there is a mark frame
* pending which now needs to be stored. DANGER: We must always
* complete a StoreTextFrame by this point to ensure that the
* current object region counter has been updated.
*/
if (qlin->bFrTypeMark != bFrTypeMarkNil)
StoreMarkFrame(qde, qlin, qlin->bFrTypeMark);
return(wStatus);
}
}
}
/*-------------------------------------------------------------------------
| WGetNextWord(qde, qlin, qply, lichMin) |
| |
| Purpose: This scans through a text buffer and finds the frame |
| corresponding to the first word break after lichMin. |
| Usage: qlin should contain information about the current layout |
| condition. In particular, we rely on lichFirst and kl.lich. |
| Also, chTLast should be set appropriately (chTNil for the |
| first call). |
| Returns: Word corresponding to the current layout status. This will |
| always be wLayStatusWordBrk if we ended on a word break, or |
| wLayStatusInWord if we ended on a command byte. |
| Method: We scan through the text, breaking on every word break. If |
| we encounter a command byte, we terminate- otherwise we keep |
| going until the first word break at or after lichMin. |
| We assume that a word consists of prefix characters, main |
| characters, and suffix characters. We index into rgchType to |
| determine the type of a particular character, and we break a |
| word every time that chTNew < chTOld. |
-------------------------------------------------------------------------*/
INLINE static int STDCALL WGetNextWord(QDE qde, QLIN qlin, QPLY qply, int lichMin)
{
LPSTR qch;
LPSTR qchBase;
char chTNew, chTOld;
BYTE bButtonType;
ASSERT(qlin->lichFirst != lichNil);
qchBase = qch = qply->qchText + qlin->lichFirst;
ASSERT(*qch != chCommand);
chTOld = qlin->chTLast;
for (;;) {
if (qlin->wFirstWord == wHaveFirstWord)
qlin->wFirstWord = wInNextWord;
for (;;) {
#ifdef DBCS_WRAP
if (IsDBCSLeadByte(*qch) && Is2ndByte(qch[1])) {
qch += 2;
if (*qch == chCommand)
chTNew = chTCom;
else
chTNew = chTSuff;
break;
}
else if (defcharset == SHIFTJIS_CHARSET) {
// yutakas New Kinsoku Routine.
PSTR ptmp;
BOOL bOiKin = FALSE;
// Check Oikomi Kinsoku Char.
ptmp = qch;
do {
ptmp = IsKinsokuChars(ptmp);
if (ptmp) {
if ((*ptmp == chCommand) || (*ptmp == ' '))
ptmp = NULL;
else
qch = ptmp;
}
} while (ptmp && *ptmp);
//Check Oidashi Kinsoku Char.
ptmp = qch;
do {
ptmp = IsOiKinsokuChars(ptmp);
if (ptmp) {
if (( *ptmp == chCommand ) || (*ptmp == chSpace))
ptmp = NULL;
else
{
qch = ptmp;
bOiKin = TRUE;
}
}
} while (ptmp && *ptmp);
// Word End at next pointer of Oidashi Kinsoku.
if (bOiKin) {
if (*qch == chCommand)
chTNew = chTCom;
else
chTNew = chTSuff;
chTOld = chTNew;
break;
}
/*
* DBCS Char treat as One Word. If Next of DBCS Char is
* Oidashi Kinsoku, Word End is after pointer of Oidashi
* Kinsoku. [yutakas]
*/
if (IsDBCSLeadByte(*qch) && Is2ndByte(qch[1])) {
qch += 2;
ptmp = qch;
do {
ptmp = IsOiKinsokuChars(ptmp);
if (ptmp) {
if (( *ptmp == chCommand ) || (*ptmp == chSpace))
ptmp = NULL;
else
qch = ptmp;
}
} while (ptmp && *ptmp);
if (*qch == chCommand)
chTNew = chTCom;
else
chTNew = chTSuff;
chTOld = chTNew;
break;
}
else
goto DoSwitch;
}
else {
DoSwitch:
#endif
switch (*qch) {
case chCommand:
chTNew = chTCom;
break;
case chSpace:
chTNew = chTSuff;
break;
default:
chTNew = chTMain;
break;
}
if (chTNew < chTOld)
break;
chTOld = chTNew;
qch++;
#ifdef DBCS_WRAP
}
#endif
}
qlin->cchSize = (qch - qchBase);
qlin->kl.lich = qlin->lichFirst + (long) qlin->cchSize;
if (chTNew == chTCom)
break;
if (qlin->wFirstWord == wInFirstWord)
qlin->wFirstWord = wHaveFirstWord;
if (qlin->kl.lich >= lichMin)
break;
chTOld = chTMain;
}
if (qlin->cchSize > 0) {
ASSERT(qlin->kl.wStyle != wStyleNil);
if (qde->wStyleDraw != qlin->kl.wStyle) {
SelFont(qde, qlin->kl.wStyle);
qde->wStyleDraw = qlin->kl.wStyle;
}
if (qlin->kl.libHotBinding != libHotNil) {
bButtonType = *((QB)qply->qchText - qlin->kl.libHotBinding);
qlin->dxSize = FindSplTextWidth(qde, qchBase, 0, qlin->cchSize, bButtonType);
}
else
qlin->dxSize = FindTextWidth(qde->hdc, qchBase, 0, qlin->cchSize);
}
if (chTNew == chTCom) {
qlin->chTLast = chTOld;
return(wLayStatusInWord);
}
qlin->chTLast = chTMain;
return(wLayStatusWordBrk);
}
/*-------------------------------------------------------------------------
| WInsertWord(qde, qply, qlin) |
| |
| Purpose: This inserts a frame or series of frames into the text stream.|
-------------------------------------------------------------------------*/
INLINE int STDCALL WInsertWord(QDE qde, QPLY qply, QLIN qlin)
{
PT ptSize;
FR fr;
QFR qfr, qfrMax;
OLR olr;
ASSERT(qlin->lichFirst == lichNil);
switch (qlin->kl.wInsertWord) {
case wInsWordAnno:
PtAnnoLim(qde->hwnd, qde->hdc, &ptSize);
fr.bType = bFrTypeAnno;
fr.rgf.fHot = TRUE;
fr.rgf.fWithLine = TRUE;
fr.xPos = min(qply->qmopg->xLeftIndent,
qply->qmopg->xLeftIndent + qply->qmopg->xFirstIndent);
if (qply->qmopg->fBoxed)
fr.xPos += DxBoxBorder(qply->qmopg, wLineLeft);
fr.yAscent = ptSize.y;
fr.dxSize = ptSize.x;
fr.dySize = ptSize.y;
fr.objrgFront = objrgNil;
fr.objrgFirst = objrgNil;
fr.objrgLast = objrgNil;
qlin->dxSize = 0;
*((QFR) QFooInMR((QMR)&qde->mrFr, sizeof(FR), qlin->kl.ifr)) = fr;
qlin->xPos += ptSize.x;
AppendMR((QMR)&qde->mrFr, sizeof(FR));
qlin->kl.ifr++;
qlin->kl.wInsertWord = wInsWordNil;
return wLayStatusWordBrk;
case wInsWordObject:
olr.xPos = qlin->xPos;
olr.yPos = 0;
olr.ifrFirst = qlin->kl.ifr;
olr.objrgFront = qlin->kl.objrgFront;
olr.objrgFirst = qlin->kl.objrgMax;
LayoutObject(qde, qply->qfcm, qlin->kl.qbCommandInsert, qply->qchText,
0, (QOLR)&olr);
// Hack to make bitmap hotspots work
qfr = (QFR) QFooInMR((QMR)&qde->mrFr, sizeof(FR), olr.ifrFirst);
qfrMax = (QFR) QFooInMR((QMR)&qde->mrFr, sizeof(FR), olr.ifrMax);
for (; qfr < qfrMax; qfr++)
{
if (qfr->bType == bFrTypeBitmap)
{
qfr->rgf.fHot = (qlin->kl.libHotBinding != libHotNil);
qfr->lHotID = qlin->kl.lHotID;
qfr->libHotBinding = qlin->kl.libHotBinding;
qfr->u.frb.wStyle = qlin->kl.wStyle;
}
}
qlin->kl.ifr = olr.ifrMax;
qlin->kl.objrgFront = olr.objrgFront;
qlin->kl.objrgMax = olr.objrgMax;
qfr = (QFR) QFooInMR((QMR)&qde->mrFr, sizeof(FR), olr.ifrFirst);
qfrMax = (QFR) QFooInMR((QMR)&qde->mrFr, sizeof(FR), olr.ifrMax);
for (; qfr < qfrMax; qfr++)
qfr->yAscent = olr.dySize - qfr->yPos;
qlin->kl.wInsertWord = wInsWordNil;
qlin->xPos += olr.dxSize;
qlin->dxSize = 0;
/* (kevynct) 91/05/15
* Fix for H3.1 987: Inserted objects need to be treated like
* characters, so if this is the first character of a word (i.e.
* the last character was a suffix character, like a space), allow
* a word break, and admit that we are in the next word already.
*/
if (qlin->chTLast == chTSuff)
{
qlin->wFirstWord = wInNextWord;
return(wLayStatusWordBrk);
}
return(wLayStatusInWord);
#ifdef _DEBUG
default:
ASSERT(FALSE);
#endif /* DEBUG */
}
}
/*-------------------------------------------------------------------------
| StoreTextFrame(qde, qlin) |
| |
| Purpose: This stores a text frame corresponding to the current lin |
| data structure. |
-------------------------------------------------------------------------*/
static void STDCALL StoreTextFrame(QDE qde, QLIN qlin)
{
FR fr;
if (qlin->cchSize == 0)
{
qlin->lichFirst = lichNil;
return;
}
if (qlin->lichFirst == lichNil)
return;
if (qlin->kl.wStyle != wStyleNil) {
if (qde->wStyleTM != qlin->kl.wStyle) {
SelFont(qde, qlin->kl.wStyle);
GetFontInfo(qde, (QTM) &qde->tm);
/*
* (kevynct)(1) Also sets de.wStyleDraw, since we called
* SelFont
*/
qde->wStyleTM = qde->wStyleDraw = qlin->kl.wStyle;
}
}
fr.bType = bFrTypeText;
fr.rgf.fHot = (qlin->kl.libHotBinding != libHotNil);
fr.rgf.fWithLine = TRUE;
fr.xPos = qlin->xPos;
fr.yAscent = qde->tm.tmAscent;
fr.dxSize = qlin->dxSize;
fr.dySize = (qde->tm.tmHeight + qde->tm.tmExternalLeading);
fr.lHotID = qlin->kl.lHotID;
fr.u.frt.lichFirst = qlin->lichFirst;
fr.u.frt.cchSize = qlin->cchSize;
fr.u.frt.wStyle = qlin->kl.wStyle;
fr.libHotBinding = qlin->kl.libHotBinding;
/*
* Each byte of the text section is considered a separate region.
* This includes text and command bytes.
* Extra regions may be inserted by in-line or wrapped objects.
* Since this is a text frame, we add the text byte regions to
* the counter.
*/
if (qlin->kl.objrgFront != objrgNil)
{
fr.objrgFront = qlin->kl.objrgFront;
qlin->kl.objrgFront = objrgNil;
}
else
fr.objrgFront = qlin->kl.objrgMax;
fr.objrgFirst = qlin->kl.objrgMax;
qlin->kl.objrgMax += qlin->cchSize;
fr.objrgLast = qlin->kl.objrgMax - 1;
*((QFR) QFooInMR((QMR)&qde->mrFr, sizeof(FR), qlin->kl.ifr)) = fr;
AppendMR((QMR)&qde->mrFr, sizeof(FR));
qlin->kl.ifr++;
qlin->xPos += fr.dxSize;
qlin->lichFirst = lichNil;
qlin->dxSize = 0;
}
/*-------------------------------------------------------------------------
| StoreMarkFrame(qde, qlin, bFrType) |
| |
| Purpose: This stores a mark frame corresponding to the given frame |
| type and the current lin data structure. Mark frames are not |
| displayed. They mark the position in the document of non- |
| visible commands such as new-line, new-paragraph, and tab. |
| Each mark frame has one unique address: the address of the |
| corresponding command byte in the command table. |
-------------------------------------------------------------------------*/
void STDCALL StoreMarkFrame(qde, qlin, bFrType)
QDE qde;
QLIN qlin;
BYTE bFrType;
{
FR fr;
/* REVIEW */
ASSERT((bFrType == bFrTypeMarkNewPara)
|| (bFrType == bFrTypeMarkNewLine)
|| (bFrType == bFrTypeMarkTab)
|| (bFrType == bFrTypeMarkBlankLine)
|| (bFrType == bFrTypeMarkEnd)
);
fr.bType = bFrType;
fr.rgf.fHot = FALSE;
fr.rgf.fWithLine = TRUE;
fr.xPos = qlin->xPos;
fr.yPos = 0; /* Set in WLayoutLine */
fr.dxSize = fr.dySize = fr.yAscent = 0;
/*
* Each byte of the text section is considered a separate region.
* This includes text and command bytes.
* Extra regions may be inserted by in-line or wrapped objects.
* Since this is a mark frame, we add one region to
* the counter (currently each mark type corresponds to one cmd byte).
*/
if (qlin->kl.objrgFront != objrgNil)
{
fr.objrgFront = qlin->kl.objrgFront;
qlin->kl.objrgFront = objrgNil;
}
else
fr.objrgFront = qlin->kl.objrgMax;
fr.objrgFirst = qlin->kl.objrgMax;
fr.objrgLast = qlin->kl.objrgMax;
++qlin->kl.objrgMax;
*((QFR) QFooInMR((QMR)&qde->mrFr, sizeof(FR), qlin->kl.ifr)) = fr;
AppendMR((QMR)&qde->mrFr, sizeof(FR));
qlin->kl.ifr++;
}
void STDCALL StoreParaFrame(QDE qde, QLIN qlin, BYTE bType)
{
FR fr;
ASSERT(qlin->lichFirst == lichNil);
fr.bType = bType;
fr.yAscent = fr.dySize = 0;
*((QFR) QFooInMR((QMR)&qde->mrFr, sizeof(FR), qlin->kl.ifr)) = fr;
AppendMR((QMR)&qde->mrFr, sizeof(FR));
qlin->kl.ifr++;
}
void STDCALL DrawTextFrame(QDE qde, PSTR qchText, QFR qfr, POINT pt, BOOL fErase)
{
BYTE bButtonType;
MHI mhi;
if (qde->wStyleDraw != qfr->u.frt.wStyle) {
SelFont(qde, qfr->u.frt.wStyle);
qde->wStyleDraw = qfr->u.frt.wStyle;
}
if (qfr->libHotBinding != libHotNil) {
bButtonType = *((QB)qchText - qfr->libHotBinding);
if (qde->fHiliteHotspots) {
DisplaySplText(qde, qchText + qfr->u.frt.lichFirst, 0, bButtonType, wSplTextHilite,
qfr->u.frt.cchSize, pt.x + qfr->xPos, pt.y + qfr->yPos);
}
else if (qde->imhiSelected != FOO_NIL) {
AccessMRD(((QMRD)&qde->mrdHot));
mhi = *(QMHI) QFooInMRD(((QMRD) &qde->mrdHot), sizeof(MHI), qde->imhiSelected);
DeAccessMRD(((QMRD) &qde->mrdHot));
if (qfr->lHotID == mhi.lHotID) {
DisplaySplText(qde, qchText + qfr->u.frt.lichFirst, 0, bButtonType, wSplTextHilite,
qfr->u.frt.cchSize, pt.x + qfr->xPos, pt.y + qfr->yPos);
}
else {
DisplaySplText(qde, qchText + qfr->u.frt.lichFirst, 0, bButtonType,
(fErase ? wSplTextErase : wSplTextNormal), qfr->u.frt.cchSize,
pt.x + qfr->xPos, pt.y + qfr->yPos);
}
}
else {
DisplaySplText(qde, qchText + qfr->u.frt.lichFirst, 0, bButtonType,
(fErase ? wSplTextErase : wSplTextNormal), qfr->u.frt.cchSize,
pt.x + qfr->xPos, pt.y + qfr->yPos);
}
}
else {
#if defined(BIDI)
#ifdef NO_RALPH_TWEAKS
SetBkMode(qde->hdc, TRANSPARENT);
if ((qde->tm.tmCharSet == HEBREW_CHARSET) ||
(qde->tm.tmCharSet == ARABIC_SIMP_CHARSET) ||
(qde->tm.tmCharSet == ARABIC_TRAD_CHARSET) ||
(qde->tm.tmCharSet == ARABIC_USER_CHARSET))
ExtTextOut(qde->hdc, pt.x + qfr->xPos, pt.y + qfr->yPos,
ETO_RTLREADING,
NULL, (LPSTR) (qchText + qfr->u.frt.lichFirst),
qfr->u.frt.cchSize, NULL);
else
RawTextOut(qde->hdc, pt.x + qfr->xPos, pt.y + qfr->yPos,
(LPSTR) (qchText + qfr->u.frt.lichFirst),
qfr->u.frt.cchSize);
#else // 06-Jun-1995 [ralphw] tweaks to match header files
SetBkMode(qde->hdc, TRANSPARENT);
if ((qde->tm.tmCharSet == HEBREW_CHARSET) ||
(qde->tm.tmCharSet == ARABIC_CHARSET))
ExtTextOut(qde->hdc, pt.x + qfr->xPos, pt.y + qfr->yPos,
ETO_RTLREADING,
NULL, (LPSTR) (qchText + qfr->u.frt.lichFirst),
qfr->u.frt.cchSize, NULL);
else
DisplayText(qde, qchText + qfr->u.frt.lichFirst, 0, qfr->u.frt.cchSize,
pt.x + qfr->xPos, pt.y + qfr->yPos);
#endif
#else // !BIDI
DisplayText(qde, qchText + qfr->u.frt.lichFirst, 0, qfr->u.frt.cchSize,
pt.x + qfr->xPos, pt.y + qfr->yPos);
#endif
}
}
void STDCALL ClickText(QDE qde, QFCM qfcm, QFR qfr)
{
QB qbObj;
LPSTR qchText;
BYTE bButtonType;
MOBJ mobj;
if (qfr->libHotBinding == libHotNil)
return;
qbObj = (QB) QobjLockHfc(qfcm->hfc);
#ifdef _X86_
qchText = qbObj + CbUnpackMOBJ((QMOBJ)&mobj, qbObj);
#else
qchText = qbObj + CbUnpackMOBJ((QMOBJ)&mobj, qbObj, QDE_ISDFFTOPIC(qde));
#endif
qchText += mobj.lcbSize;
bButtonType = *((QB)qchText - qfr->libHotBinding);
// For short hotspots, pass a pointer to the ITO or HASH following
// the hotspot. For long hotspots, pass a pointer to the data
// immediately following the word length. Note that macros are
// now considered long hotspots.
//
// REVIEW: the only difference here is the offset added to libHotBinding.
// REVIEW: there must be a better way. 24-Oct-1990 LeoN
//
if (FLongHotspot(bButtonType))
JumpButton (((QB)qchText - qfr->libHotBinding + 3), bButtonType,
qde);
else {
JumpButton (((QB)qchText - qfr->libHotBinding + 1), bButtonType,
qde);
}
}
/**************************************************************************
* 2.BOOL DisplaySplText(qde, qchBuf, iIdx, iAttr, fSelected, iCount, ix, iy)
*
* Displays count no. of characters starting from iIdx position from the
* text buffer at (ix,iy) location.
*
* Input:
* qde - Pointer to displaye environment.
* qchBuf - pointer to text string
* iIdx - index to the first byte from where on width is to be
* calculated.
* iAttr - Text Attribute i.e Jump or Def Text or Normal text
* fSelected - Is text selected?
* iCount - No. of characters to be considered from iIdx position
* onwards.
* ix - x position where text is to be displayed.
* iy - y position
*
* Output: unknown
***************************************************************************/
static BOOL STDCALL DisplaySplText(
QDE qde,
LPSTR qchBuf,
int iIdx, int iAttr, int fSelected, int iCount, int ix, int iy
) {
HBITMAP hbit; // handle to DC's bitmap
HDC hdcBit; // DC of control window bits
BOOL iRet = FALSE;
int ex;
TM tm;
int cxDot, cyDot, iyDot; /* Height, width, and placement of dotted
* underline. */
if (FInvisibleHotspot(iAttr)) {
// Don't just call DisplayText() because we have to deal with
// invisible jumps that have been tabbed to.
iAttr = 0;
}
/*
* Since dotted underlines take too long to print, we'll try solid
* underlines for printing.
*/
if (qde->deType == dePrint && FNoteHotspot(iAttr))
iAttr = AttrJumpFnt;
// Select the special font
if (SelSplAttrFont(qde, qde->ifnt, iAttr)) {
/* (kevynct)
* REVIEW THIS:
* For some reason, if I remove the following call to SetBkMode,
* TextOut puts the text out using the background colour instead
* of using transparent mode. I haven't been able to find where
* it is being set to OPAQUE, if anywhere.
*/
SetBkMode(qde->hdc, TRANSPARENT);
if (fSelected == wSplTextErase) {
ex = FindTextWidth(qde->hdc, qchBuf, iIdx, iCount);
GetTextMetrics( qde -> hdc, (LPTEXTMETRIC)&tm );
PatBlt(qde->hdc, ix, iy, ex, tm.tmHeight + tm.tmExternalLeading,
DSTINVERT);
iRet = TRUE;
}
if (fSelected == wSplTextNormal || fSelected == wSplTextHilite) {
#if defined(BIDI_MULT) // jgross - combine HEB and ARA for multi
if ((qde->tm.tmCharSet == HEBREW_CHARSET) ||
#if 1 // 06-Jun-1995 [ralphw] This is the only Arabic charset in wingdi.h
(qde->tm.tmCharSet == ARABIC_CHARSET))
#else
(qde->tm.tmCharSet == ARABIC_SIMP_CHARSET) ||
(qde->tm.tmCharSet == ARABIC_TRAD_CHARSET) ||
(qde->tm.tmCharSet == ARABIC_USER_CHARSET))
#endif
#if 1 // 06-Jun-1995 [ralphw] ETO_RTL_READING not in header files
iRet = ExtTextOut(qde->hdc, ix, iy, ETO_RTL, NULL,
qchBuf + iIdx, iCount, NULL);
#else
iRet = ExtTextOut(qde->hdc, ix, iy, ETO_RTL_READING, NULL,
qchBuf + iIdx, iCount, NULL);
#endif
else
iRet = RawTextOut(qde->hdc, ix, iy, qchBuf + iIdx, iCount);
#else // !BIDI_MULT
iRet = TextOut(qde->hdc, ix, iy, qchBuf + iIdx, iCount);
#endif
if (FNoteHotspot(iAttr)) {
// put a dotted line
ASSERT(hbitLine);
if ((hdcBit = CreateCompatibleDC(qde->hdc)) != NULL &&
(hbit = (HBITMAP) SelectObject(hdcBit, hbitLine)) != NULL) {
GetFontInfo(qde, (LPTEXTMETRIC) &tm);
/*
* This is supposed to result in a 1 pixel separation between
* text and underline in EGA or better, and no separation for CGA
*/
iyDot = iy + tm.tmAscent +
(GetDeviceCaps(qde->hdc, LOGPIXELSY) / 64);
cxDot = GetSystemMetrics(SM_CXBORDER);
cyDot = GetSystemMetrics(SM_CYBORDER);
/* This is the code for printing dotted underlines */
#if 0
/* Special code for printer support: */
if (qde->deType == dePrint)
{
POINT ptScale;
EXTTEXTMETRIC etm;
int cbEtm;
cbEtm = sizeof( etm );
if (Escape( qde->hdc, GETEXTENDEDTEXTMETRICS, 0, (LPSTR)&cbEtm,
(LPSTR) &etm) == sizeof(etm)) {
iyDot = iy + MulDiv( etm.etmUnderlineOffset, etm.etmMasterHeight,
etm.etmMasterUnits );
cyDot = MulDiv( etm.etmUnderlineWidth, etm.etmMasterHeight,
etm.etmMasterUnits );
cxDot = MulDiv( cyDot, GetDeviceCaps( qde->hdc, LOGPIXELSX ),
GetDeviceCaps( qde->hdc, LOGPIXELSY ) );
}
else
{
HDC hdcScreen;
hdcScreen = GetDC( NULL );
cyDot = MulDiv( cyDot, GetDeviceCaps( qde->hdc, LOGPIXELSY ),
GetDeviceCaps( hdcScreen, LOGPIXELSY ) );
cxDot = MulDiv( cxDot, GetDeviceCaps( qde->hdc, LOGPIXELSX ),
GetDeviceCaps( hdcScreen, LOGPIXELSX ) );
ReleaseDC( NULL, hdcScreen );
}
if (Escape( qde->hdc, GETSCALINGFACTOR, 0, NULL,
(LPSTR) &ptScale ) > 0 )
{
cxDot = (((cxDot-1) >> ptScale.x) + 1) << ptScale.x;
cyDot = (((cyDot-1) >> ptScale.y) + 1) << ptScale.y;
}
}
#endif
ex = FindTextWidth(qde->hdc, qchBuf, iIdx, iCount);
if (cxDot == 1 && cyDot == 1)
BitBlt( qde->hdc, ix, iyDot, ex, 1, hdcBit, 0, 0, SRCCOPY );
else
StretchBlt( qde->hdc, ix, iyDot, ex, cyDot,
hdcBit, 0, 0, ex / cxDot, 1, SRCCOPY );
if (hbit)
SelectObject(hdcBit, hbit);
}
if (hdcBit != NULL)
DeleteDC( hdcBit );
}
}
if (fSelected == wSplTextHilite) {
ex = FindTextWidth(qde -> hdc, qchBuf, iIdx, iCount);
GetFontInfo(qde, (LPTEXTMETRIC) &tm);
PatBlt(qde -> hdc, ix, iy, ex, tm.tmHeight + tm.tmExternalLeading,
DSTINVERT);
iRet = TRUE;
}
// restore back to the previous font
SelFont(qde, qde->ifnt);
}
return(iRet);
}
/**************************************************************************
4. WORD FindTextWidth( qde, qchBuf, iIdx, iCount)
Input:
qde - Pointer to display environment.
qchBuf - pointer to text string
iIdx - index to the first byte from where on width is to be
calculated.
iCount - No. of characters to be considered from iIdx position
onwards.
Output:
Returns the width of the string.
***************************************************************************/
WORD STDCALL FindTextWidth(HDC hdc, PSTR qchBuf, int iIdx, int iCount)
{
SIZE size;
GetTextExtentPoint(hdc, qchBuf + iIdx, iCount, &size);
return (WORD) size.cx;
}
/*-------------------------------------------------------------------------
| LayoutObject(qde, qfcm, qbObj, qchText, xWidth, qolr) |
| |
| Purpose: Lays out an object. |
| Params: qfcm Parent FCM |
| qbObj Pointer to beginning of object header |
| qchText Text data for this FCM |
| xWidth Total available display width. Certain objects |
| may exceed this width. |
| qolr OLR to work with. |
| Useage: The object handler (paragraph, bitmap, etc.) may either set |
| qolr->dxSize and qolr->dySize itself, or it may choose to |
| allow LayoutObject() to set them. If they are left as 0, |
| they will be set to correspond to the smallest rectangle |
| enclosing all frames in the object. Some objects, such as |
| paragraph objects with space underneath, need to be able to |
| set a larger size than their frames occupy. |
-------------------------------------------------------------------------*/
void STDCALL LayoutObject(QDE qde, QFCM qfcm, PBYTE qbObj, PSTR qchText,
int xWidth, QOLR qolr)
{
int ifr;
QFR qfr;
MOBJ mobj;
#ifdef _X86_
CbUnpackMOBJ((QMOBJ)&mobj, qbObj);
#else
CbUnpackMOBJ((QMOBJ)&mobj, qbObj, QDE_ISDFFTOPIC(qde));
#endif
qolr->dxSize = qolr->dySize = 0;
switch (mobj.bType)
{
case bTypeParaGroup:
case bTypeParaGroupCounted:
LayoutParaGroup(qde, qfcm, qbObj, qchText, xWidth, qolr);
break;
case bTypeBitmap:
case bTypeBitmapCounted:
LayoutBitmap(qde, qfcm, qbObj, qolr);
break;
case bTypeSbys:
case bTypeSbysCounted:
LayoutSideBySide(qde, qfcm, qbObj, qchText, xWidth, qolr);
break;
case bTypeWindow:
case bTypeWindowCounted:
LayoutWindow(qde, qfcm, qbObj, qolr);
break;
#ifdef _DEBUG
default:
ASSERT(FALSE);
break;
#endif /* DEBUG */
}
if (qolr->dxSize == 0 && qolr->dySize == 0)
{
for (ifr = qolr->ifrFirst; ifr < qolr->ifrMax; ifr++)
{
qfr = (QFR) QFooInMR((QMR)&qde->mrFr, sizeof(FR), ifr);
qolr->dxSize = max(qolr->dxSize, qfr->xPos + qfr->dxSize);
qolr->dySize = max(qolr->dySize, qfr->yPos + qfr->dySize);
qfr->xPos += qolr->xPos;
qfr->yPos += qolr->yPos;
}
}
}
/**************************************************************************
* 1. WORD FindSplTextWidth( qde, qchBuf, iIdx, iCount, iAttr)
*
* Input:
* qde - Pointer to display environment.
* qchBuf - pointer to text string
* iIdx - index to the first byte from where on width is to be
* calculated.
* iCount - No. of characters to be considered from iIdx position
* onwards.
* iAttr - Text Attribute
* Output:
* Returns the width of the string.
*
* Note: Nobody knows why this function works the way it does.
*
***************************************************************************/
static int STDCALL FindSplTextWidth(
QDE qde,
LPSTR qchBuf,
int iIdx, int iCount, int iAttr
) {
int wWidth;
if ((FJumpHotspot(iAttr) && FVisibleHotspot(iAttr))) {
if (SelSplAttrFont(qde, qde->ifnt, iAttr)) {
wWidth = FindTextWidth(qde -> hdc, qchBuf, iIdx, iCount);
// restore back to the previous font
SelFont(qde, qde->ifnt);
}
else {
NotReached();
}
}
else {
return FindTextWidth(qde->hdc, qchBuf, iIdx, iCount);
}
return wWidth;
}
INLINE static int STDCALL WProcessCommand(QDE qde, QLIN qlin, QPLY qply)
{
int xT, wTabType;
QFR qfr, qfrMax;
BYTE bT;
MOBJ mobj;
QTWS qtws;
switch ((bT = *qlin->kl.qbCommand))
{
case bWordFormat:
StoreTextFrame(qde, qlin);
qlin->bFrTypeMark = bFrTypeMarkNil;
/* The next frame will begin at this cmd byte's object region */
if (qlin->kl.objrgFront == objrgNil)
qlin->kl.objrgFront = qlin->kl.objrgMax;
qlin->kl.objrgMax++;
#ifdef _X86_
qlin->kl.wStyle = *((QI)(++qlin->kl.qbCommand));
qlin->kl.qbCommand += 2;
#else
qlin->kl.qbCommand ++;
qlin->kl.qbCommand += LcbQuickMapSDFF(QDE_ISDFFTOPIC(qde),
TE_WORD, &qlin->kl.wStyle, qlin->kl.qbCommand);
#endif
return(wLayStatusInWord);
case bNewLine:
qlin->bFrTypeMark = bFrTypeMarkNewLine;
qlin->kl.qbCommand++;
/* There is now a mark frame pending. */
/* We store the mark frame AFTER storing the text frame. */
/* We increment the objrg count when storing the mark frame */
return(wLayStatusLineBrk);
case bNewPara:
qlin->bFrTypeMark = bFrTypeMarkNewPara;
qlin->kl.qbCommand++;
/* There is now a mark frame pending. */
/* We store the mark frame AFTER storing the text frame */
/* We increment the objrg count when storing the mark frame */
return(wLayStatusParaBrk);
case bTab:
qlin->kl.qbCommand++;
StoreTextFrame(qde, qlin);
ResolveTabs(qde, qlin, qply);
if (qply->qfcm->fExport)
StoreTabFrame(qde, qlin);
// We increment the objrg count when storing the mark frame
StoreMarkFrame(qde, qlin, bFrTypeMarkTab);
qlin->bFrTypeMark = bFrTypeMarkNil;
xT = XNextTab(qlin, qply, &wTabType);
if (xT > qply->xRight && !qply->qmopg->fSingleLine)
return(wLayStatusLineBrk);
if (wTabType == wTabTypeLeft)
{
qlin->xPos = xT;
return(wLayStatusWordBrk);
}
qlin->wTabType = wTabType;
qlin->ifrTab = qlin->kl.ifr;
qlin->xTab = xT;
return(wLayStatusWordBrk);
case bBlankLine:
qlin->kl.qbCommand++;
qlin->yBlankLine = *((QI)qlin->kl.qbCommand);
#ifdef _X86_
qlin->kl.qbCommand += 2;
#else
qlin->kl.qbCommand += LcbQuickMapSDFF(QDE_ISDFFTOPIC(qde),
TE_WORD, &qlin->kl.wStyle, qlin->kl.qbCommand);
#endif
qlin->bFrTypeMark = bFrTypeMarkBlankLine;
/* There is now a mark frame pending. */
/* We store the mark frame AFTER storing the text frame */
/* We increment the objrg count when storing the mark frame */
return(wLayStatusLineBrk);
case bInlineObject:
ASSERT(qlin->kl.wInsertWord == wInsWordNil);
StoreTextFrame(qde, qlin);
ResolveTabs(qde, qlin, qply);
qlin->kl.qbCommandInsert = ++(qlin->kl.qbCommand);
#ifdef _X86_
qlin->kl.qbCommand += CbUnpackMOBJ((QMOBJ)&mobj, qlin->kl.qbCommand);
#else
qlin->kl.qbCommand += CbUnpackMOBJ((QMOBJ)&mobj, qlin->kl.qbCommand,
QDE_ISDFFTOPIC(qde));
#endif
qlin->kl.qbCommand += mobj.lcbSize;
qlin->kl.wInsertWord = wInsWordObject;
qlin->bFrTypeMark = bFrTypeMarkNil;
/* NOTE: We do not increment region here. This is because an
* inserted object's frames are numbered BEFORE the command byte.
* The increment is done after we add the frames.
*/
return(wLayStatusInWord);
case bWrapObjLeft:
case bWrapObjRight:
AccessMR(((QMR)&qde->mrTWS));
StoreTextFrame(qde, qlin);
ResolveTabs(qde, qlin, qply);
AppendMR(((QMR)&qde->mrTWS), sizeof(TWS));
qtws = (QTWS)(QFooInMR(((QMR)&qde->mrTWS), sizeof(TWS),
CFooInMR(((QMR)&qde->mrTWS)) - 1));
qtws->fLeftAligned = (bT == bWrapObjLeft);
qlin->kl.qbCommand++;
qlin->cWrapObj++;
qtws->olr.xPos = 0;
qtws->olr.yPos = 0;
qtws->olr.ifrFirst = qlin->kl.ifr;
qtws->olr.objrgFront = qlin->kl.objrgFront;
qtws->olr.objrgFirst = qlin->kl.objrgMax;
LayoutObject(qde, qply->qfcm, qlin->kl.qbCommand, qply->qchText,
0, (QOLR)&qtws->olr);
#ifdef _X86_
qlin->kl.qbCommand += CbUnpackMOBJ((QMOBJ)&mobj, qlin->kl.qbCommand);
#else
qlin->kl.qbCommand += CbUnpackMOBJ((QMOBJ)&mobj, qlin->kl.qbCommand,
QDE_ISDFFTOPIC(qde));
#endif
qlin->kl.qbCommand += mobj.lcbSize;
qlin->kl.ifr = qtws->olr.ifrMax;
/* (kevynct)
* All regions here are assigned by the object, including the
* 'basic' region that addresses the entire object. For a
* bitmap with no hotspots, for example, the object region count
* is just bumped by one by the bitmap handler.
*/
qlin->kl.objrgMax = qtws->olr.objrgMax;
qlin->kl.objrgFront = qtws->olr.objrgFront;
qlin->bFrTypeMark = bFrTypeMarkNil;
qfr = (QFR) QFooInMR((QMR)&qde->mrFr, sizeof(FR), qtws->olr.ifrFirst);
qfrMax = (QFR) QFooInMR((QMR)&qde->mrFr, sizeof(FR), qtws->olr.ifrMax);
for (; qfr < qfrMax; qfr++)
{
/* (kevynct)
*
* This seems like the only good place to put this for now.
* Note that the code for setting the proper bitmap wStyle param
* is currently spread out among wrapped objects and in-line
* objects. There must be a way to consolidate this.
*/
if(qfr->bType == bFrTypeBitmap)
{
qfr->rgf.fHot = (qlin->kl.libHotBinding != libHotNil);
qfr->lHotID = qlin->kl.lHotID;
qfr->libHotBinding = qlin->kl.libHotBinding;
qfr->u.frb.wStyle = qlin->kl.wStyle;
}
qfr->rgf.fWithLine = FALSE;
}
DeAccessMR(((QMR)&qde->mrTWS));
return(wLayStatusWordBrk);
case bEndHotspot:
ASSERT(qlin->kl.libHotBinding != libHotNil);
StoreTextFrame(qde, qlin);
qlin->kl.libHotBinding = libHotNil;
qlin->kl.qbCommand++;
qlin->bFrTypeMark = bFrTypeMarkNil;
/* The next frame will begin at this cmd byte's object region */
/*
* Ideally we would backpatch the previous frame to include this
* object region, but this doesn't seem worth the hassle?
*/
if (qlin->kl.objrgFront == objrgNil)
qlin->kl.objrgFront = qlin->kl.objrgMax;
qlin->kl.objrgMax++;
return(wLayStatusInWord);
case bEnd:
qlin->kl.qbCommand++;
qlin->bFrTypeMark = bFrTypeMarkEnd;
/* There is now a mark frame pending. */
/* We store the mark frame AFTER storing the text frame. */
/* We increment the objrg count when storing the mark frame */
return(wLayStatusEndText);
default:
/* "Begin hotspot" cmd */
ASSERT(FHotspot(bT));
ASSERT(qlin->kl.libHotBinding == libHotNil);
StoreTextFrame(qde, qlin);
qlin->kl.libHotBinding = (qply->qchText - qlin->kl.qbCommand);
#ifdef _X86_
if (FShortHotspot(bT))
{
qlin->kl.qbCommand += 5;
}
else
{
qlin->kl.qbCommand++;
qlin->kl.qbCommand += 2 + *((QW)qlin->kl.qbCommand);
}
#else
qlin->kl.qbCommand++;
if (FShortHotspot(bT))
{
qlin->kl.qbCommand += LcbStructSizeSDFF(QDE_ISDFFTOPIC(qde), TE_LONG);
}
else
{
WORD wSize;
qlin->kl.qbCommand += LcbQuickMapSDFF(QDE_ISDFFTOPIC(qde),
TE_WORD, &wSize, qlin->kl.qbCommand);
qlin->kl.qbCommand += wSize;
}
#endif
qlin->kl.lHotID = ++qde->lHotID;
qlin->bFrTypeMark = bFrTypeMarkNil;
/* The next frame will begin at this cmd byte's object region */
if (qlin->kl.objrgFront == objrgNil)
qlin->kl.objrgFront = qlin->kl.objrgMax;
qlin->kl.objrgMax++;
return(wLayStatusInWord);
break;
}
}
/*-------------------------------------------------------------------------
| AppendMR(qmr, cbFooSize) |
| |
| Purpose: This makes room for a new element at the end of the MR. |
-------------------------------------------------------------------------*/
void STDCALL AppendMR(QMR qmr, int cbFooSize)
{
#ifdef _DEBUG // ignore in _PRIVATE
ASSERT(qmr->wMagic == wMagicMR);
ASSERT(qmr->cLocked > 0);
#endif
if (++qmr->cFooCur == qmr->cFooMax) {
qmr->hFoo = GhForceResize(qmr->hFoo, 0,
(LONG) cbFooSize * (qmr->cFooMax += DC_FOO));
qmr->qFoo = PtrFromGh(qmr->hFoo);
}
}
/*******************
-
- Name: PtAnnoLim
*
* Purpose: Returns the width and height of the annotation sybmol (temporary)
*
* Arguments: hdc - handle to the display space (DC)
*
* Returns: size in a point structure
*
******************/
#include "resource.h"
INLINE void STDCALL PtAnnoLim(HWND hwnd, HDC hdc, POINT* ppt)
{
HBITMAP hbit;
BITMAP bm;
hbit = LoadBitmap(hInsNow, MAKEINTRESOURCE(IDBMP_ANNO));
GetObject(hbit, sizeof(BITMAP), &bm);
ppt->x = bm.bmWidth;
ppt->y = bm.bmHeight;
DeleteObject(hbit);
}
/***************************************************************************
*
- Name: FIsSecondaryQde
-
* Purpose:
* Determines whether the passed qde refers to a secondary window.
*
* Arguments:
* qde - de we are interested in.
*
* Returns:
* TRUE if it does refer to such a window.
*
* Globals Used:
* hwndTopic2nd, hwndTitle2nd
*
***************************************************************************/
INLINE BOOL STDCALL FIsSecondaryQde(QDE qde)
{
return (qde->hwnd != ahwnd[MAIN_HWND].hwndTopic)
&& (qde->hwnd == ahwnd[MAIN_HWND].hwndTitle);
}
#ifdef DBCS
static PSTR STDCALL IsKinsokuChars(PCSTR pszString)
{
PSTR p;
if (!*pszString)
return NULL;
if (IsDBCSLeadByte(*pszString) && Is2ndByte(pszString[1])) {
for (p = txtJapanKinsokuChars; *p; p +=2 ) {
if (*pszString == p[0] && *(pszString + 1) == p[1]) {
return (PSTR) pszString + 2;
}
}
}
else {
for (p = txtHanKinsokuChars; *p; p++) {
if (*pszString == *p) {
return (PSTR) pszString + 1;
}
}
}
return NULL;
}
static PSTR STDCALL IsOiKinsokuChars(PCSTR pszString)
{
PSTR p;
if (!*pszString)
return NULL;
if (IsDBCSLeadByte(*pszString) && Is2ndByte(pszString[1])) {
for (p = txtOiKinsokuChars; *p; p += 2) {
if (*pszString == p[0] && *(pszString + 1) == p[1]) {
return (PSTR) pszString + 2;
}
}
}
else {
for (p = txtHanOiKinsokuChars; *p; p++) {
if (*pszString == *p) {
return (PSTR) pszString + 1;
}
}
}
return NULL;
}
#if 0
static int STDCALL IsSecondBytePtr(PCSTR ptr, PCSTR ptrtop)
{
PBYTE p;
PBYTE p0;
p = (PBYTE) ptrtop;
p0 = (PBYTE) ptr;
while (p < p0) {
if (IsDBCSLeadByte(*p)) {
p += 2; // skip second byte
} else {
p++;
}
}
if (p > p0)
return 1;
else
return 0;
}
#endif
BOOL STDCALL Is2ndByte(BYTE ch)
{
if (defcharset == SHIFTJIS_CHARSET)
return (((ch) >= 0x40 && (ch) <= 0x7e) ||
((ch) >= (BYTE) 0x80 && (ch) <= (BYTE) 0xfc));
else if (defcharset == CHINESEBIG5_CHARSET)
return ((ch >= 0x40 && ch <= (BYTE) 0x7e) ||
(ch >= (BYTE) 0xa1 && ch <= (BYTE) 0xff));
else
return FALSE;
}
#endif