├── .gitignore ├── COPYING ├── README.md ├── irhydra ├── .analysis_options ├── build.dart ├── lib │ └── src │ │ ├── formatting.dart │ │ ├── modes │ │ ├── art │ │ │ ├── art.dart │ │ │ └── cfg_parser.dart │ │ ├── code.dart │ │ ├── dartvm │ │ │ ├── code_parser.dart │ │ │ ├── dartvm.dart │ │ │ ├── ir_parser.dart │ │ │ ├── name_parser.dart │ │ │ └── preparser.dart │ │ ├── ir.dart │ │ ├── mode.dart │ │ ├── perf.dart │ │ └── v8 │ │ │ ├── code_parser.dart │ │ │ ├── hydrogen_parser.dart │ │ │ ├── name_parser.dart │ │ │ ├── source_annotator.dart │ │ │ ├── ui │ │ │ ├── dependent-code-deopt-reasons.html │ │ │ ├── descriptions.dart │ │ │ └── descriptions.html │ │ │ └── v8.dart │ │ ├── spinner.dart │ │ └── ui │ │ ├── _ui.scss │ │ ├── compilation-timeline.dart │ │ ├── compilation-timeline.html │ │ ├── deopt-links.dart │ │ ├── deopt-links.html │ │ ├── dropdown-element.dart │ │ ├── dropdown-element.html │ │ ├── dropdown-element.scss │ │ ├── hydra.dart │ │ ├── hydra.html │ │ ├── hydra.scss │ │ ├── ir-pane.css │ │ ├── ir-pane.dart │ │ ├── ir-pane.html │ │ ├── method-list.dart │ │ ├── method-list.html │ │ ├── method-list.scss │ │ ├── method-name.dart │ │ ├── method-name.html │ │ ├── method-name.scss │ │ ├── open-file-button.dart │ │ ├── open-file-button.html │ │ ├── open-file-button.scss │ │ ├── prettify.css │ │ ├── prettify.js │ │ ├── source-pane.dart │ │ ├── source-pane.html │ │ ├── source-path.dart │ │ ├── source-path.html │ │ ├── source-path.scss │ │ ├── spinner-element.dart │ │ ├── spinner-element.html │ │ └── util │ │ ├── code-mirror │ │ ├── code-mirror.dart │ │ ├── code-mirror.html │ │ └── deps │ │ │ ├── codemirror.css │ │ │ ├── codemirror.js │ │ │ └── modes │ │ │ └── javascript.js │ │ ├── switching-scope.dart │ │ └── switching-scope.html ├── pubspec.lock ├── pubspec.yaml └── web │ ├── css │ └── hydra.css │ ├── demos │ ├── dart │ │ ├── code.asm │ │ └── demo.dart │ ├── v8 │ │ ├── deopt-eager │ │ │ ├── code.asm │ │ │ ├── demo.js │ │ │ └── hydrogen.cfg │ │ ├── deopt-lazy │ │ │ ├── code.asm │ │ │ ├── demo.js │ │ │ └── hydrogen.cfg │ │ └── deopt-soft │ │ │ ├── code.asm │ │ │ ├── demo.js │ │ │ └── hydrogen.cfg │ └── webrebels2014 │ │ ├── 1-concat │ │ ├── concat.js │ │ └── data.tar.bz2 │ │ ├── 2-concat-fixed │ │ ├── concat.js │ │ └── data.tar.bz2 │ │ ├── 3-prototype-node │ │ ├── data.tar.bz2 │ │ └── prototype.js │ │ ├── 4-prototype-node-getter │ │ ├── data.tar.bz2 │ │ └── prototype.js │ │ ├── 5-prototype │ │ ├── data.tar.bz2 │ │ └── prototype.js │ │ ├── 6-prototype-tostring │ │ ├── data.tar.bz2 │ │ └── prototype.js │ │ ├── 7-method-function │ │ ├── data.tar.bz2 │ │ └── method-function.js │ │ ├── 8-method-function-hack │ │ ├── data.tar.bz2 │ │ └── method-function.js │ │ ├── README.md │ │ ├── benchmark.js │ │ ├── jsperf.js │ │ └── lodash.js │ ├── deps │ ├── bunzip2.js │ ├── esprima.js │ ├── estraverse.js │ ├── fa │ │ ├── css │ │ │ └── font-awesome.min.css │ │ └── fonts │ │ │ ├── fontawesome-webfont.eot │ │ │ ├── fontawesome-webfont.svg │ │ │ ├── fontawesome-webfont.ttf │ │ │ └── fontawesome-webfont.woff │ └── spin.min.js │ ├── favicon.ico │ └── index.html ├── saga ├── .gitignore ├── lib │ └── src │ │ ├── flow │ │ ├── compact_likely.dart │ │ ├── cpu_register.dart │ │ ├── dce.dart │ │ ├── flow.dart │ │ ├── fold.dart │ │ ├── fuse_branches.dart │ │ ├── interference.dart │ │ ├── liveness.dart │ │ ├── loads.dart │ │ ├── locals.dart │ │ ├── node.dart │ │ ├── ssa.dart │ │ └── types.dart │ │ ├── parser.dart │ │ ├── ui │ │ ├── code_pane.dart │ │ ├── graph_pane.dart │ │ ├── ir_pane.dart │ │ └── tooltip.dart │ │ └── util.dart ├── pubspec.yaml └── web │ ├── code.asm │ ├── index.html │ ├── main.dart │ ├── post.dart │ └── styles.css ├── ui_components ├── .gitignore ├── lib │ └── components │ │ ├── graph-pane.dart │ │ └── graph-pane.html └── pubspec.yaml └── ui_utils ├── .analysis_options ├── .gitignore ├── lib ├── assets │ ├── bootstrap │ │ ├── css │ │ │ ├── bootstrap-theme.css │ │ │ ├── bootstrap-theme.min.css │ │ │ ├── bootstrap.css │ │ │ └── bootstrap.min.css │ │ ├── fonts │ │ │ ├── glyphicons-halflings-regular.eot │ │ │ ├── glyphicons-halflings-regular.svg │ │ │ ├── glyphicons-halflings-regular.ttf │ │ │ └── glyphicons-halflings-regular.woff │ │ └── js │ │ │ ├── bootstrap.js │ │ │ └── bootstrap.min.js │ ├── jquery │ │ ├── css │ │ │ └── ui-lightness │ │ │ │ ├── images │ │ │ │ ├── animated-overlay.gif │ │ │ │ ├── ui-bg_diagonals-thick_18_b81900_40x40.png │ │ │ │ ├── ui-bg_diagonals-thick_20_666666_40x40.png │ │ │ │ ├── ui-bg_flat_10_000000_40x100.png │ │ │ │ ├── ui-bg_glass_100_f6f6f6_1x400.png │ │ │ │ ├── ui-bg_glass_100_fdf5ce_1x400.png │ │ │ │ ├── ui-bg_glass_65_ffffff_1x400.png │ │ │ │ ├── ui-bg_gloss-wave_35_f6a828_500x100.png │ │ │ │ ├── ui-bg_highlight-soft_100_eeeeee_1x100.png │ │ │ │ ├── ui-bg_highlight-soft_75_ffe45c_1x100.png │ │ │ │ ├── ui-icons_222222_256x240.png │ │ │ │ ├── ui-icons_228ef1_256x240.png │ │ │ │ ├── ui-icons_ef8c08_256x240.png │ │ │ │ ├── ui-icons_ffd27a_256x240.png │ │ │ │ └── ui-icons_ffffff_256x240.png │ │ │ │ ├── jquery-ui-1.10.4.css │ │ │ │ └── jquery-ui-1.10.4.min.css │ │ └── js │ │ │ ├── jquery-2.0.3.js │ │ │ ├── jquery-ui-1.10.4.js │ │ │ └── jquery-ui-1.10.4.min.js │ ├── tooltip.css │ └── xref.css ├── bootstrap.dart ├── brewer.dart ├── delayed_reaction.dart ├── graph.dart ├── graph_layout.dart ├── havlak.dart ├── html_utils.dart ├── parsing.dart ├── src │ └── draw2d │ │ ├── BreakCycles.dart │ │ ├── CollapsedEdges.dart │ │ ├── CompoundBreakCycles.dart │ │ ├── CompoundDirectedGraph.dart │ │ ├── CompoundDirectedGraphLayout.dart │ │ ├── CompoundHorizontalPlacement.dart │ │ ├── CompoundPopulateRanks.dart │ │ ├── CompoundRankSolver.dart │ │ ├── CompoundTransposeMetrics.dart │ │ ├── CompoundVerticalPlacement.dart │ │ ├── ConvertCompoundGraph.dart │ │ ├── Dimension.dart │ │ ├── DirectedGraph.dart │ │ ├── DirectedGraphLayout.dart │ │ ├── Edge.dart │ │ ├── EdgeList.dart │ │ ├── Geometry.dart │ │ ├── GraphUtilities.dart │ │ ├── GraphVisitor.dart │ │ ├── HorizontalPlacement.dart │ │ ├── InitialRankSolver.dart │ │ ├── Insets.dart │ │ ├── InvertEdges.dart │ │ ├── LocalOptimizer.dart │ │ ├── MinCross.dart │ │ ├── NestingTree.dart │ │ ├── Node.dart │ │ ├── NodeCluster.dart │ │ ├── NodeList.dart │ │ ├── NodePair.dart │ │ ├── Obstacle.dart │ │ ├── Path.dart │ │ ├── Point.dart │ │ ├── PointList.dart │ │ ├── PopulateRanks.dart │ │ ├── PositionConstants.dart │ │ ├── README │ │ ├── Rank.dart │ │ ├── RankAssignmentSolver.dart │ │ ├── RankList.dart │ │ ├── RankSorter.dart │ │ ├── Rectangle.dart │ │ ├── RevertableChange.dart │ │ ├── RouteEdges.dart │ │ ├── Segment.dart │ │ ├── ShortestPathRouter.dart │ │ ├── SortSubgraphs.dart │ │ ├── SpanningTreeVisitor.dart │ │ ├── Subgraph.dart │ │ ├── SubgraphBoundary.dart │ │ ├── TightSpanningTreeSolver.dart │ │ ├── Transform.dart │ │ ├── TransposeMetrics.dart │ │ ├── Vertex.dart │ │ ├── VerticalPlacement.dart │ │ ├── VirtualNodeCreation.dart │ │ └── graph.dart ├── task.dart ├── tooltip.dart └── xref.dart └── pubspec.yaml /.gitignore: -------------------------------------------------------------------------------- 1 | packages 2 | build/ 3 | .project 4 | *.iml 5 | *.ipr 6 | *.iws 7 | .idea/ 8 | *.dart.js 9 | *.js_ 10 | *.js.deps 11 | *.js.map 12 | .DS_Store 13 | .buildlog 14 | web/out 15 | web/precompiled.js 16 | deploy/ 17 | irhydra.sublime-project 18 | irhydra.sublime-workspace 19 | build.sh 20 | serve.sh 21 | web/deps/jquery-ui-*/ 22 | web/demos/webrebels/ 23 | .pub 24 | 25 | saga/web/code1.asm 26 | 27 | saga/web/code2.asm 28 | 29 | saga/web/code3.asm 30 | 31 | saga/web/code4.asm 32 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | IRHydra is an in-browser tool that can display V8 and Dart VM compilation 2 | artifacts (namely intermediate representations and native code) dumped during 3 | optimization. 4 | 5 | ## Features 6 | 7 | See [this](http://mrale.ph/blog/2013/02/17/release-the-irhydra.html) and [this](http://mrale.ph/blog/2014/01/28/prerelease-irhydra2.html) posts for description of the most important features. 8 | 9 | ## Hosted versions 10 | 11 | [IRHydra](http://mrale.ph/irhydra/1/) 12 | 13 | [IRHydra2](http://mrale.ph/irhydra/2/), requires V8 ≥ 3.24.39. 14 | 15 | ## Running Locally 16 | 17 | IRHydra is written in [Dart](http://dartlang.org) the easiest way to run it is to [download](https://www.dartlang.org/tools/download.html) full Dart bundle and use Dart Editor. 18 | 19 | Detailed information about Dart development can be found in the [Dart: Up and Running](https://www.dartlang.org/docs/dart-up-and-running/). 20 | 21 | ### Prerequisites 22 | 23 | * [Dart SDK](https://www.dartlang.org/tools/download.html) 24 | * [Sass](http://sass-lang.com/) 25 | 26 | ### Dart Editor Workflow 27 | 28 | Launch Editor, open IRHydra folder via `File > Open Existing Folder`, right click `web/index.html` and select `Run in Dartium`. 29 | 30 | ### Dartium Workflow 31 | 32 | Requires Dart SDK and Dartium. 33 | 34 | $ cd irhydra 35 | # Get all dependencies 36 | $ pub get 37 | # Serve root 38 | $ pub serve 39 | $ DART_FLAGS="--checked" dart/chromium/chrome --enable-experimental-webkit-features --enable-devtools-experiments http://localhost:8000/web/index.html 40 | 41 | ### JavaScript Workflow 42 | 43 | Requires Dart SDK. 44 | 45 | $ cd irhydra 46 | # Get all dependencies 47 | $ pub get 48 | # Serve dart2js compiled IRHydra at http://localhost:8080/ 49 | # It will be recompiled when needed. 50 | $ pub serve 51 | 52 | or 53 | 54 | # Build IRHydra for deployment. Result is in build/ 55 | $ pub build 56 | -------------------------------------------------------------------------------- /irhydra/.analysis_options: -------------------------------------------------------------------------------- 1 | analyzer: 2 | strong-mode: true 3 | -------------------------------------------------------------------------------- /irhydra/build.dart: -------------------------------------------------------------------------------- 1 | // Copyright 2015 Google Inc. All Rights Reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | // This file is only used by Dart Editor. It displays errors and warnings after 16 | // analyzing a polymer.dart app. 17 | 18 | export 'package:polymer/default_build.dart'; 19 | -------------------------------------------------------------------------------- /irhydra/lib/src/formatting.dart: -------------------------------------------------------------------------------- 1 | // Copyright 2013 Google Inc. All Rights Reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | /** 16 | * Turn text into HTML elements by applying formatting rules to regular 17 | * expression matches. 18 | */ 19 | library formatting; 20 | 21 | import 'dart:html'; 22 | import 'package:ui_utils/parsing.dart' as parsing; 23 | 24 | /** Formatting function that turns text into HTML element based on some rules */ 25 | typedef Element Formatter(String text); 26 | 27 | /** 28 | * Make a formatter for the given [map] of rules. 29 | * 30 | * Each rule is a pair of regular expression and an associated formatter that 31 | * will be applied to regular expression's match. Regular expression will not 32 | * be tried for a match in the middle of the word. 33 | * 34 | * Parts of text that do not match any rule will be wrapped into [Text]. 35 | */ 36 | makeFormatter(Map map) { 37 | final actions = map.values.toList(); 38 | final patterns = map.keys.map((re) => new RegExp("^${re}")).toList(); 39 | 40 | final split = parsing.makeSplitter(map, other: (val) => new Text(val)); 41 | 42 | return (text) => 43 | new SpanElement()..nodes.addAll(split(text)); 44 | } 45 | 46 | -------------------------------------------------------------------------------- /irhydra/lib/src/modes/art/art.dart: -------------------------------------------------------------------------------- 1 | // Copyright 2015 Google Inc. All Rights Reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | /** Mode for parsing ART's art.cfg */ 16 | library modes.art; 17 | 18 | import 'dart:html' as html; 19 | 20 | import 'package:irhydra/src/modes/ir.dart' as ir; 21 | import 'package:irhydra/src/modes/code.dart' show Code; 22 | import 'package:irhydra/src/modes/mode.dart'; 23 | import 'package:irhydra/src/modes/art/cfg_parser.dart' as cfg_parser; 24 | 25 | class _ARTHIRDescriptor extends HIRDescriptor { 26 | const _ARTHIRDescriptor() : super(); 27 | 28 | codeOf(instr, {skipComment: false}) => instr.code; 29 | } 30 | 31 | /** 32 | * Mode for viewing of ART's compilation artifacts. 33 | * 34 | * Data arrives in the form of a single C1Visualizer CFG file. 35 | * 36 | */ 37 | class Mode extends BaseMode { 38 | final irs = const [const _ARTHIRDescriptor()]; 39 | 40 | load(text) { 41 | if (cfg_parser.canRecognize(text)) { 42 | methods = cfg_parser.preparse(text); 43 | return true; 44 | } else { 45 | return false; 46 | } 47 | } 48 | 49 | toIr(method, phase, statusObject) { 50 | final blocks = cfg_parser.parse(method, phase.ir, statusObject); 51 | final code = hasCode(blocks) ? new Code.empty() : null; 52 | return new ir.ParsedIr(method, this, blocks, code, method.deopts); 53 | } 54 | 55 | static bool hasCode(blocks) { 56 | for (var block in blocks.values) { 57 | for (var instr in block.hir) { 58 | if (instr.code != null && !instr.code.isEmpty) { 59 | return true; 60 | } 61 | } 62 | } 63 | return false; 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /irhydra/lib/src/modes/dartvm/dartvm.dart: -------------------------------------------------------------------------------- 1 | // Copyright 2013 Google Inc. All Rights Reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | /** Dart VM mode */ 16 | library modes.dartvm; 17 | 18 | import 'package:irhydra/src/modes/dartvm/code_parser.dart' as code_parser; 19 | import 'package:irhydra/src/modes/dartvm/ir_parser.dart' as ir_parser; 20 | import 'package:irhydra/src/modes/dartvm/preparser.dart' as preparser; 21 | import 'package:irhydra/src/modes/ir.dart' as ir; 22 | import 'package:irhydra/src/modes/code.dart' show CodeCollector, Comment, Jump; 23 | import 'package:irhydra/src/modes/mode.dart'; 24 | 25 | class _Descriptions { 26 | lookup(ns, value) => null; 27 | } 28 | 29 | class Mode extends BaseMode { 30 | final irs = const [const HIRDescriptor()]; 31 | 32 | load(String str) { 33 | if (!preparser.canRecognize(str)) { 34 | return false; 35 | } 36 | 37 | methods = preparser.parse(str); 38 | return true; 39 | } 40 | 41 | final descriptions = new _Descriptions(); 42 | 43 | toIr(method, phase, statusObject) { 44 | final blocks = ir_parser.parse(phase.ir); 45 | final code = code_parser.parse(phase.code); 46 | _attachCode(blocks, code); 47 | 48 | 49 | if (method.deopts.isNotEmpty) { 50 | final jumps = new Map(); 51 | 52 | for (var block in blocks.values) { 53 | for (var hirOp in block.hir) { 54 | if (hirOp.code == null) continue; 55 | for (var asmOp in hirOp.code) { 56 | if (asmOp is Jump) { 57 | jumps[asmOp.target] = hirOp; 58 | } 59 | } 60 | } 61 | } 62 | 63 | 64 | final deopts = new Map.fromIterable(method.deopts, key: (deopt) => int.parse(deopt.id, radix: 16), value: (deopt) => deopt); 65 | 66 | var previous = null; 67 | code.epilogue.forEach((instr) { 68 | if (instr is Comment) return; 69 | 70 | final deopt = deopts[instr.offset + code.start]; 71 | if (deopt != null) { 72 | deopt.hir = jumps[previous.offset]; 73 | } 74 | previous = instr; 75 | }); 76 | } 77 | 78 | return new ir.ParsedIr(method, this, blocks, code, method.deopts); 79 | } 80 | 81 | lastOffset(code) => code_parser.lastOffset(code()); 82 | 83 | _attachCode(blocks, code) { 84 | for (var block in blocks.values) { 85 | final codeCollector = new CodeCollector(code.codeOf(block.name)); 86 | 87 | var previous = block.hir.first; 88 | assert(previous.op == null); 89 | for (var instr in block.hir.skip(1)) { 90 | // TODO(mraleph) previously we used deoptid to improve matching quality. 91 | final marker = instr.id != null ? "${instr.id} <- ${instr.op}" 92 | : "${instr.op}"; 93 | codeCollector.collectUntil(marker); 94 | 95 | if (!codeCollector.isEmpty) { 96 | if (previous.code == null) previous.code = []; 97 | previous.code.addAll(codeCollector.collected); 98 | } 99 | 100 | previous = instr; 101 | } 102 | 103 | codeCollector.collectRest(); 104 | 105 | if (!codeCollector.isEmpty) { 106 | if (previous.code == null) previous.code = []; 107 | previous.code.addAll(codeCollector.collected); 108 | } 109 | } 110 | } 111 | } -------------------------------------------------------------------------------- /irhydra/lib/src/modes/mode.dart: -------------------------------------------------------------------------------- 1 | // Copyright 2013 Google Inc. All Rights Reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | /** Base mode related functionality */ 16 | library mode; 17 | 18 | import 'package:irhydra/src/modes/ir.dart' as IR; 19 | 20 | abstract class IRDescriptor { 21 | /** Namespace corresponding to this IR. */ 22 | final String ns; 23 | 24 | const IRDescriptor(this.ns); 25 | 26 | /** Fetch IR corresponding to this descriptor from the [block]. */ 27 | Iterable from(IR.Block block); 28 | 29 | codeOf(instr, {skipComment: false}) => instr.code.skip(skipComment ? 1 : 0); 30 | } 31 | 32 | 33 | class Descriptions { 34 | const Descriptions(); 35 | 36 | lookup(ns, value) => null; 37 | } 38 | 39 | 40 | /** 41 | * Modes encapsulate the way to parse compilation artifacts. 42 | */ 43 | abstract class BaseMode { 44 | get irs; 45 | 46 | final descriptions = const Descriptions(); 47 | 48 | /** Currently loaded methods. */ 49 | var methods; 50 | 51 | var timeline; 52 | 53 | /** Parses textual artifact into the list of [IR.Method] */ 54 | bool load(String text); 55 | } 56 | 57 | class HIRDescriptor extends IRDescriptor { 58 | const HIRDescriptor() : super("hir"); 59 | 60 | from(block) => block.hir; 61 | } 62 | 63 | class LIRDescriptor extends IRDescriptor { 64 | const LIRDescriptor() : super("lir"); 65 | 66 | from(block) => block.lir; 67 | } 68 | -------------------------------------------------------------------------------- /irhydra/lib/src/modes/v8/name_parser.dart: -------------------------------------------------------------------------------- 1 | // Copyright 2013 Google Inc. All Rights Reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | library modes.v8.name_parser; 16 | 17 | import 'package:irhydra/src/modes/ir.dart' show Name; 18 | 19 | Name parse(String text) { 20 | if (text.indexOf(r"$") < 0) { 21 | return new Name.fromFull(text); 22 | } 23 | 24 | if (text.length > 1 && 25 | text.startsWith(r"$") && 26 | text.endsWith(r"$")) { 27 | text = text.substring(1, text.length - 1); 28 | } 29 | 30 | final lastIdx = text.lastIndexOf(r"$"); 31 | if (lastIdx == 0 || lastIdx == text.length - 1) { 32 | return new Name.fromFull(text); 33 | } 34 | 35 | final source = text.substring(0, lastIdx - ((text[lastIdx - 1] == r"$") ? 1 : 0)); 36 | final short = text.substring(lastIdx + 1); 37 | 38 | return new Name(text, source.replaceAll(r"$", "."), short); 39 | } 40 | -------------------------------------------------------------------------------- /irhydra/lib/src/modes/v8/ui/dependent-code-deopt-reasons.html: -------------------------------------------------------------------------------- 1 | 2 | 47 | -------------------------------------------------------------------------------- /irhydra/lib/src/modes/v8/ui/descriptions.dart: -------------------------------------------------------------------------------- 1 | // Copyright 2014 Google Inc. All Rights Reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | library descriptions; 16 | 17 | import 'package:polymer/polymer.dart'; 18 | 19 | /** 20 | * A list of HIR/LIR insruction descriptions. 21 | * 22 | * Described as a polymer element for the sole purpose of storing it 23 | * modularly. 24 | */ 25 | @CustomTag('ir-descriptions-v8') 26 | class Descriptions extends PolymerElement { 27 | var _hir, _lir; 28 | 29 | Descriptions.created() : super.created() { 30 | _hir = new Map.fromIterable( 31 | shadowRoot.querySelectorAll("[data-hir]"), 32 | key: (n) => n.attributes["data-hir"], 33 | value: (n) => n.innerHtml 34 | ); 35 | 36 | _lir = new Map.fromIterable( 37 | shadowRoot.querySelectorAll("[data-lir]"), 38 | key: (n) => n.attributes["data-lir"], 39 | value: (n) => n.innerHtml 40 | ); 41 | } 42 | 43 | lookup(ns, opcode) { 44 | switch (ns) { 45 | case "lir": return _lir[opcode]; 46 | case "hir": return _hir[opcode]; 47 | } 48 | return null; 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /irhydra/lib/src/spinner.dart: -------------------------------------------------------------------------------- 1 | // Copyright 2013 Google Inc. All Rights Reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | /** Simple wrapper around spin.js that creates spinner at navbar. */ 16 | library spinner; 17 | 18 | import "dart:html" as html; 19 | import "dart:js" as js; 20 | 21 | /** Current instance of spinner. */ 22 | js.JsObject _spinner; 23 | 24 | /** Start spinner. */ 25 | start() { 26 | stop(); // Ensure that spinner is stopped. 27 | 28 | final target = html.document.querySelector(".navbar-inner > .container"); 29 | final opts = new js.JsObject.jsify({ 30 | "lines": 13, // The number of lines to draw 31 | "length": 7, // The length of each line 32 | "width": 4, // The line thickness 33 | "radius": 8, // The radius of the inner circle 34 | "corners": 1, // Corner roundness (0..1) 35 | "rotate": 0, // The rotation offset 36 | "color": '#000', // #rgb or #rrggbb 37 | "speed": 1, // Rounds per second 38 | "trail": 60, // Afterglow percentage 39 | "shadow": false, // Whether to render a shadow 40 | "hwaccel": false, // Whether to use hardware acceleration 41 | "className": 'spinner', // The CSS class to assign to the spinner 42 | "zIndex": 2e9, // The z-index (defaults to 2000000000) 43 | "top": 'auto', // Top position relative to parent in px 44 | "left": 'auto' // Left position relative to parent in px 45 | }); 46 | _spinner = new js.JsObject(js.context['Spinner'], [opts]).callMethod('spin', [target]); 47 | } 48 | 49 | /** Stop spinner. */ 50 | stop() { 51 | if (_spinner != null) { 52 | _spinner.callMethod('stop'); 53 | _spinner = null; 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /irhydra/lib/src/ui/_ui.scss: -------------------------------------------------------------------------------- 1 | $toolbar-background: white; 2 | $toolbar-color: black; 3 | $toolbar-background-hover: rgba(#999, 0.2); 4 | 5 | $toolbar-border: 1px solid #e0e0e0; 6 | $toolbar-box-shadow: 0 2px 5px rgba(0, 0, 0, .26); 7 | 8 | $button-background: $toolbar-background; 9 | $button-color: $toolbar-color; 10 | $button-background-hover: $toolbar-background-hover; 11 | 12 | $tabs-header-color: black; 13 | $tabs-header-color-active: black; 14 | $tabs-header-color-hover: black; 15 | -------------------------------------------------------------------------------- /irhydra/lib/src/ui/compilation-timeline.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /irhydra/lib/src/ui/deopt-links.dart: -------------------------------------------------------------------------------- 1 | // Copyright 2014 Google Inc. All Rights Reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | library deopt_links; 16 | 17 | import 'package:polymer/polymer.dart'; 18 | 19 | /** 20 | * Primitive tabbed pane WebComponent. 21 | */ 22 | @CustomTag('deopt-links') 23 | class DeoptLinksElement extends PolymerElement { 24 | @published var deopts; 25 | @observable var deoptInfo; 26 | 27 | DeoptLinksElement.created() : super.created(); 28 | 29 | deoptsChanged() { 30 | deoptInfo = deopts.map((deopt) { 31 | var targetId = null; 32 | if (deopt.hir != null) { 33 | targetId = deopt.hir.id; 34 | } else if (deopt.lir != null) { 35 | targetId = deopt.lir.id; 36 | } 37 | 38 | return new _DeoptInfo(targetId, deopt.type); 39 | }).toList(); 40 | } 41 | 42 | jumpToDeoptAction(event, detail, target) { 43 | final index = int.parse(target.attributes["data-target"]); 44 | fire("deopt-click", detail: deopts[index]); 45 | } 46 | 47 | enterDeoptAction(event, detail, target) { 48 | final index = int.parse(target.attributes["data-target"]); 49 | fire("deopt-enter", detail: new _DeoptHoverDetail(deopts[index], target)); 50 | } 51 | 52 | leaveDeoptAction(event, detail, target) { 53 | final index = int.parse(target.attributes["data-target"]); 54 | fire("deopt-leave", detail: new _DeoptHoverDetail(deopts[index], target)); 55 | } 56 | } 57 | 58 | class _DeoptHoverDetail { 59 | final deopt; 60 | final target; 61 | _DeoptHoverDetail(this.deopt, this.target); 62 | } 63 | 64 | class _DeoptInfo { 65 | @observable final id; 66 | @observable final type; 67 | 68 | _DeoptInfo(this.id, this.type); 69 | } -------------------------------------------------------------------------------- /irhydra/lib/src/ui/deopt-links.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 78 | 79 | 80 | -------------------------------------------------------------------------------- /irhydra/lib/src/ui/dropdown-element.dart: -------------------------------------------------------------------------------- 1 | // Copyright 2014 Google Inc. All Rights Reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | library dropdown_element; 16 | 17 | import 'dart:html' as html; 18 | import 'dart:js' as js; 19 | import 'package:ui_utils/task.dart'; 20 | import 'package:polymer/polymer.dart'; 21 | 22 | @CustomTag('dropdown-element') 23 | class DropdownElement extends PolymerElement { 24 | @published var selected; 25 | @observable var valueText; 26 | 27 | var _texts; 28 | var renderTask; 29 | 30 | selectedChanged(from, to) => renderTask.schedule(); 31 | 32 | DropdownElement.created() : super.created() { 33 | renderTask = new Task(render, frozen: true, type: MICROTASK); 34 | } 35 | 36 | attached() { 37 | super.attached(); 38 | js.context['jQuery']['fn']['dropdown'].callMethod('install', [shadowRoot]); 39 | 40 | _texts = new Map.fromIterable( 41 | (shadowRoot.querySelector("content") as html.ContentElement) 42 | .getDistributedNodes() 43 | .where((node) => (node is html.Element && node.attributes.containsKey("data-value"))), 44 | key: (node) => node.attributes["data-value"], 45 | value: (node) => node.text 46 | ); 47 | 48 | renderTask.unfreeze(); 49 | } 50 | 51 | selectAction(event, detail, target) { 52 | final attrs = event.target.attributes; 53 | if (attrs.containsKey('data-value')) { 54 | selected = attrs['data-value']; 55 | } 56 | event.preventDefault(); 57 | } 58 | 59 | render() { 60 | valueText = _texts[selected]; 61 | } 62 | 63 | detached() { 64 | js.context['jQuery']['fn']['dropdown'].callMethod('remove', [shadowRoot]); 65 | super.detached(); 66 | } 67 | } -------------------------------------------------------------------------------- /irhydra/lib/src/ui/dropdown-element.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /irhydra/lib/src/ui/dropdown-element.scss: -------------------------------------------------------------------------------- 1 | @import 'ui'; 2 | 3 | .ui-dropdown { 4 | position: relative; 5 | display: inline-block; 6 | vertical-align: middle; 7 | } 8 | 9 | .ui-dropdown-options { 10 | display: none; 11 | } 12 | 13 | .open > .ui-dropdown-options { 14 | display: block; 15 | } 16 | 17 | .ui-dropdown-selected:active, 18 | .ui-dropdown-selected:focus { 19 | outline: 0; 20 | } 21 | 22 | .ui-dropdown-caret { 23 | display: inline-block; 24 | font-family: FontAwesome; 25 | font-style: normal; 26 | font-weight: normal; 27 | line-height: 1; 28 | -webkit-font-smoothing: antialiased; 29 | } 30 | 31 | .ui-dropdown-caret:before { 32 | content: "\f0d7"; 33 | } 34 | 35 | .ui-dropdown-options { 36 | position: absolute; 37 | top: 100%; 38 | left: 0; 39 | z-index: 1000; 40 | float: left; 41 | min-width: 160px; 42 | padding: 5px 0; 43 | margin: 2px 0 0; 44 | font-size: 14px; 45 | background-clip: padding-box; 46 | display: none; 47 | box-shadow: $toolbar-box-shadow; 48 | } -------------------------------------------------------------------------------- /irhydra/lib/src/ui/ir-pane.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /irhydra/lib/src/ui/method-list.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 45 | 46 | 47 | -------------------------------------------------------------------------------- /irhydra/lib/src/ui/method-list.scss: -------------------------------------------------------------------------------- 1 | @import 'ui'; 2 | 3 | :host { 4 | max-height: 100%; 5 | overflow: auto; 6 | } 7 | 8 | .method-list { 9 | display: -webkit-flex; 10 | display: flex; 11 | 12 | -webkit-flex-flow: column; 13 | flex-flow: column; 14 | 15 | -webkit-flex-direction: column; 16 | flex-direction: column; 17 | 18 | min-height: 0px; 19 | flex: 1 1; 20 | 21 | color: $toolbar-color; 22 | font-family: RobotoDraft; 23 | } 24 | 25 | .method-list-methods { 26 | flex: 1 1; 27 | -webkit-flex: 1 1 auto; 28 | overflow-y: auto; 29 | min-height: 0px; 30 | } 31 | 32 | .method-list-footer { 33 | min-height: 50px; 34 | height: 50px; 35 | max-height: 50px; 36 | padding-left: 5px; 37 | } 38 | 39 | .method-list-methods::-webkit-scrollbar { 40 | height: 8px; 41 | width: 8px; 42 | } 43 | 44 | .method-list-methods::-webkit-scrollbar-track, 45 | .method-list-methods::-webkit-scrollbar-corner { 46 | background: inherit; 47 | } 48 | 49 | .method-list-methods::-webkit-scrollbar-thumb { 50 | background: #BDC3C7; 51 | border-radius: 5px; 52 | } 53 | 54 | .nav { 55 | list-style: none; 56 | position: relative; 57 | display: block; 58 | padding-left: 0; 59 | margin-bottom: 0; 60 | } 61 | 62 | .nav > li > h3 { 63 | white-space: nowrap; 64 | } 65 | 66 | .phases { 67 | list-style: none; 68 | padding-left: 0; 69 | } 70 | 71 | .phases > li > a { 72 | text-decoration: none; 73 | color: inherit; 74 | display: block; 75 | padding: 2px 15px; 76 | } 77 | 78 | .phases > li.selected > a, 79 | .phases > li > a:hover, 80 | .phases > li > a:focus { 81 | text-decoration: none; 82 | background-color: $toolbar-background-hover; 83 | } 84 | 85 | .toggle { 86 | text-align: center; 87 | width: 40px; 88 | height: 40px; 89 | border: none; 90 | -webkit-appearance: none; 91 | -ms-appearance: none; 92 | -o-appearance: none; 93 | appearance: none; 94 | cursor: pointer; 95 | } 96 | 97 | .toggle:hover { 98 | background: $toolbar-background-hover; 99 | } 100 | 101 | .toggle:after { 102 | content: '\f071'; 103 | font-size: 16pt; 104 | font-family: FontAwesome; 105 | font-style: normal; 106 | font-weight: normal; 107 | line-height: 40px; 108 | -webkit-font-smoothing: antialiased; 109 | -moz-osx-font-smoothing: grayscale; 110 | } 111 | 112 | .toggle:checked:after { 113 | color: red; 114 | } 115 | -------------------------------------------------------------------------------- /irhydra/lib/src/ui/method-name.dart: -------------------------------------------------------------------------------- 1 | // Copyright 2014 Google Inc. All Rights Reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | library ui.method_name; 16 | 17 | import 'package:polymer/polymer.dart'; 18 | 19 | @CustomTag('method-name') 20 | class MethodName extends PolymerElement { 21 | @published var method; 22 | @published var demangle = true; 23 | @published var targetHref; 24 | 25 | MethodName.created() : super.created(); 26 | 27 | @ComputedProperty("demangle") 28 | get source => demangle ? method.name.source : null; 29 | 30 | @ComputedProperty("demangle") 31 | get name => demangle ? method.name.display : method.name.full; 32 | } -------------------------------------------------------------------------------- /irhydra/lib/src/ui/method-name.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /irhydra/lib/src/ui/method-name.scss: -------------------------------------------------------------------------------- 1 | @import 'ui'; 2 | 3 | h3 { 4 | padding-left: 5px; 5 | font-weight: 200; 6 | font-size: 1.2em; 7 | } 8 | 9 | a { 10 | display: block; 11 | text-decoration: none; 12 | color: inherit; 13 | } 14 | 15 | :host(.selected) a, 16 | a:hover, 17 | a:focus { 18 | text-decoration: none; 19 | background-color: $toolbar-background-hover; 20 | } 21 | 22 | .deopt-eager { 23 | color: #C0392B; 24 | font-weight: 500 !important; 25 | } 26 | 27 | .deopt-lazy { 28 | color: #F39C12; 29 | font-weight: 500 !important; 30 | } 31 | 32 | .deopt-debugger { 33 | color: #827717; 34 | font-weight: 500 !important; 35 | } 36 | 37 | .deopt-soft { 38 | color: #8E44AD; 39 | font-weight: 500 !important; 40 | } 41 | 42 | .source { 43 | font-size: 0.6em; 44 | font-weight: bold; 45 | /* background-color: #1ABC9C; */ 46 | padding: 2px; 47 | border-radius: 4px; 48 | border: 1px dashed #95A5A6; 49 | } -------------------------------------------------------------------------------- /irhydra/lib/src/ui/open-file-button.dart: -------------------------------------------------------------------------------- 1 | library open_file_button; 2 | 3 | import 'package:ui_utils/bootstrap.dart' as bs; 4 | import 'package:polymer/polymer.dart'; 5 | 6 | @CustomTag('open-file-button') 7 | class OpenFileButton extends PolymerElement { 8 | OpenFileButton.created() : super.created(); 9 | 10 | attached() { 11 | super.attached(); 12 | 13 | if (attributes['data-title'] != null) { 14 | final btn = shadowRoot.querySelector("button"); 15 | final tooltip = bs.tooltip(btn, { 16 | "title": attributes['data-title'], 17 | "placement": "bottom", 18 | "container": "body", 19 | "trigger": "manual", 20 | }); 21 | 22 | btn.onMouseEnter.listen((e) => tooltip.show()); 23 | btn.onMouseLeave.listen((e) => tooltip.hide()); 24 | } 25 | } 26 | 27 | clicked(e, detail, target) { 28 | $["file-input"].click(); 29 | target.blur(); 30 | } 31 | 32 | changed(e, detail, target) { 33 | fire("opened", detail: target.files); 34 | } 35 | } -------------------------------------------------------------------------------- /irhydra/lib/src/ui/open-file-button.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /irhydra/lib/src/ui/open-file-button.scss: -------------------------------------------------------------------------------- 1 | @import 'ui'; 2 | 3 | input[type=file] { 4 | visibility: hidden; 5 | width: 0px; 6 | height: 0px; 7 | margin: 0px; 8 | padding: 0px; 9 | } 10 | 11 | span.hidden { 12 | position: absolute; 13 | overflow: hidden; 14 | width: 0px; 15 | height: 0px; 16 | } 17 | 18 | button { 19 | background: $button-background; 20 | color: $button-color; 21 | font-size: 16pt; 22 | width: 40px; 23 | height: 40px; 24 | border: 0px; 25 | } 26 | 27 | button:hover { 28 | background: $button-background-hover; 29 | } -------------------------------------------------------------------------------- /irhydra/lib/src/ui/prettify.css: -------------------------------------------------------------------------------- 1 | .pln{color:#000}@media screen{.str{color:#080}.kwd{color:#008}.com{color:#800}.typ{color:#606}.lit{color:#066}.pun,.opn,.clo{color:#660}.tag{color:#008}.atn{color:#606}.atv{color:#080}.dec,.var{color:#606}.fun{color:red}}@media print,projection{.str{color:#060}.kwd{color:#006;font-weight:bold}.com{color:#600;font-style:italic}.typ{color:#404;font-weight:bold}.lit{color:#044}.pun,.opn,.clo{color:#440}.tag{color:#006;font-weight:bold}.atn{color:#404}.atv{color:#060}}pre.prettyprint{padding:2px;border:1px solid #888}ol.linenums{margin-top:0;margin-bottom:0}li.L0,li.L1,li.L2,li.L3,li.L5,li.L6,li.L7,li.L8{list-style-type:none}li.L1,li.L3,li.L5,li.L7,li.L9{background:#eee} -------------------------------------------------------------------------------- /irhydra/lib/src/ui/source-pane.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 88 | 89 | -------------------------------------------------------------------------------- /irhydra/lib/src/ui/source-path.dart: -------------------------------------------------------------------------------- 1 | // Copyright 2014 Google Inc. All Rights Reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | library source_path; 16 | 17 | import 'package:polymer/polymer.dart'; 18 | 19 | @CustomTag('source-path') 20 | class SourcePathElement extends PolymerElement { 21 | @published var path; 22 | @observable var isEmpty; 23 | 24 | SourcePathElement.created() : super.created(); 25 | 26 | switchAction(event, detail, target) { 27 | final index = int.parse(target.attributes["data-target"]); 28 | path.removeRange(index + 1, path.length); 29 | event.preventDefault(); 30 | } 31 | } -------------------------------------------------------------------------------- /irhydra/lib/src/ui/source-path.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 15 | 16 | -------------------------------------------------------------------------------- /irhydra/lib/src/ui/source-path.scss: -------------------------------------------------------------------------------- 1 | @import 'ui'; 2 | 3 | .source-path { 4 | color: $toolbar-color; 5 | background-color: $toolbar-background; 6 | font-family: 'RobotoDraft'; 7 | font-weight: bold; 8 | padding: 10px 8px; 9 | display: inline-block; 10 | vertical-align: middle; 11 | } 12 | 13 | .source-path a, 14 | .source-path a:hover, 15 | .source-path a:focus { 16 | text-decoration: none; 17 | outline: 0; 18 | } 19 | 20 | .source-path a { 21 | color: $toolbar-color; 22 | } 23 | 24 | .source-path a:hover { 25 | color: #2a6496; 26 | } 27 | 28 | .fa { 29 | display: inline-block; 30 | font-family: FontAwesome; 31 | font-style: normal; 32 | font-weight: normal; 33 | line-height: 1; 34 | -webkit-font-smoothing: antialiased; 35 | -moz-osx-font-smoothing: grayscale; 36 | } 37 | 38 | .fa-angle-double-right:before{ 39 | content:"\f101" 40 | } 41 | -------------------------------------------------------------------------------- /irhydra/lib/src/ui/spinner-element.dart: -------------------------------------------------------------------------------- 1 | // Copyright 2014 Google Inc. All Rights Reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | library spinner_element; 16 | 17 | import 'dart:js' as js; 18 | import 'package:polymer/polymer.dart'; 19 | 20 | /** 21 | * Primitive tabbed pane WebComponent. 22 | */ 23 | @CustomTag('spinner-element') 24 | class SpinnerElement extends PolymerElement { 25 | js.JsObject _spinner; 26 | 27 | SpinnerElement.created() : super.created(); 28 | 29 | /** Start spinner. */ 30 | start() { 31 | stop(); // Ensure that spinner is stopped. 32 | 33 | final opts = new js.JsObject.jsify({ 34 | "lines": 13, // The number of lines to draw 35 | "length": 7, // The length of each line 36 | "width": 4, // The line thickness 37 | "radius": 8, // The radius of the inner circle 38 | "corners": 1, // Corner roundness (0..1) 39 | "rotate": 0, // The rotation offset 40 | "color": '#fff', // #rgb or #rrggbb 41 | "speed": 1, // Rounds per second 42 | "trail": 60, // Afterglow percentage 43 | "shadow": false, // Whether to render a shadow 44 | "hwaccel": false, // Whether to use hardware acceleration 45 | "className": 'spinner', // The CSS class to assign to the spinner 46 | "zIndex": 2e9, // The z-index (defaults to 2000000000) 47 | "top": '0px', // Top position relative to parent in px 48 | "left": '0px' // Left position relative to parent in px 49 | }); 50 | _spinner = new js.JsObject(js.context['Spinner'], [opts]).callMethod('spin', [this]); 51 | } 52 | 53 | /** Stop spinner. */ 54 | stop() { 55 | if (_spinner != null) { 56 | _spinner.callMethod('stop'); 57 | _spinner = null; 58 | } 59 | } 60 | } -------------------------------------------------------------------------------- /irhydra/lib/src/ui/spinner-element.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /irhydra/lib/src/ui/util/code-mirror/code-mirror.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /irhydra/lib/src/ui/util/switching-scope.dart: -------------------------------------------------------------------------------- 1 | // Copyright 2014 Google Inc. All Rights Reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | library ui.util.switching_scope; 16 | 17 | import 'dart:html'; 18 | import 'package:ui_utils/task.dart'; 19 | import 'package:polymer/polymer.dart'; 20 | 21 | /** 22 | * A component that applies `active` class to any distributed child that 23 | * has `when-x` attribute where `x` matches current [active] value. 24 | */ 25 | @CustomTag('switching-scope') 26 | class SwitchingScope extends PolymerElement { 27 | @published var active; 28 | 29 | var renderTask; 30 | 31 | SwitchingScope.created() : super.created() { 32 | renderTask = new Task(render, frozen: true, type: MICROTASK); 33 | } 34 | 35 | attached() { 36 | super.attached(); 37 | renderTask.unfreeze(); 38 | } 39 | 40 | activeChanged() => renderTask.schedule(); 41 | 42 | render() { 43 | for (var e in _query(".active")) { 44 | e.classes.remove("active"); 45 | } 46 | 47 | for (var e in _query("[when-$active]")) { 48 | e.classes.add("active"); 49 | } 50 | 51 | document.dispatchEvent(new CustomEvent("DisplayChanged")); 52 | } 53 | 54 | _query(sel) => (shadowRoot.querySelector("content") as ContentElement) 55 | .getDistributedNodes() 56 | .where((n) => n is Element && n.matches(sel)); 57 | } -------------------------------------------------------------------------------- /irhydra/lib/src/ui/util/switching-scope.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /irhydra/pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: irhydra 2 | dependencies: 3 | archive: any 4 | browser: any 5 | collection: any 6 | fixnum: any 7 | paper_elements: any 8 | polymer: any 9 | sass: any 10 | ui_utils: 11 | path: ../ui_utils 12 | ui_components: 13 | path: ../ui_components 14 | transformers: 15 | - sass 16 | - polymer: 17 | entry_points: web/index.html 18 | - $dart2js: 19 | checked: false 20 | minify: true 21 | commandLineOptions: ['--trust-type-annotations', '--trust-primitives'] 22 | -------------------------------------------------------------------------------- /irhydra/web/css/hydra.css: -------------------------------------------------------------------------------- 1 | .brand { 2 | font-family: 'Roboto'; 3 | } 4 | 5 | #ir-pane { 6 | background: white; 7 | } 8 | 9 | #graph-pane { 10 | margin-bottom: 500px; 11 | } 12 | 13 | .sidebar-nav { 14 | padding: 9px 0; 15 | } 16 | 17 | .popover.deopt { 18 | max-width: 500px !important; 19 | } 20 | 21 | .popover.deopt > .popover-content > pre { 22 | font-size: 0.7em; 23 | } 24 | 25 | .popover.deopt .deopt-marker { 26 | display: none; 27 | } 28 | 29 | h4.deopt-header:first-letter { 30 | text-transform: capitalize; 31 | } 32 | 33 | h4.deopt-header-eager > .first-word { 34 | color: #C0392B; 35 | } 36 | 37 | h4.deopt-header-lazy > .first-word { 38 | color: #F39C12; 39 | } 40 | 41 | h4.deopt-header-soft > .first-word { 42 | color: #8E44AD; 43 | } 44 | 45 | .welcome-message { 46 | font-family: 'RobotoDraft'; 47 | margin: 0 auto; 48 | width: 600px; 49 | font-size: 16px; 50 | padding: 5em 0; 51 | } 52 | 53 | .welcome-message h1, 54 | .welcome-message h2, 55 | .welcome-message h3 { 56 | font-family: 'Oswald'; 57 | } 58 | 59 | .alpha-warning { 60 | color: #E74C3C; 61 | } 62 | 63 | #welcome-splash { 64 | position: absolute; 65 | left: 0px; 66 | right: 0px; 67 | top: 40px; 68 | bottom: 0px; 69 | z-index: 1000; 70 | overflow: auto; 71 | } 72 | 73 | #splash-spinner { 74 | display: inline-block; 75 | position: absolute; 76 | width: 2em; 77 | height: 2em; 78 | left: -2em; 79 | right: 0px; 80 | top: -0.5em; 81 | } 82 | 83 | .welcome-message h1 { 84 | position: relative; 85 | } 86 | 87 | .welcome-message pre > span { 88 | cursor: help; 89 | } 90 | 91 | .welcome-message pre > span:hover { 92 | border-bottom: 1px dashed #ccc; 93 | } 94 | 95 | .welcome-message pre, .welcome-message code { 96 | font-size: inherit; 97 | color: inherit; 98 | background: inherit; 99 | } 100 | -------------------------------------------------------------------------------- /irhydra/web/demos/dart/demo.dart: -------------------------------------------------------------------------------- 1 | 2 | import 'dart:math'; 3 | 4 | class Vec2 { 5 | var x; 6 | var y; 7 | 8 | Vec2(this.x, this.y); 9 | 10 | get len2 => x * x + y * y; 11 | get len => sqrt(len2); 12 | } 13 | 14 | // We are going to deoptimize here when we call 15 | // loop the second time because class of 16 | // v2 does not match class of v. 17 | len(v) => v.len; 18 | 19 | loop(v) { 20 | var sum = 0.0; 21 | for (var i = 0; i < 10000; i++) sum += len(v); 22 | return sum; 23 | } 24 | 25 | class NamedVec2 extends Vec2 { 26 | final name; 27 | 28 | NamedVec2(this.name, x, y) : super(x, y); 29 | } 30 | 31 | main() { 32 | var v = new Vec2(0.1, 0.2); 33 | loop(v); 34 | 35 | var v2 = new NamedVec2("whatever", 0.1, 0.2); 36 | loop(v2); 37 | } -------------------------------------------------------------------------------- /irhydra/web/demos/v8/deopt-eager/demo.js: -------------------------------------------------------------------------------- 1 | function Vec2(x, y) { 2 | this._x = x; 3 | this._y = y; 4 | } 5 | 6 | Vec2.prototype = { 7 | get x () { return this._x; }, 8 | get y () { return this._y; }, 9 | 10 | len2: function () { 11 | return this.x * this.x + this.y * this.y; 12 | }, 13 | 14 | len: function () { 15 | return Math.sqrt(this.len2()); 16 | } 17 | } 18 | 19 | function len(v) { 20 | // We are going to deoptimize here when we call 21 | // loop the second time because hidden class of 22 | // v2 does not match hidden class of v. 23 | // We changed by adding a new property "name" to 24 | // the object allocated with Vec2. 25 | return v.len(); 26 | } 27 | 28 | function loop(v) { 29 | var sum = 0; 30 | for (var i = 0; i < 1e5; i++) sum += len(v); 31 | return sum; 32 | } 33 | 34 | var v = new Vec2(0.1, 0.2); 35 | loop(v); 36 | 37 | var v2 = new Vec2(0.1, 0.2); 38 | v2.name = "whatever"; 39 | loop(v2); -------------------------------------------------------------------------------- /irhydra/web/demos/v8/deopt-lazy/demo.js: -------------------------------------------------------------------------------- 1 | function K() { 2 | } 3 | 4 | K.prototype = { 5 | foo: function (i) { 6 | if (i === 2e4) { 7 | K.prototype.bar = function () { }; 8 | } else if (i > 1e6) { 9 | with (this) { } // To prevent inlining. 10 | } 11 | return 0; 12 | } 13 | } 14 | 15 | function loop1(v) { 16 | // In this loop function foo() changes prototype 17 | // of the object v in the middle of the loop 18 | // causing V8 to deoptimize loop1 lazily, 19 | // that is at the very moment when control returns 20 | // into loop1. 21 | // The reason for this is the global assumption that 22 | // prototypes are stable which allowed V8 to 23 | // omit prototype checks from the generated optimized 24 | // code. Instead this assumption is guarded at the 25 | // places where prototype can change shape and 26 | // generated code is invalidated. 27 | var sum = 0; 28 | for (var i = 0; i < 1e5; i++) sum += v.foo(i); 29 | return sum; 30 | } 31 | 32 | var v = new K(); 33 | loop1(v); 34 | 35 | function P() { 36 | this.v = 1.1; 37 | } 38 | 39 | function nullify(i, p) { 40 | if (i === 2e4) { 41 | p.v = null; 42 | } else if (i > 1e6) { 43 | with (p) { } // To prevent inlining. 44 | } 45 | } 46 | 47 | function loop2() { 48 | var p = new P(); 49 | var sum = 0; 50 | for (var i = 0; i < 1e5; i++) { 51 | nullify(i, p); 52 | sum += new P().v; 53 | } 54 | return sum; 55 | } 56 | 57 | loop2(); -------------------------------------------------------------------------------- /irhydra/web/demos/v8/deopt-soft/demo.js: -------------------------------------------------------------------------------- 1 | function Vec2(x, y) { 2 | this._x = x; 3 | this._y = y; 4 | } 5 | 6 | Vec2.prototype = { 7 | get x () { return this._x; }, 8 | get y () { return this._y; }, 9 | 10 | len2: function () { 11 | return this.x * this.x + this.y * this.y; 12 | }, 13 | 14 | len: function () { 15 | return Math.sqrt(this.len2()); 16 | } 17 | } 18 | 19 | var util = { 20 | logger: { 21 | log: function () { /* haha, I do nothing really */ } 22 | } 23 | }; 24 | 25 | function loop(v) { 26 | var sum = 0; 27 | for (var i = 0; i < 1e5; i++) { 28 | sum += v.len(); 29 | if (sum < 0) { 30 | // Some random code that will never get executed. 31 | for (var j = 0; j < 100; j++) { 32 | sum -= v.len(); 33 | } 34 | } 35 | } 36 | util.logger.log("loopish complete"); 37 | return sum; 38 | } 39 | 40 | var v = new Vec2(0.1, 0.2); 41 | loop(v); 42 | -------------------------------------------------------------------------------- /irhydra/web/demos/webrebels2014/1-concat/concat.js: -------------------------------------------------------------------------------- 1 | // 2 | // Is it faster two add two string constants or two variables containing the 3 | // very same constants? 4 | // 5 | // (benchmarking shows it's faster to add variables, but in fact there is a 6 | // bug in V8) 7 | // 8 | 9 | load("../jsperf.js"); 10 | 11 | Benchmark.prototype.setup = function() { 12 | var test1 = 'owijfiojwefiojewijewoijewoijofiejioejffwiejijiefwiowefjoiwejiewjfiewfoiwejewifjwefijewfiojoewfjwefiowejfiewfjiewfjiewfjieowfjewfijewiiewfjweiojewfiojewfioejfiewfjiewfo'; 13 | var test2 = 'owijfiojwefiojewijewoijewoijofiejioejffwiejijiefwiowefjoiwejiewjfiewfoiwejewifjwefijewfiojoewfjwefiowejfiewfjiewfjiewfjieowfjewfijewiiewfjweiojewfiojewfioejfiewfjiewfo'; 14 | function outsideScope() { 15 | return test1 + test2; 16 | } 17 | function insideScope() { 18 | return 'owijfiojwefiojewijewoijewoijofiejioejffwiejijiefwiowefjoiwejiewjfiewfoiwejewifjwefijewfiojoewfjwefiowejfiewfjiewfjiewfjieowfjewfijewiiewfjweiojewfiojewfioejfiewfjiewfo' + 19 | 'owijfiojwefiojewijewoijewoijofiejioejffwiejijiefwiowefjoiwejiewjfiewfoiwejewifjwefijewfiojoewfjwefiowejfiewfjiewfjiewfjieowfjewfijewiiewfjweiojewfiojewfioejfiewfjiewfo'; 20 | } 21 | }; 22 | 23 | measure({ 24 | 'Inside': function() { 25 | insideScope(); 26 | }, 27 | 'Outside': function() { 28 | outsideScope(); 29 | } 30 | }); 31 | -------------------------------------------------------------------------------- /irhydra/web/demos/webrebels2014/1-concat/data.tar.bz2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mraleph/irhydra/7297e3e320ba1e55f98483b2d35078f4ccc8ee6d/irhydra/web/demos/webrebels2014/1-concat/data.tar.bz2 -------------------------------------------------------------------------------- /irhydra/web/demos/webrebels2014/2-concat-fixed/concat.js: -------------------------------------------------------------------------------- 1 | // 2 | // Is it faster two add two string constants or two variables containing the 3 | // very same constants? 4 | // 5 | // (this is the same as 1-concat example, just running on the V8 with a fixed 6 | // constant folding --- now both cases measure emptiness) 7 | // 8 | 9 | load("../jsperf.js"); 10 | 11 | Benchmark.prototype.setup = function() { 12 | var test1 = 'owijfiojwefiojewijewoijewoijofiejioejffwiejijiefwiowefjoiwejiewjfiewfoiwejewifjwefijewfiojoewfjwefiowejfiewfjiewfjiewfjieowfjewfijewiiewfjweiojewfiojewfioejfiewfjiewfo'; 13 | var test2 = 'owijfiojwefiojewijewoijewoijofiejioejffwiejijiefwiowefjoiwejiewjfiewfoiwejewifjwefijewfiojoewfjwefiowejfiewfjiewfjiewfjieowfjewfijewiiewfjweiojewfiojewfioejfiewfjiewfo'; 14 | function outsideScope() { 15 | return test1 + test2; 16 | } 17 | function insideScope() { 18 | return 'owijfiojwefiojewijewoijewoijofiejioejffwiejijiefwiowefjoiwejiewjfiewfoiwejewifjwefijewfiojoewfjwefiowejfiewfjiewfjiewfjieowfjewfijewiiewfjweiojewfiojewfioejfiewfjiewfo' + 19 | 'owijfiojwefiojewijewoijewoijofiejioejffwiejijiefwiowefjoiwejiewjfiewfoiwejewifjwefijewfiojoewfjwefiowejfiewfjiewfjiewfjieowfjewfijewiiewfjweiojewfiojewfioejfiewfjiewfo'; 20 | } 21 | }; 22 | 23 | measure({ 24 | 'Inside': function() { 25 | insideScope(); 26 | }, 27 | 'Outside': function() { 28 | outsideScope(); 29 | } 30 | }); 31 | -------------------------------------------------------------------------------- /irhydra/web/demos/webrebels2014/2-concat-fixed/data.tar.bz2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mraleph/irhydra/7297e3e320ba1e55f98483b2d35078f4ccc8ee6d/irhydra/web/demos/webrebels2014/2-concat-fixed/data.tar.bz2 -------------------------------------------------------------------------------- /irhydra/web/demos/webrebels2014/3-prototype-node/data.tar.bz2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mraleph/irhydra/7297e3e320ba1e55f98483b2d35078f4ccc8ee6d/irhydra/web/demos/webrebels2014/3-prototype-node/data.tar.bz2 -------------------------------------------------------------------------------- /irhydra/web/demos/webrebels2014/3-prototype-node/prototype.js: -------------------------------------------------------------------------------- 1 | // 2 | // Is it faster to load something from the prototype multiple times or cache it? 3 | // 4 | // Benchmarking on node.js v0.10.29 shows that caching is 8x faster. 5 | // 6 | // Should we start caching properties in local variables now and expect 8x 7 | // speedup across the board? 8 | // 9 | // (Hint: the answer is no. We should learn how to benchmark things first) 10 | // 11 | 12 | var obj = 13 | Object.create( 14 | Object.create( 15 | Object.create( 16 | Object.create( 17 | Object.create({prop: 10}))))); 18 | 19 | 20 | function doManyLookups() { 21 | var counter = 0; 22 | for(var i = 0; i < 1000; i++) { 23 | for(var j = 0; j < 1000; j++) { 24 | for(var k = 0; k < 1000; k++) { 25 | counter += obj.prop; 26 | } 27 | } 28 | } 29 | print('In total: ' + counter); 30 | } 31 | 32 | function lookupAndCache() { 33 | var counter = 0; 34 | var value = obj.prop; 35 | for(var i = 0; i < 1000; i++) 36 | for(var j = 0; j < 1000; j++) 37 | for(var k = 0; k < 1000; k++) 38 | counter += value; 39 | print('In total: ' + counter); 40 | } 41 | 42 | function measure(f) { 43 | var start = Date.now(); 44 | f(); 45 | var end = Date.now(); 46 | print(f.name + ' took ' + (end - start) + ' ms.'); 47 | } 48 | 49 | measure(doManyLookups); 50 | measure(lookupAndCache); 51 | 52 | 53 | -------------------------------------------------------------------------------- /irhydra/web/demos/webrebels2014/4-prototype-node-getter/data.tar.bz2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mraleph/irhydra/7297e3e320ba1e55f98483b2d35078f4ccc8ee6d/irhydra/web/demos/webrebels2014/4-prototype-node-getter/data.tar.bz2 -------------------------------------------------------------------------------- /irhydra/web/demos/webrebels2014/4-prototype-node-getter/prototype.js: -------------------------------------------------------------------------------- 1 | // 2 | // Is it faster to load something from the prototype multiple times or cache it? 3 | // 4 | // Benchmarking on node.js v0.10.29 shows that caching is 8x faster for 5 | // data-properties. 6 | // 7 | // What if we replace data-property with a getter? How much slower will it get? 8 | // 9 | // Actually it gets 8x faster making doManyLookups and lookupAndCache cases 10 | // equally fast. 11 | // 12 | // (What kind of dark magic is this? Learn from data.tar.bz2) 13 | // 14 | 15 | if (typeof print === 'undefined') { 16 | print = console.log.bind(console); 17 | } 18 | 19 | var obj = 20 | Object.create( 21 | Object.create( 22 | Object.create( 23 | Object.create( 24 | Object.create({ get prop () { return 10 }}))))); 25 | 26 | 27 | function doManyLookups() { 28 | var counter = 0; 29 | for(var i = 0; i < 1000; i++) { 30 | for(var j = 0; j < 1000; j++) { 31 | for(var k = 0; k < 1000; k++) { 32 | counter += obj.prop; 33 | } 34 | } 35 | } 36 | print('In total: ' + counter); 37 | } 38 | 39 | function lookupAndCache() { 40 | var counter = 0; 41 | var value = obj.prop; 42 | for(var i = 0; i < 1000; i++) 43 | for(var j = 0; j < 1000; j++) 44 | for(var k = 0; k < 1000; k++) 45 | counter += value; 46 | print('In total: ' + counter); 47 | } 48 | 49 | function measure(f) { 50 | var start = Date.now(); 51 | f(); 52 | var end = Date.now(); 53 | print(f.name + ' took ' + (end - start) + ' ms.'); 54 | } 55 | 56 | measure(doManyLookups); 57 | measure(lookupAndCache); 58 | 59 | 60 | -------------------------------------------------------------------------------- /irhydra/web/demos/webrebels2014/5-prototype/data.tar.bz2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mraleph/irhydra/7297e3e320ba1e55f98483b2d35078f4ccc8ee6d/irhydra/web/demos/webrebels2014/5-prototype/data.tar.bz2 -------------------------------------------------------------------------------- /irhydra/web/demos/webrebels2014/5-prototype/prototype.js: -------------------------------------------------------------------------------- 1 | // 2 | // Is it faster to load something from the prototype multiple times or cache it? 3 | // 4 | // What happens if we run the same benchmark several times on a newer V8? 5 | // 6 | // (the second run is 3x slower! huh?) 7 | // 8 | 9 | var obj = 10 | Object.create( 11 | Object.create( 12 | Object.create( 13 | Object.create( 14 | Object.create({prop: 10}))))); 15 | 16 | 17 | function doManyLookups() { 18 | var counter = 0; 19 | for(var i = 0; i < 1000; i++) { 20 | for(var j = 0; j < 1000; j++) { 21 | for(var k = 0; k < 1000; k++) { 22 | counter += obj.prop; 23 | } 24 | } 25 | } 26 | print('In total: ' + counter); 27 | } 28 | 29 | function lookupAndCache() { 30 | var counter = 0; 31 | var value = obj.prop; 32 | for(var i = 0; i < 1000; i++) 33 | for(var j = 0; j < 1000; j++) 34 | for(var k = 0; k < 1000; k++) 35 | counter += value; 36 | print('In total: ' + counter); 37 | } 38 | 39 | function measure(f) { 40 | var start = Date.now(); 41 | f(); 42 | var end = Date.now(); 43 | print(f.name + ' took ' + (end - start) + ' ms.'); 44 | } 45 | 46 | measure(doManyLookups); 47 | measure(doManyLookups); 48 | measure(lookupAndCache); 49 | measure(lookupAndCache); 50 | 51 | 52 | -------------------------------------------------------------------------------- /irhydra/web/demos/webrebels2014/6-prototype-tostring/data.tar.bz2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mraleph/irhydra/7297e3e320ba1e55f98483b2d35078f4ccc8ee6d/irhydra/web/demos/webrebels2014/6-prototype-tostring/data.tar.bz2 -------------------------------------------------------------------------------- /irhydra/web/demos/webrebels2014/6-prototype-tostring/prototype.js: -------------------------------------------------------------------------------- 1 | // 2 | // Is it faster to load something from the prototype multiple times or cache it? 3 | // 4 | // What happens if we add toString() at the print statement... How does this 5 | // fix 3x slowdown that we observed on the second run of this benchmark? 6 | // 7 | // (hint: it makes representation inference go different way) 8 | // 9 | 10 | if (typeof print === 'undefined') { 11 | print = console.log.bind(console); 12 | } 13 | 14 | var obj = 15 | Object.create( 16 | Object.create( 17 | Object.create( 18 | Object.create( 19 | Object.create({prop: 10}))))); 20 | 21 | 22 | function doManyLookups() { 23 | var counter = 0; 24 | for(var i = 0; i < 1000; i++) { 25 | for(var j = 0; j < 1000; j++) { 26 | for(var k = 0; k < 1000; k++) { 27 | counter += obj.prop; 28 | } 29 | } 30 | } 31 | print('In total: ' + counter.toString()); 32 | } 33 | 34 | function lookupAndCache() { 35 | var counter = 0; 36 | var value = obj.prop; 37 | for(var i = 0; i < 1000; i++) 38 | for(var j = 0; j < 1000; j++) 39 | for(var k = 0; k < 1000; k++) 40 | counter += value; 41 | print('In total: ' + counter.toString()); 42 | } 43 | 44 | function measure(f) { 45 | var start = Date.now(); 46 | f(); 47 | var end = Date.now(); 48 | print(f.name + ' took ' + (end - start) + ' ms.'); 49 | } 50 | 51 | measure(doManyLookups); 52 | measure(doManyLookups); 53 | measure(lookupAndCache); 54 | measure(lookupAndCache); 55 | 56 | -------------------------------------------------------------------------------- /irhydra/web/demos/webrebels2014/7-method-function/data.tar.bz2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mraleph/irhydra/7297e3e320ba1e55f98483b2d35078f4ccc8ee6d/irhydra/web/demos/webrebels2014/7-method-function/data.tar.bz2 -------------------------------------------------------------------------------- /irhydra/web/demos/webrebels2014/7-method-function/method-function.js: -------------------------------------------------------------------------------- 1 | // 2 | // Is it faster to call a function directly or call it as if it was a method 3 | // on an object? 4 | // 5 | // Somehow this benchmark shows Function many times slower. 6 | // 7 | // Learn the one wierd trick to speed it up in 7-method-function-hack 8 | // 9 | 10 | load("../jsperf.js"); 11 | 12 | Benchmark.prototype.setup = function() { 13 | function mk(word) { 14 | var len = word.length; 15 | if (len > 255) return undefined; 16 | var i = len >> 2; 17 | return String.fromCharCode( 18 | (word.charCodeAt( 0) & 0x03) << 14 | 19 | (word.charCodeAt( i) & 0x03) << 12 | 20 | (word.charCodeAt( i+i) & 0x03) << 10 | 21 | (word.charCodeAt(i+i+i) & 0x03) << 8 | 22 | len 23 | ); 24 | } 25 | 26 | var MK = function() { }; 27 | MK.prototype.mk = mk; 28 | var mker = new MK; 29 | }; 30 | 31 | measure({ 32 | 'Function': function() { 33 | var key; 34 | key = mk('www.wired.com'); 35 | key = mk('www.youtube.com'); 36 | key = mk('scorecardresearch.com'); 37 | key = mk('www.google-analytics.com'); 38 | }, 39 | 'Method': function() { 40 | var key; 41 | key = mker.mk('www.wired.com'); 42 | key = mker.mk('www.youtube.com'); 43 | key = mker.mk('scorecardresearch.com'); 44 | key = mker.mk('www.google-analytics.com'); 45 | } 46 | }); -------------------------------------------------------------------------------- /irhydra/web/demos/webrebels2014/8-method-function-hack/data.tar.bz2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mraleph/irhydra/7297e3e320ba1e55f98483b2d35078f4ccc8ee6d/irhydra/web/demos/webrebels2014/8-method-function-hack/data.tar.bz2 -------------------------------------------------------------------------------- /irhydra/web/demos/webrebels2014/8-method-function-hack/method-function.js: -------------------------------------------------------------------------------- 1 | // 2 | // Is it faster to call a function directly or call it as if it was a method 3 | // on an object? 4 | // 5 | // The benchmark used to show that Function is many times slower until we 6 | // added 7 | // 8 | // "Speed" + "you" + "JS" + "with" + 9 | // "this" + "one" + "weird" + "trick"; 10 | // 11 | // in the setup. 12 | // 13 | // WAAAAAAT? 14 | // 15 | // Now they are equaly fast! 16 | // 17 | // (Hint: it was not optimized before, not it is --- both benchmarks now 18 | // measure the sound of silence because LICM completely moves the "meat" 19 | // out of benchmarking loops). 20 | // 21 | 22 | load("../jsperf.js"); 23 | 24 | Benchmark.prototype.setup = function() { 25 | "Speed" + "you" + "JS" + "with" + 26 | "this" + "one" + "weird" + "trick"; 27 | 28 | function mk(word) { 29 | var len = word.length; 30 | if (len > 255) return undefined; 31 | var i = len >> 2; 32 | return String.fromCharCode( 33 | (word.charCodeAt( 0) & 0x03) << 14 | 34 | (word.charCodeAt( i) & 0x03) << 12 | 35 | (word.charCodeAt( i+i) & 0x03) << 10 | 36 | (word.charCodeAt(i+i+i) & 0x03) << 8 | 37 | len 38 | ); 39 | } 40 | 41 | var MK = function() { }; 42 | MK.prototype.mk = mk; 43 | var mker = new MK; 44 | }; 45 | 46 | measure({ 47 | 'Function': function() { 48 | var key; 49 | key = mk('www.wired.com'); 50 | key = mk('www.youtube.com'); 51 | key = mk('scorecardresearch.com'); 52 | key = mk('www.google-analytics.com'); 53 | }, 54 | 'Method': function() { 55 | var key; 56 | key = mker.mk('www.wired.com'); 57 | key = mker.mk('www.youtube.com'); 58 | key = mker.mk('scorecardresearch.com'); 59 | key = mker.mk('www.google-analytics.com'); 60 | } 61 | }); -------------------------------------------------------------------------------- /irhydra/web/demos/webrebels2014/README.md: -------------------------------------------------------------------------------- 1 | This folder contains samples used during [my WebRebels 2014 talk about microbenchmarks](mrale.ph/talks/webrebels2014). 2 | 3 | Samples `concat`, `concat-fixed`, `method-function`, `method-function-hack`, `prototype`, `prototype-tostring` were collected on the recent V8 3.28.27. 4 | 5 | Samples `prototype-node` and `prototype-node-getter` were collected on node.js v0.10.29 and patched to allow IRHydra2 to display them. -------------------------------------------------------------------------------- /irhydra/web/demos/webrebels2014/jsperf.js: -------------------------------------------------------------------------------- 1 | // 2 | // Benchmark.js wrapper that limits amounts of samples to minimize the size 3 | // of produced hydrogen.cfg/code.asm dumps. 4 | // 5 | 6 | load("../lodash.js"); 7 | load("../benchmark.js"); 8 | 9 | Benchmark.options.maxTime = 0; 10 | Benchmark.options.minSamples = 2; 11 | 12 | function measure(cases) { 13 | var suite = new Benchmark.Suite(); 14 | 15 | Object.keys(cases).forEach(function (name) { 16 | suite.add(name, cases[name]); 17 | }); 18 | 19 | suite 20 | .on('cycle', function(event) { 21 | print(String(event.target)); 22 | }) 23 | .on('complete', function() { 24 | print('Fastest is ' + this.filter('fastest').pluck('name')); 25 | }) 26 | .run({'async': false}); 27 | } -------------------------------------------------------------------------------- /irhydra/web/deps/fa/fonts/fontawesome-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mraleph/irhydra/7297e3e320ba1e55f98483b2d35078f4ccc8ee6d/irhydra/web/deps/fa/fonts/fontawesome-webfont.eot -------------------------------------------------------------------------------- /irhydra/web/deps/fa/fonts/fontawesome-webfont.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mraleph/irhydra/7297e3e320ba1e55f98483b2d35078f4ccc8ee6d/irhydra/web/deps/fa/fonts/fontawesome-webfont.ttf -------------------------------------------------------------------------------- /irhydra/web/deps/fa/fonts/fontawesome-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mraleph/irhydra/7297e3e320ba1e55f98483b2d35078f4ccc8ee6d/irhydra/web/deps/fa/fonts/fontawesome-webfont.woff -------------------------------------------------------------------------------- /irhydra/web/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mraleph/irhydra/7297e3e320ba1e55f98483b2d35078f4ccc8ee6d/irhydra/web/favicon.ico -------------------------------------------------------------------------------- /saga/.gitignore: -------------------------------------------------------------------------------- 1 | .buildlog 2 | .DS_Store 3 | .idea 4 | .pub/ 5 | build/ 6 | packages 7 | pubspec.lock 8 | -------------------------------------------------------------------------------- /saga/lib/src/flow/compact_likely.dart: -------------------------------------------------------------------------------- 1 | // Copyright 2015 Google Inc. All Rights Reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | /// Merge blocks together assuming that branches leading to NORETURN calls 16 | /// are "unlikely" and are almost never taken. 17 | library saga.flow.compact_likely; 18 | 19 | import 'package:saga/src/flow/node.dart' as node; 20 | import 'package:saga/src/parser.dart' as parser; 21 | 22 | compact(blocks) { 23 | final throws = new Set.identity(); 24 | 25 | mark(block) { 26 | if (!throws.add(block)) { 27 | return; 28 | } 29 | 30 | for (var pred in block.predecessors) { 31 | if (pred.successors.every(throws.contains)) { 32 | mark(pred); 33 | } 34 | } 35 | } 36 | 37 | for (var block in blocks) { 38 | final last = block.code.isNotEmpty ? block.code.last : null; 39 | if (last != null && 40 | last.op is node.OpCall && 41 | last.op.target.attributes.contains(parser.CallTargetAttribute.NORETURN)) { 42 | mark(block); 43 | } 44 | } 45 | 46 | 47 | final visited = new List(blocks.length); 48 | var result = []; 49 | for (var block in blocks) { 50 | if (visited[block.id] != null) { 51 | continue; 52 | } 53 | 54 | final merged = new node.MergedBB(result.length, [block]); 55 | result.add(merged); 56 | visited[block.id] = merged; 57 | 58 | final last = block.code.isNotEmpty ? block.code.last : null; 59 | if (last != null && 60 | (last.op is node.OpBranchIf || 61 | last.op is node.OpBranchOn) && 62 | throws.contains(block.successors[1]) && 63 | (visited[block.successors.first.id] == null) && 64 | block.successors.first.predecessors.length == 1) { 65 | visited[block.successors.first.id] = merged; 66 | merged.blocks.add(block.successors.first); 67 | } 68 | } 69 | 70 | redirect(target) => 71 | (target is node.BB) ? visited[target.id] : target; 72 | 73 | for (var block in result) { 74 | final lastBlock = block.blocks.last; 75 | for (var innerBlock in block.blocks) { 76 | for (var succ in innerBlock.successors) { 77 | if (visited[succ.id] != block || innerBlock == lastBlock) { 78 | block.edge(visited[succ.id], unlikely: innerBlock != lastBlock || throws.contains(succ)); 79 | assert(visited[succ.id].blocks.first == succ); 80 | } 81 | } 82 | 83 | if (innerBlock.code.isNotEmpty) { 84 | final last = innerBlock.code.last; 85 | if (last.op is node.OpGoto) { 86 | last.op.target = redirect(last.op.target); 87 | } else if (last.op is node.OpBranchIf || last.op is node.OpBranchOn) { 88 | last.op.thenTarget = redirect(last.op.thenTarget); 89 | last.op.elseTarget = innerBlock == lastBlock ? redirect(last.op.elseTarget) : null; 90 | } 91 | } 92 | } 93 | } 94 | 95 | return new Map.fromIterable(result, key: (block) => block.name); 96 | } -------------------------------------------------------------------------------- /saga/lib/src/flow/cpu_register.dart: -------------------------------------------------------------------------------- 1 | // Copyright 2015 Google Inc. All Rights Reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | /// Register name parsing. 16 | /// Supports only x86_64 registers, ignores register size and aliasing. 17 | library saga.flow.cpu_register; 18 | 19 | final registers = (){ 20 | final map = {}; 21 | 22 | add(x, r) { 23 | map["r${x}"] = map["e${x}"] = map["${x}"] = r; 24 | } 25 | 26 | add("ax", CpuRegister.RAX); 27 | add("bx", CpuRegister.RBX); 28 | add("cx", CpuRegister.RCX); 29 | add("dx", CpuRegister.RDX); 30 | 31 | add("si", CpuRegister.RSI); 32 | add("di", CpuRegister.RDI); 33 | add("sp", CpuRegister.RSP); 34 | add("bp", CpuRegister.RBP); 35 | 36 | for (var i = CpuRegister.R8; i <= CpuRegister.R15; i++) { 37 | map["r${i}d"] = map["r${i}"] = i; 38 | } 39 | 40 | map["rip"] = CpuRegister.RIP; 41 | 42 | return map; 43 | }(); 44 | 45 | class CpuRegister { 46 | static const RAX = 0; 47 | static const RCX = 1; 48 | static const RDX = 2; 49 | static const RBX = 3; 50 | static const RSP = 4; 51 | static const RBP = 5; 52 | static const RSI = 6; 53 | static const RDI = 7; 54 | static const R8 = 8; 55 | static const R9 = 9; 56 | static const R10 = 10; 57 | static const R11 = 11; 58 | static const R12 = 12; 59 | static const R13 = 13; 60 | static const R14 = 14; 61 | static const R15 = 15; 62 | static const RIP = 16; 63 | static const FLAGS = 17; 64 | static const kNumberOfRegisters = 18; 65 | 66 | static const kNames = const [ 67 | 'RAX', 68 | 'RCX', 69 | 'RDX', 70 | 'RBX', 71 | 'RSP', 72 | 'RBP', 73 | 'RSI', 74 | 'RDI', 75 | 'R8', 76 | 'R9', 77 | 'R10', 78 | 'R11', 79 | 'R12', 80 | 'R13', 81 | 'R14', 82 | 'R15', 83 | 'RIP', 84 | 'FLAGS' 85 | ]; 86 | 87 | static parse(name) { 88 | assert(registers.containsKey(name)); 89 | return registers[name]; 90 | } 91 | } -------------------------------------------------------------------------------- /saga/lib/src/flow/dce.dart: -------------------------------------------------------------------------------- 1 | // Copyright 2015 Google Inc. All Rights Reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | /// Dead Code Elimination 16 | library saga.flow.dce; 17 | 18 | dce(blocks) { 19 | final worklist = new Set(); 20 | 21 | for (var block in blocks) { 22 | for (var node in block.code) { 23 | if (!node.hasUses && !node.hasEffect) { 24 | worklist.add(node); 25 | } 26 | } 27 | } 28 | 29 | while (worklist.isNotEmpty) { 30 | final node = worklist.first; 31 | worklist.remove(node); 32 | 33 | if (!node.hasUses && !node.hasEffect) { 34 | worklist.addAll(node.inputs.map((input) => input.def).where((def) => def != null)); 35 | node.remove(); 36 | } 37 | } 38 | } -------------------------------------------------------------------------------- /saga/lib/src/flow/fold.dart: -------------------------------------------------------------------------------- 1 | // Copyright 2015 Google Inc. All Rights Reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | /// Simple folding rules for nodes returning their canonical representation. 16 | part of saga.flow.node; 17 | 18 | fold(Node n) { 19 | final rule = rules[n.op.tag]; 20 | 21 | if (rule != null) { 22 | final folded = rule(n); 23 | if (folded != n) { 24 | assert(!n.hasUses); 25 | for (var input in n.inputs) input.bindTo(null); 26 | return folded; 27 | } 28 | } 29 | 30 | return n; 31 | } 32 | 33 | final rules = { 34 | "^": (node) { 35 | if (node.inputs[0].def == node.inputs[0].def) { 36 | return Node.konst(0, origin: node.origin); 37 | } 38 | return node; 39 | }, 40 | 41 | "+": (node) { 42 | final rhs = node.inputs[1].def; 43 | if (rhs.op is OpKonstant && 44 | rhs.op.value < 0) { 45 | return Node.binary(SUB, node.inputs[0].def, 46 | Node.konst(-rhs.op.value, origin: rhs.origin)); 47 | } 48 | return node; 49 | }, 50 | 51 | "OpSelectIf": (node) { 52 | final left = node.inputs[0].def; 53 | final right = node.inputs[1].def; 54 | final thenValue = node.inputs[2].def; 55 | final elseValue = node.inputs[3].def; 56 | 57 | if (left == thenValue && right == elseValue) { 58 | switch (node.op.condition) { 59 | case "<": 60 | case "<=": 61 | return Node.binary(MIN, left, right); 62 | 63 | case ">": 64 | case ">=": 65 | return Node.binary(MAX, left, right); 66 | } 67 | } else if (left == elseValue && right == thenValue) { 68 | switch (node.op.condition) { 69 | case ">": 70 | case ">=": 71 | return Node.binary(MIN, left, right); 72 | case "<": 73 | case "<=": 74 | return Node.binary(MAX, left, right); 75 | } 76 | } 77 | 78 | return node; 79 | }, 80 | }; -------------------------------------------------------------------------------- /saga/lib/src/flow/fuse_branches.dart: -------------------------------------------------------------------------------- 1 | // Copyright 2015 Google Inc. All Rights Reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | /// Fuse together instructions producing FLAGS and branches that branch 16 | /// on these flags: 17 | /// 18 | /// c = a - b 19 | /// f = flagsOf(c) 20 | /// BranchOn lt, c 21 | /// 22 | /// becomes 23 | /// 24 | /// BranchIf a < b 25 | /// 26 | library saga.flow.fuse_branches; 27 | 28 | import 'package:saga/src/flow/node.dart'; 29 | import 'package:saga/src/util.dart'; 30 | 31 | fuseBranches(blocks) { 32 | fusedSelect(select, left, right) => 33 | Node.selectIf(select.op.condition, left, right, select.inputs[1].def, select.inputs[2].def); 34 | 35 | fusedBranch(branch, left, right) => 36 | Node.branchIf(branch.op.condition, left, right, branch.op.thenTarget, branch.op.elseTarget); 37 | 38 | tryFuse(candidate, replacement) { 39 | final flags = candidate.inputs[0].def; 40 | assert(flags.op == FLAGS); 41 | if (flags.uses.length > 1) return; 42 | 43 | final op = flags.inputs[0].def; 44 | if (op.uses.length > 1) return; 45 | 46 | if (op.op == SUB) { 47 | candidate.replaceWith(replacement(candidate, op.inputs[0].def, op.inputs[1].def)); 48 | } else if (op.op == AND) { 49 | if (op.inputs[0].def != op.inputs[1].def) { 50 | return; 51 | } 52 | 53 | candidate.replaceWith(replacement(candidate, op.inputs[0].def, Node.konst(0))); 54 | } 55 | } 56 | 57 | for (var block in blocks) { 58 | if (block.code.isEmpty) continue; 59 | 60 | for (var select in iterate(block.code).where((node) => node.op is OpSelect)) { 61 | tryFuse(select, fusedSelect); 62 | } 63 | 64 | final branch = block.code.last; 65 | if (branch.op is OpBranchOn) { 66 | tryFuse(branch, fusedBranch); 67 | } 68 | } 69 | } -------------------------------------------------------------------------------- /saga/lib/src/flow/interference.dart: -------------------------------------------------------------------------------- 1 | // Copyright 2015 Google Inc. All Rights Reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | /// Compute interference graph. 16 | library saga.flow.interference; 17 | 18 | import 'dart:math' as math; 19 | 20 | import 'package:saga/src/flow/liveness.dart' as liveness; 21 | 22 | class Edge { 23 | final from; 24 | final to; 25 | 26 | Edge(from, to) : from = math.min(from, to), to = math.max(from, to); 27 | 28 | toString() => "(${from}, ${to})"; 29 | 30 | operator==(other) => from == other.from && to == other.to; 31 | get hashCode => from ^ to; 32 | } 33 | 34 | reversed(list) sync* { 35 | if (list.isEmpty) return; 36 | 37 | for (var node = list.last; node != null; node = node.previous) { 38 | yield node; 39 | } 40 | } 41 | 42 | build(blocks) { 43 | final stopwatch = new Stopwatch()..start(); 44 | final liveOutSets = liveness.build(blocks); 45 | 46 | final interference = new Set(); 47 | final alive = new liveness.NodeSet(); 48 | for (var block in blocks) { 49 | alive.setFrom(liveOutSets[block.id]); 50 | 51 | for (var node in reversed(block.code)) { 52 | for (var live in alive) { 53 | if (live != node.id) interference.add(new Edge(node.id, live)); 54 | } 55 | alive.remove(node); 56 | for (var input in node.inputs) { 57 | if (input.def != null) alive.add(input.def); 58 | } 59 | } 60 | 61 | for (var node in block.phis) { 62 | for (var live in alive) { 63 | if (live != node.id) interference.add(new Edge(node.id, live)); 64 | } 65 | } 66 | } 67 | 68 | print("interference graph has ${interference.length} edges, took ${stopwatch.elapsedMilliseconds} ms to build."); 69 | 70 | return interference; 71 | } -------------------------------------------------------------------------------- /saga/lib/src/flow/locals.dart: -------------------------------------------------------------------------------- 1 | // Copyright 2015 Google Inc. All Rights Reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | /// Forward loads/stores through RSP relative slots. 16 | /// Assumes stack operations are well-behaved and all stack operations are 17 | /// implicit in the IR. 18 | library saga.flow.locals; 19 | 20 | import 'package:saga/src/flow/node.dart'; 21 | import 'package:saga/src/flow/cpu_register.dart'; 22 | import 'package:saga/src/flow/ssa.dart'; 23 | import 'package:saga/src/util.dart'; 24 | 25 | findLocals(state, blocks) { 26 | final entrySp = state.entryState[CpuRegister.RSP]; 27 | 28 | final offsets = new Map(); 29 | 30 | rewire(def, int offset) { 31 | for (Use use in iterate(def.uses)) { 32 | final node = use.at; 33 | if (node.op == ADD || (node.op == SUB && use.idx == 0)) { 34 | final otherVal = node.inputs[1 - use.idx].def; 35 | if (otherVal.op is OpKonstant) { 36 | final int offs = otherVal.op.value; 37 | final int new_offset = offset + (node.op == SUB ? -offs : offs); 38 | if (def != entrySp) { 39 | final new_addr = Node.binary(ADD, entrySp, Node.konst(new_offset)); 40 | node.replaceWith(new_addr); 41 | rewire(new_addr, new_offset); 42 | } else { 43 | rewire(node, new_offset); 44 | } 45 | continue; 46 | } 47 | } else if (node.op is OpAddr) { 48 | assert(use.idx == 0); 49 | assert(node.inputs[1].def == null); 50 | if (def != entrySp) { 51 | final new_addr = Node.addr( 52 | base: entrySp, 53 | offset: node.op.offset + offset); 54 | node.replaceWith(new_addr); 55 | rewire(new_addr, new_addr.op.offset); 56 | } else { 57 | rewire(node, node.op.offset); 58 | } 59 | continue; 60 | } else if (node.op == LOAD || node.op == STORE) { 61 | offsets[node] = offset; 62 | continue; 63 | } else if (node.op == PHANTOM) { 64 | continue; // ignore phantoms 65 | } 66 | 67 | throw "can't establish the flow of RSP: ${def.opcode}"; 68 | } 69 | } 70 | 71 | rewire(entrySp, 0); 72 | 73 | final ssa = new SSABuilder(blocks); 74 | for (var block in blocks) { 75 | ssa.startBlock(block); 76 | for (var node in iterate(block.code)) { 77 | final offset = offsets[node]; 78 | if (offset != null) { 79 | if (node.op == STORE) { 80 | ssa.define(offset, node.inputs[1].def); 81 | } else { 82 | node.replaceUses(ssa.use(offset)); 83 | node.remove(); 84 | } 85 | } 86 | } 87 | } 88 | 89 | ssa.finish(); 90 | } -------------------------------------------------------------------------------- /saga/lib/src/flow/types.dart: -------------------------------------------------------------------------------- 1 | // Copyright 2015 Google Inc. All Rights Reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | /// Type descriptors. 16 | library saga.flow.types; 17 | 18 | class Type { 19 | final String name; 20 | 21 | const Type(this.name); 22 | 23 | toString() => "Type(${name})"; 24 | } 25 | 26 | class Field { 27 | final int offset; 28 | final String name; 29 | final Type type; 30 | 31 | Field(this.offset, this.name, this.type); 32 | } 33 | 34 | class ReferenceType extends Type { 35 | final Map fieldsByOffset; 36 | 37 | ReferenceType(name, fields) 38 | : fieldsByOffset = new Map.fromIterable(fields, key: (field) => field.offset), 39 | super(name); 40 | } 41 | 42 | class ArrayType extends ReferenceType { 43 | final Type elementType; 44 | 45 | static const lengthOffset = 12; 46 | static const elementsOffset = 16; 47 | static const nameSuffix = "[]"; 48 | 49 | ArrayType(elementType) 50 | : elementType = elementType, 51 | super("${elementType.name}${nameSuffix}", [new Field(lengthOffset, "length", TypeSystem.INT)]); 52 | } 53 | 54 | class TypeSystem { 55 | final Map types = {}; 56 | final Map typesInfo; 57 | 58 | static const INT = const Type("int"); 59 | 60 | TypeSystem(this.typesInfo) { 61 | types[INT.name] = INT; 62 | } 63 | 64 | resolve(String name) { 65 | return types.putIfAbsent(name, () { 66 | if (name.endsWith(ArrayType.nameSuffix)) { 67 | final elementType = resolve(name.substring(0, name.length - ArrayType.nameSuffix.length)); 68 | if (elementType != null) { 69 | return new ArrayType(elementType); 70 | } 71 | } else if (typesInfo.containsKey(name)) { 72 | return new ReferenceType(name, typesInfo[name].fields 73 | .map((fieldInfo) => new Field(fieldInfo.offset, fieldInfo.name, resolve(fieldInfo.type)))); 74 | } 75 | return null; 76 | }); 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /saga/lib/src/ui/graph_pane.dart: -------------------------------------------------------------------------------- 1 | // Copyright 2015 Google Inc. All Rights Reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | library saga.ui.graph_pane; 16 | 17 | import 'dart:html'; 18 | import 'dart:js' as js; 19 | 20 | import 'package:liquid/liquid.dart'; 21 | import 'package:liquid/vdom.dart' as v; 22 | import 'package:ui_utils/delayed_reaction.dart'; 23 | import 'package:ui_utils/graph_layout.dart' as graph_layout; 24 | 25 | import 'package:saga/src/ui/code_pane.dart' as code_pane; 26 | import 'package:saga/src/ui/ir_pane.dart' as ir_pane; 27 | import 'package:saga/src/ui/tooltip.dart'; 28 | 29 | class BlockTooltip extends Tooltip { 30 | final flowData; 31 | 32 | final _delayed = new DelayedReaction(delay: const Duration(milliseconds: 100)); 33 | 34 | BlockTooltip(this.flowData); 35 | 36 | 37 | var block; 38 | show(el, id) { 39 | _delayed.schedule(() { 40 | block = flowData.blocks[id]; 41 | target = el; 42 | isVisible = true; 43 | }); 44 | } 45 | 46 | hide() { 47 | _delayed.cancel(); 48 | isVisible = false; 49 | } 50 | 51 | get content => 52 | v.pre()(block != null ? [ 53 | code_pane.vBlock(block: block, flowData: flowData), 54 | v.text('\n'), 55 | ir_pane.vBlock(block: block) 56 | ] : const []); 57 | } 58 | 59 | 60 | final vGraphPane = v.componentFactory(GraphPaneComponent); 61 | class GraphPaneComponent extends Component { 62 | @property() var flowData; 63 | 64 | var graphPane; 65 | var tooltip; 66 | 67 | build() => 68 | v.root()([ 69 | graphPane = v.div(classes: const ['graph-pane']), 70 | (tooltip = new BlockTooltip(flowData)).build() 71 | ]); 72 | 73 | update() async { 74 | await writeDOM(); 75 | displayGraph(graphPane.ref, flowData.blocks, tooltip); 76 | } 77 | 78 | static displayGraph(pane, blocks, ref) { 79 | final stopwatch = new Stopwatch()..start(); 80 | graph_layout.display(pane, blocks, (label, blockId) { 81 | label.onMouseOver.listen((e) => ref.show(e.target, blockId)); 82 | label.onMouseOut.listen((_) => ref.hide()); 83 | label.onClick.listen((e) { 84 | for (var el in document.querySelectorAll('[data-block=${blockId}]')) { 85 | el.scrollIntoView(); 86 | js.context.callMethod('jQuery', [el]).callMethod('effect', ['highlight', new js.JsObject.jsify({ 'color': 'rgba(203, 75, 22, 0.5)' }), 500]); 87 | } 88 | e.stopPropagation(); 89 | e.preventDefault(); 90 | }); 91 | }); 92 | print("graph_layout took ${stopwatch.elapsedMilliseconds}"); 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /saga/lib/src/ui/tooltip.dart: -------------------------------------------------------------------------------- 1 | // Copyright 2015 Google Inc. All Rights Reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | library saga.ui.tooltip; 16 | 17 | import 'dart:html'; 18 | 19 | import 'package:liquid/liquid.dart'; 20 | import 'package:liquid/vdom.dart' as v; 21 | import 'package:observe/observe.dart'; 22 | import 'package:ui_utils/tooltip.dart' as tooltip; 23 | 24 | export 'package:ui_utils/tooltip.dart' show Placement; 25 | 26 | abstract class Tooltip extends Observable { 27 | @observable tooltip.Placement placement; 28 | @observable Element target; 29 | @observable bool isVisible = false; 30 | get content; 31 | 32 | Tooltip({this.placement: tooltip.Placement.BOTTOM}); 33 | 34 | build({key}) => vTooltip(data: this, key: key); 35 | } 36 | 37 | class TooltipWithContent extends Tooltip { 38 | var contentBuilder; 39 | 40 | TooltipWithContent({placement: tooltip.Placement.BOTTOM}) : super(placement: placement); 41 | 42 | get content => contentBuilder(); 43 | } 44 | 45 | final vTooltip = v.componentFactory(TooltipComponent); 46 | class TooltipComponent extends Component { 47 | @property() Tooltip data; 48 | 49 | var subscription; 50 | _unsubscribe() { 51 | if (subscription != null) { 52 | subscription.cancel(); 53 | subscription = null; 54 | } 55 | } 56 | 57 | updated() { 58 | _unsubscribe(); 59 | subscription = data.changes.listen((_) { 60 | if (!data.isVisible) { 61 | tooltip.hide(element); 62 | } else { 63 | domScheduler.nextFrame.after().then((_) { 64 | tooltip.show(data.target, data.placement, element); 65 | }); 66 | invalidate(); 67 | } 68 | }); 69 | } 70 | 71 | detached() => _unsubscribe(); 72 | 73 | build() { 74 | return v.root(classes: ['popover', 'xref', tooltip.className(data.placement)])([ 75 | v.div(classes: const ['arrow']), 76 | v.div(classes: const ['popover-content'])(data.content) 77 | ]); 78 | } 79 | } -------------------------------------------------------------------------------- /saga/lib/src/util.dart: -------------------------------------------------------------------------------- 1 | // Copyright 2015 Google Inc. All Rights Reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | library saga.util; 16 | 17 | intersperseValue(it, val) sync* { 18 | var comma = false; 19 | for (var v in it) { 20 | if (comma) yield val; else comma = true; 21 | yield v; 22 | } 23 | } 24 | 25 | intersperse(it, f) sync* { 26 | var comma = false; 27 | for (var v in it) { 28 | if (comma) yield f(); else comma = true; 29 | yield v; 30 | } 31 | } 32 | 33 | intersperseWith(it, f) sync* { 34 | var i = 0; 35 | for (var v in it) { 36 | if (i != 0) { 37 | yield f(i); 38 | i++; 39 | } 40 | 41 | yield v; 42 | i++; 43 | } 44 | } 45 | 46 | timeAndReport(action, name) { 47 | final stopwatch = new Stopwatch()..start(); 48 | final result = action(); 49 | print("${name} took ${stopwatch.elapsedMilliseconds} ms."); 50 | return result; 51 | } 52 | 53 | iterate(list) sync* { 54 | if (list.isEmpty) return; 55 | 56 | for (var curr = list.first, next; 57 | curr != null; 58 | curr = next) { 59 | next = curr.next; 60 | yield curr; 61 | } 62 | } -------------------------------------------------------------------------------- /saga/pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: saga 2 | version: 0.0.1 3 | environment: 4 | sdk: '>=1.0.0 <2.0.0' 5 | dependencies: 6 | browser: any 7 | petitparser: any 8 | ui_utils: 9 | path: ../ui_utils 10 | liquid: 11 | git: git://github.com/mraleph/liquid.git 12 | observe: any 13 | transformers: 14 | - observe 15 | - liquid 16 | -------------------------------------------------------------------------------- /saga/web/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | Saga 26 | 27 | 28 | 29 | 30 | 31 | 32 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | -------------------------------------------------------------------------------- /saga/web/main.dart: -------------------------------------------------------------------------------- 1 | // Copyright 2015 Google Inc. All Rights Reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | library saga.main; 16 | 17 | import 'dart:html'; 18 | 19 | import 'package:liquid/liquid.dart'; 20 | import 'package:liquid/vdom.dart' as v; 21 | import 'package:observe/observe.dart'; 22 | 23 | import 'package:saga/src/parser.dart' as parser; 24 | import 'package:saga/src/flow/flow.dart' as flow; 25 | import 'package:saga/src/ui/ir_pane.dart' as ir_pane; 26 | import 'package:saga/src/ui/code_pane.dart' as code_pane; 27 | import 'package:saga/src/ui/graph_pane.dart' as graph_pane; 28 | import 'package:saga/src/util.dart' show timeAndReport; 29 | 30 | class SagaApp extends Observable { 31 | @observable var flowData; 32 | 33 | render(code) { 34 | flowData = timeAndReport(() => flow.build(code), "flow analysis"); 35 | } 36 | 37 | display(text) { 38 | final code = timeAndReport(() => parser.parse(text), "parsing"); 39 | render(code); 40 | 41 | code.changes.listen((_) => render(code)); 42 | } 43 | } 44 | 45 | class SagaAppComponent extends Component { 46 | var app; 47 | 48 | init() { 49 | app.changes.listen((_) => invalidate()); 50 | } 51 | 52 | build() => 53 | v.root(classes: const ["saga-app", "saga-root"])(app.flowData == null ? const [] : [ 54 | code_pane.vCodePane(flowData: app.flowData), 55 | graph_pane.vGraphPane(flowData: app.flowData), 56 | ir_pane.vIrPane(flowData: app.flowData) 57 | ]); 58 | } 59 | 60 | injectStylesheets(hrefs) { 61 | document.head.children.addAll(hrefs.map((href) => new LinkElement() 62 | ..rel = 'stylesheet' 63 | ..href = href)); 64 | } 65 | 66 | main() { 67 | injectStylesheets(['packages/ui_utils/assets/tooltip.css', 'packages/ui_utils/assets/xref.css', 'styles.css']); 68 | 69 | final app = new SagaApp(); 70 | injectComponent(new SagaAppComponent()..app = app, document.querySelector("body")); 71 | 72 | HttpRequest.getString("code.asm").then(app.display); 73 | } -------------------------------------------------------------------------------- /saga/web/post.dart: -------------------------------------------------------------------------------- 1 | // Copyright 2015 Google Inc. All Rights Reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | library saga.post; 16 | 17 | import 'dart:html'; 18 | 19 | import 'package:liquid/liquid.dart'; 20 | import 'package:liquid/vdom.dart' as v; 21 | import 'package:observe/observe.dart'; 22 | 23 | import 'package:saga/src/parser.dart' as parser; 24 | import 'package:saga/src/flow/flow.dart' as flow; 25 | import 'package:saga/src/ui/ir_pane.dart' as ir_pane; 26 | import 'package:saga/src/ui/code_pane.dart' as code_pane; 27 | import 'package:saga/src/util.dart' show timeAndReport; 28 | 29 | class SagaApp extends Observable { 30 | @observable var flowData; 31 | 32 | render(code) { 33 | flowData = timeAndReport(() => flow.build(code), "flow analysis"); 34 | } 35 | 36 | display(text) { 37 | final code = timeAndReport(() => parser.parse(text), "parsing"); 38 | render(code); 39 | 40 | code.changes.listen((_) => render(code)); 41 | } 42 | } 43 | 44 | class SagaAppComponent extends Component { 45 | var app; 46 | 47 | final showOnly; 48 | final showIr; 49 | 50 | SagaAppComponent(showOnly, {this.showIr: false}) : showOnly = new Set.from(showOnly); 51 | 52 | init() { 53 | app.changes.listen((_) => invalidate()); 54 | } 55 | 56 | build() => 57 | v.root(classes: const ["saga-root"])(app.flowData == null ? const [] : [ 58 | showIr ? ir_pane.vIrPane(flowData: app.flowData, showOnly: showOnly) 59 | : code_pane.vCodePane(flowData: app.flowData, showOnly: showOnly, showIr: false) 60 | ]); 61 | } 62 | 63 | injectStylesheets(hrefs) { 64 | document.head.children.addAll(hrefs.map((href) => new LinkElement() 65 | ..rel = 'stylesheet' 66 | ..href = href)); 67 | } 68 | 69 | main() { 70 | injectStylesheets(['/saga/packages/ui_utils/assets/tooltip.css', 71 | '/saga/packages/ui_utils/assets/xref.css', 72 | '/saga/styles.css']); 73 | 74 | final app = new SagaApp(); 75 | 76 | for (var codeEl in document.querySelectorAll(".code0")) { 77 | injectComponent(new SagaAppComponent([2])..app = app, codeEl); 78 | } 79 | 80 | for (var codeEl in document.querySelectorAll(".code4")) { 81 | injectComponent(new SagaAppComponent([4])..app = app, codeEl); 82 | } 83 | 84 | for (var codeEl in document.querySelectorAll(".ir0")) { 85 | injectComponent(new SagaAppComponent([2], showIr: true)..app = app, codeEl); 86 | } 87 | 88 | HttpRequest.getString("/saga/code.asm").then(app.display); 89 | } -------------------------------------------------------------------------------- /saga/web/styles.css: -------------------------------------------------------------------------------- 1 | /* Copyright 2015 Google Inc. All Rights Reserved. 2 | ** 3 | ** Licensed under the Apache License, Version 2.0 (the "License"); 4 | ** you may not use this file except in compliance with the License. 5 | ** You may obtain a copy of the License at 6 | ** 7 | ** http://www.apache.org/licenses/LICENSE-2.0 8 | ** 9 | ** Unless required by applicable law or agreed to in writing, software 10 | ** distributed under the License is distributed on an "AS IS" BASIS, 11 | ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | ** See the License for the specific language governing permissions and 13 | ** limitations under the License. 14 | */ 15 | 16 | .saga-root pre { 17 | font-family: 'Inconsolata', monospace; 18 | font-size: 14pt; 19 | background: #fdf6e3; 20 | color: #657b83 !important; 21 | line-height: 1.428571429; 22 | cursor: default; 23 | } 24 | 25 | .saga-flex { 26 | display: -ms-flex; 27 | display: -webkit-flex; 28 | display: flex; 29 | background: #fdf6e3; 30 | } 31 | 32 | .saga-app { 33 | display: -ms-flex; 34 | display: -webkit-flex; 35 | display: flex; 36 | width: 100%; 37 | max-height: 100%; 38 | position: fixed; 39 | display: flex; 40 | top: 0px; 41 | left: 0px; 42 | right: 0px; 43 | bottom: 0px; 44 | } 45 | 46 | .saga-flex > * { 47 | width: 100%; 48 | padding: 10px; 49 | margin: 0px; 50 | } 51 | 52 | .saga-app > * { 53 | width: 100%; 54 | padding: 10px; 55 | overflow-y: scroll; 56 | margin: 0px; 57 | position: relative; 58 | } 59 | 60 | .asm-immediate, 61 | .ir-node-konstant { 62 | color: #2aa198; 63 | } 64 | 65 | .asm-call-target { 66 | color: #d33682; 67 | cursor: pointer; 68 | } 69 | 70 | .asm-opcode { 71 | color: #859900; 72 | } 73 | 74 | .asm-register { 75 | color: #657b83; 76 | cursor: pointer; 77 | } 78 | 79 | .asm-label, 80 | .ir-block-name { 81 | color: #268bd2; 82 | } 83 | 84 | .asm-call-target .popover { 85 | background: #002b36; 86 | } 87 | 88 | .asm-call-target .popover.top .arrow:after { 89 | border-top-color: #002b36; 90 | } 91 | 92 | .asm-call-target button[data-attr] { 93 | background: none !important; 94 | border: none; 95 | padding: 0 !important; 96 | font-family: 'Inconsolata', monospace; 97 | cursor: pointer; 98 | color: #839496; 99 | font-size: 13pt; 100 | } 101 | 102 | .asm-call-target button[data-attr]:not(.set) { 103 | text-decoration: line-through; 104 | } 105 | 106 | .inline-marker, .outline-marker { 107 | display: none; 108 | cursor: pointer; 109 | } 110 | 111 | .inline-marker:hover, .ir-use:hover > .inline-marker { 112 | display: inline-block; 113 | } 114 | 115 | .node-body-hover { 116 | text-decoration: underline; 117 | } 118 | 119 | .node-body-hover > .outline-marker { 120 | display: inline-block; 121 | } 122 | 123 | .single-use { 124 | color: #859900; 125 | } 126 | 127 | .ir-node-keyword { 128 | color: #859900; 129 | } 130 | 131 | .ir-node-op { 132 | color: #268bd2; 133 | } 134 | 135 | .ir-block-body { 136 | padding-left: 10px; 137 | } 138 | 139 | .ir-node-name { 140 | cursor: pointer; 141 | } 142 | 143 | .graph-pane { 144 | margin-left: auto; 145 | margin-right: auto; 146 | } 147 | 148 | .invalid-name { 149 | color: #dc322f; 150 | font-weight: bold; 151 | } 152 | 153 | .tooltip-def { 154 | font-size: 0.95em; 155 | font-style: italic; 156 | } -------------------------------------------------------------------------------- /ui_components/.gitignore: -------------------------------------------------------------------------------- 1 | .buildlog 2 | .DS_Store 3 | .idea 4 | .pub/ 5 | build/ 6 | packages 7 | pubspec.lock 8 | -------------------------------------------------------------------------------- /ui_components/lib/components/graph-pane.dart: -------------------------------------------------------------------------------- 1 | // Copyright 2014 Google Inc. All Rights Reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | library graph_pane; 16 | 17 | import 'dart:html'; 18 | import 'package:ui_utils/task.dart'; 19 | import 'package:ui_utils/graph_layout.dart' as graphview; 20 | import 'package:polymer/polymer.dart'; 21 | 22 | class HoverDetail { 23 | final label; 24 | final blockId; 25 | HoverDetail(this.label, this.blockId); 26 | } 27 | 28 | /** 29 | * Two column WebComponent used to display IRs and native code line by line. 30 | * 31 | * Individual lines or whole ranges can have an identifier associated with them 32 | * that allows to access these lines content as HTML, apply styles or reference 33 | * them by an [AnchorElement]. 34 | * 35 | * First column *gutter* is used to display identifier e.g. block name, 36 | * SSA name or instruction's offset. 37 | * 38 | * Second column is for line's content e.g. instruction body itself. 39 | */ 40 | @CustomTag('graph-pane') 41 | class GraphPane extends PolymerElement { 42 | @published var ir; 43 | 44 | var _renderTask; 45 | 46 | GraphPane.created() : super.created() { 47 | _renderTask = new Task(render, frozen: true); 48 | } 49 | 50 | attached() { 51 | super.attached(); 52 | _renderTask.unfreeze(); 53 | } 54 | 55 | irChanged() => _renderTask.schedule(); 56 | 57 | clear() => $["graph"].nodes.clear(); 58 | 59 | showLegend() { 60 | $["legend"].open(); 61 | } 62 | 63 | render() { 64 | if (ir == null) { 65 | return; 66 | } 67 | 68 | final stopwatch = new Stopwatch()..start(); 69 | graphview.display($["graph"], ir.blocks, (label, blockId) { 70 | label.onMouseOver.listen((event) => fire("block-mouse-over", detail: new HoverDetail(event.target, blockId))); 71 | label.onMouseOut.listen((_) => fire("block-mouse-out")); 72 | label.onClick.listen((event) { 73 | // TODO(mraleph): Shadow DOM polyfill seems to be interfering with links in SVG. Have to switch manually. 74 | (document.window.location as Location).hash = "ir-${blockId}"; 75 | }); 76 | }, blockTicks: ir.blockTicks); 77 | print("GraphPane.render() took ${stopwatch.elapsedMilliseconds}"); 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /ui_components/pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: ui_components 2 | version: 0.0.1 3 | dependencies: 4 | core_elements: any 5 | polymer: any 6 | transformers: 7 | - polymer: 8 | entry_points: [] -------------------------------------------------------------------------------- /ui_utils/.analysis_options: -------------------------------------------------------------------------------- 1 | analyzer: 2 | strong-mode: true 3 | -------------------------------------------------------------------------------- /ui_utils/.gitignore: -------------------------------------------------------------------------------- 1 | .buildlog 2 | .DS_Store 3 | .idea 4 | .pub/ 5 | build/ 6 | packages 7 | pubspec.lock 8 | -------------------------------------------------------------------------------- /ui_utils/lib/assets/bootstrap/fonts/glyphicons-halflings-regular.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mraleph/irhydra/7297e3e320ba1e55f98483b2d35078f4ccc8ee6d/ui_utils/lib/assets/bootstrap/fonts/glyphicons-halflings-regular.eot -------------------------------------------------------------------------------- /ui_utils/lib/assets/bootstrap/fonts/glyphicons-halflings-regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mraleph/irhydra/7297e3e320ba1e55f98483b2d35078f4ccc8ee6d/ui_utils/lib/assets/bootstrap/fonts/glyphicons-halflings-regular.ttf -------------------------------------------------------------------------------- /ui_utils/lib/assets/bootstrap/fonts/glyphicons-halflings-regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mraleph/irhydra/7297e3e320ba1e55f98483b2d35078f4ccc8ee6d/ui_utils/lib/assets/bootstrap/fonts/glyphicons-halflings-regular.woff -------------------------------------------------------------------------------- /ui_utils/lib/assets/jquery/css/ui-lightness/images/animated-overlay.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mraleph/irhydra/7297e3e320ba1e55f98483b2d35078f4ccc8ee6d/ui_utils/lib/assets/jquery/css/ui-lightness/images/animated-overlay.gif -------------------------------------------------------------------------------- /ui_utils/lib/assets/jquery/css/ui-lightness/images/ui-bg_diagonals-thick_18_b81900_40x40.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mraleph/irhydra/7297e3e320ba1e55f98483b2d35078f4ccc8ee6d/ui_utils/lib/assets/jquery/css/ui-lightness/images/ui-bg_diagonals-thick_18_b81900_40x40.png -------------------------------------------------------------------------------- /ui_utils/lib/assets/jquery/css/ui-lightness/images/ui-bg_diagonals-thick_20_666666_40x40.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mraleph/irhydra/7297e3e320ba1e55f98483b2d35078f4ccc8ee6d/ui_utils/lib/assets/jquery/css/ui-lightness/images/ui-bg_diagonals-thick_20_666666_40x40.png -------------------------------------------------------------------------------- /ui_utils/lib/assets/jquery/css/ui-lightness/images/ui-bg_flat_10_000000_40x100.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mraleph/irhydra/7297e3e320ba1e55f98483b2d35078f4ccc8ee6d/ui_utils/lib/assets/jquery/css/ui-lightness/images/ui-bg_flat_10_000000_40x100.png -------------------------------------------------------------------------------- /ui_utils/lib/assets/jquery/css/ui-lightness/images/ui-bg_glass_100_f6f6f6_1x400.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mraleph/irhydra/7297e3e320ba1e55f98483b2d35078f4ccc8ee6d/ui_utils/lib/assets/jquery/css/ui-lightness/images/ui-bg_glass_100_f6f6f6_1x400.png -------------------------------------------------------------------------------- /ui_utils/lib/assets/jquery/css/ui-lightness/images/ui-bg_glass_100_fdf5ce_1x400.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mraleph/irhydra/7297e3e320ba1e55f98483b2d35078f4ccc8ee6d/ui_utils/lib/assets/jquery/css/ui-lightness/images/ui-bg_glass_100_fdf5ce_1x400.png -------------------------------------------------------------------------------- /ui_utils/lib/assets/jquery/css/ui-lightness/images/ui-bg_glass_65_ffffff_1x400.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mraleph/irhydra/7297e3e320ba1e55f98483b2d35078f4ccc8ee6d/ui_utils/lib/assets/jquery/css/ui-lightness/images/ui-bg_glass_65_ffffff_1x400.png -------------------------------------------------------------------------------- /ui_utils/lib/assets/jquery/css/ui-lightness/images/ui-bg_gloss-wave_35_f6a828_500x100.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mraleph/irhydra/7297e3e320ba1e55f98483b2d35078f4ccc8ee6d/ui_utils/lib/assets/jquery/css/ui-lightness/images/ui-bg_gloss-wave_35_f6a828_500x100.png -------------------------------------------------------------------------------- /ui_utils/lib/assets/jquery/css/ui-lightness/images/ui-bg_highlight-soft_100_eeeeee_1x100.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mraleph/irhydra/7297e3e320ba1e55f98483b2d35078f4ccc8ee6d/ui_utils/lib/assets/jquery/css/ui-lightness/images/ui-bg_highlight-soft_100_eeeeee_1x100.png -------------------------------------------------------------------------------- /ui_utils/lib/assets/jquery/css/ui-lightness/images/ui-bg_highlight-soft_75_ffe45c_1x100.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mraleph/irhydra/7297e3e320ba1e55f98483b2d35078f4ccc8ee6d/ui_utils/lib/assets/jquery/css/ui-lightness/images/ui-bg_highlight-soft_75_ffe45c_1x100.png -------------------------------------------------------------------------------- /ui_utils/lib/assets/jquery/css/ui-lightness/images/ui-icons_222222_256x240.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mraleph/irhydra/7297e3e320ba1e55f98483b2d35078f4ccc8ee6d/ui_utils/lib/assets/jquery/css/ui-lightness/images/ui-icons_222222_256x240.png -------------------------------------------------------------------------------- /ui_utils/lib/assets/jquery/css/ui-lightness/images/ui-icons_228ef1_256x240.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mraleph/irhydra/7297e3e320ba1e55f98483b2d35078f4ccc8ee6d/ui_utils/lib/assets/jquery/css/ui-lightness/images/ui-icons_228ef1_256x240.png -------------------------------------------------------------------------------- /ui_utils/lib/assets/jquery/css/ui-lightness/images/ui-icons_ef8c08_256x240.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mraleph/irhydra/7297e3e320ba1e55f98483b2d35078f4ccc8ee6d/ui_utils/lib/assets/jquery/css/ui-lightness/images/ui-icons_ef8c08_256x240.png -------------------------------------------------------------------------------- /ui_utils/lib/assets/jquery/css/ui-lightness/images/ui-icons_ffd27a_256x240.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mraleph/irhydra/7297e3e320ba1e55f98483b2d35078f4ccc8ee6d/ui_utils/lib/assets/jquery/css/ui-lightness/images/ui-icons_ffd27a_256x240.png -------------------------------------------------------------------------------- /ui_utils/lib/assets/jquery/css/ui-lightness/images/ui-icons_ffffff_256x240.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mraleph/irhydra/7297e3e320ba1e55f98483b2d35078f4ccc8ee6d/ui_utils/lib/assets/jquery/css/ui-lightness/images/ui-icons_ffffff_256x240.png -------------------------------------------------------------------------------- /ui_utils/lib/assets/tooltip.css: -------------------------------------------------------------------------------- 1 | /*! 2 | * Bootstrap v3.0.2 by @fat and @mdo 3 | * Copyright 2014 Twitter, Inc. 4 | * Licensed under http://www.apache.org/licenses/LICENSE-2.0 5 | * 6 | * Designed and built with all the love in the world by @mdo and @fat. 7 | */ 8 | 9 | .popover { 10 | position: absolute; 11 | top: 0; 12 | left: 0; 13 | z-index: 1010; 14 | display: none; 15 | max-width: 276px; 16 | padding: 1px; 17 | text-align: left; 18 | white-space: normal; 19 | background-color: #ffffff; 20 | border: 1px solid #cccccc; 21 | border: 1px solid rgba(0, 0, 0, 0.2); 22 | border-radius: 6px; 23 | -webkit-box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2); 24 | box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2); 25 | background-clip: padding-box; 26 | } 27 | 28 | .popover.top { 29 | margin-top: -10px; 30 | } 31 | 32 | .popover.right { 33 | margin-left: 10px; 34 | } 35 | 36 | .popover.bottom { 37 | margin-top: 10px; 38 | } 39 | 40 | .popover.left { 41 | margin-left: -10px; 42 | } 43 | 44 | .popover-title { 45 | padding: 8px 14px; 46 | margin: 0; 47 | font-size: 14px; 48 | font-weight: normal; 49 | line-height: 18px; 50 | background-color: #f7f7f7; 51 | border-bottom: 1px solid #ebebeb; 52 | border-radius: 5px 5px 0 0; 53 | } 54 | 55 | .popover-content { 56 | padding: 9px 14px; 57 | } 58 | 59 | .popover .arrow, 60 | .popover .arrow:after { 61 | position: absolute; 62 | display: block; 63 | width: 0; 64 | height: 0; 65 | border-color: transparent; 66 | border-style: solid; 67 | } 68 | 69 | .popover .arrow { 70 | border-width: 11px; 71 | } 72 | 73 | .popover .arrow:after { 74 | border-width: 10px; 75 | content: ""; 76 | } 77 | 78 | .popover.top .arrow { 79 | bottom: -11px; 80 | left: 50%; 81 | margin-left: -11px; 82 | border-top-color: #999999; 83 | border-top-color: rgba(0, 0, 0, 0.25); 84 | border-bottom-width: 0; 85 | } 86 | 87 | .popover.top .arrow:after { 88 | bottom: 1px; 89 | margin-left: -10px; 90 | border-top-color: #ffffff; 91 | border-bottom-width: 0; 92 | content: " "; 93 | } 94 | 95 | .popover.right .arrow { 96 | top: 50%; 97 | left: -11px; 98 | margin-top: -11px; 99 | border-right-color: #999999; 100 | border-right-color: rgba(0, 0, 0, 0.25); 101 | border-left-width: 0; 102 | } 103 | 104 | .popover.right .arrow:after { 105 | bottom: -10px; 106 | left: 1px; 107 | border-right-color: #ffffff; 108 | border-left-width: 0; 109 | content: " "; 110 | } 111 | 112 | .popover.bottom .arrow { 113 | top: -11px; 114 | left: 50%; 115 | margin-left: -11px; 116 | border-bottom-color: #999999; 117 | border-bottom-color: rgba(0, 0, 0, 0.25); 118 | border-top-width: 0; 119 | } 120 | 121 | .popover.bottom .arrow:after { 122 | top: 1px; 123 | margin-left: -10px; 124 | border-bottom-color: #ffffff; 125 | border-top-width: 0; 126 | content: " "; 127 | } 128 | 129 | .popover.left .arrow { 130 | top: 50%; 131 | right: -11px; 132 | margin-top: -11px; 133 | border-left-color: #999999; 134 | border-left-color: rgba(0, 0, 0, 0.25); 135 | border-right-width: 0; 136 | } 137 | 138 | .popover.left .arrow:after { 139 | right: 1px; 140 | bottom: -10px; 141 | border-left-color: #ffffff; 142 | border-right-width: 0; 143 | content: " "; 144 | } -------------------------------------------------------------------------------- /ui_utils/lib/assets/xref.css: -------------------------------------------------------------------------------- 1 | /* Copyright 2015 Google Inc. All Rights Reserved. 2 | ** 3 | ** Licensed under the Apache License, Version 2.0 (the "License"); 4 | ** you may not use this file except in compliance with the License. 5 | ** You may obtain a copy of the License at 6 | ** 7 | ** http://www.apache.org/licenses/LICENSE-2.0 8 | ** 9 | ** Unless required by applicable law or agreed to in writing, software 10 | ** distributed under the License is distributed on an "AS IS" BASIS, 11 | ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | ** See the License for the specific language governing permissions and 13 | ** limitations under the License. 14 | */ 15 | 16 | .xref .tooltip-inner { 17 | max-width: 100% !important; 18 | } 19 | 20 | .tooltip.in.xref { 21 | opacity: 1 !important; 22 | } 23 | 24 | .tooltip.xref pre, .popover.xref pre { 25 | -moz-border-radius: 0; 26 | -webkit-border-radius: 0; 27 | -o-border-radius: 0; 28 | border-radius: 0; 29 | border-width: 0; 30 | margin: 0; 31 | padding: 0; 32 | background: transparent; 33 | font-size: 12pt; 34 | word-wrap: normal; 35 | color: inherit; 36 | } 37 | 38 | .popover.xref { 39 | max-width: 100% !important; 40 | } 41 | 42 | -------------------------------------------------------------------------------- /ui_utils/lib/bootstrap.dart: -------------------------------------------------------------------------------- 1 | // Copyright 2015 Google Inc. All Rights Reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | library bootstrap; 16 | 17 | import "dart:js" as js; 18 | 19 | js.JsObject jQuery(target) => 20 | js.context.callMethod('jQuery', [target]); 21 | 22 | Data popover(target, [options]) => 23 | new Data.of(jQuery(target).callMethod('popover', options != null ? [_toJs(options)] : null), 'bs.popover'); 24 | 25 | Data tooltip(target, [options]) => 26 | new Data.of(jQuery(target).callMethod('tooltip', options != null ? [_toJs(options)] : null), 'bs.tooltip'); 27 | 28 | class Data { 29 | final js.JsObject _data; 30 | 31 | Data.of(js.JsObject obj, id) 32 | : _data = obj.callMethod('data', [id]); 33 | 34 | get tip => _data.callMethod('tip').callMethod('get', [0]); 35 | 36 | addTipClass(String name) => _data.callMethod('tip').callMethod('addClass', [name]); 37 | 38 | show() => _data.callMethod('show'); 39 | 40 | hide() => _data.callMethod('hide'); 41 | 42 | destroy() => _data.callMethod('destroy'); 43 | } 44 | 45 | _toJs(val) => 46 | (val is Map || val is Iterable) ? new js.JsObject.jsify(val) : val; 47 | -------------------------------------------------------------------------------- /ui_utils/lib/brewer.dart: -------------------------------------------------------------------------------- 1 | // Copyright 2014 Google Inc. All Rights Reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | /** Selecting colors from the brewer palette. */ 16 | library ui.brewer; 17 | 18 | import 'dart:math' as math; 19 | 20 | /** Palette generated by http://www.colorbrewer2.org/. */ 21 | final PALETTE = [ 22 | /* "#FFF5F0", "#FEE0D2" ,*/ "#FCBBA1", "#FC9272", "#FB6A4A", 23 | "#EF3B2C", "#CB181D", "#A50F15", "#67000D" 24 | ]; 25 | 26 | colorFor(value, min, max) { 27 | final ratio = (value - min) / (max - min); 28 | return PALETTE[ 29 | math.min((ratio * PALETTE.length).ceil(), 30 | PALETTE.length - 1)]; 31 | 32 | } -------------------------------------------------------------------------------- /ui_utils/lib/delayed_reaction.dart: -------------------------------------------------------------------------------- 1 | // Copyright 2013 Google Inc. All Rights Reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | /** Scheduling actions with a delay. */ 16 | library delayed_reaction; 17 | 18 | import "dart:async"; 19 | 20 | /** 21 | * Utility class that allows to schedule an action callback with a fixed delay. 22 | * Scheduling an action before schduled one fired evicts pending action. 23 | */ 24 | class DelayedReaction { 25 | /** Default delay */ 26 | static const DEFAULT_DELAY = const Duration(milliseconds: 500); 27 | 28 | final delay; 29 | 30 | /** Timer for the currently pending action. */ 31 | var timer; 32 | 33 | DelayedReaction({this.delay: DEFAULT_DELAY}); 34 | 35 | /** 36 | * Schedule an [action] callback. If there is already an action pending 37 | * it will be evicted. 38 | */ 39 | schedule(action) => _setTimer(new Timer(delay, () => action())); 40 | 41 | /** Cancel pending action if any. */ 42 | cancel() => _setTimer(null); 43 | 44 | /** Replace the currently pending timer. */ 45 | _setTimer(new_timer) { 46 | if (timer != null) { 47 | timer.cancel(); 48 | } 49 | timer = new_timer; 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /ui_utils/lib/graph.dart: -------------------------------------------------------------------------------- 1 | // Copyright 2013 Google Inc. All Rights Reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | /** Control flow graph */ 16 | library graph; 17 | 18 | final _EMPTY_MARKS = new Set(); 19 | 20 | /** Block in the control flow graph. */ 21 | class BasicBlock { 22 | /** Block's number in a sequence of blocks. */ 23 | int id; 24 | 25 | String name; 26 | 27 | final List successors = []; 28 | final List predecessors = []; 29 | 30 | int unlikely = 0; 31 | 32 | Set marks = _EMPTY_MARKS; 33 | 34 | BasicBlock(this.id, this.name) { 35 | assert(id >= 0); 36 | } 37 | 38 | toString() => name; 39 | 40 | /** Creates an edge from this [BasicBlock] to the block [to]. */ 41 | edge(BasicBlock to, {unlikely: false}) { 42 | to.predecessors.add(this); 43 | successors.add(to); 44 | if (unlikely) { 45 | this.unlikely |= 1 << (successors.length - 1); 46 | } 47 | } 48 | 49 | isUnlikelySuccessor(BasicBlock block) => 50 | unlikely != 0 && (unlikely & (1 << successors.indexOf(block))) != 0; 51 | 52 | mark(tag) { 53 | if (identical(marks, _EMPTY_MARKS)) { 54 | marks = new Set(); 55 | } 56 | marks.add(tag); 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /ui_utils/lib/html_utils.dart: -------------------------------------------------------------------------------- 1 | // Copyright 2013 Google Inc. All Rights Reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | /** Simple helpers for HTML building. */ 16 | library html_utils; 17 | 18 | import 'dart:html'; 19 | 20 | /** Wrap [text] into a [SpanElement] with the given [klass]. */ 21 | span(String klass, String text) => 22 | new SpanElement()..classes.add(klass)..appendText(text); 23 | 24 | /** Escape special HTML characters in the given [text] string. */ 25 | escapeHtml(String text) => 26 | (new SpanElement()..appendText(text)).innerHtml; 27 | 28 | /** Get HTML representation of the given [Element] [e]. */ 29 | toHtml(Element e) { 30 | final parent = e.parent; 31 | if (parent != null && parent.nodes.length == 1) { 32 | return parent.innerHtml; 33 | } 34 | final insertable = parent == null ? e : e.clone(true); 35 | return (new DivElement()..append(insertable)).innerHtml; 36 | } -------------------------------------------------------------------------------- /ui_utils/lib/src/draw2d/CollapsedEdges.dart: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2005, 2010 IBM Corporation and others. 3 | * All rights reserved. This program and the accompanying materials 4 | * are made available under the terms of the Eclipse Public License v1.0 5 | * which accompanies this distribution, and is available at 6 | * http://www.eclipse.org/legal/epl-v10.html 7 | * Contributors: 8 | * IBM Corporation - initial API and implementation 9 | */ 10 | 11 | part of draw2d.graph; 12 | 13 | /** 14 | * Contains the information from all edges going from a given cluster to some 15 | * other cluster. An edge with minimal slack as chosen to maintain the link 16 | * between clusters. The weight and any slack more than the minimal edge's slack 17 | * is tracked for all other edges. 18 | * @since 3.1 19 | */ 20 | class CollapsedEdges { 21 | /** 22 | * The total weight of the collapsed edges. 23 | */ 24 | int collapsedWeight = 0; 25 | int collapsedCount = 0; 26 | 27 | /** 28 | * The total amount of weighted difference in the collapsed edges slack and 29 | * the tightest edge's slack. 30 | */ 31 | int overage = 0; 32 | int unOverage = 0; 33 | Edge tightestEdge; 34 | 35 | CollapsedEdges(Edge edge) 36 | : tightestEdge = edge, 37 | collapsedWeight = edge.weight, 38 | collapsedCount = 1; 39 | 40 | int get weightedPull => 41 | tightestEdge.slack * collapsedWeight + overage; 42 | 43 | bool get isTight => 44 | tightestEdge.slack == 0; 45 | 46 | /** 47 | * Compares the given edge to the current tightest edge. If the given edge 48 | * is tighter than the current, the current tightest is returned. Otherwise, 49 | * the edge itself is returned. The returned edge would be the one to remove 50 | * from the graph. 51 | * @param candidateanother edge 52 | * @return the edge which is not the tightest edge 53 | * @since 3.1 54 | */ 55 | Edge processEdge(Edge candidate) { 56 | collapsedCount++; 57 | if (candidate.slack < tightestEdge.slack) { 58 | overage += collapsedWeight * (tightestEdge.slack - candidate.slack); 59 | Edge temp = tightestEdge; 60 | tightestEdge = candidate; 61 | collapsedWeight += candidate.weight; 62 | return temp; 63 | } else { 64 | int over = candidate.slack - tightestEdge.slack; 65 | unOverage += over; 66 | overage += candidate.weight * over; 67 | collapsedWeight += candidate.weight; 68 | return candidate; 69 | } 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /ui_utils/lib/src/draw2d/CompoundDirectedGraph.dart: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2003, 2010 IBM Corporation and others. 3 | * All rights reserved. This program and the accompanying materials 4 | * are made available under the terms of the Eclipse Public License v1.0 5 | * which accompanies this distribution, and is available at 6 | * http://www.eclipse.org/legal/epl-v10.html 7 | * Contributors: 8 | * IBM Corporation - initial API and implementation 9 | */ 10 | 11 | part of draw2d.graph; 12 | 13 | /** 14 | * A DirectedGraph whose Nodes may be compound {@link Subgraph}s, 15 | * which may contain other nodes. Any node in the graph may be parented by one 16 | * subgraph. Since subgraphs are nodes, the source or target end of an 17 | * {@link Edge} may be a subgraph. For additional restrictions, refer to the 18 | * JavaDoc for the layout algorithm being used. 19 | *

