author | Gareth Stockwell <gareth.stockwell@accenture.com> |
Fri, 22 Oct 2010 11:38:29 +0100 | |
branch | bug235_bringup_0 |
changeset 206 | c170e304623f |
parent 0 | 5d03bc08d59c |
permissions | -rw-r--r-- |
// Copyright (c) 1997-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: // #include <fntstore.h> #include <bitdraw.h> #include <bitstd.h> #include <bitdev.h> #include "BITPANIC.H" #include <shapeinfo.h> #include <bmalphablend.h> #include <bitdrawinterfaceid.h> #include <graphics/fbsrasterizer.h> #include "bitgcextradata.h" #include <graphics/gdi/gdiconsts.h> #include <graphics/gdi/gdistructs.h> /** Draws text at the last print position. @param aText The text string to be drawn. */ EXPORT_C void CFbsBitGc::DrawText(const TDesC& aText) { TTextParameters* param = NULL; DrawText(aText,param,iLastPrintPosition,ELeft,CFont::EHorizontal); } /** Draws text at the specified position and updates the print position. @param aText The text string to be drawn @param aCoords Coordinates to draw the text at. */ EXPORT_C void CFbsBitGc::DrawText(const TDesC& aText,const TPoint& aCoords) { TTextParameters* param = NULL; DrawText(aText,param,aCoords,ELeft,CFont::EHorizontal); } /** Draws text clipped to the specified rectangle. @param aText The text string to be drawn @param aBox The clipping rectangle. */ EXPORT_C void CFbsBitGc::DrawText(const TDesC& aText,const TRect& aBox) { TTextParameters* param = NULL; DrawText(aText,param,aBox); } /** Draws text clipped to the specified rectangle using a baseline offset, horizontal alignment and a margin. @param aText The text string to be drawn @param aBox The clipping rectangle. @param aBLOff An offset in pixels for the baseline from the normal position (bottom of the rectangle minus the descent of the font). @param aHrz Horizontal alignment option relative to the specified rectangle. @param aMargin Offset to add to the position as calculated using specified rectangle. */ EXPORT_C void CFbsBitGc::DrawText(const TDesC& aText,const TRect& aBox,TInt aBLOff, TTextAlign aHrz,TInt aMargin) { TTextParameters* param = NULL; DrawText(aText,param,aBox,aBLOff,-1,aHrz,aMargin); } /** Draws text clipped to the specified rectangle. @param aText The text string to be drawn @param aBox The clipping rectangle. */ EXPORT_C void CFbsBitGc::DrawText(const TDesC& aText,const TRect& aBox, TInt aBLOff,TInt /*aTextWidth*/, TTextAlign aHrz,TInt aMargin) { // aTextWidth is not used here - try to abolish this - I think it is unneeded TPoint p(aBox.iTl); p.iY += aBLOff; switch (aHrz) { case ELeft: p.iX += aMargin; break; case ERight: p.iX = aBox.iBr.iX - aMargin; break; case ECenter: p.iX += aBox.Width() / 2 + aMargin; break; } TTextParameters* param = NULL; DrawText(aText,param,p,aHrz,CFont::EHorizontal,&aBox); } /** The general DrawText routine that implements all the others. @param aText the text to be drawn @param aPosition the origin of the text @param aAlignment left, centred or right, around aPosition; not used if drawing vertically @param aDirection direction: left to right, right to left, or top to bottom @param aBox if non-null, filled before the text is drawn @param aTextBounds if non-null returns the bounding box of the text */ void CFbsBitGc::DrawText(const TDesC& aText,const TTextParameters* aParam,const TPoint& aPosition,TTextAlign aAlignment, CFont::TTextDirection aDirection,const TRect* aBox) { // sanity checks BG_ASSERT_ALWAYS(iDevice,EBitgdiPanicNoDevicePresent); BG_ASSERT_ALWAYS(iFont.Handle() != 0,EBitgdiPanicNoFontSelected); const CBitmapFont* bitmap_font = iFont.Address(); BG_ASSERT_ALWAYS(bitmap_font != 0,EBitgdiPanicNoFontSelected); // anything to do? if (!aBox && !aText.Length()) return; CFbsDrawDevice* drawDevice = iDevice->iDrawDevice; TRect deviceRect; drawDevice->GetDrawRect(deviceRect); // measure the text CFont::TMeasureTextInput measure_text_input; measure_text_input.iCharJustNum = iCharJustNum; measure_text_input.iCharJustExcess = iCharJustExcess; measure_text_input.iWordJustNum = iWordJustNum; measure_text_input.iWordJustExcess = iWordJustExcess; measure_text_input.iFlags |= CFont::TMeasureTextInput::EFVisualOrder; if (aParam) { BG_ASSERT_ALWAYS(aParam->iStart < aParam->iEnd ,EBitgdiPanicInvalidParameter); measure_text_input.iStartInputChar = aParam->iStart; measure_text_input.iEndInputChar = Min(aText.Length(),aParam->iEnd); } CFont::TMeasureTextOutput measure_text_output; const int advance = iFont.MeasureText(aText,&measure_text_input,&measure_text_output); TRect text_bounds = measure_text_output.iBounds; TInt underlineStrikeoutOffset; //this call is only needed in the case of linked fonts //should this pass by one structure? underlineStrikeoutOffset= BaselineCorrection(); if (iUnderline == EUnderlineOn) { TInt underline_top = 0, underline_bottom = 0; TInt err = GetUnderlineMetrics(underline_top,underline_bottom); underline_top+=underlineStrikeoutOffset; underline_bottom+=underlineStrikeoutOffset; BG_ASSERT_DEBUG(err == KErrNone, EBitgdiPanicInvalidArg); text_bounds.iTl.iY = Min(text_bounds.iTl.iY,underline_top); text_bounds.iBr.iY = Max(text_bounds.iBr.iY,underline_bottom); } if (iStrikethrough == EStrikethroughOn) { TInt strike_top = 0,strike_bottom = 0; GetStrikethroughMetrics(strike_top,strike_bottom); strike_top+=underlineStrikeoutOffset; strike_bottom+=underlineStrikeoutOffset; text_bounds.iTl.iY = Min(text_bounds.iTl.iY,strike_top); text_bounds.iBr.iY = Max(text_bounds.iBr.iY,strike_bottom); } if (iUnderline == EUnderlineOn || iStrikethrough == EStrikethroughOn) { if (aDirection == CFont::EHorizontal) { text_bounds.iTl.iX = Min(text_bounds.iTl.iX, 0); text_bounds.iBr.iX = Max(text_bounds.iBr.iX, advance); } else { text_bounds.iTl.iY = Min(text_bounds.iTl.iY, 0); text_bounds.iBr.iY = Max(text_bounds.iBr.iY, advance); } } // work out the text origin and new drawing position TPoint text_origin = aPosition; if (aDirection != CFont::EVertical) { const TInt leftSideBearing = Min(text_bounds.iTl.iX, 0); const TInt rightSideBearing = Max(text_bounds.iBr.iX, advance); switch (aAlignment) { // We are forbidding side-bearings to leak over the sides here, // but still keeping the start and end pen positions within bounds. case ELeft: text_origin.iX -= leftSideBearing; break; case ERight: text_origin.iX -= rightSideBearing; break; case ECenter: // Centre is the average of left and right text_origin.iX -= (leftSideBearing + rightSideBearing) >> 1; break; default: break; } } iLastPrintPosition = text_origin; if (aDirection == CFont::EHorizontal) iLastPrintPosition.iX += advance; else iLastPrintPosition.iY += advance; text_origin.iY += bitmap_font->iAlgStyle.iBaselineOffsetInPixels; text_bounds.Move(text_origin); text_origin += iOrigin; // determine clipping rectangle TRect clip_rect = aBox ? *aBox : text_bounds; AddRect(clip_rect); clip_rect.Move(iOrigin); if (UserClipRect(clip_rect)) { if (iAutoUpdateJustification) UpdateJustification(aText,aParam); return; // nothing to do } SetupDevice(); iDevice->DrawingBegin(&iBrushBitmap); CFbsRasterizer* brushRasterizer = PrepareRasterizerForExtendedBitmap(iBrushBitmap); // fill the box if necessary if (aBox) { TRect fill_box = *aBox; fill_box.Move(iOrigin); RectFill(fill_box); } // decide which drawing routine to call const TBool bold = bitmap_font->iAlgStyle.IsBold(); const TBool italic = bitmap_font->iAlgStyle.IsItalic(); const TBool multiw = bitmap_font->iAlgStyle.WidthFactor() > 1; const TBool multih = bitmap_font->iAlgStyle.HeightFactor() > 1; TOpenFontMetrics metrics; iFont.GetFontMetrics(metrics); const TInt maxwidth = metrics.MaxWidth(); // extext will be TRUE, if font is bold/italic/underline/strikethrough/anti-aliased or it // has shadow/outline effects ON. Depending on these properties it will call the proper draw routine. TBool extext = FALSE; TBool normaltext = FALSE; const TBool anti_aliased = (bitmap_font->GlyphBitmapType() == EAntiAliasedGlyphBitmap); const TBool outlineAndShadow = (bitmap_font->GlyphBitmapType() == EFourColourBlendGlyphBitmap); if (anti_aliased || outlineAndShadow) { if ((outlineAndShadow) && !(iBrushStyle == ENullBrush || iBrushStyle == ESolidBrush)) { //For future compatibility it is better if brush style of ENullBrush or ESolidBrush is used //when drawing outline and shadow fonts. BG_PANIC_ALWAYS(EBitgdiPanicInvalidBrushStyle); } extext = TRUE; } else if (maxwidth > 30 || text_bounds.Height() > 32 || multiw || multih) { } else if (iUnderline == EUnderlineOn || bold || italic || iStrikethrough == EStrikethroughOn || iCharJustNum > 0 || iWordJustNum > 0) extext = TRUE; else normaltext = TRUE; const TInt charjustexcess = iCharJustExcess; const TInt charjustnum = iCharJustNum; const TInt wordjustexcess = iWordJustExcess; const TInt wordjustnum = iWordJustNum; // draw the text to all clip rectangles in turn int clip_rects = iDefaultRegionPtr->Count(); for (int i = 0; i < clip_rects; i++) { iClipRect = (*iDefaultRegionPtr)[i]; if (!iClipRect.Intersects(clip_rect)) continue; #ifdef _DEBUG BG_ASSERT_DEBUG(iClipRect.iTl.iX >= deviceRect.iTl.iX, EBitgdiPanicOutOfBounds); BG_ASSERT_DEBUG(iClipRect.iTl.iY >= deviceRect.iTl.iY, EBitgdiPanicOutOfBounds); BG_ASSERT_DEBUG(iClipRect.iBr.iX <= deviceRect.iBr.iX, EBitgdiPanicOutOfBounds); BG_ASSERT_DEBUG(iClipRect.iBr.iY <= deviceRect.iBr.iY, EBitgdiPanicOutOfBounds); #endif iClipRect.Intersection(clip_rect); // Set up the parameter block for character positioning. CFont::TPositionParam param; param.iDirection = static_cast<TInt16>(aDirection); param.iText.Set(aText); TInt endDraw = aText.Length(); if (aParam) { param.iPosInText = aParam->iStart; endDraw = Min(aText.Length(),aParam->iEnd); } else param.iPosInText = 0; param.iPen = text_origin; // Draw the text. if (normaltext) DoDrawText(param,endDraw); else if (extext) DoDrawTextEx(param,bitmap_font,endDraw,underlineStrikeoutOffset); else DoDrawTextLarge(param,bitmap_font,endDraw); /* Reset the justification parameters to their original values. These will be updated as required later in code. */ iCharJustExcess = charjustexcess; iCharJustNum = charjustnum; iWordJustExcess = wordjustexcess; iWordJustNum = wordjustnum; drawDevice->UpdateRegion(iClipRect); } if (brushRasterizer) { brushRasterizer->EndBitmap(iBrushBitmap.SerialNumber()); } iDevice->DrawingEnd(&iBrushBitmap); if (iAutoUpdateJustification) UpdateJustification(aText,aParam); } void CFbsBitGc::DoDrawText(CFont::TPositionParam& aParam, const TInt aEnd) { //const int n = aParam.iText.Length(); RShapeInfo shapeInfo; while (aParam.iPosInText < /*n*/aEnd) { if (iFont.GetCharacterPosition2(aParam, shapeInfo)) { const CFont::TPositionParam::TOutput* output = aParam.iOutput; for (int i = 0; i < aParam.iOutputGlyphs; i++, output++) DoDrawCharacter(output->iBounds.iTl,output->iBitmapSize,output->iBitmap); } } if (shapeInfo.IsOpen()) shapeInfo.Close(); } void CFbsBitGc::DoDrawCharacter(const TPoint& aTopLeft, const TSize& aDataSize, const TUint8* aData) { /* Divert if the character is larger than expected; the criterion for choosing this function is only a heuristic, because it's perfectly legal for a character's bitmap to be wider than its escapement. Use a dummy value (0) for semi-ascent because this character is not italic and so semi-ascent is irrelevant; it's used for pseudo-italic slanting. */ TInt dataheight = aDataSize.iHeight; TInt datalength = aDataSize.iWidth; if (datalength > 30 || dataheight > 32) { DoDrawCharacterExLarge(aTopLeft,aDataSize,aData,FALSE,FALSE,0,1,1); return; } TInt bitindex=0; TInt16 repeatcount=0; TUint32 binarydata[32]; TUint32* binarydataptr=binarydata; TUint32* binarydataptrlimit; for(TInt charline=0;charline<dataheight;charline+=repeatcount) // for lines in the character... { repeatcount=Load16(aData+(bitindex>>3)); repeatcount>>=bitindex&7; TInt multilineflag=repeatcount&1; repeatcount>>=1; repeatcount&=0xf; bitindex+=5; binarydataptrlimit=binarydata+charline+repeatcount; if(multilineflag) { while(binarydataptr<binarydataptrlimit) { TInt chardataoffsetptr=TInt(aData)+(bitindex>>3); TUint32* chardataword=(TUint32*)(chardataoffsetptr&~3); TInt bitshift=bitindex&7; bitshift+=(chardataoffsetptr&3)<<3; *binarydataptr=(*chardataword++)>>bitshift; if(bitshift) *binarydataptr|=(*chardataword<<(32-bitshift)); bitindex+=datalength; binarydataptr++; } } else { TInt chardataoffsetptr=TInt(aData)+(bitindex>>3); TUint32* chardataword=(TUint32*)(chardataoffsetptr&~3); TInt bitshift=bitindex&7; bitshift+=(chardataoffsetptr&3)<<3; TUint32 data=(*chardataword++)>>bitshift; if(bitshift) data|=(*chardataword<<(32-bitshift)); while(binarydataptr<binarydataptrlimit) *binarydataptr++=data; bitindex+=datalength; } } TPoint topleft(aTopLeft); binarydataptr=ClipBinaryArray(binarydata,binarydata+dataheight,1,datalength,dataheight,topleft); if(datalength>0 && dataheight>0) iDevice->iDrawDevice->WriteBinary(topleft.iX,topleft.iY,binarydataptr,datalength,dataheight,iPenColor,iDrawMode); } /** @internalTechnology This function retrieves the baseline offset from the metrics of the text currently being drawn. This is used to alter the positioning of underline and strikethrough on a linked font @return The baseline correction associated with the currently used font. */ TInt CFbsBitGc::BaselineCorrection() { TOpenFontMetrics metrics; if (iFont.GetFontMetrics(metrics)) return metrics.BaselineCorrection(); else return 0; } void CFbsBitGc::DoDrawTextEx(CFont::TPositionParam& aParam,const CBitmapFont* font, const TInt aEnd, const TInt aUnderlineStrikethroughOffset) { const TInt charclipping = iClipRect.iBr.iX; TPoint start_pen = aParam.iPen; const TBool bold = font->iAlgStyle.IsBold(); const TBool italic = font->iAlgStyle.IsItalic(); const TGlyphBitmapType glyphBitmapTypeForFont = font->GlyphBitmapType(); const TBool outlineShadowOrAntialiased = ((glyphBitmapTypeForFont == EAntiAliasedGlyphBitmap) || (glyphBitmapTypeForFont == EFourColourBlendGlyphBitmap)); TInt underline_top = 0, underline_bottom = 0; if (iUnderline == EUnderlineOn) { TInt err = GetUnderlineMetrics(underline_top,underline_bottom); underline_top+=aUnderlineStrikethroughOffset; underline_bottom+=aUnderlineStrikethroughOffset; BG_ASSERT_DEBUG(err == KErrNone, EBitgdiPanicInvalidArg); } TInt strike_top = 0, strike_bottom = 0; if (italic || iStrikethrough == EStrikethroughOn) { GetStrikethroughMetrics(strike_top,strike_bottom); strike_top+=aUnderlineStrikethroughOffset; strike_bottom+=aUnderlineStrikethroughOffset; } CFbsDrawDevice* drawDevice = iDevice->iDrawDevice; RShapeInfo shapeInfo; while (aParam.iPosInText < aEnd) { if (!iFont.GetCharacterPosition2(aParam, shapeInfo)) continue; TInt adjustment = 0; if(iCharJustExcess && iCharJustNum > 0) // character clipping/justification { adjustment = CGraphicsContext::JustificationInPixels(iCharJustExcess,iCharJustNum); if(adjustment < 0) iClipRect.iBr.iX = Min(aParam.iPen.iX + adjustment,iClipRect.iBr.iX); } const CFont::TPositionParam::TOutput* output = aParam.iOutput; int semi_ascent = start_pen.iY + strike_top; for (int i = 0; i < aParam.iOutputGlyphs; i++, output++) { //get the character metrics for the glyph type TOpenFontCharMetrics characterParams; const TUint8* bitmap; TSize size; //note may now be using a glyph code, and not a character iFont.GetCharacterData(aParam.iOutput[i].iCode,characterParams,bitmap,size); TGlyphBitmapType glyphType = characterParams.GlyphType(); switch (glyphType) { case EAntiAliasedGlyphBitmap: case EFourColourBlendGlyphBitmap: DoDrawCharacterAntiAliased(output->iBounds.iTl,output->iBitmapSize,output->iBitmap,glyphType); break; case EDefaultGlyphBitmap: case EMonochromeGlyphBitmap: DoDrawCharacterEx(output->iBounds.iTl,output->iBitmapSize,output->iBitmap,bold,italic,semi_ascent); break; default: //if the outline or shadow is not specified for the character, then use the font setting if (outlineShadowOrAntialiased) { DoDrawCharacterAntiAliased(output->iBounds.iTl,output->iBitmapSize,output->iBitmap,glyphBitmapTypeForFont); } else { DoDrawCharacterEx(output->iBounds.iTl,output->iBitmapSize,output->iBitmap,bold,italic,semi_ascent); } break; } } iClipRect.iBr.iX = charclipping; if (adjustment) aParam.iPen.iX += adjustment; if (iWordJustExcess > 0 && iWordJustNum > 0 && aParam.iOutput[0].iCode == 0x0020) // word justification { adjustment = CGraphicsContext::JustificationInPixels(iWordJustExcess,iWordJustNum); aParam.iPen.iX += adjustment; } } if (shapeInfo.IsOpen()) shapeInfo.Close(); if (iUnderline == EUnderlineOn) { TRect ul(start_pen.iX,start_pen.iY + underline_top,aParam.iPen.iX,start_pen.iY + underline_bottom); if(ul.Intersects(iClipRect)) // checks for empty aRect as well { ul.Intersection(iClipRect); drawDevice->WriteRgbMulti(ul.iTl.iX,ul.iTl.iY,ul.iBr.iX-ul.iTl.iX,ul.iBr.iY-ul.iTl.iY,iPenColor,iDrawMode); } } if (iStrikethrough == EStrikethroughOn) { TRect st(start_pen.iX,start_pen.iY + strike_top,aParam.iPen.iX,start_pen.iY + strike_bottom); if(st.Intersects(iClipRect)) // checks for empty aRect as well { st.Intersection(iClipRect); drawDevice->WriteRgbMulti(st.iTl.iX,st.iTl.iY,st.iBr.iX-st.iTl.iX,st.iBr.iY-st.iTl.iY,iPenColor,iDrawMode); } } } void CFbsBitGc::DoDrawCharacterEx(const TPoint& aTopLeft, const TSize& aDataSize, const TUint8* aData, TBool aBold,TBool aItalic,TInt aSemiAscent) { /* Divert if the character is larger than expected; the criterion for choosing this function is only a heuristic, because it's perfectly legal for a character's bitmap to be wider than its escapement. */ TInt datalength = aDataSize.iWidth; TInt dataheight = aDataSize.iHeight; if (datalength > 30 || dataheight > 32) { DoDrawCharacterExLarge(aTopLeft,aDataSize,aData,aBold,aItalic,aSemiAscent,1,1); return; } TInt bitindex=0; TInt16 repeatcount=0; TUint32 binarydata[32]; TUint32* binarydataptr=binarydata; TUint32* binarydataptrlimit; for(TInt charline=0;charline<dataheight;charline+=repeatcount) // for lines in the character... { repeatcount=Load16(aData+(bitindex>>3)); repeatcount>>=bitindex&7; TInt multilineflag=repeatcount&1; repeatcount>>=1; repeatcount&=0xf; bitindex+=5; binarydataptrlimit=binarydata+charline+repeatcount; if(multilineflag) { while(binarydataptr<binarydataptrlimit) { CopyCharWord(binarydataptr,aData+(bitindex>>3),bitindex&7); bitindex+=datalength; binarydataptr++; } } else { TUint32 data=0; CopyCharWord(&data,aData+(bitindex>>3),bitindex&7); while(binarydataptr<binarydataptrlimit) *binarydataptr++=data; bitindex+=datalength; } } binarydataptr=binarydata; binarydataptrlimit=binarydata+dataheight; if(aBold) { TInt sparemask=(0xffffffff>>(32-datalength)); while(binarydataptr<binarydataptrlimit) { *binarydataptr&=sparemask; *binarydataptr|=(*binarydataptr<<1); ++binarydataptr; } binarydataptr=binarydata; datalength++; } if(aItalic) { TInt skewlevel=aSemiAscent-aTopLeft.iY; TUint32 sparemask=(0xffffffff>>(32-datalength)); binarydataptrlimit=binarydata+skewlevel; while(binarydataptr<binarydataptrlimit) *binarydataptr++<<=1; binarydataptrlimit=binarydata+dataheight; while(binarydataptr<binarydataptrlimit) *binarydataptr++&=sparemask; binarydataptr=binarydata; datalength++; } TPoint topleft(aTopLeft); binarydataptr=ClipBinaryArray(binarydata,binarydata+dataheight,1,datalength,dataheight,topleft); if(datalength>0 && dataheight>0) iDevice->iDrawDevice->WriteBinary(topleft.iX,topleft.iY,binarydataptr,datalength,dataheight,iPenColor,iDrawMode); } /** @internalTechnology This function draws an anti-aliased character. @param aTopLeft The position to output the character @param aDataSize The size of the bitmap @param aData the bitmap for outputt in their TOpenFontCharMetrics @param aGlyphType the glyph type for the character */ void CFbsBitGc::DoDrawCharacterAntiAliased(const TPoint& aTopLeft, const TSize& aDataSize, const TUint8* aData, const TGlyphBitmapType aGlyphType) { const int top_row = Max(0,iClipRect.iTl.iY - aTopLeft.iY); const int bottom_row = Min(aDataSize.iHeight,iClipRect.iBr.iY - aTopLeft.iY); const int left_col = Max(0,iClipRect.iTl.iX - aTopLeft.iX); const int right_col = Min(aDataSize.iWidth,iClipRect.iBr.iX - aTopLeft.iX); const TUint8* p = aData + top_row * aDataSize.iWidth + left_col; const int x = aTopLeft.iX + left_col; int y = aTopLeft.iY + top_row; const int cols = right_col - left_col; const TUint32 penColor = iPenColor.Internal(); const TUint32 shadowColor = iFbsBitGcExtraData->ShadowColor().Internal(); const TUint32 brushColor = iBrushColor.Internal(); if (EFourColourBlendGlyphBitmap == aGlyphType) { MOutlineAndShadowBlend* outlineAndShadow = NULL; const TInt err = iDevice->iDrawDevice->GetInterface(KOutlineAndShadowInterfaceID, reinterpret_cast <TAny*&> (outlineAndShadow)); if(err == KErrNone) { //There is a support for the interface with KOutlineAndShadowInterface id. for (int row = top_row; row < bottom_row; row++, p += aDataSize.iWidth, y++) outlineAndShadow->WriteRgbOutlineAndShadow(x, y, cols, penColor, shadowColor, brushColor, p); } else { // Assert if MOutlineAndShadowBlend interface is not implemented BG_ASSERT_DEBUG(outlineAndShadow, EBitgdiPanicInvalidInterfaceHandle); } } else { for (int row = top_row; row < bottom_row; row++, p += aDataSize.iWidth, y++) iDevice->iDrawDevice->WriteRgbAlphaMulti(x,y,cols,iPenColor,p); } } void CFbsBitGc::DoDrawTextLarge(CFont::TPositionParam& aParam,const CBitmapFont* font,const TInt aEnd) { const TInt charclipping = iClipRect.iBr.iX; TPoint start_pen = aParam.iPen; const TInt strikeheight = start_pen.iY - (font->CBitmapFont::DoAscentInPixels() * 5/12) - 1; const TBool bold = font->iAlgStyle.IsBold(); const TBool italic = font->iAlgStyle.IsItalic(); const TInt widthfactor=font->iAlgStyle.WidthFactor(); const TInt heightfactor=font->iAlgStyle.HeightFactor(); CFbsDrawDevice* drawDevice = iDevice->iDrawDevice; RShapeInfo shapeInfo; while (aParam.iPosInText < aEnd) { if (!iFont.GetCharacterPosition2(aParam, shapeInfo)) continue; TInt adjustment = 0; if(iCharJustExcess && iCharJustNum > 0) // character clipping/justification { adjustment = CGraphicsContext::JustificationInPixels(iCharJustExcess,iCharJustNum); if(adjustment < 0) iClipRect.iBr.iX = Min(aParam.iPen.iX + adjustment,iClipRect.iBr.iX); } const CFont::TPositionParam::TOutput* output = aParam.iOutput; for (int i = 0; i < aParam.iOutputGlyphs; i++, output++) DoDrawCharacterLarge(output->iBounds.iTl,output->iBitmapSize,output->iBitmap,bold,italic,strikeheight, widthfactor,heightfactor); iClipRect.iBr.iX = charclipping; if (adjustment) aParam.iPen.iX += adjustment; if (iWordJustExcess > 0 && iWordJustNum > 0 && aParam.iOutput[0].iCode == 0x0020) // word justification { adjustment = CGraphicsContext::JustificationInPixels(iWordJustExcess,iWordJustNum); aParam.iPen.iX += adjustment; } } if (shapeInfo.IsOpen()) shapeInfo.Close(); const TInt ulwidth = Max(font->CBitmapFont::DoHeightInPixels() / 10, 1); if (iUnderline == EUnderlineOn) { TInt ulstart = start_pen.iY + 1 + ulwidth / 2; TRect ul(start_pen.iX,ulstart,aParam.iPen.iX,ulstart + ulwidth); if(ul.Intersects(iClipRect)) // checks for empty aRect as well { ul.Intersection(iClipRect); drawDevice->WriteRgbMulti(ul.iTl.iX,ul.iTl.iY,ul.iBr.iX-ul.iTl.iX,ul.iBr.iY-ul.iTl.iY,iPenColor,iDrawMode); } } if (iStrikethrough == EStrikethroughOn) { TRect st(start_pen.iX,strikeheight,aParam.iPen.iX,strikeheight + ulwidth); if(st.Intersects(iClipRect)) // checks for empty aRect as well { st.Intersection(iClipRect); drawDevice->WriteRgbMulti(st.iTl.iX,st.iTl.iY,st.iBr.iX-st.iTl.iX,st.iBr.iY-st.iTl.iY,iPenColor,iDrawMode); } } } void CFbsBitGc::DoDrawCharacterLarge(const TPoint& aTopLeft,const TSize& aDataSize,const TUint8* aData, TBool aBold,TBool aItalic,TInt aSemiAscent,TInt aWidthFactor,TInt aHeightFactor) { TInt datalength = aDataSize.iWidth; TInt dataheight = aDataSize.iHeight; if (aWidthFactor > 2 || aHeightFactor > 2) { DoDrawCharacterMultiplied(aTopLeft,aDataSize,aData,aBold,aItalic,aSemiAscent,aWidthFactor,aHeightFactor); return; } if (datalength > 30 || dataheight > 32 || (aWidthFactor == 2 && datalength > 14)) { DoDrawCharacterExLarge(aTopLeft,aDataSize,aData,aBold,aItalic,aSemiAscent,aWidthFactor,aHeightFactor); return; } TInt italicheight=aSemiAscent-aTopLeft.iY; if(aHeightFactor==2) italicheight>>=1; TInt bitindex=0; TInt16 repeatcount=0; TUint32 binarydata[64]; TUint32* binarydataptr=binarydata; TUint32* binarydataptrlimit; for(TInt charline=0;charline<dataheight;charline+=repeatcount) // for lines in the character... { repeatcount=Load16(aData+(bitindex>>3)); repeatcount>>=bitindex&7; TInt multilineflag=repeatcount&1; repeatcount>>=1; repeatcount&=0xf; bitindex+=5; binarydataptrlimit=binarydata+charline+repeatcount; if(multilineflag) { while(binarydataptr<binarydataptrlimit) { CopyCharWord(binarydataptr,aData+(bitindex>>3),bitindex&7); bitindex+=datalength; binarydataptr++; } } else { TUint32 data=0; CopyCharWord(&data,aData+(bitindex>>3),bitindex&7); while(binarydataptr<binarydataptrlimit) *binarydataptr++=data; bitindex+=datalength; } } binarydataptr=binarydata; binarydataptrlimit=binarydata+dataheight; if(aBold) { TInt sparemask=(0xffffffff>>(32-datalength)); while(binarydataptr<binarydataptrlimit) { *binarydataptr&=sparemask; *binarydataptr|=(*binarydataptr<<1); ++binarydataptr; } binarydataptr=binarydata; datalength++; } if(aItalic) { TUint32 sparemask=(0xffffffff>>(32-datalength)); binarydataptrlimit=Min(binarydataptrlimit,binarydata+italicheight); while(binarydataptr<binarydataptrlimit) { *binarydataptr<<=1; *binarydataptr++&=0xfffffffe; } binarydataptrlimit=binarydata+dataheight; while(binarydataptr<binarydataptrlimit) *binarydataptr++&=sparemask; binarydataptr=binarydata; datalength++; } if(aWidthFactor==2) { BG_ASSERT_DEBUG(datalength<=16,EBitgdiPanicCharacterTooBig); while(binarydataptr<binarydataptrlimit) { TUint32 singlemask=0x8000; TUint32 doublemask=0xc0000000; TUint32 newdata=0; while(singlemask) { if(*binarydataptr&singlemask) newdata|=doublemask; singlemask>>=1; doublemask>>=2; } *binarydataptr++=newdata; } datalength<<=1; binarydataptr=binarydata; } if(aHeightFactor==2) { binarydataptr=binarydata+dataheight-1; TUint32* tempptr=binarydataptr+dataheight; while(binarydataptr>=binarydata) { *tempptr--=*binarydataptr; *tempptr--=*binarydataptr--; } dataheight<<=1; binarydataptr=binarydata; } TPoint startpos=aTopLeft; binarydataptr=ClipBinaryArray(binarydata,binarydata+dataheight,1,datalength,dataheight,startpos); if(datalength>0 && dataheight>0) iDevice->iDrawDevice->WriteBinary(startpos.iX,startpos.iY,binarydataptr,datalength,dataheight,iPenColor,iDrawMode); } void CFbsBitGc::DoDrawCharacterExLarge(const TPoint& aTopLeft,const TSize& aDataSize,const TUint8* aData, TBool aBold,TBool aItalic,TInt aSemiAscent,TInt aWidthFactor,TInt aHeightFactor) { CFbsDrawDevice* drawDevice = iDevice->iDrawDevice; TPoint printpos(aTopLeft); const TInt datalength = aDataSize.iWidth; const TInt dataheight = aDataSize.iHeight; TInt bitindex=0; TInt16 repeatcount=0; TUint32* slbuffer=drawDevice->ScanLineBuffer(); const TInt slwords=(drawDevice->ScanLineBytes())<<3; if(aItalic && aTopLeft.iY<aSemiAscent) printpos.iX++; for(TInt charline=0;charline<dataheight;charline+=repeatcount) // for lines in the character... { repeatcount=Load16(aData+(bitindex>>3)); repeatcount>>=bitindex&7; const TInt multilineflag=repeatcount&1; repeatcount>>=1; repeatcount&=0xf; bitindex+=5; if(multilineflag) { for(TInt currentline=0;currentline<repeatcount;currentline++) { CopyCharLine(slbuffer,slwords,aData+(bitindex>>3),bitindex&7,datalength); OutputCharLineMultiplied(printpos,slbuffer,datalength,1,aBold,aWidthFactor,aHeightFactor); bitindex+=datalength; printpos.iY++; if(printpos.iY==aSemiAscent && aItalic) printpos.iX--; if(aHeightFactor==2) { printpos.iY++; if(printpos.iY==aSemiAscent && aItalic) printpos.iX--; } } } else { if(aItalic) { for(TInt currentline=0;currentline<repeatcount;currentline++) { CopyCharLine(slbuffer,slwords,aData+(bitindex>>3),bitindex&7,datalength); OutputCharLineMultiplied(printpos,slbuffer,datalength,1,aBold,aWidthFactor,aHeightFactor); printpos.iY++; if(printpos.iY==aSemiAscent && aItalic) printpos.iX--; if(aHeightFactor==2) { printpos.iY++; if(printpos.iY==aSemiAscent && aItalic) printpos.iX--; } } } else { CopyCharLine(slbuffer,slwords,aData+(bitindex>>3),bitindex&7,datalength); OutputCharLineMultiplied(printpos,slbuffer,datalength,repeatcount,aBold,aWidthFactor,aHeightFactor); printpos.iY+=repeatcount; if(aHeightFactor==2) printpos.iY+=repeatcount; } bitindex+=datalength; } } } void CFbsBitGc::DoDrawCharacterMultiplied(const TPoint& aTopLeft,const TSize& aDataSize,const TUint8* aData, TBool aBold,TBool aItalic,TInt aSemiAscent,TInt aWidthFactor,TInt aHeightFactor) { CFbsDrawDevice* drawDevice = iDevice->iDrawDevice; TPoint printpos(aTopLeft); const TInt datalength = aDataSize.iWidth; const TInt dataheight = aDataSize.iHeight; TInt bitindex=0; TInt16 repeatcount=0; TUint32* slbuffer=drawDevice->ScanLineBuffer(); const TInt slwords=(drawDevice->ScanLineBytes())<<3; if(aItalic && aTopLeft.iY<aSemiAscent) printpos.iX++; for(TInt charline=0;charline<dataheight;charline+=repeatcount) // for lines in the character... { repeatcount=Load16(aData+(bitindex>>3)); repeatcount>>=bitindex&7; const TInt multilineflag=repeatcount&1; repeatcount>>=1; repeatcount&=0xf; bitindex+=5; if(multilineflag) { for(TInt currentline=0;currentline<repeatcount;currentline++) { CopyCharLine(slbuffer,slwords,aData+(bitindex>>3),bitindex&7,datalength); OutputCharLineMultiplied(printpos,slbuffer,datalength,1,aBold,aWidthFactor,aHeightFactor); bitindex+=datalength; TBool aboveitalicjump=EFalse; if(aItalic && printpos.iY<aSemiAscent) aboveitalicjump=ETrue; printpos.iY+=aHeightFactor; if(aboveitalicjump && printpos.iY>=aSemiAscent) printpos.iX-=aWidthFactor; } } else { if(aItalic) { for(TInt currentline=0;currentline<repeatcount;currentline++) { CopyCharLine(slbuffer,slwords,aData+(bitindex>>3),bitindex&7,datalength); OutputCharLineMultiplied(printpos,slbuffer,datalength,1,aBold,aWidthFactor,aHeightFactor); TBool aboveitalicjump=EFalse; if(printpos.iY<aSemiAscent) aboveitalicjump=ETrue; printpos.iY+=aHeightFactor; if(aboveitalicjump && printpos.iY>=aSemiAscent) printpos.iX-=aWidthFactor; } } else { CopyCharLine(slbuffer,slwords,aData+(bitindex>>3),bitindex&7,datalength); OutputCharLineMultiplied(printpos,slbuffer,datalength,repeatcount,aBold,aWidthFactor,aHeightFactor); printpos.iY+=repeatcount*aHeightFactor; } bitindex+=datalength; } } } void CFbsBitGc::OutputCharLineMultiplied(TPoint aPrintPos,TUint32* aBuffer,TInt aDataLength,TInt aNum,TBool aBold,TInt aWidthFactor,TInt aHeightFactor) { if(aDataLength<=0) return; TInt bufferwords=(aDataLength+31)>>5; TUint32* bufferlimit=aBuffer+bufferwords; if(aBold) { TInt sparemask=(0xffffffff>>(32-(aDataLength&0x1f))); if((aDataLength&0x1f)==0) sparemask=0xffffffff; *(bufferlimit-1)&=sparemask; TUint32* bufferptr=aBuffer; TUint32 extrabit=0; while(bufferptr<bufferlimit) { extrabit=*bufferptr>>31; *bufferptr|=(*bufferptr<<1); ++bufferptr; if(bufferptr<bufferlimit) *bufferptr|=extrabit; } aDataLength++; if((aDataLength&0x1f)==1) { bufferwords++; *bufferlimit=extrabit; bufferlimit++; } } if(aWidthFactor>1) { BitMultiply(aBuffer,aDataLength,aWidthFactor); aDataLength*=aWidthFactor; bufferwords=(aDataLength+31)>>5; bufferlimit=aBuffer+bufferwords; } if(aPrintPos.iX<iClipRect.iTl.iX) { TInt pixelexcess=iClipRect.iTl.iX-aPrintPos.iX; while(pixelexcess>=32) { aBuffer++; bufferwords--; aDataLength-=32; pixelexcess-=32; } if(aDataLength<=0) return; if(pixelexcess>0) { TInt shiftup=32-pixelexcess; TUint32* bufferptr=aBuffer; while(bufferptr<bufferlimit) { *bufferptr>>=pixelexcess; if(bufferptr<bufferlimit-1) *bufferptr|=(*(bufferptr+1)<<shiftup); bufferptr++; } aDataLength-=pixelexcess; if(aDataLength<=0) return; } aPrintPos.iX=iClipRect.iTl.iX; } if(aPrintPos.iX+aDataLength>iClipRect.iBr.iX) { TInt pixelexcess=aPrintPos.iX+aDataLength-iClipRect.iBr.iX; aDataLength-=pixelexcess; if(aDataLength<=0) return; } aNum*=aHeightFactor; while(aNum>0) { if(aPrintPos.iY>=iClipRect.iTl.iY && aPrintPos.iY<iClipRect.iBr.iY) iDevice->iDrawDevice->WriteBinaryLine(aPrintPos.iX,aPrintPos.iY,aBuffer,aDataLength,iPenColor,iDrawMode); aPrintPos.iY++; aNum--; } } void CFbsBitGc::CopyCharWord(TUint32* aBinaryDataPtr,const TUint8* aData,TInt aBitShift) { const TUint32* dataword=(TUint32*)(TInt(aData)&~3); aBitShift+=(TInt(aData)-TInt(dataword))<<3; *aBinaryDataPtr=*dataword++; if(aBitShift<32) *aBinaryDataPtr>>=aBitShift; if(aBitShift) *aBinaryDataPtr|=(*dataword<<(32-aBitShift)); } void CFbsBitGc::CopyCharLine(TUint32* aBinaryDataPtr,TInt aBufferWords,const TUint8* aData,TInt aBitShift,TInt aCharWidth) { aBitShift&=7; TInt wordstocopy=(aCharWidth+31)>>5; if(wordstocopy>aBufferWords) wordstocopy=aBufferWords; TUint32* ptrlimit=aBinaryDataPtr+wordstocopy; TUint32* dataword=(TUint32*)(TInt(aData)&~3); aBitShift+=(TInt(aData)-TInt(dataword))<<3; while(aBinaryDataPtr<ptrlimit) { *aBinaryDataPtr=*dataword++; *aBinaryDataPtr>>=aBitShift; if(aBitShift) *aBinaryDataPtr|=(*dataword<<(32-aBitShift)); aBinaryDataPtr++; } } TUint32* CFbsBitGc::ClipBinaryArray(TUint32* aArray,TUint32* aArrayLimit,TInt aArrayWordWd,TInt& aDataWd,TInt& aDataHt,TPoint& aPos) { TUint32* arrayptr=aArray; TInt clipdiff=iClipRect.iTl.iX-aPos.iX; if(aArrayWordWd==1) { if(clipdiff>0) { while(arrayptr<aArrayLimit) *arrayptr++>>=clipdiff; aDataWd-=clipdiff; aPos.iX=iClipRect.iTl.iX; arrayptr=aArray; } if(aPos.iX+aDataWd>iClipRect.iBr.iX && aDataWd>0) aDataWd=iClipRect.iBr.iX-aPos.iX; clipdiff=iClipRect.iTl.iY-aPos.iY; if(clipdiff>0) { aDataHt-=clipdiff; arrayptr+=clipdiff; aPos.iY=iClipRect.iTl.iY; } if(aPos.iY+aDataHt>iClipRect.iBr.iY && aDataHt>0) aDataHt=iClipRect.iBr.iY-aPos.iY; } return(arrayptr); } void CFbsBitGc::BitMultiply(TUint32* aBinaryDataPtr,TInt aBitLength,TInt aFactor) { TInt bitpos=aBitLength-1; TUint32* wordpos=aBinaryDataPtr+(bitpos>>5); TInt bitoffset=bitpos&0x1f; TInt multbitpos=(aBitLength*aFactor)-1; TUint32* multwordpos=aBinaryDataPtr+(multbitpos>>5); TInt multbitoffset=multbitpos&0x1f; while(bitpos>=0) { TUint32 bit=((*wordpos)>>bitoffset)&1; TInt next=multbitpos-aFactor; while(multbitpos>next) { if(bit) *multwordpos|=(1<<multbitoffset); else *multwordpos&=~(1<<multbitoffset); multbitpos--; multbitoffset--; if(multbitoffset<0) { multbitoffset=31; multwordpos--; } } bitpos--; bitoffset--; if(bitoffset<0) { bitoffset=31; wordpos--; } } } void CFbsBitGc::GetStrikethroughMetrics(TInt& aTop,TInt& aBottom) /** Get the top and bottom of a strikethrough line for the current font, relative to the baseline.*/ { aTop = -(iFont.AscentInPixels() * 5/12) - 1; aBottom = aTop + Max(iFont.HeightInPixels() / 10,1); } /** APIExtension can contain as many additional methods as is required by CGraphicsContext after its original conception. It takes 3 parameters. Function is exported due to constrains of retaining BC with earlier versions. This is not used directly by external methods, instead it is called by a named method in CGraphicsContext which passes the relivant arguements including an unique identifier for the required action. @param aUid The unique identifier for the method that is required. Selected internally by a series of "if" statements. @see Valid Uid identifiers are listed in header gdi.h @see CGraphicsContext @param aOutput is a TAny pointer to a reference. Used to output data as the structure does not need to be instantiated before the function call this adds greater flexibility. @param aInput is a TAny pointer used to input data. */ EXPORT_C TInt CFbsBitGc::APIExtension(TUid aUid, TAny*& aOutput, TAny* aInput) { if (aUid == KGetUnderlineMetrics) { APIExGetUnderlineMetrics(aOutput); return KErrNone; } else if (aUid == KSetShadowColor) { return APIExSetShadowColor(aInput); } else if (aUid == KGetShadowColor) { return APIExGetShadowColor(aOutput); } else if (aUid == KDrawTextInContextUid) { TDrawTextInContextInternal* contextParam = (TDrawTextInContextInternal*)aInput; DrawText(contextParam->iText, &contextParam->iParam, contextParam->iPosition); return KErrNone; } else if (aUid == KDrawBoxTextInContextUid) { TDrawTextInContextInternal* contextParam = (TDrawTextInContextInternal*)aInput; DrawText(contextParam->iText,&contextParam->iParam,contextParam->iBox,contextParam->iBaselineOffset,contextParam->iAlign,contextParam->iMargin); return KErrNone; } else if (aUid == KDrawTextInContextVerticalUid) { TDrawTextInContextInternal* contextParam = (TDrawTextInContextInternal*)aInput; DrawTextVertical(contextParam->iText, &contextParam->iParam, contextParam->iPosition,contextParam->iUp); return KErrNone; } else if (aUid == KDrawBoxTextInContextVerticalUid) { TDrawTextInContextInternal* contextParam = (TDrawTextInContextInternal*)aInput; DrawTextVertical(contextParam->iText,&contextParam->iParam,contextParam->iBox,contextParam->iBaselineOffset,contextParam->iUp,contextParam->iAlign,contextParam->iMargin); return KErrNone; } else if (aUid == KUidIsFbsBitmapGc) { return APIExIsFbsBitGc(aOutput); } /* Future cases may be placed here later.*/ else return CBitmapContext::APIExtension(aUid, aOutput, aInput); } //The methods listed above in APIExtension follow here with the prefix APIEx. void CFbsBitGc::APIExGetUnderlineMetrics(TAny*& aOutput) { const TInt width = Max(iFont.HeightInPixels() / 10,1); TTwoTInt* ptr = (TTwoTInt*)aOutput; ptr->iTop = 1 + width / 2; ptr->iBottom = (ptr->iTop) + width; } TInt CFbsBitGc::APIExSetShadowColor(TAny* aShadowColor) { iFbsBitGcExtraData->SetShadowColor(*(reinterpret_cast<TRgb*>(aShadowColor))); return KErrNone; } TInt CFbsBitGc::APIExGetShadowColor(TAny*& aShadowColor) { TRgb* output = reinterpret_cast<TRgb*>(aShadowColor); *output = iFbsBitGcExtraData->ShadowColor(); return KErrNone; } TInt CFbsBitGc::APIExIsFbsBitGc(TAny*& aIsCFbsBitGc) { TBool *output = reinterpret_cast<TBool*>(aIsCFbsBitGc); *output = ETrue; return KErrNone; } EXPORT_C void CFbsBitGc::DrawText(const TDesC& aText,const TTextParameters* aParam) { DrawText(aText,aParam,iLastPrintPosition,ELeft,CFont::EHorizontal); } EXPORT_C void CFbsBitGc::DrawText(const TDesC& aText,const TTextParameters* aParam,const TPoint& aPosition) { DrawText(aText,aParam,aPosition,ELeft,CFont::EHorizontal); } EXPORT_C void CFbsBitGc::DrawText(const TDesC& aText,const TTextParameters* aParam,const TRect& aBox) { TRect boxcpy(aBox); boxcpy.Move(iOrigin); if(!iUserClipRect.Intersects(boxcpy)) return; TRect oldcliprect(iUserClipRect); iUserClipRect.Intersection(boxcpy); DrawText(aText,aParam); iUserClipRect=oldcliprect; } EXPORT_C void CFbsBitGc::DrawText(const TDesC& aText,const TTextParameters* aParam,const TRect& aBox,TInt aBaselineOffset,TTextAlign aHrz,TInt aMargin) { DrawText(aText,aParam,aBox,aBaselineOffset,-1,aHrz,aMargin); } EXPORT_C void CFbsBitGc::DrawText(const TDesC& aText,const TTextParameters* aParam,const TRect& aBox,TInt aBaselineOffset,TInt /*aTextWidth*/,TTextAlign aHrz,TInt aMargin) { // aTextWidth is not used here - try to abolish this - I think it is unneeded TPoint p(aBox.iTl); p.iY += aBaselineOffset; switch (aHrz) { case ELeft: p.iX += aMargin; break; case ERight: p.iX = aBox.iBr.iX - aMargin; break; case ECenter: p.iX += aBox.Width() / 2 + aMargin; break; } DrawText(aText,aParam,p,aHrz,CFont::EHorizontal,&aBox); }