Revert "delete old things!"

This reverts commit 15b125d401.

NOTREECHECKS=true

original change breaks android tree

BUG=skia:

Review URL: https://codereview.chromium.org/848073005
This commit is contained in:
Brian Salomon 2015-01-16 16:26:32 -05:00
parent 15b125d401
commit 8b4489b6e6
456 changed files with 903943 additions and 0 deletions

View File

@ -44,6 +44,7 @@ VALID_TARGETS := \
debugger \
dm \
everything \
gm \
most \
pathops_unittest \
pdfviewer \

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,12 @@
Baseline images originally generated on a Mac Mini
Model Name: Mac mini
Model Identifier: Macmini4,1
Processor Name: Intel Core 2 Duo
Chipset Model: NVIDIA GeForce 320M
Ran these commands to generate:
GYP_DEFINES="skia_scalar=float" make gm
out/Debug/gm -w gm/base-macmini

View File

@ -0,0 +1,12 @@
Baseline images originally generated on a Mac Mini
Model Name: Mac mini
Model Identifier: Macmini4,1
Processor Name: Intel Core 2 Duo
Chipset Model: NVIDIA GeForce 320M
Ran these commands to generate:
GYP_DEFINES="skia_scalar=float" make gm
out/Debug/gm -w gm/base-macmini

View File

@ -0,0 +1,12 @@
Baseline images originally generated on a Mac Mini
Model Name: Mac mini
Model Identifier: Macmini4,1
Processor Name: Intel Core 2 Duo
Chipset Model: NVIDIA GeForce 320M
Ran these commands to generate:
GYP_DEFINES="skia_scalar=float" make gm
out/Debug/gm -w gm/base-macmini

View File

@ -0,0 +1,12 @@
Baseline images originally generated on a Mac Mini
Model Name: Mac mini
Model Identifier: Macmini4,1
Processor Name: Intel Core 2 Duo
Chipset Model: NVIDIA GeForce 320M
Ran these commands to generate:
GYP_DEFINES="skia_scalar=float" make gm
out/Debug/gm -w gm/base-macmini

View File

@ -0,0 +1,11 @@
Baseline images originally generated on our Skia_MacMiniLion_Float builtbot slave.
Model Name: Mac mini
Model Identifier: Macmini4,1
Processor Name: Intel Core 2 Duo
Chipset Model: NVIDIA GeForce 320M
OS: Mac OS 10.7.2

View File

@ -0,0 +1,11 @@
Baseline images originally generated on our Skia_MacMiniLion_Float builtbot slave.
Model Name: Mac mini
Model Identifier: Macmini4,1
Processor Name: Intel Core 2 Duo
Chipset Model: NVIDIA GeForce 320M
OS: Mac OS 10.7.2

View File

@ -0,0 +1,11 @@
Baseline images originally generated on our Skia_MacMiniLion_Float builtbot slave.
Model Name: Mac mini
Model Identifier: Macmini4,1
Processor Name: Intel Core 2 Duo
Chipset Model: NVIDIA GeForce 320M
OS: Mac OS 10.7.2

View File

@ -0,0 +1,11 @@
Baseline images originally generated on our Skia_MacMiniLion_Float builtbot slave.
Model Name: Mac mini
Model Identifier: Macmini4,1
Processor Name: Intel Core 2 Duo
Chipset Model: NVIDIA GeForce 320M
OS: Mac OS 10.7.2

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,3 @@
{
"expected-results": {}
}

View File

