Bug 1151359 (Part 3) - Treat nsImageFrames subject to scale animation as having an identity scale when predicting size. r=tn,birtles

This commit is contained in:
Seth Fowler 2015-07-19 19:30:40 -07:00
Родитель 310598d794
Коммит ec30688068
7 изменённых файлов: 156 добавлений и 35 удалений

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

@ -365,6 +365,76 @@ ActiveLayerTracker::IsOffsetOrMarginStyleAnimated(nsIFrame* aFrame)
return false;
}
// A helper function for IsScaleSubjectToAnimation which returns true if the
// given AnimationCollection contains a current effect that animates scale.
static bool
ContainsAnimatedScale(AnimationCollection* aCollection, nsIFrame* aFrame)
{
if (!aCollection) {
return false;
}
for (dom::Animation* anim : aCollection->mAnimations) {
if (!anim->HasCurrentEffect()) {
continue;
}
KeyframeEffectReadOnly* effect = anim->GetEffect();
for (const AnimationProperty& prop : effect->Properties()) {
if (prop.mProperty != eCSSProperty_transform) {
continue;
}
for (AnimationPropertySegment segment : prop.mSegments) {
gfxSize from = segment.mFromValue.GetScaleValue(aFrame);
if (from != gfxSize(1.0f, 1.0f)) {
return true;
}
gfxSize to = segment.mToValue.GetScaleValue(aFrame);
if (to != gfxSize(1.0f, 1.0f)) {
return true;
}
}
}
}
return false;
}
/* static */ bool
ActiveLayerTracker::IsScaleSubjectToAnimation(nsIFrame* aFrame)
{
// Check whether JavaScript is animating this frame's scale.
LayerActivity* layerActivity = GetLayerActivity(aFrame);
if (layerActivity && layerActivity->mScaleRestyleCount >= 2) {
return true;
}
nsIContent* content = aFrame->GetContent();
if (!content || !content->IsElement()) {
return false;
}
nsCSSPseudoElements::Type pseudoType =
aFrame->StyleContext()->GetPseudoType();
// Check if any transitions associated with this frame may animate its scale.
AnimationCollection* transitions =
aFrame->PresContext()->TransitionManager()->GetAnimations(
content->AsElement(), pseudoType, false /* don't create */);
if (ContainsAnimatedScale(transitions, aFrame)) {
return true;
}
// Check if any animations associated with this frame may animate its scale.
AnimationCollection* animations =
aFrame->PresContext()->AnimationManager()->GetAnimations(
content->AsElement(), pseudoType, false /* don't create */);
if (ContainsAnimatedScale(animations, aFrame)) {
return true;
}
return false;
}
/* static */ void
ActiveLayerTracker::NotifyContentChange(nsIFrame* aFrame)
{

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

@ -72,6 +72,14 @@ public:
* as being animated for constructing active layers.
*/
static bool IsOffsetOrMarginStyleAnimated(nsIFrame* aFrame);
/**
* Return true if aFrame either has an animated scale now, or is likely to
* have one in the future because it has a CSS animation or transition
* (which may not be playing right now) that affects its scale.
*/
static bool IsScaleSubjectToAnimation(nsIFrame* aFrame);
/**
* Transfer the LayerActivity property to the frame's content node when the
* frame is about to be destroyed so that layer activity can be tracked

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

@ -443,38 +443,6 @@ nsLayoutUtils::HasCurrentAnimationsForProperties(const nsIFrame* aFrame,
return false;
}
static gfxSize
GetScaleForValue(const StyleAnimationValue& aValue, const nsIFrame* aFrame)
{
if (!aFrame) {
NS_WARNING("No frame.");
return gfxSize();
}
if (aValue.GetUnit() != StyleAnimationValue::eUnit_Transform) {
NS_WARNING("Expected a transform.");
return gfxSize();
}
nsCSSValueSharedList* list = aValue.GetCSSValueSharedListValue();
MOZ_ASSERT(list->mHead);
RuleNodeCacheConditions dontCare;
TransformReferenceBox refBox(aFrame);
gfx3DMatrix transform = nsStyleTransformMatrix::ReadTransforms(
list->mHead,
aFrame->StyleContext(),
aFrame->PresContext(), dontCare, refBox,
aFrame->PresContext()->AppUnitsPerDevPixel());
gfxMatrix transform2d;
bool canDraw2D = transform.CanDraw2D(&transform2d);
if (!canDraw2D) {
return gfxSize();
}
return transform2d.ScaleFactors(true);
}
static float
GetSuitableScale(float aMaxScale, float aMinScale,
nscoord aVisibleDimension, nscoord aDisplayDimension)
@ -505,12 +473,12 @@ GetMinAndMaxScaleForAnimationProperty(const nsIFrame* aFrame,
if (prop.mProperty == eCSSProperty_transform) {
for (uint32_t segIdx = prop.mSegments.Length(); segIdx-- != 0; ) {
AnimationPropertySegment& segment = prop.mSegments[segIdx];
gfxSize from = GetScaleForValue(segment.mFromValue, aFrame);
gfxSize from = segment.mFromValue.GetScaleValue(aFrame);
aMaxScale.width = std::max<float>(aMaxScale.width, from.width);
aMaxScale.height = std::max<float>(aMaxScale.height, from.height);
aMinScale.width = std::min<float>(aMinScale.width, from.width);
aMinScale.height = std::min<float>(aMinScale.height, from.height);
gfxSize to = GetScaleForValue(segment.mToValue, aFrame);
gfxSize to = segment.mToValue.GetScaleValue(aFrame);
aMaxScale.width = std::max<float>(aMaxScale.width, to.width);
aMaxScale.height = std::max<float>(aMaxScale.height, to.height);
aMinScale.width = std::min<float>(aMinScale.width, to.width);
@ -2406,6 +2374,42 @@ nsLayoutUtils::GetTransformToAncestorScale(nsIFrame* aFrame)
return gfxSize(1, 1);
}
static Matrix4x4
GetTransformToAncestorExcludingAnimated(nsIFrame* aFrame,
const nsIFrame* aAncestor)
{
nsIFrame* parent;
Matrix4x4 ctm;
if (aFrame == aAncestor) {
return ctm;
}
if (ActiveLayerTracker::IsScaleSubjectToAnimation(aFrame)) {
return ctm;
}
ctm = aFrame->GetTransformMatrix(aAncestor, &parent);
while (parent && parent != aAncestor) {
if (ActiveLayerTracker::IsScaleSubjectToAnimation(parent)) {
return Matrix4x4();
}
if (!parent->Preserves3DChildren()) {
ctm.ProjectTo2D();
}
ctm = ctm * parent->GetTransformMatrix(aAncestor, &parent);
}
return ctm;
}
gfxSize
nsLayoutUtils::GetTransformToAncestorScaleExcludingAnimated(nsIFrame* aFrame)
{
Matrix4x4 transform = GetTransformToAncestorExcludingAnimated(aFrame,
nsLayoutUtils::GetDisplayRootFrame(aFrame));
Matrix transform2D;
if (transform.Is2D(&transform2D)) {
return ThebesMatrix(transform2D).ScaleFactors(true);
}
return gfxSize(1, 1);
}
nsIFrame*
nsLayoutUtils::FindNearestCommonAncestorFrame(nsIFrame* aFrame1, nsIFrame* aFrame2)

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

@ -808,6 +808,14 @@ public:
*/
static gfxSize GetTransformToAncestorScale(nsIFrame* aFrame);
/**
* Gets the scale factors of the transform for aFrame relative to the root
* frame if this transform is 2D, or the identity scale factors otherwise.
* If some frame on the path from aFrame to the display root frame may have an
* animated scale, returns the identity scale factors.
*/
static gfxSize GetTransformToAncestorScaleExcludingAnimated(nsIFrame* aFrame);
/**
* Find the nearest common ancestor frame for aFrame1 and aFrame2. The
* ancestor frame could be cross-doc.

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

@ -718,7 +718,7 @@ nsImageFrame::MaybeDecodeForPredictedSize()
nsIPresShell* presShell = PresContext()->GetPresShell();
LayoutDeviceToScreenScale2D resolutionToScreen(
presShell->GetCumulativeResolution()
* nsLayoutUtils::GetTransformToAncestorScale(this));
* nsLayoutUtils::GetTransformToAncestorScaleExcludingAnimated(this));
// ...and this frame's content box...
const nsPoint offset =

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

@ -25,6 +25,7 @@
#include "gfxMatrix.h"
#include "gfxQuaternion.h"
#include "nsIDocument.h"
#include "nsIFrame.h"
#include "gfx2DGlue.h"
using namespace mozilla;
@ -3526,6 +3527,32 @@ StyleAnimationValue::ExtractComputedValue(nsCSSProperty aProperty,
return false;
}
gfxSize
StyleAnimationValue::GetScaleValue(const nsIFrame* aForFrame) const
{
MOZ_ASSERT(aForFrame);
MOZ_ASSERT(GetUnit() == StyleAnimationValue::eUnit_Transform);
nsCSSValueSharedList* list = GetCSSValueSharedListValue();
MOZ_ASSERT(list->mHead);
RuleNodeCacheConditions dontCare;
nsStyleTransformMatrix::TransformReferenceBox refBox(aForFrame);
gfx3DMatrix transform = nsStyleTransformMatrix::ReadTransforms(
list->mHead,
aForFrame->StyleContext(),
aForFrame->PresContext(), dontCare, refBox,
aForFrame->PresContext()->AppUnitsPerDevPixel());
gfxMatrix transform2d;
bool canDraw2D = transform.CanDraw2D(&transform2d);
if (!canDraw2D) {
return gfxSize();
}
return transform2d.ScaleFactors(true);
}
StyleAnimationValue::StyleAnimationValue(int32_t aInt, Unit aUnit,
IntegerConstructorType)
{

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

@ -15,6 +15,7 @@
#include "nsColor.h"
#include "nsCSSValue.h"
class nsIFrame;
class nsStyleContext;
class gfx3DMatrix;
@ -317,6 +318,9 @@ public:
mValue.mString->ToString(len, aBuffer);
}
/// @return the scale for this value, calculated with reference to @aForFrame.
gfxSize GetScaleValue(const nsIFrame* aForFrame) const;
explicit StyleAnimationValue(Unit aUnit = eUnit_Null) : mUnit(aUnit) {
NS_ASSERTION(aUnit == eUnit_Null || aUnit == eUnit_Normal ||
aUnit == eUnit_Auto || aUnit == eUnit_None,