Reuse previously calculated string widths

This commit is contained in:
Thomas Goyne 2015-01-18 14:56:48 -08:00
parent 427037a552
commit 2269dbcfe0
8 changed files with 80 additions and 38 deletions

View File

@ -156,6 +156,7 @@
<ClInclude Include="$(SrcDir)factory_manager.h" />
<ClInclude Include="$(SrcDir)ffmpegsource_common.h" />
<ClInclude Include="$(SrcDir)fft.h" />
<ClInclude Include="$(SrcDir)flyweight_hash.h" />
<ClInclude Include="$(SrcDir)font_file_lister.h" />
<ClInclude Include="$(SrcDir)frame_main.h" />
<ClInclude Include="$(SrcDir)gl_text.h" />

View File

@ -549,6 +549,9 @@
<ClInclude Include="$(SrcDir)dialogs.h">
<Filter>Features</Filter>
</ClInclude>
<ClInclude Include="$(SrcDir)flyweight_hash.h">
<Filter>Utilities</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="$(SrcDir)ass_dialogue.cpp">
@ -1040,9 +1043,6 @@
<ClCompile Include="$(SrcDir)ass_parser.cpp">
<Filter>ASS</Filter>
</ClCompile>
<ClCompile Include="$(SrcDir)audio_provider_lock.cpp">
<Filter>Audio\Providers</Filter>
</ClCompile>
<ClCompile Include="$(SrcDir)command\keyframe.cpp">
<Filter>Commands</Filter>
</ClCompile>
@ -1093,4 +1093,4 @@
<ResourceCompile Include="$(SrcDir)res\res.rc" />
<ResourceCompile Include="$(SrcDir)res\strings.rc" />
</ItemGroup>
</Project>
</Project>

View File

@ -45,6 +45,7 @@
#include "subs_controller.h"
#include "video_controller.h"
#include <libaegisub/make_unique.h>
#include <libaegisub/util.h>
#include <algorithm>
@ -598,15 +599,17 @@ void BaseGrid::SetColumnWidths() {
text_refresh_rects.clear();
int x = 0;
WidthHelper helper{dc, std::unordered_map<boost::flyweight<std::string>, int>{}};
helper.widths.reserve(prev_unique_string_widths);
if (!width_helper)
width_helper = agi::make_unique<WidthHelper>();
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 {

View File

@ -30,6 +30,7 @@
#include <libaegisub/signal.h>
#include <memory>
#include <string>
#include <vector>
#include <wx/window.h>
@ -39,6 +40,7 @@ namespace agi {
}
class AssDialogue;
class GridColumn;
class WidthHelper;
class BaseGrid final : public wxWindow {
std::vector<agi::signal::Connection> connections;
@ -57,7 +59,7 @@ class BaseGrid final : public wxWindow {
int active_row = -1;
size_t prev_unique_string_widths = 0;
std::unique_ptr<WidthHelper> width_helper;
/// Rows which are visible on the current video frame
std::vector<int> visible_rows;

28
src/flyweight_hash.h Normal file
View File

@ -0,0 +1,28 @@
// Copyright (c) 2015, Thomas Goyne <plorkyeran@aegisub.org>
//
// 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 <boost/flyweight.hpp>
namespace std {
template <typename T>
struct hash<boost::flyweight<T>> {
size_t operator()(boost::flyweight<T> const& ss) const {
return hash<const void*>()(&ss.get());
}
};
}

View File

@ -27,39 +27,52 @@
#include <wx/dc.h>
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<std::string> 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<wchar_t *>(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) {

View File

@ -14,7 +14,8 @@
//
// Aegisub Project http://www.aegisub.org/
#include <boost/flyweight.hpp>
#include "flyweight_hash.h"
#include <memory>
#include <string>
#include <vector>
@ -25,19 +26,21 @@ class wxDC;
class wxString;
namespace agi { struct Context; }
namespace std {
template <typename T>
struct hash<boost::flyweight<T>> {
size_t operator()(boost::flyweight<T> const& ss) const {
return hash<const void*>()(&ss.get());
}
class WidthHelper {
struct Entry {
int width;
int age;
};
}
struct WidthHelper {
wxDC &dc;
std::unordered_map<boost::flyweight<std::string>, int> widths;
int age = 0;
wxDC *dc = nullptr;
std::unordered_map<boost::flyweight<std::string>, Entry> widths;
#ifdef _WIN32
wxString scratch;
#endif
public:
void SetDC(wxDC *dc) { this->dc = dc; }
void Age();
int operator()(boost::flyweight<std::string> const& str);
int operator()(std::string const& str);

View File

@ -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 <wx/sizer.h>
#include <wx/spinctrl.h>
namespace std {
template <typename T>
struct hash<boost::flyweight<T>> {
size_t operator()(boost::flyweight<T> const& ss) const {
return hash<const void*>()(&ss.get());
}
};
}
namespace {
/// Work around wxGTK's fondness for generating events from ChangeValue