sl@0
|
1 |
// Copyright (c) 2007-2009 Nokia Corporation and/or its subsidiary(-ies).
|
sl@0
|
2 |
// All rights reserved.
|
sl@0
|
3 |
// This component and the accompanying materials are made available
|
sl@0
|
4 |
// under the terms of "Eclipse Public License v1.0"
|
sl@0
|
5 |
// which accompanies this distribution, and is available
|
sl@0
|
6 |
// at the URL "http://www.eclipse.org/legal/epl-v10.html".
|
sl@0
|
7 |
//
|
sl@0
|
8 |
// Initial Contributors:
|
sl@0
|
9 |
// Nokia Corporation - initial contribution.
|
sl@0
|
10 |
//
|
sl@0
|
11 |
// Contributors:
|
sl@0
|
12 |
//
|
sl@0
|
13 |
// Description:
|
sl@0
|
14 |
// Unless stated otherwise, all co-ordinates are recorded and calculated using
|
sl@0
|
15 |
// Symbian graphics format: origin at top left of image, 'y' increasing towards bottom
|
sl@0
|
16 |
// of image. Note that OpenVG places the origin at an image's bottom left corner, with
|
sl@0
|
17 |
// 'y' increasing towards the top of the image.
|
sl@0
|
18 |
//
|
sl@0
|
19 |
//
|
sl@0
|
20 |
|
sl@0
|
21 |
#include "vgengine.h"
|
sl@0
|
22 |
#include "directgdiadapter.h"
|
sl@0
|
23 |
#include "directgdidriverimpl.h"
|
sl@0
|
24 |
#include "directgdiimagetargetimpl.h"
|
sl@0
|
25 |
#include "directgdiimagesourceimpl.h"
|
sl@0
|
26 |
#include "confighelper.h"
|
sl@0
|
27 |
#include <graphics/directgdiimagetarget.h>
|
sl@0
|
28 |
#include <graphics/directgdidrawablesource.h>
|
sl@0
|
29 |
#include <fbs.h>
|
sl@0
|
30 |
#include <e32cmn.h>
|
sl@0
|
31 |
#include <e32math.h>
|
sl@0
|
32 |
#include <s32strm.h>
|
sl@0
|
33 |
#include <pixelformats.h>
|
sl@0
|
34 |
#include <bitdraworigin.h>
|
sl@0
|
35 |
#include <bitdrawinterfaceid.h>
|
sl@0
|
36 |
|
sl@0
|
37 |
#include "blendingalgorithms.inl"
|
sl@0
|
38 |
|
sl@0
|
39 |
/**
|
sl@0
|
40 |
Pre-calculation for normalising a 0-255 colour channel to 0..1.
|
sl@0
|
41 |
*/
|
sl@0
|
42 |
const VGfloat KColorConversion = 1.0f/255.0f;
|
sl@0
|
43 |
|
sl@0
|
44 |
|
sl@0
|
45 |
inline TInt Scale(TInt aValue,TInt aNum,TInt aDen)
|
sl@0
|
46 |
{
|
sl@0
|
47 |
if (aNum==aDen)
|
sl@0
|
48 |
return aValue;
|
sl@0
|
49 |
TInt64 result(aValue);
|
sl@0
|
50 |
result=(result*aNum+(aDen/2))/aDen;
|
sl@0
|
51 |
return I64INT(result);
|
sl@0
|
52 |
}
|
sl@0
|
53 |
|
sl@0
|
54 |
/**
|
sl@0
|
55 |
Maps TDisplayMode onto a supported VGImageFormat. Only compatible formats are returned,
|
sl@0
|
56 |
anything else results in VG_IMAGE_FORMAT_INVALID being returned.
|
sl@0
|
57 |
|
sl@0
|
58 |
@param aDisplayMode Mode to convert from.
|
sl@0
|
59 |
|
sl@0
|
60 |
@return The VGImageFormat which matches the specified TDisplayMode pixel format exactly.
|
sl@0
|
61 |
If no exact match exists, then VG_IMAGE_FORMAT_INVALID is returned.
|
sl@0
|
62 |
*/
|
sl@0
|
63 |
static VGImageFormat MapToVgDisplayMode(TDisplayMode aDisplayMode)
|
sl@0
|
64 |
{
|
sl@0
|
65 |
switch(aDisplayMode)
|
sl@0
|
66 |
{
|
sl@0
|
67 |
case ENone:
|
sl@0
|
68 |
return VG_IMAGE_FORMAT_INVALID;
|
sl@0
|
69 |
case EGray2:
|
sl@0
|
70 |
return VG_BW_1;
|
sl@0
|
71 |
case EGray4:
|
sl@0
|
72 |
case EGray16:
|
sl@0
|
73 |
return VG_IMAGE_FORMAT_INVALID;
|
sl@0
|
74 |
case EGray256:
|
sl@0
|
75 |
return VG_sL_8;
|
sl@0
|
76 |
case EColor16:
|
sl@0
|
77 |
case EColor256:
|
sl@0
|
78 |
case EColor4K:
|
sl@0
|
79 |
return VG_IMAGE_FORMAT_INVALID;
|
sl@0
|
80 |
case EColor64K:
|
sl@0
|
81 |
return VG_sRGB_565;
|
sl@0
|
82 |
case EColor16M:
|
sl@0
|
83 |
case ERgb:
|
sl@0
|
84 |
return VG_IMAGE_FORMAT_INVALID;
|
sl@0
|
85 |
case EColor16MU:
|
sl@0
|
86 |
return VG_sXRGB_8888;
|
sl@0
|
87 |
case EColor16MA:
|
sl@0
|
88 |
return VG_sARGB_8888;
|
sl@0
|
89 |
case EColor16MAP:
|
sl@0
|
90 |
return VG_sARGB_8888_PRE;
|
sl@0
|
91 |
case EColorLast:
|
sl@0
|
92 |
return VG_IMAGE_FORMAT_INVALID;
|
sl@0
|
93 |
}
|
sl@0
|
94 |
|
sl@0
|
95 |
return VG_IMAGE_FORMAT_INVALID;
|
sl@0
|
96 |
}
|
sl@0
|
97 |
|
sl@0
|
98 |
/**
|
sl@0
|
99 |
Destructor
|
sl@0
|
100 |
*/
|
sl@0
|
101 |
CVgEngine::~CVgEngine()
|
sl@0
|
102 |
{
|
sl@0
|
103 |
iRegionManager.Close();
|
sl@0
|
104 |
|
sl@0
|
105 |
if (iBrushPatternUser != VG_INVALID_HANDLE)
|
sl@0
|
106 |
vgDestroyImage(iBrushPatternUser);
|
sl@0
|
107 |
|
sl@0
|
108 |
if (iBrushPatternStandard != VG_INVALID_HANDLE)
|
sl@0
|
109 |
vgDestroyImage(iBrushPatternStandard);
|
sl@0
|
110 |
|
sl@0
|
111 |
if (iBrushPatternStandardRegion != VG_INVALID_HANDLE)
|
sl@0
|
112 |
vgDestroyImage(iBrushPatternStandardRegion);
|
sl@0
|
113 |
|
sl@0
|
114 |
if (iBrushPatternNonZeroOrigin != VG_INVALID_HANDLE)
|
sl@0
|
115 |
vgDestroyImage(iBrushPatternNonZeroOrigin);
|
sl@0
|
116 |
|
sl@0
|
117 |
User::Free(iPathCommands);
|
sl@0
|
118 |
User::Free(iPathCoords);
|
sl@0
|
119 |
|
sl@0
|
120 |
Deactivate();
|
sl@0
|
121 |
}
|
sl@0
|
122 |
|
sl@0
|
123 |
/**
|
sl@0
|
124 |
Constructor
|
sl@0
|
125 |
*/
|
sl@0
|
126 |
CVgEngine::CVgEngine(CDirectGdiDriverImpl& aDriver)
|
sl@0
|
127 |
:iDriver(aDriver),
|
sl@0
|
128 |
iPen(VG_INVALID_HANDLE),
|
sl@0
|
129 |
iBrush(VG_INVALID_HANDLE),
|
sl@0
|
130 |
iClearBrush(VG_INVALID_HANDLE),
|
sl@0
|
131 |
iVgPath(VG_INVALID_HANDLE),
|
sl@0
|
132 |
iTextBrush(VG_INVALID_HANDLE),
|
sl@0
|
133 |
iBrushPatternUser(VG_INVALID_HANDLE),
|
sl@0
|
134 |
iBrushPatternStandard(VG_INVALID_HANDLE),
|
sl@0
|
135 |
iBrushPatternStandardRegion(VG_INVALID_HANDLE),
|
sl@0
|
136 |
iBrushPatternNonZeroOrigin(VG_INVALID_HANDLE)
|
sl@0
|
137 |
{
|
sl@0
|
138 |
// Set the default paint mode for drawing and filling shapes to
|
sl@0
|
139 |
// just draw the pen and not the brush as default (to match BitGdi)
|
sl@0
|
140 |
iPaintMode = VG_STROKE_PATH;
|
sl@0
|
141 |
|
sl@0
|
142 |
//cache interface to use every time glyph gets drawn
|
sl@0
|
143 |
GetInterface(TUid::Uid(KDirectGdiGetGlyphStorageUid), (TAny*&) iFontGlyphImageStorage);
|
sl@0
|
144 |
}
|
sl@0
|
145 |
|
sl@0
|
146 |
/**
|
sl@0
|
147 |
Applies the engine's state to OpenVG, re-applying all the VgEngine settings. It is called by
|
sl@0
|
148 |
Activate() as well as when the engine is being made current.
|
sl@0
|
149 |
*/
|
sl@0
|
150 |
void CVgEngine::SetVgState()
|
sl@0
|
151 |
{
|
sl@0
|
152 |
ResetVgMatrix();
|
sl@0
|
153 |
vgSeti(VG_RENDERING_QUALITY, VG_RENDERING_QUALITY_NONANTIALIASED);
|
sl@0
|
154 |
vgSeti(VG_IMAGE_QUALITY, VG_IMAGE_QUALITY_NONANTIALIASED);
|
sl@0
|
155 |
vgSeti(VG_STROKE_CAP_STYLE, VG_CAP_ROUND);
|
sl@0
|
156 |
vgSeti(VG_STROKE_JOIN_STYLE, VG_JOIN_ROUND);
|
sl@0
|
157 |
vgSetPaint(iPen, VG_STROKE_PATH);
|
sl@0
|
158 |
vgSetPaint(iBrush, VG_FILL_PATH);
|
sl@0
|
159 |
SetDrawMode(iDrawMode);
|
sl@0
|
160 |
SetPenColor(iPenColor);
|
sl@0
|
161 |
SetPenStyle(iPenStyle);
|
sl@0
|
162 |
SetPenSize(iPenSize);
|
sl@0
|
163 |
SetBrushColor(iBrushColor);
|
sl@0
|
164 |
SetBrushStyle(iBrushStyle);
|
sl@0
|
165 |
SetBrushOrigin(iBrushOrigin);
|
sl@0
|
166 |
vgSetParameteri(iClearBrush, VG_PAINT_TYPE, VG_PAINT_TYPE_COLOR);
|
sl@0
|
167 |
vgSetParameteri(iTextBrush, VG_PAINT_TYPE, VG_PAINT_TYPE_COLOR);
|
sl@0
|
168 |
}
|
sl@0
|
169 |
|
sl@0
|
170 |
/**
|
sl@0
|
171 |
Binds a rendering target to this OpenVG rendering engine.
|
sl@0
|
172 |
Activates the target, which increments the reference count of target as it can be shared across many
|
sl@0
|
173 |
DirectGDI contexts.
|
sl@0
|
174 |
|
sl@0
|
175 |
The rendering target, for this implementation, specifies an Embedded OpenVG rendering surface.
|
sl@0
|
176 |
|
sl@0
|
177 |
@see MDirectGdiEngine::Activate()
|
sl@0
|
178 |
@see Deactivate()
|
sl@0
|
179 |
|
sl@0
|
180 |
@panic DGDIAdapter 34, if the passed target has a NULL handle.
|
sl@0
|
181 |
@panic DGDIAdapter 39, if target associated with the handle is NULL.
|
sl@0
|
182 |
*/
|
sl@0
|
183 |
TInt CVgEngine::Activate(RDirectGdiImageTarget& aTarget)
|
sl@0
|
184 |
{
|
sl@0
|
185 |
TInt result = KErrNone;
|
sl@0
|
186 |
GRAPHICS_ASSERT_ALWAYS(aTarget.Handle(), EDirectGdiPanicActivateWithNullHandle);
|
sl@0
|
187 |
CDirectGdiImageTargetImpl* target = iDriver.GetImageTargetFromHandle(aTarget.Handle());
|
sl@0
|
188 |
GRAPHICS_ASSERT_ALWAYS(target, EDirectGdiPanicNullTargetActivate);
|
sl@0
|
189 |
if (target == iRenderingTarget)
|
sl@0
|
190 |
{
|
sl@0
|
191 |
return KErrNone;
|
sl@0
|
192 |
}
|
sl@0
|
193 |
|
sl@0
|
194 |
Deactivate();
|
sl@0
|
195 |
|
sl@0
|
196 |
iDriver.Activate(target);
|
sl@0
|
197 |
iRenderingTarget = target;
|
sl@0
|
198 |
iDriver.SetCurrentEngine(this);
|
sl@0
|
199 |
iDriver.SetCurrentTarget(target);
|
sl@0
|
200 |
iSize = iRenderingTarget->Size();
|
sl@0
|
201 |
iTargetRegion.Clear();
|
sl@0
|
202 |
iTargetRegion.AddRect(iSize);
|
sl@0
|
203 |
|
sl@0
|
204 |
iRegionManager.Initialize(vgGeti(VG_MAX_SCISSOR_RECTS), iSize);
|
sl@0
|
205 |
|
sl@0
|
206 |
// Set the origin to top-left for path and image rendering. iIdentityMatrix is set so that we have a
|
sl@0
|
207 |
// record of the "identity" transform. After modifying the transform for offsets, rotations, etc, etc
|
sl@0
|
208 |
// just set to iIdentityMatrix to get back to "normal".
|
sl@0
|
209 |
//
|
sl@0
|
210 |
vgSeti(VG_MATRIX_MODE, VG_MATRIX_PATH_USER_TO_SURFACE);
|
sl@0
|
211 |
vgLoadIdentity();
|
sl@0
|
212 |
vgScale(1, -1);
|
sl@0
|
213 |
vgTranslate(0, -iSize.iHeight);
|
sl@0
|
214 |
vgGetMatrix(iIdentityMatrix);
|
sl@0
|
215 |
// Set the origin to top-left for image matrix.
|
sl@0
|
216 |
vgSeti(VG_MATRIX_MODE, VG_MATRIX_IMAGE_USER_TO_SURFACE);
|
sl@0
|
217 |
vgLoadMatrix(iIdentityMatrix);
|
sl@0
|
218 |
|
sl@0
|
219 |
// Create the path.
|
sl@0
|
220 |
if (!PreparePath(iVgPath, 1) || (iVgPath == VG_INVALID_HANDLE))
|
sl@0
|
221 |
result = KErrNoMemory;
|
sl@0
|
222 |
|
sl@0
|
223 |
// Create the pen object and set it as the object for stroking (OpenVG equivalent of a pen).
|
sl@0
|
224 |
if (result == KErrNone)
|
sl@0
|
225 |
{
|
sl@0
|
226 |
iPen = vgCreatePaint();
|
sl@0
|
227 |
if (iPen != VG_INVALID_HANDLE)
|
sl@0
|
228 |
vgSetPaint(iPen, VG_STROKE_PATH);
|
sl@0
|
229 |
else
|
sl@0
|
230 |
result = KErrNoMemory;
|
sl@0
|
231 |
}
|
sl@0
|
232 |
|
sl@0
|
233 |
if (result == KErrNone)
|
sl@0
|
234 |
{
|
sl@0
|
235 |
// Create the brush object
|
sl@0
|
236 |
// This only need to be done the first time the context is activated
|
sl@0
|
237 |
iBrush = vgCreatePaint();
|
sl@0
|
238 |
if (iBrush != VG_INVALID_HANDLE)
|
sl@0
|
239 |
vgSetPaint(iBrush, VG_FILL_PATH);
|
sl@0
|
240 |
else
|
sl@0
|
241 |
result = KErrNoMemory;
|
sl@0
|
242 |
}
|
sl@0
|
243 |
|
sl@0
|
244 |
if (result == KErrNone)
|
sl@0
|
245 |
{
|
sl@0
|
246 |
// Create the brush object for Clear operations.
|
sl@0
|
247 |
// This only need to be done the first time the context is activated
|
sl@0
|
248 |
iClearBrush = vgCreatePaint();
|
sl@0
|
249 |
if (iClearBrush == VG_INVALID_HANDLE)
|
sl@0
|
250 |
{
|
sl@0
|
251 |
result = KErrNoMemory;
|
sl@0
|
252 |
}
|
sl@0
|
253 |
}
|
sl@0
|
254 |
|
sl@0
|
255 |
if (result == KErrNone)
|
sl@0
|
256 |
{
|
sl@0
|
257 |
iTextBrush = vgCreatePaint();
|
sl@0
|
258 |
if (iTextBrush == VG_INVALID_HANDLE)
|
sl@0
|
259 |
{
|
sl@0
|
260 |
result = KErrNoMemory;
|
sl@0
|
261 |
}
|
sl@0
|
262 |
}
|
sl@0
|
263 |
|
sl@0
|
264 |
if (result == KErrNone)
|
sl@0
|
265 |
{
|
sl@0
|
266 |
result = iDriver.PreAllocateFontGlyphImages();
|
sl@0
|
267 |
}
|
sl@0
|
268 |
|
sl@0
|
269 |
if (result == KErrNone)
|
sl@0
|
270 |
{
|
sl@0
|
271 |
SetVgState();
|
sl@0
|
272 |
}
|
sl@0
|
273 |
|
sl@0
|
274 |
return result;
|
sl@0
|
275 |
}
|
sl@0
|
276 |
|
sl@0
|
277 |
/**
|
sl@0
|
278 |
@see MDirectGdiEngine::Deactivate()
|
sl@0
|
279 |
@see Activate()
|
sl@0
|
280 |
*/
|
sl@0
|
281 |
void CVgEngine::Deactivate()
|
sl@0
|
282 |
{
|
sl@0
|
283 |
if (iPen != VG_INVALID_HANDLE)
|
sl@0
|
284 |
{
|
sl@0
|
285 |
vgDestroyPaint(iPen);
|
sl@0
|
286 |
}
|
sl@0
|
287 |
if (iBrush != VG_INVALID_HANDLE)
|
sl@0
|
288 |
{
|
sl@0
|
289 |
vgDestroyPaint(iBrush);
|
sl@0
|
290 |
}
|
sl@0
|
291 |
if (iClearBrush != VG_INVALID_HANDLE)
|
sl@0
|
292 |
{
|
sl@0
|
293 |
vgDestroyPaint(iClearBrush);
|
sl@0
|
294 |
}
|
sl@0
|
295 |
if (iTextBrush != VG_INVALID_HANDLE)
|
sl@0
|
296 |
{
|
sl@0
|
297 |
vgDestroyPaint(iTextBrush);
|
sl@0
|
298 |
}
|
sl@0
|
299 |
if (iVgPath != VG_INVALID_HANDLE)
|
sl@0
|
300 |
{
|
sl@0
|
301 |
vgDestroyPath(iVgPath);
|
sl@0
|
302 |
}
|
sl@0
|
303 |
iPen = VG_INVALID_HANDLE;
|
sl@0
|
304 |
iBrush = VG_INVALID_HANDLE;
|
sl@0
|
305 |
iClearBrush = VG_INVALID_HANDLE;
|
sl@0
|
306 |
iVgPath = VG_INVALID_HANDLE;
|
sl@0
|
307 |
iTextBrush = VG_INVALID_HANDLE;
|
sl@0
|
308 |
|
sl@0
|
309 |
if (iRenderingTarget)
|
sl@0
|
310 |
{
|
sl@0
|
311 |
// Deactivating the render target could potentially unbind the current EGL context
|
sl@0
|
312 |
// which would make the above vgDestroy() calls do nothing, therefore call Deactivate() last.
|
sl@0
|
313 |
iDriver.Deactivate(iRenderingTarget);
|
sl@0
|
314 |
}
|
sl@0
|
315 |
}
|
sl@0
|
316 |
|
sl@0
|
317 |
/**
|
sl@0
|
318 |
Checks whether the engine and target are current. If current, then nothing is done, else all the OpenVG settings
|
sl@0
|
319 |
and EGL context are reapplied. This function is called in every drawing function to ensure that the engine and
|
sl@0
|
320 |
target are current.
|
sl@0
|
321 |
|
sl@0
|
322 |
If this function returns EFalse, it means any subsequent setting of OpenVG state may be invalid
|
sl@0
|
323 |
and should be avoided as it is setting a null EGL context.
|
sl@0
|
324 |
|
sl@0
|
325 |
@pre None.
|
sl@0
|
326 |
@post Applies the current state to OpenVG and is made the active EGL context, if the engine or target is
|
sl@0
|
327 |
not current.
|
sl@0
|
328 |
@return ETrue if as a result of calling this function, the underlying OpenVG context is now current. This
|
sl@0
|
329 |
effectively means whether we have a target or not. EFalse is returned otherwise.
|
sl@0
|
330 |
*/
|
sl@0
|
331 |
TBool CVgEngine::MakeEngineCurrent()
|
sl@0
|
332 |
{
|
sl@0
|
333 |
TBool vgCurrent = iRenderingTarget!=NULL;
|
sl@0
|
334 |
if(!iDriver.IsCurrentEngine(this) || !iDriver.IsCurrentTarget(iRenderingTarget))
|
sl@0
|
335 |
{
|
sl@0
|
336 |
iDriver.SetCurrentEngine(this);
|
sl@0
|
337 |
iDriver.SetCurrentTarget(iRenderingTarget);
|
sl@0
|
338 |
// Must reactivate the target (i.e. make it current to EGL) before resetting the OpenVG parameters.
|
sl@0
|
339 |
if (iRenderingTarget)
|
sl@0
|
340 |
{
|
sl@0
|
341 |
iDriver.Reactivate(iRenderingTarget);
|
sl@0
|
342 |
SetVgState();
|
sl@0
|
343 |
}
|
sl@0
|
344 |
else
|
sl@0
|
345 |
vgCurrent = EFalse;
|
sl@0
|
346 |
}
|
sl@0
|
347 |
|
sl@0
|
348 |
return vgCurrent;
|
sl@0
|
349 |
}
|
sl@0
|
350 |
|
sl@0
|
351 |
/**
|
sl@0
|
352 |
@see MDirectGdiEngine::SetOrigin()
|
sl@0
|
353 |
*/
|
sl@0
|
354 |
void CVgEngine::SetOrigin(const TPoint& aOrigin)
|
sl@0
|
355 |
{
|
sl@0
|
356 |
iOrigin = aOrigin + iDrawOrigin;
|
sl@0
|
357 |
|
sl@0
|
358 |
if (!MakeEngineCurrent())
|
sl@0
|
359 |
return;
|
sl@0
|
360 |
|
sl@0
|
361 |
ResetVgMatrix();
|
sl@0
|
362 |
}
|
sl@0
|
363 |
|
sl@0
|
364 |
/**
|
sl@0
|
365 |
@see MDrawDeviceOrigin::Set()
|
sl@0
|
366 |
*/
|
sl@0
|
367 |
TInt CVgEngine::Set(const TPoint& aDrawOrigin)
|
sl@0
|
368 |
{
|
sl@0
|
369 |
TPoint moveOrigin=aDrawOrigin;
|
sl@0
|
370 |
moveOrigin-=iDrawOrigin;
|
sl@0
|
371 |
iOrigin+=moveOrigin;
|
sl@0
|
372 |
|
sl@0
|
373 |
//offset clipping region
|
sl@0
|
374 |
TInt result = KErrNone;
|
sl@0
|
375 |
RRegion clippingRegion;
|
sl@0
|
376 |
clippingRegion.Copy(iRegionManager.ClippingRegion());
|
sl@0
|
377 |
if(!clippingRegion.CheckError())
|
sl@0
|
378 |
{
|
sl@0
|
379 |
clippingRegion.Offset(moveOrigin);
|
sl@0
|
380 |
result = iRegionManager.SetClippingRegion(clippingRegion);
|
sl@0
|
381 |
}
|
sl@0
|
382 |
else
|
sl@0
|
383 |
{
|
sl@0
|
384 |
result = KErrNoMemory;
|
sl@0
|
385 |
}
|
sl@0
|
386 |
|
sl@0
|
387 |
if(result != KErrNone)
|
sl@0
|
388 |
{
|
sl@0
|
389 |
iDriver.SetError(result);
|
sl@0
|
390 |
}
|
sl@0
|
391 |
|
sl@0
|
392 |
clippingRegion.Close();
|
sl@0
|
393 |
|
sl@0
|
394 |
iDrawOrigin = aDrawOrigin;
|
sl@0
|
395 |
return result;
|
sl@0
|
396 |
}
|
sl@0
|
397 |
|
sl@0
|
398 |
/**
|
sl@0
|
399 |
@see MDrawDeviceOrigin::Get()
|
sl@0
|
400 |
*/
|
sl@0
|
401 |
void CVgEngine::Get(TPoint& aDrawOrigin)
|
sl@0
|
402 |
{
|
sl@0
|
403 |
aDrawOrigin=iDrawOrigin;
|
sl@0
|
404 |
}
|
sl@0
|
405 |
|
sl@0
|
406 |
/**
|
sl@0
|
407 |
@see MDirectGdiEngine::SetClippingRegion(const TRegion&)
|
sl@0
|
408 |
*/
|
sl@0
|
409 |
void CVgEngine::SetClippingRegion(const TRegion& aRegion)
|
sl@0
|
410 |
{
|
sl@0
|
411 |
TInt result = KErrNone;
|
sl@0
|
412 |
TRect boundingRect=iTargetRegion.BoundingRect();
|
sl@0
|
413 |
boundingRect.iTl-=iDrawOrigin;
|
sl@0
|
414 |
boundingRect.iBr-=iDrawOrigin;
|
sl@0
|
415 |
if (!aRegion.IsContainedBy(boundingRect))
|
sl@0
|
416 |
{
|
sl@0
|
417 |
result = KErrArgument;
|
sl@0
|
418 |
}
|
sl@0
|
419 |
else
|
sl@0
|
420 |
{
|
sl@0
|
421 |
RRegion clippingRegion;
|
sl@0
|
422 |
clippingRegion.Copy(aRegion);
|
sl@0
|
423 |
if(!clippingRegion.CheckError())
|
sl@0
|
424 |
{
|
sl@0
|
425 |
clippingRegion.Offset(iDrawOrigin);
|
sl@0
|
426 |
result = iRegionManager.SetClippingRegion (clippingRegion);
|
sl@0
|
427 |
}
|
sl@0
|
428 |
else
|
sl@0
|
429 |
{
|
sl@0
|
430 |
result = KErrNoMemory;
|
sl@0
|
431 |
}
|
sl@0
|
432 |
clippingRegion.Close();
|
sl@0
|
433 |
}
|
sl@0
|
434 |
|
sl@0
|
435 |
if (result != KErrNone)
|
sl@0
|
436 |
{
|
sl@0
|
437 |
iDriver.SetError(result);
|
sl@0
|
438 |
}
|
sl@0
|
439 |
}
|
sl@0
|
440 |
|
sl@0
|
441 |
/**
|
sl@0
|
442 |
@see MDirectGdiEngine::ResetClippingRegion()
|
sl@0
|
443 |
*/
|
sl@0
|
444 |
void CVgEngine::ResetClippingRegion()
|
sl@0
|
445 |
{
|
sl@0
|
446 |
iRegionManager.Reset();
|
sl@0
|
447 |
|
sl@0
|
448 |
if (!MakeEngineCurrent())
|
sl@0
|
449 |
return;
|
sl@0
|
450 |
|
sl@0
|
451 |
vgSeti(VG_SCISSORING, VG_FALSE);
|
sl@0
|
452 |
}
|
sl@0
|
453 |
|
sl@0
|
454 |
/**
|
sl@0
|
455 |
@see MDirectGdiEngine::SetDrawMode()
|
sl@0
|
456 |
|
sl@0
|
457 |
The generic layer has already checked whether the draw mode is already aMode.
|
sl@0
|
458 |
Draw mode is referred to as "blend" mode in OpenVG.
|
sl@0
|
459 |
Note that only EDrawModePEN and EDrawModeWriteAlpha style blending are supported by OpenVG.
|
sl@0
|
460 |
The default OpenVG blend mode is VG_BLEND_SRC_OVER.
|
sl@0
|
461 |
*/
|
sl@0
|
462 |
void CVgEngine::SetDrawMode(DirectGdi::TDrawMode aMode)
|
sl@0
|
463 |
{
|
sl@0
|
464 |
iDrawMode = aMode;
|
sl@0
|
465 |
|
sl@0
|
466 |
if (!MakeEngineCurrent())
|
sl@0
|
467 |
return;
|
sl@0
|
468 |
|
sl@0
|
469 |
// Invalid modes are filtered out in the generic layer.
|
sl@0
|
470 |
if (aMode == DirectGdi::EDrawModePEN)
|
sl@0
|
471 |
{
|
sl@0
|
472 |
// Blend the destination with the source using the source alpha for blending if
|
sl@0
|
473 |
// alpha is available.
|
sl@0
|
474 |
vgSeti(VG_BLEND_MODE, VG_BLEND_SRC_OVER);
|
sl@0
|
475 |
}
|
sl@0
|
476 |
else // DirectGdi::EDrawModeWriteAlpha
|
sl@0
|
477 |
{
|
sl@0
|
478 |
// Destination colors and alpha are overwritten with source colors and alpha.
|
sl@0
|
479 |
vgSeti(VG_BLEND_MODE, VG_BLEND_SRC);
|
sl@0
|
480 |
}
|
sl@0
|
481 |
}
|
sl@0
|
482 |
|
sl@0
|
483 |
/**
|
sl@0
|
484 |
@see MDirectGdiEngine::SetPenColor()
|
sl@0
|
485 |
*/
|
sl@0
|
486 |
void CVgEngine::SetPenColor(const TRgb& aColor)
|
sl@0
|
487 |
{
|
sl@0
|
488 |
iPenColor = aColor;
|
sl@0
|
489 |
|
sl@0
|
490 |
if (!MakeEngineCurrent())
|
sl@0
|
491 |
return;
|
sl@0
|
492 |
|
sl@0
|
493 |
// Make sure our pen is the current selected pen for stroking before we set the color
|
sl@0
|
494 |
vgSetPaint(iPen, VG_STROKE_PATH);
|
sl@0
|
495 |
|
sl@0
|
496 |
// Set the color
|
sl@0
|
497 |
vgSetParameteri(iPen, VG_PAINT_TYPE, VG_PAINT_TYPE_COLOR);
|
sl@0
|
498 |
SetVgPaintColor(iPen, iPenColor);
|
sl@0
|
499 |
SetVgPaintColor(iTextBrush, iPenColor);
|
sl@0
|
500 |
}
|
sl@0
|
501 |
|
sl@0
|
502 |
/**
|
sl@0
|
503 |
Set the current pen style for drawing lines. This corresponds to setting the "stroke dash" pattern in OpenVG.
|
sl@0
|
504 |
|
sl@0
|
505 |
@see MDirectGdiEngine::SetPenStyle()
|
sl@0
|
506 |
*/
|
sl@0
|
507 |
void CVgEngine::SetPenStyle(DirectGdi::TPenStyle aStyle)
|
sl@0
|
508 |
{
|
sl@0
|
509 |
iPenStyle = aStyle;
|
sl@0
|
510 |
|
sl@0
|
511 |
if (!MakeEngineCurrent())
|
sl@0
|
512 |
return;
|
sl@0
|
513 |
|
sl@0
|
514 |
iPaintMode = iPaintMode | VG_STROKE_PATH;
|
sl@0
|
515 |
|
sl@0
|
516 |
switch (aStyle)
|
sl@0
|
517 |
{
|
sl@0
|
518 |
case DirectGdi::ENullPen:
|
sl@0
|
519 |
{
|
sl@0
|
520 |
iPaintMode = iPaintMode & (~VG_STROKE_PATH); // Unset stroke bit
|
sl@0
|
521 |
vgSetfv(VG_STROKE_DASH_PATTERN, 0, NULL);
|
sl@0
|
522 |
vgSetf(VG_STROKE_DASH_PHASE, 0.f);
|
sl@0
|
523 |
break;
|
sl@0
|
524 |
}
|
sl@0
|
525 |
|
sl@0
|
526 |
case DirectGdi::ESolidPen:
|
sl@0
|
527 |
{
|
sl@0
|
528 |
vgSetfv(VG_STROKE_DASH_PATTERN, 0, NULL);
|
sl@0
|
529 |
vgSetf(VG_STROKE_DASH_PHASE, 0.f);
|
sl@0
|
530 |
break;
|
sl@0
|
531 |
}
|
sl@0
|
532 |
|
sl@0
|
533 |
case DirectGdi::EDottedPen:
|
sl@0
|
534 |
{
|
sl@0
|
535 |
VGfloat offset = (iPenSize.iWidth > 1) ? 2.f : 0.f;
|
sl@0
|
536 |
VGfloat dashPattern[2] = {(1*iPenSize.iWidth)-offset, (3*iPenSize.iWidth)+offset};
|
sl@0
|
537 |
vgSetfv(VG_STROKE_DASH_PATTERN, 2, dashPattern);
|
sl@0
|
538 |
vgSetf(VG_STROKE_DASH_PHASE, 1.f);
|
sl@0
|
539 |
break;
|
sl@0
|
540 |
}
|
sl@0
|
541 |
|
sl@0
|
542 |
case DirectGdi::EDashedPen:
|
sl@0
|
543 |
{
|
sl@0
|
544 |
VGfloat offset = (iPenSize.iWidth > 1) ? 2.f : 0.f;
|
sl@0
|
545 |
VGfloat dashPattern[2] = {(3*iPenSize.iWidth)-offset, (3*iPenSize.iWidth)+offset};
|
sl@0
|
546 |
vgSetfv(VG_STROKE_DASH_PATTERN, 2, dashPattern);
|
sl@0
|
547 |
vgSetf(VG_STROKE_DASH_PHASE, (iPenSize.iWidth != 1) ? 1.f : 0.f);
|
sl@0
|
548 |
break;
|
sl@0
|
549 |
}
|
sl@0
|
550 |
|
sl@0
|
551 |
case DirectGdi::EDotDashPen:
|
sl@0
|
552 |
{
|
sl@0
|
553 |
VGfloat offset = (iPenSize.iWidth > 1) ? 2.f : 0.f;
|
sl@0
|
554 |
VGfloat dashPattern[4] = {(1*iPenSize.iWidth)-offset, (3*iPenSize.iWidth)+offset, (3*iPenSize.iWidth)-offset, (3*iPenSize.iWidth)+offset};
|
sl@0
|
555 |
vgSetfv(VG_STROKE_DASH_PATTERN, 4, dashPattern);
|
sl@0
|
556 |
vgSetf(VG_STROKE_DASH_PHASE, 1.f);
|
sl@0
|
557 |
break;
|
sl@0
|
558 |
}
|
sl@0
|
559 |
|
sl@0
|
560 |
case DirectGdi::EDotDotDashPen:
|
sl@0
|
561 |
{
|
sl@0
|
562 |
VGfloat offset = (iPenSize.iWidth > 1) ? 2.f : 0.f;
|
sl@0
|
563 |
VGfloat dashPattern[6] = {(1*iPenSize.iWidth)-offset, (3*iPenSize.iWidth)+offset, (1*iPenSize.iWidth)-offset, (3*iPenSize.iWidth)+offset, (3*iPenSize.iWidth)-offset, (3*iPenSize.iWidth)+offset};
|
sl@0
|
564 |
vgSetfv(VG_STROKE_DASH_PATTERN, 6, dashPattern);
|
sl@0
|
565 |
vgSetf(VG_STROKE_DASH_PHASE, (iPenSize.iWidth != 1) ? 1.f : 0.f);
|
sl@0
|
566 |
break;
|
sl@0
|
567 |
}
|
sl@0
|
568 |
|
sl@0
|
569 |
default:
|
sl@0
|
570 |
{
|
sl@0
|
571 |
// Copy BitGdi behaviour here and draw a solid line for any unknown pen style
|
sl@0
|
572 |
vgSetfv(VG_STROKE_DASH_PATTERN, 0, NULL);
|
sl@0
|
573 |
vgSetf(VG_STROKE_DASH_PHASE, 0.f);
|
sl@0
|
574 |
break;
|
sl@0
|
575 |
}
|
sl@0
|
576 |
}
|
sl@0
|
577 |
}
|
sl@0
|
578 |
|
sl@0
|
579 |
|
sl@0
|
580 |
/**
|
sl@0
|
581 |
@see MDirectGdiEngine::SetPenSize()
|
sl@0
|
582 |
*/
|
sl@0
|
583 |
void CVgEngine::SetPenSize(const TSize& aSize)
|
sl@0
|
584 |
{
|
sl@0
|
585 |
iPenSize = aSize;
|
sl@0
|
586 |
|
sl@0
|
587 |
if (!MakeEngineCurrent())
|
sl@0
|
588 |
return;
|
sl@0
|
589 |
|
sl@0
|
590 |
// VG_STROKE_LINE_WIDTH expects a float
|
sl@0
|
591 |
// Note that we set the pen size using just the width in the assumption that the pen width
|
sl@0
|
592 |
// and height are normally the same. For the special cases where the pen width and height
|
sl@0
|
593 |
// are different, the pen size is set to (1,1) then scaled to give the effect of a pen with
|
sl@0
|
594 |
// different width and height. This is done for all functions in this file that draws shapes,
|
sl@0
|
595 |
// see Plot(), DrawLine(), DrawArc(), DrawRect() etc.
|
sl@0
|
596 |
vgSetf(VG_STROKE_LINE_WIDTH, aSize.iWidth);
|
sl@0
|
597 |
|
sl@0
|
598 |
// Re-set the pen style as the pen size has changed, SetPenStyle() uses the pen size to set
|
sl@0
|
599 |
// the dotted line styles.
|
sl@0
|
600 |
SetPenStyle(iPenStyle);
|
sl@0
|
601 |
}
|
sl@0
|
602 |
|
sl@0
|
603 |
/**
|
sl@0
|
604 |
@see MDirectGdiEngine::SetTextShadowColor()
|
sl@0
|
605 |
*/
|
sl@0
|
606 |
void CVgEngine::SetTextShadowColor(const TRgb& aColor)
|
sl@0
|
607 |
{
|
sl@0
|
608 |
iTextShadowColor = aColor; //just cache this color
|
sl@0
|
609 |
}
|
sl@0
|
610 |
|
sl@0
|
611 |
|
sl@0
|
612 |
/**
|
sl@0
|
613 |
@see MDirectGdiEngine::SetBrushColor()
|
sl@0
|
614 |
*/
|
sl@0
|
615 |
void CVgEngine::SetBrushColor(const TRgb& aColor)
|
sl@0
|
616 |
{
|
sl@0
|
617 |
iBrushColor = aColor;
|
sl@0
|
618 |
|
sl@0
|
619 |
if (!MakeEngineCurrent())
|
sl@0
|
620 |
return;
|
sl@0
|
621 |
|
sl@0
|
622 |
// Convert the color components as that they are between 0.0f and 1.0f
|
sl@0
|
623 |
VGfloat color[4];
|
sl@0
|
624 |
color[0] = aColor.Red() * KColorConversion;
|
sl@0
|
625 |
color[1] = aColor.Green() * KColorConversion;
|
sl@0
|
626 |
color[2] = aColor.Blue() * KColorConversion;
|
sl@0
|
627 |
color[3] = aColor.Alpha() * KColorConversion;
|
sl@0
|
628 |
|
sl@0
|
629 |
// Make sure our brush is the current selected brush for filling before we set the color
|
sl@0
|
630 |
if (iBrushStyle != DirectGdi::ENullBrush)
|
sl@0
|
631 |
vgSetPaint(iBrush, VG_FILL_PATH);
|
sl@0
|
632 |
|
sl@0
|
633 |
vgSetParameteri(iBrush, VG_PAINT_TYPE, VG_PAINT_TYPE_COLOR);
|
sl@0
|
634 |
vgSetParameterfv(iBrush, VG_PAINT_COLOR, 4, color);
|
sl@0
|
635 |
|
sl@0
|
636 |
// Set the clear color and the tile fill color as well as these should both
|
sl@0
|
637 |
// be the same as the brush color
|
sl@0
|
638 |
vgSetParameterfv(iClearBrush, VG_PAINT_COLOR, 4, color);
|
sl@0
|
639 |
vgSetfv(VG_CLEAR_COLOR, 4, color);
|
sl@0
|
640 |
vgSetfv(VG_TILE_FILL_COLOR, 4, color);
|
sl@0
|
641 |
|
sl@0
|
642 |
// If using a patterned brush, need to reconstruct it as the colours may be out of sync.
|
sl@0
|
643 |
if ((iBrushStyle != DirectGdi::ENullBrush) && (iBrushStyle != DirectGdi::ESolidBrush))
|
sl@0
|
644 |
{
|
sl@0
|
645 |
SetBrushStyle(iBrushStyle);
|
sl@0
|
646 |
}
|
sl@0
|
647 |
}
|
sl@0
|
648 |
|
sl@0
|
649 |
|
sl@0
|
650 |
/**
|
sl@0
|
651 |
The DirectGDI brush styles do not map directly to OpenVG, so brushes for styles > DirectGdi::EPatternedBrush
|
sl@0
|
652 |
are created as bitmaps before being set.
|
sl@0
|
653 |
|
sl@0
|
654 |
@see MDirectGdiEngine::SetBrushColor()
|
sl@0
|
655 |
@see CreateStandardBrush()
|
sl@0
|
656 |
*/
|
sl@0
|
657 |
void CVgEngine::SetBrushStyle(DirectGdi::TBrushStyle aStyle)
|
sl@0
|
658 |
{
|
sl@0
|
659 |
iBrushStyle = aStyle;
|
sl@0
|
660 |
|
sl@0
|
661 |
if (!MakeEngineCurrent())
|
sl@0
|
662 |
return;
|
sl@0
|
663 |
|
sl@0
|
664 |
TInt standardBrushErr = KErrNone;
|
sl@0
|
665 |
const TInt standardBrushSize = 3;
|
sl@0
|
666 |
const TInt standardBrushArea = standardBrushSize*standardBrushSize;
|
sl@0
|
667 |
const TInt diamondCrossHatchBrushSize = 4;
|
sl@0
|
668 |
const TInt diamondCrossHatchBrushArea = diamondCrossHatchBrushSize*diamondCrossHatchBrushSize;
|
sl@0
|
669 |
|
sl@0
|
670 |
// Select the brush for drawing any style that is not ENullBrush
|
sl@0
|
671 |
iPaintMode = iPaintMode | VG_FILL_PATH;
|
sl@0
|
672 |
if (aStyle != DirectGdi::ENullBrush)
|
sl@0
|
673 |
vgSetPaint(iBrush, VG_FILL_PATH);
|
sl@0
|
674 |
|
sl@0
|
675 |
// Paint using a pattern for all styles that are not ENullBrush or ESolidBrush
|
sl@0
|
676 |
if ((aStyle != DirectGdi::ENullBrush) && (aStyle != DirectGdi::ESolidBrush))
|
sl@0
|
677 |
{
|
sl@0
|
678 |
vgSetParameteri(iBrush, VG_PAINT_TYPE, VG_PAINT_TYPE_PATTERN);
|
sl@0
|
679 |
vgSetParameteri(iBrush, VG_PAINT_PATTERN_TILING_MODE, VG_TILE_REPEAT);
|
sl@0
|
680 |
}
|
sl@0
|
681 |
|
sl@0
|
682 |
switch (aStyle)
|
sl@0
|
683 |
{
|
sl@0
|
684 |
case DirectGdi::ENullBrush:
|
sl@0
|
685 |
iPaintMode = iPaintMode & (~VG_FILL_PATH);
|
sl@0
|
686 |
|
sl@0
|
687 |
// Clear the current brush so that no brush color is drawn
|
sl@0
|
688 |
vgSetPaint(VG_INVALID_HANDLE, VG_FILL_PATH);
|
sl@0
|
689 |
break;
|
sl@0
|
690 |
|
sl@0
|
691 |
case DirectGdi::ESolidBrush:
|
sl@0
|
692 |
// Paint using a solid color
|
sl@0
|
693 |
vgSetParameteri(iBrush, VG_PAINT_TYPE, VG_PAINT_TYPE_COLOR);
|
sl@0
|
694 |
break;
|
sl@0
|
695 |
|
sl@0
|
696 |
case DirectGdi::EPatternedBrush:
|
sl@0
|
697 |
// Make sure the user has set a patterned brush for use
|
sl@0
|
698 |
GRAPHICS_ASSERT_ALWAYS(iBrushPatternUser != VG_INVALID_HANDLE, EDirectGdiPanicPatternedBrushNotSet);
|
sl@0
|
699 |
|
sl@0
|
700 |
if (NonZeroBrushPatternOrigin())
|
sl@0
|
701 |
{
|
sl@0
|
702 |
// The brush origin is non-zero, update the non-zero origin brush
|
sl@0
|
703 |
// with the user brush and use that instead of the user brush
|
sl@0
|
704 |
CopyCurrentBrushPatternForNonZeroOrigin();
|
sl@0
|
705 |
}
|
sl@0
|
706 |
else
|
sl@0
|
707 |
{
|
sl@0
|
708 |
// Set the brush to fill with the user selected bitmap pattern
|
sl@0
|
709 |
vgPaintPattern(iBrush, iBrushPatternUser);
|
sl@0
|
710 |
}
|
sl@0
|
711 |
break;
|
sl@0
|
712 |
|
sl@0
|
713 |
case DirectGdi::EVerticalHatchBrush:
|
sl@0
|
714 |
{
|
sl@0
|
715 |
// The brush fills with vertical hatching lines going from top to bottom
|
sl@0
|
716 |
TSize size(standardBrushSize, standardBrushSize);
|
sl@0
|
717 |
VGbyte brushPattern[standardBrushArea] = {0,0,1, 0,0,1, 0,0,1};
|
sl@0
|
718 |
standardBrushErr = CreateStandardBrush(size, brushPattern);
|
sl@0
|
719 |
break;
|
sl@0
|
720 |
}
|
sl@0
|
721 |
|
sl@0
|
722 |
case DirectGdi::EForwardDiagonalHatchBrush:
|
sl@0
|
723 |
{
|
sl@0
|
724 |
// The brush fills with diagonal hatching lines going from bottom left to top right
|
sl@0
|
725 |
TSize size(standardBrushSize, standardBrushSize);
|
sl@0
|
726 |
VGbyte brushPattern[standardBrushArea] = {1,0,0, 0,0,1, 0,1,0};
|
sl@0
|
727 |
standardBrushErr = CreateStandardBrush(size, brushPattern);
|
sl@0
|
728 |
break;
|
sl@0
|
729 |
}
|
sl@0
|
730 |
|
sl@0
|
731 |
case DirectGdi::EHorizontalHatchBrush:
|
sl@0
|
732 |
{
|
sl@0
|
733 |
// The brush fills with horizontal hatching lines going from left to right
|
sl@0
|
734 |
TSize size(standardBrushSize, standardBrushSize);
|
sl@0
|
735 |
VGbyte brushPattern[standardBrushArea] = {0,0,0, 0,0,0, 1,1,1};
|
sl@0
|
736 |
standardBrushErr = CreateStandardBrush(size, brushPattern);
|
sl@0
|
737 |
break;
|
sl@0
|
738 |
}
|
sl@0
|
739 |
|
sl@0
|
740 |
case DirectGdi::ERearwardDiagonalHatchBrush:
|
sl@0
|
741 |
{
|
sl@0
|
742 |
// The brush fills with rearward diagonal hatching lines going from top left to bottom right
|
sl@0
|
743 |
TSize size(standardBrushSize, standardBrushSize);
|
sl@0
|
744 |
VGbyte brushPattern[standardBrushArea] = {1,0,0, 0,1,0, 0,0,1};
|
sl@0
|
745 |
standardBrushErr = CreateStandardBrush(size, brushPattern);
|
sl@0
|
746 |
break;
|
sl@0
|
747 |
}
|
sl@0
|
748 |
|
sl@0
|
749 |
case DirectGdi::ESquareCrossHatchBrush:
|
sl@0
|
750 |
{
|
sl@0
|
751 |
// The brush fills with horizontal and vertical hatching lines going from left to right
|
sl@0
|
752 |
// plus lines going from top to bottom giving the effect of a grid of small squares
|
sl@0
|
753 |
TSize size(standardBrushSize, standardBrushSize);
|
sl@0
|
754 |
VGbyte brushPattern[standardBrushArea] = {0,0,1, 0,0,1, 1,1,1};
|
sl@0
|
755 |
standardBrushErr = CreateStandardBrush(size, brushPattern);
|
sl@0
|
756 |
break;
|
sl@0
|
757 |
}
|
sl@0
|
758 |
|
sl@0
|
759 |
case DirectGdi::EDiamondCrossHatchBrush:
|
sl@0
|
760 |
{
|
sl@0
|
761 |
// The brush fills with forward diagonal and rearward diagonal hatching lines going from
|
sl@0
|
762 |
// bottom left to top right plus lines going from top left to bottom right giving the effect
|
sl@0
|
763 |
// of a grid of small diamonds
|
sl@0
|
764 |
// The brush fills with diagonal hatching lines going from bottom left to top right
|
sl@0
|
765 |
TSize size(diamondCrossHatchBrushSize, diamondCrossHatchBrushSize);
|
sl@0
|
766 |
VGbyte brushPattern[diamondCrossHatchBrushArea] = {0,0,1,0, 0,1,0,1, 1,0,0,0, 0,1,0,1};
|
sl@0
|
767 |
standardBrushErr = CreateStandardBrush(size, brushPattern);
|
sl@0
|
768 |
break;
|
sl@0
|
769 |
}
|
sl@0
|
770 |
}
|
sl@0
|
771 |
|
sl@0
|
772 |
// Select the standard brush for all styles > EPatternedBrush
|
sl@0
|
773 |
if (aStyle > DirectGdi::EPatternedBrush)
|
sl@0
|
774 |
{
|
sl@0
|
775 |
if (standardBrushErr == KErrNone)
|
sl@0
|
776 |
{
|
sl@0
|
777 |
if (NonZeroBrushPatternOrigin())
|
sl@0
|
778 |
{
|
sl@0
|
779 |
// The brush origin is non-zero, update the non-zero origin brush
|
sl@0
|
780 |
// with the standard brush and use that instead of the standard brush
|
sl@0
|
781 |
CopyCurrentBrushPatternForNonZeroOrigin();
|
sl@0
|
782 |
}
|
sl@0
|
783 |
else
|
sl@0
|
784 |
{
|
sl@0
|
785 |
// Use the standard brush region
|
sl@0
|
786 |
vgPaintPattern(iBrush, iBrushPatternStandardRegion);
|
sl@0
|
787 |
}
|
sl@0
|
788 |
}
|
sl@0
|
789 |
else
|
sl@0
|
790 |
{
|
sl@0
|
791 |
iDriver.SetError(standardBrushErr);
|
sl@0
|
792 |
}
|
sl@0
|
793 |
}
|
sl@0
|
794 |
else
|
sl@0
|
795 |
{
|
sl@0
|
796 |
vgSeti(VG_IMAGE_MODE, VG_DRAW_IMAGE_NORMAL);
|
sl@0
|
797 |
}
|
sl@0
|
798 |
}
|
sl@0
|
799 |
|
sl@0
|
800 |
/**
|
sl@0
|
801 |
@see MDirectGdiEngine::SetBrushOrigin()
|
sl@0
|
802 |
*/
|
sl@0
|
803 |
void CVgEngine::SetBrushOrigin(const TPoint& aOrigin)
|
sl@0
|
804 |
{
|
sl@0
|
805 |
iBrushOrigin = aOrigin;
|
sl@0
|
806 |
if (NonZeroBrushPatternOrigin())
|
sl@0
|
807 |
{
|
sl@0
|
808 |
// Copy the current brush pattern into iBrushPatternNonZeroOrigin, but shift it to
|
sl@0
|
809 |
// take into account the current non-zero brush origin.
|
sl@0
|
810 |
CopyCurrentBrushPatternForNonZeroOrigin();
|
sl@0
|
811 |
}
|
sl@0
|
812 |
}
|
sl@0
|
813 |
|
sl@0
|
814 |
|
sl@0
|
815 |
/**
|
sl@0
|
816 |
@see MDirectGdiEngine::SetBrushPattern()
|
sl@0
|
817 |
*/
|
sl@0
|
818 |
TInt CVgEngine::SetBrushPattern(const CFbsBitmap& aPattern)
|
sl@0
|
819 |
{
|
sl@0
|
820 |
if (aPattern.ExtendedBitmapType() != KNullUid)
|
sl@0
|
821 |
{
|
sl@0
|
822 |
return KErrNotSupported; // Not supported for extended bitmaps
|
sl@0
|
823 |
}
|
sl@0
|
824 |
|
sl@0
|
825 |
// Destroy any previously set brush pattern
|
sl@0
|
826 |
MakeEngineCurrent();
|
sl@0
|
827 |
ResetBrushPattern();
|
sl@0
|
828 |
iBrushPatternUser = CreateSourceVGImage(aPattern);
|
sl@0
|
829 |
if (iBrushPatternUser == VG_INVALID_HANDLE)
|
sl@0
|
830 |
{
|
sl@0
|
831 |
return KErrNoMemory;
|
sl@0
|
832 |
}
|
sl@0
|
833 |
|
sl@0
|
834 |
iBrushPatternUserSize = aPattern.SizeInPixels();
|
sl@0
|
835 |
iBrushPatternUserBitmapHandle = aPattern.Handle();
|
sl@0
|
836 |
return KErrNone;
|
sl@0
|
837 |
}
|
sl@0
|
838 |
|
sl@0
|
839 |
|
sl@0
|
840 |
/**
|
sl@0
|
841 |
@see MDirectGdiEngine::ResetBrushPattern()
|
sl@0
|
842 |
*/
|
sl@0
|
843 |
void CVgEngine::ResetBrushPattern()
|
sl@0
|
844 |
{
|
sl@0
|
845 |
MakeEngineCurrent();
|
sl@0
|
846 |
if (iBrushPatternUser != VG_INVALID_HANDLE)
|
sl@0
|
847 |
{
|
sl@0
|
848 |
vgDestroyImage(iBrushPatternUser);
|
sl@0
|
849 |
iBrushPatternUser = VG_INVALID_HANDLE;
|
sl@0
|
850 |
iBrushPatternUserBitmapHandle = KNullHandle;
|
sl@0
|
851 |
iBrushPatternUserSize = TSize(0,0);
|
sl@0
|
852 |
}
|
sl@0
|
853 |
}
|
sl@0
|
854 |
|
sl@0
|
855 |
/**
|
sl@0
|
856 |
@see MDirectGdiEngine::SetFont()
|
sl@0
|
857 |
*/
|
sl@0
|
858 |
void CVgEngine::SetFont(TUint32 aFontId)
|
sl@0
|
859 |
{
|
sl@0
|
860 |
iFontId = aFontId;
|
sl@0
|
861 |
}
|
sl@0
|
862 |
|
sl@0
|
863 |
|
sl@0
|
864 |
/**
|
sl@0
|
865 |
@see MDirectGdiEngine::ResetFont()
|
sl@0
|
866 |
*/
|
sl@0
|
867 |
void CVgEngine::ResetFont()
|
sl@0
|
868 |
{
|
sl@0
|
869 |
iFontId = 0;
|
sl@0
|
870 |
}
|
sl@0
|
871 |
|
sl@0
|
872 |
/**
|
sl@0
|
873 |
Reset all the VgEngine-specific settings. Generic settings such as paint colour and pen colour
|
sl@0
|
874 |
are set by calls from the CDirectGdiContext.
|
sl@0
|
875 |
|
sl@0
|
876 |
@see MDirectGdiEngine::Reset()
|
sl@0
|
877 |
|
sl@0
|
878 |
@post All VgEngine-specific settings have been reset to their default values.
|
sl@0
|
879 |
*/
|
sl@0
|
880 |
void CVgEngine::Reset()
|
sl@0
|
881 |
{
|
sl@0
|
882 |
if (!MakeEngineCurrent())
|
sl@0
|
883 |
return;
|
sl@0
|
884 |
|
sl@0
|
885 |
ResetVgMatrix();
|
sl@0
|
886 |
}
|
sl@0
|
887 |
|
sl@0
|
888 |
|
sl@0
|
889 |
|
sl@0
|
890 |
/**
|
sl@0
|
891 |
@see MDirectGdiEngine::Clear(const TRect&)
|
sl@0
|
892 |
|
sl@0
|
893 |
@panic DGDIAdapter 62, if the brush for clearing is not valid (debug-only).
|
sl@0
|
894 |
*/
|
sl@0
|
895 |
void CVgEngine::Clear(const TRect& aRect)
|
sl@0
|
896 |
{
|
sl@0
|
897 |
MakeEngineCurrent();
|
sl@0
|
898 |
|
sl@0
|
899 |
if (255 == iBrushColor.Alpha())
|
sl@0
|
900 |
{
|
sl@0
|
901 |
const TPoint rectOrigin = ConvertToVgCoords(aRect);
|
sl@0
|
902 |
for (iRegionManager.Begin(); iRegionManager.ApplyClipRegion(); iRegionManager.Next())
|
sl@0
|
903 |
vgClear(rectOrigin.iX, rectOrigin.iY, aRect.Width(), aRect.Height());
|
sl@0
|
904 |
}
|
sl@0
|
905 |
else
|
sl@0
|
906 |
{
|
sl@0
|
907 |
// If blending is enabled, we cannot use vgClear as it ignores the current blendmode and performs a WriteAlpha.
|
sl@0
|
908 |
// Therefore a clear is done by a filled rectangle.
|
sl@0
|
909 |
|
sl@0
|
910 |
// The Clear brush should always be a solid brush.
|
sl@0
|
911 |
GRAPHICS_ASSERT_DEBUG(vgGetParameteri(iClearBrush, VG_PAINT_TYPE) == VG_PAINT_TYPE_COLOR, EDirectGdiPanicClearBrushInvalid);
|
sl@0
|
912 |
|
sl@0
|
913 |
if (PreparePath(iVgPath, 5))
|
sl@0
|
914 |
{
|
sl@0
|
915 |
// Before any vgu command, call SetError() as this stores the current OpenVG error state (if any)
|
sl@0
|
916 |
// on the driver. Some implementations of vgu clears error state so we'd lose error codes otherwise.
|
sl@0
|
917 |
iDriver.SetError(KErrNone);
|
sl@0
|
918 |
|
sl@0
|
919 |
VGUErrorCode err = vguRect(iVgPath, aRect.iTl.iX, aRect.iTl.iY, aRect.Width(), aRect.Height());
|
sl@0
|
920 |
if (err == VGU_NO_ERROR)
|
sl@0
|
921 |
{
|
sl@0
|
922 |
// Temporarily set the brush to the clear brush and fill the path.
|
sl@0
|
923 |
vgSetPaint(iClearBrush, VG_FILL_PATH);
|
sl@0
|
924 |
for (iRegionManager.Begin(); iRegionManager.ApplyClipRegion(); iRegionManager.Next())
|
sl@0
|
925 |
vgDrawPath(iVgPath, VG_FILL_PATH);
|
sl@0
|
926 |
vgSetPaint(iBrush, VG_FILL_PATH);
|
sl@0
|
927 |
}
|
sl@0
|
928 |
else
|
sl@0
|
929 |
{
|
sl@0
|
930 |
SetVguError(err);
|
sl@0
|
931 |
}
|
sl@0
|
932 |
}
|
sl@0
|
933 |
}
|
sl@0
|
934 |
}
|
sl@0
|
935 |
|
sl@0
|
936 |
/**
|
sl@0
|
937 |
@see MDirectGdiEngine::Clear()
|
sl@0
|
938 |
*/
|
sl@0
|
939 |
void CVgEngine::Clear()
|
sl@0
|
940 |
{
|
sl@0
|
941 |
Clear(TRect(iSize));
|
sl@0
|
942 |
}
|
sl@0
|
943 |
|
sl@0
|
944 |
/**
|
sl@0
|
945 |
@see MDirectGdiEngine::MoveTo()
|
sl@0
|
946 |
*/
|
sl@0
|
947 |
void CVgEngine::MoveTo(const TPoint& aPoint)
|
sl@0
|
948 |
{
|
sl@0
|
949 |
iLinePos = aPoint;
|
sl@0
|
950 |
}
|
sl@0
|
951 |
|
sl@0
|
952 |
/**
|
sl@0
|
953 |
@see MDirectGdiEngine::MoveBy()
|
sl@0
|
954 |
*/
|
sl@0
|
955 |
void CVgEngine::MoveBy(const TPoint& aVector)
|
sl@0
|
956 |
{
|
sl@0
|
957 |
iLinePos += aVector;
|
sl@0
|
958 |
}
|
sl@0
|
959 |
|
sl@0
|
960 |
/**
|
sl@0
|
961 |
@see MDirectGdiEngine::Plot()
|
sl@0
|
962 |
*/
|
sl@0
|
963 |
void CVgEngine::Plot(const TPoint& aPoint)
|
sl@0
|
964 |
{
|
sl@0
|
965 |
MakeEngineCurrent();
|
sl@0
|
966 |
GRAPHICS_ASSERT_DEBUG(vgGeti(VG_STROKE_CAP_STYLE) == VG_CAP_ROUND, EDirectGdiPanicPenEndCapStyleNotRound);
|
sl@0
|
967 |
|
sl@0
|
968 |
|
sl@0
|
969 |
// If the pen width and height are equal just plot as normal.
|
sl@0
|
970 |
if (iPenSize.iWidth == iPenSize.iHeight)
|
sl@0
|
971 |
{
|
sl@0
|
972 |
if (PreparePath(iVgPath, 2))
|
sl@0
|
973 |
{
|
sl@0
|
974 |
// A point is plotted by drawing a line with start and end points the same.
|
sl@0
|
975 |
AppendPathCommand(VG_MOVE_TO_ABS, aPoint.iX + 0.5f, aPoint.iY + 0.5f);
|
sl@0
|
976 |
AppendPathCommand(VG_HLINE_TO_REL, 0.f);
|
sl@0
|
977 |
FinishPath(iVgPath);
|
sl@0
|
978 |
|
sl@0
|
979 |
for (iRegionManager.Begin(); iRegionManager.ApplyClipRegion(); iRegionManager.Next())
|
sl@0
|
980 |
vgDrawPath(iVgPath, iPaintMode&VG_STROKE_PATH);
|
sl@0
|
981 |
}
|
sl@0
|
982 |
}
|
sl@0
|
983 |
else if ((iPenSize.iWidth != 0) && (iPenSize.iHeight != 0))
|
sl@0
|
984 |
{
|
sl@0
|
985 |
// Setting a pen with different width and height is not available on OpenVG, so we need to scale
|
sl@0
|
986 |
// the coordinates we are drawing and apply a scaling matrix that scales by the width and height
|
sl@0
|
987 |
// of the pen to get the effect of a pen width different width and height.
|
sl@0
|
988 |
if (PreparePath(iVgPath, 2))
|
sl@0
|
989 |
{
|
sl@0
|
990 |
TSize penSize = iPenSize;
|
sl@0
|
991 |
SetPenSize(TSize(1, 1));
|
sl@0
|
992 |
vgSeti(VG_MATRIX_MODE, VG_MATRIX_PATH_USER_TO_SURFACE);
|
sl@0
|
993 |
vgScale(penSize.iWidth, penSize.iHeight);
|
sl@0
|
994 |
|
sl@0
|
995 |
// A point is plotted by drawing a line with start and end points the same.
|
sl@0
|
996 |
AppendPathCommand(VG_MOVE_TO_ABS, (aPoint.iX + 0.5f)/(float)penSize.iWidth, (aPoint.iY + 0.5f)/(float)penSize.iHeight);
|
sl@0
|
997 |
AppendPathCommand(VG_HLINE_TO_REL, 0.f);
|
sl@0
|
998 |
FinishPath(iVgPath);
|
sl@0
|
999 |
|
sl@0
|
1000 |
vgDrawPath(iVgPath, iPaintMode&VG_STROKE_PATH);
|
sl@0
|
1001 |
|
sl@0
|
1002 |
ResetVgMatrix(VG_MATRIX_PATH_USER_TO_SURFACE);
|
sl@0
|
1003 |
SetPenSize(penSize);
|
sl@0
|
1004 |
}
|
sl@0
|
1005 |
}
|
sl@0
|
1006 |
}
|
sl@0
|
1007 |
|
sl@0
|
1008 |
/**
|
sl@0
|
1009 |
@see MDirectGdiEngine::DrawLine()
|
sl@0
|
1010 |
*/
|
sl@0
|
1011 |
void CVgEngine::DrawLine(const TPoint& aStart, const TPoint& aEnd)
|
sl@0
|
1012 |
{
|
sl@0
|
1013 |
MakeEngineCurrent();
|
sl@0
|
1014 |
GRAPHICS_ASSERT_DEBUG(vgGeti(VG_STROKE_CAP_STYLE) == VG_CAP_ROUND, EDirectGdiPanicPenEndCapStyleNotRound);
|
sl@0
|
1015 |
|
sl@0
|
1016 |
if (iPaintMode == 0)
|
sl@0
|
1017 |
{
|
sl@0
|
1018 |
return;
|
sl@0
|
1019 |
}
|
sl@0
|
1020 |
|
sl@0
|
1021 |
if (PreparePath(iVgPath, 2))
|
sl@0
|
1022 |
{
|
sl@0
|
1023 |
// If the pen width and height are the same then draw as normal
|
sl@0
|
1024 |
if (iPenSize.iWidth == iPenSize.iHeight)
|
sl@0
|
1025 |
{
|
sl@0
|
1026 |
// 0.5 is appended to all OpenVG drawing co-ordinates as when specifying them, the spec says
|
sl@0
|
1027 |
// co-ordinates are relative to pixel boundaries, not pixel centres, so 0,0 is the top left of the
|
sl@0
|
1028 |
// top pixel. We need to add 0.5 to specify the centre of pixels.
|
sl@0
|
1029 |
|
sl@0
|
1030 |
AppendPathCommand(VG_MOVE_TO_ABS, aStart.iX + 0.5f, aStart.iY + 0.5f);
|
sl@0
|
1031 |
if (aStart.iX == aEnd.iX)
|
sl@0
|
1032 |
{
|
sl@0
|
1033 |
AppendPathCommand(VG_VLINE_TO_ABS, aEnd.iY + 0.5f);
|
sl@0
|
1034 |
}
|
sl@0
|
1035 |
else if (aStart.iY == aEnd.iY)
|
sl@0
|
1036 |
{
|
sl@0
|
1037 |
AppendPathCommand(VG_HLINE_TO_ABS, aEnd.iX + 0.5f);
|
sl@0
|
1038 |
}
|
sl@0
|
1039 |
else
|
sl@0
|
1040 |
{
|
sl@0
|
1041 |
AppendPathCommand(VG_LINE_TO_ABS, aEnd.iX + 0.5f, aEnd.iY + 0.5f);
|
sl@0
|
1042 |
}
|
sl@0
|
1043 |
FinishPath(iVgPath);
|
sl@0
|
1044 |
for (iRegionManager.Begin(); iRegionManager.ApplyClipRegion(); iRegionManager.Next())
|
sl@0
|
1045 |
vgDrawPath(iVgPath, iPaintMode);
|
sl@0
|
1046 |
}
|
sl@0
|
1047 |
else if ((iPenSize.iWidth != 0) && (iPenSize.iHeight != 0))
|
sl@0
|
1048 |
{
|
sl@0
|
1049 |
// Setting a pen with different width and height is not available on OpenVG, so we need to scale
|
sl@0
|
1050 |
// the coordinates we are drawing and apply a scaling matrix that scales by the width and height
|
sl@0
|
1051 |
// of the pen to get the effect of a pen width different width and height.
|
sl@0
|
1052 |
TSize penSize = iPenSize;
|
sl@0
|
1053 |
SetPenSize(TSize(1, 1));
|
sl@0
|
1054 |
vgSeti(VG_MATRIX_MODE, VG_MATRIX_PATH_USER_TO_SURFACE);
|
sl@0
|
1055 |
vgScale(penSize.iWidth, penSize.iHeight);
|
sl@0
|
1056 |
|
sl@0
|
1057 |
VGfloat scaleX = 1.0f/(float)penSize.iWidth;
|
sl@0
|
1058 |
VGfloat scaleY = 1.0f/(float)penSize.iHeight;
|
sl@0
|
1059 |
AppendPathCommand(VG_MOVE_TO_ABS, (aStart.iX + 0.5f)*scaleX, (aStart.iY + 0.5f)*scaleY);
|
sl@0
|
1060 |
if (aStart.iX == aEnd.iX)
|
sl@0
|
1061 |
{
|
sl@0
|
1062 |
AppendPathCommand(VG_VLINE_TO_ABS, (aEnd.iY + 0.5f)*scaleY);
|
sl@0
|
1063 |
}
|
sl@0
|
1064 |
else if (aStart.iY == aEnd.iY)
|
sl@0
|
1065 |
{
|
sl@0
|
1066 |
AppendPathCommand(VG_HLINE_TO_ABS, (aEnd.iX + 0.5f)*scaleX);
|
sl@0
|
1067 |
}
|
sl@0
|
1068 |
else
|
sl@0
|
1069 |
{
|
sl@0
|
1070 |
AppendPathCommand(VG_LINE_TO_ABS, (aEnd.iX + 0.5f)*scaleX, (aEnd.iY + 0.5f)*scaleY);
|
sl@0
|
1071 |
}
|
sl@0
|
1072 |
FinishPath(iVgPath);
|
sl@0
|
1073 |
vgDrawPath(iVgPath, iPaintMode);
|
sl@0
|
1074 |
|
sl@0
|
1075 |
ResetVgMatrix(VG_MATRIX_PATH_USER_TO_SURFACE);
|
sl@0
|
1076 |
SetPenSize(penSize);
|
sl@0
|
1077 |
}
|
sl@0
|
1078 |
}
|
sl@0
|
1079 |
|
sl@0
|
1080 |
iLinePos = aEnd;
|
sl@0
|
1081 |
}
|
sl@0
|
1082 |
|
sl@0
|
1083 |
/**
|
sl@0
|
1084 |
@see MDirectGdiEngine::DrawLineTo()
|
sl@0
|
1085 |
*/
|
sl@0
|
1086 |
void CVgEngine::DrawLineTo(const TPoint& aPoint)
|
sl@0
|
1087 |
{
|
sl@0
|
1088 |
DrawLine(iLinePos, aPoint);
|
sl@0
|
1089 |
}
|
sl@0
|
1090 |
|
sl@0
|
1091 |
/**
|
sl@0
|
1092 |
@see MDirectGdiEngine::DrawLineBy()
|
sl@0
|
1093 |
*/
|
sl@0
|
1094 |
void CVgEngine::DrawLineBy(const TPoint& aVector)
|
sl@0
|
1095 |
{
|
sl@0
|
1096 |
DrawLine(iLinePos, iLinePos + aVector);
|
sl@0
|
1097 |
}
|
sl@0
|
1098 |
|
sl@0
|
1099 |
/**
|
sl@0
|
1100 |
@see MDirectGdiEngine::DrawRect()
|
sl@0
|
1101 |
*/
|
sl@0
|
1102 |
void CVgEngine::DrawRect(const TRect& aRect)
|
sl@0
|
1103 |
{
|
sl@0
|
1104 |
MakeEngineCurrent();
|
sl@0
|
1105 |
|
sl@0
|
1106 |
// Only draw if we are not painting with a NULL pen and a NULL brush
|
sl@0
|
1107 |
if (iPaintMode == 0)
|
sl@0
|
1108 |
return;
|
sl@0
|
1109 |
|
sl@0
|
1110 |
// If the pen size is larger then 1, make sure we are using the ESolidPen
|
sl@0
|
1111 |
// pen style (to match BitGdi behaviour)
|
sl@0
|
1112 |
DirectGdi::TPenStyle savedPenStyle = iPenStyle;
|
sl@0
|
1113 |
if (((iPenSize.iWidth > 1) || (iPenSize.iHeight > 1)) && (iPenStyle > DirectGdi::ESolidPen))
|
sl@0
|
1114 |
SetPenStyle(DirectGdi::ESolidPen);
|
sl@0
|
1115 |
|
sl@0
|
1116 |
// Create a copy of the rect. If the pen style is not null, we have to shrink the
|
sl@0
|
1117 |
// width and height of the rect by one pixel at the bottom left corner for conformance.
|
sl@0
|
1118 |
TRect copyRect(aRect.iTl.iX, aRect.iTl.iY, aRect.iBr.iX, aRect.iBr.iY-1);
|
sl@0
|
1119 |
if (iPenStyle != DirectGdi::ENullPen)
|
sl@0
|
1120 |
{
|
sl@0
|
1121 |
--copyRect.iBr.iX;
|
sl@0
|
1122 |
}
|
sl@0
|
1123 |
else
|
sl@0
|
1124 |
{
|
sl@0
|
1125 |
--copyRect.iTl.iY;
|
sl@0
|
1126 |
}
|
sl@0
|
1127 |
|
sl@0
|
1128 |
const TBool symmetricalPenSize = iPenSize.iWidth == iPenSize.iHeight;
|
sl@0
|
1129 |
|
sl@0
|
1130 |
// If the pen is so thick it covers the entire area of the rect, don't do the fill, as per BitGdi.
|
sl@0
|
1131 |
const TBool penThickerThanRect = (iPenSize.iWidth >= copyRect.Width()) || (iPenSize.iHeight >= copyRect.Height());
|
sl@0
|
1132 |
|
sl@0
|
1133 |
// If the pen width and height are the same then draw as normal. If they are different but we should be filling
|
sl@0
|
1134 |
// this shape we need to draw the filled area only as normal (not the outline). The outline of the shape is drawn
|
sl@0
|
1135 |
// in the block of code below to allow the effect of a different width and height pen to be applied.
|
sl@0
|
1136 |
if (!penThickerThanRect || (iPenStyle == DirectGdi::ENullPen))
|
sl@0
|
1137 |
{
|
sl@0
|
1138 |
if (symmetricalPenSize || (iPaintMode & VG_FILL_PATH))
|
sl@0
|
1139 |
{
|
sl@0
|
1140 |
if (PreparePath(iVgPath, 5))
|
sl@0
|
1141 |
{
|
sl@0
|
1142 |
vgSeti(VG_STROKE_JOIN_STYLE, VG_JOIN_MITER);
|
sl@0
|
1143 |
AppendPathCommand(VG_MOVE_TO_ABS, copyRect.iTl.iX + 0.5f, copyRect.iTl.iY + 0.5f);
|
sl@0
|
1144 |
AppendPathCommand(VG_HLINE_TO_ABS, copyRect.iBr.iX + 0.5f);
|
sl@0
|
1145 |
AppendPathCommand(VG_VLINE_TO_ABS, copyRect.iBr.iY + 0.5f);
|
sl@0
|
1146 |
AppendPathCommand(VG_HLINE_TO_ABS, copyRect.iTl.iX + 0.5f);
|
sl@0
|
1147 |
AppendPathCommand(VG_CLOSE_PATH);
|
sl@0
|
1148 |
FinishPath(iVgPath);
|
sl@0
|
1149 |
|
sl@0
|
1150 |
for (iRegionManager.Begin(); iRegionManager.ApplyClipRegion(); iRegionManager.Next())
|
sl@0
|
1151 |
vgDrawPath(iVgPath, symmetricalPenSize ? iPaintMode : VG_FILL_PATH);
|
sl@0
|
1152 |
vgSeti(VG_STROKE_JOIN_STYLE, VG_JOIN_ROUND);
|
sl@0
|
1153 |
}
|
sl@0
|
1154 |
}
|
sl@0
|
1155 |
}
|
sl@0
|
1156 |
if((penThickerThanRect && (iPenStyle != DirectGdi::ENullPen)) || //we shouldn't draw if pen style is null
|
sl@0
|
1157 |
(!symmetricalPenSize && (iPaintMode & VG_STROKE_PATH) && (iPenSize.iWidth != 0) && (iPenSize.iHeight != 0)))
|
sl@0
|
1158 |
{
|
sl@0
|
1159 |
// Setting a pen with different width and height is not available on OpenVG, so we need to scale
|
sl@0
|
1160 |
// the coordinates we are drawing and apply a scaling matrix that scales by the width and height
|
sl@0
|
1161 |
// of the pen to get the effect of a pen width different width and height.
|
sl@0
|
1162 |
TSize penSize = iPenSize;
|
sl@0
|
1163 |
SetPenSize(TSize(1, 1));
|
sl@0
|
1164 |
vgSeti(VG_MATRIX_MODE, VG_MATRIX_PATH_USER_TO_SURFACE);
|
sl@0
|
1165 |
vgScale(penSize.iWidth, penSize.iHeight);
|
sl@0
|
1166 |
|
sl@0
|
1167 |
if (PreparePath(iVgPath, 5))
|
sl@0
|
1168 |
{
|
sl@0
|
1169 |
vgSeti(VG_STROKE_JOIN_STYLE, VG_JOIN_MITER);
|
sl@0
|
1170 |
VGfloat scaleX = 1.0f/(float)penSize.iWidth;
|
sl@0
|
1171 |
VGfloat scaleY = 1.0f/(float)penSize.iHeight;
|
sl@0
|
1172 |
AppendPathCommand(VG_MOVE_TO_ABS, (copyRect.iTl.iX + 0.5f)*scaleX, (copyRect.iTl.iY + 0.5f)*scaleY);
|
sl@0
|
1173 |
AppendPathCommand(VG_HLINE_TO_ABS, (copyRect.iBr.iX + 0.5f)*scaleX);
|
sl@0
|
1174 |
AppendPathCommand(VG_VLINE_TO_ABS, (copyRect.iBr.iY + 0.5f)*scaleY);
|
sl@0
|
1175 |
AppendPathCommand(VG_HLINE_TO_ABS, (copyRect.iTl.iX + 0.5f)*scaleX);
|
sl@0
|
1176 |
AppendPathCommand(VG_CLOSE_PATH);
|
sl@0
|
1177 |
FinishPath(iVgPath);
|
sl@0
|
1178 |
for (iRegionManager.Begin(); iRegionManager.ApplyClipRegion(); iRegionManager.Next())
|
sl@0
|
1179 |
vgDrawPath(iVgPath, VG_STROKE_PATH);
|
sl@0
|
1180 |
vgSeti(VG_STROKE_JOIN_STYLE, VG_JOIN_ROUND);
|
sl@0
|
1181 |
}
|
sl@0
|
1182 |
|
sl@0
|
1183 |
ResetVgMatrix(VG_MATRIX_PATH_USER_TO_SURFACE);
|
sl@0
|
1184 |
SetPenSize(penSize);
|
sl@0
|
1185 |
}
|
sl@0
|
1186 |
|
sl@0
|
1187 |
// Reset the pen style if we changed it above
|
sl@0
|
1188 |
if (savedPenStyle != iPenStyle)
|
sl@0
|
1189 |
SetPenStyle(savedPenStyle);
|
sl@0
|
1190 |
}
|
sl@0
|
1191 |
|
sl@0
|
1192 |
/**
|
sl@0
|
1193 |
@see MDirectGdiEngine::DrawRoundRect()
|
sl@0
|
1194 |
*/
|
sl@0
|
1195 |
void CVgEngine::DrawRoundRect(const TRect& aRect, const TSize& aCornerSize)
|
sl@0
|
1196 |
{
|
sl@0
|
1197 |
MakeEngineCurrent();
|
sl@0
|
1198 |
|
sl@0
|
1199 |
// Only draw if we are not painting with a NULL pen and a NULL brush
|
sl@0
|
1200 |
if (iPaintMode == 0)
|
sl@0
|
1201 |
return;
|
sl@0
|
1202 |
|
sl@0
|
1203 |
// Create a copy of the rect. If the pen style is not null, we have to shrink the
|
sl@0
|
1204 |
// width and height of the rect by one pixel at the bottom left corner for conformance.
|
sl@0
|
1205 |
TRect copyRect(aRect.iTl.iX, aRect.iTl.iY, aRect.iBr.iX, aRect.iBr.iY-1);
|
sl@0
|
1206 |
if (iPenStyle != DirectGdi::ENullPen)
|
sl@0
|
1207 |
{
|
sl@0
|
1208 |
--copyRect.iBr.iX;
|
sl@0
|
1209 |
}
|
sl@0
|
1210 |
//If the penstyle is null and brush style is not null, then reduce the width and height by
|
sl@0
|
1211 |
//two pixels for conformation.
|
sl@0
|
1212 |
else if(iBrushStyle != DirectGdi::ENullBrush)
|
sl@0
|
1213 |
{
|
sl@0
|
1214 |
----copyRect.iBr.iX;
|
sl@0
|
1215 |
--copyRect.iBr.iY;
|
sl@0
|
1216 |
}
|
sl@0
|
1217 |
else if(iPenStyle == DirectGdi::ENullPen)
|
sl@0
|
1218 |
{
|
sl@0
|
1219 |
--copyRect.iTl.iY;
|
sl@0
|
1220 |
}
|
sl@0
|
1221 |
|
sl@0
|
1222 |
// check that the corner size is less than the rectangle size
|
sl@0
|
1223 |
if ((aRect.Width() > aCornerSize.iWidth) || (aRect.Height() > aCornerSize.iHeight))
|
sl@0
|
1224 |
{
|
sl@0
|
1225 |
// Before any vgu command, call SetError() as this stores the current vg error state (if any) in the
|
sl@0
|
1226 |
// driver. Some implementations of vgu clears error state so we'd lose error codes otherwise.
|
sl@0
|
1227 |
iDriver.SetError(KErrNone);
|
sl@0
|
1228 |
|
sl@0
|
1229 |
// If the pen width and height are the same then draw as normal. If they are different but we should be filling
|
sl@0
|
1230 |
// this shape we need to draw the filled area only as normal (not the outline). The outline of the shape is drawn
|
sl@0
|
1231 |
// in the block of code below to allow the effect of a different width and height pen to be applied.
|
sl@0
|
1232 |
if ((iPenSize.iWidth == iPenSize.iHeight) || (iPaintMode & VG_FILL_PATH))
|
sl@0
|
1233 |
{
|
sl@0
|
1234 |
if (PreparePath(iVgPath, 10))
|
sl@0
|
1235 |
{
|
sl@0
|
1236 |
VGUErrorCode err = vguRoundRect(iVgPath,
|
sl@0
|
1237 |
copyRect.iTl.iX + 0.5f,
|
sl@0
|
1238 |
copyRect.iTl.iY + 0.5f,
|
sl@0
|
1239 |
copyRect.Width(),
|
sl@0
|
1240 |
copyRect.Height(),
|
sl@0
|
1241 |
aCornerSize.iWidth * 2,
|
sl@0
|
1242 |
aCornerSize.iHeight * 2);
|
sl@0
|
1243 |
|
sl@0
|
1244 |
if (err == VGU_NO_ERROR)
|
sl@0
|
1245 |
{
|
sl@0
|
1246 |
for (iRegionManager.Begin(); iRegionManager.ApplyClipRegion(); iRegionManager.Next())
|
sl@0
|
1247 |
vgDrawPath(iVgPath, (iPenSize.iWidth == iPenSize.iHeight) ? iPaintMode : VG_FILL_PATH);
|
sl@0
|
1248 |
}
|
sl@0
|
1249 |
else
|
sl@0
|
1250 |
{
|
sl@0
|
1251 |
SetVguError(err);
|
sl@0
|
1252 |
}
|
sl@0
|
1253 |
}
|
sl@0
|
1254 |
}
|
sl@0
|
1255 |
|
sl@0
|
1256 |
if ((iPenSize.iWidth != iPenSize.iHeight)
|
sl@0
|
1257 |
&& (iPaintMode & VG_STROKE_PATH)
|
sl@0
|
1258 |
&& (iPenSize.iWidth != 0) && (iPenSize.iHeight != 0))
|
sl@0
|
1259 |
{
|
sl@0
|
1260 |
// Setting a pen with different width and height is not available on OpenVG, so we need to scale
|
sl@0
|
1261 |
// the coordinates we are drawing and apply a scaling matrix that scales by the width and height
|
sl@0
|
1262 |
// of the pen to get the effect of a pen width different width and height.
|
sl@0
|
1263 |
TSize penSize = iPenSize;
|
sl@0
|
1264 |
SetPenSize(TSize(1, 1));
|
sl@0
|
1265 |
vgSeti(VG_MATRIX_MODE, VG_MATRIX_PATH_USER_TO_SURFACE);
|
sl@0
|
1266 |
vgScale(penSize.iWidth, penSize.iHeight);
|
sl@0
|
1267 |
|
sl@0
|
1268 |
if (PreparePath(iVgPath, 10))
|
sl@0
|
1269 |
{
|
sl@0
|
1270 |
VGfloat scaleX = 1.0f/(float)penSize.iWidth;
|
sl@0
|
1271 |
VGfloat scaleY = 1.0f/(float)penSize.iHeight;
|
sl@0
|
1272 |
VGUErrorCode err = vguRoundRect(iVgPath,
|
sl@0
|
1273 |
(copyRect.iTl.iX + 0.5f) * scaleX,
|
sl@0
|
1274 |
(copyRect.iTl.iY + 0.5f) * scaleY,
|
sl@0
|
1275 |
copyRect.Width() * scaleX,
|
sl@0
|
1276 |
copyRect.Height() * scaleY,
|
sl@0
|
1277 |
(aCornerSize.iWidth * 2) * scaleX,
|
sl@0
|
1278 |
(aCornerSize.iHeight * 2) * scaleY);
|
sl@0
|
1279 |
if (err == VGU_NO_ERROR)
|
sl@0
|
1280 |
{
|
sl@0
|
1281 |
vgDrawPath(iVgPath, VG_STROKE_PATH);
|
sl@0
|
1282 |
}
|
sl@0
|
1283 |
else
|
sl@0
|
1284 |
{
|
sl@0
|
1285 |
SetVguError(err);
|
sl@0
|
1286 |
}
|
sl@0
|
1287 |
}
|
sl@0
|
1288 |
|
sl@0
|
1289 |
ResetVgMatrix(VG_MATRIX_PATH_USER_TO_SURFACE);
|
sl@0
|
1290 |
SetPenSize(penSize);
|
sl@0
|
1291 |
}
|
sl@0
|
1292 |
}
|
sl@0
|
1293 |
else
|
sl@0
|
1294 |
{
|
sl@0
|
1295 |
// Draw an ellipse as the corner size is greater than or equal to the rectangle size
|
sl@0
|
1296 |
DrawEllipse(copyRect);
|
sl@0
|
1297 |
}
|
sl@0
|
1298 |
}
|
sl@0
|
1299 |
|
sl@0
|
1300 |
/**
|
sl@0
|
1301 |
@see MDirectGdiEngine::DrawPolyLine()
|
sl@0
|
1302 |
|
sl@0
|
1303 |
@panic DGDIAdapter 27, if the passed point list has zero points (debug-only).
|
sl@0
|
1304 |
*/
|
sl@0
|
1305 |
void CVgEngine::DrawPolyLine(const TArray<TPoint>& aPointList)
|
sl@0
|
1306 |
{
|
sl@0
|
1307 |
DrawPolyLineNoEndPoint(aPointList);
|
sl@0
|
1308 |
|
sl@0
|
1309 |
// Do a plot at the end point to improve the appearance. For larger pen-sizes, a plot
|
sl@0
|
1310 |
// improves the correlation with BitGDI polylines, giving a subtly more rounded finish.
|
sl@0
|
1311 |
if (DirectGdi::ESolidPen == iPenStyle)
|
sl@0
|
1312 |
{
|
sl@0
|
1313 |
Plot(iLinePos);
|
sl@0
|
1314 |
}
|
sl@0
|
1315 |
}
|
sl@0
|
1316 |
|
sl@0
|
1317 |
/**
|
sl@0
|
1318 |
@see MDirectGdiEngine::DrawPolyLineNoEndPoint()
|
sl@0
|
1319 |
|
sl@0
|
1320 |
@panic DGDIAdapter 27, if the passed point list has zero points (debug-only).
|
sl@0
|
1321 |
*/
|
sl@0
|
1322 |
void CVgEngine::DrawPolyLineNoEndPoint(const TArray<TPoint>& aPointList)
|
sl@0
|
1323 |
{
|
sl@0
|
1324 |
MakeEngineCurrent();
|
sl@0
|
1325 |
|
sl@0
|
1326 |
GRAPHICS_ASSERT_DEBUG(aPointList.Count() > 0, EDirectGdiPanicInvalidPointArray);
|
sl@0
|
1327 |
|
sl@0
|
1328 |
DoDrawPoly(aPointList, EFalse);
|
sl@0
|
1329 |
}
|
sl@0
|
1330 |
|
sl@0
|
1331 |
/**
|
sl@0
|
1332 |
@see MDirectGdiEngine::DrawPolygon()
|
sl@0
|
1333 |
|
sl@0
|
1334 |
@panic DGDIAdapter 26, if the passed fill-rule is invalid (debug-only).
|
sl@0
|
1335 |
*/
|
sl@0
|
1336 |
void CVgEngine::DrawPolygon(const TArray<TPoint>& aPoints, DirectGdi::TFillRule aRule)
|
sl@0
|
1337 |
{
|
sl@0
|
1338 |
MakeEngineCurrent();
|
sl@0
|
1339 |
|
sl@0
|
1340 |
GRAPHICS_ASSERT_DEBUG(aPoints.Count() > 0, EDirectGdiPanicInvalidPointArray);
|
sl@0
|
1341 |
|
sl@0
|
1342 |
switch(aRule)
|
sl@0
|
1343 |
{
|
sl@0
|
1344 |
case DirectGdi::EAlternate:
|
sl@0
|
1345 |
vgSeti(VG_FILL_RULE, VG_EVEN_ODD);
|
sl@0
|
1346 |
break;
|
sl@0
|
1347 |
case DirectGdi::EWinding:
|
sl@0
|
1348 |
vgSeti(VG_FILL_RULE, VG_NON_ZERO);
|
sl@0
|
1349 |
break;
|
sl@0
|
1350 |
default:
|
sl@0
|
1351 |
GRAPHICS_PANIC_DEBUG(EDirectGdiPanicInvalidFillRule);
|
sl@0
|
1352 |
return;
|
sl@0
|
1353 |
};
|
sl@0
|
1354 |
|
sl@0
|
1355 |
DoDrawPoly(aPoints, ETrue);
|
sl@0
|
1356 |
}
|
sl@0
|
1357 |
|
sl@0
|
1358 |
/**
|
sl@0
|
1359 |
Helper function to assist with drawing polygons with DrawPolygon()/DrawPolyLine(). It takes care of
|
sl@0
|
1360 |
drawing the array of points given to it. It sets the internal drawing poisition to the last TPoint
|
sl@0
|
1361 |
in the array.
|
sl@0
|
1362 |
|
sl@0
|
1363 |
@see DrawPolyLine()
|
sl@0
|
1364 |
@see DrawPolygon()
|
sl@0
|
1365 |
|
sl@0
|
1366 |
@param aPoints Array of points specifying the vertices of the polygon. There must be at least one
|
sl@0
|
1367 |
vertex.
|
sl@0
|
1368 |
@param aClosed If ETrue, the start and end points are joined, and the polygon filled using current
|
sl@0
|
1369 |
brush settings, otherwise just a polyline is drawn.
|
sl@0
|
1370 |
*/
|
sl@0
|
1371 |
void CVgEngine::DoDrawPoly(const TArray<TPoint>& aPoints, TBool aClosed)
|
sl@0
|
1372 |
{
|
sl@0
|
1373 |
GRAPHICS_ASSERT_DEBUG(aPoints.Count() > 0, EDirectGdiPanicInvalidPointArray);
|
sl@0
|
1374 |
const TInt numPoints = aPoints.Count();
|
sl@0
|
1375 |
|
sl@0
|
1376 |
// Set drawing position to last point in the array (regardless of whether the poly is open/closed)
|
sl@0
|
1377 |
iLinePos = aPoints[numPoints - 1];
|
sl@0
|
1378 |
|
sl@0
|
1379 |
// Set the paint mode depending on whether we are drawing a line (not closed) or a poly (closed)
|
sl@0
|
1380 |
VGbitfield paintMode = iPaintMode;
|
sl@0
|
1381 |
if (!aClosed)
|
sl@0
|
1382 |
{
|
sl@0
|
1383 |
paintMode &= ~VG_FILL_PATH;
|
sl@0
|
1384 |
}
|
sl@0
|
1385 |
|
sl@0
|
1386 |
if (!paintMode)
|
sl@0
|
1387 |
{
|
sl@0
|
1388 |
return;
|
sl@0
|
1389 |
}
|
sl@0
|
1390 |
|
sl@0
|
1391 |
// If the pen width and height are the same then draw as normal. If they are different but we should be filling
|
sl@0
|
1392 |
// this shape we need to draw the filled area only as normal (not the outline). The outline of the shape is drawn
|
sl@0
|
1393 |
// in the block of code below to allow the effect of a different width and height pen to be applied.
|
sl@0
|
1394 |
if ((iPenSize.iWidth == iPenSize.iHeight) || (paintMode & VG_FILL_PATH))
|
sl@0
|
1395 |
{
|
sl@0
|
1396 |
if (PreparePath(iVgPath, aClosed ? numPoints + 1 : numPoints))
|
sl@0
|
1397 |
{
|
sl@0
|
1398 |
AppendPathCommand(VG_MOVE_TO_ABS, aPoints[0].iX + 0.5f, aPoints[0].iY + 0.5f);
|
sl@0
|
1399 |
for (TInt point = 0; point < numPoints; ++point)
|
sl@0
|
1400 |
{
|
sl@0
|
1401 |
AppendPathCommand(VG_LINE_TO_ABS, aPoints[point].iX + 0.5f, aPoints[point].iY + 0.5f);
|
sl@0
|
1402 |
}
|
sl@0
|
1403 |
if (aClosed)
|
sl@0
|
1404 |
{
|
sl@0
|
1405 |
AppendPathCommand(VG_CLOSE_PATH);
|
sl@0
|
1406 |
}
|
sl@0
|
1407 |
FinishPath(iVgPath);
|
sl@0
|
1408 |
for (iRegionManager.Begin(); iRegionManager.ApplyClipRegion(); iRegionManager.Next())
|
sl@0
|
1409 |
vgDrawPath(iVgPath, (iPenSize.iWidth == iPenSize.iHeight) ? paintMode : VG_FILL_PATH);
|
sl@0
|
1410 |
}
|
sl@0
|
1411 |
}
|
sl@0
|
1412 |
|
sl@0
|
1413 |
if ((iPenSize.iWidth != iPenSize.iHeight)
|
sl@0
|
1414 |
&& (paintMode & VG_STROKE_PATH)
|
sl@0
|
1415 |
&& (iPenSize.iWidth != 0) && (iPenSize.iHeight != 0))
|
sl@0
|
1416 |
{
|
sl@0
|
1417 |
// Setting a pen with different width and height is not available on OpenVG, so we need to scale
|
sl@0
|
1418 |
// the coordinates we are drawing and apply a scaling matrix that scales by the width and height
|
sl@0
|
1419 |
// of the pen to get the effect of a pen width different width and height.
|
sl@0
|
1420 |
TSize penSize = iPenSize;
|
sl@0
|
1421 |
SetPenSize(TSize(1, 1));
|
sl@0
|
1422 |
vgSeti(VG_MATRIX_MODE, VG_MATRIX_PATH_USER_TO_SURFACE);
|
sl@0
|
1423 |
vgScale(penSize.iWidth, penSize.iHeight);
|
sl@0
|
1424 |
|
sl@0
|
1425 |
if (PreparePath(iVgPath, aClosed ? numPoints + 1 : numPoints))
|
sl@0
|
1426 |
{
|
sl@0
|
1427 |
AppendPathCommand(VG_MOVE_TO_ABS, (aPoints[0].iX + 0.5f)/(float)penSize.iWidth, (aPoints[0].iY + 0.5f)/(float)penSize.iHeight);
|
sl@0
|
1428 |
for (TInt point = 0; point < numPoints; ++point)
|
sl@0
|
1429 |
{
|
sl@0
|
1430 |
AppendPathCommand(VG_LINE_TO_ABS, (aPoints[point].iX + 0.5f)/(float)penSize.iWidth, (aPoints[point].iY + 0.5f)/(float)penSize.iHeight);
|
sl@0
|
1431 |
}
|
sl@0
|
1432 |
if (aClosed)
|
sl@0
|
1433 |
{
|
sl@0
|
1434 |
AppendPathCommand(VG_CLOSE_PATH);
|
sl@0
|
1435 |
}
|
sl@0
|
1436 |
FinishPath(iVgPath);
|
sl@0
|
1437 |
vgDrawPath(iVgPath, VG_STROKE_PATH);
|
sl@0
|
1438 |
}
|
sl@0
|
1439 |
|
sl@0
|
1440 |
ResetVgMatrix(VG_MATRIX_PATH_USER_TO_SURFACE);
|
sl@0
|
1441 |
SetPenSize(penSize);
|
sl@0
|
1442 |
}
|
sl@0
|
1443 |
|
sl@0
|
1444 |
}
|
sl@0
|
1445 |
|
sl@0
|
1446 |
/**
|
sl@0
|
1447 |
@see MDirectGdiEngine::DrawArc()
|
sl@0
|
1448 |
@see DrawPie()
|
sl@0
|
1449 |
@see DrawArc(const TRect&, const TPoint&, const TPoint&, VGUArcType)
|
sl@0
|
1450 |
*/
|
sl@0
|
1451 |
void CVgEngine::DrawArc(const TRect& aRect, const TPoint& aStart, const TPoint& aEnd)
|
sl@0
|
1452 |
{
|
sl@0
|
1453 |
DoDrawArc(aRect, aStart, aEnd, VGU_ARC_OPEN);
|
sl@0
|
1454 |
}
|
sl@0
|
1455 |
|
sl@0
|
1456 |
/**
|
sl@0
|
1457 |
@see MDirectGdiEngine::DrawPie()
|
sl@0
|
1458 |
@see DrawArc(const TRect&, const TPoint&, const TPoint&)
|
sl@0
|
1459 |
@see DrawArc(const TRect&, const TPoint&, const TPoint&, VGUArcType)
|
sl@0
|
1460 |
*/
|
sl@0
|
1461 |
void CVgEngine::DrawPie(const TRect& aRect, const TPoint& aStart, const TPoint& aEnd)
|
sl@0
|
1462 |
{
|
sl@0
|
1463 |
DoDrawArc(aRect, aStart, aEnd, VGU_ARC_PIE);
|
sl@0
|
1464 |
}
|
sl@0
|
1465 |
|
sl@0
|
1466 |
/**
|
sl@0
|
1467 |
@see MDirectGdiEngine::DrawEllipse()
|
sl@0
|
1468 |
*/
|
sl@0
|
1469 |
void CVgEngine::DrawEllipse(const TRect& aRect)
|
sl@0
|
1470 |
{
|
sl@0
|
1471 |
// Null brush and pen, draw nothing.
|
sl@0
|
1472 |
if (iPaintMode == 0)
|
sl@0
|
1473 |
return;
|
sl@0
|
1474 |
|
sl@0
|
1475 |
MakeEngineCurrent();
|
sl@0
|
1476 |
VGfloat x = (aRect.iTl.iX + aRect.iBr.iX) * 0.5;
|
sl@0
|
1477 |
VGfloat y = (aRect.iTl.iY + aRect.iBr.iY) * 0.5;
|
sl@0
|
1478 |
|
sl@0
|
1479 |
// Before any vgu command, call SetError() as this stores the current vg error state (if any) in the
|
sl@0
|
1480 |
// driver. Some implementations of vgu clears error state so we'd lose error codes otherwise.
|
sl@0
|
1481 |
iDriver.SetError(KErrNone);
|
sl@0
|
1482 |
|
sl@0
|
1483 |
TInt width = aRect.Width();
|
sl@0
|
1484 |
TInt height = aRect.Height();
|
sl@0
|
1485 |
|
sl@0
|
1486 |
//If the penstyle is null and brush style is not null, then reduce the width and height by
|
sl@0
|
1487 |
//two pixels for conformation.
|
sl@0
|
1488 |
if(iPenStyle == DirectGdi::ENullPen && iBrushStyle != DirectGdi::ENullBrush)
|
sl@0
|
1489 |
{
|
sl@0
|
1490 |
width = aRect.Width() > 2 ? aRect.Width() - 2 : 1;
|
sl@0
|
1491 |
height = aRect.Height() > 2 ? aRect.Height() - 2 : 1;
|
sl@0
|
1492 |
}
|
sl@0
|
1493 |
|
sl@0
|
1494 |
// If the pen width and height are the same then draw as normal. If they are different but we should be filling
|
sl@0
|
1495 |
// this shape we need to draw the filled area only as normal (not the outline). The outline of the shape is drawn
|
sl@0
|
1496 |
// in the block of code below to allow the effect of a different width and height pen to be applied.
|
sl@0
|
1497 |
if ((iPenSize.iWidth == iPenSize.iHeight) || (iPaintMode & VG_FILL_PATH))
|
sl@0
|
1498 |
{
|
sl@0
|
1499 |
if (PreparePath(iVgPath, 4))
|
sl@0
|
1500 |
{
|
sl@0
|
1501 |
VGUErrorCode err = vguEllipse(iVgPath, x, y, width, height);
|
sl@0
|
1502 |
if (err == VGU_NO_ERROR)
|
sl@0
|
1503 |
{
|
sl@0
|
1504 |
for (iRegionManager.Begin(); iRegionManager.ApplyClipRegion(); iRegionManager.Next())
|
sl@0
|
1505 |
vgDrawPath(iVgPath, (iPenSize.iWidth == iPenSize.iHeight) ? iPaintMode : VG_FILL_PATH);
|
sl@0
|
1506 |
}
|
sl@0
|
1507 |
else
|
sl@0
|
1508 |
{
|
sl@0
|
1509 |
SetVguError(err);
|
sl@0
|
1510 |
}
|
sl@0
|
1511 |
}
|
sl@0
|
1512 |
}
|
sl@0
|
1513 |
|
sl@0
|
1514 |
if ((iPenSize.iWidth != iPenSize.iHeight)
|
sl@0
|
1515 |
&& (iPaintMode & VG_STROKE_PATH)
|
sl@0
|
1516 |
&& (iPenSize.iWidth != 0) && (iPenSize.iHeight != 0))
|
sl@0
|
1517 |
{
|
sl@0
|
1518 |
// Setting a pen with different width and height is not available on OpenVG, so we need to scale
|
sl@0
|
1519 |
// the coordinates we are drawing and apply a scaling matrix that scales by the width and height
|
sl@0
|
1520 |
// of the pen to get the effect of a pen width different width and height.
|
sl@0
|
1521 |
TSize penSize = iPenSize;
|
sl@0
|
1522 |
SetPenSize(TSize(1, 1));
|
sl@0
|
1523 |
vgSeti(VG_MATRIX_MODE, VG_MATRIX_PATH_USER_TO_SURFACE);
|
sl@0
|
1524 |
vgScale(penSize.iWidth, penSize.iHeight);
|
sl@0
|
1525 |
|
sl@0
|
1526 |
VGfloat scaleX = 1.0f/(float)penSize.iWidth;
|
sl@0
|
1527 |
VGfloat scaleY = 1.0f/(float)penSize.iHeight;
|
sl@0
|
1528 |
|
sl@0
|
1529 |
if (PreparePath(iVgPath, 4))
|
sl@0
|
1530 |
{
|
sl@0
|
1531 |
VGUErrorCode err = vguEllipse(iVgPath, x*scaleX, y*scaleY, (float)width*scaleX, (float)height*scaleY);
|
sl@0
|
1532 |
if (err == VGU_NO_ERROR)
|
sl@0
|
1533 |
{
|
sl@0
|
1534 |
vgDrawPath(iVgPath, VG_STROKE_PATH);
|
sl@0
|
1535 |
}
|
sl@0
|
1536 |
else
|
sl@0
|
1537 |
{
|
sl@0
|
1538 |
SetVguError(err);
|
sl@0
|
1539 |
}
|
sl@0
|
1540 |
}
|
sl@0
|
1541 |
|
sl@0
|
1542 |
ResetVgMatrix(VG_MATRIX_PATH_USER_TO_SURFACE);
|
sl@0
|
1543 |
SetPenSize(penSize);
|
sl@0
|
1544 |
}
|
sl@0
|
1545 |
}
|
sl@0
|
1546 |
|
sl@0
|
1547 |
/**
|
sl@0
|
1548 |
Given a TDisplayMode, returns the closest TDisplayMode that is pixel-for-pixel-compatible
|
sl@0
|
1549 |
with an OpenVG format, such that the given TDisplayMode may be converted into the result
|
sl@0
|
1550 |
without loss of colour information.
|
sl@0
|
1551 |
|
sl@0
|
1552 |
@param aDisplayMode Pixel format to find a match for.
|
sl@0
|
1553 |
|
sl@0
|
1554 |
@return Closest TDisplayMode for which there is a OpenVG-compatible match.
|
sl@0
|
1555 |
*/
|
sl@0
|
1556 |
static TDisplayMode ClosestVgCompatibleDisplayMode(TDisplayMode aDisplayMode)
|
sl@0
|
1557 |
{
|
sl@0
|
1558 |
switch (aDisplayMode)
|
sl@0
|
1559 |
{
|
sl@0
|
1560 |
case EGray2:
|
sl@0
|
1561 |
case EGray4:
|
sl@0
|
1562 |
case EGray16:
|
sl@0
|
1563 |
return EGray256;
|
sl@0
|
1564 |
|
sl@0
|
1565 |
case EColor16:
|
sl@0
|
1566 |
case EColor256:
|
sl@0
|
1567 |
case EColor4K:
|
sl@0
|
1568 |
return EColor64K;
|
sl@0
|
1569 |
|
sl@0
|
1570 |
case EColor16M:
|
sl@0
|
1571 |
return EColor16MU;
|
sl@0
|
1572 |
|
sl@0
|
1573 |
default:
|
sl@0
|
1574 |
return aDisplayMode;
|
sl@0
|
1575 |
}
|
sl@0
|
1576 |
}
|
sl@0
|
1577 |
|
sl@0
|
1578 |
/**
|
sl@0
|
1579 |
Converts a CFbsBitmap into a VGImage.
|
sl@0
|
1580 |
If the CFbsBitmap is not a volatile bitmap, the VGImage created will be stored in the thread-wide
|
sl@0
|
1581 |
VGImage cache. If the CFbsBitmap has been touched (i.e. its data has been changed since it was last
|
sl@0
|
1582 |
used), a new VGImage will be created and will replace that currently stored in the cache. An untouched
|
sl@0
|
1583 |
bitmap will store the created VGImage in the cache upon first use, and on subsequent use (if it is
|
sl@0
|
1584 |
still untouched), will just retrieve the VGImage stored in the cache.
|
sl@0
|
1585 |
|
sl@0
|
1586 |
@param aBitmap The CFbsBitmap to create a VGImage from.
|
sl@0
|
1587 |
@param aImage Returns the VGImage created from the CFbsBitmap.
|
sl@0
|
1588 |
@param aIsMask True if the CFbsBitmap is to be used as a mask.
|
sl@0
|
1589 |
@param aOrigin Position of the first pixel in the mask bitmap.
|
sl@0
|
1590 |
|
sl@0
|
1591 |
@return ETrue if the VGimage has been stored in the cache, EFalse if not.
|
sl@0
|
1592 |
*/
|
sl@0
|
1593 |
TBool CVgEngine::ConvertBitmapToVgImage(const CFbsBitmap& aBitmap, VGImage& aImage, TBool aIsMask, const TPoint& aOrigin)
|
sl@0
|
1594 |
{
|
sl@0
|
1595 |
TBool createImage = EFalse;
|
sl@0
|
1596 |
TBool storeImageInCache = EFalse;
|
sl@0
|
1597 |
TBool imageCached = EFalse;
|
sl@0
|
1598 |
// Set the options createImage, storeImageInCache and imageCached depending on
|
sl@0
|
1599 |
// whether the bitmap is volatile, has been touched since last used,
|
sl@0
|
1600 |
// and whether it already exists in the cache
|
sl@0
|
1601 |
if (aBitmap.IsVolatile())
|
sl@0
|
1602 |
{
|
sl@0
|
1603 |
// Source bitmap is volatile and so should not be stored in cache.
|
sl@0
|
1604 |
// Therefore create image only.
|
sl@0
|
1605 |
createImage = ETrue;
|
sl@0
|
1606 |
}
|
sl@0
|
1607 |
else //bitmap not volatile
|
sl@0
|
1608 |
{
|
sl@0
|
1609 |
// Source bitmap has not changed since last used.
|
sl@0
|
1610 |
// Retrieve from cache the image created from the bitmap and the touchCount of that image.
|
sl@0
|
1611 |
aImage = iDriver.GetVgImageFromCache(aBitmap, aOrigin);
|
sl@0
|
1612 |
// If the source bitmap already has an associated VGImage stored in the cache,
|
sl@0
|
1613 |
// just use that VGImage. Otherwise, need to create a VGImage and add it to the cache.
|
sl@0
|
1614 |
if (aImage == VG_INVALID_HANDLE)
|
sl@0
|
1615 |
{
|
sl@0
|
1616 |
// VGImage not in cache
|
sl@0
|
1617 |
// Create image, and store in cache
|
sl@0
|
1618 |
createImage = ETrue;
|
sl@0
|
1619 |
storeImageInCache = ETrue;
|
sl@0
|
1620 |
}
|
sl@0
|
1621 |
else
|
sl@0
|
1622 |
{
|
sl@0
|
1623 |
// Image already in cache
|
sl@0
|
1624 |
imageCached = ETrue;
|
sl@0
|
1625 |
}
|
sl@0
|
1626 |
}
|
sl@0
|
1627 |
|
sl@0
|
1628 |
// Create a new VGImage if needed
|
sl@0
|
1629 |
if (createImage)
|
sl@0
|
1630 |
{
|
sl@0
|
1631 |
aImage = CreateSourceVGImage(aBitmap, aIsMask, aOrigin);
|
sl@0
|
1632 |
// Error set on creation of VGImage if aImage == VG_INVALID_HANDLE.
|
sl@0
|
1633 |
}
|
sl@0
|
1634 |
// Store the VGImage in the cache if appropriate
|
sl@0
|
1635 |
if (storeImageInCache && aImage != VG_INVALID_HANDLE)
|
sl@0
|
1636 |
{
|
sl@0
|
1637 |
imageCached = iDriver.AddVgImageToCache(aBitmap, aImage, aOrigin);
|
sl@0
|
1638 |
}
|
sl@0
|
1639 |
return imageCached;
|
sl@0
|
1640 |
}
|
sl@0
|
1641 |
|
sl@0
|
1642 |
|
sl@0
|
1643 |
/**
|
sl@0
|
1644 |
Transforms coordinates for a TRect from Symbian Graphics to OpenVG surface coordinates.
|
sl@0
|
1645 |
This is required for OpenVG operations which are not subject to user-to-surface
|
sl@0
|
1646 |
coordinate system transformations.
|
sl@0
|
1647 |
|
sl@0
|
1648 |
OpenVG coordinates locate the BOTTOM LEFT corner of the object relative to an origin
|
sl@0
|
1649 |
at the BOTTOM LEFT of the rendering area.
|
sl@0
|
1650 |
|
sl@0
|
1651 |
Symbian Graphics coordinates locate the TOP LEFT corner of the object relative to an
|
sl@0
|
1652 |
origin located at the TOP LEFT of the rendering area.
|
sl@0
|
1653 |
|
sl@0
|
1654 |
@param aCoord Top-left of the rectangle, in Symbian graphics coordinates.
|
sl@0
|
1655 |
@param aWidth The width of the desired rectangle.
|
sl@0
|
1656 |
@param aHeight The height of the desired rectangle.
|
sl@0
|
1657 |
@return A TRect in OpenVG coordinates which describes a rectangle at aCoord with aWidth and aHeight.
|
sl@0
|
1658 |
*/
|
sl@0
|
1659 |
TRect CVgEngine::SgMetricsToVgTRect(const TPoint& aCoord, const TInt aWidth, const TInt aHeight) const
|
sl@0
|
1660 |
{
|
sl@0
|
1661 |
return TRect (TPoint (aCoord.iX + iOrigin.iX, iSize.iHeight - (aCoord.iY + aHeight) - iOrigin.iY), TSize (aWidth, aHeight));
|
sl@0
|
1662 |
}
|
sl@0
|
1663 |
|
sl@0
|
1664 |
/**
|
sl@0
|
1665 |
@see MDirectGdiEngine::BitBlt()
|
sl@0
|
1666 |
@see BitBltMasked(const TPoint&, const CFbsBitmap&, const TRect&, const CFbsBitmap&, TBool)
|
sl@0
|
1667 |
@see BitBltMasked(const TPoint&, const CFbsBitmap&, const TRect&, const CFbsBitmap&, const TPoint&)
|
sl@0
|
1668 |
*/
|
sl@0
|
1669 |
void CVgEngine::BitBlt(const TPoint& aDestPos, const CFbsBitmap& aSourceBitmap, const TRect& aSourceRect)
|
sl@0
|
1670 |
{
|
sl@0
|
1671 |
if (aSourceBitmap.ExtendedBitmapType() != KNullUid)
|
sl@0
|
1672 |
{
|
sl@0
|
1673 |
iDriver.SetError(KErrNotSupported); // Not supported for extended bitmaps
|
sl@0
|
1674 |
return;
|
sl@0
|
1675 |
}
|
sl@0
|
1676 |
|
sl@0
|
1677 |
DoVgImageDraw (TRect (aDestPos, aSourceRect.Size()), aSourceBitmap, aSourceRect);
|
sl@0
|
1678 |
}
|
sl@0
|
1679 |
|
sl@0
|
1680 |
/**
|
sl@0
|
1681 |
@see MDirectGdiEngine::DrawBitmap()
|
sl@0
|
1682 |
@see DrawBitmapMasked()
|
sl@0
|
1683 |
*/
|
sl@0
|
1684 |
void CVgEngine::DrawBitmap(const TRect& aDestRect, const CFbsBitmap& aSourceBitmap, const TRect& aSourceRect)
|
sl@0
|
1685 |
{
|
sl@0
|
1686 |
if (aSourceBitmap.ExtendedBitmapType() != KNullUid)
|
sl@0
|
1687 |
{
|
sl@0
|
1688 |
iDriver.SetError(KErrNotSupported); // Not supported for extended bitmaps
|
sl@0
|
1689 |
return;
|
sl@0
|
1690 |
}
|
sl@0
|
1691 |
|
sl@0
|
1692 |
DoVgImageDraw (aDestRect, aSourceBitmap, aSourceRect);
|
sl@0
|
1693 |
}
|
sl@0
|
1694 |
|
sl@0
|
1695 |
|
sl@0
|
1696 |
/**
|
sl@0
|
1697 |
Helper method to perform basic VgDrawImage operations, explictly optimised for the case where
|
sl@0
|
1698 |
the extents of the source image equal the specified source region.
|
sl@0
|
1699 |
|
sl@0
|
1700 |
@pre aSource image is a valid VG image handle.
|
sl@0
|
1701 |
@pre Destination position and/or scaling has already been set in OpenVG.
|
sl@0
|
1702 |
|
sl@0
|
1703 |
@param aDestRect Destination rectangle to draw to.
|
sl@0
|
1704 |
@param aSourceBitmap Source bitmap to draw.
|
sl@0
|
1705 |
@param aSourceRect Source rectangle to render.
|
sl@0
|
1706 |
*/
|
sl@0
|
1707 |
void CVgEngine::DoVgImageDraw (const TRect& aDestRect, const CFbsBitmap& aSourceBitmap, const TRect& aSourceRect)
|
sl@0
|
1708 |
{
|
sl@0
|
1709 |
MakeEngineCurrent();
|
sl@0
|
1710 |
TRect destRect(aDestRect);
|
sl@0
|
1711 |
TRect srcRect(aSourceRect);
|
sl@0
|
1712 |
if (!IntersectsClippingRegion (TRect(iOrigin, destRect.Size())))
|
sl@0
|
1713 |
return;
|
sl@0
|
1714 |
|
sl@0
|
1715 |
VGImage sourceImage = VG_INVALID_HANDLE;
|
sl@0
|
1716 |
TBool imageCached = ConvertBitmapToVgImage(aSourceBitmap, sourceImage);
|
sl@0
|
1717 |
// Error set on creation of VGImage.
|
sl@0
|
1718 |
if (sourceImage == VG_INVALID_HANDLE) return;
|
sl@0
|
1719 |
|
sl@0
|
1720 |
vgSeti(VG_MATRIX_MODE, VG_MATRIX_IMAGE_USER_TO_SURFACE);
|
sl@0
|
1721 |
vgTranslate(destRect.iTl.iX, destRect.iTl.iY);
|
sl@0
|
1722 |
|
sl@0
|
1723 |
if (aDestRect.Size() != aSourceRect.Size())
|
sl@0
|
1724 |
vgScale((VGfloat)destRect.Width()/aSourceRect.Width(), (VGfloat)destRect.Height()/aSourceRect.Height());
|
sl@0
|
1725 |
|
sl@0
|
1726 |
if(aSourceBitmap.SizeInPixels() == aSourceRect.Size())
|
sl@0
|
1727 |
{
|
sl@0
|
1728 |
for (iRegionManager.Begin(); iRegionManager.ApplyClipRegion(); iRegionManager.Next())
|
sl@0
|
1729 |
vgDrawImage(sourceImage);
|
sl@0
|
1730 |
}
|
sl@0
|
1731 |
else
|
sl@0
|
1732 |
{
|
sl@0
|
1733 |
VGImage sourceImageRegion =
|
sl@0
|
1734 |
vgChildImage(
|
sl@0
|
1735 |
sourceImage,
|
sl@0
|
1736 |
srcRect.iTl.iX,
|
sl@0
|
1737 |
srcRect.iTl.iY,
|
sl@0
|
1738 |
srcRect.Width(),
|
sl@0
|
1739 |
srcRect.Height());
|
sl@0
|
1740 |
|
sl@0
|
1741 |
if (sourceImageRegion != VG_INVALID_HANDLE)
|
sl@0
|
1742 |
{
|
sl@0
|
1743 |
for (iRegionManager.Begin(); iRegionManager.ApplyClipRegion(); iRegionManager.Next())
|
sl@0
|
1744 |
vgDrawImage(sourceImageRegion);
|
sl@0
|
1745 |
|
sl@0
|
1746 |
vgDestroyImage(sourceImageRegion);
|
sl@0
|
1747 |
}
|
sl@0
|
1748 |
}
|
sl@0
|
1749 |
|
sl@0
|
1750 |
if (!imageCached) vgDestroyImage (sourceImage);
|
sl@0
|
1751 |
ResetVgMatrix(VG_MATRIX_IMAGE_USER_TO_SURFACE); // Reset the transform matrix.
|
sl@0
|
1752 |
}
|
sl@0
|
1753 |
|
sl@0
|
1754 |
/**
|
sl@0
|
1755 |
@see MDirectGdiEngine::BitBltMasked()
|
sl@0
|
1756 |
@see BitBltMasked(const TPoint&, const CFbsBitmap&, const TRect&, const CFbsBitmap&, TBool)
|
sl@0
|
1757 |
@see BitBlt()
|
sl@0
|
1758 |
*/
|
sl@0
|
1759 |
void CVgEngine::BitBltMasked(
|
sl@0
|
1760 |
const TPoint& aDestPos,
|
sl@0
|
1761 |
const CFbsBitmap& aBitmap,
|
sl@0
|
1762 |
const TRect& aSourceRect,
|
sl@0
|
1763 |
const CFbsBitmap& aMask,
|
sl@0
|
1764 |
const TPoint& aMaskPt)
|
sl@0
|
1765 |
{
|
sl@0
|
1766 |
if ((aBitmap.ExtendedBitmapType() != KNullUid) || (aMask.ExtendedBitmapType() != KNullUid))
|
sl@0
|
1767 |
{
|
sl@0
|
1768 |
iDriver.SetError(KErrNotSupported); // Not supported for extended bitmaps
|
sl@0
|
1769 |
return;
|
sl@0
|
1770 |
}
|
sl@0
|
1771 |
|
sl@0
|
1772 |
DoBitBltMasked(aDestPos, aBitmap, aSourceRect, aMask, EFalse, aMaskPt);
|
sl@0
|
1773 |
}
|
sl@0
|
1774 |
|
sl@0
|
1775 |
/**
|
sl@0
|
1776 |
@see MDirectGdiEngine::BitBlt()
|
sl@0
|
1777 |
@see BitBltMasked(const TPoint&, const CFbsBitmap&, const TRect&, const CFbsBitmap&, const TPoint&)
|
sl@0
|
1778 |
@see BitBlt()
|
sl@0
|
1779 |
*/
|
sl@0
|
1780 |
void CVgEngine::BitBltMasked(
|
sl@0
|
1781 |
const TPoint& aDestPos,
|
sl@0
|
1782 |
const CFbsBitmap& aSourceBitmap,
|
sl@0
|
1783 |
const TRect& aSourceRect,
|
sl@0
|
1784 |
const CFbsBitmap& aMaskBitmap,
|
sl@0
|
1785 |
TBool aInvertMask)
|
sl@0
|
1786 |
{
|
sl@0
|
1787 |
if ((aSourceBitmap.ExtendedBitmapType() != KNullUid) || (aMaskBitmap.ExtendedBitmapType() != KNullUid))
|
sl@0
|
1788 |
{
|
sl@0
|
1789 |
iDriver.SetError(KErrNotSupported); // Not supported for extended bitmaps
|
sl@0
|
1790 |
return;
|
sl@0
|
1791 |
}
|
sl@0
|
1792 |
|
sl@0
|
1793 |
DoBitBltMasked(aDestPos, aSourceBitmap, aSourceRect, aMaskBitmap, aInvertMask, TPoint(0, 0));
|
sl@0
|
1794 |
}
|
sl@0
|
1795 |
|
sl@0
|
1796 |
/**
|
sl@0
|
1797 |
Helper method for performing BitBltMasked().
|
sl@0
|
1798 |
Note that aInvertMask is ignored if aMaskPos is not at 0,0.
|
sl@0
|
1799 |
|
sl@0
|
1800 |
@see CDirectGdiContext::BitBlt(const TPoint& aPoint, const CFbsBitmap& aBitmap, const TRect& aSourceRect);
|
sl@0
|
1801 |
@see CDirectGdiContext::BitBltMasked(const TPoint&, const CFbsBitmap&,const TRect&, const CFbsBitmap&, const TPoint&);
|
sl@0
|
1802 |
|
sl@0
|
1803 |
@param aDestPos The destination for the top left corner of the transferred bitmap.
|
sl@0
|
1804 |
It is relative to the top left corner of the destination bitmap, which may be the screen.
|
sl@0
|
1805 |
@param aSourceBitmap A memory-resident source bitmap.
|
sl@0
|
1806 |
@param aSourceRect A rectangle defining the piece of the bitmap to be drawn,
|
sl@0
|
1807 |
with co-ordinates relative to the top left corner of the bitmap.
|
sl@0
|
1808 |
@param aMaskBitmap Mask bitmap.
|
sl@0
|
1809 |
@param aInvertMask If EFalse, a source pixel that is masked by a black pixel is not transferred to
|
sl@0
|
1810 |
the destination rectangle. If ETrue, then a source pixel that is masked by a
|
sl@0
|
1811 |
white pixel is not transferred to the destination rectangle. If alpha blending
|
sl@0
|
1812 |
is used instead of masking, this flag is ignored and no inversion takes place.
|
sl@0
|
1813 |
Note that this parameter is ignored if aMaskPos does not equal TPoint(0,0).
|
sl@0
|
1814 |
@param aMaskPos The point on the mask bitmap to use as the top left corner
|
sl@0
|
1815 |
*/
|
sl@0
|
1816 |
void CVgEngine::DoBitBltMasked (
|
sl@0
|
1817 |
const TPoint& aDestPos,
|
sl@0
|
1818 |
const CFbsBitmap& aSourceBitmap,
|
sl@0
|
1819 |
const TRect& aSourceRect,
|
sl@0
|
1820 |
const CFbsBitmap& aMaskBitmap,
|
sl@0
|
1821 |
TBool aInvertMask,
|
sl@0
|
1822 |
const TPoint& aMaskPos)
|
sl@0
|
1823 |
{
|
sl@0
|
1824 |
MakeEngineCurrent();
|
sl@0
|
1825 |
ResetVgMatrix(VG_MATRIX_IMAGE_USER_TO_SURFACE);
|
sl@0
|
1826 |
if (!IntersectsClippingRegion (TRect (aDestPos+iOrigin, aSourceRect.Size())))
|
sl@0
|
1827 |
return;
|
sl@0
|
1828 |
|
sl@0
|
1829 |
VGImage sourceImage = VG_INVALID_HANDLE;
|
sl@0
|
1830 |
TBool imageCached = ConvertBitmapToVgImage(aSourceBitmap, sourceImage);
|
sl@0
|
1831 |
if (sourceImage == VG_INVALID_HANDLE)
|
sl@0
|
1832 |
{
|
sl@0
|
1833 |
// Error set on creation of VGImage.
|
sl@0
|
1834 |
return;
|
sl@0
|
1835 |
}
|
sl@0
|
1836 |
|
sl@0
|
1837 |
VGImage maskImage = VG_INVALID_HANDLE;
|
sl@0
|
1838 |
TBool maskImageCached = ConvertBitmapToVgImage(aMaskBitmap, maskImage, ETrue, aMaskPos);
|
sl@0
|
1839 |
if (maskImage == VG_INVALID_HANDLE)
|
sl@0
|
1840 |
{
|
sl@0
|
1841 |
// Error set on creation of VGImage.
|
sl@0
|
1842 |
if (!imageCached)
|
sl@0
|
1843 |
{
|
sl@0
|
1844 |
vgDestroyImage(sourceImage);
|
sl@0
|
1845 |
}
|
sl@0
|
1846 |
return;
|
sl@0
|
1847 |
}
|
sl@0
|
1848 |
|
sl@0
|
1849 |
DoVgMaskedImageDraw(
|
sl@0
|
1850 |
aDestPos,
|
sl@0
|
1851 |
sourceImage,
|
sl@0
|
1852 |
aSourceBitmap.SizeInPixels(),
|
sl@0
|
1853 |
aSourceRect,
|
sl@0
|
1854 |
maskImage,
|
sl@0
|
1855 |
aMaskBitmap.SizeInPixels(),
|
sl@0
|
1856 |
aSourceRect.Size(),
|
sl@0
|
1857 |
aInvertMask);
|
sl@0
|
1858 |
|
sl@0
|
1859 |
if (!maskImageCached)
|
sl@0
|
1860 |
{
|
sl@0
|
1861 |
vgDestroyImage(maskImage);
|
sl@0
|
1862 |
}
|
sl@0
|
1863 |
if (!imageCached)
|
sl@0
|
1864 |
{
|
sl@0
|
1865 |
vgDestroyImage(sourceImage);
|
sl@0
|
1866 |
}
|
sl@0
|
1867 |
}
|
sl@0
|
1868 |
|
sl@0
|
1869 |
|
sl@0
|
1870 |
/**
|
sl@0
|
1871 |
This implementation stretches the mask first, and then performs mask tiling. Another approach is to
|
sl@0
|
1872 |
tile first and then perform stretching. The latter method requires more memory and stretches
|
sl@0
|
1873 |
once. Results between these methods are different. When stretching first, all tiles will be completely
|
sl@0
|
1874 |
uniform. When stretching last, different tiles are affected differently, based on the tile's position
|
sl@0
|
1875 |
and stretch factor.
|
sl@0
|
1876 |
|
sl@0
|
1877 |
@see MDirectGdiEngine::DrawBitmapMasked()
|
sl@0
|
1878 |
@see DrawBitmap()
|
sl@0
|
1879 |
*/
|
sl@0
|
1880 |
void CVgEngine::DrawBitmapMasked(
|
sl@0
|
1881 |
const TRect& aDestRect,
|
sl@0
|
1882 |
const CFbsBitmap& aSourceBitmap,
|
sl@0
|
1883 |
const TRect& aSourceRect,
|
sl@0
|
1884 |
const CFbsBitmap& aMaskBitmap,
|
sl@0
|
1885 |
TBool aInvertMask)
|
sl@0
|
1886 |
{
|
sl@0
|
1887 |
if ((aSourceBitmap.ExtendedBitmapType() != KNullUid) || (aMaskBitmap.ExtendedBitmapType() != KNullUid))
|
sl@0
|
1888 |
{
|
sl@0
|
1889 |
iDriver.SetError(KErrNotSupported); // Not supported for extended bitmaps
|
sl@0
|
1890 |
return;
|
sl@0
|
1891 |
}
|
sl@0
|
1892 |
|
sl@0
|
1893 |
MakeEngineCurrent();
|
sl@0
|
1894 |
TRect destRect(aDestRect);
|
sl@0
|
1895 |
if (!IntersectsClippingRegion (TRect(iOrigin, destRect.Size())))
|
sl@0
|
1896 |
{
|
sl@0
|
1897 |
return;
|
sl@0
|
1898 |
}
|
sl@0
|
1899 |
|
sl@0
|
1900 |
// Create source image
|
sl@0
|
1901 |
VGImage sourceImage = VG_INVALID_HANDLE;
|
sl@0
|
1902 |
TBool imageCached = ConvertBitmapToVgImage(aSourceBitmap, sourceImage);
|
sl@0
|
1903 |
// Return if VGImage failed to be created (error set on creation of VGImage).
|
sl@0
|
1904 |
if (sourceImage == VG_INVALID_HANDLE)
|
sl@0
|
1905 |
{
|
sl@0
|
1906 |
return;
|
sl@0
|
1907 |
}
|
sl@0
|
1908 |
|
sl@0
|
1909 |
// Convert aMask to a VGImage.
|
sl@0
|
1910 |
VGImage maskImage = VG_INVALID_HANDLE;
|
sl@0
|
1911 |
TBool maskImageCached = ConvertBitmapToVgImage(aMaskBitmap, maskImage, ETrue);
|
sl@0
|
1912 |
// Error set on creation of VGImage if mask == VG_INVALID_HANDLE
|
sl@0
|
1913 |
|
sl@0
|
1914 |
if (maskImage != VG_INVALID_HANDLE)
|
sl@0
|
1915 |
{
|
sl@0
|
1916 |
TSize destSize = destRect.Size();
|
sl@0
|
1917 |
TSize sourceSize = aSourceRect.Size();
|
sl@0
|
1918 |
if ((destSize.iWidth == sourceSize.iWidth) && (destSize.iHeight == sourceSize.iHeight))
|
sl@0
|
1919 |
{
|
sl@0
|
1920 |
// No scaling of masked bitmap involved
|
sl@0
|
1921 |
DoVgMaskedImageDraw(
|
sl@0
|
1922 |
destRect.iTl,
|
sl@0
|
1923 |
sourceImage,
|
sl@0
|
1924 |
aSourceBitmap.SizeInPixels(),
|
sl@0
|
1925 |
aSourceRect,
|
sl@0
|
1926 |
maskImage,
|
sl@0
|
1927 |
aMaskBitmap.SizeInPixels(),
|
sl@0
|
1928 |
destSize,
|
sl@0
|
1929 |
aInvertMask);
|
sl@0
|
1930 |
}
|
sl@0
|
1931 |
else
|
sl@0
|
1932 |
{
|
sl@0
|
1933 |
// Unfortunately, the current implementation of VG does not support
|
sl@0
|
1934 |
// mask scaling. So, we render the mask into a VGImage pbuffer surface,
|
sl@0
|
1935 |
// and apply user to surface scaling to get a stretch. The stretched
|
sl@0
|
1936 |
// mask is then used for rendering.
|
sl@0
|
1937 |
|
sl@0
|
1938 |
// Generate the VGImage to act as a pbuffer surface and receive the stretched mask.
|
sl@0
|
1939 |
const TSize maskSizeInPixels = aMaskBitmap.SizeInPixels();
|
sl@0
|
1940 |
const VGImageFormat vgFormat = MapToVgDisplayMode(ClosestVgCompatibleDisplayMode(aMaskBitmap.DisplayMode()));
|
sl@0
|
1941 |
TInt scaledMaskWidth = Scale(maskSizeInPixels.iWidth,destSize.iWidth,sourceSize.iWidth);
|
sl@0
|
1942 |
TInt scaledMaskHeight = Scale(maskSizeInPixels.iHeight,destSize.iHeight,sourceSize.iHeight);
|
sl@0
|
1943 |
VGImage stretchedMask = DoVgCreateImage(vgFormat,
|
sl@0
|
1944 |
scaledMaskWidth,
|
sl@0
|
1945 |
scaledMaskHeight,
|
sl@0
|
1946 |
VG_IMAGE_QUALITY_NONANTIALIASED);
|
sl@0
|
1947 |
|
sl@0
|
1948 |
if (stretchedMask != VG_INVALID_HANDLE)
|
sl@0
|
1949 |
{
|
sl@0
|
1950 |
// Get a configuration handle that is compatible with the mask pixel format.
|
sl@0
|
1951 |
EGLConfig utilConfig = 0;
|
sl@0
|
1952 |
TInt err = TConfigHelper::GetConfigForFbsBitmap (aMaskBitmap, utilConfig);
|
sl@0
|
1953 |
if (err == KErrNone)
|
sl@0
|
1954 |
{
|
sl@0
|
1955 |
TBool eglSuccess = EFalse;
|
sl@0
|
1956 |
EGLDisplay eglDisplay = iDriver.EglDisplay();
|
sl@0
|
1957 |
EGLSurface lastSurface = eglGetCurrentSurface(EGL_DRAW);
|
sl@0
|
1958 |
|
sl@0
|
1959 |
// Create a Pbuffer surface from the stretched mask VGImage.
|
sl@0
|
1960 |
EGLSurface utilSurface = eglCreatePbufferFromClientBuffer(
|
sl@0
|
1961 |
eglDisplay,
|
sl@0
|
1962 |
EGL_OPENVG_IMAGE,
|
sl@0
|
1963 |
static_cast<EGLClientBuffer>(stretchedMask),
|
sl@0
|
1964 |
utilConfig,
|
sl@0
|
1965 |
NULL);
|
sl@0
|
1966 |
|
sl@0
|
1967 |
if (utilSurface != EGL_NO_SURFACE)
|
sl@0
|
1968 |
{
|
sl@0
|
1969 |
EGLContext lastContext = eglGetCurrentContext();
|
sl@0
|
1970 |
// Create config. compatible context.
|
sl@0
|
1971 |
EGLContext utilContext = eglCreateContext(eglDisplay, utilConfig, lastContext, NULL);
|
sl@0
|
1972 |
|
sl@0
|
1973 |
if (utilContext != EGL_NO_CONTEXT)
|
sl@0
|
1974 |
{
|
sl@0
|
1975 |
// Make the utility surface and context current, and stretch the mask.
|
sl@0
|
1976 |
if (eglMakeCurrent(eglDisplay, utilSurface, utilSurface, utilContext) == EGL_TRUE)
|
sl@0
|
1977 |
{
|
sl@0
|
1978 |
// Set up the scaling transform for the current surface.
|
sl@0
|
1979 |
vgSeti(VG_MATRIX_MODE, VG_MATRIX_IMAGE_USER_TO_SURFACE);
|
sl@0
|
1980 |
// Scaling factors for x and y.
|
sl@0
|
1981 |
VGfloat xScale = ((VGfloat)destSize.iWidth/sourceSize.iWidth);
|
sl@0
|
1982 |
VGfloat yScale = ((VGfloat)destSize.iHeight/sourceSize.iHeight);
|
sl@0
|
1983 |
vgScale(xScale, yScale);
|
sl@0
|
1984 |
|
sl@0
|
1985 |
// Render the stretched mask.
|
sl@0
|
1986 |
vgDrawImage(maskImage);
|
sl@0
|
1987 |
ResetVgMatrix(VG_MATRIX_IMAGE_USER_TO_SURFACE);
|
sl@0
|
1988 |
|
sl@0
|
1989 |
// All done, make current the pre-existing rendering state.
|
sl@0
|
1990 |
eglMakeCurrent(eglDisplay, lastSurface, lastSurface, lastContext);
|
sl@0
|
1991 |
|
sl@0
|
1992 |
eglSuccess = ETrue;
|
sl@0
|
1993 |
}
|
sl@0
|
1994 |
eglDestroyContext(eglDisplay, utilContext);
|
sl@0
|
1995 |
}
|
sl@0
|
1996 |
eglDestroySurface(eglDisplay, utilSurface);
|
sl@0
|
1997 |
}
|
sl@0
|
1998 |
|
sl@0
|
1999 |
if (eglSuccess)
|
sl@0
|
2000 |
{
|
sl@0
|
2001 |
DoVgMaskedImageDraw(destRect.iTl, sourceImage, aSourceBitmap.SizeInPixels(),
|
sl@0
|
2002 |
aSourceRect, stretchedMask, maskSizeInPixels, destSize, aInvertMask);
|
sl@0
|
2003 |
}
|
sl@0
|
2004 |
else
|
sl@0
|
2005 |
{
|
sl@0
|
2006 |
// coverity[check_return]
|
sl@0
|
2007 |
// coverity[unchecked_value]
|
sl@0
|
2008 |
LogEglError();
|
sl@0
|
2009 |
}
|
sl@0
|
2010 |
}
|
sl@0
|
2011 |
else
|
sl@0
|
2012 |
{
|
sl@0
|
2013 |
iDriver.SetError(err);
|
sl@0
|
2014 |
}
|
sl@0
|
2015 |
vgDestroyImage (stretchedMask);
|
sl@0
|
2016 |
}
|
sl@0
|
2017 |
if (!maskImageCached) vgDestroyImage (maskImage);
|
sl@0
|
2018 |
}
|
sl@0
|
2019 |
}
|
sl@0
|
2020 |
if (!imageCached) vgDestroyImage(sourceImage);
|
sl@0
|
2021 |
}
|
sl@0
|
2022 |
|
sl@0
|
2023 |
/**
|
sl@0
|
2024 |
Helper method that implements the core blitting functionality.
|
sl@0
|
2025 |
|
sl@0
|
2026 |
@param aDestPos The destination for the top left corner of the transferred bitmap.
|
sl@0
|
2027 |
It is relative to the top left corner of the destination bitmap, which may be the screen.
|
sl@0
|
2028 |
@param aSourceImage A valid VGImage to draw.
|
sl@0
|
2029 |
@param aSourceImageSize Extents of source bitmap.
|
sl@0
|
2030 |
@param aSourceRect A rectangle defining the piece of the bitmap to be drawn,
|
sl@0
|
2031 |
with co-ordinates relative to the top left corner of the bitmap.
|
sl@0
|
2032 |
@param aScaledMaskImage A valid mask VGImage - pre-scaled, ready for rendering.
|
sl@0
|
2033 |
@param aSrcMaskSize The size of the (unscaled) mask image.
|
sl@0
|
2034 |
@param aXscale Scaling factor to apply to x axis (already applied to mask).
|
sl@0
|
2035 |
@param aYscale Scaling factor to apply to y axis (already applied to mask).
|
sl@0
|
2036 |
@param aDestSize The size of the destination (used for calculating any scaling)
|
sl@0
|
2037 |
@param aInvertMask If EFalse, a source pixel that is masked by a black pixel
|
sl@0
|
2038 |
is not transferred to the destination rectangle. If ETrue, then a source
|
sl@0
|
2039 |
pixel that is masked by a white pixel is not transferred to the destination
|
sl@0
|
2040 |
rectangle.
|
sl@0
|
2041 |
|
sl@0
|
2042 |
@pre The rendering target has been activated. aBitmap and aMaskBitmap are not NULL and hold Handles.
|
sl@0
|
2043 |
Destination rectangle extents must intersect clipping region.
|
sl@0
|
2044 |
aSourceImage is a valid VGImage handle.
|
sl@0
|
2045 |
@post Request to draw the masked bitmap content has been accepted.
|
sl@0
|
2046 |
There is no guarantee that the request has been processed when the method returns.
|
sl@0
|
2047 |
*/
|
sl@0
|
2048 |
void CVgEngine::DoVgMaskedImageDraw(
|
sl@0
|
2049 |
const TPoint& aDestPos,
|
sl@0
|
2050 |
VGImage aSourceImage,
|
sl@0
|
2051 |
const TRect& aSourceImageSize,
|
sl@0
|
2052 |
const TRect& aSourceRect,
|
sl@0
|
2053 |
const VGImage aScaledMaskImage,
|
sl@0
|
2054 |
const TSize& aSrcMaskSize,
|
sl@0
|
2055 |
const TSize& aDestSize,
|
sl@0
|
2056 |
TBool aInvertMask)
|
sl@0
|
2057 |
{
|
sl@0
|
2058 |
TBool destroySourceImageAtEnd = EFalse;
|
sl@0
|
2059 |
|
sl@0
|
2060 |
if(aSourceImageSize != aSourceRect)
|
sl@0
|
2061 |
{
|
sl@0
|
2062 |
aSourceImage =
|
sl@0
|
2063 |
vgChildImage(
|
sl@0
|
2064 |
aSourceImage,
|
sl@0
|
2065 |
aSourceRect.iTl.iX,
|
sl@0
|
2066 |
aSourceRect.iTl.iY,
|
sl@0
|
2067 |
aSourceRect.Width(),
|
sl@0
|
2068 |
aSourceRect.Height());
|
sl@0
|
2069 |
|
sl@0
|
2070 |
if (aSourceImage == VG_INVALID_HANDLE) return;
|
sl@0
|
2071 |
destroySourceImageAtEnd = ETrue;
|
sl@0
|
2072 |
}
|
sl@0
|
2073 |
|
sl@0
|
2074 |
TBool maskOK = EFalse;
|
sl@0
|
2075 |
TSize sourceSize = aSourceRect.Size();
|
sl@0
|
2076 |
TRect destRect(aDestPos, TSize(Scale(aSourceRect.Width(),aDestSize.iWidth,sourceSize.iWidth),
|
sl@0
|
2077 |
Scale(aSourceRect.Height(),aDestSize.iHeight,sourceSize.iHeight)));
|
sl@0
|
2078 |
// VG does not provide mask tiling...we currently perform multiple
|
sl@0
|
2079 |
// vgMask operations to implement tiling. It should be possible to use
|
sl@0
|
2080 |
// pattern tiling to render the mask to a surface, convert surface region
|
sl@0
|
2081 |
// to VGImage and apply that as a mask (to take advantage of native VG
|
sl@0
|
2082 |
// tiling), though cost/benefit is has not yet been determined.
|
sl@0
|
2083 |
// NOTE: It may be worth optimising for cases where xScale or yScale equal one.
|
sl@0
|
2084 |
|
sl@0
|
2085 |
TRect destVgRect = SgMetricsToVgTRect(aDestPos, destRect.Width(), destRect.Height());
|
sl@0
|
2086 |
|
sl@0
|
2087 |
if (aScaledMaskImage != VG_INVALID_HANDLE)
|
sl@0
|
2088 |
{
|
sl@0
|
2089 |
const TSize scaledMaskSize(Scale(aSrcMaskSize.iWidth,aDestSize.iWidth,sourceSize.iWidth),
|
sl@0
|
2090 |
Scale(aSrcMaskSize.iHeight,aDestSize.iHeight,sourceSize.iHeight));
|
sl@0
|
2091 |
if (scaledMaskSize.iHeight > 0 && scaledMaskSize.iWidth > 0)
|
sl@0
|
2092 |
{
|
sl@0
|
2093 |
maskOK = ETrue;
|
sl@0
|
2094 |
// Determine mask image offset for rendering.
|
sl@0
|
2095 |
TInt scaledMaskXOffset = Scale(aSourceRect.iTl.iX%aSrcMaskSize.iWidth,aDestSize.iWidth,sourceSize.iWidth);
|
sl@0
|
2096 |
|
sl@0
|
2097 |
// Sg coordinates are relative to top left, Vg are reletive to bottom left. As we
|
sl@0
|
2098 |
// tile from the bottom up we subtract from maskSize.iHeight to get the bottom edge
|
sl@0
|
2099 |
// offset.
|
sl@0
|
2100 |
TInt scaledMaskYOffset = (aSourceRect.iTl.iY + aSourceRect.Height()) % aSrcMaskSize.iHeight;
|
sl@0
|
2101 |
if (scaledMaskYOffset != 0)
|
sl@0
|
2102 |
{
|
sl@0
|
2103 |
scaledMaskYOffset = Scale(aSrcMaskSize.iHeight-scaledMaskYOffset,aDestSize.iHeight,sourceSize.iHeight);
|
sl@0
|
2104 |
}
|
sl@0
|
2105 |
|
sl@0
|
2106 |
// If inverting the mask, we use a difference operation against the existing mask, so
|
sl@0
|
2107 |
// we need to ensure the existing mask is set to the correct state.
|
sl@0
|
2108 |
// Fill the existing mask so that it is completly transparent (set to all ones).
|
sl@0
|
2109 |
if(aInvertMask)
|
sl@0
|
2110 |
{
|
sl@0
|
2111 |
vgMask(
|
sl@0
|
2112 |
VG_INVALID_HANDLE,
|
sl@0
|
2113 |
VG_FILL_MASK,
|
sl@0
|
2114 |
destVgRect.iTl.iX,
|
sl@0
|
2115 |
destVgRect.iTl.iY,
|
sl@0
|
2116 |
destVgRect.Width(),
|
sl@0
|
2117 |
destVgRect.Height());
|
sl@0
|
2118 |
}
|
sl@0
|
2119 |
|
sl@0
|
2120 |
VGMaskOperation vgMaskOp = aInvertMask ? VG_SUBTRACT_MASK : VG_SET_MASK;
|
sl@0
|
2121 |
// NOTE: in VG destVgRect.iTl is physically at the bottom and destVgRect.iBr at the top
|
sl@0
|
2122 |
for (
|
sl@0
|
2123 |
TInt maskY = destVgRect.iTl.iY - scaledMaskYOffset;
|
sl@0
|
2124 |
maskY < destVgRect.iBr.iY;
|
sl@0
|
2125 |
maskY += scaledMaskSize.iHeight)
|
sl@0
|
2126 |
{
|
sl@0
|
2127 |
for (
|
sl@0
|
2128 |
TInt maskX = destVgRect.iTl.iX - scaledMaskXOffset;
|
sl@0
|
2129 |
maskX < destVgRect.iBr.iX;
|
sl@0
|
2130 |
maskX += scaledMaskSize.iWidth)
|
sl@0
|
2131 |
{
|
sl@0
|
2132 |
vgMask(
|
sl@0
|
2133 |
aScaledMaskImage,
|
sl@0
|
2134 |
vgMaskOp,
|
sl@0
|
2135 |
maskX,
|
sl@0
|
2136 |
maskY,
|
sl@0
|
2137 |
scaledMaskSize.iWidth,
|
sl@0
|
2138 |
scaledMaskSize.iHeight);
|
sl@0
|
2139 |
}
|
sl@0
|
2140 |
}
|
sl@0
|
2141 |
}
|
sl@0
|
2142 |
}
|
sl@0
|
2143 |
|
sl@0
|
2144 |
// Set up translation and scale for the current surface - note that translation must
|
sl@0
|
2145 |
// occur first, as is unscaled.
|
sl@0
|
2146 |
vgSeti(VG_MATRIX_MODE, VG_MATRIX_IMAGE_USER_TO_SURFACE);
|
sl@0
|
2147 |
vgTranslate(aDestPos.iX, aDestPos.iY);
|
sl@0
|
2148 |
VGfloat xScale = ((VGfloat)aDestSize.iWidth/sourceSize.iWidth);
|
sl@0
|
2149 |
VGfloat yScale = ((VGfloat)aDestSize.iHeight/sourceSize.iHeight);
|
sl@0
|
2150 |
vgScale(xScale, yScale);
|
sl@0
|
2151 |
|
sl@0
|
2152 |
// Rather than bracketing vgDrawImage with VG_MASKING on/off we may want to always enable masking,
|
sl@0
|
2153 |
// and remove the mask when finished:
|
sl@0
|
2154 |
// vgMask(VG_INVALID_HANDLE, VG_CLEAR_MASK, 0, 0, iRenderingTarget->Size().iWidth, iRenderingTarget->Size().iHeight);
|
sl@0
|
2155 |
// If the mask is not removed in some way, then subsequent rendering operations which intersect with the
|
sl@0
|
2156 |
// masking region will be affected.
|
sl@0
|
2157 |
if (maskOK)
|
sl@0
|
2158 |
{
|
sl@0
|
2159 |
vgSeti (VG_MASKING, VG_TRUE);
|
sl@0
|
2160 |
for (iRegionManager.Begin(); iRegionManager.ApplyClipRegion(); iRegionManager.Next())
|
sl@0
|
2161 |
vgDrawImage(aSourceImage);
|
sl@0
|
2162 |
vgSeti (VG_MASKING, VG_FALSE);
|
sl@0
|
2163 |
}
|
sl@0
|
2164 |
else
|
sl@0
|
2165 |
{
|
sl@0
|
2166 |
for (iRegionManager.Begin(); iRegionManager.ApplyClipRegion(); iRegionManager.Next())
|
sl@0
|
2167 |
vgDrawImage(aSourceImage);
|
sl@0
|
2168 |
}
|
sl@0
|
2169 |
// Reset the transform matrix.
|
sl@0
|
2170 |
ResetVgMatrix(VG_MATRIX_IMAGE_USER_TO_SURFACE);
|
sl@0
|
2171 |
|
sl@0
|
2172 |
if (destroySourceImageAtEnd)
|
sl@0
|
2173 |
{
|
sl@0
|
2174 |
vgDestroyImage (aSourceImage);
|
sl@0
|
2175 |
}
|
sl@0
|
2176 |
}
|
sl@0
|
2177 |
|
sl@0
|
2178 |
/**
|
sl@0
|
2179 |
@see MDirectGdiEngine::DrawResource(const TPoint&, const RDirectGdiDrawableSource&, DirectGdi::TGraphicsRotation)
|
sl@0
|
2180 |
@see DrawResource(const TRect&, const RDirectGdiDrawableSource&, const TRect&, DirectGdi::TGraphicsRotation)
|
sl@0
|
2181 |
@see DrawResource(const TRect&, const RDirectGdiDrawableSource&, const TDesC8&)
|
sl@0
|
2182 |
*/
|
sl@0
|
2183 |
void CVgEngine::DrawResource(const TPoint& aPos, const RDirectGdiDrawableSource& aSource, DirectGdi::TGraphicsRotation aRotation)
|
sl@0
|
2184 |
{
|
sl@0
|
2185 |
MakeEngineCurrent();
|
sl@0
|
2186 |
|
sl@0
|
2187 |
CDirectGdiImageSourceImpl* source = iDriver.GetImageSourceFromHandle(aSource.Handle());
|
sl@0
|
2188 |
if (source)
|
sl@0
|
2189 |
{
|
sl@0
|
2190 |
const TSize sourceSize = source->Size();
|
sl@0
|
2191 |
|
sl@0
|
2192 |
if ((sourceSize.iWidth > 0) && (sourceSize.iHeight > 0))
|
sl@0
|
2193 |
{
|
sl@0
|
2194 |
VGImage vgImage = source->VgImage();
|
sl@0
|
2195 |
if (vgImage != VG_INVALID_HANDLE)
|
sl@0
|
2196 |
{
|
sl@0
|
2197 |
vgSeti(VG_MATRIX_MODE, VG_MATRIX_IMAGE_USER_TO_SURFACE);
|
sl@0
|
2198 |
|
sl@0
|
2199 |
TPoint pos(aPos);
|
sl@0
|
2200 |
|
sl@0
|
2201 |
|
sl@0
|
2202 |
if (aRotation == DirectGdi::EGraphicsRotationNone ||
|
sl@0
|
2203 |
aRotation == DirectGdi::EGraphicsRotation180)
|
sl@0
|
2204 |
{
|
sl@0
|
2205 |
// Pixel-data in EGLImages appears to be upside down due to the Y-inversion
|
sl@0
|
2206 |
// effect of the Identity matrix. Therefore must undo the Y-inversion here
|
sl@0
|
2207 |
// and adjust destination rect accordingly.
|
sl@0
|
2208 |
pos.iY = iSize.iHeight - aPos.iY - sourceSize.iHeight - iOrigin.iY;
|
sl@0
|
2209 |
pos.iX += iOrigin.iX;
|
sl@0
|
2210 |
vgLoadIdentity();
|
sl@0
|
2211 |
}
|
sl@0
|
2212 |
else
|
sl@0
|
2213 |
{
|
sl@0
|
2214 |
// But if rotation is 90 or 270 degrees we need to mirror in the X-axis
|
sl@0
|
2215 |
// and adjust destination translation accordingly.
|
sl@0
|
2216 |
vgScale(-1, 1);
|
sl@0
|
2217 |
}
|
sl@0
|
2218 |
|
sl@0
|
2219 |
switch (aRotation)
|
sl@0
|
2220 |
{
|
sl@0
|
2221 |
case DirectGdi::EGraphicsRotation90:
|
sl@0
|
2222 |
vgTranslate(-pos.iX, pos.iY);
|
sl@0
|
2223 |
vgRotate(90.0f);
|
sl@0
|
2224 |
break;
|
sl@0
|
2225 |
case DirectGdi::EGraphicsRotation180:
|
sl@0
|
2226 |
vgTranslate(pos.iX+sourceSize.iWidth, pos.iY+sourceSize.iHeight);
|
sl@0
|
2227 |
vgRotate(180.0f);
|
sl@0
|
2228 |
break;
|
sl@0
|
2229 |
case DirectGdi::EGraphicsRotation270:
|
sl@0
|
2230 |
vgTranslate(-pos.iX-sourceSize.iHeight, pos.iY+sourceSize.iWidth);
|
sl@0
|
2231 |
vgRotate(270.0f);
|
sl@0
|
2232 |
break;
|
sl@0
|
2233 |
default:
|
sl@0
|
2234 |
// No rotation
|
sl@0
|
2235 |
vgTranslate(pos.iX, pos.iY);
|
sl@0
|
2236 |
break;
|
sl@0
|
2237 |
}
|
sl@0
|
2238 |
|
sl@0
|
2239 |
for (iRegionManager.Begin(); iRegionManager.ApplyClipRegion(); iRegionManager.Next())
|
sl@0
|
2240 |
vgDrawImage(vgImage);
|
sl@0
|
2241 |
|
sl@0
|
2242 |
ResetVgMatrix(VG_MATRIX_IMAGE_USER_TO_SURFACE);
|
sl@0
|
2243 |
}
|
sl@0
|
2244 |
}
|
sl@0
|
2245 |
}
|
sl@0
|
2246 |
}
|
sl@0
|
2247 |
|
sl@0
|
2248 |
/**
|
sl@0
|
2249 |
@see MDirectGdiEngine::DrawResource(const TRect&, const RDirectGdiDrawableSource&, DirectGdi::TGraphicsRotation)
|
sl@0
|
2250 |
*/
|
sl@0
|
2251 |
void CVgEngine::DrawResource(const TRect& aDestRect,
|
sl@0
|
2252 |
const RDirectGdiDrawableSource& aSource,
|
sl@0
|
2253 |
DirectGdi::TGraphicsRotation aRotation)
|
sl@0
|
2254 |
{
|
sl@0
|
2255 |
CDirectGdiImageSourceImpl* source = iDriver.GetImageSourceFromHandle(aSource.Handle());
|
sl@0
|
2256 |
if (source)
|
sl@0
|
2257 |
{
|
sl@0
|
2258 |
TRect srcRect(TPoint(0, 0), source->Size());
|
sl@0
|
2259 |
DoDrawResource(aDestRect, source, srcRect, aRotation);
|
sl@0
|
2260 |
}
|
sl@0
|
2261 |
}
|
sl@0
|
2262 |
|
sl@0
|
2263 |
/**
|
sl@0
|
2264 |
@see MDirectGdiEngine::DrawResource(const TRect&, const RDirectGdiDrawableSource&, const TRect&, DirectGdi::TGraphicsRotation)
|
sl@0
|
2265 |
*/
|
sl@0
|
2266 |
void CVgEngine::DrawResource(const TRect& aDestRect,
|
sl@0
|
2267 |
const RDirectGdiDrawableSource& aSource,
|
sl@0
|
2268 |
const TRect& aSourceRect,
|
sl@0
|
2269 |
DirectGdi::TGraphicsRotation aRotation)
|
sl@0
|
2270 |
{
|
sl@0
|
2271 |
CDirectGdiImageSourceImpl* source = iDriver.GetImageSourceFromHandle(aSource.Handle());
|
sl@0
|
2272 |
if (source)
|
sl@0
|
2273 |
{
|
sl@0
|
2274 |
// check source rectangle is fully contained within the image resource extent before drawing
|
sl@0
|
2275 |
TSize size = source->Size();
|
sl@0
|
2276 |
if ((aSourceRect.iTl.iX < 0)
|
sl@0
|
2277 |
|| (aSourceRect.iTl.iY < 0)
|
sl@0
|
2278 |
|| (aSourceRect.iBr.iX > size.iWidth)
|
sl@0
|
2279 |
|| (aSourceRect.iBr.iY > size.iHeight)
|
sl@0
|
2280 |
|| (aSourceRect.Width() <= 0)
|
sl@0
|
2281 |
|| (aSourceRect.Height() <= 0))
|
sl@0
|
2282 |
{
|
sl@0
|
2283 |
iDriver.SetError(KErrArgument);
|
sl@0
|
2284 |
return;
|
sl@0
|
2285 |
}
|
sl@0
|
2286 |
|
sl@0
|
2287 |
if (((aSourceRect.Width() == aDestRect.Width())
|
sl@0
|
2288 |
&& (aSourceRect.Height() == aDestRect.Height())
|
sl@0
|
2289 |
&& (aRotation == DirectGdi::EGraphicsRotationNone || aRotation == DirectGdi::EGraphicsRotation180))
|
sl@0
|
2290 |
||
|
sl@0
|
2291 |
((aSourceRect.Width() == aDestRect.Height())
|
sl@0
|
2292 |
&& (aSourceRect.Height() == aDestRect.Width())
|
sl@0
|
2293 |
&& (aRotation == DirectGdi::EGraphicsRotation90 || aRotation == DirectGdi::EGraphicsRotation270)))
|
sl@0
|
2294 |
{
|
sl@0
|
2295 |
// No scaling
|
sl@0
|
2296 |
DrawResource(TPoint(aDestRect.iTl.iX, aDestRect.iTl.iY), aSource, aRotation);
|
sl@0
|
2297 |
}
|
sl@0
|
2298 |
else
|
sl@0
|
2299 |
{
|
sl@0
|
2300 |
MakeEngineCurrent();
|
sl@0
|
2301 |
DoDrawResource(aDestRect, source, aSourceRect, aRotation);
|
sl@0
|
2302 |
}
|
sl@0
|
2303 |
}
|
sl@0
|
2304 |
}
|
sl@0
|
2305 |
|
sl@0
|
2306 |
/**
|
sl@0
|
2307 |
This method only supports drawing of image sources as Drawables. An attempt to draw
|
sl@0
|
2308 |
a Drawable that is not an image will result in a panic.
|
sl@0
|
2309 |
|
sl@0
|
2310 |
@see MDirectGdiEngine::DrawResource(const TRect&, const RDirectGdiDrawableSource&, const TDesC8&)
|
sl@0
|
2311 |
|
sl@0
|
2312 |
@panic DGDIAdapter 1, if an attempt is made to draw a drawable that is not an image source.
|
sl@0
|
2313 |
*/
|
sl@0
|
2314 |
void CVgEngine::DrawResource(
|
sl@0
|
2315 |
const TRect& aDestRect,
|
sl@0
|
2316 |
const RDirectGdiDrawableSource& aSource,
|
sl@0
|
2317 |
const TDesC8& /*aParam*/)
|
sl@0
|
2318 |
{
|
sl@0
|
2319 |
MakeEngineCurrent();
|
sl@0
|
2320 |
|
sl@0
|
2321 |
// Check to see if the passed drawable is actually an image as we only support drawing of images at present
|
sl@0
|
2322 |
if (iDriver.IsImageSource(aSource.Handle()))
|
sl@0
|
2323 |
{
|
sl@0
|
2324 |
CDirectGdiImageSourceImpl* source = iDriver.GetImageSourceFromHandle(aSource.Handle());
|
sl@0
|
2325 |
if (source)
|
sl@0
|
2326 |
{
|
sl@0
|
2327 |
DoDrawResource(aDestRect, source, DirectGdi::EGraphicsRotationNone);
|
sl@0
|
2328 |
}
|
sl@0
|
2329 |
}
|
sl@0
|
2330 |
else
|
sl@0
|
2331 |
{
|
sl@0
|
2332 |
// This method only supports drawing image sources at present
|
sl@0
|
2333 |
GRAPHICS_ASSERT_ALWAYS(0, EDirectGdiPanicNotImplemented);
|
sl@0
|
2334 |
}
|
sl@0
|
2335 |
}
|
sl@0
|
2336 |
|
sl@0
|
2337 |
/**
|
sl@0
|
2338 |
@see MDirectGdiEngine::BeginDrawGlyph()
|
sl@0
|
2339 |
|
sl@0
|
2340 |
Sets the necessary OpenVG and engine state ready for receiving DrawGlyph() commands.
|
sl@0
|
2341 |
Any OpenVG state that is common for all DrawGlyph() operations are set.
|
sl@0
|
2342 |
*/
|
sl@0
|
2343 |
void CVgEngine::BeginDrawGlyph()
|
sl@0
|
2344 |
{
|
sl@0
|
2345 |
MakeEngineCurrent();
|
sl@0
|
2346 |
vgSetPaint(iTextBrush, VG_FILL_PATH);
|
sl@0
|
2347 |
vgSeti(VG_MATRIX_MODE, VG_MATRIX_IMAGE_USER_TO_SURFACE);
|
sl@0
|
2348 |
#ifdef DRAWGLYPH_MULTIPLY_MODE
|
sl@0
|
2349 |
vgSeti(VG_IMAGE_MODE, VG_DRAW_IMAGE_MULTIPLY);
|
sl@0
|
2350 |
#else
|
sl@0
|
2351 |
vgSeti(VG_IMAGE_MODE, VG_DRAW_IMAGE_STENCIL);
|
sl@0
|
2352 |
#endif
|
sl@0
|
2353 |
|
sl@0
|
2354 |
#ifdef DRAWGLYPH_BUFFERED
|
sl@0
|
2355 |
iDrawGlyphCount = 0;
|
sl@0
|
2356 |
#endif
|
sl@0
|
2357 |
}
|
sl@0
|
2358 |
|
sl@0
|
2359 |
/**
|
sl@0
|
2360 |
Draws Glyph image to the given position and orientation.
|
sl@0
|
2361 |
The function crops the output image to the clipping rectangle specified as a parameter.
|
sl@0
|
2362 |
If the clipping region is defined on the current context, it will also be taken into consideration
|
sl@0
|
2363 |
|
sl@0
|
2364 |
@param aScrPos Position to start drawing glyph after rotation has been applied (if necessary).
|
sl@0
|
2365 |
@param aChar Character being drawn. Signifies general Unicode character value.
|
sl@0
|
2366 |
@param aGlyphImage Pointer to the glyph image data.
|
sl@0
|
2367 |
@param aGlyphBitmapType Type of bitmap format.
|
sl@0
|
2368 |
@param aGlyphImageSize Glyph image size.
|
sl@0
|
2369 |
@param aScrClipRect Clipping rect.
|
sl@0
|
2370 |
@param aRotation Rotation specifying how the glyph will be drawn. The number can only be divisible by 90 degrees,
|
sl@0
|
2371 |
i.e. horizontal and vertical rotation.
|
sl@0
|
2372 |
|
sl@0
|
2373 |
@see CFont::TTextDirection
|
sl@0
|
2374 |
@see MDirectGdiEngine::DrawGlyph()
|
sl@0
|
2375 |
|
sl@0
|
2376 |
@pre The rendering target has been activated.
|
sl@0
|
2377 |
@post Request to draw the Glyph has been accepted.
|
sl@0
|
2378 |
@panic DGDIAdapter 8, if aClipRect is empty (debug-only).
|
sl@0
|
2379 |
@panic DGDIAdapter 61, if font glyph image storage does not exist (debug-only).
|
sl@0
|
2380 |
*/
|
sl@0
|
2381 |
void CVgEngine::DrawGlyph(
|
sl@0
|
2382 |
const TPoint& aScrPos,
|
sl@0
|
2383 |
const TChar aChar,
|
sl@0
|
2384 |
const TUint8* aGlyphImage,
|
sl@0
|
2385 |
const TGlyphBitmapType aGlyphBitmapType,
|
sl@0
|
2386 |
const TSize& aGlyphImageSize,
|
sl@0
|
2387 |
const TRect& aScrClipRect,
|
sl@0
|
2388 |
const DirectGdi::TGraphicsRotation aRotation)
|
sl@0
|
2389 |
{
|
sl@0
|
2390 |
GRAPHICS_ASSERT_DEBUG(!aScrClipRect.IsEmpty(), EDirectGdiPanicInvalidRegion);
|
sl@0
|
2391 |
GRAPHICS_ASSERT_DEBUG(iFontGlyphImageStorage, EDirectGdiPanicGlyphImageStorageNotCreated);
|
sl@0
|
2392 |
|
sl@0
|
2393 |
TPoint pos = aScrPos;
|
sl@0
|
2394 |
pos += iDrawOrigin;
|
sl@0
|
2395 |
TRect clipRect = aScrClipRect;
|
sl@0
|
2396 |
clipRect.iTl += iDrawOrigin;
|
sl@0
|
2397 |
clipRect.iBr += iDrawOrigin;
|
sl@0
|
2398 |
|
sl@0
|
2399 |
if( aGlyphImageSize.iHeight <= 0 || aGlyphImageSize.iWidth <= 0 ||
|
sl@0
|
2400 |
!clipRect.Intersects(iTargetRegion.BoundingRect()) || !iRegionManager.Intersects(clipRect))
|
sl@0
|
2401 |
{
|
sl@0
|
2402 |
// Just leave silently, as spaces could be passed with empty size.
|
sl@0
|
2403 |
return;
|
sl@0
|
2404 |
}
|
sl@0
|
2405 |
|
sl@0
|
2406 |
// Clip the glyph against the target and the clipping rects.
|
sl@0
|
2407 |
// Calculate the axis-aligned bounding box of the glyph.
|
sl@0
|
2408 |
TRect glyphBoundingBox;
|
sl@0
|
2409 |
switch(aRotation)
|
sl@0
|
2410 |
{
|
sl@0
|
2411 |
case DirectGdi::EGraphicsRotation90:
|
sl@0
|
2412 |
glyphBoundingBox = TRect(TPoint(1+pos.iX-aGlyphImageSize.iHeight, pos.iY), TSize(aGlyphImageSize.iHeight, aGlyphImageSize.iWidth));
|
sl@0
|
2413 |
break;
|
sl@0
|
2414 |
case DirectGdi::EGraphicsRotation180:
|
sl@0
|
2415 |
glyphBoundingBox = TRect(TPoint(pos.iX-aGlyphImageSize.iHeight, pos.iY-aGlyphImageSize.iWidth), aGlyphImageSize);
|
sl@0
|
2416 |
break;
|
sl@0
|
2417 |
case DirectGdi::EGraphicsRotation270:
|
sl@0
|
2418 |
glyphBoundingBox = TRect(TPoint(pos.iX, 1+pos.iY-aGlyphImageSize.iWidth), TSize(aGlyphImageSize.iHeight, aGlyphImageSize.iWidth));
|
sl@0
|
2419 |
break;
|
sl@0
|
2420 |
default:
|
sl@0
|
2421 |
glyphBoundingBox = TRect(pos, aGlyphImageSize);
|
sl@0
|
2422 |
break;
|
sl@0
|
2423 |
}
|
sl@0
|
2424 |
if (!glyphBoundingBox.Intersects(iTargetRegion.BoundingRect()) || !iRegionManager.Intersects(glyphBoundingBox))
|
sl@0
|
2425 |
{
|
sl@0
|
2426 |
return;
|
sl@0
|
2427 |
}
|
sl@0
|
2428 |
#ifdef DRAWGLYPH_BUFFERED
|
sl@0
|
2429 |
iDrawGlyphCommand[iDrawGlyphCount].pos = pos;
|
sl@0
|
2430 |
iDrawGlyphCommand[iDrawGlyphCount].aChar = aChar;
|
sl@0
|
2431 |
iDrawGlyphCommand[iDrawGlyphCount].aGlyphBitmapType = aGlyphBitmapType;
|
sl@0
|
2432 |
iDrawGlyphCommand[iDrawGlyphCount].aGlyphImageSize = aGlyphImageSize;
|
sl@0
|
2433 |
iDrawGlyphCommand[iDrawGlyphCount].aClipRect = clipRect;
|
sl@0
|
2434 |
iDrawGlyphCommand[iDrawGlyphCount].aRotation = aRotation;
|
sl@0
|
2435 |
iDrawGlyphCommand[iDrawGlyphCount].aGlyphImage = const_cast<TUint8*>(aGlyphImage);
|
sl@0
|
2436 |
++iDrawGlyphCount;
|
sl@0
|
2437 |
if (iDrawGlyphCount == KMaxGlyphs)
|
sl@0
|
2438 |
{
|
sl@0
|
2439 |
FlushDrawGlyphs();
|
sl@0
|
2440 |
iDrawGlyphCount = 0;
|
sl@0
|
2441 |
}
|
sl@0
|
2442 |
#else
|
sl@0
|
2443 |
VGImage foreground = VG_INVALID_HANDLE;
|
sl@0
|
2444 |
VGImage outline = VG_INVALID_HANDLE;
|
sl@0
|
2445 |
VGImage shadow = VG_INVALID_HANDLE;
|
sl@0
|
2446 |
|
sl@0
|
2447 |
TInt err = iFontGlyphImageStorage -> GlyphImage(iFontId, aChar, aGlyphBitmapType, aGlyphImage, aGlyphImageSize, &foreground, &shadow, &outline);
|
sl@0
|
2448 |
if(err != KErrNone)
|
sl@0
|
2449 |
{
|
sl@0
|
2450 |
iDriver.SetError(err);
|
sl@0
|
2451 |
if(err == KErrNoMemory)
|
sl@0
|
2452 |
{
|
sl@0
|
2453 |
if((foreground == VG_INVALID_HANDLE) ||
|
sl@0
|
2454 |
((aGlyphBitmapType == EFourColourBlendGlyphBitmap) && ((shadow == VG_INVALID_HANDLE) || (outline == VG_INVALID_HANDLE))))
|
sl@0
|
2455 |
{
|
sl@0
|
2456 |
return;
|
sl@0
|
2457 |
}
|
sl@0
|
2458 |
}
|
sl@0
|
2459 |
else
|
sl@0
|
2460 |
{
|
sl@0
|
2461 |
return;
|
sl@0
|
2462 |
}
|
sl@0
|
2463 |
}
|
sl@0
|
2464 |
|
sl@0
|
2465 |
RRegion oldClippingRegion;
|
sl@0
|
2466 |
oldClippingRegion.Copy(iRegionManager.ClippingRegion());
|
sl@0
|
2467 |
iRegionManager.ClipTo(clipRect);
|
sl@0
|
2468 |
|
sl@0
|
2469 |
// Load the matrix which converts Symbian coordinate system to OpenVG coordinate system
|
sl@0
|
2470 |
vgLoadMatrix(Identity());
|
sl@0
|
2471 |
if(aRotation == DirectGdi::EGraphicsRotation90)
|
sl@0
|
2472 |
{
|
sl@0
|
2473 |
vgTranslate(pos.iX+1, pos.iY);
|
sl@0
|
2474 |
vgRotate(90.0f);
|
sl@0
|
2475 |
}
|
sl@0
|
2476 |
else if(aRotation == DirectGdi::EGraphicsRotation270)
|
sl@0
|
2477 |
{
|
sl@0
|
2478 |
vgTranslate(pos.iX, pos.iY+1);
|
sl@0
|
2479 |
vgRotate(270.0f);
|
sl@0
|
2480 |
}
|
sl@0
|
2481 |
else
|
sl@0
|
2482 |
{
|
sl@0
|
2483 |
vgTranslate(pos.iX, pos.iY);
|
sl@0
|
2484 |
}
|
sl@0
|
2485 |
|
sl@0
|
2486 |
switch(aGlyphBitmapType)
|
sl@0
|
2487 |
{
|
sl@0
|
2488 |
case EMonochromeGlyphBitmap:
|
sl@0
|
2489 |
case EAntiAliasedGlyphBitmap:
|
sl@0
|
2490 |
for (iRegionManager.Begin(); iRegionManager.ApplyClipRegion(); iRegionManager.Next())
|
sl@0
|
2491 |
vgDrawImage(foreground);
|
sl@0
|
2492 |
break;
|
sl@0
|
2493 |
case EFourColourBlendGlyphBitmap:
|
sl@0
|
2494 |
{
|
sl@0
|
2495 |
SetVgPaintColor(iTextBrush, iBrushColor);
|
sl@0
|
2496 |
for (iRegionManager.Begin(); iRegionManager.ApplyClipRegion(); iRegionManager.Next())
|
sl@0
|
2497 |
vgDrawImage(foreground);
|
sl@0
|
2498 |
|
sl@0
|
2499 |
SetVgPaintColor(iTextBrush, iTextShadowColor);
|
sl@0
|
2500 |
for (iRegionManager.Begin(); iRegionManager.ApplyClipRegion(); iRegionManager.Next())
|
sl@0
|
2501 |
vgDrawImage(shadow);
|
sl@0
|
2502 |
|
sl@0
|
2503 |
SetVgPaintColor(iTextBrush, iPenColor);
|
sl@0
|
2504 |
for (iRegionManager.Begin(); iRegionManager.ApplyClipRegion(); iRegionManager.Next())
|
sl@0
|
2505 |
vgDrawImage(outline);
|
sl@0
|
2506 |
break;
|
sl@0
|
2507 |
}
|
sl@0
|
2508 |
}
|
sl@0
|
2509 |
|
sl@0
|
2510 |
// Restore the clipping manager to its previous state.
|
sl@0
|
2511 |
iRegionManager.SetClippingRegion(oldClippingRegion);
|
sl@0
|
2512 |
oldClippingRegion.Close();
|
sl@0
|
2513 |
#endif
|
sl@0
|
2514 |
}
|
sl@0
|
2515 |
|
sl@0
|
2516 |
/**
|
sl@0
|
2517 |
@see MDirectGdiEngine::EndDrawGlyph()
|
sl@0
|
2518 |
|
sl@0
|
2519 |
Undoes any OpenVG or engine state changes made in BeginDrawGlyph().
|
sl@0
|
2520 |
*/
|
sl@0
|
2521 |
void CVgEngine::EndDrawGlyph()
|
sl@0
|
2522 |
{
|
sl@0
|
2523 |
#ifdef DRAWGLYPH_BUFFERED
|
sl@0
|
2524 |
FlushDrawGlyphs();
|
sl@0
|
2525 |
iDrawGlyphCount = 0;
|
sl@0
|
2526 |
#endif
|
sl@0
|
2527 |
vgLoadMatrix(Identity());
|
sl@0
|
2528 |
if (iOrigin != TPoint(0,0))
|
sl@0
|
2529 |
{
|
sl@0
|
2530 |
vgTranslate(iOrigin.iX, iOrigin.iY);
|
sl@0
|
2531 |
}
|
sl@0
|
2532 |
|
sl@0
|
2533 |
vgSetPaint(iBrush, VG_FILL_PATH);
|
sl@0
|
2534 |
vgSeti(VG_IMAGE_MODE, VG_DRAW_IMAGE_NORMAL);
|
sl@0
|
2535 |
}
|
sl@0
|
2536 |
|
sl@0
|
2537 |
#ifdef DRAWGLYPH_BUFFERED
|
sl@0
|
2538 |
void CVgEngine::FlushDrawGlyphs()
|
sl@0
|
2539 |
{
|
sl@0
|
2540 |
VGImage foreground[KMaxGlyphs];
|
sl@0
|
2541 |
Mem::FillZ(foreground, iDrawGlyphCount*sizeof(VGImage));
|
sl@0
|
2542 |
VGImage outline[KMaxGlyphs];
|
sl@0
|
2543 |
VGImage shadow[KMaxGlyphs];
|
sl@0
|
2544 |
|
sl@0
|
2545 |
for (TInt glyph = 0; glyph < iDrawGlyphCount; ++glyph)
|
sl@0
|
2546 |
{
|
sl@0
|
2547 |
if (foreground[glyph] == 0)
|
sl@0
|
2548 |
{
|
sl@0
|
2549 |
TSize aGlyphImageSize = iDrawGlyphCommand[glyph].aGlyphImageSize;
|
sl@0
|
2550 |
TChar aChar = iDrawGlyphCommand[glyph].aChar;
|
sl@0
|
2551 |
TGlyphBitmapType aGlyphBitmapType = iDrawGlyphCommand[glyph].aGlyphBitmapType;
|
sl@0
|
2552 |
TUint8* aGlyphImage = iDrawGlyphCommand[glyph].aGlyphImage;
|
sl@0
|
2553 |
|
sl@0
|
2554 |
VGImage foreground1 = VG_INVALID_HANDLE;
|
sl@0
|
2555 |
VGImage outline1 = VG_INVALID_HANDLE;
|
sl@0
|
2556 |
VGImage shadow1 = VG_INVALID_HANDLE;
|
sl@0
|
2557 |
|
sl@0
|
2558 |
TInt err = iFontGlyphImageStorage -> GlyphImage(iFontId, aChar, aGlyphBitmapType, aGlyphImage, aGlyphImageSize, &foreground1, &shadow1, &outline1);
|
sl@0
|
2559 |
if(err != KErrNone)
|
sl@0
|
2560 |
{
|
sl@0
|
2561 |
iDriver.SetError(err);
|
sl@0
|
2562 |
if(err == KErrNoMemory)
|
sl@0
|
2563 |
{
|
sl@0
|
2564 |
if((foreground1 == VG_INVALID_HANDLE) ||
|
sl@0
|
2565 |
((aGlyphBitmapType == EFourColourBlendGlyphBitmap) && ((shadow1 == VG_INVALID_HANDLE) || (outline1 == VG_INVALID_HANDLE))))
|
sl@0
|
2566 |
{
|
sl@0
|
2567 |
return;
|
sl@0
|
2568 |
}
|
sl@0
|
2569 |
}
|
sl@0
|
2570 |
else
|
sl@0
|
2571 |
{
|
sl@0
|
2572 |
return;
|
sl@0
|
2573 |
}
|
sl@0
|
2574 |
}
|
sl@0
|
2575 |
|
sl@0
|
2576 |
foreground[glyph] = foreground1;
|
sl@0
|
2577 |
outline[glyph] = outline1;
|
sl@0
|
2578 |
shadow[glyph] = shadow1;
|
sl@0
|
2579 |
|
sl@0
|
2580 |
for (TInt nextGlyph = glyph+1; nextGlyph < iDrawGlyphCount; nextGlyph++)
|
sl@0
|
2581 |
{
|
sl@0
|
2582 |
if (foreground[nextGlyph] == 0)
|
sl@0
|
2583 |
{
|
sl@0
|
2584 |
if (iDrawGlyphCommand[glyph].SameGlyph(iDrawGlyphCommand[nextGlyph]))
|
sl@0
|
2585 |
{
|
sl@0
|
2586 |
foreground[nextGlyph] = foreground[glyph];
|
sl@0
|
2587 |
outline[nextGlyph] = outline[glyph];
|
sl@0
|
2588 |
shadow[nextGlyph] = shadow[glyph];
|
sl@0
|
2589 |
}
|
sl@0
|
2590 |
}
|
sl@0
|
2591 |
}
|
sl@0
|
2592 |
}
|
sl@0
|
2593 |
}
|
sl@0
|
2594 |
|
sl@0
|
2595 |
RRegion oldClippingRegion;
|
sl@0
|
2596 |
oldClippingRegion.Copy(iRegionManager.ClippingRegion());
|
sl@0
|
2597 |
vgLoadMatrix(Identity());
|
sl@0
|
2598 |
TPoint lastPos;
|
sl@0
|
2599 |
for (TInt glyph = 0; glyph < iDrawGlyphCount; ++glyph)
|
sl@0
|
2600 |
{
|
sl@0
|
2601 |
TGlyphBitmapType aGlyphBitmapType = iDrawGlyphCommand[glyph].aGlyphBitmapType;
|
sl@0
|
2602 |
TRect aClipRect = iDrawGlyphCommand[glyph].aClipRect;
|
sl@0
|
2603 |
DirectGdi::TGraphicsRotation aRotation = iDrawGlyphCommand[glyph].aRotation;
|
sl@0
|
2604 |
TPoint aPos = iDrawGlyphCommand[glyph].pos;
|
sl@0
|
2605 |
|
sl@0
|
2606 |
iRegionManager.ClipTo(aClipRect);
|
sl@0
|
2607 |
|
sl@0
|
2608 |
// Load the matrix which converts Symbian coordinate system to OpenVG coordinate system
|
sl@0
|
2609 |
|
sl@0
|
2610 |
if(aRotation == DirectGdi::EGraphicsRotation90)
|
sl@0
|
2611 |
{
|
sl@0
|
2612 |
vgTranslate(aPos.iX+1, aPos.iY);
|
sl@0
|
2613 |
vgRotate(90.0f);
|
sl@0
|
2614 |
}
|
sl@0
|
2615 |
else if(aRotation == DirectGdi::EGraphicsRotation270)
|
sl@0
|
2616 |
{
|
sl@0
|
2617 |
vgTranslate(aPos.iX, aPos.iY+1);
|
sl@0
|
2618 |
vgRotate(270.0f);
|
sl@0
|
2619 |
}
|
sl@0
|
2620 |
else
|
sl@0
|
2621 |
{
|
sl@0
|
2622 |
//vgTranslate(aPos.iX, aPos.iY);
|
sl@0
|
2623 |
vgTranslate(aPos.iX-lastPos.iX, aPos.iY - lastPos.iY);
|
sl@0
|
2624 |
lastPos = aPos;
|
sl@0
|
2625 |
}
|
sl@0
|
2626 |
|
sl@0
|
2627 |
switch(aGlyphBitmapType)
|
sl@0
|
2628 |
{
|
sl@0
|
2629 |
case EMonochromeGlyphBitmap:
|
sl@0
|
2630 |
case EAntiAliasedGlyphBitmap:
|
sl@0
|
2631 |
for (iRegionManager.Begin(); iRegionManager.ApplyClipRegion(); iRegionManager.Next())
|
sl@0
|
2632 |
vgDrawImage(foreground[glyph]);
|
sl@0
|
2633 |
break;
|
sl@0
|
2634 |
case EFourColourBlendGlyphBitmap:
|
sl@0
|
2635 |
{
|
sl@0
|
2636 |
SetVgPaintColor(iTextBrush, iBrushColor);
|
sl@0
|
2637 |
for (iRegionManager.Begin(); iRegionManager.ApplyClipRegion(); iRegionManager.Next())
|
sl@0
|
2638 |
vgDrawImage(foreground[glyph]);
|
sl@0
|
2639 |
|
sl@0
|
2640 |
SetVgPaintColor(iTextBrush, iTextShadowColor);
|
sl@0
|
2641 |
for (iRegionManager.Begin(); iRegionManager.ApplyClipRegion(); iRegionManager.Next())
|
sl@0
|
2642 |
vgDrawImage(shadow[glyph]);
|
sl@0
|
2643 |
|
sl@0
|
2644 |
SetVgPaintColor(iTextBrush, iPenColor);
|
sl@0
|
2645 |
for (iRegionManager.Begin(); iRegionManager.ApplyClipRegion(); iRegionManager.Next())
|
sl@0
|
2646 |
vgDrawImage(outline[glyph]);
|
sl@0
|
2647 |
break;
|
sl@0
|
2648 |
}
|
sl@0
|
2649 |
}
|
sl@0
|
2650 |
|
sl@0
|
2651 |
// Restore the clipping manager to its previous state.
|
sl@0
|
2652 |
iRegionManager.SetClippingRegion(oldClippingRegion);
|
sl@0
|
2653 |
}
|
sl@0
|
2654 |
oldClippingRegion.Close();
|
sl@0
|
2655 |
}
|
sl@0
|
2656 |
#endif
|
sl@0
|
2657 |
|
sl@0
|
2658 |
/**
|
sl@0
|
2659 |
@see MDirectGdiEngine::CopyRect()
|
sl@0
|
2660 |
*/
|
sl@0
|
2661 |
void CVgEngine::CopyRect(const TPoint& aOffset, const TRect& aRect)
|
sl@0
|
2662 |
{
|
sl@0
|
2663 |
MakeEngineCurrent();
|
sl@0
|
2664 |
|
sl@0
|
2665 |
// Transformations, masking and blending are not applied.
|
sl@0
|
2666 |
// So need to convert to VG coordinate system.
|
sl@0
|
2667 |
// i.e. Need Bottom-Left coord of aRect in VG's coordinates.
|
sl@0
|
2668 |
// Also need to allow for drawing engine coordinate system (iOrigin)
|
sl@0
|
2669 |
const TPoint sourcePoint = ConvertToVgCoords(TPoint(aRect.iTl.iX, aRect.iBr.iY) + iOrigin);
|
sl@0
|
2670 |
// Scissoring is applied to destination, but does not affect reading of pixels.
|
sl@0
|
2671 |
for (iRegionManager.Begin(); iRegionManager.ApplyClipRegion(); iRegionManager.Next())
|
sl@0
|
2672 |
vgCopyPixels(sourcePoint.iX + aOffset.iX, sourcePoint.iY - aOffset.iY, // destination point
|
sl@0
|
2673 |
sourcePoint.iX, sourcePoint.iY, // source point
|
sl@0
|
2674 |
aRect.Width(), aRect.Height()); // size of rect to copy
|
sl@0
|
2675 |
}
|
sl@0
|
2676 |
|
sl@0
|
2677 |
/**
|
sl@0
|
2678 |
@see MDirectGdiEngine::ExternalizeL()
|
sl@0
|
2679 |
@see InternalizeL()
|
sl@0
|
2680 |
*/
|
sl@0
|
2681 |
void CVgEngine::ExternalizeL(RWriteStream& aWriteStream)
|
sl@0
|
2682 |
{
|
sl@0
|
2683 |
aWriteStream.WriteUint32L(iPaintMode);
|
sl@0
|
2684 |
aWriteStream << iLinePos;
|
sl@0
|
2685 |
}
|
sl@0
|
2686 |
|
sl@0
|
2687 |
/**
|
sl@0
|
2688 |
@see MDirectGdiEngine::InternalizeL()
|
sl@0
|
2689 |
@see ExternalizeL()
|
sl@0
|
2690 |
*/
|
sl@0
|
2691 |
void CVgEngine::InternalizeL(RReadStream& aReadStream)
|
sl@0
|
2692 |
{
|
sl@0
|
2693 |
iPaintMode = aReadStream.ReadUint32L();
|
sl@0
|
2694 |
aReadStream >> iLinePos;
|
sl@0
|
2695 |
}
|
sl@0
|
2696 |
|
sl@0
|
2697 |
/**
|
sl@0
|
2698 |
@see MDirectGdiEngine::GetInterface()
|
sl@0
|
2699 |
*/
|
sl@0
|
2700 |
TInt CVgEngine::GetInterface(TUid aInterfaceId, TAny*& aInterface)
|
sl@0
|
2701 |
{
|
sl@0
|
2702 |
aInterface = NULL;
|
sl@0
|
2703 |
TInt err = KErrNone;
|
sl@0
|
2704 |
switch (aInterfaceId.iUid)
|
sl@0
|
2705 |
{
|
sl@0
|
2706 |
case KDirectGdiGetGlyphStorageUid:
|
sl@0
|
2707 |
{
|
sl@0
|
2708 |
aInterface = static_cast<MFontGlyphImageStorage*> (iDriver.FontGlyphImageStorage());
|
sl@0
|
2709 |
break;
|
sl@0
|
2710 |
}
|
sl@0
|
2711 |
case KDirectGdiVgImageCacheUid:
|
sl@0
|
2712 |
{
|
sl@0
|
2713 |
aInterface = static_cast<MVgImageCache*> (iDriver.VgImageCache());
|
sl@0
|
2714 |
break;
|
sl@0
|
2715 |
}
|
sl@0
|
2716 |
case KDrawDeviceOriginInterfaceID:
|
sl@0
|
2717 |
{
|
sl@0
|
2718 |
aInterface = static_cast<MDrawDeviceOrigin*>(this);
|
sl@0
|
2719 |
break;
|
sl@0
|
2720 |
}
|
sl@0
|
2721 |
default:
|
sl@0
|
2722 |
err = KErrNotSupported;
|
sl@0
|
2723 |
break;
|
sl@0
|
2724 |
}
|
sl@0
|
2725 |
return err;
|
sl@0
|
2726 |
}
|
sl@0
|
2727 |
|
sl@0
|
2728 |
/**
|
sl@0
|
2729 |
Converts a point from the Symbian OS graphics coordinate system to the OpenVG coordinate system.
|
sl@0
|
2730 |
|
sl@0
|
2731 |
The Symbian OS coordinate system's x-axis increases positively from the origin rightwards.
|
sl@0
|
2732 |
The y-axis increases positively from the origin downwards.
|
sl@0
|
2733 |
|
sl@0
|
2734 |
The OpenVG coordinate system's x-axis increases positively from the origin rightwards.
|
sl@0
|
2735 |
The y-axis increases positively from the origin upwards.
|
sl@0
|
2736 |
|
sl@0
|
2737 |
Therefore a point (X,Y) in the Symbian OS coordinate system would be equivalent to a point
|
sl@0
|
2738 |
(X',Y') in the OpenVG coordinate system by the following transformations:
|
sl@0
|
2739 |
X' = X
|
sl@0
|
2740 |
Y' = (Height of rendering target) - Y
|
sl@0
|
2741 |
|
sl@0
|
2742 |
@param aPoint A point specified in the Symbian OS graphics coordinate system.
|
sl@0
|
2743 |
|
sl@0
|
2744 |
@return The point specified in the OpenVG-specific coordinate system.
|
sl@0
|
2745 |
*/
|
sl@0
|
2746 |
const TPoint CVgEngine::ConvertToVgCoords(const TPoint& aPoint)
|
sl@0
|
2747 |
{
|
sl@0
|
2748 |
MakeEngineCurrent();
|
sl@0
|
2749 |
TInt targetHeight = iSize.iHeight;
|
sl@0
|
2750 |
return TPoint(aPoint.iX, targetHeight - aPoint.iY);
|
sl@0
|
2751 |
}
|
sl@0
|
2752 |
|
sl@0
|
2753 |
/**
|
sl@0
|
2754 |
Converts the position of a rectangle from the Symbian OS graphics coordinate system to the
|
sl@0
|
2755 |
OpenVG coordinate system.
|
sl@0
|
2756 |
|
sl@0
|
2757 |
The Symbian OS coordinate system's x-axis increases positively from the origin rightwards.
|
sl@0
|
2758 |
The y-axis increases positively from the origin downwards.
|
sl@0
|
2759 |
A rectangle's position is specified by the top-left coordinate.
|
sl@0
|
2760 |
|
sl@0
|
2761 |
The OpenVG coordinate system's x-axis increases positively from the origin rightwards.
|
sl@0
|
2762 |
The y-axis increases positively from the origin upwards.
|
sl@0
|
2763 |
A rectangle's position is specified by the bottom-left coordinate.
|
sl@0
|
2764 |
|
sl@0
|
2765 |
A point (X,Y) in the Symbian OS coordinate system would be equivalent to point
|
sl@0
|
2766 |
(X',Y') in the OpenVG coordinate system by the following transformations:
|
sl@0
|
2767 |
X' = X
|
sl@0
|
2768 |
Y' = (Height of rendering target) - Y
|
sl@0
|
2769 |
|
sl@0
|
2770 |
@param aRect A rectangle whose position is to be converted for use in OpenVG.
|
sl@0
|
2771 |
|
sl@0
|
2772 |
@return The bottom-left point of the rectangle, specified in the OpenVG specific coordinate system.
|
sl@0
|
2773 |
*/
|
sl@0
|
2774 |
const TPoint CVgEngine::ConvertToVgCoords(const TRect& aRect)
|
sl@0
|
2775 |
{
|
sl@0
|
2776 |
MakeEngineCurrent();
|
sl@0
|
2777 |
TInt targetHeight = iSize.iHeight;
|
sl@0
|
2778 |
return TPoint(aRect.iTl.iX, targetHeight - aRect.iBr.iY);
|
sl@0
|
2779 |
}
|
sl@0
|
2780 |
|
sl@0
|
2781 |
/**
|
sl@0
|
2782 |
Resets the user-to-surface OpenVG matrices to the default system matrix.
|
sl@0
|
2783 |
*/
|
sl@0
|
2784 |
void CVgEngine::ResetVgMatrix()
|
sl@0
|
2785 |
{
|
sl@0
|
2786 |
ResetVgMatrix(VG_MATRIX_PATH_USER_TO_SURFACE);
|
sl@0
|
2787 |
ResetVgMatrix(VG_MATRIX_IMAGE_USER_TO_SURFACE);
|
sl@0
|
2788 |
}
|
sl@0
|
2789 |
|
sl@0
|
2790 |
/**
|
sl@0
|
2791 |
Resets an OpenVG matrix to the default system matrix. Current origin offset applies.
|
sl@0
|
2792 |
@param aMatrixMode The OpenVG matrix being reset.
|
sl@0
|
2793 |
*/
|
sl@0
|
2794 |
void CVgEngine::ResetVgMatrix(const VGMatrixMode aMatrixMode)
|
sl@0
|
2795 |
{
|
sl@0
|
2796 |
vgSeti(VG_MATRIX_MODE, aMatrixMode);
|
sl@0
|
2797 |
// Load matrix which converts Symbian coordinate system to VG coordinate system
|
sl@0
|
2798 |
vgLoadMatrix(Identity());
|
sl@0
|
2799 |
|
sl@0
|
2800 |
// Add in translation for drawing engine coordinate system
|
sl@0
|
2801 |
vgTranslate(iOrigin.iX, iOrigin.iY);
|
sl@0
|
2802 |
}
|
sl@0
|
2803 |
|
sl@0
|
2804 |
/**
|
sl@0
|
2805 |
If aPath is a null handle, a VGPath is created with enough space to hold aExpectedCommandCount commands.
|
sl@0
|
2806 |
If the path is already a handle to a valid path, the path is simply cleared instead of recreated.
|
sl@0
|
2807 |
Also allocates memory for two arrays; one to hold all commands we will add to the newly
|
sl@0
|
2808 |
created path, and one to hold all coordinates we will add to the newly created path.
|
sl@0
|
2809 |
Commands and coordinates are not added to the path until FinishPath() is called for this path.
|
sl@0
|
2810 |
Commands and coordinates are saved for adding to the path when FinishPath() is
|
sl@0
|
2811 |
called by calling AppendPathCommand(). Any failures are reported to the driver before returning.
|
sl@0
|
2812 |
|
sl@0
|
2813 |
@param aPath A handle to the path being cleared/created.
|
sl@0
|
2814 |
@param aExpectedCommandCount The number of commands the path is expected to hold. If this size
|
sl@0
|
2815 |
is underestimated, the arrays that hold the current commands and coordinates will grow
|
sl@0
|
2816 |
as additional items are added beyond the original estimated size. Once a path is finished, the current
|
sl@0
|
2817 |
command and coordinate counters are reset, but the memory remains to cut down on memory allocations.
|
sl@0
|
2818 |
|
sl@0
|
2819 |
@return EFalse if memory allocation or path creation fails, ETrue otherwise.
|
sl@0
|
2820 |
|
sl@0
|
2821 |
@see CVgEngine::AppendPathCommand(VGubyte)
|
sl@0
|
2822 |
@see CVgEngine::AppendPathCommand(VGubyte, VGfloat)
|
sl@0
|
2823 |
@see CVgEngine::AppendPathCommand(VGubyte, VGfloat, VGfloat)
|
sl@0
|
2824 |
@see CVgEngine::PrepareForPathCommand()
|
sl@0
|
2825 |
@see CVgEngine::FinishPath()
|
sl@0
|
2826 |
@see CVgEngine::AllocPathCommands()
|
sl@0
|
2827 |
@see CVgEngine::AllocPathCoords()
|
sl@0
|
2828 |
*/
|
sl@0
|
2829 |
TBool CVgEngine::PreparePath(VGPath& aPath, TInt aExpectedCommandCount)
|
sl@0
|
2830 |
{
|
sl@0
|
2831 |
TInt err = KErrNone;
|
sl@0
|
2832 |
err = AllocPathCommands(aExpectedCommandCount);
|
sl@0
|
2833 |
if(KErrNone == err)
|
sl@0
|
2834 |
{
|
sl@0
|
2835 |
err = AllocPathCoords(aExpectedCommandCount*2); // guess at the number of coords needed, this will be reallocated if it is not big enough
|
sl@0
|
2836 |
}
|
sl@0
|
2837 |
if(KErrNone == err)
|
sl@0
|
2838 |
{
|
sl@0
|
2839 |
if (aPath != VG_INVALID_HANDLE)
|
sl@0
|
2840 |
vgClearPath(aPath, VG_PATH_CAPABILITY_APPEND_TO);
|
sl@0
|
2841 |
else
|
sl@0
|
2842 |
{
|
sl@0
|
2843 |
aPath = vgCreatePath(VG_PATH_FORMAT_STANDARD,
|
sl@0
|
2844 |
VG_PATH_DATATYPE_F,
|
sl@0
|
2845 |
1.0f, //scale
|
sl@0
|
2846 |
0.0f, //bias
|
sl@0
|
2847 |
aExpectedCommandCount,
|
sl@0
|
2848 |
aExpectedCommandCount*2, //expected coord count
|
sl@0
|
2849 |
VG_PATH_CAPABILITY_APPEND_TO);
|
sl@0
|
2850 |
|
sl@0
|
2851 |
if (aPath == VG_INVALID_HANDLE)
|
sl@0
|
2852 |
err = KErrNoMemory;
|
sl@0
|
2853 |
}
|
sl@0
|
2854 |
}
|
sl@0
|
2855 |
if (KErrNone != err)
|
sl@0
|
2856 |
{
|
sl@0
|
2857 |
iDriver.SetError(err);
|
sl@0
|
2858 |
return EFalse;
|
sl@0
|
2859 |
}
|
sl@0
|
2860 |
return ETrue;
|
sl@0
|
2861 |
}
|
sl@0
|
2862 |
|
sl@0
|
2863 |
/**
|
sl@0
|
2864 |
Adds a path command to the currently saved array of path commands. Any error that occurs is stored
|
sl@0
|
2865 |
with the driver.
|
sl@0
|
2866 |
|
sl@0
|
2867 |
@param aCommand The VGPathCommand to add to the current path, e.g VG_CLOSE_PATH.
|
sl@0
|
2868 |
|
sl@0
|
2869 |
@see CVgEngine::CreatePath()
|
sl@0
|
2870 |
@see CVgEngine::AppendPathCommand(VGubyte, VGfloat)
|
sl@0
|
2871 |
@see CVgEngine::AppendPathCommand(VGubyte, VGfloat, VGfloat)
|
sl@0
|
2872 |
@see CVgEngine::PrepareForPathCommand()
|
sl@0
|
2873 |
@see CVgEngine::FinishPath()
|
sl@0
|
2874 |
@see CVgEngine::AllocPathCommands()
|
sl@0
|
2875 |
@see CVgEngine::AllocPathCoords()
|
sl@0
|
2876 |
*/
|
sl@0
|
2877 |
void CVgEngine::AppendPathCommand(VGubyte aCommand)
|
sl@0
|
2878 |
{
|
sl@0
|
2879 |
TInt err = PrepareForPathCommand(1, 0);
|
sl@0
|
2880 |
if (KErrNone == err)
|
sl@0
|
2881 |
{
|
sl@0
|
2882 |
iPathCommands[iPathCommandCount++] = aCommand;
|
sl@0
|
2883 |
}
|
sl@0
|
2884 |
else
|
sl@0
|
2885 |
{
|
sl@0
|
2886 |
iDriver.SetError(err);
|
sl@0
|
2887 |
}
|
sl@0
|
2888 |
}
|
sl@0
|
2889 |
|
sl@0
|
2890 |
/**
|
sl@0
|
2891 |
Adds a path command and a single coordinate to the currently saved array of path commands.
|
sl@0
|
2892 |
Any error that occurs is stored with the driver.
|
sl@0
|
2893 |
|
sl@0
|
2894 |
@param aCommand The VGPathCommand to add to the current path, e.g VG_HLINE_TO_ABS.
|
sl@0
|
2895 |
@param aCoord The coordinate to add to the current path, e.g. 10.f.
|
sl@0
|
2896 |
|
sl@0
|
2897 |
@see CVgEngine::CreatePath()
|
sl@0
|
2898 |
@see CVgEngine::AppendPathCommand(VGubyte)
|
sl@0
|
2899 |
@see CVgEngine::AppendPathCommand(VGubyte, VGfloat, VGfloat)
|
sl@0
|
2900 |
@see CVgEngine::PrepareForPathCommand()
|
sl@0
|
2901 |
@see CVgEngine::FinishPath()
|
sl@0
|
2902 |
@see CVgEngine::AllocPathCommands()
|
sl@0
|
2903 |
@see CVgEngine::AllocPathCoords()
|
sl@0
|
2904 |
*/
|
sl@0
|
2905 |
void CVgEngine::AppendPathCommand(VGubyte aCommand, VGfloat aCoord)
|
sl@0
|
2906 |
{
|
sl@0
|
2907 |
TInt err = PrepareForPathCommand(1, 1);
|
sl@0
|
2908 |
if (KErrNone == err)
|
sl@0
|
2909 |
{
|
sl@0
|
2910 |
iPathCommands[iPathCommandCount++] = aCommand;
|
sl@0
|
2911 |
iPathCoords[iPathCoordCount++] = aCoord;
|
sl@0
|
2912 |
}
|
sl@0
|
2913 |
else
|
sl@0
|
2914 |
{
|
sl@0
|
2915 |
iDriver.SetError(err);
|
sl@0
|
2916 |
}
|
sl@0
|
2917 |
}
|
sl@0
|
2918 |
|
sl@0
|
2919 |
/**
|
sl@0
|
2920 |
Adds a path command and two coordinates to the currently saved array of path commands.
|
sl@0
|
2921 |
Any error that occurs is stored with the driver.
|
sl@0
|
2922 |
|
sl@0
|
2923 |
@param aCommand The VGPathCommand to add to the current path, e.g VG_MOVE_TO_ABS.
|
sl@0
|
2924 |
@param aCoord1 The coordinate to add to the current path, e.g. 10.f.
|
sl@0
|
2925 |
@param aCoord2 The coordinate to add to the current path, e.g. 10.f.
|
sl@0
|
2926 |
|
sl@0
|
2927 |
@see CVgEngine::CreatePath()
|
sl@0
|
2928 |
@see CVgEngine::AppendPathCommand(VGubyte)
|
sl@0
|
2929 |
@see CVgEngine::AppendPathCommand(VGubyte, VGfloat)
|
sl@0
|
2930 |
@see CVgEngine::PrepareForPathCommand()
|
sl@0
|
2931 |
@see CVgEngine::FinishPath()
|
sl@0
|
2932 |
@see CVgEngine::AllocPathCommands()
|
sl@0
|
2933 |
@see CVgEngine::AllocPathCoords()
|
sl@0
|
2934 |
*/
|
sl@0
|
2935 |
void CVgEngine::AppendPathCommand(VGubyte aCommand, VGfloat aCoord1, VGfloat aCoord2)
|
sl@0
|
2936 |
{
|
sl@0
|
2937 |
TInt err = PrepareForPathCommand(1, 2);
|
sl@0
|
2938 |
if (KErrNone == err)
|
sl@0
|
2939 |
{
|
sl@0
|
2940 |
iPathCommands[iPathCommandCount++] = aCommand;
|
sl@0
|
2941 |
iPathCoords[iPathCoordCount++] = aCoord1;
|
sl@0
|
2942 |
iPathCoords[iPathCoordCount++] = aCoord2;
|
sl@0
|
2943 |
}
|
sl@0
|
2944 |
else
|
sl@0
|
2945 |
{
|
sl@0
|
2946 |
iDriver.SetError(err);
|
sl@0
|
2947 |
}
|
sl@0
|
2948 |
}
|
sl@0
|
2949 |
|
sl@0
|
2950 |
/**
|
sl@0
|
2951 |
Allocates memory to store the passed number of commands and coordinates in the saved command and
|
sl@0
|
2952 |
coordinate arrays. Any error that occurs is stored with the driver.
|
sl@0
|
2953 |
|
sl@0
|
2954 |
@param aCommandCount The number of new commands expected to be added to the current command array.
|
sl@0
|
2955 |
@param aCoordCount The number of new commands expected to be added to the current coordinate array.
|
sl@0
|
2956 |
|
sl@0
|
2957 |
@return KErrNoMemory if memory allocation fails, KErrNone otherwise.
|
sl@0
|
2958 |
|
sl@0
|
2959 |
@see CVgEngine::CreatePath()
|
sl@0
|
2960 |
@see CVgEngine::AppendPathCommand(VGubyte)
|
sl@0
|
2961 |
@see CVgEngine::AppendPathCommand(VGubyte, VGfloat)
|
sl@0
|
2962 |
@see CVgEngine::AppendPathCommand(VGubyte, VGfloat, VGfloat)
|
sl@0
|
2963 |
@see CVgEngine::FinishPath()
|
sl@0
|
2964 |
@see CVgEngine::AllocPathCommands()
|
sl@0
|
2965 |
@see CVgEngine::AllocPathCoords()
|
sl@0
|
2966 |
*/
|
sl@0
|
2967 |
TInt CVgEngine::PrepareForPathCommand(TInt aCommandCount, TInt aCoordCount)
|
sl@0
|
2968 |
{
|
sl@0
|
2969 |
// Do we need to add space for the new commands and coords?
|
sl@0
|
2970 |
TInt err = AllocPathCommands(iPathCommandCount+aCommandCount);
|
sl@0
|
2971 |
if (err == KErrNone)
|
sl@0
|
2972 |
{
|
sl@0
|
2973 |
err = AllocPathCoords(iPathCoordCount+aCoordCount);
|
sl@0
|
2974 |
}
|
sl@0
|
2975 |
if (err != KErrNone)
|
sl@0
|
2976 |
{
|
sl@0
|
2977 |
iDriver.SetError(err);
|
sl@0
|
2978 |
}
|
sl@0
|
2979 |
return err;
|
sl@0
|
2980 |
}
|
sl@0
|
2981 |
|
sl@0
|
2982 |
/**
|
sl@0
|
2983 |
Adds the contents of the saved command and coordinate arrays to the passed VGPath ready for drawing.
|
sl@0
|
2984 |
Clears the counts of saved commands and coordinates.
|
sl@0
|
2985 |
|
sl@0
|
2986 |
@param aPath The path that the current commands and coordinates are to be added to.
|
sl@0
|
2987 |
|
sl@0
|
2988 |
@see CVgEngine::CreatePath()
|
sl@0
|
2989 |
@see CVgEngine::AppendPathCommand(VGubyte)
|
sl@0
|
2990 |
@see CVgEngine::AppendPathCommand(VGubyte, VGfloat)
|
sl@0
|
2991 |
@see CVgEngine::AppendPathCommand(VGubyte, VGfloat, VGfloat)
|
sl@0
|
2992 |
@see CVgEngine::PrepareForPathCommand()
|
sl@0
|
2993 |
@see CVgEngine::AllocPathCommands()
|
sl@0
|
2994 |
@see CVgEngine::AllocPathCoords()
|
sl@0
|
2995 |
*/
|
sl@0
|
2996 |
void CVgEngine::FinishPath(VGPath aPath)
|
sl@0
|
2997 |
{
|
sl@0
|
2998 |
vgAppendPathData(aPath, iPathCommandCount, iPathCommands, iPathCoords);
|
sl@0
|
2999 |
iPathCommandCount = 0;
|
sl@0
|
3000 |
iPathCoordCount = 0;
|
sl@0
|
3001 |
}
|
sl@0
|
3002 |
|
sl@0
|
3003 |
/**
|
sl@0
|
3004 |
Allocates enough memory to hold aCommandCount path commands, unless the command array already holds
|
sl@0
|
3005 |
enough memory.
|
sl@0
|
3006 |
|
sl@0
|
3007 |
@param aCommandCount The number of commands to allocate space for in the command array.
|
sl@0
|
3008 |
|
sl@0
|
3009 |
@return KErrNoMemory if memory allocation fails, KErrNone otherwise.
|
sl@0
|
3010 |
|
sl@0
|
3011 |
@see CVgEngine::CreatePath(TInt)
|
sl@0
|
3012 |
@see CVgEngine::AppendPathCommand(VGubyte)
|
sl@0
|
3013 |
@see CVgEngine::AppendPathCommand(VGubyte, VGfloat)
|
sl@0
|
3014 |
@see CVgEngine::AppendPathCommand(VGubyte, VGfloat, VGfloat)
|
sl@0
|
3015 |
@see CVgEngine::PrepareForPathCommand(TInt, TInt)
|
sl@0
|
3016 |
@see CVgEngine::FinishPath(VGPath)
|
sl@0
|
3017 |
@see CVgEngine::AllocPathCoords(TInt)
|
sl@0
|
3018 |
*/
|
sl@0
|
3019 |
TInt CVgEngine::AllocPathCommands(TInt aCommandCount)
|
sl@0
|
3020 |
{
|
sl@0
|
3021 |
TInt err = KErrNone;
|
sl@0
|
3022 |
if (iCurrentMaxCommands < aCommandCount)
|
sl@0
|
3023 |
{
|
sl@0
|
3024 |
VGubyte* oldPathCommands = iPathCommands;
|
sl@0
|
3025 |
iPathCommands = static_cast<VGubyte*>(User::ReAlloc(iPathCommands, sizeof(VGubyte)*aCommandCount));
|
sl@0
|
3026 |
if (iPathCommands)
|
sl@0
|
3027 |
{
|
sl@0
|
3028 |
iCurrentMaxCommands = aCommandCount;
|
sl@0
|
3029 |
}
|
sl@0
|
3030 |
else
|
sl@0
|
3031 |
{
|
sl@0
|
3032 |
delete oldPathCommands;
|
sl@0
|
3033 |
iCurrentMaxCommands = 0;
|
sl@0
|
3034 |
}
|
sl@0
|
3035 |
}
|
sl@0
|
3036 |
if(!iPathCommands)
|
sl@0
|
3037 |
err = KErrNoMemory;
|
sl@0
|
3038 |
return err;
|
sl@0
|
3039 |
}
|
sl@0
|
3040 |
|
sl@0
|
3041 |
/**
|
sl@0
|
3042 |
Allocates enough memory to hold aCoordCount path coordinates, unless the coordinate array already holds
|
sl@0
|
3043 |
enough memory.
|
sl@0
|
3044 |
|
sl@0
|
3045 |
@param aCoordCount The number of coordinates to allocate space for in the coordinate array.
|
sl@0
|
3046 |
|
sl@0
|
3047 |
@return KErrNoMemory if memory allocation fails, KErrNone otherwise.
|
sl@0
|
3048 |
|
sl@0
|
3049 |
@see CVgEngine::CreatePath()
|
sl@0
|
3050 |
@see CVgEngine::AppendPathCommand(VGubyte)
|
sl@0
|
3051 |
@see CVgEngine::AppendPathCommand(VGubyte, VGfloat)
|
sl@0
|
3052 |
@see CVgEngine::AppendPathCommand(VGubyte, VGfloat, VGfloat)
|
sl@0
|
3053 |
@see CVgEngine::PrepareForPathCommand()
|
sl@0
|
3054 |
@see CVgEngine::FinishPath()
|
sl@0
|
3055 |
@see CVgEngine::AllocPathCommands()
|
sl@0
|
3056 |
*/
|
sl@0
|
3057 |
TInt CVgEngine::AllocPathCoords(TInt aCoordCount)
|
sl@0
|
3058 |
{
|
sl@0
|
3059 |
TInt err = KErrNone;
|
sl@0
|
3060 |
if (iCurrentMaxCoords < aCoordCount)
|
sl@0
|
3061 |
{
|
sl@0
|
3062 |
VGfloat* oldPathCoords = iPathCoords;
|
sl@0
|
3063 |
iPathCoords = static_cast<VGfloat*>(User::ReAlloc(iPathCoords, sizeof(VGfloat)*aCoordCount));
|
sl@0
|
3064 |
if (iPathCoords)
|
sl@0
|
3065 |
{
|
sl@0
|
3066 |
iCurrentMaxCoords = aCoordCount;
|
sl@0
|
3067 |
}
|
sl@0
|
3068 |
else
|
sl@0
|
3069 |
{
|
sl@0
|
3070 |
delete oldPathCoords;
|
sl@0
|
3071 |
iCurrentMaxCoords = 0;
|
sl@0
|
3072 |
}
|
sl@0
|
3073 |
}
|
sl@0
|
3074 |
if(!iPathCoords)
|
sl@0
|
3075 |
err = KErrNoMemory;
|
sl@0
|
3076 |
return err;
|
sl@0
|
3077 |
}
|
sl@0
|
3078 |
|
sl@0
|
3079 |
/**
|
sl@0
|
3080 |
Helper method for creating a VGImage from a CFbsBitmap. A temporary VGImageFormat-compatible
|
sl@0
|
3081 |
copy of the image may be created, if the source bitmap pixel format is not directly supported
|
sl@0
|
3082 |
by OpenVG. If there is not enough memory available, the error state on the driver is set to KErrNoMemory.
|
sl@0
|
3083 |
It sets the error in the driver if out-of-memory occurs when creating a VGImage. OpenVG will set its
|
sl@0
|
3084 |
own internal error if creation of VGImage fails.
|
sl@0
|
3085 |
|
sl@0
|
3086 |
@param aSource The source bitmap.
|
sl@0
|
3087 |
@param aFlipY If 'ETrue' then inverts the image in the y axis.
|
sl@0
|
3088 |
@param aOrigin An offset from the top-left of the image in which to take the first pixel of the image.
|
sl@0
|
3089 |
|
sl@0
|
3090 |
@return Returns a valid VGImage created using the passed CFbsBitmap. If unable to
|
sl@0
|
3091 |
create a valid VGImage then VG_INVALID_HANDLE.
|
sl@0
|
3092 |
*/
|
sl@0
|
3093 |
VGImage CVgEngine::CreateSourceVGImage(const CFbsBitmap& aSource, TBool aFlipY, const TPoint& aOrigin)
|
sl@0
|
3094 |
{
|
sl@0
|
3095 |
TDisplayMode srcDisplayMode = aSource.DisplayMode();
|
sl@0
|
3096 |
TDisplayMode vgCompatibleDisplayMode = ClosestVgCompatibleDisplayMode(srcDisplayMode);
|
sl@0
|
3097 |
VGImageFormat imageFormat = MapToVgDisplayMode(vgCompatibleDisplayMode);
|
sl@0
|
3098 |
const TSize sourceSize = aSource.SizeInPixels();
|
sl@0
|
3099 |
VGImage image = DoVgCreateImage(imageFormat, sourceSize.iWidth, sourceSize.iHeight, VG_IMAGE_QUALITY_NONANTIALIASED);
|
sl@0
|
3100 |
if (image != VG_INVALID_HANDLE)
|
sl@0
|
3101 |
{
|
sl@0
|
3102 |
const TInt pixmapStride = CFbsBitmap::ScanLineLength(sourceSize.iWidth, vgCompatibleDisplayMode);
|
sl@0
|
3103 |
|
sl@0
|
3104 |
// Conversion is performed if changing display mode (pixel format), source is compressed, or want to flip the y orientation.
|
sl@0
|
3105 |
if ((vgCompatibleDisplayMode != srcDisplayMode) || (aSource.Header().iCompression != ENoBitmapCompression) || aFlipY)
|
sl@0
|
3106 |
{
|
sl@0
|
3107 |
// May be worth using a static memory buffer for smaller scan-lines, to avoid overhead of alloc.
|
sl@0
|
3108 |
TAny* data = User::Alloc(pixmapStride);
|
sl@0
|
3109 |
if (data)
|
sl@0
|
3110 |
{
|
sl@0
|
3111 |
// Allocate memory and transform source into target format.
|
sl@0
|
3112 |
TPoint sourcePoint (0, aFlipY ? (sourceSize.iHeight - 1) : 0);
|
sl@0
|
3113 |
TPtr8 targetPoint ((TUint8*)data, pixmapStride, pixmapStride);
|
sl@0
|
3114 |
TInt adj = aFlipY ? -1 : 1;
|
sl@0
|
3115 |
|
sl@0
|
3116 |
if (aOrigin == TPoint(0,0)) // Not shifted
|
sl@0
|
3117 |
{
|
sl@0
|
3118 |
for (TInt targetY = 0; targetY < sourceSize.iHeight; targetY++, sourcePoint.iY += adj)
|
sl@0
|
3119 |
{
|
sl@0
|
3120 |
aSource.GetScanLine(targetPoint, sourcePoint, sourceSize.iWidth, vgCompatibleDisplayMode);
|
sl@0
|
3121 |
vgImageSubData(image, data, pixmapStride, imageFormat, 0, targetY, sourceSize.iWidth, 1);
|
sl@0
|
3122 |
}
|
sl@0
|
3123 |
}
|
sl@0
|
3124 |
else if (aOrigin.iX == 0) // Only shifted in Y.
|
sl@0
|
3125 |
{
|
sl@0
|
3126 |
for (TInt targetY = 0x00; targetY < sourceSize.iHeight; targetY++, sourcePoint.iY += adj)
|
sl@0
|
3127 |
{
|
sl@0
|
3128 |
aSource.GetScanLine(targetPoint, sourcePoint, sourceSize.iWidth, vgCompatibleDisplayMode);
|
sl@0
|
3129 |
vgImageSubData(image, data, pixmapStride, imageFormat, 0, targetY + aOrigin.iY, sourceSize.iWidth, 1);
|
sl@0
|
3130 |
vgImageSubData(image, data, pixmapStride, imageFormat, 0, targetY + aOrigin.iY - sourceSize.iHeight, sourceSize.iWidth, 1);
|
sl@0
|
3131 |
}
|
sl@0
|
3132 |
}
|
sl@0
|
3133 |
else if (aOrigin.iY == 0) // Only shifted in X.
|
sl@0
|
3134 |
{
|
sl@0
|
3135 |
for (TInt targetY = 0x00; targetY < sourceSize.iHeight; targetY++, sourcePoint.iY += adj)
|
sl@0
|
3136 |
{
|
sl@0
|
3137 |
aSource.GetScanLine(targetPoint, sourcePoint, sourceSize.iWidth, vgCompatibleDisplayMode);
|
sl@0
|
3138 |
vgImageSubData(image, data, pixmapStride, imageFormat, -aOrigin.iX, targetY, sourceSize.iWidth, 1);
|
sl@0
|
3139 |
vgImageSubData(image, data, pixmapStride, imageFormat, -aOrigin.iX + sourceSize.iWidth, targetY, sourceSize.iWidth, 1);
|
sl@0
|
3140 |
}
|
sl@0
|
3141 |
}
|
sl@0
|
3142 |
else // Shifted in both X and Y.
|
sl@0
|
3143 |
{
|
sl@0
|
3144 |
for (TInt targetY = 0; targetY < sourceSize.iHeight; targetY++, sourcePoint.iY += adj)
|
sl@0
|
3145 |
{
|
sl@0
|
3146 |
aSource.GetScanLine(targetPoint, sourcePoint, sourceSize.iWidth, vgCompatibleDisplayMode);
|
sl@0
|
3147 |
vgImageSubData(image, data, pixmapStride, imageFormat, -aOrigin.iX, targetY + aOrigin.iY, sourceSize.iWidth, 1);
|
sl@0
|
3148 |
vgImageSubData(image, data, pixmapStride, imageFormat, -aOrigin.iX, targetY + aOrigin.iY - sourceSize.iHeight, sourceSize.iWidth, 1);
|
sl@0
|
3149 |
vgImageSubData(image, data, pixmapStride, imageFormat, -aOrigin.iX + sourceSize.iWidth, targetY + aOrigin.iY, sourceSize.iWidth, 1);
|
sl@0
|
3150 |
vgImageSubData(image, data, pixmapStride, imageFormat, -aOrigin.iX + sourceSize.iWidth, targetY + aOrigin.iY - sourceSize.iHeight, sourceSize.iWidth, 1);
|
sl@0
|
3151 |
}
|
sl@0
|
3152 |
}
|
sl@0
|
3153 |
User::Free(data);
|
sl@0
|
3154 |
}
|
sl@0
|
3155 |
else
|
sl@0
|
3156 |
{
|
sl@0
|
3157 |
iDriver.SetError(KErrNoMemory);
|
sl@0
|
3158 |
vgDestroyImage(image);
|
sl@0
|
3159 |
return VG_INVALID_HANDLE;
|
sl@0
|
3160 |
}
|
sl@0
|
3161 |
}
|
sl@0
|
3162 |
else
|
sl@0
|
3163 |
{
|
sl@0
|
3164 |
aSource.BeginDataAccess();
|
sl@0
|
3165 |
const TInt sourceDataStride = aSource.DataStride();
|
sl@0
|
3166 |
if (aOrigin == TPoint(0,0)) // Not shifted
|
sl@0
|
3167 |
{
|
sl@0
|
3168 |
vgImageSubData(image, aSource.DataAddress(), sourceDataStride, imageFormat, 0, 0, sourceSize.iWidth, sourceSize.iHeight);
|
sl@0
|
3169 |
}
|
sl@0
|
3170 |
else
|
sl@0
|
3171 |
{
|
sl@0
|
3172 |
TUint32* dataAddress = aSource.DataAddress();
|
sl@0
|
3173 |
|
sl@0
|
3174 |
if (aOrigin.iX == 0) // Only shifted in Y.
|
sl@0
|
3175 |
{
|
sl@0
|
3176 |
vgImageSubData(image, dataAddress, sourceDataStride, imageFormat, 0, aOrigin.iY, sourceSize.iWidth, sourceSize.iHeight);
|
sl@0
|
3177 |
vgImageSubData(image, dataAddress, sourceDataStride, imageFormat, 0, aOrigin.iY - sourceSize.iHeight, sourceSize.iWidth, sourceSize.iHeight);
|
sl@0
|
3178 |
}
|
sl@0
|
3179 |
else if (aOrigin.iY == 0) // Only shifted in X.
|
sl@0
|
3180 |
{
|
sl@0
|
3181 |
vgImageSubData(image, dataAddress, sourceDataStride, imageFormat, -aOrigin.iX, 0, sourceSize.iWidth, sourceSize.iHeight);
|
sl@0
|
3182 |
vgImageSubData(image, dataAddress, sourceDataStride, imageFormat, -aOrigin.iX + sourceSize.iWidth, 0, sourceSize.iWidth, sourceSize.iHeight);
|
sl@0
|
3183 |
}
|
sl@0
|
3184 |
else // Shifted in both X and Y.
|
sl@0
|
3185 |
{
|
sl@0
|
3186 |
vgImageSubData(image, dataAddress, sourceDataStride, imageFormat, -aOrigin.iX, aOrigin.iY, sourceSize.iWidth, sourceSize.iHeight);
|
sl@0
|
3187 |
vgImageSubData(image, dataAddress, sourceDataStride, imageFormat, -aOrigin.iX, aOrigin.iY - sourceSize.iHeight, sourceSize.iWidth, sourceSize.iHeight);
|
sl@0
|
3188 |
vgImageSubData(image, dataAddress, sourceDataStride, imageFormat, -aOrigin.iX + sourceSize.iWidth, aOrigin.iY, sourceSize.iWidth, sourceSize.iHeight);
|
sl@0
|
3189 |
vgImageSubData(image, dataAddress, sourceDataStride, imageFormat, -aOrigin.iX + sourceSize.iWidth, aOrigin.iY - sourceSize.iHeight, sourceSize.iWidth, sourceSize.iHeight);
|
sl@0
|
3190 |
}
|
sl@0
|
3191 |
}
|
sl@0
|
3192 |
aSource.EndDataAccess(ETrue);
|
sl@0
|
3193 |
}
|
sl@0
|
3194 |
}
|
sl@0
|
3195 |
return image;
|
sl@0
|
3196 |
}
|
sl@0
|
3197 |
|
sl@0
|
3198 |
/**
|
sl@0
|
3199 |
Creates an image which represents a standard brush pattern (e.g. EVerticalHatchBrush), by
|
sl@0
|
3200 |
drawing the pattern using the current pen and brush colour to an image.
|
sl@0
|
3201 |
|
sl@0
|
3202 |
@param aPatternSize The dimensions in pixels of the image to create.
|
sl@0
|
3203 |
@param aBrushPattern An array of 1s and 0s representing the pattern to create, the length
|
sl@0
|
3204 |
of this array is aSize.iWidth*aSize.iHeight.
|
sl@0
|
3205 |
|
sl@0
|
3206 |
@return KErrNone if the brush is created successfully, KErrNoMemory if we fail to create
|
sl@0
|
3207 |
the brush image, KErrArgument if aBrushPattern is invalid.
|
sl@0
|
3208 |
*/
|
sl@0
|
3209 |
TInt CVgEngine::CreateStandardBrush(TSize& aPatternSize, VGbyte* aBrushPattern)
|
sl@0
|
3210 |
{
|
sl@0
|
3211 |
if (aBrushPattern == NULL)
|
sl@0
|
3212 |
return KErrArgument;
|
sl@0
|
3213 |
|
sl@0
|
3214 |
TInt err = KErrNone;
|
sl@0
|
3215 |
MakeEngineCurrent();
|
sl@0
|
3216 |
|
sl@0
|
3217 |
// The image format to use as the standard brush. If this changes, it also needs changing in
|
sl@0
|
3218 |
// GetCurrentBrush().
|
sl@0
|
3219 |
const VGImageFormat dataFormat = VG_sARGB_8888;
|
sl@0
|
3220 |
|
sl@0
|
3221 |
// We want to create the brush to the nearest power of 4 size.
|
sl@0
|
3222 |
TSize brushSize((aPatternSize.iWidth+3)&~3, (aPatternSize.iHeight+3)&~3);
|
sl@0
|
3223 |
|
sl@0
|
3224 |
// Allocate some memory to write the brush pattern to.
|
sl@0
|
3225 |
TUint32* data = new TUint32[brushSize.iWidth*brushSize.iHeight];
|
sl@0
|
3226 |
if (data == NULL)
|
sl@0
|
3227 |
err = KErrNoMemory;
|
sl@0
|
3228 |
|
sl@0
|
3229 |
if (err == KErrNone)
|
sl@0
|
3230 |
{
|
sl@0
|
3231 |
if (iBrushPatternStandardRegion != VG_INVALID_HANDLE)
|
sl@0
|
3232 |
{
|
sl@0
|
3233 |
vgDestroyImage(iBrushPatternStandardRegion);
|
sl@0
|
3234 |
iBrushPatternStandardRegion = VG_INVALID_HANDLE;
|
sl@0
|
3235 |
}
|
sl@0
|
3236 |
|
sl@0
|
3237 |
// Check the size of the existing standard brush as it can't be re-used if the
|
sl@0
|
3238 |
// new brush to be created is a different size.
|
sl@0
|
3239 |
if (iBrushPatternStandard != VG_INVALID_HANDLE)
|
sl@0
|
3240 |
{
|
sl@0
|
3241 |
if (iBrushPatternStandardSize != brushSize)
|
sl@0
|
3242 |
{
|
sl@0
|
3243 |
vgDestroyImage(iBrushPatternStandard);
|
sl@0
|
3244 |
iBrushPatternStandard = VG_INVALID_HANDLE;
|
sl@0
|
3245 |
}
|
sl@0
|
3246 |
}
|
sl@0
|
3247 |
|
sl@0
|
3248 |
if (iBrushPatternStandard == VG_INVALID_HANDLE)
|
sl@0
|
3249 |
{
|
sl@0
|
3250 |
// Create an image to draw the brush pattern onto, this will be our offscreen buffer
|
sl@0
|
3251 |
iBrushPatternStandardSize = brushSize;
|
sl@0
|
3252 |
iBrushPatternStandard = DoVgCreateImage(dataFormat, brushSize.iWidth, brushSize.iHeight, VG_IMAGE_QUALITY_NONANTIALIASED);
|
sl@0
|
3253 |
if (iBrushPatternStandard == VG_INVALID_HANDLE)
|
sl@0
|
3254 |
err = KErrNoMemory;
|
sl@0
|
3255 |
}
|
sl@0
|
3256 |
}
|
sl@0
|
3257 |
|
sl@0
|
3258 |
if (err == KErrNone)
|
sl@0
|
3259 |
{
|
sl@0
|
3260 |
// Set the colour used for the pen. If not fully opaque and not in WriteAlpha mode,
|
sl@0
|
3261 |
// blend the pen colour with the brush colour.
|
sl@0
|
3262 |
TRgb penColor = iPenColor;
|
sl@0
|
3263 |
if ((iPenColor.Alpha() != 255) && (iDrawMode != DirectGdi::EDrawModeWriteAlpha))
|
sl@0
|
3264 |
{
|
sl@0
|
3265 |
penColor.SetInternal(
|
sl@0
|
3266 |
PMA2NonPMAPixel(
|
sl@0
|
3267 |
PMAPixelBlend(
|
sl@0
|
3268 |
NonPMA2PMAPixel(iBrushColor.Internal()),
|
sl@0
|
3269 |
NonPMA2PMAPixel(iPenColor.Internal()))));
|
sl@0
|
3270 |
}
|
sl@0
|
3271 |
|
sl@0
|
3272 |
// Draw the pattern on to the brush, pixel by pixel.
|
sl@0
|
3273 |
for (TInt j = 0; j < aPatternSize.iHeight; ++j)
|
sl@0
|
3274 |
{
|
sl@0
|
3275 |
for (TInt i = 0; i < aPatternSize.iWidth; ++i)
|
sl@0
|
3276 |
{
|
sl@0
|
3277 |
if (aBrushPattern[(j*aPatternSize.iWidth)+i])
|
sl@0
|
3278 |
{
|
sl@0
|
3279 |
data[(j*brushSize.iWidth)+i] = penColor._Color16MA();
|
sl@0
|
3280 |
}
|
sl@0
|
3281 |
else
|
sl@0
|
3282 |
{
|
sl@0
|
3283 |
data[(j*brushSize.iWidth)+i] = iBrushColor._Color16MA();
|
sl@0
|
3284 |
}
|
sl@0
|
3285 |
}
|
sl@0
|
3286 |
}
|
sl@0
|
3287 |
|
sl@0
|
3288 |
// Copy the pattern to the VGImage so we can set it as the current brush
|
sl@0
|
3289 |
vgImageSubData(iBrushPatternStandard, // the image to copy to
|
sl@0
|
3290 |
data, // the source data
|
sl@0
|
3291 |
brushSize.iWidth*4, // the stride of the source data
|
sl@0
|
3292 |
dataFormat, // the format of the source data
|
sl@0
|
3293 |
0, // x
|
sl@0
|
3294 |
0, // y
|
sl@0
|
3295 |
brushSize.iWidth, // width
|
sl@0
|
3296 |
brushSize.iHeight); // height
|
sl@0
|
3297 |
iBrushPatternStandardSize = brushSize;
|
sl@0
|
3298 |
|
sl@0
|
3299 |
// We only want to use the region of the brush we just created that is the size of the pattern
|
sl@0
|
3300 |
iBrushPatternStandardRegion = vgChildImage(iBrushPatternStandard,
|
sl@0
|
3301 |
0,
|
sl@0
|
3302 |
0,
|
sl@0
|
3303 |
aPatternSize.iWidth,
|
sl@0
|
3304 |
aPatternSize.iHeight);
|
sl@0
|
3305 |
iBrushPatternStandardRegionSize = aPatternSize;
|
sl@0
|
3306 |
}
|
sl@0
|
3307 |
|
sl@0
|
3308 |
// Clean up
|
sl@0
|
3309 |
delete [] data;
|
sl@0
|
3310 |
|
sl@0
|
3311 |
return err;
|
sl@0
|
3312 |
}
|
sl@0
|
3313 |
|
sl@0
|
3314 |
/**
|
sl@0
|
3315 |
Internal function to return the currently active brush and its properties.
|
sl@0
|
3316 |
@param aBrush On success, holds the current VGImage brush being used.
|
sl@0
|
3317 |
@param aSize On success, holds the dimensions of VGImage being used as the brush.
|
sl@0
|
3318 |
@param aFormat On success, holds the VGImageFormat of the brush.
|
sl@0
|
3319 |
@return ETrue if a brush is currently being used, EFalse otherwise.
|
sl@0
|
3320 |
*/
|
sl@0
|
3321 |
TBool CVgEngine::GetCurrentBrushPattern(VGImage& aBrush, TSize& aSize, VGImageFormat& aFormat) const
|
sl@0
|
3322 |
{
|
sl@0
|
3323 |
TBool success = ETrue;
|
sl@0
|
3324 |
if (iBrushStyle == DirectGdi::EPatternedBrush)
|
sl@0
|
3325 |
{
|
sl@0
|
3326 |
aBrush = iBrushPatternUser;
|
sl@0
|
3327 |
aSize = iBrushPatternUserSize;
|
sl@0
|
3328 |
aFormat = static_cast<VGImageFormat>(vgGetParameteri(aBrush, VG_IMAGE_FORMAT));
|
sl@0
|
3329 |
}
|
sl@0
|
3330 |
else if (iBrushStyle > DirectGdi::EPatternedBrush)
|
sl@0
|
3331 |
{
|
sl@0
|
3332 |
aBrush = iBrushPatternStandardRegion;
|
sl@0
|
3333 |
aSize = iBrushPatternStandardRegionSize;
|
sl@0
|
3334 |
// Currently we only ever use VG_sARGB_8888 for the standard brush format.
|
sl@0
|
3335 |
aFormat = VG_sARGB_8888;
|
sl@0
|
3336 |
}
|
sl@0
|
3337 |
else
|
sl@0
|
3338 |
success = EFalse;
|
sl@0
|
3339 |
return success;
|
sl@0
|
3340 |
}
|
sl@0
|
3341 |
|
sl@0
|
3342 |
/**
|
sl@0
|
3343 |
Copies the current brush pattern (if a brush pattern is set) into iBrushPatternNonZeroOrigin.
|
sl@0
|
3344 |
This function should only be used if the current brush origin is not (0,0). When copying the
|
sl@0
|
3345 |
current brush pattern, it is shifted to take into account the non-zero origin. This shifted brush
|
sl@0
|
3346 |
pattern should be used for all brush operations while a non-zero origin is set.
|
sl@0
|
3347 |
|
sl@0
|
3348 |
@return KErrNone if successful, KErrNotFound if the brush pattern could not be copied.
|
sl@0
|
3349 |
*/
|
sl@0
|
3350 |
TInt CVgEngine::CopyCurrentBrushPatternForNonZeroOrigin()
|
sl@0
|
3351 |
{
|
sl@0
|
3352 |
MakeEngineCurrent();
|
sl@0
|
3353 |
TInt ret = KErrNotFound;
|
sl@0
|
3354 |
VGImage brush = VG_INVALID_HANDLE;
|
sl@0
|
3355 |
TSize brushSize;
|
sl@0
|
3356 |
VGImageFormat imageFormat;
|
sl@0
|
3357 |
|
sl@0
|
3358 |
if (GetCurrentBrushPattern(brush, brushSize, imageFormat))
|
sl@0
|
3359 |
{
|
sl@0
|
3360 |
const TInt width = brushSize.iWidth;
|
sl@0
|
3361 |
const TInt height = brushSize.iHeight;
|
sl@0
|
3362 |
|
sl@0
|
3363 |
if ((width != 0) && (height != 0))
|
sl@0
|
3364 |
{
|
sl@0
|
3365 |
if (iBrushPatternNonZeroOrigin != VG_INVALID_HANDLE)
|
sl@0
|
3366 |
{
|
sl@0
|
3367 |
vgDestroyImage(iBrushPatternNonZeroOrigin);
|
sl@0
|
3368 |
iBrushPatternNonZeroOrigin = VG_INVALID_HANDLE;
|
sl@0
|
3369 |
}
|
sl@0
|
3370 |
|
sl@0
|
3371 |
// Create the brush we are going to copy the current brush into
|
sl@0
|
3372 |
iBrushPatternNonZeroOrigin = DoVgCreateImage(imageFormat,
|
sl@0
|
3373 |
width,
|
sl@0
|
3374 |
height,
|
sl@0
|
3375 |
VG_IMAGE_QUALITY_FASTER);
|
sl@0
|
3376 |
if (iBrushPatternNonZeroOrigin != VG_INVALID_HANDLE)
|
sl@0
|
3377 |
{
|
sl@0
|
3378 |
TInt offsetX = width - (iBrushOrigin.iX % width);
|
sl@0
|
3379 |
TInt offsetY = height - (iBrushOrigin.iY % height);
|
sl@0
|
3380 |
|
sl@0
|
3381 |
// Top left to bottom right
|
sl@0
|
3382 |
if (offsetX != 0 && offsetY != 0) // check the width and height we are copying are not 0
|
sl@0
|
3383 |
vgCopyImage(iBrushPatternNonZeroOrigin, width-offsetX, height-offsetY, brush, 0, 0, offsetX, offsetY, VG_FALSE);
|
sl@0
|
3384 |
|
sl@0
|
3385 |
// Top right to bottom left
|
sl@0
|
3386 |
if ((width-offsetX) != 0 && offsetY != 0)
|
sl@0
|
3387 |
vgCopyImage(iBrushPatternNonZeroOrigin, 0, height-offsetY, brush, offsetX, 0, width-offsetX, offsetY, VG_FALSE);
|
sl@0
|
3388 |
|
sl@0
|
3389 |
// Bottom left to top right
|
sl@0
|
3390 |
if (offsetX != 0 && (height-offsetY) != 0)
|
sl@0
|
3391 |
vgCopyImage(iBrushPatternNonZeroOrigin, width-offsetX, 0, brush, 0, offsetY, offsetX, height-offsetY, VG_FALSE);
|
sl@0
|
3392 |
|
sl@0
|
3393 |
// Bottom right to top left
|
sl@0
|
3394 |
if ((width-offsetX) != 0 && (height-offsetY) != 0)
|
sl@0
|
3395 |
vgCopyImage(iBrushPatternNonZeroOrigin, 0, 0, brush, offsetX, offsetY, width-offsetX, height-offsetY, VG_FALSE);
|
sl@0
|
3396 |
|
sl@0
|
3397 |
// Paint with the new non-zero origin brush
|
sl@0
|
3398 |
vgPaintPattern(iBrush, iBrushPatternNonZeroOrigin);
|
sl@0
|
3399 |
|
sl@0
|
3400 |
ret = KErrNone;
|
sl@0
|
3401 |
}
|
sl@0
|
3402 |
else
|
sl@0
|
3403 |
{
|
sl@0
|
3404 |
ret = KErrNoMemory;
|
sl@0
|
3405 |
}
|
sl@0
|
3406 |
}
|
sl@0
|
3407 |
}
|
sl@0
|
3408 |
|
sl@0
|
3409 |
return ret;
|
sl@0
|
3410 |
}
|
sl@0
|
3411 |
|
sl@0
|
3412 |
/**
|
sl@0
|
3413 |
Calculates the angle in degrees formed anti-clockwise between vector V1 and V2, where V1 is a
|
sl@0
|
3414 |
horizontal vector to the right from aOriginX, and V2 is the vector (aPointX-aOriginX, aPointY-aOriginY).
|
sl@0
|
3415 |
|
sl@0
|
3416 |
@param aOriginX The x coordinate of a point which represents the origin of our calculation.
|
sl@0
|
3417 |
@param aOriginY The y coordinate of a point which represents the origin of our calculation.
|
sl@0
|
3418 |
@param aPointX The x coordinate of the point which defines the angle with the origin's x-axis.
|
sl@0
|
3419 |
@param aPointY The y coordinate of the point which defines the angle with the origin's y-axis.
|
sl@0
|
3420 |
@param aWidth Width of the rectangle which defines where to draw the ellipse.
|
sl@0
|
3421 |
@param aHeight Height of the rectangle which defines where to draw the ellipse.
|
sl@0
|
3422 |
|
sl@0
|
3423 |
@panic DGDIAdapter 1006, if either width or height are less than 1 (debug-only).
|
sl@0
|
3424 |
@return The angle in degrees between the vectors V1 and V2 described above.
|
sl@0
|
3425 |
*/
|
sl@0
|
3426 |
TReal CVgEngine::GetAngleFromXAxisAnticlockwise(const TReal aOriginX, const TReal aOriginY, const TReal aPointX, const TReal aPointY, const TReal aWidth, const TReal aHeight)
|
sl@0
|
3427 |
{
|
sl@0
|
3428 |
GRAPHICS_ASSERT_DEBUG((aWidth > 0) && (aHeight > 0), EDirectGdiPanicInvalidParameter);
|
sl@0
|
3429 |
|
sl@0
|
3430 |
// The angle is calculated from the radius line that joins the point to the origin.
|
sl@0
|
3431 |
// The point initially provided defines a line relative to the ellipse.
|
sl@0
|
3432 |
// But the VG spec states that the required angle is that for a perfect circle
|
sl@0
|
3433 |
// before that circle is scaled by the bounding rect into an ellipse.
|
sl@0
|
3434 |
// Therefore, downscale the position of the point relative to the origin, by the
|
sl@0
|
3435 |
// relative dimensions of the width/height of the ellipse to make it relative to
|
sl@0
|
3436 |
// the underlying circle. Then use the resulting circle radius line to calculate the angle.
|
sl@0
|
3437 |
|
sl@0
|
3438 |
TReal angle = 0.0f;
|
sl@0
|
3439 |
TReal pointX = aPointX-aOriginX;
|
sl@0
|
3440 |
TReal pointY = aPointY-aOriginY;
|
sl@0
|
3441 |
|
sl@0
|
3442 |
const TReal scalingFactor = (aWidth / aHeight);
|
sl@0
|
3443 |
pointY *= scalingFactor;
|
sl@0
|
3444 |
Math::ATan(angle, pointY, pointX);
|
sl@0
|
3445 |
|
sl@0
|
3446 |
// Adjust the angle for Q2 and Q3
|
sl@0
|
3447 |
if (pointY < 0)
|
sl@0
|
3448 |
angle = (KPi*2)+angle;
|
sl@0
|
3449 |
|
sl@0
|
3450 |
return angle*KRadToDeg;
|
sl@0
|
3451 |
}
|
sl@0
|
3452 |
|
sl@0
|
3453 |
/**
|
sl@0
|
3454 |
Method for drawing arcs or pies. An arc is a segment of an ellipse which is defined by a given rectangle.
|
sl@0
|
3455 |
The arc is drawn anti-clockwise from the arc start point to the arc end point. The arc start point is the
|
sl@0
|
3456 |
intersection between vectors from the centre of the ellipse to the given start position and the ellipse.
|
sl@0
|
3457 |
The arc end point is defined in the same way.
|
sl@0
|
3458 |
|
sl@0
|
3459 |
@param aRect The rectangle which defines where to draw the ellipse.
|
sl@0
|
3460 |
@param aStart Position to be used in defining the arc start point.
|
sl@0
|
3461 |
@param aEnd Position to be used in defining the arc end point.
|
sl@0
|
3462 |
@param aArcType The type of arc to draw; an arc, a chord or a pie.
|
sl@0
|
3463 |
|
sl@0
|
3464 |
@post Request to draw an arc has been accepted. There is no guarantee that the request
|
sl@0
|
3465 |
has been processed when the method returns.
|
sl@0
|
3466 |
|
sl@0
|
3467 |
@see CVgEngine::DrawPie()
|
sl@0
|
3468 |
@see CVgEngine::DrawArc()
|
sl@0
|
3469 |
*/
|
sl@0
|
3470 |
void CVgEngine::DoDrawArc(const TRect& aRect, const TPoint& aStart, const TPoint& aEnd, VGUArcType aArcType)
|
sl@0
|
3471 |
{
|
sl@0
|
3472 |
MakeEngineCurrent();
|
sl@0
|
3473 |
|
sl@0
|
3474 |
// Only draw if we are not painting with a NULL pen and a NULL brush
|
sl@0
|
3475 |
if (iPaintMode == 0)
|
sl@0
|
3476 |
return;
|
sl@0
|
3477 |
|
sl@0
|
3478 |
// If the pen width and height are the same then draw as normal. If they are different but we should be filling
|
sl@0
|
3479 |
// this shape we need to draw the filled area only as normal (not the outline). The outline of the shape is drawn
|
sl@0
|
3480 |
// in the block of code below to allow the effect of a different width and height pen to be applied.
|
sl@0
|
3481 |
if ((iPenSize.iWidth == iPenSize.iHeight) || ((iPaintMode & VG_FILL_PATH) && (aArcType == VGU_ARC_PIE)))
|
sl@0
|
3482 |
{
|
sl@0
|
3483 |
TReal originX = aRect.iTl.iX + (static_cast<TReal>(aRect.Width())*0.5);
|
sl@0
|
3484 |
TReal originY = aRect.iTl.iY + (static_cast<TReal>(aRect.Height())*0.5);
|
sl@0
|
3485 |
TReal startAngle = GetAngleFromXAxisAnticlockwise(originX, originY, aStart.iX, aStart.iY, aRect.Width(), aRect.Height());
|
sl@0
|
3486 |
TReal endAngle = GetAngleFromXAxisAnticlockwise(originX, originY, aEnd.iX, aEnd.iY, aRect.Width(), aRect.Height());
|
sl@0
|
3487 |
TReal extent = endAngle - startAngle;
|
sl@0
|
3488 |
|
sl@0
|
3489 |
// The extent defines what direction the arc is drawn in, so make sure we always draw
|
sl@0
|
3490 |
// anti-clockwise (-ve extent)
|
sl@0
|
3491 |
if (extent > 0.0f)
|
sl@0
|
3492 |
extent -= 360.0f;
|
sl@0
|
3493 |
|
sl@0
|
3494 |
// If the start and end points are the same, make sure we draw arc all the way round the ellipse
|
sl@0
|
3495 |
if ((aStart == aEnd) || (extent > -0.0001f))
|
sl@0
|
3496 |
extent = -360.0f;
|
sl@0
|
3497 |
|
sl@0
|
3498 |
// Before any vgu command, call SetError() as this stores the current vg error state (if any) in the
|
sl@0
|
3499 |
// driver. Some implementations of vgu clears error state so we'd lose error codes otherwise.
|
sl@0
|
3500 |
iDriver.SetError(KErrNone);
|
sl@0
|
3501 |
|
sl@0
|
3502 |
if (PreparePath(iVgPath, 5)) // N.B. 5 is just an initial hint as to how large the path may be, not its final size
|
sl@0
|
3503 |
{
|
sl@0
|
3504 |
VGUErrorCode err = vguArc(iVgPath,
|
sl@0
|
3505 |
originX + 0.5f,
|
sl@0
|
3506 |
originY + 0.5f,
|
sl@0
|
3507 |
aRect.Width(),
|
sl@0
|
3508 |
aRect.Height(),
|
sl@0
|
3509 |
startAngle,
|
sl@0
|
3510 |
extent,
|
sl@0
|
3511 |
aArcType);
|
sl@0
|
3512 |
|
sl@0
|
3513 |
if (err == VGU_NO_ERROR)
|
sl@0
|
3514 |
{
|
sl@0
|
3515 |
VGbitfield paintMode = iPaintMode;
|
sl@0
|
3516 |
if(aArcType == VGU_ARC_OPEN)
|
sl@0
|
3517 |
{
|
sl@0
|
3518 |
paintMode &= ~VG_FILL_PATH;
|
sl@0
|
3519 |
}
|
sl@0
|
3520 |
for (iRegionManager.Begin(); iRegionManager.ApplyClipRegion(); iRegionManager.Next())
|
sl@0
|
3521 |
vgDrawPath(iVgPath, (iPenSize.iWidth == iPenSize.iHeight) ? paintMode : VG_FILL_PATH);
|
sl@0
|
3522 |
}
|
sl@0
|
3523 |
else
|
sl@0
|
3524 |
{
|
sl@0
|
3525 |
SetVguError(err);
|
sl@0
|
3526 |
}
|
sl@0
|
3527 |
}
|
sl@0
|
3528 |
}
|
sl@0
|
3529 |
|
sl@0
|
3530 |
if ((iPenSize.iWidth != iPenSize.iHeight)
|
sl@0
|
3531 |
&& (iPaintMode & VG_STROKE_PATH)
|
sl@0
|
3532 |
&& (iPenSize.iWidth != 0) && (iPenSize.iHeight != 0))
|
sl@0
|
3533 |
{
|
sl@0
|
3534 |
// Setting a pen with different width and height is not available on OpenVG, so we need to scale
|
sl@0
|
3535 |
// the coordinates we are drawing and apply a scaling matrix that scales by the width and height
|
sl@0
|
3536 |
// of the pen to get the effect of a pen width different width and height.
|
sl@0
|
3537 |
TSize penSize = iPenSize;
|
sl@0
|
3538 |
SetPenSize(TSize(1, 1));
|
sl@0
|
3539 |
vgSeti(VG_MATRIX_MODE, VG_MATRIX_PATH_USER_TO_SURFACE);
|
sl@0
|
3540 |
vgScale(penSize.iWidth, penSize.iHeight);
|
sl@0
|
3541 |
VGfloat scaleX = 1.0f/(float)penSize.iWidth;
|
sl@0
|
3542 |
VGfloat scaleY = 1.0f/(float)penSize.iHeight;
|
sl@0
|
3543 |
|
sl@0
|
3544 |
TReal originX = aRect.iTl.iX + (static_cast<TReal>(aRect.Width())*0.5);
|
sl@0
|
3545 |
TReal originY = aRect.iTl.iY + (static_cast<TReal>(aRect.Height())*0.5);
|
sl@0
|
3546 |
TReal startAngle = GetAngleFromXAxisAnticlockwise(originX, originY, aStart.iX, aStart.iY, aRect.Width(), aRect.Height());
|
sl@0
|
3547 |
TReal endAngle = GetAngleFromXAxisAnticlockwise(originX, originY, aEnd.iX, aEnd.iY, aRect.Width(), aRect.Height());
|
sl@0
|
3548 |
TReal extent = endAngle - startAngle;
|
sl@0
|
3549 |
|
sl@0
|
3550 |
// The extent defines what direction the arc is drawn in, so make sure we always draw
|
sl@0
|
3551 |
// anti-clockwise (-ve extent)
|
sl@0
|
3552 |
if (extent > 0.0f)
|
sl@0
|
3553 |
extent -= 360.0f;
|
sl@0
|
3554 |
|
sl@0
|
3555 |
// If the start and end points are the same, make sure we draw arc all the way round the ellipse
|
sl@0
|
3556 |
if ((aStart == aEnd) || (extent > -0.0001f))
|
sl@0
|
3557 |
extent = -360.0f;
|
sl@0
|
3558 |
|
sl@0
|
3559 |
// Before any vgu command, call SetError() as this stores the current vg error state (if any) in the
|
sl@0
|
3560 |
// driver. Some implementations of vgu clears error state so we'd lose error codes otherwise.
|
sl@0
|
3561 |
iDriver.SetError(KErrNone);
|
sl@0
|
3562 |
|
sl@0
|
3563 |
if (PreparePath(iVgPath, 5))
|
sl@0
|
3564 |
{
|
sl@0
|
3565 |
VGUErrorCode err = vguArc(iVgPath,
|
sl@0
|
3566 |
(originX + 0.5f) * scaleX,
|
sl@0
|
3567 |
(originY + 0.5f) * scaleY,
|
sl@0
|
3568 |
(float)aRect.Width() * scaleX,
|
sl@0
|
3569 |
(float)aRect.Height() * scaleY,
|
sl@0
|
3570 |
startAngle,
|
sl@0
|
3571 |
extent,
|
sl@0
|
3572 |
aArcType);
|
sl@0
|
3573 |
|
sl@0
|
3574 |
if (err == VGU_NO_ERROR)
|
sl@0
|
3575 |
{
|
sl@0
|
3576 |
for (iRegionManager.Begin(); iRegionManager.ApplyClipRegion(); iRegionManager.Next())
|
sl@0
|
3577 |
vgDrawPath(iVgPath, VG_STROKE_PATH);
|
sl@0
|
3578 |
}
|
sl@0
|
3579 |
else
|
sl@0
|
3580 |
{
|
sl@0
|
3581 |
SetVguError(err);
|
sl@0
|
3582 |
}
|
sl@0
|
3583 |
}
|
sl@0
|
3584 |
|
sl@0
|
3585 |
ResetVgMatrix(VG_MATRIX_PATH_USER_TO_SURFACE);
|
sl@0
|
3586 |
SetPenSize(penSize);
|
sl@0
|
3587 |
}
|
sl@0
|
3588 |
|
sl@0
|
3589 |
}
|
sl@0
|
3590 |
|
sl@0
|
3591 |
/**
|
sl@0
|
3592 |
Helper function for drawing a source as a CDirectGdiImageSource.
|
sl@0
|
3593 |
|
sl@0
|
3594 |
@see DrawResource(const TRect&, const RDirectGdiDrawableSource&, DirectGdi::TGraphicsRotation).
|
sl@0
|
3595 |
*/
|
sl@0
|
3596 |
void CVgEngine::DoDrawResource(const TRect& aDestRect,
|
sl@0
|
3597 |
CDirectGdiImageSourceImpl* aSource,
|
sl@0
|
3598 |
DirectGdi::TGraphicsRotation aRotation)
|
sl@0
|
3599 |
|
sl@0
|
3600 |
{
|
sl@0
|
3601 |
TSize size = aSource->Size();
|
sl@0
|
3602 |
TRect srcRect(0, 0, size.iWidth, size.iHeight);
|
sl@0
|
3603 |
|
sl@0
|
3604 |
DoDrawResource(aDestRect, aSource, srcRect, aRotation);
|
sl@0
|
3605 |
}
|
sl@0
|
3606 |
|
sl@0
|
3607 |
/**
|
sl@0
|
3608 |
Helper function for drawing a source as a CDirectGdiImageSource.
|
sl@0
|
3609 |
|
sl@0
|
3610 |
@see DrawResource(const TRect&, const RDirectGdiDrawableSource&, const TRect&, DirectGdi::TGraphicsRotation).
|
sl@0
|
3611 |
*/
|
sl@0
|
3612 |
void CVgEngine::DoDrawResource(const TRect& aDestRect,
|
sl@0
|
3613 |
CDirectGdiImageSourceImpl* aSource,
|
sl@0
|
3614 |
const TRect& aSourceRect,
|
sl@0
|
3615 |
DirectGdi::TGraphicsRotation aRotation)
|
sl@0
|
3616 |
{
|
sl@0
|
3617 |
// If the source rect is smaller than the actual source size then we need to create a child VGImage to draw
|
sl@0
|
3618 |
VGImage vgImage = aSource->VgImage();
|
sl@0
|
3619 |
TSize size = aSource->Size();
|
sl@0
|
3620 |
if ((aSourceRect.Width() < size.iWidth) || (aSourceRect.Height() < size.iHeight))
|
sl@0
|
3621 |
{
|
sl@0
|
3622 |
vgImage = vgChildImage(vgImage, aSourceRect.iTl.iX, aSourceRect.iTl.iY, aSourceRect.Width(), aSourceRect.Height());
|
sl@0
|
3623 |
}
|
sl@0
|
3624 |
|
sl@0
|
3625 |
if (vgImage != VG_INVALID_HANDLE)
|
sl@0
|
3626 |
{
|
sl@0
|
3627 |
vgSeti(VG_MATRIX_MODE, VG_MATRIX_IMAGE_USER_TO_SURFACE);
|
sl@0
|
3628 |
|
sl@0
|
3629 |
TRect destRect(aDestRect);
|
sl@0
|
3630 |
TRect sourceRect(aSourceRect);
|
sl@0
|
3631 |
|
sl@0
|
3632 |
if (aRotation == DirectGdi::EGraphicsRotationNone ||
|
sl@0
|
3633 |
aRotation == DirectGdi::EGraphicsRotation180)
|
sl@0
|
3634 |
{
|
sl@0
|
3635 |
// Pixel-data in EGLImages appears to be upside down due to the Y-inversion
|
sl@0
|
3636 |
// effect of the Identity matrix. Therefore must undo the Y-inversion here
|
sl@0
|
3637 |
// and adjust destination rect accordingly.
|
sl@0
|
3638 |
const TInt destRectHeight = aDestRect.Height();
|
sl@0
|
3639 |
destRect.iTl.iY = (iSize.iHeight - aDestRect.iTl.iY - iOrigin.iY) - destRectHeight;
|
sl@0
|
3640 |
destRect.iTl.iX += iOrigin.iX;
|
sl@0
|
3641 |
destRect.iBr.iX += iOrigin.iX;
|
sl@0
|
3642 |
destRect.iBr.iY = destRect.iTl.iY + destRectHeight;
|
sl@0
|
3643 |
sourceRect.iBr.iY = aSource->Size().iHeight - sourceRect.iTl.iY;
|
sl@0
|
3644 |
sourceRect.iTl.iY = sourceRect.iBr.iY - aSourceRect.Height();
|
sl@0
|
3645 |
vgLoadIdentity();
|
sl@0
|
3646 |
}
|
sl@0
|
3647 |
else
|
sl@0
|
3648 |
{
|
sl@0
|
3649 |
// But if rotation is 90 or 270 degrees, only need to mirror in the X-axis.
|
sl@0
|
3650 |
vgScale(-1, 1);
|
sl@0
|
3651 |
}
|
sl@0
|
3652 |
|
sl@0
|
3653 |
VGfloat xScale = 1.f;
|
sl@0
|
3654 |
VGfloat yScale = 1.f;
|
sl@0
|
3655 |
VGint posX = destRect.iTl.iX;
|
sl@0
|
3656 |
VGint posY = destRect.iTl.iY;
|
sl@0
|
3657 |
|
sl@0
|
3658 |
switch (aRotation)
|
sl@0
|
3659 |
{
|
sl@0
|
3660 |
case DirectGdi::EGraphicsRotation90:
|
sl@0
|
3661 |
xScale = ((VGfloat)destRect.Width()/(VGfloat)sourceRect.Height());
|
sl@0
|
3662 |
yScale = ((VGfloat)destRect.Height()/(VGfloat)sourceRect.Width());
|
sl@0
|
3663 |
vgTranslate(-posX, posY);
|
sl@0
|
3664 |
vgScale(xScale, yScale);
|
sl@0
|
3665 |
vgRotate(90.0f);
|
sl@0
|
3666 |
break;
|
sl@0
|
3667 |
case DirectGdi::EGraphicsRotation180:
|
sl@0
|
3668 |
xScale = ((VGfloat)destRect.Width()/(VGfloat)sourceRect.Width());
|
sl@0
|
3669 |
yScale = ((VGfloat)destRect.Height()/(VGfloat)sourceRect.Height());
|
sl@0
|
3670 |
vgTranslate(posX+destRect.Width(), posY+destRect.Height());
|
sl@0
|
3671 |
vgScale(xScale, yScale);
|
sl@0
|
3672 |
vgRotate(180.0f);
|
sl@0
|
3673 |
break;
|
sl@0
|
3674 |
case DirectGdi::EGraphicsRotation270:
|
sl@0
|
3675 |
xScale = ((VGfloat)destRect.Width()/(VGfloat)sourceRect.Height());
|
sl@0
|
3676 |
yScale = ((VGfloat)destRect.Height()/(VGfloat)sourceRect.Width());
|
sl@0
|
3677 |
vgTranslate(-posX-destRect.Width(), (posY+destRect.Height()));
|
sl@0
|
3678 |
vgScale(xScale, yScale);
|
sl@0
|
3679 |
vgRotate(270.0f);
|
sl@0
|
3680 |
break;
|
sl@0
|
3681 |
default: // DirectGdi::EGraphicsRotationNone
|
sl@0
|
3682 |
xScale = ((VGfloat)destRect.Width()/(VGfloat)sourceRect.Width());
|
sl@0
|
3683 |
yScale = ((VGfloat)destRect.Height()/(VGfloat)sourceRect.Height());
|
sl@0
|
3684 |
vgTranslate(posX, posY);
|
sl@0
|
3685 |
vgScale(xScale, yScale);
|
sl@0
|
3686 |
break;
|
sl@0
|
3687 |
}
|
sl@0
|
3688 |
|
sl@0
|
3689 |
for (iRegionManager.Begin(); iRegionManager.ApplyClipRegion(); iRegionManager.Next())
|
sl@0
|
3690 |
vgDrawImage(vgImage);
|
sl@0
|
3691 |
|
sl@0
|
3692 |
if (vgImage != aSource->VgImage())
|
sl@0
|
3693 |
{
|
sl@0
|
3694 |
// Created a child VGImage, so destroy after use.
|
sl@0
|
3695 |
vgDestroyImage(vgImage);
|
sl@0
|
3696 |
}
|
sl@0
|
3697 |
|
sl@0
|
3698 |
ResetVgMatrix(VG_MATRIX_IMAGE_USER_TO_SURFACE);
|
sl@0
|
3699 |
}
|
sl@0
|
3700 |
}
|
sl@0
|
3701 |
|
sl@0
|
3702 |
/**
|
sl@0
|
3703 |
Maps a VGU error code to a Symbian OS error code, and sets the driver's error state. If the
|
sl@0
|
3704 |
error is unrecognised, the error is set to KErrGeneral.
|
sl@0
|
3705 |
|
sl@0
|
3706 |
@param aErr The return value (error state) from a VGU command.
|
sl@0
|
3707 |
@post If empty, the driver's error state is updated to the mapped error code.
|
sl@0
|
3708 |
*/
|
sl@0
|
3709 |
void CVgEngine::SetVguError(VGUErrorCode aErr)
|
sl@0
|
3710 |
{
|
sl@0
|
3711 |
switch(aErr)
|
sl@0
|
3712 |
{
|
sl@0
|
3713 |
case VGU_NO_ERROR:
|
sl@0
|
3714 |
break;
|
sl@0
|
3715 |
case VGU_OUT_OF_MEMORY_ERROR:
|
sl@0
|
3716 |
iDriver.SetError(KErrNoMemory);
|
sl@0
|
3717 |
break;
|
sl@0
|
3718 |
case VGU_BAD_HANDLE_ERROR:
|
sl@0
|
3719 |
iDriver.SetError(KErrBadHandle);
|
sl@0
|
3720 |
break;
|
sl@0
|
3721 |
case VGU_ILLEGAL_ARGUMENT_ERROR:
|
sl@0
|
3722 |
iDriver.SetError(KErrArgument);
|
sl@0
|
3723 |
break;
|
sl@0
|
3724 |
case VGU_PATH_CAPABILITY_ERROR:
|
sl@0
|
3725 |
iDriver.SetError(KErrNotSupported);
|
sl@0
|
3726 |
break;
|
sl@0
|
3727 |
default:
|
sl@0
|
3728 |
iDriver.SetError(KErrGeneral);
|
sl@0
|
3729 |
break;
|
sl@0
|
3730 |
}
|
sl@0
|
3731 |
}
|
sl@0
|
3732 |
|
sl@0
|
3733 |
/**
|
sl@0
|
3734 |
Helper method for creating a VGImage. This method clears the VG image cache in an attempt to
|
sl@0
|
3735 |
reclaim some memory if creation of a VGImage fails due to no memory being available,
|
sl@0
|
3736 |
it then tries to create the image again. If image creation fails again it then clears the glyph
|
sl@0
|
3737 |
cache and tries to create the image again. If image creation still fails, OpenVG is forced to
|
sl@0
|
3738 |
complete all currently outstanding drawing requests, so that any OpenVG objects marked for deletion,
|
sl@0
|
3739 |
such as VGImages that are currently waiting to be drawn, are freed. This is an attempt to make sure
|
sl@0
|
3740 |
that images are still displayed in low memory conditions. Use this method instead of calling
|
sl@0
|
3741 |
vgCreateImage() directly. Clearing the VG image cache in this way will have a negative effect on
|
sl@0
|
3742 |
performance regarding speed, but it is more important that an attempt is made to draw something
|
sl@0
|
3743 |
when memory is low.
|
sl@0
|
3744 |
|
sl@0
|
3745 |
@param aFormat The pixel format of the image to be created
|
sl@0
|
3746 |
@param aWidth The width of the image to be created
|
sl@0
|
3747 |
@param aHeight The height of the image to be created
|
sl@0
|
3748 |
@param aAllowedQuality One of the VGImageQuality flags
|
sl@0
|
3749 |
|
sl@0
|
3750 |
@return A VGImage handle if the image was created successfully, VG_INVALID_HANDLE otherwise
|
sl@0
|
3751 |
*/
|
sl@0
|
3752 |
VGImage CVgEngine::DoVgCreateImage(VGImageFormat aFormat, VGint aWidth, VGint aHeight, VGbitfield aAllowedQuality)
|
sl@0
|
3753 |
{
|
sl@0
|
3754 |
const TInt oldVgError = CDirectGdiDriverImpl::GetVgError();
|
sl@0
|
3755 |
VGImage imageRet = vgCreateImage(aFormat, aWidth, aHeight, aAllowedQuality);
|
sl@0
|
3756 |
|
sl@0
|
3757 |
if (imageRet == VG_INVALID_HANDLE)
|
sl@0
|
3758 |
{
|
sl@0
|
3759 |
// If the new error is anything other than KErrNoMemory, there is nothing that can be done.
|
sl@0
|
3760 |
TInt newVgError = CDirectGdiDriverImpl::GetVgError();
|
sl@0
|
3761 |
if (newVgError != KErrNoMemory)
|
sl@0
|
3762 |
{
|
sl@0
|
3763 |
iDriver.SetError(oldVgError != KErrNone ? oldVgError : newVgError);
|
sl@0
|
3764 |
return imageRet;
|
sl@0
|
3765 |
}
|
sl@0
|
3766 |
|
sl@0
|
3767 |
// From here on, we are assuming any failure to create the image is due to OOM.
|
sl@0
|
3768 |
if (iDriver.VgImageCache())
|
sl@0
|
3769 |
{
|
sl@0
|
3770 |
// Delete all the images that are currently in the cache then try and create the image again
|
sl@0
|
3771 |
iDriver.VgImageCache()->ResetCache();
|
sl@0
|
3772 |
imageRet = vgCreateImage(aFormat, aWidth, aHeight, aAllowedQuality);
|
sl@0
|
3773 |
}
|
sl@0
|
3774 |
if ((imageRet == VG_INVALID_HANDLE) && iFontGlyphImageStorage)
|
sl@0
|
3775 |
{
|
sl@0
|
3776 |
// Clear the glyph cache as well then try and create the image again
|
sl@0
|
3777 |
iFontGlyphImageStorage->CleanGlyphImageCache();
|
sl@0
|
3778 |
imageRet = vgCreateImage(aFormat, aWidth, aHeight, aAllowedQuality);
|
sl@0
|
3779 |
}
|
sl@0
|
3780 |
if ((imageRet == VG_INVALID_HANDLE))
|
sl@0
|
3781 |
{
|
sl@0
|
3782 |
// Finally, force completion of any outstanding drawing, may free any VGImages marked for deletion.
|
sl@0
|
3783 |
// Empty the current OpenVG error state before calling Finish(), as Finish() may call SetError(),
|
sl@0
|
3784 |
// and could prematurely set the driver error state to KErrNoMemory.
|
sl@0
|
3785 |
//coverity[check_return]
|
sl@0
|
3786 |
//coverity[unchecked_value]
|
sl@0
|
3787 |
vgGetError();
|
sl@0
|
3788 |
iDriver.Finish();
|
sl@0
|
3789 |
imageRet = vgCreateImage(aFormat, aWidth, aHeight, aAllowedQuality);
|
sl@0
|
3790 |
}
|
sl@0
|
3791 |
|
sl@0
|
3792 |
// If the above worked, empty any OpenVG error state set by any failed attempts to create the image.
|
sl@0
|
3793 |
if (imageRet != VG_INVALID_HANDLE)
|
sl@0
|
3794 |
{
|
sl@0
|
3795 |
//coverity[check_return]
|
sl@0
|
3796 |
//coverity[unchecked_value]
|
sl@0
|
3797 |
vgGetError();
|
sl@0
|
3798 |
}
|
sl@0
|
3799 |
}
|
sl@0
|
3800 |
|
sl@0
|
3801 |
// Reset the error code to the original VG error code. If oldVgError is KErrNone,
|
sl@0
|
3802 |
// SetError() will use the current OpenVG error state.
|
sl@0
|
3803 |
iDriver.SetError(oldVgError);
|
sl@0
|
3804 |
|
sl@0
|
3805 |
return imageRet;
|
sl@0
|
3806 |
}
|
sl@0
|
3807 |
|
sl@0
|
3808 |
/**
|
sl@0
|
3809 |
Helper method for setting the colour property of a VGPaint object from a TRgb structure.
|
sl@0
|
3810 |
|
sl@0
|
3811 |
@param aPaint The VGPaint object to change the colour property of.
|
sl@0
|
3812 |
@param aColor The colour to set the paint to.
|
sl@0
|
3813 |
*/
|
sl@0
|
3814 |
void CVgEngine::SetVgPaintColor(VGPaint& aPaint, const TRgb& aColor)
|
sl@0
|
3815 |
{
|
sl@0
|
3816 |
// Need to swap from internal ARGB to RGBA for OpenVG.
|
sl@0
|
3817 |
const TUint argb = aColor.Internal();
|
sl@0
|
3818 |
const VGuint rgba = ((argb & 0xFFFFFF) << 8) + ((argb & 0xFF000000) >> 24);
|
sl@0
|
3819 |
vgSetColor(aPaint, rgba);
|
sl@0
|
3820 |
}
|