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.
 
 
 
 
 
 

3079 lines
72 KiB

/*****************************************************************************
*
* frselect.c
* Copyright (C) Microsoft Corporation 1993.
* All Rights reserved.
*
******************************************************************************
*
* Module intent: This file contains code for text selection.
*
******************************************************************************
*
* Previous Owner: t-HarshR
* Previous Owner: RHobbs
* Current Owner: garrg
* Current Owner: ronm
*
* 02/23/94 -- Converted for use by WinHelp
*
*****************************************************************************/
#include "help.h"
#ifdef _DEBUG // don't want this in the retail release
static char * s_aszModule = __FILE__; // For error report
#endif
#include "inc\frstuff.h"
#include "inc\fcpriv.h"
#include "inc\navpriv.h"
#include <ctype.h>
enum {
NONE = 1,
UP,
DOWN,
LEFT,
RIGHT,
START,
END,
};
#define ifcmNil (-1)
#define LONG_MAX 2147483647 // maximum (signed) long value
/* All these are support functions that are called by the Arbitrary
selection APIs. */
static LONG lichFindMark(QDE qde, QFCM qfcm, POINT pt, int *pIFR);
static void HighlightFrames(QDE, PHELPHILITE, UINT);
static BOOL STDCALL IsSentenceDelim(LPCSTR, int);
static BOOL STDCALL IsWordDelim(LPCSTR);
static void STDCALL FindFrameBounds(QFR, int, int, int *, int*);
static void STDCALL InvalidateSelection(QDE qde);
static QFCM STDCALL qfcmGetSelectionPosition(QDE qde, POINT pt, LONG *plich, int *pIFR);
// QDE qdeSelected= NULL;
BOOL STDCALL IsSelected(QDE qde)
{
return (qde->vaStartMark.dword != qde->vaEndMark.dword
|| qde->lichStartMark != qde->lichEndMark);
}
void STDCALL KillSelection(QDE qdeFocus, BOOL fExtendSelection)
{
// This routine invalidates selections the currently active
// window.
HWND hwndTopic;
HDE hde;
QDE qde;
HDC hdc;
hwndTopic= hwndNote? hwndNote : ahwnd[iCurWindow].hwndTopic;
if (!hwndNote)
{
hde= HdeGetEnvHwnd(ahwnd[iCurWindow].hwndTitle);
if (hde && FTopicHasNSR(hde))
{
qde= QdeFromGh(hde);
if (IsSelected(qde))
{
hdc= 0;
if (!qde->hdc) qde->hdc= hdc= GetDC(qde->hwnd);
if (!fExtendSelection || qde != qdeFocus) InvalidateSelection(qde);
if (hdc)
{
ReleaseDC(qde->hwnd, hdc);
qde->hdc=NULL;
}
UpdateWindow(qde->hwnd);
}
}
}
hde= HdeGetEnvHwnd(hwndTopic);
if (hde && FTopicHasSR(hde))
{
qde= QdeFromGh(hde);
if (IsSelected(qde))
{
hdc= 0;
if (!qde->hdc) qde->hdc= hdc= GetDC(qde->hwnd);
if (!fExtendSelection || qde != qdeFocus)
InvalidateSelection(qde);
if (hdc)
{
ReleaseDC(qde->hwnd, hdc);
qde->hdc=NULL;
}
UpdateWindow(qde->hwnd);
}
}
}
/********************************************************************
* These are functions called directly by the MediaView APIs. These calls
* are the meat of the Text Selection process and primarily serve as shells
* so that levels of abstraction can be maintained.
*********************************************************************/
/*********************************************************************
* static QFCM qfcmGetSelectionPosition (QDE qde, PT pt, LONG *plich)
*
* This function calculates the QFCM and lichMark given a qde
* and a point.
*
* pIFR can be NULL, if the value is not wanted.
*
* mrdFCM must have been accessed prior to calling
*/
// REVIEW: why INT instead of int? INT forces 16-bit value
static QFCM STDCALL qfcmGetSelectionPosition (QDE qde, POINT pt,
LONG *plich, int *pIFR)
{
int ifcm,ifcmLast;
QFCM qfcm;
LONG lichMark;
RECT rc;
// adjust based on scroll position
pt.x += qde->xScrolled;
GetWindowWRect(qde->hwnd, (WRECT*) &rc);
if (pt.x < 0)
pt.x= 0;
if (pt.y < 0) {
pt.y= 0;
pt.x= 0;
}
if (pt.x >= rc.right)
pt.x= rc.right - 1;
if (pt.y >= rc.bottom) {
pt.y= rc.bottom - 1;
pt.x= rc.right-1;
}
//
// Find the FM the point is in.
//
for (ifcm = IFooFirstMRD((QMRD)&qde->mrdFCM),qfcm=NULL;
ifcm != FOO_NIL;
ifcm = IFooNextMRD((QMRD)&qde->mrdFCM, sizeof(FCM),ifcm))
{
ifcmLast = ifcm;
qfcm = (QFCM)QFooInMRD(((QMRD)&qde->mrdFCM), sizeof(FCM),
ifcm);
if ((pt.y >= qfcm->yPos) &&
(pt.y <= qfcm->yPos + qfcm->dySize))
break;
}
//
// we repeat until we get a valid lichMark or we tried all
// of the text frames.
//
while (qfcm)
{
lichMark = lichFindMark (qde, qfcm, pt, pIFR);
if (lichMark != -1)
{
*plich = lichMark;
break;
}
else
{
// There may have been no text frames in the
// FC that we attempted, so go to the next one.
if (ifcm==FOO_NIL ||
(ifcm = IFooNextMRD((QMRD)&qde->mrdFCM, sizeof(FCM),ifcm))==FOO_NIL)
{
// no more frames, try the previous. we really need to do this!
if (ifcmLast!=FOO_NIL)
ifcm = IFooPrevMRD ((QMRD)&qde->mrdFCM, sizeof(FCM),ifcmLast);
ifcmLast = ifcm;
if (ifcm==FOO_NIL)
{
// set an error here.
qfcm = NULL;
break;
}
}
qfcm = (QFCM)QFooInMRD(((QMRD)&qde->mrdFCM), sizeof(FCM),ifcm);
}
};
return qfcm;
}
/*********************************************************************/
//
// vSelectPoint
//
// mousept - the point, relative to the layout to set selection point.
// fExtend - TRUE to extend selection, FALSE to reset.
//
// This function begins or extends a selection. If we are
// beginning the start position of our selection is set at the
// point passed, otherwise the end position is set to that point.
//
void STDCALL vSelectPoint(QDE qde, POINT mousept, BOOL fExtend, DWORD *lpERR)
{
LONG lichMark;
QFCM qfcm;
if (!fExtend) InvalidateSelection(qde);
AccessMRD((QMRD)&qde->mrdFCM);
qfcm = qfcmGetSelectionPosition (qde, mousept, &lichMark, NULL);
if (qfcm!=NULL)
{
if (fExtend)
{
BOOL fSelectionChanged= qde-> vaEndMark.dword != qfcm->va.dword
|| qde-> lichEndMark != lichMark;
if ( fSelectionChanged
&& qde-> vaStartMark.dword == qde-> vaEndMark.dword
&& qde->lichStartMark == qde->lichEndMark
) InvertSelection(qde);
//
// highlight the frames between the previous end
// point and the new one.
//
if(fSelectionChanged)
{
HELPHILITE hh;
hh.ichBase = qde->lichEndMark;
hh.vaBase = qde-> vaEndMark;
hh.vaLimit = qde-> vaEndMark = qfcm->va;
hh.ichLimit = qde->lichEndMark = lichMark;
HighlightFrames(qde, &hh, 1);
if ( qde-> vaStartMark.dword == qde-> vaEndMark.dword
&& qde->lichStartMark == qde->lichEndMark
) InvertSelection(qde);
}
}
else
{
InvalidateSelection(qde);
//
// set beginning selection and end to the
// new point.
qde->vaStartMark = qfcm->va;
qde->vaEndMark = qfcm->va;
qde->lichStartMark = lichMark;
qde->lichEndMark = lichMark;
}
}
DeAccessMRD((QMRD)&qde->mrdFCM);
}
#if 0
05-Mar-1994 [ralphw] Not used
/* Corresponds to fMVClearSelection*/
VOID STDCALL ClearSelection(qde)
QDE qde;
{
InvalidateSelection(qde);
}
#endif
/******************************************************************
* vSelectWord
*
* QDE qde - the qde to change selection in.
* POINT mousept - the point at which the selection is to be made
* BOOL fExtend - TRUE to extend current selection.
* WORD *lpERR - currently not used.
*
* This function can be used to select a single word, or to extend
* the selection word by word.
*/
void STDCALL vSelectWord(QDE qde, POINT mousept, BOOL fExtend, DWORD *lpERR)
{
QFCM qfcm;
LONG lichMark, lichStartMark, lichEndMark;
PSTR qchText;
QB qbObj;
MOBJ mobj;
QFR qfr;
int ifr, tmpifr;
if (!fExtend)
InvalidateSelection(qde);
AccessMRD((QMRD)&qde->mrdFCM);
qfcm = qfcmGetSelectionPosition (qde, mousept, &lichMark, &ifr);
if (qfcm==NULL)
{
DeAccessMRD((QMRD)&qde->mrdFCM);
//
// set error
return;
}
qbObj = (QB)PtrFromGh(qfcm->hfc) + sizeof(FCINFO);
#ifdef _X86_
qchText = qbObj + CbUnpackMOBJ((QMOBJ)&mobj, qbObj);
#else
qchText = qbObj + CbUnpackMOBJ((QMOBJ)&mobj, qbObj, QDE_ISDFFTOPIC(qde));
#endif
qchText += mobj.lcbSize;
// start with start and end points
lichStartMark = lichEndMark = lichMark;
qfr = (QFR)PtrFromGh(qfcm->hfr);
qfr += ifr;
// check if our point is really in this frame
// and that is not at a space.
//
// starting at a space or outside of frame sets both
// start and end at that point, so don't look for
// start and end points.
mousept.x += qde->xScrolled;
if (mousept.x < qfcm->xPos + qfr->xPos ||
mousept.x > qfcm->xPos + qfr->xPos + qfr->dxSize ||
mousept.y < qfcm->yPos + qfr->yPos ||
mousept.y > qfcm->yPos + qfr->yPos + qfr->dySize ||
*(qchText + lichMark) == ' ')
{
}
else
{
//
// find word delimiter in front.
//
tmpifr = ifr;
// qfr is already locked and set!
while( !IsWordDelim(qchText + lichStartMark) && (lichStartMark >= 0) )
{
if( lichStartMark < qfr->u.frt.lichFirst )
{
if (tmpifr==0) break; // we are at beginning
tmpifr--;
qfr--;
if (qfr->bType != bFrTypeText)
{
break;
}
lichStartMark = qfr->u.frt.lichFirst + qfr->u.frt.cchSize;
}
lichStartMark--;
}
lichStartMark++;
//
// find the end position
//
tmpifr = ifr;
qfr = (QFR)PtrFromGh(qfcm->hfr);
qfr += tmpifr;
while( !IsWordDelim(qchText + lichEndMark) )
{
lichEndMark++;
if( lichEndMark > (qfr->u.frt.lichFirst + qfr->u.frt.cchSize) )
{
tmpifr++;
qfr++;
if( (qfcm->cfr == tmpifr) || (qfr->bType != bFrTypeText) )
{
lichEndMark--;
break;
}
lichEndMark = qfr->u.frt.lichFirst;
}
}
}
// now set the selection
if (fExtend)
{
BOOL fSelectionChanged= qde-> vaEndMark.dword != qfcm->va.dword
|| qde-> lichEndMark != lichMark;
if ( fSelectionChanged
&& qde-> vaStartMark.dword == qde-> vaEndMark.dword
&& qde->lichStartMark == qde->lichEndMark
) InvertSelection(qde);
// if our current end is less than our start, make our
// end point our start point.
if (qde->vaEndMark.dword < qde->vaStartMark.dword ||
(qde->vaEndMark.dword == qde->vaStartMark.dword &&
qde->lichEndMark < qde->lichStartMark))
{
lichEndMark = lichStartMark;
}
// invert if necessary
if (fSelectionChanged)
{
HELPHILITE hh;
hh.ichBase = qde->lichEndMark;
hh.vaBase = qde-> vaEndMark;
hh.vaLimit = qde-> vaEndMark = qfcm->va;
hh.ichLimit = qde->lichEndMark = lichEndMark;
HighlightFrames(qde, &hh, 1);
if ( qde-> vaStartMark.dword == qde-> vaEndMark.dword
&& qde->lichStartMark == qde->lichEndMark
) InvertSelection(qde);
}
}
else
{
HELPHILITE hh;
hh.ichBase = qde->lichStartMark = lichStartMark;
hh.vaBase = qde-> vaStartMark = qfcm->va;
hh.ichLimit = qde-> lichEndMark = lichEndMark;
hh.vaLimit = qde-> vaEndMark = qfcm->va;
HighlightFrames(qde, &hh, 1);
}
DeAccessMRD((QMRD)&qde->mrdFCM);
}
/******************************************************************
* vSelectSentence
*
* QDE qde - the qde to change selection in.
* POINT mousept - the point at which the selection is to be made
* BOOL fExtend - TRUE to extend current selection.
* WORD *lpERR - currently not used.
*
* This function can be used to select a single sentence, or to extedn
* the selection sentence by sentence.
*
*/
void STDCALL vSelectSentence(QDE qde, POINT mousept, BOOL fExtend, WORD *lpERR)
{
QFCM qfcm;
LONG lichMark, lichStartMark, lichEndMark;
PSTR qchText;
QB qbObj;
MOBJ mobj;
QFR qfr;
int ifr, tmpifr;
if (!fExtend) InvalidateSelection(qde);
AccessMRD((QMRD)&qde->mrdFCM);
qfcm = qfcmGetSelectionPosition (qde, mousept, &lichMark, &ifr);
if (qfcm==NULL)
{
DeAccessMRD((QMRD)&qde->mrdFCM);
//
// set error
return;
}
qbObj = (QB)PtrFromGh(qfcm->hfc) + sizeof(FCINFO);
#ifdef _X86_
qchText = qbObj + CbUnpackMOBJ((QMOBJ)&mobj, qbObj);
#else
qchText = qbObj + CbUnpackMOBJ((QMOBJ)&mobj, qbObj,QDE_ISDFFTOPIC(qde));
#endif
qchText += mobj.lcbSize;
// start with start and end points
lichStartMark = lichEndMark = lichMark;
//
// find sentence delimiter in front.
//
tmpifr = ifr;
qfr = (QFR)PtrFromGh(qfcm->hfr);
qfr += tmpifr;
while( (lichStartMark >= 0) && (tmpifr >= 0) &&
!IsSentenceDelim(qchText + lichStartMark, qfr->bType) )
{
lichStartMark--;
if( lichStartMark < qfr->u.frt.lichFirst )
{
qfr--;
tmpifr--;
}
}
while( !isalpha(*(qchText + lichStartMark)) &&
!isdigit((BYTE) *(qchText + lichStartMark)) )
lichStartMark++;
//
// find the end position
//
tmpifr = ifr;
qfr = (QFR)PtrFromGh(qfcm->hfr);
qfr += tmpifr;
while( !IsSentenceDelim(qchText + lichEndMark, qfr->bType) )
{
lichEndMark++;
if( lichEndMark > (qfr->u.frt.lichFirst + qfr->u.frt.cchSize) )
{
qfr++;
tmpifr++;
if( (qfcm->cfr == ifr) || (qfr->bType != bFrTypeText) )
{
lichEndMark--;
break;
}
lichEndMark = qfr->u.frt.lichFirst;
}
}
if (IsSentenceDelim(qchText + lichEndMark, bFrTypeText))
lichEndMark++;
//
// now set the selection
//
if (fExtend)
{
BOOL fSelectionChanged= qde-> vaEndMark.dword != qfcm->va.dword
|| qde-> lichEndMark != lichEndMark;
if ( fSelectionChanged
&& qde-> vaStartMark.dword == qde-> vaEndMark.dword
&& qde->lichStartMark == qde->lichEndMark
) InvertSelection(qde);
// if our end is less than our start, make our
// end point our start point.
if (qde->vaEndMark.dword < qde->vaStartMark.dword ||
(qde->vaEndMark.dword == qde->vaStartMark.dword &&
qde->lichEndMark < qde->lichStartMark))
{
lichEndMark = lichStartMark;
}
//
// invert if necessary
if(fSelectionChanged)
{
HELPHILITE hh;
hh.ichBase = qde->lichEndMark;
hh.vaBase = qde-> vaEndMark;
hh.vaLimit = qde-> vaEndMark = qfcm->va;
hh.ichLimit = qde->lichEndMark = lichEndMark;
HighlightFrames(qde, &hh, 1);
if ( qde-> vaStartMark.dword == qde-> vaEndMark.dword
&& qde->lichStartMark == qde->lichEndMark
) InvertSelection(qde);
}
}
else
{
HELPHILITE hh;
hh.ichBase = qde->lichStartMark = lichStartMark;
hh.vaBase = qde-> vaStartMark = qfcm->va;
hh.ichLimit = qde-> lichEndMark = lichEndMark;
hh.vaLimit = qde-> vaEndMark = qfcm->va;
HighlightFrames(qde, &hh, 1);
}
DeAccessMRD((QMRD)&qde->mrdFCM);
}
/******************************************************************
* vSelectParagraph
*
* QDE qde - the qde to change selection in.
* POINT mousept - the point at which the selection is to be made
* BOOL fExtend - TRUE to extend current selection.
* WORD *lpERR - currently not used.
*
* This function can be used to select a single paragraph, or to extedn
* the selection by paragraphs.
*
*/
void STDCALL vSelectParagraph(QDE qde, POINT mousept, BOOL fExtend, WORD *lpERR)
{
QFCM qfcm;
LONG lichMark, lichStartMark, lichEndMark;
PSTR qchText;
QB qbObj;
MOBJ mobj;
QFR qfr;
int ifr, tmpifr;
if (!fExtend) InvalidateSelection(qde);
AccessMRD((QMRD)&qde->mrdFCM);
qfcm = qfcmGetSelectionPosition (qde, mousept, &lichMark, &ifr);
if (qfcm==NULL)
{
DeAccessMRD((QMRD)&qde->mrdFCM);
//
// set error
return;
}
qbObj = (QB)PtrFromGh(qfcm->hfc) + sizeof(FCINFO);
#ifdef _X86_
qchText = qbObj + CbUnpackMOBJ((QMOBJ)&mobj, qbObj);
#else
qchText = qbObj + CbUnpackMOBJ((QMOBJ)&mobj, qbObj, QDE_ISDFFTOPIC(qde));
#endif
qchText += mobj.lcbSize;
// start with start and end points
lichStartMark = lichEndMark = lichMark;
//
// find sentence delimiter in front.
//
tmpifr = ifr;
qfr = (QFR)PtrFromGh(qfcm->hfr);
qfr += tmpifr;
while( (tmpifr > 0) &&
(qfr->bType != bFrTypeMarkNewPara) &&
(qfr->bType != bFrTypeExportNewPara) )
{
qfr--;
tmpifr--;
}
while ( qfr->bType != bFrTypeText )
qfr++;
// set lichStartMark to beginning of qfr
lichStartMark = qfr->u.frt.lichFirst;
tmpifr = ifr;
qfr = (QFR)PtrFromGh(qfcm->hfr);
qfr += tmpifr;
while((tmpifr <= qfcm->cfr) &&
(qfr->bType != bFrTypeMarkNewPara) &&
(qfr->bType != bFrTypeExportNewPara) )
{
qfr++;
tmpifr++;
}
while( qfr->bType != bFrTypeText )
qfr--;
// set lichEnd mark to end of last text frame
lichEndMark = qfr->u.frt.lichFirst + qfr->u.frt.cchSize;
//
// now set the selection
//
if (fExtend)
{
BOOL fSelectionChanged= qde-> vaEndMark.dword != qfcm->va.dword
|| qde-> lichEndMark != lichEndMark;
if ( fSelectionChanged
&& qde-> vaStartMark.dword == qde-> vaEndMark.dword
&& qde->lichStartMark == qde->lichEndMark
) InvertSelection(qde);
// if our end is less than our start, make our
// end point our start point.
if (qde->vaEndMark.dword < qde->vaStartMark.dword ||
(qde->vaEndMark.dword == qde->vaStartMark.dword &&
qde->lichEndMark < qde->lichStartMark))
{
lichEndMark = lichStartMark;
}
//
// invert if necessary
if(fSelectionChanged)
{
HELPHILITE hh;
hh.ichBase = qde->lichEndMark;
hh.vaBase = qde-> vaEndMark;
hh.vaLimit = qde-> vaEndMark = qfcm->va;
hh.ichLimit = qde->lichEndMark = lichEndMark;
HighlightFrames(qde, &hh, 1);
if ( qde-> vaStartMark.dword == qde-> vaEndMark.dword
&& qde->lichStartMark == qde->lichEndMark
) InvertSelection(qde);
}
}
else
{
HELPHILITE hh;
hh.ichBase = qde->lichStartMark = lichStartMark;
hh.vaBase = qde-> vaStartMark = qfcm->va;
hh.ichLimit = qde-> lichEndMark = lichEndMark;
hh.vaLimit = qde-> vaEndMark = qfcm->va;
HighlightFrames(qde, &hh, 1);
}
DeAccessMRD((QMRD)&qde->mrdFCM);
}
/********************************************************************
* Here are support routines that are called from within this file.
*********************************************************************/
// InvertSelection
void STDCALL InvertSelection(QDE qde)
{
HELPHILITE hh, *phh= NULL;
UINT cHilites;
if ( qde->vaStartMark.dword != qde->vaEndMark.dword
|| qde->lichStartMark != qde->lichEndMark
)
{
hh.vaBase = qde->vaStartMark;
hh.vaLimit = qde->vaEndMark;
hh.ichBase = qde->lichStartMark;
hh.ichLimit = qde->lichEndMark;
phh= &hh;
cHilites= 1;
}
#ifdef _HILIGHT
else
{
cHilites= GetHilites(qde, &phh);
if (!cHilites)
return;
}
#else
else
return;
#endif
AccessMRD((QMRD)&qde->mrdFCM);
HighlightFrames(qde, phh, cHilites);
DeAccessMRD((QMRD)&qde->mrdFCM);
}
static void STDCALL InvalidateSelection(QDE qde)
{
// This routine discards and unhighlights any selection
// which exists within *qde.
HELPHILITE hh;
if ( qde->vaStartMark.dword == qde->vaEndMark.dword
&& qde->lichStartMark == qde->lichEndMark
) return;
AccessMRD((QMRD)&qde->mrdFCM);
hh.vaBase = qde->vaStartMark;
hh.vaLimit = qde-> vaEndMark;
hh.ichBase = qde->lichStartMark;
hh.ichLimit = qde-> lichEndMark;
qde-> vaStartMark = qde-> vaEndMark;
qde->lichStartMark = qde->lichEndMark;
HighlightFrames(qde, &hh, 1);
InvertSelection(qde);
ASSERT(qde->hwnd);
UpdateWindow(qde->hwnd);
DeAccessMRD((QMRD)&qde->mrdFCM);
}
/*------------------------------------------------------
* static LONG lichFindMark(qde, qfcm, pt)
*
* This function takes a point and an FC and returns
* the offset into the FC's VA that the point cooresponds
* to. If there are no text frames in the FC, it returns
* -1.
*
*/
static LONG lichFindMark(QDE qde, QFCM qfcm, POINT pt, int *pIFR)
{
QB qbObj;
#ifdef DBCS
PSTR qchText, qchLast, qchLimit;
#else // DBCS
PSTR qchText;
#endif // DBCS
QFR qfr, qfrLastTypeText;
int ifr, ifrLastTypeText;
MOBJ mobj;
HFONT Font, oldFont;
int width1, width2;
int pos=0, top, bottom;
LONG lich;
qfr = (QFR)PtrFromGh(qfcm->hfr);
ifr = 0;
//
// if there are no text frames, use the first
// frame in this FC
//
ifrLastTypeText = ifr;
qfrLastTypeText = qfr;
//
// step through all frames in this FC
//
while(ifr < qfcm->cfr) {
if (qfr->bType == bFrTypeText) {
FindFrameBounds(qfr, (int) ifr, qfcm->cfr, &top, &bottom);
//
// return the beginning of the first text
// frame beyond the mouse point.
//
if (pt.y < top + qfcm->yPos)
{
lich = qfr->u.frt.lichFirst;
if (pIFR)
*pIFR = ifr;
return lich;
}
ifrLastTypeText = ifr;
qfrLastTypeText = qfr;
if ((pt.y >= top + qfcm->yPos) &&
(pt.y <= bottom + qfcm->yPos) &&
(pt.x < qfr->xPos + qfcm->xPos + qfr->dxSize)) {
// we are within this one vertically, but
// horizontally before it. return the beginning
if (pt.x < qfr->xPos + qfcm->xPos) {
lich = qfr->u.frt.lichFirst;
if (pIFR)
*pIFR = ifr;
return lich;
}
break;
}
}
ifr++;
qfr++;
}
//
// added - garrg 9/6/93
// check if mouse y pos is past frame. If so, return end point.
// The test is that we went through all frames without finding
// a matching Text frame.
if (ifr == qfcm->cfr || qfr == NULL) {
qfr = qfrLastTypeText;
ifr = ifrLastTypeText;
if (qfr == NULL || qfr->bType != bFrTypeText) {
// NO TEXT FRAMES. Return error indicator
lich = -1;
}
else {
// return end point of last text frame.
lich = qfr->u.frt.lichFirst + qfr->u.frt.cchSize;
}
if (pIFR)
*pIFR = ifr;
return lich;
}
qbObj = (QB)PtrFromGh(qfcm->hfc) + sizeof(FCINFO);
#ifdef _X86_
qchText = qbObj + CbUnpackMOBJ((QMOBJ)&mobj, qbObj);
#else
qchText = qbObj + CbUnpackMOBJ((QMOBJ)&mobj, qbObj,QDE_ISDFFTOPIC(qde));
#endif
qchText += mobj.lcbSize;
qchText += qfr->u.frt.lichFirst;
lich = qfr->u.frt.lichFirst;
Font = GetFontHandle(qde, qfr->u.frt.wStyle, 0);
oldFont = SelectObject(qde->hdc, Font);
#ifdef DBCS
for (qchLast= qchText , qchLimit= CharNext(qchLast); ;
qchLast= qchLimit, qchLimit= CharNext(qchLast)
)
{
pos= qchLimit - qchText;
if (pos > qfr->u.frt.cchSize) break;
width2 = (int)((GetTextSize(qde->hdc, qchText, pos)).x);
if (pt.x < (qfr->xPos + qfcm->xPos + (int) width2))
{
// back up one.
width1 = ((GetTextSize(qde->hdc, qchText, qchLast - qchText)).x);
// determine which side of the character to fall on
if (pt.x >= ((width1 + width2) /2 + qfr->xPos + qfcm->xPos))
qchLast= qchLimit;
break;
}
}
lich += qchLast - qchText;
#else // DBCS
while (pos < qfr->u.frt.cchSize) {
width2 = (int)((GetTextSize(qde->hdc, qchText, ++pos)).x);
if (pt.x < (qfr->xPos + qfcm->xPos + (int) width2)) {
// back up one.
width1 = ((GetTextSize(qde->hdc, qchText, (int)(pos - 1))).x);
// determine which side of the character to fall on
if (pt.x >= ((width1 + width2) /2 + qfr->xPos + qfcm->xPos))
lich++;
break;
}
lich++;
}
#endif // DBCS
SelectObject(qde->hdc, oldFont);
if (pIFR)
*pIFR = ifr;
return lich;
}
/*------------------------------------------------------
* HighlightFrames
*
* This function inverts all of the text on the currently
* displayed window, starting at VA=vaStartMark, offset
* lichStartMark, and stopping at VA=vaEndMark, offset lichEndMark.
* If end mark is before start mark, this function will
* work as expected (highlight between the two).
*/
static void HighlightFrames(QDE qde, PHELPHILITE phh, UINT cHilites)
{
QFCM qfcm;
IFCM ifcm, EndIfcm, StartIfcm, ifcmLast, ifcmFirst, ifcmNext;
QFR qfr;
int ifr, ifrStartMark, ifrEndMark;
LONG lichMark1, lichMark2;
RECT rect;
QB qbObj;
PSTR qchText;
MOBJ mobj;
HFONT Font, oldFont;
int top, bottom;
HRGN hrgnInvert, hrgnRect;
if (!cHilites) return;
// When we're handling a text selection highlight, the base and limit boundaries
// may be reversed. Here we check for that condition.
if ( cHilites == 1
&& phh->vaBase.dword == phh->vaLimit.dword
&& phh->ichLimit < phh->ichBase || phh->vaLimit.dword < phh->vaBase.dword
)
{
VA vaSwap;
LONG lichSwap;
lichSwap = phh->ichBase;
phh->ichBase = phh->ichLimit;
phh->ichLimit = lichSwap;
vaSwap = phh->vaBase;
phh->vaBase = phh->vaLimit;
phh->vaLimit = vaSwap;
}
hrgnInvert= CreateRectRgn(0, 0, 0, 0);
hrgnRect = CreateRectRgn(0, 0, 0, 0);
__try
{
for (ifcmFirst= ifcm = IFooFirstMRD((QMRD) &qde->mrdFCM);
cHilites && ifcm != FOO_NIL;
ifcmFirst= ifcm= ifcmNext
)
{
ASSERT (phh->ichLimit!=-1);
ASSERT (phh->ichBase!=-1);
// if phh->ichLimit is less that phh->ichBase, we need to swap
StartIfcm = FOO_NIL;
EndIfcm = FOO_NIL;
// find starting FC
for (;
ifcm != FOO_NIL;
ifcm = IFooNextMRD((QMRD) &qde->mrdFCM, sizeof(FCM), ifcm)
)
{
VA vaFCM;
ifcmLast = ifcm;
qfcm = (QFCM)QFooInMRD(((QMRD)&qde->mrdFCM), sizeof(FCM), ifcm);
vaFCM= qfcm->va;
while (vaFCM.dword > phh->vaLimit.dword)
{
++phh;
if (!--cHilites) __leave;
}
// Check for starting FC
if (StartIfcm == FOO_NIL && vaFCM.dword == phh->vaBase.dword)
{
qfr = (QFR)PtrFromGh(qfcm->hfr);
ifr = 0;
// find frame in start FC
while( ifr < qfcm->cfr )
{
if(qfr->bType == bFrTypeText)
{
while ( vaFCM.dword == phh->vaLimit.dword
&& qfr->u.frt.lichFirst >= phh->ichLimit
)
{
++phh;
if (!--cHilites) __leave;
if (vaFCM.dword < phh->vaBase.dword) break;
}
if (vaFCM.dword < phh->vaBase.dword) break;
if (qfr->u.frt.lichFirst + qfr->u.frt.cchSize >= phh->ichBase)
{
// we found it!
StartIfcm = ifcm;
ifrStartMark = ifr;
lichMark1 = phh->ichBase;
break;
}
}
qfr++;
ifr++;
}
}
if (EndIfcm==FOO_NIL && vaFCM.dword == phh->vaLimit.dword)
{
qfr = (QFR)PtrFromGh(qfcm->hfr);
ifr = 0;
// find frame in start FC
while( ifr < qfcm->cfr )
{
if( (qfr->bType == bFrTypeText)
&& ((qfr->u.frt.lichFirst + qfr->u.frt.cchSize) >= phh->ichLimit)
)
{
ifcmNext =
EndIfcm = ifcm;
ifrEndMark = ifr;
lichMark2 = phh->ichLimit;
++phh;
--cHilites;
break;
}
qfr++;
ifr++;
}
}
if (EndIfcm != FOO_NIL) break;
}
if (ifcmLast==FOO_NIL)
{
// there are no FC's so nothing to highlight
__leave;
}
//
// make sure we found the beginning. If not,
// start at the very first frame available
if( StartIfcm==FOO_NIL )
{
StartIfcm = ifcmFirst;
ifrStartMark = 0;
lichMark1 = 0;
}
//
// make sure we found the end. If not, stop at
// the very last realized frame.
if (EndIfcm == FOO_NIL)
{
ifcmNext = IFooNextMRD((QMRD) &qde->mrdFCM, sizeof(FCM), ifcmLast);
EndIfcm = ifcmLast;
qfcm = (QFCM)QFooInMRD(((QMRD)&qde->mrdFCM), sizeof(FCM), EndIfcm);
//
// if our real end is < this end point, or
// if our real start point is > this point, bail
if ( phh->vaLimit.dword < qfcm->va.dword
|| phh->vaBase.dword > qfcm->va.dword
) continue;
ifrEndMark = qfcm->cfr-1;
lichMark2 = LONG_MAX; // max long
}
qfcm = (QFCM)QFooInMRD(((QMRD)&qde->mrdFCM), sizeof(FCM), StartIfcm);
qfr = (QFR)PtrFromGh(qfcm->hfr);
ifr = ifrStartMark;
qfr += ifr;
ifcm = StartIfcm;
qbObj = (QB)PtrFromGh(qfcm->hfc) + sizeof(FCINFO);
#ifdef _X86_
qchText = qbObj + CbUnpackMOBJ((QMOBJ)&mobj, qbObj);
#else
qchText = qbObj + CbUnpackMOBJ((QMOBJ)&mobj, qbObj,QDE_ISDFFTOPIC(qde));
#endif
qchText += mobj.lcbSize;
while( ((ifcm != EndIfcm) || ((ifcm == EndIfcm) && (ifr <= ifrEndMark)))
&& (EndIfcm != IFooPrevMRD((QMRD)&qde->mrdFCM, sizeof(FCM), ifcm))
)
{
if( qfr->bType == bFrTypeText )
{
if( (ifcm == StartIfcm)
&& (qfr->u.frt.lichFirst <= lichMark1)
&& (qfr->u.frt.lichFirst + qfr->u.frt.cchSize >= lichMark1)
)
{
Font = GetFontHandle(qde, qfr->u.frt.wStyle, 0);
oldFont = SelectObject(qde->hdc, Font);
rect.left = qfr->xPos + qfcm->xPos
+ (GetTextSize(qde->hdc, qchText + (int)qfr->u.frt.lichFirst,
(int)(lichMark1 - qfr->u.frt.lichFirst)
)
).x;
SelectObject(qde->hdc, GetStockObject (SYSTEM_FONT));
}
else rect.left = qfr->xPos + qfcm->xPos;
if( (ifcm == EndIfcm)
&& (qfr->u.frt.lichFirst <= lichMark2)
&& (qfr->u.frt.lichFirst + qfr->u.frt.cchSize >= lichMark2)
)
{
Font = GetFontHandle(qde, qfr->u.frt.wStyle, 0);
oldFont = SelectObject(qde->hdc, Font);
rect.right = qfr->xPos + qfcm->xPos +
(GetTextSize(qde->hdc, qchText + (int)qfr->u.frt.lichFirst,
(int)(lichMark2 - qfr->u.frt.lichFirst) )).x;
SelectObject(qde->hdc, GetStockObject (SYSTEM_FONT));
}
else rect.right = qfr->dxSize + qfr->xPos + qfcm->xPos;
FindFrameBounds(qfr, ifr, qfcm->cfr, &top, &bottom);
rect.top = top + qfcm->yPos;//qfr->yPos + qfcm->yPos;
rect.bottom = bottom + qfcm->yPos;//rect.top + qfr->dySize;
//
// adjust rectangle by amount scroll
rect.left -= qde->xScrolled;
rect.right -= qde->xScrolled;
SetRectRgn(hrgnRect, rect.left, rect.top, rect.right, rect.bottom);
CombineRgn(hrgnInvert, hrgnInvert, hrgnRect, RGN_OR);
}
qfr++;
ifr++;
if( (ifr == qfcm->cfr) && (ifcm != EndIfcm) )
{
ifr = 0;
ifcm = IFooNextMRD((QMRD)&qde->mrdFCM, sizeof(FCM), ifcm);
// not on screen!
if (ifcm == ifcmNil)
break;
qfcm = (QFCM)QFooInMRD(((QMRD)&qde->mrdFCM), sizeof(FCM), ifcm);
qbObj = (QB)PtrFromGh(qfcm->hfc) + sizeof(FCINFO);
#ifdef _X86_
qchText = qbObj + CbUnpackMOBJ((QMOBJ)&mobj, qbObj);
#else
qchText = qbObj + CbUnpackMOBJ((QMOBJ)&mobj, qbObj,QDE_ISDFFTOPIC(qde));
#endif
qchText += mobj.lcbSize;
qfr = (QFR)PtrFromGh(qfcm->hfr);
}
}
}
}
__finally
{
if (Repainting(qde))
InvertRgn(qde->hdc, hrgnInvert);
else
InvalidateRgn(qde->hwnd, hrgnInvert, TRUE);
DeleteObject(hrgnInvert);
DeleteObject(hrgnRect );
}
}
static BOOL STDCALL IsSentenceDelim(LPCSTR psz, int bFrType)
{
if( (bFrType == bFrTypeMarkNil)
|| (bFrType == bFrTypeMarkNewPara)
|| (bFrType == bFrTypeMarkTab)
|| (bFrType == bFrTypeMarkNewLine)
|| (bFrType == bFrTypeMarkBlankLine)
|| (bFrType == bFrTypeMarkEnd)
|| (bFrType == bFrTypeExportTab)
|| (bFrType == bFrTypeExportNewPara)
|| (bFrType == bFrTypeExportEndOfText)
|| (bFrType == bFrTypeExportEndOfCell)
|| (bFrType == bFrTypeExportEndOfTable)
// || (bFrType == bFrTypeExportSoftPara) // In Media View, Not in WinHelp
)
return TRUE;
return( ((*psz == '.') ||
(*psz == '?') ||
(*psz == '!') ||
(*psz == ':')) &&
(*(psz + 1) == ' ') &&
(!islower(*(psz + 2))) &&
(!isdigit((BYTE) *(psz + 2))) );
}
static BOOL STDCALL IsWordDelim(LPCSTR psz)
{
return((StrChrDBCS (" `?!:();[]\"&\x93\x94{}",*psz) != NULL) ||
((*psz == '.') && !isalpha(*(psz+1)) && !isdigit((BYTE) *(psz+1))) ||
((*psz == ',') && !isalpha(*(psz+1)) && !isdigit((BYTE) *(psz+1))) ||
((*psz == '\'') && !isalpha(*(psz+1)) && !isdigit((BYTE) *(psz+1))));
}
////////////////////////////////////////////////////////////////
//
// HANDLE STDCALL hCopySelection(qde, vaStartSel, vaEndSel, lichStartSel, lichEndSel, lpERR)
//
//--------------------------------------------------------------
// This function copies the text starting at the character
// defined as vaStartSel+lichStartSel and ending at
// vaEndSel+lichEndSel. If the end character is before the
// start character, the points will be reversed (selection will
// be copied normally).
//
HANDLE STDCALL hCopySelection(QDE qde, VA vaStartSel, VA vaEndSel, LONG lichStartSel, LONG lichEndSel, int* lpERR)
{
HFC hfc;
HANDLE gh, ghTmp;
LONG lcb;
DWORD lcbTotal = 0;
DWORD lcbAlloc = CLIPALLOCSIZE;
PSTR pszOut, qchStart, qchText;
PBYTE qbObj;
MOBJ mobj;
int ifcm;
QFCM qfcm;
QFR qfr, qfrMax;
BOOL fTableOutput;
BOOL fDone=FALSE;
BOOL fStart=FALSE;
*lpERR = wERRS_NONE;
//
// reverse start and end if end < start
//
if ((vaEndSel.dword < vaStartSel.dword) ||
(vaEndSel.dword == vaStartSel.dword && lichEndSel < lichStartSel))
{
VA vaSwap;
LONG lSwap;
vaSwap = vaStartSel;
vaStartSel = vaEndSel;
vaEndSel = vaSwap;
lSwap = lichStartSel;
lichStartSel = lichEndSel;
lichEndSel = lSwap;
}
//
// Create an HFC for laying out the topic for export.
//
ASSERT(qde->wLayoutMagic == wLayMagicValue);
if (qde->rct.top >= qde->rct.bottom) {
qde->rct.top = 0;
qde->rct.left = 0;
qde->rct.right = cxScreen;
qde->rct.bottom = cyScreen;
}
hfc = HfcNear(qde, vaStartSel, (QTOP)&qde->top, lpERR);
if (*lpERR != wERRS_NONE)
return 0;
// Warning: Must be the REAL GlobalAlloc. And will GMEM_SHARE work?
if (!(gh = GlobalAlloc(GMEM_MOVEABLE | GMEM_ZEROINIT, lcbAlloc))) {
*lpERR = wERRS_OOM;
return 0;
}
pszOut = (PSTR) GlobalLock(gh);
while (hfc && !fDone) {
// calculate number of bytes to copy
lcb = 2 * CbTextHfc(hfc) + 6;
//
// do we need to reallocate?
//
if (lcbTotal + lcb > lcbAlloc) {
// allocate at least CLIPALLOCSIZE
GlobalUnlock(gh);
lcbAlloc = lcbTotal + ((lcb < CLIPALLOCSIZE) ? CLIPALLOCSIZE : lcb);
if (ghTmp = (HANDLE) GlobalReAlloc(gh, (DWORD) lcbAlloc,
GMEM_MOVEABLE | GMEM_ZEROINIT))
gh = ghTmp;
else {
#ifdef _DEBUG
GetLastError();
#endif
GlobalFree(gh);
*lpERR = wERRS_OOM;
return 0;
}
pszOut = (LPSTR) GlobalLock(gh);
pszOut += lcbTotal;
}
AccessMRD(((QMRD)&qde->mrdFCM));
// layout the HFC so that the frames are labeled correctly.
if ((ifcm = IfcmLayout(qde, hfc, 0, TRUE, TRUE)) == ifcmNil) {
// Upon failure, IfcmLayout() frees hfc.
hfc = 0;
DeAccessMRD(((QMRD)&qde->mrdFCM));
*lpERR = wERRS_OOM;
return(0);
}
qfcm = (QFCM)QFooInMRD(((QMRD)&qde->mrdFCM), sizeof(FCM), ifcm);
qbObj = (QB)PtrFromGh(qfcm->hfc) + sizeof(FCINFO);
#ifdef _X86_
qchText = qbObj + CbUnpackMOBJ((QMOBJ)&mobj, qbObj);
#else
qchText = qbObj + CbUnpackMOBJ((QMOBJ)&mobj, qbObj,QDE_ISDFFTOPIC(qde));
#endif
qchText += mobj.lcbSize;
// determine if this is a table
fTableOutput = mobj.bType == bTypeSbys || mobj.bType == bTypeSbysCounted;
qfr = PtrFromGh(qfcm->hfr);
qchStart = pszOut;
//
// copy all frames in this FC.
fStart = (lichStartSel==0);
qfrMax = qfr + qfcm->cfr;
for (; qfr < qfrMax && !fDone; qfr++) {
PSTR qchTemp;
qchTemp = pszOut;
switch (qfr->bType) {
case bFrTypeText:
{
LONG lFirst = qfr->u.frt.lichFirst;
LONG lCount = (LONG)qfr->u.frt.cchSize;
// we will need to special case when
// qfcm->va.dword == vaStartSel.dword or qfcm->va.dword == vaEndSel.dword
if (qfcm->va.dword == vaStartSel.dword && lFirst < lichStartSel)
{
// don't start until lichStartSel
lCount -= lichStartSel - lFirst;
lFirst = lichStartSel;
}
if (qfcm->va.dword == vaEndSel.dword && lFirst + lCount >= lichEndSel)
{
fDone = TRUE;
lCount = lichEndSel - lFirst;
}
// don't copy if there is nothing to copy
if (lCount <= 0)
break;
fStart = TRUE;
MoveMemory(pszOut,qchText + lFirst, lCount);
pszOut += lCount;
}
break;
case bFrTypeExportEndOfCell:
ASSERT(fTableOutput);
*(pszOut++) = chTab;
break;
case bFrTypeExportEndOfTable:
ASSERT(fTableOutput);
*(pszOut++) = chNewPara;
*(pszOut++) = chNewLine;
break;
case bFrTypeExportTab:
*(pszOut++) = chTab;
break;
// case bFrTypeExportSoftPara: // Defined in Media View; Not in WinHelp
// break;
case bFrTypeExportNewPara:
if (!fTableOutput) {
*(pszOut++) = chNewPara;
*(pszOut++) = chNewLine;
}
break;
case bFrTypeExportEndOfText:
if (!fTableOutput) {
*(pszOut++) = chNewPara;
*(pszOut++) = chNewLine;
}
break;
case bFrTypeWindow:
// do not copy embedded windows using arbitrary selection.
break;
case bFrTypeMarkNewLine:
*(pszOut++) = chNewPara;
break;
}
if (!fStart)
pszOut = qchTemp;
}
// add the number of bytes copied to lcbTotal
lcbTotal += (pszOut - qchStart);
// Go to the next FC
hfc = HfcNextHfc(qfcm->hfc, lpERR, qde,
VaMarkTopQde(qde), VaMarkBottomQde(qde));
/*
* DANGER: for space reasons, we don't check the error condition
* for a few lines
*/
DiscardIfcm(qde, ifcm);
DeAccessMRD(((QMRD)&qde->mrdFCM));
// DANGER: We now check the error condition from the HfcNextHfc call
if ((*lpERR != wERRS_NONE) && (*lpERR != wERRS_FCEndOfTopic)) {
if (hfc)
FreeGh(hfc);
hfc = 0;
}
}
// well, we better NULL terminate
*pszOut = '\0';
// free the HFC
if (hfc != 0)
FreeGh(hfc);
if (QDE_HCITATION(qde)) {
PSTR pszData;
PSTR pszCitation = (PSTR) QDE_HCITATION(qde);
int cbCitation = lstrlen(pszCitation) + 4;
if (lcbTotal + cbCitation > lcbAlloc) {
HANDLE hglbNew;
lcbAlloc = lcbTotal + cbCitation;
hglbNew = GlobalReAlloc(gh, (DWORD) lcbAlloc, GPTR);
if (!hglbNew) {
*lpERR = wERRS_OOM;
GlobalFree(gh);
return NULL;
}
else
gh = hglbNew;
}
pszData = (PSTR) GlobalLock(gh);
// The NULL char is added at the end of the buffer
MoveMemory(&pszData[lcbTotal], "\r\n\r\n", 4);
MoveMemory(&pszData[lcbTotal] + 4, pszCitation, cbCitation);
lcbTotal += cbCitation;
}
GlobalUnlock(gh);
if ((ghTmp = (HANDLE) GlobalReAlloc(gh, lcbTotal + 1, GPTR)))
gh = ghTmp;
return gh;
}
////////////////////////////////////////////////////////////////
//
// static void FindFrameBounds(qfr, ifr, ifrMax, top, bottom)
//
//--------------------------------------------------------------
// Find the maximum top and bottom for frames on this line.
// This keeps the selection highlight from looking "ragged" due to
// varying heights of the frames on the same line.
//
static void STDCALL FindFrameBounds(QFR qfr, int ifr, int ifrMax,
int *ptop, int *pbottom)
{
int top, bottom, baseline, ytopPhrase;
top = qfr->yPos;
bottom = top + qfr->dySize;
baseline = top + qfr->yAscent;
// First we back up looking for a text fragment with
// a baseline above our starting *qfr's baseline.
for (; ifr; qfr--, ifr--)
if ( qfr->bType == bFrTypeText
&& qfr->yPos + qfr->yAscent != baseline
) break;
// Then we scan forward until we find a text fragment
// whose baselilne is below our starting baseline.
for (qfr++, ifr++; ifr < ifrMax; qfr++, ifr++)
if ( qfr->bType == bFrTypeText )
{
ytopPhrase= qfr->yPos;
if (ytopPhrase + qfr->yAscent != baseline) break;
// We believe this fragment is on the same line
// as our starting *qfr. Expand the vertical
// boundaries as necessary.
if (top > ytopPhrase)
top = ytopPhrase;
if (bottom < ytopPhrase + qfr->dySize)
bottom = ytopPhrase + qfr->dySize;
}
*ptop= top;
*pbottom= bottom;
}
/*********************************************************************
* BOOL fPointInSelection (QDE qde, PT pt)
*
* Determines whether the point pt is on the current selection.
* If the point is on white space or on an unselected text/picture
* it returns FALSE, otherwise TRUE.
*/
BOOL STDCALL fPointInSelection (QDE qde, POINT pt)
{
int ifcm;
QFCM qfcm;
QFR qfr;
int ifr;
LONG lichMark;
VA vaStart,vaEnd;
LONG lichStart,lichEnd;
AccessMRD((QMRD)&qde->mrdFCM);
if (qde->vaStartMark.dword < qde->vaEndMark.dword
|| (qde->vaStartMark.dword==qde->vaEndMark.dword &&
qde->lichStartMark < qde->lichEndMark))
{
vaStart = qde->vaStartMark;
vaEnd = qde->vaEndMark;
lichStart = qde->lichStartMark;
lichEnd = qde->lichEndMark;
}
else
{
vaStart = qde->vaEndMark;
vaEnd = qde->vaStartMark;
lichStart = qde->lichEndMark;
lichEnd = qde->lichStartMark;
}
// adjust based on scroll position
pt.x += qde->xScrolled;
//
// Find the FM the point is in.
//
for (ifcm = IFooFirstMRD((QMRD)&qde->mrdFCM),qfcm=NULL;
ifcm != FOO_NIL;
ifcm = IFooNextMRD((QMRD)&qde->mrdFCM, sizeof(FCM),ifcm))
{
qfcm = (QFCM)QFooInMRD(((QMRD)&qde->mrdFCM), sizeof(FCM),
ifcm);
if ((pt.y >= qfcm->yPos) &&
(pt.y <= qfcm->yPos + qfcm->dySize))
break;
}
if (ifcm==FOO_NIL || qfcm->va.dword < vaStart.dword || qfcm->va.dword > vaEnd.dword)
{
DeAccessMRD(((QMRD)&qde->mrdFCM));
return FALSE;
}
qfr = (QFR)PtrFromGh(qfcm->hfr);
ifr = 0;
//
// find the FRAME the point falls in.
//
while (ifr < qfcm->cfr)
{
int top, bottom;
if( qfr->bType == bFrTypeText )
{
FindFrameBounds(qfr, ifr, qfcm->cfr, &top, &bottom);
if (pt.y >= top+qfcm->yPos && pt.y <= bottom+qfcm->yPos &&
pt.x >= qfr->xPos + qfcm->xPos
&& pt.x <= qfr->xPos + qfcm->xPos + qfr->dxSize)
{
// we are within the frame!
break;
}
}
ifr++;
qfr++;
}
//
// See if this frame is at all selected.
//
if (ifr==qfcm->cfr || qfr==NULL ||
(qfcm->va.dword == vaStart.dword && lichStart > qfr->u.frt.lichFirst + qfr->u.frt.cchSize) ||
(qfcm->va.dword == vaEnd.dword && lichEnd < qfr->u.frt.lichFirst))
{
DeAccessMRD(((QMRD)&qde->mrdFCM));
return FALSE;
}
//
// At this point we know we are close, but... Let's give
// lichFindMark a chance. We do not call this earlier, because
// it returns valid points when the point is on white space.
//
if (qfcm->va.dword != vaStart.dword && qfcm->va.dword != vaEnd.dword)
{
DeAccessMRD(((QMRD)&qde->mrdFCM));
return TRUE;
}
lichMark = lichFindMark (qde, qfcm, pt, &ifr);
DeAccessMRD(((QMRD)&qde->mrdFCM));
if (qfcm->va.dword==vaStart.dword && lichMark < lichStart)
return FALSE;
if (qfcm->va.dword==vaEnd.dword && lichMark > lichEnd)
return FALSE;
return TRUE;
}
////////////////////////////////////////////////////////////////
//
// PT ptSelectionPoint (QDE qde, VA va, long lich)
//
// BOOL fTop - if TRUE returns top of text, otherwise bottom.
//--------------------------------------------------------------
// This function finds the point on the window (relative to
// upper left hand corner) given the selection position (va and
// lich).
//
PT STDCALL ptSelectionPoint (QDE qde, VA va, LONG lich, BOOL fTop, int *pIFCM, int *pIFR)
{
IFCM ifcm;
QFCM qfcm;
PT pt;
AccessMRD((QMRD)&qde->mrdFCM);
pt.x = pt.y = -1;
//
// run through all FC's
//
for( ifcm = IFooFirstMRD((QMRD)&qde->mrdFCM);
ifcm != FOO_NIL && pt.x==-1;
ifcm = IFooNextMRD((QMRD)&qde->mrdFCM, sizeof(FCM), ifcm) )
{
qfcm = (QFCM)QFooInMRD(((QMRD)&qde->mrdFCM),sizeof(FCM), ifcm);
//
// Check for starting FC
if (qfcm->va.dword == va.dword)
{
QFR qfr;
int ifr;
qfr = (QFR)PtrFromGh(qfcm->hfr);
ifr = 0;
//
// find frame in this FC that our text is in.
//
while( ifr < qfcm->cfr )
{
if(qfr->bType == bFrTypeText &&
(qfr->u.frt.lichFirst + qfr->u.frt.cchSize) >= lich)
{
QB qbObj;
MOBJ mobj;
PSTR qchText;
HFONT hFont,holdFont;
// This is it!
// find offset of lich - qfr->u.frt.lichFirst.
qbObj = (QB)PtrFromGh(qfcm->hfc) + sizeof(FCINFO);
#ifdef _X86_
qchText = qbObj + CbUnpackMOBJ((QMOBJ)&mobj, qbObj);
#else
qchText = qbObj + CbUnpackMOBJ((QMOBJ)&mobj, qbObj, QDE_ISDFFTOPIC(qde));
#endif
qchText += mobj.lcbSize;
qchText += qfr->u.frt.lichFirst;
hFont = GetFontHandle(qde, qfr->u.frt.wStyle, 0);
holdFont = SelectObject(qde->hdc, hFont);
pt.x = qfr->xPos + qfcm->xPos - qde->xScrolled;
pt.y = qfr->yPos + qfcm->yPos;
pt.x += (GetTextSize(qde->hdc, qchText,
(int)(lich-qfr->u.frt.lichFirst) )).x;
if (!fTop)
pt.y += qfr->dySize;
if (pIFCM)
*pIFCM = (int)ifcm;
if (pIFR)
*pIFR = ifr;
SelectObject (qde->hdc, holdFont);
break;
}
qfr++;
ifr++;
}
}
}
DeAccessMRD(((QMRD)&qde->mrdFCM));
return pt;
}
#if 0
////////////////////////////////////////////////////////////////
// void STDCALL vSelectKey (QDE qde, short nKey, BOOL fExtend, WORD *lpERR)
//
//--------------------------------------------------------------
// This function extends or initiates the selection based on the
// key identifier passed in. The valid keys are UP, DOWN, LEFT,
// RIGHT, START and END.
// UP moves up 1 line
// DOWN down one line.
// LEFT->left 1 character.
// RIGHT->right one character.
// START->beginning of line.
// END->end of line.
//
void STDCALL vSelectKey (QDE qde, short nKey, BOOL fExtend, DWORD *lpERR)
{
IFCM ifcm=FOO_NIL;
int ifr=FOO_NIL;
QFR qfr;
QFCM qfcm;
LONG lich=-1;
VA va;
PT pt;
VA vaStart;
LONG lichStart;
switch (nKey)
{
case UP:
//
// find the point of the current end selection.
pt = ptSelectionPoint (qde, qde->vaEndMark, qde->lichEndMark, TRUE, (int *)&ifcm, &ifr);
//
// run through frames and find the first frame above pt.x, and use that
// as our y position.
if (ifr!=FOO_NIL)
{
AccessMRD((QMRD)&qde->mrdFCM);
qfcm = (QFCM)QFooInMRD(((QMRD)&qde->mrdFCM),sizeof(FCM), ifcm);
qfr = (QFR)PtrFromGh(qfcm->hfr);
qfr += ifr;
while (ifr != FOO_NIL)
{
while (ifr==0)
{
ifcm = IFooPrevMRD((QMRD)&qde->mrdFCM, sizeof(FCM), ifcm);
if (ifcm==FOO_NIL)
{
ifr = FOO_NIL;
break;
}
qfcm = (QFCM)QFooInMRD(((QMRD)&qde->mrdFCM),sizeof(FCM), ifcm);
ifr = qfcm->cfr;
qfr = (QFR)PtrFromGh(qfcm->hfr);
qfr += ifr;
}
if (ifr != FOO_NIL)
{
ifr--;
qfr--;
if (qfr->bType == bFrTypeText
&& qfcm->yPos + qfr->yPos + qfr->dySize <= pt.y)
{
pt.y = qfcm->yPos + qfr->yPos + 1;
break;
}
}
}
DeAccessMRD(((QMRD)&qde->mrdFCM));
vSelectPoint (qde, pt, fExtend, lpERR);
}
return;
case DOWN:
// find the point of the current end selection.
pt = ptSelectionPoint (qde, qde->vaEndMark, qde->lichEndMark, FALSE, (int *)&ifcm, &ifr);
if (ifr != FOO_NIL)
{
AccessMRD((QMRD)&qde->mrdFCM);
qfcm = (QFCM)QFooInMRD(((QMRD)&qde->mrdFCM),sizeof(FCM), ifcm);
qfr = (QFR)PtrFromGh(qfcm->hfr);
qfr += ifr;
while (qfr != NULL)
{
ifr++;
qfr++;
while (ifr==qfcm->cfr)
{
ifcm = IFooNextMRD((QMRD)&qde->mrdFCM, sizeof(FCM), ifcm);
if (ifcm==FOO_NIL)
{
qfr = NULL;
break;
}
qfcm = (QFCM)QFooInMRD(((QMRD)&qde->mrdFCM),sizeof(FCM), ifcm);
ifr = 0;
qfr = (QFR)PtrFromGh(qfcm->hfr);
}
if (qfr != NULL)
{
if (qfr->bType == bFrTypeText
&& qfcm->yPos + qfr->yPos >= pt.y)
{
// set new position
pt.y = qfcm->yPos + qfr->yPos + 1;
qfr = NULL; // break
}
}
}
DeAccessMRD(((QMRD)&qde->mrdFCM));
vSelectPoint (qde, pt, fExtend, lpERR);
}
return;
case LEFT:
//
// back up one.
pt = ptSelectionPoint (qde, qde->vaEndMark, qde->lichEndMark, FALSE, (int *)&ifcm, &ifr);
if (ifr != FOO_NIL)
{
AccessMRD((QMRD)&qde->mrdFCM);
qfcm = (QFCM)QFooInMRD(((QMRD)&qde->mrdFCM),sizeof(FCM), ifcm);
qfr = (QFR)PtrFromGh(qfcm->hfr);
qfr += ifr;
if (qde->lichEndMark > qfr->u.frt.lichFirst)
{
lich = qde->lichEndMark - 1;
va = qfcm->va;
ifr = FOO_NIL; // don't look for more
}
while (ifr != FOO_NIL)
{
while (ifr==0)
{
ifcm = IFooPrevMRD((QMRD)&qde->mrdFCM, sizeof(FCM), ifcm);
if (ifcm==FOO_NIL)
{
ifr = FOO_NIL;
break;
}
qfcm = (QFCM)QFooInMRD(((QMRD)&qde->mrdFCM),sizeof(FCM), ifcm);
ifr = qfcm->cfr;
qfr = (QFR)PtrFromGh(qfcm->hfr);
qfr += ifr;
}
if (ifr != FOO_NIL)
{
ifr--;
qfr--;
if (qfr->bType == bFrTypeText)
{
// set new position
va = qfcm->va;
lich = qfr->u.frt.lichFirst + qfr->u.frt.cchSize - 1;
break;
}
}
}
DeAccessMRD(((QMRD)&qde->mrdFCM));
}
break;
case RIGHT:
// increase lichEndMark by 1. If it is at end, we
// need to go to next qfcm.
pt = ptSelectionPoint (qde, qde->vaEndMark, qde->lichEndMark, FALSE, (int *)&ifcm, &ifr);
AccessMRD((QMRD)&qde->mrdFCM);
if (ifr != FOO_NIL)
{
qfcm = (QFCM)QFooInMRD(((QMRD)&qde->mrdFCM),sizeof(FCM), ifcm);
qfr = (QFR)PtrFromGh(qfcm->hfr);
qfr += ifr;
if (qde->lichEndMark < qfr->u.frt.lichFirst + qfr->u.frt.cchSize)
{
va = qfcm->va;
lich = qde->lichEndMark+1;
qfr = NULL;
}
while (qfr != NULL)
{
ifr++;
qfr++;
while (ifr==qfcm->cfr)
{
ifcm = IFooNextMRD((QMRD)&qde->mrdFCM, sizeof(FCM), ifcm);
if (ifcm==FOO_NIL)
{
qfr = NULL;
break;
}
qfcm = (QFCM)QFooInMRD(((QMRD)&qde->mrdFCM),sizeof(FCM), ifcm);
ifr = 0;
qfr = (QFR)PtrFromGh(qfcm->hfr);
}
if (qfr != NULL)
{
if (qfr->bType == bFrTypeText && qfr->u.frt.cchSize>0)
{
// set new position
va = qfcm->va;
lich = qfr->u.frt.lichFirst+1;
qfr = NULL;
}
}
}
}
DeAccessMRD(((QMRD)&qde->mrdFCM));
break;
case START:
pt = ptSelectionPoint (qde, qde->vaEndMark, qde->lichEndMark, FALSE, NULL, NULL);
if (pt.x!=-1)
{
pt.x = -1*qde->xScrolled;
vSelectPoint (qde, pt, fExtend, lpERR);
}
return;
case END:
pt = ptSelectionPoint (qde, qde->vaEndMark, qde->lichEndMark, FALSE, NULL, NULL);
if (pt.x!=-1)
{
// set pt.x to a maximum value
pt.x = 32000; // okay, not quite maximum.
vSelectPoint (qde, pt, fExtend, lpERR);
}
return;
default:
return;
}
//
// we should only get here in the LEFT and RIGHT cases.
// Take our new point, and use it!
//
if (!fExtend) InvalidateSelection(qde);
AccessMRD((QMRD)&qde->mrdFCM);
if (lich==-1)
{
if (!fExtend)
{
// just clear the selection
qde->vaStartMark = qde->vaEndMark;
qde->lichStartMark = qde->lichEndMark;
}
}
else
{
if (fExtend)
{
BOOL fSelectionChanged= qde-> vaEndMark.dword != va.dword
|| qde-> lichEndMark != lich;
if ( fSelectionChanged
&& qde-> vaStartMark == qde-> vaEndMark
&& qde->lichStartMark == qde->lichEndMark
) InvalidateSelection();
//
// highlight the frames between the previous end
// point and the new one.
//
if(fSelectionChanged)
{
HELPHILITE hh;
hh.ichBase = qde->lichEndMark;
hh.vaBase = qde-> vaEndMark;
hh.vaLimit = qde-> vaEndMark = va;
hh.ichLimit = qde->lichEndMark = lich;
HighlightFrames(qde, &hh, 1);
if ( qde-> vaStartMark == qde-> vaEndMark
&& qde->lichStartMark == qde->lichEndMark
) InvalidateSelection();
}
}
else
{
//
// set beginning selection and end to the
// new point.
qde->vaStartMark = va;
qde->vaEndMark = va;
qde->lichStartMark = lich;
qde->lichEndMark = lich;
}
}
DeAccessMRD((QMRD)&qde->mrdFCM);
}
#endif
/**************************************************************************
* POINTS GetTextSize(hdc, qchBuf, iCount)
*
* Wraps GetTextExtent & GetTextExtentPoint to return the size of text.
*
* Parameters:
* hdc - Handle to a display context.
* qchBuf - Pointer to text for which to get the extent.
* iCount - Count of characters to include in calculation.
*
* Returns:
* POINT containing width and height of the given text.
***************************************************************************/
POINT STDCALL GetTextSize(HDC hdc, PCSTR qchBuf, int iCount)
{
POINT ptRet;
SIZE size;
GetTextExtentPoint(hdc, qchBuf, iCount, &size);
ptRet.x = size.cx;
ptRet.y = size.cy;
return ptRet;
}
#if 0 // ifdef _HILIGHT
// Variables to support hilites from the Find tab:
static CHAR achMemberHilite[cchWindowMemberMax];
static char szFNameHilite[MAX_PATH];
static VA vaHilite= { vaNil }; // vaNil for no hilites;
// == vaNSR or vaSR when hilites exist
static HANDLE haHilites; // handle for results from HILITER
static HANDLE haHelpHilites; // handle for results mapped into HELPHILITE form
static HILITE *paHilites; // address of results from HILITER
static HELPHILITE *paHelpHilites; // address of results mapped into HELPHILITE form
static UINT cHilites; // number of hilites
// Variables used to map the HILITE array into the HELPHILITE array:
static HILITE *pHilite; // Points to the current HILITE item
static HELPHILITE *pHelpHilite; // Points to the current HELPHILITE item
static UINT cHilitesLeft; // Number of HILITE items left to map
static BOOL fScanningForStart; // True when we're looking for a text
// segment containing the base offset
// of a HILITE. False when we're looking
// for the limit offset.
#ifdef _DEBUG
#define HeapChecker() lcHeapCheck()
#else // _DEBUG
#define HeapChecker()
#endif // _DEBUG
BOOL STDCALL HilitesDefined()
{
return vaHilite.dword != vaNil;
}
BOOL IsHiliteWindow(QDE qde)
{
PSTR pszMemberName;
int iWnd;
if (!HilitesDefined()) return FALSE;
if (hwndNote) return FALSE; // If hwndNote is non-null, we're in a popup window
for (iWnd= 0; iWnd < MAX_WINDOWS; ++iWnd)
if ( ahwnd[iWnd].hwndTopic == qde->hwnd
|| ahwnd[iWnd].hwndTitle == qde->hwnd
)
{
pszMemberName= ahwnd[iWnd].pszMemberName;
if (!pszMemberName) return FALSE;
return !WCmpiSz(achMemberHilite, pszMemberName);
}
return FALSE;
}
BOOL STDCALL HasTopicChanged(QDE qde)
{
VA vaDE;
if (!IsHiliteWindow(qde)) return FALSE;
if (WCmpiSz(szFNameHilite, PszFromGh(QDE_FM(qde)))) return TRUE; // Same HLP file?
ASSERT(qde->top.mtop.vaNSR.dword != vaNil || qde->top.mtop.vaSR.dword != vaNil);
vaDE= (qde->top.mtop.vaNSR.dword != vaNil)? qde->top.mtop.vaNSR
: qde->top.mtop.vaSR;
return vaDE.dword != vaHilite.dword; // Same address within the HLP file?
}
void STDCALL CheckForTopicChanges(QDE qde)
{
if (vaHilite.dword == vaNil) return;
if (HasTopicChanged(qde))
DiscardHiliteInformation();
}
static BOOL STDCALL ScanThisTopic(QDE qde);
static void STDCALL InitScanBuffer(BOOL fSendToScanner);
static void STDCALL DisconnectScanBuffer();
void STDCALL CreateHiliteInformation(QDE qde)
{
int c;
PHILITE phlSrc, phlDest;
BOOL fScanned;
HeapChecker();
if (vaHilite.dword != vaNil) DiscardHiliteInformation();
HeapChecker();
InitScanBuffer(TRUE);
HeapChecker();
fScanned= ScanThisTopic(qde);
HeapChecker();
DisconnectScanBuffer();
HeapChecker();
if (!fScanned)
return;
ASSERT(!cHilites);
ASSERT(!haHilites);
ASSERT(!haHelpHilites);
cHilites= pCountHilites(GetHiliter(), 0, -1);
if (!cHilites)
return;
haHilites= lcMalloc(cHilites * sizeof(HILITE));
HeapChecker();
if (!haHilites) goto resource_limited;
paHilites= (PHILITE) PtrFromGh(haHilites);
if (0 > pQueryHilites(GetHiliter(), 0, -1, cHilites, paHilites))
goto resource_limited;
HeapChecker();
if (cHilites > 1)
{
// The hilite array may contain overlapping hilites.
// The loop below looks for overlaps and consolidates
// them.
for (c= cHilites, phlDest= paHilites, phlSrc= paHilites + 1;
--c;
)
{
ASSERT(phlSrc->base >= phlDest->base);
if (phlDest->limit > phlSrc->base)
{
ASSERT(phlSrc->limit >= phlDest->limit);
phlDest->limit = (phlSrc++)->limit;
}
else *(++phlDest)= *phlSrc++;
}
cHilites= 1 + (phlDest - paHilites);
HeapChecker();
}
cHilitesLeft= cHilites;
haHelpHilites= GhAlloc(GMEM_FIXED, cHilites * sizeof(HELPHILITE));
HeapChecker();
if (!haHelpHilites) goto resource_limited;
paHelpHilites= (PHELPHILITE) PtrFromGh(haHelpHilites);
HeapChecker();
InitScanBuffer(FALSE);
HeapChecker();
fScanned= ScanThisTopic(qde);
HeapChecker();
FreeGh(haHilites); haHilites= NULL; pHelpHilite= NULL; pHilite= paHilites= NULL;
HeapChecker();
if (!fScanned) goto resource_limited;
lstrcpy(achMemberHilite, ahwnd[iCurWindow].pszMemberName);
lstrcpy(szFNameHilite, PszFromGh(QDE_FM(qde)));
vaHilite= (qde->top.mtop.vaNSR.dword != vaNil)? qde->top.mtop.vaNSR
: qde->top.mtop.vaSR;
return;
resource_limited:
// If we don't have enough memory to construct the highlight structures
// we just deallocate the partial results and set the hilite count to
// zero.
HeapChecker();
if (haHelpHilites) { FreeGh(haHelpHilites); haHelpHilites = NULL; }
if (haHilites ) { FreeGh(haHilites ); haHilites = NULL; }
HeapChecker();
pHilite = paHilites = NULL;
pHelpHilite = paHelpHilites = NULL;
cHilitesLeft = cHilites = 0;
}
void STDCALL DiscardHiliteInformation()
{
int iWnd;
ASSERT(HilitesDefined());
for (iWnd= 0; iWnd < MAX_WINDOWS; ++iWnd)
if ( ahwnd[iWnd].pszMemberName
&& !WCmpiSz(achMemberHilite, ahwnd[iWnd].pszMemberName)
)
{
ASSERT(ahwnd[iWnd].hwndTopic);
if (ahwnd[iWnd].hwndTopic)
InvalidateRect(ahwnd[iWnd].hwndTopic, NULL, TRUE);
if (ahwnd[iWnd].hwndTitle)
InvalidateRect(ahwnd[iWnd].hwndTitle, NULL, TRUE);
break;
}
achMemberHilite[0] = 0;
szFNameHilite[0] = 0;
vaHilite.dword= vaNil;
ASSERT(!haHilites && !paHilites && !pHilite && !pHelpHilite);
HeapChecker();
if (haHelpHilites)
{
FreeGh(haHelpHilites);
haHelpHilites = NULL;
paHelpHilites = NULL;
cHilites = 0;
}
HeapChecker();
}
UINT STDCALL GetHilites(QDE qde, PHELPHILITE *ppHelpHilites)
{
if (!paHelpHilites || !cHilites) return 0;
if (!IsHiliteWindow(qde)) return 0;
if (HasTopicChanged(qde))
{
DiscardHiliteInformation();
return NULL;
}
*ppHelpHilites= paHelpHilites;
return cHilites;
}
#define COLLECT_BUFFER 4096
static BYTE ScanBuffer[COLLECT_BUFFER];
static PSTR pszCollect;
static UINT iCharSet;
static BOOL fPendingSpace;
static int cbScanned;
static int cbCollect;
static void STDCALL InitScanBuffer(BOOL fSendToScanner)
{
if (pszCollect) DisconnectScanBuffer();
pszCollect = fSendToScanner? ScanBuffer : NULL;
cbCollect = 0;
cbScanned = 0;
iCharSet = 0;
fPendingSpace = FALSE;
ASSERT(pClearDisplayText);
if (fSendToScanner) pClearDisplayText(GetHiliter());
else
{
pHilite = paHilites;
pHelpHilite = paHelpHilites;
cHilitesLeft = cHilites;
fScanningForStart = TRUE;
}
}
static void STDCALL FlushToScanner();
static void STDCALL DisconnectScanBuffer()
{
FlushToScanner();
pszCollect = NULL;
}
static void STDCALL FlushToScanner()
{
if (cbCollect)
pScanDisplayText(GetHiliter(), pszCollect, cbCollect, iCharSet, lcid);
cbCollect= 0;
}
// The QueueForScanner routine processes text from the display environment.
// Processing happens in two phases. During the first phase the text is passed
// to the HILITER. In that phase the explicit result from QueueForScanner is
// ignored. During the second phase we scan the text again to map an array of
// HILITES into an array of HELPHILITES. In the second phase the explicit result
// from QueueForScanner is TRUE when all the elements of the HILITES array have
// been mapped into the HELPHILITES array.
static BOOL STDCALL QueueForScanner(PSTR *ppszText, UINT charset, VA vaBase, int ichBase)
{
int cbBase;
PSZ pszText= *ppszText;
UINT cbText = strlen(pszText);
*ppszText = pszText + cbText;
if (fPendingSpace) cbScanned++;
cbBase= cbScanned;
cbScanned += cbText;
// This routine is used for two purposes. When pszCollect is non-NULL
// we're passing the topic text along to the Hiliter. When it's NULL,
// we're remapping the HILITE array into the HELPHILITE array.
if (!pszCollect)
{
fPendingSpace= FALSE;
for (;;)
{
if (!cHilitesLeft) return TRUE;
if (fScanningForStart)
{
if (pHilite->base >= cbScanned) return FALSE;
// ASSERT(pHilite->base >= cbBase);
pHelpHilite->vaBase = vaBase;
pHelpHilite->ichBase = ichBase + pHilite->base - cbBase;
if (pHilite->limit > cbScanned)
{
fScanningForStart= FALSE;
return FALSE;
}
pHelpHilite->vaLimit = vaBase;
pHelpHilite->ichLimit = ichBase + pHilite->limit - cbBase;
++pHelpHilite;
++pHilite;
--cHilitesLeft;
continue;
}
if (pHilite->limit > cbScanned) return FALSE;
pHelpHilite->vaLimit = vaBase;
pHelpHilite->ichLimit = ichBase + pHilite->limit - cbBase;
fScanningForStart = TRUE;
++pHelpHilite;
++pHilite;
--cHilitesLeft;
continue;
}
}
if (charset != iCharSet)
{
FlushToScanner();
iCharSet= charset;
}
if (cbText + cbCollect + (fPendingSpace? 1 : 0) > COLLECT_BUFFER)
FlushToScanner();
if (fPendingSpace)
{
pszCollect[cbCollect++] = ' ';
fPendingSpace= FALSE;
}
while (cbText)
{
int cbChunk= cbText;
if (cbChunk > COLLECT_BUFFER - cbCollect)
cbChunk = COLLECT_BUFFER - cbCollect;
cbText -= cbChunk;
CopyMemory(pszCollect + cbCollect, pszText, cbChunk);
cbCollect += cbChunk;
pszText += cbChunk;
if (cbCollect == COLLECT_BUFFER)
FlushToScanner();
}
return FALSE;
}
static BOOL fTitleSeen;
static BOOL bSYS;
static BOOL bSYSFirst;
static BOOL STDCALL NextFTSString(QDE qde, LPSTR pszText, LPSTR *ppCmd,
int* pCharSet, VA vaBase, PCSTR pszEnd)
{
char chCmd;
MOBJ mobj;
MOPG mopg;
BOOL bProcessCell = FALSE;
short int iCell;
BYTE oldCharSet;
LPSTR pszBase= pszText;
if (*pszText)
QueueForScanner(&pszText, *pCharSet, vaBase, pszText - pszBase);
ASSERT(*pszText == 0x00);
while (pszText < pszEnd) {
while (*pszText == chCommand) {
// Side by side paragraph has the following embedded structure:
// INT16 cell number;
// MOBJ;
// MOPG;
if (bSYS && bSYSFirst)
{
bSYSFirst = FALSE;
bProcessCell = TRUE;
#ifdef _X86_
iCell = *((short int *) *ppCmd);
#else
{
UNALIGNED short int *pTemp;
pTemp = (short int *)*ppCmd;
iCell = *pTemp;
}
#endif
(*ppCmd) += 2;
if (iCell < 0)
return TRUE;
#ifdef _X86_
(*ppCmd) += CbUnpackMOBJ(&mobj, *ppCmd);
(*ppCmd) += CbUnpackMOPG(qde, &mopg, *ppCmd);
#else
(*ppCmd) += CbUnpackMOBJ(&mobj, (void *) *ppCmd, QDE_ISDFFTOPIC(qde));
(*ppCmd) += CbUnpackMOPG(qde, &mopg, *ppCmd, QDE_ISDFFTOPIC(qde));
#endif
}
// do
// {
chCmd = **ppCmd;
switch((0x00FF & chCmd))
{
case bNewLine:
fPendingSpace = TRUE;
(*ppCmd)++;
break;
case bNewPara:
fPendingSpace = TRUE;
(*ppCmd)++;
break;
case bTab:
fPendingSpace = TRUE;
(*ppCmd)++;
break;
case bEndHotspot:
(*ppCmd)++;
break;
case bBlankLine:
fPendingSpace = TRUE;
*ppCmd += 3;
break;
case bWordFormat:
(*ppCmd)++;
oldCharSet = *pCharSet;
#ifdef _X86_
*pCharSet =
GetCharset(qde, (*((INT16*)*ppCmd))) & 0x000000ff;
#else
{UNALIGNED INT16 *pTemp;
pTemp = (INT16*) *ppCmd;
*pCharSet = GetCharset(qde, *pTemp) & 0x000000ff;
}
#endif
if (oldCharSet != *pCharSet)
FlushToScanner();
*ppCmd += 2;
break;
case bWrapObjLeft:
case bWrapObjRight:
case bInlineObject:
fPendingSpace = TRUE;
(*ppCmd)++;
#ifdef _X86_
*ppCmd += CbUnpackMOBJ(&mobj, (void *) *ppCmd);
#else
*ppCmd += CbUnpackMOBJ(&mobj, (void *) *ppCmd,
QDE_ISDFFTOPIC(qde));
#endif
*ppCmd += (INT16) mobj.lcbSize;
break;
case bEnd:
(*ppCmd)++;
// fPendingSpace= TRUE;
if (bSYS)
{
bProcessCell = TRUE;
#ifdef _X86_
iCell = *((short int *) *ppCmd);
#else
{
UNALIGNED short int *pTemp;
pTemp = (short int *)*ppCmd;
iCell = *pTemp;
}
#endif
(*ppCmd) += 2;
if (iCell < 0)
return TRUE;
#ifdef _X86_
(*ppCmd) += CbUnpackMOBJ(&mobj, *ppCmd);
(*ppCmd) += CbUnpackMOPG(qde, &mopg, *ppCmd);
#else
(*ppCmd) += CbUnpackMOBJ(&mobj, (void *) *ppCmd, QDE_ISDFFTOPIC(qde));
(*ppCmd) += CbUnpackMOPG(qde, &mopg, *ppCmd, QDE_ISDFFTOPIC(qde));
#endif
}
if (bProcessCell)
bProcessCell = FALSE;
else
return TRUE;
break;
default:
if (FShortHotspot(**ppCmd))
{
*ppCmd += 5;
}
else if (FLongHotspot(**ppCmd))
{
(*ppCmd)++;
#ifdef _X86_
*ppCmd += 2 + *((INT16*)*ppCmd);
#else
{UNALIGNED INT16 *pTemp;
pTemp = (INT16*)*ppCmd;
*ppCmd += 2 + *pTemp;
}
#endif
}
else
{
ASSERT(FALSE);
return TRUE;
}
break;
}
// } while (bProcessCell);
pszText++;
}
if (pszText) QueueForScanner(&pszText, *pCharSet, vaBase, pszText - pszBase);
}
return TRUE;
}
enum {
TABTYPELEFT,
TABTYPERIGHT,
TABTYPECENTER,
TABTYPEDECIMAL
};
#ifdef _X86_
static PBYTE STDCALL ScanTopic(LPSTR lpData, QFCINFO qfcinfo, MTOP* pmtop)
#else
static PBYTE STDCALL ScanTopic(LPSTR lpData, QFCINFO qfcinfo, MTOP* pmtop, QDE qde)
#endif
{
MOBJ mobj;
int iTopic;
QMSBS qmsbs;
#ifndef _X86_
MTOP mtop;
#endif
for(;;) {
#ifdef _X86_
lpData += CbUnpackMOBJ(&mobj, (QV) lpData);
#else
lpData += CbUnpackMOBJ(&mobj, (QV) lpData,QDE_ISDFFTOPIC(qde));
#endif
iTopic = 0x00FF & mobj.bType;
bSYS = FALSE;
bSYSFirst = FALSE;
switch (iTopic)
{
case bTypeSbys:
case bTypeSbysCounted:
if (pmtop)
return lpData;
bSYS = TRUE;
bSYSFirst = TRUE;
qmsbs = (QMSBS) lpData;
lpData += 2;
if (!qmsbs->fAbsolute)
{
lpData += 2;
}
lpData += qmsbs->bcCol * sizeof(MCOL);
return(lpData);
default:
if (pmtop)
ZeroMemory(pmtop, sizeof(MTOP));
return(NULL);
break;
case bTypeParaGroup:
case bTypeParaGroupCounted:
{
MOPG mopg;
MPFG mpfg;
LPSTR lpStart = lpData;
int iTab;
if (pmtop)
return lpData;
lpData = QVSkipQGE(lpData, (QL) &(mopg.libText));
#ifdef _X86_
mpfg = *((QMPFG) lpData);
#else
MoveMemory(&mpfg, lpData, sizeof(MPFG));
#endif
lpData = (LPSTR) (((QMPFG) lpData) + 1);
if (mpfg.rgf.fMoreFlags)
{
lpData = QVSkipQGE(lpData, (QL) &(mopg.lMoreFlags));
}
if (mpfg.rgf.fSpaceOver)
{
lpData = QVSkipQGD((LPBYTE) lpData, (QI) &(mopg.ySpaceOver));
}
if (mpfg.rgf.fSpaceUnder)
{
lpData = QVSkipQGD((LPBYTE) lpData, (QI) &(mopg.ySpaceUnder));
}
if (mpfg.rgf.fLineSpacing)
{
lpData = QVSkipQGD((LPBYTE) lpData, (QI) &(mopg.yLineSpacing));
}
if (mpfg.rgf.fLeftIndent)
{
lpData = QVSkipQGD((LPBYTE) lpData, (QI) &mopg.xLeftIndent);
}
if (mpfg.rgf.fRightIndent)
{
lpData = QVSkipQGD((LPBYTE) lpData, (QI)&mopg.xRightIndent);
}
if (mpfg.rgf.fFirstIndent)
{
lpData = QVSkipQGD((LPBYTE) lpData, (QI)&mopg.xFirstIndent);
}
mopg.xTabSpacing = 72;
if (mpfg.rgf.fTabSpacing)
{
lpData = QVSkipQGD((LPBYTE) lpData, (QI)&mopg.xTabSpacing);
}
if (mpfg.rgf.fBoxed)
{
mopg.mbox = *((QMBOX)lpData);
#ifdef _X86_
lpData = (LPSTR) (((QMBOX)lpData) + 1);
#else
lpData = (QB)lpData + 3;
#endif
}
if (mpfg.rgf.fTabs)
{
lpData = QVSkipQGD((LPBYTE) lpData, (QI) &mopg.cTabs);
}
else
mopg.cTabs = 0;
for (iTab = 0; iTab < mopg.cTabs; iTab++)
{
lpData = QVSkipQGA(lpData, (QI) &mopg.rgtab[iTab].x);
if (mopg.rgtab[iTab].x & 0x4000)
lpData = QVSkipQGA(lpData, (QI) &mopg.rgtab[iTab].wType);
else
mopg.rgtab[iTab].wType = TABTYPELEFT;
mopg.rgtab[iTab].x = mopg.rgtab[iTab].x & 0xBFFF;
}
}
return(lpData);
break;
case bTypeTopic:
if (pmtop) { // all we wanted was MTOP structure
MoveMemory(pmtop, lpData, sizeof(MTOP));
return NULL;
}
else
#ifdef _X86_
pmtop = (MTOP*) lpData;
#else
{
MoveMemory(&mtop, lpData, sizeof(MTOP));
pmtop = & mtop;
}
#endif
lpData += sizeof(MTOP);
fTitleSeen = TRUE;
return(NULL);
}
}
}
static BOOL STDCALL ForageTopic(QDE qde, VA vaNext)
{
static DB db;
int wErr;
HFC hfc = NULL;
LPSTR lpCmd;
LPSTR lpText;
DWORD dwCmd;
int cbAnimate = 0;
QFCINFO qfcinfo;
iCharSet = defcharset;
fTitleSeen = FALSE;
while (!fTitleSeen && (hfc = GetQFCINFO(qde, vaNext, &wErr)) != NULL)
{
qfcinfo = (QFCINFO) PtrFromGh(hfc);
/*
* In order for WinHelp to be able to jump to this topic,
* vaCurrent must be set to vaNext. Don't ask me why -- but it works.
* Same VA is used in History and Bookmark jumps. [ralphw]
*/
vaNext = qfcinfo->vaNext;
#ifdef _X86_
lpCmd = ScanTopic(((LPSTR) qfcinfo) + sizeof(FCINFO), qfcinfo, NULL);
#else
lpCmd = ScanTopic(((LPSTR) qfcinfo) + sizeof(FCINFO), qfcinfo, NULL, qde);
#endif
if (lpCmd)
{
lpText = ((LPSTR) qfcinfo) + qfcinfo->ichText;
dwCmd = lpText - lpCmd;
if (!NextFTSString(qde, lpText, &lpCmd, &iCharSet, qfcinfo->vaCurr,
lpText + qfcinfo->lcbText
)
)
{
FreeGh(hfc); hfc= NULL;
return FALSE;
}
}
FreeGh(hfc); hfc= NULL;
}
return TRUE;
}
static BOOL STDCALL ScanThisTopic(QDE qde)
{
HDE hde = NULL;
VA vaHilite;
BOOL fRet;
hde = HdeCreate(NULL, qde, deTopic);
if (!hde) return FALSE;
vaHilite= (qde->top.mtop.vaNSR.dword != vaNil)? qde->top.mtop.vaNSR
: qde->top.mtop.vaSR;
fRet = ForageTopic(QdeFromGh(hde), vaHilite);
ASSERT(hde);
DestroyHde(hde);
return fRet;
}
#endif