From 4b0d2f0ef0ff071ba845024971d81e7b3a0ca376 Mon Sep 17 00:00:00 2001 From: dayllenger Date: Mon, 16 Oct 2017 15:11:16 +0300 Subject: [PATCH] DrawableCache refactoring --- src/dlangui/graphics/resources.d | 253 ++++++++++++------------------- 1 file changed, 96 insertions(+), 157 deletions(-) diff --git a/src/dlangui/graphics/resources.d b/src/dlangui/graphics/resources.d index b595aab1..d0b59601 100644 --- a/src/dlangui/graphics/resources.d +++ b/src/dlangui/graphics/resources.d @@ -125,11 +125,13 @@ struct EmbeddedResourceList { void addResources(EmbeddedResource[] resources) { list ~= resources; } + void dumpEmbeddedResources() { foreach(r; list) { Log.d("EmbeddedResource: ", r.name); } } + /// find by exact file name EmbeddedResource * find(string name) { // search backwards to allow overriding standard resources (which are added first) @@ -147,6 +149,7 @@ struct EmbeddedResourceList { return &list[i]; return null; } + /// find by name w/o extension EmbeddedResource * findAutoExtension(string name) { string xmlname = name ~ ".xml"; @@ -211,18 +214,6 @@ EmbeddedResource[] embedResources(string[] resourceNames)() { return embedResources!(resourceNames[0 .. $/2])() ~ embedResources!(resourceNames[$/2 .. $])(); } -/// split string into lines, autodetect line endings -string[] splitLines(string s) { - auto lines_crlf = split(s, "\r\n"); - auto lines_cr = split(s, "\r"); - auto lines_lf = split(s, "\n"); - if (lines_crlf.length >= lines_cr.length && lines_crlf.length >= lines_lf.length) - return lines_crlf; - if (lines_cr.length > lines_lf.length) - return lines_cr; - return lines_lf; -} - /// embed all resources from list EmbeddedResource[] embedResourcesFromList(string resourceList)() { static if (BACKEND_CONSOLE) { @@ -850,6 +841,7 @@ class ImageDrawable : Drawable { debug _instanceCount--; debug(resalloc) Log.d("Destroyed ImageDrawable, count=", _instanceCount); } + @property override int width() { if (_image.isNull) return 0; @@ -857,6 +849,7 @@ class ImageDrawable : Drawable { return _image.width - 2; return _image.width; } + @property override int height() { if (_image.isNull) return 0; @@ -864,11 +857,13 @@ class ImageDrawable : Drawable { return _image.height - 2; return _image.height; } + @property override Rect padding() { if (!_image.isNull && _image.hasNinePatch) return _image.ninePatch.padding; return Rect(0,0,0,0); } + private static void correctFrameBounds(ref int n1, ref int n2, ref int n3, ref int n4) { if (n1 > n2) { //assert(n2 - n1 == n4 - n3); @@ -877,6 +872,7 @@ class ImageDrawable : Drawable { n3 = n4 = n3 + middledist; } } + override void drawTo(DrawBuf buf, Rect rc, uint state = 0, int tilex0 = 0, int tiley0 = 0) { if (_image.isNull) return; @@ -1266,9 +1262,11 @@ class ImageCache { bool _error; // flag to avoid loading of file if it has been failed once bool _used; + this(string filename) { _filename = filename; } + /// get normal image @property ref DrawBufRef get() { if (!_drawbuf.isNull || _error) { @@ -1301,6 +1299,7 @@ class ImageCache { } return _transformMap[transform]; } + /// remove from memory, will cause reload on next access void compact() { if (!_drawbuf.isNull) @@ -1389,13 +1388,12 @@ class DrawableCache { string _id; string _filename; bool _tiled; - bool _error; - bool _used; DrawableRef _drawable; DrawableRef[ColorTransform] _transformed; - debug private static __gshared int _instanceCount; - debug @property static int instanceCount() { return _instanceCount; } + bool _error; // flag to avoid loading of file if it has been failed once + bool _used; + this(string id, string filename, bool tiled) { _id = id; _filename = filename; @@ -1404,6 +1402,9 @@ class DrawableCache { debug ++_instanceCount; debug(resalloc) Log.d("Created DrawableCacheItem, count=", _instanceCount); } + debug private static __gshared int _instanceCount; + debug @property static int instanceCount() { return _instanceCount; } + ~this() { _drawable.clear(); foreach(ref t; _transformed) @@ -1431,126 +1432,26 @@ class DrawableCache { } /// returns drawable (loads from file if necessary) - @property ref DrawableRef drawable() { + @property ref DrawableRef drawable(in ColorTransform transform = ColorTransform()) { _used = true; - if (!_drawable.isNull || _error) - return _drawable; - if (_filename !is null) { - // reload from file - if (_filename.endsWith(".xml")) { - // XML drawables support - StateDrawable d = new StateDrawable(); - if (!d.load(_filename)) { - destroy(d); - _error = true; - } else { - _drawable = d; - } - } else if (_filename.endsWith(".tim")) { - static if (BACKEND_CONSOLE) { - try { - // .tim (text image) drawables support - string s = cast(string)loadResourceBytes(_filename); - if (s.length) { - TextDrawable d = new TextDrawable(s); - if (d.width && d.height) { - _drawable = d; - } - } - } catch (Exception e) { - // cannot find drawable file - } - } - if (!_drawable) - _error = true; - } else if (_filename.startsWith("#")) { - // color reference #AARRGGBB, e.g. #5599AA, or a gradient, or BorderDrawable description - _drawable = createColorDrawable(_filename); - } else if (_filename.startsWith("{")) { - // json in {} with text drawable description - static if (BACKEND_CONSOLE) { - _drawable = createTextDrawable(_filename); - } - } else { - static if (BACKEND_GUI) { - // PNG/JPEG drawables support - DrawBufRef image = imageCache.get(_filename); - if (!image.isNull) { - bool ninePatch = _filename.endsWith(".9.png"); - _drawable = new ImageDrawable(image, _tiled, ninePatch); - } else - _error = true; - } else { - _error = true; - } - } - } - return _drawable; - } - /// returns drawable (loads from file if necessary) - @property ref DrawableRef drawable(ref ColorTransform transform) { - if (transform.empty) - return drawable(); - if (transform in _transformed) + if (!transform.empty && transform in _transformed) return _transformed[transform]; - _used = true; if (!_drawable.isNull || _error) return _drawable; - if (_filename !is null) { - // reload from file - if (_filename.endsWith(".xml") || _filename.endsWith(".XML")) { - // XML drawables support - StateDrawable d = new StateDrawable(); - if (!d.load(_filename)) { - Log.e("failed to load .xml drawable from ", _filename); - destroy(d); - _error = true; - } else { - Log.d("loaded .xml drawable from ", _filename); - _drawable = d; - } - } else if (_filename.endsWith(".tim") || _filename.endsWith(".TIM")) { - static if (BACKEND_CONSOLE) { - try { - // .tim (text image) drawables support - string s = cast(string)loadResourceBytes(_filename); - if (s.length) { - TextDrawable d = new TextDrawable(s); - if (d.width && d.height) { - _drawable = d; - } - } - } catch (Exception e) { - // cannot find drawable file - } - } - if (!_drawable) - _error = true; - } else if (_filename.startsWith("{")) { - // json in {} with text drawable description - static if (BACKEND_CONSOLE) { - _drawable = createTextDrawable(_filename); - } - } else { - static if (BACKEND_GUI) { - // PNG/JPEG drawables support - DrawBufRef image = imageCache.get(_filename, transform); - if (!image.isNull) { - bool ninePatch = _filename.endsWith(".9.png") || _filename.endsWith(".9.PNG"); - _transformed[transform] = new ImageDrawable(image, _tiled, ninePatch); - return _transformed[transform]; - } else { - Log.e("failed to load image from ", _filename); - _error = true; - } - } else { - _error = true; - } - } + + // not in cache - create it + Drawable dr = makeDrawableFromId(_filename, _tiled, transform); + _error = dr is null; + if (transform.empty) { + _drawable = dr; + return _drawable; + } else { + _transformed[transform] = dr; + return _transformed[transform]; } - return _drawable; } } + void clear() { Log.d("DrawableCache.clear()"); _idToFileMap.destroy(); @@ -1568,35 +1469,19 @@ class DrawableCache { foreach (item; _idToDrawableMap) item.cleanup(); } + string[] _resourcePaths; string[string] _idToFileMap; DrawableCacheItem[string] _idToDrawableMap; DrawableRef _nullDrawable; - ref DrawableRef get(string id) { - while (id.length && (id[0] == ' ' || id[0] == '\t' || id[0] == '\r' || id[0] == '\n')) - id = id[1 .. $]; - if (id.equal("@null")) - return _nullDrawable; - if (id in _idToDrawableMap) - return _idToDrawableMap[id].drawable; - string resourceId = id; - bool tiled = false; - if (id.endsWith(".tiled")) { - resourceId = id[0..$-6]; // remove .tiled - tiled = true; - } - string filename = findResource(resourceId); - DrawableCacheItem item = new DrawableCacheItem(id, filename, tiled); - _idToDrawableMap[id] = item; - return item.drawable; - } - ref DrawableRef get(string id, ref ColorTransform transform) { - if (transform.empty) - return get(id); + + ref DrawableRef get(string id, in ColorTransform transform = ColorTransform()) { + id = id.strip; if (id.equal("@null")) return _nullDrawable; if (id in _idToDrawableMap) return _idToDrawableMap[id].drawable(transform); + // not found - create it string resourceId = id; bool tiled = false; if (id.endsWith(".tiled")) { @@ -1604,10 +1489,11 @@ class DrawableCache { tiled = true; } string filename = findResource(resourceId); - DrawableCacheItem item = new DrawableCacheItem(id, filename, tiled); + auto item = new DrawableCacheItem(id, filename, tiled); _idToDrawableMap[id] = item; return item.drawable(transform); } + @property string[] resourcePaths() { return _resourcePaths; } @@ -1629,6 +1515,7 @@ class DrawableCache { _resourcePaths = existingPaths; clear(); } + /// concatenates path with resource id and extension, returns pathname if there is such file, null if file does not exist private string checkFileName(string path, string id, string extension) { char[] fn = path.dup; @@ -1638,10 +1525,11 @@ class DrawableCache { return fn.dup; return null; } + /// get resource file full pathname by resource id, null if not found string findResource(string id) { if (id.startsWith("#") || id.startsWith("{")) - return id; // it's not a file name, just a color #AARRGGBB + return id; // it's not a file name if (id in _idToFileMap) return _idToFileMap[id]; EmbeddedResource * embedded = embeddedResourceList.findAutoExtension(id); @@ -1697,12 +1585,63 @@ class DrawableCache { } -// load text resource +/// This function takes an id and creates a drawable +/// id may be a name of file, #directive, color or json +private Drawable makeDrawableFromId(in string id, in bool tiled, ColorTransform transform = ColorTransform()) { + if (id !is null) { + if (id.endsWith(".xml") || id.endsWith(".XML")) { + // XML drawables support + auto d = new StateDrawable; + if (!d.load(id)) { + Log.e("failed to load .xml drawable from ", id); + destroy(d); + return null; + } else { + Log.d("loaded .xml drawable from ", id); + return d; + } + } else if (id.endsWith(".tim") || id.endsWith(".TIM")) { + static if (BACKEND_CONSOLE) { + try { + // .tim (text image) drawables support + string s = cast(string)loadResourceBytes(id); + if (s.length) { + auto d = new TextDrawable(s); + if (d.width && d.height) { + return d; + } + } + } catch (Exception e) { + // cannot find drawable file + } + } + } else if (id.startsWith("#")) { + // color reference #AARRGGBB, e.g. #5599AA, a gradient, border description, etc. + return createColorDrawable(id); + } else if (id.startsWith("{")) { + // json in {} with text drawable description + static if (BACKEND_CONSOLE) { + return createTextDrawable(id); + } + } else { + static if (BACKEND_GUI) { + // PNG/JPEG drawables support + DrawBufRef image = transform.empty ? imageCache.get(id) : imageCache.get(id, transform); + if (!image.isNull) { + bool ninePatch = id.endsWith(".9.png") || id.endsWith(".9.PNG"); + return new ImageDrawable(image, tiled, ninePatch); + } else + Log.e("Failed to load image from ", id); + } + } + } + return null; +} + + +/// load text resource string loadTextResource(string resourceId) { - import dlangui.graphics.resources; - import std.string : endsWith; - string filename; - filename = drawableCache.findResource(resourceId); + string filename = drawableCache.findResource(resourceId); if (!filename) { Log.e("Object resource file not found for resourceId ", resourceId); assert(false);