From f56e295e88f4ed42f4c94c54d5fc544ed0f45f18 Mon Sep 17 00:00:00 2001 From: "reed@android.com" Date: Sat, 29 Aug 2009 21:30:25 +0000 Subject: [PATCH] experimental hack to write a forth engine to drive skia git-svn-id: http://skia.googlecode.com/svn/trunk@343 2bbb7eff-a529-9590-31e7-b0007b416f81 --- forth/Forth.cpp | 682 +++++++++++++++++++++ forth/Forth.h | 98 +++ forth/SampleForth.cpp | 248 ++++++++ .../sampleapp/SampleApp.xcodeproj/project.pbxproj | 10 + 4 files changed, 1038 insertions(+) create mode 100644 forth/Forth.cpp create mode 100644 forth/Forth.h create mode 100644 forth/SampleForth.cpp diff --git a/forth/Forth.cpp b/forth/Forth.cpp new file mode 100644 index 0000000..722ed08 --- /dev/null +++ b/forth/Forth.cpp @@ -0,0 +1,682 @@ +#include "Forth.h" +#include "SkTDArray.h" +#include "SkTDict.h" +#include "SkString.h" + +ForthEngine::ForthEngine(ForthOutput* output) : fOutput(output) { + size_t size = 32 * sizeof(intptr_t); + fStackBase = reinterpret_cast(sk_malloc_throw(size)); + fStackStop = fStackBase + size/sizeof(intptr_t); + fStackCurr = fStackStop; +} + +ForthEngine::~ForthEngine() { + sk_free(fStackBase); +} + +void ForthEngine::sendOutput(const char text[]) { + if (fOutput) { + fOutput->show(text); + } else { + SkDebugf("%s", text); + } +} + +///////////////// ints + +void ForthEngine::push(intptr_t value) { + if (fStackCurr > fStackBase) { + SkASSERT(fStackCurr <= fStackStop && fStackCurr > fStackBase); + *--fStackCurr = value; + } else { + this->signal_error("overflow"); + } +} + +intptr_t ForthEngine::peek(size_t index) const { + SkASSERT(fStackCurr < fStackStop && fStackCurr >= fStackBase); + if (fStackCurr + index < fStackStop) { + return fStackCurr[index]; + } else { + this->signal_error("peek out of range"); + return 0x80000001; + } +} + +void ForthEngine::setTop(intptr_t value) { + if (fStackCurr < fStackStop) { + SkASSERT(fStackCurr < fStackStop && fStackCurr >= fStackBase); + *fStackCurr = value; + } else { + this->signal_error("underflow"); + } +} + +intptr_t ForthEngine::pop() { + if (fStackCurr < fStackStop) { + SkASSERT(fStackCurr < fStackStop && fStackCurr >= fStackBase); + return *fStackCurr++; + } else { + this->signal_error("underflow"); + return 0x80000001; + } +} + +/////////////////////////////////////////////////////////////////////////////// + +void ForthWord::call(ForthCallBlock* block) { + ForthEngine engine(NULL); + if (block) { + // walk the array backwards, so that the top of the stack is data[0] + for (size_t i = 0; i < block->in_count; i++) { + engine.push(block->in_data[i]); + } + } + this->exec(&engine); + if (block) { + size_t n = engine.depth(); + block->out_depth = n; + if (n > block->out_count) { + n = block->out_count; + } + for (size_t i = 0; i < n; i++) { + block->out_data[i] = engine.peek(i); + } + } +} + +/////////////////////////////////////////////////////////////////////////////// + +class drop_ForthWord : public ForthWord { +public: + virtual void exec(ForthEngine* fe) { + (void)fe->pop(); + } +}; + +class clearStack_ForthWord : public ForthWord { +public: + virtual void exec(ForthEngine* fe) { + fe->clearStack(); + } +}; + +class dup_ForthWord : public ForthWord { +public: + virtual void exec(ForthEngine* fe) { + fe->push(fe->top()); + } +}; + +class swap_ForthWord : public ForthWord { +public: + virtual void exec(ForthEngine* fe) { + int32_t a = fe->pop(); + int32_t b = fe->top(); + fe->setTop(a); + fe->push(b); + } +}; + +///////////////// ints + +class add_ForthWord : public ForthWord { +public: + virtual void exec(ForthEngine* fe) { + intptr_t tmp = fe->pop(); + fe->setTop(fe->top() + tmp); + } +}; + +class sub_ForthWord : public ForthWord { +public: + virtual void exec(ForthEngine* fe) { + intptr_t tmp = fe->pop(); + fe->setTop(fe->top() - tmp); + } +}; + +class mul_ForthWord : public ForthWord { +public: + virtual void exec(ForthEngine* fe) { + intptr_t tmp = fe->pop(); + fe->setTop(fe->top() * tmp); + } +}; + +class div_ForthWord : public ForthWord { +public: + virtual void exec(ForthEngine* fe) { + intptr_t tmp = fe->pop(); + fe->setTop(fe->top() / tmp); + } +}; + +class dot_ForthWord : public ForthWord { +public: + virtual void exec(ForthEngine* fe) { + SkString str; + str.printf("%d ", fe->pop()); + fe->sendOutput(str.c_str()); + } +}; + +class abs_ForthWord : public ForthWord { +public: + virtual void exec(ForthEngine* fe) { + int32_t value = fe->top(); + if (value < 0) { + fe->setTop(-value); + } + } +}; + +class min_ForthWord : public ForthWord { +public: + virtual void exec(ForthEngine* fe) { + int32_t value = fe->pop(); + if (value < fe->top()) { + fe->setTop(value); + } + } +}; + +class max_ForthWord : public ForthWord { +public: + virtual void exec(ForthEngine* fe) { + int32_t value = fe->pop(); + if (value > fe->top()) { + fe->setTop(value); + } + } +}; + +///////////////// floats + +class fadd_ForthWord : public ForthWord { +public: + virtual void exec(ForthEngine* fe) { + float tmp = fe->fpop(); + fe->fsetTop(fe->ftop() + tmp); + } +}; + +class fsub_ForthWord : public ForthWord { +public: + virtual void exec(ForthEngine* fe) { + float tmp = fe->fpop(); + fe->fsetTop(fe->ftop() - tmp); + } +}; + +class fmul_ForthWord : public ForthWord { +public: + virtual void exec(ForthEngine* fe) { + float tmp = fe->fpop(); + fe->fsetTop(fe->ftop() * tmp); + } +}; + +class fdiv_ForthWord : public ForthWord { +public: + virtual void exec(ForthEngine* fe) { + float tmp = fe->fpop(); + fe->fsetTop(fe->ftop() / tmp); + } +}; + +class fdot_ForthWord : public ForthWord { +public: + virtual void exec(ForthEngine* fe) { + SkString str; + str.printf("%g ", fe->fpop()); + fe->sendOutput(str.c_str()); + } +}; + +class fabs_ForthWord : public ForthWord { +public: + virtual void exec(ForthEngine* fe) { + float value = fe->ftop(); + if (value < 0) { + fe->fsetTop(-value); + } + } +}; + +class fmin_ForthWord : public ForthWord { +public: + virtual void exec(ForthEngine* fe) { + float value = fe->fpop(); + if (value < fe->ftop()) { + fe->fsetTop(value); + } + } +}; + +class fmax_ForthWord : public ForthWord { +public: + virtual void exec(ForthEngine* fe) { + float value = fe->fpop(); + if (value > fe->ftop()) { + fe->fsetTop(value); + } + } +}; + +class floor_ForthWord : public ForthWord { +public: + virtual void exec(ForthEngine* fe) { + fe->fsetTop(floorf(fe->ftop())); + } +}; + +class ceil_ForthWord : public ForthWord { +public: + virtual void exec(ForthEngine* fe) { + fe->fsetTop(ceilf(fe->ftop())); + } +}; + +class round_ForthWord : public ForthWord { +public: + virtual void exec(ForthEngine* fe) { + fe->fsetTop(floorf(fe->ftop() + 0.5f)); + } +}; + +class f2i_ForthWord : public ForthWord { +public: + virtual void exec(ForthEngine* fe) { + fe->setTop((int)fe->ftop()); + } +}; + +class i2f_ForthWord : public ForthWord { +public: + virtual void exec(ForthEngine* fe) { + fe->fsetTop((float)fe->top()); + } +}; + +/////////////////////////////////////////////////////////////////////////////// + +/* + reading an initial 32bit value from the code stream: + + xxxxxxxx xxxxxxxx xxxxxxxx xxxxxx00 + + Those last two bits are always 0 for a word, so we set those bits for other + opcodes + + 00 -- execute this word + 01 -- push (value & ~3) on the data stack + 10 -- push value >> 2 on the data stack (sign extended) + 11 -- switch (value >>> 2) for Code + */ + +class FCode { +public: + enum Bits { + kWord_Bits = 0, // must be zero for function address + kDataClear2_Bits = 1, + kDataShift2_Bits = 2, + kCodeShift2_Bits = 3 + }; + enum Code { + kPushInt_Code, + kDone_Code + }; + + void appendInt(int32_t); + void appendWord(ForthWord*); + void appendIF() {} + bool appendELSE() { return false; } + bool appendTHEN() { return false; } + void done(); + + intptr_t* detach() { + this->done(); + return fData.detach(); + } + intptr_t* begin() { + this->done(); + return fData.begin(); + } + + static void Exec(const intptr_t*, ForthEngine*); + +private: + SkTDArray fData; +}; + +void FCode::appendInt(int32_t value) { + if ((value & 3) == 0) { + *fData.append() = value | kDataClear2_Bits; + } else if ((value >> 2 << 2) == value) { + *fData.append() = value | kDataShift2_Bits; + } else { + intptr_t* p = fData.append(2); + *p++ = (kPushInt_Code << 2) | kCodeShift2_Bits; + *p++ = value; + } +} + +void FCode::appendWord(ForthWord* word) { + SkASSERT((reinterpret_cast(word) & 3) == 0); + *fData.append() = reinterpret_cast(word); +} + +void FCode::done() { + *fData.append() = (kDone_Code << 2) | kCodeShift2_Bits; +} + +void FCode::Exec(const intptr_t* curr, ForthEngine* engine) { + for (;;) { + intptr_t c = *curr++; + switch (c & 3) { + case kWord_Bits: + reinterpret_cast(c)->exec(engine); + break; + case kDataClear2_Bits: + engine->push(c & ~3); + break; + case kDataShift2_Bits: + engine->push(c >> 2); + break; + case kCodeShift2_Bits: + switch ((uint32_t)c >> 2) { + case kPushInt_Code: + engine->push(*curr++); + break; + case kDone_Code: + return; + } + break; + } + } +} + +/////////////////////////////////////////////////////////////////////////////// + +class CustomWord : public ForthWord { +public: + // we assume ownership of code[] + CustomWord(intptr_t code[]) : fCode(code) {} + virtual ~CustomWord() { sk_free(fCode); } + + virtual void exec(ForthEngine* engine) { + FCode::Exec(fCode, engine); + } + +private: + intptr_t* fCode; +}; + +/////////////////////////////////////////////////////////////////////////////// + +class ForthParser { +public: + ForthParser() : fDict(4096) { + this->addStdWords(); + } + + const char* parse(const char text[], FCode*); + + void addWord(const char name[], ForthWord* word) { + this->add(name, strlen(name), word); + } + + ForthWord* find(const char name[], size_t len) const { + ForthWord* word; + return fDict.find(name, len, &word) ? word : NULL; + } + +private: + void add(const char name[], size_t len, ForthWord* word) { + (void)fDict.set(name, len, word); + } + + void addStdWords() { + this->add("clr", 3, new clearStack_ForthWord); + this->add("drop", 4, new drop_ForthWord); + this->add("dup", 3, new dup_ForthWord); + this->add("swap", 4, new swap_ForthWord); + + this->add("+", 1, new add_ForthWord); + this->add("-", 1, new sub_ForthWord); + this->add("*", 1, new mul_ForthWord); + this->add("/", 1, new div_ForthWord); + this->add(".", 1, new dot_ForthWord); + this->add("abs", 3, new abs_ForthWord); + this->add("min", 3, new min_ForthWord); + this->add("max", 3, new max_ForthWord); + + this->add("f+", 2, new fadd_ForthWord); + this->add("f-", 2, new fsub_ForthWord); + this->add("f*", 2, new fmul_ForthWord); + this->add("f/", 2, new fdiv_ForthWord); + this->add("f.", 2, new fdot_ForthWord); + this->add("fabs", 4, new fabs_ForthWord); + this->add("fmin", 4, new fmin_ForthWord); + this->add("fmax", 4, new fmax_ForthWord); + this->add("fmax", 4, new fmax_ForthWord); + this->add("floor", 5, new floor_ForthWord); + this->add("ceil", 4, new ceil_ForthWord); + this->add("round", 5, new round_ForthWord); + this->add("f>i", 3, new f2i_ForthWord); + this->add("i>f", 3, new i2f_ForthWord); + } + + SkTDict fDict; +}; + +static const char* parse_error(const char msg[]) { + SkDebugf("-- parser error: %s\n", msg); + return NULL; +} + +/** returns true if c is whitespace, including null + */ +static bool is_ws(int c) { + return c <= ' '; +} + +static const char* parse_token(const char** text, size_t* len) { + const char* s = *text; + while (is_ws(*s)) { + if (0 == *s) { + return NULL; + } + s++; + } + const char* token = s++; + while (!is_ws(*s)) { + s++; + } + *text = s; + *len = s - token; + return token; +} + +static bool is_digit(int c) { return (unsigned)(c - '0') <= 9; } +static int hex_val(int c) { + if (is_digit(c)) { + return c - '0'; + } else { + if (c <= 'Z') { + return 10 + c - 'A'; + } else { + return 10 + c - 'a'; + } + } +} + +static bool parse_num(const char str[], size_t len, int32_t* numBits) { + if (1 == len && !is_digit(*str)) { + return false; + } + const char* start = str; + int32_t num = 0; + bool neg = false; + if (*str == '-') { + neg = true; + str += 1; + } else if (*str == '#') { + str++; + while (str - start < len) { + num = num*16 + hex_val(*str); + str += 1; + } + *numBits = num; + return true; + } + + while (is_digit(*str)) { + num = 10*num + *str - '0'; + str += 1; + } + SkASSERT(str - start <= len); + if (str - start == len) { + if (neg) { + num = -num; + } + *numBits = num; + return true; + } + // if we're not done with the token then the next char must be a decimal + if (*str != '.') { + return false; + } + str += 1; + float x = num; + float denom = 1; + while (str - start < len && is_digit(*str)) { + x = 10*x + *str - '0'; + denom *= 10; + str += 1; + } + x /= denom; + if (str - start == len) { + if (neg) { + x = -x; + } + *numBits = f2i_bits(x); + return true; + } + return false; +} + +static const char* parse_comment(const char text[]) { + SkASSERT(*text == '('); + while (')' != *++text) { + if (0 == *text) { + return NULL; + } + } + return text + 1; // skip past the closing ')' +} + +const char* ForthParser::parse(const char text[], FCode* code) { + for (;;) { + size_t len; + const char* token = parse_token(&text, &len); + if (NULL == token) { + break; + } + if (1 == len) { + if ('(' == *token) { + text = parse_comment(token); + if (NULL == text) { + return NULL; + } + continue; + } + if (';' == *token) { + break; + } + if (':' == *token) { + token = parse_token(&text, &len); + if (NULL == token) { + return parse_error("missing name after ':'"); + } + FCode subCode; + text = this->parse(text, &subCode); + if (NULL == text) { + return NULL; + } + this->add(token, len, new CustomWord(subCode.detach())); + continue; + } + } + int32_t num; + if (parse_num(token, len, &num)) { + // note that num is just the bit representation of the float + code->appendInt(num); + } else if (2 == len && memcmp(token, "IF", 2) == 0) { + code->appendIF(); + } else if (2 == len && memcmp(token, "ELSE", 4) == 0) { + if (!code->appendELSE()) { + return parse_error("ELSE with no matching IF"); + } + } else if (2 == len && memcmp(token, "THEN", 4) == 0) { + if (!code->appendTHEN()) { + return parse_error("THEN with no matching IF"); + } + } else{ + ForthWord* word = this->find(token, len); + if (NULL == word) { + SkString str(token, len); + str.prepend("unknown word "); + return parse_error(str.c_str()); + } + code->appendWord(word); + } + } + return text; +} + +/////////////////////////////////////////////////////////////////////////////// + +class ForthEnv::Impl { +public: + ForthParser fParser; + FCode fBuilder; +}; + +ForthEnv::ForthEnv() { + fImpl = new Impl; +} + +ForthEnv::~ForthEnv() { + delete fImpl; +} + +void ForthEnv::addWord(const char name[], ForthWord* word) { + fImpl->fParser.addWord(name, word); +} + +void ForthEnv::parse(const char text[]) { + fImpl->fParser.parse(text, &fImpl->fBuilder); +} + +ForthWord* ForthEnv::findWord(const char name[]) { + return fImpl->fParser.find(name, strlen(name)); +} + +void ForthEnv::run(ForthOutput* output) { + ForthEngine engine(output); + FCode::Exec(fImpl->fBuilder.begin(), &engine); +} + +#if 0 +void ForthEnv::run(const char text[], ForthOutput* output) { + FCode builder; + + if (fImpl->fParser.parse(text, &builder)) { + ForthEngine engine(output); + FCode::Exec(builder.begin(), &engine); + } +} +#endif + diff --git a/forth/Forth.h b/forth/Forth.h new file mode 100644 index 0000000..a68b219 --- /dev/null +++ b/forth/Forth.h @@ -0,0 +1,98 @@ +#ifndef Forth_DEFINED +#define Forth_DEFINED + +#include "SkTypes.h" + +class ForthOutput { +public: + virtual void show(const char output[]) = 0; +}; + +union FloatIntDual { + int32_t fInt; + float fFloat; +}; + +static inline int32_t f2i_bits(float x) { + FloatIntDual d; + d.fFloat = x; + return d.fInt; +} + +static inline float i2f_bits(int32_t x) { + FloatIntDual d; + d.fInt = x; + return d.fFloat; +} + +class ForthEngine { +public: + ForthEngine(ForthOutput*); + ~ForthEngine(); + + int depth() const { return fStackStop - fStackCurr; } + void clearStack() { fStackCurr = fStackStop; } + + void push(intptr_t value); + intptr_t top() const { return this->peek(0); } + intptr_t peek(size_t index) const; + void setTop(intptr_t value); + intptr_t pop(); + + void fpush(float value) { this->push(f2i_bits(value)); } + float fpeek(size_t i) const { return i2f_bits(this->fpeek(i)); } + float ftop() const { return i2f_bits(this->top()); } + void fsetTop(float value) { this->setTop(f2i_bits(value)); } + float fpop() { return i2f_bits(this->pop()); } + + void sendOutput(const char text[]); + +private: + ForthOutput* fOutput; + intptr_t* fStackBase; + intptr_t* fStackCurr; + intptr_t* fStackStop; + + void signal_error(const char msg[]) const { + SkDebugf("ForthEngine error: %s\n", msg); + } +}; + +struct ForthCallBlock { + const intptr_t* in_data; + size_t in_count; + intptr_t* out_data; + size_t out_count; + size_t out_depth; +}; + +class ForthWord { +public: + virtual ~ForthWord() {} + virtual void exec(ForthEngine*) = 0; + + // todo: return error state of the engine + void call(ForthCallBlock*); +}; + +class ForthEnv { +public: + ForthEnv(); + ~ForthEnv(); + + + void addWord(const char name[], ForthWord*); + + void parse(const char code[]); + + ForthWord* findWord(const char name[]); + + void run(ForthOutput* = NULL); + +private: + class Impl; + Impl* fImpl; +}; + +#endif + diff --git a/forth/SampleForth.cpp b/forth/SampleForth.cpp new file mode 100644 index 0000000..d207cb8 --- /dev/null +++ b/forth/SampleForth.cpp @@ -0,0 +1,248 @@ +#include "SampleCode.h" +#include "SkColorPriv.h" +#include "SkGradientShader.h" +#include "SkView.h" +#include "SkCanvas.h" +#include "SkUtils.h" +#include "Forth.h" + +class MyOutput : public ForthOutput { +public: + SkString fStr; + + virtual void show(const char text[]) { + fStr.set(text); + } +}; + +class SkForthCtx { +public: + SkCanvas fCanvas; + SkPaint fPaint; + + void init(const SkBitmap& bm) { + fCanvas.setBitmapDevice(bm); + fPaint.setAntiAlias(true); + } +}; + +class SkForthCtx_FW : public ForthWord { +public: + SkForthCtx_FW() : fCtx(NULL) {} + + void setCtx(SkForthCtx* ctx) { fCtx = ctx; } + + SkCanvas* canvas() const { return &fCtx->fCanvas; } + SkPaint* paint() const { return &fCtx->fPaint; } + +private: + SkForthCtx* fCtx; +}; + +class setColor_FW : public SkForthCtx_FW { +public: + virtual void exec(ForthEngine* fe) { + paint()->setColor(fe->pop()); + } + + static SkForthCtx_FW* New() { return new setColor_FW; } +}; + +class setStyle_FW : public SkForthCtx_FW { +public: + virtual void exec(ForthEngine* fe) { + paint()->setStyle((SkPaint::Style)fe->pop()); + } + + static SkForthCtx_FW* New() { return new setStyle_FW; } +}; + +class setStrokeWidth_FW : public SkForthCtx_FW { +public: + virtual void exec(ForthEngine* fe) { + paint()->setStrokeWidth(fe->fpop()); + } + + static SkForthCtx_FW* New() { return new setStrokeWidth_FW; } +}; + +class translate_FW : public SkForthCtx_FW { +public: + virtual void exec(ForthEngine* fe) { + SkScalar dy = fe->fpop(); + SkScalar dx = fe->fpop(); + canvas()->translate(dx, dy); + } + + static SkForthCtx_FW* New() { return new translate_FW; } +}; + +class drawColor_FW : public SkForthCtx_FW { +public: + virtual void exec(ForthEngine* fe) { + canvas()->drawColor(fe->pop()); + } + + static SkForthCtx_FW* New() { return new drawColor_FW; } +}; + +class drawRect_FW : public SkForthCtx_FW { +public: + virtual void exec(ForthEngine* fe) { + SkRect r; + r.fBottom = fe->fpop(); + r.fRight = fe->fpop(); + r.fTop = fe->fpop(); + r.fLeft = fe->fpop(); + canvas()->drawRect(r, *paint()); + } + + static SkForthCtx_FW* New() { return new drawRect_FW; } +}; + +class drawCircle_FW : public SkForthCtx_FW { +public: + virtual void exec(ForthEngine* fe) { + SkScalar radius = fe->fpop(); + SkScalar y = fe->fpop(); + SkScalar x = fe->fpop(); + canvas()->drawCircle(x, y, radius, *paint()); + } + + static SkForthCtx_FW* New() { return new drawCircle_FW; } +}; + +class drawLine_FW : public SkForthCtx_FW { +public: + virtual void exec(ForthEngine* fe) { + SkScalar x0, y0, x1, y1; + y1 = fe->fpop(); + x1 = fe->fpop(); + y0 = fe->fpop(); + x0 = fe->fpop(); + canvas()->drawLine(x0, y0, x1, y1, *paint()); + } + + static SkForthCtx_FW* New() { return new drawLine_FW; } +}; + +static const struct { + const char* fName; + SkForthCtx_FW* (*fProc)(); +} gWordRecs[] = { + { "setColor", setColor_FW::New }, + { "setStyle", setStyle_FW::New }, + { "setStrokeWidth", setStrokeWidth_FW::New }, + { "translate", translate_FW::New }, + { "drawColor", drawColor_FW::New }, + { "drawRect", drawRect_FW::New }, + { "drawCircle", drawCircle_FW::New }, + { "drawLine", drawLine_FW::New }, +}; + +static void load_words(ForthEnv* env, SkForthCtx* ctx) { + for (size_t i = 0; i < SK_ARRAY_COUNT(gWordRecs); i++) { + SkForthCtx_FW* word = gWordRecs[i].fProc(); + word->setCtx(ctx); + env->addWord(gWordRecs[i].fName, word); + } +} + +/////////////////////////////////////////////////////////////////////////////// + +class ForthView : public SkView { + ForthEnv fEnv; + ForthWord* fOnClickWord; + + SkBitmap fBM; + SkForthCtx fContext; +public: + ForthView() { + load_words(&fEnv, &fContext); + + fBM.setConfig(SkBitmap::kARGB_8888_Config, 640, 480); + fBM.allocPixels(); + fBM.eraseColor(0); + fContext.init(fBM); + + fEnv.parse(": view.onClick ( x y -- ) 10. drawCircle ;"); + fOnClickWord = fEnv.findWord("view.onClick"); +#if 0 + env.parse( + ": draw1 " + "10. setStrokeWidth 1 setStyle #FF000000 setColor " + "10. 20. 200. 100. drawLine " + "0 setStyle #80FF0000 setColor " + "50. 50. 250. 150. drawRect " + ";"); + env.parse("#FF0000FF drawColor " + "draw1 " + "150. 120. translate " + "draw1 " + ); +#endif + } + +protected: + // overrides from SkEventSink + virtual bool onQuery(SkEvent* evt) { + if (SampleCode::TitleQ(*evt)) { + SampleCode::TitleR(evt, "Forth"); + return true; + } + return this->INHERITED::onQuery(evt); + } + + void drawBG(SkCanvas* canvas) { + canvas->drawColor(0xFFDDDDDD); + } + + void test_onClick(ForthEnv* env) { + ForthWord* word = env->findWord("view.onClick"); + if (word) { + const intptr_t idata[2] = { 40, 2 }; + intptr_t odata[1] = { -1 }; + ForthCallBlock block; + block.in_data = idata; + block.in_count = 2; + block.out_data = odata; + block.out_count = 1; + word->call(&block); + SkDebugf("after view.onClick depth %d count %d top %d\n", + block.out_depth, block.out_count, odata[0]); + } else { + SkDebugf("------ view.onClick not found\n"); + } + } + + virtual void onDraw(SkCanvas* canvas) { + drawBG(canvas); + canvas->drawBitmap(fBM, 0, 0, NULL); + } + + virtual SkView::Click* onFindClickHandler(SkScalar x, SkScalar y) { + return fOnClickWord ? new Click(this) : NULL; + } + + virtual bool onClick(Click* click) { + intptr_t idata[2] = { + f2i_bits(click->fCurr.fX), f2i_bits(click->fCurr.fY) + }; + ForthCallBlock block; + block.in_data = idata; + block.in_count = 2; + block.out_count = 0; + fOnClickWord->call(&block); + this->inval(NULL); + return true; + } + +private: + typedef SkView INHERITED; +}; + +////////////////////////////////////////////////////////////////////////////// + +static SkView* MyFactory() { return new ForthView; } +static SkViewRegister reg(MyFactory); + diff --git a/xcode/sampleapp/SampleApp.xcodeproj/project.pbxproj b/xcode/sampleapp/SampleApp.xcodeproj/project.pbxproj index 3edf0e4..f3cf4e7 100644 --- a/xcode/sampleapp/SampleApp.xcodeproj/project.pbxproj +++ b/xcode/sampleapp/SampleApp.xcodeproj/project.pbxproj @@ -24,6 +24,7 @@ 00003CA10EFC233F000FF73A /* SkXMLParser.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 00003C9D0EFC233F000FF73A /* SkXMLParser.cpp */; }; 00003CA40EFC235F000FF73A /* SkXMLParser_empty.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 00003CA30EFC235F000FF73A /* SkXMLParser_empty.cpp */; }; 000A99820FD97526007E45BD /* SampleArc.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 00A41E4A0EFC312F00C9CBEB /* SampleArc.cpp */; }; + 001B871E1042184D00C84ED4 /* Forth.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 001B871D1042184D00C84ED4 /* Forth.cpp */; }; 0028847B0EFAB46A0083E387 /* libcore.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 002884510EFAA35C0083E387 /* libcore.a */; }; 002884BD0EFAB6A30083E387 /* libmaccore.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 002884BC0EFAB69F0083E387 /* libmaccore.a */; }; 0041CDDB0F00975E00695E8C /* SampleImageDir.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0041CDDA0F00975E00695E8C /* SampleImageDir.cpp */; }; @@ -71,6 +72,7 @@ 00AF77B00FE2EA2D007F9650 /* SampleTestGL.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 00A729630FD93ED600D5051F /* SampleTestGL.cpp */; }; 00AF787E0FE94433007F9650 /* SamplePath.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 00003C640EFC22A8000FF73A /* SamplePath.cpp */; }; 00AF9B18103CD5EB00CBBCB3 /* SampleDitherBitmap.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 00AF9B17103CD5EB00CBBCB3 /* SampleDitherBitmap.cpp */; }; + 00BB289B104781D00057BF7E /* SampleForth.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 00BB289A104781D00057BF7E /* SampleForth.cpp */; }; 00C1B809103857A400FA5948 /* SampleFillType.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0041CE270F00A12400695E8C /* SampleFillType.cpp */; }; 00F53F480FFCFC4D003FA70A /* SampleGradients.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 00C55DA00F8552DC000CAC09 /* SampleGradients.cpp */; }; 00FF39140FC6ED2C00915187 /* SampleEffects.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 00FF39130FC6ED2C00915187 /* SampleEffects.cpp */; }; @@ -149,6 +151,7 @@ 00003C9A0EFC233F000FF73A /* SkDOM.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = SkDOM.cpp; path = ../../src/xml/SkDOM.cpp; sourceTree = SOURCE_ROOT; }; 00003C9D0EFC233F000FF73A /* SkXMLParser.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = SkXMLParser.cpp; path = ../../src/xml/SkXMLParser.cpp; sourceTree = SOURCE_ROOT; }; 00003CA30EFC235F000FF73A /* SkXMLParser_empty.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = SkXMLParser_empty.cpp; path = ../../src/ports/SkXMLParser_empty.cpp; sourceTree = SOURCE_ROOT; }; + 001B871D1042184D00C84ED4 /* Forth.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Forth.cpp; path = ../../forth/Forth.cpp; sourceTree = SOURCE_ROOT; }; 002884490EFAA35C0083E387 /* core.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = core.xcodeproj; path = ../core/core.xcodeproj; sourceTree = SOURCE_ROOT; }; 002884B40EFAB69F0083E387 /* maccore.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = maccore.xcodeproj; path = ../maccore/maccore.xcodeproj; sourceTree = SOURCE_ROOT; }; 003145310FB9B48F00B10956 /* SampleShapes.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = SampleShapes.cpp; path = ../../samplecode/SampleShapes.cpp; sourceTree = SOURCE_ROOT; }; @@ -199,6 +202,8 @@ 00A7282E0FD43D3700D5051F /* SkMovie_gif.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = SkMovie_gif.cpp; path = ../../src/images/SkMovie_gif.cpp; sourceTree = SOURCE_ROOT; }; 00A729630FD93ED600D5051F /* SampleTestGL.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = SampleTestGL.cpp; path = ../../samplecode/SampleTestGL.cpp; sourceTree = SOURCE_ROOT; }; 00AF9B17103CD5EB00CBBCB3 /* SampleDitherBitmap.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = SampleDitherBitmap.cpp; path = ../../samplecode/SampleDitherBitmap.cpp; sourceTree = SOURCE_ROOT; }; + 00BB289A104781D00057BF7E /* SampleForth.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = SampleForth.cpp; path = ../../forth/SampleForth.cpp; sourceTree = SOURCE_ROOT; }; + 00BB289D1047826E0057BF7E /* Forth.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Forth.h; path = ../../forth/Forth.h; sourceTree = SOURCE_ROOT; }; 00C55DA00F8552DC000CAC09 /* SampleGradients.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = SampleGradients.cpp; path = ../../samplecode/SampleGradients.cpp; sourceTree = SOURCE_ROOT; }; 00D6B5CB0F72DC4300C466B9 /* SampleFuzz.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = SampleFuzz.cpp; path = ../../samplecode/SampleFuzz.cpp; sourceTree = SOURCE_ROOT; }; 00FF39130FC6ED2C00915187 /* SampleEffects.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = SampleEffects.cpp; path = ../../samplecode/SampleEffects.cpp; sourceTree = SOURCE_ROOT; }; @@ -280,6 +285,8 @@ 0041CE260F00A12400695E8C /* SampleEncode.cpp */, 0041CE270F00A12400695E8C /* SampleFillType.cpp */, 00AF9B17103CD5EB00CBBCB3 /* SampleDitherBitmap.cpp */, + 00BB289D1047826E0057BF7E /* Forth.h */, + 00BB289A104781D00057BF7E /* SampleForth.cpp */, 0041CE280F00A12400695E8C /* SampleFilter.cpp */, 0041CE290F00A12400695E8C /* SampleFilter2.cpp */, 0041CE2A0F00A12400695E8C /* SampleFontCache.cpp */, @@ -355,6 +362,7 @@ 20286C29FDCF999611CA2CEA /* CICarbonSample */ = { isa = PBXGroup; children = ( + 001B871D1042184D00C84ED4 /* Forth.cpp */, 2762F66A0FCCCAA2002BD8B4 /* images */, 00003C6A0EFC22AD000FF73A /* views */, 00003C610EFC2287000FF73A /* samples */, @@ -579,6 +587,8 @@ 27005D5F10095B2B00E275B6 /* SampleCircle.cpp in Sources */, 00C1B809103857A400FA5948 /* SampleFillType.cpp in Sources */, 00AF9B18103CD5EB00CBBCB3 /* SampleDitherBitmap.cpp in Sources */, + 001B871E1042184D00C84ED4 /* Forth.cpp in Sources */, + 00BB289B104781D00057BF7E /* SampleForth.cpp in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; -- 2.7.4