diff --git a/lib/ui/painting.dart b/lib/ui/painting.dart
index f97b2d271be83..7ac5d238b61a8 100644
--- a/lib/ui/painting.dart
+++ b/lib/ui/painting.dart
@@ -2296,25 +2296,44 @@ class Gradient extends Shader {
   /// If `matrix4` is provided, the gradient fill will be transformed by the
   /// specified 4x4 matrix relative to the local coordinate system. `matrix4` must
   /// be a column-major matrix packed into a list of 16 values.
+  /// 
+  /// If `focal` is provided and not equal to `center` or `focalRadius` is 
+  /// provided and not equal to 0.0, the generated shader will be a two point
+  /// conical radial gradient, with `focal` being the center of the focal 
+  /// circle and `focalRadius` being the radius of that circle. If `focal` is
+  /// provided and not equal to `center`, at least one of the two offsets must
+  /// not be equal to [Offset.zero].
   Gradient.radial(
     Offset center,
     double radius,
     List<Color> colors, [
     List<double> colorStops,
     TileMode tileMode = TileMode.clamp,
-    Float64List matrix4
+    Float64List matrix4,
+    Offset focal,
+    double focalRadius
   ]) : assert(_offsetIsValid(center)),
        assert(colors != null),
        assert(tileMode != null),
        assert(matrix4 == null || _matrix4IsValid(matrix4)),
        super._() {
+    focal ??= center;
+    focalRadius ??= 0.0;
     _validateColorStops(colors, colorStops);
     final Int32List colorsBuffer = _encodeColorList(colors);
     final Float32List colorStopsBuffer = colorStops == null ? null : new Float32List.fromList(colorStops);
-    _constructor();
-    _initRadial(center.dx, center.dy, radius, colorsBuffer, colorStopsBuffer, tileMode.index, matrix4);
+
+    if (center == focal && focalRadius != 0.0) {
+      _constructor();
+      _initRadial(center.dx, center.dy, radius, colorsBuffer, colorStopsBuffer, tileMode.index, matrix4);
+    } else {
+      assert(center != Offset.zero || focal != Offset.zero); // will result in nullptr in Skia side
+      _constructor();
+      _initConical(focal.dx, focal.dy, focalRadius, center.dx, center.dy, radius, colorsBuffer, colorStopsBuffer, tileMode.index, matrix4);
+    }
   }
   void _initRadial(double centerX, double centerY, double radius, Int32List colors, Float32List colorStops, int tileMode, Float64List matrix4) native 'Gradient_initRadial';
+  void _initConical(double startX, double startY, double startRadius, double endX, double endY, double endRadius, Int32List colors, Float32List colorStops, int tileMode, Float64List matrix4) native 'Gradient_initTwoPointConical';
 
   /// Creates a sweep gradient centered at `center` that starts at `startAngle`
   /// and ends at `endAngle`.
diff --git a/lib/ui/painting/gradient.cc b/lib/ui/painting/gradient.cc
index 9cbf5a19c5275..71b2669100fa1 100644
--- a/lib/ui/painting/gradient.cc
+++ b/lib/ui/painting/gradient.cc
@@ -25,7 +25,8 @@ IMPLEMENT_WRAPPERTYPEINFO(ui, Gradient);
 #define FOR_EACH_BINDING(V) \
   V(Gradient, initLinear)   \
   V(Gradient, initRadial)   \
-  V(Gradient, initSweep)
+  V(Gradient, initSweep)    \
+  V(Gradient, initTwoPointConical)
 
 FOR_EACH_BINDING(DART_NATIVE_CALLBACK)
 
@@ -109,6 +110,35 @@ void CanvasGradient::initSweep(double center_x,
       has_matrix ? &sk_matrix : nullptr)));
 }
 
+void CanvasGradient::initTwoPointConical(double start_x,
+                                         double start_y,
+                                         double start_radius,
+                                         double end_x,
+                                         double end_y,
+                                         double end_radius,
+                                         const tonic::Int32List& colors,
+                                         const tonic::Float32List& color_stops,
+                                         SkShader::TileMode tile_mode,
+                                         const tonic::Float64List& matrix4) {
+  FXL_DCHECK(colors.num_elements() == color_stops.num_elements() ||
+             color_stops.data() == nullptr);
+
+  static_assert(sizeof(SkColor) == sizeof(int32_t),
+                "SkColor doesn't use int32_t.");
+
+  SkMatrix sk_matrix;
+  bool has_matrix = matrix4.data() != nullptr;
+  if (has_matrix) {
+    sk_matrix = ToSkMatrix(matrix4);
+  }
+
+  set_shader(UIDartState::CreateGPUObject(SkGradientShader::MakeTwoPointConical(
+      SkPoint::Make(start_x, start_y), start_radius,
+      SkPoint::Make(end_x, end_y), end_radius,
+      reinterpret_cast<const SkColor*>(colors.data()), color_stops.data(),
+      colors.num_elements(), tile_mode, 0, has_matrix ? &sk_matrix : nullptr)));
+}
+
 CanvasGradient::CanvasGradient() = default;
 
 CanvasGradient::~CanvasGradient() = default;
diff --git a/lib/ui/painting/gradient.h b/lib/ui/painting/gradient.h
index 178c17fe9b41c..4d8e8ec09191b 100644
--- a/lib/ui/painting/gradient.h
+++ b/lib/ui/painting/gradient.h
@@ -52,6 +52,17 @@ class CanvasGradient : public Shader {
                  double end_angle,
                  const tonic::Float64List& matrix4);
 
+  void initTwoPointConical(double start_x,
+                           double start_y,
+                           double start_radius,
+                           double end_x,
+                           double end_y,
+                           double end_radius,
+                           const tonic::Int32List& colors,
+                           const tonic::Float32List& color_stops,
+                           SkShader::TileMode tile_mode,
+                           const tonic::Float64List& matrix4);
+
   static void RegisterNatives(tonic::DartLibraryNatives* natives);
 
  private: