Fix SliverPadding dropping the chain on scrollOffsetCorrection propagation (#14789)

* Fix SliverPadding dropping the chain on scrollOffsetCorrection propagation

* review doc
diff --git a/packages/flutter/lib/src/rendering/sliver.dart b/packages/flutter/lib/src/rendering/sliver.dart
index 2806728..0d16be6 100644
--- a/packages/flutter/lib/src/rendering/sliver.dart
+++ b/packages/flutter/lib/src/rendering/sliver.dart
@@ -520,6 +520,10 @@
   /// If this is non-zero after [RenderSliver.performLayout] returns, the scroll
   /// offset will be adjusted by the parent and then the entire layout of the
   /// parent will be rerun.
+  ///
+  /// If the parent is also a [RenderSliver], it must propagate this value
+  /// in its own [RenderSliver.geometry] property until a viewport which adjusts
+  /// its offset based on this value.
   final double scrollOffsetCorrection;
 
   /// Asserts that this geometry is internally consistent.
diff --git a/packages/flutter/lib/src/rendering/sliver_padding.dart b/packages/flutter/lib/src/rendering/sliver_padding.dart
index 21f1ecd..00716b2 100644
--- a/packages/flutter/lib/src/rendering/sliver_padding.dart
+++ b/packages/flutter/lib/src/rendering/sliver_padding.dart
@@ -189,6 +189,12 @@
       parentUsesSize: true,
     );
     final SliverGeometry childLayoutGeometry = child.geometry;
+    if (childLayoutGeometry.scrollOffsetCorrection != null) {
+      geometry = new SliverGeometry(
+        scrollOffsetCorrection: childLayoutGeometry.scrollOffsetCorrection,
+      );
+      return;
+    }
     final double beforePaddingPaintExtent = calculatePaintOffset(
       constraints,
       from: 0.0,
diff --git a/packages/flutter/test/widgets/slivers_padding_test.dart b/packages/flutter/test/widgets/slivers_padding_test.dart
index 08c640b..e566999 100644
--- a/packages/flutter/test/widgets/slivers_padding_test.dart
+++ b/packages/flutter/test/widgets/slivers_padding_test.dart
@@ -357,4 +357,69 @@
     );
     expect(tester.renderObject<RenderSliverPadding>(find.byType(SliverPadding)).afterPadding, 1.0);
   });
+
+  testWidgets('SliverPadding propagates geometry offset corrections', (WidgetTester tester) async {
+    Widget listBuilder(IndexedWidgetBuilder sliverChildBuilder) {
+      return new Directionality(
+        textDirection: TextDirection.ltr,
+        child: new CustomScrollView(
+          slivers: <Widget>[
+            new SliverPadding(
+              padding: EdgeInsets.zero,
+              sliver: new SliverList(
+                delegate: new SliverChildBuilderDelegate(
+                  sliverChildBuilder,
+                  childCount: 10,
+                ),
+              ),
+            ),
+          ],
+        ),
+      );
+    }
+
+    await tester.pumpWidget(
+      listBuilder(
+        (BuildContext context, int index) {
+          return new Container(
+            height: 200.0,
+            child: new Center(
+              child: new Text(index.toString()),
+            ),
+          );
+        },
+      ),
+    );
+
+    await tester.drag(find.text('2'), const Offset(0.0, -300.0));
+    await tester.pump();
+
+    expect(
+      tester.getRect(find.widgetWithText(Container, '2')),
+      new Rect.fromLTRB(0.0, 100.0, 800.0, 300.0),
+    );
+
+    // Now item 0 is 400.0px and going back will underflow.
+    await tester.pumpWidget(
+      listBuilder(
+        (BuildContext context, int index) {
+          return new Container(
+            height: index == 0 ? 400.0 : 200.0,
+            child: new Center(
+              child: new Text(index.toString()),
+            ),
+          );
+        },
+      ),
+    );
+
+    await tester.drag(find.text('2'), const Offset(0.0, 300.0));
+    // On this one frame, the scroll correction must properly propagate.
+    await tester.pump();
+
+    expect(
+      tester.getRect(find.widgetWithText(Container, '0')),
+      new Rect.fromLTRB(0.0, -200.0, 800.0, 200.0),
+    );
+  });
 }