--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/graphicsdeviceinterface/directgdiadaptation/swsrc/swdirectgdiline.cpp Tue Feb 02 01:47:50 2010 +0200
@@ -0,0 +1,620 @@
+// Copyright (c) 2007-2009 Nokia Corporation and/or its subsidiary(-ies).
+// All rights reserved.
+// This component and the accompanying materials are made available
+// under the terms of "Eclipse Public License v1.0"
+// which accompanies this distribution, and is available
+// at the URL "http://www.eclipse.org/legal/epl-v10.html".
+//
+// Initial Contributors:
+// Nokia Corporation - initial contribution.
+//
+// Contributors:
+//
+// Description:
+//
+
+#include "swdirectgdiengine.h"
+#include "swdirectgdipolygon.h"
+
+/**
+@see MDirectGdiEngine::DrawLine()
+*/
+void CSwDirectGdiEngine::DrawLine(const TPoint& aPt1,const TPoint& aPt2)
+ {
+ DoDrawLine(aPt1,aPt2,ETrue);
+ }
+
+/**
+@see MDirectGdiEngine::DrawLineTo()
+*/
+void CSwDirectGdiEngine::DrawLineTo(const TPoint& aPoint)
+ {
+ DrawLine(iLinePosition,aPoint);
+ }
+
+
+/**
+@see MDirectGdiEngine::DrawLineBy()
+*/
+void CSwDirectGdiEngine::DrawLineBy(const TPoint& aVector)
+ {
+ DrawLine(iLinePosition,iLinePosition + aVector);
+ }
+
+/**
+@see MDirectGdiEngine::DrawPolyLine()
+
+@panic DGDIAdapter 27, if the passed point list has too few points (debug only).
+*/
+void CSwDirectGdiEngine::DrawPolyLine(const TArray<TPoint>& aPointList)
+ {
+ DrawPolyLineNoEndPoint(aPointList);
+
+ if (iPenStyle == DirectGdi::ESolidPen)
+ {
+ Plot(aPointList[aPointList.Count()-1]);
+ }
+ }
+
+/**
+@see MDirectGdiEngine::DrawPolyLineNoEndPoint()
+
+@panic DGDIAdapter 27, if the passed point list has too few points (debug only).
+*/
+void CSwDirectGdiEngine::DrawPolyLineNoEndPoint(const TArray<TPoint>& aPointList)
+ {
+ GRAPHICS_ASSERT_DEBUG(aPointList.Count() > 0, EDirectGdiPanicInvalidPointArray);
+
+ const TInt vertexes = aPointList.Count()-1;
+
+ for (TInt count = 0; count < vertexes; count++)
+ {
+ DrawLine(aPointList[count], aPointList[count + 1]);
+ }
+ }
+
+/**
+@see MDirectGdiEngine::DrawPolygon()
+*/
+void CSwDirectGdiEngine::DrawPolygon(const TArray<TPoint>& aPointList, DirectGdi::TFillRule aFillRule)
+ {
+ const TInt numpoints = aPointList.Count();
+
+ if (iBrushStyle != DirectGdi::ENullBrush)
+ {
+ TRect pointrect(0,0,0,0);
+ TRect truncrect(0,0,0,0);
+ TBool largepolygon = EFalse;
+
+ for (TInt count = 0; count < numpoints; count++)
+ {
+ pointrect.iTl = aPointList[count] + iOrigin;
+ truncrect.iTl = pointrect.iTl;
+ TruncateRect(truncrect);
+
+ if (pointrect.iTl != truncrect.iTl)
+ {
+ largepolygon = ETrue;
+ break;
+ }
+ }
+
+ if (largepolygon)
+ {
+ PolyFillLarge(&aPointList, aFillRule);
+ }
+ else
+ {
+ PolyFill(&aPointList, aFillRule);
+ }
+ }
+
+ if (iPenStyle != DirectGdi::ENullPen)
+ {
+ if (iPenSize.iWidth > 0 && iPenSize.iHeight > 0)
+ {
+ PolyOutline(&aPointList);
+ }
+ }
+ }
+
+/**
+Draws a straight line from the start to the end position using current pen size, colour and style.
+
+@param aPt1 Start position.
+@param aPt2 End position.
+@param aDrawStartPoint If ETrue, draws the first pixel of the line.
+
+@post The internal drawing position is set to the line's endpoint.
+@see CSwDirectGdiEngine::DrawLine()
+*/
+void CSwDirectGdiEngine::DoDrawLine(TPoint aPt1, TPoint aPt2, TBool aDrawStartPoint)
+ {
+ iLinePosition = aPt2;
+
+ if ((aPt1 == aPt2))
+ {
+ return;
+ }
+
+ aPt1 += iOrigin;
+ aPt2 += iOrigin;
+
+ TRect temp(aPt1,aPt2);
+ temp.Normalize();
+ temp.Grow(iPenSize.iWidth, iPenSize.iHeight);
+
+ TRect screenRect;
+ iDrawDevice->GetDrawRect(screenRect);
+ screenRect.Grow(iPenSize.iWidth, iPenSize.iHeight);
+
+ const TInt dotParam = iDotParam;
+ TPoint plotpt(0,0);
+ const CGraphicsContext::TDrawMode drawMode = GcDrawMode(iDrawMode);
+
+ TRect clipRect(0,0,0,0);
+ for (TInt count = 0; count < iDefaultRegionPtr->Count(); count++)
+ {
+ iDotParam = dotParam;
+ clipRect = (*iDefaultRegionPtr)[count];
+
+ if (!clipRect.Intersects(temp))
+ {
+ TLinearDDA line;
+ line.Construct(aPt1,aPt2);
+ line.JumpToRect(screenRect);
+ if (iPenStyle != DirectGdi::ESolidPen)
+ {
+ while (!line.SingleStep(plotpt))
+ {
+ iDotParam += iDotDirection;
+ }
+ }
+ continue;
+ }
+
+ clipRect.Intersection(temp);
+
+ if ((iPenSize.iWidth > 1 || iPenSize.iHeight > 1) && (iPenStyle == DirectGdi::ESolidPen)) // wide solid line
+ {
+ DoDrawSolidWideLine(aPt1, aPt2, aDrawStartPoint, screenRect, clipRect);
+ }
+ else if (iPenSize.iWidth > 1 || iPenSize.iHeight > 1) // dotted line
+ {
+ DoDrawDottedWideLine(aPt1, aPt2, aDrawStartPoint, screenRect, clipRect);
+ }
+ else if (iPenStyle != DirectGdi::ESolidPen) // single pixel dotted line
+ {
+ TLinearDDA line;
+ line.Construct(aPt1,aPt2);
+ line.JumpToRect(screenRect);
+
+ iDotParam = dotParam;
+ if (!aDrawStartPoint)
+ {
+ line.SingleStep(plotpt);
+ iDotParam += iDotDirection;
+ }
+
+ while (!line.SingleStep(plotpt))
+ {
+ PenDrawClipped(plotpt, clipRect);
+ iDotParam += iDotDirection;
+ }
+ }
+ else if (aPt1.iY == aPt2.iY &&
+ (aPt1.iY >= clipRect.iTl.iY &&
+ aPt1.iY < clipRect.iBr.iY))
+ { // single pixel solid horizontal line
+ TInt start = Min(aPt1.iX,aPt2.iX + 1);
+ TInt length = Abs(aPt2.iX - aPt1.iX);
+
+ if (!aDrawStartPoint)
+ {
+ if (aPt1.iX < aPt2.iX)
+ {
+ start++;
+ }
+ else
+ {
+ length--;
+ }
+ }
+ if (start < clipRect.iTl.iX)
+ {
+ length += start - clipRect.iTl.iX;
+ start = clipRect.iTl.iX;
+ }
+ if ( (start + length) > clipRect.iBr.iX)
+ {
+ length = clipRect.iBr.iX - start;
+ }
+
+ if (length > 0)
+ {
+ iDrawDevice->WriteRgbMulti(start, aPt1.iY, length, 1, iPenColor, drawMode);
+ }
+ }
+ else if (aPt1.iX == aPt2.iX && (aPt1.iX >= clipRect.iTl.iX && aPt1.iX < clipRect.iBr.iX))
+ { // single pixel solid vertical line
+ TInt start = Min(aPt1.iY,aPt2.iY + 1);
+ TInt length = Abs(aPt2.iY - aPt1.iY);
+
+ if (!aDrawStartPoint)
+ {
+ if (aPt1.iY < aPt2.iY)
+ {
+ start++;
+ }
+ else
+ {
+ length--;
+ }
+ }
+
+ if (start < clipRect.iTl.iY)
+ {
+ length += start - clipRect.iTl.iY;
+ start = clipRect.iTl.iY;
+ }
+ if (start + length > clipRect.iBr.iY)
+ {
+ length = clipRect.iBr.iY - start;
+ }
+
+ if (length > 0)
+ {
+ iDrawDevice->WriteRgbMulti(aPt1.iX,start,1,length,iPenColor, drawMode);
+ }
+ }
+ else
+ { // single pixel solid diagonal line
+ TLinearDDA line;
+ line.Construct(aPt1,aPt2);
+
+ line.JumpToRect(screenRect);
+
+ if (!aDrawStartPoint)
+ {
+ line.SingleStep(plotpt);
+ }
+
+ while (!line.SingleStep(plotpt))
+ {
+ if (clipRect.Contains(plotpt))
+ {
+ iDrawDevice->WriteRgb(plotpt.iX, plotpt.iY, iPenColor, drawMode);
+ }
+ }
+ }
+
+ iDrawDevice->UpdateRegion(clipRect);
+ }
+ }
+
+/**
+Draws a straight line from the start to the end position using pen sizes larger than 1x1 pixel.
+
+@param aPt1 Start position.
+@param aPt2 End position.
+@param aDrawStartPoint If ETrue, draws the first pixel of the line.
+@param aScreenRect Rectangle representing the screen boundary.
+@param aClipRect The rectangle to which the line is clipped.
+@see CSwDirectGdiEngine::DrawLine()
+*/
+void CSwDirectGdiEngine::DoDrawSolidWideLine(const TPoint& aPt1,
+ const TPoint& aPt2,
+ TBool aDrawStartPoint,
+ const TRect& aScreenRect,
+ TRect aClipRect)
+ {
+ CFbsDrawDevice* drawDevice = iDrawDevice;
+
+ TLinearDDA line;
+ line.Construct(aPt1,aPt2);
+
+ TPoint plotpt(aPt1);
+ line.JumpToRect(aScreenRect);
+ if (!aDrawStartPoint)
+ line.SingleStep(plotpt);
+
+ TInt* deferred = NULL;
+ const TInt doubleheight = iPenSize.iHeight << 1;
+
+ if (iPenArray)
+ {
+ deferred = new TInt[doubleheight];
+ }
+
+ if (!iPenArray || !deferred)
+ {
+ while (!line.SingleStep(plotpt))
+ PenDrawClipped(plotpt, aClipRect);
+ }
+ else
+ {
+ const TBool down = (aPt2.iY >= aPt1.iY);
+
+ for (TInt fillcount = 0; fillcount < doubleheight; )
+ {
+ deferred[fillcount++] = KMaxTInt;
+ deferred[fillcount++] = KMinTInt;
+ }
+
+ TInt nextline = 0;
+ TInt nexty = plotpt.iY;
+ if (down)
+ {
+ nexty -= ((iPenSize.iHeight - 1) >> 1);
+ }
+ else
+ {
+ nexty += (iPenSize.iHeight >> 1);
+ }
+
+ TInt lasty = plotpt.iY;
+
+ while (!line.SingleStep(plotpt))
+ {
+ if (plotpt.iY != lasty)
+ {
+ if (nexty >= aClipRect.iTl.iY && nexty < aClipRect.iBr.iY)
+ {
+ TInt left = deferred[nextline];
+ TInt right = deferred[nextline + 1];
+ if (left < aClipRect.iTl.iX)
+ {
+ left = aClipRect.iTl.iX;
+ }
+ if (right >= aClipRect.iBr.iX)
+ {
+ right = aClipRect.iBr.iX - 1;
+ }
+
+ if (left <= right)
+ {
+ drawDevice->WriteRgbMulti(left,nexty,right - left + 1,1,iPenColor,CGraphicsContext::EDrawModePEN);
+ }
+ }
+
+ if (down)
+ {
+ nexty++;
+ }
+ else
+ {
+ nexty--;
+ }
+
+ lasty = plotpt.iY;
+ deferred[nextline++] = KMaxTInt;
+ deferred[nextline++] = KMinTInt;
+ if (nextline == doubleheight)
+ {
+ nextline = 0;
+ }
+ }
+
+ PenDrawDeferred(plotpt,deferred,nextline);
+ }
+
+ for (TInt restofline = 0; restofline < doubleheight; restofline += 2,nextline += 2)
+ {
+ if (nextline == doubleheight)
+ nextline = 0;
+
+ if (nexty >= aClipRect.iTl.iY && nexty < aClipRect.iBr.iY)
+ {
+ TInt left = deferred[nextline];
+ TInt right = deferred[nextline+1];
+ if (left < aClipRect.iTl.iX)
+ {
+ left = aClipRect.iTl.iX;
+ }
+ if (right >= aClipRect.iBr.iX)
+ {
+ right = aClipRect.iBr.iX-1;
+ }
+
+ if (left <= right)
+ {
+ drawDevice->WriteRgbMulti(left,nexty,right - left + 1,1,iPenColor,CGraphicsContext::EDrawModePEN);
+ }
+ }
+
+ if (down)
+ {
+ nexty++;
+ }
+ else
+ {
+ nexty--;
+ }
+ }
+
+ delete[] deferred;
+ }
+ }
+
+/**
+Draws a dotted straight line from the start to the end position using pen sizes larger than 1x1 pixel.
+
+@param aPt1 Start position.
+@param aPt2 End position.
+@param aDrawStartPoint If ETrue, draws the first pixel of the line.
+@param aScreenRect Rectangle representing the screen boundary.
+@param aClipRect The rectangle to which the line is clipped.
+@see CSwDirectGdiEngine::DrawLine()
+*/
+void CSwDirectGdiEngine::DoDrawDottedWideLine(const TPoint& aPt1,
+ const TPoint& aPt2,
+ TBool aDrawStartPoint,
+ const TRect& aScreenRect,
+ TRect aClipRect)
+ {
+ TLinearDDA line;
+ line.Construct(aPt1,aPt2);
+
+ TPoint plotpt(aPt1);
+ line.JumpToRect(aScreenRect);
+ if (!aDrawStartPoint)
+ {
+ line.SingleStep(plotpt);
+ iDotParam += iDotDirection;
+ }
+
+ const TInt maxdim = Max(iPenSize.iWidth, iPenSize.iHeight);
+
+ TBool done = EFalse;
+ while (!done)
+ {
+ while (!done && !(iDotMask & (1 << ((iDotParam / maxdim) % iDotLength))))
+ {
+ done = line.SingleStep(plotpt);
+ iDotParam += iDotDirection;
+ }
+
+ TPoint startdash(plotpt);
+ TPoint enddash(plotpt);
+
+ while (!done && (iDotMask & (1 << ((iDotParam / maxdim) % iDotLength))))
+ {
+ enddash = plotpt;
+ done = line.SingleStep(plotpt);
+ iDotParam += iDotDirection;
+ }
+
+ DoDrawSolidWideLine(startdash,enddash,ETrue,aScreenRect,aClipRect);
+ }
+ }
+
+/**
+Fills a polygon defined using an array of points. The first point in the array defines the
+start of the first side of the polygon. The final side of the polygon is drawn using the last point
+from the array. The area is filled with the current brush settings.
+
+Self-crossing polygons are filled according to the specified fill rule.
+
+@param aPointList Array of points specifying the vertices of the polygon.
+@param aFillRule Polygon filling rule.
+*/
+void CSwDirectGdiEngine::PolyFill(const TArray<TPoint>* aPointList, DirectGdi::TFillRule aFillRule)
+ {
+ TBool exists;
+ TInt scanline;
+ TInt pixelRunStart;
+ TInt pixelRunEnd;
+
+ TRect clipRect(0,0,0,0);
+ const TInt limit = iDefaultRegionPtr->Count();
+ for (TInt count = 0; count < limit; count++)
+ {
+ clipRect = (*iDefaultRegionPtr)[count];
+ CSwDirectGdiPolygonFiller polyfill;
+ polyfill.Construct(aPointList,aFillRule);
+
+ for(polyfill.GetNextPixelRun(exists,scanline,pixelRunStart,pixelRunEnd);exists;
+ polyfill.GetNextPixelRun(exists,scanline,pixelRunStart,pixelRunEnd))
+ {
+ TPoint start(pixelRunStart, scanline);
+ TPoint end(pixelRunEnd, scanline);
+ start += iOrigin;
+ end += iOrigin;
+ ClipFillLine(start,end,clipRect);
+ }
+
+ polyfill.Reset();
+ iDrawDevice->UpdateRegion(clipRect);
+ }
+ }
+
+
+/**
+Fills a polygon defined using an array of points. The first point in the array defines the
+start of the first side of the polygon. The final side of the polygon is drawn using the last point
+from the array. The area is filled with the current brush settings. Optimized for polygons that are
+much larger than the screen.
+
+Self-crossing polygons are filled according to the specified fill rule.
+
+@param aPointList Array of points specifying the vertices of the polygon.
+@param aFillRule Polygon filling rule.
+*/
+void CSwDirectGdiEngine::PolyFillLarge(const TArray<TPoint>* aPointList, DirectGdi::TFillRule aFillRule)
+ {
+ TBool exists;
+ TInt pixelRunStart;
+ TInt pixelRunEnd;
+
+ TRect clipRect(0,0,0,0);
+ const TInt limit = iDefaultRegionPtr->Count();
+ for (TInt count = 0; count < limit; count++)
+ {
+ clipRect = (*iDefaultRegionPtr)[count];
+ CSwDirectGdiPolygonFiller polyfill;
+ polyfill.Construct(aPointList,aFillRule,CSwDirectGdiPolygonFiller::EGetPixelRunsSequentiallyForSpecifiedScanLines);
+ TInt clipRectOffsetStart = clipRect.iTl.iY - iOrigin.iY;
+ TInt clipRectOffsetEnd = clipRect.iBr.iY - iOrigin.iY;
+
+ for (TInt scanline = clipRectOffsetStart; scanline < clipRectOffsetEnd; scanline++)
+ {
+ polyfill.GetNextPixelRunOnSpecifiedScanLine(exists,scanline,pixelRunStart,pixelRunEnd);
+ while (exists)
+ {
+ TPoint start(pixelRunStart,scanline);
+ TPoint end(pixelRunEnd,scanline);
+ start += iOrigin;
+ end += iOrigin;
+ ClipFillLine(start,end,clipRect);
+ polyfill.GetNextPixelRunOnSpecifiedScanLine(exists,scanline,pixelRunStart,pixelRunEnd);
+ }
+ }
+
+ polyfill.Reset();
+ iDrawDevice->UpdateRegion(clipRect);
+ }
+ }
+
+/**
+Draws a polygon defined by an array of points using the current pen settings. The first point in the array defines the
+start of the first side of the polygon. The final side of the polygon is drawn using the last point
+from the array, and the line is drawn to the start point of the first side.
+
+@param aPointList List of points specifying the vertices of the polygon.
+*/
+void CSwDirectGdiEngine::PolyOutline(const TArray<TPoint>* aPointList)
+ {
+ const TInt vertexes = aPointList->Count();
+
+ for (TInt count = 0; count < vertexes; count++)
+ {
+ TPoint point1((*aPointList)[count]);
+ TPoint point2((*aPointList)[(count + 1) % vertexes]);
+
+ if (point1.iY < point2.iY)
+ {
+ DoDrawLine(point1,point2,ETrue);
+ }
+ else
+ {
+ iDotDirection = -1;
+ iDotParam += Max(Abs(point2.iX - point1.iX),Abs(point2.iY - point1.iY));
+ const TInt dotParam = iDotParam;
+ DoDrawLine(point2,point1,EFalse);
+
+ if (Abs(point2.iX - point1.iX) > Abs(point2.iY - point1.iY))
+ {
+ if (iPenStyle == DirectGdi::ESolidPen || (iDotMask & (1 << ((iDotParam / iPenSize.iWidth) % iDotLength))))
+ DoPlot((*aPointList)[count]);
+ }
+ else
+ {
+ if (iPenStyle == DirectGdi::ESolidPen || (iDotMask & (1 << ((iDotParam / iPenSize.iHeight) % iDotLength))))
+ DoPlot((*aPointList)[count]);
+ }
+
+ iDotDirection = 1;
+ iDotParam = dotParam;
+ }
+ }
+ }