/**************************************************************************
 *
 * Copyright 2009 VMware, Inc.  All Rights Reserved.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and associated documentation files (the
 * "Software"), to deal in the Software without restriction, including
 * without limitation the rights to use, copy, modify, merge, publish,
 * distribute, sub license, and/or sell copies of the Software, and to
 * permit persons to whom the Software is furnished to do so, subject to
 * the following conditions:
 *
 * The above copyright notice and this permission notice (including the
 * next paragraph) shall be included in all copies or substantial portions
 * of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
 * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR
 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 *
 **************************************************************************/

#include "VG/openvg.h"

#include "vg_context.h"
#include "paint.h"
#include "path.h"
#include "image.h"
#include "matrix.h"
#include "api_consts.h"

#include "pipe/p_compiler.h"
#include "util/u_pointer.h"
#include "util/u_math.h"

#include <math.h>

static INLINE struct vg_state *current_state()
{
   struct vg_context *ctx = vg_current_context();
   if (!ctx)
      return 0;
   else
      return &ctx->state.vg;
}

static INLINE VGboolean count_in_bounds(VGParamType type, VGint count)
{
   if (count < 0)
      return VG_FALSE;

   if (type == VG_SCISSOR_RECTS)
      return (!(count % 4) && (count >= 0 || count <= VEGA_MAX_SCISSOR_RECTS * 4));
   else if (type == VG_STROKE_DASH_PATTERN) {
      return count <= VEGA_MAX_DASH_COUNT;
   } else {
      VGint real_count = vgGetVectorSize(type);
      return count == real_count;
   }
}

void vgSetf (VGParamType type, VGfloat value)
{
   struct vg_context *ctx = vg_current_context();
   struct vg_state *state = current_state();
   VGErrorCode error = VG_NO_ERROR;

   switch(type) {
   case VG_MATRIX_MODE:
   case VG_FILL_RULE:
   case VG_IMAGE_QUALITY:
   case VG_RENDERING_QUALITY:
   case VG_BLEND_MODE:
   case VG_IMAGE_MODE:
#ifdef OPENVG_VERSION_1_1
   case VG_COLOR_TRANSFORM:
#endif
   case VG_STROKE_CAP_STYLE:
   case VG_STROKE_JOIN_STYLE:
   case VG_STROKE_DASH_PHASE_RESET:
   case VG_MASKING:
   case VG_SCISSORING:
   case VG_PIXEL_LAYOUT:
   case VG_SCREEN_LAYOUT:
   case VG_FILTER_FORMAT_LINEAR:
   case VG_FILTER_FORMAT_PREMULTIPLIED:
   case VG_FILTER_CHANNEL_MASK:

   case VG_MAX_SCISSOR_RECTS:
   case VG_MAX_DASH_COUNT:
   case VG_MAX_KERNEL_SIZE:
   case VG_MAX_SEPARABLE_KERNEL_SIZE:
   case VG_MAX_COLOR_RAMP_STOPS:
   case VG_MAX_IMAGE_WIDTH:
   case VG_MAX_IMAGE_HEIGHT:
   case VG_MAX_IMAGE_PIXELS:
   case VG_MAX_IMAGE_BYTES:
   case VG_MAX_GAUSSIAN_STD_DEVIATION:
   case VG_MAX_FLOAT:
      vgSeti(type, floor(value));
      return;
      break;
   case VG_STROKE_LINE_WIDTH:
      state->stroke.line_width.f = value;
      state->stroke.line_width.i = float_to_int_floor(*((VGuint*)(&value)));
      break;
   case VG_STROKE_MITER_LIMIT:
      state->stroke.miter_limit.f = value;
      state->stroke.miter_limit.i = float_to_int_floor(*((VGuint*)(&value)));
      break;
   case VG_STROKE_DASH_PHASE:
      state->stroke.dash_phase.f = value;
      state->stroke.dash_phase.i = float_to_int_floor(*((VGuint*)(&value)));
      break;
   default:
      error = VG_ILLEGAL_ARGUMENT_ERROR;
      break;
   }
   vg_set_error(ctx, error);
}

void vgSeti (VGParamType type, VGint value)
{
   struct vg_context *ctx = vg_current_context();
   struct vg_state *state = current_state();
   VGErrorCode error = VG_NO_ERROR;

   switch(type) {
   case VG_MATRIX_MODE:
      if (value < VG_MATRIX_PATH_USER_TO_SURFACE ||
#ifdef OPENVG_VERSION_1_1
          value > VG_MATRIX_GLYPH_USER_TO_SURFACE)
#else
          value > VG_MATRIX_STROKE_PAINT_TO_USER)
#endif
         error = VG_ILLEGAL_ARGUMENT_ERROR;
      else
         state->matrix_mode = value;
      break;
   case VG_FILL_RULE:
      if (value < VG_EVEN_ODD ||
          value > VG_NON_ZERO)
         error = VG_ILLEGAL_ARGUMENT_ERROR;
      else
         state->fill_rule = value;
      break;
   case VG_IMAGE_QUALITY:
      state->image_quality = value;
      break;
   case VG_RENDERING_QUALITY:
      if (value < VG_RENDERING_QUALITY_NONANTIALIASED ||
          value > VG_RENDERING_QUALITY_BETTER)
         error = VG_ILLEGAL_ARGUMENT_ERROR;
      else
         state->rendering_quality = value;
      break;
   case VG_BLEND_MODE:
      if (value < VG_BLEND_SRC ||
          value > VG_BLEND_ADDITIVE)
         error = VG_ILLEGAL_ARGUMENT_ERROR;
      else {
         ctx->state.dirty |= BLEND_DIRTY;
         state->blend_mode = value;
      }
      break;
   case VG_IMAGE_MODE:
      if (value < VG_DRAW_IMAGE_NORMAL ||
          value > VG_DRAW_IMAGE_STENCIL)
         error = VG_ILLEGAL_ARGUMENT_ERROR;
      else
         state->image_mode = value;
#ifdef OPENVG_VERSION_1_1
   case VG_COLOR_TRANSFORM:
      state->color_transform = value;
#endif
      break;
   case VG_STROKE_LINE_WIDTH:
      state->stroke.line_width.f = value;
      state->stroke.line_width.i = value;
      break;
   case VG_STROKE_CAP_STYLE:
      if (value < VG_CAP_BUTT ||
          value > VG_CAP_SQUARE)
         error = VG_ILLEGAL_ARGUMENT_ERROR;
      else
         state->stroke.cap_style = value;
      break;
   case VG_STROKE_JOIN_STYLE:
      if (value < VG_JOIN_MITER ||
          value > VG_JOIN_BEVEL)
         error = VG_ILLEGAL_ARGUMENT_ERROR;
      else
         state->stroke.join_style = value;
      break;
   case VG_STROKE_MITER_LIMIT:
      state->stroke.miter_limit.f = value;
      state->stroke.miter_limit.i = value;
      break;
   case VG_STROKE_DASH_PHASE:
      state->stroke.dash_phase.f = value;
      state->stroke.dash_phase.i = value;
      break;
   case VG_STROKE_DASH_PHASE_RESET:
      state->stroke.dash_phase_reset = value;
      break;
   case VG_MASKING:
      state->masking = value;
      break;
   case VG_SCISSORING:
      state->scissoring = value;
      ctx->state.dirty |= DEPTH_STENCIL_DIRTY;
      break;
   case VG_PIXEL_LAYOUT:
      if (value < VG_PIXEL_LAYOUT_UNKNOWN ||
          value > VG_PIXEL_LAYOUT_BGR_HORIZONTAL)
         error = VG_ILLEGAL_ARGUMENT_ERROR;
      else
         state->pixel_layout = value;
      break;
   case VG_SCREEN_LAYOUT:
      /* read only ignore */
      break;
   case VG_FILTER_FORMAT_LINEAR:
      state->filter_format_linear = value;
      break;
   case VG_FILTER_FORMAT_PREMULTIPLIED:
      state->filter_format_premultiplied = value;
      break;
   case VG_FILTER_CHANNEL_MASK:
      state->filter_channel_mask = value;
      break;

   case VG_MAX_SCISSOR_RECTS:
   case VG_MAX_DASH_COUNT:
   case VG_MAX_KERNEL_SIZE:
   case VG_MAX_SEPARABLE_KERNEL_SIZE:
   case VG_MAX_COLOR_RAMP_STOPS:
   case VG_MAX_IMAGE_WIDTH:
   case VG_MAX_IMAGE_HEIGHT:
   case VG_MAX_IMAGE_PIXELS:
   case VG_MAX_IMAGE_BYTES:
   case VG_MAX_GAUSSIAN_STD_DEVIATION:
   case VG_MAX_FLOAT:
      /* read only ignore */
      break;
   default:
      error = VG_ILLEGAL_ARGUMENT_ERROR;
      break;
   }
   vg_set_error(ctx, error);
}

