graphicsdeviceinterface/bitgdi/sbit/POLYGON.CPP
changeset 0 5d03bc08d59c
equal deleted inserted replaced
-1:000000000000 0:5d03bc08d59c
       
     1 // Copyright (c) 1997-2009 Nokia Corporation and/or its subsidiary(-ies).
       
     2 // All rights reserved.
       
     3 // This component and the accompanying materials are made available
       
     4 // under the terms of "Eclipse Public License v1.0"
       
     5 // which accompanies this distribution, and is available
       
     6 // at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     7 //
       
     8 // Initial Contributors:
       
     9 // Nokia Corporation - initial contribution.
       
    10 //
       
    11 // Contributors:
       
    12 //
       
    13 // Description:
       
    14 //
       
    15 
       
    16 #include <bitstd.h>
       
    17 #include "BITPANIC.H"
       
    18 
       
    19 // TCompareEdgesUpperY
       
    20 
       
    21 NONSHARABLE_CLASS(TCompareEdgesUpperY) : public TKey
       
    22 	{
       
    23 public:
       
    24 	TCompareEdgesUpperY(const CPolygonFiller::SFastData& aFastData);
       
    25 private:
       
    26 	virtual TInt Compare(TInt aLeft,TInt aRight) const;
       
    27 private:
       
    28 	const CPolygonFiller::SFastData& iFastData;
       
    29 	};
       
    30 
       
    31 TCompareEdgesUpperY::TCompareEdgesUpperY(const CPolygonFiller::SFastData& aFastData):
       
    32 	iFastData(aFastData)
       
    33 	{
       
    34 	}
       
    35 
       
    36 TInt TCompareEdgesUpperY::Compare(TInt aLeft,TInt aRight) const
       
    37 	{
       
    38 	const TInt leftUpperY=iFastData.vertexList[iFastData.edgeList[aLeft].upperVertex].iY;
       
    39 	const TInt rightUpperY=iFastData.vertexList[iFastData.edgeList[aRight].upperVertex].iY;
       
    40 	if (leftUpperY<rightUpperY)
       
    41 		return -1;
       
    42 	if (leftUpperY>rightUpperY)
       
    43 		return 1;
       
    44 	return 0;
       
    45 	}
       
    46 
       
    47 // TSwapEdges
       
    48 
       
    49 NONSHARABLE_CLASS(TSwapEdges) : public TSwap
       
    50 	{
       
    51 public:
       
    52 	TSwapEdges(CPolygonFiller::SFastData& aFastData);
       
    53 private:
       
    54 	virtual void Swap(TInt aLeft,TInt aRight) const;
       
    55 private:
       
    56 	CPolygonFiller::SFastData& iFastData;
       
    57 	};
       
    58 
       
    59 TSwapEdges::TSwapEdges(CPolygonFiller::SFastData& aFastData):
       
    60 	iFastData(aFastData)
       
    61 	{
       
    62 	}
       
    63 
       
    64 void TSwapEdges::Swap(TInt aLeft,TInt aRight) const
       
    65 	{
       
    66 	CPolygonFiller::SFastEdge& leftEdge=iFastData.edgeList[aLeft];
       
    67 	CPolygonFiller::SFastEdge& rightEdge=iFastData.edgeList[aRight];
       
    68 
       
    69 	const CPolygonFiller::SFastEdge temp(leftEdge);
       
    70 	leftEdge=rightEdge;
       
    71 	rightEdge=temp;
       
    72 	}
       
    73 
       
    74 // TCompareActiveEdgesFirstVertex
       
    75 
       
    76 NONSHARABLE_CLASS(TCompareActiveEdgesFirstVertex) : public TKey
       
    77 	{
       
    78 public:
       
    79 	TCompareActiveEdgesFirstVertex(const CPolygonFiller::SFastData& aFastData);
       
    80 private:
       
    81 	virtual TInt Compare(TInt aLeft,TInt aRight) const;
       
    82 private:
       
    83 	const CPolygonFiller::SFastData& iFastData;
       
    84 	};
       
    85 
       
    86 TCompareActiveEdgesFirstVertex::TCompareActiveEdgesFirstVertex(const CPolygonFiller::SFastData& aFastData):
       
    87 	iFastData(aFastData)
       
    88 	{
       
    89 	}
       
    90 
       
    91 TInt TCompareActiveEdgesFirstVertex::Compare(TInt aLeft,TInt aRight) const
       
    92 	{
       
    93 	const TInt leftFirstVertex=iFastData.activeEdgeList[aLeft].edgePtr->firstVertex;
       
    94 	const TInt rightFirstVertex=iFastData.activeEdgeList[aRight].edgePtr->firstVertex;
       
    95 	if (leftFirstVertex<rightFirstVertex)
       
    96 		return -1;
       
    97 	if (leftFirstVertex>rightFirstVertex)
       
    98 		return 1;
       
    99 	return 0;
       
   100 	}
       
   101 
       
   102 // TSwapActiveEdges
       
   103 
       
   104 NONSHARABLE_CLASS(TSwapActiveEdges) : public TSwap
       
   105 	{
       
   106 public:
       
   107 	TSwapActiveEdges(CPolygonFiller::SFastData& aFastData);
       
   108 private:
       
   109 	virtual void Swap(TInt aLeft,TInt aRight) const;
       
   110 private:
       
   111 	CPolygonFiller::SFastData& iFastData;
       
   112 	};
       
   113 
       
   114 TSwapActiveEdges::TSwapActiveEdges(CPolygonFiller::SFastData& aFastData):
       
   115 	iFastData(aFastData)
       
   116 	{
       
   117 	}
       
   118 
       
   119 void TSwapActiveEdges::Swap(TInt aLeft,TInt aRight) const
       
   120 	{
       
   121 	CPolygonFiller::SFastActiveEdge& leftActiveEdge=iFastData.activeEdgeList[aLeft];
       
   122 	CPolygonFiller::SFastActiveEdge& rightActiveEdge=iFastData.activeEdgeList[aRight];
       
   123 
       
   124 	const CPolygonFiller::SFastActiveEdge temp(leftActiveEdge);
       
   125 	leftActiveEdge=rightActiveEdge;
       
   126 	rightActiveEdge=temp;
       
   127 
       
   128 	if (leftActiveEdge.scanLineIntersectionPtr!=NULL)
       
   129 		leftActiveEdge.scanLineIntersectionPtr->activeEdgePtr=&leftActiveEdge;
       
   130 	if (rightActiveEdge.scanLineIntersectionPtr!=NULL)
       
   131 		rightActiveEdge.scanLineIntersectionPtr->activeEdgePtr=&rightActiveEdge;
       
   132 	}
       
   133 
       
   134 // TCompareScanLineIntersectionsFirstPixel
       
   135 
       
   136 NONSHARABLE_CLASS(TCompareScanLineIntersectionsFirstPixel) : public TKey
       
   137 	{
       
   138 public:
       
   139 	TCompareScanLineIntersectionsFirstPixel(const CPolygonFiller::SFastData& aFastData);
       
   140 private:
       
   141 	virtual TInt Compare(TInt aLeft,TInt aRight) const;
       
   142 private:
       
   143 	const CPolygonFiller::SFastData& iFastData;
       
   144 	};
       
   145 
       
   146 TCompareScanLineIntersectionsFirstPixel::TCompareScanLineIntersectionsFirstPixel(const CPolygonFiller::SFastData& aFastData):
       
   147 	iFastData(aFastData)
       
   148 	{
       
   149 	}
       
   150 
       
   151 TInt TCompareScanLineIntersectionsFirstPixel::Compare(TInt aLeft,TInt aRight) const
       
   152 	{
       
   153 	const TInt leftFirstPixel=iFastData.scanLineIntersectionList[aLeft].firstPixel;
       
   154 	const TInt rightFirstPixel=iFastData.scanLineIntersectionList[aRight].firstPixel;
       
   155 	if (leftFirstPixel<rightFirstPixel)
       
   156 		return -1;
       
   157 	if (leftFirstPixel>rightFirstPixel)
       
   158 		return 1;
       
   159 	return 0;
       
   160 	}
       
   161 
       
   162 // TSwapScanLineIntersections
       
   163 
       
   164 NONSHARABLE_CLASS(TSwapScanLineIntersections) : public TSwap
       
   165 	{
       
   166 public:
       
   167 	TSwapScanLineIntersections(CPolygonFiller::SFastData& aFastData);
       
   168 private:
       
   169 	virtual void Swap(TInt aLeft,TInt aRight) const;
       
   170 private:
       
   171 	CPolygonFiller::SFastData& iFastData;
       
   172 	};
       
   173 
       
   174 TSwapScanLineIntersections::TSwapScanLineIntersections(CPolygonFiller::SFastData& aFastData):
       
   175 	iFastData(aFastData)
       
   176 	{
       
   177 	}
       
   178 
       
   179 void TSwapScanLineIntersections::Swap(TInt aLeft,TInt aRight) const
       
   180 	{
       
   181 	CPolygonFiller::SFastScanLineIntersection& leftScanLineIntersection=iFastData.scanLineIntersectionList[aLeft];
       
   182 	CPolygonFiller::SFastScanLineIntersection& rightScanLineIntersection=iFastData.scanLineIntersectionList[aRight];
       
   183 
       
   184 	const CPolygonFiller::SFastScanLineIntersection temp(leftScanLineIntersection);
       
   185 	leftScanLineIntersection=rightScanLineIntersection;
       
   186 	rightScanLineIntersection=temp;
       
   187 
       
   188 	leftScanLineIntersection.activeEdgePtr->scanLineIntersectionPtr=&leftScanLineIntersection;
       
   189 	rightScanLineIntersection.activeEdgePtr->scanLineIntersectionPtr=&rightScanLineIntersection;
       
   190 	}
       
   191 
       
   192 // the sorting function
       
   193 
       
   194 LOCAL_C void Sort(TInt aCount,const TKey& aKey,const TSwap& aSwap)
       
   195 	{
       
   196 #if 1 // quick sort
       
   197 	const TInt error=User::QuickSort(aCount,aKey,aSwap);
       
   198 	BG_ASSERT_ALWAYS_INVARIANT(error==KErrNone);
       
   199 #elif 0 // bubble sort
       
   200 	for (TInt i=1; i<aCount; ++i)
       
   201 		{
       
   202 		for (TInt j=i; j>0; --j)
       
   203 			{
       
   204 			if (aKey.Compare(j-1,j)>0)
       
   205 				{
       
   206 				aSwap.Swap(j-1,j);
       
   207 				}
       
   208 			}
       
   209 		}
       
   210 #else // heap sort
       
   211 	TInt startOfSortedPortion=aCount;
       
   212 	if (startOfSortedPortion>1)
       
   213 		{
       
   214 		TInt startOfHeap=startOfSortedPortion>>1;
       
   215 		FOREVER
       
   216 			{
       
   217 			BG_ASSERT_DEBUG_INVARIANT(startOfHeap>=0);
       
   218 			if (startOfHeap!=0)
       
   219 				{
       
   220 				--startOfHeap;
       
   221 				}
       
   222 			else
       
   223 				{
       
   224 				--startOfSortedPortion;
       
   225 				aSwap.Swap(startOfSortedPortion,0);
       
   226 				BG_ASSERT_DEBUG_INVARIANT(startOfSortedPortion>=1);
       
   227 				if (startOfSortedPortion==1)
       
   228 					{
       
   229 					break;
       
   230 					}
       
   231 				}
       
   232 			// put aArray[startOfHeap] into the correct place in the heap
       
   233 			TInt i=startOfHeap;
       
   234 			FOREVER
       
   235 				{
       
   236 				TInt j=(i+1)<<1;
       
   237 				if ((j>=startOfSortedPortion) || (aKey.Compare(j-1,j)>0))
       
   238 					{
       
   239 					--j;
       
   240 					}
       
   241 				if ((j>=startOfSortedPortion) || (aKey.Compare(i,j)>=0))
       
   242 					{
       
   243 					break;
       
   244 					}
       
   245 				aSwap.Swap(i,j);
       
   246 				i=j;
       
   247 				}
       
   248 			}
       
   249 		}
       
   250 #endif
       
   251 #if defined(_DEBUG)
       
   252 	{
       
   253 	for (TInt i=1; i<aCount; ++i)
       
   254 		{
       
   255 		BG_ASSERT_DEBUG_INVARIANT(aKey.Compare(i-1,i)<=0);
       
   256 		}
       
   257 	}
       
   258 #endif
       
   259 	}
       
   260 
       
   261 /*
       
   262  CPolygonFiller
       
   263  */
       
   264  
       
   265 /**
       
   266  Constructor which initializes all member data to zero, EFalse or null for 
       
   267  TInt, TBool pointers respectively.
       
   268  */
       
   269 EXPORT_C CPolygonFiller::CPolygonFiller():
       
   270 	CBase(),
       
   271 	iPointArray(NULL),
       
   272 	iPointList(NULL),
       
   273 	iFillRule(CGraphicsContext::EAlternate),
       
   274 	iUseFastAlgorithm(EFalse),
       
   275 	iNumVertexes(0),
       
   276 	iToggler(EFalse),
       
   277 	iNestingLevel(0),
       
   278 	iScanLineIntersection(0),
       
   279 	iRightMostPixelOnScanLine(0),
       
   280 	iFirstVertex(0),
       
   281 	iPolygonIsAllHorizontal(EFalse),
       
   282 	iFirstScanLine(0),
       
   283 	iLastScanLine(0),
       
   284 	iCurrentScanLine(0)
       
   285 	{
       
   286 	iFastData.vertexList=NULL;
       
   287 	iFastData.edgeList=NULL;
       
   288 	iFastData.activeEdgeList=NULL;
       
   289 	iFastData.scanLineIntersectionList=NULL;
       
   290 	iFastData.numActiveEdges=0;
       
   291 	iFastData.numScanLineIntersections=0;
       
   292 	iFastData.nextEdgeToActivate=0;
       
   293 	iSlowData.numIntersectionsWithSameFirstPixelPreviouslyMet=0;
       
   294 	iSlowData.numIntersectionsWithSameFirstPixelMetThisTime=0;
       
   295 	iSlowData.numScanLineIntersections=0;
       
   296 	iSlowData.scanLineComplete=EFalse;
       
   297 	iSlowData.firstPixelOfLastIntersectionInPrevBuffer=0;
       
   298 	}
       
   299 
       
   300 /**
       
   301 Destructor calls reset on the polygon.
       
   302 */
       
   303 EXPORT_C CPolygonFiller::~CPolygonFiller()
       
   304 	{
       
   305 	Reset();
       
   306 	}
       
   307 
       
   308 /**
       
   309 Takes a list of points to be the points for the new polygon and sets the number of points in the shape. 
       
   310 After this has been done it transfers the task to <code>Construct(aFillRule,aUsage)</code>. This should not fail.
       
   311 @param aPointList A list of points for the polygon. 
       
   312 @param aNumPoints The number of points in the list.
       
   313 @param aFillRule How filling should be achieved, as described by a CGraphicsContext::TFillRule object.
       
   314 @param aUsage How the polygon should be used, see TUsage enumeration.
       
   315 */
       
   316 EXPORT_C void CPolygonFiller::Construct(const TPoint* aPointList,TInt aNumPoints, 
       
   317 										CGraphicsContext::TFillRule aFillRule, TUsage aUsage)
       
   318 	{
       
   319 	BG_ASSERT_ALWAYS(aPointList!=NULL,EBitgdiPanicPolygonFiller);
       
   320 	iPointList=aPointList;
       
   321 	iNumVertexes=aNumPoints;
       
   322 	Construct(aFillRule,aUsage);
       
   323 	}
       
   324 
       
   325 /**
       
   326 An overloaded version of Construct which allows the list of points to be passed in as a point array.
       
   327 Exactly the same behaviour and structure as above. This should not fail. This method does not require the 
       
   328 number of nodes to be given as a parameter.
       
   329 @param PointArray A pointer to point array, as opposed to a pointer to a point list.
       
   330 @param aFillRule How filling should be achieved, as described by a CGraphicsContext::TFillRule object.
       
   331 @param aUsage How the polygon should be used.
       
   332 */
       
   333 EXPORT_C void CPolygonFiller::Construct(const CArrayFix<TPoint>* aPointArray, 
       
   334 										CGraphicsContext::TFillRule aFillRule, TUsage aUsage)
       
   335 	{
       
   336 	BG_ASSERT_ALWAYS(aPointArray!=NULL,EBitgdiPanicPolygonFiller);
       
   337 	iPointArray=aPointArray;
       
   338 	iNumVertexes=iPointArray->Count();
       
   339 	Construct(aFillRule,aUsage);
       
   340 	}
       
   341 
       
   342 void CPolygonFiller::Construct(CGraphicsContext::TFillRule aFillRule, TUsage aUsage)
       
   343 	{
       
   344 	BG_ASSERT_ALWAYS((aFillRule==CGraphicsContext::EAlternate) || (aFillRule==CGraphicsContext::EWinding),
       
   345 																					EBitgdiPanicPolygonFiller);
       
   346 	BG_ASSERT_ALWAYS((aUsage==EGetAllPixelRunsSequentially) || (aUsage==EGetPixelRunsSequentiallyForSpecifiedScanLines),
       
   347 																					EBitgdiPanicPolygonFiller);
       
   348 	TInt i, j;
       
   349 	iFillRule=aFillRule;
       
   350 	iUseFastAlgorithm=(aUsage==EGetAllPixelRunsSequentially);
       
   351 	iToggler=EFalse;
       
   352 	iNestingLevel=0;
       
   353 	iScanLineIntersection=0;
       
   354 	iRightMostPixelOnScanLine=KMinTInt;
       
   355 	// find the first vertex and see if the polygon is all horizontal
       
   356 	iFirstVertex=0; // dummy default value
       
   357 	iPolygonIsAllHorizontal=ETrue;
       
   358 
       
   359 	if (iNumVertexes==0)
       
   360 		return;
       
   361 
       
   362 	for (i=0; i<iNumVertexes; ++i)
       
   363 		if (Point(i).iY!=Point((i+1)%iNumVertexes).iY)
       
   364 			{
       
   365 			// i is now set to the vertex before the first non-horizontal edge
       
   366 
       
   367 			// set j%iNumVertexes to the vertex before the next non-horizontal edge
       
   368 			for (j=i+1; Point(j%iNumVertexes).iY==Point((j+1)%iNumVertexes).iY; ++j)
       
   369 				;
       
   370 			j%=iNumVertexes;
       
   371 			TInt first=Point(i).iY;
       
   372 			TInt middle=Point(j).iY;
       
   373 			TInt last=Point((j+1)%iNumVertexes).iY;
       
   374 
       
   375 			// if vertex j is a max or min point, set the first-vertex to be j
       
   376 			if ((middle<first)==(middle<last))
       
   377 				{
       
   378 				iFirstVertex=j;
       
   379 				iPolygonIsAllHorizontal=EFalse;
       
   380 				break;
       
   381 				}
       
   382 			}
       
   383 
       
   384 	if (iUseFastAlgorithm)
       
   385 		{
       
   386 		iFastData.vertexList=(TPoint*)User::Alloc(sizeof(TPoint)*iNumVertexes);
       
   387 		iFastData.edgeList=(SFastEdge*)User::Alloc(sizeof(SFastEdge)*iNumVertexes);
       
   388 		iFastData.activeEdgeList=(SFastActiveEdge*)User::Alloc(sizeof(SFastActiveEdge)*iNumVertexes);
       
   389 		iFastData.scanLineIntersectionList=(SFastScanLineIntersection*)User::Alloc(sizeof(SFastScanLineIntersection)*iNumVertexes);
       
   390 		if ((iFastData.vertexList==NULL) ||
       
   391 			(iFastData.edgeList==NULL) ||
       
   392 			(iFastData.activeEdgeList==NULL) ||
       
   393 			(iFastData.scanLineIntersectionList==NULL))
       
   394 			{
       
   395 			Reset(); // sets iUseFastAlgorithm to EFalse among other things
       
   396 			}
       
   397 		}
       
   398 
       
   399 	if (iUseFastAlgorithm)
       
   400 		{
       
   401 		for(TInt vertexcount=0;vertexcount<iNumVertexes;vertexcount++)
       
   402 			new(&iFastData.activeEdgeList[vertexcount]) SFastActiveEdge;
       
   403 		iFastData.numActiveEdges=0;
       
   404 		iFastData.numScanLineIntersections=0;
       
   405 		iFastData.nextEdgeToActivate=0;
       
   406 
       
   407 		// put the points into the vertex-list
       
   408 		// N.B. this array is uesd for speed since CArrayXxxs are slower for indexing into than built-in arrays
       
   409 		for (i=0; i<iNumVertexes; ++i)
       
   410 			iFastData.vertexList[i]=Point((i+iFirstVertex)%iNumVertexes);
       
   411 
       
   412 		// create edge-list
       
   413 		for (i=0; i<iNumVertexes; ++i)
       
   414 			{
       
   415 			if (iFastData.vertexList[i].iY<iFastData.vertexList[(i+1)%iNumVertexes].iY)
       
   416 				{
       
   417 				iFastData.edgeList[i].upperVertex=i;
       
   418 				iFastData.edgeList[i].lowerVertex=(i+1)%iNumVertexes;
       
   419 				}
       
   420 			else
       
   421 				{
       
   422 				iFastData.edgeList[i].upperVertex=(i+1)%iNumVertexes;
       
   423 				iFastData.edgeList[i].lowerVertex=i;
       
   424 				}
       
   425 			iFastData.edgeList[i].firstVertex=i;
       
   426 			}
       
   427 
       
   428 		// sort edge-list into order of increasing upper y-position
       
   429 		Sort(iNumVertexes,TCompareEdgesUpperY(iFastData),TSwapEdges(iFastData));
       
   430 
       
   431 		// find the first scan-line
       
   432 		iFirstScanLine=iFastData.vertexList[iFastData.edgeList[0].upperVertex].iY;
       
   433 
       
   434 		// find the last scan-line
       
   435 		iLastScanLine=iFirstScanLine;
       
   436 		for (i=0; i<iNumVertexes; ++i)
       
   437 			if (iLastScanLine<iFastData.vertexList[i].iY)
       
   438 				iLastScanLine=iFastData.vertexList[i].iY;
       
   439 		}
       
   440 	else
       
   441 		{
       
   442 		iSlowData.numIntersectionsWithSameFirstPixelPreviouslyMet=0;
       
   443 		iSlowData.scanLineComplete=EFalse;
       
   444 		iSlowData.firstPixelOfLastIntersectionInPrevBuffer=KMinTInt;
       
   445 
       
   446 		// find the first and last scan-lines
       
   447 		iFirstScanLine=KMaxTInt;
       
   448 		iLastScanLine=KMinTInt;
       
   449 		for (i=0; i<iNumVertexes; ++i)
       
   450 			{
       
   451 			TInt y=Point(i).iY;
       
   452 			if (iFirstScanLine>y)
       
   453 				iFirstScanLine=y;
       
   454 			if (iLastScanLine<y)
       
   455 				iLastScanLine=y;
       
   456 			}
       
   457 		}
       
   458 
       
   459 	iCurrentScanLine=iFirstScanLine;
       
   460 	}
       
   461 
       
   462 /**
       
   463 Frees any data held in the polygons lists of all edges, vertexs and scan lines and sets these values to NULL.
       
   464 It also has the feature of setting iUseFastAlgorithm = EFalse.
       
   465 */
       
   466 EXPORT_C void CPolygonFiller::Reset()
       
   467 	{
       
   468 	if(iUseFastAlgorithm)
       
   469 		{
       
   470 		if(iFastData.vertexList)
       
   471 			{
       
   472 			User::Free(iFastData.vertexList);
       
   473 			iFastData.vertexList=NULL;
       
   474 			}
       
   475 		if(iFastData.edgeList)
       
   476 			{
       
   477 			User::Free(iFastData.edgeList);
       
   478 			iFastData.edgeList=NULL;
       
   479 			}
       
   480 		if(iFastData.activeEdgeList)
       
   481 			{
       
   482 			User::Free(iFastData.activeEdgeList);
       
   483 			iFastData.activeEdgeList=NULL;
       
   484 			}
       
   485 		if(iFastData.scanLineIntersectionList)
       
   486 			{
       
   487 			User::Free(iFastData.scanLineIntersectionList);
       
   488 			iFastData.scanLineIntersectionList=NULL;
       
   489 			}
       
   490 		iUseFastAlgorithm=EFalse;
       
   491 		}
       
   492 	}
       
   493 
       
   494 /**
       
   495 Method is used to calculate the locations of vertex interactions between the polygon and scan lines. 
       
   496 An initial scan line is required. It calculates the start and end positions on the line. The method
       
   497 can use either the fast or slow polygon algorithm depending upon the state of aUsage. Polygon filling
       
   498 is also addressed by this method.
       
   499 @param aExists Will be set to false if a polygon with no vertexes is passed in, otherwise ETrue on return.
       
   500 @param aScanline On return will contain iScanline at the beginning of the operation.
       
   501 @param aStart The position on the scan line to start the run, on returned.
       
   502 @param aEnd The position on the scan line to end the run, returned.
       
   503 */
       
   504 EXPORT_C void CPolygonFiller::GetNextPixelRun(TBool& aExists, TInt& aScanLine, TInt& aStart, 
       
   505 											  TInt& aEnd)
       
   506 	{
       
   507 	if (iNumVertexes==0 || iCurrentScanLine>iLastScanLine)
       
   508 		{
       
   509 		aExists=EFalse;
       
   510 		return;
       
   511 		}
       
   512 
       
   513 	aExists=ETrue;
       
   514 	aScanLine=iCurrentScanLine;
       
   515 
       
   516 	if (iPolygonIsAllHorizontal)
       
   517 		{
       
   518 		// set the start after the end
       
   519 		aStart=KMinTInt+1;
       
   520 		aEnd=KMinTInt;
       
   521 		++iCurrentScanLine;
       
   522 		return;
       
   523 		}
       
   524 
       
   525 	if (iUseFastAlgorithm)
       
   526 		{
       
   527 		TInt i, j;
       
   528 
       
   529 		if (iScanLineIntersection==0)
       
   530 			{
       
   531 			// add any new edges to the active-edge-list
       
   532 			for (; (iFastData.nextEdgeToActivate<iNumVertexes) &&
       
   533 					(iFastData.vertexList[iFastData.edgeList[iFastData.nextEdgeToActivate].upperVertex].iY==iCurrentScanLine);
       
   534 					++iFastData.numActiveEdges, ++iFastData.nextEdgeToActivate)
       
   535 				{
       
   536 				iFastData.activeEdgeList[iFastData.numActiveEdges].edgePtr=&iFastData.edgeList[iFastData.nextEdgeToActivate];
       
   537 				iFastData.activeEdgeList[iFastData.numActiveEdges].lineGenerator.Construct(
       
   538 														iFastData.vertexList[iFastData.edgeList[iFastData.nextEdgeToActivate].upperVertex],
       
   539 														iFastData.vertexList[iFastData.edgeList[iFastData.nextEdgeToActivate].lowerVertex]);
       
   540 				iFastData.activeEdgeList[iFastData.numActiveEdges].scanLineIntersectionPtr=NULL;
       
   541 				}
       
   542 
       
   543 			// sort the active-edge-list into order of adjacent edges (if possible)
       
   544 			Sort(iFastData.numActiveEdges,TCompareActiveEdgesFirstVertex(iFastData),TSwapActiveEdges(iFastData));
       
   545 
       
   546 			// find the intersection of each active-edge with the current scan-line
       
   547 			// for max/min vertex-runs (e.g. \/, \_/, \__/, etc.) add 2 intersections for each run
       
   548 			// for other vertex-runs (e.g. /----/) add 1 intersection for each run
       
   549 			for (i=0; i<iFastData.numActiveEdges; ++i)
       
   550 				{
       
   551 				// check that active-edge i is not horizontal
       
   552 				BG_ASSERT_DEBUG(iFastData.vertexList[iFastData.activeEdgeList[i].edgePtr->upperVertex].iY!=
       
   553 							   iFastData.vertexList[iFastData.activeEdgeList[i].edgePtr->lowerVertex].iY, EBitgdiPanicPolygonFiller);
       
   554 
       
   555 				if (iFastData.vertexList[iFastData.activeEdgeList[i].edgePtr->upperVertex].iY==iCurrentScanLine)
       
   556 					// the scan-line is intersecting active-edge i at its upper-vertex
       
   557 					FastHandleVertexIntersection(i, EFalse);
       
   558 				else if (iFastData.vertexList[iFastData.activeEdgeList[i].edgePtr->lowerVertex].iY==iCurrentScanLine)
       
   559 					// the scan-line is intersecting active-edge i at its lower-vertex
       
   560 					FastHandleVertexIntersection(i, ETrue);
       
   561 				else
       
   562 					// the scan-line is intersecting active-edge i at neither of its vertices
       
   563 					SetFastIntersection(iFastData.activeEdgeList[i],*iFastData.activeEdgeList[i].scanLineIntersectionPtr);
       
   564 				}
       
   565 
       
   566 			// N.B. iFastData.numScanLineIntersections is less than or equal to iFastData.numActiveEdges
       
   567 
       
   568 			// sort the intersection-list into increasing order of first-pixel
       
   569 			Sort(iFastData.numScanLineIntersections,TCompareScanLineIntersectionsFirstPixel(iFastData),TSwapScanLineIntersections(iFastData));
       
   570 
       
   571 			BG_ASSERT_DEBUG(iFastData.numScanLineIntersections>=2, EBitgdiPanicPolygonFiller);
       
   572 			}
       
   573 
       
   574 		// depending on the rule used, find the pixel-run
       
   575 		TBool doFill=EFalse; // dummy initialization to prevent compiler warning
       
   576 		if (iScanLineIntersection<iFastData.numScanLineIntersections-1)
       
   577 			{
       
   578 			switch (iFillRule)
       
   579 				{
       
   580 			case CGraphicsContext::EAlternate:
       
   581 				iToggler=!iToggler;
       
   582 				doFill=iToggler;
       
   583 				break;
       
   584 			case CGraphicsContext::EWinding:
       
   585 					BG_ASSERT_DEBUG(iFastData.vertexList[iFastData.scanLineIntersectionList[iScanLineIntersection].activeEdgePtr->edgePtr->lowerVertex].iY!=
       
   586 								   iFastData.vertexList[iFastData.scanLineIntersectionList[iScanLineIntersection].activeEdgePtr->edgePtr->upperVertex].iY,
       
   587 																										EBitgdiPanicPolygonFiller);
       
   588 
       
   589 					if (iFastData.scanLineIntersectionList[iScanLineIntersection].activeEdgePtr->edgePtr->lowerVertex==
       
   590 						(iFastData.scanLineIntersectionList[iScanLineIntersection].activeEdgePtr->edgePtr->upperVertex+1)%iNumVertexes)
       
   591 						++iNestingLevel;
       
   592 					else
       
   593 						--iNestingLevel;
       
   594 
       
   595 				doFill=(iNestingLevel!=0);
       
   596 				break;
       
   597 				}
       
   598 
       
   599 			if (doFill)
       
   600 				{
       
   601 				aStart=Max(iRightMostPixelOnScanLine, iFastData.scanLineIntersectionList[iScanLineIntersection].lastPixel)+1;
       
   602 				aEnd=iFastData.scanLineIntersectionList[iScanLineIntersection+1].firstPixel-1;
       
   603 				}
       
   604 			else
       
   605 				{
       
   606 				// set the start after the end
       
   607 				aStart=KMinTInt+1;
       
   608 				aEnd=KMinTInt;
       
   609 				}
       
   610 
       
   611 			if (iRightMostPixelOnScanLine<iFastData.scanLineIntersectionList[iScanLineIntersection].lastPixel)
       
   612 				iRightMostPixelOnScanLine=iFastData.scanLineIntersectionList[iScanLineIntersection].lastPixel;
       
   613 			++iScanLineIntersection;
       
   614 			}
       
   615 
       
   616 		if (iScanLineIntersection==iFastData.numScanLineIntersections-1)
       
   617 			{
       
   618 			BG_ASSERT_DEBUG(iFastData.vertexList[iFastData.scanLineIntersectionList[iScanLineIntersection].activeEdgePtr->edgePtr->lowerVertex].iY!=
       
   619 						   iFastData.vertexList[iFastData.scanLineIntersectionList[iScanLineIntersection].activeEdgePtr->edgePtr->upperVertex].iY,
       
   620 																											EBitgdiPanicPolygonFiller);
       
   621 
       
   622 			switch (iFillRule)
       
   623 				{
       
   624 			case CGraphicsContext::EAlternate:
       
   625 				iToggler=!iToggler;
       
   626 				BG_ASSERT_DEBUG(iToggler==0, EBitgdiPanicPolygonFiller);
       
   627 				break;
       
   628 			case CGraphicsContext::EWinding:
       
   629 				if (iFastData.scanLineIntersectionList[iScanLineIntersection].activeEdgePtr->edgePtr->lowerVertex==
       
   630 					(iFastData.scanLineIntersectionList[iScanLineIntersection].activeEdgePtr->edgePtr->upperVertex+1)%iNumVertexes)
       
   631 					++iNestingLevel;
       
   632 				else
       
   633 					--iNestingLevel;
       
   634 				BG_ASSERT_DEBUG((iNumVertexes==2) || (iNestingLevel==0), EBitgdiPanicPolygonFiller);
       
   635 				break;
       
   636 				}
       
   637 
       
   638 			// remove any scan-line-intersections associated with old active-edges
       
   639 			for (i=0; i<iFastData.numScanLineIntersections; )
       
   640 				if (iFastData.vertexList[iFastData.scanLineIntersectionList[i].activeEdgePtr->edgePtr->lowerVertex].iY==iCurrentScanLine)
       
   641 					{
       
   642 					iFastData.scanLineIntersectionList[i].activeEdgePtr->scanLineIntersectionPtr=NULL;
       
   643 
       
   644 					// ripple all the entries in the scan-line-intersection-list after this one back one place
       
   645 					for (j=i+1; j<iFastData.numScanLineIntersections; ++j)
       
   646 						{
       
   647 						iFastData.scanLineIntersectionList[j-1]=iFastData.scanLineIntersectionList[j];
       
   648 						iFastData.scanLineIntersectionList[j-1].activeEdgePtr->scanLineIntersectionPtr=&iFastData.scanLineIntersectionList[j-1];
       
   649 						}
       
   650 
       
   651 					iFastData.scanLineIntersectionList[j-1].activeEdgePtr=NULL;
       
   652 					--iFastData.numScanLineIntersections;
       
   653 					}
       
   654 				else
       
   655 					++i;
       
   656 
       
   657 			// remove any old edges from the active-edge-list
       
   658 			for (i=0; i<iFastData.numActiveEdges; )
       
   659 				if (iFastData.vertexList[iFastData.activeEdgeList[i].edgePtr->lowerVertex].iY==iCurrentScanLine)
       
   660 					{
       
   661 					BG_ASSERT_DEBUG(iFastData.activeEdgeList[i].scanLineIntersectionPtr==NULL, EBitgdiPanicPolygonFiller);
       
   662 
       
   663 					// ripple all the entries in the active-edge-list after this one back one place
       
   664 					for (j=i+1; j<iFastData.numActiveEdges; ++j)
       
   665 						{
       
   666 						iFastData.activeEdgeList[j-1]=iFastData.activeEdgeList[j];
       
   667 						if (iFastData.activeEdgeList[j-1].scanLineIntersectionPtr)
       
   668 							iFastData.activeEdgeList[j-1].scanLineIntersectionPtr->activeEdgePtr=&iFastData.activeEdgeList[j-1];
       
   669 						}
       
   670 
       
   671 					iFastData.activeEdgeList[j-1].scanLineIntersectionPtr=NULL;
       
   672 					--iFastData.numActiveEdges;
       
   673 					}
       
   674 				else
       
   675 					++i;
       
   676 
       
   677 #if defined(_DEBUG)
       
   678 			for (i=0; i<iFastData.numActiveEdges; ++i)
       
   679 				{
       
   680 				BG_ASSERT_DEBUG(iFastData.activeEdgeList[i].scanLineIntersectionPtr->activeEdgePtr==
       
   681 								&iFastData.activeEdgeList[i], EBitgdiPanicPolygonFiller);
       
   682 				}
       
   683 
       
   684 			for (i=0; i<iFastData.numScanLineIntersections; ++i)
       
   685 				{
       
   686 				BG_ASSERT_DEBUG(iFastData.scanLineIntersectionList[i].activeEdgePtr->scanLineIntersectionPtr==
       
   687 								&iFastData.scanLineIntersectionList[i], EBitgdiPanicPolygonFiller);
       
   688 				}
       
   689 #endif
       
   690 
       
   691 			iScanLineIntersection=0;
       
   692 			++iCurrentScanLine;
       
   693 			iRightMostPixelOnScanLine=KMinTInt;
       
   694 			}
       
   695 		}
       
   696 	else
       
   697 		{
       
   698 		GetNextPixelRunOnSpecifiedScanLine(aExists, iCurrentScanLine, aStart, aEnd);
       
   699 		if (!aExists)
       
   700 			GetNextPixelRunOnSpecifiedScanLine(aExists, ++iCurrentScanLine, aStart, aEnd);
       
   701 		}
       
   702 	}
       
   703 
       
   704 /**
       
   705 Similar to GetNextPixelRun(aExists, aScanLine, aStart, aEnd) this method is used to draw the relevant 
       
   706 vertex intersections for a polygon but only for an individual specified scan line. The method
       
   707 can use either the fast or slow polygon algorithm depending upon the state of aUsage.
       
   708 @param aExists Will be set to false if the line does not pass through the polygon or if
       
   709 a polygon with no vertices is specified, otherwise ETrue on return.
       
   710 @param aScanline The scan line to be drawn on. Used to set iScanline
       
   711 @param aStart The position on the scan line to start the run, on returned.
       
   712 @param aEnd The position on the scan line to end the run, returned.
       
   713 */
       
   714 EXPORT_C void CPolygonFiller::GetNextPixelRunOnSpecifiedScanLine(TBool& aExists, 
       
   715 																 TInt aScanLine, 
       
   716 																 TInt& aStart, 
       
   717 																 TInt& aEnd)
       
   718 	{
       
   719 	TInt i, j, k;
       
   720 
       
   721 	BG_ASSERT_DEBUG(!iUseFastAlgorithm, EBitgdiPanicPolygonFiller);
       
   722 
       
   723 	if (iNumVertexes==0 || aScanLine<iCurrentScanLine || aScanLine>iLastScanLine)
       
   724 		{
       
   725 		aExists=EFalse;
       
   726 		return;
       
   727 		}
       
   728 
       
   729 	aExists=ETrue;
       
   730 	iCurrentScanLine=aScanLine;
       
   731 
       
   732 	if (iPolygonIsAllHorizontal)
       
   733 		{
       
   734 		// set the start after the end
       
   735 		aStart=KMinTInt+1;
       
   736 		aEnd=KMinTInt;
       
   737 		++iCurrentScanLine;
       
   738 		return;
       
   739 		}
       
   740 
       
   741 	if (iScanLineIntersection==0)
       
   742 		{
       
   743 		iSlowData.numIntersectionsWithSameFirstPixelMetThisTime=0;
       
   744 		iSlowData.numScanLineIntersections=0;
       
   745 		iSlowData.scanLineComplete=ETrue;
       
   746 
       
   747 		// find the left-most iSlowData::EStoreSize number (or less) of intersections with this scan-line
       
   748 		for (i=iFirstVertex; i<iNumVertexes+iFirstVertex; ++i)
       
   749 			{
       
   750 			TPoint upper=Point(i%iNumVertexes);
       
   751 			TPoint lower=Point((i+1)%iNumVertexes);
       
   752 			if (upper.iY>lower.iY)
       
   753 				{
       
   754 				TPoint temp=upper;
       
   755 				upper=lower;
       
   756 				lower=temp;
       
   757 				}
       
   758 
       
   759 			if ((iCurrentScanLine>=upper.iY) && (iCurrentScanLine<=lower.iY))
       
   760 				{
       
   761 				// check that the edge starting at vertex i%iNumVertexes is not horizontal
       
   762 				BG_ASSERT_DEBUG(upper.iY!=lower.iY, EBitgdiPanicPolygonFiller);
       
   763 
       
   764 				// step through the line-generator until the current scan-line is reached
       
   765 				TPoint startPos, endPos;
       
   766 				JumpToCurrentScanLine(iSlowData.lineGenerator, upper, lower, startPos, endPos);
       
   767 
       
   768 				// find the intersection start and end pixels
       
   769 				SSlowScanLineIntersection scanLineIntersection;
       
   770 				scanLineIntersection.firstPixel=Min(startPos.iX, endPos.iX);
       
   771 				scanLineIntersection.lastPixel=Max(startPos.iX, endPos.iX);
       
   772 				scanLineIntersection.firstVertexOfEdge=i%iNumVertexes;
       
   773 
       
   774 				// handle horizontal runs and minima/maxima
       
   775 				if (upper.iY==iCurrentScanLine)
       
   776 					SlowHandleVertexIntersection(scanLineIntersection, i, EFalse);
       
   777 				else if (lower.iY==iCurrentScanLine)
       
   778 					SlowHandleVertexIntersection(scanLineIntersection, i, ETrue);
       
   779 
       
   780 				// see if there have been other intersections with the same first-pixel
       
   781 				if (scanLineIntersection.firstPixel==iSlowData.firstPixelOfLastIntersectionInPrevBuffer)
       
   782 					++iSlowData.numIntersectionsWithSameFirstPixelMetThisTime;
       
   783 
       
   784 				// if the intersection has not already been included in a previous buffer-load
       
   785 				if ((scanLineIntersection.firstPixel>iSlowData.firstPixelOfLastIntersectionInPrevBuffer) ||
       
   786 					((scanLineIntersection.firstPixel==iSlowData.firstPixelOfLastIntersectionInPrevBuffer) &&
       
   787 													(iSlowData.numIntersectionsWithSameFirstPixelMetThisTime>=
       
   788 													iSlowData.numIntersectionsWithSameFirstPixelPreviouslyMet)))
       
   789 					{
       
   790 					// put the intersection in the right place in the intersection list (if there is room)
       
   791 					for (j=0; j<iSlowData.numScanLineIntersections; ++j)
       
   792 						if (scanLineIntersection.firstPixel<iSlowData.scanLineIntersectionList[j].firstPixel)
       
   793 							{
       
   794 							if (iSlowData.numScanLineIntersections<SSlowData::EStoreSize)
       
   795 								++iSlowData.numScanLineIntersections;
       
   796 							else
       
   797 								iSlowData.scanLineComplete=EFalse;
       
   798 
       
   799 							for (k=iSlowData.numScanLineIntersections-1; k>j; --k)
       
   800 								iSlowData.scanLineIntersectionList[k]=iSlowData.scanLineIntersectionList[k-1];
       
   801 							iSlowData.scanLineIntersectionList[j]=scanLineIntersection;
       
   802 							break;
       
   803 							}
       
   804 					if (j==iSlowData.numScanLineIntersections)
       
   805 						{
       
   806 						if (iSlowData.numScanLineIntersections<SSlowData::EStoreSize)
       
   807 							iSlowData.scanLineIntersectionList[iSlowData.numScanLineIntersections++]=scanLineIntersection;
       
   808 						else
       
   809 							iSlowData.scanLineComplete=EFalse;
       
   810 						}
       
   811 					}
       
   812 				}
       
   813 			}
       
   814 
       
   815 		if (!iSlowData.scanLineComplete)
       
   816 			{
       
   817 			BG_ASSERT_DEBUG(iSlowData.numScanLineIntersections==SSlowData::EStoreSize, EBitgdiPanicPolygonFiller);
       
   818 
       
   819 			if (iSlowData.firstPixelOfLastIntersectionInPrevBuffer==iSlowData.scanLineIntersectionList[SSlowData::EStoreSize-1].firstPixel)
       
   820 				iSlowData.numIntersectionsWithSameFirstPixelPreviouslyMet+=SSlowData::EStoreSize-1;
       
   821 			else
       
   822 				{
       
   823 				iSlowData.firstPixelOfLastIntersectionInPrevBuffer=iSlowData.scanLineIntersectionList[SSlowData::EStoreSize-1].firstPixel;
       
   824 				iSlowData.numIntersectionsWithSameFirstPixelPreviouslyMet=1;
       
   825 				for (i=SSlowData::EStoreSize-1; (i>0) && (iSlowData.firstPixelOfLastIntersectionInPrevBuffer==
       
   826 															iSlowData.scanLineIntersectionList[i-1].firstPixel); --i)
       
   827 					++iSlowData.numIntersectionsWithSameFirstPixelPreviouslyMet;
       
   828 				}
       
   829 			}
       
   830 		}
       
   831 
       
   832 	// depending on the rule used, find the pixel-run
       
   833 	TBool doFill=EFalse; // dummy initialization to prevent compiler warning
       
   834 	if (iScanLineIntersection<iSlowData.numScanLineIntersections-1)
       
   835 		{
       
   836 		switch (iFillRule)
       
   837 			{
       
   838 		case CGraphicsContext::EAlternate:
       
   839 			iToggler=!iToggler;
       
   840 			doFill=iToggler;
       
   841 			break;
       
   842 		case CGraphicsContext::EWinding:
       
   843 				BG_ASSERT_DEBUG(Point(iSlowData.scanLineIntersectionList[iScanLineIntersection].firstVertexOfEdge).iY!=
       
   844 							   Point((iSlowData.scanLineIntersectionList[iScanLineIntersection].firstVertexOfEdge+1)%iNumVertexes).iY,
       
   845 																										EBitgdiPanicPolygonFiller);
       
   846 
       
   847 				if (Point(iSlowData.scanLineIntersectionList[iScanLineIntersection].firstVertexOfEdge).iY>
       
   848 					Point((iSlowData.scanLineIntersectionList[iScanLineIntersection].firstVertexOfEdge+1)%iNumVertexes).iY)
       
   849 					++iNestingLevel;
       
   850 				else
       
   851 					--iNestingLevel;
       
   852 
       
   853 			doFill=(iNestingLevel!=0);
       
   854 			break;
       
   855 			}
       
   856 
       
   857 		if (doFill)
       
   858 			{
       
   859 			aStart=Max(iRightMostPixelOnScanLine, iSlowData.scanLineIntersectionList[iScanLineIntersection].lastPixel)+1;
       
   860 			aEnd=iSlowData.scanLineIntersectionList[iScanLineIntersection+1].firstPixel-1;
       
   861 			}
       
   862 		else
       
   863 			{
       
   864 			// set the start after the end
       
   865 			aStart=KMinTInt+1;
       
   866 			aEnd=KMinTInt;
       
   867 			}
       
   868 
       
   869 		if (iRightMostPixelOnScanLine<iSlowData.scanLineIntersectionList[iScanLineIntersection].lastPixel)
       
   870 			iRightMostPixelOnScanLine=iSlowData.scanLineIntersectionList[iScanLineIntersection].lastPixel;
       
   871 		++iScanLineIntersection;
       
   872 		}
       
   873 
       
   874 	if (iScanLineIntersection==iSlowData.numScanLineIntersections-1)
       
   875 		{
       
   876 		if (iSlowData.scanLineComplete)
       
   877 			{
       
   878 			BG_ASSERT_DEBUG(Point(iSlowData.scanLineIntersectionList[iScanLineIntersection].firstVertexOfEdge).iY!=
       
   879 						   Point((iSlowData.scanLineIntersectionList[iScanLineIntersection].firstVertexOfEdge+1)%iNumVertexes).iY,
       
   880 																											EBitgdiPanicPolygonFiller);
       
   881 
       
   882 			switch (iFillRule)
       
   883 				{
       
   884 			case CGraphicsContext::EAlternate:
       
   885 				iToggler=!iToggler;
       
   886 				BG_ASSERT_DEBUG(iToggler==0, EBitgdiPanicPolygonFiller);
       
   887 				break;
       
   888 			case CGraphicsContext::EWinding:
       
   889 				if (Point(iSlowData.scanLineIntersectionList[iScanLineIntersection].firstVertexOfEdge).iY>
       
   890 					Point((iSlowData.scanLineIntersectionList[iScanLineIntersection].firstVertexOfEdge+1)%iNumVertexes).iY)
       
   891 					++iNestingLevel;
       
   892 				else
       
   893 					--iNestingLevel;
       
   894 
       
   895 				BG_ASSERT_DEBUG((!iSlowData.scanLineComplete) || (iNumVertexes==2) || (iNestingLevel==0), EBitgdiPanicPolygonFiller);
       
   896 				break;
       
   897 				}
       
   898 			}
       
   899 
       
   900 		iScanLineIntersection=0;
       
   901 		if (iSlowData.scanLineComplete)
       
   902 			{
       
   903 			++iCurrentScanLine;
       
   904 			iRightMostPixelOnScanLine=KMinTInt;
       
   905 			iSlowData.numIntersectionsWithSameFirstPixelPreviouslyMet=0;
       
   906 			iSlowData.scanLineComplete=EFalse;
       
   907 			iSlowData.firstPixelOfLastIntersectionInPrevBuffer=KMinTInt;
       
   908 			}
       
   909 		}
       
   910 	}
       
   911 
       
   912 void CPolygonFiller::FastHandleVertexIntersection(TInt& aCurrentActiveEdge, 
       
   913 												  TBool aIsLowerVertex)
       
   914 	{
       
   915 	BG_ASSERT_DEBUG(iUseFastAlgorithm, EBitgdiPanicPolygonFiller);
       
   916 
       
   917 	if (iFastData.vertexList[(iFastData.activeEdgeList[aCurrentActiveEdge].edgePtr->firstVertex+1)%iNumVertexes].iY==iCurrentScanLine)
       
   918 		// it is the second vertex of active-edge aCurrentActiveEdge that coincides with the current scan-line
       
   919 		{
       
   920 		TInt origActiveEdge=aCurrentActiveEdge;
       
   921 		SFastScanLineIntersection scanLineIntersection;
       
   922 		scanLineIntersection.activeEdgePtr=NULL;
       
   923 		SetFastIntersection(iFastData.activeEdgeList[origActiveEdge], scanLineIntersection);
       
   924 
       
   925 		// walk through subsequent adjacent horizontal active-edges
       
   926 		for (; ; )
       
   927 			{
       
   928 			// exit the loop if the vertex-run *is* a maximum or a minimum
       
   929 			const SFastEdge* tempEdgePtr=iFastData.activeEdgeList[(aCurrentActiveEdge+1)%iFastData.numActiveEdges].edgePtr;
       
   930 			TBool isMaxOrMin = EFalse;
       
   931 
       
   932 			switch(aIsLowerVertex)
       
   933 				{
       
   934 				case EFalse:
       
   935 					isMaxOrMin = (iFastData.vertexList[tempEdgePtr->lowerVertex].iY > iCurrentScanLine);
       
   936 					break;
       
   937 
       
   938 				case ETrue:
       
   939 					isMaxOrMin = (iFastData.vertexList[tempEdgePtr->upperVertex].iY < iCurrentScanLine);
       
   940 					break;
       
   941 				}
       
   942 
       
   943 			if (isMaxOrMin)
       
   944  				// the vertex-run is a maximum or a minimum
       
   945 				{
       
   946 				if (aIsLowerVertex)
       
   947 					{
       
   948 					*iFastData.activeEdgeList[origActiveEdge].scanLineIntersectionPtr=scanLineIntersection;
       
   949 					iFastData.activeEdgeList[origActiveEdge].scanLineIntersectionPtr->activeEdgePtr=&iFastData.activeEdgeList[origActiveEdge];
       
   950 					}
       
   951 				else
       
   952 					{
       
   953 					// add an intersection
       
   954 					iFastData.scanLineIntersectionList[iFastData.numScanLineIntersections]=scanLineIntersection;
       
   955 					iFastData.scanLineIntersectionList[iFastData.numScanLineIntersections].activeEdgePtr=&iFastData.activeEdgeList[origActiveEdge];
       
   956 					iFastData.activeEdgeList[origActiveEdge].scanLineIntersectionPtr=&iFastData.scanLineIntersectionList[iFastData.numScanLineIntersections];
       
   957 					++iFastData.numScanLineIntersections;
       
   958 					}
       
   959 				break;
       
   960 				}
       
   961 
       
   962 			// the active-edge is horizontal, or the vertex-run is not a maximum or a minimum
       
   963 
       
   964 			++aCurrentActiveEdge;
       
   965 			BG_ASSERT_DEBUG(aCurrentActiveEdge<iFastData.numActiveEdges, EBitgdiPanicPolygonFiller);
       
   966 
       
   967 			// update scanLineIntersection
       
   968 			TPoint startPos, endPos;
       
   969 			TInt minX, maxX;
       
   970 			iFastData.activeEdgeList[aCurrentActiveEdge].lineGenerator.SingleScanline(startPos, endPos);
       
   971 			minX=Min(startPos.iX, endPos.iX);
       
   972 			maxX=Max(startPos.iX, endPos.iX);
       
   973 			if (scanLineIntersection.firstPixel>minX)
       
   974 				scanLineIntersection.firstPixel=minX;
       
   975 			if (scanLineIntersection.lastPixel<maxX)
       
   976 				scanLineIntersection.lastPixel=maxX;
       
   977 
       
   978 			tempEdgePtr=iFastData.activeEdgeList[aCurrentActiveEdge].edgePtr;
       
   979 			TBool isNeitherMaxOrMin = EFalse;
       
   980 
       
   981 			switch(aIsLowerVertex)
       
   982 				{
       
   983 				case EFalse:
       
   984 					isNeitherMaxOrMin = (iFastData.vertexList[tempEdgePtr->upperVertex].iY < iCurrentScanLine);
       
   985 					break;
       
   986 
       
   987 				case ETrue:
       
   988 					isNeitherMaxOrMin = (iFastData.vertexList[tempEdgePtr->lowerVertex].iY > iCurrentScanLine);
       
   989 					break;
       
   990 				}
       
   991 
       
   992  			// exit the loop if the vertex-run is *not* a maximum or a minimum
       
   993 			if (isNeitherMaxOrMin)
       
   994 				{
       
   995 				TInt newActiveEdge;
       
   996 				TInt oldActiveEdge;
       
   997 				if (aIsLowerVertex)
       
   998 					{
       
   999 					newActiveEdge=aCurrentActiveEdge;
       
  1000 					oldActiveEdge=origActiveEdge;
       
  1001 					}
       
  1002 				else
       
  1003 					{
       
  1004 					newActiveEdge=origActiveEdge;
       
  1005 					oldActiveEdge=aCurrentActiveEdge;
       
  1006 					}
       
  1007 				iFastData.activeEdgeList[newActiveEdge].scanLineIntersectionPtr=iFastData.activeEdgeList[oldActiveEdge].scanLineIntersectionPtr;
       
  1008 				iFastData.activeEdgeList[oldActiveEdge].scanLineIntersectionPtr=NULL;
       
  1009 				*iFastData.activeEdgeList[newActiveEdge].scanLineIntersectionPtr=scanLineIntersection;
       
  1010 				iFastData.activeEdgeList[newActiveEdge].scanLineIntersectionPtr->activeEdgePtr=&iFastData.activeEdgeList[newActiveEdge];
       
  1011 				break;
       
  1012 				}
       
  1013 			}
       
  1014 		}
       
  1015 	else
       
  1016 		// it is the first vertex of active-edge aCurrentActiveEdge that coincides with the current scan-line
       
  1017 		{
       
  1018 #if defined(_DEBUG)
       
  1019 		// check that the vertex we are at is a maximum or a minimum
       
  1020 		TInt previousNotLevelVertex;
       
  1021 		TInt SFastEdge::*vertex=(aIsLowerVertex)? &SFastEdge::lowerVertex: &SFastEdge::upperVertex;
       
  1022 		for (previousNotLevelVertex=iFastData.activeEdgeList[aCurrentActiveEdge].edgePtr->*vertex;
       
  1023 								iFastData.vertexList[iFastData.activeEdgeList[aCurrentActiveEdge].edgePtr->*vertex].iY==iFastData.vertexList[previousNotLevelVertex].iY;
       
  1024 								previousNotLevelVertex=(previousNotLevelVertex+iNumVertexes-1)%iNumVertexes)
       
  1025 			;
       
  1026 		TInt nextNotLevelVertex=(iFastData.activeEdgeList[aCurrentActiveEdge].edgePtr->*vertex+1)%iNumVertexes;
       
  1027 		BG_ASSERT_DEBUG((iFastData.vertexList[iFastData.activeEdgeList[aCurrentActiveEdge].edgePtr->*vertex].iY>iFastData.vertexList[previousNotLevelVertex].iY)==
       
  1028 					   (iFastData.vertexList[iFastData.activeEdgeList[aCurrentActiveEdge].edgePtr->*vertex].iY>iFastData.vertexList[nextNotLevelVertex].iY),
       
  1029 																						EBitgdiPanicPolygonFiller);
       
  1030 #endif
       
  1031 
       
  1032 		if (aIsLowerVertex)
       
  1033 			SetFastIntersection(iFastData.activeEdgeList[aCurrentActiveEdge],*iFastData.activeEdgeList[aCurrentActiveEdge].scanLineIntersectionPtr);
       
  1034 		else
       
  1035 			{
       
  1036 			// add an intersection
       
  1037 			SetFastIntersection(iFastData.activeEdgeList[aCurrentActiveEdge], iFastData.scanLineIntersectionList[iFastData.numScanLineIntersections]);
       
  1038 			iFastData.scanLineIntersectionList[iFastData.numScanLineIntersections].activeEdgePtr=&iFastData.activeEdgeList[aCurrentActiveEdge];
       
  1039 			iFastData.activeEdgeList[aCurrentActiveEdge].scanLineIntersectionPtr=&iFastData.scanLineIntersectionList[iFastData.numScanLineIntersections];
       
  1040 			++iFastData.numScanLineIntersections;
       
  1041 			}
       
  1042 		}
       
  1043 	}
       
  1044 
       
  1045 void CPolygonFiller::SetFastIntersection(SFastActiveEdge& aActiveEdge, SFastScanLineIntersection& aScanLineIntersection)
       
  1046 	{
       
  1047 	BG_ASSERT_DEBUG(iUseFastAlgorithm, EBitgdiPanicPolygonFiller);
       
  1048 
       
  1049 	TPoint startPos, endPos;
       
  1050 
       
  1051 	aActiveEdge.lineGenerator.SingleScanline(startPos, endPos);
       
  1052 	aScanLineIntersection.firstPixel=Min(startPos.iX, endPos.iX);
       
  1053 	aScanLineIntersection.lastPixel=Max(startPos.iX, endPos.iX);
       
  1054 	}
       
  1055 
       
  1056 void CPolygonFiller::SlowHandleVertexIntersection(SSlowScanLineIntersection& aScanLineIntersection, 
       
  1057 												  TInt& aVertexStartingCurrentEdge,
       
  1058 												  TBool aIsLowerVertex)
       
  1059 	{
       
  1060 	if (Point((aVertexStartingCurrentEdge+1)%iNumVertexes).iY==iCurrentScanLine)
       
  1061 		// it is the second vertex of the edge starting at vertex aVertexStartingCurrentEdge%iNumVertexes
       
  1062 		// that coincides with the current scan-line
       
  1063 		{
       
  1064 		// walk through subsequent adjacent horizontal active-edges
       
  1065 		for (; ; )
       
  1066 			{
       
  1067 			TPoint nextVertexButOne=Point((aVertexStartingCurrentEdge+2)%iNumVertexes);
       
  1068 			TBool isMaxOrMin = EFalse;
       
  1069 
       
  1070 			switch(aIsLowerVertex)
       
  1071 				{
       
  1072 				case EFalse:
       
  1073 					isMaxOrMin = (nextVertexButOne.iY > iCurrentScanLine);
       
  1074 					break;
       
  1075 
       
  1076 				case ETrue:
       
  1077 					isMaxOrMin = (nextVertexButOne.iY < iCurrentScanLine);
       
  1078 					break;
       
  1079 				}
       
  1080 
       
  1081 			// exit the loop if the vertex-run *is* a maximum or a minimum
       
  1082 			if (isMaxOrMin)
       
  1083 				{
       
  1084 				break;
       
  1085 				}
       
  1086 
       
  1087 			// the edge starting at vertex aVertexStartingCurrentEdge%iNumVertexes is horizontal, or the vertex-run is not a
       
  1088 			// maximum or a minimum
       
  1089 
       
  1090 			++aVertexStartingCurrentEdge;
       
  1091 			BG_ASSERT_DEBUG(aVertexStartingCurrentEdge%iNumVertexes!=iFirstVertex, EBitgdiPanicPolygonFiller);
       
  1092 
       
  1093 			// step through the line-generator until the current scan-line is reached
       
  1094 			TPoint upper=Point(aVertexStartingCurrentEdge%iNumVertexes);
       
  1095 			TPoint lower=nextVertexButOne;
       
  1096 			if (upper.iY>lower.iY)
       
  1097 				{
       
  1098 				TPoint temp=upper;
       
  1099 				upper=lower;
       
  1100 				lower=temp;
       
  1101 				}
       
  1102 
       
  1103 			TPoint startPos, endPos;
       
  1104 			if (upper.iY!=lower.iY)
       
  1105 				JumpToCurrentScanLine(iSlowData.lineGenerator, upper, lower, startPos, endPos);
       
  1106 			else
       
  1107 				{
       
  1108 				// N.B. which is set to which doesn't matter, as long as startPos is set to either upper or lower, and endPos is set to the other
       
  1109 				startPos=upper;
       
  1110 				endPos=lower;
       
  1111 				}
       
  1112 
       
  1113 			// expand the intersection, if necessary
       
  1114 			TInt minX=Min(startPos.iX, endPos.iX);
       
  1115 			TInt maxX=Max(startPos.iX, endPos.iX);
       
  1116 			if (aScanLineIntersection.firstPixel>minX)
       
  1117 				aScanLineIntersection.firstPixel=minX;
       
  1118 			if (aScanLineIntersection.lastPixel<maxX)
       
  1119 				aScanLineIntersection.lastPixel=maxX;
       
  1120 
       
  1121 			TBool isNeitherMaxOrMin = EFalse;
       
  1122 
       
  1123 			switch(aIsLowerVertex)
       
  1124 				{
       
  1125 				case EFalse:
       
  1126 					isNeitherMaxOrMin = (nextVertexButOne.iY < iCurrentScanLine);
       
  1127 					break;
       
  1128 
       
  1129 				case ETrue:
       
  1130 					isNeitherMaxOrMin = (nextVertexButOne.iY > iCurrentScanLine);
       
  1131 					break;
       
  1132 				}
       
  1133 							  
       
  1134 			// exit the loop if the vertex-run is *not* a maximum or a minimum					   
       
  1135 			if (isNeitherMaxOrMin)
       
  1136 				{
       
  1137 				if (aIsLowerVertex)
       
  1138 					{
       
  1139 					aScanLineIntersection.firstVertexOfEdge=aVertexStartingCurrentEdge%iNumVertexes;
       
  1140 					}
       
  1141 				break;
       
  1142 				}
       
  1143 			}
       
  1144 		}
       
  1145 	else
       
  1146 		// it is the first vertex of the edge starting at vertex aVertexStartingCurrentEdge%iNumVertexes
       
  1147 		// that coincides with the current scan-line
       
  1148 		{
       
  1149 #if defined(_DEBUG)
       
  1150 		// check that the vertex we are at is a maximum or a minimum
       
  1151 		TInt previousNotLevelVertex;
       
  1152 		for (previousNotLevelVertex=aVertexStartingCurrentEdge%iNumVertexes;
       
  1153 														Point(aVertexStartingCurrentEdge%iNumVertexes).iY==
       
  1154 														Point(previousNotLevelVertex).iY;
       
  1155 														previousNotLevelVertex=(previousNotLevelVertex+iNumVertexes-1)%iNumVertexes)
       
  1156 			;
       
  1157 		TInt nextNotLevelVertex=(aVertexStartingCurrentEdge+1)%iNumVertexes;
       
  1158 		TInt previousY=Point(previousNotLevelVertex).iY;
       
  1159 		TInt currentY=Point(aVertexStartingCurrentEdge%iNumVertexes).iY;
       
  1160 		TInt nextY=Point(nextNotLevelVertex).iY;
       
  1161 		BG_ASSERT_DEBUG((currentY>previousY) == (currentY>nextY), EBitgdiPanicPolygonFiller);
       
  1162 #endif
       
  1163 		}
       
  1164 	}
       
  1165 
       
  1166 void CPolygonFiller::JumpToCurrentScanLine(TLinearDDA& aLineGenerator, 
       
  1167 										   const TPoint& aUpper, 
       
  1168 										   const TPoint& aLower,
       
  1169 										   TPoint& aStartPos, 
       
  1170 										   TPoint& aEndPos) const
       
  1171 	{
       
  1172 	BG_ASSERT_DEBUG(aUpper.iY<=aLower.iY, EBitgdiPanicPolygonFiller);
       
  1173 	aLineGenerator.Construct(aUpper, aLower);
       
  1174 	if (aUpper.iY<iCurrentScanLine)
       
  1175 		{
       
  1176 		TInt notUsed;
       
  1177 		aLineGenerator.JumpToYCoord(notUsed, iCurrentScanLine-2);
       
  1178 		}
       
  1179 	do
       
  1180 		aLineGenerator.SingleScanline(aStartPos, aEndPos);
       
  1181 	while (aStartPos.iY!=iCurrentScanLine);
       
  1182 	BG_ASSERT_DEBUG(aStartPos.iY==iCurrentScanLine, EBitgdiPanicPolygonFiller);
       
  1183 	BG_ASSERT_DEBUG(aEndPos.iY==iCurrentScanLine, EBitgdiPanicPolygonFiller);
       
  1184 	}
       
  1185 
       
  1186 const TPoint& CPolygonFiller::Point(TInt aIndex)
       
  1187 	{
       
  1188 	if(iPointList) return(iPointList[aIndex]);
       
  1189 	BG_ASSERT_DEBUG(iPointArray,EBitgdiPanicPolygonFiller);
       
  1190 	return((*iPointArray)[aIndex]);
       
  1191 	}
       
  1192