Bug 1201327 - Don't repaint the whole frame subtree when background-position changes. r=dbaron

This commit is contained in:
Markus Stange 2015-11-02 17:36:35 +01:00
parent 37052ffe02
commit e4ffa9b774
5 changed files with 117 additions and 16 deletions

View File

@ -0,0 +1,31 @@
<!DOCTYPE html>
<html lang="en">
<meta charset="utf-8">
<title>Changes to background-position should not cause things to repaint that don't intersect the background image.</title>
<style>
body {
margin: 0;
}
#background {
height: 512px;
background-image: url(image_rgrg-256x256.png);
background-repeat: no-repeat;
background-position: 300px 100px;
}
#not-intersecting-background {
box-sizing: border-box;
width: 200px;
height: 200px;
margin: 50px;
border: 1px solid lime;
}
</style>
<div id="background">
<div id="not-intersecting-background"></div>
</div>

View File

@ -0,0 +1,41 @@
<!DOCTYPE html>
<html lang="en" class="reftest-wait">
<meta charset="utf-8">
<title>Changes to background-position should not cause things to repaint that don't intersect the background image.</title>
<style>
body {
margin: 0;
}
#background {
height: 512px;
background-image: url(image_rgrg-256x256.png);
background-repeat: no-repeat;
background-position: 300px 50px;
}
#not-intersecting-background {
box-sizing: border-box;
width: 200px;
height: 200px;
margin: 50px;
border: 1px solid lime;
}
</style>
<div id="background">
<div id="not-intersecting-background" class="reftest-no-paint"></div>
</div>
<script>
function doTest() {
document.querySelector("#background").style.backgroundPosition = "300px 100px";
document.documentElement.removeAttribute("class");
}
document.addEventListener("MozReftestInvalidate", doTest);
</script>

View File

@ -70,3 +70,4 @@ fuzzy-if(gtkWidget,2,4) fuzzy-if(asyncPan,2,3955) fuzzy-if(OSX,179,30) == image-
!= fractional-transform-1.html about:blank
!= fractional-transform-2.html about:blank
!= fractional-transform-3.html about:blank
== background-position-1.html background-position-1-ref.html

View File

@ -2251,27 +2251,32 @@ nsChangeHint nsStyleBackground::CalcDifference(const nsStyleBackground& aOther)
const nsStyleBackground* lessLayers =
mImageCount > aOther.mImageCount ? &aOther : this;
bool hasVisualDifference = false;
nsChangeHint hint = nsChangeHint(0);
NS_FOR_VISIBLE_BACKGROUND_LAYERS_BACK_TO_FRONT(i, moreLayers) {
if (i < lessLayers->mImageCount) {
if (moreLayers->mLayers[i] != lessLayers->mLayers[i]) {
if ((moreLayers->mLayers[i].mImage.GetType() == eStyleImageType_Element) ||
(lessLayers->mLayers[i].mImage.GetType() == eStyleImageType_Element))
return NS_CombineHint(nsChangeHint_UpdateEffects,
nsChangeHint_RepaintFrame);
hasVisualDifference = true;
nsChangeHint layerDifference = moreLayers->mLayers[i].CalcDifference(lessLayers->mLayers[i]);
hint |= layerDifference;
if (layerDifference &&
((moreLayers->mLayers[i].mImage.GetType() == eStyleImageType_Element) ||
(lessLayers->mLayers[i].mImage.GetType() == eStyleImageType_Element))) {
hint |= nsChangeHint_UpdateEffects | nsChangeHint_RepaintFrame;
}
} else {
if (moreLayers->mLayers[i].mImage.GetType() == eStyleImageType_Element)
return NS_CombineHint(nsChangeHint_UpdateEffects,
nsChangeHint_RepaintFrame);
hasVisualDifference = true;
hint |= nsChangeHint_RepaintFrame;
if (moreLayers->mLayers[i].mImage.GetType() == eStyleImageType_Element) {
hint |= nsChangeHint_UpdateEffects | nsChangeHint_RepaintFrame;
}
}
}
if (hasVisualDifference || mBackgroundColor != aOther.mBackgroundColor)
return nsChangeHint_RepaintFrame;
if (mBackgroundColor != aOther.mBackgroundColor) {
hint |= nsChangeHint_RepaintFrame;
}
if (hint) {
return hint;
}
if (mAttachmentCount != aOther.mAttachmentCount ||
mClipCount != aOther.mClipCount ||
@ -2482,6 +2487,25 @@ nsStyleBackground::Layer::operator==(const Layer& aOther) const
mImage == aOther.mImage;
}
nsChangeHint
nsStyleBackground::Layer::CalcDifference(const Layer& aOther) const
{
nsChangeHint hint = nsChangeHint(0);
if (mAttachment != aOther.mAttachment ||
mClip != aOther.mClip ||
mOrigin != aOther.mOrigin ||
mRepeat != aOther.mRepeat ||
mBlendMode != aOther.mBlendMode ||
mSize != aOther.mSize ||
mImage != aOther.mImage) {
hint |= nsChangeHint_RepaintFrame;
}
if (mPosition != aOther.mPosition) {
hint |= nsChangeHint_SchedulePaint;
}
return hint;
}
// --------------------
// nsStyleDisplay
//

View File

@ -396,9 +396,10 @@ struct nsStyleBackground {
nsChangeHint CalcDifference(const nsStyleBackground& aOther) const;
static nsChangeHint MaxDifference() {
return NS_CombineHint(nsChangeHint_UpdateEffects,
NS_CombineHint(nsChangeHint_RepaintFrame,
nsChangeHint_NeutralChange));
return nsChangeHint_UpdateEffects |
nsChangeHint_RepaintFrame |
nsChangeHint_SchedulePaint |
nsChangeHint_NeutralChange;
}
static nsChangeHint DifferenceAlwaysHandledForDescendants() {
// CalcDifference never returns the reflow hints that are sometimes
@ -552,6 +553,9 @@ struct nsStyleBackground {
// whose root <svg> node has a viewBox.
bool RenderingMightDependOnPositioningAreaSizeChange() const;
// Compute the change hint required by changes in just this layer.
nsChangeHint CalcDifference(const Layer& aOther) const;
// An equality operator that compares the images using URL-equality
// rather than pointer-equality.
bool operator==(const Layer& aOther) const;