2019-09-03 11:58:42 +02:00
/*
* Additional procedures for vector theme support
*
* Slice , 2018
*
*/
2020-03-13 14:38:52 +01:00
2020-03-13 14:34:36 +01:00
# define TEST_MATH 0
# define TEST_SVG_IMAGE 1
# define TEST_SIZEOF 0
# define TEST_FONT 0
# define TEST_DITHER 0
2020-03-16 12:15:25 +01:00
2020-03-31 17:59:35 +02:00
# include "VectorGraphics.h"
2019-09-03 11:58:42 +02:00
2020-03-13 14:11:58 +01:00
# include "../Platform/Platform.h"
2020-03-13 14:38:52 +01:00
2019-09-03 11:58:42 +02:00
# include "nanosvg.h"
# include "FloatLib.h"
# include "lodepng.h"
2020-02-29 08:30:21 +01:00
# include "../refit/screen.h"
2020-03-12 18:45:28 +01:00
# include "../cpp_foundation/XString.h"
2019-09-03 11:58:42 +02:00
# ifndef DEBUG_ALL
# define DEBUG_VEC 1
# else
# define DEBUG_VEC DEBUG_ALL
# endif
# if DEBUG_VEC == 0
# define DBG(...)
# else
# define DBG(...) DebugLog(DEBUG_VEC, __VA_ARGS__)
# endif
2020-03-13 14:34:36 +01:00
# if USE_XTHEME
# include "XTheme.h"
2020-03-20 21:10:08 +01:00
extern XTheme ThemeX ;
2020-03-28 19:34:23 +01:00
extern CONST CHAR8 * IconsNames [ ] ;
2020-03-13 14:34:36 +01:00
# endif
2019-09-03 11:58:42 +02:00
# define NSVG_RGB(r, g, b) (((unsigned int)b) | ((unsigned int)g << 8) | ((unsigned int)r << 16))
//#define NSVG_RGBA(r, g, b, a) (((unsigned int)b) | ((unsigned int)g << 8) | ((unsigned int)r << 16) | ((unsigned int)a << 24))
extern VOID
WaitForKeyPress ( CHAR16 * Message ) ;
2020-02-17 21:41:09 +01:00
extern void DumpFloat2 ( CONST char * s , float * t , int N ) ;
2020-03-29 09:14:14 +02:00
# if !USE_XTHEME
2019-09-03 11:58:42 +02:00
extern EG_IMAGE * BackgroundImage ;
extern EG_IMAGE * Banner ;
extern EG_IMAGE * BigBack ;
extern INTN BanHeight ;
extern INTN row0TileSize ;
extern INTN row1TileSize ;
2020-03-29 09:14:14 +02:00
//extern INTN FontWidth;
# endif
2019-09-03 11:58:42 +02:00
extern UINTN NumFrames ;
extern UINTN FrameTime ;
extern BOOLEAN DayLight ;
2020-03-29 09:14:14 +02:00
textFaces textFace [ 4 ] ; //0-help 1-message 2-menu 3-test, far future it will be infinite list with id
2019-09-03 11:58:42 +02:00
NSVGparser * mainParser = NULL ; //it must be global variable
2020-03-13 14:34:36 +01:00
# if USE_XTHEME
2020-04-08 12:49:00 +02:00
EFI_STATUS XTheme : : ParseSVGXIcon ( void * parser , INTN Id , const XString & IconNameX , float iconScale , XImage * Image ) // scale renamed iconScale to not hide member var Scale
2020-03-13 14:34:36 +01:00
{
2020-03-16 12:15:25 +01:00
EFI_STATUS Status = EFI_NOT_FOUND ;
NSVGimage * SVGimage ;
2020-03-29 18:17:27 +02:00
NSVGparser * p = ( NSVGparser * ) parser ;
2020-03-16 12:15:25 +01:00
NSVGrasterizer * rast = nsvgCreateRasterizer ( ) ;
SVGimage = p - > image ;
NSVGshape * shape ;
NSVGgroup * group ;
2020-03-20 21:10:08 +01:00
NSVGimage * IconImage ;
NSVGshape * shapeNext , * shapesTail = NULL , * shapePrev ;
2020-03-29 09:14:14 +02:00
CONST CHAR8 * IconName = IconNameX . c_str ( ) ;
2020-03-16 12:15:25 +01:00
NSVGparser * p2 = nsvg__createParser ( ) ;
IconImage = p2 - > image ;
shape = SVGimage - > shapes ;
shapePrev = NULL ;
while ( shape ) {
group = shape - > group ;
shapeNext = shape - > next ;
while ( group ) {
if ( strcmp ( group - > id , IconName ) = = 0 ) {
break ;
}
group = group - > next ;
}
if ( group ) { //the shape is in the group
// keep this sample for debug purpose
2020-03-25 19:32:44 +01:00
/* DBG("found shape %s", shape->id);
DBG ( " from group %s \n " , group - > id ) ;
2020-03-16 12:15:25 +01:00
if ( ( Id = = BUILTIN_SELECTION_BIG ) | |
( Id = = BUILTIN_ICON_BACKGROUND ) | |
( Id = = BUILTIN_ICON_BANNER ) ) {
shape - > debug = TRUE ;
} */
2020-03-29 18:17:27 +02:00
if ( BootCampStyle & & ( strstr ( IconName , " selection_big " ) ! = NULL ) ) {
2020-03-16 12:15:25 +01:00
shape - > opacity = 0.f ;
}
if ( strstr ( shape - > id , " BoundingRect " ) ! = NULL ) {
//there is bounds after nsvgParse()
IconImage - > width = shape - > bounds [ 2 ] - shape - > bounds [ 0 ] ;
IconImage - > height = shape - > bounds [ 3 ] - shape - > bounds [ 1 ] ;
2020-04-09 18:32:46 +02:00
if ( IconImage - > height ! = 0 ) { // !fontSVG->unitsPerEm generate a warning
2020-03-16 12:15:25 +01:00
IconImage - > height = 200 ;
}
2020-03-29 18:17:27 +02:00
if ( ( strstr ( IconName , " selection_big " ) ! = NULL ) & & ( ! SelectionOnTop ) ) {
2020-04-08 12:49:00 +02:00
MainEntriesSize = ( int ) ( IconImage - > width * iconScale ) ; //xxx
row0TileSize = MainEntriesSize + ( int ) ( 16.f * iconScale ) ;
2020-03-29 18:17:27 +02:00
DBG ( " main entry size = %lld \n " , MainEntriesSize ) ;
2020-03-16 12:15:25 +01:00
}
2020-03-29 18:17:27 +02:00
if ( ( strstr ( IconName , " selection_small " ) ! = NULL ) & & ( ! SelectionOnTop ) ) {
2020-04-08 12:49:00 +02:00
row1TileSize = ( int ) ( IconImage - > width * iconScale ) ;
2020-03-16 12:15:25 +01:00
}
// not exclude BoundingRect from IconImage?
shape - > flags = 0 ; //invisible
if ( shapePrev ) {
shapePrev - > next = shapeNext ;
}
else {
SVGimage - > shapes = shapeNext ;
}
shape = shapeNext ;
continue ; //while(shape) it is BoundingRect shape
// shape->opacity = 0.3f;
}
shape - > flags = NSVG_VIS_VISIBLE ;
// Add to tail
// ClipCount += shape->clip.count;
if ( IconImage - > shapes = = NULL )
IconImage - > shapes = shape ;
else
shapesTail - > next = shape ;
shapesTail = shape ;
if ( shapePrev ) {
shapePrev - > next = shapeNext ;
}
else {
SVGimage - > shapes = shapeNext ;
}
shapePrev - > next = shapeNext ;
} //the shape in the group
else {
shapePrev = shape ;
}
shape = shapeNext ;
} //while shape
shapesTail - > next = NULL ;
//add clipPaths //xxx
NSVGclipPath * clipPaths = SVGimage - > clipPaths ;
NSVGclipPath * clipNext = NULL ;
while ( clipPaths ) {
// ClipCount += clipPaths->shapes->clip.count;
group = clipPaths - > shapes - > group ;
clipNext = clipPaths - > next ;
while ( group ) {
if ( strcmp ( group - > id , IconName ) = = 0 ) {
break ;
}
group = group - > parent ;
}
if ( group ) {
2020-03-25 19:32:44 +01:00
DBG ( " found clipPaths for %s \n " , IconName ) ;
2020-03-16 12:15:25 +01:00
IconImage - > clipPaths = SVGimage - > clipPaths ;
break ;
}
clipPaths = clipNext ;
}
2020-03-25 19:32:44 +01:00
// DBG("found %d clips for %s\n", ClipCount, IconName);
2020-03-16 12:15:25 +01:00
// if (ClipCount) { //Id == BUILTIN_ICON_BANNER) {
// IconImage->clipPaths = SVGimage->clipPaths;
// }
float bounds [ 4 ] ;
bounds [ 0 ] = FLT_MAX ;
bounds [ 1 ] = FLT_MAX ;
bounds [ 2 ] = - FLT_MAX ;
bounds [ 3 ] = - FLT_MAX ;
nsvg__imageBounds ( p2 , bounds ) ;
CopyMem ( IconImage - > realBounds , bounds , 4 * sizeof ( float ) ) ;
2020-03-22 11:48:13 +01:00
if ( ( Id = = BUILTIN_ICON_BANNER ) & & ( strstr ( IconName , " Banner " ) ! = NULL ) ) {
2020-04-08 12:49:00 +02:00
BannerPosX = ( int ) ( bounds [ 0 ] * iconScale - CentreShift ) ;
BannerPosY = ( int ) ( bounds [ 1 ] * iconScale ) ;
2020-03-29 18:17:27 +02:00
DBG ( " Banner position at parse [%lld,%lld] \n " , BannerPosX , BannerPosY ) ;
2020-03-22 11:48:13 +01:00
}
2020-04-08 12:49:00 +02:00
float Height = IconImage - > height * iconScale ;
float Width = IconImage - > width * iconScale ;
2020-03-26 17:49:10 +01:00
// DBG("icon %s width=%f height=%f\n", IconName, Width, Height);
2020-03-22 11:48:13 +01:00
int iWidth = ( int ) ( Width + 0.5f ) ;
int iHeight = ( int ) ( Height + 0.5f ) ;
// EG_IMAGE *NewImage = egCreateFilledImage(iWidth, iHeight, TRUE, &MenuBackgroundPixel);
XImage NewImage ( iWidth , iHeight ) ; //empty
if ( IconImage - > shapes = = NULL ) {
2020-03-29 11:40:13 +02:00
* Image = NewImage ;
2020-04-04 19:02:30 +02:00
// DBG("return empty with status=%s\n", strerror(Status));
2020-03-22 11:48:13 +01:00
return Status ;
}
2020-03-25 19:32:44 +01:00
// DBG("begin rasterize %s\n", IconName);
2020-03-22 11:48:13 +01:00
float tx = 0.f , ty = 0.f ;
if ( ( Id ! = BUILTIN_ICON_BACKGROUND ) & &
( Id ! = BUILTIN_ICON_ANIME ) & &
( strstr ( IconName , " Banner " ) = = NULL ) ) {
2020-04-08 12:49:00 +02:00
float realWidth = ( bounds [ 2 ] - bounds [ 0 ] ) * iconScale ;
float realHeight = ( bounds [ 3 ] - bounds [ 1 ] ) * iconScale ;
2020-03-22 11:48:13 +01:00
tx = ( Width - realWidth ) * 0.5f ;
ty = ( Height - realHeight ) * 0.5f ;
}
2020-04-08 12:49:00 +02:00
nsvgRasterize ( rast , IconImage , tx , ty , iconScale , iconScale , ( UINT8 * ) NewImage . GetPixelPtr ( 0 , 0 ) , iWidth , iHeight , iWidth * 4 ) ;
2020-03-25 19:32:44 +01:00
// DBG("%s rastered, blt\n", IconImage);
2020-03-22 11:48:13 +01:00
nsvgDeleteRasterizer ( rast ) ;
// nsvg__deleteParser(p2);
// nsvgDelete(p2->image);
2020-03-29 11:40:13 +02:00
* Image = NewImage ;
2020-03-16 12:15:25 +01:00
2020-03-13 14:34:36 +01:00
return EFI_SUCCESS ;
}
2020-03-27 20:47:06 +01:00
# else
2020-03-13 14:34:36 +01:00
2019-09-03 11:58:42 +02:00
2020-02-17 21:41:09 +01:00
EFI_STATUS ParseSVGIcon ( NSVGparser * p , INTN Id , CONST CHAR8 * IconName , float Scale , EG_IMAGE * * Image )
2019-09-03 11:58:42 +02:00
{
EFI_STATUS Status = EFI_NOT_FOUND ;
NSVGimage * SVGimage ;
NSVGrasterizer * rast = nsvgCreateRasterizer ( ) ;
SVGimage = p - > image ;
NSVGshape * shape ;
NSVGgroup * group ;
NSVGimage * IconImage ; // = (NSVGimage*)AllocateZeroPool(sizeof(NSVGimage));
NSVGshape * shapeNext , * shapesTail = NULL , * shapePrev ;
// INTN ClipCount = 0;
NSVGparser * p2 = nsvg__createParser ( ) ;
IconImage = p2 - > image ;
shape = SVGimage - > shapes ;
shapePrev = NULL ;
while ( shape ) {
group = shape - > group ;
shapeNext = shape - > next ;
while ( group ) {
if ( strcmp ( group - > id , IconName ) = = 0 ) {
break ;
}
group = group - > next ;
}
if ( group ) { //the shape is in the group
// keep this sample for debug purpose
2020-03-25 19:32:44 +01:00
/* DBG("found shape %s", shape->id);
DBG ( " from group %s \n " , group - > id ) ;
2019-09-03 11:58:42 +02:00
if ( ( Id = = BUILTIN_SELECTION_BIG ) | |
( Id = = BUILTIN_ICON_BACKGROUND ) | |
( Id = = BUILTIN_ICON_BANNER ) ) {
shape - > debug = TRUE ;
} */
if ( GlobalConfig . BootCampStyle & & ( strstr ( IconName , " selection_big " ) ! = NULL ) ) {
shape - > opacity = 0.f ;
}
if ( strstr ( shape - > id , " BoundingRect " ) ! = NULL ) {
//there is bounds after nsvgParse()
IconImage - > width = shape - > bounds [ 2 ] - shape - > bounds [ 0 ] ;
IconImage - > height = shape - > bounds [ 3 ] - shape - > bounds [ 1 ] ;
2020-04-05 17:23:51 +02:00
if ( IconImage - > height = = 0 ) { // doing "if (!IconImage->height)" generates a warning
2019-09-03 11:58:42 +02:00
IconImage - > height = 200 ;
}
// if (Id == BUILTIN_ICON_BACKGROUND || Id == BUILTIN_ICON_BANNER) {
// DBG("IconImage size [%d,%d]\n", (int)IconImage->width, (int)IconImage->height);
2020-03-26 17:49:10 +01:00
// DBG("IconImage left corner x=%f y=%f\n", IconImage->realBounds[0], IconImage->realBounds[1]);
2019-09-03 11:58:42 +02:00
// DumpFloat2("IconImage real bounds", IconImage->realBounds, 4);
// }
if ( ( strstr ( IconName , " selection_big " ) ! = NULL ) & & ( ! GlobalConfig . SelectionOnTop ) ) {
GlobalConfig . MainEntriesSize = ( int ) ( IconImage - > width * Scale ) ; //xxx
row0TileSize = GlobalConfig . MainEntriesSize + ( int ) ( 16.f * Scale ) ;
2020-04-04 19:02:30 +02:00
DBG ( " main entry size = %lld \n " , GlobalConfig . MainEntriesSize ) ;
2019-09-03 11:58:42 +02:00
}
if ( ( strstr ( IconName , " selection_small " ) ! = NULL ) & & ( ! GlobalConfig . SelectionOnTop ) ) {
row1TileSize = ( int ) ( IconImage - > width * Scale ) ;
}
// not exclude BoundingRect from IconImage?
shape - > flags = 0 ; //invisible
if ( shapePrev ) {
shapePrev - > next = shapeNext ;
} else {
SVGimage - > shapes = shapeNext ;
}
shape = shapeNext ;
continue ; //while(shape) it is BoundingRect shape
// shape->opacity = 0.3f;
}
shape - > flags = NSVG_VIS_VISIBLE ;
// Add to tail
// ClipCount += shape->clip.count;
if ( IconImage - > shapes = = NULL )
IconImage - > shapes = shape ;
else
shapesTail - > next = shape ;
shapesTail = shape ;
if ( shapePrev ) {
shapePrev - > next = shapeNext ;
} else {
SVGimage - > shapes = shapeNext ;
}
shapePrev - > next = shapeNext ;
} //the shape in the group
else {
shapePrev = shape ;
}
shape = shapeNext ;
} //while shape
shapesTail - > next = NULL ;
//add clipPaths //xxx
NSVGclipPath * clipPaths = SVGimage - > clipPaths ;
NSVGclipPath * clipNext = NULL ;
while ( clipPaths ) {
// ClipCount += clipPaths->shapes->clip.count;
group = clipPaths - > shapes - > group ;
clipNext = clipPaths - > next ;
while ( group ) {
if ( strcmp ( group - > id , IconName ) = = 0 ) {
break ;
}
group = group - > parent ;
}
if ( group ) {
2020-03-25 19:32:44 +01:00
DBG ( " found clipPaths for %s \n " , IconName ) ;
2019-09-03 11:58:42 +02:00
IconImage - > clipPaths = SVGimage - > clipPaths ;
break ;
}
clipPaths = clipNext ;
}
2020-03-25 19:32:44 +01:00
// DBG("found %d clips for %s\n", ClipCount, IconName);
2019-09-03 11:58:42 +02:00
// if (ClipCount) { //Id == BUILTIN_ICON_BANNER) {
// IconImage->clipPaths = SVGimage->clipPaths;
// }
float bounds [ 4 ] ;
bounds [ 0 ] = FLT_MAX ;
bounds [ 1 ] = FLT_MAX ;
bounds [ 2 ] = - FLT_MAX ;
bounds [ 3 ] = - FLT_MAX ;
nsvg__imageBounds ( p2 , bounds ) ;
CopyMem ( IconImage - > realBounds , bounds , 4 * sizeof ( float ) ) ;
if ( ( Id = = BUILTIN_ICON_BANNER ) & & ( strstr ( IconName , " Banner " ) ! = NULL ) ) {
GlobalConfig . BannerPosX = ( int ) ( bounds [ 0 ] * Scale - GlobalConfig . CentreShift ) ;
GlobalConfig . BannerPosY = ( int ) ( bounds [ 1 ] * Scale ) ;
2020-03-25 19:32:44 +01:00
DBG ( " Banner position at parse [%lld,%lld] \n " , GlobalConfig . BannerPosX , GlobalConfig . BannerPosY ) ;
2019-09-03 11:58:42 +02:00
}
float Height = IconImage - > height * Scale ;
float Width = IconImage - > width * Scale ;
2020-03-26 17:49:10 +01:00
// DBG("icon %s width=%f height=%f\n", IconName, Width, Height);
2019-09-03 11:58:42 +02:00
int iWidth = ( int ) ( Width + 0.5f ) ;
int iHeight = ( int ) ( Height + 0.5f ) ;
EG_IMAGE * NewImage = egCreateFilledImage ( iWidth , iHeight , TRUE , & MenuBackgroundPixel ) ;
if ( IconImage - > shapes = = NULL ) {
* Image = NewImage ;
return Status ;
}
2020-03-25 19:32:44 +01:00
// DBG("begin rasterize %s\n", IconName);
2019-09-03 11:58:42 +02:00
float tx = 0.f , ty = 0.f ;
if ( ( Id ! = BUILTIN_ICON_BACKGROUND ) & &
( Id ! = BUILTIN_ICON_ANIME ) & &
( strstr ( IconName , " Banner " ) = = NULL ) ) {
float realWidth = ( bounds [ 2 ] - bounds [ 0 ] ) * Scale ;
float realHeight = ( bounds [ 3 ] - bounds [ 1 ] ) * Scale ;
tx = ( Width - realWidth ) * 0.5f ;
ty = ( Height - realHeight ) * 0.5f ;
}
nsvgRasterize ( rast , IconImage , tx , ty , Scale , Scale , ( UINT8 * ) NewImage - > PixelData , iWidth , iHeight , iWidth * 4 ) ;
2020-03-25 19:32:44 +01:00
// DBG("%s rastered, blt\n", IconImage);
2019-09-03 11:58:42 +02:00
#if 0
BltImageAlpha ( NewImage ,
( int ) ( UGAWidth - NewImage - > Width ) / 2 ,
( int ) ( UGAHeight * 0.05f ) ,
& MenuBackgroundPixel ,
16 ) ;
// WaitForKeyPress(L"waiting for key press...\n");
# endif
nsvgDeleteRasterizer ( rast ) ;
// nsvg__deleteParser(p2);
// nsvgDelete(p2->image);
* Image = NewImage ;
return EFI_SUCCESS ;
}
2020-03-27 20:47:06 +01:00
# endif
2019-09-03 11:58:42 +02:00
2020-03-20 21:10:08 +01:00
2020-03-27 20:47:06 +01:00
# if USE_XTHEME
2020-03-29 18:17:27 +02:00
EFI_STATUS XTheme : : ParseSVGXTheme ( CONST CHAR8 * buffer )
2019-09-03 11:58:42 +02:00
{
2020-03-29 18:17:27 +02:00
EFI_STATUS Status ;
2019-09-03 11:58:42 +02:00
NSVGimage * SVGimage ;
2020-04-03 22:00:42 +02:00
Icons . Empty ( ) ;
2019-09-03 11:58:42 +02:00
2020-03-27 20:47:06 +01:00
// --- Parse theme.svg --- low case
2020-03-29 18:17:27 +02:00
mainParser = nsvgParse ( ( CHAR8 * ) buffer , 72 , 1.f ) ; //the buffer will be modified, it is how nanosvg works
2019-09-03 11:58:42 +02:00
SVGimage = mainParser - > image ;
if ( ! SVGimage ) {
DBG ( " Theme not parsed! \n " ) ;
return EFI_NOT_STARTED ;
}
2020-03-27 20:47:06 +01:00
// --- Get scale as theme design height vs screen height
2019-09-03 11:58:42 +02:00
// must be svg view-box
float vbx = mainParser - > viewWidth ;
float vby = mainParser - > viewHeight ;
2020-03-27 20:47:06 +01:00
DBG ( " Theme view-bounds: w=%f h=%f units=px \n " , vbx , vby ) ;
if ( vby > 1.0f ) {
SVGimage - > height = vby ;
2020-03-29 18:17:27 +02:00
} else {
2020-03-27 20:47:06 +01:00
SVGimage - > height = 768.f ; //default height
}
2020-03-29 18:17:27 +02:00
float ScaleF = UGAHeight / SVGimage - > height ;
DBG ( " using scale %f \n " , ScaleF ) ;
2020-03-31 16:25:07 +02:00
Scale = ScaleF ;
2020-03-29 18:17:27 +02:00
CentreShift = ( vbx * Scale - ( float ) UGAWidth ) * 0.5f ;
2020-03-27 20:47:06 +01:00
2020-04-04 07:50:30 +02:00
// if (mainParser->font) { //this is strange like last found font
// DBG("theme contains font-family=%s\n", mainParser->font->fontFamily);
// }
2020-03-27 20:47:06 +01:00
2020-03-29 18:17:27 +02:00
Background = XImage ( UGAWidth , UGAHeight ) ;
if ( ! BigBack . isEmpty ( ) ) {
BigBack . setEmpty ( ) ;
2020-03-27 20:47:06 +01:00
}
Status = EFI_NOT_FOUND ;
if ( ! DayLight ) {
2020-03-29 18:17:27 +02:00
Status = ParseSVGXIcon ( mainParser , BUILTIN_ICON_BACKGROUND , " Background_night " _XS , Scale , & BigBack ) ;
2020-03-27 20:47:06 +01:00
}
if ( EFI_ERROR ( Status ) ) {
2020-03-29 18:17:27 +02:00
Status = ParseSVGXIcon ( mainParser , BUILTIN_ICON_BACKGROUND , " Background " _XS , Scale , & BigBack ) ;
2020-03-27 20:47:06 +01:00
}
2020-03-31 16:25:07 +02:00
DBG ( " Background parsed [%lld, %lld] \n " , BigBack . GetWidth ( ) , BigBack . GetHeight ( ) ) ;
2020-03-27 20:47:06 +01:00
// --- Make Banner
2020-03-29 18:17:27 +02:00
Banner . setEmpty ( ) ; //for the case of theme switch
2020-03-27 20:47:06 +01:00
Status = EFI_NOT_FOUND ;
if ( ! DayLight ) {
2020-03-29 18:17:27 +02:00
Status = ParseSVGXIcon ( mainParser , BUILTIN_ICON_BANNER , " Banner_night " _XS , Scale , & Banner ) ;
2020-03-27 20:47:06 +01:00
}
if ( EFI_ERROR ( Status ) ) {
2020-03-29 18:17:27 +02:00
Status = ParseSVGXIcon ( mainParser , BUILTIN_ICON_BANNER , " Banner " _XS , Scale , & Banner ) ;
2020-03-27 20:47:06 +01:00
}
DBG ( " Banner parsed \n " ) ;
2020-03-29 18:17:27 +02:00
BanHeight = ( int ) ( Banner . GetHeight ( ) * Scale + 1.f ) ;
2020-04-04 05:46:41 +02:00
DBG ( " parsed banner->width=%lld height=%lld \n " , Banner . GetWidth ( ) , BanHeight ) ;
2020-03-27 20:47:06 +01:00
// --- Make other icons
2020-03-28 19:34:23 +01:00
2020-04-03 22:00:42 +02:00
for ( INTN i = BUILTIN_ICON_FUNC_ABOUT ; i < = BUILTIN_CHECKBOX_CHECKED ; + + i ) {
2020-04-04 05:46:41 +02:00
if ( i = = BUILTIN_ICON_BANNER ) { //exclude "logo" as it done other way
2020-03-27 20:47:06 +01:00
continue ;
}
2020-04-05 23:14:27 +02:00
Icon * NewIcon = new Icon ( i , false ) ; //initialize without embedded
2020-04-06 11:15:36 +02:00
Status = ParseSVGXIcon ( mainParser , i , NewIcon - > Name , Scale , & NewIcon - > Image ) ;
if ( EFI_ERROR ( Status ) & &
( i > = BUILTIN_ICON_VOL_INTERNAL_HFS ) & &
( i < = BUILTIN_ICON_VOL_INTERNAL_REC ) ) {
NewIcon - > Image = GetIcon ( BUILTIN_ICON_VOL_INTERNAL ) ; //copy existing
}
2020-04-04 07:50:30 +02:00
// DBG("parse %s status %s\n", NewIcon->Name.c_str(), strerror(Status));
2020-04-06 11:15:36 +02:00
Status = ParseSVGXIcon ( mainParser , i , NewIcon - > Name + " _night " _XS , Scale , & NewIcon - > ImageNight ) ;
2020-04-04 07:50:30 +02:00
// DBG("...night status %s\n", strerror(Status));
2020-04-06 11:15:36 +02:00
if ( EFI_ERROR ( Status ) & &
( i > = BUILTIN_ICON_VOL_INTERNAL_HFS ) & &
( i < = BUILTIN_ICON_VOL_INTERNAL_REC ) ) {
NewIcon - > ImageNight = GetIcon ( BUILTIN_ICON_VOL_INTERNAL ) ; //copy existing
}
2020-04-02 21:27:10 +02:00
Icons . AddReference ( NewIcon , true ) ;
2020-03-28 19:34:23 +01:00
}
2020-04-02 16:03:58 +02:00
//selections
2020-04-06 11:15:36 +02:00
SelectionBackgroundPixel . Red = ( SelectionColor > > 24 ) & 0xFF ;
SelectionBackgroundPixel . Green = ( SelectionColor > > 16 ) & 0xFF ;
SelectionBackgroundPixel . Blue = ( SelectionColor > > 8 ) & 0xFF ;
SelectionBackgroundPixel . Reserved = ( SelectionColor > > 0 ) & 0xFF ;
2020-04-02 16:03:58 +02:00
SelectionImages [ 0 ] = GetIcon ( BUILTIN_SELECTION_BIG ) ;
SelectionImages [ 2 ] = GetIcon ( BUILTIN_SELECTION_SMALL ) ;
2020-03-27 20:47:06 +01:00
2020-03-28 19:34:23 +01:00
//selection for bootcamp style
Status = EFI_NOT_FOUND ;
if ( ! DayLight ) {
2020-03-29 18:17:27 +02:00
Status = ParseSVGXIcon ( mainParser , BUILTIN_ICON_SELECTION , " selection_indicator_night " _XS , Scale , & SelectionImages [ 4 ] ) ;
2020-03-28 19:34:23 +01:00
}
if ( EFI_ERROR ( Status ) ) {
2020-03-29 18:17:27 +02:00
Status = ParseSVGXIcon ( mainParser , BUILTIN_ICON_SELECTION , " selection_indicator " _XS , Scale , & SelectionImages [ 4 ] ) ;
2020-03-28 19:34:23 +01:00
}
2020-04-04 05:46:41 +02:00
//buttons
for ( INTN i = BUILTIN_RADIO_BUTTON ; i < = BUILTIN_CHECKBOX_CHECKED ; + + i ) {
Buttons [ i - BUILTIN_RADIO_BUTTON ] = GetIcon ( i ) ;
}
2020-04-03 22:00:42 +02:00
//for (int i=0 ; i<6 ; i+=2 ) {
//SelectionImages[i].Draw(i*100, 0);
//}
2020-03-28 19:34:23 +01:00
//banner animation
GUI_ANIME * Anime = ( __typeof__ ( Anime ) ) AllocateZeroPool ( sizeof ( GUI_ANIME ) ) ;
Anime - > ID = 1 ; //main screen
//there is no Anime->Path in vectors
Anime - > Frames = NumFrames ;
Anime - > FrameTime = FrameTime ;
Anime - > Next = GuiAnime ;
Anime - > FilmX = INITVALUE ;
Anime - > FilmY = INITVALUE ;
Anime - > NudgeX = INITVALUE ;
Anime - > NudgeY = INITVALUE ;
GuiAnime = Anime ;
2020-03-29 18:17:27 +02:00
// nsvgDeleteRasterizer(rast);
2020-03-28 19:34:23 +01:00
2020-03-29 18:17:27 +02:00
TypeSVG = TRUE ;
ThemeDesignHeight = ( int ) SVGimage - > height ;
ThemeDesignWidth = ( int ) SVGimage - > width ;
if ( SelectionOnTop ) {
row0TileSize = ( INTN ) ( 144.f * Scale ) ;
row1TileSize = ( INTN ) ( 64.f * Scale ) ;
MainEntriesSize = ( INTN ) ( 128.f * Scale ) ;
2020-03-28 19:34:23 +01:00
}
2020-04-04 07:50:30 +02:00
// DBG("parsing svg theme finished\n");
2020-03-28 19:34:23 +01:00
2020-03-27 20:47:06 +01:00
return Status ;
}
# else
EFI_STATUS ParseSVGTheme ( CONST CHAR8 * buffer , TagPtr * dict )
{
EFI_STATUS Status ;
NSVGimage * SVGimage ;
NSVGrasterizer * rast = nsvgCreateRasterizer ( ) ;
// --- Parse theme.svg --- low case
mainParser = nsvgParse ( ( CHAR8 * ) buffer , 72 , 1.f ) ;
SVGimage = mainParser - > image ;
if ( ! SVGimage ) {
DBG ( " Theme not parsed! \n " ) ;
return EFI_NOT_STARTED ;
}
// --- Get scale as theme design height vs screen height
float Scale ;
// must be svg view-box
float vbx = mainParser - > viewWidth ;
float vby = mainParser - > viewHeight ;
DBG ( " Theme view-bounds: w=%d h=%d units=%s \n " , ( int ) vbx , ( int ) vby , " px " ) ;
if ( vby > 1.0f ) {
SVGimage - > height = vby ;
} else {
SVGimage - > height = 768.f ; //default height
}
2019-09-03 11:58:42 +02:00
Scale = UGAHeight / SVGimage - > height ;
2020-03-27 20:47:06 +01:00
DBG ( " using scale %f \n " , Scale ) ;
2019-09-03 11:58:42 +02:00
GlobalConfig . Scale = Scale ;
GlobalConfig . CentreShift = ( vbx * Scale - ( float ) UGAWidth ) * 0.5f ;
2020-03-27 20:47:06 +01:00
2019-09-03 11:58:42 +02:00
if ( mainParser - > font ) {
2020-03-25 19:32:44 +01:00
DBG ( " theme contains font-family=%s \n " , mainParser - > font - > fontFamily ) ;
2019-09-03 11:58:42 +02:00
}
2020-03-27 20:47:06 +01:00
// --- Make background
2019-09-03 11:58:42 +02:00
BackgroundImage = egCreateFilledImage ( UGAWidth , UGAHeight , TRUE , & BlackPixel ) ;
if ( BigBack ) {
egFreeImage ( BigBack ) ;
BigBack = NULL ;
}
Status = EFI_NOT_FOUND ;
if ( ! DayLight ) {
Status = ParseSVGIcon ( mainParser , BUILTIN_ICON_BACKGROUND , " Background_night " , Scale , & BigBack ) ;
}
if ( EFI_ERROR ( Status ) ) {
Status = ParseSVGIcon ( mainParser , BUILTIN_ICON_BACKGROUND , " Background " , Scale , & BigBack ) ;
}
DBG ( " background parsed \n " ) ;
2020-03-27 20:47:06 +01:00
// --- Make Banner
2019-09-03 11:58:42 +02:00
if ( Banner ) {
egFreeImage ( Banner ) ;
Banner = NULL ;
}
Status = EFI_NOT_FOUND ;
if ( ! DayLight ) {
Status = ParseSVGIcon ( mainParser , BUILTIN_ICON_BANNER , " Banner_night " , Scale , & Banner ) ;
}
if ( EFI_ERROR ( Status ) ) {
Status = ParseSVGIcon ( mainParser , BUILTIN_ICON_BANNER , " Banner " , Scale , & Banner ) ;
}
DBG ( " Banner parsed \n " ) ;
2020-03-27 20:47:06 +01:00
2019-09-03 11:58:42 +02:00
BuiltinIconTable [ BUILTIN_ICON_BANNER ] . Image = Banner ;
BanHeight = ( int ) ( Banner - > Height * Scale + 1.f ) ;
2020-03-27 20:47:06 +01:00
DBG ( " parsed banner->width=%lld \n " , Banner - > Width ) ;
// --- Make other icons
2019-09-03 11:58:42 +02:00
INTN i = BUILTIN_ICON_FUNC_ABOUT ;
CHAR8 * IconName ;
while ( BuiltinIconTable [ i ] . Path ) {
if ( i = = BUILTIN_ICON_BANNER ) {
i + + ;
continue ;
}
2020-02-17 21:41:09 +01:00
CONST CHAR16 * IconPath = BuiltinIconTable [ i ] . Path ;
2020-03-27 20:47:06 +01:00
// DBG("next table icon=%ls\n", IconPath);
2020-02-17 21:41:09 +01:00
CONST CHAR16 * ptr = StrStr ( IconPath , L " \\ " ) ;
2019-09-03 11:58:42 +02:00
if ( ! ptr ) {
ptr = IconPath ;
} else {
ptr + + ;
}
2020-03-27 20:47:06 +01:00
// DBG("next icon=%ls Len=%d\n", ptr, StrLen(ptr));
2019-09-03 11:58:42 +02:00
UINTN Size = StrLen ( ptr ) + 1 ;
2019-12-21 01:31:49 +01:00
IconName = ( __typeof__ ( IconName ) ) AllocateZeroPool ( Size ) ;
2019-09-03 11:58:42 +02:00
UnicodeStrToAsciiStrS ( ptr , IconName , Size ) ;
2020-03-27 20:47:06 +01:00
// DBG("search for icon name %s\n", IconName);
2019-09-03 11:58:42 +02:00
CHAR8 IconNight [ 64 ] ;
AsciiStrCpyS ( IconNight , 64 , IconName ) ;
AsciiStrCatS ( IconNight , 64 , " _night " ) ;
Status = EFI_NOT_FOUND ;
if ( ! DayLight ) {
Status = ParseSVGIcon ( mainParser , i , IconNight , Scale , & BuiltinIconTable [ i ] . Image ) ;
}
if ( EFI_ERROR ( Status ) ) {
Status = ParseSVGIcon ( mainParser , i , IconName , Scale , & BuiltinIconTable [ i ] . Image ) ;
}
if ( EFI_ERROR ( Status ) ) {
2020-03-27 20:47:06 +01:00
DBG ( " icon %lld not parsed take common %ls \n " , i , BuiltinIconTable [ i ] . Path ) ;
2019-09-03 11:58:42 +02:00
if ( ( i > = BUILTIN_ICON_VOL_EXTERNAL ) & & ( i < = BUILTIN_ICON_VOL_INTERNAL_REC ) ) {
if ( BuiltinIconTable [ BUILTIN_ICON_VOL_INTERNAL ] . Image ) {
BuiltinIconTable [ i ] . Image = egCopyImage ( BuiltinIconTable [ BUILTIN_ICON_VOL_INTERNAL ] . Image ) ;
}
}
}
if ( i = = BUILTIN_SELECTION_BIG ) {
2020-03-27 20:47:06 +01:00
DBG ( " icon main size=[%lld,%lld] \n " , BuiltinIconTable [ i ] . Image - > Width ,
2019-09-03 11:58:42 +02:00
BuiltinIconTable [ i ] . Image - > Height ) ;
}
i + + ;
FreePool ( IconName ) ;
}
2020-03-27 20:47:06 +01:00
2019-09-03 11:58:42 +02:00
// OS icons and buttons
i = 0 ;
while ( OSIconsTable [ i ] . name ) {
CHAR8 IconNight [ 64 ] ;
AsciiStrCpyS ( IconNight , 64 , OSIconsTable [ i ] . name ) ;
AsciiStrCatS ( IconNight , 64 , " _night " ) ;
OSIconsTable [ i ] . image = NULL ;
2020-03-27 20:47:06 +01:00
// DBG("search for %s\n", OSIconsTable[i].name);
2019-09-03 11:58:42 +02:00
Status = EFI_NOT_FOUND ;
if ( ! DayLight ) {
Status = ParseSVGIcon ( mainParser , i , IconNight , Scale , & OSIconsTable [ i ] . image ) ;
}
if ( EFI_ERROR ( Status ) ) {
Status = ParseSVGIcon ( mainParser , i , OSIconsTable [ i ] . name , Scale , & OSIconsTable [ i ] . image ) ;
}
if ( EFI_ERROR ( Status ) ) {
2020-03-25 19:32:44 +01:00
DBG ( " OSicon %s not parsed \n " , OSIconsTable [ i ] . name ) ;
2019-09-03 11:58:42 +02:00
if ( ( i > 0 ) & & ( i < 13 ) ) {
if ( OSIconsTable [ 0 ] . image ) {
OSIconsTable [ i ] . image = egCopyImage ( OSIconsTable [ 0 ] . image ) ;
}
} else if ( i < 18 ) {
if ( OSIconsTable [ 13 ] . image ) {
OSIconsTable [ i ] . image = egCopyImage ( OSIconsTable [ 13 ] . image ) ;
}
}
}
i + + ;
}
2020-03-27 20:47:06 +01:00
2019-09-03 11:58:42 +02:00
//selection for bootcamp style
Status = EFI_NOT_FOUND ;
if ( ! DayLight ) {
Status = ParseSVGIcon ( mainParser , BUILTIN_ICON_SELECTION , " selection_indicator_night " , Scale , & SelectionImages [ 4 ] ) ;
}
if ( EFI_ERROR ( Status ) ) {
Status = ParseSVGIcon ( mainParser , BUILTIN_ICON_SELECTION , " selection_indicator " , Scale , & SelectionImages [ 4 ] ) ;
}
2020-03-27 20:47:06 +01:00
2019-09-03 11:58:42 +02:00
//banner animation
2019-12-21 01:31:49 +01:00
GUI_ANIME * Anime = ( __typeof__ ( Anime ) ) AllocateZeroPool ( sizeof ( GUI_ANIME ) ) ;
2019-09-03 11:58:42 +02:00
Anime - > ID = 1 ; //main screen
2020-03-27 20:47:06 +01:00
//there is no Anime->Path in vectors
2019-09-03 11:58:42 +02:00
Anime - > Frames = NumFrames ;
Anime - > FrameTime = FrameTime ;
Anime - > Next = GuiAnime ;
Anime - > FilmX = INITVALUE ;
Anime - > FilmY = INITVALUE ;
Anime - > NudgeX = INITVALUE ;
Anime - > NudgeY = INITVALUE ;
GuiAnime = Anime ;
2020-03-27 20:47:06 +01:00
2019-09-03 11:58:42 +02:00
nsvgDeleteRasterizer ( rast ) ;
2020-03-27 20:47:06 +01:00
2020-02-21 22:22:30 +01:00
* dict = ( __typeof_am__ ( * dict ) ) AllocateZeroPool ( sizeof ( TagStruct ) ) ;
2019-09-03 11:58:42 +02:00
( * dict ) - > type = kTagTypeNone ;
GlobalConfig . TypeSVG = TRUE ;
GlobalConfig . ThemeDesignHeight = ( int ) SVGimage - > height ;
GlobalConfig . ThemeDesignWidth = ( int ) SVGimage - > width ;
if ( GlobalConfig . SelectionOnTop ) {
row0TileSize = ( INTN ) ( 144.f * Scale ) ;
row1TileSize = ( INTN ) ( 64.f * Scale ) ;
GlobalConfig . MainEntriesSize = ( INTN ) ( 128.f * Scale ) ;
}
DBG ( " parsing theme finish \n " ) ;
2020-03-29 07:42:33 +02:00
2019-09-03 11:58:42 +02:00
return EFI_SUCCESS ;
}
2020-03-13 14:34:36 +01:00
# endif
2020-03-29 18:17:27 +02:00
# if USE_XTHEME
EG_IMAGE * LoadSvgFrame ( INTN i )
{
// EG_IMAGE *Frame = NULL;
XImage XFrame ;
EFI_STATUS Status ;
// CHAR8 FrameName[64];
XString XFrameName ( " frame_ " _XS ) ;
//TODO if extend SVG syntax then we can use dynamic SVG with parameter Frame
// for example use variable instead of constant like javascript
XFrameName + = SPrintf ( " %lld " , i + 1 ) ;
// printf(FrameName, 63, "frame_%lld", i+1);
Status = ThemeX . ParseSVGXIcon ( mainParser , BUILTIN_ICON_ANIME , XFrameName , ThemeX . Scale , & XFrame ) ;
if ( EFI_ERROR ( Status ) ) {
DBG ( " icon '%s' not loaded, status=%s \n " , XFrameName . c_str ( ) , strerror ( Status ) ) ;
}
return XFrame . ToEGImage ( ) ;
}
# else
2019-09-03 11:58:42 +02:00
EG_IMAGE * LoadSvgFrame ( INTN i )
{
EG_IMAGE * Frame = NULL ;
EFI_STATUS Status ;
CHAR8 FrameName [ 64 ] ;
2020-03-20 18:48:19 +01:00
//TODO if extend SVG syntax then we can use dynamic SVG with parameter Frame
// for example use variable instead of constant like javascript
2020-03-29 15:44:08 +02:00
snprintf ( FrameName , 63 , " frame_%lld " , i + 1 ) ;
2019-09-03 11:58:42 +02:00
Status = ParseSVGIcon ( mainParser , BUILTIN_ICON_ANIME , FrameName , GlobalConfig . Scale , & Frame ) ;
if ( EFI_ERROR ( Status ) ) {
2020-03-25 19:32:44 +01:00
DBG ( " icon '%s' not loaded, status=%s \n " , FrameName , strerror ( Status ) ) ;
2019-09-03 11:58:42 +02:00
}
return Frame ;
}
2020-03-29 18:17:27 +02:00
# endif
2019-09-03 11:58:42 +02:00
2020-03-21 08:34:28 +01:00
// it is not draw, it is render and mainly used in egRenderText
2020-03-29 18:17:27 +02:00
// which is used in icns.cpp as an icon replacement if no image found, looks like not used
2020-03-21 08:34:28 +01:00
// in menu.cpp 3 places
2019-09-03 11:58:42 +02:00
//textType = 0-help 1-message 2-menu 3-test
//return text width in pixels
2020-03-20 21:10:08 +01:00
# if USE_XTHEME
2020-03-31 17:59:35 +02:00
INTN renderSVGtext ( XImage * TextBufferXY_ptr , INTN posX , INTN posY , INTN textType , const XStringW & string , UINTN Cursor )
2020-03-20 21:10:08 +01:00
{
2020-03-31 17:59:35 +02:00
XImage & TextBufferXY = * TextBufferXY_ptr ;
2020-03-20 21:10:08 +01:00
INTN Width ;
UINTN i ;
UINTN len ;
NSVGparser * p ;
NSVGrasterizer * rast ;
if ( ! textFace [ textType ] . valid ) {
for ( i = 0 ; i < 4 ; i + + ) {
if ( textFace [ i ] . valid ) {
textType = i ;
break ;
}
}
}
if ( ! textFace [ textType ] . valid ) {
DBG ( " valid fontface not found! \n " ) ;
return 0 ;
}
NSVGfont * fontSVG = textFace [ textType ] . font ;
UINT32 color = textFace [ textType ] . color ;
2020-03-26 09:18:28 +01:00
INTN Height = ( INTN ) ( textFace [ textType ] . size * ThemeX . Scale ) ;
2020-03-20 21:10:08 +01:00
float Scale , sy ;
float x , y ;
if ( ! fontSVG ) {
2020-03-21 08:34:28 +01:00
DBG ( " no font for renderSVGtext \n " ) ;
2020-03-20 21:10:08 +01:00
return 0 ;
}
p = nsvg__createParser ( ) ;
if ( ! p ) {
return 0 ;
}
NSVGtext * text = ( NSVGtext * ) AllocateZeroPool ( sizeof ( NSVGtext ) ) ;
if ( ! text ) {
return 0 ;
}
text - > font = fontSVG ;
text - > fontColor = color ;
text - > fontSize = ( float ) Height ;
nsvg__xformIdentity ( text - > xform ) ;
p - > text = text ;
2020-04-09 18:32:46 +02:00
len = string . size ( ) ;
2020-03-20 21:10:08 +01:00
Width = TextBufferXY . GetWidth ( ) ;
2020-04-09 18:32:46 +02:00
if ( fontSVG - > unitsPerEm ! = 0 ) { // !fontSVG->unitsPerEm generate a warning
2020-03-20 21:10:08 +01:00
fontSVG - > unitsPerEm = 1000.f ;
}
float fH = fontSVG - > bbox [ 3 ] - fontSVG - > bbox [ 1 ] ; //1250
if ( fH = = 0.f ) {
2020-03-26 18:00:53 +01:00
DBG ( " wrong font: %f \n " , fontSVG - > unitsPerEm ) ;
2020-03-20 21:10:08 +01:00
DumpFloat2 ( " Font bbox " , fontSVG - > bbox , 4 ) ;
2020-04-09 18:32:46 +02:00
fH = fontSVG - > unitsPerEm ! = 0 ? fontSVG - > unitsPerEm : 1000.0f ; //1000
2020-03-20 21:10:08 +01:00
}
sy = ( float ) Height / fH ; //(float)fontSVG->unitsPerEm; // 260./1250.
Scale = sy ;
x = ( float ) posX ; //0.f;
y = ( float ) posY + fontSVG - > bbox [ 1 ] * Scale ;
p - > isText = TRUE ;
for ( i = 0 ; i < len ; i + + ) {
2020-04-09 18:32:46 +02:00
CHAR16 letter = string . wc_str ( ) [ i ] ;
2020-03-20 21:10:08 +01:00
if ( ! letter ) {
break ;
}
2020-03-25 19:32:44 +01:00
// DBG("add letter 0x%X\n", letter);
2020-03-20 21:10:08 +01:00
if ( i = = Cursor ) {
addLetter ( p , 0x5F , x , y , sy , color ) ;
}
x = addLetter ( p , letter , x , y , sy , color ) ;
} //end of string
p - > image - > realBounds [ 0 ] = fontSVG - > bbox [ 0 ] * Scale ;
p - > image - > realBounds [ 1 ] = fontSVG - > bbox [ 1 ] * Scale ;
p - > image - > realBounds [ 2 ] = fontSVG - > bbox [ 2 ] * Scale + x ; //last bound
p - > image - > realBounds [ 3 ] = fontSVG - > bbox [ 3 ] * Scale ;
rast = nsvgCreateRasterizer ( ) ;
nsvgRasterize ( rast , p - > image , 0 , 0 , 1.f , 1.f , ( UINT8 * ) TextBufferXY . GetPixelPtr ( 0 , 0 ) ,
2020-03-22 11:48:13 +01:00
( int ) TextBufferXY . GetWidth ( ) , ( int ) TextBufferXY . GetHeight ( ) , ( int ) ( Width * 4 ) ) ;
2020-03-20 21:10:08 +01:00
float RealWidth = p - > image - > realBounds [ 2 ] - p - > image - > realBounds [ 0 ] ;
nsvgDeleteRasterizer ( rast ) ;
// nsvg__deleteParser(p);
nsvgDelete ( p - > image ) ;
return ( INTN ) RealWidth ; //x;
}
# else
2020-03-21 08:34:28 +01:00
INTN renderSVGtext ( EG_IMAGE * TextBufferXY , INTN posX , INTN posY , INTN textType , CONST CHAR16 * string , UINTN Cursor )
2019-09-03 11:58:42 +02:00
{
INTN Width ;
UINTN i ;
UINTN len ;
NSVGparser * p ;
NSVGrasterizer * rast ;
if ( ! textFace [ textType ] . valid ) {
for ( i = 0 ; i < 4 ; i + + ) {
if ( textFace [ i ] . valid ) {
textType = i ;
break ;
}
}
}
if ( ! textFace [ textType ] . valid ) {
DBG ( " valid fontface not found! \n " ) ;
return 0 ;
}
NSVGfont * fontSVG = textFace [ textType ] . font ;
UINT32 color = textFace [ textType ] . color ;
INTN Height = ( INTN ) ( textFace [ textType ] . size * GlobalConfig . Scale ) ;
float Scale , sy ;
float x , y ;
if ( ! fontSVG ) {
2020-03-21 08:34:28 +01:00
DBG ( " no font for renderSVGtext \n " ) ;
2019-09-03 11:58:42 +02:00
return 0 ;
}
if ( ! TextBufferXY ) {
DBG ( " no buffer \n " ) ;
return 0 ;
}
p = nsvg__createParser ( ) ;
if ( ! p ) {
return 0 ;
}
NSVGtext * text = ( NSVGtext * ) AllocateZeroPool ( sizeof ( NSVGtext ) ) ;
if ( ! text ) {
return 0 ;
}
text - > font = fontSVG ;
text - > fontColor = color ;
text - > fontSize = ( float ) Height ;
nsvg__xformIdentity ( text - > xform ) ;
p - > text = text ;
len = StrLen ( string ) ;
Width = TextBufferXY - > Width ;
// Height = TextBufferXY->Height;
// DBG("Text Height=%d Buffer Height=%d\n", Height, TextBufferXY->Height);
// Height = 180; //for test
// DBG("textBuffer: [%d,%d], fontUnits=%d\n", Width, TextBufferXY->Height, (int)fontSVG->unitsPerEm);
2020-04-05 17:23:51 +02:00
if ( fontSVG - > unitsPerEm = = 0 ) { // doing "if (!fontSVG->unitsPerEm)" generates a warning
2019-09-03 11:58:42 +02:00
fontSVG - > unitsPerEm = 1000.f ;
}
float fH = fontSVG - > bbox [ 3 ] - fontSVG - > bbox [ 1 ] ; //1250
if ( fH = = 0.f ) {
2020-04-05 17:23:51 +02:00
DBG ( " wrong font: %f \n " , fontSVG - > unitsPerEm ) ;
2019-09-03 11:58:42 +02:00
DumpFloat2 ( " Font bbox " , fontSVG - > bbox , 4 ) ;
2020-04-05 17:23:51 +02:00
fH = fontSVG - > unitsPerEm ! = 0 ? fontSVG - > unitsPerEm : 1000.0f ; //1000 // using "fontSVG->unitsPerEm != 0" instead of just is to avoid a warning
2019-09-03 11:58:42 +02:00
}
sy = ( float ) Height / fH ; //(float)fontSVG->unitsPerEm; // 260./1250.
//in font units
// float fW = fontSVG->bbox[2] - fontSVG->bbox[0];
// sx = (float)Width / (fW * len);
// Scale = (sx > sy)?sy:sx;
Scale = sy ;
x = ( float ) posX ; //0.f;
y = ( float ) posY + fontSVG - > bbox [ 1 ] * Scale ;
p - > isText = TRUE ;
2020-03-25 19:32:44 +01:00
//DBG("renderSVGtext -> Enter. Text=%s\n", XString(string).c);
2019-09-03 11:58:42 +02:00
for ( i = 0 ; i < len ; i + + ) {
2020-03-12 18:45:28 +01:00
CHAR16 letter = string [ i ] ;
2019-09-03 11:58:42 +02:00
if ( ! letter ) {
break ;
}
2020-03-25 19:32:44 +01:00
// DBG("add letter 0x%X\n", letter);
2019-09-03 11:58:42 +02:00
if ( i = = Cursor ) {
addLetter ( p , 0x5F , x , y , sy , color ) ;
}
x = addLetter ( p , letter , x , y , sy , color ) ;
2020-03-26 13:59:20 +01:00
// DBG("next x=%ls\n", x);
2019-09-03 11:58:42 +02:00
} //end of string
p - > image - > realBounds [ 0 ] = fontSVG - > bbox [ 0 ] * Scale ;
p - > image - > realBounds [ 1 ] = fontSVG - > bbox [ 1 ] * Scale ;
p - > image - > realBounds [ 2 ] = fontSVG - > bbox [ 2 ] * Scale + x ; //last bound
p - > image - > realBounds [ 3 ] = fontSVG - > bbox [ 3 ] * Scale ;
2020-03-26 17:49:10 +01:00
// DBG("internal Scale=%lf\n", Scale);
2019-09-03 11:58:42 +02:00
// DumpFloat2("text bounds", p->image->realBounds, 4);
//We made an image, then rasterize it
rast = nsvgCreateRasterizer ( ) ;
2020-03-26 13:59:20 +01:00
// DBG("begin raster text, scale=%ls\n", Scale);
2019-09-03 11:58:42 +02:00
nsvgRasterize ( rast , p - > image , 0 , 0 , 1.f , 1.f , ( UINT8 * ) TextBufferXY - > PixelData ,
( int ) TextBufferXY - > Width , ( int ) TextBufferXY - > Height , ( int ) ( Width * 4 ) ) ;
float RealWidth = p - > image - > realBounds [ 2 ] - p - > image - > realBounds [ 0 ] ;
// DBG("end raster text\n");
nsvgDeleteRasterizer ( rast ) ;
// nsvg__deleteParser(p);
nsvgDelete ( p - > image ) ;
return ( INTN ) RealWidth ; //x;
}
2020-03-20 21:10:08 +01:00
# endif
2019-09-03 11:58:42 +02:00
VOID testSVG ( )
{
do {
EFI_STATUS Status ;
UINT8 * FileData = NULL ;
UINTN FileDataLength = 0 ;
INTN Width = 400 , Height = 400 ;
# if TEST_MATH
//Test mathematique
//#define fabsf(x) ((x >= 0.0f)?x:(-x))
# define pr(x) (int)fabsf(x), (int)fabsf((x - (int)x) * 1000000.0f)
int i ;
float x , y1 , y2 ;
// CHAR8 Str[128];
DBG ( " Test float: -%d.%06d \n " , pr ( - 0.7612f ) ) ;
for ( i = 0 ; i < 15 ; i + + ) {
x = ( PI ) / 30.0f * i ;
y1 = SinF ( x ) ;
y2 = CosF ( x ) ;
DBG ( " x=%d: %d.%06d " , i * 6 , pr ( x ) ) ;
DBG ( " sinx=%c%d.%06d " , ( y1 < 0 ) ? ' - ' : ' ' , pr ( y1 ) ) ;
DBG ( " cosx=%c%d.%06d \n " , ( y2 < 0 ) ? ' - ' : ' ' , pr ( y2 ) ) ;
y1 = Atan2F ( y1 , y2 ) ;
DBG ( " atan2x=%c%d.%06d " , ( y1 < 0 ) ? ' - ' : ' ' , pr ( y1 ) ) ;
y1 = AcosF ( y2 ) ;
DBG ( " acos=%c%d.%06d " , ( y1 < 0 ) ? ' - ' : ' ' , pr ( y1 ) ) ;
y1 = SqrtF ( x ) ;
DBG ( " sqrt=%d.%06d " , pr ( y1 ) ) ;
y1 = CeilF ( x ) ;
DBG ( " ceil=%c%d.%06d \n " , ( y1 < 0 ) ? ' - ' : ' ' , pr ( y1 ) ) ;
}
# undef pr
# endif
NSVGparser * p ;
# if TEST_DITHER
{
EG_IMAGE * RndImage = egCreateImage ( 256 , 256 , FALSE ) ;
INTN i , j ;
EG_PIXEL pixel = WhitePixel ;
for ( i = 0 ; i < 256 ; i + + ) {
for ( j = 0 ; j < 256 ; j + + ) {
pixel . b = 0x40 + ( dither ( ( float ) j / 32.0f , 1 ) * 8 ) ;
pixel . r = 0x0 ;
pixel . g = 0x0 ;
// if (i==1) {
2020-03-25 19:32:44 +01:00
// DBG("r=%X g=%X\n", pixel.r, pixel.g);
2019-09-03 11:58:42 +02:00
// }
RndImage - > PixelData [ i * 256 + j ] = pixel ;
}
}
BltImageAlpha ( RndImage ,
20 ,
20 ,
& MenuBackgroundPixel ,
16 ) ;
}
# endif
# if TEST_SVG_IMAGE
NSVGrasterizer * rast = nsvgCreateRasterizer ( ) ;
2020-04-01 14:57:32 +02:00
// EG_IMAGE *NewImage;
2019-09-03 11:58:42 +02:00
NSVGimage * SVGimage ;
float Scale , ScaleX , ScaleY ;
// load file
Status = egLoadFile ( SelfRootDir , L " Sample.svg " , & FileData , & FileDataLength ) ;
if ( ! EFI_ERROR ( Status ) ) {
//Parse XML to vector data
p = nsvgParse ( ( CHAR8 * ) FileData , 72 , 1.f ) ;
SVGimage = p - > image ;
DBG ( " Test image width=%d heigth=%d \n " , ( int ) ( SVGimage - > width ) , ( int ) ( SVGimage - > height ) ) ;
// FreePool(FileData);
/*
if ( p - > patterns & & p - > patterns - > image ) {
BltImageAlpha ( ( EG_IMAGE * ) ( p - > patterns - > image ) ,
40 ,
40 ,
& MenuBackgroundPixel ,
16 ) ;
}
*/
// Rasterize
2020-04-01 14:57:32 +02:00
# if USE_XTHEME
XImage NewImage ( Width , Height ) ;
# else
EG_IMAGE * NewImage = egCreateFilledImage ( Width , Height , TRUE , & MenuBackgroundPixel ) ;
# endif
2019-09-03 11:58:42 +02:00
if ( SVGimage - > width < = 0 ) SVGimage - > width = ( float ) Width ;
if ( SVGimage - > height < = 0 ) SVGimage - > height = ( float ) Height ;
ScaleX = Width / SVGimage - > width ;
ScaleY = Height / SVGimage - > height ;
Scale = ( ScaleX > ScaleY ) ? ScaleY : ScaleX ;
float tx = 0 ; //-SVGimage->realBounds[0] * Scale;
float ty = 0 ; //-SVGimage->realBounds[1] * Scale;
2020-03-26 13:59:20 +01:00
DBG ( " timing rasterize start tx=%f ty=%f \n " , tx , ty ) ;
2020-04-01 14:57:32 +02:00
# if USE_XTHEME
nsvgRasterize ( rast , SVGimage , tx , ty , Scale , Scale , ( UINT8 * ) NewImage . GetPixelPtr ( 0 , 0 ) , ( int ) Width , ( int ) Height , ( int ) Width * 4 ) ;
DBG ( " timing rasterize end \n " ) ;
NewImage . Draw ( ( UGAWidth - Width ) / 2 ,
( UGAHeight - Height ) / 2 ) ;
# else
2019-09-03 11:58:42 +02:00
nsvgRasterize ( rast , SVGimage , tx , ty , Scale , Scale , ( UINT8 * ) NewImage - > PixelData , ( int ) Width , ( int ) Height , ( int ) Width * 4 ) ;
DBG ( " timing rasterize end \n " ) ;
//now show it!
2020-03-06 15:02:06 +01:00
XImage NewX ( NewImage ) ;
NewX . Draw ( ( UGAWidth - Width ) / 2 ,
2020-03-25 18:49:01 +01:00
( UGAHeight - Height ) / 2 ) ;
2020-04-01 14:57:32 +02:00
egFreeImage ( NewImage ) ;
2020-03-06 15:02:06 +01:00
# endif //test XImage
2019-09-03 11:58:42 +02:00
FreePool ( FileData ) ;
FileData = NULL ;
2020-04-01 14:57:32 +02:00
//
2020-03-10 14:00:02 +01:00
// nsvg__deleteParser(p);
2019-09-03 11:58:42 +02:00
nsvgDeleteRasterizer ( rast ) ;
2020-03-06 15:02:06 +01:00
2019-09-03 11:58:42 +02:00
}
2020-03-06 15:02:06 +01:00
2019-09-03 11:58:42 +02:00
# endif
//Test text
Height = 80 ;
Width = UGAWidth - 200 ;
2020-04-04 07:50:30 +02:00
// DBG("create test textbuffer\n");
2020-03-21 08:34:28 +01:00
# if USE_XTHEME
XImage TextBufferXY ( Width , Height ) ;
# else
2019-09-03 11:58:42 +02:00
EG_IMAGE * TextBufferXY = egCreateFilledImage ( Width , Height , TRUE , & MenuBackgroundPixel ) ;
2020-03-21 08:34:28 +01:00
# endif
2019-09-03 11:58:42 +02:00
Status = egLoadFile ( SelfRootDir , L " Font.svg " , & FileData , & FileDataLength ) ;
2020-03-25 19:32:44 +01:00
DBG ( " test Font.svg loaded status=%s \n " , strerror ( Status ) ) ;
2019-09-03 11:58:42 +02:00
if ( ! EFI_ERROR ( Status ) ) {
p = nsvgParse ( ( CHAR8 * ) FileData , 72 , 1.f ) ;
if ( ! p ) {
DBG ( " font not parsed \n " ) ;
break ;
}
// NSVGfont* fontSVG = p->font;
textFace [ 3 ] . font = p - > font ;
textFace [ 3 ] . color = NSVG_RGBA ( 0x80 , 0xFF , 0 , 255 ) ;
textFace [ 3 ] . size = Height ;
2020-03-25 19:32:44 +01:00
// DBG("font parsed family=%s\n", p->font->fontFamily);
2019-09-03 11:58:42 +02:00
FreePool ( FileData ) ;
// Scale = Height / fontSVG->unitsPerEm;
2020-03-21 08:34:28 +01:00
# if USE_XTHEME
2020-03-31 17:59:35 +02:00
renderSVGtext ( & TextBufferXY , 0 , 0 , 3 , XStringW ( ) . takeValueFrom ( " Clover Кловер " ) , 1 ) ;
2020-03-21 08:34:28 +01:00
# else
renderSVGtext ( TextBufferXY , 0 , 0 , 3 , L " Clover Кловер " , 1 ) ;
# endif
2019-09-03 11:58:42 +02:00
// DBG("text ready to blit\n");
2020-03-21 08:34:28 +01:00
# if USE_XTHEME
TextBufferXY . Draw ( ( UGAWidth - Width ) / 2 ,
2020-03-25 18:49:01 +01:00
( UGAHeight - Height ) / 2 ) ;
2020-03-21 08:34:28 +01:00
# else
2019-09-03 11:58:42 +02:00
BltImageAlpha ( TextBufferXY ,
( UGAWidth - Width ) / 2 ,
( UGAHeight - Height ) / 2 ,
& MenuBackgroundPixel ,
16 ) ;
egFreeImage ( TextBufferXY ) ;
2020-03-21 08:34:28 +01:00
# endif
2019-09-03 11:58:42 +02:00
// nsvg__deleteParser(p);
// DBG("draw finished\n");
}
} while ( 0 ) ;
}