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