Merge m-c to m-i on a CLOSED TREE

This commit is contained in:
Gijs Kruitbosch 2013-11-02 15:33:00 +01:00
commit 7086a010d5
102 changed files with 2057 additions and 546 deletions

View File

@ -18,4 +18,4 @@
# Modifying this file will now automatically clobber the buildbot machines \o/
#
Bug 933120 needs a clobber because of bug 852814
Bug 906990 needs a clobber because of bug 928195

View File

@ -8,15 +8,10 @@
//****************************************************************************//
// Constants & Enumeration Values
/*
#ifndef XP_MACOSX
*/
var Cc = Components.classes;
var Ci = Components.interfaces;
var Cr = Components.results;
/*
#endif
*/
Components.utils.import('resource://gre/modules/Services.jsm');
const TYPE_MAYBE_FEED = "application/vnd.mozilla.maybe.feed";
@ -159,14 +154,14 @@ function isFeedType(t) {
* This object wraps nsIHandlerInfo with some additional functionality
* the Applications prefpane needs to display and allow modification of
* the list of handled types.
*
*
* We create an instance of this wrapper for each entry we might display
* in the prefpane, and we compose the instances from various sources,
* including navigator.plugins and the handler service.
* including plugins and the handler service.
*
* We don't implement all the original nsIHandlerInfo functionality,
* just the stuff that the prefpane needs.
*
*
* In theory, all of the custom functionality in this wrapper should get
* pushed down into nsIHandlerInfo eventually.
*/
@ -276,7 +271,7 @@ HandlerInfoWrapper.prototype = {
// What to do with content of this type.
get preferredAction() {
// If we have an enabled plugin, then the action is to use that plugin.
if (this.plugin && !this.isDisabledPluginType)
if (this.pluginName && !this.isDisabledPluginType)
return kActionUsePlugin;
// If the action is to use a helper app, but we don't have a preferred
@ -312,7 +307,7 @@ HandlerInfoWrapper.prototype = {
// of any user configuration, and the default in that case is to always ask,
// even though we never ask for content handled by a plugin, so special case
// plugin-handled types by returning false here.
if (this.plugin && this.handledOnlyByPlugin)
if (this.pluginName && this.handledOnlyByPlugin)
return false;
// If this is a protocol type and the preferred action is "save to disk",
@ -1092,10 +1087,17 @@ var gApplicationsPane = {
* check the pref ourselves to find out if it's enabled.
*/
_loadPluginHandlers: function() {
for (let i = 0; i < navigator.plugins.length; ++i) {
let plugin = navigator.plugins[i];
for (let j = 0; j < plugin.length; ++j) {
let type = plugin[j].type;
"use strict";
let pluginHost = Cc["@mozilla.org/plugin/host;1"].getService(Ci.nsIPluginHost);
let pluginTags = pluginHost.getPluginTags();
for (let i = 0; i < pluginTags.length; ++i) {
let pluginTag = pluginTags[i];
let mimeTypes = pluginTag.getMimeTypes();
for (let j = 0; j < mimeTypes.length; ++j) {
let type = mimeTypes[j];
let handlerInfoWrapper;
if (type in this._handledTypes)
@ -1108,7 +1110,7 @@ var gApplicationsPane = {
this._handledTypes[type] = handlerInfoWrapper;
}
handlerInfoWrapper.plugin = plugin;
handlerInfoWrapper.pluginName = pluginTag.name;
}
}
},
@ -1302,7 +1304,7 @@ var gApplicationsPane = {
case kActionUsePlugin:
return this._prefsBundle.getFormattedString("usePluginIn",
[aHandlerInfo.plugin.name,
[aHandlerInfo.pluginName,
this._brandShortName]);
}
},
@ -1484,11 +1486,11 @@ var gApplicationsPane = {
}
// Create a menu item for the plugin.
if (handlerInfo.plugin) {
if (handlerInfo.pluginName) {
var pluginMenuItem = document.createElement("menuitem");
pluginMenuItem.setAttribute("action", kActionUsePlugin);
let label = this._prefsBundle.getFormattedString("usePluginIn",
[handlerInfo.plugin.name,
[handlerInfo.pluginName,
this._brandShortName]);
pluginMenuItem.setAttribute("label", label);
pluginMenuItem.setAttribute("tooltiptext", label);
@ -1651,7 +1653,7 @@ var gApplicationsPane = {
// Set the plugin state if we're enabling or disabling a plugin.
if (action == kActionUsePlugin)
handlerInfo.enablePluginType();
else if (handlerInfo.plugin && !handlerInfo.isDisabledPluginType)
else if (handlerInfo.pluginName && !handlerInfo.isDisabledPluginType)
handlerInfo.disablePluginType();
// Set the preferred application handler.

View File

@ -146,14 +146,14 @@ function isFeedType(t) {
* This object wraps nsIHandlerInfo with some additional functionality
* the Applications prefpane needs to display and allow modification of
* the list of handled types.
*
*
* We create an instance of this wrapper for each entry we might display
* in the prefpane, and we compose the instances from various sources,
* including navigator.plugins and the handler service.
* including plugins and the handler service.
*
* We don't implement all the original nsIHandlerInfo functionality,
* just the stuff that the prefpane needs.
*
*
* In theory, all of the custom functionality in this wrapper should get
* pushed down into nsIHandlerInfo eventually.
*/
@ -263,7 +263,7 @@ HandlerInfoWrapper.prototype = {
// What to do with content of this type.
get preferredAction() {
// If we have an enabled plugin, then the action is to use that plugin.
if (this.plugin && !this.isDisabledPluginType)
if (this.pluginName && !this.isDisabledPluginType)
return kActionUsePlugin;
// If the action is to use a helper app, but we don't have a preferred
@ -299,7 +299,7 @@ HandlerInfoWrapper.prototype = {
// of any user configuration, and the default in that case is to always ask,
// even though we never ask for content handled by a plugin, so special case
// plugin-handled types by returning false here.
if (this.plugin && this.handledOnlyByPlugin)
if (this.pluginName && this.handledOnlyByPlugin)
return false;
// If this is a protocol type and the preferred action is "save to disk",
@ -1079,10 +1079,17 @@ var gApplicationsPane = {
* check the pref ourselves to find out if it's enabled.
*/
_loadPluginHandlers: function() {
for (let i = 0; i < navigator.plugins.length; ++i) {
let plugin = navigator.plugins[i];
for (let j = 0; j < plugin.length; ++j) {
let type = plugin[j].type;
"use strict";
let pluginHost = Cc["@mozilla.org/plugin/host;1"].getService(Ci.nsIPluginHost);
let pluginTags = pluginHost.getPluginTags();
for (let i = 0; i < pluginTags.length; ++i) {
let pluginTag = pluginTags[i];
let mimeTypes = pluginTag.getMimeTypes();
for (let j = 0; j < mimeTypes.length; ++j) {
let type = mimeTypes[j];
let handlerInfoWrapper;
if (type in this._handledTypes)
@ -1095,7 +1102,7 @@ var gApplicationsPane = {
this._handledTypes[type] = handlerInfoWrapper;
}
handlerInfoWrapper.plugin = plugin;
handlerInfoWrapper.pluginName = pluginTag.name;
}
}
},
@ -1289,7 +1296,7 @@ var gApplicationsPane = {
case kActionUsePlugin:
return this._prefsBundle.getFormattedString("usePluginIn",
[aHandlerInfo.plugin.name,
[aHandlerInfo.pluginName,
this._brandShortName]);
}
},
@ -1471,11 +1478,11 @@ var gApplicationsPane = {
}
// Create a menu item for the plugin.
if (handlerInfo.plugin) {
if (handlerInfo.pluginName) {
var pluginMenuItem = document.createElement("menuitem");
pluginMenuItem.setAttribute("action", kActionUsePlugin);
let label = this._prefsBundle.getFormattedString("usePluginIn",
[handlerInfo.plugin.name,
[handlerInfo.pluginName,
this._brandShortName]);
pluginMenuItem.setAttribute("label", label);
pluginMenuItem.setAttribute("tooltiptext", label);
@ -1638,7 +1645,7 @@ var gApplicationsPane = {
// Set the plugin state if we're enabling or disabling a plugin.
if (action == kActionUsePlugin)
handlerInfo.enablePluginType();
else if (handlerInfo.plugin && !handlerInfo.isDisabledPluginType)
else if (handlerInfo.pluginName && !handlerInfo.isDisabledPluginType)
handlerInfo.disablePluginType();
// Set the preferred application handler.

View File

@ -33,6 +33,7 @@
#include "nsMathUtils.h"
#include "nsNetUtil.h"
#include "nsStreamUtils.h"
#include "ActiveLayerTracker.h"
#ifdef MOZ_WEBGL
#include "../canvas/src/WebGL2Context.h"
@ -835,7 +836,7 @@ HTMLCanvasElement::InvalidateCanvasContent(const gfx::Rect* damageRect)
if (!frame)
return;
frame->MarkLayersActive(nsChangeHint(0));
ActiveLayerTracker::NotifyContentChange(frame);
Layer* layer = nullptr;
if (damageRect) {

View File

@ -4,12 +4,15 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "mozilla/dom/SVGCircleElement.h"
#include "mozilla/gfx/2D.h"
#include "nsGkAtoms.h"
#include "gfxContext.h"
#include "mozilla/dom/SVGCircleElementBinding.h"
NS_IMPL_NS_NEW_NAMESPACED_SVG_ELEMENT(Circle)
using namespace mozilla::gfx;
namespace mozilla {
namespace dom {
@ -90,5 +93,20 @@ SVGCircleElement::ConstructPath(gfxContext *aCtx)
aCtx->Arc(gfxPoint(x, y), r, 0, 2*M_PI);
}
TemporaryRef<Path>
SVGCircleElement::BuildPath()
{
RefPtr<PathBuilder> pathBuilder = CreatePathBuilder();
float x, y, r;
GetAnimatedLengthValues(&x, &y, &r, nullptr);
if (r > 0.0f) {
pathBuilder->Arc(Point(x, y), r, 0, Float(2*M_PI));
}
return pathBuilder->Finish();
}
} // namespace dom
} // namespace mozilla

View File

@ -32,6 +32,7 @@ public:
// nsSVGPathGeometryElement methods:
virtual void ConstructPath(gfxContext *aCtx) MOZ_OVERRIDE;
virtual TemporaryRef<Path> BuildPath() MOZ_OVERRIDE;
virtual nsresult Clone(nsINodeInfo *aNodeInfo, nsINode **aResult) const MOZ_OVERRIDE;

View File

@ -565,3 +565,25 @@ SVGContentUtils::ParseInteger(const nsAString& aString,
int64_t(std::numeric_limits<int32_t>::max())));
return true;
}
float
SVGContentUtils::CoordToFloat(nsPresContext *aPresContext,
nsSVGElement *aContent,
const nsStyleCoord &aCoord)
{
switch (aCoord.GetUnit()) {
case eStyleUnit_Factor:
// user units
return aCoord.GetFactorValue();
case eStyleUnit_Coord:
return nsPresContext::AppUnitsToFloatCSSPixels(aCoord.GetCoordValue());
case eStyleUnit_Percent: {
SVGSVGElement* ctx = aContent->GetCtx();
return ctx ? aCoord.GetPercentValue() * ctx->GetLength(SVGContentUtils::XY) : 0.0f;
}
default:
return 0.0f;
}
}

View File

@ -16,7 +16,9 @@
class nsIContent;
class nsIDocument;
class nsIFrame;
class nsPresContext;
class nsStyleContext;
class nsStyleCoord;
class nsSVGElement;
namespace mozilla {
@ -169,6 +171,15 @@ public:
*/
static bool
ParseInteger(const nsAString& aString, int32_t& aValue);
/**
* Converts an nsStyleCoord into a userspace value. Handles units
* Factor (straight userspace), Coord (dimensioned), and Percent (of
* aContent's SVG viewport)
*/
static float CoordToFloat(nsPresContext *aPresContext,
nsSVGElement *aContent,
const nsStyleCoord &aCoord);
};
#endif

View File

@ -5,10 +5,14 @@
#include "mozilla/dom/SVGEllipseElement.h"
#include "mozilla/dom/SVGEllipseElementBinding.h"
#include "mozilla/gfx/2D.h"
#include "mozilla/gfx/PathHelpers.h"
#include "gfxContext.h"
NS_IMPL_NS_NEW_NAMESPACED_SVG_ELEMENT(Ellipse)
using namespace mozilla::gfx;
namespace mozilla {
namespace dom {
@ -100,5 +104,20 @@ SVGEllipseElement::ConstructPath(gfxContext *aCtx)
}
}
TemporaryRef<Path>
SVGEllipseElement::BuildPath()
{
RefPtr<PathBuilder> pathBuilder = CreatePathBuilder();
float x, y, rx, ry;
GetAnimatedLengthValues(&x, &y, &rx, &ry, nullptr);
if (rx > 0.0f && ry > 0.0f) {
AppendEllipseToPath(pathBuilder, Point(x, y), Size(2.0*rx, 2.0*ry));
}
return pathBuilder->Finish();
}
} // namespace dom
} // namespace mozilla

View File

@ -32,6 +32,7 @@ public:
// nsSVGPathGeometryElement methods:
virtual void ConstructPath(gfxContext *aCtx) MOZ_OVERRIDE;
virtual TemporaryRef<Path> BuildPath() MOZ_OVERRIDE;
virtual nsresult Clone(nsINodeInfo *aNodeInfo, nsINode **aResult) const MOZ_OVERRIDE;

View File

@ -6,6 +6,7 @@
#include "mozilla/Util.h"
#include "mozilla/dom/SVGImageElement.h"
#include "mozilla/gfx/2D.h"
#include "nsCOMPtr.h"
#include "nsIURI.h"
#include "nsNetUtil.h"
@ -16,6 +17,8 @@
NS_IMPL_NS_NEW_NAMESPACED_SVG_ELEMENT(Image)
using namespace mozilla::gfx;
namespace mozilla {
namespace dom {
@ -236,6 +239,29 @@ SVGImageElement::ConstructPath(gfxContext *aCtx)
aCtx->Rectangle(gfxRect(x, y, width, height));
}
TemporaryRef<Path>
SVGImageElement::BuildPath()
{
// 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.
RefPtr<PathBuilder> pathBuilder = CreatePathBuilder();
float x, y, width, height;
GetAnimatedLengthValues(&x, &y, &width, &height, nullptr);
if (width <= 0 || height <= 0) {
Rect r(x, y, width, height);
pathBuilder->MoveTo(r.TopLeft());
pathBuilder->LineTo(r.TopRight());
pathBuilder->LineTo(r.BottomRight());
pathBuilder->LineTo(r.BottomLeft());
pathBuilder->Close();
}
return pathBuilder->Finish();
}
//----------------------------------------------------------------------
// nsSVGElement methods

View File

@ -55,6 +55,7 @@ public:
// nsSVGPathGeometryElement methods:
virtual void ConstructPath(gfxContext *aCtx) MOZ_OVERRIDE;
virtual TemporaryRef<Path> BuildPath() MOZ_OVERRIDE;
// nsSVGSVGElement methods:
virtual bool HasValidDimensions() const MOZ_OVERRIDE;

View File

@ -5,10 +5,13 @@
#include "mozilla/dom/SVGLineElement.h"
#include "mozilla/dom/SVGLineElementBinding.h"
#include "mozilla/gfx/2D.h"
#include "gfxContext.h"
NS_IMPL_NS_NEW_NAMESPACED_SVG_ELEMENT(Line)
using namespace mozilla::gfx;
namespace mozilla {
namespace dom {
@ -115,5 +118,19 @@ SVGLineElement::ConstructPath(gfxContext *aCtx)
aCtx->LineTo(gfxPoint(x2, y2));
}
TemporaryRef<Path>
SVGLineElement::BuildPath()
{
RefPtr<PathBuilder> pathBuilder = CreatePathBuilder();
float x1, y1, x2, y2;
GetAnimatedLengthValues(&x1, &y1, &x2, &y2, nullptr);
pathBuilder->MoveTo(Point(x1, y1));
pathBuilder->LineTo(Point(x2, y2));
return pathBuilder->Finish();
}
} // namespace dom
} // namespace mozilla

View File

@ -34,6 +34,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 nsresult Clone(nsINodeInfo *aNodeInfo, nsINode **aResult) const;

View File

@ -16,6 +16,7 @@
#include "nsSVGPathDataParser.h"
#include "nsSVGPathGeometryElement.h" // for nsSVGMark
#include <stdarg.h>
#include "nsStyleConsts.h"
#include "SVGContentUtils.h"
#include "SVGPathSegUtils.h"
#include "gfxContext.h"
@ -217,18 +218,51 @@ SVGPathData::GetPathSegAtLength(float aDistance) const
*
* Cairo only does this for |stroke-linecap: round| and not for
* |stroke-linecap: square| (since that's what Adobe Acrobat has always done).
* Most likely the other backends that DrawTarget uses have the same behavior.
*
* To help us conform to the SVG spec we have this helper function to draw an
* approximation of square caps for zero length subpaths. It does this by
* inserting a subpath containing a single axis aligned straight line that is
* as small as it can be without cairo throwing it away for being too small to
* affect rendering. Cairo will then draw stroke caps for this axis aligned
* line, creating an axis aligned rectangle (approximating the square that
* would ideally be drawn).
* inserting a subpath containing a single user space axis aligned straight
* line that is as small as it can be while minimizing the risk of it being
* thrown away by the DrawTarget's backend for being too small to affect
* rendering. The idea is that we'll then get stroke caps drawn for this axis
* aligned line, creating an axis aligned rectangle that approximates the
* square that would ideally be drawn.
*
* Since we don't have any information about transforms from user space to
* device space, we choose the length of the small line that we insert by
* making it a small percentage of the stroke width of the path. This should
* hopefully allow us to make the line as long as possible (to avoid rounding
* issues in the backend resulting in the backend seeing it as having zero
* length) while still avoiding the small rectangle being noticably different
* from a square.
*
* Note that this function inserts a subpath into the current gfx path that
* will be present during both fill and stroke operations.
*/
static void
ApproximateZeroLengthSubpathSquareCaps(PathBuilder* aPB,
const Point& aPoint,
Float aStrokeWidth)
{
// Note that caps are proportional to stroke width, so if stroke width is
// zero it's actually fine for |tinyLength| below to end up being zero.
// However, it would be a waste to inserting a LineTo in that case, so better
// not to.
MOZ_ASSERT(aStrokeWidth > 0.0f,
"Make the caller check for this, or check it here");
// The fraction of the stroke width that we choose for the length of the
// line is rather arbitrary, other than being chosen to meet the requirements
// described in the comment above.
Float tinyLength = aStrokeWidth / 32;
aPB->MoveTo(aPoint);
aPB->LineTo(aPoint + Point(tinyLength, 0));
aPB->MoveTo(aPoint);
}
static void
ApproximateZeroLengthSubpathSquareCaps(const gfxPoint &aPoint, gfxContext *aCtx)
{
@ -244,32 +278,12 @@ ApproximateZeroLengthSubpathSquareCaps(const gfxPoint &aPoint, gfxContext *aCtx)
aCtx->MoveTo(aPoint);
}
static void
ApproximateZeroLengthSubpathSquareCaps(const Point& aPoint,
DrawTarget* aDT,
PathBuilder* aPB)
{
// Cairo's fixed point fractional part is 8 bits wide, so its device space
// coordinate granularity is 1/256 pixels. However, to prevent user space
// |aPoint| and |aPoint + tinyAdvance| being rounded to the same device
// coordinates, we double this for |tinyAdvance|:
Matrix currentTransform = aDT->GetTransform();
currentTransform.Invert();
Size tinyAdvance = currentTransform * Size(2.0/256.0, 0.0);
aPB->MoveTo(aPoint);
aPB->LineTo(aPoint + Point(tinyAdvance.width, tinyAdvance.height));
aPB->MoveTo(aPoint);
}
#define MAYBE_APPROXIMATE_ZERO_LENGTH_SUBPATH_SQUARE_CAPS_TO_DT \
do { \
if (capsAreSquare && !subpathHasLength && subpathContainsNonArc && \
SVGPathSegUtils::IsValidType(prevSegType) && \
(!IsMoveto(prevSegType) || \
segType == PATHSEG_CLOSEPATH)) { \
ApproximateZeroLengthSubpathSquareCaps(segStart, aDT, builder); \
if (capsAreSquare && !subpathHasLength && aStrokeWidth > 0 && \
subpathContainsNonArc && SVGPathSegUtils::IsValidType(prevSegType) && \
(!IsMoveto(prevSegType) || segType == PATHSEG_CLOSEPATH)) { \
ApproximateZeroLengthSubpathSquareCaps(builder, segStart, aStrokeWidth);\
} \
} while(0)
@ -284,17 +298,23 @@ ApproximateZeroLengthSubpathSquareCaps(const Point& aPoint,
} while(0)
TemporaryRef<Path>
SVGPathData::ConstructPath(DrawTarget *aDT,
FillRule aFillRule,
CapStyle aCapStyle) const
SVGPathData::BuildPath(FillRule aFillRule,
uint8_t aStrokeLineCap,
Float aStrokeWidth) const
{
if (mData.IsEmpty() || !IsMoveto(SVGPathSegUtils::DecodeType(mData[0]))) {
return nullptr; // paths without an initial moveto are invalid
}
RefPtr<PathBuilder> builder = aDT->CreatePathBuilder(aFillRule);
RefPtr<DrawTarget> drawTarget =
gfxPlatform::GetPlatform()->ScreenReferenceDrawTarget();
NS_ASSERTION(gfxPlatform::GetPlatform()->
SupportsAzureContentForDrawTarget(drawTarget),
"Should support Moz2D content drawing");
bool capsAreSquare = aCapStyle == CAP_SQUARE;
RefPtr<PathBuilder> builder = drawTarget->CreatePathBuilder(aFillRule);
bool capsAreSquare = aStrokeLineCap == NS_STYLE_STROKE_LINECAP_SQUARE;
bool subpathHasLength = false; // visual length
bool subpathContainsNonArc = false;

View File

@ -12,6 +12,7 @@
#include "nsINode.h"
#include "nsIWeakReferenceUtils.h"
#include "mozilla/gfx/2D.h"
#include "mozilla/gfx/Types.h"
#include "mozilla/RefPtr.h"
#include "nsSVGElement.h"
#include "nsTArray.h"
@ -85,6 +86,7 @@ class SVGPathData
typedef gfx::DrawTarget DrawTarget;
typedef gfx::Path Path;
typedef gfx::FillRule FillRule;
typedef gfx::Float Float;
typedef gfx::CapStyle CapStyle;
public:
@ -161,9 +163,9 @@ public:
ToPath(const gfxMatrix& aMatrix) const;
void ConstructPath(gfxContext *aCtx) const;
TemporaryRef<Path> ConstructPath(DrawTarget* aDT,
FillRule aFillRule,
CapStyle aCapStyle) const;
TemporaryRef<Path> BuildPath(FillRule aFillRule,
uint8_t aCapStyle,
Float aStrokeWidth) const;
const_iterator begin() const { return mData.Elements(); }
const_iterator end() const { return mData.Elements() + mData.Length(); }

View File

@ -13,12 +13,18 @@
#include "gfxPath.h"
#include "mozilla/dom/SVGPathElementBinding.h"
#include "nsCOMPtr.h"
#include "nsComputedDOMStyle.h"
#include "nsGkAtoms.h"
#include "nsStyleConsts.h"
#include "nsStyleStruct.h"
#include "SVGContentUtils.h"
class gfxContext;
NS_IMPL_NS_NEW_NAMESPACED_SVG_ELEMENT(Path)
using namespace mozilla::gfx;
namespace mozilla {
namespace dom {
@ -350,5 +356,43 @@ SVGPathElement::GetPathLengthScale(PathLengthScaleForType aFor)
return 1.0;
}
TemporaryRef<Path>
SVGPathElement::BuildPath()
{
// 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
// spec regarding zero length sub-paths when square line caps are in use,
// SVGPathData needs to know our stroke-linecap style and, if "square", then
// also our stroke width. See the comment for
// ApproximateZeroLengthSubpathSquareCaps for more info.
uint8_t strokeLineCap = NS_STYLE_STROKE_LINECAP_BUTT;
Float strokeWidth = 0;
nsRefPtr<nsStyleContext> styleContext =
nsComputedDOMStyle::GetStyleContextForElementNoFlush(this, nullptr, nullptr);
if (styleContext) {
const nsStyleSVG* style = styleContext->StyleSVG();
// Note: the path that we return may be used for hit-testing, and SVG
// exposes hit-testing of strokes that are not actually painted. For that
// reason we do not check for eStyleSVGPaintType_None or check the stroke
// opacity here.
if (style->mStrokeLinecap == NS_STYLE_STROKE_LINECAP_SQUARE) {
strokeLineCap = style->mStrokeLinecap;
strokeWidth = GetStrokeWidth();
}
}
// 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.
return mD.GetAnimValue().BuildPath(GetFillRule(), strokeLineCap, strokeWidth);
}
} // namespace dom
} // namespace mozilla

View File

@ -47,6 +47,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 already_AddRefed<gfxPath> GetPath(const gfxMatrix &aMatrix) MOZ_OVERRIDE;

View File

@ -8,6 +8,7 @@
#include "nsDebug.h"
#include "gfxPoint.h"
#include "mozilla/gfx/Point.h"
namespace mozilla {
@ -18,6 +19,8 @@ namespace mozilla {
*/
class SVGPoint
{
typedef mozilla::gfx::Point Point;
public:
SVGPoint()
@ -57,6 +60,10 @@ public:
return gfxPoint(mX, mY);
}
operator Point() const {
return Point(mX, mY);
}
#ifdef DEBUG
bool IsValid() const {
return NS_finite(mX) && NS_finite(mY);

View File

@ -7,10 +7,14 @@
#include "nsGkAtoms.h"
#include "gfxContext.h"
#include "mozilla/dom/SVGRectElementBinding.h"
#include "mozilla/gfx/2D.h"
#include "mozilla/gfx/PathHelpers.h"
#include <algorithm>
NS_IMPL_NS_NEW_NAMESPACED_SVG_ELEMENT(Rect)
using namespace mozilla::gfx;
namespace mozilla {
namespace dom {
@ -148,5 +152,51 @@ SVGRectElement::ConstructPath(gfxContext *aCtx)
gfxCornerSizes(corner, corner, corner, corner));
}
TemporaryRef<Path>
SVGRectElement::BuildPath()
{
RefPtr<PathBuilder> pathBuilder = CreatePathBuilder();
float x, y, width, height, rx, ry;
GetAnimatedLengthValues(&x, &y, &width, &height, &rx, &ry, nullptr);
if (width > 0 && height > 0) {
rx = std::max(rx, 0.0f);
ry = std::max(ry, 0.0f);
if (rx == 0 && ry == 0) {
// Optimization for the no rounded corners case.
Rect r(x, y, width, height);
pathBuilder->MoveTo(r.TopLeft());
pathBuilder->LineTo(r.TopRight());
pathBuilder->LineTo(r.BottomRight());
pathBuilder->LineTo(r.BottomLeft());
pathBuilder->Close();
} else {
// If either the 'rx' or the 'ry' attribute isn't set, then we have to
// set it to the value of the other:
bool hasRx = mLengthAttributes[ATTR_RX].IsExplicitlySet();
bool hasRy = mLengthAttributes[ATTR_RY].IsExplicitlySet();
MOZ_ASSERT(hasRx || hasRy);
if (hasRx && !hasRy) {
ry = rx;
} else if (hasRy && !hasRx) {
rx = ry;
}
// Clamp rx and ry to half the rect's width and height respectively:
rx = std::min(rx, width / 2);
ry = std::min(ry, height / 2);
Size cornerRadii(rx, ry);
Size radii[] = { cornerRadii, cornerRadii, cornerRadii, cornerRadii };
AppendRoundedRectToPath(pathBuilder, Rect(x, y, width, height), radii);
}
}
return pathBuilder->Finish();
}
} // namespace dom
} // namespace mozilla

View File

@ -32,6 +32,7 @@ public:
// nsSVGPathGeometryElement methods:
virtual void ConstructPath(gfxContext *aCtx) MOZ_OVERRIDE;
virtual TemporaryRef<Path> BuildPath() MOZ_OVERRIDE;
virtual nsresult Clone(nsINodeInfo *aNodeInfo, nsINode **aResult) const MOZ_OVERRIDE;

View File

@ -4,7 +4,15 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "nsSVGPathGeometryElement.h"
#include "gfxPlatform.h"
#include "mozilla/gfx/2D.h"
#include "nsComputedDOMStyle.h"
#include "nsSVGLength2.h"
#include "SVGContentUtils.h"
using namespace mozilla;
using namespace mozilla::gfx;
//----------------------------------------------------------------------
// Implementation
@ -57,3 +65,61 @@ nsSVGPathGeometryElement::GetPath(const gfxMatrix &aMatrix)
{
return nullptr;
}
TemporaryRef<PathBuilder>
nsSVGPathGeometryElement::CreatePathBuilder()
{
RefPtr<DrawTarget> drawTarget =
gfxPlatform::GetPlatform()->ScreenReferenceDrawTarget();
NS_ASSERTION(gfxPlatform::GetPlatform()->
SupportsAzureContentForDrawTarget(drawTarget),
"Should support Moz2D content drawing");
// The fill rule that we pass to CreatePathBuilder 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.
return drawTarget->CreatePathBuilder(GetFillRule());
}
FillRule
nsSVGPathGeometryElement::GetFillRule()
{
FillRule fillRule = FILL_WINDING; // Equivalent to NS_STYLE_FILL_RULE_NONZERO
nsRefPtr<nsStyleContext> styleContext =
nsComputedDOMStyle::GetStyleContextForElementNoFlush(this, nullptr,
nullptr);
if (styleContext) {
MOZ_ASSERT(styleContext->StyleSVG()->mFillRule ==
NS_STYLE_FILL_RULE_NONZERO ||
styleContext->StyleSVG()->mFillRule ==
NS_STYLE_FILL_RULE_EVENODD);
if (styleContext->StyleSVG()->mFillRule == NS_STYLE_FILL_RULE_EVENODD) {
fillRule = FILL_EVEN_ODD;
}
} else {
// ReportToConsole
NS_WARNING("Couldn't get style context for content in GetFillRule");
}
return fillRule;
}
Float
nsSVGPathGeometryElement::GetStrokeWidth()
{
nsRefPtr<nsStyleContext> styleContext =
nsComputedDOMStyle::GetStyleContextForElementNoFlush(this, nullptr,
nullptr);
return styleContext ?
SVGContentUtils::CoordToFloat(styleContext->PresContext(), this,
styleContext->StyleSVG()->mStrokeWidth) :
0.0f;
}

View File

@ -6,6 +6,7 @@
#ifndef __NS_SVGPATHGEOMETRYELEMENT_H__
#define __NS_SVGPATHGEOMETRYELEMENT_H__
#include "mozilla/gfx/2D.h"
#include "SVGGraphicsElement.h"
class gfxPath;
@ -33,6 +34,12 @@ typedef mozilla::dom::SVGGraphicsElement nsSVGPathGeometryElementBase;
class nsSVGPathGeometryElement : public nsSVGPathGeometryElementBase
{
protected:
typedef mozilla::gfx::FillRule FillRule;
typedef mozilla::gfx::Float Float;
typedef mozilla::gfx::Path Path;
typedef mozilla::gfx::PathBuilder PathBuilder;
public:
nsSVGPathGeometryElement(already_AddRefed<nsINodeInfo> aNodeInfo);
@ -52,7 +59,34 @@ public:
virtual bool IsMarkable();
virtual void GetMarkPoints(nsTArray<nsSVGMark> *aMarks);
virtual void ConstructPath(gfxContext *aCtx) = 0;
/**
* Returns a Path that can be used to paint, hit-test or calculate bounds for
* this element.
*/
virtual mozilla::TemporaryRef<Path> BuildPath() = 0;
virtual already_AddRefed<gfxPath> GetPath(const gfxMatrix &aMatrix);
/**
* Returns a PathBuilder object created using the current computed value of
* the CSS property 'fill-rule' for this element.
*/
mozilla::TemporaryRef<PathBuilder> CreatePathBuilder();
/**
* Returns the current computed value of the CSS property 'fill-rule' for
* 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

View File

@ -6,9 +6,11 @@
#include "nsSVGPolyElement.h"
#include "DOMSVGPointList.h"
#include "gfxContext.h"
#include "mozilla/gfx/2D.h"
#include "SVGContentUtils.h"
using namespace mozilla;
using namespace mozilla::gfx;
//----------------------------------------------------------------------
// nsISupports methods
@ -120,3 +122,19 @@ nsSVGPolyElement::ConstructPath(gfxContext *aCtx)
}
}
TemporaryRef<Path>
nsSVGPolyElement::BuildPath()
{
RefPtr<PathBuilder> pathBuilder = CreatePathBuilder();
const SVGPointList &points = mPoints.GetAnimValue();
if (!points.IsEmpty()) {
pathBuilder->MoveTo(points[0]);
for (uint32_t i = 1; i < points.Length(); ++i) {
pathBuilder->LineTo(points[i]);
}
}
return pathBuilder->Finish();
}

View File

@ -43,6 +43,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;
// WebIDL
already_AddRefed<mozilla::DOMSVGPointList> Points();

View File

@ -434,6 +434,7 @@ public:
{
return mIsFrozen;
}
virtual NS_HIDDEN_(bool) IsRunningTimeout() { return mTimeoutFiringDepth > 0; }
virtual NS_HIDDEN_(bool) WouldReuseInnerWindow(nsIDocument *aNewDocument);

View File

@ -79,9 +79,7 @@ nsMimeTypeArray::IndexedGetter(uint32_t aIndex, bool &aFound)
{
aFound = false;
if (mMimeTypes.IsEmpty()) {
EnsureMimeTypes();
}
EnsurePluginMimeTypes();
MOZ_ASSERT(mMimeTypes.Length() >= mPluginMimeTypeCount);
@ -99,9 +97,7 @@ nsMimeTypeArray::NamedGetter(const nsAString& aName, bool &aFound)
{
aFound = false;
if (mMimeTypes.IsEmpty()) {
EnsureMimeTypes();
}
EnsurePluginMimeTypes();
for (uint32_t i = 0; i < mMimeTypes.Length(); ++i) {
if (aName.Equals(mMimeTypes[i]->Type())) {
@ -161,9 +157,7 @@ nsMimeTypeArray::NamedGetter(const nsAString& aName, bool &aFound)
uint32_t
nsMimeTypeArray::Length()
{
if (mMimeTypes.IsEmpty()) {
EnsureMimeTypes();
}
EnsurePluginMimeTypes();
MOZ_ASSERT(mMimeTypes.Length() >= mPluginMimeTypeCount);
@ -173,9 +167,7 @@ nsMimeTypeArray::Length()
void
nsMimeTypeArray::GetSupportedNames(nsTArray< nsString >& aRetval)
{
if (mMimeTypes.IsEmpty()) {
EnsureMimeTypes();
}
EnsurePluginMimeTypes();
for (uint32_t i = 0; i < mMimeTypes.Length(); ++i) {
aRetval.AppendElement(mMimeTypes[i]->Type());
@ -183,7 +175,7 @@ nsMimeTypeArray::GetSupportedNames(nsTArray< nsString >& aRetval)
}
void
nsMimeTypeArray::EnsureMimeTypes()
nsMimeTypeArray::EnsurePluginMimeTypes()
{
if (!mMimeTypes.IsEmpty() || !mWindow) {
return;
@ -203,14 +195,7 @@ nsMimeTypeArray::EnsureMimeTypes()
return;
}
nsTArray<nsRefPtr<nsPluginElement> > plugins;
pluginArray->GetPlugins(plugins);
for (uint32_t i = 0; i < plugins.Length(); ++i) {
nsPluginElement *plugin = plugins[i];
mMimeTypes.AppendElements(plugin->MimeTypes());
}
pluginArray->GetMimeTypes(mMimeTypes);
mPluginMimeTypeCount = mMimeTypes.Length();
}

View File

@ -41,7 +41,7 @@ public:
void GetSupportedNames(nsTArray< nsString >& retval);
protected:
void EnsureMimeTypes();
void EnsurePluginMimeTypes();
void Clear();
nsCOMPtr<nsPIDOMWindow> mWindow;

View File

@ -189,6 +189,8 @@ public:
return mDoc;
}
virtual NS_HIDDEN_(bool) IsRunningTimeout() = 0;
protected:
// Lazily instantiate an about:blank document if necessary, and if
// we have what it takes to do so.

View File

@ -68,19 +68,20 @@ NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_2(nsPluginArray,
mPlugins)
void
nsPluginArray::GetPlugins(nsTArray<nsRefPtr<nsPluginElement> >& aPlugins)
nsPluginArray::GetMimeTypes(nsTArray<nsRefPtr<nsMimeType> >& aMimeTypes)
{
aPlugins.Clear();
aMimeTypes.Clear();
if (!AllowPlugins()) {
return;
}
if (mPlugins.IsEmpty()) {
EnsurePlugins();
}
EnsurePlugins();
aPlugins = mPlugins;
for (uint32_t i = 0; i < mPlugins.Length(); ++i) {
nsPluginElement *plugin = mPlugins[i];
aMimeTypes.AppendElements(plugin->MimeTypes());
}
}
nsPluginElement*
@ -151,9 +152,7 @@ nsPluginArray::IndexedGetter(uint32_t aIndex, bool &aFound)
return nullptr;
}
if (mPlugins.IsEmpty()) {
EnsurePlugins();
}
EnsurePlugins();
aFound = aIndex < mPlugins.Length();
@ -179,9 +178,7 @@ nsPluginArray::NamedGetter(const nsAString& aName, bool &aFound)
return nullptr;
}
if (mPlugins.IsEmpty()) {
EnsurePlugins();
}
EnsurePlugins();
for (uint32_t i = 0; i < mPlugins.Length(); ++i) {
nsAutoString pluginName;
@ -205,9 +202,7 @@ nsPluginArray::Length()
return 0;
}
if (mPlugins.IsEmpty()) {
EnsurePlugins();
}
EnsurePlugins();
return mPlugins.Length();
}
@ -250,11 +245,14 @@ nsPluginArray::AllowPlugins() const
void
nsPluginArray::EnsurePlugins()
{
if (!mPlugins.IsEmpty()) {
// We already have an array of plugin elements.
return;
}
nsRefPtr<nsPluginHost> pluginHost = nsPluginHost::GetInst();
if (!mPlugins.IsEmpty() || !pluginHost) {
// We already have an array of plugin elements, or no plugin host
if (!pluginHost) {
// We have no plugin host.
return;
}
@ -327,7 +325,7 @@ nsPluginElement::GetName(nsString& retval) const
nsMimeType*
nsPluginElement::Item(uint32_t aIndex)
{
EnsureMimeTypes();
EnsurePluginMimeTypes();
return mMimeTypes.SafeElementAt(aIndex);
}
@ -342,7 +340,7 @@ nsPluginElement::NamedItem(const nsAString& aName)
nsMimeType*
nsPluginElement::IndexedGetter(uint32_t aIndex, bool &aFound)
{
EnsureMimeTypes();
EnsurePluginMimeTypes();
aFound = aIndex < mMimeTypes.Length();
@ -352,7 +350,7 @@ nsPluginElement::IndexedGetter(uint32_t aIndex, bool &aFound)
nsMimeType*
nsPluginElement::NamedGetter(const nsAString& aName, bool &aFound)
{
EnsureMimeTypes();
EnsurePluginMimeTypes();
aFound = false;
@ -370,7 +368,7 @@ nsPluginElement::NamedGetter(const nsAString& aName, bool &aFound)
uint32_t
nsPluginElement::Length()
{
EnsureMimeTypes();
EnsurePluginMimeTypes();
return mMimeTypes.Length();
}
@ -378,7 +376,7 @@ nsPluginElement::Length()
void
nsPluginElement::GetSupportedNames(nsTArray< nsString >& retval)
{
EnsureMimeTypes();
EnsurePluginMimeTypes();
for (uint32_t i = 0; i < mMimeTypes.Length(); ++i) {
retval.AppendElement(mMimeTypes[i]->Type());
@ -388,13 +386,13 @@ nsPluginElement::GetSupportedNames(nsTArray< nsString >& retval)
nsTArray<nsRefPtr<nsMimeType> >&
nsPluginElement::MimeTypes()
{
EnsureMimeTypes();
EnsurePluginMimeTypes();
return mMimeTypes;
}
void
nsPluginElement::EnsureMimeTypes()
nsPluginElement::EnsurePluginMimeTypes()
{
if (!mMimeTypes.IsEmpty()) {
return;

View File

@ -43,7 +43,7 @@ public:
void Init();
void Invalidate();
void GetPlugins(nsTArray<nsRefPtr<nsPluginElement> >& aPlugins);
void GetMimeTypes(nsTArray<nsRefPtr<nsMimeType> >& aMimeTypes);
// PluginArray WebIDL methods
@ -97,7 +97,7 @@ public:
nsTArray<nsRefPtr<nsMimeType> >& MimeTypes();
protected:
void EnsureMimeTypes();
void EnsurePluginMimeTypes();
nsCOMPtr<nsPIDOMWindow> mWindow;
nsRefPtr<nsPluginTag> mPluginTag;

View File

@ -1421,6 +1421,7 @@ ContentParent::ContentParent(mozIApplication* aApp,
NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
mSubprocess = new GeckoChildProcessHost(GeckoProcessType_Content,
aOSPrivileges);
mSubprocess->SetSandboxEnabled(ShouldSandboxContentProcesses());
IToplevelProtocol::SetTransport(mSubprocess->GetChannel());
@ -3282,5 +3283,15 @@ ContentParent::ShouldContinueFromReplyTimeout()
return false;
}
bool
ContentParent::ShouldSandboxContentProcesses()
{
#ifdef MOZ_CONTENT_SANDBOX
return !PR_GetEnv("MOZ_DISABLE_CONTENT_SANDBOX");
#else
return true;
#endif
}
} // namespace dom
} // namespace mozilla

View File

@ -220,6 +220,7 @@ protected:
void OnNuwaForkTimeout();
bool ShouldContinueFromReplyTimeout() MOZ_OVERRIDE;
bool ShouldSandboxContentProcesses();
private:
static nsDataHashtable<nsStringHashKey, ContentParent*> *sAppContentParents;

View File

@ -16,7 +16,7 @@ const PC_SESSION_CONTRACT = "@mozilla.org/dom/rtcsessiondescription;1";
const PC_MANAGER_CONTRACT = "@mozilla.org/dom/peerconnectionmanager;1";
const PC_STATS_CONTRACT = "@mozilla.org/dom/rtcstatsreport;1";
const PC_CID = Components.ID("{fc684a5c-c729-42c7-aa82-3c10dc4398f3}");
const PC_CID = Components.ID("{00e0e20d-1494-4776-8e0e-0f0acbea3c79}");
const PC_OBS_CID = Components.ID("{1d44a18e-4545-4ff3-863d-6dbd6234a583}");
const PC_ICE_CID = Components.ID("{02b9970c-433d-4cc2-923d-f7028ac66073}");
const PC_SESSION_CID = Components.ID("{1775081b-b62d-4954-8ffe-a067bbf508a7}");
@ -719,18 +719,26 @@ RTCPeerConnection.prototype = {
},
getStats: function(selector, onSuccess, onError) {
this._onGetStatsSuccess = onSuccess;
this._onGetStatsFailure = onError;
this._queueOrRun({
func: this._getStats,
args: [selector],
args: [selector, onSuccess, onError, false],
wait: true
});
},
_getStats: function(selector) {
this._getPC().getStats(selector);
getStatsInternal: function(selector, onSuccess, onError) {
this._queueOrRun({
func: this._getStats,
args: [selector, onSuccess, onError, true],
wait: true
});
},
_getStats: function(selector, onSuccess, onError, internal) {
this._onGetStatsSuccess = onSuccess;
this._onGetStatsFailure = onError;
this._getPC().getStats(selector, internal);
},
createDataChannel: function(label, dict) {
@ -1077,6 +1085,7 @@ PeerConnectionObserver.prototype = {
appendStats(dict.mediaStreamStats, report);
appendStats(dict.transportStats, report);
appendStats(dict.iceComponentStats, report);
appendStats(dict.iceCandidatePairStats, report);
appendStats(dict.iceCandidateStats, report);
appendStats(dict.codecStats, report);

View File

@ -1,11 +1,11 @@
component {fc684a5c-c729-42c7-aa82-3c10dc4398f3} PeerConnection.js
component {00e0e20d-1494-4776-8e0e-0f0acbea3c79} PeerConnection.js
component {1d44a18e-4545-4ff3-863d-6dbd6234a583} PeerConnection.js
component {02b9970c-433d-4cc2-923d-f7028ac66073} PeerConnection.js
component {1775081b-b62d-4954-8ffe-a067bbf508a7} PeerConnection.js
component {7293e901-2be3-4c02-b4bd-cbef6fc24f78} PeerConnection.js
component {7fe6e18b-0da3-4056-bf3b-440ef3809e06} PeerConnection.js
contract @mozilla.org/dom/peerconnection;1 {fc684a5c-c729-42c7-aa82-3c10dc4398f3}
contract @mozilla.org/dom/peerconnection;1 {00e0e20d-1494-4776-8e0e-0f0acbea3c79}
contract @mozilla.org/dom/peerconnectionobserver;1 {1d44a18e-4545-4ff3-863d-6dbd6234a583}
contract @mozilla.org/dom/rtcicecandidate;1 {02b9970c-433d-4cc2-923d-f7028ac66073}
contract @mozilla.org/dom/rtcsessiondescription;1 {1775081b-b62d-4954-8ffe-a067bbf508a7}

View File

@ -97,7 +97,7 @@ function waitForPaintHelper(func) {
setTimeout(func, 0);
return;
}
setTimeout(function() { waitForPaintHelper(func); }, 100);
setTimeout(function() { waitForPaintHelper(func); }, 1000);
}
</script>

View File

@ -35,7 +35,7 @@ interface PeerConnectionImpl {
/* Stats call */
[Throws]
void getStats(MediaStreamTrack? selector);
void getStats(MediaStreamTrack? selector, boolean internalStats);
/* Adds the stream created by GetUserMedia */
[Throws]

View File

@ -125,6 +125,11 @@ interface mozRTCPeerConnection : EventTarget {
RTCStatsCallback successCallback,
RTCPeerConnectionErrorCallback failureCallback);
[ChromeOnly]
void getStatsInternal (MediaStreamTrack? selector,
RTCStatsCallback successCallback,
RTCPeerConnectionErrorCallback failureCallback);
// Data channel.
RTCDataChannel createDataChannel (DOMString label,
optional RTCDataChannelInit dataChannelDict);

View File

@ -9,7 +9,13 @@
enum RTCStatsType {
"inboundrtp",
"outboundrtp"
"outboundrtp",
"session",
"track",
"transport",
"candidatepair",
"localcandidate",
"remotecandidate"
};
dictionary RTCStats {
@ -70,6 +76,26 @@ dictionary RTCIceComponentStats : RTCStats {
boolean activeConnection;
};
enum RTCStatsIceCandidatePairState {
"frozen",
"waiting",
"inprogress",
"failed",
"succeeded",
"cancelled"
};
dictionary RTCIceCandidatePairStats : RTCStats {
DOMString componentId;
DOMString localCandidateId;
DOMString remoteCandidateId;
RTCStatsIceCandidatePairState state;
unsigned long long mozPriority;
boolean readable;
boolean nominated;
boolean selected;
};
enum RTCStatsIceCandidateType {
"host",
"serverreflexive",
@ -105,6 +131,7 @@ dictionary RTCStatsReportInternal {
sequence<RTCMediaStreamStats> mediaStreamStats;
sequence<RTCTransportStats> transportStats;
sequence<RTCIceComponentStats> iceComponentStats;
sequence<RTCIceCandidatePairStats> iceCandidatePairStats;
sequence<RTCIceCandidateStats> iceCandidateStats;
sequence<RTCCodecStats> codecStats;
};

167
gfx/2d/PathHelpers.cpp Normal file
View File

@ -0,0 +1,167 @@
/* -*- 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 "PathHelpers.h"
namespace mozilla {
namespace gfx {
void
AppendRoundedRectToPath(PathBuilder* aPathBuilder,
const Rect& aRect,
// paren's needed due to operator precedence:
const Size(& aCornerRadii)[4],
bool aDrawClockwise)
{
// For CW drawing, this looks like:
//
// ...******0** 1 C
// ****
// *** 2
// **
// *
// *
// 3
// *
// *
//
// Where 0, 1, 2, 3 are the control points of the Bezier curve for
// the corner, and C is the actual corner point.
//
// At the start of the loop, the current point is assumed to be
// the point adjacent to the top left corner on the top
// horizontal. Note that corner indices start at the top left and
// continue clockwise, whereas in our loop i = 0 refers to the top
// right corner.
//
// When going CCW, the control points are swapped, and the first
// corner that's drawn is the top left (along with the top segment).
//
// There is considerable latitude in how one chooses the four
// control points for a Bezier curve approximation to an ellipse.
// For the overall path to be continuous and show no corner at the
// endpoints of the arc, points 0 and 3 must be at the ends of the
// straight segments of the rectangle; points 0, 1, and C must be
// collinear; and points 3, 2, and C must also be collinear. This
// leaves only two free parameters: the ratio of the line segments
// 01 and 0C, and the ratio of the line segments 32 and 3C. See
// the following papers for extensive discussion of how to choose
// these ratios:
//
// Dokken, Tor, et al. "Good approximation of circles by
// curvature-continuous Bezier curves." Computer-Aided
// Geometric Design 7(1990) 33--41.
// Goldapp, Michael. "Approximation of circular arcs by cubic
// polynomials." Computer-Aided Geometric Design 8(1991) 227--238.
// Maisonobe, Luc. "Drawing an elliptical arc using polylines,
// quadratic, or cubic Bezier curves."
// http://www.spaceroots.org/documents/ellipse/elliptical-arc.pdf
//
// We follow the approach in section 2 of Goldapp (least-error,
// Hermite-type approximation) and make both ratios equal to
//
// 2 2 + n - sqrt(2n + 28)
// alpha = - * ---------------------
// 3 n - 4
//
// where n = 3( cbrt(sqrt(2)+1) - cbrt(sqrt(2)-1) ).
//
// This is the result of Goldapp's equation (10b) when the angle
// swept out by the arc is pi/2, and the parameter "a-bar" is the
// expression given immediately below equation (21).
//
// Using this value, the maximum radial error for a circle, as a
// fraction of the radius, is on the order of 0.2 x 10^-3.
// Neither Dokken nor Goldapp discusses error for a general
// ellipse; Maisonobe does, but his choice of control points
// follows different constraints, and Goldapp's expression for
// 'alpha' gives much smaller radial error, even for very flat
// ellipses, than Maisonobe's equivalent.
//
// For the various corners and for each axis, the sign of this
// constant changes, or it might be 0 -- it's multiplied by the
// appropriate multiplier from the list before using.
const Float alpha = Float(0.55191497064665766025);
typedef struct { Float a, b; } twoFloats;
twoFloats cwCornerMults[4] = { { -1, 0 }, // cc == clockwise
{ 0, -1 },
{ +1, 0 },
{ 0, +1 } };
twoFloats ccwCornerMults[4] = { { +1, 0 }, // ccw == counter-clockwise
{ 0, -1 },
{ -1, 0 },
{ 0, +1 } };
twoFloats *cornerMults = aDrawClockwise ? cwCornerMults : ccwCornerMults;
Point cornerCoords[] = { aRect.TopLeft(), aRect.TopRight(),
aRect.BottomRight(), aRect.BottomLeft() };
Point pc, p0, p1, p2, p3;
// The indexes of the corners:
const int kTopLeft = 0, kTopRight = 1;
if (aDrawClockwise) {
aPathBuilder->MoveTo(Point(aRect.X() + aCornerRadii[kTopLeft].width,
aRect.Y()));
} else {
aPathBuilder->MoveTo(Point(aRect.X() + aRect.Width() - aCornerRadii[kTopRight].width,
aRect.Y()));
}
for (int i = 0; i < 4; ++i) {
// the corner index -- either 1 2 3 0 (cw) or 0 3 2 1 (ccw)
int c = aDrawClockwise ? ((i+1) % 4) : ((4-i) % 4);
// i+2 and i+3 respectively. These are used to index into the corner
// multiplier table, and were deduced by calculating out the long form
// of each corner and finding a pattern in the signs and values.
int i2 = (i+2) % 4;
int i3 = (i+3) % 4;
pc = cornerCoords[c];
if (aCornerRadii[c].width > 0.0 && aCornerRadii[c].height > 0.0) {
p0.x = pc.x + cornerMults[i].a * aCornerRadii[c].width;
p0.y = pc.y + cornerMults[i].b * aCornerRadii[c].height;
p3.x = pc.x + cornerMults[i3].a * aCornerRadii[c].width;
p3.y = pc.y + cornerMults[i3].b * aCornerRadii[c].height;
p1.x = p0.x + alpha * cornerMults[i2].a * aCornerRadii[c].width;
p1.y = p0.y + alpha * cornerMults[i2].b * aCornerRadii[c].height;
p2.x = p3.x - alpha * cornerMults[i3].a * aCornerRadii[c].width;
p2.y = p3.y - alpha * cornerMults[i3].b * aCornerRadii[c].height;
aPathBuilder->LineTo(p0);
aPathBuilder->BezierTo(p1, p2, p3);
} else {
aPathBuilder->LineTo(pc);
}
}
aPathBuilder->Close();
}
void
AppendEllipseToPath(PathBuilder* aPathBuilder,
const Point& aCenter,
const Size& aDimensions)
{
Size halfDim = aDimensions / 2.0;
Rect rect(aCenter - Point(halfDim.width, halfDim.height), aDimensions);
Size radii[] = { halfDim, halfDim, halfDim, halfDim };
AppendRoundedRectToPath(aPathBuilder, rect, radii);
}
} // namespace gfx
} // namespace mozilla

View File

@ -81,7 +81,35 @@ void ArcToBezier(T* aSink, const Point &aOrigin, float aRadius, float aStartAngl
}
}
}
}
/**
* Appends a path represending a rounded rectangle to the path being built by
* aPathBuilder.
*
* aRect The rectangle to append.
* aCornerRadii Contains the radii of the top-left, top-right, bottom-right
* and bottom-left corners, in that order.
* aDrawClockwise If set to true, the path will start at the left of the top
* left edge and draw clockwise. If set to false the path will
* start at the right of the top left edge and draw counter-
* clockwise.
*/
GFX2D_API void AppendRoundedRectToPath(PathBuilder* aPathBuilder,
const Rect& aRect,
const Size(& aCornerRadii)[4],
bool aDrawClockwise = true);
/**
* Appends a path represending an ellipse to the path being built by
* aPathBuilder.
*
* The ellipse extends aDimensions.width / 2.0 in the horizontal direction
* from aCenter, and aDimensions.height / 2.0 in the vertical direction.
*/
GFX2D_API void AppendEllipseToPath(PathBuilder* aPathBuilder,
const Point& aCenter,
const Size& aDimensions);
} // namespace gfx
} // namespace mozilla
#endif /* MOZILLA_GFX_PATHHELPERS_H_ */

View File

@ -89,6 +89,7 @@ SOURCES += [
'ImageScaling.cpp',
'Matrix.cpp',
'PathCairo.cpp',
'PathHelpers.cpp',
'PathRecording.cpp',
'RecordedEvent.cpp',
'Scale.cpp',

View File

@ -22,6 +22,7 @@
#include "gfxTeeSurface.h"
#include "GeckoProfiler.h"
#include "gfx2DGlue.h"
#include "mozilla/gfx/PathHelpers.h"
#include <algorithm>
#if CAIRO_HAS_DWRITE_FONT
@ -1911,62 +1912,11 @@ gfxContext::RoundedRectangle(const gfxRect& rect,
cairo_close_path (mCairo);
} else {
EnsurePathBuilder();
const gfxFloat alpha = 0.55191497064665766025;
typedef struct { gfxFloat a, b; } twoFloats;
twoFloats cwCornerMults[4] = { { -1, 0 },
{ 0, -1 },
{ +1, 0 },
{ 0, +1 } };
twoFloats ccwCornerMults[4] = { { +1, 0 },
{ 0, -1 },
{ -1, 0 },
{ 0, +1 } };
twoFloats *cornerMults = draw_clockwise ? cwCornerMults : ccwCornerMults;
gfxPoint pc, p0, p1, p2, p3;
if (draw_clockwise)
mPathBuilder->MoveTo(Point(Float(rect.X() + corners[NS_CORNER_TOP_LEFT].width), Float(rect.Y())));
else
mPathBuilder->MoveTo(Point(Float(rect.X() + rect.Width() - corners[NS_CORNER_TOP_RIGHT].width), Float(rect.Y())));
NS_FOR_CSS_CORNERS(i) {
// the corner index -- either 1 2 3 0 (cw) or 0 3 2 1 (ccw)
mozilla::css::Corner c = mozilla::css::Corner(draw_clockwise ? ((i+1) % 4) : ((4-i) % 4));
// i+2 and i+3 respectively. These are used to index into the corner
// multiplier table, and were deduced by calculating out the long form
// of each corner and finding a pattern in the signs and values.
int i2 = (i+2) % 4;
int i3 = (i+3) % 4;
pc = rect.AtCorner(c);
if (corners[c].width > 0.0 && corners[c].height > 0.0) {
p0.x = pc.x + cornerMults[i].a * corners[c].width;
p0.y = pc.y + cornerMults[i].b * corners[c].height;
p3.x = pc.x + cornerMults[i3].a * corners[c].width;
p3.y = pc.y + cornerMults[i3].b * corners[c].height;
p1.x = p0.x + alpha * cornerMults[i2].a * corners[c].width;
p1.y = p0.y + alpha * cornerMults[i2].b * corners[c].height;
p2.x = p3.x - alpha * cornerMults[i3].a * corners[c].width;
p2.y = p3.y - alpha * cornerMults[i3].b * corners[c].height;
mPathBuilder->LineTo(ToPoint(p0));
mPathBuilder->BezierTo(ToPoint(p1), ToPoint(p2), ToPoint(p3));
} else {
mPathBuilder->LineTo(ToPoint(pc));
}
}
mPathBuilder->Close();
Size radii[] = { ToSize(corners[NS_CORNER_TOP_LEFT]),
ToSize(corners[NS_CORNER_TOP_RIGHT]),
ToSize(corners[NS_CORNER_BOTTOM_RIGHT]),
ToSize(corners[NS_CORNER_BOTTOM_LEFT]) };
AppendRoundedRectToPath(mPathBuilder, ToRect(rect), radii, draw_clockwise);
}
}

View File

@ -70,14 +70,16 @@ InitializeBinder(void *aDummy) {
int
main(int argc, char* argv[])
{
#ifdef MOZ_NUWA_PROCESS
bool isNuwa = false;
bool isSandboxEnabled = false;
for (int i = 1; i < argc; i++) {
if (strcmp(argv[i], "-nuwa") == 0) {
PrepareNuwaProcess();
isNuwa = true;
break;
}
isNuwa |= strcmp(argv[i], "-nuwa") == 0;
isSandboxEnabled |= strcmp(argv[i], "-sandbox") == 0;
}
#ifdef MOZ_NUWA_PROCESS
if (isNuwa) {
PrepareNuwaProcess();
}
#endif
@ -99,19 +101,21 @@ main(int argc, char* argv[])
#endif
#if defined(XP_WIN) && defined(MOZ_CONTENT_SANDBOX)
sandbox::TargetServices* target_service =
sandbox::SandboxFactory::GetTargetServices();
if (!target_service) {
return 1;
}
if (isSandboxEnabled) {
sandbox::TargetServices* target_service =
sandbox::SandboxFactory::GetTargetServices();
if (!target_service) {
return 1;
}
sandbox::ResultCode result = target_service->Init();
if (result != sandbox::SBOX_ALL_OK) {
return 2;
}
sandbox::ResultCode result = target_service->Init();
if (result != sandbox::SBOX_ALL_OK) {
return 2;
}
// Initialization is finished, switch to the lowered token
target_service->LowerToken();
// Initialization is finished, switch to the lowered token
target_service->LowerToken();
}
#endif
// Check for the absolute minimum number of args we need to move

View File

@ -87,6 +87,7 @@ GeckoChildProcessHost::GeckoChildProcessHost(GeckoProcessType aProcessType,
ChildPrivileges aPrivileges)
: ChildProcessHost(RENDER_PROCESS), // FIXME/cjones: we should own this enum
mProcessType(aProcessType),
mSandboxEnabled(true),
mPrivileges(aPrivileges),
mMonitor("mozilla.ipc.GeckChildProcessHost.mMonitor"),
mProcessState(CREATING_CHANNEL),
@ -739,6 +740,13 @@ GeckoChildProcessHost::PerformAsyncLaunchInternal(std::vector<std::string>& aExt
}
}
#if defined(XP_WIN) && defined(MOZ_CONTENT_SANDBOX)
if (mSandboxEnabled) {
// Tell the process that it should lower its rights after initialization.
cmdLine.AppendLooseValue(UTF8ToWide("-sandbox"));
}
#endif
// Add the application directory path (-appdir path)
AddAppDirToCommandLine(cmdLine);
@ -761,14 +769,17 @@ GeckoChildProcessHost::PerformAsyncLaunchInternal(std::vector<std::string>& aExt
cmdLine.AppendLooseValue(UTF8ToWide(childProcessType));
#if defined(XP_WIN) && defined(MOZ_CONTENT_SANDBOX)
mozilla::SandboxBroker sandboxBroker;
sandboxBroker.LaunchApp(cmdLine.program().c_str(),
cmdLine.command_line_string().c_str(),
&process);
#else
base::LaunchApp(cmdLine, false, false, &process);
#endif
if (mSandboxEnabled) {
mozilla::SandboxBroker sandboxBroker;
sandboxBroker.LaunchApp(cmdLine.program().c_str(),
cmdLine.command_line_string().c_str(),
&process);
} else
#endif
{
base::LaunchApp(cmdLine, false, false, &process);
}
#else
# error Sorry

View File

@ -123,11 +123,17 @@ public:
*/
void Join();
void SetSandboxEnabled(bool aSandboxEnabled) {
mSandboxEnabled = aSandboxEnabled;
}
protected:
GeckoProcessType mProcessType;
bool mSandboxEnabled;
ChildPrivileges mPrivileges;
Monitor mMonitor;
FilePath mProcessPath;
// This value must be accessed while holding mMonitor.
enum {
// This object has been constructed, but the OS process has not

View File

@ -0,0 +1,3 @@
{
"expect-hazards": 19
}

View File

@ -2043,33 +2043,42 @@ js::array_push(JSContext *cx, unsigned argc, Value *vp)
if (!obj)
return false;
/* Fast path for the fully-dense case. */
if (obj->is<ArrayObject>()) {
Rooted<ArrayObject*> arr(cx, &obj->as<ArrayObject>());
if (arr->lengthIsWritable() && !ObjectMayHaveExtraIndexedProperties(arr)) {
uint32_t length = arr->length();
uint32_t argCount = args.length();
JSObject::EnsureDenseResult result = arr->ensureDenseElements(cx, length, argCount);
if (result == JSObject::ED_FAILED)
return false;
if (result == JSObject::ED_OK) {
arr->setLengthInt32(length + argCount);
for (uint32_t i = 0, index = length; i < argCount; index++, i++)
JSObject::setDenseElementWithType(cx, arr, index, args[i]);
args.rval().setNumber(arr->length());
return true;
}
MOZ_ASSERT(result == JSObject::ED_SPARSE);
}
}
/* Steps 2-3. */
uint32_t length;
if (!GetLengthProperty(cx, obj, &length))
return false;
/* Fast path for native objects with dense elements. */
do {
if (!obj->isNative())
break;
if (obj->is<ArrayObject>() && !obj->as<ArrayObject>().lengthIsWritable())
break;
if (ObjectMayHaveExtraIndexedProperties(obj))
break;
uint32_t argCount = args.length();
JSObject::EnsureDenseResult result = obj->ensureDenseElements(cx, length, argCount);
if (result == JSObject::ED_FAILED)
return false;
if (result == JSObject::ED_OK) {
for (uint32_t i = 0, index = length; i < argCount; index++, i++)
JSObject::setDenseElementWithType(cx, obj, index, args[i]);
uint32_t newlength = length + argCount;
args.rval().setNumber(newlength);
if (obj->is<ArrayObject>()) {
obj->as<ArrayObject>().setLengthInt32(newlength);
return true;
}
return SetLengthProperty(cx, obj, newlength);
}
MOZ_ASSERT(result == JSObject::ED_SPARSE);
} while (false);
/* Steps 4-5. */
if (!InitArrayElements(cx, obj, length, args.length(), args.array(), UpdateTypes))
return false;

View File

@ -0,0 +1,196 @@
/* 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 "ActiveLayerTracker.h"
#include "nsExpirationTracker.h"
#include "nsIFrame.h"
#include "nsIContent.h"
#include "nsRefreshDriver.h"
#include "nsPIDOMWindow.h"
#include "nsIDocument.h"
namespace mozilla {
/**
* This tracks the state of a frame that may need active layers due to
* ongoing content changes or style changes that indicate animation.
*
* When no changes of *any* kind are detected after 75-100ms we remove this
* object. Because we only track all kinds of activity with a single
* nsExpirationTracker, it's possible a frame might remain active somewhat
* spuriously if different kinds of changes kept happening, but that almost
* certainly doesn't matter.
*/
class LayerActivity {
public:
LayerActivity(nsIFrame* aFrame)
: mFrame(aFrame)
, mOpacityRestyleCount(0)
, mTransformRestyleCount(0)
, mContentActive(false)
{}
~LayerActivity();
nsExpirationState* GetExpirationState() { return &mState; }
uint8_t& RestyleCountForProperty(nsCSSProperty aProperty)
{
switch (aProperty) {
case eCSSProperty_opacity: return mOpacityRestyleCount;
case eCSSProperty_transform: return mTransformRestyleCount;
default: MOZ_ASSERT(false); return mOpacityRestyleCount;
}
}
nsIFrame* mFrame;
nsExpirationState mState;
// Number of restyle operations detected
uint8_t mOpacityRestyleCount;
uint8_t mTransformRestyleCount;
bool mContentActive;
};
class LayerActivityTracker MOZ_FINAL : public nsExpirationTracker<LayerActivity,4> {
public:
// 75-100ms is a good timeout period. We use 4 generations of 25ms each.
enum { GENERATION_MS = 100 };
LayerActivityTracker()
: nsExpirationTracker<LayerActivity,4>(GENERATION_MS) {}
~LayerActivityTracker() {
AgeAllGenerations();
}
virtual void NotifyExpired(LayerActivity* aObject);
};
static LayerActivityTracker* gLayerActivityTracker = nullptr;
LayerActivity::~LayerActivity()
{
if (mFrame) {
NS_ASSERTION(gLayerActivityTracker, "Should still have a tracker");
gLayerActivityTracker->RemoveObject(this);
}
}
static void DestroyLayerActivity(void* aPropertyValue)
{
delete static_cast<LayerActivity*>(aPropertyValue);
}
NS_DECLARE_FRAME_PROPERTY(LayerActivityProperty, DestroyLayerActivity)
void
LayerActivityTracker::NotifyExpired(LayerActivity* aObject)
{
RemoveObject(aObject);
nsIFrame* f = aObject->mFrame;
aObject->mFrame = nullptr;
f->SchedulePaint();
f->Properties().Delete(LayerActivityProperty());
}
static LayerActivity*
GetLayerActivity(nsIFrame* aFrame)
{
FrameProperties properties = aFrame->Properties();
return static_cast<LayerActivity*>(properties.Get(LayerActivityProperty()));
}
static LayerActivity*
GetLayerActivityForUpdate(nsIFrame* aFrame)
{
FrameProperties properties = aFrame->Properties();
LayerActivity* layerActivity =
static_cast<LayerActivity*>(properties.Get(LayerActivityProperty()));
if (layerActivity) {
gLayerActivityTracker->MarkUsed(layerActivity);
} else {
if (!gLayerActivityTracker) {
gLayerActivityTracker = new LayerActivityTracker();
}
layerActivity = new LayerActivity(aFrame);
gLayerActivityTracker->AddObject(layerActivity);
properties.Set(LayerActivityProperty(), layerActivity);
}
return layerActivity;
}
/* static */ void
ActiveLayerTracker::NotifyRestyle(nsIFrame* aFrame, nsCSSProperty aProperty)
{
LayerActivity* layerActivity = GetLayerActivityForUpdate(aFrame);
uint8_t& mutationCount = layerActivity->RestyleCountForProperty(aProperty);
mutationCount = uint8_t(std::min(0xFF, mutationCount + 1));
}
/* static */ void
ActiveLayerTracker::NotifyAnimated(nsIFrame* aFrame, nsCSSProperty aProperty)
{
LayerActivity* layerActivity = GetLayerActivityForUpdate(aFrame);
uint8_t& mutationCount = layerActivity->RestyleCountForProperty(aProperty);
// We know this is animated, so just hack the mutation count.
mutationCount = 0xFF;
}
static bool
IsPresContextInScriptAnimationCallback(nsPresContext* aPresContext)
{
if (aPresContext->RefreshDriver()->IsInRefresh()) {
return true;
}
// Treat timeouts/setintervals as scripted animation callbacks for our
// purposes.
nsPIDOMWindow* win = aPresContext->Document()->GetInnerWindow();
return win && win->IsRunningTimeout();
}
/* static */ void
ActiveLayerTracker::NotifyInlineStyleRuleModified(nsIFrame* aFrame,
nsCSSProperty aProperty)
{
if (!IsPresContextInScriptAnimationCallback(aFrame->PresContext())) {
return;
}
NotifyAnimated(aFrame, aProperty);
}
/* static */ bool
ActiveLayerTracker::IsStyleAnimated(nsIFrame* aFrame, nsCSSProperty aProperty)
{
LayerActivity* layerActivity = GetLayerActivity(aFrame);
if (layerActivity) {
if (layerActivity->RestyleCountForProperty(aProperty) >= 2) {
return true;
}
}
if (aProperty == eCSSProperty_transform && aFrame->Preserves3D()) {
return IsStyleAnimated(aFrame->GetParent(), aProperty);
}
return false;
}
/* static */ void
ActiveLayerTracker::NotifyContentChange(nsIFrame* aFrame)
{
LayerActivity* layerActivity = GetLayerActivityForUpdate(aFrame);
layerActivity->mContentActive = true;
}
/* static */ bool
ActiveLayerTracker::IsContentActive(nsIFrame* aFrame)
{
LayerActivity* layerActivity = GetLayerActivity(aFrame);
return layerActivity && layerActivity->mContentActive;
}
/* static */ void
ActiveLayerTracker::Shutdown()
{
delete gLayerActivityTracker;
gLayerActivityTracker = nullptr;
}
}

View File

@ -0,0 +1,72 @@
/* 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 ACTIVELAYERTRACKER_H_
#define ACTIVELAYERTRACKER_H_
#include "nsCSSProperty.h"
class nsIFrame;
namespace mozilla {
/**
* This class receives various notifications about style changes and content
* changes that affect layerization decisions, and implements the heuristics
* that drive those decisions. It manages per-frame state to support those
* heuristics.
*/
class ActiveLayerTracker {
public:
static void Shutdown();
/*
* We track eCSSProperty_transform and eCSSProperty_opacity style changes
* and use that information to guess whether style changes are animated.
*/
/**
* Notify aFrame's style property as having changed due to a restyle,
* and therefore possibly wanting an active layer to render that style.
* Any such marking will time out after a short period.
* @param aProperty the property that has changed
*/
static void NotifyRestyle(nsIFrame* aFrame, nsCSSProperty aProperty);
/**
* Mark aFrame as being known to have an animation of aProperty.
* Any such marking will time out after a short period.
*/
static void NotifyAnimated(nsIFrame* aFrame, nsCSSProperty aProperty);
/**
* Notify that a property in the inline style rule of aFrame's element
* has been modified.
* This notification is incomplete --- not all modifications to inline
* style will trigger this.
*/
static void NotifyInlineStyleRuleModified(nsIFrame* aFrame, nsCSSProperty aProperty);
/**
* Return true if aFrame's aProperty style should be considered as being animated
* for constructing active layers.
*/
static bool IsStyleAnimated(nsIFrame* aFrame, nsCSSProperty aProperty);
/*
* We track modifications to the content of certain frames (i.e. canvas frames)
* and use that to make layering decisions.
*/
/**
* Mark aFrame's content as being active. This marking will time out after
* a short period.
*/
static void NotifyContentChange(nsIFrame* aFrame);
/**
* Return true if this frame's content is still marked as active.
*/
static bool IsContentActive(nsIFrame* aFrame);
};
}
#endif /* ACTIVELAYERTRACKER_H_ */

View File

@ -20,6 +20,7 @@
#include "LayerTreeInvalidation.h"
#include "nsSVGIntegrationUtils.h"
#include "ImageContainer.h"
#include "ActiveLayerTracker.h"
#include "GeckoProfiler.h"
#include "mozilla/gfx/Tools.h"
@ -2698,7 +2699,7 @@ ChooseScaleAndSetTransform(FrameLayerBuilder* aLayerBuilder,
aContainerFrame->GetContent(), eCSSProperty_transform)) {
scale = nsLayoutUtils::GetMaximumAnimatedScale(aContainerFrame->GetContent());
} else {
//Scale factors are normalized to a power of 2 to reduce the number of resolution changes
// Scale factors are normalized to a power of 2 to reduce the number of resolution changes
scale = RoundToFloatPrecision(transform2d.ScaleFactors(true));
// For frames with a changing transform that's not just a translation,
// round scale factors up to nearest power-of-2 boundary so that we don't
@ -2707,7 +2708,7 @@ ChooseScaleAndSetTransform(FrameLayerBuilder* aLayerBuilder,
// jaggies. It also ensures we never scale down by more than a factor of 2,
// avoiding bad downscaling quality.
gfxMatrix frameTransform;
if (aContainerFrame->AreLayersMarkedActive(nsChangeHint_UpdateTransformLayer) &&
if (ActiveLayerTracker::IsStyleAnimated(aContainerFrame, eCSSProperty_transform) &&
aTransform &&
(!aTransform->Is2D(&frameTransform) || frameTransform.HasNonTranslationOrFlip())) {
// Don't clamp the scale factor when the new desired scale factor matches the old one
@ -2748,7 +2749,7 @@ ChooseScaleAndSetTransform(FrameLayerBuilder* aLayerBuilder,
FrameLayerBuilder::ContainerParameters(scale.width, scale.height, -offset, aIncomingScale);
if (aTransform) {
aOutgoingScale.mInTransformedSubtree = true;
if (aContainerFrame->AreLayersMarkedActive(nsChangeHint_UpdateTransformLayer)) {
if (ActiveLayerTracker::IsStyleAnimated(aContainerFrame, eCSSProperty_transform)) {
aOutgoingScale.mInActiveTransformedSubtree = true;
}
}

View File

@ -34,6 +34,7 @@
#include "nsIDOMMutationEvent.h"
#include "nsContentUtils.h"
#include "nsIFrameInlines.h"
#include "ActiveLayerTracker.h"
#ifdef ACCESSIBILITY
#include "nsAccessibilityService.h"
@ -224,7 +225,8 @@ DoApplyRenderingChangeToTree(nsIFrame* aFrame,
// FIXME/bug 796697: we can get away with empty transactions for
// opacity updates in many cases.
needInvalidatingPaint = true;
aFrame->MarkLayersActive(nsChangeHint_UpdateOpacityLayer);
ActiveLayerTracker::NotifyRestyle(aFrame, eCSSProperty_opacity);
if (nsSVGIntegrationUtils::UsingEffectsForFrame(aFrame)) {
// SVG effects paints the opacity without using
// nsDisplayOpacity. We need to invalidate manually.
@ -233,7 +235,7 @@ DoApplyRenderingChangeToTree(nsIFrame* aFrame,
}
if ((aChange & nsChangeHint_UpdateTransformLayer) &&
aFrame->IsTransformed()) {
aFrame->MarkLayersActive(nsChangeHint_UpdateTransformLayer);
ActiveLayerTracker::NotifyRestyle(aFrame, eCSSProperty_transform);
// If we're not already going to do an invalidating paint, see
// if we can get away with only updating the transform on a
// layer for this frame, and not scheduling an invalidating
@ -247,7 +249,7 @@ DoApplyRenderingChangeToTree(nsIFrame* aFrame,
nsIFrame* childFrame =
GetFrameForChildrenOnlyTransformHint(aFrame)->GetFirstPrincipalChild();
for ( ; childFrame; childFrame = childFrame->GetNextSibling()) {
childFrame->MarkLayersActive(nsChangeHint_UpdateTransformLayer);
ActiveLayerTracker::NotifyRestyle(childFrame, eCSSProperty_transform);
}
}
aFrame->SchedulePaint(needInvalidatingPaint ?

View File

@ -26,6 +26,7 @@ XPIDL_MODULE = 'layout_base'
MODULE = 'layout'
EXPORTS += [
'ActiveLayerTracker.h',
'DisplayItemClip.h',
'DisplayListClipState.h',
'FrameLayerBuilder.h',
@ -66,6 +67,7 @@ EXPORTS.mozilla += [
]
SOURCES += [
'ActiveLayerTracker.cpp',
'DisplayItemClip.cpp',
'DisplayListClipState.cpp',
'FrameLayerBuilder.cpp',

View File

@ -47,6 +47,7 @@
#include "StickyScrollContainer.h"
#include "mozilla/LookAndFeel.h"
#include "mozilla/Preferences.h"
#include "ActiveLayerTracker.h"
#include <stdint.h>
#include <algorithm>
@ -3056,7 +3057,7 @@ nsDisplayOpacity::BuildLayer(nsDisplayListBuilder* aBuilder,
LayerManager* aManager,
const ContainerParameters& aContainerParameters) {
if (mFrame->StyleDisplay()->mOpacity == 0 && mFrame->GetContent() &&
!nsLayoutUtils::HasAnimationsForCompositor(mFrame->GetContent(), eCSSProperty_opacity)) {
!nsLayoutUtils::HasAnimations(mFrame->GetContent(), eCSSProperty_opacity)) {
return nullptr;
}
nsRefPtr<Layer> container = aManager->GetLayerBuilder()->
@ -3090,7 +3091,7 @@ nsDisplayItem::LayerState
nsDisplayOpacity::GetLayerState(nsDisplayListBuilder* aBuilder,
LayerManager* aManager,
const ContainerParameters& aParameters) {
if (mFrame->AreLayersMarkedActive(nsChangeHint_UpdateOpacityLayer) &&
if (ActiveLayerTracker::IsStyleAnimated(mFrame, eCSSProperty_opacity) &&
!IsItemTooSmallForActiveLayer(this))
return LAYER_ACTIVE;
if (mFrame->GetContent()) {
@ -4213,7 +4214,7 @@ nsDisplayTransform::GetResultingTransformMatrixInternal(const FrameTransformProp
bool
nsDisplayOpacity::CanUseAsyncAnimations(nsDisplayListBuilder* aBuilder)
{
if (Frame()->AreLayersMarkedActive(nsChangeHint_UpdateOpacityLayer)) {
if (ActiveLayerTracker::IsStyleAnimated(mFrame, eCSSProperty_opacity)) {
return true;
}
@ -4243,7 +4244,7 @@ nsDisplayTransform::ShouldPrerenderTransformedContent(nsDisplayListBuilder* aBui
// have a compositor-animated transform, can be prerendered. An element
// might have only just had its transform animated in which case
// nsChangeHint_UpdateTransformLayer will not be present yet.
if (!aFrame->AreLayersMarkedActive(nsChangeHint_UpdateTransformLayer) &&
if (!ActiveLayerTracker::IsStyleAnimated(aFrame, eCSSProperty_transform) &&
(!aFrame->GetContent() ||
!nsLayoutUtils::HasAnimationsForCompositor(aFrame->GetContent(),
eCSSProperty_transform))) {
@ -4393,7 +4394,7 @@ nsDisplayTransform::GetLayerState(nsDisplayListBuilder* aBuilder,
}
// Here we check if the *post-transform* bounds of this item are big enough
// to justify an active layer.
if (mFrame->AreLayersMarkedActive(nsChangeHint_UpdateTransformLayer) &&
if (ActiveLayerTracker::IsStyleAnimated(mFrame, eCSSProperty_transform) &&
!IsItemTooSmallForActiveLayer(this))
return LAYER_ACTIVE;
if (mFrame->GetContent()) {

View File

@ -251,9 +251,9 @@ TextAlignTrueEnabledPrefChangeCallback(const char* aPrefName, void* aClosure)
template <class AnimationsOrTransitions>
static AnimationsOrTransitions*
HasAnimationOrTransition(nsIContent* aContent,
nsIAtom* aAnimationProperty,
nsCSSProperty aProperty)
HasAnimationOrTransitionForCompositor(nsIContent* aContent,
nsIAtom* aAnimationProperty,
nsCSSProperty aProperty)
{
AnimationsOrTransitions* animations =
static_cast<AnimationsOrTransitions*>(aContent->GetProperty(aAnimationProperty));
@ -275,12 +275,40 @@ nsLayoutUtils::HasAnimationsForCompositor(nsIContent* aContent,
{
if (!aContent->MayHaveAnimations())
return false;
if (HasAnimationOrTransition<ElementAnimations>
(aContent, nsGkAtoms::animationsProperty, aProperty)) {
return true;
return HasAnimationOrTransitionForCompositor<ElementAnimations>
(aContent, nsGkAtoms::animationsProperty, aProperty) ||
HasAnimationOrTransitionForCompositor<ElementTransitions>
(aContent, nsGkAtoms::transitionsProperty, aProperty);
}
template <class AnimationsOrTransitions>
static AnimationsOrTransitions*
HasAnimationOrTransition(nsIContent* aContent,
nsIAtom* aAnimationProperty,
nsCSSProperty aProperty)
{
AnimationsOrTransitions* animations =
static_cast<AnimationsOrTransitions*>(aContent->GetProperty(aAnimationProperty));
if (animations) {
bool propertyMatches = animations->HasAnimationOfProperty(aProperty);
if (propertyMatches) {
return animations;
}
}
return HasAnimationOrTransition<ElementTransitions>
(aContent, nsGkAtoms::transitionsProperty, aProperty);
return nullptr;
}
bool
nsLayoutUtils::HasAnimations(nsIContent* aContent,
nsCSSProperty aProperty)
{
if (!aContent->MayHaveAnimations())
return false;
return HasAnimationOrTransition<ElementAnimations>
(aContent, nsGkAtoms::animationsProperty, aProperty) ||
HasAnimationOrTransition<ElementTransitions>
(aContent, nsGkAtoms::transitionsProperty, aProperty);
}
static gfxSize
@ -323,7 +351,7 @@ gfxSize
nsLayoutUtils::GetMaximumAnimatedScale(nsIContent* aContent)
{
gfxSize result;
ElementAnimations* animations = HasAnimationOrTransition<ElementAnimations>
ElementAnimations* animations = HasAnimationOrTransitionForCompositor<ElementAnimations>
(aContent, nsGkAtoms::animationsProperty, eCSSProperty_transform);
if (animations) {
for (uint32_t animIdx = animations->mAnimations.Length(); animIdx-- != 0; ) {
@ -346,7 +374,7 @@ nsLayoutUtils::GetMaximumAnimatedScale(nsIContent* aContent)
}
}
}
ElementTransitions* transitions = HasAnimationOrTransition<ElementTransitions>
ElementTransitions* transitions = HasAnimationOrTransitionForCompositor<ElementTransitions>
(aContent, nsGkAtoms::transitionsProperty, eCSSProperty_transform);
if (transitions) {
for (uint32_t i = 0, i_end = transitions->mPropertyTransitions.Length();

View File

@ -1632,6 +1632,12 @@ public:
static bool HasAnimationsForCompositor(nsIContent* aContent,
nsCSSProperty aProperty);
/**
* Returns true if the content node has animations or transitions for the
* property.
*/
static bool HasAnimations(nsIContent* aContent, nsCSSProperty aProperty);
/**
* Checks if off-main-thread animations are enabled.
*/

View File

@ -26,7 +26,7 @@
#endif
#include "mozilla/Util.h"
#include "mozilla/AutoRestore.h"
#include "nsRefreshDriver.h"
#include "nsITimer.h"
#include "nsLayoutUtils.h"
@ -685,7 +685,8 @@ nsRefreshDriver::nsRefreshDriver(nsPresContext* aPresContext)
mThrottled(false),
mTestControllingRefreshes(false),
mViewManagerFlushIsPending(false),
mRequestedHighPrecision(false)
mRequestedHighPrecision(false),
mInRefresh(false)
{
mMostRecentRefreshEpochTime = JS_Now();
mMostRecentRefresh = TimeStamp::Now();
@ -1061,6 +1062,9 @@ nsRefreshDriver::Tick(int64_t aNowEpoch, TimeStamp aNowTime)
profiler_tracing("Paint", "RD", TRACING_INTERVAL_START);
AutoRestore<bool> restoreInRefresh(mInRefresh);
mInRefresh = true;
/*
* The timer holds a reference to |this| while calling |Notify|.
* However, implementations of |WillRefresh| are permitted to destroy
@ -1220,6 +1224,8 @@ nsRefreshDriver::Tick(int64_t aNowEpoch, TimeStamp aNowTime)
mPostRefreshObservers[i]->DidRefresh();
}
profiler_tracing("Paint", "RD", TRACING_INTERVAL_END);
NS_ASSERTION(mInRefresh, "Still in refresh");
}
/* static */ PLDHashOperator

View File

@ -249,6 +249,8 @@ public:
*/
static int32_t DefaultInterval();
bool IsInRefresh() { return mInRefresh; }
private:
typedef nsTObserverArray<nsARefreshObserver*> ObserverArray;
typedef nsTHashtable<nsISupportsHashKey> RequestTable;
@ -302,6 +304,7 @@ private:
bool mTestControllingRefreshes;
bool mViewManagerFlushIsPending;
bool mRequestedHighPrecision;
bool mInRefresh;
int64_t mMostRecentRefreshEpochTime;
mozilla::TimeStamp mMostRecentRefresh;

View File

@ -61,6 +61,7 @@
#include "DOMStorageObserver.h"
#include "CacheObserver.h"
#include "DisplayItemClip.h"
#include "ActiveLayerTracker.h"
#include "AudioChannelService.h"
@ -311,7 +312,7 @@ nsLayoutStatics::Shutdown()
nsFrame::DisplayReflowShutdown();
#endif
nsCellMap::Shutdown();
nsFrame::ShutdownLayerActivityTimer();
ActiveLayerTracker::Shutdown();
// Release all of our atoms
nsColorNames::ReleaseTable();

View File

@ -62,7 +62,6 @@
#include "nsBoxLayoutState.h"
#include "nsBlockFrame.h"
#include "nsDisplayList.h"
#include "nsExpirationTracker.h"
#include "nsSVGIntegrationUtils.h"
#include "nsSVGEffects.h"
#include "nsChangeHint.h"
@ -1795,8 +1794,7 @@ nsIFrame::BuildDisplayListForStackingContext(nsDisplayListBuilder* aBuilder,
// need to have display items built for them.
if (disp->mOpacity == 0.0 && aBuilder->IsForPainting() &&
!aBuilder->WillComputePluginGeometry() &&
!nsLayoutUtils::HasAnimationsForCompositor(mContent,
eCSSProperty_opacity)) {
!nsLayoutUtils::HasAnimations(mContent, eCSSProperty_opacity)) {
return;
}
@ -4562,130 +4560,6 @@ nsIFrame::IsLeaf() const
return true;
}
class LayerActivity {
public:
LayerActivity(nsIFrame* aFrame)
: mFrame(aFrame)
, mChangeHint(nsChangeHint(0))
, mMutationCount(0)
{}
~LayerActivity();
nsExpirationState* GetExpirationState() { return &mState; }
uint32_t GetMutationCount() { return mMutationCount; }
nsIFrame* mFrame;
nsExpirationState mState;
// mChangeHint can be some combination of nsChangeHint_UpdateOpacityLayer and
// nsChangeHint_UpdateTransformLayer (or neither)
// The presence of those bits indicates whether opacity or transform
// changes have been detected.
nsChangeHint mChangeHint;
uint32_t mMutationCount;
};
class LayerActivityTracker MOZ_FINAL : public nsExpirationTracker<LayerActivity,4> {
public:
// 75-100ms is a good timeout period. We use 4 generations of 25ms each.
enum { GENERATION_MS = 100 };
LayerActivityTracker()
: nsExpirationTracker<LayerActivity,4>(GENERATION_MS) {}
~LayerActivityTracker() {
AgeAllGenerations();
}
virtual void NotifyExpired(LayerActivity* aObject);
};
static LayerActivityTracker* gLayerActivityTracker = nullptr;
LayerActivity::~LayerActivity()
{
if (mFrame) {
NS_ASSERTION(gLayerActivityTracker, "Should still have a tracker");
gLayerActivityTracker->RemoveObject(this);
}
}
static void DestroyLayerActivity(void* aPropertyValue)
{
delete static_cast<LayerActivity*>(aPropertyValue);
}
NS_DECLARE_FRAME_PROPERTY(LayerActivityProperty, DestroyLayerActivity)
void
LayerActivityTracker::NotifyExpired(LayerActivity* aObject)
{
RemoveObject(aObject);
nsIFrame* f = aObject->mFrame;
aObject->mFrame = nullptr;
// if there are hints other than transform/opacity, invalidate, since we don't know what else to do.
if (aObject->mChangeHint & ~(nsChangeHint_UpdateOpacityLayer|nsChangeHint_UpdateTransformLayer)) {
f->InvalidateFrameSubtree();
} else {
if (aObject->mChangeHint & nsChangeHint_UpdateOpacityLayer) {
f->InvalidateFrameSubtree(nsDisplayItem::TYPE_OPACITY);
}
if (aObject->mChangeHint & nsChangeHint_UpdateTransformLayer) {
f->InvalidateFrameSubtree(nsDisplayItem::TYPE_TRANSFORM);
}
}
f->Properties().Delete(LayerActivityProperty());
}
void
nsIFrame::MarkLayersActive(nsChangeHint aChangeHint)
{
FrameProperties properties = Properties();
LayerActivity* layerActivity =
static_cast<LayerActivity*>(properties.Get(LayerActivityProperty()));
if (layerActivity) {
gLayerActivityTracker->MarkUsed(layerActivity);
} else {
if (!gLayerActivityTracker) {
gLayerActivityTracker = new LayerActivityTracker();
}
layerActivity = new LayerActivity(this);
gLayerActivityTracker->AddObject(layerActivity);
properties.Set(LayerActivityProperty(), layerActivity);
}
layerActivity->mMutationCount++;
NS_UpdateHint(layerActivity->mChangeHint, aChangeHint);
}
bool
nsIFrame::AreLayersMarkedActive()
{
return Properties().Get(LayerActivityProperty()) != nullptr;
}
bool
nsIFrame::AreLayersMarkedActive(nsChangeHint aChangeHint)
{
LayerActivity* layerActivity =
static_cast<LayerActivity*>(Properties().Get(LayerActivityProperty()));
if (layerActivity && (layerActivity->mChangeHint & aChangeHint)) {
if (aChangeHint & nsChangeHint_UpdateOpacityLayer) {
return layerActivity->GetMutationCount() > 1;
}
return true;
}
if (aChangeHint & nsChangeHint_UpdateTransformLayer &&
Preserves3D()) {
return GetParent()->AreLayersMarkedActive(nsChangeHint_UpdateTransformLayer);
}
return false;
}
/* static */ void
nsFrame::ShutdownLayerActivityTimer()
{
delete gLayerActivityTracker;
gLayerActivityTracker = nullptr;
}
gfx3DMatrix
nsIFrame::GetTransformMatrix(const nsIFrame* aStopAtAncestor,
nsIFrame** aOutAncestor)

View File

@ -484,8 +484,6 @@ public:
static void DisplayReflowShutdown();
#endif
static void ShutdownLayerActivityTimer();
/**
* Adds display items for standard CSS background if necessary.
* Does not check IsVisibleForPainting.

View File

@ -1560,7 +1560,7 @@ nsGfxScrollFrameInner::nsGfxScrollFrameInner(nsContainerFrame* aOuter,
, mMayHaveDirtyFixedChildren(false)
, mUpdateScrollbarAttributes(false)
, mCollapsedResizer(false)
, mShouldBuildLayer(false)
, mShouldBuildScrollableLayer(false)
, mHasBeenScrolled(false)
{
mScrollingActive = IsAlwaysActive();
@ -2131,12 +2131,6 @@ nsGfxScrollFrameInner::AppendScrollPartsTo(nsDisplayListBuilder* aBuilder,
}
}
bool
nsGfxScrollFrameInner::ShouldBuildLayer() const
{
return mShouldBuildLayer;
}
class ScrollLayerWrapper : public nsDisplayWrapper
{
public:
@ -2343,8 +2337,9 @@ nsGfxScrollFrameInner::BuildDisplayList(nsDisplayListBuilder* aBuilder,
// When a displayport is being used, force building of a layer so that
// CompositorParent can always find the scrollable layer for the root content
// document.
bool shouldBuildLayer = false;
if (usingDisplayport) {
mShouldBuildLayer = true;
shouldBuildLayer = true;
} else {
nsRect scrollRange = GetScrollRange();
ScrollbarStyles styles = GetScrollbarStylesFromFrame();
@ -2359,18 +2354,20 @@ nsGfxScrollFrameInner::BuildDisplayList(nsDisplayListBuilder* aBuilder,
wantSubAPZC = true;
}
#endif
mShouldBuildLayer =
shouldBuildLayer =
wantSubAPZC &&
hasScrollableOverflow &&
(!mIsRoot || !mOuter->PresContext()->IsRootContentDocument());
}
if (ShouldBuildLayer()) {
mShouldBuildScrollableLayer = false;
if (shouldBuildLayer) {
// ScrollLayerWrapper must always be created because it initializes the
// scroll layer count. The display lists depend on this.
ScrollLayerWrapper wrapper(mOuter, mScrolledFrame);
if (usingDisplayport) {
mShouldBuildScrollableLayer = true;
DisplayListClipState::AutoSaveRestore clipState(aBuilder);
// For root scrollframes in documents where the CSS viewport has been

View File

@ -65,8 +65,6 @@ public:
void PostOverflowEvent();
void Destroy();
bool ShouldBuildLayer() const;
void BuildDisplayList(nsDisplayListBuilder* aBuilder,
const nsRect& aDirtyRect,
const nsDisplayListSet& aLists);
@ -268,7 +266,7 @@ public:
nscoord GetNondisappearingScrollbarWidth(nsBoxLayoutState* aState);
bool IsLTR() const;
bool IsScrollbarOnRight() const;
bool IsScrollingActive() const { return mScrollingActive || ShouldBuildLayer(); }
bool IsScrollingActive() const { return mScrollingActive || mShouldBuildScrollableLayer; }
void ResetScrollPositionForLayerPixelAlignment()
{
mScrollPosForLayerPixelAlignment = GetScrollPosition();
@ -386,9 +384,9 @@ public:
// If true, the resizer is collapsed and not displayed
bool mCollapsedResizer:1;
// If true, the layer should always be active because we always build a layer.
// Used for asynchronous scrolling.
bool mShouldBuildLayer:1;
// If true, the layer should always be active because we always build a
// scrollable layer. Used for asynchronous scrolling.
bool mShouldBuildScrollableLayer:1;
// True if this frame has been scrolled at least once
bool mHasBeenScrolled:1;

View File

@ -12,6 +12,7 @@
#include "nsDisplayList.h"
#include "nsLayoutUtils.h"
#include "Layers.h"
#include "ActiveLayerTracker.h"
#include <algorithm>
@ -68,10 +69,11 @@ public:
return LAYER_INACTIVE;
// If compositing is cheap, just do that
if (aManager->IsCompositingCheap())
if (aManager->IsCompositingCheap() ||
ActiveLayerTracker::IsContentActive(mFrame))
return mozilla::LAYER_ACTIVE;
return mFrame->AreLayersMarkedActive() ? LAYER_ACTIVE : LAYER_INACTIVE;
return LAYER_INACTIVE;
}
};
@ -96,9 +98,9 @@ nsHTMLCanvasFrame::Init(nsIContent* aContent,
nsContainerFrame::Init(aContent, aParent, aPrevInFlow);
// We can fill in the canvas before the canvas frame is created, in
// which case we never get around to marking the layer active. Therefore,
// which case we never get around to marking the content as active. Therefore,
// we mark it active here when we create the frame.
MarkLayersActive(nsChangeHint(0));
ActiveLayerTracker::NotifyContentChange(this);
}
nsHTMLCanvasFrame::~nsHTMLCanvasFrame()

View File

@ -2176,30 +2176,6 @@ public:
bool IsFlexItem() const
{ return mParent && mParent->GetType() == nsGkAtoms::flexContainerFrame; }
/**
* Mark this frame as using active layers. This marking will time out
* after a short period. This call does no immediate invalidation,
* but when the mark times out, we'll invalidate the frame's overflow
* area.
* @param aChangeHint nsChangeHint_UpdateTransformLayer or
* nsChangeHint_UpdateOpacityLayer or 0, depending on whether the change
* triggering the activity is a changing transform, changing opacity, or
* something else.
*/
void MarkLayersActive(nsChangeHint aHint);
/**
* Return true if this frame is marked as needing active layers.
*/
bool AreLayersMarkedActive();
/**
* Return true if this frame is marked as needing active layers.
* @param aChangeHint nsChangeHint_UpdateTransformLayer or
* nsChangeHint_UpdateOpacityLayer. We return true only if
* a change in the transform or opacity has been recorded while layers have
* been marked active for this frame.
*/
bool AreLayersMarkedActive(nsChangeHint aChangeHint);
/**
* Marks all display items created by this frame as needing a repaint,
* and calls SchedulePaint() if requested and one is not already pending.

View File

@ -1625,7 +1625,7 @@ HTTP(..) == 615121-1.html 615121-1-ref.html
HTTP(..) != 615121-2.html 615121-2-notref.html
fails-if(Android) == 617242-1.html 617242-1-ref.html
!= 618071.html 618071-notref.html
fails-if(Android) == 619117-1.html 619117-1-ref.html
== 619117-1.html 619117-1-ref.html
HTTP(..) == 619511-1.html 619511-1-ref.html
skip-if(Android) HTTP(..) == 621253-1-externalFilter.html 621253-1-ref.html
skip-if(Android) == 621253-1-internalFilter.html 621253-1-ref.html

View File

@ -0,0 +1,31 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Testcase for bug 932506</title>
<style>
input { outline:1px solid black; }
</style>
</head>
<body>
<div style="overflow:hidden; width:160px;">
<div style="float:left; width:799px; border:1px solid blue;">
<input type="checkbox" checked style="width:400px; visibility:hidden;">
<input type="checkbox" checked style="width:400px; height:100px; visibility:hidden;">
</div>
</div>
<input type="checkbox" checked style="width:400px;"><br>
<input type="checkbox" checked style="height:100px;"><br>
<input type="checkbox" checked style=""><br>
<input type="checkbox" checked style="width:400px;"><br>
<input type="checkbox" checked style="height:100px;"><br>
<input type="checkbox" checked style=""><br>
</body>
</html>

View File

@ -0,0 +1,30 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Testcase for bug 932506</title>
<style>
input { outline:1px solid black; }
</style>
</head>
<body>
<div style="overflow:hidden; width:160px;">
<div style="float:left; width:799px; border:1px solid blue;">
<input type="checkbox" checked style="width:400px; outline:none;">
<input type="checkbox" checked style="width:400px; height:100px; outline:none;">
</div>
</div>
<input type="checkbox" checked style="width:400px; height:1px;"><br>
<input type="checkbox" checked style="width:1px; height:100px;"><br>
<input type="checkbox" checked style="width:1px; height:1px;"><br>
<input type="checkbox" checked style="width:400px; height:0;"><br>
<input type="checkbox" checked style="width:0; height:100px;"><br>
<input type="checkbox" checked style="width:0; height:0;"><br>
</body>
</html>

View File

@ -11,3 +11,4 @@ skip-if(B2G) fails-if(Android) == radio-stretched.html radio-stretched-ref.html
!= indeterminate-native-checked.html indeterminate-native-checked-notref.html
!= indeterminate-native-unchecked.html indeterminate-native-unchecked-notref.html
== indeterminate-selector.html indeterminate-selector-ref.html
skip-if(!gtk2Widget) == gtk-theme-width-height.html gtk-theme-width-height-ref.html

View File

@ -0,0 +1,31 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Testcase for bug 932506</title>
<style>
input { outline:1px solid black; }
</style>
</head>
<body>
<div style="overflow:hidden; width:160px;">
<div style="float:left; width:799px; border:1px solid blue;">
<input type="radio" checked style="width:400px; visibility:hidden;">
<input type="radio" checked style="width:400px; height:100px; visibility:hidden;">
</div>
</div>
<input type="radio" checked style="width:400px;"><br>
<input type="radio" checked style="height:100px;"><br>
<input type="radio" checked style=""><br>
<input type="radio" checked style="width:400px;"><br>
<input type="radio" checked style="height:100px;"><br>
<input type="radio" checked style=""><br>
</body>
</html>

View File

@ -0,0 +1,30 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Testcase for bug 932506</title>
<style>
input { outline:1px solid black; }
</style>
</head>
<body>
<div style="overflow:hidden; width:160px;">
<div style="float:left; width:799px; border:1px solid blue;">
<input type="radio" checked style="width:400px; outline:none;">
<input type="radio" checked style="width:400px; height:100px; outline:none;">
</div>
</div>
<input type="radio" checked style="width:400px; height:1px;"><br>
<input type="radio" checked style="width:1px; height:100px;"><br>
<input type="radio" checked style="width:1px; height:1px;"><br>
<input type="radio" checked style="width:400px; height:0;"><br>
<input type="radio" checked style="width:0; height:100px;"><br>
<input type="radio" checked style="width:0; height:0;"><br>
</body>
</html>

View File

@ -5,3 +5,4 @@
!= checked-notref.html about:blank
!= checked-native.html about:blank
!= checked-native-notref.html about:blank
skip-if(!gtk2Widget) == gtk-theme-width-height.html gtk-theme-width-height-ref.html

View File

@ -100,7 +100,7 @@ random == rotate-1f.html rotate-1-ref.html
# ensure matrix 3d does not break us - should do nothing
== matrix3d-1.html matrix3d-1-ref.html
# Test that complex transform can be reversed
skip-if(B2G) fails-if(Android) fuzzy-if(cocoaWidget,1,2) == stresstest-1.html stresstest-1-ref.html # bug 773482
skip-if(B2G) == stresstest-1.html stresstest-1-ref.html # bug 773482
# Test scale transforms
== scalex-1.html scalex-1-ref.html
== scaley-1.html scaley-1-ref.html

View File

@ -16,6 +16,7 @@
#include "nsLayoutUtils.h"
#include "nsIFrame.h"
#include "nsIDocument.h"
#include "ActiveLayerTracker.h"
#include <math.h>
using namespace mozilla;
@ -416,10 +417,10 @@ ElementAnimations::CanPerformOnCompositorThread(CanAnimateFlags aFlags) const
// This animation can be done on the compositor. Mark the frame as active, in
// case we are able to throttle this animation.
if (hasOpacity) {
frame->MarkLayersActive(nsChangeHint_UpdateOpacityLayer);
ActiveLayerTracker::NotifyAnimated(frame, eCSSProperty_opacity);
}
if (hasTransform) {
frame->MarkLayersActive(nsChangeHint_UpdateTransformLayer);
ActiveLayerTracker::NotifyAnimated(frame, eCSSProperty_transform);
}
return true;
}

View File

@ -15,9 +15,10 @@
#include "nsIURI.h"
#include "nsNodeUtils.h"
#include "nsWrapperCacheInlines.h"
#include "nsIFrame.h"
#include "ActiveLayerTracker.h"
namespace css = mozilla::css;
namespace dom = mozilla::dom;
using namespace mozilla;
nsDOMCSSAttributeDeclaration::nsDOMCSSAttributeDeclaration(dom::Element* aElement,
bool aIsSMILOverride)
@ -169,3 +170,19 @@ nsDOMCSSAttributeDeclaration::GetParentObject()
{
return mElement;
}
NS_IMETHODIMP
nsDOMCSSAttributeDeclaration::SetPropertyValue(const nsCSSProperty aPropID,
const nsAString& aValue)
{
// Scripted modifications to style.opacity or style.transform
// could immediately force us into the animated state if heuristics suggest
// this is scripted animation.
if (aPropID == eCSSProperty_opacity || aPropID == eCSSProperty_transform) {
nsIFrame* frame = mElement->GetPrimaryFrame();
if (frame) {
ActiveLayerTracker::NotifyInlineStyleRuleModified(frame, aPropID);
}
}
return nsDOMCSSDeclaration::SetPropertyValue(aPropID, aValue);
}

View File

@ -38,6 +38,9 @@ public:
virtual nsINode* GetParentObject() MOZ_OVERRIDE;
NS_IMETHOD SetPropertyValue(const nsCSSProperty aPropID,
const nsAString& aValue);
protected:
virtual nsresult SetCSSDeclaration(mozilla::css::Declaration* aDecl) MOZ_OVERRIDE;
virtual nsIDocument* DocToUpdate() MOZ_OVERRIDE;

View File

@ -28,6 +28,7 @@
#include "nsStyleChangeList.h"
#include "nsStyleSet.h"
#include "RestyleManager.h"
#include "ActiveLayerTracker.h"
using mozilla::TimeStamp;
using mozilla::TimeDuration;
@ -197,10 +198,10 @@ ElementTransitions::CanPerformOnCompositorThread(CanAnimateFlags aFlags) const
// This transition can be done on the compositor. Mark the frame as active, in
// case we are able to throttle this transition.
if (hasOpacity) {
frame->MarkLayersActive(nsChangeHint_UpdateOpacityLayer);
ActiveLayerTracker::NotifyAnimated(frame, eCSSProperty_opacity);
}
if (hasTransform) {
frame->MarkLayersActive(nsChangeHint_UpdateTransformLayer);
ActiveLayerTracker::NotifyAnimated(frame, eCSSProperty_transform);
}
return true;
}

View File

@ -5058,9 +5058,9 @@ nsSVGTextFrame2::ShouldRenderAsPath(nsRenderingContext* aContext,
// Text has a stroke.
if (!(style->mStroke.mType == eStyleSVGPaintType_None ||
style->mStrokeOpacity == 0 ||
nsSVGUtils::CoordToFloat(PresContext(),
static_cast<nsSVGElement*>(mContent),
style->mStrokeWidth) == 0)) {
SVGContentUtils::CoordToFloat(PresContext(),
static_cast<nsSVGElement*>(mContent),
style->mStrokeWidth) == 0)) {
return true;
}

View File

@ -391,28 +391,6 @@ nsSVGUtils::ComputeAlphaMask(uint8_t *aData,
}
}
float
nsSVGUtils::CoordToFloat(nsPresContext *aPresContext,
nsSVGElement *aContent,
const nsStyleCoord &aCoord)
{
switch (aCoord.GetUnit()) {
case eStyleUnit_Factor:
// user units
return aCoord.GetFactorValue();
case eStyleUnit_Coord:
return nsPresContext::AppUnitsToFloatCSSPixels(aCoord.GetCoordValue());
case eStyleUnit_Percent: {
SVGSVGElement* ctx = aContent->GetCtx();
return ctx ? aCoord.GetPercentValue() * ctx->GetLength(SVGContentUtils::XY) : 0.0f;
}
default:
return 0.0f;
}
}
nsSVGDisplayContainerFrame*
nsSVGUtils::GetNearestSVGViewport(nsIFrame *aFrame)
{
@ -1621,8 +1599,8 @@ nsSVGUtils::GetStrokeWidth(nsIFrame* aFrame, gfxTextContextPaint *aContextPaint)
nsSVGElement *ctx = static_cast<nsSVGElement*>(content);
return CoordToFloat(aFrame->PresContext(), ctx,
style->mStrokeWidth);
return SVGContentUtils::CoordToFloat(aFrame->PresContext(), ctx,
style->mStrokeWidth);
}
void
@ -1713,9 +1691,9 @@ GetStrokeDashData(nsIFrame* aFrame,
const nsStyleCoord *dasharray = style->mStrokeDasharray;
for (uint32_t i = 0; i < count; i++) {
aDashes[i] = nsSVGUtils::CoordToFloat(presContext,
ctx,
dasharray[i]) * pathScale;
aDashes[i] = SVGContentUtils::CoordToFloat(presContext,
ctx,
dasharray[i]) * pathScale;
if (aDashes[i] < 0.0) {
return false;
}
@ -1726,9 +1704,9 @@ GetStrokeDashData(nsIFrame* aFrame,
if (aContextPaint && style->mStrokeDashoffsetFromObject) {
*aDashOffset = aContextPaint->GetStrokeDashOffset();
} else {
*aDashOffset = nsSVGUtils::CoordToFloat(presContext,
ctx,
style->mStrokeDashoffset);
*aDashOffset = SVGContentUtils::CoordToFloat(presContext,
ctx,
style->mStrokeDashoffset);
}
return (totalLength > 0.0);

View File

@ -292,15 +292,6 @@ public:
const nsIntRect &aRect,
float aOpacity);
/*
* Converts a nsStyleCoord into a userspace value. Handles units
* Factor (straight userspace), Coord (dimensioned), and Percent (of
* the current SVG viewport)
*/
static float CoordToFloat(nsPresContext *aPresContext,
nsSVGElement *aContent,
const nsStyleCoord &aCoord);
/**
* Gets the nearest nsSVGInnerSVGFrame or nsSVGOuterSVGFrame frame. aFrame
* must be an SVG frame. If aFrame is of type nsGkAtoms::svgOuterSVGFrame,

View File

@ -12,6 +12,7 @@ EXPORTS.mtransport += [
'../nricectx.h',
'../nricemediastream.h',
'../nriceresolverfake.h',
'../rlogringbuffer.h',
'../runnable_utils.h',
'../runnable_utils_generated.h',
'../sigslot.h',

View File

@ -83,6 +83,7 @@ extern "C" {
#include "nricemediastream.h"
#include "nr_socket_prsock.h"
#include "nrinterfaceprioritizer.h"
#include "rlogringbuffer.h"
namespace mozilla {
@ -334,11 +335,13 @@ void NrIceCtx::trickle_cb(void *arg, nr_ice_ctx *ice_ctx,
RefPtr<NrIceCtx> NrIceCtx::Create(const std::string& name,
bool offerer,
bool set_interface_priorities) {
RefPtr<NrIceCtx> ctx = new NrIceCtx(name, offerer);
// Initialize the crypto callbacks
// Initialize the crypto callbacks and logging stuff
if (!initialized) {
NR_reg_init(NR_REG_MODE_LOCAL);
RLogRingBuffer::CreateInstance();
nr_crypto_vtbl = &nr_ice_crypto_nss_vtbl;
initialized = true;

View File

@ -291,6 +291,7 @@ nsresult NrIceMediaStream::GetCandidatePairs(std::vector<NrIceCandidatePair>*
pair.nominated = p1->peer_nominated || p1->nominated;
pair.selected = p1->local->component &&
p1->local->component->active == p1;
pair.codeword = p1->codeword;
if (!ToNrIceCandidate(*(p1->local), &pair.local) ||
!ToNrIceCandidate(*(p1->remote), &pair.remote)) {

View File

@ -104,6 +104,7 @@ struct NrIceCandidatePair {
NrIceCandidate local;
NrIceCandidate remote;
// TODO(bcampen@mozilla.com): Is it important to put the foundation in here?
std::string codeword;
};
// Abstract base class for opaque values.

View File

@ -13,6 +13,7 @@ mtransport_lcppsrcs = [
'nriceresolver.cpp',
'nriceresolverfake.cpp',
'nrinterfaceprioritizer.cpp',
'rlogringbuffer.cpp',
'simpletokenbucket.cpp',
'transportflow.cpp',
'transportlayer.cpp',

View File

@ -0,0 +1,124 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=2 et sw=2 tw=80: */
/* 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/. */
/* Original author: bcampen@mozilla.com */
#include <cstdarg>
#include "rlogringbuffer.h"
#include <deque>
#include <string>
#include "mozilla/Assertions.h"
#include "mozilla/Move.h" // Pinch hitting for <utility> and std::move
#include "mozilla/NullPtr.h"
#include <vector>
extern "C" {
#include <csi_platform.h>
#include "r_log.h"
}
/* Matches r_dest_vlog type defined in r_log.h */
static int ringbuffer_vlog(int facility,
int level,
const char *format,
va_list ap) {
MOZ_ASSERT(mozilla::RLogRingBuffer::GetInstance());
// I could be evil and printf right into a std::string, but unless this
// shows up in profiling, it is not worth doing.
char temp[4096];
vsnprintf(temp, sizeof(temp), format, ap);
mozilla::RLogRingBuffer::GetInstance()->Log(std::string(temp));
return 0;
}
namespace mozilla {
RLogRingBuffer* RLogRingBuffer::instance;
RLogRingBuffer::RLogRingBuffer()
: log_limit_(4096) {
}
RLogRingBuffer::~RLogRingBuffer() {
}
void RLogRingBuffer::SetLogLimit(uint32_t new_limit) {
log_limit_ = new_limit;
RemoveOld();
}
void RLogRingBuffer::Log(std::string&& log) {
log_messages_.push_front(Move(log));
RemoveOld();
}
inline void RLogRingBuffer::RemoveOld() {
if (log_messages_.size() > log_limit_) {
log_messages_.resize(log_limit_);
}
}
RLogRingBuffer* RLogRingBuffer::CreateInstance() {
if (!instance) {
instance = new RLogRingBuffer;
r_log_set_extra_destination(LOG_INFO, &ringbuffer_vlog);
}
return instance;
}
RLogRingBuffer* RLogRingBuffer::GetInstance() {
return instance;
}
void RLogRingBuffer::DestroyInstance() {
// First param is ignored when passing null
r_log_set_extra_destination(LOG_INFO, nullptr);
delete instance;
instance = nullptr;
}
void RLogRingBuffer::Filter(const std::string& substring,
uint32_t limit,
std::deque<std::string>* matching_logs) {
std::vector<std::string> substrings;
substrings.push_back(substring);
FilterAny(substrings, limit, matching_logs);
}
inline bool AnySubstringMatches(const std::vector<std::string>& substrings,
const std::string& string) {
for (auto sub = substrings.begin(); sub != substrings.end(); ++sub) {
if (string.find(*sub) != std::string::npos) {
return true;
}
}
return false;
}
void RLogRingBuffer::FilterAny(const std::vector<std::string>& substrings,
uint32_t limit,
std::deque<std::string>* matching_logs) {
if (limit == 0) {
// At a max, all of the log messages.
limit = log_limit_;
}
for (auto log = log_messages_.begin();
log != log_messages_.end() && matching_logs->size() < limit;
++log) {
if (AnySubstringMatches(substrings, *log)) {
matching_logs->push_front(*log);
}
}
}
} // namespace mozilla

View File

@ -0,0 +1,121 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=2 et sw=2 tw=80: */
/* 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/. */
// Some of this code is cut-and-pasted from nICEr. Copyright is:
/*
Copyright (c) 2007, Adobe Systems, Incorporated
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
* Neither the name of Adobe Systems, Network Resonance nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/* 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/. */
/* Original author: bcampen@mozilla.com */
/*
This file defines an r_dest_vlog that can be used to accumulate log messages
for later inspection/filtering. The intent is to use this for interactive
debug purposes on an about:webrtc page or similar.
*/
#ifndef rlogringbuffer_h__
#define rlogringbuffer_h__
#include <stdint.h>
#include <deque>
#include <string>
#include <vector>
#include "m_cpp_utils.h"
namespace mozilla {
class RLogRingBuffer {
public:
/*
NB: These are not threadsafe, nor are they safe to call during static
init/deinit.
*/
static RLogRingBuffer* CreateInstance();
static RLogRingBuffer* GetInstance();
static void DestroyInstance();
/*
Retrieves log statements that match a given substring, subject to a
limit. |matching_logs| will be filled in chronological order (front()
is oldest, back() is newest). |limit| == 0 will be interpreted as no
limit.
*/
void Filter(const std::string& substring,
uint32_t limit,
std::deque<std::string>* matching_logs);
void FilterAny(const std::vector<std::string>& substrings,
uint32_t limit,
std::deque<std::string>* matching_logs);
inline void GetAny(uint32_t limit,
std::deque<std::string>* matching_logs) {
Filter("", limit, matching_logs);
}
void SetLogLimit(uint32_t new_limit);
void Log(std::string&& log);
private:
RLogRingBuffer();
~RLogRingBuffer();
void RemoveOld();
static RLogRingBuffer* instance;
/*
* Might be worthwhile making this a circular buffer, but I think it is
* preferable to take up as little space as possible if no logging is
* happening/the ringbuffer is not being used.
*/
std::deque<std::string> log_messages_;
/* Max size of log buffer (should we use time-depth instead/also?) */
uint32_t log_limit_;
DISALLOW_COPY_ASSIGN(RLogRingBuffer);
}; // class RLogRingBuffer
} // namespace mozilla
#endif // rlogringbuffer_h__

View File

@ -7,6 +7,7 @@
// Original author: ekr@rtfm.com
#include <algorithm>
#include <deque>
#include <iostream>
#include <limits>
#include <map>
@ -30,6 +31,7 @@
#include "nriceresolver.h"
#include "nrinterfaceprioritizer.h"
#include "mtransport_test_utils.h"
#include "rlogringbuffer.h"
#include "runnable_utils.h"
#include "stunserver.h"
// TODO(bcampen@mozilla.com): Big fat hack since the build system doesn't give
@ -105,6 +107,9 @@ class IceCandidatePairCompare {
const NrIceCandidatePair& rhs) const {
if (lhs.priority == rhs.priority) {
if (lhs.local == rhs.local) {
if (lhs.remote == rhs.remote) {
return lhs.codeword < rhs.codeword;
}
return lhs.remote < rhs.remote;
}
return lhs.local < rhs.local;
@ -479,7 +484,8 @@ class IceTestPeer : public sigslot::has_slots<> {
std::cerr << "state = " << pair.state
<< " priority = " << pair.priority
<< " nominated = " << pair.nominated
<< " selected = " << pair.selected << std::endl;
<< " selected = " << pair.selected
<< " codeword = " << pair.codeword << std::endl;
}
void DumpCandidatePairs(NrIceMediaStream *stream) {
@ -1222,6 +1228,49 @@ TEST_F(IceConnectTest, TestPollCandPairsDuringConnect) {
ASSERT_TRUE(ContainsSucceededPair(pairs2));
}
TEST_F(IceConnectTest, TestRLogRingBuffer) {
RLogRingBuffer::CreateInstance();
AddStream("first", 1);
ASSERT_TRUE(Gather(true));
p1_->Connect(p2_, TRICKLE_NONE, false);
p2_->Connect(p1_, TRICKLE_NONE, false);
std::vector<NrIceCandidatePair> pairs1;
std::vector<NrIceCandidatePair> pairs2;
p1_->StartChecks();
p1_->UpdateAndValidateCandidatePairs(0, &pairs1);
p2_->UpdateAndValidateCandidatePairs(0, &pairs2);
p2_->StartChecks();
p1_->UpdateAndValidateCandidatePairs(0, &pairs1);
p2_->UpdateAndValidateCandidatePairs(0, &pairs2);
WaitForComplete();
p1_->UpdateAndValidateCandidatePairs(0, &pairs1);
p2_->UpdateAndValidateCandidatePairs(0, &pairs2);
ASSERT_TRUE(ContainsSucceededPair(pairs1));
ASSERT_TRUE(ContainsSucceededPair(pairs2));
for (auto p = pairs1.begin(); p != pairs1.end(); ++p) {
std::deque<std::string> logs;
std::string substring("CAND-PAIR(");
substring += p->codeword;
RLogRingBuffer::GetInstance()->Filter(substring, 0, &logs);
ASSERT_NE(0U, logs.size());
}
for (auto p = pairs2.begin(); p != pairs2.end(); ++p) {
std::deque<std::string> logs;
std::string substring("CAND-PAIR(");
substring += p->codeword;
RLogRingBuffer::GetInstance()->Filter(substring, 0, &logs);
ASSERT_NE(0U, logs.size());
}
RLogRingBuffer::DestroyInstance();
}
TEST_F(PrioritizerTest, TestPrioritizer) {
SetPriorizer(::mozilla::CreateInterfacePrioritizer());

View File

@ -10,6 +10,7 @@ if CONFIG['OS_TARGET'] != 'WINNT' and CONFIG['MOZ_WIDGET_TOOLKIT'] != 'gonk':
CPP_UNIT_TESTS += [
'ice_unittest.cpp',
'nrappkit_unittest.cpp',
'rlogringbuffer_unittest.cpp',
'runnable_utils_unittest.cpp',
'simpletokenbucket_unittest.cpp',
'sockettransportservice_unittest.cpp',

View File

@ -0,0 +1,269 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=2 et sw=2 tw=80: */
/* 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/. */
/* Original author: bcampen@mozilla.com */
#include "rlogringbuffer.h"
extern "C" {
#include "registry.h"
#include "r_log.h"
}
#define GTEST_HAS_RTTI 0
#include "gtest/gtest.h"
#include "gtest_utils.h"
#include <deque>
#include <string>
#include <vector>
using mozilla::RLogRingBuffer;
int NR_LOG_TEST = 0;
class RLogRingBufferTest : public ::testing::Test {
public:
RLogRingBufferTest() {
Init();
}
~RLogRingBufferTest() {
Free();
}
void Init() {
RLogRingBuffer::CreateInstance();
}
void Free() {
RLogRingBuffer::DestroyInstance();
}
void ReInit() {
Free();
Init();
}
};
TEST_F(RLogRingBufferTest, TestGetFree) {
RLogRingBuffer* instance = RLogRingBuffer::GetInstance();
ASSERT_NE(nullptr, instance);
}
TEST_F(RLogRingBufferTest, TestFilterEmpty) {
std::deque<std::string> logs;
RLogRingBuffer::GetInstance()->GetAny(0, &logs);
ASSERT_EQ(0U, logs.size());
}
TEST_F(RLogRingBufferTest, TestBasicFilter) {
r_log(NR_LOG_TEST, LOG_INFO, "Test");
std::deque<std::string> logs;
RLogRingBuffer::GetInstance()->Filter("Test", 0, &logs);
ASSERT_EQ(1U, logs.size());
}
TEST_F(RLogRingBufferTest, TestBasicFilterContent) {
r_log(NR_LOG_TEST, LOG_INFO, "Test");
std::deque<std::string> logs;
RLogRingBuffer::GetInstance()->Filter("Test", 0, &logs);
ASSERT_EQ("Test", logs.back());
}
TEST_F(RLogRingBufferTest, TestFilterAnyFrontMatch) {
r_log(NR_LOG_TEST, LOG_INFO, "Test");
std::vector<std::string> substrings;
substrings.push_back("foo");
substrings.push_back("Test");
std::deque<std::string> logs;
RLogRingBuffer::GetInstance()->FilterAny(substrings, 0, &logs);
ASSERT_EQ("Test", logs.back());
}
TEST_F(RLogRingBufferTest, TestFilterAnyBackMatch) {
r_log(NR_LOG_TEST, LOG_INFO, "Test");
std::vector<std::string> substrings;
substrings.push_back("Test");
substrings.push_back("foo");
std::deque<std::string> logs;
RLogRingBuffer::GetInstance()->FilterAny(substrings, 0, &logs);
ASSERT_EQ("Test", logs.back());
}
TEST_F(RLogRingBufferTest, TestFilterAnyBothMatch) {
r_log(NR_LOG_TEST, LOG_INFO, "Test");
std::vector<std::string> substrings;
substrings.push_back("Tes");
substrings.push_back("est");
std::deque<std::string> logs;
RLogRingBuffer::GetInstance()->FilterAny(substrings, 0, &logs);
ASSERT_EQ("Test", logs.back());
}
TEST_F(RLogRingBufferTest, TestFilterAnyNeitherMatch) {
r_log(NR_LOG_TEST, LOG_INFO, "Test");
std::vector<std::string> substrings;
substrings.push_back("tes");
substrings.push_back("esT");
std::deque<std::string> logs;
RLogRingBuffer::GetInstance()->FilterAny(substrings, 0, &logs);
ASSERT_EQ(0U, logs.size());
}
TEST_F(RLogRingBufferTest, TestAllMatch) {
r_log(NR_LOG_TEST, LOG_INFO, "Test1");
r_log(NR_LOG_TEST, LOG_INFO, "Test2");
std::deque<std::string> logs;
RLogRingBuffer::GetInstance()->GetAny(0, &logs);
ASSERT_EQ(2U, logs.size());
}
TEST_F(RLogRingBufferTest, TestOrder) {
r_log(NR_LOG_TEST, LOG_INFO, "Test1");
r_log(NR_LOG_TEST, LOG_INFO, "Test2");
std::deque<std::string> logs;
RLogRingBuffer::GetInstance()->GetAny(0, &logs);
ASSERT_EQ("Test2", logs.back());
ASSERT_EQ("Test1", logs.front());
}
TEST_F(RLogRingBufferTest, TestNoMatch) {
r_log(NR_LOG_TEST, LOG_INFO, "Test1");
r_log(NR_LOG_TEST, LOG_INFO, "Test2");
std::deque<std::string> logs;
RLogRingBuffer::GetInstance()->Filter("foo", 0, &logs);
ASSERT_EQ(0U, logs.size());
}
TEST_F(RLogRingBufferTest, TestSubstringFilter) {
r_log(NR_LOG_TEST, LOG_INFO, "Test1");
r_log(NR_LOG_TEST, LOG_INFO, "Test2");
std::deque<std::string> logs;
RLogRingBuffer::GetInstance()->Filter("t1", 0, &logs);
ASSERT_EQ(1U, logs.size());
ASSERT_EQ("Test1", logs.back());
}
TEST_F(RLogRingBufferTest, TestFilterLimit) {
r_log(NR_LOG_TEST, LOG_INFO, "Test1");
r_log(NR_LOG_TEST, LOG_INFO, "Test2");
r_log(NR_LOG_TEST, LOG_INFO, "Test3");
r_log(NR_LOG_TEST, LOG_INFO, "Test4");
r_log(NR_LOG_TEST, LOG_INFO, "Test5");
r_log(NR_LOG_TEST, LOG_INFO, "Test6");
std::deque<std::string> logs;
RLogRingBuffer::GetInstance()->Filter("Test", 2, &logs);
ASSERT_EQ(2U, logs.size());
ASSERT_EQ("Test6", logs.back());
ASSERT_EQ("Test5", logs.front());
}
TEST_F(RLogRingBufferTest, TestFilterAnyLimit) {
r_log(NR_LOG_TEST, LOG_INFO, "TestOne");
r_log(NR_LOG_TEST, LOG_INFO, "TestTwo");
r_log(NR_LOG_TEST, LOG_INFO, "TestThree");
r_log(NR_LOG_TEST, LOG_INFO, "TestFour");
r_log(NR_LOG_TEST, LOG_INFO, "TestFive");
r_log(NR_LOG_TEST, LOG_INFO, "TestSix");
std::vector<std::string> substrings;
// Matches Two, Three, Four, and Six
substrings.push_back("tT");
substrings.push_back("o");
substrings.push_back("r");
substrings.push_back("S");
std::deque<std::string> logs;
RLogRingBuffer::GetInstance()->FilterAny(substrings, 2, &logs);
ASSERT_EQ(2U, logs.size());
ASSERT_EQ("TestSix", logs.back());
ASSERT_EQ("TestFour", logs.front());
}
TEST_F(RLogRingBufferTest, TestLimit) {
RLogRingBuffer::GetInstance()->SetLogLimit(3);
r_log(NR_LOG_TEST, LOG_INFO, "Test1");
r_log(NR_LOG_TEST, LOG_INFO, "Test2");
r_log(NR_LOG_TEST, LOG_INFO, "Test3");
r_log(NR_LOG_TEST, LOG_INFO, "Test4");
r_log(NR_LOG_TEST, LOG_INFO, "Test5");
r_log(NR_LOG_TEST, LOG_INFO, "Test6");
std::deque<std::string> logs;
RLogRingBuffer::GetInstance()->GetAny(0, &logs);
ASSERT_EQ(3U, logs.size());
ASSERT_EQ("Test6", logs.back());
ASSERT_EQ("Test4", logs.front());
}
TEST_F(RLogRingBufferTest, TestLimitBulkDiscard) {
r_log(NR_LOG_TEST, LOG_INFO, "Test1");
r_log(NR_LOG_TEST, LOG_INFO, "Test2");
r_log(NR_LOG_TEST, LOG_INFO, "Test3");
r_log(NR_LOG_TEST, LOG_INFO, "Test4");
r_log(NR_LOG_TEST, LOG_INFO, "Test5");
r_log(NR_LOG_TEST, LOG_INFO, "Test6");
RLogRingBuffer::GetInstance()->SetLogLimit(3);
std::deque<std::string> logs;
RLogRingBuffer::GetInstance()->GetAny(0, &logs);
ASSERT_EQ(3U, logs.size());
ASSERT_EQ("Test6", logs.back());
ASSERT_EQ("Test4", logs.front());
}
TEST_F(RLogRingBufferTest, TestIncreaseLimit) {
RLogRingBuffer::GetInstance()->SetLogLimit(3);
r_log(NR_LOG_TEST, LOG_INFO, "Test1");
r_log(NR_LOG_TEST, LOG_INFO, "Test2");
r_log(NR_LOG_TEST, LOG_INFO, "Test3");
r_log(NR_LOG_TEST, LOG_INFO, "Test4");
r_log(NR_LOG_TEST, LOG_INFO, "Test5");
r_log(NR_LOG_TEST, LOG_INFO, "Test6");
RLogRingBuffer::GetInstance()->SetLogLimit(300);
std::deque<std::string> logs;
RLogRingBuffer::GetInstance()->GetAny(0, &logs);
ASSERT_EQ(3U, logs.size());
ASSERT_EQ("Test6", logs.back());
ASSERT_EQ("Test4", logs.front());
}
TEST_F(RLogRingBufferTest, TestClear) {
r_log(NR_LOG_TEST, LOG_INFO, "Test1");
r_log(NR_LOG_TEST, LOG_INFO, "Test2");
r_log(NR_LOG_TEST, LOG_INFO, "Test3");
r_log(NR_LOG_TEST, LOG_INFO, "Test4");
r_log(NR_LOG_TEST, LOG_INFO, "Test5");
r_log(NR_LOG_TEST, LOG_INFO, "Test6");
RLogRingBuffer::GetInstance()->SetLogLimit(0);
RLogRingBuffer::GetInstance()->SetLogLimit(4096);
std::deque<std::string> logs;
RLogRingBuffer::GetInstance()->GetAny(0, &logs);
ASSERT_EQ(0U, logs.size());
}
TEST_F(RLogRingBufferTest, TestReInit) {
r_log(NR_LOG_TEST, LOG_INFO, "Test1");
r_log(NR_LOG_TEST, LOG_INFO, "Test2");
r_log(NR_LOG_TEST, LOG_INFO, "Test3");
r_log(NR_LOG_TEST, LOG_INFO, "Test4");
r_log(NR_LOG_TEST, LOG_INFO, "Test5");
r_log(NR_LOG_TEST, LOG_INFO, "Test6");
ReInit();
std::deque<std::string> logs;
RLogRingBuffer::GetInstance()->GetAny(0, &logs);
ASSERT_EQ(0U, logs.size());
}
int main(int argc, char** argv) {
NR_reg_init(NR_REG_MODE_LOCAL);
r_log_init();
/* Would be nice to be able to register/unregister in the fixture */
const char* facility = "rlogringbuffer_test";
r_log_register(const_cast<char*>(facility), &NR_LOG_TEST);
::testing::InitGoogleTest(&argc, argv);
int rv = RUN_ALL_TESTS();
return rv;
}

View File

@ -383,7 +383,7 @@ int nr_ice_candidate_pair_do_triggered_check(nr_ice_peer_ctx *pctx, nr_ice_cand_
{
int r,_status;
r_log(LOG_ICE,LOG_DEBUG,"ICE-PEER(%s)/CAND-PAIR(%s): triggered check on %s",pctx->label,pair->codeword,pair->as_string);
r_log(LOG_ICE,LOG_INFO,"ICE-PEER(%s)/CAND-PAIR(%s): triggered check on %s",pctx->label,pair->codeword,pair->as_string);
switch(pair->state){
case NR_ICE_PAIR_STATE_FROZEN:
@ -461,7 +461,7 @@ int nr_ice_candidate_pair_set_state(nr_ice_peer_ctx *pctx, nr_ice_cand_pair *pai
{
int r,_status;
r_log(LOG_ICE,LOG_DEBUG,"ICE-PEER(%s)/CAND-PAIR(%s): setting pair to state %s: %s",
r_log(LOG_ICE,LOG_INFO,"ICE-PEER(%s)/CAND-PAIR(%s): setting pair to state %s: %s",
pctx->label,pair->codeword,nr_ice_cand_pair_states[state],pair->as_string);
/* NOTE: This function used to reference pctx->state instead of
@ -533,7 +533,7 @@ void nr_ice_candidate_pair_restart_stun_nominated_cb(NR_SOCKET s, int how, void
pair->restart_nominated_cb_timer=0;
r_log(LOG_ICE,LOG_DEBUG,"ICE-PEER(%s)/STREAM(%s)/CAND-PAIR(%s)/COMP(%d): Restarting pair as nominated: %s",pair->pctx->label,pair->local->stream->label,pair->codeword,pair->remote->component->component_id,pair->as_string);
r_log(LOG_ICE,LOG_INFO,"ICE-PEER(%s)/STREAM(%s)/CAND-PAIR(%s)/COMP(%d): Restarting pair as nominated: %s",pair->pctx->label,pair->local->stream->label,pair->codeword,pair->remote->component->component_id,pair->as_string);
nr_stun_client_reset(pair->stun_client);
@ -555,7 +555,7 @@ static void nr_ice_candidate_pair_restart_stun_controlled_cb(NR_SOCKET s, int ho
pair->restart_controlled_cb_timer=0;
r_log(LOG_ICE,LOG_DEBUG,"ICE-PEER(%s)/STREAM(%s)/CAND-PAIR(%s):COMP(%d): Restarting pair as CONTROLLED: %s",pair->pctx->label,pair->local->stream->label,pair->codeword,pair->remote->component->component_id,pair->as_string);
r_log(LOG_ICE,LOG_INFO,"ICE-PEER(%s)/STREAM(%s)/CAND-PAIR(%s):COMP(%d): Restarting pair as CONTROLLED: %s",pair->pctx->label,pair->local->stream->label,pair->codeword,pair->remote->component->component_id,pair->as_string);
nr_stun_client_reset(pair->stun_client);
pair->stun_client->params.ice_binding_request.control=NR_ICE_CONTROLLED;

View File

@ -792,7 +792,7 @@ int nr_ice_component_nominated_pair(nr_ice_component *comp, nr_ice_cand_pair *pa
if(comp->nominated){
if(comp->nominated->priority > pair->priority)
return(0);
r_log(LOG_ICE,LOG_DEBUG,"ICE-PEER(%s)/STREAM(%s)/COMP(%d)/CAND-PAIR(%s): replacing pair %s with CAND-PAIR(%s)",comp->stream->pctx->label,comp->stream->label,comp->component_id,comp->nominated->codeword,comp->nominated->as_string,pair->codeword);
r_log(LOG_ICE,LOG_INFO,"ICE-PEER(%s)/STREAM(%s)/COMP(%d)/CAND-PAIR(%s): replacing pair %s with CAND-PAIR(%s)",comp->stream->pctx->label,comp->stream->label,comp->component_id,comp->nominated->codeword,comp->nominated->as_string,pair->codeword);
}
/* Set the new nominated pair */
@ -801,7 +801,7 @@ int nr_ice_component_nominated_pair(nr_ice_component *comp, nr_ice_cand_pair *pa
comp->nominated=pair;
comp->active=pair;
r_log(LOG_ICE,LOG_DEBUG,"ICE-PEER(%s)/STREAM(%s)/COMP(%d)/CAND-PAIR(%s): cancelling all pairs but %s",comp->stream->pctx->label,comp->stream->label,comp->component_id,pair->codeword,pair->as_string);
r_log(LOG_ICE,LOG_INFO,"ICE-PEER(%s)/STREAM(%s)/COMP(%d)/CAND-PAIR(%s): cancelling all pairs but %s",comp->stream->pctx->label,comp->stream->label,comp->component_id,pair->codeword,pair->as_string);
/* Cancel checks in WAITING and FROZEN per ICE S 8.1.2 */
p2=TAILQ_FIRST(&comp->stream->check_list);
@ -810,7 +810,7 @@ int nr_ice_component_nominated_pair(nr_ice_component *comp, nr_ice_cand_pair *pa
(p2->remote->component->component_id == comp->component_id) &&
((p2->state == NR_ICE_PAIR_STATE_FROZEN) ||
(p2->state == NR_ICE_PAIR_STATE_WAITING))) {
r_log(LOG_ICE,LOG_DEBUG,"ICE-PEER(%s)/STREAM(%s)/COMP(%d)/CAND-PAIR(%s): cancelling FROZEN/WAITING pair %s because CAND-PAIR(%s) was nominated.",comp->stream->pctx->label,comp->stream->label,comp->component_id,p2->codeword,p2->as_string,pair->codeword);
r_log(LOG_ICE,LOG_INFO,"ICE-PEER(%s)/STREAM(%s)/COMP(%d)/CAND-PAIR(%s): cancelling FROZEN/WAITING pair %s because CAND-PAIR(%s) was nominated.",comp->stream->pctx->label,comp->stream->label,comp->component_id,p2->codeword,p2->as_string,pair->codeword);
if(r=nr_ice_candidate_pair_cancel(pair->pctx,p2))
ABORT(r);

View File

@ -330,6 +330,15 @@ int r_dump(int facility,int level,char *name,char *data,int len)
return(0);
}
// Some platforms (notably WIN32) do not have this
#ifndef va_copy
#ifdef WIN32
#define va_copy(dest, src) ( (dest) = (src) )
#else // WIN32
#error va_copy undefined, and semantics of assignment on va_list unknown
#endif //WIN32
#endif //va_copy
int r_vlog(int facility,int level,const char *format,va_list ap)
{
char log_fmt_buf[MAX_ERROR_STRING_SIZE];
@ -354,7 +363,12 @@ int r_vlog(int facility,int level,const char *format,va_list ap)
for(i=0; i<LOG_NUM_DESTINATIONS; i++){
if(r_logging_dest(i,facility,level)){
log_destinations[i].dest_vlog(facility,level,fmt_str,ap);
// Some platforms do not react well when you use a va_list more than
// once
va_list copy;
va_copy(copy, ap);
log_destinations[i].dest_vlog(facility,level,fmt_str,copy);
va_end(copy);
}
}
return(0);

View File

@ -506,7 +506,7 @@ PeerConnectionImpl::CreateRemoteSourceStreamInfo(nsRefPtr<RemoteSourceStreamInfo
return NS_ERROR_FAILURE;
}
static_cast<mozilla::SourceMediaStream*>(stream->GetStream())->SetPullEnabled(true);
static_cast<SourceMediaStream*>(stream->GetStream())->SetPullEnabled(true);
nsRefPtr<RemoteSourceStreamInfo> remote;
remote = new RemoteSourceStreamInfo(stream.forget(), mMedia);
@ -756,7 +756,7 @@ PeerConnectionImpl::Initialize(PeerConnectionObserver& aObserver,
return NS_OK;
}
mozilla::RefPtr<DtlsIdentity> const
RefPtr<DtlsIdentity> const
PeerConnectionImpl::GetIdentity() {
PC_AUTO_ENTER_API_CALL_NO_CHECK();
return mIdentity;
@ -822,7 +822,7 @@ PeerConnectionImpl::EnsureDataConnection(uint16_t aNumstreams)
// and we increase the number of streams dynamically as needed.
return NS_OK;
}
mDataConnection = new mozilla::DataChannelConnection(this);
mDataConnection = new DataChannelConnection(this);
if (!mDataConnection->Init(5000, aNumstreams, true)) {
CSFLogError(logTag,"%s DataConnection Init Failed",__FUNCTION__);
return NS_ERROR_FAILURE;
@ -897,9 +897,9 @@ PeerConnectionImpl::CreateDataChannel(const nsAString& aLabel,
MOZ_ASSERT(aRetval);
#ifdef MOZILLA_INTERNAL_API
nsRefPtr<mozilla::DataChannel> dataChannel;
mozilla::DataChannelConnection::Type theType =
static_cast<mozilla::DataChannelConnection::Type>(aType);
nsRefPtr<DataChannel> dataChannel;
DataChannelConnection::Type theType =
static_cast<DataChannelConnection::Type>(aType);
nsresult rv = EnsureDataConnection(WEBRTC_DATACHANNEL_STREAMS_DEFAULT);
if (NS_FAILED(rv)) {
@ -908,8 +908,8 @@ PeerConnectionImpl::CreateDataChannel(const nsAString& aLabel,
dataChannel = mDataConnection->Open(
NS_ConvertUTF16toUTF8(aLabel), NS_ConvertUTF16toUTF8(aProtocol), theType,
!outOfOrderAllowed,
aType == mozilla::DataChannelConnection::PARTIAL_RELIABLE_REXMIT ? aMaxNum :
(aType == mozilla::DataChannelConnection::PARTIAL_RELIABLE_TIMED ? aMaxTime : 0),
aType == DataChannelConnection::PARTIAL_RELIABLE_REXMIT ? aMaxNum :
(aType == DataChannelConnection::PARTIAL_RELIABLE_TIMED ? aMaxTime : 0),
nullptr, nullptr, aExternalNegotiated, aStream
);
NS_ENSURE_TRUE(dataChannel,NS_ERROR_FAILURE);
@ -987,7 +987,7 @@ static void NotifyDataChannel_m(nsRefPtr<nsIDOMDataChannel> aChannel,
#endif
void
PeerConnectionImpl::NotifyDataChannel(already_AddRefed<mozilla::DataChannel> aChannel)
PeerConnectionImpl::NotifyDataChannel(already_AddRefed<DataChannel> aChannel)
{
PC_AUTO_ENTER_API_CALL_NO_CHECK();
MOZ_ASSERT(aChannel.get());
@ -1110,7 +1110,8 @@ PeerConnectionImpl::GetTimeSinceEpoch(DOMHighResTimeStamp *result) {
#endif
NS_IMETHODIMP
PeerConnectionImpl::GetStats(mozilla::dom::MediaStreamTrack *aSelector) {
PeerConnectionImpl::GetStats(MediaStreamTrack *aSelector,
bool internalStats) {
PC_AUTO_ENTER_API_CALL(true);
#ifdef MOZILLA_INTERNAL_API
@ -1118,12 +1119,12 @@ PeerConnectionImpl::GetStats(mozilla::dom::MediaStreamTrack *aSelector) {
DOMHighResTimeStamp now;
nsresult rv = GetTimeSinceEpoch(&now);
NS_ENSURE_SUCCESS(rv, rv);
nsRefPtr<PeerConnectionImpl> pc(this);
RUN_ON_THREAD(mSTSThread,
WrapRunnable(pc,
&PeerConnectionImpl::GetStats_s,
track,
internalStats,
now),
NS_DISPATCH_NORMAL);
#endif
@ -1399,7 +1400,7 @@ PeerConnectionImpl::ShutdownMedia()
#ifdef MOZILLA_INTERNAL_API
// End of call to be recorded in Telemetry
if (!mStartTime.IsNull()){
mozilla::TimeDuration timeDelta = mozilla::TimeStamp::Now() - mStartTime;
TimeDuration timeDelta = TimeStamp::Now() - mStartTime;
Telemetry::Accumulate(Telemetry::WEBRTC_CALL_DURATION, timeDelta.ToSeconds());
}
#endif
@ -1626,6 +1627,7 @@ PeerConnectionImpl::IceStateChange_m(PCImplIceState aState)
#ifdef MOZILLA_INTERNAL_API
void PeerConnectionImpl::GetStats_s(
uint32_t trackId,
bool internalStats,
DOMHighResTimeStamp now) {
nsresult result = NS_OK;
@ -1633,6 +1635,70 @@ void PeerConnectionImpl::GetStats_s(
if (!report) {
result = NS_ERROR_FAILURE;
}
if (mMedia) {
RefPtr<NrIceMediaStream> mediaStream(
mMedia->ice_media_stream(trackId));
if (mediaStream) {
std::vector<NrIceCandidatePair> candPairs;
mediaStream->GetCandidatePairs(&candPairs);
report->mIceCandidatePairStats.Construct();
report->mIceCandidateStats.Construct();
NS_ConvertASCIItoUTF16 componentId(mediaStream->name().c_str());
for (auto p = candPairs.begin(); p != candPairs.end(); ++p) {
NS_ConvertASCIItoUTF16 codeword(p->codeword.c_str());
const nsString localCodeword(
NS_ConvertASCIItoUTF16("local_") + codeword);
const nsString remoteCodeword(
NS_ConvertASCIItoUTF16("remote_") + codeword);
// Only expose candidate-pair statistics to chrome, until we've thought
// through the implications of exposing it to content.
if (internalStats) {
RTCIceCandidatePairStats s;
s.mId.Construct(codeword);
s.mComponentId.Construct(componentId);
s.mTimestamp.Construct(now);
s.mType.Construct(RTCStatsType::Candidatepair);
// Not quite right; we end up with duplicate candidates. Will fix.
s.mLocalCandidateId.Construct(localCodeword);
s.mRemoteCandidateId.Construct(remoteCodeword);
s.mNominated.Construct(p->nominated);
s.mMozPriority.Construct(p->priority);
s.mSelected.Construct(p->selected);
s.mState.Construct(RTCStatsIceCandidatePairState(p->state));
report->mIceCandidatePairStats.Value().AppendElement(s);
}
{
RTCIceCandidateStats local;
local.mId.Construct(localCodeword);
local.mTimestamp.Construct(now);
local.mType.Construct(RTCStatsType::Localcandidate);
local.mCandidateType.Construct(
RTCStatsIceCandidateType(p->local.type));
local.mIpAddress.Construct(
NS_ConvertASCIItoUTF16(p->local.host.c_str()));
local.mPortNumber.Construct(p->local.port);
report->mIceCandidateStats.Value().AppendElement(local);
}
{
RTCIceCandidateStats remote;
remote.mId.Construct(remoteCodeword);
remote.mTimestamp.Construct(now);
remote.mType.Construct(RTCStatsType::Remotecandidate);
remote.mCandidateType.Construct(
RTCStatsIceCandidateType(p->remote.type));
remote.mIpAddress.Construct(
NS_ConvertASCIItoUTF16(p->remote.host.c_str()));
remote.mPortNumber.Construct(p->remote.port);
report->mIceCandidateStats.Value().AppendElement(remote);
}
}
}
}
nsRefPtr<PeerConnectionImpl> pc(this);
RUN_ON_THREAD(mThread,
WrapRunnable(pc,
@ -1646,7 +1712,7 @@ void PeerConnectionImpl::GetStats_s(
void PeerConnectionImpl::OnStatsReport_m(
uint32_t trackId,
nsresult result,
nsAutoPtr<mozilla::dom::RTCStatsReportInternal> report) {
nsAutoPtr<RTCStatsReportInternal> report) {
PeerConnectionObserver* pco = mPCObserver.MayGet();
if (pco) {
JSErrorResult rv;
@ -1696,7 +1762,7 @@ PeerConnectionImpl::GetSdpParseErrors() {
void
PeerConnectionImpl::startCallTelem() {
// Start time for calls
mStartTime = mozilla::TimeStamp::Now();
mStartTime = TimeStamp::Now();
// Increment session call counter
#ifdef MOZILLA_INTERNAL_API
@ -1709,7 +1775,7 @@ PeerConnectionImpl::startCallTelem() {
#endif
NS_IMETHODIMP
PeerConnectionImpl::GetLocalStreams(nsTArray<nsRefPtr<mozilla::DOMMediaStream > >& result)
PeerConnectionImpl::GetLocalStreams(nsTArray<nsRefPtr<DOMMediaStream > >& result)
{
PC_AUTO_ENTER_API_CALL_NO_CHECK();
#ifdef MOZILLA_INTERNAL_API
@ -1725,7 +1791,7 @@ PeerConnectionImpl::GetLocalStreams(nsTArray<nsRefPtr<mozilla::DOMMediaStream >
}
NS_IMETHODIMP
PeerConnectionImpl::GetRemoteStreams(nsTArray<nsRefPtr<mozilla::DOMMediaStream > >& result)
PeerConnectionImpl::GetRemoteStreams(nsTArray<nsRefPtr<DOMMediaStream > >& result)
{
PC_AUTO_ENTER_API_CALL_NO_CHECK();
#ifdef MOZILLA_INTERNAL_API

View File

@ -301,9 +301,10 @@ public:
}
NS_IMETHODIMP_TO_ERRORRESULT(GetStats, ErrorResult &rv,
mozilla::dom::MediaStreamTrack *aSelector)
mozilla::dom::MediaStreamTrack *aSelector,
bool internalStats)
{
rv = GetStats(aSelector);
rv = GetStats(aSelector, internalStats);
}
NS_IMETHODIMP AddIceCandidate(const char* aCandidate, const char* aMid,
@ -486,6 +487,7 @@ private:
#ifdef MOZILLA_INTERNAL_API
// Fills in an RTCStatsReportInternal. Must be run on STS.
void GetStats_s(uint32_t trackId,
bool internalStats,
DOMHighResTimeStamp now);
// Sends an RTCStatsReport to JS. Must run on main thread.

View File

@ -89,6 +89,9 @@
# define MOZ_HAVE_NEVER_INLINE __attribute__((noinline))
# define MOZ_HAVE_NORETURN __attribute__((noreturn))
#elif defined(_MSC_VER)
# if _MSC_VER >= 1800
# define MOZ_HAVE_CXX11_DELETE
# endif
# if _MSC_VER >= 1700
# define MOZ_HAVE_CXX11_FINAL final
# else

View File

@ -40,6 +40,7 @@ this.NS_ASSERT = function NS_ASSERT(condition, message) {
try {
switch (defB.getCharPref("app.update.channel")) {
case "nightly":
case "aurora":
case "beta":
case "default":
releaseBuild = false;
@ -49,15 +50,14 @@ this.NS_ASSERT = function NS_ASSERT(condition, message) {
var caller = arguments.callee.caller;
var assertionText = "ASSERT: " + message + "\n";
// Report the error to the console
Components.utils.reportError(assertionText);
if (releaseBuild) {
// Just report the error to the console
Components.utils.reportError(assertionText);
return;
}
// Otherwise, dump to stdout and launch an assertion failure dialog
dump(assertionText);
// dump the stack to stdout too in non-release builds
var stackText = "";
if (gTraceOnAssert) {
stackText = "Stack Trace: \n";
@ -75,16 +75,5 @@ this.NS_ASSERT = function NS_ASSERT(condition, message) {
}
}
var environment = Components.classes["@mozilla.org/process/environment;1"].
getService(Components.interfaces.nsIEnvironment);
if (environment.exists("XUL_ASSERT_PROMPT") &&
!parseInt(environment.get("XUL_ASSERT_PROMPT")))
return;
var source = null;
if (this.window)
source = this.window;
var ps = Components.classes["@mozilla.org/embedcomp/prompt-service;1"].
getService(Components.interfaces.nsIPromptService);
ps.alert(source, "Assertion Failed", assertionText + stackText);
dump(assertionText + stackText);
}

View File

@ -1046,13 +1046,13 @@ moz_gtk_toggle_paint(GdkDrawable* drawable, GdkRectangle* rect,
w = gCheckboxWidget;
}
NS_ASSERTION(rect->width == indicator_size,
// XXX we should assert rect->height >= indicator_size too
// after bug 369581 is fixed.
NS_ASSERTION(rect->width >= indicator_size,
"GetMinimumWidgetSize was ignored");
/*
* vertically center in the box, since XUL sometimes ignores our
* GetMinimumWidgetSize in the vertical dimension
*/
x = rect->x;
// Paint it center aligned in the rect.
x = rect->x + (rect->width - indicator_size) / 2;
y = rect->y + (rect->height - indicator_size) / 2;
width = indicator_size;
height = indicator_size;

View File

@ -958,13 +958,13 @@ moz_gtk_toggle_paint(cairo_t *cr, GdkRectangle* rect,
w = gCheckboxWidget;
}
NS_ASSERTION(rect->width == indicator_size,
// XXX we should assert rect->height >= indicator_size too
// after bug 369581 is fixed.
NS_ASSERTION(rect->width >= indicator_size,
"GetMinimumWidgetSize was ignored");
/*
* vertically center in the box, since XUL sometimes ignores our
* GetMinimumWidgetSize in the vertical dimension
*/
x = rect->x;
// Paint it center aligned in the rect.
x = rect->x + (rect->width - indicator_size) / 2;
y = rect->y + (rect->height - indicator_size) / 2;
width = indicator_size;
height = indicator_size;

Some files were not shown because too many files have changed in this diff Show More