@ -0,0 +1,132 @@
{
"expected-results": {
"imageblurtiled_565.png": {
"allowed-digests": [
[
"bitmap-64bitMD5",
1672239788423162481
]
]
},
"imageblurtiled_8888.png": {
"allowed-digests": [
[
"bitmap-64bitMD5",
6974201924079969276
]
]
},
"imageblurtiled_gpu.png": {
"allowed-digests": [
[
"bitmap-64bitMD5",
18402970219099615441
]
]
},
"imageblurtiled_pdf-poppler.png": {
"allowed-digests": [
[
"bitmap-64bitMD5",
7162962487674293114
]
]
},
"imagefiltersclipped_565.png": {
"allowed-digests": [
[
"bitmap-64bitMD5",
14771974755728278127
]
]
},
"imagefiltersclipped_8888.png": {
"allowed-digests": [
[
"bitmap-64bitMD5",
14537515405997069608
]
]
},
"imagefiltersclipped_gpu.png": {
"allowed-digests": [
[
"bitmap-64bitMD5",
11179989646465517468
]
]
},
"imagefiltersclipped_pdf-poppler.png": {
"allowed-digests": [
[
"bitmap-64bitMD5",
3854266854123865664
]
]
},
"imagefiltersscaled_565.png": {
"allowed-digests": [
[
"bitmap-64bitMD5",
15769177648683788265
]
]
},
"imagefiltersscaled_8888.png": {
"allowed-digests": [
[
"bitmap-64bitMD5",
18437708945397499005
]
]
},
"imagefiltersscaled_gpu.png": {
"allowed-digests": [
[
"bitmap-64bitMD5",
8877499313441323086
]
]
},
"imagefiltersscaled_pdf-poppler.png": {
"allowed-digests": [
[
"bitmap-64bitMD5",
7403124810876127284
]
]
},
"resizeimagefilter_565.png": {
"allowed-digests": [
[
"bitmap-64bitMD5",
11574452324482789141
]
]
},
"resizeimagefilter_8888.png": {
"allowed-digests": [
[
"bitmap-64bitMD5",
15004076002839832883
]
]
},
"resizeimagefilter_gpu.png": {
"allowed-digests": [
[
"bitmap-64bitMD5",
3830823404733713302
]
]
},
"resizeimagefilter_pdf-poppler.png": {
"allowed-digests": [
[
"bitmap-64bitMD5",
7720572764086610133
]
]
}
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,7 @@
Baseline images generated on:
Shuttle PC with Intel Core i7-2600
with Windows 7 installed
and using the CPU's built-in GPU (so-called "Intel HD Graphics 3000")

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,7 @@
Baseline images generated on:
Shuttle PC with Intel Core i7-2600
with Windows 7 installed
and using the CPU's built-in GPU (so-called "Intel HD Graphics 3000")

View File

@ -0,0 +1,7 @@
Baseline images generated on:
Shuttle PC with Intel Core i7-2600
with Windows 7 installed
and using the CPU's built-in GPU (so-called "Intel HD Graphics 3000")

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,7 @@
Baseline images generated on:
Shuttle PC with Intel Core i7-2600
with Windows 7 installed
and using the CPU's built-in GPU (so-called "Intel HD Graphics 3000")

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,7 @@
Baseline images generated on:
Shuttle PC with Intel Core i7-2600
with Windows 7 installed
and using the CPU's built-in GPU (so-called "Intel HD Graphics 3000")

View File

@ -0,0 +1,7 @@
Baseline images generated on:
Shuttle PC with Intel Core i7-2600
with Windows 7 installed
and using the CPU's built-in GPU (so-called "Intel HD Graphics 3000")

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,7 @@
Baseline images generated on:
Shuttle PC with Intel Core i7-2600
with Windows 7 installed
and using the CPU's built-in GPU (so-called "Intel HD Graphics 3000")

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,7 @@
Baseline images generated on:
Shuttle PC with Intel Core i7-2600
with Windows 7 installed
and using the CPU's built-in GPU (so-called "Intel HD Graphics 3000")

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,86 @@
# Failures of any GM tests listed in this file will be ignored [1], as
# if they had been marked "ignore-failure": true in the per-builder
# expected-results.json files.
#
# The idea is that, if you modify a GM test in such a way that you know it will
# require rebaselines on multiple platforms, you should add that test's name to
# this list within the same CL that modifies the test.
# Then, AS SOON AS POSSIBLE, you should rebaseline the tests (they will show up
# as status "failure-ignored") and remove the line you added to this file.
# If there are any lingering failures that need to be suppressed (ignored), you
# MUST move those suppressions into the per-builder expected-results.json files.
#
# The test name must match exactly (no partial string matches).
# See http://skbug.com/2022
#
# Any lines starting with '#' are comments and will be ignored.
# Other than that, each line must either be whitespace or list just one test.
#
# For more information, see https://code.google.com/p/skia/issues/detail?id=1600
# ('GM expectations: create tool to suppress failures until new baselines are
# checked in')
#
#
# [1] Differences between renderModes (e.g., normal rendering path and
# "serialized") are NEVER ignored. See
# https://code.google.com/p/skia/issues/detail?id=1748 ('gm: add new result
# type, RenderModeMismatch')
# EXAMPLES: (remove the first '#' on each line)
#
## Added as part of MADE-UP BUG
## http://skbug.com/123456 : ignoring failures on gradtext GM test
## epoger will rebaseline by 25 Dec 2013
#gradtext
# egdaniel
colortype_xfermodes
mixed_xfermodes
# reed - rebase after mipmap level improvement
coloremoji
downsamplebitmap_image_medium_mandrill_512
downsamplebitmap_image_medium_mandrill_132x132_12x12
downsamplebitmap_image_medium_mandrill_512.png
downsamplebitmap_image_medium_mandrill_132x132_12x12.astc
downsamplebitmap_checkerboard_medium_512_256
downsamplebitmap_text_medium_72.00pt
filterbitmap_checkerboard_4_4
filterbitmap_checkerboard_32_2
filterbitmap_checkerboard_32_8
filterbitmap_checkerboard_32_32
filterbitmap_checkerboard_192_192
filterbitmap_image_color_wheel.png
filterbitmap_image_mandrill_16.png
filterbitmap_image_mandrill_32.png
filterbitmap_image_mandrill_64.png
filterbitmap_image_mandrill_128.png
filterbitmap_image_mandrill_256.png
filterbitmap_image_mandrill_512.png
filterbitmap_text_3.00pt
filterbitmap_text_7.00pt
filterbitmap_text_10.00pt
filterindiabox
fontmgr_iter
downsamplebitmap_image_high_mandrill_132x132_12x12.astc
downsamplebitmap_image_high_mandrill_512.png
downsamplebitmap_text_high_72.00pt_8888.png
# robertphillips - skia:2995
blurrects
# reed - rebase after HQ filter change
bleed
# sugoi https://codereview.chromium.org/646213004/
# New shadow only option in SkDropShadowImageFilter
dropshadowimagefilter
# fmalita - rebaseline for http://crbug.com/447707
pictureshader
# bsalomon slight change to image-surface GM on gpu
image-surface

52
expectations/gm/loader.js Normal file
View File

@ -0,0 +1,52 @@
/*
* GMExpectedResultsLoader:
* Reads an expected-results.json file, and imports its data into $scope.
*/
var GMExpectedResultsLoader = angular.module(
'GMExpectedResultsLoader',
[],
function($httpProvider) {
/* Override transformResponse so that the numeric checksums are interpreted as
* strings instead, since Javascript cannot handle 64-bit integers. */
$httpProvider.defaults.transformResponse = function(data, headersGetter) {
return JSON.parse(data.replace(/\s(\d+)\s/g, " \"$1\" "));
}
}
);
GMExpectedResultsLoader.controller(
'GMExpectedResultsLoader.Controller',
function($scope, $http) {
/* When the changePlatformPath function is called, download expected-results.json
* from the desired platform directory.
*
* When the JSON is received, predigest it and return it to the frontend as
* $scope.gmExpectedResults .
*/
$scope.changePlatformPath = function() {
$http.get($scope.platformPath + "/expected-results.json").success(
function(response) {
var jsonResults = [];
var imageNameRegex = /^(.+)_([^_]+).png/;
angular.forEach(response['expected-results'], function(imageExpectations, imageName) {
var matched = imageNameRegex.exec(imageName);
var allowedImages = [];
angular.forEach(imageExpectations['allowed-digests'], function(allowedDigest, key) {
var thisImage = {
hashType: allowedDigest[0], hashValue: allowedDigest[1]
};
allowedImages.push(thisImage);
});
var thisResult = {
test: matched[1], config: matched[2],
allowedImages: allowedImages,
bugs: imageExpectations['bugs'],
reviewedByHuman: imageExpectations['reviewed-by-human']
};
jsonResults.push(thisResult);
});
$scope.gmExpectedResults = jsonResults;
}
);
};
}
);

View File

@ -0,0 +1,153 @@
<!DOCTYPE html>
<html ng-app="GMExpectedResultsLoader">
<head>
<title>View GM Expected Results for One Platform</title>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.1.5/angular.min.js"></script>
<script src="loader.js"></script>
</head>
<body>
<div ng-controller="GMExpectedResultsLoader.Controller" >
Pick a platform...
<select ng-model="platformPath" ng-change="changePlatformPath()">
<!-- Generated the option lines as follows:
$ cd expectations/gm
$ ALL=$(ls -d Test*)
$ for ONE in $ALL; do echo " <option value=\"$ONE\">$ONE</option>"; done
TODO(epoger): Once https://code.google.com/p/skia/issues/detail?id=1544
('live query of builder list makes rebaseline.py slow to start up') has been
resolved, we should use similar techniques to populate this list automatically.
-->
<option value="Test-Android-GalaxyNexus-SGX540-Arm7-Debug">Test-Android-GalaxyNexus-SGX540-Arm7-Debug</option>
<option value="Test-Android-GalaxyNexus-SGX540-Arm7-Debug-Trybot">Test-Android-GalaxyNexus-SGX540-Arm7-Debug-Trybot</option>
<option value="Test-Android-GalaxyNexus-SGX540-Arm7-Release">Test-Android-GalaxyNexus-SGX540-Arm7-Release</option>
<option value="Test-Android-GalaxyNexus-SGX540-Arm7-Release-Trybot">Test-Android-GalaxyNexus-SGX540-Arm7-Release-Trybot</option>
<option value="Test-Android-IntelRhb-SGX544-x86-Debug">Test-Android-IntelRhb-SGX544-x86-Debug</option>
<option value="Test-Android-IntelRhb-SGX544-x86-Debug-Trybot">Test-Android-IntelRhb-SGX544-x86-Debug-Trybot</option>
<option value="Test-Android-IntelRhb-SGX544-x86-Release">Test-Android-IntelRhb-SGX544-x86-Release</option>
<option value="Test-Android-Nexus10-MaliT604-Arm7-Debug">Test-Android-Nexus10-MaliT604-Arm7-Debug</option>
<option value="Test-Android-Nexus10-MaliT604-Arm7-Release">Test-Android-Nexus10-MaliT604-Arm7-Release</option>
<option value="Test-Android-Nexus4-Adreno320-Arm7-Debug">Test-Android-Nexus4-Adreno320-Arm7-Debug</option>
<option value="Test-Android-Nexus4-Adreno320-Arm7-Debug-Trybot">Test-Android-Nexus4-Adreno320-Arm7-Debug-Trybot</option>
<option value="Test-Android-Nexus4-Adreno320-Arm7-Release">Test-Android-Nexus4-Adreno320-Arm7-Release</option>
<option value="Test-Android-Nexus4-Adreno320-Arm7-Release-Trybot">Test-Android-Nexus4-Adreno320-Arm7-Release-Trybot</option>
<option value="Test-Android-Nexus7-Tegra3-Arm7-Debug">Test-Android-Nexus7-Tegra3-Arm7-Debug</option>
<option value="Test-Android-Nexus7-Tegra3-Arm7-Debug-Trybot">Test-Android-Nexus7-Tegra3-Arm7-Debug-Trybot</option>
<option value="Test-Android-Nexus7-Tegra3-Arm7-Release">Test-Android-Nexus7-Tegra3-Arm7-Release</option>
<option value="Test-Android-NexusS-SGX540-Arm7-Debug">Test-Android-NexusS-SGX540-Arm7-Debug</option>
<option value="Test-Android-NexusS-SGX540-Arm7-Debug-Trybot">Test-Android-NexusS-SGX540-Arm7-Debug-Trybot</option>
<option value="Test-Android-NexusS-SGX540-Arm7-Release">Test-Android-NexusS-SGX540-Arm7-Release</option>
<option value="Test-Android-RazrI-SGX540-x86-Debug">Test-Android-RazrI-SGX540-x86-Debug</option>
<option value="Test-Android-RazrI-SGX540-x86-Release">Test-Android-RazrI-SGX540-x86-Release</option>
<option value="Test-Android-Xoom-Tegra2-Arm7-Debug">Test-Android-Xoom-Tegra2-Arm7-Debug</option>
<option value="Test-Android-Xoom-Tegra2-Arm7-Release">Test-Android-Xoom-Tegra2-Arm7-Release</option>
<option value="Test-ChromeOS-Alex-GMA3150-x86-Debug">Test-ChromeOS-Alex-GMA3150-x86-Debug</option>
<option value="Test-ChromeOS-Alex-GMA3150-x86-Debug-Trybot">Test-ChromeOS-Alex-GMA3150-x86-Debug-Trybot</option>
<option value="Test-ChromeOS-Alex-GMA3150-x86-Release">Test-ChromeOS-Alex-GMA3150-x86-Release</option>
<option value="Test-ChromeOS-Alex-GMA3150-x86-Release-Trybot">Test-ChromeOS-Alex-GMA3150-x86-Release-Trybot</option>
<option value="Test-ChromeOS-Daisy-MaliT604-Arm7-Debug">Test-ChromeOS-Daisy-MaliT604-Arm7-Debug</option>
<option value="Test-ChromeOS-Daisy-MaliT604-Arm7-Debug-Trybot">Test-ChromeOS-Daisy-MaliT604-Arm7-Debug-Trybot</option>
<option value="Test-ChromeOS-Daisy-MaliT604-Arm7-Release">Test-ChromeOS-Daisy-MaliT604-Arm7-Release</option>
<option value="Test-ChromeOS-Daisy-MaliT604-Arm7-Release-Trybot">Test-ChromeOS-Daisy-MaliT604-Arm7-Release-Trybot</option>
<option value="Test-ChromeOS-Link-HD4000-x86_64-Debug">Test-ChromeOS-Link-HD4000-x86_64-Debug</option>
<option value="Test-ChromeOS-Link-HD4000-x86_64-Debug-Trybot">Test-ChromeOS-Link-HD4000-x86_64-Debug-Trybot</option>
<option value="Test-ChromeOS-Link-HD4000-x86_64-Release">Test-ChromeOS-Link-HD4000-x86_64-Release</option>
<option value="Test-ChromeOS-Link-HD4000-x86_64-Release-Trybot">Test-ChromeOS-Link-HD4000-x86_64-Release-Trybot</option>
<option value="Test-Mac10.6-MacMini4.1-GeForce320M-x86_64-Debug">Test-Mac10.6-MacMini4.1-GeForce320M-x86_64-Debug</option>
<option value="Test-Mac10.6-MacMini4.1-GeForce320M-x86_64-Debug-Trybot">Test-Mac10.6-MacMini4.1-GeForce320M-x86_64-Debug-Trybot</option>
<option value="Test-Mac10.6-MacMini4.1-GeForce320M-x86_64-Release">Test-Mac10.6-MacMini4.1-GeForce320M-x86_64-Release</option>
<option value="Test-Mac10.6-MacMini4.1-GeForce320M-x86_64-Release-Trybot">Test-Mac10.6-MacMini4.1-GeForce320M-x86_64-Release-Trybot</option>
<option value="Test-Mac10.6-MacMini4.1-GeForce320M-x86-Debug">Test-Mac10.6-MacMini4.1-GeForce320M-x86-Debug</option>
<option value="Test-Mac10.6-MacMini4.1-GeForce320M-x86-Debug-Trybot">Test-Mac10.6-MacMini4.1-GeForce320M-x86-Debug-Trybot</option>
<option value="Test-Mac10.6-MacMini4.1-GeForce320M-x86-Release">Test-Mac10.6-MacMini4.1-GeForce320M-x86-Release</option>
<option value="Test-Mac10.6-MacMini4.1-GeForce320M-x86-Release-Trybot">Test-Mac10.6-MacMini4.1-GeForce320M-x86-Release-Trybot</option>
<option value="Test-Mac10.7-MacMini4.1-GeForce320M-x86_64-Debug">Test-Mac10.7-MacMini4.1-GeForce320M-x86_64-Debug</option>
<option value="Test-Mac10.7-MacMini4.1-GeForce320M-x86_64-Debug-Trybot">Test-Mac10.7-MacMini4.1-GeForce320M-x86_64-Debug-Trybot</option>
<option value="Test-Mac10.7-MacMini4.1-GeForce320M-x86_64-Release">Test-Mac10.7-MacMini4.1-GeForce320M-x86_64-Release</option>
<option value="Test-Mac10.7-MacMini4.1-GeForce320M-x86_64-Release-Trybot">Test-Mac10.7-MacMini4.1-GeForce320M-x86_64-Release-Trybot</option>
<option value="Test-Mac10.7-MacMini4.1-GeForce320M-x86-Debug">Test-Mac10.7-MacMini4.1-GeForce320M-x86-Debug</option>
<option value="Test-Mac10.7-MacMini4.1-GeForce320M-x86-Debug-Trybot">Test-Mac10.7-MacMini4.1-GeForce320M-x86-Debug-Trybot</option>
<option value="Test-Mac10.7-MacMini4.1-GeForce320M-x86-Release">Test-Mac10.7-MacMini4.1-GeForce320M-x86-Release</option>
<option value="Test-Mac10.7-MacMini4.1-GeForce320M-x86-Release-Trybot">Test-Mac10.7-MacMini4.1-GeForce320M-x86-Release-Trybot</option>
<option value="Test-Mac10.8-MacMini4.1-GeForce320M-x86_64-Debug">Test-Mac10.8-MacMini4.1-GeForce320M-x86_64-Debug</option>
<option value="Test-Mac10.8-MacMini4.1-GeForce320M-x86_64-Debug-Trybot">Test-Mac10.8-MacMini4.1-GeForce320M-x86_64-Debug-Trybot</option>
<option value="Test-Mac10.8-MacMini4.1-GeForce320M-x86_64-Release">Test-Mac10.8-MacMini4.1-GeForce320M-x86_64-Release</option>
<option value="Test-Mac10.8-MacMini4.1-GeForce320M-x86_64-Release-Trybot">Test-Mac10.8-MacMini4.1-GeForce320M-x86_64-Release-Trybot</option>
<option value="Test-Mac10.8-MacMini4.1-GeForce320M-x86-Debug">Test-Mac10.8-MacMini4.1-GeForce320M-x86-Debug</option>
<option value="Test-Mac10.8-MacMini4.1-GeForce320M-x86-Debug-Trybot">Test-Mac10.8-MacMini4.1-GeForce320M-x86-Debug-Trybot</option>
<option value="Test-Mac10.8-MacMini4.1-GeForce320M-x86-Release">Test-Mac10.8-MacMini4.1-GeForce320M-x86-Release</option>
<option value="Test-Mac10.8-MacMini4.1-GeForce320M-x86-Release-Trybot">Test-Mac10.8-MacMini4.1-GeForce320M-x86-Release-Trybot</option>
<option value="Test-Ubuntu12-ShuttleA-ATI5770-x86_64-Debug">Test-Ubuntu12-ShuttleA-ATI5770-x86_64-Debug</option>
<option value="Test-Ubuntu12-ShuttleA-ATI5770-x86_64-Debug-Trybot">Test-Ubuntu12-ShuttleA-ATI5770-x86_64-Debug-Trybot</option>
<option value="Test-Ubuntu12-ShuttleA-ATI5770-x86_64-Release">Test-Ubuntu12-ShuttleA-ATI5770-x86_64-Release</option>
<option value="Test-Ubuntu12-ShuttleA-ATI5770-x86_64-Release-Trybot">Test-Ubuntu12-ShuttleA-ATI5770-x86_64-Release-Trybot</option>
<option value="Test-Ubuntu12-ShuttleA-ATI5770-x86-Debug">Test-Ubuntu12-ShuttleA-ATI5770-x86-Debug</option>
<option value="Test-Ubuntu12-ShuttleA-ATI5770-x86-Debug-Trybot">Test-Ubuntu12-ShuttleA-ATI5770-x86-Debug-Trybot</option>
<option value="Test-Ubuntu12-ShuttleA-ATI5770-x86-Release">Test-Ubuntu12-ShuttleA-ATI5770-x86-Release</option>
<option value="Test-Ubuntu12-ShuttleA-ATI5770-x86-Release-Trybot">Test-Ubuntu12-ShuttleA-ATI5770-x86-Release-Trybot</option>
<option value="Test-Ubuntu12-ShuttleA-HD2000-x86_64-Release-Valgrind">Test-Ubuntu12-ShuttleA-HD2000-x86_64-Release-Valgrind</option>
<option value="Test-Ubuntu12-ShuttleA-HD2000-x86_64-Release-Valgrind-Trybot">Test-Ubuntu12-ShuttleA-HD2000-x86_64-Release-Valgrind-Trybot</option>
<option value="Test-Ubuntu12-ShuttleA-NoGPU-x86_64-Debug">Test-Ubuntu12-ShuttleA-NoGPU-x86_64-Debug</option>
<option value="Test-Ubuntu12-ShuttleA-NoGPU-x86_64-Debug-Trybot">Test-Ubuntu12-ShuttleA-NoGPU-x86_64-Debug-Trybot</option>
<option value="Test-Ubuntu13-ShuttleA-HD2000-x86_64-Debug-ASAN">Test-Ubuntu13-ShuttleA-HD2000-x86_64-Debug-ASAN</option>
<option value="Test-Ubuntu13-ShuttleA-HD2000-x86_64-Debug-ASAN-Trybot">Test-Ubuntu13-ShuttleA-HD2000-x86_64-Debug-ASAN-Trybot</option>
<option value="Test-Win7-ShuttleA-HD2000-x86_64-Debug">Test-Win7-ShuttleA-HD2000-x86_64-Debug</option>
<option value="Test-Win7-ShuttleA-HD2000-x86_64-Debug-Trybot">Test-Win7-ShuttleA-HD2000-x86_64-Debug-Trybot</option>
<option value="Test-Win7-ShuttleA-HD2000-x86_64-Release">Test-Win7-ShuttleA-HD2000-x86_64-Release</option>
<option value="Test-Win7-ShuttleA-HD2000-x86_64-Release-Trybot">Test-Win7-ShuttleA-HD2000-x86_64-Release-Trybot</option>
<option value="Test-Win7-ShuttleA-HD2000-x86-Debug">Test-Win7-ShuttleA-HD2000-x86-Debug</option>
<option value="Test-Win7-ShuttleA-HD2000-x86-Debug-ANGLE">Test-Win7-ShuttleA-HD2000-x86-Debug-ANGLE</option>
<option value="Test-Win7-ShuttleA-HD2000-x86-Debug-ANGLE-Trybot">Test-Win7-ShuttleA-HD2000-x86-Debug-ANGLE-Trybot</option>
<option value="Test-Win7-ShuttleA-HD2000-x86-Debug-DirectWrite">Test-Win7-ShuttleA-HD2000-x86-Debug-DirectWrite</option>
<option value="Test-Win7-ShuttleA-HD2000-x86-Debug-DirectWrite-Trybot">Test-Win7-ShuttleA-HD2000-x86-Debug-DirectWrite-Trybot</option>
<option value="Test-Win7-ShuttleA-HD2000-x86-Debug-Trybot">Test-Win7-ShuttleA-HD2000-x86-Debug-Trybot</option>
<option value="Test-Win7-ShuttleA-HD2000-x86-Release">Test-Win7-ShuttleA-HD2000-x86-Release</option>
<option value="Test-Win7-ShuttleA-HD2000-x86-Release-ANGLE">Test-Win7-ShuttleA-HD2000-x86-Release-ANGLE</option>
<option value="Test-Win7-ShuttleA-HD2000-x86-Release-ANGLE-Trybot">Test-Win7-ShuttleA-HD2000-x86-Release-ANGLE-Trybot</option>
<option value="Test-Win7-ShuttleA-HD2000-x86-Release-DirectWrite">Test-Win7-ShuttleA-HD2000-x86-Release-DirectWrite</option>
<option value="Test-Win7-ShuttleA-HD2000-x86-Release-DirectWrite-Trybot">Test-Win7-ShuttleA-HD2000-x86-Release-DirectWrite-Trybot</option>
<option value="Test-Win7-ShuttleA-HD2000-x86-Release-Trybot">Test-Win7-ShuttleA-HD2000-x86-Release-Trybot</option>
</select>
<p>
Expected GM results for platform {{platformPath}}:
<table border="1">
<tr>
<th>Test/Config</th>
<th>Allowed Images</th>
<th>Bugs</th>
<th>Reviewed By Human?</th>
</tr>
<tr ng-repeat="result in gmExpectedResults">
<td>{{result.test}}_{{result.config}}</td>
<td><span ng-repeat="image in result.allowedImages">
<a target="_blank"
href="http://chromium-skia-gm.commondatastorage.googleapis.com/gm/{{image.hashType}}/{{result.test}}/{{image.hashValue}}.png">
{{image.hashValue}}</a><br>
</span></td>
<td><span ng-repeat="bug in result.bugs">
<a href="https://code.google.com/p/skia/issues/detail?id={{bug}}">{{bug}} </a>
</span></td>
<td>{{result.reviewedByHuman}}</td>
</tr>
</table>
</div>
<!-- TODO(epoger): Can we get the base URLs (commondatastorage and
issues list) from
https://skia.googlesource.com/buildbot/+/3de60f3003e3/site_config/global_variables.json ?
I tried importing the
http://skia.googlecode.com/svn/buildbot/skia_tools.js script and using
that to do so, but I got Access-Control-Allow-Origin errors.
-->
</body>
</html>

View File

@ -0,0 +1,3 @@

1
gm/__init__.py Normal file
View File

@ -0,0 +1 @@
# Allow Python import of this directory.

104
gm/copy_config.py Executable file
View File

@ -0,0 +1,104 @@
#!/usr/bin/python
# Copyright (c) 2014 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.
"""Utility to duplicate a config in some subset of our GM expectation files.
Created for http://skbug.com/2752 ('split existing "gpu" GM results into "gl"
and "gles"')
Run with -h to see usage.
Example command lines:
copy_config.py gl gles '.*Mac10.7.*'
TODO(epoger): Once https://codereview.chromium.org/397103003/ is committed,
we should add a unittest. Until then, we can test this as follows:
OLD=expectations/gm && NEW=/tmp/expectations && \
rm -rf $NEW && \
cp -a $OLD $NEW && \
gm/copy_config.py 8888 8888-copy '.*Mac10.7.*' \
--expectations-root $NEW && \
diff --recursive $OLD $NEW
"""
__author__ = 'Elliot Poger'
import argparse
import os
import re
import gm_json
DEFAULT_EXPECTATIONS_ROOT = os.path.join(
os.path.dirname(__file__), os.pardir, 'expectations', 'gm')
IMAGE_FILENAME_RE = re.compile(gm_json.IMAGE_FILENAME_PATTERN)
class Copier(object):
def __init__(self, args):
"""
Params:
args: the Namespace object generated by argparse.parse_args()
"""
self._args = args
def run(self):
"""Perform all the duplications."""
for path in self._get_file_list():
self._duplicate_config(path=path,
old=self._args.old_config_name,
new=self._args.new_config_name)
def _duplicate_config(self, path, old, new):
"""Duplicates all instances of a config within a GM expectations file.
Params:
path: path to file which will be modified in place
old: old config name
new: new config name
"""
dic = gm_json.LoadFromFile(file_path=path)
expected_results = dic[gm_json.JSONKEY_EXPECTEDRESULTS]
orig_keys = expected_results.keys()
for key in orig_keys:
result = expected_results[key]
(testname, config) = IMAGE_FILENAME_RE.match(key).groups()
if config == old:
config = new
key = '%s_%s.png' % (testname, config)
expected_results[key] = result
gm_json.WriteToFile(json_dict=dic, file_path=path)
def _get_file_list(self):
"""Returns the list of files we want to operate on (the complete path
to each file)."""
root = self._args.expectations_root
regex = re.compile(self._args.builder_name_pattern)
return [os.path.join(root, builder, 'expected-results.json')
for builder in os.listdir(root)
if regex.match(builder)]
def main():
parser = argparse.ArgumentParser()
parser.add_argument('old_config_name',
help=('Config we want to duplicate.'))
parser.add_argument('new_config_name',
help=('Name of the new config we want to create.'))
parser.add_argument('builder_name_pattern',
help=('Regex pattern describing which builders we want '
'to make the duplication for; \'.*\' to perform '
'the duplication on all builders.'))
parser.add_argument('--expectations-root',
default=DEFAULT_EXPECTATIONS_ROOT,
help=('Root of the GM expectations dir; defaults to '
'%(default)s'))
args = parser.parse_args()
copier = Copier(args)
copier.run()
if __name__ == '__main__':
main()

114
gm/display_json_results.py Normal file
View File

@ -0,0 +1,114 @@
#!/usr/bin/env python
# Copyright (c) 2013 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.
"""Utility to display a summary of JSON-format GM results, and exit with
a nonzero errorcode if there were non-ignored failures in the GM results.
Usage:
python display_json_results.py <filename>
TODO(epoger): We may want to add flags to set the following:
- which error types cause a nonzero return code
- maximum number of tests to list for any one ResultAccumulator
(to keep the output reasonably short)
"""
__author__ = 'Elliot Poger'
# system-level imports
import sys
# local imports
import gm_json
class ResultAccumulator(object):
"""Object that accumulates results of a given type, and can generate a
summary upon request."""
def __init__(self, name, do_list, do_fail):
"""name: name of the category this result type falls into
do_list: whether to list all of the tests with this results type
do_fail: whether to return with nonzero exit code if there are any
results of this type
"""
self._name = name
self._do_list = do_list
self._do_fail = do_fail
self._testnames = []
def AddResult(self, testname):
"""Adds a result of this particular type.
testname: (string) name of the test"""
self._testnames.append(testname)
def ShouldSignalFailure(self):
"""Returns true if this result type is serious (self._do_fail is True)
and there were any results of this type."""
if self._do_fail and self._testnames:
return True
else:
return False
def GetSummaryLine(self):
"""Returns a single-line string summary of all results added to this
accumulator so far."""
summary = ''
if self._do_fail:
summary += '[*] '
else:
summary += '[ ] '
summary += str(len(self._testnames))
summary += ' '
summary += self._name
if self._do_list:
summary += ': '
for testname in self._testnames:
summary += testname
summary += ' '
return summary
def Display(filepath):
"""Displays a summary of the results in a JSON file.
Returns True if the results are free of any significant failures.
filepath: (string) path to JSON file"""
# Map labels within the JSON file to the ResultAccumulator for each label.
results_map = {
gm_json.JSONKEY_ACTUALRESULTS_FAILED:
ResultAccumulator(name='ExpectationsMismatch',
do_list=True, do_fail=True),
gm_json.JSONKEY_ACTUALRESULTS_FAILUREIGNORED:
ResultAccumulator(name='IgnoredExpectationsMismatch',
do_list=True, do_fail=False),
gm_json.JSONKEY_ACTUALRESULTS_NOCOMPARISON:
ResultAccumulator(name='MissingExpectations',
do_list=False, do_fail=False),
gm_json.JSONKEY_ACTUALRESULTS_SUCCEEDED:
ResultAccumulator(name='Passed',
do_list=False, do_fail=False),
}
success = True
json_dict = gm_json.LoadFromFile(filepath)
actual_results = json_dict[gm_json.JSONKEY_ACTUALRESULTS]
for label, accumulator in results_map.iteritems():
results = actual_results[label]
if results:
for result in results:
accumulator.AddResult(result)
print accumulator.GetSummaryLine()
if accumulator.ShouldSignalFailure():
success = False
print '(results marked with [*] will cause nonzero return value)'
return success
if '__main__' == __name__:
if len(sys.argv) != 2:
raise Exception('usage: %s <input-json-filepath>' % sys.argv[0])
sys.exit(0 if Display(sys.argv[1]) else 1)

163
gm/gm_error.h Normal file
View File

@ -0,0 +1,163 @@
/*
* Copyright 2013 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
/*
* Error codes used by gmmain.cpp.
*/
#ifndef gm_error_DEFINED
#define gm_error_DEFINED
#include "gm.h"
namespace skiagm {
/**
* The complete list of error types we might encounter in GM.
*/
enum ErrorType {
// Even though kNoGpuContext_ErrorType only occurs when SK_SUPPORT_GPU
// is turned on, we always include this type in our enum so that
// reports will be consistent whether SK_SUPPORT_GPU is turned on
// or off (as long as the number of these errors is 0).
kNoGpuContext_ErrorType,
kIntentionallySkipped_ErrorType,
kRenderModeMismatch_ErrorType,
kGeneratePdfFailed_ErrorType,
kExpectationsMismatch_ErrorType,
kMissingExpectations_ErrorType,
kWritingReferenceImage_ErrorType,
kLast_ErrorType = kWritingReferenceImage_ErrorType
};
/**
* Returns the name of the given ErrorType.
*/
static const char *getErrorTypeName(ErrorType type) {
switch(type) {
case kNoGpuContext_ErrorType:
return "NoGpuContext";
case kIntentionallySkipped_ErrorType:
return "IntentionallySkipped";
case kRenderModeMismatch_ErrorType:
return "RenderModeMismatch";
case kGeneratePdfFailed_ErrorType:
return "GeneratePdfFailed";
case kExpectationsMismatch_ErrorType:
return "ExpectationsMismatch";
case kMissingExpectations_ErrorType:
return "MissingExpectations";
case kWritingReferenceImage_ErrorType:
return "WritingReferenceImage";
}
// control should never reach here
SkDEBUGFAIL("getErrorTypeName() called with unknown type");
return "Unknown";
}
/**
* Fills in "type" with the ErrorType associated with name "name".
* Returns true if we found one, false if it is an unknown type name.
*/
static bool getErrorTypeByName(const char name[], ErrorType *type) {
for (int typeInt = 0; typeInt <= kLast_ErrorType; typeInt++) {
ErrorType thisType = static_cast<ErrorType>(typeInt);
const char *thisTypeName = getErrorTypeName(thisType);
if (0 == strcmp(thisTypeName, name)) {
*type = thisType;
return true;
}
}
return false;
}
/**
* A combination of 0 or more ErrorTypes.
*/
class ErrorCombination {
public:
ErrorCombination() : fBitfield(0) {}
ErrorCombination(const ErrorType type) : fBitfield(1 << type) {}
/**
* Returns true iff there are NO errors.
*/
bool isEmpty() const {
return (0 == this->fBitfield);
}
/**
* Adds this ErrorType to this ErrorCombination.
*/
void add(const ErrorType type) {
this->fBitfield |= (1 << type);
}
/**
* Adds all ErrorTypes in "other" to this ErrorCombination.
*/
void add(const ErrorCombination other) {
this->fBitfield |= other.fBitfield;
}
/**
* Returns true iff this ErrorCombination includes this ErrorType.
*/
bool includes(const ErrorType type) const {
return !(0 == (this->fBitfield & (1 << type)));
}
/**
* Returns a string representation of all ErrorTypes in this
* ErrorCombination.
*
* @param separator text with which to separate ErrorType names
*/
SkString asString(const char separator[]) const {
SkString s;
for (int typeInt = 0; typeInt <= kLast_ErrorType; typeInt++) {
ErrorType type = static_cast<ErrorType>(typeInt);
if (this->includes(type)) {
if (!s.isEmpty()) {
s.append(separator);
}
s.append(getErrorTypeName(type));
}
}
return s;
}
/**
* Returns a new ErrorCombination, which includes the union of all
* ErrorTypes in two ErrorCombination objects (this and other).
*/
ErrorCombination plus(const ErrorCombination& other) const {
ErrorCombination retval;
retval.fBitfield = this->fBitfield | other.fBitfield;
return retval;
}
/**
* Returns a new ErrorCombination, which is a copy of "this"
* but with all ErrorTypes in "other" removed.
*/
ErrorCombination minus(const ErrorCombination& other) const {
ErrorCombination retval;
retval.fBitfield = this->fBitfield & ~(other.fBitfield);
return retval;
}
private:
int fBitfield;
};
// No errors at all.
const static ErrorCombination kEmpty_ErrorCombination;
}
#endif // ifndef gm_error_DEFINED

239
gm/gm_expectations.cpp Normal file
View File

@ -0,0 +1,239 @@
/*
* Copyright 2013 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*
* TODO(epoger): Combine this with tools/image_expectations.cpp, or eliminate one of the two.
*/
#include "gm_expectations.h"
#include "SkBitmapHasher.h"
#include "SkData.h"
#include "SkImageDecoder.h"
#define DEBUGFAIL_SEE_STDERR SkDEBUGFAIL("see stderr for message")
// See gm_json.py for descriptions of each of these JSON keys.
// These constants must be kept in sync with the ones in that Python file!
const static char kJsonKey_ActualResults[] = "actual-results";
const static char kJsonKey_ActualResults_Failed[] = "failed";
const static char kJsonKey_ActualResults_FailureIgnored[]= "failure-ignored";
const static char kJsonKey_ActualResults_NoComparison[] = "no-comparison";
const static char kJsonKey_ActualResults_Succeeded[] = "succeeded";
const static char kJsonKey_ExpectedResults[] = "expected-results";
const static char kJsonKey_ExpectedResults_AllowedDigests[] = "allowed-digests";
const static char kJsonKey_ExpectedResults_IgnoreFailure[] = "ignore-failure";
// Types of result hashes we support in the JSON file.
const static char kJsonKey_Hashtype_Bitmap_64bitMD5[] = "bitmap-64bitMD5";
namespace skiagm {
Json::Value CreateJsonTree(Json::Value expectedResults,
Json::Value actualResultsFailed,
Json::Value actualResultsFailureIgnored,
Json::Value actualResultsNoComparison,
Json::Value actualResultsSucceeded) {
Json::Value actualResults;
actualResults[kJsonKey_ActualResults_Failed] = actualResultsFailed;
actualResults[kJsonKey_ActualResults_FailureIgnored] = actualResultsFailureIgnored;
actualResults[kJsonKey_ActualResults_NoComparison] = actualResultsNoComparison;
actualResults[kJsonKey_ActualResults_Succeeded] = actualResultsSucceeded;
Json::Value root;
root[kJsonKey_ActualResults] = actualResults;
root[kJsonKey_ExpectedResults] = expectedResults;
return root;
}
// GmResultDigest class...
GmResultDigest::GmResultDigest(const SkBitmap &bitmap) {
fIsValid = SkBitmapHasher::ComputeDigest(bitmap, &fHashDigest);
}
GmResultDigest::GmResultDigest(const Json::Value &jsonTypeValuePair) {
fIsValid = false;
if (!jsonTypeValuePair.isArray()) {
SkDebugf("found non-array json value when parsing GmResultDigest: %s\n",
jsonTypeValuePair.toStyledString().c_str());
DEBUGFAIL_SEE_STDERR;
} else if (2 != jsonTypeValuePair.size()) {
SkDebugf("found json array with wrong size when parsing GmResultDigest: %s\n",
jsonTypeValuePair.toStyledString().c_str());
DEBUGFAIL_SEE_STDERR;
} else {
// TODO(epoger): The current implementation assumes that the
// result digest is always of type kJsonKey_Hashtype_Bitmap_64bitMD5
Json::Value jsonHashValue = jsonTypeValuePair[1];
if (!jsonHashValue.isIntegral()) {
SkDebugf("found non-integer jsonHashValue when parsing GmResultDigest: %s\n",
jsonTypeValuePair.toStyledString().c_str());
DEBUGFAIL_SEE_STDERR;
} else {
fHashDigest = jsonHashValue.asUInt64();
fIsValid = true;
}
}
}
bool GmResultDigest::isValid() const {
return fIsValid;
}
bool GmResultDigest::equals(const GmResultDigest &other) const {
// TODO(epoger): The current implementation assumes that this
// and other are always of type kJsonKey_Hashtype_Bitmap_64bitMD5
return (this->fIsValid && other.fIsValid && (this->fHashDigest == other.fHashDigest));
}
Json::Value GmResultDigest::asJsonTypeValuePair() const {
// TODO(epoger): The current implementation assumes that the
// result digest is always of type kJsonKey_Hashtype_Bitmap_64bitMD5
Json::Value jsonTypeValuePair;
if (fIsValid) {
jsonTypeValuePair.append(Json::Value(kJsonKey_Hashtype_Bitmap_64bitMD5));
jsonTypeValuePair.append(Json::UInt64(fHashDigest));
} else {
jsonTypeValuePair.append(Json::Value("INVALID"));
}
return jsonTypeValuePair;
}
SkString GmResultDigest::getHashType() const {
// TODO(epoger): The current implementation assumes that the
// result digest is always of type kJsonKey_Hashtype_Bitmap_64bitMD5
return SkString(kJsonKey_Hashtype_Bitmap_64bitMD5);
}
SkString GmResultDigest::getDigestValue() const {
// TODO(epoger): The current implementation assumes that the
// result digest is always of type kJsonKey_Hashtype_Bitmap_64bitMD5
SkString retval;
retval.appendU64(fHashDigest);
return retval;
}
// Expectations class...
Expectations::Expectations(bool ignoreFailure) {
fIgnoreFailure = ignoreFailure;
}
Expectations::Expectations(const SkBitmap& bitmap, bool ignoreFailure) {
fBitmap = bitmap;
fIgnoreFailure = ignoreFailure;
fAllowedResultDigests.push_back(GmResultDigest(bitmap));
}
Expectations::Expectations(const BitmapAndDigest& bitmapAndDigest) {
fBitmap = bitmapAndDigest.fBitmap;
fIgnoreFailure = false;
fAllowedResultDigests.push_back(bitmapAndDigest.fDigest);
}
Expectations::Expectations(Json::Value jsonElement) {
if (jsonElement.empty()) {
fIgnoreFailure = kDefaultIgnoreFailure;
} else {
Json::Value ignoreFailure = jsonElement[kJsonKey_ExpectedResults_IgnoreFailure];
if (ignoreFailure.isNull()) {
fIgnoreFailure = kDefaultIgnoreFailure;
} else if (!ignoreFailure.isBool()) {
SkDebugf("found non-boolean json value for key '%s' in element '%s'\n",
kJsonKey_ExpectedResults_IgnoreFailure,
jsonElement.toStyledString().c_str());
DEBUGFAIL_SEE_STDERR;
fIgnoreFailure = kDefaultIgnoreFailure;
} else {
fIgnoreFailure = ignoreFailure.asBool();
}
Json::Value allowedDigests = jsonElement[kJsonKey_ExpectedResults_AllowedDigests];
if (allowedDigests.isNull()) {
// ok, we'll just assume there aren't any AllowedDigests to compare against
} else if (!allowedDigests.isArray()) {
SkDebugf("found non-array json value for key '%s' in element '%s'\n",
kJsonKey_ExpectedResults_AllowedDigests,
jsonElement.toStyledString().c_str());
DEBUGFAIL_SEE_STDERR;
} else {
for (Json::ArrayIndex i=0; i<allowedDigests.size(); i++) {
fAllowedResultDigests.push_back(GmResultDigest(allowedDigests[i]));
}
}
}
}
bool Expectations::match(GmResultDigest actualGmResultDigest) const {
for (int i=0; i < this->fAllowedResultDigests.count(); i++) {
GmResultDigest allowedResultDigest = this->fAllowedResultDigests[i];
if (allowedResultDigest.equals(actualGmResultDigest)) {
return true;
}
}
return false;
}
Json::Value Expectations::asJsonValue() const {
Json::Value allowedDigestArray;
if (!this->fAllowedResultDigests.empty()) {
for (int i=0; i < this->fAllowedResultDigests.count(); i++) {
allowedDigestArray.append(this->fAllowedResultDigests[i].asJsonTypeValuePair());
}
}
Json::Value jsonExpectations;
jsonExpectations[kJsonKey_ExpectedResults_AllowedDigests] = allowedDigestArray;
jsonExpectations[kJsonKey_ExpectedResults_IgnoreFailure] = this->ignoreFailure();
return jsonExpectations;
}
// IndividualImageExpectationsSource class...
Expectations IndividualImageExpectationsSource::get(const char *testName) const {
SkString path = SkOSPath::Join(fRootDir.c_str(), testName);
SkBitmap referenceBitmap;
bool decodedReferenceBitmap =
SkImageDecoder::DecodeFile(path.c_str(), &referenceBitmap, kN32_SkColorType,
SkImageDecoder::kDecodePixels_Mode, NULL);
if (decodedReferenceBitmap) {
return Expectations(referenceBitmap);
} else {
return Expectations();
}
}
// JsonExpectationsSource class...
JsonExpectationsSource::JsonExpectationsSource(const char *jsonPath) {
Parse(jsonPath, &fJsonRoot);
fJsonExpectedResults = fJsonRoot[kJsonKey_ExpectedResults];
}
Expectations JsonExpectationsSource::get(const char *testName) const {
return Expectations(fJsonExpectedResults[testName]);
}
/*static*/ bool JsonExpectationsSource::Parse(const char *jsonPath, Json::Value *jsonRoot) {
SkAutoDataUnref dataRef(SkData::NewFromFileName(jsonPath));
if (NULL == dataRef.get()) {
SkDebugf("error reading JSON file %s\n", jsonPath);
DEBUGFAIL_SEE_STDERR;
return false;
}
const char *bytes = reinterpret_cast<const char *>(dataRef.get()->data());
size_t size = dataRef.get()->size();
Json::Reader reader;
if (!reader.parse(bytes, bytes+size, *jsonRoot)) {
SkDebugf("error parsing JSON file %s\n", jsonPath);
DEBUGFAIL_SEE_STDERR;
return false;
}
return true;
}
}

193
gm/gm_json.py Normal file
View File

@ -0,0 +1,193 @@
#!/usr/bin/env python
# Copyright (c) 2013 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.
"""Schema of the JSON summary file written out by the GM tool.
This must be kept in sync with the kJsonKey_ constants in gm_expectations.cpp !
"""
__author__ = 'Elliot Poger'
# system-level imports
import io
import json
import os
import posixpath
import re
# Key strings used in GM results JSON files (both expected-results.json and
# actual-results.json).
#
# NOTE: These constants must be kept in sync with the kJsonKey_ constants in
# gm_expectations.cpp and tools/PictureRenderer.cpp !
# Eric suggests: create gm/gm_expectations_constants.h containing ONLY variable
# declarations so as to be readable by both gm/gm_expectations.cpp and Python.
JSONKEY_ACTUALRESULTS = 'actual-results'
# Tests whose results failed to match expectations.
JSONKEY_ACTUALRESULTS_FAILED = 'failed'
# Tests whose results failed to match expectations, but IGNOREFAILURE causes
# us to take them less seriously.
JSONKEY_ACTUALRESULTS_FAILUREIGNORED = 'failure-ignored'
# Tests for which we do not have any expectations. They may be new tests that
# we haven't had a chance to check in expectations for yet, or we may have
# consciously decided to leave them without expectations because we are unhappy
# with the results (although we should try to move away from that, and instead
# check in expectations with the IGNOREFAILURE flag set).
JSONKEY_ACTUALRESULTS_NOCOMPARISON = 'no-comparison'
# Tests whose results matched their expectations.
JSONKEY_ACTUALRESULTS_SUCCEEDED = 'succeeded'
# Descriptions of the result set as a whole.
JSONKEY_DESCRIPTIONS = 'descriptions'
JSONKEY_DESCRIPTIONS_BUILDER = 'builder'
JSONKEY_DESCRIPTIONS_RENDER_MODE = 'renderMode'
JSONKEY_EXPECTEDRESULTS = 'expected-results'
# One or more [HashType/DigestValue] pairs representing valid results for this
# test. Typically, there will just be one pair, but we allow for multiple
# expectations, and the test will pass if any one of them is matched.
JSONKEY_EXPECTEDRESULTS_ALLOWEDDIGESTS = 'allowed-digests'
# Optional: one or more integers listing Skia bugs (under
# https://code.google.com/p/skia/issues/list ) that pertain to this expectation.
JSONKEY_EXPECTEDRESULTS_BUGS = 'bugs'
# If IGNOREFAILURE is set to True, a failure of this test will be reported
# within the FAILUREIGNORED section (thus NOT causing the buildbots to go red)
# rather than the FAILED section (which WOULD cause the buildbots to go red).
JSONKEY_EXPECTEDRESULTS_IGNOREFAILURE = 'ignore-failure'
# Optional: a free-form text string with human-readable information about
# this expectation.
JSONKEY_EXPECTEDRESULTS_NOTES = 'notes'
# Optional: boolean indicating whether this expectation was reviewed/approved
# by a human being.
# If True: a human looked at this image and approved it.
# If False: this expectation was committed blind. (In such a case, please
# add notes indicating why!)
# If absent: this expectation was committed by a tool that didn't enforce human
# review of expectations.
JSONKEY_EXPECTEDRESULTS_REVIEWED = 'reviewed-by-human'
# Allowed hash types for test expectations.
JSONKEY_HASHTYPE_BITMAP_64BITMD5 = 'bitmap-64bitMD5'
JSONKEY_HEADER = 'header'
JSONKEY_HEADER_TYPE = 'type'
JSONKEY_HEADER_REVISION = 'revision'
JSONKEY_IMAGE_CHECKSUMALGORITHM = 'checksumAlgorithm'
JSONKEY_IMAGE_CHECKSUMVALUE = 'checksumValue'
JSONKEY_IMAGE_COMPARISONRESULT = 'comparisonResult'
JSONKEY_IMAGE_FILEPATH = 'filepath'
JSONKEY_SOURCE_TILEDIMAGES = 'tiled-images'
JSONKEY_SOURCE_WHOLEIMAGE = 'whole-image'
JSONKEY_IMAGE_BASE_GS_URL = 'image-base-gs-url'
# Root directory where the buildbots store their actually-generated images...
# as a publicly readable HTTP URL:
GM_ACTUALS_ROOT_HTTP_URL = (
'http://chromium-skia-gm.commondatastorage.googleapis.com/gm')
# as a GS URL that allows credential-protected write access:
GM_ACTUALS_ROOT_GS_URL = 'gs://chromium-skia-gm/gm'
# Pattern used to assemble each image's filename
IMAGE_FILENAME_PATTERN = '(.+)_(.+)\.png' # matches (testname, config)
# Pattern used to create image URLs, relative to some base URL.
GM_RELATIVE_URL_FORMATTER = '%s/%s/%s.png' # pass in (hash_type, test_name,
# hash_digest)
GM_RELATIVE_URL_PATTERN = '(.+)/(.+)/(.+).png' # matches (hash_type, test_name,
# hash_digest)
GM_RELATIVE_URL_RE = re.compile(GM_RELATIVE_URL_PATTERN)
def CreateGmActualUrl(test_name, hash_type, hash_digest,
gm_actuals_root_url=GM_ACTUALS_ROOT_HTTP_URL):
"""Return the URL we can use to download a particular version of
the actually-generated image for this particular GM test.
test_name: name of the test, e.g. 'perlinnoise'
hash_type: string indicating the hash type used to generate hash_digest,
e.g. JSONKEY_HASHTYPE_BITMAP_64BITMD5
hash_digest: the hash digest of the image to retrieve
gm_actuals_root_url: root url where actual images are stored
"""
return posixpath.join(
gm_actuals_root_url, CreateGmRelativeUrl(
test_name=test_name, hash_type=hash_type, hash_digest=hash_digest))
def CreateGmRelativeUrl(test_name, hash_type, hash_digest):
"""Returns a relative URL pointing at a test result's image.
Returns the URL we can use to download a particular version of
the actually-generated image for this particular GM test,
relative to the URL root.
Args:
test_name: name of the test, e.g. 'perlinnoise'
hash_type: string indicating the hash type used to generate hash_digest,
e.g. JSONKEY_HASHTYPE_BITMAP_64BITMD5
hash_digest: the hash digest of the image to retrieve
"""
return GM_RELATIVE_URL_FORMATTER % (hash_type, test_name, hash_digest)
def SplitGmRelativeUrl(url):
"""Splits the relative URL into (test_name, hash_type, hash_digest) tuple.
This is the inverse of CreateGmRelativeUrl().
Args:
url: a URL generated with CreateGmRelativeUrl().
Returns: (test_name, hash_type, hash_digest) tuple.
"""
hash_type, test_name, hash_digest = GM_RELATIVE_URL_RE.match(url).groups()
return (test_name, hash_type, hash_digest)
def LoadFromString(file_contents):
"""Loads the JSON summary written out by the GM tool.
Returns a dictionary keyed by the values listed as JSONKEY_ constants
above; if file_contents is empty, returns None."""
# TODO(epoger): we should add a version number to the JSON file to ensure
# that the writer and reader agree on the schema (raising an exception
# otherwise).
if not file_contents:
return None
json_dict = json.loads(file_contents)
return json_dict
def LoadFromFile(file_path):
"""Loads the JSON summary written out by the GM tool.
Returns a dictionary keyed by the values listed as JSONKEY_ constants
above."""
file_contents = open(file_path, 'r').read()
return LoadFromString(file_contents)
def WriteToFile(json_dict, file_path):
"""Writes the JSON summary in json_dict out to file_path.
The file is written Unix-style (each line ends with just LF, not CRLF);
see https://code.google.com/p/skia/issues/detail?id=1815 for reasons."""
with io.open(file_path, mode='w', newline='', encoding='utf-8') as outfile:
outfile.write(unicode(json.dumps(json_dict, outfile, sort_keys=True,
indent=2)))

2549
gm/gmmain.cpp Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1 @@
# Needed so that test_all.py will recurse into this directory.

View File

@ -0,0 +1,41 @@
#!/usr/bin/python
"""
Copyright 2014 Google Inc.
Use of this source code is governed by a BSD-style license that can be
found in the LICENSE file.
A wrapper around the standard Python unittest library, adding features we need
for various unittests within this directory.
"""
# System-level imports.
import os
import sys
PARENT_DIR = os.path.abspath(os.path.dirname(__file__))
TRUNK_DIR = os.path.abspath(os.path.join(PARENT_DIR, os.pardir, os.pardir))
# Import the superclass base_unittest module from the tools dir.
#
# TODO(epoger): If I don't put this at the beginning of sys.path, the import of
# tests.base_unittest fails. That's bad. I need to come up with a cleaner way
# of doing this... I think this will involve changing how we import the "boto"
# library in gs_utils.py, within the common repo.
TOOLS_DIR = os.path.join(TRUNK_DIR, 'tools')
if TOOLS_DIR != sys.path[0]:
sys.path.insert(0, TOOLS_DIR)
import tests.base_unittest as superclass_module
class TestCase(superclass_module.TestCase):
def __init__(self, *args, **kwargs):
super(TestCase, self).__init__(*args, **kwargs)
# Some of the tests within this package want their output validated,
# so we declare where the expected and actual output will be.
self._testdata_dir = os.path.join(PARENT_DIR, 'testdata')
def main(*args, **kwargs):
superclass_module.main(*args, **kwargs)

View File

@ -0,0 +1,70 @@
#!/usr/bin/python
"""
Copyright 2014 Google Inc.
Use of this source code is governed by a BSD-style license that can be
found in the LICENSE file.
ColumnHeaderFactory class (see class docstring for details)
"""
# Keys used within dictionary representation of each column header.
# NOTE: Keep these in sync with static/constants.js
KEY__EXTRACOLUMNHEADERS__HEADER_TEXT = 'headerText'
KEY__EXTRACOLUMNHEADERS__HEADER_URL = 'headerUrl'
KEY__EXTRACOLUMNHEADERS__IS_FILTERABLE = 'isFilterable'
KEY__EXTRACOLUMNHEADERS__IS_SORTABLE = 'isSortable'
KEY__EXTRACOLUMNHEADERS__USE_FREEFORM_FILTER = 'useFreeformFilter'
KEY__EXTRACOLUMNHEADERS__VALUES_AND_COUNTS = 'valuesAndCounts'
class ColumnHeaderFactory(object):
"""Factory which assembles the header for a single column of data."""
def __init__(self, header_text, header_url=None,
is_filterable=True, is_sortable=True,
use_freeform_filter=False):
"""
Args:
header_text: string; text the client should display within column header.
header_url: string; target URL if user clicks on column header.
If None, nothing to click on.
is_filterable: boolean; whether client should allow filtering on this
column.
is_sortable: boolean; whether client should allow sorting on this column.
use_freeform_filter: boolean; *recommendation* to the client indicating
whether to allow freeform text matching, as opposed to listing all
values alongside checkboxes. If is_filterable==false, this is
meaningless.
"""
self._header_text = header_text
self._header_url = header_url
self._is_filterable = is_filterable
self._is_sortable = is_sortable
self._use_freeform_filter = use_freeform_filter
def create_as_dict(self, values_and_counts_dict=None):
"""Creates the header for this column, in dictionary form.
Creates the header for this column in dictionary form, as needed when
constructing the JSON representation. Uses the KEY__EXTRACOLUMNHEADERS__*
constants as keys.
Args:
values_and_counts_dict: dictionary mapping each possible column value
to its count (how many entries in the column have this value), or
None if this information is not available.
"""
asdict = {
KEY__EXTRACOLUMNHEADERS__HEADER_TEXT: self._header_text,
KEY__EXTRACOLUMNHEADERS__IS_FILTERABLE: self._is_filterable,
KEY__EXTRACOLUMNHEADERS__IS_SORTABLE: self._is_sortable,
KEY__EXTRACOLUMNHEADERS__USE_FREEFORM_FILTER: self._use_freeform_filter,
}
if self._header_url:
asdict[KEY__EXTRACOLUMNHEADERS__HEADER_URL] = self._header_url
if values_and_counts_dict:
asdict[KEY__EXTRACOLUMNHEADERS__VALUES_AND_COUNTS] = sorted(
values_and_counts_dict.items())
return asdict

Some files were not shown because too many files have changed in this diff Show More