void vgSetfv(VGParamType type, VGint count,
             const VGfloat * values)
{
   struct vg_context *ctx = vg_current_context();
   struct vg_state *state = current_state();
   VGErrorCode error = VG_NO_ERROR;

   if ((count && !values) || !count_in_bounds(type, count) || !is_aligned(values)) {
      vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
      return;
   }

   switch(type) {
   case VG_MATRIX_MODE:
   case VG_FILL_RULE:
   case VG_IMAGE_QUALITY:
   case VG_RENDERING_QUALITY:
   case VG_BLEND_MODE:
   case VG_IMAGE_MODE:
#ifdef OPENVG_VERSION_1_1
   case VG_COLOR_TRANSFORM:
#endif
   case VG_STROKE_CAP_STYLE:
   case VG_STROKE_JOIN_STYLE:
   case VG_STROKE_DASH_PHASE_RESET:
   case VG_MASKING:
   case VG_SCISSORING:
   case VG_PIXEL_LAYOUT:
   case VG_SCREEN_LAYOUT:
   case VG_FILTER_FORMAT_LINEAR:
   case VG_FILTER_FORMAT_PREMULTIPLIED:
   case VG_FILTER_CHANNEL_MASK:
      vgSeti(type, floor(values[0]));
      return;
      break;
   case VG_SCISSOR_RECTS: {
      VGint i;
      VGuint *x = (VGuint*)values;
      for (i = 0; i < count; ++i) {
         state->scissor_rects[i].f =  values[i];
         state->scissor_rects[i].i =  float_to_int_floor(x[i]);
      }
      state->scissor_rects_num = count / 4;
      ctx->state.dirty |= DEPTH_STENCIL_DIRTY;
   }
      break;
#ifdef OPENVG_VERSION_1_1
   case VG_COLOR_TRANSFORM_VALUES: {
      VGint i;
      for (i = 0; i < count; ++i) {
         state->color_transform_values[i] =  values[i];
      }
   }
      break;
#endif
   case VG_STROKE_LINE_WIDTH:
      state->stroke.line_width.f = values[0];
      state->stroke.line_width.i = float_to_int_floor(*((VGuint*)(values)));
      break;
   case VG_STROKE_MITER_LIMIT:
      state->stroke.miter_limit.f = values[0];
      state->stroke.miter_limit.i = float_to_int_floor(*((VGuint*)(values)));
      break;
   case VG_STROKE_DASH_PATTERN: {
      int i;
      for (i = 0; i < count; ++i) {
         state->stroke.dash_pattern[i].f = values[i];
         state->stroke.dash_pattern[i].i =
            float_to_int_floor(*((VGuint*)(values + i)));
      }
      state->stroke.dash_pattern_num = count;
   }
      break;
   case VG_STROKE_DASH_PHASE:
      state->stroke.dash_phase.f = values[0];
      state->stroke.dash_phase.i = float_to_int_floor(*((VGuint*)(values)));
      break;
   case VG_TILE_FILL_COLOR:
      state->tile_fill_color[0] = values[0];
      state->tile_fill_color[1] = values[1];
      state->tile_fill_color[2] = values[2];
      state->tile_fill_color[3] = values[3];

      state->tile_fill_colori[0] = float_to_int_floor(*((VGuint*)(values + 0)));
      state->tile_fill_colori[1] = float_to_int_floor(*((VGuint*)(values + 1)));
      state->tile_fill_colori[2] = float_to_int_floor(*((VGuint*)(values + 2)));
      state->tile_fill_colori[3] = float_to_int_floor(*((VGuint*)(values + 3)));
      break;
   case VG_CLEAR_COLOR:
      state->clear_color[0] = values[0];
      state->clear_color[1] = values[1];
      state->clear_color[2] = values[2];
      state->clear_color[3] = values[3];

      state->clear_colori[0] = float_to_int_floor(*((VGuint*)(values + 0)));
      state->clear_colori[1] = float_to_int_floor(*((VGuint*)(values + 1)));
      state->clear_colori[2] = float_to_int_floor(*((VGuint*)(values + 2)));
      state->clear_colori[3] = float_to_int_floor(*((VGuint*)(values + 3)));
      break;
#ifdef OPENVG_VERSION_1_1
   case VG_GLYPH_ORIGIN:
      state->glyph_origin[0].f = values[0];
      state->glyph_origin[1].f = values[1];

      state->glyph_origin[0].i = float_to_int_floor(*((VGuint*)(values + 0)));
      state->glyph_origin[1].i = float_to_int_floor(*((VGuint*)(values + 1)));
      break;
#endif

   case VG_MAX_SCISSOR_RECTS:
   case VG_MAX_DASH_COUNT:
   case VG_MAX_KERNEL_SIZE:
   case VG_MAX_SEPARABLE_KERNEL_SIZE:
   case VG_MAX_COLOR_RAMP_STOPS:
   case VG_MAX_IMAGE_WIDTH:
   case VG_MAX_IMAGE_HEIGHT:
   case VG_MAX_IMAGE_PIXELS:
   case VG_MAX_IMAGE_BYTES:
   case VG_MAX_GAUSSIAN_STD_DEVIATION:
   case VG_MAX_FLOAT:
      break;
   default:
      error = VG_ILLEGAL_ARGUMENT_ERROR;
      break;
   }
   vg_set_error(ctx, error);
}

