From 42cece988541e870959e92720d27e5180f7895ae Mon Sep 17 00:00:00 2001 From: jief Date: Wed, 8 Nov 2023 14:35:22 +0100 Subject: [PATCH] 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 --- Include/Library/MemLogLib.h | 4 + Library/MemLogLibDefault/MemLogLib.c | 1 + rEFIt_UEFI/Platform/Settings.cpp | 8 +- rEFIt_UEFI/Platform/Settings.h | 12 +- rEFIt_UEFI/entry_scan/loader.cpp | 4 - rEFIt_UEFI/gui/REFIT_MAINMENU_SCREEN.cpp | 13 +- rEFIt_UEFI/gui/REFIT_MENU_SCREEN.cpp | 26 +- rEFIt_UEFI/libeg/VectorGraphics.cpp | 330 ++++++++--------------- rEFIt_UEFI/libeg/XCinema.cpp | 33 ++- rEFIt_UEFI/libeg/XCinema.h | 2 + rEFIt_UEFI/libeg/XIcon.cpp | 28 +- rEFIt_UEFI/libeg/XIcon.h | 29 +- rEFIt_UEFI/libeg/XImage.cpp | 74 ++--- rEFIt_UEFI/libeg/XTheme.cpp | 56 +--- rEFIt_UEFI/libeg/XTheme.h | 61 ++--- rEFIt_UEFI/libeg/nanosvg.cpp | 255 ++++++++++++------ rEFIt_UEFI/libeg/nanosvg.h | 20 +- rEFIt_UEFI/libeg/nanosvgrast.cpp | 22 +- rEFIt_UEFI/libeg/text.cpp | 1 - rEFIt_UEFI/refit/lib.cpp | 3 - rEFIt_UEFI/refit/main.cpp | 33 ++- 21 files changed, 479 insertions(+), 536 deletions(-) diff --git a/Include/Library/MemLogLib.h b/Include/Library/MemLogLib.h index 852da0b45..e1f28a906 100644 --- a/Include/Library/MemLogLib.h +++ b/Include/Library/MemLogLib.h @@ -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 diff --git a/Library/MemLogLibDefault/MemLogLib.c b/Library/MemLogLibDefault/MemLogLib.c index b47068d2a..3da0a95af 100644 --- a/Library/MemLogLibDefault/MemLogLib.c +++ b/Library/MemLogLibDefault/MemLogLib.c @@ -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; diff --git a/rEFIt_UEFI/Platform/Settings.cpp b/rEFIt_UEFI/Platform/Settings.cpp index b911e05a4..34e0e4f03 100755 --- a/rEFIt_UEFI/Platform/Settings.cpp +++ b/rEFIt_UEFI/Platform/Settings.cpp @@ -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() ) { diff --git a/rEFIt_UEFI/Platform/Settings.h b/rEFIt_UEFI/Platform/Settings.h index 32a99cb99..e4452f271 100755 --- a/rEFIt_UEFI/Platform/Settings.h +++ b/rEFIt_UEFI/Platform/Settings.h @@ -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 { diff --git a/rEFIt_UEFI/entry_scan/loader.cpp b/rEFIt_UEFI/entry_scan/loader.cpp index 415953451..c63e49592 100644 --- a/rEFIt_UEFI/entry_scan/loader.cpp +++ b/rEFIt_UEFI/entry_scan/loader.cpp @@ -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; diff --git a/rEFIt_UEFI/gui/REFIT_MAINMENU_SCREEN.cpp b/rEFIt_UEFI/gui/REFIT_MAINMENU_SCREEN.cpp index 4ade95a0c..293606b7a 100644 --- a/rEFIt_UEFI/gui/REFIT_MAINMENU_SCREEN.cpp +++ b/rEFIt_UEFI/gui/REFIT_MAINMENU_SCREEN.cpp @@ -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); } diff --git a/rEFIt_UEFI/gui/REFIT_MENU_SCREEN.cpp b/rEFIt_UEFI/gui/REFIT_MENU_SCREEN.cpp index dc74119ed..c35460c55 100644 --- a/rEFIt_UEFI/gui/REFIT_MENU_SCREEN.cpp +++ b/rEFIt_UEFI/gui/REFIT_MENU_SCREEN.cpp @@ -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); diff --git a/rEFIt_UEFI/libeg/VectorGraphics.cpp b/rEFIt_UEFI/libeg/VectorGraphics.cpp index 8d9de63ba..a8193f38e 100755 --- a/rEFIt_UEFI/libeg/VectorGraphics.cpp +++ b/rEFIt_UEFI/libeg/VectorGraphics.cpp @@ -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; iclip.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; diff --git a/rEFIt_UEFI/libeg/XCinema.cpp b/rEFIt_UEFI/libeg/XCinema.cpp index a78c647d1..8839be529 100644 --- a/rEFIt_UEFI/libeg/XCinema.cpp +++ b/rEFIt_UEFI/libeg/XCinema.cpp @@ -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); + } + } +} + + + diff --git a/rEFIt_UEFI/libeg/XCinema.h b/rEFIt_UEFI/libeg/XCinema.h index ec28d4906..73451cc0d 100644 --- a/rEFIt_UEFI/libeg/XCinema.h +++ b/rEFIt_UEFI/libeg/XCinema.h @@ -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; } diff --git a/rEFIt_UEFI/libeg/XIcon.cpp b/rEFIt_UEFI/libeg/XIcon.cpp index 7cd22df12..157230162 100644 --- a/rEFIt_UEFI/libeg/XIcon.cpp +++ b/rEFIt_UEFI/libeg/XIcon.cpp @@ -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; } diff --git a/rEFIt_UEFI/libeg/XIcon.h b/rEFIt_UEFI/libeg/XIcon.h index 1bf4017ab..68ed8ae29 100644 --- a/rEFIt_UEFI/libeg/XIcon.h +++ b/rEFIt_UEFI/libeg/XIcon.h @@ -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; }; diff --git a/rEFIt_UEFI/libeg/XImage.cpp b/rEFIt_UEFI/libeg/XImage.cpp index 20d49f754..03090c5cc 100644 --- a/rEFIt_UEFI/libeg/XImage.cpp +++ b/rEFIt_UEFI/libeg/XImage.cpp @@ -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)); } } diff --git a/rEFIt_UEFI/libeg/XTheme.cpp b/rEFIt_UEFI/libeg/XTheme.cpp index 4e2e283fa..896d23ed0 100644 --- a/rEFIt_UEFI/libeg/XTheme.cpp +++ b/rEFIt_UEFI/libeg/XTheme.cpp @@ -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); diff --git a/rEFIt_UEFI/libeg/XTheme.h b/rEFIt_UEFI/libeg/XTheme.h index 730c412f2..9c5d7e281 100644 --- a/rEFIt_UEFI/libeg/XTheme.h +++ b/rEFIt_UEFI/libeg/XTheme.h @@ -22,43 +22,15 @@ class TagStruct; EFI_STATUS InitTheme (const CHAR8* ChosenTheme); +extern textFaces nullTextFaces; class XTheme { public: XObjArray 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(); diff --git a/rEFIt_UEFI/libeg/nanosvg.cpp b/rEFIt_UEFI/libeg/nanosvg.cpp index d03770df4..f46ffd6e4 100755 --- a/rEFIt_UEFI/libeg/nanosvg.cpp +++ b/rEFIt_UEFI/libeg/nanosvg.cpp @@ -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; iattr[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; } diff --git a/rEFIt_UEFI/libeg/nanosvg.h b/rEFIt_UEFI/libeg/nanosvg.h index b1c26a2cf..1ec142a00 100644 --- a/rEFIt_UEFI/libeg/nanosvg.h +++ b/rEFIt_UEFI/libeg/nanosvg.h @@ -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 diff --git a/rEFIt_UEFI/libeg/nanosvgrast.cpp b/rEFIt_UEFI/libeg/nanosvgrast.cpp index 5fd58e33c..44a07a44b 100644 --- a/rEFIt_UEFI/libeg/nanosvgrast.cpp +++ b/rEFIt_UEFI/libeg/nanosvgrast.cpp @@ -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); diff --git a/rEFIt_UEFI/libeg/text.cpp b/rEFIt_UEFI/libeg/text.cpp index a36398714..afe9424a8 100644 --- a/rEFIt_UEFI/libeg/text.cpp +++ b/rEFIt_UEFI/libeg/text.cpp @@ -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 diff --git a/rEFIt_UEFI/refit/lib.cpp b/rEFIt_UEFI/refit/lib.cpp index 2c2e7fb49..86e8332b4 100644 --- a/rEFIt_UEFI/refit/lib.cpp +++ b/rEFIt_UEFI/refit/lib.cpp @@ -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; } diff --git a/rEFIt_UEFI/refit/main.cpp b/rEFIt_UEFI/refit/main.cpp index d55b772c7..c9d17cefd 100644 --- a/rEFIt_UEFI/refit/main.cpp +++ b/rEFIt_UEFI/refit/main.cpp @@ -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