Bug 755084 Part 2: Perform CSS animations of transform and opacity on the compositor r=roc, dbaron

This commit is contained in:
David Zbarsky 2012-07-31 10:28:21 -07:00
parent ed9088a8ff
commit bde306fdca
18 changed files with 827 additions and 212 deletions

View File

@ -1291,6 +1291,8 @@ private:
NodeMayHaveDOMMutationObserver,
// Set if node is Content
NodeIsContent,
// Set if the node has animations or transitions
ElementHasAnimations,
// Guard value
BooleanFlagCount
};
@ -1356,6 +1358,8 @@ public:
bool HasPointerLock() const { return GetBoolFlag(ElementHasPointerLock); }
void SetPointerLock() { SetBoolFlag(ElementHasPointerLock); }
void ClearPointerLock() { ClearBoolFlag(ElementHasPointerLock); }
bool MayHaveAnimations() { return GetBoolFlag(ElementHasAnimations); }
void SetMayHaveAnimations() { SetBoolFlag(ElementHasAnimations); }
protected:
void SetParentIsContent(bool aValue) { SetBoolFlag(ParentIsContent, aValue); }
void SetInDocument() { SetBoolFlag(IsInDocument); }

View File

@ -26,6 +26,11 @@ public:
Init(aX1, aY1, aX2, aY2);
}
double X1() const { return mX1; }
double Y1() const { return mY1; }
double X2() const { return mX2; }
double Y2() const { return mY2; }
void Init(double aX1, double aY1,
double aX2, double aY2);

View File

@ -21,6 +21,9 @@
#include "mozilla/Preferences.h"
#include "sampler.h"
#include "nsAnimationManager.h"
#include "nsTransitionManager.h"
#ifdef DEBUG
#include <stdio.h>
#endif
@ -628,7 +631,7 @@ FrameLayerBuilder::FlashPaint(gfxContext *aContext)
if (!sPaintFlashingPrefCached) {
sPaintFlashingPrefCached = true;
mozilla::Preferences::AddBoolVarCache(&sPaintFlashingEnabled,
mozilla::Preferences::AddBoolVarCache(&sPaintFlashingEnabled,
"nglayout.debug.paint_flashing");
}
@ -1235,7 +1238,7 @@ ContainerState::ThebesLayerData::UpdateCommonClipCount(
} else {
// first item in the layer
mCommonClipCount = aCurrentClip.mRoundedClipRects.Length();
}
}
}
already_AddRefed<ImageContainer>
@ -1257,7 +1260,7 @@ ContainerState::PopThebesLayerData()
ThebesLayerData* data = mThebesLayerDataStack[lastIndex];
nsRefPtr<Layer> layer;
nsRefPtr<ImageContainer> imageContainer = data->CanOptimizeImageLayer();
nsRefPtr<ImageContainer> imageContainer = data->CanOptimizeImageLayer();
if ((data->mIsSolidColorInVisibleRegion || imageContainer) &&
data->mLayer->GetValidRegion().IsEmpty()) {
@ -1315,7 +1318,7 @@ ContainerState::PopThebesLayerData()
if (!layer->GetTransform().Is2D(&transform)) {
NS_ERROR("Only 2D transformations currently supported");
}
// ImageLayers are already configured with a visible region
if (!imageContainer) {
NS_ASSERTION(!transform.HasNonIntegerTranslation(),
@ -1645,9 +1648,9 @@ PaintInactiveLayer(nsDisplayListBuilder* aBuilder,
nsRefPtr<gfxContext> context = aContext;
#ifdef MOZ_DUMP_PAINTING
nsRefPtr<gfxASurface> surf;
nsRefPtr<gfxASurface> surf;
if (gfxUtils::sDumpPainting) {
surf = gfxPlatform::GetPlatform()->CreateOffscreenSurface(itemVisibleRect.Size(),
surf = gfxPlatform::GetPlatform()->CreateOffscreenSurface(itemVisibleRect.Size(),
gfxASurface::CONTENT_COLOR_ALPHA);
surf->SetDeviceOffset(-itemVisibleRect.TopLeft());
context = new gfxContext(surf);
@ -1680,7 +1683,7 @@ PaintInactiveLayer(nsDisplayListBuilder* aBuilder,
#ifdef MOZ_DUMP_PAINTING
if (gfxUtils::sDumpPainting) {
DumpPaintedImage(aItem, surf);
surf->SetDeviceOffset(gfxPoint(0, 0));
aContext->SetSource(surf, itemVisibleRect.TopLeft());
aContext->Rectangle(itemVisibleRect);
@ -2557,8 +2560,8 @@ static void DebugPaintItem(nsRenderingContext* aDest, nsDisplayItem *aItem, nsDi
gfxRect bounds(appUnitBounds.x, appUnitBounds.y, appUnitBounds.width, appUnitBounds.height);
bounds.ScaleInverse(aDest->AppUnitsPerDevPixel());
nsRefPtr<gfxASurface> surf =
gfxPlatform::GetPlatform()->CreateOffscreenSurface(gfxIntSize(bounds.width, bounds.height),
nsRefPtr<gfxASurface> surf =
gfxPlatform::GetPlatform()->CreateOffscreenSurface(gfxIntSize(bounds.width, bounds.height),
gfxASurface::CONTENT_COLOR_ALPHA);
surf->SetDeviceOffset(-bounds.TopLeft());
nsRefPtr<gfxContext> context = new gfxContext(surf);
@ -2568,7 +2571,7 @@ static void DebugPaintItem(nsRenderingContext* aDest, nsDisplayItem *aItem, nsDi
aItem->Paint(aBuilder, ctx);
DumpPaintedImage(aItem, surf);
aItem->SetPainted();
surf->SetDeviceOffset(gfxPoint(0, 0));
aDest->ThebesContext()->SetSource(surf, bounds.TopLeft());
aDest->ThebesContext()->Rectangle(bounds);
@ -3030,7 +3033,7 @@ CalculateBounds(nsTArray<FrameLayerBuilder::Clip::RoundedRect> aRects, PRInt32 A
void
ContainerState::SetupMaskLayer(Layer *aLayer, const FrameLayerBuilder::Clip& aClip,
PRUint32 aRoundedRectClipCount)
PRUint32 aRoundedRectClipCount)
{
// don't build an unnecessary mask
nsIntRect layerBounds = aLayer->GetVisibleRegion().GetBounds();
@ -3056,7 +3059,7 @@ ContainerState::SetupMaskLayer(Layer *aLayer, const FrameLayerBuilder::Clip& aCl
aLayer->SetMaskLayer(maskLayer);
return;
}
// calculate a more precise bounding rect
const PRInt32 A2D = mContainerFrame->PresContext()->AppUnitsPerDevPixel();
gfxRect boundingRect = CalculateBounds(newData.mRoundedClipRects, A2D);

View File

@ -10,6 +10,8 @@
* used during painting and hit testing
*/
#include "mozilla/layers/PLayers.h"
#include "nsDisplayList.h"
#include "nsCSSRendering.h"
@ -36,6 +38,8 @@
#include "nsSVGElement.h"
#include "nsSVGClipPathFrame.h"
#include "sampler.h"
#include "nsAnimationManager.h"
#include "nsIViewManager.h"
#include "mozilla/StandardInteger.h"
@ -43,6 +47,337 @@ using namespace mozilla;
using namespace mozilla::layers;
typedef FrameMetrics::ViewID ViewID;
static void AddTransformFunctions(nsCSSValueList* aList,
nsStyleContext* aContext,
nsPresContext* aPresContext,
nsRect& aBounds,
float aAppUnitsPerPixel,
InfallibleTArray<TransformFunction>& aFunctions)
{
if (aList->mValue.GetUnit() == eCSSUnit_None) {
return;
}
for (const nsCSSValueList* curr = aList; curr; curr = curr->mNext) {
const nsCSSValue& currElem = curr->mValue;
NS_ASSERTION(currElem.GetUnit() == eCSSUnit_Function,
"Stream should consist solely of functions!");
nsCSSValue::Array* array = currElem.GetArrayValue();
bool canStoreInRuleTree = true;
switch (nsStyleTransformMatrix::TransformFunctionOf(array)) {
case eCSSKeyword_rotatex:
{
double theta = array->Item(1).GetAngleValueInRadians();
aFunctions.AppendElement(RotationX(theta));
break;
}
case eCSSKeyword_rotatey:
{
double theta = array->Item(1).GetAngleValueInRadians();
aFunctions.AppendElement(RotationY(theta));
break;
}
case eCSSKeyword_rotatez:
{
double theta = array->Item(1).GetAngleValueInRadians();
aFunctions.AppendElement(RotationZ(theta));
break;
}
case eCSSKeyword_rotate:
{
double theta = array->Item(1).GetAngleValueInRadians();
aFunctions.AppendElement(Rotation(theta));
break;
}
case eCSSKeyword_rotate3d:
{
double x = array->Item(1).GetFloatValue();
double y = array->Item(2).GetFloatValue();
double z = array->Item(3).GetFloatValue();
double theta = array->Item(4).GetAngleValueInRadians();
aFunctions.AppendElement(Rotation3D(x, y, z, theta));
break;
}
case eCSSKeyword_scalex:
{
double x = array->Item(1).GetFloatValue();
aFunctions.AppendElement(Scale(x, 1, 1));
break;
}
case eCSSKeyword_scaley:
{
double y = array->Item(1).GetFloatValue();
aFunctions.AppendElement(Scale(1, y, 1));
break;
}
case eCSSKeyword_scalez:
{
double z = array->Item(1).GetFloatValue();
aFunctions.AppendElement(Scale(1, 1, z));
break;
}
case eCSSKeyword_scale:
{
double x = array->Item(1).GetFloatValue();
// scale(x) is shorthand for scale(x, x);
double y = array->Count() == 2 ? x : array->Item(2).GetFloatValue();
aFunctions.AppendElement(Scale(x, y, 1));
break;
}
case eCSSKeyword_scale3d:
{
double x = array->Item(1).GetFloatValue();
double y = array->Item(2).GetFloatValue();
double z = array->Item(3).GetFloatValue();
aFunctions.AppendElement(Scale(x, y, z));
break;
}
case eCSSKeyword_translatex:
{
double x = nsStyleTransformMatrix::ProcessTranslatePart(
array->Item(1), aContext, aPresContext, canStoreInRuleTree,
aBounds.Width(), aAppUnitsPerPixel);
aFunctions.AppendElement(Translation(x, 0, 0));
break;
}
case eCSSKeyword_translatey:
{
double y = nsStyleTransformMatrix::ProcessTranslatePart(
array->Item(1), aContext, aPresContext, canStoreInRuleTree,
aBounds.Height(), aAppUnitsPerPixel);
aFunctions.AppendElement(Translation(0, y, 0));
break;
}
case eCSSKeyword_translatez:
{
double z = nsStyleTransformMatrix::ProcessTranslatePart(
array->Item(1), aContext, aPresContext, canStoreInRuleTree,
0, aAppUnitsPerPixel);
aFunctions.AppendElement(Translation(0, 0, z));
break;
}
case eCSSKeyword_translate:
{
double x = nsStyleTransformMatrix::ProcessTranslatePart(
array->Item(1), aContext, aPresContext, canStoreInRuleTree,
aBounds.Width(), aAppUnitsPerPixel);
// translate(x) is shorthand for translate(x, 0)
double y = 0;
if (array->Count() == 3) {
y = nsStyleTransformMatrix::ProcessTranslatePart(
array->Item(2), aContext, aPresContext, canStoreInRuleTree,
aBounds.Height(), aAppUnitsPerPixel);
}
aFunctions.AppendElement(Translation(x, y, 0));
break;
}
case eCSSKeyword_translate3d:
{
double x = nsStyleTransformMatrix::ProcessTranslatePart(
array->Item(1), aContext, aPresContext, canStoreInRuleTree,
aBounds.Width(), aAppUnitsPerPixel);
double y = nsStyleTransformMatrix::ProcessTranslatePart(
array->Item(2), aContext, aPresContext, canStoreInRuleTree,
aBounds.Height(), aAppUnitsPerPixel);
double z = nsStyleTransformMatrix::ProcessTranslatePart(
array->Item(3), aContext, aPresContext, canStoreInRuleTree,
0, aAppUnitsPerPixel);
aFunctions.AppendElement(Translation(x, y, z));
break;
}
case eCSSKeyword_skewx:
{
double x = array->Item(1).GetFloatValue();
aFunctions.AppendElement(SkewX(x));
break;
}
case eCSSKeyword_skewy:
{
double y = array->Item(1).GetFloatValue();
aFunctions.AppendElement(SkewY(y));
break;
}
case eCSSKeyword_matrix:
{
gfx3DMatrix matrix;
matrix._11 = array->Item(1).GetFloatValue();
matrix._12 = array->Item(2).GetFloatValue();
matrix._13 = 0;
matrix._14 = array->Item(3).GetFloatValue();
matrix._21 = array->Item(4).GetFloatValue();
matrix._22 = array->Item(5).GetFloatValue();
matrix._23 = 0;
matrix._24 = array->Item(6).GetFloatValue();
matrix._31 = 0;
matrix._32 = 0;
matrix._33 = 1;
matrix._34 = 0;
matrix._41 = 0;
matrix._42 = 0;
matrix._43 = 0;
matrix._44 = 1;
aFunctions.AppendElement(TransformMatrix(matrix));
break;
}
case eCSSKeyword_matrix3d:
{
gfx3DMatrix matrix;
matrix._11 = array->Item(1).GetFloatValue();
matrix._12 = array->Item(2).GetFloatValue();
matrix._13 = array->Item(3).GetFloatValue();
matrix._14 = array->Item(4).GetFloatValue();
matrix._21 = array->Item(5).GetFloatValue();
matrix._22 = array->Item(6).GetFloatValue();
matrix._23 = array->Item(7).GetFloatValue();
matrix._24 = array->Item(8).GetFloatValue();
matrix._31 = array->Item(9).GetFloatValue();
matrix._32 = array->Item(10).GetFloatValue();
matrix._33 = array->Item(11).GetFloatValue();
matrix._34 = array->Item(12).GetFloatValue();
matrix._41 = array->Item(13).GetFloatValue();
matrix._42 = array->Item(14).GetFloatValue();
matrix._43 = array->Item(15).GetFloatValue();
matrix._44 = array->Item(16).GetFloatValue();
aFunctions.AppendElement(TransformMatrix(matrix));
break;
}
case eCSSKeyword_perspective:
{
aFunctions.AppendElement(Perspective(array->Item(1).GetFloatValue()));
break;
}
default:
NS_ERROR("Function not handled yet!");
}
}
}
static TimingFunction
ToTimingFunction(css::ComputedTimingFunction& aCTF)
{
if (aCTF.GetType() == nsTimingFunction::Function) {
const nsSMILKeySpline* spline = aCTF.GetFunction();
return TimingFunction(CubicBezierFunction(spline->X1(), spline->Y1(),
spline->X2(), spline->Y2()));
}
PRUint32 type = aCTF.GetType() == nsTimingFunction::StepStart ? 1 : 2;
return TimingFunction(StepFunction(aCTF.GetSteps(), type));
}
static void
AddTransformAnimations(ElementAnimations* ea, Layer* aLayer,
const nsPoint& aOrigin)
{
if (!ea)
return;
NS_ASSERTION(aLayer->AsContainerLayer(), "Should only animate ContainerLayer");
nsIFrame* frame = ea->mElement->GetPrimaryFrame();
nsRect bounds = nsDisplayTransform::GetFrameBoundsForTransform(frame);
float scale = nsDeviceContext::AppUnitsPerCSSPixel();
gfxPoint3D offsetToTransformOrigin =
nsDisplayTransform::GetDeltaToMozTransformOrigin(frame, scale, &bounds);
gfxPoint3D offsetToPerspectiveOrigin =
nsDisplayTransform::GetDeltaToMozPerspectiveOrigin(frame, scale);
nscoord perspective = 0.0;
nsStyleContext* parentStyleContext = frame->GetStyleContext()->GetParent();
if (parentStyleContext) {
const nsStyleDisplay* disp = parentStyleContext->GetStyleDisplay();
if (disp && disp->mChildPerspective.GetUnit() == eStyleUnit_Coord) {
perspective = disp->mChildPerspective.GetCoordValue();
}
}
for (PRUint32 animIdx = 0; animIdx < ea->mAnimations.Length(); animIdx++) {
ElementAnimation* anim = &ea->mAnimations[animIdx];
if (!anim->CanPerformOnCompositor(ea->mElement, TimeStamp::Now())) {
continue;
}
float iterations = anim->mIterationCount != NS_IEEEPositiveInfinity()
? anim->mIterationCount : -1;
for (PRUint32 propIdx = 0; propIdx < anim->mProperties.Length(); propIdx++) {
AnimationProperty* property = &anim->mProperties[propIdx];
InfallibleTArray<AnimationSegment> segments;
if (property->mProperty != eCSSProperty_transform) {
continue;
}
for (PRUint32 segIdx = 0; segIdx < property->mSegments.Length(); segIdx++) {
AnimationPropertySegment* segment = &property->mSegments[segIdx];
nsCSSValueList* list = segment->mFromValue.GetCSSValueListValue();
InfallibleTArray<TransformFunction> fromFunctions;
AddTransformFunctions(list, frame->GetStyleContext(),
frame->PresContext(), bounds,
scale, fromFunctions);
list = segment->mToValue.GetCSSValueListValue();
InfallibleTArray<TransformFunction> toFunctions;
AddTransformFunctions(list, frame->GetStyleContext(),
frame->PresContext(), bounds,
scale, toFunctions);
segments.AppendElement(AnimationSegment(fromFunctions, toFunctions,
segment->mFromKey, segment->mToKey,
ToTimingFunction(segment->mTimingFunction)));
}
if (segments.Length() == 0) {
continue;
}
aLayer->AddAnimation(Animation(anim->mStartTime,
anim->mIterationDuration,
segments,
iterations,
anim->mDirection,
TransformData(aOrigin, offsetToTransformOrigin,
offsetToPerspectiveOrigin,
bounds, perspective)));
}
}
}
static void
AddOpacityAnimations(ElementAnimations* ea, Layer* aLayer)
{
if (!ea)
return;
NS_ASSERTION(aLayer->AsContainerLayer(), "Should only animate ContainerLayer");
for (PRUint32 animIdx = 0; animIdx < ea->mAnimations.Length(); animIdx++) {
ElementAnimation* anim = &ea->mAnimations[animIdx];
float iterations = anim->mIterationCount != NS_IEEEPositiveInfinity()
? anim->mIterationCount : -1;
if (!anim->CanPerformOnCompositor(ea->mElement, TimeStamp::Now())) {
continue;
}
for (PRUint32 propIdx = 0; propIdx < anim->mProperties.Length(); propIdx++) {
AnimationProperty* property = &anim->mProperties[propIdx];
InfallibleTArray<AnimationSegment> segments;
if (property->mProperty != eCSSProperty_opacity) {
continue;
}
for (PRUint32 segIdx = 0; segIdx < property->mSegments.Length(); segIdx++) {
AnimationPropertySegment* segment = &property->mSegments[segIdx];
segments.AppendElement(AnimationSegment(Opacity(segment->mFromValue.GetFloatValue()),
Opacity(segment->mToValue.GetFloatValue()),
segment->mFromKey,
segment->mToKey,
ToTimingFunction(segment->mTimingFunction)));
}
aLayer->AddAnimation(Animation(anim->mStartTime,
anim->mIterationDuration,
segments,
iterations,
anim->mDirection,
null_t()));
}
}
}
nsDisplayListBuilder::nsDisplayListBuilder(nsIFrame* aReferenceFrame,
Mode aMode, bool aBuildCaret)
: mReferenceFrame(aReferenceFrame),
@ -199,10 +534,11 @@ static void RecordFrameMetrics(nsIFrame* aForFrame,
nsRect contentBounds = scrollableFrame->GetScrollRange();
contentBounds.width += scrollableFrame->GetScrollPortRect().width;
contentBounds.height += scrollableFrame->GetScrollPortRect().height;
metrics.mCSSContentRect = gfx::Rect(nsPresContext::AppUnitsToFloatCSSPixels(contentBounds.x),
nsPresContext::AppUnitsToFloatCSSPixels(contentBounds.y),
nsPresContext::AppUnitsToFloatCSSPixels(contentBounds.width),
nsPresContext::AppUnitsToFloatCSSPixels(contentBounds.height));
metrics.mCSSContentRect =
mozilla::gfx::Rect(nsPresContext::AppUnitsToFloatCSSPixels(contentBounds.x),
nsPresContext::AppUnitsToFloatCSSPixels(contentBounds.y),
nsPresContext::AppUnitsToFloatCSSPixels(contentBounds.width),
nsPresContext::AppUnitsToFloatCSSPixels(contentBounds.height));
metrics.mContentRect = contentBounds.ScaleToNearestPixels(
aContainerParameters.mXScale, aContainerParameters.mYScale, auPerDevPixel);
metrics.mViewportScrollOffset = scrollableFrame->GetScrollPosition().ScaleToNearestPixels(
@ -210,10 +546,11 @@ static void RecordFrameMetrics(nsIFrame* aForFrame,
}
else {
nsRect contentBounds = aForFrame->GetRect();
metrics.mCSSContentRect = gfx::Rect(nsPresContext::AppUnitsToFloatCSSPixels(contentBounds.x),
nsPresContext::AppUnitsToFloatCSSPixels(contentBounds.y),
nsPresContext::AppUnitsToFloatCSSPixels(contentBounds.width),
nsPresContext::AppUnitsToFloatCSSPixels(contentBounds.height));
metrics.mCSSContentRect =
mozilla::gfx::Rect(nsPresContext::AppUnitsToFloatCSSPixels(contentBounds.x),
nsPresContext::AppUnitsToFloatCSSPixels(contentBounds.y),
nsPresContext::AppUnitsToFloatCSSPixels(contentBounds.width),
nsPresContext::AppUnitsToFloatCSSPixels(contentBounds.height));
metrics.mContentRect = contentBounds.ScaleToNearestPixels(
aContainerParameters.mXScale, aContainerParameters.mYScale, auPerDevPixel);
}
@ -300,7 +637,7 @@ nsDisplayListBuilder::EnterPresShell(nsIFrame* aReferenceFrame,
if (mIsPaintingToWindow) {
mReferenceFrame->AddPaintedPresShell(state->mPresShell);
state->mPresShell->IncrementPaintCount();
}
@ -363,7 +700,7 @@ nsDisplayListBuilder::MarkFramesForDisplayList(nsIFrame* aDirtyFrame,
}
void
nsDisplayListBuilder::MarkPreserve3DFramesForDisplayList(nsIFrame* aDirtyFrame, const nsRect& aDirtyRect)
nsDisplayListBuilder::MarkPreserve3DFramesForDisplayList(nsIFrame* aDirtyFrame, const nsRect& aDirtyRect)
{
nsAutoTArray<nsIFrame::ChildList,4> childListArray;
aDirtyFrame->GetChildLists(&childListArray);
@ -764,8 +1101,8 @@ void nsDisplayList::HitTest(nsDisplayListBuilder* aBuilder, const nsRect& aRect,
if (aRect.Intersects(item->GetBounds(aBuilder, &snap))) {
nsAutoTArray<nsIFrame*, 16> outFrames;
item->HitTest(aBuilder, aRect, aState, &outFrames);
// For 3d transforms with preserve-3d we add hit frames into the temp list
// For 3d transforms with preserve-3d we add hit frames into the temp list
// so we can sort them later, otherwise we add them directly to the output list.
nsTArray<nsIFrame*> *writeFrames = aOutFrames;
if (item->GetType() == nsDisplayItem::TYPE_TRANSFORM &&
@ -781,7 +1118,7 @@ void nsDisplayList::HitTest(nsDisplayListBuilder* aBuilder, const nsRect& aRect,
writeFrames = &temp[temp.Length() - 1].mFrames;
}
} else {
// We may have just finished a run of consecutive preserve-3d transforms,
// We may have just finished a run of consecutive preserve-3d transforms,
// so flush these into the destination array before processing our frame list.
FlushFramesArray(temp, aOutFrames);
}
@ -826,7 +1163,7 @@ static void Sort(nsDisplayList* aList, PRInt32 aCount, nsDisplayList::SortLEQ aC
aList->AppendToTop(&list2);
return;
}
Sort(&list1, half, aCmp, aClosure);
Sort(&list2, aCount - half, aCmp, aClosure);
@ -890,7 +1227,7 @@ void nsDisplayList::ExplodeAnonymousChildLists(nsDisplayListBuilder* aBuilder) {
i->~nsDisplayItem();
}
}
AppendToTop(&tmp);
}
@ -1977,14 +2314,21 @@ already_AddRefed<Layer>
nsDisplayOpacity::BuildLayer(nsDisplayListBuilder* aBuilder,
LayerManager* aManager,
const ContainerParameters& aContainerParameters) {
nsRefPtr<Layer> layer = GetLayerBuilderForManager(aManager)->
nsRefPtr<Layer> container = GetLayerBuilderForManager(aManager)->
BuildContainerLayerFor(aBuilder, aManager, mFrame, this, mList,
aContainerParameters, nullptr);
if (!layer)
if (!container)
return nullptr;
layer->SetOpacity(mFrame->GetStyleDisplay()->mOpacity);
return layer.forget();
container->SetOpacity(mFrame->GetStyleDisplay()->mOpacity);
container->ClearAnimations();
ElementAnimations* ea =
nsAnimationManager::GetAnimationsForCompositor(mFrame->GetContent(),
eCSSProperty_opacity);
AddOpacityAnimations(ea, container);
return container.forget();
}
/**
@ -2009,6 +2353,12 @@ nsDisplayOpacity::GetLayerState(nsDisplayListBuilder* aBuilder,
if (mFrame->AreLayersMarkedActive(nsChangeHint_UpdateOpacityLayer) &&
!IsItemTooSmallForActiveLayer(this))
return LAYER_ACTIVE;
if (mFrame->GetContent()) {
if (nsAnimationManager::GetAnimationsForCompositor(mFrame->GetContent(),
eCSSProperty_opacity)) {
return LAYER_ACTIVE;
}
}
nsIFrame* activeScrolledRoot =
nsLayoutUtils::GetActiveScrolledRootFor(mFrame, nullptr);
return !ChildrenCanBeInactive(aBuilder, aManager, aParameters, mList, activeScrolledRoot)
@ -2360,7 +2710,7 @@ nsDisplayScrollInfoLayer::ShouldFlattenAway(nsDisplayListBuilder* aBuilder)
// Layer metadata for a particular scroll frame needs to be unique. Only
// one nsDisplayScrollLayer (with rendered content) or one
// nsDisplayScrollInfoLayer (with only the metadata) should survive the
// visibility computation.
// visibility computation.
return RemoveScrollLayerCount() == 1;
}
@ -2643,7 +2993,7 @@ nsDisplayTransform::GetFrameBoundsForTransform(const nsIFrame* aFrame)
NS_PRECONDITION(aFrame, "Can't get the bounds of a nonexistent frame!");
nsRect result;
if (aFrame->GetStateBits() & NS_FRAME_SVG_LAYOUT) {
// TODO: SVG needs to define what percentage translations resolve against.
return result;
@ -2670,12 +3020,13 @@ nsDisplayTransform::GetFrameBoundsForTransform(const nsIFrame* aFrame)
/* Returns the delta specified by the -moz-transform-origin property.
* This is a positive delta, meaning that it indicates the direction to move
* to get from (0, 0) of the frame to the transform origin.
* to get from (0, 0) of the frame to the transform origin. This function is
* called off the main thread.
*/
static
gfxPoint3D GetDeltaToMozTransformOrigin(const nsIFrame* aFrame,
float aAppUnitsPerPixel,
const nsRect* aBoundsOverride)
/* static */ gfxPoint3D
nsDisplayTransform::GetDeltaToMozTransformOrigin(const nsIFrame* aFrame,
float aAppUnitsPerPixel,
const nsRect* aBoundsOverride)
{
NS_PRECONDITION(aFrame, "Can't get delta for a null frame!");
NS_PRECONDITION(aFrame->IsTransformed(),
@ -2690,8 +3041,7 @@ gfxPoint3D GetDeltaToMozTransformOrigin(const nsIFrame* aFrame,
nsDisplayTransform::GetFrameBoundsForTransform(aFrame));
/* Allows us to access named variables by index. */
gfxPoint3D result;
gfxFloat* coords[3] = {&result.x, &result.y, &result.z};
float coords[3];
const nscoord* dimensions[2] =
{&boundingRect.width, &boundingRect.height};
@ -2702,17 +3052,17 @@ gfxPoint3D GetDeltaToMozTransformOrigin(const nsIFrame* aFrame,
const nsStyleCoord &coord = display->mTransformOrigin[index];
if (coord.GetUnit() == eStyleUnit_Calc) {
const nsStyleCoord::Calc *calc = coord.GetCalcValue();
*coords[index] =
coords[index] =
NSAppUnitsToFloatPixels(*dimensions[index], aAppUnitsPerPixel) *
calc->mPercent +
NSAppUnitsToFloatPixels(calc->mLength, aAppUnitsPerPixel);
} else if (coord.GetUnit() == eStyleUnit_Percent) {
*coords[index] =
coords[index] =
NSAppUnitsToFloatPixels(*dimensions[index], aAppUnitsPerPixel) *
coord.GetPercentValue();
} else {
NS_ABORT_IF_FALSE(coord.GetUnit() == eStyleUnit_Coord, "unexpected unit");
*coords[index] =
coords[index] =
NSAppUnitsToFloatPixels(coord.GetCoordValue(), aAppUnitsPerPixel);
}
if ((aFrame->GetStateBits() & NS_FRAME_SVG_LAYOUT) &&
@ -2721,31 +3071,32 @@ gfxPoint3D GetDeltaToMozTransformOrigin(const nsIFrame* aFrame,
// user space, not the top left of its bounds, so we must adjust for that:
nscoord offset =
(index == 0) ? aFrame->GetPosition().x : aFrame->GetPosition().y;
*coords[index] -= NSAppUnitsToFloatPixels(offset, aAppUnitsPerPixel);
coords[index] -= NSAppUnitsToFloatPixels(offset, aAppUnitsPerPixel);
}
}
*coords[2] = NSAppUnitsToFloatPixels(display->mTransformOrigin[2].GetCoordValue(),
aAppUnitsPerPixel);
coords[2] = NSAppUnitsToFloatPixels(display->mTransformOrigin[2].GetCoordValue(),
aAppUnitsPerPixel);
/* Adjust based on the origin of the rectangle. */
result.x += NSAppUnitsToFloatPixels(boundingRect.x, aAppUnitsPerPixel);
result.y += NSAppUnitsToFloatPixels(boundingRect.y, aAppUnitsPerPixel);
coords[0] += NSAppUnitsToFloatPixels(boundingRect.x, aAppUnitsPerPixel);
coords[1] += NSAppUnitsToFloatPixels(boundingRect.y, aAppUnitsPerPixel);
return result;
return gfxPoint3D(coords[0], coords[1], coords[2]);
}
/* Returns the delta specified by the -moz-perspective-origin property.
* This is a positive delta, meaning that it indicates the direction to move
* to get from (0, 0) of the frame to the perspective origin.
* to get from (0, 0) of the frame to the perspective origin. This function is
* called off the main thread.
*/
static
gfxPoint3D GetDeltaToMozPerspectiveOrigin(const nsIFrame* aFrame,
float aAppUnitsPerPixel)
/* static */ gfxPoint3D
nsDisplayTransform::GetDeltaToMozPerspectiveOrigin(const nsIFrame* aFrame,
float aAppUnitsPerPixel)
{
NS_PRECONDITION(aFrame, "Can't get delta for a null frame!");
NS_PRECONDITION(aFrame->IsTransformed(),
"Shouldn't get a delta for an untransformed frame!");
NS_PRECONDITION(aFrame->GetParentStyleContextFrame(),
NS_PRECONDITION(aFrame->GetParentStyleContextFrame(),
"Can't get delta without a style parent!");
/* For both of the coordinates, if the value of -moz-perspective-origin is a
@ -2803,12 +3154,22 @@ gfxPoint3D GetDeltaToMozPerspectiveOrigin(const nsIFrame* aFrame,
*/
gfx3DMatrix
nsDisplayTransform::GetResultingTransformMatrix(const nsIFrame* aFrame,
const nsPoint &aOrigin,
const nsPoint& aOrigin,
float aAppUnitsPerPixel,
const nsRect* aBoundsOverride,
const nsCSSValueList* aTransformOverride,
gfxPoint3D* aToMozOrigin,
gfxPoint3D* aToPerspectiveOrigin,
nscoord* aChildPerspective,
nsIFrame** aOutAncestor)
{
NS_PRECONDITION(aFrame, "Cannot get transform matrix for a null frame!");
NS_PRECONDITION(aFrame || (aToMozOrigin && aBoundsOverride && aToPerspectiveOrigin &&
aTransformOverride && aChildPerspective),
"Should have frame or necessary infromation to construct matrix");
NS_PRECONDITION(!(aFrame && (aToMozOrigin || aToPerspectiveOrigin ||
aTransformOverride || aChildPerspective)),
"Should not have both frame and necessary infromation to construct matrix");
if (aOutAncestor) {
*aOutAncestor = nsLayoutUtils::GetCrossDocParentFrame(aFrame);
@ -2818,7 +3179,7 @@ nsDisplayTransform::GetResultingTransformMatrix(const nsIFrame* aFrame,
* coordinate space to the new origin.
*/
gfxPoint3D toMozOrigin =
GetDeltaToMozTransformOrigin(aFrame, aAppUnitsPerPixel, aBoundsOverride);
aFrame ? GetDeltaToMozTransformOrigin(aFrame, aAppUnitsPerPixel, aBoundsOverride) : *aToMozOrigin;
gfxPoint3D newOrigin =
gfxPoint3D(NSAppUnitsToFloatPixels(aOrigin.x, aAppUnitsPerPixel),
NSAppUnitsToFloatPixels(aOrigin.y, aAppUnitsPerPixel),
@ -2827,7 +3188,7 @@ nsDisplayTransform::GetResultingTransformMatrix(const nsIFrame* aFrame,
/* Get the underlying transform matrix. This requires us to get the
* bounds of the frame.
*/
const nsStyleDisplay* disp = aFrame->GetStyleDisplay();
const nsStyleDisplay* disp = aFrame ? aFrame->GetStyleDisplay() : nullptr;
nsRect bounds = (aBoundsOverride ? *aBoundsOverride :
nsDisplayTransform::GetFrameBoundsForTransform(aFrame));
@ -2838,9 +3199,12 @@ nsDisplayTransform::GetResultingTransformMatrix(const nsIFrame* aFrame,
// disp->mSpecifiedTransform, since we still need any transformFromSVGParent.
gfxMatrix svgTransform, transformFromSVGParent;
bool hasSVGTransforms =
aFrame->IsSVGTransformed(&svgTransform, &transformFromSVGParent);
aFrame && aFrame->IsSVGTransformed(&svgTransform, &transformFromSVGParent);
/* Transformed frames always have a transform, or are preserving 3d (and might still have perspective!) */
if (disp->mSpecifiedTransform) {
if (aTransformOverride) {
result = nsStyleTransformMatrix::ReadTransforms(aTransformOverride, nullptr, nullptr,
dummy, bounds, aAppUnitsPerPixel);
} else if (disp->mSpecifiedTransform) {
result = nsStyleTransformMatrix::ReadTransforms(disp->mSpecifiedTransform,
aFrame->GetStyleContext(),
aFrame->PresContext(),
@ -2852,10 +3216,6 @@ nsDisplayTransform::GetResultingTransformMatrix(const nsIFrame* aFrame,
svgTransform.x0 *= pixelsPerCSSPx;
svgTransform.y0 *= pixelsPerCSSPx;
result = gfx3DMatrix::From2D(svgTransform);
} else {
NS_ASSERTION(aFrame->GetStyleDisplay()->mTransformStyle == NS_STYLE_TRANSFORM_STYLE_PRESERVE_3D ||
aFrame->GetStyleDisplay()->mBackfaceVisibility == NS_STYLE_BACKFACE_VISIBILITY_HIDDEN,
"If we don't have a transform, then we must have another reason to have an nsDisplayTransform created");
}
if (hasSVGTransforms && !transformFromSVGParent.IsIdentity()) {
@ -2868,13 +3228,19 @@ nsDisplayTransform::GetResultingTransformMatrix(const nsIFrame* aFrame,
}
const nsStyleDisplay* parentDisp = nullptr;
nsStyleContext* parentStyleContext = aFrame->GetStyleContext()->GetParent();
nsStyleContext* parentStyleContext = aFrame ? aFrame->GetStyleContext()->GetParent(): nullptr;
if (parentStyleContext) {
parentDisp = parentStyleContext->GetStyleDisplay();
}
if (nsLayoutUtils::Are3DTransformsEnabled() &&
parentDisp && parentDisp->mChildPerspective.GetUnit() == eStyleUnit_Coord &&
parentDisp->mChildPerspective.GetCoordValue() > 0.0) {
nscoord perspectiveCoord = 0;
if (parentDisp && parentDisp->mChildPerspective.GetUnit() == eStyleUnit_Coord) {
perspectiveCoord = parentDisp->mChildPerspective.GetCoordValue();
}
if (aChildPerspective) {
perspectiveCoord = *aChildPerspective;
}
if (nsLayoutUtils::Are3DTransformsEnabled() && perspectiveCoord > 0.0) {
gfx3DMatrix perspective;
perspective._34 =
-1.0 / NSAppUnitsToFloatPixels(parentDisp->mChildPerspective.GetCoordValue(),
@ -2882,18 +3248,21 @@ nsDisplayTransform::GetResultingTransformMatrix(const nsIFrame* aFrame,
/* At the point when perspective is applied, we have been translated to the transform origin.
* The translation to the perspective origin is the difference between these values.
*/
gfxPoint3D toPerspectiveOrigin = GetDeltaToMozPerspectiveOrigin(aFrame, aAppUnitsPerPixel);
gfxPoint3D toPerspectiveOrigin = aFrame ? GetDeltaToMozPerspectiveOrigin(aFrame, aAppUnitsPerPixel) : *aToPerspectiveOrigin;
result = result * nsLayoutUtils::ChangeMatrixBasis(toPerspectiveOrigin - toMozOrigin, perspective);
}
if (aFrame->Preserves3D() && nsLayoutUtils::Are3DTransformsEnabled()) {
if (aFrame && aFrame->Preserves3D() && nsLayoutUtils::Are3DTransformsEnabled()) {
// Include the transform set on our parent
NS_ASSERTION(aFrame->GetParent() &&
aFrame->GetParent()->IsTransformed() &&
aFrame->GetParent()->Preserves3DChildren(),
"Preserve3D mismatch!");
gfx3DMatrix parent = GetResultingTransformMatrix(aFrame->GetParent(), aOrigin - aFrame->GetPosition(),
aAppUnitsPerPixel, nullptr, aOutAncestor);
gfx3DMatrix parent =
GetResultingTransformMatrix(aFrame->GetParent(),
aOrigin - aFrame->GetPosition(),
aAppUnitsPerPixel, nullptr, nullptr, nullptr,
nullptr, nullptr, aOutAncestor);
return nsLayoutUtils::ChangeMatrixBasis(newOrigin + toMozOrigin, result) * parent;
}
@ -2924,7 +3293,7 @@ nsDisplayTransform::ShouldPrerenderTransformedContent(nsDisplayListBuilder* aBui
}
/* If the matrix is singular, or a hidden backface is shown, the frame won't be visible or hit. */
static bool IsFrameVisible(nsIFrame* aFrame, const gfx3DMatrix& aMatrix)
static bool IsFrameVisible(nsIFrame* aFrame, const gfx3DMatrix& aMatrix)
{
if (aMatrix.IsSingular()) {
return false;
@ -2942,8 +3311,7 @@ nsDisplayTransform::GetTransform(float aAppUnitsPerPixel)
if (mTransform.IsIdentity() || mCachedAppUnitsPerPixel != aAppUnitsPerPixel) {
mTransform =
GetResultingTransformMatrix(mFrame, ToReferenceFrame(),
aAppUnitsPerPixel,
nullptr);
aAppUnitsPerPixel);
mCachedAppUnitsPerPixel = aAppUnitsPerPixel;
}
return mTransform;
@ -2953,7 +3321,7 @@ already_AddRefed<Layer> nsDisplayTransform::BuildLayer(nsDisplayListBuilder *aBu
LayerManager *aManager,
const ContainerParameters& aContainerParameters)
{
const gfx3DMatrix& newTransformMatrix =
const gfx3DMatrix& newTransformMatrix =
GetTransform(mFrame->PresContext()->AppUnitsPerDevPixel());
if (!IsFrameVisible(mFrame, newTransformMatrix)) {
@ -2969,6 +3337,13 @@ already_AddRefed<Layer> nsDisplayTransform::BuildLayer(nsDisplayListBuilder *aBu
if (mFrame->Preserves3D() || mFrame->Preserves3DChildren()) {
container->SetContentFlags(container->GetContentFlags() | Layer::CONTENT_PRESERVE_3D);
}
container->ClearAnimations();
ElementAnimations* ea =
nsAnimationManager::GetAnimationsForCompositor(mFrame->GetContent(),
eCSSProperty_transform);
AddTransformAnimations(ea, container, ToReferenceFrame());
return container.forget();
}
@ -2983,12 +3358,18 @@ nsDisplayTransform::GetLayerState(nsDisplayListBuilder* aBuilder,
return LAYER_ACTIVE;
if (!GetTransform(mFrame->PresContext()->AppUnitsPerDevPixel()).Is2D() || mFrame->Preserves3D())
return LAYER_ACTIVE;
if (mFrame->GetContent()) {
if (nsAnimationManager::GetAnimationsForCompositor(mFrame->GetContent(),
eCSSProperty_transform)) {
return LAYER_ACTIVE;
}
}
nsIFrame* activeScrolledRoot =
nsLayoutUtils::GetActiveScrolledRootFor(mFrame, nullptr);
return !mStoredList.ChildrenCanBeInactive(aBuilder,
aManager,
return !mStoredList.ChildrenCanBeInactive(aBuilder,
aManager,
aParameters,
*mStoredList.GetList(),
*mStoredList.GetList(),
activeScrolledRoot)
? LAYER_ACTIVE : LAYER_INACTIVE;
}
@ -3007,9 +3388,9 @@ bool nsDisplayTransform::ComputeVisibility(nsDisplayListBuilder *aBuilder,
!UntransformRectMatrix(mVisibleRect,
GetTransform(factor),
factor,
&untransformedVisibleRect))
&untransformedVisibleRect))
{
untransformedVisibleRect = mFrame->GetVisualOverflowRectRelativeToSelf() +
untransformedVisibleRect = mFrame->GetVisualOverflowRectRelativeToSelf() +
aBuilder->ToReferenceFrame(mFrame);
}
nsRegion untransformedVisible = untransformedVisibleRect;
@ -3074,7 +3455,7 @@ void nsDisplayTransform::HitTest(nsDisplayListBuilder *aBuilder,
NSFloatPixelsToAppUnits(float(rect.Width()), factor),
NSFloatPixelsToAppUnits(float(rect.Height()), factor));
}
#ifdef DEBUG_HIT
printf("Frame: %p\n", dynamic_cast<void *>(mFrame));
@ -3100,8 +3481,8 @@ nsDisplayTransform::GetHitDepthAtPoint(const nsPoint& aPoint)
gfx3DMatrix matrix = GetTransform(factor);
NS_ASSERTION(IsFrameVisible(mFrame, matrix), "We can't have hit a frame that isn't visible!");
gfxPoint point =
gfxPoint point =
matrix.Inverse().ProjectPoint(gfxPoint(NSAppUnitsToFloatPixels(aPoint.x, factor),
NSAppUnitsToFloatPixels(aPoint.y, factor)));
@ -3150,7 +3531,7 @@ nsRegion nsDisplayTransform::GetOpaqueRegion(nsDisplayListBuilder *aBuilder,
if (!UntransformRectMatrix(mVisibleRect, GetTransform(factor), factor, &untransformedVisible)) {
return nsRegion();
}
const gfx3DMatrix& matrix = GetTransform(nsPresContext::AppUnitsPerCSSPixel());
nsRegion result;
@ -3297,7 +3678,7 @@ bool nsDisplayTransform::UntransformRect(const nsRect &aUntransformedBounds,
* empty rect.
*/
float factor = nsPresContext::AppUnitsPerCSSPixel();
gfx3DMatrix matrix = GetResultingTransformMatrix(aFrame, aOrigin, factor, nullptr);
gfx3DMatrix matrix = GetResultingTransformMatrix(aFrame, aOrigin, factor);
return UntransformRectMatrix(aUntransformedBounds, matrix, factor, aOutRect);
}

View File

@ -2353,6 +2353,13 @@ public:
float aAppUnitsPerPixel,
nsRect* aOutRect);
static gfxPoint3D GetDeltaToMozTransformOrigin(const nsIFrame* aFrame,
float aAppUnitsPerPixel,
const nsRect* aBoundsOverride);
static gfxPoint3D GetDeltaToMozPerspectiveOrigin(const nsIFrame* aFrame,
float aAppUnitsPerPixel);
/**
* Returns the bounds of a frame as defined for resolving percentage
* <translation-value>s in CSS transforms. If
@ -2386,6 +2393,10 @@ public:
const nsPoint& aOrigin,
float aAppUnitsPerPixel,
const nsRect* aBoundsOverride = nullptr,
const nsCSSValueList* aTransformOverride = nullptr,
gfxPoint3D* aToMozOrigin = nullptr,
gfxPoint3D* aToPerspectiveOrigin = nullptr,
nscoord* aChildPerspective = nullptr,
nsIFrame** aOutAncestor = nullptr);
/**
* Return true when we should try to prerender the entire contents of the

View File

@ -92,6 +92,7 @@
#include "CSSCalc.h"
#include "nsAbsoluteContainingBlock.h"
#include "nsFontInflationData.h"
#include "nsAnimationManager.h"
#include "mozilla/Preferences.h"
#include "mozilla/LookAndFeel.h"
@ -935,9 +936,18 @@ nsIFrame::GetPaddingRect() const
bool
nsIFrame::IsTransformed() const
{
return (mState & NS_FRAME_MAY_BE_TRANSFORMED) &&
return ((mState & NS_FRAME_MAY_BE_TRANSFORMED) &&
(GetStyleDisplay()->HasTransform() ||
IsSVGTransformed());
IsSVGTransformed() ||
(mContent &&
nsAnimationManager::GetAnimationsForCompositor(mContent, eCSSProperty_transform))));
}
bool
nsIFrame::HasOpacity() const
{
return GetStyleDisplay()->mOpacity < 1.0f || (mContent &&
nsAnimationManager::GetAnimationsForCompositor(mContent, eCSSProperty_opacity));
}
bool
@ -1927,7 +1937,7 @@ nsIFrame::BuildDisplayListForStackingContext(nsDisplayListBuilder* aBuilder,
/* Else, if the list is non-empty and there is CSS group opacity without SVG
* effects, wrap it up in an opacity item.
*/
else if (disp->mOpacity < 1.0f &&
else if (HasOpacity() &&
!nsSVGUtils::CanOptimizeOpacity(this) &&
!resultList.IsEmpty()) {
rv = resultList.AppendNewToTop(
@ -2081,7 +2091,7 @@ nsIFrame::BuildDisplayListForChild(nsDisplayListBuilder* aBuilder,
// Child is composited if it's transformed, partially transparent, or has
// SVG effects.
const nsStyleDisplay* disp = child->GetStyleDisplay();
bool isVisuallyAtomic = disp->mOpacity != 1.0f
bool isVisuallyAtomic = child->HasOpacity()
|| child->IsTransformed()
|| nsSVGIntegrationUtils::UsingEffectsForFrame(child);
@ -4745,12 +4755,12 @@ nsIFrame::GetTransformMatrix(nsIFrame* aStopAtAncestor,
* coordinates to our parent.
*/
NS_ASSERTION(nsLayoutUtils::GetCrossDocParentFrame(this),
"Cannot transform the viewport frame!");
"Cannot transform the viewport frame!");
PRInt32 scaleFactor = PresContext()->AppUnitsPerDevPixel();
gfx3DMatrix result =
nsDisplayTransform::GetResultingTransformMatrix(this, nsPoint(0, 0),
scaleFactor, nullptr, aOutAncestor);
nsDisplayTransform::GetResultingTransformMatrix(this, nsPoint(0, 0), scaleFactor, nullptr,
nullptr, nullptr, nullptr, nullptr, aOutAncestor);
// XXXjwatt: seems like this will double count offsets in the face of preserve-3d:
nsPoint delta = GetOffsetToCrossDoc(*aOutAncestor);
/* Combine the raw transform with a translation to our parent. */
@ -4760,9 +4770,9 @@ nsIFrame::GetTransformMatrix(nsIFrame* aStopAtAncestor,
0.0f);
return result;
}
*aOutAncestor = nsLayoutUtils::GetCrossDocParentFrame(this);
/* Otherwise, we're not transformed. In that case, we'll walk up the frame
* tree until we either hit the root frame or something that may be
* transformed. We'll then change coordinates into that frame, since we're

View File

@ -1227,6 +1227,8 @@ public:
* an SVG viewBox attribute).
*/
bool IsTransformed() const;
bool HasOpacity() const;
/**
* Returns true if this frame is an SVG frame that has SVG transforms applied

View File

@ -245,6 +245,7 @@ TransformShadowTree(nsDisplayListBuilder* aBuilder, nsFrameLoader* aFrameLoader,
ShadowLayer* shadow = aLayer->AsShadowLayer();
shadow->SetShadowClipRect(aLayer->GetClipRect());
shadow->SetShadowVisibleRegion(aLayer->GetVisibleRegion());
shadow->SetShadowOpacity(aLayer->GetOpacity());
const FrameMetrics* metrics = GetFrameMetrics(aLayer);

View File

@ -7,6 +7,8 @@
#include "nsRuleData.h"
#include "nsCSSValue.h"
#include "nsStyleContext.h"
#include "nsIFrame.h"
#include "nsAnimationManager.h"
namespace mozilla {
namespace css {
@ -39,7 +41,7 @@ CommonAnimationManager::AddElementData(CommonElementAnimationData* aData)
nsRefreshDriver *rd = mPresContext->RefreshDriver();
rd->AddRefreshObserver(this, Flush_Style);
}
PR_INSERT_BEFORE(aData, &mElementData);
}
@ -213,5 +215,26 @@ ComputedTimingFunction::GetValue(double aPortion) const
}
}
bool
CommonElementAnimationData::CanAnimatePropertyOnCompositor(const dom::Element *aElement,
nsCSSProperty aProperty)
{
nsIFrame* frame = aElement->GetPrimaryFrame();
if (aProperty == eCSSProperty_opacity) {
return nsAnimationManager::CanAnimateOpacity();
}
if (aProperty == eCSSProperty_transform && !(frame &&
frame->Preserves3D() &&
frame->Preserves3DChildren())) {
if (frame && frame->IsSVGTransformed()) {
return false;
}
return nsAnimationManager::CanAnimateTransform();
}
return false;
}
}
}

View File

@ -107,6 +107,12 @@ public:
typedef nsTimingFunction::Type Type;
void Init(const nsTimingFunction &aFunction);
double GetValue(double aPortion) const;
const nsSMILKeySpline* GetFunction() const {
NS_ASSERTION(mType == nsTimingFunction::Function, "Type mismatch");
return &mTimingFunction;
}
Type GetType() const { return mType; }
PRUint32 GetSteps() const { return mSteps; }
private:
Type mType;
nsSMILKeySpline mTimingFunction;
@ -142,6 +148,10 @@ struct CommonElementAnimationData : public PRCList
mElement->DeleteProperty(mElementProperty);
}
static bool
CanAnimatePropertyOnCompositor(const dom::Element *aElement,
nsCSSProperty aProperty);
dom::Element *mElement;
// the atom we use in mElement's prop table (must be a static atom,

View File

@ -22,6 +22,8 @@ LIBXUL_LIBRARY = 1
EXPORTS_NAMESPACES = mozilla/css
EXPORTS = \
AnimationCommon.h \
nsAnimationManager.h \
nsCSSAnonBoxList.h \
nsCSSAnonBoxes.h \
nsCSSFontDescList.h \
@ -55,6 +57,7 @@ EXPORTS = \
nsRuleNode.h \
nsRuleProcessorData.h \
nsRuleWalker.h \
nsStyleAnimation.h \
nsStyleContext.h \
nsStyleCoord.h \
nsStyleSet.h \
@ -124,7 +127,9 @@ FORCE_STATIC_LIB = 1
include $(topsrcdir)/config/rules.mk
LOCAL_INCLUDES = \
include $(topsrcdir)/ipc/chromium/chromium-config.mk
LOCAL_INCLUDES += \
-I$(srcdir)/../base \
-I$(srcdir)/../generic \
-I$(srcdir)/../xul/base/src \

View File

@ -11,6 +11,8 @@
#include "nsStyleAnimation.h"
#include "nsSMILKeySpline.h"
#include "nsEventDispatcher.h"
#include "nsDisplayList.h"
#include "nsCSSFrameConstructor.h"
using namespace mozilla;
@ -36,6 +38,114 @@ ElementAnimationsPropertyDtor(void *aObject,
delete ea;
}
double
ElementAnimations::GetPositionInIteration(TimeStamp aStartTime, TimeStamp aCurrentTime,
TimeDuration aDuration, double aIterationCount,
PRUint32 aDirection, bool aIsForElement,
ElementAnimation* aAnimation,
ElementAnimations* aEa,
EventArray* aEventsToDispatch)
{
// Set |currentIterationCount| to the (fractional) number of
// iterations we've completed up to the current position.
TimeDuration currentTimeDuration = aCurrentTime - aStartTime;
double currentIterationCount =
currentTimeDuration / aDuration;
bool dispatchStartOrIteration = false;
if (currentIterationCount >= aIterationCount) {
if (!aAnimation) {
// We are on the compositor, so send a signal that the animation is over.
// The main thread will fire the animationend event.
return -1;
}
// Dispatch 'animationend' when needed.
if (aIsForElement &&
aAnimation->mLastNotification !=
ElementAnimation::LAST_NOTIFICATION_END) {
aAnimation->mLastNotification = ElementAnimation::LAST_NOTIFICATION_END;
// XXXdz: if this animation was done on the compositor, we should
// invalidate the frame and update style once we start throttling style
// updates.
AnimationEventInfo ei(aEa->mElement, aAnimation->mName, NS_ANIMATION_END,
currentTimeDuration);
aEventsToDispatch->AppendElement(ei);
}
if (!aAnimation->FillsForwards()) {
// No animation data.
return -1;
}
currentIterationCount = double(aAnimation->mIterationCount);
} else {
if (aAnimation && !aAnimation->IsPaused()) {
aEa->mNeedsRefreshes = true;
}
if (currentIterationCount < 0.0) {
NS_ASSERTION(aAnimation, "Should not run animation that hasn't started yet on the compositor");
if (!aAnimation->FillsBackwards()) {
// No animation data.
return -1;
}
currentIterationCount = 0.0;
} else {
dispatchStartOrIteration = aAnimation && !aAnimation->IsPaused();
}
}
// Set |positionInIteration| to the position from 0% to 100% along
// the keyframes.
NS_ABORT_IF_FALSE(currentIterationCount >= 0.0, "must be positive");
PRUint32 whichIteration = int(currentIterationCount);
if (whichIteration == aIterationCount && whichIteration != 0) {
// When the animation's iteration count is an integer (as it
// normally is), we need to end at 100% of its last iteration
// rather than 0% of the next one (unless it's zero).
--whichIteration;
}
double positionInIteration =
currentIterationCount - double(whichIteration);
bool thisIterationReverse = false;
switch (aDirection) {
case NS_STYLE_ANIMATION_DIRECTION_NORMAL:
thisIterationReverse = false;
break;
case NS_STYLE_ANIMATION_DIRECTION_REVERSE:
thisIterationReverse = true;
break;
case NS_STYLE_ANIMATION_DIRECTION_ALTERNATE:
thisIterationReverse = (whichIteration & 1) == 1;
break;
case NS_STYLE_ANIMATION_DIRECTION_ALTERNATE_REVERSE:
thisIterationReverse = (whichIteration & 1) == 0;
break;
}
if (thisIterationReverse) {
positionInIteration = 1.0 - positionInIteration;
}
// Dispatch 'animationstart' or 'animationiteration' when needed.
if (aAnimation && aIsForElement && dispatchStartOrIteration &&
whichIteration != aAnimation->mLastNotification) {
// Notify 'animationstart' even if a negative delay puts us
// past the first iteration.
// Note that when somebody changes the animation-duration
// dynamically, this will fire an extra iteration event
// immediately in many cases. It's not clear to me if that's the
// right thing to do.
PRUint32 message =
aAnimation->mLastNotification == ElementAnimation::LAST_NOTIFICATION_NONE
? NS_ANIMATION_START : NS_ANIMATION_ITERATION;
// XXXdz: If this is a start, invalidate the frame here once we throttle animations.
aAnimation->mLastNotification = whichIteration;
AnimationEventInfo ei(aEa->mElement, aAnimation->mName, message,
currentTimeDuration);
aEventsToDispatch->AppendElement(ei);
}
return positionInIteration;
}
void
ElementAnimations::EnsureStyleRuleFor(TimeStamp aRefreshTime,
EventArray& aEventsToDispatch)
@ -68,98 +178,24 @@ ElementAnimations::EnsureStyleRuleFor(TimeStamp aRefreshTime,
continue;
}
TimeDuration currentTimeDuration;
TimeStamp currentTime;
if (anim.IsPaused()) {
// FIXME: avoid recalculating every time
currentTimeDuration = anim.mPauseStart - anim.mStartTime;
currentTime = anim.mPauseStart;
} else {
currentTimeDuration = aRefreshTime - anim.mStartTime;
currentTime = aRefreshTime;
}
// Set |currentIterationCount| to the (fractional) number of
// iterations we've completed up to the current position.
double currentIterationCount =
currentTimeDuration / anim.mIterationDuration;
bool dispatchStartOrIteration = false;
if (currentIterationCount >= double(anim.mIterationCount)) {
// Dispatch 'animationend' when needed.
if (IsForElement() &&
anim.mLastNotification !=
ElementAnimation::LAST_NOTIFICATION_END) {
anim.mLastNotification = ElementAnimation::LAST_NOTIFICATION_END;
AnimationEventInfo ei(mElement, anim.mName, NS_ANIMATION_END,
currentTimeDuration);
aEventsToDispatch.AppendElement(ei);
}
if (!anim.FillsForwards()) {
// No animation data.
continue;
}
currentIterationCount = double(anim.mIterationCount);
} else {
if (!anim.IsPaused()) {
mNeedsRefreshes = true;
}
if (currentIterationCount < 0.0) {
if (!anim.FillsBackwards()) {
// No animation data.
continue;
}
currentIterationCount = 0.0;
} else {
dispatchStartOrIteration = !anim.IsPaused();
}
}
// Set |positionInIteration| to the position from 0% to 100% along
// the keyframes.
NS_ABORT_IF_FALSE(currentIterationCount >= 0.0, "must be positive");
PRUint32 whichIteration = int(currentIterationCount);
if (whichIteration == anim.mIterationCount && whichIteration != 0) {
// When the animation's iteration count is an integer (as it
// normally is), we need to end at 100% of its last iteration
// rather than 0% of the next one (unless it's zero).
--whichIteration;
}
double positionInIteration =
currentIterationCount - double(whichIteration);
bool thisIterationReverse = false;
switch (anim.mDirection) {
case NS_STYLE_ANIMATION_DIRECTION_NORMAL:
thisIterationReverse = false;
break;
case NS_STYLE_ANIMATION_DIRECTION_REVERSE:
thisIterationReverse = true;
break;
case NS_STYLE_ANIMATION_DIRECTION_ALTERNATE:
thisIterationReverse = (whichIteration & 1) == 1;
break;
case NS_STYLE_ANIMATION_DIRECTION_ALTERNATE_REVERSE:
thisIterationReverse = (whichIteration & 1) == 0;
break;
}
if (thisIterationReverse) {
positionInIteration = 1.0 - positionInIteration;
}
GetPositionInIteration(anim.mStartTime, currentTime,
anim.mIterationDuration, anim.mIterationCount,
anim.mDirection, IsForElement(),
&anim, this, &aEventsToDispatch);
// Dispatch 'animationstart' or 'animationiteration' when needed.
if (IsForElement() && dispatchStartOrIteration &&
whichIteration != anim.mLastNotification) {
// Notify 'animationstart' even if a negative delay puts us
// past the first iteration.
// Note that when somebody changes the animation-duration
// dynamically, this will fire an extra iteration event
// immediately in many cases. It's not clear to me if that's the
// right thing to do.
PRUint32 message =
anim.mLastNotification == ElementAnimation::LAST_NOTIFICATION_NONE
? NS_ANIMATION_START : NS_ANIMATION_ITERATION;
anim.mLastNotification = whichIteration;
AnimationEventInfo ei(mElement, anim.mName, message,
currentTimeDuration);
aEventsToDispatch.AppendElement(ei);
}
// The position is -1 when we don't have fill data for the current time,
// so we shouldn't animate.
if (positionInIteration == -1)
continue;
NS_ABORT_IF_FALSE(0.0 <= positionInIteration &&
positionInIteration <= 1.0,
@ -226,6 +262,66 @@ ElementAnimations::EnsureStyleRuleFor(TimeStamp aRefreshTime,
}
}
static bool
CanPerformAnimationOnCompositor(const ElementAnimation* aAnim,
mozilla::dom::Element* aElement)
{
for (PRUint32 propIdx = 0, propEnd = aAnim->mProperties.Length();
propIdx != propEnd; ++propIdx) {
const AnimationProperty &prop = aAnim->mProperties[propIdx];
if (!mozilla::css::CommonElementAnimationData::
CanAnimatePropertyOnCompositor(aElement,
prop.mProperty)) {
return false;
}
}
return true;
}
bool
ElementAnimation::CanPerformOnCompositor(mozilla::dom::Element* aElement,
TimeStamp aTime) const
{
return CanPerformAnimationOnCompositor(this, aElement) &&
!IsPaused() && aTime > mStartTime &&
(aTime - mStartTime) / mIterationDuration < mIterationCount;
}
bool
ElementAnimations::HasAnimationOfProperty(nsCSSProperty aProperty) const
{
for (PRUint32 animIdx = mAnimations.Length(); animIdx-- != 0; ) {
const ElementAnimation &anim = mAnimations[animIdx];
for (PRUint32 propIdx = 0, propEnd = anim.mProperties.Length();
propIdx != propEnd; ++propIdx) {
const AnimationProperty &prop = anim.mProperties[propIdx];
if (aProperty == prop.mProperty) {
return true;
}
}
}
return false;
}
bool
ElementAnimations::CanPerformOnCompositorThread() const
{
if (mElementProperty != nsGkAtoms::animationsProperty)
return false;
for (PRUint32 animIdx = mAnimations.Length(); animIdx-- != 0; ) {
const ElementAnimation &anim = mAnimations[animIdx];
if (anim.mIterationDuration.ToMilliseconds() <= 0.0) {
// No animation data
continue;
}
if (!CanPerformAnimationOnCompositor(&anim, mElement))
return false;
}
return true;
}
ElementAnimations*
nsAnimationManager::GetElementAnimations(dom::Element *aElement,
nsCSSPseudoElements::Type aPseudoType,
@ -254,10 +350,6 @@ nsAnimationManager::GetElementAnimations(dom::Element *aElement,
if (!ea && aCreateIfNeeded) {
// FIXME: Consider arena-allocating?
ea = new ElementAnimations(aElement, propName, this);
if (!ea) {
NS_WARNING("out of memory");
return nullptr;
}
nsresult rv = aElement->SetProperty(propName, ea,
ElementAnimationsPropertyDtor, nullptr);
if (NS_FAILED(rv)) {
@ -265,6 +357,9 @@ nsAnimationManager::GetElementAnimations(dom::Element *aElement,
delete ea;
return nullptr;
}
if (propName == nsGkAtoms::animationsProperty) {
aElement->SetMayHaveAnimations();
}
AddElementData(ea);
}
@ -366,6 +461,7 @@ nsAnimationManager::CheckAnimationRule(nsStyleContext* aStyleContext,
TimeStamp refreshTime = mPresContext->RefreshDriver()->MostRecentRefresh();
if (ea) {
// XXXdz: Invalidate the frame since the animation changed.
// The cached style rule is invalid.
ea->mStyleRule = nullptr;
ea->mStyleRuleRefreshTime = TimeStamp();

View File

@ -11,6 +11,7 @@
#include "nsDataHashtable.h"
#include "nsGUIEvent.h"
#include "mozilla/TimeStamp.h"
#include "mozilla/Preferences.h"
#include "nsThreadUtils.h"
class nsCSSKeyframesRule;
@ -88,6 +89,9 @@ struct ElementAnimation
return mPlayState == NS_STYLE_ANIMATION_PLAY_STATE_PAUSED;
}
bool CanPerformOnCompositor(mozilla::dom::Element* aElement,
mozilla::TimeStamp aTime) const;
mozilla::TimeStamp mStartTime; // with delay taken into account
mozilla::TimeStamp mPauseStart;
mozilla::TimeDuration mIterationDuration;
@ -114,6 +118,26 @@ struct ElementAnimations : public mozilla::css::CommonElementAnimationData
ElementAnimations(mozilla::dom::Element *aElement, nsIAtom *aElementProperty,
nsAnimationManager *aAnimationManager);
// This function takes as input the start time, duration, and direction of an
// animation and returns the position in the current iteration. Note that
// this only works when we know that the animation is currently running.
// This way of calling the function can be used from the compositor. Note
// that if the animation has not started yet, has already ended, or is paused,
// it should not be run from the compositor. When this function is called
// from the main thread, we need the actual ElementAnimation* in order to
// get correct animation-fill behavior and to fire animation events.
// This function returns -1 for the position if the animation should not be
// run (because it is not currently active and has no fill behavior.)
static double GetPositionInIteration(TimeStamp aStartTime,
TimeStamp aCurrentTime,
TimeDuration aDuration,
double aIterationCount,
PRUint32 aDirection,
bool IsForElement = true,
ElementAnimation* aAnimation = nullptr,
ElementAnimations* aEa = nullptr,
EventArray* aEventsToDispatch = nullptr);
void EnsureStyleRuleFor(TimeStamp aRefreshTime,
EventArray &aEventsToDispatch);
@ -126,6 +150,9 @@ struct ElementAnimations : public mozilla::css::CommonElementAnimationData
aPresContext->PresShell()->RestyleForAnimation(mElement, styleHint);
}
// True if this animation can be performed on the compositor thread.
bool CanPerformOnCompositorThread() const;
bool HasAnimationOfProperty(nsCSSProperty aProperty) const;
// This style rule contains the style data for currently animating
// values. It only matches when styling with animation. When we
// style without animation, we need to not use it so that we can
@ -149,14 +176,39 @@ class nsAnimationManager : public mozilla::css::CommonAnimationManager
{
public:
nsAnimationManager(nsPresContext *aPresContext)
: mozilla::css::CommonAnimationManager(aPresContext),
mKeyframesListIsDirty(true)
: mozilla::css::CommonAnimationManager(aPresContext)
, mKeyframesListIsDirty(true)
{
mKeyframesRules.Init(16); // FIXME: make infallible!
}
static bool CanAnimateOpacity() {
static bool canAnimateOpacity =
mozilla::Preferences::GetBool("layers.offmainthreadcomposition.animate-opacity", false) &&
mozilla::Preferences::GetBool("layers.offmainthreadcomposition.enabled", false);
return canAnimateOpacity;
}
static bool CanAnimateTransform() {
static bool canAnimateTransform =
mozilla::Preferences::GetBool("layers.offmainthreadcomposition.animate-transform", false) &&
mozilla::Preferences::GetBool("layers.offmainthreadcomposition.enabled", false);
return canAnimateTransform;
}
static ElementAnimations* GetAnimationsForCompositor(nsIContent* aContent,
nsCSSProperty aProperty)
{
if (!aContent->MayHaveAnimations())
return nullptr;
ElementAnimations* animations = static_cast<ElementAnimations*>(
aContent->GetProperty(nsGkAtoms::animationsProperty));
if (!animations)
return nullptr;
bool propertyMatches = animations->HasAnimationOfProperty(aProperty);
return (propertyMatches && animations->CanPerformOnCompositorThread()) ?
animations : nullptr;
}
// nsIStyleRuleProcessor (parts)
virtual void RulesMatching(ElementRuleProcessorData* aData);

View File

@ -1123,9 +1123,9 @@ AddTransformScale(const nsCSSValue &aValue1, double aCoeff1,
aResult.SetFloatValue(result + 1.0f, eCSSUnit_Number);
}
static already_AddRefed<nsCSSValue::Array>
AppendTransformFunction(nsCSSKeyword aTransformFunction,
nsCSSValueList**& aListTail)
/* static */ already_AddRefed<nsCSSValue::Array>
nsStyleAnimation::AppendTransformFunction(nsCSSKeyword aTransformFunction,
nsCSSValueList**& aListTail)
{
nsRefPtr<nsCSSValue::Array> arr = AppendFunction(aTransformFunction);
nsCSSValueList *item = new nsCSSValueList;
@ -1338,7 +1338,7 @@ Decompose3DMatrix(const gfx3DMatrix &aMatrix, gfxPoint3D &aScale,
/* Normalize the matrix */
local.Normalize();
/**
/**
* perspective is used to solve for perspective, but it also provides
* an easy way to test for singularity of the upper 3x3 component.
*/
@ -1356,13 +1356,13 @@ Decompose3DMatrix(const gfx3DMatrix &aMatrix, gfxPoint3D &aScale,
/* aPerspective is the right hand side of the equation. */
aPerspective = local.TransposedVector(3);
/**
/**
* Solve the equation by inverting perspective and multiplying
* aPerspective by the inverse.
*/
perspective.Invert();
aPerspective = perspective.TransposeTransform4D(aPerspective);
/* Clear the perspective partition */
local.SetTransposedVector(3, empty);
} else {
@ -1380,11 +1380,11 @@ Decompose3DMatrix(const gfx3DMatrix &aMatrix, gfxPoint3D &aScale,
/* Compute X scale factor and normalize first row. */
aScale.x = local[0].Length();
local[0] /= aScale.x;
/* Compute XY shear factor and make 2nd local orthogonal to 1st. */
aShear[XYSHEAR] = local[0].DotProduct(local[1]);
local[1] -= local[0] * aShear[XYSHEAR];
/* Now, compute Y scale and normalize 2nd local. */
aScale.y = local[1].Length();
local[1] /= aScale.y;
@ -1461,11 +1461,11 @@ nsStyleAnimation::InterpolateTransformMatrix(const gfx3DMatrix &aMatrix1,
// Interpolate each of the pieces
gfx3DMatrix result;
gfxPointH3D perspective =
gfxPointH3D perspective =
InterpolateNumerically(perspective1, perspective2, aProgress);
result.SetTransposedVector(3, perspective);
gfxPoint3D translate =
gfxPoint3D translate =
InterpolateNumerically(translate1, translate2, aProgress);
result.Translate(translate);
@ -1494,7 +1494,7 @@ nsStyleAnimation::InterpolateTransformMatrix(const gfx3DMatrix &aMatrix1,
result.SkewXY(xyshear);
}
gfxPoint3D scale =
gfxPoint3D scale =
InterpolateNumerically(scale1, scale2, aProgress);
if (scale != gfxPoint3D(1.0, 1.0, 1.0)) {
result.Scale(scale.x, scale.y, scale.z);
@ -1511,8 +1511,8 @@ AddDifferentTransformLists(const nsCSSValueList* aList1, double aCoeff1,
nsCSSValueList **resultTail = getter_Transfers(result);
nsRefPtr<nsCSSValue::Array> arr;
arr = AppendTransformFunction(eCSSKeyword_interpolatematrix, resultTail);
arr = nsStyleAnimation::AppendTransformFunction(eCSSKeyword_interpolatematrix, resultTail);
// FIXME: We should change the other transform code to also only
// take a single progress value, as having values that don't
// sum to 1 doesn't make sense for these.
@ -1557,7 +1557,7 @@ AddTransformLists(const nsCSSValueList* aList1, double aCoeff1,
tfunc != eCSSKeyword_interpolatematrix &&
tfunc != eCSSKeyword_rotate3d &&
tfunc != eCSSKeyword_perspective) {
arr = AppendTransformFunction(tfunc, resultTail);
arr = nsStyleAnimation::AppendTransformFunction(tfunc, resultTail);
}
switch (tfunc) {

View File

@ -15,14 +15,10 @@
#include "nsCSSProperty.h"
#include "nsCoord.h"
#include "nsColor.h"
#include "nsCSSValue.h"
class nsPresContext;
class nsStyleContext;
class nsCSSValue;
struct nsCSSValueList;
struct nsCSSValuePair;
struct nsCSSValueTriplet;
struct nsCSSValuePairList;
struct nsCSSRect;
class gfx3DMatrix;
@ -132,7 +128,7 @@ public:
* (property ID + string). A style context is needed in case the
* specified value depends on inherited style or on the values of other
* properties.
*
*
* @param aProperty The property whose value we're computing.
* @param aTargetElement The content node to which our computed value is
* applicable.
@ -203,9 +199,13 @@ public:
* @param aProgress Interpolation value in the range [0.0, 1.0]
*/
static gfx3DMatrix InterpolateTransformMatrix(const gfx3DMatrix &aMatrix1,
const gfx3DMatrix &aMatrix2,
const gfx3DMatrix &aMatrix2,
double aProgress);
static already_AddRefed<nsCSSValue::Array>
AppendTransformFunction(nsCSSKeyword aTransformFunction,
nsCSSValueList**& aListTail);
/**
* The types and values for the values that we extract and animate.
*/

View File

@ -39,12 +39,13 @@ static double FlushToZero(double aVal)
return aVal;
}
static float
float
ProcessTranslatePart(const nsCSSValue& aValue,
nsStyleContext* aContext,
nsPresContext* aPresContext,
bool& aCanStoreInRuleTree,
nscoord aSize, float aAppUnitsPerMatrixUnit)
nscoord aSize,
float aAppUnitsPerMatrixUnit)
{
nscoord offset = 0;
float percent = 0.0f;

View File

@ -30,6 +30,13 @@ namespace nsStyleTransformMatrix {
*/
nsCSSKeyword TransformFunctionOf(const nsCSSValue::Array* aData);
float ProcessTranslatePart(const nsCSSValue& aValue,
nsStyleContext* aContext,
nsPresContext* aPresContext,
bool& aCanStoreInRuleTree,
nscoord aSize,
float aAppUnitsPerMatrixUnit);
/**
* Given an nsCSSValueList containing -moz-transform functions,
* returns a matrix containing the value of those functions.

View File

@ -3512,6 +3512,10 @@ pref("layers.acceleration.force-enabled", false);
pref("layers.acceleration.draw-fps", false);
// Whether to animate simple opacity and transforms on the compositor
pref("layers.offmainthreadcomposition.animate-opacity", false);
pref("layers.offmainthreadcomposition.animate-transform", false);
#ifdef MOZ_X11
#ifdef MOZ_WIDGET_GTK2
pref("gfx.xrender.enabled",true);