--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/javauis/lcdui_akn/lcdui/src/CMIDCanvas.cpp Wed Sep 01 12:33:18 2010 +0100
@@ -0,0 +1,5294 @@
+/*
+* Copyright (c) 2003-2009 Nokia Corporation and/or its subsidiary(-ies).
+* All rights reserved.
+* This component and the accompanying materials are made available
+* under the terms of "Eclipse Public License v1.0"
+* which accompanies this distribution, and is available
+* at the URL "http://www.eclipse.org/legal/epl-v10.html".
+*
+* Initial Contributors:
+* Nokia Corporation - initial contribution.
+*
+* Contributors:
+*
+* Description: CMIDCanvas - Implements the native part of the Canvas class.
+*
+*/
+
+// Using auto_ptr
+#include <memory>
+
+// API used for getting the layout for the network indicator bitmap and for
+// retrieving info if pen is enabled (in CMIDCanvas::HandlePointerEventL
+// function).
+#include <AknUtils.h>
+
+// Using Layout_Meta_Data::IsLandscapeOrientation()
+#include <layoutmetadata.cdl.h>
+
+
+// Using CRepository class used in CMIDCanvas::IsNetworkIndicatorEnabledL
+// function.
+#include <centralrepository.h>
+#ifdef RD_JAVA_NGA_ENABLED
+#include <logger.h>
+#include <e32cmn.h>
+#include <EGL/egl.h>
+#include <GLES/gl.h>
+#endif // RD_JAVA_NGA_ENABLED
+
+
+// Using debug macros.
+#include <j2me/jdebug.h>
+
+// OMJ storage
+#include <securitystoragedatadefs.h>
+#include <javastorageentry.h>
+#include <javastorage.h>
+#include <javastoragenames.h>
+#include <javauid.h>
+#include <javasymbianoslayer.h>
+#ifdef RD_JAVA_S60_RELEASE_9_2
+// Used with partial VKB
+#include <AknPriv.hrh>
+#endif // RD_JAVA_S60_RELEASE_9_2
+
+#include "javaoslayer.h"
+
+// Using constants for S60 LCDUI Plugin internal keys.
+#include "S60LCDUIInternalCRKeys.h"
+
+#include "CMIDCanvas.h"
+
+// Using CMIDUIManager for iKeyDecoder and iScaler initialization.
+#include "CMIDUIManager.h"
+
+// Using CMIDScaler as member iScaler.
+#include "CMIDScaler.h"
+
+// Using CMIDKeyDecoder as member iKeyDecoder.
+#include "CMIDKeyDecoder.h"
+
+// Using CMIDNetworkIndicator as member iNetworkIndicator.
+#include "CMIDNetworkIndicator.h"
+
+// Using CMIDCallIndicator as member iCallIndicator.
+#include "CMIDCallIndicator.h"
+
+// Using CMIDRemConObserver as memeber iRemConObserver.
+#include "CMIDRemConObserver.h"
+
+
+#ifdef RD_TACTILE_FEEDBACK
+// Using CMIDTactileFeedbackExtension as member iTactileFeedback.
+#include "CMIDTactileFeedbackExtension.h"
+#endif // RD_TACTILE_FEEDBACK
+
+#include "MMIDCustomComponent.h"
+
+// Using CoreUiAvkonLcdui for the splash screen
+#include "coreuiavkonlcdui.h"
+
+#ifdef DEFER_BITBLT
+const TInt KEstCyclesPerPixel = 32;
+#endif // DEFER_BITBLT
+
+const TInt KAllowedTimeBetweenDragEvents = 50000; // 50ms
+
+// Used with component controls
+const TInt KComponentMainControl = 0;
+const TInt KComponentFocusedNone = -1;
+
+// Using enumeration TFocusState.
+#include "MMIDTextEditor.h"
+
+#ifdef RD_JAVA_NGA_ENABLED
+// Max dimension for openGL texture, must be power of 2
+const TInt KMaxBlitSize = 256;
+const TInt KTexturesCount = 1;
+const TInt KBytesPerPixel = 4;
+const TInt KPhoneScreen = 0;
+// The color that is used to clear the framebuffer when
+// mixing 3D & 2D rendering
+#define KTransparentClearColor TRgb(0x000000, 0x0)
+#define KOpaqueClearColor TRgb(0xFFFFFF, 0xFF)
+#define KOpaqueBlackColor TRgb(0x000000, 255)
+
+#ifdef _DEBUG
+#define ASSERT_GL() AssertGL()
+#else
+#define ASSERT_GL()
+#endif
+
+#endif // RD_JAVA_NGA_ENABLED
+
+#define KZeroSize TSize()
+
+// ---------------------------------------------------------------------------
+// TBitBltData
+// BitBlt buffer data datatype.
+// ---------------------------------------------------------------------------
+//
+struct TBitBltData
+{
+ TRect iRect;
+};
+
+// ---------------------------------------------------------------------------
+// TLcduiEvent
+// ---------------------------------------------------------------------------
+//
+enum TLcduiEvent
+{
+ EFixUIOrientation,
+ EUnFixUIOrientation,
+ EVideoAdded
+};
+
+// ======== LOCAL FUNCTIONS ========
+
+// ---------------------------------------------------------------------------
+// BitBltData
+// Get BitBlt buffer data from buffered operation passed to buffer processor.
+// Used in CMIDCanvas::ProcessL function.
+// ---------------------------------------------------------------------------
+//
+inline const TBitBltData& BitBltData(const TMIDBufferOp* aOp)
+{
+ ASSERT(aOp->Size() >= TInt(1 + (
+ sizeof(TBitBltData) / sizeof(TMIDBufferOp))));
+
+ return *static_cast< const TBitBltData* >(aOp->Data());
+}
+
+#ifdef RD_JAVA_NGA_ENABLED
+// ---------------------------------------------------------------------------
+// IsDownScaling
+// Check if downscaling in use.
+// @param aSourceSize Source rect size.
+// @param aDestRect Destination rect.
+// ---------------------------------------------------------------------------
+//
+TBool CMIDCanvas::IsDownScaling(const TSize& aSourceSize, const TRect& aDestRect,TBool aM3GContent) const
+{
+ // if m3G is drawing then downscaling is turn off
+ // Send event in case of the M3G draw.
+ if (iM3GContent != iPrevM3GContent)
+ {
+ PostEvent(EM3GDraw, iM3GContent, 0);
+ }
+ iPrevM3GContent=iM3GContent;
+ if (aM3GContent)
+ {
+ return EFalse;
+ }
+ return (aSourceSize.iWidth > aDestRect.Width() ||
+ aSourceSize.iHeight > aDestRect.Height());
+}
+#else
+// ---------------------------------------------------------------------------
+// IsDownScaling
+// Check if downscaling in use.
+// @param aSourceSize Source rect size.
+// @param aDestRect Destination rect.
+// ---------------------------------------------------------------------------
+TBool CMIDCanvas::IsDownScaling(const TSize& aSourceSize, const TRect& aDestRect) const
+{
+ return (aSourceSize.iWidth > aDestRect.Width() ||
+ aSourceSize.iHeight > aDestRect.Height());
+}
+
+#endif //RD_JAVA_NGA_ENABLED
+// ======== MEMBER FUNCTIONS ========
+
+// ---------------------------------------------------------------------------
+// CMIDCanvas::NewL
+// Two-phased constructor. Use this method to create a CMIDCanvas instance.
+// ---------------------------------------------------------------------------
+//
+CMIDCanvas* CMIDCanvas::NewL(
+ MMIDEnv& aEnv,
+ CCoeControl& aWindow,
+ MMIDComponent::TType aComponentType,
+ TBool aUpdateRequired)
+{
+ CMIDCanvas* self = new(ELeave) CMIDCanvas(aEnv,
+ aComponentType,
+ aUpdateRequired);
+
+ CleanupStack::PushL(self);
+ self->ConstructL(aWindow);
+ CleanupStack::Pop(self);
+
+ return self;
+}
+
+
+// ---------------------------------------------------------------------------
+// CMIDCanvas::~CMIDCanvas
+// Destructor.
+// ---------------------------------------------------------------------------
+//
+CMIDCanvas::~CMIDCanvas()
+{
+ DEBUG("+ CMIDCanvas::~CMIDCanvas");
+
+ // Notify custom components that this container is disposing.
+ TInt customCount = iCustomComponents.Count();
+
+ for (TInt i = 0; i < customCount; i++)
+ {
+ iCustomComponents[i]->CustomComponentContainerDisposing();
+ }
+
+ // Close the array. Objects are not owned.
+ iCustomComponents.Close();
+
+ // Inform all listeners
+ TInt contentsCount(iDirectContents.Count());
+
+ for (TInt j = 0; j < contentsCount; j++)
+ {
+ iDirectContents[j]->MdcContainerDestroyed();
+ }
+
+ iDirectContents.Reset();
+
+ // Unregister the component from the observer
+ // if it were previously registered from MdcAddContent.
+ iEnv.ToLcduiObserver().UnregisterControl(*this);
+
+#ifdef CANVAS_DIRECT_ACCESS
+ StopDirectAccess();
+ delete iDirectAccess;
+#endif // CANVAS_DIRECT_ACCESS
+
+ // Network indicator
+ if (iNetworkIndicator)
+ {
+ iNetworkIndicator->Close(); // Use cancel here.
+ delete iNetworkIndicator;
+ }
+
+ // Call indicator
+ if (iCallIndicator)
+ {
+ iCallIndicator->Cancel();
+ delete iCallIndicator;
+ }
+
+ // Canvas removes itself from the CMIDRemConObserver.
+ ASSERT(iKeyDecoder);
+
+ if (iRemConObserver && iKeyDecoder->MediaKeysEnabled())
+ {
+ iRemConObserver->RemoveMediaKeysListener(this);
+ }
+
+ if (iDisplayable)
+ {
+ if (iScaler)
+ {
+ iDisplayable->GetUIManager()->CloseScaler(iScaler);
+ }
+
+ // Displayable is notified about content control deletion.
+ iDisplayable->NotifyContentDestroyed();
+ }
+
+#ifdef CANVAS_DOUBLE_BUFFER
+ if (iFrameBuffer)
+ {
+ iEnv.ReleaseCanvasFrameBuffer((*this), iFrameBuffer);
+ iFrameBuffer = NULL;
+ }
+
+ delete iFrameContext;
+ iFrameContext = NULL;
+ delete iFrameDevice;
+ iFrameDevice = NULL;
+#endif // CANVAS_DOUBLE_BUFFER
+
+#ifdef RD_TACTILE_FEEDBACK
+ delete iTactileFeedback;
+#endif // RD_TACTILE_FEEDBACK
+
+ if (iPointerEventSuppressor)
+ {
+ delete iPointerEventSuppressor;
+ iPointerEventSuppressor = NULL;
+ }
+
+#ifdef RD_JAVA_NGA_ENABLED
+ CloseEgl(EFalse);
+ DisposePixelSource();
+ delete[] iTexturePixels;
+ delete[] iVertexArray;
+ delete[] iTriangleStrip;
+#endif // RD_JAVA_NGA_ENABLED
+ DEBUG("- CMIDCanvas::~CMIDCanvas");
+}
+
+
+// ---------------------------------------------------------------------------
+// CMIDCanvas::FullScreen
+// Set fullscreen mode on/off.
+// ---------------------------------------------------------------------------
+//
+void CMIDCanvas::FullScreen(TBool aFullScreen)
+{
+ DEBUG_INT("CMIDCanvas::FullScreen(%d) ++--", aFullScreen);
+ if (iFullScreen != aFullScreen)
+ {
+ iFullScreen = aFullScreen;
+ // We have to inform all components on this Canvas.
+ if (iCustomComponents.Count() > 0)
+ {
+ for (int i = 0; i < iCustomComponents.Count(); i++)
+ {
+ iCustomComponents[i]->HandleFullscreenModeChange();
+ }
+ }
+ }
+}
+
+
+// ---------------------------------------------------------------------------
+// CMIDCanvas::IsScalingOn
+// Tells whether scaling is on or off.
+// ---------------------------------------------------------------------------
+//
+TBool CMIDCanvas::IsScalingOn()
+{
+ return iScalingOn;
+}
+
+
+// ---------------------------------------------------------------------------
+// CMIDCanvas::SelectionKeyCompatibility
+// Tells whether application attribute
+// Nokia-MIDlet-S60-Selection-Key-Compatibility is set true or not.
+// ---------------------------------------------------------------------------
+//
+TBool CMIDCanvas::SelectionKeyCompatibility()
+{
+ return iS60SelectionKeyCompatibility;
+}
+
+// ---------------------------------------------------------------------------
+// CMIDCanvas::CountComponentControls
+// (other items are commented in the header file)
+// ---------------------------------------------------------------------------
+//
+TInt CMIDCanvas::CountComponentControls() const
+{
+ return iCustomComponentsControlCount;
+}
+
+// ---------------------------------------------------------------------------
+// CMIDCanvas::ComponentControl
+// (other items are commented in the header file)
+// ---------------------------------------------------------------------------
+//
+CCoeControl* CMIDCanvas::ComponentControl(TInt aIndex) const
+{
+ TInt index = 0;
+
+ TInt count = iCustomComponents.Count();
+
+ for (int i = 0; i < count; i++)
+ {
+ TInt compoundCount =
+ iCustomComponents[i]->CustomComponentControlCount();
+
+ for (int j = 0; j < compoundCount; j++)
+ {
+ if (index == aIndex)
+ {
+ return iCustomComponents[i]->CustomComponentControl(j);
+ }
+
+ index++;
+ }
+ }
+
+ return NULL;
+}
+
+// ---------------------------------------------------------------------------
+// CMIDCanvas::SetFocusedComponent
+// (other items are commented in the header file)
+// ---------------------------------------------------------------------------
+//
+void CMIDCanvas::SetFocusedComponent(MMIDCustomComponent* aComponent)
+{
+ if (!aComponent)
+ {
+ iFocusedComponent = KComponentFocusedNone;
+ iPressedComponent = NULL;
+ }
+ else
+ {
+ TInt count = iCustomComponents.Count();
+ TInt index = iCustomComponents.Find(aComponent);
+ if ((index != KErrNotFound) && (iFocusedComponent != index))
+ {
+ iFocusedComponent = index;
+ }
+ }
+}
+
+// ---------------------------------------------------------------------------
+// From class CCoeControl.
+// CMIDCanvas::OfferKeyEventL
+// Process a key event. We ask the java environment to translate the key event
+// and we send it java side only if the translation allows it. The translation
+// is controlled by CMIDKeyDecoder via its interface to the java environment.
+// CBA keys are special. We only try and send them java side if we are full
+// screen and have no commands nor CommandListener, as stated in the specs.
+// Otherwise - if we are full screen with at least one command and
+// CommandListener we display the options menu or if we are not full screen
+// we simply return so that the CBA will process the key event and display the
+// options menu if needed. Note that in this context MSK is considered to be a
+// softkey, it must not be delivered as a key event to the Java side.
+// ---------------------------------------------------------------------------
+//
+TKeyResponse CMIDCanvas::OfferKeyEventL(
+ const TKeyEvent& aEvent,
+ TEventCode aType)
+{
+ DEBUG("+ CMIDCanvas::OfferKeyEventL");
+
+ DEBUG_INT(
+ "+ CMIDCanvas::OfferKeyEventL - received TKeyEvent: iCode = %d",
+ aEvent.iCode);
+
+ DEBUG_INT(
+ "+ CMIDCanvas::OfferKeyEventL - received TKeyEvent: iModifiers = %d",
+ aEvent.iModifiers);
+
+ DEBUG_INT(
+ "+ CMIDCanvas::OfferKeyEventL - received TKeyEvent: iRepeats = %d",
+ aEvent.iRepeats);
+
+ DEBUG_INT(
+ "+ CMIDCanvas::OfferKeyEventL - received TKeyEvent: iScanCode = %d",
+ aEvent.iScanCode);
+
+ TKeyResponse response = EKeyWasNotConsumed;
+
+ if ((iFocusedComponent != KComponentFocusedNone) &&
+ (iFocusedComponent < iCustomComponents.Count()) &&
+ (iCustomComponents[iFocusedComponent]->
+ CustomComponentControl(KComponentMainControl)->IsVisible()))
+ {
+ // Traversal check
+ if ((aType == EEventKeyDown) &&
+ (((aEvent.iCode == EKeyUpArrow) ||
+ (aEvent.iCode == EKeyDownArrow)) ||
+ ((aEvent.iScanCode == EStdKeyUpArrow) ||
+ (aEvent.iScanCode == EStdKeyDownArrow))))
+ {
+ // Traversing is not allowed when editing with VKB
+ if (iDisplayable && !iDisplayable->IsVKBOnScreen())
+ {
+ iCustomComponents[iFocusedComponent]->TraverseL(aEvent);
+ response = EKeyWasConsumed;
+ }
+ }
+
+ if (response != EKeyWasConsumed)
+ {
+ // Passing the keyevent to focused component
+ response = iCustomComponents[iFocusedComponent]->
+ CustomComponentControl(KComponentMainControl)->
+ OfferKeyEventL(aEvent, aType);
+ }
+ }
+
+ // Check if the key event was consumed by the child control.
+ if (response == EKeyWasConsumed)
+ {
+ DEBUG_INT(
+ "CMIDCanvas::OfferKeyEventL - key consumed by custom control: %d",
+ iFocusedComponent);
+
+ // Return response.
+ return response;
+ }
+
+
+ DEBUG("CMIDCanvas::OfferKeyEventL, \
+event not consumed by any custom component");
+
+ TInt keycode = aEvent.iScanCode;
+
+ // If there is additional selection key mapping (e.g. to Enter key) and
+ // scan code of delivered key is this additional key, flag is set to ETrue
+ TBool additionalSelectionKey =
+ (iKeyDecoder->AdditionalSelectionKeyMappingCode() != 0) &&
+ (keycode == iKeyDecoder->AdditionalSelectionKeyMappingCode());
+
+ if (keycode == EStdKeyDevice0 ||
+ keycode == EStdKeyDevice1 ||
+ keycode == EStdKeyDevice3 ||
+ additionalSelectionKey)
+ {
+ // CBA keys
+
+ // In S60SelectionKeyCompatibility mode turned on and MSK pressed
+ // don't map any command, send key event to Java.
+ if (iS60SelectionKeyCompatibility &&
+ (keycode == EStdKeyDevice3 || additionalSelectionKey))
+ {
+ SendKeyEventToJavaSideL(aEvent, aType);
+ DEBUG("- CMIDCanvas::OfferKeyEventL = key was not consumed");
+ return EKeyWasNotConsumed;
+ }
+
+ if (iDisplayable && !iDisplayable->IsFullScreenMode())
+ {
+ // Pressing selection key is handled in CEikCba so that command
+ // mapped to selection (MSK) key is invoked from there.
+ // But CEikCba doesn't handle additional selection key
+ // mapping, so it is done here.
+ if (additionalSelectionKey && aType == EEventKey)
+ {
+ iDisplayable->ProcessMSKCommandL();
+ }
+ else if (aType == EEventKeyDown && keycode == EStdKeyDevice3)
+ {
+ CMIDMenuHandler* menuHandler = iDisplayable->MenuHandler();
+
+ // If there is no additional selection key mapping
+ // and scan code of delivered key is MSK then show menu,
+ // used when ENavigationKeysFire or MSK were pressed
+ if (iDisplayable->NumCommandsForOkOptionsMenu() == 0
+ && menuHandler)
+ {
+ menuHandler->ProcessCommandL(EAknSoftkeyEmpty);
+ }
+ else if (iDisplayable->NumCommandsForOkOptionsMenu() > 0
+ && menuHandler)
+ {
+ menuHandler->ProcessCommandL(EAknSoftkeyContextOptions);
+ }
+ }
+
+ // Not a full screen mode, return so that the CBA gets the event.
+ DEBUG("- CMIDCanvas::OfferKeyEventL = key was not consumed");
+ return EKeyWasNotConsumed;
+ }
+
+ if (iDisplayable && iDisplayable->IsFullScreenMode() &&
+ iDisplayable->IsCommandListenerSet() &&
+ iDisplayable->CommandCount() > 0)
+ {
+ CMIDMenuHandler* menuHandler = iDisplayable->MenuHandler();
+
+ // If full screen and command listener is set and there are
+ // Commands added to Canvas, then options menu is displayed.
+ if (aType == EEventKey && menuHandler)
+ {
+ menuHandler->ShowMenuL(
+ CMIDMenuHandler::EOptionsMenu);
+ }
+
+ DEBUG("- CMIDCanvas::OfferKeyEventL = key was not consumed");
+ return EKeyWasNotConsumed;
+ }
+ }
+
+ SendKeyEventToJavaSideL(aEvent, aType);
+
+ DEBUG("- CMIDCanvas::OfferKeyEventL = key was not consumed");
+ return EKeyWasNotConsumed;
+}
+
+
+// ---------------------------------------------------------------------------
+// From class MMIDComponent.
+// CMIDCanvas::Dispose
+// Invoked by the framework to clean up resources.
+// ---------------------------------------------------------------------------
+//
+void CMIDCanvas::Dispose()
+{
+ delete this;
+}
+
+
+// ---------------------------------------------------------------------------
+// From class MMIDComponent.
+// CMIDCanvas::Type
+// Always returns the type MMIDComponent::ECanvas as component type.
+// ---------------------------------------------------------------------------
+//
+MMIDComponent::TType CMIDCanvas::Type() const
+{
+ return MMIDComponent::ECanvas;
+}
+
+
+// ---------------------------------------------------------------------------
+// From class MMIDComponent.
+// CMIDCanvas::Processor
+// Always returns this-> as buffer processor associated with this component.
+// ---------------------------------------------------------------------------
+//
+MMIDBufferProcessor* CMIDCanvas::Processor()
+{
+ return this;
+}
+
+
+// ---------------------------------------------------------------------------
+// From class MMIDCanvas.
+// CMIDCanvas::Control
+// Returns a reference to the CCoeControl corresponding to this canvas.
+// ---------------------------------------------------------------------------
+//
+CCoeControl& CMIDCanvas::Control()
+{
+ return *this;
+}
+
+
+// ---------------------------------------------------------------------------
+// From class MMIDCanvas.
+// CMIDCanvas::FrameBuffer
+// Returns a pointer to the frame buffer. If double buffering is supported
+// this method must not return NULL. There is no ownership transfer.
+// ---------------------------------------------------------------------------
+//
+CFbsBitmap* CMIDCanvas::FrameBuffer() const
+{
+#ifdef CANVAS_DOUBLE_BUFFER
+ return iFrameBuffer;
+#else
+ return NULL;
+#endif // CANVAS_DOUBLE_BUFFER
+}
+
+
+// ---------------------------------------------------------------------------
+// From class MMIDCanvas.
+// CMIDCanvas::ContentSize
+// Returns the size of the canvas content.
+// ---------------------------------------------------------------------------
+//
+TSize CMIDCanvas::ContentSize() const
+{
+ return iContentSize;
+}
+
+
+// ---------------------------------------------------------------------------
+// From class MMIDCanvas.
+// CMIDCanvas::PauseDirectAccess
+// Disables temporarily direct screen access.
+// This method should be called to disable direct screen access when a popup
+// menu is about to be displayed. This is a workaround for menu's failing to
+// correctly draw their shadows on Techview and other UI's that have floating
+// menubars.
+// ---------------------------------------------------------------------------
+//
+void CMIDCanvas::PauseDirectAccess()
+{
+#ifdef CANVAS_DIRECT_ACCESS
+ StopDirectAccess();
+#endif // CANVAS_DIRECT_ACCESS
+
+ iFlags |= EDirectPaused;
+}
+
+
+// ---------------------------------------------------------------------------
+// From class MMIDCanvas.
+// CMIDCanvas::ResumeDirectAccess
+// Re-enables direct screen access.
+// To be called when the menu has disappeared.
+// ---------------------------------------------------------------------------
+//
+void CMIDCanvas::ResumeDirectAccess()
+{
+ iFlags &= ~EDirectPaused;
+
+#ifdef CANVAS_DIRECT_ACCESS
+ StartDirectAccess();
+#endif // CANVAS_DIRECT_ACCESS
+}
+
+
+// ---------------------------------------------------------------------------
+// From class MMIDCanvas.
+// CMIDCanvas::SuppressKeys
+// Switch off key event posting. Game keys will still be tracked, but
+// keyPressed()/keyReleased() callbacks will not be called.
+// ---------------------------------------------------------------------------
+//
+void CMIDCanvas::SuppressKeys()
+{
+ iFlags &= ~EPostKeyEvents;
+ iEnv.ResetKeys();
+}
+
+
+// ---------------------------------------------------------------------------
+// From class MMIDCanvas.
+// CMIDCanvas::GameActions
+// Returns the latched state of the game action keys.
+// ---------------------------------------------------------------------------
+//
+TUint32 CMIDCanvas::GameActions()
+{
+ TUint32 latch = (iGameKeyLatch | iGameKeyState);
+ iGameKeyLatch = 0;
+ return latch;
+}
+
+
+// ---------------------------------------------------------------------------
+// From class MMIDCanvas.
+// CMIDCanvas::DirectContainer
+// Returns a direct container on which video can be rendered.
+// ---------------------------------------------------------------------------
+//
+MDirectContainer& CMIDCanvas::DirectContainer()
+{
+ return *this;
+}
+
+
+// ---------------------------------------------------------------------------
+// From class MMIDCanvas.
+// CMIDCanvas::DrawBackground
+// Draw a background image.
+// ---------------------------------------------------------------------------
+//
+void CMIDCanvas::DrawBackground(
+ CBitmapContext& aGc, const TPoint& aPosition, const TSize& aSize)
+{
+ MAknsSkinInstance* skin = AknsUtils::SkinInstance();
+ MAknsControlContext* cc = iDisplayable->BackGroundControlContext();
+
+ AknsDrawUtils::DrawBackground(
+ skin, cc, NULL, aGc, aPosition, aSize, KAknsDrawParamDefault);
+}
+
+
+// ---------------------------------------------------------------------------
+// From class MMIDCanvas.
+// CMIDCanvas::IsGameCanvas
+// Returns the type of Canvas object.
+// ---------------------------------------------------------------------------
+//
+TBool CMIDCanvas::IsGameCanvas() const
+{
+ return iIsGameCanvas;
+}
+
+
+// ---------------------------------------------------------------------------
+// From class MMIDCanvas.
+// Gets the Network indicator location for fullscreen
+// If not in fullscreenmode EFalse is returned
+// ---------------------------------------------------------------------------
+//
+TBool CMIDCanvas::NetworkIndicatorLocation(
+ TPoint& aPosition,
+ TSize& aSize) const
+{
+ if (iFullScreen)
+ {
+ if (iNetworkIndicator)
+ {
+ iNetworkIndicator->GetLocation(aPosition, aSize);
+ return ETrue;
+ }
+ }
+ return EFalse;
+}
+
+
+#ifdef RD_TACTILE_FEEDBACK
+// ---------------------------------------------------------------------------
+// From MMIDCanvas.
+// CMIDCanvas::TactileFeedbackComponent
+// Retutrns this as tactile feedback component.
+// ---------------------------------------------------------------------------
+//
+MMIDTactileFeedbackComponent* CMIDCanvas::TactileFeedbackComponent()
+{
+ return this;
+}
+#endif // RD_TACTILE_FEEDBACK
+
+
+// ---------------------------------------------------------------------------
+// From class MMIDCanvas.
+// ---------------------------------------------------------------------------
+//
+TBool CMIDCanvas::ReadyToBlit() const
+{
+ return iFirstPaintState != EFirstPaintNeverOccurred;
+}
+
+#ifdef RD_JAVA_NGA_ENABLED
+
+// ---------------------------------------------------------------------------
+// From class MMIDBufferProcessor.
+// CMIDCanvas::ProcessL
+// Process a block of commands, updating read pointer as you go.
+// ---------------------------------------------------------------------------
+//
+TBool CMIDCanvas::ProcessL(
+ const TMIDBufferOp*& aRead,
+ const TMIDBufferOp* aEnd,
+ TInt& /* aCycles */,
+ java::util::Monitor* aMonitor)
+{
+
+ if (!iForeground && iFirstPaintState == EFirstPaintNeverOccurred)
+ {
+ ASSERT(!iAlfMonitor);
+ aRead = aEnd;
+ return EFalse;
+ }
+
+ switch (aRead->OpCode())
+ {
+ case EDrwOpcM3GContentStart:
+ {
+ // EGL surface is created if canvas window is currently visible
+ // even if MIDlet would be on background.
+ if (!iM3GContent &&
+ i3DAccelerated &&
+ iDirectContents.Count() == 0 &&
+ IsWindowVisible())
+ {
+ DEBUG("CMIDCanvas::ProcessL - M3G content start");
+ iM3GContent = ETrue;
+ iM3GStart = ETrue;
+ PostEvent(EM3GDraw, iM3GContent, 0);
+ // First time when M3G content is drawn =>
+ // switch to EGL surface drawing.
+ // Pixel source must be disposed first.
+ DisposePixelSource();
+ OpenEglL();
+
+ // if we are scaling with m3g and HW acceleration
+ // create a pbuffer surface to be used with m3g rendering
+ if (iScalingOn && iFullScreen)
+ {
+ CreatePBufferSurfaceL();
+ }
+ // Draw the whole framebuffer content (as a texture) on top of
+ // the EGL window surface.
+ iUpperUpdateRect = TRect(Size());
+ UpdateEglContent();
+ }
+ }
+ break;
+ case EDrwOpcBitBltRect:
+ {
+ if (iFirstPaintState == EFirstPaintNeverOccurred)
+ {
+ iFirstPaintState = EFirstPaintInitiated;
+ }
+
+ const TBitBltData& data = BitBltData(aRead);
+ UpdateL(data.iRect);
+ }
+ break;
+ case EDrwOpcBitBlt:
+ {
+ if (iFirstPaintState == EFirstPaintNeverOccurred)
+ {
+ iFirstPaintState = EFirstPaintInitiated;
+ }
+
+ UpdateL(iViewRect);
+ }
+ break;
+ default:
+ User::Leave(KErrNotSupported);
+ break;
+ }
+
+ aRead += aRead->Size();
+ ASSERT(aRead == aEnd);
+
+ // iFrameReady tells if this is async operation.
+ // In async case CMIDBuffer waits until canvas
+ // gets callback from Alf.
+ // See CMIDBuffer.cpp and ProduceNewFrameL()
+ if (iFrameReady)
+ {
+ iAlfMonitor = aMonitor;
+ }
+ return iFrameReady;
+}
+
+#else // RD_JAVA_NGA_ENABLED
+
+// ---------------------------------------------------------------------------
+// From class MMIDBufferProcessor.
+// CMIDCanvas::ProcessL
+// Process a block of commands, updating read pointer as you go.
+// ---------------------------------------------------------------------------
+//
+TBool CMIDCanvas::ProcessL(
+ const TMIDBufferOp*& aRead,
+ const TMIDBufferOp* aEnd,
+ TInt& aCycles,
+ TRequestStatus* /* aStatus */)
+{
+ DEBUG("+ CMIDCanvas::ProcessL");
+
+#ifdef CANVAS_DOUBLE_BUFFER
+ while (aRead < aEnd)
+ {
+ switch (aRead->OpCode())
+ {
+ case EDrwOpcBitBlt:
+ {
+ TSize size = iFrameBuffer->SizeInPixels();
+
+#ifdef DEFER_BITBLT
+ aCycles -= BitBltCycles(size);
+
+ if (aCycles < 0)
+ {
+ return EFalse;
+ }
+#endif // DEFER_BITBLT
+
+ Update(TRect(size));
+ }
+ break;
+
+ case EDrwOpcBitBltRect:
+ {
+ const TBitBltData& data = BitBltData(aRead);
+ TRect rect = data.iRect;
+
+ // This is needed to avoid artifacting after orientation switch.
+ // While changing orientation, wrong rect was not updated.
+ if (iWndUpdate && (rect.Size() != iViewRect.Size())
+ && !iScalingOn)
+ {
+ break;
+ }
+
+ TRect frameRect(iFrameBuffer->SizeInPixels());
+
+ rect.Intersection(frameRect);
+
+#ifdef DEFER_BITBLT
+ aCycles -= BitBltCycles(rect.Size());
+
+ if (aCycles < 0)
+ {
+ return EFalse;
+ }
+#endif // DEFER_BITBLT
+
+ Update(rect);
+ }
+ break;
+ default:
+ User::Leave(KErrNotSupported);
+ break;
+ }
+
+ aRead += aRead->Size();
+ }
+#endif // CANVAS_DOUBLE_BUFFER
+
+ if (iFirstPaintState == EFirstPaintNeverOccurred)
+ {
+ if (iForeground)
+ {
+ // The canvas is current, therefore we can flush
+ // the graphics and take the start screen snapshot.
+ iFirstPaintState = EFirstPaintOccurred;
+ java::ui::CoreUiAvkonLcdui::getInstance().getJavaUiAppUi()->stopStartScreen();
+ }
+ else
+ {
+ // The window is not visible, the start screen snapshot
+ // will be taken when the canvas will be set current.
+ iFirstPaintState = EFirstPaintInitiated;
+ }
+ }
+
+ DEBUG("- CMIDCanvas::ProcessL");
+
+ return EFalse;
+}
+#endif // RD_JAVA_NGA_ENABLED
+
+
+// ---------------------------------------------------------------------------
+// From class MMIDBufferProcessor.
+// CMIDCanvas::AbortAsync
+// Does nothing.
+// ---------------------------------------------------------------------------
+//
+void CMIDCanvas::AbortAsync()
+{
+ // nop
+}
+
+
+#ifdef CANVAS_DIRECT_ACCESS
+// ---------------------------------------------------------------------------
+// From class MAbortDirectScreenAccess.
+// CMIDCanvas::AbortNow
+// This function is called by the window server when direct screen access
+// must stop (for example because a dialogue is moved in front of the area
+// where direct screen access is taking place).
+// ---------------------------------------------------------------------------
+//
+void CMIDCanvas::AbortNow(
+ RDirectScreenAccess::TTerminationReasons /* aReasons */)
+{
+ StopDirectAccess();
+}
+
+
+// ---------------------------------------------------------------------------
+// From class MDirectScreenAccess.
+// CMIDCanvas::Restart
+// This function is called by the window server as soon as direct screen
+// access can resume.
+// ---------------------------------------------------------------------------
+//
+void CMIDCanvas::Restart(
+ RDirectScreenAccess::TTerminationReasons /* aReasons */)
+{
+ StartDirectAccess();
+}
+#endif // CANVAS_DIRECT_ACCESS
+
+
+// ---------------------------------------------------------------------------
+// From class MDirectContainer.
+// CMIDCanvas::MdcAddContent
+// Set the content of this direct container.
+// ---------------------------------------------------------------------------
+//
+void CMIDCanvas::MdcAddContent(MDirectContent* aContent)
+{
+ TInt error = iDirectContents.Append(aContent);
+
+ __ASSERT_DEBUG(error == KErrNone, User::Invariant());
+
+ // Register this control to observer
+ // in order to provide possibility to call
+ // methods from another than LCDUI ES thread.
+ // Unregistration is done in destructor.
+#ifdef RD_JAVA_NGA_ENABLED
+ iEnv.ToLcduiObserver().RegisterControl(*this, this);
+#else
+ iEnv.ToLcduiObserver().RegisterControl(*this);
+#endif // RD_JAVA_NGA_ENABLED
+
+#ifdef RD_JAVA_NGA_ENABLED
+ if (iFirstPaintState != EFirstPaintOccurred &&
+ iDirectContents.Count() == 1)
+ {
+ // The first canvas paint using NGA might be interrupted
+ // by addition of the direct content.
+ // Invoking repaint event to restore the first paint.
+ TInt posPacked = (iViewRect.iTl.iX << 16) | (iViewRect.iTl.iY);
+ TSize size = iViewRect.Size();
+ TInt sizePacked = (size.iWidth << 16) | (size.iHeight);
+
+ PostEvent(EPaint, posPacked, sizePacked);
+ }
+
+ if (iDirectContents.Count() > 0)
+ {
+ iEnv.ToLcduiObserver().InvokeLcduiEvent(*this, EVideoAdded);
+ }
+#endif // RD_JAVA_NGA_ENABLED
+}
+
+
+// ---------------------------------------------------------------------------
+// From class MDirectContainer.
+// CMIDCanvas::MdcRemoveContent
+// Remove the content from this direct container. This will called when
+// the Player is closed.
+// ---------------------------------------------------------------------------
+//
+void CMIDCanvas::MdcRemoveContent(MDirectContent* aContent)
+{
+ TInt index = iDirectContents.Find(aContent);
+
+ if (index != KErrNotFound)
+ {
+ iDirectContents.Remove(index);
+ if (iDirectContents.Count() == 0)
+ {
+ iRestoreContentWhenUnfaded = EFalse;
+ }
+ }
+}
+
+
+// ---------------------------------------------------------------------------
+// From class MDirectContainer.
+// CMIDCanvas::MdcAddContentBounds
+// Adds a rectangle to be excluded from redrawing.
+// ---------------------------------------------------------------------------
+//
+void CMIDCanvas::MdcAddContentBounds(const TRect& aRect)
+{
+ if (iDisplayable)
+ {
+ iDisplayable->AddDirectContentArea(aRect);
+ }
+}
+
+
+// ---------------------------------------------------------------------------
+// From class MDirectContainer.
+// CMIDCanvas::MdcRemoveContentBounds
+// Removes a rectangle to be excluded from redrawing.
+// ---------------------------------------------------------------------------
+//
+void CMIDCanvas::MdcRemoveContentBounds(const TRect& aRect)
+{
+ if (iDisplayable)
+ {
+ iDisplayable->RemoveDirectContentArea(aRect);
+ }
+}
+
+
+// ---------------------------------------------------------------------------
+// From class MDirectContainer.
+// CMIDCanvas::MdcContainerWindowRect()
+// ---------------------------------------------------------------------------
+//
+TRect CMIDCanvas::MdcContainerWindowRect() const
+{
+ // CMIDCanvas has the size of the window always
+ return MdcContentBounds();
+}
+
+
+// ---------------------------------------------------------------------------
+// From class MDirectContainer.
+// CMIDCanvas::MdcContainerVisibility
+// Get the visiblity of this direct container.
+// ---------------------------------------------------------------------------
+//
+TBool CMIDCanvas::MdcContainerVisibility() const
+{
+ return iDisplayable->IsVisible();
+}
+
+
+// ---------------------------------------------------------------------------
+// From class MDirectContainer.
+// CMIDCanvas::MdcContentBounds
+// Get the bounds of the area that the content of this direct container can
+// occupy.
+// Return content rect in screen co-ordinates. Position is stored in
+// member variable because CCoeControl::PositionRelativeToScreen cannot
+// be called from another thread.
+// ---------------------------------------------------------------------------
+//
+TRect CMIDCanvas::MdcContentBounds() const
+{
+ return TRect(iPositionRelativeToScreen, Size());
+}
+
+
+// ---------------------------------------------------------------------------
+// From class MDirectContainer.
+// CMIDCanvas::MdcItemContentRect
+// Get the area on the Item on which content can be displayed.
+// This should only be called when the direct content is displayed on an Item,
+// so always panic if it is called on Canvas.
+// ---------------------------------------------------------------------------
+//
+void CMIDCanvas::MdcItemContentRect(
+ TRect& /* aContentRect */,
+ TRect& /* aScreenRect */) const
+{
+ __ASSERT_DEBUG(EFalse, User::Invariant());
+}
+
+
+// ---------------------------------------------------------------------------
+// From class MDirectContainer.
+// CMIDCanvas::MdcHandlePointerEventL
+// Allows a control created for direct container content display to pass on
+// pointer events.
+// Though this is the leaving function nothing can leave actually.
+// ---------------------------------------------------------------------------
+//
+void CMIDCanvas::MdcHandlePointerEventL(TPointerEvent& /* aPointerEvent */)
+{
+ __ASSERT_DEBUG(EFalse, User::Invariant());
+}
+
+
+// ---------------------------------------------------------------------------
+// From class MDirectContainer.
+// CMIDCanvas::MdcFlushContainer
+// Flush the direct container content.
+// ---------------------------------------------------------------------------
+//
+void CMIDCanvas::MdcFlushContainer(const TRect& aRect)
+{
+ // Flush the framebuffer on screen
+ iEnv.ToLcduiObserver().FlushControl(*this, aRect);
+}
+
+
+// ---------------------------------------------------------------------------
+// From class MDirectContainer.
+// CMIDCanvas::MdcGetDSAResources
+// Invokes callback aConsumer->MdcDSAResourcesCallback in LCDUI thread.
+// ---------------------------------------------------------------------------
+//
+void CMIDCanvas::MdcGetDSAResources(MUiEventConsumer& aConsumer)
+{
+ // May run in non-LCDUI ES thread
+ // Invoke the callback running in LCDUI ES thread
+ iEnv.ToLcduiObserver().InvokeDSAResourcesCallback(*this, aConsumer);
+}
+
+
+// ---------------------------------------------------------------------------
+// From class MDirectContainer.
+// CMIDCanvas::MdcGetUICallback
+// Invokes callback aConsumer->MdcUICallback in LCDUI thread.
+// ---------------------------------------------------------------------------
+//
+void CMIDCanvas::MdcGetUICallback(
+ MUiEventConsumer& aConsumer,
+ TInt aCallbackId)
+{
+ // May run in non-LCDUI ES thread
+ // Invoke the callback running in LCDUI ES thread
+ iEnv.ToLcduiObserver().InvokeUICallback(aConsumer, aCallbackId);
+}
+
+#ifdef RD_JAVA_NGA_ENABLED
+// ---------------------------------------------------------------------------
+// From class MDirectContainer.
+// CMIDCanvas::MdcNotifyContentAdded
+// Notification about added direct content, called in LCDUI thread.
+// Canvas needs to dispose pixel source before MMAPI adds video surface
+// to canvas window. Pixel source cannot be disposed in MdcAddContent
+// because it may be called in MMAPI thread.
+// ---------------------------------------------------------------------------
+//
+void CMIDCanvas::MdcNotifyContentAdded()
+{
+ // no implementation
+}
+#endif // RD_JAVA_NGA_ENABLED
+
+// ---------------------------------------------------------------------------
+// From class MDirectContainer.
+// CMIDCanvas::MdcFixUIOrientation(TBool aEnableFix)
+// ---------------------------------------------------------------------------
+//
+void CMIDCanvas::MdcFixUIOrientation(TBool aEnableFix)
+{
+ if (aEnableFix)
+ {
+ iEnv.ToLcduiObserver().InvokeLcduiEvent(*this, EFixUIOrientation);
+ }
+ else
+ {
+ iEnv.ToLcduiObserver().InvokeLcduiEvent(*this, EUnFixUIOrientation);
+ }
+}
+
+// ---------------------------------------------------------------------------
+// From class MMIDLcduiEventConsumer.
+// CMIDCanvas::HandleLcduiEvent(int aType)
+// ---------------------------------------------------------------------------
+//
+void CMIDCanvas::HandleLcduiEvent(int aType)
+{
+ if (!iDisplayable)
+ {
+ return;
+ }
+
+ switch (aType)
+ {
+ case EFixUIOrientation:
+ iDisplayable->FixOrientation();
+ break;
+ case EUnFixUIOrientation:
+ iDisplayable->ReleaseOrientation();
+ break;
+ case EVideoAdded:
+#ifdef RD_JAVA_NGA_ENABLED
+ DisposePixelSource();
+ CloseEgl(IsGameCanvas());
+#endif // RD_JAVA_NGA_ENABLED
+ break;
+ }
+}
+
+// ---------------------------------------------------------------------------
+// From class MMIDMediaKeysListener.
+// CMIDCanvas::HandleMediaKeyEvent
+// This method is called when a media key has been pressed.
+// ---------------------------------------------------------------------------
+//
+void CMIDCanvas::HandleMediaKeyEvent(TMIDKeyEvent& aKeyEvent)
+{
+ if (PostKeyEvents())
+ {
+ DEBUG_INT3(
+ "CMIDCanvas::HandleMediaKeyEvent - PostKeyEvent() - \
+JAVA code %d type %d repeats %d",
+ aKeyEvent.iKeyCode,
+ aKeyEvent.iEvents,
+ aKeyEvent.iRepeats);
+
+ iEnv.PostKeyEvent(*this, aKeyEvent);
+ }
+}
+
+
+#ifdef RD_TACTILE_FEEDBACK
+// ---------------------------------------------------------------------------
+// From class MMIDTactileFeedbackComponent.
+// CMIDCanvas::UpdateTactileFeedback
+// Update tactile feedback areas.
+// ---------------------------------------------------------------------------
+//
+void CMIDCanvas::UpdateTactileFeedback()
+{
+ TInt areaCount = iTactileFeedback->GetAreasCount();
+
+ for (TInt i = 0; i < areaCount; i++)
+ {
+ CMIDTactileFeedbackExtension::FeedbackArea* area =
+ iTactileFeedback->GetArea(i);
+
+ TRect physicalRect = area->rect;
+
+ iTactileFeedback->SetFeedbackArea(area->id,
+ physicalRect,
+ (TInt)area->style);
+ }
+}
+
+
+// ---------------------------------------------------------------------------
+// From class MMIDTactileFeedbackComponent.
+// CMIDCanvas::RegisterFeedbackArea
+// Register feedback area.
+// ---------------------------------------------------------------------------
+//
+void CMIDCanvas::RegisterFeedbackArea(TInt aId, TRect aRect, TInt aStyle)
+{
+ iTactileFeedback->RegisterFeedbackArea(aId, aRect, aStyle);
+}
+
+
+// ---------------------------------------------------------------------------
+// From class MMIDTactileFeedbackComponent.
+// CMIDCanvas::UnregisterFeedbackArea
+// Unregister feedback area.
+// ---------------------------------------------------------------------------
+//
+void CMIDCanvas::UnregisterFeedbackArea(TInt aId)
+{
+ iTactileFeedback->UnregisterFeedbackArea(aId);
+}
+
+
+// ---------------------------------------------------------------------------
+// From class MMIDTactileFeedbackComponent.
+// CMIDCanvas::UnregisterFeedbackForControl
+// Unregister feedback for the control.
+// ---------------------------------------------------------------------------
+//
+void CMIDCanvas::UnregisterFeedbackForControl()
+{
+ iTactileFeedback->UnregisterFeedbackForControl();
+}
+
+
+// ---------------------------------------------------------------------------
+// From class MMIDTactileFeedbackComponent.
+// CMIDCanvas::MoveAreaToFirstPriority
+// Move area to first priority.
+// ---------------------------------------------------------------------------
+//
+void CMIDCanvas::MoveAreaToFirstPriority(TInt aId)
+{
+ iTactileFeedback->MoveAreaToFirstPriority(aId);
+}
+#endif // RD_TACTILE_FEEDBACK
+
+// ---------------------------------------------------------------------------
+// CMIDCanvas::RegisterComponentL
+// Registers a new custom component to this container.
+// (other items are commented in the header file)
+// ---------------------------------------------------------------------------
+//
+void CMIDCanvas::RegisterComponentL(MMIDCustomComponent* aComponent)
+{
+ DEBUG("CMIDCanvas::RegisterComponentL +");
+
+ if (iCustomComponents.Find(aComponent) == KErrNotFound)
+ {
+ DEBUG("CMIDCanvas::RegisterComponentL, registering new");
+
+ iCustomComponents.AppendL(aComponent);
+
+ // Update custom components count in order to improve
+ // the performance when counting components
+ iCustomComponentsControlCount +=
+ aComponent->CustomComponentControlCount();
+
+ }
+
+ DEBUG("CMIDCanvas::RegisterComponentL -");
+}
+
+// ---------------------------------------------------------------------------
+// CMIDCanvas::UnregisterComponent
+// Unregisters an existing custom component from this container.
+// (other items are commented in the header file)
+// ---------------------------------------------------------------------------
+//
+void CMIDCanvas::UnregisterComponent(MMIDCustomComponent* aComponent)
+{
+ DEBUG("CMIDCanvas::UnregisterComponent +");
+
+ TInt index = iCustomComponents.Find(aComponent);
+
+ if (index != KErrNotFound)
+ {
+ // Update of iFocusedComponent index.
+ if (index < iFocusedComponent)
+ {
+ iFocusedComponent--;
+ }
+ else if (index == iFocusedComponent)
+ {
+ iFocusedComponent = KComponentFocusedNone;
+ }
+
+ if ((iPressedComponent) && (iPressedComponent == aComponent))
+ {
+ iPressedComponent = NULL;
+ }
+
+ iCustomComponents.Remove(index);
+ // Compress the array to keep the object indexes in order.
+ iCustomComponents.Compress();
+ // Update custom components count in order to improve
+ // the performance when counting components
+ iCustomComponentsControlCount -=
+ aComponent->CustomComponentControlCount();
+
+ // Redraw the whole canvas.
+ DrawDeferred();
+ }
+
+ DEBUG("CMIDCanvas::UnregisterComponent -");
+}
+
+// ---------------------------------------------------------------------------
+// CMIDCanvas::IsFullScreen
+// (other items are commented in the header file)
+// ---------------------------------------------------------------------------
+//
+TBool CMIDCanvas::IsFullScreen() const
+{
+ return iFullScreen;
+}
+
+#ifdef RD_JAVA_S60_RELEASE_9_2
+// ---------------------------------------------------------------------------
+// CMIDCanvas::GetDisplayable
+// (other items are commented in the header file)
+// ---------------------------------------------------------------------------
+//
+CMIDDisplayable* CMIDCanvas::GetDisplayable() const
+{
+ return iDisplayable;
+}
+#endif // RD_JAVA_S60_RELEASE_9_2
+
+// ---------------------------------------------------------------------------
+// CMIDCanvas::SetComponentIndexL
+// Changes the index of the specified custom component.
+// (other items are commented in the header file)
+// ---------------------------------------------------------------------------
+//
+void CMIDCanvas::SetComponentIndexL(
+ MMIDCustomComponent* aComponent,
+ TInt aNewIndex)
+{
+ DEBUG("CMIDCanvas::SetComponentIndexL +");
+
+ // Adjust the index if it is out of bounds.
+ TInt count = iCustomComponents.Count();
+ if (aNewIndex >= count)
+ {
+ aNewIndex = count - 1;
+ }
+
+ // The index must not be negative.
+ __ASSERT_DEBUG(aNewIndex >= 0, User::Invariant());
+
+ TInt index = iCustomComponents.Find(aComponent);
+
+ // Do not adjust the position if there is no need for it
+ // or if the component does not exist in the array.
+ if (index != KErrNotFound && index != aNewIndex)
+ {
+ // Update index of focused component
+
+ if (index == iFocusedComponent)
+ {
+ iFocusedComponent = aNewIndex;
+ }
+ else if ((iFocusedComponent < index) && (iFocusedComponent >= aNewIndex))
+ {
+ iFocusedComponent++;
+ }
+ else if ((iFocusedComponent > index) && (iFocusedComponent <= aNewIndex))
+ {
+ iFocusedComponent--;
+ }
+
+ // Remove the old index from the components array.
+ iCustomComponents.Remove(index);
+
+ iCustomComponents.InsertL(aComponent, aNewIndex);
+
+ // Redraw the whole canvas.
+ DrawDeferred();
+ }
+
+ DEBUG("CMIDCanvas::SetComponentIndexL -");
+}
+
+// ---------------------------------------------------------------------------
+// CMIDCanvas::ComponentIndex
+// Returns the index of the given component in this container.
+// (other items are commented in the header file)
+// ---------------------------------------------------------------------------
+//
+TInt CMIDCanvas::ComponentIndex(MMIDCustomComponent* aComponent) const
+{
+ DEBUG("CMIDCanvas::ComponentIndex");
+
+ return iCustomComponents.Find(aComponent);
+}
+
+// ---------------------------------------------------------------------------
+// CMIDCanvas::PostEvent
+// Post an event to Java side.
+// ---------------------------------------------------------------------------
+//
+TBool CMIDCanvas::PostEvent(
+ TEventType aType,
+ TInt aData0,
+ TInt aData1) const
+{
+ return iEnv.PostJavaEvent(const_cast< CMIDCanvas& >(*this),
+ EDisplayable,
+ aType,
+ aData0,
+ aData1,
+ 0);
+}
+
+#ifdef RD_JAVA_NGA_ENABLED
+
+// ---------------------------------------------------------------------------
+// CMIDCanvas::Update
+// Update screen from frame buffer.
+// ---------------------------------------------------------------------------
+//
+void CMIDCanvas::UpdateL(const TRect& aRect)
+{
+ if (!IsWindowVisible())
+ {
+ return;
+ }
+
+ // Don't update screen after canvas size has been changed,
+ // if there is no valid content from Java side yet
+ if (iWndUpdate &&
+ (iContentSize.iWidth > aRect.Size().iWidth ||
+ iContentSize.iHeight > aRect.Size().iHeight))
+ {
+ return;
+ }
+
+ iWndUpdate = EFalse;
+
+ // Drawing Network indicator only when Update is called.
+ if (iFullScreen && iNetworkIndicator)
+ {
+ iNetworkIndicator->SetDrawIndicator(ETrue);
+ }
+
+ if (iDirectContents.Count() == 0)
+ {
+ // In case direct content content was removed
+ // from canvas, recreate pixel source here
+ if (!iAlfCompositionPixelSource &&
+ !IsEglAvailable())
+ {
+ InitPixelSourceL();
+ }
+ DrawWindowNgaL(aRect);
+ }
+ else
+ {
+ // Must draw via CCoeControl framework
+ if (iFullScreen && iScalingOn)
+ {
+ DrawNow(iViewRect);
+ }
+ else
+ {
+ DrawNow(aRect);
+ }
+
+ iCoeEnv->WsSession().Finish();
+
+ if (iFirstPaintState == EFirstPaintInitiated ||
+ iFirstPaintState == EFirstPaintPrepared)
+ {
+ // NGA is not used, StartScreen can be informed now
+ if (iForeground)
+ {
+ // The canvas is current, therefore we can flush
+ // the graphics and take the start screen snapshot.
+ iFirstPaintState = EFirstPaintOccurred;
+ java::ui::CoreUiAvkonLcdui::getInstance().getJavaUiAppUi()->stopStartScreen();
+ }
+ }
+ }
+
+}
+
+#else // !RD_JAVA_NGA_ENABLED
+// ---------------------------------------------------------------------------
+// CMIDCanvas::Update
+// Update screen from frame buffer.
+// ---------------------------------------------------------------------------
+//
+void CMIDCanvas::Update(const TRect& aRect)
+{
+ DEBUG("- CMIDCanvas::Update");
+
+#ifdef CANVAS_DOUBLE_BUFFER
+ if (IsVisible())
+ {
+ // Drawing Network indicator only when Update is called.
+ if (iFullScreen && iNetworkIndicator)
+ {
+ iNetworkIndicator->SetDrawIndicator(ETrue);
+ }
+
+#ifdef CANVAS_DIRECT_ACCESS
+ // Check if some direct screen content is drawn.
+ if (iDirectContents.Count() > 0)
+ {
+ // There is some direct screen content drawn, DSA is not free for
+ // us at the moment.
+ DrawNow(aRect);
+ }
+ else
+ {
+ // No direct screen content is drawn, so we can try to use DSA.
+ StartDirectAccess();
+
+ if (iDirectGc)
+ {
+ // DSA is ready to use, draw directly.
+ DrawDirect(aRect);
+ }
+ else
+#endif // CANVAS_DIRECT_ACCESS
+ {
+ ActivateGc();
+ DrawWindow(aRect);
+ DeactivateGc();
+ }
+#ifdef CANVAS_DIRECT_ACCESS
+ }
+#endif // CANVAS_DIRECT_ACCESS
+
+ // This is needed to avoid artifacting after orientation switch.
+ // It is called once after orientation change.
+ if (iWndUpdate)
+ {
+ iWndUpdate = EFalse;
+ }
+ }
+#endif // CANVAS_DOUBLE_BUFFER
+
+ DEBUG("+ CMIDCanvas::Update");
+}
+
+#endif // RD_JAVA_NGA_ENABLED
+
+// ---------------------------------------------------------------------------
+// CMIDCanvas::PrepareDraw
+// Prepare drawing. Used in DrawWindow and DrawDirect.
+// aWindowRect is in bitmap coords.
+// ---------------------------------------------------------------------------
+//
+inline void CMIDCanvas::PrepareDraw(
+ CGraphicsContext& aGc, TRect& aWinRect) const
+{
+ const TRect rect = Rect();
+#ifdef RD_JAVA_NGA_ENABLED
+ if (iDirectContents.Count() > 0)
+ {
+
+ // Content may be centered in which case we need to clear the background.
+ if (rect != iViewRect)
+ {
+ // Clear background with black if centered.
+ aGc.SetBrushColor(KRgbBlack);
+ aGc.SetBrushStyle(CGraphicsContext::ESolidBrush);
+
+ DrawUtils::ClearBetweenRects(aGc, rect, iViewRect);
+ }
+ }
+#else
+ // Content may be centered in which case we need to clear the background.
+ if (rect != iViewRect)
+ {
+ // Clear background with black if centered.
+ aGc.SetBrushColor(KRgbBlack);
+ aGc.SetBrushStyle(CGraphicsContext::ESolidBrush);
+
+ DrawUtils::ClearBetweenRects(aGc, rect, iViewRect);
+ }
+#endif // RD_JAVA_NGA_ENABLED
+
+ if (iFullScreen && iNetworkIndicator)
+ {
+ // Network indicator or call indicator is drawn to the off-screen
+ // buffer if connection is open.
+ iNetworkIndicator->DrawNetworkIndicator(
+ *iFrameContext, aWinRect, iViewRect);
+ }
+
+ if (iViewRect.Size() == iContentSize)
+ {
+ // Transform the source rect to window coords.
+ aWinRect.Move(iViewRect.iTl);
+
+ // Clip to viewport.
+ aWinRect.Intersection(iViewRect);
+ }
+ else
+ {
+ aWinRect = iViewRect;
+ }
+}
+
+
+#ifdef RD_JAVA_NGA_ENABLED
+// ---------------------------------------------------------------------------
+// CMIDCanvas::DrawWindowNgaL
+// Draw using pixel source of EGL surface depending on what canvas content
+// has been drawn.
+// ---------------------------------------------------------------------------
+//
+void CMIDCanvas::DrawWindowNgaL(const TRect& aRect)
+{
+ ASSERT(IsEglAvailable() || iAlfCompositionPixelSource);
+
+ if (iFullScreen && iNetworkIndicator)
+ {
+ TRect windowRect(aRect);
+ iNetworkIndicator->DrawNetworkIndicator(
+ *iFrameContext, windowRect, iViewRect);
+ }
+
+ if (!IsEglAvailable())
+ {
+ // No M3G content, use pixel source
+ ActivatePixelSourceL(EFalse);
+ DEBUG("CMIDCanvas::Draw - Pixel Source activated");
+ }
+ else // M3G content, use EGL surface
+ {
+ if (iScalingOn && iFullScreen)
+ {
+ SetCurrentEglType(EEglPbuffer);
+ BlitFrameBufferPixels();
+ SetCurrentEglType(EEglWindow);
+ if (iWndUpdate)
+ {
+ DEBUG("CMIDCanvas::DrawWindowNgaL() - clearing window surface");
+ ClearEglSurface(EEglWindow);
+ }
+ BlitPBufferScaledToWindowSurface();
+ }
+ else
+ {
+ SetCurrentEglType(EEglWindow);
+ BlitFrameBufferPixels();
+ }
+
+ if (eglSwapBuffers(iEglDisplay, iEglWindowSurface) == EGL_FALSE)
+ {
+ ELOG1(EJavaUI, "eglSwapBuffers() failed, eglError=%d", eglGetError());
+ ASSERT(EFalse);
+ }
+
+ SetCurrentEglType(EEglNone);
+
+ // Invalidates window so that wserv does not
+ // draw window content on top our EGL surface.
+ // This is needed only once when starting to use EGL surface.
+ if (iM3GStart)
+ {
+ DEBUG("CMIDCanvas::DrawWindow - invalidate");
+ Window().Invalidate();
+ iM3GStart = EFalse;
+ }
+
+ if (iFirstPaintState != EFirstPaintOccurred)
+ {
+ iFirstPaintState = EFirstPaintOccurred;
+ java::ui::CoreUiAvkonLcdui::getInstance().getJavaUiAppUi()->stopStartScreen();
+ }
+ }
+}
+#endif // RD_JAVA_NGA_ENABLED
+
+
+#ifdef CANVAS_DOUBLE_BUFFER
+// ---------------------------------------------------------------------------
+// CMIDCanvas::DrawWindow
+// Draw through Window server using native frame buffer.
+// ---------------------------------------------------------------------------
+//
+void CMIDCanvas::DrawWindow(const TRect& aRect) const
+{
+ DEBUG("CMIDCanvas::DrawWindow ++");
+ ASSERT(iFrameBuffer);
+
+ CWindowGc& gc = SystemGc();
+
+ // If EColor16MA display mode is used, graphics context needs to set its
+ // draw mode to EDrawModeWriteAlpha for just to copy an alpha channel and
+ // not to do any blending.
+ if (iFrameBuffer->DisplayMode() == EColor16MA)
+ {
+ gc.SetDrawMode(CGraphicsContext::EDrawModeWriteAlpha);
+ }
+
+ TRect windowRect(aRect);
+ PrepareDraw(gc, windowRect);
+
+ // Check if Canvas scaling is used.
+ if (iViewRect.Size() == iContentSize)
+ {
+ DEBUG("DrawWindow - Not scaled - BitBlt");
+ gc.BitBlt(windowRect.iTl, iFrameBuffer, windowRect);
+ }
+
+#ifdef RD_JAVA_NGA_ENABLED
+ else if (IsDownScaling(iContentSize, iViewRect, iM3GContent))
+#else
+ else if (IsDownScaling(iContentSize, iViewRect))
+#endif //RD_JAVA_NGA_ENABLED
+ {
+ DEBUG("DrawWindow - Downscaling - BitBlt");
+ gc.BitBlt(windowRect.iTl, iFrameBuffer, windowRect.Size());
+ }
+ // Upscaling
+ else if (iScaler)
+ {
+ iFrameBuffer->LockHeap();
+ TUint32* pixelData = iFrameBuffer->DataAddress();
+ // Scale the framebuffer content.
+ CFbsBitmap* map = iScaler->Process(
+ iFrameBuffer->DisplayMode(),
+ pixelData,
+ iContentSize.iWidth,
+ iContentSize.iHeight,
+ iFrameBuffer->SizeInPixels().iWidth - iContentSize.iWidth,
+ iViewRect.Width(),
+ iViewRect.Height());
+
+ iFrameBuffer->UnlockHeap();
+
+ if (map)
+ {
+ DEBUG("DrawWindow - Upscaling - BitBlt - map ok");
+ gc.BitBlt(windowRect.iTl, map, windowRect.Size());
+ }
+ else
+ {
+ DEBUG("DrawWindow - Upscaling - DrawBitmap - no map");
+ gc.DrawBitmap(windowRect, iFrameBuffer, iContentSize);
+ }
+ }
+ DEBUG("CMIDCanvas::DrawWindow --");
+}
+#endif // CANVAS_DOUBLE_BUFFER
+
+
+#ifdef CANVAS_DIRECT_ACCESS
+// ---------------------------------------------------------------------------
+// CMIDCanvas::StartDirectAccess
+// Start Direct Screen Access.
+// ---------------------------------------------------------------------------
+//
+void CMIDCanvas::StartDirectAccess()
+{
+ // If DSA is not enabled or paused, or direct GC already exists just get
+ // out of here.
+ if (!DirectEnabled() || DirectPaused() || iDirectGc)
+ {
+ return;
+ }
+
+ CCoeAppUi& appUi = *static_cast< CCoeAppUi* >(ControlEnv()->AppUi());
+
+ if (appUi.IsDisplayingMenuOrDialog())
+ {
+ return;
+ }
+
+ TRAPD(err, RestartL());
+
+ if (KErrNone != err)
+ {
+ StopDirectAccess();
+ }
+ else
+ {
+ if (iDcDsaToStart && iDirectGc)
+ {
+ // Resume DSA for all direct contents
+ iDcDsaToStart = EFalse;
+ TInt contentsCount(iDirectContents.Count());
+
+ for (TInt j = 0; j < contentsCount; j++)
+ {
+ iDirectContents[j]->MdcResumeDSA();
+ }
+ }
+ }
+}
+
+
+// ---------------------------------------------------------------------------
+// CMIDCanvas::StopDirectAccess
+// Stop Direct Screen Access.
+// ---------------------------------------------------------------------------
+//
+void CMIDCanvas::StopDirectAccess()
+{
+ iDirectGc = NULL;
+ if (!iDcDsaToStart)
+ {
+ // Abort direct DSA for all direct contents
+
+ TInt contentsCount(iDirectContents.Count());
+
+ if (contentsCount > 0)
+ {
+ iDcDsaToStart = ETrue;
+ }
+
+ for (TInt j = 0; j < contentsCount; j++)
+ {
+ iDirectContents[j]->MdcAbortDSA();
+ }
+ }
+
+ if (iDirectAccess)
+ {
+ iDirectAccess->Cancel();
+ }
+}
+
+
+// ---------------------------------------------------------------------------
+// CMIDCanvas::RestartL
+// Restart Direct Screen Access.
+// ---------------------------------------------------------------------------
+//
+void CMIDCanvas::RestartL()
+{
+ ASSERT(DirectEnabled());
+ ASSERT(iDirectAccess);
+
+ if (!iDirectAccess->IsActive())
+ {
+ iDirectAccess->StartL();
+ }
+
+ iDirectGc = NULL;
+
+ if (iDirectAccess->DrawingRegion()->Count() == 1)
+ {
+ // Check that the drawing region is fully visibile (not covered)
+ TRect drawableRect((*iDirectAccess->DrawingRegion())[0]);
+ TRect canvasRect(PositionRelativeToScreen(), Size());
+
+ drawableRect.Intersection(canvasRect);
+
+ // Check that the drawing region has the proper size
+ if (drawableRect == canvasRect)
+ {
+ // Prepare context for actual drawing
+ iDirectGc = iDirectAccess->Gc();
+
+ // Direct draw is using only BitBlt and DrawBitmap so we can
+ // always use EDrawModeWriteAlpha draw mode to optimize drawing
+ // process. If EColor16MA display mode is used, graphics context
+ // needs to set its draw mode to EDrawModeWriteAlpha to just copy
+ // an alpha channel and not do any blending.
+ if (iFrameBuffer->DisplayMode() == EColor16MA)
+ {
+ iDirectGc->SetDrawMode(
+ CGraphicsContext::EDrawModeWriteAlpha);
+ }
+ }
+ }
+}
+
+
+// ---------------------------------------------------------------------------
+// CMIDCanvas::DrawDirect
+// Draw using Direct Screen Access.
+// aRect is in framebuffer coords.
+// ---------------------------------------------------------------------------
+//
+void CMIDCanvas::DrawDirect(const TRect& aRect) const
+{
+ DEBUG("+ CMIDCanvas::DrawDirect");
+
+ ASSERT(DirectEnabled());
+ ASSERT(iDirectGc);
+ ASSERT(iDirectAccess);
+ ASSERT(iFrameBuffer);
+
+ // Visible region in screen coordinates. Should only contain a single clip
+ // rect otherwise direct access should have aborted.
+ const RRegion& visibleRegion = *(iDirectAccess->DrawingRegion());
+
+ ASSERT(visibleRegion.Count() == 1);
+
+ TRect windowRect(aRect);
+ PrepareDraw(*iDirectGc, windowRect);
+
+ // Check if Canvas scaling is used.
+ if (iViewRect == iContentSize)
+ {
+ // No scaling, plain draw.
+ DEBUG("DrawDirect - NotScaled");
+ iDirectGc->BitBlt(windowRect.iTl, iFrameBuffer, windowRect);
+ }
+ else if (IsDownScaling(iContentSize, iViewRect))
+ {
+ DEBUG("DrawDirect - Downscaling");
+ iDirectGc->BitBlt(windowRect.iTl, iFrameBuffer, windowRect.Size());
+ }
+ // Upscaling
+ else if (iScaler)
+ {
+ iFrameBuffer->LockHeap();
+ TUint32* pixelData = iFrameBuffer->DataAddress();
+
+ // Scale the framebuffer content.
+ CFbsBitmap* map = iScaler->Process(
+ iFrameBuffer->DisplayMode(),
+ pixelData,
+ iContentSize.iWidth,
+ iContentSize.iHeight,
+ iFrameBuffer->SizeInPixels().iWidth - iContentSize.iWidth,
+ iViewRect.Width(),
+ iViewRect.Height());
+
+ iFrameBuffer->UnlockHeap();
+
+ if (map)
+ {
+ DEBUG("DrawDirect - Upscaling - BitBlt - map ok");
+ iDirectGc->BitBlt(windowRect.iTl, map, windowRect.Size());
+ }
+ else
+ {
+ DEBUG("DrawDirect - Upscaling - DrawBitmap - no map");
+ iDirectGc->DrawBitmap(windowRect, iFrameBuffer, iContentSize);
+ }
+ }
+
+ if (UpdateRequired())
+ {
+ windowRect.Move(PositionRelativeToScreen());
+ windowRect.Intersection(visibleRegion.RectangleList()[0]);
+
+ // Direct screen drawing does not show up on some devices unless the
+ // screen device Update() method is called.
+ iUpdateRegion.Clear();
+ iUpdateRegion.AddRect(windowRect);
+ iDirectAccess->ScreenDevice()->Update(iUpdateRegion);
+ }
+
+ DEBUG("- CMIDCanvas::DrawDirect");
+}
+#endif //CANVAS_DIRECT_ACCESS
+
+
+// ---------------------------------------------------------------------------
+// From class CCoeControl.
+// CMIDCanvas::HandleResourceChange
+// Resource change handling.
+// ---------------------------------------------------------------------------
+//
+void CMIDCanvas::HandleResourceChange(TInt aType)
+{
+#ifdef RD_JAVA_S60_RELEASE_9_2
+ if ((aType == KAknSplitInputEnabled) |
+ (aType == KAknSplitInputDisabled))
+ {
+ // We need inform CanvasItems that partial virtual keyboard
+ // is open or closed. This is needed only when partial VKB changes
+ // its state.
+ TBool partialVKBOpen = (aType == KAknSplitInputEnabled);
+ if (partialVKBOpen != iPartialVKBOpen)
+ {
+ // setting member variable
+ iPartialVKBOpen = partialVKBOpen;
+
+ // First we need inform focused item, after other.
+ iCustomComponents[iFocusedComponent]->HandleResourceChange(aType);
+ for (int i = 0; i < iCustomComponents.Count(); i++)
+ {
+ if (i != iFocusedComponent)
+ {
+ iCustomComponents[i]->HandleResourceChange(aType);
+ }
+ }
+ }
+ }
+ else if (aType == KEikInputLanguageChange)
+#else
+ if (aType == KEikInputLanguageChange)
+#endif // RD_JAVA_S60_RELEASE_9_2
+ {
+ // We need inform TextEditor that input language is changed.
+ if ((iFocusedComponent != KComponentFocusedNone) &&
+ (iFocusedComponent < iCustomComponents.Count()))
+ {
+ iCustomComponents[iFocusedComponent]->
+ CustomComponentControl(KComponentMainControl)->
+ HandleResourceChange(aType);
+ }
+
+ }
+ else if (aType == KEikDynamicLayoutVariantSwitch)
+ {
+ // If orientation change is done,
+ // then we have to inform all components about it.
+ if (iFullScreen && iScalingOn)
+ {
+ for (int i = 0; i < iCustomComponents.Count(); i++)
+ {
+ iCustomComponents[i]->HandleResourceChange(aType);
+ }
+ }
+ }
+ else if ((aType == KEikMessageUnfadeWindows) ||
+ (aType == KEikMessageFadeAllWindows))
+ {
+ iLastFadeMessage = aType;
+ }
+ else if ((aType == KEikMessageWindowsFadeChange) &&
+ ((iLastFadeMessage == KEikMessageUnfadeWindows) ||
+ (iLastFadeMessage == KEikMessageFadeAllWindows)))
+ {
+ TInt contentsCount(iDirectContents.Count());
+
+ switch (iLastFadeMessage)
+ {
+ case KEikMessageUnfadeWindows:
+ iRestoreContentWhenUnfaded = EFalse;
+
+#ifdef CANVAS_DIRECT_ACCESS
+ ResumeDirectAccess();
+#endif // CANVAS_DIRECT_ACCESS
+
+ for (TInt j = 0; j < contentsCount; j++)
+ {
+ iDirectContents[j]->MdcContainerVisibilityChanged(ETrue);
+ }
+ break;
+
+ case KEikMessageFadeAllWindows:
+ iRestoreContentWhenUnfaded = ETrue;
+
+#ifdef CANVAS_DIRECT_ACCESS
+ PauseDirectAccess();
+#endif // CANVAS_DIRECT_ACCESS
+
+ for (TInt j = 0; j < contentsCount; j++)
+ {
+ iDirectContents[j]->MdcContainerVisibilityChanged(EFalse);
+ }
+ break;
+ }
+ iLastFadeMessage = 0;
+ }
+}
+
+#ifdef RD_SCALABLE_UI_V2
+// ---------------------------------------------------------------------------
+// CMIDCanvas::HandlePointerEventInControlsL
+// Pointer events handling in controls.
+// ---------------------------------------------------------------------------
+//
+TBool CMIDCanvas::HandlePointerEventInControlsL(
+ const TPointerEvent& aPointerEvent)
+{
+ TBool inControl = EFalse;
+
+ switch (aPointerEvent.iType)
+ {
+ case TPointerEvent::EButton1Down:
+ case TPointerEvent::EButton2Down:
+ case TPointerEvent::EButton3Down:
+ // Pointer pressed
+ if ((iFocusedComponent > KComponentFocusedNone)&&
+ (iFocusedComponent < iCustomComponents.Count()) &&
+ (PointerEventInControl(iCustomComponents[iFocusedComponent],
+ aPointerEvent.iPosition)))
+ {
+ // Store the control for receiving pointer events until release
+ iPressedComponent = iCustomComponents[iFocusedComponent];
+ // Pass the pointer event
+ iPressedComponent->CustomComponentControl
+ (KComponentMainControl)->HandlePointerEventL(aPointerEvent);
+ inControl = ETrue;
+ }
+ break;
+ case TPointerEvent::EButton1Up:
+ case TPointerEvent::EButton2Up:
+ case TPointerEvent::EButton3Up:
+ // Pointer released
+ if ((iPressedComponent) && (PointerEventInControl(iPressedComponent,
+ aPointerEvent.iPosition)))
+ {
+ // Pass the pointer event
+ iPressedComponent->CustomComponentControl
+ (KComponentMainControl)->HandlePointerEventL(aPointerEvent);
+ iPressedComponent = NULL;
+ inControl = ETrue;
+ }
+ break;
+ case TPointerEvent::EDrag:
+ if (iPressedComponent)
+ {
+ iPressedComponent->ProcessPointerEventL(aPointerEvent);
+ inControl = ETrue;
+ }
+ break;
+ default:
+ break;
+ }
+ return inControl;
+}
+
+// ---------------------------------------------------------------------------
+// CMIDCanvas::PointerEventInControl
+// Pointer events checking.
+// ---------------------------------------------------------------------------
+//
+TBool CMIDCanvas::PointerEventInControl(MMIDCustomComponent* aControl,
+ TPoint aPoint)
+{
+ TBool inControl = EFalse;
+ TInt compoundCount = aControl->CustomComponentControlCount();
+ for (int j = 0; j < compoundCount; j++)
+ {
+ // Check if the pointer event position is in visible control's
+ // area.
+ if (aControl->CustomComponentControl(j)->IsVisible())
+ {
+ inControl |= aControl->CustomComponentControl(j)->
+ Rect().Contains(aPoint);
+ }
+ }
+ return inControl;
+}
+
+// ---------------------------------------------------------------------------
+// From class CCoeControl.
+// CMIDCanvas::HandlePointerEventL
+// Pointer events handling.
+// ---------------------------------------------------------------------------
+//
+void CMIDCanvas::HandlePointerEventL(const TPointerEvent& aPointerEvent)
+{
+ if (AknLayoutUtils::PenEnabled())
+ {
+ TPoint point = aPointerEvent.iPosition;
+ TInt count = iCustomComponents.Count();
+ TBool consumed = EFalse;
+
+ // Long tap not allowed in full screen mode.
+ if (!iFullScreen)
+ {
+ consumed = iDisplayable->TryDetectLongTapL(aPointerEvent);
+ }
+
+ if (!consumed && (iFocusedComponent != KComponentFocusedNone) &&
+ (iFocusedComponent < iCustomComponents.Count()) &&
+ (iCustomComponents[iFocusedComponent]->IsTouchEnabled()))
+ {
+ consumed = HandlePointerEventInControlsL(aPointerEvent);
+ }
+
+ if (!consumed)
+ {
+ // Points are counted from 0 to width - 1, resp. height -1,
+ // so we compute maxima for points coordinates based
+ // on native view size and java canvas size.
+ TSize nativeMaxCoords = iViewRect.Size() - TSize(1, 1);
+ TSize javaMaxCoords = iContentSize - TSize(1, 1);
+
+ // Transform point to content coordinates.
+ //
+ // iViewRect.iTl -> (0, 0)
+ // iViewRect.iBr - TSize(1, 1) -> (iContentSize.iWidth - 1,
+ // iContentSize.iHeight - 1)
+ point -= iViewRect.iTl;
+
+ if (javaMaxCoords != nativeMaxCoords)
+ {
+ point.iX = (point.iX * javaMaxCoords.iWidth) /
+ nativeMaxCoords.iWidth;
+ point.iY = (point.iY * javaMaxCoords.iHeight) /
+ nativeMaxCoords.iHeight;
+ }
+
+ TEventType type;
+ TTime now;
+
+ switch (aPointerEvent.iType)
+ {
+ case TPointerEvent::EButton1Down:
+ case TPointerEvent::EButton2Down:
+ case TPointerEvent::EButton3Down:
+ type = EPointerPressed;
+ iPointerPressedCoordinates = TPoint(point.iX, point.iY);
+ if (point.iX >= 0 && point.iX <= javaMaxCoords.iWidth &&
+ point.iY >= 0 && point.iY <= javaMaxCoords.iHeight)
+ {
+ // Translated point is inside of java canvas
+ iDragEventsStartedInside = ETrue;
+ }
+ break;
+ case TPointerEvent::EButton1Up:
+ case TPointerEvent::EButton2Up:
+ case TPointerEvent::EButton3Up:
+ type = EPointerReleased;
+ if (iPointerEventSuppressionOngoing)
+ {
+ point.iX = iPointerPressedCoordinates.iX;
+ point.iY = iPointerPressedCoordinates.iY;
+ }
+ break;
+ case TPointerEvent::EDrag:
+ type = EPointerDragged;
+ // If pointerEventSuppressor time is set to 0 don't do any
+ // drag event filtering. (default time here is 500ms and it
+ // can be changed with JAD parameter
+ // Nokia-MIDlet-Tap-Detection-Options)
+ if (iPESTimeInMilliseconds != 0)
+ {
+ now.HomeTime();
+ if (now.MicroSecondsFrom(iPreviousDragTimeStamp) <
+ KAllowedTimeBetweenDragEvents)
+ {
+ // Ignore drag event because time between drags is
+ // shorter than allowed interval.
+ return;
+ }
+ else
+ {
+ iPreviousDragTimeStamp = now;
+ }
+ }
+ break;
+ default:
+ type = ENoType;
+ }
+
+ // Pointer Event Suppressor for helping tap detection with finger
+ // usage
+ if (iPointerEventSuppressor->SuppressPointerEvent(aPointerEvent))
+ {
+ iPointerEventSuppressionOngoing = ETrue;
+ return;
+ }
+ else
+ {
+ iPointerEventSuppressionOngoing = EFalse;
+ }
+
+ // To have the cursor on focused control
+ if (iFocusedComponent != KComponentFocusedNone)
+ {
+ iCustomComponents[iFocusedComponent]->
+ CustomComponentControl(KComponentMainControl)->
+ SetFocus(ETrue);
+ }
+
+ // Ignore pointer events outside of Canvas content.
+ if (!iDragEventsStartedInside)
+ {
+ return;
+ }
+
+ PostEvent(type, point.iX, point.iY);
+
+ // Flag is reset, if release event happened. However reset
+ // has to be done after event is sent to java, because of possible
+ // dragging, which started inside of canvas. In this case
+ // also release event should be delivered to java
+ if (type == EPointerReleased)
+ {
+ iDragEventsStartedInside = EFalse;
+ }
+ }
+ }
+}
+#endif // RD_SCALABLE_UI_V2
+
+
+// ---------------------------------------------------------------------------
+// From class CCoeControl.
+// CMIDCanvas::FocusChanged
+// Change of focus.
+// ---------------------------------------------------------------------------
+//
+void CMIDCanvas::FocusChanged(TDrawNow /* aDrawNow */)
+{
+ DEBUG("+ CMIDCanvas::FocusChanged");
+
+ iEnv.ResetKeys();
+ iGameKeyState = 0;
+ iGameKeyLatch = 0;
+
+ TInt contentsCount(iDirectContents.Count());
+
+ if (IsFocused())
+ {
+#ifdef CANVAS_DIRECT_ACCESS
+ ResumeDirectAccess();
+#endif // CANVAS_DIRECT_ACCESS
+
+ if (!iRestoreContentWhenUnfaded)
+ {
+ for (TInt j = 0; j < contentsCount; j++)
+ {
+ iDirectContents[j]->MdcContainerVisibilityChanged(ETrue);
+ }
+ }
+
+ // To have cursor on focused control.
+ if ((iFocusedComponent != KComponentFocusedNone) &&
+ (iFocusedComponent < iCustomComponents.Count()) &&
+ iCustomComponents[iFocusedComponent]->
+ CustomComponentControl(KComponentMainControl)->IsVisible())
+ {
+ iCustomComponents[iFocusedComponent]->
+ CustomComponentControl(KComponentMainControl)->
+ SetFocus(ETrue);
+ }
+
+#ifdef RD_JAVA_NGA_ENABLED
+ // To avoid situation when Canvas is redrawn but black area remains
+ if (iAlfCompositionPixelSource && iDirectContents.Count() == 0)
+ {
+ TRAPD(err, ActivatePixelSourceL(EFalse));
+ if (err != KErrNone)
+ {
+ DEBUG_INT("CMIDCanvas::FocusChanged - ActivatePixelSourceL error %d", err);
+ }
+ }
+ else
+ {
+ // Redraw the canvas after unfading
+ DrawDeferred();
+ }
+#else // !RD_JAVA_NGA_ENABLED
+ // Redraw the canvas after unfading
+ DrawDeferred();
+#endif // RD_JAVA_NGA_ENABLED
+
+ }
+ else
+ {
+#ifdef CANVAS_DIRECT_ACCESS
+ PauseDirectAccess();
+#endif // CANVAS_DIRECT_ACCESS
+
+ if (!iRestoreContentWhenUnfaded)
+ {
+ for (TInt j = 0; j < contentsCount; j++)
+ {
+ iDirectContents[j]->MdcContainerVisibilityChanged(EFalse);
+ }
+ }
+
+ // To remove cursor on focused control.
+ if ((iFocusedComponent != KComponentFocusedNone) &&
+ (iFocusedComponent < iCustomComponents.Count()) &&
+ iCustomComponents[iFocusedComponent]->
+ CustomComponentControl(KComponentMainControl)->IsVisible())
+ {
+ iCustomComponents[iFocusedComponent]->
+ CustomComponentControl(KComponentMainControl)->
+ SetFocus(EFalse);
+ }
+
+ // Repaint to ensure that fading will be displayed correctly for Alert
+ // or PopupTextBox when DSA is paused. No redraw, if canvas is using
+ // background surfaces i.e. EGL or pixel source
+ if (iDirectContents.Count() > 0)
+ {
+ DrawDeferred();
+ }
+ }
+
+ DEBUG("- CMIDCanvas::FocusChanged");
+}
+
+
+// ---------------------------------------------------------------------------
+// From class CCoeControl.
+// CMIDCanvas::SizeChanged
+// Change of size.
+// ---------------------------------------------------------------------------
+//
+void CMIDCanvas::SizeChanged()
+{
+ DEBUG("+ CMIDCanvas::SizeChanged");
+
+ TSize controlSize = Size();
+
+ // Position in screen co-ordinates changes when mode (full/normal) is
+ // changed.
+ iPositionRelativeToScreen = PositionRelativeToScreen();
+ TRect contentBounds = TRect(iPositionRelativeToScreen, controlSize);
+
+ // If JAD attribute Nokia-MIDlet-Original-Display-Size for graphics
+ // scaling is defined, the iContentSize must follow it.
+ TSize orientedOrgMIDletScrSize(OrientedOrgMIDletScrSize());
+
+ if (contentBounds != iOldContentBounds)
+ {
+ iOldContentBounds = contentBounds;
+
+ TSize contentSize;
+
+#ifdef RD_JAVA_S60_RELEASE_9_2
+ if (iFullScreen && (orientedOrgMIDletScrSize != controlSize)
+ && !iPartialVKBOpen)
+#else
+ if (iFullScreen && (orientedOrgMIDletScrSize != controlSize))
+#endif // RD_JAVA_S60_RELEASE_9_2
+ {
+ contentSize = orientedOrgMIDletScrSize;
+ }
+
+ if (contentSize == KZeroSize)
+ {
+ contentSize = controlSize;
+ }
+
+ if ((contentSize != iContentSize) || iScalingOn)
+ {
+#ifdef RD_JAVA_NGA_ENABLED
+ TSize oldContentSize = iContentSize;
+ iContentSize = contentSize;
+
+ TBool landscape = Layout_Meta_Data::IsLandscapeOrientation();
+
+ if (IsWindowVisible() &&
+ (oldContentSize.iWidth < iContentSize.iWidth ||
+ oldContentSize.iHeight < iContentSize.iHeight ||
+ landscape != iLandscape))
+ {
+ iWndUpdate = ETrue;
+ if (IsEglAvailable())
+ {
+ // Clear with black to avoid incorrectly sized
+ // surface flashing on screen in orientation switch
+ TRgb color(KOpaqueBlackColor);
+ ClearEglSurface(EEglWindow, &color);
+ }
+ }
+
+ HandleSizeChanged(landscape != iLandscape);
+ iLandscape = landscape;
+
+ PostEvent(ESizeChanged, iContentSize.iWidth, iContentSize.iHeight);
+
+ if (IsWindowVisible() && iWndUpdate)
+ {
+ // Post forced paint to enable Canvas repaint behind
+ // Alert or Pop-up TextBox
+ PostForcedPaint();
+ }
+#else
+ iContentSize = contentSize;
+ PostEvent(ESizeChanged, iContentSize.iWidth, iContentSize.iHeight);
+#endif // RD_JAVA_NGA_ENABLED
+ }
+
+#ifdef CANVAS_DIRECT_ACCESS
+ // Stop direct screen access to avoid restarting
+ // of direct content DSA during MdcContentBoundsChanged.
+ // DSA is resumed by Layout method.
+ StopDirectAccess();
+#endif // CANVAS_DIRECT_ACCESS
+
+ // Inform all listeners.
+ TInt contentsCount(iDirectContents.Count());
+
+ for (TInt j = 0; j < contentsCount; j++)
+ {
+ iDirectContents[j]->MdcContentBoundsChanged(contentBounds);
+ iDirectContents[j]->MdcContainerWindowRectChanged(MdcContainerWindowRect());
+ }
+
+ // We cannot determine whether the control size actually did change or
+ // not, so we have to do the layout no matter what.
+ Layout();
+ }
+ DEBUG("- CMIDCanvas::SizeChanged");
+}
+
+
+// ---------------------------------------------------------------------------
+// From class CCoeControl.
+// CMIDCanvas::PositionChanged
+// Change of position.
+// ---------------------------------------------------------------------------
+//
+void CMIDCanvas::PositionChanged()
+{
+ Layout();
+}
+
+#ifdef RD_JAVA_NGA_ENABLED
+// ---------------------------------------------------------------------------
+// From class CCoeControl.
+// CMIDCanvas::Draw
+// Drawing.
+// ---------------------------------------------------------------------------
+//
+void CMIDCanvas::Draw(const TRect& aRect) const
+{
+ DEBUG("CMIDCanvas::Draw ++");
+
+ if (iWndUpdate)
+ {
+ return;
+ }
+
+ if (iDirectContents.Count() > 0)
+ {
+ DrawWindow(aRect);
+ }
+ else
+ {
+ CMIDCanvas* myself = const_cast<CMIDCanvas*>(this);
+
+ if (IsEglAvailable())
+ {
+ myself->ClearUiSurface(ETrue);
+ }
+ else if (iAlfCompositionPixelSource)
+ {
+ myself->ClearUiSurface(ETrue);
+ TRAP_IGNORE(myself->ActivatePixelSourceL(ETrue));
+ }
+ else
+ {
+ // This is the case when M3G midlet is
+ // coming back to foreground and EGL
+ // surface is not re-created yet
+ DrawWindow(aRect);
+ }
+ }
+
+ DEBUG("CMIDCanvas::Draw --");
+}
+#else // !RD_JAVA_NGA_ENABLED
+
+// ---------------------------------------------------------------------------
+// From class CCoeControl.
+// CMIDCanvas::Draw
+// Drawing.
+// ---------------------------------------------------------------------------
+//
+void CMIDCanvas::Draw(const TRect& aRect) const
+{
+ DEBUG("+ CMIDCanvas::Draw");
+
+#ifdef CANVAS_DOUBLE_BUFFER
+ ASSERT(iFrameBuffer);
+#endif // CANVAS_DOUBLE_BUFFER
+
+#ifdef CANVAS_ASYNC_PAINT
+ TRect rect(aRect);
+
+ rect.Intersection(iViewRect);
+ rect.Move(-iViewRect.iTl);
+
+ TSize size(rect.Size());
+
+ TInt posPacked = (rect.iTl.iX << 16) | (rect.iTl.iY);
+ TInt sizePacked = (size.iWidth << 16) | (size.iHeight);
+
+ PostEvent(EPaint, posPacked, sizePacked);
+#else
+#ifdef CANVAS_DOUBLE_BUFFER
+
+// While changing the orientation method DrawWindow() not called,
+// variable iWndUpdate is set to True. If iWndUpdate is True
+// DrawWindow() is called from method Update()
+// This is needed to avoid artifacting after orientation switch.
+TBool landscape = Layout_Meta_Data::IsLandscapeOrientation();
+
+if (iLandscape != landscape)
+{
+ iLandscape = landscape;
+ iWndUpdate = ETrue;
+}
+else
+{
+#ifdef CANVAS_DIRECT_ACCESS
+ // Check if DSA is ready and not used by some other client.
+ if (iDirectGc && !iDirectContents.Count() && !DirectPaused())
+ {
+ DrawDirect(aRect); // Draw directly to screen.
+ }
+ else
+ {
+#endif // CANVAS_DIRECT_ACCESS
+ DrawWindow(aRect); // Bitblt via window server.
+#ifdef CANVAS_DIRECT_ACCESS
+ }
+#endif // CANVAS_DIRECT_ACCESS
+
+ iWndUpdate = EFalse;
+}
+#endif // CANVAS_DOUBLE_BUFFER
+#endif // CANVAS_ASYNC_PAINT
+
+ DEBUG("- CMIDCanvas::Draw");
+}
+#endif // RD_JAVA_NGA_ENABLED
+
+// ---------------------------------------------------------------------------
+// CMIDCanvas::CMIDCanvas
+// C++ constructor.
+// ---------------------------------------------------------------------------
+//
+CMIDCanvas::CMIDCanvas(
+ MMIDEnv& aEnv,
+ MMIDComponent::TType aComponentType,
+#ifdef CANVAS_DIRECT_ACCESS
+ TBool /*aUpdateRequired*/
+#else
+ TBool aUpdateRequired
+#endif // CANVAS_DIRECT_ACCESS
+) :
+ CCoeControl()
+ ,iEnv(aEnv)
+#ifdef CANVAS_DOUBLE_BUFFER
+ ,iFrameBuffer(NULL)
+#endif // CANVAS_DOUBLE_BUFFER
+ ,iIsGameCanvas((
+ aComponentType == MMIDComponent::EGameCanvas ? ETrue : EFalse))
+ ,iFlags(EPostKeyEvents)
+ ,iFullScreen(EFalse)
+ ,iScalingOn(EFalse)
+ ,iS60SelectionKeyCompatibility(EFalse)
+ ,iRestoreContentWhenUnfaded(EFalse)
+ ,iLastFadeMessage(0)
+#ifdef CANVAS_DIRECT_ACCESS
+ ,iDcDsaToStart(EFalse)
+#endif // CANVAS_DIRECT_ACCESS
+ ,iDragEventsStartedInside(EFalse)
+ ,iFirstPaintState(EFirstPaintNeverOccurred)
+{
+ DEBUG("+ CMIDCanvas::CMIDCanvas - EDirectEnabled");
+
+#ifdef CANVAS_DIRECT_ACCESS
+ iFlags |= (EDirectPaused | EDirectEnabled | EUpdateRequired);
+#else
+
+#if defined( __WINS__ ) || defined( __WINSCW__ )
+ aUpdateRequired = ETrue;
+#endif
+
+ if (aUpdateRequired)
+ {
+ iFlags |= EUpdateRequired;
+ }
+#endif // CANVAS_DIRECT_ACCESS
+
+ //Default values for PointerEventSuppressor
+ iPESPointerMovementInTwips = CMIDUIManager::EPESPointerMovementInTwips;
+ iPESTimeInMilliseconds = CMIDUIManager:: EPESTimeInMilliseconds;
+
+ DEBUG("- CMIDCanvas::CMIDCanvas");
+}
+
+
+// ---------------------------------------------------------------------------
+// CMIDCanvas::ConstructL
+// Symbian 2nd phase constructor can leave.
+// ---------------------------------------------------------------------------
+//
+void CMIDCanvas::ConstructL(CCoeControl& aWindow)
+{
+ SetContainerWindowL(aWindow);
+
+ iFocusedComponent = KComponentFocusedNone;
+ iPressedComponent = NULL;
+ iOrgMIDletScrSize = TSize();
+ iTargetMIDletScrSize = TSize();
+
+#ifdef CANVAS_DOUBLE_BUFFER
+ // Create a framebuffer large enough for full screen mode.
+ // In normal mode we will waste the border pixels. This may be offset in
+ // future by sharing the framebuffer between displayables.
+ //
+ // Allow dynamic changing of screen modes find the
+ // largest available screen size to allocate a frame buffer big enough to
+ // deal with all screen modes;
+ CWsScreenDevice* device = ControlEnv()->ScreenDevice();
+ TInt noModes = device->NumScreenModes();
+ TPixelsAndRotation pixelAndRot;
+ TSize frameBufferSize(0, 0);
+
+ for (TInt ii=0 ; ii < noModes; ++ii)
+ {
+ device->GetScreenModeSizeAndRotation(ii, pixelAndRot);
+
+ if (frameBufferSize.iHeight < pixelAndRot.iPixelSize.iHeight)
+ {
+ frameBufferSize.iHeight = pixelAndRot.iPixelSize.iHeight;
+ }
+
+ if (frameBufferSize.iWidth < pixelAndRot.iPixelSize.iWidth)
+ {
+ frameBufferSize.iWidth = pixelAndRot.iPixelSize.iWidth;
+ }
+ }
+
+ DEBUG_INT2("Canvas FrameBuffer Size: Width: %d, Height %d",
+ frameBufferSize.iWidth, frameBufferSize.iHeight);
+
+ CreateFrameBufferL(frameBufferSize);
+
+ if (iFrameBuffer)
+ {
+ iFrameDevice = CFbsBitmapDevice::NewL(iFrameBuffer);
+ User::LeaveIfError(iFrameDevice->CreateContext(iFrameContext));
+ }
+
+ // Set iLandscape set as True according to landscape orientation mode
+ // and initialize iWndUpdat. iWndUpdat variable notify us, when
+ // orienation was changed
+ iLandscape = Layout_Meta_Data::IsLandscapeOrientation();
+ iWndUpdate = EFalse;
+
+#endif // CANVAS_DOUBLE_BUFFER
+
+ SetScalingFactors();
+
+ if (iScalingOn)
+ {
+ // We need iScaler only when scaling is on.
+ iScaler = iDisplayable->GetUIManager()->OpenScalerL();
+ }
+
+#ifdef CANVAS_DIRECT_ACCESS
+ ResumeDirectAccess();
+#endif // CANVAS_DIRECT_ACCESS
+
+ if (IsNetworkIndicatorEnabledL())
+ {
+ iNetworkIndicator = CMIDNetworkIndicator::NewL(this);
+
+ // Initialize and set active CallIndicator to receive notification
+ // when voiceline status changes.
+ iCallIndicator = CMIDCallIndicator::NewL(iNetworkIndicator);
+ iCallIndicator->SetActiveLocal();
+ }
+
+ iKeyDecoder = iDisplayable->GetUIManager()->OpenKeyDecoderL();
+ ASSERT(iKeyDecoder);
+
+ // Canvas listens Media key events if CMIDRemConObserver is initialized
+ // and media keys keys are enabled.
+ iRemConObserver = iKeyDecoder->GetRemConObserver();
+ if (iRemConObserver && iKeyDecoder->MediaKeysEnabled())
+ {
+ iRemConObserver->AddMediaKeysListenerL(this);
+ }
+
+ // Set S60 Selection Key Compatibility to provide MSK key events to
+ // canvas.
+ iS60SelectionKeyCompatibility = iEnv.MidletAttributeIsSetToVal(
+ LcduiMidletAttributes::KAttribS60SelectionKeyCompatibility,
+ LcduiMidletAttributeValues::KTrueValue);
+
+ if (iDisplayable)
+ {
+ iDisplayable->SetS60SelectionKeyCompatibility(
+ iS60SelectionKeyCompatibility);
+ }
+
+#ifdef RD_TACTILE_FEEDBACK
+ // Create a CMIDTactileFeedbackExtension in case tactile feedback is
+ // supported.
+ iTactileFeedback = new(ELeave) CMIDTactileFeedbackExtension(this, 1);
+#endif // RD_TACTILE_FEEDBACK
+
+ //Create PointerEventSuppressor with default values or JAD parameter defined values
+ iPointerEventSuppressor = CAknPointerEventSuppressor::NewL();
+ TInt pointerMovementInPixels =
+ ControlEnv()->ScreenDevice()->HorizontalTwipsToPixels(iPESPointerMovementInTwips);
+ TSize suppressorValues =
+ iDisplayable->GetUIManager()->ReadPointerEventSuppressorValues();
+ if (!(suppressorValues.iWidth == KPESErrorValue &&
+ suppressorValues.iHeight == KPESErrorValue))
+ {
+ iPESTimeInMilliseconds = suppressorValues.iHeight;
+ pointerMovementInPixels =
+ ControlEnv()->ScreenDevice()->HorizontalTwipsToPixels(suppressorValues.iWidth);
+ }
+ iPointerEventSuppressor->SetMaxTapDuration(iPESTimeInMilliseconds * 1000);
+ iPointerEventSuppressor->SetMaxTapMove(TSize(pointerMovementInPixels,
+ pointerMovementInPixels));
+
+ iForeground = EFalse;
+#ifdef RD_JAVA_NGA_ENABLED
+ iEglDisplay = EGL_NO_DISPLAY;
+ iEglWindowSurface = EGL_NO_SURFACE;
+ iEglWindowSurfaceContext = EGL_NO_CONTEXT;
+ iEglPbufferSurface = EGL_NO_SURFACE;
+ iEglPbufferSurfaceContext = EGL_NO_CONTEXT;
+ iPbufferTexture = 0;
+
+ i3DAccelerated =
+ iEnv.IsHardwareAcceleratedL(MMIDEnv::EHardware3D) > 0;
+
+ InitPixelSourceL();
+#endif // RD_JAVA_NGA_ENABLED
+
+#ifdef RD_JAVA_S60_RELEASE_9_2
+ iPartialVKBOpen = EFalse;
+#endif // RD_JAVA_S60_RELEASE_9_2
+}
+
+
+// ---------------------------------------------------------------------------
+// CMIDCanvas::SetContainerWindowL
+// Set the container window.
+// ---------------------------------------------------------------------------
+//
+void CMIDCanvas::SetContainerWindowL(const CCoeControl& aWindow)
+{
+#ifdef CANVAS_DIRECT_ACCESS
+ StopDirectAccess();
+
+ if (iDirectAccess)
+ {
+ delete iDirectAccess;
+ iDirectAccess = NULL;
+ }
+#endif // CANVAS_DIRECT_ACCESS
+
+ iDisplayable = (CMIDDisplayable*) &aWindow;
+ CCoeControl::SetContainerWindowL(aWindow);
+ Window().SetBackgroundColor();
+ MakeVisible(aWindow.IsVisible());
+
+#ifdef RD_SCALABLE_UI_V2
+ Window().SetPointerGrab(ETrue);
+#endif // RD_SCALABLE_UI_V2
+
+#ifdef CANVAS_DIRECT_ACCESS
+ if (DirectEnabled())
+ {
+ RWsSession& session = ControlEnv()->WsSession();
+ CWsScreenDevice* device = ControlEnv()->ScreenDevice();
+
+ iDirectAccess = CDirectScreenAccess::NewL(
+ session, *device, *DrawableWindow(), *this);
+ }
+#endif // CANVAS_DIRECT_ACCESS
+
+ // Position in screen co-ordinates is first time available when container
+ // window is set.
+ iPositionRelativeToScreen = PositionRelativeToScreen();
+}
+
+
+// ---------------------------------------------------------------------------
+// CMIDCanvas::SendKeyEventToJavaSideL
+// Send key event to Java side.
+// ---------------------------------------------------------------------------
+//
+void CMIDCanvas::SendKeyEventToJavaSideL(
+ const TKeyEvent& aEvent, TEventCode aType)
+{
+ DEBUG("+ CMIDCanvas::SendKeyEventToJavaSideL");
+ TMIDKeyEvent event;
+
+ // See if the key can be sent java side.
+ DEBUG_INT2("CMIDCanvas::PostKeyEvent - SOS code %d SOS type %d",
+ aEvent.iCode,
+ aType);
+
+ // map key event data
+ TKeyEvent wsEvent = aEvent;
+
+ DEBUG_INT("+ CMIDCanvas::SendKeyEventToJavaSideL - received TKeyEvent: iCode = %d", aEvent.iCode);
+ DEBUG_INT("+ CMIDCanvas::SendKeyEventToJavaSideL - received TKeyEvent: iModifiers = %d", aEvent.iModifiers);
+ DEBUG_INT("+ CMIDCanvas::SendKeyEventToJavaSideL - received TKeyEvent: iRepeats = %d", aEvent.iRepeats);
+ DEBUG_INT("+ CMIDCanvas::SendKeyEventToJavaSideL - received TKeyEvent: iScanCode = %d", aEvent.iScanCode);
+
+ iEnv.MappingDataForKey(wsEvent, aType);
+
+ DEBUG_INT("+ CMIDCanvas::SendKeyEventToJavaSideL - mapped TKeyEvent: iCode = %d", aEvent.iCode);
+ DEBUG_INT("+ CMIDCanvas::SendKeyEventToJavaSideL - mapped TKeyEvent: iModifiers = %d", aEvent.iModifiers);
+ DEBUG_INT("+ CMIDCanvas::SendKeyEventToJavaSideL - mapped TKeyEvent: iRepeats = %d", aEvent.iRepeats);
+ DEBUG_INT("+ CMIDCanvas::SendKeyEventToJavaSideL - mapped TKeyEvent: iScanCode = %d", aEvent.iScanCode);
+
+ //See if the key can be sent java side.
+ if (iEnv.TranslateKeyL(event, wsEvent, aType))
+ {
+ DEBUG_INT("+ CMIDCanvas::SendKeyEventToJavaSideL - translated TMIDKeyEvent: iEvents = %d", event.iEvents);
+ DEBUG_INT("+ CMIDCanvas::SendKeyEventToJavaSideL - translated TMIDKeyEvent: iKeyCode = %d", event.iKeyCode);
+ DEBUG_INT("+ CMIDCanvas::SendKeyEventToJavaSideL - translated TMIDKeyEvent: iRepeats = %d", event.iRepeats);
+
+ ASSERT(iKeyDecoder);
+
+ TInt gameAction = iKeyDecoder->GameAction(event.iKeyCode);
+
+ if (0 != gameAction)
+ {
+ if (event.iEvents & TMIDKeyEvent::EPressed)
+ {
+ GamePress(gameAction);
+ }
+
+ if (event.iEvents & TMIDKeyEvent::EReleased)
+ {
+ GameRelease(gameAction);
+ }
+ }
+
+ if (PostKeyEvents() || (0 == gameAction))
+ {
+ DEBUG_INT2(
+ "CMIDCanvas::PostKeyEvent - JAVA code %d JAVA type %d",
+ event.iKeyCode,
+ event.iEvents);
+
+ // 9-way Navigation Support
+ // Send two arrow events generated when press diagonal direction
+ switch (event.iKeyCode)
+ {
+ //KeyLeftUpArrow
+ case EKeyLeftUpArrow:
+ {
+ TMIDKeyEvent pevent;
+ pevent.iKeyCode = iKeyDecoder->MapNonUnicodeKey(EStdKeyUpArrow);
+ pevent.iEvents = event.iEvents;
+ pevent.iRepeats = event.iRepeats;
+ iEnv.PostKeyEvent(*this, pevent);
+ pevent.iKeyCode = iKeyDecoder->MapNonUnicodeKey(EStdKeyLeftArrow);
+ pevent.iEvents = event.iEvents;
+ pevent.iRepeats = event.iRepeats;
+ iEnv.PostKeyEvent(*this, pevent);
+ break;
+ }
+ //KeyRightUpArrow
+ case EKeyRightUpArrow:
+ {
+ TMIDKeyEvent pevent;
+ pevent.iKeyCode = iKeyDecoder->MapNonUnicodeKey(EStdKeyUpArrow);
+ pevent.iEvents = event.iEvents;
+ pevent.iRepeats = event.iRepeats;
+ iEnv.PostKeyEvent(*this, pevent);
+ pevent.iKeyCode = iKeyDecoder->MapNonUnicodeKey(EStdKeyRightArrow);
+ pevent.iEvents = event.iEvents;
+ pevent.iRepeats = event.iRepeats;
+ iEnv.PostKeyEvent(*this, pevent);
+ break;
+ }
+ //KeyRightDownArrow
+ case EKeyRightDownArrow:
+ {
+ TMIDKeyEvent pevent;
+ pevent.iKeyCode = iKeyDecoder->MapNonUnicodeKey(EStdKeyDownArrow);
+ pevent.iEvents = event.iEvents;
+ pevent.iRepeats = event.iRepeats;
+ iEnv.PostKeyEvent(*this, pevent);
+ pevent.iKeyCode = iKeyDecoder->MapNonUnicodeKey(EStdKeyRightArrow);
+ pevent.iEvents = event.iEvents;
+ pevent.iRepeats = event.iRepeats;
+ iEnv.PostKeyEvent(*this, pevent);
+ break;
+ }
+ //KeyLeftDownArrow
+ case EKeyLeftDownArrow:
+ {
+ TMIDKeyEvent pevent;
+ pevent.iKeyCode = iKeyDecoder->MapNonUnicodeKey(EStdKeyDownArrow);
+ pevent.iEvents = event.iEvents;
+ pevent.iRepeats = event.iRepeats;
+ iEnv.PostKeyEvent(*this, pevent);
+ pevent.iKeyCode = iKeyDecoder->MapNonUnicodeKey(EStdKeyLeftArrow);
+ pevent.iEvents = event.iEvents;
+ pevent.iRepeats = event.iRepeats;
+ iEnv.PostKeyEvent(*this, pevent);
+ break;
+ }
+ default:
+ iEnv.PostKeyEvent(*this, event);
+ }
+ }
+ }
+ DEBUG("- CMIDCanvas::SendKeyEventToJavaSideL");
+}
+
+
+#ifdef CANVAS_DOUBLE_BUFFER
+// ---------------------------------------------------------------------------
+// CMIDCanvas::CreateFrameBufferL
+// Create frame buffer.
+// ---------------------------------------------------------------------------
+//
+void CMIDCanvas::CreateFrameBufferL(const TSize& aSize)
+{
+ DEBUG_INT2("+ CMIDCanvas::CreateFrameBufferL( %D, %D)",
+ aSize.iWidth,
+ aSize.iHeight);
+
+ iFrameBuffer = iEnv.ReserveCanvasFrameBufferL((*this), aSize);
+
+ DEBUG("- CMIDCanvas::CreateFrameBufferL");
+}
+#endif // CANVAS_DOUBLE_BUFFER
+
+
+#ifdef DEFER_BITBLT
+// ---------------------------------------------------------------------------
+// CMIDCanvas::BitBltCycles
+// Get BitBlt cycles count.
+// ---------------------------------------------------------------------------
+//
+TInt CMIDCanvas::BitBltCycles(const TSize& aSize) const
+{
+ TInt cycles = (aSize.iWidth * aSize.iHeight * KEstCyclesPerPixel);
+
+ if (cycles < KMinOpCycles) cycles = KMinOpCycles;
+ if (cycles > KMaxOpCycles) cycles = KMaxOpCycles;
+
+ return cycles;
+}
+#endif // DEFER_BITBLT
+
+
+// ---------------------------------------------------------------------------
+// CMIDCanvas::Layout
+// Layout Canvas control.
+// ---------------------------------------------------------------------------
+//
+void CMIDCanvas::Layout()
+{
+ DEBUG("+ CMIDCanvas::Layout");
+#ifdef CANVAS_DIRECT_ACCESS
+ StopDirectAccess();
+#endif // CANVAS_DIRECT_ACCESS
+
+ TRect rect(Rect());
+ TSize size(rect.Size());
+ TSize viewSize;
+
+ if (iFullScreen)
+ {
+ if (iNetworkIndicator)
+ {
+ // Refresh the layout data for network indicator.
+ iNetworkIndicator->GetLayoutData();
+ }
+
+ // Get original MIDlet size which eventually reflects display
+ // orientation.
+ TSize orientedOrgMIDletScrSize(OrientedOrgMIDletScrSize());
+
+#ifdef RD_JAVA_S60_RELEASE_9_2
+ // If partial VKB is open then MIDlet is not scaled.
+ // That we need set iViewRect to whole size of Canvas.
+ if (iPartialVKBOpen)
+ {
+ viewSize = Size();
+ }
+ else if (iTargetMIDletScrSize != KZeroSize)
+#else
+ if (iTargetMIDletScrSize != KZeroSize)
+#endif //RD_JAVA_S60_RELEASE_9_2
+ {
+ // If Nokia-MIDlet-Target-Display-Size is defined, Canvas will be
+ // scaled to that size.
+ viewSize = iTargetMIDletScrSize;
+ }
+ // If optional JAD parameter Nokia-MIDlet-Target-Display-Size is NOT
+ // defined and Nokia-MIDlet-Original-Display-Size is defined to
+ // smaller size than the device's screen size, we will scale the
+ // Canvas to fit the screen without changing aspect ratio.
+ // If the aspect ratio of Nokia-MIDlet-Original-Display-Size is not
+ // same as the display has, we need to leave black borders to both
+ // sides or up and down.
+ else if (
+ (orientedOrgMIDletScrSize.iWidth != 0) &&
+ (orientedOrgMIDletScrSize.iHeight != 0))
+ {
+ TReal widthScalingFactor =
+ (TReal)size.iWidth /
+ (TReal)orientedOrgMIDletScrSize.iWidth;
+
+ TReal heightScalingFactor =
+ (TReal)size.iHeight /
+ (TReal)orientedOrgMIDletScrSize.iHeight;
+
+ // Aspect ratio of MIDlet is same as display.
+ if (widthScalingFactor == heightScalingFactor)
+ {
+ viewSize.SetSize(size.iWidth, size.iHeight);
+ }
+ // Aspect ratio of MIDlet is "wider" than display.
+ else if (widthScalingFactor < heightScalingFactor)
+ {
+ viewSize.SetSize(size.iWidth,
+ widthScalingFactor * iContentSize.iHeight);
+ }
+ //Aspect ratio of MIDlet is "narrower" than display.
+ else
+ {
+ viewSize.SetSize(heightScalingFactor * iContentSize.iWidth,
+ size.iHeight);
+ }
+ }
+ // If JAD parameters for graphics scaling are not defined, Canvas
+ // won't be scaled.
+ else
+ {
+ viewSize = iContentSize;
+ }
+ }
+ // If Canvas is not in full screen mode, it won't be scaled.
+ else
+ {
+ viewSize = iContentSize;
+ }
+
+ TSize border = (size - viewSize);
+ TBool center = ((border.iWidth != 0) || (border.iHeight != 0));
+ TPoint viewPos = rect.iTl;
+
+ // Compute position of view rect in window.
+ //
+ // If content does not fill the control, center it, but try
+ // to keep the left hand pixel of content aligned to a word
+ // boundary of screen memory to enable faster blts.
+ if (center)
+ {
+ viewPos.iX += border.iWidth / 2;
+ viewPos.iY += border.iHeight / 2;
+
+ const TPoint screenPos = PositionRelativeToScreen();
+
+ // Align to 4-pixel boundary - this is overkill but covers both
+ // EColor256 and EColor4K. Should query graphics plugin for the
+ // alignment.
+ const TInt KAlignBoundary = 4;
+ TInt alignment = KAlignBoundary
+ - ((viewPos.iX + screenPos.iX) & 0x3);
+
+ // This alignment change is made to keep canvas as more center
+ // as it is possible. Alignment can have values between 0 and 4
+ // so if it have value more than 2, there is a -4 subtraction
+ // to prevent moving canvas too much to right side of display.
+ if (alignment > 2)
+ {
+ alignment -= KAlignBoundary;
+ }
+
+ viewPos.iX += alignment;
+
+ // Fallback to original position - we'll just have to take the
+ // unaligned bitblt performance hit.
+ if (viewPos.iX < rect.iTl.iX ||
+ (viewPos.iX + viewSize.iWidth) > rect.iBr.iX)
+ {
+ viewPos.iX -= alignment;
+ }
+ }
+
+ iViewRect = TRect(viewPos, viewSize);
+
+#ifdef CANVAS_DIRECT_ACCESS
+ StartDirectAccess();
+#endif // CANVAS_DIRECT_ACCESS
+
+ TInt contentsCount(iDirectContents.Count());
+
+ for (TInt j = 0; j < contentsCount; j++)
+ {
+ iDirectContents[j]->MdcContentBoundsChanged(
+ TRect(PositionRelativeToScreen(), Size()));
+ }
+
+ DEBUG_PROFILE("CMIDCanvas::Layout Canvas up and running \n");
+ DEBUG("- CMIDCanvas::Layout");
+}
+
+
+#ifdef CANVAS_DIRECT_ACCESS
+// ---------------------------------------------------------------------------
+// CMIDCanvas::DirectEnabled
+// Tells whether Direct Screen Access is enabled or disabled.
+// ---------------------------------------------------------------------------
+//
+inline TBool CMIDCanvas::DirectEnabled() const
+{
+ return iFlags & EDirectEnabled;
+}
+
+
+// ---------------------------------------------------------------------------
+// CMIDCanvas::DirectPaused
+// Tells whether Direct Screen Access is paused or not.
+// ---------------------------------------------------------------------------
+//
+inline TBool CMIDCanvas::DirectPaused() const
+{
+ return iFlags & EDirectPaused;
+}
+
+
+// ---------------------------------------------------------------------------
+// CMIDCanvas::UpdateRequired
+// Tells whether update is required or not.
+// ---------------------------------------------------------------------------
+//
+inline TBool CMIDCanvas::UpdateRequired() const
+{
+ return iFlags & EUpdateRequired;
+}
+#endif //CANVAS_DIRECT_ACCESS
+
+
+// ---------------------------------------------------------------------------
+// CMIDCanvas::PostKeyEvents
+// Tells whether posting of key events is enabled or disabled.
+// ---------------------------------------------------------------------------
+//
+inline TBool CMIDCanvas::PostKeyEvents() const
+{
+ return iFlags & EPostKeyEvents;
+}
+
+
+// ---------------------------------------------------------------------------
+// CMIDCanvas::GamePress
+// Process game press action.
+// ---------------------------------------------------------------------------
+//
+void CMIDCanvas::GamePress(TInt aGameAction)
+{
+ const TInt gameBit = 1 << aGameAction;
+ iGameKeyState |= gameBit;
+ iGameKeyLatch |= iGameKeyState;
+}
+
+
+// ---------------------------------------------------------------------------
+// CMIDCanvas::GameRelease
+// Process game release action.
+// ---------------------------------------------------------------------------
+//
+void CMIDCanvas::GameRelease(TInt aGameAction)
+{
+ const TInt gameBit = 1 << aGameAction;
+ iGameKeyState &= ~ gameBit;
+ iGameKeyLatch |= iGameKeyState;
+}
+
+
+// ---------------------------------------------------------------------------
+// CMIDCanvas::SetScalingFactors
+// Sets MIDlet's original size and target size resolutions if those are
+// defined in JAD or manifest. If attribute is missing or it's not defined
+// correctly, the value will be 0,0. This value is later used as an "error
+// value".
+// ---------------------------------------------------------------------------
+//
+void CMIDCanvas::SetScalingFactors()
+{
+ CMIDMenuHandler* menuHandler = iDisplayable->MenuHandler();
+
+ ASSERT(menuHandler);
+
+ iScalingOn = menuHandler->IsScalingEnabled();
+
+ iOrgMIDletScrSize = menuHandler->GetScalingParameterOrgMIDletScrSize();
+
+ iTargetMIDletScrSize =
+ menuHandler->GetScalingParameterTargetMIDletScrSize();
+
+ iScaleMIDletOnOrientSwitch =
+ menuHandler->GetScalingParameterScaleMIDletOnOrientSwitch();
+}
+
+
+// ---------------------------------------------------------------------------
+// CMIDCanvas::OrientedOrgMIDletScrSize
+// Returns original MIDlet screen size with regards to display orientation.
+// ---------------------------------------------------------------------------
+//
+TSize CMIDCanvas::OrientedOrgMIDletScrSize() const
+{
+ // Ensure that scaling and scaling-on-orientation-switch is enabled.
+ if (iScalingOn && iScaleMIDletOnOrientSwitch)
+ {
+ TSize orientedSize;
+
+ // Ensure that original size is defined as portrait.
+ if (iOrgMIDletScrSize.iWidth < iOrgMIDletScrSize.iHeight)
+ {
+ orientedSize = iOrgMIDletScrSize;
+ }
+ else
+ {
+ orientedSize.iWidth = iOrgMIDletScrSize.iHeight;
+ orientedSize.iHeight = iOrgMIDletScrSize.iWidth;
+ }
+
+ // Change original size orientation if actuall display orientation
+ // is landscape.
+ if (Layout_Meta_Data::IsLandscapeOrientation())
+ {
+ TInt swap = orientedSize.iWidth;
+ orientedSize.iWidth = orientedSize.iHeight;
+ orientedSize.iHeight = swap;
+ }
+
+ return orientedSize;
+ }
+ else
+ {
+ return iOrgMIDletScrSize;
+ }
+}
+
+// ---------------------------------------------------------------------------
+// CMIDCanvas::IsNetworkIndicatorEnabledL
+// Check if the network indicator should be shown in Canvas.
+// ---------------------------------------------------------------------------
+//
+TBool CMIDCanvas::IsNetworkIndicatorEnabledL() const
+{
+#ifndef RD_JAVA_S60_RELEASE_9_2
+ if (RProcess().SecureId().iId != 0x102033E6)
+ {
+ // For standalone type apps we don't show indicator.
+ return EFalse;
+ }
+ TBool enabled = ETrue; // Return ETrue by default.
+
+ std::auto_ptr<java::storage::JavaStorage> js(java::storage::JavaStorage::createInstance());
+ java::storage::JavaStorageApplicationEntry_t entries;
+ try
+ {
+ js->open();
+ java::util::Uid uid;
+ TUidToUid(iEnv.MidletSuiteUid(), uid);
+ js->read(java::storage::MIDP_PACKAGE_TABLE, uid, entries);
+ js->close();
+ }
+ catch (java::storage::JavaStorageException& ex)
+ {
+ DEBUG_INT("CMIDCanvas::IsNetworkIndicatorEnabledL: JavaStorage error: \
+ reading MIDP_PACKAGE_TABLE failed, error code = %D", ex.mStatus);
+ }
+ java::storage::JavaStorageEntry attribute;
+ attribute.setEntry(java::storage::SECURITY_DOMAIN_CATEGORY, L"");
+ java::storage::JavaStorageApplicationEntry_t::const_iterator findIterator = entries.find(attribute);
+ std::wstring res = L"";
+ if (findIterator != entries.end())
+ {
+ res = (*findIterator).entryValue();
+ }
+ entries.clear();
+
+ if (res == MANUFACTURER_DOMAIN_CATEGORY)
+ {
+ enabled = EFalse;
+ }
+ else if (res == OPERATOR_DOMAIN_CATEGORY)
+ {
+ // Read the central repository key to find out if the
+ // network indicator should be shown for midlets in
+ // operator domain.
+ CRepository* repository = NULL;
+ TRAPD(err, repository = CRepository::NewL(KCRUidMidpLcdui));
+
+ if (err == KErrNone)
+ {
+ err = repository->Get(KShowCanvasNetIndicatorInOperatorDomain, enabled);
+ if (err != KErrNone)
+ {
+ DEBUG_INT("CMIDCanvas::IsNetworkIndicatorEnabledL: \
+ reading CenRep key failed, error code = %D", err);
+ }
+ }
+
+ delete repository;
+ repository = NULL;
+ }
+
+ return enabled;
+#else
+// Network and Call indicator is disabled for 9_2
+ return EFalse;
+#endif //RD_JAVA_S60_RELEASE_9_2
+}
+
+// ---------------------------------------------------------------------------
+// CMIDCanvas::HandleForeground
+// Relases resources in graphics HW (=pixel source or EGL resources)
+// when going to background.
+// ---------------------------------------------------------------------------
+//
+void CMIDCanvas::HandleForeground(TBool aForeground)
+{
+ DEBUG_INT("CMIDCanvas::HandleForeground(%d) ++", aForeground);
+
+ // If foreground/background state is changed,
+ // then we need resize all custom components.
+ if (iForeground != aForeground && iCustomComponents.Count() > 0)
+ {
+ for (int i = 0; i < iCustomComponents.Count(); i++)
+ {
+ iCustomComponents[i]->HandleForeground(aForeground);
+ }
+ }
+
+ iForeground = aForeground;
+
+#ifdef RD_JAVA_NGA_ENABLED
+ if (!aForeground)
+ {
+ FreeGraphicsMemory(EFalse);
+ }
+#endif // RD_JAVA_NGA_ENABLED
+
+ DEBUG("CMIDCanvas::HandleForeground --");
+}
+
+#ifdef RD_JAVA_NGA_ENABLED
+// ---------------------------------------------------------------------------
+// CMIDCanvas::HandleFullOrPartialForegroundL
+// ---------------------------------------------------------------------------
+//
+void CMIDCanvas::HandleFullOrPartialForegroundL(
+ TBool aFullOrPartialFg, TBool aCurrentDisplayable)
+{
+ if (!aFullOrPartialFg && aCurrentDisplayable)
+ {
+ FreeGraphicsMemory(ETrue);
+ }
+ else if (!iPrevM3GContent && iAlfCompositionPixelSource)
+ {
+ SuspendPixelSource();
+ ActivatePixelSourceL(ETrue);
+ }
+}
+
+// ---------------------------------------------------------------------------
+// CMIDCanvas::FreeGraphicsMemory
+// Free GPU memory if the canvas is not visible anymore. If aForced is true,
+// visibility is not checked.
+// ---------------------------------------------------------------------------
+//
+void CMIDCanvas::FreeGraphicsMemory(TBool aForced)
+{
+ // No freeing in exit case to avoid flickering
+ if ((!aForced && IsWindowVisible()) || iExiting)
+ {
+ return;
+ }
+
+ if (IsEglAvailable())
+ {
+ if (iEglOccupied)
+ {
+ DEBUG("CMIDCanvas::FreeGraphcisMemory() - egl - pending dispose");
+ iEglPendingDispose = ETrue;
+ }
+ else
+ {
+ CloseEgl(ETrue);
+ // If MIDlet is not visible on foreground post event to Java
+ // so that M3G is notfied and frees the m3gCore memory
+ if (!iEnv.HasFullOrPartialForeground())
+ {
+ iEnv.PostMidletEvent(EFreeGraphicsMemory);
+ eglReleaseThread();
+ }
+ }
+ }
+
+ SuspendPixelSource();
+}
+
+// ---------------------------------------------------------------------------
+// CMIDCanvas::InitPixelSourceL()
+// ---------------------------------------------------------------------------
+//
+void CMIDCanvas::InitPixelSourceL()
+{
+ if (iAlfCompositionPixelSource)
+ {
+ return;
+ }
+ iPixelSourceSuspended = ETrue;
+ TBool modeSupported = EFalse;
+ switch (iFrameBuffer->DisplayMode())
+ {
+ case EColor16MU:
+ modeSupported = ETrue;
+ iAlfBufferAttributes.iFormat =
+ MAlfBufferProvider::ESourceFormatXRGB_8888;
+ break;
+ case EColor16MA:
+ modeSupported = ETrue;
+ iAlfBufferAttributes.iFormat =
+ MAlfBufferProvider::ESourceFormatARGB_8888;
+ break;
+ case EColor16MAP:
+ modeSupported = ETrue;
+ iAlfBufferAttributes.iFormat =
+ MAlfBufferProvider::ESourceFormatARGB_8888_PRE;
+ break;
+ default:
+ break;
+ }
+
+ if (modeSupported)
+ {
+ iAlfCompositionPixelSource = CAlfCompositionPixelSource::NewL(*this, &Window());
+
+ iAlfBufferAttributes.iWidth = iContentSize.iWidth;
+ iAlfBufferAttributes.iHeight = iContentSize.iHeight;
+ iAlfBufferAttributes.iStride = iAlfBufferAttributes.iWidth * KBytesPerPixel;
+ iAlfBufferAttributes.iAlignment = 32;
+ }
+}
+
+// ---------------------------------------------------------------------------
+// CMIDCanvas::DisposePixelSource
+// ---------------------------------------------------------------------------
+//
+void CMIDCanvas::DisposePixelSource()
+{
+ DEBUG("CMIDCanvas::DisposePixelSource ++");
+ NotifyMonitor();
+ if (iAlfCompositionPixelSource)
+ {
+ DEBUG("CMIDCanvas::DisposePixelSource - delete alf");
+ iAlfCompositionPixelSource->Suspend();
+ delete iAlfCompositionPixelSource;
+ iAlfCompositionPixelSource = NULL;
+ }
+ DEBUG("CMIDCanvas::DisposePixelSource --");
+}
+
+// ---------------------------------------------------------------------------
+// CMIDCanvas::ActivatePixelSourceL
+// In scaling case need to call SetExtent() again if pixel source was suspended.
+// ---------------------------------------------------------------------------
+//
+void CMIDCanvas::ActivatePixelSourceL(TBool aDrawingOngoing)
+{
+ ASSERT(iAlfCompositionPixelSource);
+
+ if (iDirectContents.Count() > 0)
+ {
+ return;
+ }
+
+ // Don't activate, if there is no valid content from Java yet
+ if (!ReadyToBlit())
+ {
+ return;
+ }
+
+ // ProduceNewFrameL() is called directly from ActivateSyncL()
+ // if pixel source is suspended, need to set iFrameReady
+ // before ActivateSyncL()
+ iFrameReady = ETrue;
+ TRAPD(err, iAlfCompositionPixelSource->ActivateSyncL());
+ if (err != KErrNone)
+ {
+ iFrameReady = EFalse;
+ User::Leave(err);
+ }
+
+ if (iPixelSourceSuspended)
+ {
+ iPixelSourceSuspended = EFalse;
+ if (iFullScreen && iScalingOn)
+ {
+ TRect targetRect = iViewRect;
+ targetRect.Move(iPositionRelativeToScreen);
+ iAlfCompositionPixelSource->SetExtent(targetRect, KPhoneScreen);
+ // Flag is set to in order that screen gets updated at least once
+ // after SetExtent() call
+ iFrameReady = ETrue;
+ }
+
+ if (!aDrawingOngoing)
+ {
+ ClearUiSurface(aDrawingOngoing);
+ iCoeEnv->WsSession().Finish();
+ }
+ }
+}
+
+// ---------------------------------------------------------------------------
+// CMIDCanvas::ClearUiSurface
+// ---------------------------------------------------------------------------
+//
+void CMIDCanvas::ClearUiSurface(TBool aDrawing)
+{
+ if (!aDrawing)
+ {
+ Window().BeginRedraw();
+ ActivateGc();
+ }
+ CWindowGc& gc = SystemGc();
+ gc.SetBrushColor(KTransparentClearColor);
+ gc.SetDrawMode(CGraphicsContext::EDrawModeWriteAlpha);
+ gc.Clear();
+
+ // Clearing is done via EGL in scaled M3G case
+ if (iScalingOn && iFullScreen && !IsEglAvailable())
+ {
+ const TRect rect = Rect();
+ if (rect != iViewRect)
+ {
+ gc.SetBrushColor(KRgbBlack);
+ gc.SetBrushStyle(CGraphicsContext::ESolidBrush);
+ DrawUtils::ClearBetweenRects(gc, rect, iViewRect);
+ }
+ }
+
+ if (!aDrawing)
+ {
+ DeactivateGc();
+ Window().EndRedraw();
+ }
+}
+
+// ---------------------------------------------------------------------------
+// CMIDCanvas::DrawToWindowGc
+// Draws current frame buffer content to CWindowGc
+// ---------------------------------------------------------------------------
+//
+void CMIDCanvas::DrawToWindowGc()
+{
+ if (iDirectContents.Count() > 0 ||
+ !IsWindowVisible() ||
+ !iForeground)
+ {
+ return;
+ }
+
+ Window().BeginRedraw();
+ ActivateGc();
+
+ TRect rect = (iFullScreen && iScalingOn) ? iViewRect : Rect();
+ DrawWindow(rect);
+
+ DeactivateGc();
+ Window().EndRedraw();
+
+ iCoeEnv->WsSession().Finish();
+}
+
+// ---------------------------------------------------------------------------
+// CMIDCanvas::SuspendPixelSource
+// ---------------------------------------------------------------------------
+//
+void CMIDCanvas::SuspendPixelSource()
+{
+ NotifyMonitor();
+ if (iAlfCompositionPixelSource && !iPixelSourceSuspended)
+ {
+ iAlfCompositionPixelSource->Suspend();
+ iPixelSourceSuspended = ETrue;
+ }
+}
+
+// ---------------------------------------------------------------------------
+// CMIDCanvas::NotifyMonitor
+// CMIDCanvas::ProcessL() is asyncronous when CAlfCompositionPixelSource is used.
+// This notiCMIDBuffer's monitor so that waiting Java thread is resumed.
+// ---------------------------------------------------------------------------
+//
+void CMIDCanvas::NotifyMonitor()
+{
+ if (iAlfMonitor)
+ {
+ iAlfMonitor->notify();
+ iAlfMonitor = NULL;
+ }
+ iFrameReady = EFalse;
+}
+
+// ---------------------------------------------------------------------------
+// From MAlfBufferProvider
+// CMIDCanvas::ProduceNewFrameL
+// Callback from CAlfCompositionPixelSource. Copy RGB data from framebuffer
+// to pixel source's buffer. Return ETrue if we have a frame ready,
+// EFalse otherwise.
+// ---------------------------------------------------------------------------
+//
+TBool CMIDCanvas::ProduceNewFrameL(const TRegion& aVisibleRegion, TUint8*& aBuffer)
+{
+ DEBUG_INT("CMIDCanvas::ProduceNewFrameL (thread=%d) ++", RThread().Id().Id());
+ TRect bbox(aVisibleRegion.BoundingRect());
+ DEBUG_INT4("CMIDCanvas::ProduceNewFrameL - visible region(x=%d, y=%d, w=%d, h=%d) ++",
+ bbox.iTl.iX, bbox.iTl.iY, bbox.Width(), bbox.Height());
+
+ // If iDirectContents.Count() > 0, canvas hasn't received
+ // MdcNotifyContentAdded in LCDUI thread yet.
+ TBool res;
+ if (!iFrameReady || iDirectContents.Count() > 0)
+ {
+ DEBUG("CMIDCanvas::ProduceNewFrameL - FRAME IS NOT READY --");
+ NotifyMonitor();
+ res = EFalse;
+ }
+ else
+ {
+ NotifyMonitor();
+
+ TUint8* from = (TUint8*)iFrameBuffer->DataAddress();
+
+ TBool downScaling = IsDownScaling(iContentSize, iViewRect, iM3GContent);
+ TInt width = downScaling ? iViewRect.Width() : iContentSize.iWidth;
+ TInt height = downScaling ? iViewRect.Height() : iContentSize.iHeight;
+
+ TUint bytes = width * KBytesPerPixel;
+ TInt scanLength = CFbsBitmap::ScanLineLength(
+ iFrameBuffer->SizeInPixels().iWidth, iFrameBuffer->DisplayMode());
+
+ for (TInt y = 0; y < height; ++y)
+ {
+ Mem::Copy(aBuffer, from, bytes);
+ aBuffer += iAlfBufferAttributes.iStride;
+ from += scanLength;
+ }
+
+ res = ETrue;
+ }
+
+ if (iFirstPaintState == EFirstPaintInitiated || iFirstPaintState == EFirstPaintPrepared)
+ {
+ if (iFirstPaintState == EFirstPaintInitiated)
+ {
+ iFirstPaintState = EFirstPaintPrepared;
+ }
+ else
+ {
+ iFirstPaintState = EFirstPaintOccurred;
+ java::ui::CoreUiAvkonLcdui::getInstance().getJavaUiAppUi()->stopStartScreen();
+ }
+ }
+
+ DEBUG("CMIDCanvas::ProduceNewFrameL --");
+
+ return res;
+}
+
+// ---------------------------------------------------------------------------
+// From MAlfBufferProvider
+// CMIDCanvas::BufferAttributes
+// Called by CAlfCompositionPixelSource to get the size of RGB data.
+// ---------------------------------------------------------------------------
+//
+MAlfBufferProvider::TBufferCreationAttributes& CMIDCanvas::BufferAttributes()
+{
+ DEBUG_INT2("CMIDCanvas::BufferAttributes - iContentSize(w=%d, h=%d) ++",
+ iContentSize.iWidth, iContentSize.iHeight);
+
+ TBool downScaling = IsDownScaling(iContentSize, iViewRect, iM3GContent);
+ iAlfBufferAttributes.iWidth = downScaling ? iViewRect.Width() : iContentSize.iWidth;
+ iAlfBufferAttributes.iHeight = downScaling ? iViewRect.Height() : iContentSize.iHeight;
+
+ iAlfBufferAttributes.iStride = iAlfBufferAttributes.iWidth * KBytesPerPixel;
+ return iAlfBufferAttributes;
+}
+
+// ---------------------------------------------------------------------------
+// From MAlfBufferProvider
+// CMIDCanvas::ContextAboutToSuspend
+// Notification from Alf.
+// ---------------------------------------------------------------------------
+//
+void CMIDCanvas::ContextAboutToSuspend()
+{
+ DEBUG("CMIDCanvas::ContextAboutToSuspend() ++");
+ NotifyMonitor();
+ iPixelSourceSuspended = ETrue;
+ DEBUG("CMIDCanvas::ContextAboutToSuspend() --");
+}
+
+// ---------------------------------------------------------------------------
+// From MAlfBufferProvider
+// CMIDCanvas::OnActivation
+// Notification from Alf.
+// ---------------------------------------------------------------------------
+//
+void CMIDCanvas::OnActivation()
+{
+ DEBUG("CMIDCanvas::OnActivation()++--");
+}
+
+
+// ---------------------------------------------------------------------------
+// CMIDCanvas::OpenEglL
+// Creates EGL window surface and context. Only 32 bit display modes are
+// supported.
+// ---------------------------------------------------------------------------
+//
+void CMIDCanvas::OpenEglL()
+{
+ if (IsEglAvailable())
+ {
+ return;
+ }
+
+ DEBUG("CMIDCanvas::OpenEglL() ++");
+
+ if (iEglDisplay == EGL_NO_DISPLAY)
+ {
+ iEglDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY);
+
+ // Initializing an already initialized display has no effect.
+ // eglTerminate is not called in LCDUI side ever, only by M3G
+ if (eglInitialize(iEglDisplay, NULL, NULL) == EGL_FALSE)
+ {
+ ELOG1(EJavaUI, "eglInitialize() failed, eglError=%d", eglGetError());
+ User::Leave(KErrNotSupported);
+ }
+ }
+
+ RWindow& window = Window();
+ // Choose the buffer size based on the Window's display mode.
+ TDisplayMode displayMode = window.DisplayMode();
+ TInt bufferSize = 0;
+ switch (displayMode)
+ {
+ case(EColor16MU):
+ case(EColor16MA):
+ case(EColor16MAP):
+ bufferSize = 32;
+ break;
+ default:
+ ELOG1(EJavaUI, "CMIDCanvas::OpenEglL(): unsupported window display mode %d",
+ displayMode);
+ User::Leave(KErrNotSupported);
+ break;
+ }
+
+ EGLint surfaceType = EGL_WINDOW_BIT | EGL_SWAP_BEHAVIOR_PRESERVED_BIT;
+
+ const EGLint attributeList[] =
+ {
+ EGL_SURFACE_TYPE, surfaceType,
+ EGL_RED_SIZE, 8,
+ EGL_GREEN_SIZE, 8,
+ EGL_BLUE_SIZE, 8,
+ EGL_ALPHA_SIZE, 8,
+ EGL_BUFFER_SIZE, bufferSize,
+ EGL_TRANSPARENT_TYPE, EGL_NONE,
+ EGL_DEPTH_SIZE, 16,
+ EGL_NONE
+ };
+
+ EGLint numConfigs = 0;
+
+ // Choose the best EGLConfig that matches the desired properties.
+ if ((eglChooseConfig(iEglDisplay, attributeList, &iEglConfig, 1, &numConfigs) == EGL_FALSE) ||
+ numConfigs == 0)
+ {
+ ELOG1(EJavaUI, "eglChooseConfig() failed, eglError=%d", eglGetError());
+ User::Leave(KErrNotSupported);
+ }
+
+ // Check that surface content is preserved in swap, otherwise the
+ // game canvas content cannot be preserved.
+ eglGetConfigAttrib(iEglDisplay, iEglConfig, EGL_SURFACE_TYPE, &surfaceType);
+ if (surfaceType & EGL_SWAP_BEHAVIOR_PRESERVED_BIT == 0)
+ {
+ ELOG(EJavaUI, "Egl config does not support EGL_SWAP_BEHAVIOR_PRESERVED_BIT");
+ User::Leave(KErrNotSupported);
+ }
+
+ // Create a window surface where the graphics are blitted.
+ // Pass the Native Window handle to egl.
+ iEglWindowSurface = eglCreateWindowSurface(iEglDisplay, iEglConfig, (void*)&window, NULL);
+ if (iEglWindowSurface == EGL_NO_SURFACE)
+ {
+ ELOG1(EJavaUI, "eglCreateWindowSurface() failed, eglError=%d", eglGetError());
+ User::Leave(KErrNoMemory);
+ }
+ // Need to preserve surface content after swapping
+ eglSurfaceAttrib(iEglDisplay, iEglWindowSurface, EGL_SWAP_BEHAVIOR, EGL_BUFFER_PRESERVED);
+
+ CreateEglContext();
+ ClearEglSurface(EEglWindow);
+
+ // Allocate memory for ARGB->RGBA conversion needed by
+ // openGL texture
+ if (!iTexturePixels)
+ {
+ iTexturePixels = new(ELeave) TUint8[KMaxBlitSize * KMaxBlitSize * KBytesPerPixel];
+ }
+ glDisable(GL_DEPTH_TEST);
+ glDisable(GL_LIGHTING);
+ glEnableClientState(GL_VERTEX_ARRAY);
+ if (!iVertexArray)
+ {
+ iVertexArray = new(ELeave) GLshort[8];
+ }
+ if (!iTriangleStrip)
+ {
+ iTriangleStrip = new(ELeave) GLubyte[4];
+ iTriangleStrip[0] = 0;
+ iTriangleStrip[1] = 1;
+ iTriangleStrip[2] = 3;
+ iTriangleStrip[3] = 2;
+ }
+ DEBUG("CMIDCanvas::OpenEglL() --");
+}
+
+// ---------------------------------------------------------------------------
+// CMIDCanvas::CloseEgl
+// Destroys EGL contexts and surfaces.
+// ---------------------------------------------------------------------------
+//
+void CMIDCanvas::CloseEgl(TBool aReadback)
+{
+ DEBUG("CMIDCanvas::CloseEglL() ++");
+
+ iM3GContent = EFalse;
+ iM3GStart = EFalse;
+ iEglPendingResize = EFalse;
+ iEglPendingDispose = EFalse;
+ PostEvent(EM3GDraw, iM3GContent, 0);
+ if (iEglDisplay == EGL_NO_DISPLAY)
+ {
+ return;
+ }
+
+ // MIDlet might draw only 2D after this =>
+ // need to set frame buffer opaque to be compatible with
+ // blending methods in Lcdgd. UpdateOffScreenBitmapL() does this too.
+ if (!aReadback && iFrameContext)
+ {
+ iFrameContext->SetBrushColor(KOpaqueClearColor);
+ iFrameContext->SetDrawMode(CGraphicsContext::EDrawModeWriteAlpha);
+ iFrameContext->Clear();
+ }
+
+ // Take a snapshot from window surface to the frame buffer.
+ if (aReadback)
+ {
+ TRAPD(err, UpdateOffScreenBitmapL(ETrue));
+ if (err != KErrNone)
+ {
+ DEBUG("CMIDCanvas::CloseEgl() - UpdateOffScreenBitmapL() failed");
+ }
+ }
+
+ // make sure the we have no current target
+ // so that surfaces and contexts are destoyed immediately
+ SetCurrentEglType(EEglNone);
+
+ // If pbuffer has been created dispose that here
+ if (iEglPbufferSurfaceContext != EGL_NO_CONTEXT ||
+ iEglPbufferSurface != EGL_NO_SURFACE)
+ {
+ DisposePBufferSurface();
+ }
+
+ if (iEglWindowSurfaceContext != EGL_NO_CONTEXT)
+ {
+ eglDestroyContext(iEglDisplay, iEglWindowSurfaceContext);
+ iEglWindowSurfaceContext = EGL_NO_CONTEXT;
+ }
+ if (iEglWindowSurface != EGL_NO_SURFACE)
+ {
+ eglDestroySurface(iEglDisplay, iEglWindowSurface);
+ iEglWindowSurface = EGL_NO_SURFACE;
+ }
+
+ DEBUG("CMIDCanvas::CloseEglL() --");
+}
+
+// ---------------------------------------------------------------------------
+// CMIDCanvas::CreateEglContext
+// (Re)create EGL context
+// ---------------------------------------------------------------------------
+//
+void CMIDCanvas::CreateEglContext()
+{
+ if (iEglWindowSurfaceContext != EGL_NO_CONTEXT)
+ {
+ SetCurrentEglType(EEglNone);
+ eglDestroyContext(iEglDisplay, iEglWindowSurfaceContext);
+ iEglWindowSurfaceContext = EGL_NO_CONTEXT;
+ }
+ // Create a rendering context
+ iEglWindowSurfaceContext = eglCreateContext(iEglDisplay, iEglConfig, EGL_NO_CONTEXT, NULL);
+ if (iEglWindowSurfaceContext == EGL_NO_CONTEXT)
+ {
+ ELOG1(EJavaUI, "eglCreateContext() failed, eglError=%d", eglGetError());
+ }
+}
+
+// ---------------------------------------------------------------------------
+// CMIDCanvas::SetCurrentEglType
+// Sets the current EGL context and surface.
+// ---------------------------------------------------------------------------
+//
+TBool CMIDCanvas::SetCurrentEglType(TEglType aType)
+{
+ EGLBoolean res = EGL_TRUE;
+ if (aType == EEglPbuffer)
+ {
+ res = eglMakeCurrent(
+ iEglDisplay, iEglPbufferSurface, iEglPbufferSurface, iEglPbufferSurfaceContext);
+ }
+ else if (aType == EEglWindow)
+ {
+ res = eglMakeCurrent(
+ iEglDisplay, iEglWindowSurface, iEglWindowSurface, iEglWindowSurfaceContext);
+ }
+ else
+ {
+ res = eglMakeCurrent(
+ iEglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
+ }
+ if (res == EGL_FALSE)
+ {
+ ELOG1(EJavaUI, "eglMakeCurrent() failed, eglError=%s", GetEglError(eglGetError()).Ptr());
+ }
+ return (res == EGL_FALSE ? EFalse : ETrue);
+}
+
+// ---------------------------------------------------------------------------
+// CMIDCanvas::GetCurrentEgl
+// Gets the current EGL type
+// ---------------------------------------------------------------------------
+//
+CMIDCanvas::TEglType CMIDCanvas::GetCurrentEglType()
+{
+ EGLSurface surface = eglGetCurrentSurface(EGL_READ);
+ if (surface == EGL_NO_SURFACE)
+ {
+ return EEglNone;
+ }
+ else if (surface == iEglPbufferSurface)
+ {
+ return EEglPbuffer;
+ }
+ else
+ {
+ return EEglWindow;
+ }
+}
+
+// ---------------------------------------------------------------------------
+// CMIDCanvas::GetEglSurfaceSize
+// Returns size of the EGL surface.
+// ---------------------------------------------------------------------------
+//
+TSize CMIDCanvas::GetEglSurfaceSize(EGLSurface aSurface)
+{
+ TSize sz;
+ if (aSurface == EGL_NO_SURFACE)
+ {
+ aSurface = iEglWindowSurface;
+ if (iScalingOn && iFullScreen)
+ {
+ aSurface = iEglPbufferSurface;
+ }
+ }
+ if (!(eglQuerySurface(iEglDisplay, aSurface, EGL_WIDTH, &sz.iWidth) &&
+ eglQuerySurface(iEglDisplay, aSurface, EGL_HEIGHT, &sz.iHeight)))
+ {
+ sz.SetSize(0, 0);
+ }
+ DEBUG_INT2("CMIDCanvas::GetEglSurfaceSizeL() - w=%d, h=%d", sz.iWidth, sz.iHeight);
+ return sz;
+}
+
+// ---------------------------------------------------------------------------
+// CMIDCanvas::HandleSizeChanged()
+// EGL cannot handle window resize upwards and in this case we need to
+// recreate the surface. If recreation is needed (and M3G is not using our
+// surface) EGL context and surface are destoryed here and recreated in
+// next ProcessL() when M3G_CONTENT_START is recieved from Java side.
+// ---------------------------------------------------------------------------
+//
+void CMIDCanvas::HandleSizeChanged(TBool aOrientationChange)
+{
+ DEBUG("CMIDCanvas::HandleSizeChanged ++");
+
+ SuspendPixelSource();
+
+ if (IsEglAvailable())
+ {
+ TSize surfaceSize = GetEglSurfaceSize(iEglWindowSurface);
+ TSize controlSize = Size();
+ if (aOrientationChange ||
+ surfaceSize.iHeight < controlSize.iHeight ||
+ surfaceSize.iWidth < controlSize.iWidth)
+ {
+ // Check if egl surface is currently occupied.
+ if (iEglOccupied)
+ {
+ // Delayed resizing. It is done when the ReleaseEglSurface method
+ // is called.
+ iEglPendingResize = ETrue;
+ }
+ else
+ {
+ // Surface recreation is done in next ProcessL() call
+ // No readback from EGL, because canvas needs to
+ // repaint itself anyway in new size
+ CloseEgl(EFalse);
+ }
+ }
+ }
+ DEBUG("CMIDCanvas::HandleSizeChanged --");
+}
+
+// ---------------------------------------------------------------------------
+// From MMIDComponentNgaExtension
+// CMIDCanvas::UpdateEglContent
+// Renders current 2D content in frame buffer as an OpenGL texture to
+// EGL surface. If scaling is on, renders to pbuffer, otherwise to window surface.
+// Called from M3G (via CMIDGraphics) when EGL surface needs to be updated with
+// 2D content. This will not be called if M3G Background is used for clearing
+// entire canvas area.
+// ---------------------------------------------------------------------------
+//
+void CMIDCanvas::UpdateEglContent()
+{
+ if (!IsEglAvailable())
+ {
+ return;
+ }
+
+ DEBUG("CMIDCanvas::UpdateEglContent() ++");
+
+ // If scaling update framebuffer to pbuffer, otherwise to windowsurface
+ if (iScalingOn && iFullScreen)
+ {
+ SetCurrentEglType(EEglPbuffer);
+ }
+ else
+ {
+ SetCurrentEglType(EEglWindow);
+ }
+ BlitFrameBufferPixels();
+ SetCurrentEglType(EEglNone);
+
+ DEBUG("CMIDCanvas::UpdateEglContent() --");
+}
+
+// ---------------------------------------------------------------------------
+// From MMIDComponentNgaExtension
+// CMIDCanvas::IsEglAvailable
+// Return ETrue, if EGL based drawing is in use.
+// ---------------------------------------------------------------------------
+//
+TBool CMIDCanvas::IsEglAvailable() const
+{
+ return (iEglWindowSurface != EGL_NO_SURFACE);
+}
+
+// ---------------------------------------------------------------------------
+// From MMIDComponentNgaExtension
+// CMIDCanvas::BindEglSurface
+// Called from M3G (via CMIDGraphics) when M3G binds to canvas
+// graphics rendering target.
+// ---------------------------------------------------------------------------
+//
+EGLSurface CMIDCanvas::BindEglSurface()
+{
+ if (IsEglAvailable())
+ {
+ iEglOccupied = ETrue;
+ }
+
+ if (iScalingOn && iFullScreen)
+ {
+ return iEglPbufferSurface;
+ }
+ return iEglWindowSurface;
+}
+
+// ---------------------------------------------------------------------------
+// From MMIDComponentNgaExtension
+// CMIDCanvas::ReleaseEglSurface
+// Called from M3G (via CMIDGraphics) when M3G releases canvas
+// graphics rendering target.
+// ---------------------------------------------------------------------------
+//
+void CMIDCanvas::ReleaseEglSurface()
+{
+ iEglOccupied = EFalse;
+ if (IsEglAvailable())
+ {
+ // Pending dispose. Egl context must be released.
+ if (iEglPendingDispose)
+ {
+ DEBUG("CMIDCanvas::ReleaseEglSurface() - dispose egl");
+ FreeGraphicsMemory(ETrue);
+ }
+ else if (iEglPendingResize)
+ {
+ DEBUG("CMIDCanvas::ReleaseEglSurface() - pending resize");
+ HandleSizeChanged(ETrue);
+ }
+
+ if (IsEglAvailable())
+ {
+ ClearFrameBuffer();
+ }
+ }
+}
+
+// ---------------------------------------------------------------------------
+// From MMIDComponentNgaExtension
+// CMIDCanvas::UpdateOffScreenBitmap()
+// ---------------------------------------------------------------------------
+//
+void CMIDCanvas::UpdateOffScreenBitmapL(TBool aForced)
+{
+ if (IsEglAvailable() && iFrameContext && (IsGameCanvas() || aForced))
+ {
+ DEBUG("CMIDCanvas::UpdateOffScreenBitmapL() ++");
+
+ UpdateEglContent();
+
+ EGLSurface surface = EGL_NO_SURFACE;
+ TEglType current = GetCurrentEglType();
+
+ if (iScalingOn && iFullScreen)
+ {
+ SetCurrentEglType(EEglPbuffer);
+ surface = iEglPbufferSurface;
+ }
+ else
+ {
+ SetCurrentEglType(EEglWindow);
+ surface = iEglWindowSurface;
+ }
+
+ CFbsBitmap* bitmap = new(ELeave) CFbsBitmap;
+ CleanupStack::PushL(bitmap);
+ User::LeaveIfError(bitmap->Create(
+ GetEglSurfaceSize(surface), iEnv.DisplayMode()));
+
+ if (EGL_FALSE == eglCopyBuffers(iEglDisplay, surface, bitmap))
+ {
+ ELOG1(EJavaUI, "eglCopyBuffers() failed, eglError=%s",
+ GetEglError(eglGetError()).Ptr());
+ User::Leave(KErrUnknown);
+ }
+
+ // Clear with opaque black so that EDrawModeOR can be used in BitBlt()
+ iFrameContext->SetBrushColor(KOpaqueBlackColor);
+ iFrameContext->SetDrawMode(CGraphicsContext::EDrawModeWriteAlpha);
+ iFrameContext->Clear();
+ iFrameContext->SetDrawMode(CGraphicsContext::EDrawModeOR);
+ iFrameContext->BitBlt(TPoint(), bitmap);
+ CleanupStack::PopAndDestroy();
+ SetCurrentEglType(current);
+
+ // Make sure that full Canvas area
+ // is made transparent in next ClearFrameBuffer() call.
+ // This is needed in case UpdateOffScreenBitmapL is called
+ // from Nokia UI API
+ iUpperUpdateRect = TRect(Size());
+
+ DEBUG("CMIDCanvas::UpdateOffScreenBitmapL() --");
+ }
+}
+
+// ---------------------------------------------------------------------------
+// From MMIDComponentNgaExtension
+// CMIDCanvas::UpdateOffScreenBitmap()
+// ---------------------------------------------------------------------------
+//
+TBool CMIDCanvas::FillEglSurface(const TRect& aRect, const TRgb& aColor)
+{
+ if (!IsEglAvailable() ||
+ !iUpperUpdateRect.IsEmpty() ||
+ !iLowerUpdateRect.IsEmpty())
+ {
+ return EFalse;
+ }
+ TSize sz(this->GetEglSurfaceSize());
+ if (aRect.Width() >= sz.iWidth && aRect.Height() >= sz.iHeight)
+ {
+ return ClearEglSurface(EEglNone, &aColor);
+ }
+ TEglType current = GetCurrentEglType();
+ if (iScalingOn && iFullScreen)
+ {
+ if (current != EEglPbuffer)
+ {
+ SetCurrentEglType(EEglPbuffer);
+ }
+ }
+ else if (current != EEglWindow)
+ {
+ SetCurrentEglType(EEglWindow);
+ }
+ InitOpenGl(ETrue);
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ glVertexPointer(2, GL_SHORT, 0, iVertexArray);
+ iVertexArray[0] = aRect.iTl.iX;
+ iVertexArray[1] = aRect.iTl.iY;
+
+ iVertexArray[2] = aRect.iBr.iX;
+ iVertexArray[3] = aRect.iTl.iY;
+
+ iVertexArray[4] = iVertexArray[2];
+ iVertexArray[5] = aRect.iBr.iY;
+
+ iVertexArray[6] = iVertexArray[0];
+ iVertexArray[7] = iVertexArray[5];
+
+ glColor4f(
+ aColor.Red() / 255.0f, aColor.Green() / 255.0f,
+ aColor.Blue() / 255.0f, aColor.Alpha() / 255.0f);
+
+ glDrawElements(GL_TRIANGLE_STRIP, 4, GL_UNSIGNED_BYTE, iTriangleStrip);
+ SetCurrentEglType(EEglNone);
+ return ETrue;
+}
+
+// ---------------------------------------------------------------------------
+// From CMIDCanvas
+// CMIDCanvas::ClearEglSurface
+// ---------------------------------------------------------------------------
+//
+TBool CMIDCanvas::ClearEglSurface(
+ CMIDCanvas::TEglType aSurfaceType, const TRgb* aRgba)
+{
+ if (!IsEglAvailable())
+ {
+ return EFalse;
+ }
+ TEglType current = GetCurrentEglType();
+ if (aSurfaceType == EEglNone || !aRgba)
+ {
+ if (iScalingOn && iFullScreen)
+ {
+ if (aSurfaceType == EEglNone)
+ {
+ aSurfaceType = EEglPbuffer;
+ }
+ if (!aRgba)
+ {
+ glClearColor(0.f, 0.f, 0.f, 1.f);
+ }
+ }
+ else
+ {
+ if (aSurfaceType == EEglNone)
+ {
+ aSurfaceType = EEglWindow;
+ }
+ if (!aRgba)
+ {
+ glClearColor(1.f, 1.f, 1.f, 1.f);
+ }
+ }
+ }
+ SetCurrentEglType(aSurfaceType);
+ if (aRgba)
+ {
+ glClearColor(
+ aRgba->Red() / 255.f, aRgba->Green() / 255.0f,
+ aRgba->Blue() / 255.0f, aRgba->Alpha() / 255.0f);
+ }
+ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+ SetCurrentEglType(current);
+ return ETrue;
+}
+
+// ---------------------------------------------------------------------------
+// From MMIDCanvas
+// CMIDCanvas::UpdateRect
+// Notifies canvas about which areas have been updated with 2D content.
+// ---------------------------------------------------------------------------
+//
+void CMIDCanvas::UpdateRect(const TRect& aRect)
+{
+ if (aRect.IsEmpty())
+ {
+ return;
+ }
+
+ TRect rect(aRect);
+ TRect canvasRect = IsDownScaling(iContentSize, iViewRect, iM3GContent) ?
+ TRect(iViewRect.Size()) : TRect(iContentSize);
+ rect.Intersection(canvasRect);
+ // Checking if rect have intersection with frameRect
+ TRect frameRect(TPoint(), iFrameBuffer->SizeInPixels());
+ if (!rect.Intersects(frameRect))
+ {
+ return;
+ }
+ rect.Intersection(frameRect);
+ if (rect.IsEmpty())
+ {
+ return;
+ }
+
+ // Update the member rects
+ if (iUpperUpdateRect.Intersects(rect))
+ {
+ iUpperUpdateRect.BoundingRect(rect);
+ }
+ else if (iLowerUpdateRect.Intersects(rect))
+ {
+ iLowerUpdateRect.BoundingRect(rect);
+ }
+ // If rect is fully in the lower half of canvas,
+ // merge it with iLowerUpdateRect, otherwise with iUpperUpdateRect
+ else if (rect.iTl.iY > canvasRect.Height() / 2)
+ {
+ if (iLowerUpdateRect.IsEmpty())
+ {
+ iLowerUpdateRect = rect;
+ }
+ else
+ {
+ iLowerUpdateRect.BoundingRect(rect);
+ }
+ }
+ else
+ {
+ if (iUpperUpdateRect.IsEmpty())
+ {
+ iUpperUpdateRect = rect;
+ }
+ else
+ {
+ iUpperUpdateRect.BoundingRect(rect);
+ }
+ }
+}
+
+// ---------------------------------------------------------------------------
+// From MMIDCanvas
+// CMIDCanvas::MidletExiting
+// Draws content to CWindowGc to enable the system effect on MIDlet exit.
+// Canvas might be in the middle of rendering new frame when this is called.
+// Having incomplete frame on screen in some exit cases is anyway better than
+// fully black always.
+// ---------------------------------------------------------------------------
+//
+void CMIDCanvas::MidletExiting()
+{
+ iExiting = ETrue;
+ TRAP_IGNORE(UpdateOffScreenBitmapL(ETrue));
+ DrawToWindowGc();
+}
+
+// ---------------------------------------------------------------------------
+// CMIDCanvas::BlitFrameBufferPixels
+// Sets up OpenGL state for 2D texture rendering and renders the textures for
+// updated frame buffer areas by calling BlitSubRect().
+// ---------------------------------------------------------------------------
+//
+void CMIDCanvas::BlitFrameBufferPixels()
+{
+ if (iUpperUpdateRect.IsEmpty() && iLowerUpdateRect.IsEmpty())
+ {
+ return;
+ }
+ InitOpenGl();
+ // Must use this blending function because frame buffer
+ // content is in pre-multiplied ARGB format.
+ // See alpha blending in Lcdgd, lcdc16ma.cpp.
+ glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
+
+ glEnable(GL_ALPHA_TEST);
+ glAlphaFunc(GL_GREATER, 0.0f);
+
+ // Disable any stray state we don't want
+ glDisable(GL_CULL_FACE);
+ glDisableClientState(GL_NORMAL_ARRAY);
+ glDisableClientState(GL_COLOR_ARRAY);
+ glDisable(GL_LIGHTING);
+ glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
+ glDepthMask(GL_FALSE);
+ glDepthFunc(GL_ALWAYS);
+
+ ASSERT_GL();
+
+ if (iUpperUpdateRect.Intersects(iLowerUpdateRect))
+ {
+ iUpperUpdateRect.BoundingRect(iLowerUpdateRect);
+ iLowerUpdateRect = TRect();
+ BlitSubRect(iUpperUpdateRect);
+ }
+ else
+ {
+ BlitSubRect(iUpperUpdateRect);
+ BlitSubRect(iLowerUpdateRect);
+ }
+
+ ClearFrameBuffer();
+}
+
+// ---------------------------------------------------------------------------
+// CMIDCanvas::InitOpenGl
+// Initiazes OpenGL before 2d rendering
+// ---------------------------------------------------------------------------
+//
+TSize CMIDCanvas::InitOpenGl(TBool aTopLeftOrigo, const TRect* aRect)
+{
+ // scaling is on the framebuffer is blitted to pbuffer instead of
+ // window surface so get the size of appropriate surface for
+ // setting correct values for viewport, projection etc.
+ TSize size = GetEglSurfaceSize();
+ glViewport(0, 0, size.iWidth, size.iHeight);
+ if (aRect)
+ {
+ glScissor(aRect->iTl.iX, aRect->iTl.iY, aRect->Width(), aRect->Height());
+ }
+ else
+ {
+ glScissor(0, 0, size.iWidth, size.iHeight);
+ }
+ glEnable(GL_BLEND);
+ glMatrixMode(GL_PROJECTION);
+ glLoadIdentity();
+ // Checks where the origo should be
+ if (aTopLeftOrigo)
+ {
+ // Top-left
+ glOrthof(0, TReal32(size.iWidth), TReal32(size.iHeight), 0.f, -1.f, 1.f);
+ }
+ else
+ {
+ // Bottom-left
+ glOrthox(0, size.iWidth << 16, 0, size.iHeight << 16, -1 << 16, 1 << 16);
+ }
+ glMatrixMode(GL_MODELVIEW);
+ glLoadIdentity();
+ glDisable(GL_DEPTH_TEST);
+ glEnableClientState(GL_VERTEX_ARRAY);
+ glDisable(GL_LIGHTING);
+ glDepthMask(GL_FALSE);
+ glDepthFunc(GL_ALWAYS);
+ return size;
+}
+
+// ---------------------------------------------------------------------------
+// CMIDCanvas::BlitSubRect
+// OpenGL texture dimensions must be powers of 2. Devides aRect into smaller
+// areas for texture rendering so that texture dimensions won't exceed
+// KMaxBlitSize.
+// ---------------------------------------------------------------------------
+//
+void CMIDCanvas::BlitSubRect(const TRect& aRect)
+{
+ if (aRect.IsEmpty())
+ {
+ return;
+ }
+
+ // OpenGL coordinate origin is in bottom left corner of screen
+ TInt yOffset = iContentSize.iHeight - aRect.iBr.iY;
+ TInt xOffset = aRect.iTl.iX;
+ TInt width = aRect.Width();
+ TInt height = aRect.Height();
+
+ TInt canvasHeight = iContentSize.iHeight;
+
+ TInt xBlits = (width == KMaxBlitSize) ? 1 : (width / KMaxBlitSize) + 1;
+ TInt yBlits = (height == KMaxBlitSize) ? 1 : (height / KMaxBlitSize) + 1;
+
+ TInt stride = iFrameBuffer->ScanLineLength(
+ iFrameBuffer->SizeInPixels().iWidth, iFrameBuffer->DisplayMode());
+
+ for (TInt yBlit = 0; yBlit < yBlits; ++yBlit)
+ {
+ for (TInt xBlit = 0; xBlit < xBlits; ++xBlit)
+ {
+
+ TInt xStart = xOffset + xBlit * KMaxBlitSize;
+ TInt yStart = yOffset + yBlit * KMaxBlitSize;
+ TInt xSize = Min(KMaxBlitSize, width - (xStart - xOffset));
+ TInt ySize = Min(KMaxBlitSize, height - (yStart - yOffset));
+
+ // The first rectangle will be in bottom left corner,
+ // then rectangle is moved right and upwards.
+ // OpenGL y-coordinate increases upwards.
+ TInt srcOffset = (canvasHeight - (yStart + ySize)) * stride +
+ xStart * KBytesPerPixel;
+
+ if ((xSize > 0) && (xSize <= 256) && (ySize > 0) && (ySize <= 256))
+ {
+ BlitSubRectTexture(xStart, yStart, xSize, ySize, stride,
+ (TUint8*)iFrameBuffer->DataAddress() + srcOffset);
+ }
+ }
+ }
+}
+
+
+// ---------------------------------------------------------------------------
+// CMIDCanvas::BlitSubRectTexture
+// Creates OpenGL texture from the pixels passed as a parameter and draws
+// texture to the current EGL surface.
+// ---------------------------------------------------------------------------
+//
+void CMIDCanvas::BlitSubRectTexture(TInt aXOffset, TInt aYOffset,
+ TInt aWidth, TInt aHeight,
+ TInt aStride, const TUint8* aPixels)
+{
+ DEBUG_INT4("BlitSubRectTextureL: aXOffset=%d, aYOffset=%d, aWidth=%d, aHeight=%d",
+ aXOffset, aYOffset, aWidth, aHeight);
+ DEBUG_INT("BlitSubRectTextureL: aStride=%d", aStride);
+
+ ASSERT((aWidth > 0) && (aWidth <= 256));
+ ASSERT((aHeight > 0) && (aHeight <= 256));
+ ASSERT(iTexturePixels);
+ ASSERT_GL();
+
+ TInt tileWidth = KMaxBlitSize;
+ TInt tileHeight = KMaxBlitSize;
+
+ // Tweak tile size to avoid using excessive amounts of memory for
+ // portions outside the blit area
+ while (tileWidth >= aWidth * 2)
+ {
+ tileWidth >>= 1;
+ tileHeight <<= 1;
+ }
+
+ while (tileHeight >= aHeight * 2)
+ {
+ tileHeight >>= 1;
+ }
+
+ glActiveTexture(GL_TEXTURE0);
+ glEnable(GL_TEXTURE_2D);
+
+ TUint tempTexObj[KTexturesCount];
+ glGenTextures(KTexturesCount, tempTexObj);
+
+ glBindTexture(GL_TEXTURE_2D, tempTexObj[0]);
+
+ glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
+
+ glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA,
+ tileWidth, tileHeight, 0,
+ GL_RGBA, GL_UNSIGNED_BYTE, NULL);
+
+ // Raise out-of-memory if OpenGL ran out of resources
+ GLint err = glGetError();
+ if (err == GL_OUT_OF_MEMORY)
+ {
+ glDeleteTextures(KTexturesCount, tempTexObj);
+ ELOG(EJavaUI, "CMIDCanvas::BlitSubRectTexture(): Out of memory when creating OpenGL texture");
+ return;
+ }
+ else if (err != GL_NO_ERROR)
+ {
+ ELOG1(EJavaUI, "CMIDCanvas::BlitSubRectTexture(): GL error after glTexImage2D(): %d", err);
+ ASSERT(EFalse);
+ }
+
+ // Set up texture and vertex coordinate arrays for the image tiles
+ const TUint8 tc[8] = { 0, 0, 0, 1, 1, 0, 1, 1 };
+ GLshort pos[8];
+
+ glClientActiveTexture(GL_TEXTURE0);
+ glTexCoordPointer(2, GL_BYTE, 0, tc);
+ glEnableClientState(GL_TEXTURE_COORD_ARRAY);
+ glVertexPointer(2, GL_SHORT, 0, pos);
+ glEnableClientState(GL_VERTEX_ARRAY);
+ glMatrixMode(GL_TEXTURE);
+ glLoadIdentity();
+ glMatrixMode(GL_MODELVIEW);
+
+ ASSERT_GL();
+
+ glBindTexture(GL_TEXTURE_2D, tempTexObj[0]);
+ TUint8* dst = iTexturePixels;
+ const TUint8* src = aPixels;
+
+ TInt h = aHeight;
+
+ if (tileWidth > aWidth ||
+ tileHeight > aHeight)
+ {
+ // Clear the pixel data with transparent for case where
+ // actual texture data does not cover the full tile.
+ Mem::FillZ(dst, tileWidth * tileHeight * KBytesPerPixel);
+ dst += tileWidth * (tileHeight - aHeight) * KBytesPerPixel;
+ }
+
+ while (h-- > 0)
+ {
+ ConvertPixels((TUint32*)src, dst, aWidth);
+ src += aStride;
+ dst += tileWidth * KBytesPerPixel;
+ }
+
+ glTexSubImage2D(GL_TEXTURE_2D, 0,
+ 0, 0,
+ tileWidth, tileHeight,
+ GL_RGBA, GL_UNSIGNED_BYTE, iTexturePixels);
+
+ // If scaling is on and pbuffer is used, the framebuffer contents
+ // must be positioned to the top part of the puffer as m3g renders
+ // there as well, thus 2D and 3D content are correctly on top of each other
+ if (iScalingOn && iFullScreen)
+ {
+ TSize pbufferSize = GetEglSurfaceSize(iEglPbufferSurface);
+ TInt offset = pbufferSize.iHeight - iContentSize.iHeight;
+
+ pos[0] = (GLshort)aXOffset;
+ pos[1] = (GLshort)(tileHeight + aYOffset + offset);
+ pos[2] = pos[0];
+ pos[3] = (GLshort)aYOffset + offset;
+ pos[4] = (GLshort)(tileWidth + aXOffset);
+ pos[5] = pos[1];
+ pos[6] = pos[4];
+ pos[7] = pos[3];
+ }
+ else
+ {
+ pos[0] = (GLshort)aXOffset;
+ pos[1] = (GLshort)(tileHeight + aYOffset);
+ pos[2] = pos[0];
+ pos[3] = (GLshort)aYOffset;
+ pos[4] = (GLshort)(tileWidth + aXOffset);
+ pos[5] = pos[1];
+ pos[6] = pos[4];
+ pos[7] = pos[3];
+ }
+
+ glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
+
+ // release resources
+ glDeleteTextures(KTexturesCount, tempTexObj);
+ ASSERT_GL();
+}
+
+// ---------------------------------------------------------------------------
+// CMIDCanvas::CreatePBufferSurfaceL
+// Create EGL pbuffer to be used in scaling case.
+// ---------------------------------------------------------------------------
+//
+void CMIDCanvas::CreatePBufferSurfaceL()
+{
+ DEBUG("CMIDCanvas::CreatePBufferSurface() ++");
+ ASSERT(iEglDisplay != EGL_NO_DISPLAY);
+
+ RWindow& window = Window();
+
+ // Choose the buffer size based on the Window's display mode.
+ TDisplayMode displayMode = window.DisplayMode();
+ TInt bufferSize = 0;
+ switch (displayMode)
+ {
+ case(EColor16MU):
+ case(EColor16MA):
+ case(EColor16MAP):
+ bufferSize = 32;
+ break;
+ default:
+ ELOG1(EJavaUI, "CMIDCanvas::OpenEglL(): unsupported window display mode %d",
+ displayMode);
+ User::Leave(KErrNotSupported);
+ break;
+ }
+
+ // Set the desired properties for the EGLSurface
+ const EGLint attributeList[] =
+ {
+ EGL_SURFACE_TYPE, EGL_PBUFFER_BIT,
+ EGL_RED_SIZE, 8,
+ EGL_GREEN_SIZE, 8,
+ EGL_BLUE_SIZE, 8,
+ EGL_ALPHA_SIZE, 8,
+ EGL_BUFFER_SIZE, bufferSize,
+ EGL_BIND_TO_TEXTURE_RGBA, EGL_TRUE,
+ EGL_TRANSPARENT_TYPE, EGL_NONE,
+ EGL_DEPTH_SIZE, 16,
+ EGL_NONE
+ };
+
+ EGLConfig bestConfig;
+ EGLint numConfigs = 0;
+
+ // Choose the best EGLConfig that matches the desired properties.
+ if (!eglChooseConfig(iEglDisplay, attributeList, &bestConfig, 1, &numConfigs) ||
+ numConfigs == 0)
+ {
+ ELOG1(EJavaUI, "eglChooseConfig() for pbuffer failed, eglError=%d", eglGetError());
+ User::Leave(KErrNotSupported);
+ }
+
+ // find buffer size based on the framebuffer size
+ // pbuffer size must be power of two so that it can be bound
+ // as texture image
+ TInt width = 2;
+ TInt height = 2;
+
+ while (width < iContentSize.iWidth)
+ {
+ width <<= 1;
+ }
+ while (height < iContentSize.iHeight)
+ {
+ height <<= 1;
+ }
+
+ DEBUG_INT4("CMIDCanvas::CreatePBufferSurface - pbuffer size resolved as (width=%d, height=%d), contentSize(%d, %d)",
+ width, height, iContentSize.iWidth, iContentSize.iHeight);
+
+ // Special attributes in order for binding this surface as texture image
+ EGLint attrib[] =
+ {
+ EGL_WIDTH, width,
+ EGL_HEIGHT, height,
+ EGL_TEXTURE_FORMAT, EGL_TEXTURE_RGBA,
+ EGL_TEXTURE_TARGET, EGL_TEXTURE_2D,
+ EGL_MIPMAP_TEXTURE, EGL_TRUE,
+ EGL_NONE
+ };
+
+ iEglPbufferSurface = eglCreatePbufferSurface(iEglDisplay, bestConfig, attrib);
+ if (iEglPbufferSurface == EGL_NO_SURFACE)
+ {
+ ELOG1(EJavaUI, "eglCreatePbufferSurface() failed, eglError=%d", eglGetError());
+ User::Leave(KErrNoMemory);
+ }
+
+ // Create a rendering context
+ iEglPbufferSurfaceContext = eglCreateContext(iEglDisplay, bestConfig, NULL, NULL);
+ if (iEglPbufferSurfaceContext == EGL_NO_CONTEXT)
+ {
+ ELOG1(EJavaUI, "eglCreateContext() for pbuffer failed, eglError=%d", eglGetError());
+ User::Leave(KErrNoMemory);
+ }
+
+ DEBUG("CMIDCanvas::CreatePBufferSurface() --");
+}
+
+// ---------------------------------------------------------------------------
+// CMIDCanvas::DisposePBufferSurface
+// Destroys EGL pbuffer surface and context.
+// ---------------------------------------------------------------------------
+//
+void CMIDCanvas::DisposePBufferSurface()
+{
+ if (iEglPbufferSurfaceContext != EGL_NO_CONTEXT)
+ {
+ eglDestroyContext(iEglDisplay, iEglPbufferSurfaceContext);
+ iEglPbufferSurfaceContext = EGL_NO_CONTEXT;
+
+ // textures are destoyed along with the context so it's safe
+ // set texture name to zero
+ iPbufferTexture = 0;
+ }
+ if (iEglPbufferSurface != EGL_NO_SURFACE)
+ {
+ eglDestroySurface(iEglDisplay, iEglPbufferSurface);
+ iEglPbufferSurface = EGL_NO_SURFACE;
+ }
+}
+
+// ---------------------------------------------------------------------------
+// CMIDCanvas::BlitPBufferScaledToWindowSurface
+// In scaling case renders and scales pbuffer content (=canvas 2D + 3D
+// content in orig size) to EGL window surface.
+// ---------------------------------------------------------------------------
+//
+void CMIDCanvas::BlitPBufferScaledToWindowSurface()
+{
+ DEBUG("CMIDCanvas::BlitPBufferScaledToWindowSurface() ++");
+
+ // Get screen size for setting clips and
+ // parallel projection correctly
+ TRect screenRect = Rect();
+ TInt width = screenRect.Width();
+ TInt height = screenRect.Height();
+
+ glScissor(0, 0, width, height);
+ glViewport(0, 0, width, height);
+ glMatrixMode(GL_PROJECTION);
+ glLoadIdentity();
+
+ glOrthox(0, width << 16,
+ 0, height << 16,
+ -1 << 16, 1 << 16);
+
+ glMatrixMode(GL_MODELVIEW);
+ glLoadIdentity();
+
+ glActiveTexture(GL_TEXTURE0);
+ glEnable(GL_TEXTURE_2D);
+
+ // generate texture name if not already generated
+ if (glIsTexture(iPbufferTexture) == GL_FALSE)
+ {
+ glGenTextures(1, &iPbufferTexture);
+ }
+
+ glBindTexture(GL_TEXTURE_2D, iPbufferTexture);
+ if (eglBindTexImage(iEglDisplay, iEglPbufferSurface, EGL_BACK_BUFFER) == EGL_FALSE)
+ {
+ ELOG1(EJavaUI, "eglBindTexImage() failed, eglError=%d", eglGetError());
+ ASSERT(EFalse);
+ }
+
+ glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
+ glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+
+ // calculate texture coordinates, i.e. the area in pbuffer
+ // that has the actual frame content
+ GLfloat contentWidth = iContentSize.iWidth;
+ GLfloat contentHeight = iContentSize.iHeight;
+ TSize bufferSize = GetEglSurfaceSize(iEglPbufferSurface);
+ GLfloat horRatio = contentWidth / bufferSize.iWidth;
+ GLfloat yoffset = (bufferSize.iHeight - contentHeight) / bufferSize.iHeight;
+ GLfloat tc[8] = { 0.0f, 1.0f, 0.0f, yoffset, horRatio, 1.0f, horRatio, yoffset};
+
+ GLshort pos[8];
+
+ ASSERT_GL();
+
+ glClientActiveTexture(GL_TEXTURE0);
+ glTexCoordPointer(2, GL_FLOAT, 0, tc);
+ glEnableClientState(GL_TEXTURE_COORD_ARRAY);
+ glVertexPointer(2, GL_SHORT, 0, pos);
+ glEnableClientState(GL_VERTEX_ARRAY);
+ glMatrixMode(GL_TEXTURE);
+ glLoadIdentity();
+
+ // position texture screen coordinates
+ pos[0] = (GLshort)iViewRect.iTl.iX;
+ pos[1] = (GLshort)iViewRect.Height() + (height - iViewRect.iBr.iY);
+ pos[2] = pos[0];
+ pos[3] = (GLshort)height - iViewRect.iBr.iY;
+ pos[4] = (GLshort)iViewRect.iBr.iX;
+ pos[5] = pos[1];
+ pos[6] = pos[4];
+ pos[7] = pos[3];
+
+ glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
+
+ // release pbuffer from texture
+ eglReleaseTexImage(iEglDisplay, iEglPbufferSurface, EGL_BACK_BUFFER);
+
+ DEBUG("CMIDCanvas::BlitPBufferScaledToWindowSurface() --");
+}
+
+
+// ---------------------------------------------------------------------------
+// CMIDCanvas::ClearFrameBuffer
+// Clears the frame buffer with fully transparent color. Rendering canvas 2D
+// content as an OpenGL texture requires that texture is transparent in
+// the areas where no 2D content has been drawn.
+// ---------------------------------------------------------------------------
+//
+void CMIDCanvas::ClearFrameBuffer()
+{
+ if (!iM3GStart && iUpperUpdateRect.IsEmpty() && iLowerUpdateRect.IsEmpty())
+ {
+ return;
+ }
+ // Clear the frame buffer
+ iFrameContext->SetBrushColor(KTransparentClearColor);
+ iFrameContext->SetDrawMode(CGraphicsContext::EDrawModeWriteAlpha);
+
+ iFrameContext->Clear(iUpperUpdateRect);
+ iFrameContext->Clear(iLowerUpdateRect);
+
+ // Reset members
+ iUpperUpdateRect.SetRect(0,0,0,0);
+ iLowerUpdateRect.SetRect(0,0,0,0);
+}
+
+
+// ---------------------------------------------------------------------------
+// CMIDCanvas::AssertGL
+// Check for OpenGL ES errors. Only for debug builds.
+// ---------------------------------------------------------------------------
+//
+void CMIDCanvas::AssertGL()
+{
+ GLint err = glGetError();
+ if (err == GL_NO_ERROR)
+ {
+ return;
+ }
+ else
+ {
+ ELOG1(EJavaUI, "OpenGL ES error=%d", err);
+ ASSERT(EFalse);
+ }
+}
+
+// ---------------------------------------------------------------------------
+// CMIDCanvas::AssertGL
+// Check for OpenGL ES errors. Only for debug builds.
+// ---------------------------------------------------------------------------
+//
+const TDesC8& CMIDCanvas::GetEglError(EGLint aErr)
+{
+ _LIT8(KEglSuccess, "EGL_SUCCESS");
+ _LIT8(KEglNotInitialized, "EGL_NOT_INITIALIZED");
+ _LIT8(KEglBadAccess, "EGL_BAD_ACCESS");
+ _LIT8(KEglBadAlloc, "EGL_BAD_ALLOC");
+ _LIT8(KEglBadAttribute, "EGL_BAD_ATTRIBUTE");
+ _LIT8(KEglBadContext, "EGL_BAD_CONTEXT");
+ _LIT8(KEglBadConfig, "EGL_BAD_CONFIG");
+ _LIT8(KEglBadCurrentSurface, "EGL_BAD_CURRENT_SURFACE");
+ _LIT8(KEglBadDisplay, "EGL_BAD_DISPLAY");
+ _LIT8(KEglBadSurface, "EGL_BAD_SURFACE");
+ _LIT8(KEglBadMatch, "EGL_BAD_MATCH");
+ _LIT8(KEglBadParameter, "EGL_BAD_PARAMETER");
+ _LIT8(KEglBadNativePixmap, "EGL_BAD_NATIVE_PIXMAP");
+ _LIT8(KEglBadNativeWindow, "EGL_BAD_NATIVE_WINDOW");
+ switch (aErr)
+ {
+ case EGL_NOT_INITIALIZED:
+ return KEglNotInitialized;
+ case EGL_BAD_ACCESS:
+ return KEglBadAccess;
+ case EGL_BAD_ALLOC:
+ return KEglBadAlloc;
+ case EGL_BAD_ATTRIBUTE:
+ return KEglBadAttribute;
+ case EGL_BAD_CONTEXT:
+ return KEglBadContext;
+ case EGL_BAD_CONFIG:
+ return KEglBadConfig;
+ case EGL_BAD_CURRENT_SURFACE:
+ return KEglBadCurrentSurface;
+ case EGL_BAD_DISPLAY:
+ return KEglBadDisplay;
+ case EGL_BAD_SURFACE:
+ return KEglBadSurface;
+ case EGL_BAD_MATCH:
+ return KEglBadMatch;
+ case EGL_BAD_PARAMETER:
+ return KEglBadParameter;
+ case EGL_BAD_NATIVE_PIXMAP:
+ return KEglBadNativePixmap;
+ case EGL_BAD_NATIVE_WINDOW:
+ return KEglBadNativeWindow;
+ }
+ return KEglSuccess;
+}
+
+// ---------------------------------------------------------------------------
+// CMIDCanvas::IsWindowVisible
+// Checks if canvas window is currently visible on display. Canvas may be visible
+// e.g. behind task switcher or system dialogs even though MIDlet is not the
+// foreground application in that case. This function relies on
+// CMIDDisplayble setting canvas window invisible when some other full-screen
+// displayble is set as current.
+// ---------------------------------------------------------------------------
+//
+TBool CMIDCanvas::IsWindowVisible() const
+{
+ return iEnv.HasFullOrPartialForeground() && IsVisible();
+}
+
+// ---------------------------------------------------------------------------
+// CMIDCanvas::PostForcedPaint
+// Send forced paint to Java. Canvas.paint() will be called even if canvas is
+// not the current displayable.
+// ---------------------------------------------------------------------------
+//
+void CMIDCanvas::PostForcedPaint()
+{
+ TInt posPacked = 0;
+ TInt sizePacked = (iContentSize.iWidth << 16) | (iContentSize.iHeight);
+ PostEvent(EForcedPaint, posPacked, sizePacked);
+}
+#endif // RD_JAVA_NGA_ENABLED
+// End of File.