diff -r 000000000000 -r 2f259fa3e83a uifw/EikStd/coctlsrc/aknedwincustomdrawbase.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/uifw/EikStd/coctlsrc/aknedwincustomdrawbase.cpp Tue Feb 02 01:00:49 2010 +0200 @@ -0,0 +1,767 @@ +/* +* Copyright (c) 2002 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: +* +*/ + + +// INCLUDE FILES +#include "aknedwincustomdrawbase.h" +#include +#include +#include +#include +#include +#include // for AKN_LAF_COLOR macro +#include +#include +#include +#include +#include +#include +#include +#include + + +// CONSTANTS + +// This is the last character that will be treated as requiring higher underline +// const TText KMaxSpecialUnderliningChar = 0x0E5B; +const TInt KWsBufferSize = 16000; + +// MEMBER FUNCTIONS + +CAknEdwinCustomDrawBase::CAknEdwinCustomDrawBase( + const MLafEnv& aEnv, const CEikEdwin& aEdwin ) : + CLafEdwinCustomDrawBase( aEnv, aEdwin ), iEdwin( aEdwin ) + { + // This value has to be stored as the meaning of the flag governs behaviour of controls + // at the point of construction + iAppSkinEnabled = AknsUtils::AvkonSkinEnabled(); + } + +CAknEdwinCustomDrawBase::CAknEdwinCustomDrawBase( + const MLafEnv& aEnv, + const CEikEdwin& aEdwin, + CTextView* aTextView, + CWindowGc* aSystemGc ) : + CLafEdwinCustomDrawBase( aEnv,aEdwin ), + iEdwin( aEdwin ), + iTextView( aTextView ), + iSysGc( aSystemGc ) + { + // This value has to be stored as the meaning of the flag governs behaviour of controls + // at the point of construction + iAppSkinEnabled = AknsUtils::AvkonSkinEnabled(); + } + +// ----------------------------------------------------------------------------- +// CAknEdwinCustomDrawBase::ConstructL +// Symbian 2nd phase constructor can leave. +// ----------------------------------------------------------------------------- +// +void CAknEdwinCustomDrawBase::ConstructL() + { + iWsBufferRequestId = CAknEnv::Static()->RequestWsBuffer( KWsBufferSize ); + // Returns NULL if feature not supported. + iPictographDrawer = CAknPictographInterface::NewL( + static_cast( const_cast( iEdwin ) ), + *static_cast( this ) ); + } + +// ----------------------------------------------------------------------------- +// CAknEdwinCustomDraw::NewL +// Two-phased constructor. +// ----------------------------------------------------------------------------- +// +CAknEdwinCustomDrawBase* CAknEdwinCustomDrawBase::NewL( + const MLafEnv& aEnv, const CEikEdwin& aControl ) + { // static + CAknEdwinCustomDrawBase* self = + new( ELeave ) CAknEdwinCustomDrawBase( aEnv, aControl ); + CleanupStack::PushL( self ); + self->ConstructL(); + CleanupStack::Pop(); + return self; + } + +// ----------------------------------------------------------------------------- +// CAknEdwinCustomDraw::NewL +// Two-phased constructor. +// ----------------------------------------------------------------------------- +// +CAknEdwinCustomDrawBase* CAknEdwinCustomDrawBase::NewL( + const MLafEnv& aEnv, + const CEikEdwin& aControl, + CTextView* aTextView, + CWindowGc* aSystemGc ) + { // static + CAknEdwinCustomDrawBase* self = new( ELeave ) CAknEdwinCustomDrawBase( + aEnv, aControl, aTextView, aSystemGc ); + CleanupStack::PushL( self ); + self->ConstructL(); + CleanupStack::Pop(); + return self; + } + +// Destructor +CAknEdwinCustomDrawBase::~CAknEdwinCustomDrawBase() + { + delete iPictographDrawer; + CAknEnv::Static()->CancelWsBufferRequest( iWsBufferRequestId ); + } + +// ----------------------------------------------------------------------------- +// CAknEdwinCustomDrawBase::DrawPictographArea +// ----------------------------------------------------------------------------- +// +void CAknEdwinCustomDrawBase::DrawPictographArea() + { + iEdwin.DrawTextView(); + + // Mainly used for drawing form highlight frame + const TCallBack& callback = iEdwin.PictographAnimationCallBack(); + if ( callback.iFunction ) + { + callback.CallBack(); + } + } + +// ----------------------------------------------------------------------------- +// CAknEdwinCustomDrawBase::DrawText +// ----------------------------------------------------------------------------- +// +void CAknEdwinCustomDrawBase::DrawText( const TParam& aParam, + const TLineInfo& aLineInfo, const TCharFormat& aFormat, const TDesC& aText, + const TPoint& aTextOrigin, TInt aExtraPixels ) const + { + TRect textLinesRect = iEdwin.GetTextLinesRect(); + + if ( !textLinesRect.IsEmpty() ) + { + if ( aLineInfo.iInnerRect.iTl.iY < textLinesRect.iTl.iY || + aLineInfo.iInnerRect.iBr.iY > textLinesRect.iBr.iY ) + { + return; + } + } + + TCharFormat alteredFormat(aFormat); + + if( aFormat.iFontPresentation.iUnderline == EUnderlineOn ) + { + // Inhibit all excess pixels + aExtraPixels = 0; + + TInt underlinePos(0); + (void)TextNeedsCustomUnderline( aText, aParam, aFormat, underlinePos ) ; + // always perform custom underlining + + TRect underlineRect(aParam.iDrawRect); + TAknTextDecorationMetrics decoration( 0 ); // Give dummy font id for default decoration + // Note that underlinePos in scalable is a delta relative to normal baseline + underlineRect.iBr.iY = aLineInfo.iBaseline - underlinePos + decoration.BaselineToUnderlineOffset(); + underlineRect.iTl.iY = underlineRect.iBr.iY - decoration.UnderlineHeight(); + + TRAPD + ( + err, + DrawUnderlineL( underlineRect, aParam,aLineInfo,alteredFormat,aText,aTextOrigin,aExtraPixels) + ); + if ( err != KErrNone ) + { + // Just draw the underline solid + aParam.iGc.DrawRect( underlineRect ); + } + // we've handled the underline, so switch it off now + alteredFormat.iFontPresentation.iUnderline = EUnderlineOff; + aParam.iGc.SetUnderlineStyle( EUnderlineOff); // and force it off in the GC + } + CFont* font = NULL; + aParam.iMap.GetNearestFontInTwips( font, aFormat.iFontSpec ); + RRegion rgn; + if ( iEdwin.IsSmileyEnabled() && font ) + { + rgn.AddRect( iEdwin.AdjustDrawRectForSmiley( aParam.iDrawRect ) ); + iEdwin.GetClipRegionForSmiley( rgn, *font, aText, aTextOrigin, + aParam.iDrawRect ); + aParam.iGc.SetClippingRegion( rgn ); + } + CLafEdwinCustomDrawBase::DrawText( aParam, aLineInfo, alteredFormat, + aText, aTextOrigin, aExtraPixels ); + if ( iEdwin.IsSmileyEnabled() ) + { + aParam.iGc.CancelClippingRegion(); + } + rgn.Close(); + + if ( iEdwin.IsSmileyEnabled() && font && ( &aParam.iGc == + static_cast( iTextView->BitmapContext() ) ) ) + { + CBitmapContext* bitmapGc( iTextView->BitmapContext() ); + CEikEdwin& edwin = const_cast( iEdwin ); + TPoint startPt( aParam.iDrawRect.iTl ); + startPt.iY = aLineInfo.iBaseline; + TRAP_IGNORE( { + edwin.HandleScrollForSmileyL(); + edwin.DrawSmileyInTextL( *bitmapGc, *font, aText, startPt ); + } ); + } + + // Draw pictographs if the feature is supported. + // Character justification is not supported. + if ( ( iPictographDrawer && !aExtraPixels ) ) + { + CBitmapContext* bitmapGc = NULL; + + // This is how we check the type of the graphics context + // The gc should be one of these: + if ( &aParam.iGc == static_cast( iSysGc ) ) + { + bitmapGc = iSysGc; + } + else if ( &aParam.iGc == + static_cast( iTextView->BitmapContext() ) ) + { + bitmapGc = iTextView->BitmapContext(); + } + + if ( bitmapGc ) + { + const TText* text = aText.Ptr(); + TInt length( aText.Length() ); + + TPoint point = aParam.iDrawRect.iTl; + point.iY = aLineInfo.iBaseline; + if ( iPictographDrawer && !aExtraPixels ) + { + MAknPictographDrawer* drawer = + iPictographDrawer->Interface(); + if ( font ) + { + drawer->DrawPictographsInText( + *bitmapGc, + *font, + aText, + point); + } + } + } + } + aParam.iMap.ReleaseFont( font ); + // set brush back to original + aParam.iGc.SetBrushColor(CEikonEnv::Static()->ControlColor(EColorControlBackground,iEdwin)); + } + +// ----------------------------------------------------------------------------- +// CAknEdwinCustomDrawBase::DrawText +// ----------------------------------------------------------------------------- +// +void CAknEdwinCustomDrawBase::DrawText( const TParam& aParam, + const TLineInfo& aLineInfo, const TCharFormat& aFormat, const TDesC& aText, + const TInt aStart, const TInt aEnd, const TPoint& aTextOrigin, + TInt aExtraPixels ) const + { + DrawText( aParam, aLineInfo, aFormat, aText.Mid( aStart, aEnd - aStart ), + aTextOrigin, aExtraPixels ); + } + +// ----------------------------------------------------------------------------- +// CAknEdwinCustomDrawBase::DrawBackground +// ----------------------------------------------------------------------------- +// +void CAknEdwinCustomDrawBase::DrawBackground( + const TParam& aParam, const TRgb& aBackground, TRect& aDrawnRect ) const + { + if ( !iEdwin.IsBackgroundDrawingSuppressed() ) + { + const MCoeControlBackground* drawer = iEdwin.FindBackground(); + + if ( drawer ) + { + if ( !iEdwin.SkipBackgroundDrawer() ) + { + drawer->Draw( static_cast( aParam.iGc ), + iEdwin, + aParam.iDrawRect ); + } + } + else + { + if ( !DrawRectWithSkin( aParam.iGc, aParam.iDrawRect, aDrawnRect ) ) + { + aParam.iGc.SetBrushStyle( CGraphicsContext::ESolidBrush ); + aParam.iGc.SetPenStyle( CGraphicsContext::ESolidPen ); + aParam.iGc.SetBrushColor( aBackground ); + aParam.iGc.SetPenColor( aBackground ); + aParam.iGc.DrawRect( aParam.iDrawRect ); + } + } + } + + aDrawnRect = aParam.iDrawRect; + } + +// ----------------------------------------------------------------------------- +// CAknEdwinCustomDrawBase::DrawLineGraphics +// ----------------------------------------------------------------------------- +// +void CAknEdwinCustomDrawBase::DrawLineGraphics(const TParam& aParam,const TLineInfo& aLineInfo ) const + { + CLafEdwinCustomDrawBase::DrawLineGraphics( aParam, aLineInfo ); // Base Call + } + + +TRgb CAknEdwinCustomDrawBase::SystemColor(TUint aColorIndex,TRgb aDefaultColor) const + { + TRgb ret = aDefaultColor; + if (aColorIndex==TLogicalRgb::ESystemForegroundIndex) + { + MAknsSkinInstance* skin = AknsUtils::SkinInstance(); + if (skin && iEdwin.SkinColorId() != KErrNotFound) + { + AknsUtils::GetCachedColor(skin, ret, KAknsIIDQsnTextColors, iEdwin.SkinColorId()); + } + } + else if (aColorIndex==TLogicalRgb::ESystemBackgroundIndex) + { + // Only override aDefaultColor if SetBackgroundColorL was called: + (void)iEdwin.EditorBackgroundColor(ret); + // Insist on opaque background + ret.SetAlpha(0xFF); + } + + else if (aColorIndex==TLogicalRgb::ESystemSelectionForegroundIndex) + { + ret = KRgbWhite; + MAknsSkinInstance* skin = AknsUtils::SkinInstance(); + if (skin) + { + if ( iEdwin.HighlightStyle() == EEikEdwinHighlightLink ) + { + AknsUtils::GetCachedColor(skin, ret, KAknsIIDQsnHighlightColors, EAknsCIQsnTextColorsCG3); + } + else // default + { + AknsUtils::GetCachedColor(skin, ret, KAknsIIDQsnTextColors, EAknsCIQsnTextColorsCG24); + } + } + } + else if (aColorIndex==TLogicalRgb::ESystemSelectionBackgroundIndex) + { + ret = KRgbBlue; + MAknsSkinInstance* skin = AknsUtils::SkinInstance(); + if (skin) + { + if ( iEdwin.HighlightStyle() == EEikEdwinHighlightLink ) + { + AknsUtils::GetCachedColor(skin, ret, KAknsIIDQsnHighlightColors, EAknsCIQsnTextColorsCG1); + } + else // default + { + AknsUtils::GetCachedColor(skin, ret, KAknsIIDQsnHighlightColors, EAknsCIQsnHighlightColorsCG2); + } + } + } + + return ret; + } + +void CAknEdwinCustomDrawBase::CAknEdwinCustomDrawBase_Reserved_1() + { + } + +/** +* Routine to group the common skin custom drawing +* +* @return TBool EFalse iff the drawing was not performed +*/ +TBool CAknEdwinCustomDrawBase::DrawRectWithSkin( const CGraphicsContext& aGc, const TRect& aRect, TRect& aDrawnRect ) const + { + TBool drawn(EFalse); + + if ( iAppSkinEnabled && iTextView) + { + CBitmapContext* bitmapGc = NULL; + + // This is how we check the type of the graphics context + // The gc should be one of these: + if ( &aGc == static_cast( iSysGc ) ) + bitmapGc = iSysGc; + else if ( &aGc == static_cast( iTextView->BitmapContext() ) ) + bitmapGc = iTextView->BitmapContext(); +#ifdef RD_UI_TRANSITION_EFFECTS_POPUPS + else if( &aGc == static_cast( &(iControl.SystemGc()) ) ) + bitmapGc = &(iControl.SystemGc()); +#endif //RD_UI_TRANSITION_EFFECTS_POPUPS + if ( bitmapGc && iEdwin.SkinEnabled() ) + { + MAknsSkinInstance* skin = AknsUtils::SkinInstance(); + // Edwin manages the skin background + MAknsControlContext* edCc = iEdwin.SkinBackgroundControlContext(); + + TInt drawFlags = KAknsDrawParamDefault; + if( CAknEnv::Static()->TransparencyEnabled() ) + { + drawFlags |= KAknsDrawParamNoClearUnderImage; + } + + if( AknsDrawUtils::DrawBackground( skin, edCc, + &iControl, *bitmapGc, aRect.iTl, aRect, + drawFlags )) + { + aDrawnRect = aRect; + drawn = ETrue; + } + } + else + { + // perform unoptimized draw of skin using bitmap brushstyle? + } + + } + + return drawn; + } + +TBool CAknEdwinCustomDrawBase::TextNeedsCustomUnderline( const TDesC& aText, const TParam& aParam, const TCharFormat& aFormat, TInt& underlinePos ) const + { + TBool needsCustomUnderline(EFalse); + + TInt fontProviderIndex = AknFontProvider::FontProviderIndexFromFontSpec( aFormat.iFontSpec ); + if ( fontProviderIndex > KErrNotFound ) + { + needsCustomUnderline = AknFontProvider::HasBaselineCorrection( fontProviderIndex ); + if ( needsCustomUnderline ) + { + TInt denominatorIfFractional(KAknFontProviderBaselineCorrectionIsAbsolute); + TInt numInitialCharsTheSame(0); // not used + TInt minimumBaselineLift(0); + AknFontProvider::MinimumBaselineDeltaForDescriptor( + fontProviderIndex, + aText, + minimumBaselineLift, + denominatorIfFractional, + EFalse, // Look at whole descriptor and take minimum baseline lift + numInitialCharsTheSame); + + // Check for proportional baseline deltas: + if ( denominatorIfFractional != KAknFontProviderBaselineCorrectionIsAbsolute ) + { + underlinePos = minimumBaselineLift * aParam.iDrawRect.Height() / denominatorIfFractional; + } + else + { + underlinePos = minimumBaselineLift; + } + } + } + + return needsCustomUnderline; + } + +// ----------------------------------------------------------------------------- +// CAknEdwinCustomDrawBase::DrawUnderlineL +// ----------------------------------------------------------------------------- +/* +This method has the responsibility for drawing a custom underline. + +An offscreen bitmap with 8 bit greyscale is made the size of the underline. Using the same font as the editor, the text +is drawn onto this bitmap, with variable positioning, so that the text is smeared. + +The "descenderBitmap" is passed to a routine that analyzes this bitmap and draws the underlines only in +between the descenders, leaving gaps. + +*/ +void CAknEdwinCustomDrawBase::DrawUnderlineL( + const TRect& aUnderlineRect, + const TParam& aParam, + const TLineInfo& aLineInfo, + const TCharFormat& aFormat, + const TDesC& aText, + const TPoint& /*aTextOrigin*/, // Not currently used + TInt aExtraPixels) const + { + + if (aUnderlineRect.Width() <= 0 || aUnderlineRect.Height() <= 0 ) + return; + + TRect localUnderlineRect(aUnderlineRect); + + // Create bitmap to draw the descenders to + CFbsBitmap* descendersBitmap = new (ELeave) CFbsBitmap(); + CleanupStack::PushL( descendersBitmap); + User::LeaveIfError( descendersBitmap->Create(TSize(localUnderlineRect.Width(),localUnderlineRect.Height()) , EGray256)); + + CFbsBitmapDevice* device = CFbsBitmapDevice::NewL(descendersBitmap); + CleanupStack::PushL(device); + CGraphicsContext* context=NULL; + User::LeaveIfError(device->CreateContext(context)); + CleanupStack::PushL(context); + + CFont* font; + // Fetch the font. This font is already in use by the editor. Since it is a request in twips, it will be in the + // twips cache and the request should not go to the Fbserv server. It should therefore be fast. + User::LeaveIfError(aParam.iMap.GetNearestFontInTwips( font, aFormat.iFontSpec) ); + + context->UseFont( font ); + DrawDescendersOntoBitmap( *context, aText, aParam, aLineInfo, localUnderlineRect, aExtraPixels ); + context->DiscardFont (); + + aParam.iMap.ReleaseFont( font ); + + // Draw the line using aParam.iGc so as to pick up correct foreground color. Algo inside this method is used to avoid the descenders that are + // already drawn onto descendersBitmap + DrawLineWithGaps( aParam, *descendersBitmap, localUnderlineRect ) ; + + // Delete all the local objects + CleanupStack::PopAndDestroy( context ); + CleanupStack::PopAndDestroy( device ); + CleanupStack::PopAndDestroy( descendersBitmap ); + } + +/** +* The descender parts of the text are drawn onto the bitmap context. +* The text is drawn several times with horizontal and vertical offsets. The resulting bitmap will be used to determine +* where the underline should be drawn to avoid touching the descenders +*/ +void CAknEdwinCustomDrawBase::DrawDescendersOntoBitmap( + CGraphicsContext& aContext, + const TDesC& aText, + const TParam& /*aParam*/, + const TLineInfo& aLineInfo, + const TRect& aUnderlineRect, + TInt aExtraPixels ) const + { + // Have to arrange to draw text onto the underline rectangle bitmap context. + // The text needs to be positioned so that the correct parts of the text (ie.part of the descenders) + // are within this underline rectangle. We need to calculate the distance from the top of the drawing rectangle + // (which will perform the clipping) to the baseline of the text. + // This will be used as the "aBaselineOffset" parameter to the CGraphicsContext::DrawText method. + // Expect this value to be small and negative, since the baseline is usually above the underline. + TInt posOfBaselineFromUnderline = posOfBaselineFromUnderline = aLineInfo.iBaseline - aUnderlineRect.iTl.iY; + + // Here, draw the text with letter spacing. This is what Tagma will do when it really draws the text. + if (aExtraPixels) + { + aContext.SetCharJustification(aExtraPixels,aText.Length()); + } + + // We are going to draw the text moved around both horizontally and vertically. + // Use this rectangle with 0,0 at top left to match the bitmap's own 0,0-based coord system + TRect movingRect( TPoint(0,0), TPoint( aUnderlineRect.Width(), aUnderlineRect.Height())); + + // Double loop to perform text smearing horizontally and vertically + + // These constants reflect the desired gaps around the descenders + // This calculation allows the descender-avoiding gaps to scale: + const TInt KHorizontalSmear = Max( aUnderlineRect.Height()/2, 1); + const TInt KVerticalSmear = KHorizontalSmear; + + for ( TInt xOffset = -KHorizontalSmear; xOffset <= KHorizontalSmear; xOffset++ ) + { + for ( TInt yOffset = -KVerticalSmear; yOffset <= KVerticalSmear; yOffset++ ) + { + // Drawing is relative to the left, and top (assuming posOfBaselineFromUnderline is constant), so fiddle + // top left point. + movingRect.iTl.iX = xOffset; + movingRect.iTl.iY = 0; + aContext.DrawText( aText, movingRect, posOfBaselineFromUnderline + yOffset, CGraphicsContext::ELeft, 0 ); + } + } + } + +/** + Draws the underline in the aParam.iGc pen color onto the screen, but uses the smeared descenders bitmap to + avoid drawing underline through descenders. + + The offscreen bitmap is walked, watching for light/dark and dark./light transitions which drive the drawing of line segments + on the screen device. + + Various features are built in the bitmap walk. + - use special "off" threshold near the beginning of a text to encourage leading bits of underline + - special "on" threshold to encourage small trailing pieces of underlines + + There are special conditions that must be met for success to be claimed, and a value of ETrue to be returned. + These conditions insist on at least one segment of line being drawn, and that lines occupy a big enough percentage of the + total underline length. + */ +void CAknEdwinCustomDrawBase::DrawLineWithGaps( + const TParam& aParam, + CFbsBitmap& aSmearedDescendersBitmap, + const TRect& aUnderlineRect ) const + { + // Use the Symbian utility to provide access to bitmaps: + TBitmapUtil util(&aSmearedDescendersBitmap); + util.Begin( TPoint(0,0) ); + + const TInt lastRow = aUnderlineRect.Height() - 1; // zero-based + const TInt lastPos = aUnderlineRect.Width() - 1; // zero-based + + TUint32 thisPixel; + const TUint32 thresholdPixel(254); // Must suit the TDrawMode. This value for Gray255 + const TUint32 darkerThreshold(32); // Must suit the TDrawMode. this low (near-black) value encourages underlines to start at the far left. + const TUint32 endThreshold(128); // Must suit the TDrawMode. Lower threshold to encourage a line segment at the far right. + const TInt shortRunLimit(1); + + // Anchor and end point are used to draw the lines in the most common cases + TPoint anchor; + TPoint earlyAnchor; + + // State flags + TBool currentlyInALine; // An anchor point of some sort has been recorded. Committed to drawing at least something for the segment. + TBool earlyLineActive; // Special state where the earlyAnchor is used rather than the normally recorded one. + + TInt numberSegmentsDrawn(0); // records how many segments of underline are drawn. Used to set a return value + TInt lengthDrawnOnThisLine(0); + TInt maxPercentOfALineDrawn(0); + + // Analyse the smeared character bitmap, and draw line segments that avoid the descenders + // The smeared descenders appear as black (or grey) pixels in the offscreen bitmap + // Using gray256, white is 255, black is 0. + // Do not get confused by the fact we tend to draw where there is white, and not draw then there is black! + + for ( TInt row = 0; row <= lastRow; row++, util.IncYPos() ) + { + // Set at beginning of the row at column 0 + util.SetPos( TPoint(0,row) ); + + // row initialization. + TInt pos = 0; // Position in the row. + currentlyInALine = EFalse; + earlyLineActive = EFalse; + lengthDrawnOnThisLine = 0; // zero the length recorded to be drawn in each row. + + thisPixel = util.GetPixel(); + if ( thisPixel >= darkerThreshold ) // use low (near-black) value to encourage leading lines + { + anchor = TPoint(aUnderlineRect.iTl.iX + pos, aUnderlineRect.iTl.iY + row); // beginning of lines + currentlyInALine = ETrue; + } + + for (util.IncXPos(), pos = 1; pos < lastPos; pos++, util.IncXPos()) + { + thisPixel = util.GetPixel(); + + if ( currentlyInALine ) + { + // If we are not near the beginning, but have gone below normal threshold, end the line segment + TBool endTheLineSegment(EFalse); + if ( thisPixel < thresholdPixel && pos > shortRunLimit ) //then end it + { + endTheLineSegment = ETrue; + } + // If we ARE near the beginning and below the special dark threshold + else if ( thisPixel < darkerThreshold && pos <= shortRunLimit ) + { + endTheLineSegment = ETrue; + } + + if ( endTheLineSegment ) + { // The last TPoint is not drawn, so use pos and not pos - 1 + DrawLineAndRecord( aParam.iGc, aUnderlineRect, anchor, pos, row, lengthDrawnOnThisLine, numberSegmentsDrawn); + currentlyInALine = EFalse; + earlyLineActive = EFalse; // cancel any early starts + } + + } + else // not currentlyInALine + { + // + if (thisPixel >= thresholdPixel ) // not in a line, but now above threshold + { + anchor = TPoint(aUnderlineRect.iTl.iX+pos, aUnderlineRect.iTl.iY + row); + currentlyInALine = ETrue; + } + else if ( thisPixel >= endThreshold ) // mark a potential "early start" for a line if even a little off black + { + // There is no test on whether we are already in earlyLineActive, so this updates, essentially recording a last + // point above this lower threshold + earlyAnchor = TPoint( aUnderlineRect.iTl.iX+pos, aUnderlineRect.iTl.iY + row ); + earlyLineActive = ETrue; + // But not currently in a line + } + else // not in a line and going below (darker than) endThreshold cancels the earlyLine stuff + { + earlyLineActive = EFalse; + } + } + + } // end of for loop over columns + + // Finish off the line. Pixel index already incremented by the for loop, but the pixel has not been fetched + thisPixel = util.GetPixel(); + if ( currentlyInALine) + { + // 2nd TPoint in the call is not plotted, so go further, to lastPos+1 + DrawLineAndRecord( aParam.iGc, aUnderlineRect, anchor, lastPos+1, row, lengthDrawnOnThisLine, numberSegmentsDrawn); + } + else + { + // Special rule, with special low threshold, to get end runs even if somewhat suppressed + if ( thisPixel >= endThreshold ) + { + if ( earlyLineActive ) // Use the recorded early anchor + { + // 2nd TPoint in the call is not plotted, so go further by 1 + DrawLineAndRecord( aParam.iGc, aUnderlineRect, earlyAnchor, lastPos+1, row, lengthDrawnOnThisLine, numberSegmentsDrawn); + } + else // just draw the one point + { + TPoint startPoint(aUnderlineRect.iTl.iX+lastPos,aUnderlineRect.iTl.iY + row); + // 2nd TPoint in the call is not plotted, so go further by 1 + DrawLineAndRecord( aParam.iGc, aUnderlineRect, startPoint, lastPos+1, row, lengthDrawnOnThisLine, numberSegmentsDrawn); + } + } + } + + maxPercentOfALineDrawn = Max( maxPercentOfALineDrawn, (lengthDrawnOnThisLine * 100 )/aUnderlineRect.Width() ); + } // end of for loop over rows + + util.End(); + + // Check criteria for whether to say this was successful or not. + const TInt KMinPercentOfLineDrawn(33); // need a third drawn + if ( numberSegmentsDrawn < (aUnderlineRect.Height()*2) && ( maxPercentOfALineDrawn < KMinPercentOfLineDrawn ) ) + { + // Not enough line drawn. + // Extend the underlines on both sides. Use some scaling for how much to extend + const TInt extraLineLength = Max( 1, aUnderlineRect.Height() ); + for ( TInt row = 0; row <= lastRow; row++ ) // lastRow is zero-based + { + aParam.iGc.DrawLine( + TPoint(aUnderlineRect.iTl.iX-extraLineLength, aUnderlineRect.iTl.iY+ row ), + TPoint(aUnderlineRect.iTl.iX, aUnderlineRect.iTl.iY+ row) ); + aParam.iGc.DrawLine( + TPoint(aUnderlineRect.iBr.iX, aUnderlineRect.iTl.iY+ row ), + TPoint(aUnderlineRect.iBr.iX+extraLineLength, aUnderlineRect.iTl.iY+ row) ); + } + + } + } + +void CAknEdwinCustomDrawBase::DrawLineAndRecord( + CGraphicsContext& aGc, + const TRect& aRect, + const TPoint& aAnchor, + TInt aColumn, + TInt aRow, + TInt& aAccumulatedLength, + TInt& aSegmentsDrawn) const + { + TPoint endPoint = TPoint(aRect.iTl.iX + aColumn, aRect.iTl.iY + aRow); + aGc.DrawLine( aAnchor, endPoint ); + aAccumulatedLength += (endPoint.iX - aAnchor.iX); + aSegmentsDrawn++; + }