void vgSetiv(VGParamType type, VGint count,
             const VGint * values)
{
   struct vg_context *ctx = vg_current_context();
   struct vg_state *state = current_state();

   if ((count && !values) || !count_in_bounds(type, count) || !is_aligned(values)) {
      vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
      return;
   }

   switch(type) {
   case VG_MATRIX_MODE:
   case VG_FILL_RULE:
   case VG_IMAGE_QUALITY:
   case VG_RENDERING_QUALITY:
   case VG_BLEND_MODE:
   case VG_IMAGE_MODE:
#ifdef OPENVG_VERSION_1_1
   case VG_COLOR_TRANSFORM:
#endif
   case VG_STROKE_CAP_STYLE:
   case VG_STROKE_JOIN_STYLE:
   case VG_STROKE_DASH_PHASE_RESET:
   case VG_MASKING:
   case VG_SCISSORING:
   case VG_PIXEL_LAYOUT:
   case VG_SCREEN_LAYOUT:
   case VG_FILTER_FORMAT_LINEAR:
   case VG_FILTER_FORMAT_PREMULTIPLIED:
   case VG_FILTER_CHANNEL_MASK:
      vgSeti(type, values[0]);
      return;
      break;
   case VG_SCISSOR_RECTS: {
      VGint i;
      for (i = 0; i < count; ++i) {
         state->scissor_rects[i].i =  values[i];
         state->scissor_rects[i].f =  values[i];
      }
      state->scissor_rects_num = count / 4;
      ctx->state.dirty |= DEPTH_STENCIL_DIRTY;
   }
      break;
#ifdef OPENVG_VERSION_1_1
   case VG_COLOR_TRANSFORM_VALUES: {
      VGint i;
      for (i = 0; i < count; ++i) {
         state->color_transform_values[i] =  values[i];
      }
   }
      break;
#endif
   case VG_STROKE_LINE_WIDTH:
      state->stroke.line_width.f = values[0];
      state->stroke.line_width.i = values[0];
      break;
   case VG_STROKE_MITER_LIMIT:
      state->stroke.miter_limit.f = values[0];
      state->stroke.miter_limit.i = values[0];
      break;
   case VG_STROKE_DASH_PATTERN: {
      int i;
      for (i = 0; i < count; ++i) {
         state->stroke.dash_pattern[i].f = values[i];
         state->stroke.dash_pattern[i].i = values[i];
      }
      state->stroke.dash_pattern_num = count;
   }
      break;
   case VG_STROKE_DASH_PHASE:
      state->stroke.dash_phase.f = values[0];
      state->stroke.dash_phase.i = values[0];
      break;
   case VG_TILE_FILL_COLOR:
      state->tile_fill_color[0] = values[0];
      state->tile_fill_color[1] = values[1];
      state->tile_fill_color[2] = values[2];
      state->tile_fill_color[3] = values[3];

      state->tile_fill_colori[0] = values[0];
      state->tile_fill_colori[1] = values[1];
      state->tile_fill_colori[2] = values[2];
      state->tile_fill_colori[3] = values[3];
      break;
   case VG_CLEAR_COLOR:
      state->clear_color[0] = values[0];
      state->clear_color[1] = values[1];
      state->clear_color[2] = values[2];
      state->clear_color[3] = values[3];

      state->clear_colori[0] = values[0];
      state->clear_colori[1] = values[1];
      state->clear_colori[2] = values[2];
      state->clear_colori[3] = values[3];
      break;
#ifdef OPENVG_VERSION_1_1
   case VG_GLYPH_ORIGIN:
      state->glyph_origin[0].f = values[0];
      state->glyph_origin[1].f = values[1];
      state->glyph_origin[0].i = values[0];
      state->glyph_origin[1].i = values[1];
      break;
#endif

   case VG_MAX_SCISSOR_RECTS:
   case VG_MAX_DASH_COUNT:
   case VG_MAX_KERNEL_SIZE:
   case VG_MAX_SEPARABLE_KERNEL_SIZE:
   case VG_MAX_COLOR_RAMP_STOPS:
   case VG_MAX_IMAGE_WIDTH:
   case VG_MAX_IMAGE_HEIGHT:
   case VG_MAX_IMAGE_PIXELS:
   case VG_MAX_IMAGE_BYTES:
   case VG_MAX_GAUSSIAN_STD_DEVIATION:
   case VG_MAX_FLOAT:
      break;

   default:
      vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
      break;
   }
}

VGfloat vgGetf(VGParamType type)
{
   struct vg_context *ctx = vg_current_context();
   const struct vg_state *state = current_state();
   VGErrorCode error = VG_NO_ERROR;
   VGfloat value = 0.0f;

   switch(type) {
   case VG_MATRIX_MODE:
   case VG_FILL_RULE:
   case VG_IMAGE_QUALITY:
   case VG_RENDERING_QUALITY:
   case VG_BLEND_MODE:
   case VG_IMAGE_MODE:
#ifdef OPENVG_VERSION_1_1
   case VG_COLOR_TRANSFORM:
#endif
   case VG_STROKE_CAP_STYLE:
   case VG_STROKE_JOIN_STYLE:
   case VG_STROKE_DASH_PHASE_RESET:
   case VG_MASKING:
   case VG_SCISSORING:
   case VG_PIXEL_LAYOUT:
   case VG_SCREEN_LAYOUT:
   case VG_FILTER_FORMAT_LINEAR:
   case VG_FILTER_FORMAT_PREMULTIPLIED:
   case VG_FILTER_CHANNEL_MASK:
      return vgGeti(type);
      break;
   case VG_STROKE_LINE_WIDTH:
      value = state->stroke.line_width.f;
      break;
   case VG_STROKE_MITER_LIMIT:
      value = state->stroke.miter_limit.f;
      break;
   case VG_STROKE_DASH_PHASE:
      value = state->stroke.dash_phase.f;
      break;

   case VG_MAX_SCISSOR_RECTS:
   case VG_MAX_DASH_COUNT:
   case VG_MAX_KERNEL_SIZE:
   case VG_MAX_SEPARABLE_KERNEL_SIZE:
   case VG_MAX_COLOR_RAMP_STOPS:
   case VG_MAX_IMAGE_WIDTH:
   case VG_MAX_IMAGE_HEIGHT:
   case VG_MAX_IMAGE_PIXELS:
   case VG_MAX_IMAGE_BYTES:
   case VG_MAX_GAUSSIAN_STD_DEVIATION:
      return vgGeti(type);
      break;
   case VG_MAX_FLOAT:
      value = 1e+10;/*must be at least 1e+10*/
      break;
   default:
      error = VG_ILLEGAL_ARGUMENT_ERROR;
      break;
   }
   vg_set_error(ctx, error);
   return value;
}

