diff --git a/.gitignore b/.gitignore index b5f80bd40a3..445374a7392 100644 --- a/.gitignore +++ b/.gitignore @@ -9,7 +9,6 @@ .checkstyle .gdbinit .landmines -.packages .project .pub .pydevproject diff --git a/BUILD.gn b/BUILD.gn index 67da82bd9e5..c478f43d46c 100644 --- a/BUILD.gn +++ b/BUILD.gn @@ -9,6 +9,7 @@ group("flutter") { # TODO(abarth) Remove this specific list once Fuchsia can build everything. deps = [ "//flutter/content_handler", + "//flutter/examples", "//flutter/flow", "//flutter/runtime", "//flutter/snapshotter", diff --git a/build/flx.gni b/build/flx.gni new file mode 100644 index 00000000000..4a982a73aff --- /dev/null +++ b/build/flx.gni @@ -0,0 +1,68 @@ +# 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. + +template("flx") { + if (defined(invoker.output_name)) { + bundle_name = invoker.output_name + } else { + bundle_name = "${target_name}.flx" + } + + bundle_path = "$root_out_dir/$bundle_name" + snapshot_path = "$target_gen_dir/${target_name}_snapshot.bin" + depfile_path = "${snapshot_path}.d" + + main_dart = invoker.main_dart + + if (defined(invoker.packages)) { + packages_path = invoker.packages + } else { + main_dir = get_path_info(main_dart, "dir") + package_dir = get_path_info(main_dir, "dir") + packages_path = "$package_dir/.packages" + } + + sky_snapshot_label = "//flutter/snapshotter($host_toolchain)" + sky_snapshot_dir = get_label_info(sky_snapshot_label, "root_out_dir") + sky_snapshot = "$sky_snapshot_dir/sky_snapshot" + + action(target_name) { + depfile = depfile_path + + inputs = [ + main_dart, + packages_path, + ] + + outputs = [ + bundle_path, + snapshot_path, + ] + + if (defined(invoker.sources)) { + sources = invoker.sources + } + + script = "//flutter/build/package.py" + + args = [ + "--snapshotter", rebase_path(sky_snapshot), + "--main-dart", rebase_path(main_dart), + "--packages", rebase_path(packages_path), + "--bundle", rebase_path(bundle_path), + "--bundle-header", "#!mojo mojo:flutter_content_handler", + "--snapshot", rebase_path(snapshot_path), + "--depfile", rebase_path(depfile_path), + "--build-output", rebase_path(bundle_path, root_build_dir), + ] + + deps = [ + sky_snapshot_label, + ] + + if (defined(invoker.deps)) { + deps += invoker.deps + } + } +} diff --git a/build/package.py b/build/package.py new file mode 100755 index 00000000000..b6635ba3630 --- /dev/null +++ b/build/package.py @@ -0,0 +1,60 @@ +#!/usr/bin/env python +# 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 argparse +import subprocess +import os +import StringIO +import sys +import zipfile + + +def main(): + parser = argparse.ArgumentParser(description='Package a Flutter application') + + parser.add_argument('--snapshotter', type=str, required=True, + help='The snapshot binary to use') + parser.add_argument('--main-dart', type=str, required=True, + help='The main.dart file to use') + parser.add_argument('--packages', type=str, required=True, + help='The package map to use') + parser.add_argument('--snapshot', type=str, required=True, + help='Path to application snapshot') + parser.add_argument('--depfile', type=str, required=True, + help='Where to output dependency information') + parser.add_argument('--build-output', type=str, required=True, + help='The final target to use in the dependency information') + parser.add_argument('--bundle', type=str, required=True, + help='Where to output application bundle') + parser.add_argument('--bundle-header', type=str, required=True, + help='String to prepend to bundle') + + args = parser.parse_args() + + result = subprocess.call([ + args.snapshotter, + '--packages=%s' % args.packages, + '--snapshot=%s' % args.snapshot, + '--depfile=%s' % args.depfile, + '--build-output=%s' % args.build_output, + args.main_dart, + ]) + + if result != 0: + return result + + archive = StringIO.StringIO() + with zipfile.ZipFile(archive, 'w') as z: + z.write(args.snapshot, 'snapshot_blob.bin', zipfile.ZIP_DEFLATED) + + with open(args.bundle, 'w') as f: + if args.bundle_header: + f.write(args.bundle_header) + f.write('\n') + f.write(archive.getvalue()) + + +if __name__ == '__main__': + sys.exit(main()) diff --git a/examples/BUILD.gn b/examples/BUILD.gn new file mode 100644 index 00000000000..81b122feef2 --- /dev/null +++ b/examples/BUILD.gn @@ -0,0 +1,9 @@ +# 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. + +group("examples") { + deps = [ + "spinning_square" + ] +} diff --git a/examples/spinning_square/.packages b/examples/spinning_square/.packages new file mode 100644 index 00000000000..14423b3a80b --- /dev/null +++ b/examples/spinning_square/.packages @@ -0,0 +1 @@ +# spinning_square doesn't depend on any packages. diff --git a/examples/spinning_square/BUILD.gn b/examples/spinning_square/BUILD.gn new file mode 100644 index 00000000000..2bd87c3a025 --- /dev/null +++ b/examples/spinning_square/BUILD.gn @@ -0,0 +1,9 @@ +# 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("//flutter/build/flx.gni") + +flx("spinning_square") { + main_dart = "lib/main.dart" +} diff --git a/examples/spinning_square/lib/main.dart b/examples/spinning_square/lib/main.dart new file mode 100644 index 00000000000..24b3e737173 --- /dev/null +++ b/examples/spinning_square/lib/main.dart @@ -0,0 +1,59 @@ +// Copyright 2015 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. + +// This example shows how to perform a simple animation using the raw interface +// to the engine. + +import 'dart:math' as math; +import 'dart:typed_data'; +import 'dart:ui' as ui; + +void beginFrame(Duration timeStamp) { + // The timeStamp argument to beginFrame indicates the timing information we + // should use to clock our animations. It's important to use timeStamp rather + // than reading the system time because we want all the parts of the system to + // coordinate the timings of their animations. If each component read the + // system clock independently, the animations that we processed later would be + // slightly ahead of the animations we processed earlier. + + // PAINT + + ui.Rect paintBounds = ui.Point.origin & ui.window.size; + ui.PictureRecorder recorder = new ui.PictureRecorder(); + ui.Canvas canvas = new ui.Canvas(recorder, paintBounds); + canvas.translate(paintBounds.width / 2.0, paintBounds.height / 2.0); + + // Here we determine the rotation according to the timeStamp given to us by + // the engine. + double t = timeStamp.inMicroseconds / Duration.MICROSECONDS_PER_MILLISECOND / 1800.0; + canvas.rotate(math.PI * (t % 1.0)); + + canvas.drawRect(new ui.Rect.fromLTRB(-100.0, -100.0, 100.0, 100.0), + new ui.Paint()..color = const ui.Color.fromARGB(255, 0, 255, 0)); + ui.Picture picture = recorder.endRecording(); + + // COMPOSITE + + final double devicePixelRatio = ui.window.devicePixelRatio; + Float64List deviceTransform = new Float64List(16) + ..[0] = devicePixelRatio + ..[5] = devicePixelRatio + ..[10] = 1.0 + ..[15] = 1.0; + ui.SceneBuilder sceneBuilder = new ui.SceneBuilder() + ..pushTransform(deviceTransform) + ..addPicture(ui.Offset.zero, picture) + ..pop(); + ui.window.render(sceneBuilder.build()); + + // After rendering the current frame of the animation, we ask the engine to + // schedule another frame. The engine will call beginFrame again when its time + // to produce the next frame. + ui.window.scheduleFrame(); +} + +void main() { + ui.window.onBeginFrame = beginFrame; + ui.window.scheduleFrame(); +}