Compare commits
1 Commits
gdk-win32-
...
wip/cherge
Author | SHA1 | Date | |
---|---|---|---|
|
990102f269 |
@@ -306,6 +306,11 @@ collect_reused_child_nodes (GskRenderer *renderer,
|
||||
gsk_debug_node_get_child (node));
|
||||
break;
|
||||
|
||||
case GSK_HINT_NODE:
|
||||
collect_reused_node (renderer,
|
||||
gsk_hint_node_get_child (node));
|
||||
break;
|
||||
|
||||
/* Generic nodes */
|
||||
|
||||
case GSK_CONTAINER_NODE:
|
||||
@@ -796,6 +801,11 @@ gsk_broadway_renderer_add_node (GskRenderer *renderer,
|
||||
}
|
||||
return;
|
||||
|
||||
case GSK_HINT_NODE:
|
||||
gsk_broadway_renderer_add_node (renderer,
|
||||
gsk_hint_node_get_child (node), offset_x, offset_y, clip_bounds);
|
||||
return;
|
||||
|
||||
/* Generic nodes */
|
||||
|
||||
case GSK_CONTAINER_NODE:
|
||||
|
@@ -173,6 +173,11 @@ struct _GskGLRenderJob
|
||||
* looking at the format of the framebuffer we are rendering on.
|
||||
*/
|
||||
int target_format;
|
||||
|
||||
/* If caching render nodes is inhibited from a hint node through
|
||||
* all of the descendants.
|
||||
*/
|
||||
int inhibit_cache_count;
|
||||
};
|
||||
|
||||
typedef struct _GskGLRenderOffscreen
|
||||
@@ -2903,6 +2908,9 @@ is_non_branching (const GskRenderNode *node)
|
||||
case GSK_DEBUG_NODE:
|
||||
return is_non_branching (gsk_debug_node_get_child (node));
|
||||
|
||||
case GSK_HINT_NODE:
|
||||
return is_non_branching (gsk_hint_node_get_child (node));
|
||||
|
||||
case GSK_CONTAINER_NODE:
|
||||
return gsk_container_node_get_n_children (node) == 1 &&
|
||||
is_non_branching (gsk_container_node_get_child (node, 0));
|
||||
@@ -3646,6 +3654,51 @@ gsk_gl_render_job_visit_repeat_node (GskGLRenderJob *job,
|
||||
gsk_gl_render_job_end_draw (job);
|
||||
}
|
||||
|
||||
static void
|
||||
gsk_gl_render_job_visit_hint_node (GskGLRenderJob *job,
|
||||
const GskRenderNode *node)
|
||||
{
|
||||
const GskRenderNode *child = gsk_hint_node_get_child (node);
|
||||
GskRenderHints hints = gsk_hint_node_get_hints (node);
|
||||
gboolean never_cache = !!(hints & GSK_RENDER_HINTS_NEVER_CACHE);
|
||||
gboolean force_cache = !!(hints & GSK_RENDER_HINTS_FORCE_CACHE);
|
||||
|
||||
job->inhibit_cache_count += never_cache;
|
||||
|
||||
if (force_cache && job->inhibit_cache_count == 0)
|
||||
{
|
||||
GskGLRenderOffscreen offscreen = {0};
|
||||
|
||||
offscreen.bounds = &child->bounds;
|
||||
offscreen.reset_clip = TRUE;
|
||||
offscreen.force_offscreen = TRUE;
|
||||
|
||||
/* gsk_gl_render_job_visit_node_with_offscreen() will cache the texture
|
||||
* for @child and if already cached, re-use it without further rendering.
|
||||
*/
|
||||
if (!gsk_gl_render_job_visit_node_with_offscreen (job, child, &offscreen))
|
||||
g_assert_not_reached ();
|
||||
|
||||
g_assert (offscreen.texture_id);
|
||||
g_assert (offscreen.was_offscreen == TRUE);
|
||||
|
||||
gsk_gl_render_job_begin_draw (job, CHOOSE_PROGRAM (job, blit));
|
||||
gsk_gl_program_set_uniform_texture (job->current_program,
|
||||
UNIFORM_SHARED_SOURCE, 0,
|
||||
GL_TEXTURE_2D,
|
||||
GL_TEXTURE0,
|
||||
offscreen.texture_id);
|
||||
gsk_gl_render_job_draw_offscreen (job, &node->bounds, &offscreen);
|
||||
gsk_gl_render_job_end_draw (job);
|
||||
}
|
||||
else
|
||||
{
|
||||
gsk_gl_render_job_visit_node (job, child);
|
||||
}
|
||||
|
||||
job->inhibit_cache_count -= never_cache;
|
||||
}
|
||||
|
||||
static void
|
||||
gsk_gl_render_job_visit_node (GskGLRenderJob *job,
|
||||
const GskRenderNode *node)
|
||||
@@ -3757,6 +3810,10 @@ gsk_gl_render_job_visit_node (GskGLRenderJob *job,
|
||||
gsk_gl_render_job_visit_node (job, gsk_debug_node_get_child (node));
|
||||
break;
|
||||
|
||||
case GSK_HINT_NODE:
|
||||
gsk_gl_render_job_visit_hint_node (job, node);
|
||||
break;
|
||||
|
||||
case GSK_GL_SHADER_NODE:
|
||||
gsk_gl_render_job_visit_gl_shader_node (job, node);
|
||||
break;
|
||||
@@ -4000,7 +4057,7 @@ gsk_gl_render_job_visit_node_with_offscreen (GskGLRenderJob *job,
|
||||
|
||||
init_full_texture_region (offscreen);
|
||||
|
||||
if (!offscreen->do_not_cache)
|
||||
if (!offscreen->do_not_cache && job->inhibit_cache_count == 0)
|
||||
gsk_gl_driver_cache_texture (job->driver, &key, offscreen->texture_id);
|
||||
|
||||
return TRUE;
|
||||
|
@@ -50,7 +50,8 @@
|
||||
* @GSK_BLUR_NODE: A node that applies a blur
|
||||
* @GSK_DEBUG_NODE: Debug information that does not affect the rendering
|
||||
* @GSK_GL_SHADER_NODE: A node that uses OpenGL fragment shaders to render
|
||||
|
||||
* @GSK_HINT_NODE: A node that provides hints to the renderer
|
||||
|
||||
* The type of a node determines what the node is rendering.
|
||||
*/
|
||||
typedef enum {
|
||||
@@ -79,7 +80,8 @@ typedef enum {
|
||||
GSK_TEXT_NODE,
|
||||
GSK_BLUR_NODE,
|
||||
GSK_DEBUG_NODE,
|
||||
GSK_GL_SHADER_NODE
|
||||
GSK_GL_SHADER_NODE,
|
||||
GSK_HINT_NODE
|
||||
} GskRenderNodeType;
|
||||
|
||||
/**
|
||||
@@ -251,5 +253,24 @@ typedef enum
|
||||
GSK_GL_UNIFORM_TYPE_VEC4,
|
||||
} GskGLUniformType;
|
||||
|
||||
/**
|
||||
* GskRenderHints:
|
||||
* @GSK_RENDER_HINTS_NEVER_CACHE: Hints to the renderer that it should never
|
||||
* cache the contents of this or any descendant node.
|
||||
* @GSK_RENDER_HINTS_FORCE_CACHE: Hints to the renderer that it should try
|
||||
* to cache the conents of the node as it is likely to be reused in future
|
||||
* render requests.
|
||||
*
|
||||
* This defines the hints that may be provided to renderers to instruct
|
||||
* preferred behavior.
|
||||
*
|
||||
* Since: 4.8
|
||||
*/
|
||||
typedef enum
|
||||
{
|
||||
GSK_RENDER_HINTS_NEVER_CACHE = 1 << 0,
|
||||
GSK_RENDER_HINTS_FORCE_CACHE = 1 << 1,
|
||||
} GskRenderHints;
|
||||
|
||||
|
||||
#endif /* __GSK_TYPES_H__ */
|
||||
|
@@ -164,6 +164,7 @@ GskRenderNode * gsk_render_node_deserialize (GBytes
|
||||
#define GSK_TYPE_TEXT_NODE (gsk_text_node_get_type())
|
||||
#define GSK_TYPE_BLUR_NODE (gsk_blur_node_get_type())
|
||||
#define GSK_TYPE_GL_SHADER_NODE (gsk_gl_shader_node_get_type())
|
||||
#define GSK_TYPE_HINT_NODE (gsk_hint_node_get_type())
|
||||
|
||||
typedef struct _GskDebugNode GskDebugNode;
|
||||
typedef struct _GskColorNode GskColorNode;
|
||||
@@ -190,6 +191,7 @@ typedef struct _GskCrossFadeNode GskCrossFadeNode;
|
||||
typedef struct _GskTextNode GskTextNode;
|
||||
typedef struct _GskBlurNode GskBlurNode;
|
||||
typedef struct _GskGLShaderNode GskGLShaderNode;
|
||||
typedef struct _GskHintNode GskHintNode;
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
GType gsk_debug_node_get_type (void) G_GNUC_CONST;
|
||||
@@ -534,6 +536,16 @@ GBytes * gsk_gl_shader_node_get_args (const GskRender
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
GskGLShader * gsk_gl_shader_node_get_shader (const GskRenderNode *node) G_GNUC_PURE;
|
||||
|
||||
GDK_AVAILABLE_IN_4_8
|
||||
GType gsk_hint_node_get_type (void) G_GNUC_CONST;
|
||||
GDK_AVAILABLE_IN_4_8
|
||||
GskRenderNode * gsk_hint_node_new (GskRenderNode *child,
|
||||
GskRenderHints hints);
|
||||
GDK_AVAILABLE_IN_4_8
|
||||
GskRenderNode * gsk_hint_node_get_child (const GskRenderNode *node) G_GNUC_PURE;
|
||||
GDK_AVAILABLE_IN_4_8
|
||||
GskRenderHints gsk_hint_node_get_hints (const GskRenderNode *node) G_GNUC_PURE;
|
||||
|
||||
/**
|
||||
* GSK_VALUE_HOLDS_RENDER_NODE:
|
||||
* @value: a `GValue`
|
||||
|
@@ -5056,6 +5056,127 @@ gsk_debug_node_get_message (const GskRenderNode *node)
|
||||
return self->message;
|
||||
}
|
||||
|
||||
/*** GSK_HINT_NODE ***/
|
||||
|
||||
/**
|
||||
* GskHintNode:
|
||||
*
|
||||
* A render node that provides hints to the renderer about how a child node
|
||||
* should be processed.
|
||||
*/
|
||||
struct _GskHintNode
|
||||
{
|
||||
GskRenderNode render_node;
|
||||
|
||||
GskRenderNode *child;
|
||||
GskRenderHints hints;
|
||||
};
|
||||
|
||||
static void
|
||||
gsk_hint_node_finalize (GskRenderNode *node)
|
||||
{
|
||||
GskHintNode *self = (GskHintNode *) node;
|
||||
GskRenderNodeClass *parent_class = g_type_class_peek (g_type_parent (GSK_TYPE_HINT_NODE));
|
||||
|
||||
gsk_render_node_unref (self->child);
|
||||
|
||||
parent_class->finalize (node);
|
||||
}
|
||||
|
||||
static void
|
||||
gsk_hint_node_draw (GskRenderNode *node,
|
||||
cairo_t *cr)
|
||||
{
|
||||
GskHintNode *self = (GskHintNode *) node;
|
||||
|
||||
gsk_render_node_draw (self->child, cr);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gsk_hint_node_can_diff (const GskRenderNode *node1,
|
||||
const GskRenderNode *node2)
|
||||
{
|
||||
GskHintNode *self1 = (GskHintNode *) node1;
|
||||
GskHintNode *self2 = (GskHintNode *) node2;
|
||||
|
||||
return gsk_render_node_can_diff (self1->child, self2->child);
|
||||
}
|
||||
|
||||
static void
|
||||
gsk_hint_node_diff (GskRenderNode *node1,
|
||||
GskRenderNode *node2,
|
||||
cairo_region_t *region)
|
||||
{
|
||||
GskHintNode *self1 = (GskHintNode *) node1;
|
||||
GskHintNode *self2 = (GskHintNode *) node2;
|
||||
|
||||
gsk_render_node_diff (self1->child, self2->child, region);
|
||||
}
|
||||
|
||||
/**
|
||||
* gsk_hint_node_new:
|
||||
* @child: The child to add hint info for
|
||||
* @hints: The hints for the child
|
||||
*
|
||||
* Creates a `GskRenderNode` that will add hints about how the child
|
||||
* should be processed by the renderer.
|
||||
*
|
||||
* Returns: (transfer full) (type GskHintNode): A new `GskRenderNode`
|
||||
*/
|
||||
GskRenderNode *
|
||||
gsk_hint_node_new (GskRenderNode *child,
|
||||
GskRenderHints hints)
|
||||
{
|
||||
GskHintNode *self;
|
||||
GskRenderNode *node;
|
||||
|
||||
g_return_val_if_fail (GSK_IS_RENDER_NODE (child), NULL);
|
||||
|
||||
self = gsk_render_node_alloc (GSK_HINT_NODE);
|
||||
node = (GskRenderNode *) self;
|
||||
|
||||
self->child = gsk_render_node_ref (child);
|
||||
self->hints = hints;
|
||||
|
||||
graphene_rect_init_from_rect (&node->bounds, &child->bounds);
|
||||
|
||||
node->prefers_high_depth = gsk_render_node_prefers_high_depth (child);
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
/**
|
||||
* gsk_hint_node_get_child:
|
||||
* @node: (type GskHintNode): a hint `GskRenderNode`
|
||||
*
|
||||
* Gets the child node that is getting drawn by the given @node.
|
||||
*
|
||||
* Returns: (transfer none): the child `GskRenderNode`
|
||||
**/
|
||||
GskRenderNode *
|
||||
gsk_hint_node_get_child (const GskRenderNode *node)
|
||||
{
|
||||
const GskHintNode *self = (const GskHintNode *) node;
|
||||
|
||||
return self->child;
|
||||
}
|
||||
|
||||
/**
|
||||
* gsk_hint_node_get_hints:
|
||||
* @node: (type GskHintNode): a hint `GskRenderNode`
|
||||
*
|
||||
* Gets the hints applied to this node
|
||||
*
|
||||
* Returns: The hints for the node
|
||||
**/
|
||||
GskRenderHints
|
||||
gsk_hint_node_get_hints (const GskRenderNode *node)
|
||||
{
|
||||
const GskHintNode *self = (const GskHintNode *) node;
|
||||
|
||||
return self->hints;
|
||||
}
|
||||
|
||||
/*** GSK_GL_SHADER_NODE ***/
|
||||
|
||||
/**
|
||||
@@ -5298,6 +5419,7 @@ GSK_DEFINE_RENDER_NODE_TYPE (gsk_cross_fade_node, GSK_CROSS_FADE_NODE)
|
||||
GSK_DEFINE_RENDER_NODE_TYPE (gsk_text_node, GSK_TEXT_NODE)
|
||||
GSK_DEFINE_RENDER_NODE_TYPE (gsk_blur_node, GSK_BLUR_NODE)
|
||||
GSK_DEFINE_RENDER_NODE_TYPE (gsk_gl_shader_node, GSK_GL_SHADER_NODE)
|
||||
GSK_DEFINE_RENDER_NODE_TYPE (gsk_hint_node, GSK_HINT_NODE)
|
||||
GSK_DEFINE_RENDER_NODE_TYPE (gsk_debug_node, GSK_DEBUG_NODE)
|
||||
|
||||
static void
|
||||
@@ -5687,6 +5809,22 @@ gsk_render_node_init_types_once (void)
|
||||
gsk_render_node_types[GSK_GL_SHADER_NODE] = node_type;
|
||||
}
|
||||
|
||||
{
|
||||
const GskRenderNodeTypeInfo node_info =
|
||||
{
|
||||
GSK_HINT_NODE,
|
||||
sizeof (GskHintNode),
|
||||
NULL,
|
||||
gsk_hint_node_finalize,
|
||||
gsk_hint_node_draw,
|
||||
gsk_hint_node_can_diff,
|
||||
gsk_hint_node_diff,
|
||||
};
|
||||
|
||||
GType node_type = gsk_render_node_type_register_static (I_("GskHintNode"), &node_info);
|
||||
gsk_render_node_types[GSK_HINT_NODE] = node_type;
|
||||
}
|
||||
|
||||
{
|
||||
const GskRenderNodeTypeInfo node_info =
|
||||
{
|
||||
|
@@ -416,6 +416,29 @@ clear_string (gpointer inout_string)
|
||||
g_clear_pointer ((char **) inout_string, g_free);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
parse_bool (GtkCssParser *parser,
|
||||
gpointer out_bool)
|
||||
{
|
||||
if (gtk_css_parser_try_ident (parser, "true") ||
|
||||
gtk_css_parser_try_ident (parser, "True") ||
|
||||
gtk_css_parser_try_ident (parser, "TRUE"))
|
||||
{
|
||||
*(gboolean *) out_bool = TRUE;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
if (gtk_css_parser_try_ident (parser, "false") ||
|
||||
gtk_css_parser_try_ident (parser, "False") ||
|
||||
gtk_css_parser_try_ident (parser, "FALSE"))
|
||||
{
|
||||
*(gboolean *) out_bool = FALSE;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
parse_stops (GtkCssParser *parser,
|
||||
gpointer out_stops)
|
||||
@@ -1102,7 +1125,7 @@ parse_conic_gradient_node (GtkCssParser *parser)
|
||||
g_array_append_val (stops, to);
|
||||
}
|
||||
|
||||
result = gsk_conic_gradient_node_new (&bounds, ¢er, rotation,
|
||||
result = gsk_conic_gradient_node_new (&bounds, ¢er, rotation,
|
||||
(GskColorStop *) stops->data, stops->len);
|
||||
|
||||
g_array_free (stops, TRUE);
|
||||
@@ -1388,7 +1411,7 @@ parse_cairo_node (GtkCssParser *parser)
|
||||
parse_declarations (parser, declarations, G_N_ELEMENTS(declarations));
|
||||
|
||||
node = gsk_cairo_node_new (&bounds);
|
||||
|
||||
|
||||
if (surface != NULL)
|
||||
{
|
||||
cairo_t *cr = gsk_cairo_node_get_draw_context (node);
|
||||
@@ -1816,6 +1839,37 @@ parse_debug_node (GtkCssParser *parser)
|
||||
return result;
|
||||
}
|
||||
|
||||
static GskRenderNode *
|
||||
parse_hint_node (GtkCssParser *parser)
|
||||
{
|
||||
gboolean force_cache = FALSE;
|
||||
gboolean never_cache = FALSE;
|
||||
GskRenderHints hints = 0;
|
||||
GskRenderNode *child = NULL;
|
||||
const Declaration declarations[] = {
|
||||
{ "never-cache", parse_bool, NULL, &never_cache },
|
||||
{ "force-cache", parse_bool, NULL, &force_cache },
|
||||
{ "child", parse_node, clear_node, &child },
|
||||
};
|
||||
GskRenderNode *result;
|
||||
|
||||
parse_declarations (parser, declarations, G_N_ELEMENTS(declarations));
|
||||
if (child == NULL)
|
||||
child = create_default_render_node ();
|
||||
|
||||
if (never_cache)
|
||||
hints |= GSK_RENDER_HINTS_NEVER_CACHE;
|
||||
|
||||
if (force_cache)
|
||||
hints |= GSK_RENDER_HINTS_FORCE_CACHE;
|
||||
|
||||
result = gsk_hint_node_new (child, hints);
|
||||
|
||||
gsk_render_node_unref (child);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
parse_node (GtkCssParser *parser,
|
||||
gpointer out_node)
|
||||
@@ -1849,6 +1903,7 @@ parse_node (GtkCssParser *parser,
|
||||
{ "texture", parse_texture_node },
|
||||
{ "transform", parse_transform_node },
|
||||
{ "glshader", parse_glshader_node },
|
||||
{ "hint", parse_hint_node },
|
||||
};
|
||||
GskRenderNode **node_p = out_node;
|
||||
guint i;
|
||||
@@ -2158,6 +2213,17 @@ append_point_param (Printer *p,
|
||||
g_string_append_c (p->str, '\n');
|
||||
}
|
||||
|
||||
static void
|
||||
append_bool_param (Printer *p,
|
||||
const char *param_name,
|
||||
gboolean value)
|
||||
{
|
||||
_indent (p);
|
||||
g_string_append_printf (p->str, "%s: %s", param_name, value ? "true" : "false");
|
||||
g_string_append_c (p->str, ';');
|
||||
g_string_append_c (p->str, '\n');
|
||||
}
|
||||
|
||||
static void
|
||||
append_string_param (Printer *p,
|
||||
const char *param_name,
|
||||
@@ -2765,6 +2831,24 @@ render_node_print (Printer *p,
|
||||
}
|
||||
break;
|
||||
|
||||
case GSK_HINT_NODE:
|
||||
{
|
||||
GskRenderHints hints = gsk_hint_node_get_hints (node);
|
||||
|
||||
start_node (p, "hint");
|
||||
|
||||
if (hints & GSK_RENDER_HINTS_NEVER_CACHE)
|
||||
append_bool_param (p, "never-cache", TRUE);
|
||||
|
||||
if (hints & GSK_RENDER_HINTS_FORCE_CACHE)
|
||||
append_bool_param (p, "force-cache", TRUE);
|
||||
|
||||
append_node_param (p, "child", gsk_hint_node_get_child (node));
|
||||
|
||||
end_node (p);
|
||||
}
|
||||
break;
|
||||
|
||||
case GSK_BLUR_NODE:
|
||||
{
|
||||
start_node (p, "blur");
|
||||
|
@@ -13,7 +13,7 @@ typedef struct _GskRenderNodeClass GskRenderNodeClass;
|
||||
* We don't add an "n-types" value to avoid having to handle
|
||||
* it in every single switch.
|
||||
*/
|
||||
#define GSK_RENDER_NODE_TYPE_N_TYPES (GSK_GL_SHADER_NODE + 1)
|
||||
#define GSK_RENDER_NODE_TYPE_N_TYPES (GSK_HINT_NODE + 1)
|
||||
|
||||
extern GType gsk_render_node_types[];
|
||||
|
||||
|
@@ -232,6 +232,9 @@ create_list_model_for_render_node (GskRenderNode *node)
|
||||
|
||||
case GSK_DEBUG_NODE:
|
||||
return create_render_node_list_model ((GskRenderNode *[1]) { gsk_debug_node_get_child (node) }, 1);
|
||||
|
||||
case GSK_HINT_NODE:
|
||||
return create_render_node_list_model ((GskRenderNode *[1]) { gsk_hint_node_get_child (node) }, 1);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -310,6 +313,8 @@ node_type_name (GskRenderNodeType type)
|
||||
return "Blur";
|
||||
case GSK_GL_SHADER_NODE:
|
||||
return "GL Shader";
|
||||
case GSK_HINT_NODE:
|
||||
return "Hint";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -343,6 +348,7 @@ node_name (GskRenderNode *node)
|
||||
case GSK_TEXT_NODE:
|
||||
case GSK_BLUR_NODE:
|
||||
case GSK_GL_SHADER_NODE:
|
||||
case GSK_HINT_NODE:
|
||||
return g_strdup (node_type_name (gsk_render_node_get_node_type (node)));
|
||||
|
||||
case GSK_DEBUG_NODE:
|
||||
@@ -1216,6 +1222,19 @@ populate_render_node_properties (GtkListStore *store,
|
||||
add_text_row (store, "Message", gsk_debug_node_get_message (node));
|
||||
break;
|
||||
|
||||
case GSK_HINT_NODE:
|
||||
{
|
||||
GskRenderHints hints = gsk_hint_node_get_hints (node);
|
||||
|
||||
if (hints & GSK_RENDER_HINTS_NEVER_CACHE)
|
||||
add_text_row (store, "Never Cache", "True");
|
||||
|
||||
if (hints & GSK_RENDER_HINTS_FORCE_CACHE)
|
||||
add_text_row (store, "Force Cache", "True");
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case GSK_SHADOW_NODE:
|
||||
{
|
||||
int i;
|
||||
|
Reference in New Issue
Block a user