VGint vgGeti(VGParamType type)
{
   const struct vg_state *state = current_state();
   struct vg_context *ctx = vg_current_context();
   VGErrorCode error = VG_NO_ERROR;
   VGint value = 0;

   switch(type) {
   case VG_MATRIX_MODE:
      value = state->matrix_mode;
      break;
   case VG_FILL_RULE:
      value = state->fill_rule;
      break;
   case VG_IMAGE_QUALITY:
      value = state->image_quality;
      break;
   case VG_RENDERING_QUALITY:
      value = state->rendering_quality;
      break;
   case VG_BLEND_MODE:
      value = state->blend_mode;
      break;
   case VG_IMAGE_MODE:
      value = state->image_mode;
      break;
#ifdef OPENVG_VERSION_1_1
   case VG_COLOR_TRANSFORM:
      value = state->color_transform;
      break;
#endif
   case VG_STROKE_LINE_WIDTH:
      value = state->stroke.line_width.i;
      break;
   case VG_STROKE_CAP_STYLE:
      value = state->stroke.cap_style;
      break;
   case VG_STROKE_JOIN_STYLE:
      value = state->stroke.join_style;
      break;
   case VG_STROKE_MITER_LIMIT:
      value = state->stroke.miter_limit.i;
      break;
   case VG_STROKE_DASH_PHASE:
      value = state->stroke.dash_phase.i;
      break;
   case VG_STROKE_DASH_PHASE_RESET:
      value = state->stroke.dash_phase_reset;
      break;
   case VG_MASKING:
      value = state->masking;
      break;
   case VG_SCISSORING:
      value = state->scissoring;
      break;
   case VG_PIXEL_LAYOUT:
      value = state->pixel_layout;
      break;
   case VG_SCREEN_LAYOUT:
      value = state->screen_layout;
      break;
   case VG_FILTER_FORMAT_LINEAR:
      value = state->filter_format_linear;
      break;
   case VG_FILTER_FORMAT_PREMULTIPLIED:
      value = state->filter_format_premultiplied;
      break;
   case VG_FILTER_CHANNEL_MASK:
      value = state->filter_channel_mask;
      break;

   case VG_MAX_SCISSOR_RECTS:
      value = 32; /*must be at least 32*/
      break;
   case VG_MAX_DASH_COUNT:
      value = 16; /*must be at least 16*/
      break;
   case VG_MAX_KERNEL_SIZE:
      value = 7; /*must be at least 7*/
      break;
   case VG_MAX_SEPARABLE_KERNEL_SIZE:
      value = 15; /*must be at least 15*/
      break;
   case VG_MAX_COLOR_RAMP_STOPS:
      value = 256; /*must be at least 32*/
      break;
   case VG_MAX_IMAGE_WIDTH:
      value = 2048;
      break;
   case VG_MAX_IMAGE_HEIGHT:
      value = 2048;
      break;
   case VG_MAX_IMAGE_PIXELS:
      value = 2048*2048;
      break;
   case VG_MAX_IMAGE_BYTES:
      value = 2048*2048 * 4;
      break;
   case VG_MAX_GAUSSIAN_STD_DEVIATION:
      value = 128; /*must be at least 128*/
      break;

   case VG_MAX_FLOAT: {
      VGfloat val = vgGetf(type);
      value = float_to_int_floor(*((VGuint*)&val));
   }
      break;
   default:
      error = VG_ILLEGAL_ARGUMENT_ERROR;
      break;
   }
   vg_set_error(ctx, error);
   return value;
}

VGint vgGetVectorSize(VGParamType type)
{
   struct vg_context *ctx = vg_current_context();
   const struct vg_state *state = current_state();
   switch(type) {
   case VG_MATRIX_MODE:
   case VG_FILL_RULE:
   case VG_IMAGE_QUALITY:
   case VG_RENDERING_QUALITY:
   case VG_BLEND_MODE:
   case VG_IMAGE_MODE:
      return 1;
   case VG_SCISSOR_RECTS:
      return state->scissor_rects_num * 4;
#ifdef OPENVG_VERSION_1_1
   case VG_COLOR_TRANSFORM:
      return 1;
   case VG_COLOR_TRANSFORM_VALUES:
      return 8;
#endif
   case VG_STROKE_LINE_WIDTH:
   case VG_STROKE_CAP_STYLE:
   case VG_STROKE_JOIN_STYLE:
   case VG_STROKE_MITER_LIMIT:
      return 1;
   case VG_STROKE_DASH_PATTERN:
      return state->stroke.dash_pattern_num;
   case VG_STROKE_DASH_PHASE:
      return 1;
   case VG_STROKE_DASH_PHASE_RESET:
      return 1;
   case VG_TILE_FILL_COLOR:
      return 4;
   case VG_CLEAR_COLOR:
      return 4;
#ifdef OPENVG_VERSION_1_1
   case VG_GLYPH_ORIGIN:
      return 2;
#endif
   case VG_MASKING:
      return 1;
   case VG_SCISSORING:
      return 1;
   case VG_PIXEL_LAYOUT:
      return 1;
   case VG_SCREEN_LAYOUT:
      return 1;
   case VG_FILTER_FORMAT_LINEAR:
      return 1;
   case VG_FILTER_FORMAT_PREMULTIPLIED:
      return 1;
   case VG_FILTER_CHANNEL_MASK:
      return 1;

   case VG_MAX_COLOR_RAMP_STOPS:
      return 1;
   case VG_MAX_SCISSOR_RECTS:
   case VG_MAX_DASH_COUNT:
   case VG_MAX_KERNEL_SIZE:
   case VG_MAX_SEPARABLE_KERNEL_SIZE:
   case VG_MAX_IMAGE_WIDTH:
   case VG_MAX_IMAGE_HEIGHT:
   case VG_MAX_IMAGE_PIXELS:
   case VG_MAX_IMAGE_BYTES:
   case VG_MAX_FLOAT:
   case VG_MAX_GAUSSIAN_STD_DEVIATION:
      return 1;
   default:
      if (ctx)
         vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
      return 0;
   }
}

