Milán Major

netscape-revival

1 branch
Code

lib/mac/TX/QDTextRun.cp

// ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ
//	
// ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ

#include "TextensionCommon.h"
#include "QDTextRun.h"


//***************************************************************************************************


//***************************************************************************************************

CQDTextRun::CQDTextRun()
{
}
//***************************************************************************************************

void CQDTextRun::IQDTextRun()
{
	this->IRunObject();
}
//***************************************************************************************************

CAttrObject* CQDTextRun::CreateNew() const
{
	CQDTextRun* newText = new CQDTextRun;
	if (newText)
		newText->IQDTextRun();
	
	return newText;
}
//***************************************************************************************************


void CQDTextRun::GetAttributes(CObjAttributes* attributes) const
{
	CRunObject::GetAttributes(attributes);
	
	attributes->Add(kFontAttr);
	attributes->Add(kFontSizeAttr);
	attributes->Add(kFaceAttr);
	attributes->Add(kForeColorAttr);
}
//***************************************************************************************************

ClassId CQDTextRun::GetClassId() const
{
	return kQDTextRunClassId;
}
//***************************************************************************************************

Boolean CQDTextRun::IsTextRun() const
{
	return true;
}
//***************************************************************************************************

char CQDTextRun::GetRunDir() const
//Assumed to not disturb memory (see Line.cp)
{
	return fDirection;
}
//***************************************************************************************************

Boolean CQDTextRun::Is2Bytes() const
{
	return f2Bytes;
}
//***************************************************************************************************

char CQDTextRun::GetRunScript() const
{
	return (this->IsAttributeON(kFontAttr)) ? fScript : smUninterp;
}
//***************************************************************************************************

void CQDTextRun::AttributeToBuffer(AttrId theAttr, void* attrBuffer) const //override
{
	switch (theAttr) {
		case kFontAttr:
			*(short*)attrBuffer = fFont;
			break;
			
		case kFontSizeAttr:
			*(short*)attrBuffer = fFontSize;
			break;
			
		case kFaceAttr:
			*(long*)attrBuffer = fFace;
			break;
			
		case kForeColorAttr:
			*(RGBColor*)attrBuffer = fForeColor;
			break;
		
		default:
			CRunObject::AttributeToBuffer(theAttr, attrBuffer);
	}
}
//***************************************************************************************************

void CQDTextRun::BufferToAttribute(AttrId theAttr, const void* attrBuffer)
{
	switch (theAttr) {
		case kFontAttr:
			fFont = *(short*)attrBuffer;
			fScript = MonoFontToScript(*(short*)attrBuffer);
			
			if (g2Directions)
				fDirection = (IsScriptR2L(fScript)) ? kRL : kLR;
			else
				fDirection = kLR;
			
			f2Bytes = (g2Bytes) ? IsScript2Bytes(fScript) : false;
			break;
			
		case kFontSizeAttr:
			fFontSize = *(short*)attrBuffer;
			break;
			
		case kFaceAttr:
			fFace = *(long*)attrBuffer;
			break;

		case kForeColorAttr:
			fForeColor = *(RGBColor*)attrBuffer;
			break;
		
		default:
			CRunObject::BufferToAttribute(theAttr, attrBuffer);
	}
}
//***************************************************************************************************


void CQDTextRun::SetDefaults(long message /*= 0*/)
{
	CRunObject::SetDefaults(message);
	
	short defFont, defSize;
	long fond_size = GetScriptVariable(short(message), smScriptPrefFondSize);
	defFont = short(fond_size >> 16); //hi word
	defSize = short(fond_size); //lo word
	
	this->SetAttributeValue(kFontAttr, &defFont);
	this->SetAttributeValue(kFontSizeAttr, &defSize);  

	if ((message & kUpdateOnlyScriptInfo) == 0) {
		long defFace = 0;
		this->SetAttributeValue(kFaceAttr, &defFace);  
	
		RGBColor foreColor;
		foreColor.red = 0;
		foreColor.green = 0;
		foreColor.blue = 0;
		this->SetAttributeValue(kForeColorAttr, &foreColor);
	}
}
//***************************************************************************************************

