2007-03-22 10:30:00 -07:00
|
|
|
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
|
|
|
/* ***** BEGIN LICENSE BLOCK *****
|
|
|
|
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
|
|
|
*
|
|
|
|
* The contents of this file are subject to the Mozilla Public License Version
|
|
|
|
* 1.1 (the "License"); you may not use this file except in compliance with
|
|
|
|
* the License. You may obtain a copy of the License at
|
|
|
|
* http://www.mozilla.org/MPL/
|
|
|
|
*
|
|
|
|
* Software distributed under the License is distributed on an "AS IS" basis,
|
|
|
|
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
|
|
|
* for the specific language governing rights and limitations under the
|
|
|
|
* License.
|
|
|
|
*
|
|
|
|
* The Original Code is the Mozilla SVG project.
|
|
|
|
*
|
|
|
|
* The Initial Developer of the Original Code is IBM Corporation.
|
|
|
|
* Portions created by the Initial Developer are Copyright (C) 2005
|
|
|
|
* the Initial Developer. All Rights Reserved.
|
|
|
|
*
|
|
|
|
* Contributor(s):
|
|
|
|
*
|
|
|
|
* Alternatively, the contents of this file may be used under the terms of
|
|
|
|
* either of the GNU General Public License Version 2 or later (the "GPL"),
|
|
|
|
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
|
|
|
* in which case the provisions of the GPL or the LGPL are applicable instead
|
|
|
|
* of those above. If you wish to allow use of your version of this file only
|
|
|
|
* under the terms of either the GPL or the LGPL, and not to allow others to
|
|
|
|
* use your version of this file under the terms of the MPL, indicate your
|
|
|
|
* decision by deleting the provisions above and replace them with the notice
|
|
|
|
* and other provisions required by the GPL or the LGPL. If you do not delete
|
|
|
|
* the provisions above, a recipient may use your version of this file under
|
|
|
|
* the terms of any one of the MPL, the GPL or the LGPL.
|
|
|
|
*
|
|
|
|
* ***** END LICENSE BLOCK ***** */
|
|
|
|
|
|
|
|
#include "nsSVGLength.h"
|
|
|
|
#include "nsIDOMDocument.h"
|
|
|
|
#include "nsIDOMSVGElement.h"
|
|
|
|
#include "nsIDOMSVGSVGElement.h"
|
|
|
|
#include "nsStyleCoord.h"
|
|
|
|
#include "nsPresContext.h"
|
|
|
|
#include "nsSVGSVGElement.h"
|
|
|
|
#include "nsIContent.h"
|
|
|
|
#include "nsIDocument.h"
|
|
|
|
#include "nsIFrame.h"
|
|
|
|
#include "nsGkAtoms.h"
|
|
|
|
#include "nsIURI.h"
|
|
|
|
#include "nsStyleStruct.h"
|
|
|
|
#include "nsIPresShell.h"
|
|
|
|
#include "nsSVGUtils.h"
|
|
|
|
#include "nsISVGGlyphFragmentLeaf.h"
|
|
|
|
#include "nsNetUtil.h"
|
|
|
|
#include "nsIDOMSVGRect.h"
|
|
|
|
#include "nsFrameList.h"
|
|
|
|
#include "nsISVGChildFrame.h"
|
|
|
|
#include "nsContentDLF.h"
|
|
|
|
#include "nsContentUtils.h"
|
|
|
|
#include "nsSVGFilterFrame.h"
|
|
|
|
#include "nsINameSpaceManager.h"
|
|
|
|
#include "nsIDOMSVGPoint.h"
|
|
|
|
#include "nsSVGPoint.h"
|
|
|
|
#include "nsDOMError.h"
|
|
|
|
#include "nsSVGOuterSVGFrame.h"
|
|
|
|
#include "nsIDOMSVGAnimPresAspRatio.h"
|
|
|
|
#include "nsIDOMSVGPresAspectRatio.h"
|
|
|
|
#include "nsSVGMatrix.h"
|
|
|
|
#include "nsSVGClipPathFrame.h"
|
|
|
|
#include "nsSVGMaskFrame.h"
|
|
|
|
#include "nsSVGContainerFrame.h"
|
|
|
|
#include "nsSVGLength2.h"
|
|
|
|
#include "nsGenericElement.h"
|
|
|
|
#include "nsAttrValue.h"
|
|
|
|
#include "nsSVGGeometryFrame.h"
|
|
|
|
#include "nsIScriptError.h"
|
|
|
|
#include "gfxContext.h"
|
|
|
|
#include "gfxMatrix.h"
|
|
|
|
#include "gfxRect.h"
|
|
|
|
#include "gfxImageSurface.h"
|
|
|
|
#include "nsStubMutationObserver.h"
|
2007-04-18 14:09:31 -07:00
|
|
|
#include "gfxPlatform.h"
|
2007-05-16 08:14:19 -07:00
|
|
|
#include "nsSVGForeignObjectFrame.h"
|
2007-06-25 09:12:35 -07:00
|
|
|
#include "nsIFontMetrics.h"
|
2007-12-03 20:40:52 -08:00
|
|
|
#include "nsIDOMSVGUnitTypes.h"
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2007-12-03 08:57:34 -08:00
|
|
|
static void AddEffectProperties(nsIFrame *aFrame);
|
|
|
|
|
2007-04-26 01:36:16 -07:00
|
|
|
class nsSVGPropertyBase : public nsStubMutationObserver {
|
2007-03-22 10:30:00 -07:00
|
|
|
public:
|
2007-04-26 01:36:16 -07:00
|
|
|
nsSVGPropertyBase(nsIContent *aContent, nsIFrame *aFrame, nsIAtom *aName);
|
|
|
|
virtual ~nsSVGPropertyBase();
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
// nsISupports
|
|
|
|
NS_DECL_ISUPPORTS
|
|
|
|
|
|
|
|
// nsIMutationObserver
|
2007-04-27 07:37:15 -07:00
|
|
|
NS_DECL_NSIMUTATIONOBSERVER_ATTRIBUTECHANGED
|
|
|
|
NS_DECL_NSIMUTATIONOBSERVER_CONTENTAPPENDED
|
|
|
|
NS_DECL_NSIMUTATIONOBSERVER_CONTENTINSERTED
|
|
|
|
NS_DECL_NSIMUTATIONOBSERVER_CONTENTREMOVED
|
2007-04-26 01:36:16 -07:00
|
|
|
|
|
|
|
protected:
|
|
|
|
virtual void DoUpdate() = 0;
|
|
|
|
|
|
|
|
nsWeakPtr mObservedContent;
|
|
|
|
nsIFrame *mFrame;
|
|
|
|
};
|
|
|
|
|
|
|
|
NS_IMPL_ISUPPORTS1(nsSVGPropertyBase, nsIMutationObserver)
|
|
|
|
|
|
|
|
nsSVGPropertyBase::nsSVGPropertyBase(nsIContent *aContent,
|
|
|
|
nsIFrame *aFrame,
|
|
|
|
nsIAtom *aName)
|
|
|
|
: mFrame(aFrame)
|
|
|
|
{
|
|
|
|
mObservedContent = do_GetWeakReference(aContent);
|
|
|
|
aContent->AddMutationObserver(this);
|
|
|
|
|
|
|
|
NS_ADDREF(this); // addref to allow QI - SupportsDtorFunc releases
|
|
|
|
mFrame->SetProperty(aName,
|
2007-07-08 00:08:04 -07:00
|
|
|
static_cast<nsISupports*>(this),
|
2007-04-26 01:36:16 -07:00
|
|
|
nsPropertyTable::SupportsDtorFunc);
|
|
|
|
}
|
|
|
|
|
|
|
|
nsSVGPropertyBase::~nsSVGPropertyBase()
|
|
|
|
{
|
|
|
|
nsCOMPtr<nsIContent> content = do_QueryReferent(mObservedContent);
|
|
|
|
if (content)
|
|
|
|
content->RemoveMutationObserver(this);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
nsSVGPropertyBase::AttributeChanged(nsIDocument *aDocument,
|
|
|
|
nsIContent *aContent,
|
|
|
|
PRInt32 aNameSpaceID,
|
|
|
|
nsIAtom *aAttribute,
|
2007-07-12 13:05:45 -07:00
|
|
|
PRInt32 aModType,
|
|
|
|
PRUint32 aStateMask)
|
2007-04-26 01:36:16 -07:00
|
|
|
{
|
|
|
|
DoUpdate();
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
nsSVGPropertyBase::ContentAppended(nsIDocument *aDocument,
|
|
|
|
nsIContent *aContainer,
|
|
|
|
PRInt32 aNewIndexInContainer)
|
|
|
|
{
|
|
|
|
DoUpdate();
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
nsSVGPropertyBase::ContentInserted(nsIDocument *aDocument,
|
|
|
|
nsIContent *aContainer,
|
|
|
|
nsIContent *aChild,
|
|
|
|
PRInt32 aIndexInContainer)
|
|
|
|
{
|
|
|
|
DoUpdate();
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
nsSVGPropertyBase::ContentRemoved(nsIDocument *aDocument,
|
|
|
|
nsIContent *aContainer,
|
|
|
|
nsIContent *aChild,
|
|
|
|
PRInt32 aIndexInContainer)
|
|
|
|
{
|
|
|
|
DoUpdate();
|
|
|
|
}
|
|
|
|
|
|
|
|
class nsSVGFilterProperty : public nsSVGPropertyBase {
|
|
|
|
public:
|
|
|
|
nsSVGFilterProperty(nsIContent *aFilter, nsIFrame *aFilteredFrame);
|
|
|
|
virtual ~nsSVGFilterProperty() {
|
|
|
|
mFrame->RemoveStateBits(NS_STATE_SVG_FILTERED);
|
|
|
|
}
|
|
|
|
|
|
|
|
nsRect GetRect() { return mFilterRect; }
|
|
|
|
nsSVGFilterFrame *GetFilterFrame();
|
2007-05-29 17:36:02 -07:00
|
|
|
void UpdateRect();
|
2007-04-26 01:36:16 -07:00
|
|
|
|
|
|
|
// nsIMutationObserver
|
2007-04-27 07:37:15 -07:00
|
|
|
NS_DECL_NSIMUTATIONOBSERVER_PARENTCHAINCHANGED
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
private:
|
2007-04-26 01:36:16 -07:00
|
|
|
// nsSVGPropertyBase
|
|
|
|
virtual void DoUpdate();
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
nsRect mFilterRect;
|
|
|
|
};
|
|
|
|
|
2007-04-05 06:23:21 -07:00
|
|
|
nsSVGFilterProperty::nsSVGFilterProperty(nsIContent *aFilter,
|
|
|
|
nsIFrame *aFilteredFrame)
|
2007-04-26 01:36:16 -07:00
|
|
|
: nsSVGPropertyBase(aFilter, aFilteredFrame, nsGkAtoms::filter)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
2007-04-26 01:36:16 -07:00
|
|
|
nsSVGFilterFrame *filterFrame = GetFilterFrame();
|
|
|
|
if (filterFrame)
|
|
|
|
mFilterRect = filterFrame->GetInvalidationRegion(mFrame);
|
2007-04-05 06:23:21 -07:00
|
|
|
|
2007-04-26 01:36:16 -07:00
|
|
|
mFrame->AddStateBits(NS_STATE_SVG_FILTERED);
|
2007-04-05 06:23:21 -07:00
|
|
|
}
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2007-04-05 06:23:21 -07:00
|
|
|
nsSVGFilterFrame *
|
|
|
|
nsSVGFilterProperty::GetFilterFrame()
|
|
|
|
{
|
2007-04-26 01:36:16 -07:00
|
|
|
nsCOMPtr<nsIContent> filter = do_QueryReferent(mObservedContent);
|
2007-04-05 06:23:21 -07:00
|
|
|
if (filter) {
|
|
|
|
nsIFrame *frame =
|
2007-07-08 00:08:04 -07:00
|
|
|
static_cast<nsGenericElement*>(filter.get())->GetPrimaryFrame();
|
2007-04-05 06:23:21 -07:00
|
|
|
if (frame && frame->GetType() == nsGkAtoms::svgFilterFrame)
|
2007-07-08 00:08:04 -07:00
|
|
|
return static_cast<nsSVGFilterFrame*>(frame);
|
2007-04-05 06:23:21 -07:00
|
|
|
}
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2007-04-05 06:23:21 -07:00
|
|
|
return nsnull;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
2007-05-29 17:36:02 -07:00
|
|
|
void
|
|
|
|
nsSVGFilterProperty::UpdateRect()
|
|
|
|
{
|
|
|
|
nsSVGFilterFrame *filter = GetFilterFrame();
|
|
|
|
if (filter)
|
|
|
|
mFilterRect = filter->GetInvalidationRegion(mFrame);
|
|
|
|
}
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
void
|
|
|
|
nsSVGFilterProperty::DoUpdate()
|
|
|
|
{
|
|
|
|
nsSVGOuterSVGFrame *outerSVGFrame = nsSVGUtils::GetOuterSVGFrame(mFrame);
|
|
|
|
if (outerSVGFrame) {
|
|
|
|
outerSVGFrame->InvalidateRect(mFilterRect);
|
2007-05-29 17:36:02 -07:00
|
|
|
UpdateRect();
|
|
|
|
outerSVGFrame->InvalidateRect(mFilterRect);
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2007-04-26 01:36:16 -07:00
|
|
|
nsSVGFilterProperty::ParentChainChanged(nsIContent *aContent)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
2007-04-26 01:36:16 -07:00
|
|
|
if (aContent->IsInDoc())
|
|
|
|
return;
|
|
|
|
|
|
|
|
nsSVGOuterSVGFrame *outerSVGFrame = nsSVGUtils::GetOuterSVGFrame(mFrame);
|
|
|
|
if (outerSVGFrame)
|
|
|
|
outerSVGFrame->InvalidateRect(mFilterRect);
|
|
|
|
|
|
|
|
mFrame->DeleteProperty(nsGkAtoms::filter);
|
|
|
|
}
|
|
|
|
|
|
|
|
class nsSVGClipPathProperty : public nsSVGPropertyBase {
|
|
|
|
public:
|
|
|
|
nsSVGClipPathProperty(nsIContent *aClipPath, nsIFrame *aClippedFrame)
|
|
|
|
: nsSVGPropertyBase(aClipPath, aClippedFrame, nsGkAtoms::clipPath) {
|
|
|
|
mFrame->AddStateBits(NS_STATE_SVG_CLIPPED);
|
|
|
|
}
|
|
|
|
virtual ~nsSVGClipPathProperty() {
|
|
|
|
mFrame->RemoveStateBits(NS_STATE_SVG_CLIPPED);
|
|
|
|
}
|
|
|
|
|
|
|
|
nsSVGClipPathFrame *GetClipPathFrame();
|
|
|
|
|
|
|
|
// nsIMutationObserver
|
2007-04-27 07:37:15 -07:00
|
|
|
NS_DECL_NSIMUTATIONOBSERVER_PARENTCHAINCHANGED
|
2007-04-26 01:36:16 -07:00
|
|
|
|
|
|
|
private:
|
|
|
|
virtual void DoUpdate();
|
|
|
|
};
|
|
|
|
|
|
|
|
nsSVGClipPathFrame *
|
|
|
|
nsSVGClipPathProperty::GetClipPathFrame()
|
|
|
|
{
|
|
|
|
nsCOMPtr<nsIContent> clipPath = do_QueryReferent(mObservedContent);
|
|
|
|
if (clipPath) {
|
|
|
|
nsIFrame *frame =
|
2007-07-08 00:08:04 -07:00
|
|
|
static_cast<nsGenericElement*>(clipPath.get())->GetPrimaryFrame();
|
2007-04-26 01:36:16 -07:00
|
|
|
if (frame && frame->GetType() == nsGkAtoms::svgClipPathFrame)
|
2007-07-08 00:08:04 -07:00
|
|
|
return static_cast<nsSVGClipPathFrame*>(frame);
|
2007-04-26 01:36:16 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
return nsnull;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2007-04-26 01:36:16 -07:00
|
|
|
nsSVGClipPathProperty::DoUpdate()
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
2007-04-26 01:36:16 -07:00
|
|
|
nsISVGChildFrame *svgChildFrame;
|
|
|
|
CallQueryInterface(mFrame, &svgChildFrame);
|
|
|
|
|
|
|
|
if (!svgChildFrame)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (svgChildFrame->HasValidCoveredRect()) {
|
|
|
|
nsSVGOuterSVGFrame *outerSVGFrame = nsSVGUtils::GetOuterSVGFrame(mFrame);
|
|
|
|
if (outerSVGFrame)
|
|
|
|
outerSVGFrame->InvalidateRect(mFrame->GetRect());
|
|
|
|
}
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2007-04-26 01:36:16 -07:00
|
|
|
nsSVGClipPathProperty::ParentChainChanged(nsIContent *aContent)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
2007-04-26 01:36:16 -07:00
|
|
|
if (aContent->IsInDoc())
|
|
|
|
return;
|
|
|
|
|
|
|
|
mFrame->DeleteProperty(nsGkAtoms::clipPath);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
class nsSVGMaskProperty : public nsSVGPropertyBase {
|
|
|
|
public:
|
|
|
|
nsSVGMaskProperty(nsIContent *aMask, nsIFrame *aMaskedFrame)
|
|
|
|
: nsSVGPropertyBase(aMask, aMaskedFrame, nsGkAtoms::mask) {
|
|
|
|
mFrame->AddStateBits(NS_STATE_SVG_MASKED);
|
|
|
|
}
|
|
|
|
virtual ~nsSVGMaskProperty() {
|
|
|
|
mFrame->RemoveStateBits(NS_STATE_SVG_MASKED);
|
|
|
|
}
|
|
|
|
|
|
|
|
nsSVGMaskFrame *GetMaskFrame();
|
|
|
|
|
|
|
|
// nsIMutationObserver
|
2007-04-27 07:37:15 -07:00
|
|
|
NS_DECL_NSIMUTATIONOBSERVER_PARENTCHAINCHANGED
|
2007-04-26 01:36:16 -07:00
|
|
|
|
|
|
|
private:
|
|
|
|
virtual void DoUpdate();
|
|
|
|
};
|
|
|
|
|
|
|
|
nsSVGMaskFrame *
|
|
|
|
nsSVGMaskProperty::GetMaskFrame()
|
|
|
|
{
|
|
|
|
nsCOMPtr<nsIContent> mask = do_QueryReferent(mObservedContent);
|
|
|
|
if (mask) {
|
|
|
|
nsIFrame *frame =
|
2007-07-08 00:08:04 -07:00
|
|
|
static_cast<nsGenericElement*>(mask.get())->GetPrimaryFrame();
|
2007-04-26 01:36:16 -07:00
|
|
|
if (frame && frame->GetType() == nsGkAtoms::svgMaskFrame)
|
2007-07-08 00:08:04 -07:00
|
|
|
return static_cast<nsSVGMaskFrame*>(frame);
|
2007-04-26 01:36:16 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
return nsnull;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2007-04-26 01:36:16 -07:00
|
|
|
nsSVGMaskProperty::DoUpdate()
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
2007-04-26 01:36:16 -07:00
|
|
|
nsISVGChildFrame *svgChildFrame;
|
|
|
|
CallQueryInterface(mFrame, &svgChildFrame);
|
|
|
|
|
|
|
|
if (!svgChildFrame)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (svgChildFrame->HasValidCoveredRect()) {
|
|
|
|
nsSVGOuterSVGFrame *outerSVGFrame = nsSVGUtils::GetOuterSVGFrame(mFrame);
|
|
|
|
if (outerSVGFrame)
|
|
|
|
outerSVGFrame->InvalidateRect(mFrame->GetRect());
|
|
|
|
}
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2007-04-26 01:36:16 -07:00
|
|
|
nsSVGMaskProperty::ParentChainChanged(nsIContent *aContent)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
|
|
|
if (aContent->IsInDoc())
|
|
|
|
return;
|
|
|
|
|
2007-04-26 01:36:16 -07:00
|
|
|
mFrame->DeleteProperty(nsGkAtoms::mask);
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
gfxASurface *nsSVGUtils::mThebesComputationalSurface = nsnull;
|
|
|
|
|
|
|
|
// c = n / 255
|
|
|
|
// (c <= 0.0031308 ? c * 12.92 : 1.055 * pow(c, 1 / 2.4) - 0.055) * 255 + 0.5
|
|
|
|
static const PRUint8 glinearRGBTosRGBMap[256] = {
|
|
|
|
0, 13, 22, 28, 34, 38, 42, 46,
|
|
|
|
50, 53, 56, 59, 61, 64, 66, 69,
|
|
|
|
71, 73, 75, 77, 79, 81, 83, 85,
|
|
|
|
86, 88, 90, 92, 93, 95, 96, 98,
|
|
|
|
99, 101, 102, 104, 105, 106, 108, 109,
|
|
|
|
110, 112, 113, 114, 115, 117, 118, 119,
|
|
|
|
120, 121, 122, 124, 125, 126, 127, 128,
|
|
|
|
129, 130, 131, 132, 133, 134, 135, 136,
|
|
|
|
137, 138, 139, 140, 141, 142, 143, 144,
|
|
|
|
145, 146, 147, 148, 148, 149, 150, 151,
|
|
|
|
152, 153, 154, 155, 155, 156, 157, 158,
|
|
|
|
159, 159, 160, 161, 162, 163, 163, 164,
|
|
|
|
165, 166, 167, 167, 168, 169, 170, 170,
|
|
|
|
171, 172, 173, 173, 174, 175, 175, 176,
|
|
|
|
177, 178, 178, 179, 180, 180, 181, 182,
|
|
|
|
182, 183, 184, 185, 185, 186, 187, 187,
|
|
|
|
188, 189, 189, 190, 190, 191, 192, 192,
|
|
|
|
193, 194, 194, 195, 196, 196, 197, 197,
|
|
|
|
198, 199, 199, 200, 200, 201, 202, 202,
|
|
|
|
203, 203, 204, 205, 205, 206, 206, 207,
|
|
|
|
208, 208, 209, 209, 210, 210, 211, 212,
|
|
|
|
212, 213, 213, 214, 214, 215, 215, 216,
|
|
|
|
216, 217, 218, 218, 219, 219, 220, 220,
|
|
|
|
221, 221, 222, 222, 223, 223, 224, 224,
|
|
|
|
225, 226, 226, 227, 227, 228, 228, 229,
|
|
|
|
229, 230, 230, 231, 231, 232, 232, 233,
|
|
|
|
233, 234, 234, 235, 235, 236, 236, 237,
|
|
|
|
237, 238, 238, 238, 239, 239, 240, 240,
|
|
|
|
241, 241, 242, 242, 243, 243, 244, 244,
|
|
|
|
245, 245, 246, 246, 246, 247, 247, 248,
|
|
|
|
248, 249, 249, 250, 250, 251, 251, 251,
|
|
|
|
252, 252, 253, 253, 254, 254, 255, 255
|
|
|
|
};
|
|
|
|
|
|
|
|
// c = n / 255
|
|
|
|
// c <= 0.04045 ? c / 12.92 : pow((c + 0.055) / 1.055, 2.4)) * 255 + 0.5
|
|
|
|
static const PRUint8 gsRGBToLinearRGBMap[256] = {
|
|
|
|
0, 0, 0, 0, 0, 0, 0, 1,
|
|
|
|
1, 1, 1, 1, 1, 1, 1, 1,
|
|
|
|
1, 1, 2, 2, 2, 2, 2, 2,
|
|
|
|
2, 2, 3, 3, 3, 3, 3, 3,
|
|
|
|
4, 4, 4, 4, 4, 5, 5, 5,
|
|
|
|
5, 6, 6, 6, 6, 7, 7, 7,
|
|
|
|
8, 8, 8, 8, 9, 9, 9, 10,
|
|
|
|
10, 10, 11, 11, 12, 12, 12, 13,
|
|
|
|
13, 13, 14, 14, 15, 15, 16, 16,
|
|
|
|
17, 17, 17, 18, 18, 19, 19, 20,
|
|
|
|
20, 21, 22, 22, 23, 23, 24, 24,
|
|
|
|
25, 25, 26, 27, 27, 28, 29, 29,
|
|
|
|
30, 30, 31, 32, 32, 33, 34, 35,
|
|
|
|
35, 36, 37, 37, 38, 39, 40, 41,
|
|
|
|
41, 42, 43, 44, 45, 45, 46, 47,
|
|
|
|
48, 49, 50, 51, 51, 52, 53, 54,
|
|
|
|
55, 56, 57, 58, 59, 60, 61, 62,
|
|
|
|
63, 64, 65, 66, 67, 68, 69, 70,
|
|
|
|
71, 72, 73, 74, 76, 77, 78, 79,
|
|
|
|
80, 81, 82, 84, 85, 86, 87, 88,
|
|
|
|
90, 91, 92, 93, 95, 96, 97, 99,
|
|
|
|
100, 101, 103, 104, 105, 107, 108, 109,
|
|
|
|
111, 112, 114, 115, 116, 118, 119, 121,
|
|
|
|
122, 124, 125, 127, 128, 130, 131, 133,
|
|
|
|
134, 136, 138, 139, 141, 142, 144, 146,
|
|
|
|
147, 149, 151, 152, 154, 156, 157, 159,
|
|
|
|
161, 163, 164, 166, 168, 170, 171, 173,
|
|
|
|
175, 177, 179, 181, 183, 184, 186, 188,
|
|
|
|
190, 192, 194, 196, 198, 200, 202, 204,
|
|
|
|
206, 208, 210, 212, 214, 216, 218, 220,
|
|
|
|
222, 224, 226, 229, 231, 233, 235, 237,
|
|
|
|
239, 242, 244, 246, 248, 250, 253, 255
|
|
|
|
};
|
|
|
|
|
|
|
|
static PRBool gSVGEnabled;
|
|
|
|
static const char SVG_PREF_STR[] = "svg.enabled";
|
|
|
|
|
|
|
|
PR_STATIC_CALLBACK(int)
|
|
|
|
SVGPrefChanged(const char *aPref, void *aClosure)
|
|
|
|
{
|
|
|
|
PRBool prefVal = nsContentUtils::GetBoolPref(SVG_PREF_STR);
|
|
|
|
if (prefVal == gSVGEnabled)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
gSVGEnabled = prefVal;
|
|
|
|
if (gSVGEnabled)
|
|
|
|
nsContentDLF::RegisterSVG();
|
|
|
|
else
|
|
|
|
nsContentDLF::UnregisterSVG();
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
PRBool
|
|
|
|
NS_SVGEnabled()
|
|
|
|
{
|
|
|
|
static PRBool sInitialized = PR_FALSE;
|
|
|
|
|
|
|
|
if (!sInitialized) {
|
|
|
|
/* check and register ourselves with the pref */
|
|
|
|
gSVGEnabled = nsContentUtils::GetBoolPref(SVG_PREF_STR);
|
|
|
|
nsContentUtils::RegisterPrefCallback(SVG_PREF_STR, SVGPrefChanged, nsnull);
|
|
|
|
|
|
|
|
sInitialized = PR_TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
return gSVGEnabled;
|
|
|
|
}
|
|
|
|
|
2007-08-17 16:49:01 -07:00
|
|
|
static nsIFrame*
|
|
|
|
GetFrameForContent(nsIContent* aContent)
|
2007-06-25 09:12:35 -07:00
|
|
|
{
|
2007-08-17 16:49:01 -07:00
|
|
|
if (!aContent)
|
|
|
|
return nsnull;
|
2007-06-25 09:12:35 -07:00
|
|
|
|
2007-08-17 16:49:01 -07:00
|
|
|
nsIDocument *doc = aContent->GetCurrentDoc();
|
|
|
|
if (!doc)
|
|
|
|
return nsnull;
|
2007-07-06 02:02:44 -07:00
|
|
|
|
2007-08-17 16:49:01 -07:00
|
|
|
return nsGenericElement::GetPrimaryFrameFor(aContent, doc);
|
2007-06-25 09:12:35 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
float
|
|
|
|
nsSVGUtils::GetFontSize(nsIContent *aContent)
|
|
|
|
{
|
2007-08-17 16:49:01 -07:00
|
|
|
nsIFrame* frame = GetFrameForContent(aContent);
|
|
|
|
if (!frame) {
|
|
|
|
NS_WARNING("no frame in GetFontSize()");
|
2007-06-25 09:12:35 -07:00
|
|
|
return 1.0f;
|
|
|
|
}
|
|
|
|
|
2007-08-17 16:49:01 -07:00
|
|
|
return nsPresContext::AppUnitsToFloatCSSPixels(frame->GetStyleFont()->mSize) /
|
|
|
|
frame->PresContext()->TextZoom();
|
2007-06-25 09:12:35 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
float
|
|
|
|
nsSVGUtils::GetFontXHeight(nsIContent *aContent)
|
|
|
|
{
|
2007-08-17 16:49:01 -07:00
|
|
|
nsIFrame* frame = GetFrameForContent(aContent);
|
|
|
|
if (!frame) {
|
|
|
|
NS_WARNING("no frame in GetFontXHeight()");
|
2007-06-25 09:12:35 -07:00
|
|
|
return 1.0f;
|
|
|
|
}
|
|
|
|
|
2007-08-17 16:49:01 -07:00
|
|
|
nsCOMPtr<nsIFontMetrics> fontMetrics;
|
|
|
|
nsLayoutUtils::GetFontMetricsForFrame(frame, getter_AddRefs(fontMetrics));
|
2007-06-25 09:12:35 -07:00
|
|
|
|
|
|
|
if (!fontMetrics) {
|
|
|
|
NS_WARNING("no FontMetrics in GetFontXHeight()");
|
|
|
|
return 1.0f;
|
|
|
|
}
|
|
|
|
|
|
|
|
nscoord xHeight;
|
|
|
|
fontMetrics->GetXHeight(xHeight);
|
2007-08-17 16:49:01 -07:00
|
|
|
return nsPresContext::AppUnitsToFloatCSSPixels(xHeight) /
|
|
|
|
frame->PresContext()->TextZoom();
|
2007-06-25 09:12:35 -07:00
|
|
|
}
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
void
|
|
|
|
nsSVGUtils::UnPremultiplyImageDataAlpha(PRUint8 *data,
|
|
|
|
PRInt32 stride,
|
|
|
|
const nsRect &rect)
|
|
|
|
{
|
|
|
|
for (PRInt32 y = rect.y; y < rect.YMost(); y++) {
|
|
|
|
for (PRInt32 x = rect.x; x < rect.XMost(); x++) {
|
|
|
|
PRUint8 *pixel = data + stride * y + 4 * x;
|
|
|
|
|
|
|
|
PRUint8 a = pixel[GFX_ARGB32_OFFSET_A];
|
|
|
|
if (a == 255)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (a) {
|
|
|
|
pixel[GFX_ARGB32_OFFSET_B] = (255 * pixel[GFX_ARGB32_OFFSET_B]) / a;
|
|
|
|
pixel[GFX_ARGB32_OFFSET_G] = (255 * pixel[GFX_ARGB32_OFFSET_G]) / a;
|
|
|
|
pixel[GFX_ARGB32_OFFSET_R] = (255 * pixel[GFX_ARGB32_OFFSET_R]) / a;
|
|
|
|
} else {
|
|
|
|
pixel[GFX_ARGB32_OFFSET_B] = 0;
|
|
|
|
pixel[GFX_ARGB32_OFFSET_G] = 0;
|
|
|
|
pixel[GFX_ARGB32_OFFSET_R] = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
nsSVGUtils::PremultiplyImageDataAlpha(PRUint8 *data,
|
|
|
|
PRInt32 stride,
|
|
|
|
const nsRect &rect)
|
|
|
|
{
|
|
|
|
for (PRInt32 y = rect.y; y < rect.YMost(); y++) {
|
|
|
|
for (PRInt32 x = rect.x; x < rect.XMost(); x++) {
|
|
|
|
PRUint8 *pixel = data + stride * y + 4 * x;
|
|
|
|
|
|
|
|
PRUint8 a = pixel[GFX_ARGB32_OFFSET_A];
|
|
|
|
if (a == 255)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
FAST_DIVIDE_BY_255(pixel[GFX_ARGB32_OFFSET_B],
|
|
|
|
pixel[GFX_ARGB32_OFFSET_B] * a);
|
|
|
|
FAST_DIVIDE_BY_255(pixel[GFX_ARGB32_OFFSET_G],
|
|
|
|
pixel[GFX_ARGB32_OFFSET_G] * a);
|
|
|
|
FAST_DIVIDE_BY_255(pixel[GFX_ARGB32_OFFSET_R],
|
|
|
|
pixel[GFX_ARGB32_OFFSET_R] * a);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
nsSVGUtils::ConvertImageDataToLinearRGB(PRUint8 *data,
|
|
|
|
PRInt32 stride,
|
|
|
|
const nsRect &rect)
|
|
|
|
{
|
|
|
|
for (PRInt32 y = rect.y; y < rect.YMost(); y++) {
|
|
|
|
for (PRInt32 x = rect.x; x < rect.XMost(); x++) {
|
|
|
|
PRUint8 *pixel = data + stride * y + 4 * x;
|
|
|
|
|
|
|
|
pixel[GFX_ARGB32_OFFSET_B] =
|
|
|
|
gsRGBToLinearRGBMap[pixel[GFX_ARGB32_OFFSET_B]];
|
|
|
|
pixel[GFX_ARGB32_OFFSET_G] =
|
|
|
|
gsRGBToLinearRGBMap[pixel[GFX_ARGB32_OFFSET_G]];
|
|
|
|
pixel[GFX_ARGB32_OFFSET_R] =
|
|
|
|
gsRGBToLinearRGBMap[pixel[GFX_ARGB32_OFFSET_R]];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
nsSVGUtils::ConvertImageDataFromLinearRGB(PRUint8 *data,
|
|
|
|
PRInt32 stride,
|
|
|
|
const nsRect &rect)
|
|
|
|
{
|
|
|
|
for (PRInt32 y = rect.y; y < rect.YMost(); y++) {
|
|
|
|
for (PRInt32 x = rect.x; x < rect.XMost(); x++) {
|
|
|
|
PRUint8 *pixel = data + stride * y + 4 * x;
|
|
|
|
|
|
|
|
pixel[GFX_ARGB32_OFFSET_B] =
|
|
|
|
glinearRGBTosRGBMap[pixel[GFX_ARGB32_OFFSET_B]];
|
|
|
|
pixel[GFX_ARGB32_OFFSET_G] =
|
|
|
|
glinearRGBTosRGBMap[pixel[GFX_ARGB32_OFFSET_G]];
|
|
|
|
pixel[GFX_ARGB32_OFFSET_R] =
|
|
|
|
glinearRGBTosRGBMap[pixel[GFX_ARGB32_OFFSET_R]];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
nsresult
|
|
|
|
nsSVGUtils::ReportToConsole(nsIDocument* doc,
|
|
|
|
const char* aWarning,
|
|
|
|
const PRUnichar **aParams,
|
|
|
|
PRUint32 aParamsLength)
|
|
|
|
{
|
|
|
|
return nsContentUtils::ReportToConsole(nsContentUtils::eSVG_PROPERTIES,
|
|
|
|
aWarning,
|
|
|
|
aParams, aParamsLength,
|
|
|
|
doc ? doc->GetDocumentURI() : nsnull,
|
|
|
|
EmptyString(), 0, 0,
|
|
|
|
nsIScriptError::warningFlag,
|
|
|
|
"SVG");
|
|
|
|
}
|
|
|
|
|
|
|
|
float
|
|
|
|
nsSVGUtils::CoordToFloat(nsPresContext *aPresContext,
|
|
|
|
nsSVGElement *aContent,
|
|
|
|
const nsStyleCoord &aCoord)
|
|
|
|
{
|
|
|
|
float val = 0.0f;
|
|
|
|
|
|
|
|
switch (aCoord.GetUnit()) {
|
|
|
|
case eStyleUnit_Factor:
|
|
|
|
// user units
|
|
|
|
val = aCoord.GetFactorValue();
|
|
|
|
break;
|
|
|
|
|
|
|
|
case eStyleUnit_Coord:
|
|
|
|
val = nsPresContext::AppUnitsToFloatCSSPixels(aCoord.GetCoordValue());
|
|
|
|
break;
|
|
|
|
|
|
|
|
case eStyleUnit_Percent: {
|
|
|
|
nsCOMPtr<nsISVGLength> length;
|
|
|
|
NS_NewSVGLength(getter_AddRefs(length),
|
|
|
|
aCoord.GetPercentValue() * 100.0f,
|
|
|
|
nsIDOMSVGLength::SVG_LENGTHTYPE_PERCENTAGE);
|
|
|
|
|
|
|
|
if (!length)
|
|
|
|
break;
|
|
|
|
|
|
|
|
nsWeakPtr weakCtx =
|
2007-07-08 00:08:04 -07:00
|
|
|
do_GetWeakReference(static_cast<nsGenericElement*>(aContent));
|
2007-03-22 10:30:00 -07:00
|
|
|
length->SetContext(weakCtx, nsSVGUtils::XY);
|
|
|
|
length->GetValue(&val);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
return val;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsresult nsSVGUtils::GetReferencedFrame(nsIFrame **aRefFrame, nsIURI* aURI, nsIContent *aContent,
|
|
|
|
nsIPresShell *aPresShell)
|
|
|
|
{
|
|
|
|
*aRefFrame = nsnull;
|
|
|
|
|
|
|
|
nsIContent* content = nsContentUtils::GetReferencedElement(aURI, aContent);
|
|
|
|
if (!content)
|
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
|
|
|
|
// Get the Primary Frame
|
|
|
|
NS_ASSERTION(aPresShell, "Get referenced SVG frame -- no pres shell provided");
|
|
|
|
if (!aPresShell)
|
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
|
|
|
|
*aRefFrame = aPresShell->GetPrimaryFrameFor(content);
|
|
|
|
if (!(*aRefFrame)) return NS_ERROR_FAILURE;
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsresult
|
|
|
|
nsSVGUtils::GetBBox(nsFrameList *aFrames, nsIDOMSVGRect **_retval)
|
|
|
|
{
|
|
|
|
*_retval = nsnull;
|
|
|
|
|
|
|
|
float minx, miny, maxx, maxy;
|
|
|
|
minx = miny = FLT_MAX;
|
|
|
|
maxx = maxy = -1.0 * FLT_MAX;
|
|
|
|
|
|
|
|
nsCOMPtr<nsIDOMSVGRect> unionRect;
|
|
|
|
|
|
|
|
nsIFrame* kid = aFrames->FirstChild();
|
|
|
|
while (kid) {
|
|
|
|
nsISVGChildFrame* SVGFrame = nsnull;
|
|
|
|
CallQueryInterface(kid, &SVGFrame);
|
|
|
|
if (SVGFrame) {
|
|
|
|
nsCOMPtr<nsIDOMSVGRect> box;
|
|
|
|
SVGFrame->GetBBox(getter_AddRefs(box));
|
|
|
|
|
|
|
|
if (box) {
|
|
|
|
float bminx, bminy, bmaxx, bmaxy, width, height;
|
|
|
|
box->GetX(&bminx);
|
|
|
|
box->GetY(&bminy);
|
|
|
|
box->GetWidth(&width);
|
|
|
|
box->GetHeight(&height);
|
|
|
|
bmaxx = bminx+width;
|
|
|
|
bmaxy = bminy+height;
|
|
|
|
|
|
|
|
if (!unionRect)
|
|
|
|
unionRect = box;
|
|
|
|
minx = PR_MIN(minx, bminx);
|
|
|
|
miny = PR_MIN(miny, bminy);
|
|
|
|
maxx = PR_MAX(maxx, bmaxx);
|
|
|
|
maxy = PR_MAX(maxy, bmaxy);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
kid = kid->GetNextSibling();
|
|
|
|
}
|
|
|
|
|
|
|
|
if (unionRect) {
|
|
|
|
unionRect->SetX(minx);
|
|
|
|
unionRect->SetY(miny);
|
|
|
|
unionRect->SetWidth(maxx - minx);
|
|
|
|
unionRect->SetHeight(maxy - miny);
|
|
|
|
*_retval = unionRect;
|
|
|
|
NS_ADDREF(*_retval);
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsRect
|
|
|
|
nsSVGUtils::FindFilterInvalidation(nsIFrame *aFrame)
|
|
|
|
{
|
2007-12-19 10:24:34 -08:00
|
|
|
nsISVGChildFrame *svgFrame = nsnull;
|
|
|
|
CallQueryInterface(aFrame, &svgFrame);
|
|
|
|
if (!svgFrame)
|
|
|
|
return nsRect();
|
|
|
|
|
|
|
|
nsRect rect = svgFrame->GetCoveredRegion();
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
while (aFrame) {
|
|
|
|
if (aFrame->GetStateBits() & NS_STATE_IS_OUTER_SVG)
|
|
|
|
break;
|
|
|
|
|
|
|
|
if (aFrame->GetStateBits() & NS_STATE_SVG_FILTERED) {
|
|
|
|
nsSVGFilterProperty *property;
|
2007-07-08 00:08:04 -07:00
|
|
|
property = static_cast<nsSVGFilterProperty *>
|
|
|
|
(aFrame->GetProperty(nsGkAtoms::filter));
|
2007-03-22 10:30:00 -07:00
|
|
|
rect = property->GetRect();
|
|
|
|
}
|
|
|
|
aFrame = aFrame->GetParent();
|
|
|
|
}
|
|
|
|
|
|
|
|
return rect;
|
|
|
|
}
|
|
|
|
|
2007-05-29 17:36:02 -07:00
|
|
|
void
|
|
|
|
nsSVGUtils::UpdateFilterRegion(nsIFrame *aFrame)
|
|
|
|
{
|
2007-12-03 08:57:34 -08:00
|
|
|
AddEffectProperties(aFrame);
|
|
|
|
|
2007-05-29 17:36:02 -07:00
|
|
|
if (aFrame->GetStateBits() & NS_STATE_SVG_FILTERED) {
|
|
|
|
nsSVGFilterProperty *property;
|
2007-07-08 00:08:04 -07:00
|
|
|
property = static_cast<nsSVGFilterProperty *>
|
|
|
|
(aFrame->GetProperty(nsGkAtoms::filter));
|
2007-05-29 17:36:02 -07:00
|
|
|
property->UpdateRect();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
float
|
|
|
|
nsSVGUtils::ObjectSpace(nsIDOMSVGRect *aRect, nsSVGLength2 *aLength)
|
|
|
|
{
|
|
|
|
float fraction, axis;
|
|
|
|
|
|
|
|
switch (aLength->GetCtxType()) {
|
|
|
|
case X:
|
|
|
|
aRect->GetWidth(&axis);
|
|
|
|
break;
|
|
|
|
case Y:
|
|
|
|
aRect->GetHeight(&axis);
|
|
|
|
break;
|
|
|
|
case XY:
|
|
|
|
{
|
|
|
|
float width, height;
|
|
|
|
aRect->GetWidth(&width);
|
|
|
|
aRect->GetHeight(&height);
|
|
|
|
axis = sqrt(width * width + height * height)/sqrt(2.0f);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (aLength->GetSpecifiedUnitType() ==
|
|
|
|
nsIDOMSVGLength::SVG_LENGTHTYPE_PERCENTAGE) {
|
|
|
|
fraction = aLength->GetAnimValInSpecifiedUnits() / 100;
|
|
|
|
} else
|
2007-07-08 00:08:04 -07:00
|
|
|
fraction = aLength->GetAnimValue(static_cast<nsSVGSVGElement*>
|
|
|
|
(nsnull));
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
return fraction * axis;
|
|
|
|
}
|
|
|
|
|
|
|
|
float
|
|
|
|
nsSVGUtils::UserSpace(nsSVGElement *aSVGElement, nsSVGLength2 *aLength)
|
|
|
|
{
|
|
|
|
return aLength->GetAnimValue(aSVGElement);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
nsSVGUtils::TransformPoint(nsIDOMSVGMatrix *matrix,
|
|
|
|
float *x, float *y)
|
|
|
|
{
|
|
|
|
nsCOMPtr<nsIDOMSVGPoint> point;
|
|
|
|
NS_NewSVGPoint(getter_AddRefs(point), *x, *y);
|
|
|
|
if (!point)
|
|
|
|
return;
|
|
|
|
|
|
|
|
nsCOMPtr<nsIDOMSVGPoint> xfpoint;
|
|
|
|
point->MatrixTransform(matrix, getter_AddRefs(xfpoint));
|
|
|
|
if (!xfpoint)
|
|
|
|
return;
|
|
|
|
|
|
|
|
xfpoint->GetX(x);
|
|
|
|
xfpoint->GetY(y);
|
|
|
|
}
|
|
|
|
|
|
|
|
float
|
|
|
|
nsSVGUtils::AngleBisect(float a1, float a2)
|
|
|
|
{
|
2007-07-08 00:08:04 -07:00
|
|
|
float delta = fmod(a2 - a1, static_cast<float>(2*M_PI));
|
2007-03-22 10:30:00 -07:00
|
|
|
if (delta < 0) {
|
|
|
|
delta += 2*M_PI;
|
|
|
|
}
|
|
|
|
/* delta is now the angle from a1 around to a2, in the range [0, 2*M_PI) */
|
|
|
|
float r = a1 + delta/2;
|
|
|
|
if (delta >= M_PI) {
|
|
|
|
/* the arc from a2 to a1 is smaller, so use the ray on that side */
|
|
|
|
r += M_PI;
|
|
|
|
}
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsSVGOuterSVGFrame *
|
|
|
|
nsSVGUtils::GetOuterSVGFrame(nsIFrame *aFrame)
|
|
|
|
{
|
|
|
|
while (aFrame) {
|
|
|
|
if (aFrame->GetStateBits() & NS_STATE_IS_OUTER_SVG) {
|
2007-07-08 00:08:04 -07:00
|
|
|
return static_cast<nsSVGOuterSVGFrame*>(aFrame);
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
aFrame = aFrame->GetParent();
|
|
|
|
}
|
|
|
|
|
|
|
|
return nsnull;
|
|
|
|
}
|
|
|
|
|
2007-05-30 15:32:54 -07:00
|
|
|
nsIFrame*
|
|
|
|
nsSVGUtils::GetOuterSVGFrameAndCoveredRegion(nsIFrame* aFrame, nsRect* aRect)
|
|
|
|
{
|
|
|
|
nsISVGChildFrame* svg;
|
|
|
|
CallQueryInterface(aFrame, &svg);
|
|
|
|
if (!svg)
|
|
|
|
return nsnull;
|
|
|
|
*aRect = svg->GetCoveredRegion();
|
|
|
|
return GetOuterSVGFrame(aFrame);
|
|
|
|
}
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
already_AddRefed<nsIDOMSVGMatrix>
|
|
|
|
nsSVGUtils::GetViewBoxTransform(float aViewportWidth, float aViewportHeight,
|
|
|
|
float aViewboxX, float aViewboxY,
|
|
|
|
float aViewboxWidth, float aViewboxHeight,
|
|
|
|
nsIDOMSVGAnimatedPreserveAspectRatio *aPreserveAspectRatio,
|
|
|
|
PRBool aIgnoreAlign)
|
|
|
|
{
|
|
|
|
PRUint16 align, meetOrSlice;
|
|
|
|
{
|
|
|
|
nsCOMPtr<nsIDOMSVGPreserveAspectRatio> par;
|
|
|
|
aPreserveAspectRatio->GetAnimVal(getter_AddRefs(par));
|
|
|
|
NS_ASSERTION(par, "could not get preserveAspectRatio");
|
|
|
|
par->GetAlign(&align);
|
|
|
|
par->GetMeetOrSlice(&meetOrSlice);
|
|
|
|
}
|
|
|
|
|
|
|
|
// default to the defaults
|
|
|
|
if (align == nsIDOMSVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_UNKNOWN)
|
|
|
|
align = nsIDOMSVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_XMIDYMID;
|
|
|
|
if (meetOrSlice == nsIDOMSVGPreserveAspectRatio::SVG_MEETORSLICE_UNKNOWN)
|
|
|
|
meetOrSlice = nsIDOMSVGPreserveAspectRatio::SVG_MEETORSLICE_MEET;
|
|
|
|
|
|
|
|
// alignment disabled for this matrix setup
|
|
|
|
if (aIgnoreAlign)
|
|
|
|
align = nsIDOMSVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_XMINYMIN;
|
|
|
|
|
|
|
|
float a, d, e, f;
|
|
|
|
a = aViewportWidth / aViewboxWidth;
|
|
|
|
d = aViewportHeight / aViewboxHeight;
|
|
|
|
e = 0.0f;
|
|
|
|
f = 0.0f;
|
|
|
|
|
|
|
|
if (align != nsIDOMSVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_NONE &&
|
|
|
|
a != d) {
|
|
|
|
if (meetOrSlice == nsIDOMSVGPreserveAspectRatio::SVG_MEETORSLICE_MEET &&
|
|
|
|
a < d ||
|
|
|
|
meetOrSlice == nsIDOMSVGPreserveAspectRatio::SVG_MEETORSLICE_SLICE &&
|
|
|
|
d < a) {
|
|
|
|
d = a;
|
|
|
|
switch (align) {
|
|
|
|
case nsIDOMSVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_XMINYMIN:
|
|
|
|
case nsIDOMSVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_XMIDYMIN:
|
|
|
|
case nsIDOMSVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_XMAXYMIN:
|
|
|
|
break;
|
|
|
|
case nsIDOMSVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_XMINYMID:
|
|
|
|
case nsIDOMSVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_XMIDYMID:
|
|
|
|
case nsIDOMSVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_XMAXYMID:
|
|
|
|
f = (aViewportHeight - a * aViewboxHeight) / 2.0f;
|
|
|
|
break;
|
|
|
|
case nsIDOMSVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_XMINYMAX:
|
|
|
|
case nsIDOMSVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_XMIDYMAX:
|
|
|
|
case nsIDOMSVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_XMAXYMAX:
|
|
|
|
f = aViewportHeight - a * aViewboxHeight;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
NS_NOTREACHED("Unknown value for align");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (
|
|
|
|
meetOrSlice == nsIDOMSVGPreserveAspectRatio::SVG_MEETORSLICE_MEET &&
|
|
|
|
d < a ||
|
|
|
|
meetOrSlice == nsIDOMSVGPreserveAspectRatio::SVG_MEETORSLICE_SLICE &&
|
|
|
|
a < d) {
|
|
|
|
a = d;
|
|
|
|
switch (align) {
|
|
|
|
case nsIDOMSVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_XMINYMIN:
|
|
|
|
case nsIDOMSVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_XMINYMID:
|
|
|
|
case nsIDOMSVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_XMINYMAX:
|
|
|
|
break;
|
|
|
|
case nsIDOMSVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_XMIDYMIN:
|
|
|
|
case nsIDOMSVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_XMIDYMID:
|
|
|
|
case nsIDOMSVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_XMIDYMAX:
|
|
|
|
e = (aViewportWidth - a * aViewboxWidth) / 2.0f;
|
|
|
|
break;
|
|
|
|
case nsIDOMSVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_XMAXYMIN:
|
|
|
|
case nsIDOMSVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_XMAXYMID:
|
|
|
|
case nsIDOMSVGPreserveAspectRatio::SVG_PRESERVEASPECTRATIO_XMAXYMAX:
|
|
|
|
e = aViewportWidth - a * aViewboxWidth;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
NS_NOTREACHED("Unknown value for align");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else NS_NOTREACHED("Unknown value for meetOrSlice");
|
|
|
|
}
|
|
|
|
|
|
|
|
if (aViewboxX) e += -a * aViewboxX;
|
|
|
|
if (aViewboxY) f += -d * aViewboxY;
|
|
|
|
|
|
|
|
nsIDOMSVGMatrix *retval;
|
|
|
|
NS_NewSVGMatrix(&retval, a, 0.0f, 0.0f, d, e, f);
|
|
|
|
return retval;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// This is ugly and roc will want to kill me...
|
|
|
|
|
|
|
|
already_AddRefed<nsIDOMSVGMatrix>
|
|
|
|
nsSVGUtils::GetCanvasTM(nsIFrame *aFrame)
|
|
|
|
{
|
|
|
|
if (!aFrame->IsLeaf()) {
|
2007-05-16 08:14:19 -07:00
|
|
|
// foreignObject is the one non-leaf svg frame that isn't a SVGContainer
|
|
|
|
if (aFrame->GetType() == nsGkAtoms::svgForeignObjectFrame) {
|
|
|
|
nsSVGForeignObjectFrame *foreignFrame =
|
2007-07-08 00:08:04 -07:00
|
|
|
static_cast<nsSVGForeignObjectFrame*>(aFrame);
|
2007-05-16 08:14:19 -07:00
|
|
|
return foreignFrame->GetCanvasTM();
|
|
|
|
}
|
2007-07-08 00:08:04 -07:00
|
|
|
nsSVGContainerFrame *containerFrame = static_cast<nsSVGContainerFrame*>
|
|
|
|
(aFrame);
|
2007-03-22 10:30:00 -07:00
|
|
|
return containerFrame->GetCanvasTM();
|
|
|
|
}
|
|
|
|
|
2007-07-08 00:08:04 -07:00
|
|
|
nsSVGGeometryFrame *geometryFrame = static_cast<nsSVGGeometryFrame*>
|
|
|
|
(aFrame);
|
2007-03-22 10:30:00 -07:00
|
|
|
nsCOMPtr<nsIDOMSVGMatrix> matrix;
|
|
|
|
nsIDOMSVGMatrix *retval;
|
|
|
|
geometryFrame->GetCanvasTM(getter_AddRefs(matrix));
|
|
|
|
retval = matrix.get();
|
|
|
|
NS_IF_ADDREF(retval);
|
|
|
|
return retval;
|
|
|
|
}
|
|
|
|
|
2007-12-20 06:26:34 -08:00
|
|
|
void
|
|
|
|
nsSVGUtils::NotifyChildrenCanvasTMChanged(nsIFrame *aFrame, PRBool suppressInvalidation)
|
|
|
|
{
|
|
|
|
nsIFrame *aKid = aFrame->GetFirstChild(nsnull);
|
|
|
|
|
|
|
|
while (aKid) {
|
|
|
|
nsISVGChildFrame* SVGFrame = nsnull;
|
|
|
|
CallQueryInterface(aKid, &SVGFrame);
|
|
|
|
if (SVGFrame) {
|
|
|
|
SVGFrame->NotifyCanvasTMChanged(suppressInvalidation);
|
|
|
|
} else {
|
2007-12-20 06:31:17 -08:00
|
|
|
NS_ASSERTION(aKid->IsFrameOfType(nsIFrame::eSVG), "SVG frame expected");
|
2007-12-20 06:26:34 -08:00
|
|
|
// recurse into the children of container frames e.g. <clipPath>, <mask>
|
|
|
|
// in case they have child frames with transformation matrices
|
|
|
|
nsSVGUtils::NotifyChildrenCanvasTMChanged(aKid, suppressInvalidation);
|
|
|
|
}
|
|
|
|
aKid = aKid->GetNextSibling();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
void
|
|
|
|
nsSVGUtils::AddObserver(nsISupports *aObserver, nsISupports *aTarget)
|
|
|
|
{
|
|
|
|
nsISVGValueObserver *observer = nsnull;
|
|
|
|
nsISVGValue *v = nsnull;
|
|
|
|
CallQueryInterface(aObserver, &observer);
|
|
|
|
CallQueryInterface(aTarget, &v);
|
|
|
|
if (observer && v)
|
|
|
|
v->AddObserver(observer);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
nsSVGUtils::RemoveObserver(nsISupports *aObserver, nsISupports *aTarget)
|
|
|
|
{
|
|
|
|
nsISVGValueObserver *observer = nsnull;
|
|
|
|
nsISVGValue *v = nsnull;
|
|
|
|
CallQueryInterface(aObserver, &observer);
|
|
|
|
CallQueryInterface(aTarget, &v);
|
|
|
|
if (observer && v)
|
|
|
|
v->RemoveObserver(observer);
|
|
|
|
}
|
|
|
|
|
|
|
|
// ************************************************************
|
|
|
|
// Effect helper functions
|
|
|
|
|
|
|
|
static void
|
|
|
|
AddEffectProperties(nsIFrame *aFrame)
|
|
|
|
{
|
|
|
|
const nsStyleSVGReset *style = aFrame->GetStyleSVGReset();
|
|
|
|
|
|
|
|
if (style->mFilter && !(aFrame->GetStateBits() & NS_STATE_SVG_FILTERED)) {
|
2007-04-05 06:23:21 -07:00
|
|
|
nsIContent *filter = NS_GetSVGFilterElement(style->mFilter,
|
|
|
|
aFrame->GetContent());
|
2007-04-26 01:36:16 -07:00
|
|
|
if (filter && !new nsSVGFilterProperty(filter, aFrame)) {
|
|
|
|
NS_ERROR("Could not create filter property");
|
|
|
|
return;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-04-26 01:36:16 -07:00
|
|
|
if (style->mClipPath && !(aFrame->GetStateBits() & NS_STATE_SVG_CLIPPED)) {
|
|
|
|
nsIContent *clipPath = NS_GetSVGClipPathElement(style->mClipPath,
|
|
|
|
aFrame->GetContent());
|
|
|
|
if (clipPath && !new nsSVGClipPathProperty(clipPath, aFrame)) {
|
|
|
|
NS_ERROR("Could not create clipPath property");
|
|
|
|
return;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (style->mMask && !(aFrame->GetStateBits() & NS_STATE_SVG_MASKED)) {
|
2007-04-26 01:36:16 -07:00
|
|
|
nsIContent *mask = NS_GetSVGMaskElement(style->mMask,
|
|
|
|
aFrame->GetContent());
|
|
|
|
if (mask && !new nsSVGMaskProperty(mask, aFrame)) {
|
|
|
|
NS_ERROR("Could not create mask property");
|
|
|
|
return;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-04-26 01:36:16 -07:00
|
|
|
static nsSVGFilterFrame *
|
|
|
|
GetFilterFrame(nsFrameState aState, nsIFrame *aFrame)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
2007-04-26 01:36:16 -07:00
|
|
|
if (aState & NS_STATE_SVG_FILTERED) {
|
|
|
|
nsSVGFilterProperty *property;
|
2007-07-08 00:08:04 -07:00
|
|
|
property = static_cast<nsSVGFilterProperty *>
|
|
|
|
(aFrame->GetProperty(nsGkAtoms::filter));
|
2007-04-26 01:36:16 -07:00
|
|
|
return property->GetFilterFrame();
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
2007-04-26 01:36:16 -07:00
|
|
|
return nsnull;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
2007-04-26 01:36:16 -07:00
|
|
|
static nsSVGClipPathFrame *
|
|
|
|
GetClipPathFrame(nsFrameState aState, nsIFrame *aFrame)
|
2007-03-22 10:30:00 -07:00
|
|
|
{
|
2007-04-26 01:36:16 -07:00
|
|
|
if (aState & NS_STATE_SVG_CLIPPED) {
|
|
|
|
nsSVGClipPathProperty *property;
|
2007-07-08 00:08:04 -07:00
|
|
|
property = static_cast<nsSVGClipPathProperty *>
|
|
|
|
(aFrame->GetProperty(nsGkAtoms::clipPath));
|
2007-04-26 01:36:16 -07:00
|
|
|
return property->GetClipPathFrame();
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
return nsnull;
|
|
|
|
}
|
|
|
|
|
2007-04-26 01:36:16 -07:00
|
|
|
static nsSVGMaskFrame *
|
|
|
|
GetMaskFrame(nsFrameState aState, nsIFrame *aFrame)
|
|
|
|
{
|
|
|
|
if (aState & NS_STATE_SVG_MASKED) {
|
|
|
|
nsSVGMaskProperty *property;
|
2007-07-08 00:08:04 -07:00
|
|
|
property = static_cast<nsSVGMaskProperty *>
|
|
|
|
(aFrame->GetProperty(nsGkAtoms::mask));
|
2007-04-26 01:36:16 -07:00
|
|
|
return property->GetMaskFrame();
|
|
|
|
}
|
|
|
|
return nsnull;
|
|
|
|
}
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
// ************************************************************
|
|
|
|
|
|
|
|
void
|
|
|
|
nsSVGUtils::PaintChildWithEffects(nsSVGRenderState *aContext,
|
|
|
|
nsRect *aDirtyRect,
|
|
|
|
nsIFrame *aFrame)
|
|
|
|
{
|
|
|
|
nsISVGChildFrame *svgChildFrame;
|
|
|
|
CallQueryInterface(aFrame, &svgChildFrame);
|
|
|
|
|
|
|
|
if (!svgChildFrame)
|
|
|
|
return;
|
|
|
|
|
|
|
|
float opacity = aFrame->GetStyleDisplay()->mOpacity;
|
|
|
|
if (opacity == 0.0f)
|
|
|
|
return;
|
|
|
|
|
|
|
|
/* Properties are added lazily and may have been removed by a restyle,
|
|
|
|
so make sure all applicable ones are set again. */
|
|
|
|
|
|
|
|
AddEffectProperties(aFrame);
|
|
|
|
nsFrameState state = aFrame->GetStateBits();
|
|
|
|
|
|
|
|
/* Check if we need to draw anything */
|
|
|
|
if (aDirtyRect) {
|
|
|
|
if (state & NS_STATE_SVG_FILTERED) {
|
|
|
|
if (!aDirtyRect->Intersects(FindFilterInvalidation(aFrame)))
|
|
|
|
return;
|
|
|
|
} else if (svgChildFrame->HasValidCoveredRect()) {
|
|
|
|
if (!aDirtyRect->Intersects(aFrame->GetRect()))
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* SVG defines the following rendering model:
|
|
|
|
*
|
|
|
|
* 1. Render geometry
|
|
|
|
* 2. Apply filter
|
|
|
|
* 3. Apply clipping, masking, group opacity
|
|
|
|
*
|
2007-04-26 01:36:16 -07:00
|
|
|
* We follow this, but perform a couple of optimizations:
|
2007-03-22 10:30:00 -07:00
|
|
|
*
|
|
|
|
* + Use cairo's clipPath when representable natively (single object
|
|
|
|
* clip region).
|
|
|
|
*
|
|
|
|
* + Merge opacity and masking if both used together.
|
|
|
|
*/
|
|
|
|
|
2007-04-26 01:36:16 -07:00
|
|
|
if (opacity != 1.0f && CanOptimizeOpacity(aFrame))
|
|
|
|
opacity = 1.0f;
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
gfxContext *gfx = aContext->GetGfxContext();
|
2007-05-22 12:31:04 -07:00
|
|
|
PRBool complexEffects = PR_FALSE;
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2007-04-26 01:36:16 -07:00
|
|
|
nsSVGClipPathFrame *clipPathFrame = GetClipPathFrame(state, aFrame);
|
|
|
|
PRBool isTrivialClip = clipPathFrame ? clipPathFrame->IsTrivial() : PR_TRUE;
|
|
|
|
|
|
|
|
nsSVGMaskFrame *maskFrame = GetMaskFrame(state, aFrame);
|
|
|
|
|
|
|
|
nsCOMPtr<nsIDOMSVGMatrix> matrix =
|
|
|
|
(clipPathFrame || maskFrame) ? GetCanvasTM(aFrame) : nsnull;
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
/* Check if we need to do additional operations on this child's
|
|
|
|
* rendering, which necessitates rendering into another surface. */
|
2007-04-26 01:36:16 -07:00
|
|
|
if (opacity != 1.0f || maskFrame || (clipPathFrame && !isTrivialClip)) {
|
2007-05-22 12:31:04 -07:00
|
|
|
complexEffects = PR_TRUE;
|
|
|
|
gfx->Save();
|
|
|
|
gfx->PushGroup(gfxASurface::CONTENT_COLOR_ALPHA);
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
/* If this frame has only a trivial clipPath, set up cairo's clipping now so
|
|
|
|
* we can just do normal painting and get it clipped appropriately.
|
|
|
|
*/
|
2007-04-26 01:36:16 -07:00
|
|
|
if (clipPathFrame && isTrivialClip) {
|
2007-03-22 10:30:00 -07:00
|
|
|
gfx->Save();
|
2007-04-26 01:36:16 -07:00
|
|
|
clipPathFrame->ClipPaint(aContext, svgChildFrame, matrix);
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Paint the child */
|
2007-04-26 01:36:16 -07:00
|
|
|
nsSVGFilterFrame *filterFrame = GetFilterFrame(state, aFrame);
|
|
|
|
if (filterFrame) {
|
|
|
|
filterFrame->FilterPaint(aContext, svgChildFrame);
|
2007-03-22 10:30:00 -07:00
|
|
|
} else {
|
|
|
|
svgChildFrame->PaintSVG(aContext, aDirtyRect);
|
|
|
|
}
|
|
|
|
|
2007-04-26 01:36:16 -07:00
|
|
|
if (clipPathFrame && isTrivialClip) {
|
2007-03-22 10:30:00 -07:00
|
|
|
gfx->Restore();
|
|
|
|
}
|
|
|
|
|
|
|
|
/* No more effects, we're done. */
|
2007-05-22 12:31:04 -07:00
|
|
|
if (!complexEffects)
|
2007-03-22 10:30:00 -07:00
|
|
|
return;
|
|
|
|
|
2007-05-22 12:31:04 -07:00
|
|
|
gfx->PopGroupToSource();
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2007-05-22 12:31:04 -07:00
|
|
|
nsRefPtr<gfxPattern> maskSurface =
|
2007-04-26 01:36:16 -07:00
|
|
|
maskFrame ? maskFrame->ComputeMaskAlpha(aContext, svgChildFrame,
|
|
|
|
matrix, opacity) : nsnull;
|
|
|
|
|
2007-05-22 12:31:04 -07:00
|
|
|
nsRefPtr<gfxPattern> clipMaskSurface;
|
2007-04-26 01:36:16 -07:00
|
|
|
if (clipPathFrame && !isTrivialClip) {
|
2007-05-22 12:31:04 -07:00
|
|
|
gfx->PushGroup(gfxASurface::CONTENT_COLOR_ALPHA);
|
2007-04-26 01:36:16 -07:00
|
|
|
|
|
|
|
nsresult rv = clipPathFrame->ClipPaint(aContext, svgChildFrame, matrix);
|
2007-05-22 12:31:04 -07:00
|
|
|
clipMaskSurface = gfx->PopGroup();
|
2007-04-26 01:36:16 -07:00
|
|
|
|
|
|
|
if (NS_SUCCEEDED(rv) && clipMaskSurface) {
|
|
|
|
// Still more set after clipping, so clip to another surface
|
|
|
|
if (maskSurface || opacity != 1.0f) {
|
2007-05-22 12:31:04 -07:00
|
|
|
gfx->PushGroup(gfxASurface::CONTENT_COLOR_ALPHA);
|
|
|
|
gfx->Mask(clipMaskSurface);
|
|
|
|
gfx->PopGroupToSource();
|
2007-04-26 01:36:16 -07:00
|
|
|
} else {
|
2007-05-22 12:31:04 -07:00
|
|
|
gfx->Mask(clipMaskSurface);
|
2007-04-26 01:36:16 -07:00
|
|
|
}
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (maskSurface) {
|
2007-05-22 12:31:04 -07:00
|
|
|
gfx->Mask(maskSurface);
|
2007-04-26 01:36:16 -07:00
|
|
|
} else if (opacity != 1.0f) {
|
2007-05-22 12:31:04 -07:00
|
|
|
gfx->Paint(opacity);
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
2007-05-22 12:31:04 -07:00
|
|
|
gfx->Restore();
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
nsSVGUtils::StyleEffects(nsIFrame *aFrame)
|
|
|
|
{
|
|
|
|
nsFrameState state = aFrame->GetStateBits();
|
|
|
|
|
|
|
|
/* clear out all effects */
|
|
|
|
|
2007-04-26 01:36:16 -07:00
|
|
|
if (state & NS_STATE_SVG_CLIPPED) {
|
2007-03-22 10:30:00 -07:00
|
|
|
aFrame->DeleteProperty(nsGkAtoms::clipPath);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (state & NS_STATE_SVG_FILTERED) {
|
|
|
|
aFrame->DeleteProperty(nsGkAtoms::filter);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (state & NS_STATE_SVG_MASKED) {
|
|
|
|
aFrame->DeleteProperty(nsGkAtoms::mask);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
PRBool
|
|
|
|
nsSVGUtils::HitTestClip(nsIFrame *aFrame, float x, float y)
|
|
|
|
{
|
2007-04-26 01:36:16 -07:00
|
|
|
nsSVGClipPathFrame *clipPathFrame =
|
|
|
|
GetClipPathFrame(aFrame->GetStateBits(), aFrame);
|
|
|
|
|
|
|
|
if (clipPathFrame) {
|
|
|
|
nsISVGChildFrame* SVGFrame;
|
|
|
|
CallQueryInterface(aFrame, &SVGFrame);
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
nsCOMPtr<nsIDOMSVGMatrix> matrix = GetCanvasTM(aFrame);
|
2007-04-26 01:36:16 -07:00
|
|
|
return clipPathFrame->ClipHitTest(SVGFrame, matrix, x, y);
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
2007-04-17 02:01:52 -07:00
|
|
|
return PR_TRUE;
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
nsSVGUtils::HitTestChildren(nsIFrame *aFrame, float x, float y,
|
|
|
|
nsIFrame **aResult)
|
|
|
|
{
|
|
|
|
// XXX: The frame's children are linked in a singly-linked list in document
|
|
|
|
// order. If we were to hit test the children in this order we would need to
|
|
|
|
// hit test *every* SVG frame, since even if we get a hit, later SVG frames
|
|
|
|
// may lie on top of the matching frame. We really want to traverse SVG
|
|
|
|
// frames in reverse order so we can stop at the first match. Since we don't
|
|
|
|
// have a doubly-linked list, for the time being we traverse the
|
|
|
|
// singly-linked list backwards by first reversing the nextSibling pointers
|
|
|
|
// in place, and then restoring them when done.
|
|
|
|
//
|
|
|
|
// Note: While the child list pointers are reversed, any method which walks
|
|
|
|
// the list would only encounter a single child!
|
|
|
|
|
|
|
|
*aResult = nsnull;
|
|
|
|
|
|
|
|
nsIFrame* current = nsnull;
|
|
|
|
nsIFrame* next = aFrame->GetFirstChild(nsnull);
|
|
|
|
|
|
|
|
// reverse sibling pointers
|
|
|
|
while (next) {
|
|
|
|
nsIFrame* temp = next->GetNextSibling();
|
|
|
|
next->SetNextSibling(current);
|
|
|
|
current = next;
|
|
|
|
next = temp;
|
|
|
|
}
|
|
|
|
|
|
|
|
// now do the backwards traversal
|
|
|
|
while (current) {
|
|
|
|
nsISVGChildFrame* SVGFrame;
|
|
|
|
CallQueryInterface(current, &SVGFrame);
|
|
|
|
if (SVGFrame) {
|
|
|
|
if (NS_SUCCEEDED(SVGFrame->GetFrameForPointSVG(x, y, aResult)) &&
|
|
|
|
*aResult)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
// restore current frame's sibling pointer
|
|
|
|
nsIFrame* temp = current->GetNextSibling();
|
|
|
|
current->SetNextSibling(next);
|
|
|
|
next = current;
|
|
|
|
current = temp;
|
|
|
|
}
|
|
|
|
|
|
|
|
// restore remaining pointers
|
|
|
|
while (current) {
|
|
|
|
nsIFrame* temp = current->GetNextSibling();
|
|
|
|
current->SetNextSibling(next);
|
|
|
|
next = current;
|
|
|
|
current = temp;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (*aResult && !HitTestClip(aFrame, x, y))
|
|
|
|
*aResult = nsnull;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsRect
|
|
|
|
nsSVGUtils::GetCoveredRegion(const nsFrameList &aFrames)
|
|
|
|
{
|
|
|
|
nsRect rect;
|
|
|
|
|
|
|
|
for (nsIFrame* kid = aFrames.FirstChild();
|
|
|
|
kid;
|
|
|
|
kid = kid->GetNextSibling()) {
|
|
|
|
nsISVGChildFrame* child = nsnull;
|
|
|
|
CallQueryInterface(kid, &child);
|
|
|
|
if (child) {
|
|
|
|
nsRect childRect = child->GetCoveredRegion();
|
|
|
|
rect.UnionRect(rect, childRect);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return rect;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsRect
|
|
|
|
nsSVGUtils::ToBoundingPixelRect(double xmin, double ymin,
|
|
|
|
double xmax, double ymax)
|
|
|
|
{
|
|
|
|
return nsRect(nscoord(floor(xmin)),
|
|
|
|
nscoord(floor(ymin)),
|
|
|
|
nscoord(ceil(xmax) - floor(xmin)),
|
|
|
|
nscoord(ceil(ymax) - floor(ymin)));
|
|
|
|
}
|
|
|
|
|
|
|
|
nsRect
|
|
|
|
nsSVGUtils::ToBoundingPixelRect(const gfxRect& rect)
|
|
|
|
{
|
|
|
|
return nsRect(nscoord(floor(rect.X())),
|
|
|
|
nscoord(floor(rect.Y())),
|
|
|
|
nscoord(ceil(rect.XMost()) - floor(rect.X())),
|
|
|
|
nscoord(ceil(rect.YMost()) - floor(rect.Y())));
|
|
|
|
}
|
|
|
|
|
2007-06-13 02:02:48 -07:00
|
|
|
gfxIntSize
|
|
|
|
nsSVGUtils::ConvertToSurfaceSize(const gfxSize& aSize, PRBool *aResultOverflows)
|
|
|
|
{
|
|
|
|
gfxIntSize surfaceSize =
|
|
|
|
gfxIntSize(PRInt32(aSize.width + 0.5), PRInt32(aSize.height + 0.5));
|
|
|
|
|
|
|
|
*aResultOverflows = (aSize.width >= PR_INT32_MAX + 0.5 ||
|
|
|
|
aSize.height >= PR_INT32_MAX + 0.5 ||
|
|
|
|
aSize.width <= PR_INT32_MIN - 0.5 ||
|
|
|
|
aSize.height <= PR_INT32_MIN - 0.5);
|
|
|
|
|
|
|
|
if (*aResultOverflows ||
|
|
|
|
!gfxASurface::CheckSurfaceSize(surfaceSize)) {
|
|
|
|
surfaceSize.width = PR_MIN(NS_SVG_OFFSCREEN_MAX_DIMENSION,
|
|
|
|
surfaceSize.width);
|
|
|
|
surfaceSize.height = PR_MIN(NS_SVG_OFFSCREEN_MAX_DIMENSION,
|
|
|
|
surfaceSize.height);
|
|
|
|
*aResultOverflows = PR_TRUE;
|
|
|
|
}
|
|
|
|
return surfaceSize;
|
|
|
|
}
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
gfxASurface *
|
|
|
|
nsSVGUtils::GetThebesComputationalSurface()
|
|
|
|
{
|
|
|
|
if (!mThebesComputationalSurface) {
|
2007-09-04 02:43:09 -07:00
|
|
|
nsRefPtr<gfxImageSurface> surface =
|
|
|
|
new gfxImageSurface(gfxIntSize(1, 1), gfxASurface::ImageFormatARGB32);
|
2007-07-17 02:24:27 -07:00
|
|
|
NS_ASSERTION(surface && !surface->CairoStatus(),
|
|
|
|
"Could not create offscreen surface");
|
2007-04-18 14:09:31 -07:00
|
|
|
mThebesComputationalSurface = surface;
|
2007-03-22 10:30:00 -07:00
|
|
|
// we want to keep this surface around
|
|
|
|
NS_IF_ADDREF(mThebesComputationalSurface);
|
|
|
|
}
|
|
|
|
|
|
|
|
return mThebesComputationalSurface;
|
|
|
|
}
|
|
|
|
|
|
|
|
gfxMatrix
|
|
|
|
nsSVGUtils::ConvertSVGMatrixToThebes(nsIDOMSVGMatrix *aMatrix)
|
|
|
|
{
|
|
|
|
float A, B, C, D, E, F;
|
|
|
|
aMatrix->GetA(&A);
|
|
|
|
aMatrix->GetB(&B);
|
|
|
|
aMatrix->GetC(&C);
|
|
|
|
aMatrix->GetD(&D);
|
|
|
|
aMatrix->GetE(&E);
|
|
|
|
aMatrix->GetF(&F);
|
|
|
|
return gfxMatrix(A, B, C, D, E, F);
|
|
|
|
}
|
|
|
|
|
|
|
|
PRBool
|
|
|
|
nsSVGUtils::HitTestRect(nsIDOMSVGMatrix *aMatrix,
|
|
|
|
float aRX, float aRY, float aRWidth, float aRHeight,
|
|
|
|
float aX, float aY)
|
|
|
|
{
|
|
|
|
PRBool result = PR_TRUE;
|
|
|
|
|
|
|
|
if (aMatrix) {
|
2007-05-23 08:42:12 -07:00
|
|
|
gfxContext ctx(GetThebesComputationalSurface());
|
|
|
|
ctx.SetMatrix(ConvertSVGMatrixToThebes(aMatrix));
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2007-05-23 08:42:12 -07:00
|
|
|
ctx.NewPath();
|
|
|
|
ctx.Rectangle(gfxRect(aRX, aRY, aRWidth, aRHeight));
|
|
|
|
ctx.IdentityMatrix();
|
2007-03-22 10:30:00 -07:00
|
|
|
|
2007-05-23 08:42:12 -07:00
|
|
|
if (!ctx.PointInFill(gfxPoint(aX, aY)))
|
2007-03-22 10:30:00 -07:00
|
|
|
result = PR_FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
nsSVGUtils::CompositeSurfaceMatrix(gfxContext *aContext,
|
|
|
|
gfxASurface *aSurface,
|
|
|
|
nsIDOMSVGMatrix *aCTM, float aOpacity)
|
|
|
|
{
|
2007-03-27 05:43:59 -07:00
|
|
|
gfxMatrix matrix = ConvertSVGMatrixToThebes(aCTM);
|
|
|
|
if (matrix.IsSingular())
|
2007-03-22 10:30:00 -07:00
|
|
|
return;
|
|
|
|
|
|
|
|
aContext->Save();
|
|
|
|
|
2007-03-27 05:43:59 -07:00
|
|
|
aContext->Multiply(matrix);
|
2007-03-22 10:30:00 -07:00
|
|
|
|
|
|
|
aContext->SetSource(aSurface);
|
|
|
|
aContext->Paint(aOpacity);
|
|
|
|
|
|
|
|
aContext->Restore();
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
nsSVGUtils::SetClipRect(gfxContext *aContext,
|
|
|
|
nsIDOMSVGMatrix *aCTM, float aX, float aY,
|
|
|
|
float aWidth, float aHeight)
|
|
|
|
{
|
2007-03-27 05:43:59 -07:00
|
|
|
gfxMatrix matrix = ConvertSVGMatrixToThebes(aCTM);
|
|
|
|
if (matrix.IsSingular())
|
2007-03-22 10:30:00 -07:00
|
|
|
return;
|
|
|
|
|
|
|
|
gfxMatrix oldMatrix = aContext->CurrentMatrix();
|
2007-03-27 05:43:59 -07:00
|
|
|
aContext->Multiply(matrix);
|
2007-03-22 10:30:00 -07:00
|
|
|
aContext->Clip(gfxRect(aX, aY, aWidth, aHeight));
|
|
|
|
aContext->SetMatrix(oldMatrix);
|
|
|
|
}
|
|
|
|
|
|
|
|
PRBool
|
|
|
|
nsSVGUtils::CanOptimizeOpacity(nsIFrame *aFrame)
|
|
|
|
{
|
|
|
|
if (!(aFrame->GetStateBits() & NS_STATE_SVG_FILTERED)) {
|
|
|
|
nsIAtom *type = aFrame->GetType();
|
|
|
|
if (type == nsGkAtoms::svgImageFrame)
|
|
|
|
return PR_TRUE;
|
|
|
|
if (type == nsGkAtoms::svgPathGeometryFrame) {
|
2007-07-08 00:08:04 -07:00
|
|
|
nsSVGGeometryFrame *geom = static_cast<nsSVGGeometryFrame*>(aFrame);
|
2007-03-22 10:30:00 -07:00
|
|
|
if (!(geom->HasFill() && geom->HasStroke()))
|
|
|
|
return PR_TRUE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return PR_FALSE;
|
|
|
|
}
|
|
|
|
|
2007-10-02 07:57:47 -07:00
|
|
|
float
|
|
|
|
nsSVGUtils::MaxExpansion(nsIDOMSVGMatrix *aMatrix)
|
|
|
|
{
|
|
|
|
float a, b, c, d;
|
|
|
|
aMatrix->GetA(&a);
|
|
|
|
aMatrix->GetB(&b);
|
|
|
|
aMatrix->GetC(&c);
|
|
|
|
aMatrix->GetD(&d);
|
|
|
|
|
|
|
|
// maximum expansion derivation from
|
|
|
|
// http://lists.cairographics.org/archives/cairo/2004-October/001980.html
|
|
|
|
float f = (a * a + b * b + c * c + d * d) / 2;
|
|
|
|
float g = (a * a + b * b - c * c - d * d) / 2;
|
|
|
|
float h = a * c + b * d;
|
|
|
|
return sqrt(f + sqrt(g * g + h * h));
|
|
|
|
}
|
|
|
|
|
2007-12-03 20:40:52 -08:00
|
|
|
already_AddRefed<nsIDOMSVGMatrix>
|
|
|
|
nsSVGUtils::AdjustMatrixForUnits(nsIDOMSVGMatrix *aMatrix,
|
|
|
|
nsSVGEnum *aUnits,
|
|
|
|
nsISVGChildFrame *aFrame)
|
|
|
|
{
|
|
|
|
nsCOMPtr<nsIDOMSVGMatrix> fini = aMatrix;
|
|
|
|
|
|
|
|
if (aFrame &&
|
|
|
|
aUnits->GetAnimValue() == nsIDOMSVGUnitTypes::SVG_UNIT_TYPE_OBJECTBOUNDINGBOX) {
|
|
|
|
nsCOMPtr<nsIDOMSVGRect> rect;
|
|
|
|
nsresult rv = aFrame->GetBBox(getter_AddRefs(rect));
|
|
|
|
|
|
|
|
if (NS_SUCCEEDED(rv)) {
|
|
|
|
float minx, miny, width, height;
|
|
|
|
rect->GetX(&minx);
|
|
|
|
rect->GetY(&miny);
|
|
|
|
rect->GetWidth(&width);
|
|
|
|
rect->GetHeight(&height);
|
|
|
|
|
|
|
|
// Correct for scaling in outersvg CTM
|
|
|
|
nsIFrame *frame;
|
|
|
|
CallQueryInterface(aFrame, &frame);
|
|
|
|
nsPresContext *presCtx = frame->PresContext();
|
|
|
|
float cssPxPerDevPx =
|
|
|
|
presCtx->AppUnitsToFloatCSSPixels(presCtx->AppUnitsPerDevPixel());
|
|
|
|
minx *= cssPxPerDevPx;
|
|
|
|
miny *= cssPxPerDevPx;
|
|
|
|
width *= cssPxPerDevPx;
|
|
|
|
height *= cssPxPerDevPx;
|
|
|
|
|
|
|
|
nsCOMPtr<nsIDOMSVGMatrix> tmp;
|
|
|
|
aMatrix->Translate(minx, miny, getter_AddRefs(tmp));
|
|
|
|
tmp->ScaleNonUniform(width, height, getter_AddRefs(fini));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
nsIDOMSVGMatrix* retval = fini.get();
|
|
|
|
NS_IF_ADDREF(retval);
|
|
|
|
return retval;
|
|
|
|
}
|
|
|
|
|
2007-09-17 08:20:35 -07:00
|
|
|
#ifdef DEBUG
|
|
|
|
void
|
|
|
|
nsSVGUtils::WritePPM(const char *fname, gfxImageSurface *aSurface)
|
|
|
|
{
|
|
|
|
FILE *f = fopen(fname, "wb");
|
|
|
|
if (!f)
|
|
|
|
return;
|
|
|
|
|
|
|
|
gfxIntSize size = aSurface->GetSize();
|
|
|
|
fprintf(f, "P6\n%d %d\n255\n", size.width, size.height);
|
|
|
|
unsigned char *data = aSurface->Data();
|
|
|
|
PRInt32 stride = aSurface->Stride();
|
|
|
|
for (int y=0; y<size.height; y++) {
|
|
|
|
for (int x=0; x<size.width; x++) {
|
|
|
|
fwrite(data + y * stride + 4 * x + GFX_ARGB32_OFFSET_R, 1, 1, f);
|
|
|
|
fwrite(data + y * stride + 4 * x + GFX_ARGB32_OFFSET_G, 1, 1, f);
|
|
|
|
fwrite(data + y * stride + 4 * x + GFX_ARGB32_OFFSET_B, 1, 1, f);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
fclose(f);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2007-03-22 10:30:00 -07:00
|
|
|
// ----------------------------------------------------------------------
|
|
|
|
|
|
|
|
nsSVGRenderState::nsSVGRenderState(nsIRenderingContext *aContext) :
|
|
|
|
mRenderMode(NORMAL), mRenderingContext(aContext)
|
|
|
|
{
|
2007-12-18 15:01:15 -08:00
|
|
|
mGfxContext = aContext->ThebesContext();
|
2007-03-22 10:30:00 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
nsSVGRenderState::nsSVGRenderState(gfxContext *aContext) :
|
|
|
|
mRenderMode(NORMAL), mRenderingContext(nsnull), mGfxContext(aContext)
|
|
|
|
{
|
|
|
|
}
|