void vgGetfv(VGParamType type, VGint count,
             VGfloat * values)
{
   const struct vg_state *state = current_state();
   struct vg_context *ctx = vg_current_context();
   VGint real_count = vgGetVectorSize(type);

   if (!values || count <= 0 || count > real_count || !is_aligned(values)) {
      vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
      return;
   }

   switch(type) {
   case VG_MATRIX_MODE:
   case VG_FILL_RULE:
   case VG_IMAGE_QUALITY:
   case VG_RENDERING_QUALITY:
   case VG_BLEND_MODE:
   case VG_IMAGE_MODE:
#ifdef OPENVG_VERSION_1_1
   case VG_COLOR_TRANSFORM:
#endif
   case VG_STROKE_CAP_STYLE:
   case VG_STROKE_JOIN_STYLE:
   case VG_STROKE_DASH_PHASE_RESET:
   case VG_MASKING:
   case VG_SCISSORING:
   case VG_PIXEL_LAYOUT:
   case VG_SCREEN_LAYOUT:
   case VG_FILTER_FORMAT_LINEAR:
   case VG_FILTER_FORMAT_PREMULTIPLIED:
   case VG_FILTER_CHANNEL_MASK:
   case VG_MAX_SCISSOR_RECTS:
   case VG_MAX_DASH_COUNT:
   case VG_MAX_KERNEL_SIZE:
   case VG_MAX_SEPARABLE_KERNEL_SIZE:
   case VG_MAX_COLOR_RAMP_STOPS:
   case VG_MAX_IMAGE_WIDTH:
   case VG_MAX_IMAGE_HEIGHT:
   case VG_MAX_IMAGE_PIXELS:
   case VG_MAX_IMAGE_BYTES:
   case VG_MAX_GAUSSIAN_STD_DEVIATION:
      values[0] = vgGeti(type);
      break;
   case VG_MAX_FLOAT:
      values[0] = vgGetf(type);
      break;
   case VG_SCISSOR_RECTS: {
      VGint i;
      for (i = 0; i < count; ++i) {
         values[i] = state->scissor_rects[i].f;
      }
   }
      break;
#ifdef OPENVG_VERSION_1_1
   case VG_COLOR_TRANSFORM_VALUES: {
      memcpy(values, state->color_transform_values,
             sizeof(VGfloat) * count);
   }
      break;
#endif
   case VG_STROKE_LINE_WIDTH:
      values[0] = state->stroke.line_width.f;
      break;
   case VG_STROKE_MITER_LIMIT:
      values[0] = state->stroke.miter_limit.f;
      break;
   case VG_STROKE_DASH_PATTERN: {
      VGint i;
      for (i = 0; i < count; ++i) {
         values[i] = state->stroke.dash_pattern[i].f;
      }
   }
      break;
   case VG_STROKE_DASH_PHASE:
      values[0] = state->stroke.dash_phase.f;
      break;
   case VG_TILE_FILL_COLOR:
      values[0] = state->tile_fill_color[0];
      values[1] = state->tile_fill_color[1];
      values[2] = state->tile_fill_color[2];
      values[3] = state->tile_fill_color[3];
      break;
   case VG_CLEAR_COLOR:
      values[0] = state->clear_color[0];
      values[1] = state->clear_color[1];
      values[2] = state->clear_color[2];
      values[3] = state->clear_color[3];
      break;
#ifdef OPENVG_VERSION_1_1
   case VG_GLYPH_ORIGIN:
      values[0] = state->glyph_origin[0].f;
      values[1] = state->glyph_origin[1].f;
      break;
#endif
   default:
      vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
      break;
   }
}

void vgGetiv(VGParamType type, VGint count,
             VGint * values)
{
   const struct vg_state *state = current_state();
   struct vg_context *ctx = vg_current_context();
   VGint real_count = vgGetVectorSize(type);

   if (!values || count <= 0 || count > real_count || !is_aligned(values)) {
      vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
      return;
   }

   switch(type) {
   case VG_MATRIX_MODE:
   case VG_FILL_RULE:
   case VG_IMAGE_QUALITY:
   case VG_RENDERING_QUALITY:
   case VG_BLEND_MODE:
   case VG_IMAGE_MODE:
#ifdef OPENVG_VERSION_1_1
   case VG_COLOR_TRANSFORM:
#endif
   case VG_STROKE_CAP_STYLE:
   case VG_STROKE_JOIN_STYLE:
   case VG_STROKE_DASH_PHASE_RESET:
   case VG_MASKING:
   case VG_SCISSORING:
   case VG_PIXEL_LAYOUT:
   case VG_SCREEN_LAYOUT:
   case VG_FILTER_FORMAT_LINEAR:
   case VG_FILTER_FORMAT_PREMULTIPLIED:
   case VG_FILTER_CHANNEL_MASK:
   case VG_MAX_SCISSOR_RECTS:
   case VG_MAX_DASH_COUNT:
   case VG_MAX_KERNEL_SIZE:
   case VG_MAX_SEPARABLE_KERNEL_SIZE:
   case VG_MAX_COLOR_RAMP_STOPS:
   case VG_MAX_IMAGE_WIDTH:
   case VG_MAX_IMAGE_HEIGHT:
   case VG_MAX_IMAGE_PIXELS:
   case VG_MAX_IMAGE_BYTES:
   case VG_MAX_GAUSSIAN_STD_DEVIATION:
      values[0] = vgGeti(type);
      break;
   case VG_MAX_FLOAT: {
      VGfloat val = vgGetf(type);
      values[0] = float_to_int_floor(*((VGuint*)&val));
   }
      break;
   case VG_SCISSOR_RECTS: {
      VGint i;
      for (i = 0; i < count; ++i) {
         values[i] = state->scissor_rects[i].i;
      }
   }
      break;
#ifdef OPENVG_VERSION_1_1
   case VG_COLOR_TRANSFORM_VALUES: {
      VGint i;
      VGuint *x = (VGuint*)state->color_transform_values;
      for (i = 0; i < count; ++i) {
         values[i] = float_to_int_floor(x[i]);
      }
   }
      break;
#endif
   case VG_STROKE_LINE_WIDTH:
      values[0] = state->stroke.line_width.i;
      break;
   case VG_STROKE_MITER_LIMIT:
      values[0] = state->stroke.miter_limit.i;
      break;
   case VG_STROKE_DASH_PATTERN: {
      VGint i;
      for (i = 0; i < count; ++i) {
         values[i] = state->stroke.dash_pattern[i].i;
      }
   }
      break;
   case VG_STROKE_DASH_PHASE:
      values[0] = state->stroke.dash_phase.i;
      break;
   case VG_TILE_FILL_COLOR:
      values[0] = state->tile_fill_colori[0];
      values[1] = state->tile_fill_colori[1];
      values[2] = state->tile_fill_colori[2];
      values[3] = state->tile_fill_colori[3];
      break;
   case VG_CLEAR_COLOR:
      values[0] = state->clear_colori[0];
      values[1] = state->clear_colori[1];
      values[2] = state->clear_colori[2];
      values[3] = state->clear_colori[3];
      break;
#ifdef OPENVG_VERSION_1_1
   case VG_GLYPH_ORIGIN:
      values[0] = state->glyph_origin[0].i;
      values[1] = state->glyph_origin[1].i;
      break;
#endif
   default:
      vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
      break;
   }
}

