Support per-platform default typography (#6634)

On Android and Fuchsia, default to Roboto. On iOS, use San Francisco.
diff --git a/packages/flutter/lib/src/material/theme_data.dart b/packages/flutter/lib/src/material/theme_data.dart
index fc64449..5362a98 100644
--- a/packages/flutter/lib/src/material/theme_data.dart
+++ b/packages/flutter/lib/src/material/theme_data.dart
@@ -122,11 +122,13 @@
     indicatorColor ??= accentColor == primaryColor ? Colors.white : accentColor;
     hintColor ??= isDark ? const Color(0x42FFFFFF) : const Color(0x4C000000);
     errorColor ??= Colors.red[700];
-    textTheme ??= isDark ? Typography.white : Typography.black;
-    primaryTextTheme ??= primaryIsDark ? Typography.white : Typography.black;
     iconTheme ??= isDark ? const IconThemeData(color: Colors.white) : const IconThemeData(color: Colors.black);
     primaryIconTheme ??= primaryIsDark ? const IconThemeData(color: Colors.white) : const IconThemeData(color: Colors.black);
     platform ??= defaultTargetPlatform;
+
+    final Typography typography = new Typography(platform: platform);
+    primaryTextTheme ??= primaryIsDark ? typography.white : typography.black;
+    textTheme ??= isDark ? typography.white : typography.black;
     return new ThemeData.raw(
       brightness: brightness,
       primaryColor: primaryColor,
diff --git a/packages/flutter/lib/src/material/typography.dart b/packages/flutter/lib/src/material/typography.dart
index 88e662d..d611829 100644
--- a/packages/flutter/lib/src/material/typography.dart
+++ b/packages/flutter/lib/src/material/typography.dart
@@ -3,7 +3,9 @@
 // found in the LICENSE file.
 
 
+import 'package:flutter/foundation.dart';
 import 'package:flutter/painting.dart';
+import 'package:meta/meta.dart';
 
 import 'colors.dart';
 
@@ -51,7 +53,7 @@
     this.button
   });
 
-  const TextTheme._black()
+  const TextTheme._blackMountainView()
     : display4 = const TextStyle(fontFamily: 'Roboto', inherit: false, fontSize: 112.0, fontWeight: FontWeight.w100, color: Colors.black54, textBaseline: TextBaseline.alphabetic),
       display3 = const TextStyle(fontFamily: 'Roboto', inherit: false, fontSize:  56.0, fontWeight: FontWeight.w400, color: Colors.black54, textBaseline: TextBaseline.alphabetic),
       display2 = const TextStyle(fontFamily: 'Roboto', inherit: false, fontSize:  45.0, fontWeight: FontWeight.w400, color: Colors.black54, textBaseline: TextBaseline.alphabetic),
@@ -64,7 +66,7 @@
       caption  = const TextStyle(fontFamily: 'Roboto', inherit: false, fontSize:  12.0, fontWeight: FontWeight.w400, color: Colors.black54, textBaseline: TextBaseline.alphabetic),
       button   = const TextStyle(fontFamily: 'Roboto', inherit: false, fontSize:  14.0, fontWeight: FontWeight.w500, color: Colors.black87, textBaseline: TextBaseline.alphabetic);
 
-  const TextTheme._white()
+  const TextTheme._whiteMountainView()
     : display4 = const TextStyle(fontFamily: 'Roboto', inherit: false, fontSize: 112.0, fontWeight: FontWeight.w100, color: Colors.white70, textBaseline: TextBaseline.alphabetic),
       display3 = const TextStyle(fontFamily: 'Roboto', inherit: false, fontSize:  56.0, fontWeight: FontWeight.w400, color: Colors.white70, textBaseline: TextBaseline.alphabetic),
       display2 = const TextStyle(fontFamily: 'Roboto', inherit: false, fontSize:  45.0, fontWeight: FontWeight.w400, color: Colors.white70, textBaseline: TextBaseline.alphabetic),
@@ -77,6 +79,32 @@
       caption  = const TextStyle(fontFamily: 'Roboto', inherit: false, fontSize:  12.0, fontWeight: FontWeight.w400, color: Colors.white70, textBaseline: TextBaseline.alphabetic),
       button   = const TextStyle(fontFamily: 'Roboto', inherit: false, fontSize:  14.0, fontWeight: FontWeight.w500, color: Colors.white,   textBaseline: TextBaseline.alphabetic);
 
