Snapshot from http://skia.googlecode.com/svn/trunk@7527
Change-Id: I83c7c2152f5d2c303b4655a5a604f513a54f350a
diff --git a/tools/PdfRenderer.cpp b/tools/PdfRenderer.cpp
index 8819266..9a4bd38 100644
--- a/tools/PdfRenderer.cpp
+++ b/tools/PdfRenderer.cpp
@@ -48,15 +48,10 @@
}
}
-bool PdfRenderer::write(const SkString& path) const {
+void PdfRenderer::write(SkWStream* stream) const {
SkPDFDocument doc;
doc.appendPage(fPDFDevice);
- SkFILEWStream stream(path.c_str());
- if (stream.isValid()) {
- doc.emitPDF(&stream);
- return true;
- }
- return false;
+ doc.emitPDF(stream);
}
void SimplePdfRenderer::render() {
diff --git a/tools/PdfRenderer.h b/tools/PdfRenderer.h
index bce6197..3524a9d 100644
--- a/tools/PdfRenderer.h
+++ b/tools/PdfRenderer.h
@@ -39,7 +39,7 @@
, fPDFDevice(NULL)
{}
- bool write(const SkString& path) const;
+ void write(SkWStream* stream) const;
protected:
SkCanvas* setupCanvas();
diff --git a/tools/PictureBenchmark.cpp b/tools/PictureBenchmark.cpp
index bdf1306..f1be2aa 100644
--- a/tools/PictureBenchmark.cpp
+++ b/tools/PictureBenchmark.cpp
@@ -70,9 +70,8 @@
// We throw this away to remove first time effects (such as paging in this program)
fRenderer->setup();
fRenderer->render(NULL);
- fRenderer->resetState();
+ fRenderer->resetState(true);
- BenchTimer* timer = this->setupTimer();
bool usingGpu = false;
#if SK_SUPPORT_GPU
usingGpu = fRenderer->isUsingGpuDevice();
@@ -95,26 +94,55 @@
int x, y;
while (tiledRenderer->nextTile(x, y)) {
- TimerData timerData(tiledRenderer->getPerIterTimeFormat(),
- tiledRenderer->getNormalTimeFormat());
+ // There are two timers, which will behave slightly differently:
+ // 1) longRunningTimer, along with perTileTimerData, will time how long it takes to draw
+ // one tile fRepeats times, and take the average. As such, it will not respect the
+ // logPerIter or printMin options, since it does not know the time per iteration. It
+ // will also be unable to call flush() for each tile.
+ // The goal of this timer is to make up for a system timer that is not precise enough to
+ // measure the small amount of time it takes to draw one tile once.
+ //
+ // 2) perTileTimer, along with perTileTimerData, will record each run separately, and
+ // then take the average. As such, it supports logPerIter and printMin options.
+ SkAutoTDelete<BenchTimer> longRunningTimer(this->setupTimer());
+ TimerData longRunningTimerData(tiledRenderer->getPerIterTimeFormat(),
+ tiledRenderer->getNormalTimeFormat());
+ SkAutoTDelete<BenchTimer> perTileTimer(this->setupTimer());
+ TimerData perTileTimerData(tiledRenderer->getPerIterTimeFormat(),
+ tiledRenderer->getNormalTimeFormat());
+ longRunningTimer->start();
for (int i = 0; i < fRepeats; ++i) {
- timer->start();
+ perTileTimer->start();
tiledRenderer->drawCurrentTile();
- timer->truncatedEnd();
- tiledRenderer->resetState();
- timer->end();
- timerData.appendTimes(timer, fRepeats - 1 == i);
+ perTileTimer->truncatedEnd();
+ tiledRenderer->resetState(false);
+ perTileTimer->end();
+ perTileTimerData.appendTimes(perTileTimer.get(), fRepeats - 1 == i);
}
+ longRunningTimer->truncatedEnd();
+ tiledRenderer->resetState(true);
+ longRunningTimer->end();
+ longRunningTimerData.appendTimes(longRunningTimer.get(), true);
+
SkString configName = tiledRenderer->getConfigName();
configName.appendf(": tile [%i,%i] out of [%i,%i]", x, y, xTiles, yTiles);
- SkString result = timerData.getResult(fLogPerIter, fPrintMin, fRepeats,
- configName.c_str(), fShowWallTime,
- fShowTruncatedWallTime, fShowCpuTime,
- fShowTruncatedCpuTime, usingGpu && fShowGpuTime);
+ SkString result = perTileTimerData.getResult(fLogPerIter, fPrintMin, fRepeats,
+ configName.c_str(), fShowWallTime,
+ fShowTruncatedWallTime, fShowCpuTime,
+ fShowTruncatedCpuTime,
+ usingGpu && fShowGpuTime);
result.append("\n");
this->logProgress(result.c_str());
+
+ configName.append(" <averaged>");
+ SkString longRunningResult = longRunningTimerData.getResult(false, false, fRepeats,
+ configName.c_str(), fShowWallTime, fShowTruncatedWallTime,
+ fShowCpuTime, fShowTruncatedCpuTime, usingGpu && fShowGpuTime);
+ longRunningResult.append("\n");
+ this->logProgress(longRunningResult.c_str());
}
} else {
+ SkAutoTDelete<BenchTimer> timer(this->setupTimer());
TimerData timerData(fRenderer->getPerIterTimeFormat(), fRenderer->getNormalTimeFormat());
for (int i = 0; i < fRepeats; ++i) {
fRenderer->setup();
@@ -124,10 +152,10 @@
timer->truncatedEnd();
// Finishes gl context
- fRenderer->resetState();
+ fRenderer->resetState(true);
timer->end();
- timerData.appendTimes(timer, fRepeats - 1 == i);
+ timerData.appendTimes(timer.get(), fRepeats - 1 == i);
}
SkString configName = fRenderer->getConfigName();
@@ -140,7 +168,6 @@
}
fRenderer->end();
- SkDELETE(timer);
}
}
diff --git a/tools/PictureRenderer.cpp b/tools/PictureRenderer.cpp
index 61de8c6..cb2c3a4 100644
--- a/tools/PictureRenderer.cpp
+++ b/tools/PictureRenderer.cpp
@@ -131,7 +131,7 @@
}
void PictureRenderer::end() {
- this->resetState();
+ this->resetState(true);
SkSafeUnref(fPicture);
fPicture = NULL;
fCanvas.reset(NULL);
@@ -172,7 +172,7 @@
}
}
-void PictureRenderer::resetState() {
+void PictureRenderer::resetState(bool callFinish) {
#if SK_SUPPORT_GPU
if (this->isUsingGpuDevice()) {
SkGLContext* glContext = fGrContextFactory.getGLContext(
@@ -184,14 +184,17 @@
}
fGrContext->flush();
- SK_GL(*glContext, Finish());
+ if (callFinish) {
+ SK_GL(*glContext, Finish());
+ }
}
#endif
}
uint32_t PictureRenderer::recordFlags() {
- return kNone_BBoxHierarchyType == fBBoxHierarchyType ? 0 :
- SkPicture::kOptimizeForClippedPlayback_RecordingFlag;
+ return ((kNone_BBoxHierarchyType == fBBoxHierarchyType) ? 0 :
+ SkPicture::kOptimizeForClippedPlayback_RecordingFlag) |
+ SkPicture::kUsePathBoundsForClip_RecordingFlag;
}
/**
@@ -288,7 +291,7 @@
*out = SkNEW(SkBitmap);
setup_bitmap(*out, fPicture->width(), fPicture->height());
fCanvas->readPixels(*out, 0, 0);
- }
+ }
return true;
}
@@ -315,7 +318,7 @@
if (NULL != path) {
return write(fCanvas, *path);
}
-
+
if (NULL != out) {
*out = SkNEW(SkBitmap);
setup_bitmap(*out, fPicture->width(), fPicture->height());
@@ -522,8 +525,8 @@
}
if (NULL != out) {
if (fCanvas->readPixels(&bitmap, 0, 0)) {
- bitmapCopySubset(bitmap, *out, fTileRects[i].left(),
- fTileRects[i].top());
+ bitmapCopySubset(bitmap, *out, SkScalarFloorToInt(fTileRects[i].left()),
+ SkScalarFloorToInt(fTileRects[i].top()));
} else {
success = false;
}
@@ -594,9 +597,9 @@
SkBitmap bitmap;
if (fBitmap != NULL) {
// All tiles are the same size.
- setup_bitmap(&bitmap, fRects[0].width(), fRects[0].height());
+ setup_bitmap(&bitmap, SkScalarFloorToInt(fRects[0].width()), SkScalarFloorToInt(fRects[0].height()));
}
-
+
for (int i = fStart; i < fEnd; i++) {
DrawTileToCanvas(fCanvas, fRects[i], fClone);
if (fPath != NULL && !writeAppendNumber(fCanvas, fPath, i)
@@ -608,8 +611,8 @@
if (fBitmap != NULL) {
if (fCanvas->readPixels(&bitmap, 0, 0)) {
SkAutoLockPixels alp(*fBitmap);
- bitmapCopySubset(bitmap, fBitmap, fRects[i].left(),
- fRects[i].top());
+ bitmapCopySubset(bitmap, fBitmap, SkScalarFloorToInt(fRects[i].left()),
+ SkScalarFloorToInt(fRects[i].top()));
} else {
*fSuccess = false;
// If one tile fails to read pixels, do not continue drawing the rest.
diff --git a/tools/PictureRenderer.h b/tools/PictureRenderer.h
index 5d6c516..df38faa 100644
--- a/tools/PictureRenderer.h
+++ b/tools/PictureRenderer.h
@@ -110,7 +110,12 @@
*/
virtual TiledPictureRenderer* getTiledRenderer() { return NULL; }
- void resetState();
+ /**
+ * Resets the GPU's state. Does nothing if the backing is raster. For a GPU renderer, calls
+ * flush, and calls finish if callFinish is true.
+ * @param callFinish Whether to call finish.
+ */
+ void resetState(bool callFinish);
void setDeviceType(SkDeviceTypes deviceType) {
fDeviceType = deviceType;
@@ -184,10 +189,10 @@
, fBBoxHierarchyType(kNone_BBoxHierarchyType)
, fGridWidth(0)
, fGridHeight(0)
- , fScaleFactor(SK_Scalar1)
#if SK_SUPPORT_GPU
, fGrContext(fGrContextFactory.get(GrContextFactory::kNative_GLContextType))
#endif
+ , fScaleFactor(SK_Scalar1)
{
sk_bzero(fDrawFilters, sizeof(fDrawFilters));
fViewport.set(0, 0);
diff --git a/tools/bench_pictures.cfg b/tools/bench_pictures.cfg
index c64a686..661af52 100644
--- a/tools/bench_pictures.cfg
+++ b/tools/bench_pictures.cfg
@@ -55,11 +55,11 @@
TiledBitmapConfig(1024, 64),
# Different bounding box heirarchies, for different modes.
- RecordRTreeConfig( DEFAULT_TILE_X, DEFAULT_TILE_Y),
- RecordGridConfig( DEFAULT_TILE_X, DEFAULT_TILE_Y),
- PlaybackCreationRTreeConfig(DEFAULT_TILE_X, DEFAULT_TILE_Y),
- PlaybackCreationGridConfig( DEFAULT_TILE_X, DEFAULT_TILE_Y),
+ RecordRTreeConfig(),
+ PlaybackCreationRTreeConfig(),
TileRTreeConfig( DEFAULT_TILE_X, DEFAULT_TILE_Y),
+ RecordGridConfig( DEFAULT_TILE_X, DEFAULT_TILE_Y),
+ PlaybackCreationGridConfig( DEFAULT_TILE_X, DEFAULT_TILE_Y),
TileGridConfig( DEFAULT_TILE_X, DEFAULT_TILE_Y),
]
@@ -73,8 +73,8 @@
configs = [
# Record
- RecordConfig(scale=str(scale)),
- RecordRTreeConfig(tile_x, tile_y, scale=str(scale)),
+ RecordConfig( scale=str(scale)),
+ RecordRTreeConfig(scale=str(scale)),
RecordGridConfig( tile_x, tile_y, scale=str(scale)),
# Tiled playback
@@ -85,7 +85,6 @@
# Viewport playback
ViewportBitmapConfig(viewport_x, viewport_y, scale=str(scale)),
ViewportRTreeConfig( viewport_x, viewport_y, scale=str(scale)),
- ViewportGridConfig( viewport_x, viewport_y, scale=str(scale)),
]
if do_gpu:
@@ -107,11 +106,11 @@
'debug': [TiledBitmapConfig(DEFAULT_TILE_X, DEFAULT_TILE_Y)],
'default': default_configs,
'no_gpu': [cfg for cfg in default_configs if cfg['device'] != 'gpu'],
- 'nexus_s': AndroidConfigList((256, 256), 0.4897, [], (800, 480),
+ 'nexus_s': AndroidConfigList((256, 256), 0.4897, [], (480, 800),
do_gpu=False),
- 'nexus_4': AndroidConfigList((256, 256), 0.8163, [], (1280, 768)),
- 'nexus_7': AndroidConfigList((256, 256), 0.8163, [2], (1280, 800)),
- 'nexus_10': AndroidConfigList((512, 512), 1.6326, [], (2560, 1600)),
- 'galaxy_nexus': AndroidConfigList((256, 256), 0.8163, [], (1280, 800)),
- 'xoom': AndroidConfigList((256, 256), 0.8163, [], (1200, 800)),
+ 'xoom': AndroidConfigList((256, 256), 1.2244, [], (1200, 800)),
+ 'galaxy_nexus': AndroidConfigList((256, 256), 0.8163, [], (800, 1280)),
+ 'nexus_4': AndroidConfigList((256, 256), 0.7836, [], (768, 1280)),
+ 'nexus_7': AndroidConfigList((256, 256), 1.3061, [2], (1280, 800)),
+ 'nexus_10': AndroidConfigList((512, 512), 2.6122, [], (2560, 1600)),
}
\ No newline at end of file
diff --git a/tools/bench_pictures_cfg_helper.py b/tools/bench_pictures_cfg_helper.py
index 654bad6..65d63a4 100644
--- a/tools/bench_pictures_cfg_helper.py
+++ b/tools/bench_pictures_cfg_helper.py
@@ -13,6 +13,13 @@
return config
+def TileArgs(tile_x, tile_y):
+ return {'mode': ['tile', str(tile_x), str(tile_y)],
+ # TODO(borenet): Turn this back on once the parser is working.
+ #'timeIndividualTiles': True
+ }
+
+
def BitmapConfig(**kwargs):
return Config(device='bitmap', **kwargs)
@@ -22,11 +29,11 @@
def TiledBitmapConfig(tile_x, tile_y, **kwargs):
- return BitmapConfig(mode=['tile', str(tile_x), str(tile_y)], **kwargs)
+ return BitmapConfig(**dict(TileArgs(tile_x, tile_y).items() + kwargs.items()))
def TiledGPUConfig(tile_x, tile_y, **kwargs):
- return GPUConfig(mode=['tile', str(tile_x), str(tile_y)], **kwargs)
+ return GPUConfig(**dict(TileArgs(tile_x, tile_y).items() + kwargs.items()))
def ViewportBitmapConfig(viewport_x, viewport_y, **kwargs):
@@ -38,8 +45,8 @@
def ViewportRTreeConfig(viewport_x, viewport_y, **kwargs):
- return RTreeConfig(viewport_x, viewport_y, mode='simple',
- viewport=[str(viewport_x), str(viewport_y)], **kwargs)
+ return RTreeConfig(mode='simple', viewport=[str(viewport_x), str(viewport_y)],
+ **kwargs)
def ViewportGridConfig(viewport_x, viewport_y, **kwargs):
@@ -64,9 +71,8 @@
**kwargs)
-def RTreeConfig(tile_x, tile_y, mode, **kwargs):
- return BitmapConfig(mode=mode, bbh=['rtree', str(tile_x), str(tile_y)],
- **kwargs)
+def RTreeConfig(**kwargs):
+ return BitmapConfig(bbh='rtree', **kwargs)
def GridConfig(tile_x, tile_y, mode, **kwargs):
@@ -74,18 +80,16 @@
**kwargs)
-def RecordRTreeConfig(tile_x, tile_y, **kwargs):
- return RTreeConfig(tile_x=tile_x, tile_y=tile_y, mode='record', **kwargs)
+def RecordRTreeConfig(**kwargs):
+ return RTreeConfig(mode='record', **kwargs)
-def PlaybackCreationRTreeConfig(tile_x, tile_y, **kwargs):
- return RTreeConfig(tile_x=tile_x, tile_y=tile_y, mode='playbackCreation',
- **kwargs)
+def PlaybackCreationRTreeConfig(**kwargs):
+ return RTreeConfig(mode='playbackCreation', **kwargs)
def TileRTreeConfig(tile_x, tile_y, **kwargs):
- return RTreeConfig(tile_x=tile_x, tile_y=tile_y,
- mode=['tile', str(tile_x), str(tile_y)], **kwargs)
+ return RTreeConfig(**dict(TileArgs(tile_x, tile_y).items() + kwargs.items()))
def RecordGridConfig(tile_x, tile_y, **kwargs):
@@ -97,5 +101,5 @@
def TileGridConfig(tile_x, tile_y, **kwargs):
- return GridConfig(tile_x, tile_y, mode=['tile', str(tile_x), str(tile_y)],
- **kwargs)
\ No newline at end of file
+ return GridConfig(tile_x, tile_y,
+ **dict(TileArgs(tile_x, tile_y).items() + kwargs.items()))
\ No newline at end of file
diff --git a/tools/bench_pictures_main.cpp b/tools/bench_pictures_main.cpp
index 65fc42a..b485aff 100644
--- a/tools/bench_pictures_main.cpp
+++ b/tools/bench_pictures_main.cpp
@@ -27,6 +27,7 @@
"line",
"bitmap",
"rect",
+ "oval",
"path",
"text",
"all",
@@ -450,7 +451,7 @@
gLogger.logError("Missing scaleFactor for --scale\n");
PRINT_USAGE_AND_EXIT;
}
- scaleFactor = atof(*argv);
+ scaleFactor = SkDoubleToScalar(atof(*argv));
} else if (0 == strcmp(*argv, "--tiles")) {
++argv;
if (argv >= stop) {
@@ -774,7 +775,7 @@
int tool_main(int argc, char** argv);
int tool_main(int argc, char** argv) {
-#ifdef SK_ENABLE_INST_COUNT
+#if SK_ENABLE_INST_COUNT
gPrintInstCount = true;
#endif
SkAutoGraphics ag;
diff --git a/tools/build-tot-chromium.sh b/tools/build-tot-chromium.sh
new file mode 100755
index 0000000..9592462
--- /dev/null
+++ b/tools/build-tot-chromium.sh
@@ -0,0 +1,59 @@
+#!/bin/bash
+#
+# Author: Ravi Mistry
+#
+# Script to checkout and build a fresh copy of Chromium from head that uses a
+# writable, tip-of-tree Skia rather than the read-only, revision-locked Skia
+# specified in http://src.chromium.org/viewvc/chrome/trunk/src/DEPS
+#
+# Sample Usage:
+# tools/build-tot-chromium.sh ~/chromiumtrunk
+
+if [[ $# -ne 1 ]] ; then
+ echo "usage: $0 chromium_location"
+ exit 1
+fi
+CHROMIUM_LOCATION=$1
+
+echo -e "\n\n========Deleting $CHROMIUM_LOCATION========\n\n"
+rm -rf $CHROMIUM_LOCATION
+
+mkdir $CHROMIUM_LOCATION
+cd $CHROMIUM_LOCATION
+gclient config https://src.chromium.org/chrome/trunk/src
+echo '
+solutions = [
+ { "name" : "src",
+ "url" : "https://src.chromium.org/chrome/trunk/src",
+ "deps_file" : "DEPS",
+ "managed" : True,
+ "custom_deps" : {
+ "src/third_party/skia": "https://skia.googlecode.com/svn/trunk",
+ "src/third_party/skia/gyp": None,
+ "src/third_party/skia/src": None,
+ "src/third_party/skia/include": None,
+ },
+ "safesync_url": "",
+ },
+]
+' > .gclient
+
+echo -e "\n\n========Starting gclient sync========\n\n"
+START_TIME=$SECONDS
+gclient sync
+END_TIME=$SECONDS
+echo -e "\n\n========gclient sync took $((END_TIME - START_TIME)) seconds========\n\n"
+
+cd src
+rm -rf out/Debug out/Release
+GYP_GENERATORS='ninja' ./build/gyp_chromium
+
+echo -e "\n\n========Starting ninja build========\n\n"
+START_TIME=$SECONDS
+ninja -C out/Release chrome
+END_TIME=$SECONDS
+echo -e "\n\n========ninja build took $((END_TIME - START_TIME)) seconds========\n\n"
+
+SVN_VERSION=`svnversion .`
+echo -e "\n\n========The Chromium & Skia versions are $SVN_VERSION========\n\n"
+
diff --git a/tools/filtermain.cpp b/tools/filtermain.cpp
index c1b2040..3715b3e 100644
--- a/tools/filtermain.cpp
+++ b/tools/filtermain.cpp
@@ -5,6 +5,7 @@
* found in the LICENSE file.
*/
+#include "SkDebugCanvas.h"
#include "SkDevice.h"
#include "SkGraphics.h"
#include "SkImageDecoder.h"
@@ -19,129 +20,27 @@
static void usage() {
SkDebugf("Usage: filter -i inFile [-o outFile] [--input-dir path] [--output-dir path]\n");
- SkDebugf(" [-p pathFile] [-t textureDir] [-h|--help]\n\n");
+ SkDebugf(" [-h|--help]\n\n");
SkDebugf(" -i inFile : file to file.\n");
SkDebugf(" -o outFile : result of filtering.\n");
SkDebugf(" --input-dir : process all files in dir with .skp extension.\n");
SkDebugf(" --output-dir : results of filtering the input dir.\n");
- SkDebugf(" -p pathFile : file in which to place compileable path data.\n");
- SkDebugf(" -t textureDir : directory in which to place textures. (only available w/ single file)\n");
SkDebugf(" -h|--help : Show this help message.\n");
}
-// SkFilterRecord allows the filter to manipulate the read in SkPicture
-class SkFilterRecord : public SkPictureRecord {
-public:
- SkFilterRecord(uint32_t recordFlags, SkDevice* device, SkFILEWStream* pathStream)
- : INHERITED(recordFlags, device)
- , fTransSkipped(0)
- , fTransTot(0)
- , fScalesSkipped(0)
- , fScalesTot(0)
- , fPathStream(pathStream) {
- }
-
- virtual ~SkFilterRecord() {
- }
-
- virtual bool clipPath(const SkPath& path, SkRegion::Op op, bool doAntiAlias) SK_OVERRIDE {
- if (!path.isRect(NULL) && 4 < path.countPoints()) {
- sk_tools::dump_path(fPathStream, path);
- }
- return INHERITED::clipPath(path, op, doAntiAlias);
- }
-
- virtual void drawPath(const SkPath& path, const SkPaint& p) SK_OVERRIDE {
- if (!path.isRect(NULL) && 4 < path.countPoints()) {
- sk_tools::dump_path(fPathStream, path);
- }
- INHERITED::drawPath(path, p);
- }
-
- virtual bool translate(SkScalar dx, SkScalar dy) SK_OVERRIDE {
- ++fTransTot;
-
-#if 0
- if (0 == dx && 0 == dy) {
- ++fTransSkipped;
- return true;
- }
-#endif
-
- return INHERITED::translate(dx, dy);
- }
-
- virtual bool scale(SkScalar sx, SkScalar sy) SK_OVERRIDE {
- ++fScalesTot;
-
-#if 0
- if (SK_Scalar1 == sx && SK_Scalar1 == sy) {
- ++fScalesSkipped;
- return true;
- }
-#endif
-
- return INHERITED::scale(sx, sy);
- }
-
- void saveImages(const SkString& path) {
- SkTRefArray<SkBitmap>* bitmaps = fBitmapHeap->extractBitmaps();
-
- if (NULL != bitmaps) {
- for (int i = 0; i < bitmaps->count(); ++i) {
- SkString filename(path);
- if (!path.endsWith("\\")) {
- filename.append("\\");
- }
- filename.append("image");
- filename.appendS32(i);
- filename.append(".png");
-
- SkImageEncoder::EncodeFile(filename.c_str(), (*bitmaps)[i],
- SkImageEncoder::kPNG_Type, 0);
- }
- }
-
- bitmaps->unref();
- }
-
- void report() {
- SkDebugf("%d Trans skipped (out of %d)\n", fTransSkipped, fTransTot);
- SkDebugf("%d Scales skipped (out of %d)\n", fScalesSkipped, fScalesTot);
- }
-
-protected:
- int fTransSkipped;
- int fTransTot;
-
- int fScalesSkipped;
- int fScalesTot;
-
- SkFILEWStream* fPathStream;
-private:
- typedef SkPictureRecord INHERITED;
-};
-
-// Wrap SkPicture to allow installation of a SkFilterRecord object
-class SkFilterPicture : public SkPicture {
-public:
- SkFilterPicture(int width, int height, SkPictureRecord* record) {
- fWidth = width;
- fHeight = height;
- fRecord = record;
- SkSafeRef(fRecord);
- }
-
-private:
- typedef SkPicture INHERITED;
-};
-
-static bool PNGEncodeBitmapToStream(SkWStream* stream, const SkBitmap& bitmap) {
- return SkImageEncoder::EncodeStream(stream, bitmap, SkImageEncoder::kPNG_Type, 100);
+// Is the supplied paint simply a color?
+static bool is_simple(const SkPaint& p) {
+ return NULL == p.getPathEffect() &&
+ NULL == p.getShader() &&
+ NULL == p.getXfermode() &&
+ NULL == p.getMaskFilter() &&
+ NULL == p.getColorFilter() &&
+ NULL == p.getRasterizer() &&
+ NULL == p.getLooper() &&
+ NULL == p.getImageFilter();
}
-int filter_picture(const SkString& inFile, const SkString& outFile,
- const SkString& textureDir, SkFILEWStream *pathStream) {
+static int filter_picture(const SkString& inFile, const SkString& outFile) {
SkPicture* inPicture = NULL;
SkFILEStream inStream(inFile.c_str());
@@ -154,35 +53,67 @@
return -1;
}
- SkBitmap bm;
- bm.setConfig(SkBitmap::kNo_Config, inPicture->width(), inPicture->height());
- SkAutoTUnref<SkDevice> dev(SkNEW_ARGS(SkDevice, (bm)));
+ SkDebugCanvas debugCanvas(inPicture->width(), inPicture->height());
+ debugCanvas.setBounds(inPicture->width(), inPicture->height());
+ inPicture->draw(&debugCanvas);
- SkAutoTUnref<SkFilterRecord> filterRecord(SkNEW_ARGS(SkFilterRecord, (0, dev, pathStream)));
+ const SkTDArray<SkDrawCommand*>& commands = debugCanvas.getDrawCommands();
- // Playback the read in picture to the SkFilterRecorder to allow filtering
- filterRecord->beginRecording();
- inPicture->draw(filterRecord);
- filterRecord->endRecording();
+ for (int i = 0; i < commands.count(); ++i) {
+ // Check for:
+ // SAVE_LAYER
+ // DRAW_BITMAP_RECT_TO_RECT
+ // RESTORE
+ // where the saveLayer's color can be moved into the drawBitmapRect
+ if (SAVE_LAYER == commands[i]->getType() && commands.count() > i+2) {
+ if (DRAW_BITMAP_RECT_TO_RECT == commands[i+1]->getType() &&
+ RESTORE == commands[i+2]->getType()) {
+ SaveLayer* sl = (SaveLayer*) commands[i];
+ DrawBitmapRect* dbmr = (DrawBitmapRect*) commands[i+1];
- filterRecord->report();
+ const SkPaint* p0 = sl->paint();
+ SkPaint* p1 = dbmr->paint();
+
+ if (NULL == p0) {
+ commands[i]->setVisible(false);
+ commands[i+2]->setVisible(false);
+ } else if (NULL == p1) {
+ commands[i]->setVisible(false);
+ dbmr->setPaint(*p0);
+ commands[i+2]->setVisible(false);
+ } else if (is_simple(*p0) &&
+ (SkColorGetR(p0->getColor()) == SkColorGetR(p1->getColor())) &&
+ (SkColorGetG(p0->getColor()) == SkColorGetG(p1->getColor())) &&
+ (SkColorGetB(p0->getColor()) == SkColorGetB(p1->getColor()))) {
+ commands[i]->setVisible(false);
+ SkColor newColor = SkColorSetA(p1->getColor(),
+ SkColorGetA(p0->getColor()));
+ p1->setColor(newColor);
+ commands[i+2]->setVisible(false);
+ }
+ }
+ }
+ }
if (!outFile.isEmpty()) {
- SkFilterPicture outPicture(inPicture->width(), inPicture->height(), filterRecord);
+ SkPicture outPicture;
+
+ SkCanvas* canvas = outPicture.beginRecording(inPicture->width(), inPicture->height());
+ debugCanvas.draw(canvas);
+ outPicture.endRecording();
+
SkFILEWStream outStream(outFile.c_str());
outPicture.serialize(&outStream);
}
- if (!textureDir.isEmpty()) {
- filterRecord->saveImages(textureDir);
- }
-
return 0;
}
// This function is not marked as 'static' so it can be referenced externally
// in the iOS build.
+int tool_main(int argc, char** argv); // suppress a warning on mac
+
int tool_main(int argc, char** argv) {
SkGraphics::Init();
@@ -191,7 +122,7 @@
return -1;
}
- SkString inFile, outFile, inDir, outDir, textureDir, pathFile;
+ SkString inFile, outFile, inDir, outDir;
char* const* stop = argv + argc;
for (++argv; argv < stop; ++argv) {
@@ -231,24 +162,6 @@
usage();
return -1;
}
- } else if (strcmp(*argv, "-p") == 0) {
- argv++;
- if (argv < stop && **argv) {
- pathFile.set(*argv);
- } else {
- SkDebugf("missing arg for -p\n");
- usage();
- return -1;
- }
- } else if (strcmp(*argv, "-t") == 0) {
- argv++;
- if (argv < stop && **argv) {
- textureDir.set(*argv);
- } else {
- SkDebugf("missing arg for -t\n");
- usage();
- return -1;
- }
} else if (strcmp(*argv, "--help") == 0 || strcmp(*argv, "-h") == 0) {
usage();
return 0;
@@ -259,27 +172,8 @@
}
}
- if(!inDir.isEmpty() && !textureDir.isEmpty()) {
- SkDebugf("ERROR: The textureDir option is not permitted when passing an input directory.\n");
- usage();
- return -1;
- }
-
- SkFILEWStream *pathStream = NULL;
-
- if (!pathFile.isEmpty()) {
- pathStream = new SkFILEWStream(pathFile.c_str());
- if (!pathStream->isValid()) {
- SkDebugf("Could open path file %s\n", pathFile.c_str());
- delete pathStream;
- return -1;
- }
-
- sk_tools::dump_path_prefix(pathStream);
- }
-
SkOSFile::Iter iter(inDir.c_str(), "skp");
- int failures = 0;
+
SkString inputFilename, outputFilename;
if (iter.next(&inputFilename)) {
@@ -289,26 +183,16 @@
sk_tools::make_filepath(&outFile, outDir, inputFilename);
}
SkDebugf("Executing %s\n", inputFilename.c_str());
- filter_picture(inFile, outFile, textureDir, pathStream);
+ filter_picture(inFile, outFile);
} while(iter.next(&inputFilename));
} else if (!inFile.isEmpty()) {
- filter_picture(inFile, outFile, textureDir, pathStream);
+ filter_picture(inFile, outFile);
} else {
usage();
- if (NULL != pathStream) {
- delete pathStream;
- pathStream = NULL;
- }
return -1;
}
- if (NULL != pathStream) {
- sk_tools::dump_path_suffix(pathStream);
- delete pathStream;
- pathStream = NULL;
- }
-
SkGraphics::Term();
return 0;
}
diff --git a/tools/pinspect.cpp b/tools/pinspect.cpp
index b82bd33..b5a6727 100644
--- a/tools/pinspect.cpp
+++ b/tools/pinspect.cpp
@@ -39,9 +39,13 @@
}
static void dumpOps(SkPicture* pic) {
+#ifdef SK_DEVELOPER
SkDebugfDumper dumper;
SkDumpCanvas canvas(&dumper);
canvas.drawPicture(*pic);
+#else
+ printf("SK_DEVELOPER mode not enabled\n");
+#endif
}
int tool_main(int argc, char** argv);
diff --git a/tools/render_pdfs_main.cpp b/tools/render_pdfs_main.cpp
index 231f52e..3aac682 100644
--- a/tools/render_pdfs_main.cpp
+++ b/tools/render_pdfs_main.cpp
@@ -33,7 +33,7 @@
SkDebugf("SKP to PDF rendering tool\n");
SkDebugf("\n"
"Usage: \n"
-" %s <input>... <outputDir> \n"
+" %s <input>... -w <outputDir> \n"
, argv0);
SkDebugf("\n\n");
SkDebugf(
@@ -89,15 +89,25 @@
static bool write_output(const SkString& outputDir,
const SkString& inputFilename,
const sk_tools::PdfRenderer& renderer) {
+ if (outputDir.isEmpty()) {
+ SkDynamicMemoryWStream stream;
+ renderer.write(&stream);
+ return true;
+ }
+
SkString outputPath;
if (!make_output_filepath(&outputPath, outputDir, inputFilename)) {
return false;
}
- bool isWritten = renderer.write(outputPath);
- if (!isWritten) {
+
+ SkFILEWStream stream(outputPath.c_str());
+ if (!stream.isValid()) {
SkDebugf("Could not write to file %s\n", outputPath.c_str());
+ return false;
}
- return isWritten;
+ renderer.write(&stream);
+
+ return true;
}
/** Reads an skp file, renders it to pdf and writes the output to a pdf file
@@ -168,7 +178,8 @@
}
static void parse_commandline(int argc, char* const argv[],
- SkTArray<SkString>* inputs) {
+ SkTArray<SkString>* inputs,
+ SkString* outputDir) {
const char* argv0 = argv[0];
char* const* stop = argv + argc;
@@ -176,12 +187,20 @@
if ((0 == strcmp(*argv, "-h")) || (0 == strcmp(*argv, "--help"))) {
usage(argv0);
exit(-1);
+ } else if (0 == strcmp(*argv, "-w")) {
+ ++argv;
+ if (argv >= stop) {
+ SkDebugf("Missing outputDir for -w\n");
+ usage(argv0);
+ exit(-1);
+ }
+ *outputDir = SkString(*argv);
} else {
inputs->push_back(SkString(*argv));
}
}
- if (inputs->count() < 2) {
+ if (inputs->count() < 1) {
usage(argv0);
exit(-1);
}
@@ -197,11 +216,11 @@
renderer(SkNEW(sk_tools::SimplePdfRenderer));
SkASSERT(renderer.get());
- parse_commandline(argc, argv, &inputs);
- SkString outputDir = inputs[inputs.count() - 1];
+ SkString outputDir;
+ parse_commandline(argc, argv, &inputs, &outputDir);
int failures = 0;
- for (int i = 0; i < inputs.count() - 1; i ++) {
+ for (int i = 0; i < inputs.count(); i ++) {
failures += process_input(inputs[i], outputDir, *renderer);
}
@@ -209,6 +228,7 @@
SkDebugf("Failed to render %i PDFs.\n", failures);
return 1;
}
+ return 0;
}
#if !defined SK_BUILD_FOR_IOS
@@ -216,4 +236,3 @@
return tool_main(argc, (char**) argv);
}
#endif
-
diff --git a/tools/render_pictures_main.cpp b/tools/render_pictures_main.cpp
index fce4055..a459bf2 100644
--- a/tools/render_pictures_main.cpp
+++ b/tools/render_pictures_main.cpp
@@ -32,7 +32,7 @@
" [--pipe]\n"
" [--bbh bbhType]\n"
" [--multi count]\n"
-" [--validate]\n"
+" [--validate [--maxComponentDiff n]]\n"
" [--writeWholeImage]\n"
" [--clone n]\n"
" [--viewport width height][--scale sf]\n"
@@ -86,6 +86,8 @@
SkDebugf(
" --validate: Verify that the rendered image contains the same pixels as "
"the picture rendered in simple mode.\n"
+" --maxComponentDiff: maximum diff on a component. Default is 256, "
+"which means we report but we do not generate an error.\n"
" --writeWholeImage: In tile mode, write the entire rendered image to a "
"file, instead of an image for each tile.\n");
SkDebugf(
@@ -166,19 +168,28 @@
SkDELETE(outputPath);
}
- renderer.resetState();
-
renderer.end();
SkDELETE(picture);
return success;
}
+static inline int getByte(uint32_t value, int index) {
+ SkASSERT(0 <= index && index < 4);
+ return (value >> (index * 8)) & 0xFF;
+}
+
+static int MaxByteDiff(uint32_t v1, uint32_t v2) {
+ return SkMax32(SkMax32(abs(getByte(v1, 0) - getByte(v2, 0)), abs(getByte(v1, 1) - getByte(v2, 1))),
+ SkMax32(abs(getByte(v1, 2) - getByte(v2, 2)), abs(getByte(v1, 3) - getByte(v2, 3))));
+}
+
static bool render_picture(const SkString& inputPath, const SkString* outputDir,
sk_tools::PictureRenderer& renderer,
- bool validate,
+ bool validate, int maxComponentDiff,
bool writeWholeImage,
int clones) {
+ int diffs[256] = {0};
SkBitmap* bitmap = NULL;
bool success = render_picture(inputPath,
writeWholeImage ? NULL : outputDir,
@@ -218,13 +229,19 @@
SkDELETE(referenceBitmap);
return false;
}
-
+
for (int y = 0; success && y < bitmap->height(); y++) {
for (int x = 0; success && x < bitmap->width(); x++) {
- if (*referenceBitmap->getAddr32(x, y) != *bitmap->getAddr32(x, y)) {
- SkDebugf("Expected pixel at (%i %i): 0x%x, actual 0x%x\n",
- x, y,
- referenceBitmap->getAddr32(x, y),
+ int diff = MaxByteDiff(*referenceBitmap->getAddr32(x, y),
+ *bitmap->getAddr32(x, y));
+ SkASSERT(diff >= 0 && diff <= 255);
+ diffs[diff]++;
+
+ if (diff > maxComponentDiff) {
+ SkDebugf("Expected pixel at (%i %i) exceedds maximum "
+ "component diff of %i: 0x%x, actual 0x%x\n",
+ x, y, maxComponentDiff,
+ *referenceBitmap->getAddr32(x, y),
*bitmap->getAddr32(x, y));
SkDELETE(bitmap);
SkDELETE(referenceBitmap);
@@ -233,6 +250,12 @@
}
}
SkDELETE(referenceBitmap);
+
+ for (int i = 1; i <= 255; ++i) {
+ if(diffs[i] > 0) {
+ SkDebugf("Number of pixels with max diff of %i is %i\n", i, diffs[i]);
+ }
+ }
}
if (writeWholeImage) {
@@ -258,7 +281,8 @@
static int process_input(const SkString& input, const SkString* outputDir,
sk_tools::PictureRenderer& renderer,
- bool validate, bool writeWholeImage, int clones) {
+ bool validate, int maxComponentDiff,
+ bool writeWholeImage, int clones) {
SkOSFile::Iter iter(input.c_str(), "skp");
SkString inputFilename;
int failures = 0;
@@ -268,14 +292,16 @@
SkString inputPath;
sk_tools::make_filepath(&inputPath, input, inputFilename);
if (!render_picture(inputPath, outputDir, renderer,
- validate, writeWholeImage, clones)) {
+ validate, maxComponentDiff,
+ writeWholeImage, clones)) {
++failures;
}
} while(iter.next(&inputFilename));
} else if (SkStrEndsWith(input.c_str(), ".skp")) {
SkString inputPath(input);
if (!render_picture(inputPath, outputDir, renderer,
- validate, writeWholeImage, clones)) {
+ validate, maxComponentDiff,
+ writeWholeImage, clones)) {
++failures;
}
} else {
@@ -288,7 +314,8 @@
static void parse_commandline(int argc, char* const argv[], SkTArray<SkString>* inputs,
sk_tools::PictureRenderer*& renderer, SkString*& outputDir,
- bool* validate, bool* writeWholeImage,
+ bool* validate, int* maxComponentDiff,
+ bool* writeWholeImage,
int* clones){
const char* argv0 = argv[0];
char* const* stop = argv + argc;
@@ -312,6 +339,7 @@
sk_tools::PictureRenderer::BBoxHierarchyType bbhType =
sk_tools::PictureRenderer::kNone_BBoxHierarchyType;
*validate = false;
+ *maxComponentDiff = 256;
*writeWholeImage = false;
*clones = 0;
SkISize viewport;
@@ -425,7 +453,7 @@
usage(argv0);
exit(-1);
}
- scaleFactor = atof(*argv);
+ scaleFactor = SkDoubleToScalar(atof(*argv));
} else if (0 == strcmp(*argv, "--tiles")) {
++argv;
if (argv >= stop) {
@@ -511,6 +539,25 @@
outputDir = SkNEW_ARGS(SkString, (*argv));
} else if (0 == strcmp(*argv, "--validate")) {
*validate = true;
+ } else if (0 == strcmp(*argv, "--maxComponentDiff")) {
+ if (!*validate) {
+ SkDebugf("--maxComponentDiff must be used only with --validate\n");
+ usage(argv0);
+ exit(-1);
+ }
+ ++argv;
+ if (argv >= stop) {
+ SkDebugf("Missing arg for --maxComponentDiff\n");
+ usage(argv0);
+ exit(-1);
+ }
+ *maxComponentDiff = atoi(*argv);
+ if (*maxComponentDiff < 0 || *maxComponentDiff > 256) {
+ SkSafeUnref(renderer);
+ SkDebugf("maxComponentDiff: 0 - 256.\n");
+ usage(argv0);
+ exit(-1);
+ }
} else if (0 == strcmp(*argv, "--writeWholeImage")) {
*writeWholeImage = true;
} else {
@@ -676,16 +723,18 @@
sk_tools::PictureRenderer* renderer = NULL;
SkString* outputDir = NULL;
bool validate = false;
+ int maxComponentDiff = 256;
bool writeWholeImage = false;
int clones = 0;
parse_commandline(argc, argv, &inputs, renderer, outputDir,
- &validate, &writeWholeImage, &clones);
+ &validate, &maxComponentDiff, &writeWholeImage, &clones);
SkASSERT(renderer);
int failures = 0;
for (int i = 0; i < inputs.count(); i ++) {
failures += process_input(inputs[i], outputDir, *renderer,
- validate, writeWholeImage, clones);
+ validate, maxComponentDiff,
+ writeWholeImage, clones);
}
if (failures != 0) {
SkDebugf("Failed to render %i pictures.\n", failures);
diff --git a/tools/sanitize_source_files.py b/tools/sanitize_source_files.py
index d6e3ec6..c7edaa0 100755
--- a/tools/sanitize_source_files.py
+++ b/tools/sanitize_source_files.py
@@ -23,7 +23,7 @@
directory: string - The directory which will be recursively traversed to
find source files to apply modifiers to.
file_modifiers: list - file-modification methods which should be applied to
- the complete file content (Eg: EOFNewlineAdder).
+ the complete file content (Eg: EOFOneAndOnlyOneNewlineAdder).
line_modifiers: list - line-modification methods which should be applied to
lines in a file (Eg: TabReplacer).
"""
@@ -114,11 +114,12 @@
return file_content
-def EOFNewlineAdder(file_content, file_path):
- """Adds a LF at the end of the file if it does not have one."""
- if file_content and file_content[-1] != '\n':
+def EOFOneAndOnlyOneNewlineAdder(file_content, file_path):
+ """Adds one and only one LF at the end of the file."""
+ if file_content and (file_content[-1] != '\n' or file_content[-2:-1] == '\n'):
+ file_content = file_content.rstrip()
file_content += '\n'
- print 'Added newline to %s' % file_path
+ print 'Added exactly one newline to %s' % file_path
return file_content
@@ -140,7 +141,7 @@
os.getcwd(),
file_modifiers=[
CopywriteChecker,
- EOFNewlineAdder,
+ EOFOneAndOnlyOneNewlineAdder,
SvnEOLChecker,
],
line_modifiers=[
@@ -149,4 +150,3 @@
TrailingWhitespaceRemover,
],
))
-
diff --git a/tools/skdiff.cpp b/tools/skdiff.cpp
index a1783a4..ae6d72c 100644
--- a/tools/skdiff.cpp
+++ b/tools/skdiff.cpp
@@ -166,6 +166,7 @@
SkAutoLockPixels alpDiff(dr->fDifference.fBitmap);
SkAutoLockPixels alpWhite(dr->fWhite.fBitmap);
int mismatchedPixels = 0;
+ int totalMismatchA = 0;
int totalMismatchR = 0;
int totalMismatchG = 0;
int totalMismatchB = 0;
@@ -177,17 +178,21 @@
for (int x = 0; x < w; x++) {
SkPMColor c0 = *dr->fBase.fBitmap.getAddr32(x, y);
SkPMColor c1 = *dr->fComparison.fBitmap.getAddr32(x, y);
- SkPMColor trueDifference = compute_diff_pmcolor(c0, c1);
SkPMColor outputDifference = diffFunction(c0, c1);
- uint32_t thisR = SkGetPackedR32(trueDifference);
- uint32_t thisG = SkGetPackedG32(trueDifference);
- uint32_t thisB = SkGetPackedB32(trueDifference);
+ uint32_t thisA = SkAbs32(SkGetPackedA32(c0) - SkGetPackedA32(c1));
+ uint32_t thisR = SkAbs32(SkGetPackedR32(c0) - SkGetPackedR32(c1));
+ uint32_t thisG = SkAbs32(SkGetPackedG32(c0) - SkGetPackedG32(c1));
+ uint32_t thisB = SkAbs32(SkGetPackedB32(c0) - SkGetPackedB32(c1));
+ totalMismatchA += thisA;
totalMismatchR += thisR;
totalMismatchG += thisG;
totalMismatchB += thisB;
// In HSV, value is defined as max RGB component.
int value = MAX3(thisR, thisG, thisB);
dr->fWeightedFraction += ((float) value) / 255;
+ if (thisA > dr->fMaxMismatchA) {
+ dr->fMaxMismatchA = thisA;
+ }
if (thisR > dr->fMaxMismatchR) {
dr->fMaxMismatchR = thisR;
}
@@ -215,6 +220,8 @@
int pixelCount = w * h;
dr->fFractionDifference = ((float) mismatchedPixels) / pixelCount;
dr->fWeightedFraction /= pixelCount;
+ dr->fTotalMismatchA = totalMismatchA;
+ dr->fAverageMismatchA = ((float) totalMismatchA) / pixelCount;
dr->fAverageMismatchR = ((float) totalMismatchR) / pixelCount;
dr->fAverageMismatchG = ((float) totalMismatchG) / pixelCount;
dr->fAverageMismatchB = ((float) totalMismatchB) / pixelCount;
diff --git a/tools/skdiff.h b/tools/skdiff.h
index b9e69ce..6abaf6c 100644
--- a/tools/skdiff.h
+++ b/tools/skdiff.h
@@ -115,9 +115,12 @@
, fWhite()
, fFractionDifference(0)
, fWeightedFraction(0)
+ , fAverageMismatchA(0)
, fAverageMismatchR(0)
, fAverageMismatchG(0)
, fAverageMismatchB(0)
+ , fTotalMismatchA(0)
+ , fMaxMismatchA(0)
, fMaxMismatchR(0)
, fMaxMismatchG(0)
, fMaxMismatchB(0)
@@ -135,10 +138,14 @@
float fFractionDifference;
float fWeightedFraction;
+ float fAverageMismatchA;
float fAverageMismatchR;
float fAverageMismatchG;
float fAverageMismatchB;
+ uint32_t fTotalMismatchA;
+
+ uint32_t fMaxMismatchA;
uint32_t fMaxMismatchR;
uint32_t fMaxMismatchG;
uint32_t fMaxMismatchB;
diff --git a/tools/skdiff_html.cpp b/tools/skdiff_html.cpp
index 85d8777..6f3c3b0 100644
--- a/tools/skdiff_html.cpp
+++ b/tools/skdiff_html.cpp
@@ -124,10 +124,23 @@
if (diff.fFractionDifference < 0.01) {
print_pixel_count(stream, diff);
}
+ stream->writeText("<br>");
+ if (SkScalarRoundToInt(diff.fAverageMismatchA) > 0) {
+ stream->writeText("<br>Average alpha channel mismatch ");
+ stream->writeDecAsText(SkScalarRoundToInt(diff.fAverageMismatchA));
+ }
+
+ stream->writeText("<br>Max alpha channel mismatch ");
+ stream->writeDecAsText(SkScalarRoundToInt(diff.fMaxMismatchA));
+
+ stream->writeText("<br>Total alpha channel mismatch ");
+ stream->writeDecAsText(static_cast<int>(diff.fTotalMismatchA));
+
+ stream->writeText("<br>");
stream->writeText("<br>Average color mismatch ");
- stream->writeDecAsText(static_cast<int>(MAX3(diff.fAverageMismatchR,
- diff.fAverageMismatchG,
- diff.fAverageMismatchB)));
+ stream->writeDecAsText(SkScalarRoundToInt(MAX3(diff.fAverageMismatchR,
+ diff.fAverageMismatchG,
+ diff.fAverageMismatchB)));
stream->writeText("<br>Max color mismatch ");
stream->writeDecAsText(MAX3(diff.fMaxMismatchR,
diff.fMaxMismatchG,
diff --git a/tools/skimage_main.cpp b/tools/skimage_main.cpp
index 83f115c..53cc6b3 100644
--- a/tools/skimage_main.cpp
+++ b/tools/skimage_main.cpp
@@ -108,4 +108,3 @@
return tool_main(argc, (char**) argv);
}
#endif
-
diff --git a/tools/submit_try b/tools/submit_try
new file mode 100755
index 0000000..0a4cf2d
--- /dev/null
+++ b/tools/submit_try
@@ -0,0 +1,266 @@
+#!/usr/bin/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.
+
+
+"""
+submit_try: Submit a try request.
+
+This is a thin wrapper around the try request utilities in depot_tools which
+adds some validation and supports both git and svn.
+"""
+
+
+import httplib
+import json
+import os
+import subprocess
+import sys
+
+
+# Alias which can be used to run a try on every builder.
+ALL_BUILDERS = 'all'
+
+# Contact information for the build master.
+# TODO(borenet): Share this information from a single location. Filed bug:
+# http://code.google.com/p/skia/issues/detail?id=1081
+SKIA_BUILD_MASTER_HOST = '70.32.156.51'
+SKIA_BUILD_MASTER_PORT = '10117'
+
+# All try builders have this suffix.
+TRYBOT_SUFFIX = '_Trybot'
+
+# Location of the codereview.settings file in the Skia repo.
+SKIA_URL = 'skia.googlecode.com'
+CODEREVIEW_SETTINGS = '/svn/codereview.settings'
+
+# String for matching the svn url of the try server inside codereview.settings.
+TRYSERVER_SVN_URL = 'TRYSERVER_SVN_URL: '
+
+# Strings used for matching svn config properties.
+URL_STR = 'URL: '
+REPO_ROOT_STR = 'Repository Root: '
+
+
+def FindDepotTools():
+ """ Find depot_tools on the local machine and return its location. """
+ which_cmd = 'where' if os.name == 'nt' else 'which'
+ cmd = [which_cmd, 'gcl']
+ proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
+ if proc.wait() != 0:
+ raise Exception('Couldn\'t find depot_tools in PATH!')
+ gcl = proc.communicate()[0].split('\n')[0].rstrip()
+ depot_tools_dir = os.path.dirname(gcl)
+ return depot_tools_dir
+
+
+def GetCheckoutRoot(is_svn=True):
+ """ Determine where the local checkout is rooted.
+
+ is_svn: boolean; whether we're in an SVN checkout. If False, assume we're in
+ a git checkout.
+ """
+ if is_svn:
+ svn_cmd = 'svn.bat' if os.name == 'nt' else 'svn'
+ cmd = [svn_cmd, 'info']
+ proc = subprocess.Popen(cmd, stdout=subprocess.PIPE,
+ stderr=subprocess.STDOUT)
+ if proc.wait() != 0:
+ raise Exception('Couldn\'t find checkout root!')
+ output = proc.communicate()[0].split('\n')
+ url = None
+ repo_root = None
+ for line in output:
+ if line.startswith(REPO_ROOT_STR):
+ repo_root = line[len(REPO_ROOT_STR):].rstrip()
+ elif line.startswith(URL_STR):
+ url = line[len(URL_STR):].rstrip()
+ if not url or not repo_root:
+ raise Exception('Couldn\'t find checkout root!')
+ if url == repo_root:
+ return 'svn'
+ return url[len(repo_root)+1:]
+ else:
+ cmd = ['git', 'rev-parse', '--show-toplevel']
+ proc = subprocess.Popen(cmd, stdout=subprocess.PIPE,
+ stderr=subprocess.STDOUT)
+ if proc.wait() != 0:
+ raise Exception('Couldn\'t find checkout root!')
+ return os.path.basename(proc.communicate()[0])
+
+
+def GetTryRepo():
+ """ Determine the TRYSERVER_SVN_URL from the codereview.settings file in the
+ Skia repo. """
+ connection = httplib.HTTPConnection(SKIA_URL)
+ connection.request('GET', CODEREVIEW_SETTINGS)
+ content = connection.getresponse().read()
+ for line in content.split('\n'):
+ if line.startswith(TRYSERVER_SVN_URL):
+ return line[len(TRYSERVER_SVN_URL):].rstrip()
+ raise Exception('Couldn\'t determine the TRYSERVER_SVN_URL. Make sure it is '
+ 'defined in the %s file.' % CODEREVIEW_SETTINGS)
+
+
+def RetrieveTrybotList():
+ """ Retrieve the list of known trybots from the build master, stripping
+ TRYBOT_SUFFIX from the name. """
+ trybots = []
+ connection = httplib.HTTPConnection(SKIA_BUILD_MASTER_HOST,
+ SKIA_BUILD_MASTER_PORT)
+ connection.request('GET', '/json/builders')
+ response = connection.getresponse()
+ builders = json.load(response)
+
+ for builder in builders:
+ if builder.endswith(TRYBOT_SUFFIX):
+ trybots.append(builder[:-len(TRYBOT_SUFFIX)])
+ return trybots
+
+
+def ValidateArgs(argv, trybots, is_svn=True):
+ """ Parse and validate command-line arguments. If the arguments are valid,
+ returns a tuple of (<changelist name>, <list of trybots>).
+
+ trybots: A list of the known try builders.
+ """
+
+ class CollectedArgs(object):
+ def __init__(self, bots, changelist, revision):
+ self._bots = bots
+ self._changelist = changelist
+ self._revision = revision
+
+ @property
+ def bots(self):
+ for bot in self._bots:
+ yield bot
+
+ @property
+ def changelist(self):
+ return self._changelist
+
+ @property
+ def revision(self):
+ return self._revision
+
+ usage = (
+"""submit_try: Submit a try request.
+submit_try %s--bot <buildername> [<buildername> ...]
+
+--bot Builder on which to run the try. Required.
+-h, --help Show this message.
+-r <revision#> Revision from which to run the try.
+-l, --list_bots List the available try builders and exit.
+""" % ('<changelist> ' if is_svn else ''))
+
+ def Error(msg=None):
+ if msg:
+ print msg
+ print usage
+ sys.exit(1)
+
+ using_bots = None
+ changelist = None
+ revision = None
+
+ while argv:
+ arg = argv.pop(0)
+ if arg == '-h' or arg == '--help':
+ Error()
+ elif arg == '-l' or arg == '--list_bots':
+ print 'submit_try: Available builders:\n %s' % '\n '.join(trybots)
+ sys.exit(0)
+ elif arg == '--bot':
+ if using_bots:
+ Error('--bot specified multiple times.')
+ if len(argv) < 1:
+ Error('You must specify a builder with "--bot".')
+ using_bots = []
+ while argv and not argv[0].startswith('-'):
+ bot = argv.pop(0)
+ if bot == ALL_BUILDERS:
+ if using_bots:
+ Error('Cannot specify "all" with additional builder names.')
+ using_bots = trybots
+ break
+ else:
+ if not bot in trybots:
+ Error('Unrecognized builder: %s' % bot)
+ using_bots.append(bot)
+ elif arg == '-r':
+ if len(argv) < 1:
+ Error('You must specify a revision with "-r".')
+ revision = argv.pop(0)
+ else:
+ if changelist or not is_svn:
+ Error('Unknown argument: %s' % arg)
+ changelist = arg
+ if is_svn and not changelist:
+ Error('You must specify a changelist name.')
+ if not using_bots:
+ Error('You must specify one or more builders using --bot.')
+ return CollectedArgs(bots=using_bots, changelist=changelist,
+ revision=revision)
+
+
+def SubmitTryRequest(args, is_svn=True):
+ """ Submits a try request for the given changelist on the given list of
+ trybots.
+
+ args: Object whose properties are derived from command-line arguments. If
+ is_svn is True, it should contain:
+ - changelist: string; the name of the changelist to try.
+ - bot: list of strings; the names of the try builders to run.
+ - revision: optional, int; the revision number from which to run the try.
+ If is_svn is False, it should contain:
+ - bot: list of strings; the names of the try builders to run.
+ - revision: optional, int; the revision number from which to run the try.
+ is_svn: boolean; are we in an SVN repo?
+ """
+ botlist = ','.join(['%s%s' % (bot, TRYBOT_SUFFIX) for bot in args.bots])
+ if is_svn:
+ gcl_cmd = 'gcl.bat' if os.name == 'nt' else 'gcl'
+ try_args = [gcl_cmd, 'try', args.changelist,
+ '--root', GetCheckoutRoot(is_svn),
+ '--bot', botlist]
+ if args.revision:
+ try_args.extend(['-r', args.revision])
+ print ' '.join(try_args)
+ proc = subprocess.Popen(try_args, stdout=subprocess.PIPE,
+ stderr=subprocess.STDOUT)
+ if proc.wait() != 0:
+ raise Exception('Failed to submit try request: %s' % (
+ proc.communicate()[0]))
+ print proc.communicate()[0]
+ else:
+ # First, find depot_tools. This is needed to import trychange.
+ sys.path.append(FindDepotTools())
+ import trychange
+ try_args = ['--use_svn',
+ '--svn_repo', GetTryRepo(),
+ '--root', GetCheckoutRoot(is_svn),
+ '--bot', botlist]
+ if args.revision:
+ try_args.extend(['-r', args.revision])
+ trychange.TryChange(try_args, None, False)
+
+
+def main():
+ # Retrieve the list of active try builders from the build master.
+ trybots = RetrieveTrybotList()
+
+ # Determine if we're in an SVN checkout.
+ is_svn = os.path.isdir('.svn')
+
+ # Parse and validate the command-line arguments.
+ args = ValidateArgs(sys.argv[1:], trybots=trybots, is_svn=is_svn)
+
+ # Submit the try request.
+ SubmitTryRequest(args, is_svn=is_svn)
+
+
+if __name__ == '__main__':
+ sys.exit(main())
\ No newline at end of file
diff --git a/tools/submit_try.bat b/tools/submit_try.bat
new file mode 100644
index 0000000..d1d5392
--- /dev/null
+++ b/tools/submit_try.bat
@@ -0,0 +1 @@
+python tools\submit_try %*
\ No newline at end of file
diff --git a/tools/tests/bench_pictures_cfg_test.py b/tools/tests/bench_pictures_cfg_test.py
index 77ad553..9b0e0ac 100644
--- a/tools/tests/bench_pictures_cfg_test.py
+++ b/tools/tests/bench_pictures_cfg_test.py
@@ -39,7 +39,7 @@
if type(value).__name__ == 'list':
for item in value:
ThrowIfNotAString(item)
- else:
+ elif not value is True:
ThrowIfNotAString(value)
if __name__ == '__main__':
diff --git a/tools/tests/rebaseline.sh b/tools/tests/rebaseline.sh
new file mode 100755
index 0000000..eee8db8
--- /dev/null
+++ b/tools/tests/rebaseline.sh
@@ -0,0 +1,73 @@
+#!/bin/bash
+
+# Rebaseline the skdiff/*/output-expected/ subdirectories used by the skdiff
+# self-tests.
+# Use with caution: are you sure the new results are actually correct?
+#
+# YOU MUST RE-RUN THIS UNTIL THE SELF-TESTS SUCCEED!
+#
+# TODO: currently, this must be run on Linux to generate baselines that match
+# the ones on the housekeeper bot (which runs on Linux... see
+# http://70.32.156.51:10117/builders/Skia_PerCommit_House_Keeping/builds/1417/steps/RunGmSelfTests/logs/stdio )
+# See https://code.google.com/p/skia/issues/detail?id=677
+# ('make tools/tests/run.sh work cross-platform')
+
+function replace_expected_with_actual {
+ # Delete all the expected output files
+ EXPECTED_FILES=$(find skdiff/*/output-expected -type f | grep -v /\.svn/)
+ for EXPECTED_FILE in $EXPECTED_FILES; do
+ rm $EXPECTED_FILE
+ done
+
+ # Copy all the actual output files into the "expected" directories,
+ # creating new subdirs as we go.
+ ACTUAL_FILES=$(find skdiff/*/output-actual -type f | grep -v /\.svn/)
+ for ACTUAL_FILE in $ACTUAL_FILES; do
+ EXPECTED_FILE=${ACTUAL_FILE//actual/expected}
+ mkdir -p $(dirname $EXPECTED_FILE)
+ cp $ACTUAL_FILE $EXPECTED_FILE
+ done
+}
+
+function svn_add_new_files {
+ # Delete all the "actual" directories, so we can svn-add any new "expected"
+ # directories without adding the "actual" ones.
+ rm -rf skdiff/*/output-actual
+ FILES=$(svn stat skdiff/* | grep ^\? | awk '{print $2}')
+ for FILE in $FILES; do
+ svn add $FILE
+ done
+ FILES=$(svn stat skdiff/*/output-expected | grep ^\? | awk '{print $2}')
+ for FILE in $FILES; do
+ svn add $FILE
+ done
+}
+
+function svn_delete_old_files {
+ FILES=$(svn stat skdiff/*/output-expected | grep ^\! | awk '{print $2}')
+ for FILE in $FILES; do
+ svn rm $FILE
+ done
+ FILES=$(svn stat skdiff/* | grep ^\! | awk '{print $2}')
+ for FILE in $FILES; do
+ svn rm $FILE
+ done
+}
+
+
+# cd into the gm self-test dir
+cd $(dirname $0)
+
+./run.sh
+SELFTEST_RESULT=$?
+echo
+if [ "$SELFTEST_RESULT" != "0" ]; then
+ replace_expected_with_actual
+ echo "Self-tests still failing, you should probably run this again..."
+else
+ svn_add_new_files
+ svn_delete_old_files
+ echo "Self-tests succeeded this time, you should be done!"
+fi
+exit $SELFTEST_RESULT
+
diff --git a/tools/tests/run.sh b/tools/tests/run.sh
index 1acb124..7731805 100755
--- a/tools/tests/run.sh
+++ b/tools/tests/run.sh
@@ -1,7 +1,17 @@
#!/bin/bash
# Tests for our tools.
+#
# TODO: for now, it only tests skdiff
+#
+# TODO: currently, this only passes on Linux (which is the platform that
+# the housekeeper bot runs on, e.g.
+# http://70.32.156.51:10117/builders/Skia_PerCommit_House_Keeping/builds/1415/steps/RunToolSelfTests/logs/stdio )
+# See https://code.google.com/p/skia/issues/detail?id=677
+# ('make tools/tests/run.sh work cross-platform')
+# Ideally, these tests should pass on all development platforms...
+# otherwise, how can developers be expected to test them before committing a
+# change?
# cd into .../trunk so all the paths will work
cd $(dirname $0)/../..
diff --git a/tools/tests/skdiff/test1/output-expected/index.html b/tools/tests/skdiff/test1/output-expected/index.html
index a3e192e..4bf8eee 100644
--- a/tools/tests/skdiff/test1/output-expected/index.html
+++ b/tools/tests/skdiff/test1/output-expected/index.html
@@ -39,10 +39,10 @@
<td><input type="checkbox" name="different-bits/very-different-sizes.png" checked="yes"></td><td><b>different-bits/very-different-sizes.png</b><br>Image sizes differ</td><td>N/A</td><td>N/A</td><td><a href="../../../../../tools/tests/skdiff/baseDir/different-bits/very-different-sizes.png"><img src="../../../../../tools/tests/skdiff/baseDir/different-bits/very-different-sizes.png" height="240px"></a></td><td><a href="../../../../../tools/tests/skdiff/comparisonDir/different-bits/very-different-sizes.png"><img src="../../../../../tools/tests/skdiff/comparisonDir/different-bits/very-different-sizes.png" height="128px"></a></td></tr>
<tr>
<td><input type="checkbox" name="different-bits/very-different-pixels-same-size.png" checked="yes"></td><td><b>different-bits/very-different-pixels-same-size.png</b><br>97.9926% of pixels differ
- (42.8911% weighted)<br>Average color mismatch 89<br>Max color mismatch 239</td><td><a href="different-bits_very-different-pixels-same-size-white.png"><img src="different-bits_very-different-pixels-same-size-white.png" height="240px"></a></td><td><a href="different-bits_very-different-pixels-same-size-diff.png"><img src="different-bits_very-different-pixels-same-size-diff.png" height="240px"></a></td><td><a href="../../../../../tools/tests/skdiff/baseDir/different-bits/very-different-pixels-same-size.png"><img src="../../../../../tools/tests/skdiff/baseDir/different-bits/very-different-pixels-same-size.png" height="240px"></a></td><td><a href="../../../../../tools/tests/skdiff/comparisonDir/different-bits/very-different-pixels-same-size.png"><img src="../../../../../tools/tests/skdiff/comparisonDir/different-bits/very-different-pixels-same-size.png" height="240px"></a></td></tr>
+ (42.8911% weighted)<br><br>Max alpha channel mismatch 0<br>Total alpha channel mismatch 0<br><br>Average color mismatch 89<br>Max color mismatch 239</td><td><a href="different-bits_very-different-pixels-same-size-white.png"><img src="different-bits_very-different-pixels-same-size-white.png" height="240px"></a></td><td><a href="different-bits_very-different-pixels-same-size-diff.png"><img src="different-bits_very-different-pixels-same-size-diff.png" height="240px"></a></td><td><a href="../../../../../tools/tests/skdiff/baseDir/different-bits/very-different-pixels-same-size.png"><img src="../../../../../tools/tests/skdiff/baseDir/different-bits/very-different-pixels-same-size.png" height="240px"></a></td><td><a href="../../../../../tools/tests/skdiff/comparisonDir/different-bits/very-different-pixels-same-size.png"><img src="../../../../../tools/tests/skdiff/comparisonDir/different-bits/very-different-pixels-same-size.png" height="240px"></a></td></tr>
<tr>
<td><input type="checkbox" name="different-bits/slightly-different-pixels-same-size.png" checked="yes"></td><td><b>different-bits/slightly-different-pixels-same-size.png</b><br>0.6630% of pixels differ
- (0.1904% weighted)<br>(2164 pixels)<br>Average color mismatch 0<br>Max color mismatch 213</td><td><a href="different-bits_slightly-different-pixels-same-size-white.png"><img src="different-bits_slightly-different-pixels-same-size-white.png" height="240px"></a></td><td><a href="different-bits_slightly-different-pixels-same-size-diff.png"><img src="different-bits_slightly-different-pixels-same-size-diff.png" height="240px"></a></td><td><a href="../../../../../tools/tests/skdiff/baseDir/different-bits/slightly-different-pixels-same-size.png"><img src="../../../../../tools/tests/skdiff/baseDir/different-bits/slightly-different-pixels-same-size.png" height="240px"></a></td><td><a href="../../../../../tools/tests/skdiff/comparisonDir/different-bits/slightly-different-pixels-same-size.png"><img src="../../../../../tools/tests/skdiff/comparisonDir/different-bits/slightly-different-pixels-same-size.png" height="240px"></a></td></tr>
+ (0.1904% weighted)<br>(2164 pixels)<br><br>Max alpha channel mismatch 0<br>Total alpha channel mismatch 0<br><br>Average color mismatch 0<br>Max color mismatch 213</td><td><a href="different-bits_slightly-different-pixels-same-size-white.png"><img src="different-bits_slightly-different-pixels-same-size-white.png" height="240px"></a></td><td><a href="different-bits_slightly-different-pixels-same-size-diff.png"><img src="different-bits_slightly-different-pixels-same-size-diff.png" height="240px"></a></td><td><a href="../../../../../tools/tests/skdiff/baseDir/different-bits/slightly-different-pixels-same-size.png"><img src="../../../../../tools/tests/skdiff/baseDir/different-bits/slightly-different-pixels-same-size.png" height="240px"></a></td><td><a href="../../../../../tools/tests/skdiff/comparisonDir/different-bits/slightly-different-pixels-same-size.png"><img src="../../../../../tools/tests/skdiff/comparisonDir/different-bits/slightly-different-pixels-same-size.png" height="240px"></a></td></tr>
</table>
<input type="button" onclick="generateCheckedList()" value="Create Rebaseline List">
<div id="checkedList"></div>