void vgSetParameterf(VGHandle object,
                     VGint paramType,
                     VGfloat value)
{
   struct vg_context *ctx = vg_current_context();
   void *ptr = (void*)object;

   if (!object || object == VG_INVALID_HANDLE || !is_aligned(ptr)) {
      vg_set_error(ctx, VG_BAD_HANDLE_ERROR);
      return;
   }

   switch(paramType) {
   case VG_PAINT_TYPE:
   case VG_PAINT_COLOR_RAMP_SPREAD_MODE:
   case VG_PAINT_PATTERN_TILING_MODE:
      vgSetParameteri(object, paramType, floor(value));
      return;
      break;
   case VG_PAINT_COLOR:
   case VG_PAINT_COLOR_RAMP_STOPS:
   case VG_PAINT_LINEAR_GRADIENT:
   case VG_PAINT_RADIAL_GRADIENT:
      /* it's an error if paramType refers to a vector parameter */
      vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
      break;
   case VG_PAINT_COLOR_RAMP_PREMULTIPLIED: {
      struct vg_paint *p = (struct vg_paint *)object;
      paint_set_color_ramp_premultiplied(p, value);
   }
      break;

   case VG_PATH_DATATYPE:
   case VG_PATH_FORMAT:
   case VG_PATH_SCALE:
   case VG_PATH_BIAS:
   case VG_PATH_NUM_SEGMENTS:
   case VG_PATH_NUM_COORDS:

   case VG_IMAGE_FORMAT:
   case VG_IMAGE_WIDTH:
   case VG_IMAGE_HEIGHT:

#ifdef OPENVG_VERSION_1_1
   case VG_FONT_NUM_GLYPHS:
      /* read only don't produce an error */
      break;
#endif
   default:
      vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
      break;
   }
}

void vgSetParameteri(VGHandle object,
                     VGint paramType,
                     VGint value)
{
   struct vg_context *ctx = vg_current_context();
   void *ptr = (void*)object;

   if (!object || object == VG_INVALID_HANDLE || !is_aligned(ptr)) {
      vg_set_error(ctx, VG_BAD_HANDLE_ERROR);
      return;
   }

   switch(paramType) {
   case VG_PAINT_TYPE:
      if (value < VG_PAINT_TYPE_COLOR ||
          value > VG_PAINT_TYPE_PATTERN)
         vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
      else {
         struct vg_paint *paint = (struct vg_paint *)ptr;
         paint_set_type(paint, value);
      }
      break;
   case VG_PAINT_COLOR:
   case VG_PAINT_COLOR_RAMP_STOPS:
   case VG_PAINT_LINEAR_GRADIENT:
   case VG_PAINT_RADIAL_GRADIENT:
      /* it's an error if paramType refers to a vector parameter */
      vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
      break;
   case VG_PAINT_COLOR_RAMP_SPREAD_MODE:
      if (value < VG_COLOR_RAMP_SPREAD_PAD ||
          value > VG_COLOR_RAMP_SPREAD_REFLECT)
         vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
      else {
         struct vg_paint *paint = (struct vg_paint *)ptr;
         paint_set_spread_mode(paint, value);
      }
      break;
   case VG_PAINT_COLOR_RAMP_PREMULTIPLIED: {
      struct vg_paint *p = (struct vg_paint *)object;
      paint_set_color_ramp_premultiplied(p, value);
   }
      break;
   case VG_PAINT_PATTERN_TILING_MODE:
      if (value < VG_TILE_FILL ||
          value > VG_TILE_REFLECT)
         vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
      else {
         struct vg_paint *paint = (struct vg_paint *)ptr;
         paint_set_pattern_tiling(paint, value);
      }
      break;

   case VG_PATH_DATATYPE:
   case VG_PATH_FORMAT:
   case VG_PATH_SCALE:
   case VG_PATH_BIAS:
   case VG_PATH_NUM_SEGMENTS:
   case VG_PATH_NUM_COORDS:

   case VG_IMAGE_FORMAT:
   case VG_IMAGE_WIDTH:
   case VG_IMAGE_HEIGHT:

#ifdef OPENVG_VERSION_1_1
   case VG_FONT_NUM_GLYPHS:
      /* read only don't produce an error */
      break;
#endif
   default:
      vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
      return;
   }
}

void vgSetParameterfv(VGHandle object,
                      VGint paramType,
                      VGint count,
                      const VGfloat * values)
{
   struct vg_context *ctx = vg_current_context();
   void *ptr = (void*)object;
   VGint real_count = vgGetParameterVectorSize(object, paramType);

   if (!object || object == VG_INVALID_HANDLE || !is_aligned(ptr)) {
      vg_set_error(ctx, VG_BAD_HANDLE_ERROR);
      return;
   }

   if (count < 0 || count < real_count ||
       (values == NULL && count != 0) ||
       !is_aligned(values)) {
      vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
      return;
   }

   switch(paramType) {
   case VG_PAINT_TYPE:
   case VG_PAINT_COLOR_RAMP_SPREAD_MODE:
   case VG_PAINT_COLOR_RAMP_PREMULTIPLIED:
   case VG_PAINT_PATTERN_TILING_MODE:
      if (count != 1)
         vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
      else
         vgSetParameterf(object, paramType, values[0]);
      return;
      break;
   case VG_PAINT_COLOR: {
      if (count != 4)
         vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
      else {
         struct vg_paint *paint = (struct vg_paint *)object;
         paint_set_color(paint, values);
      }
   }
      break;
   case VG_PAINT_COLOR_RAMP_STOPS: {
      if (count && count < 4)
         vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
      else {
         struct vg_paint *paint = (struct vg_paint *)object;
         count = MIN2(count, VEGA_MAX_COLOR_RAMP_STOPS);
         paint_set_ramp_stops(paint, values, count);
         {
            VGint stopsi[VEGA_MAX_COLOR_RAMP_STOPS];
            int i = 0;
            for (i = 0; i < count; ++i) {
               stopsi[i] = float_to_int_floor(*((VGuint*)(values + i)));
            }
            paint_set_ramp_stopsi(paint, stopsi, count);
         }
      }
   }
      break;
   case VG_PAINT_LINEAR_GRADIENT: {
      if (count != 4)
         vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
      else {
         struct vg_paint *paint = (struct vg_paint *)object;
         paint_set_linear_gradient(paint, values);
         {
            VGint vals[4];
            vals[0] = FLT_TO_INT(values[0]);
            vals[1] = FLT_TO_INT(values[1]);
            vals[2] = FLT_TO_INT(values[2]);
            vals[3] = FLT_TO_INT(values[3]);
            paint_set_linear_gradienti(paint, vals);
         }
      }
   }
      break;
   case VG_PAINT_RADIAL_GRADIENT: {
      if (count != 5)
         vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
      else {
         struct vg_paint *paint = (struct vg_paint *)object;
         paint_set_radial_gradient(paint, values);
         {
            VGint vals[5];
            vals[0] = FLT_TO_INT(values[0]);
            vals[1] = FLT_TO_INT(values[1]);
            vals[2] = FLT_TO_INT(values[2]);
            vals[3] = FLT_TO_INT(values[3]);
            vals[4] = FLT_TO_INT(values[4]);
            paint_set_radial_gradienti(paint, vals);
         }
      }
   }
      break;

   case VG_PATH_DATATYPE:
   case VG_PATH_FORMAT:
   case VG_PATH_SCALE:
   case VG_PATH_BIAS:
   case VG_PATH_NUM_SEGMENTS:
   case VG_PATH_NUM_COORDS:

#ifdef OPENVG_VERSION_1_1
   case VG_FONT_NUM_GLYPHS:
      /* read only don't produce an error */
      break;
#endif
   default:
      vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
      return;
   }
}

