зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1304011 - Part 3. Add clip function in SetupContextMatrix, and give a frame to this function as the source of offset computing. r=mstange
MozReview-Commit-ID: 2ry6c1cECvb --HG-- extra : rebase_source : 54fc13e3948179ec543b0c7f4c8cf342108992fd
This commit is contained in:
Родитель
22ac005328
Коммит
07e41f0497
|
@ -180,11 +180,6 @@ GetOffsetToBoundingBox(nsIFrame* aFrame)
|
|||
// no offset adjustment to make.
|
||||
return nsPoint();
|
||||
}
|
||||
// We could allow aFrame to be any continuation, but since that would require
|
||||
// a GetPrevContinuation() virtual call and conditional returns, and since
|
||||
// all our current consumers always pass in the first continuation, we don't
|
||||
// currently bother.
|
||||
NS_ASSERTION(!aFrame->GetPrevContinuation(), "Not first continuation");
|
||||
|
||||
// The GetAllInFlowRectsUnion() call gets the union of the frame border-box
|
||||
// rects over all continuations, relative to the origin (top-left of the
|
||||
|
@ -657,24 +652,32 @@ ValidateSVGFrame(const PaintFramesParams& aParams, bool aHasSVGLayout,
|
|||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Setup transform matrix of a gfx context by a specific frame. Depend on
|
||||
* aClipCtx, this function may clip that context by the visual overflow area
|
||||
* of aFrame.
|
||||
*
|
||||
* @param aFrame is the target frame.
|
||||
* @param aOffsetToBoundingBox returns the offset between the reference frame
|
||||
* and the bounding box of aFrame.
|
||||
* @oaram aOffsetToUserSpace returns the offset between the reference frame and
|
||||
* the user space coordinate of aFrame.
|
||||
* @param aClipCtx indicate whether clip aParams.ctx by visual overflow rect of
|
||||
* aFrame or not.
|
||||
*/
|
||||
static void
|
||||
SetupContextMatrix(const PaintFramesParams& aParams,
|
||||
nsPoint& aOffsetToBoundingBox,
|
||||
nsPoint& aToUserSpace,
|
||||
nsPoint& aOffsetToUserSpace)
|
||||
SetupContextMatrix(nsIFrame* aFrame, const PaintFramesParams& aParams,
|
||||
nsPoint& aOffsetToBoundingBox, nsPoint& aOffsetToUserSpace,
|
||||
bool aClipCtx)
|
||||
{
|
||||
nsIFrame* frame = aParams.frame;
|
||||
nsIFrame* firstFrame =
|
||||
nsLayoutUtils::FirstContinuationOrIBSplitSibling(frame);
|
||||
|
||||
nsPoint firstFrameOffset = GetOffsetToBoundingBox(firstFrame);
|
||||
aOffsetToBoundingBox = aParams.builder->ToReferenceFrame(firstFrame) - firstFrameOffset;
|
||||
if (!firstFrame->IsFrameOfType(nsIFrame::eSVG)) {
|
||||
aOffsetToBoundingBox = aParams.builder->ToReferenceFrame(aFrame) -
|
||||
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. */
|
||||
aOffsetToBoundingBox = nsPoint(
|
||||
frame->PresContext()->RoundAppUnitsToNearestDevPixels(aOffsetToBoundingBox.x),
|
||||
frame->PresContext()->RoundAppUnitsToNearestDevPixels(aOffsetToBoundingBox.y));
|
||||
aFrame->PresContext()->RoundAppUnitsToNearestDevPixels(aOffsetToBoundingBox.x),
|
||||
aFrame->PresContext()->RoundAppUnitsToNearestDevPixels(aOffsetToBoundingBox.y));
|
||||
}
|
||||
|
||||
// After applying only "aOffsetToBoundingBox", aCtx would have its origin at
|
||||
|
@ -688,23 +691,32 @@ SetupContextMatrix(const PaintFramesParams& aParams,
|
|||
// 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);
|
||||
aToUserSpace =
|
||||
gfxPoint toUserSpaceGfx = nsSVGUtils::FrameSpaceInCSSPxToUserSpaceOffset(aFrame);
|
||||
nsPoint toUserSpace =
|
||||
nsPoint(nsPresContext::CSSPixelsToAppUnits(float(toUserSpaceGfx.x)),
|
||||
nsPresContext::CSSPixelsToAppUnits(float(toUserSpaceGfx.y)));
|
||||
|
||||
aOffsetToUserSpace = aOffsetToBoundingBox - aToUserSpace;
|
||||
aOffsetToUserSpace = aOffsetToBoundingBox - toUserSpace;
|
||||
|
||||
#ifdef DEBUG
|
||||
bool hasSVGLayout = (frame->GetStateBits() & NS_FRAME_SVG_LAYOUT);
|
||||
bool hasSVGLayout = (aFrame->GetStateBits() & NS_FRAME_SVG_LAYOUT);
|
||||
NS_ASSERTION(hasSVGLayout || aOffsetToBoundingBox == aOffsetToUserSpace,
|
||||
"For non-SVG frames there shouldn't be any additional offset");
|
||||
#endif
|
||||
|
||||
gfxPoint devPixelOffsetToUserSpace =
|
||||
nsLayoutUtils::PointToGfxPoint(aOffsetToUserSpace,
|
||||
frame->PresContext()->AppUnitsPerDevPixel());
|
||||
aParams.ctx.SetMatrix(aParams.ctx.CurrentMatrix().Translate(devPixelOffsetToUserSpace));
|
||||
aFrame->PresContext()->AppUnitsPerDevPixel());
|
||||
gfxContext& context = aParams.ctx;
|
||||
context.SetMatrix(context.CurrentMatrix().Translate(devPixelOffsetToUserSpace));
|
||||
|
||||
if (aClipCtx) {
|
||||
nsRect clipRect =
|
||||
aParams.frame->GetVisualOverflowRectRelativeToSelf() + toUserSpace;
|
||||
context.Clip(NSRectToSnappedRect(clipRect,
|
||||
aFrame->PresContext()->AppUnitsPerDevPixel(),
|
||||
*context.GetDrawTarget()));
|
||||
}
|
||||
}
|
||||
|
||||
static already_AddRefed<gfxContext>
|
||||
|
@ -783,11 +795,6 @@ nsSVGIntegrationUtils::PaintMaskAndClipPath(const PaintFramesParams& aParams)
|
|||
|
||||
gfxContext& context = aParams.ctx;
|
||||
gfxContextMatrixAutoSaveRestore matrixAutoSaveRestore(&context);
|
||||
nsPoint offsetToBoundingBox;
|
||||
nsPoint toUserSpace;
|
||||
nsPoint offsetToUserSpace;
|
||||
SetupContextMatrix(aParams, offsetToBoundingBox, toUserSpace,
|
||||
offsetToUserSpace);
|
||||
|
||||
/* Properties are added lazily and may have been removed by a restyle,
|
||||
so make sure all applicable ones are set again. */
|
||||
|
@ -831,12 +838,23 @@ nsSVGIntegrationUtils::PaintMaskAndClipPath(const PaintFramesParams& aParams)
|
|||
MOZ_ASSERT_IF(shouldGenerateClipMaskLayer,
|
||||
!shouldApplyClipPath && !shouldApplyBasicShape);
|
||||
|
||||
nsPoint offsetToBoundingBox;
|
||||
nsPoint offsetToUserSpace;
|
||||
|
||||
// These are used if we require a temporary surface for a custom blend mode.
|
||||
// Clip the source context first, so that we can generate a smaller temporary
|
||||
// surface. (Since we will clip this context in SetupContextMatrix, a pair
|
||||
// of save/restore is needed.)
|
||||
context.Save();
|
||||
SetupContextMatrix(firstFrame, aParams, offsetToBoundingBox,
|
||||
offsetToUserSpace, true);
|
||||
IntPoint targetOffset;
|
||||
RefPtr<gfxContext> target =
|
||||
(aParams.frame->StyleEffects()->mMixBlendMode == NS_STYLE_BLEND_NORMAL)
|
||||
? RefPtr<gfxContext>(&aParams.ctx).forget()
|
||||
: CreateBlendTarget(aParams, targetOffset);
|
||||
context.Restore();
|
||||
|
||||
if (!target) {
|
||||
return DrawResult::TEMPORARY_ERROR;
|
||||
}
|
||||
|
@ -847,12 +865,9 @@ nsSVGIntegrationUtils::PaintMaskAndClipPath(const PaintFramesParams& aParams)
|
|||
/* Check if we need to do additional operations on this child's
|
||||
* rendering, which necessitates rendering into another surface. */
|
||||
if (shouldGenerateMask) {
|
||||
context.Save();
|
||||
nsRect clipRect =
|
||||
frame->GetVisualOverflowRectRelativeToSelf() + toUserSpace;
|
||||
context.Clip(NSRectToSnappedRect(clipRect,
|
||||
frame->PresContext()->AppUnitsPerDevPixel(),
|
||||
*context.GetDrawTarget()));
|
||||
gfxContextMatrixAutoSaveRestore save(&context);
|
||||
SetupContextMatrix(firstFrame, aParams, offsetToBoundingBox,
|
||||
offsetToUserSpace, true);
|
||||
Matrix maskTransform;
|
||||
RefPtr<SourceSurface> maskSurface;
|
||||
if (shouldGenerateMaskLayer) {
|
||||
|
@ -864,7 +879,6 @@ nsSVGIntegrationUtils::PaintMaskAndClipPath(const PaintFramesParams& aParams)
|
|||
|
||||
if (shouldGenerateMaskLayer && !maskSurface) {
|
||||
// Entire surface is clipped out.
|
||||
context.Restore();
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -880,6 +894,8 @@ nsSVGIntegrationUtils::PaintMaskAndClipPath(const PaintFramesParams& aParams)
|
|||
maskTransform = clippedMaskTransform;
|
||||
}
|
||||
}
|
||||
// Pop the clip pushed in SetupContextMatrix.
|
||||
context.PopClip();
|
||||
|
||||
target->PushGroupForBlendBack(gfxContentType::COLOR_ALPHA, opacity, maskSurface, maskTransform);
|
||||
}
|
||||
|
@ -887,12 +903,17 @@ nsSVGIntegrationUtils::PaintMaskAndClipPath(const PaintFramesParams& aParams)
|
|||
/* If this frame has only a trivial clipPath, set up cairo's clipping now so
|
||||
* we can just do normal painting and get it clipped appropriately.
|
||||
*/
|
||||
if (shouldApplyClipPath) {
|
||||
if (shouldApplyClipPath || shouldApplyBasicShape) {
|
||||
context.Save();
|
||||
clipPathFrame->ApplyClipPath(context, frame, cssPxToDevPxMatrix);
|
||||
} else if (shouldApplyBasicShape) {
|
||||
context.Save();
|
||||
nsCSSClipPathInstance::ApplyBasicShapeClip(context, frame);
|
||||
SetupContextMatrix(firstFrame, aParams, offsetToBoundingBox,
|
||||
offsetToUserSpace, false);
|
||||
|
||||
MOZ_ASSERT(!shouldApplyClipPath || !shouldApplyBasicShape);
|
||||
if (shouldApplyClipPath) {
|
||||
clipPathFrame->ApplyClipPath(context, frame, cssPxToDevPxMatrix);
|
||||
} else {
|
||||
nsCSSClipPathInstance::ApplyBasicShapeClip(context, frame);
|
||||
}
|
||||
}
|
||||
|
||||
/* Paint the child */
|
||||
|
@ -910,7 +931,6 @@ nsSVGIntegrationUtils::PaintMaskAndClipPath(const PaintFramesParams& aParams)
|
|||
|
||||
if (shouldGenerateMask) {
|
||||
target->PopGroupAndBlend();
|
||||
context.Restore();
|
||||
}
|
||||
|
||||
if (aParams.frame->StyleEffects()->mMixBlendMode != NS_STYLE_BLEND_NORMAL) {
|
||||
|
@ -941,14 +961,6 @@ nsSVGIntegrationUtils::PaintFilter(const PaintFramesParams& aParams)
|
|||
return DrawResult::SUCCESS;
|
||||
}
|
||||
|
||||
gfxContext& context = aParams.ctx;
|
||||
gfxContextMatrixAutoSaveRestore matrixAutoSaveRestore(&context);
|
||||
nsPoint offsetToBoundingBox;
|
||||
nsPoint toUserSpace;
|
||||
nsPoint offsetToUserSpace;
|
||||
SetupContextMatrix(aParams, offsetToBoundingBox, toUserSpace,
|
||||
offsetToUserSpace);
|
||||
|
||||
/* Properties are added lazily and may have been removed by a restyle,
|
||||
so make sure all applicable ones are set again. */
|
||||
nsIFrame* firstFrame =
|
||||
|
@ -960,24 +972,28 @@ nsSVGIntegrationUtils::PaintFilter(const PaintFramesParams& aParams)
|
|||
return DrawResult::NOT_READY;
|
||||
}
|
||||
|
||||
gfxContext& context = aParams.ctx;
|
||||
nsPoint offsetToBoundingBox;
|
||||
nsPoint offsetToUserSpace;
|
||||
|
||||
// These are used if we require a temporary surface for a custom blend mode.
|
||||
// Clip the source context first, so that we can generate a smaller temporary
|
||||
// surface. (Since we will clip this context in SetupContextMatrix, a pair
|
||||
// of save/restore is needed.)
|
||||
context.Save();
|
||||
SetupContextMatrix(firstFrame, aParams, offsetToBoundingBox,
|
||||
offsetToUserSpace, true);
|
||||
IntPoint targetOffset;
|
||||
RefPtr<gfxContext> target =
|
||||
(aParams.frame->StyleEffects()->mMixBlendMode == NS_STYLE_BLEND_NORMAL)
|
||||
? RefPtr<gfxContext>(&aParams.ctx).forget()
|
||||
: CreateBlendTarget(aParams, targetOffset);
|
||||
if (!target) {
|
||||
context.Restore();
|
||||
return DrawResult::TEMPORARY_ERROR;
|
||||
}
|
||||
|
||||
if (opacity != 1.0f) {
|
||||
context.Save();
|
||||
nsRect clipRect =
|
||||
frame->GetVisualOverflowRectRelativeToSelf() + toUserSpace;
|
||||
context.Clip(NSRectToSnappedRect(clipRect,
|
||||
frame->PresContext()->AppUnitsPerDevPixel(),
|
||||
*context.GetDrawTarget()));
|
||||
|
||||
target->PushGroupForBlendBack(gfxContentType::COLOR_ALPHA, opacity,
|
||||
nullptr, Matrix());
|
||||
}
|
||||
|
@ -992,7 +1008,6 @@ nsSVGIntegrationUtils::PaintFilter(const PaintFramesParams& aParams)
|
|||
|
||||
if (opacity != 1.0f) {
|
||||
target->PopGroupAndBlend();
|
||||
context.Restore();
|
||||
}
|
||||
|
||||
if (aParams.frame->StyleEffects()->mMixBlendMode != NS_STYLE_BLEND_NORMAL) {
|
||||
|
@ -1000,6 +1015,7 @@ nsSVGIntegrationUtils::PaintFilter(const PaintFramesParams& aParams)
|
|||
BlendToTarget(aParams, target, targetOffset);
|
||||
}
|
||||
|
||||
context.Restore();
|
||||
return result;
|
||||
}
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче