LCOV - code coverage report
Current view: directory - layout/svg/base/src - nsSVGUtils.cpp (source / functions) Found Hit Coverage
Test: app.info Lines: 738 0 0.0 %
Date: 2012-06-02 Functions: 69 0 0.0 %

       1                 : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
       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 the Mozilla SVG project.
      16                 :  *
      17                 :  * The Initial Developer of the Original Code is IBM Corporation.
      18                 :  * Portions created by the Initial Developer are Copyright (C) 2005
      19                 :  * the Initial Developer. All Rights Reserved.
      20                 :  *
      21                 :  * Contributor(s):
      22                 :  *
      23                 :  * Alternatively, the contents of this file may be used under the terms of
      24                 :  * either of the GNU General Public License Version 2 or later (the "GPL"),
      25                 :  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
      26                 :  * in which case the provisions of the GPL or the LGPL are applicable instead
      27                 :  * of those above. If you wish to allow use of your version of this file only
      28                 :  * under the terms of either the GPL or the LGPL, and not to allow others to
      29                 :  * use your version of this file under the terms of the MPL, indicate your
      30                 :  * decision by deleting the provisions above and replace them with the notice
      31                 :  * and other provisions required by the GPL or the LGPL. If you do not delete
      32                 :  * the provisions above, a recipient may use your version of this file under
      33                 :  * the terms of any one of the MPL, the GPL or the LGPL.
      34                 :  *
      35                 :  * ***** END LICENSE BLOCK ***** */
      36                 : 
      37                 : // include nsSVGUtils.h first to ensure definition of M_SQRT1_2 is picked up
      38                 : #include "nsSVGUtils.h"
      39                 : #include "nsIDOMDocument.h"
      40                 : #include "nsIDOMSVGElement.h"
      41                 : #include "nsIDOMSVGSVGElement.h"
      42                 : #include "nsStyleCoord.h"
      43                 : #include "nsPresContext.h"
      44                 : #include "nsSVGSVGElement.h"
      45                 : #include "nsIContent.h"
      46                 : #include "nsIDocument.h"
      47                 : #include "nsIFrame.h"
      48                 : #include "nsGkAtoms.h"
      49                 : #include "nsIURI.h"
      50                 : #include "nsStyleStruct.h"
      51                 : #include "nsIPresShell.h"
      52                 : #include "nsNetUtil.h"
      53                 : #include "nsFrameList.h"
      54                 : #include "nsISVGChildFrame.h"
      55                 : #include "nsContentDLF.h"
      56                 : #include "nsContentUtils.h"
      57                 : #include "nsSVGFilterFrame.h"
      58                 : #include "nsINameSpaceManager.h"
      59                 : #include "nsDOMError.h"
      60                 : #include "nsSVGOuterSVGFrame.h"
      61                 : #include "nsSVGInnerSVGFrame.h"
      62                 : #include "SVGAnimatedPreserveAspectRatio.h"
      63                 : #include "nsSVGClipPathFrame.h"
      64                 : #include "nsSVGMaskFrame.h"
      65                 : #include "nsSVGContainerFrame.h"
      66                 : #include "nsSVGTextContainerFrame.h"
      67                 : #include "nsSVGLength2.h"
      68                 : #include "nsGenericElement.h"
      69                 : #include "nsSVGGraphicElement.h"
      70                 : #include "nsAttrValue.h"
      71                 : #include "nsIScriptError.h"
      72                 : #include "gfxContext.h"
      73                 : #include "gfxMatrix.h"
      74                 : #include "gfxRect.h"
      75                 : #include "gfxImageSurface.h"
      76                 : #include "gfxPlatform.h"
      77                 : #include "nsSVGForeignObjectFrame.h"
      78                 : #include "nsIDOMSVGUnitTypes.h"
      79                 : #include "nsSVGEffects.h"
      80                 : #include "nsMathUtils.h"
      81                 : #include "nsSVGIntegrationUtils.h"
      82                 : #include "nsSVGFilterPaintCallback.h"
      83                 : #include "nsSVGGeometryFrame.h"
      84                 : #include "nsComputedDOMStyle.h"
      85                 : #include "nsSVGPathGeometryFrame.h"
      86                 : #include "nsSVGPathGeometryElement.h"
      87                 : #include "prdtoa.h"
      88                 : #include "mozilla/dom/Element.h"
      89                 : #include "gfxUtils.h"
      90                 : #include "mozilla/Preferences.h"
      91                 : 
      92                 : #include "mozilla/gfx/2D.h"
      93                 : 
      94                 : using namespace mozilla;
      95                 : using namespace mozilla::dom;
      96                 : using namespace mozilla::gfx;
      97                 : 
      98                 : // c = n / 255
      99                 : // (c <= 0.0031308 ? c * 12.92 : 1.055 * pow(c, 1 / 2.4) - 0.055) * 255 + 0.5
     100                 : static const PRUint8 glinearRGBTosRGBMap[256] = {
     101                 :   0,  13,  22,  28,  34,  38,  42,  46,
     102                 :  50,  53,  56,  59,  61,  64,  66,  69,
     103                 :  71,  73,  75,  77,  79,  81,  83,  85,
     104                 :  86,  88,  90,  92,  93,  95,  96,  98,
     105                 :  99, 101, 102, 104, 105, 106, 108, 109,
     106                 : 110, 112, 113, 114, 115, 117, 118, 119,
     107                 : 120, 121, 122, 124, 125, 126, 127, 128,
     108                 : 129, 130, 131, 132, 133, 134, 135, 136,
     109                 : 137, 138, 139, 140, 141, 142, 143, 144,
     110                 : 145, 146, 147, 148, 148, 149, 150, 151,
     111                 : 152, 153, 154, 155, 155, 156, 157, 158,
     112                 : 159, 159, 160, 161, 162, 163, 163, 164,
     113                 : 165, 166, 167, 167, 168, 169, 170, 170,
     114                 : 171, 172, 173, 173, 174, 175, 175, 176,
     115                 : 177, 178, 178, 179, 180, 180, 181, 182,
     116                 : 182, 183, 184, 185, 185, 186, 187, 187,
     117                 : 188, 189, 189, 190, 190, 191, 192, 192,
     118                 : 193, 194, 194, 195, 196, 196, 197, 197,
     119                 : 198, 199, 199, 200, 200, 201, 202, 202,
     120                 : 203, 203, 204, 205, 205, 206, 206, 207,
     121                 : 208, 208, 209, 209, 210, 210, 211, 212,
     122                 : 212, 213, 213, 214, 214, 215, 215, 216,
     123                 : 216, 217, 218, 218, 219, 219, 220, 220,
     124                 : 221, 221, 222, 222, 223, 223, 224, 224,
     125                 : 225, 226, 226, 227, 227, 228, 228, 229,
     126                 : 229, 230, 230, 231, 231, 232, 232, 233,
     127                 : 233, 234, 234, 235, 235, 236, 236, 237,
     128                 : 237, 238, 238, 238, 239, 239, 240, 240,
     129                 : 241, 241, 242, 242, 243, 243, 244, 244,
     130                 : 245, 245, 246, 246, 246, 247, 247, 248,
     131                 : 248, 249, 249, 250, 250, 251, 251, 251,
     132                 : 252, 252, 253, 253, 254, 254, 255, 255
     133                 : };
     134                 : 
     135                 : // c = n / 255
     136                 : // c <= 0.04045 ? c / 12.92 : pow((c + 0.055) / 1.055, 2.4)) * 255 + 0.5
     137                 : static const PRUint8 gsRGBToLinearRGBMap[256] = {
     138                 :   0,   0,   0,   0,   0,   0,   0,   1,
     139                 :   1,   1,   1,   1,   1,   1,   1,   1,
     140                 :   1,   1,   2,   2,   2,   2,   2,   2,
     141                 :   2,   2,   3,   3,   3,   3,   3,   3,
     142                 :   4,   4,   4,   4,   4,   5,   5,   5,
     143                 :   5,   6,   6,   6,   6,   7,   7,   7,
     144                 :   8,   8,   8,   8,   9,   9,   9,  10,
     145                 :  10,  10,  11,  11,  12,  12,  12,  13,
     146                 :  13,  13,  14,  14,  15,  15,  16,  16,
     147                 :  17,  17,  17,  18,  18,  19,  19,  20,
     148                 :  20,  21,  22,  22,  23,  23,  24,  24,
     149                 :  25,  25,  26,  27,  27,  28,  29,  29,
     150                 :  30,  30,  31,  32,  32,  33,  34,  35,
     151                 :  35,  36,  37,  37,  38,  39,  40,  41,
     152                 :  41,  42,  43,  44,  45,  45,  46,  47,
     153                 :  48,  49,  50,  51,  51,  52,  53,  54,
     154                 :  55,  56,  57,  58,  59,  60,  61,  62,
     155                 :  63,  64,  65,  66,  67,  68,  69,  70,
     156                 :  71,  72,  73,  74,  76,  77,  78,  79,
     157                 :  80,  81,  82,  84,  85,  86,  87,  88,
     158                 :  90,  91,  92,  93,  95,  96,  97,  99,
     159                 : 100, 101, 103, 104, 105, 107, 108, 109,
     160                 : 111, 112, 114, 115, 116, 118, 119, 121,
     161                 : 122, 124, 125, 127, 128, 130, 131, 133,
     162                 : 134, 136, 138, 139, 141, 142, 144, 146,
     163                 : 147, 149, 151, 152, 154, 156, 157, 159,
     164                 : 161, 163, 164, 166, 168, 170, 171, 173,
     165                 : 175, 177, 179, 181, 183, 184, 186, 188,
     166                 : 190, 192, 194, 196, 198, 200, 202, 204,
     167                 : 206, 208, 210, 212, 214, 216, 218, 220,
     168                 : 222, 224, 226, 229, 231, 233, 235, 237,
     169                 : 239, 242, 244, 246, 248, 250, 253, 255
     170                 : };
     171                 : 
     172                 : static bool gSMILEnabled;
     173                 : static const char SMIL_PREF_STR[] = "svg.smil.enabled";
     174                 : 
     175                 : static int
     176               0 : SMILPrefChanged(const char *aPref, void *aClosure)
     177                 : {
     178               0 :   bool prefVal = Preferences::GetBool(SMIL_PREF_STR);
     179               0 :   gSMILEnabled = prefVal;
     180               0 :   return 0;
     181                 : }
     182                 : 
     183                 : bool
     184               0 : NS_SMILEnabled()
     185                 : {
     186                 :   static bool sInitialized = false;
     187                 :   
     188               0 :   if (!sInitialized) {
     189                 :     /* check and register ourselves with the pref */
     190               0 :     gSMILEnabled = Preferences::GetBool(SMIL_PREF_STR);
     191               0 :     Preferences::RegisterCallback(SMILPrefChanged, SMIL_PREF_STR);
     192                 : 
     193               0 :     sInitialized = true;
     194                 :   }
     195                 : 
     196               0 :   return gSMILEnabled;
     197                 : }
     198                 : 
     199                 : // we only take the address of this:
     200                 : static mozilla::gfx::UserDataKey sSVGAutoRenderStateKey;
     201                 : 
     202               0 : SVGAutoRenderState::SVGAutoRenderState(nsRenderingContext *aContext,
     203                 :                                        RenderMode aMode)
     204                 :   : mContext(aContext)
     205                 :   , mOriginalRenderState(nsnull)
     206                 :   , mMode(aMode)
     207               0 :   , mPaintingToWindow(false)
     208                 : {
     209               0 :   mOriginalRenderState = aContext->RemoveUserData(&sSVGAutoRenderStateKey);
     210                 :   // We always remove ourselves from aContext before it dies, so
     211                 :   // passing nsnull as the destroy function is okay.
     212               0 :   aContext->AddUserData(&sSVGAutoRenderStateKey, this, nsnull);
     213               0 : }
     214                 : 
     215               0 : SVGAutoRenderState::~SVGAutoRenderState()
     216                 : {
     217               0 :   mContext->RemoveUserData(&sSVGAutoRenderStateKey);
     218               0 :   if (mOriginalRenderState) {
     219               0 :     mContext->AddUserData(&sSVGAutoRenderStateKey, mOriginalRenderState, nsnull);
     220                 :   }
     221               0 : }
     222                 : 
     223                 : void
     224               0 : SVGAutoRenderState::SetPaintingToWindow(bool aPaintingToWindow)
     225                 : {
     226               0 :   mPaintingToWindow = aPaintingToWindow;
     227               0 : }
     228                 : 
     229                 : /* static */ SVGAutoRenderState::RenderMode
     230               0 : SVGAutoRenderState::GetRenderMode(nsRenderingContext *aContext)
     231                 : {
     232               0 :   void *state = aContext->GetUserData(&sSVGAutoRenderStateKey);
     233               0 :   if (state) {
     234               0 :     return static_cast<SVGAutoRenderState*>(state)->mMode;
     235                 :   }
     236               0 :   return NORMAL;
     237                 : }
     238                 : 
     239                 : /* static */ bool
     240               0 : SVGAutoRenderState::IsPaintingToWindow(nsRenderingContext *aContext)
     241                 : {
     242               0 :   void *state = aContext->GetUserData(&sSVGAutoRenderStateKey);
     243               0 :   if (state) {
     244               0 :     return static_cast<SVGAutoRenderState*>(state)->mPaintingToWindow;
     245                 :   }
     246               0 :   return false;
     247                 : }
     248                 : 
     249                 : nsSVGSVGElement*
     250               0 : nsSVGUtils::GetOuterSVGElement(nsSVGElement *aSVGElement)
     251                 : {
     252               0 :   nsIContent *element = nsnull;
     253               0 :   nsIContent *ancestor = aSVGElement->GetFlattenedTreeParent();
     254                 : 
     255               0 :   while (ancestor && ancestor->IsSVG() &&
     256               0 :                      ancestor->Tag() != nsGkAtoms::foreignObject) {
     257               0 :     element = ancestor;
     258               0 :     ancestor = element->GetFlattenedTreeParent();
     259                 :   }
     260                 : 
     261               0 :   if (element && element->Tag() == nsGkAtoms::svg) {
     262               0 :     return static_cast<nsSVGSVGElement*>(element);
     263                 :   }
     264               0 :   return nsnull;
     265                 : }
     266                 : 
     267                 : float
     268               0 : nsSVGUtils::GetFontSize(Element *aElement)
     269                 : {
     270               0 :   if (!aElement)
     271               0 :     return 1.0f;
     272                 : 
     273                 :   nsRefPtr<nsStyleContext> styleContext = 
     274                 :     nsComputedDOMStyle::GetStyleContextForElementNoFlush(aElement,
     275               0 :                                                          nsnull, nsnull);
     276               0 :   if (!styleContext) {
     277                 :     // ReportToConsole
     278               0 :     NS_WARNING("Couldn't get style context for content in GetFontStyle");
     279               0 :     return 1.0f;
     280                 :   }
     281                 : 
     282               0 :   return GetFontSize(styleContext);
     283                 : }
     284                 : 
     285                 : float
     286               0 : nsSVGUtils::GetFontSize(nsIFrame *aFrame)
     287                 : {
     288               0 :   NS_ABORT_IF_FALSE(aFrame, "NULL frame in GetFontSize");
     289               0 :   return GetFontSize(aFrame->GetStyleContext());
     290                 : }
     291                 : 
     292                 : float
     293               0 : nsSVGUtils::GetFontSize(nsStyleContext *aStyleContext)
     294                 : {
     295               0 :   NS_ABORT_IF_FALSE(aStyleContext, "NULL style context in GetFontSize");
     296                 : 
     297               0 :   nsPresContext *presContext = aStyleContext->PresContext();
     298               0 :   NS_ABORT_IF_FALSE(presContext, "NULL pres context in GetFontSize");
     299                 : 
     300               0 :   nscoord fontSize = aStyleContext->GetStyleFont()->mSize;
     301               0 :   return nsPresContext::AppUnitsToFloatCSSPixels(fontSize) / 
     302               0 :          presContext->TextZoom();
     303                 : }
     304                 : 
     305                 : float
     306               0 : nsSVGUtils::GetFontXHeight(Element *aElement)
     307                 : {
     308               0 :   if (!aElement)
     309               0 :     return 1.0f;
     310                 : 
     311                 :   nsRefPtr<nsStyleContext> styleContext = 
     312                 :     nsComputedDOMStyle::GetStyleContextForElementNoFlush(aElement,
     313               0 :                                                          nsnull, nsnull);
     314               0 :   if (!styleContext) {
     315                 :     // ReportToConsole
     316               0 :     NS_WARNING("Couldn't get style context for content in GetFontStyle");
     317               0 :     return 1.0f;
     318                 :   }
     319                 : 
     320               0 :   return GetFontXHeight(styleContext);
     321                 : }
     322                 :   
     323                 : float
     324               0 : nsSVGUtils::GetFontXHeight(nsIFrame *aFrame)
     325                 : {
     326               0 :   NS_ABORT_IF_FALSE(aFrame, "NULL frame in GetFontXHeight");
     327               0 :   return GetFontXHeight(aFrame->GetStyleContext());
     328                 : }
     329                 : 
     330                 : float
     331               0 : nsSVGUtils::GetFontXHeight(nsStyleContext *aStyleContext)
     332                 : {
     333               0 :   NS_ABORT_IF_FALSE(aStyleContext, "NULL style context in GetFontXHeight");
     334                 : 
     335               0 :   nsPresContext *presContext = aStyleContext->PresContext();
     336               0 :   NS_ABORT_IF_FALSE(presContext, "NULL pres context in GetFontXHeight");
     337                 : 
     338               0 :   nsRefPtr<nsFontMetrics> fontMetrics;
     339                 :   nsLayoutUtils::GetFontMetricsForStyleContext(aStyleContext,
     340               0 :                                                getter_AddRefs(fontMetrics));
     341                 : 
     342               0 :   if (!fontMetrics) {
     343                 :     // ReportToConsole
     344               0 :     NS_WARNING("no FontMetrics in GetFontXHeight()");
     345               0 :     return 1.0f;
     346                 :   }
     347                 : 
     348               0 :   nscoord xHeight = fontMetrics->XHeight();
     349               0 :   return nsPresContext::AppUnitsToFloatCSSPixels(xHeight) /
     350               0 :          presContext->TextZoom();
     351                 : }
     352                 : 
     353                 : void
     354               0 : nsSVGUtils::UnPremultiplyImageDataAlpha(PRUint8 *data, 
     355                 :                                         PRInt32 stride,
     356                 :                                         const nsIntRect &rect)
     357                 : {
     358               0 :   for (PRInt32 y = rect.y; y < rect.YMost(); y++) {
     359               0 :     for (PRInt32 x = rect.x; x < rect.XMost(); x++) {
     360               0 :       PRUint8 *pixel = data + stride * y + 4 * x;
     361                 : 
     362               0 :       PRUint8 a = pixel[GFX_ARGB32_OFFSET_A];
     363               0 :       if (a == 255)
     364               0 :         continue;
     365                 : 
     366               0 :       if (a) {
     367               0 :         pixel[GFX_ARGB32_OFFSET_B] = (255 * pixel[GFX_ARGB32_OFFSET_B]) / a;
     368               0 :         pixel[GFX_ARGB32_OFFSET_G] = (255 * pixel[GFX_ARGB32_OFFSET_G]) / a;
     369               0 :         pixel[GFX_ARGB32_OFFSET_R] = (255 * pixel[GFX_ARGB32_OFFSET_R]) / a;
     370                 :       } else {
     371               0 :         pixel[GFX_ARGB32_OFFSET_B] = 0;
     372               0 :         pixel[GFX_ARGB32_OFFSET_G] = 0;
     373               0 :         pixel[GFX_ARGB32_OFFSET_R] = 0;
     374                 :       }
     375                 :     }
     376                 :   }
     377               0 : }
     378                 : 
     379                 : void
     380               0 : nsSVGUtils::PremultiplyImageDataAlpha(PRUint8 *data, 
     381                 :                                       PRInt32 stride,
     382                 :                                       const nsIntRect &rect)
     383                 : {
     384               0 :   for (PRInt32 y = rect.y; y < rect.YMost(); y++) {
     385               0 :     for (PRInt32 x = rect.x; x < rect.XMost(); x++) {
     386               0 :       PRUint8 *pixel = data + stride * y + 4 * x;
     387                 : 
     388               0 :       PRUint8 a = pixel[GFX_ARGB32_OFFSET_A];
     389               0 :       if (a == 255)
     390               0 :         continue;
     391                 : 
     392               0 :       FAST_DIVIDE_BY_255(pixel[GFX_ARGB32_OFFSET_B],
     393                 :                          pixel[GFX_ARGB32_OFFSET_B] * a);
     394               0 :       FAST_DIVIDE_BY_255(pixel[GFX_ARGB32_OFFSET_G],
     395                 :                          pixel[GFX_ARGB32_OFFSET_G] * a);
     396               0 :       FAST_DIVIDE_BY_255(pixel[GFX_ARGB32_OFFSET_R],
     397                 :                          pixel[GFX_ARGB32_OFFSET_R] * a);
     398                 :     }
     399                 :   }
     400               0 : }
     401                 : 
     402                 : void
     403               0 : nsSVGUtils::ConvertImageDataToLinearRGB(PRUint8 *data, 
     404                 :                                         PRInt32 stride,
     405                 :                                         const nsIntRect &rect)
     406                 : {
     407               0 :   for (PRInt32 y = rect.y; y < rect.YMost(); y++) {
     408               0 :     for (PRInt32 x = rect.x; x < rect.XMost(); x++) {
     409               0 :       PRUint8 *pixel = data + stride * y + 4 * x;
     410                 : 
     411                 :       pixel[GFX_ARGB32_OFFSET_B] =
     412               0 :         gsRGBToLinearRGBMap[pixel[GFX_ARGB32_OFFSET_B]];
     413               0 :       pixel[GFX_ARGB32_OFFSET_G] =
     414               0 :         gsRGBToLinearRGBMap[pixel[GFX_ARGB32_OFFSET_G]];
     415               0 :       pixel[GFX_ARGB32_OFFSET_R] =
     416               0 :         gsRGBToLinearRGBMap[pixel[GFX_ARGB32_OFFSET_R]];
     417                 :     }
     418                 :   }
     419               0 : }
     420                 : 
     421                 : void
     422               0 : nsSVGUtils::ConvertImageDataFromLinearRGB(PRUint8 *data, 
     423                 :                                           PRInt32 stride,
     424                 :                                           const nsIntRect &rect)
     425                 : {
     426               0 :   for (PRInt32 y = rect.y; y < rect.YMost(); y++) {
     427               0 :     for (PRInt32 x = rect.x; x < rect.XMost(); x++) {
     428               0 :       PRUint8 *pixel = data + stride * y + 4 * x;
     429                 : 
     430                 :       pixel[GFX_ARGB32_OFFSET_B] =
     431               0 :         glinearRGBTosRGBMap[pixel[GFX_ARGB32_OFFSET_B]];
     432               0 :       pixel[GFX_ARGB32_OFFSET_G] =
     433               0 :         glinearRGBTosRGBMap[pixel[GFX_ARGB32_OFFSET_G]];
     434               0 :       pixel[GFX_ARGB32_OFFSET_R] =
     435               0 :         glinearRGBTosRGBMap[pixel[GFX_ARGB32_OFFSET_R]];
     436                 :     }
     437                 :   }
     438               0 : }
     439                 : 
     440                 : nsresult
     441               0 : nsSVGUtils::ReportToConsole(nsIDocument* doc,
     442                 :                             const char* aWarning,
     443                 :                             const PRUnichar **aParams,
     444                 :                             PRUint32 aParamsLength)
     445                 : {
     446                 :   return nsContentUtils::ReportToConsole(nsIScriptError::warningFlag,
     447                 :                                          "SVG", doc,
     448                 :                                          nsContentUtils::eSVG_PROPERTIES,
     449                 :                                          aWarning,
     450               0 :                                          aParams, aParamsLength);
     451                 : }
     452                 : 
     453                 : float
     454               0 : nsSVGUtils::CoordToFloat(nsPresContext *aPresContext,
     455                 :                          nsSVGElement *aContent,
     456                 :                          const nsStyleCoord &aCoord)
     457                 : {
     458               0 :   switch (aCoord.GetUnit()) {
     459                 :   case eStyleUnit_Factor:
     460                 :     // user units
     461               0 :     return aCoord.GetFactorValue();
     462                 : 
     463                 :   case eStyleUnit_Coord:
     464               0 :     return nsPresContext::AppUnitsToFloatCSSPixels(aCoord.GetCoordValue());
     465                 : 
     466                 :   case eStyleUnit_Percent: {
     467               0 :       nsSVGSVGElement* ctx = aContent->GetCtx();
     468               0 :       return ctx ? aCoord.GetPercentValue() * ctx->GetLength(nsSVGUtils::XY) : 0.0f;
     469                 :     }
     470                 :   default:
     471               0 :     return 0.0f;
     472                 :   }
     473                 : }
     474                 : 
     475                 : bool
     476               0 : nsSVGUtils::EstablishesViewport(nsIContent *aContent)
     477                 : {
     478                 :   // Although SVG 1.1 states that <image> is an element that establishes a
     479                 :   // viewport, this is really only for the document it references, not
     480                 :   // for any child content, which is what this function is used for.
     481               0 :   return aContent && aContent->IsSVG() &&
     482               0 :            (aContent->Tag() == nsGkAtoms::svg ||
     483               0 :             aContent->Tag() == nsGkAtoms::foreignObject ||
     484               0 :             aContent->Tag() == nsGkAtoms::symbol);
     485                 : }
     486                 : 
     487                 : already_AddRefed<nsIDOMSVGElement>
     488               0 : nsSVGUtils::GetNearestViewportElement(nsIContent *aContent)
     489                 : {
     490               0 :   nsIContent *element = aContent->GetFlattenedTreeParent();
     491                 : 
     492               0 :   while (element && element->IsSVG()) {
     493               0 :     if (EstablishesViewport(element)) {
     494               0 :       if (element->Tag() == nsGkAtoms::foreignObject) {
     495               0 :         return nsnull;
     496                 :       }
     497               0 :       return nsCOMPtr<nsIDOMSVGElement>(do_QueryInterface(element)).forget();
     498                 :     }
     499               0 :     element = element->GetFlattenedTreeParent();
     500                 :   }
     501               0 :   return nsnull;
     502                 : }
     503                 : 
     504                 : static gfxMatrix
     505               0 : GetCTMInternal(nsSVGElement *aElement, bool aScreenCTM, bool aHaveRecursed)
     506                 : {
     507               0 :   nsIDocument* currentDoc = aElement->GetCurrentDoc();
     508                 : 
     509                 :   gfxMatrix matrix = aElement->PrependLocalTransformsTo(gfxMatrix(),
     510               0 :     aHaveRecursed ? nsSVGElement::eAllTransforms : nsSVGElement::eUserSpaceToParent);
     511               0 :   nsSVGElement *element = aElement;
     512               0 :   nsIContent *ancestor = aElement->GetFlattenedTreeParent();
     513                 : 
     514               0 :   while (ancestor && ancestor->IsSVG() &&
     515               0 :                      ancestor->Tag() != nsGkAtoms::foreignObject) {
     516               0 :     element = static_cast<nsSVGElement*>(ancestor);
     517               0 :     matrix *= element->PrependLocalTransformsTo(gfxMatrix()); // i.e. *A*ppend
     518               0 :     if (!aScreenCTM && nsSVGUtils::EstablishesViewport(element)) {
     519               0 :       if (!element->NodeInfo()->Equals(nsGkAtoms::svg, kNameSpaceID_SVG) &&
     520               0 :           !element->NodeInfo()->Equals(nsGkAtoms::symbol, kNameSpaceID_SVG)) {
     521               0 :         NS_ERROR("New (SVG > 1.1) SVG viewport establishing element?");
     522               0 :         return gfxMatrix(0.0, 0.0, 0.0, 0.0, 0.0, 0.0); // singular
     523                 :       }
     524                 :       // XXX spec seems to say x,y translation should be undone for IsInnerSVG
     525               0 :       return matrix;
     526                 :     }
     527               0 :     ancestor = ancestor->GetFlattenedTreeParent();
     528                 :   }
     529               0 :   if (!aScreenCTM) {
     530                 :     // didn't find a nearestViewportElement
     531               0 :     return gfxMatrix(0.0, 0.0, 0.0, 0.0, 0.0, 0.0); // singular
     532                 :   }
     533               0 :   if (!ancestor || !ancestor->IsElement()) {
     534               0 :     return matrix;
     535                 :   }
     536               0 :   if (ancestor->IsSVG()) {
     537               0 :     if (element->Tag() != nsGkAtoms::svg) {
     538               0 :       return gfxMatrix(0.0, 0.0, 0.0, 0.0, 0.0, 0.0); // singular
     539                 :     }
     540                 :     return
     541               0 :       matrix * GetCTMInternal(static_cast<nsSVGElement*>(ancestor), true, true);
     542                 :   }
     543                 :   // XXX this does not take into account CSS transform, or that the non-SVG
     544                 :   // content that we've hit may itself be inside an SVG foreignObject higher up
     545               0 :   float x = 0.0f, y = 0.0f;
     546               0 :   if (currentDoc && element->NodeInfo()->Equals(nsGkAtoms::svg, kNameSpaceID_SVG)) {
     547               0 :     nsIPresShell *presShell = currentDoc->GetShell();
     548               0 :     if (presShell) {
     549               0 :       nsIFrame* frame = element->GetPrimaryFrame();
     550               0 :       nsIFrame* ancestorFrame = presShell->GetRootFrame();
     551               0 :       if (frame && ancestorFrame) {
     552               0 :         nsPoint point = frame->GetOffsetTo(ancestorFrame);
     553               0 :         x = nsPresContext::AppUnitsToFloatCSSPixels(point.x);
     554               0 :         y = nsPresContext::AppUnitsToFloatCSSPixels(point.y);
     555                 :       }
     556                 :     }
     557                 :   }
     558               0 :   return matrix * gfxMatrix().Translate(gfxPoint(x, y));
     559                 : }
     560                 : 
     561                 : gfxMatrix
     562               0 : nsSVGUtils::GetCTM(nsSVGElement *aElement, bool aScreenCTM)
     563                 : {
     564               0 :   nsIDocument* currentDoc = aElement->GetCurrentDoc();
     565               0 :   if (currentDoc) {
     566                 :     // Flush all pending notifications so that our frames are up to date
     567               0 :     currentDoc->FlushPendingNotifications(Flush_Layout);
     568                 :   }
     569               0 :   return GetCTMInternal(aElement, aScreenCTM, false);
     570                 : }
     571                 : 
     572                 : nsSVGDisplayContainerFrame*
     573               0 : nsSVGUtils::GetNearestSVGViewport(nsIFrame *aFrame)
     574                 : {
     575               0 :   NS_ASSERTION(aFrame->IsFrameOfType(nsIFrame::eSVG), "SVG frame expected");
     576               0 :   if (aFrame->GetType() == nsGkAtoms::svgOuterSVGFrame) {
     577               0 :     return nsnull;
     578                 :   }
     579               0 :   while ((aFrame = aFrame->GetParent())) {
     580               0 :     NS_ASSERTION(aFrame->IsFrameOfType(nsIFrame::eSVG), "SVG frame expected");
     581               0 :     if (aFrame->GetType() == nsGkAtoms::svgInnerSVGFrame ||
     582               0 :         aFrame->GetType() == nsGkAtoms::svgOuterSVGFrame) {
     583               0 :       return do_QueryFrame(aFrame);
     584                 :     }
     585                 :   }
     586               0 :   NS_NOTREACHED("This is not reached. It's only needed to compile.");
     587               0 :   return nsnull;
     588                 : }
     589                 : 
     590                 : nsRect
     591               0 : nsSVGUtils::FindFilterInvalidation(nsIFrame *aFrame, const nsRect& aRect)
     592                 : {
     593               0 :   PRInt32 appUnitsPerDevPixel = aFrame->PresContext()->AppUnitsPerDevPixel();
     594               0 :   nsIntRect rect = aRect.ToOutsidePixels(appUnitsPerDevPixel);
     595                 : 
     596               0 :   while (aFrame) {
     597               0 :     if (aFrame->GetStateBits() & NS_STATE_IS_OUTER_SVG)
     598               0 :       break;
     599                 : 
     600               0 :     nsSVGFilterFrame *filter = nsSVGEffects::GetFilterFrame(aFrame);
     601               0 :     if (filter) {
     602                 :       // When we are under AttributeChanged, we can no longer get the old bbox
     603                 :       // by calling GetBBox(), and we need that to set up the filter region
     604                 :       // with the correct position. :-(
     605                 :       //rect = filter->GetInvalidationBBox(aFrame, rect);
     606                 : 
     607                 :       // XXX [perf] As a horrible workaround, for now we just invalidate the
     608                 :       // entire area of the nearest viewport establishing frame that doesnt
     609                 :       // have overflow:visible. See bug 463939.
     610               0 :       nsSVGDisplayContainerFrame* viewportFrame = GetNearestSVGViewport(aFrame);
     611               0 :       while (viewportFrame && !viewportFrame->GetStyleDisplay()->IsScrollableOverflow()) {
     612               0 :         viewportFrame = GetNearestSVGViewport(viewportFrame);
     613                 :       }
     614               0 :       if (!viewportFrame) {
     615               0 :         viewportFrame = GetOuterSVGFrame(aFrame);
     616                 :       }
     617               0 :       if (viewportFrame->GetType() == nsGkAtoms::svgOuterSVGFrame) {
     618               0 :         nsRect r = viewportFrame->GetVisualOverflowRect();
     619                 :         // GetOverflowRect is relative to our border box, but we need it
     620                 :         // relative to our content box.
     621               0 :         r.MoveBy(viewportFrame->GetPosition() - viewportFrame->GetContentRect().TopLeft());
     622               0 :         return r;
     623                 :       }
     624               0 :       NS_ASSERTION(viewportFrame->GetType() == nsGkAtoms::svgInnerSVGFrame,
     625                 :                    "Wrong frame type");
     626               0 :       nsSVGInnerSVGFrame* innerSvg = do_QueryFrame(static_cast<nsIFrame*>(viewportFrame));
     627               0 :       nsSVGDisplayContainerFrame* innerSvgParent = do_QueryFrame(viewportFrame->GetParent());
     628                 :       float x, y, width, height;
     629               0 :       static_cast<nsSVGSVGElement*>(innerSvg->GetContent())->
     630               0 :         GetAnimatedLengthValues(&x, &y, &width, &height, nsnull);
     631               0 :       gfxRect bounds = GetCanvasTM(innerSvgParent).
     632               0 :                          TransformBounds(gfxRect(x, y, width, height));
     633               0 :       bounds.RoundOut();
     634               0 :       nsIntRect r;
     635               0 :       if (gfxUtils::GfxRectToIntRect(bounds, &r)) {
     636               0 :         rect = r;
     637                 :       } else {
     638               0 :         NS_NOTREACHED("Not going to invalidate the correct area");
     639                 :       }
     640               0 :       aFrame = viewportFrame;
     641                 :     }
     642               0 :     aFrame = aFrame->GetParent();
     643                 :   }
     644                 : 
     645               0 :   nsRect r = rect.ToAppUnits(appUnitsPerDevPixel);
     646               0 :   if (aFrame) {
     647               0 :     NS_ASSERTION(aFrame->GetStateBits() & NS_STATE_IS_OUTER_SVG,
     648                 :                  "outer SVG frame expected");
     649               0 :     r.MoveBy(aFrame->GetContentRect().TopLeft() - aFrame->GetPosition());
     650                 :   }
     651               0 :   return r;
     652                 : }
     653                 : 
     654                 : void
     655               0 : nsSVGUtils::InvalidateCoveredRegion(nsIFrame *aFrame)
     656                 : {
     657               0 :   if (aFrame->GetStateBits() & NS_STATE_SVG_NONDISPLAY_CHILD)
     658               0 :     return;
     659                 : 
     660               0 :   if (aFrame->GetStateBits() & NS_STATE_SVG_REDRAW_SUSPENDED) {
     661               0 :     aFrame->AddStateBits(NS_STATE_SVG_DIRTY);
     662               0 :     return;
     663                 :   }
     664                 : 
     665               0 :   aFrame->RemoveStateBits(NS_STATE_SVG_DIRTY);
     666                 : 
     667               0 :   nsSVGOuterSVGFrame* outerSVGFrame = GetOuterSVGFrame(aFrame);
     668               0 :   NS_ASSERTION(outerSVGFrame, "no outer svg frame");
     669               0 :   if (outerSVGFrame) {
     670               0 :     nsISVGChildFrame *svgFrame = do_QueryFrame(aFrame);
     671               0 :     if (!svgFrame)
     672               0 :       return;
     673                 : 
     674                 :     // Make sure elements styled by :hover get updated if script/animation moves
     675                 :     // them under or out from under the pointer:
     676               0 :     aFrame->PresContext()->PresShell()->SynthesizeMouseMove(false);
     677                 : 
     678               0 :     nsRect rect = FindFilterInvalidation(aFrame, svgFrame->GetCoveredRegion());
     679               0 :     outerSVGFrame->Invalidate(rect);
     680                 :   }
     681                 : }
     682                 : 
     683                 : void
     684               0 : nsSVGUtils::UpdateGraphic(nsIFrame *aFrame)
     685                 : {
     686               0 :   nsSVGEffects::InvalidateRenderingObservers(aFrame);
     687                 : 
     688               0 :   if (aFrame->GetStateBits() & NS_STATE_SVG_NONDISPLAY_CHILD)
     689               0 :     return;
     690                 : 
     691               0 :   if (aFrame->GetStateBits() & NS_STATE_SVG_REDRAW_SUSPENDED) {
     692               0 :     aFrame->AddStateBits(NS_STATE_SVG_DIRTY);
     693               0 :     return;
     694                 :   }
     695                 : 
     696               0 :   aFrame->RemoveStateBits(NS_STATE_SVG_DIRTY);
     697                 : 
     698               0 :   nsISVGChildFrame *svgFrame = do_QueryFrame(aFrame);
     699               0 :   if (!svgFrame)
     700               0 :     return;
     701                 : 
     702               0 :   nsSVGOuterSVGFrame *outerSVGFrame = GetOuterSVGFrame(aFrame);
     703               0 :   if (!outerSVGFrame) {
     704               0 :     NS_ERROR("null outerSVGFrame");
     705               0 :     return;
     706                 :   }
     707                 : 
     708                 :   // Make sure elements styled by :hover get updated if script/animation moves
     709                 :   // them under or out from under the pointer:
     710               0 :   aFrame->PresContext()->PresShell()->SynthesizeMouseMove(false);
     711                 : 
     712               0 :   nsRect oldRegion = svgFrame->GetCoveredRegion();
     713               0 :   outerSVGFrame->Invalidate(FindFilterInvalidation(aFrame, oldRegion));
     714               0 :   svgFrame->UpdateCoveredRegion();
     715               0 :   nsRect newRegion = svgFrame->GetCoveredRegion();
     716               0 :   if (oldRegion.IsEqualInterior(newRegion))
     717                 :     return;
     718                 : 
     719               0 :   outerSVGFrame->Invalidate(FindFilterInvalidation(aFrame, newRegion));
     720               0 :   if (!(aFrame->GetStateBits() & NS_STATE_IS_OUTER_SVG)) {
     721               0 :     NotifyAncestorsOfFilterRegionChange(aFrame);
     722                 :   }
     723                 : }
     724                 : 
     725                 : void
     726               0 : nsSVGUtils::NotifyAncestorsOfFilterRegionChange(nsIFrame *aFrame)
     727                 : {
     728               0 :   NS_ABORT_IF_FALSE(!(aFrame->GetStateBits() & NS_STATE_IS_OUTER_SVG),
     729                 :                     "Not expecting to be called on the outer SVG Frame");
     730                 : 
     731               0 :   aFrame = aFrame->GetParent();
     732                 : 
     733               0 :   while (aFrame) {
     734               0 :     if (aFrame->GetStateBits() & NS_STATE_IS_OUTER_SVG)
     735               0 :       return;
     736                 : 
     737               0 :     nsSVGFilterProperty *property = nsSVGEffects::GetFilterProperty(aFrame);
     738               0 :     if (property) {
     739               0 :       property->Invalidate();
     740                 :     }
     741               0 :     aFrame = aFrame->GetParent();
     742                 :   }
     743                 : }
     744                 : 
     745                 : double
     746               0 : nsSVGUtils::ComputeNormalizedHypotenuse(double aWidth, double aHeight)
     747                 : {
     748               0 :   return sqrt((aWidth*aWidth + aHeight*aHeight)/2);
     749                 : }
     750                 : 
     751                 : float
     752               0 : nsSVGUtils::ObjectSpace(const gfxRect &aRect, const nsSVGLength2 *aLength)
     753                 : {
     754                 :   float fraction, axis;
     755                 : 
     756               0 :   switch (aLength->GetCtxType()) {
     757                 :   case X:
     758               0 :     axis = aRect.Width();
     759               0 :     break;
     760                 :   case Y:
     761               0 :     axis = aRect.Height();
     762               0 :     break;
     763                 :   case XY:
     764               0 :     axis = float(ComputeNormalizedHypotenuse(aRect.Width(), aRect.Height()));
     765               0 :     break;
     766                 :   default:
     767               0 :     NS_NOTREACHED("unexpected ctx type");
     768               0 :     axis = 0.0f;
     769               0 :     break;
     770                 :   }
     771                 : 
     772               0 :   if (aLength->IsPercentage()) {
     773               0 :     fraction = aLength->GetAnimValInSpecifiedUnits() / 100;
     774                 :   } else {
     775                 :     fraction = aLength->GetAnimValue(static_cast<nsSVGSVGElement*>
     776               0 :                                                 (nsnull));
     777                 :   }
     778                 : 
     779               0 :   return fraction * axis;
     780                 : }
     781                 : 
     782                 : float
     783               0 : nsSVGUtils::UserSpace(nsSVGElement *aSVGElement, const nsSVGLength2 *aLength)
     784                 : {
     785               0 :   return aLength->GetAnimValue(aSVGElement);
     786                 : }
     787                 : 
     788                 : float
     789               0 : nsSVGUtils::UserSpace(nsIFrame *aNonSVGContext, const nsSVGLength2 *aLength)
     790                 : {
     791               0 :   return aLength->GetAnimValue(aNonSVGContext);
     792                 : }
     793                 : 
     794                 : float
     795               0 : nsSVGUtils::AngleBisect(float a1, float a2)
     796                 : {
     797               0 :   float delta = fmod(a2 - a1, static_cast<float>(2*M_PI));
     798               0 :   if (delta < 0) {
     799               0 :     delta += 2*M_PI;
     800                 :   }
     801                 :   /* delta is now the angle from a1 around to a2, in the range [0, 2*M_PI) */
     802               0 :   float r = a1 + delta/2;
     803               0 :   if (delta >= M_PI) {
     804                 :     /* the arc from a2 to a1 is smaller, so use the ray on that side */
     805               0 :     r += M_PI;
     806                 :   }
     807               0 :   return r;
     808                 : }
     809                 : 
     810                 : nsSVGOuterSVGFrame *
     811               0 : nsSVGUtils::GetOuterSVGFrame(nsIFrame *aFrame)
     812                 : {
     813               0 :   while (aFrame) {
     814               0 :     if (aFrame->GetStateBits() & NS_STATE_IS_OUTER_SVG) {
     815               0 :       return static_cast<nsSVGOuterSVGFrame*>(aFrame);
     816                 :     }
     817               0 :     aFrame = aFrame->GetParent();
     818                 :   }
     819                 : 
     820               0 :   return nsnull;
     821                 : }
     822                 : 
     823                 : nsIFrame*
     824               0 : nsSVGUtils::GetOuterSVGFrameAndCoveredRegion(nsIFrame* aFrame, nsRect* aRect)
     825                 : {
     826               0 :   nsISVGChildFrame* svg = do_QueryFrame(aFrame);
     827               0 :   if (!svg)
     828               0 :     return nsnull;
     829               0 :   *aRect = (aFrame->GetStateBits() & NS_STATE_SVG_NONDISPLAY_CHILD) ?
     830               0 :              nsRect(0, 0, 0, 0) : svg->GetCoveredRegion();
     831               0 :   return GetOuterSVGFrame(aFrame);
     832                 : }
     833                 : 
     834                 : gfxMatrix
     835               0 : nsSVGUtils::GetViewBoxTransform(const nsSVGElement* aElement,
     836                 :                                 float aViewportWidth, float aViewportHeight,
     837                 :                                 float aViewboxX, float aViewboxY,
     838                 :                                 float aViewboxWidth, float aViewboxHeight,
     839                 :                                 const SVGAnimatedPreserveAspectRatio &aPreserveAspectRatio)
     840                 : {
     841                 :   return GetViewBoxTransform(aElement,
     842                 :                              aViewportWidth, aViewportHeight,
     843                 :                              aViewboxX, aViewboxY,
     844                 :                              aViewboxWidth, aViewboxHeight,
     845               0 :                              aPreserveAspectRatio.GetAnimValue());
     846                 : }
     847                 : 
     848                 : gfxMatrix
     849               0 : nsSVGUtils::GetViewBoxTransform(const nsSVGElement* aElement,
     850                 :                                 float aViewportWidth, float aViewportHeight,
     851                 :                                 float aViewboxX, float aViewboxY,
     852                 :                                 float aViewboxWidth, float aViewboxHeight,
     853                 :                                 const SVGPreserveAspectRatio &aPreserveAspectRatio)
     854                 : {
     855               0 :   NS_ASSERTION(aViewportWidth  >= 0, "viewport width must be nonnegative!");
     856               0 :   NS_ASSERTION(aViewportHeight >= 0, "viewport height must be nonnegative!");
     857               0 :   NS_ASSERTION(aViewboxWidth  > 0, "viewBox width must be greater than zero!");
     858               0 :   NS_ASSERTION(aViewboxHeight > 0, "viewBox height must be greater than zero!");
     859                 : 
     860               0 :   PRUint16 align = aPreserveAspectRatio.GetAlign();
     861               0 :   PRUint16 meetOrSlice = aPreserveAspectRatio.GetMeetOrSlice();
     862                 : 
     863                 :   // default to the defaults
     864               0 :   if (align == nsIDOMSVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_UNKNOWN)
     865               0 :     align = nsIDOMSVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_XMIDYMID;
     866               0 :   if (meetOrSlice == nsIDOMSVGPreserveAspectRatio::SVG_MEETORSLICE_UNKNOWN)
     867               0 :     meetOrSlice = nsIDOMSVGPreserveAspectRatio::SVG_MEETORSLICE_MEET;
     868                 : 
     869                 :   float a, d, e, f;
     870               0 :   a = aViewportWidth / aViewboxWidth;
     871               0 :   d = aViewportHeight / aViewboxHeight;
     872               0 :   e = 0.0f;
     873               0 :   f = 0.0f;
     874                 : 
     875               0 :   if (align != nsIDOMSVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_NONE &&
     876                 :       a != d) {
     877               0 :     if ((meetOrSlice == nsIDOMSVGPreserveAspectRatio::SVG_MEETORSLICE_MEET &&
     878                 :         a < d) ||
     879                 :         (meetOrSlice == nsIDOMSVGPreserveAspectRatio::SVG_MEETORSLICE_SLICE &&
     880                 :         d < a)) {
     881               0 :       d = a;
     882               0 :       switch (align) {
     883                 :       case nsIDOMSVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_XMINYMIN:
     884                 :       case nsIDOMSVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_XMIDYMIN:
     885                 :       case nsIDOMSVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_XMAXYMIN:
     886               0 :         break;
     887                 :       case nsIDOMSVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_XMINYMID:
     888                 :       case nsIDOMSVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_XMIDYMID:
     889                 :       case nsIDOMSVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_XMAXYMID:
     890               0 :         f = (aViewportHeight - a * aViewboxHeight) / 2.0f;
     891               0 :         break;
     892                 :       case nsIDOMSVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_XMINYMAX:
     893                 :       case nsIDOMSVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_XMIDYMAX:
     894                 :       case nsIDOMSVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_XMAXYMAX:
     895               0 :         f = aViewportHeight - a * aViewboxHeight;
     896               0 :         break;
     897                 :       default:
     898               0 :         NS_NOTREACHED("Unknown value for align");
     899                 :       }
     900                 :     }
     901               0 :     else if (
     902                 :       (meetOrSlice == nsIDOMSVGPreserveAspectRatio::SVG_MEETORSLICE_MEET &&
     903                 :       d < a) ||
     904                 :       (meetOrSlice == nsIDOMSVGPreserveAspectRatio::SVG_MEETORSLICE_SLICE &&
     905                 :       a < d)) {
     906               0 :       a = d;
     907               0 :       switch (align) {
     908                 :       case nsIDOMSVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_XMINYMIN:
     909                 :       case nsIDOMSVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_XMINYMID:
     910                 :       case nsIDOMSVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_XMINYMAX:
     911               0 :         break;
     912                 :       case nsIDOMSVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_XMIDYMIN:
     913                 :       case nsIDOMSVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_XMIDYMID:
     914                 :       case nsIDOMSVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_XMIDYMAX:
     915               0 :         e = (aViewportWidth - a * aViewboxWidth) / 2.0f;
     916               0 :         break;
     917                 :       case nsIDOMSVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_XMAXYMIN:
     918                 :       case nsIDOMSVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_XMAXYMID:
     919                 :       case nsIDOMSVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_XMAXYMAX:
     920               0 :         e = aViewportWidth - a * aViewboxWidth;
     921               0 :         break;
     922                 :       default:
     923               0 :         NS_NOTREACHED("Unknown value for align");
     924                 :       }
     925                 :     }
     926               0 :     else NS_NOTREACHED("Unknown value for meetOrSlice");
     927                 :   }
     928                 :   
     929               0 :   if (aViewboxX) e += -a * aViewboxX;
     930               0 :   if (aViewboxY) f += -d * aViewboxY;
     931                 :   
     932               0 :   return gfxMatrix(a, 0.0f, 0.0f, d, e, f);
     933                 : }
     934                 : 
     935                 : gfxMatrix
     936               0 : nsSVGUtils::GetCanvasTM(nsIFrame *aFrame)
     937                 : {
     938                 :   // XXX yuck, we really need a common interface for GetCanvasTM
     939                 : 
     940               0 :   if (!aFrame->IsFrameOfType(nsIFrame::eSVG)) {
     941               0 :     return nsSVGIntegrationUtils::GetInitialMatrix(aFrame);
     942                 :   }
     943                 : 
     944               0 :   nsIAtom* type = aFrame->GetType();
     945               0 :   if (type == nsGkAtoms::svgForeignObjectFrame) {
     946               0 :     return static_cast<nsSVGForeignObjectFrame*>(aFrame)->GetCanvasTM();
     947                 :   }
     948                 : 
     949               0 :   nsSVGContainerFrame *containerFrame = do_QueryFrame(aFrame);
     950               0 :   if (containerFrame) {
     951               0 :     return containerFrame->GetCanvasTM();
     952                 :   }
     953                 : 
     954               0 :   return static_cast<nsSVGGeometryFrame*>(aFrame)->GetCanvasTM();
     955                 : }
     956                 : 
     957                 : void 
     958               0 : nsSVGUtils::NotifyChildrenOfSVGChange(nsIFrame *aFrame, PRUint32 aFlags)
     959                 : {
     960               0 :   nsIFrame *kid = aFrame->GetFirstPrincipalChild();
     961                 : 
     962               0 :   while (kid) {
     963               0 :     nsISVGChildFrame* SVGFrame = do_QueryFrame(kid);
     964               0 :     if (SVGFrame) {
     965               0 :       SVGFrame->NotifySVGChanged(aFlags); 
     966                 :     } else {
     967               0 :       NS_ASSERTION(kid->IsFrameOfType(nsIFrame::eSVG), "SVG frame expected");
     968                 :       // recurse into the children of container frames e.g. <clipPath>, <mask>
     969                 :       // in case they have child frames with transformation matrices
     970               0 :       NotifyChildrenOfSVGChange(kid, aFlags);
     971                 :     }
     972               0 :     kid = kid->GetNextSibling();
     973                 :   }
     974               0 : }
     975                 : 
     976                 : void
     977               0 : nsSVGUtils::NotifyRedrawSuspended(nsIFrame *aFrame)
     978                 : {
     979               0 :   aFrame->AddStateBits(NS_STATE_SVG_REDRAW_SUSPENDED);
     980                 : 
     981               0 :   nsIFrame *kid = aFrame->GetFirstPrincipalChild();
     982                 : 
     983               0 :   while (kid) {
     984               0 :     nsISVGChildFrame* SVGFrame = do_QueryFrame(kid);
     985               0 :     if (SVGFrame) {
     986               0 :       SVGFrame->NotifyRedrawSuspended();
     987                 :     }
     988               0 :     kid = kid->GetNextSibling();
     989                 :   }
     990               0 : }
     991                 : 
     992                 : void
     993               0 : nsSVGUtils::NotifyRedrawUnsuspended(nsIFrame *aFrame)
     994                 : {
     995               0 :   aFrame->RemoveStateBits(NS_STATE_SVG_REDRAW_SUSPENDED);
     996                 : 
     997               0 :   nsIFrame *kid = aFrame->GetFirstPrincipalChild();
     998                 : 
     999               0 :   while (kid) {
    1000               0 :     nsISVGChildFrame* SVGFrame = do_QueryFrame(kid);
    1001               0 :     if (SVGFrame) {
    1002               0 :       SVGFrame->NotifyRedrawUnsuspended();
    1003                 :     }
    1004               0 :     kid = kid->GetNextSibling();
    1005                 :   }
    1006               0 : }
    1007                 : 
    1008                 : // ************************************************************
    1009                 : 
    1010                 : class SVGPaintCallback : public nsSVGFilterPaintCallback
    1011               0 : {
    1012                 : public:
    1013               0 :   virtual void Paint(nsRenderingContext *aContext, nsIFrame *aTarget,
    1014                 :                      const nsIntRect* aDirtyRect)
    1015                 :   {
    1016               0 :     nsISVGChildFrame *svgChildFrame = do_QueryFrame(aTarget);
    1017               0 :     NS_ASSERTION(svgChildFrame, "Expected SVG frame here");
    1018                 : 
    1019               0 :     nsIntRect* dirtyRect = nsnull;
    1020               0 :     nsIntRect tmpDirtyRect;
    1021                 : 
    1022                 :     // aDirtyRect is in user-space pixels, we need to convert to
    1023                 :     // outer-SVG-frame-relative device pixels.
    1024               0 :     if (aDirtyRect) {
    1025               0 :       gfxMatrix userToDeviceSpace = nsSVGUtils::GetCanvasTM(aTarget);
    1026               0 :       if (userToDeviceSpace.IsSingular()) {
    1027               0 :         return;
    1028                 :       }
    1029                 :       gfxRect dirtyBounds = userToDeviceSpace.TransformBounds(
    1030               0 :         gfxRect(aDirtyRect->x, aDirtyRect->y, aDirtyRect->width, aDirtyRect->height));
    1031               0 :       dirtyBounds.RoundOut();
    1032               0 :       if (gfxUtils::GfxRectToIntRect(dirtyBounds, &tmpDirtyRect)) {
    1033               0 :         dirtyRect = &tmpDirtyRect;
    1034                 :       }
    1035                 :     }
    1036                 : 
    1037               0 :     svgChildFrame->PaintSVG(aContext, dirtyRect);
    1038                 :   }
    1039                 : };
    1040                 : 
    1041                 : void
    1042               0 : nsSVGUtils::PaintFrameWithEffects(nsRenderingContext *aContext,
    1043                 :                                   const nsIntRect *aDirtyRect,
    1044                 :                                   nsIFrame *aFrame)
    1045                 : {
    1046               0 :   nsISVGChildFrame *svgChildFrame = do_QueryFrame(aFrame);
    1047               0 :   if (!svgChildFrame)
    1048               0 :     return;
    1049                 : 
    1050               0 :   float opacity = aFrame->GetStyleDisplay()->mOpacity;
    1051               0 :   if (opacity == 0.0f)
    1052               0 :     return;
    1053                 : 
    1054               0 :   const nsIContent* content = aFrame->GetContent();
    1055               0 :   if (content->IsSVG() &&
    1056               0 :       !static_cast<const nsSVGElement*>(content)->HasValidDimensions()) {
    1057               0 :     return;
    1058                 :   }
    1059                 : 
    1060                 :   /* Properties are added lazily and may have been removed by a restyle,
    1061                 :      so make sure all applicable ones are set again. */
    1062                 : 
    1063                 :   nsSVGEffects::EffectProperties effectProperties =
    1064               0 :     nsSVGEffects::GetEffectProperties(aFrame);
    1065                 : 
    1066               0 :   bool isOK = true;
    1067               0 :   nsSVGFilterFrame *filterFrame = effectProperties.GetFilterFrame(&isOK);
    1068                 : 
    1069                 :   /* Check if we need to draw anything. HasValidCoveredRect only returns
    1070                 :    * true for path geometry and glyphs, so basically we're traversing
    1071                 :    * all containers and we can only skip leaves here.
    1072                 :    */
    1073               0 :   if (aDirtyRect && svgChildFrame->HasValidCoveredRect()) {
    1074               0 :     if (filterFrame) {
    1075               0 :       if (!aDirtyRect->Intersects(filterFrame->GetFilterBBox(aFrame, nsnull)))
    1076               0 :         return;
    1077                 :     } else {
    1078                 :       nsRect leafBounds = nsSVGUtils::TransformFrameRectToOuterSVG(
    1079               0 :         aFrame->GetRect(), GetCanvasTM(aFrame), aFrame->PresContext());
    1080               0 :       nsRect rect = aDirtyRect->ToAppUnits(aFrame->PresContext()->AppUnitsPerDevPixel());
    1081               0 :       if (!rect.Intersects(leafBounds))
    1082                 :         return;
    1083                 :     }
    1084                 :   }
    1085                 : 
    1086                 :   /* SVG defines the following rendering model:
    1087                 :    *
    1088                 :    *  1. Render fill
    1089                 :    *  2. Render stroke
    1090                 :    *  3. Render markers
    1091                 :    *  4. Apply filter
    1092                 :    *  5. Apply clipping, masking, group opacity
    1093                 :    *
    1094                 :    * We follow this, but perform a couple of optimizations:
    1095                 :    *
    1096                 :    * + Use cairo's clipPath when representable natively (single object
    1097                 :    *   clip region).
    1098                 :    *
    1099                 :    * + Merge opacity and masking if both used together.
    1100                 :    */
    1101                 : 
    1102               0 :   if (opacity != 1.0f && CanOptimizeOpacity(aFrame))
    1103               0 :     opacity = 1.0f;
    1104                 : 
    1105               0 :   gfxContext *gfx = aContext->ThebesContext();
    1106               0 :   bool complexEffects = false;
    1107                 : 
    1108               0 :   nsSVGClipPathFrame *clipPathFrame = effectProperties.GetClipPathFrame(&isOK);
    1109               0 :   nsSVGMaskFrame *maskFrame = effectProperties.GetMaskFrame(&isOK);
    1110                 : 
    1111               0 :   bool isTrivialClip = clipPathFrame ? clipPathFrame->IsTrivial() : true;
    1112                 : 
    1113               0 :   if (!isOK) {
    1114                 :     // Some resource is invalid. We shouldn't paint anything.
    1115               0 :     return;
    1116                 :   }
    1117                 :   
    1118               0 :   gfxMatrix matrix;
    1119               0 :   if (clipPathFrame || maskFrame)
    1120               0 :     matrix = GetCanvasTM(aFrame);
    1121                 : 
    1122                 :   /* Check if we need to do additional operations on this child's
    1123                 :    * rendering, which necessitates rendering into another surface. */
    1124               0 :   if (opacity != 1.0f || maskFrame || (clipPathFrame && !isTrivialClip)) {
    1125               0 :     complexEffects = true;
    1126               0 :     gfx->Save();
    1127               0 :     gfx->PushGroup(gfxASurface::CONTENT_COLOR_ALPHA);
    1128                 :   }
    1129                 : 
    1130                 :   /* If this frame has only a trivial clipPath, set up cairo's clipping now so
    1131                 :    * we can just do normal painting and get it clipped appropriately.
    1132                 :    */
    1133               0 :   if (clipPathFrame && isTrivialClip) {
    1134               0 :     gfx->Save();
    1135               0 :     clipPathFrame->ClipPaint(aContext, aFrame, matrix);
    1136                 :   }
    1137                 : 
    1138                 :   /* Paint the child */
    1139               0 :   if (filterFrame) {
    1140               0 :     SVGPaintCallback paintCallback;
    1141               0 :     filterFrame->FilterPaint(aContext, aFrame, &paintCallback, aDirtyRect);
    1142                 :   } else {
    1143               0 :     svgChildFrame->PaintSVG(aContext, aDirtyRect);
    1144                 :   }
    1145                 : 
    1146               0 :   if (clipPathFrame && isTrivialClip) {
    1147               0 :     gfx->Restore();
    1148                 :   }
    1149                 : 
    1150                 :   /* No more effects, we're done. */
    1151               0 :   if (!complexEffects)
    1152               0 :     return;
    1153                 : 
    1154               0 :   gfx->PopGroupToSource();
    1155                 : 
    1156                 :   nsRefPtr<gfxPattern> maskSurface =
    1157                 :     maskFrame ? maskFrame->ComputeMaskAlpha(aContext, aFrame,
    1158               0 :                                             matrix, opacity) : nsnull;
    1159                 : 
    1160               0 :   nsRefPtr<gfxPattern> clipMaskSurface;
    1161               0 :   if (clipPathFrame && !isTrivialClip) {
    1162               0 :     gfx->PushGroup(gfxASurface::CONTENT_COLOR_ALPHA);
    1163                 : 
    1164               0 :     nsresult rv = clipPathFrame->ClipPaint(aContext, aFrame, matrix);
    1165               0 :     clipMaskSurface = gfx->PopGroup();
    1166                 : 
    1167               0 :     if (NS_SUCCEEDED(rv) && clipMaskSurface) {
    1168                 :       // Still more set after clipping, so clip to another surface
    1169               0 :       if (maskSurface || opacity != 1.0f) {
    1170               0 :         gfx->PushGroup(gfxASurface::CONTENT_COLOR_ALPHA);
    1171               0 :         gfx->Mask(clipMaskSurface);
    1172               0 :         gfx->PopGroupToSource();
    1173                 :       } else {
    1174               0 :         gfx->Mask(clipMaskSurface);
    1175                 :       }
    1176                 :     }
    1177                 :   }
    1178                 : 
    1179               0 :   if (maskSurface) {
    1180               0 :     gfx->Mask(maskSurface);
    1181               0 :   } else if (opacity != 1.0f) {
    1182               0 :     gfx->Paint(opacity);
    1183                 :   }
    1184                 : 
    1185               0 :   gfx->Restore();
    1186                 : }
    1187                 : 
    1188                 : bool
    1189               0 : nsSVGUtils::HitTestClip(nsIFrame *aFrame, const nsPoint &aPoint)
    1190                 : {
    1191                 :   nsSVGEffects::EffectProperties props =
    1192               0 :     nsSVGEffects::GetEffectProperties(aFrame);
    1193               0 :   if (!props.mClipPath)
    1194               0 :     return true;
    1195                 : 
    1196               0 :   bool isOK = true;
    1197               0 :   nsSVGClipPathFrame *clipPathFrame = props.GetClipPathFrame(&isOK);
    1198               0 :   if (!clipPathFrame || !isOK) {
    1199                 :     // clipPath is not a valid resource, so nothing gets painted, so
    1200                 :     // hit-testing must fail.
    1201               0 :     return false;
    1202                 :   }
    1203                 : 
    1204               0 :   return clipPathFrame->ClipHitTest(aFrame, GetCanvasTM(aFrame), aPoint);
    1205                 : }
    1206                 : 
    1207                 : nsIFrame *
    1208               0 : nsSVGUtils::HitTestChildren(nsIFrame *aFrame, const nsPoint &aPoint)
    1209                 : {
    1210                 :   // Traverse the list in reverse order, so that if we get a hit we know that's
    1211                 :   // the topmost frame that intersects the point; then we can just return it.
    1212               0 :   nsIFrame* result = nsnull;
    1213               0 :   for (nsIFrame* current = aFrame->PrincipalChildList().LastChild();
    1214                 :        current;
    1215                 :        current = current->GetPrevSibling()) {
    1216               0 :     nsISVGChildFrame* SVGFrame = do_QueryFrame(current);
    1217               0 :     if (SVGFrame) {
    1218               0 :       const nsIContent* content = current->GetContent();
    1219               0 :       if (content->IsSVG() &&
    1220               0 :           !static_cast<const nsSVGElement*>(content)->HasValidDimensions()) {
    1221               0 :         continue;
    1222                 :       }
    1223               0 :       result = SVGFrame->GetFrameForPoint(aPoint);
    1224               0 :       if (result)
    1225               0 :         break;
    1226                 :     }
    1227                 :   }
    1228                 : 
    1229               0 :   if (result && !HitTestClip(aFrame, aPoint))
    1230               0 :     result = nsnull;
    1231                 : 
    1232               0 :   return result;
    1233                 : }
    1234                 : 
    1235                 : nsRect
    1236               0 : nsSVGUtils::GetCoveredRegion(const nsFrameList &aFrames)
    1237                 : {
    1238               0 :   nsRect rect;
    1239                 : 
    1240               0 :   for (nsIFrame* kid = aFrames.FirstChild();
    1241                 :        kid;
    1242                 :        kid = kid->GetNextSibling()) {
    1243               0 :     nsISVGChildFrame* child = do_QueryFrame(kid);
    1244               0 :     if (child) {
    1245               0 :       nsRect childRect = child->GetCoveredRegion();
    1246               0 :       rect.UnionRect(rect, childRect);
    1247                 :     }
    1248                 :   }
    1249                 : 
    1250                 :   return rect;
    1251                 : }
    1252                 : 
    1253                 : nsPoint
    1254               0 : nsSVGUtils::TransformOuterSVGPointToChildFrame(nsPoint aPoint,
    1255                 :                                                const gfxMatrix& aFrameToCanvasTM,
    1256                 :                                                nsPresContext* aPresContext)
    1257                 : {
    1258               0 :   NS_ABORT_IF_FALSE(!aFrameToCanvasTM.IsSingular(),
    1259                 :                     "Callers must not pass a singular matrix");
    1260               0 :   gfxMatrix canvasDevToFrameUserSpace = aFrameToCanvasTM;
    1261               0 :   canvasDevToFrameUserSpace.Invert();
    1262                 :   gfxPoint devPt = gfxPoint(aPoint.x, aPoint.y) /
    1263               0 :     aPresContext->AppUnitsPerDevPixel();
    1264               0 :   gfxPoint userPt = canvasDevToFrameUserSpace.Transform(devPt).Round();
    1265               0 :   gfxPoint appPt = userPt * aPresContext->AppUnitsPerCSSPixel();
    1266               0 :   userPt.x = clamped(appPt.x, gfxFloat(nscoord_MIN), gfxFloat(nscoord_MAX));
    1267               0 :   userPt.y = clamped(appPt.y, gfxFloat(nscoord_MIN), gfxFloat(nscoord_MAX));
    1268                 :   // now guaranteed to be safe:
    1269               0 :   return nsPoint(nscoord(userPt.x), nscoord(userPt.y));
    1270                 : }
    1271                 : 
    1272                 : nsRect
    1273               0 : nsSVGUtils::TransformFrameRectToOuterSVG(const nsRect& aRect,
    1274                 :                                          const gfxMatrix& aMatrix,
    1275                 :                                          nsPresContext* aPresContext)
    1276                 : {
    1277               0 :   gfxRect r(aRect.x, aRect.y, aRect.width, aRect.height);
    1278               0 :   r.Scale(1.0 / nsPresContext::AppUnitsPerCSSPixel());
    1279                 :   return nsLayoutUtils::RoundGfxRectToAppRect(
    1280               0 :     aMatrix.TransformBounds(r), aPresContext->AppUnitsPerDevPixel());
    1281                 : }
    1282                 : 
    1283                 : gfxIntSize
    1284               0 : nsSVGUtils::ConvertToSurfaceSize(const gfxSize& aSize,
    1285                 :                                  bool *aResultOverflows)
    1286                 : {
    1287               0 :   gfxIntSize surfaceSize(ClampToInt(ceil(aSize.width)), ClampToInt(ceil(aSize.height)));
    1288                 : 
    1289               0 :   *aResultOverflows = surfaceSize.width != ceil(aSize.width) ||
    1290               0 :     surfaceSize.height != ceil(aSize.height);
    1291                 : 
    1292               0 :   if (!gfxASurface::CheckSurfaceSize(surfaceSize)) {
    1293                 :     surfaceSize.width = NS_MIN(NS_SVG_OFFSCREEN_MAX_DIMENSION,
    1294               0 :                                surfaceSize.width);
    1295                 :     surfaceSize.height = NS_MIN(NS_SVG_OFFSCREEN_MAX_DIMENSION,
    1296               0 :                                 surfaceSize.height);
    1297               0 :     *aResultOverflows = true;
    1298                 :   }
    1299                 : 
    1300                 :   return surfaceSize;
    1301                 : }
    1302                 : 
    1303                 : bool
    1304               0 : nsSVGUtils::HitTestRect(const gfxMatrix &aMatrix,
    1305                 :                         float aRX, float aRY, float aRWidth, float aRHeight,
    1306                 :                         float aX, float aY)
    1307                 : {
    1308               0 :   if (aMatrix.IsSingular()) {
    1309               0 :     return false;
    1310                 :   }
    1311               0 :   gfxContext ctx(gfxPlatform::GetPlatform()->ScreenReferenceSurface());
    1312               0 :   ctx.SetMatrix(aMatrix);
    1313               0 :   ctx.NewPath();
    1314               0 :   ctx.Rectangle(gfxRect(aRX, aRY, aRWidth, aRHeight));
    1315               0 :   ctx.IdentityMatrix();
    1316               0 :   return ctx.PointInFill(gfxPoint(aX, aY));
    1317                 : }
    1318                 : 
    1319                 : gfxRect
    1320               0 : nsSVGUtils::GetClipRectForFrame(nsIFrame *aFrame,
    1321                 :                                 float aX, float aY, float aWidth, float aHeight)
    1322                 : {
    1323               0 :   const nsStyleDisplay* disp = aFrame->GetStyleDisplay();
    1324                 : 
    1325               0 :   if (!(disp->mClipFlags & NS_STYLE_CLIP_RECT)) {
    1326               0 :     NS_ASSERTION(disp->mClipFlags == NS_STYLE_CLIP_AUTO,
    1327                 :                  "We don't know about this type of clip.");
    1328               0 :     return gfxRect(aX, aY, aWidth, aHeight);
    1329                 :   }
    1330                 : 
    1331               0 :   if (disp->mOverflowX == NS_STYLE_OVERFLOW_HIDDEN ||
    1332                 :       disp->mOverflowY == NS_STYLE_OVERFLOW_HIDDEN) {
    1333                 : 
    1334                 :     nsIntRect clipPxRect =
    1335               0 :       disp->mClip.ToOutsidePixels(aFrame->PresContext()->AppUnitsPerDevPixel());
    1336                 :     gfxRect clipRect =
    1337               0 :       gfxRect(clipPxRect.x, clipPxRect.y, clipPxRect.width, clipPxRect.height);
    1338                 : 
    1339               0 :     if (NS_STYLE_CLIP_RIGHT_AUTO & disp->mClipFlags) {
    1340               0 :       clipRect.width = aWidth - clipRect.X();
    1341                 :     }
    1342               0 :     if (NS_STYLE_CLIP_BOTTOM_AUTO & disp->mClipFlags) {
    1343               0 :       clipRect.height = aHeight - clipRect.Y();
    1344                 :     }
    1345                 : 
    1346               0 :     if (disp->mOverflowX != NS_STYLE_OVERFLOW_HIDDEN) {
    1347               0 :       clipRect.x = aX;
    1348               0 :       clipRect.width = aWidth;
    1349                 :     }
    1350               0 :     if (disp->mOverflowY != NS_STYLE_OVERFLOW_HIDDEN) {
    1351               0 :       clipRect.y = aY;
    1352               0 :       clipRect.height = aHeight;
    1353                 :     }
    1354                 :      
    1355               0 :     return clipRect;
    1356                 :   }
    1357               0 :   return gfxRect(aX, aY, aWidth, aHeight);
    1358                 : }
    1359                 : 
    1360                 : void
    1361               0 : nsSVGUtils::CompositeSurfaceMatrix(gfxContext *aContext,
    1362                 :                                    gfxASurface *aSurface,
    1363                 :                                    const gfxMatrix &aCTM, float aOpacity)
    1364                 : {
    1365               0 :   if (aCTM.IsSingular())
    1366               0 :     return;
    1367                 :   
    1368               0 :   if (aContext->IsCairo()) {
    1369               0 :     aContext->Save();
    1370               0 :     aContext->Multiply(aCTM);
    1371               0 :     aContext->SetSource(aSurface);
    1372               0 :     aContext->Paint(aOpacity);
    1373               0 :     aContext->Restore();
    1374                 :   } else {
    1375               0 :     DrawTarget *dt = aContext->GetDrawTarget();
    1376               0 :     Matrix oldMat = dt->GetTransform();
    1377                 :     RefPtr<SourceSurface> surf =
    1378               0 :       gfxPlatform::GetPlatform()->GetSourceSurfaceForSurface(dt, aSurface);
    1379               0 :     dt->SetTransform(oldMat * ToMatrix(aCTM));
    1380                 : 
    1381               0 :     gfxSize size = aSurface->GetSize();
    1382               0 :     NS_ASSERTION(size.width >= 0 && size.height >= 0, "Failure to get size for aSurface.");
    1383                 : 
    1384               0 :     gfxPoint pt = aSurface->GetDeviceOffset();
    1385                 : 
    1386                 :     dt->FillRect(Rect(-pt.x, -pt.y, size.width, size.height),
    1387                 :                  SurfacePattern(surf, EXTEND_CLAMP,
    1388               0 :                                 Matrix(1.0f, 0, 0, 1.0f, -pt.x, -pt.y)),
    1389               0 :                  DrawOptions(aOpacity));
    1390                 : 
    1391               0 :     dt->SetTransform(oldMat);
    1392                 :   }
    1393                 : }
    1394                 : 
    1395                 : void
    1396               0 : nsSVGUtils::CompositePatternMatrix(gfxContext *aContext,
    1397                 :                                    gfxPattern *aPattern,
    1398                 :                                    const gfxMatrix &aCTM, float aWidth, float aHeight, float aOpacity)
    1399                 : {
    1400               0 :   if (aCTM.IsSingular())
    1401               0 :     return;
    1402                 : 
    1403               0 :   aContext->Save();
    1404               0 :   SetClipRect(aContext, aCTM, gfxRect(0, 0, aWidth, aHeight));
    1405               0 :   aContext->Multiply(aCTM);
    1406               0 :   aContext->SetPattern(aPattern);
    1407               0 :   aContext->Paint(aOpacity);
    1408               0 :   aContext->Restore();
    1409                 : }
    1410                 : 
    1411                 : void
    1412               0 : nsSVGUtils::SetClipRect(gfxContext *aContext,
    1413                 :                         const gfxMatrix &aCTM,
    1414                 :                         const gfxRect &aRect)
    1415                 : {
    1416               0 :   if (aCTM.IsSingular())
    1417               0 :     return;
    1418                 : 
    1419               0 :   gfxMatrix oldMatrix = aContext->CurrentMatrix();
    1420               0 :   aContext->Multiply(aCTM);
    1421               0 :   aContext->Clip(aRect);
    1422               0 :   aContext->SetMatrix(oldMatrix);
    1423                 : }
    1424                 : 
    1425                 : void
    1426               0 : nsSVGUtils::ClipToGfxRect(nsIntRect* aRect, const gfxRect& aGfxRect)
    1427                 : {
    1428               0 :   gfxRect r = aGfxRect;
    1429               0 :   r.RoundOut();
    1430               0 :   gfxRect r2(aRect->x, aRect->y, aRect->width, aRect->height);
    1431               0 :   r = r.Intersect(r2);
    1432               0 :   *aRect = nsIntRect(PRInt32(r.X()), PRInt32(r.Y()),
    1433               0 :                      PRInt32(r.Width()), PRInt32(r.Height()));
    1434               0 : }
    1435                 : 
    1436                 : gfxRect
    1437               0 : nsSVGUtils::GetBBox(nsIFrame *aFrame, PRUint32 aFlags)
    1438                 : {
    1439               0 :   if (aFrame->GetContent()->IsNodeOfType(nsINode::eTEXT)) {
    1440               0 :     aFrame = aFrame->GetParent();
    1441                 :   }
    1442               0 :   gfxRect bbox;
    1443               0 :   nsISVGChildFrame *svg = do_QueryFrame(aFrame);
    1444               0 :   if (svg) {
    1445                 :     // It is possible to apply a gradient, pattern, clipping path, mask or
    1446                 :     // filter to text. When one of these facilities is applied to text
    1447                 :     // the bounding box is the entire text element in all
    1448                 :     // cases.
    1449                 :     nsSVGTextContainerFrame* metrics = do_QueryFrame(
    1450               0 :       GetFirstNonAAncestorFrame(aFrame));
    1451               0 :     if (metrics) {
    1452               0 :       while (aFrame->GetType() != nsGkAtoms::svgTextFrame) {
    1453               0 :         aFrame = aFrame->GetParent();
    1454                 :       }
    1455               0 :       svg = do_QueryFrame(aFrame);
    1456                 :     }
    1457               0 :     nsIContent* content = aFrame->GetContent();
    1458               0 :     if (content->IsSVG() &&
    1459               0 :         !static_cast<const nsSVGElement*>(content)->HasValidDimensions()) {
    1460               0 :       return bbox;
    1461                 :     }
    1462               0 :     gfxMatrix matrix;
    1463               0 :     if (aFrame->GetType() == nsGkAtoms::svgForeignObjectFrame) {
    1464                 :       // The spec says getBBox "Returns the tight bounding box in *current user
    1465                 :       // space*". So we should really be doing this for all elements, but that
    1466                 :       // needs investigation to check that we won't break too much content.
    1467               0 :       NS_ABORT_IF_FALSE(content->IsSVG(), "bad cast");
    1468               0 :       nsSVGElement *element = static_cast<nsSVGElement*>(content);
    1469                 :       matrix = element->PrependLocalTransformsTo(matrix,
    1470               0 :                           nsSVGElement::eChildToUserSpace);
    1471                 :     }
    1472               0 :     bbox = svg->GetBBoxContribution(matrix, aFlags);
    1473                 :   } else {
    1474               0 :     bbox = nsSVGIntegrationUtils::GetSVGBBoxForNonSVGFrame(aFrame);
    1475                 :   }
    1476               0 :   NS_ASSERTION(bbox.Width() >= 0.0 && bbox.Height() >= 0.0, "Invalid bbox!");
    1477               0 :   return bbox;
    1478                 : }
    1479                 : 
    1480                 : gfxRect
    1481               0 : nsSVGUtils::GetRelativeRect(PRUint16 aUnits, const nsSVGLength2 *aXYWH,
    1482                 :                             const gfxRect &aBBox, nsIFrame *aFrame)
    1483                 : {
    1484                 :   float x, y, width, height;
    1485               0 :   if (aUnits == nsIDOMSVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX) {
    1486               0 :     x = aBBox.X() + ObjectSpace(aBBox, &aXYWH[0]);
    1487               0 :     y = aBBox.Y() + ObjectSpace(aBBox, &aXYWH[1]);
    1488               0 :     width = ObjectSpace(aBBox, &aXYWH[2]);
    1489               0 :     height = ObjectSpace(aBBox, &aXYWH[3]);
    1490                 :   } else {
    1491               0 :     x = UserSpace(aFrame, &aXYWH[0]);
    1492               0 :     y = UserSpace(aFrame, &aXYWH[1]);
    1493               0 :     width = UserSpace(aFrame, &aXYWH[2]);
    1494               0 :     height = UserSpace(aFrame, &aXYWH[3]);
    1495                 :   }
    1496               0 :   return gfxRect(x, y, width, height);
    1497                 : }
    1498                 : 
    1499                 : bool
    1500               0 : nsSVGUtils::CanOptimizeOpacity(nsIFrame *aFrame)
    1501                 : {
    1502               0 :   nsIAtom *type = aFrame->GetType();
    1503               0 :   if (type != nsGkAtoms::svgImageFrame &&
    1504                 :       type != nsGkAtoms::svgPathGeometryFrame) {
    1505               0 :     return false;
    1506                 :   }
    1507               0 :   if (aFrame->GetStyleSVGReset()->mFilter) {
    1508               0 :     return false;
    1509                 :   }
    1510                 :   // XXX The SVG WG is intending to allow fill, stroke and markers on <image>
    1511               0 :   if (type == nsGkAtoms::svgImageFrame) {
    1512               0 :     return true;
    1513                 :   }
    1514               0 :   const nsStyleSVG *style = aFrame->GetStyleSVG();
    1515               0 :   if (style->mMarkerStart || style->mMarkerMid || style->mMarkerEnd) {
    1516               0 :     return false;
    1517                 :   }
    1518               0 :   if (style->mFill.mType == eStyleSVGPaintType_None ||
    1519                 :       style->mFillOpacity <= 0 ||
    1520               0 :       !static_cast<nsSVGPathGeometryFrame*>(aFrame)->HasStroke()) {
    1521               0 :     return true;
    1522                 :   }
    1523               0 :   return false;
    1524                 : }
    1525                 : 
    1526                 : float
    1527               0 : nsSVGUtils::MaxExpansion(const gfxMatrix &aMatrix)
    1528                 : {
    1529                 :   // maximum expansion derivation from
    1530                 :   // http://lists.cairographics.org/archives/cairo/2004-October/001980.html
    1531                 :   // and also implemented in cairo_matrix_transformed_circle_major_axis
    1532               0 :   double a = aMatrix.xx;
    1533               0 :   double b = aMatrix.yx;
    1534               0 :   double c = aMatrix.xy;
    1535               0 :   double d = aMatrix.yy;
    1536               0 :   double f = (a * a + b * b + c * c + d * d) / 2;
    1537               0 :   double g = (a * a + b * b - c * c - d * d) / 2;
    1538               0 :   double h = a * c + b * d;
    1539               0 :   return sqrt(f + sqrt(g * g + h * h));
    1540                 : }
    1541                 : 
    1542                 : gfxMatrix
    1543               0 : nsSVGUtils::AdjustMatrixForUnits(const gfxMatrix &aMatrix,
    1544                 :                                  nsSVGEnum *aUnits,
    1545                 :                                  nsIFrame *aFrame)
    1546                 : {
    1547               0 :   if (aFrame &&
    1548               0 :       aUnits->GetAnimValue() ==
    1549                 :       nsIDOMSVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX) {
    1550               0 :     gfxRect bbox = GetBBox(aFrame);
    1551               0 :     return gfxMatrix().Scale(bbox.Width(), bbox.Height()) *
    1552               0 :            gfxMatrix().Translate(gfxPoint(bbox.X(), bbox.Y())) *
    1553               0 :            aMatrix;
    1554                 :   }
    1555               0 :   return aMatrix;
    1556                 : }
    1557                 : 
    1558                 : nsIFrame*
    1559               0 : nsSVGUtils::GetFirstNonAAncestorFrame(nsIFrame* aStartFrame)
    1560                 : {
    1561               0 :   for (nsIFrame *ancestorFrame = aStartFrame; ancestorFrame;
    1562                 :        ancestorFrame = ancestorFrame->GetParent()) {
    1563               0 :     if (ancestorFrame->GetType() != nsGkAtoms::svgAFrame) {
    1564               0 :       return ancestorFrame;
    1565                 :     }
    1566                 :   }
    1567               0 :   return nsnull;
    1568                 : }
    1569                 : 
    1570                 : #ifdef DEBUG
    1571                 : void
    1572               0 : nsSVGUtils::WritePPM(const char *fname, gfxImageSurface *aSurface)
    1573                 : {
    1574               0 :   FILE *f = fopen(fname, "wb");
    1575               0 :   if (!f)
    1576               0 :     return;
    1577                 : 
    1578               0 :   gfxIntSize size = aSurface->GetSize();
    1579               0 :   fprintf(f, "P6\n%d %d\n255\n", size.width, size.height);
    1580               0 :   unsigned char *data = aSurface->Data();
    1581               0 :   PRInt32 stride = aSurface->Stride();
    1582               0 :   for (int y=0; y<size.height; y++) {
    1583               0 :     for (int x=0; x<size.width; x++) {
    1584               0 :       fwrite(data + y * stride + 4 * x + GFX_ARGB32_OFFSET_R, 1, 1, f);
    1585               0 :       fwrite(data + y * stride + 4 * x + GFX_ARGB32_OFFSET_G, 1, 1, f);
    1586               0 :       fwrite(data + y * stride + 4 * x + GFX_ARGB32_OFFSET_B, 1, 1, f);
    1587                 :     }
    1588                 :   }
    1589               0 :   fclose(f);
    1590                 : }
    1591                 : #endif
    1592                 : 
    1593                 : // The logic here comes from _cairo_stroke_style_max_distance_from_path
    1594                 : static gfxRect
    1595               0 : PathExtentsToMaxStrokeExtents(const gfxRect& aPathExtents,
    1596                 :                               nsSVGGeometryFrame* aFrame,
    1597                 :                               double styleExpansionFactor,
    1598                 :                               const gfxMatrix& aMatrix)
    1599                 : {
    1600                 :   double style_expansion =
    1601               0 :     styleExpansionFactor * aFrame->GetStrokeWidth();
    1602                 : 
    1603               0 :   double dx = style_expansion * (fabs(aMatrix.xx) + fabs(aMatrix.xy));
    1604               0 :   double dy = style_expansion * (fabs(aMatrix.yy) + fabs(aMatrix.yx));
    1605                 : 
    1606               0 :   gfxRect strokeExtents = aPathExtents;
    1607               0 :   strokeExtents.Inflate(dx, dy);
    1608                 :   return strokeExtents;
    1609                 : }
    1610                 : 
    1611                 : /*static*/ gfxRect
    1612               0 : nsSVGUtils::PathExtentsToMaxStrokeExtents(const gfxRect& aPathExtents,
    1613                 :                                           nsSVGGeometryFrame* aFrame,
    1614                 :                                           const gfxMatrix& aMatrix)
    1615                 : {
    1616               0 :   return ::PathExtentsToMaxStrokeExtents(aPathExtents, aFrame, 0.5, aMatrix);
    1617                 : }
    1618                 : 
    1619                 : /*static*/ gfxRect
    1620               0 : nsSVGUtils::PathExtentsToMaxStrokeExtents(const gfxRect& aPathExtents,
    1621                 :                                           nsSVGPathGeometryFrame* aFrame,
    1622                 :                                           const gfxMatrix& aMatrix)
    1623                 : {
    1624               0 :   double styleExpansionFactor = 0.5;
    1625                 : 
    1626               0 :   if (static_cast<nsSVGPathGeometryElement*>(aFrame->GetContent())->IsMarkable()) {
    1627               0 :     const nsStyleSVG* style = aFrame->GetStyleSVG();
    1628                 : 
    1629               0 :     if (style->mStrokeLinecap == NS_STYLE_STROKE_LINECAP_SQUARE) {
    1630               0 :       styleExpansionFactor = M_SQRT1_2;
    1631                 :     }
    1632                 : 
    1633               0 :     if (style->mStrokeLinejoin == NS_STYLE_STROKE_LINEJOIN_MITER &&
    1634                 :         styleExpansionFactor < style->mStrokeMiterlimit &&
    1635               0 :         aFrame->GetContent()->Tag() != nsGkAtoms::line) {
    1636               0 :       styleExpansionFactor = style->mStrokeMiterlimit;
    1637                 :     }
    1638                 :   }
    1639                 : 
    1640                 :   return ::PathExtentsToMaxStrokeExtents(aPathExtents,
    1641                 :                                          aFrame,
    1642                 :                                          styleExpansionFactor,
    1643               0 :                                          aMatrix);
    1644                 : }
    1645                 : 
    1646                 : // ----------------------------------------------------------------------
    1647                 : 
    1648                 : /* static */ bool
    1649               0 : nsSVGUtils::RootSVGElementHasViewbox(const nsIContent *aRootSVGElem)
    1650                 : {
    1651               0 :   if (!aRootSVGElem->IsSVG(nsGkAtoms::svg)) {
    1652               0 :     NS_ABORT_IF_FALSE(false, "Expecting an SVG <svg> node");
    1653               0 :     return false;
    1654                 :   }
    1655                 : 
    1656                 :   const nsSVGSVGElement *svgSvgElem =
    1657               0 :     static_cast<const nsSVGSVGElement*>(aRootSVGElem);
    1658                 : 
    1659               0 :   return svgSvgElem->HasValidViewbox();
    1660                 : }
    1661                 : 
    1662                 : /* static */ void
    1663               0 : nsSVGUtils::GetFallbackOrPaintColor(gfxContext *aContext, nsStyleContext *aStyleContext,
    1664                 :                                     nsStyleSVGPaint nsStyleSVG::*aFillOrStroke,
    1665                 :                                     float *aOpacity, nscolor *color)
    1666                 : {
    1667               0 :   const nsStyleSVGPaint &paint = aStyleContext->GetStyleSVG()->*aFillOrStroke;
    1668               0 :   nsStyleContext *styleIfVisited = aStyleContext->GetStyleIfVisited();
    1669               0 :   bool isServer = paint.mType == eStyleSVGPaintType_Server;
    1670               0 :   *color = isServer ? paint.mFallbackColor : paint.mPaint.mColor;
    1671               0 :   if (styleIfVisited) {
    1672                 :     const nsStyleSVGPaint &paintIfVisited =
    1673               0 :       styleIfVisited->GetStyleSVG()->*aFillOrStroke;
    1674                 :     // To prevent Web content from detecting if a user has visited a URL
    1675                 :     // (via URL loading triggered by paint servers or performance
    1676                 :     // differences between paint servers or between a paint server and a
    1677                 :     // color), we do not allow whether links are visited to change which
    1678                 :     // paint server is used or switch between paint servers and simple
    1679                 :     // colors.  A :visited style may only override a simple color with
    1680                 :     // another simple color.
    1681               0 :     if (paintIfVisited.mType == eStyleSVGPaintType_Color &&
    1682                 :         paint.mType == eStyleSVGPaintType_Color) {
    1683               0 :       nscolor colorIfVisited = paintIfVisited.mPaint.mColor;
    1684               0 :       nscolor colors[2] = { *color, colorIfVisited };
    1685                 :       *color = nsStyleContext::CombineVisitedColors(colors,
    1686               0 :                                          aStyleContext->RelevantLinkVisited());
    1687                 :     }
    1688                 :   }
    1689               0 : }

Generated by: LCOV version 1.7