/* $Header$ */

// base WP text object class implementation

/**************** Changes ******************
Date			Edit				Bug					Description
06-Oct-22	rmm11749		ST/WO/2704	Issues with HTML (docview) when printed to a report.
16-Feb-22	rmm11442								Highlight function parameters in online help descriptions.
12-Nov-21	rmm11295								Changed GDIgetStockPen() to have two new arguments (GDI_STOCK_PEN_WINDOW and GDI_STOCK_PEN_WINDOWTEXT), replacing WHITE_PEN and BLACK_PEN respectively. Also tidied up some old menu code.
14-Apr-21	rmm10984								Removed compiler warnings on Windows platform.
03-Jan-19	rmm9887			ST/HE/1560	Problems viewing and printing Omnis help pages.
31-Dec-18	rmm9881			ST/EC/1524	Issues with RTF on reports - text spanning pages had problems, and tabs did not always render nicely.
19-Dec-17	rmm_emat								Text editor for Omnis language.
29-Sep-14	rmm8434			ST/BE/1015	More print preview scaling issues.
19-Aug-13	rmm64bitux							Linux 64 bit port.
25-Jul-07	rmm6181									Changed font for help pages.
19-Apr-04	AE6431			ST/GS/118:	Small text was drawing incorrectly on Win2000
14-Aug-03	AE6315			ST/PF/263: 	Crash when displaying an html file (+ added colour names)
12-Feb-03	rmmdocgen								Studio 4.0 documentation generator.
15 NOV 01 mpm_rmm4180							More RTF problems
01 AUG 00 mpm4723a		st/dc/176		Fixes blank space problem between paras (zero length text objects were causing problems)
22 MAY 00	mpm4700									Implements printing of document
08 NOV 99 mlr0006									Added Rtf support
********************************************/

#ifndef _extcomp_
#include "extcomp.he" // jmg_includecasing
#endif

#ifndef	_WPTEXT_HE_
#include "wptext.he" // jmg_includecasing
#endif

#ifndef	_WPDOC_HE_
#include "wpdoc.he" // jmg_includecasing
#endif

#include "wprtf.he"	// rmm9881
#include "htmlctrl.he"	// rmm11749

// ###############################################################################
// ################# WPTextInfoStruct Public #####################################
// ###############################################################################


void WPTextInfoStruct::getTextSpec( WPDocClass* pObject, GDItextSpecStruct* pTextSpec, qbool pGetSub )
{
	if ( !pGetSub ) pGetSub = isSubscript() || isSuperscript();
	WPTextInfoStruct* ti = 0;
	pTextSpec->mSty = styPlain;
	pTextSpec->mJst = jstLeft;	// rmm8434: This was not being initialised
	pObject->getDocumentInfo( eWPdocInfoTextColor, 0, (qlong&)pTextSpec->mTextColor );
	if ( mSet & WPTEXT_STYLESET )
	{
		if ( pObject->getDocumentInfoPtr( eWPdocInfoStyle, mStyle, (qlongptr&)(ti) ) ) // rmm64bitux
		{
			ti->getTextSpec( pObject, pTextSpec, pGetSub );
		}
	}
	if ( mSet & WPTEXT_FONTNUMSET )
	{
		GDIsetFontNumber( &pTextSpec->mFnt, mFontNum );
	}
	if ( mSet & WPTEXT_FONTSIZESET )
	{
		qshort size; qlong extra = 0;
		pObject->getDocumentInfo( eWPdocInfoFontSizeAdj, 0, extra );
		switch ( mFontSizeMode )
		{
			case eWPFontSizePoints:
				size = pGetSub ? mFontSize * 4 / 5 : mFontSize;
				break;
			case eWPFontSizeHtml:
			case eWPFontSizeHtmlAdj:
				if ( mFontSizeMode == eWPFontSizeHtml )
					size = (qshort) (mFontSize+extra-1);
				else
				{
					if ( !ti ) pObject->getDocumentInfoPtr( eWPdocInfoStyle, WP_DOCINFO_BASESTYLE, (qlongptr&)(ti) ); // rmm64bitux
					if ( ti && ti->mFontSizeMode == eWPFontSizeHtml )
						size = ti->mFontSize + mFontSize - 1 +(qshort)extra;
					else
						size = 3 + mFontSize - 1 + (qshort)extra;
				}
				qshort* fontSize = pGetSub ? &pObject->mWPfontSubSizes[0] : &pObject->mWPfontSizes[0]; // rmm_emat
				if ( size < 0 )
					size = fontSize[0] + size * 2;
				else if ( size > 6 )
					size = fontSize[6] + (size-6) * 2;
				else
					size = fontSize[size];
				break;
		}
		// AE6431 Hack for Windows 2000 fonts. Prevent fonts less than eight points in size
#if 0 // rmm10984: defined(iswin32) && !defined(isunix)
		DWORD verinfo = GetVersion();
		DWORD verMajor = verinfo & 0xff;
		DWORD verMinor = (verinfo >> 8) & 0xff;
		if ( verMajor==5 && verMinor==0 && size<8 )
			size = 8;
#endif
		if (mFontSizeMode != eWPFontSizeNone)
			GDIfontSetSize(&pTextSpec->mFnt, size);
	}
	if ( mSet & WPTEXT_FONTSTYBSET )
	{
		if ( mFontStyBold )
			pTextSpec->mSty |= styBold;
		else
			pTextSpec->mSty &= ~styBold;
	}
	if ( mSet & WPTEXT_FONTSTYISET )
	{
		if ( mFontStyItalic )
			pTextSpec->mSty |= styItalic;
		else
			pTextSpec->mSty &= ~styItalic;
	}
	if ( mSet & WPTEXT_FONTSTYUSET )
	{
		if ( mFontStyUnderline )
			pTextSpec->mSty |= styUnderline;
		else
			pTextSpec->mSty &= ~styUnderline;
	}
	if ( mSet & WPTEXT_TEXTCOLORSET )
	{
		pTextSpec->mTextColor = mTextColor;
	}
}


