зеркало из https://github.com/mozilla/gecko-dev.git
Merge m-c to m-i on a CLOSED TREE
This commit is contained in:
Коммит
67b66a1095
2
CLOBBER
2
CLOBBER
|
@ -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
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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(); }
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -434,6 +434,7 @@ public:
|
|||
{
|
||||
return mIsFrozen;
|
||||
}
|
||||
virtual NS_HIDDEN_(bool) IsRunningTimeout() { return mTimeoutFiringDepth > 0; }
|
||||
|
||||
virtual NS_HIDDEN_(bool) WouldReuseInnerWindow(nsIDocument *aNewDocument);
|
||||
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -41,7 +41,7 @@ public:
|
|||
void GetSupportedNames(nsTArray< nsString >& retval);
|
||||
|
||||
protected:
|
||||
void EnsureMimeTypes();
|
||||
void EnsurePluginMimeTypes();
|
||||
void Clear();
|
||||
|
||||
nsCOMPtr<nsPIDOMWindow> mWindow;
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -220,6 +220,7 @@ protected:
|
|||
void OnNuwaForkTimeout();
|
||||
|
||||
bool ShouldContinueFromReplyTimeout() MOZ_OVERRIDE;
|
||||
bool ShouldSandboxContentProcesses();
|
||||
|
||||
private:
|
||||
static nsDataHashtable<nsStringHashKey, ContentParent*> *sAppContentParents;
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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}
|
||||
|
|
|
@ -97,7 +97,7 @@ function waitForPaintHelper(func) {
|
|||
setTimeout(func, 0);
|
||||
return;
|
||||
}
|
||||
setTimeout(function() { waitForPaintHelper(func); }, 100);
|
||||
setTimeout(function() { waitForPaintHelper(func); }, 1000);
|
||||
}
|
||||
|
||||
</script>
|
||||
|
|
|
@ -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]
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
|
|
@ -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
|
||||
|
|
@ -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_ */
|
||||
|
|
|
@ -89,6 +89,7 @@ SOURCES += [
|
|||
'ImageScaling.cpp',
|
||||
'Matrix.cpp',
|
||||
'PathCairo.cpp',
|
||||
'PathHelpers.cpp',
|
||||
'PathRecording.cpp',
|
||||
'RecordedEvent.cpp',
|
||||
'Scale.cpp',
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
{
|
||||
"expect-hazards": 19
|
||||
}
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
|
@ -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_ */
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 ?
|
||||
|
|
|
@ -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',
|
||||
|
|
|
@ -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()) {
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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.
|
||||
*/
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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>
|
|
@ -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>
|
|
@ -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
|
||||
|
|
|
@ -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>
|
|
@ -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>
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -12,6 +12,7 @@ EXPORTS.mtransport += [
|
|||
'../nricectx.h',
|
||||
'../nricemediastream.h',
|
||||
'../nriceresolverfake.h',
|
||||
'../rlogringbuffer.h',
|
||||
'../runnable_utils.h',
|
||||
'../runnable_utils_generated.h',
|
||||
'../sigslot.h',
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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)) {
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -13,6 +13,7 @@ mtransport_lcppsrcs = [
|
|||
'nriceresolver.cpp',
|
||||
'nriceresolverfake.cpp',
|
||||
'nrinterfaceprioritizer.cpp',
|
||||
'rlogringbuffer.cpp',
|
||||
'simpletokenbucket.cpp',
|
||||
'transportflow.cpp',
|
||||
'transportlayer.cpp',
|
||||
|
|
|
@ -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
|
||||
|
|
@ -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__
|
||||
|
||||
|
|
@ -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());
|
||||
|
|
|
@ -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',
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче