Home | History | Annotate | Download | only in vega
      1 /**************************************************************************
      2  *
      3  * Copyright 2009 VMware, Inc.  All Rights Reserved.
      4  *
      5  * Permission is hereby granted, free of charge, to any person obtaining a
      6  * copy of this software and associated documentation files (the
      7  * "Software"), to deal in the Software without restriction, including
      8  * without limitation the rights to use, copy, modify, merge, publish,
      9  * distribute, sub license, and/or sell copies of the Software, and to
     10  * permit persons to whom the Software is furnished to do so, subject to
     11  * the following conditions:
     12  *
     13  * The above copyright notice and this permission notice (including the
     14  * next paragraph) shall be included in all copies or substantial portions
     15  * of the Software.
     16  *
     17  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
     18  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
     19  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
     20  * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR
     21  * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
     22  * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
     23  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
     24  *
     25  **************************************************************************/
     26 
     27 #include "VG/openvg.h"
     28 
     29 #include "vg_context.h"
     30 #include "handle.h"
     31 #include "path.h"
     32 #include "api.h"
     33 
     34 #include "pipe/p_context.h"
     35 
     36 VGPath vegaCreatePath(VGint pathFormat,
     37                       VGPathDatatype datatype,
     38                       VGfloat scale, VGfloat bias,
     39                       VGint segmentCapacityHint,
     40                       VGint coordCapacityHint,
     41                       VGbitfield capabilities)
     42 {
     43    struct vg_context *ctx = vg_current_context();
     44 
     45    if (pathFormat != VG_PATH_FORMAT_STANDARD) {
     46       vg_set_error(ctx, VG_UNSUPPORTED_PATH_FORMAT_ERROR);
     47       return VG_INVALID_HANDLE;
     48    }
     49    if (datatype < VG_PATH_DATATYPE_S_8 ||
     50        datatype > VG_PATH_DATATYPE_F) {
     51       vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
     52       return VG_INVALID_HANDLE;
     53    }
     54    if (!scale) {
     55       vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
     56       return VG_INVALID_HANDLE;
     57    }
     58 
     59    return path_to_handle(path_create(datatype, scale, bias,
     60                                      segmentCapacityHint, coordCapacityHint,
     61                                      capabilities));
     62 }
     63 
     64 void vegaClearPath(VGPath path, VGbitfield capabilities)
     65 {
     66    struct vg_context *ctx = vg_current_context();
     67    struct path *p = 0;
     68 
     69    if (path == VG_INVALID_HANDLE) {
     70       vg_set_error(ctx, VG_BAD_HANDLE_ERROR);
     71       return;
     72    }
     73 
     74    p = handle_to_path(path);
     75    path_clear(p, capabilities);
     76 }
     77 
     78 void vegaDestroyPath(VGPath p)
     79 {
     80    struct path *path = 0;
     81    struct vg_context *ctx = vg_current_context();
     82 
     83    if (p == VG_INVALID_HANDLE) {
     84       vg_set_error(ctx, VG_BAD_HANDLE_ERROR);
     85       return;
     86    }
     87 
     88    path = handle_to_path(p);
     89    path_destroy(path);
     90 }
     91 
     92 void vegaRemovePathCapabilities(VGPath path,
     93                                 VGbitfield capabilities)
     94 {
     95    struct vg_context *ctx = vg_current_context();
     96    VGbitfield current;
     97    struct path *p;
     98 
     99    if (path == VG_INVALID_HANDLE) {
    100       vg_set_error(ctx, VG_BAD_HANDLE_ERROR);
    101       return;
    102    }
    103 
    104    p = handle_to_path(path);
    105    current = path_capabilities(p);
    106    path_set_capabilities(p, (current &
    107                              (~(capabilities & VG_PATH_CAPABILITY_ALL))));
    108 }
    109 
    110 VGbitfield vegaGetPathCapabilities(VGPath path)
    111 {
    112    struct vg_context *ctx = vg_current_context();
    113    struct path *p = 0;
    114 
    115    if (path == VG_INVALID_HANDLE) {
    116       vg_set_error(ctx, VG_BAD_HANDLE_ERROR);
    117       return 0;
    118    }
    119    p = handle_to_path(path);
    120    return path_capabilities(p);
    121 }
    122 
    123 void vegaAppendPath(VGPath dstPath, VGPath srcPath)
    124 {
    125    struct vg_context *ctx = vg_current_context();
    126    struct path *src, *dst;
    127 
    128    if (dstPath == VG_INVALID_HANDLE || srcPath == VG_INVALID_HANDLE) {
    129       vg_set_error(ctx, VG_BAD_HANDLE_ERROR);
    130       return;
    131    }
    132    src = handle_to_path(srcPath);
    133    dst = handle_to_path(dstPath);
    134 
    135    if (!(path_capabilities(src) & VG_PATH_CAPABILITY_APPEND_FROM) ||
    136        !(path_capabilities(dst) & VG_PATH_CAPABILITY_APPEND_TO)) {
    137       vg_set_error(ctx, VG_PATH_CAPABILITY_ERROR);
    138       return;
    139    }
    140    path_append_path(dst, src);
    141 }
    142 
    143 void vegaAppendPathData(VGPath dstPath,
    144                         VGint numSegments,
    145                         const VGubyte * pathSegments,
    146                         const void * pathData)
    147 {
    148    struct vg_context *ctx = vg_current_context();
    149    struct path *p = 0;
    150    VGint i;
    151 
    152    if (dstPath == VG_INVALID_HANDLE) {
    153       vg_set_error(ctx, VG_BAD_HANDLE_ERROR);
    154       return;
    155    }
    156    if (!pathSegments) {
    157       vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
    158       return;
    159    }
    160    if (numSegments <= 0) {
    161       vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
    162       return;
    163    }
    164    for (i = 0; i < numSegments; ++i) {
    165       if (pathSegments[i] > VG_LCWARC_TO_REL) {
    166          vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
    167          return;
    168       }
    169    }
    170 
    171    p = handle_to_path(dstPath);
    172 
    173    if (!p || !is_aligned_to(p, path_datatype_size(p))) {
    174       vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
    175       return;
    176    }
    177 
    178    if (!(path_capabilities(p)&VG_PATH_CAPABILITY_APPEND_TO)) {
    179       vg_set_error(ctx, VG_PATH_CAPABILITY_ERROR);
    180       return;
    181    }
    182 
    183    path_append_data(p, numSegments, pathSegments, pathData);
    184 }
    185 
    186 void vegaModifyPathCoords(VGPath dstPath,
    187                           VGint startIndex,
    188                           VGint numSegments,
    189                           const void * pathData)
    190 {
    191    struct vg_context *ctx = vg_current_context();
    192    struct path *p = 0;
    193 
    194    if (dstPath == VG_INVALID_HANDLE) {
    195       vg_set_error(ctx, VG_BAD_HANDLE_ERROR);
    196       return;
    197    }
    198    if (startIndex < 0 || numSegments <= 0) {
    199       vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
    200       return;
    201    }
    202 
    203    p = handle_to_path(dstPath);
    204 
    205    if (!pathData || !is_aligned_to(pathData, path_datatype_size(p))) {
    206       vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
    207       return;
    208    }
    209 
    210    if (startIndex + numSegments > path_num_segments(p)) {
    211       vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
    212       return;
    213    }
    214    if (!(path_capabilities(p)&VG_PATH_CAPABILITY_MODIFY)) {
    215       vg_set_error(ctx, VG_PATH_CAPABILITY_ERROR);
    216       return;
    217    }
    218    path_modify_coords(p, startIndex, numSegments, pathData);
    219 }
    220 
    221 void vegaTransformPath(VGPath dstPath, VGPath srcPath)
    222 {
    223    struct vg_context *ctx = vg_current_context();
    224    struct path *src = 0, *dst = 0;
    225 
    226    if (dstPath == VG_INVALID_HANDLE || srcPath == VG_INVALID_HANDLE) {
    227       vg_set_error(ctx, VG_BAD_HANDLE_ERROR);
    228       return;
    229    }
    230    src = handle_to_path(srcPath);
    231    dst = handle_to_path(dstPath);
    232 
    233    if (!(path_capabilities(src) & VG_PATH_CAPABILITY_TRANSFORM_FROM) ||
    234        !(path_capabilities(dst) & VG_PATH_CAPABILITY_TRANSFORM_TO)) {
    235       vg_set_error(ctx, VG_PATH_CAPABILITY_ERROR);
    236       return;
    237    }
    238    path_transform(dst, src);
    239 }
    240 
    241 VGboolean vegaInterpolatePath(VGPath dstPath,
    242                               VGPath startPath,
    243                               VGPath endPath,
    244                               VGfloat amount)
    245 {
    246    struct vg_context *ctx = vg_current_context();
    247    struct path *start = 0, *dst = 0, *end = 0;
    248 
    249    if (dstPath == VG_INVALID_HANDLE ||
    250        startPath == VG_INVALID_HANDLE ||
    251        endPath == VG_INVALID_HANDLE) {
    252       vg_set_error(ctx, VG_BAD_HANDLE_ERROR);
    253       return VG_FALSE;
    254    }
    255    dst = handle_to_path(dstPath);
    256    start = handle_to_path(startPath);
    257    end = handle_to_path(endPath);
    258 
    259    if (!(path_capabilities(dst) & VG_PATH_CAPABILITY_INTERPOLATE_TO) ||
    260        !(path_capabilities(start) & VG_PATH_CAPABILITY_INTERPOLATE_FROM) ||
    261        !(path_capabilities(end) & VG_PATH_CAPABILITY_INTERPOLATE_FROM)) {
    262       vg_set_error(ctx, VG_PATH_CAPABILITY_ERROR);
    263       return VG_FALSE;
    264    }
    265 
    266    return path_interpolate(dst,
    267                            start, end, amount);
    268 }
    269 
    270 VGfloat vegaPathLength(VGPath path,
    271                        VGint startSegment,
    272                        VGint numSegments)
    273 {
    274    struct vg_context *ctx = vg_current_context();
    275    struct path *p = 0;
    276 
    277    if (path == VG_INVALID_HANDLE) {
    278       vg_set_error(ctx, VG_BAD_HANDLE_ERROR);
    279       return -1;
    280    }
    281    if (startSegment < 0) {
    282       vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
    283       return -1;
    284    }
    285    if (numSegments <= 0) {
    286       vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
    287       return -1;
    288    }
    289    p = handle_to_path(path);
    290 
    291    if (!(path_capabilities(p) & VG_PATH_CAPABILITY_PATH_LENGTH)) {
    292       vg_set_error(ctx, VG_PATH_CAPABILITY_ERROR);
    293       return -1;
    294    }
    295    if (startSegment + numSegments > path_num_segments(p)) {
    296       vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
    297       return -1;
    298    }
    299 
    300    return path_length(p, startSegment, numSegments);
    301 }
    302 
    303 void vegaPointAlongPath(VGPath path,
    304                         VGint startSegment,
    305                         VGint numSegments,
    306                         VGfloat distance,
    307                         VGfloat * x, VGfloat * y,
    308                         VGfloat * tangentX,
    309                         VGfloat * tangentY)
    310 {
    311    struct vg_context *ctx = vg_current_context();
    312    struct path *p = 0;
    313    VGbitfield caps;
    314 
    315    if (path == VG_INVALID_HANDLE) {
    316       vg_set_error(ctx, VG_BAD_HANDLE_ERROR);
    317       return;
    318    }
    319    if (startSegment < 0) {
    320       vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
    321       return;
    322    }
    323    if (numSegments <= 0) {
    324       vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
    325       return;
    326    }
    327 
    328    if (!is_aligned(x) || !is_aligned(y) ||
    329        !is_aligned(tangentX) || !is_aligned(tangentY)) {
    330       vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
    331       return;
    332    }
    333 
    334    p = handle_to_path(path);
    335 
    336    caps = path_capabilities(p);
    337    if (!(caps & VG_PATH_CAPABILITY_POINT_ALONG_PATH) ||
    338        !(caps & VG_PATH_CAPABILITY_TANGENT_ALONG_PATH)) {
    339       vg_set_error(ctx, VG_PATH_CAPABILITY_ERROR);
    340       return;
    341    }
    342 
    343    if (startSegment + numSegments > path_num_segments(p)) {
    344       vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
    345       return;
    346    }
    347 
    348    {
    349       VGfloat point[2], normal[2];
    350       path_point(p, startSegment, numSegments, distance,
    351                  point, normal);
    352       if (x)
    353          *x = point[0];
    354       if (y)
    355          *y = point[1];
    356       if (tangentX)
    357          *tangentX = -normal[1];
    358       if (tangentY)
    359          *tangentY = normal[0];
    360    }
    361 }
    362 
    363 void vegaPathBounds(VGPath path,
    364                     VGfloat * minX,
    365                     VGfloat * minY,
    366                     VGfloat * width,
    367                     VGfloat * height)
    368 {
    369    struct vg_context *ctx = vg_current_context();
    370    struct path *p = 0;
    371    VGbitfield caps;
    372 
    373    if (path == VG_INVALID_HANDLE) {
    374       vg_set_error(ctx, VG_BAD_HANDLE_ERROR);
    375       return;
    376    }
    377 
    378    if (!minX || !minY || !width || !height) {
    379       vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
    380       return;
    381    }
    382 
    383    if (!is_aligned(minX) || !is_aligned(minY) ||
    384        !is_aligned(width) || !is_aligned(height)) {
    385       vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
    386       return;
    387    }
    388 
    389    p = handle_to_path(path);
    390 
    391    caps = path_capabilities(p);
    392    if (!(caps & VG_PATH_CAPABILITY_PATH_BOUNDS)) {
    393       vg_set_error(ctx, VG_PATH_CAPABILITY_ERROR);
    394       return;
    395    }
    396 
    397    path_bounding_rect(p, minX, minY, width, height);
    398 }
    399 
    400 void vegaPathTransformedBounds(VGPath path,
    401                                VGfloat * minX,
    402                                VGfloat * minY,
    403                                VGfloat * width,
    404                                VGfloat * height)
    405 {
    406    struct vg_context *ctx = vg_current_context();
    407    struct path *p = 0;
    408    VGbitfield caps;
    409 
    410    if (path == VG_INVALID_HANDLE) {
    411       vg_set_error(ctx, VG_BAD_HANDLE_ERROR);
    412       return;
    413    }
    414 
    415    if (!minX || !minY || !width || !height) {
    416       vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
    417       return;
    418    }
    419 
    420    if (!is_aligned(minX) || !is_aligned(minY) ||
    421        !is_aligned(width) || !is_aligned(height)) {
    422       vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
    423       return;
    424    }
    425 
    426    p = handle_to_path(path);
    427 
    428    caps = path_capabilities(p);
    429    if (!(caps & VG_PATH_CAPABILITY_PATH_TRANSFORMED_BOUNDS)) {
    430       vg_set_error(ctx, VG_PATH_CAPABILITY_ERROR);
    431       return;
    432    }
    433 
    434 #if 0
    435    /* faster, but seems to have precision problems... */
    436    path_bounding_rect(p, minX, minY, width, height);
    437    if (*width > 0 && *height > 0) {
    438       VGfloat pts[] = {*minX,          *minY,
    439                        *minX + *width, *minY,
    440                        *minX + *width, *minY + *height,
    441                        *minX,          *minY + *height};
    442       struct matrix *matrix = &ctx->state.vg.path_user_to_surface_matrix;
    443       VGfloat maxX, maxY;
    444       matrix_map_point(matrix, pts[0], pts[1], pts + 0, pts + 1);
    445       matrix_map_point(matrix, pts[2], pts[3], pts + 2, pts + 3);
    446       matrix_map_point(matrix, pts[4], pts[5], pts + 4, pts + 5);
    447       matrix_map_point(matrix, pts[6], pts[7], pts + 6, pts + 7);
    448       *minX = MIN2(pts[0], MIN2(pts[2], MIN2(pts[4], pts[6])));
    449       *minY = MIN2(pts[1], MIN2(pts[3], MIN2(pts[5], pts[7])));
    450       maxX = MAX2(pts[0], MAX2(pts[2], MAX2(pts[4], pts[6])));
    451       maxY = MAX2(pts[1], MAX2(pts[3], MAX2(pts[5], pts[7])));
    452       *width  = maxX - *minX;
    453       *height = maxY - *minY;
    454    }
    455 #else
    456    {
    457       struct path *dst = path_create(VG_PATH_DATATYPE_F, 1.0, 0,
    458                                      0, 0, VG_PATH_CAPABILITY_ALL);
    459       path_transform(dst, p);
    460       path_bounding_rect(dst, minX, minY, width, height);
    461       path_destroy(dst);
    462    }
    463 #endif
    464 }
    465 
    466 
    467 void vegaDrawPath(VGPath path, VGbitfield paintModes)
    468 {
    469    struct vg_context *ctx = vg_current_context();
    470    struct path *p = handle_to_path(path);
    471 
    472    if (path == VG_INVALID_HANDLE) {
    473       vg_set_error(ctx, VG_BAD_HANDLE_ERROR);
    474       return;
    475    }
    476 
    477    if (!(paintModes & (VG_STROKE_PATH | VG_FILL_PATH))) {
    478       vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
    479       return;
    480    }
    481 
    482    if (path_is_empty(p))
    483       return;
    484    path_render(p, paintModes,
    485          &ctx->state.vg.path_user_to_surface_matrix);
    486 }
    487 
    488