+  const TextTheme._blackCupertino()
+      : display4 = const TextStyle(fontFamily: '.SF UI Display', inherit: false, fontSize: 112.0, fontWeight: FontWeight.w100, color: Colors.black54, textBaseline: TextBaseline.alphabetic),
+        display3 = const TextStyle(fontFamily: '.SF UI Display', inherit: false, fontSize:  56.0, fontWeight: FontWeight.w400, color: Colors.black54, textBaseline: TextBaseline.alphabetic),
+        display2 = const TextStyle(fontFamily: '.SF UI Display', inherit: false, fontSize:  45.0, fontWeight: FontWeight.w400, color: Colors.black54, textBaseline: TextBaseline.alphabetic),
+        display1 = const TextStyle(fontFamily: '.SF UI Display', inherit: false, fontSize:  34.0, fontWeight: FontWeight.w400, color: Colors.black54, textBaseline: TextBaseline.alphabetic),
+        headline = const TextStyle(fontFamily: '.SF UI Display', inherit: false, fontSize:  24.0, fontWeight: FontWeight.w400, color: Colors.black87, textBaseline: TextBaseline.alphabetic),
+        title    = const TextStyle(fontFamily: '.SF UI Display', inherit: false, fontSize:  20.0, fontWeight: FontWeight.w500, color: Colors.black87, textBaseline: TextBaseline.alphabetic),
+        subhead  = const TextStyle(fontFamily: '.SF UI Text', inherit: false, fontSize:  16.0, fontWeight: FontWeight.w400, color: Colors.black87, textBaseline: TextBaseline.alphabetic),
+        body2    = const TextStyle(fontFamily: '.SF UI Text', inherit: false, fontSize:  14.0, fontWeight: FontWeight.w500, color: Colors.black87, textBaseline: TextBaseline.alphabetic),
+        body1    = const TextStyle(fontFamily: '.SF UI Text', inherit: false, fontSize:  14.0, fontWeight: FontWeight.w400, color: Colors.black87, textBaseline: TextBaseline.alphabetic),
+        caption  = const TextStyle(fontFamily: '.SF UI Text', inherit: false, fontSize:  12.0, fontWeight: FontWeight.w400, color: Colors.black54, textBaseline: TextBaseline.alphabetic),
+        button   = const TextStyle(fontFamily: '.SF UI Text', inherit: false, fontSize:  14.0, fontWeight: FontWeight.w500, color: Colors.black87, textBaseline: TextBaseline.alphabetic);
+
+  const TextTheme._whiteCupertino()
+      : display4 = const TextStyle(fontFamily: '.SF UI Display', inherit: false, fontSize: 112.0, fontWeight: FontWeight.w100, color: Colors.white70, textBaseline: TextBaseline.alphabetic),
+        display3 = const TextStyle(fontFamily: '.SF UI Display', inherit: false, fontSize:  56.0, fontWeight: FontWeight.w400, color: Colors.white70, textBaseline: TextBaseline.alphabetic),
+        display2 = const TextStyle(fontFamily: '.SF UI Display', inherit: false, fontSize:  45.0, fontWeight: FontWeight.w400, color: Colors.white70, textBaseline: TextBaseline.alphabetic),
+        display1 = const TextStyle(fontFamily: '.SF UI Display', inherit: false, fontSize:  34.0, fontWeight: FontWeight.w400, color: Colors.white70, textBaseline: TextBaseline.alphabetic),
+        headline = const TextStyle(fontFamily: '.SF UI Display', inherit: false, fontSize:  24.0, fontWeight: FontWeight.w400, color: Colors.white,   textBaseline: TextBaseline.alphabetic),
+        title    = const TextStyle(fontFamily: '.SF UI Display', inherit: false, fontSize:  20.0, fontWeight: FontWeight.w500, color: Colors.white,   textBaseline: TextBaseline.alphabetic),
+        subhead  = const TextStyle(fontFamily: '.SF UI Text', inherit: false, fontSize:  16.0, fontWeight: FontWeight.w400, color: Colors.white,   textBaseline: TextBaseline.alphabetic),
+        body2    = const TextStyle(fontFamily: '.SF UI Text', inherit: false, fontSize:  14.0, fontWeight: FontWeight.w500, color: Colors.white,   textBaseline: TextBaseline.alphabetic),
+        body1    = const TextStyle(fontFamily: '.SF UI Text', inherit: false, fontSize:  14.0, fontWeight: FontWeight.w400, color: Colors.white,   textBaseline: TextBaseline.alphabetic),
+        caption  = const TextStyle(fontFamily: '.SF UI Text', inherit: false, fontSize:  12.0, fontWeight: FontWeight.w400, color: Colors.white70, textBaseline: TextBaseline.alphabetic),
+        button   = const TextStyle(fontFamily: '.SF UI Text', inherit: false, fontSize:  14.0, fontWeight: FontWeight.w500, color: Colors.white,   textBaseline: TextBaseline.alphabetic);
+
   /// Extremely large text.
   ///
   /// The font size is 112 pixels.
@@ -255,10 +283,10 @@
 
 /// The two material design text themes.
 ///
