mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-09 03:15:11 +00:00
Bug 1299715 - Part 6. Move ComputeMaskGeometry from nsSVGIntegrationUtils to nsDisplayMask. r=mstange
MozReview-Commit-ID: 4uLfaGDXGyE --HG-- extra : rebase_source : 136a87f3b23578d6a3a2cf95474463edb6a53708
This commit is contained in:
parent
a31601cee7
commit
faa1874701
@ -80,6 +80,7 @@
|
||||
#include "nsCSSProps.h"
|
||||
#include "nsPluginFrame.h"
|
||||
#include "DisplayItemScrollClip.h"
|
||||
#include "nsSVGMaskFrame.h"
|
||||
|
||||
// GetCurrentTime is defined in winbase.h as zero argument macro forwarding to
|
||||
// GetTickCount().
|
||||
@ -6826,6 +6827,127 @@ bool nsDisplaySVGEffects::ValidateSVGFrame()
|
||||
return true;
|
||||
}
|
||||
|
||||
static IntRect
|
||||
ComputeClipExtsInDeviceSpace(gfxContext& aCtx)
|
||||
{
|
||||
gfxContextMatrixAutoSaveRestore matRestore(&aCtx);
|
||||
|
||||
// Get the clip extents in device space.
|
||||
aCtx.SetMatrix(gfxMatrix());
|
||||
gfxRect clippedFrameSurfaceRect = aCtx.GetClipExtents();
|
||||
clippedFrameSurfaceRect.RoundOut();
|
||||
|
||||
IntRect result;
|
||||
ToRect(clippedFrameSurfaceRect).ToIntRect(&result);
|
||||
return mozilla::gfx::Factory::CheckSurfaceSize(result.Size()) ? result
|
||||
: IntRect();
|
||||
}
|
||||
|
||||
typedef nsSVGIntegrationUtils::PaintFramesParams PaintFramesParams;
|
||||
|
||||
static nsPoint
|
||||
ComputeOffsetToUserSpace(const PaintFramesParams& aParams)
|
||||
{
|
||||
nsIFrame* frame = aParams.frame;
|
||||
nsPoint offsetToBoundingBox = aParams.builder->ToReferenceFrame(frame) -
|
||||
nsSVGIntegrationUtils::GetOffsetToBoundingBox(frame);
|
||||
if (!frame->IsFrameOfType(nsIFrame::eSVG)) {
|
||||
// Snap the offset if the reference frame is not a SVG frame, since other
|
||||
// frames will be snapped to pixel when rendering.
|
||||
offsetToBoundingBox = nsPoint(
|
||||
frame->PresContext()->RoundAppUnitsToNearestDevPixels(offsetToBoundingBox.x),
|
||||
frame->PresContext()->RoundAppUnitsToNearestDevPixels(offsetToBoundingBox.y));
|
||||
}
|
||||
|
||||
// After applying only "offsetToBoundingBox", aParams.ctx would have its
|
||||
// origin at the top left corner of frame's bounding box (over all
|
||||
// continuations).
|
||||
// However, SVG painting needs the origin to be located at the origin of the
|
||||
// SVG frame's "user space", i.e. the space in which, for example, the
|
||||
// frame's BBox lives.
|
||||
// SVG geometry frames and foreignObject frames apply their own offsets, so
|
||||
// their position is relative to their user space. So for these frame types,
|
||||
// if we want aCtx to be in user space, we first need to subtract the
|
||||
// frame's position so that SVG painting can later add it again and the
|
||||
// frame is painted in the right place.
|
||||
gfxPoint toUserSpaceGfx = nsSVGUtils::FrameSpaceInCSSPxToUserSpaceOffset(frame);
|
||||
nsPoint toUserSpace =
|
||||
nsPoint(nsPresContext::CSSPixelsToAppUnits(float(toUserSpaceGfx.x)),
|
||||
nsPresContext::CSSPixelsToAppUnits(float(toUserSpaceGfx.y)));
|
||||
|
||||
return (offsetToBoundingBox - toUserSpace);
|
||||
}
|
||||
|
||||
static void
|
||||
ComputeMaskGeometry(PaintFramesParams& aParams)
|
||||
{
|
||||
// Properties are added lazily and may have been removed by a restyle, so
|
||||
// make sure all applicable ones are set again.
|
||||
nsIFrame* firstFrame =
|
||||
nsLayoutUtils::FirstContinuationOrIBSplitSibling(aParams.frame);
|
||||
|
||||
const nsStyleSVGReset *svgReset = firstFrame->StyleSVGReset();
|
||||
|
||||
nsSVGEffects::EffectProperties effectProperties =
|
||||
nsSVGEffects::GetEffectProperties(firstFrame);
|
||||
nsTArray<nsSVGMaskFrame *> maskFrames = effectProperties.GetMaskFrames();
|
||||
|
||||
if (maskFrames.Length() == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
gfxContext& ctx = aParams.ctx;
|
||||
nsIFrame* frame = aParams.frame;
|
||||
|
||||
nsPoint offsetToUserSpace = ComputeOffsetToUserSpace(aParams);
|
||||
gfxPoint devPixelOffsetToUserSpace =
|
||||
nsLayoutUtils::PointToGfxPoint(offsetToUserSpace,
|
||||
frame->PresContext()->AppUnitsPerDevPixel());
|
||||
|
||||
gfxContextMatrixAutoSaveRestore matSR(&ctx);
|
||||
ctx.SetMatrix(ctx.CurrentMatrix().Translate(devPixelOffsetToUserSpace));
|
||||
|
||||
// Convert boaderArea and dirtyRect to user space.
|
||||
int32_t appUnitsPerDevPixel = frame->PresContext()->AppUnitsPerDevPixel();
|
||||
nsRect userSpaceBorderArea = aParams.borderArea - offsetToUserSpace;
|
||||
nsRect userSpaceDirtyRect = aParams.dirtyRect - offsetToUserSpace;
|
||||
|
||||
// Union all mask layer rectangles in user space.
|
||||
gfxRect maskInUserSpace;
|
||||
for (size_t i = 0; i < maskFrames.Length() ; i++) {
|
||||
nsSVGMaskFrame* maskFrame = maskFrames[i];
|
||||
gfxRect currentMaskSurfaceRect;
|
||||
|
||||
if (maskFrame) {
|
||||
currentMaskSurfaceRect = maskFrame->GetMaskArea(aParams.frame);
|
||||
} else {
|
||||
nsCSSRendering::ImageLayerClipState clipState;
|
||||
nsCSSRendering::GetImageLayerClip(svgReset->mMask.mLayers[i],
|
||||
frame,
|
||||
*frame->StyleBorder(),
|
||||
userSpaceBorderArea,
|
||||
userSpaceDirtyRect,
|
||||
false, /* aWillPaintBorder */
|
||||
appUnitsPerDevPixel,
|
||||
&clipState);
|
||||
currentMaskSurfaceRect = clipState.mDirtyRectGfx;
|
||||
}
|
||||
|
||||
maskInUserSpace = maskInUserSpace.Union(currentMaskSurfaceRect);
|
||||
}
|
||||
|
||||
ctx.Save();
|
||||
|
||||
if (!maskInUserSpace.IsEmpty()) {
|
||||
ctx.Clip(maskInUserSpace);
|
||||
}
|
||||
|
||||
IntRect result = ComputeClipExtsInDeviceSpace(ctx);
|
||||
ctx.Restore();
|
||||
|
||||
aParams.maskRect = result;
|
||||
}
|
||||
|
||||
nsDisplayMask::nsDisplayMask(nsDisplayListBuilder* aBuilder,
|
||||
nsIFrame* aFrame, nsDisplayList* aList,
|
||||
bool aHandleOpacity,
|
||||
@ -6945,6 +7067,8 @@ nsDisplayMask::PaintAsLayer(nsDisplayListBuilder* aBuilder,
|
||||
mFrame->PresContext()->AppUnitsPerDevPixel(),
|
||||
*aCtx->GetDrawTarget()));
|
||||
|
||||
ComputeMaskGeometry(params);
|
||||
|
||||
image::DrawResult result =
|
||||
nsSVGIntegrationUtils::PaintMaskAndClipPath(params);
|
||||
|
||||
|
@ -168,10 +168,8 @@ nsSVGIntegrationUtils::UsingMaskOrClipPathForFrame(const nsIFrame* aFrame)
|
||||
style->mMask.HasLayerWithImage();
|
||||
}
|
||||
|
||||
// For non-SVG frames, this gives the offset to the frame's "user space".
|
||||
// For SVG frames, this returns a zero offset.
|
||||
static nsPoint
|
||||
GetOffsetToBoundingBox(nsIFrame* aFrame)
|
||||
nsPoint
|
||||
nsSVGIntegrationUtils::GetOffsetToBoundingBox(nsIFrame* aFrame)
|
||||
{
|
||||
if ((aFrame->GetStateBits() & NS_FRAME_SVG_LAYOUT)) {
|
||||
// Do NOT call GetAllInFlowRectsUnion for SVG - it will get the
|
||||
@ -413,83 +411,8 @@ private:
|
||||
nsPoint mOffset;
|
||||
};
|
||||
|
||||
static IntRect
|
||||
ComputeClipExtsInDeviceSpace(gfxContext& aCtx)
|
||||
{
|
||||
gfxContextMatrixAutoSaveRestore matRestore(&aCtx);
|
||||
|
||||
// Get the clip extents in device space.
|
||||
aCtx.SetMatrix(gfxMatrix());
|
||||
gfxRect clippedFrameSurfaceRect = aCtx.GetClipExtents();
|
||||
clippedFrameSurfaceRect.RoundOut();
|
||||
|
||||
IntRect result;
|
||||
ToRect(clippedFrameSurfaceRect).ToIntRect(&result);
|
||||
return mozilla::gfx::Factory::CheckSurfaceSize(result.Size()) ? result
|
||||
: IntRect();
|
||||
}
|
||||
|
||||
typedef nsSVGIntegrationUtils::PaintFramesParams PaintFramesParams;
|
||||
|
||||
static IntRect
|
||||
ComputeMaskGeometry(const PaintFramesParams& aParams,
|
||||
const nsStyleSVGReset *svgReset,
|
||||
const nsPoint& aOffsetToUserSpace,
|
||||
const nsTArray<nsSVGMaskFrame *>& aMaskFrames)
|
||||
{
|
||||
gfxContext& ctx = aParams.ctx;
|
||||
nsIFrame* frame = aParams.frame;
|
||||
|
||||
// Convert boaderArea and dirtyRect to user space.
|
||||
int32_t appUnitsPerDevPixel = frame->PresContext()->AppUnitsPerDevPixel();
|
||||
nsRect userSpaceBorderArea = aParams.borderArea - aOffsetToUserSpace;
|
||||
nsRect userSpaceDirtyRect = aParams.dirtyRect - aOffsetToUserSpace;
|
||||
|
||||
// Union all mask layer rectangles in user space.
|
||||
gfxRect maskInUserSpace;
|
||||
for (size_t i = 0; i < aMaskFrames.Length() ; i++) {
|
||||
nsSVGMaskFrame* maskFrame = aMaskFrames[i];
|
||||
gfxRect currentMaskSurfaceRect;
|
||||
|
||||
if (maskFrame) {
|
||||
currentMaskSurfaceRect = maskFrame->GetMaskArea(aParams.frame);
|
||||
} else {
|
||||
nsCSSRendering::ImageLayerClipState clipState;
|
||||
nsCSSRendering::GetImageLayerClip(svgReset->mMask.mLayers[i],
|
||||
frame,
|
||||
*frame->StyleBorder(),
|
||||
userSpaceBorderArea,
|
||||
userSpaceDirtyRect,
|
||||
false, /* aWillPaintBorder */
|
||||
appUnitsPerDevPixel,
|
||||
&clipState);
|
||||
currentMaskSurfaceRect = clipState.mDirtyRectGfx;
|
||||
}
|
||||
|
||||
maskInUserSpace = maskInUserSpace.Union(currentMaskSurfaceRect);
|
||||
}
|
||||
|
||||
ctx.Save();
|
||||
|
||||
// Clip ctx by both frame's visual overflow rect and mask union.
|
||||
gfxRect frameVisualOverflowRect =
|
||||
nsLayoutUtils::RectToGfxRect(frame->GetVisualOverflowRectRelativeToSelf(),
|
||||
appUnitsPerDevPixel);
|
||||
ctx.Clip(frameVisualOverflowRect);
|
||||
// maskInUserSpace might be empty if all mask references are not resolvable
|
||||
// or the size of them are empty. We still need to create a transparent mask
|
||||
// before bug 1276834 fixed, so don't clip ctx by an empty rectangle for for
|
||||
// now.
|
||||
if (!maskInUserSpace.IsEmpty()) {
|
||||
ctx.Clip(maskInUserSpace);
|
||||
}
|
||||
|
||||
IntRect result = ComputeClipExtsInDeviceSpace(ctx);
|
||||
ctx.Restore();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static DrawResult
|
||||
GenerateMaskSurface(const PaintFramesParams& aParams,
|
||||
float aOpacity, nsStyleContext* aSC,
|
||||
@ -518,9 +441,7 @@ GenerateMaskSurface(const PaintFramesParams& aParams,
|
||||
return DrawResult::SUCCESS;
|
||||
}
|
||||
|
||||
IntRect maskSurfaceRect = ComputeMaskGeometry(aParams, svgReset,
|
||||
aOffsetToUserSpace,
|
||||
aMaskFrames);
|
||||
const IntRect& maskSurfaceRect = aParams.maskRect;
|
||||
if (maskSurfaceRect.IsEmpty()) {
|
||||
return DrawResult::SUCCESS;
|
||||
}
|
||||
@ -687,7 +608,7 @@ SetupContextMatrix(nsIFrame* aFrame, const PaintFramesParams& aParams,
|
||||
bool aClipCtx)
|
||||
{
|
||||
aOffsetToBoundingBox = aParams.builder->ToReferenceFrame(aFrame) -
|
||||
GetOffsetToBoundingBox(aFrame);
|
||||
nsSVGIntegrationUtils::GetOffsetToBoundingBox(aFrame);
|
||||
if (!aFrame->IsFrameOfType(nsIFrame::eSVG)) {
|
||||
/* Snap the offset if the reference frame is not a SVG frame,
|
||||
* since other frames will be snapped to pixel when rendering. */
|
||||
@ -1046,7 +967,7 @@ PaintFrameCallback::operator()(gfxContext* aContext,
|
||||
// to have it anchored at the top left corner of the bounding box of all of
|
||||
// mFrame's continuations. So we add a translation transform.
|
||||
int32_t appUnitsPerDevPixel = mFrame->PresContext()->AppUnitsPerDevPixel();
|
||||
nsPoint offset = GetOffsetToBoundingBox(mFrame);
|
||||
nsPoint offset = nsSVGIntegrationUtils::GetOffsetToBoundingBox(mFrame);
|
||||
gfxPoint devPxOffset = gfxPoint(offset.x, offset.y) / appUnitsPerDevPixel;
|
||||
aContext->Multiply(gfxMatrix::Translation(devPxOffset));
|
||||
|
||||
|
@ -9,6 +9,7 @@
|
||||
#include "gfxMatrix.h"
|
||||
#include "gfxRect.h"
|
||||
#include "nsRegionFwd.h"
|
||||
#include "mozilla/gfx/Rect.h"
|
||||
|
||||
class gfxContext;
|
||||
class gfxDrawable;
|
||||
@ -37,6 +38,7 @@ struct nsSize;
|
||||
class nsSVGIntegrationUtils final
|
||||
{
|
||||
typedef mozilla::gfx::DrawTarget DrawTarget;
|
||||
typedef mozilla::gfx::IntRect IntRect;
|
||||
typedef mozilla::image::DrawResult DrawResult;
|
||||
|
||||
public:
|
||||
@ -138,6 +140,8 @@ public:
|
||||
mozilla::layers::LayerManager* layerManager;
|
||||
bool handleOpacity; // If true, PaintMaskAndClipPath/ PaintFilter should
|
||||
// apply css opacity.
|
||||
IntRect maskRect;
|
||||
|
||||
explicit PaintFramesParams(gfxContext& aCtx, nsIFrame* aFrame,
|
||||
const nsRect& aDirtyRect,
|
||||
const nsRect& aBorderArea,
|
||||
@ -202,6 +206,13 @@ public:
|
||||
const DrawTarget* aDrawTarget,
|
||||
const gfxMatrix& aContextMatrix,
|
||||
uint32_t aFlags);
|
||||
|
||||
/**
|
||||
* For non-SVG frames, this gives the offset to the frame's "user space".
|
||||
* For SVG frames, this returns a zero offset.
|
||||
*/
|
||||
static nsPoint
|
||||
GetOffsetToBoundingBox(nsIFrame* aFrame);
|
||||
};
|
||||
|
||||
#endif /*NSSVGINTEGRATIONUTILS_H_*/
|
||||
|
Loading…
Reference in New Issue
Block a user