void CQDTextRun::AddFace(long faceToAdd, long* destFace)
/*normally the result is (faceToAdd | destFace), but this methode is the place to check for exclusif faces
(eg superScript, subScript)
*/
{
	*destFace |= faceToAdd;

	if ((*destFace & extend) && (*destFace & condense))
		this->RemoveFace((faceToAdd & extend) ? condense : extend, destFace);
}
//***************************************************************************************************

void CQDTextRun::RemoveFace(long faceToRemove, long *destFace) const
{
	*destFace &= (~faceToRemove);
}
//***************************************************************************************************

void CQDTextRun::UpdateAttribute(AttrId theAttr, const void* srcAttr, long updateMessage
															, const void* continuousAttr /*= nil*/)
/*
if the scripts are not the same, the font and script are copied from srcObj only if
forceScriptModif flag is true in srcObj.
*/
{
	Boolean pass = true;
	
	switch (theAttr) {
		case kFontAttr:
			if ((!(updateMessage & kForceScriptModif))
				&& (fScript != MonoFontToScript(*(short*)srcAttr)))
				pass = false;
			break;
			
		case kFontSizeAttr:
			if (updateMessage & kAddSize) {
				short newSize = fFontSize + *(short*)srcAttr;
				if (newSize < 1)
					newSize = 1;
					
				this->SetAttributeValue(kFontSizeAttr, &newSize);
				
				pass = false;
			}
			break;
		
		case kFaceAttr :
			long newFace = fFace;
			
			long srcFace = *(long*)srcAttr;
			
			if (updateMessage & kAddFace) {
				this->AddFace(srcFace, &newFace);
				pass = false;
			}
			else {
				if (updateMessage & kRemoveFace) {
					this->RemoveFace(srcFace, &newFace);
					pass = false;
				}
				else {
					if ((updateMessage & kToggleFace) && (srcFace) && (fFace)) {
						if (continuousAttr && (*(long*)continuousAttr & srcFace))
							this->RemoveFace(srcFace, &newFace);
						else
							this->AddFace(srcFace, &newFace);
							
						pass = false;
					}
				}
			}
							
			if (!pass)
				this->SetAttributeValue(kFaceAttr, &newFace);
			break;
		
		//default :pass
	}
	
	if (pass)
		CRunObject::UpdateAttribute(theAttr, srcAttr, updateMessage, continuousAttr);
}
//***************************************************************************************************

Boolean EqualRGB(const RGBColor& rgb1, const RGBColor& rgb2);
Boolean EqualRGB(const RGBColor& rgb1, const RGBColor& rgb2)
{
	return (rgb1.red == rgb2.red) && (rgb1.green == rgb2.green) && (rgb1.blue == rgb2.blue);
}
//***************************************************************************************************

Boolean CQDTextRun::EqualAttribute(AttrId theAttr, const void* valToCheck) const
{
	switch (theAttr) {
		case kFontAttr:
			return (fFont == *(short*)valToCheck);
			
		case kFontSizeAttr:
			return (fFontSize == *(short*)valToCheck);
			
		case kFaceAttr:
			return (fFace == *(long*)valToCheck);
			
		case kForeColorAttr:
			return EqualRGB(fForeColor, *(RGBColor*)valToCheck);
			
		default:
			return CRunObject::EqualAttribute(theAttr, valToCheck);
	}
}
//************************************************************************************************

Boolean CQDTextRun::SetCommonAttribute(AttrId theAttr, const void* valToCheck)
{
	if (theAttr == kFaceAttr) {
		long faceToCheck = *(long*)valToCheck;
		
		if ((fFace == 0) && (faceToCheck == 0))
			{return true;}
		
		long theCommonFace = fFace & faceToCheck;
		if (theCommonFace) {
			fFace = theCommonFace;
			return true;
		}
		else
			return false;
	}
	else
		return CRunObject::SetCommonAttribute(theAttr, valToCheck);
}
//***************************************************************************************************