20 | * A CompoundDirectedGraph is passed to a graph layout, which will position all 21 | * of the nodes, subgraphs, and edges in that graph. This class serves as the 22 | * data structure for a layout algorithm. 23 | * 24 | * @author Randy Hudson 25 | * @since 2.1.2 26 | */ 27 | class CompoundDirectedGraph extends DirectedGraph { 28 | NodeList subgraphs = new NodeList(); 29 | EdgeList containment = new EdgeList(); 30 | } 31 | -------------------------------------------------------------------------------- /ui_utils/lib/src/draw2d/CompoundDirectedGraphLayout.dart: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2003, 2010 IBM Corporation and others. 3 | * All rights reserved. This program and the accompanying materials 4 | * are made available under the terms of the Eclipse Public License v1.0 5 | * which accompanies this distribution, and is available at 6 | * http://www.eclipse.org/legal/epl-v10.html 7 | * Contributors: 8 | * IBM Corporation - initial API and implementation 9 | */ 10 | 11 | part of draw2d.graph; 12 | 13 | /** 14 | * Performs a graph layout on a CompoundDirectedGraph. The input 15 | * format is the same as for {@link DirectedGraphLayout}. All nodes, including 16 | * subgraphs and their children, should be added to the 17 | * {@link DirectedGraph#nodes} field. 18 | *

19 | * The requirements for this algorithm are the same as those of 20 | * DirectedGraphLayout, with the following exceptions: 21 | *

    22 | *
  • There is an implied edge between a subgraph and each of its member nodes. 23 | * These edges form the containment graph T. Thus, the compound 24 | * directed graph CG is said to be connected iff Union(G, 25 | * T) is connected, where G represents the given nodes (including 26 | * subgraphs) and edges. 27 | * 28 | *
  • This algorithm will remove any compound cycles found in the input graph 29 | * G by inverting edges according to a heuristic until no more cycles 30 | * are found. A compound cycle is defined as: a cycle comprised of edges from 31 | * G, T, and T-1, in the form 32 | * (c*e+p*e+)*, where 33 | * T-1 is the backwards graph of T, c element of T, 34 | * e element of G, and p element of T-1. 35 | *
36 | * 37 | * @author Randy Hudson 38 | * @since 2.1.2 39 | */ 40 | class CompoundDirectedGraphLayout extends DirectedGraphLayout { 41 | 42 | void init() { 43 | steps.add(new CompoundTransposeMetrics()); 44 | steps.add(new CompoundBreakCycles()); 45 | steps.add(new RouteEdges()); 46 | steps.add(new ConvertCompoundGraph()); 47 | steps.add(new InitialRankSolver()); 48 | steps.add(new TightSpanningTreeSolver()); 49 | steps.add(new RankAssignmentSolver()); 50 | steps.add(new CompoundPopulateRanks()); 51 | steps.add(new CompoundVerticalPlacement()); 52 | steps.add(new MinCross(new CompoundRankSorter())); 53 | steps.add(new SortSubgraphs()); 54 | steps.add(new CompoundHorizontalPlacement()); 55 | } 56 | 57 | } 58 | -------------------------------------------------------------------------------- /ui_utils/lib/src/draw2d/CompoundPopulateRanks.dart: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2003, 2010 IBM Corporation and others. 3 | * All rights reserved. This program and the accompanying materials 4 | * are made available under the terms of the Eclipse Public License v1.0 5 | * which accompanies this distribution, and is available at 6 | * http://www.eclipse.org/legal/epl-v10.html 7 | * Contributors: 8 | * IBM Corporation - initial API and implementation 9 | */ 10 | 11 | part of draw2d.graph; 12 | 13 | /** 14 | * Places nodes into ranks for a compound directed graph. If a subgraph spans a 15 | * rank without any nodes which belong to that rank, a bridge node is inserted 16 | * to prevent nodes from violating the subgraph boundary. 17 | * 18 | * @author Randy Hudson 19 | * @since 2.1.2 20 | */ 21 | class CompoundPopulateRanks extends PopulateRanks { 22 | 23 | void visit(CompoundDirectedGraph graph) { 24 | /** 25 | * Remove long containment edges at this point so they don't affect 26 | * MinCross. 27 | */ 28 | for (var e in graph.containment.where((e) => e.slack > 0)) { 29 | graph.removeEdge(e); 30 | } 31 | graph.containment.removeWhere((e) => e.slack > 0); 32 | 33 | super.visit(graph); 34 | 35 | for (var subgraph in graph.subgraphs) { 36 | bridgeSubgraph(subgraph, graph); 37 | } 38 | } 39 | 40 | /** 41 | * @param subgraph 42 | */ 43 | void bridgeSubgraph(Subgraph subgraph, CompoundDirectedGraph g) { 44 | int offset = subgraph.head.rank; 45 | List occupied = new List.filled(subgraph.tail.rank - subgraph.head.rank + 1, false); 46 | List bridge = new List(occupied.length); 47 | 48 | for (var n in subgraph.members) { 49 | if (n is Subgraph) { 50 | for (int r = n.head.rank; r <= n.tail.rank; r++) 51 | occupied[r - offset] = true; 52 | } else 53 | occupied[n.rank - offset] = true; 54 | } 55 | 56 | for (int i = 0; i < bridge.length; i++) { 57 | if (!occupied[i]) { 58 | Node br = bridge[i] = new Node(data: "bridge", parent: subgraph); //$NON-NLS-1$ 59 | br.rank = i + offset; 60 | br.height = br.width = 0; 61 | br.nestingIndex = subgraph.nestingIndex; 62 | g.ranks[br.rank].add(br); 63 | g.nodes.add(br); 64 | } 65 | } 66 | } 67 | 68 | } 69 | -------------------------------------------------------------------------------- /ui_utils/lib/src/draw2d/CompoundTransposeMetrics.dart: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2003, 2010 IBM Corporation and others. 3 | * All rights reserved. This program and the accompanying materials 4 | * are made available under the terms of the Eclipse Public License v1.0 5 | * which accompanies this distribution, and is available at 6 | * http://www.eclipse.org/legal/epl-v10.html 7 | * Contributors: 8 | * IBM Corporation - initial API and implementation 9 | */ 10 | 11 | part of draw2d.graph; 12 | 13 | /** 14 | * Performs transposing of subgraphics in a compound directed graph. 15 | * 16 | * @since 3.7.1 17 | */ 18 | class CompoundTransposeMetrics extends TransposeMetrics { 19 | 20 | void visit(DirectedGraph g) { 21 | if (g.getDirection() == PositionConstants.SOUTH) 22 | return; 23 | super.visit(g); 24 | int temp; 25 | CompoundDirectedGraph cg = g; 26 | for (int i = 0; i < cg.subgraphs.length; i++) { 27 | Node node = cg.subgraphs[i]; 28 | temp = node.width; 29 | node.width = node.height; 30 | node.height = temp; 31 | if (node.padding != null) 32 | node.padding = node.padding.getTransposed(); 33 | } 34 | } 35 | 36 | void revisit(DirectedGraph g) { 37 | if (g.getDirection() == PositionConstants.SOUTH) 38 | return; 39 | super.revisit(g); 40 | int temp; 41 | CompoundDirectedGraph cg = g; 42 | for (int i = 0; i < cg.subgraphs.length; i++) { 43 | Node node = cg.subgraphs[i]; 44 | temp = node.width; 45 | node.width = node.height; 46 | node.height = temp; 47 | temp = node.y; 48 | node.y = node.x; 49 | node.x = temp; 50 | if (node.padding != null) 51 | node.padding = node.padding.getTransposed(); 52 | } 53 | } 54 | 55 | } -------------------------------------------------------------------------------- /ui_utils/lib/src/draw2d/CompoundVerticalPlacement.dart: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2003, 2010 IBM Corporation and others. 3 | * All rights reserved. This program and the accompanying materials 4 | * are made available under the terms of the Eclipse Public License v1.0 5 | * which accompanies this distribution, and is available at 6 | * http://www.eclipse.org/legal/epl-v10.html 7 | * Contributors: 8 | * IBM Corporation - initial API and implementation 9 | */ 10 | 11 | part of draw2d.graph; 12 | 13 | /** 14 | * calculates the height and y-coordinates for nodes and subgraphs in a compound 15 | * directed graph. 16 | * 17 | * @author Randy Hudson 18 | * @since 2.1.2 19 | */ 20 | class CompoundVerticalPlacement extends VerticalPlacement { 21 | 22 | /** 23 | * @see GraphVisitor#visit(DirectedGraph) Extended to set subgraph values. 24 | */ 25 | void visit(CompoundDirectedGraph g) { 26 | super.visit(g); 27 | for (Subgraph s in g.subgraphs) { 28 | s.y = s.head.y; 29 | s.height = s.tail.height + s.tail.y - s.y; 30 | } 31 | } 32 | 33 | } 34 | -------------------------------------------------------------------------------- /ui_utils/lib/src/draw2d/Dimension.dart: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2000, 2010 IBM Corporation and others. 3 | * All rights reserved. This program and the accompanying materials 4 | * are made available under the terms of the Eclipse Public License v1.0 5 | * which accompanies this distribution, and is available at 6 | * http://www.eclipse.org/legal/epl-v10.html 7 | * Contributors: 8 | * IBM Corporation - initial API and implementation 9 | */ 10 | 11 | 12 | part of draw2d.graph; 13 | 14 | /** 15 | * Stores an integer width and height. This class provides various methods for 16 | * manipulating this Dimension or creating new derived Objects. 17 | */ 18 | class Dimension { 19 | int width = 0; 20 | int height = 0; 21 | 22 | Dimension(int this.width, int this.height); 23 | 24 | /** 25 | * Returns whether the input Object is equivalent to this Dimension. 26 | * true if the Object is a Dimension and its width and height 27 | * are equal to this Dimension's width and height, false 28 | * otherwise. 29 | * @param othe Object being tested for equality 30 | * @return true if the given object is equal to this dimension 31 | * @since 2.0 32 | */ 33 | 34 | bool operator == (Object o) { 35 | if (o is Dimension) { 36 | return (o.width == width && o.height == height); 37 | } 38 | 39 | return false; 40 | } 41 | 42 | /** 43 | * @see java.lang.Object#hashCode() 44 | */ 45 | int get hashCode { 46 | return (width * height) ^ (width + height); 47 | } 48 | 49 | /** 50 | * @see Object#toString() 51 | */ 52 | String toString() { 53 | return "Dimension(${width}, ${height})"; 54 | } 55 | 56 | /** 57 | * Swaps the width and height of this Dimension, and returns this for 58 | * convenience. Can be useful in orientation changes. 59 | * @return this for convenience 60 | * @since 2.0 61 | */ 62 | Dimension transpose() { 63 | int temp = width; 64 | width = height; 65 | height = temp; 66 | return this; 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /ui_utils/lib/src/draw2d/EdgeList.dart: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2003, 2010 IBM Corporation and others. 3 | * All rights reserved. This program and the accompanying materials 4 | * are made available under the terms of the Eclipse Public License v1.0 5 | * which accompanies this distribution, and is available at 6 | * http://www.eclipse.org/legal/epl-v10.html 7 | * Contributors: 8 | * IBM Corporation - initial API and implementation 9 | */ 10 | 11 | part of draw2d.graph; 12 | 13 | /** 14 | * A list of Edges. 15 | * @author hudsonr 16 | * @since 2.1.2 17 | */ 18 | class EdgeList extends ListBase { 19 | int getSourceIndex(int i) { 20 | return this[i].source.index; 21 | } 22 | 23 | int getTargetIndex(int i) { 24 | return this[i].target.index; 25 | } 26 | 27 | int getSlack() { 28 | int slack = Integer.MAX_VALUE; 29 | for (final edge in this) slack = Math.min(slack, edge.slack); 30 | return slack; 31 | } 32 | 33 | int getWeight() { 34 | int w = 0; 35 | for (final edge in this) w += edge.weight; 36 | return w; 37 | } 38 | 39 | bool isCompletelyFlagged() { 40 | for (final edge in this) { 41 | if (!edge.flag) return false; 42 | } 43 | return true; 44 | } 45 | 46 | void resetFlags(bool resetTree) { 47 | for (final edge in this) { 48 | edge.flag = false; 49 | if (resetTree) edge.tree = false; 50 | } 51 | } 52 | 53 | void setFlags(bool value) { 54 | for (final edge in this) edge.flag = value; 55 | } 56 | 57 | // TODO(vegorov) remove when dartbug.com/8075 is fixed 58 | remove(e) => Collections.remove(list, e); 59 | } 60 | -------------------------------------------------------------------------------- /ui_utils/lib/src/draw2d/Geometry.dart: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2005, 2010 IBM Corporation and others. 3 | * All rights reserved. This program and the accompanying materials 4 | * are made available under the terms of the Eclipse Public License v1.0 5 | * which accompanies this distribution, and is available at 6 | * http://www.eclipse.org/legal/epl-v10.html 7 | * Contributors: 8 | * IBM Corporation - initial API and implementation 9 | * Alexander Shatalin (Borland) - Contribution for Bug 238874 10 | */ 11 | 12 | 13 | part of draw2d.graph; 14 | 15 | /** 16 | * A Utilities class for geometry operations. 17 | * @author Pratik Shah 18 | * @author Alexander Nyssen 19 | * @since 3.1 20 | */ 21 | class Geometry { 22 | /** 23 | * Determines whether the two line segments p1->p2 and p3->p4, given by 24 | * p1=(x1, y1), p2=(x2,y2), p3=(x3,y3), p4=(x4,y4) intersect. Two line 25 | * segments are regarded to be intersecting in case they share at least one 26 | * common point, i.e if one of the two line segments starts or ends on the 27 | * other line segment or the line segments are collinear and overlapping, 28 | * then they are as well considered to be intersecting. 29 | * @param x1x coordinate of starting point of line segment 1 30 | * @param y1y coordinate of starting point of line segment 1 31 | * @param x2x coordinate of ending point of line segment 1 32 | * @param y2y coordinate of ending point of line segment 1 33 | * @param x3x coordinate of the starting point of line segment 2 34 | * @param y3y coordinate of the starting point of line segment 2 35 | * @param x4x coordinate of the ending point of line segment 2 36 | * @param y4y coordinate of the ending point of line segment 2 37 | * @return true if the two line segments formed by the given 38 | * coordinates share at least one common point. 39 | * @since 3.1 40 | */ 41 | static bool linesIntersect(int x1, int y1, int x2, int y2, int x3, int y3, int x4, int y4) { 42 | int bb1_x = Math.min(x1, x2); 43 | int bb1_y = Math.min(y1, y2); 44 | int bb2_x = Math.max(x1, x2); 45 | int bb2_y = Math.max(y1, y2); 46 | int bb3_x = Math.min(x3, x4); 47 | int bb3_y = Math.min(y3, y4); 48 | int bb4_x = Math.max(x3, x4); 49 | int bb4_y = Math.max(y3, y4); 50 | if (!(bb2_x >= bb3_x && bb4_x >= bb1_x && bb2_y >= bb3_y && bb4_y >= bb1_y)) { 51 | return false; 52 | } 53 | int p1p3_x = x1 - x3; 54 | int p1p3_y = y1 - y3; 55 | int p2p3_x = x2 - x3; 56 | int p2p3_y = y2 - y3; 57 | int p3p4_x = x3 - x4; 58 | int p3p4_y = y3 - y4; 59 | if (productSign(crossProduct(p2p3_x, p2p3_y, p3p4_x, p3p4_y), crossProduct(p3p4_x, p3p4_y, p1p3_x, p1p3_y)) >= 0) { 60 | int p2p1_x = x2 - x1; 61 | int p2p1_y = y2 - y1; 62 | int p1p4_x = x1 - x4; 63 | int p1p4_y = y1 - y4; 64 | return productSign(crossProduct(-p1p3_x, -p1p3_y, p2p1_x, p2p1_y), crossProduct(p2p1_x, p2p1_y, p1p4_x, p1p4_y)) <= 0; 65 | } 66 | return false; 67 | } 68 | static int productSign(int x, int y) { 69 | if (x == 0 || y == 0) { 70 | return 0; 71 | } else if ((x < 0) != (y < 0)) { 72 | return -1; 73 | } 74 | return 1; 75 | } 76 | static int crossProduct(int x1, int y1, int x2, int y2) { 77 | return x1 * y2 - x2 * y1; 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /ui_utils/lib/src/draw2d/GraphUtilities.dart: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2003, 2010 IBM Corporation and others. 3 | * All rights reserved. This program and the accompanying materials 4 | * are made available under the terms of the Eclipse Public License v1.0 5 | * which accompanies this distribution, and is available at 6 | * http://www.eclipse.org/legal/epl-v10.html 7 | * Contributors: 8 | * IBM Corporation - initial API and implementation 9 | */ 10 | 11 | part of draw2d.graph; 12 | 13 | /** 14 | * Some utility methods for graphs. 15 | * @author Eric Bordeau 16 | * @since 2.1.2 17 | */ 18 | class GraphUtilities { 19 | static Subgraph getCommonAncestor(Node left, Node right) { 20 | Subgraph parent; 21 | if (right is Subgraph) 22 | parent = right; 23 | else 24 | parent = right.parent; 25 | while (parent != null) { 26 | if (parent.isNested(left)) 27 | return parent; 28 | parent = parent.parent; 29 | } 30 | return null; 31 | } 32 | 33 | /** 34 | * Counts the number of edge crossings in a DirectedGraph 35 | * @param graphthe graph whose crossed edges are counted 36 | * @return the number of edge crossings in the graph 37 | */ 38 | static int numberOfCrossingsInGraph(DirectedGraph graph) { 39 | int crossings = 0; 40 | for (var rank in graph.ranks) { 41 | crossings += numberOfCrossingsInRank(rank); 42 | } 43 | return crossings; 44 | } 45 | /** 46 | * Counts the number of edge crossings in a Rank 47 | * @param rankthe rank whose crossed edges are counted 48 | * @return the number of edge crossings in the rank 49 | */ 50 | static int numberOfCrossingsInRank(Rank rank) { 51 | int crossings = 0; 52 | for (int i = 0; i < rank.length - 1; i++) { 53 | Node currentNode = rank[i]; 54 | Node nextNode; 55 | for (int j = i + 1; j < rank.length; j++) { 56 | nextNode = rank[j]; 57 | EdgeList currentOutgoing = currentNode.outgoing; 58 | EdgeList nextOutgoing = nextNode.outgoing; 59 | for (int k = 0; k < currentOutgoing.length; k++) { 60 | Edge currentEdge = currentOutgoing[k]; 61 | for (int l = 0; l < nextOutgoing.length; l++) { 62 | if (nextOutgoing[l].getIndexForRank(currentNode.rank + 1) < currentEdge.getIndexForRank(currentNode.rank + 1)) crossings++; 63 | } 64 | } 65 | } 66 | } 67 | return crossings; 68 | } 69 | static NodeList search(Node node, NodeList list) { 70 | if (node.flag) return list; 71 | node.flag = true; 72 | list.add(node); 73 | for (int i = 0; i < node.outgoing.length; i++) search(node.outgoing[i].target, list); 74 | return list; 75 | } 76 | /** 77 | * Returns true if adding an edge between the 2 given nodes 78 | * will introduce a cycle in the containing graph. 79 | * @param sourcethe potential source node 80 | * @param targetthe potential target node 81 | * @return whether an edge between the 2 given nodes will introduce a cycle 82 | */ 83 | static bool willCauseCycle(Node source, Node target) { 84 | NodeList nodes = search(target, new NodeList()); 85 | nodes.resetFlags(); 86 | return nodes.contains(source); 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /ui_utils/lib/src/draw2d/GraphVisitor.dart: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2003, 2010 IBM Corporation and others. 3 | * All rights reserved. This program and the accompanying materials 4 | * are made available under the terms of the Eclipse Public License v1.0 5 | * which accompanies this distribution, and is available at 6 | * http://www.eclipse.org/legal/epl-v10.html 7 | * Contributors: 8 | * IBM Corporation - initial API and implementation 9 | */ 10 | 11 | part of draw2d.graph; 12 | 13 | /** 14 | * Performs some action on a Graph. 15 | * @author Randy Hudson 16 | * @since 2.1.2 17 | */ 18 | abstract class GraphVisitor { 19 | /** 20 | * Act on the given directed graph. 21 | * @param gthe graph 22 | */ 23 | void visit(DirectedGraph g) { 24 | } 25 | 26 | /** 27 | * Called in reverse order of visit. 28 | * @since 3.1 29 | * @param gthe graph to act upon 30 | */ 31 | void revisit(DirectedGraph g) { 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /ui_utils/lib/src/draw2d/InitialRankSolver.dart: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2003, 2010 IBM Corporation and others. 3 | * All rights reserved. This program and the accompanying materials 4 | * are made available under the terms of the Eclipse Public License v1.0 5 | * which accompanies this distribution, and is available at 6 | * http://www.eclipse.org/legal/epl-v10.html 7 | * Contributors: 8 | * IBM Corporation - initial API and implementation 9 | */ 10 | 11 | part of draw2d.graph; 12 | 13 | /** 14 | * Assigns a valid rank assignment to all nodes based on their edges. The 15 | * assignment is not optimal in that it does not provide the minimum global 16 | * length of edge lengths. 17 | * @author Randy Hudson 18 | * @since 2.1.2 19 | */ 20 | class InitialRankSolver extends GraphVisitor { 21 | DirectedGraph graph; 22 | EdgeList candidates = new EdgeList(); 23 | NodeList members = new NodeList(); 24 | void visit(DirectedGraph graph) { 25 | this.graph = graph; 26 | graph.edges.resetFlags(false); 27 | graph.nodes.resetFlags(); 28 | solve(); 29 | } 30 | void solve() { 31 | if (graph.nodes.length == 0) return; 32 | NodeList unranked = new NodeList(graph.nodes); 33 | NodeList rankMe = new NodeList(); 34 | Node node; 35 | int i; 36 | while (!unranked.isEmpty) { 37 | rankMe.clear(); 38 | for (i = 0; i < unranked.length;) { 39 | node = unranked[i]; 40 | if (node.incoming.isCompletelyFlagged()) { 41 | rankMe.add(node); 42 | unranked.removeAt(i); 43 | } else i++; 44 | } 45 | if (rankMe.length == 0) throw ("Cycle detected in graph"); 46 | for (i = 0; i < rankMe.length; i++) { 47 | node = rankMe[i]; 48 | assignMinimumRank(node); 49 | node.outgoing.setFlags(true); 50 | } 51 | } 52 | connectForest(); 53 | } 54 | void connectForest() { 55 | List forest = new List(); 56 | List stack = new List(); 57 | NodeList tree; 58 | graph.nodes.resetFlags(); 59 | for (int i = 0; i < graph.nodes.length; i++) { 60 | Node neighbor, n = graph.nodes[i]; 61 | if (n.flag) continue; 62 | tree = new NodeList(); 63 | stack.add(n); 64 | while (!stack.isEmpty) { 65 | n = stack.removeLast(); 66 | n.flag = true; 67 | tree.add(n); 68 | for (int s = 0; s < n.incoming.length; s++) { 69 | neighbor = n.incoming[s].source; 70 | if (!neighbor.flag) stack.add(neighbor); 71 | } 72 | for (int s = 0; s < n.outgoing.length; s++) { 73 | neighbor = n.outgoing[s].target; 74 | if (!neighbor.flag) stack.add(neighbor); 75 | } 76 | } 77 | forest.add(tree); 78 | } 79 | if (forest.length > 1) { 80 | graph.forestRoot = new Node(data: "the forest root"); 81 | graph.nodes.add(graph.forestRoot); 82 | for (var tree in forest) { 83 | graph.edges.add(new Edge(graph.forestRoot, tree[0], delta: 0, weight: 0)); 84 | } 85 | } 86 | } 87 | void assignMinimumRank(Node node) { 88 | int rank = 0; 89 | Edge e; 90 | for (int i1 = 0; i1 < node.incoming.length; i1++) { 91 | e = node.incoming[i1]; 92 | rank = Math.max(rank, e.delta + e.source.rank); 93 | } 94 | node.rank = rank; 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /ui_utils/lib/src/draw2d/InvertEdges.dart: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2003, 2010 IBM Corporation and others. 3 | * All rights reserved. This program and the accompanying materials 4 | * are made available under the terms of the Eclipse Public License v1.0 5 | * which accompanies this distribution, and is available at 6 | * http://www.eclipse.org/legal/epl-v10.html 7 | * Contributors: 8 | * IBM Corporation - initial API and implementation 9 | */ 10 | 11 | part of draw2d.graph; 12 | 13 | /** 14 | * Inverts any edges which are marked as backwards or "feedback" edges. 15 | * @author Daniel Lee 16 | * @since 2.1.2 17 | */ 18 | class InvertEdges extends GraphVisitor { 19 | /** 20 | * @see GraphVisitor#visit(org.eclipse.draw2d.graph.DirectedGraph) 21 | */ 22 | void visit(DirectedGraph g) { 23 | for (int i = 0; i < g.edges.length; i++) { 24 | Edge e = g.edges[i]; 25 | if (e.isFeedback) e.invert(); 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /ui_utils/lib/src/draw2d/LocalOptimizer.dart: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2003, 2010 IBM Corporation and others. 3 | * All rights reserved. This program and the accompanying materials 4 | * are made available under the terms of the Eclipse Public License v1.0 5 | * which accompanies this distribution, and is available at 6 | * http://www.eclipse.org/legal/epl-v10.html 7 | * Contributors: 8 | * IBM Corporation - initial API and implementation 9 | */ 10 | 11 | part of draw2d.graph; 12 | 13 | /** 14 | * This graph visitor examines all adjacent pairs of nodes and determines if 15 | * swapping the two nodes provides improved graph aesthetics. 16 | * @author Daniel Lee 17 | * @since 2.1.2 18 | */ 19 | class LocalOptimizer extends GraphVisitor { 20 | bool shouldSwap(Node current, Node next) { 21 | int crossCount = 0; 22 | int invertedCrossCount = 0; 23 | EdgeList currentEdges = current.incoming; 24 | EdgeList nextEdges = next.incoming; 25 | int rank = current.rank - 1; 26 | int iCurrent, iNext; 27 | for (int i = 0; i < currentEdges.length; i++) { 28 | Edge currentEdge = currentEdges[i]; 29 | iCurrent = currentEdge.getIndexForRank(rank); 30 | for (int j = 0; j < nextEdges.length; j++) { 31 | iNext = nextEdges[j].getIndexForRank(rank); 32 | if (iNext < iCurrent) crossCount++; else if (iNext > iCurrent) invertedCrossCount++; else { 33 | int offsetDiff = nextEdges[j].sourceOffset - currentEdge.sourceOffset; 34 | if (offsetDiff < 0) crossCount++; else if (offsetDiff > 0) invertedCrossCount++; 35 | } 36 | } 37 | } 38 | currentEdges = current.outgoing; 39 | nextEdges = next.outgoing; 40 | rank = current.rank + 1; 41 | for (int i = 0; i < currentEdges.length; i++) { 42 | Edge currentEdge = currentEdges[i]; 43 | iCurrent = currentEdge.getIndexForRank(rank); 44 | for (int j = 0; j < nextEdges.length; j++) { 45 | iNext = nextEdges[j].getIndexForRank(rank); 46 | if (iNext < iCurrent) crossCount++; else if (iNext > iCurrent) invertedCrossCount++; else { 47 | int offsetDiff = nextEdges[j].targetOffset - currentEdge.targetOffset; 48 | if (offsetDiff < 0) crossCount++; else if (offsetDiff > 0) invertedCrossCount++; 49 | } 50 | } 51 | } 52 | if (invertedCrossCount < crossCount) return true; 53 | return false; 54 | } 55 | void swapNodes(Node current, Node next, Rank rank) { 56 | int index = rank.indexOf(current); 57 | rank[index + 1] = current; 58 | rank[index] = next; 59 | index = current.index; 60 | current.index = next.index; 61 | next.index = index; 62 | } 63 | /** 64 | * @see GraphVisitor#visit(org.eclipse.draw2d.graph.DirectedGraph) 65 | */ 66 | void visit(DirectedGraph g) { 67 | bool flag; 68 | do { 69 | flag = false; 70 | for (int r = 0; r < g.ranks.length; r++) { 71 | Rank rank = g.ranks[r]; 72 | for (int n = 0; n < rank.count() - 1; n++) { 73 | Node currentNode = rank[n]; 74 | Node nextNode = rank[n + 1]; 75 | if (shouldSwap(currentNode, nextNode)) { 76 | swapNodes(currentNode, nextNode, rank); 77 | flag = true; 78 | n = Math.max(0, n - 2); 79 | } 80 | } 81 | } 82 | } while (flag); 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /ui_utils/lib/src/draw2d/MinCross.dart: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2003, 2010 IBM Corporation and others. 3 | * All rights reserved. This program and the accompanying materials 4 | * are made available under the terms of the Eclipse Public License v1.0 5 | * which accompanies this distribution, and is available at 6 | * http://www.eclipse.org/legal/epl-v10.html 7 | * Contributors: 8 | * IBM Corporation - initial API and implementation 9 | */ 10 | 11 | part of draw2d.graph; 12 | 13 | /** 14 | * Sweeps up and down the ranks rearranging them so as to reduce edge crossings. 15 | * @author Randy Hudson 16 | * @since 2.1.2 17 | */ 18 | class MinCross extends GraphVisitor { 19 | static final int MAX = 45; 20 | DirectedGraph g; 21 | RankSorter sorter; 22 | 23 | MinCross([this.sorter]) { 24 | if (sorter == null) sorter = new RankSorter(); 25 | } 26 | 27 | void setRankSorter(RankSorter sorter) { 28 | this.sorter = sorter; 29 | } 30 | void solve() { 31 | Rank rank; 32 | for (int loop = 0; loop < MAX; loop++) { 33 | for (int row = 1; row < g.ranks.length; row++) { 34 | rank = g.ranks[row]; 35 | sorter.sortRankIncoming(g, rank, row, loop / MAX); 36 | } 37 | if (loop == MAX - 1) continue; 38 | for (int row = g.ranks.length - 2; row >= 0; row--) { 39 | rank = g.ranks[row]; 40 | sorter.sortRankOutgoing(g, rank, row, loop / MAX); 41 | } 42 | } 43 | } 44 | /** 45 | * @see GraphVisitor#visit(org.eclipse.draw2d.graph.DirectedGraph) 46 | */ 47 | void visit(DirectedGraph g) { 48 | sorter.init(g); 49 | this.g = g; 50 | solve(); 51 | sorter.optimize(g); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /ui_utils/lib/src/draw2d/NodeList.dart: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2003, 2010 IBM Corporation and others. 3 | * All rights reserved. This program and the accompanying materials 4 | * are made available under the terms of the Eclipse Public License v1.0 5 | * which accompanies this distribution, and is available at 6 | * http://www.eclipse.org/legal/epl-v10.html 7 | * Contributors: 8 | * IBM Corporation - initial API and implementation 9 | */ 10 | 11 | part of draw2d.graph; 12 | 13 | /** 14 | * A list containing nodes. 15 | * @author hudsonr 16 | * @since 2.1.2 17 | */ 18 | class NodeList extends ListBase { 19 | 20 | NodeList([NodeList other]) { 21 | if (other != null) { 22 | list.addAll(other.list); 23 | } 24 | } 25 | 26 | void adjustRankSimple(int delta) { 27 | if (delta == 0) return; 28 | for (var node in this) node.rank += delta; 29 | } 30 | 31 | void resetSortValues() { 32 | for (var node in this) node.sortValue = 0.0; 33 | } 34 | 35 | void resetIndices() { 36 | for (var node in this) node.index = 0; 37 | } 38 | 39 | void normalizeRanks() { 40 | int minRank = Integer.MAX_VALUE; 41 | for (var node in this) { 42 | minRank = Math.min(minRank, node.rank); 43 | } 44 | adjustRankSimple(-minRank); 45 | } 46 | 47 | void resetFlags() { 48 | for (var node in this) { 49 | node.flag = false; 50 | } 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /ui_utils/lib/src/draw2d/NodePair.dart: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2003, 2010 IBM Corporation and others. 3 | * All rights reserved. This program and the accompanying materials 4 | * are made available under the terms of the Eclipse Public License v1.0 5 | * which accompanies this distribution, and is available at 6 | * http://www.eclipse.org/legal/epl-v10.html 7 | * Contributors: 8 | * IBM Corporation - initial API and implementation 9 | */ 10 | 11 | part of draw2d.graph; 12 | 13 | /** 14 | * @author hudsonr 15 | * @since 2.1 16 | */ 17 | class NodePair { 18 | Node n1; 19 | Node n2; 20 | 21 | NodePair([this.n1, this.n2]) { 22 | } 23 | 24 | bool operator == (Object obj) { 25 | if (obj is NodePair) { 26 | return obj.n1 == n1 && obj.n2 == n2; 27 | } 28 | return false; 29 | } 30 | 31 | int get hashCode { 32 | return n1.hashCode ^ n2.hashCode; 33 | } 34 | 35 | /** 36 | * @see java.lang.Object#toString() 37 | */ 38 | String toString() { 39 | return "[$n1, $n2]"; 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /ui_utils/lib/src/draw2d/Obstacle.dart: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2004, 2010 IBM Corporation and others. 3 | * All rights reserved. This program and the accompanying materials 4 | * are made available under the terms of the Eclipse Public License v1.0 5 | * which accompanies this distribution, and is available at 6 | * http://www.eclipse.org/legal/epl-v10.html 7 | * Contributors: 8 | * IBM Corporation - initial API and implementation 9 | */ 10 | 11 | part of draw2d.graph; 12 | 13 | /** 14 | * An obstacle representation for the ShortestPathRouting. This is a subclass of 15 | * Rectangle. 16 | * This class is for internal use only. 17 | * @author Whitney Sorenson 18 | * @since 3.0 19 | */ 20 | class Obstacle extends Rectangle { 21 | bool exclude = false; 22 | Vertex topLeft, topRight, bottomLeft, bottomRight, center; 23 | ShortestPathRouter router; 24 | 25 | Obstacle(Rectangle rect, ShortestPathRouter router) : super(0, 0, 0, 0) { 26 | init(rect); 27 | this.router = router; 28 | } 29 | /** 30 | * Returns true if the given point is contained but not on the 31 | * boundary of this obstacle. 32 | * @param pa point 33 | * @return true if properly contained 34 | */ 35 | bool containsProper(Point p) { 36 | return p.x > this.x && p.x < this.x + this.width - 1 && p.y > this.y && p.y < this.y + this.height - 1; 37 | } 38 | int getSpacing() { 39 | return router.getSpacing(); 40 | } 41 | void growVertex(Vertex vertex) { 42 | if (vertex.totalCount > 0) vertex.grow(); 43 | } 44 | /** 45 | * Grows all vertices on this obstacle. 46 | */ 47 | void growVertices() { 48 | growVertex(topLeft); 49 | growVertex(topRight); 50 | growVertex(bottomLeft); 51 | growVertex(bottomRight); 52 | } 53 | /** 54 | * Initializes this obstacle to the values of the given rectangle 55 | * @param rectbounds of this obstacle 56 | */ 57 | void init(Rectangle rect) { 58 | this.x = rect.x; 59 | this.y = rect.y; 60 | this.width = rect.width; 61 | this.height = rect.height; 62 | exclude = false; 63 | topLeft = new Vertex(x, y, this); 64 | topLeft.positionOnObstacle = PositionConstants.NORTH_WEST; 65 | topRight = new Vertex(x + width - 1, y, this); 66 | topRight.positionOnObstacle = PositionConstants.NORTH_EAST; 67 | bottomLeft = new Vertex(x, y + height - 1, this); 68 | bottomLeft.positionOnObstacle = PositionConstants.SOUTH_WEST; 69 | bottomRight = new Vertex(x + width - 1, y + height - 1, this); 70 | bottomRight.positionOnObstacle = PositionConstants.SOUTH_EAST; 71 | center = new Vertex.fromPoint(getCenter(), this); 72 | } 73 | /** 74 | * Requests a full reset on all four vertices of this obstacle. 75 | */ 76 | void reset() { 77 | topLeft.fullReset(); 78 | bottomLeft.fullReset(); 79 | bottomRight.fullReset(); 80 | topRight.fullReset(); 81 | } 82 | void shrinkVertex(Vertex vertex) { 83 | if (vertex.totalCount > 0) vertex.shrink(); 84 | } 85 | /** 86 | * Shrinks all four vertices of this obstacle. 87 | */ 88 | void shrinkVertices() { 89 | shrinkVertex(topLeft); 90 | shrinkVertex(topRight); 91 | shrinkVertex(bottomLeft); 92 | shrinkVertex(bottomRight); 93 | } 94 | /** 95 | * @see org.eclipse.draw2d.geometry.Rectangle#toString() 96 | */ 97 | String toString() { 98 | return "Obstacle($x"; // TODO(vegorov) 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /ui_utils/lib/src/draw2d/Point.dart: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2000, 2010 IBM Corporation and others. 3 | * All rights reserved. This program and the accompanying materials 4 | * are made available under the terms of the Eclipse Public License v1.0 5 | * which accompanies this distribution, and is available at 6 | * http://www.eclipse.org/legal/epl-v10.html 7 | * Contributors: 8 | * IBM Corporation - initial API and implementation 9 | */ 10 | 11 | 12 | part of draw2d.graph; 13 | 14 | /** 15 | * Represents a point (x, y) in 2-dimensional space. This class provides various 16 | * methods for manipulating this Point or creating new derived geometrical 17 | * Objects. 18 | */ 19 | class Point { 20 | int x; 21 | int y; 22 | 23 | Point(this.x, this.y); 24 | 25 | Point clone() => new Point(x, y); 26 | 27 | /** 28 | * Test for equality. 29 | * @param oObject being tested for equality 30 | * @return true if both x and y values are equal 31 | * @since 2.0 32 | */ 33 | bool operator == (Object o) { 34 | if (o is Point) { 35 | return o.x == x && o.y == y; 36 | } 37 | return false; 38 | } 39 | 40 | /** 41 | * @see java.lang.Object#hashCode() 42 | */ 43 | int get hashCode { 44 | return (x * y) ^ (x + y); 45 | } 46 | 47 | /** 48 | * @return String representation. 49 | * @since 2.0 50 | */ 51 | String toString() { 52 | return "Point(${x}, ${y})"; 53 | } 54 | 55 | /** 56 | * Calculates the distance from this Point to the one specified. 57 | * @param pThe Point being compared to this 58 | * @return The distance 59 | * @since 2.0 60 | */ 61 | double getDistance(Point p) { 62 | final dx = p.x - x; 63 | final dy = p.y - y; 64 | return math.sqrt((dx * dx + dy * dy).toDouble()); // TODO(vegorov) working around the crash. 65 | } 66 | 67 | 68 | /** 69 | * Creates a new Point which is translated by the values of the provided 70 | * Point. 71 | * @param pPoint which provides the translation amounts. 72 | * @return A new Point 73 | * @since 2.0 74 | */ 75 | Point translate(Point p) { 76 | x += p.x; 77 | y += p.y; 78 | return this; 79 | } 80 | 81 | /** 82 | * Scales this Point by the specified amount. 83 | * @return this for convenience 84 | * @param factorscale factor 85 | * @since 2.0 86 | */ 87 | Point scale(double factor) { 88 | x = Math.floor(x * factor); 89 | y = Math.floor(y * factor); 90 | return this; 91 | } 92 | 93 | /** 94 | * Transposes this object. X and Y values are exchanged. 95 | * @return this for convenience 96 | * @since 2.0 97 | */ 98 | Point transpose() { 99 | var t = x; 100 | x = y; 101 | y = t; 102 | return this; 103 | } 104 | } 105 | -------------------------------------------------------------------------------- /ui_utils/lib/src/draw2d/PointList.dart: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2000, 2010 IBM Corporation and others. 3 | * All rights reserved. This program and the accompanying materials 4 | * are made available under the terms of the Eclipse Public License v1.0 5 | * which accompanies this distribution, and is available at 6 | * http://www.eclipse.org/legal/epl-v10.html 7 | * Contributors: 8 | * IBM Corporation - initial API and implementation 9 | * Alexander Shatalin (Borland) - Contribution for Bug 238874 10 | */ 11 | 12 | 13 | part of draw2d.graph; 14 | 15 | /** 16 | * Represents a List of Points. 17 | */ 18 | class PointList { 19 | final List points = new List(); 20 | 21 | get iterator => points.iterator; 22 | 23 | Rectangle bounds; 24 | 25 | PointList(); 26 | 27 | void addAll(PointList source) { 28 | for (var p in source.points) points.add(p.clone()); 29 | } 30 | 31 | void addPoint(Point p) { 32 | points.add(p.clone()); 33 | } 34 | 35 | /** 36 | * Returns the smallest Rectangle which contains all Points. 37 | */ 38 | Rectangle getBounds() { 39 | if (bounds != null) { 40 | return bounds; 41 | } 42 | 43 | bounds = new Rectangle(0, 0, 0, 0); 44 | if (!points.isEmpty) { 45 | bounds.setLocation2(first); 46 | for (var p in points) bounds.unionPoint(p); 47 | } 48 | return bounds; 49 | } 50 | 51 | Point get first => points.first; 52 | 53 | Point get last => points.last; 54 | 55 | Point get midpoint { 56 | final midpoint = (length ~/ 2); 57 | if (length % 2 == 0) { 58 | return points[midpoint - 1].clone().translate(points[midpoint]).scale(0.5); 59 | } 60 | return points[midpoint]; 61 | } 62 | 63 | operator[] (int i) => points[i]; 64 | 65 | void insertPoint(Point p, int index) { 66 | if (bounds != null && !bounds.containsPoint(p)) { 67 | bounds = null; 68 | } 69 | 70 | points.insert(index, p.clone()); 71 | } 72 | 73 | void setPoint(Point p, int index) { // TODO(vegorov) verify 74 | if (bounds != null && !bounds.containsPoint(p)) { 75 | bounds = null; 76 | } 77 | 78 | points[index] = p.clone(); 79 | } 80 | 81 | /** 82 | * Removes all the points stored by this list. Resets all the properties 83 | * based on the point information. 84 | */ 85 | void removeAllPoints() { 86 | bounds = null; 87 | points.clear(); 88 | } 89 | 90 | /** 91 | * Removes the point at the specified index from the PointList, and returns 92 | * it. 93 | */ 94 | Point removePoint(int index) { 95 | bounds = null; 96 | return points.removeAt(index); 97 | } 98 | 99 | void reverse() { 100 | Collections.reverse(points); 101 | } 102 | 103 | int get length => points.length; 104 | 105 | /** 106 | * Transposes all x and y values. Useful for orientation changes. 107 | * @since 3.2 108 | */ 109 | void transpose() { 110 | if (bounds != null) { 111 | bounds.transpose(); 112 | } 113 | 114 | for (var p in points) p.transpose(); 115 | } 116 | } 117 | -------------------------------------------------------------------------------- /ui_utils/lib/src/draw2d/PopulateRanks.dart: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2003, 2010 IBM Corporation and others. 3 | * All rights reserved. This program and the accompanying materials 4 | * are made available under the terms of the Eclipse Public License v1.0 5 | * which accompanies this distribution, and is available at 6 | * http://www.eclipse.org/legal/epl-v10.html 7 | * Contributors: 8 | * IBM Corporation - initial API and implementation 9 | */ 10 | 11 | part of draw2d.graph; 12 | 13 | /** 14 | * This class takes a DirectedGraph with an optimal rank assignment and a 15 | * spanning tree, and populates the ranks of the DirectedGraph. Virtual nodes 16 | * are inserted for edges that span 1 or more ranks. 17 | *

