diff --git a/gfx/src/Makefile.in b/gfx/src/Makefile.in index 41799212ee41..85f38bc7f05a 100644 --- a/gfx/src/Makefile.in +++ b/gfx/src/Makefile.in @@ -94,13 +94,18 @@ CPPSRCS = \ nsNameValuePairDB.cpp \ nsRenderingContextImpl.cpp \ nsRect.cpp \ - nsTransform2D.cpp \ nsScriptableRegion.cpp \ nsGraphicsImpl.cpp \ nsPrintOptionsImpl.cpp \ nsPrintSettingsImpl.cpp \ $(NULL) +ifeq ($(OS_ARCH),OS2) +CPPSRCS += nsTransform2DOS2.cpp +else +CPPSRCS += nsTransform2D.cpp +endif + ifeq (,$(filter windows,$(MOZ_WIDGET_TOOLKIT))) CPPSRCS += nsCompressedCharMap.cpp endif diff --git a/gfx/src/nsTransform2DOS2.cpp b/gfx/src/nsTransform2DOS2.cpp new file mode 100644 index 000000000000..4ced8ea05ce1 --- /dev/null +++ b/gfx/src/nsTransform2DOS2.cpp @@ -0,0 +1,671 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: NPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Netscape Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * http://www.mozilla.org/NPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is mozilla.org code. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 1998 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the NPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the NPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + + +#include "nsTransform2D.h" + +// These functions need to be separate so that the compiler doesn't +// optimize them away. +void _ToFloat( float* pf, double d ) +{ + *pf = d; +} + +float ToFloat( double x ) +{ + float temp; + _ToFloat( &temp, x ); + return temp; +} + +void nsTransform2D :: SetToScale(float sx, float sy) +{ + m01 = m10 = m20 = m21 = 0.0f; + m00 = sx; + m11 = sy; + type = MG_2DSCALE; +} + +void nsTransform2D :: SetToTranslate(float tx, float ty) +{ + m01 = m10 = 0.0f; + m00 = m11 = 1.0f; + m20 = tx; + m21 = ty; + type = MG_2DTRANSLATION; +} + +void nsTransform2D :: SetMatrix(nsTransform2D *aTransform2D) +{ + m00 = aTransform2D->m00; + m01 = aTransform2D->m01; + m10 = aTransform2D->m10; + m11 = aTransform2D->m11; + m20 = aTransform2D->m20; + m21 = aTransform2D->m21; + type = aTransform2D->type; +} + +void nsTransform2D :: Concatenate(nsTransform2D *newxform) +{ + float temp00, temp01, temp10, temp11; + float new00, new01, new10, new11, new20, new21; + PRUint16 newtype = newxform->type; + + if (type == MG_2DIDENTITY) + { + //current matrix is identity + + if (newtype != MG_2DIDENTITY) + SetMatrix(newxform); + + return; + } + else if (newtype == MG_2DIDENTITY) + return; + else if ((type & MG_2DSCALE) != 0) + { + //current matrix is at least scale + + if ((newtype & (MG_2DGENERAL | MG_2DSCALE)) != 0) + { + //new matrix is general or scale + + if ((newtype & MG_2DTRANSLATION) != 0) + { + m20 += ToFloat( newxform->m20 * m00 ); + m21 += ToFloat( newxform->m21 * m11 ); + } + + m00 *= newxform->m00; + m11 *= newxform->m11; + } + else + { + //new matrix must be translation only + + m20 += ToFloat( newxform->m20 * m00 ); + m21 += ToFloat( newxform->m21 * m11 ); + } + } + else if ((type & MG_2DGENERAL) != 0) + { + //current matrix is at least general + + if ((newtype & MG_2DGENERAL) != 0) + { + //new matrix is general - worst case + + temp00 = m00; + temp01 = m01; + temp10 = m10; + temp11 = m11; + + new00 = newxform->m00; + new01 = newxform->m01; + new10 = newxform->m10; + new11 = newxform->m11; + + if ((newtype & MG_2DTRANSLATION) != 0) + { + new20 = newxform->m20; + new21 = newxform->m21; + + m20 += ToFloat( new20 * temp00 ) + ToFloat( new21 * temp10 ); + m21 += ToFloat( new20 * temp01 ) + ToFloat( new21 * temp11 ); + } + + m00 = ToFloat( new00 * temp00 ) + ToFloat( new01 * temp10 ); + m01 = ToFloat( new00 * temp01 ) + ToFloat( new01 * temp11 ); + m10 = ToFloat( new10 * temp00 ) + ToFloat( new11 * temp10 ); + m11 = ToFloat( new10 * temp01 ) + ToFloat( new11 * temp11 ); + } + else if ((newtype & MG_2DSCALE) != 0) + { + //new matrix is at least scale + + temp00 = m00; + temp01 = m01; + temp10 = m10; + temp11 = m11; + + new00 = newxform->m00; + new11 = newxform->m11; + + if ((newtype & MG_2DTRANSLATION) != 0) + { + new20 = newxform->m20; + new21 = newxform->m21; + + m20 += ToFloat( new20 * temp00 ) + ToFloat( new21 * temp10 ); + m21 += ToFloat( new20 * temp01 ) + ToFloat( new21 * temp11 ); + } + + m00 = new00 * temp00; + m01 = new00 * temp01; + m10 = new11 * temp10; + m11 = new11 * temp11; + } + else + { + //new matrix must be translation only + + new20 = newxform->m20; + new21 = newxform->m21; + + m20 += ToFloat( new20 * m00 ) + ToFloat( new21 * m10 ); + m21 += ToFloat( new20 * m01 ) + ToFloat( new21 * m11 ); + } + } + else + { + //current matrix is translation only + + if ((newtype & (MG_2DGENERAL | MG_2DSCALE)) != 0) + { + //new matrix is general or scale + + if ((newtype & MG_2DTRANSLATION) != 0) + { + m20 += newxform->m20; + m21 += newxform->m21; + } + + m00 = newxform->m00; + m11 = newxform->m11; + } + else + { + //new matrix must be translation only + + m20 += newxform->m20; + m21 += newxform->m21; + } + } + +/* temp00 = m00; + temp01 = m01; + temp10 = m10; + temp11 = m11; + temp20 = m20; + temp21 = m21; + + new00 = newxform.m00; + new01 = newxform.m01; + new10 = newxform.m10; + new11 = newxform.m11; + new20 = newxform.m20; + new21 = newxform.m21; + + m00 = new00 * temp00 + new01 * temp10; // + new02 * temp20 == 0 + m01 = new00 * temp01 + new01 * temp11; // + new02 * temp21 == 0 +// m02 += new00 * temp02 + new01 * temp12; // + new02 * temp22 == 0 + m10 = new10 * temp00 + new11 * temp10; // + new12 * temp20 == 0 + m11 = new10 * temp01 + new11 * temp11; // + new12 * temp21 == 0 +// m12 += new10 * temp02 + new11 * temp12; // + new12 * temp22 == 0 + m20 = new20 * temp00 + new21 * temp10 + temp20; // + new22 * temp20 == temp20 + m21 = new20 * temp01 + new21 * temp11 + temp21; // + new22 * temp21 == temp21 +// m22 += new20 * temp02 + new21 * temp12; // + new22 * temp22 == 1 +*/ + type |= newtype; +} + +void nsTransform2D :: PreConcatenate(nsTransform2D *newxform) +{ + float temp00, temp01, temp10, temp11, temp20, temp21; + float new00, new01, new10, new11; + + //this is totally unoptimized MMP + + temp00 = m00; + temp01 = m01; + temp10 = m10; + temp11 = m11; + temp20 = m20; + temp21 = m21; + + new00 = newxform->m00; + new01 = newxform->m01; + new10 = newxform->m10; + new11 = newxform->m11; + + m00 = ToFloat( temp00 * new00 ) + ToFloat( temp01 * new10 ); // + temp02 * new20 == 0 + m01 = ToFloat( temp00 * new01 ) + ToFloat( temp01 * new11 ); // + temp02 * new21 == 0 +// m02 += temp00 * new02 + temp01 * new12; // + temp02 * new22 == 0 + m10 = ToFloat( temp10 * new00 ) + ToFloat( temp11 * new10 ); // + temp12 * new20 == 0 + m11 = ToFloat( temp10 * new01 ) + ToFloat( temp11 * new11 ); // + temp12 * new21 == 0 +// m12 += temp10 * new02 + temp11 * new12; // + temp12 * new22 == 0 + m20 = ToFloat( temp20 * new00 ) + ToFloat( temp21 * temp10 ) + temp20; // + temp22 * new20 == new20 + m21 = ToFloat( temp20 * new01 ) + ToFloat( temp21 * new11 ) + temp21; // + temp22 * new21 == new21 +// m22 += temp20 * new02 + temp21 * new12; // + temp22 * new22 == 1 + + type |= newxform->type; +} + +void nsTransform2D :: TransformNoXLate(float *ptX, float *ptY) +{ + float x, y; + + switch (type) + { + case MG_2DIDENTITY: + break; + + case MG_2DSCALE: + *ptX *= m00; + *ptY *= m11; + break; + + default: + case MG_2DGENERAL: + x = *ptX; + y = *ptY; + + *ptX = x * m00 + y * m10; + *ptY = x * m01 + y * m11; + + break; + } +} + +void nsTransform2D :: TransformNoXLateCoord(nscoord *ptX, nscoord *ptY) +{ + float x, y; + + switch (type) + { + case MG_2DIDENTITY: + break; + + case MG_2DSCALE: + *ptX = NSToCoordRound(*ptX * m00); + *ptY = NSToCoordRound(*ptY * m11); + break; + + default: + case MG_2DGENERAL: + x = (float)*ptX; + y = (float)*ptY; + + *ptX = NSToCoordRound(x * m00 + y * m10); + *ptY = NSToCoordRound(x * m01 + y * m11); + + break; + } +} + +inline PRIntn NSToIntNFloor(float aValue) +{ + return ((0.0f <= aValue) ? PRIntn(aValue) : PRIntn(aValue - CEIL_CONST_FLOAT)); +} + +void nsTransform2D :: ScaleXCoords(const nscoord* aSrc, + PRUint32 aNumCoords, + PRIntn* aDst) +{ +const nscoord* end = aSrc + aNumCoords; + + if (type == MG_2DIDENTITY){ + while (aSrc < end ) { + *aDst++ = PRIntn(*aSrc++); + } + } else { + float scale = m00; + while (aSrc < end) { + nscoord c = *aSrc++; + *aDst++ = NSToIntNFloor(c * scale); + } + } +} + +void nsTransform2D :: ScaleYCoords(const nscoord* aSrc, + PRUint32 aNumCoords, + PRIntn* aDst) +{ +const nscoord* end = aSrc + aNumCoords; + + if (type == MG_2DIDENTITY){ + while (aSrc < end ) { + *aDst++ = PRIntn(*aSrc++); + } + } else { + float scale = m11; + while (aSrc < end) { + nscoord c = *aSrc++; + *aDst++ = NSToIntNFloor(c * scale); + } + } +} + + +void nsTransform2D :: Transform(float *ptX, float *ptY) +{ + float x, y; + + switch (type) + { + case MG_2DIDENTITY: + break; + + case MG_2DTRANSLATION: + *ptX += m20; + *ptY += m21; + break; + + case MG_2DSCALE: + *ptX *= m00; + *ptY *= m11; + break; + + case MG_2DGENERAL: + x = *ptX; + y = *ptY; + + *ptX = x * m00 + y * m10; + *ptY = x * m01 + y * m11; + + break; + + case MG_2DSCALE | MG_2DTRANSLATION: + *ptX = *ptX * m00 + m20; + *ptY = *ptY * m11 + m21; + break; + + default: + case MG_2DGENERAL | MG_2DTRANSLATION: + x = *ptX; + y = *ptY; + + *ptX = x * m00 + y * m10 + m20; + *ptY = x * m01 + y * m11 + m21; + + break; + } +} + +void nsTransform2D :: TransformCoord(nscoord *ptX, nscoord *ptY) +{ + float x, y; + + switch (type) + { + case MG_2DIDENTITY: + break; + + case MG_2DTRANSLATION: + *ptX += NSToCoordRound(m20); + *ptY += NSToCoordRound(m21); + break; + + case MG_2DSCALE: + *ptX = NSToCoordRound(*ptX * m00); + *ptY = NSToCoordRound(*ptY * m11); + break; + + case MG_2DGENERAL: + x = (float)*ptX; + y = (float)*ptY; + + *ptX = NSToCoordRound(x * m00 + y * m10); + *ptY = NSToCoordRound(x * m01 + y * m11); + + break; + + case MG_2DSCALE | MG_2DTRANSLATION: + // You can not use a translation that is not rounded to calculate a + // final destination and get consistent results. The translation is rounded + // seperatly only for the final coordinate location. Its ok + // to keep the tranlation in floating for the matrix.. just don't use it + // pre-rounded for coordinate locations. Its not valid to translate 1.333 pixels for example + // on output since .33 pixel is not a valid output unit and can cause inconsistencies. (dcone) + *ptX = NSToCoordRound(*ptX * m00) + NSToCoordRound(m20); + *ptY = NSToCoordRound(*ptY * m11) + NSToCoordRound(m21); + break; + + default: + case MG_2DGENERAL | MG_2DTRANSLATION: + x = (float)*ptX; + y = (float)*ptY; + + *ptX = NSToCoordRound(x * m00 + y * m10 + m20); + *ptY = NSToCoordRound(x * m01 + y * m11 + m21); + + break; + } +} + +void nsTransform2D :: Transform(float *aX, float *aY, float *aWidth, float *aHeight) +{ + float x, y; + + switch (type) + { + case MG_2DIDENTITY: + break; + + case MG_2DTRANSLATION: + *aX += m20; + *aY += m21; + break; + + case MG_2DSCALE: + *aX *= m00; + *aY *= m11; + *aWidth *= m00; + *aHeight *= m11; + break; + + case MG_2DGENERAL: + x = *aX; + y = *aY; + + *aX = x * m00 + y * m10; + *aY = x * m01 + y * m11; + + x = *aWidth; + y = *aHeight; + + *aWidth = x * m00 + y * m10; + *aHeight = x * m01 + y * m11; + + break; + + case MG_2DSCALE | MG_2DTRANSLATION: + *aX = *aX * m00 + m20; + *aY = *aY * m11 + m21; + *aWidth *= m00; + *aHeight *= m11; + break; + + default: + case MG_2DGENERAL | MG_2DTRANSLATION: + x = *aX; + y = *aY; + + *aX = x * m00 + y * m10 + m20; + *aY = x * m01 + y * m11 + m21; + + x = *aWidth; + y = *aHeight; + + *aWidth = x * m00 + y * m10; + *aHeight = x * m01 + y * m11; + + break; + } +} + +void nsTransform2D :: TransformCoord(nscoord *aX, nscoord *aY, nscoord *aWidth, nscoord *aHeight) +{ + float x, y; + float ex,ey; + + switch (type) + { + case MG_2DIDENTITY: + break; + + case MG_2DTRANSLATION: + *aX += NSToCoordRound(m20); + *aY += NSToCoordRound(m21); + break; + + case MG_2DSCALE: + *aX = NSToCoordRound(*aX * m00); + *aY = NSToCoordRound(*aY * m11); + *aWidth = NSToCoordRound(*aWidth * m00); + *aHeight = NSToCoordRound(*aHeight * m11); + break; + + case MG_2DGENERAL: + x = (float)*aX; + y = (float)*aY; + + *aX = NSToCoordRound(x * m00 + y * m10); + *aY = NSToCoordRound(x * m01 + y * m11); + + x = (float)*aWidth; + y = (float)*aHeight; + + *aWidth = NSToCoordRound(x * m00 + y * m10); + *aHeight = NSToCoordRound(x * m01 + y * m11); + + break; + + case MG_2DSCALE | MG_2DTRANSLATION: + // first transform the X and Y locations + x = *aX * m00 + NSToCoordRound(m20); + y = *aY * m11 + NSToCoordRound(m21); + *aX = NSToCoordRound(x); + *aY = NSToCoordRound(y); + + // the starting locations have a direct effect on the width and height if and only if + // the width and height are used to calculate positions relative to these locations. + // The layout engine does count on the width and height to be so many units away, so an + // error can be introduced if you round and then add a rounded width. To compensate, this error + // should be added to the width or height before rounding. If the width or height is used as a + // measurment, or distance, then use the direct floating point number. This width and height + // has an error adjustment for the starting locations inorder to calculate the ending positions. + // The error is the fractional difference between the transformed point and the next pixel + + // calculate the error + ex = x - float(NSToCoordRound(x)); + ey = y - float(NSToCoordRound(y)); + + // now you can transform with the error added in + *aWidth = NSToCoordRound(*aWidth * m00 + ex); + *aHeight = NSToCoordRound(*aHeight * m11 + ey); + break; + + default: + case MG_2DGENERAL | MG_2DTRANSLATION: + x = (float)*aX; + y = (float)*aY; + + x = x * m00 + y * m10 + m20; + y = x * m01 + y * m11 + m21; + ex = x - float(NSToCoordRound(x)); + ey = y - float(NSToCoordRound(y)); + *aX = NSToCoordRound(x); + *aY = NSToCoordRound(y); + + x = (float)*aWidth; + y = (float)*aHeight; + + *aWidth = NSToCoordRound((x * m00 + y * m10)+ex); + *aHeight = NSToCoordRound((x * m01 + y * m11)+ey); + break; + } +} + +void nsTransform2D :: AddTranslation(float ptX, float ptY) +{ + if (type == MG_2DIDENTITY) + { + m20 = ptX; + m21 = ptY; + } + else if ((type & MG_2DSCALE) != 0) + { + //current matrix is at least scale + + m20 += ToFloat( ptX * m00 ); + m21 += ToFloat( ptY * m11 ); + } + else if ((type & MG_2DGENERAL) != 0) + { + //current matrix is at least general + + m20 += ToFloat( ptX * m00 ) + ToFloat( ptY * m10 ); + m21 += ToFloat( ptX * m01 ) + ToFloat( ptY * m11 ); + } + else + { + m20 += ptX; + m21 += ptY; + } + + type |= MG_2DTRANSLATION; +} + +void nsTransform2D :: AddScale(float ptX, float ptY) +{ + if ((type == MG_2DIDENTITY) || (type == MG_2DTRANSLATION)) + { + m00 = ptX; + m11 = ptY; + } + else if ((type & MG_2DSCALE) != 0) + { + //current matrix is at least scale + + m00 *= ptX; + m11 *= ptY; + } + else if ((type & MG_2DGENERAL) != 0) + { + //current matrix is at least general + + m00 *= ptX; + m01 *= ptX; + m10 *= ptY; + m11 *= ptY; + } + + type |= MG_2DSCALE; +}