qcol WPTextInfoStruct::getTextColor( WPDocClass* pObject )
{
	qcol col = GDI_COLOR_QBLACK;
	if ( mSet & WPTEXT_TEXTCOLORSET )
	{
		col = mTextColor;
	}
	else if ( mSet & WPTEXT_STYLESET )
	{
		WPTextInfoStruct* ti = 0;
		if ( pObject->getDocumentInfoPtr( eWPdocInfoStyle, mStyle, (qlongptr&)(ti) ) ) // rmm64bitux
		{
			col = ti->getTextColor( pObject );
		}
	}
	return col;
}


// ###############################################################################
// ################# WPTextClass Public ##########################################
// ###############################################################################


WPTextClass::WPTextClass( WPObjectClass* pParent, WPDocClass* pDocumentObj )
						:WPObjectClass( pParent, pDocumentObj )
{
	mLinkInfo = 0;
	mBreak = qfalse;
}


WPTextClass::~WPTextClass()
{
	if ( mLinkInfo ) delete mLinkInfo;
}


WPTextClass* WPTextClass::make( WPObjectClass* pParent, WPDocClass* pDocumentObj, WPTextInfoStruct* pTextInfo, qlong pTextStart, qlong pTextLen )
{
	WPTextClass* obj = new WPTextClass( pParent, pDocumentObj );
	obj->mTextInfo = *pTextInfo;
	obj->mTextStart = pTextStart;
	obj->mTextLen = pTextLen;
	// Start rmm11749
#ifdef _DEBUG
	if ((0))
	{
		qchar* p = pDocumentObj->getTextPtr(pTextStart);
		str255 s(p, pTextLen);
		p = 0;	// Line for setting breakpoint to inspect s
	}
#endif
	// End rmm11749
	return obj;
}


void WPTextClass::initData( WPObjInfoStruct* pObjInfo,printInfo* pInfo )
{
	// if printing want a different init, although similar
	if ( pInfo != NULL )
	{
		initDataPri(pObjInfo,pInfo) ;
		return ;
	}
	if ( mBreak ) mParent->newRow( pObjInfo );
	
	pObjInfo->mVAlign = eWPVAbaseline;
	
	if ( !mTextLen )
	{
		qlrect& ownerRect = pObjInfo->mOwnerRect; // mpm4723a begins
		GDItextSpecStruct ts; mTextInfo.getTextSpec( mDocumentObj, &ts );
		qldim fntHt = GDIfontPart( &ts.mFnt, ts.mSty, eFontHeight/*mpm_rmm4180 eFontLineHeight*/ );
		qdim descent = GDIfontPart( &ts.mFnt, ts.mSty, eFontDescent );
		ownerRect.height( fntHt );
		ownerRect.width( 1 );
		pObjInfo->mOwnerBaseLine = ownerRect.top + fntHt - descent - 1;
		pObjInfo->mOwnerData1 = pObjInfo->mOwnerData2 = 0;
		mParent->addRowInfo( pObjInfo ); // mpm4723a ends
	}
	else
	{ // calculate the rows of text
		qlrect& ownerRect = pObjInfo->mOwnerRect;
		qlrect& rowRect = pObjInfo->mRowRect;
		HDC dc = GDIgetTempDC();
		GDItextSpecStruct ts; mTextInfo.getTextSpec( mDocumentObj, &ts );

		HFONT fnt = GDIcreateFont( &ts.mFnt, ts.mSty );
		fnt = GDIselectObject( dc, fnt );
		
		qldim fntHt = GDIfontPart( dc, eFontHeight/*mpm_rmm4180 eFontLineHeight*/ );
		qdim descent = GDIfontPart( dc, eFontDescent );
		ownerRect.bottom = ownerRect.top + fntHt - 1;

		pObjInfo->mOwnerBaseLine = ownerRect.top + fntHt - descent - 1;
		if ( mTextInfo.isSuperscript() )
			pObjInfo->mOwnerBaseLine += descent + 1;
		else if ( mTextInfo.isSubscript() )
			pObjInfo->mOwnerBaseLine -= descent + 1;
		
		qchar* textPtr = mDocumentObj->getTextPtr( mTextStart );
		qldim wid = GDItextWidth( dc, textPtr,(qshort) mTextLen );
		
		qldim maxWid = rowRect.right - ownerRect.left + 1;
		if (wid <= maxWid || pObjInfo->mNoWrap || (parent() && parent()->parent() && parent()->parent()->tableCellWithNoWrap())) // rmm_emat
		{
			ownerRect.right = ownerRect.left + wid - 1;
			pObjInfo->mOwnerData1 = 0;
			pObjInfo->mOwnerData2 = mTextLen;
			mParent->addRowInfo( pObjInfo );
		}
		else
		{ // wrapping takes place
			qlong rowStart = 0;
			qlong rowLen = 0;
			qlong lastRowLen = 0;
			qldim lastWid = 0;
			while ( addNextWord( rowStart, rowLen ) )
			{
				qldim wid = GDIcharWidth( dc, *MEMincAddr( textPtr, rowStart ) );
				if ( wid > maxWid && wid > rowRect.width() ) maxWid = wid;
				wid = GDItextWidth( dc, MEMincAddr( textPtr, rowStart ), (qshort)rowLen );
				if ( wid > maxWid )
				{
					if ( !lastRowLen && ownerRect.left == rowRect.left ) ;
					else 
					{
						rowLen = lastRowLen;
						wid = lastWid;
					}
					addNextSpaces( rowStart, rowLen );
					if ( rowLen )
					{
						ownerRect.right = ownerRect.left + wid - 1;
						pObjInfo->mOwnerData1 = rowStart;
						pObjInfo->mOwnerData2 = rowLen;
						mParent->addRowInfo( pObjInfo );
					}
					// prepare row info for next row
					mParent->newRow( pObjInfo );
					ownerRect.bottom = ownerRect.top + fntHt - 1;
					pObjInfo->mOwnerBaseLine = ownerRect.top + fntHt - descent - 1;
					maxWid = rowRect.right - ownerRect.left + 1;
					
					rowStart += rowLen;
					rowLen = lastRowLen = 0;
				}
				else
				{
					lastRowLen = rowLen;
					lastWid = wid;
				}
			}
			addNextSpaces( rowStart, rowLen );
			if ( rowLen )
			{
				wid = GDItextWidth( dc, MEMincAddr( textPtr, rowStart ), (qshort)rowLen );
				if ( wid > maxWid ) wid = lastWid;
				ownerRect.right = ownerRect.left + wid - 1;
				pObjInfo->mOwnerData1 = rowStart;
				pObjInfo->mOwnerData2 = rowLen;
				mParent->addRowInfo( pObjInfo );
			}
		}
		
		fnt = GDIselectObject( dc, fnt );
		GDIdeleteObject( fnt );
	}
}


void WPTextClass::paint( WPObjInfoStruct* pObjInfo, WNDpaintStruct* pPaintStruct, qldim pHorzOff, qldim pVertOff )
{
	if ( !pObjInfo || !pObjInfo->mOwnerData2 ) return;
	GDItextSpecStruct ts; mTextInfo.getTextSpec( mDocumentObj, &ts );
	
	HDC dc = pPaintStruct->hdc;
	HFONT fnt = GDIcreateFont( &ts.mFnt, ts.mSty );
	fnt = GDIselectObject( dc, fnt );
	
	GDIsetTextColor( dc, ts.mTextColor );
	
	qldim vertPos; 
	qdim ascent = GDIfontPart( dc, eFontAscent );
	qdim descent = GDIfontPart( dc, eFontDescent );
	if ( mTextInfo.isSubscript() )
		vertPos = pObjInfo->mOwnerRect.bottom -  GDIfontPart( dc, eFontHeight/*mpm_rmm4180 eFontLineHeight*/ ) + 1 + pVertOff;
	else if ( mTextInfo.isSuperscript() )
		vertPos = pObjInfo->mOwnerRect.top + pVertOff;
	else
		vertPos = pObjInfo->mOwnerBaseLine - ascent + 1 + pVertOff;
	
	qchar* textPtr = mDocumentObj->getTextPtr( mTextStart + pObjInfo->mOwnerData1 );	
	qldim horzPos = pObjInfo->mOwnerRect.left + pHorzOff;
	GDIdrawText( dc, qdim(horzPos), qdim(vertPos), 
								textPtr, (qshort) pObjInfo->mOwnerData2, jstLeft );

	if ( mTextInfo.isStrike() )
	{
		HPEN pen = GDIselectObject( dc, GDIgetStockPen( GDI_STOCK_PEN_WINDOWTEXT ) ); // rmm11295
		vertPos += descent + ascent / 2 - 1;
		GDImoveTo( dc, horzPos, vertPos );
		horzPos += GDItextWidth( dc, textPtr, (qshort) pObjInfo->mOwnerData2 );
		GDIlineTo( dc, horzPos, vertPos );
		GDIselectObject( dc, pen );
	}
	
	if ( mTextInfo.mInvert )
	{
		qlrect lr = pObjInfo->mOwnerRect; lr.offset( pHorzOff, pVertOff );
		qrect r; lr.conv( &r );
		GDIinvertRect( dc, &r );
	}

	fnt = GDIselectObject( dc, fnt );
	GDIdeleteObject( fnt );
}