void vgSetParameteriv(VGHandle object,
                      VGint paramType,
                      VGint count,
                      const VGint * values)
{
   struct vg_context *ctx = vg_current_context();
   void *ptr = (void*)object;
   VGint real_count = vgGetParameterVectorSize(object, paramType);

   if (!object || object == VG_INVALID_HANDLE || !is_aligned(ptr)) {
      vg_set_error(ctx, VG_BAD_HANDLE_ERROR);
      return;
   }

   if (count < 0 || count < real_count ||
       (values == NULL && count != 0) ||
       !is_aligned(values)) {
      vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
      return;
   }

   switch(paramType) {
   case VG_PAINT_TYPE:
   case VG_PAINT_COLOR_RAMP_SPREAD_MODE:
   case VG_PAINT_COLOR_RAMP_PREMULTIPLIED:
   case VG_PAINT_PATTERN_TILING_MODE:
      if (count != 1)
         vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
      else
         vgSetParameteri(object, paramType, values[0]);
      return;
      break;
   case VG_PAINT_COLOR: {
      if (count != 4)
         vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
      else {
         struct vg_paint *paint = (struct vg_paint *)object;
         paint_set_coloriv(paint, values);
      }
   }
      break;
   case VG_PAINT_COLOR_RAMP_STOPS: {
      if ((count % 5))
         vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
      else {
         VGfloat *vals = 0;
         int i;
         struct vg_paint *paint = (struct vg_paint *)object;
         if (count) {
            vals = malloc(sizeof(VGfloat)*count);
            for (i = 0; i < count; ++i)
               vals[i] = values[i];
         }

         paint_set_ramp_stopsi(paint, values, count);
         paint_set_ramp_stops(paint, vals, count);
         free(vals);
      }
   }
      break;
   case VG_PAINT_LINEAR_GRADIENT: {
      if (count != 4)
         vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
      else {
         VGfloat vals[4];
         struct vg_paint *paint = (struct vg_paint *)object;
         vals[0] = values[0];
         vals[1] = values[1];
         vals[2] = values[2];
         vals[3] = values[3];
         paint_set_linear_gradient(paint, vals);
         paint_set_linear_gradienti(paint, values);
      }
   }
      break;
   case VG_PAINT_RADIAL_GRADIENT: {
      if (count != 5)
         vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
      else {
         VGfloat vals[5];
         struct vg_paint *paint = (struct vg_paint *)object;
         vals[0] = values[0];
         vals[1] = values[1];
         vals[2] = values[2];
         vals[3] = values[3];
         vals[4] = values[4];
         paint_set_radial_gradient(paint, vals);
         paint_set_radial_gradienti(paint, values);
      }
   }
      break;
   case VG_PATH_DATATYPE:
   case VG_PATH_FORMAT:
   case VG_PATH_SCALE:
   case VG_PATH_BIAS:
   case VG_PATH_NUM_SEGMENTS:
   case VG_PATH_NUM_COORDS:
      /* read only don't produce an error */
      break;
   default:
      vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
      return;
   }
}

VGint vgGetParameterVectorSize(VGHandle object,
                               VGint paramType)
{
   struct vg_context *ctx = vg_current_context();
   void *ptr = (void*)object;

   if (!ptr || object == VG_INVALID_HANDLE) {
      vg_set_error(ctx, VG_BAD_HANDLE_ERROR);
      return 0;
   }

   switch(paramType) {
   case VG_PAINT_TYPE:
   case VG_PAINT_COLOR_RAMP_SPREAD_MODE:
   case VG_PAINT_COLOR_RAMP_PREMULTIPLIED:
   case VG_PAINT_PATTERN_TILING_MODE:
      return 1;
   case VG_PAINT_COLOR:
      return 4;
   case VG_PAINT_COLOR_RAMP_STOPS: {
      struct vg_paint *p = (struct vg_paint *)object;
      return paint_num_ramp_stops(p);
   }
      break;
   case VG_PAINT_LINEAR_GRADIENT:
      return 4;
   case VG_PAINT_RADIAL_GRADIENT:
      return 5;


   case VG_PATH_FORMAT:
   case VG_PATH_DATATYPE:
   case VG_PATH_SCALE:
   case VG_PATH_BIAS:
   case VG_PATH_NUM_SEGMENTS:
   case VG_PATH_NUM_COORDS:
      return 1;

   case VG_IMAGE_FORMAT:
   case VG_IMAGE_WIDTH:
   case VG_IMAGE_HEIGHT:
      return 1;

#ifdef OPENVG_VERSION_1_1
   case VG_FONT_NUM_GLYPHS:
      return 1;
#endif

   default:
      vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
      break;
   }
   return 0;
}


VGfloat vgGetParameterf(VGHandle object,
                        VGint paramType)
{
   struct vg_context *ctx = vg_current_context();
   void *ptr = (void*)object;

   if (!ptr || object == VG_INVALID_HANDLE) {
      vg_set_error(ctx, VG_BAD_HANDLE_ERROR);
      return 0;
   }

   switch(paramType) {
   case VG_PAINT_TYPE:
   case VG_PAINT_COLOR_RAMP_SPREAD_MODE:
   case VG_PAINT_COLOR_RAMP_PREMULTIPLIED:
   case VG_PAINT_PATTERN_TILING_MODE:
      return vgGetParameteri(object, paramType);
      break;
   case VG_PAINT_COLOR:
   case VG_PAINT_COLOR_RAMP_STOPS:
   case VG_PAINT_LINEAR_GRADIENT:
   case VG_PAINT_RADIAL_GRADIENT:
      vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
      break;

   case VG_PATH_FORMAT:
      return VG_PATH_FORMAT_STANDARD;
   case VG_PATH_SCALE: {
      struct path *p = (struct path*)object;
      return path_scale(p);
   }
   case VG_PATH_BIAS: {
      struct path *p = (struct path*)object;
      return path_bias(p);
   }
   case VG_PATH_DATATYPE:
   case VG_PATH_NUM_SEGMENTS:
   case VG_PATH_NUM_COORDS:
      return vgGetParameteri(object, paramType);
      break;

   case VG_IMAGE_FORMAT:
   case VG_IMAGE_WIDTH:
   case VG_IMAGE_HEIGHT:
#ifdef OPENVG_VERSION_1_1
   case VG_FONT_NUM_GLYPHS: 
      return vgGetParameteri(object, paramType);
      break;
#endif

   default:
      vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
      break;
   }
   return 0;
}

