2005-09-13 22:38:36 +00: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
|
|
|
|
* Scooter Morris.
|
|
|
|
* Portions created by the Initial Developer are Copyright (C) 2005
|
|
|
|
* the Initial Developer. All Rights Reserved.
|
|
|
|
*
|
|
|
|
* Contributor(s):
|
|
|
|
* Scooter Morris <scootermorris@comcast.net>
|
|
|
|
*
|
|
|
|
* Alternatively, the contents of this file may be used under the terms of
|
|
|
|
* either 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 ***** */
|
|
|
|
|
2006-03-22 01:40:00 +00:00
|
|
|
#include "nsGkAtoms.h"
|
2005-09-13 22:38:36 +00:00
|
|
|
#include "nsIDOMSVGAnimatedEnum.h"
|
|
|
|
#include "nsIDOMSVGAnimatedRect.h"
|
|
|
|
#include "nsIDOMSVGAnimTransformList.h"
|
|
|
|
#include "nsIDOMSVGTransformList.h"
|
|
|
|
#include "nsSVGAnimatedPreserveAspectRatio.h"
|
|
|
|
#include "nsStyleContext.h"
|
|
|
|
#include "nsINameSpaceManager.h"
|
|
|
|
#include "nsISVGChildFrame.h"
|
|
|
|
#include "nsIDOMSVGRect.h"
|
|
|
|
#include "nsSVGMatrix.h"
|
|
|
|
#include "nsSVGRect.h"
|
|
|
|
#include "nsLayoutAtoms.h"
|
|
|
|
#include "nsSVGUtils.h"
|
2006-06-15 19:10:28 +00:00
|
|
|
#include "nsSVGOuterSVGFrame.h"
|
2006-04-14 15:09:39 +00:00
|
|
|
#include "nsSVGPatternElement.h"
|
2006-05-02 15:05:25 +00:00
|
|
|
#include "nsSVGGeometryFrame.h"
|
2006-05-05 16:06:43 +00:00
|
|
|
#include "nsSVGPatternFrame.h"
|
2006-11-27 17:30:57 +00:00
|
|
|
#include "gfxASurface.h"
|
|
|
|
#include "gfxContext.h"
|
2005-09-13 22:38:36 +00:00
|
|
|
|
|
|
|
#ifdef DEBUG_scooter
|
|
|
|
static void printCTM(char *msg, nsIDOMSVGMatrix *aCTM);
|
|
|
|
static void printRect(char *msg, nsIDOMSVGRect *aRect);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------
|
|
|
|
// Implementation
|
|
|
|
|
2006-09-08 13:54:05 +00:00
|
|
|
nsSVGPatternFrame::nsSVGPatternFrame(nsStyleContext* aContext,
|
|
|
|
nsIDOMSVGURIReference *aRef) :
|
|
|
|
nsSVGPatternFrameBase(aContext),
|
|
|
|
mNextPattern(nsnull),
|
|
|
|
mLoopFlag(PR_FALSE)
|
|
|
|
{
|
|
|
|
if (aRef) {
|
|
|
|
// Get the hRef
|
|
|
|
aRef->GetHref(getter_AddRefs(mHref));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2005-09-13 22:38:36 +00:00
|
|
|
nsSVGPatternFrame::~nsSVGPatternFrame()
|
|
|
|
{
|
2006-03-22 01:40:00 +00:00
|
|
|
WillModify(mod_die);
|
|
|
|
if (mNextPattern)
|
|
|
|
mNextPattern->RemoveObserver(this);
|
2005-09-13 22:38:36 +00:00
|
|
|
|
|
|
|
// Notify the world that we're dying
|
|
|
|
DidModify(mod_die);
|
|
|
|
}
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------
|
|
|
|
// nsISupports methods:
|
|
|
|
|
|
|
|
NS_INTERFACE_MAP_BEGIN(nsSVGPatternFrame)
|
|
|
|
NS_INTERFACE_MAP_ENTRY(nsISVGValueObserver)
|
2006-01-18 16:31:42 +00:00
|
|
|
NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
|
2005-09-13 22:38:36 +00:00
|
|
|
NS_INTERFACE_MAP_END_INHERITING(nsSVGPatternFrameBase)
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------
|
|
|
|
// nsISVGValueObserver methods:
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsSVGPatternFrame::WillModifySVGObservable(nsISVGValue* observable,
|
|
|
|
modificationType aModType)
|
|
|
|
{
|
|
|
|
WillModify(aModType);
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsSVGPatternFrame::DidModifySVGObservable(nsISVGValue* observable,
|
|
|
|
nsISVGValue::modificationType aModType)
|
|
|
|
{
|
2006-05-05 16:06:43 +00:00
|
|
|
nsIFrame *pattern = nsnull;
|
|
|
|
CallQueryInterface(observable, &pattern);
|
2005-09-13 22:38:36 +00:00
|
|
|
// Is this a pattern we are observing that is going away?
|
|
|
|
if (mNextPattern && aModType == nsISVGValue::mod_die && pattern) {
|
|
|
|
// Yes, we need to handle this differently
|
2006-05-05 16:06:43 +00:00
|
|
|
if (mNextPattern == pattern) {
|
2005-09-13 22:38:36 +00:00
|
|
|
mNextPattern = nsnull;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// Something we depend on was modified -- pass it on!
|
|
|
|
DidModify(aModType);
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------
|
|
|
|
// nsIFrame methods:
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
2006-03-09 18:55:21 +00:00
|
|
|
nsSVGPatternFrame::DidSetStyleContext()
|
2005-09-13 22:38:36 +00:00
|
|
|
{
|
2006-03-22 01:40:00 +00:00
|
|
|
WillModify();
|
|
|
|
DidModify();
|
2005-09-13 22:38:36 +00:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2006-03-22 01:40:00 +00:00
|
|
|
NS_IMETHODIMP
|
|
|
|
nsSVGPatternFrame::AttributeChanged(PRInt32 aNameSpaceID,
|
|
|
|
nsIAtom* aAttribute,
|
|
|
|
PRInt32 aModType)
|
|
|
|
{
|
|
|
|
if (aNameSpaceID == kNameSpaceID_None &&
|
|
|
|
(aAttribute == nsGkAtoms::patternUnits ||
|
|
|
|
aAttribute == nsGkAtoms::patternContentUnits ||
|
|
|
|
aAttribute == nsGkAtoms::patternTransform ||
|
|
|
|
aAttribute == nsGkAtoms::x ||
|
|
|
|
aAttribute == nsGkAtoms::y ||
|
|
|
|
aAttribute == nsGkAtoms::width ||
|
|
|
|
aAttribute == nsGkAtoms::height ||
|
|
|
|
aAttribute == nsGkAtoms::preserveAspectRatio ||
|
|
|
|
aAttribute == nsGkAtoms::viewBox)) {
|
|
|
|
WillModify();
|
|
|
|
DidModify();
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (aNameSpaceID == kNameSpaceID_XLink &&
|
|
|
|
aAttribute == nsGkAtoms::href) {
|
|
|
|
if (mNextPattern)
|
|
|
|
mNextPattern->RemoveObserver(this);
|
|
|
|
mNextPattern = nsnull;
|
|
|
|
WillModify();
|
|
|
|
DidModify();
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
return nsSVGPatternFrameBase::AttributeChanged(aNameSpaceID,
|
|
|
|
aAttribute, aModType);
|
|
|
|
}
|
|
|
|
|
2005-09-13 22:38:36 +00:00
|
|
|
nsIAtom*
|
|
|
|
nsSVGPatternFrame::GetType() const
|
|
|
|
{
|
|
|
|
return nsLayoutAtoms::svgPatternFrame;
|
|
|
|
}
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------
|
2006-06-01 15:31:15 +00:00
|
|
|
// nsSVGContainerFrame methods:
|
2005-09-13 22:38:36 +00:00
|
|
|
|
|
|
|
// If our GetCanvasTM is getting called, we
|
|
|
|
// need to return *our current* transformation
|
|
|
|
// matrix, which depends on our units parameters
|
|
|
|
// and X, Y, Width, and Height
|
|
|
|
already_AddRefed<nsIDOMSVGMatrix>
|
|
|
|
nsSVGPatternFrame::GetCanvasTM() {
|
2006-02-09 18:15:03 +00:00
|
|
|
nsIDOMSVGMatrix *rCTM;
|
2005-09-13 22:38:36 +00:00
|
|
|
|
|
|
|
if (mCTM) {
|
2006-02-09 18:15:03 +00:00
|
|
|
rCTM = mCTM;
|
|
|
|
NS_IF_ADDREF(rCTM);
|
2005-09-13 22:38:36 +00:00
|
|
|
} else {
|
|
|
|
// Do we know our rendering parent?
|
|
|
|
if (mSource) {
|
|
|
|
// Yes, use it!
|
2006-02-09 18:15:03 +00:00
|
|
|
mSource->GetCanvasTM(&rCTM);
|
2005-09-13 22:38:36 +00:00
|
|
|
} else {
|
2006-05-02 15:05:25 +00:00
|
|
|
// No, return an identity
|
|
|
|
// We get here when geometry in the <pattern> container is updated
|
|
|
|
NS_NewSVGMatrix(&rCTM);
|
2005-09-13 22:38:36 +00:00
|
|
|
}
|
|
|
|
}
|
2006-02-09 18:15:03 +00:00
|
|
|
return rCTM;
|
2005-09-13 22:38:36 +00:00
|
|
|
}
|
|
|
|
|
2006-05-05 16:06:43 +00:00
|
|
|
nsresult
|
2006-11-27 17:30:57 +00:00
|
|
|
nsSVGPatternFrame::PaintPattern(cairo_surface_t** surface,
|
2005-09-13 22:38:36 +00:00
|
|
|
nsIDOMSVGMatrix** patternMatrix,
|
2006-05-02 15:05:25 +00:00
|
|
|
nsSVGGeometryFrame *aSource)
|
2005-09-13 22:38:36 +00:00
|
|
|
{
|
|
|
|
|
|
|
|
/*
|
|
|
|
* General approach:
|
|
|
|
* Set the content geometry stuff
|
|
|
|
* Calculate our bbox (using x,y,width,height & patternUnits &
|
|
|
|
* patternTransform)
|
|
|
|
* Create the surface
|
|
|
|
* Calculate the content transformation matrix
|
|
|
|
* Get our children (we may need to get them from another Pattern)
|
|
|
|
* Call SVGPaint on all of our children
|
|
|
|
* Return
|
|
|
|
*/
|
|
|
|
*surface = nsnull;
|
2006-03-22 01:40:00 +00:00
|
|
|
*patternMatrix = nsnull;
|
2005-09-13 22:38:36 +00:00
|
|
|
|
|
|
|
// Get our child
|
|
|
|
nsIFrame *firstKid;
|
|
|
|
if (NS_FAILED(GetPatternFirstChild(&firstKid)))
|
|
|
|
return NS_ERROR_FAILURE; // Either no kids or a bad reference
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Get the content geometry information. This is a little tricky --
|
|
|
|
* our parent is probably a <defs>, but we are rendering in the context
|
|
|
|
* of some geometry source. Our content geometry information needs to
|
|
|
|
* come from our rendering parent as opposed to our content parent. We
|
|
|
|
* get that information from aSource, which is passed to us from the
|
|
|
|
* backend renderer.
|
2006-04-04 20:40:27 +00:00
|
|
|
*
|
|
|
|
* There are three "geometries" that we need:
|
|
|
|
* 1) The bounding box for the pattern. We use this to get the
|
|
|
|
* width and height for the surface, and as the return to
|
|
|
|
* GetBBox.
|
|
|
|
* 2) The transformation matrix for the pattern. This is not *quite*
|
|
|
|
* the same as the canvas transformation matrix that we will
|
|
|
|
* provide to our rendering children since we "fudge" it a little
|
|
|
|
* to get the renderer to handle the translations correctly for us.
|
|
|
|
* 3) The CTM that we return to our children who make up the pattern.
|
2005-09-13 22:38:36 +00:00
|
|
|
*/
|
|
|
|
|
2006-04-04 20:40:27 +00:00
|
|
|
// Get all of the information we need from our "caller" -- i.e.
|
|
|
|
// the geometry that is being rendered with a pattern
|
2006-04-14 15:09:39 +00:00
|
|
|
nsSVGElement *callerContent;
|
2006-04-04 20:40:27 +00:00
|
|
|
nsCOMPtr<nsIDOMSVGRect> callerBBox;
|
|
|
|
nsCOMPtr<nsIDOMSVGMatrix> callerCTM;
|
|
|
|
if (NS_FAILED(GetCallerGeometry(getter_AddRefs(callerCTM),
|
|
|
|
getter_AddRefs(callerBBox),
|
|
|
|
&callerContent, aSource)))
|
2005-09-13 22:38:36 +00:00
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
|
2006-04-04 20:40:27 +00:00
|
|
|
// Construct the CTM that we will provide to our children when we
|
|
|
|
// render them into the tile.
|
|
|
|
if (NS_FAILED(ConstructCTM(getter_AddRefs(mCTM), callerBBox)))
|
2005-09-13 22:38:36 +00:00
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
|
2006-04-04 20:40:27 +00:00
|
|
|
// Get the bounding box of the pattern. This will be used to determine
|
|
|
|
// the size of the surface, and will also be used to define the bounding
|
|
|
|
// box for the pattern tile.
|
2006-06-28 12:32:26 +00:00
|
|
|
nsCOMPtr<nsIDOMSVGRect> bbox;
|
|
|
|
if (NS_FAILED(GetPatternRect(getter_AddRefs(bbox), callerBBox,
|
2006-04-04 20:40:27 +00:00
|
|
|
callerContent)))
|
2006-02-09 18:15:03 +00:00
|
|
|
return NS_ERROR_FAILURE;
|
2006-04-04 20:40:27 +00:00
|
|
|
|
|
|
|
// Get the transformation matrix that we will hand to the renderer's pattern
|
|
|
|
// routine.
|
2006-06-28 12:32:26 +00:00
|
|
|
if (NS_FAILED(GetPatternMatrix(patternMatrix, bbox, callerCTM)))
|
2006-04-04 20:40:27 +00:00
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
|
2005-09-13 22:38:36 +00:00
|
|
|
#ifdef DEBUG_scooter
|
2006-06-28 12:32:26 +00:00
|
|
|
printRect("Bounding Rect: ",bbox);
|
2006-04-04 20:40:27 +00:00
|
|
|
printCTM("Pattern TM ",*patternMatrix);
|
|
|
|
printCTM("Child TM ",mCTM);
|
2005-09-13 22:38:36 +00:00
|
|
|
#endif
|
2006-04-04 20:40:27 +00:00
|
|
|
|
|
|
|
// Now that we have all of the necessary geometries, we can
|
2006-06-28 12:32:26 +00:00
|
|
|
// create our surface.
|
2006-09-26 16:36:03 +00:00
|
|
|
cairo_surface_t *patternSurface = CreateSurface(bbox);
|
|
|
|
if (!patternSurface)
|
2006-04-04 20:40:27 +00:00
|
|
|
return NS_ERROR_FAILURE;
|
2005-09-13 22:38:36 +00:00
|
|
|
|
2006-11-27 17:30:57 +00:00
|
|
|
gfxUnknownSurface tmpSurface(patternSurface);
|
|
|
|
gfxContext tmpContext(&tmpSurface);
|
|
|
|
|
|
|
|
// thebes types don't like being stack allocated - addref the surface
|
|
|
|
// so that gfxContext doesn't try destroying it (scope will delete it)
|
|
|
|
tmpSurface.AddRef();
|
|
|
|
|
|
|
|
nsSVGRenderState tmpState(&tmpContext);
|
2005-09-13 22:38:36 +00:00
|
|
|
|
|
|
|
// OK, now render -- note that we use "firstKid", which
|
|
|
|
// we got at the beginning because it takes care of the
|
|
|
|
// referenced pattern situation for us
|
2006-02-09 18:15:03 +00:00
|
|
|
|
|
|
|
// Set our geometrical parent
|
|
|
|
mSource = aSource;
|
|
|
|
|
2005-09-13 22:38:36 +00:00
|
|
|
nsRect dummyRect;
|
|
|
|
for (nsIFrame* kid = firstKid; kid;
|
|
|
|
kid = kid->GetNextSibling()) {
|
2006-11-27 17:30:57 +00:00
|
|
|
nsSVGUtils::PaintChildWithEffects(&tmpState, nsnull, kid);
|
2005-09-13 22:38:36 +00:00
|
|
|
}
|
2006-02-09 18:15:03 +00:00
|
|
|
mSource = nsnull;
|
2005-09-13 22:38:36 +00:00
|
|
|
|
|
|
|
*surface = patternSurface;
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Will probably need something like this... */
|
|
|
|
// How do we handle the insertion of a new frame?
|
|
|
|
// We really don't want to rerender this every time,
|
|
|
|
// do we?
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsSVGPatternFrame::GetPatternFirstChild(nsIFrame **kid)
|
|
|
|
{
|
|
|
|
nsresult rv = NS_OK;
|
2006-03-22 01:40:00 +00:00
|
|
|
|
2005-09-13 22:38:36 +00:00
|
|
|
// Do we have any children ourselves?
|
2006-03-22 01:40:00 +00:00
|
|
|
if (!(*kid = mFrames.FirstChild())) {
|
2005-09-13 22:38:36 +00:00
|
|
|
// No, see if we chain to someone who does
|
|
|
|
if (checkURITarget())
|
|
|
|
rv = mNextPattern->GetPatternFirstChild(kid);
|
|
|
|
else
|
|
|
|
rv = NS_ERROR_FAILURE; // No children = error
|
|
|
|
}
|
|
|
|
mLoopFlag = PR_FALSE;
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
|
2006-05-05 16:06:43 +00:00
|
|
|
PRUint16
|
|
|
|
nsSVGPatternFrame::GetPatternUnits()
|
2005-09-13 22:38:36 +00:00
|
|
|
{
|
2006-05-05 16:06:43 +00:00
|
|
|
PRUint16 rv;
|
|
|
|
|
2006-03-22 01:40:00 +00:00
|
|
|
// See if we need to get the value from another pattern
|
|
|
|
if (!checkURITarget(nsGkAtoms::patternUnits)) {
|
|
|
|
// No, return the values
|
2006-04-04 20:40:27 +00:00
|
|
|
nsCOMPtr<nsIDOMSVGPatternElement> patternElement =
|
|
|
|
do_QueryInterface(mContent);
|
2006-03-22 01:40:00 +00:00
|
|
|
nsCOMPtr<nsIDOMSVGAnimatedEnumeration> units;
|
|
|
|
patternElement->GetPatternUnits(getter_AddRefs(units));
|
2006-05-05 16:06:43 +00:00
|
|
|
units->GetAnimVal(&rv);
|
2006-03-22 01:40:00 +00:00
|
|
|
} else {
|
|
|
|
// Yes, get it from the target
|
2006-05-05 16:06:43 +00:00
|
|
|
rv = mNextPattern->GetPatternUnits();
|
2006-03-22 01:40:00 +00:00
|
|
|
}
|
|
|
|
mLoopFlag = PR_FALSE;
|
2006-05-05 16:06:43 +00:00
|
|
|
return rv;
|
2005-09-13 22:38:36 +00:00
|
|
|
}
|
|
|
|
|
2006-05-05 16:06:43 +00:00
|
|
|
PRUint16
|
|
|
|
nsSVGPatternFrame::GetPatternContentUnits()
|
2005-09-13 22:38:36 +00:00
|
|
|
{
|
2006-05-05 16:06:43 +00:00
|
|
|
PRUint16 rv;
|
|
|
|
|
2006-03-22 01:40:00 +00:00
|
|
|
// See if we need to get the value from another pattern
|
|
|
|
if (!checkURITarget(nsGkAtoms::patternContentUnits)) {
|
|
|
|
// No, return the values
|
2006-04-04 20:40:27 +00:00
|
|
|
nsCOMPtr<nsIDOMSVGPatternElement> patternElement =
|
|
|
|
do_QueryInterface(mContent);
|
2006-03-22 01:40:00 +00:00
|
|
|
nsCOMPtr<nsIDOMSVGAnimatedEnumeration> units;
|
|
|
|
patternElement->GetPatternContentUnits(getter_AddRefs(units));
|
2006-05-05 16:06:43 +00:00
|
|
|
units->GetAnimVal(&rv);
|
2006-03-22 01:40:00 +00:00
|
|
|
} else {
|
|
|
|
// Yes, get it from the target
|
2006-05-05 16:06:43 +00:00
|
|
|
rv = mNextPattern->GetPatternContentUnits();
|
2006-03-22 01:40:00 +00:00
|
|
|
}
|
|
|
|
mLoopFlag = PR_FALSE;
|
2006-05-05 16:06:43 +00:00
|
|
|
return rv;
|
2005-09-13 22:38:36 +00:00
|
|
|
}
|
|
|
|
|
2006-05-05 16:06:43 +00:00
|
|
|
nsresult
|
2005-09-13 22:38:36 +00:00
|
|
|
nsSVGPatternFrame::GetPatternTransform(nsIDOMSVGMatrix **aPatternTransform)
|
|
|
|
{
|
2006-04-20 15:24:51 +00:00
|
|
|
*aPatternTransform = nsnull;
|
2006-05-05 16:06:43 +00:00
|
|
|
nsresult rv;
|
2006-04-20 15:24:51 +00:00
|
|
|
|
2005-09-13 22:38:36 +00:00
|
|
|
// See if we need to get the value from another pattern
|
2006-03-22 01:40:00 +00:00
|
|
|
if (!checkURITarget(nsGkAtoms::patternTransform)) {
|
2005-09-13 22:38:36 +00:00
|
|
|
// No, return the values
|
2006-04-04 20:40:27 +00:00
|
|
|
nsCOMPtr<nsIDOMSVGPatternElement> patternElement =
|
|
|
|
do_QueryInterface(mContent);
|
2006-03-22 01:40:00 +00:00
|
|
|
nsCOMPtr<nsIDOMSVGAnimatedTransformList> trans;
|
|
|
|
patternElement->GetPatternTransform(getter_AddRefs(trans));
|
2005-09-13 22:38:36 +00:00
|
|
|
nsCOMPtr<nsIDOMSVGTransformList> lTrans;
|
2006-02-09 18:15:03 +00:00
|
|
|
trans->GetAnimVal(getter_AddRefs(lTrans));
|
2006-05-05 16:06:43 +00:00
|
|
|
rv = lTrans->GetConsolidationMatrix(aPatternTransform);
|
|
|
|
if (NS_FAILED(rv) || !*aPatternTransform)
|
|
|
|
rv = NS_NewSVGMatrix(aPatternTransform);
|
2005-09-13 22:38:36 +00:00
|
|
|
} else {
|
|
|
|
// Yes, get it from the target
|
2006-05-05 16:06:43 +00:00
|
|
|
rv = mNextPattern->GetPatternTransform(aPatternTransform);
|
2005-09-13 22:38:36 +00:00
|
|
|
}
|
|
|
|
mLoopFlag = PR_FALSE;
|
|
|
|
|
2006-05-05 16:06:43 +00:00
|
|
|
return rv;
|
2005-09-13 22:38:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
|
|
|
nsSVGPatternFrame::GetViewBox(nsIDOMSVGRect **aViewBox)
|
|
|
|
{
|
2006-03-22 01:40:00 +00:00
|
|
|
// See if we need to get the value from another pattern
|
|
|
|
if (!checkURITarget(nsGkAtoms::viewBox)) {
|
|
|
|
// No, return the values
|
2006-04-04 20:40:27 +00:00
|
|
|
nsCOMPtr<nsIDOMSVGFitToViewBox> patternElement =
|
|
|
|
do_QueryInterface(mContent);
|
2006-03-22 01:40:00 +00:00
|
|
|
nsCOMPtr<nsIDOMSVGAnimatedRect> viewBox;
|
|
|
|
patternElement->GetViewBox(getter_AddRefs(viewBox));
|
|
|
|
viewBox->GetAnimVal(aViewBox);
|
|
|
|
} else {
|
|
|
|
// Yes, get it from the target
|
|
|
|
mNextPattern->GetViewBox(aViewBox);
|
2005-09-13 22:38:36 +00:00
|
|
|
}
|
2006-03-22 01:40:00 +00:00
|
|
|
mLoopFlag = PR_FALSE;
|
2005-09-13 22:38:36 +00:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
NS_IMETHODIMP
|
2006-02-26 17:58:58 +00:00
|
|
|
nsSVGPatternFrame::GetPreserveAspectRatio(nsIDOMSVGAnimatedPreserveAspectRatio
|
|
|
|
**aPreserveAspectRatio)
|
2005-09-13 22:38:36 +00:00
|
|
|
{
|
2006-03-22 01:40:00 +00:00
|
|
|
// See if we need to get the value from another pattern
|
|
|
|
if (!checkURITarget(nsGkAtoms::preserveAspectRatio)) {
|
|
|
|
// No, return the values
|
2006-04-04 20:40:27 +00:00
|
|
|
nsCOMPtr<nsIDOMSVGFitToViewBox> patternElement =
|
|
|
|
do_QueryInterface(mContent);
|
2006-03-22 01:40:00 +00:00
|
|
|
patternElement->GetPreserveAspectRatio(aPreserveAspectRatio);
|
|
|
|
} else {
|
|
|
|
// Yes, get it from the target
|
|
|
|
mNextPattern->GetPreserveAspectRatio(aPreserveAspectRatio);
|
2005-09-13 22:38:36 +00:00
|
|
|
}
|
2006-03-22 01:40:00 +00:00
|
|
|
mLoopFlag = PR_FALSE;
|
2005-09-13 22:38:36 +00:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2006-04-14 15:09:39 +00:00
|
|
|
nsSVGLength2 *
|
|
|
|
nsSVGPatternFrame::GetX()
|
2005-09-13 22:38:36 +00:00
|
|
|
{
|
2006-04-14 15:09:39 +00:00
|
|
|
nsSVGLength2 *rv = nsnull;
|
|
|
|
|
2006-03-22 01:40:00 +00:00
|
|
|
// See if we need to get the value from another pattern
|
|
|
|
if (checkURITarget(nsGkAtoms::x)) {
|
|
|
|
// Yes, get it from the target
|
2006-04-14 15:09:39 +00:00
|
|
|
rv = mNextPattern->GetX();
|
2006-03-22 01:40:00 +00:00
|
|
|
} else {
|
|
|
|
// No, return the values
|
2006-04-14 15:09:39 +00:00
|
|
|
nsSVGPatternElement *pattern =
|
|
|
|
NS_STATIC_CAST(nsSVGPatternElement*, mContent);
|
|
|
|
rv = &pattern->mLengthAttributes[nsSVGPatternElement::X];
|
2005-09-13 22:38:36 +00:00
|
|
|
}
|
2006-03-22 01:40:00 +00:00
|
|
|
mLoopFlag = PR_FALSE;
|
2006-04-14 15:09:39 +00:00
|
|
|
return rv;
|
2005-09-13 22:38:36 +00:00
|
|
|
}
|
|
|
|
|
2006-04-14 15:09:39 +00:00
|
|
|
nsSVGLength2 *
|
|
|
|
nsSVGPatternFrame::GetY()
|
2005-09-13 22:38:36 +00:00
|
|
|
{
|
2006-04-14 15:09:39 +00:00
|
|
|
nsSVGLength2 *rv = nsnull;
|
|
|
|
|
2006-03-22 01:40:00 +00:00
|
|
|
// See if we need to get the value from another pattern
|
|
|
|
if (checkURITarget(nsGkAtoms::y)) {
|
|
|
|
// Yes, get it from the target
|
2006-04-14 15:09:39 +00:00
|
|
|
rv = mNextPattern->GetY();
|
2006-03-22 01:40:00 +00:00
|
|
|
} else {
|
|
|
|
// No, return the values
|
2006-04-14 15:09:39 +00:00
|
|
|
nsSVGPatternElement *pattern =
|
|
|
|
NS_STATIC_CAST(nsSVGPatternElement*, mContent);
|
|
|
|
rv = &pattern->mLengthAttributes[nsSVGPatternElement::Y];
|
2005-09-13 22:38:36 +00:00
|
|
|
}
|
2006-03-22 01:40:00 +00:00
|
|
|
mLoopFlag = PR_FALSE;
|
2006-04-14 15:09:39 +00:00
|
|
|
return rv;
|
2005-09-13 22:38:36 +00:00
|
|
|
}
|
|
|
|
|
2006-04-14 15:09:39 +00:00
|
|
|
nsSVGLength2 *
|
|
|
|
nsSVGPatternFrame::GetWidth()
|
2006-03-22 01:40:00 +00:00
|
|
|
{
|
2006-04-14 15:09:39 +00:00
|
|
|
nsSVGLength2 *rv = nsnull;
|
|
|
|
|
2005-09-13 22:38:36 +00:00
|
|
|
// See if we need to get the value from another pattern
|
2006-03-22 01:40:00 +00:00
|
|
|
if (checkURITarget(nsGkAtoms::width)) {
|
2005-09-13 22:38:36 +00:00
|
|
|
// Yes, get it from the target
|
2006-04-14 15:09:39 +00:00
|
|
|
rv = mNextPattern->GetWidth();
|
2006-03-22 01:40:00 +00:00
|
|
|
} else {
|
|
|
|
// No, return the values
|
2006-04-14 15:09:39 +00:00
|
|
|
nsSVGPatternElement *pattern =
|
|
|
|
NS_STATIC_CAST(nsSVGPatternElement*, mContent);
|
|
|
|
rv = &pattern->mLengthAttributes[nsSVGPatternElement::WIDTH];
|
2006-03-22 01:40:00 +00:00
|
|
|
}
|
2005-09-13 22:38:36 +00:00
|
|
|
mLoopFlag = PR_FALSE;
|
2006-04-14 15:09:39 +00:00
|
|
|
return rv;
|
2005-09-13 22:38:36 +00:00
|
|
|
}
|
|
|
|
|
2006-04-14 15:09:39 +00:00
|
|
|
nsSVGLength2 *
|
|
|
|
nsSVGPatternFrame::GetHeight()
|
2006-03-22 01:40:00 +00:00
|
|
|
{
|
2006-04-14 15:09:39 +00:00
|
|
|
nsSVGLength2 *rv = nsnull;
|
|
|
|
|
2005-09-13 22:38:36 +00:00
|
|
|
// See if we need to get the value from another pattern
|
2006-03-22 01:40:00 +00:00
|
|
|
if (checkURITarget(nsGkAtoms::height)) {
|
2005-09-13 22:38:36 +00:00
|
|
|
// Yes, get it from the target
|
2006-04-14 15:09:39 +00:00
|
|
|
rv = mNextPattern->GetHeight();
|
2006-03-22 01:40:00 +00:00
|
|
|
} else {
|
|
|
|
// No, return the values
|
2006-04-14 15:09:39 +00:00
|
|
|
nsSVGPatternElement *pattern =
|
|
|
|
NS_STATIC_CAST(nsSVGPatternElement*, mContent);
|
|
|
|
rv = &pattern->mLengthAttributes[nsSVGPatternElement::HEIGHT];
|
2005-09-13 22:38:36 +00:00
|
|
|
}
|
|
|
|
mLoopFlag = PR_FALSE;
|
2006-04-14 15:09:39 +00:00
|
|
|
return rv;
|
2005-09-13 22:38:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Private (helper) methods
|
|
|
|
PRBool
|
|
|
|
nsSVGPatternFrame::checkURITarget(nsIAtom *attr) {
|
|
|
|
// Was the attribute explicitly set?
|
|
|
|
if (mContent->HasAttr(kNameSpaceID_None, attr)) {
|
|
|
|
// Yes, just return
|
|
|
|
return PR_FALSE;
|
|
|
|
}
|
|
|
|
return checkURITarget();
|
|
|
|
}
|
|
|
|
|
|
|
|
PRBool
|
|
|
|
nsSVGPatternFrame::checkURITarget(void) {
|
2006-02-09 18:15:03 +00:00
|
|
|
nsIFrame *nextPattern;
|
2005-09-13 22:38:36 +00:00
|
|
|
mLoopFlag = PR_TRUE; // Set our loop detection flag
|
|
|
|
// Have we already figured out the next Pattern?
|
|
|
|
if (mNextPattern != nsnull) {
|
|
|
|
return PR_TRUE;
|
|
|
|
}
|
|
|
|
|
2006-03-22 01:40:00 +00:00
|
|
|
// check if we reference another pattern to "inherit" its children
|
|
|
|
// or attributes
|
|
|
|
nsAutoString href;
|
|
|
|
mHref->GetAnimVal(href);
|
2005-09-13 22:38:36 +00:00
|
|
|
// Do we have URI?
|
2006-03-22 01:40:00 +00:00
|
|
|
if (href.IsEmpty()) {
|
2005-09-13 22:38:36 +00:00
|
|
|
return PR_FALSE; // No, return the default
|
|
|
|
}
|
|
|
|
|
2005-10-18 20:33:35 +00:00
|
|
|
nsCOMPtr<nsIURI> targetURI;
|
|
|
|
nsCOMPtr<nsIURI> base = mContent->GetBaseURI();
|
|
|
|
nsContentUtils::NewURIWithDocumentCharset(getter_AddRefs(targetURI),
|
2006-03-22 01:40:00 +00:00
|
|
|
href, mContent->GetCurrentDoc(), base);
|
2005-10-18 20:33:35 +00:00
|
|
|
|
2005-09-13 22:38:36 +00:00
|
|
|
// Note that we are using *our* frame tree for this call,
|
|
|
|
// otherwise we're going to have to get the PresShell in each call
|
2006-04-04 20:40:27 +00:00
|
|
|
if (NS_SUCCEEDED(
|
|
|
|
nsSVGUtils::GetReferencedFrame(&nextPattern, targetURI,
|
|
|
|
mContent,
|
|
|
|
GetPresContext()->PresShell()))) {
|
2006-02-09 18:15:03 +00:00
|
|
|
nsIAtom* frameType = nextPattern->GetType();
|
2005-09-13 22:38:36 +00:00
|
|
|
if (frameType != nsLayoutAtoms::svgPatternFrame)
|
|
|
|
return PR_FALSE;
|
2006-02-09 18:15:03 +00:00
|
|
|
mNextPattern = (nsSVGPatternFrame *)nextPattern;
|
2005-09-13 22:38:36 +00:00
|
|
|
// Are we looping?
|
|
|
|
if (mNextPattern->mLoopFlag) {
|
|
|
|
// Yes, remove the reference and return an error
|
|
|
|
NS_WARNING("Pattern loop detected!");
|
|
|
|
mNextPattern = nsnull;
|
|
|
|
return PR_FALSE;
|
|
|
|
}
|
|
|
|
// Add ourselves to the observer list
|
|
|
|
if (mNextPattern) {
|
|
|
|
// Can't use the NS_ADD macro here because of nsISupports ambiguity
|
|
|
|
mNextPattern->AddObserver(this);
|
|
|
|
}
|
|
|
|
return PR_TRUE;
|
|
|
|
}
|
|
|
|
return PR_FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
// -------------------------------------------------------------------------
|
|
|
|
// Helper functions
|
|
|
|
// -------------------------------------------------------------------------
|
|
|
|
|
|
|
|
nsresult
|
2006-04-04 20:40:27 +00:00
|
|
|
nsSVGPatternFrame::GetPatternRect(nsIDOMSVGRect **patternRect,
|
|
|
|
nsIDOMSVGRect *bbox,
|
2006-04-14 15:09:39 +00:00
|
|
|
nsSVGElement *content)
|
2005-09-13 22:38:36 +00:00
|
|
|
{
|
|
|
|
// Get our type
|
2006-05-05 16:06:43 +00:00
|
|
|
PRUint16 type = GetPatternUnits();
|
2005-09-13 22:38:36 +00:00
|
|
|
|
|
|
|
// We need to initialize our box
|
2006-03-22 01:40:00 +00:00
|
|
|
float x,y,width,height;
|
|
|
|
|
|
|
|
// Get the pattern x,y,width, and height
|
2006-04-14 15:09:39 +00:00
|
|
|
nsSVGLength2 *tmpX, *tmpY, *tmpHeight, *tmpWidth;
|
|
|
|
tmpX = GetX();
|
|
|
|
tmpY = GetY();
|
|
|
|
tmpHeight = GetHeight();
|
|
|
|
tmpWidth = GetWidth();
|
2006-03-22 01:40:00 +00:00
|
|
|
|
2005-09-13 22:38:36 +00:00
|
|
|
if (type == nsIDOMSVGPatternElement::SVG_PUNITS_OBJECTBOUNDINGBOX) {
|
2006-04-14 15:09:39 +00:00
|
|
|
x = nsSVGUtils::ObjectSpace(bbox, tmpX);
|
|
|
|
y = nsSVGUtils::ObjectSpace(bbox, tmpY);
|
|
|
|
width = nsSVGUtils::ObjectSpace(bbox, tmpWidth);
|
|
|
|
height = nsSVGUtils::ObjectSpace(bbox, tmpHeight);
|
2005-09-13 22:38:36 +00:00
|
|
|
} else {
|
2006-04-14 15:09:39 +00:00
|
|
|
x = nsSVGUtils::UserSpace(content, tmpX);
|
|
|
|
y = nsSVGUtils::UserSpace(content, tmpY);
|
|
|
|
width = nsSVGUtils::UserSpace(content, tmpWidth);
|
|
|
|
height = nsSVGUtils::UserSpace(content, tmpHeight);
|
2005-09-13 22:38:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return NS_NewSVGRect(patternRect, x, y, width, height);
|
|
|
|
}
|
|
|
|
|
2006-05-05 16:06:43 +00:00
|
|
|
static float
|
|
|
|
GetLengthValue(nsSVGLength2 *aLength)
|
|
|
|
{
|
|
|
|
return aLength->GetAnimValue(NS_STATIC_CAST(nsSVGCoordCtxProvider*, nsnull));
|
|
|
|
}
|
|
|
|
|
2005-09-13 22:38:36 +00:00
|
|
|
nsresult
|
2006-04-04 20:40:27 +00:00
|
|
|
nsSVGPatternFrame::ConstructCTM(nsIDOMSVGMatrix **aCTM,
|
|
|
|
nsIDOMSVGRect *callerBBox)
|
2005-09-13 22:38:36 +00:00
|
|
|
{
|
2006-04-04 20:40:27 +00:00
|
|
|
nsCOMPtr<nsIDOMSVGMatrix> tCTM, tempTM;
|
|
|
|
|
|
|
|
// Begin by handling the objectBoundingBox conversion since
|
|
|
|
// this must be handled in the CTM
|
2006-05-05 16:06:43 +00:00
|
|
|
PRUint16 type = GetPatternContentUnits();
|
2006-04-04 20:40:27 +00:00
|
|
|
|
|
|
|
if (type == nsIDOMSVGPatternElement::SVG_PUNITS_OBJECTBOUNDINGBOX) {
|
|
|
|
// Use the bounding box
|
|
|
|
float minx,miny,width,height;
|
|
|
|
callerBBox->GetX(&minx);
|
|
|
|
callerBBox->GetY(&miny);
|
|
|
|
callerBBox->GetWidth(&width);
|
|
|
|
callerBBox->GetHeight(&height);
|
|
|
|
NS_NewSVGMatrix(getter_AddRefs(tCTM), width, 0.0f, 0.0f,
|
2006-05-30 16:10:26 +00:00
|
|
|
height, minx, miny);
|
2006-04-04 20:40:27 +00:00
|
|
|
} else {
|
|
|
|
NS_NewSVGMatrix(getter_AddRefs(tCTM));
|
|
|
|
}
|
|
|
|
|
|
|
|
// Do we have a viewbox?
|
|
|
|
nsCOMPtr<nsIDOMSVGRect> viewRect;
|
|
|
|
GetViewBox(getter_AddRefs(viewRect));
|
2005-09-13 22:38:36 +00:00
|
|
|
|
|
|
|
// See if we really have something
|
|
|
|
float viewBoxX, viewBoxY, viewBoxHeight, viewBoxWidth;
|
2006-04-04 20:40:27 +00:00
|
|
|
viewRect->GetX(&viewBoxX);
|
|
|
|
viewRect->GetY(&viewBoxY);
|
|
|
|
viewRect->GetHeight(&viewBoxHeight);
|
|
|
|
viewRect->GetWidth(&viewBoxWidth);
|
2005-09-13 22:38:36 +00:00
|
|
|
if (viewBoxHeight != 0.0f && viewBoxWidth != 0.0f) {
|
|
|
|
|
2006-05-05 16:06:43 +00:00
|
|
|
float viewportWidth = GetLengthValue(GetWidth());
|
|
|
|
float viewportHeight = GetLengthValue(GetHeight());
|
|
|
|
float refX = GetLengthValue(GetX());
|
|
|
|
float refY = GetLengthValue(GetY());
|
2005-09-13 22:38:36 +00:00
|
|
|
|
2006-02-26 17:58:58 +00:00
|
|
|
nsCOMPtr<nsIDOMSVGAnimatedPreserveAspectRatio> par;
|
|
|
|
GetPreserveAspectRatio(getter_AddRefs(par));
|
2005-09-13 22:38:36 +00:00
|
|
|
|
2006-02-26 17:58:58 +00:00
|
|
|
tempTM = nsSVGUtils::GetViewBoxTransform(viewportWidth, viewportHeight,
|
|
|
|
viewBoxX + refX, viewBoxY + refY,
|
|
|
|
viewBoxWidth, viewBoxHeight,
|
|
|
|
par,
|
|
|
|
PR_TRUE);
|
2005-09-13 22:38:36 +00:00
|
|
|
|
|
|
|
} else {
|
|
|
|
// No viewBox, construct from the (modified) parent matrix
|
2006-06-06 07:50:11 +00:00
|
|
|
NS_NewSVGMatrix(getter_AddRefs(tempTM));
|
2005-09-13 22:38:36 +00:00
|
|
|
}
|
2006-06-06 07:50:11 +00:00
|
|
|
tCTM->Multiply(tempTM, aCTM);
|
2005-09-13 22:38:36 +00:00
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsresult
|
2006-04-04 20:40:27 +00:00
|
|
|
nsSVGPatternFrame::GetPatternMatrix(nsIDOMSVGMatrix **aCTM,
|
|
|
|
nsIDOMSVGRect *bbox,
|
|
|
|
nsIDOMSVGMatrix *callerCTM)
|
2005-09-13 22:38:36 +00:00
|
|
|
{
|
2006-05-05 16:06:43 +00:00
|
|
|
*aCTM = nsnull;
|
|
|
|
|
2005-09-13 22:38:36 +00:00
|
|
|
// Get the pattern transform
|
|
|
|
nsCOMPtr<nsIDOMSVGMatrix> patternTransform;
|
2006-05-05 16:06:43 +00:00
|
|
|
nsresult rv = GetPatternTransform(getter_AddRefs(patternTransform));
|
|
|
|
NS_ENSURE_SUCCESS(rv, rv);
|
2005-09-13 22:38:36 +00:00
|
|
|
|
2006-04-04 20:40:27 +00:00
|
|
|
// We really want the pattern matrix to handle translations
|
|
|
|
float minx,miny;
|
|
|
|
bbox->GetX(&minx);
|
|
|
|
bbox->GetY(&miny);
|
|
|
|
nsCOMPtr<nsIDOMSVGMatrix> tCTM;
|
|
|
|
patternTransform->Translate(minx, miny, getter_AddRefs(tCTM));
|
|
|
|
|
|
|
|
// Multiply in the caller's CTM to handle device coordinates
|
|
|
|
callerCTM->Multiply(tCTM, aCTM);
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsresult
|
|
|
|
nsSVGPatternFrame::GetCallerGeometry(nsIDOMSVGMatrix **aCTM,
|
|
|
|
nsIDOMSVGRect **aBBox,
|
2006-04-14 15:09:39 +00:00
|
|
|
nsSVGElement **aContent,
|
2006-05-02 15:05:25 +00:00
|
|
|
nsSVGGeometryFrame *aSource)
|
2006-04-04 20:40:27 +00:00
|
|
|
{
|
|
|
|
*aCTM = nsnull;
|
|
|
|
*aBBox = nsnull;
|
|
|
|
*aContent = nsnull;
|
|
|
|
|
|
|
|
// Make sure the callerContent is an SVG element. If we are attempting
|
|
|
|
// to paint a pattern for text, then the content will be the #text, so we
|
|
|
|
// actually want the parent, which should be the <svg:text> or <svg:tspan>
|
|
|
|
// element.
|
2006-05-02 15:05:25 +00:00
|
|
|
nsIAtom *callerType = aSource->GetType();
|
2006-04-04 20:40:27 +00:00
|
|
|
if (callerType == nsLayoutAtoms::svgGlyphFrame) {
|
2006-04-14 15:09:39 +00:00
|
|
|
*aContent = NS_STATIC_CAST(nsSVGElement*,
|
2006-05-02 15:05:25 +00:00
|
|
|
aSource->GetContent()->GetParent());
|
2005-09-13 22:38:36 +00:00
|
|
|
} else {
|
2006-05-02 15:05:25 +00:00
|
|
|
*aContent = NS_STATIC_CAST(nsSVGElement*, aSource->GetContent());
|
2006-04-04 20:40:27 +00:00
|
|
|
}
|
|
|
|
NS_ASSERTION(aContent,"Caller does not have any content!");
|
|
|
|
if (!aContent)
|
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
|
|
|
|
// Get the calling geometry's bounding box. This
|
|
|
|
// will be in *device coordinates*
|
2006-05-02 15:05:25 +00:00
|
|
|
nsISVGChildFrame *callerSVGFrame;
|
2006-11-13 20:42:42 +00:00
|
|
|
if (callerType == nsGkAtoms::svgGlyphFrame)
|
|
|
|
CallQueryInterface(aSource->GetParent(), &callerSVGFrame);
|
|
|
|
else
|
|
|
|
CallQueryInterface(aSource, &callerSVGFrame);
|
2006-04-04 20:40:27 +00:00
|
|
|
callerSVGFrame->GetBBox(aBBox);
|
|
|
|
// Sanity check
|
|
|
|
{
|
|
|
|
float width, height;
|
|
|
|
(*aBBox)->GetWidth(&width);
|
|
|
|
(*aBBox)->GetHeight(&height);
|
|
|
|
if (width <= 0 || height <= 0) {
|
|
|
|
return NS_ERROR_FAILURE;
|
2005-09-13 22:38:36 +00:00
|
|
|
}
|
|
|
|
}
|
2006-04-04 20:40:27 +00:00
|
|
|
|
|
|
|
// Get the transformation matrix from our calling geometry
|
|
|
|
aSource->GetCanvasTM(aCTM);
|
|
|
|
|
|
|
|
// OK, now fix up the bounding box to reflect user coordinates
|
|
|
|
// We handle device unit scaling in pattern matrix
|
|
|
|
{
|
|
|
|
float x,y,width,height,xscale,yscale;
|
|
|
|
(*aBBox)->GetX(&x);
|
|
|
|
(*aBBox)->GetY(&y);
|
|
|
|
(*aBBox)->GetWidth(&width);
|
|
|
|
(*aBBox)->GetHeight(&height);
|
|
|
|
(*aCTM)->GetA(&xscale);
|
|
|
|
(*aCTM)->GetD(&yscale);
|
|
|
|
x = x / xscale;
|
|
|
|
y = y / yscale;
|
|
|
|
width = width / xscale;
|
|
|
|
height = height / yscale;
|
|
|
|
(*aBBox)->SetX(x);
|
|
|
|
(*aBBox)->SetY(y);
|
|
|
|
(*aBBox)->SetWidth(width);
|
|
|
|
(*aBBox)->SetHeight(height);
|
|
|
|
}
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
2006-09-26 16:36:03 +00:00
|
|
|
cairo_surface_t *
|
|
|
|
nsSVGPatternFrame::CreateSurface(nsIDOMSVGRect *bbox)
|
2006-04-04 20:40:27 +00:00
|
|
|
{
|
|
|
|
float width, height;
|
2006-06-28 12:32:26 +00:00
|
|
|
bbox->GetWidth(&width);
|
|
|
|
bbox->GetHeight(&height);
|
2006-04-04 20:40:27 +00:00
|
|
|
|
|
|
|
#ifdef DEBUG_scooter
|
|
|
|
printf("Creating %dX%d surface\n",(int)(width),(int)(height));
|
|
|
|
#endif
|
2006-09-26 16:36:03 +00:00
|
|
|
return cairo_image_surface_create(CAIRO_FORMAT_ARGB32,
|
|
|
|
(int)(width), (int)(height));
|
2005-09-13 22:38:36 +00:00
|
|
|
}
|
|
|
|
|
2006-05-16 15:55:01 +00:00
|
|
|
//----------------------------------------------------------------------
|
|
|
|
// nsSVGPaintServerFrame methods:
|
|
|
|
|
|
|
|
nsresult
|
2006-11-27 17:30:57 +00:00
|
|
|
nsSVGPatternFrame::SetupPaintServer(cairo_t *aCtx,
|
2006-05-16 15:55:01 +00:00
|
|
|
nsSVGGeometryFrame *aSource,
|
|
|
|
float aOpacity,
|
|
|
|
void **aClosure)
|
|
|
|
{
|
|
|
|
*aClosure = nsnull;
|
|
|
|
|
|
|
|
cairo_matrix_t matrix;
|
|
|
|
cairo_get_matrix(aCtx, &matrix);
|
|
|
|
|
|
|
|
// Paint it!
|
2006-09-26 16:36:03 +00:00
|
|
|
cairo_surface_t *surface;
|
2006-05-16 15:55:01 +00:00
|
|
|
nsCOMPtr<nsIDOMSVGMatrix> pMatrix;
|
|
|
|
cairo_identity_matrix(aCtx);
|
2006-11-27 17:30:57 +00:00
|
|
|
nsresult rv = PaintPattern(&surface, getter_AddRefs(pMatrix), aSource);
|
2006-05-16 15:55:01 +00:00
|
|
|
cairo_set_matrix(aCtx, &matrix);
|
2006-09-26 16:36:03 +00:00
|
|
|
if (NS_FAILED(rv)) {
|
|
|
|
cairo_surface_destroy(surface);
|
|
|
|
return rv;
|
|
|
|
}
|
2006-05-16 15:55:01 +00:00
|
|
|
|
|
|
|
// Translate the pattern frame
|
2006-09-11 15:26:19 +00:00
|
|
|
cairo_matrix_t pmatrix = nsSVGUtils::ConvertSVGMatrixToCairo(pMatrix);
|
2006-11-27 17:30:57 +00:00
|
|
|
cairo_matrix_invert(&matrix);
|
|
|
|
cairo_matrix_multiply(&pmatrix, &pmatrix, &matrix);
|
2006-09-26 16:36:03 +00:00
|
|
|
if (cairo_matrix_invert(&pmatrix)) {
|
|
|
|
cairo_surface_destroy(surface);
|
2006-05-16 15:55:01 +00:00
|
|
|
return NS_ERROR_FAILURE;
|
2006-09-26 16:36:03 +00:00
|
|
|
}
|
2006-05-16 15:55:01 +00:00
|
|
|
|
|
|
|
cairo_pattern_t *surface_pattern =
|
2006-09-26 16:36:03 +00:00
|
|
|
cairo_pattern_create_for_surface(surface);
|
|
|
|
|
|
|
|
// Decrease the surface reference count (pattern keeps a reference)
|
|
|
|
cairo_surface_destroy(surface);
|
|
|
|
|
2006-05-16 15:55:01 +00:00
|
|
|
if (!surface_pattern)
|
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
|
|
|
|
cairo_pattern_set_matrix (surface_pattern, &pmatrix);
|
|
|
|
cairo_pattern_set_extend (surface_pattern, CAIRO_EXTEND_REPEAT);
|
|
|
|
|
|
|
|
cairo_set_source(aCtx, surface_pattern);
|
|
|
|
|
2006-09-26 16:36:03 +00:00
|
|
|
*aClosure = surface_pattern;
|
2006-05-16 15:55:01 +00:00
|
|
|
|
|
|
|
return NS_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
nsSVGPatternFrame::CleanupPaintServer(cairo_t *aCtx, void *aClosure)
|
|
|
|
{
|
2006-09-26 16:36:03 +00:00
|
|
|
cairo_pattern_t *pattern = NS_STATIC_CAST(cairo_pattern_t*, aClosure);
|
|
|
|
cairo_pattern_destroy(pattern);
|
2006-05-16 15:55:01 +00:00
|
|
|
}
|
|
|
|
|
2005-09-13 22:38:36 +00:00
|
|
|
// -------------------------------------------------------------------------
|
|
|
|
// Public functions
|
|
|
|
// -------------------------------------------------------------------------
|
|
|
|
|
2006-03-26 21:30:36 +00:00
|
|
|
nsIFrame* NS_NewSVGPatternFrame(nsIPresShell* aPresShell,
|
|
|
|
nsIContent* aContent,
|
|
|
|
nsStyleContext* aContext)
|
2005-09-13 22:38:36 +00:00
|
|
|
{
|
2006-03-22 01:40:00 +00:00
|
|
|
nsCOMPtr<nsIDOMSVGPatternElement> patternElement = do_QueryInterface(aContent);
|
|
|
|
NS_ASSERTION(patternElement,
|
2005-09-13 22:38:36 +00:00
|
|
|
"NS_NewSVGPatternFrame -- Content doesn't support nsIDOMSVGPattern");
|
2006-03-22 01:40:00 +00:00
|
|
|
if (!patternElement)
|
2005-11-11 02:36:29 +00:00
|
|
|
return nsnull;
|
2006-03-26 21:30:36 +00:00
|
|
|
|
2006-02-09 18:15:03 +00:00
|
|
|
nsCOMPtr<nsIDOMSVGURIReference> ref = do_QueryInterface(aContent);
|
|
|
|
NS_ASSERTION(ref,
|
2005-09-13 22:38:36 +00:00
|
|
|
"NS_NewSVGPatternFrame -- Content doesn't support nsIDOMSVGURIReference");
|
|
|
|
|
|
|
|
#ifdef DEBUG_scooter
|
2006-03-22 01:40:00 +00:00
|
|
|
printf("NS_NewSVGPatternFrame\n");
|
2005-09-13 22:38:36 +00:00
|
|
|
#endif
|
2006-09-08 13:54:05 +00:00
|
|
|
return new (aPresShell) nsSVGPatternFrame(aContext, ref);
|
2005-09-13 22:38:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef DEBUG_scooter
|
|
|
|
static void printCTM(char *msg, nsIDOMSVGMatrix *aCTM)
|
|
|
|
{
|
|
|
|
float a,b,c,d,e,f;
|
|
|
|
aCTM->GetA(&a);
|
|
|
|
aCTM->GetB(&b);
|
|
|
|
aCTM->GetC(&c);
|
|
|
|
aCTM->GetD(&d);
|
|
|
|
aCTM->GetE(&e);
|
|
|
|
aCTM->GetF(&f);
|
|
|
|
printf("%s {%f,%f,%f,%f,%f,%f}\n",msg,a,b,c,d,e,f);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void printRect(char *msg, nsIDOMSVGRect *aRect)
|
|
|
|
{
|
|
|
|
float x,y,width,height;
|
|
|
|
aRect->GetX(&x);
|
|
|
|
aRect->GetY(&y);
|
|
|
|
aRect->GetWidth(&width);
|
|
|
|
aRect->GetHeight(&height);
|
|
|
|
printf("%s {%f,%f,%f,%f}\n",msg,x,y,width,height);
|
|
|
|
}
|
|
|
|
#endif
|