2008-09-10 17:24:16 -07:00
|
|
|
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
2012-05-21 04:12:37 -07:00
|
|
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
2008-09-10 17:24:16 -07:00
|
|
|
|
2012-03-26 04:58:59 -07:00
|
|
|
// Main header first:
|
2008-09-10 17:24:16 -07:00
|
|
|
#include "nsSVGIntegrationUtils.h"
|
|
|
|
|
2012-03-26 04:58:59 -07:00
|
|
|
// Keep others in (case-insensitive) order:
|
|
|
|
#include "gfxDrawable.h"
|
|
|
|
#include "nsDisplayList.h"
|
|
|
|
#include "nsLayoutUtils.h"
|
2012-03-20 05:15:55 -07:00
|
|
|
#include "nsRenderingContext.h"
|
2012-03-26 04:58:59 -07:00
|
|
|
#include "nsSVGClipPathFrame.h"
|
2008-09-10 17:24:16 -07:00
|
|
|
#include "nsSVGEffects.h"
|
2008-09-30 17:51:05 -07:00
|
|
|
#include "nsSVGFilterFrame.h"
|
2012-03-26 04:58:59 -07:00
|
|
|
#include "nsSVGFilterPaintCallback.h"
|
2008-09-30 17:51:05 -07:00
|
|
|
#include "nsSVGMaskFrame.h"
|
2010-08-13 06:32:27 -07:00
|
|
|
#include "nsSVGPaintServerFrame.h"
|
2012-03-26 04:58:59 -07:00
|
|
|
#include "nsSVGUtils.h"
|
2008-09-10 17:24:16 -07:00
|
|
|
|
|
|
|
// ----------------------------------------------------------------------
|
|
|
|
|
2011-09-28 23:19:26 -07:00
|
|
|
bool
|
2008-09-10 17:24:16 -07:00
|
|
|
nsSVGIntegrationUtils::UsingEffectsForFrame(const nsIFrame* aFrame)
|
|
|
|
{
|
2011-06-22 13:07:31 -07:00
|
|
|
if (aFrame->IsFrameOfType(nsIFrame::eSVG)) {
|
2011-10-17 07:59:28 -07:00
|
|
|
return false;
|
2011-06-22 13:07:31 -07:00
|
|
|
}
|
2008-09-10 17:24:16 -07:00
|
|
|
const nsStyleSVGReset *style = aFrame->GetStyleSVGReset();
|
2011-06-22 13:07:31 -07:00
|
|
|
return (style->mFilter || style->mClipPath || style->mMask);
|
2008-09-10 17:24:16 -07:00
|
|
|
}
|
|
|
|
|
2012-06-19 08:28:04 -07:00
|
|
|
/* static */ nsPoint
|
|
|
|
nsSVGIntegrationUtils::GetOffsetToUserSpace(nsIFrame* aFrame)
|
2008-09-10 17:24:16 -07:00
|
|
|
{
|
2012-06-19 08:28:04 -07:00
|
|
|
// 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
|
|
|
|
// border box) of its second argument (here, aFrame, the first continuation).
|
|
|
|
return -nsLayoutUtils::GetAllInFlowRectsUnion(aFrame, aFrame).TopLeft();
|
|
|
|
}
|
|
|
|
|
|
|
|
/* static */ nsSize
|
|
|
|
nsSVGIntegrationUtils::GetContinuationUnionSize(nsIFrame* aNonSVGFrame)
|
|
|
|
{
|
|
|
|
NS_ASSERTION(!aNonSVGFrame->IsFrameOfType(nsIFrame::eSVG),
|
|
|
|
"SVG frames should not get here");
|
|
|
|
nsIFrame* firstFrame =
|
|
|
|
nsLayoutUtils::GetFirstContinuationOrSpecialSibling(aNonSVGFrame);
|
|
|
|
return nsLayoutUtils::GetAllInFlowRectsUnion(firstFrame, firstFrame).Size();
|
|
|
|
}
|
|
|
|
|
|
|
|
/* static */ gfxSize
|
|
|
|
nsSVGIntegrationUtils::GetSVGCoordContextForNonSVGFrame(nsIFrame* aNonSVGFrame)
|
|
|
|
{
|
|
|
|
NS_ASSERTION(!aNonSVGFrame->IsFrameOfType(nsIFrame::eSVG),
|
|
|
|
"SVG frames should not get here");
|
|
|
|
nsIFrame* firstFrame =
|
|
|
|
nsLayoutUtils::GetFirstContinuationOrSpecialSibling(aNonSVGFrame);
|
|
|
|
nsRect r = nsLayoutUtils::GetAllInFlowRectsUnion(firstFrame, firstFrame);
|
|
|
|
nsPresContext* presContext = firstFrame->PresContext();
|
|
|
|
return gfxSize(presContext->AppUnitsToFloatCSSPixels(r.width),
|
|
|
|
presContext->AppUnitsToFloatCSSPixels(r.height));
|
2008-09-10 17:24:16 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
static nsRect
|
|
|
|
GetPreEffectsOverflowRect(nsIFrame* aFrame)
|
|
|
|
{
|
2010-03-28 18:46:55 -07:00
|
|
|
nsRect* r = static_cast<nsRect*>
|
|
|
|
(aFrame->Properties().Get(nsIFrame::PreEffectsBBoxProperty()));
|
2008-09-10 17:24:16 -07:00
|
|
|
if (r)
|
|
|
|
return *r;
|
2010-10-06 21:25:47 -07:00
|
|
|
return aFrame->GetVisualOverflowRect();
|
2008-09-10 17:24:16 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
struct BBoxCollector : public nsLayoutUtils::BoxCallback {
|
|
|
|
nsIFrame* mReferenceFrame;
|
|
|
|
nsIFrame* mCurrentFrame;
|
|
|
|
const nsRect& mCurrentFrameOverflowArea;
|
|
|
|
nsRect mResult;
|
|
|
|
|
|
|
|
BBoxCollector(nsIFrame* aReferenceFrame, nsIFrame* aCurrentFrame,
|
|
|
|
const nsRect& aCurrentFrameOverflowArea)
|
|
|
|
: mReferenceFrame(aReferenceFrame), mCurrentFrame(aCurrentFrame),
|
|
|
|
mCurrentFrameOverflowArea(aCurrentFrameOverflowArea) {}
|
|
|
|
|
|
|
|
virtual void AddBox(nsIFrame* aFrame) {
|
|
|
|
nsRect overflow = aFrame == mCurrentFrame ? mCurrentFrameOverflowArea
|
|
|
|
: GetPreEffectsOverflowRect(aFrame);
|
|
|
|
mResult.UnionRect(mResult, overflow + aFrame->GetOffsetTo(mReferenceFrame));
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
static nsRect
|
2012-06-19 08:28:04 -07:00
|
|
|
GetSVGBBox(nsIFrame* aFirstContinuation,
|
|
|
|
nsIFrame* aCurrentFrame,
|
|
|
|
const nsRect& aCurrentFramesPreEffectsOverflow,
|
|
|
|
const nsPoint& aFirstContinuationToUserSpace)
|
2008-09-10 17:24:16 -07:00
|
|
|
{
|
2012-06-19 08:28:04 -07:00
|
|
|
NS_ASSERTION(!aFirstContinuation->GetPrevContinuation(),
|
2008-09-10 17:24:16 -07:00
|
|
|
"Need first continuation here");
|
2012-06-19 08:28:04 -07:00
|
|
|
// Compute union of all overflow areas relative to aFirstContinuation:
|
|
|
|
BBoxCollector collector(aFirstContinuation, aCurrentFrame,
|
|
|
|
aCurrentFramesPreEffectsOverflow);
|
|
|
|
nsLayoutUtils::GetAllInFlowBoxes(aFirstContinuation, &collector);
|
2008-09-10 17:24:16 -07:00
|
|
|
// Get it into "user space" for non-SVG frames
|
2012-06-19 08:28:04 -07:00
|
|
|
return collector.mResult + aFirstContinuationToUserSpace;
|
2008-09-10 17:24:16 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
nsRect
|
|
|
|
nsSVGIntegrationUtils::ComputeFrameEffectsRect(nsIFrame* aFrame,
|
|
|
|
const nsRect& aOverflowRect)
|
|
|
|
{
|
|
|
|
nsIFrame* firstFrame =
|
|
|
|
nsLayoutUtils::GetFirstContinuationOrSpecialSibling(aFrame);
|
|
|
|
nsSVGEffects::EffectProperties effectProperties =
|
|
|
|
nsSVGEffects::GetEffectProperties(firstFrame);
|
|
|
|
nsSVGFilterFrame *filterFrame = effectProperties.mFilter ?
|
2008-09-30 17:51:05 -07:00
|
|
|
effectProperties.mFilter->GetFilterFrame() : nsnull;
|
2008-09-10 17:24:16 -07:00
|
|
|
if (!filterFrame)
|
|
|
|
return aOverflowRect;
|
|
|
|
|
|
|
|
// XXX this isn't really right. We can't compute the correct filter
|
|
|
|
// bbox until all aFrame's continuations have been reflowed.
|
|
|
|
// but then it's too late to set the overflow areas for the earlier frames.
|
2012-06-19 08:28:04 -07:00
|
|
|
nsPoint firstFrameToUserSpace = GetOffsetToUserSpace(firstFrame);
|
|
|
|
nsRect r = GetSVGBBox(firstFrame, aFrame, aOverflowRect,
|
|
|
|
firstFrameToUserSpace);
|
2008-09-10 17:24:16 -07:00
|
|
|
// r is relative to user space
|
|
|
|
PRUint32 appUnitsPerDevPixel = aFrame->PresContext()->AppUnitsPerDevPixel();
|
2009-05-07 19:31:04 -07:00
|
|
|
nsIntRect p = r.ToOutsidePixels(appUnitsPerDevPixel);
|
2012-06-16 13:23:48 -07:00
|
|
|
p = filterFrame->GetPostFilterBounds(firstFrame, &p);
|
2009-05-07 19:31:04 -07:00
|
|
|
r = p.ToAppUnits(appUnitsPerDevPixel);
|
2008-09-10 17:24:16 -07:00
|
|
|
// Make it relative to aFrame again
|
2012-06-19 08:28:04 -07:00
|
|
|
return r - (aFrame->GetOffsetTo(firstFrame) + firstFrameToUserSpace);
|
2008-09-10 17:24:16 -07:00
|
|
|
}
|
|
|
|
|
Backout 61fd66629c4f, 7c8121f8d3af & 2a2e9cf8fd41 (bug 539356), e31a5e6545d3 (bug 761884), 85fa80bd9792, a284ccb25b83, 2865904db9fc, 34e07b09c426, e9b3d41e0360, cef00ebcd6c8, f943b729ac14 & 783f298401b6 (bug 539356), 330a086f1570 (bug 741682), d80219c8842c (bug 739671), e8c96b4fd4da, 313af486e68d, 0adc41ff56dc, 0cd288a38085, f1d43208825c, 4859876972f3, eec8ef3ebe48, f7f29fcd1845, 6079b229d306, f23c3a7e7ce0, 9824458a41e2 & 6748b5496059 (bug 539356) for mochitest-4 orange & talos regressions on multiple platforms
2012-06-11 02:08:32 -07:00
|
|
|
nsRect
|
2008-09-10 17:24:16 -07:00
|
|
|
nsSVGIntegrationUtils::GetInvalidAreaForChangedSource(nsIFrame* aFrame,
|
Backout 61fd66629c4f, 7c8121f8d3af & 2a2e9cf8fd41 (bug 539356), e31a5e6545d3 (bug 761884), 85fa80bd9792, a284ccb25b83, 2865904db9fc, 34e07b09c426, e9b3d41e0360, cef00ebcd6c8, f943b729ac14 & 783f298401b6 (bug 539356), 330a086f1570 (bug 741682), d80219c8842c (bug 739671), e8c96b4fd4da, 313af486e68d, 0adc41ff56dc, 0cd288a38085, f1d43208825c, 4859876972f3, eec8ef3ebe48, f7f29fcd1845, 6079b229d306, f23c3a7e7ce0, 9824458a41e2 & 6748b5496059 (bug 539356) for mochitest-4 orange & talos regressions on multiple platforms
2012-06-11 02:08:32 -07:00
|
|
|
const nsRect& aInvalidRect)
|
2008-09-10 17:24:16 -07:00
|
|
|
{
|
|
|
|
// Don't bother calling GetEffectProperties; the filter property should
|
|
|
|
// already have been set up during reflow/ComputeFrameEffectsRect
|
|
|
|
nsIFrame* firstFrame =
|
|
|
|
nsLayoutUtils::GetFirstContinuationOrSpecialSibling(aFrame);
|
2008-12-12 00:25:16 -08:00
|
|
|
nsSVGEffects::EffectProperties effectProperties =
|
|
|
|
nsSVGEffects::GetEffectProperties(firstFrame);
|
|
|
|
if (!effectProperties.mFilter)
|
2008-09-10 17:24:16 -07:00
|
|
|
return aInvalidRect;
|
2010-11-09 21:50:29 -08:00
|
|
|
|
2010-11-10 13:18:11 -08:00
|
|
|
nsSVGFilterProperty *prop = nsSVGEffects::GetFilterProperty(firstFrame);
|
2010-11-09 21:50:29 -08:00
|
|
|
if (!prop || !prop->IsInObserverList()) {
|
|
|
|
return aInvalidRect;
|
|
|
|
}
|
|
|
|
|
|
|
|
nsSVGFilterFrame* filterFrame = prop->GetFilterFrame();
|
2008-12-12 00:25:16 -08:00
|
|
|
if (!filterFrame) {
|
|
|
|
// The frame is either not there or not currently available,
|
|
|
|
// perhaps because we're in the middle of tearing stuff down.
|
|
|
|
// Be conservative.
|
Backout 61fd66629c4f, 7c8121f8d3af & 2a2e9cf8fd41 (bug 539356), e31a5e6545d3 (bug 761884), 85fa80bd9792, a284ccb25b83, 2865904db9fc, 34e07b09c426, e9b3d41e0360, cef00ebcd6c8, f943b729ac14 & 783f298401b6 (bug 539356), 330a086f1570 (bug 741682), d80219c8842c (bug 739671), e8c96b4fd4da, 313af486e68d, 0adc41ff56dc, 0cd288a38085, f1d43208825c, 4859876972f3, eec8ef3ebe48, f7f29fcd1845, 6079b229d306, f23c3a7e7ce0, 9824458a41e2 & 6748b5496059 (bug 539356) for mochitest-4 orange & talos regressions on multiple platforms
2012-06-11 02:08:32 -07:00
|
|
|
return aFrame->GetVisualOverflowRect();
|
2008-12-12 00:25:16 -08:00
|
|
|
}
|
2008-09-10 17:24:16 -07:00
|
|
|
|
2012-06-19 08:28:04 -07:00
|
|
|
// Convert aInvalidRect into "user space" in dev pixels:
|
Backout 61fd66629c4f, 7c8121f8d3af & 2a2e9cf8fd41 (bug 539356), e31a5e6545d3 (bug 761884), 85fa80bd9792, a284ccb25b83, 2865904db9fc, 34e07b09c426, e9b3d41e0360, cef00ebcd6c8, f943b729ac14 & 783f298401b6 (bug 539356), 330a086f1570 (bug 741682), d80219c8842c (bug 739671), e8c96b4fd4da, 313af486e68d, 0adc41ff56dc, 0cd288a38085, f1d43208825c, 4859876972f3, eec8ef3ebe48, f7f29fcd1845, 6079b229d306, f23c3a7e7ce0, 9824458a41e2 & 6748b5496059 (bug 539356) for mochitest-4 orange & talos regressions on multiple platforms
2012-06-11 02:08:32 -07:00
|
|
|
PRInt32 appUnitsPerDevPixel = aFrame->PresContext()->AppUnitsPerDevPixel();
|
2012-06-19 08:28:04 -07:00
|
|
|
nsPoint toUserSpace =
|
|
|
|
aFrame->GetOffsetTo(firstFrame) + GetOffsetToUserSpace(firstFrame);
|
|
|
|
nsIntRect preEffectsRect =
|
|
|
|
(aInvalidRect + toUserSpace).ToOutsidePixels(appUnitsPerDevPixel);
|
|
|
|
|
|
|
|
nsIntRect postEffectsRect =
|
|
|
|
filterFrame->GetPostFilterDirtyArea(firstFrame, preEffectsRect);
|
|
|
|
|
|
|
|
// Return result relative to aFrame, rather than "user space":
|
|
|
|
return postEffectsRect.ToAppUnits(appUnitsPerDevPixel) - toUserSpace;
|
2008-09-10 17:24:16 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
nsRect
|
|
|
|
nsSVGIntegrationUtils::GetRequiredSourceForInvalidArea(nsIFrame* aFrame,
|
2012-06-19 08:28:04 -07:00
|
|
|
const nsRect& aDirtyRect)
|
2008-09-10 17:24:16 -07:00
|
|
|
{
|
|
|
|
// Don't bother calling GetEffectProperties; the filter property should
|
|
|
|
// already have been set up during reflow/ComputeFrameEffectsRect
|
|
|
|
nsIFrame* firstFrame =
|
|
|
|
nsLayoutUtils::GetFirstContinuationOrSpecialSibling(aFrame);
|
|
|
|
nsSVGFilterFrame* filterFrame =
|
|
|
|
nsSVGEffects::GetFilterFrame(firstFrame);
|
|
|
|
if (!filterFrame)
|
2012-06-19 08:28:04 -07:00
|
|
|
return aDirtyRect;
|
2008-09-10 17:24:16 -07:00
|
|
|
|
2012-06-19 08:28:04 -07:00
|
|
|
// Convert aDirtyRect into "user space" in dev pixels:
|
2008-09-10 17:24:16 -07:00
|
|
|
PRInt32 appUnitsPerDevPixel = aFrame->PresContext()->AppUnitsPerDevPixel();
|
2012-06-19 08:28:04 -07:00
|
|
|
nsPoint toUserSpace =
|
|
|
|
aFrame->GetOffsetTo(firstFrame) + GetOffsetToUserSpace(firstFrame);
|
|
|
|
nsIntRect postEffectsRect =
|
|
|
|
(aDirtyRect + toUserSpace).ToOutsidePixels(appUnitsPerDevPixel);
|
|
|
|
|
|
|
|
nsIntRect preEffectsRect =
|
|
|
|
filterFrame->GetPreFilterNeededArea(firstFrame, postEffectsRect);
|
|
|
|
|
|
|
|
// Return result relative to aFrame, rather than "user space":
|
|
|
|
return preEffectsRect.ToAppUnits(appUnitsPerDevPixel) - toUserSpace;
|
2008-09-10 17:24:16 -07:00
|
|
|
}
|
|
|
|
|
2011-09-28 23:19:26 -07:00
|
|
|
bool
|
2008-09-10 17:24:16 -07:00
|
|
|
nsSVGIntegrationUtils::HitTestFrameForEffects(nsIFrame* aFrame, const nsPoint& aPt)
|
|
|
|
{
|
|
|
|
nsIFrame* firstFrame =
|
|
|
|
nsLayoutUtils::GetFirstContinuationOrSpecialSibling(aFrame);
|
2012-06-19 08:28:04 -07:00
|
|
|
// Convert aPt to user space:
|
|
|
|
nsPoint toUserSpace =
|
|
|
|
aFrame->GetOffsetTo(firstFrame) + GetOffsetToUserSpace(firstFrame);
|
|
|
|
nsPoint pt = aPt + toUserSpace;
|
2008-09-10 17:24:16 -07:00
|
|
|
return nsSVGUtils::HitTestClip(firstFrame, pt);
|
|
|
|
}
|
|
|
|
|
|
|
|
class RegularFramePaintCallback : public nsSVGFilterPaintCallback
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
RegularFramePaintCallback(nsDisplayListBuilder* aBuilder,
|
Backout 61fd66629c4f, 7c8121f8d3af & 2a2e9cf8fd41 (bug 539356), e31a5e6545d3 (bug 761884), 85fa80bd9792, a284ccb25b83, 2865904db9fc, 34e07b09c426, e9b3d41e0360, cef00ebcd6c8, f943b729ac14 & 783f298401b6 (bug 539356), 330a086f1570 (bug 741682), d80219c8842c (bug 739671), e8c96b4fd4da, 313af486e68d, 0adc41ff56dc, 0cd288a38085, f1d43208825c, 4859876972f3, eec8ef3ebe48, f7f29fcd1845, 6079b229d306, f23c3a7e7ce0, 9824458a41e2 & 6748b5496059 (bug 539356) for mochitest-4 orange & talos regressions on multiple platforms
2012-06-11 02:08:32 -07:00
|
|
|
nsDisplayList* aInnerList,
|
|
|
|
nsIFrame* aFrame,
|
2008-09-10 17:24:16 -07:00
|
|
|
const nsPoint& aOffset)
|
Backout 61fd66629c4f, 7c8121f8d3af & 2a2e9cf8fd41 (bug 539356), e31a5e6545d3 (bug 761884), 85fa80bd9792, a284ccb25b83, 2865904db9fc, 34e07b09c426, e9b3d41e0360, cef00ebcd6c8, f943b729ac14 & 783f298401b6 (bug 539356), 330a086f1570 (bug 741682), d80219c8842c (bug 739671), e8c96b4fd4da, 313af486e68d, 0adc41ff56dc, 0cd288a38085, f1d43208825c, 4859876972f3, eec8ef3ebe48, f7f29fcd1845, 6079b229d306, f23c3a7e7ce0, 9824458a41e2 & 6748b5496059 (bug 539356) for mochitest-4 orange & talos regressions on multiple platforms
2012-06-11 02:08:32 -07:00
|
|
|
: mBuilder(aBuilder), mInnerList(aInnerList), mFrame(aFrame),
|
2010-03-10 12:55:05 -08:00
|
|
|
mOffset(aOffset) {}
|
2008-09-10 17:24:16 -07:00
|
|
|
|
2012-03-02 00:28:59 -08:00
|
|
|
virtual void Paint(nsRenderingContext *aContext, nsIFrame *aTarget,
|
2008-10-16 00:55:10 -07:00
|
|
|
const nsIntRect* aDirtyRect)
|
2008-09-10 17:24:16 -07:00
|
|
|
{
|
2012-03-02 00:28:59 -08:00
|
|
|
nsRenderingContext::AutoPushTranslation push(aContext, -mOffset);
|
Backout 61fd66629c4f, 7c8121f8d3af & 2a2e9cf8fd41 (bug 539356), e31a5e6545d3 (bug 761884), 85fa80bd9792, a284ccb25b83, 2865904db9fc, 34e07b09c426, e9b3d41e0360, cef00ebcd6c8, f943b729ac14 & 783f298401b6 (bug 539356), 330a086f1570 (bug 741682), d80219c8842c (bug 739671), e8c96b4fd4da, 313af486e68d, 0adc41ff56dc, 0cd288a38085, f1d43208825c, 4859876972f3, eec8ef3ebe48, f7f29fcd1845, 6079b229d306, f23c3a7e7ce0, 9824458a41e2 & 6748b5496059 (bug 539356) for mochitest-4 orange & talos regressions on multiple platforms
2012-06-11 02:08:32 -07:00
|
|
|
mInnerList->PaintForFrame(mBuilder, aContext, mFrame, nsDisplayList::PAINT_DEFAULT);
|
2008-09-10 17:24:16 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
nsDisplayListBuilder* mBuilder;
|
Backout 61fd66629c4f, 7c8121f8d3af & 2a2e9cf8fd41 (bug 539356), e31a5e6545d3 (bug 761884), 85fa80bd9792, a284ccb25b83, 2865904db9fc, 34e07b09c426, e9b3d41e0360, cef00ebcd6c8, f943b729ac14 & 783f298401b6 (bug 539356), 330a086f1570 (bug 741682), d80219c8842c (bug 739671), e8c96b4fd4da, 313af486e68d, 0adc41ff56dc, 0cd288a38085, f1d43208825c, 4859876972f3, eec8ef3ebe48, f7f29fcd1845, 6079b229d306, f23c3a7e7ce0, 9824458a41e2 & 6748b5496059 (bug 539356) for mochitest-4 orange & talos regressions on multiple platforms
2012-06-11 02:08:32 -07:00
|
|
|
nsDisplayList* mInnerList;
|
|
|
|
nsIFrame* mFrame;
|
2008-09-10 17:24:16 -07:00
|
|
|
nsPoint mOffset;
|
|
|
|
};
|
|
|
|
|
|
|
|
void
|
2011-04-07 18:04:40 -07:00
|
|
|
nsSVGIntegrationUtils::PaintFramesWithEffects(nsRenderingContext* aCtx,
|
2008-09-10 17:24:16 -07:00
|
|
|
nsIFrame* aEffectsFrame,
|
|
|
|
const nsRect& aDirtyRect,
|
|
|
|
nsDisplayListBuilder* aBuilder,
|
Backout 61fd66629c4f, 7c8121f8d3af & 2a2e9cf8fd41 (bug 539356), e31a5e6545d3 (bug 761884), 85fa80bd9792, a284ccb25b83, 2865904db9fc, 34e07b09c426, e9b3d41e0360, cef00ebcd6c8, f943b729ac14 & 783f298401b6 (bug 539356), 330a086f1570 (bug 741682), d80219c8842c (bug 739671), e8c96b4fd4da, 313af486e68d, 0adc41ff56dc, 0cd288a38085, f1d43208825c, 4859876972f3, eec8ef3ebe48, f7f29fcd1845, 6079b229d306, f23c3a7e7ce0, 9824458a41e2 & 6748b5496059 (bug 539356) for mochitest-4 orange & talos regressions on multiple platforms
2012-06-11 02:08:32 -07:00
|
|
|
nsDisplayList* aInnerList)
|
2008-09-10 17:24:16 -07:00
|
|
|
{
|
|
|
|
#ifdef DEBUG
|
2009-01-12 11:20:59 -08:00
|
|
|
nsISVGChildFrame *svgChildFrame = do_QueryFrame(aEffectsFrame);
|
2009-01-09 08:35:24 -08:00
|
|
|
NS_ASSERTION(!svgChildFrame, "Should never be called on an SVG frame");
|
2009-01-12 11:20:59 -08:00
|
|
|
#endif
|
2008-09-10 17:24:16 -07:00
|
|
|
|
|
|
|
float opacity = aEffectsFrame->GetStyleDisplay()->mOpacity;
|
|
|
|
if (opacity == 0.0f)
|
|
|
|
return;
|
|
|
|
|
|
|
|
/* Properties are added lazily and may have been removed by a restyle,
|
|
|
|
so make sure all applicable ones are set again. */
|
|
|
|
nsIFrame* firstFrame =
|
|
|
|
nsLayoutUtils::GetFirstContinuationOrSpecialSibling(aEffectsFrame);
|
|
|
|
nsSVGEffects::EffectProperties effectProperties =
|
|
|
|
nsSVGEffects::GetEffectProperties(firstFrame);
|
|
|
|
|
|
|
|
/* SVG defines the following rendering model:
|
|
|
|
*
|
|
|
|
* 1. Render geometry
|
|
|
|
* 2. Apply filter
|
|
|
|
* 3. Apply clipping, masking, group opacity
|
|
|
|
*
|
|
|
|
* We follow this, but perform a couple of optimizations:
|
|
|
|
*
|
|
|
|
* + Use cairo's clipPath when representable natively (single object
|
|
|
|
* clip region).
|
|
|
|
*
|
|
|
|
* + Merge opacity and masking if both used together.
|
|
|
|
*/
|
|
|
|
|
2011-09-28 23:19:26 -07:00
|
|
|
bool isOK = true;
|
2008-09-30 17:51:05 -07:00
|
|
|
nsSVGClipPathFrame *clipPathFrame = effectProperties.GetClipPathFrame(&isOK);
|
|
|
|
nsSVGFilterFrame *filterFrame = effectProperties.GetFilterFrame(&isOK);
|
|
|
|
nsSVGMaskFrame *maskFrame = effectProperties.GetMaskFrame(&isOK);
|
2008-09-10 17:24:16 -07:00
|
|
|
|
2011-09-28 23:19:26 -07:00
|
|
|
bool isTrivialClip = clipPathFrame ? clipPathFrame->IsTrivial() : true;
|
2008-09-10 17:24:16 -07:00
|
|
|
|
|
|
|
if (!isOK) {
|
|
|
|
// Some resource is missing. We shouldn't paint anything.
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
gfxContext* gfx = aCtx->ThebesContext();
|
2012-06-14 20:02:27 -07:00
|
|
|
gfxContextMatrixAutoSaveRestore matrixAutoSaveRestore(gfx);
|
2012-03-02 00:28:59 -08:00
|
|
|
|
2012-06-19 08:28:04 -07:00
|
|
|
PRInt32 appUnitsPerDevPixel =
|
|
|
|
aEffectsFrame->PresContext()->AppUnitsPerDevPixel();
|
|
|
|
nsPoint firstFrameOffset = GetOffsetToUserSpace(firstFrame);
|
|
|
|
nsPoint offset = (aBuilder->ToReferenceFrame(firstFrame) - firstFrameOffset).
|
|
|
|
ToNearestPixels(appUnitsPerDevPixel).
|
|
|
|
ToAppUnits(appUnitsPerDevPixel);
|
|
|
|
aCtx->Translate(offset);
|
2008-09-10 17:24:16 -07:00
|
|
|
|
2009-07-23 01:35:59 -07:00
|
|
|
gfxMatrix matrix = GetInitialMatrix(aEffectsFrame);
|
2008-09-10 17:24:16 -07:00
|
|
|
|
2011-09-28 23:19:26 -07:00
|
|
|
bool complexEffects = false;
|
2008-09-10 17:24:16 -07:00
|
|
|
/* Check if we need to do additional operations on this child's
|
|
|
|
* rendering, which necessitates rendering into another surface. */
|
|
|
|
if (opacity != 1.0f || maskFrame || (clipPathFrame && !isTrivialClip)) {
|
2011-10-17 07:59:28 -07:00
|
|
|
complexEffects = true;
|
2008-09-10 17:24:16 -07:00
|
|
|
gfx->Save();
|
2011-04-07 18:04:40 -07:00
|
|
|
aCtx->IntersectClip(aEffectsFrame->GetVisualOverflowRect());
|
2008-09-10 17:24:16 -07:00
|
|
|
gfx->PushGroup(gfxASurface::CONTENT_COLOR_ALPHA);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* 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 (clipPathFrame && isTrivialClip) {
|
|
|
|
gfx->Save();
|
2012-03-02 00:28:59 -08:00
|
|
|
clipPathFrame->ClipPaint(aCtx, aEffectsFrame, matrix);
|
2008-09-10 17:24:16 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Paint the child */
|
|
|
|
if (filterFrame) {
|
2012-06-16 13:23:48 -07:00
|
|
|
RegularFramePaintCallback callback(aBuilder, aInnerList, aEffectsFrame,
|
2012-06-19 08:28:04 -07:00
|
|
|
offset);
|
|
|
|
nsIntRect dirtyRect = (aDirtyRect - offset)
|
2012-06-16 13:23:48 -07:00
|
|
|
.ToOutsidePixels(appUnitsPerDevPixel);
|
|
|
|
filterFrame->PaintFilteredFrame(aCtx, aEffectsFrame, &callback, &dirtyRect);
|
2008-09-10 17:24:16 -07:00
|
|
|
} else {
|
2012-06-14 20:02:27 -07:00
|
|
|
gfx->SetMatrix(matrixAutoSaveRestore.Matrix());
|
Backout 61fd66629c4f, 7c8121f8d3af & 2a2e9cf8fd41 (bug 539356), e31a5e6545d3 (bug 761884), 85fa80bd9792, a284ccb25b83, 2865904db9fc, 34e07b09c426, e9b3d41e0360, cef00ebcd6c8, f943b729ac14 & 783f298401b6 (bug 539356), 330a086f1570 (bug 741682), d80219c8842c (bug 739671), e8c96b4fd4da, 313af486e68d, 0adc41ff56dc, 0cd288a38085, f1d43208825c, 4859876972f3, eec8ef3ebe48, f7f29fcd1845, 6079b229d306, f23c3a7e7ce0, 9824458a41e2 & 6748b5496059 (bug 539356) for mochitest-4 orange & talos regressions on multiple platforms
2012-06-11 02:08:32 -07:00
|
|
|
aInnerList->PaintForFrame(aBuilder, aCtx, aEffectsFrame,
|
|
|
|
nsDisplayList::PAINT_DEFAULT);
|
2012-06-19 08:28:04 -07:00
|
|
|
aCtx->Translate(offset);
|
2008-09-10 17:24:16 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
if (clipPathFrame && isTrivialClip) {
|
|
|
|
gfx->Restore();
|
|
|
|
}
|
|
|
|
|
|
|
|
/* No more effects, we're done. */
|
|
|
|
if (!complexEffects) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
gfx->PopGroupToSource();
|
|
|
|
|
|
|
|
nsRefPtr<gfxPattern> maskSurface =
|
2012-03-02 00:28:59 -08:00
|
|
|
maskFrame ? maskFrame->ComputeMaskAlpha(aCtx, aEffectsFrame,
|
2008-09-10 17:24:16 -07:00
|
|
|
matrix, opacity) : nsnull;
|
|
|
|
|
|
|
|
nsRefPtr<gfxPattern> clipMaskSurface;
|
|
|
|
if (clipPathFrame && !isTrivialClip) {
|
|
|
|
gfx->PushGroup(gfxASurface::CONTENT_COLOR_ALPHA);
|
|
|
|
|
2012-03-02 00:28:59 -08:00
|
|
|
nsresult rv = clipPathFrame->ClipPaint(aCtx, aEffectsFrame, matrix);
|
2008-09-10 17:24:16 -07:00
|
|
|
clipMaskSurface = gfx->PopGroup();
|
|
|
|
|
|
|
|
if (NS_SUCCEEDED(rv) && clipMaskSurface) {
|
|
|
|
// Still more set after clipping, so clip to another surface
|
|
|
|
if (maskSurface || opacity != 1.0f) {
|
|
|
|
gfx->PushGroup(gfxASurface::CONTENT_COLOR_ALPHA);
|
|
|
|
gfx->Mask(clipMaskSurface);
|
|
|
|
gfx->PopGroupToSource();
|
|
|
|
} else {
|
|
|
|
gfx->Mask(clipMaskSurface);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (maskSurface) {
|
|
|
|
gfx->Mask(maskSurface);
|
|
|
|
} else if (opacity != 1.0f) {
|
|
|
|
gfx->Paint(opacity);
|
|
|
|
}
|
|
|
|
|
|
|
|
gfx->Restore();
|
|
|
|
}
|
|
|
|
|
2009-07-23 01:35:59 -07:00
|
|
|
gfxMatrix
|
2008-09-10 17:24:16 -07:00
|
|
|
nsSVGIntegrationUtils::GetInitialMatrix(nsIFrame* aNonSVGFrame)
|
|
|
|
{
|
|
|
|
NS_ASSERTION(!aNonSVGFrame->IsFrameOfType(nsIFrame::eSVG),
|
|
|
|
"SVG frames should not get here");
|
|
|
|
PRInt32 appUnitsPerDevPixel = aNonSVGFrame->PresContext()->AppUnitsPerDevPixel();
|
|
|
|
float devPxPerCSSPx =
|
|
|
|
1 / nsPresContext::AppUnitsToFloatCSSPixels(appUnitsPerDevPixel);
|
2009-07-23 01:35:59 -07:00
|
|
|
|
|
|
|
return gfxMatrix(devPxPerCSSPx, 0.0,
|
|
|
|
0.0, devPxPerCSSPx,
|
|
|
|
0.0, 0.0);
|
2008-09-10 17:24:16 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
gfxRect
|
|
|
|
nsSVGIntegrationUtils::GetSVGBBoxForNonSVGFrame(nsIFrame* aNonSVGFrame)
|
|
|
|
{
|
|
|
|
NS_ASSERTION(!aNonSVGFrame->IsFrameOfType(nsIFrame::eSVG),
|
|
|
|
"SVG frames should not get here");
|
|
|
|
nsIFrame* firstFrame =
|
|
|
|
nsLayoutUtils::GetFirstContinuationOrSpecialSibling(aNonSVGFrame);
|
2012-06-19 08:28:04 -07:00
|
|
|
// 'r' is in "user space":
|
|
|
|
nsRect r = GetSVGBBox(firstFrame, nsnull, nsRect(),
|
|
|
|
GetOffsetToUserSpace(firstFrame));
|
|
|
|
return nsLayoutUtils::RectToGfxRect(r,
|
|
|
|
aNonSVGFrame->PresContext()->AppUnitsPerCSSPixel());
|
2008-09-10 17:24:16 -07:00
|
|
|
}
|
2010-08-13 06:32:27 -07:00
|
|
|
|
|
|
|
class PaintFrameCallback : public gfxDrawingCallback {
|
|
|
|
public:
|
|
|
|
PaintFrameCallback(nsIFrame* aFrame,
|
|
|
|
nsIFrame* aTarget,
|
|
|
|
const nsSize aPaintServerSize,
|
|
|
|
const gfxIntSize aRenderSize)
|
|
|
|
: mFrame(aFrame)
|
|
|
|
, mTarget(aTarget)
|
|
|
|
, mPaintServerSize(aPaintServerSize)
|
|
|
|
, mRenderSize(aRenderSize)
|
|
|
|
{}
|
2011-09-28 23:19:26 -07:00
|
|
|
virtual bool operator()(gfxContext* aContext,
|
2010-08-13 06:32:27 -07:00
|
|
|
const gfxRect& aFillRect,
|
|
|
|
const gfxPattern::GraphicsFilter& aFilter,
|
|
|
|
const gfxMatrix& aTransform);
|
|
|
|
private:
|
|
|
|
nsIFrame* mFrame;
|
|
|
|
nsIFrame* mTarget;
|
|
|
|
nsSize mPaintServerSize;
|
|
|
|
gfxIntSize mRenderSize;
|
|
|
|
};
|
|
|
|
|
2011-09-28 23:19:26 -07:00
|
|
|
bool
|
2010-08-13 06:32:27 -07:00
|
|
|
PaintFrameCallback::operator()(gfxContext* aContext,
|
|
|
|
const gfxRect& aFillRect,
|
|
|
|
const gfxPattern::GraphicsFilter& aFilter,
|
|
|
|
const gfxMatrix& aTransform)
|
|
|
|
{
|
|
|
|
if (mFrame->GetStateBits() & NS_FRAME_DRAWING_AS_PAINTSERVER)
|
2011-10-17 07:59:28 -07:00
|
|
|
return false;
|
2010-08-13 06:32:27 -07:00
|
|
|
|
|
|
|
mFrame->AddStateBits(NS_FRAME_DRAWING_AS_PAINTSERVER);
|
|
|
|
|
2012-03-02 00:28:59 -08:00
|
|
|
nsRenderingContext context;
|
|
|
|
context.Init(mFrame->PresContext()->DeviceContext(), aContext);
|
2010-08-13 06:32:27 -07:00
|
|
|
aContext->Save();
|
|
|
|
|
|
|
|
// Clip to aFillRect so that we don't paint outside.
|
|
|
|
aContext->NewPath();
|
|
|
|
aContext->Rectangle(aFillRect);
|
|
|
|
aContext->Clip();
|
|
|
|
|
|
|
|
aContext->Multiply(gfxMatrix(aTransform).Invert());
|
|
|
|
|
|
|
|
// nsLayoutUtils::PaintFrame will anchor its painting at mFrame. But we want
|
|
|
|
// 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.
|
|
|
|
PRInt32 appUnitsPerDevPixel = mFrame->PresContext()->AppUnitsPerDevPixel();
|
2012-06-19 08:28:04 -07:00
|
|
|
nsPoint offset = nsSVGIntegrationUtils::GetOffsetToUserSpace(mFrame);
|
|
|
|
gfxPoint devPxOffset = gfxPoint(offset.x, offset.y) / appUnitsPerDevPixel;
|
|
|
|
aContext->Multiply(gfxMatrix().Translate(devPxOffset));
|
2010-08-13 06:32:27 -07:00
|
|
|
|
|
|
|
gfxSize paintServerSize =
|
|
|
|
gfxSize(mPaintServerSize.width, mPaintServerSize.height) /
|
|
|
|
mFrame->PresContext()->AppUnitsPerDevPixel();
|
|
|
|
|
|
|
|
// nsLayoutUtils::PaintFrame wants to render with paintServerSize, but we
|
|
|
|
// want it to render with mRenderSize, so we need to set up a scale transform.
|
|
|
|
gfxFloat scaleX = mRenderSize.width / paintServerSize.width;
|
|
|
|
gfxFloat scaleY = mRenderSize.height / paintServerSize.height;
|
|
|
|
gfxMatrix scaleMatrix = gfxMatrix().Scale(scaleX, scaleY);
|
|
|
|
aContext->Multiply(scaleMatrix);
|
|
|
|
|
|
|
|
// Draw.
|
2012-06-19 08:28:04 -07:00
|
|
|
nsRect dirty(-offset.x, -offset.y,
|
|
|
|
mPaintServerSize.width, mPaintServerSize.height);
|
2012-03-02 00:28:59 -08:00
|
|
|
nsLayoutUtils::PaintFrame(&context, mFrame,
|
2010-08-13 06:32:27 -07:00
|
|
|
dirty, NS_RGBA(0, 0, 0, 0),
|
|
|
|
nsLayoutUtils::PAINT_IN_TRANSFORM |
|
|
|
|
nsLayoutUtils::PAINT_ALL_CONTINUATIONS);
|
|
|
|
|
|
|
|
aContext->Restore();
|
|
|
|
|
|
|
|
mFrame->RemoveStateBits(NS_FRAME_DRAWING_AS_PAINTSERVER);
|
|
|
|
|
2011-10-17 07:59:28 -07:00
|
|
|
return true;
|
2010-08-13 06:32:27 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
static already_AddRefed<gfxDrawable>
|
|
|
|
DrawableFromPaintServer(nsIFrame* aFrame,
|
|
|
|
nsIFrame* aTarget,
|
|
|
|
const nsSize& aPaintServerSize,
|
|
|
|
const gfxIntSize& aRenderSize)
|
|
|
|
{
|
|
|
|
// aPaintServerSize is the size that would be filled when using
|
|
|
|
// background-repeat:no-repeat and background-size:auto. For normal background
|
|
|
|
// images, this would be the intrinsic size of the image; for gradients and
|
|
|
|
// patterns this would be the whole target frame fill area.
|
|
|
|
// aRenderSize is what we will be actually filling after accounting for
|
|
|
|
// background-size.
|
|
|
|
if (aFrame->IsFrameOfType(nsIFrame::eSVGPaintServer)) {
|
|
|
|
// aFrame is either a pattern or a gradient. These fill the whole target
|
|
|
|
// frame by default, so aPaintServerSize is the whole target background fill
|
|
|
|
// area.
|
|
|
|
nsSVGPaintServerFrame* server =
|
|
|
|
static_cast<nsSVGPaintServerFrame*>(aFrame);
|
|
|
|
|
|
|
|
gfxRect overrideBounds(0, 0,
|
|
|
|
aPaintServerSize.width, aPaintServerSize.height);
|
|
|
|
overrideBounds.ScaleInverse(aFrame->PresContext()->AppUnitsPerDevPixel());
|
|
|
|
nsRefPtr<gfxPattern> pattern =
|
2012-05-18 01:34:25 -07:00
|
|
|
server->GetPaintServerPattern(aTarget, &nsStyleSVG::mFill, 1.0, &overrideBounds);
|
2010-08-13 06:32:27 -07:00
|
|
|
|
2010-09-05 20:12:46 -07:00
|
|
|
if (!pattern)
|
|
|
|
return nsnull;
|
|
|
|
|
2010-08-13 06:32:27 -07:00
|
|
|
// pattern is now set up to fill aPaintServerSize. But we want it to
|
|
|
|
// fill aRenderSize, so we need to add a scaling transform.
|
|
|
|
// We couldn't just have set overrideBounds to aRenderSize - it would have
|
|
|
|
// worked for gradients, but for patterns it would result in a different
|
|
|
|
// pattern size.
|
|
|
|
gfxFloat scaleX = overrideBounds.Width() / aRenderSize.width;
|
|
|
|
gfxFloat scaleY = overrideBounds.Height() / aRenderSize.height;
|
|
|
|
gfxMatrix scaleMatrix = gfxMatrix().Scale(scaleX, scaleY);
|
|
|
|
pattern->SetMatrix(scaleMatrix.Multiply(pattern->GetMatrix()));
|
|
|
|
nsRefPtr<gfxDrawable> drawable =
|
|
|
|
new gfxPatternDrawable(pattern, aRenderSize);
|
|
|
|
return drawable.forget();
|
|
|
|
}
|
|
|
|
|
|
|
|
// We don't want to paint into a surface as long as we don't need to, so we
|
|
|
|
// set up a drawing callback.
|
|
|
|
nsRefPtr<gfxDrawingCallback> cb =
|
|
|
|
new PaintFrameCallback(aFrame, aTarget, aPaintServerSize, aRenderSize);
|
|
|
|
nsRefPtr<gfxDrawable> drawable = new gfxCallbackDrawable(cb, aRenderSize);
|
|
|
|
return drawable.forget();
|
|
|
|
}
|
|
|
|
|
|
|
|
/* static */ void
|
2011-04-07 18:04:40 -07:00
|
|
|
nsSVGIntegrationUtils::DrawPaintServer(nsRenderingContext* aRenderingContext,
|
2010-08-13 06:32:27 -07:00
|
|
|
nsIFrame* aTarget,
|
|
|
|
nsIFrame* aPaintServer,
|
|
|
|
gfxPattern::GraphicsFilter aFilter,
|
|
|
|
const nsRect& aDest,
|
|
|
|
const nsRect& aFill,
|
|
|
|
const nsPoint& aAnchor,
|
|
|
|
const nsRect& aDirty,
|
|
|
|
const nsSize& aPaintServerSize)
|
|
|
|
{
|
|
|
|
if (aDest.IsEmpty() || aFill.IsEmpty())
|
|
|
|
return;
|
|
|
|
|
|
|
|
PRInt32 appUnitsPerDevPixel = aTarget->PresContext()->AppUnitsPerDevPixel();
|
|
|
|
nsRect destSize = aDest - aDest.TopLeft();
|
|
|
|
nsIntSize roundedOut = destSize.ToOutsidePixels(appUnitsPerDevPixel).Size();
|
|
|
|
gfxIntSize imageSize(roundedOut.width, roundedOut.height);
|
|
|
|
nsRefPtr<gfxDrawable> drawable =
|
|
|
|
DrawableFromPaintServer(aPaintServer, aTarget, aPaintServerSize, imageSize);
|
|
|
|
|
2010-09-05 20:12:46 -07:00
|
|
|
if (drawable) {
|
|
|
|
nsLayoutUtils::DrawPixelSnapped(aRenderingContext, drawable, aFilter,
|
|
|
|
aDest, aFill, aAnchor, aDirty);
|
|
|
|
}
|
2010-08-13 06:32:27 -07:00
|
|
|
}
|