2017-10-27 20:33:53 +03:00
|
|
|
|
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
|
|
|
|
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
2012-05-21 15:12:37 +04:00
|
|
|
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
|
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
|
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
2005-09-14 02:38:36 +04:00
|
|
|
|
|
2012-03-26 15:58:59 +04:00
|
|
|
|
// Main header first:
|
2011-08-11 17:29:50 +04:00
|
|
|
|
#include "nsSVGPatternFrame.h"
|
|
|
|
|
|
2012-03-26 15:58:59 +04:00
|
|
|
|
// Keep others in (case-insensitive) order:
|
2017-02-21 13:34:52 +03:00
|
|
|
|
#include "AutoReferenceChainGuard.h"
|
2013-10-29 12:14:40 +04:00
|
|
|
|
#include "gfx2DGlue.h"
|
2012-03-26 15:58:59 +04:00
|
|
|
|
#include "gfxContext.h"
|
|
|
|
|
#include "gfxMatrix.h"
|
|
|
|
|
#include "gfxPattern.h"
|
|
|
|
|
#include "gfxPlatform.h"
|
2019-04-16 10:24:49 +03:00
|
|
|
|
#include "mozilla/ComputedStyle.h"
|
|
|
|
|
#include "mozilla/PresShell.h"
|
|
|
|
|
#include "mozilla/dom/SVGPatternElement.h"
|
|
|
|
|
#include "mozilla/dom/SVGUnitTypesBinding.h"
|
2013-10-29 12:14:40 +04:00
|
|
|
|
#include "mozilla/gfx/2D.h"
|
2007-01-30 03:06:41 +03:00
|
|
|
|
#include "nsGkAtoms.h"
|
2017-02-09 21:24:31 +03:00
|
|
|
|
#include "nsSVGDisplayableFrame.h"
|
2017-08-30 16:14:46 +03:00
|
|
|
|
#include "SVGObserverUtils.h"
|
2016-12-18 14:11:47 +03:00
|
|
|
|
#include "SVGGeometryFrame.h"
|
2012-03-26 15:58:59 +04:00
|
|
|
|
#include "nsSVGUtils.h"
|
2018-12-27 02:46:38 +03:00
|
|
|
|
#include "SVGAnimatedTransformList.h"
|
2012-09-22 23:26:05 +04:00
|
|
|
|
#include "SVGContentUtils.h"
|
2005-09-14 02:38:36 +04:00
|
|
|
|
|
2010-12-20 03:45:29 +03:00
|
|
|
|
using namespace mozilla;
|
2013-01-10 03:02:45 +04:00
|
|
|
|
using namespace mozilla::dom;
|
2018-06-26 00:20:54 +03:00
|
|
|
|
using namespace mozilla::dom::SVGUnitTypes_Binding;
|
2013-10-29 12:14:40 +04:00
|
|
|
|
using namespace mozilla::gfx;
|
2017-03-08 07:07:00 +03:00
|
|
|
|
using namespace mozilla::image;
|
2005-09-14 02:38:36 +04:00
|
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------
|
|
|
|
|
// Implementation
|
|
|
|
|
|
2019-05-01 11:47:10 +03:00
|
|
|
|
nsSVGPatternFrame::nsSVGPatternFrame(ComputedStyle* aStyle,
|
|
|
|
|
nsPresContext* aPresContext)
|
2019-02-05 19:45:54 +03:00
|
|
|
|
: nsSVGPaintServerFrame(aStyle, aPresContext, kClassID),
|
2017-05-03 18:41:08 +03:00
|
|
|
|
mSource(nullptr),
|
2016-04-18 10:40:29 +03:00
|
|
|
|
mLoopFlag(false),
|
|
|
|
|
mNoHRefURI(false) {}
|
2006-09-08 17:54:05 +04:00
|
|
|
|
|
2009-09-12 20:49:24 +04:00
|
|
|
|
NS_IMPL_FRAMEARENA_HELPERS(nsSVGPatternFrame)
|
|
|
|
|
|
2005-09-14 02:38:36 +04:00
|
|
|
|
//----------------------------------------------------------------------
|
|
|
|
|
// nsIFrame methods:
|
|
|
|
|
|
2012-08-22 19:56:38 +04:00
|
|
|
|
nsresult nsSVGPatternFrame::AttributeChanged(int32_t aNameSpaceID,
|
2019-05-01 11:47:10 +03:00
|
|
|
|
nsAtom* aAttribute,
|
2012-08-22 19:56:38 +04:00
|
|
|
|
int32_t aModType) {
|
2006-03-22 04:40:00 +03:00
|
|
|
|
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)) {
|
2017-08-30 17:58:31 +03:00
|
|
|
|
SVGObserverUtils::InvalidateDirectRenderingObservers(this);
|
2008-10-01 04:51:05 +04:00
|
|
|
|
}
|
2006-03-22 04:40:00 +03:00
|
|
|
|
|
2016-07-06 12:00:41 +03:00
|
|
|
|
if ((aNameSpaceID == kNameSpaceID_XLink ||
|
|
|
|
|
aNameSpaceID == kNameSpaceID_None) &&
|
2006-03-22 04:40:00 +03:00
|
|
|
|
aAttribute == nsGkAtoms::href) {
|
2008-10-01 04:51:05 +04:00
|
|
|
|
// Blow away our reference, if any
|
2018-08-21 16:54:26 +03:00
|
|
|
|
SVGObserverUtils::RemoveTemplateObserver(this);
|
2011-10-17 18:59:28 +04:00
|
|
|
|
mNoHRefURI = false;
|
2008-10-01 04:51:05 +04:00
|
|
|
|
// And update whoever references us
|
2017-08-30 17:58:31 +03:00
|
|
|
|
SVGObserverUtils::InvalidateDirectRenderingObservers(this);
|
2006-03-22 04:40:00 +03:00
|
|
|
|
}
|
|
|
|
|
|
2016-04-18 10:40:29 +03:00
|
|
|
|
return nsSVGPaintServerFrame::AttributeChanged(aNameSpaceID, aAttribute,
|
2006-03-22 04:40:00 +03:00
|
|
|
|
aModType);
|
|
|
|
|
}
|
|
|
|
|
|
2009-01-19 21:31:34 +03:00
|
|
|
|
#ifdef DEBUG
|
2019-05-01 11:47:10 +03:00
|
|
|
|
void nsSVGPatternFrame::Init(nsIContent* aContent, nsContainerFrame* aParent,
|
|
|
|
|
nsIFrame* aPrevInFlow) {
|
2015-03-03 14:08:59 +03:00
|
|
|
|
NS_ASSERTION(aContent->IsSVGElement(nsGkAtoms::pattern),
|
|
|
|
|
"Content is not an SVG pattern");
|
2009-01-19 21:31:34 +03:00
|
|
|
|
|
2016-04-18 10:40:29 +03:00
|
|
|
|
nsSVGPaintServerFrame::Init(aContent, aParent, aPrevInFlow);
|
2009-01-19 21:31:34 +03:00
|
|
|
|
}
|
|
|
|
|
#endif /* DEBUG */
|
|
|
|
|
|
2005-09-14 02:38:36 +04:00
|
|
|
|
//----------------------------------------------------------------------
|
2006-06-01 19:31:15 +04:00
|
|
|
|
// nsSVGContainerFrame methods:
|
2005-09-14 02:38:36 +04: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
|
2014-09-08 15:28:50 +04:00
|
|
|
|
gfxMatrix nsSVGPatternFrame::GetCanvasTM() {
|
2005-09-14 02:38:36 +04:00
|
|
|
|
if (mCTM) {
|
2011-09-26 01:04:32 +04:00
|
|
|
|
return *mCTM;
|
2005-09-14 02:38:36 +04:00
|
|
|
|
}
|
2009-04-29 08:31:34 +04:00
|
|
|
|
|
|
|
|
|
// Do we know our rendering parent?
|
|
|
|
|
if (mSource) {
|
|
|
|
|
// Yes, use it!
|
2014-09-08 15:28:50 +04:00
|
|
|
|
return mSource->GetCanvasTM();
|
2009-04-29 08:31:34 +04:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// We get here when geometry in the <pattern> container is updated
|
|
|
|
|
return gfxMatrix();
|
2005-09-14 02:38:36 +04:00
|
|
|
|
}
|
|
|
|
|
|
2012-07-31 14:17:11 +04:00
|
|
|
|
// -------------------------------------------------------------------------
|
|
|
|
|
// Helper functions
|
|
|
|
|
// -------------------------------------------------------------------------
|
|
|
|
|
|
2013-10-29 12:14:40 +04:00
|
|
|
|
/** Calculate the maximum expansion of a matrix */
|
2019-05-01 11:47:10 +03:00
|
|
|
|
static float MaxExpansion(const Matrix& aMatrix) {
|
2013-10-29 12:14:40 +04:00
|
|
|
|
// maximum expansion derivation from
|
|
|
|
|
// http://lists.cairographics.org/archives/cairo/2004-October/001980.html
|
|
|
|
|
// and also implemented in cairo_matrix_transformed_circle_major_axis
|
|
|
|
|
double a = aMatrix._11;
|
|
|
|
|
double b = aMatrix._12;
|
|
|
|
|
double c = aMatrix._21;
|
|
|
|
|
double d = aMatrix._22;
|
|
|
|
|
double f = (a * a + b * b + c * c + d * d) / 2;
|
|
|
|
|
double g = (a * a + b * b - c * c - d * d) / 2;
|
|
|
|
|
double h = a * c + b * d;
|
|
|
|
|
return sqrt(f + sqrt(g * g + h * h));
|
|
|
|
|
}
|
|
|
|
|
|
2012-07-31 14:17:11 +04:00
|
|
|
|
// The SVG specification says that the 'patternContentUnits' attribute "has no
|
2012-08-01 22:30:00 +04:00
|
|
|
|
// effect if attribute ‘viewBox’ is specified". We still need to include a bbox
|
2012-07-31 14:17:11 +04:00
|
|
|
|
// scale if the viewBox is specified and _patternUnits_ is set to or defaults to
|
|
|
|
|
// objectBoundingBox though, since in that case the viewBox is relative to the
|
|
|
|
|
// bbox
|
2019-05-01 11:47:10 +03:00
|
|
|
|
static bool IncludeBBoxScale(const SVGAnimatedViewBox& aViewBox,
|
2012-08-22 19:56:38 +04:00
|
|
|
|
uint32_t aPatternContentUnits,
|
|
|
|
|
uint32_t aPatternUnits) {
|
2012-07-31 14:17:11 +04:00
|
|
|
|
return (!aViewBox.IsExplicitlySet() &&
|
2013-02-18 06:14:02 +04:00
|
|
|
|
aPatternContentUnits == SVG_UNIT_TYPE_OBJECTBOUNDINGBOX) ||
|
2012-07-31 14:17:11 +04:00
|
|
|
|
(aViewBox.IsExplicitlySet() &&
|
2013-02-18 06:14:02 +04:00
|
|
|
|
aPatternUnits == SVG_UNIT_TYPE_OBJECTBOUNDINGBOX);
|
2012-07-31 14:17:11 +04:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Given the matrix for the pattern element's own transform, this returns a
|
|
|
|
|
// combined matrix including the transforms applicable to its target.
|
2012-08-22 19:56:38 +04:00
|
|
|
|
static Matrix GetPatternMatrix(uint16_t aPatternUnits,
|
2019-05-01 11:47:10 +03:00
|
|
|
|
const Matrix& patternTransform,
|
|
|
|
|
const gfxRect& bbox, const gfxRect& callerBBox,
|
|
|
|
|
const Matrix& callerCTM) {
|
2012-07-31 14:17:11 +04:00
|
|
|
|
// We really want the pattern matrix to handle translations
|
|
|
|
|
gfxFloat minx = bbox.X();
|
|
|
|
|
gfxFloat miny = bbox.Y();
|
|
|
|
|
|
2013-02-18 06:14:02 +04:00
|
|
|
|
if (aPatternUnits == SVG_UNIT_TYPE_OBJECTBOUNDINGBOX) {
|
2012-07-31 14:17:11 +04:00
|
|
|
|
minx += callerBBox.X();
|
|
|
|
|
miny += callerBBox.Y();
|
|
|
|
|
}
|
|
|
|
|
|
2013-10-29 12:14:40 +04:00
|
|
|
|
float scale = 1.0f / MaxExpansion(callerCTM);
|
2014-06-18 04:07:21 +04:00
|
|
|
|
Matrix patternMatrix = patternTransform;
|
2014-09-10 21:29:35 +04:00
|
|
|
|
patternMatrix.PreScale(scale, scale);
|
|
|
|
|
patternMatrix.PreTranslate(minx, miny);
|
2012-07-31 14:17:11 +04:00
|
|
|
|
|
|
|
|
|
return patternMatrix;
|
|
|
|
|
}
|
|
|
|
|
|
2019-05-01 11:47:10 +03:00
|
|
|
|
static nsresult GetTargetGeometry(gfxRect* aBBox,
|
|
|
|
|
const SVGAnimatedViewBox& aViewBox,
|
2012-08-22 19:56:38 +04:00
|
|
|
|
uint16_t aPatternContentUnits,
|
2019-05-01 11:47:10 +03:00
|
|
|
|
uint16_t aPatternUnits, nsIFrame* aTarget,
|
|
|
|
|
const Matrix& aContextMatrix,
|
|
|
|
|
const gfxRect* aOverrideBounds) {
|
2017-03-14 08:26:05 +03:00
|
|
|
|
*aBBox = aOverrideBounds
|
|
|
|
|
? *aOverrideBounds
|
|
|
|
|
: nsSVGUtils::GetBBox(aTarget,
|
|
|
|
|
nsSVGUtils::eUseFrameBoundsForOuterSVG |
|
|
|
|
|
nsSVGUtils::eBBoxIncludeFillGeometry);
|
2012-07-31 14:17:11 +04:00
|
|
|
|
|
|
|
|
|
// Sanity check
|
|
|
|
|
if (IncludeBBoxScale(aViewBox, aPatternContentUnits, aPatternUnits) &&
|
|
|
|
|
(aBBox->Width() <= 0 || aBBox->Height() <= 0)) {
|
|
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// OK, now fix up the bounding box to reflect user coordinates
|
|
|
|
|
// We handle device unit scaling in pattern matrix
|
2013-10-29 12:14:40 +04:00
|
|
|
|
float scale = MaxExpansion(aContextMatrix);
|
2012-07-31 14:17:11 +04:00
|
|
|
|
if (scale <= 0) {
|
|
|
|
|
return NS_ERROR_FAILURE;
|
|
|
|
|
}
|
|
|
|
|
aBBox->Scale(scale);
|
|
|
|
|
return NS_OK;
|
|
|
|
|
}
|
|
|
|
|
|
2017-05-18 23:03:50 +03:00
|
|
|
|
already_AddRefed<SourceSurface> nsSVGPatternFrame::PaintPattern(
|
2019-05-01 11:47:10 +03:00
|
|
|
|
const DrawTarget* aDrawTarget, Matrix* patternMatrix,
|
|
|
|
|
const Matrix& aContextMatrix, nsIFrame* aSource,
|
2019-07-06 11:31:02 +03:00
|
|
|
|
mozilla::StyleSVGPaint nsStyleSVG::*aFillOrStroke, float aGraphicOpacity,
|
2019-05-01 11:47:10 +03:00
|
|
|
|
const gfxRect* aOverrideBounds, imgDrawingParams& aImgParams) {
|
2005-09-14 02:38:36 +04:00
|
|
|
|
/*
|
|
|
|
|
* General approach:
|
|
|
|
|
* Set the content geometry stuff
|
2008-10-01 04:51:05 +04:00
|
|
|
|
* Calculate our bbox (using x,y,width,height & patternUnits &
|
2005-09-14 02:38:36 +04:00
|
|
|
|
* 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
|
|
|
|
|
*/
|
|
|
|
|
|
2019-05-01 11:47:10 +03:00
|
|
|
|
nsSVGPatternFrame* patternWithChildren = GetPatternWithChildren();
|
2014-09-30 21:08:14 +04:00
|
|
|
|
if (!patternWithChildren) {
|
2017-03-21 05:12:23 +03:00
|
|
|
|
// Either no kids or a bad reference
|
2017-05-18 23:03:50 +03:00
|
|
|
|
return nullptr;
|
2014-06-18 04:07:21 +04:00
|
|
|
|
}
|
2019-05-01 11:47:10 +03:00
|
|
|
|
nsIFrame* firstKid = patternWithChildren->mFrames.FirstChild();
|
2005-09-14 02:38:36 +04:00
|
|
|
|
|
2019-05-01 11:47:10 +03:00
|
|
|
|
const SVGAnimatedViewBox& viewBox = GetViewBox();
|
2012-07-31 14:17:11 +04:00
|
|
|
|
|
2012-08-22 19:56:38 +04:00
|
|
|
|
uint16_t patternContentUnits =
|
2013-01-17 00:51:00 +04:00
|
|
|
|
GetEnumValue(SVGPatternElement::PATTERNCONTENTUNITS);
|
|
|
|
|
uint16_t patternUnits = GetEnumValue(SVGPatternElement::PATTERNUNITS);
|
2012-07-31 14:17:11 +04:00
|
|
|
|
|
2005-09-14 02:38:36 +04:00
|
|
|
|
/*
|
|
|
|
|
* 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-05 00:40:27 +04: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-14 02:38:36 +04:00
|
|
|
|
*/
|
|
|
|
|
|
2006-04-05 00:40:27 +04:00
|
|
|
|
// Get all of the information we need from our "caller" -- i.e.
|
|
|
|
|
// the geometry that is being rendered with a pattern
|
2009-06-11 19:21:03 +04:00
|
|
|
|
gfxRect callerBBox;
|
2012-07-14 03:18:38 +04:00
|
|
|
|
if (NS_FAILED(GetTargetGeometry(&callerBBox, viewBox, patternContentUnits,
|
2012-07-31 14:17:11 +04:00
|
|
|
|
patternUnits, aSource, aContextMatrix,
|
2014-06-18 04:07:21 +04:00
|
|
|
|
aOverrideBounds))) {
|
2017-05-18 23:03:50 +03:00
|
|
|
|
return nullptr;
|
2014-06-18 04:07:21 +04:00
|
|
|
|
}
|
2005-09-14 02:38:36 +04:00
|
|
|
|
|
2006-04-05 00:40:27 +04:00
|
|
|
|
// Construct the CTM that we will provide to our children when we
|
|
|
|
|
// render them into the tile.
|
2012-07-31 14:17:11 +04:00
|
|
|
|
gfxMatrix ctm = ConstructCTM(viewBox, patternContentUnits, patternUnits,
|
2014-06-18 04:07:21 +04:00
|
|
|
|
callerBBox, aContextMatrix, aSource);
|
2009-07-23 12:35:59 +04:00
|
|
|
|
if (ctm.IsSingular()) {
|
2017-05-18 23:03:50 +03:00
|
|
|
|
return nullptr;
|
2009-07-23 12:35:59 +04:00
|
|
|
|
}
|
2009-10-26 22:37:31 +03:00
|
|
|
|
|
2014-09-30 21:08:14 +04:00
|
|
|
|
if (patternWithChildren->mCTM) {
|
|
|
|
|
*patternWithChildren->mCTM = ctm;
|
2011-09-26 01:04:32 +04:00
|
|
|
|
} else {
|
2014-09-30 21:08:14 +04:00
|
|
|
|
patternWithChildren->mCTM = new gfxMatrix(ctm);
|
2011-09-26 01:04:32 +04:00
|
|
|
|
}
|
2005-09-14 02:38:36 +04:00
|
|
|
|
|
2006-04-05 00:40:27 +04: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.
|
2014-06-18 04:07:21 +04:00
|
|
|
|
gfxRect bbox =
|
|
|
|
|
GetPatternRect(patternUnits, callerBBox, aContextMatrix, aSource);
|
2014-02-21 00:49:14 +04:00
|
|
|
|
if (bbox.Width() <= 0.0 || bbox.Height() <= 0.0) {
|
2017-05-18 23:03:50 +03:00
|
|
|
|
return nullptr;
|
2014-02-21 00:49:14 +04:00
|
|
|
|
}
|
2006-04-05 00:40:27 +04:00
|
|
|
|
|
2011-10-27 12:51:46 +04:00
|
|
|
|
// Get the pattern transform
|
2014-06-18 04:07:21 +04:00
|
|
|
|
Matrix patternTransform = ToMatrix(GetPatternTransform());
|
2011-10-27 12:51:46 +04:00
|
|
|
|
|
2012-05-18 12:34:25 +04:00
|
|
|
|
// revert the vector effect transform so that the pattern appears unchanged
|
|
|
|
|
if (aFillOrStroke == &nsStyleSVG::mStroke) {
|
2014-09-30 21:08:14 +04:00
|
|
|
|
gfxMatrix userToOuterSVG;
|
|
|
|
|
if (nsSVGUtils::GetNonScalingStrokeTransform(aSource, &userToOuterSVG)) {
|
|
|
|
|
patternTransform *= ToMatrix(userToOuterSVG);
|
|
|
|
|
if (patternTransform.IsSingular()) {
|
|
|
|
|
NS_WARNING("Singular matrix painting non-scaling-stroke");
|
2017-05-18 23:03:50 +03:00
|
|
|
|
return nullptr;
|
2014-09-30 21:08:14 +04:00
|
|
|
|
}
|
2014-06-18 04:07:21 +04:00
|
|
|
|
}
|
2012-05-18 12:34:25 +04:00
|
|
|
|
}
|
|
|
|
|
|
2006-04-05 00:40:27 +04:00
|
|
|
|
// Get the transformation matrix that we will hand to the renderer's pattern
|
|
|
|
|
// routine.
|
2012-07-31 14:17:11 +04:00
|
|
|
|
*patternMatrix = GetPatternMatrix(patternUnits, patternTransform, bbox,
|
2014-06-18 04:07:21 +04:00
|
|
|
|
callerBBox, aContextMatrix);
|
2012-08-09 12:17:05 +04:00
|
|
|
|
if (patternMatrix->IsSingular()) {
|
2017-05-18 23:03:50 +03:00
|
|
|
|
return nullptr;
|
2012-08-09 12:17:05 +04:00
|
|
|
|
}
|
2006-04-05 00:40:27 +04:00
|
|
|
|
|
|
|
|
|
// Now that we have all of the necessary geometries, we can
|
2006-06-28 16:32:26 +04:00
|
|
|
|
// create our surface.
|
2014-06-18 04:07:21 +04:00
|
|
|
|
gfxRect transformedBBox =
|
|
|
|
|
ThebesRect(patternTransform.TransformBounds(ToRect(bbox)));
|
2007-06-13 13:02:48 +04:00
|
|
|
|
|
2011-09-29 10:19:26 +04:00
|
|
|
|
bool resultOverflows;
|
2011-10-04 19:22:46 +04:00
|
|
|
|
IntSize surfaceSize = nsSVGUtils::ConvertToSurfaceSize(transformedBBox.Size(),
|
2015-03-29 17:59:08 +03:00
|
|
|
|
&resultOverflows);
|
2007-06-13 13:02:48 +04:00
|
|
|
|
|
|
|
|
|
// 0 disables rendering, < 0 is an error
|
2014-06-18 04:07:21 +04:00
|
|
|
|
if (surfaceSize.width <= 0 || surfaceSize.height <= 0) {
|
2017-05-18 23:03:50 +03:00
|
|
|
|
return nullptr;
|
2014-06-18 04:07:21 +04:00
|
|
|
|
}
|
2007-06-13 13:02:48 +04:00
|
|
|
|
|
2012-08-09 12:17:05 +04:00
|
|
|
|
gfxFloat patternWidth = bbox.Width();
|
|
|
|
|
gfxFloat patternHeight = bbox.Height();
|
|
|
|
|
|
2009-12-23 14:30:44 +03:00
|
|
|
|
if (resultOverflows || patternWidth != surfaceSize.width ||
|
|
|
|
|
patternHeight != surfaceSize.height) {
|
|
|
|
|
// scale drawing to pattern surface size
|
2015-04-07 10:45:59 +03:00
|
|
|
|
gfxMatrix tempTM = gfxMatrix(surfaceSize.width / patternWidth, 0.0, 0.0,
|
|
|
|
|
surfaceSize.height / patternHeight, 0.0, 0.0);
|
2014-09-30 21:08:14 +04:00
|
|
|
|
patternWithChildren->mCTM->PreMultiply(tempTM);
|
2007-06-13 13:02:48 +04:00
|
|
|
|
|
2009-12-23 14:30:44 +03:00
|
|
|
|
// and rescale pattern to compensate
|
2014-09-10 21:29:35 +04:00
|
|
|
|
patternMatrix->PreScale(patternWidth / surfaceSize.width,
|
|
|
|
|
patternHeight / surfaceSize.height);
|
2007-06-13 13:02:48 +04:00
|
|
|
|
}
|
2005-09-14 02:38:36 +04:00
|
|
|
|
|
2014-09-29 17:15:19 +04:00
|
|
|
|
RefPtr<DrawTarget> dt = aDrawTarget->CreateSimilarDrawTarget(
|
|
|
|
|
surfaceSize, SurfaceFormat::B8G8R8A8);
|
2016-04-12 22:18:11 +03:00
|
|
|
|
if (!dt || !dt->IsValid()) {
|
2017-05-18 23:03:50 +03:00
|
|
|
|
return nullptr;
|
2014-06-18 04:07:21 +04:00
|
|
|
|
}
|
2014-11-20 13:40:04 +03:00
|
|
|
|
dt->ClearRect(Rect(0, 0, surfaceSize.width, surfaceSize.height));
|
2006-11-27 20:30:57 +03:00
|
|
|
|
|
2017-03-21 18:40:36 +03:00
|
|
|
|
RefPtr<gfxContext> ctx = gfxContext::CreateOrNull(dt);
|
|
|
|
|
MOZ_ASSERT(ctx); // already checked the draw target above
|
2005-09-14 02:38:36 +04:00
|
|
|
|
|
2007-04-24 12:11:22 +04:00
|
|
|
|
if (aGraphicOpacity != 1.0f) {
|
2017-03-21 18:40:36 +03:00
|
|
|
|
ctx->Save();
|
|
|
|
|
ctx->PushGroupForBlendBack(gfxContentType::COLOR_ALPHA, aGraphicOpacity);
|
2007-04-24 12:11:22 +04:00
|
|
|
|
}
|
|
|
|
|
|
2005-09-14 02:38:36 +04: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 21:15:03 +03:00
|
|
|
|
|
2010-07-01 20:40:30 +04:00
|
|
|
|
if (aSource->IsFrameOfType(nsIFrame::eSVGGeometry)) {
|
|
|
|
|
// Set the geometrical parent of the pattern we are rendering
|
2019-05-01 11:47:10 +03:00
|
|
|
|
patternWithChildren->mSource = static_cast<SVGGeometryFrame*>(aSource);
|
2010-07-01 20:40:30 +04:00
|
|
|
|
}
|
2006-02-09 21:15:03 +03:00
|
|
|
|
|
2010-08-13 17:32:15 +04:00
|
|
|
|
// Delay checking NS_FRAME_DRAWING_AS_PAINTSERVER bit until here so we can
|
|
|
|
|
// give back a clear surface if there's a loop
|
2014-09-30 21:08:14 +04:00
|
|
|
|
if (!(patternWithChildren->GetStateBits() &
|
|
|
|
|
NS_FRAME_DRAWING_AS_PAINTSERVER)) {
|
2017-03-24 21:07:26 +03:00
|
|
|
|
AutoSetRestorePaintServerState paintServer(patternWithChildren);
|
2019-05-01 11:47:10 +03:00
|
|
|
|
for (nsIFrame* kid = firstKid; kid; kid = kid->GetNextSibling()) {
|
2019-04-18 17:35:23 +03:00
|
|
|
|
gfxMatrix tm = *(patternWithChildren->mCTM);
|
|
|
|
|
|
2010-12-23 08:48:31 +03:00
|
|
|
|
// The CTM of each frame referencing us can be different
|
2019-05-01 11:47:10 +03:00
|
|
|
|
nsSVGDisplayableFrame* SVGFrame = do_QueryFrame(kid);
|
2010-12-23 08:48:31 +03:00
|
|
|
|
if (SVGFrame) {
|
2017-02-09 21:24:31 +03:00
|
|
|
|
SVGFrame->NotifySVGChanged(nsSVGDisplayableFrame::TRANSFORM_CHANGED);
|
2019-04-27 10:22:53 +03:00
|
|
|
|
tm = nsSVGUtils::GetTransformMatrixInUserSpace(kid) * tm;
|
2014-08-29 23:42:07 +04:00
|
|
|
|
}
|
2017-03-21 05:12:23 +03:00
|
|
|
|
|
2017-05-18 23:03:50 +03:00
|
|
|
|
nsSVGUtils::PaintFrameWithEffects(kid, *ctx, tm, aImgParams);
|
2008-10-01 04:51:05 +04:00
|
|
|
|
}
|
2005-09-14 02:38:36 +04:00
|
|
|
|
}
|
2008-10-01 04:51:05 +04:00
|
|
|
|
|
2014-09-30 21:08:14 +04:00
|
|
|
|
patternWithChildren->mSource = nullptr;
|
2005-09-14 02:38:36 +04:00
|
|
|
|
|
2007-04-24 12:11:22 +04:00
|
|
|
|
if (aGraphicOpacity != 1.0f) {
|
2017-03-21 18:40:36 +03:00
|
|
|
|
ctx->PopGroupAndBlend();
|
|
|
|
|
ctx->Restore();
|
2007-04-24 12:11:22 +04:00
|
|
|
|
}
|
|
|
|
|
|
2007-04-30 19:53:55 +04:00
|
|
|
|
// caller now owns the surface
|
2017-05-18 23:03:50 +03:00
|
|
|
|
return dt->Snapshot();
|
2005-09-14 02:38:36 +04:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* 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?
|
2019-05-01 11:47:10 +03:00
|
|
|
|
nsSVGPatternFrame* nsSVGPatternFrame::GetPatternWithChildren() {
|
2008-09-30 15:28:20 +04:00
|
|
|
|
// Do we have any children ourselves?
|
2018-12-12 09:32:44 +03:00
|
|
|
|
if (!mFrames.IsEmpty()) {
|
|
|
|
|
return this;
|
|
|
|
|
}
|
2008-10-01 04:51:05 +04:00
|
|
|
|
|
|
|
|
|
// No, see if we chain to someone who does
|
|
|
|
|
|
2017-02-21 13:34:52 +03:00
|
|
|
|
// Before we recurse, make sure we'll break reference loops and over long
|
|
|
|
|
// reference chains:
|
|
|
|
|
static int16_t sRefChainLengthCounter = AutoReferenceChainGuard::noChain;
|
|
|
|
|
AutoReferenceChainGuard refChainGuard(this, &mLoopFlag,
|
|
|
|
|
&sRefChainLengthCounter);
|
|
|
|
|
if (MOZ_UNLIKELY(!refChainGuard.Reference())) {
|
|
|
|
|
// Break reference chain
|
|
|
|
|
return nullptr;
|
|
|
|
|
}
|
|
|
|
|
|
2019-05-01 11:47:10 +03:00
|
|
|
|
nsSVGPatternFrame* next = GetReferencedPattern();
|
2018-12-12 09:32:44 +03:00
|
|
|
|
if (!next) {
|
|
|
|
|
return nullptr;
|
|
|
|
|
}
|
2008-10-01 04:51:05 +04:00
|
|
|
|
|
2014-09-30 21:08:14 +04:00
|
|
|
|
return next->GetPatternWithChildren();
|
2005-09-14 02:38:36 +04:00
|
|
|
|
}
|
|
|
|
|
|
2012-08-22 19:56:38 +04:00
|
|
|
|
uint16_t nsSVGPatternFrame::GetEnumValue(uint32_t aIndex,
|
2019-05-01 11:47:10 +03:00
|
|
|
|
nsIContent* aDefault) {
|
|
|
|
|
SVGAnimatedEnumeration& thisEnum =
|
|
|
|
|
static_cast<SVGPatternElement*>(GetContent())->mEnumAttributes[aIndex];
|
2011-01-16 10:36:34 +03:00
|
|
|
|
|
2018-12-12 09:32:44 +03:00
|
|
|
|
if (thisEnum.IsExplicitlySet()) {
|
|
|
|
|
return thisEnum.GetAnimValue();
|
|
|
|
|
}
|
2011-01-16 10:36:34 +03:00
|
|
|
|
|
2017-02-21 13:34:52 +03:00
|
|
|
|
// Before we recurse, make sure we'll break reference loops and over long
|
|
|
|
|
// reference chains:
|
|
|
|
|
static int16_t sRefChainLengthCounter = AutoReferenceChainGuard::noChain;
|
|
|
|
|
AutoReferenceChainGuard refChainGuard(this, &mLoopFlag,
|
|
|
|
|
&sRefChainLengthCounter);
|
|
|
|
|
if (MOZ_UNLIKELY(!refChainGuard.Reference())) {
|
|
|
|
|
// Break reference chain
|
2019-05-01 11:47:10 +03:00
|
|
|
|
return static_cast<SVGPatternElement*>(aDefault)
|
2017-02-21 13:34:52 +03:00
|
|
|
|
->mEnumAttributes[aIndex]
|
|
|
|
|
.GetAnimValue();
|
|
|
|
|
}
|
2011-01-16 10:36:34 +03:00
|
|
|
|
|
2019-05-01 11:47:10 +03:00
|
|
|
|
nsSVGPatternFrame* next = GetReferencedPattern();
|
2017-02-21 13:34:52 +03:00
|
|
|
|
return next ? next->GetEnumValue(aIndex, aDefault)
|
2019-05-01 11:47:10 +03:00
|
|
|
|
: static_cast<SVGPatternElement*>(aDefault)
|
2017-02-21 13:34:52 +03:00
|
|
|
|
->mEnumAttributes[aIndex]
|
|
|
|
|
.GetAnimValue();
|
2005-09-14 02:38:36 +04:00
|
|
|
|
}
|
|
|
|
|
|
2019-05-01 11:47:10 +03:00
|
|
|
|
SVGAnimatedTransformList* nsSVGPatternFrame::GetPatternTransformList(
|
|
|
|
|
nsIContent* aDefault) {
|
|
|
|
|
SVGAnimatedTransformList* thisTransformList =
|
|
|
|
|
static_cast<SVGPatternElement*>(GetContent())->GetAnimatedTransformList();
|
2011-09-26 01:04:32 +04:00
|
|
|
|
|
2012-07-30 04:35:26 +04:00
|
|
|
|
if (thisTransformList && thisTransformList->IsExplicitlySet())
|
2011-01-16 10:36:34 +03:00
|
|
|
|
return thisTransformList;
|
|
|
|
|
|
2017-02-21 13:34:52 +03:00
|
|
|
|
// Before we recurse, make sure we'll break reference loops and over long
|
|
|
|
|
// reference chains:
|
|
|
|
|
static int16_t sRefChainLengthCounter = AutoReferenceChainGuard::noChain;
|
|
|
|
|
AutoReferenceChainGuard refChainGuard(this, &mLoopFlag,
|
|
|
|
|
&sRefChainLengthCounter);
|
|
|
|
|
if (MOZ_UNLIKELY(!refChainGuard.Reference())) {
|
|
|
|
|
// Break reference chain
|
2019-05-01 11:47:10 +03:00
|
|
|
|
return static_cast<SVGPatternElement*>(aDefault)->mPatternTransform.get();
|
2017-02-21 13:34:52 +03:00
|
|
|
|
}
|
2011-01-16 10:36:34 +03:00
|
|
|
|
|
2019-05-01 11:47:10 +03:00
|
|
|
|
nsSVGPatternFrame* next = GetReferencedPattern();
|
2017-02-21 13:34:52 +03:00
|
|
|
|
return next ? next->GetPatternTransformList(aDefault)
|
2019-05-01 11:47:10 +03:00
|
|
|
|
: static_cast<SVGPatternElement*>(aDefault)
|
2017-02-21 13:34:52 +03:00
|
|
|
|
->mPatternTransform.get();
|
2005-09-14 02:38:36 +04:00
|
|
|
|
}
|
|
|
|
|
|
2007-04-30 19:53:55 +04:00
|
|
|
|
gfxMatrix nsSVGPatternFrame::GetPatternTransform() {
|
2019-05-01 11:47:10 +03:00
|
|
|
|
SVGAnimatedTransformList* animTransformList =
|
2017-08-27 01:58:38 +03:00
|
|
|
|
GetPatternTransformList(GetContent());
|
2018-12-12 09:32:44 +03:00
|
|
|
|
if (!animTransformList) {
|
|
|
|
|
return gfxMatrix();
|
|
|
|
|
}
|
2008-10-01 04:51:05 +04:00
|
|
|
|
|
2011-09-26 01:04:32 +04:00
|
|
|
|
return animTransformList->GetAnimValue().GetConsolidationMatrix();
|
2005-09-14 02:38:36 +04:00
|
|
|
|
}
|
|
|
|
|
|
2019-05-01 11:47:10 +03:00
|
|
|
|
const SVGAnimatedViewBox& nsSVGPatternFrame::GetViewBox(nsIContent* aDefault) {
|
|
|
|
|
const SVGAnimatedViewBox& thisViewBox =
|
|
|
|
|
static_cast<SVGPatternElement*>(GetContent())->mViewBox;
|
2008-10-01 04:51:05 +04:00
|
|
|
|
|
2018-12-12 09:32:44 +03:00
|
|
|
|
if (thisViewBox.IsExplicitlySet()) {
|
|
|
|
|
return thisViewBox;
|
|
|
|
|
}
|
2011-01-16 10:36:34 +03:00
|
|
|
|
|
2017-02-21 13:34:52 +03:00
|
|
|
|
// Before we recurse, make sure we'll break reference loops and over long
|
|
|
|
|
// reference chains:
|
|
|
|
|
static int16_t sRefChainLengthCounter = AutoReferenceChainGuard::noChain;
|
|
|
|
|
AutoReferenceChainGuard refChainGuard(this, &mLoopFlag,
|
|
|
|
|
&sRefChainLengthCounter);
|
|
|
|
|
if (MOZ_UNLIKELY(!refChainGuard.Reference())) {
|
|
|
|
|
// Break reference chain
|
2019-05-01 11:47:10 +03:00
|
|
|
|
return static_cast<SVGPatternElement*>(aDefault)->mViewBox;
|
2017-02-21 13:34:52 +03:00
|
|
|
|
}
|
2011-01-16 10:36:34 +03:00
|
|
|
|
|
2019-05-01 11:47:10 +03:00
|
|
|
|
nsSVGPatternFrame* next = GetReferencedPattern();
|
2017-02-21 13:34:52 +03:00
|
|
|
|
return next ? next->GetViewBox(aDefault)
|
2019-05-01 11:47:10 +03:00
|
|
|
|
: static_cast<SVGPatternElement*>(aDefault)->mViewBox;
|
2005-09-14 02:38:36 +04:00
|
|
|
|
}
|
|
|
|
|
|
2019-05-01 11:47:10 +03:00
|
|
|
|
const SVGAnimatedPreserveAspectRatio& nsSVGPatternFrame::GetPreserveAspectRatio(
|
|
|
|
|
nsIContent* aDefault) {
|
|
|
|
|
const SVGAnimatedPreserveAspectRatio& thisPar =
|
|
|
|
|
static_cast<SVGPatternElement*>(GetContent())->mPreserveAspectRatio;
|
2008-10-01 04:51:05 +04:00
|
|
|
|
|
2018-12-12 09:32:44 +03:00
|
|
|
|
if (thisPar.IsExplicitlySet()) {
|
|
|
|
|
return thisPar;
|
|
|
|
|
}
|
2005-09-14 02:38:36 +04:00
|
|
|
|
|
2017-02-21 13:34:52 +03:00
|
|
|
|
// Before we recurse, make sure we'll break reference loops and over long
|
|
|
|
|
// reference chains:
|
|
|
|
|
static int16_t sRefChainLengthCounter = AutoReferenceChainGuard::noChain;
|
|
|
|
|
AutoReferenceChainGuard refChainGuard(this, &mLoopFlag,
|
|
|
|
|
&sRefChainLengthCounter);
|
|
|
|
|
if (MOZ_UNLIKELY(!refChainGuard.Reference())) {
|
|
|
|
|
// Break reference chain
|
2019-05-01 11:47:10 +03:00
|
|
|
|
return static_cast<SVGPatternElement*>(aDefault)->mPreserveAspectRatio;
|
2017-02-21 13:34:52 +03:00
|
|
|
|
}
|
2005-09-14 02:38:36 +04:00
|
|
|
|
|
2019-05-01 11:47:10 +03:00
|
|
|
|
nsSVGPatternFrame* next = GetReferencedPattern();
|
|
|
|
|
return next ? next->GetPreserveAspectRatio(aDefault)
|
|
|
|
|
: static_cast<SVGPatternElement*>(aDefault)->mPreserveAspectRatio;
|
2005-09-14 02:38:36 +04:00
|
|
|
|
}
|
|
|
|
|
|
2019-05-01 11:47:10 +03:00
|
|
|
|
const SVGAnimatedLength* nsSVGPatternFrame::GetLengthValue(
|
|
|
|
|
uint32_t aIndex, nsIContent* aDefault) {
|
|
|
|
|
const SVGAnimatedLength* thisLength =
|
|
|
|
|
&static_cast<SVGPatternElement*>(GetContent())->mLengthAttributes[aIndex];
|
2005-09-14 02:38:36 +04:00
|
|
|
|
|
2018-12-12 09:32:44 +03:00
|
|
|
|
if (thisLength->IsExplicitlySet()) {
|
|
|
|
|
return thisLength;
|
|
|
|
|
}
|
2011-01-16 10:36:34 +03:00
|
|
|
|
|
2017-02-21 13:34:52 +03:00
|
|
|
|
// Before we recurse, make sure we'll break reference loops and over long
|
|
|
|
|
// reference chains:
|
|
|
|
|
static int16_t sRefChainLengthCounter = AutoReferenceChainGuard::noChain;
|
|
|
|
|
AutoReferenceChainGuard refChainGuard(this, &mLoopFlag,
|
|
|
|
|
&sRefChainLengthCounter);
|
|
|
|
|
if (MOZ_UNLIKELY(!refChainGuard.Reference())) {
|
|
|
|
|
// Break reference chain
|
2019-05-01 11:47:10 +03:00
|
|
|
|
return &static_cast<SVGPatternElement*>(aDefault)
|
2017-02-21 13:34:52 +03:00
|
|
|
|
->mLengthAttributes[aIndex];
|
|
|
|
|
}
|
2011-01-16 10:36:34 +03:00
|
|
|
|
|
2019-05-01 11:47:10 +03:00
|
|
|
|
nsSVGPatternFrame* next = GetReferencedPattern();
|
2017-02-21 13:34:52 +03:00
|
|
|
|
return next ? next->GetLengthValue(aIndex, aDefault)
|
2019-05-01 11:47:10 +03:00
|
|
|
|
: &static_cast<SVGPatternElement*>(aDefault)
|
2017-02-21 13:34:52 +03:00
|
|
|
|
->mLengthAttributes[aIndex];
|
2005-09-14 02:38:36 +04:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Private (helper) methods
|
2018-08-21 16:54:26 +03:00
|
|
|
|
|
2019-05-01 11:47:10 +03:00
|
|
|
|
nsSVGPatternFrame* nsSVGPatternFrame::GetReferencedPattern() {
|
2018-08-21 16:54:26 +03:00
|
|
|
|
if (mNoHRefURI) {
|
2012-07-30 18:20:58 +04:00
|
|
|
|
return nullptr;
|
2018-08-21 16:54:26 +03:00
|
|
|
|
}
|
2008-09-30 15:28:20 +04:00
|
|
|
|
|
2019-05-01 11:47:10 +03:00
|
|
|
|
auto GetHref = [this](nsAString& aHref) {
|
|
|
|
|
SVGPatternElement* pattern =
|
|
|
|
|
static_cast<SVGPatternElement*>(this->GetContent());
|
2016-07-06 12:00:41 +03:00
|
|
|
|
if (pattern->mStringAttributes[SVGPatternElement::HREF].IsExplicitlySet()) {
|
|
|
|
|
pattern->mStringAttributes[SVGPatternElement::HREF].GetAnimValue(aHref,
|
2018-08-21 16:54:26 +03:00
|
|
|
|
pattern);
|
2016-07-06 12:00:41 +03:00
|
|
|
|
} else {
|
|
|
|
|
pattern->mStringAttributes[SVGPatternElement::XLINK_HREF].GetAnimValue(
|
2018-08-21 16:54:26 +03:00
|
|
|
|
aHref, pattern);
|
2016-07-06 12:00:41 +03:00
|
|
|
|
}
|
2018-08-21 16:54:26 +03:00
|
|
|
|
this->mNoHRefURI = aHref.IsEmpty();
|
|
|
|
|
};
|
|
|
|
|
|
2019-05-01 11:47:10 +03:00
|
|
|
|
nsIFrame* tframe = SVGObserverUtils::GetAndObserveTemplate(this, GetHref);
|
2018-08-21 16:54:26 +03:00
|
|
|
|
if (tframe) {
|
|
|
|
|
LayoutFrameType frameType = tframe->Type();
|
|
|
|
|
if (frameType == LayoutFrameType::SVGPattern) {
|
2019-05-01 11:47:10 +03:00
|
|
|
|
return static_cast<nsSVGPatternFrame*>(tframe);
|
2018-08-17 18:57:30 +03:00
|
|
|
|
}
|
2018-08-21 16:54:26 +03:00
|
|
|
|
// We don't call SVGObserverUtils::RemoveTemplateObserver and set
|
|
|
|
|
// `mNoHRefURI = false` here since we want to be invalidated if the ID
|
|
|
|
|
// specified by our href starts resolving to a different/valid element.
|
2008-09-30 15:28:20 +04:00
|
|
|
|
}
|
2008-10-01 04:51:05 +04:00
|
|
|
|
|
2018-08-21 16:54:26 +03:00
|
|
|
|
return nullptr;
|
2008-10-01 04:51:05 +04:00
|
|
|
|
}
|
|
|
|
|
|
2012-08-22 19:56:38 +04:00
|
|
|
|
gfxRect nsSVGPatternFrame::GetPatternRect(uint16_t aPatternUnits,
|
2019-05-01 11:47:10 +03:00
|
|
|
|
const gfxRect& aTargetBBox,
|
|
|
|
|
const Matrix& aTargetCTM,
|
|
|
|
|
nsIFrame* aTarget) {
|
2005-09-14 02:38:36 +04:00
|
|
|
|
// We need to initialize our box
|
2006-03-22 04:40:00 +03:00
|
|
|
|
float x, y, width, height;
|
|
|
|
|
|
|
|
|
|
// Get the pattern x,y,width, and height
|
2019-04-09 23:04:33 +03:00
|
|
|
|
const SVGAnimatedLength *tmpX, *tmpY, *tmpHeight, *tmpWidth;
|
2013-01-17 00:51:00 +04:00
|
|
|
|
tmpX = GetLengthValue(SVGPatternElement::ATTR_X);
|
|
|
|
|
tmpY = GetLengthValue(SVGPatternElement::ATTR_Y);
|
|
|
|
|
tmpHeight = GetLengthValue(SVGPatternElement::ATTR_HEIGHT);
|
|
|
|
|
tmpWidth = GetLengthValue(SVGPatternElement::ATTR_WIDTH);
|
2006-03-22 04:40:00 +03:00
|
|
|
|
|
2013-02-18 06:14:02 +04:00
|
|
|
|
if (aPatternUnits == SVG_UNIT_TYPE_OBJECTBOUNDINGBOX) {
|
2009-06-11 19:21:03 +04:00
|
|
|
|
x = nsSVGUtils::ObjectSpace(aTargetBBox, tmpX);
|
|
|
|
|
y = nsSVGUtils::ObjectSpace(aTargetBBox, tmpY);
|
|
|
|
|
width = nsSVGUtils::ObjectSpace(aTargetBBox, tmpWidth);
|
|
|
|
|
height = nsSVGUtils::ObjectSpace(aTargetBBox, tmpHeight);
|
2005-09-14 02:38:36 +04:00
|
|
|
|
} else {
|
2013-10-29 12:14:40 +04:00
|
|
|
|
float scale = MaxExpansion(aTargetCTM);
|
2009-06-11 19:21:03 +04:00
|
|
|
|
x = nsSVGUtils::UserSpace(aTarget, tmpX) * scale;
|
|
|
|
|
y = nsSVGUtils::UserSpace(aTarget, tmpY) * scale;
|
|
|
|
|
width = nsSVGUtils::UserSpace(aTarget, tmpWidth) * scale;
|
|
|
|
|
height = nsSVGUtils::UserSpace(aTarget, tmpHeight) * scale;
|
2005-09-14 02:38:36 +04:00
|
|
|
|
}
|
|
|
|
|
|
2009-06-11 19:21:03 +04:00
|
|
|
|
return gfxRect(x, y, width, height);
|
2005-09-14 02:38:36 +04:00
|
|
|
|
}
|
|
|
|
|
|
2019-05-01 11:47:10 +03:00
|
|
|
|
gfxMatrix nsSVGPatternFrame::ConstructCTM(const SVGAnimatedViewBox& aViewBox,
|
2012-08-22 19:56:38 +04:00
|
|
|
|
uint16_t aPatternContentUnits,
|
|
|
|
|
uint16_t aPatternUnits,
|
2019-05-01 11:47:10 +03:00
|
|
|
|
const gfxRect& callerBBox,
|
|
|
|
|
const Matrix& callerCTM,
|
|
|
|
|
nsIFrame* aTarget) {
|
|
|
|
|
SVGViewportElement* ctx = nullptr;
|
|
|
|
|
nsIContent* targetContent = aTarget->GetContent();
|
2015-04-07 10:45:59 +03:00
|
|
|
|
gfxFloat scaleX, scaleY;
|
2006-04-05 00:40:27 +04:00
|
|
|
|
|
2009-07-23 12:35:59 +04:00
|
|
|
|
// The objectBoundingBox conversion must be handled in the CTM:
|
2012-07-31 14:17:11 +04:00
|
|
|
|
if (IncludeBBoxScale(aViewBox, aPatternContentUnits, aPatternUnits)) {
|
2015-04-07 10:45:59 +03:00
|
|
|
|
scaleX = callerBBox.Width();
|
|
|
|
|
scaleY = callerBBox.Height();
|
2006-04-05 00:40:27 +04:00
|
|
|
|
} else {
|
2015-03-03 14:08:59 +03:00
|
|
|
|
if (targetContent->IsSVGElement()) {
|
2019-05-01 11:47:10 +03:00
|
|
|
|
ctx = static_cast<SVGElement*>(targetContent)->GetCtx();
|
2010-10-19 02:08:52 +04:00
|
|
|
|
}
|
2015-04-07 10:45:59 +03:00
|
|
|
|
scaleX = scaleY = MaxExpansion(callerCTM);
|
2006-04-05 00:40:27 +04:00
|
|
|
|
}
|
|
|
|
|
|
2012-07-31 14:17:11 +04:00
|
|
|
|
if (!aViewBox.IsExplicitlySet()) {
|
2015-04-07 10:45:59 +03:00
|
|
|
|
return gfxMatrix(scaleX, 0.0, 0.0, scaleY, 0.0, 0.0);
|
2012-03-31 14:47:18 +04:00
|
|
|
|
}
|
2019-05-01 11:47:10 +03:00
|
|
|
|
const SVGViewBox& viewBox = aViewBox.GetAnimValue();
|
2012-03-31 14:47:18 +04:00
|
|
|
|
|
2019-04-10 07:08:14 +03:00
|
|
|
|
if (viewBox.height <= 0.0f || viewBox.width <= 0.0f) {
|
2012-03-31 14:47:18 +04:00
|
|
|
|
return gfxMatrix(0.0, 0.0, 0.0, 0.0, 0.0, 0.0); // singular
|
|
|
|
|
}
|
2009-12-29 12:56:25 +03:00
|
|
|
|
|
2011-04-10 00:57:51 +04:00
|
|
|
|
float viewportWidth, viewportHeight;
|
2015-03-03 14:08:59 +03:00
|
|
|
|
if (targetContent->IsSVGElement()) {
|
2011-04-10 00:57:51 +04:00
|
|
|
|
// If we're dealing with an SVG target only retrieve the context once.
|
|
|
|
|
// Calling the nsIFrame* variant of GetAnimValue would look it up on
|
|
|
|
|
// every call.
|
|
|
|
|
viewportWidth =
|
2013-01-17 00:51:00 +04:00
|
|
|
|
GetLengthValue(SVGPatternElement::ATTR_WIDTH)->GetAnimValue(ctx);
|
2011-04-10 00:57:51 +04:00
|
|
|
|
viewportHeight =
|
2013-01-17 00:51:00 +04:00
|
|
|
|
GetLengthValue(SVGPatternElement::ATTR_HEIGHT)->GetAnimValue(ctx);
|
2011-04-10 00:57:51 +04:00
|
|
|
|
} else {
|
|
|
|
|
// No SVG target, call the nsIFrame* variant of GetAnimValue.
|
|
|
|
|
viewportWidth =
|
2013-01-17 00:51:00 +04:00
|
|
|
|
GetLengthValue(SVGPatternElement::ATTR_WIDTH)->GetAnimValue(aTarget);
|
2011-04-10 00:57:51 +04:00
|
|
|
|
viewportHeight =
|
2013-01-17 00:51:00 +04:00
|
|
|
|
GetLengthValue(SVGPatternElement::ATTR_HEIGHT)->GetAnimValue(aTarget);
|
2005-09-14 02:38:36 +04:00
|
|
|
|
}
|
2012-03-31 14:47:18 +04:00
|
|
|
|
|
|
|
|
|
if (viewportWidth <= 0.0f || viewportHeight <= 0.0f) {
|
|
|
|
|
return gfxMatrix(0.0, 0.0, 0.0, 0.0, 0.0, 0.0); // singular
|
|
|
|
|
}
|
|
|
|
|
|
2013-12-30 10:50:17 +04:00
|
|
|
|
Matrix tm = SVGContentUtils::GetViewBoxTransform(
|
2019-04-10 07:08:14 +03:00
|
|
|
|
viewportWidth * scaleX, viewportHeight * scaleY, viewBox.x, viewBox.y,
|
|
|
|
|
viewBox.width, viewBox.height, GetPreserveAspectRatio());
|
2011-04-10 00:57:51 +04:00
|
|
|
|
|
2015-04-07 10:45:59 +03:00
|
|
|
|
return ThebesMatrix(tm);
|
2005-09-14 02:38:36 +04:00
|
|
|
|
}
|
|
|
|
|
|
2006-05-16 19:55:01 +04:00
|
|
|
|
//----------------------------------------------------------------------
|
|
|
|
|
// nsSVGPaintServerFrame methods:
|
2010-07-01 20:40:30 +04:00
|
|
|
|
already_AddRefed<gfxPattern> nsSVGPatternFrame::GetPaintServerPattern(
|
2019-05-01 11:47:10 +03:00
|
|
|
|
nsIFrame* aSource, const DrawTarget* aDrawTarget,
|
2019-07-06 11:31:02 +03:00
|
|
|
|
const gfxMatrix& aContextMatrix,
|
|
|
|
|
mozilla::StyleSVGPaint nsStyleSVG::*aFillOrStroke, float aGraphicOpacity,
|
|
|
|
|
imgDrawingParams& aImgParams, const gfxRect* aOverrideBounds) {
|
2008-02-09 00:52:04 +03:00
|
|
|
|
if (aGraphicOpacity == 0.0f) {
|
2017-05-18 23:03:50 +03:00
|
|
|
|
return do_AddRef(new gfxPattern(Color()));
|
2008-02-09 00:52:04 +03:00
|
|
|
|
}
|
2007-04-24 12:11:22 +04:00
|
|
|
|
|
2006-05-16 19:55:01 +04:00
|
|
|
|
// Paint it!
|
2014-06-18 04:07:21 +04:00
|
|
|
|
Matrix pMatrix;
|
2017-05-18 23:03:50 +03:00
|
|
|
|
RefPtr<SourceSurface> surface =
|
2014-09-29 17:15:19 +04:00
|
|
|
|
PaintPattern(aDrawTarget, &pMatrix, ToMatrix(aContextMatrix), aSource,
|
2017-05-18 23:03:50 +03:00
|
|
|
|
aFillOrStroke, aGraphicOpacity, aOverrideBounds, aImgParams);
|
2007-10-02 18:57:47 +04:00
|
|
|
|
|
2014-06-18 04:07:21 +04:00
|
|
|
|
if (!surface) {
|
2017-05-18 23:03:50 +03:00
|
|
|
|
return nullptr;
|
2006-09-26 20:36:03 +04:00
|
|
|
|
}
|
2006-05-16 19:55:01 +04:00
|
|
|
|
|
2015-10-18 08:24:48 +03:00
|
|
|
|
RefPtr<gfxPattern> pattern = new gfxPattern(surface, pMatrix);
|
2006-09-26 20:36:03 +04:00
|
|
|
|
|
2017-03-21 05:12:23 +03:00
|
|
|
|
if (!pattern) {
|
2017-05-18 23:03:50 +03:00
|
|
|
|
return nullptr;
|
2017-03-21 05:12:23 +03:00
|
|
|
|
}
|
2006-05-16 19:55:01 +04:00
|
|
|
|
|
2015-09-25 10:58:23 +03:00
|
|
|
|
pattern->SetExtend(ExtendMode::REPEAT);
|
2017-05-18 23:03:50 +03:00
|
|
|
|
return pattern.forget();
|
2006-05-16 19:55:01 +04:00
|
|
|
|
}
|
|
|
|
|
|
2005-09-14 02:38:36 +04:00
|
|
|
|
// -------------------------------------------------------------------------
|
|
|
|
|
// Public functions
|
|
|
|
|
// -------------------------------------------------------------------------
|
|
|
|
|
|
2019-05-01 11:47:10 +03:00
|
|
|
|
nsIFrame* NS_NewSVGPatternFrame(PresShell* aPresShell, ComputedStyle* aStyle) {
|
2019-02-05 19:45:54 +03:00
|
|
|
|
return new (aPresShell)
|
|
|
|
|
nsSVGPatternFrame(aStyle, aPresShell->GetPresContext());
|
2005-09-14 02:38:36 +04:00
|
|
|
|
}
|