Browse Source

Fix font baseline_x problem, decrease word-wrap stack usage, add text justification options

inmarket 3 years ago
parent
commit
d8c9ca184f
6 changed files with 160 additions and 83 deletions
  1. 7 0
      changelog.txt
  2. 2 0
      gfxconf.example.h
  3. 117 80
      src/gdisp/gdisp.c
  4. 12 3
      src/gdisp/gdisp.h
  5. 4 0
      src/gdisp/gdisp_driver.h
  6. 18 0
      src/gdisp/gdisp_options.h

+ 7 - 0
changelog.txt

@@ -23,6 +23,13 @@ FEATURE:	Significantly improved the FreeRTOS port
23 23
 FEATURE:	Added support for operating system initialisation in FreeRTOS
24 24
 FEATURE:	Added GFX_OS_CALL_UGFXMAIN configuration option to allow uGFXMain() to be automatically called
25 25
 FEATURE:	Added GFX_OS_UGFXMAIN_STACKSIZE configuration option to control uGFXMain() stack size
26
+FIX:		Fixed where a font with more than 255 glyphs could fail to display some glyphs
27
+FIX:		Fixed where a font with a large x baseline could be incorrectly clipped or word-wrapped
28
+IMPROVE:	Significantly decrease the stack usage required for word-wrapping
29
+FEATURE:	Added justifyTop, justifyMiddle & justifyBottom text justification to GDISP
30
+FEATURE:	Added justifyWordWrap, justifyNoWordWrap text justification to GDISP (requires GDISP_NEED_TEXT_WORDWRAP)
31
+FEATURE:	Added justifyPad, justifyNoPad text justification to GDISP
32
+FEATURE:	Added GDISP_NEED_TEXT_BOXPADLR and GDISP_NEED_TEXT_BOXPADTB configuration options
26 33
 
27 34
 
28 35
 *** Release 2.7 ***

+ 2 - 0
gfxconf.example.h

@@ -84,6 +84,8 @@
84 84
 //#define GDISP_NEED_STREAMING                         FALSE
85 85
 //#define GDISP_NEED_TEXT                              FALSE
86 86
 //    #define GDISP_NEED_TEXT_WORDWRAP                 FALSE
87
+//    #define GDISP_NEED_TEXT_BOXPADLR                 1
88
+//    #define GDISP_NEED_TEXT_BOXPADTB                 1
87 89
 //    #define GDISP_NEED_ANTIALIAS                     FALSE
88 90
 //    #define GDISP_NEED_UTF8                          FALSE
89 91
 //    #define GDISP_NEED_TEXT_KERNING                  FALSE

+ 117 - 80
src/gdisp/gdisp.c

@@ -20,17 +20,6 @@
20 20
 	#define GDISP_STARTUP_LOGO_TIMEOUT		0
21 21
 #endif
22 22
 
23
-// For internal use only.
24
-#if GDISP_NEED_TEXT_WORDWRAP
25
-	typedef struct wrapParameters {
26
-		GDisplay* g;
27
-		coord_t x;
28
-		coord_t y;
29
-		font_t font;
30
-		justify_t justify;
31
-	} wrapParameters_t;
32
-#endif
33
-
34 23
 /*===========================================================================*/
35 24
 /* Driver local variables.                                                   */
36 25
 /*===========================================================================*/