qlong WPTextClass::getChar( qlong pIndex, qldim pWidth )
{
	GDItextSpecStruct ts; mTextInfo.getTextSpec( mDocumentObj, &ts );
	HDC dc = GDIgetTempDC();
	HFONT fnt = GDIcreateFont( &ts.mFnt, ts.mSty );
	fnt = GDIselectObject( dc, fnt );

	qchar* text = mDocumentObj->getTextPtr( pIndex );
	qldim wid = 0; qlong len = 0;
	while ( wid < pWidth )
	{
		len++;
		wid = GDItextWidth( dc, text,(qshort) len );
	}
	
	fnt = GDIselectObject( dc, fnt );
	GDIdeleteObject( fnt );

	return pIndex + len - 1;
}


qlong WPTextClass::message( WPObjInfoStruct* pObjInfo, eWPMessage pMessage, qldim pHorzOff, qldim pVertOff, LPARAM lParam1, LPARAM lParam2 )
{
	if ( pMessage == eWPMessGetCharRange )
	{
		WPgetCharRangeStruct* charRangeInfo = (WPgetCharRangeStruct*)lParam1;
		qlrect& selRect = charRangeInfo->mSelRect;
		qlrect ownerRect = pObjInfo->mOwnerRect; ownerRect.offset( pHorzOff, pVertOff );
		qlrect ownerRect2 = ownerRect;
		if ( selRect.bottom < ownerRect.top && selRect.top < ownerRect.top ) return 0L;
		else if ( selRect.bottom > ownerRect.bottom && selRect.top > ownerRect.bottom ) return 0L;
		else if ( selRect.right < ownerRect.left && selRect.left < ownerRect.left ) return 0L;
		else if ( selRect.right > ownerRect.right && selRect.left > ownerRect.right ) return 0L;
		//if ( selRect.bottom < ownerRect.top || selRect.top > ownerRect.bottom ) return 0L; // we are not within selRect
		else
		{
			if ( selRect.top >= ownerRect.top && selRect.top <= ownerRect.bottom && ownerRect.left < selRect.left ) ownerRect.left = selRect.left;
			if ( selRect.bottom >= ownerRect.top && selRect.bottom <= ownerRect.bottom && ownerRect.right > selRect.right ) ownerRect.right = selRect.right;
			if ( ownerRect.right < ownerRect.left ) { qldim tmp = ownerRect.left; ownerRect.left = ownerRect.right; ownerRect.right = tmp; }
			if ( ownerRect.width() > 0 )
			{
				qlong start = 0x7FFFFFFF, end = 0;
				if ( ownerRect.left == ownerRect2.left )
					start = mTextStart + pObjInfo->mOwnerData1;
				else 
					start = getChar( mTextStart + pObjInfo->mOwnerData1, ownerRect.left - ownerRect2.left );
				if ( ownerRect.right == ownerRect2.right )
					end = mTextStart + pObjInfo->mOwnerData1 + pObjInfo->mOwnerData2 - 1;
				else
					end = getChar( mTextStart + pObjInfo->mOwnerData1, ownerRect.right - ownerRect2.left );
				if ( start < charRangeInfo->mFstChar ) charRangeInfo->mFstChar = start;
				if ( end > charRangeInfo->mLstChar ) charRangeInfo->mLstChar = end;
			}
		}
		return 0L;
	}
	else if ( pMessage == eWPMessGetCharRangeRgn )
	{
		WPgetCharRangeStruct* charRangeInfo = (WPgetCharRangeStruct*)lParam1;
		qlong textStart = mTextStart + pObjInfo->mOwnerData1;
		qlong textEnd = textStart + pObjInfo->mOwnerData2 - 1;
		qlong fstChar = charRangeInfo->mFstChar;
		qlong lstChar = charRangeInfo->mLstChar;
		if ( lstChar < textStart || fstChar > textEnd ) return 0L;
		
		if ( textStart > fstChar ) fstChar = textStart;
		if ( textEnd < lstChar ) lstChar = textEnd;
		
		if ( lstChar >= fstChar )
		{
			qlrect ownerRect = pObjInfo->mOwnerRect; ownerRect.offset( pHorzOff, pVertOff );
			if ( fstChar > textStart || lstChar < textEnd )
			{
				GDItextSpecStruct ts; mTextInfo.getTextSpec( mDocumentObj, &ts );
				HDC dc = GDIgetTempDC();
				HFONT fnt = GDIcreateFont( &ts.mFnt, ts.mSty );
				fnt = GDIselectObject( dc, fnt );
	
				if ( fstChar > textStart )
					ownerRect.left += GDItextWidth( dc, mDocumentObj->getTextPtr( textStart ), (qshort) (fstChar - textStart) );
				if ( lstChar < textEnd )
					ownerRect.right = ownerRect.left + GDItextWidth( dc, mDocumentObj->getTextPtr( fstChar ), (qshort) (lstChar - fstChar + 1) ) - 1;
	
				fnt = GDIselectObject( dc, fnt );
				GDIdeleteObject( fnt );
			}
			qrect r; ownerRect.conv( &r );
			if ( !charRangeInfo->mSelRgn )
			{
				charRangeInfo->mSelRgn = GDIcreateRectRgn( &r );
			}
			else
			{
				qrgn ownerRgn; GDIsetRectRgn( &ownerRgn, &r );
				GDIrgnOr( charRangeInfo->mSelRgn, charRangeInfo->mSelRgn, &ownerRgn );
			}
		}
		return 0L;
	}
	else if ( pMessage == eWPMessCopyCharRange )
	{
		WPgetCharRangeStruct* charRangeInfo = (WPgetCharRangeStruct*)lParam1;
		qlong textStart = mTextStart + pObjInfo->mOwnerData1;
		qlong textEnd = textStart + pObjInfo->mOwnerData2 - 1;
		qlong fstChar = charRangeInfo->mFstChar;
		qlong lstChar = charRangeInfo->mLstChar;
		
		if ( textStart > fstChar ) fstChar = textStart;
		if ( textEnd < lstChar ) lstChar = textEnd;
		
		if ( lstChar >= fstChar )
		{
			EXTfldval* fldval = (EXTfldval*)lParam2;
			if ( fstChar == mTextStart && mBreak ) fldval->concat( (qchar)13 );
			fldval->concat( mDocumentObj->getTextPtr( fstChar ), lstChar - fstChar + 1 );
		}
		return 0L;
	}
	else if ( pMessage == eWPMessFindBookmark )
	{
		if ( mLinkInfo && mLinkInfo->mIsBookmark )
		{
			strxxx* bookmark = (strxxx*)lParam1;
			if ( mLinkInfo->mName.uprCmp( *bookmark ) == 0 )
			{
				pObjInfo->mOwnerRect.offset( pHorzOff, pVertOff );
				pObjInfo->mOwnerBaseLine += pVertOff;
				return 1L;
			}
		}
	}
	else if ( pMessage == eWPMessFindSearchWord )
	{
		if ( mTextInfo.mInvert )
		{
			pObjInfo->mOwnerRect.offset( pHorzOff, pVertOff );
			pObjInfo->mOwnerBaseLine += pVertOff;
			return 1L;
		}
	}
	return 0L;
}


