Generate Android Framework host-side Skia (linux)

Bug: b/118742766

Update gn_to_bp to write an Android.bp file that will build a host-side
Skia library.

Switch some methods from SK_BUILD_FOR_ANDROID to
SK_BUILD_FOR_ANDROID_FRAMEWORK.

Prior reviews were done at ag/5482397.

gn_to_bp.py:
- Run GN twice - once for android and once for linux
- Disable GPU (depends on a to-be-written host side GL target) and HEIF
  (which relies on Android hardware) on linux
  - TODO: Turn on GPU on linux
- Split sources into everywhere, android-only, and linux-only.
  It seems that Android.bp does not allow using the same cpp
  file in multiple targets.
  - note that we currently *only* divide out the sources. The cflags are
    the same (except for a couple manual ones) and include
    directories are mostly the same (again, except for manual ones).
    Android has a "gpu" include directory, which I don't expect to
    make a difference to the linux build, which isn't using GPU (yet).
- Use the same "custom empty" font manager on the host as on Android
- Write separate SkUserConfig files; one for android and one for linux.
  This allows libskia to force libraries that use it to use the right
  defines by setting export_include_dirs.
- Add extra checks to SkUserConfig.h to ensure we have only the
  appropriate SK_BUILD_FOR macro defined
- Add host_supported: true for libskia

gn_to_bp_utils.py:
- Switch SkUserConfig.h from include guards to pragma once so it is
  easier to append to the end. This matches how Android generally
  includes headers.

BUILD.gn:
- Add skia_use_fixed_gamma_text so host build can use the same SK_GAMMA
  defines as the device.

SkPreConfig.h:
- Stop making SK_BUILD_FOR_ANDROID_FRAMEWORK imply SK_BUILD_FOR_ANDROID.
  The host build needs the former defined but not the latter.

SkRegion.cpp/.h:
- Make toString() SK_BUILD_FOR_ANDROID_FRAMEWORK so it can be called on
  the host.

SkCamera.h/.cpp:
- Switch methods to SK_BUILD_FOR_ANDROID_FRAMEWORK so they can be called
  on the host.
- Make getCameraLocation*() const. They are logically const, and this
  allows removing a const_cast + TODO in hwui.

Change-Id: I771f825d06380e01c0488fd1c00df1d8a2454dc0
Reviewed-on: https://skia-review.googlesource.com/c/171231
Reviewed-by: Derek Sollenberger <djsollen@google.com>
Commit-Queue: Leon Scroggins <scroggo@google.com>
diff --git a/gn/gn_to_bp.py b/gn/gn_to_bp.py
index e941a5b..f9d5443 100644
--- a/gn/gn_to_bp.py
+++ b/gn/gn_to_bp.py
@@ -7,7 +7,6 @@
 
 # Generate Android.bp for Skia from GN configuration.
 
-import json
 import os
 import pprint
 import string
@@ -22,6 +21,7 @@
 
 cc_library_static {
     name: "libskia",
+    host_supported: true,
     cflags: [
         $cflags
     ],
@@ -86,6 +86,36 @@
         },
     },
 
+    target: {
+      android: {
+        srcs: [
+          $android_srcs
+          "third_party/vulkanmemoryallocator/GrVulkanMemoryAllocator.cpp",
+        ],
+        local_include_dirs: [
+          "include/config/android",
+          "third_party/vulkanmemoryallocator/",
+        ],
+        export_include_dirs: [
+          "include/config/android",
+        ],
+      },
+      linux_glibc: {
+        cflags: [
+          "-mssse3",
+        ],
+        srcs: [
+          $linux_srcs
+        ],
+        local_include_dirs: [
+          "include/config/linux",
+        ],
+        export_include_dirs: [
+          "include/config/linux",
+        ],
+      },
+    },
+
     defaults: ["skia_deps",
                "skia_pgo",
     ],
