/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* vim: set ts=8 sts=2 et sw=2 tw=80: */ /* 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/. */
// 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
gfxMatrix SVGPatternFrame::GetCanvasTM() { if (mCTM) { return *mCTM;
}
// Do we know our rendering parent? if (mSource) { // Yes, use it! return mSource->GetCanvasTM();
}
// We get here when geometry in the <pattern> container is updated return gfxMatrix();
}
/** Calculate the maximum expansion of a matrix */ staticfloat MaxExpansion(const Matrix& aMatrix) { // 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));
}
// The SVG specification says that the 'patternContentUnits' attribute "has no // effect if attribute ‘viewBox’ is specified". We still need to include a bbox // 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 staticbool IncludeBBoxScale(const SVGAnimatedViewBox& aViewBox,
uint32_t aPatternContentUnits,
uint32_t aPatternUnits) { return (!aViewBox.IsExplicitlySet() &&
aPatternContentUnits == SVG_UNIT_TYPE_OBJECTBOUNDINGBOX) ||
(aViewBox.IsExplicitlySet() &&
aPatternUnits == SVG_UNIT_TYPE_OBJECTBOUNDINGBOX);
}
// Given the matrix for the pattern element's own transform, this returns a // combined matrix including the transforms applicable to its target. static Matrix GetPatternMatrix(nsIFrame* aSource, const StyleSVGPaint nsStyleSVG::*aFillOrStroke,
uint16_t aPatternUnits, const gfxMatrix& patternTransform, const gfxRect& bbox, const gfxRect& callerBBox, const Matrix& callerCTM) { // We really want the pattern matrix to handle translations
gfxFloat minx = bbox.X();
gfxFloat miny = bbox.Y();
// revert the vector effect transform so that the pattern appears unchanged if (aFillOrStroke == &nsStyleSVG::mStroke) {
gfxMatrix userToOuterSVG; if (SVGUtils::GetNonScalingStrokeTransform(aSource, &userToOuterSVG)) {
patternMatrix *= userToOuterSVG;
}
}
// OK, now fix up the bounding box to reflect user coordinates // We handle device unit scaling in pattern matrix float scale = MaxExpansion(aContextMatrix); if (scale <= 0) { return NS_ERROR_FAILURE;
}
aBBox->Scale(scale); return NS_OK;
}
if (aGraphicOpacity != 1.0f) {
autoGroupForBlend.PushGroupForBlendBack(gfxContentType::COLOR_ALPHA,
aGraphicOpacity);
}
// 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
if (aSource->IsSVGGeometryFrame()) { // Set the geometrical parent of the pattern we are rendering
aPatternWithChildren->mSource = static_cast<SVGGeometryFrame*>(aSource);
}
// Delay checking NS_FRAME_DRAWING_AS_PAINTSERVER bit until here so we can // give back a clear surface if there's a loop if (!aPatternWithChildren->HasAnyStateBits(NS_FRAME_DRAWING_AS_PAINTSERVER)) {
AutoSetRestorePaintServerState paintServer(aPatternWithChildren); for (auto* kid : aPatternWithChildren->mFrames) {
gfxMatrix tm = *(aPatternWithChildren->mCTM);
// The CTM of each frame referencing us can be different
ISVGDisplayableFrame* SVGFrame = do_QueryFrame(kid); if (SVGFrame) {
SVGFrame->NotifySVGChanged(ISVGDisplayableFrame::TRANSFORM_CHANGED);
tm = SVGUtils::GetTransformMatrixInUserSpace(kid) * tm;
}
already_AddRefed<SourceSurface> SVGPatternFrame::PaintPattern( const DrawTarget* aDrawTarget, Matrix* patternMatrix, const Matrix& aContextMatrix, nsIFrame* aSource,
StyleSVGPaint nsStyleSVG::*aFillOrStroke, float aGraphicOpacity, const gfxRect* aOverrideBounds, imgDrawingParams& aImgParams) { /* * 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
*/
SVGPatternFrame* patternWithChildren = GetPatternWithChildren(); if (!patternWithChildren) { // Either no kids or a bad reference return nullptr;
}
/* * 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. * * 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.
*/
// Get all of the information we need from our "caller" -- i.e. // the geometry that is being rendered with a pattern
gfxRect callerBBox; if (NS_FAILED(GetTargetGeometry(&callerBBox, viewBox, patternContentUnits,
patternUnits, aSource, aContextMatrix,
aOverrideBounds))) { return nullptr;
}
// Construct the CTM that we will provide to our children when we // render them into the tile.
gfxMatrix ctm = ConstructCTM(viewBox, patternContentUnits, patternUnits,
callerBBox, aContextMatrix, aSource); if (ctm.IsSingular()) { return nullptr;
}
// 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.
gfxRect bbox =
GetPatternRect(patternUnits, callerBBox, aContextMatrix, aSource); if (bbox.Width() <= 0.0 || bbox.Height() <= 0.0) { return nullptr;
}
// Get the pattern transform auto patternTransform = GetPatternTransform();
// Get the transformation matrix that we will hand to the renderer's pattern // routine.
*patternMatrix =
GetPatternMatrix(aSource, aFillOrStroke, patternUnits, patternTransform,
bbox, callerBBox, aContextMatrix); if (patternMatrix->IsSingular()) { return nullptr;
}
// Now that we have all of the necessary geometries, we can // create our surface.
gfxSize scaledSize = bbox.Size() * MaxExpansion(ToMatrix(patternTransform));
// caller now owns the surface return dt->GetBackingSurface();
}
/* 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?
SVGPatternFrame* SVGPatternFrame::GetPatternWithChildren() { // Do we have any children ourselves? if (!mFrames.IsEmpty()) { returnthis;
}
// No, see if we chain to someone who does
// 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;
}
SVGPatternFrame* next = GetReferencedPattern(); if (!next) { return nullptr;
}
if (thisEnum.IsExplicitlySet()) { return thisEnum.GetAnimValue();
}
// 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 returnstatic_cast<SVGPatternElement*>(aDefault)
->mEnumAttributes[aIndex]
.GetAnimValue();
}
SVGPatternFrame* next = GetReferencedPattern(); return next ? next->GetEnumValue(aIndex, aDefault)
: static_cast<SVGPatternElement*>(aDefault)
->mEnumAttributes[aIndex]
.GetAnimValue();
}
SVGPatternFrame* SVGPatternFrame::GetPatternTransformFrame(
SVGPatternFrame* aDefault) { if (!StyleDisplay()->mTransform.IsNone()) { returnthis;
}
// 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;
}
if (SVGPatternFrame* next = GetReferencedPattern()) { return next->GetPatternTransformFrame(aDefault);
} return aDefault;
}
if (thisViewBox.IsExplicitlySet()) { return thisViewBox;
}
// 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 returnstatic_cast<SVGPatternElement*>(aDefault)->mViewBox;
}
SVGPatternFrame* next = GetReferencedPattern(); return next ? next->GetViewBox(aDefault)
: static_cast<SVGPatternElement*>(aDefault)->mViewBox;
}
if (thisPar.IsExplicitlySet()) { return thisPar;
}
// 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 returnstatic_cast<SVGPatternElement*>(aDefault)->mPreserveAspectRatio;
}
SVGPatternFrame* next = GetReferencedPattern(); return next ? next->GetPreserveAspectRatio(aDefault)
: static_cast<SVGPatternElement*>(aDefault)->mPreserveAspectRatio;
}
// We don't call SVGObserverUtils::RemoveTemplateObserver and set // `mNoHRefURI = false` on failure since we want to be invalidated if the ID // specified by our href starts resolving to a different/valid element.
float viewportWidth, viewportHeight; if (targetContent->IsSVGElement()) { // 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 = GetLengthValue(SVGPatternElement::ATTR_WIDTH)
->GetAnimValueWithZoom(ctx);
viewportHeight = GetLengthValue(SVGPatternElement::ATTR_HEIGHT)
->GetAnimValueWithZoom(ctx);
} else { // No SVG target, call the nsIFrame* variant of GetAnimValue.
viewportWidth = GetLengthValue(SVGPatternElement::ATTR_WIDTH)
->GetAnimValueWithZoom(aTarget);
viewportHeight = GetLengthValue(SVGPatternElement::ATTR_HEIGHT)
->GetAnimValueWithZoom(aTarget);
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung ist noch experimentell.