Milán Major

netscape-revival

1 branch
Code

lib/mac/TX/CLineHeights.cp

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


#include "CLineHeights.h"


// ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ
//	CLineHeights.cp	
// ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ

#include "CLineHeights.h"


// ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ
//	¥	
// ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ

CLineHeights::CLineHeights()
{
	IArray(sizeof(TLineHeightGroup));

	fTotalHeight = 0;
	fLastLineIndex = -1;

	fNumer = fDenom = 1;
}

// ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ
//	¥	
// ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ

CLineHeights::~CLineHeights()
{
}

// ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ
//	¥	
// ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ
		
TLineHeightGroup* CLineHeights::LineToHeightGroup(long* lineNo, long* groupNo /*=nil*/) const
/*return the ptr in "this" to the group element containing the line "lineNo"
on output, lineNo is set to be the index of the line in its group
¥¥on input, assume lineNo is a valid line*/
{
	TLineHeightGroup* firstGroupPtr = (TLineHeightGroup*)(this->GetElementPtr(0));
	register TLineHeightGroup* groupPtr = firstGroupPtr;
	while (true)
		{
		Assert_(groupPtr-firstGroupPtr < this->CountElements());
		
		register long count = groupPtr->groupCountLines;
		
		if (count > *lineNo)
			{
			if (groupNo)
				*groupNo = groupPtr-firstGroupPtr;
			return groupPtr;
			}
		
		*lineNo -= count;
		++groupPtr;
		}
}

// ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ
//	¥	
// ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ

TLineHeightGroup* CLineHeights::PixelToHeightGroup(long* vPix, long* groupLineNo) const
//the out vPix is the pix offset to the group returned as the fn result
{
	*groupLineNo = 0;

	register long	maxGroupIndex = this->CountElements() - 1;
	register TLineHeightGroup* groupPtr = (TLineHeightGroup*)(this->GetElementPtr(0));
	register long remainPix = *vPix;
	long totalPix = remainPix;
	
	for (long groupIndex = 0; groupIndex <= maxGroupIndex; ++groupIndex, ++groupPtr) {
		long groupHeight = groupPtr->groupCountLines * groupPtr->lineHeight;
		
		if (groupHeight > remainPix) {
			*vPix = totalPix-remainPix;
			return groupPtr;
		}
		
		remainPix -= groupHeight;
		*groupLineNo += groupPtr->groupCountLines;
	}
	
	//vPix is >= last line pix start
	#ifdef txtnDebug
	SignalPStr_("\p PixelToHeightGroup : Will return nil");
	#endif
	return nil;
}
// ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ
//	¥	
// ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ

long CLineHeights::HeightToCountLines(const TLineHeightGroup& group, long groupLineNo
																				, long* height) const
//works on a height group scope
//groupLineNo is the index of the line in the the group "group"
//height is input/output and its measured starting from groupLineNo
//¥¥ should not disturb memory
{
	long linesRemain = group.groupCountLines-groupLineNo;
	
	Assert_(linesRemain > 0);
	
	register short lineHeight = group.lineHeight;
	
	long heightRemain = linesRemain * lineHeight;
	
	if (*height >= heightRemain) {
		*height -= heightRemain;
		return linesRemain;
	}
	else {
		long temp = LongRoundUp(*height, lineHeight);
		*height -= (temp*lineHeight);
		return temp;
	}
}
//************************************************************************************************

long CLineHeights::PixelToLine(long* vPix, long lineNo /*=0*/, TLineHeightGroup** heightGroupPtr /*= nil*/, long* groupLineIndex /*= nil*/) const
/*
-¥¥ doesn't disturb memory
-vPix is input/output, the out vPix is the pixOffset to the line returned as the fn result
-vPix is measured from the input "lineNo"
-if vPix is beyond the text height ==> the returned value is > fLastLineIndex
- if vPix is at exactly 2 lines boundary, the returned result is the higher line,
	 otherwise when called to draw lines starting from vPix the result will be inaccurate
	(will include unecessary line)
*/
{
	long index = lineNo;
	TLineHeightGroup* groupPtr = this->LineToHeightGroup(&index);
	
	long pixRemain = *vPix;
	long countGroupLines;
	if (!pixRemain) {countGroupLines = index;}
	else {
		--groupPtr;
		do {
			countGroupLines = this->HeightToCountLines(*(++groupPtr), index, &pixRemain);
			
			lineNo += countGroupLines;
			countGroupLines += index;
			index = 0;
		} while ((pixRemain > 0) && (lineNo <= fLastLineIndex));
		
		if (pixRemain < 0) {
			short lineHeight = groupPtr->lineHeight;
			*vPix -= (lineHeight+pixRemain);
			
			--countGroupLines;
			--lineNo;
		}
		else {
			if (pixRemain == 0) {
				if (countGroupLines == groupPtr->groupCountLines) { //vPix is at the boundary of 2 height groups
					countGroupLines = 0;
					++groupPtr;
				}
			}
			else {if (lineNo > fLastLineIndex) {*vPix -= pixRemain;} }
		}
	}
	
	if (heightGroupPtr) {
		*heightGroupPtr = groupPtr;
		*groupLineIndex = countGroupLines;
	}
	
	return lineNo;
}
// ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ
//	¥	
// ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ

