mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-25 05:41:12 +00:00
Bug 755084 Part 2: Perform CSS animations of transform and opacity on the compositor r=roc, dbaron
This commit is contained in:
parent
609441e255
commit
bf4f8d3c97
@ -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); }
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -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,
|
||||
|
@ -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 \
|
||||
|
@ -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();
|
||||
|
@ -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);
|
||||
|
@ -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) {
|
||||
|
@ -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.
|
||||
*/
|
||||
|
@ -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;
|
||||
|
@ -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.
|
||||
|
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user