@@ -120,22 +150,17 @@
 cc_defaults {
     name: "skia_deps",
     shared_libs: [
-        "libEGL",
-        "libGLESv2",
         "libdng_sdk",
         "libexpat",
         "libft2",
-        "libheif",
         "libicui18n",
         "libicuuc",
         "libjpeg",
         "liblog",
         "libpiex",
         "libpng",
-        "libvulkan",
         "libz",
         "libcutils",
-        "libnativewindow",
     ],
     static_libs: [
         "libarect",
@@ -144,6 +169,17 @@
         "libwebp-encode",
     ],
     group_static_libs: true,
+    target: {
+      android: {
+        shared_libs: [
+            "libEGL",
+            "libGLESv2",
+            "libheif",
+            "libvulkan",
+            "libnativewindow",
+        ],
+      },
+    },
 }
 
 cc_defaults {
@@ -217,21 +253,31 @@
   'skia_enable_fontmgr_android':        'false',
 }
 
-extra_userconfig_defines = [
-]
+gn_args_linux = {
+  'is_official_build':                  'true',
+  'skia_enable_tools':                  'true',
+  'skia_enable_gpu'  :                  'false',
+  'skia_use_libheif':                   'false',
+  'skia_use_vulkan':                    'false',
+  'target_cpu':                         '"none"',
+  'target_os':                          '"linux"',
+  'skia_enable_fontmgr_custom':         'false',
+  'skia_enable_fontmgr_custom_empty':   'true',
+  'skia_enable_fontmgr_android':        'false',
+  'skia_use_fontconfig':                'false',
+  'skia_use_fixed_gamma_text':          'true',
+}
 
 js = gn_to_bp_utils.GenerateJSONFromGN(gn_args)
 
 def strip_slashes(lst):
   return {str(p.lstrip('/')) for p in lst}
 
-srcs            = strip_slashes(js['targets']['//:skia']['sources'])
+android_srcs    = strip_slashes(js['targets']['//:skia']['sources'])
 cflags          = strip_slashes(js['targets']['//:skia']['cflags'])
 cflags_cc       = strip_slashes(js['targets']['//:skia']['cflags_cc'])
 local_includes  = strip_slashes(js['targets']['//:skia']['include_dirs'])
 export_includes = strip_slashes(js['targets']['//:public']['include_dirs'])
-defines      = [str(d) for d in js['targets']['//:skia']['defines']]
-defines      += extra_userconfig_defines
 
 dm_srcs         = strip_slashes(js['targets']['//:dm']['sources'])
 dm_includes     = strip_slashes(js['targets']['//:dm']['include_dirs'])
@@ -240,7 +286,6 @@
 nanobench_srcs     = strip_slashes(nanobench_target['sources'])
 nanobench_includes = strip_slashes(nanobench_target['include_dirs'])
 
-gn_to_bp_utils.GrabDependentValues(js, '//:skia', 'sources', srcs, None)
 gn_to_bp_utils.GrabDependentValues(js, '//:dm', 'sources', dm_srcs, 'skia')
 gn_to_bp_utils.GrabDependentValues(js, '//:nanobench', 'sources',
                                    nanobench_srcs, 'skia')
@@ -249,16 +294,22 @@
 local_includes.add("third_party/skcms")
 dm_includes   .add("third_party/skcms")
 
-# need to manually include the vulkanmemoryallocator headers. If HWUI ever needs
-# direct access to the allocator we need to add it to export_includes as well.
-srcs.add("third_party/vulkanmemoryallocator/GrVulkanMemoryAllocator.cpp")
-local_includes.add("third_party/vulkanmemoryallocator/")
-
 # Android's build will choke if we list headers.
 def strip_headers(sources):
   return {s for s in sources if not s.endswith('.h')}
 