HCURSOR WPTextClass::getCursor( WPObjInfoStruct* pObjInfo, qpoint* pPoint )
{
	return (mLinkInfo && !mLinkInfo->mIsBookmark && mLinkInfo->mHRef.length()) ? WND_CURS_FINGER : WND_CURS_IBEAM; // rmmdocgen: use finger cursor for links // rmm11442: Check length
}


WPLinkInfoStruct* WPTextClass::getLinkInfo()
{
	return (mLinkInfo && !mLinkInfo->mIsBookmark && mLinkInfo->mHRef.length()) ? mLinkInfo : 0; // rmm11442: Check length
}


void WPTextClass::setLinkInfo( WPLinkInfoStruct* pLinkInfo )
{
	if ( mLinkInfo != pLinkInfo )
	{
		mLinkInfo = new WPLinkInfoStruct;
		*mLinkInfo = *pLinkInfo;
	}
	
	if ( !mLinkInfo->mIsBookmark )
	{
		qlong x = colNone;
		eWPdocInfoSwitch infoSwitch = eWPdocInfoLinkColor;
		if (mLinkInfo->mActive)
			infoSwitch = eWPdocInfoALinkColor;
		else if (mLinkInfo->mVisited)
			infoSwitch = eWPdocInfoVLinkColor;
		// Start rmm_emat
		else
			x = mLinkInfo->mColor;
		if (x != colNone || mDocumentObj->getDocumentInfo(infoSwitch, 0, x))
		{
			// End rmm_emat
			mTextInfo.mTextColor = qcol(x);
			mTextInfo.mSet |= WPTEXT_TEXTCOLORSET;
		}
		if (mLinkInfo->mHRef.length())	// rmm11442
		{
			mTextInfo.mFontStyUnderline = qtrue;
			mTextInfo.mSet |= WPTEXT_FONTSTYUSET;
		}
		// Start rmm11442
		else if (mLinkInfo->mColor != colNone)
		{
			mTextInfo.mFontStyBold = qtrue;
			mTextInfo.mSet |= WPTEXT_FONTSTYBSET;
		}
		// End rmm11442
	}
}


