Bug 1288626 Part 8 - Add shape-outside support to style system. r=heycam

I have to move the definition of FragmentOrURL, StyleBasicShape and
StyleShapeSource prior to where nsStyleDisplay::mShapeOutside is defined since
the template struct need to be fully defined before using as a member variable.

Use SetIdent() in CreatePrimitiveValueForBasicShapeOrURL() in
nsComputedDOMStyle.cpp per bug 1288626 comment 6.

MozReview-Commit-ID: 1KZS299CFul
This commit is contained in:
Ting-Yu Lin 2016-08-09 00:15:06 +08:00
Родитель 62e2bf343b
Коммит 82b2646797
16 изменённых файлов: 683 добавлений и 525 удалений

Просмотреть файл

@ -823,6 +823,7 @@ PropertySupportsVariant(nsCSSProperty aPropertyID, uint32_t aVariant)
case eCSSProperty_content:
case eCSSProperty_cursor:
case eCSSProperty_clip_path:
case eCSSProperty_shape_outside:
supported = VARIANT_URL;
break;

Просмотреть файл

@ -1066,6 +1066,7 @@ protected:
bool ParseShadowItem(nsCSSValue& aValue, bool aIsBoxShadow);
bool ParseShadowList(nsCSSProperty aProperty);
bool ParseShapeOutside(nsCSSValue& aValue);
bool ParseTransitionProperty();
bool ParseTransitionTimingFunctionValues(nsCSSValue& aValue);
bool ParseTransitionTimingFunctionValueComponent(float& aComponent,
@ -1324,6 +1325,8 @@ protected:
}
/* Functions for basic shapes */
bool ParseReferenceBoxAndBasicShape(nsCSSValue& aValue,
const KTableEntry aBoxKeywordTable[]);
bool ParseBasicShape(nsCSSValue& aValue, bool* aConsumedTokens);
bool ParsePolygonFunction(nsCSSValue& aValue);
bool ParseCircleOrEllipseFunction(nsCSSKeyword, nsCSSValue& aValue);
@ -11759,6 +11762,8 @@ CSSParserImpl::ParseSingleValuePropertyByFunction(nsCSSValue& aValue,
return ParseScrollSnapDestination(aValue);
case eCSSProperty_scroll_snap_coordinate:
return ParseScrollSnapCoordinate(aValue);
case eCSSProperty_shape_outside:
return ParseShapeOutside(aValue);
case eCSSProperty_text_align:
return ParseTextAlign(aValue);
case eCSSProperty_text_align_last:
@ -16165,20 +16170,13 @@ CSSParserImpl::ParseBasicShape(nsCSSValue& aValue, bool* aConsumedTokens)
}
}
/* Parse a clip-path url to a <clipPath> element or a basic shape. */
bool CSSParserImpl::ParseClipPath()
bool
CSSParserImpl::ParseReferenceBoxAndBasicShape(
nsCSSValue& aValue,
const KTableEntry aBoxKeywordTable[])
{
nsCSSValue value;
if (!ParseSingleTokenVariant(value, VARIANT_HUO, nullptr)) {
if (!nsLayoutUtils::CSSClipPathShapesEnabled()) {
// With CSS Clip Path Shapes disabled, we should only accept
// SVG clipPath reference and none.
REPORT_UNEXPECTED_TOKEN(PEExpectedNoneOrURL);
return false;
}
nsCSSValue referenceBox;
bool hasBox = ParseEnum(referenceBox, nsCSSProps::kClipPathGeometryBoxKTable);
bool hasBox = ParseEnum(referenceBox, aBoxKeywordTable);
const bool boxCameFirst = hasBox;
@ -16194,7 +16192,7 @@ bool CSSParserImpl::ParseClipPath()
// Check if the second argument is a reference box if the first wasn't.
if (!hasBox) {
hasBox = ParseEnum(referenceBox, nsCSSProps::kClipPathGeometryBoxKTable);
hasBox = ParseEnum(referenceBox, aBoxKeywordTable);
}
RefPtr<nsCSSValue::Array> fullValue =
@ -16210,13 +16208,45 @@ bool CSSParserImpl::ParseClipPath()
fullValue->Item(0) = basicShape;
}
value.SetArrayValue(fullValue, eCSSUnit_Array);
aValue.SetArrayValue(fullValue, eCSSUnit_Array);
return true;
}
/* Parse a clip-path url to a <clipPath> element or a basic shape. */
bool CSSParserImpl::ParseClipPath()
{
nsCSSValue value;
if (!ParseSingleTokenVariant(value, VARIANT_HUO, nullptr)) {
if (!nsLayoutUtils::CSSClipPathShapesEnabled()) {
// With CSS Clip Path Shapes disabled, we should only accept
// SVG clipPath reference and none.
REPORT_UNEXPECTED_TOKEN(PEExpectedNoneOrURL);
return false;
}
if (!ParseReferenceBoxAndBasicShape(
value, nsCSSProps::kClipPathGeometryBoxKTable)) {
return false;
}
}
AppendValue(eCSSProperty_clip_path, value);
return true;
}
// none | [ <basic-shape> || <shape-box> ] | <image>
bool
CSSParserImpl::ParseShapeOutside(nsCSSValue& aValue)
{
if (ParseSingleTokenVariant(aValue, VARIANT_HUO, nullptr)) {
// 'inherit', 'initial', 'unset', 'none', and <image> url must be alone.
return true;
}
return ParseReferenceBoxAndBasicShape(
aValue, nsCSSProps::kShapeOutsideShapeBoxKTable);
}
bool CSSParserImpl::ParseTransformOrigin(bool aPerspective)
{
nsCSSValuePair position;

Просмотреть файл

@ -3708,6 +3708,18 @@ CSS_PROP_DISPLAY(
kScrollSnapTypeKTable,
CSS_PROP_NO_OFFSET,
eStyleAnimType_None)
CSS_PROP_DISPLAY(
shape-outside,
shape_outside,
ShapeOutside,
CSS_PROPERTY_PARSE_VALUE |
CSS_PROPERTY_VALUE_PARSER_FUNCTION |
CSS_PROPERTY_APPLIES_TO_FIRST_LETTER,
"layout.css.shape-outside.enabled",
0,
nullptr,
CSS_PROP_NO_OFFSET,
eStyleAnimType_None) // FIXME: Bug 1289049 for adding animation support
CSS_PROP_SVG(
shape-rendering,
shape_rendering,

Просмотреть файл

@ -2341,6 +2341,14 @@ const KTableEntry nsCSSProps::kMaskTypeKTable[] = {
{ eCSSKeyword_UNKNOWN, -1 }
};
const KTableEntry nsCSSProps::kShapeOutsideShapeBoxKTable[] = {
{ eCSSKeyword_content_box, StyleShapeOutsideShapeBox::Content },
{ eCSSKeyword_padding_box, StyleShapeOutsideShapeBox::Padding },
{ eCSSKeyword_border_box, StyleShapeOutsideShapeBox::Border },
{ eCSSKeyword_margin_box, StyleShapeOutsideShapeBox::Margin },
{ eCSSKeyword_UNKNOWN, -1 }
};
const KTableEntry nsCSSProps::kShapeRenderingKTable[] = {
{ eCSSKeyword_auto, NS_STYLE_SHAPE_RENDERING_AUTO },
{ eCSSKeyword_optimizespeed, NS_STYLE_SHAPE_RENDERING_OPTIMIZESPEED },

Просмотреть файл

@ -742,6 +742,7 @@ public:
static const KTableEntry kFillRuleKTable[];
static const KTableEntry kFilterFunctionKTable[];
static const KTableEntry kImageRenderingKTable[];
static const KTableEntry kShapeOutsideShapeBoxKTable[];
static const KTableEntry kShapeRenderingKTable[];
static const KTableEntry kStrokeLinecapKTable[];
static const KTableEntry kStrokeLinejoinKTable[];

Просмотреть файл

@ -1428,6 +1428,12 @@ nsCSSValue::AppendToString(nsCSSProperty aProperty, nsAString& aResult,
aResult);
break;
case eCSSProperty_shape_outside:
AppendASCIItoUTF16(nsCSSProps::ValueToKeyword(intValue,
nsCSSProps::kShapeOutsideShapeBoxKTable),
aResult);
break;
case eCSSProperty_contain:
if (intValue & NS_STYLE_CONTAIN_STRICT) {
NS_ASSERTION(intValue == (NS_STYLE_CONTAIN_STRICT | NS_STYLE_CONTAIN_ALL_BITS),
@ -2522,7 +2528,8 @@ nsCSSValuePairList::AppendToString(nsCSSProperty aProperty,
if (nsCSSProps::PropHasFlags(aProperty,
CSS_PROPERTY_VALUE_LIST_USES_COMMAS) ||
aProperty == eCSSProperty_clip_path)
aProperty == eCSSProperty_clip_path ||
aProperty == eCSSProperty_shape_outside)
aResult.Append(char16_t(','));
aResult.Append(char16_t(' '));
}

Просмотреть файл

@ -5995,10 +5995,12 @@ nsComputedDOMStyle::CreatePrimitiveValueForBasicShape(
return functionValue.forget();
}
template<typename ReferenceBox>
already_AddRefed<CSSValue>
nsComputedDOMStyle::CreatePrimitiveValueForClipPath(
nsComputedDOMStyle::CreatePrimitiveValueForShapeSource(
const StyleBasicShape* aStyleBasicShape,
StyleClipPathGeometryBox aSizingBox)
ReferenceBox aReferenceBox,
const KTableEntry aBoxKeywordTable[])
{
RefPtr<nsDOMCSSValueList> valueList = GetROCSSValueList(false);
if (aStyleBasicShape) {
@ -6006,36 +6008,35 @@ nsComputedDOMStyle::CreatePrimitiveValueForClipPath(
CreatePrimitiveValueForBasicShape(aStyleBasicShape));
}
if (aSizingBox == StyleClipPathGeometryBox::NoBox) {
if (aReferenceBox == ReferenceBox::NoBox) {
return valueList.forget();
}
nsAutoString boxString;
AppendASCIItoUTF16(
nsCSSProps::ValueToKeyword(aSizingBox,
nsCSSProps::kClipPathGeometryBoxKTable),
boxString);
RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
val->SetString(boxString);
val->SetIdent(nsCSSProps::ValueToKeywordEnum(aReferenceBox, aBoxKeywordTable));
valueList->AppendCSSValue(val.forget());
return valueList.forget();
}
template<typename ReferenceBox>
already_AddRefed<CSSValue>
nsComputedDOMStyle::DoGetClipPath()
nsComputedDOMStyle::GetShapeSource(
const StyleShapeSource<ReferenceBox>& aShapeSource,
const KTableEntry aBoxKeywordTable[])
{
const nsStyleSVGReset* svg = StyleSVGReset();
switch (svg->mClipPath.GetType()) {
switch (aShapeSource.GetType()) {
case StyleShapeSourceType::Shape:
return CreatePrimitiveValueForClipPath(svg->mClipPath.GetBasicShape(),
svg->mClipPath.GetReferenceBox());
return CreatePrimitiveValueForShapeSource(aShapeSource.GetBasicShape(),
aShapeSource.GetReferenceBox(),
aBoxKeywordTable);
case StyleShapeSourceType::Box:
return CreatePrimitiveValueForClipPath(nullptr,
svg->mClipPath.GetReferenceBox());
return CreatePrimitiveValueForShapeSource(nullptr,
aShapeSource.GetReferenceBox(),
aBoxKeywordTable);
case StyleShapeSourceType::URL: {
// Bug 1288812 - we should only serialize fragment for local-ref URL.
nsCOMPtr<nsIURI> pathURI = svg->mClipPath.GetURL()->GetSourceURL();
nsCOMPtr<nsIURI> pathURI = aShapeSource.GetURL()->GetSourceURL();
RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
val->SetURI(pathURI);
return val.forget();
@ -6051,6 +6052,20 @@ nsComputedDOMStyle::DoGetClipPath()
return nullptr;
}
already_AddRefed<CSSValue>
nsComputedDOMStyle::DoGetClipPath()
{
return GetShapeSource(StyleSVGReset()->mClipPath,
nsCSSProps::kClipPathGeometryBoxKTable);
}
already_AddRefed<CSSValue>
nsComputedDOMStyle::DoGetShapeOutside()
{
return GetShapeSource(StyleDisplay()->mShapeOutside,
nsCSSProps::kShapeOutsideShapeBoxKTable);
}
void
nsComputedDOMStyle::SetCssTextToCoord(nsAString& aCssText,
const nsStyleCoord& aCoord)

Просмотреть файл

@ -481,6 +481,7 @@ private:
already_AddRefed<CSSValue> DoGetScrollSnapPointsY();
already_AddRefed<CSSValue> DoGetScrollSnapDestination();
already_AddRefed<CSSValue> DoGetScrollSnapCoordinate();
already_AddRefed<CSSValue> DoGetShapeOutside();
/* User interface properties */
already_AddRefed<CSSValue> DoGetCursor();
@ -643,9 +644,17 @@ private:
already_AddRefed<CSSValue> CreatePrimitiveValueForStyleFilter(
const nsStyleFilter& aStyleFilter);
already_AddRefed<CSSValue> CreatePrimitiveValueForClipPath(
template<typename ReferenceBox>
already_AddRefed<CSSValue>
GetShapeSource(const mozilla::StyleShapeSource<ReferenceBox>& aShapeSource,
const KTableEntry aBoxKeywordTable[]);
template<typename ReferenceBox>
already_AddRefed<CSSValue>
CreatePrimitiveValueForShapeSource(
const mozilla::StyleBasicShape* aStyleBasicShape,
mozilla::StyleClipPathGeometryBox aSizingBox);
ReferenceBox aReferenceBox,
const KTableEntry aBoxKeywordTable[]);
// Helper function for computing basic shape styles.
already_AddRefed<CSSValue> CreatePrimitiveValueForBasicShape(

Просмотреть файл

@ -217,6 +217,7 @@ COMPUTED_STYLE_PROP(scroll_snap_points_x, ScrollSnapPointsX)
COMPUTED_STYLE_PROP(scroll_snap_points_y, ScrollSnapPointsY)
COMPUTED_STYLE_PROP(scroll_snap_type_x, ScrollSnapTypeX)
COMPUTED_STYLE_PROP(scroll_snap_type_y, ScrollSnapTypeY)
COMPUTED_STYLE_PROP(shape_outside, ShapeOutside)
//// COMPUTED_STYLE_PROP(size, Size)
COMPUTED_STYLE_PROP(table_layout, TableLayout)
COMPUTED_STYLE_PROP(text_align, TextAlign)

Просмотреть файл

@ -119,6 +119,14 @@ SetImageRequest(function<void(imgRequestProxy*)> aCallback,
}
}
template<typename ReferenceBox>
static void
SetStyleShapeSourceToCSSValue(StyleShapeSource<ReferenceBox>* aShapeSource,
const nsCSSValue* aValue,
nsStyleContext* aStyleContext,
nsPresContext* aPresContext,
RuleNodeCacheConditions& aConditions);
/* Helper function to convert a CSS <position> specified value into its
* computed-style form. */
static void
@ -6434,6 +6442,35 @@ nsRuleNode::ComputeDisplayData(void* aStartStruct,
parentDisplay->mOrient,
NS_STYLE_ORIENT_INLINE);
// shape-outside: none | [ <basic-shape> || <shape-box> ] | <image>
const nsCSSValue* shapeOutsideValue = aRuleData->ValueForShapeOutside();
switch (shapeOutsideValue->GetUnit()) {
case eCSSUnit_Null:
break;
case eCSSUnit_None:
case eCSSUnit_Initial:
case eCSSUnit_Unset:
display->mShapeOutside = StyleShapeOutside();
break;
case eCSSUnit_Inherit:
conditions.SetUncacheable();
display->mShapeOutside = parentDisplay->mShapeOutside;
break;
case eCSSUnit_URL: {
display->mShapeOutside = StyleShapeOutside();
display->mShapeOutside.SetURL(shapeOutsideValue);
break;
}
case eCSSUnit_Array: {
display->mShapeOutside = StyleShapeOutside();
SetStyleShapeSourceToCSSValue(&display->mShapeOutside, shapeOutsideValue,
aContext, mPresContext, conditions);
break;
}
default:
MOZ_ASSERT_UNREACHABLE("Unrecognized shape-outside unit!");
}
COMPUTE_END_RESET(Display, display)
}
@ -9730,8 +9767,10 @@ GetStyleBasicShapeFromCSSValue(const nsCSSValue& aValue,
return basicShape.forget();
}
template<typename ReferenceBox>
static void
SetStyleClipPathToCSSValue(StyleClipPath* aStyleClipPath,
SetStyleShapeSourceToCSSValue(
StyleShapeSource<ReferenceBox>* aShapeSource,
const nsCSSValue* aValue,
nsStyleContext* aStyleContext,
nsPresContext* aPresContext,
@ -9742,32 +9781,28 @@ SetStyleClipPathToCSSValue(StyleClipPath* aStyleClipPath,
const nsCSSValue::Array* array = aValue->GetArrayValue();
MOZ_ASSERT(array->Count() == 1 || array->Count() == 2,
"Expect one or both of a shape function and geometry-box");
"Expect one or both of a shape function and a reference box");
StyleClipPathGeometryBox sizingBox = StyleClipPathGeometryBox::NoBox;
ReferenceBox referenceBox = ReferenceBox::NoBox;
RefPtr<StyleBasicShape> basicShape;
for (size_t i = 0; i < array->Count(); ++i) {
if (array->Item(i).GetUnit() == eCSSUnit_Enumerated) {
int32_t type = array->Item(i).GetIntValue();
if (type > uint8_t(StyleClipPathGeometryBox::View) ||
type < uint8_t(StyleClipPathGeometryBox::NoBox)) {
NS_NOTREACHED("unexpected reference box");
return;
}
sizingBox = static_cast<StyleClipPathGeometryBox>(type);
} else if (array->Item(i).GetUnit() == eCSSUnit_Function) {
basicShape = GetStyleBasicShapeFromCSSValue(array->Item(i), aStyleContext,
const nsCSSValue& item = array->Item(i);
if (item.GetUnit() == eCSSUnit_Enumerated) {
referenceBox = static_cast<ReferenceBox>(item.GetIntValue());
} else if (item.GetUnit() == eCSSUnit_Function) {
basicShape = GetStyleBasicShapeFromCSSValue(item, aStyleContext,
aPresContext, aConditions);
} else {
NS_NOTREACHED("unexpected value");
MOZ_ASSERT_UNREACHABLE("Unexpected unit!");
return;
}
}
if (basicShape) {
aStyleClipPath->SetBasicShape(basicShape, sizingBox);
aShapeSource->SetBasicShape(basicShape, referenceBox);
} else {
aStyleClipPath->SetReferenceBox(sizingBox);
aShapeSource->SetReferenceBox(referenceBox);
}
}
@ -9892,7 +9927,7 @@ nsRuleNode::ComputeSVGResetData(void* aStartStruct,
}
case eCSSUnit_Array: {
svgReset->mClipPath = StyleClipPath();
SetStyleClipPathToCSSValue(&svgReset->mClipPath, clipPathValue, aContext,
SetStyleShapeSourceToCSSValue(&svgReset->mClipPath, clipPathValue, aContext,
mPresContext, conditions);
break;
}

Просмотреть файл

@ -91,6 +91,15 @@ enum class StyleFloatEdge : uint8_t {
MarginBox,
};
// shape-box for shape-outside
enum class StyleShapeOutsideShapeBox : uint8_t {
NoBox,
Content,
Padding,
Border,
Margin
};
// Shape source type
// X11 has a #define for None causing conflicts, so we use None_ here
enum class StyleShapeSourceType : uint8_t {

Просмотреть файл

@ -3076,6 +3076,7 @@ nsStyleDisplay::nsStyleDisplay(const nsStyleDisplay& aSource)
, mAnimationFillModeCount(aSource.mAnimationFillModeCount)
, mAnimationPlayStateCount(aSource.mAnimationPlayStateCount)
, mAnimationIterationCountCount(aSource.mAnimationIterationCountCount)
, mShapeOutside(aSource.mShapeOutside)
{
MOZ_COUNT_CTOR(nsStyleDisplay);
@ -3300,7 +3301,8 @@ nsStyleDisplay::CalcDifference(const nsStyleDisplay& aNewData) const
mAnimationFillModeCount != aNewData.mAnimationFillModeCount ||
mAnimationPlayStateCount != aNewData.mAnimationPlayStateCount ||
mAnimationIterationCountCount != aNewData.mAnimationIterationCountCount ||
mScrollSnapCoordinate != aNewData.mScrollSnapCoordinate)) {
mScrollSnapCoordinate != aNewData.mScrollSnapCoordinate ||
mShapeOutside != aNewData.mShapeOutside)) {
hint |= nsChangeHint_NeutralChange;
}

Просмотреть файл

@ -2387,6 +2387,40 @@ private:
void AssignFromKeyword(int32_t aTimingFunctionType);
};
struct FragmentOrURL
{
FragmentOrURL() : mIsLocalRef(false) {}
FragmentOrURL(const FragmentOrURL& aSource)
: mIsLocalRef(false)
{ *this = aSource; }
void SetValue(const nsCSSValue* aValue);
void SetNull();
FragmentOrURL& operator=(const FragmentOrURL& aOther);
bool operator==(const FragmentOrURL& aOther) const;
bool operator!=(const FragmentOrURL& aOther) const {
return !(*this == aOther);
}
bool EqualsExceptRef(nsIURI* aURI) const;
nsIURI* GetSourceURL() const { return mURL; }
void GetSourceString(nsString& aRef) const;
// When matching a url with mIsLocalRef set, resolve it against aURI;
// Otherwise, ignore aURL and return mURL directly.
already_AddRefed<nsIURI> Resolve(nsIURI* aURI) const;
already_AddRefed<nsIURI> Resolve(nsIContent* aContent) const;
bool IsLocalRef() const { return mIsLocalRef; }
private:
nsCOMPtr<nsIURI> mURL;
bool mIsLocalRef;
};
namespace mozilla {
struct StyleTransition
@ -2490,6 +2524,259 @@ private:
float mIterationCount; // mozilla::PositiveInfinity<float>() means infinite
};
class StyleBasicShape final
{
public:
explicit StyleBasicShape(StyleBasicShapeType type)
: mType(type),
mFillRule(NS_STYLE_FILL_RULE_NONZERO)
{
mPosition.SetInitialPercentValues(0.5f);
}
StyleBasicShapeType GetShapeType() const { return mType; }
nsCSSKeyword GetShapeTypeName() const;
int32_t GetFillRule() const { return mFillRule; }
void SetFillRule(int32_t aFillRule)
{
MOZ_ASSERT(mType == StyleBasicShapeType::Polygon, "expected polygon");
mFillRule = aFillRule;
}
typedef nsStyleImageLayers::Position Position;
Position& GetPosition() {
MOZ_ASSERT(mType == StyleBasicShapeType::Circle ||
mType == StyleBasicShapeType::Ellipse,
"expected circle or ellipse");
return mPosition;
}
const Position& GetPosition() const {
MOZ_ASSERT(mType == StyleBasicShapeType::Circle ||
mType == StyleBasicShapeType::Ellipse,
"expected circle or ellipse");
return mPosition;
}
bool HasRadius() const {
MOZ_ASSERT(mType == StyleBasicShapeType::Inset, "expected inset");
nsStyleCoord zero;
zero.SetCoordValue(0);
NS_FOR_CSS_HALF_CORNERS(corner) {
if (mRadius.Get(corner) != zero) {
return true;
}
}
return false;
}
nsStyleCorners& GetRadius() {
MOZ_ASSERT(mType == StyleBasicShapeType::Inset, "expected inset");
return mRadius;
}
const nsStyleCorners& GetRadius() const {
MOZ_ASSERT(mType == StyleBasicShapeType::Inset, "expected inset");
return mRadius;
}
// mCoordinates has coordinates for polygon or radii for
// ellipse and circle.
nsTArray<nsStyleCoord>& Coordinates()
{
return mCoordinates;
}
const nsTArray<nsStyleCoord>& Coordinates() const
{
return mCoordinates;
}
bool operator==(const StyleBasicShape& aOther) const
{
return mType == aOther.mType &&
mFillRule == aOther.mFillRule &&
mCoordinates == aOther.mCoordinates &&
mPosition == aOther.mPosition &&
mRadius == aOther.mRadius;
}
bool operator!=(const StyleBasicShape& aOther) const {
return !(*this == aOther);
}
NS_INLINE_DECL_REFCOUNTING(StyleBasicShape);
private:
~StyleBasicShape() {}
StyleBasicShapeType mType;
int32_t mFillRule;
// mCoordinates has coordinates for polygon or radii for
// ellipse and circle.
nsTArray<nsStyleCoord> mCoordinates;
Position mPosition;
nsStyleCorners mRadius;
};
template<typename ReferenceBox>
struct StyleShapeSource
{
StyleShapeSource()
: mURL(nullptr)
{}
StyleShapeSource(const StyleShapeSource& aSource)
: StyleShapeSource()
{
if (aSource.mType == StyleShapeSourceType::URL) {
CopyURL(aSource);
} else if (aSource.mType == StyleShapeSourceType::Shape) {
SetBasicShape(aSource.mBasicShape, aSource.mReferenceBox);
} else if (aSource.mType == StyleShapeSourceType::Box) {
SetReferenceBox(aSource.mReferenceBox);
}
}
~StyleShapeSource()
{
ReleaseRef();
}
StyleShapeSource& operator=(const StyleShapeSource& aOther)
{
if (this == &aOther) {
return *this;
}
if (aOther.mType == StyleShapeSourceType::URL) {
CopyURL(aOther);
} else if (aOther.mType == StyleShapeSourceType::Shape) {
SetBasicShape(aOther.mBasicShape, aOther.mReferenceBox);
} else if (aOther.mType == StyleShapeSourceType::Box) {
SetReferenceBox(aOther.mReferenceBox);
} else {
ReleaseRef();
mReferenceBox = ReferenceBox::NoBox;
mType = StyleShapeSourceType::None_;
}
return *this;
}
bool operator==(const StyleShapeSource& aOther) const
{
if (mType != aOther.mType) {
return false;
}
if (mType == StyleShapeSourceType::URL) {
return mURL == aOther.mURL;
} else if (mType == StyleShapeSourceType::Shape) {
return *mBasicShape == *aOther.mBasicShape &&
mReferenceBox == aOther.mReferenceBox;
} else if (mType == StyleShapeSourceType::Box) {
return mReferenceBox == aOther.mReferenceBox;
}
return true;
}
bool operator!=(const StyleShapeSource& aOther) const
{
return !(*this == aOther);
}
StyleShapeSourceType GetType() const
{
return mType;
}
FragmentOrURL* GetURL() const
{
MOZ_ASSERT(mType == StyleShapeSourceType::URL, "Wrong shape source type!");
return mURL;
}
bool SetURL(const nsCSSValue* aValue)
{
if (!aValue->GetURLValue()) {
return false;
}
ReleaseRef();
mURL = new FragmentOrURL();
mURL->SetValue(aValue);
mType = StyleShapeSourceType::URL;
return true;
}
StyleBasicShape* GetBasicShape() const
{
MOZ_ASSERT(mType == StyleShapeSourceType::Shape, "Wrong shape source type!");
return mBasicShape;
}
void SetBasicShape(StyleBasicShape* aBasicShape,
ReferenceBox aReferenceBox)
{
NS_ASSERTION(aBasicShape, "expected pointer");
ReleaseRef();
mBasicShape = aBasicShape;
mBasicShape->AddRef();
mReferenceBox = aReferenceBox;
mType = StyleShapeSourceType::Shape;
}
ReferenceBox GetReferenceBox() const
{
MOZ_ASSERT(mType == StyleShapeSourceType::Box ||
mType == StyleShapeSourceType::Shape,
"Wrong shape source type!");
return mReferenceBox;
}
void SetReferenceBox(ReferenceBox aReferenceBox)
{
ReleaseRef();
mReferenceBox = aReferenceBox;
mType = StyleShapeSourceType::Box;
}
private:
void ReleaseRef()
{
if (mType == StyleShapeSourceType::Shape) {
NS_ASSERTION(mBasicShape, "expected pointer");
mBasicShape->Release();
} else if (mType == StyleShapeSourceType::URL) {
NS_ASSERTION(mURL, "expected pointer");
delete mURL;
}
// Both mBasicShape and mURL are pointers in a union. Nulling one of them
// nulls both of them.
mURL = nullptr;
}
void CopyURL(const StyleShapeSource& aOther)
{
ReleaseRef();
mURL = new FragmentOrURL(*aOther.mURL);
mType = StyleShapeSourceType::URL;
}
void* operator new(size_t) = delete;
union {
StyleBasicShape* mBasicShape;
FragmentOrURL* mURL;
};
StyleShapeSourceType mType = StyleShapeSourceType::None_;
ReferenceBox mReferenceBox = ReferenceBox::NoBox;
};
using StyleClipPath = StyleShapeSource<StyleClipPathGeometryBox>;
using StyleShapeOutside = StyleShapeSource<StyleShapeOutsideShapeBox>;
} // namespace mozilla
struct MOZ_NEEDS_MEMMOVABLE_MEMBERS nsStyleDisplay
@ -2611,6 +2898,8 @@ struct MOZ_NEEDS_MEMMOVABLE_MEMBERS nsStyleDisplay
mAnimationPlayStateCount,
mAnimationIterationCountCount;
mozilla::StyleShapeOutside mShapeOutside; // [reset]
bool IsBlockInsideStyle() const {
return NS_STYLE_DISPLAY_BLOCK == mDisplay ||
NS_STYLE_DISPLAY_LIST_ITEM == mDisplay ||
@ -3233,39 +3522,6 @@ protected:
nscoord mTwipsPerPixel;
};
struct FragmentOrURL
{
FragmentOrURL() : mIsLocalRef(false) {}
FragmentOrURL(const FragmentOrURL& aSource)
: mIsLocalRef(false)
{ *this = aSource; }
void SetValue(const nsCSSValue* aValue);
void SetNull();
FragmentOrURL& operator=(const FragmentOrURL& aOther);
bool operator==(const FragmentOrURL& aOther) const;
bool operator!=(const FragmentOrURL& aOther) const {
return !(*this == aOther);
}
bool EqualsExceptRef(nsIURI* aURI) const;
nsIURI* GetSourceURL() const { return mURL; }
void GetSourceString(nsString& aRef) const;
// When matching a url with mIsLocalRef set, resolve it against aURI;
// Otherwise, ignore aURL and return mURL directly.
already_AddRefed<nsIURI> Resolve(nsIURI* aURI) const;
already_AddRefed<nsIURI> Resolve(nsIContent* aContent) const;
bool IsLocalRef() const { return mIsLocalRef; }
private:
nsCOMPtr<nsIURI> mURL;
bool mIsLocalRef;
};
enum nsStyleSVGPaintType {
eStyleSVGPaintType_None = 1,
eStyleSVGPaintType_Color,
@ -3436,262 +3692,6 @@ private:
uint8_t mContextFlags; // [inherited]
};
namespace mozilla {
class StyleBasicShape final
{
public:
explicit StyleBasicShape(StyleBasicShapeType type)
: mType(type),
mFillRule(NS_STYLE_FILL_RULE_NONZERO)
{
mPosition.SetInitialPercentValues(0.5f);
}
StyleBasicShapeType GetShapeType() const { return mType; }
nsCSSKeyword GetShapeTypeName() const;
int32_t GetFillRule() const { return mFillRule; }
void SetFillRule(int32_t aFillRule)
{
MOZ_ASSERT(mType == StyleBasicShapeType::Polygon, "expected polygon");
mFillRule = aFillRule;
}
typedef nsStyleImageLayers::Position Position;
Position& GetPosition() {
MOZ_ASSERT(mType == StyleBasicShapeType::Circle ||
mType == StyleBasicShapeType::Ellipse,
"expected circle or ellipse");
return mPosition;
}
const Position& GetPosition() const {
MOZ_ASSERT(mType == StyleBasicShapeType::Circle ||
mType == StyleBasicShapeType::Ellipse,
"expected circle or ellipse");
return mPosition;
}
bool HasRadius() const {
MOZ_ASSERT(mType == StyleBasicShapeType::Inset, "expected inset");
nsStyleCoord zero;
zero.SetCoordValue(0);
NS_FOR_CSS_HALF_CORNERS(corner) {
if (mRadius.Get(corner) != zero) {
return true;
}
}
return false;
}
nsStyleCorners& GetRadius() {
MOZ_ASSERT(mType == StyleBasicShapeType::Inset, "expected inset");
return mRadius;
}
const nsStyleCorners& GetRadius() const {
MOZ_ASSERT(mType == StyleBasicShapeType::Inset, "expected inset");
return mRadius;
}
// mCoordinates has coordinates for polygon or radii for
// ellipse and circle.
nsTArray<nsStyleCoord>& Coordinates()
{
return mCoordinates;
}
const nsTArray<nsStyleCoord>& Coordinates() const
{
return mCoordinates;
}
bool operator==(const StyleBasicShape& aOther) const
{
return mType == aOther.mType &&
mFillRule == aOther.mFillRule &&
mCoordinates == aOther.mCoordinates &&
mPosition == aOther.mPosition &&
mRadius == aOther.mRadius;
}
bool operator!=(const StyleBasicShape& aOther) const {
return !(*this == aOther);
}
NS_INLINE_DECL_REFCOUNTING(StyleBasicShape);
private:
~StyleBasicShape() {}
StyleBasicShapeType mType;
int32_t mFillRule;
// mCoordinates has coordinates for polygon or radii for
// ellipse and circle.
nsTArray<nsStyleCoord> mCoordinates;
Position mPosition;
nsStyleCorners mRadius;
};
template<typename ReferenceBox>
struct StyleShapeSource
{
StyleShapeSource()
: mURL(nullptr)
{}
StyleShapeSource(const StyleShapeSource& aSource)
: StyleShapeSource()
{
if (aSource.mType == StyleShapeSourceType::URL) {
CopyURL(aSource);
} else if (aSource.mType == StyleShapeSourceType::Shape) {
SetBasicShape(aSource.mBasicShape, aSource.mReferenceBox);
} else if (aSource.mType == StyleShapeSourceType::Box) {
SetReferenceBox(aSource.mReferenceBox);
}
}
~StyleShapeSource()
{
ReleaseRef();
}
StyleShapeSource& operator=(const StyleShapeSource& aOther)
{
if (this == &aOther) {
return *this;
}
if (aOther.mType == StyleShapeSourceType::URL) {
CopyURL(aOther);
} else if (aOther.mType == StyleShapeSourceType::Shape) {
SetBasicShape(aOther.mBasicShape, aOther.mReferenceBox);
} else if (aOther.mType == StyleShapeSourceType::Box) {
SetReferenceBox(aOther.mReferenceBox);
} else {
ReleaseRef();
mReferenceBox = ReferenceBox::NoBox;
mType = StyleShapeSourceType::None_;
}
return *this;
}
bool operator==(const StyleShapeSource& aOther) const
{
if (mType != aOther.mType) {
return false;
}
if (mType == StyleShapeSourceType::URL) {
return mURL == aOther.mURL;
} else if (mType == StyleShapeSourceType::Shape) {
return *mBasicShape == *aOther.mBasicShape &&
mReferenceBox == aOther.mReferenceBox;
} else if (mType == StyleShapeSourceType::Box) {
return mReferenceBox == aOther.mReferenceBox;
}
return true;
}
bool operator!=(const StyleShapeSource& aOther) const
{
return !(*this == aOther);
}
StyleShapeSourceType GetType() const
{
return mType;
}
FragmentOrURL* GetURL() const
{
MOZ_ASSERT(mType == StyleShapeSourceType::URL, "Wrong shape source type!");
return mURL;
}
bool SetURL(const nsCSSValue* aValue)
{
if (!aValue->GetURLValue()) {
return false;
}
ReleaseRef();
mURL = new FragmentOrURL();
mURL->SetValue(aValue);
mType = StyleShapeSourceType::URL;
return true;
}
StyleBasicShape* GetBasicShape() const
{
MOZ_ASSERT(mType == StyleShapeSourceType::Shape, "Wrong shape source type!");
return mBasicShape;
}
void SetBasicShape(StyleBasicShape* aBasicShape,
ReferenceBox aReferenceBox)
{
NS_ASSERTION(aBasicShape, "expected pointer");
ReleaseRef();
mBasicShape = aBasicShape;
mBasicShape->AddRef();
mReferenceBox = aReferenceBox;
mType = StyleShapeSourceType::Shape;
}
ReferenceBox GetReferenceBox() const
{
MOZ_ASSERT(mType == StyleShapeSourceType::Box ||
mType == StyleShapeSourceType::Shape,
"Wrong shape source type!");
return mReferenceBox;
}
void SetReferenceBox(ReferenceBox aReferenceBox)
{
ReleaseRef();
mReferenceBox = aReferenceBox;
mType = StyleShapeSourceType::Box;
}
private:
void ReleaseRef()
{
if (mType == StyleShapeSourceType::Shape) {
NS_ASSERTION(mBasicShape, "expected pointer");
mBasicShape->Release();
} else if (mType == StyleShapeSourceType::URL) {
NS_ASSERTION(mURL, "expected pointer");
delete mURL;
}
// Both mBasicShape and mURL are pointers in a union. Nulling one of them
// nulls both of them.
mURL = nullptr;
}
void CopyURL(const StyleShapeSource& aOther)
{
ReleaseRef();
mURL = new FragmentOrURL(*aOther.mURL);
mType = StyleShapeSourceType::URL;
}
void* operator new(size_t) = delete;
union {
StyleBasicShape* mBasicShape;
FragmentOrURL* mURL;
};
StyleShapeSourceType mType = StyleShapeSourceType::None_;
ReferenceBox mReferenceBox = ReferenceBox::NoBox;
};
using StyleClipPath = StyleShapeSource<StyleClipPathGeometryBox>;
} // namespace mozilla
struct nsStyleFilter
{
nsStyleFilter();

Просмотреть файл

@ -5598,16 +5598,7 @@ if (IsCSSPropertyPrefEnabled("svg.transform-box.enabled")) {
};
}
if (IsCSSPropertyPrefEnabled("layout.css.clip-path-shapes.enabled")) {
gCSSProperties["clip-path"] = {
domProp: "clipPath",
inherited: false,
type: CSS_TYPE_LONGHAND,
initial_values: [ "none" ],
other_values: [
// SVG reference clip-path
"url(#my-clip-path)",
var basicShapeOtherValues = [
"polygon(20px 20px)",
"polygon(20px 20%)",
"polygon(20% 20%)",
@ -5622,9 +5613,6 @@ if (IsCSSPropertyPrefEnabled("layout.css.clip-path-shapes.enabled")) {
"padding-box",
"border-box",
"margin-box",
"fill-box",
"stroke-box",
"view-box",
"polygon(0 0) content-box",
"border-box polygon(0 0)",
@ -5633,9 +5621,6 @@ if (IsCSSPropertyPrefEnabled("layout.css.clip-path-shapes.enabled")) {
"polygon(evenodd, 20vh 20em) padding-box",
"polygon(evenodd, 20vh calc(20% + 20em)) border-box",
"polygon(evenodd, 20vh 20vw) margin-box",
"polygon(evenodd, 20pt 20cm) fill-box",
"polygon(evenodd, 20ex 20pc) stroke-box",
"polygon(evenodd, 20rem 20in) view-box",
"circle()",
"circle(at center)",
@ -5678,8 +5663,9 @@ if (IsCSSPropertyPrefEnabled("layout.css.clip-path-shapes.enabled")) {
"inset(1px 2px round 3px / 3px)",
"inset(1px 2px 3px round 3px 2em / 20%)",
"inset(1px 2px 3px 4px round 3px 2vw 20% / 20px 3em 2vh 20%)",
],
invalid_values: [
];
var basicShapeInvalidValues = [
"url(#test) url(#tes2)",
"polygon (0 0)",
"polygon(20px, 40px)",
@ -5759,8 +5745,9 @@ if (IsCSSPropertyPrefEnabled("layout.css.clip-path-shapes.enabled")) {
"inset(1px round)",
"inset(1px calc(2px + rubbish))",
"inset(1px round 2px calc(3px + rubbish))",
],
unbalanced_values: [
];
var basicShapeUnbalancedValues = [
"polygon(30% 30%",
"polygon(nonzero, 20% 20px",
"polygon(evenodd, 20px 20px",
@ -5776,7 +5763,42 @@ if (IsCSSPropertyPrefEnabled("layout.css.clip-path-shapes.enabled")) {
"inset(1px 2px 3px 4px",
"inset(1px 2px 3px 4px round 5px",
"inset(1px 2px 3px 4px round 5px / 6px",
]
];
if (IsCSSPropertyPrefEnabled("layout.css.clip-path-shapes.enabled")) {
gCSSProperties["clip-path"] = {
domProp: "clipPath",
inherited: false,
type: CSS_TYPE_LONGHAND,
initial_values: [ "none" ],
other_values: [
// SVG reference clip-path
"url(#my-clip-path)",
"fill-box",
"stroke-box",
"view-box",
"polygon(evenodd, 20pt 20cm) fill-box",
"polygon(evenodd, 20ex 20pc) stroke-box",
"polygon(evenodd, 20rem 20in) view-box",
].concat(basicShapeOtherValues),
invalid_values: basicShapeInvalidValues,
unbalanced_values: basicShapeUnbalancedValues,
};
}
if (IsCSSPropertyPrefEnabled("layout.css.shape-outside.enabled")) {
gCSSProperties["shape-outside"] = {
domProp: "shapeOutside",
inherited: false,
type: CSS_TYPE_LONGHAND,
initial_values: [ "none" ],
other_values: [
"url(#my-shape-outside)",
].concat(basicShapeOtherValues),
invalid_values: basicShapeInvalidValues,
unbalanced_values: basicShapeUnbalancedValues,
};
}

Просмотреть файл

@ -2603,6 +2603,9 @@ pref("layout.css.scroll-behavior.damping-ratio", "1.0");
// Is support for scroll-snap enabled?
pref("layout.css.scroll-snap.enabled", true);
// Is support for CSS shape-outside enabled?
pref("layout.css.shape-outside.enabled", false);
// Is support for document.fonts enabled?
pref("layout.css.font-loading-api.enabled", true);

Просмотреть файл

@ -176,6 +176,9 @@ user_pref("layout.css.prefixes.webkit", true);
// Enable -webkit-{min|max}-device-pixel-ratio media queries for testing
user_pref("layout.css.prefixes.device-pixel-ratio-webkit", true);
// Enable CSS shape-outside for testing
user_pref("layout.css.shape-outside.enabled", true);
// Disable spammy layout warnings because they pollute test logs
user_pref("layout.spammy_warnings.enabled", false);