18 | * Ranks are populated using a pre-order depth-first traversal of the spanning 19 | * tree. For each node, all edges requiring virtual nodes are added to the 20 | * ranks. 21 | * @author Randy Hudson 22 | * @since 2.1.2 23 | */ 24 | class PopulateRanks extends GraphVisitor { 25 | final List changes = []; 26 | 27 | /** 28 | * @see GraphVisitor#visit(DirectedGraph) 29 | */ 30 | void visit(DirectedGraph g) { 31 | if (g.forestRoot != null) { 32 | for (int i = g.forestRoot.outgoing.length - 1; i >= 0; i--) { 33 | g.removeEdge(g.forestRoot.outgoing[i]); 34 | } 35 | g.removeNode(g.forestRoot); 36 | } 37 | 38 | g.ranks = new RankList(); 39 | for (var node in g.nodes) { 40 | g.ranks[node.rank].add(node); 41 | } 42 | 43 | for (var i = 0; i < g.nodes.length; i++) { 44 | final node = g.nodes[i]; 45 | for (int j = 0; j < node.outgoing.length;) { 46 | Edge e = node.outgoing[j]; 47 | if (e.length > 1) { 48 | changes.add(new VirtualNodeCreation(e, g)); 49 | } else { 50 | j++; 51 | } 52 | } 53 | } 54 | } 55 | 56 | /** 57 | * @see GraphVisitor#revisit(DirectedGraph) 58 | */ 59 | void revisit(DirectedGraph g) { 60 | for (var rank in g.ranks) { 61 | Node prev; 62 | for (var cur in rank) { 63 | cur.left = prev; 64 | if (prev != null) prev.right = cur; 65 | prev = cur; 66 | } 67 | } 68 | 69 | for (var change in changes) change.revert(); 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /ui_utils/lib/src/draw2d/PositionConstants.dart: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2000, 2010 IBM Corporation and others. 3 | * All rights reserved. This program and the accompanying materials 4 | * are made available under the terms of the Eclipse Public License v1.0 5 | * which accompanies this distribution, and is available at 6 | * http://www.eclipse.org/legal/epl-v10.html 7 | * Contributors: 8 | * IBM Corporation - initial API and implementation 9 | */ 10 | 11 | 12 | part of draw2d.graph; 13 | 14 | /** 15 | * Constants representing cardinal directions and relative positions. Some of 16 | * these constants can be grouped as follows: 17 | * 18 | * 19 | * 20 | * 21 | * 22 | * 23 | * 24 | * 25 | * 26 | * 27 | * 28 | * 29 | * 33 | * 34 | * 35 | *
LEFT, CENTER, RIGHTUsed to describe horizontal position.
TOP, MIDDLE, BOTTOMUsed to describe vertical position.
NORTH, SOUTH, EAST, WESTUsed to describe the four positions relative to an object's center point. 30 | * May also be used when describing which direction an object is facing.
31 | * NOTE: If you have a use for all four of these possibilities, do not use TOP, 32 | * BOTTOM, RIGHT, LEFT in place of NORTH, SOUTH, EAST, WEST.
36 | */ 37 | class PositionConstants { 38 | /** 39 | * None 40 | */ 41 | static const int NONE = 0; 42 | /** 43 | * Left 44 | */ 45 | static const int LEFT = 1; 46 | /** 47 | * Center (Horizontal) 48 | */ 49 | static const int CENTER = 2; 50 | /** 51 | * Right 52 | */ 53 | static const int RIGHT = 4; 54 | /** 55 | * Bit-wise OR of LEFT, CENTER, and RIGHT 56 | */ 57 | static const int LEFT_CENTER_RIGHT = LEFT | CENTER; 58 | /** 59 | * Used to signify left alignment regardless of orientation (i.e., LTR or 60 | * RTL) 61 | */ 62 | static const int ALWAYS_LEFT = 64; 63 | /** 64 | * Used to signify right alignment regardless of orientation (i.e., LTR or 65 | * RTL) 66 | */ 67 | static const int ALWAYS_RIGHT = 128; 68 | /** 69 | * Top 70 | */ 71 | static const int TOP = 8; 72 | /** 73 | * Middle (Vertical) 74 | */ 75 | static const int MIDDLE = 16; 76 | /** 77 | * Bottom 78 | */ 79 | static const int BOTTOM = 32; 80 | /** 81 | * Bit-wise OR of TOP, MIDDLE, and BOTTOM 82 | */ 83 | static const int TOP_MIDDLE_BOTTOM = TOP | MIDDLE; 84 | /** 85 | * North 86 | */ 87 | static const int NORTH = 1; 88 | /** 89 | * South 90 | */ 91 | static const int SOUTH = 4; 92 | /** 93 | * West 94 | */ 95 | static const int WEST = 8; 96 | /** 97 | * East 98 | */ 99 | static const int EAST = 16; 100 | /** 101 | * A constant indicating horizontal direction 102 | */ 103 | static const int HORIZONTAL = 64; 104 | /** 105 | * A constant indicating vertical direction 106 | */ 107 | static const int VERTICAL = 128; 108 | /** 109 | * North-East: a bit-wise OR of {@link #NORTH} and {@link #EAST} 110 | */ 111 | static const int NORTH_EAST = NORTH | EAST; 112 | /** 113 | * North-West: a bit-wise OR of {@link #NORTH} and {@link #WEST} 114 | */ 115 | static const int NORTH_WEST = NORTH | WEST; 116 | /** 117 | * South-East: a bit-wise OR of {@link #SOUTH} and {@link #EAST} 118 | */ 119 | static const int SOUTH_EAST = SOUTH | EAST; 120 | /** 121 | * South-West: a bit-wise OR of {@link #SOUTH} and {@link #WEST} 122 | */ 123 | static const int SOUTH_WEST = SOUTH | WEST; 124 | /** 125 | * North-South: a bit-wise OR of {@link #NORTH} and {@link #SOUTH} 126 | */ 127 | static const int NORTH_SOUTH = NORTH | SOUTH; 128 | /** 129 | * East-West: a bit-wise OR of {@link #EAST} and {@link #WEST} 130 | */ 131 | static const int EAST_WEST = EAST | WEST; 132 | /** 133 | * North-South-East-West: a bit-wise OR of all 4 directions. 134 | */ 135 | static const int NSEW = NORTH_SOUTH | EAST_WEST; 136 | } 137 | -------------------------------------------------------------------------------- /ui_utils/lib/src/draw2d/README: -------------------------------------------------------------------------------- 1 | This folder contains parts of Draw2d library translated from Java to Dart. 2 | 3 | The translation was mostly done by a java2dart tool and resulting source was 4 | cleaned up manually. Cleanup is incomplete and the libarary definetely contains 5 | untested and/or dead code that does not match Dart style guide. 6 | 7 | Translated files retain their original license and comments. 8 | 9 | Draw2d: http://www.eclipse.org/gef/draw2d/index.php -------------------------------------------------------------------------------- /ui_utils/lib/src/draw2d/Rank.dart: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2003, 2010 IBM Corporation and others. 3 | * All rights reserved. This program and the accompanying materials 4 | * are made available under the terms of the Eclipse Public License v1.0 5 | * which accompanies this distribution, and is available at 6 | * http://www.eclipse.org/legal/epl-v10.html 7 | * Contributors: 8 | * IBM Corporation - initial API and implementation 9 | */ 10 | 11 | part of draw2d.graph; 12 | 13 | /** 14 | * For Internal Use only. 15 | * @author hudsonr 16 | * @since 2.1.2 17 | */ 18 | class Rank extends NodeList { 19 | int bottomPadding = 0; 20 | int height = 0; 21 | int location = 0; 22 | final int hash = new Object().hashCode; 23 | int topPadding = 0; 24 | int total = 0; 25 | 26 | Rank() : super(); 27 | 28 | void assignIndices() { 29 | total = 0; 30 | int mag; 31 | for (var node in this) { 32 | if (node is SubgraphBoundary) { 33 | mag = 4; 34 | } else { 35 | mag = Math.max(1, node.incoming.length + node.outgoing.length); 36 | mag = Math.min(mag, 5); 37 | } 38 | total += mag; 39 | node.index = total; 40 | total += mag; 41 | } 42 | } 43 | /** 44 | * Returns the number of nodes in this rank. 45 | * @return the number of nodes 46 | */ 47 | int count() { 48 | return this.length; 49 | } 50 | 51 | /** 52 | * @see Object#hashCode() Overridden for speed based on equality. 53 | */ 54 | int get hashCode { 55 | return hash; 56 | } 57 | 58 | void setDimensions(int location, int rowHeight) { 59 | this.height = rowHeight; 60 | this.location = location; 61 | for (var n in this) { 62 | n.y = location; 63 | n.height = rowHeight; 64 | } 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /ui_utils/lib/src/draw2d/RankList.dart: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2003, 2010 IBM Corporation and others. 3 | * All rights reserved. This program and the accompanying materials 4 | * are made available under the terms of the Eclipse Public License v1.0 5 | * which accompanies this distribution, and is available at 6 | * http://www.eclipse.org/legal/epl-v10.html 7 | * Contributors: 8 | * IBM Corporation - initial API and implementation 9 | */ 10 | 11 | part of draw2d.graph; 12 | 13 | /** 14 | * For internal use only. A list of lists. 15 | * @author hudsonr 16 | * @since 2.1.2 17 | */ 18 | class RankList extends ListBase { 19 | /** 20 | * Returns the specified rank. 21 | * @param rankthe row 22 | * @return the rank 23 | */ 24 | Rank operator [](int rank) { 25 | while (list.length <= rank) list.add(new Rank()); 26 | return list[rank]; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /ui_utils/lib/src/draw2d/RevertableChange.dart: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2004, 2010 IBM Corporation and others. 3 | * All rights reserved. This program and the accompanying materials 4 | * are made available under the terms of the Eclipse Public License v1.0 5 | * which accompanies this distribution, and is available at 6 | * http://www.eclipse.org/legal/epl-v10.html 7 | * Contributors: 8 | * IBM Corporation - initial API and implementation 9 | */ 10 | 11 | part of draw2d.graph; 12 | 13 | /** 14 | * @since 3.1 15 | */ 16 | class RevertableChange { 17 | void revert() { 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /ui_utils/lib/src/draw2d/RouteEdges.dart: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2003, 2010 IBM Corporation and others. 3 | * All rights reserved. This program and the accompanying materials 4 | * are made available under the terms of the Eclipse Public License v1.0 5 | * which accompanies this distribution, and is available at 6 | * http://www.eclipse.org/legal/epl-v10.html 7 | * Contributors: 8 | * IBM Corporation - initial API and implementation 9 | */ 10 | 11 | part of draw2d.graph; 12 | 13 | /** 14 | * @author Randy Hudson 15 | */ 16 | class RouteEdges extends GraphVisitor { 17 | /** 18 | * @see GraphVisitor#visit(DirectedGraph) 19 | */ 20 | void revisit(DirectedGraph g) { 21 | for (int i = 0; i < g.edges.length; i++) { 22 | Edge edge = g.edges[i]; 23 | edge.start = new Point(edge.sourceOffset + edge.source.x, edge.source.y + edge.source.height); 24 | if (edge.source is SubgraphBoundary) { 25 | SubgraphBoundary boundary = edge.source; 26 | if (boundary.parent.head == boundary) 27 | edge.start.y = boundary.parent.y 28 | + boundary.parent.insets.top; 29 | } 30 | edge.end = new Point(edge.targetOffset + edge.target.x, edge.target.y); 31 | if (edge.vNodes != null) { 32 | routeLongEdge(edge, g); 33 | } else { 34 | PointList list = new PointList(); 35 | list.addPoint(edge.start); 36 | list.addPoint(edge.end); 37 | edge.setPoints(list); 38 | } 39 | } 40 | } 41 | 42 | static void routeLongEdge(Edge edge, DirectedGraph g) { 43 | ShortestPathRouter router = new ShortestPathRouter(); 44 | Path path = new Path(start: edge.start, end: edge.end); 45 | router.addPath(path); 46 | Rectangle o; 47 | Insets padding; 48 | final P1 = new Point(-100000, 2); 49 | final P2 = new Point(100000, 2); 50 | for (int i = 0; i < edge.vNodes.length; i++) { 51 | Node node = edge.vNodes[i]; 52 | Node neighbor; 53 | if (node.left != null) { 54 | neighbor = node.left; 55 | o = new Rectangle(neighbor.x, neighbor.y, neighbor.width, neighbor.height); 56 | padding = g.getPadding(neighbor); 57 | o.width += padding.right + edge.padding - 1; 58 | o.x -= padding.left; 59 | o.unionPoint(o.getLocation().translate(P1)); 60 | router.addObstacle(o); 61 | } 62 | if (node.right != null) { 63 | neighbor = node.right; 64 | o = new Rectangle(neighbor.x, neighbor.y, neighbor.width, neighbor.height); 65 | padding = g.getPadding(neighbor); 66 | o.width += padding.right; 67 | o.x -= padding.left + edge.padding - 1; 68 | o.unionPoint(o.getLocation().translate(P2)); 69 | router.addObstacle(o); 70 | } 71 | } 72 | router.setSpacing(0); 73 | router.solve(); 74 | edge.setPoints(path.getPoints()); 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /ui_utils/lib/src/draw2d/Segment.dart: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2004, 2010 IBM Corporation and others. 3 | * All rights reserved. This program and the accompanying materials 4 | * are made available under the terms of the Eclipse Public License v1.0 5 | * which accompanies this distribution, and is available at 6 | * http://www.eclipse.org/legal/epl-v10.html 7 | * Contributors: 8 | * IBM Corporation - initial API and implementation 9 | */ 10 | 11 | part of draw2d.graph; 12 | 13 | /** 14 | * A Segment representation for the ShortestPathRouting. A segment is a line 15 | * between two vertices. 16 | * This class is for internal use only 17 | * @author Whitney Sorenson 18 | * @since 3.0 19 | */ 20 | class Segment { 21 | Vertex start, end; 22 | Segment(Vertex start, Vertex end) { 23 | this.start = start; 24 | this.end = end; 25 | } 26 | /** 27 | * Returns the cosine of the made between this segment and the given segment 28 | * @param otherSegmentthe other segment 29 | * @return cosine value (not arc-cos) 30 | */ 31 | double cosine(Segment otherSegment) { 32 | double cos = (((start.x - end.x) * (otherSegment.end.x - otherSegment.start.x)) + ((start.y - end.y) * (otherSegment.end.y - otherSegment.start.y))) / (getLength() * otherSegment.getLength()); 33 | double sin = (((start.x - end.x) * (otherSegment.end.y - otherSegment.start.y)) - ((start.y - end.y) * (otherSegment.end.x - otherSegment.start.x))).toDouble(); 34 | if (sin < 0.0) return (1 + cos); 35 | return -(1 + cos); 36 | } 37 | /** 38 | * Returns the cross product of this segment and the given segment 39 | * @param otherSegmentthe other segment 40 | * @return the cross product 41 | */ 42 | int crossProduct(Segment otherSegment) { 43 | return (((start.x - end.x) * (otherSegment.end.y - end.y)) - ((start.y - end.y) * (otherSegment.end.x - end.x))); 44 | } 45 | double getLength() { 46 | return (end.getDistance(start)); 47 | } 48 | /** 49 | * Returns a number that represents the sign of the slope of this segment. 50 | * It does not return the actual slope. 51 | * @return number representing sign of the slope 52 | */ 53 | double getSlope() { 54 | if (end.x - start.x >= 0) return (end.y - start.y).toDouble(); else return -(end.y - start.y).toDouble(); 55 | } 56 | /** 57 | * Returns true if the given segment intersects this segment. 58 | * @param sxstart x 59 | * @param systart y 60 | * @param txend x 61 | * @param tyend y 62 | * @return true if the segments intersect 63 | */ 64 | bool intersects(int sx, int sy, int tx, int ty) { 65 | return Geometry.linesIntersect(start.x, start.y, end.x, end.y, sx, sy, tx, ty); 66 | } 67 | /** 68 | * Return true if the segment represented by the points intersects this 69 | * segment. 70 | * @param sstart point 71 | * @param tend point 72 | * @return true if the segments intersect 73 | */ 74 | bool intersects2(Point s, Point t) { 75 | return intersects(s.x, s.y, t.x, t.y); 76 | } 77 | /** 78 | * @see java.lang.Object#toString() 79 | */ 80 | String toString() { 81 | return "$start---"; // TODO(vegorov) 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /ui_utils/lib/src/draw2d/SpanningTreeVisitor.dart: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2003, 2010 IBM Corporation and others. 3 | * All rights reserved. This program and the accompanying materials 4 | * are made available under the terms of the Eclipse Public License v1.0 5 | * which accompanies this distribution, and is available at 6 | * http://www.eclipse.org/legal/epl-v10.html 7 | * Contributors: 8 | * IBM Corporation - initial API and implementation 9 | */ 10 | 11 | part of draw2d.graph; 12 | 13 | /** 14 | * A base class for visitors which operate on the graphs spanning tree used to 15 | * induce rank assignments. 16 | * @author Randy Hudson 17 | * @since 2.1.2 18 | */ 19 | abstract class SpanningTreeVisitor extends GraphVisitor { 20 | Edge getParentEdge(Node node) { 21 | return node.workingData[1]; 22 | } 23 | EdgeList getSpanningTreeChildren(Node node) { 24 | return node.workingData[0]; 25 | } 26 | Node getTreeHead(Edge edge) { 27 | if (getParentEdge(edge.source) == edge) return edge.target; 28 | return edge.source; 29 | } 30 | Node getTreeParent(Node node) { 31 | Edge e = getParentEdge(node); 32 | if (e == null) return null; 33 | return e.opposite(node); 34 | } 35 | Node getTreeTail(Edge edge) { 36 | if (getParentEdge(edge.source) == edge) return edge.source; 37 | return edge.target; 38 | } 39 | void setParentEdge(Node node, Edge edge) { 40 | node.workingData[1] = edge; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /ui_utils/lib/src/draw2d/Subgraph.dart: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2003, 2010 IBM Corporation and others. 3 | * All rights reserved. This program and the accompanying materials 4 | * are made available under the terms of the Eclipse Public License v1.0 5 | * which accompanies this distribution, and is available at 6 | * http://www.eclipse.org/legal/epl-v10.html 7 | * Contributors: 8 | * IBM Corporation - initial API and implementation 9 | */ 10 | 11 | part of draw2d.graph; 12 | 13 | /** 14 | * A Node which may contain other nodes. A Subgraph is a compound or container 15 | * node. It may have incoming and outgoing edges just like a node. Subgraphs are 16 | * used in {@link CompoundDirectedGraph}s. A proper layout of a compound graph 17 | * ensures that all of a subgraph's children are placed inside its rectangular 18 | * region. Nodes which do not belong to the subgraph must be placed outside that 19 | * region. 20 | *

21 | * A Subgraph may contain another Subgraph. 22 | *

23 | * A Subgraph has additional geometric properties which describe the containing 24 | * box. They are: 25 | *

    26 | *
  • {@link #insets} - the size of the subgraph's border. A subgraph is 27 | * typically rendered as a thin rectangular box. Sometimes this box is labeled 28 | * or decorated. The insets can be used to reserve space for this purpose. 29 | *
  • {@link #innerPadding} - the amount of empty space that must be preserved 30 | * just inside the subgraph's border. This is the minimum space between the 31 | * border, and the children node's contained inside the subgraph. 32 | *
33 | * 34 | * @author hudsonr 35 | * @since 2.1.2 36 | */ 37 | class Subgraph extends Node { 38 | 39 | /** 40 | * The children of this subgraph. Nodes may not belong to more than one 41 | * subgraph. 42 | */ 43 | NodeList members = new NodeList(); 44 | 45 | Node head; 46 | Node tail; 47 | Node left; 48 | Node right; 49 | int nestingTreeMin; 50 | 51 | /** 52 | * The space required for this subgraph's border. The default value is 53 | * undefined. 54 | */ 55 | Insets insets = new Insets.round(1); 56 | 57 | /** 58 | * The minimum space between this subgraph's border and it's children. 59 | */ 60 | Insets innerPadding = NO_INSETS; 61 | 62 | static final Insets NO_INSETS = new Insets.round(0); 63 | 64 | /** 65 | * Constructs a new subgraph with the given data object and parent subgraph. 66 | * 67 | * @see Node#Node(Object, Subgraph) 68 | * @param data 69 | * an arbitrary data object 70 | * @param parent 71 | * the parent 72 | */ 73 | Subgraph(Object data, [Subgraph parent]) : super(data: data, parent: parent); 74 | 75 | /** 76 | * Adds the given node to this subgraph. 77 | * 78 | * @param n 79 | * the node to add 80 | */ 81 | void addMember(Node n) { 82 | members.add(n); 83 | } 84 | 85 | /** 86 | * Returns true if the given node is contained inside the 87 | * branch represented by this subgraph. 88 | * 89 | * @param n 90 | * the node in question 91 | * @return true if nested 92 | */ 93 | bool isNested(Node n) { 94 | return n.nestingIndex >= nestingTreeMin 95 | && n.nestingIndex <= nestingIndex; 96 | } 97 | 98 | } 99 | -------------------------------------------------------------------------------- /ui_utils/lib/src/draw2d/SubgraphBoundary.dart: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2003, 2010 IBM Corporation and others. 3 | * All rights reserved. This program and the accompanying materials 4 | * are made available under the terms of the Eclipse Public License v1.0 5 | * which accompanies this distribution, and is available at 6 | * http://www.eclipse.org/legal/epl-v10.html 7 | * Contributors: 8 | * IBM Corporation - initial API and implementation 9 | */ 10 | 11 | part of draw2d.graph; 12 | 13 | /** 14 | * For INTERNAL use only. 15 | * 16 | * @author hudsonr 17 | * @since 2.1.2 18 | */ 19 | class SubgraphBoundary extends Node { 20 | 21 | /** 22 | * constant indicating TOP. 23 | */ 24 | static const int TOP = 0; 25 | 26 | /** 27 | * constant indicating LEFT. 28 | */ 29 | static const int LEFT = 1; 30 | 31 | /** 32 | * constant indicating BOTTOM. 33 | */ 34 | static const int BOTTOM = 2; 35 | 36 | /** 37 | * constant indicating RIGHT. 38 | */ 39 | static const int RIGHT = 3; 40 | 41 | /** 42 | * Constructs a new boundary. 43 | * 44 | * @param s 45 | * the subgraph 46 | * @param p 47 | * the padding 48 | * @param side 49 | * which side 50 | */ 51 | SubgraphBoundary(Subgraph s, Insets p, int side) : super(parent: s) { 52 | this.width = s.width; 53 | this.height = s.height; 54 | this.padding = new Insets.round(0); 55 | switch (side) { 56 | case LEFT: 57 | width = s.insets.left; 58 | y = s.y; 59 | padding.left = p.left; 60 | padding.right = s.innerPadding.left; 61 | padding.top = padding.bottom = 0; 62 | parent = s.parent; 63 | data = "left(${s})"; //$NON-NLS-1$ //$NON-NLS-2$ 64 | break; 65 | case RIGHT: 66 | width = s.insets.right; 67 | y = s.y; 68 | padding.right = p.right; 69 | padding.left = s.innerPadding.right; 70 | padding.top = padding.bottom = 0; 71 | parent = s.parent; 72 | data = "right(${s})"; //$NON-NLS-1$ //$NON-NLS-2$ 73 | break; 74 | case TOP: 75 | height = s.insets.top; 76 | // $TODO width of head/tail should be 0 77 | width = 5; 78 | padding.top = p.top; 79 | padding.bottom = s.innerPadding.top; 80 | padding.left = padding.right = 0; 81 | data = "top(${s})"; //$NON-NLS-1$ //$NON-NLS-2$ 82 | break; 83 | case BOTTOM: 84 | height = s.insets.bottom; 85 | // $TODO width of head/tail should be 0 86 | width = 5; 87 | padding.top = s.innerPadding.bottom; 88 | padding.bottom = p.bottom; 89 | padding.left = padding.right = 0; 90 | data = "bottom(${s})"; //$NON-NLS-1$ //$NON-NLS-2$ 91 | break; 92 | } 93 | } 94 | 95 | } 96 | -------------------------------------------------------------------------------- /ui_utils/lib/src/draw2d/TightSpanningTreeSolver.dart: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2003, 2010 IBM Corporation and others. 3 | * All rights reserved. This program and the accompanying materials 4 | * are made available under the terms of the Eclipse Public License v1.0 5 | * which accompanies this distribution, and is available at 6 | * http://www.eclipse.org/legal/epl-v10.html 7 | * Contributors: 8 | * IBM Corporation - initial API and implementation 9 | */ 10 | 11 | part of draw2d.graph; 12 | 13 | 14 | /** 15 | * Finds a tight spanning tree from the graphs edges which induce a valid rank 16 | * assignment. This process requires that the nodes be initially given a 17 | * feasible ranking. 18 | * @author Randy Hudson 19 | * @since 2.1.2 20 | */ 21 | class TightSpanningTreeSolver extends SpanningTreeVisitor { 22 | DirectedGraph graph; 23 | final candidates = new List(); 24 | NodeList members = new NodeList(); 25 | 26 | void visit(DirectedGraph graph) { 27 | this.graph = graph; 28 | init(); 29 | solve(); 30 | } 31 | 32 | Node addEdge(Edge edge) { 33 | int delta = edge.slack; 34 | edge.tree = true; 35 | Node node; 36 | if (edge.target.flag) { 37 | delta = -delta; 38 | node = edge.source; 39 | setParentEdge(node, edge); 40 | getSpanningTreeChildren(edge.target).add(edge); 41 | } else { 42 | node = edge.target; 43 | setParentEdge(node, edge); 44 | getSpanningTreeChildren(edge.source).add(edge); 45 | } 46 | members.adjustRankSimple(delta); 47 | addNode(node); 48 | return node; 49 | } 50 | 51 | bool isNodeReachable(Node node) { 52 | return node.flag; 53 | } 54 | 55 | void setNodeReachable(Node node) { 56 | node.flag = true; 57 | } 58 | 59 | bool isCandidate(Edge e) { 60 | return e.flag; 61 | } 62 | 63 | void setCandidate(Edge e) { 64 | e.flag = true; 65 | } 66 | 67 | void addNode(Node node) { 68 | setNodeReachable(node); 69 | EdgeList list = node.incoming; 70 | Edge e; 71 | for (int i = 0; i < list.length; i++) { 72 | e = list[i]; 73 | if (!isNodeReachable(e.source)) { 74 | if (!isCandidate(e)) { 75 | setCandidate(e); 76 | candidates.add(e); 77 | } 78 | } else { 79 | Collections.remove(candidates, e); 80 | } 81 | } 82 | list = node.outgoing; 83 | for (int i = 0; i < list.length; i++) { 84 | e = list[i]; 85 | if (!isNodeReachable(e.target)) { 86 | if (!isCandidate(e)) { 87 | setCandidate(e); 88 | candidates.add(e); 89 | } 90 | } else { 91 | Collections.remove(candidates, e); 92 | } 93 | 94 | } 95 | members.add(node); 96 | } 97 | 98 | void init() { 99 | graph.edges.resetFlags(true); 100 | graph.nodes.resetFlags(); 101 | for (int i = 0; i < graph.nodes.length; i++) { 102 | Node node = graph.nodes[i]; 103 | node.workingData[0] = new EdgeList(); 104 | } 105 | } 106 | 107 | void solve() { 108 | Node root = graph.nodes[0]; 109 | setParentEdge(root, null); 110 | addNode(root); 111 | while (members.length < graph.nodes.length) { 112 | if (candidates.isEmpty) throw ("graph is not fully connected"); 113 | int minSlack = Integer.MAX_VALUE, slack; 114 | Edge minEdge = null, edge; 115 | for (int i = 0; i < candidates.length && minSlack > 0; i++) { 116 | edge = candidates[i]; 117 | slack = edge.slack; 118 | if (slack < minSlack) { 119 | minSlack = slack; 120 | minEdge = edge; 121 | } 122 | } 123 | addEdge(minEdge); 124 | } 125 | graph.nodes.normalizeRanks(); 126 | } 127 | } 128 | -------------------------------------------------------------------------------- /ui_utils/lib/src/draw2d/Transform.dart: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2000, 2010 IBM Corporation and others. 3 | * All rights reserved. This program and the accompanying materials 4 | * are made available under the terms of the Eclipse Public License v1.0 5 | * which accompanies this distribution, and is available at 6 | * http://www.eclipse.org/legal/epl-v10.html 7 | * Contributors: 8 | * IBM Corporation - initial API and implementation 9 | */ 10 | 11 | 12 | part of draw2d.graph; 13 | 14 | /** 15 | * Provides support for transformations of scaling, translation and rotation. 16 | */ 17 | class Transform { 18 | double scaleX = 1.0, scaleY = 1.0, dx = 0.0, dy = 0.0, cos = 1.0, sin = 0.0; 19 | /** 20 | * Sets the value for the amount of scaling to be done along both axes. 21 | * @param scaleScale factor 22 | * @since 2.0 23 | */ 24 | void setScale(double scale) { 25 | scaleX = scaleY = scale; 26 | } 27 | /** 28 | * Sets the value for the amount of scaling to be done along X and Y axes 29 | * individually. 30 | * @param xAmount of scaling on X axis 31 | * @param yAmount of scaling on Y axis 32 | * @since 2.0 33 | */ 34 | void setScale2(double x, double y) { 35 | scaleX = x; 36 | scaleY = y; 37 | } 38 | /** 39 | * Sets the rotation angle. 40 | * @param angleAngle of rotation 41 | * @since 2.0 42 | */ 43 | void setRotation(double angle) { 44 | cos = math.cos(angle); 45 | sin = math.sin(angle); 46 | } 47 | /** 48 | * Sets the translation amounts for both axes. 49 | * @param xAmount of shift on X axis 50 | * @param yAmount of shift on Y axis 51 | * @since 2.0 52 | */ 53 | void setTranslation(double x, double y) { 54 | dx = x; 55 | dy = y; 56 | } 57 | /** 58 | * Returns a new transformed Point of the input Point based on the 59 | * transformation values set. 60 | * @param pPoint being transformed 61 | * @return The transformed Point 62 | * @since 2.0 63 | */ 64 | Point getTransformed(Point p) { 65 | double x = p.x.toDouble(); 66 | double y = p.y.toDouble(); 67 | double temp; 68 | x *= scaleX; 69 | y *= scaleY; 70 | temp = x * cos - y * sin; 71 | y = x * sin + y * cos; 72 | x = temp; 73 | return new Point(Math.round(x + dx), Math.round(y + dy)); 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /ui_utils/lib/src/draw2d/TransposeMetrics.dart: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2005, 2010 IBM Corporation and others. 3 | * All rights reserved. This program and the accompanying materials 4 | * are made available under the terms of the Eclipse Public License v1.0 5 | * which accompanies this distribution, and is available at 6 | * http://www.eclipse.org/legal/epl-v10.html 7 | * Contributors: 8 | * IBM Corporation - initial API and implementation 9 | */ 10 | 11 | part of draw2d.graph; 12 | 13 | class TransposeMetrics extends GraphVisitor { 14 | void visit(DirectedGraph g) { 15 | if (g.getDirection() == PositionConstants.SOUTH) return; 16 | int temp; 17 | g.setDefaultPadding(g.getDefaultPadding().getTransposed()); 18 | for (int i = 0; i < g.nodes.length; i++) { 19 | Node node = g.nodes[i]; 20 | temp = node.width; 21 | node.width = node.height; 22 | node.height = temp; 23 | if (node.padding != null) { 24 | node.padding = node.padding.getTransposed(); 25 | } 26 | } 27 | } 28 | void revisit(DirectedGraph g) { 29 | if (g.getDirection() == PositionConstants.SOUTH) return; 30 | int temp; 31 | g.setDefaultPadding(g.getDefaultPadding().getTransposed()); 32 | for (int i = 0; i < g.nodes.length; i++) { 33 | Node node = g.nodes[i]; 34 | temp = node.width; 35 | node.width = node.height; 36 | node.height = temp; 37 | temp = node.y; 38 | node.y = node.x; 39 | node.x = temp; 40 | if (node.padding != null) { 41 | node.padding = node.padding.getTransposed(); 42 | } 43 | } 44 | for (int i = 0; i < g.edges.length; i++) { 45 | Edge edge = g.edges[i]; 46 | edge.start.transpose(); 47 | edge.end.transpose(); 48 | edge.points.transpose(); 49 | List bends = edge.vNodes.list; 50 | if (bends == null) continue; 51 | for (int b = 0; b < bends.length; b++) { 52 | Node vnode = bends[b]; 53 | temp = vnode.y; 54 | vnode.y = vnode.x; 55 | vnode.x = temp; 56 | temp = vnode.width; 57 | vnode.width = vnode.height; 58 | vnode.height = temp; 59 | } 60 | } 61 | g.size.transpose(); 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /ui_utils/lib/src/draw2d/VerticalPlacement.dart: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2003, 2010 IBM Corporation and others. 3 | * All rights reserved. This program and the accompanying materials 4 | * are made available under the terms of the Eclipse Public License v1.0 5 | * which accompanies this distribution, and is available at 6 | * http://www.eclipse.org/legal/epl-v10.html 7 | * Contributors: 8 | * IBM Corporation - initial API and implementation 9 | */ 10 | 11 | part of draw2d.graph; 12 | 13 | /** 14 | * Assigns the Y and Height values to the nodes in the graph. All nodes in the 15 | * same row are given the same height. 16 | * @author Randy Hudson 17 | * @since 2.1.2 18 | */ 19 | class VerticalPlacement extends GraphVisitor { 20 | void visit(DirectedGraph g) { 21 | Insets pad; 22 | int currentY = g.getMargin().top; 23 | int row, rowHeight; 24 | g.rankLocations = new List.filled(g.ranks.length + 1, 0); 25 | for (row = 0; row < g.ranks.length; row++) { 26 | g.rankLocations[row] = currentY; 27 | Rank rank = g.ranks[row]; 28 | rowHeight = 0; 29 | rank.topPadding = rank.bottomPadding = 0; 30 | for (int n = 0; n < rank.length; n++) { 31 | Node node = rank[n]; 32 | pad = g.getPadding(node); 33 | rowHeight = Math.max(node.height, rowHeight); 34 | rank.topPadding = Math.max(pad.top, rank.topPadding); 35 | rank.bottomPadding = Math.max(pad.bottom, rank.bottomPadding); 36 | } 37 | currentY += rank.topPadding; 38 | rank.setDimensions(currentY, rowHeight); 39 | currentY += rank.height + rank.bottomPadding; 40 | } 41 | g.rankLocations[row] = currentY; 42 | g.size.height = currentY; 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /ui_utils/lib/src/draw2d/VirtualNodeCreation.dart: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (c) 2004, 2010 IBM Corporation and others. 3 | * All rights reserved. This program and the accompanying materials 4 | * are made available under the terms of the Eclipse Public License v1.0 5 | * which accompanies this distribution, and is available at 6 | * http://www.eclipse.org/legal/epl-v10.html 7 | * Contributors: 8 | * IBM Corporation - initial API and implementation 9 | */ 10 | 11 | part of draw2d.graph; 12 | 13 | /** 14 | * Encapsulates the conversion of a long edge to multiple short edges and back. 15 | * @since 3.1 16 | */ 17 | class VirtualNodeCreation extends RevertableChange { 18 | final Edge edge; 19 | final DirectedGraph graph; 20 | List nodes; 21 | List edges; 22 | static final int INNER_EDGE_X = 2; 23 | static final int LONG_EDGE_X = 8; 24 | VirtualNodeCreation(Edge this.edge, DirectedGraph this.graph) { 25 | int size = edge.target.rank - edge.source.rank - 1; 26 | int offset = edge.source.rank + 1; 27 | Node prevNode = edge.source; 28 | Node currentNode; 29 | Edge currentEdge; 30 | nodes = new List(size); 31 | edges = new List(size + 1); 32 | Insets padding = new Insets(0, edge.padding, 0, edge.padding); 33 | Subgraph s = GraphUtilities.getCommonAncestor(edge.source, edge.target); 34 | for (int i = 0; i < size; i++) { 35 | nodes[i] = currentNode = new Node(data: "Virtual$i:$edge", parent: s); 36 | currentNode.width = 1; 37 | if (s != null) { 38 | currentNode.nestingIndex = s.nestingIndex; 39 | } 40 | currentNode.height = 0; 41 | currentNode.padding = padding; 42 | currentNode.rank = offset + i; 43 | graph.ranks[offset + i].add(currentNode); 44 | currentEdge = new Edge(prevNode, currentNode, delta: 1, weight: edge.weight * LONG_EDGE_X); 45 | if (i == 0) { 46 | currentEdge.weight = edge.weight * INNER_EDGE_X; 47 | } 48 | graph.edges.add(edges[i] = currentEdge); 49 | graph.nodes.add(currentNode); 50 | prevNode = currentNode; 51 | } 52 | currentEdge = new Edge(prevNode, edge.target, delta: 1, weight: edge.weight * INNER_EDGE_X); 53 | graph.edges.add(edges[edges.length - 1] = currentEdge); 54 | graph.removeEdge(edge); 55 | } 56 | void revert() { 57 | edge.start = edges[0].start; 58 | edge.end = edges[edges.length - 1].end; 59 | edge.vNodes = new NodeList(); 60 | for (int i = 0; i < edges.length; i++) { 61 | graph.removeEdge(edges[i]); 62 | } 63 | for (int i = 0; i < nodes.length; i++) { 64 | edge.vNodes.add(nodes[i]); 65 | graph.removeNode(nodes[i]); 66 | } 67 | edge.source.outgoing.add(edge); 68 | edge.target.incoming.add(edge); 69 | graph.edges.add(edge); 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /ui_utils/lib/task.dart: -------------------------------------------------------------------------------- 1 | // Copyright 2014 Google Inc. All Rights Reserved. 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | library task; 16 | 17 | import 'dart:async'; 18 | 19 | const MICROTASK = const _TypeMicrotask(); 20 | const TASK = const _TypeTask(); 21 | 22 | /** Simple one time task. */ 23 | class Task { 24 | var type; 25 | final _callback; 26 | var _scheduled = false; 27 | 28 | var frozen; 29 | 30 | Task(this._callback, {this.frozen: false, this.type: TASK}); 31 | 32 | /** 33 | * Schedule execution of the callback in the microtask queue. 34 | * If the task is already scheduled does nothing. 35 | */ 36 | schedule() { 37 | if (!_scheduled && !frozen) { 38 | type.schedule(_execute); 39 | _scheduled = true; 40 | } 41 | } 42 | 43 | unfreeze() { 44 | frozen = false; 45 | schedule(); 46 | } 47 | 48 | _execute() { 49 | _scheduled = false; 50 | _callback(); 51 | } 52 | } 53 | 54 | class _TypeMicrotask { 55 | const _TypeMicrotask(); 56 | schedule(cb) => scheduleMicrotask(cb); 57 | } 58 | 59 | class _TypeTask { 60 | const _TypeTask(); 61 | schedule(cb) => new Timer(const Duration(milliseconds: 1), cb); 62 | } 63 | -------------------------------------------------------------------------------- /ui_utils/pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: ui_utils 2 | version: 0.0.1 3 | --------------------------------------------------------------------------------