-srcs            = strip_headers(srcs)
+gn_to_bp_utils.GrabDependentValues(js, '//:skia', 'sources', android_srcs, None)
+android_srcs    = strip_headers(android_srcs)
+
+js_linux        = gn_to_bp_utils.GenerateJSONFromGN(gn_args_linux)
+linux_srcs      = strip_slashes(js_linux['targets']['//:skia']['sources'])
+gn_to_bp_utils.GrabDependentValues(js_linux, '//:skia', 'sources', linux_srcs,
+                                   None)
+linux_srcs      = strip_headers(linux_srcs)
+
+srcs = android_srcs.intersection(linux_srcs)
+android_srcs    = android_srcs.difference(srcs)
+linux_srcs      =   linux_srcs.difference(srcs)
 dm_srcs         = strip_headers(dm_srcs)
 nanobench_srcs  = strip_headers(nanobench_srcs)
 
@@ -268,7 +319,57 @@
 here = os.path.dirname(__file__)
 defs = gn_to_bp_utils.GetArchSources(os.path.join(here, 'opts.gni'))
 
-gn_to_bp_utils.WriteUserConfig('include/config/SkUserConfig.h', defines)
+def get_defines(json):
+  return {str(d) for d in json['targets']['//:skia']['defines']}
+android_defines = get_defines(js)
+linux_defines   = get_defines(js_linux)
+
+def mkdir_if_not_exists(path):
+  if not os.path.exists(path):
+    os.mkdir(path)
+mkdir_if_not_exists('include/config/android/')
+mkdir_if_not_exists('include/config/linux/')
+
+platforms = { 'IOS', 'MAC', 'WIN', 'ANDROID', 'UNIX' }
+
+def disallow_platforms(config, desired):
+  with open(config, 'a') as f:
+    p = sorted(platforms.difference({ desired }))
+    s = '#if '
+    for i in range(len(p)):
+      s = s + 'defined(SK_BUILD_FOR_%s)' % p[i]
+      if i < len(p) - 1:
+        s += ' || '
+        if i % 2 == 1:
+          s += '\\\n    '
+    print >>f, s
+    print >>f, '    #error "Only SK_BUILD_FOR_%s should be defined!"' % desired
+    print >>f, '#endif'
+
+def append_to_file(config, s):
+  with open(config, 'a') as f:
+    print >>f, s
+
+android_config = 'include/config/android/SkUserConfig.h'
+gn_to_bp_utils.WriteUserConfig(android_config, android_defines)
+append_to_file(android_config, '''
+#ifndef SK_BUILD_FOR_ANDROID
+    #error "SK_BUILD_FOR_ANDROID must be defined!"
+#endif''')
+disallow_platforms(android_config, 'ANDROID')
+
+linux_config = 'include/config/linux/SkUserConfig.h'
+gn_to_bp_utils.WriteUserConfig(linux_config, linux_defines)
+append_to_file(linux_config, '''
+// Correct SK_BUILD_FOR flags that may have been set by
+// SkPreConfig.h/Android.bp
+#ifndef SK_BUILD_FOR_UNIX
+    #define SK_BUILD_FOR_UNIX
+#endif
+#ifdef SK_BUILD_FOR_ANDROID
+    #undef SK_BUILD_FOR_ANDROID
+#endif''')
+disallow_platforms(linux_config, 'UNIX')
 
 # Turn a list of strings into the style bpfmt outputs.
 def bpfmt(indent, lst, sort=True):
@@ -277,8 +378,8 @@
   return ('\n' + ' '*indent).join('"%s",' % v for v in lst)
 
 # OK!  We have everything to fill in Android.bp...
-with open('Android.bp', 'w') as f:
-  print >>f, bp.substitute({
+with open('Android.bp', 'w') as Android_bp:
+  print >>Android_bp, bp.substitute({
     'export_includes': bpfmt(8, export_includes),
     'local_includes':  bpfmt(8, local_includes),
     'srcs':            bpfmt(8, srcs),
@@ -302,4 +403,7 @@
 
     'nanobench_includes'    : bpfmt(8, nanobench_includes),
     'nanobench_srcs'        : bpfmt(8, nanobench_srcs),
+
+    'android_srcs':  bpfmt(10, android_srcs),
+    'linux_srcs':    bpfmt(10, linux_srcs),
   })