Fix nanosvg leaks.

Move global variable textfaces in XTheme.
Move global variable fontsDB in XTheme.
Remove XTheme member SVGParser. SVGParser is deleted just after use.
Remove XTheme members ImageSVG and ImageSVGnight. All images are
rasterized at load, so no need to keep that.
Remove XIcon setFilled because XIcon knows if it's filled or not by
checking Image & ImageNight
This commit is contained in:
jief 2023-11-08 14:35:22 +01:00
parent 8de61a22fb
commit 42cece9885
21 changed files with 479 additions and 536 deletions

View File

@ -10,7 +10,11 @@
// Mem log sizes
//
#define MEM_LOG_INITIAL_SIZE (128 * 1024)
#ifdef JIEF_DEBUG
#define MEM_LOG_MAX_SIZE (10 * 1024 * 1024)
#else
#define MEM_LOG_MAX_SIZE (2 * 1024 * 1024)
#endif
#define MEM_LOG_MAX_LINE_SIZE 1024

View File

@ -457,6 +457,7 @@ static void transmitS8Printf(const char* buf, unsigned int nbchar, void* context
// but not too big (if something gets out of controll)
if (mMemLog->BufferSize + MEM_LOG_INITIAL_SIZE > MEM_LOG_MAX_SIZE) {
// Out of resources!
// Jief : Silent fail. TODO : At least put "Out of resource" at the end of the log
return;
}
Offset = mMemLog->Cursor - mMemLog->Buffer;

View File

@ -115,14 +115,10 @@ const SETTINGS_DATA::SmbiosClass::SlotDeviceClass SETTINGS_DATA::SmbiosClass::Sl
CUSTOM_LOADER_ENTRY::CUSTOM_LOADER_ENTRY(const CUSTOM_LOADER_ENTRY_SETTINGS& _settings) : settings(_settings)
{
if ( settings.ImageData.notEmpty() ) {
if ( !EFI_ERROR(Image.Image.FromPNG(settings.ImageData.data(), settings.ImageData.size())) ) {
Image.setFilled();
}
Image.Image.FromPNG(settings.ImageData.data(), settings.ImageData.size());
}
if ( settings.DriveImageData.notEmpty() ) {
if ( !EFI_ERROR(DriveImage.Image.FromPNG(settings.DriveImageData.data(), settings.DriveImageData.size())) ) {
DriveImage.setFilled();
}
DriveImage.Image.FromPNG(settings.DriveImageData.data(), settings.DriveImageData.size());
}
if ( settings.CustomLogoTypeSettings == CUSTOM_BOOT_USER && settings.CustomLogoAsXString8.notEmpty() ) {

View File

@ -473,16 +473,12 @@ public:
if ( settings.ImagePath.notEmpty() ) {
Image.LoadXImage(&ThemeDir, settings.ImagePath);
}else if ( settings.ImageData.notEmpty() ) {
if ( !EFI_ERROR(Image.Image.FromPNG(settings.ImageData.data(), settings.ImageData.size())) ) {
Image.setFilled();
}
Image.Image.FromPNG(settings.ImageData.data(), settings.ImageData.size());
}
if ( settings.DriveImagePath.notEmpty() ) {
DriveImage.LoadXImage(&ThemeDir, settings.DriveImagePath);
}else if ( settings.DriveImageData.notEmpty() ) {
if ( !EFI_ERROR(DriveImage.Image.FromPNG(settings.DriveImageData.data(), settings.DriveImageData.size())) ) {
DriveImage.setFilled();
}
DriveImage.Image.FromPNG(settings.DriveImageData.data(), settings.DriveImageData.size());
}
}
@ -560,9 +556,7 @@ public:
if ( settings.ImagePath.notEmpty() ) {
Image.LoadXImage(&ThemeDir, settings.ImagePath);
} else if ( settings.ImageData.notEmpty() ) {
if ( !EFI_ERROR(Image.Image.FromPNG(settings.ImageData.data(), settings.ImageData.size())) ) {
Image.setFilled();
}
Image.Image.FromPNG(settings.ImageData.data(), settings.ImageData.size());
}
}
UINT8 getFlags() const {

View File

@ -1180,7 +1180,6 @@ if ( Entry->APFSTargetUUID.Data1 == 0x99999999 ) {
if (gSettings.GUI.CustomIcons && FileExists(Volume->RootDir, L"\\.VolumeIcon.icns")){
Entry->Image.Image.LoadIcns(Volume->RootDir, L"\\.VolumeIcon.icns", 128);
if (!Entry->Image.Image.isEmpty()) {
Entry->Image.setFilled();
DBG("%susing VolumeIcon.icns image from Volume\n", indent);
}
} else if (Image) {
@ -1205,9 +1204,6 @@ if ( Entry->APFSTargetUUID.Data1 == 0x99999999 ) {
Entry->BadgeImage.Image = XImage(Entry->Image.Image, 0);
DBG("%sShow badge as OSImage.\n", indent);
}
if (!Entry->BadgeImage.Image.isEmpty()) {
Entry->BadgeImage.setFilled();
}
}
Entry->BootBgColor = BootBgColor;
Entry->KernelAndKextPatches = Patches == NULL ? gSettings.KernelAndKextPatches : *Patches;

View File

@ -229,7 +229,6 @@ void REFIT_MAINMENU_SCREEN::DrawMainMenuEntry(REFIT_ABSTRACT_MENU_ENTRY *Entry,
}
if (MainIcon.Image.isEmpty()) {
MainIcon.Image.DummyImage(MainSize);
MainIcon.setFilled();
}
}
@ -349,8 +348,8 @@ void REFIT_MAINMENU_SCREEN::MainMenuStyle(IN UINTN Function, IN CONST CHAR16 *Pa
// INTN i = 0;
INTN MessageHeight = 0;
// clovy
if (ThemeX->TypeSVG && textFace[1].valid) {
MessageHeight = (INTN)(textFace[1].size * RowHeightFromTextHeight * ThemeX->Scale);
if (ThemeX->TypeSVG && ThemeX->getTextFace(1).valid) {
MessageHeight = (INTN)(ThemeX->getTextFace(1).size * RowHeightFromTextHeight * ThemeX->Scale);
} else {
MessageHeight = (INTN)(ThemeX->TextHeight * RowHeightFromTextHeight * ThemeX->Scale);
}
@ -574,8 +573,8 @@ void REFIT_MAINMENU_SCREEN::MainMenuVerticalStyle(IN UINTN Function, IN CONST CH
INTN VisibleHeight = (UGAHeight - EntriesPosY - (int)(LAYOUT_Y_EDGE * ThemeX->Scale) + EntriesGap) / (EntriesHeight + EntriesGap);
EntriesPosX = UGAWidth - EntriesWidth - (int)((BAR_WIDTH + LAYOUT_X_EDGE) * ThemeX->Scale);
INTN MessageHeight = 20;
if (ThemeX->TypeSVG && textFace[1].valid) {
MessageHeight = (INTN)(textFace[1].size * RowHeightFromTextHeight * ThemeX->Scale);
if (ThemeX->TypeSVG && ThemeX->getTextFace(1).valid) {
MessageHeight = (INTN)(ThemeX->getTextFace(1).size * RowHeightFromTextHeight * ThemeX->Scale);
} else {
MessageHeight = (INTN)(ThemeX->TextHeight * RowHeightFromTextHeight * ThemeX->Scale);
}
@ -684,8 +683,8 @@ void REFIT_MAINMENU_SCREEN::MainMenuVerticalStyle(IN UINTN Function, IN CONST CH
case MENU_FUNCTION_PAINT_TIMEOUT:
INTN MessageHeight = 20;
if (ThemeX->TypeSVG && textFace[1].valid) {
MessageHeight = (INTN)(textFace[1].size * RowHeightFromTextHeight * ThemeX->Scale);
if (ThemeX->TypeSVG && ThemeX->getTextFace(1).valid) {
MessageHeight = (INTN)(ThemeX->getTextFace(1).size * RowHeightFromTextHeight * ThemeX->Scale);
} else {
MessageHeight = (INTN)(ThemeX->TextHeight * RowHeightFromTextHeight * ThemeX->Scale);
}

View File

@ -705,22 +705,22 @@ UINTN REFIT_MENU_SCREEN::RunGenericMenu(IN OUT INTN *DefaultEntryIndex, OUT REFI
TextStyle = 2;
}
if (ThemeX->TypeSVG) {
if (!textFace[TextStyle].valid) {
if (textFace[0].valid) {
if (!ThemeX->getTextFace(TextStyle).valid) {
if (ThemeX->getTextFace(0).valid) {
TextStyle = 0;
} else if (textFace[2].valid) {
} else if (ThemeX->getTextFace(2).valid) {
TextStyle = 2;
} else if (textFace[1].valid) {
} else if (ThemeX->getTextFace(1).valid) {
TextStyle = 1;
} else {
DBG("no valid text style\n");
textFace[TextStyle].size = ThemeX->TextHeight - 4;
// ThemeX->getTextFace(TextStyle).size = ThemeX->TextHeight - 4;
}
}
if (textFace[TextStyle].valid) {
// TextHeight = (int)((textFace[TextStyle].size + 4) * GlobalConfig.Scale);
if (ThemeX->getTextFace(TextStyle).valid) {
// TextHeight = (int)((ThemeX->getTextFace(TextStyle].size + 4) * GlobalConfig.Scale);
//clovy - row height / text size factor
ThemeX->TextHeight = (int)((textFace[TextStyle].size * RowHeightFromTextHeight) * ThemeX->Scale);
ThemeX->TextHeight = (int)((ThemeX->getTextFace(TextStyle).size * RowHeightFromTextHeight) * ThemeX->Scale);
}
}
@ -1314,8 +1314,8 @@ INTN REFIT_MENU_SCREEN::DrawTextXY(IN const XStringW& Text, IN INTN XPos, IN INT
}
//TODO assume using embedded font for BootScreen
//messages must be TextXYStyle = 1 if it is provided by theme
if (!textFace[1].valid) {
if (textFace[2].valid) {
if (!ThemeX->getTextFace(1).valid) {
if (ThemeX->getTextFace(2).valid) {
TextXYStyle = 2;
} else {
TextXYStyle = 0;
@ -1336,11 +1336,11 @@ INTN REFIT_MENU_SCREEN::DrawTextXY(IN const XStringW& Text, IN INTN XPos, IN INT
if (!isBootScreen && ThemeX->TypeSVG) {
TextWidth += ThemeX->TextHeight * 2; //give more place for buffer
if (!textFace[TextXYStyle].valid) {
if (!ThemeX->getTextFace(TextXYStyle).valid) {
DBG("no vaid text face for message!\n");
Height = ThemeX->TextHeight;
} else {
Height = (int)(textFace[TextXYStyle].size * RowHeightFromTextHeight * ThemeX->Scale);
Height = (int)(ThemeX->getTextFace(TextXYStyle).size * RowHeightFromTextHeight * ThemeX->Scale);
}
} else {
Height = ThemeX->TextHeight;
@ -1442,7 +1442,7 @@ void REFIT_MENU_SCREEN::DrawMenuText(IN const XStringW& Text, IN INTN SelectedWi
if (ThemeX->TypeSVG) {
//clovy - text vertically centred on Height
ThemeX->RenderText(Text, &TextBufferX, 0,
(INTN)((ThemeX->TextHeight - (textFace[TextStyle].size * ThemeX->Scale)) / 2),
(INTN)((ThemeX->TextHeight - (ThemeX->getTextFace(TextStyle).size * ThemeX->Scale)) / 2),
Cursor, TextStyle);
} else {
ThemeX->RenderText(Text, &TextBufferX, TEXT_XMARGIN, TEXT_YMARGIN, Cursor, TextStyle);

View File

@ -53,110 +53,61 @@ extern void DumpFloat2 (CONST char* s, float* t, int N);
extern UINTN NumFrames;
extern UINTN FrameTime;
textFaces textFace[4]; //0-help 1-message 2-menu 3-test, far future it will be infinite list with id
EFI_STATUS XTheme::ParseSVGXIcon(INTN Id, const XString8& IconNameX, OUT XImage* Image, OUT void **SVGIcon)
EFI_STATUS XTheme::ParseSVGXIcon(NSVGparser* SVGParser, INTN Id, const XString8& IconNameX, OUT XImage* Image)
{
EFI_STATUS Status = EFI_NOT_FOUND;
NSVGimage *SVGimage;
NSVGparser *p = (NSVGparser *)SVGParser;
NSVGrasterizer* rast = nsvgCreateRasterizer();
SVGimage = p->image; // full theme SVG image
NSVGimage* SVGimage = SVGParser->image; // full theme SVG image
NSVGshape *shape;
NSVGgroup *group;
NSVGimage *IconImage; // separate SVG image
NSVGshape *shapeNext, *shapesTail = NULL, *shapePrev;
NSVGshape *shapeNext/*, *shapesTail = NULL, *shapePrev*/;
float IconImageWidth = 0; // Width of the image.
float IconImageHeight = 0; // Height of the image.
NSVGparser* p2 = nsvg__createParser();
IconImage = p2->image;
IconImage->clip.count = 0;
shape = SVGimage->shapes;
shapePrev = NULL;
while (shape) {
group = shape->group;
shapeNext = shape->next;
while (group) {
if (strcmp(group->id, IconNameX.c_str()) == 0) {
strncpy(IconImage->id, group->id, 63);
break;
}
group = group->parent;
}
if (group) { //the shape is in the group
// keep this sample for debug purpose
/* DBG("found shape %s", shape->id);
DBG(" from group %s\n", group->id);
if ((Id == BUILTIN_SELECTION_BIG) ||
(Id == BUILTIN_ICON_BACKGROUND) ||
(Id == BUILTIN_ICON_BANNER)) {
shape->debug = true;
} */
int prevCount = IconImage->clip.count;
for (int i=0; i<shape->clip.count; i++) {
IconImage->clip.index[prevCount+i] = shape->clip.index[i];
IconImage->clip.count++;
}
if ( isShapeInGroup(shape, IconNameX.c_str()) )
{
if (BootCampStyle && IconNameX.contains("selection_big")) {
shape->opacity = 0.f;
}
if (XString8().takeValueFrom(shape->id).contains("BoundingRect")) {
//there is bounds after nsvgParse()
IconImage->width = shape->bounds[2] - shape->bounds[0];
IconImage->height = shape->bounds[3] - shape->bounds[1];
DBG("parsed bounds: %f, %f\n", IconImage->width, IconImage->height);
if ( IconImage->height < 1.f ) {
IconImage->height = 200.f;
IconImageWidth = shape->bounds[2] - shape->bounds[0];
IconImageHeight = shape->bounds[3] - shape->bounds[1];
// DBG("parsed bounds: %f, %f\n", IconImage.width, IconImage.height);
if ( IconImageHeight < 1.f ) {
IconImageHeight = 200.f;
}
if (IconNameX.contains("selection_big") && (!SelectionOnTop)) {
MainEntriesSize = (int)(IconImage->width * Scale); //xxx
MainEntriesSize = (int)(IconImageWidth * Scale); //xxx
row0TileSize = MainEntriesSize + (int)(16.f * Scale);
// DBG("main entry size = %lld\n", MainEntriesSize);
}
if (IconNameX.contains("selection_small") && (!SelectionOnTop)) {
row1TileSize = (int)(IconImage->width * Scale);
row1TileSize = (int)(IconImageWidth * 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->flags = NSVG_VIS_VISIBLE;
// Add to tail
if (IconImage->shapes == NULL)
IconImage->shapes = shape;
else
shapesTail->next = shape;
shapesTail = shape;
if (shapePrev) {
shapePrev->next = shapeNext;
}
else {
SVGimage->shapes = shapeNext;
}
} //the shape in the group
else {
shapePrev = shape;
}
shape = shapeNext;
shape = shapeNext;
} //while shape
shapesTail->next = NULL;
IconImage->clipPaths = SVGimage->clipPaths;
if ( IconImageWidth == 0 || IconImageHeight == 0 ) {
return Status;
}
float bounds[4];
nsvg__imageBounds(IconImage, bounds);
CopyMem(IconImage->realBounds, bounds, 4 * sizeof(float));
nsvg__imageBounds(SVGimage, bounds, IconNameX.c_str());
if ((Id == BUILTIN_ICON_BANNER) && IconNameX.contains("Banner")) {
BannerPosX = (int)(bounds[0] * Scale - CentreShift);
if (BannerPosX < 0) {
@ -166,25 +117,16 @@ EFI_STATUS XTheme::ParseSVGXIcon(INTN Id, const XString8& IconNameX, OUT XImage*
// DBG("Banner position at parse [%lld,%lld]\n", BannerPosX, BannerPosY);
}
float Height = IconImage->height * Scale;
float Width = IconImage->width * Scale;
float Height = IconImageHeight * Scale;
float Width = IconImageWidth * Scale;
if (Height < 0 || Width < 0) {
nsvgDeleteRasterizer(rast);
return EFI_NOT_FOUND;
}
// DBG("icon %s width=%f height=%f\n", IconNameX.c_str(), Width, Height);
int iWidth = ((int)(Width+0.5f) + 7) & ~0x07u;
int iHeight = ((int)(Height+0.5f) + 7) & ~0x07u;
XImage NewImage(iWidth, iHeight); //empty
if (IconImage->shapes == NULL) {
*Image = NewImage;
// DBG("return empty with status=%s\n", efiStrError(Status));
nsvgDeleteRasterizer(rast);
return Status;
}
IconImage->scale = Scale;
// DBG("begin rasterize %s\n", IconNameX.c_str());
float tx = 0.f, ty = 0.f;
if ((Id != BUILTIN_ICON_BACKGROUND) &&
(Id != BUILTIN_ICON_ANIME) &&
@ -196,17 +138,10 @@ EFI_STATUS XTheme::ParseSVGXIcon(INTN Id, const XString8& IconNameX, OUT XImage*
ty = (Height - realHeight) * 0.5f;
}
nsvgRasterize(rast, IconImage, tx, ty, Scale, Scale, (UINT8*)NewImage.GetPixelPtr(0,0), iWidth, iHeight, iWidth*4);
// DBG("%s rastered, blt\n", IconImage);
NSVGrasterizer* rast = nsvgCreateRasterizer();
nsvgRasterize(rast, SVGimage, bounds, IconNameX.c_str(), tx, ty, Scale, Scale, (UINT8*)NewImage.GetPixelPtr(0,0), iWidth, iHeight, iWidth*4);
nsvgDeleteRasterizer(rast);
// nsvg__deleteParser(p2);
// nsvgDelete(p2->image); //somehow we can't delete them producing memory leaks
// well, we will use them later
*Image = NewImage; //copy array
if (SVGIcon) {
*SVGIcon = (void*)IconImage; //copy pointer into parser
}
return EFI_SUCCESS;
}
@ -217,18 +152,27 @@ EFI_STATUS XTheme::ParseSVGXTheme(UINT8* buffer, UINTN Size)
Icons.setEmpty();
#if 1 && defined(NANOSVG_MEMORY_ALLOCATION_TRACE)
displayFreeMemory("XTheme::ParseSVGXTheme begin"_XS8);
#if defined(JIEF_DEBUG) && defined(NANOSVG_MEMORY_ALLOCATION_TRACE)
if ( nsvg__nbDanglingPtr() > 0 ) {
DBG("There is already dangling ptr. nano svg memory leak test not done\n");
}else{
char* buffer2 = (char*)malloc(Size);
memcpy(buffer2, buffer, Size);
nvsg__memoryallocation_verbose = false;
SVGParser = nsvgParse(buffer2, 72, 1.f); //the buffer will be modified, it is how nanosvg works // Jief : NEVER cast const to not const. Just change the parameter to not const !!! Nothing better to deceive.
// nsvg__deleteParser(SVGParser);
NSVGparser* p = nsvgParse(buffer2, 72, 1.f); //the buffer will be modified, it is how nanosvg works
nsvg__deleteParser(p);
if ( nsvg__nbDanglingPtr() > 0 ) {
// nsvg__outputDanglingPtr();
// nvsg__memoryallocation_verbose = true; // there leaks. Activate verbose
nsvg__outputDanglingPtr();
nvsg__memoryallocation_verbose = true;
#if 1
// Do it a second time, to display all allocations and to be able to step in with debugger
memcpy(buffer2, buffer, Size);
p = nsvgParse(buffer2, 72, 1.f); //the buffer will be modified, it is how nanosvg works
nsvg__deleteParser(p);
nsvg__outputDanglingPtr();
#endif
}else{
nvsg__memoryallocation_verbose = false; // be sure that nvsg__memoryallocation_verbose is false, as it seems there is no memory leaks
}
@ -238,9 +182,9 @@ if ( nsvg__nbDanglingPtr() > 0 ) {
#endif
// --- Parse theme.svg --- low case
NSVGparser *mainParser = nsvgParse((CHAR8*)buffer, 72, 1.f); //the buffer will be modified, it is how nanosvg works
SVGParser = mainParser; //store the pointer for future use
NSVGimage *SVGimage = mainParser->image;
NSVGparser* SVGParser = nsvgParse((CHAR8*)buffer, 72, 1.f); //the buffer will be modified, it is how nanosvg works// Jief : NEVER cast const to not const. Just change the parameter to not const !!! Nothing better to deceive.
NSVGimage *SVGimage = SVGParser->image;
if (!SVGimage) {
// DBG("Theme not parsed!\n");
return EFI_NOT_STARTED;
@ -249,16 +193,16 @@ if ( nsvg__nbDanglingPtr() > 0 ) {
// --- Get scale as theme design height vs screen height
// must be svg view-box. This is Design Width and Heigth
float vbx = mainParser->viewWidth;
float vby = mainParser->viewHeight;
DBG("Theme view-bounds: w=%f h=%f units=px\n", vbx, vby); //Theme view-bounds: w=1600.000000 h=900.000000 units=px
float vbx = SVGParser->viewWidth;
float vby = SVGParser->viewHeight;
// DBG("Theme view-bounds: w=%f h=%f units=px\n", vbx, vby); //Theme view-bounds: w=1600.000000 h=900.000000 units=px
if (vby > 1.0f) {
SVGimage->height = vby;
} else {
SVGimage->height = 768.f; //default height
}
float ScaleF = UGAHeight / SVGimage->height;
DBG("using scale %f\n", ScaleF); // using scale 0.666667
// DBG("using scale %f\n", ScaleF); // using scale 0.666667
Scale = ScaleF;
CentreShift = (vbx * Scale - (float)UGAWidth) * 0.5f;
@ -267,25 +211,27 @@ if ( nsvg__nbDanglingPtr() > 0 ) {
BigBack.setEmpty();
}
Status = EFI_NOT_FOUND;
if (!ThemeX->Daylight) {
Status = ParseSVGXIcon(BUILTIN_ICON_BACKGROUND, "Background_night"_XS8, &BigBack, NULL); //we should have a place for SVG background
if (!Daylight) {
Status = ParseSVGXIcon(SVGParser, BUILTIN_ICON_BACKGROUND, "Background_night"_XS8, &BigBack);
}
if (EFI_ERROR(Status)) {
Status = ParseSVGXIcon(BUILTIN_ICON_BACKGROUND, "Background"_XS8, &BigBack, NULL);
Status = ParseSVGXIcon(SVGParser, BUILTIN_ICON_BACKGROUND, "Background"_XS8, &BigBack);
}
DBG(" Background parsed [%lld, %lld]\n", BigBack.GetWidth(), BigBack.GetHeight()); //Background parsed [1067, 133]
// DBG(" Background parsed [%lld, %lld]\n", BigBack.GetWidth(), BigBack.GetHeight()); //Background parsed [1067, 133]
// --- Make Banner
Banner.setEmpty(); //for the case of theme switch
Status = EFI_NOT_FOUND;
if (!ThemeX->Daylight) {
Status = ParseSVGXIcon(BUILTIN_ICON_BANNER, "Banner_night"_XS8, &Banner, NULL);
if (!Daylight) {
Status = ParseSVGXIcon(SVGParser, BUILTIN_ICON_BANNER, "Banner_night"_XS8, &Banner);
}
if (EFI_ERROR(Status)) {
Status = ParseSVGXIcon(BUILTIN_ICON_BANNER, "Banner"_XS8, &Banner, NULL);
Status = ParseSVGXIcon(SVGParser, BUILTIN_ICON_BANNER, "Banner"_XS8, &Banner);
}
// DBG("Banner parsed\n");
BanHeight = (int)(Banner.GetHeight() * Scale + 1.f);
DBG(" parsed banner->width=%lld height=%lld\n", Banner.GetWidth(), BanHeight); //parsed banner->width=467 height=89
// DBG(" parsed banner->width=%lld height=%lld\n", Banner.GetWidth(), BanHeight); //parsed banner->width=467 height=89
// --- Make other icons
for (INTN i = BUILTIN_ICON_FUNC_ABOUT; i <= BUILTIN_CHECKBOX_CHECKED; ++i) {
@ -293,12 +239,11 @@ if ( nsvg__nbDanglingPtr() > 0 ) {
continue;
}
XIcon* NewIcon = new XIcon(i, false); //initialize without embedded
Status = ParseSVGXIcon(i, NewIcon->Name, &NewIcon->Image, &NewIcon->ImageSVG);
Status = ParseSVGXIcon(SVGParser, i, NewIcon->Name, &NewIcon->Image);
// DBG("parse %s status %s\n", NewIcon->Name.c_str(), efiStrError(Status));
NewIcon->Native = !EFI_ERROR(Status);
if (!EFI_ERROR(Status)) {
NewIcon->setFilled();
ParseSVGXIcon(i, NewIcon->Name + "_night"_XS8, &NewIcon->ImageNight, &NewIcon->ImageSVGnight);
ParseSVGXIcon(SVGParser, i, NewIcon->Name + "_night"_XS8, &NewIcon->ImageNight);
}
// DBG("parse night %s status %s\n", NewIcon->Name.c_str(), efiStrError(Status));
Icons.AddReference(NewIcon, true);
@ -316,19 +261,19 @@ if ( nsvg__nbDanglingPtr() > 0 ) {
for (INTN i = ICON_OTHER_OS; i < IconsNamesSize; ++i) {
if (AsciiStrLen(IconsNames[i]) == 0) break;
XIcon* NewIcon = new XIcon(i, false); //initialize without embedded
Status = ParseSVGXIcon(i, NewIcon->Name, &NewIcon->Image, &NewIcon->ImageSVG);
Status = ParseSVGXIcon(SVGParser, i, NewIcon->Name, &NewIcon->Image);
// DBG("parse %s i=%lld status %s\n", NewIcon->Name.c_str(), i, efiStrError(Status));
NewIcon->Native = !EFI_ERROR(Status);
if (!EFI_ERROR(Status)) {
ParseSVGXIcon(i, NewIcon->Name + "_night"_XS8, &NewIcon->ImageNight, &NewIcon->ImageSVGnight);
ParseSVGXIcon(SVGParser, i, NewIcon->Name + "_night"_XS8, &NewIcon->ImageNight);
}
Icons.AddReference(NewIcon, true);
}
//selection for bootcampstyle
XIcon *NewIcon = new XIcon(BUILTIN_ICON_SELECTION);
Status = ParseSVGXIcon(BUILTIN_ICON_SELECTION, "selection_indicator"_XS8, &NewIcon->Image, &NewIcon->ImageSVG);
Status = ParseSVGXIcon(SVGParser, BUILTIN_ICON_SELECTION, "selection_indicator"_XS8, &NewIcon->Image);
if (!EFI_ERROR(Status)) {
Status = ParseSVGXIcon(BUILTIN_ICON_SELECTION, "selection_indicator_night"_XS8, &NewIcon->ImageNight, &NewIcon->ImageSVGnight);
Status = ParseSVGXIcon(SVGParser, BUILTIN_ICON_SELECTION, "selection_indicator_night"_XS8, &NewIcon->ImageNight);
}
Icons.AddReference(NewIcon, true);
@ -346,82 +291,7 @@ if ( nsvg__nbDanglingPtr() > 0 ) {
for (INTN i = BUILTIN_RADIO_BUTTON; i <= BUILTIN_CHECKBOX_CHECKED; ++i) {
Buttons[i - BUILTIN_RADIO_BUTTON] = GetIcon(i).GetBest(!Daylight);
}
//for (int i=0 ; i<6 ; i+=2 ) {
//SelectionImages[i].Draw(i*100, 0);
//}
//TODO parse anime like for PNG themes
/*
Dict = GetProperty(DictPointer, "Anime");
if (Dict != NULL) {
INTN Count = Get_TagCount (Dict);
for (INTN i = 0; i < Count; i++) {
FILM *NewFilm = new FILM;
if (EFI_ERROR(GetElement(Dict, i, &Dict3))) {
continue;
}
if (Dict3 == NULL) {
break;
}
Dict2 = GetProperty(Dict3, "ID");
NewFilm->SetIndex((UINTN)GetPropertyInteger(Dict2, 1)); //default=main screen
Dict2 = GetProperty(Dict3, "Path");
if (Dict2 != NULL && (Dict2->isString()) && Dict2->getString()->stringValue().notEmpty() ) {
NewFilm->Path.takeValueFrom(Dict2->getString()->stringValue());
}
Dict2 = GetProperty(Dict3, "Frames");
NewFilm->NumFrames = (UINTN)GetPropertyInteger(Dict2, 0);
Dict2 = GetProperty(Dict3, "FrameTime");
NewFilm->FrameTime = (UINTN)GetPropertyInteger(Dict2, 50); //default will be 50ms
Dict2 = GetProperty(Dict3, "ScreenEdgeX");
if (Dict2 != NULL && (Dict2->isString()) && Dict2->getString()->stringValue().notEmpty() ) {
if (Dict2->getString()->stringValue().isEqual("left")) {
NewFilm->ScreenEdgeHorizontal = SCREEN_EDGE_LEFT;
} else if (Dict2->getString()->stringValue().isEqual("right")) {
NewFilm->ScreenEdgeHorizontal = SCREEN_EDGE_RIGHT;
}
}
Dict2 = GetProperty(Dict3, "ScreenEdgeY");
if (Dict2 != NULL && (Dict2->isString()) && Dict2->getString()->stringValue().notEmpty() ) {
if (Dict2->getString()->stringValue().isEqual("top")) {
NewFilm->ScreenEdgeVertical = SCREEN_EDGE_TOP;
} else if (Dict2->getString()->stringValue().isEqual("bottom")) {
NewFilm->ScreenEdgeVertical = SCREEN_EDGE_BOTTOM;
}
}
//default values are centre
Dict2 = GetProperty(Dict3, "DistanceFromScreenEdgeX%");
NewFilm->FilmX = GetPropertyInteger(Dict2, INITVALUE);
Dict2 = GetProperty(Dict3, "DistanceFromScreenEdgeY%");
NewFilm->FilmY = GetPropertyInteger(Dict2, INITVALUE);
Dict2 = GetProperty(Dict3, "NudgeX");
NewFilm->NudgeX = GetPropertyInteger(Dict2, INITVALUE);
Dict2 = GetProperty(Dict3, "NudgeY");
NewFilm->NudgeY = GetPropertyInteger(Dict2, INITVALUE);
Dict2 = GetProperty(Dict3, "Once");
NewFilm->RunOnce = IsPropertyTrue(Dict2);
NewFilm->GetFrames(ThemeX); //used properties: ID, Path, NumFrames
ThemeX->Cinema.AddFilm(NewFilm);
// delete NewFilm; //looks like already deleted
}
}
*/
// nsvgDeleteRasterizer(rast);
TypeSVG = true;
ThemeDesignHeight = (int)SVGimage->height;
ThemeDesignWidth = (int)SVGimage->width;
@ -430,16 +300,30 @@ if ( nsvg__nbDanglingPtr() > 0 ) {
row1TileSize = (INTN)(64.f * Scale);
MainEntriesSize = (INTN)(128.f * Scale);
}
// DBG("parsing svg theme finished\n");
// DBG("parsing svg theme finished\n");
// It looks like the fonts are self-contained. So we can just keep fontsDB pointer and copy textfaces and delete the parser.
// I'm not sure if font are self contained with all theme. To avoid deleting, just comment out the next line.
// SVGParser will still be deleted at XTheme dtor. So it's not a memory leak.
fontsDB = SVGParser->fontsDB;
for (size_t i = 0; i < sizeof(textFace)/sizeof(textFace[0]); i++) {
textFace[i] = SVGParser->textFace[i];
}
SVGParser->fontsDB = NULL; // To avoid nsvg__deleteParser to delete it;
nsvg__deleteParser(SVGParser); // comment out this line and the next to keep the parser memory, in case of doubt that font are dependent.
SVGParser = NULL;
displayFreeMemory("XTheme::ParseSVGXTheme end"_XS8);
return EFI_SUCCESS;
}
EFI_STATUS XTheme::LoadSvgFrame(INTN i, OUT XImage* XFrame)
// 2023-11 This is currently never called.
EFI_STATUS XTheme::LoadSvgFrame(NSVGparser* SVGParser, INTN i, OUT XImage* XFrame)
{
EFI_STATUS Status = EFI_NOT_FOUND;
XString8 XFrameName = S8Printf("frame_%04lld", i+1);
Status = ParseSVGXIcon(BUILTIN_ICON_ANIME, XFrameName, XFrame, NULL); //svg anime will be full redesigned
Status = ParseSVGXIcon(SVGParser, BUILTIN_ICON_ANIME, XFrameName, XFrame); //svg anime will be full redesigned
if (EFI_ERROR(Status)) {
DBG("frame '%s' not loaded, status=%s\n", XFrameName.c_str(), efiStrError(Status));
}
@ -453,28 +337,21 @@ EFI_STATUS XTheme::LoadSvgFrame(INTN i, OUT XImage* XFrame)
//textType = 0-help 1-message 2-menu 3-test
//return text width in pixels
//it is not theme member!
INTN renderSVGtext(XImage* TextBufferXY_ptr, INTN posX, INTN posY, INTN textType, const XStringW& string, UINTN Cursor)
INTN renderSVGtext(XImage* TextBufferXY_ptr, INTN posX, INTN posY, const textFaces& textFace, const XStringW& string, UINTN Cursor)
{
XImage& TextBufferXY = *TextBufferXY_ptr;
INTN Width;
NSVGparser* p;
NSVGrasterizer* rast;
if (!textFace[textType].valid) {
for (decltype(textType) i=0; i<4; i++) {
if (textFace[i].valid) {
textType = i;
break;
}
}
}
if (!textFace[textType].valid) {
DBG("valid fontface not found!\n");
if (!textFace.valid) {
DBG("invalid fontface!\n");
return 0;
}
NSVGfont* fontSVG = textFace[textType].font;
UINT32 color = textFace[textType].color;
INTN Height = (INTN)(textFace[textType].size * ThemeX->Scale);
NSVGfont* fontSVG = textFace.font;
UINT32 color = textFace.color;
INTN Height = (INTN)(textFace.size * ThemeX->Scale);
float Scale, sy;
float x, y;
if (!fontSVG) {
@ -533,11 +410,30 @@ INTN renderSVGtext(XImage* TextBufferXY_ptr, INTN posX, INTN posY, INTN textType
float RealWidth = p->image->realBounds[2] - p->image->realBounds[0];
nsvgDeleteRasterizer(rast);
// nsvg__deleteParser(p);
nsvgDelete(p->image);
nsvg__deleteParser(p); // this deletes p->text;
// nsvgDelete(p->image);
// TODO delete parser p and p->text?
return (INTN)RealWidth; //x;
}
INTN renderSVGtext(XImage* TextBufferXY_ptr, INTN posX, INTN posY, INTN textType, const XStringW& string, UINTN Cursor)
{
if (!ThemeX->getTextFace(textType).valid) {
for (decltype(textType) i=0; i<4; i++) {
if (ThemeX->getTextFace(i).valid) {
textType = i;
break;
}
}
}
if (!ThemeX->getTextFace(textType).valid) {
DBG("valid fontface not found!\n");
return 0;
}
return renderSVGtext(TextBufferXY_ptr, posX, posY, ThemeX->getTextFace(textType), string, Cursor);
}
void testSVG()
{
do {
@ -654,9 +550,11 @@ void testSVG()
break;
}
textFace[3].font = p->font;
textFace[3].color = NSVG_RGBA(0x80, 0xFF, 0, 255);
textFace[3].size = Height;
textFaces textFace;
textFace.font = p->currentFont;
textFace.color = NSVG_RGBA(0x80, 0xFF, 0, 255);
textFace.size = Height;
textFace.valid = true;
// DBG("font parsed family=%s\n", p->font->fontFamily);
FreePool(FileData);
// Scale = Height / fontSVG->unitsPerEm;

View File

@ -90,7 +90,7 @@ void FILM::AddFrame(XImage* Frame, INTN Index)
}
}
// 2023-11 : this is currently never called when theme is svg
void FILM::GetFrames(XTheme& TheTheme /*, const XStringW& Path*/) // Path already exist as a member. Is it the same ?
{
const EFI_FILE *ThemeDir = &TheTheme.getThemeDir();
@ -99,16 +99,12 @@ void FILM::GetFrames(XTheme& TheTheme /*, const XStringW& Path*/) // Path alread
for (INTN Index = 0; Index < NumFrames; Index++) {
XImage NewImage;
Status = EFI_NOT_FOUND;
if (TheTheme.TypeSVG) {
Status = TheTheme.LoadSvgFrame(Index, &NewImage);
} else {
XStringW Name = SWPrintf("%ls\\%ls_%03lld.png", Path.wc_str(), Path.wc_str(), Index);
// DBG("try to load %ls\n", Name.wc_str()); //fine
if (FileExists(ThemeDir, Name)) {
Status = NewImage.LoadXImage(ThemeDir, Name);
}
// DBG(" read status=%s\n", efiStrError(Status));
XStringW Name = SWPrintf("%ls\\%ls_%03lld.png", Path.wc_str(), Path.wc_str(), Index);
// DBG("try to load %ls\n", Name.wc_str()); //fine
if (FileExists(ThemeDir, Name)) {
Status = NewImage.LoadXImage(ThemeDir, Name);
}
// DBG(" read status=%s\n", efiStrError(Status));
if (!EFI_ERROR(Status)) {
AddFrame(&NewImage, Index);
}
@ -116,3 +112,20 @@ void FILM::GetFrames(XTheme& TheTheme /*, const XStringW& Path*/) // Path alread
}
// 2023-11 : this is currently never called
// This should be 2 implementations of the same method in 2 different subclass, I think.
void FILM::GetFramesSVG(NSVGparser* SVGParser, XTheme& TheTheme /*, const XStringW& Path*/) // Path already exist as a member. Is it the same ?
{
EFI_STATUS Status;
LastIndex = 0;
for (INTN Index = 0; Index < NumFrames; Index++) {
XImage NewImage;
Status = TheTheme.LoadSvgFrame(SVGParser, Index, &NewImage);
if (!EFI_ERROR(Status)) {
AddFrame(&NewImage, Index);
}
}
}

View File

@ -15,6 +15,7 @@ extern "C" {
#include "../cpp_foundation/XArray.h"
#include "../cpp_foundation/XString.h"
#include "../libeg/libeg.h"
#include "../libeg/nanosvg.h"
#include "XImage.h"
class XTheme;
@ -64,6 +65,7 @@ public:
INTN LastFrameID() { return LastIndex; }
XBool Finished() { return CurrentFrame == 0; }
void GetFrames(XTheme& TheTheme/*, const XStringW& Path*/); //read image sequence from Theme/Path/
void GetFramesSVG(NSVGparser* SVGParser, XTheme& TheTheme);
void SetPlace(const EG_RECT& Rect) { FilmPlace = Rect; }
void Advance() { ++CurrentFrame %= (LastIndex + 1); }
void Reset() { CurrentFrame = 0; }

View File

@ -102,19 +102,8 @@ ImageNight.FromPNG(ACCESS_EMB_DATA(dark), ACCESS_EMB_SIZE(dark)); \
}
XIcon::~XIcon()
XIcon::XIcon(INTN Index, XBool TakeEmbedded) : Id(Index), Empty(false)
{
// memory leak : we can't free (yet?) ImageSVG and ImageSVGnight because operator might have copied it
}
XIcon::XIcon(INTN Index, XBool TakeEmbedded) : Id(Index), Name(), Image(), ImageNight(), Native(false),
ImageSVG(nullptr), ImageSVGnight(nullptr), Empty(false)
{
// Id = Index;
// Name.setEmpty();
// Native = false;
// ImageSVG = nullptr;
// ImageSVGnight = nullptr;
if (Index >= BUILTIN_ICON_FUNC_ABOUT && Index < IconsNamesSize) { //full table
Name.takeValueFrom(IconsNames[Index]);
}
@ -123,20 +112,6 @@ XIcon::XIcon(INTN Index, XBool TakeEmbedded) : Id(Index), Name(), Image(), Image
}
}
XIcon& XIcon::operator=(const XIcon& src)
{
Id = src.Id;
Name = src.Name;
Image = src.Image;
ImageNight = src.ImageNight;
Native = src.Native;
Empty = src.Empty;
//this moment we copy pointers. Later it will be class variables
ImageSVG = src.ImageSVG;
ImageSVGnight = src.ImageSVGnight;
return *this;
}
void XIcon::GetEmbedded()
{
switch (Id) {
@ -246,7 +221,6 @@ EFI_STATUS XIcon::LoadXImage(const EFI_FILE *BaseDir, const XStringW& IconName)
{
EFI_STATUS Status = Image.LoadXImage(BaseDir, IconName);
ImageNight.LoadXImage(BaseDir, IconName + L"_night"_XSW);
if (!EFI_ERROR(Status)) setFilled();
return Status;
}

View File

@ -5,33 +5,31 @@
#include "../cpp_foundation/XString.h"
#include "XImage.h"
#include "libeg.h"
#include "nanosvg.h"
#include "../Platform/BootLog.h"
#include "../Platform/Utils.h"
extern CONST CHAR8* IconsNames[];
extern const INTN IconsNamesSize;
class XIcon
{
public:
INTN Id; //for example BUILTIN_ICON_POINTER
XString8 Name; //for example "os_moja", "vol_internal"
XImage Image;
XImage ImageNight;
XBool Native;
void *ImageSVG; //NSVGimage*
void *ImageSVGnight;
INTN Id = 0; //for example BUILTIN_ICON_POINTER
XString8 Name = XString8(); //for example "os_moja", "vol_internal"
XImage Image = XImage();
XImage ImageNight = XImage();
XBool Native = false;
protected:
XBool Empty;
XBool Empty = true;
public:
XIcon(): Id(0), Name(), Image(), ImageNight(), Native(false), ImageSVG(nullptr), ImageSVGnight(nullptr), Empty(true) {};
XIcon() {};
XIcon(INTN Id, XBool Embedded = false);
// Initialisation of ImageSVG(other.ImageSVG), ImageSVGnight(other.ImageSVGnight) is wrong because we just copy the pointer
XIcon(const XIcon& other) : Id(other.Id), Name(other.Name), Image(other.Image), ImageNight(other.ImageNight), Native(other.Native), ImageSVG(other.ImageSVG), ImageSVGnight(other.ImageSVGnight), Empty(other.Empty) {} ;
~XIcon();
XBool isEmpty() const { return Empty; }
void setFilled() { Empty = false; }
void setEmpty() { Empty = true; }
XBool isEmpty() const { return Image.isEmpty() && ImageNight.isEmpty(); }
void setEmpty() { Id = 0; Name.setEmpty(); Image.setEmpty(); ImageNight.setEmpty(); Native = false; }
EFI_STATUS LoadXImage(const EFI_FILE *Dir, const XStringW& FileName); //for example LoadImage(ThemeDir, L"icons\\" + Name);
EFI_STATUS LoadXImage(const EFI_FILE *Dir, const wchar_t* LIconName);
@ -40,7 +38,6 @@ public:
// Default are not valid, as usual. We delete them. If needed, proper ones can be created
// Icon(const Icon&) = delete;
XIcon& operator=(const XIcon&); // = delete;
const XImage& GetBest(XBool night) const;
};

View File

@ -431,41 +431,41 @@ EFI_STATUS XImage::ToPNG(UINT8** Data, UINTN& OutSize)
return EFI_SUCCESS;
}
/*
* fill XImage object by raster data described in SVG file
* caller should create the object with Width and Height and calculate scale
* scale = 1 correspond to fill the rect with the image
* scale = 0.5 will reduce image
* but this procedure is mostly for testing purpose. Real SVG theme can't be divided to separate SVG files
*/
EFI_STATUS XImage::FromSVG(const CHAR8 *SVGData, float scale)
{
NSVGimage *SVGimage;
NSVGparser* p;
NSVGrasterizer* rast = nsvgCreateRasterizer();
if (!rast) return EFI_UNSUPPORTED;
//we have to copy input data because nanosvg wants to change it
char *input = (__typeof__(input))AllocateCopyPool(AsciiStrSize(SVGData), SVGData);
if (!input) return EFI_DEVICE_ERROR;
p = nsvgParse(input, 72, 1.f); //the parse will change input contents
SVGimage = p->image;
if (SVGimage) {
float ScaleX = Width / SVGimage->width;
float ScaleY = Height / SVGimage->height;
float Scale = (ScaleX > ScaleY) ? ScaleY : ScaleX;
Scale *= scale;
DBG("Test image width=%d heigth=%d\n", (int)(SVGimage->width), (int)(SVGimage->height));
nsvgRasterize(rast, SVGimage, 0.f, 0.f, Scale, Scale, (UINT8*)&PixelData[0], (int)Width, (int)Height, (int)Width * sizeof(PixelData[0]));
FreePool(SVGimage);
}
// nsvg__deleteParser(p); //can't delete raster until we make imageChain
nsvgDeleteRasterizer(rast);
FreePool(input);
return EFI_SUCCESS;
}
///*
// * fill XImage object by raster data described in SVG file
// * caller should create the object with Width and Height and calculate scale
// * scale = 1 correspond to fill the rect with the image
// * scale = 0.5 will reduce image
// * but this procedure is mostly for testing purpose. Real SVG theme can't be divided to separate SVG files
// */
//EFI_STATUS XImage::FromSVG(const CHAR8 *SVGData, float scale)
//{
// NSVGimage *SVGimage;
// NSVGparser* p;
//
// NSVGrasterizer* rast = nsvgCreateRasterizer();
// if (!rast) return EFI_UNSUPPORTED;
// //we have to copy input data because nanosvg wants to change it
// char *input = (__typeof__(input))AllocateCopyPool(AsciiStrSize(SVGData), SVGData);
// if (!input) return EFI_DEVICE_ERROR;
//
// p = nsvgParse(input, 72, 1.f); //the parse will change input contents
// SVGimage = p->image;
// if (SVGimage) {
// float ScaleX = Width / SVGimage->width;
// float ScaleY = Height / SVGimage->height;
// float Scale = (ScaleX > ScaleY) ? ScaleY : ScaleX;
// Scale *= scale;
//
// DBG("Test image width=%d heigth=%d\n", (int)(SVGimage->width), (int)(SVGimage->height));
// nsvgRasterize(rast, SVGimage, 0.f, 0.f, Scale, Scale, (UINT8*)&PixelData[0], (int)Width, (int)Height, (int)Width * sizeof(PixelData[0]));
// FreePool(SVGimage);
// }
//// nsvg__deleteParser(p); //can't delete raster until we make imageChain // not sure why, but this is npt used so far. FIX if back in use.
// nsvgDeleteRasterizer(rast);
// FreePool(input);
// return EFI_SUCCESS;
//}
// Screen operations
/*
@ -556,12 +556,12 @@ void XImage::DrawWithoutCompose(INTN x, INTN y, UINTN width, UINTN height) const
}
//output combined image
if (GraphicsOutput != NULL) {
GraphicsOutput->Blt(GraphicsOutput, PixelData.data(),
GraphicsOutput->Blt(GraphicsOutput, (*this).GetPixelPtr(0, 0),
EfiBltBufferToVideo,
0, 0, x, y, AreaWidth, AreaHeight, GetWidth()*sizeof(EFI_GRAPHICS_OUTPUT_BLT_PIXEL));
}
else if (UgaDraw != NULL) {
UgaDraw->Blt(UgaDraw, (EFI_UGA_PIXEL *)GetPixelPtr(0, 0), EfiUgaBltBufferToVideo,
UgaDraw->Blt(UgaDraw, (EFI_UGA_PIXEL *)(*this).GetPixelPtr(0, 0), EfiUgaBltBufferToVideo,
0, 0, x, y, AreaWidth, AreaHeight, GetWidth()*sizeof(EFI_GRAPHICS_OUTPUT_BLT_PIXEL));
}
}

View File

@ -32,12 +32,13 @@ extern "C" {
#endif
XTheme* ThemeX = NULL;
textFaces nullTextFaces;
EFI_STATUS
InitTheme(const CHAR8* ChosenTheme)
{
EFI_STATUS Status = EFI_NOT_FOUND;
EFI_STATUS Status = EFI_NOT_FOUND;
UINTN i;
TagDict* ThemeDict = NULL;
// CHAR8 *ChosenTheme = NULL;
@ -46,6 +47,9 @@ InitTheme(const CHAR8* ChosenTheme)
gRT->GetTime(&Now, NULL);
DbgHeader("InitXTheme");
if ( ThemeX != NULL ) delete ThemeX;
ThemeX = new XTheme();
ThemeX->Init();
//initialize Daylight when we know timezone
@ -64,33 +68,6 @@ InitTheme(const CHAR8* ChosenTheme)
DBG("use night theme\n");
}
for (i = 0; i < 3; i++) {
// DBG("validate %d face\n", i);
textFace[i].valid = false;
}
NSVGfontChain *fontChain = fontsDB;
while (fontChain) {
NSVGfont *font = fontChain->font;
// DBG("free font %s\n", font->fontFamily);
NSVGfontChain *nextChain = fontChain->next;
if (font) {
nsvg__deleteFont(font);
fontChain->font = NULL;
}
FreePool(fontChain);
fontChain = nextChain;
}
//as all font freed then free the chain
fontsDB = NULL;
/*
if (mainParser) {
nsvg__deleteParser(mainParser);
DBG("parser deleted\n");
mainParser = NULL;
}
*/
ThemeX->FontImage.setEmpty();
Rnd = (ThemeNameArray.size() != 0) ? Now.Second % ThemeNameArray.size() : 0;
@ -183,11 +160,10 @@ finish:
ThemeX->FillByEmbedded();
OldChosenTheme = 0xFFFF;
ThemeX->closeThemeDir();
// if (ThemeX->ThemeDir != NULL) {
// ThemeX->ThemeDir->Close(ThemeX->ThemeDir);
// ThemeX->ThemeDir = NULL;
// }
if (ThemeX->ThemeDir != NULL) {
ThemeX->ThemeDir->Close(ThemeX->ThemeDir);
ThemeX->ThemeDir = NULL;
}
// ThemeX->GetThemeTagSettings(NULL); already done
//fill some fields
@ -233,8 +209,9 @@ finish:
if (!ThemeX->TypeSVG) {
ThemeX->PrepareFont();
}
//ThemeX->ClearScreen();
displayFreeMemory("InitTheme end"_XS8);
return Status;
}
@ -253,14 +230,11 @@ XTheme::XTheme() : Icons(), ThemeDir(0), HideBadges(0), HideUIFlags(0), Font(FON
row0TileSize(0), row1TileSize(0), BanHeight(0), LayoutHeight(0), LayoutBannerOffset(0), LayoutButtonOffset(0), LayoutTextOffset(0),
LayoutAnimMoveForMenuX(0), ScrollWidth(0), ScrollButtonsHeight(0), ScrollBarDecorationsHeight(0), ScrollScrollDecorationsHeight(0),
FontWidth(0), FontHeight(0), TextHeight(0), Daylight(false), Background(), BigBack(), Banner(), SelectionImages(), Buttons(), ScrollbarBackgroundImage(), BarStartImage(), BarEndImage(),
ScrollbarImage(), ScrollStartImage(), ScrollEndImage(), UpButtonImage(), DownButtonImage(), FontImage(), BannerPlace(), Cinema(), SVGParser(0)
ScrollbarImage(), ScrollStartImage(), ScrollEndImage(), UpButtonImage(), DownButtonImage(), FontImage(), BannerPlace(), Cinema()
{
Init();
}
XTheme::~XTheme() {
//nothing todo?
}
void XTheme::Init()
{
@ -735,7 +709,7 @@ XTheme::GetThemeTagSettings(const TagDict* DictPointer)
NewFilm->RunOnce = IsPropertyNotNullAndTrue(Prop);
NewFilm->GetFrames(*ThemeX); //used properties: ID, Path, NumFrames
ThemeX->Cinema.AddFilm(NewFilm);
Cinema.AddFilm(NewFilm);
// delete NewFilm; //looks like already deleted
}
}
@ -839,7 +813,6 @@ XIcon& XTheme::GetIconAlt(INTN Id, INTN Alt) //if not found then take embedded
// using Alt icon
Icons[IdFound].Image = Icons[AltFound].Image;
Icons[IdFound].ImageNight = Icons[AltFound].ImageNight;
Icons[IdFound].setFilled();
} else {
// check for embedded with ID=Id
XIcon *NewIcon = new XIcon(Id, true);
@ -851,7 +824,6 @@ XIcon& XTheme::GetIconAlt(INTN Id, INTN Alt) //if not found then take embedded
// using Embedded icon
Icons[IdFound].Image = NewIcon->Image;
Icons[IdFound].ImageNight = NewIcon->ImageNight;
Icons[IdFound].setFilled();
}
}
}
@ -918,7 +890,6 @@ const XIcon& XTheme::LoadOSIcon(const XString8& Full)
// else something
if (DummyIcon.isEmpty()) { //initialize once per session
DummyIcon.Image.DummyImage(MainEntriesSize);
DummyIcon.setFilled();
}
}
return DummyIcon;
@ -1115,7 +1086,6 @@ void XTheme::FillByDir() //assume ThemeDir is defined by InitTheme() procedure
}
NewIcon->Native = !EFI_ERROR(Status);
if (!EFI_ERROR(Status)) {
NewIcon->setFilled();
NewIcon->ImageNight.LoadXImage(ThemeDir, SWPrintf("%s_night", IconsNames[i]));
}
Icons.AddReference(NewIcon, true);

View File

@ -22,43 +22,15 @@ class TagStruct;
EFI_STATUS InitTheme (const CHAR8* ChosenTheme);
extern textFaces nullTextFaces;
class XTheme
{
public:
XObjArray<XIcon> Icons;
protected:
XStringW m_ThemePath = NullXStringW;
EFI_FILE *ThemeDir;
EFI_FILE *ThemeDir = 0;
public:
void openThemeDir() {
if ( ThemeDir != NULL ) ThemeDir->Close(ThemeDir);
/*Status = */self.getCloverDir().Open(&self.getCloverDir(), &ThemeDir, m_ThemePath.wc_str(), EFI_FILE_MODE_READ, 0);
}
void closeThemeDir() {
if ( ThemeDir != NULL ) ThemeDir->Close(ThemeDir);
ThemeDir = NULL;
}
// const XStringW& getThemePath() { return m_ThemePath; }
// void setThemePath(const XStringW& aThemePath) {
// m_ThemePath = aThemePath;
// closeThemeDir();
// openThemeDir();
// }
const EFI_FILE& getThemeDir() {
return *ThemeDir;
}
XBool IsEmbeddedTheme(void)
{
if (embedded) {
ThemeDir = NULL;
}
return ThemeDir == NULL;
}
public:
// UINTN DisableFlags;
UINTN HideBadges;
UINTN HideUIFlags;
@ -146,20 +118,36 @@ public:
XCinema Cinema;
NSVGparser* SVGParser;
public:
NSVGfontChain* fontsDB = 0;
textFaces textFace[4]; //0-help 1-message 2-menu 3-test, far future it will be infinite list with id // in VectorGraphics, I use sizeof(textFace)/sizeof(textFace[0]. So if you change that to a pointer, it'll break.
void Init();
XTheme(); //default constructor
XTheme(const XTheme&) = delete;
XTheme& operator=(const XTheme&) = delete;
~XTheme();
~XTheme() {
if ( ThemeDir != NULL ) ThemeDir->Close(ThemeDir);
if ( fontsDB ) {
nsvg__deleteFontChain(fontsDB);
}
for (size_t i=0 ; i < Icons.length() ; ++i ) {
Icons[i].setEmpty();
}
}
const EFI_FILE& getThemeDir() const { return *ThemeDir; }
XBool IsEmbeddedTheme(void) const { return embedded; }
//fill the theme
// const XImage& GetIcon(const char* Name);
// const XImage& GetIcon(const CHAR16* Name);
const XIcon& GetIcon(const XString8& Name); //get by name
XIcon* GetIconP(const XString8& Name);
const XIcon& GetIcon(INTN Id); //get by id
XIcon& GetIconAlt(INTN Id, INTN Alt); //if id not found
const XIcon& LoadOSIcon(const CHAR16* OSIconName); //TODO make XString provider
@ -184,9 +172,14 @@ public:
EFI_STATUS GetThemeTagSettings(const TagDict* DictPointer);
void parseTheme(void* p, char** dict); //in nano project
EFI_STATUS ParseSVGXTheme(UINT8* buffer, UINTN Size); // in VectorTheme
EFI_STATUS ParseSVGXIcon(INTN Id, const XString8& IconNameX, XImage* Image, void **SVGIcon);
EFI_STATUS ParseSVGXIcon(NSVGparser* SVGParser, INTN Id, const XString8& IconNameX, XImage* Image);
TagDict* LoadTheme(const XStringW& TestTheme); //return TagStruct* why?
EFI_STATUS LoadSvgFrame(INTN i, OUT XImage* XFrame); // for animation
EFI_STATUS LoadSvgFrame(NSVGparser* SVGParser, INTN i, OUT XImage* XFrame); // for animation
const textFaces& getTextFace(size_t idx) {
if (!TypeSVG ) return nullTextFaces;
return textFace[idx];
}
//screen operations
void ClearScreen();

View File

@ -667,29 +667,38 @@ static void nsvg__deletePaths(NSVGpath* path)
}
}
static void nsvg__deleteGlyphs(NSVGglyph* glyphs)
{
while (glyphs) {
NSVGglyph *next = glyphs->next;
nsvg__deletePaths(glyphs->path);
nsvg__delete(glyphs, "nsvg__deleteGlyphs"_XS8);
glyphs = next;
}
}
void nsvg__deleteFont(NSVGfont* font)
{
NSVGglyph *glyphs, *next;
if (!font) {
return;
}
if (font->missingGlyph) {
// DBG("missing glyph=%s\n", font->missingGlyph->name);
nsvg__deletePaths(font->missingGlyph->path);
nsvg__delete(font->missingGlyph, "nsvg__deleteFont"_XS8);
font->missingGlyph = NULL;
}
glyphs = font->glyphs;
while (glyphs) {
// DBG(" glyph=%s\n", glyphs->name);
next = glyphs->next;
nsvg__deletePaths(glyphs->path);
nsvg__delete(glyphs, "nsvg__deleteFont"_XS8);
glyphs = next;
}
//DBG("nsvg__deleteFont %s %llx\n", font->id, uintptr_t(font));
nsvg__deleteGlyphs(font->glyphs);
nsvg__deleteGlyphs(font->missingGlyph);
nsvg__delete(font, "nsvg__deleteFont"_XS8);
}
void nsvg__deleteFontChain(NSVGfontChain *fontChain)
{
while (fontChain) {
NSVGfont* font = fontChain->font;
NSVGfontChain *nextChain = fontChain->next;
nsvg__deleteFont(font);
nsvg__delete(fontChain, "nsvg__deleteParser1"_XS8);
fontChain = nextChain;
}
}
static void nsvg__deletePaint(NSVGpaint* paint)
{
if (!paint || !paint->paint.gradient) {
@ -729,33 +738,41 @@ static void nsvg__deleteSymbols(NSVGsymbol* symbol)
}
}
static void nsvg__popAttr(NSVGparser* p);
static NSVGattrib* nsvg__getAttr(NSVGparser* p);
void nsvg__deleteParser(NSVGparser* p)
{
int i;
if (p != NULL) {
nsvg__deleteStyles(p->styles);
nsvg__deleteSymbols(p->symbols);
nsvg__deletePaths(p->pathList);
nsvg__deleteGradientData(p->gradients);
// do not delete font here, as we free all fonts later by following fontsdb
nsvg__deleteFontChain(p->fontsDB);
nsvgDelete(p->image);
if (p->cpts > 0 && p->pts) {
nsvg__delete(p->pts, "nsvg__deleteParser"_XS8);
nsvg__delete(p->pts, "nsvg__deleteParser2"_XS8);
}
for (i=0; i<NSVG_MAX_ATTR; i++) {
NSVGattrib* attr = &(p->attr[i]);
auto text = p->text;
while ( text ) {
nsvg__delete(text, "nsvg__deleteParser3"_XS8);
text = text->next;
}
while ( p->attrHead > 0 ) {
NSVGattrib* attr = nsvg__getAttr(p);
if (attr && attr->fontFace) {
nsvg__delete(attr->fontFace, "nsvg__deleteParser2"_XS8);
nsvg__delete(attr->fontFace, "nsvg__deleteParser3"_XS8);
attr->fontFace = NULL;
}
while (attr->group) {
NSVGgroup* group = attr->group->parent;
nsvg__delete(attr->group, "nsvg__deleteParser3"_XS8);
attr->group = group;
if ( attr->group ) {
nsvg__delete(attr->group, "nsvg__deleteParser4"_XS8);
}
nsvg__popAttr(p);
}
nsvg__delete(p, "nsvg__deleteParser4"_XS8);
nsvg__delete(p, "nsvg__deleteParser5"_XS8);
}
}
@ -843,8 +860,13 @@ static void nsvg__pushAttr(NSVGparser* p)
static void nsvg__popAttr(NSVGparser* p)
{
if (p->attrHead > 0)
if (p->attrHead > 0) {
auto attr = nsvg__getAttr(p);
if ( attr->fontFace ) {
nsvg__delete(attr->fontFace, "nsvg__popAttr"_XS8);
}
p->attrHead--;
}
}
static float nsvg__actualOrigX(NSVGparser* p)
@ -3080,7 +3102,7 @@ static void nsvg__parseText(NSVGparser* p, char** dict)
// DBG("required font %s required style=%c\n", text->fontFace->fontFamily, text->fontStyle);
//if the font is not registered then we have to load new one
NSVGfont *fontSVG = NULL;
NSVGfontChain *fontChain = fontsDB;
NSVGfontChain *fontChain = p->fontsDB;
NSVGfontChain *fontChainSimilar = NULL;
while (fontChain) {
fontSVG = fontChain->font;
@ -3117,14 +3139,21 @@ static void nsvg__parseText(NSVGparser* p, char** dict)
if (!p1) {
// DBG("font %s not parsed\n", text->fontFace->fontFamily);
} else {
fontSVG = fontsDB->font; //last added during parse file data
// Jief : this is only taking the first font from the file. It would not be hard to take the whole p1->fontsDB and to link it on p->fontsDB
NSVGfontChain* fc = p1->fontsDB;
p1->fontsDB = p1->fontsDB->next;
fc->next = p->fontsDB;
p->fontsDB = fc;
fontSVG = p->fontsDB->font; //last added during parse file data
text->font = fontSVG;
nsvg__deleteParser(p1);
}
FreePool(FileData); //after load // don not use nsvg__delete because it's not allocated by nsvg__alloc...
FileData = NULL;
} else {
// DBG("set embedded font\n");
text->font = p->font; //else embedded if present which is also double fontChain
text->font = p->currentFont; //else embedded if present which is also double fontChain
}
} else {
// DBG("set found font %s\n", fontSVG->fontFamily);
@ -3136,58 +3165,58 @@ static void nsvg__parseText(NSVGparser* p, char** dict)
NSVGgroup* group = attr->group;
while (group) {
if (strcmp(group->id, "MessageRow") == 0) {
if (!textFace[1].valid) {
if (!p->textFace[1].valid) {
//here we want to set text->font as p->font if text->groupID == MessageRow
p->font = fontSVG;
p->currentFont = fontSVG;
p->fontSize = text->fontSize;
p->fontColor = text->fontColor;
textFace[1].font = fontSVG;
textFace[1].size = (INTN)text->fontSize;
textFace[1].color = text->fontColor;
textFace[1].valid = true;
p->textFace[1].font = fontSVG;
p->textFace[1].size = (INTN)text->fontSize;
p->textFace[1].color = text->fontColor;
p->textFace[1].valid = true;
// DBG("set message->font=%s color=%X size=%f as in MessageRow\n", fontSVG->fontFamily, text->fontColor, text->fontSize);
}
break;
} else if (!ThemeX->Daylight && strcmp(group->id, "MessageRow_night") == 0) {
//replace ThemeX->Daylight settings
p->font = fontSVG;
p->currentFont = fontSVG;
p->fontSize = text->fontSize;
p->fontColor = text->fontColor;
textFace[1].font = fontSVG;
textFace[1].size = (INTN)text->fontSize;
textFace[1].color = text->fontColor;
textFace[1].valid = true;
p->textFace[1].font = fontSVG;
p->textFace[1].size = (INTN)text->fontSize;
p->textFace[1].color = text->fontColor;
p->textFace[1].valid = true;
// DBG("set message_night->font=%s color=%X size=%f as in MessageRow\n", fontSVG->fontFamily, text->fontColor, text->fontSize);
break;
} else if (strcmp(group->id, "MenuRows") == 0) {
if (!textFace[2].valid) {
textFace[2].font = fontSVG;
textFace[2].size = (INTN)text->fontSize;
textFace[2].color = text->fontColor;
textFace[2].valid = true;
if (!p->textFace[2].valid) {
p->textFace[2].font = fontSVG;
p->textFace[2].size = (INTN)text->fontSize;
p->textFace[2].color = text->fontColor;
p->textFace[2].valid = true;
// DBG("set menu->font=%s color=%X size=%f as in MenuRows\n", fontSVG->fontFamily, text->fontColor, text->fontSize);
}
break;
} else if (!ThemeX->Daylight && strcmp(group->id, "MenuRows_night") == 0) {
textFace[2].font = fontSVG;
textFace[2].size = (INTN)text->fontSize;
textFace[2].color = text->fontColor;
textFace[2].valid = true;
p->textFace[2].font = fontSVG;
p->textFace[2].size = (INTN)text->fontSize;
p->textFace[2].color = text->fontColor;
p->textFace[2].valid = true;
break;
} else if (strcmp(group->id, "HelpRows") == 0) {
if (!textFace[0].valid) {
textFace[0].font = fontSVG;
textFace[0].size = (INTN)text->fontSize;
textFace[0].color = text->fontColor;
textFace[0].valid = true;
if (!p->textFace[0].valid) {
p->textFace[0].font = fontSVG;
p->textFace[0].size = (INTN)text->fontSize;
p->textFace[0].color = text->fontColor;
p->textFace[0].valid = true;
// DBG("set help->font=%s color=%X size=%f as in HelpRows\n", fontSVG->fontFamily, text->fontColor, text->fontSize);
}
break;
} else if (!ThemeX->Daylight && strstr(group->id, "HelpRows_night") != NULL) {
textFace[0].font = fontSVG;
textFace[0].size = (INTN)text->fontSize;
textFace[0].color = text->fontColor;
textFace[0].valid = true;
p->textFace[0].font = fontSVG;
p->textFace[0].size = (INTN)text->fontSize;
p->textFace[0].color = text->fontColor;
p->textFace[0].valid = true;
// DBG("set help_night->font=%s color=%X size=%f as in HelpRows\n", fontSVG->fontFamily, text->fontColor, text->fontSize);
break;
}
@ -3673,6 +3702,8 @@ static void nsvg__parseGroup(NSVGparser* p, char** dict)
}
// DBG("parse group\n");
NSVGgroup* group = (NSVGgroup*)nsvg__alloczero(sizeof(NSVGgroup), "nsvg__parseGroup"_XS8);
group->next = p->image->groups;
p->image->groups = group;
// if (curAttr->id[0] == '\0') //skip anonymous groups
// return;
@ -3812,10 +3843,10 @@ static void nsvg__parseFont(NSVGparser* p, char** dict)
NSVGfontChain* fontChain = (decltype(fontChain))nsvg__alloc(sizeof(*fontChain), "nsvg__parseFont fontChain"_XS8);
fontChain->font = font;
fontChain->next = fontsDB;
p->font = font;
fontChain->next = p->fontsDB;
p->currentFont = font;
fontsDB = fontChain;
p->fontsDB = fontChain;
}
static void nsvg__parseFontFace(NSVGparser* p, char** dict)
@ -3825,7 +3856,7 @@ static void nsvg__parseFontFace(NSVGparser* p, char** dict)
// DBG("no parser\n");
return;
}
NSVGfont* font = p->font; //if present??? assumed good svg structure
NSVGfont* font = p->currentFont; //if present??? assumed good svg structure
if (!font) {
return;
}
@ -3982,6 +4013,7 @@ static void nsvg__parseGlyph(NSVGparser* p, char** dict, XBool missing)
} else if (strcmp(dict[i], "glyph-name") == 0) {
strncpy(glyph->name, dict[i+1], 16);
glyph->name[15] = '\0';
//DBG("nsvg__parseGlyph name=%s\n", glyph->name);
if (strcmp(dict[i+1], "nonmarkingreturn") == 0) {
glyph->unicode = L'\n';
} else if (strcmp(dict[i+1], ".notdef") == 0) {
@ -3993,24 +4025,28 @@ static void nsvg__parseGlyph(NSVGparser* p, char** dict, XBool missing)
nsvg__parsePath(p, dict);
glyph->path = p->pathList;
p->pathList = 0; //lastPath;
p->pathList = 0;
if (p->font) {
if (p->currentFont) {
//DBG("nsvg__parseGlyph name=%s missign=%d currentfont=%s\n", glyph->name, (bool)missing, p->currentFont->id);
if (missing) {
p->font->missingGlyph = glyph;
if (!glyph->horizAdvX && p->font->horizAdvX) {
p->font->missingGlyph->horizAdvX = p->font->horizAdvX;
//Jief : Having more than one missing glyph happen at least with cesium theme.
// That's why I add them in the chain instead of just reassign p->currentFont->missingGlyph
glyph->next = p->currentFont->missingGlyph;
p->currentFont->missingGlyph = glyph;
if (!glyph->horizAdvX && p->currentFont->horizAdvX) {
p->currentFont->missingGlyph->horizAdvX = p->currentFont->horizAdvX;
}
} else {
if (!glyph->horizAdvX) {
if (p->font->missingGlyph) {
glyph->horizAdvX = p->font->missingGlyph->horizAdvX;
} else if (p->font->horizAdvX) {
glyph->horizAdvX = p->font->horizAdvX;
if (p->currentFont->missingGlyph) {
glyph->horizAdvX = p->currentFont->missingGlyph->horizAdvX;
} else if (p->currentFont->horizAdvX) {
glyph->horizAdvX = p->currentFont->horizAdvX;
}
}
glyph->next = p->font->glyphs;
p->font->glyphs = glyph;
glyph->next = p->currentFont->glyphs;
p->currentFont->glyphs = glyph;
}
}
// DBG("glyph %X parsed\n", glyph->unicode);
@ -4480,10 +4516,23 @@ void takeXformBounds(NSVGshape *shape, float *xform, float *bounds)
bounds[3] = nsvg__maxf(bounds[3], newBounds[5]);
bounds[3] = nsvg__maxf(bounds[3], newBounds[7]);
}
bool isShapeInGroup(NSVGshape* shape, const char* groupName)
{
NSVGgroup* group = shape->group;
while (group) {
if (strcmp(group->id, groupName) == 0) {
return true;
}
group = group->parent;
}
return false;
}
//image bounds for a shape group
//bounds inited before use, called from nsvgParse
//assumed each shape already has bounds calculated.
int nsvg__shapesBound(/*NSVGimage* image,*/ NSVGshape *shapes, float* bounds)
int nsvg__shapesBound(/*NSVGimage* image,*/ NSVGshape *shapes, float* bounds, const char* groupName)
{
NSVGshape *shape, *shapeLink;
float xform[6];
@ -4491,6 +4540,9 @@ int nsvg__shapesBound(/*NSVGimage* image,*/ NSVGshape *shapes, float* bounds)
int count = 0;
int visibility;
for (shapeLink = shapes; shapeLink != NULL; shapeLink = shapeLink->next) {
if ( groupName && !isShapeInGroup(shapeLink, groupName) ) {
continue;
}
memcpy(&xform[0], shapeLink->xform, sizeof(float)*6);
visibility = (shapeLink->flags & NSVG_VIS_VISIBLE); //check origin visibility, not link
@ -4521,7 +4573,6 @@ int nsvg__shapesBound(/*NSVGimage* image,*/ NSVGshape *shapes, float* bounds)
void nsvg__imageBounds(NSVGimage* image, float* bounds)
{
// NSVGimage* image = p->image;
NSVGclipPath* clipPath;
if (!bounds || !image) {
return;
@ -4536,13 +4587,13 @@ void nsvg__imageBounds(NSVGimage* image, float* bounds)
while (clipPath != NULL) {
for (int i = 0; i < image->clip.count; i++) {
if (clipPath->index == image->clip.index[i]) {
count += nsvg__shapesBound(clipPath->shapes, bounds);
count += nsvg__shapesBound(clipPath->shapes, bounds, NULL);
break;
}
}
clipPath = clipPath->next;
}
count += nsvg__shapesBound(image->shapes, bounds);
count += nsvg__shapesBound(image->shapes, bounds, NULL);
// DBG("found shapes=%d\n", count);
if (count == 0) {
bounds[0] = bounds[1] = 0.0f;
@ -4550,6 +4601,47 @@ void nsvg__imageBounds(NSVGimage* image, float* bounds)
}
}
NSVGclipPath* getClipPathWithIndex(NSVGimage* image, NSVGclipPathIndex idx)
{
NSVGclipPath* clipPath = image->clipPaths;
for (NSVGclipPathIndex i = 0; i < idx; i++) clipPath = clipPath->next;
return clipPath;
}
void nsvg__imageBounds(NSVGimage* image, float* bounds, const char* groupName)
{
if (!bounds || !image) {
return;
}
bounds[0] = FLT_MAX;
bounds[1] = FLT_MAX;
bounds[2] = -FLT_MAX;
bounds[3] = -FLT_MAX;
int count = 0;
NSVGshape *shape;
for (shape = image->shapes; shape != NULL; shape = shape->next) {
if ( groupName && !isShapeInGroup(shape, groupName) ) {
continue;
}
// DBG("nsvg__imageBounds2 found shapes=%s shape->clip.count=%d\n", shape->id, shape->clip.count);
for (int i = 0; i < shape->clip.count; i++) {
NSVGclipPath* clipPath = getClipPathWithIndex(image, shape->clip.index[i]);
if ( clipPath ) {
// DBG("nsvg__imageBounds found clipPath %s\n", clipPath->id);
count += nsvg__shapesBound(clipPath->shapes, bounds, NULL);
}
}
}
count += nsvg__shapesBound(image->shapes, bounds, groupName);
if (count == 0) {
bounds[0] = bounds[1] = 0.0f;
bounds[2] = bounds[3] = 1.0f;
}
}
// units like "px" is not used so just exclude it
NSVGparser* nsvgParse(char* input, /* const char* units,*/ float dpi, float opacity)
{
@ -4604,6 +4696,9 @@ void nsvg__deleteShapes(NSVGshape* shape)
shape->fontFace = NULL;
nsvg__deletePaint(&shape->fill);
nsvg__deletePaint(&shape->stroke);
if ( !shape->isText ) {
nsvg__deletePaths(shape->paths);
}
}
nsvg__delete(shape, "nsvg__deleteShapes"_XS8);
shape = snext;
@ -4629,7 +4724,7 @@ void nsvgDelete(NSVGimage* image)
nsvg__deleteClipPaths(image->clipPaths);
group = image->groups;
while (group != NULL) {
gnext = group->parent;
gnext = group->next;
nsvg__delete(group, "nsvgDelete group"_XS8);
group = gnext;
}

View File

@ -58,8 +58,8 @@ extern "C" {
#define NSVG_MAX_ATTR 2048
#define NSVG_MAX_CLIP_PATHS 1024 // also note NSVGclipPathIndex
#define NANOSVG_MEMORY_ALLOCATION_TRACE
#ifdef JIEF_DEBUG
#define NANOSVG_MEMORY_ALLOCATION_TRACE
#define NANOSVG_MEMORY_ALLOCATION_TRACE_VERBOSE
#endif
@ -164,6 +164,7 @@ typedef struct NSVGpattern {
typedef struct NSVGgroup
{
char id[kMaxIDLength];
struct NSVGgroup* next; // Pointer to parent group or NULL
struct NSVGgroup* parent; // Pointer to next group or NULL
int visibility;
} NSVGgroup;
@ -369,8 +370,6 @@ typedef struct textFaces {
XBool valid = false;
} textFaces;
extern textFaces textFace[]; //0-help 1-message 2-menu 3-test
typedef struct NSVGtext {
char id[kMaxIDLength];
// char class[64];
@ -416,7 +415,8 @@ typedef struct NSVGparser
NSVGstyles* styles;
NSVGgradientData* gradients;
NSVGshape* shapesTail;
struct NSVGfont* font;
struct NSVGfont* currentFont;
NSVGfontChain* fontsDB;
float opacity;
// this is temporary set for Menu text, later each text will have own face
float fontSize;
@ -436,6 +436,8 @@ typedef struct NSVGparser
XBool isText;
char unknown[64];
NSVGtext* text;
textFaces textFace[4]; //0-help 1-message 2-menu 3-test, far future it will be infinite list with id
NSVGsymbol* symbols;
NSVGpattern *patterns;
NSVGclipPath* clipPath;
@ -459,7 +461,7 @@ void nsvg__outputDanglingPtr();
#endif
bool isShapeInGroup(NSVGshape* shape, const char* groupName);
NSVGclipPath* getClipPathWithIndex(NSVGimage* image, NSVGclipPathIndex idx);
//---
// Duplicates a path.
@ -482,7 +484,9 @@ void nsvg__xformSetScale(float* t, float sx, float sy);
void nsvg__xformPremultiply(float* t, float* s);
void nsvg__xformMultiply(float* t, float* s);
void nsvg__deleteFont(NSVGfont* font);
void nsvg__deleteFontChain(NSVGfontChain *fontChain);
void nsvg__imageBounds(NSVGimage* image, float* bounds);
void nsvg__imageBounds(NSVGimage* image, float* bounds, const char* groupName);
float addLetter(NSVGparser* p, CHAR16 letter, float x, float y, float scale, UINT32 color);
void RenderSVGfont(NSVGfont *fontSVG, UINT32 color);
@ -503,6 +507,9 @@ NSVGrasterizer* nsvgCreateRasterizer(void);
// w - width of the image to render
// h - height of the image to render
// stride - number of bytes per scaleline in the destination buffer
void nsvgRasterize(NSVGrasterizer* r,
NSVGimage* image, float* bounds, const char* groupName, float tx, float ty, float scalex, float scaley,
UINT8* dst, int w, int h, int stride);
void nsvgRasterize(NSVGrasterizer* r,
NSVGimage* image, float tx, float ty, float scalex, float scaley,
UINT8* dst, int w, int h, int stride);
@ -606,7 +613,4 @@ struct NSVGrasterizer
NSVGstencil* stencilList;
};
extern NSVGfontChain *fontsDB;
//extern struct NSVGparser *mainParser;
#endif

View File

@ -1645,7 +1645,8 @@ static void nsvg__initPaint(NSVGcachedPaint* cache, NSVGpaint* paint, NSVGshape*
static void nsvg__rasterizeShapes(NSVGrasterizer* r,
NSVGshape* shapes, float tx, float ty, float scalex, float scaley,
NSVGshape* shapes, const char* groupName,
float tx, float ty, float scalex, float scaley,
UINT8* dst, int w, int h, int stride,
NSVGscanlineFunction fscanline)
{
@ -1679,6 +1680,9 @@ static void nsvg__rasterizeShapes(NSVGrasterizer* r,
for (shape = shapes; shape != NULL; shape = shape->next) {
if (!(shape->flags & NSVG_VIS_VISIBLE))
continue;
if ( groupName && !isShapeInGroup(shape, groupName) ) {
continue;
}
memcpy(&xform[0], shape->xform, sizeof(float)*6);
@ -1801,7 +1805,7 @@ void nsvg__rasterizeClipPaths(
clipPath = image->clipPaths;
while (clipPath != NULL) {
nsvg__rasterizeShapes(r, clipPath->shapes, tx, ty, scalex, scaley,
nsvg__rasterizeShapes(r, clipPath->shapes, NULL, tx, ty, scalex, scaley,
&r->stencil[r->stencilSize * clipPath->index],
w, h, r->stencilStride, nsvg__scanlineBit);
clipPath = clipPath->next;
@ -1812,14 +1816,22 @@ void nsvgRasterize(NSVGrasterizer* r,
NSVGimage* image, float tx, float ty, float scalex, float scaley,
UINT8* dst, int w, int h, int stride)
{
tx -= image->realBounds[0] * scalex;
ty -= image->realBounds[1] * scaley;
nsvgRasterize(r, image, &image->realBounds[0], NULL, tx, ty, scalex, scaley, dst, w, h, stride);
}
void nsvgRasterize(NSVGrasterizer* r,
NSVGimage* image, float* bounds, const char* groupName,
float tx, float ty, float scalex, float scaley,
UINT8* dst, int w, int h, int stride)
{
tx -= bounds[0] * scalex;
ty -= bounds[1] * scaley;
// DBG(" image %s will be scaled by [%f]\n", image->id, scalex);
// DumpFloat(" image real bounds ", image->realBounds, 4);
nsvg__rasterizeClipPaths(r, image, w, h, tx, ty, scalex, scaley);
nsvg__rasterizeShapes(r, image->shapes, tx, ty, scalex, scaley,
nsvg__rasterizeShapes(r, image->shapes, groupName, tx, ty, scalex, scaley,
dst, w, h, stride, nsvg__scanlineSolid);
nsvg__unpremultiplyAlpha(dst, w, h, stride);

View File

@ -64,7 +64,6 @@ extern "C" {
#endif
const EFI_GRAPHICS_OUTPUT_BLT_PIXEL SemiWhitePixel = {0xFF, 0xFF, 0xFF, 0xD2}; //semitransparent white
NSVGfontChain *fontsDB = NULL;
//
// Text rendering

View File

@ -173,8 +173,6 @@ void UninitRefitLib(void)
{
// called before running external programs to close open file handles
//ThemeX->closeThemeDir();
selfOem.closeHandle();
self.closeHandle();
@ -190,7 +188,6 @@ EFI_STATUS ReinitRefitLib(void)
selfOem.reInitialize();
ReinitVolumes();
//ThemeX->openThemeDir();
return EFI_SUCCESS;
}

View File

@ -669,7 +669,6 @@ void LOADER_ENTRY::StartLoader()
EFI_HANDLE ImageHandle = NULL;
EFI_LOADED_IMAGE *LoadedImage = NULL;
CONST CHAR8 *InstallerVersion;
NSVGfont *font; // , *nextFont;
DbgHeader("StartLoader");
@ -710,18 +709,21 @@ void LOADER_ENTRY::StartLoader()
// mainParser
// BuiltinIcons
// OSIcons
NSVGfontChain *fontChain = fontsDB;
while (fontChain) {
font = fontChain->font;
NSVGfontChain *nextChain = fontChain->next;
if (font) {
nsvg__deleteFont(font);
fontChain->font = NULL;
delete ThemeX;
ThemeX = NULL;
#ifdef NANOSVG_MEMORY_ALLOCATION_TRACE
if ( nsvg__nbDanglingPtr() > 0 ) {
DBG("There is %zu dangling ptr from SVG subsytem\n", nsvg__nbDanglingPtr());
nsvg__outputDanglingPtr();
}
FreePool(fontChain);
fontChain = nextChain;
}
fontsDB = NULL;
#endif
#ifdef JIEF_DEBUG
displayFreeMemory("LOADER_ENTRY::StartLoader() atfer ThemeX deleted"_XS8);
#endif
if ( OSTYPE_IS_OSX(LoaderType) || OSTYPE_IS_OSX_RECOVERY(LoaderType) || OSTYPE_IS_OSX_INSTALLER(LoaderType) ) {
@ -1615,12 +1617,9 @@ void LOADER_ENTRY::StartLoader()
Status = SaveBooterLog(&self.getCloverDir(), PREBOOT_LOG);
}
#ifdef JIEF_DEBUG
//Status = EFI_NOT_FOUND;
displayFreeMemory("Just before lauching image"_XS8);
Status = gBS->StartImage (ImageHandle, 0, NULL); // point to OcStartImage from OC
#else
Status = gBS->StartImage (ImageHandle, 0, NULL); // point to OcStartImage from OC
#endif
if ( EFI_ERROR(Status) ) {
// Ideally, we would return to the menu, displaying an error message