mirror of https://github.com/OpenTTD/OpenTTD.git
Fix: Memory leak in ICUParagraphLayout::NextLine() (#11895)
This function calls icu::BreakIterator::createLineInstance() but does not clean up after it. Instead use a static instance that is cloned (for thread-safety) and deleted as necessary.
This commit is contained in:
parent
1df7b21ee3
commit
6d276698b6
|
@ -334,6 +334,16 @@ Font *Layouter::GetFont(FontSize size, TextColour colour)
|
||||||
return fonts[size][colour].get();
|
return fonts[size][colour].get();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Perform initialization of layout engine.
|
||||||
|
*/
|
||||||
|
void Layouter::Initialize()
|
||||||
|
{
|
||||||
|
#if defined(WITH_ICU_I18N) && defined(WITH_HARFBUZZ)
|
||||||
|
ICUParagraphLayoutFactory::InitializeLayouter();
|
||||||
|
#endif /* WITH_ICU_I18N && WITH_HARFBUZZ */
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Reset cached font information.
|
* Reset cached font information.
|
||||||
* @param size Font size to reset.
|
* @param size Font size to reset.
|
||||||
|
|
|
@ -179,6 +179,7 @@ public:
|
||||||
Point GetCharPosition(std::string_view::const_iterator ch) const;
|
Point GetCharPosition(std::string_view::const_iterator ch) const;
|
||||||
ptrdiff_t GetCharAtPosition(int x, size_t line_index) const;
|
ptrdiff_t GetCharAtPosition(int x, size_t line_index) const;
|
||||||
|
|
||||||
|
static void Initialize();
|
||||||
static void ResetFontCache(FontSize size);
|
static void ResetFontCache(FontSize size);
|
||||||
static void ResetLineCache();
|
static void ResetLineCache();
|
||||||
static void ReduceLineCache();
|
static void ReduceLineCache();
|
||||||
|
|
|
@ -381,6 +381,30 @@ std::vector<ICURun> ItemizeStyle(std::vector<ICURun> &runs_current, FontMap &fon
|
||||||
return new ICUParagraphLayout(runs, buff, length);
|
return new ICUParagraphLayout(runs, buff, length);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* static */ std::unique_ptr<icu::BreakIterator> ICUParagraphLayoutFactory::break_iterator;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize data needed for the ICU layouter.
|
||||||
|
*/
|
||||||
|
/* static */ void ICUParagraphLayoutFactory::InitializeLayouter()
|
||||||
|
{
|
||||||
|
auto locale = icu::Locale(_current_language->isocode);
|
||||||
|
UErrorCode status = U_ZERO_ERROR;
|
||||||
|
ICUParagraphLayoutFactory::break_iterator.reset(icu::BreakIterator::createLineInstance(locale, status));
|
||||||
|
assert(U_SUCCESS(status));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a thread-safe line break iterator.
|
||||||
|
* @returns unique_ptr managed BreakIterator instance.
|
||||||
|
*/
|
||||||
|
/* static */ std::unique_ptr<icu::BreakIterator> ICUParagraphLayoutFactory::GetBreakIterator()
|
||||||
|
{
|
||||||
|
assert(ICUParagraphLayoutFactory::break_iterator != nullptr);
|
||||||
|
|
||||||
|
return std::unique_ptr<icu::BreakIterator>(ICUParagraphLayoutFactory::break_iterator->clone());
|
||||||
|
}
|
||||||
|
|
||||||
std::unique_ptr<const ICUParagraphLayout::Line> ICUParagraphLayout::NextLine(int max_width)
|
std::unique_ptr<const ICUParagraphLayout::Line> ICUParagraphLayout::NextLine(int max_width)
|
||||||
{
|
{
|
||||||
std::vector<ICURun>::iterator start_run = this->current_run;
|
std::vector<ICURun>::iterator start_run = this->current_run;
|
||||||
|
@ -413,11 +437,8 @@ std::unique_ptr<const ICUParagraphLayout::Line> ICUParagraphLayout::NextLine(int
|
||||||
/* If the text does not fit into the available width, find a suitable breaking point. */
|
/* If the text does not fit into the available width, find a suitable breaking point. */
|
||||||
int new_partial_length = 0;
|
int new_partial_length = 0;
|
||||||
if (cur_width > max_width) {
|
if (cur_width > max_width) {
|
||||||
auto locale = icu::Locale(_current_language->isocode);
|
|
||||||
|
|
||||||
/* Create a break-iterator to find a good place to break lines. */
|
/* Create a break-iterator to find a good place to break lines. */
|
||||||
UErrorCode err = U_ZERO_ERROR;
|
auto break_iterator = ICUParagraphLayoutFactory::GetBreakIterator();
|
||||||
auto break_iterator = icu::BreakIterator::createLineInstance(locale, err);
|
|
||||||
break_iterator->setText(icu::UnicodeString(this->buff, this->buff_length));
|
break_iterator->setText(icu::UnicodeString(this->buff, this->buff_length));
|
||||||
|
|
||||||
auto overflow_run = last_run - 1;
|
auto overflow_run = last_run - 1;
|
||||||
|
|
|
@ -12,6 +12,7 @@
|
||||||
|
|
||||||
#include "gfx_layout.h"
|
#include "gfx_layout.h"
|
||||||
|
|
||||||
|
#include <unicode/brkiter.h>
|
||||||
#include <unicode/ustring.h>
|
#include <unicode/ustring.h>
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -26,6 +27,11 @@ public:
|
||||||
|
|
||||||
static ParagraphLayouter *GetParagraphLayout(UChar *buff, UChar *buff_end, FontMap &fontMapping);
|
static ParagraphLayouter *GetParagraphLayout(UChar *buff, UChar *buff_end, FontMap &fontMapping);
|
||||||
static size_t AppendToBuffer(UChar *buff, const UChar *buffer_last, char32_t c);
|
static size_t AppendToBuffer(UChar *buff, const UChar *buffer_last, char32_t c);
|
||||||
|
|
||||||
|
static void InitializeLayouter();
|
||||||
|
static std::unique_ptr<icu::BreakIterator> GetBreakIterator();
|
||||||
|
private:
|
||||||
|
static std::unique_ptr<icu::BreakIterator> break_iterator;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* GFX_LAYOUT_ICU_H */
|
#endif /* GFX_LAYOUT_ICU_H */
|
||||||
|
|
|
@ -37,6 +37,7 @@
|
||||||
#include "network/network_content_gui.h"
|
#include "network/network_content_gui.h"
|
||||||
#include "newgrf_engine.h"
|
#include "newgrf_engine.h"
|
||||||
#include "core/backup_type.hpp"
|
#include "core/backup_type.hpp"
|
||||||
|
#include "gfx_layout.h"
|
||||||
#include <stack>
|
#include <stack>
|
||||||
#include <charconv>
|
#include <charconv>
|
||||||
|
|
||||||
|
@ -1976,6 +1977,8 @@ bool ReadLanguagePack(const LanguageMetadata *lang)
|
||||||
}
|
}
|
||||||
#endif /* WITH_ICU_I18N */
|
#endif /* WITH_ICU_I18N */
|
||||||
|
|
||||||
|
Layouter::Initialize();
|
||||||
|
|
||||||
/* Some lists need to be sorted again after a language change. */
|
/* Some lists need to be sorted again after a language change. */
|
||||||
ReconsiderGameScriptLanguage();
|
ReconsiderGameScriptLanguage();
|
||||||
InitializeSortedCargoSpecs();
|
InitializeSortedCargoSpecs();
|
||||||
|
|
Loading…
Reference in New Issue