Beispiel #1
0
	void Polygon2f::Shrink(float distance, list<Polygon2f*> &parentPolygons, list<Polygon2f*> &polygons)
	{
		list<Polygon2f*> emptyPolygons;
		list<Polygon2f*> rootPolygons;
		DoShrink(distance, emptyPolygons, rootPolygons);

		if( distance > 0 )
		{
			for(list<Polygon2f*>::iterator pIt =containedSolids.begin(); pIt!=containedSolids.end(); pIt++)
			{
				(*pIt)->Shrink(distance, rootPolygons, emptyPolygons);
			}
			assert(emptyPolygons.size() == 0);

			for(list<Polygon2f*>::iterator pIt =containedHoles.begin(); pIt!=containedHoles.end(); pIt++)
			{
				(*pIt)->DoShrink(distance, rootPolygons, emptyPolygons);
			}
			assert(emptyPolygons.size() == 0);

			for(list<Polygon2f*>::iterator pIt =rootPolygons.begin(); pIt!=rootPolygons.end(); )
			{
				if( (*pIt)->TryPlaceInList(parentPolygons) )
				{
					pIt = rootPolygons.erase(pIt);
				}
				else
				{
					pIt++;
				}
			}

			for(list<Polygon2f*>::iterator pIt =rootPolygons.begin(); pIt!=rootPolygons.end(); pIt++)
			{
				polygons.push_back(*pIt);
			}
		}
		else
		{
			for(list<Polygon2f*>::iterator pIt =containedHoles.begin(); pIt!=containedHoles.end(); pIt++)
			{
				(*pIt)->DoShrink(distance, rootPolygons, emptyPolygons);
			}
			assert(emptyPolygons.size() == 0);

			for(list<Polygon2f*>::iterator pIt =containedSolids.begin(); pIt!=containedSolids.end(); pIt++)
			{
				(*pIt)->DoShrink(distance, rootPolygons, emptyPolygons);
			}
			assert(emptyPolygons.size() == 0);

			for(list<Polygon2f*>::iterator pIt =rootPolygons.begin(); pIt!=rootPolygons.end(); )
			{
				if( (*pIt)->TryPlaceInList(parentPolygons) )
				{
					pIt = rootPolygons.erase(pIt);
				}
				else
				{
					pIt++;
				}
			}

			for(list<Polygon2f*>::iterator pIt =rootPolygons.begin(); pIt!=rootPolygons.end(); pIt++)
			{
				(*pIt)->PlaceInList(polygons);
			}						
		}
	}
