'<(skia_src_path)/core/SkEdgeClipper.cpp',
'<(skia_src_path)/core/SkEdge.cpp',
'<(skia_src_path)/core/SkEdge.h',
+ '<(skia_src_path)/core/SkError.cpp',
+ '<(skia_src_path)/core/SkErrorInternals.h',
'<(skia_src_path)/core/SkFDStream.cpp',
'<(skia_src_path)/core/SkFP.h',
'<(skia_src_path)/core/SkFilterProc.cpp',
'<(skia_include_path)/core/SkDrawFilter.h',
'<(skia_include_path)/core/SkDrawLooper.h',
'<(skia_include_path)/core/SkEndian.h',
+ '<(skia_include_path)/core/SkError.h',
'<(skia_include_path)/core/SkFixed.h',
'<(skia_include_path)/core/SkFlattenable.h',
'<(skia_include_path)/core/SkFloatBits.h',
'../tests/DrawPathTest.cpp',
'../tests/DrawTextTest.cpp',
'../tests/EmptyPathTest.cpp',
+ '../tests/ErrorTest.cpp',
'../tests/FillPathTest.cpp',
'../tests/FlatDataTest.cpp',
'../tests/FlateTest.cpp',
--- /dev/null
+/*
+ * Copyright 2013 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef SkError_DEFINED
+#define SkError_DEFINED
+
+
+/** \file SkError.h
+*/
+
+enum SkError {
+ /** All is well
+ */
+ kNoError_SkError=0,
+
+ /** User argument passed to Skia function was invalid: NULL when that’s
+ * not allowed, out of numeric range, bad enum, or violating some
+ * other general precondition.
+ */
+ kInvalidArgument_SkError,
+
+ /** User tried to perform some operation in a state when the operation
+ * was not legal, or the operands make no sense (e.g., asking for
+ * pixels from an SkPictureCanvas). Other examples might be
+ * inset()’ing a rectangle to make it degenerate (negative width/height).
+ */
+ kInvalidOperation_SkError,
+
+ /** Probably not needed right now, but in the future we could have opaque
+ * handles for SkPictures floating around, and it would be a good idea
+ * to anticipate this kind of issue.
+ */
+ kInvalidHandle_SkError,
+
+ /** This is probably not possible because paint surely has defaults for
+ * everything, but perhaps a paint can get into a bad state somehow.
+ */
+ kInvalidPaint_SkError,
+
+ /** Skia was unable to allocate memory to perform some task.
+ */
+ kOutOfMemory_SkError,
+
+ /** Skia failed while trying to consume some external resource.
+ */
+ kParseError_SkError
+};
+
+/** Return the current per-thread error code. Error codes are "sticky"; they
+ * are not not reset by subsequent successful operations.
+ */
+SkError SkGetLastError();
+
+/** Clear the current per-thread error code back to kNoError_SkError.
+ */
+void SkClearLastError();
+
+/** Type for callback functions to be invoked whenever an error is registered.
+ * Callback functions take the error code being set, as well as a context
+ * argument that is provided when the callback is registered.
+ */
+typedef void (*SkErrorCallbackFunction)(SkError, void *);
+
+/** Set the current per-thread error callback.
+ *
+ * @param cb The callback function to be invoked. Passing NULL
+ * for cb will revert to the default error callback which
+ * does nothing on release builds, but on debug builds will
+ * print an informative error message to the screen.
+ * @param context An arbitrary pointer that will be passed to
+ * the provided callback function.
+ */
+void SkSetErrorCallback(SkErrorCallbackFunction cb, void *context);
+
+/** Get a human-readable description of the last (per-thread) error that
+ * occurred. The returned error message will include not only a human
+ * readable version of the error code, but also information about the
+ * conditions that led to the error itself.
+ */
+const char *SkGetLastErrorString();
+
+#endif /* SkError_DEFINED */
--- /dev/null
+
+/*
+ * Copyright 2013 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "SkTLS.h"
+#include "SkTypes.h"
+#include "SkError.h"
+#include "SkErrorInternals.h"
+
+#include <stdio.h>
+#include <stdarg.h>
+
+namespace {
+ void *CreateThreadError() {
+ return SkNEW_ARGS(SkError, (kNoError_SkError));
+ }
+ void DeleteThreadError(void* v) {
+ SkDELETE(reinterpret_cast<SkError*>(v));
+ }
+ #define THREAD_ERROR \
+ (*reinterpret_cast<SkError*>(SkTLS::Get(CreateThreadError, DeleteThreadError)))
+
+ void *CreateThreadErrorCallback() {
+ return SkNEW_ARGS(SkErrorCallbackFunction, (SkErrorInternals::DefaultErrorCallback));
+ }
+ void DeleteThreadErrorCallback(void* v) {
+ SkDELETE(reinterpret_cast<SkErrorCallbackFunction *>(v));
+ }
+
+ #define THREAD_ERROR_CALLBACK \
+ *(reinterpret_cast<SkErrorCallbackFunction *>(SkTLS::Get(CreateThreadErrorCallback, \
+ DeleteThreadErrorCallback)))
+
+ void *CreateThreadErrorContext() {
+ return SkNEW_ARGS(void **, (NULL));
+ }
+ void DeleteThreadErrorContext(void* v) {
+ SkDELETE(reinterpret_cast<void **>(v));
+ }
+ #define THREAD_ERROR_CONTEXT \
+ (*reinterpret_cast<void **>(SkTLS::Get(CreateThreadErrorContext, DeleteThreadErrorContext)))
+
+ #define ERROR_STRING_LENGTH 2048
+
+ void *CreateThreadErrorString() {
+ return SkNEW_ARRAY(char, (ERROR_STRING_LENGTH));
+ }
+ void DeleteThreadErrorString(void* v) {
+ SkDELETE_ARRAY(reinterpret_cast<char *>(v));
+ }
+ #define THREAD_ERROR_STRING \
+ (reinterpret_cast<char *>(SkTLS::Get(CreateThreadErrorString, DeleteThreadErrorString)))
+}
+
+SkError SkGetLastError() {
+ return SkErrorInternals::GetLastError();
+}
+void SkClearLastError() {
+ SkErrorInternals::ClearError();
+}
+void SkSetErrorCallback(SkErrorCallbackFunction cb, void *context) {
+ SkErrorInternals::SetErrorCallback(cb, context);
+}
+const char *SkGetLastErrorString() {
+ return SkErrorInternals::GetLastErrorString();
+}
+
+// ------------ Private Error functions ---------
+
+void SkErrorInternals::SetErrorCallback(SkErrorCallbackFunction cb, void *context) {
+ if (cb == NULL) {
+ THREAD_ERROR_CALLBACK = SkErrorInternals::DefaultErrorCallback;
+ } else {
+ THREAD_ERROR_CALLBACK = cb;
+ }
+ THREAD_ERROR_CONTEXT = context;
+}
+
+void SkErrorInternals::DefaultErrorCallback(SkError code, void *context) {
+ SkDebugf("Skia Error: %s\n", SkGetLastErrorString());
+}
+
+void SkErrorInternals::ClearError() {
+ SkErrorInternals::SetError( kNoError_SkError, "All is well" );
+}
+
+SkError SkErrorInternals::GetLastError() {
+ return THREAD_ERROR;
+}
+
+const char *SkErrorInternals::GetLastErrorString() {
+ return THREAD_ERROR_STRING;
+}
+
+void SkErrorInternals::SetError(SkError code, const char *fmt, ...) {
+ THREAD_ERROR = code;
+ va_list args;
+
+ char *str = THREAD_ERROR_STRING;
+ const char *error_name = NULL;
+ switch( code ) {
+ case kNoError_SkError:
+ error_name = "No Error";
+ break;
+ case kInvalidArgument_SkError:
+ error_name = "Invalid Argument";
+ break;
+ case kInvalidOperation_SkError:
+ error_name = "Invalid Operation";
+ break;
+ case kInvalidHandle_SkError:
+ error_name = "Invalid Handle";
+ break;
+ case kInvalidPaint_SkError:
+ error_name = "Invalid Paint";
+ break;
+ case kOutOfMemory_SkError:
+ error_name = "Out Of Memory";
+ break;
+ case kParseError_SkError:
+ error_name = "Parse Error";
+ break;
+ default:
+ error_name = "Unknown error";
+ break;
+ }
+
+ sprintf( str, "%s: ", error_name );
+ int string_left = ERROR_STRING_LENGTH - strlen( str );
+ str += strlen(str);
+
+ va_start( args, fmt );
+ vsnprintf( str, string_left, fmt, args );
+ va_end( args );
+ SkErrorCallbackFunction fn = THREAD_ERROR_CALLBACK;
+ if (fn && code != kNoError_SkError) {
+ fn(code, THREAD_ERROR_CONTEXT);
+ }
+}
--- /dev/null
+
+/*
+ * Copyright 2013 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef SkErrorInternals_DEFINED
+#define SkErrorInternals_DEFINED
+
+#include "SkError.h"
+
+class SkErrorInternals {
+
+public:
+ static void ClearError();
+ static void SetError(SkError code, const char *fmt, ...);
+ static SkError GetLastError();
+ static const char *GetLastErrorString();
+ static void SetErrorCallback(SkErrorCallbackFunction cb, void *context);
+ static void DefaultErrorCallback(SkError code, void *context);
+};
+
+
+
+#endif /* SkErrorInternals_DEFINED */
*/
-#include "SkPath.h"
#include "SkBuffer.h"
+#include "SkErrorInternals.h"
#include "SkMath.h"
+#include "SkPath.h"
#include "SkPathRef.h"
#include "SkRRect.h"
#include "SkThread.h"
void SkPath::addRoundRect(const SkRect& rect, SkScalar rx, SkScalar ry,
Direction dir) {
assert_known_direction(dir);
+
+ if (rx < 0 || ry < 0) {
+ SkErrorInternals::SetError( kInvalidArgument_SkError,
+ "I got %f and %f as radii to SkPath::AddRoundRect, "
+ "but negative radii are not allowed.",
+ SkScalarToDouble(rx), SkScalarToDouble(ry) );
+ return;
+ }
SkScalar w = rect.width();
SkScalar halfW = SkScalarHalf(w);
--- /dev/null
+
+/*
+ * Copyright 2013 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+#include "Test.h"
+#include "SkError.h"
+#include "SkPath.h"
+#include "SkRect.h"
+
+#define CHECK(errcode) \
+ REPORTER_ASSERT( reporter, (err = SkGetLastError()) == errcode); \
+ if (err != kNoError_SkError) \
+ { \
+ SkDebugf("Last error string: %s\n", SkGetLastErrorString()); \
+ SkClearLastError(); \
+ }
+
+void cb(SkError err, void *context) {
+ int *context_ptr = static_cast<int *>(context);
+ SkDebugf("CB (0x%x): %s\n", *context_ptr, SkGetLastErrorString());
+}
+
+static void ErrorTest(skiatest::Reporter* reporter) {
+ SkError err;
+
+ CHECK(kNoError_SkError);
+
+ SkRect r = SkRect::MakeWH(50, 100);
+ CHECK(kNoError_SkError);
+
+ SkPath path;
+ path.addRect(r);
+ CHECK(kNoError_SkError);
+
+ path.addRoundRect(r, 10, 10);
+ CHECK(kNoError_SkError);
+
+ // should trigger the default error callback, which just prints to the screen.
+ path.addRoundRect(r, -10, -10);
+ CHECK(kInvalidArgument_SkError);
+ CHECK(kNoError_SkError);
+
+ int test_value = 0xdeadbeef;
+ SkSetErrorCallback(cb, &test_value);
+
+ // should trigger *our* callback.
+ path.addRoundRect(r, -10, -10);
+ CHECK(kInvalidArgument_SkError);
+ CHECK(kNoError_SkError);
+
+ // Should trigger the default one again.
+ SkSetErrorCallback(NULL, NULL);
+ path.addRoundRect(r, -10, -10);
+ CHECK(kInvalidArgument_SkError);
+ CHECK(kNoError_SkError);
+}
+
+#include "TestClassDef.h"
+DEFINE_TESTCLASS("Error", ErrorTestClass, ErrorTest)