From 2d6cb3e2089bdee1b2e158a869f56f025c0a0fb0 Mon Sep 17 00:00:00 2001 From: lawnjelly Date: Sun, 13 Dec 2020 10:12:10 +0000 Subject: [PATCH] Batching - Protection against zero and small sized ninepatches Although the minimum size of ninepatches is set to the sum of the margins in normal use (through gdscript etc) it turns out that it is possible to programmatically create ninepatches that are small than this minimum - in particular zero size is used in sliders to not draw items. This PR deals with zero sized ninepatches by not drawing anything, and has some basic protection for ninepatches smaller than the margins. Whether these occur in the wild is not clear but is put in for completeness. --- .../gles_common/rasterizer_canvas_batcher.h | 37 ++++++++++++++----- 1 file changed, 27 insertions(+), 10 deletions(-) diff --git a/drivers/gles_common/rasterizer_canvas_batcher.h b/drivers/gles_common/rasterizer_canvas_batcher.h index 59f520dddcc5..73286e705220 100644 --- a/drivers/gles_common/rasterizer_canvas_batcher.h +++ b/drivers/gles_common/rasterizer_canvas_batcher.h @@ -1357,6 +1357,22 @@ template bool C_PREAMBLE::_prefill_ninepatch(RasterizerCanvas::Item::CommandNinePatch *p_np, FillState &r_fill_state, int &r_command_start, int command_num, int command_count, RasterizerCanvas::Item *p_item, bool multiply_final_modulate) { typename T_STORAGE::Texture *tex = get_storage()->texture_owner.getornull(p_np->texture); + if (!tex) { + // FIXME: Handle textureless ninepatch gracefully + WARN_PRINT("NinePatch without texture not supported yet, skipping."); + return false; + } + if (tex->width == 0 || tex->height == 0) { + WARN_PRINT("Cannot set empty texture to NinePatch."); + return false; + } + + // cope with ninepatch of zero area. These cannot be created by the user interface or gdscript, but can + // be created programmatically from c++, e.g. by the Godot UI for sliders. We will just not draw these. + if ((p_np->rect.size.x * p_np->rect.size.y) <= 0.0f) { + return false; + } + // conditions for creating a new batch if (r_fill_state.curr_batch->type != RasterizerStorageCommon::BT_RECT) { @@ -1368,16 +1384,6 @@ bool C_PREAMBLE::_prefill_ninepatch(RasterizerCanvas::Item::CommandNinePatch *p_ } } - if (!tex) { - // FIXME: Handle textureless ninepatch gracefully - WARN_PRINT("NinePatch without texture not supported yet in GLES2 backend, skipping."); - return false; - } - if (tex->width == 0 || tex->height == 0) { - WARN_PRINT("Cannot set empty texture to NinePatch."); - return false; - } - // first check there are enough verts for this to complete successfully if (bdata.vertices.size() + (4 * 9) > bdata.vertices.max_size()) { // return where we got to @@ -1446,6 +1452,17 @@ bool C_PREAMBLE::_prefill_ninepatch(RasterizerCanvas::Item::CommandNinePatch *p_ v[3] = v[0] + source.size.y; v[2] = v[3] - tex_margin_bottom; + // Some protection for the use of ninepatches with rect size smaller than margin size. + // Note these cannot be produced by the UI, only programmatically, and the results + // are somewhat undefined, because the margins overlap. + // Ninepatch get_minimum_size() forces minimum size to be the sum of the margins. + // So this should occur very rarely if ever. Consider commenting these 4 lines out for higher speed + // in ninepatches. + x[1] = MIN(x[1], x[3]); + x[2] = MIN(x[2], x[3]); + y[1] = MIN(y[1], y[3]); + y[2] = MIN(y[2], y[3]); + // temporarily override to prevent single rect fallback bool single_rect_fallback = bdata.settings_use_single_rect_fallback; bdata.settings_use_single_rect_fallback = false;