long CLineHeights::GetTotalLinesHeight(void) const
{
	if (fNumer == fDenom)
		return fTotalHeight;
		
	return GetLineRangeHeight(0, fLastLineIndex);
}


Int32 CLineHeights::GetLineRangeHeight(long firstLine, long lastLine) const
//¥¥should not disturb memory
{
	Assert_(firstLine <= lastLine);
	
	if (fLastLineIndex < 0)
		return 0;
	
	if ((firstLine == 0) && (lastLine == fLastLineIndex))
		return fTotalHeight;
	
	Boolean oneLine = firstLine == lastLine;
	
	register TLineHeightGroup* lineGroup = this->LineToHeightGroup(&firstLine);
	
	short lineHeight = lineGroup->lineHeight;
	
	if (oneLine)
		return lineHeight;
	
	register TLineHeightGroup* lastLineGroup = this->LineToHeightGroup(&lastLine);
	
	if (lineGroup == lastLineGroup)
		return (lastLine-firstLine+1) * lineHeight;
	
	register long theHeight = (lineGroup->groupCountLines - firstLine) * lineHeight
										+ (lastLine+1) * lastLineGroup->lineHeight;

	while (++lineGroup < lastLineGroup) {
		theHeight += lineGroup->groupCountLines * lineGroup->lineHeight;
	}
	
	return theHeight;
}
// ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ
//	¥	
// ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ

void CLineHeights::GetLineHeightInfo(long lineNo, TLineHeightInfo* lineHeightInfo) const
{
	TLineHeightGroup* lineGroup = this->LineToHeightGroup(&lineNo);

		lineHeightInfo->lineHeight = lineGroup->lineHeight;
		lineHeightInfo->lineAscent = lineGroup->lineAscent;
}
// ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ
//	¥	
// ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ

Boolean CLineHeights::EqualGroup(long groupIndex, const TLineHeightGroup& group) const
//shouldn't disturb memory
{
	if ((groupIndex >= 0) && (groupIndex < this->CountElements())) {
		TLineHeightGroup* groupToCompare = (TLineHeightGroup*)(this->GetElementPtr(groupIndex));
		return (group.lineHeight == groupToCompare->lineHeight) && (group.lineAscent == groupToCompare->lineAscent);
	}
	else
		return false;
}
// ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ
//	¥	
// ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ

Boolean CLineHeights::EqualGroup(long group1Index, long group2Index) const
{
	if ((group2Index >= 0) && (group2Index < this->CountElements()))
		return this->EqualGroup(group1Index, *(TLineHeightGroup*) this->GetElementPtr(group2Index));
	else
		return false;
}
// ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ
//	¥	
// ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ

Boolean CLineHeights::Concat(long group1Index, long group2Index, const TLineHeightGroup* groupPtr/*=nil*/)
/*if groupPtr != nil concate *groupPtr with either group1Index or group2Index if possible
else concate group1Index or group2Index if possible
-shouldn't disturb memory*/
{
	if (groupPtr) {
		long concatIndex = group1Index;
		if (!this->EqualGroup(concatIndex, *groupPtr)) {
			concatIndex = group2Index;
			if (!this->EqualGroup(concatIndex, *groupPtr))
				return false;
		}
		
		((TLineHeightGroup*) this->GetElementPtr(concatIndex))->groupCountLines += groupPtr->groupCountLines;
		return true;
	}
	else {
		if (this->EqualGroup(group1Index, group2Index)) {
			((TLineHeightGroup*) this->GetElementPtr(group1Index))->groupCountLines +=
								((TLineHeightGroup*) this->GetElementPtr(group2Index))->groupCountLines;
			return true;
		}
		else
			return false;
	}
}
// ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ
//	¥	
// ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ

