From c13d5fd6ba6232ecb4809d52c988ef57d34b43cb Mon Sep 17 00:00:00 2001 From: Caleb Connolly Date: Sun, 23 Jan 2022 21:25:19 +0000 Subject: [PATCH] sorta works things run, text and logos work, it's a start --- include/nanosvg.h | 41 +++++++++++-------- include/nanosvgrast.h | 29 +++++++++---- src/pbsplash.c | 94 +++++++++++++++++++++++-------------------- 3 files changed, 98 insertions(+), 66 deletions(-) diff --git a/include/nanosvg.h b/include/nanosvg.h index 6964811..81c4130 100644 --- a/include/nanosvg.h +++ b/include/nanosvg.h @@ -161,6 +161,9 @@ typedef struct NSVGimage { float width; // Width of the image. float height; // Height of the image. + int fontAscent; + int fontDescent; + int defaultHorizAdv; NSVGshape* shapes; // Linked list of shapes in the image. } NSVGimage; @@ -456,7 +459,6 @@ typedef struct NSVGparser char defsFlag; char *unicodeFlag; char *horizAdvFlag; - char *defaultHorizAdv; } NSVGparser; static void nsvg__xformIdentity(float* t) @@ -982,7 +984,7 @@ static void nsvg__addShape(NSVGparser* p) shape->horizAdvX = 0; } if (shape->horizAdvX == 0) { - shape->horizAdvX = p->defaultHorizAdv; + shape->horizAdvX = p->image->defaultHorizAdv; } p->unicodeFlag = NULL; p->horizAdvFlag = NULL; @@ -1880,10 +1882,17 @@ static void nsvg__parseAttribs(NSVGparser* p, const char** attr) if (strcmp(attr[i], "style") == 0) { nsvg__parseStyle(p, attr[i + 1]); } else if (strcmp(attr[i], "horiz-adv-x") == 0) { - printf("Setting defualt horiz adv to %s\n", attr[i + 1]); - p->defaultHorizAdv = strtol(attr[i+1], &end, 10); - if (end == p->defaultHorizAdv) - p->defaultHorizAdv = 0; + p->image->defaultHorizAdv = strtol(attr[i+1], &end, 10); + if (end == attr[i+1]) + p->image->defaultHorizAdv = 0; + } else if (strcmp(attr[i], "ascent") == 0) { + p->image->fontAscent = strtol(attr[i+1], &end, 10); + if (end == attr[i+1]) + p->image->fontAscent = 0; + } else if (strcmp(attr[i], "descent") == 0) { + p->image->fontDescent = strtol(attr[i+1], &end, 10); + if (end == attr[i+1]) + p->image->fontDescent = 0; } else { nsvg__parseAttr(p, attr[i], attr[i + 1]); } @@ -2746,11 +2755,10 @@ static void nsvg__startElement(void* ud, const char* el, const char** attr) } else if (strcmp(el, "font") == 0) { // fonts are special "g" tags nsvg__pushAttr(p); nsvg__parseAttribs(p, attr); + } else if (strcmp(el, "font-face") == 0) { // for the default character width + nsvg__pushAttr(p); + nsvg__parseAttribs(p, attr); } - // } else if (strcmp(el, "missing-glyph") == 0) { // for the default character width - // nsvg__pushAttr(p); - // nsvg__parseAttribs(p, attr); - // } return; } @@ -2955,7 +2963,7 @@ NSVGshape** nsvgGetTextShapes(NSVGimage* image, char* text, int textLen) { NSVGshape *shape = NULL; NSVGpath *path = NULL; - NSVGshape **shapes = malloc(sizeof(NSVGshape*)*textLen); // array of paths, text to render + NSVGshape **ret = malloc(sizeof(NSVGshape*)*textLen); // array of paths, text to render int i; // make list of paths representing glyphs to render @@ -2964,15 +2972,16 @@ NSVGshape** nsvgGetTextShapes(NSVGimage* image, char* text, int textLen) for (shape = image->shapes; shape != NULL; shape = shape->next) { if (!(shape->flags & NSVG_FLAGS_VISIBLE)) continue; - if (shape->unicode) - if (shape->unicode[0] == text[i]) { - shapes[i] = shape; - break; + if (shape->unicode && shape->unicode[0] == text[i]) { + ret[i] = shape; + goto found; } } +found: + continue; } - return shapes; + return ret; } NSVGimage* nsvgParse(char* input, const char* units, float dpi) diff --git a/include/nanosvgrast.h b/include/nanosvgrast.h index 0b0041a..4fedf4a 100644 --- a/include/nanosvgrast.h +++ b/include/nanosvgrast.h @@ -1371,7 +1371,7 @@ void nsvgRasterizeText(NSVGrasterizer* r, NSVGedge *e = NULL; NSVGcachedPaint cache; NSVGshape **shapes = nsvgGetTextShapes(font, text, strlen(text)); - int i = 0, textLen = strlen(text); + int i = 0, j = 0, textLen = strlen(text); r->bitmap = dst; r->width = w; @@ -1381,26 +1381,38 @@ void nsvgRasterizeText(NSVGrasterizer* r, if (w > r->cscanline) { r->cscanline = w; r->scanline = (unsigned char*)realloc(r->scanline, w); - if (r->scanline == NULL) return; + if (r->scanline == NULL) { + return; + } } for (i = 0; i < h; i++) memset(&dst[i*stride], 0, w*4); - for (shape = shapes[i]; i < textLen; i++) { + for (i = 0; i < textLen; i++) { + shape = shapes[i]; + if (!shape) { + if (text[i] == ' ') + tx += font->defaultHorizAdv * scale; + continue; + } if (!(shape->flags & NSVG_FLAGS_VISIBLE)) continue; + if (i == 0 && strcmp(shape->id, "OpenSansRegular") == 0) + tx -= shape->horizAdvX * scale; + if (shape->fill.type != NSVG_PAINT_NONE) { nsvg__resetPool(r); + shape->fill.color = 0xffffffff; r->freelist = NULL; r->nedges = 0; nsvg__flattenShape(r, shape, scale); // Scale and translate edges - for (i = 0; i < r->nedges; i++) { - e = &r->edges[i]; + for (j = 0; j < r->nedges; j++) { + e = &r->edges[j]; e->x0 = tx + e->x0; e->y0 = (ty + e->y0) * NSVG__SUBSAMPLES; e->x1 = tx + e->x1; @@ -1425,8 +1437,8 @@ void nsvgRasterizeText(NSVGrasterizer* r, // dumpEdges(r, "edge.svg"); // Scale and translate edges - for (i = 0; i < r->nedges; i++) { - e = &r->edges[i]; + for (j = 0; j < r->nedges; j++) { + e = &r->edges[j]; e->x0 = tx + e->x0; e->y0 = (ty + e->y0) * NSVG__SUBSAMPLES; e->x1 = tx + e->x1; @@ -1441,10 +1453,13 @@ void nsvgRasterizeText(NSVGrasterizer* r, nsvg__rasterizeSortedEdges(r, tx,ty,scale, &cache, NSVG_FILLRULE_NONZERO); } + tx += shape->horizAdvX * scale; } nsvg__unpremultiplyAlpha(dst, w, h, stride); + free(shapes); + r->bitmap = NULL; r->width = 0; r->height = 0; diff --git a/src/pbsplash.c b/src/pbsplash.c index 9098751..7d8ad4a 100644 --- a/src/pbsplash.c +++ b/src/pbsplash.c @@ -123,11 +123,11 @@ static void drawPath(float *pts, int npts, int xoff, int yoff, float scale_x, fl // scaled based on the target width and height. static void draw_svg(NSVGimage *image, int x, int y, int width, int height) { - fprintf(stdout, "size: %f x %f\n", image->width, image->height); + //fprintf(stdout, "size: %f x %f\n", image->width, image->height); float sz = (float)width / image->width; int w = image->width * sz + 0.5; int h = image->height * sz + 0.5; - fprintf(stdout, "scale: %f\n", sz); + //fprintf(stdout, "scale: %f\n", sz); NSVGrasterizer *rast = nsvgCreateRasterizer(); unsigned char *img = malloc(w * h * 4); @@ -145,73 +145,78 @@ static void draw_svg(NSVGimage *image, int x, int y, int width, int height) free(img); } -static void draw_text(NSVGimage *font, char *text, int x, int y, float scale) +static void getTextDimensions(NSVGimage *font, char *text, float scale, int *width, int *height) { - int width, height = 200; - printf("text: %s\n", text); + int i = 0; + + *width = 0; + *height = (font->fontAscent - font->fontDescent) * scale; NSVGshape **shapes = nsvgGetTextShapes(font, text, strlen(text)); for (size_t i = 0; i < strlen(text); i++) { - width += shapes[i]->horizAdvX * scale + 1; + NSVGshape *shape = shapes[i]; + if (shape) { + *width += shapes[i]->horizAdvX * scale + 1; + } else { + *width += font->defaultHorizAdv * scale; + } + } +} + +static void draw_text(NSVGimage *font, char *text, int x, int y, int width, int height, float scale) +{ + //printf("text: %s, scale: %f, x: %d, y: %d\n", text, scale, x, y); + NSVGshape **shapes = nsvgGetTextShapes(font, text, strlen(text)); unsigned char *img = malloc(width * height * 4); NSVGrasterizer *rast = nsvgCreateRasterizer(); - printf("text dimensions: %d x %d\n", width, height); + //printf("text dimensions: %d x %d\n", width, height); - nsvgRasterize(rast, font, 0, 0, scale, img, width, height, width * 4); + nsvgRasterizeText(rast, font, 0, 0, scale, img, width, height, width * 4, text); for (size_t i = 0; i < width; i++) { for (size_t j = 0; j < height; j++) { unsigned int col = tfb_make_color(img[(j * width + i) * 4 + 0], img[(j * width + i) * 4 + 1], img[(j * width + i) * 4 + 2]); - tfb_draw_pixel(x + i, y - j, col); + tfb_draw_pixel(x + i, y + height - j, col); } } free(img); + free(shapes); } int main(int argc, char **argv) { int rc = 0; int opt; - char *message = calloc(MSG_MAX_LEN, 1); + char *message; + char *logoText = "postmarketOS"; char *splash_image; NSVGimage *image; NSVGimage *font; + int textWidth, textHeight; for (int i = 1; i < argc; i++) { - printf("%d: %s\n", i, argv[i]); if (strcmp(argv[i], "-h") == 0) { rc = usage(); - goto out; + return rc; } if (strcmp(argv[i], "-s") == 0 && i + 1 < argc) { splash_image = argv[i + 1]; - printf("splash_image path: %s\n", splash_image); + //printf("splash_image path: %s\n", splash_image); continue; } if (strcmp(argv[i], "-m") == 0) { - if (*argv[i + 1] == '-') - { - rc = read(STDIN_FILENO, message, MSG_MAX_LEN); - if (rc < 0) - goto out; - printf("%s\n", message); - } - else - { - free(message); - message = argv[i + 1]; - } + message = argv[i + 1]; printf("message: %s\n", message); continue; } @@ -221,55 +226,58 @@ int main(int argc, char **argv) { fprintf(stderr, "tfb_acquire_fb() failed with error code: %d\n", rc); rc = 1; - goto out; + return rc; } int w = (int)tfb_screen_width(); int h = (int)tfb_screen_height(); float sz = (float)(w < h ? w : h) * 0.5f; - fprintf(stdout, "w=%du, h=%du\n", w, h); + //fprintf(stdout, "w=%du, h=%du\n", w, h); float x = (float)w / 2 - sz / 2; float y = (float)h / 2 - sz / 2 - 300; - fprintf(stdout, "x=%f, y=%f, sz=%f\n", x, y, sz); + //fprintf(stdout, "x=%f, y=%f, sz=%f\n", x, y, sz); image = nsvgParseFromFile(splash_image, "px", 96); if (!image) { fprintf(stderr, "failed to load SVG image\n"); rc = 1; - goto out; + return rc; } font = nsvgParseFromFile(FONT_PATH, "px", 500); if (!font || !font->shapes) { fprintf(stderr, "failed to load SVG font\n"); rc = 1; - goto out; + goto free_image; } - float fontsz = 0.05f; - fprintf(stdout, "font size: %f\n", fontsz); /* Paint the whole screen in black */ tfb_clear_screen(tfb_black); - /* Draw some text on-screen */ - tfb_draw_string_scaled(x + 75, y + sz + 40, tfb_white, tfb_black, 4, 4, "postmarketOS"); - - if (message) - { - tfb_draw_string_scaled_wrapped(50, (int)((float)h * 0.6), tfb_white, tfb_black, 2, 2, 80, message); - } draw_svg(image, x, y, sz, sz); - draw_text(font, "postmarketOS", 100, h / 2.f + 100, fontsz); + float fontsz = (sz * 0.25) / (font->fontAscent - font->fontDescent); + //fprintf(stdout, "font size: %f\n", fontsz); + + getTextDimensions(font, logoText, fontsz, &textWidth, &textHeight); + + draw_text(font, logoText, w / 2.f - textWidth / 2.f, y + sz + sz*0.2, textWidth, textHeight, fontsz); + + fontsz = (sz * 0.1) / (font->fontAscent - font->fontDescent); + + getTextDimensions(font, message, fontsz, &textWidth, &textHeight); + + draw_text(font, message, w / 2.f - textWidth / 2.f, y + sz * 2, textWidth, textHeight, fontsz); + printf("Rendered text: %s\n", message); tfb_flush_window(); tfb_flush_fb(); - sleep(20); + //sleep(20); out: + nsvgDelete(font); +free_image: nsvgDelete(image); - tfb_release_fb(); - free(message); return rc; }