diff -r 000000000000 -r 7f656887cf89 plugins/consoles/guicons/src/guicons.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/plugins/consoles/guicons/src/guicons.cpp Wed Jun 23 15:52:26 2010 +0100 @@ -0,0 +1,1858 @@ +// guicons.cpp +// +// Copyright (c) 2010 Accenture. All rights reserved. +// This component and the accompanying materials are made available +// under the terms of the "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: +// Accenture - Initial contribution +// + +#include +#include "guicons.h" +#include +#include + +#include "defaultfontdata.inl" + +const TInt KAttributeMapGranularity = 3; + +const ConsoleAttributes::TColor KDefaultForegroundColor = ConsoleAttributes::EBlack; +const ConsoleAttributes::TColor KDefaultBackgroundColor = ConsoleAttributes::EWhite; + + +ConsoleAttributes::TAttributes DefaultAttributes() + { + return ConsoleAttributes::TAttributes(ConsoleAttributes::ENone, KDefaultForegroundColor, KDefaultBackgroundColor); + } + +TRgb MapColor(TUint aAttributes, ConsoleAttributes::TColor aColor) + { + TRgb rgb; + + switch (aColor) + { + case ConsoleAttributes::EBlack: + if (aAttributes & ConsoleAttributes::EBold) + { + rgb = KRgbGray; + } + else + { + rgb = KRgbBlack; + } + break; + case ConsoleAttributes::ERed: + if (aAttributes & ConsoleAttributes::EBold) + { + rgb = KRgbRed; + } + else + { + rgb = KRgbDarkRed; + } + break; + case ConsoleAttributes::EGreen: + if (aAttributes & ConsoleAttributes::EBold) + { + rgb = KRgbGreen; + } + else + { + rgb = KRgbDarkGreen; + } + break; + case ConsoleAttributes::EYellow: + if (aAttributes & ConsoleAttributes::EBold) + { + rgb = KRgbYellow; + } + else + { + rgb = KRgbDarkYellow; + } + break; + case ConsoleAttributes::EBlue: + if (aAttributes & ConsoleAttributes::EBold) + { + rgb = KRgbBlue; + } + else + { + rgb = KRgbDarkBlue; + } + break; + case ConsoleAttributes::EMagenta: + if (aAttributes & ConsoleAttributes::EBold) + { + rgb = KRgbMagenta; + } + else + { + rgb = KRgbDarkMagenta; + } + break; + case ConsoleAttributes::ECyan: + if (aAttributes & ConsoleAttributes::EBold) + { + rgb = KRgbCyan; + } + else + { + rgb = KRgbDarkCyan; + } + break; + case ConsoleAttributes::EWhite: + if (aAttributes & ConsoleAttributes::EBold) + { + rgb = KRgbWhite; + } + else + { + rgb = KRgbWhite;//KRgbGray; + } + break; + case ConsoleAttributes::EReset: + case ConsoleAttributes::EUnchanged: + default: + ASSERT(EFalse); + } + + if (aAttributes & ConsoleAttributes::EInverse) + { + rgb = ~rgb; + } + + return rgb; + } + +void SignalSemaphore(TAny* aSemaphore) + { + ((RSemaphore*)aSemaphore)->Signal(); + } + +void CleanupSignalSemaphorePushL(RSemaphore& aSemaphore) + { + CleanupStack::PushL(TCleanupItem(SignalSemaphore, &aSemaphore)); + } + +void WaitForRequest(TAny* aStatus) + { + User::WaitForRequest(*(TRequestStatus*)aStatus); + } + +void CleanupWaitForRequestPushL(TRequestStatus& aStatus) + { + CleanupStack::PushL(TCleanupItem(WaitForRequest, &aStatus)); + } + +//______________________________________________________________________________ +// CConsoleControl +EXPORT_C CConsoleControl* CConsoleControl::NewL(TInt aBufferSize, MConsoleUi* aUi) + { + CConsoleControl* self = new(ELeave)CConsoleControl(aUi, aBufferSize); + CleanupStack::PushL(self); + self->ConstructL(CConsoleFont::NewL(KDefaultFontImageData)); + CleanupStack::Pop(self); + return self; + } + +EXPORT_C CConsoleControl* CConsoleControl::NewL(TInt aBufferSize, const TDesC& aFontFile, MConsoleUi* aUi) + { + CConsoleControl* self = new(ELeave)CConsoleControl(aUi, aBufferSize); + CleanupStack::PushL(self); + self->ConstructL(CConsoleFont::NewL(aFontFile)); + CleanupStack::Pop(self); + return self; + } + +EXPORT_C CConsoleControl::~CConsoleControl() + { + delete iBlinkTimer; + delete iFont; + iCursor.Hide(); + iBuffer.ResetAndDestroy(); + iKeyQueue.Close(); + } + +EXPORT_C void CConsoleControl::Closed() + { + if (iUi) + { + iUi->HandleConsoleClosed(this); + } + } + +EXPORT_C void CConsoleControl::Draw(const TRect& aRect) const + { + CWindowGc& gc = SystemGc(); + gc.SetBrushStyle(CGraphicsContext::ENullBrush); + gc.SetPenStyle(CGraphicsContext::ENullPen); + // Need to do a clear here, to ensure we actually draw to all the pixels in aRect that we've been asked to draw. If we don't do that, wserv generally gets upset. +// gc.SetBrushColor(KDefaultBackgroundColor); +// gc.Clear(aRect); + + for (TInt y=0; yCancel(); + } + } + +EXPORT_C void CConsoleControl::HandlePointerEventL(const TPointerEvent& aPointerEvent) + { + if (aPointerEvent.iType == TPointerEvent::EButton1Down) + { + for (TInt i = 0; i < ENumButtons; i++) + { + if (iButtonRects[i].Contains(aPointerEvent.iPosition)) + { + SimulateKeyL((TButton)i); + iIgnoringDrags = ETrue; + return; + } + } + iIgnoringDrags = EFalse; + } + + if (iIgnoringDrags) return; + if (aPointerEvent.iType == TPointerEvent::EButton1Down) + { + iDragStart = aPointerEvent.iPosition; + } + if (aPointerEvent.iType == TPointerEvent::EDrag) + { + TPoint delta = iDragStart - aPointerEvent.iPosition; + TInt lines = delta.iY / iFont->GlyphSize().iHeight; + if (lines) + { + iViewWindow.iY += lines; + ViewMoved(); + + iDragStart.iY -= (lines * iFont->GlyphSize().iHeight); + } + } + } + +EXPORT_C TKeyResponse CConsoleControl::OfferKeyEventL(const TKeyEvent& aKeyEvent,TEventCode aType) + { + if ((!IsFocused()) || IsNonFocusing()) return EKeyWasNotConsumed; + + if (aType == EEventKey) + { + iKeyQueue.AppendL(aKeyEvent); + SendKey(); + +#ifdef LOCAL_ECHO + TUint code = aKeyEvent.iCode; + if (code == '\r') code = '\n'; + + TBuf<0x20> ip; + ip.AppendFormat(_L("key %d"), code); + User::InfoPrint(ip); + + TBuf<1> buf; + buf.Append(TChar(code)); + Write(buf); +#endif + return EKeyWasConsumed; + } + return EKeyWasNotConsumed; + } + +EXPORT_C void CConsoleControl::InjectKeysL(const TDesC& aKeys) + { + for (TInt i=0; iDraw(aDrawTo, aLine); + } + } + +TRect CConsoleControl::LineRect(TViewPosition aLine) const + { + return TRect(TScreenPosition(aLine).iPoint, TSize(iFont->GlyphSize().iWidth * iSizeChars.iWidth, iFont->GlyphSize().iHeight)); + } + + +EXPORT_C void CConsoleControl::SizeChanged() + { + TSize sizePixels = Size(); + TSize newSizeChars(sizePixels.iWidth / iFont->GlyphSize().iWidth, sizePixels.iHeight / iFont->GlyphSize().iHeight); + if (newSizeChars != iSizeChars) + { + iSizeChars = newSizeChars; + TRAP_IGNORE(SizeChangedL()); + } + } + +CConsoleControl::CConsoleControl(MConsoleUi* aUi, TInt aBufferSize) + : iUi(aUi), iCursor(*this), iCurrentAttributes(ConsoleAttributes::ENone, KDefaultForegroundColor, KDefaultBackgroundColor), iBufferSize(aBufferSize) + { + } + +void CConsoleControl::ConstructL(CConsoleFont* aFont) + { + iBlinkTimer = CPeriodic::NewL(CActive::EPriorityStandard); + iFont = aFont; + iCursor.SetFont(*iFont); + SetCursorHeight(KDefaultCursorHeightPercentage); + } + +void CConsoleControl::SizeChangedL() + { + TInt bufferSize = Max(iBufferSize, iSizeChars.iHeight); + for (TInt i=0; iSetWidthL(iSizeChars.iWidth); + } + while (iBuffer.Count() < bufferSize) + { + CConsoleLine* line = CConsoleLine::NewL(*this, *iFont, iSizeChars.iWidth); + CleanupStack::PushL(line); + iBuffer.AppendL(line); + CleanupStack::Pop(); + } + while (iBuffer.Count() > bufferSize) + { + delete iBuffer[iBuffer.Count()-1]; + iBuffer.Remove(iBuffer.Count()-1); + } + iCursor.Update(); + + if (FivewayNavIsDisplaying()) SetDisplayFivewayNav(ETrue); // re-layout the onscreen nav if applicable + } + +CConsoleLine* CConsoleControl::GetLine(TBufferPosition aLine) const + { + return iBuffer[aLine.iPoint.iY]; + } + +TPoint CConsoleControl::ViewPosition() const + { + return iViewWindow; + } + +TPoint CConsoleControl::CursorWindowPosition() const + { + return iCursorWindow; + } + +TSize CConsoleControl::GlyphSize() const + { + return iFont->GlyphSize(); + } + +TBool CConsoleControl::IsSpecialChar(TChar aChar) const + { + switch(aChar) + { + case 0x00: // Null. + case 0x07: // Bell. + case 0x08: // Backspace. + case 0x7f: // Delete. + case 0x09: // Tab. + case 0x0a: // Line feed. + case 0x0b: // Vertical tab. + case 0x0c: // Form feed. + case 0x0d: // Carriage return. + return ETrue; + default: + return EFalse; + } + } + +void CConsoleControl::HandleSpecialChar(TChar aChar) + { + switch(aChar) + { + case 0x00: // Null. + break; + case 0x07: // Bell. + break; + case 0x08: // Backspace. + case 0x7f: // Delete. + iCursor--; + break; + case 0x09: // horizontal tab + iCursor += KTabSize - (iCursor.Position().iPoint.iX % KTabSize); + break; + case 0x0a: // line feed + iCursor -= iCursor.Position().iPoint.iX; + iCursor.Down(); + break; + case 0x0b: // Vertical tab. + break; + case 0x0c: // Form feed + ClearScreen(); + break; + case 0x0d: // carriage return + iCursor -= iCursor.Position().iPoint.iX; + break; + default: + User::Invariant(); + } + } + +void CConsoleControl::SendKey() + { + if (iReader && iKeyQueue.Count()) + { + iCurrentKey = iKeyQueue[0]; + iKeyQueue.Remove(0); + iReader->ReadComplete(KErrNone); + iReader = NULL; + } + } + +EXPORT_C void CConsoleControl::Read(MGuiConsoleReader& aReader) + { + if (iReader) + { + aReader.ReadComplete(KErrInUse); + } + else + { + iReader = &aReader; + SendKey(); + } + } + +EXPORT_C void CConsoleControl::ReadCancel() + { + iReader = NULL; + } + +EXPORT_C void CConsoleControl::Write(const TDesC &aDes) + { + TRAP_IGNORE(WriteL(aDes)); + } + +void CConsoleControl::WriteL(const TDesC &aDes) + { + TRect invalidRect; + for (TInt i=0; iSetL(iCursor.Position().iPoint.iX, aDes[i], iCurrentAttributes); + TRect lineRect(LineRect(iCursor.Position())); + Window().Invalidate(lineRect); + if (invalidRect.IsEmpty()) + { + invalidRect = lineRect; + } + else + { + invalidRect.BoundingRect(lineRect); + } + iCursor++; + } + } + + if (!invalidRect.IsEmpty()) + { + DrawNow(invalidRect); + } + + iCursor.Update(); + } + +void CConsoleControl::StartBlinking() + { + if (!iBlinkTimer->IsActive()) + { + iBlinkTimer->Start(500000, 500000, TCallBack(BlinkCallback, this)); + } + } + +TInt CConsoleControl::BlinkCallback(TAny* aPtr) + { + CConsoleControl* self = static_cast(aPtr); + + TBool neededToBlink(EFalse); + for (TInt y = 0; y < self->iSizeChars.iHeight; ++y) + { + TViewPosition line(*self, 0, y); + if (self->GetLine(line)->NeedToBlink(self->iBlinkOn)) + { + neededToBlink = ETrue; + self->Window().Invalidate(self->LineRect(line)); + } + } + if (neededToBlink) + { + self->iBlinkOn = !self->iBlinkOn; + } + else + { + self->iBlinkTimer->Cancel(); + } + + return KErrNone; + } + +EXPORT_C void CConsoleControl::ViewScrollUp() + { + iViewWindow.iY--; + ViewMoved(); + } + +EXPORT_C void CConsoleControl::ViewScrollDown() + { + iViewWindow.iY++; + ViewMoved(); + } + +EXPORT_C void CConsoleControl::ViewPageUp() + { + iViewWindow.iY -= iSizeChars.iHeight-1; + ViewMoved(); + } + +EXPORT_C void CConsoleControl::ViewPageDown() + { + iViewWindow.iY += iSizeChars.iHeight-1; + ViewMoved(); + } + +EXPORT_C void CConsoleControl::ViewHome() + { + iViewWindow.iY = 0; + ViewMoved(); + } + +EXPORT_C void CConsoleControl::ViewEnd() + { + iViewWindow = iCursorWindow; + ViewMoved(); + } + +void CConsoleControl::Invalidate5Way() + { + if (iDrawNavigator) + { + for (TInt i = 0; i < ENumButtons; i++) + { + Window().Invalidate(iButtonRects[i]); + } + } + } + +EXPORT_C TInt CConsoleControl::SetAttributes(TUint aAttributes, ConsoleAttributes::TColor aForegroundColor, ConsoleAttributes::TColor aBackgroundColor) + { + ConsoleAttributes::TAttributes currentAttributes = iCurrentAttributes; + + if (aAttributes == ConsoleAttributes::ENone) + { + currentAttributes = DefaultAttributes(); + } + else + { + currentAttributes.iAttributes = aAttributes; + } + + switch (aForegroundColor) + { + case ConsoleAttributes::EReset: + currentAttributes.iForegroundColor = KDefaultForegroundColor; + break; + case ConsoleAttributes::EUnchanged: + // Do nothing. + break; + default: + currentAttributes.iForegroundColor = aForegroundColor; + break; + } + + switch (aBackgroundColor) + { + case ConsoleAttributes::EReset: + currentAttributes.iBackgroundColor = KDefaultBackgroundColor; + break; + case ConsoleAttributes::EUnchanged: + // Do nothing. + break; + default: + currentAttributes.iBackgroundColor = aBackgroundColor; + break; + } + + TRAPD(err, iFont->PrepareForegroundColorL(MapColor(currentAttributes.iAttributes, currentAttributes.iForegroundColor))); + if (err == KErrNone) + { + iCurrentAttributes = currentAttributes; + } + + return err; + } + +void CConsoleControl::ViewMoved() + { + if (iViewWindow.iY < 0) iViewWindow.iY = 0; + if (iViewWindow.iY + iSizeChars.iHeight > iBuffer.Count()) iViewWindow.iY = iBuffer.Count() - iSizeChars.iHeight; + Window().Invalidate(); + } + +void CConsoleControl::CursorWindowScrollDown() + { + TBool viewWindowMatchesCursorWindow = (iViewWindow.iY == iCursorWindow.iY); + iCursorWindow.iY++; + if (iCursorWindow.iY + iSizeChars.iHeight > iBuffer.Count()) + { + iCursorWindow.iY--; + CConsoleLine* topLine = iBuffer[0]; + iBuffer.Remove(0); + topLine->Clear(); + iBuffer.Append(topLine); + + // JB - Disabled the code below because it forces a full redraw of the window which seems + // unnecessary, particularly now that this function trys to efficiently scroll using + // RDrawableWindow::Scroll. Note though that I can't claim to fully understand this code, + // so this may be a dumb thing to do. Original comment follows... + // move this up so that the text in the view window moves up with the scrolling text. + // ViewScrollUp(); + } + + if (viewWindowMatchesCursorWindow) // keep them in sync if they were when we started + { + iViewWindow.iY = iCursorWindow.iY; + } + +#ifndef FSHELL_WSERV2_SUPPORT + // On wserv1 we can't use Scroll if we're showing the 5-way nav - it looks bad + if (iDrawNavigator) + { + DrawDeferred(); + } + else +#endif + { + // on wserv2, or wserv1 when the 5-way nav isn't displayed, we can use RWindow::Scroll for better performance (although, performance only seems to be a problem on wserv1 with a wide screen. On wserv2 probably just a DrawDeferred() would be sufficient) + Invalidate5Way(); + Window().Scroll(Rect(), TPoint(0, -(iFont->GlyphSize().iHeight))); + Invalidate5Way(); + TRect invalidRect(LineRect(TViewPosition(*this, 0, iSizeChars.iHeight - 1))); + Window().Invalidate(invalidRect); + } + } + +EXPORT_C TPoint CConsoleControl::CursorPos() const + { + return iCursor.Position().iPoint; + } + +EXPORT_C void CConsoleControl::SetCursorPosAbs(const TPoint &aPoint) + { + iCursor.SetPosAbs(TConsCursorPosition(*this, aPoint)); + iCursor.Update(); + } + +EXPORT_C void CConsoleControl::SetCursorPosRel(const TPoint &aPoint) + { + iCursor.SetPosRel(TConsCursorPosition(*this, aPoint)); + iCursor.Update(); + } + +EXPORT_C void CConsoleControl::SetCursorHeight(TInt aPercentage) + { + iCursor.SetHeight(aPercentage); + iCursor.Update(); + } + +EXPORT_C void CConsoleControl::SetTitle(const TDesC &aTitle) + { + if (iUi) + { + TRAP_IGNORE(iUi->ConsoleTitleChangedL(this, aTitle)); + } + } + +EXPORT_C void CConsoleControl::ClearScreen() + { + Window().Invalidate(); + for (TInt y=0; yClear(); + } + iCursorWindow.iY = 0; + iViewWindow.iY = 0; + iCursor.SetPosAbs(TConsCursorPosition(*this, 0,0)); + iCurrentAttributes = DefaultAttributes(); + } + +EXPORT_C void CConsoleControl::ClearToEndOfLine() + { + GetLine(iCursor.Position())->ClearFrom(iCursor.Position()); + Window().Invalidate(LineRect(iCursor.Position())); + } + +EXPORT_C TSize CConsoleControl::ScreenSize() const + { + return iSizeChars; + } + +EXPORT_C TKeyCode CConsoleControl::KeyCode() const + { + return (TKeyCode)iCurrentKey.iCode; + } + +EXPORT_C TUint CConsoleControl::KeyModifiers() const + { + return iCurrentKey.iModifiers; + } + +void CConsoleControl::SimulateKeyL(TButton aButton) + { + TKeyEvent key; + key.iRepeats = 0; + key.iModifiers = 0; + switch (aButton) + { + case EUp: + key.iCode = EKeyUpArrow; + key.iScanCode = EStdKeyUpArrow; + break; + case EDown: + key.iCode = EKeyDownArrow; + key.iScanCode = EStdKeyDownArrow; + break; + case ELeft: + key.iCode = EKeyLeftArrow; + key.iScanCode = EStdKeyLeftArrow; + break; + case ERight: + key.iCode = EKeyRightArrow; + key.iScanCode = EStdKeyRightArrow; + break; + case ECenter: + key.iCode = EKeyEnter; + key.iScanCode = EStdKeyEnter; + break; + default: + return; + } + iCoeEnv->SimulateKeyEventL(key, EEventKey); + } + +EXPORT_C TBool CConsoleControl::FivewayNavIsDisplaying() const + { + return iButtonRects[ECenter].Width(); + } + +EXPORT_C void CConsoleControl::SetDisplayFivewayNav(TBool aShow) + { + if (aShow) + { + TRect rect(Rect()); + TInt shortLen = Min(rect.Width(), rect.Height()); // Look nicer in landscape + TSize buttonSize(shortLen / 4, shortLen / 4); + TRect center(TPoint(rect.Width()/2 - buttonSize.iWidth/2, rect.Height() - 2*buttonSize.iHeight), buttonSize); + iButtonRects[ECenter] = center; + iButtonRects[ECenter].Shrink(5, 5); + iButtonRects[ELeft] = center; iButtonRects[ELeft].Move(-buttonSize.iWidth, 0); + iButtonRects[ERight] = center; iButtonRects[ERight].Move(buttonSize.iWidth, 0); + iButtonRects[EUp] = center; iButtonRects[EUp].Move(0, -buttonSize.iHeight); + iButtonRects[EDown] = center; iButtonRects[EDown].Move(0, buttonSize.iHeight); + iDrawNavigator = ETrue; + } + else + { + Mem::FillZ(iButtonRects, sizeof(iButtonRects)); + } + DrawDeferred(); + } + +void CConsoleControl::ActivateL() + { + Window().SetBackgroundColor(KRgbWhite); + CCoeControl::ActivateL(); + } + +//______________________________________________________________________________ +// Image loader thread +// We use ICl to decode the font image. Despite ICL having the ability to create +// a thread of it own to do the decoding, when we decode from a descriptor +// (instead of a file), it still requires a AO RunL's in out thread to operate. +// So, we have to create a new thread manually so that we can always load images +// synchronously. + +class RImageDecodeThreadParams + { +public: + RImageDecodeThreadParams(const TDesC& aFileName) + : iMode(EDecodeFile), iFileName(aFileName), iData(KNullDesC8), iBitmapHandle(KNullHandle) {} + RImageDecodeThreadParams(const TDesC8& aImageData) + : iMode(EDecodeData), iFileName(KNullDesC), iData(aImageData), iBitmapHandle(KNullHandle) {} + TInt Open() + { + TInt err = iBitmapReadySemaphore.CreateLocal(0); + if (err==KErrNone) err = iThreadExitSemaphore.CreateLocal(0); + if (err!=KErrNone) Close(); + return err; + } + void Close() + { + iBitmapReadySemaphore.Close(); + iThreadExitSemaphore.Close(); + } +public: + enum + { + EDecodeFile, + EDecodeData, + } iMode; + const TPtrC iFileName; + const TPtrC8 iData; + TFrameInfo iFrameInfo; + TInt iBitmapHandle; + RSemaphore iBitmapReadySemaphore; + RSemaphore iThreadExitSemaphore; + TInt iThreadError; + }; + +class CImageDecodeWaiter : public CActive + { +public: + CImageDecodeWaiter(TInt aPriority) + : CActive(aPriority) + { + CActiveScheduler::Add(this); + } + void Start(CImageDecoder* aDecoder, CFbsBitmap* aBitmap) + { + TRequestStatus* stat = &iStatus; + aDecoder->Convert(stat, *aBitmap); + SetActive(); + CActiveScheduler::Start(); + } + virtual void RunL() + { + iCompletionErr = iStatus.Int(); + CActiveScheduler::Stop(); + } + virtual void DoCancel() {} +public: + TInt iCompletionErr; + }; + +void ImageDecodeThreadL(RImageDecodeThreadParams& aParams) + { + User::LeaveIfError(RFbsSession::Connect()); + + CActiveScheduler* as = new(ELeave)CActiveScheduler; + CActiveScheduler::Install(as); + CleanupStack::PushL(as); + + RFs fs; + User::LeaveIfError(fs.Connect()); + CleanupClosePushL(fs); + User::LeaveIfError(fs.ShareAuto()); + + CImageDecoder* dec = NULL; + switch (aParams.iMode) + { + case RImageDecodeThreadParams::EDecodeFile: + dec = CImageDecoder::FileNewL(fs, aParams.iFileName); + break; + case RImageDecodeThreadParams::EDecodeData: + dec = CImageDecoder::DataNewL(fs, aParams.iData); + break; + } + CleanupStack::PushL(dec); + + aParams.iFrameInfo = dec->FrameInfo(); + CFbsBitmap* bmp = new(ELeave)CFbsBitmap; + CleanupStack::PushL(bmp); + User::LeaveIfError(bmp->Create(aParams.iFrameInfo.iOverallSizeInPixels, aParams.iFrameInfo.iFrameDisplayMode)); + + + CImageDecodeWaiter* waiter = new(ELeave)CImageDecodeWaiter(CActive::EPriorityStandard); + CleanupStack::PushL(waiter); + + waiter->Start(dec, bmp); + User::LeaveIfError(waiter->iCompletionErr); + + aParams.iBitmapHandle = bmp->Handle(); + aParams.iThreadError = KErrNone; + aParams.iBitmapReadySemaphore.Signal(); + aParams.iThreadExitSemaphore.Wait(); + + CleanupStack::PopAndDestroy(5, as); // as, fs, dec, bmp, waiter + } + +TInt ImageDecodeThead(TAny* aParams) + { + User::SetCritical(User::EProcessCritical); + __UHEAP_MARK; + RImageDecodeThreadParams* params = (RImageDecodeThreadParams*)aParams; + + CTrapCleanup* cleanup = CTrapCleanup::New(); // get clean-up stack + if (!cleanup) return KErrNoMemory; + TRAPD(err, ImageDecodeThreadL(*params)); + params->iThreadError = err; + if (err!=KErrNone) + { + params->iBitmapReadySemaphore.Signal(); + } + + delete cleanup; + REComSession::FinalClose(); + RFbsSession::Disconnect(); + __UHEAP_MARKEND; + User::SetCritical(User::ENotCritical); + return err; + } + +//______________________________________________________________________________ +// CConsoleFont +EXPORT_C CConsoleFont* CConsoleFont::NewL(const TDesC& aFontFile) + { + CConsoleFont* self = new(ELeave)CConsoleFont; + CleanupStack::PushL(self); + self->ConstructL(aFontFile); + CleanupStack::Pop(self); + return self; + } + +EXPORT_C CConsoleFont* CConsoleFont::NewL(const TDesC8& aEncodedFontImage) + { + CConsoleFont* self = new(ELeave)CConsoleFont; + CleanupStack::PushL(self); + self->ConstructL(aEncodedFontImage); + CleanupStack::Pop(self); + return self; + } + +EXPORT_C CConsoleFont::~CConsoleFont() + { + for (TInt i = 0; i < KNumGlyphs; ++i) + { + delete iChars[i]; + } + for (TInt i = 0; i < KNumColors; ++i) + { + delete iColors[i]; + } + } + +EXPORT_C TSize CConsoleFont::GlyphSize() const + { + return iGlyphRect.Size(); + } + + +EXPORT_C void CConsoleFont::DrawChar(TChar aChar, CBitmapContext& aDrawTo, TPoint aPosPixels, TRgb aColor) + { + // Note, this method assumes that the glyph's background has already been set to the appropriate color. + + if ((aChar < KFontBitmapFirstCharCode) || (aChar > KFontBitmapLastCharCode)) + { + aChar = KFontBitmapLastCharCode; + } + + aDrawTo.BitBltMasked(aPosPixels, ForegroundBitmap(aColor), iGlyphRect, iChars[(TInt)aChar - KFontBitmapFirstCharCode], ETrue); + } + +CConsoleFont::CConsoleFont() + { + } + +void CConsoleFont::ConstructL(const TDesC& aFontFile) + { + RImageDecodeThreadParams decodeParams(aFontFile); + ConstructL(decodeParams); + } + +void CConsoleFont::ConstructL(const TDesC8& aEncodedFontImage) + { + RImageDecodeThreadParams decodeParams(aEncodedFontImage); + ConstructL(decodeParams); + } + +_LIT(KImageDecodeThreadNameFmt, "ImageDecodeThread%08x"); + +void CConsoleFont::ConstructL(RImageDecodeThreadParams& aDecodeParams) + { + User::LeaveIfError(aDecodeParams.Open()); + CleanupClosePushL(aDecodeParams); + RThread decodeThread; + CleanupClosePushL(decodeThread); + // kick off the sub thread doing the decoding + TInt err; + TInt seq = 0; + do + { + TBuf<0x20> threadName; + threadName.AppendFormat(KImageDecodeThreadNameFmt, seq); + err = decodeThread.Create(threadName, ImageDecodeThead, KDefaultStackSize, 0x1000, 0x200000, &aDecodeParams); + seq++; + } while (err==KErrAlreadyExists); + User::LeaveIfError(err); + decodeThread.Resume(); + + TRequestStatus threadExit; + decodeThread.Logon(threadExit); + + CleanupWaitForRequestPushL(threadExit); // things will probably go wrong if we leave on this line + CleanupSignalSemaphorePushL(aDecodeParams.iThreadExitSemaphore); + + /* + Now, on the cleanup stack we have: + 1. iThreadExitSemaphore.Signal() + 2. WaitForRequest(threadExit) + 3. decodeThread + 4. aDecodeParams + + So, if we leave now: + 1. We will signal the sub thread to exit + 2. We will then wait for the sub thread to exit + 3. close the sub thread handle + 4. close aDecodeParams, which will destroy the semaphores + + Note, it's important that we wait for the thread to exit before the cleanup stack + if fully unwound, as if we destroy the semaphores before the sub thread has exitted, + then it will panic with KERN-EXEC 0. + */ + + // wait for it to decode the bitmap (or die) + aDecodeParams.iBitmapReadySemaphore.Wait(); + User::LeaveIfError(aDecodeParams.iThreadError); // we will leave here if there was an error in the subthread + + // process decoded image + TSize bmpSize = aDecodeParams.iFrameInfo.iOverallSizeInPixels; + if (bmpSize.iWidth % KFontBitmapWidthChars) User::Leave(KErrCorrupt);// better error code / panic? + if (bmpSize.iHeight % KFontBitmapHeightChars) User::Leave(KErrCorrupt);// better error code / panic? + iGlyphRect = TRect(TPoint(0, 0), TSize(bmpSize.iWidth / KFontBitmapWidthChars, bmpSize.iHeight / KFontBitmapHeightChars)); + + CFbsBitmap* allChars = new(ELeave)CFbsBitmap(); + CleanupStack::PushL(allChars); + User::LeaveIfError(allChars->Duplicate(aDecodeParams.iBitmapHandle)); + + for (TInt i = 0; i < KNumGlyphs; ++i) + { + iChars[i] = new(ELeave)CFbsBitmap; + User::LeaveIfError(iChars[i]->Create(iGlyphRect.Size(), EGray2)); + + CFbsBitmapDevice* bitmapDevice = CFbsBitmapDevice::NewL(iChars[i]); + CleanupStack::PushL(bitmapDevice); + + CBitmapContext* bitmapContext; + User::LeaveIfError(bitmapDevice->CreateBitmapContext(bitmapContext)); + CleanupStack::PushL(bitmapContext); + + TPoint charPos(i % KFontBitmapWidthChars, i / KFontBitmapWidthChars); + TPoint pixelPos(charPos.iX * iGlyphRect.Size().iWidth, charPos.iY * iGlyphRect.Size().iHeight); + TRect charRect(pixelPos, iGlyphRect.Size()); + bitmapContext->BitBlt(TPoint(0, 0), allChars, charRect); + + CleanupStack::PopAndDestroy(2, bitmapDevice); + } + + // this will clean everything up - see above comment. + CleanupStack::PopAndDestroy(5, &aDecodeParams); // decodeThread, aDecodeParams + + PrepareForegroundColorL(KDefaultForegroundColor); + } + +void CConsoleFont::PrepareForegroundColorL(TRgb aColor) + { + CFbsBitmap* bitmap = ForegroundBitmap(aColor); + if (bitmap == NULL) + { + bitmap = new(ELeave)CFbsBitmap; + CleanupStack::PushL(bitmap); + User::LeaveIfError(bitmap->Create(iGlyphRect.Size(), EColor16)); + CFbsBitmapDevice* bitmapDevice = CFbsBitmapDevice::NewL(bitmap); + CleanupStack::PushL(bitmapDevice); + CBitmapContext* bitmapContext; + User::LeaveIfError(bitmapDevice->CreateBitmapContext(bitmapContext)); + CleanupStack::PushL(bitmapContext); + bitmapContext->SetBrushColor(aColor); + bitmapContext->SetPenStyle(CGraphicsContext::ENullPen); + bitmapContext->SetBrushStyle(CGraphicsContext::ESolidBrush); + bitmapContext->DrawRect(iGlyphRect); + CleanupStack::PopAndDestroy(2, bitmapDevice); + CleanupStack::Pop(bitmap); + iColors[aColor.Color16()] = bitmap; + } + } + +CFbsBitmap* CConsoleFont::ForegroundBitmap(TRgb aColor) + { + return iColors[aColor.Color16()]; + } + +//______________________________________________________________________________ +// CConsoleLine +CConsoleLine* CConsoleLine::NewL(CConsoleControl& aControl, const CConsoleFont& aFont, TInt aWidth) + { + CConsoleLine* self = new(ELeave)CConsoleLine(aControl, aFont); + CleanupStack::PushL(self); + self->ConstructL(aWidth); + CleanupStack::Pop(self); + return self; + } + +CConsoleLine::~CConsoleLine() + { + iText.Close(); + iAttributeMap.Close(); + } + +void CConsoleLine::SetWidthL(TInt aNewWidth) + { + if (aNewWidth != iWidth) + { + RBuf8 newText; + newText.CreateL(aNewWidth); + newText.Copy(iText.Left(aNewWidth)); + newText.Swap(iText); + newText.Close(); + iWidth = aNewWidth; + iAttributeMap.RemoveFrom(aNewWidth); + } + } + +void CConsoleLine::SetL(TInt aIndex, TUint8 aChar, const ConsoleAttributes::TAttributes& aAttributes) + { + __ASSERT_ALWAYS((aIndex < iWidth)&&(aIndex>=0), User::Invariant()); + iAttributeMap.AddL(aIndex, iWidth, aAttributes); + if (aIndex > iText.Length()) + { + TInt oldLen = iText.Length(); + iText.SetLength(aIndex); + iText.MidTPtr(oldLen).Fill(' '); + iText.Append(aChar); + } + else if (aIndex == iText.Length()) + { + iText.Append(aChar); + } + else + { + iText[aIndex] = aChar; + } + } + +void CConsoleLine::Clear() + { + iAttributeMap.Reset(); + iText.Zero(); + } + +void CConsoleLine::ClearFrom(TBufferPosition aPos) + { + TInt pos = Min(aPos.iPoint.iX, iText.Length()); + iText.SetLength(pos); + iAttributeMap.RemoveFrom(pos); + } + +void CConsoleLine::Draw(CBitmapContext& aDrawTo, TViewPosition aViewPosition) const + { + const TSize glyphSize(iFont.GlyphSize()); + + TScreenPosition screenPos(aViewPosition); + TRect rectToClear(screenPos.iPoint, TScreenPosition(aViewPosition.iConsole, 0, (aViewPosition.iPoint.iY + 1) * glyphSize.iHeight).iPoint); + + const TInt numAttributeBlocks = iAttributeMap.NumberOfBlocks(); + for (TInt i = 0; i < numAttributeBlocks; ++i) + { + TInt startXPos = 0; + TInt endXPos = 0; + ConsoleAttributes::TAttributes attributes(ConsoleAttributes::ENone); + iAttributeMap.GetBlock(i, iWidth, startXPos, endXPos, attributes); + + // Draw the background in the appropriate color in one hit. + rectToClear.iTl.iX = screenPos.iPoint.iX + (startXPos * glyphSize.iWidth); + rectToClear.iBr.iX = screenPos.iPoint.iX + (endXPos * glyphSize.iWidth); + TRgb backgroundColor = MapColor(attributes.iAttributes, attributes.iBackgroundColor); + aDrawTo.SetBrushColor(backgroundColor); + aDrawTo.Clear(rectToClear); + + // Check if we're blinking. + TRgb foregroundColor = MapColor(attributes.iAttributes, attributes.iForegroundColor); + if ((attributes.iAttributes & ConsoleAttributes::EBlink) && iBlinkOn) + { + foregroundColor = backgroundColor; + } + + // Draw any non-white-space characters in the appropriate foreground color. + for (TInt i = startXPos; i < endXPos; ++i) + { + TUint16 c = At(i); + if (c != ' ') + { + const_cast(iFont).DrawChar(c, aDrawTo, TPoint(screenPos.iPoint.iX + (i * glyphSize.iWidth), screenPos.iPoint.iY), foregroundColor); + } + if (attributes.iAttributes & ConsoleAttributes::EUnderscore) + { + const_cast(iFont).DrawChar('_', aDrawTo, TPoint(screenPos.iPoint.iX + (i * glyphSize.iWidth), screenPos.iPoint.iY), foregroundColor); + } + } + + if (attributes.iAttributes & ConsoleAttributes::EBlink) + { + iControl.StartBlinking(); + } + } + } + +TBool CConsoleLine::NeedToBlink(TBool aBlinkOn) + { + TBool needToBlink(EFalse); + const TInt numAttributeBlocks = iAttributeMap.NumberOfBlocks(); + for (TInt i = 0; i < numAttributeBlocks; ++i) + { + TInt startXPos = 0; + TInt endXPos = 0; + ConsoleAttributes::TAttributes attributes(ConsoleAttributes::ENone); + iAttributeMap.GetBlock(i, iWidth, startXPos, endXPos, attributes); + if (attributes.iAttributes & ConsoleAttributes::EBlink) + { + needToBlink = ETrue; + iBlinkOn = aBlinkOn; + break; + } + } + return needToBlink; + } + +TUint16 CConsoleLine::At(TInt aPos) const + { + __ASSERT_ALWAYS((aPos < iWidth)&&(aPos>=0), User::Invariant()); + if (aPos < iText.Length()) + { + return iText[aPos]; + } + else + { + return ' '; + } + } + +CConsoleLine::CConsoleLine(CConsoleControl& aControl, const CConsoleFont& aFont) + : iControl(aControl), iFont(aFont) + { + } + +void CConsoleLine::ConstructL(TInt aWidth) + { + iText.CreateL(aWidth); + iWidth = aWidth; + } + +//______________________________________________________________________________ +// TConsoleCursor +TConsoleCursor::TConsoleCursor(CConsoleControl& aOwner) + : iOwner(aOwner) + { + iTextCursor.iType = TTextCursor::ETypeRectangle; + iTextCursor.iAscent = 0; + iTextCursor.iColor = KRgbWhite; + } + +void TConsoleCursor::SetFont(const CConsoleFont& aFont) + { + iGlyphSize = aFont.GlyphSize(); + iTextCursor.iWidth = iGlyphSize.iWidth; + } + +TConsCursorPosition TConsoleCursor::Position() const + { + return TConsCursorPosition(iOwner, iPosition); + } + +void TConsoleCursor::SetPosAbs(TConsCursorPosition aPos) + { + iPosition = aPos.iPoint; + BoundsCheck(); + } + +void TConsoleCursor::SetPosRel(TConsCursorPosition aPos) + { + iPosition += aPos.iPoint; + BoundsCheck(); + } + +void TConsoleCursor::SetHeight(TInt aPercentage) + { + aPercentage = Max(0, Min(100, aPercentage)); + TReal height = ((TReal)iGlyphSize.iHeight * (TReal)aPercentage) / 100.0; + TReal roundedHeight; + Math::Round(roundedHeight, height, 0); + iTextCursor.iHeight = (TInt)roundedHeight; + // make sure the cursor is always visible if the percentage is non-zero. + if ((iTextCursor.iHeight==0) && (aPercentage!=0)) iTextCursor.iHeight = 1; + iTextCursor.iAscent = 0; + iTextCursorOffset = iGlyphSize.iHeight - iTextCursor.iHeight; + } + +void TConsoleCursor::Update() + { + if (iOwner.IsFocused() && !iOwner.IsNonFocusing()) + { + TViewPosition viewPos = Position(); + TPoint cursorPosPixels; + cursorPosPixels.iX = viewPos.iPoint.iX * iGlyphSize.iWidth; + cursorPosPixels.iY = ((viewPos.iPoint.iY) * iGlyphSize.iHeight) + iTextCursorOffset; + /*if (iOwner.Rect().Contains(cursorPosPixels)) + {*/ + if (iOwner.DrawableWindow()) + { + CCoeEnv::Static()->RootWin().SetTextCursor(*iOwner.DrawableWindow(), cursorPosPixels, iTextCursor); + } + /* } + else + { + Hide(); + }*/ + } + } + +void TConsoleCursor::Hide() + { + CCoeEnv::Static()->RootWin().CancelTextCursor(); + } + +void TConsoleCursor::BoundsCheck() + { + iPosition.iX = Max(0, iPosition.iX); + iPosition.iY = Max(0, iPosition.iY); + iPosition.iX = Min(iOwner.ScreenSize().iWidth-1, iPosition.iX); + iPosition.iY = Min(iOwner.ScreenSize().iHeight-1, iPosition.iY); + } + +void TConsoleCursor::operator++(int) + { + (*this)+=1; + } + +void TConsoleCursor::operator--(int) + { + (*this)-=1; + } + +void TConsoleCursor::operator+=(TUint aHowMuch) + { + TSize consSize(iOwner.ScreenSize()); + while (aHowMuch) + { + TInt len = Min(consSize.iWidth - iPosition.iX, aHowMuch); + iPosition.iX += len; + aHowMuch -= len; + + if (iPosition.iX == consSize.iWidth) + { + Down(); + iPosition.iX = 0; + } + } + } + +void TConsoleCursor::operator-=(TUint aHowMuch) + { + TSize consSize(iOwner.ScreenSize()); + while (aHowMuch) + { + if (iPosition.iX == 0) + { + Up(); + iPosition.iX = consSize.iWidth; + } + + TInt len = Min(iPosition.iX, aHowMuch); + iPosition.iX -= len; + aHowMuch -= len; + } + + } + +void TConsoleCursor::Down() + { + iPosition.iY++; + if (iPosition.iY >= iOwner.ScreenSize().iHeight) + { + iPosition.iY--; + iOwner.CursorWindowScrollDown(); + } + } + +void TConsoleCursor::Up() + { + iPosition.iY--; + BoundsCheck(); + } + +//______________________________________________________________________________ +// CGuiConsole +EXPORT_C CGuiConsole::CGuiConsole(CConsoleControl& aControl) + : iControl(aControl), iRefCount(1) + { + } + +EXPORT_C CConsoleControl& CGuiConsole::Control() + { + return iControl; + } + +EXPORT_C TInt CGuiConsole::Create(const TDesC &aTitle, TSize) + { + iControl.SetTitle(aTitle); + return KErrNone; + } + +EXPORT_C void CGuiConsole::Read(TRequestStatus &aStatus) + { + if (iReadStatus || iReader) + { + TRequestStatus* stat = &aStatus; + User::RequestComplete(stat, KErrInUse); + } + else + { + iReadStatus = &aStatus; + iControl.Read(*this); + } + } + +EXPORT_C void CGuiConsole::ReadCancel() + { + if (iReadStatus) + { + User::RequestComplete(iReadStatus, KErrCancel); + iControl.ReadCancel(); + } + else if (iReader) + { + iReader->ReadComplete(KErrCancel); + iReader = NULL; + iControl.ReadCancel(); + } + } + +EXPORT_C void CGuiConsole::Write(const TDesC &aDes) + { + iControl.Write(aDes); + } + +EXPORT_C TPoint CGuiConsole::CursorPos() const + { + return iControl.CursorPos(); + } + +EXPORT_C void CGuiConsole::SetCursorPosAbs(const TPoint &aPoint) + { + iControl.SetCursorPosAbs(aPoint); + } + +EXPORT_C void CGuiConsole::SetCursorPosRel(const TPoint &aPoint) + { + iControl.SetCursorPosRel(aPoint); + } + +EXPORT_C void CGuiConsole::SetCursorHeight(TInt aPercentage) + { + iControl.SetCursorHeight(aPercentage); + } + +EXPORT_C void CGuiConsole::SetTitle(const TDesC &aTitle) + { + iControl.SetTitle(aTitle); + } + +EXPORT_C void CGuiConsole::ClearScreen() + { + iControl.ClearScreen(); + } + +EXPORT_C void CGuiConsole::ClearToEndOfLine() + { + iControl.ClearToEndOfLine(); + } + +EXPORT_C TSize CGuiConsole::ScreenSize() const + { + return iControl.ScreenSize(); + } + + +EXPORT_C TKeyCode CGuiConsole::KeyCode() const + { + return iControl.KeyCode(); + } + + +EXPORT_C TUint CGuiConsole::KeyModifiers() const + { + return iControl.KeyModifiers(); + } + +EXPORT_C TInt CGuiConsole::Extension_(TUint aExtensionId, TAny*&, TAny* a1) + { + if (aExtensionId == ConsoleAttributes::KSetConsoleAttributesExtension) + { + ConsoleAttributes::TAttributes* attributes = (ConsoleAttributes::TAttributes*)a1; + return iControl.SetAttributes(attributes->iAttributes, attributes->iForegroundColor, attributes->iBackgroundColor); + } + return KErrNotSupported; + } + +void CGuiConsole::ReadComplete(TInt aStatus) + { + if (iReadStatus) + { + User::RequestComplete(iReadStatus, aStatus); + } + if (iReader) + { + CConsoleProxySession* reader = iReader; + iReader = NULL; + reader->ReadComplete(aStatus); + } + } + +void CGuiConsole::Open() + { + ++iRefCount; + } + +void CGuiConsole::Close() + { + --iRefCount; + if (iRefCount==0) + { + delete this; + } + } + +CConsoleBase* CGuiConsole::Console() + { + return this; + } + +void CGuiConsole::Read(CConsoleProxySession& aSession) + { + if (iReader || iReadStatus) + { + aSession.ReadComplete(KErrInUse); + } + else + { + iReader = &aSession; + iControl.Read(*this); + } + } + +CGuiConsole::~CGuiConsole() + { + iControl.Closed(); + } + +//______________________________________________________________________________ +// TBufferPosition +TBufferPosition::TBufferPosition(const CConsoleControl& aConsole, TPoint aPosition) + : iConsole(aConsole), iPoint(aPosition) + { + } + +TBufferPosition::TBufferPosition(const CConsoleControl& aConsole, TInt aX, TInt aY) + : iConsole(aConsole), iPoint(aX, aY) + { + } + +TBufferPosition::TBufferPosition(const TConsCursorPosition& aCursorPosition) + : iConsole(aCursorPosition.iConsole) + , iPoint(aCursorPosition.iPoint + aCursorPosition.iConsole.CursorWindowPosition()) + { + } + +TBufferPosition::TBufferPosition(const TViewPosition& aViewPosition) + : iConsole(aViewPosition.iConsole) + , iPoint(aViewPosition.iPoint + aViewPosition.iConsole.ViewPosition()) + { + } + + + +//______________________________________________________________________________ +// TConsCursorPosition +TConsCursorPosition::TConsCursorPosition(const CConsoleControl& aConsole, TPoint aPosition) + : iConsole(aConsole), iPoint(aPosition) + { + } + +TConsCursorPosition::TConsCursorPosition(const CConsoleControl& aConsole, TInt aX, TInt aY) + : iConsole(aConsole), iPoint(aX, aY) + { + } + +TConsCursorPosition::TConsCursorPosition(const TBufferPosition& aBufferPosition) + : iConsole(aBufferPosition.iConsole) + , iPoint(aBufferPosition.iPoint - aBufferPosition.iConsole.CursorWindowPosition()) + { + } + +TConsCursorPosition::TConsCursorPosition(const TViewPosition& aViewPosition) + : iConsole(aViewPosition.iConsole) + , iPoint(aViewPosition.iPoint + aViewPosition.iConsole.ViewPosition() - aViewPosition.iConsole.CursorWindowPosition()) + { + } + + + +//______________________________________________________________________________ +// TViewPosition +TViewPosition::TViewPosition(const CConsoleControl& aConsole, TPoint aPosition) + : iConsole(aConsole), iPoint(aPosition) + { + } + +TViewPosition::TViewPosition(const CConsoleControl& aConsole, TInt aX, TInt aY) + : iConsole(aConsole), iPoint(aX, aY) + { + } + +TViewPosition::TViewPosition(const TConsCursorPosition& aCursorPosition) + : iConsole(aCursorPosition.iConsole) + , iPoint(aCursorPosition.iPoint + aCursorPosition.iConsole.CursorWindowPosition() - aCursorPosition.iConsole.ViewPosition()) + { + } + +TViewPosition::TViewPosition(const TBufferPosition& aBufferPosition) + : iConsole(aBufferPosition.iConsole) + , iPoint(aBufferPosition.iPoint - aBufferPosition.iConsole.ViewPosition()) + { + } + +//______________________________________________________________________________ +// TScreenPosition +TScreenPosition::TScreenPosition(const CConsoleControl& aConsole, TPoint aPosition) + : iConsole(aConsole), iPoint(aPosition) + { + } + +TScreenPosition::TScreenPosition(const CConsoleControl& aConsole, TInt aX, TInt aY) + : iConsole(aConsole), iPoint(aX, aY) + { + } + +TScreenPosition::TScreenPosition(const TViewPosition& aViewPosition) + : iConsole(aViewPosition.iConsole) + , iPoint(aViewPosition.iPoint.iX * aViewPosition.iConsole.GlyphSize().iWidth, aViewPosition.iPoint.iY * aViewPosition.iConsole.GlyphSize().iHeight) + { + } + +//______________________________________________________________________________ +// RAttributeMap + +RAttributeMap::RAttributeMap() + : iAttributes(KAttributeMapGranularity, _FOFF(TAttributes, iPosition)) + { + } + +void RAttributeMap::Close() + { + iAttributes.Close(); + } + +void RAttributeMap::Reset() + { + iAttributes.Reset(); + } + +void RAttributeMap::AddL(TInt aPosition, TInt aLineWidth, const ConsoleAttributes::TAttributes& aAttributes) + { + // Take a copy of the attributes array to make cleanup easier. + RArray attributes; + CleanupClosePushL(attributes); + const TInt numAttributes = iAttributes.Count(); + for (TInt i = 0; i < numAttributes; ++i) + { + attributes.AppendL(iAttributes[i]); + } + + if (attributes.Count() == 0) + { + // This is the first set of attributes to be added. Add a default set before them. + attributes.AppendL(TAttributes(0, DefaultAttributes())); + } + + TAttributes attr(aPosition, aAttributes); + TInt pos; + TInt err = attributes.FindInSignedKeyOrder(attr, pos); + if (err == KErrNone) + { + // Attribute already exists at this position - replace. + attributes[pos] = attr; + } + else + { + // No attribute found at aPosition. + // pos is set to the index _after_ aPosition. This must be at least 1 because the first slot in the array is always taken with defaults or something else. + // Set pos to the index _before_ aPosition. + --pos; + + // Check earlier attributes to see if they match. + if (!(attributes[pos] == attr)) + { + // No match - insert new attributes. + attributes.InsertInSignedKeyOrderL(attr); + + // Get the position of the newly inserted attributes. + attributes.FindInSignedKeyOrder(attr, pos); + } + } + + const TAttributes& newAttributes = attributes[pos]; + if ((pos == (attributes.Count() - 1)) && (newAttributes.iPosition < (aLineWidth - 1)) && !(newAttributes == TAttributes(0, DefaultAttributes()))) + { + // New attributes are the last in the list, and not at the end of the line and not defaults. + // Add another set of defaults after them. + attributes.AppendL(TAttributes(newAttributes.iPosition + 1, DefaultAttributes())); + } + + iAttributes.Close(); + iAttributes = attributes; + CleanupStack::Pop(&attributes); + } + +void RAttributeMap::RemoveFrom(TInt aPosition) + { + for (TInt i = (iAttributes.Count() - 1); i >= 0; --i) + { + if (iAttributes[i].iPosition >= aPosition) + { + iAttributes.Remove(i); + } + } + } + +TInt RAttributeMap::NumberOfBlocks() const + { + if (iAttributes.Count() == 0) + { + return 1; // If no attributes have been added, give the entire line an implict default set of attributes. + } + return iAttributes.Count(); + } + +void RAttributeMap::GetBlock(TInt aIndex, TInt aLineWidth, TInt& aStartPosition, TInt& aEndPosition, ConsoleAttributes::TAttributes& aAttributes) const + { + if (iAttributes.Count() == 0) + { + ASSERT(aIndex == 0); + aStartPosition = 0; + aEndPosition = aLineWidth; + aAttributes = DefaultAttributes(); + } + else + { + const TAttributes& attributes = iAttributes[aIndex]; + aAttributes = attributes.iAttributes; + aStartPosition = attributes.iPosition; + + if ((iAttributes.Count() == 1) || (aIndex == (iAttributes.Count() - 1))) + { + aEndPosition = aLineWidth; + } + else + { + aEndPosition = iAttributes[aIndex + 1].iPosition; + } + } + } + +RAttributeMap::TAttributes::TAttributes(TInt aPosition, const ConsoleAttributes::TAttributes& aAttributes) + : iPosition(aPosition), iAttributes(aAttributes) + { + } + +TBool RAttributeMap::TAttributes::operator==(const TAttributes& aAttributes) const + { + // Note, intentionally ignoring iPosition so ensure that existing attribute block are extended where possible. + return ((iAttributes.iAttributes == aAttributes.iAttributes.iAttributes) && + (iAttributes.iForegroundColor == aAttributes.iAttributes.iForegroundColor) && + (iAttributes.iBackgroundColor == aAttributes.iAttributes.iBackgroundColor)); + }