diff options
author | borenet@google.com <borenet@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81> | 2013-05-06 12:50:00 +0000 |
---|---|---|
committer | borenet@google.com <borenet@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81> | 2013-05-06 12:50:00 +0000 |
commit | 6a98b8c0b5ffe1a23902cdf7e692f702b703eaeb (patch) | |
tree | 7c5b356f6fa4fb71876465f372eedc3d3ee25801 /platform_tools | |
parent | f073b3332d7c9f7dba6bcf7eb93708593a90036c (diff) |
Copy NaCl directory into trunk/platform_tools, adjust paths
(SkipBuildbotRuns)
R=djsollen@google.com
Review URL: https://codereview.chromium.org/14771017
git-svn-id: http://skia.googlecode.com/svn/trunk@9008 2bbb7eff-a529-9590-31e7-b0007b416f81
Diffstat (limited to 'platform_tools')
28 files changed, 1702 insertions, 0 deletions
diff --git a/platform_tools/nacl/SampleApp/SampleApp.nmf b/platform_tools/nacl/SampleApp/SampleApp.nmf new file mode 100644 index 0000000000..7296c07885 --- /dev/null +++ b/platform_tools/nacl/SampleApp/SampleApp.nmf @@ -0,0 +1,6 @@ +{ + "program": { + "x86-64": {"url": "../../out/nacl64/Debug/SampleApp"}, + "x86-32": {"url": "../../out/nacl32/Debug/SampleApp"} + } +} diff --git a/platform_tools/nacl/SampleApp/index.html b/platform_tools/nacl/SampleApp/index.html new file mode 100644 index 0000000000..cbdeefe029 --- /dev/null +++ b/platform_tools/nacl/SampleApp/index.html @@ -0,0 +1,71 @@ +<!DOCTYPE html> +<html> + <!-- + Copyright 2013 Google Inc. + + Use of this source code is governed by a BSD-style license that can be + found in the LICENSE file. + --> +<head> + + <title>Skia Sample App</title> + + <script type="text/javascript"> + "use strict"; + + var SkiaModule = null; // Global application object. + + // Force a re-draw of the given element. + function refresh(elem) { + var old_display_style = elem.style.display; + elem.style.display = "none"; + elem.style.display = old_display_style; + } + + // When the module loads, begin running the application. + function moduleDidLoad() { + SkiaModule = document.getElementById("skia_nacl"); + run(); + } + + function handleMessage(message_event) { + var skdebugf_cmd = "SkDebugf:"; + if (message_event.data.indexOf(skdebugf_cmd) == 0) { + var msg_contents = message_event.data.slice(skdebugf_cmd.length) + console.log("Skia: " + msg_contents); + } else { + alert(message_event.data); + } + } + + // Run the application. + function run() { + if (SkiaModule) { + var cmd = "init"; + SkiaModule.postMessage(cmd); + } else { + alert("The Skia module has not properly loaded..."); + } + } + </script> +</head> +<body> + +<h1>Skia Sample App</h1> +<p> + <div id="listener"> + <script type="text/javascript"> + var listener = document.getElementById('listener'); + listener.addEventListener('load', moduleDidLoad, true); + listener.addEventListener('message', handleMessage, true); + </script> + + <embed name="nacl_module" + id="skia_nacl" + width=0 height=0 + src="SampleApp.nmf" + type="application/x-nacl" /> + </div> +</p> +</body> +</html> diff --git a/platform_tools/nacl/debugger/debugger.css b/platform_tools/nacl/debugger/debugger.css new file mode 100644 index 0000000000..a63b7e0816 --- /dev/null +++ b/platform_tools/nacl/debugger/debugger.css @@ -0,0 +1,172 @@ +body { + width:100%; + height:100%; + margin:0px; + padding:0px; + background-color:#EEE; +} + +div.single-line { + clear:both; +} + +div.column-set { + width:100%; + height:100%; + display:table; + vertical-align:top; + border-collapse:collapse; + margin:0px; +} + +div.column { + display:table-cell; + vertical-align:top; + margin:0px; +} + +div.row-set { + width:100%; + height:100%; + display:table; + vertical-align:top; + border-collapse:collapse; + margin:0px; +} + +div.row { + display:table-row; + vertical-align:top; + margin:0px; +} + +#buttons { + height:5px; + overflow:auto; +} + +#left_column { + width:230px; +} + +#command_list_div { +} + +#command_list_form { + width:100%; + height:100%; +} + +#command_list { + width:100%; + height:100%; +} + +#bottom_row { + height:275px; +} + +#display_pane { +} + +#right_panel { + width:230px; +} + +#tabview { +} + +#matrixclip { +} + +#small_window { + width:218px; + height:218px; + background-color:#FFF; +} + +div.thin_outline { + border:1px solid; + margin:6px; + padding:8px; +} + +div.settings_block { +} + +input.matrix { + width:50px; +} + +#overviewdetails { + width:100%; + height:100%; + resize:none; + padding:10px; +} + +#menu { + height:5px; + overflow:auto; + background-color:#999; +} + +#menu-bar { + margin:0px; +} + +ul.dropdown-menu a { + display:block; + text-decoration:none; + color:#000; +} + +ul.dropdown-menu, ul.dropdown-menu li, ul.dropdown-menu ul { + list-style:none; + margin:0px; + padding:0px; +} + +ul.dropdown-menu { + position:relative; + z-index:597; + float:left; +} + +ul.dropdown-menu li { + float:left; + padding:5px; + cursor:pointer; +} + +ul.dropdown-menu li.hover, ul.dropdown-menu li:hover { + position:relative; + z-index:599; + cursor:default; + background-color:#FFF; +} + +ul.dropdown-menu ul { + visibility:hidden; + position:absolute; + top:100%; + left:0; + z-index:598; + width:195px; + border:1px solid; + border-collapse:collapse; + background-color:#DDD; +} + +ul.dropdown-menu ul li { + float:none; +} + +ul.dropdown-menu ul ul { + top:-2px; + left:100%; +} + +ul.dropdown-menu li:hover > ul { + visibility:visible; +}
\ No newline at end of file diff --git a/platform_tools/nacl/debugger/debugger.nmf b/platform_tools/nacl/debugger/debugger.nmf new file mode 100644 index 0000000000..7a53e52b03 --- /dev/null +++ b/platform_tools/nacl/debugger/debugger.nmf @@ -0,0 +1,6 @@ +{ + "program": { + "x86-64": {"url": "../../out/nacl64/Debug/debugger"}, + "x86-32": {"url": "../../out/nacl32/Debug/debugger"} + } +} diff --git a/platform_tools/nacl/debugger/icons/blank.png b/platform_tools/nacl/debugger/icons/blank.png Binary files differnew file mode 100644 index 0000000000..97246fb9a0 --- /dev/null +++ b/platform_tools/nacl/debugger/icons/blank.png diff --git a/platform_tools/nacl/debugger/icons/breakpoint.png b/platform_tools/nacl/debugger/icons/breakpoint.png Binary files differnew file mode 100644 index 0000000000..b6290b4f0e --- /dev/null +++ b/platform_tools/nacl/debugger/icons/breakpoint.png diff --git a/platform_tools/nacl/debugger/icons/breakpoint_16x16.png b/platform_tools/nacl/debugger/icons/breakpoint_16x16.png Binary files differnew file mode 100644 index 0000000000..a25ece8f84 --- /dev/null +++ b/platform_tools/nacl/debugger/icons/breakpoint_16x16.png diff --git a/platform_tools/nacl/debugger/icons/delete.png b/platform_tools/nacl/debugger/icons/delete.png Binary files differnew file mode 100644 index 0000000000..50b604fb9e --- /dev/null +++ b/platform_tools/nacl/debugger/icons/delete.png diff --git a/platform_tools/nacl/debugger/icons/inspector.png b/platform_tools/nacl/debugger/icons/inspector.png Binary files differnew file mode 100644 index 0000000000..360f23ef47 --- /dev/null +++ b/platform_tools/nacl/debugger/icons/inspector.png diff --git a/platform_tools/nacl/debugger/icons/next.png b/platform_tools/nacl/debugger/icons/next.png Binary files differnew file mode 100644 index 0000000000..aae8934424 --- /dev/null +++ b/platform_tools/nacl/debugger/icons/next.png diff --git a/platform_tools/nacl/debugger/icons/pause.png b/platform_tools/nacl/debugger/icons/pause.png Binary files differnew file mode 100644 index 0000000000..a026a545be --- /dev/null +++ b/platform_tools/nacl/debugger/icons/pause.png diff --git a/platform_tools/nacl/debugger/icons/play.png b/platform_tools/nacl/debugger/icons/play.png Binary files differnew file mode 100644 index 0000000000..5528bafc06 --- /dev/null +++ b/platform_tools/nacl/debugger/icons/play.png diff --git a/platform_tools/nacl/debugger/icons/previous.png b/platform_tools/nacl/debugger/icons/previous.png Binary files differnew file mode 100644 index 0000000000..3396a3f8bd --- /dev/null +++ b/platform_tools/nacl/debugger/icons/previous.png diff --git a/platform_tools/nacl/debugger/icons/profile.png b/platform_tools/nacl/debugger/icons/profile.png Binary files differnew file mode 100644 index 0000000000..d4b8501810 --- /dev/null +++ b/platform_tools/nacl/debugger/icons/profile.png diff --git a/platform_tools/nacl/debugger/icons/reload.png b/platform_tools/nacl/debugger/icons/reload.png Binary files differnew file mode 100644 index 0000000000..316f36c704 --- /dev/null +++ b/platform_tools/nacl/debugger/icons/reload.png diff --git a/platform_tools/nacl/debugger/icons/rewind.png b/platform_tools/nacl/debugger/icons/rewind.png Binary files differnew file mode 100644 index 0000000000..d8d4902e56 --- /dev/null +++ b/platform_tools/nacl/debugger/icons/rewind.png diff --git a/platform_tools/nacl/debugger/icons/skia.png b/platform_tools/nacl/debugger/icons/skia.png Binary files differnew file mode 100644 index 0000000000..017ee4f8aa --- /dev/null +++ b/platform_tools/nacl/debugger/icons/skia.png diff --git a/platform_tools/nacl/debugger/index.html b/platform_tools/nacl/debugger/index.html new file mode 100644 index 0000000000..9d4644d956 --- /dev/null +++ b/platform_tools/nacl/debugger/index.html @@ -0,0 +1,468 @@ +<!DOCTYPE html> +<html> + <!-- + Copyright 2013 Google Inc. + + Use of this source code is governed by a BSD-style license that can be + found in the LICENSE file. + --> +<head> + <title>Skia Debugger</title> + <link rel="stylesheet" type="text/css" href="debugger.css"/> + <script type="text/javascript"> + "use strict"; + + var skia_module = null; // Global application object. + var display_right_panel = null; + var display_bottom_row = null; + var overview_text = ""; + var details_text = "Default details text."; + var command_list = []; + var command_types = {}; + var no_filter_text = "--Filter By Available Commands--"; + + function openFileDialog() { + var event = document.createEvent("MouseEvents"); + event.initEvent("click", true, false); + document.getElementById("file_open").dispatchEvent(event); + } + + function updateOverviewDetails() { + var radio_buttons = document.getElementsByName("overviewdetails_radio"); + for (var i = 0; i < radio_buttons.length; ++i) { + if (radio_buttons[i].checked) { + if (radio_buttons[i].value == "details") { + document.getElementById("overviewdetails").innerHTML = details_text; + } else { + document.getElementById("overviewdetails").innerHTML = overview_text; + } + return; + } + } + // If no radio button is checked, check the "overview" button. + for (var i = 0; i < radio_buttons.length; ++i) { + if (radio_buttons[i].value == "overview") { + radio_buttons[i].checked = true; + document.getElementById("overviewdetails").innerHTML = overview_text; + return; + } + } + } + + function makeIndentString(indent_amt) { + var indent_str = ""; + for (var i = 0; i < indent_amt; ++i) { + indent_str += "--"; + } + return indent_str; + } + + function updateCommandList(filter) { + var command_list_display = document.getElementById("command_list"); + command_list_display.options.length = 0; + var indent = 0; + var indent_str = ""; + for (var i = 0; i < command_list.length; ++i) { + if (command_list[i] == "Restore") { + indent--; + indent_str = makeIndentString(indent); + } + if (!filter || filter == no_filter_text || command_list[i] == filter) { + command_list_display.options.add(new Option(indent_str + command_list[i], i)); + } + if (command_list[i] == "Save" || command_list[i] == "Save Layer") { + indent++; + indent_str = makeIndentString(indent); + } + } + command_list_display.selectedIndex = command_list_display.length - 1; + + // TODO(borenet): Should the SKP re-draw when the command list is updated? + //commandSelected(); + } + + function updateFilterList() { + var filter_list_display = document.getElementById("command_filter"); + filter_list_display.options.length = 0; + filter_list_display.options.add(new Option(no_filter_text, no_filter_text)); + for (var command_type in command_types) { + if (command_types.hasOwnProperty(command_type)) { + filter_list_display.options.add(new Option(command_type, command_type)); + } + } + } + + function openFile(event) { + document.getElementById("overviewdetails").innerHTML = ""; + var files = event.target.files; + if (files.length != 1) { + return; + } + var file = files[0]; + var reader = new FileReader(); + reader.onload = (function(theFile) { + return function(e) { + var data_prefix = "data:;base64,"; + skia_module.postMessage("LoadSKP" + e.target.result.slice(data_prefix.length)); + }; + })(file); + reader.readAsDataURL(file); + } + + function toggleInspector() { + var right_panel = document.getElementById("right_panel"); + var bottom_row = document.getElementById("bottom_row"); + if (right_panel.style.display == display_right_panel) { + right_panel.style.display = "none"; + bottom_row.style.display = "none"; + } else { + right_panel.style.display = display_right_panel; + bottom_row.style.display = display_bottom_row; + } + } + + function onLoad() { + document.getElementById("file_open").addEventListener("change", openFile, false); + var right_panel = document.getElementById("right_panel"); + var bottom_row = document.getElementById("bottom_row"); + display_right_panel = right_panel.style.display; + display_bottom_row = bottom_row.style.display; + updateOverviewDetails(); + updateFilterList(); + } + + // When the module loads, begin running the application. + function moduleDidLoad() { + skia_module = document.getElementById("skia_nacl"); + sendMsg("init"); + } + + function handleMessage(message_event) { + var cmd_skdebugf = "SkDebugf:"; + var cmd_clear_commands = "ClearCommands"; + var cmd_add_command = "AddCommand:"; + var cmd_update_commands = "UpdateCommands"; + var cmd_set_overview = "SetOverview:"; + var cmd_add_filter_option = "AddFilterOption"; + if (message_event.data.indexOf(cmd_skdebugf) == 0) { + var msg_contents = message_event.data.slice(cmd_skdebugf.length) + console.log("Skia: " + msg_contents); + } else if (message_event.data.indexOf(cmd_clear_commands) == 0) { + command_list = []; + command_types = {}; + updateCommandList(); + updateFilterList(); + } else if (message_event.data.indexOf(cmd_add_command) == 0) { + var command = message_event.data.slice(cmd_add_command.length); + command_list.push(command); + if (command_types[command] == undefined) { + command_types[command] = 1; + } else { + command_types[command]++; + } + } else if (message_event.data.indexOf(cmd_update_commands) == 0) { + updateCommandList(); + updateFilterList(); + } else if (message_event.data.indexOf(cmd_set_overview) == 0) { + overview_text = message_event.data.slice(cmd_set_overview.length); + document.getElementById("overview_radio").checked = true; + updateOverviewDetails(); + } else { + alert(message_event.data); + } + } + + // Send a message to the plugin. + function sendMsg(msg) { + if (skia_module) { + //console.log("Sending msg:" + msg); + skia_module.postMessage(msg); + } else { + alert("The Skia module has not properly loaded..."); + } + } + + function commandSelected() { + var command_list = document.getElementById("command_list"); + var selected_index = command_list.options[command_list.selectedIndex].value; + if (selected_index >= 0) { + sendMsg("CommandSelected:" + selected_index); + } + } + + function rewind() { + command_list.selectedIndex = 0; + sendMsg("Rewind"); + } + + function stepBack() { + if (command_list.selectedIndex > 0) { + command_list.selectedIndex = command_list.selectedIndex - 1; + } + sendMsg("StepBack"); + } + + function pause() { + sendMsg("Pause"); + } + + function stepForward() { + if (command_list.selectedIndex < command_list.length - 1) { + command_list.selectedIndex = command_list.selectedIndex + 1; + } + sendMsg("StepForward"); + } + + function play() { + command_list.selectedIndex = command_list.length - 1; + sendMsg("Play"); + } + </script> +</head> +<body onLoad="javascript:onLoad()"> +<div id="content" class="row-set"> + <div id="menu" class="row"> + <ul id="menu-bar" class="dropdown-menu"> + <li><a href="#">File</a> + <ul> + <li><a href="#" onClick="javascript:openFileDialog()">Open</a></li> + <li><a href="#">Save</a></li> + <li><a href="#">Save As</a></li> + <li><a href="#">Exit</a></li> + </ul> + </li> + <li><a href="#">Edit</a> + <ul> + <li><a href="#">Delete Command</a></li> + <li><a href="#">Clear Deletes</a></li> + <li><a href="#">Set Breakpoint</a></li> + <li><a href="#">Clear Breakpoints</a></li> + </ul> + </li> + <li><a href="#">View</a> + <ul> + <li><a href="#">Breakpoints</a></li> + <li><a href="#">Deleted Commands</a></li> + <li><a href="#">Zoom In</a></li> + <li><a href="#">Zoom Out</a></li> + </ul> + </li> + <li><a href="#">Navigate</a> + <ul> + <li><a href="#" onClick="javascript:rewind()">Rewind</a></li> + <li><a href="#" onClick="javascript:stepBack()">Step Back</a></li> + <li><a href="#" onClick="javascript:stepForward()">Step Forward</a></li> + <li><a href="#" onClick="javascript:play()">Play</a></li> + <li><a href="#" onClick="javascript:pause()">Pause</a></li> + <li><a href="#">Go to Line...</a></li> + </ul> + </li> + <li><a href="#">Window</a> + <ul> + <li><a href="#">Inspector</a></li> + <li><a href="#">Directory</a></li> + </ul> + </li> + </ul> + </div> + <div id="buttons" class="row"> + <div class="column-set"> + <div class="column"> + <button onClick="javascript:rewind()"><img src="icons/rewind.png"/><br/>Rewind</button> + <button onClick="javascript:stepBack()"><img src="icons/previous.png"/><br/>Step Back</button> + <button onClick="javascript:pause()"><img src="icons/pause.png"/><br/>Pause</button> + <button onClick="javascript:stepForward()"><img src="icons/next.png"/><br/>Step Forward</button> + <button onClick="javascript:play()"><img src="icons/play.png"/><br/>Play</button> + </div> + <div class="column"> + <button onClick="javascript:toggleInspector()"><img src="icons/inspector.png"/><br/>Inspector</button> + </div> + <div class="column"> + <button><img src="icons/profile.png"/><br/>Profile</button> + </div> + <div class="column" style="text-align:right; vertical-align:middle;"> + <select id="command_filter" onChange="javascript:updateCommandList(this.options[this.selectedIndex].value)"></select> + <button onClick="javascript:updateCommandList()"><img src="icons/reload.png" /><br/>Clear Filter</button> + </div> + </div> + </div> + <div class="row"> + <div class="column-set"> + <div id="left_column" class="column"> + <div class="row-set"> + <div id="command_list_div" class="row"> + <form id="command_list_form"> + <select id="command_list" size="2" onChange="javascript:commandSelected()"> + <option value="-1">Commands go here...</option> + </select> + </form> + </div> + </div> + </div> + <div id="right_column" class="row-set"> + <div id="top_row" class="row"> + <div id="display_pane" class="column"> + <div id="listener" style="width:100%; height:100%;"> + <script type="text/javascript"> + var listener = document.getElementById('listener'); + listener.addEventListener('load', moduleDidLoad, true); + listener.addEventListener('message', handleMessage, true); + </script> + <embed name="nacl_module" + id="skia_nacl" + src="debugger.nmf" + type="application/x-nacl" + width="100%" + height="100%" + style="width:100%, height:100%;"/> + </div> + </div> + <div id="right_panel" class="column"> + <div class="thin_outline"> + <div id="visibility_filter" class="settings_block"> + Visibility Filter<br/> + <div class="thin_outline"> + <form id="visibility_filter_form"> + <input type="radio" name="visibility_filter_radio" value="on">On<br/> + <input type="radio" name="visibility_filter_radio" value="off" checked>Off + </form> + </div> + </div> + <div id="command_scrolling" class="settings_block"> + Command Scrolling Preferences<br/> + <div class="thin_outline"> + <div class="row-set"> + <div class="row"> + <div class="column-set"> + <div class="column"> + Current Command: + </div> + <div class="column" style="text-align:right; width:35%;"> + <input type="text" style="width:100%;"/> + </div> + </div> + </div> + <div class="row"> + <div class="column-set"> + <div class="column"> + Command HitBox: + </div> + <div class="column" style="text-align:right; width:35%;"> + <input type="text" style="width:100%;"/> + </div> + </div> + </div> + </div> + </div> + </div> + <div id="render_targets" class="settings_block"> + Render Targets<br/> + <div class="thin_outline"> + <form id="render_targets_form"> + <div class="row-set"> + <div class="row"> + <div class="column-set"> + <div class="column">Raster:</div> + <div class="column" style="text-align:right;"> + <input type="checkbox" name="render_targets_checkbox" value="raster" checked/> + </div> + </div> + </div> + <div class="row"> + <div class="column-set"> + <div class="column" style="padding-left:30px;">Overdraw Viz:</div> + <div class="column" style="text-align:right;"> + <input type="checkbox" name="render_targets_checkbox" value="overdraw"/> + </div> + </div> + </div> + <div class="row"> + <div class="column-set"> + <div class="column">OpenGL</div> + <div class="column" style="text-align:right;"> + <input type="checkbox" name="render_targets_checkbox" value="opengl"/> + </div> + </div> + </div> + </div> + </form> + </div> + </div> + <div id="zoom_level" class="settings_block"> + <div class="thin_outline"> + <div class="row-set"> + <div class="row"> + <div class="column-set"> + <div class="column"> + Zoom Level: + </div> + <div class="column" style="text-align:right; width:35%;"> + <input type="text" style="width:100%;"/> + </div> + </div> + </div> + </div> + </div> + </div> + </div> + <div id="small_window_wrapper" class="settings_block"> + <div class="thin_outline" style="padding:0px;"> + <div id="small_window"> + </div> + </div> + </div> + </div> + </div> + <div id="bottom_row" class="row"> + <div id="tabview" class="column"> + <div class="row-set"> + <div class="row" style="height:5px; overflow:auto;"> + <form id="overviewdetails_form"> + <input type="radio" name="overviewdetails_radio" onChange="javascript:updateOverviewDetails()" id="overview_radio" value="overview" checked>Overview + <input type="radio" name="overviewdetails_radio" onChange="javascript:updateOverviewDetails()" id="details_radio" value="details">Details + </form> + </div> + <div class="row"> + <div id="overviewdetails"></div> + </div> + </div> + </div> + <div id="matrixclip" class="column"> + Current Matrix + <table> + <tr> + <td><input type="text" id="matrix00" class="matrix" /></td> + <td><input type="text" id="matrix01" class="matrix" /></td> + <td><input type="text" id="matrix02" class="matrix" /></td> + </tr> + <tr> + <td><input type="text" id="matrix10" class="matrix" /></td> + <td><input type="text" id="matrix11" class="matrix" /></td> + <td><input type="text" id="matrix12" class="matrix" /></td> + </tr> + <tr> + <td><input type="text" id="matrix20" class="matrix" /></td> + <td><input type="text" id="matrix21" class="matrix" /></td> + <td><input type="text" id="matrix22" class="matrix" /></td> + </tr> + </table> + Current Clip + <table> + <tr> + <td><input type="text" id="clip00" class="matrix" /></td> + <td><input type="text" id="clip01" class="matrix" /></td> + </tr> + <tr> + <td><input type="text" id="clip10" class="matrix" /></td> + <td><input type="text" id="clip11" class="matrix" /></td> + </tr> + </table> + </div> + </div> + </div> + </div> + </div> +</div> +<input type="file" id="file_open" style="display:none;"/> +</body> +</html> diff --git a/platform_tools/nacl/favicon.ico b/platform_tools/nacl/favicon.ico Binary files differnew file mode 100644 index 0000000000..e7440c7512 --- /dev/null +++ b/platform_tools/nacl/favicon.ico diff --git a/platform_tools/nacl/gclient.config b/platform_tools/nacl/gclient.config new file mode 100644 index 0000000000..922ae43db8 --- /dev/null +++ b/platform_tools/nacl/gclient.config @@ -0,0 +1,13 @@ +# To develop Skia targeting NaCl, +# copy this file to your root development directory as ".gclient" +# and then run "gclient sync". +solutions = [ + { + "name" : "nacl", + "url" : "https://skia.googlecode.com/svn/nacl", + }, + { + "name" : "trunk", + "url" : "https://skia.googlecode.com/svn/trunk", + }, +] diff --git a/platform_tools/nacl/httpd.py b/platform_tools/nacl/httpd.py new file mode 100755 index 0000000000..2ad1d49438 --- /dev/null +++ b/platform_tools/nacl/httpd.py @@ -0,0 +1,212 @@ +#!/usr/bin/env python +# Copyright (c) 2012 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +"""A tiny web server. + +This is intended to be used for testing, and only run from within the examples +directory. +""" + +import BaseHTTPServer +import logging +import optparse +import os +import SimpleHTTPServer +import SocketServer +import sys +import urlparse + + +EXAMPLE_PATH=os.path.dirname(os.path.abspath(__file__)) +NACL_SDK_ROOT = os.getenv('NACL_SDK_ROOT', os.path.dirname(EXAMPLE_PATH)) + + +if os.path.exists(NACL_SDK_ROOT): + sys.path.append(os.path.join(NACL_SDK_ROOT, 'tools')) + import decode_dump + import getos +else: + NACL_SDK_ROOT=None + +last_nexe = None +last_nmf = None + +logging.getLogger().setLevel(logging.INFO) + +# Using 'localhost' means that we only accept connections +# via the loop back interface. +SERVER_PORT = 5103 +SERVER_HOST = '' + +# We only run from the examples directory so that not too much is exposed +# via this HTTP server. Everything in the directory is served, so there should +# never be anything potentially sensitive in the serving directory, especially +# if the machine might be a multi-user machine and not all users are trusted. +# We only serve via the loopback interface. +def SanityCheckDirectory(): + httpd_path = os.path.abspath(os.path.dirname(__file__)) + serve_path = os.path.abspath(os.getcwd()) + + # Verify we are serving from the directory this script came from, or bellow + if serve_path[:len(httpd_path)] == httpd_path: + return + logging.error('For security, httpd.py should only be run from within the') + logging.error('example directory tree.') + logging.error('We are currently in %s.' % serve_path) + sys.exit(1) + + +# An HTTP server that will quit when |is_running| is set to False. We also use +# SocketServer.ThreadingMixIn in order to handle requests asynchronously for +# faster responses. +class QuittableHTTPServer(SocketServer.ThreadingMixIn, + BaseHTTPServer.HTTPServer): + def serve_forever(self, timeout=0.5): + self.is_running = True + self.timeout = timeout + while self.is_running: + self.handle_request() + + def shutdown(self): + self.is_running = False + return 1 + + +# "Safely" split a string at |sep| into a [key, value] pair. If |sep| does not +# exist in |str|, then the entire |str| is the key and the value is set to an +# empty string. +def KeyValuePair(str, sep='='): + if sep in str: + return str.split(sep) + else: + return [str, ''] + + +# A small handler that looks for '?quit=1' query in the path and shuts itself +# down if it finds that parameter. +class QuittableHTTPHandler(SimpleHTTPServer.SimpleHTTPRequestHandler): + def send_head(self): + """Common code for GET and HEAD commands. + + This sends the response code and MIME headers. + + Return value is either a file object (which has to be copied + to the outputfile by the caller unless the command was HEAD, + and must be closed by the caller under all circumstances), or + None, in which case the caller has nothing further to do. + + """ + path = self.translate_path(self.path) + f = None + if os.path.isdir(path): + if not self.path.endswith('/'): + # redirect browser - doing basically what apache does + self.send_response(301) + self.send_header("Location", self.path + "/") + self.end_headers() + return None + for index in "index.html", "index.htm": + index = os.path.join(path, index) + if os.path.exists(index): + path = index + break + else: + return self.list_directory(path) + ctype = self.guess_type(path) + try: + # Always read in binary mode. Opening files in text mode may cause + # newline translations, making the actual size of the content + # transmitted *less* than the content-length! + f = open(path, 'rb') + except IOError: + self.send_error(404, "File not found") + return None + self.send_response(200) + self.send_header("Content-type", ctype) + fs = os.fstat(f.fileno()) + self.send_header("Content-Length", str(fs[6])) + self.send_header("Last-Modified", self.date_time_string(fs.st_mtime)) + self.send_header('Cache-Control','no-cache, must-revalidate') + self.send_header('Expires','-1') + self.end_headers() + return f + + def do_GET(self): + global last_nexe, last_nmf + (_, _, path, query, _) = urlparse.urlsplit(self.path) + url_params = dict([KeyValuePair(key_value) + for key_value in query.split('&')]) + if 'quit' in url_params and '1' in url_params['quit']: + self.send_response(200, 'OK') + self.send_header('Content-type', 'text/html') + self.send_header('Content-length', '0') + self.end_headers() + self.server.shutdown() + return + + if path.endswith('.nexe'): + last_nexe = path + if path.endswith('.nmf'): + last_nmf = path + + SimpleHTTPServer.SimpleHTTPRequestHandler.do_GET(self) + + def do_POST(self): + (_, _,path, query, _) = urlparse.urlsplit(self.path) + if 'Content-Length' in self.headers: + if not NACL_SDK_ROOT: + self.wfile('Could not find NACL_SDK_ROOT to decode trace.') + return + data = self.rfile.read(int(self.headers['Content-Length'])) + nexe = '.' + last_nexe + nmf = '.' + last_nmf + addr = os.path.join(NACL_SDK_ROOT, 'toolchain', + getos.GetPlatform() + '_x86_newlib', + 'bin', 'x86_64-nacl-addr2line') + decoder = decode_dump.CoreDecoder(nexe, nmf, addr, None, None) + info = decoder.Decode(data) + trace = decoder.StackTrace(info) + decoder.PrintTrace(trace, sys.stdout) + decoder.PrintTrace(trace, self.wfile) + + +def Run(server_address, + server_class=QuittableHTTPServer, + handler_class=QuittableHTTPHandler): + httpd = server_class(server_address, handler_class) + logging.info("Starting local server on port %d", server_address[1]) + logging.info("To shut down send http://localhost:%d?quit=1", + server_address[1]) + try: + httpd.serve_forever() + except KeyboardInterrupt: + logging.info("Received keyboard interrupt.") + httpd.server_close() + + logging.info("Shutting down local server on port %d", server_address[1]) + + +def main(): + usage_str = "usage: %prog [options] [optional_portnum]" + parser = optparse.OptionParser(usage=usage_str) + parser.add_option( + '--no_dir_check', dest='do_safe_check', + action='store_false', default=True, + help='Do not ensure that httpd.py is being run from a safe directory.') + (options, args) = parser.parse_args(sys.argv) + if options.do_safe_check: + SanityCheckDirectory() + if len(args) > 2: + print 'Too many arguments specified.' + parser.print_help() + elif len(args) == 2: + Run((SERVER_HOST, int(args[1]))) + else: + Run((SERVER_HOST, SERVER_PORT)) + return 0 + + +if __name__ == '__main__': + sys.exit(main()) diff --git a/platform_tools/nacl/index.html b/platform_tools/nacl/index.html new file mode 100644 index 0000000000..abe5d1e6ef --- /dev/null +++ b/platform_tools/nacl/index.html @@ -0,0 +1,22 @@ +<!DOCTYPE html> +<html> + <!-- + Copyright 2013 Google Inc. + + Use of this source code is governed by a BSD-style license that can be + found in the LICENSE file. + --> +<head> + <title>Skia Native Client Apps</title> +</head> +<body> + <h1>Skia Native Client Apps</h1> + <p> + <ul> + <li><a href="tests">Skia Unit Tests</a></li> + <li><a href="debugger">Skia Debugger</a></li> + <li><a href="SampleApp">Skia Sample App</a></li> + </ul> + </p> +</body> +</html> diff --git a/platform_tools/nacl/nacl_make b/platform_tools/nacl/nacl_make new file mode 100755 index 0000000000..81f6eb23dd --- /dev/null +++ b/platform_tools/nacl/nacl_make @@ -0,0 +1,104 @@ +#!/bin/bash + +function setenv { + if [ -z "$1" ]; then + echo "ERROR: setenv() requires one argument." + exit 1 + fi + if [ -z "${NACL_SDK_ROOT}" ]; then + echo "ERROR: This script requires NACL_SDK_ROOT to be set." + exit 1 + fi + + ARCH_WIDTH=$1 + if [ ${ARCH_WIDTH} = "32" ]; then + CROSS_ID=i686 + elif [ ${ARCH_WIDTH} = "64" ]; then + CROSS_ID=x86_64 + else + echo "ERROR: Unknown arch width: ${ARCH_WIDTH}" + exit 1 + fi + + OS_NAME=$(uname -s) + if [ $OS_NAME = "Darwin" ]; then + OS_SUBDIR="mac" + OS_SUBDIR_SHORT="mac" + OS_JOBS=4 + elif [ $OS_NAME = "Linux" ]; then + OS_SUBDIR="linux" + OS_SUBDIR_SHORT="linux" + OS_JOBS=4 + else + OS_SUBDIR="windows" + OS_SUBDIR_SHORT="win" + OS_JOBS=1 + fi + + NACL_TOOLCHAIN_ROOT=${NACL_SDK_ROOT}/toolchain/${OS_SUBDIR_SHORT}_x86_newlib + NACL_BIN_PATH=${NACL_TOOLCHAIN_ROOT}/bin + export NACL_CROSS_PREFIX=${CROSS_ID}-nacl + + if [[ -z "$NACL_MAKE_CCACHE" ]]; then + export NACLCC=${NACL_BIN_PATH}/${NACL_CROSS_PREFIX}-gcc + export NACLCXX=${NACL_BIN_PATH}/${NACL_CROSS_PREFIX}-g++ + else + export NACLCC="${NACL_MAKE_CCACHE} ${NACL_BIN_PATH}/${NACL_CROSS_PREFIX}-gcc" + export NACLCXX="${NACL_MAKE_CCACHE} ${NACL_BIN_PATH}/${NACL_CROSS_PREFIX}-g++" + fi + export NACLAR=${NACL_BIN_PATH}/${NACL_CROSS_PREFIX}-ar + export NACLRANLIB=${NACL_BIN_PATH}/${NACL_CROSS_PREFIX}-ranlib + export NACLLD=${NACL_BIN_PATH}/${NACL_CROSS_PREFIX}-ld + export NACLSTRINGS=${NACL_BIN_PATH}/${NACL_CROSS_PREFIX}-strings + export NACLSTRIP=${NACL_BIN_PATH}/${NACL_CROSS_PREFIX}-strip + + export CC=${NACLCC} + export CXX=${NACLCXX} + export AR=${NACLAR} + export RANLIB=${NACLRANLIB} + export PATH=${NACL_BIN_PATH}:${PATH}; + + export GYP_DEFINES="skia_os=nacl skia_arch_width=${ARCH_WIDTH}" +} + +function build { + if [ -z "$1" ]; then + echo "ERROR: build() requires one argument." + exit 1 + fi + setenv $1 + + export SKIA_OUT=out/nacl$1 + make ${MAKE_ARGS} +} + +MAKE_ARGS="" + +while (( "$#" )); do + if [[ "$1" == "--use-ccache" ]]; + then + if [[ -z "$NACL_MAKE_CCACHE" ]]; + then + NACL_MAKE_CCACHE=$(which ccache) + fi + elif [ -z "${MAKE_ARGS}" ]; then + MAKE_ARGS="$1" + else + MAKE_ARGS="${MAKE_ARGS} $1" + fi + shift +done + +if [[ -n "$NACL_MAKE_CCACHE" ]]; then + $NACL_MAKE_CCACHE --version &> /dev/null + if [[ "$?" != "0" ]]; then + echo "Unable to find ccache!" + exit 1 + fi +fi + +build 32 && \ +build 64 && \ +if ! [ -L platform_tools/nacl/out ]; then + ln -s ../../out platform_tools/nacl +fi
\ No newline at end of file diff --git a/platform_tools/nacl/src/nacl_debugger.cpp b/platform_tools/nacl/src/nacl_debugger.cpp new file mode 100644 index 0000000000..26e3ed67c7 --- /dev/null +++ b/platform_tools/nacl/src/nacl_debugger.cpp @@ -0,0 +1,221 @@ + +/* + * Copyright 2013 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "ppapi/cpp/completion_callback.h" +#include "ppapi/cpp/graphics_2d.h" +#include "ppapi/cpp/image_data.h" +#include "ppapi/cpp/instance.h" +#include "ppapi/cpp/module.h" +#include "ppapi/cpp/point.h" +#include "ppapi/cpp/rect.h" +#include "ppapi/cpp/var.h" + +#include "SkBase64.h" +#include "SkBitmap.h" +#include "SkCanvas.h" +#include "SkColor.h" +#include "SkDebugger.h" +#include "SkGraphics.h" +#include "SkStream.h" +#include "SkString.h" + +class SkiaInstance; + +// Used by SkDebugf +SkiaInstance* gPluginInstance; + +void FlushCallback(void* data, int32_t result); + +// Skia's subclass of pp::Instance, our interface with the browser. +class SkiaInstance : public pp::Instance { +public: + explicit SkiaInstance(PP_Instance instance) + : pp::Instance(instance) + , fCanvas(NULL) + , fPicture(NULL) + , fFlushLoopRunning(false) + , fFlushPending(false) + + { + gPluginInstance = this; + SkGraphics::Init(); + } + + virtual ~SkiaInstance() { + SkGraphics::Term(); + gPluginInstance = NULL; + } + + virtual void HandleMessage(const pp::Var& var_message) { + // Receive a message from javascript. + if (var_message.is_string()) { + SkString msg(var_message.AsString().c_str()); + if (msg.startsWith("init")) { + } else if (msg.startsWith("LoadSKP")) { + size_t startIndex = strlen("LoadSKP"); + size_t dataSize = msg.size()/sizeof(char) - startIndex; + SkBase64 decodedData; + decodedData.decode(msg.c_str() + startIndex, dataSize); + size_t decodedSize = 3 * (dataSize / 4); + SkDebugf("Got size: %d\n", decodedSize); + if (!decodedData.getData()) { + SkDebugf("Failed to decode SKP\n"); + return; + } + SkMemoryStream pictureStream(decodedData.getData(), decodedSize); + fPicture = new SkPicture(&pictureStream); + if (fPicture->width() == 0 || fPicture->height() == 0) { + SkDebugf("Failed to create SKP.\n"); + return; + } + fDebugger.loadPicture(fPicture); + + // Set up the command list. + SkTArray<SkString>* commands = fDebugger.getDrawCommandsAsStrings(); + PostMessage("ClearCommands"); + for (int i = 0; i < commands->count(); ++i) { + SkString addCommand("AddCommand:"); + addCommand.append((*commands)[i]); + PostMessage(addCommand.c_str()); + } + PostMessage("UpdateCommands"); + + // Set the overview text. + SkString overviewText; + fDebugger.getOverviewText(NULL, 0.0, &overviewText, 1); + overviewText.prepend("SetOverview:"); + PostMessage(overviewText.c_str()); + + // Draw the SKP. + if (!fFlushLoopRunning) { + Paint(); + } + } else if (msg.startsWith("CommandSelected:")) { + size_t startIndex = strlen("CommandSelected:"); + int index = atoi(msg.c_str() + startIndex); + fDebugger.setIndex(index); + if (!fFlushLoopRunning) { + Paint(); + } + } else if (msg.startsWith("Rewind")) { + fCanvas->clear(SK_ColorWHITE); + fDebugger.setIndex(0); + if (!fFlushLoopRunning) { + Paint(); + } + } else if (msg.startsWith("StepBack")) { + fCanvas->clear(SK_ColorWHITE); + int currentIndex = fDebugger.index(); + if (currentIndex > 1) { + fDebugger.setIndex(currentIndex - 1); + if (!fFlushLoopRunning) { + Paint(); + } + } + } else if (msg.startsWith("Pause")) { + // TODO(borenet) + } else if (msg.startsWith("StepForward")) { + int currentIndex = fDebugger.index(); + if (currentIndex < fDebugger.getSize() -1) { + fDebugger.setIndex(currentIndex + 1); + if (!fFlushLoopRunning) { + Paint(); + } + } + } else if (msg.startsWith("Play")) { + fDebugger.setIndex(fDebugger.getSize() - 1); + if (!fFlushLoopRunning) { + Paint(); + } + } + } + } + + void Paint() { + if (!fImage.is_null()) { + fDebugger.draw(fCanvas); + fDeviceContext.PaintImageData(fImage, pp::Point(0, 0)); + if (!fFlushPending) { + fFlushPending = true; + fDeviceContext.Flush(pp::CompletionCallback(&FlushCallback, this)); + } else { + SkDebugf("A flush is pending... Skipping flush.\n"); + } + } else { + SkDebugf("No pixels to write to!\n"); + } + } + + virtual void DidChangeView(const pp::Rect& position, const pp::Rect& clip) { + if (position.size().width() == fWidth && + position.size().height() == fHeight) { + return; // We don't care about the position, only the size. + } + fWidth = position.size().width(); + fHeight = position.size().height(); + + fDeviceContext = pp::Graphics2D(this, pp::Size(fWidth, fHeight), false); + if (!BindGraphics(fDeviceContext)) { + SkDebugf("Couldn't bind the device context\n"); + return; + } + fImage = pp::ImageData(this, + PP_IMAGEDATAFORMAT_BGRA_PREMUL, + pp::Size(fWidth, fHeight), false); + fBitmap.setConfig(SkBitmap::kARGB_8888_Config, fWidth, fHeight); + fBitmap.setPixels(fImage.data()); + if (fCanvas) { + delete fCanvas; + } + fCanvas = new SkCanvas(fBitmap); + fCanvas->clear(SK_ColorWHITE); + if (!fFlushLoopRunning) { + Paint(); + } + } + + void OnFlush() { + fFlushLoopRunning = true; + fFlushPending = false; + Paint(); + } + +private: + pp::Graphics2D fDeviceContext; + pp::ImageData fImage; + int fWidth; + int fHeight; + + SkBitmap fBitmap; + SkCanvas* fCanvas; + SkDebugger fDebugger; + SkPicture* fPicture; + + bool fFlushLoopRunning; + bool fFlushPending; +}; + +void FlushCallback(void* data, int32_t result) { + static_cast<SkiaInstance*>(data)->OnFlush(); +} + +class SkiaModule : public pp::Module { +public: + SkiaModule() : pp::Module() {} + virtual ~SkiaModule() {} + + virtual pp::Instance* CreateInstance(PP_Instance instance) { + return new SkiaInstance(instance); + } +}; + +namespace pp { +Module* CreateModule() { + return new SkiaModule(); +} +} // namespace pp diff --git a/platform_tools/nacl/src/nacl_interface.cpp b/platform_tools/nacl/src/nacl_interface.cpp new file mode 100644 index 0000000000..09d55c3fec --- /dev/null +++ b/platform_tools/nacl/src/nacl_interface.cpp @@ -0,0 +1,111 @@ + +/* + * Copyright 2013 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#include "ppapi/cpp/completion_callback.h" +#include "ppapi/cpp/graphics_2d.h" +#include "ppapi/cpp/image_data.h" +#include "ppapi/cpp/instance.h" +#include "ppapi/cpp/module.h" +#include "ppapi/cpp/var.h" + +#include "SkCanvas.h" +#include "SkBitmap.h" +#include "SkString.h" +#include "SkThreadUtils.h" + +class SkiaInstance; + +// Used by SkDebugf +SkiaInstance* gPluginInstance; + +// Main entry point for the app we're linked into +extern int tool_main(int, char**); + +// Tokenize a command line and store it in argc and argv. +void SkStringToProgramArgs(const SkString commandLine, int* argc, char*** argv) { + int numBreaks = 0; + const char* commandChars = commandLine.c_str(); + for (size_t i = 0; i < strlen(commandChars); i++) { + if (isspace(commandChars[i])) { + numBreaks++; + } + } + int numArgs; + if (strlen(commandChars) > 0) { + numArgs = numBreaks + 1; + } else { + numArgs = 0; + } + *argc = numArgs; + *argv = new char*[numArgs + 1]; + (*argv)[numArgs] = NULL; + char* start = (char*) commandChars; + int length = 0; + int argIndex = 0; + for (size_t i = 0; i < strlen(commandChars) + 1; i++) { + if (isspace(commandChars[i]) || '\0' == commandChars[i]) { + if (length > 0) { + char* argument = new char[length + 1]; + memcpy(argument, start, length); + argument[length] = '\0'; + (*argv)[argIndex++] = argument; + } + start = (char*) commandChars + i + 1; + length = 0; + } else { + length++; + } + } +} + +// Run the program with the given command line. +void RunProgram(const SkString& commandLine) { + int argc; + char** argv; + SkStringToProgramArgs(commandLine, &argc, &argv); + tool_main(argc, argv); +} + + +// Skia's subclass of pp::Instance, our interface with the browser. +class SkiaInstance : public pp::Instance { +public: + explicit SkiaInstance(PP_Instance instance) : pp::Instance(instance) { + gPluginInstance = this; + } + + virtual ~SkiaInstance() { + gPluginInstance = NULL; + } + + virtual void HandleMessage(const pp::Var& var_message) { + // Receive a message from javascript. + if (var_message.is_string()) { + SkString msg(var_message.AsString().c_str()); + if (msg.startsWith("init")) { + RunProgram(msg); + } + } + } +}; + +class SkiaModule : public pp::Module { +public: + SkiaModule() : pp::Module() {} + virtual ~SkiaModule() {} + + virtual pp::Instance* CreateInstance(PP_Instance instance) { + return new SkiaInstance(instance); + } +}; + +namespace pp { +Module* CreateModule() { + return new SkiaModule(); +} +} // namespace pp diff --git a/platform_tools/nacl/src/nacl_sample.cpp b/platform_tools/nacl/src/nacl_sample.cpp new file mode 100644 index 0000000000..aca74f4247 --- /dev/null +++ b/platform_tools/nacl/src/nacl_sample.cpp @@ -0,0 +1,212 @@ +#include <cstdio> +#include <string> + +#include "ppapi/cpp/completion_callback.h" +#include "ppapi/cpp/graphics_2d.h" +#include "ppapi/cpp/image_data.h" +#include "ppapi/cpp/instance.h" +#include "ppapi/cpp/module.h" +#include "ppapi/cpp/var.h" + +#include "SampleApp.h" +#include "SkApplication.h" +#include "SkCanvas.h" +#include "SkBitmap.h" +#include "SkEvent.h" +#include "SkWindow.h" + +class SkiaInstance; + +namespace { +void FlushCallback(void* data, int32_t result); +} + +SkiaInstance* gPluginInstance; +extern int main(int, char**); + +class SkiaInstance : public pp::Instance { + public: + explicit SkiaInstance(PP_Instance instance) : pp::Instance(instance), + fFlushPending(false), + fGraphics2dContext(NULL), + fPixelBuffer(NULL) + { + gPluginInstance = this; + application_init(); + char* commandName = "SampleApp"; + fWindow = new SampleWindow(NULL, 0, &commandName, NULL); + } + + virtual ~SkiaInstance() { + gPluginInstance = NULL; + delete fWindow; + application_term(); + } + + virtual void HandleMessage(const pp::Var& var_message) { + // Receive a message from javascript. Right now this just signals us to + // get started. + uint32_t width = 500; + uint32_t height = 500; + char buffer[2048]; + sprintf(buffer, "SetSize:%d,%d", width, height); + PostMessage(buffer); + } + + virtual void DidChangeView(const pp::Rect& position, + const pp::Rect& clip) { + if (position.size().width() == width() && + position.size().height() == height()) { + return; // Size didn't change, no need to update anything. + } + // Create a new device context with the new size. + DestroyContext(); + CreateContext(position.size()); + // Delete the old pixel buffer and create a new one. + delete fPixelBuffer; + fPixelBuffer = NULL; + if (fGraphics2dContext != NULL) { + fPixelBuffer = new pp::ImageData(this, + PP_IMAGEDATAFORMAT_BGRA_PREMUL, + fGraphics2dContext->size(), + false); + fWindow->resize(position.size().width(), position.size().height()); + fWindow->update(NULL); + paint(); + } + } + + // Indicate whether a flush is pending. This can only be called from the + // main thread; it is not thread safe. + bool flush_pending() const { + return fFlushPending; + } + void set_flush_pending(bool flag) { + fFlushPending = flag; + } + + void paint() { + if (fPixelBuffer) { + // Draw some stuff. TODO(borenet): Actually have SampleApp draw into + // the plugin area. + uint32_t w = fPixelBuffer->size().width(); + uint32_t h = fPixelBuffer->size().height(); + uint32_t* data = (uint32_t*) fPixelBuffer->data(); + // Create a bitmap using the fPixelBuffer pixels + SkBitmap bitmap; + bitmap.setConfig(SkBitmap::kARGB_8888_Config, w, h); + bitmap.setPixels(data); + // Create a canvas with the bitmap as the backend + SkCanvas canvas(bitmap); + + canvas.drawColor(SK_ColorBLUE); + SkRect rect = SkRect::MakeXYWH(10, 10, 80, 80); + SkPaint rect_paint; + rect_paint.setStyle(SkPaint::kFill_Style); + rect_paint.setColor(SK_ColorRED); + canvas.drawRect(rect, rect_paint); + + FlushPixelBuffer(); + } + } + +private: + int width() const { + return fPixelBuffer ? fPixelBuffer->size().width() : 0; + } + + int height() const { + return fPixelBuffer ? fPixelBuffer->size().height() : 0; + } + + bool IsContextValid() const { + return fGraphics2dContext != NULL; + } + + void CreateContext(const pp::Size& size) { + if (IsContextValid()) + return; + fGraphics2dContext = new pp::Graphics2D(this, size, false); + if (!BindGraphics(*fGraphics2dContext)) { + SkDebugf("Couldn't bind the device context"); + } + } + + void DestroyContext() { + if (!IsContextValid()) + return; + delete fGraphics2dContext; + fGraphics2dContext = NULL; + } + + void FlushPixelBuffer() { + if (!IsContextValid()) + return; + // Note that the pixel lock is held while the buffer is copied into the + // device context and then flushed. + fGraphics2dContext->PaintImageData(*fPixelBuffer, pp::Point()); + if (flush_pending()) + return; + set_flush_pending(true); + fGraphics2dContext->Flush(pp::CompletionCallback(&FlushCallback, this)); + } + + bool fFlushPending; + pp::Graphics2D* fGraphics2dContext; + pp::ImageData* fPixelBuffer; + SampleWindow* fWindow; +}; + +class SkiaModule : public pp::Module { +public: + SkiaModule() : pp::Module() {} + virtual ~SkiaModule() {} + + virtual pp::Instance* CreateInstance(PP_Instance instance) { + gPluginInstance = new SkiaInstance(instance); + return gPluginInstance; + } +}; + +namespace { +void FlushCallback(void* data, int32_t result) { + static_cast<SkiaInstance*>(data)->set_flush_pending(false); +} +} + +namespace pp { +Module* CreateModule() { + return new SkiaModule(); +} +} // namespace pp + + +/////////////////////////////////////////// +///////////// SkOSWindow impl ///////////// +/////////////////////////////////////////// + +void SkOSWindow::onSetTitle(const char title[]) +{ + char buffer[2048]; + sprintf(buffer, "SetTitle:%s", title); + gPluginInstance->PostMessage(buffer); +} + +void SkOSWindow::onHandleInval(const SkIRect& rect) +{ + gPluginInstance->paint(); +} + +void SkOSWindow::onPDFSaved(const char title[], const char desc[], + const char path[]) { +} + +/////////////////////////////////////////// +/////////////// SkEvent impl ////////////// +/////////////////////////////////////////// + +void SkEvent::SignalQueueTimer(SkMSec ms) { +} + +void SkEvent::SignalNonEmptyQueue() { +} diff --git a/platform_tools/nacl/tests/index.html b/platform_tools/nacl/tests/index.html new file mode 100644 index 0000000000..3a0bdb9415 --- /dev/null +++ b/platform_tools/nacl/tests/index.html @@ -0,0 +1,78 @@ +<!DOCTYPE html> +<html> + <!-- + Copyright 2013 Google Inc. + + Use of this source code is governed by a BSD-style license that can be + found in the LICENSE file. + --> +<head> + + <title>Skia Unit Tests</title> + + <script type="text/javascript"> + "use strict"; + + var SkiaModule = null; // Global application object. + + // Force a re-draw of the given element. + function refresh(elem) { + var old_display_style = elem.style.display; + elem.style.display = "none"; + elem.style.display = old_display_style; + } + + // When the module loads, begin running the application. + function moduleDidLoad() { + SkiaModule = document.getElementById("skia_nacl"); + run(); + } + + function handleMessage(message_event) { + var skdebugf_cmd = "SkDebugf:"; + if (message_event.data.indexOf(skdebugf_cmd) == 0) { + var msg_contents = message_event.data.slice(skdebugf_cmd.length) + //console.log("Skia: " + msg_contents); + var log_textarea = document.getElementById("log_textarea") + log_textarea.value += msg_contents; + log_textarea.scrollTop = log_textarea.scrollHeight; + refresh(log_textarea); + } else { + alert(message_event.data); + } + } + + // Run the application. + function run() { + if (SkiaModule) { + var cmd = "init"; + SkiaModule.postMessage(cmd); + } else { + alert("The Skia module has not properly loaded..."); + } + } + </script> +</head> +<body> + +<h1>Skia Unit Tests</h1> +<p> +<textarea id="log_textarea" rows="2" cols="2" readonly style="width:100%; height:500px; resize:none;"></textarea> +</p> +<p> + <div id="listener"> + <script type="text/javascript"> + var listener = document.getElementById('listener'); + listener.addEventListener('load', moduleDidLoad, true); + listener.addEventListener('message', handleMessage, true); + </script> + + <embed name="nacl_module" + id="skia_nacl" + width=0 height=0 + src="tests.nmf" + type="application/x-nacl" /> + </div> +</p> +</body> +</html> diff --git a/platform_tools/nacl/tests/tests.nmf b/platform_tools/nacl/tests/tests.nmf new file mode 100644 index 0000000000..95db050086 --- /dev/null +++ b/platform_tools/nacl/tests/tests.nmf @@ -0,0 +1,6 @@ +{ + "program": { + "x86-64": {"url": "../../out/nacl64/Debug/tests"}, + "x86-32": {"url": "../../out/nacl32/Debug/tests"} + } +} |