// ###############################################################################
// ################# WPTextClass Private #########################################
// ###############################################################################


qbool WPTextClass::addNextWord( qlong& pRowStart, qlong& pRowLen )
{
	qchar* textPtr = mDocumentObj->getTextPtr( mTextStart );
	qbool ret = qfalse;
	qlong pos = pRowStart+pRowLen;
	while ( pos < mTextLen )
	{
		if ( textPtr[pos] != ' ' ) break;
		pos++;
	}
	while ( pos < mTextLen )
	{
		if ( textPtr[pos] == ' ' ) break;
		pos++; ret = qtrue;
	}
	pRowLen = pos - pRowStart;
	return ret;
}


void WPTextClass::addNextSpaces( qlong& pRowStart, qlong& pRowLen )
{
	qchar* textPtr = mDocumentObj->getTextPtr( mTextStart );
	qlong pos = pRowStart+pRowLen;
	while ( pos < mTextLen )
	{
		if ( textPtr[pos] != ' ' ) break;
		pos++;
	}
	pRowLen = pos - pRowStart;
}


void WPTextClass::initDataPri( WPObjInfoStruct* pObjInfo, printInfo* pInfo ) // mpm4700 many changes
{
	if ( mBreak ) mParent->newRow( pObjInfo );
	
	pObjInfo->mVAlign = eWPVAbaseline;
	
	if ( !mTextLen )
	{
		qlrect& ownerRect = pObjInfo->mOwnerRect; // mpm4723a begins
		GDItextSpecStruct ts; mTextInfo.getTextSpec( mDocumentObj, &ts ); 
		qldim fntHt = PRIconvToScreen( PRItextHeight( pInfo->mJob,&ts.mFnt ), qtrue );
		qdim descent = GDIfontPart( &ts.mFnt, ts.mSty, eFontDescent );
		ownerRect.height( fntHt );
		ownerRect.width( 1 );
		pObjInfo->mOwnerBaseLine = ownerRect.top + fntHt - descent - 1;
		pObjInfo->mOwnerData1 = pObjInfo->mOwnerData2 = 0;
		mParent->addRowInfo( pObjInfo ); // mpm4723a ends
	}
	else
	{ // calculate the rows of text
		qlrect& ownerRect = pObjInfo->mOwnerRect;
		qlrect& rowRect = pObjInfo->mRowRect;
		GDItextSpecStruct ts; mTextInfo.getTextSpec( mDocumentObj, &ts );

		qldim fntHt = PRIconvToScreen( PRItextHeight( pInfo->mJob,&ts.mFnt ), qtrue );
		qdim descent = GDIfontPart( &ts.mFnt, ts.mSty, eFontDescent );
		ownerRect.bottom = ownerRect.top + fntHt - 1;

		pObjInfo->mOwnerBaseLine = ownerRect.top + fntHt - descent - 1;
		if ( mTextInfo.isSuperscript() )
			pObjInfo->mOwnerBaseLine += descent + 1;
		else if ( mTextInfo.isSubscript() )
			pObjInfo->mOwnerBaseLine -= descent + 1;
		
		qchar* textPtr = mDocumentObj->getTextPtr( mTextStart );
		qldim wid = PRIconvToScreen( PRItextWidth( pInfo->mJob, textPtr, mTextLen, &ts ), qfalse );
		
		qldim maxWid = rowRect.right - ownerRect.left + 1;
		if ( wid <= maxWid || pObjInfo->mNoWrap )
		{
			ownerRect.right = ownerRect.left + wid - 1;
			pObjInfo->mOwnerData1 = 0;
			pObjInfo->mOwnerData2 = mTextLen;
			mParent->addRowInfo( pObjInfo );
		}
		else
		{ // wrapping takes place
			qlong rowStart = 0;
			qlong rowLen = 0;
			qlong lastRowLen = 0;
			qldim lastWid = 0;
			while ( addNextWord( rowStart, rowLen ) )
			{
				qldim wid = PRIconvToScreen( PRItextWidth( pInfo->mJob, MEMincAddr( textPtr, rowStart ), 1, &ts ), qfalse );
				if ( wid > maxWid && wid > rowRect.width() ) maxWid = wid;
				wid = PRIconvToScreen( PRItextWidth( pInfo->mJob, MEMincAddr( textPtr, rowStart ), rowLen, &ts ), qfalse );
				if ( wid > maxWid )
				{
					if ( !lastRowLen && ownerRect.left == rowRect.left ) ;
					else 
					{
						rowLen = lastRowLen;
						wid = lastWid;
					}
					addNextSpaces( rowStart, rowLen );
					if ( rowLen )
					{
						ownerRect.right = ownerRect.left + wid - 1;
						pObjInfo->mOwnerData1 = rowStart;
						pObjInfo->mOwnerData2 = rowLen;
						mParent->addRowInfo( pObjInfo );
					}
					// prepare row info for next row
					mParent->newRow( pObjInfo );
					ownerRect.bottom = ownerRect.top + fntHt - 1;
					pObjInfo->mOwnerBaseLine = ownerRect.top + fntHt - descent - 1;
					maxWid = rowRect.right - ownerRect.left + 1;
					
					rowStart += rowLen;
					rowLen = lastRowLen = 0;
				}
				else
				{
					lastRowLen = rowLen;
					lastWid = wid;
				}
			}
			addNextSpaces( rowStart, rowLen );
			if ( rowLen )
			{
				wid = PRIconvToScreen( PRItextWidth( pInfo->mJob,  MEMincAddr( textPtr, rowStart ), rowLen, &ts ), qfalse );
				if ( wid > maxWid ) wid = lastWid;
				ownerRect.right = ownerRect.left + wid - 1;
				pObjInfo->mOwnerData1 = rowStart;
				pObjInfo->mOwnerData2 = rowLen;
				mParent->addRowInfo( pObjInfo );
			}
		}
	}
}


qprierr WPTextClass::addToPrintJob( printInfo* pInfo, EXTCompInfo* eci, WPObjInfoStruct* pObjInfo, // mpm4700
																		qldim& pHorzOff, qldim& pVertOff)
{
	PRIobjectStruct obj = *pInfo->mObj; // mpm4700
	obj.mType = PRI_OBJ_TEXT ;
	obj.mTextSpec.mSty = (qsty) mTextInfo.mStyle;
	obj.mFontIndex = 0;
	obj.mStyleIndex = 0;
	obj.mFitVertPage = qtrue; // mpm4700
	obj.mTextSpec.mTextColor = mTextInfo.getTextColor(mDocumentObj);
	GDItextSpecStruct ts; 
	mTextInfo.getTextSpec( mDocumentObj, &ts );
	obj.mTextSpec = ts;
	
	if ( mTextInfo.isSubscript() || mTextInfo.isSuperscript() )
	{
		// perhaps this should be in the initPriData not here
 		qpridim fontSize = PRItextHeight( pInfo->mJob, &(ts.mFnt) );
		qpridim vertOff;
		qprirect rect = obj.mPos ;
		if ( mTextInfo.isSubscript() )
			vertOff = fontSize/3;	
    else //  isSuperscript
			vertOff = qpridim(- (fontSize/2.5));	
			rect.offset(0,vertOff);
		obj.mPos = rect ;
	}
	
	qchar* textPtr = mDocumentObj->getTextPtr( mTextStart + pObjInfo->mOwnerData1);	
	// Start rmm9881: If required, replace tabs with spaces
	EXTfldval fval;
	fval.setChar(textPtr, pObjInfo->mOwnerData2);
	if (mDocumentObj->isRTF() && WPRtfClass::smReplaceTabsWithSpacesWhenAddingToPrintJob)
	{
		EXTfldval findStr, replaceStr;
		findStr.setChar(QTEXT("\t"), 1);
		replaceStr.setChar(WPRtfClass::smSpaces, WPRtfClass::smReplaceTabsWithSpacesWhenAddingToPrintJob);
		fval.replaceStr(findStr, replaceStr, qtrue);
	}
	// End rmm9881
	obj.mData = fval.getFldVal();
	// Start rmm9887: If necessary, reduce font size to make text fit on page
	qpripos pos = obj.mPos;
	PRIconvPos(pInfo->mJob, &pos, ePosPaper);
	if (pos.right > mDocumentObj->mPageInfo.mGlobalBounds.right)
	{
		obj.mPos.right = mDocumentObj->mPageInfo.mGlobalBounds.right;
		// We now have the correct width for the text object
		// Try to make the text fit
		qpridim width = obj.mPos.width();
		for (qint1 ptSize = ts.mFnt.size(); ptSize >= 6; --ptSize)
		{
			ts.mFnt.size(ptSize);
			if (PRItextWidth(pInfo->mJob, textPtr, pObjInfo->mOwnerData2, &ts) <= width)
			{
				obj.mTextSpec.mFnt.size(ptSize);
				break;
			}
		}
		obj.mHorzExtend = qfalse;
	}
	// End rmm9887

	qpridim top = obj.mPos.top;
	qprierr err = tqfWPObject::doPRIaddObject( pInfo->mJob, &obj );
	// Start rmm9881: Always adjust vertical offset if top has changed (this occurs when moving to a new page)
	if (!err)
	{
		if (top != obj.mPos.top) 
			pVertOff += qlrect::convfrom(obj.mPos.top - top, qtrue);
		// End rmm9881
		if (mTextInfo.isStrike())
		{
			obj.mType = PRI_OBJ_LINE;
			qprirect rect = obj.mPos;
			rect.top = (qlong)((double)((rect.top + rect.bottom) / 2.0));
			rect.bottom = rect.top;
			obj.mPos = rect;
			obj.mBorder.mLineStyle.setColor(obj.mTextSpec.mTextColor);
			err = tqfWPObject::doPRIaddObject(pInfo->mJob, &obj);
		}
	}
	return err;
}