VGint vgGetParameteri(VGHandle object,
                      VGint paramType)
{
   struct vg_context *ctx = vg_current_context();
   void *ptr = (void*)object;

   if (!ptr || object == VG_INVALID_HANDLE) {
      vg_set_error(ctx, VG_BAD_HANDLE_ERROR);
      return 0;
   }

   switch(paramType) {
   case VG_PAINT_TYPE: {
         struct vg_paint *paint = (struct vg_paint *)ptr;
         return paint_type(paint);
   }
      break;
   case VG_PAINT_COLOR_RAMP_SPREAD_MODE: {
      struct vg_paint *p = (struct vg_paint *)object;
      return paint_spread_mode(p);
   }
   case VG_PAINT_COLOR_RAMP_PREMULTIPLIED: {
      struct vg_paint *p = (struct vg_paint *)object;
      return paint_color_ramp_premultiplied(p);
   }
      break;
   case VG_PAINT_PATTERN_TILING_MODE: {
      struct vg_paint *p = (struct vg_paint *)object;
      return paint_pattern_tiling(p);
   }
      break;
   case VG_PAINT_COLOR:
   case VG_PAINT_COLOR_RAMP_STOPS:
   case VG_PAINT_LINEAR_GRADIENT:
   case VG_PAINT_RADIAL_GRADIENT:
      vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
      break;

   case VG_PATH_FORMAT:
      return VG_PATH_FORMAT_STANDARD;
   case VG_PATH_SCALE:
   case VG_PATH_BIAS:
      return vgGetParameterf(object, paramType);
   case VG_PATH_DATATYPE: {
      struct path *p = (struct path*)object;
      return path_datatype(p);
   }
   case VG_PATH_NUM_SEGMENTS: {
      struct path *p = (struct path*)object;
      return path_num_segments(p);
   }
   case VG_PATH_NUM_COORDS: {
      struct path *p = (struct path*)object;
      return path_num_coords(p);
   }
      break;

   case VG_IMAGE_FORMAT: {
      struct vg_image *img = (struct vg_image*)object;
      return img->format;
   }
      break;
   case VG_IMAGE_WIDTH: {
      struct vg_image *img = (struct vg_image*)object;
      return img->width;
   }
      break;
   case VG_IMAGE_HEIGHT: {
      struct vg_image *img = (struct vg_image*)object;
      return img->height;
   }
      break;

#ifdef OPENVG_VERSION_1_1
   case VG_FONT_NUM_GLYPHS: {
      return 1;
   }
      break;
#endif

   default:
      vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
      break;
   }
   return 0;
}

void vgGetParameterfv(VGHandle object,
                      VGint paramType,
                      VGint count,
                      VGfloat * values)
{
   struct vg_context *ctx = vg_current_context();
   void *ptr = (void*)object;
   VGint real_count = vgGetParameterVectorSize(object, paramType);

   if (!ptr || object == VG_INVALID_HANDLE) {
      vg_set_error(ctx, VG_BAD_HANDLE_ERROR);
      return;
   }

   if (!values || count <= 0 || count > real_count ||
       !is_aligned(values)) {
      vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
      return;
   }

   switch(paramType) {
   case VG_PAINT_TYPE: {
      struct vg_paint *p = (struct vg_paint *)object;
      values[0] = paint_type(p);
   }
      break;
   case VG_PAINT_COLOR_RAMP_SPREAD_MODE: {
      struct vg_paint *p = (struct vg_paint *)object;
      values[0] = paint_spread_mode(p);
   }
      break;
   case VG_PAINT_COLOR_RAMP_PREMULTIPLIED: {
      struct vg_paint *p = (struct vg_paint *)object;
      values[0] = paint_color_ramp_premultiplied(p);
   }
      break;
   case VG_PAINT_PATTERN_TILING_MODE: {
      values[0] = vgGetParameterf(object, paramType);
   }
      break;
   case VG_PAINT_COLOR: {
      struct vg_paint *paint = (struct vg_paint *)object;
      paint_get_color(paint, values);
   }
      break;
   case VG_PAINT_COLOR_RAMP_STOPS: {
      struct vg_paint *paint = (struct vg_paint *)object;
      paint_ramp_stops(paint, values, count);
   }
      break;
   case VG_PAINT_LINEAR_GRADIENT: {
      struct vg_paint *paint = (struct vg_paint *)object;
      paint_linear_gradient(paint, values);
   }
      break;
   case VG_PAINT_RADIAL_GRADIENT: {
      struct vg_paint *paint = (struct vg_paint *)object;
      paint_radial_gradient(paint, values);
   }
      break;

   case VG_PATH_FORMAT:
   case VG_PATH_DATATYPE:
   case VG_PATH_NUM_SEGMENTS:
   case VG_PATH_NUM_COORDS:
      values[0] = vgGetParameteri(object, paramType);
      break;
   case VG_PATH_SCALE:
   case VG_PATH_BIAS:
      values[0] = vgGetParameterf(object, paramType);
      break;

   case VG_IMAGE_FORMAT:
   case VG_IMAGE_WIDTH:
   case VG_IMAGE_HEIGHT:
#ifdef OPENVG_VERSION_1_1
   case VG_FONT_NUM_GLYPHS:
      values[0] = vgGetParameteri(object, paramType);
      break;
#endif

   default:
      vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
      break;
   }
}

void vgGetParameteriv(VGHandle object,
                      VGint paramType,
                      VGint count,
                      VGint * values)
{
   struct vg_context *ctx = vg_current_context();
   void *ptr = (void*)object;
   VGint real_count = vgGetParameterVectorSize(object, paramType);

   if (!ptr || object == VG_INVALID_HANDLE) {
      vg_set_error(ctx, VG_BAD_HANDLE_ERROR);
      return;
   }

   if (!values || count <= 0 || count > real_count ||
       !is_aligned(values)) {
      vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
      return;
   }

   switch(paramType) {
   case VG_PAINT_TYPE:
   case VG_PAINT_COLOR_RAMP_SPREAD_MODE:
   case VG_PAINT_COLOR_RAMP_PREMULTIPLIED:
   case VG_PAINT_PATTERN_TILING_MODE:
#ifdef OPENVG_VERSION_1_1
   case VG_FONT_NUM_GLYPHS:
      values[0] = vgGetParameteri(object, paramType);
      break;
#endif
   case VG_PAINT_COLOR: {
      struct vg_paint *paint = (struct vg_paint *)object;
      paint_get_coloriv(paint, values);
   }
      break;
   case VG_PAINT_COLOR_RAMP_STOPS: {
      struct vg_paint *paint = (struct vg_paint *)object;
      paint_ramp_stopsi(paint, values, count);
   }
      break;
   case VG_PAINT_LINEAR_GRADIENT: {
      struct vg_paint *paint = (struct vg_paint *)object;
      paint_linear_gradienti(paint, values);
   }
      break;
   case VG_PAINT_RADIAL_GRADIENT: {
      struct vg_paint *paint = (struct vg_paint *)object;
      paint_radial_gradienti(paint, values);
   }
      break;

   case VG_PATH_SCALE:
   case VG_PATH_BIAS:
      values[0] = vgGetParameterf(object, paramType);
      break;
   case VG_PATH_FORMAT:
   case VG_PATH_DATATYPE:
   case VG_PATH_NUM_SEGMENTS:
   case VG_PATH_NUM_COORDS:
      values[0] = vgGetParameteri(object, paramType);
      break;

   case VG_IMAGE_FORMAT:
   case VG_IMAGE_WIDTH:
   case VG_IMAGE_HEIGHT:
      values[0] = vgGetParameteri(object, paramType);
      break;

   default:
      vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
      break;
   }
}
