author | Ting-Yu Lin <tlin@mozilla.com> |
Mon, 23 May 2016 01:03:25 +0800 | |
changeset 369619 | d9fd7a942b5ee0fa6062500cc25de58d1a43537f |
parent 369355 | 3efb130c6dca2cd2899f0e99befb546ad8cfc241 |
child 521574 | 43f3e1e762c56947a19565d6f86ac01fda7ff109 |
push id | 18866 |
push user | bmo:tlin@mozilla.com |
push date | Mon, 23 May 2016 07:38:35 +0000 |
bugs | 1098939 |
milestone | 49.0a1 |
--- a/layout/style/nsCSSParser.cpp +++ b/layout/style/nsCSSParser.cpp @@ -1058,16 +1058,17 @@ protected: bool ParseTextEmphasisPosition(nsCSSValue& aValue); bool ParseTextEmphasisStyle(nsCSSValue& aValue); bool ParseTextCombineUpright(nsCSSValue& aValue); bool ParseTextOverflow(nsCSSValue& aValue); bool ParseTouchAction(nsCSSValue& aValue); bool ParseShadowItem(nsCSSValue& aValue, bool aIsBoxShadow); bool ParseShadowList(nsCSSProperty aProperty); + bool ParseShapeOutside(nsCSSValue& aValue); bool ParseTransitionProperty(); bool ParseTransitionTimingFunctionValues(nsCSSValue& aValue); bool ParseTransitionTimingFunctionValueComponent(float& aComponent, char aStop, bool aCheckRange); bool ParseTransitionStepTimingFunctionValues(nsCSSValue& aValue); enum ParseAnimationOrTransitionShorthandResult { eParseAnimationOrTransitionShorthand_Values, @@ -11705,16 +11706,18 @@ CSSParserImpl::ParseSingleValuePropertyB case eCSSProperty_scroll_snap_points_x: return ParseScrollSnapPoints(aValue, eCSSProperty_scroll_snap_points_x); case eCSSProperty_scroll_snap_points_y: return ParseScrollSnapPoints(aValue, eCSSProperty_scroll_snap_points_y); case eCSSProperty_scroll_snap_destination: 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: return ParseTextAlignLast(aValue); case eCSSProperty_text_decoration_line: return ParseTextDecorationLine(aValue); case eCSSProperty_text_combine_upright: return ParseTextCombineUpright(aValue); @@ -16069,16 +16072,62 @@ bool CSSParserImpl::ParseClipPath() value.SetArrayValue(fullValue, eCSSUnit_Array); } 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; + } + + nsCSSValue shapeBox; + bool hasBox = ParseEnum(shapeBox, nsCSSProps::kShapeBoxKTable); + const bool boxCameFirst = hasBox; + + nsCSSValue basicShape; + bool basicShapeConsumedTokens = false; + bool hasShape = ParseBasicShape(basicShape, &basicShapeConsumedTokens); + + // Parsing wasn't successful if ParseBasicShape() consumed tokens but failed + // or if the token was neither a shape-box nor a basic-shape. + if ((!hasShape && basicShapeConsumedTokens) || (!hasBox && !hasShape)) { + return false; + } + + // Check if the second argument is a shape box if the first wasn't. + if (!hasBox) { + hasBox = ParseEnum(shapeBox, nsCSSProps::kClipShapeSizingKTable); + } + + RefPtr<nsCSSValue::Array> fullValue = + nsCSSValue::Array::Create(hasBox && hasShape ? 2 : 1); + + if (hasBox && hasShape) { + fullValue->Item(boxCameFirst ? 0 : 1) = shapeBox; + fullValue->Item(boxCameFirst ? 1 : 0) = basicShape; + } else if (hasBox) { + fullValue->Item(0) = shapeBox; + } else { + MOZ_ASSERT(hasShape, "Should've bailed if we got neither box nor shape!"); + fullValue->Item(0) = basicShape; + } + + aValue.SetArrayValue(fullValue, eCSSUnit_Array); + + return true; +} + bool CSSParserImpl::ParseTransformOrigin(bool aPerspective) { nsCSSValuePair position; if (!ParseBoxPositionValues(position, true)) return false; nsCSSProperty prop = eCSSProperty_transform_origin; if (aPerspective) {
--- a/layout/style/nsCSSPropList.h +++ b/layout/style/nsCSSPropList.h @@ -3692,16 +3692,27 @@ CSS_PROP_DISPLAY( scroll_snap_type_y, ScrollSnapTypeY, CSS_PROPERTY_PARSE_VALUE, "layout.css.scroll-snap.enabled", VARIANT_HK, kScrollSnapTypeKTable, CSS_PROP_NO_OFFSET, eStyleAnimType_None) +CSS_PROP_DISPLAY( + shape-outside, + shape_outside, + ShapeOutside, + CSS_PROPERTY_PARSE_VALUE | + CSS_PROPERTY_VALUE_PARSER_FUNCTION, + "layout.css.shape-outside.enabled", + 0, + nullptr, + CSS_PROP_NO_OFFSET, + eStyleAnimType_None) CSS_PROP_SVG( shape-rendering, shape_rendering, ShapeRendering, CSS_PROPERTY_PARSE_VALUE, "", VARIANT_HK, kShapeRenderingKTable,
--- a/layout/style/nsCSSProps.cpp +++ b/layout/style/nsCSSProps.cpp @@ -2331,16 +2331,24 @@ const KTableEntry nsCSSProps::kImageRend }; const KTableEntry nsCSSProps::kMaskTypeKTable[] = { { eCSSKeyword_luminance, NS_STYLE_MASK_TYPE_LUMINANCE }, { eCSSKeyword_alpha, NS_STYLE_MASK_TYPE_ALPHA }, { eCSSKeyword_UNKNOWN, -1 } }; +const KTableEntry nsCSSProps::kShapeBoxKTable[] = { + { eCSSKeyword_margin_box, uint8_t(StyleShapeBox::Margin) }, + { eCSSKeyword_border_box, uint8_t(StyleShapeBox::Border) }, + { eCSSKeyword_padding_box, uint8_t(StyleShapeBox::Padding) }, + { eCSSKeyword_content_box, uint8_t(StyleShapeBox::Content) }, + { eCSSKeyword_UNKNOWN, -1 } +}; + const KTableEntry nsCSSProps::kShapeRenderingKTable[] = { { eCSSKeyword_auto, NS_STYLE_SHAPE_RENDERING_AUTO }, { eCSSKeyword_optimizespeed, NS_STYLE_SHAPE_RENDERING_OPTIMIZESPEED }, { eCSSKeyword_crispedges, NS_STYLE_SHAPE_RENDERING_CRISPEDGES }, { eCSSKeyword_geometricprecision, NS_STYLE_SHAPE_RENDERING_GEOMETRICPRECISION }, { eCSSKeyword_UNKNOWN, -1 } };
--- a/layout/style/nsCSSProps.h +++ b/layout/style/nsCSSProps.h @@ -679,16 +679,17 @@ public: static const KTableEntry kCounterSpeakAsKTable[]; static const KTableEntry kCounterSymbolsSystemKTable[]; static const KTableEntry kCounterSystemKTable[]; static const KTableEntry kDominantBaselineKTable[]; static const KTableEntry kShapeRadiusKTable[]; static const KTableEntry kFillRuleKTable[]; static const KTableEntry kFilterFunctionKTable[]; static const KTableEntry kImageRenderingKTable[]; + static const KTableEntry kShapeBoxKTable[]; static const KTableEntry kShapeRenderingKTable[]; static const KTableEntry kStrokeLinecapKTable[]; static const KTableEntry kStrokeLinejoinKTable[]; static const KTableEntry kStrokeContextValueKTable[]; static const KTableEntry kVectorEffectKTable[]; static const KTableEntry kTextAnchorKTable[]; static const KTableEntry kTextRenderingKTable[]; static const KTableEntry kColorAdjustKTable[];
--- a/layout/style/nsComputedDOMStyle.cpp +++ b/layout/style/nsComputedDOMStyle.cpp @@ -3197,16 +3197,68 @@ nsComputedDOMStyle::DoGetScrollSnapCoord SetValueToPosition(sd->mScrollSnapCoordinate[i], itemList); valueList->AppendCSSValue(itemList.forget()); } return valueList.forget(); } } already_AddRefed<CSSValue> +nsComputedDOMStyle::CreatePrimitiveValueForShapeOutside( + const nsStyleBasicShape* aStyleBasicShape, StyleShapeBox aShapeBox) +{ + RefPtr<nsDOMCSSValueList> valueList = GetROCSSValueList(false); + if (aStyleBasicShape) { + valueList->AppendCSSValue( + CreatePrimitiveValueForBasicShape(aStyleBasicShape)); + } + + if (aShapeBox == StyleShapeBox::None) { + return valueList.forget(); + } + + nsAutoString boxString; + AppendASCIItoUTF16( + nsCSSProps::ValueToKeyword(static_cast<uint8_t>(aShapeBox), + nsCSSProps::kShapeBoxKTable), + boxString); + RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue; + val->SetString(boxString); + valueList->AppendCSSValue(val.forget()); + + return valueList.forget(); +} + +already_AddRefed<CSSValue> +nsComputedDOMStyle::DoGetShapeOutside() +{ + const nsStyleDisplay* display = StyleDisplay(); + switch (display->mShapeOutside.GetType()) { + case StyleShapeOutside::Type::None: { + RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue; + val->SetIdent(eCSSKeyword_none); + return val.forget(); + } + case StyleShapeOutside::Type::ShapeBox: + return CreatePrimitiveValueForShapeOutside( + nullptr, display->mShapeOutside.GetShapeBox()); + case StyleShapeOutside::Type::BasicShape: + return CreatePrimitiveValueForShapeOutside( + display->mShapeOutside.GetBasicShape(), + display->mShapeOutside.GetShapeBox()); + case StyleShapeOutside::Type::URL: { + RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue; + val->SetIdent(eCSSKeyword_none); + return val.forget(); + } + } + return nullptr; +} + +already_AddRefed<CSSValue> nsComputedDOMStyle::DoGetOutlineWidth() { RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue; const nsStyleOutline* outline = StyleOutline(); nscoord width; if (outline->GetOutlineStyle() == NS_STYLE_BORDER_STYLE_NONE) {
--- a/layout/style/nsComputedDOMStyle.h +++ b/layout/style/nsComputedDOMStyle.h @@ -476,16 +476,17 @@ private: already_AddRefed<CSSValue> DoGetScrollBehavior(); already_AddRefed<CSSValue> DoGetScrollSnapType(); already_AddRefed<CSSValue> DoGetScrollSnapTypeX(); already_AddRefed<CSSValue> DoGetScrollSnapTypeY(); already_AddRefed<CSSValue> DoGetScrollSnapPointsX(); already_AddRefed<CSSValue> DoGetScrollSnapPointsY(); already_AddRefed<CSSValue> DoGetScrollSnapDestination(); already_AddRefed<CSSValue> DoGetScrollSnapCoordinate(); + already_AddRefed<CSSValue> DoGetShapeOutside(); /* User interface properties */ already_AddRefed<CSSValue> DoGetCursor(); already_AddRefed<CSSValue> DoGetForceBrokenImageIcon(); already_AddRefed<CSSValue> DoGetIMEMode(); already_AddRefed<CSSValue> DoGetUserFocus(); already_AddRefed<CSSValue> DoGetUserInput(); already_AddRefed<CSSValue> DoGetUserModify(); @@ -640,16 +641,18 @@ private: /* Helper functions for computing the filter property style. */ void SetCssTextToCoord(nsAString& aCssText, const nsStyleCoord& aCoord); already_AddRefed<CSSValue> CreatePrimitiveValueForStyleFilter( const nsStyleFilter& aStyleFilter); already_AddRefed<CSSValue> CreatePrimitiveValueForClipPath( const nsStyleBasicShape* aStyleBasicShape, uint8_t aSizingBox); + already_AddRefed<CSSValue> CreatePrimitiveValueForShapeOutside( + const nsStyleBasicShape* aStyleBasicShape, mozilla::StyleShapeBox aShapeBox); // Helper function for computing basic shape styles. already_AddRefed<CSSValue> CreatePrimitiveValueForBasicShape( const nsStyleBasicShape* aStyleBasicShape); void BoxValuesToString(nsAString& aString, const nsTArray<nsStyleCoord>& aBoxValues); void BasicShapeRadiiToString(nsAString& aCssText, const nsStyleCorners& aCorners);
--- a/layout/style/nsComputedDOMStylePropertyList.h +++ b/layout/style/nsComputedDOMStylePropertyList.h @@ -210,16 +210,17 @@ COMPUTED_STYLE_PROP(ruby_align, COMPUTED_STYLE_PROP(ruby_position, RubyPosition) COMPUTED_STYLE_PROP(scroll_behavior, ScrollBehavior) COMPUTED_STYLE_PROP(scroll_snap_coordinate, ScrollSnapCoordinate) COMPUTED_STYLE_PROP(scroll_snap_destination, ScrollSnapDestination) 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) COMPUTED_STYLE_PROP(text_combine_upright, TextCombineUpright) COMPUTED_STYLE_PROP(text_decoration, TextDecoration) COMPUTED_STYLE_PROP(text_decoration_color, TextDecorationColor) COMPUTED_STYLE_PROP(text_decoration_line, TextDecorationLine) COMPUTED_STYLE_PROP(text_decoration_style, TextDecorationStyle)
--- a/layout/style/nsRuleNode.cpp +++ b/layout/style/nsRuleNode.cpp @@ -6339,16 +6339,48 @@ nsRuleNode::ComputeDisplayData(void* aSt // orient: enum, inherit, initial SetDiscrete(*aRuleData->ValueForOrient(), display->mOrient, conditions, SETDSC_ENUMERATED | SETDSC_UNSET_INITIAL, parentDisplay->mOrient, NS_STYLE_ORIENT_INLINE, 0, 0, 0, 0); + // 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(); + nsIURI* url = shapeOutsideValue->GetURLValue(); + if (url) { + display->mShapeOutside.SetURL(url); + } + break; + } + case eCSSUnit_Array: { + display->mShapeOutside = StyleShapeOutside(); + SetStyleShapeOutsideToCSSValue(&display->mShapeOutside, shapeOutsideValue, + aContext, mPresContext, conditions); + break; + } + default: + MOZ_ASSERT_UNREACHABLE("Unrecognized shape-outside unit!"); + } + COMPUTE_END_RESET(Display, display) } const void* nsRuleNode::ComputeVisibilityData(void* aStartStruct, const nsRuleData* aRuleData, nsStyleContext* aContext, nsRuleNode* aHighestNode, @@ -9707,16 +9739,57 @@ nsRuleNode::SetStyleClipPathToCSSValue(n if (basicShape) { aStyleClipPath->SetBasicShape(basicShape, sizingBox); } else { aStyleClipPath->SetSizingBox(sizingBox); } } +void +nsRuleNode::SetStyleShapeOutsideToCSSValue(StyleShapeOutside* aShapeOutside, + const nsCSSValue* aValue, + nsStyleContext* aStyleContext, + nsPresContext* aPresContext, + RuleNodeCacheConditions& aConditions) +{ + MOZ_ASSERT(aValue->GetUnit() == eCSSUnit_Array, + "Expect a basic shape or shape box!"); + + const nsCSSValue::Array* array = aValue->GetArrayValue(); + MOZ_ASSERT(array->Count() == 1 || array->Count() == 2, + "Expect one or both of a shape function and a shape box!"); + + StyleShapeBox shapeBox = StyleShapeBox::Margin; + RefPtr<nsStyleBasicShape> basicShape; + + for (size_t i = 0; i < array->Count(); ++i) { + const nsCSSValue& item = array->Item(i); + switch (item.GetUnit()) { + case eCSSUnit_Enumerated: + shapeBox = static_cast<StyleShapeBox>(item.GetIntValue()); + break; + case eCSSUnit_Function: + basicShape = GetStyleBasicShapeFromCSSValue(item, aStyleContext, + aPresContext, aConditions); + break; + default: + MOZ_ASSERT_UNREACHABLE("Unrecognized shape-outside unit in the array!"); + break; + } + } + + if (basicShape) { + aShapeOutside->SetBasicShape(basicShape, shapeBox); + } else { + aShapeOutside->SetShapeBox(shapeBox); + } +} + + // Returns true if the nsStyleFilter was successfully set using the nsCSSValue. bool nsRuleNode::SetStyleFilterToCSSValue(nsStyleFilter* aStyleFilter, const nsCSSValue& aValue, nsStyleContext* aStyleContext, nsPresContext* aPresContext, RuleNodeCacheConditions& aConditions) {
--- a/layout/style/nsRuleNode.h +++ b/layout/style/nsRuleNode.h @@ -798,16 +798,21 @@ protected: nsStyleContext* aStyleContext, nsPresContext* aPresContext, mozilla::RuleNodeCacheConditions& aConditions); void SetStyleClipPathToCSSValue(nsStyleClipPath* aStyleClipPath, const nsCSSValue* aValue, nsStyleContext* aStyleContext, nsPresContext* aPresContext, mozilla::RuleNodeCacheConditions& aConditions); + void SetStyleShapeOutsideToCSSValue(mozilla::StyleShapeOutside* aShapeOutside, + const nsCSSValue* aValue, + nsStyleContext* aStyleContext, + nsPresContext* aPresContext, + mozilla::RuleNodeCacheConditions& aConditions); private: nsRuleNode(nsPresContext* aPresContext, nsRuleNode* aParent, nsIStyleRule* aRule, mozilla::SheetType aLevel, bool aIsImportant); ~nsRuleNode(); public: // This is infallible; it will never return nullptr.
--- a/layout/style/nsStyleStruct.cpp +++ b/layout/style/nsStyleStruct.cpp @@ -2792,16 +2792,142 @@ mozilla::StyleAnimation::operator==(cons mName == aOther.mName && mDirection == aOther.mDirection && mFillMode == aOther.mFillMode && mPlayState == aOther.mPlayState && mIterationCount == aOther.mIterationCount; } // -------------------- +// StyleShapeOutside +// +StyleShapeOutside::StyleShapeOutside() +{ + Reset(); +} + +StyleShapeOutside::StyleShapeOutside(const StyleShapeOutside& aSource) +{ + switch (aSource.mType) { + case Type::None: + Reset(); + break; + case Type::ShapeBox: + SetShapeBox(aSource.mShapeBox); + break; + case Type::BasicShape: + SetBasicShape(aSource.mBasicShape, aSource.mShapeBox); + break; + case Type::URL: + SetURL(aSource.mURL); + break; + } +} + +StyleShapeOutside::~StyleShapeOutside() +{ + Reset(); +} + +StyleShapeOutside& +StyleShapeOutside::operator=(const StyleShapeOutside& aOther) +{ + if (this == &aOther) { + return *this; + } + + switch (aOther.mType) { + case Type::None: + Reset(); + break; + case Type::ShapeBox: + SetShapeBox(aOther.mShapeBox); + break; + case Type::BasicShape: + SetBasicShape(aOther.mBasicShape, aOther.mShapeBox); + break; + case Type::URL: + SetURL(aOther.mURL); + break; + } + + return *this; +} + +bool +StyleShapeOutside::operator==(const StyleShapeOutside& aOther) const +{ + if (mType != aOther.mType) { + return false; + } + + switch (mType) { + case Type::None: + return true; + case Type::ShapeBox: + return mShapeBox == aOther.mShapeBox; + case Type::BasicShape: + return *mBasicShape == *aOther.mBasicShape && + mShapeBox == aOther.mShapeBox; + case Type::URL: + return EqualURIs(mURL, aOther.mURL); + } +} + +void +StyleShapeOutside::Reset() +{ + switch (mType) { + case Type::None: + case Type::ShapeBox: + break; + case Type::BasicShape: + NS_IF_RELEASE(mBasicShape); + break; + case Type::URL: + NS_IF_RELEASE(mURL); + break; + } + + mType = Type::None; + mShapeBox = StyleShapeBox::None; + mBasicShape = nullptr; +} + +void +StyleShapeOutside::SetShapeBox(StyleShapeBox aShapeBox) +{ + Reset(); + mShapeBox = aShapeBox; + mType = Type::ShapeBox; +} + +void +StyleShapeOutside::SetBasicShape(nsStyleBasicShape* aBasicShape, + StyleShapeBox aShapeBox) +{ + MOZ_ASSERT(aBasicShape, "Expect a valid aBasicShape pointer!"); + Reset(); + mBasicShape = aBasicShape; + mBasicShape->AddRef(); + mShapeBox = aShapeBox; + mType = Type::BasicShape; +} + +void +StyleShapeOutside::SetURL(nsIURI* aURL) +{ + MOZ_ASSERT(aURL, "Expect a valid aURL pointer!"); + Reset(); + mURL = aURL; + mURL->AddRef(); + mType = Type::URL; +} + +// -------------------- // nsStyleDisplay // nsStyleDisplay::nsStyleDisplay(StyleStructContext aContext) : mDisplay(NS_STYLE_DISPLAY_INLINE) , mOriginalDisplay(NS_STYLE_DISPLAY_INLINE) , mContain(NS_STYLE_CONTAIN_NONE) , mAppearance(NS_THEME_NONE) , mPosition(NS_STYLE_POSITION_STATIC) @@ -2905,16 +3031,17 @@ nsStyleDisplay::nsStyleDisplay(const nsS , mAnimationTimingFunctionCount(aSource.mAnimationTimingFunctionCount) , mAnimationDurationCount(aSource.mAnimationDurationCount) , mAnimationDelayCount(aSource.mAnimationDelayCount) , mAnimationNameCount(aSource.mAnimationNameCount) , mAnimationDirectionCount(aSource.mAnimationDirectionCount) , mAnimationFillModeCount(aSource.mAnimationFillModeCount) , mAnimationPlayStateCount(aSource.mAnimationPlayStateCount) , mAnimationIterationCountCount(aSource.mAnimationIterationCountCount) + , mShapeOutside(aSource.mShapeOutside) { MOZ_COUNT_CTOR(nsStyleDisplay); /* Copy over transform origin. */ mTransformOrigin[0] = aSource.mTransformOrigin[0]; mTransformOrigin[1] = aSource.mTransformOrigin[1]; mTransformOrigin[2] = aSource.mTransformOrigin[2]; mPerspectiveOrigin[0] = aSource.mPerspectiveOrigin[0]; @@ -2984,17 +3111,18 @@ nsChangeHint nsStyleDisplay::CalcDiffere // XXX the following is conservative, for now: changing float breaking shouldn't // necessarily require a repaint, reflow should suffice. if (mBreakType != aOther.mBreakType || mBreakInside != aOther.mBreakInside || mBreakBefore != aOther.mBreakBefore || mBreakAfter != aOther.mBreakAfter || mAppearance != aOther.mAppearance || mOrient != aOther.mOrient - || mOverflowClipBox != aOther.mOverflowClipBox) + || mOverflowClipBox != aOther.mOverflowClipBox + || mShapeOutside != aOther.mShapeOutside) NS_UpdateHint(hint, NS_CombineHint(nsChangeHint_AllReflowHints, nsChangeHint_RepaintFrame)); if (mIsolation != aOther.mIsolation) { NS_UpdateHint(hint, nsChangeHint_RepaintFrame); } /* If we've added or removed the transform property, we need to reconstruct the frame to add
--- a/layout/style/nsStyleStruct.h +++ b/layout/style/nsStyleStruct.h @@ -33,16 +33,17 @@ #include "imgRequestProxy.h" #include "Orientation.h" #include "CounterStyleManager.h" #include <cstddef> // offsetof() #include <utility> class nsIFrame; class nsIURI; +class nsStyleBasicShape; class nsStyleContext; class nsTextFrame; class imgIContainer; struct nsStyleVisibility; // Includes nsStyleStructID. #include "nsStyleStructFwd.h" @@ -2453,16 +2454,66 @@ private: float mDelay; nsString mName; // empty string for 'none' dom::PlaybackDirection mDirection; dom::FillMode mFillMode; uint8_t mPlayState; float mIterationCount; // mozilla::PositiveInfinity<float>() means infinite }; +// shape-box for shape-outside +enum class StyleShapeBox : uint8_t { + None, + Margin, + Border, + Padding, + Content +}; + +struct StyleShapeOutside +{ + enum class Type : uint8_t { + None, + ShapeBox, + BasicShape, + URL + }; + + StyleShapeOutside(); + StyleShapeOutside(const StyleShapeOutside& aSource); + ~StyleShapeOutside(); + StyleShapeOutside& operator=(const StyleShapeOutside& aOther); + + bool operator==(const StyleShapeOutside& aOther) const; + bool operator!=(const StyleShapeOutside& aOther) const { + return !(*this == aOther); + } + + void Reset(); + + Type GetType() const { return mType; } + + StyleShapeBox GetShapeBox() const { return mShapeBox; } + void SetShapeBox(StyleShapeBox aShapeBox); + + nsStyleBasicShape* GetBasicShape() const { return mBasicShape; } + void SetBasicShape(nsStyleBasicShape* aBasicShape, + StyleShapeBox aShapeBox = StyleShapeBox::Margin); + nsIURI* GetURL() const { return mURL; } + void SetURL(nsIURI* aURL); + +private: + Type mType = Type::None; + StyleShapeBox mShapeBox = StyleShapeBox::None; + union { + nsStyleBasicShape* mBasicShape; + nsIURI* mURL; + }; +}; + } // namespace mozilla struct MOZ_NEEDS_MEMMOVABLE_MEMBERS nsStyleDisplay { explicit nsStyleDisplay(StyleStructContext aContext); nsStyleDisplay(const nsStyleDisplay& aOther); ~nsStyleDisplay() { MOZ_COUNT_DTOR(nsStyleDisplay); @@ -2573,16 +2624,18 @@ struct MOZ_NEEDS_MEMMOVABLE_MEMBERS nsSt mAnimationDurationCount, mAnimationDelayCount, mAnimationNameCount, mAnimationDirectionCount, mAnimationFillModeCount, mAnimationPlayStateCount, mAnimationIterationCountCount; + mozilla::StyleShapeOutside mShapeOutside; // [reset] + bool IsBlockInsideStyle() const { return NS_STYLE_DISPLAY_BLOCK == mDisplay || NS_STYLE_DISPLAY_LIST_ITEM == mDisplay || NS_STYLE_DISPLAY_INLINE_BLOCK == mDisplay || NS_STYLE_DISPLAY_TABLE_CAPTION == mDisplay; // Should TABLE_CELL be included here? They have // block frames nested inside of them. // (But please audit all callers before changing.)
--- a/layout/style/test/property_database.js +++ b/layout/style/test/property_database.js @@ -5518,195 +5518,217 @@ if (IsCSSPropertyPrefEnabled("svg.transf inherited: false, type: CSS_TYPE_LONGHAND, initial_values: [ "border-box" ], other_values: [ "fill-box", "view-box" ], invalid_values: [] }; } +var basicShapeOtherValues = [ + "polygon(20px 20px)", + "polygon(20px 20%)", + "polygon(20% 20%)", + "polygon(20rem 20em)", + "polygon(20cm 20mm)", + "polygon(20px 20px, 30px 30px)", + "polygon(20px 20px, 30% 30%, 30px 30px)", + "polygon(nonzero, 20px 20px, 30% 30%, 30px 30px)", + "polygon(evenodd, 20px 20px, 30% 30%, 30px 30px)", + + "content-box", + "padding-box", + "border-box", + "margin-box", + + "polygon(0 0) content-box", + "border-box polygon(0 0)", + "padding-box polygon( 0 20px , 30px 20% ) ", + "polygon(evenodd, 20% 20em) content-box", + "polygon(evenodd, 20vh 20em) padding-box", + "polygon(evenodd, 20vh calc(20% + 20em)) border-box", + "polygon(evenodd, 20vh 20vw) margin-box", + + "circle()", + "circle(at center)", + "circle(at top left 20px)", + "circle(at bottom right)", + "circle(20%)", + "circle(300px)", + "circle(calc(20px + 30px))", + "circle(farthest-side)", + "circle(closest-side)", + "circle(closest-side at center)", + "circle(farthest-side at top)", + "circle(20px at top right)", + "circle(40% at 50% 100%)", + "circle(calc(20% + 20%) at right bottom)", + "circle() padding-box", + + "ellipse()", + "ellipse(at center)", + "ellipse(at top left 20px)", + "ellipse(at bottom right)", + "ellipse(20% 20%)", + "ellipse(300px 50%)", + "ellipse(calc(20px + 30px) 10%)", + "ellipse(farthest-side closest-side)", + "ellipse(closest-side farthest-side)", + "ellipse(farthest-side farthest-side)", + "ellipse(closest-side closest-side)", + "ellipse(closest-side closest-side at center)", + "ellipse(20% farthest-side at top)", + "ellipse(20px 50% at top right)", + "ellipse(closest-side 40% at 50% 100%)", + "ellipse(calc(20% + 20%) calc(20px + 20cm) at right bottom)", + + "inset(1px)", + "inset(20% -20px)", + "inset(20em 4rem calc(20% + 20px))", + "inset(20vh 20vw 20pt 3%)", + "inset(5px round 3px)", + "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%)", +]; + +var basicShapeInvalidValues = [ + "url(#test) url(#tes2)", + "polygon (0 0)", + "polygon(20px, 40px)", + "border-box content-box", + "polygon(0 0) polygon(0 0)", + "polygon(nonzero 0 0)", + "polygon(evenodd 20px 20px)", + "polygon(20px 20px, evenodd)", + "polygon(20px 20px, nonzero)", + "polygon(0 0) conten-box content-box", + "content-box polygon(0 0) conten-box", + "padding-box polygon(0 0) conten-box", + "polygon(0 0) polygon(0 0) content-box", + "polygon(0 0) content-box polygon(0 0)", + "polygon(0 0), content-box", + "polygon(0 0), polygon(0 0)", + "content-box polygon(0 0) polygon(0 0)", + "content-box polygon(0 0) none", + "none content-box polygon(0 0)", + "inherit content-box polygon(0 0)", + "initial polygon(0 0)", + "polygon(0 0) farthest-side", + "farthest-corner polygon(0 0)", + "polygon(0 0) farthest-corner", + "polygon(0 0) conten-box", + "polygon(0 0) polygon(0 0) farthest-corner", + "polygon(0 0) polygon(0 0) polygon(0 0)", + "border-box polygon(0, 0)", + "border-box padding-box", + "margin-box farthest-side", + "nonsense() border-box", + "border-box nonsense()", + + "circle(at)", + "circle(at 20% 20% 30%)", + "circle(20px 2px at center)", + "circle(2at center)", + "circle(closest-corner)", + "circle(at center top closest-side)", + "circle(-20px)", + "circle(farthest-side closest-side)", + "circle(20% 20%)", + "circle(at farthest-side)", + "circle(calc(20px + rubbish))", + + "ellipse(at)", + "ellipse(at 20% 20% 30%)", + "ellipse(20px at center)", + "ellipse(-20px 20px)", + "ellipse(closest-corner farthest-corner)", + "ellipse(20px -20px)", + "ellipse(-20px -20px)", + "ellipse(farthest-side)", + "ellipse(20%)", + "ellipse(at farthest-side farthest-side)", + "ellipse(at top left calc(20px + rubbish))", + + "polygon(at)", + "polygon(at 20% 20% 30%)", + "polygon(20px at center)", + "polygon(2px 2at center)", + "polygon(closest-corner farthest-corner)", + "polygon(at center top closest-side closest-side)", + "polygon(40% at 50% 100%)", + "polygon(40% farthest-side 20px at 50% 100%)", + + "inset()", + "inset(round)", + "inset(round 3px)", + "inset(1px round 1px 2px 3px 4px 5px)", + "inset(1px 2px 3px 4px 5px)", + "inset(1px, round 3px)", + "inset(1px, 2px)", + "inset(1px 2px, 3px)", + "inset(1px at 3px)", + "inset(1px round 1px // 2px)", + "inset(1px round)", + "inset(1px calc(2px + rubbish))", + "inset(1px round 2px calc(3px + rubbish))", +]; + +var basicShapeUnbalancedValues = [ + "polygon(30% 30%", + "polygon(nonzero, 20% 20px", + "polygon(evenodd, 20px 20px", + + "circle(", + "circle(40% at 50% 100%", + "ellipse(", + "ellipse(40% at 50% 100%", + + "inset(1px", + "inset(1px 2px", + "inset(1px 2px 3px", + "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)", - "polygon(20px 20px)", - "polygon(20px 20%)", - "polygon(20% 20%)", - "polygon(20rem 20em)", - "polygon(20cm 20mm)", - "polygon(20px 20px, 30px 30px)", - "polygon(20px 20px, 30% 30%, 30px 30px)", - "polygon(nonzero, 20px 20px, 30% 30%, 30px 30px)", - "polygon(evenodd, 20px 20px, 30% 30%, 30px 30px)", - - "content-box", - "padding-box", - "border-box", - "margin-box", "fill-box", "stroke-box", "view-box", - "polygon(0 0) content-box", - "border-box polygon(0 0)", - "padding-box polygon( 0 20px , 30px 20% ) ", - "polygon(evenodd, 20% 20em) content-box", - "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)", - "circle(at top left 20px)", - "circle(at bottom right)", - "circle(20%)", - "circle(300px)", - "circle(calc(20px + 30px))", - "circle(farthest-side)", - "circle(closest-side)", - "circle(closest-side at center)", - "circle(farthest-side at top)", - "circle(20px at top right)", - "circle(40% at 50% 100%)", - "circle(calc(20% + 20%) at right bottom)", - "circle() padding-box", - - "ellipse()", - "ellipse(at center)", - "ellipse(at top left 20px)", - "ellipse(at bottom right)", - "ellipse(20% 20%)", - "ellipse(300px 50%)", - "ellipse(calc(20px + 30px) 10%)", - "ellipse(farthest-side closest-side)", - "ellipse(closest-side farthest-side)", - "ellipse(farthest-side farthest-side)", - "ellipse(closest-side closest-side)", - "ellipse(closest-side closest-side at center)", - "ellipse(20% farthest-side at top)", - "ellipse(20px 50% at top right)", - "ellipse(closest-side 40% at 50% 100%)", - "ellipse(calc(20% + 20%) calc(20px + 20cm) at right bottom)", - - "inset(1px)", - "inset(20% -20px)", - "inset(20em 4rem calc(20% + 20px))", - "inset(20vh 20vw 20pt 3%)", - "inset(5px round 3px)", - "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: [ - "url(#test) url(#tes2)", - "polygon (0 0)", - "polygon(20px, 40px)", - "border-box content-box", - "polygon(0 0) polygon(0 0)", - "polygon(nonzero 0 0)", - "polygon(evenodd 20px 20px)", - "polygon(20px 20px, evenodd)", - "polygon(20px 20px, nonzero)", - "polygon(0 0) conten-box content-box", - "content-box polygon(0 0) conten-box", - "padding-box polygon(0 0) conten-box", - "polygon(0 0) polygon(0 0) content-box", - "polygon(0 0) content-box polygon(0 0)", - "polygon(0 0), content-box", - "polygon(0 0), polygon(0 0)", - "content-box polygon(0 0) polygon(0 0)", - "content-box polygon(0 0) none", - "none content-box polygon(0 0)", - "inherit content-box polygon(0 0)", - "initial polygon(0 0)", - "polygon(0 0) farthest-side", - "farthest-corner polygon(0 0)", - "polygon(0 0) farthest-corner", - "polygon(0 0) conten-box", - "polygon(0 0) polygon(0 0) farthest-corner", - "polygon(0 0) polygon(0 0) polygon(0 0)", - "border-box polygon(0, 0)", - "border-box padding-box", - "margin-box farthest-side", - "nonsense() border-box", - "border-box nonsense()", - - "circle(at)", - "circle(at 20% 20% 30%)", - "circle(20px 2px at center)", - "circle(2at center)", - "circle(closest-corner)", - "circle(at center top closest-side)", - "circle(-20px)", - "circle(farthest-side closest-side)", - "circle(20% 20%)", - "circle(at farthest-side)", - "circle(calc(20px + rubbish))", - - "ellipse(at)", - "ellipse(at 20% 20% 30%)", - "ellipse(20px at center)", - "ellipse(-20px 20px)", - "ellipse(closest-corner farthest-corner)", - "ellipse(20px -20px)", - "ellipse(-20px -20px)", - "ellipse(farthest-side)", - "ellipse(20%)", - "ellipse(at farthest-side farthest-side)", - "ellipse(at top left calc(20px + rubbish))", - - "polygon(at)", - "polygon(at 20% 20% 30%)", - "polygon(20px at center)", - "polygon(2px 2at center)", - "polygon(closest-corner farthest-corner)", - "polygon(at center top closest-side closest-side)", - "polygon(40% at 50% 100%)", - "polygon(40% farthest-side 20px at 50% 100%)", - - "inset()", - "inset(round)", - "inset(round 3px)", - "inset(1px round 1px 2px 3px 4px 5px)", - "inset(1px 2px 3px 4px 5px)", - "inset(1px, round 3px)", - "inset(1px, 2px)", - "inset(1px 2px, 3px)", - "inset(1px at 3px)", - "inset(1px round 1px // 2px)", - "inset(1px round)", - "inset(1px calc(2px + rubbish))", - "inset(1px round 2px calc(3px + rubbish))", - ], - unbalanced_values: [ - "polygon(30% 30%", - "polygon(nonzero, 20% 20px", - "polygon(evenodd, 20px 20px", - - "circle(", - "circle(40% at 50% 100%", - "ellipse(", - "ellipse(40% at 50% 100%", - - "inset(1px", - "inset(1px 2px", - "inset(1px 2px 3px", - "inset(1px 2px 3px 4px", - "inset(1px 2px 3px 4px round 5px", - "inset(1px 2px 3px 4px round 5px / 6px", - ] + ].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, }; } if (IsCSSPropertyPrefEnabled("layout.css.filters.enabled")) { gCSSProperties["filter"] = { domProp: "filter", inherited: false,
--- a/modules/libpref/init/all.js +++ b/modules/libpref/init/all.js @@ -2513,16 +2513,23 @@ pref("layout.css.scroll-behavior.spring- // reduced speed without overshooting. // When equal to 1.0, the system is critically-damped; it will reach the target // at the greatest speed without overshooting. 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? +#ifdef NIGHTLY_BUILD +pref("layout.css.shape-outside.enabled", true); +#else +pref("layout.css.shape-outside.enabled", false); +#endif + // Is support for document.fonts enabled? pref("layout.css.font-loading-api.enabled", true); // Should stray control characters be rendered visibly? #ifdef RELEASE_BUILD pref("layout.css.control-characters.visible", false); #else pref("layout.css.control-characters.visible", true);