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 "nsSVGLength.h"
38 #include "nsIDOMDocument.h"
39 #include "nsIDOMSVGElement.h"
40 #include "nsIDOMSVGSVGElement.h"
41 #include "nsStyleCoord.h"
42 #include "nsPresContext.h"
43 #include "nsSVGSVGElement.h"
44 #include "nsIContent.h"
45 #include "nsIDocument.h"
47 #include "nsGkAtoms.h"
49 #include "nsStyleStruct.h"
50 #include "nsIPresShell.h"
51 #include "nsSVGUtils.h"
52 #include "nsISVGGlyphFragmentLeaf.h"
53 #include "nsNetUtil.h"
54 #include "nsIDOMSVGRect.h"
55 #include "nsFrameList.h"
56 #include "nsISVGChildFrame.h"
57 #include "nsContentDLF.h"
58 #include "nsContentUtils.h"
59 #include "nsSVGFilterFrame.h"
60 #include "nsINameSpaceManager.h"
61 #include "nsIDOMSVGPoint.h"
62 #include "nsSVGPoint.h"
63 #include "nsDOMError.h"
64 #include "nsSVGOuterSVGFrame.h"
65 #include "nsIDOMSVGAnimPresAspRatio.h"
66 #include "nsIDOMSVGPresAspectRatio.h"
67 #include "nsSVGMatrix.h"
68 #include "nsSVGClipPathFrame.h"
69 #include "nsSVGMaskFrame.h"
70 #include "nsSVGContainerFrame.h"
71 #include "nsSVGLength2.h"
72 #include "nsGenericElement.h"
73 #include "nsAttrValue.h"
74 #include "nsSVGGeometryFrame.h"
75 #include "nsIScriptError.h"
76 #include "gfxContext.h"
77 #include "gfxMatrix.h"
79 #include "gfxImageSurface.h"
80 #include "gfxPlatform.h"
81 #include "nsSVGForeignObjectFrame.h"
82 #include "nsIFontMetrics.h"
83 #include "nsIDOMSVGUnitTypes.h"
84 #include "nsSVGRect.h"
85 #include "nsSVGEffects.h"
86 #include "nsSVGIntegrationUtils.h"
87 #include "nsSVGFilterPaintCallback.h"
89 gfxASurface
*nsSVGUtils::mThebesComputationalSurface
= nsnull
;
92 // (c <= 0.0031308 ? c * 12.92 : 1.055 * pow(c, 1 / 2.4) - 0.055) * 255 + 0.5
93 static const PRUint8 glinearRGBTosRGBMap
[256] = {
94 0, 13, 22, 28, 34, 38, 42, 46,
95 50, 53, 56, 59, 61, 64, 66, 69,
96 71, 73, 75, 77, 79, 81, 83, 85,
97 86, 88, 90, 92, 93, 95, 96, 98,
98 99, 101, 102, 104, 105, 106, 108, 109,
99 110, 112, 113, 114, 115, 117, 118, 119,
100 120, 121, 122, 124, 125, 126, 127, 128,
101 129, 130, 131, 132, 133, 134, 135, 136,
102 137, 138, 139, 140, 141, 142, 143, 144,
103 145, 146, 147, 148, 148, 149, 150, 151,
104 152, 153, 154, 155, 155, 156, 157, 158,
105 159, 159, 160, 161, 162, 163, 163, 164,
106 165, 166, 167, 167, 168, 169, 170, 170,
107 171, 172, 173, 173, 174, 175, 175, 176,
108 177, 178, 178, 179, 180, 180, 181, 182,
109 182, 183, 184, 185, 185, 186, 187, 187,
110 188, 189, 189, 190, 190, 191, 192, 192,
111 193, 194, 194, 195, 196, 196, 197, 197,
112 198, 199, 199, 200, 200, 201, 202, 202,
113 203, 203, 204, 205, 205, 206, 206, 207,
114 208, 208, 209, 209, 210, 210, 211, 212,
115 212, 213, 213, 214, 214, 215, 215, 216,
116 216, 217, 218, 218, 219, 219, 220, 220,
117 221, 221, 222, 222, 223, 223, 224, 224,
118 225, 226, 226, 227, 227, 228, 228, 229,
119 229, 230, 230, 231, 231, 232, 232, 233,
120 233, 234, 234, 235, 235, 236, 236, 237,
121 237, 238, 238, 238, 239, 239, 240, 240,
122 241, 241, 242, 242, 243, 243, 244, 244,
123 245, 245, 246, 246, 246, 247, 247, 248,
124 248, 249, 249, 250, 250, 251, 251, 251,
125 252, 252, 253, 253, 254, 254, 255, 255
129 // c <= 0.04045 ? c / 12.92 : pow((c + 0.055) / 1.055, 2.4)) * 255 + 0.5
130 static const PRUint8 gsRGBToLinearRGBMap
[256] = {
131 0, 0, 0, 0, 0, 0, 0, 1,
132 1, 1, 1, 1, 1, 1, 1, 1,
133 1, 1, 2, 2, 2, 2, 2, 2,
134 2, 2, 3, 3, 3, 3, 3, 3,
135 4, 4, 4, 4, 4, 5, 5, 5,
136 5, 6, 6, 6, 6, 7, 7, 7,
137 8, 8, 8, 8, 9, 9, 9, 10,
138 10, 10, 11, 11, 12, 12, 12, 13,
139 13, 13, 14, 14, 15, 15, 16, 16,
140 17, 17, 17, 18, 18, 19, 19, 20,
141 20, 21, 22, 22, 23, 23, 24, 24,
142 25, 25, 26, 27, 27, 28, 29, 29,
143 30, 30, 31, 32, 32, 33, 34, 35,
144 35, 36, 37, 37, 38, 39, 40, 41,
145 41, 42, 43, 44, 45, 45, 46, 47,
146 48, 49, 50, 51, 51, 52, 53, 54,
147 55, 56, 57, 58, 59, 60, 61, 62,
148 63, 64, 65, 66, 67, 68, 69, 70,
149 71, 72, 73, 74, 76, 77, 78, 79,
150 80, 81, 82, 84, 85, 86, 87, 88,
151 90, 91, 92, 93, 95, 96, 97, 99,
152 100, 101, 103, 104, 105, 107, 108, 109,
153 111, 112, 114, 115, 116, 118, 119, 121,
154 122, 124, 125, 127, 128, 130, 131, 133,
155 134, 136, 138, 139, 141, 142, 144, 146,
156 147, 149, 151, 152, 154, 156, 157, 159,
157 161, 163, 164, 166, 168, 170, 171, 173,
158 175, 177, 179, 181, 183, 184, 186, 188,
159 190, 192, 194, 196, 198, 200, 202, 204,
160 206, 208, 210, 212, 214, 216, 218, 220,
161 222, 224, 226, 229, 231, 233, 235, 237,
162 239, 242, 244, 246, 248, 250, 253, 255
165 static PRBool gSVGEnabled
;
166 static const char SVG_PREF_STR
[] = "svg.enabled";
169 SVGPrefChanged(const char *aPref
, void *aClosure
)
171 PRBool prefVal
= nsContentUtils::GetBoolPref(SVG_PREF_STR
);
172 if (prefVal
== gSVGEnabled
)
175 gSVGEnabled
= prefVal
;
177 nsContentDLF::RegisterSVG();
179 nsContentDLF::UnregisterSVG();
187 static PRBool sInitialized
= PR_FALSE
;
190 /* check and register ourselves with the pref */
191 gSVGEnabled
= nsContentUtils::GetBoolPref(SVG_PREF_STR
);
192 nsContentUtils::RegisterPrefCallback(SVG_PREF_STR
, SVGPrefChanged
, nsnull
);
194 sInitialized
= PR_TRUE
;
201 GetFrameForContent(nsIContent
* aContent
)
206 nsIDocument
*doc
= aContent
->GetCurrentDoc();
210 return nsGenericElement::GetPrimaryFrameFor(aContent
, doc
);
214 nsSVGUtils::GetFontSize(nsIContent
*aContent
)
216 nsIFrame
* frame
= GetFrameForContent(aContent
);
218 NS_WARNING("no frame in GetFontSize()");
222 return GetFontSize(frame
);
226 nsSVGUtils::GetFontSize(nsIFrame
*aFrame
)
228 return nsPresContext::AppUnitsToFloatCSSPixels(aFrame
->GetStyleFont()->mSize
) /
229 aFrame
->PresContext()->TextZoom();
233 nsSVGUtils::GetFontXHeight(nsIContent
*aContent
)
235 nsIFrame
* frame
= GetFrameForContent(aContent
);
237 NS_WARNING("no frame in GetFontXHeight()");
241 return GetFontXHeight(frame
);
245 nsSVGUtils::GetFontXHeight(nsIFrame
*aFrame
)
247 nsCOMPtr
<nsIFontMetrics
> fontMetrics
;
248 nsLayoutUtils::GetFontMetricsForFrame(aFrame
, getter_AddRefs(fontMetrics
));
251 NS_WARNING("no FontMetrics in GetFontXHeight()");
256 fontMetrics
->GetXHeight(xHeight
);
257 return nsPresContext::AppUnitsToFloatCSSPixels(xHeight
) /
258 aFrame
->PresContext()->TextZoom();
262 nsSVGUtils::UnPremultiplyImageDataAlpha(PRUint8
*data
,
264 const nsIntRect
&rect
)
266 for (PRInt32 y
= rect
.y
; y
< rect
.YMost(); y
++) {
267 for (PRInt32 x
= rect
.x
; x
< rect
.XMost(); x
++) {
268 PRUint8
*pixel
= data
+ stride
* y
+ 4 * x
;
270 PRUint8 a
= pixel
[GFX_ARGB32_OFFSET_A
];
275 pixel
[GFX_ARGB32_OFFSET_B
] = (255 * pixel
[GFX_ARGB32_OFFSET_B
]) / a
;
276 pixel
[GFX_ARGB32_OFFSET_G
] = (255 * pixel
[GFX_ARGB32_OFFSET_G
]) / a
;
277 pixel
[GFX_ARGB32_OFFSET_R
] = (255 * pixel
[GFX_ARGB32_OFFSET_R
]) / a
;
279 pixel
[GFX_ARGB32_OFFSET_B
] = 0;
280 pixel
[GFX_ARGB32_OFFSET_G
] = 0;
281 pixel
[GFX_ARGB32_OFFSET_R
] = 0;
288 nsSVGUtils::PremultiplyImageDataAlpha(PRUint8
*data
,
290 const nsIntRect
&rect
)
292 for (PRInt32 y
= rect
.y
; y
< rect
.YMost(); y
++) {
293 for (PRInt32 x
= rect
.x
; x
< rect
.XMost(); x
++) {
294 PRUint8
*pixel
= data
+ stride
* y
+ 4 * x
;
296 PRUint8 a
= pixel
[GFX_ARGB32_OFFSET_A
];
300 FAST_DIVIDE_BY_255(pixel
[GFX_ARGB32_OFFSET_B
],
301 pixel
[GFX_ARGB32_OFFSET_B
] * a
);
302 FAST_DIVIDE_BY_255(pixel
[GFX_ARGB32_OFFSET_G
],
303 pixel
[GFX_ARGB32_OFFSET_G
] * a
);
304 FAST_DIVIDE_BY_255(pixel
[GFX_ARGB32_OFFSET_R
],
305 pixel
[GFX_ARGB32_OFFSET_R
] * a
);
311 nsSVGUtils::ConvertImageDataToLinearRGB(PRUint8
*data
,
313 const nsIntRect
&rect
)
315 for (PRInt32 y
= rect
.y
; y
< rect
.YMost(); y
++) {
316 for (PRInt32 x
= rect
.x
; x
< rect
.XMost(); x
++) {
317 PRUint8
*pixel
= data
+ stride
* y
+ 4 * x
;
319 pixel
[GFX_ARGB32_OFFSET_B
] =
320 gsRGBToLinearRGBMap
[pixel
[GFX_ARGB32_OFFSET_B
]];
321 pixel
[GFX_ARGB32_OFFSET_G
] =
322 gsRGBToLinearRGBMap
[pixel
[GFX_ARGB32_OFFSET_G
]];
323 pixel
[GFX_ARGB32_OFFSET_R
] =
324 gsRGBToLinearRGBMap
[pixel
[GFX_ARGB32_OFFSET_R
]];
330 nsSVGUtils::ConvertImageDataFromLinearRGB(PRUint8
*data
,
332 const nsIntRect
&rect
)
334 for (PRInt32 y
= rect
.y
; y
< rect
.YMost(); y
++) {
335 for (PRInt32 x
= rect
.x
; x
< rect
.XMost(); x
++) {
336 PRUint8
*pixel
= data
+ stride
* y
+ 4 * x
;
338 pixel
[GFX_ARGB32_OFFSET_B
] =
339 glinearRGBTosRGBMap
[pixel
[GFX_ARGB32_OFFSET_B
]];
340 pixel
[GFX_ARGB32_OFFSET_G
] =
341 glinearRGBTosRGBMap
[pixel
[GFX_ARGB32_OFFSET_G
]];
342 pixel
[GFX_ARGB32_OFFSET_R
] =
343 glinearRGBTosRGBMap
[pixel
[GFX_ARGB32_OFFSET_R
]];
349 nsSVGUtils::ReportToConsole(nsIDocument
* doc
,
350 const char* aWarning
,
351 const PRUnichar
**aParams
,
352 PRUint32 aParamsLength
)
354 return nsContentUtils::ReportToConsole(nsContentUtils::eSVG_PROPERTIES
,
356 aParams
, aParamsLength
,
357 doc
? doc
->GetDocumentURI() : nsnull
,
359 nsIScriptError::warningFlag
,
364 nsSVGUtils::CoordToFloat(nsPresContext
*aPresContext
,
365 nsSVGElement
*aContent
,
366 const nsStyleCoord
&aCoord
)
370 switch (aCoord
.GetUnit()) {
371 case eStyleUnit_Factor
:
373 val
= aCoord
.GetFactorValue();
376 case eStyleUnit_Coord
:
377 val
= nsPresContext::AppUnitsToFloatCSSPixels(aCoord
.GetCoordValue());
380 case eStyleUnit_Percent
: {
381 nsCOMPtr
<nsISVGLength
> length
;
382 NS_NewSVGLength(getter_AddRefs(length
),
383 aCoord
.GetPercentValue() * 100.0f
,
384 nsIDOMSVGLength::SVG_LENGTHTYPE_PERCENTAGE
);
390 do_GetWeakReference(static_cast<nsGenericElement
*>(aContent
));
391 length
->SetContext(weakCtx
, nsSVGUtils::XY
);
392 length
->GetValue(&val
);
403 nsSVGUtils::GetNearestViewportElement(nsIContent
*aContent
,
404 nsIDOMSVGElement
* *aNearestViewportElement
)
406 *aNearestViewportElement
= nsnull
;
408 nsBindingManager
*bindingManager
= nsnull
;
409 // XXXbz I _think_ this is right. We want to be using the binding manager
410 // that would have attached the bindings that gives us our anonymous
411 // ancestors. That's the binding manager for the document we actually belong
412 // to, which is our owner doc.
413 nsIDocument
* ownerDoc
= aContent
->GetOwnerDoc();
415 bindingManager
= ownerDoc
->BindingManager();
418 nsCOMPtr
<nsIContent
> element
= aContent
;
419 nsCOMPtr
<nsIContent
> ancestor
;
420 unsigned short ancestorCount
= 0;
425 if (bindingManager
) {
426 // check for an anonymous ancestor first
427 ancestor
= bindingManager
->GetInsertionParent(element
);
430 // if we didn't find an anonymous ancestor, use the explicit one
431 ancestor
= element
->GetParent();
434 nsCOMPtr
<nsIDOMSVGFitToViewBox
> fitToViewBox
= do_QueryInterface(element
);
436 if (fitToViewBox
&& (ancestor
|| ancestorCount
)) {
437 // right interface and not the outermost SVG element
438 nsCOMPtr
<nsIDOMSVGElement
> SVGElement
= do_QueryInterface(element
);
439 SVGElement
.swap(*aNearestViewportElement
);
444 // reached the top of our parent chain
456 nsSVGUtils::GetFarthestViewportElement(nsIContent
*aContent
,
457 nsIDOMSVGElement
* *aFarthestViewportElement
)
459 *aFarthestViewportElement
= nsnull
;
461 nsBindingManager
*bindingManager
= nsnull
;
462 // XXXbz I _think_ this is right. We want to be using the binding manager
463 // that would have attached the bindings that gives us our anonymous
464 // ancestors. That's the binding manager for the document we actually belong
465 // to, which is our owner doc.
466 nsIDocument
* ownerDoc
= aContent
->GetOwnerDoc();
468 bindingManager
= ownerDoc
->BindingManager();
471 nsCOMPtr
<nsIContent
> element
= aContent
;
472 nsCOMPtr
<nsIContent
> ancestor
;
473 nsCOMPtr
<nsIDOMSVGElement
> SVGElement
;
474 unsigned short ancestorCount
= 0;
479 if (bindingManager
) {
480 // check for an anonymous ancestor first
481 ancestor
= bindingManager
->GetInsertionParent(element
);
484 // if we didn't find an anonymous ancestor, use the explicit one
485 ancestor
= element
->GetParent();
488 nsCOMPtr
<nsIDOMSVGFitToViewBox
> fitToViewBox
= do_QueryInterface(element
);
492 SVGElement
= do_QueryInterface(element
);
496 // reached the top of our parent chain
504 if (ancestorCount
== 0 || !SVGElement
) {
505 // outermost SVG element or no viewport found
509 SVGElement
.swap(*aFarthestViewportElement
);
514 nsSVGUtils::GetBBox(nsFrameList
*aFrames
, nsIDOMSVGRect
**_retval
)
518 float minx
, miny
, maxx
, maxy
;
519 minx
= miny
= FLT_MAX
;
520 maxx
= maxy
= -1.0 * FLT_MAX
;
522 nsCOMPtr
<nsIDOMSVGRect
> unionRect
;
524 nsIFrame
* kid
= aFrames
->FirstChild();
526 nsISVGChildFrame
* SVGFrame
= nsnull
;
527 CallQueryInterface(kid
, &SVGFrame
);
529 nsCOMPtr
<nsIDOMSVGRect
> box
;
530 SVGFrame
->GetBBox(getter_AddRefs(box
));
533 float bminx
, bminy
, bmaxx
, bmaxy
, width
, height
;
536 box
->GetWidth(&width
);
537 box
->GetHeight(&height
);
539 bmaxy
= bminy
+height
;
543 minx
= PR_MIN(minx
, bminx
);
544 miny
= PR_MIN(miny
, bminy
);
545 maxx
= PR_MAX(maxx
, bmaxx
);
546 maxy
= PR_MAX(maxy
, bmaxy
);
549 kid
= kid
->GetNextSibling();
553 unionRect
->SetX(minx
);
554 unionRect
->SetY(miny
);
555 unionRect
->SetWidth(maxx
- minx
);
556 unionRect
->SetHeight(maxy
- miny
);
557 *_retval
= unionRect
;
562 return NS_ERROR_FAILURE
;
566 nsSVGUtils::FindFilterInvalidation(nsIFrame
*aFrame
, const nsRect
& aRect
)
568 PRInt32 appUnitsPerDevPixel
= aFrame
->PresContext()->AppUnitsPerDevPixel();
570 rect
.ScaleRoundOutInverse(appUnitsPerDevPixel
);
573 if (aFrame
->GetStateBits() & NS_STATE_IS_OUTER_SVG
)
576 nsSVGFilterFrame
*filter
= nsSVGEffects::GetFilterFrame(aFrame
);
578 rect
= filter
->GetInvalidationBBox(aFrame
, rect
);
580 aFrame
= aFrame
->GetParent();
583 rect
.ScaleRoundOut(appUnitsPerDevPixel
);
588 nsSVGUtils::InvalidateCoveredRegion(nsIFrame
*aFrame
)
590 if (aFrame
->GetStateBits() & NS_STATE_SVG_NONDISPLAY_CHILD
)
593 nsSVGOuterSVGFrame
* outerSVGFrame
= nsSVGUtils::GetOuterSVGFrame(aFrame
);
594 NS_ASSERTION(outerSVGFrame
, "no outer svg frame");
596 outerSVGFrame
->InvalidateCoveredRegion(aFrame
);
600 nsSVGUtils::UpdateGraphic(nsISVGChildFrame
*aSVGFrame
)
603 CallQueryInterface(aSVGFrame
, &frame
);
605 nsSVGEffects::InvalidateRenderingObservers(frame
);
607 if (frame
->GetStateBits() & NS_STATE_SVG_NONDISPLAY_CHILD
)
610 nsSVGOuterSVGFrame
*outerSVGFrame
= nsSVGUtils::GetOuterSVGFrame(frame
);
611 if (!outerSVGFrame
) {
612 NS_ERROR("null outerSVGFrame");
616 if (outerSVGFrame
->IsRedrawSuspended()) {
617 frame
->AddStateBits(NS_STATE_SVG_DIRTY
);
619 frame
->RemoveStateBits(NS_STATE_SVG_DIRTY
);
621 PRBool changed
= outerSVGFrame
->UpdateAndInvalidateCoveredRegion(frame
);
623 NotifyAncestorsOfFilterRegionChange(frame
);
629 nsSVGUtils::NotifyAncestorsOfFilterRegionChange(nsIFrame
*aFrame
)
631 if (aFrame
->GetStateBits() & NS_STATE_IS_OUTER_SVG
) {
632 // It would be better if we couldn't get here
636 aFrame
= aFrame
->GetParent();
639 if (aFrame
->GetStateBits() & NS_STATE_IS_OUTER_SVG
)
642 nsSVGFilterProperty
*property
= nsSVGEffects::GetFilterProperty(aFrame
);
644 property
->Invalidate();
646 aFrame
= aFrame
->GetParent();
651 nsSVGUtils::ComputeNormalizedHypotenuse(double aWidth
, double aHeight
)
653 return sqrt((aWidth
*aWidth
+ aHeight
*aHeight
)/2);
657 nsSVGUtils::ObjectSpace(nsIDOMSVGRect
*aRect
, const nsSVGLength2
*aLength
)
659 float fraction
, axis
;
661 switch (aLength
->GetCtxType()) {
663 aRect
->GetWidth(&axis
);
666 aRect
->GetHeight(&axis
);
671 aRect
->GetWidth(&width
);
672 aRect
->GetHeight(&height
);
673 axis
= float(ComputeNormalizedHypotenuse(width
, height
));
677 if (aLength
->IsPercentage()) {
678 fraction
= aLength
->GetAnimValInSpecifiedUnits() / 100;
680 fraction
= aLength
->GetAnimValue(static_cast<nsSVGSVGElement
*>
683 return fraction
* axis
;
687 nsSVGUtils::UserSpace(nsSVGElement
*aSVGElement
, const nsSVGLength2
*aLength
)
689 return aLength
->GetAnimValue(aSVGElement
);
693 nsSVGUtils::UserSpace(nsIFrame
*aNonSVGContext
, const nsSVGLength2
*aLength
)
695 return aLength
->GetAnimValue(aNonSVGContext
);
699 nsSVGUtils::TransformPoint(nsIDOMSVGMatrix
*matrix
,
702 nsCOMPtr
<nsIDOMSVGPoint
> point
;
703 NS_NewSVGPoint(getter_AddRefs(point
), *x
, *y
);
707 nsCOMPtr
<nsIDOMSVGPoint
> xfpoint
;
708 point
->MatrixTransform(matrix
, getter_AddRefs(xfpoint
));
717 nsSVGUtils::AngleBisect(float a1
, float a2
)
719 float delta
= fmod(a2
- a1
, static_cast<float>(2*M_PI
));
723 /* delta is now the angle from a1 around to a2, in the range [0, 2*M_PI) */
724 float r
= a1
+ delta
/2;
726 /* the arc from a2 to a1 is smaller, so use the ray on that side */
733 nsSVGUtils::GetOuterSVGFrame(nsIFrame
*aFrame
)
736 if (aFrame
->GetStateBits() & NS_STATE_IS_OUTER_SVG
) {
737 return static_cast<nsSVGOuterSVGFrame
*>(aFrame
);
739 aFrame
= aFrame
->GetParent();
746 nsSVGUtils::GetOuterSVGFrameAndCoveredRegion(nsIFrame
* aFrame
, nsRect
* aRect
)
748 nsISVGChildFrame
* svg
;
749 CallQueryInterface(aFrame
, &svg
);
752 *aRect
= svg
->GetCoveredRegion();
753 return GetOuterSVGFrame(aFrame
);
756 already_AddRefed
<nsIDOMSVGMatrix
>
757 nsSVGUtils::GetViewBoxTransform(float aViewportWidth
, float aViewportHeight
,
758 float aViewboxX
, float aViewboxY
,
759 float aViewboxWidth
, float aViewboxHeight
,
760 nsIDOMSVGAnimatedPreserveAspectRatio
*aPreserveAspectRatio
,
763 NS_ASSERTION(aViewboxWidth
> 0, "viewBox width must be greater than zero!");
764 NS_ASSERTION(aViewboxHeight
> 0, "viewBox height must be greater than zero!");
766 PRUint16 align
, meetOrSlice
;
768 nsCOMPtr
<nsIDOMSVGPreserveAspectRatio
> par
;
769 aPreserveAspectRatio
->GetAnimVal(getter_AddRefs(par
));
770 NS_ASSERTION(par
, "could not get preserveAspectRatio");
771 par
->GetAlign(&align
);
772 par
->GetMeetOrSlice(&meetOrSlice
);
775 // default to the defaults
776 if (align
== nsIDOMSVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_UNKNOWN
)
777 align
= nsIDOMSVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_XMIDYMID
;
778 if (meetOrSlice
== nsIDOMSVGPreserveAspectRatio::SVG_MEETORSLICE_UNKNOWN
)
779 meetOrSlice
= nsIDOMSVGPreserveAspectRatio::SVG_MEETORSLICE_MEET
;
781 // alignment disabled for this matrix setup
783 align
= nsIDOMSVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_XMINYMIN
;
786 a
= aViewportWidth
/ aViewboxWidth
;
787 d
= aViewportHeight
/ aViewboxHeight
;
791 if (align
!= nsIDOMSVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_NONE
&&
793 if ((meetOrSlice
== nsIDOMSVGPreserveAspectRatio::SVG_MEETORSLICE_MEET
&&
795 (meetOrSlice
== nsIDOMSVGPreserveAspectRatio::SVG_MEETORSLICE_SLICE
&&
799 case nsIDOMSVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_XMINYMIN
:
800 case nsIDOMSVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_XMIDYMIN
:
801 case nsIDOMSVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_XMAXYMIN
:
803 case nsIDOMSVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_XMINYMID
:
804 case nsIDOMSVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_XMIDYMID
:
805 case nsIDOMSVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_XMAXYMID
:
806 f
= (aViewportHeight
- a
* aViewboxHeight
) / 2.0f
;
808 case nsIDOMSVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_XMINYMAX
:
809 case nsIDOMSVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_XMIDYMAX
:
810 case nsIDOMSVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_XMAXYMAX
:
811 f
= aViewportHeight
- a
* aViewboxHeight
;
814 NS_NOTREACHED("Unknown value for align");
818 (meetOrSlice
== nsIDOMSVGPreserveAspectRatio::SVG_MEETORSLICE_MEET
&&
820 (meetOrSlice
== nsIDOMSVGPreserveAspectRatio::SVG_MEETORSLICE_SLICE
&&
824 case nsIDOMSVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_XMINYMIN
:
825 case nsIDOMSVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_XMINYMID
:
826 case nsIDOMSVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_XMINYMAX
:
828 case nsIDOMSVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_XMIDYMIN
:
829 case nsIDOMSVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_XMIDYMID
:
830 case nsIDOMSVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_XMIDYMAX
:
831 e
= (aViewportWidth
- a
* aViewboxWidth
) / 2.0f
;
833 case nsIDOMSVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_XMAXYMIN
:
834 case nsIDOMSVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_XMAXYMID
:
835 case nsIDOMSVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_XMAXYMAX
:
836 e
= aViewportWidth
- a
* aViewboxWidth
;
839 NS_NOTREACHED("Unknown value for align");
842 else NS_NOTREACHED("Unknown value for meetOrSlice");
845 if (aViewboxX
) e
+= -a
* aViewboxX
;
846 if (aViewboxY
) f
+= -d
* aViewboxY
;
848 nsIDOMSVGMatrix
*retval
;
849 NS_NewSVGMatrix(&retval
, a
, 0.0f
, 0.0f
, d
, e
, f
);
854 // This is ugly and roc will want to kill me...
856 already_AddRefed
<nsIDOMSVGMatrix
>
857 nsSVGUtils::GetCanvasTM(nsIFrame
*aFrame
)
859 if (!aFrame
->IsFrameOfType(nsIFrame::eSVG
))
860 return nsSVGIntegrationUtils::GetInitialMatrix(aFrame
);
862 if (!aFrame
->IsLeaf()) {
863 // foreignObject is the one non-leaf svg frame that isn't a SVGContainer
864 if (aFrame
->GetType() == nsGkAtoms::svgForeignObjectFrame
) {
865 nsSVGForeignObjectFrame
*foreignFrame
=
866 static_cast<nsSVGForeignObjectFrame
*>(aFrame
);
867 return foreignFrame
->GetCanvasTM();
869 nsSVGContainerFrame
*containerFrame
= static_cast<nsSVGContainerFrame
*>
871 return containerFrame
->GetCanvasTM();
874 nsSVGGeometryFrame
*geometryFrame
= static_cast<nsSVGGeometryFrame
*>
876 nsCOMPtr
<nsIDOMSVGMatrix
> matrix
;
877 nsIDOMSVGMatrix
*retval
;
878 geometryFrame
->GetCanvasTM(getter_AddRefs(matrix
));
879 retval
= matrix
.get();
880 NS_IF_ADDREF(retval
);
885 nsSVGUtils::NotifyChildrenOfSVGChange(nsIFrame
*aFrame
, PRUint32 aFlags
)
887 nsIFrame
*aKid
= aFrame
->GetFirstChild(nsnull
);
890 nsISVGChildFrame
* SVGFrame
= nsnull
;
891 CallQueryInterface(aKid
, &SVGFrame
);
893 SVGFrame
->NotifySVGChanged(aFlags
);
895 NS_ASSERTION(aKid
->IsFrameOfType(nsIFrame::eSVG
), "SVG frame expected");
896 // recurse into the children of container frames e.g. <clipPath>, <mask>
897 // in case they have child frames with transformation matrices
898 nsSVGUtils::NotifyChildrenOfSVGChange(aKid
, aFlags
);
900 aKid
= aKid
->GetNextSibling();
905 nsSVGUtils::AddObserver(nsISupports
*aObserver
, nsISupports
*aTarget
)
907 nsISVGValueObserver
*observer
= nsnull
;
908 nsISVGValue
*v
= nsnull
;
909 CallQueryInterface(aObserver
, &observer
);
910 CallQueryInterface(aTarget
, &v
);
912 v
->AddObserver(observer
);
916 nsSVGUtils::RemoveObserver(nsISupports
*aObserver
, nsISupports
*aTarget
)
918 nsISVGValueObserver
*observer
= nsnull
;
919 nsISVGValue
*v
= nsnull
;
920 CallQueryInterface(aObserver
, &observer
);
921 CallQueryInterface(aTarget
, &v
);
923 v
->RemoveObserver(observer
);
926 // ************************************************************
928 class SVGPaintCallback
: public nsSVGFilterPaintCallback
931 virtual void Paint(nsSVGRenderState
*aContext
, nsIFrame
*aTarget
,
932 const nsIntRect
* aDirtyRect
)
934 nsISVGChildFrame
*svgChildFrame
;
935 CallQueryInterface(aTarget
, &svgChildFrame
);
936 NS_ASSERTION(svgChildFrame
, "Expected SVG frame here");
937 NS_ASSERTION(!svgChildFrame
->GetMatrixPropagation(),
938 "This should have been set to false already");
940 nsIntRect
* dirtyRect
= nsnull
;
941 nsIntRect tmpDirtyRect
;
943 // aDirtyRect is in user-space pixels, we need to convert to
944 // outer-SVG-frame-relative device pixels.
946 // Temporarily set SetMatrixPropagation so we can find out what
947 // the actual CTM is.
948 svgChildFrame
->SetMatrixPropagation(PR_TRUE
);
949 nsCOMPtr
<nsIDOMSVGMatrix
> ctm
= nsSVGUtils::GetCanvasTM(aTarget
);
950 NS_ASSERTION(ctm
, "graphic source didn't specify a ctm");
951 svgChildFrame
->SetMatrixPropagation(PR_FALSE
);
953 gfxMatrix matrix
= nsSVGUtils::ConvertSVGMatrixToThebes(ctm
);
954 gfxRect dirtyBounds
= matrix
.TransformBounds(
955 gfxRect(aDirtyRect
->x
, aDirtyRect
->y
, aDirtyRect
->width
, aDirtyRect
->height
));
956 dirtyBounds
.RoundOut();
957 if (NS_SUCCEEDED(nsSVGUtils::GfxRectToIntRect(dirtyBounds
, &tmpDirtyRect
))) {
958 dirtyRect
= &tmpDirtyRect
;
962 svgChildFrame
->PaintSVG(aContext
, dirtyRect
);
967 nsSVGUtils::PaintFrameWithEffects(nsSVGRenderState
*aContext
,
968 const nsIntRect
*aDirtyRect
,
971 nsISVGChildFrame
*svgChildFrame
;
972 CallQueryInterface(aFrame
, &svgChildFrame
);
977 float opacity
= aFrame
->GetStyleDisplay()->mOpacity
;
981 /* Properties are added lazily and may have been removed by a restyle,
982 so make sure all applicable ones are set again. */
984 nsSVGEffects::EffectProperties effectProperties
=
985 nsSVGEffects::GetEffectProperties(aFrame
);
987 PRBool isOK
= PR_TRUE
;
988 nsSVGFilterFrame
*filterFrame
= effectProperties
.GetFilterFrame(&isOK
);
990 /* Check if we need to draw anything. HasValidCoveredRect only returns
991 * true for path geometry and glyphs, so basically we're traversing
992 * all containers and we can only skip leaves here.
994 if (aDirtyRect
&& svgChildFrame
->HasValidCoveredRect()) {
996 if (!aDirtyRect
->Intersects(filterFrame
->GetFilterBBox(aFrame
, nsnull
)))
999 nsRect rect
= *aDirtyRect
;
1000 rect
.ScaleRoundOut(aFrame
->PresContext()->AppUnitsPerDevPixel());
1001 if (!rect
.Intersects(aFrame
->GetRect()))
1006 /* SVG defines the following rendering model:
1008 * 1. Render geometry
1010 * 3. Apply clipping, masking, group opacity
1012 * We follow this, but perform a couple of optimizations:
1014 * + Use cairo's clipPath when representable natively (single object
1017 * + Merge opacity and masking if both used together.
1020 if (opacity
!= 1.0f
&& CanOptimizeOpacity(aFrame
))
1023 gfxContext
*gfx
= aContext
->GetGfxContext();
1024 PRBool complexEffects
= PR_FALSE
;
1026 nsSVGClipPathFrame
*clipPathFrame
= effectProperties
.GetClipPathFrame(&isOK
);
1027 nsSVGMaskFrame
*maskFrame
= effectProperties
.GetMaskFrame(&isOK
);
1029 PRBool isTrivialClip
= clipPathFrame
? clipPathFrame
->IsTrivial() : PR_TRUE
;
1032 // Some resource is missing. We shouldn't paint anything.
1036 nsCOMPtr
<nsIDOMSVGMatrix
> matrix
=
1037 (clipPathFrame
|| maskFrame
) ? GetCanvasTM(aFrame
) : nsnull
;
1039 /* Check if we need to do additional operations on this child's
1040 * rendering, which necessitates rendering into another surface. */
1041 if (opacity
!= 1.0f
|| maskFrame
|| (clipPathFrame
&& !isTrivialClip
)) {
1042 complexEffects
= PR_TRUE
;
1044 gfx
->PushGroup(gfxASurface::CONTENT_COLOR_ALPHA
);
1047 /* If this frame has only a trivial clipPath, set up cairo's clipping now so
1048 * we can just do normal painting and get it clipped appropriately.
1050 if (clipPathFrame
&& isTrivialClip
) {
1052 clipPathFrame
->ClipPaint(aContext
, aFrame
, matrix
);
1055 /* Paint the child */
1057 SVGPaintCallback paintCallback
;
1058 filterFrame
->FilterPaint(aContext
, aFrame
, &paintCallback
, aDirtyRect
);
1060 svgChildFrame
->PaintSVG(aContext
, aDirtyRect
);
1063 if (clipPathFrame
&& isTrivialClip
) {
1067 /* No more effects, we're done. */
1068 if (!complexEffects
)
1071 gfx
->PopGroupToSource();
1073 nsRefPtr
<gfxPattern
> maskSurface
=
1074 maskFrame
? maskFrame
->ComputeMaskAlpha(aContext
, aFrame
,
1075 matrix
, opacity
) : nsnull
;
1077 nsRefPtr
<gfxPattern
> clipMaskSurface
;
1078 if (clipPathFrame
&& !isTrivialClip
) {
1079 gfx
->PushGroup(gfxASurface::CONTENT_COLOR_ALPHA
);
1081 nsresult rv
= clipPathFrame
->ClipPaint(aContext
, aFrame
, matrix
);
1082 clipMaskSurface
= gfx
->PopGroup();
1084 if (NS_SUCCEEDED(rv
) && clipMaskSurface
) {
1085 // Still more set after clipping, so clip to another surface
1086 if (maskSurface
|| opacity
!= 1.0f
) {
1087 gfx
->PushGroup(gfxASurface::CONTENT_COLOR_ALPHA
);
1088 gfx
->Mask(clipMaskSurface
);
1089 gfx
->PopGroupToSource();
1091 gfx
->Mask(clipMaskSurface
);
1097 gfx
->Mask(maskSurface
);
1098 } else if (opacity
!= 1.0f
) {
1099 gfx
->Paint(opacity
);
1106 nsSVGUtils::HitTestClip(nsIFrame
*aFrame
, const nsPoint
&aPoint
)
1108 nsSVGEffects::EffectProperties props
=
1109 nsSVGEffects::GetEffectProperties(aFrame
);
1110 if (!props
.mClipPath
)
1113 nsSVGClipPathFrame
*clipPathFrame
= props
.GetClipPathFrame(nsnull
);
1114 if (!clipPathFrame
) {
1115 // clipPath is not a valid resource, so nothing gets painted, so
1116 // hit-testing must fail.
1120 nsCOMPtr
<nsIDOMSVGMatrix
> matrix
= GetCanvasTM(aFrame
);
1121 return clipPathFrame
->ClipHitTest(aFrame
, matrix
, aPoint
);
1125 nsSVGUtils::HitTestChildren(nsIFrame
*aFrame
, const nsPoint
&aPoint
)
1127 // XXX: The frame's children are linked in a singly-linked list in document
1128 // order. If we were to hit test the children in this order we would need to
1129 // hit test *every* SVG frame, since even if we get a hit, later SVG frames
1130 // may lie on top of the matching frame. We really want to traverse SVG
1131 // frames in reverse order so we can stop at the first match. Since we don't
1132 // have a doubly-linked list, for the time being we traverse the
1133 // singly-linked list backwards by first reversing the nextSibling pointers
1134 // in place, and then restoring them when done.
1136 // Note: While the child list pointers are reversed, any method which walks
1137 // the list would only encounter a single child!
1139 nsIFrame
* current
= nsnull
;
1140 nsIFrame
* next
= aFrame
->GetFirstChild(nsnull
);
1142 nsIFrame
* result
= nsnull
;
1144 // reverse sibling pointers
1146 nsIFrame
* temp
= next
->GetNextSibling();
1147 next
->SetNextSibling(current
);
1152 // now do the backwards traversal
1154 nsISVGChildFrame
* SVGFrame
;
1155 CallQueryInterface(current
, &SVGFrame
);
1157 result
= SVGFrame
->GetFrameForPoint(aPoint
);
1161 // restore current frame's sibling pointer
1162 nsIFrame
* temp
= current
->GetNextSibling();
1163 current
->SetNextSibling(next
);
1168 // restore remaining pointers
1170 nsIFrame
* temp
= current
->GetNextSibling();
1171 current
->SetNextSibling(next
);
1176 if (result
&& !HitTestClip(aFrame
, aPoint
))
1183 nsSVGUtils::GetCoveredRegion(const nsFrameList
&aFrames
)
1187 for (nsIFrame
* kid
= aFrames
.FirstChild();
1189 kid
= kid
->GetNextSibling()) {
1190 nsISVGChildFrame
* child
= nsnull
;
1191 CallQueryInterface(kid
, &child
);
1193 nsRect childRect
= child
->GetCoveredRegion();
1194 rect
.UnionRect(rect
, childRect
);
1202 nsSVGUtils::ToAppPixelRect(nsPresContext
*aPresContext
,
1203 double xmin
, double ymin
,
1204 double xmax
, double ymax
)
1206 return ToAppPixelRect(aPresContext
,
1207 gfxRect(xmin
, ymin
, xmax
- xmin
, ymax
- ymin
));
1211 nsSVGUtils::ToAppPixelRect(nsPresContext
*aPresContext
, const gfxRect
& rect
)
1213 return nsRect(aPresContext
->DevPixelsToAppUnits(NSToIntFloor(rect
.X())),
1214 aPresContext
->DevPixelsToAppUnits(NSToIntFloor(rect
.Y())),
1215 aPresContext
->DevPixelsToAppUnits(NSToIntCeil(rect
.XMost()) - NSToIntFloor(rect
.X())),
1216 aPresContext
->DevPixelsToAppUnits(NSToIntCeil(rect
.YMost()) - NSToIntFloor(rect
.Y())));
1220 nsSVGUtils::ConvertToSurfaceSize(const gfxSize
& aSize
, PRBool
*aResultOverflows
)
1222 gfxIntSize surfaceSize
=
1223 gfxIntSize(PRInt32(aSize
.width
+ 0.5), PRInt32(aSize
.height
+ 0.5));
1225 *aResultOverflows
= (aSize
.width
>= PR_INT32_MAX
+ 0.5 ||
1226 aSize
.height
>= PR_INT32_MAX
+ 0.5 ||
1227 aSize
.width
<= PR_INT32_MIN
- 0.5 ||
1228 aSize
.height
<= PR_INT32_MIN
- 0.5);
1230 if (*aResultOverflows
||
1231 !gfxASurface::CheckSurfaceSize(surfaceSize
)) {
1232 surfaceSize
.width
= PR_MIN(NS_SVG_OFFSCREEN_MAX_DIMENSION
,
1234 surfaceSize
.height
= PR_MIN(NS_SVG_OFFSCREEN_MAX_DIMENSION
,
1235 surfaceSize
.height
);
1236 *aResultOverflows
= PR_TRUE
;
1242 nsSVGUtils::GetThebesComputationalSurface()
1244 if (!mThebesComputationalSurface
) {
1245 nsRefPtr
<gfxImageSurface
> surface
=
1246 new gfxImageSurface(gfxIntSize(1, 1), gfxASurface::ImageFormatARGB32
);
1247 NS_ASSERTION(surface
&& !surface
->CairoStatus(),
1248 "Could not create offscreen surface");
1249 mThebesComputationalSurface
= surface
;
1250 // we want to keep this surface around
1251 NS_IF_ADDREF(mThebesComputationalSurface
);
1254 return mThebesComputationalSurface
;
1258 nsSVGUtils::ConvertSVGMatrixToThebes(nsIDOMSVGMatrix
*aMatrix
)
1260 float A
, B
, C
, D
, E
, F
;
1267 return gfxMatrix(A
, B
, C
, D
, E
, F
);
1271 nsSVGUtils::HitTestRect(nsIDOMSVGMatrix
*aMatrix
,
1272 float aRX
, float aRY
, float aRWidth
, float aRHeight
,
1275 PRBool result
= PR_TRUE
;
1278 gfxContext
ctx(GetThebesComputationalSurface());
1279 ctx
.SetMatrix(ConvertSVGMatrixToThebes(aMatrix
));
1282 ctx
.Rectangle(gfxRect(aRX
, aRY
, aRWidth
, aRHeight
));
1283 ctx
.IdentityMatrix();
1285 if (!ctx
.PointInFill(gfxPoint(aX
, aY
)))
1293 nsSVGUtils::CompositeSurfaceMatrix(gfxContext
*aContext
,
1294 gfxASurface
*aSurface
,
1295 nsIDOMSVGMatrix
*aCTM
, float aOpacity
)
1297 gfxMatrix matrix
= ConvertSVGMatrixToThebes(aCTM
);
1298 if (matrix
.IsSingular())
1303 aContext
->Multiply(matrix
);
1305 aContext
->SetSource(aSurface
);
1306 aContext
->Paint(aOpacity
);
1308 aContext
->Restore();
1312 nsSVGUtils::CompositePatternMatrix(gfxContext
*aContext
,
1313 gfxPattern
*aPattern
,
1314 nsIDOMSVGMatrix
*aCTM
, float aWidth
, float aHeight
, float aOpacity
)
1316 gfxMatrix matrix
= ConvertSVGMatrixToThebes(aCTM
);
1317 if (matrix
.IsSingular())
1322 SetClipRect(aContext
, aCTM
, 0, 0, aWidth
, aHeight
);
1324 aContext
->Multiply(matrix
);
1326 aContext
->SetPattern(aPattern
);
1327 aContext
->Paint(aOpacity
);
1329 aContext
->Restore();
1333 nsSVGUtils::SetClipRect(gfxContext
*aContext
,
1334 nsIDOMSVGMatrix
*aCTM
, float aX
, float aY
,
1335 float aWidth
, float aHeight
)
1337 gfxMatrix matrix
= ConvertSVGMatrixToThebes(aCTM
);
1338 if (matrix
.IsSingular())
1341 gfxMatrix oldMatrix
= aContext
->CurrentMatrix();
1342 aContext
->Multiply(matrix
);
1343 aContext
->Clip(gfxRect(aX
, aY
, aWidth
, aHeight
));
1344 aContext
->SetMatrix(oldMatrix
);
1348 nsSVGUtils::ClipToGfxRect(nsIntRect
* aRect
, const gfxRect
& aGfxRect
)
1350 gfxRect r
= aGfxRect
;
1352 gfxRect
r2(aRect
->x
, aRect
->y
, aRect
->width
, aRect
->height
);
1353 r
= r
.Intersect(r2
);
1354 *aRect
= nsIntRect(PRInt32(r
.X()), PRInt32(r
.Y()),
1355 PRInt32(r
.Width()), PRInt32(r
.Height()));
1359 nsSVGUtils::GfxRectToIntRect(const gfxRect
& aIn
, nsIntRect
* aOut
)
1361 *aOut
= nsIntRect(PRInt32(aIn
.X()), PRInt32(aIn
.Y()),
1362 PRInt32(aIn
.Width()), PRInt32(aIn
.Height()));
1363 return gfxRect(aOut
->x
, aOut
->y
, aOut
->width
, aOut
->height
) == aIn
1364 ? NS_OK
: NS_ERROR_FAILURE
;
1367 already_AddRefed
<nsIDOMSVGRect
>
1368 nsSVGUtils::GetBBox(nsIFrame
*aFrame
)
1370 nsISVGChildFrame
*svg
;
1371 CallQueryInterface(aFrame
, &svg
);
1373 nsIDOMSVGRect
*rect
= nsnull
;
1374 gfxRect r
= nsSVGIntegrationUtils::GetSVGBBoxForNonSVGFrame(aFrame
);
1375 NS_NewSVGRect(&rect
, r
);
1379 PRBool needToDisablePropagation
= svg
->GetMatrixPropagation();
1380 if (needToDisablePropagation
) {
1381 svg
->SetMatrixPropagation(PR_FALSE
);
1382 svg
->NotifySVGChanged(nsISVGChildFrame::SUPPRESS_INVALIDATION
|
1383 nsISVGChildFrame::TRANSFORM_CHANGED
);
1386 nsCOMPtr
<nsIDOMSVGRect
> bbox
;
1387 svg
->GetBBox(getter_AddRefs(bbox
));
1389 if (needToDisablePropagation
) {
1390 svg
->SetMatrixPropagation(PR_TRUE
);
1391 svg
->NotifySVGChanged(nsISVGChildFrame::SUPPRESS_INVALIDATION
|
1392 nsISVGChildFrame::TRANSFORM_CHANGED
);
1395 return bbox
.forget();
1399 nsSVGUtils::GetRelativeRect(PRUint16 aUnits
, const nsSVGLength2
*aXYWH
,
1400 nsIDOMSVGRect
*aBBox
, nsIFrame
*aFrame
)
1402 float x
, y
, width
, height
;
1403 if (aUnits
== nsIDOMSVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX
) {
1405 x
+= ObjectSpace(aBBox
, &aXYWH
[0]);
1407 y
+= ObjectSpace(aBBox
, &aXYWH
[1]);
1408 width
= ObjectSpace(aBBox
, &aXYWH
[2]);
1409 height
= ObjectSpace(aBBox
, &aXYWH
[3]);
1411 x
= nsSVGUtils::UserSpace(aFrame
, &aXYWH
[0]);
1412 y
= nsSVGUtils::UserSpace(aFrame
, &aXYWH
[1]);
1413 width
= nsSVGUtils::UserSpace(aFrame
, &aXYWH
[2]);
1414 height
= nsSVGUtils::UserSpace(aFrame
, &aXYWH
[3]);
1416 return gfxRect(x
, y
, width
, height
);
1420 nsSVGUtils::CanOptimizeOpacity(nsIFrame
*aFrame
)
1422 if (!aFrame
->GetStyleSVGReset()->mFilter
) {
1423 nsIAtom
*type
= aFrame
->GetType();
1424 if (type
== nsGkAtoms::svgImageFrame
)
1426 if (type
== nsGkAtoms::svgPathGeometryFrame
) {
1427 const nsStyleSVG
*style
= aFrame
->GetStyleSVG();
1428 if (style
->mFill
.mType
== eStyleSVGPaintType_None
&&
1429 style
->mStroke
.mType
== eStyleSVGPaintType_None
)
1437 nsSVGUtils::MaxExpansion(nsIDOMSVGMatrix
*aMatrix
)
1445 // maximum expansion derivation from
1446 // http://lists.cairographics.org/archives/cairo/2004-October/001980.html
1447 float f
= (a
* a
+ b
* b
+ c
* c
+ d
* d
) / 2;
1448 float g
= (a
* a
+ b
* b
- c
* c
- d
* d
) / 2;
1449 float h
= a
* c
+ b
* d
;
1450 return sqrt(f
+ sqrt(g
* g
+ h
* h
));
1453 already_AddRefed
<nsIDOMSVGMatrix
>
1454 nsSVGUtils::AdjustMatrixForUnits(nsIDOMSVGMatrix
*aMatrix
,
1458 nsCOMPtr
<nsIDOMSVGMatrix
> fini
= aMatrix
;
1461 aUnits
->GetAnimValue() == nsIDOMSVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX
) {
1462 float minx
, miny
, width
, height
;
1464 PRBool gotRect
= PR_FALSE
;
1465 if (aFrame
->IsFrameOfType(nsIFrame::eSVG
)) {
1466 nsISVGChildFrame
*svgFrame
;
1467 CallQueryInterface(aFrame
, &svgFrame
);
1468 nsCOMPtr
<nsIDOMSVGRect
> rect
;
1469 svgFrame
->GetBBox(getter_AddRefs(rect
));
1474 rect
->GetWidth(&width
);
1475 rect
->GetHeight(&height
);
1476 // Correct for scaling in outersvg CTM
1477 nsPresContext
*presCtx
= aFrame
->PresContext();
1479 presCtx
->AppUnitsToGfxUnits(presCtx
->AppUnitsPerCSSPixel());
1487 gfxRect r
= nsSVGIntegrationUtils::GetSVGBBoxForNonSVGFrame(aFrame
);
1491 height
= r
.Height();
1495 nsCOMPtr
<nsIDOMSVGMatrix
> tmp
;
1496 aMatrix
->Translate(minx
, miny
, getter_AddRefs(tmp
));
1497 tmp
->ScaleNonUniform(width
, height
, getter_AddRefs(fini
));
1501 nsIDOMSVGMatrix
* retval
= fini
.get();
1502 NS_IF_ADDREF(retval
);
1508 nsSVGUtils::WritePPM(const char *fname
, gfxImageSurface
*aSurface
)
1510 FILE *f
= fopen(fname
, "wb");
1514 gfxIntSize size
= aSurface
->GetSize();
1515 fprintf(f
, "P6\n%d %d\n255\n", size
.width
, size
.height
);
1516 unsigned char *data
= aSurface
->Data();
1517 PRInt32 stride
= aSurface
->Stride();
1518 for (int y
=0; y
<size
.height
; y
++) {
1519 for (int x
=0; x
<size
.width
; x
++) {
1520 fwrite(data
+ y
* stride
+ 4 * x
+ GFX_ARGB32_OFFSET_R
, 1, 1, f
);
1521 fwrite(data
+ y
* stride
+ 4 * x
+ GFX_ARGB32_OFFSET_G
, 1, 1, f
);
1522 fwrite(data
+ y
* stride
+ 4 * x
+ GFX_ARGB32_OFFSET_B
, 1, 1, f
);
1529 // ----------------------------------------------------------------------
1531 nsSVGRenderState::nsSVGRenderState(nsIRenderingContext
*aContext
) :
1532 mRenderMode(NORMAL
), mRenderingContext(aContext
)
1534 mGfxContext
= aContext
->ThebesContext();
1537 nsSVGRenderState::nsSVGRenderState(gfxASurface
*aSurface
) :
1540 mGfxContext
= new gfxContext(aSurface
);
1543 nsIRenderingContext
*
1544 nsSVGRenderState::GetRenderingContext(nsIFrame
*aFrame
)
1546 if (!mRenderingContext
) {
1547 nsIDeviceContext
* devCtx
= aFrame
->PresContext()->DeviceContext();
1548 devCtx
->CreateRenderingContextInstance(*getter_AddRefs(mRenderingContext
));
1549 if (!mRenderingContext
)
1551 mRenderingContext
->Init(devCtx
, mGfxContext
);
1553 return mRenderingContext
;