|
1 // Copyright (c) 2007-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 "directgdiadapter.h" |
|
17 #include "swdirectgdiellipse.h" |
|
18 #include "swdirectgdiengine.h" |
|
19 |
|
20 /* |
|
21 * TSwDirectGdiEllipse |
|
22 */ |
|
23 |
|
24 /** |
|
25 Initialises the values of the ellipse so that it conforms to a rectangle entered as a parameter. |
|
26 @param aRect the rectangle within which the ellipse is drawn |
|
27 */ |
|
28 void TSwDirectGdiEllipse::Construct(const TRect& aRect) |
|
29 { |
|
30 TInt width = aRect.Width(); |
|
31 TInt height = aRect.Height(); |
|
32 iA = (width-1) >> 1; |
|
33 iB = (height-1) >> 1; |
|
34 iXAdj = (width+1) & 1; |
|
35 iYAdj = (height+1) & 1; |
|
36 iOffset = aRect.iTl; |
|
37 iX = 0; |
|
38 iY = iB; |
|
39 iASquared = iA * iA; |
|
40 iBSquared = iB * iB; |
|
41 iASquBSqu = iASquared * iBSquared; |
|
42 iD1 = iBSquared - iASquared * iB + (iASquared>>1); |
|
43 if (width<=0 || height<=0) |
|
44 { |
|
45 iStatus = EComplete; |
|
46 } |
|
47 else if (width<=2 || height<=2) |
|
48 { |
|
49 iStatus = ELine; |
|
50 } |
|
51 else |
|
52 { |
|
53 iStatus = EInitialised; |
|
54 } |
|
55 } |
|
56 |
|
57 /** |
|
58 Does the next stage in producing an ellipse by taking four points (the corners of |
|
59 the rectangle the ellipse should fill) as parameters. Updates TSwDirectGdiEllipse status |
|
60 accordingly and calls Output(aTopLeft,aTopRight,aBottomLeft,aBottomRight). |
|
61 |
|
62 @param aTopLeft Top left corner of rectangle. |
|
63 @param aTopRight Top right corner of rectangle. |
|
64 @param aBottomLeft Bottom left corner of rectangle. |
|
65 @param aBottomRight Bottom right corner of rectangle. |
|
66 @return TBool ETrue if step completed successfully. |
|
67 */ |
|
68 TBool TSwDirectGdiEllipse::SingleStep(TPoint& aTopLeft, TPoint& aTopRight, |
|
69 TPoint& aBottomLeft, TPoint& aBottomRight) |
|
70 { |
|
71 TBool ret = EFalse; |
|
72 if (iStatus == EFirstSector) |
|
73 { |
|
74 if (iD1 < 0) |
|
75 { |
|
76 iD1 += iBSquared * ((iX<<1)+3); |
|
77 } |
|
78 else if (iY > 0) |
|
79 { |
|
80 iD1 += iBSquared * ((iX<<1)+3) + iASquared * (2-(iY<<1)); |
|
81 iY--; |
|
82 } |
|
83 iX++; |
|
84 ret = Output(aTopLeft,aTopRight,aBottomLeft,aBottomRight); |
|
85 if (iStatus == EComplete && iX<iA) |
|
86 { |
|
87 iStatus = EFirstSector; |
|
88 return EFalse; |
|
89 } |
|
90 if (iASquared*iY<=iBSquared*(iX+1) && ret==EFalse) |
|
91 { |
|
92 iStatus = ESecondSector; |
|
93 iD2 =- iASquBSqu + iBSquared * iX * iX + iASquared * (iY-1) * (iY-1); |
|
94 } |
|
95 return ret; |
|
96 } |
|
97 if (iStatus == ESecondSector) |
|
98 { |
|
99 if (iD2 < 0) |
|
100 { |
|
101 iD2 += iBSquared * ((iX<<1)+2) + iASquared * (3-(iY<<1)); |
|
102 iX++; |
|
103 } |
|
104 else |
|
105 { |
|
106 iD2 += iASquared * (3-(iY<<1)); |
|
107 } |
|
108 iY--; |
|
109 return Output(aTopLeft, aTopRight, aBottomLeft, aBottomRight); |
|
110 } |
|
111 if (iStatus == ELine) |
|
112 { |
|
113 ret = Output(aTopLeft, aTopRight, aBottomLeft, aBottomRight); |
|
114 if (iA == 0) |
|
115 { |
|
116 iY--; |
|
117 } |
|
118 else |
|
119 { |
|
120 iX++; |
|
121 if (iX > iA+iXAdj) |
|
122 { |
|
123 ret = ETrue; |
|
124 } |
|
125 else |
|
126 { |
|
127 iStatus = ELine; |
|
128 ret = EFalse; |
|
129 } |
|
130 } |
|
131 return ret; |
|
132 } |
|
133 if (iStatus == EInitialised) |
|
134 { |
|
135 iStatus = EFirstSector; |
|
136 return Output(aTopLeft, aTopRight, aBottomLeft, aBottomRight); |
|
137 } |
|
138 Output(aTopLeft, aTopRight, aBottomLeft, aBottomRight); |
|
139 return ETrue; |
|
140 } |
|
141 |
|
142 /** |
|
143 Sets the absolute points that define the ellipse as calculated using its iOffset |
|
144 from the origin and using the half width and half height of the rectangle iA and iB. |
|
145 |
|
146 @param aTopLeft The absolute (x,y) position for the top left point. |
|
147 @param aTopRight The absolute (x,y) position for the top right point. |
|
148 @param aBottomLeft The absolute (x,y) position for the bottom left point. |
|
149 @param aBottomRight The absolute (x,y) position for the bottom right point. |
|
150 @return ETrue if a valid rectangle is produced, else EFalse. Also sets |
|
151 iStatus to EComplete. |
|
152 */ |
|
153 TBool TSwDirectGdiEllipse::Output(TPoint& aTopLeft, TPoint& aTopRight, |
|
154 TPoint& aBottomLeft, TPoint& aBottomRight) |
|
155 { |
|
156 TInt lx = iA-iX+iOffset.iX; |
|
157 TInt ty = iB-iY+iOffset.iY; |
|
158 TInt rx = iA+iX+iXAdj+iOffset.iX; |
|
159 TInt by = iB+iY+iYAdj+iOffset.iY; |
|
160 aTopLeft.SetXY(lx,ty); |
|
161 aTopRight.SetXY(rx,ty); |
|
162 aBottomLeft.SetXY(lx,by); |
|
163 aBottomRight.SetXY(rx,by); |
|
164 if (iY <= 0) |
|
165 { |
|
166 iStatus = EComplete; |
|
167 if (iYAdj==0 || ty>by) |
|
168 return ETrue; |
|
169 } |
|
170 return EFalse; |
|
171 } |
|
172 |
|
173 /** |
|
174 By analysing the current state of the ellipse the process is taken to the next appropriate step. |
|
175 If iStatus = EInitialised only one step will be taken, if the ellipse is already semi constructed then |
|
176 it will be taken to completion. Takes in four point parameters that define the rectangle in order to pass to |
|
177 SingleStep(aTopLeft,aTopRight,aBottomLeft,aBottomRight). |
|
178 |
|
179 @param aTopLeft Top-left corner of rectangle. |
|
180 @param aTopRight Top-right corner of rectangle. |
|
181 @param aBottomLeft Bottom-left corner of rectangle. |
|
182 @param aBottomRight Bottom-right corner of rectangle. |
|
183 @return ETrue if a valid rectangle is produced, else EFalse. |
|
184 */ |
|
185 TBool TSwDirectGdiEllipse::NextStep(TPoint& aTopLeft, TPoint& aTopRight, |
|
186 TPoint& aBottomLeft, TPoint& aBottomRight) |
|
187 { |
|
188 if(iStatus == EInitialised) |
|
189 { |
|
190 return(SingleStep(aTopLeft,aTopRight,aBottomLeft,aBottomRight)); |
|
191 } |
|
192 TInt prevlev = iY; |
|
193 TBool ret; |
|
194 do |
|
195 { |
|
196 ret = SingleStep(aTopLeft,aTopRight,aBottomLeft,aBottomRight); |
|
197 } |
|
198 while (prevlev==iY && ret==EFalse); |
|
199 return ret; |
|
200 } |
|
201 |
|
202 /** |
|
203 Constructs an ellipse from the rectangle that has been added. Assesses the position of |
|
204 the points and the places where they intersect the ellipse. |
|
205 |
|
206 @param aRect The rectangle within which the ellipse is drawn. |
|
207 @param aPoint A point to compare with the ellipse to determine if intersection occurs. |
|
208 @return TPoint The point is set to the corner which the intersection is nearest to. |
|
209 */ |
|
210 TPoint TSwDirectGdiEllipse::Intersection(const TRect& aRect, const TPoint& aPoint) |
|
211 { |
|
212 Construct(aRect); //constructs the rect (an elipse object) |
|
213 TPoint centre = aRect.Center(); //centre of ellipse |
|
214 TPoint ptcpy(aPoint); |
|
215 ptcpy -= iOffset; //ptcpy = aPoint - iOffset - TPoint(iA,iB) //radius from centre of ellipse |
|
216 ptcpy -= TPoint(iA,iB); |
|
217 TPoint pt[4], opt[4]; |
|
218 TInt mpt[4], ompt[4]; |
|
219 TInt count = 0; |
|
220 for( ; count < 4; count++) |
|
221 { |
|
222 ompt[count]=KMaxTInt; //fills ompt 1->4 with KMaxTInt |
|
223 } |
|
224 while (SingleStep(pt[0], pt[1], pt[2], pt[3]) == EFalse) //creates a complete ellipse with pts as rect |
|
225 { |
|
226 for (count = 0; count < 4; count++) |
|
227 { |
|
228 mpt[count] = Abs((pt[count].iY-iOffset.iY-iB)*(ptcpy.iX)-(ptcpy.iY)*(pt[count].iX-iOffset.iX-iA)); |
|
229 if (mpt[count] < ompt[count]) //use the larger number set. |
|
230 { |
|
231 ompt[count] = mpt[count]; |
|
232 opt[count] = pt[count]; |
|
233 } |
|
234 } |
|
235 } |
|
236 if (pt[0].iY == pt[2].iY) //if it is horizontal |
|
237 { |
|
238 for (count = 0; count < 4; count++) |
|
239 { |
|
240 mpt[count] = Abs((pt[count].iY-iOffset.iY-iB)*(ptcpy.iX)-(ptcpy.iY)*(pt[count].iX-iOffset.iX-iA)); |
|
241 if (mpt[count] < ompt[count]) //use the larger number set. |
|
242 { |
|
243 ompt[count] = mpt[count]; |
|
244 opt[count] = pt[count]; |
|
245 } |
|
246 } |
|
247 } |
|
248 if (ptcpy.iX<0 && ptcpy.iY<0) //if point is further left and higher than centre of rect |
|
249 { |
|
250 return opt[0]; |
|
251 } |
|
252 if (ptcpy.iY < 0) //if point is higher than centre of rect |
|
253 { |
|
254 return opt[1]; |
|
255 } |
|
256 if (ptcpy.iX < 0) //if point is further left than centre of rect |
|
257 { |
|
258 return opt[2]; |
|
259 } |
|
260 if (aPoint.iX<centre.iX && aPoint.iY<centre.iY) //if point is further left and higher than centre of rect |
|
261 { |
|
262 return opt[0]; |
|
263 } |
|
264 if (aPoint.iY < centre.iY) //if point is higher than centre of rect |
|
265 { |
|
266 return opt[1]; |
|
267 } |
|
268 if (aPoint.iX < centre.iX) //if point is further left than centre of rect |
|
269 { |
|
270 return opt[2]; |
|
271 } |
|
272 return(opt[3]); //else |
|
273 } |
|
274 |
|
275 // |
|
276 // Ellipse drawing |
|
277 // |
|
278 |
|
279 /** |
|
280 @see MDirectGdiEngine::DrawEllipse() |
|
281 */ |
|
282 void CSwDirectGdiEngine::DrawEllipse(const TRect& aRect) |
|
283 { |
|
284 TRect rcpy(aRect); |
|
285 rcpy.Move(iOrigin); |
|
286 TruncateRect(rcpy); |
|
287 iBrushBitmap.BeginDataAccess(); |
|
288 if(iBrushStyle!=DirectGdi::ENullBrush) |
|
289 EllipseFill(rcpy); |
|
290 |
|
291 if(iPenStyle!=DirectGdi::ENullPen) |
|
292 { |
|
293 if(iPenSize.iWidth>1 && iPenSize.iHeight>1) |
|
294 { |
|
295 EllipseOutlineWide(rcpy); |
|
296 } |
|
297 else if(iPenSize.iWidth==1 || iPenSize.iHeight==1) |
|
298 { |
|
299 EllipseOutline(rcpy); |
|
300 } |
|
301 } |
|
302 iBrushBitmap.EndDataAccess(ETrue); |
|
303 } |
|
304 |
|
305 /** |
|
306 Draws an ellipse inside the given rectangle. Current pen settings apply. |
|
307 @param aRect The rectangle in which to draw the ellipse. |
|
308 */ |
|
309 void CSwDirectGdiEngine::EllipseOutline(const TRect& aRect) |
|
310 { |
|
311 TPoint tl,tr,bl,br; |
|
312 #if defined(_DEBUG) |
|
313 TRect deviceDestRect; |
|
314 iDrawDevice->GetDrawRect(deviceDestRect); |
|
315 #endif |
|
316 TRect clipRect(0,0,0,0); |
|
317 const CGraphicsContext::TDrawMode drawMode = GcDrawMode(iDrawMode); |
|
318 for(TInt count=0;count<iDefaultRegionPtr->Count();count++) |
|
319 { |
|
320 clipRect=(*iDefaultRegionPtr)[count]; |
|
321 if(!clipRect.Intersects(aRect)) |
|
322 continue; |
|
323 clipRect.Intersection(aRect); |
|
324 GRAPHICS_ASSERT_DEBUG(clipRect.iTl.iX >= deviceDestRect.iTl.iX, EDirectGdiPanicOutOfBounds); |
|
325 GRAPHICS_ASSERT_DEBUG(clipRect.iTl.iY >= deviceDestRect.iTl.iY, EDirectGdiPanicOutOfBounds); |
|
326 GRAPHICS_ASSERT_DEBUG(clipRect.iBr.iX <= deviceDestRect.iBr.iX, EDirectGdiPanicOutOfBounds); |
|
327 GRAPHICS_ASSERT_DEBUG(clipRect.iBr.iY <= deviceDestRect.iBr.iY, EDirectGdiPanicOutOfBounds); |
|
328 TSwDirectGdiEllipse ellipse; |
|
329 ellipse.Construct(aRect); |
|
330 TInt pattern=0; |
|
331 while(!ellipse.SingleStep(tl,tr,bl,br)) |
|
332 { |
|
333 if(iPenStyle==DirectGdi::ESolidPen || (iDotMask&(1<<(pattern%iDotLength)))) |
|
334 { |
|
335 if(tl.iY>=clipRect.iTl.iY && tl.iY<clipRect.iBr.iY) |
|
336 { |
|
337 if(tl.iX>=clipRect.iTl.iX && tl.iX<clipRect.iBr.iX) |
|
338 iDrawDevice->WriteRgb(tl.iX,tl.iY,iPenColor,drawMode); |
|
339 if(tr.iX>=clipRect.iTl.iX && tr.iX<clipRect.iBr.iX && tl.iX!=tr.iX) |
|
340 iDrawDevice->WriteRgb(tr.iX,tr.iY,iPenColor,drawMode); |
|
341 } |
|
342 if(bl.iY>=clipRect.iTl.iY && bl.iY<clipRect.iBr.iY) |
|
343 { |
|
344 if(bl.iX>=clipRect.iTl.iX && bl.iX<clipRect.iBr.iX) |
|
345 iDrawDevice->WriteRgb(bl.iX,bl.iY,iPenColor,drawMode); |
|
346 if(br.iX>=clipRect.iTl.iX && br.iX<clipRect.iBr.iX && bl.iX!=br.iX) |
|
347 iDrawDevice->WriteRgb(br.iX,br.iY,iPenColor,drawMode); |
|
348 } |
|
349 } |
|
350 pattern++; |
|
351 } |
|
352 if(tl.iY==bl.iY && tl.iY>=clipRect.iTl.iY && tl.iY<clipRect.iBr.iY) |
|
353 { |
|
354 if(tl.iX>=clipRect.iTl.iX && tl.iX<clipRect.iBr.iX) |
|
355 iDrawDevice->WriteRgb(tl.iX,tl.iY,iPenColor,drawMode); |
|
356 if(tr.iX>=clipRect.iTl.iX && tr.iX<clipRect.iBr.iX && tl.iX!=tr.iX) |
|
357 iDrawDevice->WriteRgb(tr.iX,tr.iY,iPenColor,drawMode); |
|
358 } |
|
359 iDrawDevice->UpdateRegion(clipRect); |
|
360 } |
|
361 } |
|
362 |
|
363 /** |
|
364 Draws an ellipse inside the given rectangle. Current pen settings apply. |
|
365 @param aRect The rectangle in which to draw the ellipse. |
|
366 */ |
|
367 void CSwDirectGdiEngine::EllipseOutlineWide(const TRect& aRect) |
|
368 { |
|
369 TRect rcpy(aRect); |
|
370 TPoint tl,tr,bl,br; |
|
371 TInt halfpenwidth=(iPenSize.iWidth+1)>>1; |
|
372 TInt halfpenheight=(iPenSize.iHeight+1)>>1; |
|
373 rcpy.Grow(halfpenwidth, halfpenheight); |
|
374 TInt dp=iDotParam; |
|
375 TRect clipRect(0,0,0,0); |
|
376 for(TInt count=0;count<iDefaultRegionPtr->Count();count++) |
|
377 { |
|
378 clipRect=(*iDefaultRegionPtr)[count]; |
|
379 if(!clipRect.Intersects(rcpy)) |
|
380 continue; |
|
381 clipRect.Intersection(rcpy); |
|
382 TSwDirectGdiEllipse ellipse; |
|
383 ellipse.Construct(aRect); |
|
384 iDotParam=Max(iPenSize.iWidth>>1,iPenSize.iHeight>>1); |
|
385 while(!ellipse.SingleStep(tl,tr,bl,br)) |
|
386 { |
|
387 PenDrawClipped(tl, clipRect); |
|
388 PenDrawClipped(tr, clipRect); |
|
389 PenDrawClipped(bl, clipRect); |
|
390 PenDrawClipped(br, clipRect); |
|
391 iDotParam+=iDotDirection; |
|
392 } |
|
393 if(tl.iY==bl.iY) |
|
394 { |
|
395 PenDrawClipped(tl, clipRect); |
|
396 PenDrawClipped(tr, clipRect); |
|
397 } |
|
398 iDrawDevice->UpdateRegion(clipRect); |
|
399 } |
|
400 iDotParam=dp; |
|
401 } |
|
402 |
|
403 /** |
|
404 Fills an ellipse inside the given rectangle. Current brush settings apply. |
|
405 @param aRect The rectangle in which to draw the ellipse. |
|
406 */ |
|
407 void CSwDirectGdiEngine::EllipseFill(const TRect& aRect) |
|
408 { |
|
409 TRect rcpy(aRect); |
|
410 if(iPenSize.iWidth==0 || iPenSize.iHeight==0) |
|
411 { |
|
412 rcpy.Grow(1,1); |
|
413 } |
|
414 TPoint tl,tr,bl,br; |
|
415 TRect clipRect(0,0,0,0); |
|
416 for(TInt count=0;count<iDefaultRegionPtr->Count();count++) |
|
417 { |
|
418 clipRect=(*iDefaultRegionPtr)[count]; |
|
419 if(!clipRect.Intersects(rcpy)) |
|
420 continue; |
|
421 clipRect.Intersection(rcpy); |
|
422 TSwDirectGdiEllipse ellipse; |
|
423 ellipse.Construct(rcpy); |
|
424 while(!ellipse.NextStep(tl,tr,bl,br)) |
|
425 { |
|
426 tl.iX++; |
|
427 tr.iX--; |
|
428 bl.iX++; |
|
429 br.iX--; |
|
430 ClipFillLine(tl,tr, clipRect); |
|
431 ClipFillLine(bl,br, clipRect); |
|
432 } |
|
433 if(tl.iY==bl.iY) |
|
434 { |
|
435 tl.iX++; |
|
436 tr.iX--; |
|
437 ClipFillLine(tl,tr, clipRect); |
|
438 } |
|
439 iDrawDevice->UpdateRegion(clipRect); |
|
440 } |
|
441 } |