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:
cku 2016-10-11 13:12:00 +08:00
Родитель a31601cee7
Коммит faa1874701
3 изменённых файлов: 140 добавлений и 84 удалений

Просмотреть файл

@ -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_*/