@@ -3340,29 +3329,24 @@ void gdispGDrawBox(GDisplay *g, coord_t x, coord_t y, coord_t cx, coord_t cy, co
3340 3329
 	/* Callback to render string boxes with word wrap. */
3341 3330
 	#if GDISP_NEED_TEXT_WORDWRAP
3342 3331
 		static bool mf_countline_callback(mf_str line, uint16_t count, void *state) {
3343
-			uint16_t *linecount;
3344 3332
 			(void) line;
3345 3333
 			(void) count;
3346 3334
 
3347
-			linecount = (uint16_t*)state;
3348
-			(*linecount)++;
3349
-
3335
+			((coord_t*)state)[0]++;
3350 3336
 			return TRUE;
3351 3337
 		}
3352 3338
 		static bool mf_drawline_callback(mf_str line, uint16_t count, void *state) {
3353
-			wrapParameters_t* wrapParameters = (wrapParameters_t*)state;
3354
-
3355
-			mf_render_aligned(wrapParameters->font, wrapParameters->x, wrapParameters->y, wrapParameters->justify, line, count, drawcharglyph, wrapParameters->g);
3356
-
3357
-			wrapParameters->y += wrapParameters->font->line_height;
3339
+			#define GD	((GDisplay *)state)
3340
+				mf_render_aligned(GD->t.font, GD->t.wrapx, GD->t.wrapy, GD->t.lrj, line, count, drawcharglyph, state);
3341
+				GD->t.wrapy += GD->t.font->line_height;
3342
+			#undef GD
3358 3343
 			return TRUE;
3359 3344
 		}
3360 3345
 		static bool mf_fillline_callback(mf_str line, uint16_t count, void *state) {
3361
-			wrapParameters_t* wrapParameters = (wrapParameters_t*)state;
3362
-
3363
-			mf_render_aligned(wrapParameters->font, wrapParameters->x, wrapParameters->y, wrapParameters->justify, line, count, fillcharglyph, wrapParameters->g);
3364
-
3365
-			wrapParameters->y += wrapParameters->font->line_height;
3346
+			#define GD	((GDisplay *)state)
3347
+				mf_render_aligned(GD->t.font, GD->t.wrapx, GD->t.wrapy, GD->t.lrj, line, count, fillcharglyph, state);
3348
+				GD->t.wrapy += GD->t.font->line_height;
3349
+			#undef GD
3366 3350
 			return TRUE;
3367 3351
 		}	
3368 3352
 	#endif
@@ -3411,7 +3395,7 @@ void gdispGDrawBox(GDisplay *g, coord_t x, coord_t y, coord_t cx, coord_t cy, co
3411 3395
 		g->t.font = font;
3412 3396
 		g->t.clipx0 = x;
3413 3397
 		g->t.clipy0 = y;
3414
-		g->t.clipx1 = x + mf_get_string_width(font, str, 0, 0) + font->baseline_x;
3398
+		g->t.clipx1 = 32768;	//x + mf_get_string_width(font, str, 0, 0) + font->baseline_x;
3415 3399
 		g->t.clipy1 = y + font->height;
3416 3400
 		g->t.color = color;
3417 3401
 
@@ -3444,24 +3428,55 @@ void gdispGDrawBox(GDisplay *g, coord_t x, coord_t y, coord_t cx, coord_t cy, co
3444 3428
 	}
3445 3429
 
3446 3430
 	void gdispGDrawStringBox(GDisplay *g, coord_t x, coord_t y, coord_t cx, coord_t cy, const char* str, font_t font, color_t color, justify_t justify) {
3447
-		#if GDISP_NEED_TEXT_WORDWRAP
3448
-			wrapParameters_t wrapParameters;
3449
-			uint16_t nbrLines;
3450
-		#endif
3431
+		coord_t		totalHeight;
3451 3432
 
3452 3433
 		if (!font)
3453 3434
 			return;
3454 3435
 		MUTEX_ENTER(g);
3455 3436
 
3456
-		g->t.font = font;
3437
+		// Apply padding
3438
+		#if GDISP_NEED_TEXT_BOXPADLR != 0 || GDISP_NEED_TEXT_BOXPADTB != 0
3439
+			if (!(justify & justifyNoPad)) {
3440
+				#if GDISP_NEED_TEXT_BOXPADLR != 0
3441
+					x += GDISP_NEED_TEXT_BOXPADLR;
3442
+					cx -= 2*GDISP_NEED_TEXT_BOXPADLR;
3443
+				#endif
3444
+				#if GDISP_NEED_TEXT_BOXPADTB != 0
3445
+					y += GDISP_NEED_TEXT_BOXPADTB;
3446
+					cy -= 2*GDISP_NEED_TEXT_BOXPADTB;
3447
+				#endif
3448
+			}
3449
+		#endif
3450
+			
3451
+		// Save the clipping area
3457 3452
 		g->t.clipx0 = x;
3458 3453
 		g->t.clipy0 = y;
3459 3454
 		g->t.clipx1 = x+cx;
3460 3455
 		g->t.clipy1 = y+cy;
3461
-		g->t.color = color;
3462 3456
 
3463
-		/* Select the anchor position */
3464
-		switch(justify) {
3457
+		// Calculate the total text height
3458
+		#if GDISP_NEED_TEXT_WORDWRAP
3459
+			if (!(justify & justifyNoWordWrap)) {
3460
+				// Count the number of lines
3461
+				totalHeight = 0;
3462
+				mf_wordwrap(font, cx, str, mf_countline_callback, &totalHeight);
3463
+				totalHeight *= font->height;
3464
+			} else
3465
+		#endif
3466
+		totalHeight = font->height;
3467
+
3468
+		// Select the anchor position
3469
+		switch((justify & JUSTIFYMASK_TOPBOTTOM)) {
3470
+		case justifyTop:
3471
+			break;
3472
+		case justifyBottom:
3473
+			y += cy - totalHeight;
3474
+			break;
3475
+		default:	// justifyMiddle
3476
+			y += (cy+1 - totalHeight)/2;
3477
+			break;
3478
+		}
3479
+		switch((justify & JUSTIFYMASK_LEFTRIGHT)) {
3465 3480
 		case justifyCenter:
3466 3481
 			x += (cx + 1) / 2;
3467 3482
 			break;
@@ -3469,60 +3484,88 @@ void gdispGDrawBox(GDisplay *g, coord_t x, coord_t y, coord_t cx, coord_t cy, co
3469 3484
 			x += cx;
3470 3485
 			break;
3471 3486
 		default:	// justifyLeft
3472
-			x += font->baseline_x;
3473 3487
 			break;
3474 3488
 		}
3475 3489
 
3476 3490
 		/* Render */
3491
+		g->t.font = font;
3492
+		g->t.color = color;
3477 3493
 		#if GDISP_NEED_TEXT_WORDWRAP
3478
-			wrapParameters.x = x;
3479
-			wrapParameters.y = y;
3480
-			wrapParameters.font = font;
3481
-			wrapParameters.justify = justify;
3482
-			wrapParameters.g = g;
3483
-
3484
-			// Count the number of lines
3485
-			nbrLines = 0;
3486
-			mf_wordwrap(font, cx, str, mf_countline_callback, &nbrLines);
3487
-			wrapParameters.y += (cy+1 - nbrLines*font->height)/2;
3488
-			
3489
-			mf_wordwrap(font, cx, str, mf_drawline_callback, &wrapParameters);
3490
-		#else
3491
-			y += (cy+1 - font->height)/2;
3492
-			mf_render_aligned(font, x, y, justify, str, 0, drawcharglyph, g);
3494
+			if (!(justify & justifyNoWordWrap)) {
3495
+				g->t.lrj = (justify & JUSTIFYMASK_LEFTRIGHT);
3496
+				g->t.wrapx = x;
3497
+				g->t.wrapy = y;
3498
+				
3499
+				mf_wordwrap(font, cx, str, mf_drawline_callback, g);
3500
+			} else
3493 3501
 		#endif
3502
+		mf_render_aligned(font, x, y, (justify & JUSTIFYMASK_LEFTRIGHT), str, 0, drawcharglyph, g);
3494 3503
 
3495 3504
 		autoflush(g);
3496 3505
 		MUTEX_EXIT(g);
3497 3506
 	}
3498 3507
 
3499 3508
 	void gdispGFillStringBox(GDisplay *g, coord_t x, coord_t y, coord_t cx, coord_t cy, const char* str, font_t font, color_t color, color_t bgcolor, justify_t justify) {
3500
-		#if GDISP_NEED_TEXT_WORDWRAP
3501
-			wrapParameters_t wrapParameters;
3502
-			uint16_t nbrLines;
3503
-		#endif
3509
+		coord_t		totalHeight;
3504 3510
 
3505 3511
 		if (!font)
3506 3512
 			return;
3507 3513
 		MUTEX_ENTER(g);
3508 3514
 
3515
+		g->p.x = x;
3516
+		g->p.y = y;
3509 3517
 		g->p.cx = cx;
3510 3518
 		g->p.cy = cy;
3511
-		g->t.font = font;
3512
-		g->t.clipx0 = g->p.x = x;
3513
-		g->t.clipy0 = g->p.y = y;
3514
-		g->t.clipx1 = x+cx;
3515
-		g->t.clipy1 = y+cy;
3516
-		g->t.color = color;
3517
-		g->t.bgcolor = g->p.color = bgcolor;
3518 3519
 
3519 3520
 		TEST_CLIP_AREA(g) {
3520 3521
 
3521 3522
 			// background fill
3523
+			g->p.color = bgcolor;
3522 3524
 			fillarea(g);
3523 3525
 
3524
-			/* Select the anchor position */
3525
-			switch(justify) {
3526
+			// Apply padding
3527
+			#if GDISP_NEED_TEXT_BOXPADLR != 0 || GDISP_NEED_TEXT_BOXPADTB != 0
3528
+				if (!(justify & justifyNoPad)) {
3529
+					#if GDISP_NEED_TEXT_BOXPADLR != 0
3530
+						x += GDISP_NEED_TEXT_BOXPADLR;
3531
+						cx -= 2*GDISP_NEED_TEXT_BOXPADLR;
3532
+					#endif
3533
+					#if GDISP_NEED_TEXT_BOXPADTB != 0
3534
+						y += GDISP_NEED_TEXT_BOXPADTB;
3535
+						cy -= 2*GDISP_NEED_TEXT_BOXPADTB;
3536
+					#endif
3537
+				}
3538
+			#endif
3539
+			
3540
+			// Save the clipping area
3541
+			g->t.clipx0 = x;
3542
+			g->t.clipy0 = y;
3543
+			g->t.clipx1 = x+cx;
3544
+			g->t.clipy1 = y+cy;
3545
+
3546
+			// Calculate the total text height
3547
+			#if GDISP_NEED_TEXT_WORDWRAP
3548
+				if (!(justify & justifyNoWordWrap)) {
3549
+					// Count the number of lines
3550
+					totalHeight = 0;
3551
+					mf_wordwrap(font, cx, str, mf_countline_callback, &totalHeight);
3552
+					totalHeight *= font->height;
3553
+				} else
3554
+			#endif
3555
+			totalHeight = font->height;
3556
+	
3557
+			// Select the anchor position
3558
+			switch((justify & JUSTIFYMASK_TOPBOTTOM)) {
3559
+			case justifyTop:
3560
+				break;
3561
+			case justifyBottom:
3562
+				y += cy - totalHeight;
3563
+				break;
3564
+			default:	// justifyMiddle
3565
+				y += (cy+1 - totalHeight)/2;
3566
+				break;
3567
+			}
3568
+			switch((justify & JUSTIFYMASK_LEFTRIGHT)) {
3526 3569
 			case justifyCenter:
3527 3570
 				x += (cx + 1) / 2;
3528 3571
 				break;
@@ -3530,29 +3573,23 @@ void gdispGDrawBox(GDisplay *g, coord_t x, coord_t y, coord_t cx, coord_t cy, co
3530 3573
 				x += cx;
3531 3574
 				break;
3532 3575
 			default:	// justifyLeft
3533
-				x += font->baseline_x;
3534 3576
 				break;
3535 3577
 			}
3536 3578
 
3537 3579
 			/* Render */
3580
+			g->t.font = font;
3581
+			g->t.color = color;
3582
+			g->t.bgcolor = bgcolor;
3538 3583
 			#if GDISP_NEED_TEXT_WORDWRAP
3539
-				wrapParameters.x = x;
3540
-				wrapParameters.y = y;
3541
-				wrapParameters.font = font;
3542
-				wrapParameters.justify = justify;
3543
-				wrapParameters.g = g;
3544
-
3545
-
3546
-				// Count the number of lines
3547
-				nbrLines = 0;
3548
-				mf_wordwrap(font, cx, str, mf_countline_callback, &nbrLines);
3549
-				wrapParameters.y += (cy+1 - nbrLines*font->height)/2;
3550
-
3551
-				mf_wordwrap(font, cx, str, mf_fillline_callback, &wrapParameters);
3552
-			#else
3553
-				y += (cy+1 - font->height)/2;
3554
-				mf_render_aligned(font, x, y, justify, str, 0, fillcharglyph, g);
3584
+				if (!(justify & justifyNoWordWrap)) {
3585
+					g->t.lrj = (justify & JUSTIFYMASK_LEFTRIGHT);
3586
+					g->t.wrapx = x;
3587
+					g->t.wrapy = y;
3588
+					
3589
+					mf_wordwrap(font, cx, str, mf_fillline_callback, g);
3590
+				} else
3555 3591
 			#endif
3592
+			mf_render_aligned(font, x, y, (justify & JUSTIFYMASK_LEFTRIGHT), str, 0, fillcharglyph, g);
3556 3593
 		}
3557 3594
 
3558 3595
 		autoflush(g);

+ 12 - 3
src/gdisp/gdisp.h

@@ -58,10 +58,19 @@ typedef struct point {
58 58
  * @brief   Type for the text justification.
59 59
  */
60 60
 typedef enum justify {
61
-	justifyLeft = 0,		/**< Justify Left */
62
-	justifyCenter = 1,		/**< Justify Center */
63
-	justifyRight = 2		/**< Justify Right */
61
+	justifyLeft = 0x00,			/**< Justify Left (the default) */
62
+	justifyCenter = 0x01,		/**< Justify Center */
63
+	justifyRight = 0x02,		/**< Justify Right */
64
+	justifyTop = 0x10,			/**< Justify Top */
65
+	justifyMiddle = 0x00,		/**< Justify Middle (the default) */
66
+	justifyBottom = 0x20,		/**< Justify Bottom */
67
+	justifyWordWrap = 0x00,		/**< Word wrap (the default if GDISP_NEED_TEXT_WORDWRAP is on) */
68
+	justifyNoWordWrap = 0x40,	/**< No word wrap */
69
+	justifyPad = 0x00,			/**< Pad the text box (the default) */
70
+	justifyNoPad = 0x04			/**< No padding the text box */
64 71
 } justify_t;
72
+#define JUSTIFYMASK_LEFTRIGHT	(justifyLeft|justifyCenter|justifyRight)
73
+#define JUSTIFYMASK_TOPBOTTOM	(justifyTop|justifyMiddle|justifyBottom)
65 74
 
66 75
 /**
67 76
  * @enum fontmetric

+ 4 - 0
src/gdisp/gdisp_driver.h

@@ -367,6 +367,10 @@ struct GDisplay {
367 367
 			color_t		bgcolor;
368 368
 			coord_t		clipx0, clipy0;
369 369
 			coord_t		clipx1, clipy1;
370
+			#if GDISP_NEED_TEXT_WORDWRAP
371
+				coord_t		wrapx, wrapy;
372
+				justify_t	lrj;
373
+			#endif
370 374
 		} t;
371 375
 	#endif
372 376
 	#if GDISP_LINEBUF_SIZE != 0 && ((GDISP_NEED_SCROLL && !GDISP_HARDWARE_SCROLL) || (!GDISP_HARDWARE_STREAM_WRITE && GDISP_HARDWARE_BITFILLS))

+ 18 - 0
src/gdisp/gdisp_options.h

@@ -574,6 +574,24 @@
574 574
 	#ifndef GDISP_NEED_TEXT_WORDWRAP
575 575
 		#define GDISP_NEED_TEXT_WORDWRAP		FALSE
576 576
 	#endif
577
+	/**
578
+	 * @brief	Adding pixels to the left and right side of the box to pad text.
579
+	 * @details	Only has an effect with @p gdispGDrawStringBox() and @p gdispGFillStringBox()
580
+	 * @note	Can be turned off by using justifyNoPad
581
+	 * @details Defaults to 1
582
+	 */
583
+	#ifndef GDISP_NEED_TEXT_BOXPADLR
584
+		#define GDISP_NEED_TEXT_BOXPADLR		1
585
+	#endif
586
+	/**
587
+	 * @brief	Adding pixels to the top and bottom side of the box to pad text.
588
+	 * @details	Only has an effect with @p gdispGDrawStringBox() and @p gdispGFillStringBox()
589
+	 * @note	Can be turned off by using justifyNoPad
590
+	 * @details Defaults to 1
591
+	 */
592
+	#ifndef GDISP_NEED_TEXT_BOXPADTB
593
+		#define GDISP_NEED_TEXT_BOXPADTB		1
594
+	#endif
577 595
 	/**
578 596
 	 * @brief	Enable UTF-8 support for text rendering.
579 597
 	 * @details Defaults to FALSE