-/// [Typography.black] and [Typography.white] define the two text themes used in
-/// material design. The black text theme, which uses dark glyphs, is used on
-/// light backgrounds in light themes. The white text theme, which uses light
-/// glyphs, is used in dark themes and on dark backgrounds in in light themes.
+/// Material design defines two text themes: [black] and [white]. The black
+/// text theme, which uses dark glyphs, is used on light backgrounds in light
+/// themes. The white text theme, which uses light glyphs, is used in dark
+/// themes and on dark backgrounds in light themes.
 ///
 /// To obtain the current text theme, call [Theme.of] with the current
 /// [BuildContext] and read the [ThemeData.textTheme] property.
@@ -269,11 +297,30 @@
 ///  * [ThemeData]
 ///  * <http://material.google.com/style/typography.html>
 class Typography {
-  Typography._();
+  /// Creates the default typography for the specified platform.
+  factory Typography({ @required TargetPlatform platform }) {
+    assert(platform != null);
+    switch (platform) {
+      case TargetPlatform.android:
+      case TargetPlatform.fuchsia:
+        return const Typography._(
+            const TextTheme._blackMountainView(),
+            const TextTheme._whiteMountainView(),
+        );
+      case TargetPlatform.iOS:
+        return const Typography._(
+            const TextTheme._blackCupertino(),
+            const TextTheme._whiteCupertino(),
+        );
+    }
+    return null;
+  }
+
+  const Typography._(this.black, this.white);
 
   /// A material design text theme with dark glyphs.
-  static const TextTheme black = const TextTheme._black();
+  final TextTheme black;
 
   /// A material design text theme with light glyphs.
-  static const TextTheme white = const TextTheme._white();
+  final TextTheme white;
 }
diff --git a/packages/flutter/test/material/theme_data_test.dart b/packages/flutter/test/material/theme_data_test.dart
new file mode 100644
index 0000000..8c5f951
--- /dev/null
+++ b/packages/flutter/test/material/theme_data_test.dart
@@ -0,0 +1,16 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+import 'package:flutter/material.dart';
+import 'package:flutter_test/flutter_test.dart';
+
+void main() {
+  test('Defaults to the default typography for the platform', () {
+    for (TargetPlatform platform in TargetPlatform.values) {
+      ThemeData theme = new ThemeData(platform: platform);
+      Typography typography = new Typography(platform: platform);
+      expect(theme.textTheme, typography.black, reason: 'Not using default typography for $platform');
+    }
+  });
+}
diff --git a/packages/flutter/test/material/typography_test.dart b/packages/flutter/test/material/typography_test.dart
new file mode 100644
index 0000000..88d99d7
--- /dev/null
+++ b/packages/flutter/test/material/typography_test.dart
@@ -0,0 +1,44 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+import 'package:flutter/material.dart';
+import 'package:flutter_test/flutter_test.dart';
+
+void main() {
+  test('Typography is defined for all target platforms', () {
+    for (TargetPlatform platform in TargetPlatform.values) {
+      Typography typography = new Typography(platform: platform);
+      expect(typography, isNotNull, reason: 'null typography for $platform');
+      expect(typography.black, isNotNull, reason: 'null black typography for $platform');
+      expect(typography.white, isNotNull, reason: 'null white typography for $platform');
+    }
+  });
+
+  test('Typography on Android, Fuchsia defaults to Roboto', () {
+    expect(new Typography(platform: TargetPlatform.android).black.title.fontFamily, 'Roboto');
+    expect(new Typography(platform: TargetPlatform.fuchsia).black.title.fontFamily, 'Roboto');
+  });
+
+  test('Typography on iOS defaults to the correct SF font family based on size', () {
+    // Ref: https://developer.apple.com/ios/human-interface-guidelines/visual-design/typography/
+    Matcher hasCorrectFont = predicate((TextStyle s) {
+      return s.fontFamily == (s.fontSize <= 19.0 ? '.SF UI Text' : '.SF UI Display');
+    }, 'Uses SF Display font for font sizes over 19.0, otherwise SF Text font');
+
+    Typography typography = new Typography(platform: TargetPlatform.iOS);
+    for (TextTheme textTheme in <TextTheme>[typography.black, typography.white]) {
+      expect(textTheme.display4, hasCorrectFont);
+      expect(textTheme.display3, hasCorrectFont);
+      expect(textTheme.display2, hasCorrectFont);
+      expect(textTheme.display1, hasCorrectFont);
+      expect(textTheme.headline, hasCorrectFont);
+      expect(textTheme.title, hasCorrectFont);
+      expect(textTheme.subhead, hasCorrectFont);
+      expect(textTheme.body2, hasCorrectFont);
+      expect(textTheme.body1, hasCorrectFont);
+      expect(textTheme.caption, hasCorrectFont);
+      expect(textTheme.button, hasCorrectFont);
+    }
+  });
+}