long CQDTextRun::GetAttributeFlags(AttrId theAttr) const
{
	long flags = 0;
	
	if ((theAttr == kFontAttr) || (theAttr == kFontSizeAttr) || (theAttr == kFaceAttr))
		flags = kReformat | kVReformat;
	
	return flags | CRunObject::GetAttributeFlags(theAttr);
}
//*************************************************************************************************

void CQDTextRun::CalcHeightInfo(short* ascent, short* descent, short* leading)
//assume the obj env is saved
{
	Assert_(qd.thePort->txFont == fFont);
	Assert_(qd.thePort->txSize == fFontSize);
	Assert_(qd.thePort->txFace == Style(fFace));
	
	Assert_(this->IsAttributeON(kFontAttr) && this->IsAttributeON(kFontSizeAttr) && this->IsAttributeON(kFaceAttr));
	
	FontInfo	theFontInfo;
	GetFontInfo(&theFontInfo);

	*ascent = theFontInfo.ascent;
	*descent = theFontInfo.descent;
	*leading = theFontInfo.leading;
}
//***************************************************************************************************

void CQDTextRun::SetKeyScript() const
{
	if (gHasManyScripts && this->IsAttributeON(kFontAttr))
		MyKeyScript(fScript);
}
//***************************************************************************************************

void CQDTextRun::SetRunEnv() const
{
	CRunObject::SetRunEnv();

	TextFont(fFont);
	TextSize(fFontSize);
	TextFace(Style(fFace));

	if (IsColorPort()) {
		RGBColor temp = fForeColor;
		RGBForeColor(&temp);
	}
	
	::SetSysDirection(fDirection);
	/*needed in PixelToChar, CharToPixel, Draw, LineBreak, made here for descendents to
	be able to override those members without worring about sysjust. See comments in those members
	for more informations on why sysjust is needed to be set.
	We will not save the direction in "SaveRunEnv", we assume that this is done at higher level
	(CSTyledText::SetTextEnv and RestoreTextEnv)
	*/
}
//***************************************************************************************************

void CQDTextRun::SaveRunEnv()
{
	CRunObject::SaveRunEnv();
	
	GrafPtr currPort = qd.thePort;
	fFont = currPort->txFont;
	fFontSize = currPort->txSize;
	fFace = currPort->txFace;

	if (IsColorPort())
		{GetForeColor(&fForeColor);}
}
//***************************************************************************************************

Boolean CQDTextRun::FilterControlChar(unsigned char theChar) const
{
	Assert_(IsCtrlChar(theChar));
	
	if ((theChar == kBackSpaceCharCode) || (theChar == kClearCharCode) || (theChar == kCRCharCode)
		|| (theChar == kTabCharCode)
		|| ((theChar >= kRLArrowCharCode) && (theChar <= kDownArrowCharCode))) {return false;}
		
	return true;
}
//***************************************************************************************************

void CQDTextRun::PixelToChar(const LineRunDisplayInfo& displayInfo, Fixed pixel, TOffsetRange* charRange)
/*assume SetSysJust is called with the run dir (SetRunEnv).
PixelToChar depends on the SysJust (!) in a strange way : For Instance if passed "An English text"
as text with pix = 0 ==>if SysJust == -1 PixelToChar returns the offset to the end of text??
Similarly if passed "cibarA" which is in arabic with pix == 0 and sysJust == 0 ==> returns 0
*/
{
	if (pixel <= 0)
		pixel = LongToFixed(1); //work around bug ais SSNPixel2Char
	
	short result;
	Boolean leadingEdge;
	
	Point numer = displayInfo.zoomNumer;
	Point denom = displayInfo.zoomDenom;
	this->AdjustScaleVals(&numer, &denom);
	
	Fixed widthRemain;
	result = ::PixelToChar(Ptr(displayInfo.runChars), displayInfo.runLen, displayInfo.runExtraWidth, pixel
										, &leadingEdge, &widthRemain, smOnlyStyleRun, numer, denom);
										
	Boolean trailEdge;
	if (!result)
		trailEdge = false;
	else {
		if (result == displayInfo.runLen)
			trailEdge = true;
		else
			trailEdge = !leadingEdge;
	}
	
	charRange->Set(result, result, trailEdge, trailEdge);
}
//***************************************************************************************************

