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
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/
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
15 * The Original Code is the Mozilla SVG project.
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.
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.
35 * ***** END LICENSE BLOCK ***** */
37 #include "nsIDOMDocument.h"
38 #include "nsIDOMSVGElement.h"
39 #include "nsIDOMSVGSVGElement.h"
40 #include "nsStyleCoord.h"
41 #include "nsPresContext.h"
42 #include "nsSVGSVGElement.h"
43 #include "nsIContent.h"
44 #include "nsIDocument.h"
46 #include "nsGkAtoms.h"
48 #include "nsStyleStruct.h"
49 #include "nsIPresShell.h"
50 #include "nsSVGUtils.h"
51 #include "nsISVGGlyphFragmentLeaf.h"
52 #include "nsNetUtil.h"
53 #include "nsIDOMSVGRect.h"
54 #include "nsFrameList.h"
55 #include "nsISVGChildFrame.h"
56 #include "nsContentDLF.h"
57 #include "nsContentUtils.h"
58 #include "nsSVGFilterFrame.h"
59 #include "nsINameSpaceManager.h"
60 #include "nsIDOMSVGPoint.h"
61 #include "nsSVGPoint.h"
62 #include "nsDOMError.h"
63 #include "nsSVGOuterSVGFrame.h"
64 #include "nsSVGPreserveAspectRatio.h"
65 #include "nsSVGMatrix.h"
66 #include "nsSVGClipPathFrame.h"
67 #include "nsSVGMaskFrame.h"
68 #include "nsSVGContainerFrame.h"
69 #include "nsSVGLength2.h"
70 #include "nsGenericElement.h"
71 #include "nsAttrValue.h"
72 #include "nsSVGGeometryFrame.h"
73 #include "nsIScriptError.h"
74 #include "gfxContext.h"
75 #include "gfxMatrix.h"
77 #include "gfxImageSurface.h"
78 #include "gfxPlatform.h"
79 #include "nsSVGForeignObjectFrame.h"
80 #include "nsIFontMetrics.h"
81 #include "nsIDOMSVGUnitTypes.h"
82 #include "nsSVGRect.h"
83 #include "nsSVGEffects.h"
84 #include "nsSVGIntegrationUtils.h"
85 #include "nsSVGFilterPaintCallback.h"
87 gfxASurface
*nsSVGUtils::mThebesComputationalSurface
= nsnull
;
90 // (c <= 0.0031308 ? c * 12.92 : 1.055 * pow(c, 1 / 2.4) - 0.055) * 255 + 0.5
91 static const PRUint8 glinearRGBTosRGBMap
[256] = {
92 0, 13, 22, 28, 34, 38, 42, 46,
93 50, 53, 56, 59, 61, 64, 66, 69,
94 71, 73, 75, 77, 79, 81, 83, 85,
95 86, 88, 90, 92, 93, 95, 96, 98,
96 99, 101, 102, 104, 105, 106, 108, 109,
97 110, 112, 113, 114, 115, 117, 118, 119,
98 120, 121, 122, 124, 125, 126, 127, 128,
99 129, 130, 131, 132, 133, 134, 135, 136,
100 137, 138, 139, 140, 141, 142, 143, 144,
101 145, 146, 147, 148, 148, 149, 150, 151,
102 152, 153, 154, 155, 155, 156, 157, 158,
103 159, 159, 160, 161, 162, 163, 163, 164,
104 165, 166, 167, 167, 168, 169, 170, 170,
105 171, 172, 173, 173, 174, 175, 175, 176,
106 177, 178, 178, 179, 180, 180, 181, 182,
107 182, 183, 184, 185, 185, 186, 187, 187,
108 188, 189, 189, 190, 190, 191, 192, 192,
109 193, 194, 194, 195, 196, 196, 197, 197,
110 198, 199, 199, 200, 200, 201, 202, 202,
111 203, 203, 204, 205, 205, 206, 206, 207,
112 208, 208, 209, 209, 210, 210, 211, 212,
113 212, 213, 213, 214, 214, 215, 215, 216,
114 216, 217, 218, 218, 219, 219, 220, 220,
115 221, 221, 222, 222, 223, 223, 224, 224,
116 225, 226, 226, 227, 227, 228, 228, 229,
117 229, 230, 230, 231, 231, 232, 232, 233,
118 233, 234, 234, 235, 235, 236, 236, 237,
119 237, 238, 238, 238, 239, 239, 240, 240,
120 241, 241, 242, 242, 243, 243, 244, 244,
121 245, 245, 246, 246, 246, 247, 247, 248,
122 248, 249, 249, 250, 250, 251, 251, 251,
123 252, 252, 253, 253, 254, 254, 255, 255
127 // c <= 0.04045 ? c / 12.92 : pow((c + 0.055) / 1.055, 2.4)) * 255 + 0.5
128 static const PRUint8 gsRGBToLinearRGBMap
[256] = {
129 0, 0, 0, 0, 0, 0, 0, 1,
130 1, 1, 1, 1, 1, 1, 1, 1,
131 1, 1, 2, 2, 2, 2, 2, 2,
132 2, 2, 3, 3, 3, 3, 3, 3,
133 4, 4, 4, 4, 4, 5, 5, 5,
134 5, 6, 6, 6, 6, 7, 7, 7,
135 8, 8, 8, 8, 9, 9, 9, 10,
136 10, 10, 11, 11, 12, 12, 12, 13,
137 13, 13, 14, 14, 15, 15, 16, 16,
138 17, 17, 17, 18, 18, 19, 19, 20,
139 20, 21, 22, 22, 23, 23, 24, 24,
140 25, 25, 26, 27, 27, 28, 29, 29,
141 30, 30, 31, 32, 32, 33, 34, 35,
142 35, 36, 37, 37, 38, 39, 40, 41,
143 41, 42, 43, 44, 45, 45, 46, 47,
144 48, 49, 50, 51, 51, 52, 53, 54,
145 55, 56, 57, 58, 59, 60, 61, 62,
146 63, 64, 65, 66, 67, 68, 69, 70,
147 71, 72, 73, 74, 76, 77, 78, 79,
148 80, 81, 82, 84, 85, 86, 87, 88,
149 90, 91, 92, 93, 95, 96, 97, 99,
150 100, 101, 103, 104, 105, 107, 108, 109,
151 111, 112, 114, 115, 116, 118, 119, 121,
152 122, 124, 125, 127, 128, 130, 131, 133,
153 134, 136, 138, 139, 141, 142, 144, 146,
154 147, 149, 151, 152, 154, 156, 157, 159,
155 161, 163, 164, 166, 168, 170, 171, 173,
156 175, 177, 179, 181, 183, 184, 186, 188,
157 190, 192, 194, 196, 198, 200, 202, 204,
158 206, 208, 210, 212, 214, 216, 218, 220,
159 222, 224, 226, 229, 231, 233, 235, 237,
160 239, 242, 244, 246, 248, 250, 253, 255
163 static PRBool gSVGEnabled
;
164 static const char SVG_PREF_STR
[] = "svg.enabled";
167 SVGPrefChanged(const char *aPref
, void *aClosure
)
169 PRBool prefVal
= nsContentUtils::GetBoolPref(SVG_PREF_STR
);
170 if (prefVal
== gSVGEnabled
)
173 gSVGEnabled
= prefVal
;
175 nsContentDLF::RegisterSVG();
177 nsContentDLF::UnregisterSVG();
185 static PRBool sInitialized
= PR_FALSE
;
188 /* check and register ourselves with the pref */
189 gSVGEnabled
= nsContentUtils::GetBoolPref(SVG_PREF_STR
);
190 nsContentUtils::RegisterPrefCallback(SVG_PREF_STR
, SVGPrefChanged
, nsnull
);
192 sInitialized
= PR_TRUE
;
199 GetFrameForContent(nsIContent
* aContent
)
204 nsIDocument
*doc
= aContent
->GetCurrentDoc();
208 return nsGenericElement::GetPrimaryFrameFor(aContent
, doc
);
212 nsSVGUtils::GetFontSize(nsIContent
*aContent
)
214 nsIFrame
* frame
= GetFrameForContent(aContent
);
216 NS_WARNING("no frame in GetFontSize()");
220 return GetFontSize(frame
);
224 nsSVGUtils::GetFontSize(nsIFrame
*aFrame
)
226 return nsPresContext::AppUnitsToFloatCSSPixels(aFrame
->GetStyleFont()->mSize
) /
227 aFrame
->PresContext()->TextZoom();
231 nsSVGUtils::GetFontXHeight(nsIContent
*aContent
)
233 nsIFrame
* frame
= GetFrameForContent(aContent
);
235 NS_WARNING("no frame in GetFontXHeight()");
239 return GetFontXHeight(frame
);
243 nsSVGUtils::GetFontXHeight(nsIFrame
*aFrame
)
245 nsCOMPtr
<nsIFontMetrics
> fontMetrics
;
246 nsLayoutUtils::GetFontMetricsForFrame(aFrame
, getter_AddRefs(fontMetrics
));
249 NS_WARNING("no FontMetrics in GetFontXHeight()");
254 fontMetrics
->GetXHeight(xHeight
);
255 return nsPresContext::AppUnitsToFloatCSSPixels(xHeight
) /
256 aFrame
->PresContext()->TextZoom();
260 nsSVGUtils::UnPremultiplyImageDataAlpha(PRUint8
*data
,
262 const nsIntRect
&rect
)
264 for (PRInt32 y
= rect
.y
; y
< rect
.YMost(); y
++) {
265 for (PRInt32 x
= rect
.x
; x
< rect
.XMost(); x
++) {
266 PRUint8
*pixel
= data
+ stride
* y
+ 4 * x
;
268 PRUint8 a
= pixel
[GFX_ARGB32_OFFSET_A
];
273 pixel
[GFX_ARGB32_OFFSET_B
] = (255 * pixel
[GFX_ARGB32_OFFSET_B
]) / a
;
274 pixel
[GFX_ARGB32_OFFSET_G
] = (255 * pixel
[GFX_ARGB32_OFFSET_G
]) / a
;
275 pixel
[GFX_ARGB32_OFFSET_R
] = (255 * pixel
[GFX_ARGB32_OFFSET_R
]) / a
;
277 pixel
[GFX_ARGB32_OFFSET_B
] = 0;
278 pixel
[GFX_ARGB32_OFFSET_G
] = 0;
279 pixel
[GFX_ARGB32_OFFSET_R
] = 0;
286 nsSVGUtils::PremultiplyImageDataAlpha(PRUint8
*data
,
288 const nsIntRect
&rect
)
290 for (PRInt32 y
= rect
.y
; y
< rect
.YMost(); y
++) {
291 for (PRInt32 x
= rect
.x
; x
< rect
.XMost(); x
++) {
292 PRUint8
*pixel
= data
+ stride
* y
+ 4 * x
;
294 PRUint8 a
= pixel
[GFX_ARGB32_OFFSET_A
];
298 FAST_DIVIDE_BY_255(pixel
[GFX_ARGB32_OFFSET_B
],
299 pixel
[GFX_ARGB32_OFFSET_B
] * a
);
300 FAST_DIVIDE_BY_255(pixel
[GFX_ARGB32_OFFSET_G
],
301 pixel
[GFX_ARGB32_OFFSET_G
] * a
);
302 FAST_DIVIDE_BY_255(pixel
[GFX_ARGB32_OFFSET_R
],
303 pixel
[GFX_ARGB32_OFFSET_R
] * a
);
309 nsSVGUtils::ConvertImageDataToLinearRGB(PRUint8
*data
,
311 const nsIntRect
&rect
)
313 for (PRInt32 y
= rect
.y
; y
< rect
.YMost(); y
++) {
314 for (PRInt32 x
= rect
.x
; x
< rect
.XMost(); x
++) {
315 PRUint8
*pixel
= data
+ stride
* y
+ 4 * x
;
317 pixel
[GFX_ARGB32_OFFSET_B
] =
318 gsRGBToLinearRGBMap
[pixel
[GFX_ARGB32_OFFSET_B
]];
319 pixel
[GFX_ARGB32_OFFSET_G
] =
320 gsRGBToLinearRGBMap
[pixel
[GFX_ARGB32_OFFSET_G
]];
321 pixel
[GFX_ARGB32_OFFSET_R
] =
322 gsRGBToLinearRGBMap
[pixel
[GFX_ARGB32_OFFSET_R
]];
328 nsSVGUtils::ConvertImageDataFromLinearRGB(PRUint8
*data
,
330 const nsIntRect
&rect
)
332 for (PRInt32 y
= rect
.y
; y
< rect
.YMost(); y
++) {
333 for (PRInt32 x
= rect
.x
; x
< rect
.XMost(); x
++) {
334 PRUint8
*pixel
= data
+ stride
* y
+ 4 * x
;
336 pixel
[GFX_ARGB32_OFFSET_B
] =
337 glinearRGBTosRGBMap
[pixel
[GFX_ARGB32_OFFSET_B
]];
338 pixel
[GFX_ARGB32_OFFSET_G
] =
339 glinearRGBTosRGBMap
[pixel
[GFX_ARGB32_OFFSET_G
]];
340 pixel
[GFX_ARGB32_OFFSET_R
] =
341 glinearRGBTosRGBMap
[pixel
[GFX_ARGB32_OFFSET_R
]];
347 nsSVGUtils::ReportToConsole(nsIDocument
* doc
,
348 const char* aWarning
,
349 const PRUnichar
**aParams
,
350 PRUint32 aParamsLength
)
352 return nsContentUtils::ReportToConsole(nsContentUtils::eSVG_PROPERTIES
,
354 aParams
, aParamsLength
,
355 doc
? doc
->GetDocumentURI() : nsnull
,
357 nsIScriptError::warningFlag
,
362 nsSVGUtils::CoordToFloat(nsPresContext
*aPresContext
,
363 nsSVGElement
*aContent
,
364 const nsStyleCoord
&aCoord
)
366 switch (aCoord
.GetUnit()) {
367 case eStyleUnit_Factor
:
369 return aCoord
.GetFactorValue();
371 case eStyleUnit_Coord
:
372 return nsPresContext::AppUnitsToFloatCSSPixels(aCoord
.GetCoordValue());
374 case eStyleUnit_Percent
: {
375 nsSVGSVGElement
* ctx
= aContent
->GetCtx();
376 return ctx
? aCoord
.GetPercentValue() * ctx
->GetLength(nsSVGUtils::XY
) : 0.0f
;
384 nsSVGUtils::GetNearestViewportElement(nsIContent
*aContent
,
385 nsIDOMSVGElement
* *aNearestViewportElement
)
387 *aNearestViewportElement
= nsnull
;
389 nsBindingManager
*bindingManager
= nsnull
;
390 // XXXbz I _think_ this is right. We want to be using the binding manager
391 // that would have attached the bindings that gives us our anonymous
392 // ancestors. That's the binding manager for the document we actually belong
393 // to, which is our owner doc.
394 nsIDocument
* ownerDoc
= aContent
->GetOwnerDoc();
396 bindingManager
= ownerDoc
->BindingManager();
399 nsCOMPtr
<nsIContent
> element
= aContent
;
400 nsCOMPtr
<nsIContent
> ancestor
;
401 unsigned short ancestorCount
= 0;
406 if (bindingManager
) {
407 // check for an anonymous ancestor first
408 ancestor
= bindingManager
->GetInsertionParent(element
);
411 // if we didn't find an anonymous ancestor, use the explicit one
412 ancestor
= element
->GetParent();
415 nsCOMPtr
<nsIDOMSVGFitToViewBox
> fitToViewBox
= do_QueryInterface(element
);
417 if (fitToViewBox
&& (ancestor
|| ancestorCount
)) {
418 // right interface and not the outermost SVG element
419 nsCOMPtr
<nsIDOMSVGElement
> SVGElement
= do_QueryInterface(element
);
420 SVGElement
.swap(*aNearestViewportElement
);
425 // reached the top of our parent chain
437 nsSVGUtils::GetFarthestViewportElement(nsIContent
*aContent
,
438 nsIDOMSVGElement
* *aFarthestViewportElement
)
440 *aFarthestViewportElement
= nsnull
;
442 nsBindingManager
*bindingManager
= nsnull
;
443 // XXXbz I _think_ this is right. We want to be using the binding manager
444 // that would have attached the bindings that gives us our anonymous
445 // ancestors. That's the binding manager for the document we actually belong
446 // to, which is our owner doc.
447 nsIDocument
* ownerDoc
= aContent
->GetOwnerDoc();
449 bindingManager
= ownerDoc
->BindingManager();
452 nsCOMPtr
<nsIContent
> element
= aContent
;
453 nsCOMPtr
<nsIContent
> ancestor
;
454 nsCOMPtr
<nsIDOMSVGElement
> SVGElement
;
455 unsigned short ancestorCount
= 0;
460 if (bindingManager
) {
461 // check for an anonymous ancestor first
462 ancestor
= bindingManager
->GetInsertionParent(element
);
465 // if we didn't find an anonymous ancestor, use the explicit one
466 ancestor
= element
->GetParent();
469 nsCOMPtr
<nsIDOMSVGFitToViewBox
> fitToViewBox
= do_QueryInterface(element
);
473 SVGElement
= do_QueryInterface(element
);
477 // reached the top of our parent chain
485 if (ancestorCount
== 0 || !SVGElement
) {
486 // outermost SVG element or no viewport found
490 SVGElement
.swap(*aFarthestViewportElement
);
495 nsSVGUtils::GetBBox(nsFrameList
*aFrames
, nsIDOMSVGRect
**_retval
)
499 float minx
, miny
, maxx
, maxy
;
500 minx
= miny
= FLT_MAX
;
501 maxx
= maxy
= -1.0 * FLT_MAX
;
503 nsCOMPtr
<nsIDOMSVGRect
> unionRect
;
505 nsIFrame
* kid
= aFrames
->FirstChild();
507 nsISVGChildFrame
* SVGFrame
= do_QueryFrame(kid
);
509 nsCOMPtr
<nsIDOMSVGRect
> box
;
510 SVGFrame
->GetBBox(getter_AddRefs(box
));
513 float bminx
, bminy
, bmaxx
, bmaxy
, width
, height
;
516 box
->GetWidth(&width
);
517 box
->GetHeight(&height
);
519 bmaxy
= bminy
+height
;
523 minx
= PR_MIN(minx
, bminx
);
524 miny
= PR_MIN(miny
, bminy
);
525 maxx
= PR_MAX(maxx
, bmaxx
);
526 maxy
= PR_MAX(maxy
, bmaxy
);
529 kid
= kid
->GetNextSibling();
533 unionRect
->SetX(minx
);
534 unionRect
->SetY(miny
);
535 unionRect
->SetWidth(maxx
- minx
);
536 unionRect
->SetHeight(maxy
- miny
);
537 *_retval
= unionRect
;
542 return NS_ERROR_FAILURE
;
546 nsSVGUtils::FindFilterInvalidation(nsIFrame
*aFrame
, const nsRect
& aRect
)
548 PRInt32 appUnitsPerDevPixel
= aFrame
->PresContext()->AppUnitsPerDevPixel();
549 nsIntRect rect
= nsRect::ToOutsidePixels(aRect
, appUnitsPerDevPixel
);
552 if (aFrame
->GetStateBits() & NS_STATE_IS_OUTER_SVG
)
555 nsSVGFilterFrame
*filter
= nsSVGEffects::GetFilterFrame(aFrame
);
557 rect
= filter
->GetInvalidationBBox(aFrame
, rect
);
559 aFrame
= aFrame
->GetParent();
562 return nsIntRect::ToAppUnits(rect
, appUnitsPerDevPixel
);
566 nsSVGUtils::InvalidateCoveredRegion(nsIFrame
*aFrame
)
568 if (aFrame
->GetStateBits() & NS_STATE_SVG_NONDISPLAY_CHILD
)
571 nsSVGOuterSVGFrame
* outerSVGFrame
= nsSVGUtils::GetOuterSVGFrame(aFrame
);
572 NS_ASSERTION(outerSVGFrame
, "no outer svg frame");
574 outerSVGFrame
->InvalidateCoveredRegion(aFrame
);
578 nsSVGUtils::UpdateGraphic(nsISVGChildFrame
*aSVGFrame
)
580 nsIFrame
*frame
= do_QueryFrame(aSVGFrame
);
582 nsSVGEffects::InvalidateRenderingObservers(frame
);
584 if (frame
->GetStateBits() & NS_STATE_SVG_NONDISPLAY_CHILD
)
587 nsSVGOuterSVGFrame
*outerSVGFrame
= nsSVGUtils::GetOuterSVGFrame(frame
);
588 if (!outerSVGFrame
) {
589 NS_ERROR("null outerSVGFrame");
593 if (outerSVGFrame
->IsRedrawSuspended()) {
594 frame
->AddStateBits(NS_STATE_SVG_DIRTY
);
596 frame
->RemoveStateBits(NS_STATE_SVG_DIRTY
);
598 PRBool changed
= outerSVGFrame
->UpdateAndInvalidateCoveredRegion(frame
);
600 NotifyAncestorsOfFilterRegionChange(frame
);
606 nsSVGUtils::NotifyAncestorsOfFilterRegionChange(nsIFrame
*aFrame
)
608 if (aFrame
->GetStateBits() & NS_STATE_IS_OUTER_SVG
) {
609 // It would be better if we couldn't get here
613 aFrame
= aFrame
->GetParent();
616 if (aFrame
->GetStateBits() & NS_STATE_IS_OUTER_SVG
)
619 nsSVGFilterProperty
*property
= nsSVGEffects::GetFilterProperty(aFrame
);
621 property
->Invalidate();
623 aFrame
= aFrame
->GetParent();
628 nsSVGUtils::ComputeNormalizedHypotenuse(double aWidth
, double aHeight
)
630 return sqrt((aWidth
*aWidth
+ aHeight
*aHeight
)/2);
634 nsSVGUtils::ObjectSpace(nsIDOMSVGRect
*aRect
, const nsSVGLength2
*aLength
)
636 float fraction
, axis
;
638 switch (aLength
->GetCtxType()) {
640 aRect
->GetWidth(&axis
);
643 aRect
->GetHeight(&axis
);
648 aRect
->GetWidth(&width
);
649 aRect
->GetHeight(&height
);
650 axis
= float(ComputeNormalizedHypotenuse(width
, height
));
654 if (aLength
->IsPercentage()) {
655 fraction
= aLength
->GetAnimValInSpecifiedUnits() / 100;
657 fraction
= aLength
->GetAnimValue(static_cast<nsSVGSVGElement
*>
660 return fraction
* axis
;
664 nsSVGUtils::UserSpace(nsSVGElement
*aSVGElement
, const nsSVGLength2
*aLength
)
666 return aLength
->GetAnimValue(aSVGElement
);
670 nsSVGUtils::UserSpace(nsIFrame
*aNonSVGContext
, const nsSVGLength2
*aLength
)
672 return aLength
->GetAnimValue(aNonSVGContext
);
676 nsSVGUtils::TransformPoint(nsIDOMSVGMatrix
*matrix
,
679 nsCOMPtr
<nsIDOMSVGPoint
> point
;
680 NS_NewSVGPoint(getter_AddRefs(point
), *x
, *y
);
684 nsCOMPtr
<nsIDOMSVGPoint
> xfpoint
;
685 point
->MatrixTransform(matrix
, getter_AddRefs(xfpoint
));
694 nsSVGUtils::AngleBisect(float a1
, float a2
)
696 float delta
= fmod(a2
- a1
, static_cast<float>(2*M_PI
));
700 /* delta is now the angle from a1 around to a2, in the range [0, 2*M_PI) */
701 float r
= a1
+ delta
/2;
703 /* the arc from a2 to a1 is smaller, so use the ray on that side */
710 nsSVGUtils::GetOuterSVGFrame(nsIFrame
*aFrame
)
713 if (aFrame
->GetStateBits() & NS_STATE_IS_OUTER_SVG
) {
714 return static_cast<nsSVGOuterSVGFrame
*>(aFrame
);
716 aFrame
= aFrame
->GetParent();
723 nsSVGUtils::GetOuterSVGFrameAndCoveredRegion(nsIFrame
* aFrame
, nsRect
* aRect
)
725 nsISVGChildFrame
* svg
= do_QueryFrame(aFrame
);
728 *aRect
= svg
->GetCoveredRegion();
729 return GetOuterSVGFrame(aFrame
);
732 already_AddRefed
<nsIDOMSVGMatrix
>
733 nsSVGUtils::GetViewBoxTransform(float aViewportWidth
, float aViewportHeight
,
734 float aViewboxX
, float aViewboxY
,
735 float aViewboxWidth
, float aViewboxHeight
,
736 const nsSVGPreserveAspectRatio
&aPreserveAspectRatio
,
739 NS_ASSERTION(aViewboxWidth
> 0, "viewBox width must be greater than zero!");
740 NS_ASSERTION(aViewboxHeight
> 0, "viewBox height must be greater than zero!");
742 PRUint16 align
= aPreserveAspectRatio
.GetAnimValue().GetAlign();
743 PRUint16 meetOrSlice
= aPreserveAspectRatio
.GetAnimValue().GetMeetOrSlice();
745 // default to the defaults
746 if (align
== nsIDOMSVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_UNKNOWN
)
747 align
= nsIDOMSVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_XMIDYMID
;
748 if (meetOrSlice
== nsIDOMSVGPreserveAspectRatio::SVG_MEETORSLICE_UNKNOWN
)
749 meetOrSlice
= nsIDOMSVGPreserveAspectRatio::SVG_MEETORSLICE_MEET
;
751 // alignment disabled for this matrix setup
753 align
= nsIDOMSVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_XMINYMIN
;
756 a
= aViewportWidth
/ aViewboxWidth
;
757 d
= aViewportHeight
/ aViewboxHeight
;
761 if (align
!= nsIDOMSVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_NONE
&&
763 if ((meetOrSlice
== nsIDOMSVGPreserveAspectRatio::SVG_MEETORSLICE_MEET
&&
765 (meetOrSlice
== nsIDOMSVGPreserveAspectRatio::SVG_MEETORSLICE_SLICE
&&
769 case nsIDOMSVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_XMINYMIN
:
770 case nsIDOMSVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_XMIDYMIN
:
771 case nsIDOMSVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_XMAXYMIN
:
773 case nsIDOMSVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_XMINYMID
:
774 case nsIDOMSVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_XMIDYMID
:
775 case nsIDOMSVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_XMAXYMID
:
776 f
= (aViewportHeight
- a
* aViewboxHeight
) / 2.0f
;
778 case nsIDOMSVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_XMINYMAX
:
779 case nsIDOMSVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_XMIDYMAX
:
780 case nsIDOMSVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_XMAXYMAX
:
781 f
= aViewportHeight
- a
* aViewboxHeight
;
784 NS_NOTREACHED("Unknown value for align");
788 (meetOrSlice
== nsIDOMSVGPreserveAspectRatio::SVG_MEETORSLICE_MEET
&&
790 (meetOrSlice
== nsIDOMSVGPreserveAspectRatio::SVG_MEETORSLICE_SLICE
&&
794 case nsIDOMSVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_XMINYMIN
:
795 case nsIDOMSVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_XMINYMID
:
796 case nsIDOMSVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_XMINYMAX
:
798 case nsIDOMSVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_XMIDYMIN
:
799 case nsIDOMSVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_XMIDYMID
:
800 case nsIDOMSVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_XMIDYMAX
:
801 e
= (aViewportWidth
- a
* aViewboxWidth
) / 2.0f
;
803 case nsIDOMSVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_XMAXYMIN
:
804 case nsIDOMSVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_XMAXYMID
:
805 case nsIDOMSVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_XMAXYMAX
:
806 e
= aViewportWidth
- a
* aViewboxWidth
;
809 NS_NOTREACHED("Unknown value for align");
812 else NS_NOTREACHED("Unknown value for meetOrSlice");
815 if (aViewboxX
) e
+= -a
* aViewboxX
;
816 if (aViewboxY
) f
+= -d
* aViewboxY
;
818 nsIDOMSVGMatrix
*retval
;
819 NS_NewSVGMatrix(&retval
, a
, 0.0f
, 0.0f
, d
, e
, f
);
824 // This is ugly and roc will want to kill me...
826 already_AddRefed
<nsIDOMSVGMatrix
>
827 nsSVGUtils::GetCanvasTM(nsIFrame
*aFrame
)
829 if (!aFrame
->IsFrameOfType(nsIFrame::eSVG
))
830 return nsSVGIntegrationUtils::GetInitialMatrix(aFrame
);
832 if (!aFrame
->IsLeaf()) {
833 // foreignObject is the one non-leaf svg frame that isn't a SVGContainer
834 if (aFrame
->GetType() == nsGkAtoms::svgForeignObjectFrame
) {
835 nsSVGForeignObjectFrame
*foreignFrame
=
836 static_cast<nsSVGForeignObjectFrame
*>(aFrame
);
837 return foreignFrame
->GetCanvasTM();
839 nsSVGContainerFrame
*containerFrame
= static_cast<nsSVGContainerFrame
*>
841 return containerFrame
->GetCanvasTM();
844 nsSVGGeometryFrame
*geometryFrame
= static_cast<nsSVGGeometryFrame
*>
846 nsCOMPtr
<nsIDOMSVGMatrix
> matrix
;
847 nsIDOMSVGMatrix
*retval
;
848 geometryFrame
->GetCanvasTM(getter_AddRefs(matrix
));
849 retval
= matrix
.get();
850 NS_IF_ADDREF(retval
);
855 nsSVGUtils::NotifyChildrenOfSVGChange(nsIFrame
*aFrame
, PRUint32 aFlags
)
857 nsIFrame
*aKid
= aFrame
->GetFirstChild(nsnull
);
860 nsISVGChildFrame
* SVGFrame
= do_QueryFrame(aKid
);
862 SVGFrame
->NotifySVGChanged(aFlags
);
864 NS_ASSERTION(aKid
->IsFrameOfType(nsIFrame::eSVG
), "SVG frame expected");
865 // recurse into the children of container frames e.g. <clipPath>, <mask>
866 // in case they have child frames with transformation matrices
867 nsSVGUtils::NotifyChildrenOfSVGChange(aKid
, aFlags
);
869 aKid
= aKid
->GetNextSibling();
873 // ************************************************************
875 class SVGPaintCallback
: public nsSVGFilterPaintCallback
878 virtual void Paint(nsSVGRenderState
*aContext
, nsIFrame
*aTarget
,
879 const nsIntRect
* aDirtyRect
)
881 nsISVGChildFrame
*svgChildFrame
= do_QueryFrame(aTarget
);
882 NS_ASSERTION(svgChildFrame
, "Expected SVG frame here");
883 NS_ASSERTION(!svgChildFrame
->GetMatrixPropagation(),
884 "This should have been set to false already");
886 nsIntRect
* dirtyRect
= nsnull
;
887 nsIntRect tmpDirtyRect
;
889 // aDirtyRect is in user-space pixels, we need to convert to
890 // outer-SVG-frame-relative device pixels.
892 // Temporarily set SetMatrixPropagation so we can find out what
893 // the actual CTM is.
894 svgChildFrame
->SetMatrixPropagation(PR_TRUE
);
895 nsCOMPtr
<nsIDOMSVGMatrix
> ctm
= nsSVGUtils::GetCanvasTM(aTarget
);
896 NS_ASSERTION(ctm
, "graphic source didn't specify a ctm");
897 svgChildFrame
->SetMatrixPropagation(PR_FALSE
);
899 gfxMatrix matrix
= nsSVGUtils::ConvertSVGMatrixToThebes(ctm
);
900 gfxRect dirtyBounds
= matrix
.TransformBounds(
901 gfxRect(aDirtyRect
->x
, aDirtyRect
->y
, aDirtyRect
->width
, aDirtyRect
->height
));
902 dirtyBounds
.RoundOut();
903 if (NS_SUCCEEDED(nsSVGUtils::GfxRectToIntRect(dirtyBounds
, &tmpDirtyRect
))) {
904 dirtyRect
= &tmpDirtyRect
;
908 svgChildFrame
->PaintSVG(aContext
, dirtyRect
);
913 nsSVGUtils::PaintFrameWithEffects(nsSVGRenderState
*aContext
,
914 const nsIntRect
*aDirtyRect
,
917 nsISVGChildFrame
*svgChildFrame
= do_QueryFrame(aFrame
);
921 float opacity
= aFrame
->GetStyleDisplay()->mOpacity
;
925 /* Properties are added lazily and may have been removed by a restyle,
926 so make sure all applicable ones are set again. */
928 nsSVGEffects::EffectProperties effectProperties
=
929 nsSVGEffects::GetEffectProperties(aFrame
);
931 PRBool isOK
= PR_TRUE
;
932 nsSVGFilterFrame
*filterFrame
= effectProperties
.GetFilterFrame(&isOK
);
934 /* Check if we need to draw anything. HasValidCoveredRect only returns
935 * true for path geometry and glyphs, so basically we're traversing
936 * all containers and we can only skip leaves here.
938 if (aDirtyRect
&& svgChildFrame
->HasValidCoveredRect()) {
940 if (!aDirtyRect
->Intersects(filterFrame
->GetFilterBBox(aFrame
, nsnull
)))
943 nsRect rect
= nsIntRect::ToAppUnits(*aDirtyRect
, aFrame
->PresContext()->AppUnitsPerDevPixel());
944 if (!rect
.Intersects(aFrame
->GetRect()))
949 /* SVG defines the following rendering model:
953 * 3. Apply clipping, masking, group opacity
955 * We follow this, but perform a couple of optimizations:
957 * + Use cairo's clipPath when representable natively (single object
960 * + Merge opacity and masking if both used together.
963 if (opacity
!= 1.0f
&& CanOptimizeOpacity(aFrame
))
966 gfxContext
*gfx
= aContext
->GetGfxContext();
967 PRBool complexEffects
= PR_FALSE
;
969 nsSVGClipPathFrame
*clipPathFrame
= effectProperties
.GetClipPathFrame(&isOK
);
970 nsSVGMaskFrame
*maskFrame
= effectProperties
.GetMaskFrame(&isOK
);
972 PRBool isTrivialClip
= clipPathFrame
? clipPathFrame
->IsTrivial() : PR_TRUE
;
975 // Some resource is missing. We shouldn't paint anything.
979 nsCOMPtr
<nsIDOMSVGMatrix
> matrix
=
980 (clipPathFrame
|| maskFrame
) ? GetCanvasTM(aFrame
) : nsnull
;
982 /* Check if we need to do additional operations on this child's
983 * rendering, which necessitates rendering into another surface. */
984 if (opacity
!= 1.0f
|| maskFrame
|| (clipPathFrame
&& !isTrivialClip
)) {
985 complexEffects
= PR_TRUE
;
987 gfx
->PushGroup(gfxASurface::CONTENT_COLOR_ALPHA
);
990 /* If this frame has only a trivial clipPath, set up cairo's clipping now so
991 * we can just do normal painting and get it clipped appropriately.
993 if (clipPathFrame
&& isTrivialClip
) {
995 clipPathFrame
->ClipPaint(aContext
, aFrame
, matrix
);
998 /* Paint the child */
1000 SVGPaintCallback paintCallback
;
1001 filterFrame
->FilterPaint(aContext
, aFrame
, &paintCallback
, aDirtyRect
);
1003 svgChildFrame
->PaintSVG(aContext
, aDirtyRect
);
1006 if (clipPathFrame
&& isTrivialClip
) {
1010 /* No more effects, we're done. */
1011 if (!complexEffects
)
1014 gfx
->PopGroupToSource();
1016 nsRefPtr
<gfxPattern
> maskSurface
=
1017 maskFrame
? maskFrame
->ComputeMaskAlpha(aContext
, aFrame
,
1018 matrix
, opacity
) : nsnull
;
1020 nsRefPtr
<gfxPattern
> clipMaskSurface
;
1021 if (clipPathFrame
&& !isTrivialClip
) {
1022 gfx
->PushGroup(gfxASurface::CONTENT_COLOR_ALPHA
);
1024 nsresult rv
= clipPathFrame
->ClipPaint(aContext
, aFrame
, matrix
);
1025 clipMaskSurface
= gfx
->PopGroup();
1027 if (NS_SUCCEEDED(rv
) && clipMaskSurface
) {
1028 // Still more set after clipping, so clip to another surface
1029 if (maskSurface
|| opacity
!= 1.0f
) {
1030 gfx
->PushGroup(gfxASurface::CONTENT_COLOR_ALPHA
);
1031 gfx
->Mask(clipMaskSurface
);
1032 gfx
->PopGroupToSource();
1034 gfx
->Mask(clipMaskSurface
);
1040 gfx
->Mask(maskSurface
);
1041 } else if (opacity
!= 1.0f
) {
1042 gfx
->Paint(opacity
);
1049 nsSVGUtils::HitTestClip(nsIFrame
*aFrame
, const nsPoint
&aPoint
)
1051 nsSVGEffects::EffectProperties props
=
1052 nsSVGEffects::GetEffectProperties(aFrame
);
1053 if (!props
.mClipPath
)
1056 nsSVGClipPathFrame
*clipPathFrame
= props
.GetClipPathFrame(nsnull
);
1057 if (!clipPathFrame
) {
1058 // clipPath is not a valid resource, so nothing gets painted, so
1059 // hit-testing must fail.
1063 nsCOMPtr
<nsIDOMSVGMatrix
> matrix
= GetCanvasTM(aFrame
);
1064 return clipPathFrame
->ClipHitTest(aFrame
, matrix
, aPoint
);
1068 nsSVGUtils::HitTestChildren(nsIFrame
*aFrame
, const nsPoint
&aPoint
)
1070 // XXX: The frame's children are linked in a singly-linked list in document
1071 // order. If we were to hit test the children in this order we would need to
1072 // hit test *every* SVG frame, since even if we get a hit, later SVG frames
1073 // may lie on top of the matching frame. We really want to traverse SVG
1074 // frames in reverse order so we can stop at the first match. Since we don't
1075 // have a doubly-linked list, for the time being we traverse the
1076 // singly-linked list backwards by first reversing the nextSibling pointers
1077 // in place, and then restoring them when done.
1079 // Note: While the child list pointers are reversed, any method which walks
1080 // the list would only encounter a single child!
1082 nsIFrame
* current
= nsnull
;
1083 nsIFrame
* next
= aFrame
->GetFirstChild(nsnull
);
1085 nsIFrame
* result
= nsnull
;
1087 // reverse sibling pointers
1089 nsIFrame
* temp
= next
->GetNextSibling();
1090 next
->SetNextSibling(current
);
1095 // now do the backwards traversal
1097 nsISVGChildFrame
* SVGFrame
= do_QueryFrame(current
);
1099 result
= SVGFrame
->GetFrameForPoint(aPoint
);
1103 // restore current frame's sibling pointer
1104 nsIFrame
* temp
= current
->GetNextSibling();
1105 current
->SetNextSibling(next
);
1110 // restore remaining pointers
1112 nsIFrame
* temp
= current
->GetNextSibling();
1113 current
->SetNextSibling(next
);
1118 if (result
&& !HitTestClip(aFrame
, aPoint
))
1125 nsSVGUtils::GetCoveredRegion(const nsFrameList
&aFrames
)
1129 for (nsIFrame
* kid
= aFrames
.FirstChild();
1131 kid
= kid
->GetNextSibling()) {
1132 nsISVGChildFrame
* child
= do_QueryFrame(kid
);
1134 nsRect childRect
= child
->GetCoveredRegion();
1135 rect
.UnionRect(rect
, childRect
);
1143 nsSVGUtils::ToAppPixelRect(nsPresContext
*aPresContext
,
1144 double xmin
, double ymin
,
1145 double xmax
, double ymax
)
1147 return ToAppPixelRect(aPresContext
,
1148 gfxRect(xmin
, ymin
, xmax
- xmin
, ymax
- ymin
));
1152 nsSVGUtils::ToAppPixelRect(nsPresContext
*aPresContext
, const gfxRect
& rect
)
1154 return nsRect(aPresContext
->DevPixelsToAppUnits(NSToIntFloor(rect
.X())),
1155 aPresContext
->DevPixelsToAppUnits(NSToIntFloor(rect
.Y())),
1156 aPresContext
->DevPixelsToAppUnits(NSToIntCeil(rect
.XMost()) - NSToIntFloor(rect
.X())),
1157 aPresContext
->DevPixelsToAppUnits(NSToIntCeil(rect
.YMost()) - NSToIntFloor(rect
.Y())));
1161 nsSVGUtils::ConvertToSurfaceSize(const gfxSize
& aSize
, PRBool
*aResultOverflows
)
1163 gfxIntSize surfaceSize
=
1164 gfxIntSize(PRInt32(aSize
.width
+ 0.5), PRInt32(aSize
.height
+ 0.5));
1166 *aResultOverflows
= (aSize
.width
>= PR_INT32_MAX
+ 0.5 ||
1167 aSize
.height
>= PR_INT32_MAX
+ 0.5 ||
1168 aSize
.width
<= PR_INT32_MIN
- 0.5 ||
1169 aSize
.height
<= PR_INT32_MIN
- 0.5);
1171 if (*aResultOverflows
||
1172 !gfxASurface::CheckSurfaceSize(surfaceSize
)) {
1173 surfaceSize
.width
= PR_MIN(NS_SVG_OFFSCREEN_MAX_DIMENSION
,
1175 surfaceSize
.height
= PR_MIN(NS_SVG_OFFSCREEN_MAX_DIMENSION
,
1176 surfaceSize
.height
);
1177 *aResultOverflows
= PR_TRUE
;
1183 nsSVGUtils::GetThebesComputationalSurface()
1185 if (!mThebesComputationalSurface
) {
1186 nsRefPtr
<gfxImageSurface
> surface
=
1187 new gfxImageSurface(gfxIntSize(1, 1), gfxASurface::ImageFormatARGB32
);
1188 NS_ASSERTION(surface
&& !surface
->CairoStatus(),
1189 "Could not create offscreen surface");
1190 mThebesComputationalSurface
= surface
;
1191 // we want to keep this surface around
1192 NS_IF_ADDREF(mThebesComputationalSurface
);
1195 return mThebesComputationalSurface
;
1199 nsSVGUtils::ConvertSVGMatrixToThebes(nsIDOMSVGMatrix
*aMatrix
)
1201 float A
, B
, C
, D
, E
, F
;
1208 return gfxMatrix(A
, B
, C
, D
, E
, F
);
1212 nsSVGUtils::HitTestRect(nsIDOMSVGMatrix
*aMatrix
,
1213 float aRX
, float aRY
, float aRWidth
, float aRHeight
,
1216 PRBool result
= PR_TRUE
;
1219 gfxContext
ctx(GetThebesComputationalSurface());
1220 ctx
.SetMatrix(ConvertSVGMatrixToThebes(aMatrix
));
1223 ctx
.Rectangle(gfxRect(aRX
, aRY
, aRWidth
, aRHeight
));
1224 ctx
.IdentityMatrix();
1226 if (!ctx
.PointInFill(gfxPoint(aX
, aY
)))
1234 nsSVGUtils::CompositeSurfaceMatrix(gfxContext
*aContext
,
1235 gfxASurface
*aSurface
,
1236 nsIDOMSVGMatrix
*aCTM
, float aOpacity
)
1238 gfxMatrix matrix
= ConvertSVGMatrixToThebes(aCTM
);
1239 if (matrix
.IsSingular())
1244 aContext
->Multiply(matrix
);
1246 aContext
->SetSource(aSurface
);
1247 aContext
->Paint(aOpacity
);
1249 aContext
->Restore();
1253 nsSVGUtils::CompositePatternMatrix(gfxContext
*aContext
,
1254 gfxPattern
*aPattern
,
1255 nsIDOMSVGMatrix
*aCTM
, float aWidth
, float aHeight
, float aOpacity
)
1257 gfxMatrix matrix
= ConvertSVGMatrixToThebes(aCTM
);
1258 if (matrix
.IsSingular())
1263 SetClipRect(aContext
, aCTM
, 0, 0, aWidth
, aHeight
);
1265 aContext
->Multiply(matrix
);
1267 aContext
->SetPattern(aPattern
);
1268 aContext
->Paint(aOpacity
);
1270 aContext
->Restore();
1274 nsSVGUtils::SetClipRect(gfxContext
*aContext
,
1275 nsIDOMSVGMatrix
*aCTM
, float aX
, float aY
,
1276 float aWidth
, float aHeight
)
1278 gfxMatrix matrix
= ConvertSVGMatrixToThebes(aCTM
);
1279 if (matrix
.IsSingular())
1282 gfxMatrix oldMatrix
= aContext
->CurrentMatrix();
1283 aContext
->Multiply(matrix
);
1284 aContext
->Clip(gfxRect(aX
, aY
, aWidth
, aHeight
));
1285 aContext
->SetMatrix(oldMatrix
);
1289 nsSVGUtils::ClipToGfxRect(nsIntRect
* aRect
, const gfxRect
& aGfxRect
)
1291 gfxRect r
= aGfxRect
;
1293 gfxRect
r2(aRect
->x
, aRect
->y
, aRect
->width
, aRect
->height
);
1294 r
= r
.Intersect(r2
);
1295 *aRect
= nsIntRect(PRInt32(r
.X()), PRInt32(r
.Y()),
1296 PRInt32(r
.Width()), PRInt32(r
.Height()));
1300 nsSVGUtils::GfxRectToIntRect(const gfxRect
& aIn
, nsIntRect
* aOut
)
1302 *aOut
= nsIntRect(PRInt32(aIn
.X()), PRInt32(aIn
.Y()),
1303 PRInt32(aIn
.Width()), PRInt32(aIn
.Height()));
1304 return gfxRect(aOut
->x
, aOut
->y
, aOut
->width
, aOut
->height
) == aIn
1305 ? NS_OK
: NS_ERROR_FAILURE
;
1308 already_AddRefed
<nsIDOMSVGRect
>
1309 nsSVGUtils::GetBBox(nsIFrame
*aFrame
)
1311 nsISVGChildFrame
*svg
= do_QueryFrame(aFrame
);
1313 nsIDOMSVGRect
*rect
= nsnull
;
1314 gfxRect r
= nsSVGIntegrationUtils::GetSVGBBoxForNonSVGFrame(aFrame
);
1315 NS_NewSVGRect(&rect
, r
);
1319 PRBool needToDisablePropagation
= svg
->GetMatrixPropagation();
1320 if (needToDisablePropagation
) {
1321 svg
->SetMatrixPropagation(PR_FALSE
);
1322 svg
->NotifySVGChanged(nsISVGChildFrame::SUPPRESS_INVALIDATION
|
1323 nsISVGChildFrame::TRANSFORM_CHANGED
);
1326 nsCOMPtr
<nsIDOMSVGRect
> bbox
;
1327 svg
->GetBBox(getter_AddRefs(bbox
));
1329 if (needToDisablePropagation
) {
1330 svg
->SetMatrixPropagation(PR_TRUE
);
1331 svg
->NotifySVGChanged(nsISVGChildFrame::SUPPRESS_INVALIDATION
|
1332 nsISVGChildFrame::TRANSFORM_CHANGED
);
1335 return bbox
.forget();
1339 nsSVGUtils::GetRelativeRect(PRUint16 aUnits
, const nsSVGLength2
*aXYWH
,
1340 nsIDOMSVGRect
*aBBox
, nsIFrame
*aFrame
)
1342 float x
, y
, width
, height
;
1343 if (aUnits
== nsIDOMSVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX
) {
1345 x
+= ObjectSpace(aBBox
, &aXYWH
[0]);
1347 y
+= ObjectSpace(aBBox
, &aXYWH
[1]);
1348 width
= ObjectSpace(aBBox
, &aXYWH
[2]);
1349 height
= ObjectSpace(aBBox
, &aXYWH
[3]);
1351 x
= nsSVGUtils::UserSpace(aFrame
, &aXYWH
[0]);
1352 y
= nsSVGUtils::UserSpace(aFrame
, &aXYWH
[1]);
1353 width
= nsSVGUtils::UserSpace(aFrame
, &aXYWH
[2]);
1354 height
= nsSVGUtils::UserSpace(aFrame
, &aXYWH
[3]);
1356 return gfxRect(x
, y
, width
, height
);
1360 nsSVGUtils::CanOptimizeOpacity(nsIFrame
*aFrame
)
1362 if (!aFrame
->GetStyleSVGReset()->mFilter
) {
1363 nsIAtom
*type
= aFrame
->GetType();
1364 if (type
== nsGkAtoms::svgImageFrame
)
1366 if (type
== nsGkAtoms::svgPathGeometryFrame
) {
1367 const nsStyleSVG
*style
= aFrame
->GetStyleSVG();
1368 if (style
->mFill
.mType
== eStyleSVGPaintType_None
&&
1369 style
->mStroke
.mType
== eStyleSVGPaintType_None
)
1377 nsSVGUtils::MaxExpansion(nsIDOMSVGMatrix
*aMatrix
)
1385 // maximum expansion derivation from
1386 // http://lists.cairographics.org/archives/cairo/2004-October/001980.html
1387 float f
= (a
* a
+ b
* b
+ c
* c
+ d
* d
) / 2;
1388 float g
= (a
* a
+ b
* b
- c
* c
- d
* d
) / 2;
1389 float h
= a
* c
+ b
* d
;
1390 return sqrt(f
+ sqrt(g
* g
+ h
* h
));
1393 already_AddRefed
<nsIDOMSVGMatrix
>
1394 nsSVGUtils::AdjustMatrixForUnits(nsIDOMSVGMatrix
*aMatrix
,
1398 nsCOMPtr
<nsIDOMSVGMatrix
> fini
= aMatrix
;
1401 aUnits
->GetAnimValue() == nsIDOMSVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX
) {
1402 float minx
, miny
, width
, height
;
1404 PRBool gotRect
= PR_FALSE
;
1405 if (aFrame
->IsFrameOfType(nsIFrame::eSVG
)) {
1406 nsISVGChildFrame
*svgFrame
= do_QueryFrame(aFrame
);
1407 nsCOMPtr
<nsIDOMSVGRect
> rect
;
1408 svgFrame
->GetBBox(getter_AddRefs(rect
));
1413 rect
->GetWidth(&width
);
1414 rect
->GetHeight(&height
);
1415 // Correct for scaling in outersvg CTM
1416 nsPresContext
*presCtx
= aFrame
->PresContext();
1418 presCtx
->AppUnitsToGfxUnits(presCtx
->AppUnitsPerCSSPixel());
1426 gfxRect r
= nsSVGIntegrationUtils::GetSVGBBoxForNonSVGFrame(aFrame
);
1430 height
= r
.Height();
1434 nsCOMPtr
<nsIDOMSVGMatrix
> tmp
;
1435 aMatrix
->Translate(minx
, miny
, getter_AddRefs(tmp
));
1436 tmp
->ScaleNonUniform(width
, height
, getter_AddRefs(fini
));
1440 nsIDOMSVGMatrix
* retval
= fini
.get();
1441 NS_IF_ADDREF(retval
);
1447 nsSVGUtils::WritePPM(const char *fname
, gfxImageSurface
*aSurface
)
1449 FILE *f
= fopen(fname
, "wb");
1453 gfxIntSize size
= aSurface
->GetSize();
1454 fprintf(f
, "P6\n%d %d\n255\n", size
.width
, size
.height
);
1455 unsigned char *data
= aSurface
->Data();
1456 PRInt32 stride
= aSurface
->Stride();
1457 for (int y
=0; y
<size
.height
; y
++) {
1458 for (int x
=0; x
<size
.width
; x
++) {
1459 fwrite(data
+ y
* stride
+ 4 * x
+ GFX_ARGB32_OFFSET_R
, 1, 1, f
);
1460 fwrite(data
+ y
* stride
+ 4 * x
+ GFX_ARGB32_OFFSET_G
, 1, 1, f
);
1461 fwrite(data
+ y
* stride
+ 4 * x
+ GFX_ARGB32_OFFSET_B
, 1, 1, f
);
1468 // ----------------------------------------------------------------------
1470 nsSVGRenderState::nsSVGRenderState(nsIRenderingContext
*aContext
) :
1471 mRenderMode(NORMAL
), mRenderingContext(aContext
)
1473 mGfxContext
= aContext
->ThebesContext();
1476 nsSVGRenderState::nsSVGRenderState(gfxASurface
*aSurface
) :
1479 mGfxContext
= new gfxContext(aSurface
);
1482 nsIRenderingContext
*
1483 nsSVGRenderState::GetRenderingContext(nsIFrame
*aFrame
)
1485 if (!mRenderingContext
) {
1486 nsIDeviceContext
* devCtx
= aFrame
->PresContext()->DeviceContext();
1487 devCtx
->CreateRenderingContextInstance(*getter_AddRefs(mRenderingContext
));
1488 if (!mRenderingContext
)
1490 mRenderingContext
->Init(devCtx
, mGfxContext
);
1492 return mRenderingContext
;