mirror of https://github.com/buggins/dlangui.git
fix resource cleanup
This commit is contained in:
parent
b553a7e1d0
commit
300bc90dbf
|
@ -41,7 +41,7 @@ import std.algorithm;
|
|||
|
||||
/// array based collection of items
|
||||
/// retains item order when during add/remove operations
|
||||
struct Collection(T) {
|
||||
struct Collection(T, bool ownItems = false) {
|
||||
private T[] _items;
|
||||
private size_t _len;
|
||||
/// returns true if there are no items in collection
|
||||
|
@ -62,8 +62,11 @@ struct Collection(T) {
|
|||
// shrink
|
||||
static if (is(T == class) || is(T == struct)) {
|
||||
// clear items
|
||||
for (size_t i = newSize; i < _len; i++)
|
||||
_items[i] = T.init;
|
||||
for (size_t i = newSize; i < _len; i++) {
|
||||
static if (ownItems)
|
||||
destroy(_items[i]);
|
||||
_items[i] = T.init;
|
||||
}
|
||||
}
|
||||
} else if (newSize > _len) {
|
||||
// expand
|
||||
|
@ -130,7 +133,9 @@ struct Collection(T) {
|
|||
size_t index = indexOf(value);
|
||||
if (index == size_t.max)
|
||||
return false;
|
||||
remove(index);
|
||||
T res = remove(index);
|
||||
static if (ownItems)
|
||||
destroy(res);
|
||||
return true;
|
||||
}
|
||||
/// support of foreach with reference
|
||||
|
@ -147,8 +152,11 @@ struct Collection(T) {
|
|||
void clear() {
|
||||
static if (is(T == class) || is(T == struct)) {
|
||||
/// clear references
|
||||
for(size_t i = 0; i < _len; i++)
|
||||
_items[i] = T.init;
|
||||
for(size_t i = 0; i < _len; i++) {
|
||||
static if (ownItems)
|
||||
destroy(_items[i]);
|
||||
_items[i] = T.init;
|
||||
}
|
||||
}
|
||||
_len = 0;
|
||||
_items = null;
|
||||
|
|
|
@ -138,7 +138,16 @@ class DrawBuf : RefCountedObject {
|
|||
version (USE_OPENGL) {
|
||||
_id = drawBufIdGenerator++;
|
||||
}
|
||||
debug(resalloc) _instanceCount++;
|
||||
}
|
||||
|
||||
debug(resalloc) private static int _instanceCount;
|
||||
debug(resalloc) @property static int instanceCount() { return _instanceCount; }
|
||||
~this() {
|
||||
debug(resalloc) _instanceCount--;
|
||||
clear();
|
||||
}
|
||||
|
||||
protected void function(uint) _onDestroyCallback;
|
||||
@property void onDestroyCallback(void function(uint) callback) { _onDestroyCallback = callback; }
|
||||
@property void function(uint) onDestroyCallback() { return _onDestroyCallback; }
|
||||
|
@ -355,7 +364,6 @@ class DrawBuf : RefCountedObject {
|
|||
}
|
||||
|
||||
void clear() {}
|
||||
~this() { clear(); }
|
||||
}
|
||||
|
||||
alias DrawBufRef = Ref!DrawBuf;
|
||||
|
|
|
@ -5,6 +5,7 @@ import dlangui.graphics.fonts;
|
|||
|
||||
import derelict.freetype.ft;
|
||||
private import dlangui.core.logger;
|
||||
private import dlangui.core.collections;
|
||||
private import std.algorithm;
|
||||
private import std.file;
|
||||
private import std.string;
|
||||
|
@ -99,7 +100,7 @@ private class FreeTypeFontFile {
|
|||
@property int weight() { return _weight; }
|
||||
@property bool italic() { return _italic; }
|
||||
|
||||
//private static int _instanceCount;
|
||||
debug private static int _instanceCount;
|
||||
this(FT_Library library, string filename) {
|
||||
_library = library;
|
||||
_filename = filename;
|
||||
|
@ -107,12 +108,12 @@ private class FreeTypeFontFile {
|
|||
_matrix.yy = 0x10000;
|
||||
_matrix.xy = 0;
|
||||
_matrix.yx = 0;
|
||||
//Log.d("Created FreeTypeFontFile, count=", ++_instanceCount);
|
||||
debug Log.d("Created FreeTypeFontFile, count=", ++_instanceCount);
|
||||
}
|
||||
|
||||
~this() {
|
||||
clear();
|
||||
//Log.d("Destroyed FreeTypeFontFile, count=", --_instanceCount);
|
||||
debug Log.d("Destroyed FreeTypeFontFile, count=", --_instanceCount);
|
||||
}
|
||||
|
||||
private static string familyName(FT_Face face)
|
||||
|
@ -292,21 +293,21 @@ private class FreeTypeFontFile {
|
|||
*/
|
||||
class FreeTypeFont : Font {
|
||||
private FontFileItem _fontItem;
|
||||
private FreeTypeFontFile[] _files;
|
||||
private Collection!(FreeTypeFontFile, true) _files;
|
||||
|
||||
static int _instanceCount;
|
||||
debug(resalloc) static int _instanceCount;
|
||||
/// need to call create() after construction to initialize font
|
||||
this(FontFileItem item, int size) {
|
||||
_fontItem = item;
|
||||
_size = size;
|
||||
_height = size;
|
||||
debug Log.d("Created font, count=", ++_instanceCount);
|
||||
debug(resalloc) Log.d("Created font, count=", ++_instanceCount);
|
||||
}
|
||||
|
||||
/// do cleanup
|
||||
~this() {
|
||||
clear();
|
||||
debug Log.d("Destroyed font, count=", --_instanceCount);
|
||||
debug(resalloc) Log.d("Destroyed font, count=", --_instanceCount);
|
||||
}
|
||||
|
||||
private int _size;
|
||||
|
@ -317,10 +318,6 @@ class FreeTypeFont : Font {
|
|||
|
||||
/// cleanup resources
|
||||
override void clear() {
|
||||
foreach(ref FreeTypeFontFile file; _files) {
|
||||
destroy(file);
|
||||
file = null;
|
||||
}
|
||||
_files.clear();
|
||||
}
|
||||
|
||||
|
@ -375,8 +372,10 @@ class FreeTypeFont : Font {
|
|||
foreach (string filename; _fontItem.filenames) {
|
||||
FreeTypeFontFile file = new FreeTypeFontFile(_fontItem.library, filename);
|
||||
if (file.open(_size, 0)) {
|
||||
_files ~= file;
|
||||
}
|
||||
_files.add(file);
|
||||
} else {
|
||||
destroy(file);
|
||||
}
|
||||
}
|
||||
return _files.length > 0;
|
||||
}
|
||||
|
@ -503,6 +502,7 @@ class FreeTypeFontManager : FontManager {
|
|||
weight = font.weight;
|
||||
Log.d("Using properties from font file: face=", face, " weight=", weight, " italic=", italic);
|
||||
}
|
||||
destroy(font);
|
||||
|
||||
FontDef def = FontDef(family, face, italic, weight);
|
||||
FontFileItem item = findFileItem(def);
|
||||
|
|
|
@ -24,8 +24,8 @@ Copyright: Vadim Lopatin, 2014
|
|||
License: $(WEB boost.org/LICENSE_1_0.txt, Boost License 1.0).
|
||||
Authors: $(WEB coolreader.org, Vadim Lopatin)
|
||||
*/
|
||||
module dlangui.graphics.resources;
|
||||
|
||||
module dlangui.graphics.resources;
|
||||
|
||||
import dlangui.graphics.images;
|
||||
import dlangui.graphics.drawbuf;
|
||||
import dlangui.core.logger;
|
||||
|
@ -34,8 +34,8 @@ import std.algorithm;
|
|||
import std.xml;
|
||||
import std.algorithm;
|
||||
import std.conv;
|
||||
|
||||
|
||||
|
||||
|
||||
class Drawable : RefCountedObject {
|
||||
//private static int _instanceCount;
|
||||
this() {
|
||||
|
@ -169,17 +169,28 @@ static Drawable createColorDrawable(string s) {
|
|||
class ImageDrawable : Drawable {
|
||||
protected DrawBufRef _image;
|
||||
protected bool _tiled;
|
||||
//private int _instanceCount;
|
||||
|
||||
debug(resalloc) private static int _instanceCount;
|
||||
|
||||
this(ref DrawBufRef image, bool tiled = false, bool ninePatch = false) {
|
||||
_image = image;
|
||||
_tiled = tiled;
|
||||
if (ninePatch)
|
||||
_image.detectNinePatch();
|
||||
//Log.d("Created ImageDrawable, count=", ++_instanceCount);
|
||||
debug(resalloc) {
|
||||
_instanceCount++;
|
||||
Log.d("Created ImageDrawable, count=", _instanceCount);
|
||||
}
|
||||
}
|
||||
debug(resalloc) {
|
||||
@property static int instanceCount() { return _instanceCount; }
|
||||
}
|
||||
~this() {
|
||||
_image.clear();
|
||||
//Log.d("Destroyed ImageDrawable, count=", --_instanceCount);
|
||||
debug(resalloc) {
|
||||
_instanceCount--;
|
||||
Log.d("Destroyed ImageDrawable, count=", _instanceCount);
|
||||
}
|
||||
}
|
||||
@property override int width() {
|
||||
if (_image.isNull)
|
||||
|
@ -328,29 +339,29 @@ void extractStateFlags(ref string[string] attr, ref uint stateMask, ref uint sta
|
|||
sample:
|
||||
(prefix android: is optional)
|
||||
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<selector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:constantSize=["true" | "false"]
|
||||
android:dither=["true" | "false"]
|
||||
android:variablePadding=["true" | "false"] >
|
||||
<item
|
||||
android:drawable="@[package:]drawable/drawable_resource"
|
||||
android:state_pressed=["true" | "false"]
|
||||
android:state_focused=["true" | "false"]
|
||||
android:state_hovered=["true" | "false"]
|
||||
android:state_selected=["true" | "false"]
|
||||
android:state_checkable=["true" | "false"]
|
||||
android:state_checked=["true" | "false"]
|
||||
android:state_enabled=["true" | "false"]
|
||||
android:state_activated=["true" | "false"]
|
||||
android:state_window_focused=["true" | "false"] />
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<selector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:constantSize=["true" | "false"]
|
||||
android:dither=["true" | "false"]
|
||||
android:variablePadding=["true" | "false"] >
|
||||
<item
|
||||
android:drawable="@[package:]drawable/drawable_resource"
|
||||
android:state_pressed=["true" | "false"]
|
||||
android:state_focused=["true" | "false"]
|
||||
android:state_hovered=["true" | "false"]
|
||||
android:state_selected=["true" | "false"]
|
||||
android:state_checkable=["true" | "false"]
|
||||
android:state_checked=["true" | "false"]
|
||||
android:state_enabled=["true" | "false"]
|
||||
android:state_activated=["true" | "false"]
|
||||
android:state_window_focused=["true" | "false"] />
|
||||
</selector>
|
||||
*/
|
||||
*/
|
||||
|
||||
/// Drawable which is drawn depending on state (see http://developer.android.com/guide/topics/resources/drawable-resource.html#StateList)
|
||||
class StateDrawable : Drawable {
|
||||
|
||||
static struct StateItem {
|
||||
static class StateItem {
|
||||
uint stateMask;
|
||||
uint stateValue;
|
||||
ColorTransform transform;
|
||||
|
@ -366,8 +377,14 @@ class StateDrawable : Drawable {
|
|||
// max drawable size for all states
|
||||
protected Point _size;
|
||||
|
||||
~this() {
|
||||
foreach(ref item; _stateList)
|
||||
destroy(item);
|
||||
_stateList = null;
|
||||
}
|
||||
|
||||
void addState(uint stateMask, uint stateValue, string resourceId, ref ColorTransform transform) {
|
||||
StateItem item;
|
||||
StateItem item = new StateItem();
|
||||
item.stateMask = stateMask;
|
||||
item.stateValue = stateValue;
|
||||
item.drawable = drawableCache.get(resourceId, transform);
|
||||
|
@ -375,14 +392,14 @@ class StateDrawable : Drawable {
|
|||
}
|
||||
|
||||
void addState(uint stateMask, uint stateValue, DrawableRef drawable) {
|
||||
StateItem item;
|
||||
StateItem item = new StateItem();
|
||||
item.stateMask = stateMask;
|
||||
item.stateValue = stateValue;
|
||||
item.drawable = drawable;
|
||||
itemAdded(item);
|
||||
}
|
||||
|
||||
private void itemAdded(ref StateItem item) {
|
||||
private void itemAdded(StateItem item) {
|
||||
_stateList ~= item;
|
||||
if (!item.drawable.isNull) {
|
||||
if (_size.x < item.drawable.width)
|
||||
|
@ -471,12 +488,12 @@ class StateDrawable : Drawable {
|
|||
import std.string;
|
||||
|
||||
try {
|
||||
string s = cast(string)std.file.read(filename);
|
||||
|
||||
// Check for well-formedness
|
||||
//check(s);
|
||||
|
||||
// Make a DOM tree
|
||||
string s = cast(string)std.file.read(filename);
|
||||
|
||||
// Check for well-formedness
|
||||
//check(s);
|
||||
|
||||
// Make a DOM tree
|
||||
auto doc = new Document(s);
|
||||
|
||||
return load(doc);
|
||||
|
@ -513,8 +530,8 @@ class StateDrawable : Drawable {
|
|||
alias DrawableRef = Ref!Drawable;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/// decoded raster images cache (png, jpeg) -- access by filenames
|
||||
class ImageCache {
|
||||
|
@ -654,23 +671,29 @@ class DrawableCache {
|
|||
DrawableRef _drawable;
|
||||
DrawableRef[ColorTransform] _transformed;
|
||||
|
||||
//private int _instanceCount;
|
||||
debug(resalloc) private static int _instanceCount;
|
||||
this(string id, string filename, bool tiled) {
|
||||
_id = id;
|
||||
_filename = filename;
|
||||
_tiled = tiled;
|
||||
_error = filename is null;
|
||||
//Log.d("Created DrawableCacheItem, count=", ++_instanceCount);
|
||||
debug(resalloc) Log.d("Created DrawableCacheItem, count=", ++_instanceCount);
|
||||
}
|
||||
~this() {
|
||||
_drawable.clear();
|
||||
//Log.d("Destroyed DrawableCacheItem, count=", --_instanceCount);
|
||||
foreach(ref t; _transformed)
|
||||
t.clear();
|
||||
_transformed.clear();
|
||||
debug(resalloc) Log.d("Destroyed DrawableCacheItem, count=", --_instanceCount);
|
||||
}
|
||||
/// remove from memory, will cause reload on next access
|
||||
void compact() {
|
||||
if (!_drawable.isNull)
|
||||
_drawable.clear();
|
||||
}
|
||||
foreach(t; _transformed)
|
||||
t.clear();
|
||||
_transformed.clear();
|
||||
}
|
||||
/// mark as not used
|
||||
void checkpoint() {
|
||||
_used = false;
|
||||
|
@ -864,12 +887,15 @@ class DrawableCache {
|
|||
debug Log.i("Creating DrawableCache");
|
||||
}
|
||||
~this() {
|
||||
debug Log.i("Destroying DrawableCache");
|
||||
debug(resalloc) Log.e("Drawable instace count before destroying of DrawableCache: ", ImageDrawable.instanceCount);
|
||||
|
||||
Log.i("Destroying DrawableCache _idToDrawableMap.length=", _idToDrawableMap.length);
|
||||
foreach (ref item; _idToDrawableMap) {
|
||||
destroy(item);
|
||||
item = null;
|
||||
}
|
||||
_idToDrawableMap.clear();
|
||||
debug(resalloc) Log.e("Drawable instace count after destroying of DrawableCache: ", ImageDrawable.instanceCount);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -54,6 +54,8 @@ version(USE_SDL) {
|
|||
}
|
||||
if (_win)
|
||||
SDL_DestroyWindow(_win);
|
||||
if (_drawbuf)
|
||||
destroy(_drawbuf);
|
||||
}
|
||||
|
||||
version(USE_OPENGL) {
|
||||
|
@ -798,7 +800,7 @@ version(USE_SDL) {
|
|||
|
||||
SDL_DisplayMode displayMode;
|
||||
if (SDL_Init(SDL_INIT_VIDEO|SDL_INIT_TIMER|SDL_INIT_EVENTS) != 0) {
|
||||
Log.e("Cannot init SDL2");
|
||||
Log.e("Cannot init SDL2");
|
||||
return 2;
|
||||
}
|
||||
scope(exit)SDL_Quit();
|
||||
|
@ -828,7 +830,7 @@ version(USE_SDL) {
|
|||
Platform.setInstance(null);
|
||||
|
||||
//
|
||||
debug {
|
||||
debug(resalloc) {
|
||||
Widget.shuttingDown();
|
||||
}
|
||||
|
||||
|
@ -836,10 +838,19 @@ version(USE_SDL) {
|
|||
drawableCache = null;
|
||||
imageCache = null;
|
||||
FontManager.instance = null;
|
||||
debug {
|
||||
if (Widget.instanceCount() > 0) {
|
||||
Log.e("Non-zero Widget instance count when exiting: ", Widget.instanceCount());
|
||||
debug(resalloc) {
|
||||
if (DrawBuf.instanceCount > 0) {
|
||||
Log.e("Non-zero DrawBuf instance count when exiting: ", DrawBuf.instanceCount);
|
||||
}
|
||||
if (Style.instanceCount > 0) {
|
||||
Log.e("Non-zero Style instance count when exiting: ", Style.instanceCount);
|
||||
}
|
||||
if (Widget.instanceCount() > 0) {
|
||||
Log.e("Non-zero Widget instance count when exiting: ", Widget.instanceCount);
|
||||
}
|
||||
if (ImageDrawable.instanceCount > 0) {
|
||||
Log.e("Non-zero ImageDrawable instance count when exiting: ", ImageDrawable.instanceCount);
|
||||
}
|
||||
}
|
||||
Log.d("Exiting main");
|
||||
|
||||
|
|
|
@ -123,6 +123,10 @@ class ImageWidget : Widget {
|
|||
_drawableId = drawableId;
|
||||
}
|
||||
|
||||
~this() {
|
||||
_drawable.clear();
|
||||
}
|
||||
|
||||
/// get drawable image id
|
||||
@property string drawableId() { return _drawableId; }
|
||||
/// set drawable image id
|
||||
|
|
|
@ -451,14 +451,18 @@ class Style {
|
|||
return this;
|
||||
}
|
||||
|
||||
private static int _instanceCount;
|
||||
debug(resalloc) private static int _instanceCount;
|
||||
debug(resalloc) @property static int instanceCount() { return _instanceCount; }
|
||||
|
||||
this(Theme theme, string id) {
|
||||
_theme = theme;
|
||||
_parentStyle = theme;
|
||||
_id = id;
|
||||
debug(resalloc) _instanceCount++;
|
||||
//Log.d("Created style ", _id, ", count=", ++_instanceCount);
|
||||
}
|
||||
|
||||
|
||||
~this() {
|
||||
foreach(ref Style item; _substates) {
|
||||
//Log.d("Destroying substate");
|
||||
|
@ -473,6 +477,7 @@ class Style {
|
|||
_children.clear();
|
||||
_backgroundDrawable.clear();
|
||||
_font.clear();
|
||||
debug(resalloc) _instanceCount--;
|
||||
//Log.d("Destroyed style ", _id, ", parentId=", _parentId, ", state=", _stateMask, ", count=", --_instanceCount);
|
||||
}
|
||||
|
||||
|
|
|
@ -121,7 +121,7 @@ class Widget {
|
|||
/// set new trackHover flag value (when true, widget will change Hover state while mouse is moving)
|
||||
@property Widget trackHover(bool v) { _trackHover = v; return this; }
|
||||
|
||||
debug {
|
||||
debug(resalloc) {
|
||||
private static int _instanceCount = 0;
|
||||
private static bool _appShuttingDown = false;
|
||||
}
|
||||
|
@ -129,13 +129,12 @@ class Widget {
|
|||
this(string ID = null) {
|
||||
_id = ID;
|
||||
_state = State.Enabled;
|
||||
debug {
|
||||
_instanceCount++;
|
||||
}
|
||||
debug(resalloc) _instanceCount++;
|
||||
//Log.d("Created widget, count = ", ++_instanceCount);
|
||||
}
|
||||
|
||||
~this() {
|
||||
debug {
|
||||
debug(resalloc) {
|
||||
//Log.v("destroying widget ", _id);
|
||||
if (_appShuttingDown)
|
||||
Log.e("Destroying widget ", _id, " after app shutdown: probably, resource leak");
|
||||
|
@ -146,7 +145,8 @@ class Widget {
|
|||
_ownStyle = null;
|
||||
//Log.d("Destroyed widget, count = ", --_instanceCount);
|
||||
}
|
||||
debug {
|
||||
|
||||
debug(resalloc) {
|
||||
/// for debug purposes - number of created widget objects, not yet destroyed
|
||||
static @property int instanceCount() { return _instanceCount; }
|
||||
/// for debug purposes - sets shutdown flag to log widgets not destroyed in time.
|
||||
|
|
Loading…
Reference in New Issue