LCOV - code coverage report
Current view: directory - layout/style - CSSCalc.h (source / functions) Found Hit Coverage
Test: app.info Lines: 111 0 0.0 %
Date: 2012-06-02 Functions: 19 0 0.0 %

       1                 : /* vim: set shiftwidth=2 tabstop=8 autoindent cindent expandtab: */
       2                 : /* ***** BEGIN LICENSE BLOCK *****
       3                 :  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
       4                 :  *
       5                 :  * The contents of this file are subject to the Mozilla Public License Version
       6                 :  * 1.1 (the "License"); you may not use this file except in compliance with
       7                 :  * the License. You may obtain a copy of the License at
       8                 :  * http://www.mozilla.org/MPL/
       9                 :  *
      10                 :  * Software distributed under the License is distributed on an "AS IS" basis,
      11                 :  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
      12                 :  * for the specific language governing rights and limitations under the
      13                 :  * License.
      14                 :  *
      15                 :  * The Original Code is CSSCalc.h.
      16                 :  *
      17                 :  * The Initial Developer of the Original Code is the Mozilla Foundation.
      18                 :  * Portions created by the Initial Developer are Copyright (C) 2009
      19                 :  * the Initial Developer. All Rights Reserved.
      20                 :  *
      21                 :  * Contributor(s):
      22                 :  *   L. David Baron <dbaron@dbaron.org>, Mozilla Corporation (original author)
      23                 :  *
      24                 :  * Alternatively, the contents of this file may be used under the terms of
      25                 :  * either the GNU General Public License Version 2 or later (the "GPL"), or
      26                 :  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
      27                 :  * in which case the provisions of the GPL or the LGPL are applicable instead
      28                 :  * of those above. If you wish to allow use of your version of this file only
      29                 :  * under the terms of either the GPL or the LGPL, and not to allow others to
      30                 :  * use your version of this file under the terms of the MPL, indicate your
      31                 :  * decision by deleting the provisions above and replace them with the notice
      32                 :  * and other provisions required by the GPL or the LGPL. If you do not delete
      33                 :  * the provisions above, a recipient may use your version of this file under
      34                 :  * the terms of any one of the MPL, the GPL or the LGPL.
      35                 :  *
      36                 :  * ***** END LICENSE BLOCK ***** */
      37                 : #ifndef CSSCalc_h_
      38                 : #define CSSCalc_h_
      39                 : 
      40                 : #include "nsCSSValue.h"
      41                 : #include "nsStyleCoord.h"
      42                 : #include <math.h>
      43                 : 
      44                 : namespace mozilla {
      45                 : 
      46                 : namespace css {
      47                 : 
      48                 : /**
      49                 :  * ComputeCalc computes the result of a calc() expression tree.
      50                 :  *
      51                 :  * It is templatized over a CalcOps class that is expected to provide:
      52                 :  *
      53                 :  *   // input_type and input_array_type have a bunch of very specific
      54                 :  *   // expectations (which happen to be met by two classes (nsCSSValue
      55                 :  *   // and nsStyleCoord).  There must be methods (roughly):
      56                 :  *   //   input_array_type* input_type::GetArrayValue();
      57                 :  *   //   PRUint32 input_array_type::Count() const;
      58                 :  *   //   input_type& input_array_type::Item(PRUint32);
      59                 :  *   typedef ... input_type;
      60                 :  *   typedef ... input_array_type;
      61                 :  *
      62                 :  *   typedef ... result_type;
      63                 :  *
      64                 :  *   // GetUnit(avalue) must return the correct nsCSSUnit for any
      65                 :  *   // value that represents a calc tree node (eCSSUnit_Calc*).  For
      66                 :  *   // other nodes, it may return any non eCSSUnit_Calc* unit.
      67                 :  *   static nsCSSUnit GetUnit(const input_type& aValue);
      68                 :  *
      69                 :  *   result_type
      70                 :  *   MergeAdditive(nsCSSUnit aCalcFunction,
      71                 :  *                 result_type aValue1, result_type aValue2);
      72                 :  *
      73                 :  *   result_type
      74                 :  *   MergeMultiplicativeL(nsCSSUnit aCalcFunction,
      75                 :  *                        float aValue1, result_type aValue2);
      76                 :  *
      77                 :  *   result_type
      78                 :  *   MergeMultiplicativeR(nsCSSUnit aCalcFunction,
      79                 :  *                        result_type aValue1, float aValue2);
      80                 :  *
      81                 :  *   result_type
      82                 :  *   ComputeLeafValue(const input_type& aValue);
      83                 :  *
      84                 :  *   float
      85                 :  *   ComputeNumber(const input_type& aValue);
      86                 :  *
      87                 :  * The CalcOps methods might compute the calc() expression down to a
      88                 :  * number, reduce some parts of it to a number but replicate other
      89                 :  * parts, or produce a tree with a different data structure (for
      90                 :  * example, nsCSS* for specified values vs nsStyle* for computed
      91                 :  * values).
      92                 :  *
      93                 :  * For each leaf in the calc() expression, ComputeCalc will call either
      94                 :  * ComputeNumber (when the leaf is the left side of a Times_L or the
      95                 :  * right side of a Times_R or Divided) or ComputeLeafValue (otherwise).
      96                 :  * (The CalcOps in the CSS parser that reduces purely numeric
      97                 :  * expressions in turn calls ComputeCalc on numbers; other ops can
      98                 :  * presume that expressions in the number positions have already been
      99                 :  * normalized to a single numeric value and derive from
     100                 :  * NumbersAlreadyNormalizedCalcOps.)
     101                 :  *
     102                 :  * For non-leaves, one of the Merge functions will be called:
     103                 :  *   MergeAdditive for Plus and Minus
     104                 :  *   MergeMultiplicativeL for Times_L (number * value)
     105                 :  *   MergeMultiplicativeR for Times_R (value * number) and Divided
     106                 :  */
     107                 : template <class CalcOps>
     108                 : static typename CalcOps::result_type
     109               0 : ComputeCalc(const typename CalcOps::input_type& aValue, CalcOps &aOps)
     110                 : {
     111               0 :   switch (CalcOps::GetUnit(aValue)) {
     112                 :     case eCSSUnit_Calc: {
     113               0 :       typename CalcOps::input_array_type *arr = aValue.GetArrayValue();
     114               0 :       NS_ABORT_IF_FALSE(arr->Count() == 1, "unexpected length");
     115               0 :       return ComputeCalc(arr->Item(0), aOps);
     116                 :     }
     117                 :     case eCSSUnit_Calc_Plus:
     118                 :     case eCSSUnit_Calc_Minus: {
     119               0 :       typename CalcOps::input_array_type *arr = aValue.GetArrayValue();
     120               0 :       NS_ABORT_IF_FALSE(arr->Count() == 2, "unexpected length");
     121               0 :       typename CalcOps::result_type lhs = ComputeCalc(arr->Item(0), aOps),
     122               0 :                                     rhs = ComputeCalc(arr->Item(1), aOps);
     123               0 :       return aOps.MergeAdditive(CalcOps::GetUnit(aValue), lhs, rhs);
     124                 :     }
     125                 :     case eCSSUnit_Calc_Times_L: {
     126               0 :       typename CalcOps::input_array_type *arr = aValue.GetArrayValue();
     127               0 :       NS_ABORT_IF_FALSE(arr->Count() == 2, "unexpected length");
     128               0 :       float lhs = aOps.ComputeNumber(arr->Item(0));
     129               0 :       typename CalcOps::result_type rhs = ComputeCalc(arr->Item(1), aOps);
     130               0 :       return aOps.MergeMultiplicativeL(CalcOps::GetUnit(aValue), lhs, rhs);
     131                 :     }
     132                 :     case eCSSUnit_Calc_Times_R:
     133                 :     case eCSSUnit_Calc_Divided: {
     134               0 :       typename CalcOps::input_array_type *arr = aValue.GetArrayValue();
     135               0 :       NS_ABORT_IF_FALSE(arr->Count() == 2, "unexpected length");
     136               0 :       typename CalcOps::result_type lhs = ComputeCalc(arr->Item(0), aOps);
     137               0 :       float rhs = aOps.ComputeNumber(arr->Item(1));
     138               0 :       return aOps.MergeMultiplicativeR(CalcOps::GetUnit(aValue), lhs, rhs);
     139                 :     }
     140                 :     default: {
     141               0 :       return aOps.ComputeLeafValue(aValue);
     142                 :     }
     143                 :   }
     144                 : }
     145                 : 
     146                 : /**
     147                 :  * The input unit operation for input_type being nsCSSValue.
     148                 :  */
     149                 : struct CSSValueInputCalcOps
     150               0 : {
     151                 :   typedef nsCSSValue input_type;
     152                 :   typedef nsCSSValue::Array input_array_type;
     153                 : 
     154               0 :   static nsCSSUnit GetUnit(const nsCSSValue& aValue)
     155                 :   {
     156               0 :     return aValue.GetUnit();
     157                 :   }
     158                 : 
     159                 : };
     160                 : 
     161                 : /**
     162                 :  * Basic*CalcOps provide a partial implementation of the CalcOps
     163                 :  * template parameter to ComputeCalc, for those callers whose merging
     164                 :  * just consists of mathematics (rather than tree construction).
     165                 :  */
     166                 : 
     167                 : struct BasicCoordCalcOps
     168               0 : {
     169                 :   typedef nscoord result_type;
     170                 : 
     171                 :   result_type
     172               0 :   MergeAdditive(nsCSSUnit aCalcFunction,
     173                 :                 result_type aValue1, result_type aValue2)
     174                 :   {
     175               0 :     if (aCalcFunction == eCSSUnit_Calc_Plus) {
     176               0 :       return NSCoordSaturatingAdd(aValue1, aValue2);
     177                 :     }
     178               0 :     NS_ABORT_IF_FALSE(aCalcFunction == eCSSUnit_Calc_Minus,
     179                 :                       "unexpected unit");
     180               0 :     return NSCoordSaturatingSubtract(aValue1, aValue2, 0);
     181                 :   }
     182                 : 
     183                 :   result_type
     184               0 :   MergeMultiplicativeL(nsCSSUnit aCalcFunction,
     185                 :                        float aValue1, result_type aValue2)
     186                 :   {
     187               0 :     NS_ABORT_IF_FALSE(aCalcFunction == eCSSUnit_Calc_Times_L,
     188                 :                       "unexpected unit");
     189               0 :     return NSCoordSaturatingMultiply(aValue2, aValue1);
     190                 :   }
     191                 : 
     192                 :   result_type
     193               0 :   MergeMultiplicativeR(nsCSSUnit aCalcFunction,
     194                 :                        result_type aValue1, float aValue2)
     195                 :   {
     196               0 :     NS_ABORT_IF_FALSE(aCalcFunction == eCSSUnit_Calc_Times_R ||
     197                 :                       aCalcFunction == eCSSUnit_Calc_Divided,
     198                 :                       "unexpected unit");
     199               0 :     if (aCalcFunction == eCSSUnit_Calc_Divided) {
     200               0 :       aValue2 = 1.0f / aValue2;
     201                 :     }
     202               0 :     return NSCoordSaturatingMultiply(aValue1, aValue2);
     203                 :   }
     204                 : };
     205                 : 
     206                 : struct BasicFloatCalcOps
     207                 : {
     208                 :   typedef float result_type;
     209                 : 
     210                 :   result_type
     211               0 :   MergeAdditive(nsCSSUnit aCalcFunction,
     212                 :                 result_type aValue1, result_type aValue2)
     213                 :   {
     214               0 :     if (aCalcFunction == eCSSUnit_Calc_Plus) {
     215               0 :       return aValue1 + aValue2;
     216                 :     }
     217               0 :     NS_ABORT_IF_FALSE(aCalcFunction == eCSSUnit_Calc_Minus,
     218                 :                       "unexpected unit");
     219               0 :     return aValue1 - aValue2;
     220                 :   }
     221                 : 
     222                 :   result_type
     223               0 :   MergeMultiplicativeL(nsCSSUnit aCalcFunction,
     224                 :                        float aValue1, result_type aValue2)
     225                 :   {
     226               0 :     NS_ABORT_IF_FALSE(aCalcFunction == eCSSUnit_Calc_Times_L,
     227                 :                       "unexpected unit");
     228               0 :     return aValue1 * aValue2;
     229                 :   }
     230                 : 
     231                 :   result_type
     232               0 :   MergeMultiplicativeR(nsCSSUnit aCalcFunction,
     233                 :                        result_type aValue1, float aValue2)
     234                 :   {
     235               0 :     if (aCalcFunction == eCSSUnit_Calc_Times_R) {
     236               0 :       return aValue1 * aValue2;
     237                 :     }
     238               0 :     NS_ABORT_IF_FALSE(aCalcFunction == eCSSUnit_Calc_Divided,
     239                 :                       "unexpected unit");
     240               0 :     return aValue1 / aValue2;
     241                 :   }
     242                 : };
     243                 : 
     244                 : /**
     245                 :  * A ComputeNumber implementation for callers that can assume numbers
     246                 :  * are already normalized (i.e., anything past the parser).
     247                 :  */
     248                 : struct NumbersAlreadyNormalizedOps : public CSSValueInputCalcOps
     249               0 : {
     250               0 :   float ComputeNumber(const nsCSSValue& aValue)
     251                 :   {
     252               0 :     NS_ABORT_IF_FALSE(aValue.GetUnit() == eCSSUnit_Number, "unexpected unit");
     253               0 :     return aValue.GetFloatValue();
     254                 :   }
     255                 : };
     256                 : 
     257                 : /**
     258                 :  * SerializeCalc appends the serialization of aValue to a string.
     259                 :  *
     260                 :  * It is templatized over a CalcOps class that is expected to provide:
     261                 :  *
     262                 :  *   // input_type and input_array_type have a bunch of very specific
     263                 :  *   // expectations (which happen to be met by two classes (nsCSSValue
     264                 :  *   // and nsStyleCoord).  There must be methods (roughly):
     265                 :  *   //   input_array_type* input_type::GetArrayValue();
     266                 :  *   //   PRUint32 input_array_type::Count() const;
     267                 :  *   //   input_type& input_array_type::Item(PRUint32);
     268                 :  *   typedef ... input_type;
     269                 :  *   typedef ... input_array_type;
     270                 :  *
     271                 :  *   static nsCSSUnit GetUnit(const input_type& aValue);
     272                 :  *
     273                 :  *   void Append(const char* aString);
     274                 :  *   void AppendLeafValue(const input_type& aValue);
     275                 :  *   void AppendNumber(const input_type& aValue);
     276                 :  *
     277                 :  * Data structures given may or may not have a toplevel eCSSUnit_Calc
     278                 :  * node representing a calc whose toplevel is not min() or max().
     279                 :  */
     280                 : 
     281                 : template <class CalcOps>
     282                 : static void
     283                 : SerializeCalcInternal(const typename CalcOps::input_type& aValue, CalcOps &aOps);
     284                 : 
     285                 : // Serialize the toplevel value in a calc() tree.  See big comment
     286                 : // above.
     287                 : template <class CalcOps>
     288                 : static void
     289               0 : SerializeCalc(const typename CalcOps::input_type& aValue, CalcOps &aOps)
     290                 : {
     291               0 :   aOps.Append("-moz-calc(");
     292               0 :   nsCSSUnit unit = CalcOps::GetUnit(aValue);
     293               0 :   if (unit == eCSSUnit_Calc) {
     294               0 :     const typename CalcOps::input_array_type *array = aValue.GetArrayValue();
     295               0 :     NS_ABORT_IF_FALSE(array->Count() == 1, "unexpected length");
     296               0 :     SerializeCalcInternal(array->Item(0), aOps);
     297                 :   } else {
     298               0 :     SerializeCalcInternal(aValue, aOps);
     299                 :   }
     300               0 :   aOps.Append(")");
     301               0 : }
     302                 : 
     303                 : static inline bool
     304               0 : IsCalcAdditiveUnit(nsCSSUnit aUnit)
     305                 : {
     306                 :   return aUnit == eCSSUnit_Calc_Plus ||
     307               0 :          aUnit == eCSSUnit_Calc_Minus;
     308                 : }
     309                 : 
     310                 : static inline bool
     311               0 : IsCalcMultiplicativeUnit(nsCSSUnit aUnit)
     312                 : {
     313                 :   return aUnit == eCSSUnit_Calc_Times_L ||
     314                 :          aUnit == eCSSUnit_Calc_Times_R ||
     315               0 :          aUnit == eCSSUnit_Calc_Divided;
     316                 : }
     317                 : 
     318                 : // Serialize a non-toplevel value in a calc() tree.  See big comment
     319                 : // above.
     320                 : template <class CalcOps>
     321                 : /* static */ void
     322               0 : SerializeCalcInternal(const typename CalcOps::input_type& aValue, CalcOps &aOps)
     323                 : {
     324               0 :   nsCSSUnit unit = CalcOps::GetUnit(aValue);
     325               0 :   if (IsCalcAdditiveUnit(unit)) {
     326               0 :     const typename CalcOps::input_array_type *array = aValue.GetArrayValue();
     327               0 :     NS_ABORT_IF_FALSE(array->Count() == 2, "unexpected length");
     328                 : 
     329               0 :     SerializeCalcInternal(array->Item(0), aOps);
     330                 : 
     331               0 :     if (eCSSUnit_Calc_Plus == unit) {
     332               0 :       aOps.Append(" + ");
     333                 :     } else {
     334               0 :       NS_ABORT_IF_FALSE(eCSSUnit_Calc_Minus == unit, "unexpected unit");
     335               0 :       aOps.Append(" - ");
     336                 :     }
     337                 : 
     338               0 :     bool needParens = IsCalcAdditiveUnit(CalcOps::GetUnit(array->Item(1)));
     339               0 :     if (needParens) {
     340               0 :       aOps.Append("(");
     341                 :     }
     342               0 :     SerializeCalcInternal(array->Item(1), aOps);
     343               0 :     if (needParens) {
     344               0 :       aOps.Append(")");
     345                 :     }
     346               0 :   } else if (IsCalcMultiplicativeUnit(unit)) {
     347               0 :     const typename CalcOps::input_array_type *array = aValue.GetArrayValue();
     348               0 :     NS_ABORT_IF_FALSE(array->Count() == 2, "unexpected length");
     349                 : 
     350               0 :     bool needParens = IsCalcAdditiveUnit(CalcOps::GetUnit(array->Item(0)));
     351               0 :     if (needParens) {
     352               0 :       aOps.Append("(");
     353                 :     }
     354               0 :     if (unit == eCSSUnit_Calc_Times_L) {
     355               0 :       aOps.AppendNumber(array->Item(0));
     356                 :     } else {
     357               0 :       SerializeCalcInternal(array->Item(0), aOps);
     358                 :     }
     359               0 :     if (needParens) {
     360               0 :       aOps.Append(")");
     361                 :     }
     362                 : 
     363               0 :     if (eCSSUnit_Calc_Times_L == unit || eCSSUnit_Calc_Times_R == unit) {
     364               0 :       aOps.Append(" * ");
     365                 :     } else {
     366               0 :       NS_ABORT_IF_FALSE(eCSSUnit_Calc_Divided == unit, "unexpected unit");
     367               0 :       aOps.Append(" / ");
     368                 :     }
     369                 : 
     370               0 :     nsCSSUnit subUnit = CalcOps::GetUnit(array->Item(1));
     371               0 :     needParens = IsCalcAdditiveUnit(subUnit) ||
     372                 :                  IsCalcMultiplicativeUnit(subUnit);
     373               0 :     if (needParens) {
     374               0 :       aOps.Append("(");
     375                 :     }
     376               0 :     if (unit == eCSSUnit_Calc_Times_L) {
     377               0 :       SerializeCalcInternal(array->Item(1), aOps);
     378                 :     } else {
     379               0 :       aOps.AppendNumber(array->Item(1));
     380                 :     }
     381               0 :     if (needParens) {
     382               0 :       aOps.Append(")");
     383                 :     }
     384                 :   } else {
     385               0 :     aOps.AppendLeafValue(aValue);
     386                 :   }
     387               0 : }
     388                 : 
     389                 : }
     390                 : 
     391                 : }
     392                 : 
     393                 : #endif /* !defined(CSSCalc_h_) */

Generated by: LCOV version 1.7