зеркало из https://github.com/mozilla/gecko-dev.git
Merge mozilla-inbound to mozilla-central. a=merge
This commit is contained in:
Коммит
49014f945b
|
@ -38,14 +38,18 @@ class FlexItemSizingOutline extends PureComponent {
|
|||
);
|
||||
}
|
||||
|
||||
renderFinalOutline(mainFinalSize, mainMaxSize, mainMinSize, isClamped) {
|
||||
return (
|
||||
dom.div({ className: "flex-outline-final" + (isClamped ? " clamped" : "") })
|
||||
);
|
||||
renderFinalOutline(isClamped) {
|
||||
return dom.div({ className: "flex-outline-final" + (isClamped ? " clamped" : "") });
|
||||
}
|
||||
|
||||
renderPoint(className, label = className) {
|
||||
return dom.div({ className: `flex-outline-point ${className}`, "data-label": label });
|
||||
return (
|
||||
dom.div({
|
||||
key: className,
|
||||
className: `flex-outline-point ${className}`,
|
||||
"data-label": label,
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
render() {
|
||||
|
@ -145,7 +149,7 @@ class FlexItemSizingOutline extends PureComponent {
|
|||
dom.div(
|
||||
{
|
||||
className: `flex-outline ${mainAxisDirection}` +
|
||||
(mainDeltaSize > 0 ? " growing" : " shrinking"),
|
||||
(mainDeltaSize > 0 ? " growing" : " shrinking"),
|
||||
style: {
|
||||
gridTemplateColumns,
|
||||
},
|
||||
|
@ -155,8 +159,7 @@ class FlexItemSizingOutline extends PureComponent {
|
|||
showMax ? this.renderPoint("max") : null,
|
||||
this.renderBasisOutline(mainBaseSize),
|
||||
this.renderDeltaOutline(mainDeltaSize),
|
||||
this.renderFinalOutline(mainFinalSize, mainMaxSize, mainMinSize,
|
||||
clampState !== "unclamped")
|
||||
this.renderFinalOutline(clampState !== "unclamped")
|
||||
)
|
||||
)
|
||||
);
|
||||
|
|
|
@ -1005,10 +1005,6 @@ DOMInterfaces = {
|
|||
'headerFile': 'mozilla/dom/SVGGradientElement.h',
|
||||
},
|
||||
|
||||
'SVGRect': {
|
||||
'nativeType': 'mozilla::dom::SVGIRect'
|
||||
},
|
||||
|
||||
'SVGStringList': {
|
||||
'nativeType': 'mozilla::DOMSVGStringList',
|
||||
'headerFile': 'DOMSVGStringList.h',
|
||||
|
|
|
@ -7,8 +7,8 @@
|
|||
#include "SVGAnimatedRect.h"
|
||||
#include "mozilla/dom/SVGAnimatedRectBinding.h"
|
||||
#include "mozilla/dom/SVGElement.h"
|
||||
#include "mozilla/dom/SVGRect.h"
|
||||
#include "SVGAnimatedViewBox.h"
|
||||
#include "SVGIRect.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
@ -26,11 +26,11 @@ SVGAnimatedRect::~SVGAnimatedRect() {
|
|||
SVGAnimatedViewBox::sSVGAnimatedRectTearoffTable.RemoveTearoff(mVal);
|
||||
}
|
||||
|
||||
already_AddRefed<SVGIRect> SVGAnimatedRect::GetBaseVal() {
|
||||
already_AddRefed<SVGRect> SVGAnimatedRect::GetBaseVal() {
|
||||
return mVal->ToDOMBaseVal(mSVGElement);
|
||||
}
|
||||
|
||||
already_AddRefed<SVGIRect> SVGAnimatedRect::GetAnimVal() {
|
||||
already_AddRefed<SVGRect> SVGAnimatedRect::GetAnimVal() {
|
||||
return mVal->ToDOMAnimVal(mSVGElement);
|
||||
}
|
||||
|
||||
|
|
|
@ -9,15 +9,21 @@
|
|||
|
||||
#include "nsCycleCollectionParticipant.h"
|
||||
#include "mozilla/dom/SVGElement.h"
|
||||
#include "mozilla/dom/SVGRectBinding.h"
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "mozilla/ErrorResult.h"
|
||||
#include "nsWrapperCache.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
class SVGAnimatedViewBox;
|
||||
|
||||
namespace dom {
|
||||
|
||||
class SVGRect;
|
||||
|
||||
// Despite the name of this class appearing to be generic,
|
||||
// SVGAnimatedRect is only used for viewBox attributes.
|
||||
|
||||
class SVGAnimatedRect final : public nsWrapperCache {
|
||||
public:
|
||||
NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(SVGAnimatedRect)
|
||||
|
@ -30,9 +36,9 @@ class SVGAnimatedRect final : public nsWrapperCache {
|
|||
virtual JSObject* WrapObject(JSContext* aCx,
|
||||
JS::Handle<JSObject*> aGivenProto) override;
|
||||
|
||||
already_AddRefed<SVGIRect> GetBaseVal();
|
||||
already_AddRefed<SVGRect> GetBaseVal();
|
||||
|
||||
already_AddRefed<SVGIRect> GetAnimVal();
|
||||
already_AddRefed<SVGRect> GetAnimVal();
|
||||
|
||||
private:
|
||||
virtual ~SVGAnimatedRect();
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
#include "mozilla/Move.h"
|
||||
#include "mozilla/SMILValue.h"
|
||||
#include "mozilla/SVGContentUtils.h"
|
||||
#include "mozilla/dom/SVGRect.h"
|
||||
#include "nsCharSeparatedTokenizer.h"
|
||||
#include "SVGViewBoxSMILType.h"
|
||||
#include "nsTextFormatter.h"
|
||||
|
@ -61,32 +62,9 @@ nsresult SVGViewBox::FromString(const nsAString& aStr, SVGViewBox* aViewBox) {
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
/* Cycle collection macros for SVGAnimatedViewBox */
|
||||
|
||||
NS_SVG_VAL_IMPL_CYCLE_COLLECTION_WRAPPERCACHED(SVGAnimatedViewBox::DOMBaseVal,
|
||||
mSVGElement)
|
||||
NS_SVG_VAL_IMPL_CYCLE_COLLECTION_WRAPPERCACHED(SVGAnimatedViewBox::DOMAnimVal,
|
||||
mSVGElement)
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTING_ADDREF(SVGAnimatedViewBox::DOMBaseVal)
|
||||
NS_IMPL_CYCLE_COLLECTING_RELEASE(SVGAnimatedViewBox::DOMBaseVal)
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTING_ADDREF(SVGAnimatedViewBox::DOMAnimVal)
|
||||
NS_IMPL_CYCLE_COLLECTING_RELEASE(SVGAnimatedViewBox::DOMAnimVal)
|
||||
|
||||
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(SVGAnimatedViewBox::DOMBaseVal)
|
||||
NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
|
||||
NS_INTERFACE_MAP_ENTRY(nsISupports)
|
||||
NS_INTERFACE_MAP_END
|
||||
|
||||
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(SVGAnimatedViewBox::DOMAnimVal)
|
||||
NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
|
||||
NS_INTERFACE_MAP_ENTRY(nsISupports)
|
||||
NS_INTERFACE_MAP_END
|
||||
|
||||
static SVGAttrTearoffTable<SVGAnimatedViewBox, SVGAnimatedViewBox::DOMBaseVal>
|
||||
static SVGAttrTearoffTable<SVGAnimatedViewBox, SVGRect>
|
||||
sBaseSVGViewBoxTearoffTable;
|
||||
static SVGAttrTearoffTable<SVGAnimatedViewBox, SVGAnimatedViewBox::DOMAnimVal>
|
||||
static SVGAttrTearoffTable<SVGAnimatedViewBox, SVGRect>
|
||||
sAnimSVGViewBoxTearoffTable;
|
||||
SVGAttrTearoffTable<SVGAnimatedViewBox, SVGAnimatedRect>
|
||||
SVGAnimatedViewBox::sSVGAnimatedRectTearoffTable;
|
||||
|
@ -206,70 +184,45 @@ already_AddRefed<SVGAnimatedRect> SVGAnimatedViewBox::ToSVGAnimatedRect(
|
|||
return domAnimatedRect.forget();
|
||||
}
|
||||
|
||||
already_AddRefed<SVGIRect> SVGAnimatedViewBox::ToDOMBaseVal(
|
||||
already_AddRefed<SVGRect> SVGAnimatedViewBox::ToDOMBaseVal(
|
||||
SVGElement* aSVGElement) {
|
||||
if (!mHasBaseVal || mBaseVal.none) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
RefPtr<DOMBaseVal> domBaseVal = sBaseSVGViewBoxTearoffTable.GetTearoff(this);
|
||||
RefPtr<SVGRect> domBaseVal = sBaseSVGViewBoxTearoffTable.GetTearoff(this);
|
||||
if (!domBaseVal) {
|
||||
domBaseVal = new DOMBaseVal(this, aSVGElement);
|
||||
domBaseVal = new SVGRect(this, aSVGElement, SVGRect::BaseValue);
|
||||
sBaseSVGViewBoxTearoffTable.AddTearoff(this, domBaseVal);
|
||||
}
|
||||
|
||||
return domBaseVal.forget();
|
||||
}
|
||||
|
||||
SVGAnimatedViewBox::DOMBaseVal::~DOMBaseVal() {
|
||||
sBaseSVGViewBoxTearoffTable.RemoveTearoff(mVal);
|
||||
SVGRect::~SVGRect() {
|
||||
if (mType == BaseValue) {
|
||||
sBaseSVGViewBoxTearoffTable.RemoveTearoff(mVal);
|
||||
} else if (mType == AnimValue) {
|
||||
sAnimSVGViewBoxTearoffTable.RemoveTearoff(mVal);
|
||||
}
|
||||
}
|
||||
|
||||
already_AddRefed<SVGIRect> SVGAnimatedViewBox::ToDOMAnimVal(
|
||||
already_AddRefed<SVGRect> SVGAnimatedViewBox::ToDOMAnimVal(
|
||||
SVGElement* aSVGElement) {
|
||||
if ((mAnimVal && mAnimVal->none) ||
|
||||
(!mAnimVal && (!mHasBaseVal || mBaseVal.none))) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
RefPtr<DOMAnimVal> domAnimVal = sAnimSVGViewBoxTearoffTable.GetTearoff(this);
|
||||
RefPtr<SVGRect> domAnimVal = sAnimSVGViewBoxTearoffTable.GetTearoff(this);
|
||||
if (!domAnimVal) {
|
||||
domAnimVal = new DOMAnimVal(this, aSVGElement);
|
||||
domAnimVal = new SVGRect(this, aSVGElement, SVGRect::AnimValue);
|
||||
sAnimSVGViewBoxTearoffTable.AddTearoff(this, domAnimVal);
|
||||
}
|
||||
|
||||
return domAnimVal.forget();
|
||||
}
|
||||
|
||||
SVGAnimatedViewBox::DOMAnimVal::~DOMAnimVal() {
|
||||
sAnimSVGViewBoxTearoffTable.RemoveTearoff(mVal);
|
||||
}
|
||||
|
||||
void SVGAnimatedViewBox::DOMBaseVal::SetX(float aX, ErrorResult& aRv) {
|
||||
SVGViewBox rect = mVal->GetBaseValue();
|
||||
rect.x = aX;
|
||||
mVal->SetBaseValue(rect, mSVGElement);
|
||||
}
|
||||
|
||||
void SVGAnimatedViewBox::DOMBaseVal::SetY(float aY, ErrorResult& aRv) {
|
||||
SVGViewBox rect = mVal->GetBaseValue();
|
||||
rect.y = aY;
|
||||
mVal->SetBaseValue(rect, mSVGElement);
|
||||
}
|
||||
|
||||
void SVGAnimatedViewBox::DOMBaseVal::SetWidth(float aWidth, ErrorResult& aRv) {
|
||||
SVGViewBox rect = mVal->GetBaseValue();
|
||||
rect.width = aWidth;
|
||||
mVal->SetBaseValue(rect, mSVGElement);
|
||||
}
|
||||
|
||||
void SVGAnimatedViewBox::DOMBaseVal::SetHeight(float aHeight,
|
||||
ErrorResult& aRv) {
|
||||
SVGViewBox rect = mVal->GetBaseValue();
|
||||
rect.height = aHeight;
|
||||
mVal->SetBaseValue(rect, mSVGElement);
|
||||
}
|
||||
|
||||
UniquePtr<SMILAttr> SVGAnimatedViewBox::ToSMILAttr(SVGElement* aSVGElement) {
|
||||
return MakeUnique<SMILViewBox>(this, aSVGElement);
|
||||
}
|
||||
|
|
|
@ -15,13 +15,13 @@
|
|||
#include "mozilla/SMILAttr.h"
|
||||
#include "mozilla/UniquePtr.h"
|
||||
#include "mozilla/dom/SVGAnimatedRect.h"
|
||||
#include "mozilla/dom/SVGIRect.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
class SMILValue;
|
||||
|
||||
namespace dom {
|
||||
class SVGRect;
|
||||
class SVGAnimationElement;
|
||||
class SVGElement;
|
||||
} // namespace dom
|
||||
|
@ -80,11 +80,9 @@ class SVGAnimatedViewBox {
|
|||
already_AddRefed<mozilla::dom::SVGAnimatedRect> ToSVGAnimatedRect(
|
||||
SVGElement* aSVGElement);
|
||||
|
||||
already_AddRefed<mozilla::dom::SVGIRect> ToDOMBaseVal(
|
||||
SVGElement* aSVGElement);
|
||||
already_AddRefed<dom::SVGRect> ToDOMBaseVal(SVGElement* aSVGElement);
|
||||
|
||||
already_AddRefed<mozilla::dom::SVGIRect> ToDOMAnimVal(
|
||||
SVGElement* aSVGElement);
|
||||
already_AddRefed<dom::SVGRect> ToDOMAnimVal(SVGElement* aSVGElement);
|
||||
|
||||
mozilla::UniquePtr<SMILAttr> ToSMILAttr(SVGElement* aSVGElement);
|
||||
|
||||
|
@ -94,89 +92,6 @@ class SVGAnimatedViewBox {
|
|||
bool mHasBaseVal;
|
||||
|
||||
public:
|
||||
struct DOMBaseVal final : public mozilla::dom::SVGIRect {
|
||||
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
|
||||
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(DOMBaseVal)
|
||||
|
||||
DOMBaseVal(SVGAnimatedViewBox* aVal, SVGElement* aSVGElement)
|
||||
: mozilla::dom::SVGIRect(), mVal(aVal), mSVGElement(aSVGElement) {}
|
||||
|
||||
SVGAnimatedViewBox* mVal; // kept alive because it belongs to content
|
||||
RefPtr<SVGElement> mSVGElement;
|
||||
|
||||
float X() const final { return mVal->GetBaseValue().x; }
|
||||
|
||||
float Y() const final { return mVal->GetBaseValue().y; }
|
||||
|
||||
float Width() const final { return mVal->GetBaseValue().width; }
|
||||
|
||||
float Height() const final { return mVal->GetBaseValue().height; }
|
||||
|
||||
void SetX(float aX, mozilla::ErrorResult& aRv) final;
|
||||
void SetY(float aY, mozilla::ErrorResult& aRv) final;
|
||||
void SetWidth(float aWidth, mozilla::ErrorResult& aRv) final;
|
||||
void SetHeight(float aHeight, mozilla::ErrorResult& aRv) final;
|
||||
|
||||
virtual nsIContent* GetParentObject() const override { return mSVGElement; }
|
||||
|
||||
private:
|
||||
virtual ~DOMBaseVal();
|
||||
};
|
||||
|
||||
struct DOMAnimVal final : public mozilla::dom::SVGIRect {
|
||||
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
|
||||
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(DOMAnimVal)
|
||||
|
||||
DOMAnimVal(SVGAnimatedViewBox* aVal, SVGElement* aSVGElement)
|
||||
: mozilla::dom::SVGIRect(), mVal(aVal), mSVGElement(aSVGElement) {}
|
||||
|
||||
SVGAnimatedViewBox* mVal; // kept alive because it belongs to content
|
||||
RefPtr<SVGElement> mSVGElement;
|
||||
|
||||
// Script may have modified animation parameters or timeline -- DOM getters
|
||||
// need to flush any resample requests to reflect these modifications.
|
||||
float X() const final {
|
||||
mSVGElement->FlushAnimations();
|
||||
return mVal->GetAnimValue().x;
|
||||
}
|
||||
|
||||
float Y() const final {
|
||||
mSVGElement->FlushAnimations();
|
||||
return mVal->GetAnimValue().y;
|
||||
}
|
||||
|
||||
float Width() const final {
|
||||
mSVGElement->FlushAnimations();
|
||||
return mVal->GetAnimValue().width;
|
||||
}
|
||||
|
||||
float Height() const final {
|
||||
mSVGElement->FlushAnimations();
|
||||
return mVal->GetAnimValue().height;
|
||||
}
|
||||
|
||||
void SetX(float aX, mozilla::ErrorResult& aRv) final {
|
||||
aRv.Throw(NS_ERROR_DOM_NO_MODIFICATION_ALLOWED_ERR);
|
||||
}
|
||||
|
||||
void SetY(float aY, mozilla::ErrorResult& aRv) final {
|
||||
aRv.Throw(NS_ERROR_DOM_NO_MODIFICATION_ALLOWED_ERR);
|
||||
}
|
||||
|
||||
void SetWidth(float aWidth, mozilla::ErrorResult& aRv) final {
|
||||
aRv.Throw(NS_ERROR_DOM_NO_MODIFICATION_ALLOWED_ERR);
|
||||
}
|
||||
|
||||
void SetHeight(float aHeight, mozilla::ErrorResult& aRv) final {
|
||||
aRv.Throw(NS_ERROR_DOM_NO_MODIFICATION_ALLOWED_ERR);
|
||||
}
|
||||
|
||||
virtual nsIContent* GetParentObject() const override { return mSVGElement; }
|
||||
|
||||
private:
|
||||
virtual ~DOMAnimVal();
|
||||
};
|
||||
|
||||
struct SMILViewBox : public SMILAttr {
|
||||
public:
|
||||
SMILViewBox(SVGAnimatedViewBox* aVal, SVGElement* aSVGElement)
|
||||
|
|
|
@ -1,52 +0,0 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=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/. */
|
||||
|
||||
#ifndef mozilla_dom_SVGIRect_h
|
||||
#define mozilla_dom_SVGIRect_h
|
||||
|
||||
#include "nsCycleCollectionParticipant.h"
|
||||
#include "mozilla/dom/SVGRectBinding.h"
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "mozilla/ErrorResult.h"
|
||||
#include "nsWrapperCache.h"
|
||||
|
||||
class nsIContent;
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
class SVGIRect : public nsISupports, public nsWrapperCache {
|
||||
public:
|
||||
virtual ~SVGIRect() = default;
|
||||
|
||||
JSObject* WrapObject(JSContext* aCx,
|
||||
JS::Handle<JSObject*> aGivenProto) override {
|
||||
return SVGRect_Binding::Wrap(aCx, this, aGivenProto);
|
||||
}
|
||||
|
||||
virtual nsIContent* GetParentObject() const = 0;
|
||||
|
||||
virtual float X() const = 0;
|
||||
|
||||
virtual void SetX(float aX, ErrorResult& aRv) = 0;
|
||||
|
||||
virtual float Y() const = 0;
|
||||
|
||||
virtual void SetY(float aY, ErrorResult& aRv) = 0;
|
||||
|
||||
virtual float Width() const = 0;
|
||||
|
||||
virtual void SetWidth(float aWidth, ErrorResult& aRv) = 0;
|
||||
|
||||
virtual float Height() const = 0;
|
||||
|
||||
virtual void SetHeight(float aHeight, ErrorResult& aRv) = 0;
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // mozilla_dom_SVGIRect_h
|
|
@ -5,19 +5,17 @@
|
|||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "mozilla/dom/SVGRect.h"
|
||||
#include "SVGElement.h"
|
||||
|
||||
#include "mozilla/dom/SVGRectBinding.h"
|
||||
#include "mozilla/dom/SVGSVGElement.h"
|
||||
#include "SVGAnimatedViewBox.h"
|
||||
#include "nsWrapperCache.h"
|
||||
|
||||
using namespace mozilla::gfx;
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// implementation:
|
||||
|
||||
SVGRect::SVGRect(nsIContent* aParent, float x, float y, float w, float h)
|
||||
: SVGIRect(), mParent(aParent), mX(x), mY(y), mWidth(w), mHeight(h) {}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// nsISupports methods:
|
||||
|
||||
|
@ -31,23 +29,132 @@ NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(SVGRect)
|
|||
NS_INTERFACE_MAP_ENTRY(nsISupports)
|
||||
NS_INTERFACE_MAP_END
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// implementation:
|
||||
|
||||
SVGRect::SVGRect(SVGSVGElement* aSVGElement)
|
||||
: mVal(nullptr), mParent(aSVGElement), mType(CreatedValue) {
|
||||
MOZ_ASSERT(mParent);
|
||||
mRect = gfx::Rect(0, 0, 0, 0);
|
||||
}
|
||||
|
||||
JSObject* SVGRect::WrapObject(JSContext* aCx,
|
||||
JS::Handle<JSObject*> aGivenProto) {
|
||||
MOZ_ASSERT(mParent);
|
||||
return SVGRect_Binding::Wrap(aCx, this, aGivenProto);
|
||||
}
|
||||
|
||||
float SVGRect::X() {
|
||||
switch (mType) {
|
||||
case AnimValue:
|
||||
static_cast<SVGElement*>(mParent->AsElement())->FlushAnimations();
|
||||
return mVal->GetAnimValue().x;
|
||||
case BaseValue:
|
||||
return mVal->GetBaseValue().x;
|
||||
default:
|
||||
return mRect.x;
|
||||
}
|
||||
}
|
||||
|
||||
float SVGRect::Y() {
|
||||
switch (mType) {
|
||||
case AnimValue:
|
||||
static_cast<SVGElement*>(mParent->AsElement())->FlushAnimations();
|
||||
return mVal->GetAnimValue().y;
|
||||
case BaseValue:
|
||||
return mVal->GetBaseValue().y;
|
||||
default:
|
||||
return mRect.y;
|
||||
}
|
||||
}
|
||||
|
||||
float SVGRect::Width() {
|
||||
switch (mType) {
|
||||
case AnimValue:
|
||||
static_cast<SVGElement*>(mParent->AsElement())->FlushAnimations();
|
||||
return mVal->GetAnimValue().width;
|
||||
case BaseValue:
|
||||
return mVal->GetBaseValue().width;
|
||||
default:
|
||||
return mRect.width;
|
||||
}
|
||||
}
|
||||
|
||||
float SVGRect::Height() {
|
||||
switch (mType) {
|
||||
case AnimValue:
|
||||
static_cast<SVGElement*>(mParent->AsElement())->FlushAnimations();
|
||||
return mVal->GetAnimValue().height;
|
||||
case BaseValue:
|
||||
return mVal->GetBaseValue().height;
|
||||
default:
|
||||
return mRect.height;
|
||||
}
|
||||
}
|
||||
|
||||
void SVGRect::SetX(float aX, ErrorResult& aRv) {
|
||||
switch (mType) {
|
||||
case AnimValue:
|
||||
aRv.Throw(NS_ERROR_DOM_NO_MODIFICATION_ALLOWED_ERR);
|
||||
return;
|
||||
case BaseValue: {
|
||||
SVGViewBox rect = mVal->GetBaseValue();
|
||||
rect.x = aX;
|
||||
mVal->SetBaseValue(rect, static_cast<SVGElement*>(mParent->AsElement()));
|
||||
return;
|
||||
}
|
||||
default:
|
||||
mRect.x = aX;
|
||||
}
|
||||
}
|
||||
|
||||
void SVGRect::SetY(float aY, ErrorResult& aRv) {
|
||||
switch (mType) {
|
||||
case AnimValue:
|
||||
aRv.Throw(NS_ERROR_DOM_NO_MODIFICATION_ALLOWED_ERR);
|
||||
return;
|
||||
case BaseValue: {
|
||||
SVGViewBox rect = mVal->GetBaseValue();
|
||||
rect.y = aY;
|
||||
mVal->SetBaseValue(rect, static_cast<SVGElement*>(mParent->AsElement()));
|
||||
return;
|
||||
}
|
||||
default:
|
||||
mRect.y = aY;
|
||||
}
|
||||
}
|
||||
|
||||
void SVGRect::SetWidth(float aWidth, ErrorResult& aRv) {
|
||||
switch (mType) {
|
||||
case AnimValue:
|
||||
aRv.Throw(NS_ERROR_DOM_NO_MODIFICATION_ALLOWED_ERR);
|
||||
return;
|
||||
case BaseValue: {
|
||||
SVGViewBox rect = mVal->GetBaseValue();
|
||||
rect.width = aWidth;
|
||||
mVal->SetBaseValue(rect, static_cast<SVGElement*>(mParent->AsElement()));
|
||||
return;
|
||||
}
|
||||
default:
|
||||
mRect.width = aWidth;
|
||||
}
|
||||
}
|
||||
|
||||
void SVGRect::SetHeight(float aHeight, ErrorResult& aRv) {
|
||||
switch (mType) {
|
||||
case AnimValue:
|
||||
aRv.Throw(NS_ERROR_DOM_NO_MODIFICATION_ALLOWED_ERR);
|
||||
return;
|
||||
case BaseValue: {
|
||||
SVGViewBox rect = mVal->GetBaseValue();
|
||||
rect.height = aHeight;
|
||||
mVal->SetBaseValue(rect, static_cast<SVGElement*>(mParent->AsElement()));
|
||||
return;
|
||||
}
|
||||
default:
|
||||
mRect.height = aHeight;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
// Exported creation functions:
|
||||
|
||||
already_AddRefed<mozilla::dom::SVGRect> NS_NewSVGRect(nsIContent* aParent,
|
||||
float aX, float aY,
|
||||
float aWidth,
|
||||
float aHeight) {
|
||||
RefPtr<mozilla::dom::SVGRect> rect =
|
||||
new mozilla::dom::SVGRect(aParent, aX, aY, aWidth, aHeight);
|
||||
|
||||
return rect.forget();
|
||||
}
|
||||
|
||||
already_AddRefed<mozilla::dom::SVGRect> NS_NewSVGRect(nsIContent* aParent,
|
||||
const Rect& aRect) {
|
||||
return NS_NewSVGRect(aParent, aRect.x, aRect.y, aRect.width, aRect.height);
|
||||
}
|
||||
|
|
|
@ -7,10 +7,8 @@
|
|||
#ifndef mozilla_dom_SVGRect_h
|
||||
#define mozilla_dom_SVGRect_h
|
||||
|
||||
#include "mozilla/dom/SVGIRect.h"
|
||||
#include "mozilla/dom/SVGElement.h"
|
||||
#include "mozilla/gfx/Rect.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "SVGElement.h"
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
// SVGRect class
|
||||
|
@ -18,50 +16,71 @@
|
|||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
class SVGRect final : public SVGIRect {
|
||||
class SVGSVGElement;
|
||||
|
||||
class SVGRect final : public nsISupports, public nsWrapperCache {
|
||||
public:
|
||||
explicit SVGRect(nsIContent* aParent, float x = 0.0f, float y = 0.0f,
|
||||
float w = 0.0f, float h = 0.0f);
|
||||
typedef enum { BaseValue, AnimValue, CreatedValue } RectType;
|
||||
|
||||
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
|
||||
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(SVGRect)
|
||||
|
||||
// WebIDL
|
||||
float X() const final { return mX; }
|
||||
/**
|
||||
* Generic ctor for objects that are created for an attribute.
|
||||
*/
|
||||
SVGRect(SVGAnimatedViewBox* aVal, SVGElement* aSVGElement, RectType aType)
|
||||
: mVal(aVal), mParent(aSVGElement), mType(aType) {
|
||||
MOZ_ASSERT(mParent);
|
||||
MOZ_ASSERT(mType == BaseValue || mType == AnimValue);
|
||||
}
|
||||
|
||||
void SetX(float aX, ErrorResult& aRv) final { mX = aX; }
|
||||
/**
|
||||
* Ctor for creating the objects returned by SVGSVGElement.createSVGRect(),
|
||||
* which do not initially belong to an attribute.
|
||||
*/
|
||||
explicit SVGRect(SVGSVGElement* aSVGElement);
|
||||
|
||||
float Y() const final { return mY; }
|
||||
/**
|
||||
* Ctor for all other non-attribute usage i.e getBBox, getExtentOfChar etc.
|
||||
*/
|
||||
SVGRect(nsIContent* aParent, const gfx::Rect& aRect)
|
||||
: mVal(nullptr), mRect(aRect), mParent(aParent), mType(CreatedValue) {
|
||||
MOZ_ASSERT(mParent);
|
||||
}
|
||||
|
||||
void SetY(float aY, ErrorResult& aRv) final { mY = aY; }
|
||||
JSObject* WrapObject(JSContext* aCx,
|
||||
JS::Handle<JSObject*> aGivenProto) override;
|
||||
|
||||
float Width() const final { return mWidth; }
|
||||
float X();
|
||||
float Y();
|
||||
float Width();
|
||||
float Height();
|
||||
|
||||
void SetWidth(float aWidth, ErrorResult& aRv) final { mWidth = aWidth; }
|
||||
void SetX(float aX, mozilla::ErrorResult& aRv);
|
||||
void SetY(float aY, mozilla::ErrorResult& aRv);
|
||||
void SetWidth(float aWidth, mozilla::ErrorResult& aRv);
|
||||
void SetHeight(float aHeight, mozilla::ErrorResult& aRv);
|
||||
|
||||
float Height() const final { return mHeight; }
|
||||
nsIContent* GetParentObject() const {
|
||||
MOZ_ASSERT(mParent);
|
||||
return mParent;
|
||||
}
|
||||
|
||||
void SetHeight(float aHeight, ErrorResult& aRv) final { mHeight = aHeight; }
|
||||
private:
|
||||
virtual ~SVGRect();
|
||||
|
||||
virtual nsIContent* GetParentObject() const override { return mParent; }
|
||||
// If we're actually representing a viewBox rect then our value
|
||||
// will come from that element's viewBox attribute's value.
|
||||
SVGAnimatedViewBox* mVal; // kept alive because it belongs to content
|
||||
gfx::Rect mRect;
|
||||
|
||||
protected:
|
||||
~SVGRect() = default;
|
||||
|
||||
nsCOMPtr<nsIContent> mParent;
|
||||
float mX, mY, mWidth, mHeight;
|
||||
// If mType is AnimValue or BaseValue this will be an element that
|
||||
// has a viewBox, otherwise it could be any nsIContent.
|
||||
RefPtr<nsIContent> mParent;
|
||||
const RectType mType;
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
already_AddRefed<mozilla::dom::SVGRect> NS_NewSVGRect(nsIContent* aParent,
|
||||
float x = 0.0f,
|
||||
float y = 0.0f,
|
||||
float width = 0.0f,
|
||||
float height = 0.0f);
|
||||
|
||||
already_AddRefed<mozilla::dom::SVGRect> NS_NewSVGRect(
|
||||
nsIContent* aParent, const mozilla::gfx::Rect& rect);
|
||||
|
||||
#endif // mozilla_dom_SVGRect_h
|
||||
|
|
|
@ -270,8 +270,8 @@ already_AddRefed<SVGMatrix> SVGSVGElement::CreateSVGMatrix() {
|
|||
return do_AddRef(new SVGMatrix());
|
||||
}
|
||||
|
||||
already_AddRefed<SVGIRect> SVGSVGElement::CreateSVGRect() {
|
||||
return NS_NewSVGRect(this);
|
||||
already_AddRefed<SVGRect> SVGSVGElement::CreateSVGRect() {
|
||||
return do_AddRef(new SVGRect(this));
|
||||
}
|
||||
|
||||
already_AddRefed<DOMSVGTransform> SVGSVGElement::CreateSVGTransform() {
|
||||
|
|
|
@ -25,7 +25,7 @@ class DOMSVGAngle;
|
|||
class DOMSVGLength;
|
||||
class DOMSVGNumber;
|
||||
class SVGMatrix;
|
||||
class SVGIRect;
|
||||
class SVGRect;
|
||||
class SVGSVGElement;
|
||||
|
||||
// Stores svgView arguments of SVG fragment identifiers.
|
||||
|
@ -137,7 +137,7 @@ class SVGSVGElement final : public SVGSVGElementBase {
|
|||
already_AddRefed<DOMSVGAngle> CreateSVGAngle();
|
||||
already_AddRefed<nsISVGPoint> CreateSVGPoint();
|
||||
already_AddRefed<SVGMatrix> CreateSVGMatrix();
|
||||
already_AddRefed<SVGIRect> CreateSVGRect();
|
||||
already_AddRefed<SVGRect> CreateSVGRect();
|
||||
already_AddRefed<DOMSVGTransform> CreateSVGTransform();
|
||||
already_AddRefed<DOMSVGTransform> CreateSVGTransformFromMatrix(
|
||||
SVGMatrix& matrix);
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
|
||||
#include "mozilla/dom/SVGLengthBinding.h"
|
||||
#include "mozilla/dom/SVGTextContentElementBinding.h"
|
||||
#include "mozilla/dom/SVGIRect.h"
|
||||
#include "mozilla/dom/SVGRect.h"
|
||||
#include "nsBidiUtils.h"
|
||||
#include "nsISVGPoint.h"
|
||||
#include "nsTextFragment.h"
|
||||
|
@ -163,7 +163,7 @@ already_AddRefed<nsISVGPoint> SVGTextContentElement::GetEndPositionOfChar(
|
|||
return point.forget();
|
||||
}
|
||||
|
||||
already_AddRefed<SVGIRect> SVGTextContentElement::GetExtentOfChar(
|
||||
already_AddRefed<SVGRect> SVGTextContentElement::GetExtentOfChar(
|
||||
uint32_t charnum, ErrorResult& rv) {
|
||||
SVGTextFrame* textFrame = GetSVGTextFrame();
|
||||
|
||||
|
@ -172,7 +172,7 @@ already_AddRefed<SVGIRect> SVGTextContentElement::GetExtentOfChar(
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
RefPtr<SVGIRect> rect;
|
||||
RefPtr<SVGRect> rect;
|
||||
rv = textFrame->GetExtentOfChar(this, charnum, getter_AddRefs(rect));
|
||||
return rect.forget();
|
||||
}
|
||||
|
|
|
@ -20,7 +20,7 @@ class nsISVGPoint;
|
|||
namespace dom {
|
||||
|
||||
struct DOMPointInit;
|
||||
class SVGIRect;
|
||||
class SVGRect;
|
||||
|
||||
typedef SVGGraphicsElement SVGTextContentElementBase;
|
||||
|
||||
|
@ -46,7 +46,7 @@ class SVGTextContentElement : public SVGTextContentElementBase {
|
|||
already_AddRefed<nsISVGPoint> GetEndPositionOfChar(uint32_t charnum,
|
||||
ErrorResult& rv);
|
||||
MOZ_CAN_RUN_SCRIPT
|
||||
already_AddRefed<SVGIRect> GetExtentOfChar(uint32_t charnum, ErrorResult& rv);
|
||||
already_AddRefed<SVGRect> GetExtentOfChar(uint32_t charnum, ErrorResult& rv);
|
||||
MOZ_CAN_RUN_SCRIPT float GetRotationOfChar(uint32_t charnum, ErrorResult& rv);
|
||||
MOZ_CAN_RUN_SCRIPT int32_t GetCharNumAtPosition(const DOMPointInit& aPoint);
|
||||
|
||||
|
|
|
@ -156,7 +156,7 @@ SVGElement* SVGTransformableElement::GetFarthestViewportElement() {
|
|||
return SVGContentUtils::GetOuterSVGElement(this);
|
||||
}
|
||||
|
||||
already_AddRefed<SVGIRect> SVGTransformableElement::GetBBox(
|
||||
already_AddRefed<SVGRect> SVGTransformableElement::GetBBox(
|
||||
const SVGBoundingBoxOptions& aOptions, ErrorResult& rv) {
|
||||
nsIFrame* frame = GetPrimaryFrame(FlushType::Layout);
|
||||
|
||||
|
@ -199,14 +199,14 @@ already_AddRefed<SVGIRect> SVGTransformableElement::GetBBox(
|
|||
rec.x += float(text->GetPosition().x) / AppUnitsPerCSSPixel();
|
||||
rec.y += float(text->GetPosition().y) / AppUnitsPerCSSPixel();
|
||||
|
||||
return NS_NewSVGRect(this, ToRect(rec));
|
||||
return do_AddRef(new SVGRect(this, ToRect(rec)));
|
||||
}
|
||||
|
||||
if (!NS_SVGNewGetBBoxEnabled()) {
|
||||
return NS_NewSVGRect(
|
||||
return do_AddRef(new SVGRect(
|
||||
this, ToRect(nsSVGUtils::GetBBox(
|
||||
frame, nsSVGUtils::eBBoxIncludeFillGeometry |
|
||||
nsSVGUtils::eUseUserSpaceOfUseElement)));
|
||||
nsSVGUtils::eUseUserSpaceOfUseElement))));
|
||||
}
|
||||
uint32_t flags = 0;
|
||||
if (aOptions.mFill) {
|
||||
|
@ -222,14 +222,15 @@ already_AddRefed<SVGIRect> SVGTransformableElement::GetBBox(
|
|||
flags |= nsSVGUtils::eBBoxIncludeClipped;
|
||||
}
|
||||
if (flags == 0) {
|
||||
return NS_NewSVGRect(this, 0, 0, 0, 0);
|
||||
return do_AddRef(new SVGRect(this, gfx::Rect()));
|
||||
}
|
||||
if (flags == nsSVGUtils::eBBoxIncludeMarkers ||
|
||||
flags == nsSVGUtils::eBBoxIncludeClipped) {
|
||||
flags |= nsSVGUtils::eBBoxIncludeFill;
|
||||
}
|
||||
flags |= nsSVGUtils::eUseUserSpaceOfUseElement;
|
||||
return NS_NewSVGRect(this, ToRect(nsSVGUtils::GetBBox(frame, flags)));
|
||||
return do_AddRef(
|
||||
new SVGRect(this, ToRect(nsSVGUtils::GetBBox(frame, flags))));
|
||||
}
|
||||
|
||||
already_AddRefed<SVGMatrix> SVGTransformableElement::GetCTM() {
|
||||
|
|
|
@ -20,7 +20,7 @@ namespace dom {
|
|||
class DOMSVGAnimatedTransformList;
|
||||
class SVGGraphicsElement;
|
||||
class SVGMatrix;
|
||||
class SVGIRect;
|
||||
class SVGRect;
|
||||
struct SVGBoundingBoxOptions;
|
||||
|
||||
class SVGTransformableElement : public SVGElement {
|
||||
|
@ -36,8 +36,8 @@ class SVGTransformableElement : public SVGElement {
|
|||
SVGElement* GetNearestViewportElement();
|
||||
SVGElement* GetFarthestViewportElement();
|
||||
MOZ_CAN_RUN_SCRIPT
|
||||
already_AddRefed<SVGIRect> GetBBox(const SVGBoundingBoxOptions& aOptions,
|
||||
ErrorResult& rv);
|
||||
already_AddRefed<SVGRect> GetBBox(const SVGBoundingBoxOptions& aOptions,
|
||||
ErrorResult& rv);
|
||||
already_AddRefed<SVGMatrix> GetCTM();
|
||||
already_AddRefed<SVGMatrix> GetScreenCTM();
|
||||
already_AddRefed<SVGMatrix> GetTransformToElement(
|
||||
|
|
|
@ -62,7 +62,6 @@ EXPORTS.mozilla.dom += [
|
|||
'SVGGradientElement.h',
|
||||
'SVGGraphicsElement.h',
|
||||
'SVGImageElement.h',
|
||||
'SVGIRect.h',
|
||||
'SVGLineElement.h',
|
||||
'SVGMarkerElement.h',
|
||||
'SVGMaskElement.h',
|
||||
|
|
|
@ -210,9 +210,8 @@ void brush_vs(
|
|||
|
||||
#ifdef WR_FRAGMENT_SHADER
|
||||
|
||||
Fragment brush_fs() {
|
||||
vec2 compute_repeated_uvs(float perspective_divisor) {
|
||||
vec2 uv_size = vUvBounds.zw - vUvBounds.xy;
|
||||
float perspective_divisor = mix(gl_FragCoord.w, 1.0, vLayerAndPerspective.y);
|
||||
|
||||
#ifdef WR_FEATURE_ALPHA_PASS
|
||||
// This prevents the uv on the top and left parts of the primitive that was inflated
|
||||
|
@ -233,10 +232,21 @@ Fragment brush_fs() {
|
|||
repeated_uv.y = vUvBounds.w;
|
||||
}
|
||||
#else
|
||||
// Handle horizontal and vertical repetitions.
|
||||
vec2 repeated_uv = mod(vUv * perspective_divisor, uv_size) + vUvBounds.xy;
|
||||
#endif
|
||||
|
||||
return repeated_uv;
|
||||
}
|
||||
|
||||
Fragment brush_fs() {
|
||||
float perspective_divisor = mix(gl_FragCoord.w, 1.0, vLayerAndPerspective.y);
|
||||
|
||||
#ifdef WR_FEATURE_REPETITION
|
||||
vec2 repeated_uv = compute_repeated_uvs(perspective_divisor);
|
||||
#else
|
||||
vec2 repeated_uv = vUv * perspective_divisor + vUvBounds.xy;
|
||||
#endif
|
||||
|
||||
// Clamp the uvs to avoid sampling artifacts.
|
||||
vec2 uv = clamp(repeated_uv, vUvSampleBounds.xy, vUvSampleBounds.zw);
|
||||
|
||||
|
@ -245,7 +255,11 @@ Fragment brush_fs() {
|
|||
Fragment frag;
|
||||
|
||||
#ifdef WR_FEATURE_ALPHA_PASS
|
||||
float alpha = init_transform_fs(vLocalPos);
|
||||
#ifdef WR_FEATURE_ANTIALIASING
|
||||
float alpha = init_transform_fs(vLocalPos);
|
||||
#else
|
||||
float alpha = 1.0;
|
||||
#endif
|
||||
texel.rgb = texel.rgb * vMaskSwizzle.x + texel.aaa * vMaskSwizzle.y;
|
||||
|
||||
vec4 alpha_mask = texel * alpha;
|
||||
|
|
|
@ -157,6 +157,7 @@ impl AlphaBatchList {
|
|||
pub fn set_params_and_get_batch(
|
||||
&mut self,
|
||||
key: BatchKey,
|
||||
features: BatchFeatures,
|
||||
// The bounding box of everything at this Z plane. We expect potentially
|
||||
// multiple primitive segments coming with the same `z_id`.
|
||||
z_bounding_rect: &PictureRect,
|
||||
|
@ -226,7 +227,10 @@ impl AlphaBatchList {
|
|||
assert_eq!(self.item_rects[self.current_batch_index].last(), Some(z_bounding_rect));
|
||||
}
|
||||
|
||||
&mut self.batches[self.current_batch_index].instances
|
||||
let batch = &mut self.batches[self.current_batch_index];
|
||||
batch.features |= features;
|
||||
|
||||
&mut batch.instances
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -250,6 +254,7 @@ impl OpaqueBatchList {
|
|||
pub fn set_params_and_get_batch(
|
||||
&mut self,
|
||||
key: BatchKey,
|
||||
features: BatchFeatures,
|
||||
// The bounding box of everything at the current Z, whatever it is. We expect potentially
|
||||
// multiple primitive segments produced by a primitive, which we allow to check
|
||||
// `current_batch_index` instead of iterating the batches.
|
||||
|
@ -289,7 +294,10 @@ impl OpaqueBatchList {
|
|||
self.current_batch_index = selected_batch_index.unwrap();
|
||||
}
|
||||
|
||||
&mut self.batches[self.current_batch_index].instances
|
||||
let batch = &mut self.batches[self.current_batch_index];
|
||||
batch.features |= features;
|
||||
|
||||
&mut batch.instances
|
||||
}
|
||||
|
||||
fn finalize(&mut self) {
|
||||
|
@ -310,6 +318,25 @@ impl OpaqueBatchList {
|
|||
pub struct PrimitiveBatch {
|
||||
pub key: BatchKey,
|
||||
pub instances: Vec<PrimitiveInstanceData>,
|
||||
pub features: BatchFeatures,
|
||||
}
|
||||
|
||||
bitflags! {
|
||||
/// Features of the batch that, if not requested, may allow a fast-path.
|
||||
///
|
||||
/// Rather than breaking batches when primitives request different features,
|
||||
/// we always request the minimum amount of features to satisfy all items in
|
||||
/// the batch.
|
||||
/// The goal is to let the renderer be optionally select more specialized
|
||||
/// versions of a shader if the batch doesn't require code certain code paths.
|
||||
/// Not all shaders necessarily implement all of these features.
|
||||
#[cfg_attr(feature = "capture", derive(Serialize))]
|
||||
#[cfg_attr(feature = "replay", derive(Deserialize))]
|
||||
pub struct BatchFeatures: u8 {
|
||||
const ALPHA_PASS = 1 << 0;
|
||||
const ANTIALIASING = 1 << 1;
|
||||
const REPETITION = 1 << 2;
|
||||
}
|
||||
}
|
||||
|
||||
impl PrimitiveBatch {
|
||||
|
@ -317,6 +344,7 @@ impl PrimitiveBatch {
|
|||
PrimitiveBatch {
|
||||
key,
|
||||
instances: Vec::new(),
|
||||
features: BatchFeatures::empty(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -454,24 +482,26 @@ impl AlphaBatchBuilder {
|
|||
pub fn push_single_instance(
|
||||
&mut self,
|
||||
key: BatchKey,
|
||||
features: BatchFeatures,
|
||||
bounding_rect: &PictureRect,
|
||||
z_id: ZBufferId,
|
||||
instance: PrimitiveInstanceData,
|
||||
) {
|
||||
self.set_params_and_get_batch(key, bounding_rect, z_id)
|
||||
self.set_params_and_get_batch(key, features, bounding_rect, z_id)
|
||||
.push(instance);
|
||||
}
|
||||
|
||||
pub fn set_params_and_get_batch(
|
||||
&mut self,
|
||||
key: BatchKey,
|
||||
features: BatchFeatures,
|
||||
bounding_rect: &PictureRect,
|
||||
z_id: ZBufferId,
|
||||
) -> &mut Vec<PrimitiveInstanceData> {
|
||||
match key.blend_mode {
|
||||
BlendMode::None => {
|
||||
self.opaque_batch_list
|
||||
.set_params_and_get_batch(key, bounding_rect)
|
||||
.set_params_and_get_batch(key, features, bounding_rect)
|
||||
}
|
||||
BlendMode::Alpha |
|
||||
BlendMode::PremultipliedAlpha |
|
||||
|
@ -481,7 +511,7 @@ impl AlphaBatchBuilder {
|
|||
BlendMode::SubpixelDualSource |
|
||||
BlendMode::Advanced(_) => {
|
||||
self.alpha_batch_list
|
||||
.set_params_and_get_batch(key, bounding_rect, z_id)
|
||||
.set_params_and_get_batch(key, features, bounding_rect, z_id)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -513,6 +543,7 @@ impl BatchBuilder {
|
|||
fn add_brush_instance_to_batches(
|
||||
&mut self,
|
||||
batch_key: BatchKey,
|
||||
features: BatchFeatures,
|
||||
bounding_rect: &PictureRect,
|
||||
z_id: ZBufferId,
|
||||
segment_index: i32,
|
||||
|
@ -539,6 +570,7 @@ impl BatchBuilder {
|
|||
|
||||
batcher.push_single_instance(
|
||||
batch_key,
|
||||
features,
|
||||
bounding_rect,
|
||||
z_id,
|
||||
PrimitiveInstanceData::from(instance),
|
||||
|
@ -562,6 +594,7 @@ impl BatchBuilder {
|
|||
|
||||
batcher.push_single_instance(
|
||||
batch_key,
|
||||
BatchFeatures::empty(),
|
||||
bounding_rect,
|
||||
z_id,
|
||||
PrimitiveInstanceData::from(SplitCompositeInstance {
|
||||
|
@ -654,6 +687,15 @@ impl BatchBuilder {
|
|||
prim_common_data.prim_size,
|
||||
);
|
||||
|
||||
let mut batch_features = BatchFeatures::empty();
|
||||
if prim_common_data.may_need_repetition {
|
||||
batch_features |= BatchFeatures::REPETITION;
|
||||
}
|
||||
|
||||
if transform_kind != TransformedRectKind::AxisAligned {
|
||||
batch_features |= BatchFeatures::ANTIALIASING;
|
||||
}
|
||||
|
||||
let snap_offsets = prim_info.snap_offsets;
|
||||
let prim_vis_mask = prim_info.visibility_mask;
|
||||
|
||||
|
@ -705,6 +747,7 @@ impl BatchBuilder {
|
|||
|
||||
self.add_brush_instance_to_batches(
|
||||
batch_key,
|
||||
batch_features,
|
||||
bounding_rect,
|
||||
z_id,
|
||||
INVALID_SEGMENT_INDEX,
|
||||
|
@ -781,6 +824,7 @@ impl BatchBuilder {
|
|||
&batch_params,
|
||||
specified_blend_mode,
|
||||
non_segmented_blend_mode,
|
||||
batch_features,
|
||||
prim_header_index,
|
||||
bounding_rect,
|
||||
transform_kind,
|
||||
|
@ -907,6 +951,7 @@ impl BatchBuilder {
|
|||
let render_task_address = batcher.render_task_address;
|
||||
let batch = batcher.alpha_batch_list.set_params_and_get_batch(
|
||||
key,
|
||||
BatchFeatures::empty(),
|
||||
bounding_rect,
|
||||
z_id,
|
||||
);
|
||||
|
@ -1001,6 +1046,7 @@ impl BatchBuilder {
|
|||
|
||||
self.add_brush_instance_to_batches(
|
||||
batch_key,
|
||||
batch_features,
|
||||
bounding_rect,
|
||||
z_id,
|
||||
INVALID_SEGMENT_INDEX,
|
||||
|
@ -1177,6 +1223,7 @@ impl BatchBuilder {
|
|||
&batch_params,
|
||||
blend_mode,
|
||||
blend_mode,
|
||||
batch_features,
|
||||
prim_header_index,
|
||||
bounding_rect,
|
||||
transform_kind,
|
||||
|
@ -1213,6 +1260,7 @@ impl BatchBuilder {
|
|||
|
||||
self.add_brush_instance_to_batches(
|
||||
key,
|
||||
batch_features,
|
||||
bounding_rect,
|
||||
z_id,
|
||||
INVALID_SEGMENT_INDEX,
|
||||
|
@ -1284,6 +1332,7 @@ impl BatchBuilder {
|
|||
|
||||
self.add_brush_instance_to_batches(
|
||||
shadow_key,
|
||||
batch_features,
|
||||
bounding_rect,
|
||||
z_id,
|
||||
INVALID_SEGMENT_INDEX,
|
||||
|
@ -1306,6 +1355,7 @@ impl BatchBuilder {
|
|||
|
||||
self.add_brush_instance_to_batches(
|
||||
content_key,
|
||||
batch_features,
|
||||
bounding_rect,
|
||||
z_id_content,
|
||||
INVALID_SEGMENT_INDEX,
|
||||
|
@ -1386,6 +1436,7 @@ impl BatchBuilder {
|
|||
|
||||
self.add_brush_instance_to_batches(
|
||||
key,
|
||||
batch_features,
|
||||
bounding_rect,
|
||||
z_id,
|
||||
INVALID_SEGMENT_INDEX,
|
||||
|
@ -1432,6 +1483,7 @@ impl BatchBuilder {
|
|||
|
||||
self.add_brush_instance_to_batches(
|
||||
key,
|
||||
batch_features,
|
||||
bounding_rect,
|
||||
z_id,
|
||||
INVALID_SEGMENT_INDEX,
|
||||
|
@ -1464,6 +1516,7 @@ impl BatchBuilder {
|
|||
|
||||
self.add_brush_instance_to_batches(
|
||||
key,
|
||||
batch_features,
|
||||
bounding_rect,
|
||||
z_id,
|
||||
INVALID_SEGMENT_INDEX,
|
||||
|
@ -1506,6 +1559,7 @@ impl BatchBuilder {
|
|||
|
||||
self.add_brush_instance_to_batches(
|
||||
key,
|
||||
batch_features,
|
||||
bounding_rect,
|
||||
z_id,
|
||||
INVALID_SEGMENT_INDEX,
|
||||
|
@ -1575,6 +1629,7 @@ impl BatchBuilder {
|
|||
&batch_params,
|
||||
specified_blend_mode,
|
||||
non_segmented_blend_mode,
|
||||
batch_features,
|
||||
prim_header_index,
|
||||
bounding_rect,
|
||||
transform_kind,
|
||||
|
@ -1664,6 +1719,7 @@ impl BatchBuilder {
|
|||
&batch_params,
|
||||
specified_blend_mode,
|
||||
non_segmented_blend_mode,
|
||||
batch_features,
|
||||
prim_header_index,
|
||||
bounding_rect,
|
||||
transform_kind,
|
||||
|
@ -1726,6 +1782,7 @@ impl BatchBuilder {
|
|||
&batch_params,
|
||||
specified_blend_mode,
|
||||
non_segmented_blend_mode,
|
||||
batch_features,
|
||||
prim_header_index,
|
||||
bounding_rect,
|
||||
transform_kind,
|
||||
|
@ -1834,6 +1891,7 @@ impl BatchBuilder {
|
|||
&batch_params,
|
||||
specified_blend_mode,
|
||||
non_segmented_blend_mode,
|
||||
batch_features,
|
||||
prim_header_index,
|
||||
bounding_rect,
|
||||
transform_kind,
|
||||
|
@ -1939,6 +1997,7 @@ impl BatchBuilder {
|
|||
&batch_params,
|
||||
specified_blend_mode,
|
||||
non_segmented_blend_mode,
|
||||
batch_features,
|
||||
prim_header_index,
|
||||
bounding_rect,
|
||||
transform_kind,
|
||||
|
@ -1995,6 +2054,7 @@ impl BatchBuilder {
|
|||
};
|
||||
self.add_brush_instance_to_batches(
|
||||
batch_key,
|
||||
batch_features,
|
||||
bounding_rect,
|
||||
z_id,
|
||||
i as i32,
|
||||
|
@ -2072,6 +2132,7 @@ impl BatchBuilder {
|
|||
|
||||
self.add_brush_instance_to_batches(
|
||||
batch_key,
|
||||
batch_features,
|
||||
bounding_rect,
|
||||
z_id,
|
||||
INVALID_SEGMENT_INDEX,
|
||||
|
@ -2115,6 +2176,7 @@ impl BatchBuilder {
|
|||
&batch_params,
|
||||
specified_blend_mode,
|
||||
non_segmented_blend_mode,
|
||||
batch_features,
|
||||
prim_header_index,
|
||||
bounding_rect,
|
||||
transform_kind,
|
||||
|
@ -2201,6 +2263,7 @@ impl BatchBuilder {
|
|||
&batch_params,
|
||||
specified_blend_mode,
|
||||
non_segmented_blend_mode,
|
||||
batch_features,
|
||||
prim_header_index,
|
||||
bounding_rect,
|
||||
transform_kind,
|
||||
|
@ -2245,6 +2308,7 @@ impl BatchBuilder {
|
|||
batch_kind: BrushBatchKind,
|
||||
prim_header_index: PrimitiveHeaderIndex,
|
||||
alpha_blend_mode: BlendMode,
|
||||
features: BatchFeatures,
|
||||
bounding_rect: &PictureRect,
|
||||
transform_kind: TransformedRectKind,
|
||||
render_tasks: &RenderTaskGraph,
|
||||
|
@ -2281,6 +2345,7 @@ impl BatchBuilder {
|
|||
|
||||
self.add_brush_instance_to_batches(
|
||||
batch_key,
|
||||
features,
|
||||
bounding_rect,
|
||||
z_id,
|
||||
segment_index,
|
||||
|
@ -2301,6 +2366,7 @@ impl BatchBuilder {
|
|||
params: &BrushBatchParameters,
|
||||
alpha_blend_mode: BlendMode,
|
||||
non_segmented_blend_mode: BlendMode,
|
||||
features: BatchFeatures,
|
||||
prim_header_index: PrimitiveHeaderIndex,
|
||||
bounding_rect: &PictureRect,
|
||||
transform_kind: TransformedRectKind,
|
||||
|
@ -2327,6 +2393,7 @@ impl BatchBuilder {
|
|||
params.batch_kind,
|
||||
prim_header_index,
|
||||
alpha_blend_mode,
|
||||
features,
|
||||
bounding_rect,
|
||||
transform_kind,
|
||||
render_tasks,
|
||||
|
@ -2352,6 +2419,7 @@ impl BatchBuilder {
|
|||
params.batch_kind,
|
||||
prim_header_index,
|
||||
alpha_blend_mode,
|
||||
features,
|
||||
bounding_rect,
|
||||
transform_kind,
|
||||
render_tasks,
|
||||
|
@ -2377,6 +2445,7 @@ impl BatchBuilder {
|
|||
).unwrap_or(OPAQUE_TASK_ADDRESS);
|
||||
self.add_brush_instance_to_batches(
|
||||
batch_key,
|
||||
features,
|
||||
bounding_rect,
|
||||
z_id,
|
||||
INVALID_SEGMENT_INDEX,
|
||||
|
@ -2437,6 +2506,7 @@ impl BatchBuilder {
|
|||
|
||||
self.add_brush_instance_to_batches(
|
||||
key,
|
||||
BatchFeatures::empty(),
|
||||
bounding_rect,
|
||||
z_id,
|
||||
INVALID_SEGMENT_INDEX,
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
use api::{BorderRadius, ClipMode, ColorF};
|
||||
use api::{ImageRendering, RepeatMode};
|
||||
use api::{PremultipliedColorF, PropertyBinding, Shadow, GradientStop};
|
||||
use api::{BoxShadowClipMode, LineStyle, LineOrientation};
|
||||
use api::{BoxShadowClipMode, LineStyle, LineOrientation, BorderStyle};
|
||||
use api::{PrimitiveKeyKind};
|
||||
use api::units::*;
|
||||
use crate::border::{get_max_scale_for_border, build_border_instances};
|
||||
|
@ -650,6 +650,7 @@ impl From<PrimitiveKeyKind> for PrimitiveTemplateKind {
|
|||
#[derive(MallocSizeOf)]
|
||||
pub struct PrimTemplateCommonData {
|
||||
pub is_backface_visible: bool,
|
||||
pub may_need_repetition: bool,
|
||||
pub prim_size: LayoutSize,
|
||||
pub opacity: PrimitiveOpacity,
|
||||
/// The GPU cache handle for a primitive template. Since this structure
|
||||
|
@ -663,6 +664,7 @@ impl PrimTemplateCommonData {
|
|||
pub fn with_key_common(common: PrimKeyCommonData) -> Self {
|
||||
PrimTemplateCommonData {
|
||||
is_backface_visible: common.is_backface_visible,
|
||||
may_need_repetition: true,
|
||||
prim_size: common.prim_size.into(),
|
||||
gpu_cache_handle: GpuCacheHandle::new(),
|
||||
opacity: PrimitiveOpacity::translucent(),
|
||||
|
@ -2334,6 +2336,7 @@ impl PrimitiveStore {
|
|||
|
||||
match image_properties {
|
||||
Some(ImageProperties { tiling: None, .. }) => {
|
||||
|
||||
frame_state.resource_cache.request_image(
|
||||
request,
|
||||
frame_state.gpu_cache,
|
||||
|
@ -2373,6 +2376,10 @@ impl PrimitiveStore {
|
|||
|
||||
let stride = image_data.stretch_size + image_data.tile_spacing;
|
||||
|
||||
// We are performing the decomposition on the CPU here, no need to
|
||||
// have it in the shader.
|
||||
common_data.may_need_repetition = false;
|
||||
|
||||
let repetitions = crate::image::repetitions(
|
||||
&prim_rect,
|
||||
&visible_rect,
|
||||
|
@ -2819,6 +2826,8 @@ impl PrimitiveStore {
|
|||
let prim_data = &mut data_stores.text_run[*data_handle];
|
||||
let run = &mut self.text_runs[*run_index];
|
||||
|
||||
prim_data.common.may_need_repetition = false;
|
||||
|
||||
// The transform only makes sense for screen space rasterization
|
||||
let relative_transform = frame_context
|
||||
.clip_scroll_tree
|
||||
|
@ -2851,6 +2860,8 @@ impl PrimitiveStore {
|
|||
PrimitiveInstanceKind::Clear { data_handle, .. } => {
|
||||
let prim_data = &mut data_stores.prim[*data_handle];
|
||||
|
||||
prim_data.common.may_need_repetition = false;
|
||||
|
||||
// Update the template this instane references, which may refresh the GPU
|
||||
// cache with any shared template data.
|
||||
prim_data.update(frame_state);
|
||||
|
@ -2860,7 +2871,27 @@ impl PrimitiveStore {
|
|||
let common_data = &mut prim_data.common;
|
||||
let border_data = &mut prim_data.kind;
|
||||
|
||||
// Update the template this instane references, which may refresh the GPU
|
||||
let mut needs_repetition = false;
|
||||
needs_repetition |= match border_data.border.top.style {
|
||||
BorderStyle::Dotted | BorderStyle::Dashed => true,
|
||||
_ => false,
|
||||
};
|
||||
needs_repetition |= match border_data.border.right.style {
|
||||
BorderStyle::Dotted | BorderStyle::Dashed => true,
|
||||
_ => false,
|
||||
};
|
||||
needs_repetition |= match border_data.border.bottom.style {
|
||||
BorderStyle::Dotted | BorderStyle::Dashed => true,
|
||||
_ => false,
|
||||
};
|
||||
needs_repetition |= match border_data.border.left.style {
|
||||
BorderStyle::Dotted | BorderStyle::Dashed => true,
|
||||
_ => false,
|
||||
};
|
||||
|
||||
common_data.may_need_repetition = needs_repetition;
|
||||
|
||||
// Update the template this instance references, which may refresh the GPU
|
||||
// cache with any shared template data.
|
||||
border_data.update(common_data, frame_state);
|
||||
|
||||
|
@ -2930,6 +2961,8 @@ impl PrimitiveStore {
|
|||
}
|
||||
PrimitiveInstanceKind::ImageBorder { data_handle, .. } => {
|
||||
let prim_data = &mut data_stores.image_border[*data_handle];
|
||||
// TODO: get access to the ninepatch and to check whwther we need support
|
||||
// for repetitions in the shader.
|
||||
|
||||
// Update the template this instane references, which may refresh the GPU
|
||||
// cache with any shared template data.
|
||||
|
@ -2937,6 +2970,7 @@ impl PrimitiveStore {
|
|||
}
|
||||
PrimitiveInstanceKind::Rectangle { data_handle, segment_instance_index, opacity_binding_index, .. } => {
|
||||
let prim_data = &mut data_stores.prim[*data_handle];
|
||||
prim_data.common.may_need_repetition = false;
|
||||
|
||||
// Update the template this instane references, which may refresh the GPU
|
||||
// cache with any shared template data.
|
||||
|
@ -2963,6 +2997,8 @@ impl PrimitiveStore {
|
|||
PrimitiveInstanceKind::YuvImage { data_handle, segment_instance_index, .. } => {
|
||||
let yuv_image_data = &mut data_stores.yuv_image[*data_handle];
|
||||
|
||||
yuv_image_data.common.may_need_repetition = false;
|
||||
|
||||
// Update the template this instane references, which may refresh the GPU
|
||||
// cache with any shared template data.
|
||||
yuv_image_data.kind.update(&mut yuv_image_data.common, frame_state);
|
||||
|
@ -2982,6 +3018,12 @@ impl PrimitiveStore {
|
|||
let common_data = &mut prim_data.common;
|
||||
let image_data = &mut prim_data.kind;
|
||||
|
||||
if image_data.stretch_size.width >= common_data.prim_size.width &&
|
||||
image_data.stretch_size.height >= common_data.prim_size.height {
|
||||
|
||||
common_data.may_need_repetition = false;
|
||||
}
|
||||
|
||||
// Update the template this instane references, which may refresh the GPU
|
||||
// cache with any shared template data.
|
||||
image_data.update(common_data, frame_state);
|
||||
|
@ -3012,6 +3054,12 @@ impl PrimitiveStore {
|
|||
// cache with any shared template data.
|
||||
prim_data.update(frame_state);
|
||||
|
||||
if prim_data.stretch_size.width >= prim_data.common.prim_size.width &&
|
||||
prim_data.stretch_size.height >= prim_data.common.prim_size.height {
|
||||
|
||||
prim_data.common.may_need_repetition = false;
|
||||
}
|
||||
|
||||
if prim_data.supports_caching {
|
||||
let gradient_size = (prim_data.end_point - prim_data.start_point).to_size();
|
||||
|
||||
|
@ -3085,6 +3133,10 @@ impl PrimitiveStore {
|
|||
}
|
||||
|
||||
if prim_data.tile_spacing != LayoutSize::zero() {
|
||||
// We are performing the decomposition on the CPU here, no need to
|
||||
// have it in the shader.
|
||||
prim_data.common.may_need_repetition = false;
|
||||
|
||||
let prim_info = &scratch.prim_info[prim_instance.visibility_info.0 as usize];
|
||||
let prim_rect = LayoutRect::new(
|
||||
prim_instance.prim_origin,
|
||||
|
@ -3134,6 +3186,14 @@ impl PrimitiveStore {
|
|||
PrimitiveInstanceKind::RadialGradient { data_handle, ref mut visible_tiles_range, .. } => {
|
||||
let prim_data = &mut data_stores.radial_grad[*data_handle];
|
||||
|
||||
if prim_data.stretch_size.width >= prim_data.common.prim_size.width &&
|
||||
prim_data.stretch_size.height >= prim_data.common.prim_size.height {
|
||||
|
||||
// We are performing the decomposition on the CPU here, no need to
|
||||
// have it in the shader.
|
||||
prim_data.common.may_need_repetition = false;
|
||||
}
|
||||
|
||||
// Update the template this instane references, which may refresh the GPU
|
||||
// cache with any shared template data.
|
||||
prim_data.update(frame_state);
|
||||
|
@ -3152,6 +3212,8 @@ impl PrimitiveStore {
|
|||
frame_context.clip_scroll_tree,
|
||||
);
|
||||
|
||||
prim_data.common.may_need_repetition = false;
|
||||
|
||||
*visible_tiles_range = decompose_repeated_primitive(
|
||||
&prim_info.combined_local_clip_rect,
|
||||
&prim_rect,
|
||||
|
@ -3185,9 +3247,12 @@ impl PrimitiveStore {
|
|||
// TODO(gw): Consider whether it's worth doing segment building
|
||||
// for gradient primitives.
|
||||
}
|
||||
PrimitiveInstanceKind::Picture { pic_index, segment_instance_index, .. } => {
|
||||
PrimitiveInstanceKind::Picture { pic_index, segment_instance_index, data_handle, .. } => {
|
||||
let pic = &mut self.pictures[pic_index.0];
|
||||
let prim_info = &scratch.prim_info[prim_instance.visibility_info.0 as usize];
|
||||
|
||||
data_stores.picture[*data_handle].common.may_need_repetition = false;
|
||||
|
||||
if pic.prepare_for_render(
|
||||
frame_context,
|
||||
frame_state,
|
||||
|
|
|
@ -44,7 +44,7 @@ use api::channel;
|
|||
use api::units::*;
|
||||
pub use api::DebugFlags;
|
||||
use api::channel::{MsgSender, PayloadReceiverHelperMethods};
|
||||
use crate::batch::{AlphaBatchContainer, BatchKind, BatchTextures, BrushBatchKind, ClipBatchList};
|
||||
use crate::batch::{AlphaBatchContainer, BatchKind, BatchFeatures, BatchTextures, BrushBatchKind, ClipBatchList};
|
||||
#[cfg(any(feature = "capture", feature = "replay"))]
|
||||
use crate::capture::{CaptureConfig, ExternalCaptureImage, PlainExternalImage};
|
||||
use crate::debug_colors;
|
||||
|
@ -3465,7 +3465,7 @@ impl Renderer {
|
|||
}
|
||||
|
||||
self.shaders.borrow_mut()
|
||||
.get(&batch.key, self.debug_flags)
|
||||
.get(&batch.key, batch.features, self.debug_flags)
|
||||
.bind(
|
||||
&mut self.device, projection,
|
||||
&mut self.renderer_errors,
|
||||
|
@ -3514,7 +3514,7 @@ impl Renderer {
|
|||
}
|
||||
|
||||
self.shaders.borrow_mut()
|
||||
.get(&batch.key, self.debug_flags)
|
||||
.get(&batch.key, batch.features | BatchFeatures::ALPHA_PASS, self.debug_flags)
|
||||
.bind(
|
||||
&mut self.device, projection,
|
||||
&mut self.renderer_errors,
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
* 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/. */
|
||||
|
||||
use crate::batch::{BatchKey, BatchKind, BrushBatchKind};
|
||||
use crate::batch::{BatchKey, BatchKind, BrushBatchKind, BatchFeatures};
|
||||
use crate::device::{Device, Program, ShaderError};
|
||||
use euclid::{Transform3D};
|
||||
use crate::glyph_rasterizer::GlyphFormat;
|
||||
|
@ -516,6 +516,7 @@ pub struct Shaders {
|
|||
// Brush shaders
|
||||
brush_solid: BrushShader,
|
||||
brush_image: Vec<Option<BrushShader>>,
|
||||
brush_fast_image: Vec<Option<BrushShader>>,
|
||||
brush_blend: BrushShader,
|
||||
brush_mix_blend: BrushShader,
|
||||
brush_yuv_image: Vec<Option<BrushShader>>,
|
||||
|
@ -740,26 +741,45 @@ impl Shaders {
|
|||
// All image configuration.
|
||||
let mut image_features = Vec::new();
|
||||
let mut brush_image = Vec::new();
|
||||
let mut brush_fast_image = Vec::new();
|
||||
// PrimitiveShader is not clonable. Use push() to initialize the vec.
|
||||
for _ in 0 .. IMAGE_BUFFER_KINDS.len() {
|
||||
brush_image.push(None);
|
||||
brush_fast_image.push(None);
|
||||
}
|
||||
for buffer_kind in 0 .. IMAGE_BUFFER_KINDS.len() {
|
||||
if IMAGE_BUFFER_KINDS[buffer_kind].has_platform_support(&gl_type) {
|
||||
let feature_string = IMAGE_BUFFER_KINDS[buffer_kind].get_feature_string();
|
||||
if feature_string != "" {
|
||||
image_features.push(feature_string);
|
||||
}
|
||||
brush_image[buffer_kind] = Some(BrushShader::new(
|
||||
"brush_image",
|
||||
device,
|
||||
&image_features,
|
||||
options.precache_flags,
|
||||
options.allow_advanced_blend_equation,
|
||||
options.allow_dual_source_blending,
|
||||
use_pixel_local_storage,
|
||||
)?);
|
||||
if !IMAGE_BUFFER_KINDS[buffer_kind].has_platform_support(&gl_type) {
|
||||
continue;
|
||||
}
|
||||
|
||||
let feature_string = IMAGE_BUFFER_KINDS[buffer_kind].get_feature_string();
|
||||
if feature_string != "" {
|
||||
image_features.push(feature_string);
|
||||
}
|
||||
|
||||
brush_fast_image[buffer_kind] = Some(BrushShader::new(
|
||||
"brush_image",
|
||||
device,
|
||||
&image_features,
|
||||
options.precache_flags,
|
||||
options.allow_advanced_blend_equation,
|
||||
options.allow_dual_source_blending,
|
||||
use_pixel_local_storage,
|
||||
)?);
|
||||
|
||||
image_features.push("REPETITION");
|
||||
image_features.push("ANTIALIASING");
|
||||
|
||||
brush_image[buffer_kind] = Some(BrushShader::new(
|
||||
"brush_image",
|
||||
device,
|
||||
&image_features,
|
||||
options.precache_flags,
|
||||
options.allow_advanced_blend_equation,
|
||||
options.allow_dual_source_blending,
|
||||
use_pixel_local_storage,
|
||||
)?);
|
||||
|
||||
image_features.clear();
|
||||
}
|
||||
|
||||
|
@ -838,6 +858,7 @@ impl Shaders {
|
|||
cs_scale_rgba8,
|
||||
brush_solid,
|
||||
brush_image,
|
||||
brush_fast_image,
|
||||
brush_blend,
|
||||
brush_mix_blend,
|
||||
brush_yuv_image,
|
||||
|
@ -859,7 +880,7 @@ impl Shaders {
|
|||
(buffer_kind as usize)
|
||||
}
|
||||
|
||||
pub fn get(&mut self, key: &BatchKey, debug_flags: DebugFlags) -> &mut LazilyCompiledShader {
|
||||
pub fn get(&mut self, key: &BatchKey, features: BatchFeatures, debug_flags: DebugFlags) -> &mut LazilyCompiledShader {
|
||||
match key.kind {
|
||||
BatchKind::SplitComposite => {
|
||||
&mut self.ps_split_composite
|
||||
|
@ -870,9 +891,18 @@ impl Shaders {
|
|||
&mut self.brush_solid
|
||||
}
|
||||
BrushBatchKind::Image(image_buffer_kind) => {
|
||||
self.brush_image[image_buffer_kind as usize]
|
||||
.as_mut()
|
||||
.expect("Unsupported image shader kind")
|
||||
if features.contains(BatchFeatures::ANTIALIASING) ||
|
||||
features.contains(BatchFeatures::REPETITION) ||
|
||||
!features.contains(BatchFeatures::ALPHA_PASS) {
|
||||
|
||||
self.brush_image[image_buffer_kind as usize]
|
||||
.as_mut()
|
||||
.expect("Unsupported image shader kind")
|
||||
} else {
|
||||
self.brush_fast_image[image_buffer_kind as usize]
|
||||
.as_mut()
|
||||
.expect("Unsupported image shader kind")
|
||||
}
|
||||
}
|
||||
BrushBatchKind::Blend => {
|
||||
&mut self.brush_blend
|
||||
|
@ -929,6 +959,11 @@ impl Shaders {
|
|||
shader.deinit(device);
|
||||
}
|
||||
}
|
||||
for shader in self.brush_fast_image {
|
||||
if let Some(shader) = shader {
|
||||
shader.deinit(device);
|
||||
}
|
||||
}
|
||||
for shader in self.brush_yuv_image {
|
||||
if let Some(shader) = shader {
|
||||
shader.deinit(device);
|
||||
|
|
|
@ -4035,7 +4035,7 @@ nsresult SVGTextFrame::GetEndPositionOfChar(nsIContent* aContent,
|
|||
* text content element.
|
||||
*/
|
||||
nsresult SVGTextFrame::GetExtentOfChar(nsIContent* aContent, uint32_t aCharNum,
|
||||
SVGIRect** aResult) {
|
||||
SVGRect** aResult) {
|
||||
nsIFrame* kid = PrincipalChildList().FirstChild();
|
||||
if (NS_SUBTREE_DIRTY(kid)) {
|
||||
// We're never reflowed if we're under a non-SVG element that is
|
||||
|
@ -4088,7 +4088,7 @@ nsresult SVGTextFrame::GetExtentOfChar(nsIContent* aContent, uint32_t aCharNum,
|
|||
// Transform the glyph's rect into user space.
|
||||
gfxRect r = m.TransformBounds(glyphRect);
|
||||
|
||||
RefPtr<SVGRect> rect = new SVGRect(aContent, r.x, r.y, r.width, r.height);
|
||||
RefPtr<SVGRect> rect = new SVGRect(aContent, ToRect(r));
|
||||
rect.forget(aResult);
|
||||
return NS_OK;
|
||||
}
|
||||
|
|
|
@ -35,7 +35,7 @@ class TextRenderedRunIterator;
|
|||
|
||||
namespace dom {
|
||||
struct DOMPointInit;
|
||||
class SVGIRect;
|
||||
class SVGRect;
|
||||
class SVGGeometryElement;
|
||||
} // namespace dom
|
||||
|
||||
|
@ -247,7 +247,7 @@ class SVGTextFrame final : public nsSVGDisplayContainerFrame {
|
|||
nsresult GetEndPositionOfChar(nsIContent* aContent, uint32_t aCharNum,
|
||||
mozilla::nsISVGPoint** aResult);
|
||||
nsresult GetExtentOfChar(nsIContent* aContent, uint32_t aCharNum,
|
||||
mozilla::dom::SVGIRect** aResult);
|
||||
mozilla::dom::SVGRect** aResult);
|
||||
nsresult GetRotationOfChar(nsIContent* aContent, uint32_t aCharNum,
|
||||
float* aResult);
|
||||
|
||||
|
|
|
@ -567,6 +567,11 @@ bool DataChannelConnection::Init(const uint16_t aLocalPort,
|
|||
}
|
||||
}
|
||||
|
||||
// Update number of streams
|
||||
mStreams.AppendElements(aNumStreams);
|
||||
for (uint32_t i = 0; i < aNumStreams; ++i) {
|
||||
mStreams[i] = nullptr;
|
||||
}
|
||||
memset(&initmsg, 0, sizeof(initmsg));
|
||||
len = sizeof(initmsg);
|
||||
if (usrsctp_getsockopt(mMasterSocket, IPPROTO_SCTP, SCTP_INITMSG, &initmsg,
|
||||
|
@ -662,27 +667,20 @@ bool DataChannelConnection::ConnectToTransport(const std::string& aTransportId,
|
|||
mLocalPort = localport;
|
||||
mRemotePort = remoteport;
|
||||
mState = CONNECTING;
|
||||
mAllocateEven = Some(aClient);
|
||||
|
||||
// Could be faster. Probably doesn't matter.
|
||||
while (auto channel = mChannels.Get(INVALID_STREAM)) {
|
||||
mChannels.Remove(channel);
|
||||
channel->mStream = FindFreeStream();
|
||||
if (channel->mStream != INVALID_STREAM) {
|
||||
mChannels.Insert(channel);
|
||||
}
|
||||
}
|
||||
|
||||
RUN_ON_THREAD(mSTS,
|
||||
WrapRunnable(RefPtr<DataChannelConnection>(this),
|
||||
&DataChannelConnection::SetSignals, aTransportId),
|
||||
NS_DISPATCH_NORMAL);
|
||||
RUN_ON_THREAD(
|
||||
mSTS,
|
||||
WrapRunnable(RefPtr<DataChannelConnection>(this),
|
||||
&DataChannelConnection::SetSignals, aTransportId, aClient),
|
||||
NS_DISPATCH_NORMAL);
|
||||
return true;
|
||||
}
|
||||
|
||||
void DataChannelConnection::SetSignals(const std::string& aTransportId) {
|
||||
void DataChannelConnection::SetSignals(const std::string& aTransportId,
|
||||
bool aClient) {
|
||||
ASSERT_WEBRTC(IsSTSThread());
|
||||
mTransportId = aTransportId;
|
||||
mAllocateEven = aClient;
|
||||
mTransportHandler->SignalPacketReceived.connect(
|
||||
this, &DataChannelConnection::SctpDtlsInput);
|
||||
// SignalStateChange() doesn't call you with the initial state
|
||||
|
@ -1027,47 +1025,48 @@ bool DataChannelConnection::Connect(const char* addr, unsigned short port) {
|
|||
#endif
|
||||
|
||||
DataChannel* DataChannelConnection::FindChannelByStream(uint16_t stream) {
|
||||
return mChannels.Get(stream).get();
|
||||
return mStreams.SafeElementAt(stream);
|
||||
}
|
||||
|
||||
uint16_t DataChannelConnection::FindFreeStream() {
|
||||
ASSERT_WEBRTC(NS_IsMainThread());
|
||||
uint16_t i, limit;
|
||||
uint32_t i, j, limit;
|
||||
|
||||
limit = MAX_NUM_STREAMS;
|
||||
limit = mStreams.Length();
|
||||
if (limit > MAX_NUM_STREAMS) limit = MAX_NUM_STREAMS;
|
||||
|
||||
MOZ_ASSERT(mAllocateEven.isSome());
|
||||
for (i = (*mAllocateEven ? 0 : 1); i < limit; i += 2) {
|
||||
if (mChannels.Get(i)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Verify it's not still in the process of closing
|
||||
size_t j;
|
||||
for (j = 0; j < mStreamsResetting.Length(); ++j) {
|
||||
if (mStreamsResetting[j] == i) {
|
||||
break;
|
||||
for (i = (mAllocateEven ? 0 : 1); i < limit; i += 2) {
|
||||
if (!mStreams[i]) {
|
||||
// Verify it's not still in the process of closing
|
||||
for (j = 0; j < mStreamsResetting.Length(); ++j) {
|
||||
if (mStreamsResetting[j] == i) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (j == mStreamsResetting.Length()) {
|
||||
return i;
|
||||
if (j == mStreamsResetting.Length()) break;
|
||||
}
|
||||
}
|
||||
return INVALID_STREAM;
|
||||
if (i >= limit) {
|
||||
return INVALID_STREAM;
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
uint32_t DataChannelConnection::UpdateCurrentStreamIndex() {
|
||||
RefPtr<DataChannel> channel = mChannels.GetNextChannel(mCurrentStream);
|
||||
if (!channel) {
|
||||
if (mCurrentStream == mStreams.Length() - 1) {
|
||||
mCurrentStream = 0;
|
||||
} else {
|
||||
mCurrentStream = channel->mStream;
|
||||
++mCurrentStream;
|
||||
}
|
||||
|
||||
return mCurrentStream;
|
||||
}
|
||||
|
||||
uint32_t DataChannelConnection::GetCurrentStreamIndex() {
|
||||
// Fix current stream index (in case #streams decreased)
|
||||
if (mCurrentStream >= mStreams.Length()) {
|
||||
mCurrentStream = 0;
|
||||
}
|
||||
|
||||
return mCurrentStream;
|
||||
}
|
||||
|
||||
|
@ -1077,8 +1076,8 @@ bool DataChannelConnection::RequestMoreStreams(int32_t aNeeded) {
|
|||
uint32_t outStreamsNeeded;
|
||||
socklen_t len;
|
||||
|
||||
if (aNeeded + mNegotiatedIdLimit > MAX_NUM_STREAMS) {
|
||||
aNeeded = MAX_NUM_STREAMS - mNegotiatedIdLimit;
|
||||
if (aNeeded + mStreams.Length() > MAX_NUM_STREAMS) {
|
||||
aNeeded = MAX_NUM_STREAMS - mStreams.Length();
|
||||
}
|
||||
if (aNeeded <= 0) {
|
||||
return false;
|
||||
|
@ -1109,8 +1108,8 @@ bool DataChannelConnection::RequestMoreStreams(int32_t aNeeded) {
|
|||
return false;
|
||||
}
|
||||
LOG(("Requested %u more streams", outStreamsNeeded));
|
||||
// We add to mNegotiatedIdLimit when we get a SCTP_STREAM_CHANGE_EVENT and the
|
||||
// values are larger than mNegotiatedIdLimit
|
||||
// We add to mStreams when we get a SCTP_STREAM_CHANGE_EVENT and the
|
||||
// values are larger than mStreams.Length()
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -1218,7 +1217,6 @@ bool DataChannelConnection::SendDeferredMessages() {
|
|||
|
||||
// This may block while something is modifying channels, but should not block
|
||||
// for IO
|
||||
ASSERT_WEBRTC(!NS_IsMainThread());
|
||||
mLock.AssertCurrentThreadOwns();
|
||||
|
||||
LOG(("SendDeferredMessages called, pending type: %d", mPendingType));
|
||||
|
@ -1244,7 +1242,7 @@ bool DataChannelConnection::SendDeferredMessages() {
|
|||
uint32_t i = GetCurrentStreamIndex();
|
||||
uint32_t end = i;
|
||||
do {
|
||||
channel = mChannels.Get(i);
|
||||
channel = mStreams[i];
|
||||
// Should already be cleared if closing/closed
|
||||
if (!channel || channel->mBufferedData.IsEmpty()) {
|
||||
i = UpdateCurrentStreamIndex();
|
||||
|
@ -1321,7 +1319,6 @@ void DataChannelConnection::HandleOpenRequestMessage(
|
|||
uint32_t prValue;
|
||||
uint16_t prPolicy;
|
||||
|
||||
ASSERT_WEBRTC(!NS_IsMainThread());
|
||||
mLock.AssertCurrentThreadOwns();
|
||||
|
||||
const size_t requiredLength = (sizeof(*req) - 1) + ntohs(req->label_length) +
|
||||
|
@ -1357,7 +1354,7 @@ void DataChannelConnection::HandleOpenRequestMessage(
|
|||
bool ordered = !(req->channel_type & 0x80);
|
||||
|
||||
if ((channel = FindChannelByStream(stream))) {
|
||||
if (!channel->mNegotiated) {
|
||||
if (!(channel->mFlags & DATA_CHANNEL_FLAGS_EXTERNAL_NEGOTIATED)) {
|
||||
LOG(
|
||||
("ERROR: HandleOpenRequestMessage: channel for pre-existing stream "
|
||||
"%u that was not externally negotiated. JS is lying to us, or "
|
||||
|
@ -1378,9 +1375,9 @@ void DataChannelConnection::HandleOpenRequestMessage(
|
|||
}
|
||||
return;
|
||||
}
|
||||
if (stream >= mNegotiatedIdLimit) {
|
||||
if (stream >= mStreams.Length()) {
|
||||
LOG(("%s: stream %u out of bounds (%zu)", __FUNCTION__, stream,
|
||||
mNegotiatedIdLimit));
|
||||
mStreams.Length()));
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -1392,7 +1389,7 @@ void DataChannelConnection::HandleOpenRequestMessage(
|
|||
channel =
|
||||
new DataChannel(this, stream, DataChannel::OPEN, label, protocol,
|
||||
prPolicy, prValue, ordered, false, nullptr, nullptr);
|
||||
mChannels.Insert(channel);
|
||||
mStreams[stream] = channel;
|
||||
|
||||
LOG(("%s: sending ON_CHANNEL_CREATED for %s/%s: %u", __FUNCTION__,
|
||||
channel->mLabel.get(), channel->mProtocol.get(), stream));
|
||||
|
@ -1564,7 +1561,8 @@ void DataChannelConnection::HandleDataMessage(const void* data, size_t length,
|
|||
"closing",
|
||||
data_length));
|
||||
// Only unblock if unordered
|
||||
if (!channel->mOrdered && (flags & MSG_EOR)) {
|
||||
if ((channel->mFlags & DATA_CHANNEL_FLAGS_OUT_OF_ORDER_ALLOWED) &&
|
||||
(flags & MSG_EOR)) {
|
||||
channel->mFlags &= ~DATA_CHANNEL_FLAGS_CLOSING_TOO_LARGE;
|
||||
}
|
||||
}
|
||||
|
@ -1991,9 +1989,7 @@ void DataChannelConnection::ClearResets() {
|
|||
if (channel) {
|
||||
LOG(("Forgetting channel %u (%p) with pending reset", channel->mStream,
|
||||
channel.get()));
|
||||
// TODO: Do we _really_ want to remove this? Are we allowed to reuse the
|
||||
// id?
|
||||
mChannels.Remove(channel);
|
||||
mStreams[channel->mStream] = nullptr;
|
||||
}
|
||||
}
|
||||
mStreamsResetting.Clear();
|
||||
|
@ -2075,10 +2071,11 @@ void DataChannelConnection::HandleStreamResetEvent(
|
|||
// yet.
|
||||
|
||||
LOG(("Incoming: Channel %u closed", channel->mStream));
|
||||
if (mChannels.Remove(channel)) {
|
||||
if (mStreams[channel->mStream]) {
|
||||
// Mark the stream for reset (the reset is sent below)
|
||||
ResetOutgoingStream(channel->mStream);
|
||||
}
|
||||
mStreams[channel->mStream] = nullptr;
|
||||
|
||||
LOG(("Disconnected DataChannel %p from connection %p",
|
||||
(void*)channel.get(), (void*)channel->mConnection.get()));
|
||||
|
@ -2099,43 +2096,48 @@ void DataChannelConnection::HandleStreamResetEvent(
|
|||
|
||||
void DataChannelConnection::HandleStreamChangeEvent(
|
||||
const struct sctp_stream_change_event* strchg) {
|
||||
ASSERT_WEBRTC(!NS_IsMainThread());
|
||||
uint16_t stream;
|
||||
RefPtr<DataChannel> channel;
|
||||
|
||||
if (strchg->strchange_flags == SCTP_STREAM_CHANGE_DENIED) {
|
||||
LOG(("*** Failed increasing number of streams from %zu (%u/%u)",
|
||||
mNegotiatedIdLimit, strchg->strchange_instrms,
|
||||
mStreams.Length(), strchg->strchange_instrms,
|
||||
strchg->strchange_outstrms));
|
||||
// XXX FIX! notify pending opens of failure
|
||||
return;
|
||||
}
|
||||
if (strchg->strchange_instrms > mNegotiatedIdLimit) {
|
||||
LOG(("Other side increased streams from %zu to %u", mNegotiatedIdLimit,
|
||||
if (strchg->strchange_instrms > mStreams.Length()) {
|
||||
LOG(("Other side increased streams from %zu to %u", mStreams.Length(),
|
||||
strchg->strchange_instrms));
|
||||
}
|
||||
uint16_t old_limit = mNegotiatedIdLimit;
|
||||
uint16_t new_limit =
|
||||
std::max(strchg->strchange_outstrms, strchg->strchange_instrms);
|
||||
if (new_limit > mNegotiatedIdLimit) {
|
||||
if (strchg->strchange_outstrms > mStreams.Length() ||
|
||||
strchg->strchange_instrms > mStreams.Length()) {
|
||||
uint16_t old_len = mStreams.Length();
|
||||
uint16_t new_len =
|
||||
std::max(strchg->strchange_outstrms, strchg->strchange_instrms);
|
||||
LOG(("Increasing number of streams from %u to %u - adding %u (in: %u)",
|
||||
old_limit, new_limit, new_limit - old_limit,
|
||||
strchg->strchange_instrms));
|
||||
old_len, new_len, new_len - old_len, strchg->strchange_instrms));
|
||||
// make sure both are the same length
|
||||
mNegotiatedIdLimit = new_limit;
|
||||
LOG(("New length = %zu (was %d)", mNegotiatedIdLimit, old_limit));
|
||||
mStreams.AppendElements(new_len - old_len);
|
||||
LOG(("New length = %zu (was %d)", mStreams.Length(), old_len));
|
||||
for (size_t i = old_len; i < mStreams.Length(); ++i) {
|
||||
mStreams[i] = nullptr;
|
||||
}
|
||||
// Re-process any channels waiting for streams.
|
||||
// Linear search, but we don't increase channels often and
|
||||
// the array would only get long in case of an app error normally
|
||||
|
||||
// Make sure we request enough streams if there's a big jump in streams
|
||||
// Could make a more complex API for OpenXxxFinish() and avoid this loop
|
||||
auto channels = mChannels.GetAll();
|
||||
size_t num_needed =
|
||||
channels.Length() ? (channels.LastElement()->mStream + 1) : 0;
|
||||
MOZ_ASSERT(num_needed != INVALID_STREAM);
|
||||
if (num_needed > new_limit) {
|
||||
int32_t more_needed = num_needed - ((int32_t)mNegotiatedIdLimit) + 16;
|
||||
LOG(("Not enough new streams, asking for %d more", more_needed));
|
||||
size_t num_needed = mPending.GetSize();
|
||||
LOG(("%zu of %d new streams already needed", num_needed,
|
||||
new_len - old_len));
|
||||
num_needed -= (new_len - old_len); // number we added
|
||||
if (num_needed > 0) {
|
||||
if (num_needed < 16) num_needed = 16;
|
||||
LOG(("Not enough new streams, asking for %zu more", num_needed));
|
||||
// TODO: parameter is an int32_t but we pass size_t
|
||||
RequestMoreStreams(more_needed);
|
||||
RequestMoreStreams(num_needed);
|
||||
} else if (strchg->strchange_outstrms < strchg->strchange_instrms) {
|
||||
LOG(("Requesting %d output streams to match partner",
|
||||
strchg->strchange_instrms - strchg->strchange_outstrms));
|
||||
|
@ -2147,14 +2149,41 @@ void DataChannelConnection::HandleStreamChangeEvent(
|
|||
}
|
||||
// else probably not a change in # of streams
|
||||
|
||||
if ((strchg->strchange_flags & SCTP_STREAM_CHANGE_DENIED) ||
|
||||
(strchg->strchange_flags & SCTP_STREAM_CHANGE_FAILED)) {
|
||||
// Other side denied our request. Need to AnnounceClosed some stuff.
|
||||
for (auto& channel : mChannels.GetAll()) {
|
||||
if (channel->mStream >= mNegotiatedIdLimit) {
|
||||
for (uint32_t i = 0; i < mStreams.Length(); ++i) {
|
||||
channel = mStreams[i];
|
||||
if (!channel) continue;
|
||||
|
||||
if (channel->mStream == INVALID_STREAM) {
|
||||
if ((strchg->strchange_flags & SCTP_STREAM_CHANGE_DENIED) ||
|
||||
(strchg->strchange_flags & SCTP_STREAM_CHANGE_FAILED)) {
|
||||
/* XXX: Signal to the other end. */
|
||||
channel->AnnounceClosed();
|
||||
// maybe fire onError (bug 843625)
|
||||
} else {
|
||||
stream = FindFreeStream();
|
||||
if (stream != INVALID_STREAM) {
|
||||
channel->mStream = stream;
|
||||
mStreams[stream] = channel;
|
||||
|
||||
// Send open request
|
||||
int error = SendOpenRequestMessage(
|
||||
channel->mLabel, channel->mProtocol, channel->mStream,
|
||||
!!(channel->mFlags & DATA_CHANNEL_FLAGS_OUT_OF_ORDER_ALLOWED),
|
||||
channel->mPrPolicy, channel->mPrValue);
|
||||
if (error) {
|
||||
LOG(("SendOpenRequest failed, error = %d", error));
|
||||
// Close the channel, inform the user
|
||||
mStreams[channel->mStream] = nullptr;
|
||||
channel->AnnounceClosed();
|
||||
// Don't need to reset; we didn't open it
|
||||
} else {
|
||||
channel->mFlags |= DATA_CHANNEL_FLAGS_READY;
|
||||
channel->AnnounceOpen();
|
||||
}
|
||||
} else {
|
||||
/* We will not find more ... */
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2250,18 +2279,9 @@ already_AddRefed<DataChannel> DataChannelConnection::Open(
|
|||
const nsACString& label, const nsACString& protocol, Type type,
|
||||
bool inOrder, uint32_t prValue, DataChannelListener* aListener,
|
||||
nsISupports* aContext, bool aExternalNegotiated, uint16_t aStream) {
|
||||
ASSERT_WEBRTC(NS_IsMainThread());
|
||||
if (!aExternalNegotiated) {
|
||||
if (mAllocateEven.isSome()) {
|
||||
aStream = FindFreeStream();
|
||||
if (aStream == INVALID_STREAM) {
|
||||
return nullptr;
|
||||
}
|
||||
} else {
|
||||
// We do not yet know whether we are client or server, and an id has not
|
||||
// been chosen for us. We will need to choose later.
|
||||
aStream = INVALID_STREAM;
|
||||
}
|
||||
// aStream == INVALID_STREAM to have the protocol allocate
|
||||
aStream = INVALID_STREAM;
|
||||
}
|
||||
uint16_t prPolicy = SCTP_PR_SCTP_NONE;
|
||||
|
||||
|
@ -2290,7 +2310,9 @@ already_AddRefed<DataChannel> DataChannelConnection::Open(
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
if (aStream != INVALID_STREAM && mChannels.Get(aStream)) {
|
||||
// Don't look past currently-negotiated streams
|
||||
if (aStream != INVALID_STREAM && aStream < mStreams.Length() &&
|
||||
mStreams[aStream]) {
|
||||
LOG(("ERROR: external negotiation of already-open channel %u", aStream));
|
||||
// XXX How do we indicate this up to the application? Probably the
|
||||
// caller's job, but we may need to return an error code.
|
||||
|
@ -2300,7 +2322,6 @@ already_AddRefed<DataChannel> DataChannelConnection::Open(
|
|||
RefPtr<DataChannel> channel(new DataChannel(
|
||||
this, aStream, DataChannel::CONNECTING, label, protocol, prPolicy,
|
||||
prValue, inOrder, aExternalNegotiated, aListener, aContext));
|
||||
mChannels.Insert(channel);
|
||||
|
||||
MutexAutoLock lock(mLock); // OpenFinish assumes this
|
||||
return OpenFinish(channel.forget());
|
||||
|
@ -2312,7 +2333,7 @@ already_AddRefed<DataChannel> DataChannelConnection::OpenFinish(
|
|||
RefPtr<DataChannel> channel(aChannel); // takes the reference passed in
|
||||
// Normally 1 reference if called from ::Open(), or 2 if called from
|
||||
// ProcessQueuedOpens() unless the DOMDataChannel was gc'd
|
||||
const uint16_t stream = channel->mStream;
|
||||
uint16_t stream = channel->mStream;
|
||||
bool queue = false;
|
||||
|
||||
mLock.AssertCurrentThreadOwns();
|
||||
|
@ -2342,12 +2363,16 @@ already_AddRefed<DataChannel> DataChannelConnection::OpenFinish(
|
|||
// either change the initial ask or possibly renegotiate after open.
|
||||
|
||||
if (mState == OPEN) {
|
||||
MOZ_ASSERT(stream != INVALID_STREAM);
|
||||
if (stream >= mNegotiatedIdLimit) {
|
||||
if (stream == INVALID_STREAM) {
|
||||
stream = FindFreeStream(); // may be INVALID_STREAM if we need more
|
||||
}
|
||||
if (stream == INVALID_STREAM || stream >= mStreams.Length()) {
|
||||
// RequestMoreStreams() limits to MAX_NUM_STREAMS -- allocate extra
|
||||
// streams to avoid going back immediately for more if the ask to N, N+1,
|
||||
// etc
|
||||
int32_t more_needed = stream - ((int32_t)mNegotiatedIdLimit) + 16;
|
||||
int32_t more_needed = (stream == INVALID_STREAM)
|
||||
? 16
|
||||
: (stream - ((int32_t)mStreams.Length())) + 16;
|
||||
if (!RequestMoreStreams(more_needed)) {
|
||||
// Something bad happened... we're done
|
||||
goto request_error_cleanup;
|
||||
|
@ -2356,13 +2381,12 @@ already_AddRefed<DataChannel> DataChannelConnection::OpenFinish(
|
|||
}
|
||||
} else {
|
||||
// not OPEN
|
||||
if (stream != INVALID_STREAM && stream >= mNegotiatedIdLimit &&
|
||||
if (stream != INVALID_STREAM && stream >= mStreams.Length() &&
|
||||
mState == CLOSED) {
|
||||
// Update number of streams for init message
|
||||
struct sctp_initmsg initmsg;
|
||||
socklen_t len = sizeof(initmsg);
|
||||
uint16_t total_needed =
|
||||
(stream < UINT16_MAX - 16) ? stream + 16 : UINT16_MAX;
|
||||
int32_t total_needed = stream + 16;
|
||||
|
||||
memset(&initmsg, 0, sizeof(initmsg));
|
||||
if (usrsctp_getsockopt(mMasterSocket, IPPROTO_SCTP, SCTP_INITMSG,
|
||||
|
@ -2379,6 +2403,12 @@ already_AddRefed<DataChannel> DataChannelConnection::OpenFinish(
|
|||
LOG(("*** failed setsockopt SCTP_INITMSG, errno %d", errno));
|
||||
goto request_error_cleanup;
|
||||
}
|
||||
|
||||
int32_t old_len = mStreams.Length();
|
||||
mStreams.AppendElements(total_needed - old_len);
|
||||
for (int32_t i = old_len; i < total_needed; ++i) {
|
||||
mStreams[i] = nullptr;
|
||||
}
|
||||
}
|
||||
// else if state is CONNECTING, we'll just re-negotiate when OpenFinish
|
||||
// is called, if needed
|
||||
|
@ -2396,24 +2426,28 @@ already_AddRefed<DataChannel> DataChannelConnection::OpenFinish(
|
|||
}
|
||||
|
||||
MOZ_ASSERT(stream != INVALID_STREAM);
|
||||
MOZ_ASSERT(stream < mNegotiatedIdLimit);
|
||||
// just allocated (& OPEN), or externally negotiated
|
||||
mStreams[stream] = channel; // holds a reference
|
||||
channel->mStream = stream;
|
||||
|
||||
#ifdef TEST_QUEUED_DATA
|
||||
// It's painful to write a test for this...
|
||||
channel->AnnounceOpen();
|
||||
channel->mFlags |= DATA_CHANNEL_FLAGS_READY;
|
||||
SendDataMsgInternalOrBuffer(channel, "Help me!", 8,
|
||||
DATA_CHANNEL_PPID_DOMSTRING);
|
||||
#endif
|
||||
|
||||
if (!channel->mOrdered) {
|
||||
if (channel->mFlags & DATA_CHANNEL_FLAGS_OUT_OF_ORDER_ALLOWED) {
|
||||
// Don't send unordered until this gets cleared
|
||||
channel->mFlags |= DATA_CHANNEL_FLAGS_WAITING_ACK;
|
||||
}
|
||||
|
||||
if (!channel->mNegotiated) {
|
||||
int error = SendOpenRequestMessage(channel->mLabel, channel->mProtocol,
|
||||
stream, !channel->mOrdered,
|
||||
channel->mPrPolicy, channel->mPrValue);
|
||||
if (!(channel->mFlags & DATA_CHANNEL_FLAGS_EXTERNAL_NEGOTIATED)) {
|
||||
int error = SendOpenRequestMessage(
|
||||
channel->mLabel, channel->mProtocol, stream,
|
||||
!!(channel->mFlags & DATA_CHANNEL_FLAGS_OUT_OF_ORDER_ALLOWED),
|
||||
channel->mPrPolicy, channel->mPrValue);
|
||||
if (error) {
|
||||
LOG(("SendOpenRequest failed, error = %d", error));
|
||||
if (channel->mFlags & DATA_CHANNEL_FLAGS_FINISH_OPEN) {
|
||||
|
@ -2423,7 +2457,8 @@ already_AddRefed<DataChannel> DataChannelConnection::OpenFinish(
|
|||
}
|
||||
// If we haven't returned the channel yet, it will get destroyed when we
|
||||
// exit this function.
|
||||
mChannels.Remove(channel);
|
||||
mStreams[stream] = nullptr;
|
||||
channel->mStream = INVALID_STREAM;
|
||||
// we'll be destroying the channel
|
||||
return nullptr;
|
||||
/* NOTREACHED */
|
||||
|
@ -2431,6 +2466,7 @@ already_AddRefed<DataChannel> DataChannelConnection::OpenFinish(
|
|||
}
|
||||
|
||||
// Either externally negotiated or we sent Open
|
||||
channel->mFlags |= DATA_CHANNEL_FLAGS_READY;
|
||||
// FIX? Move into DOMDataChannel? I don't think we can send it yet here
|
||||
channel->AnnounceOpen();
|
||||
|
||||
|
@ -2614,12 +2650,12 @@ int DataChannelConnection::SendDataMsgInternalOrBuffer(DataChannel& channel,
|
|||
info.sendv_sndinfo.snd_flags = SCTP_EOR;
|
||||
info.sendv_sndinfo.snd_ppid = htonl(ppid);
|
||||
|
||||
MutexAutoLock lock(mLock); // Need to protect mFlags... :(
|
||||
// Unordered?
|
||||
// To avoid problems where an in-order OPEN is lost and an
|
||||
// out-of-order data message "beats" it, require data to be in-order
|
||||
// until we get an ACK.
|
||||
if (!channel.mOrdered && !(channel.mFlags & DATA_CHANNEL_FLAGS_WAITING_ACK)) {
|
||||
if ((channel.mFlags & DATA_CHANNEL_FLAGS_OUT_OF_ORDER_ALLOWED) &&
|
||||
!(channel.mFlags & DATA_CHANNEL_FLAGS_WAITING_ACK)) {
|
||||
info.sendv_sndinfo.snd_flags |= SCTP_UNORDERED;
|
||||
}
|
||||
|
||||
|
@ -2632,6 +2668,7 @@ int DataChannelConnection::SendDataMsgInternalOrBuffer(DataChannel& channel,
|
|||
|
||||
// Create message instance and send
|
||||
OutgoingMsg msg(info, data, len);
|
||||
MutexAutoLock lock(mLock);
|
||||
bool buffered;
|
||||
size_t written = 0;
|
||||
mDeferSend = true;
|
||||
|
@ -2706,7 +2743,7 @@ class ReadBlobRunnable : public Runnable {
|
|||
|
||||
// Returns a POSIX error code.
|
||||
int DataChannelConnection::SendBlob(uint16_t stream, nsIInputStream* aBlob) {
|
||||
RefPtr<DataChannel> channel = mChannels.Get(stream);
|
||||
DataChannel* channel = mStreams[stream];
|
||||
if (NS_WARN_IF(!channel)) {
|
||||
return EINVAL; // TODO: Find a better error code
|
||||
}
|
||||
|
@ -2792,6 +2829,15 @@ void DataChannelConnection::ReadBlob(
|
|||
Dispatch(runnable.forget());
|
||||
}
|
||||
|
||||
void DataChannelConnection::GetStreamIds(std::vector<uint16_t>* aStreamList) {
|
||||
ASSERT_WEBRTC(NS_IsMainThread());
|
||||
for (uint32_t i = 0; i < mStreams.Length(); ++i) {
|
||||
if (mStreams[i]) {
|
||||
aStreamList->push_back(mStreams[i]->mStream);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Returns a POSIX error code.
|
||||
int DataChannelConnection::SendDataMsgCommon(uint16_t stream,
|
||||
const nsACString& aMsg,
|
||||
|
@ -2799,7 +2845,7 @@ int DataChannelConnection::SendDataMsgCommon(uint16_t stream,
|
|||
ASSERT_WEBRTC(NS_IsMainThread());
|
||||
// We really could allow this from other threads, so long as we deal with
|
||||
// asynchronosity issues with channels closing, in particular access to
|
||||
// mChannels, and issues with the association closing (access to mSocket).
|
||||
// mStreams, and issues with the association closing (access to mSocket).
|
||||
|
||||
const uint8_t* data = (const uint8_t*)aMsg.BeginReading();
|
||||
uint32_t len = aMsg.Length();
|
||||
|
@ -2808,11 +2854,12 @@ int DataChannelConnection::SendDataMsgCommon(uint16_t stream,
|
|||
return EMSGSIZE;
|
||||
}
|
||||
#endif
|
||||
DataChannel* channelPtr;
|
||||
|
||||
LOG(("Sending %sto stream %u: %u bytes", isBinary ? "binary " : "", stream,
|
||||
len));
|
||||
// XXX if we want more efficiency, translate flags once at open time
|
||||
RefPtr<DataChannel> channelPtr = mChannels.Get(stream);
|
||||
channelPtr = mStreams[stream];
|
||||
if (NS_WARN_IF(!channelPtr)) {
|
||||
return EINVAL; // TODO: Find a better error code
|
||||
}
|
||||
|
@ -2847,24 +2894,24 @@ void DataChannelConnection::CloseInt(DataChannel* aChannel) {
|
|||
mLock.AssertCurrentThreadOwns();
|
||||
LOG(("Connection %p/Channel %p: Closing stream %u",
|
||||
channel->mConnection.get(), channel.get(), channel->mStream));
|
||||
|
||||
aChannel->mBufferedData.Clear();
|
||||
if (mState == CLOSED) {
|
||||
// If we're CLOSING, we might leave this in place until we can send a
|
||||
// reset.
|
||||
mChannels.Remove(channel);
|
||||
}
|
||||
|
||||
// re-test since it may have closed before the lock was grabbed
|
||||
if (aChannel->mReadyState == CLOSED || aChannel->mReadyState == CLOSING) {
|
||||
LOG(("Channel already closing/closed (%u)", aChannel->mReadyState));
|
||||
if (mState == CLOSED && channel->mStream != INVALID_STREAM) {
|
||||
// called from CloseAll()
|
||||
// we're not going to hang around waiting any more
|
||||
mStreams[channel->mStream] = nullptr;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
aChannel->mBufferedData.Clear();
|
||||
if (channel->mStream != INVALID_STREAM) {
|
||||
ResetOutgoingStream(channel->mStream);
|
||||
if (mState != CLOSED) {
|
||||
// Individual channel is being closed, send reset now.
|
||||
if (mState == CLOSED) { // called from CloseAll()
|
||||
// Let resets accumulate then send all at once in CloseAll()
|
||||
// we're not going to hang around waiting
|
||||
mStreams[channel->mStream] = nullptr;
|
||||
} else {
|
||||
SendOutgoingStreamReset();
|
||||
}
|
||||
}
|
||||
|
@ -2890,8 +2937,12 @@ void DataChannelConnection::CloseAll() {
|
|||
// Close current channels
|
||||
// If there are runnables, they hold a strong ref and keep the channel
|
||||
// and/or connection alive (even if in a CLOSED state)
|
||||
for (auto& channel : mChannels.GetAll()) {
|
||||
channel->Close();
|
||||
bool closed_some = false;
|
||||
for (uint32_t i = 0; i < mStreams.Length(); ++i) {
|
||||
if (mStreams[i]) {
|
||||
mStreams[i]->Close();
|
||||
closed_some = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Clean up any pending opens for channels
|
||||
|
@ -2901,78 +2952,14 @@ void DataChannelConnection::CloseAll() {
|
|||
LOG(("closing pending channel %p, stream %u", channel.get(),
|
||||
channel->mStream));
|
||||
channel->Close(); // also releases the ref on each iteration
|
||||
closed_some = true;
|
||||
}
|
||||
// It's more efficient to let the Resets queue in shutdown and then
|
||||
// SendOutgoingStreamReset() here.
|
||||
MutexAutoLock lock(mLock);
|
||||
SendOutgoingStreamReset();
|
||||
}
|
||||
|
||||
bool DataChannelConnection::Channels::IdComparator::Equals(
|
||||
const RefPtr<DataChannel>& aChannel, uint16_t aId) const {
|
||||
return aChannel->mStream == aId;
|
||||
}
|
||||
|
||||
bool DataChannelConnection::Channels::IdComparator::LessThan(
|
||||
const RefPtr<DataChannel>& aChannel, uint16_t aId) const {
|
||||
return aChannel->mStream < aId;
|
||||
}
|
||||
|
||||
bool DataChannelConnection::Channels::IdComparator::Equals(
|
||||
const RefPtr<DataChannel>& a1, const RefPtr<DataChannel>& a2) const {
|
||||
return Equals(a1, a2->mStream);
|
||||
}
|
||||
|
||||
bool DataChannelConnection::Channels::IdComparator::LessThan(
|
||||
const RefPtr<DataChannel>& a1, const RefPtr<DataChannel>& a2) const {
|
||||
return LessThan(a1, a2->mStream);
|
||||
}
|
||||
|
||||
void DataChannelConnection::Channels::Insert(
|
||||
const RefPtr<DataChannel>& aChannel) {
|
||||
LOG(("Inserting channel %u : %p", aChannel->mStream, aChannel.get()));
|
||||
MutexAutoLock lock(mMutex);
|
||||
if (aChannel->mStream != INVALID_STREAM) {
|
||||
MOZ_ASSERT(!mChannels.ContainsSorted(aChannel, IdComparator()));
|
||||
if (closed_some) {
|
||||
MutexAutoLock lock(mLock);
|
||||
SendOutgoingStreamReset();
|
||||
}
|
||||
|
||||
MOZ_ASSERT(!mChannels.Contains(aChannel));
|
||||
|
||||
mChannels.InsertElementSorted(aChannel, IdComparator());
|
||||
}
|
||||
|
||||
bool DataChannelConnection::Channels::Remove(
|
||||
const RefPtr<DataChannel>& aChannel) {
|
||||
LOG(("Removing channel %u : %p", aChannel->mStream, aChannel.get()));
|
||||
MutexAutoLock lock(mMutex);
|
||||
if (aChannel->mStream == INVALID_STREAM) {
|
||||
return mChannels.RemoveElement(aChannel);
|
||||
}
|
||||
|
||||
return mChannels.RemoveElementSorted(aChannel, IdComparator());
|
||||
}
|
||||
|
||||
RefPtr<DataChannel> DataChannelConnection::Channels::Get(uint16_t aId) const {
|
||||
MutexAutoLock lock(mMutex);
|
||||
auto index = mChannels.BinaryIndexOf(aId, IdComparator());
|
||||
if (index == ChannelArray::NoIndex) {
|
||||
return nullptr;
|
||||
}
|
||||
return mChannels[index];
|
||||
}
|
||||
|
||||
RefPtr<DataChannel> DataChannelConnection::Channels::GetNextChannel(
|
||||
uint16_t aCurrentId) const {
|
||||
MutexAutoLock lock(mMutex);
|
||||
if (mChannels.IsEmpty()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto index = mChannels.IndexOfFirstElementGt(aCurrentId, IdComparator());
|
||||
if (index == mChannels.Length()) {
|
||||
index = 0;
|
||||
}
|
||||
return mChannels[index];
|
||||
}
|
||||
|
||||
DataChannel::~DataChannel() {
|
||||
|
@ -2999,6 +2986,8 @@ void DataChannel::StreamClosedLocked() {
|
|||
LOG(("Destroying Data channel %u", mStream));
|
||||
MOZ_ASSERT_IF(mStream != INVALID_STREAM,
|
||||
!mConnection->FindChannelByStream(mStream));
|
||||
// Spec doesn't say to mess with the stream id...
|
||||
mStream = INVALID_STREAM;
|
||||
AnnounceClosed();
|
||||
// We leave mConnection live until the DOM releases us, to avoid races
|
||||
}
|
||||
|
|
|
@ -164,7 +164,7 @@ class DataChannelConnection final : public net::NeckoTargetHolder
|
|||
void TransportStateChange(const std::string& aTransportId,
|
||||
TransportLayer::State aState);
|
||||
void CompleteConnect();
|
||||
void SetSignals(const std::string& aTransportId);
|
||||
void SetSignals(const std::string& aTransportId, bool aClient);
|
||||
#endif
|
||||
|
||||
typedef enum {
|
||||
|
@ -216,6 +216,8 @@ class DataChannelConnection final : public net::NeckoTargetHolder
|
|||
void ReadBlob(already_AddRefed<DataChannelConnection> aThis, uint16_t aStream,
|
||||
nsIInputStream* aBlob);
|
||||
|
||||
void GetStreamIds(std::vector<uint16_t>* aStreamList);
|
||||
|
||||
bool SendDeferredMessages();
|
||||
|
||||
protected:
|
||||
|
@ -308,47 +310,16 @@ class DataChannelConnection final : public net::NeckoTargetHolder
|
|||
}
|
||||
#endif
|
||||
|
||||
class Channels {
|
||||
public:
|
||||
Channels() : mMutex("DataChannelConnection::Channels::mMutex") {}
|
||||
void Insert(const RefPtr<DataChannel>& aChannel);
|
||||
bool Remove(const RefPtr<DataChannel>& aChannel);
|
||||
RefPtr<DataChannel> Get(uint16_t aId) const;
|
||||
typedef AutoTArray<RefPtr<DataChannel>, 16> ChannelArray;
|
||||
ChannelArray GetAll() const {
|
||||
MutexAutoLock lock(mMutex);
|
||||
return mChannels;
|
||||
}
|
||||
RefPtr<DataChannel> GetNextChannel(uint16_t aCurrentId) const;
|
||||
|
||||
private:
|
||||
struct IdComparator {
|
||||
bool Equals(const RefPtr<DataChannel>& aChannel, uint16_t aId) const;
|
||||
bool LessThan(const RefPtr<DataChannel>& aChannel, uint16_t aId) const;
|
||||
bool Equals(const RefPtr<DataChannel>& a1,
|
||||
const RefPtr<DataChannel>& a2) const;
|
||||
bool LessThan(const RefPtr<DataChannel>& a1,
|
||||
const RefPtr<DataChannel>& a2) const;
|
||||
};
|
||||
mutable Mutex mMutex;
|
||||
ChannelArray mChannels;
|
||||
};
|
||||
|
||||
bool mSendInterleaved = false;
|
||||
bool mMaxMessageSizeSet = false;
|
||||
uint64_t mMaxMessageSize = 0;
|
||||
// Main thread only
|
||||
Maybe<bool> mAllocateEven;
|
||||
bool mAllocateEven = false;
|
||||
// Data:
|
||||
// NOTE: while this container will auto-expand, increases in the number of
|
||||
// NOTE: while this array will auto-expand, increases in the number of
|
||||
// channels available from the stack must be negotiated!
|
||||
// Accessed from both main and sts, API is threadsafe
|
||||
Channels mChannels;
|
||||
// STS only
|
||||
AutoTArray<RefPtr<DataChannel>, 16> mStreams;
|
||||
uint32_t mCurrentStream = 0;
|
||||
nsDeque mPending; // Holds addref'ed DataChannel's -- careful!
|
||||
// STS and main
|
||||
size_t mNegotiatedIdLimit = 0; // GUARDED_BY(mConnection->mLock)
|
||||
uint8_t mPendingType = PENDING_NONE;
|
||||
// holds data that's come in before a channel is open
|
||||
nsTArray<nsAutoPtr<QueuedDataMessage>> mQueuedData;
|
||||
|
@ -356,8 +327,8 @@ class DataChannelConnection final : public net::NeckoTargetHolder
|
|||
nsTArray<nsAutoPtr<BufferedOutgoingMsg>>
|
||||
mBufferedControl; // GUARDED_BY(mConnection->mLock)
|
||||
|
||||
// Streams pending reset. Accessed from main and STS.
|
||||
AutoTArray<uint16_t, 4> mStreamsResetting; // GUARDED_BY(mConnection->mLock)
|
||||
// Streams pending reset
|
||||
AutoTArray<uint16_t, 4> mStreamsResetting;
|
||||
// accessed from STS thread
|
||||
struct socket* mMasterSocket = nullptr;
|
||||
// cloned from mMasterSocket on successful Connect on STS thread
|
||||
|
@ -414,10 +385,17 @@ class DataChannel {
|
|||
mNegotiated(negotiated),
|
||||
mOrdered(ordered),
|
||||
mFlags(0),
|
||||
mId(0),
|
||||
mIsRecvBinary(false),
|
||||
mBufferedThreshold(0), // default from spec
|
||||
mBufferedAmount(0),
|
||||
mMainThreadEventTarget(connection->GetNeckoTarget()) {
|
||||
if (!ordered) {
|
||||
mFlags |= DATA_CHANNEL_FLAGS_OUT_OF_ORDER_ALLOWED;
|
||||
}
|
||||
if (negotiated) {
|
||||
mFlags |= DATA_CHANNEL_FLAGS_EXTERNAL_NEGOTIATED;
|
||||
}
|
||||
NS_ASSERTION(mConnection, "NULL connection");
|
||||
}
|
||||
|
||||
|
@ -515,10 +493,10 @@ class DataChannel {
|
|||
uint16_t mStream;
|
||||
uint16_t mPrPolicy;
|
||||
uint32_t mPrValue;
|
||||
// Accessed on main and STS
|
||||
const bool mNegotiated;
|
||||
const bool mOrdered;
|
||||
uint32_t mFlags;
|
||||
uint32_t mId;
|
||||
bool mIsRecvBinary;
|
||||
size_t mBufferedThreshold;
|
||||
// Read/written on main only. Decremented via message-passing, because the
|
||||
|
|
|
@ -36,7 +36,10 @@
|
|||
|
||||
#define DATA_CHANNEL_MAX_BINARY_FRAGMENT 0x4000
|
||||
|
||||
#define DATA_CHANNEL_FLAGS_READY 0x00000001
|
||||
#define DATA_CHANNEL_FLAGS_OUT_OF_ORDER_ALLOWED 0x00000002
|
||||
#define DATA_CHANNEL_FLAGS_FINISH_OPEN 0x00000004
|
||||
#define DATA_CHANNEL_FLAGS_EXTERNAL_NEGOTIATED 0x00000008
|
||||
#define DATA_CHANNEL_FLAGS_WAITING_ACK 0x00000010
|
||||
#define DATA_CHANNEL_FLAGS_CLOSING_TOO_LARGE 0x00000020
|
||||
|
||||
|
|
|
@ -121,16 +121,22 @@ TestPassed = [
|
|||
{'regex': re.compile('''(TEST-INFO|TEST-KNOWN-FAIL|TEST-PASS|INFO \| )'''), 'level': INFO},
|
||||
]
|
||||
|
||||
HarnessErrorList = [
|
||||
BaseHarnessErrorList = [
|
||||
{'substr': 'TEST-UNEXPECTED', 'level': ERROR, },
|
||||
{'substr': 'PROCESS-CRASH', 'level': ERROR, },
|
||||
{'substr': 'A content process crashed', 'level': ERROR, },
|
||||
{'regex': re.compile('''ERROR: (Address|Leak)Sanitizer'''), 'level': ERROR, },
|
||||
{'regex': re.compile('''thread '([^']+)' panicked'''), 'level': ERROR, },
|
||||
{'substr': 'pure virtual method called', 'level': ERROR, },
|
||||
{'substr': 'Pure virtual function called!', 'level': ERROR, },
|
||||
]
|
||||
|
||||
HarnessErrorList = BaseHarnessErrorList + [
|
||||
{'substr': 'A content process crashed', 'level': ERROR, },
|
||||
]
|
||||
|
||||
# wpt can have expected crashes so we can't always turn treeherder orange in those cases
|
||||
WptHarnessErrorList = BaseHarnessErrorList
|
||||
|
||||
LogcatErrorList = [
|
||||
{'substr': 'Fatal signal 11 (SIGSEGV)', 'level': ERROR,
|
||||
'explanation': 'This usually indicates the B2G process has crashed'},
|
||||
|
|
|
@ -26,7 +26,7 @@ from mozharness.mozilla.testing.codecoverage import (
|
|||
CodeCoverageMixin,
|
||||
code_coverage_config_options
|
||||
)
|
||||
from mozharness.mozilla.testing.errors import HarnessErrorList
|
||||
from mozharness.mozilla.testing.errors import WptHarnessErrorList
|
||||
|
||||
from mozharness.mozilla.structuredlog import StructuredOutputParser
|
||||
from mozharness.base.log import INFO
|
||||
|
@ -342,7 +342,7 @@ class WebPlatformTest(TestingMixin, MercurialScript, CodeCoverageMixin, AndroidM
|
|||
parser = StructuredOutputParser(config=self.config,
|
||||
log_obj=self.log_obj,
|
||||
log_compact=True,
|
||||
error_list=BaseErrorList + HarnessErrorList,
|
||||
error_list=BaseErrorList + WptHarnessErrorList,
|
||||
allow_crashes=True)
|
||||
|
||||
env = {'MINIDUMP_SAVE_PATH': dirs['abs_blob_upload_dir']}
|
||||
|
|
|
@ -1,4 +0,0 @@
|
|||
[2d.drawImage.zerocanvas.html]
|
||||
[Canvas test: 2d.drawImage.zerocanvas]
|
||||
expected: FAIL
|
||||
|
|
@ -1,2 +1,2 @@
|
|||
leak-threshold: [default:102400]
|
||||
lsan-allowed: [Alloc, Create, MakeUnique, PLDHashTable::Add, Realloc, SetPropertyAsInterface, WeakPtr, already_AddRefed, mozilla::SupportsWeakPtr, mozilla::WeakPtr, mozilla::dom::BrowsingContext::Create, mozilla::dom::ContentParent::CreateBrowser, mozilla::dom::BrowserParent::GetLoadContext, mozilla::extensions::ChannelWrapper::ChannelWrapper, mozilla::net::CacheFile::OnFileOpened, mozilla::net::CacheFileHandles::NewHandle, mozilla::net::nsHttpTransaction::ParseHead, mozilla::net::nsStandardURL::TemplatedMutator, nsLocalFile::Clone, nsNodeSupportsWeakRefTearoff::GetWeakReference, nsSegmentedBuffer::AppendNewSegment]
|
||||
leak-threshold: [default:102400]
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
[2d.shadow.enable.blur.html]
|
||||
[Shadows are drawn if shadowBlur is set]
|
||||
expected:
|
||||
if not e10s: FAIL
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
[2d.shadow.enable.x.html]
|
||||
[Shadows are drawn if shadowOffsetX is set]
|
||||
expected:
|
||||
if not e10s: FAIL
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
[2d.shadow.enable.y.html]
|
||||
[Shadows are drawn if shadowOffsetY is set]
|
||||
expected:
|
||||
if not e10s: FAIL
|
||||
|
|
@ -1,7 +0,0 @@
|
|||
[bigint_value.htm]
|
||||
[Values]
|
||||
expected: FAIL
|
||||
|
||||
[IndexedDB: BigInt keys and values]
|
||||
expected: FAIL
|
||||
|
|
@ -1,39 +0,0 @@
|
|||
[pbkdf2.https.any.html?1001-2000]
|
||||
|
||||
[pbkdf2.https.any.html?3001-4000]
|
||||
|
||||
[pbkdf2.https.any.html?1-1000]
|
||||
|
||||
[pbkdf2.https.any.html?5001-6000]
|
||||
|
||||
[pbkdf2.https.any.html?7001-8000]
|
||||
|
||||
[pbkdf2.https.any.html?2001-3000]
|
||||
|
||||
[pbkdf2.https.any.html?8001-last]
|
||||
|
||||
[pbkdf2.https.any.html?4001-5000]
|
||||
[Derived key of type name: AES-CBC length: 128 using long password, empty salt, SHA-384, with 100000 iterations]
|
||||
expected:
|
||||
if not debug and (os == "linux") and (bits == "32"): TIMEOUT
|
||||
|
||||
|
||||
[pbkdf2.https.any.html?6001-7000]
|
||||
|
||||
[pbkdf2.https.any.worker.html?2001-3000]
|
||||
|
||||
[pbkdf2.https.any.worker.html?1-1000]
|
||||
|
||||
[pbkdf2.https.any.worker.html?1001-2000]
|
||||
|
||||
[pbkdf2.https.any.worker.html?3001-4000]
|
||||
|
||||
[pbkdf2.https.any.worker.html?8001-last]
|
||||
|
||||
[pbkdf2.https.any.worker.html?4001-5000]
|
||||
|
||||
[pbkdf2.https.any.worker.html?7001-8000]
|
||||
|
||||
[pbkdf2.https.any.worker.html?6001-7000]
|
||||
|
||||
[pbkdf2.https.any.worker.html?5001-6000]
|
|
@ -5,3 +5,5 @@
|
|||
[WebCryptoAPI: generateKey() Successful Calls]
|
||||
expected: FAIL
|
||||
|
||||
|
||||
[successes_AES-CBC.https.any.html]
|
||||
|
|
|
@ -5,3 +5,5 @@
|
|||
[WebCryptoAPI: generateKey() Successful Calls]
|
||||
expected: FAIL
|
||||
|
||||
|
||||
[successes_AES-CTR.https.any.html]
|
||||
|
|
|
@ -5,3 +5,5 @@
|
|||
[WebCryptoAPI: generateKey() Successful Calls]
|
||||
expected: FAIL
|
||||
|
||||
|
||||
[successes_AES-GCM.https.any.html]
|
||||
|
|
|
@ -5,3 +5,5 @@
|
|||
[WebCryptoAPI: generateKey() Successful Calls]
|
||||
expected: FAIL
|
||||
|
||||
|
||||
[successes_AES-KW.https.any.html]
|
||||
|
|
|
@ -5,3 +5,5 @@
|
|||
[WebCryptoAPI: generateKey() Successful Calls]
|
||||
expected: FAIL
|
||||
|
||||
|
||||
[successes_ECDH.https.any.html]
|
||||
|
|
|
@ -5,3 +5,5 @@
|
|||
[WebCryptoAPI: generateKey() Successful Calls]
|
||||
expected: FAIL
|
||||
|
||||
|
||||
[successes_ECDSA.https.any.html]
|
||||
|
|
|
@ -5,3 +5,5 @@
|
|||
[WebCryptoAPI: generateKey() Successful Calls]
|
||||
expected: FAIL
|
||||
|
||||
|
||||
[successes_HMAC.https.any.html]
|
||||
|
|
|
@ -125,3 +125,35 @@
|
|||
[WebCryptoAPI: generateKey() Successful Calls]
|
||||
expected: FAIL
|
||||
|
||||
|
||||
[successes_RSA-OAEP.https.any.html?11-20]
|
||||
|
||||
[successes_RSA-OAEP.https.any.html?141-150]
|
||||
|
||||
[successes_RSA-OAEP.https.any.html?131-140]
|
||||
|
||||
[successes_RSA-OAEP.https.any.html?1-10]
|
||||
|
||||
[successes_RSA-OAEP.https.any.html?61-70]
|
||||
|
||||
[successes_RSA-OAEP.https.any.html?21-30]
|
||||
|
||||
[successes_RSA-OAEP.https.any.html?31-40]
|
||||
|
||||
[successes_RSA-OAEP.https.any.html?151-last]
|
||||
|
||||
[successes_RSA-OAEP.https.any.html?71-80]
|
||||
|
||||
[successes_RSA-OAEP.https.any.html?81-90]
|
||||
|
||||
[successes_RSA-OAEP.https.any.html?101-110]
|
||||
|
||||
[successes_RSA-OAEP.https.any.html?41-50]
|
||||
|
||||
[successes_RSA-OAEP.https.any.html?91-100]
|
||||
|
||||
[successes_RSA-OAEP.https.any.html?111-120]
|
||||
|
||||
[successes_RSA-OAEP.https.any.html?51-60]
|
||||
|
||||
[successes_RSA-OAEP.https.any.html?121-130]
|
||||
|
|
|
@ -29,3 +29,11 @@
|
|||
[WebCryptoAPI: generateKey() Successful Calls]
|
||||
expected: FAIL
|
||||
|
||||
|
||||
[successes_RSA-PSS.https.any.html?1-10]
|
||||
|
||||
[successes_RSA-PSS.https.any.html?21-30]
|
||||
|
||||
[successes_RSA-PSS.https.any.html?11-20]
|
||||
|
||||
[successes_RSA-PSS.https.any.html?31-last]
|
||||
|
|
|
@ -29,3 +29,11 @@
|
|||
[WebCryptoAPI: generateKey() Successful Calls]
|
||||
expected: FAIL
|
||||
|
||||
|
||||
[successes_RSASSA-PKCS1-v1_5.https.any.html?21-30]
|
||||
|
||||
[successes_RSASSA-PKCS1-v1_5.https.any.html?1-10]
|
||||
|
||||
[successes_RSASSA-PKCS1-v1_5.https.any.html?11-20]
|
||||
|
||||
[successes_RSASSA-PKCS1-v1_5.https.any.html?31-last]
|
||||
|
|
|
@ -1,19 +0,0 @@
|
|||
[exceptions.html]
|
||||
[Object.getOwnPropertyDescriptor(exception, "name")]
|
||||
expected: FAIL
|
||||
|
||||
[typeof exception.message === "string"]
|
||||
expected: FAIL
|
||||
|
||||
[Object.getOwnPropertyDescriptor(exception, "code")]
|
||||
expected: FAIL
|
||||
|
||||
[In iframe: Object.getOwnPropertyDescriptor(exception, "name")]
|
||||
expected: FAIL
|
||||
|
||||
[In iframe: typeof exception.message === "string"]
|
||||
expected: FAIL
|
||||
|
||||
[In iframe: Object.getOwnPropertyDescriptor(exception, "code")]
|
||||
expected: FAIL
|
||||
|
|
@ -1,4 +0,0 @@
|
|||
[Accelerometer_insecure_context.html]
|
||||
[Accelerometer Test: insecure context]
|
||||
expected: FAIL
|
||||
|
|
@ -0,0 +1 @@
|
|||
leak-threshold: [default:2969600]
|
|
@ -1,7 +0,0 @@
|
|||
[AmbientLightSensor_insecure_context.html]
|
||||
[throw a 'SecurityError' when construct AmbientLightSensor in an insecure context]
|
||||
expected: FAIL
|
||||
|
||||
[AmbientLightSensor Test: insecure context]
|
||||
expected: FAIL
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
[worklet-animation-get-timing-on-worklet-thread.https.html]
|
||||
expected: TIMEOUT
|
|
@ -0,0 +1 @@
|
|||
leak-threshold: [default:51200]
|
|
@ -1,12 +0,0 @@
|
|||
[idlharness.any.html]
|
||||
[Navigator interface: operation sendBacon(USVString, BodyInit)]
|
||||
expected: FAIL
|
||||
|
||||
[Navigator interface: navigator must inherit property "sendBacon(USVString, BodyInit)" with the proper type]
|
||||
expected: FAIL
|
||||
|
||||
[Navigator interface: calling sendBacon(USVString, BodyInit) on navigator with too few arguments must throw TypeError]
|
||||
expected: FAIL
|
||||
|
||||
|
||||
[idlharness.any.worker.html]
|
|
@ -0,0 +1,4 @@
|
|||
[buffer-is-detached.https.html]
|
||||
[writeValue() fails when passed a detached buffer]
|
||||
expected: FAIL
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
[buffer-is-detached.https.html]
|
||||
[writeValue() fails when passed a detached buffer]
|
||||
expected: FAIL
|
||||
|
|
@ -1,4 +0,0 @@
|
|||
[idl-NavigatorBluetooth.html]
|
||||
[navigator.bluetooth IDL test]
|
||||
expected: FAIL
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
[accept_ch_feature_policy.tentative.sub.https.html]
|
||||
[Accept-CH header test]
|
||||
expected: FAIL
|
||||
|
||||
[Cross-Origin Accept-CH header test]
|
||||
expected: FAIL
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
[accept_ch_no_feature_policy.tentative.sub.https.html]
|
||||
[Accept-CH header test]
|
||||
expected: FAIL
|
||||
|
|
@ -4,14 +4,12 @@
|
|||
|
||||
[Window interface: attribute orientation]
|
||||
expected:
|
||||
if (os == "android") and not e10s: PASS
|
||||
if (os == "android") and e10s: PASS
|
||||
if os == "android": PASS
|
||||
FAIL
|
||||
|
||||
[Window interface: window must inherit property "orientation" with the proper type]
|
||||
expected:
|
||||
if (os == "android") and not e10s: PASS
|
||||
if (os == "android") and e10s: PASS
|
||||
if os == "android": PASS
|
||||
FAIL
|
||||
|
||||
[HTMLBodyElement interface: attribute onorientationchange]
|
||||
|
@ -19,13 +17,14 @@
|
|||
|
||||
[Window interface: window must inherit property "onorientationchange" with the proper type]
|
||||
expected:
|
||||
if (os == "android") and not e10s: PASS
|
||||
if (os == "android") and e10s: PASS
|
||||
if os == "android": PASS
|
||||
FAIL
|
||||
|
||||
[Window interface: attribute onorientationchange]
|
||||
expected:
|
||||
if (os == "android") and not e10s: PASS
|
||||
if (os == "android") and e10s: PASS
|
||||
if os == "android": PASS
|
||||
FAIL
|
||||
|
||||
[idlharness]
|
||||
expected: FAIL
|
||||
|
||||
|
|
|
@ -1,8 +0,0 @@
|
|||
[connect-src-beacon-blocked.sub.html]
|
||||
type: testharness
|
||||
[sendBeacon should not throw.]
|
||||
expected: FAIL
|
||||
|
||||
[redirect case]
|
||||
expected: TIMEOUT
|
||||
|
|
@ -1,5 +0,0 @@
|
|||
[connect-src-websocket-blocked.sub.html]
|
||||
type: testharness
|
||||
[WebSocket should fire error event.]
|
||||
expected: FAIL
|
||||
|
|
@ -1,7 +0,0 @@
|
|||
[connect-src-xmlhttprequest-blocked.sub.html]
|
||||
[XHR should fire onerror.]
|
||||
expected: TIMEOUT
|
||||
|
||||
[XHR should fire onerror after a redirect.]
|
||||
expected: FAIL
|
||||
|
|
@ -1,6 +1,8 @@
|
|||
[subsumption_algorithm-host_sources-ports.html]
|
||||
[Specified ports must match.]
|
||||
expected: FAIL
|
||||
expected:
|
||||
if webrender and debug and (os == "linux"): FAIL
|
||||
FAIL
|
||||
|
||||
[Returned CSP should be subsumed if the port is specified but is not default for a more secure scheme.]
|
||||
expected: FAIL
|
||||
|
|
|
@ -1,5 +0,0 @@
|
|||
[form-action-src-blocked.sub.html]
|
||||
type: testharness
|
||||
[form-action-src-blocked]
|
||||
expected: FAIL
|
||||
|
|
@ -1,5 +0,0 @@
|
|||
[form-action-src-get-blocked.sub.html]
|
||||
type: testharness
|
||||
[form-action-src-allowed]
|
||||
expected: FAIL
|
||||
|
|
@ -1,5 +0,0 @@
|
|||
[form-action-src-javascript-blocked.sub.html]
|
||||
type: testharness
|
||||
[form-action-src-javascript-blocked]
|
||||
expected: FAIL
|
||||
|
|
@ -1,6 +1,5 @@
|
|||
[dedicated-inheritance.html]
|
||||
disabled: https://bugzilla.mozilla.org/show_bug.cgi?id=1556907
|
||||
|
||||
expected: ERROR
|
||||
[Same-origin 'fetch()' in http:?pipe=sub|header(Content-Security-Policy,connect-src%20%27none%27)]
|
||||
expected: FAIL
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[child-navigates-parent-blocked.sub.html]
|
||||
disabled:
|
||||
if os == "android" and not e10s: https://bugzilla.mozilla.org/show_bug.cgi?id=1511193
|
||||
if (os == "android") and not e10s: https://bugzilla.mozilla.org/show_bug.cgi?id=1511193
|
||||
[Violation report status OK.]
|
||||
expected: FAIL
|
||||
|
||||
|
|
|
@ -0,0 +1,4 @@
|
|||
[cookies-without-samesite-must-be-secure.https.tentative.html]
|
||||
[SameSite=None cookies are rejected unless the Secure attribute is set.]
|
||||
expected: FAIL
|
||||
|
|
@ -8,3 +8,23 @@
|
|||
[Cross-site redirecting to subdomain fetches are strictly same-site]
|
||||
expected: FAIL
|
||||
|
||||
|
||||
[fetch.html?samesite-by-default-cookies.tentative]
|
||||
[Subdomain redirecting to cross-site fetches are cross-site]
|
||||
expected: FAIL
|
||||
|
||||
[Same-host redirecting to cross-site fetches are cross-site]
|
||||
expected: FAIL
|
||||
|
||||
[Cross-site redirecting to same-host fetches are strictly same-site]
|
||||
expected: FAIL
|
||||
|
||||
[Cross-site redirecting to subdomain fetches are strictly same-site]
|
||||
expected: FAIL
|
||||
|
||||
[Cross-site redirecting to cross-site fetches are cross-site]
|
||||
expected: FAIL
|
||||
|
||||
[Cross-site fetches are cross-site]
|
||||
expected: FAIL
|
||||
|
||||
|
|
|
@ -1,4 +0,0 @@
|
|||
[form-get-blank-reload.html]
|
||||
[Untitled]
|
||||
expected: FAIL
|
||||
|
|
@ -8,3 +8,11 @@
|
|||
[Cross-site redirecting to subdomain top-level form GETs are strictly same-site]
|
||||
expected: FAIL
|
||||
|
||||
|
||||
[form-get-blank.html?samesite-by-default-cookies.tentative]
|
||||
[Cross-site redirecting to subdomain top-level form GETs are strictly same-site]
|
||||
expected: FAIL
|
||||
|
||||
[Cross-site redirecting to same-host top-level form GETs are strictly same-site]
|
||||
expected: FAIL
|
||||
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
[form-post-blank-reload.html]
|
||||
expected:
|
||||
if (os == "android") and not e10s: TIMEOUT
|
||||
if (os == "android") and e10s: TIMEOUT
|
||||
if os == "android": TIMEOUT
|
||||
ERROR
|
||||
[Untitled]
|
||||
expected:
|
||||
|
@ -9,20 +8,25 @@
|
|||
FAIL
|
||||
|
||||
[Reloaded same-host top-level form POSTs are strictly same-site]
|
||||
expected:
|
||||
if (os == "android") and not e10s: TIMEOUT
|
||||
if debug and not e10s and (os == "linux"): TIMEOUT
|
||||
if (os == "android") and e10s: TIMEOUT
|
||||
expected: TIMEOUT
|
||||
|
||||
[Reloaded subdomain top-level form POSTs are strictly same-site]
|
||||
expected:
|
||||
if (os == "android") and not e10s: NOTRUN
|
||||
if debug and not e10s and (os == "linux"): NOTRUN
|
||||
if (os == "android") and e10s: NOTRUN
|
||||
expected: NOTRUN
|
||||
|
||||
[Reloaded cross-site top-level form POSTs are not same-site]
|
||||
expected:
|
||||
if (os == "android") and not e10s: NOTRUN
|
||||
if debug and not e10s and (os == "linux"): NOTRUN
|
||||
if (os == "android") and e10s: NOTRUN
|
||||
expected: NOTRUN
|
||||
|
||||
|
||||
[form-post-blank-reload.html?samesite-by-default-cookies.tentative]
|
||||
expected:
|
||||
if os == "android": TIMEOUT
|
||||
ERROR
|
||||
[Reloaded same-host top-level form POSTs are strictly same-site]
|
||||
expected: TIMEOUT
|
||||
|
||||
[Reloaded subdomain top-level form POSTs are strictly same-site]
|
||||
expected: NOTRUN
|
||||
|
||||
[Reloaded cross-site top-level form POSTs are not same-site]
|
||||
expected: NOTRUN
|
||||
|
||||
|
|
|
@ -8,3 +8,23 @@
|
|||
[Cross-site redirecting to subdomain top-level form POSTs are strictly same-site]
|
||||
expected: FAIL
|
||||
|
||||
|
||||
[form-post-blank.html?samesite-by-default-cookies.tentative]
|
||||
[Cross-site redirecting to same-host top-level form POSTs are strictly same-site]
|
||||
expected: FAIL
|
||||
|
||||
[Cross-site top-level form POSTs are cross-site]
|
||||
expected: FAIL
|
||||
|
||||
[Same-host redirecting to cross-site top-level form POSTs are cross-site]
|
||||
expected: FAIL
|
||||
|
||||
[Cross-site redirecting to subdomain top-level form POSTs are strictly same-site]
|
||||
expected: FAIL
|
||||
|
||||
[Cross-site redirecting to cross-site top-level form POSTs are cross-site]
|
||||
expected: FAIL
|
||||
|
||||
[Subdomain redirecting to cross-site top-level form POSTs are cross-site]
|
||||
expected: FAIL
|
||||
|
||||
|
|
|
@ -2,3 +2,8 @@
|
|||
[Untitled]
|
||||
expected: FAIL
|
||||
|
||||
|
||||
[iframe-reload.html?samesite-by-default-cookies.tentative]
|
||||
[Reloaded cross-site fetches are cross-site]
|
||||
expected: FAIL
|
||||
|
||||
|
|
|
@ -8,3 +8,23 @@
|
|||
[Cross-site redirecting to subdomain fetches are strictly same-site]
|
||||
expected: FAIL
|
||||
|
||||
|
||||
[iframe.html?samesite-by-default-cookies.tentative]
|
||||
[Subdomain redirecting to cross-site fetches are cross-site]
|
||||
expected: FAIL
|
||||
|
||||
[Same-host redirecting to cross-site fetches are cross-site]
|
||||
expected: FAIL
|
||||
|
||||
[Cross-site redirecting to same-host fetches are strictly same-site]
|
||||
expected: FAIL
|
||||
|
||||
[Cross-site redirecting to subdomain fetches are strictly same-site]
|
||||
expected: FAIL
|
||||
|
||||
[Cross-site redirecting to cross-site fetches are cross-site]
|
||||
expected: FAIL
|
||||
|
||||
[Cross-site fetches are cross-site]
|
||||
expected: FAIL
|
||||
|
||||
|
|
|
@ -8,3 +8,23 @@
|
|||
[Cross-site redirecting to subdomain images are strictly same-site]
|
||||
expected: FAIL
|
||||
|
||||
|
||||
[img.html?samesite-by-default-cookies.tentative]
|
||||
[Cross-site redirecting to cross-site images are cross-site]
|
||||
expected: FAIL
|
||||
|
||||
[Subdomain redirecting to cross-site images are cross-site]
|
||||
expected: FAIL
|
||||
|
||||
[Cross-site images are cross-site]
|
||||
expected: FAIL
|
||||
|
||||
[Same-host redirecting to cross-site images are cross-site]
|
||||
expected: FAIL
|
||||
|
||||
[Cross-site redirecting to same-host images are strictly same-site]
|
||||
expected: FAIL
|
||||
|
||||
[Cross-site redirecting to subdomain images are strictly same-site]
|
||||
expected: FAIL
|
||||
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
[setcookie-lax.html?samesite-by-default-cookies.tentative]
|
||||
[Cross-site window shouldn't be able to set `SameSite=Lax` or `SameSite=Strict` cookies.]
|
||||
expected: FAIL
|
||||
|
||||
|
||||
[setcookie-lax.html]
|
|
@ -1,7 +0,0 @@
|
|||
[window-open-reload.html]
|
||||
[Untitled]
|
||||
expected: FAIL
|
||||
|
||||
[Reloaded ross-site auxiliary navigations are laxly same-site]
|
||||
expected: FAIL
|
||||
|
|
@ -1,4 +0,0 @@
|
|||
[window-open.html]
|
||||
[Untitled]
|
||||
expected: FAIL
|
||||
|
|
@ -1,4 +0,0 @@
|
|||
[preflight-failure.htm]
|
||||
[Should throw error if preflight respond with 100]
|
||||
expected: TIMEOUT
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
[c44-ln-box-001.xht]
|
||||
expected:
|
||||
if (os == "android") and debug: FAIL
|
|
@ -0,0 +1,2 @@
|
|||
[adjoining-float-nested-forced-clearance-002.html]
|
||||
expected: FAIL
|
|
@ -1,3 +1,5 @@
|
|||
[font-011.xht]
|
||||
expected:
|
||||
if os == "win": FAIL
|
||||
if os == "linux": PASS
|
||||
if os == "mac": PASS
|
||||
FAIL
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
[font-012.xht]
|
||||
expected:
|
||||
if os == "win": FAIL
|
||||
if os == "mac": PASS
|
||||
if os == "linux": PASS
|
||||
FAIL
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
[font-013.xht]
|
||||
expected:
|
||||
if os == "win": FAIL
|
||||
if os == "mac": PASS
|
||||
if os == "linux": PASS
|
||||
FAIL
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
[font-014.xht]
|
||||
expected:
|
||||
if os == "win": FAIL
|
||||
if os == "mac": PASS
|
||||
if os == "linux": PASS
|
||||
FAIL
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
[font-015.xht]
|
||||
expected:
|
||||
if os == "win": FAIL
|
||||
if os == "mac": PASS
|
||||
if os == "linux": PASS
|
||||
FAIL
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
[font-016.xht]
|
||||
expected:
|
||||
if os == "win": FAIL
|
||||
if os == "linux": PASS
|
||||
if os == "mac": PASS
|
||||
FAIL
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
[font-029.xht]
|
||||
expected:
|
||||
if os == "win": FAIL
|
||||
if os == "mac": PASS
|
||||
if os == "linux": PASS
|
||||
FAIL
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
[font-030.xht]
|
||||
expected:
|
||||
if os == "win": FAIL
|
||||
if os == "mac": PASS
|
||||
if os == "linux": PASS
|
||||
FAIL
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
[font-031.xht]
|
||||
expected:
|
||||
if os == "win": FAIL
|
||||
if os == "mac": PASS
|
||||
if os == "linux": PASS
|
||||
FAIL
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
[font-032.xht]
|
||||
expected:
|
||||
if os == "win": FAIL
|
||||
if os == "mac": PASS
|
||||
if os == "linux": PASS
|
||||
FAIL
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
[font-042.xht]
|
||||
expected:
|
||||
if os == "win": FAIL
|
||||
if os == "mac": PASS
|
||||
if os == "linux": PASS
|
||||
FAIL
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
[font-043.xht]
|
||||
expected:
|
||||
if os == "win": FAIL
|
||||
if os == "linux": PASS
|
||||
if os == "mac": PASS
|
||||
FAIL
|
||||
|
|
|
@ -0,0 +1,2 @@
|
|||
[margin-collapse-through-percentage-height-block.html]
|
||||
expected: FAIL
|
|
@ -0,0 +1,2 @@
|
|||
[margin-collapse-through-percentage-padding.html]
|
||||
expected: FAIL
|
|
@ -2,3 +2,5 @@
|
|||
disabled:
|
||||
if os == "linux": https://bugzilla.mozilla.org/show_bug.cgi?id=1383229
|
||||
if os == "win": https://bugzilla.mozilla.org/show_bug.cgi?id=1383229
|
||||
expected:
|
||||
if not e10s: FAIL
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
[text-indent-007.xht]
|
||||
expected:
|
||||
if os == "android": FAIL
|
|
@ -0,0 +1,3 @@
|
|||
[text-indent-008.xht]
|
||||
expected:
|
||||
if os == "android": FAIL
|
|
@ -0,0 +1,3 @@
|
|||
[text-indent-019.xht]
|
||||
expected:
|
||||
if os == "android": FAIL
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче