Commit 4f873ff4 authored by robhogan@gmail.com's avatar robhogan@gmail.com

Adding or changing any of box-shadow, outline, or border-image-outset does not need a layout..

.. so just require a paint invalidation and ensure visual overflow gets recomputed.

There is an optimization that throttles paint invalidations on an element when
the children have just been laid out - now that we avoid this layout we want
to continue throttling these repaints. I will address this in a follow-up.

BUG=396825

Review URL: https://codereview.chromium.org/561303002

git-svn-id: svn://svn.chromium.org/blink/trunk@183698 bbb929c8-8fbe-4397-9dbb-9b2b20218538
parent 62f32d7f
...@@ -86,6 +86,10 @@ crbug.com/239811 crbug.com/229113 http/tests/history/redirect-js-location-assign ...@@ -86,6 +86,10 @@ crbug.com/239811 crbug.com/229113 http/tests/history/redirect-js-location-assign
crbug.com/231721 [ Win ] svg/custom/invisible-text-after-scrolling.xhtml [ Pass Timeout ] crbug.com/231721 [ Win ] svg/custom/invisible-text-after-scrolling.xhtml [ Pass Timeout ]
crbug.com/396825 svg/repaint/remove-outline-property-on-root.html [ NeedsRebaseline ]
crbug.com/396825 svg/repaint/add-outline-property-on-root.html [ NeedsRebaseline ]
crbug.com/396825 fast/repaint/outline-change-invalidation.html [ NeedsRebaseline ]
# Crashing after V8 roll to 3.28.43.1. # Crashing after V8 roll to 3.28.43.1.
crbug.com/398306 fast/events/before-unload-return-bad-value.html [ Crash Timeout Pass ] crbug.com/398306 fast/events/before-unload-return-bad-value.html [ Crash Timeout Pass ]
......
<!DOCTYPE html>
<style>
div {
border-width: 21px 30px 30px 21px;
width: 75px;
height: 75px;
display: inline-block;
border-image-source: url("../borders/resources/border-image.png");
border-image-slice: 21 30 30 21 fill;
border-image-width: 1;
border-image-outset: 1;
}
</style>
<script src="../../resources/js-test.js"></script>
<div id="test"></div>
<script>
// Force style recalc and layout.
document.body.offsetTop;
if (window.internals)
shouldBe("window.internals.needsLayoutCount()", "0", true);
// Changing border-image-outset will cause a repaint but no layout.
document.getElementById("test").style['border-image-outset'] = '5';
if (window.internals) {
shouldBe("window.internals.needsLayoutCount()", "0", true);
}
</script>
<!DOCTYPE html>
<script src="../../resources/js-test.js"></script>
<div id="test" style="background-color: green; width: 100px; height: 100px;"></div>
<script>
// Force style recalc and layout.
document.body.offsetTop;
if (window.internals)
shouldBe("window.internals.needsLayoutCount()", "0", true);
// Adding box-shadow will cause a repaint but no layout.
document.getElementById("test").style['outline'] = 'solid black 5px;';
if (window.internals) {
shouldBe("window.internals.needsLayoutCount()", "0", true);
}
</script>
<!DOCTYPE html>
<script src="../../resources/js-test.js"></script>
<div id="test" style="background-color: green; width: 100px; height: 100px;"></div>
<script>
// Force style recalc and layout.
document.body.offsetTop;
if (window.internals)
shouldBe("window.internals.needsLayoutCount()", "0", true);
// Adding box-shadow will cause a repaint but no layout.
document.getElementById("test").style['box-shadow'] = '5px 5px 5px rgba(0,0,0,0.3)';
if (window.internals) {
shouldBe("window.internals.needsLayoutCount()", "0", true);
}
</script>
{
"bounds": [800, 600],
"children": [
{
"bounds": [800, 600],
"contentsOpaque": true,
"drawsContent": true,
"repaintRects": [
[8, 8, 126, 126]
]
}
]
}
<!DOCTYPE HTML>
<style>
div {
border-width: 21px 30px 30px 21px;
width: 75px;
height: 75px;
display: inline-block;
border-image-source: url("../borders/resources/border-image.png");
border-image-slice: 21 30 30 21 fill;
border-image-width: 1;
}
</style>
<script src="resources/text-based-repaint.js"></script>
<script>
function repaintTest()
{
// Adding border-image-outset will cause a repaint but no layout.
document.getElementById("test").style['border-image-outset'] = '5';
}
window.onload = runRepaintTest;
</script>
<div id="test"></div>
<p>
Tests the repainting of border-image-outset when added.
</p>
{
"bounds": [800, 600],
"children": [
{
"bounds": [800, 600],
"contentsOpaque": true,
"drawsContent": true,
"repaintRects": [
[8, 8, 126, 126]
]
}
]
}
<!DOCTYPE HTML>
<style>
div {
border-width: 21px 30px 30px 21px;
width: 75px;
height: 75px;
display: inline-block;
border-image-source: url("../borders/resources/border-image.png");
border-image-slice: 21 30 30 21 fill;
border-image-width: 1;
border-image-outset: 1;
}
</style>
<script src="resources/text-based-repaint.js"></script>
<script>
function repaintTest()
{
// Changing border-image-outset will cause a repaint but no layout.
document.getElementById("test").style['border-image-outset'] = '5';
}
window.onload = runRepaintTest;
</script>
<div id="test"></div>
<p>
Tests the repainting of border-image-outset when changed.
</p>
{
"bounds": [800, 600],
"children": [
{
"bounds": [800, 600],
"contentsOpaque": true,
"drawsContent": true,
"repaintRects": [
[8, 8, 110, 110],
[8, 8, 100, 100]
]
}
]
}
<!DOCTYPE HTML>
<script src="resources/text-based-repaint.js"></script>
<script>
function repaintTest()
{
// Adding box-shadow will cause a repaint but no layout.
document.getElementById("test").style['box-shadow'] = '5px 5px 5px rgba(0,0,0,0.3)';
}
window.onload = runRepaintTest;
</script>
<div id="test" style="background-color: green; width: 100px; height: 100px;"></div>
<p>
Tests the repainting of box shadows when added.
</p>
{
"bounds": [800, 600],
"children": [
{
"bounds": [800, 600],
"contentsOpaque": true,
"drawsContent": true,
"repaintRects": [
[8, 8, 120, 120],
[8, 8, 110, 110]
]
}
]
}
<!DOCTYPE HTML>
<script src="resources/text-based-repaint.js"></script>
<script>
function repaintTest()
{
// Adding box-shadow will cause a repaint but no layout.
document.getElementById("test").style['box-shadow'] = '5px 5px 5px rgba(0,0,0,0.3)';
}
window.onload = runRepaintTest;
</script>
<div id="test" style="background-color: green; width: 100px; height: 100px; box-shadow: 10px 10px 10px rgba(0,0,0,0.3);"></div>
<p>
Tests the repainting of box shadows when changed.
</p>
{
"bounds": [800, 600],
"children": [
{
"bounds": [800, 600],
"contentsOpaque": true,
"drawsContent": true,
"repaintRects": [
[0, 0, 800, 100],
[0, 0, 800, 100],
[0, 0, 100, 100],
[-10, -10, 810, 120],
[-10, -10, 810, 120],
[-10, -10, 120, 120]
]
}
]
}
<!DOCTYPE HTML>
<script src="resources/text-based-repaint.js"></script>
<script>
function repaintTest()
{
// Adding outline will cause a repaint but no layout.
document.getElementById("test").style['outline'] = 'solid black 10px';
}
window.onload = runRepaintTest;
</script>
<style>
body {
margin: 0;
}
</style>
<div id="test" style="background-color: green; width: 100px; height: 100px;"></div>
<!-- Tests the repainting of outline when added. -->
{
"bounds": [800, 600],
"children": [
{
"bounds": [800, 600],
"contentsOpaque": true,
"drawsContent": true,
"repaintRects": [
[-5, -5, 805, 110],
[-5, -5, 805, 110],
[-5, -5, 110, 110],
[-10, -10, 810, 120],
[-10, -10, 810, 120],
[-10, -10, 120, 120]
]
}
]
}
<!DOCTYPE HTML>
<script src="resources/text-based-repaint.js"></script>
<script>
function repaintTest()
{
// Changing outline will cause a repaint but no layout.
document.getElementById("test").style['outline'] = 'solid black 10px';
}
window.onload = runRepaintTest;
</script>
<style>
body {
margin: 0;
}
</style>
<div id="test" style="background-color: green; width: 100px; height: 100px; outline: solid black 5px;"></div>
<!-- Tests the repainting of outline when changed. -->
...@@ -6,10 +6,12 @@ ...@@ -6,10 +6,12 @@
"contentsOpaque": true, "contentsOpaque": true,
"drawsContent": true, "drawsContent": true,
"repaintRects": [ "repaintRects": [
[792, 16, 5, 97],
[30, 88, 762, 20], [30, 88, 762, 20],
[30, 88, 762, 20], [30, 88, 762, 20],
[30, 83, 767, 30], [30, 83, 767, 30],
[30, 83, 767, 30], [30, 83, 767, 30],
[8, 108, 789, 5],
[8, 88, 784, 20], [8, 88, 784, 20],
[8, 83, 789, 30] [8, 83, 789, 30]
] ]
......
...@@ -6,13 +6,7 @@ ...@@ -6,13 +6,7 @@
"contentsOpaque": true, "contentsOpaque": true,
"drawsContent": true, "drawsContent": true,
"repaintRects": [ "repaintRects": [
[8, 8, 784, 105], [8, 8, 100, 100]
[8, 8, 100, 100],
[8, 8, 100, 100],
[0, 0, 800, 121],
[-2, -2, 802, 123],
[-2, -2, 794, 120],
[-2, -2, 120, 120]
] ]
} }
] ]
......
...@@ -6,12 +6,6 @@ ...@@ -6,12 +6,6 @@
"contentsOpaque": true, "contentsOpaque": true,
"drawsContent": true, "drawsContent": true,
"repaintRects": [ "repaintRects": [
[8, 8, 784, 105],
[8, 8, 100, 100],
[8, 8, 100, 100],
[0, 0, 800, 121],
[-2, -2, 802, 123],
[-2, -2, 794, 120],
[-2, -2, 120, 120] [-2, -2, 120, 120]
] ]
} }
......
...@@ -1699,6 +1699,9 @@ void RenderObject::setStyle(PassRefPtr<RenderStyle> style) ...@@ -1699,6 +1699,9 @@ void RenderObject::setStyle(PassRefPtr<RenderStyle> style)
container->setNeedsOverflowRecalcAfterStyleChange(); container->setNeedsOverflowRecalcAfterStyleChange();
} }
if (diff.visualOverflowChanged() && !needsLayout() && isRenderBlock())
setNeedsOverflowRecalcAfterStyleChange();
if (updatedDiff.needsPaintInvalidationLayer()) if (updatedDiff.needsPaintInvalidationLayer())
toRenderLayerModelObject(this)->layer()->setShouldDoFullPaintInvalidationIncludingNonCompositingDescendants(); toRenderLayerModelObject(this)->layer()->setShouldDoFullPaintInvalidationIncludingNonCompositingDescendants();
else if (diff.needsPaintInvalidationObject() || updatedDiff.needsPaintInvalidationObject()) else if (diff.needsPaintInvalidationObject() || updatedDiff.needsPaintInvalidationObject())
......
...@@ -107,6 +107,11 @@ public: ...@@ -107,6 +107,11 @@ public:
&& m_bottomRight == o.m_bottomRight; && m_bottomRight == o.m_bottomRight;
} }
bool visualOverflowEqual(const BorderData& o) const
{
return m_image.outset() == o.m_image.outset();
}
bool operator!=(const BorderData& o) const bool operator!=(const BorderData& o) const
{ {
return !(*this == o); return !(*this == o);
......
...@@ -469,10 +469,6 @@ bool RenderStyle::diffNeedsFullLayoutAndPaintInvalidation(const RenderStyle& oth ...@@ -469,10 +469,6 @@ bool RenderStyle::diffNeedsFullLayoutAndPaintInvalidation(const RenderStyle& oth
&& *rareNonInheritedData->m_flexibleBox.get() != *other.rareNonInheritedData->m_flexibleBox.get()) && *rareNonInheritedData->m_flexibleBox.get() != *other.rareNonInheritedData->m_flexibleBox.get())
return true; return true;
// FIXME: We should add an optimized form of layout that just recomputes visual overflow.
if (!rareNonInheritedData->shadowDataEquivalent(*other.rareNonInheritedData.get()))
return true;
if (!rareNonInheritedData->reflectionDataEquivalent(*other.rareNonInheritedData.get())) if (!rareNonInheritedData->reflectionDataEquivalent(*other.rareNonInheritedData.get()))
return true; return true;
...@@ -588,11 +584,6 @@ bool RenderStyle::diffNeedsFullLayoutAndPaintInvalidation(const RenderStyle& oth ...@@ -588,11 +584,6 @@ bool RenderStyle::diffNeedsFullLayoutAndPaintInvalidation(const RenderStyle& oth
if ((visibility() == COLLAPSE) != (other.visibility() == COLLAPSE)) if ((visibility() == COLLAPSE) != (other.visibility() == COLLAPSE))
return true; return true;
if (!m_background->outline().visuallyEqual(other.m_background->outline())) {
// FIXME: We only really need to recompute the overflow but we don't have an optimized layout for it.
return true;
}
// Movement of non-static-positioned object is special cased in RenderStyle::visualInvalidationDiff(). // Movement of non-static-positioned object is special cased in RenderStyle::visualInvalidationDiff().
return false; return false;
...@@ -656,6 +647,9 @@ bool RenderStyle::diffNeedsPaintInvalidationLayer(const RenderStyle& other) cons ...@@ -656,6 +647,9 @@ bool RenderStyle::diffNeedsPaintInvalidationLayer(const RenderStyle& other) cons
bool RenderStyle::diffNeedsPaintInvalidationObject(const RenderStyle& other) const bool RenderStyle::diffNeedsPaintInvalidationObject(const RenderStyle& other) const
{ {
if (!m_background->outline().visuallyEqual(other.m_background->outline()))
return true;
if (inherited_flags._visibility != other.inherited_flags._visibility if (inherited_flags._visibility != other.inherited_flags._visibility
|| inherited_flags.m_printColorAdjust != other.inherited_flags.m_printColorAdjust || inherited_flags.m_printColorAdjust != other.inherited_flags.m_printColorAdjust
|| inherited_flags._insideLink != other.inherited_flags._insideLink || inherited_flags._insideLink != other.inherited_flags._insideLink
...@@ -674,6 +668,7 @@ bool RenderStyle::diffNeedsPaintInvalidationObject(const RenderStyle& other) con ...@@ -674,6 +668,7 @@ bool RenderStyle::diffNeedsPaintInvalidationObject(const RenderStyle& other) con
if (rareNonInheritedData->userDrag != other.rareNonInheritedData->userDrag if (rareNonInheritedData->userDrag != other.rareNonInheritedData->userDrag
|| rareNonInheritedData->m_objectFit != other.rareNonInheritedData->m_objectFit || rareNonInheritedData->m_objectFit != other.rareNonInheritedData->m_objectFit
|| rareNonInheritedData->m_objectPosition != other.rareNonInheritedData->m_objectPosition || rareNonInheritedData->m_objectPosition != other.rareNonInheritedData->m_objectPosition
|| !rareNonInheritedData->shadowDataEquivalent(*other.rareNonInheritedData.get())
|| !dataEquivalent(rareNonInheritedData->m_shapeOutside, other.rareNonInheritedData->m_shapeOutside) || !dataEquivalent(rareNonInheritedData->m_shapeOutside, other.rareNonInheritedData->m_shapeOutside)
|| !dataEquivalent(rareNonInheritedData->m_clipPath, other.rareNonInheritedData->m_clipPath)) || !dataEquivalent(rareNonInheritedData->m_clipPath, other.rareNonInheritedData->m_clipPath))
return true; return true;
...@@ -697,8 +692,14 @@ void RenderStyle::updatePropertySpecificDifferences(const RenderStyle& other, St ...@@ -697,8 +692,14 @@ void RenderStyle::updatePropertySpecificDifferences(const RenderStyle& other, St
if (rareNonInheritedData->m_filter != other.rareNonInheritedData->m_filter) if (rareNonInheritedData->m_filter != other.rareNonInheritedData->m_filter)
diff.setFilterChanged(); diff.setFilterChanged();
if (!rareNonInheritedData->shadowDataEquivalent(*other.rareNonInheritedData.get()))
diff.setVisualOverflowChanged();
} }
if (!m_background->outline().visuallyEqual(other.m_background->outline()) || !surround->border.visualOverflowEqual(other.surround->border))
diff.setVisualOverflowChanged();
if (!diff.needsPaintInvalidation()) { if (!diff.needsPaintInvalidation()) {
if (inherited->color != other.inherited->color if (inherited->color != other.inherited->color
|| inherited_flags.m_textUnderline != other.inherited_flags.m_textUnderline || inherited_flags.m_textUnderline != other.inherited_flags.m_textUnderline
......
...@@ -18,6 +18,7 @@ public: ...@@ -18,6 +18,7 @@ public:
FilterChanged = 1 << 3, FilterChanged = 1 << 3,
// The object needs to issue paint invalidations if it contains text or properties dependent on color (e.g., border or outline). // The object needs to issue paint invalidations if it contains text or properties dependent on color (e.g., border or outline).
TextOrColorChanged = 1 << 4, TextOrColorChanged = 1 << 4,
VisualOverflowChanged = 1 << 5
}; };
StyleDifference() StyleDifference()
...@@ -77,6 +78,8 @@ public: ...@@ -77,6 +78,8 @@ public:
bool textOrColorChanged() const { return m_propertySpecificDifferences & TextOrColorChanged; } bool textOrColorChanged() const { return m_propertySpecificDifferences & TextOrColorChanged; }
void setTextOrColorChanged() { m_propertySpecificDifferences |= TextOrColorChanged; } void setTextOrColorChanged() { m_propertySpecificDifferences |= TextOrColorChanged; }
bool visualOverflowChanged() const { return m_propertySpecificDifferences & VisualOverflowChanged; }
void setVisualOverflowChanged() { m_propertySpecificDifferences |= VisualOverflowChanged; }
private: private:
enum PaintInvalidationType { enum PaintInvalidationType {
NoPaintInvalidation = 0, NoPaintInvalidation = 0,
...@@ -92,7 +95,7 @@ private: ...@@ -92,7 +95,7 @@ private:
}; };
unsigned m_layoutType : 2; unsigned m_layoutType : 2;
unsigned m_propertySpecificDifferences : 5; unsigned m_propertySpecificDifferences : 6;
}; };
} // namespace blink } // namespace blink
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment