layout/style/AnimationCommon.cpp

Wed, 31 Dec 2014 07:16:47 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 07:16:47 +0100
branch
TOR_BUG_9701
changeset 3
141e0f1194b1
permissions
-rw-r--r--

Revert simplistic fix pending revisit of Mozilla integration attempt.

michael@0 1 /* vim: set shiftwidth=2 tabstop=8 autoindent cindent expandtab: */
michael@0 2 /* This Source Code Form is subject to the terms of the Mozilla Public
michael@0 3 * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 5
michael@0 6 #include "AnimationCommon.h"
michael@0 7 #include "nsTransitionManager.h"
michael@0 8 #include "nsAnimationManager.h"
michael@0 9
michael@0 10 #include "gfxPlatform.h"
michael@0 11 #include "nsRuleData.h"
michael@0 12 #include "nsCSSValue.h"
michael@0 13 #include "nsStyleContext.h"
michael@0 14 #include "nsIFrame.h"
michael@0 15 #include "nsLayoutUtils.h"
michael@0 16 #include "mozilla/LookAndFeel.h"
michael@0 17 #include "Layers.h"
michael@0 18 #include "FrameLayerBuilder.h"
michael@0 19 #include "nsDisplayList.h"
michael@0 20 #include "mozilla/MemoryReporting.h"
michael@0 21 #include "RestyleManager.h"
michael@0 22 #include "nsStyleSet.h"
michael@0 23 #include "nsStyleChangeList.h"
michael@0 24
michael@0 25
michael@0 26 using mozilla::layers::Layer;
michael@0 27
michael@0 28 namespace mozilla {
michael@0 29 namespace css {
michael@0 30
michael@0 31 /* static */ bool
michael@0 32 IsGeometricProperty(nsCSSProperty aProperty)
michael@0 33 {
michael@0 34 switch (aProperty) {
michael@0 35 case eCSSProperty_bottom:
michael@0 36 case eCSSProperty_height:
michael@0 37 case eCSSProperty_left:
michael@0 38 case eCSSProperty_right:
michael@0 39 case eCSSProperty_top:
michael@0 40 case eCSSProperty_width:
michael@0 41 return true;
michael@0 42 default:
michael@0 43 return false;
michael@0 44 }
michael@0 45 }
michael@0 46
michael@0 47 CommonAnimationManager::CommonAnimationManager(nsPresContext *aPresContext)
michael@0 48 : mPresContext(aPresContext)
michael@0 49 {
michael@0 50 PR_INIT_CLIST(&mElementData);
michael@0 51 }
michael@0 52
michael@0 53 CommonAnimationManager::~CommonAnimationManager()
michael@0 54 {
michael@0 55 NS_ABORT_IF_FALSE(!mPresContext, "Disconnect should have been called");
michael@0 56 }
michael@0 57
michael@0 58 void
michael@0 59 CommonAnimationManager::Disconnect()
michael@0 60 {
michael@0 61 // Content nodes might outlive the transition or animation manager.
michael@0 62 RemoveAllElementData();
michael@0 63
michael@0 64 mPresContext = nullptr;
michael@0 65 }
michael@0 66
michael@0 67 void
michael@0 68 CommonAnimationManager::RemoveAllElementData()
michael@0 69 {
michael@0 70 while (!PR_CLIST_IS_EMPTY(&mElementData)) {
michael@0 71 CommonElementAnimationData *head =
michael@0 72 static_cast<CommonElementAnimationData*>(PR_LIST_HEAD(&mElementData));
michael@0 73 head->Destroy();
michael@0 74 }
michael@0 75 }
michael@0 76
michael@0 77 /*
michael@0 78 * nsISupports implementation
michael@0 79 */
michael@0 80
michael@0 81 NS_IMPL_ISUPPORTS(CommonAnimationManager, nsIStyleRuleProcessor)
michael@0 82
michael@0 83 nsRestyleHint
michael@0 84 CommonAnimationManager::HasStateDependentStyle(StateRuleProcessorData* aData)
michael@0 85 {
michael@0 86 return nsRestyleHint(0);
michael@0 87 }
michael@0 88
michael@0 89 nsRestyleHint
michael@0 90 CommonAnimationManager::HasStateDependentStyle(PseudoElementStateRuleProcessorData* aData)
michael@0 91 {
michael@0 92 return nsRestyleHint(0);
michael@0 93 }
michael@0 94
michael@0 95 bool
michael@0 96 CommonAnimationManager::HasDocumentStateDependentStyle(StateRuleProcessorData* aData)
michael@0 97 {
michael@0 98 return false;
michael@0 99 }
michael@0 100
michael@0 101 nsRestyleHint
michael@0 102 CommonAnimationManager::HasAttributeDependentStyle(AttributeRuleProcessorData* aData)
michael@0 103 {
michael@0 104 return nsRestyleHint(0);
michael@0 105 }
michael@0 106
michael@0 107 /* virtual */ bool
michael@0 108 CommonAnimationManager::MediumFeaturesChanged(nsPresContext* aPresContext)
michael@0 109 {
michael@0 110 return false;
michael@0 111 }
michael@0 112
michael@0 113 /* virtual */ size_t
michael@0 114 CommonAnimationManager::SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) const
michael@0 115 {
michael@0 116 // Measurement of the following members may be added later if DMD finds it is
michael@0 117 // worthwhile:
michael@0 118 // - mElementData
michael@0 119 //
michael@0 120 // The following members are not measured
michael@0 121 // - mPresContext, because it's non-owning
michael@0 122
michael@0 123 return 0;
michael@0 124 }
michael@0 125
michael@0 126 /* virtual */ size_t
michael@0 127 CommonAnimationManager::SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const
michael@0 128 {
michael@0 129 return aMallocSizeOf(this) + SizeOfExcludingThis(aMallocSizeOf);
michael@0 130 }
michael@0 131
michael@0 132 /* static */ bool
michael@0 133 CommonAnimationManager::ExtractComputedValueForTransition(
michael@0 134 nsCSSProperty aProperty,
michael@0 135 nsStyleContext* aStyleContext,
michael@0 136 nsStyleAnimation::Value& aComputedValue)
michael@0 137 {
michael@0 138 bool result =
michael@0 139 nsStyleAnimation::ExtractComputedValue(aProperty, aStyleContext,
michael@0 140 aComputedValue);
michael@0 141 if (aProperty == eCSSProperty_visibility) {
michael@0 142 NS_ABORT_IF_FALSE(aComputedValue.GetUnit() ==
michael@0 143 nsStyleAnimation::eUnit_Enumerated,
michael@0 144 "unexpected unit");
michael@0 145 aComputedValue.SetIntValue(aComputedValue.GetIntValue(),
michael@0 146 nsStyleAnimation::eUnit_Visibility);
michael@0 147 }
michael@0 148 return result;
michael@0 149 }
michael@0 150
michael@0 151 already_AddRefed<nsStyleContext>
michael@0 152 CommonAnimationManager::ReparentContent(nsIContent* aContent,
michael@0 153 nsStyleContext* aParentStyle)
michael@0 154 {
michael@0 155 nsStyleSet* styleSet = mPresContext->PresShell()->StyleSet();
michael@0 156 nsIFrame* primaryFrame = nsLayoutUtils::GetStyleFrame(aContent);
michael@0 157 if (!primaryFrame) {
michael@0 158 return nullptr;
michael@0 159 }
michael@0 160
michael@0 161 dom::Element* element = aContent->IsElement()
michael@0 162 ? aContent->AsElement()
michael@0 163 : nullptr;
michael@0 164
michael@0 165 nsRefPtr<nsStyleContext> newStyle =
michael@0 166 styleSet->ReparentStyleContext(primaryFrame->StyleContext(),
michael@0 167 aParentStyle, element);
michael@0 168 primaryFrame->SetStyleContext(newStyle);
michael@0 169 ReparentBeforeAndAfter(element, primaryFrame, newStyle, styleSet);
michael@0 170
michael@0 171 return newStyle.forget();
michael@0 172 }
michael@0 173
michael@0 174 /* static */ void
michael@0 175 CommonAnimationManager::ReparentBeforeAndAfter(dom::Element* aElement,
michael@0 176 nsIFrame* aPrimaryFrame,
michael@0 177 nsStyleContext* aNewStyle,
michael@0 178 nsStyleSet* aStyleSet)
michael@0 179 {
michael@0 180 if (nsIFrame* before = nsLayoutUtils::GetBeforeFrame(aPrimaryFrame)) {
michael@0 181 nsRefPtr<nsStyleContext> beforeStyle =
michael@0 182 aStyleSet->ReparentStyleContext(before->StyleContext(),
michael@0 183 aNewStyle, aElement);
michael@0 184 before->SetStyleContext(beforeStyle);
michael@0 185 }
michael@0 186 if (nsIFrame* after = nsLayoutUtils::GetBeforeFrame(aPrimaryFrame)) {
michael@0 187 nsRefPtr<nsStyleContext> afterStyle =
michael@0 188 aStyleSet->ReparentStyleContext(after->StyleContext(),
michael@0 189 aNewStyle, aElement);
michael@0 190 after->SetStyleContext(afterStyle);
michael@0 191 }
michael@0 192 }
michael@0 193
michael@0 194 nsStyleContext*
michael@0 195 CommonAnimationManager::UpdateThrottledStyle(dom::Element* aElement,
michael@0 196 nsStyleContext* aParentStyle,
michael@0 197 nsStyleChangeList& aChangeList)
michael@0 198 {
michael@0 199 NS_ASSERTION(mPresContext->TransitionManager()->GetElementTransitions(
michael@0 200 aElement,
michael@0 201 nsCSSPseudoElements::ePseudo_NotPseudoElement,
michael@0 202 false) ||
michael@0 203 mPresContext->AnimationManager()->GetElementAnimations(
michael@0 204 aElement,
michael@0 205 nsCSSPseudoElements::ePseudo_NotPseudoElement,
michael@0 206 false), "element not animated");
michael@0 207
michael@0 208 nsIFrame* primaryFrame = nsLayoutUtils::GetStyleFrame(aElement);
michael@0 209 if (!primaryFrame) {
michael@0 210 return nullptr;
michael@0 211 }
michael@0 212
michael@0 213 nsStyleContext* oldStyle = primaryFrame->StyleContext();
michael@0 214 nsRuleNode* ruleNode = oldStyle->RuleNode();
michael@0 215 nsTArray<nsStyleSet::RuleAndLevel> rules;
michael@0 216 do {
michael@0 217 if (ruleNode->IsRoot()) {
michael@0 218 break;
michael@0 219 }
michael@0 220
michael@0 221 nsStyleSet::RuleAndLevel curRule;
michael@0 222 curRule.mLevel = ruleNode->GetLevel();
michael@0 223
michael@0 224 if (curRule.mLevel == nsStyleSet::eAnimationSheet) {
michael@0 225 ElementAnimations* ea =
michael@0 226 mPresContext->AnimationManager()->GetElementAnimations(
michael@0 227 aElement,
michael@0 228 oldStyle->GetPseudoType(),
michael@0 229 false);
michael@0 230 NS_ASSERTION(ea,
michael@0 231 "Rule has level eAnimationSheet without animation on manager");
michael@0 232
michael@0 233 mPresContext->AnimationManager()->EnsureStyleRuleFor(ea);
michael@0 234 curRule.mRule = ea->mStyleRule;
michael@0 235 } else if (curRule.mLevel == nsStyleSet::eTransitionSheet) {
michael@0 236 ElementTransitions *et =
michael@0 237 mPresContext->TransitionManager()->GetElementTransitions(
michael@0 238 aElement,
michael@0 239 oldStyle->GetPseudoType(),
michael@0 240 false);
michael@0 241 NS_ASSERTION(et,
michael@0 242 "Rule has level eTransitionSheet without transition on manager");
michael@0 243
michael@0 244 et->EnsureStyleRuleFor(mPresContext->RefreshDriver()->MostRecentRefresh());
michael@0 245 curRule.mRule = et->mStyleRule;
michael@0 246 } else {
michael@0 247 curRule.mRule = ruleNode->GetRule();
michael@0 248 }
michael@0 249
michael@0 250 if (curRule.mRule) {
michael@0 251 rules.AppendElement(curRule);
michael@0 252 }
michael@0 253 } while ((ruleNode = ruleNode->GetParent()));
michael@0 254
michael@0 255 nsRefPtr<nsStyleContext> newStyle = mPresContext->PresShell()->StyleSet()->
michael@0 256 ResolveStyleForRules(aParentStyle, oldStyle, rules);
michael@0 257
michael@0 258 // We absolutely must call CalcStyleDifference in order to ensure the
michael@0 259 // new context has all the structs cached that the old context had.
michael@0 260 // We also need it for processing of the changes.
michael@0 261 nsChangeHint styleChange =
michael@0 262 oldStyle->CalcStyleDifference(newStyle, nsChangeHint(0));
michael@0 263 aChangeList.AppendChange(primaryFrame, primaryFrame->GetContent(),
michael@0 264 styleChange);
michael@0 265
michael@0 266 primaryFrame->SetStyleContext(newStyle);
michael@0 267
michael@0 268 ReparentBeforeAndAfter(aElement, primaryFrame, newStyle,
michael@0 269 mPresContext->PresShell()->StyleSet());
michael@0 270
michael@0 271 return newStyle;
michael@0 272 }
michael@0 273
michael@0 274 NS_IMPL_ISUPPORTS(AnimValuesStyleRule, nsIStyleRule)
michael@0 275
michael@0 276 /* virtual */ void
michael@0 277 AnimValuesStyleRule::MapRuleInfoInto(nsRuleData* aRuleData)
michael@0 278 {
michael@0 279 nsStyleContext *contextParent = aRuleData->mStyleContext->GetParent();
michael@0 280 if (contextParent && contextParent->HasPseudoElementData()) {
michael@0 281 // Don't apply transitions or animations to things inside of
michael@0 282 // pseudo-elements.
michael@0 283 // FIXME (Bug 522599): Add tests for this.
michael@0 284 return;
michael@0 285 }
michael@0 286
michael@0 287 for (uint32_t i = 0, i_end = mPropertyValuePairs.Length(); i < i_end; ++i) {
michael@0 288 PropertyValuePair &cv = mPropertyValuePairs[i];
michael@0 289 if (aRuleData->mSIDs & nsCachedStyleData::GetBitForSID(
michael@0 290 nsCSSProps::kSIDTable[cv.mProperty]))
michael@0 291 {
michael@0 292 nsCSSValue *prop = aRuleData->ValueFor(cv.mProperty);
michael@0 293 if (prop->GetUnit() == eCSSUnit_Null) {
michael@0 294 #ifdef DEBUG
michael@0 295 bool ok =
michael@0 296 #endif
michael@0 297 nsStyleAnimation::UncomputeValue(cv.mProperty, cv.mValue, *prop);
michael@0 298 NS_ABORT_IF_FALSE(ok, "could not store computed value");
michael@0 299 }
michael@0 300 }
michael@0 301 }
michael@0 302 }
michael@0 303
michael@0 304 #ifdef DEBUG
michael@0 305 /* virtual */ void
michael@0 306 AnimValuesStyleRule::List(FILE* out, int32_t aIndent) const
michael@0 307 {
michael@0 308 for (int32_t index = aIndent; --index >= 0; ) fputs(" ", out);
michael@0 309 fputs("[anim values] { ", out);
michael@0 310 for (uint32_t i = 0, i_end = mPropertyValuePairs.Length(); i < i_end; ++i) {
michael@0 311 const PropertyValuePair &pair = mPropertyValuePairs[i];
michael@0 312 nsAutoString value;
michael@0 313 nsStyleAnimation::UncomputeValue(pair.mProperty, pair.mValue, value);
michael@0 314 fprintf(out, "%s: %s; ", nsCSSProps::GetStringValue(pair.mProperty).get(),
michael@0 315 NS_ConvertUTF16toUTF8(value).get());
michael@0 316 }
michael@0 317 fputs("}\n", out);
michael@0 318 }
michael@0 319 #endif
michael@0 320
michael@0 321 void
michael@0 322 ComputedTimingFunction::Init(const nsTimingFunction &aFunction)
michael@0 323 {
michael@0 324 mType = aFunction.mType;
michael@0 325 if (mType == nsTimingFunction::Function) {
michael@0 326 mTimingFunction.Init(aFunction.mFunc.mX1, aFunction.mFunc.mY1,
michael@0 327 aFunction.mFunc.mX2, aFunction.mFunc.mY2);
michael@0 328 } else {
michael@0 329 mSteps = aFunction.mSteps;
michael@0 330 }
michael@0 331 }
michael@0 332
michael@0 333 static inline double
michael@0 334 StepEnd(uint32_t aSteps, double aPortion)
michael@0 335 {
michael@0 336 NS_ABORT_IF_FALSE(0.0 <= aPortion && aPortion <= 1.0, "out of range");
michael@0 337 uint32_t step = uint32_t(aPortion * aSteps); // floor
michael@0 338 return double(step) / double(aSteps);
michael@0 339 }
michael@0 340
michael@0 341 double
michael@0 342 ComputedTimingFunction::GetValue(double aPortion) const
michael@0 343 {
michael@0 344 switch (mType) {
michael@0 345 case nsTimingFunction::Function:
michael@0 346 return mTimingFunction.GetSplineValue(aPortion);
michael@0 347 case nsTimingFunction::StepStart:
michael@0 348 // There are diagrams in the spec that seem to suggest this check
michael@0 349 // and the bounds point should not be symmetric with StepEnd, but
michael@0 350 // should actually step up at rather than immediately after the
michael@0 351 // fraction points. However, we rely on rounding negative values
michael@0 352 // up to zero, so we can't do that. And it's not clear the spec
michael@0 353 // really meant it.
michael@0 354 return 1.0 - StepEnd(mSteps, 1.0 - aPortion);
michael@0 355 default:
michael@0 356 NS_ABORT_IF_FALSE(false, "bad type");
michael@0 357 // fall through
michael@0 358 case nsTimingFunction::StepEnd:
michael@0 359 return StepEnd(mSteps, aPortion);
michael@0 360 }
michael@0 361 }
michael@0 362
michael@0 363 } /* end sub-namespace css */
michael@0 364
michael@0 365 bool
michael@0 366 StyleAnimation::IsRunningAt(TimeStamp aTime) const
michael@0 367 {
michael@0 368 if (IsPaused() || mIterationDuration.ToMilliseconds() <= 0.0 ||
michael@0 369 mStartTime.IsNull()) {
michael@0 370 return false;
michael@0 371 }
michael@0 372
michael@0 373 double iterationsElapsed = ElapsedDurationAt(aTime) / mIterationDuration;
michael@0 374 return 0.0 <= iterationsElapsed && iterationsElapsed < mIterationCount;
michael@0 375 }
michael@0 376
michael@0 377 bool
michael@0 378 StyleAnimation::HasAnimationOfProperty(nsCSSProperty aProperty) const
michael@0 379 {
michael@0 380 for (uint32_t propIdx = 0, propEnd = mProperties.Length();
michael@0 381 propIdx != propEnd; ++propIdx) {
michael@0 382 if (aProperty == mProperties[propIdx].mProperty) {
michael@0 383 return true;
michael@0 384 }
michael@0 385 }
michael@0 386 return false;
michael@0 387 }
michael@0 388
michael@0 389 namespace css {
michael@0 390
michael@0 391 bool
michael@0 392 CommonElementAnimationData::CanAnimatePropertyOnCompositor(const dom::Element *aElement,
michael@0 393 nsCSSProperty aProperty,
michael@0 394 CanAnimateFlags aFlags)
michael@0 395 {
michael@0 396 bool shouldLog = nsLayoutUtils::IsAnimationLoggingEnabled();
michael@0 397 if (!gfxPlatform::OffMainThreadCompositingEnabled()) {
michael@0 398 if (shouldLog) {
michael@0 399 nsCString message;
michael@0 400 message.AppendLiteral("Performance warning: Compositor disabled");
michael@0 401 LogAsyncAnimationFailure(message);
michael@0 402 }
michael@0 403 return false;
michael@0 404 }
michael@0 405
michael@0 406 nsIFrame* frame = nsLayoutUtils::GetStyleFrame(aElement);
michael@0 407 if (IsGeometricProperty(aProperty)) {
michael@0 408 if (shouldLog) {
michael@0 409 nsCString message;
michael@0 410 message.AppendLiteral("Performance warning: Async animation of geometric property '");
michael@0 411 message.Append(nsCSSProps::GetStringValue(aProperty));
michael@0 412 message.AppendLiteral("' is disabled");
michael@0 413 LogAsyncAnimationFailure(message, aElement);
michael@0 414 }
michael@0 415 return false;
michael@0 416 }
michael@0 417 if (aProperty == eCSSProperty_transform) {
michael@0 418 if (frame->Preserves3D() &&
michael@0 419 frame->Preserves3DChildren()) {
michael@0 420 if (shouldLog) {
michael@0 421 nsCString message;
michael@0 422 message.AppendLiteral("Gecko bug: Async animation of 'preserve-3d' transforms is not supported. See bug 779598");
michael@0 423 LogAsyncAnimationFailure(message, aElement);
michael@0 424 }
michael@0 425 return false;
michael@0 426 }
michael@0 427 if (frame->IsSVGTransformed()) {
michael@0 428 if (shouldLog) {
michael@0 429 nsCString message;
michael@0 430 message.AppendLiteral("Gecko bug: Async 'transform' animations of frames with SVG transforms is not supported. See bug 779599");
michael@0 431 LogAsyncAnimationFailure(message, aElement);
michael@0 432 }
michael@0 433 return false;
michael@0 434 }
michael@0 435 if (aFlags & CanAnimate_HasGeometricProperty) {
michael@0 436 if (shouldLog) {
michael@0 437 nsCString message;
michael@0 438 message.AppendLiteral("Performance warning: Async animation of 'transform' not possible due to presence of geometric properties");
michael@0 439 LogAsyncAnimationFailure(message, aElement);
michael@0 440 }
michael@0 441 return false;
michael@0 442 }
michael@0 443 }
michael@0 444 bool enabled = nsLayoutUtils::AreAsyncAnimationsEnabled();
michael@0 445 if (!enabled && shouldLog) {
michael@0 446 nsCString message;
michael@0 447 message.AppendLiteral("Performance warning: Async animations are disabled");
michael@0 448 LogAsyncAnimationFailure(message);
michael@0 449 }
michael@0 450 bool propertyAllowed = (aProperty == eCSSProperty_transform) ||
michael@0 451 (aProperty == eCSSProperty_opacity) ||
michael@0 452 (aFlags & CanAnimate_AllowPartial);
michael@0 453 return enabled && propertyAllowed;
michael@0 454 }
michael@0 455
michael@0 456 /* static */ bool
michael@0 457 CommonElementAnimationData::IsCompositorAnimationDisabledForFrame(nsIFrame* aFrame)
michael@0 458 {
michael@0 459 void* prop = aFrame->Properties().Get(nsIFrame::RefusedAsyncAnimation());
michael@0 460 return bool(reinterpret_cast<intptr_t>(prop));
michael@0 461 }
michael@0 462
michael@0 463 /* static */ void
michael@0 464 CommonElementAnimationData::LogAsyncAnimationFailure(nsCString& aMessage,
michael@0 465 const nsIContent* aContent)
michael@0 466 {
michael@0 467 if (aContent) {
michael@0 468 aMessage.AppendLiteral(" [");
michael@0 469 aMessage.Append(nsAtomCString(aContent->Tag()));
michael@0 470
michael@0 471 nsIAtom* id = aContent->GetID();
michael@0 472 if (id) {
michael@0 473 aMessage.AppendLiteral(" with id '");
michael@0 474 aMessage.Append(nsAtomCString(aContent->GetID()));
michael@0 475 aMessage.AppendLiteral("'");
michael@0 476 }
michael@0 477 aMessage.AppendLiteral("]");
michael@0 478 }
michael@0 479 aMessage.AppendLiteral("\n");
michael@0 480 printf_stderr(aMessage.get());
michael@0 481 }
michael@0 482
michael@0 483 bool
michael@0 484 CommonElementAnimationData::CanThrottleTransformChanges(TimeStamp aTime)
michael@0 485 {
michael@0 486 if (!nsLayoutUtils::AreAsyncAnimationsEnabled()) {
michael@0 487 return false;
michael@0 488 }
michael@0 489
michael@0 490 // If we know that the animation cannot cause overflow,
michael@0 491 // we can just disable flushes for this animation.
michael@0 492
michael@0 493 // If we don't show scrollbars, we don't care about overflow.
michael@0 494 if (LookAndFeel::GetInt(LookAndFeel::eIntID_ShowHideScrollbars) == 0) {
michael@0 495 return true;
michael@0 496 }
michael@0 497
michael@0 498 // If this animation can cause overflow, we can throttle some of the ticks.
michael@0 499 if ((aTime - mStyleRuleRefreshTime) < TimeDuration::FromMilliseconds(200)) {
michael@0 500 return true;
michael@0 501 }
michael@0 502
michael@0 503 // If the nearest scrollable ancestor has overflow:hidden,
michael@0 504 // we don't care about overflow.
michael@0 505 nsIScrollableFrame* scrollable = nsLayoutUtils::GetNearestScrollableFrame(
michael@0 506 nsLayoutUtils::GetStyleFrame(mElement));
michael@0 507 if (!scrollable) {
michael@0 508 return true;
michael@0 509 }
michael@0 510
michael@0 511 ScrollbarStyles ss = scrollable->GetScrollbarStyles();
michael@0 512 if (ss.mVertical == NS_STYLE_OVERFLOW_HIDDEN &&
michael@0 513 ss.mHorizontal == NS_STYLE_OVERFLOW_HIDDEN &&
michael@0 514 scrollable->GetLogicalScrollPosition() == nsPoint(0, 0)) {
michael@0 515 return true;
michael@0 516 }
michael@0 517
michael@0 518 return false;
michael@0 519 }
michael@0 520
michael@0 521 bool
michael@0 522 CommonElementAnimationData::CanThrottleAnimation(TimeStamp aTime)
michael@0 523 {
michael@0 524 nsIFrame* frame = nsLayoutUtils::GetStyleFrame(mElement);
michael@0 525 if (!frame) {
michael@0 526 return false;
michael@0 527 }
michael@0 528
michael@0 529 bool hasTransform = HasAnimationOfProperty(eCSSProperty_transform);
michael@0 530 bool hasOpacity = HasAnimationOfProperty(eCSSProperty_opacity);
michael@0 531 if (hasOpacity) {
michael@0 532 Layer* layer = FrameLayerBuilder::GetDedicatedLayer(
michael@0 533 frame, nsDisplayItem::TYPE_OPACITY);
michael@0 534 if (!layer || mAnimationGeneration > layer->GetAnimationGeneration()) {
michael@0 535 return false;
michael@0 536 }
michael@0 537 }
michael@0 538
michael@0 539 if (!hasTransform) {
michael@0 540 return true;
michael@0 541 }
michael@0 542
michael@0 543 Layer* layer = FrameLayerBuilder::GetDedicatedLayer(
michael@0 544 frame, nsDisplayItem::TYPE_TRANSFORM);
michael@0 545 if (!layer || mAnimationGeneration > layer->GetAnimationGeneration()) {
michael@0 546 return false;
michael@0 547 }
michael@0 548
michael@0 549 return CanThrottleTransformChanges(aTime);
michael@0 550 }
michael@0 551
michael@0 552 void
michael@0 553 CommonElementAnimationData::UpdateAnimationGeneration(nsPresContext* aPresContext)
michael@0 554 {
michael@0 555 mAnimationGeneration =
michael@0 556 aPresContext->RestyleManager()->GetAnimationGeneration();
michael@0 557 }
michael@0 558
michael@0 559 }
michael@0 560 }

mercurial