Beispiel #1
0
nsresult
nsSVGClipPathFrame::ClipPaint(nsSVGRenderState* aContext,
                              nsISVGChildFrame* aParent,
                              nsIDOMSVGMatrix *aMatrix)
{
  // If the flag is set when we get here, it means this clipPath frame
  // has already been used painting the current clip, and the document
  // has a clip reference loop.
  if (mInUse) {
    NS_WARNING("Clip loop detected!");
    return NS_OK;
  }
  AutoClipPathReferencer clipRef(this);

  mClipParent = aParent,
  mClipParentMatrix = aMatrix;

  PRBool isTrivial = IsTrivial();

  nsAutoSVGRenderMode mode(aContext,
                           isTrivial ? nsSVGRenderState::CLIP
                                     : nsSVGRenderState::CLIP_MASK);

  for (nsIFrame* kid = mFrames.FirstChild(); kid;
       kid = kid->GetNextSibling()) {
    nsISVGChildFrame* SVGFrame = nsnull;
    CallQueryInterface(kid, &SVGFrame);
    if (SVGFrame) {
      // The CTM of each frame referencing us can be different.
      SVGFrame->NotifySVGChanged(nsISVGChildFrame::SUPPRESS_INVALIDATION | 
                                 nsISVGChildFrame::TRANSFORM_CHANGED);
      SVGFrame->PaintSVG(aContext, nsnull);
    }
  }

  if (isTrivial) {
    aContext->GetGfxContext()->Clip();
    aContext->GetGfxContext()->NewPath();
  }

  return NS_OK;
}
bool
nsSVGClipPathFrame::ClipHitTest(nsIFrame* aParent,
                                const gfxMatrix &aMatrix,
                                const nsPoint &aPoint)
{
    // If the flag is set when we get here, it means this clipPath frame
    // has already been used in hit testing against the current clip,
    // and the document has a clip reference loop.
    if (mInUse) {
        NS_WARNING("Clip loop detected!");
        return false;
    }
    AutoClipPathReferencer clipRef(this);

    mClipParent = aParent;
    if (mClipParentMatrix) {
        *mClipParentMatrix = aMatrix;
    } else {
        mClipParentMatrix = new gfxMatrix(aMatrix);
    }

    nsSVGClipPathFrame *clipPathFrame =
        nsSVGEffects::GetEffectProperties(this).GetClipPathFrame(nsnull);
    if (clipPathFrame && !clipPathFrame->ClipHitTest(aParent, aMatrix, aPoint))
        return false;

    for (nsIFrame* kid = mFrames.FirstChild(); kid;
            kid = kid->GetNextSibling()) {
        nsISVGChildFrame* SVGFrame = do_QueryFrame(kid);
        if (SVGFrame) {
            // Notify the child frame that we may be working with a
            // different transform, so it can update its covered region
            // (used to shortcut hit testing).
            SVGFrame->NotifySVGChanged(nsISVGChildFrame::TRANSFORM_CHANGED);

            if (SVGFrame->GetFrameForPoint(aPoint))
                return true;
        }
    }
    return false;
}
bool
nsSVGClipPathFrame::IsValid()
{
    if (mInUse) {
        NS_WARNING("Clip loop detected!");
        return false;
    }
    AutoClipPathReferencer clipRef(this);

    bool isOK = true;
    nsSVGEffects::GetEffectProperties(this).GetClipPathFrame(&isOK);
    if (!isOK) {
        return false;
    }

    for (nsIFrame* kid = mFrames.FirstChild(); kid;
            kid = kid->GetNextSibling()) {

        nsIAtom *type = kid->GetType();

        if (type == nsGkAtoms::svgUseFrame) {
            for (nsIFrame* grandKid = kid->GetFirstPrincipalChild(); grandKid;
                    grandKid = grandKid->GetNextSibling()) {

                nsIAtom *type = grandKid->GetType();

                if (type != nsGkAtoms::svgPathGeometryFrame &&
                        type != nsGkAtoms::svgTextFrame) {
                    return false;
                }
            }
            continue;
        }
        if (type != nsGkAtoms::svgPathGeometryFrame &&
                type != nsGkAtoms::svgTextFrame) {
            return false;
        }
    }
    return true;
}
Beispiel #4
0
PRBool
nsSVGClipPathFrame::ClipHitTest(nsISVGChildFrame* aParent,
                                nsIDOMSVGMatrix *aMatrix,
                                float aX, float aY)
{
  // If the flag is set when we get here, it means this clipPath frame
  // has already been used in hit testing against the current clip,
  // and the document has a clip reference loop.
  if (mInUse) {
    NS_WARNING("Clip loop detected!");
    return PR_FALSE;
  }
  AutoClipPathReferencer clipRef(this);

  nsRect dirty;
  mClipParent = aParent,
  mClipParentMatrix = aMatrix;

  for (nsIFrame* kid = mFrames.FirstChild(); kid;
       kid = kid->GetNextSibling()) {
    nsISVGChildFrame* SVGFrame = nsnull;
    CallQueryInterface(kid, &SVGFrame);
    if (SVGFrame) {
      // Notify the child frame that we may be working with a
      // different transform, so it can update its covered region
      // (used to shortcut hit testing).
      SVGFrame->NotifySVGChanged(nsISVGChildFrame::TRANSFORM_CHANGED);

      nsIFrame *temp = nsnull;
      nsresult rv = SVGFrame->GetFrameForPointSVG(aX, aY, &temp);
      if (NS_SUCCEEDED(rv) && temp)
        return PR_TRUE;
    }
  }
  return PR_FALSE;
}
nsresult
nsSVGClipPathFrame::ClipPaint(nsSVGRenderState* aContext,
                              nsIFrame* aParent,
                              const gfxMatrix &aMatrix)
{
    // If the flag is set when we get here, it means this clipPath frame
    // has already been used painting the current clip, and the document
    // has a clip reference loop.
    if (mInUse) {
        NS_WARNING("Clip loop detected!");
        return NS_OK;
    }
    AutoClipPathReferencer clipRef(this);

    mClipParent = aParent;
    if (mClipParentMatrix) {
        *mClipParentMatrix = aMatrix;
    } else {
        mClipParentMatrix = new gfxMatrix(aMatrix);
    }

    bool isTrivial = IsTrivial();

    nsAutoSVGRenderMode mode(aContext,
                             isTrivial ? nsSVGRenderState::CLIP
                             : nsSVGRenderState::CLIP_MASK);


    gfxContext *gfx = aContext->GetGfxContext();

    nsSVGClipPathFrame *clipPathFrame =
        nsSVGEffects::GetEffectProperties(this).GetClipPathFrame(nsnull);
    bool referencedClipIsTrivial;
    if (clipPathFrame) {
        referencedClipIsTrivial = clipPathFrame->IsTrivial();
        gfx->Save();
        if (referencedClipIsTrivial) {
            clipPathFrame->ClipPaint(aContext, aParent, aMatrix);
        } else {
            gfx->PushGroup(gfxASurface::CONTENT_ALPHA);
        }
    }

    for (nsIFrame* kid = mFrames.FirstChild(); kid;
            kid = kid->GetNextSibling()) {
        nsISVGChildFrame* SVGFrame = do_QueryFrame(kid);
        if (SVGFrame) {
            // The CTM of each frame referencing us can be different.
            SVGFrame->NotifySVGChanged(nsISVGChildFrame::SUPPRESS_INVALIDATION |
                                       nsISVGChildFrame::TRANSFORM_CHANGED);

            bool isOK = true;
            nsSVGClipPathFrame *clipPathFrame =
                nsSVGEffects::GetEffectProperties(kid).GetClipPathFrame(&isOK);
            if (!isOK) {
                continue;
            }

            bool isTrivial;

            if (clipPathFrame) {
                isTrivial = clipPathFrame->IsTrivial();
                gfx->Save();
                if (isTrivial) {
                    clipPathFrame->ClipPaint(aContext, aParent, aMatrix);
                } else {
                    gfx->PushGroup(gfxASurface::CONTENT_ALPHA);
                }
            }

            SVGFrame->PaintSVG(aContext, nsnull);

            if (clipPathFrame) {
                if (!isTrivial) {
                    gfx->PopGroupToSource();

                    nsRefPtr<gfxPattern> clipMaskSurface;
                    gfx->PushGroup(gfxASurface::CONTENT_ALPHA);

                    clipPathFrame->ClipPaint(aContext, aParent, aMatrix);
                    clipMaskSurface = gfx->PopGroup();

                    if (clipMaskSurface) {
                        gfx->Mask(clipMaskSurface);
                    }
                }
                gfx->Restore();
            }
        }
    }

    if (clipPathFrame) {
        if (!referencedClipIsTrivial) {
            gfx->PopGroupToSource();

            nsRefPtr<gfxPattern> clipMaskSurface;
            gfx->PushGroup(gfxASurface::CONTENT_ALPHA);

            clipPathFrame->ClipPaint(aContext, aParent, aMatrix);
            clipMaskSurface = gfx->PopGroup();

            if (clipMaskSurface) {
                gfx->Mask(clipMaskSurface);
            }
        }
        gfx->Restore();
    }

    if (isTrivial) {
        gfx->Clip();
        gfx->NewPath();
    }

    return NS_OK;
}
nsresult
nsSVGClipPathFrame::ClipPaint(nsRenderingContext* aContext,
                              nsIFrame* aParent,
                              const gfxMatrix &aMatrix)
{
  // If the flag is set when we get here, it means this clipPath frame
  // has already been used painting the current clip, and the document
  // has a clip reference loop.
  if (mInUse) {
    NS_WARNING("Clip loop detected!");
    return NS_OK;
  }
  AutoClipPathReferencer clipRef(this);

  mClipParent = aParent;
  if (mClipParentMatrix) {
    *mClipParentMatrix = aMatrix;
  } else {
    mClipParentMatrix = new gfxMatrix(aMatrix);
  }

  gfxContext *gfx = aContext->ThebesContext();

  nsISVGChildFrame *singleClipPathChild = nsnull;

  if (IsTrivial(&singleClipPathChild)) {
    // Notify our child that it's painting as part of a clipPath, and that
    // we only require it to draw its path (it should skip filling, etc.):
    SVGAutoRenderState mode(aContext, SVGAutoRenderState::CLIP);

    if (!singleClipPathChild) {
      // We have no children - the spec says clip away everything:
      gfx->Rectangle(gfxRect());
    } else {
      singleClipPathChild->NotifySVGChanged(
                             nsISVGChildFrame::DO_NOT_NOTIFY_RENDERING_OBSERVERS | 
                             nsISVGChildFrame::TRANSFORM_CHANGED);
      singleClipPathChild->PaintSVG(aContext, nsnull);
    }
    gfx->Clip();
    gfx->NewPath();
    return NS_OK;
  }

  // Seems like this is a non-trivial clipPath, so we need to use a clip mask.

  // Notify our children that they're painting into a clip mask:
  SVGAutoRenderState mode(aContext, SVGAutoRenderState::CLIP_MASK);

  // Check if this clipPath is itself clipped by another clipPath:
  nsSVGClipPathFrame *clipPathFrame =
    nsSVGEffects::GetEffectProperties(this).GetClipPathFrame(nsnull);
  bool referencedClipIsTrivial;
  if (clipPathFrame) {
    referencedClipIsTrivial = clipPathFrame->IsTrivial();
    gfx->Save();
    if (referencedClipIsTrivial) {
      clipPathFrame->ClipPaint(aContext, aParent, aMatrix);
    } else {
      gfx->PushGroup(gfxASurface::CONTENT_ALPHA);
    }
  }

  for (nsIFrame* kid = mFrames.FirstChild(); kid;
       kid = kid->GetNextSibling()) {
    nsISVGChildFrame* SVGFrame = do_QueryFrame(kid);
    if (SVGFrame) {
      // The CTM of each frame referencing us can be different.
      SVGFrame->NotifySVGChanged(
                          nsISVGChildFrame::DO_NOT_NOTIFY_RENDERING_OBSERVERS | 
                          nsISVGChildFrame::TRANSFORM_CHANGED);

      bool isOK = true;
      nsSVGClipPathFrame *clipPathFrame =
        nsSVGEffects::GetEffectProperties(kid).GetClipPathFrame(&isOK);
      if (!isOK) {
        continue;
      }

      bool isTrivial;

      if (clipPathFrame) {
        isTrivial = clipPathFrame->IsTrivial();
        gfx->Save();
        if (isTrivial) {
          clipPathFrame->ClipPaint(aContext, aParent, aMatrix);
        } else {
          gfx->PushGroup(gfxASurface::CONTENT_ALPHA);
        }
      }

      SVGFrame->PaintSVG(aContext, nsnull);

      if (clipPathFrame) {
        if (!isTrivial) {
          gfx->PopGroupToSource();

          nsRefPtr<gfxPattern> clipMaskSurface;
          gfx->PushGroup(gfxASurface::CONTENT_ALPHA);

          clipPathFrame->ClipPaint(aContext, aParent, aMatrix);
          clipMaskSurface = gfx->PopGroup();

          if (clipMaskSurface) {
            gfx->Mask(clipMaskSurface);
          }
        }
        gfx->Restore();
      }
    }
  }

  if (clipPathFrame) {
    if (!referencedClipIsTrivial) {
      gfx->PopGroupToSource();

      nsRefPtr<gfxPattern> clipMaskSurface;
      gfx->PushGroup(gfxASurface::CONTENT_ALPHA);

      clipPathFrame->ClipPaint(aContext, aParent, aMatrix);
      clipMaskSurface = gfx->PopGroup();

      if (clipMaskSurface) {
        gfx->Mask(clipMaskSurface);
      }
    }
    gfx->Restore();
  }

  return NS_OK;
}