ref: 8626465772e8dd47dfc7e5f0319f6458d3be5335
parent: 807afae69b7551b681b638d64f1099af5c672fdd
author: sirjofri <sirjofri@sirjofri.de>
date: Tue Aug 20 04:27:47 EDT 2024
use embedded mask, use db for serializing tool data
--- a/blie.c
+++ b/blie.c
@@ -26,6 +26,17 @@
.keyzoom = 0.2,
};
+static Memimage*
+memcol(int chan, int color)
+{
+ Memimage *i;
+ i = allocmemimage(Rect(0, 0, 1, 1), chan);
+ memfillcolor(i, color);
+ i->flags |= Fsimple|Frepl;
+ i->clipr = Rect(-0x3FFFFFF, -0x3FFFFFF, 0x3FFFFFF, 0x3FFFFFF);
+ return i;
+}
+
static void
initvdata(void)
{
@@ -583,10 +594,11 @@
sysfatal("memimageinit: %r");
headless = outputonly;
- if (!headless)
+ if (!headless) {
if (initdraw(nil, nil, "blie") < 0)
sysfatal("initdraw: %r");
- initvdata();
+ initvdata();
+ }
loadeditors();
if (!loadfile())
--- a/blie.h
+++ b/blie.h
@@ -38,6 +38,7 @@
int fontheight; /* height of font */
int keyoffset; /* offset on key input */
float keyzoom; /* zoom change */
+
Image *gray;
};
--- /dev/null
+++ b/db.c
@@ -1,0 +1,490 @@
+#include <u.h>
+#include <libc.h>
+#include <bio.h>
+#include <ctype.h>
+#include "db.h"
+
+
+#define DEBUG
+#undef DEBUG
+#define LOG 1
+#define VERBOSE 2
+#define VERYVERBOSE 3
+static int verbosity = LOG;
+static int consfd = -1; /* 2 for stderr, -1 for cons */
+
+static void
+clog(int v, char *fmt, ...)
+{
+#ifdef DEBUG
+ va_list args;
+
+ if (v > verbosity)
+ return;
+
+ if (consfd < 0) {
+ consfd = open("#c/cons", OWRITE|OCEXEC);
+ if (consfd < 0)
+ return;
+ }
+
+ fprint(consfd, "bliedb: ");
+ va_start(args, fmt);
+ vfprint(consfd, fmt, args);
+ va_end(args);
+ fprint(consfd, "\n");
+#else
+ USED(v, fmt);
+#endif
+}
+
+static char*
+estrdup(char *s)
+{
+ char *t;
+ t = strdup(s);
+ if (!t)
+ sysfatal("out of memory: %r");
+ return t;
+}
+
+static char*
+unesc(char *s)
+{
+ char *t;
+ int n;
+ n = strlen(s);
+
+ while (t = strstr(s, "''")) {
+ memmove(t, t+1, n - (t-s));
+ n--;
+ }
+ clog(VERYVERBOSE, "parse: unesc: %s", s);
+ return s;
+}
+
+enum {
+ OUT = 0,
+ QUOT = 1,
+};
+
+static Dpack*
+pgetdv(Db *db, char *i)
+{
+ clog(VERBOSE, "parse: dpack %s", i);
+ return getdpack(db, i);
+}
+
+static void
+paddkv(Dpack *dv, char *k, char *v)
+{
+ clog(VERBOSE, "parse: %s = %s", k, v);
+ setdval(dv, k, unesc(v));
+}
+
+char *allowed = ".(){}!#$%&*+,-/:;<>?@[]^\_`|~\"";
+
+static int
+iswc(int c)
+{
+ return isalnum(c) || strchr(allowed, c);
+}
+
+static void
+parsedb(Db *db, char *s)
+{
+ Dpack *dv;
+ char *k, *v;
+ int state = 0;
+ char *t;
+ int doquit;
+
+ clog(LOG, "parse: begin parsing: %s", s);
+
+ dv = nil;
+ t = nil;
+ k = nil;
+ v = nil;
+ doquit = 0;
+ while (1) {
+ if (doquit)
+ break;
+ clog(VERYVERBOSE, "parse: state: %d, char '%c'", state, *s);
+ if (state == QUOT && *s == 0) {
+ clog(LOG, "parse: bad syntax EOL");
+ break;
+ }
+ if (state == OUT && (*s == ' ' || *s == '\t' || *s == 0)) {
+ if (*s == 0) {
+ clog(VERBOSE, "parse: regular EOL");
+ doquit++;
+ }
+ if (!t) {
+ s++;
+ continue;
+ }
+ if (!dv) {
+ *s = 0;
+ dv = pgetdv(db, t);
+ t = nil;
+ s++;
+ continue;
+ }
+ if (!k) {
+ *s = 0;
+ k = t;
+ clog(VERBOSE, "parse: key %s", k);
+ t = nil;
+ s++;
+ continue;
+ }
+ if (!v) {
+ *s = 0;
+ v = t;
+ paddkv(dv, k, v);
+ k = nil;
+ v = nil;
+ t = nil;
+ s++;
+ continue;
+ }
+ goto Bad;
+ }
+
+ if (state == QUOT && (*s == ' ' || *s == '\t' || *s == '=')) {
+ goto Alnum;
+ }
+
+ if (state == OUT && *s == '\'') {
+ state = QUOT;
+ clog(VERYVERBOSE, "parse: {quote");
+ s++;
+ t = s;
+ continue;
+ }
+ if (state == QUOT && *s == '\'') {
+ if (s[1] == '\'') {
+ s++; /* skip escaped quote */
+ clog(VERYVERBOSE, "parse: esc: >%c<", *s);
+ goto Alnum;
+ }
+ state = OUT;
+ clog(VERYVERBOSE, "parse: }quote");
+ *s = 0;
+ s++;
+ continue;
+ }
+ if (iswc(*s)) { /* both states */
+Alnum:
+ if (!t) {
+ clog(VERYVERBOSE, "parse: encountered new word");
+ t = s;
+ }
+ s++;
+ continue;
+ }
+ if (state == OUT && *s == '=') {
+ *s = ' ';
+ continue;
+ }
+Bad:
+ clog(LOG, "parse: bad state: got '%c'", *s);
+ break;
+ }
+
+ clog(LOG, "parse: finished parsing line");
+}
+
+Db*
+opendb(char *file)
+{
+ Biobuf *bin;
+ int fd;
+ char *s;
+ Db *db;
+
+ /* try to install "%q" quote fmt, will silently
+ * fail if it's already installed.
+ */
+ quotefmtinstall();
+
+ if (!file) {
+ db = mallocz(sizeof(Db), 1);
+ return db;
+ }
+
+ fd = open(file, OREAD);
+ if (fd < 0) {
+ db = mallocz(sizeof(Db), 1);
+ db->file = estrdup(file);
+ return db;
+ }
+ bin = Bfdopen(fd, OREAD);
+ if (!bin)
+ sysfatal("%r");
+
+ db = mallocz(sizeof(Db), 1);
+ db->file = estrdup(file);
+
+ while (s = Brdstr(bin, '\n', 1)) {
+ parsedb(db, s);
+ free(s);
+ }
+
+ Bterm(bin);
+ return db;
+}
+
+static void
+freedpack(Dpack *dv)
+{
+ Dtuple *tp, *ttp;
+
+ for (tp = dv->tuple; tp;) {
+ free(tp->key);
+ if (tp->value)
+ free(tp->value);
+ ttp = tp->next;
+ free(tp);
+ tp = ttp;
+ }
+ free(dv->id);
+}
+
+void
+freedb(Db *db)
+{
+ Dpack *dv, *tdv;
+
+ for (dv = db->dpack; dv;) {
+ tdv = dv->next;
+ freedpack(dv);
+ dv = tdv;
+ }
+
+ if (db->file)
+ free(db->file);
+ free(db);
+}
+
+int
+writedb(Db *db, char *file)
+{
+ int fd;
+ Biobuf *bout;
+ Dpack *dv;
+ Dtuple *tp;
+
+ if (!file)
+ file = db->file;
+ if (!file) {
+ werrstr("no file");
+ return 0;
+ }
+
+ fd = create(file, OWRITE|OTRUNC, 0666);
+ if (fd < 0) {
+ werrstr("create: %r");
+ return 0;
+ }
+ bout = Bfdopen(fd, OWRITE);
+ if (!bout)
+ sysfatal("%r");
+
+ // TODO: implement esc sequence
+ for (dv = db->dpack; dv; dv = dv->next) {
+ Bprint(bout, "%s", dv->id);
+ for (tp = dv->tuple; tp; tp = tp->next) {
+ if (tp->value) {
+ Bprint(bout, " %s=%q", tp->key, tp->value);
+ } else {
+ Bprint(bout, " %s", tp->key);
+ }
+ }
+ Bprint(bout, "\n");
+ }
+
+ Bterm(bout);
+ return 1;
+}
+
+Dpack*
+getdpack(Db *db, char *id)
+{
+ Dpack *dv, *pdv;
+
+ if (!db->dpack) {
+ db->dpack = mallocz(sizeof(Dpack), 1);
+ db->dpack->id = estrdup(id);
+ return db->dpack;
+ }
+
+ pdv = nil; /* shut up compiler */
+ for (dv = db->dpack; dv; dv = dv->next) {
+ if (strcmp(dv->id, id) == 0)
+ return dv;
+ pdv = dv;
+ }
+ pdv->next = mallocz(sizeof(Dpack), 1);
+ dv = pdv->next;
+ dv->id = estrdup(id);
+ return dv;
+}
+
+static Dtuple*
+getdtuple(Dpack *dv, char *key)
+{
+ Dtuple *tp, *ptp;
+
+ if (!dv->tuple) {
+ dv->tuple = mallocz(sizeof(Dtuple), 1);
+ dv->tuple->key = estrdup(key);
+ return dv->tuple;
+ }
+
+ ptp = nil; /* shut up compiler */
+ for (tp = dv->tuple; tp; tp = tp->next) {
+ if (strcmp(tp->key, key) == 0)
+ return tp;
+ ptp = tp;
+ }
+ ptp->next = mallocz(sizeof(Dtuple), 1);
+ tp = ptp->next;
+ tp->key = estrdup(key);
+ return tp;
+}
+
+void
+setdval(Dpack *dv, char *key, char *value)
+{
+ Dtuple *dt;
+
+ dt = getdtuple(dv, key);
+ if (dt->value)
+ free(dt->value);
+ dt->value = value ? estrdup(value) : nil;
+}
+
+char*
+getdval(Dpack *dv, char *key, char *def)
+{
+ Dtuple *tp;
+
+ for (tp = dv->tuple; tp; tp = tp->next) {
+ if (strcmp(tp->key, key) == 0)
+ return tp->value;
+ }
+ return def;
+}
+
+void
+deldtuple(Dpack *dv, char *key)
+{
+ USED(dv, key);
+ sysfatal("deldtuple not implemented yet!");
+}
+
+void
+deldpack(Db *db, Dpack *dv)
+{
+ USED(db, dv);
+ sysfatal("deldpack not implemented yet!");
+}
+
+
+int
+typelen(Stype t)
+{
+ switch (t) {
+ case INT:
+ return sizeof(int);
+ case FLOAT:
+ return sizeof(double);
+ case STRING:
+ return sizeof(char*);
+ }
+ return 0;
+}
+
+void
+serialize(Dpack *dv, void *data, Sdata *desc)
+{
+ char buf[32], *str;
+ Sdata *s;
+ uchar *p;
+ int *ip;
+ double *fp;
+ char **sp;
+
+ p = (uchar*)data;
+ for (s = desc; s->type; s++) {
+ str = nil;
+ switch (s->type) {
+ case NIL:
+ return;
+ case INT:
+ ip = (int*)p;
+ snprint(buf, sizeof buf, "%d", *ip);
+ str = buf;
+ p += typelen(INT);
+ break;
+ case STRING:
+ sp = (char**)p;
+ str = *sp;
+ p += typelen(STRING);
+ break;
+ case FLOAT:
+ fp = (double*)p;
+ snprint(buf, sizeof buf, "%f", *fp);
+ str = buf;
+ p += typelen(FLOAT);
+ break;
+ }
+ setdval(dv, s->name, str);
+ }
+}
+
+void
+deserialize(Dpack *dv, void *data, Sdata *desc)
+{
+ char *str;
+ Sdata *s;
+ uchar *p;
+ int *ip;
+ double *fp;
+ char **cp;
+
+ p = (uchar*)data;
+ for (s = desc; s->type; s++) {
+ clog(VERBOSE, "des: '%s' (%d)", s->name, s->type);
+ str = getdval(dv, s->name, s->def);
+ if (!str) {
+ clog(LOG, "des: %s not found", s->name);
+ clog(VERYVERBOSE, "des: ptr: %p", p);
+ p += typelen(s->type);
+ continue;
+ }
+ switch (s->type) {
+ case NIL:
+ return;
+ case INT:
+ ip = (int*)p;
+ *ip = atoi(str);
+ clog(VERYVERBOSE, "des: int: %d", *ip);
+ p += typelen(INT);
+ continue;
+ case STRING:
+ cp = (char**)p;
+ *cp = str;
+ clog(VERYVERBOSE, "des: str: %s", *cp);
+ p += typelen(STRING);
+ continue;
+ case FLOAT:
+ fp = (double*)p;
+ *fp = atof(str);
+ clog(VERYVERBOSE, "des: float: %f", *fp);
+ p += typelen(FLOAT);
+ continue;
+ }
+ }
+}
--- /dev/null
+++ b/db.h
@@ -1,0 +1,73 @@
+typedef struct Db Db;
+typedef struct Dpack Dpack;
+typedef struct Dtuple Dtuple;
+
+/* format:
+<i1> <k1>=<v1> <k2>=<v2>
+<i2> <k1>=<v1> <k2>=<v2>
+*/
+
+struct Db {
+ Dpack *dpack;
+ char *file;
+};
+
+struct Dpack {
+ Dpack *next;
+ char *id;
+ Dtuple *tuple;
+};
+
+struct Dtuple {
+ Dtuple *next;
+ char *key;
+ char *value;
+};
+
+Db *opendb(char *file);
+void freedb(Db*);
+
+int writedb(Db*, char *file);
+
+Dpack *getdpack(Db*, char *id);
+void setdval(Dpack*, char *key, char *value);
+char *getdval(Dpack*, char *key, char *def);
+void deldtuple(Dpack*, char *key);
+void deldpack(Db*, Dpack*);
+
+
+/* serializable structure:
+
+struct mystruct {
+ int a;
+ char *b;
+ int c;
+};
+Sdata data[] = {
+ { INT, "a", "5" },
+ { STRING, "b", "hello" },
+ { INT, "c", nil },
+ { NIL, nil, nil },
+};
+*/
+
+#define STRUCT(name, type, dtype, dval) dtype name;
+#define SDATA(name, type, dtype, dval) { type, "name", dval },
+#define ENDSDATA { NIL, nil, nil },
+
+typedef enum {
+ NIL = 0,
+ INT,
+ STRING,
+ FLOAT,
+} Stype;
+
+typedef struct Sdata Sdata;
+struct Sdata {
+ Stype type;
+ char *name;
+ char *def;
+};
+
+void serialize(Dpack *dv, void *data, Sdata *desc);
+void deserialize(Dpack *dv, void *data, Sdata *desc);
--- a/eentercolor.c
+++ b/eentercolor.c
@@ -82,8 +82,8 @@
return r;
}
-Image *colors = nil;
-uchar *data;
+static Image *colors = nil;
+static uchar *data;
static void
initimage(double hue)
@@ -119,7 +119,7 @@
loadimage(colors, colors->r, data, n);
}
-Image *huegrad = nil;
+static Image *huegrad = nil;
static void
inithuegrad(void)
@@ -193,6 +193,8 @@
return rgb;
}
+static double hue = 0.;
+
int
eentercolor(char *ask, ulong *out, Mouse *m)
{
@@ -203,7 +205,6 @@
Point xy;
uchar *pixel;
int fy;
- double hue;
Rgb rgb;
Hsv hsv;
Image *blitimg;
@@ -210,8 +211,6 @@
Image *selcol;
char buf[1 + 3 + 1 + 3 + 1 + 3 + 1 + 1]; /* (XXX,XXX,XXX) */
- hue = 0.;
-
if (!ask)
ask = "color:";
@@ -220,8 +219,7 @@
if (!huegrad)
inithuegrad();
- if (!colors)
- initimage(hue);
+ initimage(hue);
pixel = (uchar*)out;
@@ -296,10 +294,12 @@
break;
if (ptinrect(ev.mouse.xy, ri)) {
xy = subpt(ev.mouse.xy, ri.min);
- hsv.h = hue;
hsv.s = (double)xy.x/100;
hsv.v = 1.-(double)xy.y/100;
+Setcolor:
+ hsv.h = hue;
rgb = hsv2rgb(hsv);
+Setpixel:
pixel[3] = rgb.r * 256;
pixel[2] = rgb.g * 256;
pixel[1] = rgb.b * 256;
@@ -311,18 +311,13 @@
xy.x = ev.mouse.xy.x - rh.min.x;
hue = ((double)xy.x / 100);
initimage(hue);
- break;
+ goto Setcolor;
}
if (ptinrect(ev.mouse.xy, ro)) {
if (!eenter("color:", buf, sizeof buf, &ev.mouse))
break;
rgb = parsergb(buf);
- pixel[3] = rgb.r * 255;
- pixel[2] = rgb.g * 255;
- pixel[1] = rgb.b * 255;
- pixel[0] = 255;
- snprint(buf, sizeof buf, "%3d,%3d,%3d", pixel[3], pixel[2], pixel[1]);
- break;
+ goto Setpixel;
}
}
}
--- a/mkfile
+++ b/mkfile
@@ -8,6 +8,7 @@
layer.$O\
sample.$O\
eentercolor.$O\
+ db.$O\
util.$O\
p9image.$O\
--- a/p9image.c
+++ b/p9image.c
@@ -6,7 +6,29 @@
#include <event.h>
#include <cursor.h>
#include "blie.h"
+#include "db.h"
+#define DEBUG
+static int consfd = -1;
+static void
+clog(char *fmt, ...)
+{
+#ifdef DEBUG
+ va_list args;
+
+ if (consfd < 0) {
+ consfd = open("#c/cons", OWRITE|OCEXEC);
+ if (consfd < 0)
+ return;
+ }
+ fprint(consfd, "blie-p9image: ");
+ va_start(args, fmt);
+ vfprint(consfd, fmt, args);
+ va_end(args);
+ fprint(consfd, "\n");
+#endif
+}
+
Cursor ccircle = {
{-7, -7},
{0xFF, 0xFF, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x07,
@@ -24,11 +46,27 @@
Image *tmpcol;
+#define SLIST(DO) \
+ DO(value, INT, int, nil)
+
+typedef struct Maskdata Maskdata;
+struct Maskdata {
+ SLIST(STRUCT)
+};
+Sdata smaskdata[] = {
+ SLIST(SDATA)
+ ENDSDATA
+};
+
typedef struct Data Data;
struct Data {
Memimage *img;
Memimage *mask;
- Drawop op;
+ Memimage *imask;
+
+ /* serializable values */
+ Db *db;
+ Maskdata *maskdata;
};
typedef enum {
@@ -151,59 +189,58 @@
static void
readcolors(void)
{
- int fd, i;
- Biobuf *bin;
- char *s;
- char *args[2];
+ int i;
+ Db *db;
ulong val;
+ Dpack *dv;
+ char *tv;
- fd = open("p9image/colors", OREAD);
- if (fd < 0)
- return;
+ db = opendb("p9image/colors");
+ if (!db)
+ sysfatal("cannot read colors: %r");
- bin = Bfdopen(fd, OREAD);
- if (!bin)
- sysfatal("%r");
-
- while (s = Brdstr(bin, '\n', 1)) {
- if (tokenize(s, args, 2) == 2) {
- i = atoi(args[0]);
- val = strtoul(args[1], nil, 16);
- tstate.colordata[i] = val;
- } else
- fprint(2, "ignoring line: %s\n", args[0]);
- free(s);
+ for (dv = db->dpack; dv; dv = dv->next) {
+ tv = getdval(dv, "color", nil);
+ if (!tv)
+ continue;
+ i = atoi(dv->id);
+ val = strtoul(tv, nil, 16);
+ tstate.colordata[i] = val;
}
+ freedb(db);
}
static int
writecolors(void)
{
- int fd, i;
+ int i;
ulong c;
+ Dpack *dv;
+ Db *db;
+ char buf[9];
+
if (access("p9image", AEXIST)) {
- fd = create("p9image", OREAD, DMDIR|0555);
- if (fd < 0) {
+ i = create("p9image", OREAD, DMDIR|0555);
+ if (i < 0) {
werrstr("p9image: %r");
return 0;
}
- close(fd);
+ close(i);
}
- fd = open("p9image/colors", OWRITE|OTRUNC);
- if (fd < 0)
- fd = create("p9image/colors", OWRITE|OTRUNC, 0666);
- if (fd < 0) {
- werrstr("p9image: colors: %r");
- return 0;
- }
+ db = opendb(nil);
+
for (i = 0; i < NUMCELLS; i++) {
c = tstate.colordata[i];
- fprint(fd, "%d\t%ulx\n", i, c&0xff ? c : 0);
+ snprint(buf, sizeof(buf), "%d", i);
+ dv = getdpack(db, buf);
+ snprint(buf, sizeof(buf), "%ulx", c&0xff ? c : 0);
+ setdval(dv, "color", buf);
}
- close(fd);
- return 1;
+ i = writedb(db, "p9image/colors");
+ freedb(db);
+ return i;
}
static void
@@ -212,11 +249,11 @@
tstate.mode = Composite;
tstate.drawtarget = DTimg;
- toolcell = Pt(15, vdata.fontheight + 4);
-
if (headless)
return;
+ toolcell = Pt(15, vdata.fontheight + 4);
+
tstate.circle = allocimage(display, Rect(0, 0, 41, 41), RGBA32, 0, DTransparent);
ellipse(tstate.circle, Pt(20, 20), 19, 19, 0, display->white, ZP);
ellipse(tstate.circle, Pt(20, 20), 20, 20, 0, display->black, ZP);
@@ -289,7 +326,75 @@
return 1;
}
+static int
+p9writedata(Layer *l, Data *d)
+{
+ Db *db;
+ Dpack *dv;
+
+ char buf[128];
+ db = d->db;
+
+ dv = getdpack(db, "mask");
+ if (dv) {
+ snprint(buf, sizeof buf, "%d", d->maskdata->value);
+ setdval(dv, "value", buf);
+ }
+
+ return writedb(db, nil);
+}
+
static void
+updateimask(Data *d)
+{
+ int x, y, dx, dy;
+ double m;
+ uchar *p;
+
+ if (d->maskdata->value == 255) {
+ d->imask = allocmemimage(d->img->r, GREY8);
+ memfillcolor(d->imask, 0);
+ memimagedraw(d->imask, d->imask->r, memwhite, ZP, d->img, ZP, SoverD);
+ return;
+ }
+
+ m = (double)d->maskdata->value / 256;
+ dx = Dx(d->img->r);
+ dy = Dy(d->img->r);
+ d->imask = allocmemimage(d->img->r, GREY8);
+ memfillcolor(d->imask, 0);
+ memimagedraw(d->imask, d->imask->r, memwhite, ZP, d->img, ZP, SoverD);
+
+ for (y = 0; y < dy; y++) {
+ for (x = 0; x < dx; x++) {
+ p = byteaddr(d->imask, Pt(x, y));
+ *p = *p * m;
+ }
+ }
+}
+
+static void
+p9readdata(Layer *l, Data *d)
+{
+ Db *db;
+ Dpack *dv;
+ char *s;
+ int i;
+
+ clog("readdata: %s", l->name);
+
+ s = smprint("l/%s/data", l->name);
+ db = opendb(s);
+ free(s);
+ if (!db)
+ return;
+ d->db = db;
+
+ dv = getdpack(db, "mask");
+ deserialize(dv, d->maskdata, smaskdata);
+}
+
+static void
p9init(Layer *l)
{
int fd;
@@ -300,7 +405,10 @@
return;
d = mallocz(sizeof(Data), 1);
l->data = d;
+ d->maskdata = mallocz(sizeof(Maskdata), 1);
+ p9readdata(l, d);
+
/* image file */
s = smprint("l/%s/img", l->name);
fd = open(s, OREAD);
@@ -323,6 +431,7 @@
fd = open(s, OREAD);
if (fd < 0) {
free(s);
+ updateimask(d);
return;
}
free(s);
@@ -334,6 +443,7 @@
d->mask = readmemimage(fd);
}
close(fd);
+ updateimask(d);
}
/* just use ecompose, which uses raw() and mask() */
@@ -366,6 +476,8 @@
{
Data *d;
d = (Data*)l->data;
+ if (d->imask)
+ return d->imask;
return d->mask;
}
@@ -387,7 +499,11 @@
mi = data->img;
goto Mout;
case Mask:
- mi = data->mask;
+ if (data->imask) {
+ mi = data->imask;
+ goto Mout;
+ }
+ mi = nil;
goto Mout;
}
changecursor(nil, nil, ZP);
@@ -474,7 +590,9 @@
static int
p9savedata(Layer *l)
{
- return writelayer(l);
+ Data *d;
+ d = (Data*)l->data;
+ return writelayer(l) && p9writedata(l, d);
}
static int
@@ -529,6 +647,7 @@
color->clipr = brush->i->r;
memimagedraw(tgt, r, color, ZP, brush->i, ZP, SoverD);
+ updateimask(d);
setdrawingdirty(Dcontent);
dirtylayer(l);
return Rdrawing;
binary files a/test/img/l/layerB/mask /dev/null differ