Beispiel #2
0
// Shrink lengths of [part1..part2] (including)
// They must not exceed `right` X coordinate
void CVConLine::DistributeParts(unsigned part1, unsigned part2, unsigned right)
{
	if ((part1 > part2) || (part2 >= PartsCount))
	{
		_ASSERTE((part1 <= part2) && (part2 < PartsCount));
		return;
	}

	if (!gpSet->isCompressLongStrings)
	{
		// Do not shrink, just crop
		CropParts(part1, part2, right);
		return;
	}


	// If possible - shrink only last part
	// TRF_SizeFree - Spaces or horizontal frames. It does not matter, how many *real* characters we have to write
	// TODO: However, this may shift cells and "columns" would be not aligned
	if ((TextParts[part2].Flags & TRF_SizeFree)
		&& ((TextParts[part2].PositionX + MIN_SIZEFREE_WIDTH) <= right)
		)
		part1 = part2;

	if (right <= TextParts[part1].PositionX)
	{
		_ASSERTE(right > TextParts[part1].PositionX);
		return;
	}


	unsigned ReqWidth = (right - TextParts[part1].PositionX);
	unsigned FullWidth = (TextParts[part2].PositionX + TextParts[part2].TotalWidth - TextParts[part1].PositionX);

	// 1) ...
	// 2) ...
	// 3) ...

	Shrinker shrinker;
	shrinker.init(TextParts, part1, part2, FontWidth);
	shrinker.eval_compression(TextParts, part1, part2, right - TextParts[part1].PositionX);

	// Leftmost char coord
	unsigned PosX = TextParts[part1].PositionX;
	for (unsigned k = part1; k <= part2; k++)
	{
		VConTextPart& part = TextParts[k];
		if (!part.Flags)
		{
			_ASSERTE(part.Flags); // Part must not be dropped yet!
			continue;
		}

		// Prepare loops
		TextCharType* pcf = part.CharFlags; // character flags (zero/free/normal/double)
		unsigned* pcw = part.CharWidth; // pointer to character width
		int ShrinkLeft = part.Length;
		unsigned NeedWidth = shrinker.data[k-part1].new_width;
		unsigned NewPartWidth = 0;
		for (unsigned c = 0; c < part.Length; c++, pcf++, pcw++)
		{
			DoShrink(*pcw, ShrinkLeft, NeedWidth, NewPartWidth);
		}
		part.TotalWidth = NewPartWidth;

		// Advance coord
		PosX += NewPartWidth;
	}

	// End of shrink (no more parts, no more methods)
	_ASSERTE(PosX <= right);
}
Beispiel #3
0
// Shrink lengths of [part1..part2] (including)
// They must not exceed `right` X coordinate
void CVConLine::DistributeParts(uint part1, uint part2, uint right)
{
	if ((part1 > part2) || (part2 >= PartsCount))
	{
		_ASSERTE((part1 <= part2) && (part2 < PartsCount));
		return;
	}

	// If possible - shrink only last part
	// TRF_SizeFree - Spaces or horizontal frames. It does not matter, how many *real* characters we may write
	if ((TextParts[part2].Flags & TRF_SizeFree)
		&& ((TextParts[part2].PositionX + MIN_SIZEFREE_WIDTH) < right)
		)
		part1 = part2;

	if (right <= TextParts[part1].PositionX)
	{
		_ASSERTE(right > TextParts[part1].PositionX);
		return;
	}

	const uint suggMul = 4, suggDiv = 5;
	uint FontWidth2 = (FontWidth * 2);
	uint FontWidth2m = (FontWidth2 * suggMul / suggDiv);
	uint ReqWidth = (right - TextParts[part1].PositionX);

	// unused?
	uint FullWidth = (TextParts[part2].PositionX + TextParts[part2].TotalWidth - TextParts[part1].PositionX);

	// 1) shrink only TCF_WidthFree chars
	// 2) also shrink TCF_WidthDouble (if exist) a little
	// 3) shrink all possibilities

	WARNING("Change the algorithm");
	// a) count all TCF_WidthFree, TCF_WidthNormal, TCF_WidthDouble separatedly
	// b) so we able to find most suitable way to shrink either part with its own factor (especially useful when both CJK and single-cell chars exists)

	VConTextPartWidth AllWidths[TCF_WidthLast] = {};

	// Count all widths for parts and check if we may do shrink with TCF_WidthFree chars only
	bool bHasFreeOverlaps = HasFreeOverlaps(part1, part2, right, AllWidths);

	uint nAllWidths = (AllWidths[TCF_WidthFree].Width + AllWidths[TCF_WidthNormal].Width + AllWidths[TCF_WidthDouble].Width);
	_ASSERTE(nAllWidths == FullWidth); // At the moment, they must match

	// What we may to shrink?
	if (nAllWidths <= ReqWidth)
	{
		if ((nAllWidths != ReqWidth) && !bHasFreeOverlaps)
		{
			DistributePartsFree(part1, part2, right);
		}
		else
		{
			_ASSERTE(FALSE && "Already fit, nothing to shrink");
		}
		return;
	}

	// Only spaces and horizontal frames
	if (!bHasFreeOverlaps
		&& ((AllWidths[TCF_WidthFree].MinWidth + AllWidths[TCF_WidthNormal].Width + AllWidths[TCF_WidthDouble].Width) <= ReqWidth)
		)
	{
		DistributePartsFree(part1, part2, right);
		return;
	}

	uint nAllMin = AllWidths[TCF_WidthFree].MinWidth + AllWidths[TCF_WidthNormal].MinWidth + AllWidths[TCF_WidthDouble].MinWidth;
	if (!nAllMin)
	{
		_ASSERTE(nAllMin!=NULL); // Must not be zero!
		return;
	}

	// method and options
	uint nShrinkParts = (1 << TCF_WidthFree);

	if ((AllWidths[TCF_WidthFree].MinWidth + AllWidths[TCF_WidthNormal].Width + AllWidths[TCF_WidthDouble].Width) <= ReqWidth)
	{
		AllWidths[TCF_WidthFree].ReqWidth = ReqWidth - (AllWidths[TCF_WidthNormal].Width + AllWidths[TCF_WidthDouble].Width);
	}
	else if ((AllWidths[TCF_WidthFree].MinWidth + AllWidths[TCF_WidthNormal].Width + AllWidths[TCF_WidthDouble].MinWidth) <= ReqWidth)
	{
		// Spaces and double-space glyphs
		// Actually, with monospaced fonts we would have fit problems,
		// when double-space glyphs takes only one cell in console.
		// That is non-DBCS systems or UTF-8(?) on DBCS system
		nShrinkParts |= (1 << TCF_WidthDouble);
		AllWidths[TCF_WidthFree].ReqWidth = AllWidths[TCF_WidthFree].MinWidth;
		AllWidths[TCF_WidthDouble].ReqWidth = ReqWidth - (AllWidths[TCF_WidthNormal].Width + AllWidths[TCF_WidthFree].ReqWidth);
	}
	else
	{
		// Shrink all types
		nShrinkParts |= (1 << TCF_WidthNormal) | (1 << TCF_WidthDouble);

		// And we may apply a larger coefficient to dominating type of chars

		// Count each double-space glyph as 2 cells (preferred)
		AllWidths[TCF_WidthDouble].Count *= 2;
		// Count "all" cells
		int nAllCells = AllWidths[TCF_WidthDouble].Count + AllWidths[TCF_WidthNormal].Count + AllWidths[TCF_WidthFree].Count;

		// Sort types by cells used
		uint nMost = TCF_WidthFree;
		if ((AllWidths[TCF_WidthDouble].Count >= AllWidths[TCF_WidthNormal].Count) && (AllWidths[TCF_WidthDouble].Count >= AllWidths[TCF_WidthFree].Count))
			nMost = TCF_WidthDouble;
		else if ((AllWidths[TCF_WidthNormal].Count >= AllWidths[TCF_WidthDouble].Count) && (AllWidths[TCF_WidthNormal].Count >= AllWidths[TCF_WidthFree].Count))
			nMost = TCF_WidthNormal;
		uint nOther1 = (nMost != TCF_WidthDouble) ? TCF_WidthDouble : TCF_WidthNormal;
		uint nFlags = (1 << nMost) | (1 << nOther1);
		uint nOther2 = (!(nFlags & (1 << TCF_WidthDouble))) ? TCF_WidthDouble
			: (!(nFlags & (1 << TCF_WidthNormal))) ? TCF_WidthNormal
			: TCF_WidthFree;
		if (AllWidths[nOther1].Count < AllWidths[nOther2].Count)
			klSwap(nOther1, nOther2);

		uint nMostMul = (nMost == TCF_WidthDouble) ? 9 : 10;
		uint nMostDiv = 10;

		// Apply denominators
		AllWidths[nMost].ReqWidth = ReqWidth * AllWidths[nMost].Count * nMostMul / (nAllCells * nMostDiv);
		_ASSERTE(AllWidths[nMost].ReqWidth <= ReqWidth);

		// And prepare lesser types
		if ((ReqWidth - AllWidths[nMost].ReqWidth) >= (AllWidths[nOther1].Width + AllWidths[nOther2].MinWidth))
		{
			AllWidths[nOther1].ReqWidth = AllWidths[nOther1].Width;
			AllWidths[nOther2].ReqWidth = ReqWidth - (AllWidths[nMost].ReqWidth + AllWidths[nOther1].ReqWidth);
		}
		else if (AllWidths[nOther1].Count > 0 && AllWidths[nOther2].Count > 0)
		{
			_ASSERTE(AllWidths[nMost].Count > 0);
			AllWidths[nOther1].ReqWidth = ReqWidth * AllWidths[nOther1].Count / nAllCells;
			AllWidths[nOther2].ReqWidth = ReqWidth - (AllWidths[nMost].ReqWidth + AllWidths[nOther1].ReqWidth);
		}
		else if (AllWidths[nOther1].Count > 0)
		{
			_ASSERTE(AllWidths[nMost].Count > 0 && AllWidths[nOther2].Count == 0);
			AllWidths[nOther1].ReqWidth = ReqWidth - (AllWidths[nMost].ReqWidth);
			_ASSERTE(AllWidths[nOther2].Width == 0);
			AllWidths[nOther2].ReqWidth = 0;
		}
		else
		{
			_ASSERTE(AllWidths[nMost].Count > 0 && AllWidths[nOther1].Count == 0 && AllWidths[nOther2].Count == 0);
			_ASSERTE(AllWidths[nOther1].Width == 0 && AllWidths[nOther2].Width == 0);
			AllWidths[nOther1].ReqWidth = AllWidths[nOther2].ReqWidth = 0;
		}
		// Return *char* count
		AllWidths[TCF_WidthDouble].Count /= 2;
	}

	// Debug validations
	_ASSERTE((int)AllWidths[TCF_WidthFree].ReqWidth >= 0);
	_ASSERTE((int)AllWidths[TCF_WidthNormal].ReqWidth >= 0);
	_ASSERTE((int)AllWidths[TCF_WidthDouble].ReqWidth >= 0);

	// *Process* the shrink

	// Leftmost char coord
	uint PosX = TextParts[part1].PositionX;

	for (uint k = part1; k <= part2; k++)
	{
		VConTextPart& part = TextParts[k];
		if (!part.Flags)
		{
			_ASSERTE(part.Flags); // Part must not be dropped yet!
			continue;
		}

		// Update new leftmost coord for this part
		part.PositionX = PosX;

		// Prepare loops
		TextCharType* pcf = part.CharFlags; // character flags (zero/free/normal/double)
		uint* pcw = part.CharWidth; // pointer to character width

		// Run part shrink
		part.TotalWidth = 0;
		if ((part.Flags & TRF_SizeFree) && (nShrinkParts & (1 << TCF_WidthFree)))
		{
			VConTextPartWidth& aw = AllWidths[TCF_WidthFree];
			int iShrinkLeft = part.Length;
			_ASSERTE(AllWidths[TCF_WidthFree].Count>0);
			uint partReqWidth = (AllWidths[TCF_WidthFree].Count > 0) ? (aw.ReqWidth / AllWidths[TCF_WidthFree].Count) : 0;
			for (uint c = 0; c < part.Length; c++, pcf++, pcw++)
			{
				_ASSERTE(*pcf == TCF_WidthFree);
				DoShrink(*pcw, iShrinkLeft, partReqWidth, part.TotalWidth);
			}
		}
		else
		{
			for (uint c = 0; c < part.Length; c++, pcf++, pcw++)
			{
				if (nShrinkParts & (1 << *pcf))
				{
					VConTextPartWidth& aw = AllWidths[*pcf];
					DoShrink(*pcw, aw.Count, aw.ReqWidth, part.TotalWidth);
				}
				else
				{
					part.TotalWidth += *pcw;
				}
			}
		}

		PosX += part.TotalWidth;
	}

	// End of shrink (no more parts, no more methods)
	_ASSERTE(PosX <= right);
}