Fixed CQDTextRun::CharToPixel(const LineRunDisplayInfo& displayInfo, short charOffset)
{
	short result;
	
	Point numer = displayInfo.zoomNumer;
	Point denom = displayInfo.zoomDenom;
	this->AdjustScaleVals(&numer, &denom);
	
	result = ::CharToPixel(Ptr(displayInfo.runChars), displayInfo.runLen, displayInfo.runExtraWidth, charOffset, fDirection
									, smOnlyStyleRun, numer, denom);
									
	return LongToFixed(result);
}
//***************************************************************************************************

void CQDTextRun::Draw(const LineRunDisplayInfo& displayInfo, Fixed /*runLeftEdge*/
														, const Rect& /*lineRect*/, short /*lineAscent*/)
{
	Point numer = displayInfo.zoomNumer;
	Point denom = displayInfo.zoomDenom;
	this->AdjustScaleVals(&numer, &denom);
	
	::DrawJustified(Ptr(displayInfo.runChars), displayInfo.runLen, displayInfo.runExtraWidth
						, smOnlyStyleRun, numer, denom);
}
//***************************************************************************************************

#ifdef txtnRulers
Fixed CQDTextRun::FullJustifPortion(const LineRunDisplayInfo& displayInfo)
{
	Point numer = displayInfo.zoomNumer;
	Point denom = displayInfo.zoomDenom;
	this->AdjustScaleVals(&numer, &denom);
	
	return NPortionText(Ptr(displayInfo.runChars), displayInfo.runLen
										, smOnlyStyleRun, numer, denom);
}
//***************************************************************************************************
#endif

#ifdef powerc
#pragma options align=mac68k


struct QuickDrawGlobals {
	short						QDSpareD;
	short						QDSpareC;
	short						QDSpareB;
	short						QDSpareA;
	short						QDSpare9;
	short						QDSpare8;
	Fixed						qdChExtra;
	Fixed						qdRunSlop;
	short						pnLocFixed;
	long						playIndex;
	FMOutput					*fontPtr;
	Fixed						fontAdj;
	Point						patAlign;
	short						polyMax;
	PolyHandle					thePoly;
	short						QDSpare0;
	PicHandle					playPic;
	unsigned short		rgnMax;
	unsigned short		rgnIndex;
	short						**rgnBuf;
	unsigned short		wideRgnSize;
	Rect						wideRgnBBox;
	RgnPtr						wideMaster;
	RgnHandle					wideOpen;
	long						randSeed;
	BitMap						screenBits;
	Cursor						arrow;
	Pattern						dkGray;
	Pattern						ltGray;
	Pattern						gray;
	Pattern						black;
	Pattern						white;
	GrafPtr						thePort;
};
typedef struct QuickDrawGlobals QuickDrawGlobals;
#pragma options align=reset



#define GetStdTxMeasResult() (((QuickDrawGlobals*)&qd)->fontAdj)
#else
Fixed GetStdTxMeasResult() = {0x2055, 0x90FC, 0x00AC, 0x2010};
// MOVEA.L (A5),A0  --  SUBA.W  #$00AC,A0  --   MOVE.L (A0),D0
#endif
//***************************************************************************************************

Fixed StdTxFixedMeas(short byteCount,const void *textAddr, Point numer, Point denom)
{
	FontInfo notUsedInfo;
	StdTxMeas(byteCount, textAddr, &numer, &denom, &notUsedInfo);

	return FixScaleVal((Fixed)GetStdTxMeasResult(), numer.h, denom.h);
}
//***************************************************************************************************

