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/. */
|
2004-10-15 03:02:53 +04:00
|
|
|
|
2012-03-26 15:58:59 +04:00
|
|
|
// Main header first:
|
2006-05-12 00:01:12 +04:00
|
|
|
#include "nsSVGGradientFrame.h"
|
2013-01-15 16:22:03 +04:00
|
|
|
#include <algorithm>
|
2012-03-26 15:58:59 +04:00
|
|
|
|
|
|
|
// Keep others in (case-insensitive) order:
|
2017-02-21 13:10:43 +03:00
|
|
|
#include "AutoReferenceChainGuard.h"
|
2007-04-27 18:28:39 +04:00
|
|
|
#include "gfxPattern.h"
|
2013-01-11 12:43:01 +04:00
|
|
|
#include "mozilla/dom/SVGGradientElement.h"
|
2018-02-18 18:53:13 +03:00
|
|
|
#include "mozilla/dom/SVGGradientElementBinding.h"
|
2013-01-11 12:43:01 +04:00
|
|
|
#include "mozilla/dom/SVGStopElement.h"
|
2018-02-18 18:53:13 +03:00
|
|
|
#include "mozilla/dom/SVGUnitTypesBinding.h"
|
2011-08-11 17:29:50 +04:00
|
|
|
#include "nsContentUtils.h"
|
2017-08-30 16:14:46 +03:00
|
|
|
#include "SVGObserverUtils.h"
|
2018-12-27 02:46:38 +03:00
|
|
|
#include "SVGAnimatedTransformList.h"
|
2013-01-11 12:43:01 +04:00
|
|
|
|
|
|
|
// XXX Tight coupling with content classes ahead!
|
2005-03-09 22:24:18 +03:00
|
|
|
|
2013-01-08 07:22:41 +04:00
|
|
|
using namespace mozilla;
|
|
|
|
using namespace mozilla::dom;
|
2018-06-26 00:20:54 +03:00
|
|
|
using namespace mozilla::dom::SVGGradientElement_Binding;
|
|
|
|
using namespace mozilla::dom::SVGUnitTypes_Binding;
|
2015-09-25 03:50:46 +03:00
|
|
|
using namespace mozilla::gfx;
|
2011-09-26 01:04:32 +04:00
|
|
|
|
2004-10-15 03:02:53 +04:00
|
|
|
//----------------------------------------------------------------------
|
2005-03-09 22:24:18 +03:00
|
|
|
// Implementation
|
|
|
|
|
2019-02-05 19:45:54 +03:00
|
|
|
nsSVGGradientFrame::nsSVGGradientFrame(ComputedStyle* aStyle,
|
|
|
|
nsPresContext* aPresContext, ClassID aID)
|
|
|
|
: nsSVGPaintServerFrame(aStyle, aPresContext, aID),
|
2017-05-11 06:20:58 +03:00
|
|
|
mSource(nullptr),
|
2016-04-18 10:15:23 +03:00
|
|
|
mLoopFlag(false),
|
|
|
|
mNoHRefURI(false) {}
|
2006-09-08 17:19:47 +04:00
|
|
|
|
2005-03-09 22:24:18 +03:00
|
|
|
//----------------------------------------------------------------------
|
|
|
|
// nsIFrame methods:
|
|
|
|
|
2012-08-22 19:56:38 +04:00
|
|
|
nsresult nsSVGGradientFrame::AttributeChanged(int32_t aNameSpaceID,
|
2017-10-03 01:05:19 +03:00
|
|
|
nsAtom* aAttribute,
|
2012-08-22 19:56:38 +04:00
|
|
|
int32_t aModType) {
|
2006-03-07 03:04:59 +03:00
|
|
|
if (aNameSpaceID == kNameSpaceID_None &&
|
|
|
|
(aAttribute == nsGkAtoms::gradientUnits ||
|
|
|
|
aAttribute == nsGkAtoms::gradientTransform ||
|
|
|
|
aAttribute == nsGkAtoms::spreadMethod)) {
|
2017-08-30 17:58:31 +03:00
|
|
|
SVGObserverUtils::InvalidateDirectRenderingObservers(this);
|
2016-07-07 09:26:57 +03:00
|
|
|
} else if ((aNameSpaceID == kNameSpaceID_XLink ||
|
|
|
|
aNameSpaceID == kNameSpaceID_None) &&
|
2008-10-01 04:51:05 +04:00
|
|
|
aAttribute == nsGkAtoms::href) {
|
|
|
|
// 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-07 03:04:59 +03:00
|
|
|
}
|
|
|
|
|
2016-04-18 10:15:23 +03:00
|
|
|
return nsSVGPaintServerFrame::AttributeChanged(aNameSpaceID, aAttribute,
|
|
|
|
aModType);
|
2006-03-07 03:04:59 +03:00
|
|
|
}
|
|
|
|
|
2005-03-09 22:24:18 +03:00
|
|
|
//----------------------------------------------------------------------
|
2004-10-15 03:02:53 +04:00
|
|
|
|
2012-08-22 19:56:38 +04:00
|
|
|
uint16_t nsSVGGradientFrame::GetEnumValue(uint32_t aIndex,
|
|
|
|
nsIContent* aDefault) {
|
2019-04-04 20:40:56 +03:00
|
|
|
const SVGAnimatedEnumeration& thisEnum =
|
|
|
|
static_cast<dom::SVGGradientElement*>(GetContent())
|
|
|
|
->mEnumAttributes[aIndex];
|
2012-03-06 10:58:40 +04:00
|
|
|
|
2018-12-12 09:32:44 +03:00
|
|
|
if (thisEnum.IsExplicitlySet()) {
|
|
|
|
return thisEnum.GetAnimValue();
|
|
|
|
}
|
2012-03-06 10:58:40 +04:00
|
|
|
|
2017-02-21 13:10:43 +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 static_cast<dom::SVGGradientElement*>(aDefault)
|
|
|
|
->mEnumAttributes[aIndex]
|
|
|
|
.GetAnimValue();
|
|
|
|
}
|
|
|
|
|
|
|
|
nsSVGGradientFrame* next = GetReferencedGradient();
|
2012-03-06 10:58:40 +04:00
|
|
|
|
2017-02-21 13:10:43 +03:00
|
|
|
return next ? next->GetEnumValue(aIndex, aDefault)
|
|
|
|
: static_cast<dom::SVGGradientElement*>(aDefault)
|
|
|
|
->mEnumAttributes[aIndex]
|
|
|
|
.GetAnimValue();
|
2012-03-06 10:58:40 +04:00
|
|
|
}
|
|
|
|
|
2012-03-20 16:15:55 +04:00
|
|
|
uint16_t nsSVGGradientFrame::GetGradientUnits() {
|
|
|
|
// This getter is called every time the others are called - maybe cache it?
|
2013-01-11 12:43:01 +04:00
|
|
|
return GetEnumValue(dom::SVGGradientElement::GRADIENTUNITS);
|
2012-03-20 16:15:55 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
uint16_t nsSVGGradientFrame::GetSpreadMethod() {
|
2013-01-11 12:43:01 +04:00
|
|
|
return GetEnumValue(dom::SVGGradientElement::SPREADMETHOD);
|
2012-03-20 16:15:55 +04:00
|
|
|
}
|
|
|
|
|
2018-12-27 02:46:38 +03:00
|
|
|
const SVGAnimatedTransformList* nsSVGGradientFrame::GetGradientTransformList(
|
2012-03-06 10:58:40 +04:00
|
|
|
nsIContent* aDefault) {
|
2018-12-27 02:46:38 +03:00
|
|
|
SVGAnimatedTransformList* thisTransformList =
|
2017-08-27 01:58:38 +03:00
|
|
|
static_cast<dom::SVGGradientElement*>(GetContent())
|
|
|
|
->GetAnimatedTransformList();
|
2012-03-06 10:58:40 +04:00
|
|
|
|
2012-07-30 04:35:26 +04:00
|
|
|
if (thisTransformList && thisTransformList->IsExplicitlySet())
|
2012-03-06 10:58:40 +04:00
|
|
|
return thisTransformList;
|
|
|
|
|
2017-02-21 13:10:43 +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 static_cast<const dom::SVGGradientElement*>(aDefault)
|
|
|
|
->mGradientTransform.get();
|
|
|
|
}
|
2012-03-06 10:58:40 +04:00
|
|
|
|
2017-02-21 13:10:43 +03:00
|
|
|
nsSVGGradientFrame* next = GetReferencedGradient();
|
|
|
|
|
|
|
|
return next ? next->GetGradientTransformList(aDefault)
|
|
|
|
: static_cast<const dom::SVGGradientElement*>(aDefault)
|
|
|
|
->mGradientTransform.get();
|
2012-03-06 10:58:40 +04:00
|
|
|
}
|
|
|
|
|
2010-07-01 20:40:30 +04:00
|
|
|
gfxMatrix nsSVGGradientFrame::GetGradientTransform(
|
|
|
|
nsIFrame* aSource, const gfxRect* aOverrideBounds) {
|
2007-04-27 18:28:39 +04:00
|
|
|
gfxMatrix bboxMatrix;
|
2006-04-20 19:24:51 +04:00
|
|
|
|
2012-08-22 19:56:38 +04:00
|
|
|
uint16_t gradientUnits = GetGradientUnits();
|
2013-05-27 11:31:39 +04:00
|
|
|
if (gradientUnits != SVG_UNIT_TYPE_USERSPACEONUSE) {
|
|
|
|
NS_ASSERTION(gradientUnits == SVG_UNIT_TYPE_OBJECTBOUNDINGBOX,
|
|
|
|
"Unknown gradientUnits type");
|
2006-03-28 04:33:22 +04:00
|
|
|
// objectBoundingBox is the default anyway
|
2005-02-19 02:17:48 +03:00
|
|
|
|
2017-03-14 08:26:05 +03:00
|
|
|
gfxRect bbox = aOverrideBounds
|
|
|
|
? *aOverrideBounds
|
|
|
|
: nsSVGUtils::GetBBox(
|
|
|
|
aSource, nsSVGUtils::eUseFrameBoundsForOuterSVG |
|
|
|
|
nsSVGUtils::eBBoxIncludeFillGeometry);
|
2012-03-06 10:58:40 +04:00
|
|
|
bboxMatrix =
|
|
|
|
gfxMatrix(bbox.Width(), 0, 0, bbox.Height(), bbox.X(), bbox.Y());
|
2005-02-19 02:17:48 +03:00
|
|
|
}
|
|
|
|
|
2018-12-27 02:46:38 +03:00
|
|
|
const SVGAnimatedTransformList* animTransformList =
|
2017-08-27 01:58:38 +03:00
|
|
|
GetGradientTransformList(GetContent());
|
2018-12-12 09:32:44 +03:00
|
|
|
if (!animTransformList) {
|
|
|
|
return bboxMatrix;
|
|
|
|
}
|
2006-04-20 19:24:51 +04:00
|
|
|
|
2011-09-26 01:04:32 +04:00
|
|
|
gfxMatrix gradientTransform =
|
|
|
|
animTransformList->GetAnimValue().GetConsolidationMatrix();
|
|
|
|
return bboxMatrix.PreMultiply(gradientTransform);
|
2004-10-15 03:02:53 +04:00
|
|
|
}
|
|
|
|
|
2012-08-22 19:56:38 +04:00
|
|
|
dom::SVGLinearGradientElement* nsSVGGradientFrame::GetLinearGradientWithLength(
|
2013-01-11 12:43:01 +04:00
|
|
|
uint32_t aIndex, dom::SVGLinearGradientElement* aDefault) {
|
2012-03-06 10:58:40 +04:00
|
|
|
// If this was a linear gradient with the required length, we would have
|
|
|
|
// already found it in nsSVGLinearGradientFrame::GetLinearGradientWithLength.
|
|
|
|
// Since we didn't find the length, continue looking down the chain.
|
|
|
|
|
2017-02-21 13:10:43 +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 aDefault;
|
|
|
|
}
|
2006-05-12 00:01:12 +04:00
|
|
|
|
2017-02-21 13:10:43 +03:00
|
|
|
nsSVGGradientFrame* next = GetReferencedGradient();
|
2012-03-06 10:58:40 +04:00
|
|
|
return next ? next->GetLinearGradientWithLength(aIndex, aDefault) : aDefault;
|
|
|
|
}
|
|
|
|
|
2012-08-22 19:56:38 +04:00
|
|
|
dom::SVGRadialGradientElement* nsSVGGradientFrame::GetRadialGradientWithLength(
|
2013-01-11 12:43:01 +04:00
|
|
|
uint32_t aIndex, dom::SVGRadialGradientElement* aDefault) {
|
2012-03-06 10:58:40 +04:00
|
|
|
// If this was a radial gradient with the required length, we would have
|
|
|
|
// already found it in nsSVGRadialGradientFrame::GetRadialGradientWithLength.
|
|
|
|
// Since we didn't find the length, continue looking down the chain.
|
|
|
|
|
2017-02-21 13:10:43 +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 aDefault;
|
|
|
|
}
|
2012-03-06 10:58:40 +04:00
|
|
|
|
2017-02-21 13:10:43 +03:00
|
|
|
nsSVGGradientFrame* next = GetReferencedGradient();
|
2012-03-06 10:58:40 +04:00
|
|
|
return next ? next->GetRadialGradientWithLength(aIndex, aDefault) : aDefault;
|
2004-10-15 03:02:53 +04:00
|
|
|
}
|
|
|
|
|
2006-05-16 19:55:01 +04:00
|
|
|
//----------------------------------------------------------------------
|
|
|
|
// nsSVGPaintServerFrame methods:
|
|
|
|
|
2013-05-27 11:34:01 +04:00
|
|
|
// helper
|
|
|
|
static void GetStopInformation(nsIFrame* aStopFrame, float* aOffset,
|
|
|
|
nscolor* aStopColor, float* aStopOpacity) {
|
|
|
|
nsIContent* stopContent = aStopFrame->GetContent();
|
2015-03-03 14:08:59 +03:00
|
|
|
MOZ_ASSERT(stopContent && stopContent->IsSVGElement(nsGkAtoms::stop));
|
2013-05-27 11:34:01 +04:00
|
|
|
|
|
|
|
static_cast<SVGStopElement*>(stopContent)
|
|
|
|
->GetAnimatedNumberValues(aOffset, nullptr);
|
|
|
|
|
2018-04-27 05:07:20 +03:00
|
|
|
const nsStyleSVGReset* styleSVGReset = aStopFrame->StyleSVGReset();
|
2013-05-27 11:34:01 +04:00
|
|
|
*aOffset = mozilla::clamped(*aOffset, 0.0f, 1.0f);
|
2018-04-27 05:07:20 +03:00
|
|
|
*aStopColor = styleSVGReset->mStopColor.CalcColor(aStopFrame);
|
|
|
|
*aStopOpacity = styleSVGReset->mStopOpacity;
|
2013-05-27 11:34:01 +04:00
|
|
|
}
|
|
|
|
|
2014-09-29 17:15:19 +04:00
|
|
|
already_AddRefed<gfxPattern> nsSVGGradientFrame::GetPaintServerPattern(
|
|
|
|
nsIFrame* aSource, const DrawTarget* aDrawTarget,
|
2012-05-18 12:34:25 +04:00
|
|
|
const gfxMatrix& aContextMatrix, nsStyleSVGPaint nsStyleSVG::*aFillOrStroke,
|
2017-05-18 23:03:50 +03:00
|
|
|
float aGraphicOpacity, imgDrawingParams& aImgParams,
|
|
|
|
const gfxRect* aOverrideBounds) {
|
2013-05-27 11:31:39 +04:00
|
|
|
uint16_t gradientUnits = GetGradientUnits();
|
|
|
|
MOZ_ASSERT(gradientUnits == SVG_UNIT_TYPE_OBJECTBOUNDINGBOX ||
|
|
|
|
gradientUnits == SVG_UNIT_TYPE_USERSPACEONUSE);
|
|
|
|
if (gradientUnits == SVG_UNIT_TYPE_USERSPACEONUSE) {
|
|
|
|
// Set mSource for this consumer.
|
|
|
|
// If this gradient is applied to text, our caller will be the glyph, which
|
|
|
|
// is not an element, so we need to get the parent
|
2018-04-13 01:41:00 +03:00
|
|
|
mSource = aSource->GetContent()->IsText() ? aSource->GetParent() : aSource;
|
2013-05-27 11:31:39 +04:00
|
|
|
}
|
2006-05-16 19:55:01 +04:00
|
|
|
|
2016-02-02 18:36:30 +03:00
|
|
|
AutoTArray<nsIFrame*, 8> stopFrames;
|
2013-05-27 11:34:01 +04:00
|
|
|
GetStopFrames(&stopFrames);
|
|
|
|
|
|
|
|
uint32_t nStops = stopFrames.Length();
|
2008-02-09 00:52:04 +03:00
|
|
|
|
|
|
|
// SVG specification says that no stops should be treated like
|
|
|
|
// the corresponding fill or stroke had "none" specified.
|
|
|
|
if (nStops == 0) {
|
2015-10-18 08:24:48 +03:00
|
|
|
RefPtr<gfxPattern> pattern = new gfxPattern(Color());
|
2017-05-18 23:03:50 +03:00
|
|
|
return do_AddRef(new gfxPattern(Color()));
|
2008-02-09 00:52:04 +03:00
|
|
|
}
|
2012-10-06 16:52:32 +04:00
|
|
|
|
2013-05-27 11:34:01 +04:00
|
|
|
if (nStops == 1 || GradientVectorLengthIsZero()) {
|
2018-04-27 05:07:20 +03:00
|
|
|
auto lastStopFrame = stopFrames[nStops - 1];
|
|
|
|
auto svgReset = lastStopFrame->StyleSVGReset();
|
2013-05-27 11:34:01 +04:00
|
|
|
// The gradient paints a single colour, using the stop-color of the last
|
|
|
|
// gradient step if there are more than one.
|
2018-04-27 05:07:20 +03:00
|
|
|
float stopOpacity = svgReset->mStopOpacity;
|
|
|
|
nscolor stopColor = svgReset->mStopColor.CalcColor(lastStopFrame);
|
2013-05-27 11:34:01 +04:00
|
|
|
|
2015-09-25 03:50:46 +03:00
|
|
|
Color stopColor2 = Color::FromABGR(stopColor);
|
|
|
|
stopColor2.a *= stopOpacity * aGraphicOpacity;
|
2017-05-18 23:03:50 +03:00
|
|
|
return do_AddRef(new gfxPattern(stopColor2));
|
2012-10-06 16:52:32 +04:00
|
|
|
}
|
2008-02-09 00:52:04 +03:00
|
|
|
|
2013-05-27 11:31:39 +04:00
|
|
|
// Get the transform list (if there is one). We do this after the returns
|
|
|
|
// above since this call can be expensive when "gradientUnits" is set to
|
|
|
|
// "objectBoundingBox" (since that requiring a GetBBox() call).
|
|
|
|
gfxMatrix patternMatrix = GetGradientTransform(aSource, aOverrideBounds);
|
|
|
|
|
|
|
|
if (patternMatrix.IsSingular()) {
|
2017-05-18 23:03:50 +03:00
|
|
|
return nullptr;
|
2013-05-27 11:31:39 +04:00
|
|
|
}
|
|
|
|
|
2014-09-30 21:08:14 +04:00
|
|
|
// revert any vector effect transform so that the gradient appears unchanged
|
2012-05-18 12:34:25 +04:00
|
|
|
if (aFillOrStroke == &nsStyleSVG::mStroke) {
|
2014-09-30 21:08:14 +04:00
|
|
|
gfxMatrix userToOuterSVG;
|
|
|
|
if (nsSVGUtils::GetNonScalingStrokeTransform(aSource, &userToOuterSVG)) {
|
|
|
|
patternMatrix *= userToOuterSVG;
|
2014-07-11 11:06:39 +04:00
|
|
|
}
|
2012-05-18 12:34:25 +04:00
|
|
|
}
|
|
|
|
|
2014-07-11 11:06:39 +04:00
|
|
|
if (!patternMatrix.Invert()) {
|
2017-05-18 23:03:50 +03:00
|
|
|
return nullptr;
|
2014-07-11 11:06:39 +04:00
|
|
|
}
|
2007-04-27 18:28:39 +04:00
|
|
|
|
2015-10-18 08:24:48 +03:00
|
|
|
RefPtr<gfxPattern> gradient = CreateGradient();
|
2017-03-21 05:12:23 +03:00
|
|
|
if (!gradient) {
|
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
|
|
|
|
2012-08-22 19:56:38 +04:00
|
|
|
uint16_t aSpread = GetSpreadMethod();
|
2013-02-03 00:23:16 +04:00
|
|
|
if (aSpread == SVG_SPREADMETHOD_PAD)
|
2015-09-25 10:58:23 +03:00
|
|
|
gradient->SetExtend(ExtendMode::CLAMP);
|
2013-02-03 00:23:16 +04:00
|
|
|
else if (aSpread == SVG_SPREADMETHOD_REFLECT)
|
2015-09-25 10:58:23 +03:00
|
|
|
gradient->SetExtend(ExtendMode::REFLECT);
|
2013-02-03 00:23:16 +04:00
|
|
|
else if (aSpread == SVG_SPREADMETHOD_REPEAT)
|
2015-09-25 10:58:23 +03:00
|
|
|
gradient->SetExtend(ExtendMode::REPEAT);
|
2007-04-27 18:28:39 +04:00
|
|
|
|
|
|
|
gradient->SetMatrix(patternMatrix);
|
2006-05-16 19:55:01 +04:00
|
|
|
|
|
|
|
// setup stops
|
|
|
|
float lastOffset = 0.0f;
|
|
|
|
|
2012-08-22 19:56:38 +04:00
|
|
|
for (uint32_t i = 0; i < nStops; i++) {
|
2007-04-24 12:11:22 +04:00
|
|
|
float offset, stopOpacity;
|
|
|
|
nscolor stopColor;
|
2006-05-16 19:55:01 +04:00
|
|
|
|
2013-05-27 11:34:01 +04:00
|
|
|
GetStopInformation(stopFrames[i], &offset, &stopColor, &stopOpacity);
|
2006-05-16 19:55:01 +04:00
|
|
|
|
|
|
|
if (offset < lastOffset)
|
|
|
|
offset = lastOffset;
|
|
|
|
else
|
|
|
|
lastOffset = offset;
|
|
|
|
|
2015-09-25 03:50:46 +03:00
|
|
|
Color stopColor2 = Color::FromABGR(stopColor);
|
|
|
|
stopColor2.a *= stopOpacity * aGraphicOpacity;
|
|
|
|
gradient->AddColorStop(offset, stopColor2);
|
2006-05-16 19:55:01 +04:00
|
|
|
}
|
|
|
|
|
2017-05-18 23:03:50 +03:00
|
|
|
return gradient.forget();
|
2006-05-16 19:55:01 +04:00
|
|
|
}
|
|
|
|
|
2004-10-15 03:02:53 +04:00
|
|
|
// Private (helper) methods
|
|
|
|
|
2008-10-01 04:51:05 +04:00
|
|
|
nsSVGGradientFrame* nsSVGGradientFrame::GetReferencedGradient() {
|
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 12:47:20 +04:00
|
|
|
|
2018-08-21 16:54:26 +03:00
|
|
|
auto GetHref = [this](nsAString& aHref) {
|
2016-07-07 09:26:57 +03:00
|
|
|
dom::SVGGradientElement* grad =
|
2018-08-21 16:54:26 +03:00
|
|
|
static_cast<dom::SVGGradientElement*>(this->GetContent());
|
2016-07-07 09:26:57 +03:00
|
|
|
if (grad->mStringAttributes[dom::SVGGradientElement::HREF]
|
|
|
|
.IsExplicitlySet()) {
|
|
|
|
grad->mStringAttributes[dom::SVGGradientElement::HREF].GetAnimValue(aHref,
|
2018-08-21 16:54:26 +03:00
|
|
|
grad);
|
2016-07-07 09:26:57 +03:00
|
|
|
} else {
|
|
|
|
grad->mStringAttributes[dom::SVGGradientElement::XLINK_HREF].GetAnimValue(
|
2018-08-21 16:54:26 +03:00
|
|
|
aHref, grad);
|
2016-07-07 09:26:57 +03:00
|
|
|
}
|
2018-08-21 16:54:26 +03:00
|
|
|
this->mNoHRefURI = aHref.IsEmpty();
|
|
|
|
};
|
|
|
|
|
2018-09-25 23:16:49 +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::SVGLinearGradient ||
|
|
|
|
frameType == LayoutFrameType::SVGRadialGradient) {
|
|
|
|
return static_cast<nsSVGGradientFrame*>(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.
|
2004-10-15 03:02:53 +04:00
|
|
|
}
|
2008-10-01 04:51:05 +04:00
|
|
|
|
2018-08-21 16:54:26 +03:00
|
|
|
return nullptr;
|
2004-10-15 03:02:53 +04:00
|
|
|
}
|
|
|
|
|
2013-05-27 11:34:01 +04:00
|
|
|
void nsSVGGradientFrame::GetStopFrames(nsTArray<nsIFrame*>* aStopFrames) {
|
2012-07-30 18:20:58 +04:00
|
|
|
nsIFrame* stopFrame = nullptr;
|
2005-03-09 22:24:18 +03:00
|
|
|
for (stopFrame = mFrames.FirstChild(); stopFrame;
|
|
|
|
stopFrame = stopFrame->GetNextSibling()) {
|
2017-04-30 18:30:08 +03:00
|
|
|
if (stopFrame->IsSVGStopFrame()) {
|
2013-05-27 11:34:01 +04:00
|
|
|
aStopFrames->AppendElement(stopFrame);
|
2005-03-09 22:24:18 +03:00
|
|
|
}
|
|
|
|
}
|
2013-05-27 11:34:01 +04:00
|
|
|
if (aStopFrames->Length() > 0) {
|
|
|
|
return;
|
2006-03-28 04:33:22 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
// Our gradient element doesn't have stops - try to "inherit" them
|
|
|
|
|
2017-02-21 13:10:43 +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
|
2013-05-27 11:34:01 +04:00
|
|
|
return;
|
|
|
|
}
|
2006-03-28 04:33:22 +04:00
|
|
|
|
2017-02-21 13:10:43 +03:00
|
|
|
nsSVGGradientFrame* next = GetReferencedGradient();
|
|
|
|
if (next) {
|
|
|
|
next->GetStopFrames(aStopFrames);
|
|
|
|
}
|
2006-03-28 04:33:22 +04:00
|
|
|
}
|
|
|
|
|
2005-03-09 22:24:18 +03:00
|
|
|
// -------------------------------------------------------------------------
|
|
|
|
// Linear Gradients
|
|
|
|
// -------------------------------------------------------------------------
|
2004-10-15 03:02:53 +04:00
|
|
|
|
2009-01-19 21:31:34 +03:00
|
|
|
#ifdef DEBUG
|
2014-05-25 02:20:40 +04:00
|
|
|
void nsSVGLinearGradientFrame::Init(nsIContent* aContent,
|
|
|
|
nsContainerFrame* aParent,
|
|
|
|
nsIFrame* aPrevInFlow) {
|
2015-03-03 14:08:59 +03:00
|
|
|
NS_ASSERTION(aContent->IsSVGElement(nsGkAtoms::linearGradient),
|
2013-01-08 07:22:41 +04:00
|
|
|
"Content is not an SVG linearGradient");
|
2009-01-19 21:31:34 +03:00
|
|
|
|
2016-04-18 10:17:35 +03:00
|
|
|
nsSVGGradientFrame::Init(aContent, aParent, aPrevInFlow);
|
2009-01-19 21:31:34 +03:00
|
|
|
}
|
|
|
|
#endif /* DEBUG */
|
|
|
|
|
2012-08-22 19:56:38 +04:00
|
|
|
nsresult nsSVGLinearGradientFrame::AttributeChanged(int32_t aNameSpaceID,
|
2017-10-03 01:05:19 +03:00
|
|
|
nsAtom* aAttribute,
|
2012-08-22 19:56:38 +04:00
|
|
|
int32_t aModType) {
|
2006-03-07 03:04:59 +03:00
|
|
|
if (aNameSpaceID == kNameSpaceID_None &&
|
|
|
|
(aAttribute == nsGkAtoms::x1 || aAttribute == nsGkAtoms::y1 ||
|
|
|
|
aAttribute == nsGkAtoms::x2 || aAttribute == nsGkAtoms::y2)) {
|
2017-08-30 17:58:31 +03:00
|
|
|
SVGObserverUtils::InvalidateDirectRenderingObservers(this);
|
2006-03-07 03:04:59 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
return nsSVGGradientFrame::AttributeChanged(aNameSpaceID, aAttribute,
|
|
|
|
aModType);
|
|
|
|
}
|
|
|
|
|
2004-10-15 03:02:53 +04:00
|
|
|
//----------------------------------------------------------------------
|
2006-03-28 04:33:22 +04:00
|
|
|
|
2012-08-22 19:56:38 +04:00
|
|
|
float nsSVGLinearGradientFrame::GetLengthValue(uint32_t aIndex) {
|
2013-01-11 12:43:01 +04:00
|
|
|
dom::SVGLinearGradientElement* lengthElement = GetLinearGradientWithLength(
|
2017-08-27 01:58:38 +03:00
|
|
|
aIndex, static_cast<dom::SVGLinearGradientElement*>(GetContent()));
|
2012-03-06 10:58:40 +04:00
|
|
|
// We passed in mContent as a fallback, so, assuming mContent is non-null, the
|
|
|
|
// return value should also be non-null.
|
2015-02-10 01:34:50 +03:00
|
|
|
MOZ_ASSERT(lengthElement,
|
2012-03-06 10:58:40 +04:00
|
|
|
"Got unexpected null element from GetLinearGradientWithLength");
|
2019-04-09 23:04:33 +03:00
|
|
|
const SVGAnimatedLength& length = lengthElement->mLengthAttributes[aIndex];
|
2006-03-07 03:04:59 +03:00
|
|
|
|
|
|
|
// Object bounding box units are handled by setting the appropriate
|
2007-08-28 03:11:14 +04:00
|
|
|
// transform in GetGradientTransform, but we need to handle user
|
2006-03-07 03:04:59 +03:00
|
|
|
// space units as part of the individual Get* routines. Fixes 323669.
|
|
|
|
|
2012-08-22 19:56:38 +04:00
|
|
|
uint16_t gradientUnits = GetGradientUnits();
|
2013-02-18 06:14:02 +04:00
|
|
|
if (gradientUnits == SVG_UNIT_TYPE_USERSPACEONUSE) {
|
2012-03-06 10:58:40 +04:00
|
|
|
return nsSVGUtils::UserSpace(mSource, &length);
|
2006-03-07 03:04:59 +03:00
|
|
|
}
|
2006-03-28 04:33:22 +04:00
|
|
|
|
2013-02-18 06:14:02 +04:00
|
|
|
NS_ASSERTION(gradientUnits == SVG_UNIT_TYPE_OBJECTBOUNDINGBOX,
|
2012-03-06 10:58:40 +04:00
|
|
|
"Unknown gradientUnits type");
|
2006-03-28 04:33:22 +04:00
|
|
|
|
2017-08-21 11:19:31 +03:00
|
|
|
return length.GetAnimValue(static_cast<SVGViewportElement*>(nullptr));
|
2012-03-06 10:58:40 +04:00
|
|
|
}
|
|
|
|
|
2013-01-11 12:43:01 +04:00
|
|
|
dom::SVGLinearGradientElement*
|
2012-08-22 19:56:38 +04:00
|
|
|
nsSVGLinearGradientFrame::GetLinearGradientWithLength(
|
2013-01-11 12:43:01 +04:00
|
|
|
uint32_t aIndex, dom::SVGLinearGradientElement* aDefault) {
|
|
|
|
dom::SVGLinearGradientElement* thisElement =
|
2017-08-27 01:58:38 +03:00
|
|
|
static_cast<dom::SVGLinearGradientElement*>(GetContent());
|
2019-04-09 23:04:33 +03:00
|
|
|
const SVGAnimatedLength& length = thisElement->mLengthAttributes[aIndex];
|
2012-03-06 10:58:40 +04:00
|
|
|
|
|
|
|
if (length.IsExplicitlySet()) {
|
|
|
|
return thisElement;
|
|
|
|
}
|
|
|
|
|
2016-04-18 10:17:35 +03:00
|
|
|
return nsSVGGradientFrame::GetLinearGradientWithLength(aIndex, aDefault);
|
2004-10-15 03:02:53 +04:00
|
|
|
}
|
|
|
|
|
2013-05-27 11:34:01 +04:00
|
|
|
bool nsSVGLinearGradientFrame::GradientVectorLengthIsZero() {
|
|
|
|
return GetLengthValue(dom::SVGLinearGradientElement::ATTR_X1) ==
|
|
|
|
GetLengthValue(dom::SVGLinearGradientElement::ATTR_X2) &&
|
|
|
|
GetLengthValue(dom::SVGLinearGradientElement::ATTR_Y1) ==
|
|
|
|
GetLengthValue(dom::SVGLinearGradientElement::ATTR_Y2);
|
2012-10-06 16:52:32 +04:00
|
|
|
}
|
|
|
|
|
2006-05-16 19:55:01 +04:00
|
|
|
already_AddRefed<gfxPattern> nsSVGLinearGradientFrame::CreateGradient() {
|
|
|
|
float x1, y1, x2, y2;
|
|
|
|
|
2013-01-11 12:43:01 +04:00
|
|
|
x1 = GetLengthValue(dom::SVGLinearGradientElement::ATTR_X1);
|
|
|
|
y1 = GetLengthValue(dom::SVGLinearGradientElement::ATTR_Y1);
|
|
|
|
x2 = GetLengthValue(dom::SVGLinearGradientElement::ATTR_X2);
|
|
|
|
y2 = GetLengthValue(dom::SVGLinearGradientElement::ATTR_Y2);
|
2006-05-16 19:55:01 +04:00
|
|
|
|
2015-10-18 08:24:48 +03:00
|
|
|
RefPtr<gfxPattern> pattern = new gfxPattern(x1, y1, x2, y2);
|
2013-04-22 15:15:59 +04:00
|
|
|
return pattern.forget();
|
2005-03-09 22:24:18 +03:00
|
|
|
}
|
2004-10-15 03:02:53 +04:00
|
|
|
|
2006-03-07 03:04:59 +03:00
|
|
|
// -------------------------------------------------------------------------
|
|
|
|
// Radial Gradients
|
|
|
|
// -------------------------------------------------------------------------
|
2004-10-15 03:02:53 +04:00
|
|
|
|
2009-01-19 21:31:34 +03:00
|
|
|
#ifdef DEBUG
|
2014-05-25 02:20:40 +04:00
|
|
|
void nsSVGRadialGradientFrame::Init(nsIContent* aContent,
|
|
|
|
nsContainerFrame* aParent,
|
|
|
|
nsIFrame* aPrevInFlow) {
|
2015-03-03 14:08:59 +03:00
|
|
|
NS_ASSERTION(aContent->IsSVGElement(nsGkAtoms::radialGradient),
|
2013-01-08 07:22:41 +04:00
|
|
|
"Content is not an SVG radialGradient");
|
2009-01-19 21:31:34 +03:00
|
|
|
|
2016-04-18 10:19:21 +03:00
|
|
|
nsSVGGradientFrame::Init(aContent, aParent, aPrevInFlow);
|
2009-01-19 21:31:34 +03:00
|
|
|
}
|
|
|
|
#endif /* DEBUG */
|
|
|
|
|
2012-08-22 19:56:38 +04:00
|
|
|
nsresult nsSVGRadialGradientFrame::AttributeChanged(int32_t aNameSpaceID,
|
2017-10-03 01:05:19 +03:00
|
|
|
nsAtom* aAttribute,
|
2012-08-22 19:56:38 +04:00
|
|
|
int32_t aModType) {
|
2006-03-07 03:04:59 +03:00
|
|
|
if (aNameSpaceID == kNameSpaceID_None &&
|
|
|
|
(aAttribute == nsGkAtoms::r || aAttribute == nsGkAtoms::cx ||
|
|
|
|
aAttribute == nsGkAtoms::cy || aAttribute == nsGkAtoms::fx ||
|
|
|
|
aAttribute == nsGkAtoms::fy)) {
|
2017-08-30 17:58:31 +03:00
|
|
|
SVGObserverUtils::InvalidateDirectRenderingObservers(this);
|
2006-01-19 02:50:40 +03:00
|
|
|
}
|
2004-10-15 03:02:53 +04:00
|
|
|
|
2006-03-07 03:04:59 +03:00
|
|
|
return nsSVGGradientFrame::AttributeChanged(aNameSpaceID, aAttribute,
|
|
|
|
aModType);
|
|
|
|
}
|
2004-10-15 03:02:53 +04:00
|
|
|
|
|
|
|
//----------------------------------------------------------------------
|
|
|
|
|
2012-08-22 19:56:38 +04:00
|
|
|
float nsSVGRadialGradientFrame::GetLengthValue(uint32_t aIndex) {
|
2013-01-11 12:43:01 +04:00
|
|
|
dom::SVGRadialGradientElement* lengthElement = GetRadialGradientWithLength(
|
2017-08-27 01:58:38 +03:00
|
|
|
aIndex, static_cast<dom::SVGRadialGradientElement*>(GetContent()));
|
2012-03-06 10:58:40 +04:00
|
|
|
// We passed in mContent as a fallback, so, assuming mContent is non-null,
|
|
|
|
// the return value should also be non-null.
|
2015-02-10 01:34:50 +03:00
|
|
|
MOZ_ASSERT(lengthElement,
|
2012-03-06 10:58:40 +04:00
|
|
|
"Got unexpected null element from GetRadialGradientWithLength");
|
|
|
|
return GetLengthValueFromElement(aIndex, *lengthElement);
|
|
|
|
}
|
|
|
|
|
2012-08-22 19:56:38 +04:00
|
|
|
float nsSVGRadialGradientFrame::GetLengthValue(uint32_t aIndex,
|
|
|
|
float aDefaultValue) {
|
2013-01-11 12:43:01 +04:00
|
|
|
dom::SVGRadialGradientElement* lengthElement =
|
2012-07-30 18:20:58 +04:00
|
|
|
GetRadialGradientWithLength(aIndex, nullptr);
|
2006-03-28 04:33:22 +04:00
|
|
|
|
2012-03-06 10:58:40 +04:00
|
|
|
return lengthElement ? GetLengthValueFromElement(aIndex, *lengthElement)
|
|
|
|
: aDefaultValue;
|
|
|
|
}
|
|
|
|
|
2012-08-22 19:56:38 +04:00
|
|
|
float nsSVGRadialGradientFrame::GetLengthValueFromElement(
|
2013-01-11 12:43:01 +04:00
|
|
|
uint32_t aIndex, dom::SVGRadialGradientElement& aElement) {
|
2019-04-09 23:04:33 +03:00
|
|
|
const SVGAnimatedLength& length = aElement.mLengthAttributes[aIndex];
|
2006-03-28 04:33:22 +04:00
|
|
|
|
|
|
|
// Object bounding box units are handled by setting the appropriate
|
2007-08-28 03:11:14 +04:00
|
|
|
// transform in GetGradientTransform, but we need to handle user
|
2006-03-28 04:33:22 +04:00
|
|
|
// space units as part of the individual Get* routines. Fixes 323669.
|
|
|
|
|
2012-08-22 19:56:38 +04:00
|
|
|
uint16_t gradientUnits = GetGradientUnits();
|
2013-02-18 06:14:02 +04:00
|
|
|
if (gradientUnits == SVG_UNIT_TYPE_USERSPACEONUSE) {
|
2012-03-06 10:58:40 +04:00
|
|
|
return nsSVGUtils::UserSpace(mSource, &length);
|
2006-01-19 02:50:40 +03:00
|
|
|
}
|
2006-03-28 04:33:22 +04:00
|
|
|
|
2013-02-18 06:14:02 +04:00
|
|
|
NS_ASSERTION(gradientUnits == SVG_UNIT_TYPE_OBJECTBOUNDINGBOX,
|
2012-03-06 10:58:40 +04:00
|
|
|
"Unknown gradientUnits type");
|
2006-03-28 04:33:22 +04:00
|
|
|
|
2017-08-21 11:19:31 +03:00
|
|
|
return length.GetAnimValue(static_cast<SVGViewportElement*>(nullptr));
|
2005-03-09 22:24:18 +03:00
|
|
|
}
|
|
|
|
|
2013-01-11 12:43:01 +04:00
|
|
|
dom::SVGRadialGradientElement*
|
2012-08-22 19:56:38 +04:00
|
|
|
nsSVGRadialGradientFrame::GetRadialGradientWithLength(
|
2013-01-11 12:43:01 +04:00
|
|
|
uint32_t aIndex, dom::SVGRadialGradientElement* aDefault) {
|
|
|
|
dom::SVGRadialGradientElement* thisElement =
|
2017-08-27 01:58:38 +03:00
|
|
|
static_cast<dom::SVGRadialGradientElement*>(GetContent());
|
2019-04-09 23:04:33 +03:00
|
|
|
const SVGAnimatedLength& length = thisElement->mLengthAttributes[aIndex];
|
2006-05-16 19:55:01 +04:00
|
|
|
|
2012-03-06 10:58:40 +04:00
|
|
|
if (length.IsExplicitlySet()) {
|
|
|
|
return thisElement;
|
|
|
|
}
|
2006-03-28 04:33:22 +04:00
|
|
|
|
2016-04-18 10:19:21 +03:00
|
|
|
return nsSVGGradientFrame::GetRadialGradientWithLength(aIndex, aDefault);
|
2012-03-06 10:58:40 +04:00
|
|
|
}
|
2006-03-28 04:33:22 +04:00
|
|
|
|
2013-05-27 11:34:01 +04:00
|
|
|
bool nsSVGRadialGradientFrame::GradientVectorLengthIsZero() {
|
|
|
|
return GetLengthValue(dom::SVGRadialGradientElement::ATTR_R) == 0;
|
2012-10-06 16:52:32 +04:00
|
|
|
}
|
|
|
|
|
2012-03-06 10:58:40 +04:00
|
|
|
already_AddRefed<gfxPattern> nsSVGRadialGradientFrame::CreateGradient() {
|
2017-05-23 09:15:02 +03:00
|
|
|
float cx, cy, r, fx, fy, fr;
|
2006-03-28 04:33:22 +04:00
|
|
|
|
2013-01-11 12:43:01 +04:00
|
|
|
cx = GetLengthValue(dom::SVGRadialGradientElement::ATTR_CX);
|
|
|
|
cy = GetLengthValue(dom::SVGRadialGradientElement::ATTR_CY);
|
|
|
|
r = GetLengthValue(dom::SVGRadialGradientElement::ATTR_R);
|
2012-03-06 10:58:40 +04:00
|
|
|
// If fx or fy are not set, use cx/cy instead
|
2013-01-11 12:43:01 +04:00
|
|
|
fx = GetLengthValue(dom::SVGRadialGradientElement::ATTR_FX, cx);
|
|
|
|
fy = GetLengthValue(dom::SVGRadialGradientElement::ATTR_FY, cy);
|
2017-05-23 09:15:02 +03:00
|
|
|
fr = GetLengthValue(dom::SVGRadialGradientElement::ATTR_FR);
|
2006-05-16 19:55:01 +04:00
|
|
|
|
|
|
|
if (fx != cx || fy != cy) {
|
|
|
|
// The focal point (fFx and fFy) must be clamped to be *inside* - not on -
|
|
|
|
// the circumference of the gradient or we'll get rendering anomalies. We
|
|
|
|
// calculate the distance from the focal point to the gradient center and
|
2010-07-01 00:24:53 +04:00
|
|
|
// make sure it is *less* than the gradient radius.
|
|
|
|
// 1/128 is the limit of the fractional part of cairo's 24.8 fixed point
|
|
|
|
// representation divided by 2 to ensure that we get different cairo
|
|
|
|
// fractions
|
2013-01-15 16:22:03 +04:00
|
|
|
double dMax = std::max(0.0, r - 1.0 / 128);
|
2006-05-16 19:55:01 +04:00
|
|
|
float dx = fx - cx;
|
|
|
|
float dy = fy - cy;
|
|
|
|
double d = sqrt((dx * dx) + (dy * dy));
|
|
|
|
if (d > dMax) {
|
|
|
|
double angle = atan2(dy, dx);
|
|
|
|
fx = (float)(dMax * cos(angle)) + cx;
|
|
|
|
fy = (float)(dMax * sin(angle)) + cy;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-05-23 09:15:02 +03:00
|
|
|
RefPtr<gfxPattern> pattern = new gfxPattern(fx, fy, fr, cx, cy, r);
|
2013-04-22 15:15:59 +04:00
|
|
|
return pattern.forget();
|
2004-10-15 03:02:53 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
// -------------------------------------------------------------------------
|
|
|
|
// Public functions
|
|
|
|
// -------------------------------------------------------------------------
|
|
|
|
|
2006-03-27 01:30:36 +04:00
|
|
|
nsIFrame* NS_NewSVGLinearGradientFrame(nsIPresShell* aPresShell,
|
2018-03-22 21:20:41 +03:00
|
|
|
ComputedStyle* aStyle) {
|
2019-02-05 19:45:54 +03:00
|
|
|
return new (aPresShell)
|
|
|
|
nsSVGLinearGradientFrame(aStyle, aPresShell->GetPresContext());
|
2004-10-15 03:02:53 +04:00
|
|
|
}
|
|
|
|
|
2009-09-12 20:49:24 +04:00
|
|
|
NS_IMPL_FRAMEARENA_HELPERS(nsSVGLinearGradientFrame)
|
|
|
|
|
2006-03-27 01:30:36 +04:00
|
|
|
nsIFrame* NS_NewSVGRadialGradientFrame(nsIPresShell* aPresShell,
|
2018-03-22 21:20:41 +03:00
|
|
|
ComputedStyle* aStyle) {
|
2019-02-05 19:45:54 +03:00
|
|
|
return new (aPresShell)
|
|
|
|
nsSVGRadialGradientFrame(aStyle, aPresShell->GetPresContext());
|
2004-10-15 03:02:53 +04:00
|
|
|
}
|
2009-09-12 20:49:24 +04:00
|
|
|
|
|
|
|
NS_IMPL_FRAMEARENA_HELPERS(nsSVGRadialGradientFrame)
|