Ejemplo n.º 1
0
DrawResult
nsSVGClipPathFrame::PaintFrameIntoMask(nsIFrame *aFrame,
                                       nsIFrame* aClippedFrame,
                                       gfxContext& aTarget,
                                       const gfxMatrix& aMatrix)
{
    nsISVGChildFrame* frame = do_QueryFrame(aFrame);
    if (!frame) {
        return DrawResult::SUCCESS;
    }

    // The CTM of each frame referencing us can be different.
    frame->NotifySVGChanged(nsISVGChildFrame::TRANSFORM_CHANGED);

    // Children of this clipPath may themselves be clipped.
    nsSVGEffects::EffectProperties effectProperties =
        nsSVGEffects::GetEffectProperties(aFrame);
    if (effectProperties.HasInvalidClipPath()) {
        return DrawResult::SUCCESS;
    }
    nsSVGClipPathFrame *clipPathThatClipsChild =
        effectProperties.GetClipPathFrame();

    nsSVGUtils::MaskUsage maskUsage;
    nsSVGUtils::DetermineMaskUsage(aFrame, true, maskUsage);
    DrawResult result = DrawResult::SUCCESS;
    if (maskUsage.shouldApplyClipPath) {
        clipPathThatClipsChild->ApplyClipPath(aTarget, aClippedFrame, aMatrix);
    } else if (maskUsage.shouldGenerateClipMaskLayer) {
        Matrix maskTransform;
        RefPtr<SourceSurface> maskSurface;
        Tie(result, maskSurface) =
            clipPathThatClipsChild->GetClipMask(aTarget, aClippedFrame,
                                                aMatrix, &maskTransform);
        aTarget.PushGroupForBlendBack(gfxContentType::ALPHA, 1.0,
                                      maskSurface, maskTransform);
        // The corresponding PopGroupAndBlend call below will mask the
        // blend using |maskSurface|.
    }

    gfxMatrix toChildsUserSpace = mMatrixForChildren;
    nsIFrame* child = do_QueryFrame(frame);
    nsIContent* childContent = child->GetContent();
    if (childContent->IsSVGElement()) {
        toChildsUserSpace =
            static_cast<const nsSVGElement*>(childContent)->
            PrependLocalTransformsTo(mMatrixForChildren, eUserSpaceToParent);
    }

    // Our children have NS_STATE_SVG_CLIPPATH_CHILD set on them, and
    // SVGGeometryFrame::Render checks for that state bit and paints
    // only the geometry (opaque black) if set.
    result &= frame->PaintSVG(aTarget, toChildsUserSpace);

    if (maskUsage.shouldGenerateClipMaskLayer) {
        aTarget.PopGroupAndBlend();
    } else if (maskUsage.shouldApplyClipPath) {
        aTarget.PopClip();
    }

    return result;
}
Ejemplo n.º 2
0
DrawResult
nsSVGClipPathFrame::PaintClipMask(gfxContext& aMaskContext,
                                  nsIFrame* aClippedFrame,
                                  const gfxMatrix& aMatrix,
                                  Matrix* aMaskTransform,
                                  SourceSurface* aExtraMask,
                                  const Matrix& aExtraMasksTransform)
{
    // A clipPath can reference another clipPath.  We re-enter this method for
    // each clipPath in a reference chain, so here we limit chain length:
    static int16_t sRefChainLengthCounter = AutoReferenceLimiter::notReferencing;
    AutoReferenceLimiter
    refChainLengthLimiter(&sRefChainLengthCounter,
                          MAX_SVG_CLIP_PATH_REFERENCE_CHAIN_LENGTH);
    if (!refChainLengthLimiter.Reference()) {
        return DrawResult::SUCCESS; // Reference chain is too long!
    }

    // And to prevent reference loops we check that this clipPath only appears
    // once in the reference chain (if any) that we're currently processing:
    AutoReferenceLimiter refLoopDetector(&mReferencing, 1);
    if (!refLoopDetector.Reference()) {
        return DrawResult::SUCCESS; // Reference loop!
    }

    DrawResult result = DrawResult::SUCCESS;
    DrawTarget* maskDT = aMaskContext.GetDrawTarget();
    MOZ_ASSERT(maskDT->GetFormat() == SurfaceFormat::A8);

    // Paint this clipPath's contents into aMaskDT:
    // We need to set mMatrixForChildren here so that under the PaintSVG calls
    // on our children (below) our GetCanvasTM() method will return the correct
    // transform.
    mMatrixForChildren = GetClipPathTransform(aClippedFrame) * aMatrix;

    // Check if this clipPath is itself clipped by another clipPath:
    nsSVGClipPathFrame* clipPathThatClipsClipPath =
        nsSVGEffects::GetEffectProperties(this).GetClipPathFrame();
    nsSVGUtils::MaskUsage maskUsage;
    nsSVGUtils::DetermineMaskUsage(this, true, maskUsage);

    if (maskUsage.shouldApplyClipPath) {
        clipPathThatClipsClipPath->ApplyClipPath(aMaskContext, aClippedFrame,
                aMatrix);
    } else if (maskUsage.shouldGenerateClipMaskLayer) {
        Matrix maskTransform;
        RefPtr<SourceSurface> maskSurface;
        Tie(result, maskSurface) =
            clipPathThatClipsClipPath->GetClipMask(aMaskContext, aClippedFrame,
                    aMatrix, &maskTransform);
        aMaskContext.PushGroupForBlendBack(gfxContentType::ALPHA, 1.0,
                                           maskSurface, maskTransform);
        // The corresponding PopGroupAndBlend call below will mask the
        // blend using |maskSurface|.
    }

    // Paint our children into the mask:
    for (nsIFrame* kid = mFrames.FirstChild(); kid;
            kid = kid->GetNextSibling()) {
        result &= PaintFrameIntoMask(kid, aClippedFrame, aMaskContext, aMatrix);
    }

    if (maskUsage.shouldGenerateClipMaskLayer) {
        aMaskContext.PopGroupAndBlend();
    } else if (maskUsage.shouldApplyClipPath) {
        aMaskContext.PopClip();
    }

    // Moz2D transforms in the opposite direction to Thebes
    gfxMatrix maskTransfrom = aMaskContext.CurrentMatrix();
    maskTransfrom.Invert();

    if (aExtraMask) {
        ComposeExtraMask(maskDT, maskTransfrom, aExtraMask, aExtraMasksTransform);
    }

    *aMaskTransform = ToMatrix(maskTransfrom);
    return result;
}