diff --git a/build/Aegisub/Aegisub.vcxproj b/build/Aegisub/Aegisub.vcxproj index 76209cdae..c0e935cef 100644 --- a/build/Aegisub/Aegisub.vcxproj +++ b/build/Aegisub/Aegisub.vcxproj @@ -156,6 +156,7 @@ + diff --git a/build/Aegisub/Aegisub.vcxproj.filters b/build/Aegisub/Aegisub.vcxproj.filters index ca09046ad..458dc1fe4 100644 --- a/build/Aegisub/Aegisub.vcxproj.filters +++ b/build/Aegisub/Aegisub.vcxproj.filters @@ -549,6 +549,9 @@ Features + + Utilities + @@ -1040,9 +1043,6 @@ ASS - - Audio\Providers - Commands @@ -1093,4 +1093,4 @@ - + \ No newline at end of file diff --git a/src/base_grid.cpp b/src/base_grid.cpp index 1d3801c96..25f9f6197 100644 --- a/src/base_grid.cpp +++ b/src/base_grid.cpp @@ -45,6 +45,7 @@ #include "subs_controller.h" #include "video_controller.h" +#include #include #include @@ -598,15 +599,17 @@ void BaseGrid::SetColumnWidths() { text_refresh_rects.clear(); int x = 0; - WidthHelper helper{dc, std::unordered_map, int>{}}; - helper.widths.reserve(prev_unique_string_widths); + if (!width_helper) + width_helper = agi::make_unique(); + width_helper->SetDC(&dc); + for (auto const& column : columns) { - column->UpdateWidth(context, helper); + column->UpdateWidth(context, *width_helper); if (column->Width() && column->RefreshOnTextChange()) text_refresh_rects.emplace_back(x, 0, column->Width(), h); x += column->Width(); } - prev_unique_string_widths = helper.widths.size(); + width_helper->Age(); } AssDialogue *BaseGrid::GetDialogue(int n) const { diff --git a/src/base_grid.h b/src/base_grid.h index 86ca3071d..366189588 100644 --- a/src/base_grid.h +++ b/src/base_grid.h @@ -30,6 +30,7 @@ #include #include +#include #include #include @@ -39,6 +40,7 @@ namespace agi { } class AssDialogue; class GridColumn; +class WidthHelper; class BaseGrid final : public wxWindow { std::vector connections; @@ -57,7 +59,7 @@ class BaseGrid final : public wxWindow { int active_row = -1; - size_t prev_unique_string_widths = 0; + std::unique_ptr width_helper; /// Rows which are visible on the current video frame std::vector visible_rows; diff --git a/src/flyweight_hash.h b/src/flyweight_hash.h new file mode 100644 index 000000000..3eb3afff2 --- /dev/null +++ b/src/flyweight_hash.h @@ -0,0 +1,28 @@ +// Copyright (c) 2015, Thomas Goyne +// +// Permission to use, copy, modify, and distribute this software for any +// purpose with or without fee is hereby granted, provided that the above +// copyright notice and this permission notice appear in all copies. +// +// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +// +// Aegisub Project http://www.aegisub.org/ + +#pragma once + +#include + +namespace std { + template + struct hash> { + size_t operator()(boost::flyweight const& ss) const { + return hash()(&ss.get()); + } + }; +} diff --git a/src/grid_column.cpp b/src/grid_column.cpp index 757966b93..289ea79b3 100644 --- a/src/grid_column.cpp +++ b/src/grid_column.cpp @@ -27,39 +27,52 @@ #include +void WidthHelper::Age() { + for (auto it = begin(widths), e = end(widths); it != e; ) { + if (it->second.age == age) + ++it; + else + it = widths.erase(it); + } + ++age; +} + int WidthHelper::operator()(boost::flyweight const& str) { if (str.get().empty()) return 0; auto it = widths.find(str); - if (it != end(widths)) return it->second; + if (it != end(widths)) { + it->second.age = age; + return it->second.width; + } #ifdef _WIN32 wxMBConvUTF8 conv; size_t len = conv.ToWChar(nullptr, 0, str.get().c_str(), str.get().size()); scratch.resize(len); conv.ToWChar(const_cast(scratch.wx_str()), len, str.get().c_str(), str.get().size()); - int width = dc.GetTextExtent(scratch).GetWidth(); + int width = dc->GetTextExtent(scratch).GetWidth(); #else - int width = dc.GetTextExtent(to_wx(str)).GetWidth(); + int width = dc->GetTextExtent(to_wx(str)).GetWidth(); #endif - widths[str] = width; + widths[str] = {width, age}; return width; } int WidthHelper::operator()(std::string const& str) { - return dc.GetTextExtent(to_wx(str)).GetWidth(); + return dc->GetTextExtent(to_wx(str)).GetWidth(); } int WidthHelper::operator()(wxString const& str) { - return dc.GetTextExtent(str).GetWidth(); + return dc->GetTextExtent(str).GetWidth(); } int WidthHelper::operator()(const char *str) { - return dc.GetTextExtent(wxString::FromUTF8(str)).GetWidth(); + return dc->GetTextExtent(wxString::FromUTF8(str)).GetWidth(); } int WidthHelper::operator()(const wchar_t *str) { - return dc.GetTextExtent(str).GetWidth(); + return dc->GetTextExtent(str).GetWidth(); } void GridColumn::UpdateWidth(const agi::Context *c, WidthHelper &helper) { diff --git a/src/grid_column.h b/src/grid_column.h index 54497610b..16b70f2a9 100644 --- a/src/grid_column.h +++ b/src/grid_column.h @@ -14,7 +14,8 @@ // // Aegisub Project http://www.aegisub.org/ -#include +#include "flyweight_hash.h" + #include #include #include @@ -25,19 +26,21 @@ class wxDC; class wxString; namespace agi { struct Context; } -namespace std { - template - struct hash> { - size_t operator()(boost::flyweight const& ss) const { - return hash()(&ss.get()); - } +class WidthHelper { + struct Entry { + int width; + int age; }; -} - -struct WidthHelper { - wxDC &dc; - std::unordered_map, int> widths; + int age = 0; + wxDC *dc = nullptr; + std::unordered_map, Entry> widths; +#ifdef _WIN32 wxString scratch; +#endif + +public: + void SetDC(wxDC *dc) { this->dc = dc; } + void Age(); int operator()(boost::flyweight const& str); int operator()(std::string const& str); diff --git a/src/subs_edit_box.cpp b/src/subs_edit_box.cpp index 7ed9111bc..c19b2f9c8 100644 --- a/src/subs_edit_box.cpp +++ b/src/subs_edit_box.cpp @@ -40,6 +40,7 @@ #include "command/command.h" #include "compat.h" #include "dialog_style_editor.h" +#include "flyweight_hash.h" #include "include/aegisub/context.h" #include "include/aegisub/hotkey.h" #include "initial_line_state.h" @@ -69,15 +70,6 @@ #include #include -namespace std { - template - struct hash> { - size_t operator()(boost::flyweight const& ss) const { - return hash()(&ss.get()); - } - }; -} - namespace { /// Work around wxGTK's fondness for generating events from ChangeValue