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
This commit is contained in:
borenet@google.com 2013-05-06 12:50:00 +00:00
parent f073b3332d
commit 6a98b8c0b5
30 changed files with 1704 additions and 2 deletions

View File

@ -109,7 +109,7 @@
'../src/utils',
],
'sources': [
'../../nacl/src/nacl_debugger.cpp',
'../platform_tools/nacl/src/nacl_debugger.cpp',
],
}, { # skia_os != "nacl"
'include_dirs': [

View File

@ -12,7 +12,7 @@
'../src/utils',
],
'sources': [
'../../nacl/src/nacl_interface.cpp',
'../platform_tools/nacl/src/nacl_interface.cpp',
],
},
],

View File

@ -0,0 +1,6 @@
{
"program": {
"x86-64": {"url": "../../out/nacl64/Debug/SampleApp"},
"x86-32": {"url": "../../out/nacl32/Debug/SampleApp"}
}
}

View File

@ -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>

View File

@ -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;
}

View File

@ -0,0 +1,6 @@
{
"program": {
"x86-64": {"url": "../../out/nacl64/Debug/debugger"},
"x86-32": {"url": "../../out/nacl32/Debug/debugger"}
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 146 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 938 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 943 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 243 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

View File

@ -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>

Binary file not shown.

After

Width:  |  Height:  |  Size: 318 B

View File

@ -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",
},
]

212
platform_tools/nacl/httpd.py Executable file
View File

@ -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())

View File

@ -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>

104
platform_tools/nacl/nacl_make Executable file
View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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() {
}

View File

@ -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>

View File

@ -0,0 +1,6 @@
{
"program": {
"x86-64": {"url": "../../out/nacl64/Debug/tests"},
"x86-32": {"url": "../../out/nacl32/Debug/tests"}
}
}