Back to index

lightning-sunbird  0.9+nobinonly
nsTransform2D.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
00002 /* ***** BEGIN LICENSE BLOCK *****
00003  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00004  *
00005  * The contents of this file are subject to the Mozilla Public License Version
00006  * 1.1 (the "License"); you may not use this file except in compliance with
00007  * the License. You may obtain a copy of the License at
00008  * http://www.mozilla.org/MPL/
00009  *
00010  * Software distributed under the License is distributed on an "AS IS" basis,
00011  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00012  * for the specific language governing rights and limitations under the
00013  * License.
00014  *
00015  * The Original Code is mozilla.org code.
00016  *
00017  * The Initial Developer of the Original Code is
00018  * Netscape Communications Corporation.
00019  * Portions created by the Initial Developer are Copyright (C) 1998
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *
00024  * Alternatively, the contents of this file may be used under the terms of
00025  * either of the GNU General Public License Version 2 or later (the "GPL"),
00026  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00027  * in which case the provisions of the GPL or the LGPL are applicable instead
00028  * of those above. If you wish to allow use of your version of this file only
00029  * under the terms of either the GPL or the LGPL, and not to allow others to
00030  * use your version of this file under the terms of the MPL, indicate your
00031  * decision by deleting the provisions above and replace them with the notice
00032  * and other provisions required by the GPL or the LGPL. If you do not delete
00033  * the provisions above, a recipient may use your version of this file under
00034  * the terms of any one of the MPL, the GPL or the LGPL.
00035  *
00036  * ***** END LICENSE BLOCK ***** */
00037 
00038 
00039 #include "nsTransform2D.h"
00040 
00041 void nsTransform2D :: SetToScale(float sx, float sy)
00042 {
00043   m01 = m10 = m20 = m21 = 0.0f;
00044   m00 = sx;
00045   m11 = sy;
00046   type = MG_2DSCALE;
00047 }
00048 
00049 void nsTransform2D :: SetToTranslate(float tx, float ty)
00050 {
00051   m01 = m10 = 0.0f;
00052   m00 = m11 = 1.0f;
00053   m20 = tx;
00054   m21 = ty;
00055   type = MG_2DTRANSLATION;
00056 }
00057 
00058 void nsTransform2D :: SetMatrix(nsTransform2D *aTransform2D)
00059 {
00060   m00 = aTransform2D->m00;
00061   m01 = aTransform2D->m01;
00062   m10 = aTransform2D->m10;
00063   m11 = aTransform2D->m11;
00064   m20 = aTransform2D->m20;
00065   m21 = aTransform2D->m21;
00066   type = aTransform2D->type;
00067 }
00068 
00069 void nsTransform2D :: Concatenate(nsTransform2D *newxform)
00070 {
00071   float     temp00, temp01, temp10, temp11;
00072   float     new00, new01, new10, new11, new20, new21;
00073   PRUint16  newtype = newxform->type;
00074 
00075   if (type == MG_2DIDENTITY)
00076   {
00077     //current matrix is identity
00078 
00079     if (newtype != MG_2DIDENTITY)
00080       SetMatrix(newxform);
00081 
00082     return;
00083   }
00084   else if (newtype == MG_2DIDENTITY)
00085     return;
00086   else if ((type & MG_2DSCALE) != 0)
00087   {
00088     //current matrix is at least scale
00089 
00090     if ((newtype & (MG_2DGENERAL | MG_2DSCALE)) != 0)
00091     {
00092       //new matrix is general or scale
00093 
00094       if ((newtype & MG_2DTRANSLATION) != 0)
00095       {
00096         m20 += newxform->m20 * m00;
00097         m21 += newxform->m21 * m11;
00098       }
00099 
00100       m00 *= newxform->m00;
00101       m11 *= newxform->m11;
00102     }
00103     else
00104     {
00105       //new matrix must be translation only
00106 
00107       m20 += newxform->m20 * m00;
00108       m21 += newxform->m21 * m11;
00109     }
00110   }
00111   else if ((type & MG_2DGENERAL) != 0)
00112   {
00113     //current matrix is at least general
00114 
00115     if ((newtype & MG_2DGENERAL) != 0)
00116     {
00117       //new matrix is general - worst case
00118 
00119       temp00 = m00;
00120       temp01 = m01;
00121       temp10 = m10;
00122       temp11 = m11;
00123 
00124       new00 = newxform->m00;
00125       new01 = newxform->m01;
00126       new10 = newxform->m10;
00127       new11 = newxform->m11;
00128 
00129       if ((newtype & MG_2DTRANSLATION) != 0)
00130       {
00131         new20 = newxform->m20;
00132         new21 = newxform->m21;
00133 
00134         m20 += new20 * temp00 + new21 * temp10;
00135         m21 += new20 * temp01 + new21 * temp11;
00136       }
00137 
00138       m00 = new00 * temp00 + new01 * temp10;
00139       m01 = new00 * temp01 + new01 * temp11;
00140       m10 = new10 * temp00 + new11 * temp10;
00141       m11 = new10 * temp01 + new11 * temp11;
00142     }
00143     else if ((newtype & MG_2DSCALE) != 0)
00144     {
00145       //new matrix is at least scale
00146 
00147       temp00 = m00;
00148       temp01 = m01;
00149       temp10 = m10;
00150       temp11 = m11;
00151 
00152       new00 = newxform->m00;
00153       new11 = newxform->m11;
00154 
00155       if ((newtype & MG_2DTRANSLATION) != 0)
00156       {
00157         new20 = newxform->m20;
00158         new21 = newxform->m21;
00159 
00160         m20 += new20 * temp00 + new21 * temp10;
00161         m21 += new20 * temp01 + new21 * temp11;
00162       }
00163 
00164       m00 = new00 * temp00;
00165       m01 = new00 * temp01;
00166       m10 = new11 * temp10;
00167       m11 = new11 * temp11;
00168     }
00169     else
00170     {
00171         //new matrix must be translation only
00172 
00173         new20 = newxform->m20;
00174         new21 = newxform->m21;
00175 
00176         m20 += new20 * m00 + new21 * m10;
00177         m21 += new20 * m01 + new21 * m11;
00178     }
00179   }
00180   else
00181   {
00182     //current matrix is translation only
00183 
00184     if ((newtype & (MG_2DGENERAL | MG_2DSCALE)) != 0)
00185     {
00186       //new matrix is general or scale
00187 
00188       if ((newtype & MG_2DTRANSLATION) != 0)
00189       {
00190         m20 += newxform->m20;
00191         m21 += newxform->m21;
00192       }
00193 
00194       m00 = newxform->m00;
00195       m11 = newxform->m11;
00196     }
00197     else
00198     {
00199         //new matrix must be translation only
00200 
00201         m20 += newxform->m20;
00202         m21 += newxform->m21;
00203     }
00204   }
00205 
00206 /*    temp00 = m00;
00207   temp01 = m01;
00208   temp10 = m10;
00209   temp11 = m11;
00210   temp20 = m20;
00211   temp21 = m21;
00212 
00213   new00 = newxform.m00;
00214   new01 = newxform.m01;
00215   new10 = newxform.m10;
00216   new11 = newxform.m11;
00217   new20 = newxform.m20;
00218   new21 = newxform.m21;
00219 
00220   m00 = new00 * temp00 + new01 * temp10; // + new02 * temp20 == 0
00221   m01 = new00 * temp01 + new01 * temp11; // + new02 * temp21 == 0
00222 //    m02 += new00 * temp02 + new01 * temp12; // + new02 * temp22 == 0
00223   m10 = new10 * temp00 + new11 * temp10; // + new12 * temp20 == 0
00224   m11 = new10 * temp01 + new11 * temp11; // + new12 * temp21 == 0
00225 //    m12 += new10 * temp02 + new11 * temp12; // + new12 * temp22 == 0
00226   m20 = new20 * temp00 + new21 * temp10 + temp20; // + new22 * temp20 == temp20
00227   m21 = new20 * temp01 + new21 * temp11 + temp21; // + new22 * temp21 == temp21
00228 //    m22 += new20 * temp02 + new21 * temp12; // + new22 * temp22 == 1
00229 */
00230   type |= newtype;
00231 }
00232 
00233 void nsTransform2D :: PreConcatenate(nsTransform2D *newxform)
00234 {
00235   float temp00, temp01, temp10, temp11, temp20, temp21;
00236   float new00, new01, new10, new11;
00237 
00238   //this is totally unoptimized MMP
00239 
00240   temp00 = m00;
00241   temp01 = m01;
00242   temp10 = m10;
00243   temp11 = m11;
00244   temp20 = m20;
00245   temp21 = m21;
00246 
00247   new00 = newxform->m00;
00248   new01 = newxform->m01;
00249   new10 = newxform->m10;
00250   new11 = newxform->m11;
00251 
00252   m00 = temp00 * new00 + temp01 * new10; // + temp02 * new20 == 0
00253   m01 = temp00 * new01 + temp01 * new11; // + temp02 * new21 == 0
00254 //    m02 += temp00 * new02 + temp01 * new12; // + temp02 * new22 == 0
00255   m10 = temp10 * new00 + temp11 * new10; // + temp12 * new20 == 0
00256   m11 = temp10 * new01 + temp11 * new11; // + temp12 * new21 == 0
00257 //    m12 += temp10 * new02 + temp11 * new12; // + temp12 * new22 == 0
00258   m20 = temp20 * new00 + temp21 * temp10 + temp20; // + temp22 * new20 == new20
00259   m21 = temp20 * new01 + temp21 * new11 + temp21; // + temp22 * new21 == new21
00260 //    m22 += temp20 * new02 + temp21 * new12; // + temp22 * new22 == 1
00261 
00262   type |= newxform->type;
00263 }
00264 
00265 void nsTransform2D :: TransformNoXLate(float *ptX, float *ptY)
00266 {
00267   float x, y;
00268 
00269   switch (type)
00270   {
00271     case MG_2DIDENTITY:
00272       break;
00273 
00274     case MG_2DSCALE:
00275       *ptX *= m00;
00276       *ptY *= m11;
00277       break;
00278 
00279     default:
00280     case MG_2DGENERAL:
00281       x = *ptX;
00282       y = *ptY;
00283 
00284       *ptX = x * m00 + y * m10;
00285       *ptY = x * m01 + y * m11;
00286 
00287       break;
00288   }
00289 }
00290 
00291 void nsTransform2D :: TransformNoXLateCoord(nscoord *ptX, nscoord *ptY)
00292 {
00293   float x, y;
00294 
00295   switch (type)
00296   {
00297     case MG_2DIDENTITY:
00298       break;
00299 
00300     case MG_2DSCALE:
00301       *ptX = NSToCoordRound(*ptX * m00);
00302       *ptY = NSToCoordRound(*ptY * m11);
00303       break;
00304 
00305     default:
00306     case MG_2DGENERAL:
00307       x = (float)*ptX;
00308       y = (float)*ptY;
00309 
00310       *ptX = NSToCoordRound(x * m00 + y * m10);
00311       *ptY = NSToCoordRound(x * m01 + y * m11);
00312 
00313       break;
00314   }
00315 }
00316 
00317 inline PRIntn NSToIntNFloor(float aValue)
00318 {
00319   return ((0.0f <= aValue) ? PRIntn(aValue) : PRIntn(aValue - CEIL_CONST_FLOAT));
00320 }
00321 
00322 void nsTransform2D :: ScaleXCoords(const nscoord* aSrc,
00323                                    PRUint32 aNumCoords,
00324                                    PRIntn* aDst)
00325 {
00326 const nscoord* end = aSrc + aNumCoords;
00327 
00328   if (type == MG_2DIDENTITY){
00329     while (aSrc < end ) {
00330       *aDst++ = PRIntn(*aSrc++);
00331     }
00332   } else {
00333     float scale = m00;
00334     while (aSrc < end) {
00335       nscoord c = *aSrc++;
00336       *aDst++ = NSToIntNFloor(c * scale);
00337     }
00338   }
00339 }
00340 
00341 void nsTransform2D :: ScaleYCoords(const nscoord* aSrc,
00342                                    PRUint32 aNumCoords,
00343                                    PRIntn* aDst)
00344 {
00345 const nscoord* end = aSrc + aNumCoords;
00346 
00347   if (type == MG_2DIDENTITY){
00348     while (aSrc < end ) {
00349       *aDst++ = PRIntn(*aSrc++); 
00350     } 
00351   } else {
00352     float scale = m11;
00353     while (aSrc < end) {
00354       nscoord c = *aSrc++;
00355       *aDst++ = NSToIntNFloor(c * scale);
00356     }
00357   }
00358 }
00359   
00360 
00361 void nsTransform2D :: Transform(float *ptX, float *ptY)
00362 {
00363   float x, y;
00364 
00365   switch (type)
00366   {
00367     case MG_2DIDENTITY:
00368       break;
00369 
00370     case MG_2DTRANSLATION:
00371       *ptX += m20;
00372       *ptY += m21;
00373       break;
00374 
00375     case MG_2DSCALE:
00376       *ptX *= m00;
00377       *ptY *= m11;
00378       break;
00379 
00380     case MG_2DGENERAL:
00381       x = *ptX;
00382       y = *ptY;
00383 
00384       *ptX = x * m00 + y * m10;
00385       *ptY = x * m01 + y * m11;
00386 
00387       break;
00388 
00389     case MG_2DSCALE | MG_2DTRANSLATION:
00390       *ptX = *ptX * m00 + m20;
00391       *ptY = *ptY * m11 + m21;
00392       break;
00393 
00394     default:
00395     case MG_2DGENERAL | MG_2DTRANSLATION:
00396       x = *ptX;
00397       y = *ptY;
00398 
00399       *ptX = x * m00 + y * m10 + m20;
00400       *ptY = x * m01 + y * m11 + m21;
00401 
00402       break;
00403   }
00404 }
00405 
00406 void nsTransform2D :: TransformCoord(nscoord *ptX, nscoord *ptY)
00407 {
00408   float x, y;
00409 
00410   switch (type)
00411   {
00412     case MG_2DIDENTITY:
00413       break;
00414 
00415     case MG_2DTRANSLATION:
00416       *ptX += NSToCoordRound(m20);
00417       *ptY += NSToCoordRound(m21);
00418       break;
00419 
00420     case MG_2DSCALE:
00421       *ptX = NSToCoordRound(*ptX * m00);
00422       *ptY = NSToCoordRound(*ptY * m11);
00423       break;
00424 
00425     case MG_2DGENERAL:
00426       x = (float)*ptX;
00427       y = (float)*ptY;
00428 
00429       *ptX = NSToCoordRound(x * m00 + y * m10);
00430       *ptY = NSToCoordRound(x * m01 + y * m11);
00431 
00432       break;
00433 
00434     case MG_2DSCALE | MG_2DTRANSLATION:
00435       *ptX = NSToCoordRound(*ptX * m00 + m20);
00436 
00437 #if defined(_MSC_VER) && _MSC_VER < 1300
00438       *ptY = ToCoordRound(*ptY * m11 + m21);
00439 #else
00440       *ptY = NSToCoordRound(*ptY * m11 + m21);
00441 #endif
00442       break;
00443 
00444     default:
00445     case MG_2DGENERAL | MG_2DTRANSLATION:
00446       x = (float)*ptX;
00447       y = (float)*ptY;
00448 
00449       *ptX = NSToCoordRound(x * m00 + y * m10 + m20);
00450       *ptY = NSToCoordRound(x * m01 + y * m11 + m21);
00451 
00452       break;
00453   }
00454 }
00455 
00456 void nsTransform2D :: Transform(float *aX, float *aY, float *aWidth, float *aHeight)
00457 {
00458   float x, y;
00459 
00460   switch (type)
00461   {
00462     case MG_2DIDENTITY:
00463       break;
00464 
00465     case MG_2DTRANSLATION:
00466       *aX += m20;
00467       *aY += m21;
00468       break;
00469 
00470     case MG_2DSCALE:
00471       *aX *= m00;
00472       *aY *= m11;
00473       *aWidth *= m00;
00474       *aHeight *= m11;
00475       break;
00476 
00477     case MG_2DGENERAL:
00478       x = *aX;
00479       y = *aY;
00480 
00481       *aX = x * m00 + y * m10;
00482       *aY = x * m01 + y * m11;
00483 
00484       x = *aWidth;
00485       y = *aHeight;
00486 
00487       *aWidth = x * m00 + y * m10;
00488       *aHeight = x * m01 + y * m11;
00489 
00490       break;
00491 
00492     case MG_2DSCALE | MG_2DTRANSLATION:
00493       *aX = *aX * m00 + m20;
00494       *aY = *aY * m11 + m21;
00495       *aWidth *= m00;
00496       *aHeight *= m11;
00497       break;
00498 
00499     default:
00500     case MG_2DGENERAL | MG_2DTRANSLATION:
00501       x = *aX;
00502       y = *aY;
00503 
00504       *aX = x * m00 + y * m10 + m20;
00505       *aY = x * m01 + y * m11 + m21;
00506 
00507       x = *aWidth;
00508       y = *aHeight;
00509 
00510       *aWidth = x * m00 + y * m10;
00511       *aHeight = x * m01 + y * m11;
00512 
00513       break;
00514   }
00515 }
00516 
00517 void nsTransform2D :: TransformCoord(nscoord *aX, nscoord *aY, nscoord *aWidth, nscoord *aHeight)
00518 {
00519   nscoord x2 = *aX + *aWidth;
00520   nscoord y2 = *aY + *aHeight;
00521   TransformCoord(aX, aY);
00522   TransformCoord(&x2, &y2);
00523   *aWidth = x2 - *aX;
00524   *aHeight = y2 - *aY;
00525 }
00526 
00527 void nsTransform2D :: AddTranslation(float ptX, float ptY)
00528 {
00529   if (type == MG_2DIDENTITY)
00530   {
00531     m20 = ptX;
00532     m21 = ptY;
00533   }
00534   else if ((type & MG_2DSCALE) != 0)
00535   {
00536     //current matrix is at least scale
00537 
00538     m20 += ptX * m00;
00539     m21 += ptY * m11;
00540   }
00541   else if ((type & MG_2DGENERAL) != 0)
00542   {
00543     //current matrix is at least general
00544 
00545     m20 += ptX * m00 + ptY * m10;
00546     m21 += ptX * m01 + ptY * m11;
00547   }
00548   else
00549   {
00550     m20 += ptX;
00551     m21 += ptY;
00552   }
00553 
00554   type |= MG_2DTRANSLATION;
00555 }
00556 
00557 void nsTransform2D :: AddScale(float ptX, float ptY)
00558 {
00559   if ((type == MG_2DIDENTITY) || (type == MG_2DTRANSLATION))
00560   {
00561     m00 = ptX;
00562     m11 = ptY;
00563   }
00564   else if ((type & MG_2DSCALE) != 0)
00565   {
00566     //current matrix is at least scale
00567 
00568     m00 *= ptX;
00569     m11 *= ptY;
00570   }
00571   else if ((type & MG_2DGENERAL) != 0)
00572   {
00573     //current matrix is at least general
00574 
00575     m00 *= ptX;
00576     m01 *= ptX;
00577     m10 *= ptY;
00578     m11 *= ptY;
00579   }
00580 
00581   type |= MG_2DSCALE;
00582 }
00583 
00584 nscoord nsTransform2D::ToCoordRound(float aCoord)
00585 {
00586   return NSToCoordRound(aCoord);
00587 }
00588