OSErr CLineHeights::SetLineHeightInfo(const TLineHeightInfo& lineHeightInfo, long lineNo)
{
	long groupIndex;
	TLineHeightGroup* lineGroup = this->LineToHeightGroup(&lineNo, &groupIndex);
	if ((lineGroup->lineHeight == lineHeightInfo.lineHeight) && (lineGroup->lineAscent == lineHeightInfo.lineAscent))
		{return noErr;}
	
	TLineHeightGroup newGroup;
	newGroup.groupCountLines = 1;
	newGroup.lineHeight = lineHeightInfo.lineHeight;
	newGroup.lineAscent = lineHeightInfo.lineAscent;
	
//	this->CalcScaledHeightInfo(&newGroup);
//	fTotalHeight += newGroup.scaledHeight - lineGroup->scaledHeight;
	fTotalHeight += newGroup.lineHeight - lineGroup->lineHeight;
	
	
	long oldGroupCountLines = lineGroup->groupCountLines;
	
	if (oldGroupCountLines == 1) {
		long groupBefore = groupIndex-1;
		long groupAfter = groupIndex+1;
		if (this->Concat(groupBefore, groupAfter, &newGroup)) {
			this->RemoveElements(groupIndex, this->Concat(groupBefore, groupAfter) ? 2 : 1);
		}
		else {*lineGroup = newGroup;}
		
		return noErr;
	}
	
	long insertIndex = groupIndex + (lineNo != 0);
	
	if ((lineNo == 0) || (lineNo == oldGroupCountLines-1)) {
		--(lineGroup->groupCountLines);
		if (this->Concat(insertIndex-1, insertIndex, &newGroup)) {return noErr;}
		else {return (this->InsertElements(1/*count*/, &newGroup, insertIndex) ? noErr : memFullErr);}
	}

	TLineHeightGroup oldGroup = *lineGroup;
	
	lineGroup->groupCountLines = lineNo;

	lineGroup = (TLineHeightGroup*)(this->InsertElements(2/*count*/, nil, insertIndex));
	
	if (lineGroup) {
		*lineGroup++ = newGroup;
		
		*lineGroup = oldGroup;
		lineGroup->groupCountLines = oldGroupCountLines-lineNo-1;
		
		return noErr;
	}
	else {return memFullErr;}
}
// ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ
//	¥	
// ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ

OSErr CLineHeights::InsertLine(const TLineHeightInfo& lineHeightInfo, long lineNo /*= -1*/)
{
	if (++fLastLineIndex == 0) {
		TLineHeightGroup* lineGroup = (TLineHeightGroup*) this->InsertElements(1/*count*/, nil, 0);
		if (lineGroup) {
			lineGroup->groupCountLines = 1;
			lineGroup->lineAscent = lineHeightInfo.lineAscent;
			lineGroup->lineHeight = lineHeightInfo.lineHeight;
			
//			this->CalcScaledHeightInfo(lineGroup);
//			fTotalHeight = lineGroup->scaledHeight;
			fTotalHeight = lineGroup->lineHeight;
						
			return noErr;
		}
		else
			return memFullErr;
	}
	

	if (lineNo < 0)
		lineNo = fLastLineIndex;
	
	long groupLineNo = lineNo - (lineNo == fLastLineIndex);
	TLineHeightGroup* lineGroup = this->LineToHeightGroup(&groupLineNo);
	
	++(lineGroup->groupCountLines);
	fTotalHeight += lineGroup->lineHeight;

	return CLineHeights::SetLineHeightInfo(lineHeightInfo, lineNo);
	
	/*it's required to be CLineHeights::SetLineHeightInfo and not "this->SetLineHeightInfo" since the call of
	SetLineHeightInfo here is an implementation dependent of the CLineHeights class and not a general 
	behaviour of all descendents*/
}
// ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ
//	¥	
// ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ

void CLineHeights::RemoveLines(long countLines, long lineNo)
{
	if (!countLines) {return;}
	
	if ((fLastLineIndex -= countLines) < 0)
		{
		this->SetElementsCount(0);
		fTotalHeight = 0;
		return;
		}
	
	long groupIndex;
	register TLineHeightGroup* lineGroup = this->LineToHeightGroup(&lineNo, &groupIndex);
	
	long groupLinesToRemove;
	if (lineNo)
		{
		groupLinesToRemove = MinLong(countLines, lineGroup->groupCountLines-lineNo);
		lineGroup->groupCountLines -= groupLinesToRemove;
		++groupIndex;
		}
	else
		groupLinesToRemove = 0;

	long groupsToRemove = 0;
	while (countLines)
		{
		if (groupLinesToRemove == 0)
			{
			if (countLines >= lineGroup->groupCountLines)
				{
				groupLinesToRemove = lineGroup->groupCountLines;
				++groupsToRemove;
				}
			else
				{
				groupLinesToRemove = countLines;
				lineGroup->groupCountLines -= countLines;
				}
			}
		
		countLines -= groupLinesToRemove;
		
		fTotalHeight -= groupLinesToRemove * lineGroup->lineHeight;
		
		++lineGroup;
		groupLinesToRemove = 0;
		}
	
	if (groupsToRemove)
		{
		if (this->Concat(groupIndex-1, groupIndex+groupsToRemove))
			++groupsToRemove;
		this->RemoveElements(groupIndex, groupsToRemove);
		}
}


Boolean CLineHeights::GetTotalLineRange(TOffsetPair& outLines) const
{
	outLines.firstOffset = 0;
	outLines.lastOffset = CountLines() - 1;

	return (outLines.lastOffset >= 0);
}

// ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ
//	¥	
// ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