Fixed CQDTextRun::MeasureWidth(const LineRunDisplayInfo& runDisplayInfo)
{
	Point numer = runDisplayInfo.zoomNumer;
	Point denom = runDisplayInfo.zoomDenom;
	this->AdjustScaleVals(&numer, &denom);
	
	return StdTxFixedMeas(runDisplayInfo.runLen, runDisplayInfo.runChars
											, numer, denom);
}
//***************************************************************************************************

#ifndef powerc
extern pascal StyledLineBreakCode NTextensionStyledLineBreak(unsigned char* textPtr
																						, long textLen, long textStart
																						, long textEnd, long flags
																						, Fixed* textWidth, long* textOffset
																						, Point numer, Point denom);
#endif
//***************************************************************************************************


StyledLineBreakCode CQDTextRun::LineBreak(unsigned char* scriptRunChars, long scriptRunLen, long runOffset
																				, Fixed* widthAvail, Boolean forceBreak, long* breakLen)
/*
StyledLineBreak(Ptr textPtr,long textLen,long textStart,
								long textEnd,long flags,Fixed *textWidth,long *textOffset)
¥	on input if the parameter "textOffset" != 0 ==> "textPtr" points to the start of the line to
	be broken or to the start of a script run, if 0 ==> "textPtr" points to a char inside this line.
	in the former case the result may be smCharBreak if the line contains only 1 word, in the 2nd case
	the result is never smCharBreak and in the case of 1 word textOffset will be = textStart with result
	smBreakWord.
	===> textOffset should be 0 <==> textPtr points to a script boundary.

StyledLineBreak include the extra spaces (spaces that expand out of the width of the line)
only if the dir of the spaces is the same as the SysJust i.e remove A0 if sysjust -1 and $20 if
sysJust 0. for this reason SetSysJust with the dir of the run to break is done in "BreakLine" and then
formatting is independent of the direction of the text and of SysJust, and we don't need to reformat
when Direction or SysJust change (SetSysJust is called in SetRunEnv).
*/
{
	StyledLineBreakCode result;

	long breakOffset = (forceBreak) ? 1 : 0;
	
#ifdef powerc
	
	result = StyledLineBreak((Ptr)scriptRunChars, scriptRunLen
												,	runOffset, scriptRunLen
												, 0/*flags*/, widthAvail, &breakOffset);
#else
	
	Point numer, denom;
	numer.h = 1;
	numer.v = numer.h;
	denom = numer;
	
	this->AdjustScaleVals(&numer, &denom);
	
	result = NTextensionStyledLineBreak(scriptRunChars, scriptRunLen
									,	runOffset, scriptRunLen
									, 0/*flags*/, widthAvail, &breakOffset
									, numer, denom);
#endif //powerc
	
	*breakLen = breakOffset - runOffset;

	return result;
}
//***************************************************************************************************

void CQDTextRun::SetCursor(Point, const RunPositionInfo&) const
{
	SetCursorIBeam();

/*
	if (fFace & italic) {
		short italicCursor[] = {0x2A4A, 0x2444, 0x584F, 0x6100, 0xF0DE, 0x7000, 0x7200, 0x101D
														, 0x4EF4, 0x0521, 0x0018, 0x0640, 0x0100, 0x0640, 0x0100, 0x41FA
														, 0x0008, 0x42A7, 0x6000, 0xEE22, 0x2A4A, 0x2444, 0x251F, 0x60D6
														, 0x0014, 0x2D4A, 0x0006, 0x0016, 0x0046, 0x006A, 0x009A, 0x0136
														, 0x01DC, 0x06D8};
		::SetCursor((Cursor*)&italicCursor[0]);
	}
	else {
		SetCursorIBeam();
	}
*/
}
//***************************************************************************************************