os/graphics/graphicsdeviceinterface/screendriver/sbit/BmDrawScaling.cpp
author sl
Tue, 10 Jun 2014 14:32:02 +0200
changeset 1 260cb5ec6c19
permissions -rw-r--r--
Update contrib.
     1 // Copyright (c) 2006-2009 Nokia Corporation and/or its subsidiary(-ies).
     2 // All rights reserved.
     3 // This component and the accompanying materials are made available
     4 // under the terms of "Eclipse Public License v1.0"
     5 // which accompanies this distribution, and is available
     6 // at the URL "http://www.eclipse.org/legal/epl-v10.html".
     7 //
     8 // Initial Contributors:
     9 // Nokia Corporation - initial contribution.
    10 //
    11 // Contributors:
    12 //
    13 // Description:
    14 //
    15 
    16 #include "BMDRAW.H"
    17 #include "BitDrawInterfaceId.h"
    18 
    19 //The method prepares RGB value writting, calculating physical aX, aY, aWidth and aHeight.
    20 //The calculated coordinates are used by methods wich do not use methods in BmDraw8Scaling.cpp
    21 //file - WriteRgbMultiXOR(), WriteRgbMultiAND(), WriteRgbMultiOR(). 
    22 //If the scaling is "off" then it is very simple - draw physical pixels. But if the scaling is 
    23 //"on" then a rectanngle is being drawn instead of a pixel. And rectangle coordinates are 
    24 //calculated depending on the device' orientation.
    25 //aX, aY - logical coordinates.
    26 //aWidth, aHeight - output parameters, they will be initialized in the method's body,
    27 //if aDrawMode is not CGraphicsContext::EPenmode. If aDrawMode is CGraphicsContext::EPenmode,
    28 //then aWidth will be set with iScalingSettings.iFactorX and aheight - with 
    29 //iScalingSettings.iFactorY.
    30 void CDrawBitmap::PreWriteRgb(TInt& aWidth, 
    31 							  TInt& aHeight, 
    32 							  TInt& aX, 
    33 							  TInt& aY, 
    34 							  CGraphicsContext::TDrawMode aDrawMode)
    35 	{
    36 	DeOrientate(aX, aY);//aX and aY - physical coordinates
    37 
    38 	__ASSERT_DEBUG(aX >= 0 && aX < iSize.iWidth,Panic(EScreenDriverPanicOutOfBounds));
    39 	__ASSERT_DEBUG(aY >= 0 && aY < iSize.iHeight,Panic(EScreenDriverPanicOutOfBounds));
    40 
    41 	//If scaling is ON, instead of drawing single point, rectangle with size [FactorX, FactorY]
    42 	//is drawn. Rectangle's width and height might be swapped, depending on the orientation.
    43 	aWidth = iScalingSettings.iFactorX;
    44 	aHeight = iScalingSettings.iFactorY;
    45 
    46 	if(iScalingOff)
    47 		{
    48 		return;
    49 		}
    50 
    51 	//Do this additional deorientation only for not EPenmode modes and when scaling is ON!
    52 	//EPenmode uses WriteRgb(aX,aY,aColor), which does not need any changes in 
    53 	//coordinates!
    54 	if(!(aDrawMode & CGraphicsContext::EPenmode))
    55 		{
    56 		//aX, aY - physical coordinates
    57 		//aWidth, aWidth - output parameters
    58 		//When scaling is ON, instead of drawing single point, rectangle is drawn 
    59 		//and top-left coordinates, width and height has to be calculated.
    60 		register TInt scalingFactorX = aWidth;
    61 		register TInt scalingFactorY = aHeight;
    62 		__ASSERT_DEBUG(scalingFactorX > 0, User::Invariant());
    63 		__ASSERT_DEBUG(scalingFactorY > 0, User::Invariant());
    64 		register CFbsDrawDevice::TOrientation orientation = iOrientation;
    65 
    66 	switch(orientation)
    67 		{
    68 		case  EOrientationRotated90:
    69 		case  EOrientationRotated270:
    70 			{
    71 			if(orientation == EOrientationRotated90)
    72 					{
    73 					aX -= (scalingFactorX - 1);
    74 					}
    75 			if(orientation == EOrientationRotated270)
    76 					{
    77 					aY -= (scalingFactorY - 1);
    78 					}
    79 			break;
    80 			}	
    81 		case EOrientationRotated180 :
    82 			{
    83 			aX -= (scalingFactorX - 1);
    84 			aY -= (scalingFactorY - 1);
    85 			break;
    86 			}
    87 		default:
    88 			break;
    89 		}
    90 		//If the calculated coordinates are negative, set them to 0.
    91 		if(aX < 0)
    92 			{
    93 			aX = 0;
    94 			}
    95 		if(aY < 0)
    96 			{
    97 			aY = 0;
    98 			}
    99 		}
   100 	}
   101 
   102 //Writes RGB value at the specified physical screen coordinates.
   103 //When scaling is ON - rectangle [aWidth, aHeight] is drawn instead of single point.
   104 //Depending on the orientation aWidth and aHeight might be swapped.
   105 //aX, aY - physical coordinates
   106 //aWidth, aHeight - physical
   107 void CDrawBitmap::WriteRgb(TInt& aWidth, TInt& aHeight, 
   108 						   TInt& aX, TInt& aY, TRgb aColor, 
   109 						   CGraphicsContext::TDrawMode aDrawMode)
   110 	{
   111 	MapColorToUserDisplayMode(aColor);
   112 	if(iShadowMode) 
   113 		{
   114 		Shadow(aColor);
   115 		}
   116 	if(aDrawMode&CGraphicsContext::EInvertPen)
   117 		{
   118 		aColor=~aColor;
   119 		}
   120 	if(aDrawMode&CGraphicsContext::EPenmode)
   121 		{
   122 		WriteRgb(aX,aY,aColor);
   123 		return;
   124 		}
   125 	__ASSERT_DEBUG(aWidth > 0, User::Invariant());
   126 	__ASSERT_DEBUG(aHeight > 0, User::Invariant());
   127 	if(aDrawMode&CGraphicsContext::EWriteAlpha)
   128 		{
   129 		// WriteRgbMulti is the only available api that writes alpha
   130 		WriteRgbMulti(aX,aY,aWidth,aHeight,aColor);
   131 		return;
   132 		}
   133 	if(aDrawMode&CGraphicsContext::EInvertScreen)
   134 		{
   135 		WriteRgbMultiXOR(aX, aY, aWidth, aHeight, KRgbWhite);
   136 		}
   137 	if(aDrawMode&CGraphicsContext::EXor)
   138 		{
   139 		WriteRgbMultiXOR(aX, aY, aWidth, aHeight, aColor);
   140 		}
   141 	else if(aDrawMode&CGraphicsContext::EAnd)
   142 		{
   143 		WriteRgbMultiAND(aX, aY, aWidth, aHeight, aColor);
   144 		}
   145 	else if(aDrawMode&CGraphicsContext::EOr)
   146 		{
   147 		WriteRgbMultiOR(aX, aY, aWidth, aHeight, aColor);
   148 		}
   149 	}
   150 
   151 /**
   152 Implementation for CFbsDrawDevice::GetDrawRect().
   153 Gets logical coordinates of the drawing rectangle.
   154 If the device is not scaled and with zero origin, logocal coordinates of 
   155 the drawing rectangle are the same as its physical coordinates.
   156 If the device is rotated, drawing rectangle width and height are swapped.
   157 Always prefer GetDrawRect() to SizeInPixels() call. SizeInPixels() will return
   158 drawing rectangle width and height. But if the device is scaled or with nonzero origin,
   159 GetDrawRect() will take into account and the top-left corner of the drawing rectangle too,
   160 which may not be [0, 0].
   161 @param aRect Upon return aRect contains drawing rectangle logical coordinates.
   162 */
   163 void CDrawBitmap::GetDrawRect(TRect& aDrawRect) const
   164 	{
   165 	aDrawRect = iDrawRect;
   166 	if (iOrientation & 1)
   167 		{//90 or 270 degrees
   168 		if (iOrigin.iX!=iOrigin.iY || iScalingSettings.iFactorX!=iScalingSettings.iFactorY)
   169 			{		//When the scales are different between the dimensions the origin needs to recalculating
   170 			aDrawRect.iTl.iX=Origin(iOrigin.iX,iScalingSettings.iFactorY);
   171 			aDrawRect.iTl.iY=Origin(iOrigin.iY,iScalingSettings.iFactorX);
   172 			}
   173 		aDrawRect.SetWidth(iDrawRect.Height());
   174 		aDrawRect.SetHeight(iDrawRect.Width());
   175 		}
   176 	}
   177 
   178 /**
   179 Implementation for MScalingSettings::Set().
   180 Sets scaling factor by which the drawing device should scale the drawing images.
   181 If you want to un-scale the device, call Set() with 
   182 factorX = 1, factorY = 1, divisorX = 1, divisorY = 1.
   183 @param aFactorX Scaling factor for the X-axis of the screen device.
   184 @param aFactorY Scaling factor for the y-axis of the screen device.
   185 @param aDivisorX Not used. Should be set to 1.
   186 @param aDivisorY Not used. Should be set to 1.
   187 @return KErrNone success.
   188 */
   189 TInt CDrawBitmap::Set(TInt aFactorX, TInt aFactorY, TInt aDivisorX, TInt aDivisorY)
   190 	{
   191 	__ASSERT_DEBUG(aDivisorX == 1 && aDivisorY == 1, User::Invariant());
   192 	__ASSERT_DEBUG(aFactorX > 0 && aFactorY > 0, User::Invariant());
   193 
   194 	iScalingSettings.iFactorX = aFactorX;
   195 	iScalingSettings.iFactorY = aFactorY;
   196 	iScalingSettings.iDivisorX = aDivisorX;
   197 	iScalingSettings.iDivisorY = aDivisorY;
   198 
   199 	iScalingOff = aFactorX == 1 && aFactorY == 1 && aDivisorX == 1 && aDivisorY == 1;
   200 
   201 	InitLogicalCoordinates();
   202 
   203 	return KErrNone;
   204 	}
   205 
   206 /**
   207 Implementation for MScalingSettings::Get().
   208 Retrieves X-axis and Y-axis scaling factors.
   209 @param aFactorX Upon return contains X-axis scaling factor.
   210 @param aFactorY Upon return contains Y-axis scaling factor.
   211 @param aDivisorX Upon return contains the decimal fraction of X-axis scaling factor.
   212 @param aDivisorY Upon return contains the decimal fraction of Y-axis scaling factor.
   213 */
   214 void CDrawBitmap::Get(TInt& aFactorX, TInt& aFactorY, TInt& aDivisorX, TInt& aDivisorY)
   215 	{
   216 	aFactorX = iScalingSettings.iFactorX;
   217 	aFactorY = iScalingSettings.iFactorY;
   218 	aDivisorX = iScalingSettings.iDivisorX;
   219 	aDivisorY = iScalingSettings.iDivisorY;
   220 	}
   221 
   222 /**
   223 Implementation for MScalingSettings::IsScalingOff().
   224 Notifies the caller whether the drawing device is scaled or not.
   225 @return ETrue Drawing device is not scaled, EFalse - it is scaled.
   226 */
   227 TBool CDrawBitmap::IsScalingOff()
   228 	{
   229 	return iScalingOff;
   230 	}
   231 
   232 /**
   233 Implementation for MDrawDeviceOrigin::Set().
   234 Sets drawing device origin.
   235 If you want to the default origin, call Set() with Origin (0,0).
   236 @param aOrigin Specifies physical coordinates of the new scaling origin
   237 of the drawing device. The drawing device maps the logical point [0,0] to
   238 the "aOrigin" physical point .
   239 @return KErrNone success.
   240 */
   241 TInt CDrawBitmap::Set(const TPoint& aOrigin)
   242 	{
   243 	__ASSERT_DEBUG(aOrigin.iX >= 0 && aOrigin.iY >= 0, User::Invariant());
   244 	__ASSERT_DEBUG(aOrigin.iX < iSize.iWidth && aOrigin.iY < iSize.iHeight, User::Invariant());
   245 
   246 	iOrigin = aOrigin;
   247 
   248 	iOriginIsZero = iOrigin.iX == 0 && iOrigin.iY == 0;
   249 
   250 	InitLogicalCoordinates();
   251 
   252 	return KErrNone;
   253 	}
   254 
   255 /**
   256 Implementation for MDrawDeviceOrigin::Get().
   257 Retrieves origin point.
   258 @param aOrigin Upon return contains scaling origin point.
   259 */
   260 void CDrawBitmap::Get(TPoint& aOrigin)
   261 	{
   262 	aOrigin = iOrigin;
   263 	}
   264 
   265 //Initializes iDrawRect data member, which contains logical coordinates of
   266 //the drawing(screen) rectangle.
   267 //The method does not use iOrientation data member.
   268 void CDrawBitmap::InitLogicalCoordinates()
   269 	{
   270 	register TInt orgX = iOrigin.iX;
   271 	register TInt orgY = iOrigin.iY;
   272 	register TInt fX = iScalingSettings.iFactorX;
   273 	register TInt fY = iScalingSettings.iFactorY;
   274 
   275 	iDrawRect.iTl.iX = Origin(orgX, fX);
   276 	iDrawRect.iTl.iY = Origin(orgY, fY);
   277 	iDrawRect.iBr.iX = OtherSide(orgX, iSize.iWidth, fX);
   278 	iDrawRect.iBr.iY = OtherSide(orgY, iSize.iHeight, fY);
   279 	if (orgX!=orgY)
   280 		{		//The number of addressable pixels in the physical dimensions
   281 				//Sometimes needs to be one less when rotationed by 90 or 270
   282 				//If so set it one less all the time as the value is not recalculated
   283 		if (fX>1)
   284 			{	//Calculated the physical left and right of screen when rotation by 90 or 270
   285 				//Use this width if it is smaller
   286 			TInt left = Origin(orgY, fX);
   287 			TInt right = OtherSide(orgY, iSize.iWidth, fX);
   288 			iDrawRect.iBr.iX = Min(iDrawRect.iBr.iX, iDrawRect.iTl.iX+(right-left));
   289 			}
   290 		if (fY>1)
   291 			{	//Calculated the physical top and bottom of screen when rotation by 90 or 270
   292 				//Use this height if it is smaller
   293 			TInt top = Origin(orgX, fY);
   294 			TInt bottom = OtherSide(orgX, iSize.iHeight, fY);
   295 			iDrawRect.iBr.iY = Min(iDrawRect.iBr.iY, iDrawRect.iTl.iY+(bottom-top));
   296 			}
   297 		}
   298 	}
   299 
   300 /**
   301 Notifies the caller whether the drawing device can be scaled or not.
   302 @return ETrue Drawing device can be scaled, EFalse - it can't be scaled.
   303 */
   304 TBool CDrawBitmap::CanBeScaled() const
   305 	{
   306 	//The function will return true for all display modes 
   307 	return ETrue;
   308 	}
   309 
   310 /**
   311 Notifies the caller whether the drawing device origin can be moved from (0, 0) point or not.
   312 @return ETrue Drawing device origin can be moved, EFalse - it can't be moved.
   313 */
   314 TBool CDrawBitmap::CanOriginBeMoved() const
   315 	{
   316 	//The function will return true for all display modes 
   317 	return ETrue;
   318 	}
   319 
   320 //This method calculates pixel increment value and row increment value depending
   321 //on the orientation. The device might be scaled. The result is returned in
   322 //aPixelInc and aRowInc parameters.
   323 void CDrawBitmap::SetPixelInc(TInt& aPixelInc, TInt& aRowInc) const
   324 	{
   325 	register TInt scalingFactorX = iScalingSettings.iFactorX;
   326 	register TInt scalingFactorY = iScalingSettings.iFactorY;
   327 	switch(iOrientation)
   328 		{
   329 		case EOrientationNormal:
   330 			{
   331 			aPixelInc = scalingFactorX;
   332 			aRowInc = iLongWidth * scalingFactorY;
   333 			break;
   334 			}
   335 		case EOrientationRotated90:
   336 			{
   337 			aPixelInc = iLongWidth * scalingFactorY;
   338 			aRowInc = -scalingFactorX;
   339 			break;
   340 			}
   341 		case EOrientationRotated180:
   342 			{
   343 			aPixelInc = -scalingFactorX;
   344 			aRowInc = -iLongWidth * scalingFactorY;
   345 			break;
   346 			}
   347 		default: // EOrientationRotated270
   348 			{
   349 			aPixelInc = -iLongWidth * scalingFactorY;
   350 			aRowInc = scalingFactorX;
   351 			break;
   352 			}	
   353 		}
   354 	}
   355 
   356 //Calculates "Y" increment value and assigns it to aY parameter.
   357 //The device might be scaled and rotated.
   358 //It is used by WriteBinary(), WriteBinaryOp(), ... methods and only there.
   359 //The method is very specific for the methods mentioned above - 
   360 //if the device is scaled and rotated 0 or 180 degrees, Y-axis coordinate has to 
   361 //be incremented not by 1, but by iScalingSettings.iFactorY. Because of the integer divison 
   362 //when transforming logical to physical coordinates, incremented Y-axis coordinates may 
   363 //go negative or greater than drawing rectangle height. Then it has to be adjusted to 0 
   364 //or rectangle height.
   365 void CDrawBitmap::IncScaledY(TInt& aY, TInt aYOrg) const
   366 	{
   367 	const TOrientation orientation = iOrientation;
   368 	const TInt fY = iScalingSettings.iFactorY;
   369 	switch(orientation)
   370 		{
   371 		case EOrientationNormal:
   372 			{
   373 			aY += fY;
   374 			const TInt height = iSize.iHeight - 1;
   375 			if(aY > height)
   376 				{
   377 				aY = height;
   378 				}
   379 			break;
   380 			}
   381 		case EOrientationRotated180:
   382 			{
   383 			aY -= fY;
   384 			if(aY < 0)
   385 				{
   386 				aY = 0;
   387 				}
   388 			break;
   389 			}
   390 		default:
   391 			{
   392 			aY = aYOrg;
   393 			}	
   394 		}
   395 	}
   396 
   397 //Calculates "Y" increment value and assigns it to aY parameter.
   398 //The device might be scaled and rotated.
   399 //It is used by WriteBinary(), WriteBinaryOp(), WriteLine...() methods and only there.
   400 //The method is very specific for the methods mentioned above - 
   401 //if the device is scaled and rotated 90 or 270 degrees, Y-axis coordinate has to 
   402 //be incremented not by 1, but by iScalingSettings.iFactorX. Because of the integer divison 
   403 //when transforming logical to physical coordinates, incremented Y-axis coordinates may 
   404 //go negative or greater than drawing rectangle height. Then it has to be adjusted to 0 
   405 //or rectangle height.
   406 void CDrawBitmap::IncScaledY(TInt& aY) const
   407 	{
   408 	const TOrientation orientation = iOrientation;
   409 	const TInt fX = iScalingSettings.iFactorY;
   410 	if(orientation == EOrientationRotated90)
   411 		{
   412 		aY += fX;
   413 		const TInt height = iSize.iHeight - 1;
   414 		if(aY > height)
   415 			{
   416 			aY = height;
   417 			}
   418 		}
   419 	else if(orientation == EOrientationRotated270)
   420 		{
   421 		aY -= fX;
   422 		if(aY < 0)
   423 			{
   424 			aY = 0;
   425 			}
   426 		}
   427 	}
   428 
   429 //Increment without scaling
   430 TInt CDrawBitmap::PixelAddressIncrement() const
   431 	{
   432 	switch (iOrientation)
   433 		{
   434 	case EOrientationNormal:
   435 		return 1;
   436 	case EOrientationRotated90:
   437 		return iLongWidth;
   438 	case EOrientationRotated180:
   439 		return -1;
   440 	case EOrientationRotated270:
   441 		return -iLongWidth;
   442 	default:
   443 		break;
   444 		}
   445 	return KInvalidValue;
   446 	}
   447 
   448 //Pixel increment with scaling.
   449 //It is used by CDrawEightBppBitmapCommon::SetPixels,
   450 //CDrawEightBppBitmapCommon::XORPixels, CDrawEightBppBitmapCommon::ANDPixels,
   451 //CDrawEightBppBitmapCommon::ORPixels methods
   452 TInt CDrawBitmap::LogicalPixelAddressIncrement() const
   453 	{
   454 	register TInt scalingFactorX = iScalingSettings.iFactorX;
   455 	register TInt scalingFactorY = iScalingSettings.iFactorY;
   456 	switch (iOrientation)
   457 		{
   458 	case EOrientationNormal:
   459 		return scalingFactorX;
   460 	case EOrientationRotated90:
   461 		return iLongWidth * scalingFactorY;
   462 	case EOrientationRotated180:
   463 		return -scalingFactorX;
   464 	case EOrientationRotated270:
   465 		return -iLongWidth * scalingFactorY;
   466 	default:
   467 		break;
   468 		}
   469 	return KInvalidValue;
   470 	}
   471 
   472 inline TInt CDrawBitmap::Origin(TInt aPhysOrg, TInt aScale) const
   473 	{
   474 	return -(aPhysOrg/aScale + (aPhysOrg%aScale ? 1:0));
   475 	}
   476 
   477 inline TInt CDrawBitmap::OtherSide(TInt aPhysOrg, TInt aPhysSize, TInt aScale) const
   478 	{
   479 	return (aPhysSize-1-aPhysOrg) / aScale + 1;
   480 	}