// ###############################################################################
// ################# WPHorzRule Public ###########################################
// ###############################################################################


WPHorzRule::WPHorzRule( WPObjectClass* pParent, WPDocClass* pDocumentObj )
						:WPObjectClass( pParent, pDocumentObj )
{
}


WPHorzRule::~WPHorzRule()
{
}


WPHorzRule*	WPHorzRule::make( WPObjectClass* pParent, WPDocClass* pDocumentObj, WPHorzRuleInfoStruct* pHorzRuleInfo )
{
	WPHorzRule* obj = new WPHorzRule(pParent,pDocumentObj);
	obj->mHorzRuleInfo = *pHorzRuleInfo;
	WPHorzRuleInfoStruct& horzRuleInfo = obj->mHorzRuleInfo;
	if ( !horzRuleInfo.mSize )
		horzRuleInfo.mSize = horzRuleInfo.mNoShade ? 1 : 2;
	else if ( horzRuleInfo.mSize == 1 )
		horzRuleInfo.mNoShade = qtrue;
	return obj;
}


void WPHorzRule::initData( WPObjInfoStruct* pObjInfo ,printInfo* pInfo)
{
	mParent->newRow( pObjInfo );
	
	qlrect& ownerRect = pObjInfo->mOwnerRect;
	qlrect& rowRect = pObjInfo->mRowRect;
	ownerRect.width( rowRect.width() );
	ownerRect.height( WPARA_SPACING * 2 );
	if ( (mHorzRuleInfo.mSize+2) > ownerRect.height() ) ownerRect.height( mHorzRuleInfo.mSize+2 );
	mParent->addRowInfo( pObjInfo );
	
	mParent->newRow( pObjInfo );
}


void WPHorzRule::paint( WPObjInfoStruct* pObjInfo, WNDpaintStruct* pPaintStruct, qldim pHorzOff, qldim pVertOff )
{
	if ( !pObjInfo ) return;	// AE6315
	qlrect lr = pObjInfo->mOwnerRect;
	lr.offset( pHorzOff, pVertOff );
	if ( mHorzRuleInfo.mWidth < 0 )
		lr.width( lr.width() * (-mHorzRuleInfo.mWidth) / 100 );
	else if ( mHorzRuleInfo.mWidth > 0 )
		lr.width( mHorzRuleInfo.mWidth );
	
	lr.top += (lr.height() - mHorzRuleInfo.mSize) / 2;
	lr.height( mHorzRuleInfo.mSize );
	
	qrect r; lr.conv(&r);
	HDC dc = pPaintStruct->hdc;
	if ( mHorzRuleInfo.mNoShade )
	{
		GDIsetTextColor( dc, GDI_COLOR_QBLACK );
		GDIfillRect( dc, &r, GDIgetStockBrush( BLACK_BRUSH ) );
	}
	else
	{
		HPEN lpen = GDIcreatePen( 1, GDI_COLOR_3DLIGHT );
		HPEN dpen = GDIcreatePen( 1, GDI_COLOR_3DSHADOW );
		HPEN savedPen = GDIselectObject( dc, lpen );
		GDIselectObject( dc, dpen );
		GDImoveTo( dc, r.left, r.bottom );
		GDIlineTo( dc, r.left, r.top );
		GDIlineTo( dc, r.right, r.top );
		GDIselectObject( dc, lpen );
		GDIlineTo( dc, r.right, r.bottom );
		GDIlineTo( dc, r.left, r.bottom );
		GDIselectObject( dc, savedPen );
		GDIdeleteObject( lpen );
		GDIdeleteObject( dpen );
	}
}


qprierr WPHorzRule::addToPrintJob( printInfo* pInfo, EXTCompInfo* eci, WPObjInfoStruct* pObjInfo, // mpm4700
																 	qldim& pHorzOff, qldim& pVertOff )
{
	qlrect lr = pObjInfo->mOwnerRect;
	lr.offset( pHorzOff, pVertOff );
	if ( mHorzRuleInfo.mWidth < 0 )
		lr.width( lr.width() * (-mHorzRuleInfo.mWidth) / 100 );
	else if ( mHorzRuleInfo.mWidth > 0 )
		lr.width( mHorzRuleInfo.mWidth );
	
	lr.top += (lr.height() - mHorzRuleInfo.mSize) / 2;
	lr.height( mHorzRuleInfo.mSize );
	
	PRIobjectStruct objInfo = *pInfo->mObj;
	objInfo.mType = PRI_OBJ_BORDER;
	objInfo.mBorder = WNDborderStruct( WND_BORD_PLAIN, qpen( 1 ) );
	lr.convto( &objInfo.mPos );
	return tqfWPObject::doPRIaddObject( pInfo->mJob, &objInfo );
}
/* eof */










