Bug 505115 - Part 9 - Implement the perspective() transform function and style property. diff --git a/dom/interfaces/css/nsIDOMCSS2Properties.idl b/dom/interfaces/css/nsIDOMCSS2Properties.idl --- a/dom/interfaces/css/nsIDOMCSS2Properties.idl +++ b/dom/interfaces/css/nsIDOMCSS2Properties.idl @@ -675,16 +675,19 @@ interface nsIDOMCSS2Properties : nsISupp // raises(DOMException) on setting attribute DOMString MozTransformOrigin; // raises(DOMException) on setting attribute DOMString MozPerspective; // raises(DOMException) on setting + attribute DOMString MozBackfaceVisibility; + // raises(DOMException) on setting + attribute DOMString MozWindowShadow; // raises(DOMException) on setting attribute DOMString backgroundSize; // raises(DOMException) on setting attribute DOMString MozTextBlink; // raises(DOMException) on setting diff --git a/gfx/thebes/gfx3DMatrix.cpp b/gfx/thebes/gfx3DMatrix.cpp --- a/gfx/thebes/gfx3DMatrix.cpp +++ b/gfx/thebes/gfx3DMatrix.cpp @@ -387,8 +387,22 @@ gfxRect gfx3DMatrix::ProjectRect(const g max_x = max(points[i].x, max_x); min_y = min(points[i].y, min_y); max_y = max(points[i].y, max_y); } return gfxRect(min_x, min_y, max_x - min_x, max_y - min_y); } +gfxPoint3D gfx3DMatrix::GetNormalVector() const +{ + // Define a plane in transformed space as the transformations + // of 3 points on the z=0 screen plane. + gfxPoint3D a = Transform3D(gfxPoint3D(0, 0, 0)); + gfxPoint3D b = Transform3D(gfxPoint3D(0, 1, 0)); + gfxPoint3D c = Transform3D(gfxPoint3D(1, 0, 0)); + + // Convert to two vectors on the surface of the plane. + gfxPoint3D ab = a - b; + gfxPoint3D ac = a - c; + + return ab.CrossProduct(ac); +} diff --git a/gfx/thebes/gfx3DMatrix.h b/gfx/thebes/gfx3DMatrix.h --- a/gfx/thebes/gfx3DMatrix.h +++ b/gfx/thebes/gfx3DMatrix.h @@ -129,16 +129,18 @@ public: inline gfx3DMatrix Inverse() const { gfx3DMatrix temp = *this; temp.Invert(); return temp; } + gfxPoint3D GetNormalVector() const; + /** * Check if matrix is singular (no inverse exists). */ PRBool IsSingular() const; /** * Create a translation matrix. * diff --git a/layout/base/nsDisplayList.cpp b/layout/base/nsDisplayList.cpp --- a/layout/base/nsDisplayList.cpp +++ b/layout/base/nsDisplayList.cpp @@ -2398,19 +2398,23 @@ nsDisplayTransform::GetTransform(float a } return mTransform; } already_AddRefed nsDisplayTransform::BuildLayer(nsDisplayListBuilder *aBuilder, LayerManager *aManager) { const gfx3DMatrix& newTransformMatrix = GetTransform(mFrame->PresContext()->AppUnitsPerDevPixel()); - - if (newTransformMatrix.IsSingular()) - return nsnull; + + gfxPoint3D normal = newTransformMatrix.GetNormalVector(); + if (newTransformMatrix.IsSingular() || + (mFrame->GetStyleDisplay()->mBackfaceVisible == NS_STYLE_BACKFACE_HIDDEN && + normal.DotProduct(gfxPoint3D(0,0,1)) >= 0.0)) { + return nsnull; + } nsRefPtr layer = aBuilder->LayerBuilder()-> BuildContainerLayerFor(aBuilder, aManager, mFrame, this, *mStoredList.GetList()); if (!layer) return nsnull; layer->SetTransform(newTransformMatrix); return layer.forget(); diff --git a/layout/base/nsStyleConsts.h b/layout/base/nsStyleConsts.h --- a/layout/base/nsStyleConsts.h +++ b/layout/base/nsStyleConsts.h @@ -854,16 +854,20 @@ static inline mozilla::css::Side operato #define NS_STYLE_TEXT_RENDERING_OPTIMIZELEGIBILITY 2 #define NS_STYLE_TEXT_RENDERING_GEOMETRICPRECISION 3 // color-interpolation and color-interpolation-filters #define NS_STYLE_COLOR_INTERPOLATION_AUTO 0 #define NS_STYLE_COLOR_INTERPOLATION_SRGB 1 #define NS_STYLE_COLOR_INTERPOLATION_LINEARRGB 2 +// 3d Transforms - Backface visibility +#define NS_STYLE_BACKFACE_VISIBLE 1 +#define NS_STYLE_BACKFACE_HIDDEN 0 + /***************************************************************************** * Constants for media features. * *****************************************************************************/ // orientation #define NS_STYLE_ORIENTATION_PORTRAIT 0 #define NS_STYLE_ORIENTATION_LANDSCAPE 1 diff --git a/layout/style/nsCSSPropList.h b/layout/style/nsCSSPropList.h --- a/layout/style/nsCSSPropList.h +++ b/layout/style/nsCSSPropList.h @@ -2255,16 +2255,25 @@ CSS_PROP_DISPLAY( -moz-perspective, _moz_perspective, CSS_PROP_DOMPROP_PREFIXED(Perspective), CSS_PROPERTY_PARSE_VALUE, VARIANT_NONE|VARIANT_INHERIT|VARIANT_NUMBER, kDisplayKTable, offsetof(nsStyleDisplay, mChildPerspective), eStyleAnimType_float) +CSS_PROP_DISPLAY( + -moz-backface-visibility, + _moz_backface_visibility, + CSS_PROP_DOMPROP_PREFIXED(BackfaceVisibility), + CSS_PROPERTY_PARSE_VALUE, + VARIANT_HK, + kBackfaceVisibilityKTable, + offsetof(nsStyleDisplay, mBackfaceVisible), + eStyleAnimType_EnumU8) CSS_PROP_POSITION( top, top, Top, CSS_PROPERTY_PARSE_VALUE | CSS_PROPERTY_STORES_CALC, VARIANT_AHLP | VARIANT_CALC, nsnull, diff --git a/layout/style/nsCSSProps.cpp b/layout/style/nsCSSProps.cpp --- a/layout/style/nsCSSProps.cpp +++ b/layout/style/nsCSSProps.cpp @@ -578,16 +578,21 @@ const PRInt32 nsCSSProps::kAppearanceKTa eCSSKeyword__moz_window_button_maximize, NS_THEME_WINDOW_BUTTON_MAXIMIZE, eCSSKeyword__moz_window_button_restore, NS_THEME_WINDOW_BUTTON_RESTORE, eCSSKeyword__moz_window_button_box, NS_THEME_WINDOW_BUTTON_BOX, eCSSKeyword__moz_window_button_box_maximized, NS_THEME_WINDOW_BUTTON_BOX_MAXIMIZED, eCSSKeyword__moz_win_exclude_glass, NS_THEME_WIN_EXCLUDE_GLASS, eCSSKeyword_UNKNOWN,-1 }; +const PRInt32 nsCSSProps::kBackfaceVisibilityKTable[] = { + eCSSKeyword_visible, NS_STYLE_BACKFACE_VISIBLE, + eCSSKeyword_hidden, NS_STYLE_BACKFACE_HIDDEN +}; + const PRInt32 nsCSSProps::kBackgroundAttachmentKTable[] = { eCSSKeyword_fixed, NS_STYLE_BG_ATTACHMENT_FIXED, eCSSKeyword_scroll, NS_STYLE_BG_ATTACHMENT_SCROLL, eCSSKeyword_UNKNOWN,-1 }; const PRInt32 nsCSSProps::kBackgroundInlinePolicyKTable[] = { eCSSKeyword_each_box, NS_STYLE_BG_INLINE_POLICY_EACH_BOX, diff --git a/layout/style/nsCSSProps.h b/layout/style/nsCSSProps.h --- a/layout/style/nsCSSProps.h +++ b/layout/style/nsCSSProps.h @@ -330,16 +330,17 @@ public: static const PRInt32 kAnimationDirectionKTable[]; static const PRInt32 kAnimationFillModeKTable[]; static const PRInt32 kAnimationIterationCountKTable[]; static const PRInt32 kAnimationPlayStateKTable[]; static const PRInt32 kAnimationTimingFunctionKTable[]; #endif static const PRInt32 kAppearanceKTable[]; static const PRInt32 kAzimuthKTable[]; + static const PRInt32 kBackfaceVisibilityKTable[]; static const PRInt32 kBackgroundAttachmentKTable[]; static const PRInt32 kBackgroundInlinePolicyKTable[]; static const PRInt32 kBackgroundOriginKTable[]; static const PRInt32 kBackgroundPositionKTable[]; static const PRInt32 kBackgroundRepeatKTable[]; static const PRInt32 kBackgroundSizeKTable[]; static const PRInt32 kBorderCollapseKTable[]; static const PRInt32 kBorderColorKTable[]; diff --git a/layout/style/nsComputedDOMStyle.cpp b/layout/style/nsComputedDOMStyle.cpp --- a/layout/style/nsComputedDOMStyle.cpp +++ b/layout/style/nsComputedDOMStyle.cpp @@ -945,16 +945,26 @@ nsComputedDOMStyle::DoGetMozTransformOri nsIDOMCSSValue* nsComputedDOMStyle::DoGetMozPerspective() { nsROCSSPrimitiveValue* val = GetROCSSPrimitiveValue(); val->SetNumber(GetStyleDisplay()->mChildPerspective); return val; } +nsIDOMCSSValue* +nsComputedDOMStyle::DoGetMozBackfaceVisibility() +{ + nsROCSSPrimitiveValue* val = GetROCSSPrimitiveValue(); + val->SetIdent( + nsCSSProps::ValueToKeywordEnum(GetStyleDisplay()->mBackfaceVisible, + nsCSSProps::kBackfaceVisibilityKTable)); + return val; +} + /* If the property is "none", hand back "none" wrapped in a value. * Otherwise, compute the aggregate transform matrix and hands it back in a * "matrix" wrapper. */ nsIDOMCSSValue* nsComputedDOMStyle::DoGetMozTransform() { /* First, get the display data. We'll need it. */ @@ -4353,16 +4363,17 @@ nsComputedDOMStyle::GetQueryableProperty COMPUTED_STYLE_MAP_ENTRY(animation_duration, AnimationDuration), COMPUTED_STYLE_MAP_ENTRY(animation_fill_mode, AnimationFillMode), COMPUTED_STYLE_MAP_ENTRY(animation_iteration_count, AnimationIterationCount), COMPUTED_STYLE_MAP_ENTRY(animation_name, AnimationName), COMPUTED_STYLE_MAP_ENTRY(animation_play_state, AnimationPlayState), COMPUTED_STYLE_MAP_ENTRY(animation_timing_function, AnimationTimingFunction), #endif COMPUTED_STYLE_MAP_ENTRY(appearance, Appearance), + COMPUTED_STYLE_MAP_ENTRY_LAYOUT(_moz_backface_visibility, MozBackfaceVisibility), COMPUTED_STYLE_MAP_ENTRY(_moz_background_inline_policy, BackgroundInlinePolicy), COMPUTED_STYLE_MAP_ENTRY(binding, Binding), COMPUTED_STYLE_MAP_ENTRY(border_bottom_colors, BorderBottomColors), COMPUTED_STYLE_MAP_ENTRY(border_image, BorderImage), COMPUTED_STYLE_MAP_ENTRY(border_left_colors, BorderLeftColors), COMPUTED_STYLE_MAP_ENTRY(border_right_colors, BorderRightColors), COMPUTED_STYLE_MAP_ENTRY(border_top_colors, BorderTopColors), COMPUTED_STYLE_MAP_ENTRY(box_align, BoxAlign), diff --git a/layout/style/nsComputedDOMStyle.h b/layout/style/nsComputedDOMStyle.h --- a/layout/style/nsComputedDOMStyle.h +++ b/layout/style/nsComputedDOMStyle.h @@ -342,16 +342,17 @@ private: nsIDOMCSSValue* DoGetOverflowX(); nsIDOMCSSValue* DoGetOverflowY(); nsIDOMCSSValue* DoGetResize(); nsIDOMCSSValue* DoGetPageBreakAfter(); nsIDOMCSSValue* DoGetPageBreakBefore(); nsIDOMCSSValue* DoGetMozTransform(); nsIDOMCSSValue* DoGetMozTransformOrigin(); nsIDOMCSSValue* DoGetMozPerspective(); + nsIDOMCSSValue* DoGetMozBackfaceVisibility(); nsIDOMCSSValue* DoGetOrient(); /* User interface properties */ nsIDOMCSSValue* DoGetCursor(); nsIDOMCSSValue* DoGetForceBrokenImageIcon(); nsIDOMCSSValue* DoGetIMEMode(); nsIDOMCSSValue* DoGetUserFocus(); nsIDOMCSSValue* DoGetUserInput(); diff --git a/layout/style/nsRuleNode.cpp b/layout/style/nsRuleNode.cpp --- a/layout/style/nsRuleNode.cpp +++ b/layout/style/nsRuleNode.cpp @@ -4477,16 +4477,20 @@ nsRuleNode::ComputeDisplayData(void* aSt NS_ASSERTION(result, "Malformed -moz-transform-origin parse!"); } SetFactor(*aRuleData->ValueForPerspective(), display->mChildPerspective, canStoreInRuleTree, parentDisplay->mChildPerspective, 0.0f, SETFCT_NONE); + SetDiscrete(*aRuleData->ValueForBackfaceVisibility(), + display->mBackfaceVisible, canStoreInRuleTree, + SETDSC_ENUMERATED, parentDisplay->mBackfaceVisible, + NS_STYLE_BACKFACE_VISIBLE, 0, 0, 0, 0); // orient: enum, inherit, initial SetDiscrete(*aRuleData->ValueForOrient(), display->mOrient, canStoreInRuleTree, SETDSC_ENUMERATED, parentDisplay->mOrient, NS_STYLE_ORIENT_HORIZONTAL, 0, 0, 0, 0); COMPUTE_END_RESET(Display, display) diff --git a/layout/style/nsStyleAnimation.cpp b/layout/style/nsStyleAnimation.cpp --- a/layout/style/nsStyleAnimation.cpp +++ b/layout/style/nsStyleAnimation.cpp @@ -280,16 +280,25 @@ nsStyleAnimation::ComputeDistance(nsCSSP switch (aProperty) { case eCSSProperty_font_stretch: { // just like eUnit_Integer. PRInt32 startInt = aStartValue.GetIntValue(); PRInt32 endInt = aEndValue.GetIntValue(); aDistance = PR_ABS(endInt - startInt); return PR_TRUE; } + case eCSSProperty__moz_backface_visibility: { + // just like eUnit_Integer. + PRInt32 startInt = + aStartValue.GetIntValue() == NS_STYLE_BACKFACE_VISIBLE; + PRInt32 endInt = + aEndValue.GetIntValue() == NS_STYLE_BACKFACE_VISIBLE; + aDistance = PR_ABS(endInt - startInt); + return PR_TRUE; + } default: return PR_FALSE; } case eUnit_Visibility: { PRInt32 startVal = aStartValue.GetIntValue() == NS_STYLE_VISIBILITY_VISIBLE; PRInt32 endVal = aEndValue.GetIntValue() == NS_STYLE_VISIBILITY_VISIBLE; @@ -1397,16 +1406,25 @@ nsStyleAnimation::AddWeighted(nsCSSPrope if (result < NS_STYLE_FONT_STRETCH_ULTRA_CONDENSED) { result = NS_STYLE_FONT_STRETCH_ULTRA_CONDENSED; } else if (result > NS_STYLE_FONT_STRETCH_ULTRA_EXPANDED) { result = NS_STYLE_FONT_STRETCH_ULTRA_EXPANDED; } aResultValue.SetIntValue(result, eUnit_Enumerated); return PR_TRUE; } + case eCSSProperty__moz_backface_visibility: { + PRInt32 val1 = aValue1.GetIntValue() == NS_STYLE_BACKFACE_VISIBLE; + PRInt32 val2 = aValue2.GetIntValue() == NS_STYLE_BACKFACE_VISIBLE; + double interp = aCoeff1 * val1 + aCoeff2 * val2; + PRInt32 result = interp > 0.0 ? NS_STYLE_BACKFACE_VISIBLE + : NS_STYLE_BACKFACE_HIDDEN; + aResultValue.SetIntValue(result, eUnit_Enumerated); + return PR_TRUE; + } default: return PR_FALSE; } case eUnit_Visibility: { PRInt32 val1 = aValue1.GetIntValue() == NS_STYLE_VISIBILITY_VISIBLE; PRInt32 val2 = aValue2.GetIntValue() == NS_STYLE_VISIBILITY_VISIBLE; double interp = aCoeff1 * val1 + aCoeff2 * val2; PRInt32 result = interp > 0.0 ? NS_STYLE_VISIBILITY_VISIBLE diff --git a/layout/style/nsStyleStruct.cpp b/layout/style/nsStyleStruct.cpp --- a/layout/style/nsStyleStruct.cpp +++ b/layout/style/nsStyleStruct.cpp @@ -2029,16 +2029,17 @@ nsStyleDisplay::nsStyleDisplay() mClipFlags = NS_STYLE_CLIP_AUTO; mClip.SetRect(0,0,0,0); mOpacity = 1.0f; mSpecifiedTransform = nsnull; mTransformOrigin[0].SetPercentValue(0.5f); // Transform is centered on origin mTransformOrigin[1].SetPercentValue(0.5f); mChildPerspective = 0.0; mPerspective = 0.0; + mBackfaceVisible = NS_STYLE_BACKFACE_VISIBLE; mOrient = NS_STYLE_ORIENT_HORIZONTAL; mTransitions.AppendElement(); NS_ABORT_IF_FALSE(mTransitions.Length() == 1, "appending within auto buffer should never fail"); mTransitions[0].SetInitialValues(); mTransitionTimingFunctionCount = 1; mTransitionDurationCount = 1; @@ -2100,16 +2101,18 @@ nsStyleDisplay::nsStyleDisplay(const nsS /* Copy over the transformation information. */ mSpecifiedTransform = aSource.mSpecifiedTransform; /* Copy over transform origin. */ mTransformOrigin[0] = aSource.mTransformOrigin[0]; mTransformOrigin[1] = aSource.mTransformOrigin[1]; mPerspective = aSource.mPerspective; mChildPerspective = aSource.mChildPerspective; + + mBackfaceVisible = aSource.mBackfaceVisible; } nsChangeHint nsStyleDisplay::CalcDifference(const nsStyleDisplay& aOther) const { nsChangeHint hint = nsChangeHint(0); if (!EqualURIs(mBinding, aOther.mBinding) || mPosition != aOther.mPosition @@ -2168,16 +2171,20 @@ nsChangeHint nsStyleDisplay::CalcDiffere if (!(mPerspective == aOther.mPerspective)) NS_UpdateHint(hint, NS_CombineHint(nsChangeHint_ReflowFrame, nsChangeHint_RepaintFrame)); if (!(mChildPerspective == aOther.mChildPerspective)) NS_UpdateHint(hint, NS_CombineHint(nsChangeHint_ReflowFrame, nsChangeHint_RepaintFrame)); + + if (mBackfaceVisible != aOther.mBackfaceVisible) + NS_UpdateHint(hint, NS_CombineHint(nsChangeHint_ReflowFrame, + nsChangeHint_RepaintFrame)); } // Note: Our current behavior for handling changes to the // transition-duration, transition-delay, and transition-timing-function // properties is to do nothing. In other words, the transition // property that matters is what it is when the transition begins, and // we don't stop a transition later because the transition property // changed. diff --git a/layout/style/nsStyleStruct.h b/layout/style/nsStyleStruct.h --- a/layout/style/nsStyleStruct.h +++ b/layout/style/nsStyleStruct.h @@ -1499,16 +1499,17 @@ struct nsStyleDisplay { // mSpecifiedTransform is the list of transform functions as // specified, or null to indicate there is no transform. (inherit or // initial are replaced by an actual list of transform functions, or // null, as appropriate.) (owned by the style rule) const nsCSSValueList *mSpecifiedTransform; // [reset] nsStyleCoord mTransformOrigin[2]; // [reset] percent, coord, calc float mPerspective; float mChildPerspective; + PRUint8 mBackfaceVisible; nsAutoTArray mTransitions; // [reset] // The number of elements in mTransitions that are not from repeating // a list due to another property being longer. PRUint32 mTransitionTimingFunctionCount, mTransitionDurationCount, mTransitionDelayCount, mTransitionPropertyCount; diff --git a/layout/style/test/property_database.js b/layout/style/test/property_database.js --- a/layout/style/test/property_database.js +++ b/layout/style/test/property_database.js @@ -969,16 +969,24 @@ var gCSSProperties = { "-moz-perspective": { domProp: "MozPerspective", inherited: false, type: CSS_TYPE_LONGHAND, initial_values: [ "0" ], other_values: [ "1000", "500.2" ], invalid_values: [ "pants" ] }, + "-moz-backface-visibility": { + domProp: "MozBackfaceVisibility", + inherited: false, + type: CSS_TYPE_LONGHAND, + initial_values: [ "visible" ], + other_values: [ "hidden" ], + invalid_values: [] + }, "-moz-user-focus": { domProp: "MozUserFocus", inherited: true, type: CSS_TYPE_LONGHAND, initial_values: [ "none" ], other_values: [ "normal", "ignore", "select-all", "select-before", "select-after", "select-same", "select-menu" ], invalid_values: [] }, diff --git a/layout/style/test/test_transitions_per_property.html b/layout/style/test/test_transitions_per_property.html --- a/layout/style/test/test_transitions_per_property.html +++ b/layout/style/test/test_transitions_per_property.html @@ -76,16 +76,17 @@ var supported_properties = { "-moz-outline-radius-topleft": [ test_radius_transition ], "-moz-outline-radius-topright": [ test_radius_transition ], "-moz-text-decoration-color": [ test_color_transition, test_border_color_transition ], "-moz-transform": [ test_transform_transition ], "-moz-transform-origin": [ test_length_pair_transition, test_length_percent_pair_transition, test_length_percent_pair_unclamped ], + "-moz-backface-visibility": [ test_visibility_transition ], "background-color": [ test_color_transition ], "background-position": [ test_background_position_transition, // FIXME: We don't currently test clamping, // since background-position uses calc() as // an intermediate form. /* test_length_percent_pair_unclamped */ ], "background-size": [ test_background_size_transition, // FIXME: We don't currently test clamping,