зеркало из https://github.com/mozilla/gecko-dev.git
merge mozilla-inbound to mozilla-central a=merge
This commit is contained in:
Коммит
2d8d746257
|
@ -16,7 +16,6 @@ class nsMacShellService : public nsIMacShellService,
|
|||
{
|
||||
public:
|
||||
nsMacShellService() : mCheckedThisSession(false) {};
|
||||
virtual ~nsMacShellService() {};
|
||||
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSISHELLSERVICE
|
||||
|
@ -24,6 +23,7 @@ public:
|
|||
NS_DECL_NSIWEBPROGRESSLISTENER
|
||||
|
||||
protected:
|
||||
virtual ~nsMacShellService() {};
|
||||
|
||||
private:
|
||||
nsCOMPtr<nsIFile> mBackgroundFile;
|
||||
|
|
|
@ -43,10 +43,6 @@ public:
|
|||
SetIsDOMBinding();
|
||||
}
|
||||
|
||||
~DOMMatrixReadOnly()
|
||||
{
|
||||
}
|
||||
|
||||
#define GetMatrixMember(entry2D, entry3D, default) \
|
||||
{ \
|
||||
if (mMatrix3D) { \
|
||||
|
@ -135,6 +131,10 @@ protected:
|
|||
nsCOMPtr<nsISupports> mParent;
|
||||
nsAutoPtr<gfx::Matrix> mMatrix2D;
|
||||
nsAutoPtr<gfx::Matrix4x4> mMatrix3D;
|
||||
|
||||
~DOMMatrixReadOnly()
|
||||
{
|
||||
}
|
||||
private:
|
||||
DOMMatrixReadOnly() MOZ_DELETE;
|
||||
DOMMatrixReadOnly(const DOMMatrixReadOnly&) MOZ_DELETE;
|
||||
|
@ -248,6 +248,8 @@ public:
|
|||
DOMMatrix* SetMatrixValue(const nsAString& aTransformList, ErrorResult& aRv);
|
||||
private:
|
||||
void Ensure3DMatrix();
|
||||
|
||||
~DOMMatrix() {}
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -1385,7 +1385,6 @@ public:
|
|||
NS_DECL_NSIDOMEVENTLISTENER
|
||||
|
||||
WebGLObserver(WebGLContext* aContext);
|
||||
~WebGLObserver();
|
||||
|
||||
void Destroy();
|
||||
|
||||
|
@ -1396,6 +1395,8 @@ public:
|
|||
void UnregisterMemoryPressureEvent();
|
||||
|
||||
private:
|
||||
~WebGLObserver();
|
||||
|
||||
WebGLContext* mContext;
|
||||
};
|
||||
|
||||
|
|
|
@ -94,7 +94,7 @@ SVGCircleElement::ConstructPath(gfxContext *aCtx)
|
|||
}
|
||||
|
||||
TemporaryRef<Path>
|
||||
SVGCircleElement::BuildPath()
|
||||
SVGCircleElement::BuildPath(PathBuilder* aBuilder)
|
||||
{
|
||||
float x, y, r;
|
||||
GetAnimatedLengthValues(&x, &y, &r, nullptr);
|
||||
|
@ -103,7 +103,7 @@ SVGCircleElement::BuildPath()
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
RefPtr<PathBuilder> pathBuilder = CreatePathBuilder();
|
||||
RefPtr<PathBuilder> pathBuilder = aBuilder ? aBuilder : CreatePathBuilder();
|
||||
|
||||
pathBuilder->Arc(Point(x, y), r, 0, Float(2*M_PI));
|
||||
|
||||
|
|
|
@ -31,7 +31,7 @@ public:
|
|||
|
||||
// nsSVGPathGeometryElement methods:
|
||||
virtual void ConstructPath(gfxContext *aCtx) MOZ_OVERRIDE;
|
||||
virtual TemporaryRef<Path> BuildPath() MOZ_OVERRIDE;
|
||||
virtual TemporaryRef<Path> BuildPath(PathBuilder* aBuilder = nullptr) MOZ_OVERRIDE;
|
||||
|
||||
virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult) const MOZ_OVERRIDE;
|
||||
|
||||
|
|
|
@ -8,8 +8,13 @@
|
|||
#include "SVGContentUtils.h"
|
||||
|
||||
// Keep others in (case-insensitive) order:
|
||||
#include "gfx2DGlue.h"
|
||||
#include "gfxMatrix.h"
|
||||
#include "gfxPlatform.h"
|
||||
#include "gfxSVGGlyphs.h"
|
||||
#include "mozilla/gfx/2D.h"
|
||||
#include "mozilla/dom/SVGSVGElement.h"
|
||||
#include "mozilla/RefPtr.h"
|
||||
#include "nsComputedDOMStyle.h"
|
||||
#include "nsFontMetrics.h"
|
||||
#include "nsIFrame.h"
|
||||
|
@ -20,12 +25,14 @@
|
|||
#include "nsContentUtils.h"
|
||||
#include "mozilla/gfx/2D.h"
|
||||
#include "mozilla/gfx/Types.h"
|
||||
#include "gfx2DGlue.h"
|
||||
#include "nsStyleContext.h"
|
||||
#include "nsSVGPathDataParser.h"
|
||||
#include "SVGPathData.h"
|
||||
#include "SVGPathElement.h"
|
||||
|
||||
using namespace mozilla;
|
||||
using namespace mozilla::dom;
|
||||
using namespace mozilla::gfx;
|
||||
|
||||
SVGSVGElement*
|
||||
SVGContentUtils::GetOuterSVGElement(nsSVGElement *aSVGElement)
|
||||
|
@ -54,6 +61,179 @@ SVGContentUtils::ActivateByHyperlink(nsIContent *aContent)
|
|||
static_cast<SVGAnimationElement*>(aContent)->ActivateByHyperlink();
|
||||
}
|
||||
|
||||
enum DashState {
|
||||
eDashedStroke,
|
||||
eContinuousStroke, //< all dashes, no gaps
|
||||
eNoStroke //< all gaps, no dashes
|
||||
};
|
||||
|
||||
static DashState
|
||||
GetStrokeDashData(SVGContentUtils::AutoStrokeOptions* aStrokeOptions,
|
||||
nsSVGElement* aElement,
|
||||
const nsStyleSVG* aStyleSVG,
|
||||
gfxTextContextPaint *aContextPaint)
|
||||
{
|
||||
size_t dashArrayLength;
|
||||
Float totalLengthOfDashes = 0.0, totalLengthOfGaps = 0.0;
|
||||
|
||||
if (aContextPaint && aStyleSVG->mStrokeDasharrayFromObject) {
|
||||
const FallibleTArray<gfxFloat>& dashSrc = aContextPaint->GetStrokeDashArray();
|
||||
dashArrayLength = dashSrc.Length();
|
||||
if (dashArrayLength <= 0) {
|
||||
return eContinuousStroke;
|
||||
}
|
||||
Float* dashPattern = aStrokeOptions->InitDashPattern(dashArrayLength);
|
||||
if (!dashPattern) {
|
||||
return eContinuousStroke;
|
||||
}
|
||||
for (size_t i = 0; i < dashArrayLength; i++) {
|
||||
if (dashSrc[i] < 0.0) {
|
||||
return eContinuousStroke; // invalid
|
||||
}
|
||||
dashPattern[i] = Float(dashSrc[i]);
|
||||
(i % 2 ? totalLengthOfGaps : totalLengthOfDashes) += dashSrc[i];
|
||||
}
|
||||
} else {
|
||||
const nsStyleCoord *dasharray = aStyleSVG->mStrokeDasharray;
|
||||
dashArrayLength = aStyleSVG->mStrokeDasharrayLength;
|
||||
if (dashArrayLength <= 0) {
|
||||
return eContinuousStroke;
|
||||
}
|
||||
Float pathScale = 1.0;
|
||||
if (aElement->Tag() == nsGkAtoms::path) {
|
||||
pathScale = static_cast<SVGPathElement*>(aElement)->
|
||||
GetPathLengthScale(SVGPathElement::eForStroking);
|
||||
if (pathScale <= 0) {
|
||||
return eContinuousStroke;
|
||||
}
|
||||
}
|
||||
Float* dashPattern = aStrokeOptions->InitDashPattern(dashArrayLength);
|
||||
if (!dashPattern) {
|
||||
return eContinuousStroke;
|
||||
}
|
||||
for (uint32_t i = 0; i < dashArrayLength; i++) {
|
||||
Float dashLength =
|
||||
SVGContentUtils::CoordToFloat(aElement, dasharray[i]) * pathScale;
|
||||
if (dashLength < 0.0) {
|
||||
return eContinuousStroke; // invalid
|
||||
}
|
||||
dashPattern[i] = dashLength;
|
||||
(i % 2 ? totalLengthOfGaps : totalLengthOfDashes) += dashLength;
|
||||
}
|
||||
}
|
||||
|
||||
// Now that aStrokeOptions.mDashPattern is fully initialized we can safely
|
||||
// set mDashLength:
|
||||
aStrokeOptions->mDashLength = dashArrayLength;
|
||||
|
||||
if (totalLengthOfDashes <= 0 || totalLengthOfGaps <= 0) {
|
||||
if (totalLengthOfGaps > 0 && totalLengthOfDashes <= 0) {
|
||||
return eNoStroke;
|
||||
}
|
||||
return eContinuousStroke;
|
||||
}
|
||||
|
||||
if (aContextPaint && aStyleSVG->mStrokeDashoffsetFromObject) {
|
||||
aStrokeOptions->mDashOffset = Float(aContextPaint->GetStrokeDashOffset());
|
||||
} else {
|
||||
aStrokeOptions->mDashOffset =
|
||||
SVGContentUtils::CoordToFloat(aElement, aStyleSVG->mStrokeDashoffset);
|
||||
}
|
||||
|
||||
return eDashedStroke;
|
||||
}
|
||||
|
||||
void
|
||||
SVGContentUtils::GetStrokeOptions(AutoStrokeOptions* aStrokeOptions,
|
||||
nsSVGElement* aElement,
|
||||
nsStyleContext* aStyleContext,
|
||||
gfxTextContextPaint *aContextPaint)
|
||||
{
|
||||
nsRefPtr<nsStyleContext> styleContext;
|
||||
if (aStyleContext) {
|
||||
styleContext = aStyleContext;
|
||||
} else {
|
||||
styleContext =
|
||||
nsComputedDOMStyle::GetStyleContextForElementNoFlush(aElement, nullptr,
|
||||
nullptr);
|
||||
}
|
||||
|
||||
if (!styleContext) {
|
||||
return;
|
||||
}
|
||||
|
||||
const nsStyleSVG* styleSVG = styleContext->StyleSVG();
|
||||
|
||||
DashState dashState =
|
||||
GetStrokeDashData(aStrokeOptions, aElement, styleSVG, aContextPaint);
|
||||
|
||||
if (dashState == eNoStroke) {
|
||||
// Hopefully this will shortcircuit any stroke operations:
|
||||
aStrokeOptions->mLineWidth = 0;
|
||||
return;
|
||||
}
|
||||
if (dashState == eContinuousStroke) {
|
||||
// Prevent our caller from wasting time looking at the dash array:
|
||||
aStrokeOptions->mDashLength = 0;
|
||||
}
|
||||
|
||||
aStrokeOptions->mLineWidth =
|
||||
GetStrokeWidth(aElement, styleContext, aContextPaint);
|
||||
|
||||
aStrokeOptions->mMiterLimit = Float(styleSVG->mStrokeMiterlimit);
|
||||
|
||||
switch (styleSVG->mStrokeLinejoin) {
|
||||
case NS_STYLE_STROKE_LINEJOIN_MITER:
|
||||
aStrokeOptions->mLineJoin = JoinStyle::MITER;
|
||||
break;
|
||||
case NS_STYLE_STROKE_LINEJOIN_ROUND:
|
||||
aStrokeOptions->mLineJoin = JoinStyle::ROUND;
|
||||
break;
|
||||
case NS_STYLE_STROKE_LINEJOIN_BEVEL:
|
||||
aStrokeOptions->mLineJoin = JoinStyle::BEVEL;
|
||||
break;
|
||||
}
|
||||
|
||||
switch (styleSVG->mStrokeLinecap) {
|
||||
case NS_STYLE_STROKE_LINECAP_BUTT:
|
||||
aStrokeOptions->mLineCap = CapStyle::BUTT;
|
||||
break;
|
||||
case NS_STYLE_STROKE_LINECAP_ROUND:
|
||||
aStrokeOptions->mLineCap = CapStyle::ROUND;
|
||||
break;
|
||||
case NS_STYLE_STROKE_LINECAP_SQUARE:
|
||||
aStrokeOptions->mLineCap = CapStyle::SQUARE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Float
|
||||
SVGContentUtils::GetStrokeWidth(nsSVGElement* aElement,
|
||||
nsStyleContext* aStyleContext,
|
||||
gfxTextContextPaint *aContextPaint)
|
||||
{
|
||||
nsRefPtr<nsStyleContext> styleContext;
|
||||
if (aStyleContext) {
|
||||
styleContext = aStyleContext;
|
||||
} else {
|
||||
styleContext =
|
||||
nsComputedDOMStyle::GetStyleContextForElementNoFlush(aElement, nullptr,
|
||||
nullptr);
|
||||
}
|
||||
|
||||
if (!styleContext) {
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
const nsStyleSVG* styleSVG = styleContext->StyleSVG();
|
||||
|
||||
if (aContextPaint && styleSVG->mStrokeWidthFromObject) {
|
||||
return aContextPaint->GetStrokeWidth();
|
||||
}
|
||||
|
||||
return SVGContentUtils::CoordToFloat(aElement, styleSVG->mStrokeWidth);
|
||||
}
|
||||
|
||||
float
|
||||
SVGContentUtils::GetFontSize(Element *aElement)
|
||||
{
|
||||
|
@ -596,5 +776,10 @@ SVGContentUtils::GetPath(const nsAString& aPathString)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
return pathData.BuildPath(mozilla::gfx::FillRule::FILL_WINDING, NS_STYLE_STROKE_LINECAP_BUTT, 1);
|
||||
RefPtr<DrawTarget> drawTarget =
|
||||
gfxPlatform::GetPlatform()->ScreenReferenceDrawTarget();
|
||||
RefPtr<PathBuilder> builder =
|
||||
drawTarget->CreatePathBuilder(FillRule::FILL_WINDING);
|
||||
|
||||
return pathData.BuildPath(builder, NS_STYLE_STROKE_LINECAP_BUTT, 1);
|
||||
}
|
||||
|
|
|
@ -10,12 +10,15 @@
|
|||
#define _USE_MATH_DEFINES
|
||||
#include <math.h>
|
||||
|
||||
#include "mozilla/fallible.h"
|
||||
#include "mozilla/gfx/2D.h" // for StrokeOptions
|
||||
#include "mozilla/gfx/Matrix.h"
|
||||
#include "mozilla/RangedPtr.h"
|
||||
#include "nsError.h"
|
||||
#include "nsStringFwd.h"
|
||||
#include "gfx2DGlue.h"
|
||||
|
||||
class gfxTextContextPaint;
|
||||
class nsIContent;
|
||||
class nsIDocument;
|
||||
class nsIFrame;
|
||||
|
@ -58,6 +61,8 @@ IsSVGWhitespace(char16_t aChar)
|
|||
class SVGContentUtils
|
||||
{
|
||||
public:
|
||||
typedef mozilla::gfx::Float Float;
|
||||
typedef mozilla::gfx::StrokeOptions StrokeOptions;
|
||||
typedef mozilla::SVGAnimatedPreserveAspectRatio SVGAnimatedPreserveAspectRatio;
|
||||
typedef mozilla::SVGPreserveAspectRatio SVGPreserveAspectRatio;
|
||||
|
||||
|
@ -76,6 +81,64 @@ public:
|
|||
*/
|
||||
static void ActivateByHyperlink(nsIContent *aContent);
|
||||
|
||||
/**
|
||||
* Moz2D's StrokeOptions requires someone else to own its mDashPattern
|
||||
* buffer, which is a pain when you want to initialize a StrokeOptions object
|
||||
* in a helper function and pass it out. This sub-class owns the mDashPattern
|
||||
* buffer so that consumers of such a helper function don't need to worry
|
||||
* about creating it, passing it in, or deleting it. (An added benefit is
|
||||
* that in the typical case when stroke-dasharray is short it will avoid
|
||||
* allocating.)
|
||||
*/
|
||||
struct AutoStrokeOptions : public StrokeOptions {
|
||||
AutoStrokeOptions()
|
||||
{
|
||||
MOZ_ASSERT(mDashLength == 0, "InitDashPattern() depends on this");
|
||||
}
|
||||
~AutoStrokeOptions() {
|
||||
if (mDashPattern && mDashPattern != mSmallArray) {
|
||||
delete [] mDashPattern;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Creates the buffer to store the stroke-dasharray, assuming out-of-memory
|
||||
* does not occur. The buffer's address is assigned to mDashPattern and
|
||||
* returned to the caller as a non-const pointer (so that the caller can
|
||||
* initialize the values in the buffer, since mDashPattern is const).
|
||||
*/
|
||||
Float* InitDashPattern(size_t aDashCount) {
|
||||
if (aDashCount <= MOZ_ARRAY_LENGTH(mSmallArray)) {
|
||||
mDashPattern = mSmallArray;
|
||||
return mSmallArray;
|
||||
}
|
||||
static const mozilla::fallible_t fallible = mozilla::fallible_t();
|
||||
Float* nonConstArray = new (fallible) Float[aDashCount];
|
||||
mDashPattern = nonConstArray;
|
||||
return nonConstArray;
|
||||
}
|
||||
private:
|
||||
// Most dasharrays will fit in this and save us allocating
|
||||
Float mSmallArray[16];
|
||||
};
|
||||
|
||||
static void GetStrokeOptions(AutoStrokeOptions* aStrokeOptions,
|
||||
nsSVGElement* aElement,
|
||||
nsStyleContext* aStyleContext,
|
||||
gfxTextContextPaint *aContextPaint);
|
||||
|
||||
/**
|
||||
* Returns the current computed value of the CSS property 'stroke-width' for
|
||||
* the given element. aStyleContext may be provided as an optimization.
|
||||
* aContextPaint is also optional.
|
||||
*
|
||||
* Note that this function does NOT take account of the value of the 'stroke'
|
||||
* and 'stroke-opacity' properties to, say, return zero if they are "none" or
|
||||
* "0", respectively.
|
||||
*/
|
||||
static Float GetStrokeWidth(nsSVGElement* aElement,
|
||||
nsStyleContext* aStyleContext,
|
||||
gfxTextContextPaint *aContextPaint);
|
||||
|
||||
/*
|
||||
* Get the number of CSS px (user units) per em (i.e. the em-height in user
|
||||
* units) for an nsIContent
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
#include "mozilla/dom/SVGEllipseElementBinding.h"
|
||||
#include "mozilla/gfx/2D.h"
|
||||
#include "mozilla/gfx/PathHelpers.h"
|
||||
#include "mozilla/RefPtr.h"
|
||||
#include "gfxContext.h"
|
||||
|
||||
NS_IMPL_NS_NEW_NAMESPACED_SVG_ELEMENT(Ellipse)
|
||||
|
@ -96,7 +97,12 @@ void
|
|||
SVGEllipseElement::ConstructPath(gfxContext *aCtx)
|
||||
{
|
||||
if (!aCtx->IsCairo()) {
|
||||
RefPtr<Path> path = BuildPath();
|
||||
RefPtr<DrawTarget> dt = aCtx->GetDrawTarget();
|
||||
FillRule fillRule =
|
||||
aCtx->CurrentFillRule() == gfxContext::FILL_RULE_WINDING ?
|
||||
FillRule::FILL_WINDING : FillRule::FILL_EVEN_ODD;
|
||||
RefPtr<PathBuilder> builder = dt->CreatePathBuilder(fillRule);
|
||||
RefPtr<Path> path = BuildPath(builder);
|
||||
if (path) {
|
||||
nsRefPtr<gfxPath> gfxpath = new gfxPath(path);
|
||||
aCtx->SetPath(gfxpath);
|
||||
|
@ -114,7 +120,7 @@ SVGEllipseElement::ConstructPath(gfxContext *aCtx)
|
|||
}
|
||||
|
||||
TemporaryRef<Path>
|
||||
SVGEllipseElement::BuildPath()
|
||||
SVGEllipseElement::BuildPath(PathBuilder* aBuilder)
|
||||
{
|
||||
float x, y, rx, ry;
|
||||
GetAnimatedLengthValues(&x, &y, &rx, &ry, nullptr);
|
||||
|
@ -123,7 +129,7 @@ SVGEllipseElement::BuildPath()
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
RefPtr<PathBuilder> pathBuilder = CreatePathBuilder();
|
||||
RefPtr<PathBuilder> pathBuilder = aBuilder ? aBuilder : CreatePathBuilder();
|
||||
|
||||
EllipseToBezier(pathBuilder.get(), Point(x, y), Size(rx, ry));
|
||||
|
||||
|
|
|
@ -31,7 +31,7 @@ public:
|
|||
|
||||
// nsSVGPathGeometryElement methods:
|
||||
virtual void ConstructPath(gfxContext *aCtx) MOZ_OVERRIDE;
|
||||
virtual TemporaryRef<Path> BuildPath() MOZ_OVERRIDE;
|
||||
virtual TemporaryRef<Path> BuildPath(PathBuilder* aBuilder = nullptr) MOZ_OVERRIDE;
|
||||
|
||||
virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult) const MOZ_OVERRIDE;
|
||||
|
||||
|
|
|
@ -241,7 +241,7 @@ SVGImageElement::ConstructPath(gfxContext *aCtx)
|
|||
}
|
||||
|
||||
TemporaryRef<Path>
|
||||
SVGImageElement::BuildPath()
|
||||
SVGImageElement::BuildPath(PathBuilder* aBuilder)
|
||||
{
|
||||
// We get called in order to get bounds for this element, and for
|
||||
// hit-testing against it. For that we just pretend to be a rectangle.
|
||||
|
@ -253,7 +253,7 @@ SVGImageElement::BuildPath()
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
RefPtr<PathBuilder> pathBuilder = CreatePathBuilder();
|
||||
RefPtr<PathBuilder> pathBuilder = aBuilder ? aBuilder : CreatePathBuilder();
|
||||
|
||||
Rect r(x, y, width, height);
|
||||
pathBuilder->MoveTo(r.TopLeft());
|
||||
|
|
|
@ -54,7 +54,7 @@ public:
|
|||
|
||||
// nsSVGPathGeometryElement methods:
|
||||
virtual void ConstructPath(gfxContext *aCtx) MOZ_OVERRIDE;
|
||||
virtual TemporaryRef<Path> BuildPath() MOZ_OVERRIDE;
|
||||
virtual TemporaryRef<Path> BuildPath(PathBuilder* aBuilder = nullptr) MOZ_OVERRIDE;
|
||||
|
||||
// nsSVGSVGElement methods:
|
||||
virtual bool HasValidDimensions() const MOZ_OVERRIDE;
|
||||
|
|
|
@ -119,9 +119,9 @@ SVGLineElement::ConstructPath(gfxContext *aCtx)
|
|||
}
|
||||
|
||||
TemporaryRef<Path>
|
||||
SVGLineElement::BuildPath()
|
||||
SVGLineElement::BuildPath(PathBuilder* aBuilder)
|
||||
{
|
||||
RefPtr<PathBuilder> pathBuilder = CreatePathBuilder();
|
||||
RefPtr<PathBuilder> pathBuilder = aBuilder ? aBuilder : CreatePathBuilder();
|
||||
|
||||
float x1, y1, x2, y2;
|
||||
GetAnimatedLengthValues(&x1, &y1, &x2, &y2, nullptr);
|
||||
|
|
|
@ -33,7 +33,7 @@ public:
|
|||
virtual bool IsMarkable() MOZ_OVERRIDE { return true; }
|
||||
virtual void GetMarkPoints(nsTArray<nsSVGMark> *aMarks) MOZ_OVERRIDE;
|
||||
virtual void ConstructPath(gfxContext *aCtx) MOZ_OVERRIDE;
|
||||
virtual TemporaryRef<Path> BuildPath() MOZ_OVERRIDE;
|
||||
virtual TemporaryRef<Path> BuildPath(PathBuilder* aBuilder = nullptr) MOZ_OVERRIDE;
|
||||
|
||||
virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult) const;
|
||||
|
||||
|
|
|
@ -302,7 +302,7 @@ ApproximateZeroLengthSubpathSquareCaps(const gfxPoint &aPoint, gfxContext *aCtx)
|
|||
} while(0)
|
||||
|
||||
TemporaryRef<Path>
|
||||
SVGPathData::BuildPath(FillRule aFillRule,
|
||||
SVGPathData::BuildPath(PathBuilder* builder,
|
||||
uint8_t aStrokeLineCap,
|
||||
Float aStrokeWidth) const
|
||||
{
|
||||
|
@ -310,14 +310,6 @@ SVGPathData::BuildPath(FillRule aFillRule,
|
|||
return nullptr; // paths without an initial moveto are invalid
|
||||
}
|
||||
|
||||
RefPtr<DrawTarget> drawTarget =
|
||||
gfxPlatform::GetPlatform()->ScreenReferenceDrawTarget();
|
||||
NS_ASSERTION(gfxPlatform::GetPlatform()->
|
||||
SupportsAzureContentForDrawTarget(drawTarget),
|
||||
"Should support Moz2D content drawing");
|
||||
|
||||
RefPtr<PathBuilder> builder = drawTarget->CreatePathBuilder(aFillRule);
|
||||
|
||||
bool capsAreSquare = aStrokeLineCap == NS_STYLE_STROKE_LINECAP_SQUARE;
|
||||
bool subpathHasLength = false; // visual length
|
||||
bool subpathContainsNonArc = false;
|
||||
|
@ -814,15 +806,19 @@ TemporaryRef<Path>
|
|||
SVGPathData::ToPathForLengthOrPositionMeasuring() const
|
||||
{
|
||||
// Since the path that we return will not be used for painting it doesn't
|
||||
// matter what we pass to BuildPath as aFillRule. Hawever, we do want to
|
||||
// pass something other than NS_STYLE_STROKE_LINECAP_SQUARE as aStrokeLineCap
|
||||
// to avoid the insertion of extra little lines (by
|
||||
// matter what we pass to CreatePathBuilder as aFillRule. Hawever, we do want
|
||||
// to pass something other than NS_STYLE_STROKE_LINECAP_SQUARE as
|
||||
// aStrokeLineCap to avoid the insertion of extra little lines (by
|
||||
// ApproximateZeroLengthSubpathSquareCaps), in which case the value that we
|
||||
// pass as aStrokeWidth doesn't matter (since it's only used to determine the
|
||||
// length of those extra little lines).
|
||||
|
||||
if (!mCachedPath) {
|
||||
mCachedPath = BuildPath(FillRule::FILL_WINDING, NS_STYLE_STROKE_LINECAP_BUTT, 0);
|
||||
RefPtr<DrawTarget> drawTarget =
|
||||
gfxPlatform::GetPlatform()->ScreenReferenceDrawTarget();
|
||||
RefPtr<PathBuilder> builder =
|
||||
drawTarget->CreatePathBuilder(FillRule::FILL_WINDING);
|
||||
mCachedPath = BuildPath(builder, NS_STYLE_STROKE_LINECAP_BUTT, 0);
|
||||
}
|
||||
|
||||
return mCachedPath;
|
||||
|
|
|
@ -84,6 +84,7 @@ class SVGPathData
|
|||
|
||||
typedef gfx::DrawTarget DrawTarget;
|
||||
typedef gfx::Path Path;
|
||||
typedef gfx::PathBuilder PathBuilder;
|
||||
typedef gfx::FillRule FillRule;
|
||||
typedef gfx::Float Float;
|
||||
typedef gfx::CapStyle CapStyle;
|
||||
|
@ -166,7 +167,7 @@ public:
|
|||
TemporaryRef<Path> ToPathForLengthOrPositionMeasuring() const;
|
||||
|
||||
void ConstructPath(gfxContext *aCtx) const;
|
||||
TemporaryRef<Path> BuildPath(FillRule aFillRule,
|
||||
TemporaryRef<Path> BuildPath(PathBuilder* aBuilder,
|
||||
uint8_t aCapStyle,
|
||||
Float aStrokeWidth) const;
|
||||
|
||||
|
|
|
@ -11,8 +11,10 @@
|
|||
#include "DOMSVGPathSegList.h"
|
||||
#include "DOMSVGPoint.h"
|
||||
#include "gfx2DGlue.h"
|
||||
#include "gfxPlatform.h"
|
||||
#include "mozilla/dom/SVGPathElementBinding.h"
|
||||
#include "mozilla/gfx/2D.h"
|
||||
#include "mozilla/RefPtr.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsComputedDOMStyle.h"
|
||||
#include "nsGkAtoms.h"
|
||||
|
@ -370,7 +372,7 @@ SVGPathElement::GetPathLengthScale(PathLengthScaleForType aFor)
|
|||
}
|
||||
|
||||
TemporaryRef<Path>
|
||||
SVGPathElement::BuildPath()
|
||||
SVGPathElement::BuildPath(PathBuilder* aBuilder)
|
||||
{
|
||||
// The Moz2D PathBuilder that our SVGPathData will be using only cares about
|
||||
// the fill rule. However, in order to fulfill the requirements of the SVG
|
||||
|
@ -392,19 +394,28 @@ SVGPathElement::BuildPath()
|
|||
// opacity here.
|
||||
if (style->mStrokeLinecap == NS_STYLE_STROKE_LINECAP_SQUARE) {
|
||||
strokeLineCap = style->mStrokeLinecap;
|
||||
strokeWidth = GetStrokeWidth();
|
||||
strokeWidth = SVGContentUtils::GetStrokeWidth(this, styleContext, nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
// The fill rule that we pass must be the current
|
||||
// computed value of our CSS 'fill-rule' property if the path that we return
|
||||
// will be used for painting or hit-testing. For all other uses (bounds
|
||||
// calculatons, length measurement, position-at-offset calculations) the fill
|
||||
// rule that we pass doesn't matter. As a result we can just pass the current
|
||||
// computed value regardless of who's calling us, or what they're going to do
|
||||
// with the path that we return.
|
||||
RefPtr<PathBuilder> builder;
|
||||
if (aBuilder) {
|
||||
builder = aBuilder;
|
||||
} else {
|
||||
RefPtr<DrawTarget> drawTarget =
|
||||
gfxPlatform::GetPlatform()->ScreenReferenceDrawTarget();
|
||||
// The fill rule that we pass must be the current computed value of our
|
||||
// CSS 'fill-rule' property if the path that we return will be used for
|
||||
// painting or hit-testing. For all other uses (bounds calculatons, length
|
||||
// measurement, position-at-offset calculations) the fill rule that we pass
|
||||
// doesn't matter. As a result we can just pass the current computed value
|
||||
// regardless of who's calling us, or what they're going to do with the
|
||||
// path that we return.
|
||||
RefPtr<PathBuilder> builder =
|
||||
drawTarget->CreatePathBuilder(GetFillRule());
|
||||
}
|
||||
|
||||
return mD.GetAnimValue().BuildPath(GetFillRule(), strokeLineCap, strokeWidth);
|
||||
return mD.GetAnimValue().BuildPath(builder, strokeLineCap, strokeWidth);
|
||||
}
|
||||
|
||||
} // namespace dom
|
||||
|
|
|
@ -53,7 +53,7 @@ public:
|
|||
virtual bool IsMarkable() MOZ_OVERRIDE;
|
||||
virtual void GetMarkPoints(nsTArray<nsSVGMark> *aMarks) MOZ_OVERRIDE;
|
||||
virtual void ConstructPath(gfxContext *aCtx) MOZ_OVERRIDE;
|
||||
virtual TemporaryRef<Path> BuildPath() MOZ_OVERRIDE;
|
||||
virtual TemporaryRef<Path> BuildPath(PathBuilder* aBuilder = nullptr) MOZ_OVERRIDE;
|
||||
|
||||
/**
|
||||
* This returns a path without the extra little line segments that
|
||||
|
|
|
@ -153,7 +153,7 @@ SVGRectElement::ConstructPath(gfxContext *aCtx)
|
|||
}
|
||||
|
||||
TemporaryRef<Path>
|
||||
SVGRectElement::BuildPath()
|
||||
SVGRectElement::BuildPath(PathBuilder* aBuilder)
|
||||
{
|
||||
float x, y, width, height, rx, ry;
|
||||
GetAnimatedLengthValues(&x, &y, &width, &height, &rx, &ry, nullptr);
|
||||
|
@ -162,7 +162,7 @@ SVGRectElement::BuildPath()
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
RefPtr<PathBuilder> pathBuilder = CreatePathBuilder();
|
||||
RefPtr<PathBuilder> pathBuilder = aBuilder ? aBuilder : CreatePathBuilder();
|
||||
|
||||
rx = std::max(rx, 0.0f);
|
||||
ry = std::max(ry, 0.0f);
|
||||
|
|
|
@ -31,7 +31,7 @@ public:
|
|||
|
||||
// nsSVGPathGeometryElement methods:
|
||||
virtual void ConstructPath(gfxContext *aCtx) MOZ_OVERRIDE;
|
||||
virtual TemporaryRef<Path> BuildPath() MOZ_OVERRIDE;
|
||||
virtual TemporaryRef<Path> BuildPath(PathBuilder* aBuilder = nullptr) MOZ_OVERRIDE;
|
||||
|
||||
virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult) const MOZ_OVERRIDE;
|
||||
|
||||
|
|
|
@ -111,15 +111,3 @@ nsSVGPathGeometryElement::GetFillRule()
|
|||
|
||||
return fillRule;
|
||||
}
|
||||
|
||||
Float
|
||||
nsSVGPathGeometryElement::GetStrokeWidth()
|
||||
{
|
||||
nsRefPtr<nsStyleContext> styleContext =
|
||||
nsComputedDOMStyle::GetStyleContextForElementNoFlush(this, nullptr,
|
||||
nullptr);
|
||||
return styleContext ?
|
||||
SVGContentUtils::CoordToFloat(this,
|
||||
styleContext->StyleSVG()->mStrokeWidth) :
|
||||
0.0f;
|
||||
}
|
||||
|
|
|
@ -62,7 +62,7 @@ public:
|
|||
* Returns a Path that can be used to paint, hit-test or calculate bounds for
|
||||
* this element. May return nullptr if there is no [valid] path.
|
||||
*/
|
||||
virtual mozilla::TemporaryRef<Path> BuildPath() = 0;
|
||||
virtual mozilla::TemporaryRef<Path> BuildPath(PathBuilder* aBuilder = nullptr) = 0;
|
||||
|
||||
virtual mozilla::TemporaryRef<Path> GetPathForLengthOrPositionMeasuring();
|
||||
|
||||
|
@ -77,14 +77,6 @@ public:
|
|||
* this element.
|
||||
*/
|
||||
FillRule GetFillRule();
|
||||
|
||||
/**
|
||||
* Returns the current computed value of the CSS property 'stroke-width' for
|
||||
* this element. (I.e. this does NOT take account of the value of the
|
||||
* 'stroke' and 'stroke-opacity' properties to, say, return zero if they are
|
||||
* "none" or "0", respectively.)
|
||||
*/
|
||||
Float GetStrokeWidth();
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -132,7 +132,7 @@ nsSVGPolyElement::ConstructPath(gfxContext *aCtx)
|
|||
}
|
||||
|
||||
TemporaryRef<Path>
|
||||
nsSVGPolyElement::BuildPath()
|
||||
nsSVGPolyElement::BuildPath(PathBuilder* aBuilder)
|
||||
{
|
||||
const SVGPointList &points = mPoints.GetAnimValue();
|
||||
|
||||
|
@ -140,7 +140,7 @@ nsSVGPolyElement::BuildPath()
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
RefPtr<PathBuilder> pathBuilder = CreatePathBuilder();
|
||||
RefPtr<PathBuilder> pathBuilder = aBuilder ? aBuilder : CreatePathBuilder();
|
||||
|
||||
pathBuilder->MoveTo(points[0]);
|
||||
for (uint32_t i = 1; i < points.Length(); ++i) {
|
||||
|
|
|
@ -46,7 +46,7 @@ public:
|
|||
virtual bool IsMarkable() MOZ_OVERRIDE { return true; }
|
||||
virtual void GetMarkPoints(nsTArray<nsSVGMark> *aMarks) MOZ_OVERRIDE;
|
||||
virtual void ConstructPath(gfxContext *aCtx) MOZ_OVERRIDE;
|
||||
virtual mozilla::TemporaryRef<Path> BuildPath() MOZ_OVERRIDE;
|
||||
virtual mozilla::TemporaryRef<Path> BuildPath(PathBuilder* aBuilder = nullptr) MOZ_OVERRIDE;
|
||||
|
||||
// WebIDL
|
||||
already_AddRefed<mozilla::DOMSVGPointList> Points();
|
||||
|
|
|
@ -6,6 +6,13 @@ text { font: 20px monospace; }
|
|||
</style>
|
||||
|
||||
<g id="g">
|
||||
<svg id="svg1" x="10" y="10" width="25" height="30"/>
|
||||
<svg id="svg2" width="1" height="1" overflow="visible">
|
||||
<rect width="2" height="2" fill="yellow"/>
|
||||
</svg>
|
||||
<svg id="svg3" width="1" height="1" overflow="hidden">
|
||||
<rect width="2" height="2" fill="yellow"/>
|
||||
</svg>
|
||||
<text id="text1" x="25" y="25">abc</text>
|
||||
<text id="text1a" x="85" y="25" stroke="black" stroke-width="4">abc</text>
|
||||
<rect id="rect1" x="50" y="50" width="50" height="50" fill="green"/>
|
||||
|
|
До Ширина: | Высота: | Размер: 1.7 KiB После Ширина: | Высота: | Размер: 2.0 KiB |
|
@ -44,6 +44,24 @@ function runTest()
|
|||
{
|
||||
var doc = $("svg").contentWindow.document;
|
||||
|
||||
var svg1Bounds = doc.getElementById("svg1").getBoundingClientRect();
|
||||
is(svg1Bounds.left, 10, "svg1.getBoundingClientRect().left");
|
||||
is(svg1Bounds.top, 10, "svg1.getBoundingClientRect().top");
|
||||
is(svg1Bounds.width, 25, "svg1.getBoundingClientRect().width");
|
||||
is(svg1Bounds.height, 30, "svg1.getBoundingClientRect().height");
|
||||
|
||||
var svg2Bounds = doc.getElementById("svg2").getBoundingClientRect();
|
||||
is(svg2Bounds.left, 0, "svg2.getBoundingClientRect().left");
|
||||
is(svg2Bounds.top, 0, "svg2.getBoundingClientRect().top");
|
||||
is(svg2Bounds.width, 2, "svg2.getBoundingClientRect().width");
|
||||
is(svg2Bounds.height, 2, "svg2.getBoundingClientRect().height");
|
||||
|
||||
var svg3Bounds = doc.getElementById("svg3").getBoundingClientRect();
|
||||
is(svg3Bounds.left, 0, "svg3.getBoundingClientRect().left");
|
||||
is(svg3Bounds.top, 0, "svg3.getBoundingClientRect().top");
|
||||
is(svg3Bounds.width, 1, "svg3.getBoundingClientRect().width");
|
||||
is(svg3Bounds.height, 1, "svg3.getBoundingClientRect().height");
|
||||
|
||||
var text1 = doc.getElementById("text1");
|
||||
|
||||
var text1Bounds = text1.getBoundingClientRect();
|
||||
|
|
|
@ -22,7 +22,7 @@ function run()
|
|||
var originY = div.offsetTop;
|
||||
var circle = document.getElementById("circle");
|
||||
|
||||
var elementFromPoint = document.elementFromPoint(originX + 150, originY + 51);
|
||||
var elementFromPoint = document.elementFromPoint(originX + 150, originY + 52);
|
||||
is(elementFromPoint, circle, "Top of circle should hit");
|
||||
|
||||
var elementFromPoint = document.elementFromPoint(originX + 249, originY + 150);
|
||||
|
@ -44,10 +44,10 @@ function run()
|
|||
<div id="content">
|
||||
|
||||
<div width="100%" height="1" id="div">
|
||||
</div>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="100%" height="400" id="svg">
|
||||
<circle id="circle" cx="1.5" cy="1.5" r="1" transform="scale(100, 100)"/>
|
||||
</svg>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<pre id="test">
|
||||
|
|
|
@ -2135,7 +2135,7 @@ this.DOMApplicationRegistry = {
|
|||
if (xhr.status == 200) {
|
||||
if (!AppsUtils.checkManifestContentType(app.installOrigin, app.origin,
|
||||
xhr.getResponseHeader("content-type"))) {
|
||||
sendError("INVALID_MANIFEST");
|
||||
sendError("INVALID_MANIFEST_CONTENT_TYPE");
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -2235,7 +2235,7 @@ this.DOMApplicationRegistry = {
|
|||
if (xhr.status == 200) {
|
||||
if (!AppsUtils.checkManifestContentType(app.installOrigin, app.origin,
|
||||
xhr.getResponseHeader("content-type"))) {
|
||||
sendError("INVALID_MANIFEST");
|
||||
sendError("INVALID_MANIFEST_CONTENT_TYPE");
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -110,7 +110,7 @@ var steps = [
|
|||
var miniManifestURL = PackagedTestHelper.gSJS +
|
||||
"?getManifest=true" +
|
||||
"&noManifestContentType=true";
|
||||
checkAppInstallError(miniManifestURL, "INVALID_MANIFEST");
|
||||
checkAppInstallError(miniManifestURL, "INVALID_MANIFEST_CONTENT_TYPE");
|
||||
},
|
||||
function() {
|
||||
// Test mini-manifest 'size' value is not number. Bug 839435.
|
||||
|
|
|
@ -68,6 +68,8 @@ public:
|
|||
|
||||
private:
|
||||
IDBDatabase* mDatabase;
|
||||
|
||||
~VersionChangeListener() {}
|
||||
};
|
||||
|
||||
NS_IMPL_ISUPPORTS(VersionChangeListener, nsIDOMEventListener)
|
||||
|
|
|
@ -32,9 +32,12 @@
|
|||
</hbox>
|
||||
</vbox>
|
||||
|
||||
<!-- wrap svg in a div so that it can take its intrinsic width -->
|
||||
<div>
|
||||
<svg:svg id="svgbase" width="45" height="20" xmlns:svg="http://www.w3.org/2000/svg">
|
||||
<svg:rect id="svgrect" x="3" y="5" width="45" height="20" fill="red"/>
|
||||
</svg:svg>
|
||||
</div>
|
||||
|
||||
</vbox>
|
||||
|
||||
|
|
|
@ -91,7 +91,7 @@ function invalidContent(next) {
|
|||
var request = navigator.mozApps.install(url, null);
|
||||
|
||||
request.onerror = function onInstallError() {
|
||||
is(this.error.name, "INVALID_MANIFEST", "manifest with bad content type");
|
||||
is(this.error.name, "INVALID_MANIFEST_CONTENT_TYPE", "manifest with bad content type");
|
||||
next();
|
||||
};
|
||||
|
||||
|
|
|
@ -213,6 +213,9 @@ class ServiceWorkerUpdateInstance MOZ_FINAL : public nsISupports
|
|||
nsCOMPtr<nsPIDOMWindow> mWindow;
|
||||
|
||||
bool mAborted;
|
||||
|
||||
~ServiceWorkerUpdateInstance() {}
|
||||
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
|
||||
|
|
|
@ -1,15 +0,0 @@
|
|||
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||
<head>
|
||||
<script>
|
||||
<![CDATA[
|
||||
|
||||
function boom()
|
||||
{
|
||||
document.createElement("head").innerHTML = "<";
|
||||
}
|
||||
|
||||
]]>
|
||||
</script></head>
|
||||
|
||||
<body onload="boom();"></body>
|
||||
</html>
|
|
@ -17,14 +17,16 @@
|
|||
|
||||
class nsPrintProgress : public nsIPrintProgress, public nsIPrintStatusFeedback
|
||||
{
|
||||
public:
|
||||
public:
|
||||
NS_DECL_THREADSAFE_ISUPPORTS
|
||||
NS_DECL_NSIPRINTPROGRESS
|
||||
NS_DECL_NSIWEBPROGRESSLISTENER
|
||||
NS_DECL_NSIPRINTSTATUSFEEDBACK
|
||||
|
||||
nsPrintProgress();
|
||||
virtual ~nsPrintProgress();
|
||||
nsPrintProgress();
|
||||
|
||||
protected:
|
||||
virtual ~nsPrintProgress();
|
||||
|
||||
private:
|
||||
nsresult ReleaseListeners();
|
||||
|
|
|
@ -11,12 +11,14 @@
|
|||
|
||||
class nsPrintProgressParams : public nsIPrintProgressParams
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSIPRINTPROGRESSPARAMS
|
||||
|
||||
nsPrintProgressParams();
|
||||
virtual ~nsPrintProgressParams();
|
||||
nsPrintProgressParams();
|
||||
|
||||
protected:
|
||||
virtual ~nsPrintProgressParams();
|
||||
|
||||
private:
|
||||
nsString mDocTitle;
|
||||
|
|
|
@ -30,7 +30,6 @@ class nsPrintingPromptService: public nsIPrintingPromptService,
|
|||
{
|
||||
public:
|
||||
nsPrintingPromptService();
|
||||
virtual ~nsPrintingPromptService();
|
||||
|
||||
nsresult Init();
|
||||
|
||||
|
@ -38,6 +37,9 @@ public:
|
|||
NS_DECL_NSIWEBPROGRESSLISTENER
|
||||
NS_DECL_ISUPPORTS
|
||||
|
||||
protected:
|
||||
virtual ~nsPrintingPromptService();
|
||||
|
||||
private:
|
||||
nsCOMPtr<nsIPrintProgress> mPrintProgress;
|
||||
};
|
||||
|
|
|
@ -8,6 +8,10 @@
|
|||
|
||||
#include "mozilla/RefPtr.h"
|
||||
#include "mozilla/NullPtr.h"
|
||||
#include "mozilla/Likely.h"
|
||||
#include "MainThreadUtils.h"
|
||||
#include "base/message_loop.h"
|
||||
#include "base/task.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
|
@ -18,10 +22,21 @@ class AtomicRefCountedWithFinalize
|
|||
AtomicRefCountedWithFinalize()
|
||||
: mRecycleCallback(nullptr)
|
||||
, mRefCount(0)
|
||||
, mMessageLoopToPostDestructionTo(nullptr)
|
||||
{}
|
||||
|
||||
~AtomicRefCountedWithFinalize() {}
|
||||
|
||||
void SetMessageLoopToPostDestructionTo(MessageLoop* l) {
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
mMessageLoopToPostDestructionTo = l;
|
||||
}
|
||||
|
||||
static void DestroyToBeCalledOnMainThread(T* ptr) {
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
delete ptr;
|
||||
}
|
||||
|
||||
public:
|
||||
void AddRef() {
|
||||
MOZ_ASSERT(mRefCount >= 0);
|
||||
|
@ -43,7 +58,17 @@ class AtomicRefCountedWithFinalize
|
|||
#endif
|
||||
T* derived = static_cast<T*>(this);
|
||||
derived->Finalize();
|
||||
delete derived;
|
||||
if (MOZ_LIKELY(!mMessageLoopToPostDestructionTo)) {
|
||||
delete derived;
|
||||
} else {
|
||||
if (MOZ_LIKELY(NS_IsMainThread())) {
|
||||
delete derived;
|
||||
} else {
|
||||
mMessageLoopToPostDestructionTo->PostTask(
|
||||
FROM_HERE,
|
||||
NewRunnableFunction(&DestroyToBeCalledOnMainThread, derived));
|
||||
}
|
||||
}
|
||||
} else if (1 == currCount && recycleCallback) {
|
||||
T* derived = static_cast<T*>(this);
|
||||
recycleCallback(derived, mClosure);
|
||||
|
@ -71,6 +96,7 @@ private:
|
|||
RecycleCallback mRecycleCallback;
|
||||
void *mClosure;
|
||||
Atomic<int> mRefCount;
|
||||
MessageLoop *mMessageLoopToPostDestructionTo;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -18,7 +18,6 @@
|
|||
#include "basic/BasicLayers.h" // for BasicLayerManager, etc
|
||||
#include "gfx3DMatrix.h" // for gfx3DMatrix
|
||||
#include "gfxASurface.h" // for gfxASurface, etc
|
||||
#include "gfxCachedTempSurface.h" // for gfxCachedTempSurface
|
||||
#include "gfxColor.h" // for gfxRGBA
|
||||
#include "gfxContext.h" // for gfxContext, etc
|
||||
#include "gfxImageSurface.h" // for gfxImageSurface
|
||||
|
@ -98,7 +97,8 @@ BasicLayerManager::PushGroupForLayer(gfxContext* aContext, Layer* aLayer,
|
|||
// clipped precisely to the visible region.
|
||||
*aNeedsClipToVisibleRegion = !didCompleteClip || aRegion.GetNumRects() > 1;
|
||||
MOZ_ASSERT(!aContext->IsCairo());
|
||||
result = PushGroupWithCachedSurface(aContext, gfxContentType::COLOR);
|
||||
aContext->PushGroup(gfxContentType::COLOR);
|
||||
result = aContext;
|
||||
} else {
|
||||
*aNeedsClipToVisibleRegion = false;
|
||||
result = aContext;
|
||||
|
@ -235,7 +235,6 @@ BasicLayerManager::BasicLayerManager(nsIWidget* aWidget) :
|
|||
mPhase(PHASE_NONE),
|
||||
mWidget(aWidget)
|
||||
, mDoubleBuffering(BufferMode::BUFFER_NONE), mUsingDefaultTarget(false)
|
||||
, mCachedSurfaceInUse(false)
|
||||
, mTransactionIncomplete(false)
|
||||
, mCompositorMightResample(false)
|
||||
{
|
||||
|
@ -247,7 +246,6 @@ BasicLayerManager::BasicLayerManager() :
|
|||
mPhase(PHASE_NONE),
|
||||
mWidget(nullptr)
|
||||
, mDoubleBuffering(BufferMode::BUFFER_NONE), mUsingDefaultTarget(false)
|
||||
, mCachedSurfaceInUse(false)
|
||||
, mTransactionIncomplete(false)
|
||||
{
|
||||
MOZ_COUNT_CTOR(BasicLayerManager);
|
||||
|
@ -286,53 +284,6 @@ BasicLayerManager::BeginTransaction()
|
|||
BeginTransactionWithTarget(mDefaultTarget);
|
||||
}
|
||||
|
||||
already_AddRefed<gfxContext>
|
||||
BasicLayerManager::PushGroupWithCachedSurface(gfxContext *aTarget,
|
||||
gfxContentType aContent)
|
||||
{
|
||||
nsRefPtr<gfxContext> ctx;
|
||||
// We can't cache Azure DrawTargets at this point.
|
||||
if (!mCachedSurfaceInUse && aTarget->IsCairo()) {
|
||||
gfxContextMatrixAutoSaveRestore saveMatrix(aTarget);
|
||||
aTarget->IdentityMatrix();
|
||||
|
||||
nsRefPtr<gfxASurface> currentSurf = aTarget->CurrentSurface();
|
||||
gfxRect clip = aTarget->GetClipExtents();
|
||||
clip.RoundOut();
|
||||
|
||||
ctx = mCachedSurface.Get(aContent, clip, currentSurf);
|
||||
|
||||
if (ctx) {
|
||||
mCachedSurfaceInUse = true;
|
||||
/* Align our buffer for the original surface */
|
||||
ctx->SetMatrix(saveMatrix.Matrix());
|
||||
return ctx.forget();
|
||||
}
|
||||
}
|
||||
|
||||
ctx = aTarget;
|
||||
ctx->PushGroup(aContent);
|
||||
return ctx.forget();
|
||||
}
|
||||
|
||||
void
|
||||
BasicLayerManager::PopGroupToSourceWithCachedSurface(gfxContext *aTarget, gfxContext *aPushed)
|
||||
{
|
||||
if (!aTarget)
|
||||
return;
|
||||
if (aTarget->IsCairo()) {
|
||||
nsRefPtr<gfxASurface> current = aPushed->CurrentSurface();
|
||||
if (mCachedSurface.IsSurface(current)) {
|
||||
gfxContextMatrixAutoSaveRestore saveMatrix(aTarget);
|
||||
aTarget->IdentityMatrix();
|
||||
aTarget->SetSource(current);
|
||||
mCachedSurfaceInUse = false;
|
||||
return;
|
||||
}
|
||||
}
|
||||
aTarget->PopGroupToSource();
|
||||
}
|
||||
|
||||
void
|
||||
BasicLayerManager::BeginTransactionWithTarget(gfxContext* aTarget)
|
||||
{
|
||||
|
@ -924,7 +875,7 @@ BasicLayerManager::PaintLayer(gfxContext* aTarget,
|
|||
nsRefPtr<gfxContext> groupTarget = PushGroupForLayer(aTarget, aLayer, aLayer->GetEffectiveVisibleRegion(),
|
||||
&needsClipToVisibleRegion);
|
||||
PaintSelfOrChildren(paintLayerContext, groupTarget);
|
||||
PopGroupToSourceWithCachedSurface(aTarget, groupTarget);
|
||||
aTarget->PopGroupToSource();
|
||||
FlushGroup(paintLayerContext, needsClipToVisibleRegion);
|
||||
} else {
|
||||
PaintSelfOrChildren(paintLayerContext, aTarget);
|
||||
|
@ -988,7 +939,6 @@ BasicLayerManager::ClearCachedResources(Layer* aSubtree)
|
|||
} else if (mRoot) {
|
||||
ClearLayer(mRoot);
|
||||
}
|
||||
mCachedSurface.Expire();
|
||||
}
|
||||
void
|
||||
BasicLayerManager::ClearLayer(Layer* aLayer)
|
||||
|
|
|
@ -9,7 +9,6 @@
|
|||
#include <stdint.h> // for INT32_MAX, int32_t
|
||||
#include "Layers.h" // for Layer (ptr only), etc
|
||||
#include "gfxTypes.h"
|
||||
#include "gfxCachedTempSurface.h" // for gfxCachedTempSurface
|
||||
#include "gfxContext.h" // for gfxContext
|
||||
#include "mozilla/Attributes.h" // for MOZ_OVERRIDE
|
||||
#include "mozilla/WidgetUtils.h" // for ScreenRotation
|
||||
|
@ -136,9 +135,6 @@ public:
|
|||
already_AddRefed<gfxContext> PushGroupForLayer(gfxContext* aContext, Layer* aLayer,
|
||||
const nsIntRegion& aRegion,
|
||||
bool* aNeedsClipToVisibleRegion);
|
||||
already_AddRefed<gfxContext> PushGroupWithCachedSurface(gfxContext *aTarget,
|
||||
gfxContentType aContent);
|
||||
void PopGroupToSourceWithCachedSurface(gfxContext *aTarget, gfxContext *aPushed);
|
||||
|
||||
virtual bool IsCompositingCheap() { return false; }
|
||||
virtual int32_t GetMaxTextureSize() const { return INT32_MAX; }
|
||||
|
@ -186,12 +182,8 @@ protected:
|
|||
// Image factory we use.
|
||||
nsRefPtr<ImageFactory> mFactory;
|
||||
|
||||
// Cached surface for double buffering
|
||||
gfxCachedTempSurface mCachedSurface;
|
||||
|
||||
BufferMode mDoubleBuffering;
|
||||
bool mUsingDefaultTarget;
|
||||
bool mCachedSurfaceInUse;
|
||||
bool mTransactionIncomplete;
|
||||
bool mCompositorMightResample;
|
||||
};
|
||||
|
|
|
@ -93,7 +93,7 @@ BasicThebesLayer::PaintThebes(gfxContext* aContext,
|
|||
SetAntialiasingFlags(this, groupContext);
|
||||
aCallback(this, groupContext, toDraw, DrawRegionClip::CLIP_NONE, nsIntRegion(), aCallbackData);
|
||||
if (needsGroup) {
|
||||
BasicManager()->PopGroupToSourceWithCachedSurface(aContext, groupContext);
|
||||
aContext->PopGroupToSource();
|
||||
if (needsClipToVisibleRegion) {
|
||||
gfxUtils::ClipToRegion(aContext, toDraw);
|
||||
}
|
||||
|
|
|
@ -471,11 +471,12 @@ static void
|
|||
FillSurface(gfxASurface* aSurface, const nsIntRegion& aRegion,
|
||||
const nsIntPoint& aOffset, const gfxRGBA& aColor)
|
||||
{
|
||||
nsRefPtr<gfxContext> ctx = new gfxContext(aSurface);
|
||||
ctx->Translate(-gfxPoint(aOffset.x, aOffset.y));
|
||||
gfxUtils::ClipToRegion(ctx, aRegion);
|
||||
ctx->SetColor(aColor);
|
||||
ctx->Paint();
|
||||
nsIntRegionRectIterator iter(aRegion);
|
||||
const nsIntRect* r;
|
||||
while ((r = iter.Next()) != nullptr) {
|
||||
nsIntRect rect = *r + aOffset;
|
||||
gfxUtils::ClearThebesSurface(aSurface, &rect, aColor);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -526,17 +527,13 @@ ThebesLayerD3D9::DrawRegion(nsIntRegion &aRegion, SurfaceMode aMode,
|
|||
if (!destinationSurface)
|
||||
return;
|
||||
|
||||
nsRefPtr<gfxContext> context;
|
||||
if (gfxPlatform::GetPlatform()->SupportsAzureContentForType(BackendType::CAIRO)) {
|
||||
RefPtr<DrawTarget> dt =
|
||||
gfxPlatform::GetPlatform()->CreateDrawTargetForSurface(destinationSurface,
|
||||
IntSize(destinationSurface->GetSize().width,
|
||||
destinationSurface->GetSize().height));
|
||||
MOZ_ASSERT(gfxPlatform::GetPlatform()->SupportsAzureContentForType(BackendType::CAIRO));
|
||||
RefPtr<DrawTarget> dt =
|
||||
gfxPlatform::GetPlatform()->CreateDrawTargetForSurface(destinationSurface,
|
||||
IntSize(destinationSurface->GetSize().width,
|
||||
destinationSurface->GetSize().height));
|
||||
|
||||
context = new gfxContext(dt);
|
||||
} else {
|
||||
context = new gfxContext(destinationSurface);
|
||||
}
|
||||
nsRefPtr<gfxContext> context = new gfxContext(dt);
|
||||
|
||||
context->Translate(gfxPoint(-bounds.x, -bounds.y));
|
||||
LayerManagerD3D9::CallbackInfo cbInfo = mD3DManager->GetCallbackInfo();
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
#include "nsCOMPtr.h" // for nsCOMPtr
|
||||
#include "nsHashKeys.h" // for nsUint64HashKey
|
||||
#include "nsISupportsImpl.h" // for NS_INLINE_DECL_REFCOUNTING
|
||||
#include "ThreadSafeRefcountingWithMainThreadDestruction.h"
|
||||
|
||||
class nsIObserver;
|
||||
|
||||
|
@ -29,7 +30,8 @@ struct FrameMetrics;
|
|||
|
||||
class CompositorChild MOZ_FINAL : public PCompositorChild
|
||||
{
|
||||
NS_INLINE_DECL_REFCOUNTING(CompositorChild)
|
||||
NS_INLINE_DECL_THREADSAFE_REFCOUNTING_WITH_MAIN_THREAD_DESTRUCTION(CompositorChild)
|
||||
|
||||
public:
|
||||
CompositorChild(ClientLayerManager *aLayerManager);
|
||||
|
||||
|
|
|
@ -53,6 +53,7 @@
|
|||
#include "mozilla/unused.h"
|
||||
#include "mozilla/Hal.h"
|
||||
#include "mozilla/HalTypes.h"
|
||||
#include "mozilla/StaticPtr.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace layers {
|
||||
|
@ -73,64 +74,65 @@ CompositorParent::LayerTreeState::LayerTreeState()
|
|||
typedef map<uint64_t, CompositorParent::LayerTreeState> LayerTreeMap;
|
||||
static LayerTreeMap sIndirectLayerTrees;
|
||||
|
||||
// FIXME/bug 774386: we're assuming that there's only one
|
||||
// CompositorParent, but that's not always true. This assumption only
|
||||
// affects CrossProcessCompositorParent below.
|
||||
static Thread* sCompositorThread = nullptr;
|
||||
// manual reference count of the compositor thread.
|
||||
static int sCompositorThreadRefCount = 0;
|
||||
static MessageLoop* sMainLoop = nullptr;
|
||||
/**
|
||||
* A global map referencing each compositor by ID.
|
||||
*
|
||||
* This map is used by the ImageBridge protocol to trigger
|
||||
* compositions without having to keep references to the
|
||||
* compositor
|
||||
*/
|
||||
typedef map<uint64_t,CompositorParent*> CompositorMap;
|
||||
static CompositorMap* sCompositorMap;
|
||||
|
||||
static void CreateCompositorMap()
|
||||
{
|
||||
MOZ_ASSERT(!sCompositorMap);
|
||||
sCompositorMap = new CompositorMap;
|
||||
}
|
||||
|
||||
static void DestroyCompositorMap()
|
||||
{
|
||||
MOZ_ASSERT(sCompositorMap);
|
||||
MOZ_ASSERT(sCompositorMap->empty());
|
||||
delete sCompositorMap;
|
||||
sCompositorMap = nullptr;
|
||||
}
|
||||
|
||||
// See ImageBridgeChild.cpp
|
||||
void ReleaseImageBridgeParentSingleton();
|
||||
|
||||
static void DeferredDeleteCompositorParent(CompositorParent* aNowReadyToDie)
|
||||
CompositorThreadHolder::CompositorThreadHolder()
|
||||
: mCompositorThread(CreateCompositorThread())
|
||||
{
|
||||
aNowReadyToDie->Release();
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
MOZ_COUNT_CTOR(CompositorThreadHolder);
|
||||
}
|
||||
|
||||
static void DeleteCompositorThread()
|
||||
CompositorThreadHolder::~CompositorThreadHolder()
|
||||
{
|
||||
if (NS_IsMainThread()){
|
||||
ReleaseImageBridgeParentSingleton();
|
||||
delete sCompositorThread;
|
||||
sCompositorThread = nullptr;
|
||||
} else {
|
||||
sMainLoop->PostTask(FROM_HERE, NewRunnableFunction(&DeleteCompositorThread));
|
||||
}
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
MOZ_COUNT_DTOR(CompositorThreadHolder);
|
||||
|
||||
DestroyCompositorThread(mCompositorThread);
|
||||
}
|
||||
|
||||
static void ReleaseCompositorThread()
|
||||
static StaticRefPtr<CompositorThreadHolder> sCompositorThreadHolder;
|
||||
static bool sFinishedCompositorShutDown = false;
|
||||
|
||||
CompositorThreadHolder* GetCompositorThreadHolder()
|
||||
{
|
||||
if(--sCompositorThreadRefCount == 0) {
|
||||
DeleteCompositorThread();
|
||||
}
|
||||
return sCompositorThreadHolder;
|
||||
}
|
||||
|
||||
static void SetThreadPriority()
|
||||
/* static */ Thread*
|
||||
CompositorThreadHolder::CreateCompositorThread()
|
||||
{
|
||||
hal::SetCurrentThreadPriority(hal::THREAD_PRIORITY_COMPOSITOR);
|
||||
}
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
void CompositorParent::StartUp()
|
||||
{
|
||||
CreateCompositorMap();
|
||||
CreateThread();
|
||||
sMainLoop = MessageLoop::current();
|
||||
}
|
||||
MOZ_ASSERT(!sCompositorThreadHolder, "The compositor thread has already been started!");
|
||||
|
||||
void CompositorParent::ShutDown()
|
||||
{
|
||||
DestroyThread();
|
||||
DestroyCompositorMap();
|
||||
}
|
||||
|
||||
bool CompositorParent::CreateThread()
|
||||
{
|
||||
NS_ASSERTION(NS_IsMainThread(), "Should be on the main Thread!");
|
||||
MOZ_ASSERT(!sCompositorThread);
|
||||
sCompositorThreadRefCount = 1;
|
||||
sCompositorThread = new Thread("Compositor");
|
||||
Thread* compositorThread = new Thread("Compositor");
|
||||
|
||||
Thread::Options options;
|
||||
/* Timeout values are powers-of-two to enable us get better data.
|
||||
|
@ -141,24 +143,64 @@ bool CompositorParent::CreateThread()
|
|||
than the default hang timeout on major platforms (about 5 seconds). */
|
||||
options.permanent_hang_timeout = 8192; // milliseconds
|
||||
|
||||
if (!sCompositorThread->StartWithOptions(options)) {
|
||||
delete sCompositorThread;
|
||||
sCompositorThread = nullptr;
|
||||
return false;
|
||||
if (!compositorThread->StartWithOptions(options)) {
|
||||
delete compositorThread;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return true;
|
||||
CreateCompositorMap();
|
||||
|
||||
return compositorThread;
|
||||
}
|
||||
|
||||
void CompositorParent::DestroyThread()
|
||||
/* static */ void
|
||||
CompositorThreadHolder::DestroyCompositorThread(Thread* aCompositorThread)
|
||||
{
|
||||
NS_ASSERTION(NS_IsMainThread(), "Should be on the main Thread!");
|
||||
ReleaseCompositorThread();
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
MOZ_ASSERT(!sCompositorThreadHolder, "We shouldn't be destroying the compositor thread yet.");
|
||||
|
||||
DestroyCompositorMap();
|
||||
delete aCompositorThread;
|
||||
sFinishedCompositorShutDown = true;
|
||||
}
|
||||
|
||||
static Thread* CompositorThread() {
|
||||
return sCompositorThreadHolder ? sCompositorThreadHolder->GetCompositorThread() : nullptr;
|
||||
}
|
||||
|
||||
static void SetThreadPriority()
|
||||
{
|
||||
hal::SetCurrentThreadPriority(hal::THREAD_PRIORITY_COMPOSITOR);
|
||||
}
|
||||
|
||||
void CompositorParent::StartUp()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread(), "Should be on the main Thread!");
|
||||
MOZ_ASSERT(!sCompositorThreadHolder, "The compositor thread has already been started!");
|
||||
|
||||
sCompositorThreadHolder = new CompositorThreadHolder();
|
||||
}
|
||||
|
||||
void CompositorParent::ShutDown()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread(), "Should be on the main Thread!");
|
||||
MOZ_ASSERT(sCompositorThreadHolder, "The compositor thread has already been shut down!");
|
||||
|
||||
ReleaseImageBridgeParentSingleton();
|
||||
|
||||
sCompositorThreadHolder = nullptr;
|
||||
|
||||
// No locking is needed around sFinishedCompositorShutDown because it is only
|
||||
// ever accessed on the main thread.
|
||||
while (!sFinishedCompositorShutDown) {
|
||||
NS_ProcessNextEvent(nullptr, true);
|
||||
}
|
||||
}
|
||||
|
||||
MessageLoop* CompositorParent::CompositorLoop()
|
||||
{
|
||||
return sCompositorThread ? sCompositorThread->message_loop() : nullptr;
|
||||
return CompositorThread() ? CompositorThread()->message_loop() : nullptr;
|
||||
}
|
||||
|
||||
CompositorParent::CompositorParent(nsIWidget* aWidget,
|
||||
|
@ -175,9 +217,11 @@ CompositorParent::CompositorParent(nsIWidget* aWidget,
|
|||
, mResumeCompositionMonitor("ResumeCompositionMonitor")
|
||||
, mOverrideComposeReadiness(false)
|
||||
, mForceCompositionTask(nullptr)
|
||||
, mCompositorThreadHolder(sCompositorThreadHolder)
|
||||
{
|
||||
MOZ_ASSERT(sCompositorThread != nullptr,
|
||||
"The compositor thread must be Initialized before instanciating a CmpositorParent.");
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
MOZ_ASSERT(CompositorThread(),
|
||||
"The compositor thread must be Initialized before instanciating a CompositorParent.");
|
||||
MOZ_COUNT_CTOR(CompositorParent);
|
||||
mCompositorID = 0;
|
||||
// FIXME: This holds on the the fact that right now the only thing that
|
||||
|
@ -192,13 +236,12 @@ CompositorParent::CompositorParent(nsIWidget* aWidget,
|
|||
sIndirectLayerTrees[mRootLayerTreeID].mParent = this;
|
||||
|
||||
mApzcTreeManager = new APZCTreeManager();
|
||||
++sCompositorThreadRefCount;
|
||||
}
|
||||
|
||||
bool
|
||||
CompositorParent::IsInCompositorThread()
|
||||
{
|
||||
return sCompositorThread && sCompositorThread->thread_id() == PlatformThread::CurrentId();
|
||||
return CompositorThread() && CompositorThread()->thread_id() == PlatformThread::CurrentId();
|
||||
}
|
||||
|
||||
uint64_t
|
||||
|
@ -209,9 +252,8 @@ CompositorParent::RootLayerTreeId()
|
|||
|
||||
CompositorParent::~CompositorParent()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
MOZ_COUNT_DTOR(CompositorParent);
|
||||
|
||||
ReleaseCompositorThread();
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -264,6 +306,13 @@ CompositorParent::RecvWillStop()
|
|||
return true;
|
||||
}
|
||||
|
||||
void CompositorParent::DeferredDestroy()
|
||||
{
|
||||
MOZ_ASSERT(!NS_IsMainThread());
|
||||
mCompositorThreadHolder = nullptr;
|
||||
Release();
|
||||
}
|
||||
|
||||
bool
|
||||
CompositorParent::RecvStop()
|
||||
{
|
||||
|
@ -273,10 +322,9 @@ CompositorParent::RecvStop()
|
|||
// this thread.
|
||||
// We must keep the compositor parent alive untill the code handling message
|
||||
// reception is finished on this thread.
|
||||
this->AddRef(); // Corresponds to DeferredDeleteCompositorParent's Release
|
||||
CompositorLoop()->PostTask(FROM_HERE,
|
||||
NewRunnableFunction(&DeferredDeleteCompositorParent,
|
||||
this));
|
||||
this->AddRef(); // Corresponds to DeferredDestroy's Release
|
||||
MessageLoop::current()->PostTask(FROM_HERE,
|
||||
NewRunnableMethod(this,&CompositorParent::DeferredDestroy));
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -921,27 +969,6 @@ CompositorParent::DeallocPLayerTransactionParent(PLayerTransactionParent* actor)
|
|||
return true;
|
||||
}
|
||||
|
||||
|
||||
typedef map<uint64_t,CompositorParent*> CompositorMap;
|
||||
static CompositorMap* sCompositorMap;
|
||||
|
||||
void CompositorParent::CreateCompositorMap()
|
||||
{
|
||||
if (sCompositorMap == nullptr) {
|
||||
sCompositorMap = new CompositorMap;
|
||||
}
|
||||
}
|
||||
|
||||
void CompositorParent::DestroyCompositorMap()
|
||||
{
|
||||
if (sCompositorMap != nullptr) {
|
||||
NS_ASSERTION(sCompositorMap->empty(),
|
||||
"The Compositor map should be empty when destroyed>");
|
||||
delete sCompositorMap;
|
||||
sCompositorMap = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
CompositorParent* CompositorParent::GetCompositor(uint64_t id)
|
||||
{
|
||||
CompositorMap::iterator it = sCompositorMap->find(id);
|
||||
|
@ -1077,12 +1104,15 @@ class CrossProcessCompositorParent MOZ_FINAL : public PCompositorParent,
|
|||
{
|
||||
friend class CompositorParent;
|
||||
|
||||
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(CrossProcessCompositorParent)
|
||||
NS_INLINE_DECL_THREADSAFE_REFCOUNTING_WITH_MAIN_THREAD_DESTRUCTION(CrossProcessCompositorParent)
|
||||
public:
|
||||
CrossProcessCompositorParent(Transport* aTransport, ProcessId aOtherProcess)
|
||||
: mTransport(aTransport)
|
||||
, mChildProcessId(aOtherProcess)
|
||||
{}
|
||||
, mCompositorThreadHolder(sCompositorThreadHolder)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
}
|
||||
|
||||
// IToplevelProtocol::CloneToplevel()
|
||||
virtual IToplevelProtocol*
|
||||
|
@ -1145,6 +1175,8 @@ private:
|
|||
Transport* mTransport;
|
||||
// Child side's process Id.
|
||||
base::ProcessId mChildProcessId;
|
||||
|
||||
nsRefPtr<CompositorThreadHolder> mCompositorThreadHolder;
|
||||
};
|
||||
|
||||
void
|
||||
|
@ -1176,6 +1208,8 @@ OpenCompositor(CrossProcessCompositorParent* aCompositor,
|
|||
/*static*/ PCompositorParent*
|
||||
CompositorParent::Create(Transport* aTransport, ProcessId aOtherProcess)
|
||||
{
|
||||
gfxPlatform::InitLayersIPC();
|
||||
|
||||
nsRefPtr<CrossProcessCompositorParent> cpcp =
|
||||
new CrossProcessCompositorParent(aTransport, aOtherProcess);
|
||||
ProcessHandle handle;
|
||||
|
@ -1404,16 +1438,14 @@ CrossProcessCompositorParent::GetCompositionManager(LayerTransactionParent* aLay
|
|||
void
|
||||
CrossProcessCompositorParent::DeferredDestroy()
|
||||
{
|
||||
CrossProcessCompositorParent* self;
|
||||
mSelfRef.forget(&self);
|
||||
|
||||
nsCOMPtr<nsIRunnable> runnable =
|
||||
NS_NewNonOwningRunnableMethod(self, &CrossProcessCompositorParent::Release);
|
||||
MOZ_ALWAYS_TRUE(NS_SUCCEEDED(NS_DispatchToMainThread(runnable)));
|
||||
mCompositorThreadHolder = nullptr;
|
||||
mSelfRef = nullptr;
|
||||
}
|
||||
|
||||
CrossProcessCompositorParent::~CrossProcessCompositorParent()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
MOZ_ASSERT(XRE_GetIOMessageLoop());
|
||||
XRE_GetIOMessageLoop()->PostTask(FROM_HERE,
|
||||
new DeleteTask<Transport>(mTransport));
|
||||
}
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
#include "ShadowLayersManager.h" // for ShadowLayersManager
|
||||
#include "base/basictypes.h" // for DISALLOW_EVIL_CONSTRUCTORS
|
||||
#include "base/platform_thread.h" // for PlatformThreadId
|
||||
#include "base/thread.h" // for Thread
|
||||
#include "mozilla/Assertions.h" // for MOZ_ASSERT_HELPER2
|
||||
#include "mozilla/Attributes.h" // for MOZ_OVERRIDE
|
||||
#include "mozilla/Monitor.h" // for Monitor
|
||||
|
@ -33,6 +34,7 @@
|
|||
#include "nsAutoPtr.h" // for nsRefPtr
|
||||
#include "nsISupportsImpl.h"
|
||||
#include "nsSize.h" // for nsIntSize
|
||||
#include "ThreadSafeRefcountingWithMainThreadDestruction.h"
|
||||
|
||||
class CancelableTask;
|
||||
class MessageLoop;
|
||||
|
@ -63,10 +65,32 @@ private:
|
|||
uint64_t mLayersId;
|
||||
};
|
||||
|
||||
class CompositorThreadHolder MOZ_FINAL
|
||||
{
|
||||
NS_INLINE_DECL_THREADSAFE_REFCOUNTING_WITH_MAIN_THREAD_DESTRUCTION(CompositorThreadHolder)
|
||||
|
||||
public:
|
||||
CompositorThreadHolder();
|
||||
|
||||
base::Thread* GetCompositorThread() const {
|
||||
return mCompositorThread;
|
||||
}
|
||||
|
||||
private:
|
||||
~CompositorThreadHolder();
|
||||
|
||||
base::Thread* const mCompositorThread;
|
||||
|
||||
static base::Thread* CreateCompositorThread();
|
||||
static void DestroyCompositorThread(base::Thread* aCompositorThread);
|
||||
|
||||
friend class CompositorParent;
|
||||
};
|
||||
|
||||
class CompositorParent : public PCompositorParent,
|
||||
public ShadowLayersManager
|
||||
{
|
||||
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(CompositorParent)
|
||||
NS_INLINE_DECL_THREADSAFE_REFCOUNTING_WITH_MAIN_THREAD_DESTRUCTION(CompositorParent)
|
||||
|
||||
public:
|
||||
CompositorParent(nsIWidget* aWidget,
|
||||
|
@ -166,7 +190,10 @@ public:
|
|||
static void StartUp();
|
||||
|
||||
/**
|
||||
* Destroys the compositor thread and the global compositor map.
|
||||
* Waits for all [CrossProcess]CompositorParent's to be gone,
|
||||
* and destroys the compositor thread and global compositor map.
|
||||
*
|
||||
* Does not return until all of that has completed.
|
||||
*/
|
||||
static void ShutDown();
|
||||
|
||||
|
@ -239,6 +266,8 @@ protected:
|
|||
// Protected destructor, to discourage deletion outside of Release():
|
||||
virtual ~CompositorParent();
|
||||
|
||||
void DeferredDestroy();
|
||||
|
||||
virtual PLayerTransactionParent*
|
||||
AllocPLayerTransactionParent(const nsTArray<LayersBackend>& aBackendHints,
|
||||
const uint64_t& aId,
|
||||
|
@ -259,36 +288,6 @@ protected:
|
|||
void ForceComposition();
|
||||
void CancelCurrentCompositeTask();
|
||||
|
||||
/**
|
||||
* Creates a global map referencing each compositor by ID.
|
||||
*
|
||||
* This map is used by the ImageBridge protocol to trigger
|
||||
* compositions without having to keep references to the
|
||||
* compositor
|
||||
*/
|
||||
static void CreateCompositorMap();
|
||||
static void DestroyCompositorMap();
|
||||
|
||||
/**
|
||||
* Creates the compositor thread.
|
||||
*
|
||||
* All compositors live on the same thread.
|
||||
* The thread is not lazily created on first access to avoid dealing with
|
||||
* thread safety. Therefore it's best to create and destroy the thread when
|
||||
* we know we areb't using it (So creating/destroying along with gfxPlatform
|
||||
* looks like a good place).
|
||||
*/
|
||||
static bool CreateThread();
|
||||
|
||||
/**
|
||||
* Destroys the compositor thread.
|
||||
*
|
||||
* It is safe to call this fucntion more than once, although the second call
|
||||
* will have no effect.
|
||||
* This function is not thread-safe.
|
||||
*/
|
||||
static void DestroyThread();
|
||||
|
||||
/**
|
||||
* Add a compositor to the global compositor map.
|
||||
*/
|
||||
|
@ -336,6 +335,8 @@ protected:
|
|||
|
||||
nsRefPtr<APZCTreeManager> mApzcTreeManager;
|
||||
|
||||
nsRefPtr<CompositorThreadHolder> mCompositorThreadHolder;
|
||||
|
||||
DISALLOW_EVIL_CONSTRUCTORS(CompositorParent);
|
||||
};
|
||||
|
||||
|
|
|
@ -221,7 +221,6 @@ static void ImageBridgeShutdownStep2(ReentrantMonitor *aBarrier, bool *aDone)
|
|||
|
||||
sImageBridgeChildSingleton->SendStop();
|
||||
|
||||
sImageBridgeChildSingleton = nullptr;
|
||||
*aDone = true;
|
||||
aBarrier->NotifyAll();
|
||||
}
|
||||
|
@ -248,10 +247,14 @@ static void ConnectImageBridge(ImageBridgeChild * child, ImageBridgeParent * par
|
|||
ImageBridgeChild::ImageBridgeChild()
|
||||
: mShuttingDown(false)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
mTxn = new CompositableTransaction();
|
||||
}
|
||||
ImageBridgeChild::~ImageBridgeChild()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
delete mTxn;
|
||||
}
|
||||
|
||||
|
@ -547,7 +550,7 @@ PImageBridgeChild*
|
|||
ImageBridgeChild::StartUpInChildProcess(Transport* aTransport,
|
||||
ProcessId aOtherProcess)
|
||||
{
|
||||
NS_ASSERTION(NS_IsMainThread(), "Should be on the main Thread!");
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
gfxPlatform::GetPlatform();
|
||||
|
||||
|
@ -572,7 +575,7 @@ ImageBridgeChild::StartUpInChildProcess(Transport* aTransport,
|
|||
|
||||
void ImageBridgeChild::ShutDown()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread(), "Should be on the main Thread!");
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
if (ImageBridgeChild::IsCreated()) {
|
||||
MOZ_ASSERT(!sImageBridgeChildSingleton->mShuttingDown);
|
||||
|
||||
|
@ -600,6 +603,8 @@ void ImageBridgeChild::ShutDown()
|
|||
}
|
||||
}
|
||||
|
||||
sImageBridgeChildSingleton = nullptr;
|
||||
|
||||
delete sImageBridgeChildThread;
|
||||
sImageBridgeChildThread = nullptr;
|
||||
}
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
#include "mozilla/layers/PImageBridgeChild.h"
|
||||
#include "nsDebug.h" // for NS_RUNTIMEABORT
|
||||
#include "nsRegion.h" // for nsIntRegion
|
||||
|
||||
class MessageLoop;
|
||||
struct nsIntPoint;
|
||||
struct nsIntRect;
|
||||
|
|
|
@ -44,13 +44,25 @@ using namespace mozilla::gfx;
|
|||
|
||||
std::map<base::ProcessId, ImageBridgeParent*> ImageBridgeParent::sImageBridges;
|
||||
|
||||
MessageLoop* ImageBridgeParent::sMainLoop = nullptr;
|
||||
|
||||
// defined in CompositorParent.cpp
|
||||
CompositorThreadHolder* GetCompositorThreadHolder();
|
||||
|
||||
ImageBridgeParent::ImageBridgeParent(MessageLoop* aLoop,
|
||||
Transport* aTransport,
|
||||
ProcessId aChildProcessId)
|
||||
: mMessageLoop(aLoop)
|
||||
, mTransport(aTransport)
|
||||
, mChildProcessId(aChildProcessId)
|
||||
, mCompositorThreadHolder(GetCompositorThreadHolder())
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
sMainLoop = MessageLoop::current();
|
||||
|
||||
// top-level actors must be destroyed on the main thread.
|
||||
SetMessageLoopToPostDestructionTo(sMainLoop);
|
||||
|
||||
// creates the map only if it has not been created already, so it is safe
|
||||
// with several bridges
|
||||
CompositableMap::Create();
|
||||
|
@ -59,10 +71,14 @@ ImageBridgeParent::ImageBridgeParent(MessageLoop* aLoop,
|
|||
|
||||
ImageBridgeParent::~ImageBridgeParent()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
if (mTransport) {
|
||||
MOZ_ASSERT(XRE_GetIOMessageLoop());
|
||||
XRE_GetIOMessageLoop()->PostTask(FROM_HERE,
|
||||
new DeleteTask<Transport>(mTransport));
|
||||
}
|
||||
|
||||
sImageBridges.erase(mChildProcessId);
|
||||
}
|
||||
|
||||
|
@ -160,10 +176,25 @@ bool ImageBridgeParent::RecvWillStop()
|
|||
return true;
|
||||
}
|
||||
|
||||
static void
|
||||
ReleaseImageBridgeParent(ImageBridgeParent* aImageBridgeParent)
|
||||
{
|
||||
aImageBridgeParent->Release();
|
||||
}
|
||||
|
||||
bool ImageBridgeParent::RecvStop()
|
||||
{
|
||||
// Nothing to do. This message just serves as synchronization between the
|
||||
// This message just serves as synchronization between the
|
||||
// child and parent threads during shutdown.
|
||||
|
||||
// There is one thing that we need to do here: temporarily addref, so that
|
||||
// the handling of this sync message can't race with the destruction of
|
||||
// the ImageBridgeParent, which would trigger the dreaded "mismatched CxxStackFrames"
|
||||
// assertion of MessageChannel.
|
||||
AddRef();
|
||||
MessageLoop::current()->PostTask(
|
||||
FROM_HERE,
|
||||
NewRunnableFunction(&ReleaseImageBridgeParent, this));
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -265,32 +296,11 @@ MessageLoop * ImageBridgeParent::GetMessageLoop() const {
|
|||
return mMessageLoop;
|
||||
}
|
||||
|
||||
class ReleaseRunnable : public nsRunnable
|
||||
{
|
||||
public:
|
||||
ReleaseRunnable(ImageBridgeParent* aRef)
|
||||
: mRef(aRef)
|
||||
{
|
||||
}
|
||||
|
||||
NS_IMETHOD Run()
|
||||
{
|
||||
mRef->Release();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
private:
|
||||
ImageBridgeParent* mRef;
|
||||
};
|
||||
|
||||
void
|
||||
ImageBridgeParent::DeferredDestroy()
|
||||
{
|
||||
ImageBridgeParent* self;
|
||||
mSelfRef.forget(&self);
|
||||
|
||||
nsCOMPtr<nsIRunnable> runnable = new ReleaseRunnable(self);
|
||||
MOZ_ALWAYS_TRUE(NS_SUCCEEDED(NS_DispatchToMainThread(runnable)));
|
||||
mCompositorThreadHolder = nullptr;
|
||||
mSelfRef = nullptr;
|
||||
}
|
||||
|
||||
ImageBridgeParent*
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
#include <stddef.h> // for size_t
|
||||
#include <stdint.h> // for uint32_t, uint64_t
|
||||
#include "CompositableTransactionParent.h"
|
||||
#include "CompositorParent.h"
|
||||
#include "mozilla/Assertions.h" // for MOZ_ASSERT_HELPER2
|
||||
#include "mozilla/Attributes.h" // for MOZ_OVERRIDE
|
||||
#include "mozilla/ipc/ProtocolUtils.h"
|
||||
|
@ -151,6 +152,10 @@ private:
|
|||
* Map of all living ImageBridgeParent instances
|
||||
*/
|
||||
static std::map<base::ProcessId, ImageBridgeParent*> sImageBridges;
|
||||
|
||||
static MessageLoop* sMainLoop;
|
||||
|
||||
nsRefPtr<CompositorThreadHolder> mCompositorThreadHolder;
|
||||
};
|
||||
|
||||
} // layers
|
||||
|
|
|
@ -0,0 +1,83 @@
|
|||
/* 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/. */
|
||||
|
||||
#ifndef THREADSAFEREFCOUNTINGWITHMAINTHREADDESTRUCTION_H_
|
||||
#define THREADSAFEREFCOUNTINGWITHMAINTHREADDESTRUCTION_H_
|
||||
|
||||
#include "MainThreadUtils.h"
|
||||
#include "base/message_loop.h"
|
||||
#include "base/task.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace layers {
|
||||
|
||||
inline MessageLoop* GetMainLoopAssertingMainThread()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
return MessageLoop::current();
|
||||
}
|
||||
|
||||
inline MessageLoop* GetMainLoop()
|
||||
{
|
||||
static MessageLoop* sMainLoop = GetMainLoopAssertingMainThread();
|
||||
return sMainLoop;
|
||||
}
|
||||
|
||||
struct HelperForMainThreadDestruction
|
||||
{
|
||||
HelperForMainThreadDestruction()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
GetMainLoop();
|
||||
}
|
||||
|
||||
~HelperForMainThreadDestruction()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace layers
|
||||
} // namespace mozilla
|
||||
|
||||
#define NS_INLINE_DECL_THREADSAFE_REFCOUNTING_WITH_MAIN_THREAD_DESTRUCTION(_class) \
|
||||
public: \
|
||||
NS_METHOD_(MozExternalRefCountType) AddRef(void) { \
|
||||
MOZ_ASSERT_TYPE_OK_FOR_REFCOUNTING(_class) \
|
||||
MOZ_ASSERT(int32_t(mRefCnt) >= 0, "illegal refcnt"); \
|
||||
nsrefcnt count = ++mRefCnt; \
|
||||
NS_LOG_ADDREF(this, count, #_class, sizeof(*this)); \
|
||||
return (nsrefcnt) count; \
|
||||
} \
|
||||
static void DestroyToBeCalledOnMainThread(_class* ptr) { \
|
||||
MOZ_ASSERT(NS_IsMainThread()); \
|
||||
NS_LOG_RELEASE(ptr, 0, #_class); \
|
||||
delete ptr; \
|
||||
} \
|
||||
NS_METHOD_(MozExternalRefCountType) Release(void) { \
|
||||
MOZ_ASSERT(int32_t(mRefCnt) > 0, "dup release"); \
|
||||
nsrefcnt count = --mRefCnt; \
|
||||
if (count == 0) { \
|
||||
if (NS_IsMainThread()) { \
|
||||
NS_LOG_RELEASE(this, 0, #_class); \
|
||||
delete this; \
|
||||
} else { \
|
||||
/* no NS_LOG_RELEASE here, will be in the runnable */ \
|
||||
MessageLoop *l = ::mozilla::layers::GetMainLoop(); \
|
||||
l->PostTask(FROM_HERE, \
|
||||
NewRunnableFunction(&DestroyToBeCalledOnMainThread, \
|
||||
this)); \
|
||||
} \
|
||||
} else { \
|
||||
NS_LOG_RELEASE(this, count, #_class); \
|
||||
} \
|
||||
return count; \
|
||||
} \
|
||||
protected: \
|
||||
::mozilla::ThreadSafeAutoRefCnt mRefCnt; \
|
||||
private: \
|
||||
::mozilla::layers::HelperForMainThreadDestruction mHelperForMainThreadDestruction; \
|
||||
public:
|
||||
|
||||
#endif
|
|
@ -27,6 +27,7 @@ EXPORTS += [
|
|||
'ipc/CompositorChild.h',
|
||||
'ipc/CompositorParent.h',
|
||||
'ipc/ShadowLayersManager.h',
|
||||
'ipc/ThreadSafeRefcountingWithMainThreadDestruction.h',
|
||||
'Layers.h',
|
||||
'LayerScope.h',
|
||||
'LayersLogging.h',
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
</head>
|
||||
<body style="font-variant: small-caps; font-family: 'Times New Roman';">
|
||||
<div>x󠄱</div>
|
||||
</body>
|
||||
</html>
|
|
@ -108,3 +108,4 @@ load 893572-1.html
|
|||
load 893572-2.html
|
||||
load 893572-3.html
|
||||
load 893572-4.html
|
||||
load 1034403-1.html
|
||||
|
|
|
@ -1,106 +0,0 @@
|
|||
/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
* 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/. */
|
||||
|
||||
#include "gfxCachedTempSurface.h"
|
||||
#include "gfxContext.h"
|
||||
#include "mozilla/Attributes.h"
|
||||
|
||||
class CachedSurfaceExpirationTracker MOZ_FINAL :
|
||||
public nsExpirationTracker<gfxCachedTempSurface,2> {
|
||||
|
||||
public:
|
||||
// With K = 2, this means that surfaces will be released when they are not
|
||||
// used for 1-2 seconds.
|
||||
enum { TIMEOUT_MS = 1000 };
|
||||
CachedSurfaceExpirationTracker()
|
||||
: nsExpirationTracker<gfxCachedTempSurface,2>(TIMEOUT_MS) {}
|
||||
|
||||
~CachedSurfaceExpirationTracker() {
|
||||
AgeAllGenerations();
|
||||
}
|
||||
|
||||
virtual void NotifyExpired(gfxCachedTempSurface* aSurface) {
|
||||
RemoveObject(aSurface);
|
||||
aSurface->Expire();
|
||||
}
|
||||
|
||||
static void MarkSurfaceUsed(gfxCachedTempSurface* aSurface)
|
||||
{
|
||||
if (aSurface->GetExpirationState()->IsTracked()) {
|
||||
sExpirationTracker->MarkUsed(aSurface);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!sExpirationTracker) {
|
||||
sExpirationTracker = new CachedSurfaceExpirationTracker();
|
||||
}
|
||||
sExpirationTracker->AddObject(aSurface);
|
||||
}
|
||||
|
||||
static void RemoveSurface(gfxCachedTempSurface* aSurface)
|
||||
{
|
||||
if (!sExpirationTracker)
|
||||
return;
|
||||
|
||||
if (aSurface->GetExpirationState()->IsTracked()) {
|
||||
sExpirationTracker->RemoveObject(aSurface);
|
||||
}
|
||||
if (sExpirationTracker->IsEmpty()) {
|
||||
delete sExpirationTracker;
|
||||
sExpirationTracker = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
static CachedSurfaceExpirationTracker* sExpirationTracker;
|
||||
};
|
||||
|
||||
CachedSurfaceExpirationTracker*
|
||||
CachedSurfaceExpirationTracker::sExpirationTracker = nullptr;
|
||||
|
||||
gfxCachedTempSurface::~gfxCachedTempSurface()
|
||||
{
|
||||
CachedSurfaceExpirationTracker::RemoveSurface(this);
|
||||
}
|
||||
|
||||
already_AddRefed<gfxContext>
|
||||
gfxCachedTempSurface::Get(gfxContentType aContentType,
|
||||
const gfxRect& aRect,
|
||||
gfxASurface* aSimilarTo)
|
||||
{
|
||||
if (mSurface) {
|
||||
/* Verify the current buffer is valid for this purpose */
|
||||
if (mSize.width < aRect.width || mSize.height < aRect.height
|
||||
|| mSurface->GetContentType() != aContentType
|
||||
|| mType != aSimilarTo->GetType()) {
|
||||
mSurface = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
bool cleared = false;
|
||||
if (!mSurface) {
|
||||
mSize = gfxIntSize(int32_t(ceil(aRect.width)), int32_t(ceil(aRect.height)));
|
||||
mSurface = aSimilarTo->CreateSimilarSurface(aContentType, mSize);
|
||||
if (!mSurface)
|
||||
return nullptr;
|
||||
|
||||
cleared = true;
|
||||
mType = aSimilarTo->GetType();
|
||||
}
|
||||
mSurface->SetDeviceOffset(-aRect.TopLeft());
|
||||
|
||||
nsRefPtr<gfxContext> ctx = new gfxContext(mSurface);
|
||||
ctx->Rectangle(aRect);
|
||||
ctx->Clip();
|
||||
if (!cleared && aContentType != gfxContentType::COLOR) {
|
||||
ctx->SetOperator(gfxContext::OPERATOR_CLEAR);
|
||||
ctx->Paint();
|
||||
ctx->SetOperator(gfxContext::OPERATOR_OVER);
|
||||
}
|
||||
|
||||
CachedSurfaceExpirationTracker::MarkSurfaceUsed(this);
|
||||
|
||||
return ctx.forget();
|
||||
}
|
|
@ -1,58 +0,0 @@
|
|||
/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
* 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/. */
|
||||
|
||||
#ifndef GFX_CACHED_TEMP_SURFACE_H
|
||||
#define GFX_CACHED_TEMP_SURFACE_H
|
||||
|
||||
#include "gfxASurface.h"
|
||||
#include "nsExpirationTracker.h"
|
||||
#include "nsSize.h"
|
||||
|
||||
class gfxContext;
|
||||
|
||||
/**
|
||||
* This class can be used to cache double-buffering back surfaces.
|
||||
*
|
||||
* Large resource allocations may have an overhead that can be avoided by
|
||||
* caching. Caching also alows the system to use history in deciding whether
|
||||
* to manage the surfaces in video or system memory.
|
||||
*
|
||||
* However, because we don't want to set aside megabytes of unused resources
|
||||
* unncessarily, these surfaces are released on a timer.
|
||||
*/
|
||||
|
||||
class gfxCachedTempSurface {
|
||||
public:
|
||||
/**
|
||||
* Returns a context for a surface that can be efficiently copied to
|
||||
* |aSimilarTo|.
|
||||
*
|
||||
* When |aContentType| has an alpha component, the surface will be cleared.
|
||||
* For opaque surfaces, the initial surface contents are undefined.
|
||||
* When |aContentType| differs in different invocations this is handled
|
||||
* appropriately, creating a new surface if necessary.
|
||||
*
|
||||
* Because the cached surface may have been created during a previous
|
||||
* invocation, this will not be efficient if the new |aSimilarTo| has a
|
||||
* different format, size, or gfxSurfaceType.
|
||||
*/
|
||||
already_AddRefed<gfxContext> Get(gfxContentType aContentType,
|
||||
const gfxRect& aRect,
|
||||
gfxASurface* aSimilarTo);
|
||||
|
||||
void Expire() { mSurface = nullptr; }
|
||||
nsExpirationState* GetExpirationState() { return &mExpirationState; }
|
||||
~gfxCachedTempSurface();
|
||||
|
||||
bool IsSurface(gfxASurface* aSurface) { return mSurface == aSurface; }
|
||||
|
||||
private:
|
||||
nsRefPtr<gfxASurface> mSurface;
|
||||
gfxIntSize mSize;
|
||||
nsExpirationState mExpirationState;
|
||||
gfxSurfaceType mType;
|
||||
};
|
||||
|
||||
#endif /* GFX_CACHED_TEMP_SURFACE_H */
|
|
@ -5764,6 +5764,9 @@ gfxFont::InitFakeSmallCapsRun(gfxContext *aContext,
|
|||
uint32_t runStart = 0;
|
||||
|
||||
for (uint32_t i = 0; i <= aLength; ++i) {
|
||||
uint32_t extraCodeUnits = 0; // Will be set to 1 if we need to consume
|
||||
// a trailing surrogate as well as the
|
||||
// current code unit.
|
||||
RunCaseAction chAction = kNoChange;
|
||||
// Unless we're at the end, figure out what treatment the current
|
||||
// character will need.
|
||||
|
@ -5772,6 +5775,7 @@ gfxFont::InitFakeSmallCapsRun(gfxContext *aContext,
|
|||
if (NS_IS_HIGH_SURROGATE(ch) && i < aLength - 1 &&
|
||||
NS_IS_LOW_SURROGATE(aText[i + 1])) {
|
||||
ch = SURROGATE_TO_UCS4(ch, aText[i + 1]);
|
||||
extraCodeUnits = 1;
|
||||
}
|
||||
// Characters that aren't the start of a cluster are ignored here.
|
||||
// They get added to whatever lowercase/non-lowercase run we're in.
|
||||
|
@ -5885,6 +5889,7 @@ gfxFont::InitFakeSmallCapsRun(gfxContext *aContext,
|
|||
runStart = i;
|
||||
}
|
||||
|
||||
i += extraCodeUnits;
|
||||
if (i < aLength) {
|
||||
runAction = chAction;
|
||||
}
|
||||
|
|
|
@ -1005,7 +1005,9 @@ gfxUtils::ConvertYCbCrToRGB(const PlanarYCbCrData& aData,
|
|||
}
|
||||
}
|
||||
|
||||
/* static */ void gfxUtils::ClearThebesSurface(gfxASurface* aSurface)
|
||||
/* static */ void gfxUtils::ClearThebesSurface(gfxASurface* aSurface,
|
||||
nsIntRect* aRect,
|
||||
const gfxRGBA& aColor)
|
||||
{
|
||||
if (aSurface->CairoStatus()) {
|
||||
return;
|
||||
|
@ -1015,8 +1017,16 @@ gfxUtils::ConvertYCbCrToRGB(const PlanarYCbCrData& aData,
|
|||
return;
|
||||
}
|
||||
cairo_t* ctx = cairo_create(surf);
|
||||
cairo_set_operator(ctx, CAIRO_OPERATOR_CLEAR);
|
||||
cairo_paint_with_alpha(ctx, 1.0);
|
||||
cairo_set_source_rgba(ctx, aColor.r, aColor.g, aColor.b, aColor.a);
|
||||
cairo_set_operator(ctx, CAIRO_OPERATOR_SOURCE);
|
||||
nsIntRect bounds;
|
||||
if (aRect) {
|
||||
bounds = *aRect;
|
||||
} else {
|
||||
bounds = nsIntRect(nsIntPoint(0, 0), aSurface->GetSize());
|
||||
}
|
||||
cairo_rectangle(ctx, bounds.x, bounds.y, bounds.width, bounds.height);
|
||||
cairo_fill(ctx);
|
||||
cairo_destroy(ctx);
|
||||
}
|
||||
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
#ifndef GFX_UTILS_H
|
||||
#define GFX_UTILS_H
|
||||
|
||||
#include "gfxColor.h"
|
||||
#include "gfxTypes.h"
|
||||
#include "GraphicsFilter.h"
|
||||
#include "imgIContainer.h"
|
||||
|
@ -171,9 +172,11 @@ public:
|
|||
int32_t aStride);
|
||||
|
||||
/**
|
||||
* Clears surface to transparent black.
|
||||
* Clears surface to aColor (which defaults to transparent black).
|
||||
*/
|
||||
static void ClearThebesSurface(gfxASurface* aSurface);
|
||||
static void ClearThebesSurface(gfxASurface* aSurface,
|
||||
nsIntRect* aRect = nullptr,
|
||||
const gfxRGBA& aColor = gfxRGBA(0.0, 0.0, 0.0, 0.0));
|
||||
|
||||
/**
|
||||
* Creates a copy of aSurface, but having the SurfaceFormat aFormat.
|
||||
|
|
|
@ -12,7 +12,6 @@ EXPORTS += [
|
|||
'gfxASurface.h',
|
||||
'gfxBaseSharedMemorySurface.h',
|
||||
'gfxBlur.h',
|
||||
'gfxCachedTempSurface.h',
|
||||
'gfxColor.h',
|
||||
'gfxContext.h',
|
||||
'gfxDrawable.h',
|
||||
|
@ -223,7 +222,6 @@ UNIFIED_SOURCES += [
|
|||
'gfxAlphaRecovery.cpp',
|
||||
'gfxBaseSharedMemorySurface.cpp',
|
||||
'gfxBlur.cpp',
|
||||
'gfxCachedTempSurface.cpp',
|
||||
'gfxContext.cpp',
|
||||
'gfxFontFeatures.cpp',
|
||||
'gfxFontInfoLoader.cpp',
|
||||
|
|
|
@ -115,6 +115,9 @@ struct SingletonDestroyer MOZ_FINAL : public nsIObserver
|
|||
{
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSIOBSERVER
|
||||
|
||||
private:
|
||||
~SingletonDestroyer() {}
|
||||
};
|
||||
|
||||
NS_IMPL_ISUPPORTS(SingletonDestroyer, nsIObserver)
|
||||
|
|
|
@ -31,11 +31,12 @@ public:
|
|||
NS_DECL_NSISTREAMLISTENER
|
||||
|
||||
nsIconChannel();
|
||||
virtual ~nsIconChannel();
|
||||
|
||||
nsresult Init(nsIURI* uri);
|
||||
|
||||
protected:
|
||||
virtual ~nsIconChannel();
|
||||
|
||||
nsCOMPtr<nsIURI> mUrl;
|
||||
nsCOMPtr<nsIURI> mOriginalURI;
|
||||
int64_t mContentLength;
|
||||
|
|
|
@ -22,7 +22,6 @@ class nsCollationMacUC MOZ_FINAL : public nsICollation {
|
|||
|
||||
public:
|
||||
nsCollationMacUC();
|
||||
~nsCollationMacUC();
|
||||
|
||||
// nsISupports interface
|
||||
NS_DECL_ISUPPORTS
|
||||
|
@ -31,6 +30,8 @@ public:
|
|||
NS_DECL_NSICOLLATION
|
||||
|
||||
protected:
|
||||
~nsCollationMacUC();
|
||||
|
||||
nsresult ConvertLocale(nsILocale* aNSLocale, LocaleRef* aMacLocale);
|
||||
nsresult StrengthToOptions(const int32_t aStrength,
|
||||
UCCollateOptions* aOptions);
|
||||
|
|
|
@ -45,9 +45,10 @@ public:
|
|||
nsAString& stringOut);
|
||||
|
||||
nsDateTimeFormatMac() {}
|
||||
|
||||
|
||||
protected:
|
||||
virtual ~nsDateTimeFormatMac() {}
|
||||
|
||||
|
||||
private:
|
||||
// init this interface to a specified locale
|
||||
NS_IMETHOD Initialize(nsILocale* locale);
|
||||
|
|
|
@ -19,11 +19,14 @@ namespace ipc {
|
|||
|
||||
IToplevelProtocol::~IToplevelProtocol()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
mOpenActors.clear();
|
||||
}
|
||||
|
||||
void IToplevelProtocol::AddOpenedActor(IToplevelProtocol* aActor)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
#ifdef DEBUG
|
||||
for (const IToplevelProtocol* actor = mOpenActors.getFirst();
|
||||
actor;
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
#include "mozilla/ipc/Transport.h"
|
||||
#include "mozilla/ipc/MessageLink.h"
|
||||
#include "mozilla/LinkedList.h"
|
||||
#include "MainThreadUtils.h"
|
||||
|
||||
#if defined(ANDROID) && defined(DEBUG)
|
||||
#include <android/log.h>
|
||||
|
@ -187,6 +188,7 @@ protected:
|
|||
: mProtocolId(aProtoId)
|
||||
, mTrans(nullptr)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
}
|
||||
|
||||
~IToplevelProtocol();
|
||||
|
@ -212,10 +214,12 @@ public:
|
|||
*/
|
||||
IToplevelProtocol* GetFirstOpenedActors()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
return mOpenActors.getFirst();
|
||||
}
|
||||
const IToplevelProtocol* GetFirstOpenedActors() const
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
return mOpenActors.getFirst();
|
||||
}
|
||||
|
||||
|
|
|
@ -303,9 +303,11 @@ AssertMarkedOrAllocated(const EdgeValue &edge)
|
|||
if (!edge.thing || IsMarkedOrAllocated(static_cast<Cell *>(edge.thing)))
|
||||
return;
|
||||
|
||||
// Permanent atoms aren't marked during graph traversal.
|
||||
// Permanent atoms and well-known symbols aren't marked during graph traversal.
|
||||
if (edge.kind == JSTRACE_STRING && static_cast<JSString *>(edge.thing)->isPermanentAtom())
|
||||
return;
|
||||
if (edge.kind == JSTRACE_SYMBOL && static_cast<JS::Symbol *>(edge.thing)->isWellKnownSymbol())
|
||||
return;
|
||||
|
||||
char msgbuf[1024];
|
||||
const char *label = edge.label;
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
gczeal(4);
|
||||
var symbols = [Symbol(), Symbol("comet"), Symbol.for("moon"), Symbol.iterator, 0];
|
||||
for (var a of symbols) {}
|
|
@ -0,0 +1,29 @@
|
|||
var tests = [
|
||||
{T: Uint8Array, result: 0},
|
||||
{T: Uint8ClampedArray, result: 0},
|
||||
{T: Int16Array, result: 0},
|
||||
{T: Float32Array, result: NaN}
|
||||
];
|
||||
|
||||
var LENGTH = 1024, SYMBOL_INDEX = 999;
|
||||
|
||||
var big = [];
|
||||
for (var i = 0; i < LENGTH; i++)
|
||||
big[i] = (i === SYMBOL_INDEX ? Symbol.for("comet") : i);
|
||||
|
||||
function copy(arr, big) {
|
||||
for (var i = 0; i < LENGTH; i++)
|
||||
arr[i] = big[i];
|
||||
}
|
||||
|
||||
for (var {T, result} of tests) {
|
||||
// Typed array constructors convert symbols to NaN or 0.
|
||||
arr = new T(big);
|
||||
assertEq(arr[SYMBOL_INDEX], result);
|
||||
|
||||
// Element assignment does the same.
|
||||
for (var k = 0; k < 3; k++) {
|
||||
copy(arr, big);
|
||||
assertEq(arr[SYMBOL_INDEX], result);
|
||||
}
|
||||
}
|
|
@ -27,6 +27,13 @@ BEGIN_TEST(testGCHeapPostBarriers)
|
|||
return true;
|
||||
}
|
||||
|
||||
MOZ_NEVER_INLINE bool
|
||||
Passthrough(bool value)
|
||||
{
|
||||
/* Work around a Win64 optimization bug in VS2010. (Bug 1033146) */
|
||||
return value;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
bool
|
||||
TestHeapPostBarriers(T initialObj)
|
||||
|
@ -37,7 +44,7 @@ TestHeapPostBarriers(T initialObj)
|
|||
/* Construct Heap<> wrapper. */
|
||||
JS::Heap<T> *heapData = new JS::Heap<T>();
|
||||
CHECK(heapData);
|
||||
CHECK(heapData->get() == nullptr);
|
||||
CHECK(Passthrough(heapData->get() == nullptr));
|
||||
heapData->set(initialObj);
|
||||
|
||||
/* Store the pointer as an integer so that the hazard analysis will miss it. */
|
||||
|
|
|
@ -5769,7 +5769,7 @@ DumpProperty(JSObject *obj, Shape &shape)
|
|||
jsid id = shape.propid();
|
||||
uint8_t attrs = shape.attributes();
|
||||
|
||||
fprintf(stderr, " ((JSShape *) %p) ", (void *) &shape);
|
||||
fprintf(stderr, " ((js::Shape *) %p) ", (void *) &shape);
|
||||
if (attrs & JSPROP_ENUMERATE) fprintf(stderr, "enumerate ");
|
||||
if (attrs & JSPROP_READONLY) fprintf(stderr, "readonly ");
|
||||
if (attrs & JSPROP_PERMANENT) fprintf(stderr, "permanent ");
|
||||
|
@ -5785,10 +5785,8 @@ DumpProperty(JSObject *obj, Shape &shape)
|
|||
else if (!shape.hasDefaultSetter())
|
||||
fprintf(stderr, "setterOp=%p ", JS_FUNC_TO_DATA_PTR(void *, shape.setterOp()));
|
||||
|
||||
if (JSID_IS_ATOM(id))
|
||||
JSID_TO_STRING(id)->dump();
|
||||
else if (JSID_IS_INT(id))
|
||||
fprintf(stderr, "%d", (int) JSID_TO_INT(id));
|
||||
if (JSID_IS_ATOM(id) || JSID_IS_INT(id) || JSID_IS_SYMBOL(id))
|
||||
dumpValue(js::IdToValue(id));
|
||||
else
|
||||
fprintf(stderr, "unknown jsid %p", (void *) JSID_BITS(id));
|
||||
|
||||
|
|
|
@ -292,7 +292,7 @@ PreprocessValue(JSContext *cx, HandleObject holder, KeyType key, MutableHandleVa
|
|||
static inline bool
|
||||
IsFilteredValue(const Value &v)
|
||||
{
|
||||
return v.isUndefined() || IsCallable(v);
|
||||
return v.isUndefined() || v.isSymbol() || IsCallable(v);
|
||||
}
|
||||
|
||||
/* ES5 15.12.3 JO. */
|
||||
|
|
|
@ -0,0 +1,19 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/licenses/publicdomain/ */
|
||||
|
||||
// JSON.stringify ignores symbol-keyed properties, even enumerable ones.
|
||||
|
||||
var obj = {a: 1};
|
||||
obj[Symbol.for("ponies")] = {toJSON: function () { throw "fit"; }};
|
||||
obj[Symbol.iterator] = {toJSON: function () { throw "fit"; }};
|
||||
assertEq(JSON.stringify(obj), '{"a":1}');
|
||||
|
||||
var replacer = function (k, v) {
|
||||
if (typeof k === "symbol")
|
||||
throw "fit";
|
||||
return v;
|
||||
};
|
||||
assertEq(JSON.stringify(obj, replacer), '{"a":1}');
|
||||
|
||||
if (typeof reportCompare === 'function')
|
||||
reportCompare(0, 0, 'ok');
|
|
@ -0,0 +1,33 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/licenses/publicdomain/ */
|
||||
|
||||
// To JSON.stringify, symbols are the same as undefined.
|
||||
|
||||
var symbols = [
|
||||
Symbol(),
|
||||
Symbol.for("ponies"),
|
||||
Symbol.iterator
|
||||
];
|
||||
|
||||
for (var sym of symbols) {
|
||||
assertEq(JSON.stringify(sym), undefined);
|
||||
assertEq(JSON.stringify([sym]), "[null]");
|
||||
|
||||
// JSON.stringify skips symbol-valued properties!
|
||||
assertEq(JSON.stringify({x: sym}), '{}');
|
||||
|
||||
// However such properties are passed to the replacerFunction if any.
|
||||
var replacer = function (key, val) {
|
||||
assertEq(typeof this, "object");
|
||||
if (typeof val === "symbol") {
|
||||
assertEq(val, sym);
|
||||
return "ding";
|
||||
}
|
||||
return val;
|
||||
};
|
||||
assertEq(JSON.stringify(sym, replacer), '"ding"');
|
||||
assertEq(JSON.stringify({x: sym}, replacer), '{"x":"ding"}');
|
||||
}
|
||||
|
||||
if (typeof reportCompare === 'function')
|
||||
reportCompare(0, 0, 'ok');
|
|
@ -0,0 +1,26 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/licenses/publicdomain/ */
|
||||
|
||||
// Symbol-to-number type conversions involving typed arrays.
|
||||
|
||||
var tests = [
|
||||
{T: Uint8Array, result: 0},
|
||||
{T: Uint8ClampedArray, result: 0},
|
||||
{T: Int16Array, result: 0},
|
||||
{T: Float32Array, result: NaN}
|
||||
];
|
||||
|
||||
for (var {T, result} of tests) {
|
||||
// Typed array constructors convert symbols to NaN or 0.
|
||||
var arr = new T([Symbol("a")]);
|
||||
assertEq(arr.length, 1);
|
||||
assertEq(arr[0], result);
|
||||
|
||||
// Assignment also converts symbols to NaN or 0.
|
||||
arr[0] = 0;
|
||||
assertEq(arr[0] = Symbol.iterator, Symbol.iterator);
|
||||
assertEq(arr[0], result);
|
||||
}
|
||||
|
||||
if (typeof reportCompare === "function")
|
||||
reportCompare(0, 0);
|
|
@ -84,6 +84,7 @@ class Test:
|
|||
self.jitflags = [] # jit flags to enable
|
||||
self.slow = False # True means the test is slow-running
|
||||
self.allow_oom = False # True means that OOM is not considered a failure
|
||||
self.allow_unhandlable_oom = False # True means CrashAtUnhandlableOOM is not considered a failure
|
||||
self.allow_overrecursed = False # True means that hitting recursion the
|
||||
# limits is not considered a failure.
|
||||
self.valgrind = False # True means run under valgrind
|
||||
|
@ -96,6 +97,7 @@ class Test:
|
|||
t.jitflags = self.jitflags[:]
|
||||
t.slow = self.slow
|
||||
t.allow_oom = self.allow_oom
|
||||
t.allow_unhandlable_oom = self.allow_unhandlable_oom
|
||||
t.allow_overrecursed = self.allow_overrecursed
|
||||
t.valgrind = self.valgrind
|
||||
t.tz_pacific = self.tz_pacific
|
||||
|
@ -141,6 +143,8 @@ class Test:
|
|||
test.slow = True
|
||||
elif name == 'allow-oom':
|
||||
test.allow_oom = True
|
||||
elif name == 'allow-unhandlable-oom':
|
||||
test.allow_unhandlable_oom = True
|
||||
elif name == 'allow-overrecursed':
|
||||
test.allow_overrecursed = True
|
||||
elif name == 'valgrind':
|
||||
|
@ -390,6 +394,11 @@ def check_output(out, err, rc, timed_out, test):
|
|||
if test.allow_oom and 'out of memory' in err and 'Assertion failure' not in err:
|
||||
return True
|
||||
|
||||
# Allow a non-zero exit code if we want to allow unhandlable OOM, but
|
||||
# only if we actually got unhandlable OOM.
|
||||
if test.allow_unhandlable_oom and 'Assertion failure: [unhandlable oom]' in err:
|
||||
return True
|
||||
|
||||
# Allow a non-zero exit code if we want to all too-much-recursion and
|
||||
# the test actually over-recursed.
|
||||
if test.allow_overrecursed and 'too much recursion' in err and 'Assertion failure' not in err:
|
||||
|
|
|
@ -883,7 +883,7 @@ class TypedArrayObjectTemplate : public TypedArrayObject
|
|||
static bool
|
||||
canConvertInfallibly(const Value &v)
|
||||
{
|
||||
return v.isNumber() || v.isBoolean() || v.isNull() || v.isUndefined();
|
||||
return v.isNumber() || v.isBoolean() || v.isNull() || v.isUndefined() || v.isSymbol();
|
||||
}
|
||||
|
||||
static NativeType
|
||||
|
@ -898,7 +898,7 @@ class TypedArrayObjectTemplate : public TypedArrayObject
|
|||
if (v.isNull())
|
||||
return NativeType(0);
|
||||
|
||||
MOZ_ASSERT(v.isUndefined());
|
||||
MOZ_ASSERT(v.isUndefined() || v.isSymbol());
|
||||
return ArrayTypeIsFloatingPoint() ? NativeType(GenericNaN()) : NativeType(0);
|
||||
}
|
||||
|
||||
|
|
|
@ -249,16 +249,6 @@ nsDisplayCanvasBackgroundColor::WriteDebugInfo(nsACString& aTo)
|
|||
}
|
||||
#endif
|
||||
|
||||
static void BlitSurface(gfxContext* aDest, const gfxRect& aRect, gfxASurface* aSource)
|
||||
{
|
||||
aDest->Translate(gfxPoint(aRect.x, aRect.y));
|
||||
aDest->SetSource(aSource);
|
||||
aDest->NewPath();
|
||||
aDest->Rectangle(gfxRect(0, 0, aRect.width, aRect.height));
|
||||
aDest->Fill();
|
||||
aDest->Translate(-gfxPoint(aRect.x, aRect.y));
|
||||
}
|
||||
|
||||
static void BlitSurface(DrawTarget* aDest, const gfxRect& aRect, DrawTarget* aSource)
|
||||
{
|
||||
RefPtr<SourceSurface> source = aSource->Snapshot();
|
||||
|
@ -277,9 +267,7 @@ nsDisplayCanvasBackgroundImage::Paint(nsDisplayListBuilder* aBuilder,
|
|||
|
||||
nsRefPtr<nsRenderingContext> context;
|
||||
nsRefPtr<gfxContext> dest = aCtx->ThebesContext();
|
||||
nsRefPtr<gfxASurface> surf;
|
||||
RefPtr<DrawTarget> dt;
|
||||
nsRefPtr<gfxContext> ctx;
|
||||
gfxRect destRect;
|
||||
#ifndef MOZ_GFX_OPTIMIZE_MOBILE
|
||||
if (IsSingleFixedPositionImage(aBuilder, bgClipRect, &destRect) &&
|
||||
|
@ -288,31 +276,15 @@ nsDisplayCanvasBackgroundImage::Paint(nsDisplayListBuilder* aBuilder,
|
|||
// Snap image rectangle to nearest pixel boundaries. This is the right way
|
||||
// to snap for this context, because we checked HasNonIntegerTranslation above.
|
||||
destRect.Round();
|
||||
if (dest->IsCairo()) {
|
||||
surf = static_cast<gfxASurface*>(Frame()->Properties().Get(nsIFrame::CachedBackgroundImage()));
|
||||
nsRefPtr<gfxASurface> destSurf = dest->CurrentSurface();
|
||||
if (surf && surf->GetType() == destSurf->GetType()) {
|
||||
BlitSurface(dest, destRect, surf);
|
||||
return;
|
||||
}
|
||||
surf = destSurf->CreateSimilarSurface(
|
||||
gfxContentType::COLOR_ALPHA,
|
||||
gfxIntSize(ceil(destRect.width), ceil(destRect.height)));
|
||||
} else {
|
||||
dt = static_cast<DrawTarget*>(Frame()->Properties().Get(nsIFrame::CachedBackgroundImageDT()));
|
||||
DrawTarget* destDT = dest->GetDrawTarget();
|
||||
if (dt) {
|
||||
BlitSurface(destDT, destRect, dt);
|
||||
return;
|
||||
}
|
||||
dt = destDT->CreateSimilarDrawTarget(IntSize(ceil(destRect.width), ceil(destRect.height)), SurfaceFormat::B8G8R8A8);
|
||||
dt = static_cast<DrawTarget*>(Frame()->Properties().Get(nsIFrame::CachedBackgroundImageDT()));
|
||||
DrawTarget* destDT = dest->GetDrawTarget();
|
||||
if (dt) {
|
||||
BlitSurface(destDT, destRect, dt);
|
||||
return;
|
||||
}
|
||||
if (surf || dt) {
|
||||
if (surf) {
|
||||
ctx = new gfxContext(surf);
|
||||
} else {
|
||||
ctx = new gfxContext(dt);
|
||||
}
|
||||
dt = destDT->CreateSimilarDrawTarget(IntSize(ceil(destRect.width), ceil(destRect.height)), SurfaceFormat::B8G8R8A8);
|
||||
if (dt) {
|
||||
nsRefPtr<gfxContext> ctx = new gfxContext(dt);
|
||||
ctx->Translate(-gfxPoint(destRect.x, destRect.y));
|
||||
context = new nsRenderingContext();
|
||||
context->Init(aCtx->DeviceContext(), ctx);
|
||||
|
@ -321,15 +293,10 @@ nsDisplayCanvasBackgroundImage::Paint(nsDisplayListBuilder* aBuilder,
|
|||
#endif
|
||||
|
||||
PaintInternal(aBuilder,
|
||||
(surf || dt) ? context.get() : aCtx,
|
||||
(surf || dt) ? bgClipRect: mVisibleRect,
|
||||
dt ? context.get() : aCtx,
|
||||
dt ? bgClipRect: mVisibleRect,
|
||||
&bgClipRect);
|
||||
|
||||
if (surf) {
|
||||
BlitSurface(dest, destRect, surf);
|
||||
frame->Properties().Set(nsIFrame::CachedBackgroundImage(),
|
||||
surf.forget().take());
|
||||
}
|
||||
if (dt) {
|
||||
BlitSurface(dest->GetDrawTarget(), destRect, dt);
|
||||
frame->Properties().Set(nsIFrame::CachedBackgroundImageDT(), dt.forget().drop());
|
||||
|
|
|
@ -298,30 +298,18 @@ nsFilterInstance::ComputeNeededBoxes()
|
|||
|
||||
nsresult
|
||||
nsFilterInstance::BuildSourcePaint(SourceInfo *aSource,
|
||||
gfxASurface* aTargetSurface,
|
||||
DrawTarget* aTargetDT)
|
||||
{
|
||||
nsIntRect neededRect = aSource->mNeededBounds;
|
||||
|
||||
RefPtr<DrawTarget> offscreenDT;
|
||||
nsRefPtr<gfxASurface> offscreenSurface;
|
||||
nsRefPtr<gfxContext> ctx;
|
||||
if (aTargetSurface) {
|
||||
offscreenSurface = gfxPlatform::GetPlatform()->CreateOffscreenSurface(
|
||||
neededRect.Size().ToIntSize(), gfxContentType::COLOR_ALPHA);
|
||||
if (!offscreenSurface || offscreenSurface->CairoStatus()) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
ctx = new gfxContext(offscreenSurface);
|
||||
} else {
|
||||
offscreenDT = gfxPlatform::GetPlatform()->CreateOffscreenContentDrawTarget(
|
||||
RefPtr<DrawTarget> offscreenDT =
|
||||
gfxPlatform::GetPlatform()->CreateOffscreenContentDrawTarget(
|
||||
ToIntSize(neededRect.Size()), SurfaceFormat::B8G8R8A8);
|
||||
if (!offscreenDT) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
ctx = new gfxContext(offscreenDT);
|
||||
if (!offscreenDT) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
nsRefPtr<gfxContext> ctx = new gfxContext(offscreenDT);
|
||||
ctx->Translate(-neededRect.TopLeft());
|
||||
|
||||
nsRefPtr<nsRenderingContext> tmpCtx(new nsRenderingContext());
|
||||
|
@ -348,63 +336,46 @@ nsFilterInstance::BuildSourcePaint(SourceInfo *aSource,
|
|||
}
|
||||
gfx->Restore();
|
||||
|
||||
if (offscreenSurface) {
|
||||
aSource->mSourceSurface =
|
||||
gfxPlatform::GetPlatform()->GetSourceSurfaceForSurface(aTargetDT, offscreenSurface);
|
||||
} else {
|
||||
aSource->mSourceSurface = offscreenDT->Snapshot();
|
||||
}
|
||||
|
||||
aSource->mSourceSurface = offscreenDT->Snapshot();
|
||||
aSource->mSurfaceRect = ToIntRect(neededRect);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsFilterInstance::BuildSourcePaints(gfxASurface* aTargetSurface,
|
||||
DrawTarget* aTargetDT)
|
||||
nsFilterInstance::BuildSourcePaints(DrawTarget* aTargetDT)
|
||||
{
|
||||
nsresult rv = NS_OK;
|
||||
|
||||
if (!mFillPaint.mNeededBounds.IsEmpty()) {
|
||||
rv = BuildSourcePaint(&mFillPaint, aTargetSurface, aTargetDT);
|
||||
rv = BuildSourcePaint(&mFillPaint, aTargetDT);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
|
||||
if (!mStrokePaint.mNeededBounds.IsEmpty()) {
|
||||
rv = BuildSourcePaint(&mStrokePaint, aTargetSurface, aTargetDT);
|
||||
rv = BuildSourcePaint(&mStrokePaint, aTargetDT);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsFilterInstance::BuildSourceImage(gfxASurface* aTargetSurface,
|
||||
DrawTarget* aTargetDT)
|
||||
nsFilterInstance::BuildSourceImage(DrawTarget* aTargetDT)
|
||||
{
|
||||
nsIntRect neededRect = mSourceGraphic.mNeededBounds;
|
||||
if (neededRect.IsEmpty()) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
RefPtr<DrawTarget> offscreenDT;
|
||||
nsRefPtr<gfxASurface> offscreenSurface;
|
||||
nsRefPtr<gfxContext> ctx;
|
||||
if (aTargetSurface) {
|
||||
offscreenSurface = gfxPlatform::GetPlatform()->CreateOffscreenSurface(
|
||||
neededRect.Size().ToIntSize(), gfxContentType::COLOR_ALPHA);
|
||||
if (!offscreenSurface || offscreenSurface->CairoStatus()) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
ctx = new gfxContext(offscreenSurface);
|
||||
} else {
|
||||
offscreenDT = gfxPlatform::GetPlatform()->CreateOffscreenContentDrawTarget(
|
||||
RefPtr<DrawTarget> offscreenDT =
|
||||
gfxPlatform::GetPlatform()->CreateOffscreenContentDrawTarget(
|
||||
ToIntSize(neededRect.Size()), SurfaceFormat::B8G8R8A8);
|
||||
if (!offscreenDT) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
ctx = new gfxContext(offscreenDT);
|
||||
if (!offscreenDT) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
nsRefPtr<gfxContext> ctx = new gfxContext(offscreenDT);
|
||||
ctx->Translate(-neededRect.TopLeft());
|
||||
|
||||
nsRefPtr<nsRenderingContext> tmpCtx(new nsRenderingContext());
|
||||
|
@ -431,16 +402,7 @@ nsFilterInstance::BuildSourceImage(gfxASurface* aTargetSurface,
|
|||
tmpCtx->ThebesContext()->Multiply(deviceToFilterSpace);
|
||||
mPaintCallback->Paint(tmpCtx, mTargetFrame, &dirty, mTransformRoot);
|
||||
|
||||
RefPtr<SourceSurface> sourceGraphicSource;
|
||||
|
||||
if (offscreenSurface) {
|
||||
sourceGraphicSource =
|
||||
gfxPlatform::GetPlatform()->GetSourceSurfaceForSurface(aTargetDT, offscreenSurface);
|
||||
} else {
|
||||
sourceGraphicSource = offscreenDT->Snapshot();
|
||||
}
|
||||
|
||||
mSourceGraphic.mSourceSurface = sourceGraphicSource;
|
||||
mSourceGraphic.mSourceSurface = offscreenDT->Snapshot();
|
||||
mSourceGraphic.mSurfaceRect = ToIntRect(neededRect);
|
||||
|
||||
return NS_OK;
|
||||
|
@ -457,34 +419,18 @@ nsFilterInstance::Render(gfxContext* aContext)
|
|||
}
|
||||
|
||||
Matrix oldDTMatrix;
|
||||
nsRefPtr<gfxASurface> resultImage;
|
||||
RefPtr<DrawTarget> dt;
|
||||
if (aContext->IsCairo()) {
|
||||
resultImage =
|
||||
gfxPlatform::GetPlatform()->CreateOffscreenSurface(filterRect.Size().ToIntSize(),
|
||||
gfxContentType::COLOR_ALPHA);
|
||||
if (!resultImage || resultImage->CairoStatus())
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
// Create a Cairo DrawTarget around resultImage.
|
||||
dt = gfxPlatform::GetPlatform()->CreateDrawTargetForSurface(
|
||||
resultImage, ToIntSize(filterRect.Size()));
|
||||
} else {
|
||||
// When we have a DrawTarget-backed context, we can call DrawFilter
|
||||
// directly on the target DrawTarget and don't need a temporary DT.
|
||||
dt = aContext->GetDrawTarget();
|
||||
oldDTMatrix = dt->GetTransform();
|
||||
Matrix matrix = ToMatrix(ctm);
|
||||
matrix.Translate(filterRect.x, filterRect.y);
|
||||
dt->SetTransform(matrix * oldDTMatrix);
|
||||
}
|
||||
RefPtr<DrawTarget> dt = aContext->GetDrawTarget();
|
||||
oldDTMatrix = dt->GetTransform();
|
||||
Matrix matrix = ToMatrix(ctm);
|
||||
matrix.Translate(filterRect.x, filterRect.y);
|
||||
dt->SetTransform(matrix * oldDTMatrix);
|
||||
|
||||
ComputeNeededBoxes();
|
||||
|
||||
nsresult rv = BuildSourceImage(resultImage, dt);
|
||||
nsresult rv = BuildSourceImage(dt);
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
rv = BuildSourcePaints(resultImage, dt);
|
||||
rv = BuildSourcePaints(dt);
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
|
||||
|
@ -498,16 +444,7 @@ nsFilterInstance::Render(gfxContext* aContext)
|
|||
mStrokePaint.mSourceSurface, mStrokePaint.mSurfaceRect,
|
||||
mInputImages);
|
||||
|
||||
if (resultImage) {
|
||||
aContext->Save();
|
||||
aContext->Multiply(ctm);
|
||||
aContext->Translate(filterRect.TopLeft());
|
||||
aContext->SetSource(resultImage);
|
||||
aContext->Paint();
|
||||
aContext->Restore();
|
||||
} else {
|
||||
dt->SetTransform(oldDTMatrix);
|
||||
}
|
||||
dt->SetTransform(oldDTMatrix);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
|
|
@ -183,7 +183,6 @@ private:
|
|||
* nodes
|
||||
*/
|
||||
nsresult BuildSourcePaint(SourceInfo *aPrimitive,
|
||||
gfxASurface* aTargetSurface,
|
||||
DrawTarget* aTargetDT);
|
||||
|
||||
/**
|
||||
|
@ -191,15 +190,13 @@ private:
|
|||
* nodes, fills its contents and assigns it to mFillPaint.mSourceSurface and
|
||||
* mStrokePaint.mSourceSurface respectively.
|
||||
*/
|
||||
nsresult BuildSourcePaints(gfxASurface* aTargetSurface,
|
||||
DrawTarget* aTargetDT);
|
||||
nsresult BuildSourcePaints(DrawTarget* aTargetDT);
|
||||
|
||||
/**
|
||||
* Creates the SourceSurface for the SourceGraphic graph node, paints its
|
||||
* contents, and assigns it to mSourceGraphic.mSourceSurface.
|
||||
*/
|
||||
nsresult BuildSourceImage(gfxASurface* aTargetSurface,
|
||||
DrawTarget* aTargetDT);
|
||||
nsresult BuildSourceImage(DrawTarget* aTargetDT);
|
||||
|
||||
/**
|
||||
* Build the list of FilterPrimitiveDescriptions that describes the filter's
|
||||
|
|
|
@ -91,6 +91,25 @@ nsSVGInnerSVGFrame::PaintSVG(nsRenderingContext *aContext,
|
|||
return nsSVGInnerSVGFrameBase::PaintSVG(aContext, aDirtyRect);
|
||||
}
|
||||
|
||||
nsRect
|
||||
nsSVGInnerSVGFrame::GetCoveredRegion()
|
||||
{
|
||||
float x, y, w, h;
|
||||
static_cast<SVGSVGElement*>(mContent)->
|
||||
GetAnimatedLengthValues(&x, &y, &w, &h, nullptr);
|
||||
if (w < 0.0f) w = 0.0f;
|
||||
if (h < 0.0f) h = 0.0f;
|
||||
// GetCanvasTM includes the x,y translation
|
||||
nsRect bounds = nsSVGUtils::ToCanvasBounds(gfxRect(0.0, 0.0, w, h),
|
||||
GetCanvasTM(FOR_OUTERSVG_TM),
|
||||
PresContext());
|
||||
|
||||
if (!StyleDisplay()->IsScrollableOverflow()) {
|
||||
bounds.UnionRect(bounds, nsSVGUtils::GetCoveredRegion(mFrames));
|
||||
}
|
||||
return bounds;
|
||||
}
|
||||
|
||||
void
|
||||
nsSVGInnerSVGFrame::ReflowSVG()
|
||||
{
|
||||
|
|
|
@ -56,6 +56,7 @@ public:
|
|||
virtual nsresult PaintSVG(nsRenderingContext *aContext,
|
||||
const nsIntRect *aDirtyRect,
|
||||
nsIFrame* aTransformRoot = nullptr) MOZ_OVERRIDE;
|
||||
virtual nsRect GetCoveredRegion() MOZ_OVERRIDE;
|
||||
virtual void ReflowSVG() MOZ_OVERRIDE;
|
||||
virtual void NotifySVGChanged(uint32_t aFlags) MOZ_OVERRIDE;
|
||||
virtual nsIFrame* GetFrameForPoint(const nsPoint &aPoint) MOZ_OVERRIDE;
|
||||
|
|
|
@ -112,7 +112,6 @@ public:
|
|||
virtual nsresult PaintSVG(nsRenderingContext* aContext,
|
||||
const nsIntRect *aDirtyRect,
|
||||
nsIFrame* aTransformRoot = nullptr) MOZ_OVERRIDE;
|
||||
|
||||
virtual SVGBBox GetBBoxContribution(const Matrix &aToBBoxUserspace,
|
||||
uint32_t aFlags) MOZ_OVERRIDE;
|
||||
|
||||
|
|
|
@ -7,9 +7,12 @@
|
|||
#include "nsSVGPathGeometryFrame.h"
|
||||
|
||||
// Keep others in (case-insensitive) order:
|
||||
#include "gfx2DGlue.h"
|
||||
#include "gfxContext.h"
|
||||
#include "gfxPlatform.h"
|
||||
#include "gfxSVGGlyphs.h"
|
||||
#include "mozilla/gfx/2D.h"
|
||||
#include "mozilla/RefPtr.h"
|
||||
#include "nsDisplayList.h"
|
||||
#include "nsGkAtoms.h"
|
||||
#include "nsRenderingContext.h"
|
||||
|
@ -20,6 +23,7 @@
|
|||
#include "nsSVGUtils.h"
|
||||
#include "mozilla/ArrayUtils.h"
|
||||
#include "SVGAnimatedTransformList.h"
|
||||
#include "SVGContentUtils.h"
|
||||
#include "SVGGraphicsElement.h"
|
||||
|
||||
using namespace mozilla;
|
||||
|
@ -234,48 +238,77 @@ nsSVGPathGeometryFrame::PaintSVG(nsRenderingContext *aContext,
|
|||
nsIFrame*
|
||||
nsSVGPathGeometryFrame::GetFrameForPoint(const nsPoint &aPoint)
|
||||
{
|
||||
gfxMatrix canvasTM = GetCanvasTM(FOR_HIT_TESTING);
|
||||
if (canvasTM.IsSingular()) {
|
||||
gfxMatrix hitTestingTM = GetCanvasTM(FOR_HIT_TESTING);
|
||||
if (hitTestingTM.IsSingular()) {
|
||||
return nullptr;
|
||||
}
|
||||
uint16_t fillRule, hitTestFlags;
|
||||
FillRule fillRule;
|
||||
uint16_t hitTestFlags;
|
||||
if (GetStateBits() & NS_STATE_SVG_CLIPPATH_CHILD) {
|
||||
hitTestFlags = SVG_HIT_TEST_FILL;
|
||||
fillRule = StyleSVG()->mClipRule;
|
||||
fillRule = StyleSVG()->mClipRule == NS_STYLE_FILL_RULE_NONZERO
|
||||
? FillRule::FILL_WINDING : FillRule::FILL_EVEN_ODD;
|
||||
} else {
|
||||
hitTestFlags = GetHitTestFlags();
|
||||
nsPoint point =
|
||||
nsSVGUtils::TransformOuterSVGPointToChildFrame(aPoint, canvasTM, PresContext());
|
||||
nsSVGUtils::TransformOuterSVGPointToChildFrame(aPoint, hitTestingTM, PresContext());
|
||||
if (!hitTestFlags || ((hitTestFlags & SVG_HIT_TEST_CHECK_MRECT) &&
|
||||
!mRect.Contains(point)))
|
||||
!mRect.Contains(point))) {
|
||||
return nullptr;
|
||||
fillRule = StyleSVG()->mFillRule;
|
||||
}
|
||||
fillRule = StyleSVG()->mFillRule == NS_STYLE_FILL_RULE_NONZERO
|
||||
? FillRule::FILL_WINDING : FillRule::FILL_EVEN_ODD;
|
||||
}
|
||||
|
||||
bool isHit = false;
|
||||
|
||||
nsRefPtr<gfxContext> tmpCtx =
|
||||
new gfxContext(gfxPlatform::GetPlatform()->ScreenReferenceSurface());
|
||||
nsSVGPathGeometryElement* content =
|
||||
static_cast<nsSVGPathGeometryElement*>(mContent);
|
||||
|
||||
GeneratePath(tmpCtx, ToMatrix(canvasTM));
|
||||
gfxPoint userSpacePoint =
|
||||
tmpCtx->DeviceToUser(gfxPoint(aPoint.x, aPoint.y) / PresContext()->AppUnitsPerCSSPixel());
|
||||
// Using ScreenReferenceDrawTarget() opens us to Moz2D backend specific hit-
|
||||
// testing bugs. Maybe we should use a BackendType::CAIRO DT for hit-testing
|
||||
// so that we get more consistent/backwards compatible results?
|
||||
RefPtr<DrawTarget> drawTarget =
|
||||
gfxPlatform::GetPlatform()->ScreenReferenceDrawTarget();
|
||||
RefPtr<PathBuilder> builder =
|
||||
drawTarget->CreatePathBuilder(fillRule);
|
||||
RefPtr<Path> path = content->BuildPath(builder);
|
||||
if (!path) {
|
||||
return nullptr; // no path, so we don't paint anything that can be hit
|
||||
}
|
||||
|
||||
if (fillRule == NS_STYLE_FILL_RULE_EVENODD)
|
||||
tmpCtx->SetFillRule(gfxContext::FILL_RULE_EVEN_ODD);
|
||||
else
|
||||
tmpCtx->SetFillRule(gfxContext::FILL_RULE_WINDING);
|
||||
if (!hitTestingTM.IsIdentity()) {
|
||||
// We'll only get here if we don't have a nsDisplayItem that has called us
|
||||
// (for example, if we're a NS_FRAME_IS_NONDISPLAY frame under a clipPath).
|
||||
RefPtr<PathBuilder> builder =
|
||||
path->TransformedCopyToBuilder(ToMatrix(hitTestingTM), fillRule);
|
||||
path = builder->Finish();
|
||||
}
|
||||
|
||||
if (hitTestFlags & SVG_HIT_TEST_FILL)
|
||||
isHit = tmpCtx->PointInFill(userSpacePoint);
|
||||
int32_t appUnitsPerCSSPx = PresContext()->AppUnitsPerCSSPixel();
|
||||
Point userSpacePoint = Point(Float(aPoint.x) / appUnitsPerCSSPx,
|
||||
Float(aPoint.y) / appUnitsPerCSSPx);
|
||||
|
||||
if (hitTestFlags & SVG_HIT_TEST_FILL) {
|
||||
isHit = path->ContainsPoint(userSpacePoint, Matrix());
|
||||
}
|
||||
if (!isHit && (hitTestFlags & SVG_HIT_TEST_STROKE)) {
|
||||
nsSVGUtils::SetupCairoStrokeGeometry(this, tmpCtx);
|
||||
// tmpCtx's matrix may have transformed by SetupCairoStrokeGeometry
|
||||
// if there is a non-scaling stroke. We need to transform userSpacePoint
|
||||
// so that everything is using the same co-ordinate system.
|
||||
userSpacePoint =
|
||||
nsSVGUtils::GetStrokeTransform(this).Invert().Transform(userSpacePoint);
|
||||
isHit = tmpCtx->PointInStroke(userSpacePoint);
|
||||
SVGContentUtils::AutoStrokeOptions stroke;
|
||||
SVGContentUtils::GetStrokeOptions(&stroke, content, StyleContext(), nullptr);
|
||||
Matrix nonScalingStrokeMatrix =
|
||||
ToMatrix(nsSVGUtils::GetStrokeTransform(this));
|
||||
if (!nonScalingStrokeMatrix.IsIdentity()) {
|
||||
// We need to transform the path back into the appropriate ancestor
|
||||
// coordinate system in order for non-scaled stroke to be correct.
|
||||
// Naturally we also need to transform the point into the same
|
||||
// coordinate system in order to hit-test against the path.
|
||||
nonScalingStrokeMatrix.Invert();
|
||||
userSpacePoint = ToMatrix(hitTestingTM) * nonScalingStrokeMatrix * userSpacePoint;
|
||||
RefPtr<PathBuilder> builder =
|
||||
path->TransformedCopyToBuilder(nonScalingStrokeMatrix, fillRule);
|
||||
path = builder->Finish();
|
||||
}
|
||||
isHit = path->StrokeContainsPoint(stroke, userSpacePoint, Matrix());
|
||||
}
|
||||
|
||||
if (isHit && nsSVGUtils::HitTestClip(this, aPoint))
|
||||
|
@ -416,8 +449,21 @@ nsSVGPathGeometryFrame::GetBBoxContribution(const Matrix &aToBBoxUserspace,
|
|||
return bbox;
|
||||
}
|
||||
|
||||
nsRefPtr<gfxContext> tmpCtx =
|
||||
new gfxContext(gfxPlatform::GetPlatform()->ScreenReferenceSurface());
|
||||
RefPtr<DrawTarget> tmpDT;
|
||||
#ifdef XP_WIN
|
||||
// Unfortunately D2D backed DrawTarget produces bounds with rounding errors
|
||||
// when whole number results are expected, even in the case of trivial
|
||||
// calculations. To avoid that and meet the expectations of web content we
|
||||
// have to use a CAIRO DrawTarget. The most efficient way to do that is to
|
||||
// wrap the cached cairo_surface_t from ScreenReferenceSurface():
|
||||
nsRefPtr<gfxASurface> refSurf =
|
||||
gfxPlatform::GetPlatform()->ScreenReferenceSurface();
|
||||
tmpDT = gfxPlatform::GetPlatform()->
|
||||
CreateDrawTargetForSurface(refSurf, IntSize(1, 1));
|
||||
#else
|
||||
tmpDT = gfxPlatform::GetPlatform()->ScreenReferenceDrawTarget();
|
||||
#endif
|
||||
nsRefPtr<gfxContext> tmpCtx = new gfxContext(tmpDT);
|
||||
|
||||
GeneratePath(tmpCtx, aToBBoxUserspace);
|
||||
tmpCtx->IdentityMatrix();
|
||||
|
|
|
@ -356,9 +356,13 @@ nsSVGUtils::GetOuterSVGFrameAndCoveredRegion(nsIFrame* aFrame, nsRect* aRect)
|
|||
nsISVGChildFrame* svg = do_QueryFrame(aFrame);
|
||||
if (!svg)
|
||||
return nullptr;
|
||||
nsSVGOuterSVGFrame* outer = GetOuterSVGFrame(aFrame);
|
||||
if (outer == svg) {
|
||||
return nullptr;
|
||||
}
|
||||
*aRect = (aFrame->GetStateBits() & NS_FRAME_IS_NONDISPLAY) ?
|
||||
nsRect(0, 0, 0, 0) : svg->GetCoveredRegion();
|
||||
return GetOuterSVGFrame(aFrame);
|
||||
return outer;
|
||||
}
|
||||
|
||||
gfxMatrix
|
||||
|
|
|
@ -19,11 +19,13 @@ public:
|
|||
NS_DECL_NSIOBSERVER
|
||||
|
||||
nsNetworkLinkService();
|
||||
virtual ~nsNetworkLinkService();
|
||||
|
||||
nsresult Init();
|
||||
nsresult Shutdown();
|
||||
|
||||
protected:
|
||||
virtual ~nsNetworkLinkService();
|
||||
|
||||
private:
|
||||
bool mLinkUp;
|
||||
bool mStatusKnown;
|
||||
|
|
|
@ -12,12 +12,14 @@ class nsUserInfo: public nsIUserInfo
|
|||
{
|
||||
public:
|
||||
nsUserInfo();
|
||||
virtual ~nsUserInfo() {}
|
||||
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSIUSERINFO
|
||||
|
||||
|
||||
nsresult GetPrimaryEmailAddress(nsCString &aEmailAddress);
|
||||
|
||||
protected:
|
||||
virtual ~nsUserInfo() {}
|
||||
};
|
||||
|
||||
#endif /* __nsUserInfo_h */
|
||||
|
|
|
@ -30,13 +30,15 @@ public:
|
|||
NS_DECL_NSITIMERCALLBACK
|
||||
|
||||
OSXNotificationCenter();
|
||||
virtual ~OSXNotificationCenter();
|
||||
|
||||
nsresult Init();
|
||||
void CloseAlertCocoaString(NSString *aAlertName);
|
||||
void OnClick(NSString *aAlertName);
|
||||
void ShowPendingNotification(OSXNotificationInfo *osxni);
|
||||
|
||||
protected:
|
||||
virtual ~OSXNotificationCenter();
|
||||
|
||||
private:
|
||||
mozNotificationCenterDelegate *mDelegate;
|
||||
nsTArray<nsRefPtr<OSXNotificationInfo> > mActiveAlerts;
|
||||
|
|
|
@ -49,6 +49,8 @@ public:
|
|||
NS_DECL_ISUPPORTS;
|
||||
|
||||
private:
|
||||
~MacWakeLockListener() {}
|
||||
|
||||
IOPMAssertionID mAssertionID = kIOPMNullAssertionID;
|
||||
|
||||
NS_IMETHOD Callback(const nsAString& aTopic, const nsAString& aState) {
|
||||
|
|
|
@ -16,6 +16,8 @@ public:
|
|||
NS_DECL_NSIBIDIKEYBOARD
|
||||
|
||||
nsBidiKeyboard();
|
||||
|
||||
protected:
|
||||
virtual ~nsBidiKeyboard();
|
||||
};
|
||||
|
||||
|
|
|
@ -35,6 +35,8 @@ public:
|
|||
void Done();
|
||||
|
||||
private:
|
||||
~nsColorPicker();
|
||||
|
||||
static NSColor* GetNSColorFromHexString(const nsAString& aColor);
|
||||
static void GetHexStringFromNSColor(NSColor* aColor, nsAString& aResult);
|
||||
|
||||
|
|
|
@ -97,6 +97,10 @@ NS_IMPL_ISUPPORTS(nsColorPicker, nsIColorPicker)
|
|||
|
||||
NSColorPanelWrapper* nsColorPicker::sColorPanelWrapper = nullptr;
|
||||
|
||||
nsColorPicker::~nsColorPicker()
|
||||
{
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsColorPicker::Init(nsIDOMWindow* aParent, const nsAString& aTitle,
|
||||
const nsAString& aInitialColor)
|
||||
|
|
|
@ -21,7 +21,6 @@ class nsFilePicker : public nsBaseFilePicker
|
|||
{
|
||||
public:
|
||||
nsFilePicker();
|
||||
virtual ~nsFilePicker();
|
||||
|
||||
NS_DECL_ISUPPORTS
|
||||
|
||||
|
@ -46,6 +45,7 @@ public:
|
|||
NSArray* GetFilterList();
|
||||
|
||||
protected:
|
||||
virtual ~nsFilePicker();
|
||||
|
||||
virtual void InitNative(nsIWidget *aParent, const nsAString& aTitle);
|
||||
|
||||
|
|
|
@ -15,13 +15,14 @@ class nsMacDockSupport : public nsIMacDockSupport, public nsITaskbarProgress
|
|||
{
|
||||
public:
|
||||
nsMacDockSupport();
|
||||
virtual ~nsMacDockSupport();
|
||||
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSIMACDOCKSUPPORT
|
||||
NS_DECL_NSITASKBARPROGRESS
|
||||
|
||||
protected:
|
||||
virtual ~nsMacDockSupport();
|
||||
|
||||
nsCOMPtr<nsIStandaloneNativeMenu> mDockMenu;
|
||||
nsString mBadgeText;
|
||||
|
||||
|
|
|
@ -11,10 +11,12 @@
|
|||
class nsMacWebAppUtils : public nsIMacWebAppUtils {
|
||||
public:
|
||||
nsMacWebAppUtils() {}
|
||||
virtual ~nsMacWebAppUtils() {}
|
||||
|
||||
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSIMACWEBAPPUTILS
|
||||
|
||||
protected:
|
||||
virtual ~nsMacWebAppUtils() {}
|
||||
};
|
||||
|
||||
#endif //_MAC_WEB_APP_UTILS_H_
|
||||
|
|
|
@ -28,9 +28,11 @@ public:
|
|||
NS_DECL_ISUPPORTS
|
||||
|
||||
nsNativeMenuServiceX() {}
|
||||
virtual ~nsNativeMenuServiceX() {}
|
||||
|
||||
NS_IMETHOD CreateNativeMenuBar(nsIWidget* aParent, nsIContent* aMenuBarNode);
|
||||
|
||||
protected:
|
||||
virtual ~nsNativeMenuServiceX() {}
|
||||
};
|
||||
|
||||
@interface NSMenu (Undocumented)
|
||||
|
|
|
@ -27,7 +27,6 @@ class nsMenuGroupOwnerX : public nsMenuObjectX, public nsIMutationObserver
|
|||
{
|
||||
public:
|
||||
nsMenuGroupOwnerX();
|
||||
virtual ~nsMenuGroupOwnerX();
|
||||
|
||||
nsresult Create(nsIContent * aContent);
|
||||
|
||||
|
@ -42,6 +41,8 @@ public:
|
|||
NS_DECL_NSIMUTATIONOBSERVER
|
||||
|
||||
protected:
|
||||
virtual ~nsMenuGroupOwnerX();
|
||||
|
||||
nsChangeObserver* LookupContentChangeObserver(nsIContent* aContent);
|
||||
|
||||
uint32_t mCurrentCommandID; // unique command id (per menu-bar) to
|
||||
|
|
|
@ -19,7 +19,6 @@ class nsPrintDialogServiceX : public nsIPrintDialogService
|
|||
{
|
||||
public:
|
||||
nsPrintDialogServiceX();
|
||||
virtual ~nsPrintDialogServiceX();
|
||||
|
||||
NS_DECL_ISUPPORTS
|
||||
|
||||
|
@ -28,6 +27,9 @@ public:
|
|||
nsIWebBrowserPrint *aWebBrowserPrint);
|
||||
NS_IMETHODIMP ShowPageSetup(nsIDOMWindow *aParent,
|
||||
nsIPrintSettings *aSettings);
|
||||
|
||||
protected:
|
||||
virtual ~nsPrintDialogServiceX();
|
||||
};
|
||||
|
||||
@interface PrintPanelAccessoryView : NSView
|
||||
|
|
|
@ -17,11 +17,13 @@ class nsScreenManagerCocoa : public nsIScreenManager
|
|||
{
|
||||
public:
|
||||
nsScreenManagerCocoa();
|
||||
virtual ~nsScreenManagerCocoa();
|
||||
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSISCREENMANAGER
|
||||
|
||||
protected:
|
||||
virtual ~nsScreenManagerCocoa();
|
||||
|
||||
private:
|
||||
|
||||
nsScreenCocoa *ScreenForCocoaScreen(NSScreen *screen);
|
||||
|
|
|
@ -15,11 +15,13 @@ class nsSound : public nsISound,
|
|||
{
|
||||
public:
|
||||
nsSound();
|
||||
virtual ~nsSound();
|
||||
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSISOUND
|
||||
NS_DECL_NSISTREAMLOADEROBSERVER
|
||||
|
||||
protected:
|
||||
virtual ~nsSound();
|
||||
};
|
||||
|
||||
#endif // nsSound_h_
|
||||
|
|
|
@ -14,7 +14,6 @@ class nsStandaloneNativeMenu : public nsMenuGroupOwnerX, public nsIStandaloneNat
|
|||
{
|
||||
public:
|
||||
nsStandaloneNativeMenu();
|
||||
virtual ~nsStandaloneNativeMenu();
|
||||
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSISTANDALONENATIVEMENU
|
||||
|
@ -26,6 +25,8 @@ public:
|
|||
nsMenuX * GetMenuXObject() { return mMenu; }
|
||||
|
||||
protected:
|
||||
virtual ~nsStandaloneNativeMenu();
|
||||
|
||||
nsMenuX * mMenu;
|
||||
};
|
||||
|
||||
|
|
|
@ -25,7 +25,6 @@ class nsBaseClipboard : public nsIClipboard
|
|||
|
||||
public:
|
||||
nsBaseClipboard();
|
||||
virtual ~nsBaseClipboard();
|
||||
|
||||
//nsISupports
|
||||
NS_DECL_ISUPPORTS
|
||||
|
@ -34,6 +33,7 @@ public:
|
|||
NS_DECL_NSICLIPBOARD
|
||||
|
||||
protected:
|
||||
virtual ~nsBaseClipboard();
|
||||
|
||||
NS_IMETHOD SetNativeClipboardData ( int32_t aWhichClipboard ) = 0;
|
||||
NS_IMETHOD GetNativeClipboardData ( nsITransferable * aTransferable, int32_t aWhichClipboard ) = 0;
|
||||
|
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче