зеркало из https://github.com/mozilla/gecko-dev.git
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:
Родитель
310598d794
Коммит
ec30688068
|
@ -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,
|
||||
|
|
Загрузка…
Ссылка в новой задаче