os/graphics/graphicsdeviceinterface/directgdiadaptation/swsrc/swdirectgdipolygon.cpp
1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/os/graphics/graphicsdeviceinterface/directgdiadaptation/swsrc/swdirectgdipolygon.cpp Fri Jun 15 03:10:57 2012 +0200
1.3 @@ -0,0 +1,1319 @@
1.4 +// Copyright (c) 2007-2009 Nokia Corporation and/or its subsidiary(-ies).
1.5 +// All rights reserved.
1.6 +// This component and the accompanying materials are made available
1.7 +// under the terms of "Eclipse Public License v1.0"
1.8 +// which accompanies this distribution, and is available
1.9 +// at the URL "http://www.eclipse.org/legal/epl-v10.html".
1.10 +//
1.11 +// Initial Contributors:
1.12 +// Nokia Corporation - initial contribution.
1.13 +//
1.14 +// Contributors:
1.15 +//
1.16 +// Description:
1.17 +//
1.18 +
1.19 +#include "swdirectgdipolygon.h"
1.20 +
1.21 +/**
1.22 +A utility class used to sort vertex lists based on y coordinates.
1.23 +@see CSwDirectGdiPolygonFiller
1.24 +@see TKey
1.25 +
1.26 +@internalComponent
1.27 +*/
1.28 +NONSHARABLE_CLASS(TCompareEdgesUpperY) : public TKey
1.29 + {
1.30 +public:
1.31 + TCompareEdgesUpperY(const CSwDirectGdiPolygonFiller::SFastData& aFastData);
1.32 +private:
1.33 + virtual TInt Compare(TInt aLeft,TInt aRight) const;
1.34 +private:
1.35 + const CSwDirectGdiPolygonFiller::SFastData& iFastData;
1.36 + };
1.37 +
1.38 +TCompareEdgesUpperY::TCompareEdgesUpperY(const CSwDirectGdiPolygonFiller::SFastData& aFastData):
1.39 + iFastData(aFastData)
1.40 + {
1.41 + }
1.42 +
1.43 +/**
1.44 +Compare edges based on their upper Y coordinate.
1.45 +
1.46 +@param aLeft Index corresponding to the "left" side of the comparison.
1.47 +@param aRight Index corresponding to the "right" side of the comparison.
1.48 +
1.49 +@return Zero, if the two keys are equal; negative, if the left key is less than the right key; positive, if the left key is greater than the right key.
1.50 +
1.51 +@see TKey::Compare
1.52 +*/
1.53 +TInt TCompareEdgesUpperY::Compare(TInt aLeft,TInt aRight) const
1.54 + {
1.55 + const TInt leftUpperY=iFastData.vertexList[iFastData.edgeList[aLeft].upperVertex].iY;
1.56 + const TInt rightUpperY=iFastData.vertexList[iFastData.edgeList[aRight].upperVertex].iY;
1.57 + if (leftUpperY<rightUpperY)
1.58 + return -1;
1.59 + if (leftUpperY>rightUpperY)
1.60 + return 1;
1.61 + return 0;
1.62 + }
1.63 +
1.64 +/**
1.65 +A utility class used to swap entries in edgeList arrays during sort operations.
1.66 +@see CSwDirectGdiPolygonFiller
1.67 +@see TSwap
1.68 +
1.69 +@internalComponent
1.70 +*/
1.71 +NONSHARABLE_CLASS(TSwapEdges) : public TSwap
1.72 + {
1.73 +public:
1.74 + TSwapEdges(CSwDirectGdiPolygonFiller::SFastData& aFastData);
1.75 +private:
1.76 + virtual void Swap(TInt aLeft,TInt aRight) const;
1.77 +private:
1.78 + CSwDirectGdiPolygonFiller::SFastData& iFastData;
1.79 + };
1.80 +
1.81 +TSwapEdges::TSwapEdges(CSwDirectGdiPolygonFiller::SFastData& aFastData):
1.82 + iFastData(aFastData)
1.83 + {
1.84 + }
1.85 +
1.86 +/**
1.87 +Swaps two elements of an edgeList array.
1.88 +
1.89 +@param aLeft The index of an array element participating in the swap.
1.90 +@param aRight The index of an array element participating in the swap.
1.91 +
1.92 +@see TSwap::Swap
1.93 +*/
1.94 +void TSwapEdges::Swap(TInt aLeft,TInt aRight) const
1.95 + {
1.96 + CSwDirectGdiPolygonFiller::SFastEdge& leftEdge=iFastData.edgeList[aLeft];
1.97 + CSwDirectGdiPolygonFiller::SFastEdge& rightEdge=iFastData.edgeList[aRight];
1.98 +
1.99 + const CSwDirectGdiPolygonFiller::SFastEdge temp(leftEdge);
1.100 + leftEdge=rightEdge;
1.101 + rightEdge=temp;
1.102 + }
1.103 +
1.104 +/**
1.105 +A utility class used to sort active edge lists based on the order of their vertexes.
1.106 +@see CSwDirectGdiPolygonFiller
1.107 +@see TKey
1.108 +
1.109 +@internalComponent
1.110 +*/
1.111 +NONSHARABLE_CLASS(TCompareActiveEdgesFirstVertex) : public TKey
1.112 + {
1.113 +public:
1.114 + TCompareActiveEdgesFirstVertex(const CSwDirectGdiPolygonFiller::SFastData& aFastData);
1.115 +private:
1.116 + virtual TInt Compare(TInt aLeft,TInt aRight) const;
1.117 +private:
1.118 + const CSwDirectGdiPolygonFiller::SFastData& iFastData;
1.119 + };
1.120 +
1.121 +TCompareActiveEdgesFirstVertex::TCompareActiveEdgesFirstVertex(const CSwDirectGdiPolygonFiller::SFastData& aFastData):
1.122 + iFastData(aFastData)
1.123 + {
1.124 + }
1.125 +
1.126 +/**
1.127 +Compare edges based on the order of their vertexes.
1.128 +
1.129 +@param aLeft Index corresponding to the "left" side of the comparison.
1.130 +@param aRight Index corresponding to the "right" side of the comparison.
1.131 +
1.132 +@return Zero, if the two keys are equal; negative, if the left key is less than the right key; positive, if the left key is greater than the right key.
1.133 +
1.134 +@see TKey::Compare
1.135 +*/
1.136 +TInt TCompareActiveEdgesFirstVertex::Compare(TInt aLeft,TInt aRight) const
1.137 + {
1.138 + const TInt leftFirstVertex=iFastData.activeEdgeList[aLeft].edgePtr->firstVertex;
1.139 + const TInt rightFirstVertex=iFastData.activeEdgeList[aRight].edgePtr->firstVertex;
1.140 + if (leftFirstVertex<rightFirstVertex)
1.141 + return -1;
1.142 + if (leftFirstVertex>rightFirstVertex)
1.143 + return 1;
1.144 + return 0;
1.145 + }
1.146 +
1.147 +/**
1.148 +A utility class used to swap entries in activeEdgeList arrays during sort operations.
1.149 +@see CSwDirectGdiPolygonFiller
1.150 +@see TSwap
1.151 +
1.152 +@internalComponent
1.153 +*/
1.154 +NONSHARABLE_CLASS(TSwapActiveEdges) : public TSwap
1.155 + {
1.156 +public:
1.157 + TSwapActiveEdges(CSwDirectGdiPolygonFiller::SFastData& aFastData);
1.158 +private:
1.159 + virtual void Swap(TInt aLeft,TInt aRight) const;
1.160 +private:
1.161 + CSwDirectGdiPolygonFiller::SFastData& iFastData;
1.162 + };
1.163 +
1.164 +TSwapActiveEdges::TSwapActiveEdges(CSwDirectGdiPolygonFiller::SFastData& aFastData):
1.165 + iFastData(aFastData)
1.166 + {
1.167 + }
1.168 +
1.169 +/**
1.170 +Swaps two elements of an activeEdgeList array.
1.171 +@param aLeft The index of an array element participating in the swap.
1.172 +@param aRight The index of an array element participating in the swap.
1.173 +@see TSwap::Swap
1.174 +*/
1.175 +void TSwapActiveEdges::Swap(TInt aLeft,TInt aRight) const
1.176 + {
1.177 + CSwDirectGdiPolygonFiller::SFastActiveEdge& leftActiveEdge=iFastData.activeEdgeList[aLeft];
1.178 + CSwDirectGdiPolygonFiller::SFastActiveEdge& rightActiveEdge=iFastData.activeEdgeList[aRight];
1.179 +
1.180 + const CSwDirectGdiPolygonFiller::SFastActiveEdge temp(leftActiveEdge);
1.181 + leftActiveEdge=rightActiveEdge;
1.182 + rightActiveEdge=temp;
1.183 +
1.184 + if (leftActiveEdge.scanLineIntersectionPtr!=NULL)
1.185 + leftActiveEdge.scanLineIntersectionPtr->activeEdgePtr=&leftActiveEdge;
1.186 + if (rightActiveEdge.scanLineIntersectionPtr!=NULL)
1.187 + rightActiveEdge.scanLineIntersectionPtr->activeEdgePtr=&rightActiveEdge;
1.188 + }
1.189 +
1.190 +/**
1.191 +A utility class used to sort intersection lists based on the position of their first pixel.
1.192 +@see CSwDirectGdiPolygonFiller
1.193 +@see TKey
1.194 +
1.195 +@internalComponent
1.196 +*/
1.197 +NONSHARABLE_CLASS(TCompareScanLineIntersectionsFirstPixel) : public TKey
1.198 + {
1.199 +public:
1.200 + TCompareScanLineIntersectionsFirstPixel(const CSwDirectGdiPolygonFiller::SFastData& aFastData);
1.201 +private:
1.202 + virtual TInt Compare(TInt aLeft,TInt aRight) const;
1.203 +private:
1.204 + const CSwDirectGdiPolygonFiller::SFastData& iFastData;
1.205 + };
1.206 +
1.207 +TCompareScanLineIntersectionsFirstPixel::TCompareScanLineIntersectionsFirstPixel(const CSwDirectGdiPolygonFiller::SFastData& aFastData):
1.208 + iFastData(aFastData)
1.209 + {
1.210 + }
1.211 +
1.212 +/**
1.213 +Compare intersections based on the order of their first pixel.
1.214 +
1.215 +@param aLeft Index corresponding to the "left" side of the comparison.
1.216 +@param aRight Index corresponding to the "right" side of the comparison.
1.217 +
1.218 +@return Zero, if the two keys are equal; negative, if the left key is less than the right key; positive, if the left key is greater than the right key.
1.219 +
1.220 +@see TKey::Compare
1.221 +*/
1.222 +TInt TCompareScanLineIntersectionsFirstPixel::Compare(TInt aLeft,TInt aRight) const
1.223 + {
1.224 + const TInt leftFirstPixel=iFastData.scanLineIntersectionList[aLeft].firstPixel;
1.225 + const TInt rightFirstPixel=iFastData.scanLineIntersectionList[aRight].firstPixel;
1.226 + if (leftFirstPixel<rightFirstPixel)
1.227 + return -1;
1.228 + if (leftFirstPixel>rightFirstPixel)
1.229 + return 1;
1.230 + return 0;
1.231 + }
1.232 +
1.233 +/**
1.234 +A utility class used to swap entries in intersection list arrays during sort operations.
1.235 +@see CSwDirectGdiPolygonFiller
1.236 +@see TSwap
1.237 +
1.238 +@internalComponent
1.239 +*/
1.240 +NONSHARABLE_CLASS(TSwapScanLineIntersections) : public TSwap
1.241 + {
1.242 +public:
1.243 + TSwapScanLineIntersections(CSwDirectGdiPolygonFiller::SFastData& aFastData);
1.244 +private:
1.245 + virtual void Swap(TInt aLeft,TInt aRight) const;
1.246 +private:
1.247 + CSwDirectGdiPolygonFiller::SFastData& iFastData;
1.248 + };
1.249 +
1.250 +TSwapScanLineIntersections::TSwapScanLineIntersections(CSwDirectGdiPolygonFiller::SFastData& aFastData):
1.251 + iFastData(aFastData)
1.252 + {
1.253 + }
1.254 +
1.255 +/**
1.256 +Swaps two elements of a scanLineIntersectionList array.
1.257 +@param aLeft The index of an array element participating in the swap.
1.258 +@param aRight The index of an array element participating in the swap.
1.259 +@see TSwap::Swap
1.260 +*/
1.261 +void TSwapScanLineIntersections::Swap(TInt aLeft,TInt aRight) const
1.262 + {
1.263 + CSwDirectGdiPolygonFiller::SFastScanLineIntersection& leftScanLineIntersection=iFastData.scanLineIntersectionList[aLeft];
1.264 + CSwDirectGdiPolygonFiller::SFastScanLineIntersection& rightScanLineIntersection=iFastData.scanLineIntersectionList[aRight];
1.265 +
1.266 + const CSwDirectGdiPolygonFiller::SFastScanLineIntersection temp(leftScanLineIntersection);
1.267 + leftScanLineIntersection=rightScanLineIntersection;
1.268 + rightScanLineIntersection=temp;
1.269 +
1.270 + leftScanLineIntersection.activeEdgePtr->scanLineIntersectionPtr=&leftScanLineIntersection;
1.271 + rightScanLineIntersection.activeEdgePtr->scanLineIntersectionPtr=&rightScanLineIntersection;
1.272 + }
1.273 +
1.274 +/**
1.275 +Sorts array elements
1.276 +
1.277 +@param aCount The number of elements in the array.
1.278 +@param aKey A reference to a suitably initialised TKey derived object.
1.279 +@param aSwap A reference to a suitably initialised TSwap derived object.
1.280 +@panic DGDIAdapter 1015, if QuickSort failed.
1.281 +
1.282 +@internalComponent
1.283 +*/
1.284 +LOCAL_C void Sort(TInt aCount,const TKey& aKey,const TSwap& aSwap)
1.285 + {
1.286 +#if 1 // quick sort
1.287 + const TInt error=User::QuickSort(aCount,aKey,aSwap);
1.288 + GRAPHICS_ASSERT_ALWAYS(error==KErrNone, EDirectGdiPanicPolygonFiller);
1.289 +#elif 0 // bubble sort
1.290 + for (TInt i=1; i<aCount; ++i)
1.291 + {
1.292 + for (TInt j=i; j>0; --j)
1.293 + {
1.294 + if (aKey.Compare(j-1,j)>0)
1.295 + {
1.296 + aSwap.Swap(j-1,j);
1.297 + }
1.298 + }
1.299 + }
1.300 +#else // heap sort
1.301 + TInt startOfSortedPortion=aCount;
1.302 + if (startOfSortedPortion>1)
1.303 + {
1.304 + TInt startOfHeap=startOfSortedPortion>>1;
1.305 + FOREVER
1.306 + {
1.307 + GRAPHICS_ASSERT_DEBUG(startOfHeap>=0, EDirectGdiPanicPolygonFiller);
1.308 + if (startOfHeap!=0)
1.309 + {
1.310 + --startOfHeap;
1.311 + }
1.312 + else
1.313 + {
1.314 + --startOfSortedPortion;
1.315 + aSwap.Swap(startOfSortedPortion,0);
1.316 + GRAPHICS_ASSERT_DEBUG(startOfSortedPortion>=1, EDirectGdiPanicPolygonFiller);
1.317 + if (startOfSortedPortion==1)
1.318 + {
1.319 + break;
1.320 + }
1.321 + }
1.322 + // put aArray[startOfHeap] into the correct place in the heap
1.323 + TInt i=startOfHeap;
1.324 + FOREVER
1.325 + {
1.326 + TInt j=(i+1)<<1;
1.327 + if ((j>=startOfSortedPortion) || (aKey.Compare(j-1,j)>0))
1.328 + {
1.329 + --j;
1.330 + }
1.331 + if ((j>=startOfSortedPortion) || (aKey.Compare(i,j)>=0))
1.332 + {
1.333 + break;
1.334 + }
1.335 + aSwap.Swap(i,j);
1.336 + i=j;
1.337 + }
1.338 + }
1.339 + }
1.340 +#endif
1.341 +#if defined(_DEBUG)
1.342 + {
1.343 + for (TInt i=1; i<aCount; ++i)
1.344 + {
1.345 + GRAPHICS_ASSERT_DEBUG(aKey.Compare(i-1,i)<=0, EDirectGdiPanicPolygonFiller);
1.346 + }
1.347 + }
1.348 +#endif
1.349 + }
1.350 +
1.351 +/*
1.352 + CSwDirectGdiPolygonFiller
1.353 + */
1.354 +
1.355 +/**
1.356 + Constructor which initialises all member data to zero, EFalse or null for
1.357 + TInt, TBool pointers respectively.
1.358 + */
1.359 +CSwDirectGdiPolygonFiller::CSwDirectGdiPolygonFiller():
1.360 + CBase(),
1.361 + iPointArray(NULL),
1.362 + iFillRule(DirectGdi::EAlternate),
1.363 + iUseFastAlgorithm(EFalse),
1.364 + iNumVertexes(0),
1.365 + iToggler(EFalse),
1.366 + iNestingLevel(0),
1.367 + iScanLineIntersection(0),
1.368 + iRightMostPixelOnScanLine(0),
1.369 + iFirstVertex(0),
1.370 + iPolygonIsAllHorizontal(EFalse),
1.371 + iFirstScanLine(0),
1.372 + iLastScanLine(0),
1.373 + iCurrentScanLine(0)
1.374 + {
1.375 + iFastData.vertexList=NULL;
1.376 + iFastData.edgeList=NULL;
1.377 + iFastData.activeEdgeList=NULL;
1.378 + iFastData.scanLineIntersectionList=NULL;
1.379 + iFastData.numActiveEdges=0;
1.380 + iFastData.numScanLineIntersections=0;
1.381 + iFastData.nextEdgeToActivate=0;
1.382 + iSlowData.numIntersectionsWithSameFirstPixelPreviouslyMet=0;
1.383 + iSlowData.numIntersectionsWithSameFirstPixelMetThisTime=0;
1.384 + iSlowData.numScanLineIntersections=0;
1.385 + iSlowData.scanLineComplete=EFalse;
1.386 + iSlowData.firstPixelOfLastIntersectionInPrevBuffer=0;
1.387 + }
1.388 +
1.389 +/**
1.390 +Destructor calls reset on the polygon.
1.391 +*/
1.392 +CSwDirectGdiPolygonFiller::~CSwDirectGdiPolygonFiller()
1.393 + {
1.394 + Reset();
1.395 + }
1.396 +
1.397 +/**
1.398 +An overloaded version of Construct which allows the list of points to be passed in as a point array.
1.399 +Exactly the same behaviour and structure as above. This should not fail. This method does not require the
1.400 +number of nodes to be given as a parameter.
1.401 +
1.402 +@param aPointArray A pointer to point array, as opposed to a pointer to a point list.
1.403 +@param aFillRule How filling should be achieved, as described by a DirectGdi::TFillRule object.
1.404 +@param aUsage How the polygon should be used.
1.405 +@panic DGDIAdapter 1015, if aPointArray is NULL.
1.406 +*/
1.407 +void CSwDirectGdiPolygonFiller::Construct(const TArray<TPoint>* aPointArray,
1.408 + DirectGdi::TFillRule aFillRule, TUsage aUsage)
1.409 + {
1.410 + GRAPHICS_ASSERT_ALWAYS(aPointArray!=NULL,EDirectGdiPanicPolygonFiller);
1.411 + iPointArray=aPointArray;
1.412 + iNumVertexes=iPointArray->Count();
1.413 + Construct(aFillRule,aUsage);
1.414 + }
1.415 +
1.416 +/**
1.417 +Builds up the internal meta-data needed to fill the polygon.
1.418 +
1.419 +@param aFillRule How filling should be achieved, as described by a DirectGdi::TFillRule object.
1.420 +@param aUsage How the polygon should be used, see TUsage enumeration.
1.421 +@panic DGDIAdapter 1015, if aFillRule is invalid, or aUsage is invalid.
1.422 +*/
1.423 +void CSwDirectGdiPolygonFiller::Construct(DirectGdi::TFillRule aFillRule, TUsage aUsage)
1.424 + {
1.425 + GRAPHICS_ASSERT_ALWAYS((aFillRule==DirectGdi::EAlternate) || (aFillRule==DirectGdi::EWinding),
1.426 + EDirectGdiPanicPolygonFiller);
1.427 + GRAPHICS_ASSERT_ALWAYS((aUsage==EGetAllPixelRunsSequentially) || (aUsage==EGetPixelRunsSequentiallyForSpecifiedScanLines),
1.428 + EDirectGdiPanicPolygonFiller);
1.429 + TInt i, j;
1.430 + iFillRule=aFillRule;
1.431 + iUseFastAlgorithm=(aUsage==EGetAllPixelRunsSequentially);
1.432 + iToggler=EFalse;
1.433 + iNestingLevel=0;
1.434 + iScanLineIntersection=0;
1.435 + iRightMostPixelOnScanLine=KMinTInt;
1.436 + // find the first vertex and see if the polygon is all horizontal
1.437 + iFirstVertex=0; // dummy default value
1.438 + iPolygonIsAllHorizontal=ETrue;
1.439 +
1.440 + for (i=0; i<iNumVertexes; ++i)
1.441 + if (Point(i).iY!=Point((i+1)%iNumVertexes).iY)
1.442 + {
1.443 + // i is now set to the vertex before the first non-horizontal edge
1.444 +
1.445 + // set j%iNumVertexes to the vertex before the next non-horizontal edge
1.446 + for (j=i+1; Point(j%iNumVertexes).iY==Point((j+1)%iNumVertexes).iY; ++j)
1.447 + ;
1.448 + j%=iNumVertexes;
1.449 + TInt first=Point(i).iY;
1.450 + TInt middle=Point(j).iY;
1.451 + TInt last=Point((j+1)%iNumVertexes).iY;
1.452 +
1.453 + // if vertex j is a max or min point, set the first-vertex to be j
1.454 + if ((middle<first)==(middle<last))
1.455 + {
1.456 + iFirstVertex=j;
1.457 + iPolygonIsAllHorizontal=EFalse;
1.458 + break;
1.459 + }
1.460 + }
1.461 +
1.462 + if (iUseFastAlgorithm)
1.463 + {
1.464 + iFastData.vertexList=(TPoint*)User::Alloc(sizeof(TPoint)*iNumVertexes);
1.465 + iFastData.edgeList=(SFastEdge*)User::Alloc(sizeof(SFastEdge)*iNumVertexes);
1.466 + iFastData.activeEdgeList=(SFastActiveEdge*)User::Alloc(sizeof(SFastActiveEdge)*iNumVertexes);
1.467 + iFastData.scanLineIntersectionList=(SFastScanLineIntersection*)User::Alloc(sizeof(SFastScanLineIntersection)*iNumVertexes);
1.468 + if ((iFastData.vertexList==NULL) ||
1.469 + (iFastData.edgeList==NULL) ||
1.470 + (iFastData.activeEdgeList==NULL) ||
1.471 + (iFastData.scanLineIntersectionList==NULL))
1.472 + {
1.473 + Reset(); // sets iUseFastAlgorithm to EFalse among other things
1.474 + }
1.475 + }
1.476 +
1.477 + if (iUseFastAlgorithm)
1.478 + {
1.479 + for(TInt vertexcount=0;vertexcount<iNumVertexes;vertexcount++)
1.480 + new(&iFastData.activeEdgeList[vertexcount]) SFastActiveEdge;
1.481 + iFastData.numActiveEdges=0;
1.482 + iFastData.numScanLineIntersections=0;
1.483 + iFastData.nextEdgeToActivate=0;
1.484 +
1.485 + // put the points into the vertex-list
1.486 + // N.B. this array is used for speed since CArrayXxxs are slower for indexing into than built-in arrays
1.487 + for (i=0; i<iNumVertexes; ++i)
1.488 + {
1.489 + // If iFastData.vertexList is NULL this will never be run. iFastData.vertexList is checked
1.490 + // above after which iUseFastAlgorithm is set to EFalse if it is NULL (in Reset())
1.491 + // coverity[var_deref_op]
1.492 + iFastData.vertexList[i]=Point((i+iFirstVertex)%iNumVertexes);
1.493 + }
1.494 +
1.495 + // create edge-list
1.496 + for (i=0; i<iNumVertexes; ++i)
1.497 + {
1.498 + // See preceding coverity comment
1.499 + // coverity[var_deref_op]
1.500 + if (iFastData.vertexList[i].iY<iFastData.vertexList[(i+1)%iNumVertexes].iY)
1.501 + {
1.502 + iFastData.edgeList[i].upperVertex=i;
1.503 + iFastData.edgeList[i].lowerVertex=(i+1)%iNumVertexes;
1.504 + }
1.505 + else
1.506 + {
1.507 + iFastData.edgeList[i].upperVertex=(i+1)%iNumVertexes;
1.508 + iFastData.edgeList[i].lowerVertex=i;
1.509 + }
1.510 + iFastData.edgeList[i].firstVertex=i;
1.511 + }
1.512 +
1.513 + // sort edge-list into order of increasing upper y-position
1.514 + Sort(iNumVertexes,TCompareEdgesUpperY(iFastData),TSwapEdges(iFastData));
1.515 +
1.516 + // find the first scan-line
1.517 + iFirstScanLine=iFastData.vertexList[iFastData.edgeList[0].upperVertex].iY;
1.518 +
1.519 + // find the last scan-line
1.520 + iLastScanLine=iFirstScanLine;
1.521 + for (i=0; i<iNumVertexes; ++i)
1.522 + if (iLastScanLine<iFastData.vertexList[i].iY)
1.523 + iLastScanLine=iFastData.vertexList[i].iY;
1.524 + }
1.525 + else
1.526 + {
1.527 + iSlowData.numIntersectionsWithSameFirstPixelPreviouslyMet=0;
1.528 + iSlowData.scanLineComplete=EFalse;
1.529 + iSlowData.firstPixelOfLastIntersectionInPrevBuffer=KMinTInt;
1.530 +
1.531 + // find the first and last scan-lines
1.532 + iFirstScanLine=KMaxTInt;
1.533 + iLastScanLine=KMinTInt;
1.534 + for (i=0; i<iNumVertexes; ++i)
1.535 + {
1.536 + TInt y=Point(i).iY;
1.537 + if (iFirstScanLine>y)
1.538 + iFirstScanLine=y;
1.539 + if (iLastScanLine<y)
1.540 + iLastScanLine=y;
1.541 + }
1.542 + }
1.543 +
1.544 + iCurrentScanLine=iFirstScanLine;
1.545 + }
1.546 +
1.547 +/**
1.548 +Frees any data held in the polygon’s lists of edges, vertexes and scan lines, and sets these values to NULL.
1.549 +It also has the feature of setting iUseFastAlgorithm = EFalse.
1.550 +*/
1.551 +void CSwDirectGdiPolygonFiller::Reset()
1.552 + {
1.553 + if(iUseFastAlgorithm)
1.554 + {
1.555 + if(iFastData.vertexList)
1.556 + {
1.557 + User::Free(iFastData.vertexList);
1.558 + iFastData.vertexList=NULL;
1.559 + }
1.560 + if(iFastData.edgeList)
1.561 + {
1.562 + User::Free(iFastData.edgeList);
1.563 + iFastData.edgeList=NULL;
1.564 + }
1.565 + if(iFastData.activeEdgeList)
1.566 + {
1.567 + User::Free(iFastData.activeEdgeList);
1.568 + iFastData.activeEdgeList=NULL;
1.569 + }
1.570 + if(iFastData.scanLineIntersectionList)
1.571 + {
1.572 + User::Free(iFastData.scanLineIntersectionList);
1.573 + iFastData.scanLineIntersectionList=NULL;
1.574 + }
1.575 + iUseFastAlgorithm=EFalse;
1.576 + }
1.577 + }
1.578 +
1.579 +/**
1.580 +Method is used to calculate the locations of vertex interactions between the polygon and scan lines.
1.581 +An initial scan line is required. It calculates the start and end positions on the line. The method
1.582 +can use either the fast or slow polygon algorithm depending upon the state of aUsage. Polygon filling
1.583 +is also addressed by this method.
1.584 +
1.585 +@param aExists Will be set to EFalse if a polygon with no vertexes is passed in, otherwise ETrue on return.
1.586 +@param aScanLine On return will contain iScanline at the beginning of the operation.
1.587 +@param aStart On return, contains the position on the scan line to start the run.
1.588 +@param aEnd On return, contains the position on the scan line to end the run.
1.589 +@panic DGDIAdapter 1015 (debug only)
1.590 +*/
1.591 +void CSwDirectGdiPolygonFiller::GetNextPixelRun(TBool& aExists, TInt& aScanLine, TInt& aStart,
1.592 + TInt& aEnd)
1.593 + {
1.594 + if (iCurrentScanLine>iLastScanLine)
1.595 + {
1.596 + aExists=EFalse;
1.597 + return;
1.598 + }
1.599 +
1.600 + aExists=ETrue;
1.601 + aScanLine=iCurrentScanLine;
1.602 +
1.603 + if (iPolygonIsAllHorizontal)
1.604 + {
1.605 + // set the start after the end
1.606 + aStart=KMinTInt+1;
1.607 + aEnd=KMinTInt;
1.608 + ++iCurrentScanLine;
1.609 + return;
1.610 + }
1.611 +
1.612 + if (iUseFastAlgorithm)
1.613 + {
1.614 + TInt i, j;
1.615 +
1.616 + if (iScanLineIntersection==0)
1.617 + {
1.618 + // add any new edges to the active-edge-list
1.619 + for (; (iFastData.nextEdgeToActivate<iNumVertexes) &&
1.620 + (iFastData.vertexList[iFastData.edgeList[iFastData.nextEdgeToActivate].upperVertex].iY==iCurrentScanLine);
1.621 + ++iFastData.numActiveEdges, ++iFastData.nextEdgeToActivate)
1.622 + {
1.623 + iFastData.activeEdgeList[iFastData.numActiveEdges].edgePtr=&iFastData.edgeList[iFastData.nextEdgeToActivate];
1.624 + iFastData.activeEdgeList[iFastData.numActiveEdges].lineGenerator.Construct(
1.625 + iFastData.vertexList[iFastData.edgeList[iFastData.nextEdgeToActivate].upperVertex],
1.626 + iFastData.vertexList[iFastData.edgeList[iFastData.nextEdgeToActivate].lowerVertex]);
1.627 + iFastData.activeEdgeList[iFastData.numActiveEdges].scanLineIntersectionPtr=NULL;
1.628 + }
1.629 +
1.630 + // sort the active-edge-list into order of adjacent edges (if possible)
1.631 + Sort(iFastData.numActiveEdges,TCompareActiveEdgesFirstVertex(iFastData),TSwapActiveEdges(iFastData));
1.632 +
1.633 + // find the intersection of each active-edge with the current scan-line
1.634 + // for max/min vertex-runs (e.g. \/, \_/, \__/, etc.) add 2 intersections for each run
1.635 + // for other vertex-runs (e.g. /----/) add 1 intersection for each run
1.636 + for (i=0; i<iFastData.numActiveEdges; ++i)
1.637 + {
1.638 + // check that active-edge i is not horizontal
1.639 + GRAPHICS_ASSERT_DEBUG(iFastData.vertexList[iFastData.activeEdgeList[i].edgePtr->upperVertex].iY!=
1.640 + iFastData.vertexList[iFastData.activeEdgeList[i].edgePtr->lowerVertex].iY, EDirectGdiPanicPolygonFiller);
1.641 +
1.642 + if (iFastData.vertexList[iFastData.activeEdgeList[i].edgePtr->upperVertex].iY==iCurrentScanLine)
1.643 + // the scan-line is intersecting active-edge i at its upper-vertex
1.644 + FastHandleVertexIntersection(i, EFalse);
1.645 + else if (iFastData.vertexList[iFastData.activeEdgeList[i].edgePtr->lowerVertex].iY==iCurrentScanLine)
1.646 + // the scan-line is intersecting active-edge i at its lower-vertex
1.647 + FastHandleVertexIntersection(i, ETrue);
1.648 + else
1.649 + // the scan-line is intersecting active-edge i at neither of its vertexes
1.650 + SetFastIntersection(iFastData.activeEdgeList[i],*iFastData.activeEdgeList[i].scanLineIntersectionPtr);
1.651 + }
1.652 +
1.653 + // N.B. iFastData.numScanLineIntersections is less than or equal to iFastData.numActiveEdges
1.654 +
1.655 + // sort the intersection-list into increasing order of first-pixel
1.656 + Sort(iFastData.numScanLineIntersections,TCompareScanLineIntersectionsFirstPixel(iFastData),TSwapScanLineIntersections(iFastData));
1.657 +
1.658 + GRAPHICS_ASSERT_DEBUG(iFastData.numScanLineIntersections>=2, EDirectGdiPanicPolygonFiller);
1.659 + }
1.660 +
1.661 + // depending on the rule used, find the pixel-run
1.662 + TBool doFill=EFalse; // dummy initialization to prevent compiler warning
1.663 + if (iScanLineIntersection<iFastData.numScanLineIntersections-1)
1.664 + {
1.665 + switch (iFillRule)
1.666 + {
1.667 + case DirectGdi::EAlternate:
1.668 + iToggler=!iToggler;
1.669 + doFill=iToggler;
1.670 + break;
1.671 + case DirectGdi::EWinding:
1.672 + GRAPHICS_ASSERT_DEBUG(iFastData.vertexList[iFastData.scanLineIntersectionList[iScanLineIntersection].activeEdgePtr->edgePtr->lowerVertex].iY!=
1.673 + iFastData.vertexList[iFastData.scanLineIntersectionList[iScanLineIntersection].activeEdgePtr->edgePtr->upperVertex].iY,
1.674 + EDirectGdiPanicPolygonFiller);
1.675 +
1.676 + if (iFastData.scanLineIntersectionList[iScanLineIntersection].activeEdgePtr->edgePtr->lowerVertex==
1.677 + (iFastData.scanLineIntersectionList[iScanLineIntersection].activeEdgePtr->edgePtr->upperVertex+1)%iNumVertexes)
1.678 + ++iNestingLevel;
1.679 + else
1.680 + --iNestingLevel;
1.681 +
1.682 + doFill=(iNestingLevel!=0);
1.683 + break;
1.684 + }
1.685 +
1.686 + if (doFill)
1.687 + {
1.688 + aStart=Max(iRightMostPixelOnScanLine, iFastData.scanLineIntersectionList[iScanLineIntersection].lastPixel)+1;
1.689 + aEnd=iFastData.scanLineIntersectionList[iScanLineIntersection+1].firstPixel-1;
1.690 + }
1.691 + else
1.692 + {
1.693 + // set the start after the end
1.694 + aStart=KMinTInt+1;
1.695 + aEnd=KMinTInt;
1.696 + }
1.697 +
1.698 + if (iRightMostPixelOnScanLine<iFastData.scanLineIntersectionList[iScanLineIntersection].lastPixel)
1.699 + iRightMostPixelOnScanLine=iFastData.scanLineIntersectionList[iScanLineIntersection].lastPixel;
1.700 + ++iScanLineIntersection;
1.701 + }
1.702 +
1.703 + if (iScanLineIntersection==iFastData.numScanLineIntersections-1)
1.704 + {
1.705 + GRAPHICS_ASSERT_DEBUG(iFastData.vertexList[iFastData.scanLineIntersectionList[iScanLineIntersection].activeEdgePtr->edgePtr->lowerVertex].iY!=
1.706 + iFastData.vertexList[iFastData.scanLineIntersectionList[iScanLineIntersection].activeEdgePtr->edgePtr->upperVertex].iY,
1.707 + EDirectGdiPanicPolygonFiller);
1.708 +
1.709 + switch (iFillRule)
1.710 + {
1.711 + case DirectGdi::EAlternate:
1.712 + iToggler=!iToggler;
1.713 + GRAPHICS_ASSERT_DEBUG(iToggler==0, EDirectGdiPanicPolygonFiller);
1.714 + break;
1.715 + case DirectGdi::EWinding:
1.716 + if (iFastData.scanLineIntersectionList[iScanLineIntersection].activeEdgePtr->edgePtr->lowerVertex==
1.717 + (iFastData.scanLineIntersectionList[iScanLineIntersection].activeEdgePtr->edgePtr->upperVertex+1)%iNumVertexes)
1.718 + ++iNestingLevel;
1.719 + else
1.720 + --iNestingLevel;
1.721 + GRAPHICS_ASSERT_DEBUG((iNumVertexes==2) || (iNestingLevel==0), EDirectGdiPanicPolygonFiller);
1.722 + break;
1.723 + }
1.724 +
1.725 + // remove any scan-line-intersections associated with old active-edges
1.726 + for (i=0; i<iFastData.numScanLineIntersections; )
1.727 + if (iFastData.vertexList[iFastData.scanLineIntersectionList[i].activeEdgePtr->edgePtr->lowerVertex].iY==iCurrentScanLine)
1.728 + {
1.729 + iFastData.scanLineIntersectionList[i].activeEdgePtr->scanLineIntersectionPtr=NULL;
1.730 +
1.731 + // ripple all the entries in the scan-line-intersection-list after this one back one place
1.732 + for (j=i+1; j<iFastData.numScanLineIntersections; ++j)
1.733 + {
1.734 + iFastData.scanLineIntersectionList[j-1]=iFastData.scanLineIntersectionList[j];
1.735 + iFastData.scanLineIntersectionList[j-1].activeEdgePtr->scanLineIntersectionPtr=&iFastData.scanLineIntersectionList[j-1];
1.736 + }
1.737 +
1.738 + iFastData.scanLineIntersectionList[j-1].activeEdgePtr=NULL;
1.739 + --iFastData.numScanLineIntersections;
1.740 + }
1.741 + else
1.742 + ++i;
1.743 +
1.744 + // remove any old edges from the active-edge-list
1.745 + for (i=0; i<iFastData.numActiveEdges; )
1.746 + if (iFastData.vertexList[iFastData.activeEdgeList[i].edgePtr->lowerVertex].iY==iCurrentScanLine)
1.747 + {
1.748 + GRAPHICS_ASSERT_DEBUG(iFastData.activeEdgeList[i].scanLineIntersectionPtr==NULL, EDirectGdiPanicPolygonFiller);
1.749 +
1.750 + // ripple all the entries in the active-edge-list after this one back one place
1.751 + for (j=i+1; j<iFastData.numActiveEdges; ++j)
1.752 + {
1.753 + iFastData.activeEdgeList[j-1]=iFastData.activeEdgeList[j];
1.754 + if (iFastData.activeEdgeList[j-1].scanLineIntersectionPtr)
1.755 + iFastData.activeEdgeList[j-1].scanLineIntersectionPtr->activeEdgePtr=&iFastData.activeEdgeList[j-1];
1.756 + }
1.757 +
1.758 + iFastData.activeEdgeList[j-1].scanLineIntersectionPtr=NULL;
1.759 + --iFastData.numActiveEdges;
1.760 + }
1.761 + else
1.762 + ++i;
1.763 +
1.764 +#if defined(_DEBUG)
1.765 + for (i=0; i<iFastData.numActiveEdges; ++i)
1.766 + {
1.767 + GRAPHICS_ASSERT_DEBUG(iFastData.activeEdgeList[i].scanLineIntersectionPtr->activeEdgePtr==
1.768 + &iFastData.activeEdgeList[i], EDirectGdiPanicPolygonFiller);
1.769 + }
1.770 +
1.771 + for (i=0; i<iFastData.numScanLineIntersections; ++i)
1.772 + {
1.773 + GRAPHICS_ASSERT_DEBUG(iFastData.scanLineIntersectionList[i].activeEdgePtr->scanLineIntersectionPtr==
1.774 + &iFastData.scanLineIntersectionList[i], EDirectGdiPanicPolygonFiller);
1.775 + }
1.776 +#endif
1.777 +
1.778 + iScanLineIntersection=0;
1.779 + ++iCurrentScanLine;
1.780 + iRightMostPixelOnScanLine=KMinTInt;
1.781 + }
1.782 + }
1.783 + else
1.784 + {
1.785 + GetNextPixelRunOnSpecifiedScanLine(aExists, iCurrentScanLine, aStart, aEnd);
1.786 + if (!aExists)
1.787 + GetNextPixelRunOnSpecifiedScanLine(aExists, ++iCurrentScanLine, aStart, aEnd);
1.788 + }
1.789 + }
1.790 +
1.791 +/**
1.792 +Similar to GetNextPixelRun(aExists, aScanLine, aStart, aEnd) this method is used to draw the relevant
1.793 +vertex intersections for a polygon but only for an individual specified scan line. The method
1.794 +can use either the fast or slow polygon algorithm depending upon the state of aUsage.
1.795 +
1.796 +@param aExists Will be set to false if the line does not pass through the polygon or if
1.797 +a polygon with no vertexes is specified, otherwise ETrue on return.
1.798 +@param aScanLine The scan line to be drawn on. Used to set iScanline
1.799 +@param aStart On return, contains the position on the scan line to start the run.
1.800 +@param aEnd The position on the scan line to end the run, returned.
1.801 +@panic DGDIAdapter 1015, if iUseFastAlgorithm is ETrue (debug only).
1.802 +*/
1.803 +void CSwDirectGdiPolygonFiller::GetNextPixelRunOnSpecifiedScanLine(TBool& aExists,
1.804 + TInt aScanLine,
1.805 + TInt& aStart,
1.806 + TInt& aEnd)
1.807 + {
1.808 + TInt i, j, k;
1.809 +
1.810 + GRAPHICS_ASSERT_DEBUG(!iUseFastAlgorithm, EDirectGdiPanicPolygonFiller);
1.811 +
1.812 + if (aScanLine<iCurrentScanLine || aScanLine>iLastScanLine)
1.813 + {
1.814 + aExists=EFalse;
1.815 + return;
1.816 + }
1.817 +
1.818 + aExists=ETrue;
1.819 + iCurrentScanLine=aScanLine;
1.820 +
1.821 + if (iPolygonIsAllHorizontal)
1.822 + {
1.823 + // set the start after the end
1.824 + aStart=KMinTInt+1;
1.825 + aEnd=KMinTInt;
1.826 + ++iCurrentScanLine;
1.827 + return;
1.828 + }
1.829 +
1.830 + if (iScanLineIntersection==0)
1.831 + {
1.832 + iSlowData.numIntersectionsWithSameFirstPixelMetThisTime=0;
1.833 + iSlowData.numScanLineIntersections=0;
1.834 + iSlowData.scanLineComplete=ETrue;
1.835 +
1.836 + // find the left-most iSlowData::EStoreSize number (or less) of intersections with this scan-line
1.837 + for (i=iFirstVertex; i<iNumVertexes+iFirstVertex; ++i)
1.838 + {
1.839 + TPoint upper=Point(i%iNumVertexes);
1.840 + TPoint lower=Point((i+1)%iNumVertexes);
1.841 + if (upper.iY>lower.iY)
1.842 + {
1.843 + TPoint temp=upper;
1.844 + upper=lower;
1.845 + lower=temp;
1.846 + }
1.847 +
1.848 + if ((iCurrentScanLine>=upper.iY) && (iCurrentScanLine<=lower.iY))
1.849 + {
1.850 + // check that the edge starting at vertex i%iNumVertexes is not horizontal
1.851 + GRAPHICS_ASSERT_DEBUG(upper.iY!=lower.iY, EDirectGdiPanicPolygonFiller);
1.852 +
1.853 + // step through the line-generator until the current scan-line is reached
1.854 + TPoint startPos, endPos;
1.855 + JumpToCurrentScanLine(iSlowData.lineGenerator, upper, lower, startPos, endPos);
1.856 +
1.857 + // find the intersection start and end pixels
1.858 + SSlowScanLineIntersection scanLineIntersection;
1.859 + scanLineIntersection.firstPixel=Min(startPos.iX, endPos.iX);
1.860 + scanLineIntersection.lastPixel=Max(startPos.iX, endPos.iX);
1.861 + scanLineIntersection.firstVertexOfEdge=i%iNumVertexes;
1.862 +
1.863 + // handle horizontal runs and minima/maxima
1.864 + if (upper.iY==iCurrentScanLine)
1.865 + SlowHandleVertexIntersection(scanLineIntersection, i, EFalse);
1.866 + else if (lower.iY==iCurrentScanLine)
1.867 + SlowHandleVertexIntersection(scanLineIntersection, i, ETrue);
1.868 +
1.869 + // see if there have been other intersections with the same first-pixel
1.870 + if (scanLineIntersection.firstPixel==iSlowData.firstPixelOfLastIntersectionInPrevBuffer)
1.871 + ++iSlowData.numIntersectionsWithSameFirstPixelMetThisTime;
1.872 +
1.873 + // if the intersection has not already been included in a previous buffer-load
1.874 + if ((scanLineIntersection.firstPixel>iSlowData.firstPixelOfLastIntersectionInPrevBuffer) ||
1.875 + ((scanLineIntersection.firstPixel==iSlowData.firstPixelOfLastIntersectionInPrevBuffer) &&
1.876 + (iSlowData.numIntersectionsWithSameFirstPixelMetThisTime>=
1.877 + iSlowData.numIntersectionsWithSameFirstPixelPreviouslyMet)))
1.878 + {
1.879 + // put the intersection in the right place in the intersection list (if there is room)
1.880 + for (j=0; j<iSlowData.numScanLineIntersections; ++j)
1.881 + if (scanLineIntersection.firstPixel<iSlowData.scanLineIntersectionList[j].firstPixel)
1.882 + {
1.883 + if (iSlowData.numScanLineIntersections<SSlowData::EStoreSize)
1.884 + ++iSlowData.numScanLineIntersections;
1.885 + else
1.886 + iSlowData.scanLineComplete=EFalse;
1.887 +
1.888 + for (k=iSlowData.numScanLineIntersections-1; k>j; --k)
1.889 + iSlowData.scanLineIntersectionList[k]=iSlowData.scanLineIntersectionList[k-1];
1.890 + iSlowData.scanLineIntersectionList[j]=scanLineIntersection;
1.891 + break;
1.892 + }
1.893 + if (j==iSlowData.numScanLineIntersections)
1.894 + {
1.895 + if (iSlowData.numScanLineIntersections<SSlowData::EStoreSize)
1.896 + iSlowData.scanLineIntersectionList[iSlowData.numScanLineIntersections++]=scanLineIntersection;
1.897 + else
1.898 + iSlowData.scanLineComplete=EFalse;
1.899 + }
1.900 + }
1.901 + }
1.902 + }
1.903 +
1.904 + if (!iSlowData.scanLineComplete)
1.905 + {
1.906 + GRAPHICS_ASSERT_DEBUG(iSlowData.numScanLineIntersections==SSlowData::EStoreSize, EDirectGdiPanicPolygonFiller);
1.907 +
1.908 + if (iSlowData.firstPixelOfLastIntersectionInPrevBuffer==iSlowData.scanLineIntersectionList[SSlowData::EStoreSize-1].firstPixel)
1.909 + iSlowData.numIntersectionsWithSameFirstPixelPreviouslyMet+=SSlowData::EStoreSize-1;
1.910 + else
1.911 + {
1.912 + iSlowData.firstPixelOfLastIntersectionInPrevBuffer=iSlowData.scanLineIntersectionList[SSlowData::EStoreSize-1].firstPixel;
1.913 + iSlowData.numIntersectionsWithSameFirstPixelPreviouslyMet=1;
1.914 + for (i=SSlowData::EStoreSize-1; (i>0) && (iSlowData.firstPixelOfLastIntersectionInPrevBuffer==
1.915 + iSlowData.scanLineIntersectionList[i-1].firstPixel); --i)
1.916 + ++iSlowData.numIntersectionsWithSameFirstPixelPreviouslyMet;
1.917 + }
1.918 + }
1.919 + }
1.920 +
1.921 + // depending on the rule used, find the pixel-run
1.922 + TBool doFill=EFalse; // dummy initialization to prevent compiler warning
1.923 + if (iScanLineIntersection<iSlowData.numScanLineIntersections-1)
1.924 + {
1.925 + switch (iFillRule)
1.926 + {
1.927 + case DirectGdi::EAlternate:
1.928 + iToggler=!iToggler;
1.929 + doFill=iToggler;
1.930 + break;
1.931 + case DirectGdi::EWinding:
1.932 + GRAPHICS_ASSERT_DEBUG(Point(iSlowData.scanLineIntersectionList[iScanLineIntersection].firstVertexOfEdge).iY!=
1.933 + Point((iSlowData.scanLineIntersectionList[iScanLineIntersection].firstVertexOfEdge+1)%iNumVertexes).iY,
1.934 + EDirectGdiPanicPolygonFiller);
1.935 +
1.936 + if (Point(iSlowData.scanLineIntersectionList[iScanLineIntersection].firstVertexOfEdge).iY>
1.937 + Point((iSlowData.scanLineIntersectionList[iScanLineIntersection].firstVertexOfEdge+1)%iNumVertexes).iY)
1.938 + ++iNestingLevel;
1.939 + else
1.940 + --iNestingLevel;
1.941 +
1.942 + doFill=(iNestingLevel!=0);
1.943 + break;
1.944 + }
1.945 +
1.946 + if (doFill)
1.947 + {
1.948 + aStart=Max(iRightMostPixelOnScanLine, iSlowData.scanLineIntersectionList[iScanLineIntersection].lastPixel)+1;
1.949 + aEnd=iSlowData.scanLineIntersectionList[iScanLineIntersection+1].firstPixel-1;
1.950 + }
1.951 + else
1.952 + {
1.953 + // set the start after the end
1.954 + aStart=KMinTInt+1;
1.955 + aEnd=KMinTInt;
1.956 + }
1.957 +
1.958 + if (iRightMostPixelOnScanLine<iSlowData.scanLineIntersectionList[iScanLineIntersection].lastPixel)
1.959 + iRightMostPixelOnScanLine=iSlowData.scanLineIntersectionList[iScanLineIntersection].lastPixel;
1.960 + ++iScanLineIntersection;
1.961 + }
1.962 +
1.963 + if (iScanLineIntersection==iSlowData.numScanLineIntersections-1)
1.964 + {
1.965 + if (iSlowData.scanLineComplete)
1.966 + {
1.967 + GRAPHICS_ASSERT_DEBUG(Point(iSlowData.scanLineIntersectionList[iScanLineIntersection].firstVertexOfEdge).iY!=
1.968 + Point((iSlowData.scanLineIntersectionList[iScanLineIntersection].firstVertexOfEdge+1)%iNumVertexes).iY,
1.969 + EDirectGdiPanicPolygonFiller);
1.970 +
1.971 + switch (iFillRule)
1.972 + {
1.973 + case DirectGdi::EAlternate:
1.974 + iToggler=!iToggler;
1.975 + GRAPHICS_ASSERT_DEBUG(iToggler==0, EDirectGdiPanicPolygonFiller);
1.976 + break;
1.977 + case DirectGdi::EWinding:
1.978 + if (Point(iSlowData.scanLineIntersectionList[iScanLineIntersection].firstVertexOfEdge).iY>
1.979 + Point((iSlowData.scanLineIntersectionList[iScanLineIntersection].firstVertexOfEdge+1)%iNumVertexes).iY)
1.980 + ++iNestingLevel;
1.981 + else
1.982 + --iNestingLevel;
1.983 +
1.984 + GRAPHICS_ASSERT_DEBUG((!iSlowData.scanLineComplete) || (iNumVertexes==2) || (iNestingLevel==0), EDirectGdiPanicPolygonFiller);
1.985 + break;
1.986 + }
1.987 + }
1.988 +
1.989 + iScanLineIntersection=0;
1.990 + if (iSlowData.scanLineComplete)
1.991 + {
1.992 + ++iCurrentScanLine;
1.993 + iRightMostPixelOnScanLine=KMinTInt;
1.994 + iSlowData.numIntersectionsWithSameFirstPixelPreviouslyMet=0;
1.995 + iSlowData.scanLineComplete=EFalse;
1.996 + iSlowData.firstPixelOfLastIntersectionInPrevBuffer=KMinTInt;
1.997 + }
1.998 + }
1.999 + }
1.1000 +
1.1001 +/**
1.1002 +Builds up drawing meta-data in the case where a scanline intersects the active edge at a vertex using
1.1003 +fast algorithms.
1.1004 +
1.1005 +@param aCurrentActiveEdge Index of the current active edge
1.1006 +@param aIsLowerVertex If the vertex is the lower vertex ETrue otherwise EFalse.
1.1007 +@panic DGDIAdapter 1015, if iUseFastAlgorithm is EFalse.
1.1008 +
1.1009 +@see GetNextPixelRun()
1.1010 +*/
1.1011 +void CSwDirectGdiPolygonFiller::FastHandleVertexIntersection(TInt& aCurrentActiveEdge,
1.1012 + TBool aIsLowerVertex)
1.1013 + {
1.1014 + GRAPHICS_ASSERT_DEBUG(iUseFastAlgorithm, EDirectGdiPanicPolygonFiller);
1.1015 +
1.1016 + if (iFastData.vertexList[(iFastData.activeEdgeList[aCurrentActiveEdge].edgePtr->firstVertex+1)%iNumVertexes].iY==iCurrentScanLine)
1.1017 + // it is the second vertex of active-edge aCurrentActiveEdge that coincides with the current scan-line
1.1018 + {
1.1019 + TInt origActiveEdge=aCurrentActiveEdge;
1.1020 + SFastScanLineIntersection scanLineIntersection;
1.1021 + scanLineIntersection.activeEdgePtr=NULL;
1.1022 + SetFastIntersection(iFastData.activeEdgeList[origActiveEdge], scanLineIntersection);
1.1023 +
1.1024 + // walk through subsequent adjacent horizontal active-edges
1.1025 + FOREVER
1.1026 + {
1.1027 + // exit the loop if the vertex-run *is* a maximum or a minimum
1.1028 + const SFastEdge* tempEdgePtr=iFastData.activeEdgeList[(aCurrentActiveEdge+1)%iFastData.numActiveEdges].edgePtr;
1.1029 + TBool isMaxOrMin = EFalse;
1.1030 +
1.1031 + switch(aIsLowerVertex)
1.1032 + {
1.1033 + case EFalse:
1.1034 + isMaxOrMin = (iFastData.vertexList[tempEdgePtr->lowerVertex].iY > iCurrentScanLine);
1.1035 + break;
1.1036 +
1.1037 + case ETrue:
1.1038 + isMaxOrMin = (iFastData.vertexList[tempEdgePtr->upperVertex].iY < iCurrentScanLine);
1.1039 + break;
1.1040 + }
1.1041 +
1.1042 + if (isMaxOrMin)
1.1043 + // the vertex-run is a maximum or a minimum
1.1044 + {
1.1045 + if (aIsLowerVertex)
1.1046 + {
1.1047 + *iFastData.activeEdgeList[origActiveEdge].scanLineIntersectionPtr=scanLineIntersection;
1.1048 + iFastData.activeEdgeList[origActiveEdge].scanLineIntersectionPtr->activeEdgePtr=&iFastData.activeEdgeList[origActiveEdge];
1.1049 + }
1.1050 + else
1.1051 + {
1.1052 + // add an intersection
1.1053 + iFastData.scanLineIntersectionList[iFastData.numScanLineIntersections]=scanLineIntersection;
1.1054 + iFastData.scanLineIntersectionList[iFastData.numScanLineIntersections].activeEdgePtr=&iFastData.activeEdgeList[origActiveEdge];
1.1055 + iFastData.activeEdgeList[origActiveEdge].scanLineIntersectionPtr=&iFastData.scanLineIntersectionList[iFastData.numScanLineIntersections];
1.1056 + ++iFastData.numScanLineIntersections;
1.1057 + }
1.1058 + break;
1.1059 + }
1.1060 +
1.1061 + // the active-edge is horizontal, or the vertex-run is not a maximum or a minimum
1.1062 +
1.1063 + ++aCurrentActiveEdge;
1.1064 + GRAPHICS_ASSERT_DEBUG(aCurrentActiveEdge<iFastData.numActiveEdges, EDirectGdiPanicPolygonFiller);
1.1065 +
1.1066 + // update scanLineIntersection
1.1067 + TPoint startPos, endPos;
1.1068 + TInt minX, maxX;
1.1069 + iFastData.activeEdgeList[aCurrentActiveEdge].lineGenerator.SingleScanline(startPos, endPos);
1.1070 + minX=Min(startPos.iX, endPos.iX);
1.1071 + maxX=Max(startPos.iX, endPos.iX);
1.1072 + if (scanLineIntersection.firstPixel>minX)
1.1073 + scanLineIntersection.firstPixel=minX;
1.1074 + if (scanLineIntersection.lastPixel<maxX)
1.1075 + scanLineIntersection.lastPixel=maxX;
1.1076 +
1.1077 + // exit the loop if the vertex-run is *not* a maximum or a minimum
1.1078 + tempEdgePtr=iFastData.activeEdgeList[aCurrentActiveEdge].edgePtr;
1.1079 + TBool isNeitherMaxOrMin = EFalse;
1.1080 +
1.1081 + switch(aIsLowerVertex)
1.1082 + {
1.1083 + case EFalse:
1.1084 + isNeitherMaxOrMin = (iFastData.vertexList[tempEdgePtr->upperVertex].iY < iCurrentScanLine);
1.1085 + break;
1.1086 +
1.1087 + case ETrue:
1.1088 + isNeitherMaxOrMin = (iFastData.vertexList[tempEdgePtr->lowerVertex].iY > iCurrentScanLine);
1.1089 + break;
1.1090 + }
1.1091 +
1.1092 + // exit the loop if the vertex-run is *not* a maximum or a minimum
1.1093 + if (isNeitherMaxOrMin)
1.1094 + {
1.1095 + TInt newActiveEdge;
1.1096 + TInt oldActiveEdge;
1.1097 + if (aIsLowerVertex)
1.1098 + {
1.1099 + newActiveEdge=aCurrentActiveEdge;
1.1100 + oldActiveEdge=origActiveEdge;
1.1101 + }
1.1102 + else
1.1103 + {
1.1104 + newActiveEdge=origActiveEdge;
1.1105 + oldActiveEdge=aCurrentActiveEdge;
1.1106 + }
1.1107 + iFastData.activeEdgeList[newActiveEdge].scanLineIntersectionPtr=iFastData.activeEdgeList[oldActiveEdge].scanLineIntersectionPtr;
1.1108 + iFastData.activeEdgeList[oldActiveEdge].scanLineIntersectionPtr=NULL;
1.1109 + *iFastData.activeEdgeList[newActiveEdge].scanLineIntersectionPtr=scanLineIntersection;
1.1110 + iFastData.activeEdgeList[newActiveEdge].scanLineIntersectionPtr->activeEdgePtr=&iFastData.activeEdgeList[newActiveEdge];
1.1111 + break;
1.1112 + }
1.1113 + }
1.1114 + }
1.1115 + else
1.1116 + // it is the first vertex of active-edge aCurrentActiveEdge that coincides with the current scan-line
1.1117 + {
1.1118 +#if defined(_DEBUG)
1.1119 + // check that the vertex we are at is a maximum or a minimum
1.1120 + TInt previousNotLevelVertex;
1.1121 + TInt SFastEdge::*vertex=(aIsLowerVertex)? &SFastEdge::lowerVertex: &SFastEdge::upperVertex;
1.1122 + for (previousNotLevelVertex=iFastData.activeEdgeList[aCurrentActiveEdge].edgePtr->*vertex;
1.1123 + iFastData.vertexList[iFastData.activeEdgeList[aCurrentActiveEdge].edgePtr->*vertex].iY==iFastData.vertexList[previousNotLevelVertex].iY;
1.1124 + previousNotLevelVertex=(previousNotLevelVertex+iNumVertexes-1)%iNumVertexes)
1.1125 + ;
1.1126 + TInt nextNotLevelVertex=(iFastData.activeEdgeList[aCurrentActiveEdge].edgePtr->*vertex+1)%iNumVertexes;
1.1127 + GRAPHICS_ASSERT_DEBUG((iFastData.vertexList[iFastData.activeEdgeList[aCurrentActiveEdge].edgePtr->*vertex].iY>iFastData.vertexList[previousNotLevelVertex].iY)==
1.1128 + (iFastData.vertexList[iFastData.activeEdgeList[aCurrentActiveEdge].edgePtr->*vertex].iY>iFastData.vertexList[nextNotLevelVertex].iY),
1.1129 + EDirectGdiPanicPolygonFiller);
1.1130 +#endif
1.1131 +
1.1132 + if (aIsLowerVertex)
1.1133 + SetFastIntersection(iFastData.activeEdgeList[aCurrentActiveEdge],*iFastData.activeEdgeList[aCurrentActiveEdge].scanLineIntersectionPtr);
1.1134 + else
1.1135 + {
1.1136 + // add an intersection
1.1137 + SetFastIntersection(iFastData.activeEdgeList[aCurrentActiveEdge], iFastData.scanLineIntersectionList[iFastData.numScanLineIntersections]);
1.1138 + iFastData.scanLineIntersectionList[iFastData.numScanLineIntersections].activeEdgePtr=&iFastData.activeEdgeList[aCurrentActiveEdge];
1.1139 + iFastData.activeEdgeList[aCurrentActiveEdge].scanLineIntersectionPtr=&iFastData.scanLineIntersectionList[iFastData.numScanLineIntersections];
1.1140 + ++iFastData.numScanLineIntersections;
1.1141 + }
1.1142 + }
1.1143 + }
1.1144 +
1.1145 +/**
1.1146 +Calculates the extent of the intersection for the current active edge.
1.1147 +
1.1148 +@param aActiveEdge The current active edge.
1.1149 +@param aScanLineIntersection On return, contains the intersection data.
1.1150 +*/
1.1151 +void CSwDirectGdiPolygonFiller::SetFastIntersection(SFastActiveEdge& aActiveEdge, SFastScanLineIntersection& aScanLineIntersection)
1.1152 + {
1.1153 + GRAPHICS_ASSERT_DEBUG(iUseFastAlgorithm, EDirectGdiPanicPolygonFiller);
1.1154 +
1.1155 + TPoint startPos, endPos;
1.1156 +
1.1157 + aActiveEdge.lineGenerator.SingleScanline(startPos, endPos);
1.1158 + aScanLineIntersection.firstPixel=Min(startPos.iX, endPos.iX);
1.1159 + aScanLineIntersection.lastPixel=Max(startPos.iX, endPos.iX);
1.1160 + }
1.1161 +
1.1162 +/**
1.1163 +Builds up drawing meta-data in the case where a scanline intersects the active edge at a vertex using
1.1164 +slow algorithms.
1.1165 +
1.1166 +@param aScanLineIntersection Reference to the current intersection data.
1.1167 +@param aVertexStartingCurrentEdge Current vertex.
1.1168 +@param aIsLowerVertex If the vertex is the lower vertex ETrue otherwise EFalse.
1.1169 +@see GetNextPixelRunOnSpecifiedScanLine()
1.1170 +*/
1.1171 +void CSwDirectGdiPolygonFiller::SlowHandleVertexIntersection(SSlowScanLineIntersection& aScanLineIntersection,
1.1172 + TInt& aVertexStartingCurrentEdge,
1.1173 + TBool aIsLowerVertex)
1.1174 + {
1.1175 + if (Point((aVertexStartingCurrentEdge+1)%iNumVertexes).iY==iCurrentScanLine)
1.1176 + // it is the second vertex of the edge starting at vertex aVertexStartingCurrentEdge%iNumVertexes
1.1177 + // that coincides with the current scan-line
1.1178 + {
1.1179 + // walk through subsequent adjacent horizontal active-edges
1.1180 + for (; ; )
1.1181 + {
1.1182 + TPoint nextVertexButOne=Point((aVertexStartingCurrentEdge+2)%iNumVertexes);
1.1183 + TBool isMaxOrMin = EFalse;
1.1184 +
1.1185 + switch(aIsLowerVertex)
1.1186 + {
1.1187 + case EFalse:
1.1188 + isMaxOrMin = (nextVertexButOne.iY > iCurrentScanLine);
1.1189 + break;
1.1190 +
1.1191 + case ETrue:
1.1192 + isMaxOrMin = (nextVertexButOne.iY < iCurrentScanLine);
1.1193 + break;
1.1194 + }
1.1195 +
1.1196 + // exit the loop if the vertex-run *is* a maximum or a minimum
1.1197 + if (isMaxOrMin)
1.1198 + {
1.1199 + break;
1.1200 + }
1.1201 +
1.1202 + // the edge starting at vertex aVertexStartingCurrentEdge%iNumVertexes is horizontal, or the vertex-run is not a
1.1203 + // maximum or a minimum
1.1204 +
1.1205 + ++aVertexStartingCurrentEdge;
1.1206 + GRAPHICS_ASSERT_DEBUG(aVertexStartingCurrentEdge%iNumVertexes!=iFirstVertex, EDirectGdiPanicPolygonFiller);
1.1207 +
1.1208 + // step through the line-generator until the current scan-line is reached
1.1209 + TPoint upper=Point(aVertexStartingCurrentEdge%iNumVertexes);
1.1210 + TPoint lower=nextVertexButOne;
1.1211 + if (upper.iY>lower.iY)
1.1212 + {
1.1213 + TPoint temp=upper;
1.1214 + upper=lower;
1.1215 + lower=temp;
1.1216 + }
1.1217 +
1.1218 + TPoint startPos, endPos;
1.1219 + if (upper.iY!=lower.iY)
1.1220 + JumpToCurrentScanLine(iSlowData.lineGenerator, upper, lower, startPos, endPos);
1.1221 + else
1.1222 + {
1.1223 + // 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
1.1224 + startPos=upper;
1.1225 + endPos=lower;
1.1226 + }
1.1227 +
1.1228 + // expand the intersection, if necessary
1.1229 + TInt minX=Min(startPos.iX, endPos.iX);
1.1230 + TInt maxX=Max(startPos.iX, endPos.iX);
1.1231 + if (aScanLineIntersection.firstPixel>minX)
1.1232 + aScanLineIntersection.firstPixel=minX;
1.1233 + if (aScanLineIntersection.lastPixel<maxX)
1.1234 + aScanLineIntersection.lastPixel=maxX;
1.1235 +
1.1236 + TBool isNeitherMaxOrMin = EFalse;
1.1237 +
1.1238 + switch(aIsLowerVertex)
1.1239 + {
1.1240 + case EFalse:
1.1241 + isNeitherMaxOrMin = (nextVertexButOne.iY < iCurrentScanLine);
1.1242 + break;
1.1243 +
1.1244 + case ETrue:
1.1245 + isNeitherMaxOrMin = (nextVertexButOne.iY > iCurrentScanLine);
1.1246 + break;
1.1247 + }
1.1248 +
1.1249 + // exit the loop if the vertex-run is *not* a maximum or a minimum
1.1250 + if (isNeitherMaxOrMin)
1.1251 + {
1.1252 + if (aIsLowerVertex)
1.1253 + {
1.1254 + aScanLineIntersection.firstVertexOfEdge=aVertexStartingCurrentEdge%iNumVertexes;
1.1255 + }
1.1256 + break;
1.1257 + }
1.1258 + }
1.1259 + }
1.1260 + else
1.1261 + // it is the first vertex of the edge starting at vertex aVertexStartingCurrentEdge%iNumVertexes
1.1262 + // that coincides with the current scan-line
1.1263 + {
1.1264 +#if defined(_DEBUG)
1.1265 + // check that the vertex we are at is a maximum or a minimum
1.1266 + TInt previousNotLevelVertex;
1.1267 + for (previousNotLevelVertex=aVertexStartingCurrentEdge%iNumVertexes;
1.1268 + Point(aVertexStartingCurrentEdge%iNumVertexes).iY==
1.1269 + Point(previousNotLevelVertex).iY;
1.1270 + previousNotLevelVertex=(previousNotLevelVertex+iNumVertexes-1)%iNumVertexes)
1.1271 + ;
1.1272 + TInt nextNotLevelVertex=(aVertexStartingCurrentEdge+1)%iNumVertexes;
1.1273 + TInt previousY=Point(previousNotLevelVertex).iY;
1.1274 + TInt currentY=Point(aVertexStartingCurrentEdge%iNumVertexes).iY;
1.1275 + TInt nextY=Point(nextNotLevelVertex).iY;
1.1276 + GRAPHICS_ASSERT_DEBUG((currentY>previousY) == (currentY>nextY), EDirectGdiPanicPolygonFiller);
1.1277 +#endif
1.1278 + }
1.1279 + }
1.1280 +
1.1281 +/**
1.1282 +For a given line between two given endpoints, calculate the right and leftmost pixels of the line segment
1.1283 +that fall on the current scanline.
1.1284 +
1.1285 +@param aLineGenerator Reference to class used to calculate the pixels on the line.
1.1286 +@param aUpper The upper endpoint of the line.
1.1287 +@param aLower The lower endpoint of the line.
1.1288 +@param aStartPos On return, contains the position of the line's leftmost pixel on the current scanline.
1.1289 +@param aEndPos On return, contains the position of the line's rightmost pixel on the current scanline.
1.1290 +*/
1.1291 +void CSwDirectGdiPolygonFiller::JumpToCurrentScanLine(TLinearDDA& aLineGenerator,
1.1292 + const TPoint& aUpper,
1.1293 + const TPoint& aLower,
1.1294 + TPoint& aStartPos,
1.1295 + TPoint& aEndPos) const
1.1296 + {
1.1297 + GRAPHICS_ASSERT_DEBUG(aUpper.iY<=aLower.iY, EDirectGdiPanicPolygonFiller);
1.1298 + aLineGenerator.Construct(aUpper, aLower);
1.1299 + if (aUpper.iY<iCurrentScanLine)
1.1300 + {
1.1301 + TInt notUsed;
1.1302 + aLineGenerator.JumpToYCoord(notUsed, iCurrentScanLine-2);
1.1303 + }
1.1304 + do
1.1305 + aLineGenerator.SingleScanline(aStartPos, aEndPos);
1.1306 + while (aStartPos.iY!=iCurrentScanLine);
1.1307 + GRAPHICS_ASSERT_DEBUG(aStartPos.iY==iCurrentScanLine, EDirectGdiPanicPolygonFiller);
1.1308 + GRAPHICS_ASSERT_DEBUG(aEndPos.iY==iCurrentScanLine, EDirectGdiPanicPolygonFiller);
1.1309 + }
1.1310 +
1.1311 +/**
1.1312 +Returns the point data for a given index.
1.1313 +
1.1314 +@param aIndex The index.
1.1315 +@return The point data.
1.1316 +*/
1.1317 +const TPoint& CSwDirectGdiPolygonFiller::Point(TInt aIndex)
1.1318 + {
1.1319 + GRAPHICS_ASSERT_DEBUG(iPointArray,EDirectGdiPanicPolygonFiller);
1.1320 + return((*iPointArray)[aIndex]);
1.1321 + }
1.1322 +