Add margins to tooltips (#36963)
* Add margin parameter to tooltips
* Improve tooltip tests to find the tooltip's `Container` instead of arbitrary number of parent calls
diff --git a/packages/flutter/lib/src/material/tooltip.dart b/packages/flutter/lib/src/material/tooltip.dart
index dfdd001..2d58c1b 100644
--- a/packages/flutter/lib/src/material/tooltip.dart
+++ b/packages/flutter/lib/src/material/tooltip.dart
@@ -51,6 +51,7 @@
     @required this.message,
     this.height,
     this.padding,
+    this.margin,
     this.verticalOffset,
     this.preferBelow,
     this.excludeFromSemantics,
@@ -75,6 +76,19 @@
   /// Defaults to 16.0 logical pixels in each direction.
   final EdgeInsetsGeometry padding;
 
+  /// The empty space that surrounds the tooltip.
+  ///
+  /// Defines the tooltip's outer [Container.margin]. By default, a
+  /// long tooltip will span the width of its window. If long enough,
+  /// a tooltip might also span the window's height. This property allows
+  /// one to define how much space the tooltip must be inset from the edges
+  /// of their display window.
+  ///
+  /// If this property is null, then [TooltipThemeData.margin] is used.
+  /// If [TooltipThemeData.margin] is also null, the default margin is
+  /// 0.0 logical pixels on all sides.
+  final EdgeInsetsGeometry margin;
+
   /// The vertical gap between the widget and the displayed tooltip.
   ///
   /// When [preferBelow] is set to true and tooltips have sufficient space to
@@ -145,6 +159,7 @@
     properties.add(StringProperty('message', message, showName: false));
     properties.add(DoubleProperty('height', height, defaultValue: null));
     properties.add(DiagnosticsProperty<EdgeInsetsGeometry>('padding', padding, defaultValue: null));
+    properties.add(DiagnosticsProperty<EdgeInsetsGeometry>('margin', margin, defaultValue: null));
     properties.add(DoubleProperty('vertical offset', verticalOffset, defaultValue: null));
     properties.add(FlagProperty('position', value: preferBelow, ifTrue: 'below', ifFalse: 'above', showName: true, defaultValue: null));
     properties.add(FlagProperty('semantics', value: excludeFromSemantics, ifTrue: 'excluded', showName: true, defaultValue: null));
@@ -158,6 +173,7 @@
   static const double _defaultVerticalOffset = 24.0;
   static const bool _defaultPreferBelow = true;
   static const EdgeInsetsGeometry _defaultPadding = EdgeInsets.symmetric(horizontal: 16.0);
+  static const EdgeInsetsGeometry _defaultMargin = EdgeInsets.all(0.0);
   static const Duration _fadeInDuration = Duration(milliseconds: 150);
   static const Duration _fadeOutDuration = Duration(milliseconds: 75);
   static const Duration _defaultShowDuration = Duration(milliseconds: 1500);
@@ -166,6 +182,7 @@
 
   double height;
   EdgeInsetsGeometry padding;
+  EdgeInsetsGeometry margin;
   Decoration decoration;
   TextStyle textStyle;
   double verticalOffset;
@@ -273,6 +290,7 @@
       message: widget.message,
       height: height,
       padding: padding,
+      margin: margin,
       decoration: decoration,
       textStyle: textStyle,
       animation: CurvedAnimation(
@@ -360,6 +378,7 @@
 
     height = widget.height ?? tooltipTheme.height ?? _defaultTooltipHeight;
     padding = widget.padding ?? tooltipTheme.padding ?? _defaultPadding;
+    margin = widget.margin ?? tooltipTheme.margin ?? _defaultMargin;
     verticalOffset = widget.verticalOffset ?? tooltipTheme.verticalOffset ?? _defaultVerticalOffset;
     preferBelow = widget.preferBelow ?? tooltipTheme.preferBelow ?? _defaultPreferBelow;
     excludeFromSemantics = widget.excludeFromSemantics ?? tooltipTheme.excludeFromSemantics ?? _defaultExcludeFromSemantics;
@@ -447,6 +466,7 @@
     this.message,
     this.height,
     this.padding,
+    this.margin,
     this.decoration,
     this.textStyle,
     this.animation,
@@ -458,6 +478,7 @@
   final String message;
   final double height;
   final EdgeInsetsGeometry padding;
+  final EdgeInsetsGeometry margin;
   final Decoration decoration;
   final TextStyle textStyle;
   final Animation<double> animation;
@@ -482,6 +503,7 @@
               child: Container(
                 decoration: decoration,
                 padding: padding,
+                margin: margin,
                 child: Center(
                   widthFactor: 1.0,
                   heightFactor: 1.0,
diff --git a/packages/flutter/lib/src/material/tooltip_theme.dart b/packages/flutter/lib/src/material/tooltip_theme.dart
index 713229f..0316d33 100644
--- a/packages/flutter/lib/src/material/tooltip_theme.dart
+++ b/packages/flutter/lib/src/material/tooltip_theme.dart
@@ -28,6 +28,7 @@
   const TooltipThemeData({
     this.height,
     this.padding,
+    this.margin,
     this.verticalOffset,
     this.preferBelow,
     this.excludeFromSemantics,
@@ -43,6 +44,9 @@
   /// If provided, the amount of space by which to inset [Tooltip.child].
   final EdgeInsetsGeometry padding;
 
+  /// If provided, the amount of empty space to surround the [Tooltip].
+  final EdgeInsetsGeometry margin;
+
   /// The vertical gap between the widget and the displayed tooltip.
   ///
   /// When [preferBelow] is set to true and tooltips have sufficient space to
@@ -84,6 +88,7 @@
   TooltipThemeData copyWith({
     double height,
     EdgeInsetsGeometry padding,
+    EdgeInsetsGeometry margin,
     double verticalOffset,
     bool preferBelow,
     bool excludeFromSemantics,
@@ -95,6 +100,7 @@
     return TooltipThemeData(
       height: height ?? this.height,
       padding: padding ?? this.padding,
+      margin: margin ?? this.margin,
       verticalOffset: verticalOffset ?? this.verticalOffset,
       preferBelow: preferBelow ?? this.preferBelow,
       excludeFromSemantics: excludeFromSemantics ?? this.excludeFromSemantics,
@@ -117,6 +123,7 @@
     return TooltipThemeData(
       height: lerpDouble(a?.height, b?.height, t),
       padding: EdgeInsets.lerp(a?.padding, b?.padding, t),
+      margin: EdgeInsets.lerp(a?.margin, b?.margin, t),
       verticalOffset: lerpDouble(a?.verticalOffset, b?.verticalOffset, t),
       preferBelow: t < 0.5 ? a.preferBelow: b.preferBelow,
       excludeFromSemantics: t < 0.5 ? a.excludeFromSemantics : b.excludeFromSemantics,
@@ -130,6 +137,7 @@
     return hashValues(
       height,
       padding,
+      margin,
       verticalOffset,
       preferBelow,
       excludeFromSemantics,
@@ -149,6 +157,7 @@
     final TooltipThemeData typedOther = other;
     return typedOther.height == height
         && typedOther.padding == padding
+        && typedOther.margin == margin
         && typedOther.verticalOffset == verticalOffset
         && typedOther.preferBelow == preferBelow
         && typedOther.excludeFromSemantics == excludeFromSemantics
@@ -163,6 +172,7 @@
     super.debugFillProperties(properties);
     properties.add(DoubleProperty('height', height, defaultValue: null));
     properties.add(DiagnosticsProperty<EdgeInsetsGeometry>('padding', padding, defaultValue: null));
+    properties.add(DiagnosticsProperty<EdgeInsetsGeometry>('margin', margin, defaultValue: null));
     properties.add(DoubleProperty('vertical offset', verticalOffset, defaultValue: null));
     properties.add(FlagProperty('position', value: preferBelow, ifTrue: 'below', ifFalse: 'above', showName: true, defaultValue: null));
     properties.add(FlagProperty('semantics', value: excludeFromSemantics, ifTrue: 'excluded', showName: true, defaultValue: null));
@@ -208,6 +218,7 @@
     Key key,
     double height,
     EdgeInsetsGeometry padding,
+    EdgeInsetsGeometry margin,
     double verticalOffset,
     bool preferBelow,
     bool excludeFromSemantics,
@@ -219,6 +230,7 @@
   }) : data = TooltipThemeData(
          height: height,
          padding: padding,
+         margin: margin,
          verticalOffset: verticalOffset,
          preferBelow: preferBelow,
          excludeFromSemantics: excludeFromSemantics,
diff --git a/packages/flutter/test/material/tooltip_test.dart b/packages/flutter/test/material/tooltip_test.dart
index 50f58d54..bcb86ee 100644
--- a/packages/flutter/test/material/tooltip_test.dart
+++ b/packages/flutter/test/material/tooltip_test.dart
@@ -32,6 +32,13 @@
 
 const String tooltipText = 'TIP';
 
+Finder _findTooltipContainer(String tooltipText) {
+  return find.ancestor(
+    of: find.text(tooltipText),
+    matching: find.byType(Container),
+  );
+}
+
 void main() {
   testWidgets('Does tooltip end up in the right place - center', (WidgetTester tester) async {
     final GlobalKey key = GlobalKey();
@@ -80,8 +87,9 @@
      *                   *
      *********************/
 
-    final RenderBox tip = tester.renderObject(find.text(tooltipText)).parent.parent.parent.parent.parent;
-
+    final RenderBox tip = tester.renderObject(
+      _findTooltipContainer(tooltipText),
+    );
     final Offset tipInGlobal = tip.localToGlobal(tip.size.topCenter(Offset.zero));
     // The exact position of the left side depends on the font the test framework
     // happens to pick, so we don't test that.
@@ -136,7 +144,9 @@
      *                   *
      *********************/
 
-    final RenderBox tip = tester.renderObject(find.text(tooltipText)).parent.parent.parent.parent.parent;
+    final RenderBox tip = tester.renderObject(
+      _findTooltipContainer(tooltipText),
+    );
     expect(tip.size.height, equals(24.0)); // 14.0 height + 5.0 padding * 2 (top, bottom)
     expect(tip.localToGlobal(tip.size.topLeft(Offset.zero)), equals(const Offset(10.0, 20.0)));
   }, skip: isBrowser);
@@ -189,7 +199,9 @@
      *                   *
      *********************/
 
-    final RenderBox tip = tester.renderObject(find.text(tooltipText)).parent;
+    final RenderBox tip = tester.renderObject(
+      _findTooltipContainer(tooltipText),
+    );
     expect(tip.size.height, equals(100.0));
     expect(tip.localToGlobal(tip.size.topLeft(Offset.zero)).dy, equals(100.0));
     expect(tip.localToGlobal(tip.size.bottomRight(Offset.zero)).dy, equals(200.0));
@@ -254,7 +266,9 @@
      *                   * }- 10.0 margin
      *********************/
 
-    final RenderBox tip = tester.renderObject(find.text(tooltipText)).parent;
+    final RenderBox tip = tester.renderObject(
+      _findTooltipContainer(tooltipText),
+    );
     expect(tip.size.height, equals(190.0));
     expect(tip.localToGlobal(tip.size.topLeft(Offset.zero)).dy, equals(399.0));
     expect(tip.localToGlobal(tip.size.bottomRight(Offset.zero)).dy, equals(589.0));
@@ -307,7 +321,9 @@
      *                   * }- 10.0 margin
      *********************/
 
-    final RenderBox tip = tester.renderObject(find.text(tooltipText)).parent;
+    final RenderBox tip = tester.renderObject(
+      _findTooltipContainer(tooltipText),
+    );
     expect(tip.size.height, equals(190.0));
     expect(tip.localToGlobal(tip.size.topLeft(Offset.zero)).dy, equals(400.0));
     expect(tip.localToGlobal(tip.size.bottomRight(Offset.zero)).dy, equals(590.0));
@@ -361,7 +377,9 @@
      *                   * }-10.0 margin
      *********************/
 
-    final RenderBox tip = tester.renderObject(find.text(tooltipText)).parent;
+    final RenderBox tip = tester.renderObject(
+      _findTooltipContainer(tooltipText),
+    );
     expect(tip.size.height, equals(14.0));
     expect(tip.localToGlobal(tip.size.topLeft(Offset.zero)).dy, equals(310.0));
     expect(tip.localToGlobal(tip.size.bottomRight(Offset.zero)).dx, equals(790.0));
@@ -416,13 +434,73 @@
      *                   * }-10.0 margin
      *********************/
 
-    final RenderBox tip = tester.renderObject(find.text(tooltipText)).parent;
+    final RenderBox tip = tester.renderObject(
+      _findTooltipContainer(tooltipText),
+    );
     expect(tip.size.height, equals(14.0));
     expect(tip.localToGlobal(tip.size.topLeft(Offset.zero)).dy, equals(310.0));
     expect(tip.localToGlobal(tip.size.bottomRight(Offset.zero)).dx, equals(790.0));
     expect(tip.localToGlobal(tip.size.bottomRight(Offset.zero)).dy, equals(324.0));
   }, skip: isBrowser);
 
+  testWidgets('Custom tooltip margin', (WidgetTester tester) async {
+    const double _customMarginValue = 10.0;
+    final GlobalKey key = GlobalKey();
+    await tester.pumpWidget(
+      Directionality(
+        textDirection: TextDirection.ltr,
+        child: Overlay(
+          initialEntries: <OverlayEntry>[
+            OverlayEntry(
+              builder: (BuildContext context) {
+                return Tooltip(
+                  key: key,
+                  message: tooltipText,
+                  padding: const EdgeInsets.all(0.0),
+                  margin: const EdgeInsets.all(_customMarginValue),
+                  child: Container(
+                    width: 0.0,
+                    height: 0.0,
+                  ),
+                );
+              },
+            ),
+          ],
+        ),
+      ),
+    );
+    (key.currentState as dynamic).ensureTooltipVisible(); // Before using "as dynamic" in your code, see note at the top of the file.
+    await tester.pump(const Duration(seconds: 2)); // faded in, show timer started (and at 0.0)
+
+    final Offset topLeftTipInGlobal = tester.getTopLeft(
+      _findTooltipContainer(tooltipText),
+    );
+    final Offset topLeftTooltipContentInGlobal = tester.getTopLeft(find.text(tooltipText));
+    expect(topLeftTooltipContentInGlobal.dx, topLeftTipInGlobal.dx + _customMarginValue);
+    expect(topLeftTooltipContentInGlobal.dy, topLeftTipInGlobal.dy + _customMarginValue);
+
+    final Offset topRightTipInGlobal = tester.getTopRight(
+      _findTooltipContainer(tooltipText),
+    );
+    final Offset topRightTooltipContentInGlobal = tester.getTopRight(find.text(tooltipText));
+    expect(topRightTooltipContentInGlobal.dx, topRightTipInGlobal.dx - _customMarginValue);
+    expect(topRightTooltipContentInGlobal.dy, topRightTipInGlobal.dy + _customMarginValue);
+
+    final Offset bottomLeftTipInGlobal = tester.getBottomLeft(
+      _findTooltipContainer(tooltipText),
+    );
+    final Offset bottomLeftTooltipContentInGlobal = tester.getBottomLeft(find.text(tooltipText));
+    expect(bottomLeftTooltipContentInGlobal.dx, bottomLeftTipInGlobal.dx + _customMarginValue);
+    expect(bottomLeftTooltipContentInGlobal.dy, bottomLeftTipInGlobal.dy - _customMarginValue);
+
+    final Offset bottomRightTipInGlobal = tester.getBottomRight(
+      _findTooltipContainer(tooltipText),
+    );
+    final Offset bottomRightTooltipContentInGlobal = tester.getBottomRight(find.text(tooltipText));
+    expect(bottomRightTooltipContentInGlobal.dx, bottomRightTipInGlobal.dx - _customMarginValue);
+    expect(bottomRightTooltipContentInGlobal.dy, bottomRightTipInGlobal.dy - _customMarginValue);
+  });
+
   testWidgets('Default tooltip message textStyle - light', (WidgetTester tester) async {
     final GlobalKey key = GlobalKey();
     await tester.pumpWidget(MaterialApp(
@@ -524,8 +602,9 @@
     (key.currentState as dynamic).ensureTooltipVisible(); // Before using "as dynamic" in your code, see note at the top of the file.
     await tester.pump(const Duration(seconds: 2)); // faded in, show timer started (and at 0.0)
 
-    final RenderBox tip = tester.renderObject(find.text(tooltipText)).parent.parent.parent.parent;
-
+    final RenderBox tip = tester.renderObject(
+      _findTooltipContainer(tooltipText),
+    );
     expect(tip.size.height, equals(32.0));
     expect(tip.size.width, equals(74.0));
     expect(tip, paints..rrect(
@@ -565,8 +644,9 @@
     (key.currentState as dynamic).ensureTooltipVisible(); // Before using "as dynamic" in your code, see note at the top of the file.
     await tester.pump(const Duration(seconds: 2)); // faded in, show timer started (and at 0.0)
 
-    final RenderBox tip = tester.renderObject(find.text(tooltipText)).parent.parent.parent.parent;
-
+    final RenderBox tip = tester.renderObject(
+      _findTooltipContainer(tooltipText),
+    );
     expect(tip.size.height, equals(32.0));
     expect(tip.size.width, equals(74.0));
     expect(tip, paints..path(
@@ -782,14 +862,18 @@
     await tester.longPress(find.byType(Tooltip));
     expect(find.text(tooltipText), findsOneWidget);
     expect(tester.getSize(find.text(tooltipText)), equals(const Size(42.0, 14.0)));
-    RenderBox tip = tester.renderObject(find.text(tooltipText)).parent;
+    RenderBox tip = tester.renderObject(
+      _findTooltipContainer(tooltipText),
+    );
     expect(tip.size.height, equals(32.0));
 
     await tester.pumpWidget(buildApp(tooltipText, textScaleFactor: 4.0));
     await tester.longPress(find.byType(Tooltip));
     expect(find.text(tooltipText), findsOneWidget);
     expect(tester.getSize(find.text(tooltipText)), equals(const Size(168.0, 56.0)));
-    tip = tester.renderObject(find.text(tooltipText)).parent;
+    tip = tester.renderObject(
+      _findTooltipContainer(tooltipText),
+    );
     expect(tip.size.height, equals(56.0));
   }, skip: isBrowser);
 
@@ -953,6 +1037,7 @@
       waitDuration: Duration(seconds: 1),
       showDuration: Duration(seconds: 2),
       padding: EdgeInsets.zero,
+      margin: EdgeInsets.all(5.0),
       height: 100.0,
       excludeFromSemantics: true,
       preferBelow: false,
@@ -967,6 +1052,7 @@
       '"message"',
       'height: 100.0',
       'padding: EdgeInsets.zero',
+      'margin: EdgeInsets.all(5.0)',
       'vertical offset: 50.0',
       'position: above',
       'semantics: excluded',
diff --git a/packages/flutter/test/material/tooltip_theme_test.dart b/packages/flutter/test/material/tooltip_theme_test.dart
index 722b676..3625ef6 100644
--- a/packages/flutter/test/material/tooltip_theme_test.dart
+++ b/packages/flutter/test/material/tooltip_theme_test.dart
@@ -28,6 +28,7 @@
 // production code.
 
 const String tooltipText = 'TIP';
+const double _customPaddingValue = 10.0;
 
 void main() {
   test('TooltipThemeData copyWith, ==, hashCode basics', () {
@@ -460,6 +461,118 @@
     expect(tip.localToGlobal(tip.size.bottomRight(Offset.zero)).dy, equals(590.0));
   });
 
+  testWidgets('Tooltip margin - ThemeData', (WidgetTester tester) async {
+    final GlobalKey key = GlobalKey();
+    await tester.pumpWidget(
+      Directionality(
+        textDirection: TextDirection.ltr,
+        child: Overlay(
+          initialEntries: <OverlayEntry>[
+            OverlayEntry(
+              builder: (BuildContext context) {
+                return Theme(
+                  data: ThemeData(
+                    tooltipTheme: const TooltipThemeData(
+                      padding: EdgeInsets.all(0.0),
+                      margin: EdgeInsets.all(_customPaddingValue),
+                    ),
+                  ),
+                  child: Tooltip(
+                    key: key,
+                    message: tooltipText,
+                    child: Container(
+                      width: 0.0,
+                      height: 0.0,
+                    ),
+                  ),
+                );
+              },
+            ),
+          ],
+        ),
+      ),
+    );
+    (key.currentState as dynamic).ensureTooltipVisible(); // Before using "as dynamic" in your code, see note at the top of the file.
+    await tester.pump(const Duration(seconds: 2)); // faded in, show timer started (and at 0.0)
+
+    final RenderBox tip = tester.renderObject(find.text(tooltipText)).parent.parent.parent.parent.parent;
+    final RenderBox tooltipContent = tester.renderObject(find.text(tooltipText));
+
+    final Offset topLeftTipInGlobal = tip.localToGlobal(tip.size.topLeft(Offset.zero));
+    final Offset topLeftTooltipContentInGlobal = tooltipContent.localToGlobal(tooltipContent.size.topLeft(Offset.zero));
+    expect(topLeftTooltipContentInGlobal.dx, topLeftTipInGlobal.dx + _customPaddingValue);
+    expect(topLeftTooltipContentInGlobal.dy, topLeftTipInGlobal.dy + _customPaddingValue);
+
+    final Offset topRightTipInGlobal = tip.localToGlobal(tip.size.topRight(Offset.zero));
+    final Offset topRightTooltipContentInGlobal = tooltipContent.localToGlobal(tooltipContent.size.topRight(Offset.zero));
+    expect(topRightTooltipContentInGlobal.dx, topRightTipInGlobal.dx - _customPaddingValue);
+    expect(topRightTooltipContentInGlobal.dy, topRightTipInGlobal.dy + _customPaddingValue);
+
+    final Offset bottomLeftTipInGlobal = tip.localToGlobal(tip.size.bottomLeft(Offset.zero));
+    final Offset bottomLeftTooltipContentInGlobal = tooltipContent.localToGlobal(tooltipContent.size.bottomLeft(Offset.zero));
+    expect(bottomLeftTooltipContentInGlobal.dx, bottomLeftTipInGlobal.dx + _customPaddingValue);
+    expect(bottomLeftTooltipContentInGlobal.dy, bottomLeftTipInGlobal.dy - _customPaddingValue);
+
+    final Offset bottomRightTipInGlobal = tip.localToGlobal(tip.size.bottomRight(Offset.zero));
+    final Offset bottomRightTooltipContentInGlobal = tooltipContent.localToGlobal(tooltipContent.size.bottomRight(Offset.zero));
+    expect(bottomRightTooltipContentInGlobal.dx, bottomRightTipInGlobal.dx - _customPaddingValue);
+    expect(bottomRightTooltipContentInGlobal.dy, bottomRightTipInGlobal.dy - _customPaddingValue);
+  });
+
+  testWidgets('Tooltip margin - TooltipTheme', (WidgetTester tester) async {
+    final GlobalKey key = GlobalKey();
+    await tester.pumpWidget(
+      Directionality(
+        textDirection: TextDirection.ltr,
+        child: Overlay(
+          initialEntries: <OverlayEntry>[
+            OverlayEntry(
+              builder: (BuildContext context) {
+                return TooltipTheme(
+                  padding: const EdgeInsets.all(0.0),
+                  margin: const EdgeInsets.all(_customPaddingValue),
+                  child: Tooltip(
+                    key: key,
+                    message: tooltipText,
+                    child: Container(
+                      width: 0.0,
+                      height: 0.0,
+                    ),
+                  ),
+                );
+              },
+            ),
+          ],
+        ),
+      ),
+    );
+    (key.currentState as dynamic).ensureTooltipVisible(); // Before using "as dynamic" in your code, see note at the top of the file.
+    await tester.pump(const Duration(seconds: 2)); // faded in, show timer started (and at 0.0)
+
+    final RenderBox tip = tester.renderObject(find.text(tooltipText)).parent.parent.parent.parent.parent;
+    final RenderBox tooltipContent = tester.renderObject(find.text(tooltipText));
+
+    final Offset topLeftTipInGlobal = tip.localToGlobal(tip.size.topLeft(Offset.zero));
+    final Offset topLeftTooltipContentInGlobal = tooltipContent.localToGlobal(tooltipContent.size.topLeft(Offset.zero));
+    expect(topLeftTooltipContentInGlobal.dx, topLeftTipInGlobal.dx + _customPaddingValue);
+    expect(topLeftTooltipContentInGlobal.dy, topLeftTipInGlobal.dy + _customPaddingValue);
+
+    final Offset topRightTipInGlobal = tip.localToGlobal(tip.size.topRight(Offset.zero));
+    final Offset topRightTooltipContentInGlobal = tooltipContent.localToGlobal(tooltipContent.size.topRight(Offset.zero));
+    expect(topRightTooltipContentInGlobal.dx, topRightTipInGlobal.dx - _customPaddingValue);
+    expect(topRightTooltipContentInGlobal.dy, topRightTipInGlobal.dy + _customPaddingValue);
+
+    final Offset bottomLeftTipInGlobal = tip.localToGlobal(tip.size.bottomLeft(Offset.zero));
+    final Offset bottomLeftTooltipContentInGlobal = tooltipContent.localToGlobal(tooltipContent.size.bottomLeft(Offset.zero));
+    expect(bottomLeftTooltipContentInGlobal.dx, bottomLeftTipInGlobal.dx + _customPaddingValue);
+    expect(bottomLeftTooltipContentInGlobal.dy, bottomLeftTipInGlobal.dy - _customPaddingValue);
+
+    final Offset bottomRightTipInGlobal = tip.localToGlobal(tip.size.bottomRight(Offset.zero));
+    final Offset bottomRightTooltipContentInGlobal = tooltipContent.localToGlobal(tooltipContent.size.bottomRight(Offset.zero));
+    expect(bottomRightTooltipContentInGlobal.dx, bottomRightTipInGlobal.dx - _customPaddingValue);
+    expect(bottomRightTooltipContentInGlobal.dy, bottomRightTipInGlobal.dy - _customPaddingValue);
+  });
+
   testWidgets('Tooltip message textStyle - ThemeData.tooltipTheme', (WidgetTester tester) async {
     final GlobalKey key = GlobalKey();
     await tester.pumpWidget(MaterialApp(
@@ -641,7 +754,7 @@
 
     final RenderBox tip = tester.renderObject(find.ancestor(
       of: find.text(tooltipText),
-      matching: find.byType(Padding),
+      matching: find.byType(Padding).first, // select [Tooltip.padding] instead of [Tooltip.margin]
     ));
     final RenderBox content = tester.renderObject(find.ancestor(
       of: find.text(tooltipText),
@@ -684,7 +797,7 @@
 
     final RenderBox tip = tester.renderObject(find.ancestor(
       of: find.text(tooltipText),
-      matching: find.byType(Padding),
+      matching: find.byType(Padding).first, // select [Tooltip.padding] instead of [Tooltip.margin]
     ));
     final RenderBox content = tester.renderObject(find.ancestor(
       of: find.text(tooltipText),